【JavaWeb】三大组件之——Servlet
一、什么是ServletServlet是Server Applet的简称是用 Java 编写的服务器端程序。Servlet 被部署在 Web 服务器如 Tomcat中由服务器负责管理并调用用于处理客户端发送的请求并返回响应。Servlet 的作用可以概括为三个核心步骤接收请求数据处理请求完成响应 简单来说Servlet 就是运行在服务器上的 Java 类专门用来处理 HTTP 请求和响应。二、Servlet 的核心特点特点说明功能强大基于 Java 语言编写可调用 Java API能处理各种 HTTP 请求可移植Java 语言跨平台Servlet 可在任何支持 Java 的服务器上运行性能高效采用单例多线程模型首次实例化后驻留内存后续请求复用实例安全性高继承 Java 安全框架Servlet 容器提供额外安全机制可扩展面向对象设计支持封装、继承、多态等特性三、Servlet 的体系结构Servlet 的框架由两个核心 Java 包组成javax.servlet定义了所有 Servlet 类必须实现或扩展的通用接口和类javax.servlet.http定义了采用 HTTP 协议通信的HttpServlet 类3.1 核心接口与类的继承关系Servlet (接口) │ ▼ GenericServlet (抽象类) │ ▼ HttpServlet (抽象类) │ ▼ 自定义 Servlet (如 MyServlet)3.2 Servlet 接口中的核心方法方法声明功能描述void init(ServletConfig config)Servlet 实例化后容器调用该方法完成初始化工作ServletConfig getServletConfig()获取 Servlet 对象的配置信息String getServletInfo()返回 Servlet 的描述信息作者、版本等void service(ServletRequest req, ServletResponse res)负责响应用户请求是 Servlet 的核心方法void destroy()负责释放 Servlet 占用的资源四、Servlet 的生命周期Servlet 的生命周期由Web 容器如 Tomcat管理分为以下四个阶段4.1 生命周期图解4.2 各阶段详解① 加载和实例化阶段触发时机容器启动时配置了load-on-startup客户端首次请求该 Servlet 时过程容器通过 Java 反射调用 Servlet 的无参构造方法创建实例注意事项编写 Servlet 时不要提供带参数的构造方法② 初始化阶段initpublicvoidinit(ServletConfigconfig)throwsServletException{// 初始化代码加载配置文件、建立数据库连接等super.init(config);}特点只执行一次用途完成一些初始化工作如加载配置文件、建立数据库连接、创建必要对象等参数ServletConfig对象包含了 web.xml 或WebServlet中配置的初始化参数③ 服务阶段servicepublicvoidservice(ServletRequestreq,ServletResponseres)throwsServletException,IOException{// 处理请求的核心方法}特点每次请求都会执行过程容器为每个请求创建ServletRequest和ServletResponse对象调用service()方法处理请求service()方法根据请求类型GET/POST/PUT/DELETE 等分派到doGet()、doPost()等方法线程模型Servlet 采用单例多线程模式多个请求共享同一个 Servlet 实例每个请求由独立线程处理④ 销毁阶段destroypublicvoiddestroy(){// 释放资源关闭数据库连接、清理临时文件等super.destroy();}触发时机服务器关闭、Web 应用被移除、Servlet 被卸载特点只执行一次用途释放 Servlet 占用的资源如关闭数据库连接、清理临时文件等4.3 生命周期执行流程图五、Servlet 的配置方式Servlet 的配置有两种方式web.xml 配置和注解配置。5.1 web.xml 配置方式传统方式在WEB-INF/web.xml文件中进行配置?xml version1.0 encodingUTF-8?web-appxmlnshttp://xmlns.jcp.org/xml/ns/javaeexmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsdversion4.0!-- Servlet 配置 --servlet!-- Servlet 名称自定义 --servlet-nameHelloServlet/servlet-name!-- Servlet 类的全限定名 --servlet-classcom.example.servlet.HelloServlet/servlet-class!-- 初始化参数 --init-paramparam-nameencoding/param-nameparam-valueUTF-8/param-value/init-param!-- 启动时加载顺序数字越小优先级越高 --load-on-startup1/load-on-startup/servlet!-- Servlet 映射配置 --servlet-mappingservlet-nameHelloServlet/servlet-name!-- 访问路径 --url-pattern/hello/url-pattern/servlet-mapping/web-app5.2 注解配置方式推荐使用WebServlet注解无需 web.xml 配置packagecom.example.servlet;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.PrintWriter;// 使用 WebServlet 注解配置WebServlet(nameHelloServlet,// Servlet 名称urlPatterns/hello,// URL 映射路径initParams{// 初始化参数WebInitParam(nameencoding,valueUTF-8)},loadOnStartup1// 启动加载顺序)publicclassHelloServletextendsHttpServlet{OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{// 设置响应内容类型和编码resp.setContentType(text/html;charsetUTF-8);// 获取输出流PrintWriteroutresp.getWriter();out.println(html);out.println(headtitleHello Servlet/title/head);out.println(body);out.println(h1Hello, Servlet!/h1);out.println(p这是我的第一个 Servlet 程序/p);out.println(/body);out.println(/html);}OverrideprotectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{// 设置请求编码解决中文乱码req.setCharacterEncoding(UTF-8);// 获取表单参数Stringusernamereq.getParameter(username);Stringpasswordreq.getParameter(password);// 处理业务逻辑...// 转发到结果页面req.setAttribute(msg,登录成功);req.getRequestDispatcher(/result.jsp).forward(req,resp);}}5.3 WebServlet 注解属性详解属性名类型功能描述等价于 web.xmlnameString指定 Servlet 的名称servlet-namevalueString[]等价于urlPatternsurl-patternurlPatternsString[]指定 URL 匹配模式url-patternloadOnStartupint指定启动加载顺序load-on-startupinitParamsWebInitParam[]指定初始化参数init-paramasyncSupportedboolean是否支持异步操作async-supporteddescriptionStringServlet 描述信息descriptiondisplayNameStringServlet 显示名称display-name六、Servlet 处理请求的流程6.1 请求处理完整流程6.2 HttpServlet 常用方法方法功能描述doGet(HttpServletRequest, HttpServletResponse)处理 GET 请求doPost(HttpServletRequest, HttpServletResponse)处理 POST 请求doPut(HttpServletRequest, HttpServletResponse)处理 PUT 请求doDelete(HttpServletRequest, HttpServletResponse)处理 DELETE 请求doHead(HttpServletRequest, HttpServletResponse)处理 HEAD 请求doOptions(HttpServletRequest, HttpServletResponse)处理 OPTIONS 请求七、Servlet 线程安全问题由于 Servlet 采用单例多线程模型多个请求共享同一个实例因此需要注意线程安全问题。7.1 线程安全问题示例WebServlet(/unsafe)publicclassUnsafeServletextendsHttpServlet{// ❌ 错误实例变量被多线程共享存在线程安全问题privateintcount0;OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{count;// 多个线程同时操作结果不可预期resp.getWriter().println(Count: count);}}7.2 解决方案WebServlet(/safe)publicclassSafeServletextendsHttpServlet{// ✅ 正确使用局部变量每个线程独立OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{intcount0;// 局部变量线程安全count;resp.getWriter().println(Count: count);}// ✅ 正确使用同步代码块但会影响性能privatefinalObjectlocknewObject();privateintsharedCount0;protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{synchronized(lock){sharedCount;resp.getWriter().println(Shared Count: sharedCount);}}}7.3 线程安全最佳实践建议说明避免使用实例变量尽量使用局部变量存储请求相关数据使用线程安全类如ConcurrentHashMap、AtomicInteger等同步关键代码必要时使用synchronized或Lock使用请求域存储数据通过request.setAttribute()传递数据八、ServletContext 与 ServletConfig8.1 ServletConfig单个 Servlet 配置ServletConfig对象代表当前 Servlet 的配置信息每个 Servlet 独享一个ServletConfig。Overridepublicvoidinit(ServletConfigconfig)throwsServletException{super.init(config);// 获取初始化参数Stringencodingconfig.getInitParameter(encoding);System.out.println(编码配置encoding);// 获取 Servlet 名称StringservletNameconfig.getServletName();System.out.println(Servlet 名称servletName);}8.2 ServletContext全局应用配置ServletContext对象代表整个 Web 应用所有 Servlet 共享同一个ServletContext。WebServlet(/context)publicclassContextServletextendsHttpServlet{OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{// 获取 ServletContextServletContextcontextgetServletContext();// 获取全局初始化参数StringdbUrlcontext.getInitParameter(dbUrl);// 存储全局属性所有 Servlet 共享context.setAttribute(appName,MyWebApp);// 获取真实路径StringrealPathcontext.getRealPath(/upload);// 获取资源输入流InputStreamiscontext.getResourceAsStream(/WEB-INF/config.properties);}}8.3 两者对比特性ServletConfigServletContext作用范围单个 Servlet整个 Web 应用获取方式getServletConfig()getServletContext()参数配置init-paramcontext-param数据共享不共享所有 Servlet 共享九、请求转发与重定向9.1 请求转发Forward// 获取请求分发器RequestDispatcherdispatcherreq.getRequestDispatcher(/target.jsp);// 转发请求dispatcher.forward(req,resp);特点服务器内部跳转URL 不变请求对象共享适用场景MVC 模式中的控制器转发到视图9.2 重定向Redirect// 发送重定向响应resp.sendRedirect(/target.jsp);// 或重定向到外部网站resp.sendRedirect(https://www.example.com);特点客户端重新发起请求URL 改变请求对象不共享适用场景登录成功后跳转、跨域跳转9.3 两者对比特性请求转发Forward重定向Redirect跳转方式服务器内部客户端重新请求URL 变化不变改变请求对象共享不共享范围同一服务器内可跨域效率高低两次请求十、完整示例用户登录 Servletpackagecom.example.servlet;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.PrintWriter;/** * 用户登录 Servlet 示例 */WebServlet(nameLoginServlet,urlPatterns/login)publicclassLoginServletextendsHttpServlet{Overridepublicvoidinit()throwsServletException{System.out.println(LoginServlet 初始化...);}OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{// 显示登录页面resp.setContentType(text/html;charsetUTF-8);PrintWriteroutresp.getWriter();out.println(!DOCTYPE html);out.println(htmlheadtitle登录/title/headbody);out.println(h2用户登录/h2);out.println(form action/login methodpost);out.println(用户名input typetext nameusernamebrbr);out.println(密nbsp;nbsp;码input typepassword namepasswordbrbr);out.println(input typesubmit value登录);out.println(/form/body/html);}OverrideprotectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{// 设置请求编码req.setCharacterEncoding(UTF-8);// 获取请求参数Stringusernamereq.getParameter(username);Stringpasswordreq.getParameter(password);// 简单的业务逻辑验证if(admin.equals(username)123456.equals(password)){// 登录成功重定向到首页req.getSession().setAttribute(user,username);resp.sendRedirect(/index.jsp);}else{// 登录失败请求转发回登录页并显示错误信息req.setAttribute(error,用户名或密码错误);req.getRequestDispatcher(/login.jsp).forward(req,resp);}}Overridepublicvoiddestroy(){System.out.println(LoginServlet 销毁...);}}总结本文详细介绍了 JavaWeb 三大组件之一的Servlet包括知识点核心内容Servlet 定义运行在服务器端的 Java 程序处理 HTTP 请求和响应核心特点功能强大、可移植、性能高效、安全性高、可扩展体系结构Servlet → GenericServlet → HttpServlet → 自定义 Servlet生命周期加载实例化 → init() → service() → destroy()配置方式web.xml 配置 和 WebServlet 注解配置线程安全单例多线程模型注意避免实例变量的线程安全问题核心对象ServletRequest、ServletResponse、ServletConfig、ServletContext页面跳转请求转发Forward和重定向Redirect如果本文对你有帮助欢迎点赞 、收藏 ⭐、关注 你的支持是我持续创作的动力