JavaWEB大神成长篇:2026 最新 Java Web 开发教程之深度剖析 Servlet 生命周期与 MVC 架构(第三期)
Servlet技术简介与应用 Servlet是JavaEE平台下的服务端小程序技术标准,基于Java语言编写,运行在Web容器中。它具有单进程多线程的运行特点,主要功能是生成动态数据并响应请求。Servlet作为动态资源技术,在MVC模式中扮演Controller层的角色,负责前后端数据交互和控制逻辑。 开发Servlet需要继承HttpServlet类并重写service方法,通过HttpSer
·
1_Servlet简介
2_Servlet初识
-
了解 Servlet 开发流程
-
创建一个 JAVAWEB 项目, 并在项目中开发一个自己的 Servlet , 继承 HttpServlet 类

-
在 MyServlet 类中重写 service 方法
-
在 service 方法中定义具体的功能代码
-
代码展示
package com.xxxxx.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.Random; public class MyServlet extends HttpServlet { /* * 可以接收浏览器的请求 * 并作出运算和响应 * service Servlet服务方法 * */ @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 动态生成数据 int num = new Random().nextInt(); String message = num % 2 == 0 ? "happy birthday" : "happy new year"; // 对浏览器作出响应 PrintWriter writer = response.getWriter(); // 该打印流指向了浏览器 writer.write(message); } }
-
-
在 web.xml 中配置 Servlet 的映射路径

-
打开浏览器请求Servlet资源

3_Servlet案例开发
-
web.xml 配置欢迎页
-
案例开发需求
-
开发过程如下
-
项目结构

-
开发登录页
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="get" action="loginServlet.do"> <table style="margin: 0px auto" width="300px" cellpadding="0px" cellspacing="0px" border="1px"> <tr> <td>用户名</td> <td> <input type="text" name="username"> </td> </tr> <tr> <td>密码</td> <td> <input type="password" name="pwd"> </td> </tr> <tr align="center"> <td colspan="2"> <input type="submit" value="登录"> </td> </tr> </table> </form> </body> </html> -
开发后台Servlet
package com.xxxxx.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @Auther: xiaowaitao * @Date: 2026/5/24 - 05 - 24 - 13:33 * @Description: com.xxxxx.servlet * @Version: 1.0 */ public class LoginServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("login servlet invoked"); // 获取请求中的数据 String username = req.getParameter("username"); String pwd = req.getParameter("pwd"); // 判断数据 String message = null; if (username.equals("xxxxx") && pwd.equals("123456")) { message = "Success"; } else { message = "Fail"; } // 作出相应 resp.getWriter().write(message); } } -
配置Servlet
<?xml version="1.0" encoding="UTF-8"?> <web-app 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_4_0.xsd" version="4.0"> <servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>com.xxxxx.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/loginServlet.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>login.html</welcome-file> </welcome-file-list> </web-app> -
运行测试
-
4_HttpServletRequest
-
回顾 http 请求:
-
http支持的请求方式:

-
post 和 get 方式提交请求的差别 (面试,重要)
-
GET在浏览器回退时是无害的,而POST会再次提交请求
-
GET产生的URL地址可以被Bookmark,而POST不可以
-
GET请求会被浏览器主动cache,而POST不会,除非手动设置
-
GET请求只能进行url编码,而POST支持多种编码方式
-
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留
-
GET请求在URL中传送的参数是有长度限制的,而POST则没有。对参数的数据类型GET只接受ASCII字符,而POST即可是字符也可是字节
-
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息
-
GET参数通过URL传递,POST放在Request body中
-
-
HttpServletRequest
-
HttpServletRequest对象代表客户端浏览器的请求,当客户端浏览器通过HTTP协议访问服务器时,HTTP请求中的所有信息都会被Tomcat所解析并封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息 -
1.获取请求行信息
-
2.获取请求头信息
public class Servlet3 extends HttpServlet { @override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException) { System.out.println(req.getRequestURL()); //返回客户端浏览器发出请求时的完整URL System.out.println(req.getRequestURI()); //返回请求行中指定资源部分 System.out.println(req.getRemoteAddr()); //返回发出请求的客户机的IP地址 System.out.println(req.getLocalAddr()); //返回WEB服务器的IP地址 System.out.println(req.getLocalPort()); //返回WEB服务器处理Http协议的连接器所监听的端口 System.out.println("主机名: " + req.getLocalName()); System.out.println("客户端PORT: " + req.getRemotePort()); System.out.println("当前项目部署名: " + req.getContextPath()); System.out.println("协议名:"+req.getScheme()); System.out.println("请求方式:"+req.getMethod()); // 根据请求头名或者请求头对应的值 System.out.println(req.getHeader("Accept")); // 获得全部的请求头名 Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()){ String headername = headerNames.nextElement(); System.out.println(headername+":"+req.getHeader(headername)); } } } -
3.获取请求数据
-
测试代码:
-
前端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 开发form表单注意事项 1_ form 不是from 2_ form表单内部不是所有的标签信息都会提交 一些输入信息 input select textarea ... ... 3_ 要提交的标签必须具备name属性 name属性的作用是让后台区分数据 id便于在前端区分数据 4_ 要提交的标签一般都要具备value属性 value属性确定我们要提交的具体的数据 5_ get post get方式 数据是通过URL携带 提交的数据只能是文本 提交的数据量不大 get方式提交的数据相对不安全 post 将数据单独打包放到请求体中 提交的数据可以是文本可以是各种文件 提交的数据量理论上没有上限 post方式提交数据相对安全 当一个表单标签 readonly只读 也是会提交数据的 hidden 隐藏 也是会提交数据 disabled 不可用 显示但是不提交 --> <form method="get" action="myServlet"> <table style="margin: 0px auto" width="300px" cellpadding="0px" cellspacing="0px" border="1px"> <tr> <td>用户名</td> <td> <input type="text" name="username" id="in1" value="12345" disabled > </td> </tr> <tr> <td>密码</td> <td> <input type="password" name="pwd"> </td> </tr> <tr> <td>性别</td> <td> <input type="radio" name="gender" value="1" checked>男 <input type="radio" name="gender" value="0">女 </td> </tr> <tr> <td>爱好</td> <td> <input type="checkbox" name="hobby" value="1">蓝球 <input type="checkbox" name="hobby" value="2">足球 <input type="checkbox" name="hobby" value="3">羽毛球 <input type="checkbox" name="hobby" value="4">乒乓球 </td> </tr> <tr> <td>个人简介</td> <td> <!-- 文本域 双标签 页面上显示的文字是双标签中的文本 不是value属性 文本域提交的数据不是value属性值,是双标签中的文本 --> <textarea name="introduce" >b</textarea> </td> </tr> <tr> <td>籍贯</td> <td> <!-- select option没有定义value属性 那么就提交option中间的文字(不推荐) --> <select name="provience"> <option value="1">a京</option> <option value="2">b津</option> <option value="3">c冀</option> </select> </td> </tr> <tr align="center"> <td colspan="2"> <input type="submit" value="提交数据"> </td> </tr> </table> </form> </body> </html> -
Servlet:
package com.xxxxx.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;import java.util.Arrays; import java.util.Enumeration; import java.util.Map; import java.util.Set; public class MyServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // req获取参数 // 如果 前端发过来的数据由数据名但是没有值, getParameter返回的是一个空字符串 "" // 获取的参数在提交的数据中名都没有,getParameter返回的是null String username = req.getParameter("username"); System.out.println("username:"+username); System.out.println("password:"+req.getParameter("pwd")); System.out.println("gender:"+req.getParameter("gender")); // hobby=1&hobby=2&hobby=3 想要获得多个同名的参数 getParameterValues 返回的是一个Sting数组 String[] hobbies = req.getParameterValues("hobby"); // textarea System.out.println("introduce:"+req.getParameter("introduce")); // select System.out.println("provience:"+req.getParameter("provience")); System.out.println("___________________________"); // 如果不知道参数的名字? // 获取所有的参数名 Enumeration<String> pNames = req.getParameterNames(); while(pNames.hasMoreElements()){ String pname = pNames.nextElement(); String[] pValues = req.getParameterValues(pname); System.out.println(pname+":"+Arrays.toString(pValues)); } System.out.println("________________________________"); Map<String, String[]> pmap = req.getParameterMap(); Set<Map.Entry<String, String[]>> entries = pmap.entrySet(); for (Map.Entry<String, String[]> entry : entries) { System.out.println(entry.getKey()+":"+Arrays.toString(entry.getValue())); } } }
-
-
5_HttpServletResponse
-
http响应部分可以分为三部分
-
响应的设置
-
ContentType响应头
-
resp.setContentType("MIME")-
该方法可通过 MIME-Type 设置响应类型
-
MIME的全称是 Multipurpose Internet Mail Extensions,即多用途互联网邮件扩展类型 -
这是 HTTP协议 中用来定义文档性质及格式的标准 -
对 HTTP传输内容类型 进行了全面定义 -
服务器通过MIME告知响应内容类型,而浏览器则通过MIME类型来确定如何处理文档
Type Meaning (描述) application/msword Microsoft Word document application/octet-stream Unrecognized or binary data application/pdf Acrobat (.pdf) file application/postscript PostScript file application/vnd.lotus-notes Lotus Notes file application/vnd.ms-excel Excel spreadsheet application/vnd.ms-powerpoint PowerPoint presentation application/x-gzip Gzip archive application/x-java-archive JAR file application/x-java-serialized-object Serialized Java object application/x-java-vm Java bytecode (.class) file application/zip Zip archive application/json JSON audio/basic Sound file in .au or .snd format audio/midi MIDI sound file audio/x-aiff AIFF sound file audio/x-wav Microsoft Windows sound file image/gif GIF image image/jpeg JPEG image image/png PNG image image/tiff TIFF image image/x-xbitmap X Windows bitmap image text/css HTML cascading style sheet text/html HTML document text/plain Plain text text/xml XML video/mpeg MPEG video clip video/quicktime QuickTime video clip -
-
-
-
设置字符型响应
-
设置字节型响应
-
设置响应编码
-
在响应中添加附加信息(文件下载)
-
测试代码
package com.xxxxx.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class MyServlet2 extends HttpServlet { @override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 设置响应码 // resp.setStatus(500); // resp.setStatus(405, "request method not supported"); // 设置响应头 // resp.setHeader("Date", "2026-5-25"); // 自定义头 // resp.setHeader("aaa", "bbb"); // 高速浏览器响应的数据是什么? 浏览器根据此头决定 数据如何应用 // 设置MIME类型 json xml 文件下载 ... ... // resp.setHeader("content-type", "type/css"); resp.setContentType("text/html"); //专门用于设置 Content-Type 响应头 resp.getWriter().write("<h1>this is tag h1</h1>"); } }
-
6_关于乱码问题
7_Servlet的继承结构

-
Servlet 接口
-
ServletConfig 接口
-
GenericServlet 抽象类
-
HttpServlet
-
继承自 GenericServlet, 针对于处理 HTTP 协议的请求所定制
-
在 HttpServlet 的 service() 方法中已经把 ServletReuqest 和 ServletResponse 转为 HttpServletRequest 和 HttpServletResponse
-
直接使用 HttpServletRequest 和 HttpServletResponse, 不再需要强转
-
实际开发中, 直接继承 HttpServlet, 并根据请求方式复写 doXxx() 方法即可

-
在我们自定义的 Servlet 中, 如果想区分请求方式, 不同的请求方式使用不同的代码处理, 那么我么重写 doGet doPost 即可
-
如果我们没有必要区分请求方式的差异, 那么我们直接重写 service 方法即可
-
要么重写 doGet doPost 要么重写 service, 必须二选一, 而且必须进行重写


-
8_Servlet的生命周期
-
概念
-
Servlet的生命周期是由容器管理的,分别经历四各阶段
阶段 次数 时机 创建 1次 第一次请求 初始化 1次 实例化之后 执行服务 多次 每次请求 销毁 1次 停止服务 -
当客户端浏览器第一次请求 Servlet 时,容器会实例化这个 Servlet,然后调用一次 init 方法,并在新的线程中执行 service 方法处理请求
-
service 方法执行完毕后容器不会销毁这个 Servlet 而是做缓存处理,当客户端浏览器再次请求这个 Servlet 时,容器会从缓存中直接找到这个 Servlet 对象,并再一次在新的线程中执行 Service 方法
-
当容器在销毁 Servlet 之前对调用一次 destory 方法
-
在 Servlet 中我们一般不要轻易使用成员变量!!!
-
如果要使用的话, 应该尽量避免对成员变量产生修改
-
如果要产生修改, 我们应该注意线程安全问题
-
如果我们自己添加线程安全编码处理, 会严重影响效率
-
综上所述:
-
-
Servlet代码
package com.xxxxx.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class MyServlet4 extends HttpServlet { // 成员变量 public MyServlet4() {// 构造一个Servlet对象的方法 System.out.println("MyServlet4 Constructor invoked"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void init() throws ServletException {// 初始化 System.out.println("MyServlet4 init invoked"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 执行服务 System.out.println("MyServlet4 service invoked"); } @Override public void destroy() {// 销毁 System.out.println("MyServlet4 destory invoked"); } } -
配置Servlet
<servlet> <servlet-name>myServlet4</servlet-name> <servlet-class>com.xxxxx.servlet.MyServlet4</servlet-class> <load-on-startup>6</load-on-startup> </servlet> <servlet-mapping> <servlet-name>myServlet4</servlet-name> <url-pattern>/myServlet4.do</url-pattern> </servlet-mapping> -
Servlet处理请求的过程
-
当浏览器基于 get方式 请求我们创建 Servlet 时,我们自定义的 Servlet 中的 doGet 方法会被执行
-
doGet方法 能够被执行并处理 get请求 的原因是,容器在启动时会解析 web工程 中 WEB-INF 目录中的 web.xml 文件,在该文件中我们配置了 Servlet 与 URI 的绑定,容器通过对请求的解析可以获取请求资源的 URI,然后找到与该 URI 绑定的 Servlet 并做实例化处理 (注意:只实例化一次,如果在缓存中能够找到这个 Servlet 就不会再做次实例化处理)
-
在实例化时会使用 Servlet接口类型 作为引用类型的定义,并调用一次 init方法 ,由于 HttpServlet 中重写了该方法所以最终执行的是 HttpServlet 中 init方法 (HttpServlet 中的 Init方法 是一个空的方法体),然后在新的线程中调用 service方法
-
由于在 HttpServlet 中重写了 Service方法 所以最终执行的是 HttpServlet 中的 service方法
-
在 service方法 中通过
request.getMethod()获取到请求方式进行判断如果是 Get方式 请求就执行 doGet方法,如果是 POST请求 就执行 doPost方法 -
如果是基于 GET方式 提交的,并且在我们自定义的 Servlet 中又重写了 HttpServlet 中的 doGet方法,那么最终会根据 Java的多态特性 转而执行我们自定义的 Servlet 中的 doGet方法

-
9_ServletConfig 和 ServletContext
-
ServletContext对象介绍
-
ServletContext对象作用
-
ServletContext对象的使用
-
全局容器
-
ServletContext对象生命周期
-
ServletConfig对象
-
测试代码
-
Servlet1
package com.xxx.testServlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Servlet1 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取Servlet对象的方式 // 通过req对象 ServletContext servletContext1 = req.getServletContext(); // 通过继承的方法 ServletContext servletContext2 = this.getServletContext(); System.out.println(servletContext1 == servletContext2); // 获取当前项目的部署名 String contextPath = servletContext1.getContextPath(); System.out.println("contextPath"+contextPath); // 将一个相对路径转化为项目的绝对路径 String fileUpload = servletContext1.getRealPath("fileUpload"); System.out.println(fileUpload); String serverInfo = servletContext1.getServerInfo(); System.out.println("servletInfo"+serverInfo); int majorVersion = servletContext1.getMajorVersion(); int minorVersion = servletContext1.getMinorVersion(); System.out.println(majorVersion+":"+minorVersion); // 获取web.xml中配置的全局的初始信息 String username = servletContext1.getInitParameter("username"); String password = servletContext1.getInitParameter("password"); System.out.println(username+":"+password); //向ServletContext对象中增加数据 域对象 List<String> data = new ArrayList<>(); Collections.addAll(data,"张三","李四","王五"); servletContext1.setAttribute("list", data); servletContext1.setAttribute("gender", "boy"); } } -
Servlet2
package com.xxx.testServlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Enumeration; import java.util.List; public class Servlet2 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); // 获取web.xml中配置的全局的初始信息 Enumeration<String> pnames = servletContext.getInitParameterNames(); while(pnames.hasMoreElements()){ String e = pnames.nextElement(); System.out.println(e+":"+servletContext.getInitParameter(e)); } List<String> list = (List<String>) servletContext.getAttribute("list"); System.out.println(list); String gender = (String)servletContext.getAttribute("gender"); System.out.println(gender); } } -
Servlet3
package com.xxx.testServlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class Servlet3 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletConfig servletConfig = this.getServletConfig(); System.out.println(servletConfig.getInitParameter("brand")); System.out.println(servletConfig.getInitParameter("screen")); } } -
Servlet4
package com.xxx.testServlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class Servlet4 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletConfig servletConfig = this.getServletConfig(); System.out.println(servletConfig.getInitParameter("pinpai")); System.out.println(servletConfig.getInitParameter("pingmu")); } } -
web.xml配置
<?xml version="1.0" encoding="UTF-8"?> <web-app 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_4_0.xsd" version="4.0"> <context-param> <param-name>username</param-name> <param-value>xxx</param-value> </context-param> <context-param> <param-name>password</param-name> <param-value>123456</param-value> </context-param> <servlet> <servlet-name>servlet1</servlet-name> <servlet-class>com.xxx.testServlet.Servlet1</servlet-class> </servlet> <servlet> <servlet-name>servlet2</servlet-name> <servlet-class>com.xxx.testServlet.Servlet2</servlet-class> </servlet> <servlet> <servlet-name>servlet3</servlet-name> <servlet-class>com.xxx.testServlet.Servlet3</servlet-class> <init-param> <param-name>brand</param-name> <param-value>ASUS</param-value> </init-param> </servlet> <servlet> <servlet-name>servlet4</servlet-name> <servlet-class>com.xxx.testServlet.Servlet4</servlet-class> <init-param> <param-name>pinpai</param-name> <param-value>联想</param-value> </init-param> <init-param> <param-name>pingmu</param-name> <param-value>京东方</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>servlet1</servlet-name> <url-pattern>/servlet1.do</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>servlet2</servlet-name> <url-pattern>/servlet2.do</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>servlet3</servlet-name> <url-pattern>/servlet3.do</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>servlet4</servlet-name> <url-pattern>/servlet4.do</url-pattern> </servlet-mapping> </web-app>
-
更多推荐


















所有评论(0)