1. Servlet 技术
1.1 Servlet 的概念
- servlet 是 JavaEE 规范之一,规范就是接口
- Servlet 就 JavaWeb 三大组件之一,三大组件分别是 Servlet 程序、Filter 过滤器、Listener 监听器
- Servlet 是运行在服务器上的java小程序,他可以接受用户发送的请求,并发出响应
1.2 手动实现 Servlet
- 基础 Servlet 类,并实现其中的接口方法
- 其中 Service 方法是专门处理请求和响应的方法,只要访问目标程序就会触发、
- 使用前要配置 web.xml
<servlet>
<servlet-name>HelloServlet</servlet-name> // 程序的别名
<servlet-class>com.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<!--Servlet-name 的作用告诉服务器,我当前配置的地址是哪个Servlet程序使用-->
<servlet-name>HelloServlet</servlet-name>
<!---->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
常见的错误:
- 404 :丢失
- 500: servlet-class 标签全类名错误
1.3 Servlet 的生命周期
- 执行 Servlet 构造器方法
- 执行init初始化方法 (1、2就执行一次用于创建servlet程序,重复访问直接第三步)
- 执行service方法
- 执行destroy方法 (web工程停止时调用)
1.4 Servlet的请求分发处理
针对:get 、post 等不同请求做出不同的响应 一般我们实际开发通过继承 HttpServlet 类的方法区实现 Servlet程序,原始得到HttpServlet 是要我们自己分辨请求类型的
- get :
- post:
- 编写一个类继承与 HttpServlet 类
- 根据业务需要重写 doGet 或者 doPost 方法
-
1.5 ServletConfig 类介绍
ServletConfig 类从类名上来看,就知道是Servlet程序的配置信息类 Servlet 程序和 ServletConfig 对象都是有Tomcat负责创建的我们负责使用 Sevlet 程序默认是第一次访问时候创建,servletconfig 是每个 Servlet程序创建的时候,就创建一个对应的 ServletConfig 对象
ServletConfig 类的三大作用
写入 | 获取 | 移除 | |
---|---|---|---|
Map | put | get | remove |
域对象 | setAttribute | getAttribute | removeAttribute |
ServletContext类的作用
- 获取web.xml中配置的上下文参数 context-param (可以配置多组)
- 获取当前的工程路径,格式: /工程路径
- 获取工程部署后,在服务器磁盘上的绝对路径
- 像 Map 一样保存数据
- 域指的是整个web项目工程
2 Http 协议
什么是协议?
协议是双方或者多方,相互约定浩,大家都要遵守的规则
2.1 请求的HTTP协议格式
客户端给服务器发送的叫请求 服务器个客户端回传的叫响应 请求分为 GET 请求和 POST 请求两种
- GET 请求 ```markdown
- 请求行
- 请求方式 GET
- 请求的资源路径 + [? + 请求参数]
- 请求协议的版本号 Http/1.1
- 请求方式 GET
请求头 key: value 注册 不同键值对有不同的含义 ```
POST 请求 ```markdown
- 请求行
- 请求方式 POST
- 请求的资源路径 + [? + 请求参数]
- 请求协议的版本号 Http/1.1
- 请求方式 POST
- 请求头 key:value 不同的头有不同含义 空行
- 请求体 发送给服务器的数据 Post 请求
3. 常用的请求头的说明
```markdown
Accept: 表示客户端可以接受的数据类型
Accept-Language : 表示客户端可以接受的语言类型
Host :
Referer : 表示请求发起时,浏览器地址栏中的地址(从哪来)
User-Agent : 表示浏览器的信息
User-Agent : 表示浏览器的信息
Content-Type : 表示发送的数据的类型
application/x-www-form-urlencoded
表示提交的数据格式是: name=vale&name=value,然后对其进行 URL 编码,把非英文内容转换位 %xx%xx的形式
multipart/form-data
表示多段形式提交数据给服务器(以流的形式提交,用于上传)
Content-Length :发送的数据长度
Cache-Control :表示如何控制缓存,no-cache 不缓存
- 哪些是 GET 请求, 哪些是POST请求 ```markdown
- GET请求:
- form 标签 mthod = get
- a 标签
- link 标签引入 css
- Script 引入 js 文件
- img 标签引入图片
- iframe 引入html 页面
- 在地址栏食人鱼地址直接回车
- form 标签 mthod = get
- POST请求:
form 标签明确 mthod = post
**响应 HTPP协议的格式 **
markdown
- 响应行
- 响应的协议和版本号
- 响应状态码
- 响应状态描述符
- 响应的协议和版本号
- 响应头
- key:value 空行
- 响应体 ——> 回传个数据 ``` 常见的响应码
- 200 : 请求成功
- 302 : 请求重定向
- 404 : 收到服务但是,目标数据不存在
- 500 : 服务器已经收到请求,但是内部发生错误,比如代码层错误,一些编译发现不了的错误
MIME 类型说明
MIME 是 HTTP 协议中的数据类型
MIME 的英文全称是 “multipurpose internet Mail extensions” 多功能 internet 邮件扩充服务, MIME 类型的格式是 “大类型/小类型” , 并与某种文件扩展名对应
3. HttpServletRequest 类
- HttpServletRequest 类的作用:
每次只要有请求加入tomcat服务器,tomcat服务器就会把请求的学习解析并封装到 Request对象中,然后传递到 service 方法(doGet 和 doPost)中给我们使用,我们可以获取所有的请求信息
- HttpServletRequest 类的常用方法:
- getRequestURI() : 获取请求的URI地址,即资源路径
- getRequestURL() :获取请求的统一资源定位符,即绝对路径
- getRemoteHost() :获取 ip 地址
- getHeader() :获取请求头
- getParameter() : 获取请求的参数
- getParameterValues() : 获取请求的参数(多参数的情况下)
- getMethod() : 获取请求的方式 GET 或者 POST
- setAttribute(key , value) : 设置域数据
- getAttribute(key) : 获取域数据
- getRequestDispatcher() : 获取请求转发对象
get 没有请求体,不会乱乱码(主要有Tomcat服务器进行解析,只需要准正确设置服务器就可以正常读取),而post需要设置编码保证读取数据的准确
4 Servlet 的两个响应流介绍
字节流 getOutputStream(); 常用与下载(快速传递二进制数据)
字符流 getWrite(); 常用于字符串的传递
两个流同时只能使用一个,否则会处错
public void test(){
resp.getWriter();
resp.getOUtputStream(); // 同时调用出问题
}
5 如何往客户端会回传字符串数据
代码例子:
protectd void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException ,IOException{
resp.setCharacterEncoding("UTF-8"); // 设置服务器字符集为 UTF-8
//resp.setHeader("Content-Type" , "text/html;charset=UTF-8"); // 设置浏览器字符集
resp.setContentType("text/html;charset=UTF-8"); // 可以替代上上面两行代码效果,不过有局限。注意,此方法一定要获取流对象之前才有效
PrintWriter writer = resp.getWriter();
writer.write("----");
}
6 请求重定向
请求重定向,是指客户端给服务器发送请求,然后服务器告诉客户端,然后其访问新地址(因为之前的地址已经废弃)。却比于转发
表示,有一个废弃的servlet 提供信息跳转新的位置
servlet1
protectd void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException ,IOException{
System.out.println("Servlet 1 ");
resp.setStatus(302);
resp.setHdeader("Location","http://localhost:8088/Servlet_2");
}
servlet2
protectd void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException ,IOException{
System.out.println("Servlet 2 ");
}
特点:
1. 浏览器的地址会明确电话
- 两次请求
- 不共享 Request 域中的数据
- 不能访问 WEB-INF 目录下资源,但是可以访问其他平台资源
另一种实现重定向的方法:
resp.sendRedirect("目标地址");
7 WEB实现文件上传、下载
7.1 要点(上传)
- 要有要给 form 标签, method=post 请求
- Form标签的 enctype 属性,值必须位 multipart/form-data 值,表示一多段的形式进行拼接,然后以二进制流的方式发送给服务器
- 在form标签中是哟哦你input type = file 添加上传的文件
- 编写服务器代昂吗接收,处理上传数据,接收到数据后用第三方的接口解析目标数据
```java
// 上传
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}if(ServletFileUpload.isMultipartContent(request)){
// 创建 FileItemFactory 工厂实现类
FileItemFactory diskFileItemFactory = new DiskFileItemFactory();
// 创建用于解析上传数据的工具类 ServletFileUpload
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
try {
List<FileItem> fileItems = servletFileUpload.parseRequest(request);
// 循环判断每一个表单项是普通类型还是上传文件
for(FileItem fileItem : fileItems)
{
if(fileItem.isFormField())
{
// 普通表单项
System.out.println(fileItem.getFieldName());
// 获取编码参数
System.out.println(fileItem.getString("UTF-8"));
}else {
// 上传的文件
System.out.println(fileItem.getFieldName());
// 上传的文件名
System.out.println(fileItem.getName());
fileItem.write(new File("e:\\"));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
<a name="HVQfU"></a>
### 7.2 要点(下载)
1. 获取要下载的文件名
1. 读取要下载的文件内容
1. 把要下载的内容回传给客户端
1. 在回传前通过响应头,通知客户端其文件类型
1. 提示客户端收到的数据用于下载(通过响应头实现)
```java
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取文件名
String s = "2.jpg";
s = URLEncoder.encode(s,"UTF-8"); // 设置文件名编码
// 2. 读取要下载的文件内容(通过ServletContext对象读取)
ServletContext servletContext = getServletContext();
// 获取下载文件类型
String mimeType = servletContext.getMimeType("/file/" + s);
// 3. 在回传前,通过响应头告诉客户端返回的类型
response.setContentType(mimeType);
// 4. 提示客户端是作为下载文件使用
response.setHeader("Context-Disposition" , "attachment;filement="+s);
// 5. 把下载的文件内容传递给客户端 / 不然他会自动显示结果
// 输入流
InputStream resource = servletContext.getResourceAsStream("/file/"+s);
// 输出流
ServletOutputStream outputStream = response.getOutputStream();
int copy = IOUtils.copy(resource, outputStream);
}
文件名乱码问题解决方法: 我们需要对文件进行编码
s = URLEncoder.encode(s,"UTF-8"); // 设置文件名编码
7.3 使用Base64 编码操作
针对部分不支持 Unicode 编的浏览器,比如老板的火狐浏览器
// 1. 获取文件名
String s = "2.jpg";
// 创建一个Base64编码器
BASE64Encoder base64Encoder = new BASE64Encoder();
// 执行 Base64 编码操作
String encode = base64Encoder.encode(s.getBytes("UTF-8"));
// 解码操作
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] bytes = base64Decoder.decodeBuffer(encode); // 复原位字节数组
s = new String(bytes,"UTF-8");// 还原原本的字符串
针对火狐的格式进行定制
// 1. 获取文件名
String s = "2.jpg";
// 创建一个Base64编码器
BASE64Encoder base64Encoder = new BASE64Encoder();
// 执行 Base64 编码操作
String encode = base64Encoder.encode(s.getBytes("UTF-8"));
// 解码操作
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] bytes = base64Decoder.decodeBuffer(encode); // 复原位字节数组
s = new String(bytes,"UTF-8");// 还原原本的字符串
// s 进行 base64加密
response.setHeader("Context-Disposition" , "attachment;filement==?UTF-8?B"+s + "?=");
7.4 使用 User-Agent 请求头,动态切换不同的方式处理附件中文乱码问题
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
if(req.getHeader("User-Agent").contains("Firefox")){
// 包含火狐标记,我们进行 Base64 编码
//...//
}else{
// 其他浏览器,另外编码
}
8 Cookie 和 Session
8.1 Cookie
8.1.1 定义
- cookie是服务器同时客户端保存键值对的一种技术,信息有浏览器保存,再返回服务器
- 客户端有了Cookie后,每次请求都发送给服务器
- 每个Cookie的大小都不可以超过 4kb
8.1.2 如何创建 cookie
可以一次创建多个
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
// 解决中文乱码问题
response.setContentType("text/html;charset=UTF-8");
// 1. 创建Cookie对象
Cookie cookie = new Cookie("key1", "value1"); // 现在还在服务器内存中而已
// 2. 通知客户端保存
response.addCookie(cookie);
response.setHeader("set-cookie","");
response.getWriter().write("Cookie 创建成功");
System.out.println("isok");
}
8.1.3 获取 Cookie
服务器获取客户端的Cookie只需要: Cookie[] cookies = request.getCookies();
8.1.4 修改 Cookie 的值
不支持中文和特殊值,如果要用必须要Base64编码
方案一:
直接同名覆盖,与map覆盖效果类似
方案二:
- 先调查找到需要修改的Cookie对象
- 调用 setValue() 方法赋予新的Cookie值
- 调用 response.addCookie() 通知客户端保存
8.1.5 Cookie的存活设置
Cookie 的生命控制指的是如何管理 Cookie 什么时候被销毁(删除)
setMaxAge()
正数:表示在指定的秒数后会过期
负数:表示浏览器一关,Cookie就会被删除(默认)
0 :马上删除 Cookie8.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 满足发送条件
---
> 可以通过 setPath() 修改(位于 Cookie 类中)
<a name="tSZx4"></a>
#### 8.1.7 Cookie 实现免用户名登陆
表单处理流程:
1. 获取用户的账号和密码
1. 判断其有效性
1. 有效即登陆
1. 同时将用户名保存位Cookie发送给服务器
- 当我们第二次登陆的时候,会把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)
<a name="wt87G"></a>
### 8.2 Session 会话
<a name="aIC9c"></a>
#### 8.2.1 什么是Session
1. Session :一类接口(HttpSession)
1. Session 就是会话。它是用来维护一个客户的服务器之间管理的一种技术
1. 每个客户端都有自己的一个Session 会话
1. Session 会话中,我们经常用来保存用户登陆的信息
> 区别:Cookie 在客户端,Session 在服务器上
<a name="codGI"></a>
#### 8.2.2 如何创建Session 和获取 (id 号,是否位新)
创建和获取Session的API是一样的
```java
request.getSession()
- 第一次调用是:创建Session 会话
- 之后调用都是:获取前面创建浩的 Session 会话对象,可以通过 isNew() 判断是否位新建的Session
isNew()
- true : 新
- false : 旧
每个会话都有一个身份id,也就ID值,而且这个值是唯一的
getId():
- 获取到 Session 的会话 ID 值
8.2.3 向 Session 域中存取数据
request.getSession().setAttribute("key1","value1");
request.getSession().getAttribute("key1");
8.2.4 Session 生命周期
setMaxInactiveInterval(int interval) : 设置 Session 的超时时间,超过指定时长,Session就会被销毁,负数表示永不超时(很少使用),0不对应立即无效化接口
getMaxInactiveInterval() : 获取Session 超时时长
- 默认的生命时长是:1800 秒,在tomcat中可以设置
invalidate()
- 使session立即超时无效
在web.xml添加设置 (作用与全局,个别修改使用上面的api为好 )
<session-config>
<session-timeout>20</session-timeout>
</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方法,简化重定向和转发的操作。