🐌个人主页: 🐌 叶落闲庭
💨我的专栏:💨
c语言
数据结构
javaEE
操作系统
Redis石可破也,而不可夺坚;丹可磨也,而不可夺赤。
Servlet
- [一、 Servlet执行流程](#一、 Servlet执行流程)
- 二、Servlet生命周期
- [三、 Servlet方法介绍](#三、 Servlet方法介绍)
- [四、 Servlet体系结构](#四、 Servlet体系结构)
- [五、 urlPattern配置](#五、 urlPattern配置)
- [六、 XML配置Servlet(老版本)](#六、 XML配置Servlet(老版本))
- 七、Request
-
- [7.1 Request继承体系](#7.1 Request继承体系)
- [7.2 Request获取请求数据](#7.2 Request获取请求数据)
- [7.3 Request通用方式获取请求参数](#7.3 Request通用方式获取请求参数)
- [7.4 请求参数中文乱码处理](#7.4 请求参数中文乱码处理)
-
- [7.4.1 POST 解决方案](#7.4.1 POST 解决方案)
- [7.4.1 GET 解决方案](#7.4.1 GET 解决方案)
- [7.5 Request请求转发](#7.5 Request请求转发)
- 八、Response
-
- [8.1 设置相应数据功能](#8.1 设置相应数据功能)
- [8.2 完成重定向](#8.2 完成重定向)
- 8.3资源路径问题
- [8.4 Response响应字符数据](#8.4 Response响应字符数据)
- [8.5 Response响应字节数据](#8.5 Response响应字节数据)
一、 Servlet执行流程
- Servlet由Tomcat服务器创建,,web项目发布到Tomcat服务器后,Tomcat服务器会自动调用web项目中的service()方法,但是在调用service()方法之前,会先创建一个Servlet对象,这个Servlet对象也是由Tomcat服务器创建的,Servlet执行流程就是由浏览器向Servlet发送请求,根据url路径找到要执行的方法,也就是service()方法,这个service()方法也是Tomcat调用的,这个service()方法一被调用,就会返回对应的响应给客户端浏览器。
二、Servlet生命周期
- 对象的生命周期指一个对象从被创建到被销毁的整个过程
- Servleti运行在Servlet:容器(web服务器)中,其生命周期由容器来管理,分为4个阶段:
-
- 1.加载和实例化:默认情况下,当Servlet第一次被访问时,由容器创建Servlet对象
-
- 2.初始化:在Servlet实例化之后,容器将调用Servlet的
init()
方法初始化这个对象,完成一些如加载配置文件、创建连接等初始化的工作,该方法只调用一次
- 2.初始化:在Servlet实例化之后,容器将调用Servlet的
-
- 3.请求处理:每次请求Servlet时,Servlet容器都会调用Servlet的
service()
方法对请求进行处理。
- 3.请求处理:每次请求Servlet时,Servlet容器都会调用Servlet的
-
- 4.服务终止:当需要释放内存或者容器关闭时,容器就会调用Servlet实例的
destroy()
方法完成资源的释放,在destroy()
方法调用之后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾收集器所回收
- 4.服务终止:当需要释放内存或者容器关闭时,容器就会调用Servlet实例的
java
@WebServlet("/demo")
public class ServletDemo implements Servlet {
/**
* 初始化方法
* 1.调用时机:默认情况下,Servlet被第一次访问时调用
* 2.调用次数:1次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init...");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 提供服务
* 1.调用时机:每次Servlet被访问时调用
* 2.调用次数:多次
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("hello service~");
}
@Override
public String getServletInfo() {
return null;
}
/**
* 销毁方法
* 1.调用时机:内存释放或服务器关闭时
* 2.调用次数:1次
*/
@Override
public void destroy() {
System.out.println("destroy...");
}
}
三、 Servlet方法介绍
- 初始化方法,在Servleti被创建时执行,只执行一次
java
void init(ServletConfig servletConfig)
- 提供服务方法,每次Servleti被访问,都会调用该方法
java
void service(ServletRequest servletRequest, ServletResponse servletResponse)
- 销毁方法,当Servlet被销毁时,调用该方法。在内存释放或服务器关闭时销毁Servlet
java
void destroy()
- 获取ServletConfig对象
java
ServletConfig getServletConfig()
- 获取Servlet信息
java
String getServletInfo()
java
@WebServlet("/demo")
public class ServletDemo implements Servlet {
private ServletConfig servletConfig;
/**
* 初始化方法
* 1.调用时机:默认情况下,Servlet被第一次访问时调用
* 2.调用次数:1次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
System.out.println("init...");
}
@Override
public ServletConfig getServletConfig() {
return this.servletConfig;
}
/**
* 提供服务
* 1.调用时机:每次Servlet被访问时调用
* 2.调用次数:多次
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("hello service~");
}
@Override
public String getServletInfo() {
return "";
}
/**
* 销毁方法
* 1.调用时机:内存释放或服务器关闭时
* 2.调用次数:1次
*/
@Override
public void destroy() {
System.out.println("destroy...");
}
}
四、 Servlet体系结构
- 我们将来开发B/S架构的web项目,都是针对HTTP协议所以我们自定义Servlet,会继承HttpServlet
- 自定义Servlet,重写
doGet
和doPost
方法:
java
@WebServlet("/demo1")
public class ServletDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("get...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("post...");
}
}
- 默认执行
doGet
方法:
- 执行
doPost
方法: -
- 创建一个html文件,定义一个表单,设置url路径,方法为post请求,发送post请求:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>doPost</title>
</head>
<body>
<form action="/BBS/demo1" method="post">
<input name="username">
<input type="submit">
</form>
</body>
</html>
五、 urlPattern配置
- Servlet要想被访问,必须配置其访间路径(urlPattern)
- 一个Servlet,可以配置多个urlPattern
java
String[] urlPatterns() default {};
java
@WebServlet(urlPatterns = {"/demo1","/demo2"})
- urlPattern配置规则
-
- 精确匹配
-
-
- 配置路径:
@WebServlet(urlPatterns = "/user/select")
- 配置路径:
-
-
-
- 访问路径:
http://localhost:8080/BBS/user/select
- 访问路径:
-
-
- 目录匹配
-
-
- 配置路径:
@WebServlet(urlPatterns = "/user/*")
- 配置路径:
-
-
-
- 访问路径:
http://localhost:8080/BBS/user/aaa
(aaa可以使任意字符)
- 访问路径:
-
-
- 扩展名匹配
-
-
- 配置路径:
@WebServlet(urlPatterns = "*.do")
注意:此处没有/
,这里的*表示任意以.do
的路径均可
- 配置路径:
-
-
-
- 访问路径:
http://localhost:8080/BBS/demo1.do
- 访问路径:
-
-
- 任意匹配
-
-
- 配置路径:
@WebServlet(urlPatterns = "/")
或@WebServlet(urlPatterns = "/*")
后者优先级更高
- 配置路径:
-
-
-
- 访问路径:
http://localhost:8080/BBS/
/
后可为任意内容
- 访问路径:
-
-
/
和/*
的区别:
-
-
- 当我们的项目中的Servlet配置了
"/"
,会覆盖掉tomcat中的DefaultServlet,当其他的url-patterni都匹配不上时都会走这个Servlet
- 当我们的项目中的Servlet配置了
-
-
-
- 当我们的项目中配置了
"*"
,意味着匹配任意访问路径
- 当我们的项目中配置了
-
- 优先级:
-
- 精确路径 > 目录路径 > 扩展名路径 > /* > /
六、 XML配置Servlet(老版本)
- 1.编写Servlet类
- 2.在web.xml中配置该Servlet类
xml
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--Servlet全类名-->
<servlet>
<servlet-name>demo2</servlet-name>
<servlet-class>test.ServletDemo2</servlet-class>
</servlet>
<!--Servlet访问路径-->
<servlet-mapping>
<servlet-name>demo2</servlet-name>
<url-pattern>/demo2</url-pattern>
</servlet-mapping>
</web-app>
七、Request
- Request:获取请求数据
- Response:设置响应数据
7.1 Request继承体系
- Tomcati需要解析请求数据,封装为request对象并且创建request对象传递到service方法中
- 使用request对象,查阅JavaEE API文档的HttpServletRequest接口
7.2 Request获取请求数据
- 请求行:
GET /request-demo/req1?username=zhangsan HTTP/1.1
-
String getMethod()
:获取请求方式:GET
-
String getContextPath()
:获取虚拟目录(项目访问路径):/request-demo
-
String Buffer getRequestURL()
:获取URL(统一资源定位符):http:/localhost:8080/request--demo/req1
-
String getRequestURI()
:获取URI(统一资源标识符):/request-demo/req1
-
String getQueryString()
:获取请求参数(GET方式):username=zhangsan&password=123
java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//String getMethod()
String method = req.getMethod();
System.out.println(method);
//String getContextPath()
String contextPath = req.getContextPath();
System.out.println(contextPath);
//String Buffer getRequestURL()
StringBuffer requestURL = req.getRequestURL();
System.out.println(requestURL.toString());
//String getRequestURI()
String requestURI = req.getRequestURI();
System.out.println(requestURI);
//String getQueryString()
String queryString = req.getQueryString();
System.out.println(queryString);
}
- 请求头:
User-Agent:Mozilla/5.0 Chrome/91.0.4472.106
String getHeader((String name);
根据请求头名称,获取值
java
//user-agent:浏览器版本信息
String agent = req.getHeader("user-agent");
System.out.println(agent);
- 请求体:
username=superbaby&password=123
ServletInputStream getInputStream();
获取字节输入流BufferedReader getReader();
获取字符输入流
java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取字符输入流
BufferedReader reader = req.getReader();
//2.读取数据
String s = reader.readLine();
System.out.println(s);
}
7.3 Request通用方式获取请求参数
-
Map<String,String[]>getParameterMap()
:获取所有参数Map集合 -
String[]getParameterValues(String name)
:根据名称获取参数值(数组) -
String getParameter(String name)
:根据名称获取参数值(单个值) -
get方式:
-
- html代码:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>doPost</title>
</head>
<body>
<form action="/BBS/demo5" method="get">
<input type="text" name="username"><br>
<input type="password" name="password"><br>
<input type="checkbox" name="hobby" value="1"> 游泳
<input type="checkbox" name="hobby" value="2"> 跑步 <br>
<input type="submit">
</form>
</body>
</html>
- Java代码:
java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Get请求
System.out.println("get...");
//1.获取所有参数的Map集合
Map<String, String[]> parameterMap = req.getParameterMap();
for (String key : parameterMap.keySet()) {
System.out.print(key + ": ");
//获取值
String[] strings = parameterMap.get(key);
for (String string : strings) {
System.out.print(string + " ");
}
System.out.println();
}
System.out.println("----------------------");
//2.根据key获取值
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
System.out.println("----------------------");
//3.获取单个参数
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}
- post方式:
-
- html代码:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>doPost</title>
</head>
<body>
<form action="/BBS/demo5" method="post">
<input type="text" name="username"><br>
<input type="password" name="password"><br>
<input type="checkbox" name="hobby" value="1"> 游泳
<input type="checkbox" name="hobby" value="2"> 跑步 <br>
<input type="submit">
</form>
</body>
</html>
- Java代码:
java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Post请求
System.out.println("get...");
//1.获取所有参数的Map集合
Map<String, String[]> parameterMap = req.getParameterMap();
for (String key : parameterMap.keySet()) {
System.out.print(key + ": ");
//获取值
String[] strings = parameterMap.get(key);
for (String string : strings) {
System.out.print(string + " ");
}
System.out.println();
}
System.out.println("----------------------");
//2.根据key获取值
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
System.out.println("----------------------");
//3.获取单个参数
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}
- 通用代码:
java
@WebServlet("/demo5")
public class ServletDemo5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Get请求
System.out.println("get...");
//1.获取所有参数的Map集合
Map<String, String[]> parameterMap = req.getParameterMap();
for (String key : parameterMap.keySet()) {
System.out.print(key + ": ");
//获取值
String[] strings = parameterMap.get(key);
for (String string : strings) {
System.out.print(string + " ");
}
System.out.println();
}
System.out.println("----------------------");
//2.根据key获取值
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
System.out.println("----------------------");
//3.获取单个参数
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
7.4 请求参数中文乱码处理
7.4.1 POST 解决方案
java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码POST
//设置字符输入流的编码
req.setCharacterEncoding("utf-8");
//获取数据
String username = req.getParameter("username");
System.out.println(username);
}
7.4.1 GET 解决方案
- GET获取参数方式:
getQueryString
- 产生乱码的原因:
-
- 浏览器在解析中文字符时采用UTF-8的字符集通过URL进行编码,将中文转换成
%
+16进制数
的格式,然后将转换后的字符发送给服务器进行解码,tomcat在进行解码时是通过ISO-8859-1
的字符集进行URL解码,由于编码和解码时用的字符集不同,所以就会出现乱码。
- 浏览器在解析中文字符时采用UTF-8的字符集通过URL进行编码,将中文转换成
- URL编码:
-
- 将字符串按照编码方式转为二进制
-
- 每个字节转为2个16进制数并在前边加上%
java
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码GET
String username = req.getParameter("username");
//转换为字节数据,编码
byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1);
//将字节数组转换为字符串,解码
username = new String(bytes,"utf-8");
System.out.println(username);
}
- Tomcat8.0之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8
7.5 Request请求转发
- 请求转发(forward):一种在服务器内部的资源跳转方式
java
req.getRequestDispatcher("资源B路径").forward(req,resp);
- 请求转发资源间共享数据:使用Request对象
void setAttribute(String name,Object o)
:存储数据到request域中Object getAttribute(String name)
:根据key,获取值void removeAttribute(String name)
:根据key,删除该键值对
java
@WebServlet("/demo7")
public class ServletDemo7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo7...");
//存储数据
req.setAttribute("msg","hello");
//请求转发
req.getRequestDispatcher("/demo8").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
java
@WebServlet("/demo8")
public class ServletDemo8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo8...");
//获取数据
Object msg = req.getAttribute("msg");
System.out.println(msg);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
- 请求转发特点:
-
- 浏览器地址栏路径不发生变化
-
- 只能转发到当前服务器的内部资源
-
- 一次请求,可以在转发的资源间使用request共享数据
八、Response
8.1 设置相应数据功能
- 响应数据分为3部分:
-
- 响应行
-
-
- 设置响应状态码:
-
java
void setStatus(int sc)
-
- 响应头
-
-
- 设置响应键值对
-
java
void setHeader(String name,String value)
-
- 响应体
-
-
- 获取字符输出流
-
java
PrintWriter getWriter();
-
-
- 获取字节输出流
-
java
ServletOutputStream getOutputStream();
8.2 完成重定向
- 重定向(Redirect):一种资源跳转方式
java
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("resp1...");
//重定向
//设置响应状态码302
//resp.setStatus(302);
//设置响应头
//resp.setHeader("Location","/BBS/resp2");
//简化方式
resp.sendRedirect("/BBS/resp2");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
java
@WebServlet("/resp2")
public class ResponseDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("resp2...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
- 重定向特点:
-
- 浏览器地址栏路径发生变化
-
- 可以重定向到任意位置的资源(服务器内部、外部均可)
-
- 两次请求,不能在多个资源使用request:共享数据
8.3资源路径问题
- 明确路径谁使用?
-
- 浏览器使用:需要加虚拟目录(项目访问路径)
-
- 服务端使用:不需要加虚拟目录
java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("resp1...");
//简化方式
//动态获取虚拟目录
String contextPath = req.getContextPath();
resp.sendRedirect(contextPath + "/resp2");
}
8.4 Response响应字符数据
- 使用:
-
- 1.通过Response对象获取字符输出流
java
PrintWriter writer resp.getWriter();
- 2.写数据
java
writer.write("hello~");
java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
resp.setHeader("content-type","text/html");
writer.write("<h1>hello~</h1>");
writer.write("<h1>你好~</h1>");
}
注意:
- 该流不需要关闭,随着响应结束,response对象销毁,由服务器关闭
- 中文数据乱码:原因通过Response获取的字符输出流默认编码:
ISO-8859-1
8.5 Response响应字节数据
- 使用:
- 通过Response对象获取字符输出流
java
ServletOutputStream outputStream resp.getOutputStream();
- 写数据
java
outputStream.write("字节数据");
java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//读取文件
FileInputStream fis = new FileInputStream("d://head.jpg");
//获取response字节输出流
ServletOutputStream os = resp.getOutputStream();
//完成流的copy
byte[] buff = new byte[1024];
int len = 0;
while ((len = fis.read(buff)) != -1) {
os.write(buff,0,len);
}
fis.close();
}
- IOUtils工具类使用:
-
- 导入坐标:
xml
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
-
- 使用:
java
IOUtils.copy(fis,os);
java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//读取文件
FileInputStream fis = new FileInputStream("d://head.jpg");
//获取response字节输出流
ServletOutputStream os = resp.getOutputStream();
//完成流的copy
IOUtils.copy(fis,os);
fis.close();
}