📚博客主页:代码探秘者
✨专栏:《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的
这样配置,最终访问路径
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
注意: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();