JSP基础

JSP(Java Server Page)基础

Servlet和JSP的相同点

JSP和Servlet从本质上,是相同的技术.
继承结构如下:

接口源代码

1
2
3
4
5
6
7
public interface JspPage extends Servlet {

public void jspInit();

public void jspDestroy();

}

1
2
3
4
5
6
public interface HttpJspPage extends JspPage {

public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}

Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。


Servlet和JSP最主要的不同点

Servlet的应用逻辑是在Java文件中,并且完全从视图层中的HTML分离开来。而JSP是Java和HTML组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(Controller)。


JSP的执行流程

Servlet/JSP容器首先将JSP页面转换成一个JSP页面的实现类,这是一个实现了JspPage接口或其子接口HttpJspPage的Java类。JspPage接口是Servlet的子接口,因此每个JSP页面都是一个Servlet。转换成功后,容器会编译Servlet类,之后容器加载和实例化Java字节码,并执行它通常对Servlet所做的生命周期操作。对同一个JSP页面的后续请求,容器会查看这个JSP页面是否被修改过,如果修改过就会重新转换并重新编译并执行。如果没有则执行内存中已经存在的Servlet实例。
例子
JSP页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
<title>Title</title>
</head>

<body>
<%= new Date()%>

<%!
int anInt = 20180713;
%>

<%
out.print("20180713日");
%>
</body>
</html>

该JSP页面会被容器编译为以下内容,其本质就是Servlet,简化了开发者对视图的开发,避免硬编码.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.86
* Generated at: 2018-07-13 07:43:45 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.Date;

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {

// 声明标签内的内容的生成位置
int anInt = 20180713;

private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();

private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}

public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}

public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}

public void _jspInit() {
}

public void _jspDestroy() {
}

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
// JSP 内置对象
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;


try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;

out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <title>Title</title>\n");
out.write("</head>\n");
out.write("<body>\n");

// 赋值标签内的内容生成位置
out.print( new Date());
out.write('\n');
out.write('\n');
out.write('\n');
out.write('\n');

// 脚本标签内的内容生成位置
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
out.println(sdf.format(date));

out.write("\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}

JSP的三种原始标签

声明标签

1
2
3
<%!  
int anInt = 20180713;
%>

根据上面JSP文件编译的结果,可知在声明标签中所编写的代码,最终是类的成员变量.

脚本标签

1
2
3
4
5
<%
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
out.println(sdf.format(date));
%>

根据上面JSP文件编译的结果,可知在脚本标签中所编写的代码,最终会在类的_jspService(..)的方法体中出现

赋值标签

1
<%= new Date() %>

根据上面JSP文件编译的结果,可知在赋值标签中所编写的代码,最终会成为字符输出流的方法参数.


JSP的常用指令标签

  1. <%@ page %>
    1. language属性 指定当前页面的语言,目前只支持java
    2. import属性:导入包
    3. contentType属性: 设置JSP的响应类型,该属性中的值最终会被填充到response.setContentType(..)方法
    4. pageEncoding属性:当前页面从字符到字节用什么字符集转换.如果响应类型是text/html,并且contentType中没有指定字符集,则会在_jspService(..)方法中的response.setContentType(..)方法中默认使用该参数.
    5. sesssion属性:可选值true/false.如果true,访问当前JSP页面就会创建一个Session;如果false,反之则不创建.
    6. errorPage属性: 当前页面发生异常后跳转到指定的错误页面
    7. isErrorPage属性:只能在errorPage页面使用,可选值true/false.如果true,则当前页面可以获取到exception对象并且输出.
  2. <%@ include %>

JSP的9个内置对象

内置对象不用开发者手动创建,可以直接使用
查看上面JSP编译后的代码中的_jspService方法,参数是request和response,方法体里创建了其余的6个内置对象.由于page指令标签中没有isErrorPage=”true”,所以exception对象没有创建.

JSP Servlet
request HttpServletRequest
response HttpServletResponse
application ServletContext
session HttpSession(该对象是否创建取决于page指令标签中的session属性,若true则自动创建,若false,反之)
config ServletConfig
out PrintWriter的兄弟类JspWriter
exception Throwable(该对象是否创建取决于page指令标签中的isErrorPage属性,若true则创建.若false,反之)
page
pageContext

请求转发和重定向的区别

请求转发 重定向
服务器端完成 客户端完成
速度快 速度慢
一次请求和一次响应的过程 两次请求和两次响应的过程
浏览器地址栏不改变 浏览器地址栏要改变
可以利用request对象来传递数据 不能使用request对象传递数据
只能是在同一个服务器下完成 可以在不同的服务器间完成

JSTL和EL表达式

参考该博客
JSTL 表达式与 EL 语言

您的支持将让服务器运行更长久