Tomcat目录
1.Tomcat目录学习1.Tomcat目录学习1.Tomcat目录学习
5.设置注解:
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
知识点 学习
2.写的格式
![](https://i-blog.csdnimg.cn/blog_migrate/43742536e58dcff01e4cda092d5b9c0a.png)
3.请求头
4.什么是Tomcat:
5.设置注解:
设置注解 在完成好了一切代码的编写后,还需要向服务器说明,特定请求对应特定资源。 开发servlet项目,使用@WebServlet将一个继承于javax.servlet.http.HttpServlet 的类定义为Servlet组件。在 Servlet3.0中 .
可以使用@WebServlet注解将一个继承于javax.servlet.http.HttpServlet的类标注为可以处理用户请 求的 Servlet。
package com.xxxx.servlet;
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;
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException {
System.out.println("Hello Servlet!");
resp.getWriter().write("Hello World");
}
}
6.Servlert 的访问流程:
Servlet的工作流程:
1. 通过请求头获知浏览器访问的是哪个主机
2. 再通过请求行获取访问的是哪个一个web应用
3. 再通过请求行中的请求路径获知访问的是哪个资源
4. 通过获取的资源路径在配置中匹配到真实的路径,
5. 服务器会创建servlet对象,(如果是第一次访问时,创建servlet实例,并调用init方法进行初 始化操作)
6. 调用service(request, response)方法来处理请求和响应的操作
7. 调用service完毕后返回服务器 由服务器讲response缓冲区的数据取出,以http响应的格式发 送给浏览器
首先浏览器向Web 服务器发送一个HTTP请求,Web 服务器根据收到的请求,会创建一个HttpServltRequest 和 HttpServletResponse 对象,然后在调用相应的servlert 程序。
在Svleret 程序运行的,他会首先从 HttpServlertRequest 对象中读取数据,然后通过service()的方法处理请求的信息,并将处理后的响应数据写入到HttpServlertResponse 对象中 ,最后Web 服务对从ServlertResponse 对象中读取到响应的数据,并发给浏览器。
需要注意的是,在web浏览器服务运行的阶段,每一个Servlet 都会创建一个实例的对象,针对每次的Http请求,Web服务器都会调用请求的Servlert 实例的service (HttpServlertRequest request,HttpServlertRequest response) 方法,并创建一个response 对象。
7.HttpServletRequest对象和 HttpServletResponse对象
HttpServletResponse对象
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的 request 对象和代表响应的response 对象。
request和response对象代表请求和响应︰获取客户端数据,需要通过request对象;向客户端输出 数据,需要通过response对象。
HttpServletResponse 的主要功能用于服务器对客户端的请求进行响应,将Web服务器处理后的 结果返回给客户端。service()方法中形参接收的是HttpServletResponse接口的实例化对象,这个 对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。
响应数据 接收到客户端请求后,可以通过 HttpServletResponse 对象直接进行响应,响应时需要获取输出流。 有两种形式: getWriter() 获取字符流(只能响应回字符) getOutputStream() 获取字节流(能响应一切数据) 响应回的数据到客户端被浏览器解析。
有两种形式
getWriter() 获取字符流
getOutputStream() 获取字节流 (能响应一切数据)
响应回的数据到客服端 被浏览器解析
注意:两者不能同时用
//字符输入流
PrintWriter writer = response.getWriter();
writer.writer("hello");
writer.writer("<h2> hell </h2>");
//字节流输出流
ServlertOutputStream out = response.getOutputStream();
out.writer("hello".getBytes());
out.writer("<h2>hello <h2>".getBytes());
//设置响应类型,默认是字符串
response.setHeader("content-type","text/html");
8.HttpServletRequest对象-常用方法和获取请求数据:
9.请求乱码问题:
// 设置服务端的编码
response.setCharacterEncoding("UTF-8");
// 设置客户端的响应类型及编码
response.setHeader("content-type","text/html;charset=UTF-8");
// 得到字符输出流
PrintWriter writer = response.getWriter();
writer.write("<h2>你好</h2>");
10.请求转发与重定向:
请求转发:
请求转发,是一种服务器的行为,当客户端请求到达后,服务器进行转发,此时会将请求对· 象进行保存,地址栏中的URL地址不会改变,得到响应后,服务器端再将响应发送给客户 端,从始至终只有一个请求发出。
实现方式如下,达到多个资源协同响应的效果。
request.getRequestDispatcher(ur1).forward(request,response);
1. 地址上显示的是请求servlet的地址。 返回200 ok
2. 请求次数只有一次, 因为是服务器内部帮客户端执行了后续的工作。
3. 只能跳转自己项目的资源路径 。
4. 效率上稍微高一点,因为只执行一次请求。
5. 可以使用上一次的request对象。
重定向:
举个例子来说,重定向就是一个客户向客服打电话咨询某某技术问题应该怎么处理,但客服也不 会,于是告诉了客户一个号码,说,你打这个电话,我们技术部的人会专门给你解答,然后客户 打了技术部电话,这就是重定向。
response.sendRedirect("login_success.html");
1. 地址上显示的是最后的那个资源的路径地址
2. 请求次数最少有两次, 服务器在第一次请求后,会返回302 以及一个地址, 浏览器在根据这个地址,执行第二次访问。
3. 可以跳转到任意路径。 不是自己的工程也可以跳。
4. 效率稍微低一点, 执行两次请求。
5. 后续的请求,没法使用上一次的request存储的数据,或者 没法使用上一次的request对象,因为这是两次不同的请求。
请求转发和重定向的区别:
11.request作用域:
通过该对象可以在一个请求中传递数据,作用范围:在一次请求中有效,及服务器跳转有效
//设置域对象的内容
request.setAttribute(String name,String value);
//获取对象的内容
request.getAttribute(String name);
//删除域对象的内容
request.removeAttribute(String name)
//request 域对象中的数据在一次请求中有效,则经过请求转发,request域中的数据依然存在,
则在请求转发的过程中通过request 来传输、共享数据
12.Cookie对象
@WebServlet("/") 这样配置时,不过滤(放行)jsp文件。只有jsp不进控制器(servlet),其他都 进
@WebServlet("/*") 过滤所有文件。
(1.)Cookie 的创建和发送
通过new Cookie(“key”,"value";来创建一个cookie 对象,要想要将Cookie 谁着响应发送到客户端,需要先添加到response 对象中,response.addCookie(cookie); 该时cookie 对象谁着响应发送到客服端,在浏览器上可以看见
//创建Cookie 对象
Cookie cookie = new Cookie("uname","zhangsan");
//发送Cookie 对象
response.addCookie(cookie);
Cookie的获取
在服务器端只能提供一个getCookies() 的方法用来获取客户端回传的所有cookie 组成的一个数组,如果需要获取单个cookie 则需要通过遍历 ,getName() 来获取 Cookie 的名称 ,getValue() 获取Cookie的值。
//获取Cookie 的数组
Cookie[] cookies = request.getCookies();
//判断数组是不是为空
if(Cookie != null && cookies){
//循环遍历Cookie 数组
for(Cookie cookie : cookies){
System.out.println(cookie.getName());
System.out.println(cookie.getName());
}
}
Cookie 到期的时间
除了Cookie 的名称和内容外,我们还需要关系一个信息,到期的时间,到期时间用来指定cookie什么时候失效,默认为了当前浏览器关闭就失效,我们可以手动设置cookie的有效时间(通过到期的时间计算),通过setMaxAge(inttime);方法设定cookie 的最大有效时间,以秒为单位。
到期时间
* 负整数
如果为负数,表示不存放改cookie 。cookie的maxAge 的属性默认值计算-1,表示只能在浏览器中存活,一旦关闭浏览器,就算重新启动客户端电脑,cookie也会存活相应的时间
*零
如果为0,表示删除改cookie
cookie 生命等于0 是一个特殊的值,他表示cookie 被作废,也就是说如果原来浏览器已经保存了这个Cookie,那么可以通过Cookie的setMaxAge(0)来删除这个cookie。无论是在浏览器内存中,还是在客户端硬盘上都会删除这个Cookie。
Cookie的注意点:
1.cookie保存在当前浏览器中,
有一般的站点中常常有记住,用户名这样的操作,该操作只是保存在本机上面,然后换上电脑这些信息就没有用了,而且cookie还不能跨浏览器。
2.Cookie存在中文问题
Cookie中不能出现中文的问题
Cookie 中不能出现中文,如果有中文则通过URLEcoder.encode() 来进行编码,获取则通过URLDecoder.decode()来进行编码
String name = "姓名";
String value = "张山";
//通过URLEncoder.encode(name);
value = URLEncoder.encode(name):
value = URLEncoder.encode(value);
//创建cookie 对象
Cookie cookie = new Cookie(name,value);
//发送cookie对象
response.addCookie(cookie);
//获取的时候通过URLDecoder.decode()来进行编码
URLDecoder.decode(cookie.getName());
URLDecoder.decode(cookie.getValue());
3. 同名Cookie问题 如果服务器端发送重复的Cookie那么会覆盖原有的Cookie。
4. 浏览器存放Cookie的数量 不同的浏览器对Cookie也有限定,Cookie的存储有是上限的。Cookie是存储在客户端(浏览器)的,而且一般 是由服务器端创建和设定。后期结合Session来实现回话跟踪。
Cookie的路径:
情景二: 当前项目下的资源可获取Cookie对象 (默认不设置cookie的path)
/* 当前路径为 s01*/
Cookie cookie = new Cookie("xxx","xxx");
//设置路径为:s01表示当前目录下的任何项目都可以访问到Cookie 对象
cookie。setPath("/s01"); //默认情况,可以不设置path的值
response.addCookie()cookie;
情景三: 指定项目下的资源可以获取Cookie 对象
/* 当前项目的资源可以获取Cookie 对象*/
Cookie cookie = new Cookie( "xxx","xxx");
cookie.setPath("/s02"); //只能在s02的项目下才可以访问到Cookie 对象
response.addCokie(cookie);
情景四: 指定目录下的资源可以获取Cookie 对象
/* 当前项目 的路径为 s01 */
Cookie cookie = new Cookie("xxx","xxx");
//设置路径为"/s01/cook" 表示s02/cook 目录下才可以访问到 Cookie 对象
cookie.setPath("/s01/cook");
response.addCookie(cookie);
cookie的路径指的是可以访问该cookie的顶层目录,该路径的子路径也可以访问该cookie。
总结:当访问的路径包含了cookie的路径时,则该请求将带上该cookie;如果访问路径不包含cookie路径,则该请 求不会携带该cookie。
13.HttpSession对象
HttpSession对象是javax.servlet.http.HttpSession的实例,该接口并不像 HttpServletRequest或
HttpServletResponse还存在一个父接口,该接口只是一个纯粹的接口。这因为session本身就属于HTTP协议的范畴。
对于服务器而言,每一个连接到它的客户端都是一个session,servlet容器使用此接口创建HTTP客户端和HTTP服务器之间的会话。会话将保留指定的时间段,跨多个连接或来自用户的页面请求。一个会话通常对应于一个用户,该用户可能多次访问一个站点。可以通过此接口查看和操作有关某个会话的信息,比如会话标识符、创建时间和最后一次访问时间。在整个session中,最重要的就是属性的操作。
Session 的作用:
为了标识一次会话,或者说确认一个用户;并且在一次会话(一个用户的多次请求)期间共享数 据。我们可以通过 request.getSession()方法,来获取当前会话的 session 对象。
// 如果session对象存在,则获取;如果session对象不存在,则创建
HttpSession session = request.getSession();
标识符JSESSIONID
Session既然是为了标识一次会话,那么此次会话就应该有一个唯一的标志,这个标志就是sessionld。
每当一次请求到达服务器,如果开启了会话((访问了session),服务器第一步会查看是否从客户端回传一个名为JSESSIONID的cookie,如果没有则认为这是一次新的会话,会创建一个新的session对象,并用唯一的sessionld为此次会话做一个标志。如果有JESSIONID这个cookie回传,服务器则会根据]SESSIONID这个值去查看是否含有id为JSESSION值的session对象,如果没有则认为是一个新的会话,重新创建一个新的session对象,并标志此次会话;如果找到了相应的session对象,则认为是之前标志过的一次会话,返回该session对象,数据达到共享。
这里提到一个叫做JSESSIONID的cookie,这是一个比较特殊的cookie,当用户请求服务器时,如果访问了session,则服务器会创建一个名为JSESSIONID,值为获取到的session(无论是获取到的还是新创建的)的sessionld的cookie对象,并添加到response对象中,响应给客户端,有效时间为关闭浏览器。
所以Session的底层依赖Cookie来实现。
session 域对象
Session 用来表示一次会话,在一次会话中数据是可以共享的,这时的session 作为域对象的存在,可以通过setAttribute(name,value)方向向域对象添加数据,通过getAttribute(name)从域对象中获取数据,通过removeAttribute(name)从域对象中移除数据。
// 获取session对象
HttpSession session = request.getSession();
// 设置session域对象
session.setAttribute("uname","admin");
// 获取指定名称的session域对象
String uname = (String) request.getAttribute("uname");
// 移除指定名称的session域对象
session.removeAttribute("uname");
数据存在session域对象中,当session 对象不存在了,或者是2个不同的session 对象 时,数据就不能共享了,这就不得不谈到session 的生命周期了。
session域对象 Session 用来表示一次会话,
在一次会话中数据是可以共享的,这时 session 作为域对象存在,可以通过 setAttribute(name,value) 方法向域对象中添加数据,通过 getAttribute(name) 从域对象中获取数据,通过 removeAttribute(name) 从域对象中移除数据。
session对象的销毁 :
默认时间到期 当客户端第一次请求 servlet 并且操作 session 时,session 对象生成,Tomcat 中 session 默认的存活时间为 30min,即你不操作界面的时间,一旦有操作,session 会重新计时。 那么 session 的默认时间可以改么?答案是肯定的。 可以在 Tomcat 中的 conf 目录下的 web.xml 文件中进行修改。
<wep-app>
<!-- session 默认的最大不活动时间。单位:分钟。 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
自己设定到期时间:
当然除了以上的修改方式外,我们也可以在程序中自己设定 session 的生命周期,通过 session.setMaxInactiveInterval(int) 来设定 session 的最大不活动时间,单位为秒。
// 获取session对象 HttpSession session = request.getSession();
// 设置session的最大不活动时间 session.setMaxInactiveInterval(15); // 15秒
当然我们也可以通过 getMaxInactiveInterval() 方法来查看当前 Session 对象的最大不活动时间
// 获取session的最大不活动时间 int time = session.getMaxInactiveInterval();
ServletContext对象:
每一个 web 应用都有且仅有一个ServletContext 对象,又称 Application 对象,从名称中可知,该对象是与应用程 序相关的。在 WEB 容器启动的时候,会为每一个 WEB 应用程序创建一个对应的 ServletContext 对象。 该对象有两大作用,第一、作为域对象用来共享数据,此时数据在整个应用程序中共享; 第二、该对象中保存了当 前应用程序相关信息。例如可以通过 getServerInfo() 方法获取当前服务器信息 ,getRealPath(String path) 获取资 源的真实路径等。
ServletContext对象的获取:
获取 ServletContext 对象的途径有很多。比如:
1. 通过 request 对象获取
ServletContext servletContext = request.getServletContext();
//2. 通过 session 对象获取
ServletContext servletContext = request.getSession().getServletContext();
//3. 通过 servletConfig 对象获取,在 Servlet 标准中提供了 ServletConfig 方法
ServletConfig servletConfig = getServletConfig();
ServletContext servletContext = servletConfig.getServletContext();
//4. 直接获取,Servlet 类中提供了直接获取 ServletContext 对象的方法常用方法
ServletContext servletContext = getServletContext();
常用方法:
//获取当前服务器的真实路径 如:F:\FirstServlet\out\artifacts\FirstServlet_war_exploded\
String realPath = request.getServletContext().getRealPath("/");
System.out.println(realPath);
// 获取当前服务器的版本信息 如:Apache Tomcat/8.5.66
String serverInfo = request.getServletContext().getServerInfo();
System.out.println(serverInfo);
14.文件的上传:
//前端的代码
<!--
文件上传表单
1.表单提交类型 method = "post"
2.表单类型 enctype = "multipart/form-data"
3.表单的元素类型 文件域设置 name 的属性值
-->
<!--设置表单为 上传文件 -->
<!--默认情况下这个表单类型是 " application/x-www-form-date " 不能上传文件 只有
multipart/form-data才可以
-->
<form method="post" action="uploadServlet" enctype="multipart/from-date">
姓名:<input type="text" name="uname"> <br>
文件:<input type="text" name="myfile"> <br>
<button type="submit"> 提交 </button>
</form>
//后端的代码
package com.openhome;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
/*
文件上传
使用注解@MultipartConfig将一个ServLet 标识为支持文件上传。
ServLet 将 muLtipart/form-data 的 POST 请求封装成Part对象,通过 Part对上传的文件进行操作。
* */
@WebServlet("/uploadServlert")
@MultipartConfig //如果是文件上传,就一定要加这个注解
public class UploadServlert extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("上传文件");
// 1.设置请求编码的格式
request.setCharacterEncoding("UTF-8");
// 2. 获取普通表单像
String uname = request.getParameter("uname"); // "uname" 代表的是文本框的name 属性值
// 3.通过getPart 方法获取Part 对象 (name 代表的是页面的file 文件域的name 属性值)
Part part = request.getPart("myfile"); // 参数的 name =“myfile”
// 通过表单file控件(<input type="file" name="file">)的名字直接获取Par
// 4.通过part 获取上传文件的文件名
String fileName = part.getSubmittedFileName();
System.out.println("文件存放路径的名称 "+fileName);
// 5。获取上传文件需要存放的路径(得到项目的正时路径)
String realpath = request.getServletContext().getRealPath("/");
System.out.println(" 上传文件需要存放的路径 "+realpath);
// 将文件上传到指定的位置
part.write(realpath +"/"+ fileName);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
控制台显示:
上传文件
文件存放路径 学生管理系统.txt
上传文件需要存放的路径 F:\练习\FirstServlet\out\artifacts\FirstServlet_war_explode然后文件是会被放到 F:\练习\FirstServlet\out\artifacts\FirstServlet_war_explode 这个文件夹里面去
15.文件的下载:
文件下载
文件下载,即将服务器上的资源下载(拷贝)到本地,我们可以通过两种方式下载。第一种是通过超链接本身的特性
来下载;第二种是通过代码下载。
超链接下载
当我们在 HTML 或 JSP 页面中使用a标签时,原意是希望能够进行跳转,但当超链接遇到浏览器不识别的资源时会自
动下载;当遇见浏览器能够直接显示的资源,浏览器就会默认显示出来,比如 txt、png、jpg 等。当然我们也可以通
过 download 属性规定浏览器进行下载。但有些浏览器并不支持。
默认下载
指定的download属性下载
<!-- 当超链接遇到浏览器识别的资源时,默认不会下载,通过download 属性进行下载 -->
<a href="test.txt" download> 超链接下载 </a>
download 属性可以不写任何的信息,会自动使用默认的文件名,如果设置了 download 属性的值,则用设置的值为文件名。当用户打开浏览器点击链接的时候会直接下载文件。
后端代码:
实现步骤
1. 需要通过 response.setContentType 方法设置 Content-type 头字段的值, 为浏览器无法使用某种方式或激活
某个程序来处理的 MIME 类型,例 如 "application/octet-stream" 或 "application/x-msdownload" 等。
2. 需要通过 response.setHeader 方法设置 Content-Disposition 头的值 为 "attachment;filename=文件名"
3. 读取下载文件,调用 response.getOutputStream 方法向客户端写入附件内容。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件传输</title>
</head>
<body>
<form action="download">
文件<input type="text" name="fileName" placeholder="请输入你要的文件">
<button> 提交 </button>
</form>
</body>
</html>
//后端代码
package com.openhome;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@WebServlet("/download")
public class DownloadSerclet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("文件下载...");
// 设置请求的编码格式
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 获取参数 (得到要下载的文件名)
String fileName = request.getParameter("fileName");
// 参数的非空判断 trim():去除字符串的前后空格
if (fileName == null || "".equals(fileName.trim())) {
response.getWriter().write("请输入要下载的文件名!");
response.getWriter().close();
return;
}
// 得到图片存放的路径
String path = request.getServletContext().getRealPath("/download/");
// 通过路径得到file对象
System.out.println("通过路径得到file对象" + path);
File file = new File(path + fileName);
// 判断文件对象是否存在并且是一个标准文件
if (file.exists() && file.isFile()) {
// 设置响应类型 (浏览器无法使用某种方式或激活某个程序来处理的 MIME 类型)
response.setContentType("application/x-msdownload");
// 设置响应头
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
// 得到file文件输入流
InputStream in = new FileInputStream(file);
// 得到字节输出流
ServletOutputStream out = response.getOutputStream();
// 定义byte数组
byte[] bytes = new byte[1024];
// 定义长度
int len = 0;
// 循环输出
while ((len = in.read(bytes)) != -1){
// 输出
out.write(bytes,0,len);
}
// 关闭资源
out.close();
in.close();
} else {
response.getWriter().write("文件不存在,请重试!");
response.getWriter().close();
}
}
}
16.Filter 过滤器
16.1 现有问题
在以往的Servlet中,有没有冗余的代码,多个servlet都要进行编写。
16.2 概念
过滤器(Filter)是处于客户端与服务器目标资源之间的一道过滤技术。
16.3过滤器作用
执行地位在Servlet之前,客户端发送请求时,会先经过Filter,再到达目标Servlet中;响应时,会根据执行流程再次反向执行Filter,可以解决多个Servlet共性代码的冗余问题(例如:乱码处理、登录验证)
16.4编写过滤器
Servlet API中提供了一个Filter接口,开发人员编写一个Java类实现了这个接口即可,这个Java类称之为过滤器(Filter)
16.5实现过程
编写Java类实现Filter接口。 在doFilter方法中编写拦截逻辑。 设置拦截路径
16.7过滤器配置
16.8注解配置
在自定义的Filter类上使用注解@WebFilter(value=“/过滤目标资源”)
xml设置
package com.avaliable;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.util.logging.LogRecord;
//需要拦截的资源
@WebFilter(value="/t")
public class Myfilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("myfilter");
filterChain.doFilter(servletRequest,servletResponse); //返回 刚刚设置 T的目录
System.out.println("------ end -----"); //成功打印end
}
@Override
public void destroy() {
System.out.println("正在销毁。。。。");
}
}
package com.avaliable;
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;
@WebServlet(name ="TargetServlet", value="/t")
public class TargetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("-------/t targetServlet ");
}
}
16.9过滤器链和优先级
16.9.1过滤器链
客户端对服务器请求之后,服务器调用Sservlet之前会执行一组过滤器(多个过滤器),那么这组过滤器就称为一条过滤器链。
每个过滤器实现某个特定的功能,当第一个Filter的doFilter方法被调用时,Web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用 FilterChain对象的doFilter方法,则Web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。
19.10.1过滤器优先级
在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。优先级:
1.如果为注解的话,是按照类全名称的字符串顺序决定作用顺序。 (字母顺序) 2. 如果web.xml,按照filter-mapping注册顺序,从上往下
3. web.xml配置高于注解方式。如果注解和web.xml同时配置,会创建多个过滤器对象,造成 过滤多次。
精确拦截 html 的请求
package com.avaliable;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(value="*.html") // 拦截所有后缀为 HTML 的语句 (不显示)
public class HtmlFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截HTML的请求");
}
@Override
public void destroy() {
System.out.println("销毁---");
}
}
拦截所有请求
package com.avaliable;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/*
也可以拦截 a/b/*
a目录下的b目录下的所有资源
*/
@WebFilter("/*") ///* 拦截所有请求
public class AllFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("/* 拦截所有请求 ");
}
@Override
public void destroy() {
System.out.println("销毁----------");
}
}
实战:过滤器解决编码问题:
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> 过滤器的经典应用(解决乱码) </title>
</head>
<body>
<form action="login" method ="post">
用户名 :<input type="text" name = "username" >
密 码 :<input type="text" name = "password">
<input type="submit" value="登入">
</form>
</body>
</html>
//后端1(过滤器 拦截所有)
package com.avaliable;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/*
也可以拦截 a/b/*
a目录下的b目录下的所有资源
*/
@WebFilter("/*") ///* 拦截所有请求
public class AllFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletResponse.setContentType("text/html;charset=utf-8");
servletRequest.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse); // 转换
System.out.println("/* 拦截所有请求 ");
}
@Override
public void destroy() {
System.out.println("销毁----------");
}
}
//后端2(servlet 的后端编码)
package com.avaliable;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "LoginServlet", value = "/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("username");
String pass = request.getParameter("password");
System.out.println(" 姓名 " + name + " " +pass);
PrintWriter out = response.getWriter();
out.write(" 性名 " + name+ " 密码 "+ pass );
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}