Servlet

Servlet

Servlet是一个Java程序 是运行在服务器上 处理客户端请求并作出响应

image-20251204192236544

Servlet声明周期

image-20251204192248116

生命周期的各个阶段

image-20251204192258512

Servlet构造方法

构造方法只有首次调用Servlet时,会被执行,后续请求不在执行

1
2
3
4
5
public HelloServlet() {
//1.只有首次会执行
System.out.println("创建HelloServlet对象");
}

init()方法

init方法被设计成只调用一次

它在第一次创建Servelt时,被调用,在后续每次用户请求时,不再调用。因此,它是用于一次性初始化。

1
2
3
4
5
6
7
@Override
public void init(ServletConfig config) throws ServletException {
//2.只有首次会执行
System.out.println("开始初始化");
super.init(config);
}

service方法

service()方法是执行实际任务的主要方法

Servlet容器(即Web服务器)调用service()方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

1
2
3
4
5
6
7
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//3.每次刷新都执行
System.out.println("service方法执行");
super.service(req, resp);
}

doGet()方法

get请求来自于一个URL的正常请求,或者来自于一个未指定Method的HTML表单,它由doGet()方法处理。

1
2
3
4
5
6
7
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

//4.由service方法决定是调用doGet方法还是doPost等方法
System.out.println("doGet方法执行");
}

doPost()方法

post请求来自于一个特别指定了Method为POST的HTML表单,它由doPost()方法处理。

1
2
3
4
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}

destroy()方法

destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

1
2
3
4
5
6
7
@Override
public void destroy() {
//销毁时,执行
System.out.println("destroy方法执行");
super.destroy();
}

@webservlet注解的作用

Servlet3.0提供了注解(annotation),我们可以不用在web.xml里面配置servlet,只需要加上@WebServlet注解就可以修改该servlet的属性了。web.xml可以配置的servlet属性,在@WebServlet中都可以配置。

1
2
3
@WebServlet(name = "MyHelloServlet", urlPatterns = "/hello")
//name:相当于 <servlet-name>,用于标识这个 Servlet 的名字(可选)
//urlPatterns:相当于 <url-pattern>,指定访问路径(必填)

可以通过 @WebInitParam 来设置初始化参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@WebServlet(
urlPatterns = "/hello",
initParams = {
@WebInitParam(name = "websiteName", value = "MyAwesomeSite"),
@WebInitParam(name = "adminEmail", value = "admin@example.com")
}
)
public class HelloServlet extends HttpServlet {

@Override
public void init() throws ServletException {
ServletConfig config = getServletConfig();
String name = config.getInitParameter("websiteName");
String email = config.getInitParameter("adminEmail");
System.out.println("网站名称:" + name);
System.out.println("管理员邮箱:" + email);
}

protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
// 处理请求
}
}

@WebServlet 的属性列表

213.png

servlet的url-pattern匹配规则

url-pattern 是设置映射关系的 它支持三模式

精准模式

1
2
3
4
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello-servlet</url-pattern>
</servlet-mapping>

路径匹配

以/ 或者 /*结尾是匹配路径

1
2
3
4
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello-servlet/*</url-pattern>
</servlet-mapping>

后缀匹配

1
2
3
4
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>

传入参数获取参数

将参数存储在web.xml的init-param中,可以给程序提供更多的灵活性。可以在init启动的时候getInitParameter(“参数名”)获取值

1
2
3
4
5
6
7
8
9
10
11
12
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>org.example.demo1.HelloServlet</servlet-class>
<init-param>
<param-name>name</param-name>
<param-value>moonsec</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello-servlet</url-pattern>
</servlet-mapping>
1
2
3
4
public void init() {
message = "Hello World!";
System.out.println(getInitParameter("name"));
}

也可以在doGet方法里使用req.getParameter来获取参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.name=req.getParameter("name");
this.age=req.getParameter("age");
System.out.println("doGet方法,每次请求调用");
resp.setContentType("text/html; charset=UTF-8");
PrintWriter out=resp.getWriter();
out.println("<html><body>");
out.println("<h1>"+message+"</h1>");
out.println(name);
out.println(":");
out.println(age);
out.println("</html></body>");
// super.doGet(req, resp);
}

Servlet 请求和响应

Request

Request即HttpRequest,可以获取客户端相关的信息、获取请求头以及获取请求参数等。

获取客户端相关的信息

常使用的API有如下

1
2
3
4
5
6
7
8
9
10
11
getRequestURL //-- 返回客户端发出请求完整URL

getRequestURI //-- 返回请求行中的资源名部分

getQueryString //-- 返回请求行中的参数部分

getRemoteAddr //-- 返回发出请求的客户机的IP地址

getMethod //-- 得到客户机请求方式

getContextPath //-- 获得当前web应用虚拟目录名称 -- 在写路径时不要将web应用的虚拟路径的名称写死, 应该在需要写web应用的名称

获取请求参数

1
2
3
4
5
6
7
getParameter(String name) //--- String 通过name获得值

getParameterValues(String name) //--- String[ ] 通过name获得多值 checkbox

getParameterMap() //--- Map<String,String[ ]> key :name value: 多值 将查询的参数保存在一个Map中

getParameterNames() //--- Enumeration<String> 获得所有name的地方通过getContextPath方法动态获取
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
@WebServlet("/request")
public class RequestServlet extends HttpServlet {

@Override
public void init() throws ServletException {
super.init();
}

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=UTF-8");
//获取客户端数据
System.out.println("获取客户端数据");
System.out.println("获取请求url:"+req.getRequestURL());
System.out.println("获取请求参数:"+req.getQueryString());
System.out.println("获取请求方法:"+req.getMethod());
System.out.println("获取请求ip:"+req.getRemoteAddr());
System.out.println("获取虚拟目录:"+req.getContextPath());
System.out.println("获取servlet名称:"+req.getServletPath());
//获取参数数据
System.out.println("获取参数数据");
System.out.println("获取Get请求参数:"+req.getQueryString());
String username=req.getParameter("username");
Integer age=Integer.parseInt(req.getParameter("age"));
System.out.println(String.format("username is %s and age is %d ", username, age));
resp.getWriter().println(String.format("username is %s and age is %d ", username, age));

if (req.getQueryString()!= null){
resp.getWriter().write("只能写文本");
}

for (String hobby : req.getParameterValues("hobby")) {
System.out.println(hobby);
}

Map<String, String[]> parameterMap = req.getParameterMap();//获取所有请求
for(String key:parameterMap.keySet()){//遍历key
for (String s: parameterMap.get(key)){//根据key遍历值
System.out.println(s);
}
// System.out.println("参数:"+key+" 值:"+parameterMap.get(key));
}

Enumeration<String> parameterNames = req.getParameterNames();
while (parameterNames.hasMoreElements()){
String name =(String) parameterNames.nextElement();//获取参数
String value = req.getParameter(name);
System.out.println("请求参数:" + name + " 请求值:" + value);
}
}


@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}

@Override
public void destroy() {
super.destroy();
}
}

response

响应返回信息

1
2
3
4
5
6
7
8
9
//响应返回信息
response.getWriter() //获取输出字符流
resp.getWriter().println(); //打印文本和其他数据类型
resp.getWriter().write(); //只能打印文本
resp.setContentType("text/html; charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.sendRedirect("xxx.html");//跳转
resp.setStatus(301);
resp.setHeader("Location", "fail.html");

请求转发和跳转

请求转发,是使用RequestDispatcher资源调度,将请求从当前资源交给下一个资源处理,下一个资源可以是servlet,也可以是JSP。转发的过程中,只有一次请求和一次响应,并且地址不变。

客户端跳转 sendRedirect ,直接跳转,不会转发请求

服务器转发 getRequestDispatcher ,会转发请求

HttpSession session = req.getSession(); 创建seesion对象

HttpServletRequest 接口中的 getSession() 方法用于获取与当前请求关联的会话对象,如果不存在会话,则创建一个新的会话。

LoginServlet

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
package com.example.servlet2;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Map;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=UTF-8");
Map<String, String[]> parameterMap = req.getParameterMap();
HttpSession session = req.getSession();
String username = req.getParameter("username");
if(parameterMap.containsKey("username") && parameterMap.containsKey("password")){
if(req.getParameter("username").equals("admin")&&req.getParameter("password").equals("123456")){
session.setAttribute("user",username);
// req.getRequestDispatcher("main").forward(req,resp);
resp.sendRedirect("main");
}else {
resp.getWriter().println("账号或密码错误");
}
}else {
resp.getWriter().println("账号或密码不能为空");
}
// req.getRequestDispatcher("/main").forward(req,resp);//转发
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}

MainServlet

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
package com.example.servlet2;

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

@WebServlet("/main")
public class MainServlet extends HttpServlet {
public MainServlet(){

}

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String user = (String) session.getAttribute("user");
if (user != null){
resp.setContentType("text/html; charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("<h1>hello world</h1><br>");
out.println("欢迎:"+ user);
out.println("<p>There is main</p>");
}else {
resp.sendRedirect("login.jsp");
}
}
}

filter过滤器

Filter过滤器是Servlet2.3中所提供的一个过滤请求与响应的对象。

Filter过滤器既可以对客户端向服务器端发送的请求进行过滤,也可以对服务器端向客户端产生的响应进行过滤处理

image-20251204192329573

filter 的生命周期

Filter 的生命周期由 Web 容器管理,包含以下三个阶段:

  1. 初始化阶段
    • 调用 init(FilterConfig filterConfig) 方法
    • 在 Web 应用启动时执行一次
  2. 过滤阶段
    • 每次请求匹配 Filter 的 URL 模式时,调用 doFilter(ServletRequest, ServletResponse, FilterChain) 方法
  3. 销毁阶段
    • 调用 destroy() 方法
    • 在 Web 应用关闭时执行一次
1
2
3
4
5
6
7
8
9
10
11
[Web 应用启动]

init() 被调用(1次)

[每次请求匹配 Filter URL]

doFilter() 被调用(多次)

[Web 应用关闭]

destroy() 被调用(1次)

FilterChain(过滤器链)

image-20251204192340261

demo

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
package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/admin")//请求“/”的页面才会触发filter
public class Filter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter1 init");
Filter.super.init(filterConfig);
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

System.out.println("Filter1 req");
filterChain.doFilter(servletRequest,servletResponse);//将请求和响应传给下一个对象
System.out.println("Filter1 resp");//响应阶段的代码只在 doFilter() 后面执行,等整个请求处理完成,响应返回时,再继续执行当前 Filter 中 doFilter() 后面的代码

}

@Override
public void destroy() {
System.out.println("Filter1 destory");
Filter.super.destroy();
}
}

设置字符

1
2
3
4
5
6
7
8
9
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
req.setCharacterEncoding("utf-8");
res.setCharacterEncoding("utf-8");
res.setContentType("text/html;charset=UTF-8");
String name = req.getParameter("name");
res.getWriter().println(name);
chain.doFilter(req,res);
}

filter登录验证

LoginServlet

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
package Servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Map;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
public LoginServlet(){}

@Override
public void init() throws ServletException {
super.init();
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
HttpSession session = req.getSession();
Map<String, String[]> parameterMap = req.getParameterMap();
if (parameterMap.containsKey("username")&&parameterMap.containsKey("password")){
String username = req.getParameter("username");
if (req.getParameter("username").equals("admin")&&req.getParameter("password").equals("123456")){
session.setAttribute("user",username);
resp.sendRedirect("main");
}else {
resp.getWriter().println("账号或密码错误,请重新输入");
}
}else {
resp.getWriter().println("账号或密码校验错误,请重新输入");
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}

@Override
public void destroy() {
super.destroy();
}
}

MainServlet

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
package Servlet;

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

@WebServlet("/main")
public class MainServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
HttpSession session = req.getSession();
String user =(String) session.getAttribute("user");
// if (user != null){
out.println("欢迎 【"+user+"】 访问");
// }else {
// resp.sendRedirect("login.jsp");
// }
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}

MainFilter

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
package Filter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter("/*") // 拦截所有请求
public class MainFilter extends HttpFilter {

@Override
protected void doFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain)
throws IOException, ServletException {
String url = req.getRequestURI().toString(); // 获取当前请求的 URI

if (!url.endsWith("jsp")){ // 如果不是以 .jsp 结尾的资源
HttpSession session = req.getSession();
String user = (String) session.getAttribute("user");
System.out.println(user);

if (user == null && !url.endsWith("login")){ // 用户未登录 且 不是访问 login 资源
resp.sendRedirect("login.jsp"); // 跳转到登录页
return;
}
}

chain.doFilter(req, resp); // 放行请求
}
}

ServletContext

ServletContext全局唯一,它是属于整个Web应用程序的,我们可以通过getServletContext()来获取到此对象。

设置ServletContext

1
req.getServletContext().setAttribute("username","admin");

获取ServletContext

1
2
System.out.println(req.getServletContext().getAttribute("username"));
//服务器不关,任何浏览器均可访问

Servlet
http://xiaowu5.cn/2025/12/04/Servlet/
作者
5
发布于
2025年12月4日
许可协议
BY XIAOWU