0%

循序渐进写一个Servlet(3) - 分别处理GET和POST

Servlet(Server Applet),全称Java Servlet,是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。本系列将一步步地写出一个Servlet程序。

这篇博文将演示如何分别处理GETPOST请求,以及处理请求中的参数。

编写doGet()doPost()方法

首先把要实现的功能写好,后面才好调用不是。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 设定返回内容的MIME类型
response.setContentType("text/html");

// 设定内容以UTF-8编码
response.setCharacterEncoding("utf-8");

try (PrintWriter writer = response.getWriter()) {
// 开始输出HTML文本
writer.print("<html lang=\"en\">");
writer.print("<body>");
writer.print("<b>Response from DemoServlet</b>");
writer.print("<b>Handled by <code>doGet()</code></b>");
writer.print("</body>");
writer.print("</html>");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 设定返回内容的MIME类型
response.setContentType("text/html");

// 设定内容以UTF-8编码
response.setCharacterEncoding("utf-8");

try (PrintWriter writer = response.getWriter()) {
// 开始输出HTML文本
writer.print("<html lang=\"en\">");
writer.print("<body>");
writer.print("<b>Response from DemoServlet</b>");
writer.print("<b>Handled by <code>doPost()</code></b>");
writer.print("</body>");
writer.print("</html>");
}
}

区分HTTP方法

因为servlet是调用service()方法来处理请求的,所以对请求做区分也需要在service()方法中进行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

HttpServletRequest httpServletRequest = (HttpServletRequest) req;
HttpServletResponse httpServletResponse = (HttpServletResponse) res;

if ("GET".equalsIgnoreCase(httpServletRequest.getMethod())) {
doGet(httpServletRequest, httpServletResponse);
} else if ("POST".equalsIgnoreCase(httpServletRequest.getMethod())) {
doPost(httpServletRequest, httpServletResponse);
} else {
// 如果请求既不是GET也不是POST
// 那么就返回HTTP 501 NOT IMPLEMENTED状态码
// 毕竟不能把请求直接扔了,总是要有个返回的
httpServletResponse.sendError(501);
}
}

运行起来看看效果

首先发个GET请求

Handling GET request

再发个POST请求

Handling POST request

为什么不用HttpServlet类呢

没错,上面做的,就是自己实现了一个简陋的HttpServlet类,因为是循序渐进嘛,没头没脑的直接砸上来一个,算什么循序渐进。

那么现在就让DemoServlet继承HttpServlet。同时,因为HttpServlet已经在service()方法中实现了判断请求类型,所以DemoServlet中不要覆盖service()方法,只覆盖doGet()doPost()方法。

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
public class DemoServlet extends HttpServlet {

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 设定返回内容的MIME类型
response.setContentType("text/html");

// 设定内容以UTF-8编码
response.setCharacterEncoding("utf-8");

try (PrintWriter writer = response.getWriter()) {
// 开始输出HTML文本
writer.print("<html lang=\"en\">");
writer.print("<body>");
writer.print("<b>Response from DemoServlet</b>");
writer.print("<b>Handled by <code>doGet()</code></b>");
writer.print("</body>");
writer.print("</html>");
}
}

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 设定返回内容的MIME类型
response.setContentType("text/html");

// 设定内容以UTF-8编码
response.setCharacterEncoding("utf-8");

try (PrintWriter writer = response.getWriter()) {
// 开始输出HTML文本
writer.print("<html lang=\"en\">");
writer.print("<body>");
writer.print("<b>Response from DemoServlet</b>");
writer.print("<b>Handled by <code>doPost()</code></b>");
writer.print("</body>");
writer.print("</html>");
}
}
}

处理请求中的参数

HTTP请求是可以带参数的,有了参数,那就得处理。

处理GET请求的参数

GET请求里带的参数,名字叫查询字符串(query string),是一组或多组key=value格式的键值对。

Query string写在URL后面,以一个问号起头,用&分隔各个键值对,即类似http://localhost:8080/appname/servlet?arg1=value1&arg2=value2&...&argN=valueN

在代码里使用HttpServletRequest#getQueryString()方法,就可以获取到问号后面的query string,分别用&=分割字符串,就可以取到每个参数的key和value。

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
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 设定返回内容的MIME类型
response.setContentType("text/html");

// 设定内容以UTF-8编码
response.setCharacterEncoding("utf-8");

/*

String queryString = request.getQueryString();
String[] queryStrings;

if (queryString != null) {
queryStrings = queryString.split("&");
} else {
queryStrings = new String[]{};
}

*/

// 使用Optional类简化null判断
Optional<String> optionalQueryString = Optional.ofNullable(request.getQueryString());

// 如果有query string则取出每个参数
// 如果没有则返回一个空的String数组
String[] queryStrings = optionalQueryString.isPresent() ? optionalQueryString.get().split("&") : new String[]{};

try (PrintWriter writer = response.getWriter()) {
// 开始输出HTML文本
writer.print("<html lang=\"en\">");
writer.print("<body>");
writer.print("<b>Response from DemoServlet</b>");
writer.print("<b>Handled by <code>doGet()</code></b>");

writer.print("<br>");

// 遍历每个参数
for (String query : queryStrings) {
// 取出参数的key和value
String[] q = query.split("=");

writer.print(q[0] + " = " + q[1] + "<br>");
}

writer.print("<br>");

writer.print("</body>");
writer.print("</html>");
}
}

运行一下,结果是这样子的:

Handling query string

处理POST请求的参数

POST请求的参数就叫参数(parameter),位于请求体(body)里,格式由Content-Type请求头决定。详细介绍可以参考这篇MDN文档

HttpServletRequest#getParameterMap()方法可以取出请求中的所有参数,并放到一个Map中。

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
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 设定返回内容的MIME类型
response.setContentType("text/html");

// 设定内容以UTF-8编码
response.setCharacterEncoding("utf-8");

// 取出所有参数,得到一个Map
Map parameterMap = request.getParameterMap();

try (PrintWriter writer = response.getWriter()) {
// 开始输出HTML文本
writer.print("<html lang=\"en\">");
writer.print("<body>");
writer.print("<b>Response from DemoServlet</b>");
writer.print("<b>Handled by <code>doPost()</code></b>");

writer.print("<br>");

// 遍历parameterMap
parameterMap.forEach((k, v) -> writer.print(k + " = " + ((String[]) v)[0] + "<br>"));

writer.print("</body>");
writer.print("</html>");
}
}

本文中将使用application/x-www-form-urlencoded格式做示例。

Handling parameter

系列博文