10、Servlet
1、Request
1.1、请求行
* 请求行例子
GET /day06_request/requestLine?name=zs HTTP/1.1
* 重要方法:
1. String getMethod() 获取请求方式 GET/POST
2. String getRequestURL() 获取请求完整路径(URL) `http://localhost:8080/day06_request/requestLine`
3. String getRequestURI() 获取请求资源部分(URI) `/day06_request/requestLine`
4. String getContextPath() 获取项目虚拟目录 `/day06_request`
5. String getServletPath() 获取项目资源路径 `/requestLine`
6. String getProtocol() 获取请求协议和版本号 HTTP/1.1
7. int getLocalPort() 获得服务器端口号 8080
8. String getRemoteAddr() 获得客户端 ip 地址
- 如果写的是 localhost, 显示 ipv6 地址
- 如果写的是 127.0.0.1, 显示 ipv4 地址
9. #{pageContext.request.contextPath}
1.2、请求头
* 请求头例子
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
* 重要方法:
1. String getHeader(String name) 以 String 的形式返回指定请求头的值
2. Enumeration getHeaderNames() 返回此请求包含的所有头名称的枚举
1.3、请求参数(重要)
* 请求参数的位置
get 请求: URL 上
post 请求: 请求体中
* 请求参数例子
name=张三&age=18&hobby=抽烟&hobby=喝酒&hobby=烫头
* 重要方法
1. String getParameter(String name) 根据参数名获得参数值(单个)
2. String[] getParameterValues(String name) 根据参数名获得参数值(数组)
3. Map<String, String[]> getParameterMap() 获得所有的参数, 封装到 Map 集合
1.4、将请求参数封装成实体(重要)
* https://www.hutool.cn/docs/#/
* hutool 提供了一个方法可以将请求的 Map 转成一个实体对象 BeanUtil.copyProperties(map, user, true) (源, 目标, 是否忽略属性大小写)
* 需要注意的是: map 中的 key 要和实体类中的属性保持一致
Map<String, String[]> map = req.getParameterMap();
User user = new User();
BeanUtil.copyProperties(map, user, false);
System.out.println(user);
1.5、总结
1. Request 概念: Tomcat 创建出来, 用于封装请求行头体
2. 接收请求行
- 虚拟路径 request.getContextpath()
3. 接收请求头
- 接收所有 key: request.getHeaderNames()
- 根据 key 接收 value: request.getHeader(key)
4. 接收请求参数
- getParameter("name") getParameterValues("name")
- getParameterMap() ------> Map<String, String[]> ------> BeanUtil.copyProperties(map, obj) =====> obj
- 转发: request.getRequestDispatcher("流转路径{不需要写虚拟路径}").forward(req, resp);
- 域对象: set get remove
2、Responce
2.1、响应行头体
* 响应行
- 响应行格式例子
- HTTP/1.1 200 OK
- HTTP/1.1 302 OK
- 设置响应行:
- void setStatus(int sc)
* 响应头
- 响应头格式例子
- Location:http://www.baidu.com
- Content-Type:text/html;charset=utf-8
- 设置响应头
- void setHeader(String name, String value)
* 响应体
- 通过 response 获取输出流
- 字符流: PrintWriter getWriter()
- 字节流: ServletOutputStream getOutputStream()
- 注意: 在同一个 servlet 中, 不能同时使用字节流和字符流
2.2、响应重定向
1. 方式一
- response.setStatus(302);
- response.setHeader("Location", 目标资源位置);
2. 方式二
- response.sendRedirect(目标资源位置);
2.3、向浏览器输出中文
* 使用字符流输出内容到浏览器
- PrintWriter writer = response.getWriter();
- writer.write() 将其他类型转换为字符, 再输出
- writer.print() 只能输出字符
2.4、总结
* response
1. 重定向
- resp.sendRedirct(req.getContextPath() + "/资源路径")
2. 设置编码
- resp.setContentType("text/html;charset=utf-8");
3、请求转发和响应重定向
1. 实现
- 请求转发(request 对象的方法)
- request.getRequestDispatcher("/BServlet").forward(request,response);
- 响应重定向(response 对象的方法)
- response.sendRedirect(request.getContextPath() + "/BServlet");
2. 区别
- 请求转发
- 地址栏: 没有改变
- 浏览器: 发了一次请求
- 服务器: 只有一对请求和响应对象
- 发生的位置: 服务器内部
- 响应重定向
- 地址栏: 发生了改变
- 浏览器: 发了两次请求
- 服务器: 有两对请求和响应对象
- 发生的位置: 浏览器外部
4、Cookie 和 Session
1. cookie 基本原理
- 创建服务器, 保存在客户端, 用于记录一次会话中的请求和响应的信息
- 使用的头:
- 响应头: 服务器向浏览器保存 cookie Set-Cookie: product=xiaomi
- 请求头: 浏览器向服务器报告 cookie Cookie: product=xiaomi
2. api
- 创建 cookie: new Cookie(key, value)
- 设置存活时间: cookie.setMaxAge(正整数时长)
- 设置数据共享路径: cookie.setPath("服务器路径")
- cookie 数据的覆盖因素: cookie 的 path 相同并且 name 相同
- 中文和字符: 使用编码技术 URL
- 将 cookie 写回浏览器: resp.addCookie(cookie)
- 从请求中获取 cookie: req.getCookies()
3. Cookie 特点
- cookie 创建在服务器, 存储数据在客户端(浏览器)
- cookie 只能存储字符串
- cookie 单个大小不能超过 4KB
- cookie 存储数据不太安全
1. session 基本原理
- 创建服务器, 保存在服务器, 用于记录一次会话中的请求和响应的信息
- 使用的头:
- 响应头: 服务器向浏览器保存 cookie Set-Cookie: JESESSIONID=session 标识
- 请求头: 浏览器向服务器报告 cookie Cookie: JESESSIONID=session 标识
2. api
1) 创建 Session: req.getSession()
2) 向 session 中保存数据: setAttribute(key, value)
3) 从 session 中获取数据: getAttribue(key)
4) 摧毁 session: session.invlidate()
3. sessione 特点
- session 存储数据在服务器
- session 存储类型任意(Object)
- session 存储大小和数量没有限制(相对于内存)
- session 存储相对安全
4. Cookie 和 Session 的选择
- cookie: 将数据保存在浏览器端, 数据相对不安全, 而且数据大小是有限制的, 建议不太敏感的数据使用它
- session: 将数据保存在服务器端, 数据相对安全, 数据的大小要比 cookie 中数据灵活很多, 但是会占用服务器内存, 建议敏感且小量数据使用它
5、Get 和 Post
POST `/day05_tomcat/index.html` HTTP/1.1
* 请求行由三部分组成: 请求方式 请求路径 请求协议/版本
* 请求方式有很多, 我们需要关注两种: get 和 post
1. get
- 请求参数在地址栏显示, 不太安全
- 请求参数大小有限制
- 没有请求体
2. post
- 请求参数没有在地址栏显示, 而是在请求体显示, 相对安全
- 请求参数大小没有限制
- 有请求体
6、乱码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
7、注解
@WebServlet(
name = "servlet", // 指定 Servlet 名称, 等价于 web.xml 中的 servlet-name, 如果省略, 则为 Servlet 的完整类名
urlPatterns = {"/servlet.do","/s.do"}, // Servlet 的访问 URL, 支持多个, 等价于 web.xml 中的 urlPatterns
loadOnStartup = 6, // 自启动 Servlet, 指定 Servlet 的加载顺序, 等价于 web.xml 中的 load-on-startup
initParams = { // 给 servletConfig 初始化, 设置初始化参数, 等价于 web.xml 中的 init-param
@WebInitParam(name = "brand", value = "ASUS"),
@WebInitParam(name = "screen", value = "三星")
}
)
@WebFilter(
urlPatterns = {"/myServlet1.do"}, // Filter 过滤 Servlet 的 URL, 支持多个
// 指定过滤器将应用于哪些 Servlet, 支持多个
// 取值是 @WebServlet 中的 name 属性的取值, 或者是 web.xml 中 <servlet-name> 的取值
servletNames = {"myServlet1"},
initParams = { // 给 filterConfig 初始化
@WebInitParam(name = "realName", value = "张三"),
@WebInitParam(name = "charset", value = "utf-8")
}
)
// 任何资源都要过滤, 包括 JSP
@WebFilter(urlPatterns = "/*")
8、Servlet
8.1、示例
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello World.");
}
}
8.2、Servlet 的生命周期
阶段 | 次数 | 时机 |
---|---|---|
创建 new | 1 次 | 第一次请求 |
初始化 init | 1 次 | 实例化之后 |
执行服务 service | 多次 | 每次请求 |
销毁 destroy | 1 次 | 停止服务 |
8.3、ServletConfig 和 ServletContext
* 当 Tomcat 初始化一个 Servlet 时, 该 Servlet 的配置信息, 封装到一个 ServletConfig 对象中
- ServletConfig servletConfig = this.getServletConfig() 获取当前 servet 的配置信息对象
- getInitParameter("key") 根据 key 获取当前 servet 的配置信息
* ServletContext 作为域对象可以在同一个应用中共享数据
* 获取服务器上的资源
- getRealPath(String filename) 获取资源真实路径[重要]
- getResourceAsStream(String filename) 将项目中的文件转换成流
* 获取全局配置参数
- servletContext.getInitParameter("key") [重要]
8.4、Servlet 三大域对象
域对象 | 类 | 作用域 |
---|---|---|
Request 域 | HttpServletRequest | 一次请求 / 请求转发 |
Session 域 | HttpSession | 一次会话(跨请求) |
Application 域 | ServletContext | 任意一次请求和会话(跨会话) |
三大于对象的获取
- Request 域:request(只有请求转发,Request 域中的数据才可以传递)
- Session 域:HttpSession session = request.getSession();
- Application 域:ServletContext application = request.getServletContext();
三大于对象的共有方法
- 设置和修改数据:setAttribute(key, value);
- 获得数据的方法:getAttribute(key);
- 移除数据的方法:removeAttribute(key);
9、web.xml 三大组件
执行流程:ServletContext、监听器、过滤器、Servlet
- Servlet(前端控制器 DisptcherServlet)
- 过滤器
- 监听器
- 在启动 Web 项目时,Tomcat 会读取 web.xml 中的 comtext-param 节点,获取这个 Web 应用的全局参数
Tomcat 创建一个 ServletContext 实例,是全局有效的
将 context-param 的参数转换为键值对,存储在 ServletContext 里 - 创建 listener 中定义的监听类的实例,按照规定 Listener 要继承自 ServletContextListener
监听器初始化方法是 contextlnitialized(ServletContextEvent event)
初始化方法中可以通过 event.getServletContext().getlnitParameter("name") 方法获得上下文环境中的键值对 - 当 Tomcat 完成启动,也就是 contextlnitialized 方法完成后,再对 Filter 过滤器进行初始化
- servlet 初始化:有一个参数 load-on-startup,它为正数的值越小优先级越高,会自动启动,如果为负数或未指定这个参数,会在 servlet 被调用时再进行初始化
init-param 是一个 servlet 整个范围之内有效的参数,在 servlet 类的 init 方法中通过 this.getInitParameter('"param1") 方法获得
Servlet
<!--向 Tomcat 声明一个 Servlet-->
<servlet>
<!--别名-->
<servlet-name>myServlet</servlet-name>
<!--对应的类-->
<servlet-class>servlet.MyServlet</servlet-class>
<!--用来修改 servlet 的创建时机-->
<!--负 数: Servlet 在第一次被访问时创建-->
<!--非负数: Servlet 在 tomcat 启动的时候创建, 范围: 0-10, 值越小优先级越高, 推荐使用 4 以上的数-->
<load-on-startup>6</load-on-startup>
</servlet>
<!--给 Servlet 匹配一个映射路径-->
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myServlet.do</url-pattern>
</servlet-mapping>
<!--自定义欢迎页, 可以有多个-->
<welcome-file-list>
<welcome-file>a.html</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>servlet4</servlet-name>
<servlet-class>servlet.Servlet4</servlet-class>
<init-param>
<param-name>brand</param-name>
<param-value>联想</param-value>
</init-param>
<!--给当前 ServletConfig 放入初始值-->
<init-param>
<param-name>screen</param-name>
<param-value>京东</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>servlet4</servlet-name>
<url-pattern>/servlet4.do</url-pattern>
</servlet-mapping>
配置
<!--context 全局通用-->
<context-param>
<param-name>username</param-name>
<param-value>dodo</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</context-param>
<!--session 最大不活动时间, 单位: minute-->
<!--Tomcat 默认 session 最大不活动时间: 30 minutes-->
<session-config>
<session-timeout>1</session-timeout>
</session-config>
<!--配置异常提示页-->
<!--当 JSP 中发生了异常时,如果 JSP 中配置的错误页和 web.xml 中配置的错误页冲突了,JSP page 指令的 errorPage 优先级更高-->
<error-page>
<error-code>500</error-code>
<location>/error500.JSP</location>
</error-page>
过滤器和监听器
<!--向 Tomcat 声明一个 filter-->
<filter>
<!--别名-->
<filter-name>filter</filter-name>
<!--对应的类-->
<filter-class>filter.MyFilter</filter-class>
</filter>
<!--给 filter 匹配多个过滤对象-->
<filter-mapping>
<!--指定要使用哪个过滤器-->
<filter-name>filter</filter-name>
<!--根据 name(Servlet的别名) 指定要使用过滤器过滤哪个 Servlet-->
<servlet-name>myServlet1</servlet-name>
<servlet-name>myServlet2</servlet-name>
<!--根据 name(Servlet的路径) 指定要使用过滤器过滤哪个 Servlet-->
<url-pattern>/</url-pattern> // 不包括 JSP
<url-pattern>/*</url-pattern> // 包括 JSP
</filter-mapping>
<listener>
<listener-class>com.z.listener.MyRequestListener</listener-class>
</listener>
10、其他
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.2.3</version>
</dependency>
// 添加
private void save(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.axios 发送的 post 请求参数必须要用流接收
ServletInputStream inputStream = request.getInputStream();
// 2.将输入流转为 json
String json = IoUtil.read(inputStream, "UTF-8");
// json -> student
Student student = new ObjectMapper().readValue(json, Student.class);
studentService.save(student);
}
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17571262.html