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)
  • 过滤器
  • 监听器
  1. 在启动 Web 项目时,Tomcat 会读取 web.xml 中的 comtext-param 节点,获取这个 Web 应用的全局参数
    Tomcat 创建一个 ServletContext 实例,是全局有效的
    将 context-param 的参数转换为键值对,存储在 ServletContext 里
  2. 创建 listener 中定义的监听类的实例,按照规定 Listener 要继承自 ServletContextListener
    监听器初始化方法是 contextlnitialized(ServletContextEvent event)
    初始化方法中可以通过 event.getServletContext().getlnitParameter("name") 方法获得上下文环境中的键值对
  3. 当 Tomcat 完成启动,也就是 contextlnitialized 方法完成后,再对 Filter 过滤器进行初始化
  4. 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);
}
posted @ 2023-07-21 14:25  lidongdongdong~  阅读(12)  评论(0编辑  收藏  举报