深入明白 Servlet:从基础概念到高级特性与实战应用

打印 上一主题 下一主题

主题 862|帖子 862|积分 2586

一、Servlet简介与工作原理

Servlet是Java Web开辟中的重要组件,它运行在服务器端,用于处理客户端的哀求并返回响应。其工作原理涉及多个组件和步调,从客户端发起哀求到服务器端的处理和响应,整个过程井然有序地进行。
(一)Servlet容器与Tomcat

Servlet容器是Servlet运行的环境,负责管理Servlet的生命周期、资源分配和哀求处理等工作。Tomcat是常用的Servlet容器之一,它具有强大的功能和良好的性能。在Tomcat中,Context容器直接管理Servlet的包装类Wrapper,一个Context对应一个Web工程。比方,在Tomcat的配置文件中,可以通过标签来配置Web应用的相关参数,如路径、文档库等。
(二)Servlet的生命周期


  • 加载和实例化

    • Servlet容器在启动时或首次检测到需要Servlet响应哀求时,会加载Servlet类。它通过类加载器从当地文件系统、远程文件系统或网络服务中获取Servlet类。比方,在一个Web应用启动时,Tomcat会根据web.xml中的配置找到对应的Servlet类并加载它。
    • 容器利用Java反射API创建Servlet实例,调用默认构造方法(无参构造方法),因此编写Servlet类时不应提供带参数的构造方法。

  • 初始化

    • 实例化后,容器调用Servlet的init()方法进行初始化。在这个方法中,Servlet可以进行一些准备工作,如创建数据库毗连、获取配置信息等。比方,以下是一个简单的init()方法实现:

  1. public void init(ServletConfig config) throws ServletException {
  2.     super.init(config);
  3.     // 在这里进行初始化操作,如获取初始化参数
  4.     String paramValue = config.getInitParameter("paramName");
  5.     // 其他初始化逻辑
  6. }
复制代码

  • 每个Servlet实例的init()方法只被调用一次,初始化期间可以利用ServletConfig对象获取web.xml中配置的初始化参数。如果发生错误,可抛出ServletException或UnavailableException异常关照容器。

  • 哀求处理

    • 容器调用Servlet的service()方法处理哀求。在service()方法中,Servlet通过ServletRequest对象获取客户端信息和哀求信息,处理后通过ServletResponse对象设置响应信息。比方,在一个处理登录哀求的Servlet中:

  1. protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2.     // 获取用户名和密码
  3.     String username = request.getParameter("username");
  4.     String password = request.getParameter("password");
  5.     // 进行登录验证等业务逻辑处理
  6.     if (isValidUser(username, password)) {
  7.         response.getWriter().println("登录成功");
  8.     } else {
  9.         response.getWriter().println("登录失败");
  10.     }
  11. }
复制代码

  • 如果service()方法执行期间发生错误,可抛出ServletException或UnavailableException异常。若UnavailableException指示实例永世不可用,容器将调用destroy()方法释放实例。

  • 服务终止

    • 当容器检测到Servlet实例应被移除时,调用destroy()方法释放资源,如关闭数据库毗连、保存数据等。比方:

  1. public void destroy() {
  2.     // 释放资源的逻辑,如关闭数据库连接
  3.     if (connection!= null) {
  4.         try {
  5.             connection.close();
  6.         } catch (SQLException e) {
  7.             e.printStackTrace();
  8.         }
  9.     }
  10.     super.destroy();
  11. }
复制代码

  • destroy()方法调用后,容器释放Servlet实例,由Java垃圾收集器采取。若再次需要该Servlet处理哀求,容器会创建新的实例。
(三)Servlet的体系结构

Servlet规范基于几个关键类运转,其中ServletConfig、ServletRequest和ServletResponse与Servlet自动关联。ServletConfig在初始化时传递给Servlet,用于获取Servlet的配置属性;ServletRequest和ServletResponse在哀求处理时传递给Servlet,分别用于获取哀求信息和设置响应信息。
在Tomcat容器中,存在门面计划模式的应用。比方,StandardWrapper和StandardWrapperFacade实现了ServletConfig接口,传给Servlet的是StandardWrapperFacade对象,它能包管Servlet获取到所需数据而不暴露无关数据。同样,ServletContext也有类似结构,Servlet中获取的实际对象是ApplicationContextFacade,用于获取应用的相关信息。
二、Servlet的基本利用与配置

(一)创建Servlet类

创建Servlet类需要继承HttpServlet类并重写相应方法。比方,创建一个简单的HelloWorldServlet:
  1. import javax.servlet.ServletException;
  2. import javax.servlet.http.HttpServlet;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpServletResponse;
  5. import java.io.IOException;
  6. import java.io.PrintWriter;
  7. public class HelloWorldServlet extends HttpServlet {
  8.     @Override
  9.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  10.         // 设置响应内容类型为HTML
  11.         response.setContentType("text/html");
  12.         // 获取输出流对象
  13.         PrintWriter out = response.getWriter();
  14.         // 输出HTML内容
  15.         out.println("<html><body>");
  16.         out.println("<h1>Hello, World!</h1>");
  17.         out.println("</body></html>");
  18.     }
  19. }
复制代码
(二)在web.xml中配置Servlet

在web.xml文件中,需要配置Servlet的相关信息,包罗名称、类名、初始化参数和映射路径等。以下是上述HelloWorldServlet的配置示例:
  1. <servlet>
  2.     <servlet-name>HelloWorldServlet</servlet-name>
  3.     <servlet-class>com.example.HelloWorldServlet</servlet-class>
  4.     <init-param>
  5.         <param-name>greeting</param-name>
  6.         <param-value>Hello!</param-value>
  7.     </init-param>
  8. </servlet>
  9. <servlet-mapping>
  10.     <servlet-name>HelloWorldServlet</servlet-name>
  11.     <url-pattern>/hello</url-pattern>
  12. </servlet-mapping>
复制代码
(三)Servlet与JSP的关系

JSP本质上是Servlet的扩展,JSP页面在第一次被访问时会被翻译成Servlet并执行。在Tomcat中,通过JspServlet来处理JSP页面的翻译工作,其在conf/web.xml中有相应的配置,会拦截全部以.jsp或.jspx为后缀的哀求并进行翻译。比方,一个简单的JSP页面:
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <title>JSP Example</title>
  6. </head>
  7. <body>
  8.     <%
  9.     // 这里可以嵌入Java代码
  10.     String message = "This is a JSP page.";
  11.     %>
  12.     <h1><%=message%></h1>
  13. </body>
  14. </html>
复制代码
当访问该JSP页面时,Tomcat会将其翻译成对应的Servlet类并执行,终极将生成的HTML内容返回给客户端。
三、Servlet 3.0新特性详解

(一)异步处理支持


  • 解决的问题

    • 在Servlet 3.0之前,Servlet线程在处理业务时一直处于壅闭状态,直到业务处理完毕才气输出响应并结束线程。这在业务处理耗时较长(如数据库操作、跨网络调用等)的情况下,会导致服务器资源占用过多,影响并发处理速度。

  • 异步处理流程

    • Servlet接收到哀求后,可先进行预处理,然后将哀求转交给异步线程处理,自身返回容器。异步线程处理完业务后,可直接生成响应数据或转发哀求给其他Servlet。比方:

  1. @WebServlet(urlPatterns = "/asyncDemo", asyncSupported = true)
  2. public class AsyncDemoServlet extends HttpServlet {
  3.     @Override
  4.     public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
  5.         resp.setContentType("text/html;charset=UTF-8");
  6.         PrintWriter out = resp.getWriter();
  7.         out.println("进入Servlet的时间:" + new Date() + ".");
  8.         out.flush();
  9.         // 启动异步处理
  10.         AsyncContext ctx = req.startAsync();
  11.         // 执行异步业务逻辑
  12.         new Thread(new AsyncTask(ctx)).start();
  13.         out.println("结束Servlet的时间:" + new Date() + ".");
  14.         out.flush();
  15.     }
  16. }
  17. class AsyncTask implements Runnable {
  18.     private AsyncContext ctx;
  19.     public AsyncTask(AsyncContext ctx) {
  20.         this.ctx = ctx;
  21.     }
  22.     @Override
  23.     public void run() {
  24.         try {
  25.             // 模拟耗时业务操作,这里等待5秒
  26.             Thread.sleep(5000);
  27.             PrintWriter out = ctx.getResponse().getWriter();
  28.             out.println("业务处理完毕的时间:" + new Date() + ".");
  29.             out.flush();
  30.             ctx.complete();
  31.         } catch (Exception e) {
  32.             e.printStackTrace();
  33.         }
  34.     }
  35. }
复制代码

  • 配置方式

    • 利用传统web.xml配置时,在标签中添加true子标签。利用注解配置时,在@WebServlet或@WebFilter注解中设置asyncSupported = true。

(二)新增的注解支持


  • 简化配置

    • Servlet 3.0新增了多个注解,用于简化Servlet、过滤器和监听器的声明,使web.xml摆设描述文件不再是必选的。

  • 常用注解介绍

    • @WebServlet:用于将类声明为Servlet,可配置名称、URL匹配模式、加载顺序、初始化参数、异步支持等属性。比方:

  1. @WebServlet(urlPatterns = {"/demoServlet"}, asyncSupported = true, loadOnStartup = 1, name = "DemoServlet", displayName = "DS", initParams = {@WebInitParam(name = "param1", value = "value1")})
  2. public class DemoServlet extends HttpServlet {...}
复制代码

  • @WebFilter:用于声明过滤器,可配置过滤器名称、URL匹配模式、应用的Servlet、转发模式、初始化参数、异步支持等属性。比方:
  1. @WebFilter(servletNames = {"DemoServlet"}, filterName = "DemoFilter")
  2. public class DemoFilter implements Filter {...}
复制代码

  • @WebListener:用于将类声明为监听器,被标注的类需实现至少一个相关接口,如ServletContextListener等。比方:
  1. @WebListener("This is a demo listener")
  2. public class SimpleListener implements ServletContextListener {...}
复制代码

  • @MultipartConfig:辅助HttpServletRequest对上传文件的支持,标注在Servlet上,表现盼望处理的哀求的MIME类型是multipart/form-data,并可配置文件巨细阈值、存放地点、允许上传的最大值等属性。比方:
  1. @MultipartConfig(fileSizeThreshold = 1024 * 1024, location = "/tmp/uploads", maxFileSize = 1024 * 1024 * 5, maxRequestSize = 1024 * 1024 * 10)
  2. @WebServlet("/uploadServlet")
  3. public class UploadServlet extends HttpServlet {...}
复制代码
(三)可插性支持


  • 功能扩充方式

    • 可插性支持允许在不修改已有Web应用的前提下,通过将按照一定格式打成的JAR包放到WEB-INF/lib目录下,实现新功能的扩充。

  • web-fragment.xml文件

    • Servlet 3.0引入了web-fragment.xml摆设描述文件,存放在JAR文件的META-INF目录下,可包含web.xml中能界说的内容。比方:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-fragment xmlns="http://java.sun.com/xml/ns/javaee"
  3.                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
  4.                xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3.0.xsd"
  5.                metadata-complete="true">
  6.     <servlet>
  7.         <servlet-name>FragmentServlet</servlet-name>
  8.         <servlet-class>com.example.FragmentServlet</servlet-class>
  9.     </servlet>
  10.     <servlet-mapping>
  11.         <servlet-name>FragmentServlet</servlet-name>
  12.         <url-pattern>/fragment</url-pattern>
  13.     </servlet-mapping>
  14. </web-fragment>
复制代码

  • 加载顺序规则

    • web-fragment.xml包含和两个可选顶层标签,用于指定加载顺序。标识文件,通过和子标签指定与其他文件的相对位置关系,还可利用表现除自身外的其他文件,其优先级低于明白指定的相对位置关系。

(四)ServletContext的性能增强


  • 动态摆设与配置

    • ServletContext对象在Servlet 3.0中支持在运行时动态摆设Servlet、过滤器、监听器,以及为Servlet和过滤器增加URL映射等。比方,动态添加Servlet:

  1. ServletContext context = getServletContext();
  2. ServletRegistration.Dynamic dynamicServlet = context.addServlet("DynamicServlet", DynamicServlet.class);
  3. dynamicServlet.addMapping("/dynamic");
  4. dynamicServlet.setLoadOnStartup(2);
复制代码

  • 与相关接口和类的共同

    • 这些动态配置方法通常在ServletContextListener的contextInitialized方法或ServletContainerInitializer的onStartup()方法中调用。ServletContainerInitializer是Servlet 3.0新增接口,容器启动时利用JAR服务API发现实在现类,并将WEB-INF/lib目录下JAR包中的类交给onStartup()方法处理,通常需利用@HandlesTypes注解指定处理的类。

(五)HttpServletRequest对文件上传的支持


  • 简化文件上传操作

    • Servlet 3.0之前,处理上传文件需利用第三方框架,而现在HttpServletRequest提供了getPart()和getParts()方法用于从哀求中解析上传文件,每个文件用javax.servlet.http.Part对象表现,该接口提供了处理文件的简易方法,如write()、delete()等。比方:

  1. @WebServlet("/upload")
  2. @MultipartConfig
  3. public class FileUploadServlet extends HttpServlet {
  4.     @Override
  5.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  6.         Part filePart = request.getPart("file");
  7.         if (filePart!= null) {
  8.             filePart.write("/tmp/uploadedFile.txt");
  9.             response.getWriter().println("文件上传成功");
  10.         } else {
  11.             response.getWriter().println("没有选择文件上传");
  12.         }
  13.     }
  14. }
复制代码

  • 配置与注意事项

    • 需共同@MultipartConfig注解对上传操作进行自界说配置,如限制文件巨细和保存路径等。注意,如果哀求的MIME类型不是multipart/form-data,利用上述方法会抛出异常。

四、Servlet在实际应用中的场景与案例分析

(一)在Web应用中的常见应用场景


  • 处理用户哀求与业务逻辑

    • Servlet可接收用户在浏览器中输入的URL哀求,根据哀求参数进行业务逻辑处理,如登录验证、数据查询与更新等。比方,在一个电商网站中,用户登录时,LoginServlet接收用户名和密码,与数据库中的用户信息进行比对,验证用户身份。

  • 生成动态页面内容

    • 通过获取数据库数据或其他业务逻辑处理结果,Servlet可以动态生成HTML、XML等格式的页面内容返回给客户端。比如,一个新闻网站的NewsServlet根据用户哀求的新闻类别,从数据库中查询相关新闻数据,然后生成包含新闻列表的HTML页面返回给用户。

(二)案例分析:利用Servlet实现简单的用户登录系统


  • 功能需求

    • 用户在登录页面输入用户名和密码,点击登录按钮后,哀求发送到服务器端的LoginServlet。LoginServlet验证用户名和密码是否精确,如果精确,跳转到欢迎页面;如果错误,返回错误提示信息到登录页面。

  • 代码实现

    • 登录页面(login.jsp)

  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <title>Login Page</title>
  6. </head>
  7. <body>
  8.     <h1>Login</h1>
  9.     <form action="login" method="post">
  10.         <label for="username">Username:</label><input type="text" id="username" name="username">
  11.         <label for="password">Password:</label><input type="password" id="password" name="password">
  12.         <input type="submit" value="Login">
  13.     </form>
  14. </body>
  15. </html>
复制代码

  • LoginServlet.java
  1. import javax.servlet.ServletException;
  2. import javax.servlet.http.HttpServlet;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpServletResponse;
  5. import java.io.IOException;
  6. import java.io.PrintWriter;
  7. public class LoginServlet extends HttpServlet {
  8.     @Override
  9.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  10.         // 设置响应内容类型为HTML
  11.         response.setContentType("text/html");
  12.         // 获取输出流对象
  13.         PrintWriter out = response.getWriter();
  14.         // 获取用户名和密码
  15.         String username = request.getParameter("username");
  16.         String password = request.getParameter("password");
  17.         // 假设这里进行简单的用户名和密码验证,实际应用中应与数据库比对
  18.         if ("admin".equals(username) && "123456".equals(password)) {
  19.             // 登录成功,跳转到欢迎页面
  20.             response.sendRedirect("welcome.jsp");
  21.         } else {
  22.             // 登录失败,返回错误提示
  23.             out.println("<html><body>");
  24.             out.println("<h1>Login Failed</h1>");
  25.             out.println("<p>Invalid username or password.</p>");
  26.             out.println("</body></html>");
  27.         }
  28.     }
  29. }
复制代码

  • web.xml配置
  1. <servlet>
  2.     <servlet-name>LoginServlet</servlet-name>
  3.     <servlet-class>com.example.LoginServlet</servlet-class>
  4. </servlet>
  5. <servlet-mapping>
  6.     <servlet-name>LoginServlet</servlet-name>
  7.     <url-pattern>/login</url-pattern>
  8. </servlet-mapping>
复制代码

  • 欢迎页面(welcome.jsp)
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <title>Welcome</title>
  6. </head>
  7. <body>
  8.     <h1>Welcome, <%= request.getParameter("username") %>!</h1>
  9. </body>
  10. </html>
复制代码
通过这个案例,可以看到Servlet在处理用户哀求、验证用户身份以及控制页面跳转等方面的实际应用,它是构建Java Web应用的重要基础组件,在实际开辟中还有更多复杂和高级的应用场景等待开辟者去探索和实践。
五、总结与展望

Servlet作为Java Web开辟的焦点技术之一,在服务器端处理哀求和生成响应方面有着不可替代的作用。从其基本的工作原理、生命周期到配置利用,再到Servlet 3.0带来的一系列新特性,都为Java Web开辟提供了更强大、更灵活的工具。在实际应用中,它广泛应用于各种Web系统的构建,从简单的网站到复杂的企业级应用。随着技术的不停发展,Servlet也在不停演进,未来大概会在性能优化、与新兴技术的融合等方面有更多的突破,开辟者需要持续关注其发展动态,以便更好地利用Servlet构建高效、稳定的Web应用。
作者:代老师的编程课
出处:https://zthinker.com/
如果你喜欢本文,请长按二维码,关注 Java码界探秘
.


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

宝塔山

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表