Java 中的 Servlet&Http&Request

# 今日内容 :
1. Servlet
2. HTTP 协议
3. Request (就是 Servlet 中 service 方法的 形参. (有这个))
 
 
## Servlet :
1. 概念
2. 执行步骤
3. 执行原理 (反射)
4. 生命周期
5. Servlet 3.0 注解配置.
 
6. Servlet 的 体系结构
Servlet -- 接口
有 这 两个 实现类.
|
GenericServlet ---- 实现了 Servlet 接口, 它是 一个 抽象类. 儿子
|
HttpServlet 继承了 GenericServlet 它 是一个 抽象类. 孙子.
 
GenericServlet : 将 Servlet 接口中 其他的方法 做了 默认 空实现, 只将 service() 方法 作为 抽象.
* 将来 定义 Servlet 时, 可以 继承 GenericServlet , 实现 service() 方法 即可.
* 其它的 方法 想 复写 哪个 就复写 哪个.
 
idea 使用: 复写 方法的 话, 知道方法名, 直接打 方法名, 会有提示 复写方法.
 
 
 
GenericServlet 类 实现了 Servlet 接口, 实现了 除 service() 以外的 其它 方法, 那些 方法的 实现 都是 空实现, 只有 一个 abstract service() 是 抽象的, 我们 继承 这个 类 时 只需要 重写 这个 抽象的 service() 方法, 这就 达到了 我们的 初步需求, 只 实现 service() 这一个 方法.
(但是 实际开发中,一般 不用这种方式. )
 
* HttpServlet : 是对 HTTP 协议的 封装 和 描述., 简化操作.
不再 复写 service 方法, service 方法 人家 给你 逻辑判断过了 get, post 等 请求方式.
1. 定义类 继承 HtttpServlet.
2. 复写 doGet / doPost 方法.
 
( *** 推荐 以后 写 Servlet 的 时候, 继承 HttpServlet , 复写 其中的 doGet 和 doPost 方法. )
* 如果 不是继承它, 你就要开始 写 判断逻辑, 获取 请求方式, 如果 是 get, 如果 是 post , 怎么怎么样, 繁琐, 继承 HttpServlet 就只要 重写 doGet() 或者 doPost 中 自己的 需求 即可, 已经 获取到 请求方式.
 
Http协议 有 7 中 请求方式, 常用的 就 get post 两种.
通过 浏览器 直接请求 是 doGet 方式.
我们现在 掌握的知识 只有 表单 才有 post 这种 请求方式.
80
After lanuch : 这个 不勾选 的话, 服务器启动了, 不会自己打开 浏览器 . 需要手动 打开浏览器.
/
 
 
我们 编写一个 类 继承 Servlet 接口 就要实现 其中 所有的 方法, 不得不实现, 我们 这个 类 也不是 一个 抽象类, 但是 大多数 情况下 我们 只需要 用 service() 一个 方法 就可以了. 所以 怎么办?
先 了解 Servlet 继承的 体系结构.
 
 
 
7. Servlet 相关配置 (web.xml 注解配置)
配置啥:
1. urlpattern : Servlet 访问 路径.
 
在 注解配置 WebServlet 中
String[ ] urlPatterns() default {};
这里定义的 urlPatterns 是一个 数组, 数组的 意思就是说 将来我们 可以为 这 一个 Servlet 定义 多个 访问 路径.
 
* 一个 Servlet 可以定义多个 访问 路径 : (不过 一般 我们还是 只 定义一个.)
 
写法: @WebServlet({"/d4","/dd4","/ddd4","/demoFour"})
 
2. 路径的 定义规则:
1. / xxx
2. /xxx/xxx : 多层 路径, 目录结构,
3. *.do
 
*
* Servlet 路径配置.
*
*/
// *** 多个 就要 用大括号 括起来, 一个的话 大括号 就可以省略.
// 1. @WebServlet({"/d4","/dd4","/ddd4","/demoFour"})
 
// *** 这里写的 有 两层 路径, 将来 访问的 时候 就要将 这两层 路径 都写上.
// @WebServlet("/user/demo4")
 
// *** 也可以写成 , 这种形式, 代表 /user 后面 想写啥 就 写啥. * 是一个 通配符.
// @WebServlet("/user/*")
 
// *** 更狠, 写什么 都可以访问到 ServletDemo4.
// /* 的这种方式优先级 是最低的, 是 别的 都访问 不到 才会找它.
// @WebServlet("/*")
@WebServlet("*.do") // *** * 前面 不能加 / , 否则 会报 资源的 配置 路径 不合法. .do 可以随便写.
public class ServletDemo4 extends HttpServlet {
 
查询 JavaEE 的 API (中的 Servlet interface)
 
 
 
 
## HTTP :
* 概念: Hyper Text Transfer Protocol 超文本 传输协议.
* 传输协议 : 定义了 客户端 和 服务器端 通信时, 发送数据的 格式(规则).
* 特点:
1. 基于 TCP / IP 的 高级协议. (TCP 是一个 安全的 协议,经过 三次 握手, HTTP 是基于 TCP的, 所以 HTTP 也是一个 安全的 协议. )
2. 默认端口号: 80
例如: http://www.itcast.cn : 80
3. 基于请求 / 响应模型的, 一次请求 对应 一次响应.
4. 无状态的 : 每次 请求之间 相互独立, 不能通信(交互)数据.
 
// *** 一个网页中, 每一个 图片资源, css 资源, js 资源 等等 都要发 请求. 每一次 的请求 最后 才组成了 这个 页面.
 
// *** 打开 网页, F12, Network 里 列表的 每一项 都是一次请求 或者 一次响应. (网页中的 图片 也会有对应的 响应, copy url , 搜索 url , 得到 这张图片, 哈哈. )
* 历史版本:
HTTP 1.0 : 每一次请求 都会建立 新的连接 . (效率低, 消耗资源. )
HTTP 1.1 : 复用这个连接, 对 缓存的 支持比较好. (也就是说, 第一次 请求, 连接上了, 返回响应, 等一会, 如果 后面还有资源, 那么 复用 这个连接, 不需要建立 新的连接. )
 
 
HTTP 协议 请求 和 响应 是两部分, 所以 会有 两部分的 格式.
 
 
// *** login.html F12, Network Headers General Response Headers Request Headers
 
 
// *** 在 Firefox 浏览器中, F13 , 网络, 消息头, 请求头 原始头.
* 请求消息 数据格式
1. 请求行
请求方式 请求url 请求协议 / 版本
GET login.html HTTP / 1.1
 
* 请求方式:
* HTTP 协议 有 7中 请求方式, 常用的有 2 种
* GET :
1. 请求参数 在 请求行中, (在 url 后) 例如: http://localhost/demo3?username=zhangsan
2. 请求的 url 长度 是有限制的.
3. 不太安全 (请求消息的 位置在 url 地址栏中. )
* POST :
1. 请求参数 在 请求体 中.
2. 请求的 url 长度是没有限制的. (例如 上传一个 文件, 就只能用 POST, 文件的 长度 远远超过了 url 的长度. )
 
知道了 这两种方式的 区别, 以后 用代码 来获取 这个 请求参数, 才知道 在哪里 获取.
3. 相对安全. (请求消息的 位置在 请求体中.)
 
但是 会的人, 通过 抓包 技术, 拦截 你这个 请求, 请求体一样还是被 获取到 .
 
 
 
2. 请求头 : 客户端 (浏览器) 告诉 服务器 一些 信息, (服务器 可以来 解析 这些 信息)
 
这些 信息 头 都是 固定的, 值 是 不一样的. 例如: Host : localhost , Host: 10.254.1.219
 
请求头名称 : 请求头的 值(有多个值, 用 逗号 隔开) (浏览器 告诉 服务器 我自身的 一些 信息. )
* 常见的 请求头:
0. Host : 表示 了 请求的 主机 是 localhost
1. User-Agent : 浏览器 告诉 服务器, 我访问你 使用的 浏览器 版本信息.
* 可以在 服务器端 获取 该 头的 信息, 解决浏览器的 兼容性问题(将来会在 编码中 使用它).
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
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0
 
* 告诉服务器, 我(当前请求) 从 哪里来?
* 作用:
1. 防盗链 :
2. 统计工作 :
 
 
referer 就是在当前 这个 电影的 播放页面 获取当前 这个 (超链接) 请求, 从哪里来, 你如果 是从 优酷首页来, 就让你 放电影, 如果不是, 说明 当前 这个 请求链接 是被盗取的, 是 盗链来的 一个请求.
 
 
 
3. 请求空行
 
空行 (起分隔 作用, 分隔 POST请求 请求头 和 请求体. )
4. 请求体(正文)
GET 方式 请求 是 没有 请求体的.
 
* 封装 POST 请求消息的 请求体(请求参数)的. (参数)
 
username = zhangsan
 
* 字符串格式 :
POST / login.html HTTP / 1.1 // *** 请求行 下面 就是 请求头 , 没有 分隔.
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive (1.1)
Upgrade-Insecure-Requests: 1 (关于升级的信息)
If-Modified-Since: Sat, 30 Nov 2019 01:43:36 GMT
If-None-Match: W/"549-1575078216305"
Cache-Control: max-age=0
 
username = zhangsan
 
*** 消息体(正文) :
将 login.html 这个表单中的 method 改为 POST, 在 页面中 输入 数据, 提交,
这时 F12 , 网络 消息头, 请求方法 : POST, 参数 username: zhangsan (这种形式 是 浏览器 解析后的结果. )
 
消息体的内容:
username = zhangsan
 
* 响应消息 数据格式
 
 
3. Request
 
ServletRequest servletRequest, ServletResponse servletResponse
 
servletRequest 对应的 就是 请求消息 数据.
servletResponse 对应的 就是 响应 消息数据.
 
## Request :
1. request 对象 和 response 对象的原理:
1. tomcat 服务器 会根据 请求 url 中的 资源路径(demo1), 创建 对应的 ServletDemo1 的对象
2. tomcat 服务器, 会创建 request 和 response 对象, request 对象 中 封装 请求消息 数据.
3. tomcat 将 request 和 response 两个 对象 传递给 service 方法, 并且 调用 service 方法.
4. 程序员(我们) , 可以通过 request 对象 获取 请求消息数据, 通过 response 对象 设置 响应 消息数据
5. 服务器 在 给 浏览器做出响应 之前, 会从 response 对象中 拿 程序员 设置的 响应消息数据, 放到 响应 消息中, 返回给 客户端(浏览器)
 
1. request 和 response 对象 是由 服务器(tomcat) 创建的. 我们来使用它们
 
2. request 对象 是用来 获取请求 消息的, response 对象 是用来 设置 响应消息.
 
2. request 对象 继承 体系结构 :
ServletRequest -- 接口
| 继承
HttpServletRequest -- 接口 (查阅 还是 看这个 接口的 源码, 因为 tomcat 编写的 这个类 是实现 HttpServletReques 这个接口的, 实现了 其中的 方法. )
| 实现
org.apache.catalina.connector.RequestFacade -- 类 (tomcat 编写的. tomcat 将来 就会通过 这个类 来创建 Request 的对象, 来 传递 给 service 方法. ) (多态, 父类型 接收 子类对象. )
 
查阅 tomcat 的源码包.
java / org / apache / catalina / connector / RequestFacade.java
 
发现 : public class RequestFacade implements HttpServletRequest{
 
}
 
查阅 javaEE 开发文档, SevletRequest.
 
 
 
 
 
3. request 功能 :
 
1. request : 获取 请求 消息数据 :
获取 :
1. 请求行 数据
请求方式 请求 url 请求的参数 HTTP 协议 版本
* GET / day14 / demo1?name = zhangsan HTTP / 1.1
* 方法 : (HttpServlet)
1. 获取 请求方式 : GET // *** 这个 方法 已经被 service 方法 内部使用了, 因为 我们 这里要走的 就是 doGet 或者 doPost 方法. 说明 已经 给我们 判断过了, 我们 用到的 机会 会 很少.
* String getMethod( );
 
2. (** 重点掌握) 获取 虚拟目录 : /day14
* String getContextPath( );
 
3. 获取 Servlet 的 路径 : / demo1
* String getServletPath( );
4. 获取 GET 方式的 请求参数 : name = zhangsan
// 4. 获取 GET 方式的 请求参数 : name=zhangsan 这里 现在只有一对参数, 如果 有很多 参数, 我们 用 & 符号隔开, 这个 方法 会将 后面的 所有 参数 都获取到. (这个 方法 也一般 不用. )
// *** name=zhangsan&age=12 每一对 用 & 分隔.
* String getQueryString();
5. (** 重点掌握)获取 请求的 URI : /day14/demo1 (权限 控制 框架 的 时候 会用. )
* String getRequestURI( ); : /day14/demo1
* StringBuffer getRequestURL( ); : http://localhost/day14/demo1
 
// *** 请求的 Servlet 资源路径.
* URL : 统一资源定位符 : http://localhost/day14/demo1 例如: 中华人民共和国
* URI : 统一资源标识符 : /day14/demo1 (这个 代表的 范围更大一些. ) 没有 IP 和 端口号. 例如: 共和国
 
6. 获取 协议 及 版本 : HTTP / 1.1
* String getProtocol (Servlet)
 
7. (** 重点掌握 ) 获取 客户机的 IP 地址 :
* String getRemoteAddr( ); (Servlet)
 
2. 获取请求头 数据
* 方法 :
(**)String getHeader(String name) : 通过 请求头的 名称 获取请求头的 值. 一般 只用 这个方法, 因为 我们 已经 明确 有哪些头.
* Enumeration<String> getHeaderNames( ) : 获取 所有的 请求头名称.
 
jdk 开发文档 : Enumeration : 枚举, 一个 接口, 该接口的 功能 由 Iterator 接口复制.
hasMoreElements( ); boolean
测试 此 枚举是否 包含 更多 元素.
nextElement( );
如果 此 枚举对象 至少有一个要提供的 元素, 则返回此枚举 的 下一个元素.
 
 
这里 要演示 盗链的 功能 , 要两个 tomcat 服务器 启动, 所以 这里 加一个 tomcat 服务器.
新创建的 tomcat 服务器的 名字, 端口号, JMX port 端口号 都不能相同, 然后 部署一下 项目, 改一下 虚拟 路径.
分别启动 两个 tomcat.
判断 referer
package request;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author Yujiang
 * @create 2019-12-02-13:04
 */
@WebServlet("/requestDemo4")
public class RequestDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // *** 演示 获取 请求头数据:  referer   :  告诉 服务器 , 链接, 请求 从哪里来.
        // *** 现在不是 点别人的 超链接 访问的 demo4, 是在 浏览器 地址栏中 直接输入的, 所以 referer 是没有的. 获取 不到.
       // *** 应该 从一个 链接 或者 从 一个 路径 点进来 访问到 demo4.
        String referer = request.getHeader("referer");  // *** 获取 referer 请求头中 对应的 值.

        System.out.println(referer);  // *** null  // *** 之后 写了 一个 超链接,  输出结果: http://10.254.1.219/day14/login.html  表示 是从 login.html 页面中来的.

     // *** 防盗链 :  例如 看电影:

     if(referer != null){
         if(referer.contains("/day14")){

            // *** 假设 这里的 day14  是 优酷 首页 , 正常访问
          //   System.out.println("播放电影......");
             // *** 写成中文

             response.setContentType("text/html;charset=utf-8");
             response.getWriter().write("播放电影......");

         }else{
             // *** 盗链

          //   System.out.println("想看电影吗? 来优酷吧...");

             response.setContentType("text/html;charset=utf-8");
             response.getWriter().write("想看电影吗? 来优酷吧...");

             // *** 使用 response 对象 就可以在 页面上 展示了. 
         }


         // *** 现在 是输出到 控制台, 将来 学习了 response 对象 是可以 往 页面里面    输出 数据的.

        // *** 需要 两个项目 来访问, 一个 虚拟目录 包含 day14, 另一个 例如 是自己写的 电影网站, 是不包含 day14 的.



     }
    }
}
 
播放电影......
想看电影吗? 来优酷吧...
***
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("想看电影吗? 来优酷吧...");
 
 
 
(3. 请求 空行)
 
3. 获取 请求体数据 :
* 请求体 : 只有 POST 请求方式, 才有请求体, 在 请求体中 封装了 POST 请求的 请求参数.
request 对象 对 请求体 中的 数据 将其 封装成 流.
* 步骤 :
1. 获取 流对象 (获取 一个 字符输入流,; 如果 是 文件的 上传, 图片 等 就是 字节流
Bufferedreader : 高效的, 带有缓冲区的, 有 readline 方法的.
* Bufferedreader getReader( ) : 获取字符输入流, 只能 操作 字符 数据
 
* ServletInputStream getInputStream( ) : 获取 字节 输入流, 可以 操作 所有类型的 数据.
* 将 这个 流 就当作 InputStream 来使用, 因为 它 继承了 InputStream.
* 在 文件上传 知识点 后 讲解.
2. 再 从 流对象 中 拿 数据.
 
 
 
2. 其他 功能 (重要 ):
1. 获取 请求 参数 通用方式 : 不论 get 还是 post 请求方式 都可以使用 下列 方法 来获取 请求 参数.
1. String getParameter(String name) : 根据 参数名称 获取 参数值. 例如 : username=zhangsan&password=123; (常用)
2. Stirng[ ] String getParameterValues(Stirng name) : 根据 参数名称 获取 参数值的 数组. (了解. )
例如: hobby=xx&hobby=game
(这种 多用于 复选框)
Enumeration: 是个 枚举.
3. Enumeration<String> getParameterNames( ): 获取 所有的 请求参数的 名称. (了解.)
4. Map<String , String[ ]> getParameterMap( ): 获取 所有参数 的 map 集合, 键值对 的集合. (常用)
 
* 中文 乱码 问题 :
(在很多的 页面上 , 我们 可能都需要 填写 中文, 这时 后台 获取到的 中文 信息 可能 会出现 乱码 问题. )
 
* get 方式 : tomcat 8 已经 将 get 方式乱码 问题 解决了.
 
* post 方式 : 会乱码
* 解决 : 在 获取 参数前, 设置 request 的 编码 request.setCharacterEncoding("utf-8"); (这个 编码 就是从 我们 的 HTML 页面中 而来. )
 
那也就是说, 无论 post 还是 get 请求方式 在 获取 参数的 编码的 第一行 都写上 request.setCharacterEncoding("utf-8");
 
 
2. 请求转发 : 一种 在 服务器 内部的 资源跳转 方式.
1. 步骤 :
1. 通过 request 对象 获取 请求 转换器 对象. RequestDispatcher getRequestDispatcher(String path); 这个 方法 传一个 要 访问 的 资源的 路径.
2. 使用 RequestDispatcher 对象 进行 转发 : forward(ServletRequest request, ServletResponse response)
 
2. 特点 (面试题) :
前提 : 只 请求了 requestDemo9 , 访问到了 requestDemo 和 requestDemo10 两个 资源.
1. 浏览器 地址栏 路径 不发生 变化.
2. 只能 转发到 当前 服务器 内部资源中.
3. F12 , Network (抓包 工具), 转发 是 一次 请求. 使用的是 同一次 请求.
 
 
3. 共享数据
* 域对象 : 一个 有 作用 范围的 对象, 可以在 范围内 共享数据. 域 : 范围.
* request域 : 代表一次 请求的 范围. 因为 转发 属于 一次 请求, 所以 这个 request 域 一般用于 请求 转发 的 多个资源中 共享数据.
* 方法 :
1. void setAttribute(String name,Object obj) : 存储 数据.
2. Object getAttribute(String name) : 通过 键(名称) 获取值.
3. void removeAttribute(String name) : 通过 键 移除 键值对
 
*** 在 转发 之前 存储 数据到 request 域 中.
1. request 域 的范围 是 一次请求, 它 只能 用于 转发的 情况.
一次 请求 访问 多个 资源的 情况下, 也就是 转发 的 情况下 才可以使用 request 域 来 共享 数据.
 
4. 获取 ServletContext :
 
使用 request 对象 中的 方法 : ServletContext getServletContext( );
 
ServletContext servletContext = request.getServletContext();
System.out.println(servletContext); // *** 输出 结果: org.apache.catalina.core.ApplicationContextFacade@576e2cd5
 
这个 对象 以后说.
 
 
 
补充: 在 idea 工具中, 可以直接 new Servlet, 它会 自动补全 注解 配置. 继承 HttpServlet , 复写 doPost( ), 和 doGet( ) 方法.
 
## Response 对象 :
* 功能 : 设置 响应 消息
1. 设置 响应 行
1. 格式 : HTTP / 1.1 200 ok 200 : 状态码
设置 状态码 : setStatus(int sc)
 
2. 设置 响应 头
1. 格式 :
setHeader(String name, String value)
3. 设置 响应 体 :
* 使用 步骤 : 通过 流 的 方式 : 与 请求体 一样, 获取的 话 要通过 流 的 方式. (getReader( ) )
1. 获取 输出流 : (输出 到 客户端 浏览器上 )
* 字符 输出流 :
PrintWriter getWriter( ); (返回一个 打印流 对象 )
* 字节 输出流 :
ServletOutputStream getOutputStream( ) (可以当作 OutputStream 来使用. )
 
通过 字符 输出流 只能 输出 字符型 的数据, 通过 字节 输出流 可以 输出 任何 数据.
2. 使用 输出流, 将 数据输出到 客户端 浏览器.
 
 
* 案例 :
1. 完成 重定向
 
* 重定向 : 资源跳转的 方式. (请求 转发 也是 资源 跳转的 一种方式. )
* 代码 实现 :
 
// 访问 /requestDemo1 这个 资源, 会自动跳转到 /requestDemo2 这个资源.
 
// 1. 设置 状态码 为 302
 
// response.setStatus(302);
 
// 2. 设置 响应头 location
// response.setHeader("location" ,"/day15/responseDemo2");
 
// *** 以后重定向 这种 资源 跳转的 方式 会用的 比较多, 那这里的 方法中 的 可变 部分 就是 只有 跳转的 资源 路径 可变.
 
// *** 为此, 提供了 一种 简单的 重定向 方法.
 
response.sendRedirect("/day15/responseDemo2"); // *** (将来 要用 重定向的 话,, 就用 这个 方法. )
 
// *** 当然 这个 方法 的 内部 原理 也就是我们 上面 写的 两行 代码, 它 将 我们 上面的 两行 代码 封装进了 这一个 方法 里面.
 
* 重定向的 特点 : redirect (面试题, 重定向 与 转发 的 区别. )
1. 地址栏 发生 变化.
 
2. 重定向 可以 访问 其他 站点 (服务器) 的 资源.
 
3. 重定向 是 两次 请求. 意味着 有 两次 request 请求, 就 不能 使用 request 域对象 共享 数据了.
responseDemo1
302
 
Other
105 B
70 ms
responseDemo2
200
document
responseDemo1
73 B
8 ms
重定向的 请求 还可以 再 重定向 到 其他 资源上.
 
 
 
* 转发的 特点: forward (也是 资源 跳转的 一种 方式 .)
1. 转发 地址栏 路径 不变
 
2. 转发 只能 访问 当前 服务器下的 资源.
 
3. 转发是一次 请求, 可以使用 request 对象 来 共享数据.
 
* forward 和 redirect 区别. (面试题 )
 
* 路径的 写法 (重要) :
1. 相对路径 : 通过 相对路径 不可以确定 唯一资源. (有一个 相对 位置 关系. )
* 如 : ./index.html 如 : ./ 表示 在 当前 目录下, 那 当前 目录 是 哪个 目录.
* 简单的 说, 不以 斜杠 / 开头 , 以 . 开头 的 路径 称为 相对路径.
 
* 规则 : 要找到 当前 资源 和 目标资源 之间的 相对位置 关系. 就可以 将 相对 路径 写出来. (相对位置 关系: 例如 : 在 当前资源下, 或者 在 当前 资源里头 ...)
 
*
./ : 当前 目录
 
../ : 后退一级 目录 (上一级 目录)
 
*** 以后如果 使用 JSP 页面 , 不推荐 使用 相对路径, 相对路径 写起来 麻烦, 要确定 位置关系, JSP 推荐使用 绝对路径.
 
2. 绝对 路径 : 通过 绝对路径 可以确定 唯一 资源.
* 如 : http://localhost/day15/requestDemo2 /day/requestDemo2
 
* 简单的 认为, 以 / 开头的 路径 是 绝对 路径.
 
* 规则 : 判断 定义的 路径 是 给谁用的 ? 判断 请求 从哪 发出?
 
* 给客户端 浏览器使用 : 需要加 虚拟 目录. (项目的 访问 路径. )
* 建议 虚拟目录 动态 获取 : request.getContextPath( );
获取当前项目根地址
比如你现在的URL是192.1.1.1:8080/my/index.jsp
tomcat配置的当前项目访问地址是192.1.1.1:8080/my
request.getContextPath()得到的就是192.1.1.1:8080/m
 
request.getContextPath()是在开发Web项目时,经常用到的方法,其作用是获取当前的系统路径。
* <a> , <form> 重定向.
* 给 服务器 使用 : 不需要加 虚拟目录. (转发 的 时候 不需要加 虚拟目录. )
 
重定向 是 客户端 (浏览器)路径, 重定向 需要 加 虚拟目录.
 
是在 服务器 内部 喊得, 喊谁 谁知道, 所以 不需要 虚拟 目录 ; 是在 客户端(浏览器) 喊得, 多个 目录下 也许 有相同的 文件, 谁知道 你喊谁 ,所以要加 虚拟 目录.
 
虚拟目录 写死, 将 虚拟目录 改掉, 原来的 路径 就没有用. 一改 , 代码 全改. 使用 动态 获取 虚拟 目录 .
 
 
 
 
2. 服务器 输出 字符 数据 到 浏览器.
* 步骤 :
1. 获取 字符 输出流 : (这个 流 的 流向, 流到 客户端 浏览器的. )
2. 输出数据
* 注意 :
* 乱码 问题 : (乱码 问题 主要是 编解码 不一致 造成. )
1. PrintWriter pw = response.getWriter( ); 获取的 流 的 默认编码是 ISO-8859-1
2. 设置 该流 的 默认 编码
3. 告诉 浏览器 响应体 使用的 编码.

        // *** 在 获取 流 对象之前,  设置 流的 默认 编码,  ISO-8859-1  设置为 GBK.

      //  response.setCharacterEncoding("UTF-8");

        // *** 告诉 浏览器,   服务器 发送的 消息体 的 数据的 编码 方式.  建议 浏览器 使用 该 编码 解码.

        // *** 1. Content-Type :  服务器 告诉 客户端 本次 响应体 数据格式 以及 编码 格式.
                                     // ***     文本数据 , 子类型 html  编码
       //  response.setHeader("Content-Type","text/html;charset=utf-8");
// *** 浏览器 看到 这个消息, 就一定会以 utf-8 解码.

        // *** 因为 上面这句话, 的 content-type 是固定的, 每次 都要写 , 很麻烦, 所以 提供了 另外的 一个 方法.

        // *** 简单的 形式 , 设置编码

        response.setContentType("text/html;charset=utf-8");


        // *** 一定要在 获取 流 之前 写上 这行 代码. 
        
// *** 简单的 形式, 设置编码, 是在 获取流 之前 设置
*** response.setContentType("text/html;charset=utf-8");
 
3. 服务器 输出 字节 数据 到 浏览器.
* 步骤 :
1. 获取 字节输出流 :
 
2. 输出 数据 :
 
// 1. 获取 字节 输出流.
 
// *** 告诉 浏览器
response.setContentType("text/html;charset=utf-8");
 
// *** 保证了 客户端 知道了 服务端 用什么 编码 给你 发数据, 然后 客户端 也会用 这种 编码 去 解码, 就不会 有 乱码 错误了.
字节输出流 一般用于 输出 图片, 字符输出流 一般用于 输出文本 字符.
 
 
 
4. 验证码 (本质上 是一张 图片,只不过 这张图片 是保存在 内存中的, 会以 二进制的 方式 输出 到 浏览器上. )
1. 本质 : 是图片
2. 目的 : 防止 恶意 表单 注册. (没有验证码, 死循环, 随机生成 用户名,密码等, 不停的 注册, 数据库 崩溃).
 
 
 
验证码 大多数 采用的 都是 在 程序里 动态 生成的 方式.
完成 验证码的 生成, 以及 输出到 页面上.
 
以后 用的 话, 不会 写 这么 复杂的, 回去 网上 找些 好看的 模板 改一改.
 
 
2. 响应头 :
1. 格式 : 头名称 : 值
 
2. 常见的 响应头 :
1. Content-Type : 服务器 告诉 客户端 本次 响应体 数据格式 以及 编码 格式.
2. Content-disposition : 服务器告诉 客户端 以什么 格式 打开 响应体 数据.
* 值 :
* in-line : 默认值, 在当前 页面内 打开.
* attachment; filename=xxx : 以附件形式 打开 响应体. 文件下载.
 
3. 响应 空行.
 
4. 响应体 : 传输 的 数据.
 
 
## ServletContext 对象.
1. 概念 :代表 整个 web 应用, 可以和 程序(servlet)的 容器 (服务器: tomcat) 来通信.
就是说 通过 ServletContext , 里面的 servlet 程序里面 可以去和 web 容器 去 通信.
2. 获取 :
1. 通过 request 对象 获取
request.getServletContext();
2. 通过 HttpServlet 来 获取.
this.getServletContext(); // *** 我们的 Servlet 是 继承 HttpServlet , HttpServlet 中 有 getServletContext(); 这个 方法 可以 直接 拿来用.
 
 
*** 这个 ServletContext 对象 代表的 是整个 web 应用, web 应用 就那 一份, 在 一个 工作空间中 获取 再多的 ServletContext 对象 都是一样的. *** 都是 那一个 对象.
 
3. 功能 :
 
1. 获取 MIME 类型: (在 互联网 通信过程中 文件类型的 一种 标准, HTTP 协议 也遵循了 这种 标准. )
* MIME 类型 : 在 互联网 通信过程中 定义的 一种 文件数据类型.
* 格式 : 大类型 / 小类型 例如 : text / html : 这就是 一个 非常 标准的 MIME 类型, 表示 这个 数据是 纯文本的, 并且 里面定义的 是 HTML 形式的.
 
又例如 : image / jpeg
 
功能 : HTTP 协议中 有一个 响应头 是 ContentType(); 设置 文件的 MIME 类型. 告诉 浏览器 我发送的 响应 消息是 什么 格式, 你得 用 相应的 解析 引擎 去 解析 它们.
 
1. *** 给 客户端 发送 数据, 得 去 获取 发送数据 对应的 MIME 类型, 然后 告诉浏览器. 用 相应的 解析 引擎 去 解析 它们.
 
* 获取 : String getMimeType(String file); (其实 是通过 文件的 扩展名 来获取的. )
 
 
 
这些 类型 都是 在 服务器中 存储着的, 因为 ServletContext 对象 可以 和 服务器 进行通信, 所以 可以 获取 到 这些 MIME 类型.
 
tomcat 配置文件中 有一个 web.xml 文件 这个 文件是 所有 的 项目的 web.xml 的爹,
我们的 项目 都继承了 这个 web.xml
 
例如 :
<mime-mapping>
<extension>jpg</extension>
<mime-type>image/jpeg</mime-type>
</mime-mapping> ...
 
MIME 类型.
 
调用 方法, 动态的 获取 web.xml 配置文件中的 MIME 类型.
 
2. 域对象 : 共享 数据 (下面 这 三个 方法 是 所有的 域对象 都有的, 例如 request 域对象. )
1. setAttribute(String name,Object value)
2. getAttribute(Stirng name);
3. removeAttribute(String name);
 
ServletContext 对象 代表的是 整个 web 应用.
* ServletContext 对象 范围 : 所有用户 所有请求的 数据.
例如 : zs 往里面 存数据, zs 走了, ls 也可以 拿到 这个 数据, 共享所有 用户的 数据. 只要有 ServletContext 对象.
 
用这个 对象 非常 谨慎, 所有用户 共享了, 意味着 , 所有的 用户 都可以 操作它, 不太 安全.
 
这个 对象 生命 周期 非常长, 从 服务器 启动 到 服务器 关闭, 所以 这个对象 再 内存中 驻留的 时间 很长, 在 ServletContext 这个 对象里 存的 数据多了 会造成 内存的 压力 大.
 
 
3. 获取 文件的 真实(服务器)路径. (以后 都是 部署在 远程 服务器上的, 不存在 本地工作空间的 .)
1. 方法 :String getRealPath(String path); (重要)
     // 1. 通过 HttpServlet 获取 ServletContext 对象

        ServletContext context = this.getServletContext();

        // 2. 获取 文件的 服务器(真实) 路径
        // *** 例如 读取 不同位置的 配置文件, 路径 不好写, 使用 context  获取 文件的 真实(服务器) 路径.

        String realPath = context.getRealPath("/b.txt");  // web 目录下 资源访问.


        System.out.println(realPath);
        // *** 输出 结果 : E:\IDEA\Project01\out\artifacts\day15_response_war_exploded\b.txt
        File file = new File(realPath);

        String c = context.getRealPath("/WEB-INF/c.txt"); // *** WEB-INF 目录下的  资源 访问.

        System.out.println(c);


        // *** src 目录下的 所有东西 将来 会被放到 WEB-INF 目录下的 classes 目录下去.

        String a = context.getRealPath("/WEB-INF/classes/a.txt");   // src 目录下的 资源访问.
        System.out.println(a);


        // *** 接下来 可以通过 输入流 来 加载 这个 文件 进 内存了.

        // *** 每一个 项目 都对应着 一份 配置 文件.
        // C:\Users\闲客\.IntelliJIdea2019.2\system\tomcat\_Project01
        // 其中的 配置文件中 , 真正对应的 服务器中的 路径是: docBase="E:\IDEA\Project01\out\artifacts\day15_response_war_exploded" />
                // 就是 这个 目录里的 东西 被 发布到 服务器 里面,  并且 访问它.  out 目录下, 不在 webapps 目录下.

        // *** 现在 / 代表  E:\IDEA\Project01\out\artifacts\day15_response_war_exploded


// *** 以后 配置文件 放的 位置 的 不一样, 要会写 获取 真实 路径的 字符串写法.
// *** classloader 类加载器 也可以 获取 src 下的 真实 路径, 但是 获取 不了 web 目录下 文件的 真实路径, 局限性 较大.
 
// *** 以后 要会写 服务器 上 部署的 文件的 真实(服务器) 位置路径, 比如 说 这些 文件 是 配置文件, 就可以读取过来 加载进 内存了.


posted @ 2019-12-12 20:00  裕江  阅读(685)  评论(0编辑  收藏  举报