Servlet(Server Applet),全称 Java Servlet,是用 Java 编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态 Web 内容。本系列将一步步地写出一个 Servlet 程序。
这篇博文将演示如何分别处理 GET
和 POST
请求,以及处理请求中的参数。
编写 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 { response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
try (PrintWriter writer = response.getWriter()) { 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 { response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
try (PrintWriter writer = response.getWriter()) { 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 { httpServletResponse.sendError(501); } }
|
运行起来看看效果
首先发个 GET
请求
再发个 POST
请求
为什么不用 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 { response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
try (PrintWriter writer = response.getWriter()) { 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 { response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
try (PrintWriter writer = response.getWriter()) { 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 { response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
Optional<String> optionalQueryString = Optional.ofNullable(request.getQueryString());
String[] queryStrings = optionalQueryString.isPresent() ? optionalQueryString.get().split("&") : new String[]{};
try (PrintWriter writer = response.getWriter()) { 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) { String[] q = query.split("=");
writer.print(q[0] + " = " + q[1] + "<br>"); }
writer.print("<br>");
writer.print("</body>"); writer.print("</html>"); } }
|
运行一下,结果是这样子的:
处理 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 { response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
Map parameterMap = request.getParameterMap();
try (PrintWriter writer = response.getWriter()) { 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.forEach((k, v) -> writer.print(k + " = " + ((String[]) v)[0] + "<br>"));
writer.print("</body>"); writer.print("</html>"); } }
|
本文中将使用 application/x-www-form-urlencoded
格式做示例。
系列博文