Servlets and JSPs

Servlet

Understanding the servlet

Tomcat可以简单的理解为一个web容器,我们编写的servelet程序必须要在web容器中才能运行,这很好理解,因为单单一个servlet java程序并不能够接收浏览器的信息,我们需要通过web容器接收到浏览器的命令,然后web容器再调用servlet处理并返回结果。
Tomcat从浏览器接收到请求后生成request和response两个对象,将这两个对象传入servlet,servelet处理后再返回Tomcat。
Servlet可以使用xml或者annotation来处理路径。

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
package org.shiyu.liu;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Servlet implementation class SimpleServlet
*/
@WebServlet(description = "A simple servlet", urlPatterns = { "/SimpleServletPath" })//使用annotation来处理路径
public class SimpleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//从Tomcat中接收到的request和response对象
// TODO Auto-generated method stub
System.out.println("Hello From Get Method");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<h3>Hello from html</h3>");
}

}

Servlet XML configuration

我们可以不使用annonation配置servlet的url,而是直接在web.xml中进行配置
: welcome-file-list的工作原理是,按照welcome-file的.list一个一个去检查是否web目录下面存在这个文件,如果存在,继续下面的工作,先去webcontent(这里是Eclipse的工程目录根目录)下是否真的存在index.html这个文件,如果不存在去找是否存在index.jsp这个文件,以此类推。
: 关联
: 关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
<display-name>SimpleServletProject</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>xmlServlet</servlet-name>
<servlet-class>org.shiyu.liu.XmlServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xmlServlet</servlet-name>
<url-pattern>/xmlServletPath</url-pattern>
</servlet-mapping>
</web-app>

xml比annotation的优势在于,当我们改变路径的时候,如果是在xml修改,只需要重启Tomcat即可,但是如果修改java代码,那么需要重新编译。

The POST Method and Passing Parameters

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
package org.shiyu.liu;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Servlet implementation class XmlServlet
*/
public class XmlServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String userName = request.getParameter("userName");//得到userName这个参数的值
out.println("Hello " + userName);
}
}

Request, Session, context

response, request和servlet本身都是objects,由Tomcat创建(我们只写了servlet的class,它的instantiate是由Tomcat实现的)。
request和response objects每一次有浏览器发起请求都会由Tomcat实例化一次(因为HTTP协议是stateless的)
servlet object只有一个,不同的请求有不同的servlet thread,但是都是在这一个实例下面的

由于request object在每次请求事都会被重置,有的时候我们需要记住已有的信息(比如用户的登录信息),这个时候就要使用session。
Tomcat将session存在内存中。
https://www.zhihu.com/question/19786827
https://www.runoob.com/servlet/servlet-session-tracking.html

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String userName = request.getParameter("userName");
HttpSession session = request.getSession();
if(userName!=null && !userName.equals("")) {
session.setAttribute("savedUserName", userName);
}
out.println("Hello from GET moethd " + userName);
out.println("Saved session user name: "+ (String)session.getAttribute("savedUserName"));

}

session object对于不同的用户(浏览器)有不同的值,如果我们需要一个对于所有用户都存有同样值的对象,那么可以使用context object。https://blog.csdn.net/gavin_john/article/details/51399425

Understanding init, service and ServletConfig(how a servlet is initialized, the methods that get called and the objects used on initialization and execution)

There are methods which run before the doGet and doPost. 代码都可以在HttpServlet.java中查看
init(servletConfig):第一次call servlet的时候,进行servlet初始化
service():service通过判断HTTP code来调用doGet或者其他方法

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
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {

String method = req.getMethod();

if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}

} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);

} else if (method.equals(METHOD_POST)) {
doPost(req, resp);

} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);

} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);

} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);

} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);

} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//

String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);

resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}

所以比如连接数据库的操作就可以在init()中完成。

Servlet一个最大的缺点就是在java code中写html,JSP可以解决这个问题,JSP其实就是一种动态思想,web界面主要由html显示,其中需要改变的地方可以使用java变量。

JSP

JSP baiscs

Servlet一个最大的缺点就是在java code中写html,JSP可以解决这个问题,JSP其实就是一种动态思想,web界面主要由html显示,其中需要改变的地方可以使用java变量。
JSP和EJS里用于表示变量的方法很像(我感觉ejs应该是模仿JSP的吧),JSP使用<% JAVA语句 %>来写java代码, <%= JAVA变量%>来显示到html中,<%! JAVA函数 %>来定义一个全局函数。

1
2
3
4
5
6
7
8
9
<%! 
public int add(int a, int b){
return a+b;
}
%>
<%
int t = add(234, 123);
%>
t's value is: <%=t %>

所以其实JSP/EJS/jinja2本质上其实就是simple templating language that lets you generate HTML markup with plain JAVA/JavaScript/python

understanding JSP

JSP在运行的时候,其实会被Tomcat转化成java class文件,也就是一个servlet,所有<% %>里面的语句都会运行在servlet的doGet method中。所以我们不能在<% %>中间写另一个函数。而<%! %>里的内容只会被放在class中。
而对于JSP中其他的html tag,其实就相当于java调用了out.println()函数。
这也是JSP可以像下面这样写的原因(和ejs类似)

1
2
3
4
5
6
7
8
9
<% 
for(int p = 0;p<=5;p++){
%>
<br>
The value of p is: <%=p %>
<%
}
%>

JSP被翻译的java class可以在Tomcat的work文件夹下面找到

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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/9.0.33
* Generated at: 2020-03-30 18:00:34 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.*;

public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {


public int add(int a, int b){
return a+b;
}

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 static final java.util.Set<java.lang.String> _jspx_imports_packages;

private static final java.util.Set<java.lang.String> _jspx_imports_classes;

static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}

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 java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}

public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}

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 {

if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
final java.lang.String _jspx_method = request.getMethod();
if ("OPTIONS".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
return;
}
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
return;
}
}

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("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write("<meta charset=\"UTF-8\">\n");
out.write("<title>Test jsp</title>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write("\t");

int i = 1;
int j = 2;
int k;
k = i + j;
out.println(k);

out.write("\n");
out.write("\tThe value of k is: ");
out.print( k );
out.write("\n");
out.write("\t\n");
out.write("\t");
out.write('\n');
out.write(' ');

int t = add(234, 123);

out.write("\n");
out.write("\tt's value is: ");
out.print(t );
out.write("\n");
out.write("\t\n");
out.write("\t");

for(int p = 0;p<=5;p++){

out.write("\n");
out.write("\t<br> \n");
out.write("\tThe value of p is: ");
out.print(p );
out.write('\n');
out.write(' ');

}

out.write("\n");
out.write("</body>\n");
out.write("</html>");
} 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);
}
}
}

page directives

用于java程序的一些全局配置

1
2
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.Date"%>

Scopes in JSP and the PageContext object

JSP中可以直接使用类似servlet的request, response, session, context objects。

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
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<% String userName = request.getParameter("userName");
application.setAttribute("applicationContextName", "defaultName");
if(userName!=null){
session.setAttribute("sessionName", userName);
application.setAttribute("applicationContextName", userName);//application context object
pageContext.setAttribute("pageContextName", userName);//page context object
}

%>
<br>
The user name in the request object is : <%= userName %>
<br>
The user name in the session object is : <%= session.getAttribute("sessionName") %>
<br>
The user name in the application context object is : <%= application.getAttribute("applicationContextName") %>
<br>
The user name in the page context object is : <%= pageContext.getAttribute("pageContextName") %>
</body>
</html>

Using jspInit and InitParams

JSP也可以配置initParameter或者重写jspInit()函数。

MVC

Servlet(Controller)
Bean(Model)
JSP(View)

我们这里的MVC数据由JSP(View层)直接返回给user,也可以是JSP返回给COntroller,Controller处理后再返回给user,这取决于MVC的设计。

jstl

jsp的缺点是要在html中夹杂很多java code,所以产生了jstl