1. Servlet 技术

1.1 Servlet 的概念

  1. servlet 是 JavaEE 规范之一,规范就是接口
  2. Servlet 就 JavaWeb 三大组件之一,三大组件分别是 Servlet 程序、Filter 过滤器、Listener 监听器
  3. Servlet 是运行在服务器上的java小程序,他可以接受用户发送的请求,并发出响应

1.2 手动实现 Servlet

  1. 基础 Servlet 类,并实现其中的接口方法
  2. 其中 Service 方法是专门处理请求和响应的方法,只要访问目标程序就会触发、
  3. 使用前要配置 web.xml
    1. <servlet>
    2. <servlet-name>HelloServlet</servlet-name> // 程序的别名
    3. <servlet-class>com.servlet.HelloServlet</servlet-class>
    4. </servlet>
    5. <servlet-mapping>
    6. <!--Servlet-name 的作用告诉服务器,我当前配置的地址是哪个Servlet程序使用-->
    7. <servlet-name>HelloServlet</servlet-name>
    8. <!---->
    9. <url-pattern>/hello</url-pattern>
    10. </servlet-mapping>

常见的错误:

  1. 404 :丢失
  2. 500: servlet-class 标签全类名错误

1.3 Servlet 的生命周期

  1. 执行 Servlet 构造器方法
  2. 执行init初始化方法 (1、2就执行一次用于创建servlet程序,重复访问直接第三步)
  3. 执行service方法
  4. 执行destroy方法 (web工程停止时调用)

    1.4 Servlet的请求分发处理

    针对:get 、post 等不同请求做出不同的响应 一般我们实际开发通过继承 HttpServlet 类的方法区实现 Servlet程序,原始得到HttpServlet 是要我们自己分辨请求类型的

  • get :
  • post:
  1. 编写一个类继承与 HttpServlet 类
  2. 根据业务需要重写 doGet 或者 doPost 方法
  3. 到web.xml中配置 servlet 程序的访问地址

    1.5 ServletConfig 类介绍

    ServletConfig 类从类名上来看,就知道是Servlet程序的配置信息类 Servlet 程序和 ServletConfig 对象都是有Tomcat负责创建的我们负责使用 Sevlet 程序默认是第一次访问时候创建,servletconfig 是每个 Servlet程序创建的时候,就创建一个对应的 ServletConfig 对象

  4. ServletConfig 类的三大作用

    1. 可以获取程序的别名即Servlet-name的值
    2. 获取初始化 init-param 参数,初始化参数
    3. 获取 ServletContext 对象

      1.6 ServletContrext 一个类接口

      1. 表示 ServletContext 是一个接口,他表示 Servlet 上下文对象
      2. 一个web工程,只有要给ServletContext实例,多次调用都是返回同一个对象
      3. ServletContext 对象是一个域对象(域:可以像map一样存取数据的)
写入 获取 移除
Map put get remove
域对象 setAttribute getAttribute removeAttribute

ServletContext类的作用

  1. 获取web.xml中配置的上下文参数 context-param (可以配置多组)
  2. 获取当前的工程路径,格式: /工程路径
  3. 获取工程部署后,在服务器磁盘上的绝对路径
  4. 像 Map 一样保存数据
  5. 域指的是整个web项目工程

2 Http 协议

什么是协议?
协议是双方或者多方,相互约定浩,大家都要遵守的规则

2.1 请求的HTTP协议格式

客户端给服务器发送的叫请求 服务器个客户端回传的叫响应 请求分为 GET 请求和 POST 请求两种

  1. GET 请求 ```markdown
  2. 请求行
    • 请求方式 GET
      • 请求的资源路径 + [? + 请求参数]
      • 请求协议的版本号 Http/1.1
  3. 请求头 key: value 注册 不同键值对有不同的含义 ```

  4. POST 请求 ```markdown

  5. 请求行
    • 请求方式 POST
      • 请求的资源路径 + [? + 请求参数]
      • 请求协议的版本号 Http/1.1
  6. 请求头 key:value 不同的头有不同含义 空行
  7. 请求体 发送给服务器的数据 Post 请求
  1. 3. 常用的请求头的说明
  2. ```markdown
  3. Accept: 表示客户端可以接受的数据类型
  4. Accept-Language : 表示客户端可以接受的语言类型
  5. Host :
  6. Referer : 表示请求发起时,浏览器地址栏中的地址(从哪来)
  7. User-Agent : 表示浏览器的信息
  8. User-Agent : 表示浏览器的信息
  9. Content-Type : 表示发送的数据的类型
  10. application/x-www-form-urlencoded
  11. 表示提交的数据格式是: name=vale&name=value,然后对其进行 URL 编码,把非英文内容转换位 %xx%xx的形式
  12. multipart/form-data
  13. 表示多段形式提交数据给服务器(以流的形式提交,用于上传)
  14. Content-Length :发送的数据长度
  15. Cache-Control :表示如何控制缓存,no-cache 不缓存
  1. 哪些是 GET 请求, 哪些是POST请求 ```markdown
  • GET请求:
    1. form 标签 mthod = get
      1. a 标签
      2. link 标签引入 css
      3. Script 引入 js 文件
      4. img 标签引入图片
      5. iframe 引入html 页面
      6. 在地址栏食人鱼地址直接回车
  • POST请求: form 标签明确 mthod = post **响应 HTPP协议的格式 **markdown
  1. 响应行
    1. 响应的协议和版本号
      1. 响应状态码
      2. 响应状态描述符
  2. 响应头
    1. key:value 空行
  3. 响应体 ——> 回传个数据 ``` 常见的响应码
  • 200 : 请求成功
  • 302 : 请求重定向
  • 404 : 收到服务但是,目标数据不存在
  • 500 : 服务器已经收到请求,但是内部发生错误,比如代码层错误,一些编译发现不了的错误

MIME 类型说明
MIME 是 HTTP 协议中的数据类型
MIME 的英文全称是 “multipurpose internet Mail extensions” 多功能 internet 邮件扩充服务, MIME 类型的格式是 “大类型/小类型” , 并与某种文件扩展名对应
image.png

3. HttpServletRequest 类

  1. HttpServletRequest 类的作用:

每次只要有请求加入tomcat服务器,tomcat服务器就会把请求的学习解析并封装到 Request对象中,然后传递到 service 方法(doGet 和 doPost)中给我们使用,我们可以获取所有的请求信息

  1. HttpServletRequest 类的常用方法:
    1. getRequestURI() : 获取请求的URI地址,即资源路径
    2. getRequestURL() :获取请求的统一资源定位符,即绝对路径
    3. getRemoteHost() :获取 ip 地址
    4. getHeader() :获取请求头
    5. getParameter() : 获取请求的参数
    6. getParameterValues() : 获取请求的参数(多参数的情况下)
    7. getMethod() : 获取请求的方式 GET 或者 POST
    8. setAttribute(key , value) : 设置域数据
    9. getAttribute(key) : 获取域数据
    10. getRequestDispatcher() : 获取请求转发对象

      get 没有请求体,不会乱乱码(主要有Tomcat服务器进行解析,只需要准正确设置服务器就可以正常读取),而post需要设置编码保证读取数据的准确


4 Servlet 的两个响应流介绍

  1. 字节流 getOutputStream(); 常用与下载(快速传递二进制数据)
  2. 字符流 getWrite(); 常用于字符串的传递

两个流同时只能使用一个,否则会处错

  1. public void test(){
  2. resp.getWriter();
  3. resp.getOUtputStream(); // 同时调用出问题
  4. }

5 如何往客户端会回传字符串数据

代码例子:

  1. protectd void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException ,IOException{
  2. resp.setCharacterEncoding("UTF-8"); // 设置服务器字符集为 UTF-8
  3. //resp.setHeader("Content-Type" , "text/html;charset=UTF-8"); // 设置浏览器字符集
  4. resp.setContentType("text/html;charset=UTF-8"); // 可以替代上上面两行代码效果,不过有局限。注意,此方法一定要获取流对象之前才有效
  5. PrintWriter writer = resp.getWriter();
  6. writer.write("----");
  7. }

6 请求重定向

请求重定向,是指客户端给服务器发送请求,然后服务器告诉客户端,然后其访问新地址(因为之前的地址已经废弃)。却比于转发

表示,有一个废弃的servlet 提供信息跳转新的位置

servlet1

  1. protectd void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException ,IOException{
  2. System.out.println("Servlet 1 ");
  3. resp.setStatus(302);
  4. resp.setHdeader("Location","http://localhost:8088/Servlet_2");
  5. }

servlet2

  1. protectd void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException ,IOException{
  2. System.out.println("Servlet 2 ");
  3. }

特点:
1. 浏览器的地址会明确电话

  1. 两次请求
  2. 不共享 Request 域中的数据
  3. 不能访问 WEB-INF 目录下资源,但是可以访问其他平台资源

另一种实现重定向的方法:

  1. resp.sendRedirect("目标地址");

7 WEB实现文件上传、下载

7.1 要点(上传)

  1. 要有要给 form 标签, method=post 请求
  2. Form标签的 enctype 属性,值必须位 multipart/form-data 值,表示一多段的形式进行拼接,然后以二进制流的方式发送给服务器
  3. 在form标签中是哟哦你input type = file 添加上传的文件
  4. 编写服务器代昂吗接收,处理上传数据,接收到数据后用第三方的接口解析目标数据 ```java // 上传 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    1. if(ServletFileUpload.isMultipartContent(request)){
    2. // 创建 FileItemFactory 工厂实现类
    3. FileItemFactory diskFileItemFactory = new DiskFileItemFactory();
    4. // 创建用于解析上传数据的工具类 ServletFileUpload
    5. ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
    6. try {
    7. List<FileItem> fileItems = servletFileUpload.parseRequest(request);
    8. // 循环判断每一个表单项是普通类型还是上传文件
    9. for(FileItem fileItem : fileItems)
    10. {
    11. if(fileItem.isFormField())
    12. {
    13. // 普通表单项
    14. System.out.println(fileItem.getFieldName());
    15. // 获取编码参数
    16. System.out.println(fileItem.getString("UTF-8"));
    17. }else {
    18. // 上传的文件
    19. System.out.println(fileItem.getFieldName());
    20. // 上传的文件名
    21. System.out.println(fileItem.getName());
    22. fileItem.write(new File("e:\\"));
    23. }
    24. }
    25. } catch (Exception e) {
    26. e.printStackTrace();
    27. }
    28. }
    }
  1. <a name="HVQfU"></a>
  2. ### 7.2 要点(下载)
  3. 1. 获取要下载的文件名
  4. 1. 读取要下载的文件内容
  5. 1. 把要下载的内容回传给客户端
  6. 1. 在回传前通过响应头,通知客户端其文件类型
  7. 1. 提示客户端收到的数据用于下载(通过响应头实现)
  8. ```java
  9. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  10. // 1. 获取文件名
  11. String s = "2.jpg";
  12. s = URLEncoder.encode(s,"UTF-8"); // 设置文件名编码
  13. // 2. 读取要下载的文件内容(通过ServletContext对象读取)
  14. ServletContext servletContext = getServletContext();
  15. // 获取下载文件类型
  16. String mimeType = servletContext.getMimeType("/file/" + s);
  17. // 3. 在回传前,通过响应头告诉客户端返回的类型
  18. response.setContentType(mimeType);
  19. // 4. 提示客户端是作为下载文件使用
  20. response.setHeader("Context-Disposition" , "attachment;filement="+s);
  21. // 5. 把下载的文件内容传递给客户端 / 不然他会自动显示结果
  22. // 输入流
  23. InputStream resource = servletContext.getResourceAsStream("/file/"+s);
  24. // 输出流
  25. ServletOutputStream outputStream = response.getOutputStream();
  26. int copy = IOUtils.copy(resource, outputStream);
  27. }

文件名乱码问题解决方法: 我们需要对文件进行编码

  1. s = URLEncoder.encode(s,"UTF-8"); // 设置文件名编码

7.3 使用Base64 编码操作

针对部分不支持 Unicode 编的浏览器,比如老板的火狐浏览器

  1. // 1. 获取文件名
  2. String s = "2.jpg";
  3. // 创建一个Base64编码器
  4. BASE64Encoder base64Encoder = new BASE64Encoder();
  5. // 执行 Base64 编码操作
  6. String encode = base64Encoder.encode(s.getBytes("UTF-8"));
  7. // 解码操作
  8. BASE64Decoder base64Decoder = new BASE64Decoder();
  9. byte[] bytes = base64Decoder.decodeBuffer(encode); // 复原位字节数组
  10. s = new String(bytes,"UTF-8");// 还原原本的字符串

针对火狐的格式进行定制

  1. // 1. 获取文件名
  2. String s = "2.jpg";
  3. // 创建一个Base64编码器
  4. BASE64Encoder base64Encoder = new BASE64Encoder();
  5. // 执行 Base64 编码操作
  6. String encode = base64Encoder.encode(s.getBytes("UTF-8"));
  7. // 解码操作
  8. BASE64Decoder base64Decoder = new BASE64Decoder();
  9. byte[] bytes = base64Decoder.decodeBuffer(encode); // 复原位字节数组
  10. s = new String(bytes,"UTF-8");// 还原原本的字符串
  1. // s 进行 base64加密
  2. response.setHeader("Context-Disposition" , "attachment;filement==?UTF-8?B"+s + "?=");

7.4 使用 User-Agent 请求头,动态切换不同的方式处理附件中文乱码问题

  1. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.38
  1. if(req.getHeader("User-Agent").contains("Firefox")){
  2. // 包含火狐标记,我们进行 Base64 编码
  3. //...//
  4. }else{
  5. // 其他浏览器,另外编码
  6. }

8 Cookie 和 Session

8.1 Cookie

8.1.1 定义

  • cookie是服务器同时客户端保存键值对的一种技术,信息有浏览器保存,再返回服务器
  • 客户端有了Cookie后,每次请求都发送给服务器
  • 每个Cookie的大小都不可以超过 4kb

    8.1.2 如何创建 cookie

    可以一次创建多个

  1. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. response.setCharacterEncoding("UTF-8");
  3. // 解决中文乱码问题
  4. response.setContentType("text/html;charset=UTF-8");
  5. // 1. 创建Cookie对象
  6. Cookie cookie = new Cookie("key1", "value1"); // 现在还在服务器内存中而已
  7. // 2. 通知客户端保存
  8. response.addCookie(cookie);
  9. response.setHeader("set-cookie","");
  10. response.getWriter().write("Cookie 创建成功");
  11. System.out.println("isok");
  12. }

8.1.3 获取 Cookie

服务器获取客户端的Cookie只需要: Cookie[] cookies = request.getCookies();

8.1.4 修改 Cookie 的值

不支持中文和特殊值,如果要用必须要Base64编码

方案一:
直接同名覆盖,与map覆盖效果类似
方案二:

  1. 先调查找到需要修改的Cookie对象
  2. 调用 setValue() 方法赋予新的Cookie值
  3. 调用 response.addCookie() 通知客户端保存

    8.1.5 Cookie的存活设置

    Cookie 的生命控制指的是如何管理 Cookie 什么时候被销毁(删除)
    setMaxAge()
    正数:表示在指定的秒数后会过期
    负数:表示浏览器一关,Cookie就会被删除(默认)
    0 :马上删除 Cookie

    8.1.6 Cookie 有效路径 Path 的设置

    Cookie 的 Path 属性可以有效的过滤哪些 Cookie 可以发送给服务器,哪些不发,Path 属性是通过请求的地址来进行过滤的 ```markdown
  • CookieA path=/工程路径
  • CookieB path=/工程路径/abc

请求地址为:[http://ip:port/工程路径/a.html] cookieA 满足发送条件 cookieB 不满足发送条件

请求地址位:[http://ip:prot/工程路径/abc/a.html] cookieA 满足发送条件 cookieB 满足发送条件

  1. ---
  2. > 可以通过 setPath() 修改(位于 Cookie 类中)
  3. <a name="tSZx4"></a>
  4. #### 8.1.7 Cookie 实现免用户名登陆
  5. 表单处理流程:
  6. 1. 获取用户的账号和密码
  7. 1. 判断其有效性
  8. 1. 有效即登陆
  9. 1. 同时将用户名保存位Cookie发送给服务器
  10. - 当我们第二次登陆的时候,会把Cookie信息也发送给服务器,客户端就可以显示处用户名<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/22473566/1631015457054-8fb443a6-1cb8-4a8c-9d3b-f9da1c427f31.png#clientId=u51ab0ace-2b5e-4&from=paste&id=u62b426bf&margin=%5Bobject%20Object%5D&name=image.png&originHeight=775&originWidth=1620&originalType=binary&ratio=1&size=450918&status=done&style=stroke&taskId=u265b053f-aae8-4a96-887a-7f7fc1cdf81)
  11. <a name="wt87G"></a>
  12. ### 8.2 Session 会话
  13. <a name="aIC9c"></a>
  14. #### 8.2.1 什么是Session
  15. 1. Session :一类接口(HttpSession)
  16. 1. Session 就是会话。它是用来维护一个客户的服务器之间管理的一种技术
  17. 1. 每个客户端都有自己的一个Session 会话
  18. 1. Session 会话中,我们经常用来保存用户登陆的信息
  19. > 区别:Cookie 在客户端,Session 在服务器上
  20. <a name="codGI"></a>
  21. #### 8.2.2 如何创建Session 和获取 (id 号,是否位新)
  22. 创建和获取SessionAPI是一样的
  23. ```java
  24. request.getSession()
  25. - 第一次调用是:创建Session 会话
  26. - 之后调用都是:获取前面创建浩的 Session 会话对象,可以通过 isNew() 判断是否位新建的Session
  27. isNew()
  28. - true : 新
  29. - false : 旧
  30. 每个会话都有一个身份id,也就ID值,而且这个值是唯一的
  31. getId():
  32. - 获取到 Session 的会话 ID 值

8.2.3 向 Session 域中存取数据

  1. request.getSession().setAttribute("key1","value1");
  2. request.getSession().getAttribute("key1");

8.2.4 Session 生命周期

  1. setMaxInactiveInterval(int interval) : 设置 Session 的超时时间,超过指定时长,Session就会被销毁,负数表示永不超时(很少使用),0不对应立即无效化接口
  2. getMaxInactiveInterval() : 获取Session 超时时长
  3. - 默认的生命时长是:1800 秒,在tomcat中可以设置
  4. invalidate()
  5. - 使session立即超时无效

在web.xml添加设置 (作用与全局,个别修改使用上面的api为好 )

  1. <session-config>
  2. <session-timeout>20</session-timeout>
  3. </session-config>

超时的概念:用户不发起访问请求。每次访问会重置计时器。

8.2.5 浏览器与Session之间的关联的技术内幕

9 四大域对象

四个域的作用域范围大小:PageContext (page域) < request < session < servletContext(application域)
一、ServletContext
1、生命周期:当Web应用被加载进容器时创建代表整个web应用的ServletContext对象,当服务器关闭或Web应用被移除时,ServletContext对象跟着销毁。
2、作用范围:整个Web应用。(跟随服务器创建到销毁)
3、常用功能:
(a)在不同Servlet 之间转发
(b)读取资源文件。
二、Request 域
1、生命周期:在service 方法调用前由服务器创建,传入service方法。整个请求结束,request生命结束。
2、作用范围:整个请求链(请求转发也存在)。
3、常用功能: 在整个请求链中共享数据。例如在Servlet 中处理好的数据交给Jsp显示,此时参数就可以放置在Request域中带过去。
三、Session 域
1、生命周期:在第一次调用 request.getSession() 方法时,服务器会检查是否已经有对应的session,如果没有就在内存 中创建一个session并返回。当一段时间内session没有被使用(默认为30分钟),则服务器会销毁该session。如果服务器非正常关闭(强行关闭),没有到期的session也会跟着销毁。如果调用session提供的invalidate(),可以立即销毁session。
注意:服务器正常关闭,再启动,Session对象会进行钝化和活化操作。同时如果服务器钝化的时间在session 默认销毁时间之内,则活化后session还是存在的。否则Session不存在。如果JavaBean 数据在session钝化时,没有实现Serializable 则当Session活化时,会消失。
2、作用范围:一次会话。(跟随浏览器,一同启动和销毁,只和浏览器的开关有关,其钝化和活化机制,只要我们的cookie中的标识码存在,就可以唯一找到目标对象)
3、常用功能:为浏览器创建独一无二的内存空间,在其中保存会话相关的信息。
四、PageContext 域 (JSP相关)
1、生命周期:当对JSP的请求时开始,当响应结束时销毁。
2、作用范围:整个JSP页面,是四大作用域中最小的一个,即超过这个页面就不能够使用了。(所以使用pageContext对象向其它页面传递参数是不可能的.)
3、常用功能:
(1)获取其它八大隐式对象,可以认为是一个入口对象。
(2)获取其所有域中的数据
(3)跳转到其他资源,其身上提供了forward和include方法,简化重定向和转发的操作。