返回介绍

00-04、理解 Servlet

发布于 2025-03-09 23:21:22 字数 11030 浏览 0 评论 0 收藏 0

本文依然使用 00-03、从 JSP 开始 中创建的项目 HelloJSP。

本文主要有以下内容:

  • 如何使用 Servlet 编写 Hello Servlet

  • 如何将 Servlet 与 URL 对应起来

  • Servlet 如何调用 JSP

  • Servlet 如何返回 JSON 数据

  • 如何编写一个 Dispatcher

Hello Servlet

项目结构如下:

HelloServlet.java 内容如下:

package me.letiantian.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet {

  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    try (PrintWriter out = response.getWriter()) {
      out.println("<!DOCTYPE html>");
      out.println("<html>");
      out.println("<head>");
      out.println("<title>Servlet HelloServlet</title>");      
      out.println("</head>");
      out.println("<body>");
      out.println("<h1>Servlet HelloServlet at " + request.getContextPath() + "</h1>");
      out.println("</body>");
      out.println("</html>");
    }
  }

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

}

HTTP 最常见的方法是 GET 和 POST,在一个 Servlet 中对应的处理方法分别是 doGet() 和 doPost()。 response.setContentType("text/html;charset=UTF-8"); 用来设置 HTTP 响应头中的 Content-Type。 PrintWriter 对象 out 的输出内容则是响应正文。

web.xml 内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
  <servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>me.letiantian.servlet.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/HelloServlet</url-pattern>
  </servlet-mapping>
  <session-config>
    <session-timeout>
      30
    </session-timeout>
  </session-config>
</web-app>

在这个配置中, me.letiantian.servlet.HelloServlet 与 URL /HelloServlet 对应。 session-timeout 设置了 session 的有效时间,单位是分钟(不过目前的程序里还没用过 session)。

浏览器访问 http://127.0.0.1:8084/HelloJSP 会显示 404;访问 http://127.0.0.1:8084/HelloJSP/HelloServlet 会显示 Servlet HelloServlet at /HelloJSP ,这也正是 me.letiantian.servlet.HelloServlet 输出的 HTML 的渲染结果。

也可以使用注解将 Servlet 和 URL 对应起来

首先清空 web.xml 中关于 URL 的配置,web.xml 最终内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

  <session-config>
    <session-timeout>
      30
    </session-timeout>
  </session-config>

</web-app>

然后对 me.letiantian.servlet.HelloServlet 类略做修改:

package me.letiantian.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.servlet.annotation.WebServlet;

@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
  // ......
}

重新启动项目,浏览器访问效果和之前是相同的。

Servlet 调用 JSP

改写 me.letiantian.servlet.HelloServlet 类,内容如下:

package me.letiantian.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.servlet.annotation.WebServlet;

@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {

  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    request.setAttribute("title", "Hello Servlet");
    request.setAttribute("content", "你好");
    RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/jsp/hello.jsp");
    rd.forward(request, response);
  }

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

}

WEB-INF/ 下创建目录 jsp ,然后在 jsp 目录下新建 hello.jsp ,内容如下:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>${title}</title>
  </head>
  <body>
    <h1>${content}</h1>
  </body>
</html>

重启该项目,访问 http://127.0.0.1:8084/HelloJSP/HelloServlet

$ curl -i  http://127.0.0.1:8084/HelloJSP/HelloServlet
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=7CCCFD5467F8330066F827623802FB23; Path=/HelloJSP/; HttpOnly
Content-Type: text/html;charset=UTF-8
Content-Length: 215
Date: Fri, 18 Sep 2015 08:09:58 GMT

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Hello Servlet</title>
  </head>
  <body>
    <h1>你好</h1>
  </body>
</html>

CSS 等静态文件放在什么地方

在项目下建立 static 目录,再这个目录下添加 test.js ,内容如下:

console.log("hello world");

web.xml 添加以下内容:

<servlet-mapping>  
  <servlet-name>default</servlet-name>
  <url-pattern>*.jpg</url-pattern>   
</servlet-mapping>  

<servlet-mapping>  
  <servlet-name>default</servlet-name>
  <url-pattern>*.png</url-pattern>   
</servlet-mapping>  

<servlet-mapping>  
  <servlet-name>default</servlet-name>  
  <url-pattern>*.js</url-pattern>  
</servlet-mapping>  

<servlet-mapping>  
  <servlet-name>default</servlet-name>  
  <url-pattern>*.css</url-pattern>   
</servlet-mapping>

此时,项目结构如下:

启动项目,访问

$ curl -i http://localhost:8084/HelloJSP/static/test.js
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"27-1442566151000"
Last-Modified: Fri, 18 Sep 2015 08:49:11 GMT
Content-Type: application/javascript
Content-Length: 27
Date: Fri, 18 Sep 2015 08:58:00 GMT

console.log("hello world");
$ curl -i http://localhost:8084/HelloJSP/static/test.js?time=123
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"27-1442566151000"
Last-Modified: Fri, 18 Sep 2015 08:49:11 GMT
Content-Type: application/javascript
Content-Length: 27
Date: Fri, 18 Sep 2015 08:58:09 GMT

console.log("hello world");

Servlet 如何返回 JSON 数据

response.setContentType("text/html;charset=UTF-8");

修改为

response.setContentType("application/json;charset=UTF-8");

out.println 输出 JSON 格式的字符串即可。

编写 Dispatcher

基于以上的学习,已经可以编写一个分发器了。 将 HelloServlet.java 修改为 DispatcherServlet.java,内容修改为:

package me.letiantian.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.servlet.annotation.WebServlet;

@WebServlet("/")
public class HelloServlet extends HttpServlet {

  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/plain;charset=UTF-8");
    try (PrintWriter out = response.getWriter()) {
      out.println("context: " + request.getContextPath());
      out.println("request uri: " + request.getRequestURI());
      out.println("params: " + request.getParameterMap());
    }
  }

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

}

运行项目,访问结果如下:

$ curl http://localhost:8084/HelloJSP/user
context: /HelloJSP
request uri: /HelloJSP/user
params: {}
$ curl http://localhost:8084/HelloJSP/user?name=letian
context: /HelloJSP
request uri: /HelloJSP/user
params: {name=[Ljava.lang.String;@49ea47b4}
$ curl http://localhost:8084/HelloJSP/static/test.js
console.log("hello world");

(这个代码并没什么用~)

从这段代码中可以看到,我们可以通过 request 对象得到 HTTP 请求信息,特别是 request URI。在这个程序的基础上,我们 可以继续扩充它,使得其遇到某个 URI,就调用指定的处理函数。慢慢地补充,一个框架就出来了。

资料

本节中,JSP 使用了表达式语言,可以参考:
JSTL 入门: 表达式语言
JSP 表达式语言

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文