【Java后端基础 003】Servlet 是什么?为什么 Java Web 项目都离不开它?

【Java后端基础 003】Servlet 是什么?为什么 Java Web 项目都离不开它?

📚博客主页:代码探秘者

✨专栏:《JavaSe》 其他更新ing…

❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️

🙏作者水平有限,欢迎各位大佬指点,相互学习进步!

文章目录

1️⃣ Servlet 是什么?2️⃣ Servlet 的典型用途3️⃣ Servlet 简单示例4️⃣ Servlet 不是主流了?为什么?✅ 现实情况:

5️⃣ 但为什么说“离不开 Servlet”?6️⃣ Servlet 的生命周期(了解一下)✅ 总结一句话

1.Servlet-动态web网页的神器框图加jar文件

2.入门小知识1.实现Servlet接口开发Servlet2.重写的五个方法3.配置4.流程5.证明Servlet是单例的6.重新发布7.自动加载8.查看源码

3.生命周期4.GET和POST请求的分发处理0.回顾get和post请求方法1.获取得到方式2.分发处理

5.HttpServlet继承框架重写doGet和doPostidea创建servlet程序

6.注解方式入门小案例url-pattern四种匹配方式(不做演示)

7.HttpServletRequest1.常用方法2.获取请求行常用方法案例演示URI和URL区别

3.获取请求头常见方法案例演示

4.获取请求体常用方法案例演示

5.请求转发例子1直接跳转和请求转发

ContextPath

8.乱码问题1.Request乱码问题**GET 和 POST 请求的乱码**

2.Response乱码问题

9.域对象1.getParameter2.setAttribute和getAttribute

10.HttpServletResponse1.设置响应状态码2.设置响应头3.设置响应内容案例分析

4.请求重定向5.设置 Cookie6.其他方法

在学习 Java Web 开发时,你一定听过“Servlet”这个词。虽然现在很多人用 Spring Boot,但其实它的底层,仍然离不开 Servlet。

本篇文章我们来通俗讲解:

什么是 Servlet?它在 Web 开发中是干什么的?为什么说它“不是主流”,但依然“无处不在”?

1️⃣ Servlet 是什么?

菜鸟教程:https://www.runoob.com/servlet/servlet-intro.html

简单说,Servlet 就是用 Java 写的服务器程序,用于处理客户端(如浏览器)发来的请求,并生成响应。

📦 它是 Java EE(现在叫 Jakarta EE)规范的一部分,必须运行在 Servlet 容器 中,比如 Tomcat。

2️⃣ Servlet 的典型用途

当你访问一个网站,比如提交表单、登录账号,后台就会有代码处理这些请求。这个后台处理逻辑,早期就是用 Servlet 来写的。

常见功能包括:

接收 HTTP 请求(GET / POST);读取请求参数;调用后端逻辑(如查数据库);返回 HTML 或 JSON 响应。

3️⃣ Servlet 简单示例

@WebServlet("/hello")

public class HelloServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp)

throws IOException {

resp.setContentType("text/html");

resp.getWriter().write("

Hello, Servlet!

");

}

}

部署到 Tomcat 后,访问 http://localhost:8080/hello,你就能看到响应页面。

4️⃣ Servlet 不是主流了?为什么?

✅ 现实情况:

虽然 Servlet 是 Java Web 的基础,但现在大多数开发者不会直接写 Servlet,而是用更高级的框架(如 Spring Boot、Spring MVC)来开发。

这些框架帮你封装了很多 Servlet 细节,让你只需要专注于业务逻辑,比如这样写 Controller:

@GetMapping("/hello")

public String hello() {

return "Hello, Spring!";

}

是不是比手写 HttpServletRequest、HttpServletResponse 清爽很多?

5️⃣ 但为什么说“离不开 Servlet”?

虽然我们现在不直接写 Servlet,但Spring MVC、Spring Boot 的底层依然是基于 Servlet 架构的!

📌 你写的每一个 @RestController,最终还是通过一个叫 DispatcherServlet 的 Servlet 来转发请求。

所以说:

✅ Servlet 是 Java Web 的“基础设施”, ❌ 但不是现代 Web 开发的“主流入口”。

6️⃣ Servlet 的生命周期(了解一下)

在容器(Tomcat)中,Servlet 有以下生命周期方法:

init():初始化,只执行一次;service():每次请求都会调用;destroy():销毁前调用一次,用于释放资源。

框架帮你管理这些了,但了解这个原理对调试和优化很有帮助。

✅ 总结一句话

Servlet 是 Java Web 的底层处理器,现在不常直接使用,但它依然是每个 Java Web 应用的“底座”。

1.Servlet-动态web网页的神器

框图

用户留言/评论/支付

加jar文件

tomcat目录下的libs下ng)

2.入门小知识

1.实现Servlet接口开发Servlet

public class test01 implements Servlet {

}

2.重写的五个方法

/**

* 1. 开发一个Servlet 需要 实现Servlet接口

* 2. 实现Servlet接口的方法5个

*/

@Override

public void init(ServletConfig servletConfig) throws ServletException {

}

//返回ServletConfig 也就是返回Servlet的配置

@Override

public ServletConfig getServletConfig() {

return null;

}

/**

* 1. service方法处理浏览器的请求(包括get/post)

* 2. 当浏览器每次请求Servlet时,就会调用一次service

* 3. 当tomcat调用该方法时,会把http请求的数据封装成实现ServletRequest接口的request对象

* 4. 通过servletRequest 对象,可以得到用户提交的数据

* 5. servletResponse 对象可以用于返回数据给tomcat->浏览器

*/

@Override

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

}

//返回servlet信息,使用较少

@Override

public String getServletInfo() {

return null;

}

/**

* 1. 该方法是在servlet销毁时,被调用

* 2. 只会调用一次

*/

@Override

public void destroy() {

}

3.配置

web.xml就是专门配置xml的

test01

com.lgj.servlet.test01

test01

/helloServlet

这样配置,最终访问路径

http://localhost:8082/servlet/helloServlet

4.流程

没有找到:404

5.证明Servlet是单例的

private int count=0; //属性

@Override

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

System.out.println("每访问一次,调用service()"+"第"+(++count)+"次");

}

6.重新发布

修改之后,重新发布,不用重启也行。设置快捷键Ctrl+D 自己设置的

重新发布(装载),tomcat维护的所有Sevrlet实例,会销毁掉,调用init被再次调用

7.自动加载

//load-on-startup 表示在tomcat 启动时,会自动的加载servlet实例

有 :当你在 servlet 配置中包含 元素时,这个 servlet 会在 Servlet 容器(如 Tomcat)启动时自动加载。

加载的顺序由 的值决定,值越小,优先级越高,越早被加载。 没有 :如果没有指定 ,servlet 会在第一次被请求时才被加载和实例化。

8.查看源码

进入下一级源码:Ctrl+B 或者 Alt+ —>

上一级源码:Alt+<-

Ctrl+Alt+B 查看子接口或者实现子类的源码

3.生命周期

4.GET和POST请求的分发处理

0.回顾get和post请求方法

GET和POST是HTTP协议中的两种最常见的请求方法

GET(可见,但是不安全)

数据传输:通过URL传递数据,数据附加在URL后面,以查询字符串的形式发送(例如,http://example.com/page?name=kimi&year=2024)

可见性:用户可以看到GET请求发送的所有数据,因为它们显示在URL中。

POST(不可见,安全)

数据传输:数据在请求体(body)中发送,不会显示在URL中。

安全性:相比GET,POST请求更适合发送敏感信息,因为数据不会显示在URL中。

register.html

注意url的填写和直接弄的一致

1.获取得到方式

//先转换子类

// 因为子类HttpServletRequest才有获取请求方式的方法

HttpServletRequest httpservletRequest = (HttpServletRequest) servletRequest;

String method=httpservletRequest.getMethod();

2.分发处理

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

//线程id每次调用,不一样

System.out.println("当然线程id:"+Thread.currentThread().getId());

System.out.println("每访问一次,调用service()"+"第"+(++count)+"次");

//这里演示: GET和POST请求的分发处理

//先转换子类

// 因为子类HttpServletRequest才有获取请求方式的方法

HttpServletRequest httpservletRequest = (HttpServletRequest) servletRequest;

String method=httpservletRequest.getMethod();

System.out.println("请求方式是:"+method);

if("get".equals(method)){

doGet();

}else if("post".equals(method))

{

doPost();

}

}

public void doGet(){

System.out.println("响应get请求,doGet()被调用");

}

public void doPost(){

System.out.println("响应post请求,doPost()被调用");

}

5.HttpServlet

继承框架

继承HttpServlet开发Servlet程序

重写doGet和doPost

注意HttpServlet已经有doGet和doPost了,所以要直接重写

重写快捷键:Ctrl+O

idea创建servlet程序

6.注解方式

入门小案例

WebServlet部分源码

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented //在javacdoc文档记录

public @interface WebServlet {

String name() default "";

String[] value() default {};

//对应

String[] urlPatterns() default {};

int loadOnStartup() default -1;

WebInitParam[] initParams() default {};

boolean asyncSupported() default false;

String smallIcon() default "";

}

url-pattern四种匹配方式(不做演示)

7.HttpServletRequest

1.常用方法

String getContextPath();//返回请求上下文的请求URI部分

Cookie[] getCookies();//返回一个cookie对象数组

String getHeader(String var1);//返回指定HTTP标题的值

String getMethod();//返回生成这个请求HTTP的方法名称

String getQueryString();//返回请求URL中的查询字符串

HttpSession getSession();//返回与这个请求相关的会话对象

2.获取请求行

常用方法

获得客户端的请求方式:

String getMethod()------------获取请求行中的 HTTP 方法(如 GET、POST 等)。

获得请求的资源:

String getRequestURI()--------获取请求行中的 请求 URI(即资源路径)

StringBuffer getRequestURL()-获取完整的请求 URL(包括协议、服务器地址、端口、路径等)

String getQueryString() -------get提交url地址后的参数字符串,假设查询字符串为:username=1323

String getContextPath() -------web应用的名称

String getProtocol() ----------获取请求行中的 协议版本(如 HTTP/1.1)。

案例演示

输入用户名:1323

获取:

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Exception {

System.out.println("doGet()被调用");

System.out.println(req.getMethod());

System.out.println(req.getQueryString());

System.out.println(req.getRequestURI());

System.out.println(req.getRequestURL());

System.out.println(req.getContextPath());

System.out.println(req.getProtocol());

}

URI和URL区别

如果请求的 URL 是:http://localhost:8084/servlet/test03?username=1323

getRequestURI():获取请求行中的 请求 URI(即资源路径)。

servlet/test03

getRequestURL():获取完整的请求 URL(包括协议、服务器地址、端口、路径等)。这个方法返回的是一个 StringBuffer 类型。

http://localhost:8084/servlet/test03是URL

3.获取请求头

常见方法

String getHeader(String name) :单个请求头的值

Enumeration getHeaderNames():获取所有请求头

Enumeration getHeaders(String name):某个请求头的所有值

int getIntHeader(String name)

referer头的作用:执行该此访问的的来源,做防盗链

如果我们需要获得更多请求头的相关信息,可以使用

req.getHeader(“请求字段”)

//http请求头host

System.out.println(req.getHeader("Host"));

//请求访问的浏览器

String userAgent = req.getHeader("User-Agent");

System.out.println(userAgent);

案例演示

截取目前使用什么浏览器访问

代码:

//请求访问的浏览器

String userAgent = req.getHeader("User-Agent");

System.out.println(userAgent);

String[] s=userAgent.split(" ");

//1.用空格分隔,取最后一段

//2.再用/分隔,注意转义

//3.取第一部分

System.out.println(s[s.length-1].split("\\/")[0]);

成功截取火狐浏览器

4.获取请求体

常用方法

请求体中的内容是通过post提交的请求参数,格式是:

username=lan&password=123&hobby=lq&hobby=zq&hobby=ppq

key=value 格式

以上面参数为例,通过一下方法获得请求参数:

String getParameter(String name)

String[] getParameterValues(String name)

Enumeration getParameterNames()

Map getParameterMap()

注意:get请求方式的请求参数 上述的方法一样可以获得。

案例演示

register.html

抓包查看我输入的账号密码爱好:

获取属性:

//获取参数

//单个

System.out.println("用户:"+req.getParameter("username"));

System.out.println("密码:"+req.getParameter("pwd"));

//获取表单数据

String[] hobbies = req.getParameterValues("hobby");

System.out.println("爱好有:");

for (String hobby : hobbies) {

System.out.print(hobby+" ");

}

输出:

5.请求转发

(1)概念

实现请求转发:请求转发指一个 web 资源收到客户端请求后,通知服务器去调用另外

一个 web 资源进行处理

(2)怎么实现?

流程:

例子1

输入jinge显示管理员身份

输入其他显示普通用户身份

request.html

用户名:


check

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("check 被调用");

//通过用户名判断身份

String username = request.getParameter("username");

if("jinge".equals(username)){

//分配管理员身份

request.setAttribute("role","管理员");

}else{

request.setAttribute("role","普通用户");

}

//请求转发

//获得分发器

// /manage是要转发得servlet得url 就是要跳得servlet

RequestDispatcher requestDispatcher = request.getRequestDispatcher("/manage");

//把对象传給下一个servlet

requestDispatcher.forward(request,response);

}

manage

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("manage 被调用");

//获取用户名

String username=request.getParameter("username");

//获取身份

String role =(String) request.getAttribute("role");

//防止乱码

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

PrintWriter writer = response.getWriter();

writer.print("用户名:"+username+"
");

writer.print("身份:"+role);

writer.flush();

writer.close();

}

代码解释:

直接跳转和请求转发

(一).请求转发

比如:

1.我在b.html,访问servlet1

2.servlet1可以设置请求转发到b.html

(二).直接跳转

ContextPath

上下文路径或者工程路径

获取当前Servlet的上下文对象:

String contextPath =getServletContext().getContextPath();

8.乱码问题

统一编码格式

// 设置请求编码

request.setCharacterEncoding("UTF-8");

// 设置响应编码

response.setCharacterEncoding("UTF-8");

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

1.Request乱码问题

*在service中使用的编码解码方式默认为:ISO-8859-1编码*,但此编码并不支持中文,因此会出现乱码问题.

所以我们需要手动修改编码方式为UTF-8编码,才能解决中文乱码问题,下面是发生乱码的具体细节:

//统一请求编码,防止

req.setCharacterEncoding("UTF-8");

GET 和 POST 请求的乱码

POST:

// 设置请求编码

request.setCharacterEncoding("UTF-8");

GET:

String parameter = req.getParameter("uername");

String s1 = new String(parameter.getBytes("iso-8859-1"), "UTF-8");

2.Response乱码问题

方案一(常用):

设置服务器和客户端都都用utf-8字符集,还设置响应头注意:setContentType要在获取流对象(getWriter)之前才能调用

resp.setContentType("text/html;charset=utf-8");

方案二:

//1.设置服务器字符集

resp.setCharacterEncoding("UTF-8");

//2.通过响应头,设浏览器也使用UTF-8字符集

resp.setHeader("Content-Type","text/html;charset=UTF-8");

9.域对象

1.getParameter

获取input标签输入的内容呗:

2.setAttribute和getAttribute

前面的servlet程序就是先setAttribute(key,value)存起来

后面的servlet程序可以getAttribute(key)来获取

10.HttpServletResponse

1.设置响应状态码

状态码用于告诉客户端请求的处理结果(如成功、失败、重定向等)。

设置响应的状态码

response.setStatus(HttpServletResponse.SC_OK); // 200

response.setStatus(HttpServletResponse.SC_NOT_FOUND); // 404

response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 500

发出错误响应

response.sendError(HttpServletResponse.SC_NOT_FOUND, "Resource not found");

2.设置响应头

响应头用于向客户端传递额外信息,如内容类型、缓存控制等。

setHeader(String name, String value):设置响应头。

response.setHeader("Content-Type", "application/json");

response.setHeader("Cache-Control", "no-cache");

addHeader(String name, String value):添加响应头(允许重复)

response.addHeader("Set-Cookie", "session=abc123");

setContentType(String type):设置响应的内容类型。

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

setCharacterEncoding(String charset):设置响应的字符编码。

response.setCharacterEncoding("UTF-8");

3.设置响应内容

getWriter():获取 PrintWriter,用于发送文本响应。

PrintWriter out = response.getWriter();

out.println("

Hello, World!

");

getOutputStream():获取 ServletOutputStream,用于发送二进制数据(如文件下载)。

getOutputStream():获取 ServletOutputStream,用于发送二进制数据(如文件下载)。

PrintWriter writer = resp.getWriter();

writer.println("注册成功1");

writer.println("

注册成功2

");

案例分析

注册成功,浏览器打印“注册成功”

//中文乱码

//方案一(常用):

//设置服务器和客户端都都用utf-8字符集,还设置响应头

//resp.setContentType("text/html;charset=utf-8");

//方案二

//1.设置服务器字符集

resp.setCharacterEncoding("UTF-8");

//2.通过响应头,设浏览器也使用UTF-8字符集

resp.setHeader("Content-Type","text/html;charset=UTF-8");

//设置响应内容

PrintWriter writer = resp.getWriter();

writer.println("注册成功1");

writer.println("

注册成功2

");

//关闭

writer.flush();

writer.close();

4.请求重定向

(1)概念

一个 web 资源收到客户端请求后,通知客户端去访问另外一个 web

资源,这称之为请求重定向

(2)流程图

(3)步骤

需求:

NewDownLoad文件:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("新页面的doPost()");

//解决乱码

//html

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

//gzip-直接文件下载

//response.setContentType("application/x-gzip;charset=utf-8");

//在浏览器打印

PrintWriter writer = response.getWriter();

writer.print("请求重定向测试完毕");

writer.flush(); //刷新缓存

writer.close(); //关闭

}

response.html

点击下载王者荣耀

方式1:

DownLoad文件:

注意得:/servlet/NewDownLoad非NewDownLoad

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//请求重定向

//1方式1

//重新http请求,跳到这里

response.sendRedirect("/servlet/NewDownLoad");

}

抓包发现:

方式2(上面抓包得原理):

方式1:

DownLoad文件:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//请求重定向

//(1).先设置状态码为302

response.setStatus(302);

//(2).设置Location为重定向路径

response.setHeader("Location","/servlet/NewDownLoad");

}

扩展使用:

3.方式1+动态获得application context

String contextPath = getServletContext().getContextPath();

System.out.println("contextPath:"+contextPath); // 现在这里就是/servlet

response.sendRedirect(contextPath+"/NewDownLoad");

5.设置 Cookie

向客户端发送 Cookie。

addCookie(Cookie cookie):添加一个 Cookie。

Cookie cookie = new Cookie("session", "abc123");

cookie.setMaxAge(60 * 60 * 24); // 设置 Cookie 的有效期为 1 天

response.addCookie(cookie);

设置成功:

6.其他方法

isCommitted():检查响应是否已经提交(即是否已经发送到客户端)。

if (!response.isCommitted()) {

response.sendRedirect("error.html");

}

reset():重置响应,清除已设置的头信息和状态码。

response.reset();

flushBuffer():强制将响应缓冲区的内容发送到客户端。

response.flushBuffer();

相关推荐