JavaWeb(六)
2.11 JSP 过滤器
JSP 和 Servlet 中的过滤器都是 Java 类。
过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。
可以将一个或多个过滤器附加到一个 Servlet 或一组 Servlet。过滤器也可以附加到 JavaServer Pages (JSP) 文件和 HTML 页面。
过滤器是可用于 Servlet 编程的 Java 类,可以实现以下目的:
- 在客户端的请求访问后端资源之前,拦截这些请求。
- 在服务器的响应发送回客户端之前,处理这些响应。
过滤器通过 Web 部署描述符(web.xml)中的 XML 标签来声明,然后映射到您的应用程序的部署描述符中的 Servlet 名称或 URL 模式。
当 Web 容器启动 Web 应用程序时,它会为您在部署描述符中声明的每一个过滤器创建一个实例。
Filter 的执行顺序与在 web.xml 配置文件中的配置顺序一致,一般把 Filter 配置在所有的 Servlet 之前。

过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类。javax.servlet.Filter 接口定义了三个方法:
| 序号 | 方法 & 描述 |
|---|---|
| 1 | public void doFilter (ServletRequest, ServletResponse, FilterChain) 该方法完成实际的过滤操作,当客户端的请求与过滤器设置的 URL 匹配时,Servlet 容器将先调用过滤器的 doFilter 方法。FilterChain 用于访问后续过滤器。 |
| 2 | public void init(FilterConfig filterConfig) web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。 |
| 3 | public void destroy() Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。 |
FilterConfig 使用
Filter 的 init 方法中提供了一个 FilterConfig 对象。
如 web.xml 文件配置如下:
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.wyz.test.LogFilter</filter-class>
<init-param>
<param-name>Site</param-name>
<param-value>无涯子博客</param-value>
</init-param>
</filter>
在 init 方法使用 FilterConfig 对象获取参数:
public void init(FilterConfig config) throws ServletException {
// 获取初始化参数
String site = config.getInitParameter("Site");
// 输出初始化参数
System.out.println("网站名称: " + site);
}
JSP 过滤器实例
我们在请求和响应中可能会出现中文乱码情况,我们可以使用过滤器统一处理。
public class CharacterFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterFilter过滤器被初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
System.out.println("CharacterFilter过滤器之前");
chain.doFilter(request,response);
System.out.println("CharacterFilter过滤器之后");
}
@Override
public void destroy() {
System.out.println("CharacterFilter过滤器被销毁");
}
}
配置过滤器:
<filter>
<filter-name>CharacterFilter</filter-name>
<filter-class>com.wyz.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterFilter</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
web.xml 中的 filter-mapping 元素的顺序决定了 Web 容器应用过滤器到 Servlet 的顺序。若要反转过滤器的顺序,您只需要在 web.xml 文件中反转 filter-mapping 元素即可。
过滤器简单应用
- 乱码处理
- 过滤拦截请求
我们很多网站都需要用户登录之后才能访问某些页面,没有登录则不能访问,会自动跳转到登录页面,这个功能就可以使用过滤器来实现。这里我们简单模拟一下:
<%-- 登录 --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/sys/login" method="post">
<label for="username">用户名</label>
<input type="text" name="username" id="username"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
<%-- 主页 --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录成功</h1>
<a href="${pageContext.request.contextPath}/sys/logout">注销</a>
</body>
</html>
<%-- 错误页面 --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录失败,您的用户名错误</h1>
<a href="${pageContext.request.contextPath}/sys/login.jsp">返回登录页面</a>
</body>
</html>
//处理登录请求的Servlet
public class SysLogin extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String username = req.getParameter("username");
if("admin".equals(username)){//登录成功
session.setAttribute("USER_NAME",req.getSession().getId());
resp.sendRedirect("/web01/sys/main.jsp");
}else{
//登录失败
resp.sendRedirect("/web01/sys/error.jsp");
}
}
}
//退出登录
public class LogOut extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
if(session.getAttribute("USER_NAME") != null){
session.removeAttribute("USER_NAME");//移出Session数据
}
//跳转到登录页面
System.out.println("退出");
resp.sendRedirect("/web01/sys/login.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
//过滤器
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request1 = (HttpServletRequest) request;
HttpServletResponse response1 = (HttpServletResponse) response;
HttpSession session = request1.getSession();
if(session.getAttribute("USER_NAME") == null){
response1.sendRedirect("/web01/sys/login.jsp");
}
chain.doFilter(request1,response1);
}
@Override
public void destroy() {
}
}
在web.xml中配置:
<servlet>
<servlet-name>SysLogin</servlet-name>
<servlet-class>com.wyz.SysLogin</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SysLogin</servlet-name>
<url-pattern>/sys/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>LogOut</servlet-name>
<servlet-class>com.wyz.LogOut</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogOut</servlet-name>
<url-pattern>/sys/logout</url-pattern>
</servlet-mapping>
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.wyz.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/sys/main.jsp</url-pattern>
</filter-mapping>
3. 文件上传
依赖引入:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
前端编写:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
<title>文件上传测试</title>
</head>
<body>
<h1>文件上传测试</h1>
<form action="${pageContext.request.contextPath}/uploadServlet" method="post" enctype="multipart/form-data">
<label for="uploadFile">选择一个文件</label>
<input type="file" name="uploadFile" id="uploadFile"><br/>
<input type="submit" value="上传">
</form>
</body>
</html>
- 表单 method 属性应该设置为 POST 方法,不能使用 GET 方法。
- 表单 enctype 属性应该设置为 multipart/form-data
后端编写:
public class Upload extends HttpServlet {
private static final long serialVersionUID = 1L;
//上传文件保存目录
private static final String UPLOAD_DIRECTORY = "upload";
//上传配置
private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3; // 3MB
private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB
private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
//检查是否为多媒体上传
if(!ServletFileUpload.isMultipartContent(req)){
//不是则停止
PrintWriter out = resp.getWriter();
out.write("Error:表单必须包含enctype=multipart/form-data");
out.flush();
return;
}
// 配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中
factory.setSizeThreshold(MEMORY_THRESHOLD);
// 设置临时存储目录
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大文件上传值
upload.setFileSizeMax(MAX_FILE_SIZE);
// 设置最大请求值 (包含文件和表单数据)
upload.setSizeMax(MAX_REQUEST_SIZE);
// 中文处理
upload.setHeaderEncoding("UTF-8");
// 构造临时路径来存储上传的文件
// 这个路径相对当前应用的目录
String uploadPath = getServletContext().getRealPath("/") + File.separator + UPLOAD_DIRECTORY;
// 如果目录不存在则创建
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdir();
}
try{
// 解析请求的内容提取文件数据
List<FileItem> formItems = upload.parseRequest(req);
if (formItems != null && formItems.size() > 0) {
// 迭代表单数据
for (FileItem item : formItems) {
// 处理不在表单中的字段
if (!item.isFormField()) {
String fileName = new File(item.getName()).getName();
String filePath = uploadPath + File.separator + fileName;
File storeFile = new File(filePath);
// 在控制台输出文件的上传路径
System.out.println(filePath);
// 保存文件到硬盘
item.write(storeFile);
req.setAttribute("message",
"文件上传成功!");
}
}
}
}catch(Exception e){
req.setAttribute("message",e.getMessage());
}
//请求转发跳转
req.getRequestDispatcher("/message.jsp").forward(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
上传之后跳转页面,显示上传结果:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
<title>文件上传结果</title>
<meta charset="UTF-8">
</head>
<body>
<h2>${message}</h2>
</body>
</html>




浙公网安备 33010602011771号