本文主要是介绍JAVAWEB开发之Servlet Filter(过滤器)详解包括post和get编码过滤器、URL访问权限控制、自动登录。以及装饰模式的使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Filter简介
- Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如JSP,Servlet,静态图片文件或静态HTML文件进行拦截,从而实现一些特殊功能。例如实现URL级别的权限控制、过滤敏感词汇、压缩响应信息等一些高级功能。
- ServletAPI中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个Java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前对访问的请求和响应进行拦截,如下所示:
Filter开发入门
Filter生命周期
- 和我们编写的Servlet程序一样,Filter的创建与销毁由WEB服务器负责。web应用程序启动时,web服务器将创建Filter的实例对象,并调用init方法进行初始化(注意:filter对象只会创建一次,init方法也只会执行一次)
- 开发人员通过init方法的参数,可以获得代表当前filter配置信息的FilterConfig对象。
- 每次filter进行拦截都会执行
- 在实际开发中方法中参数request和response通常转换为HttpServletRequest和HttpServletResponse类型进行操作。
FilterConfig接口
- String getFilterName():得到filter的名称。
- String getInitParameter(String name):返回在部署描述中指定名称的初始化参数的值。如果不存在则返回null。
- Enumeration getInitParameterNames():返回过滤器中的所有初始化参数的名字的枚举集合。
- public ServletContext getServletContext():返回Servlet上下文对象的引用。
注册与映射Filter
<filter-name>testFitler</filter-name>
<filter-class>org.test.TestFiter</filter-class>
<init-param>
<param-name>word_file</param-name>
<param-value>/WEB-INF/word.txt</param-value>
</init-param>
</filter>
- <filter-name> 用于为过滤器指定一个名字,该元素的内容不能为空。
- <filter-class> 元素用于指定过滤器的完整的限定类名。
- <init-param> 元素用于用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名称,<param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。
- <filter-name> 子元素用于设置Filter的注册名称。该值必须是在<filter>元素中生命过的过滤器的名称。
- <url-pattern> 设置filter所拦截的请求路径(过滤器关联的URL样式)。
- <servlet-name>指定过滤器所拦截的Servlet名称。
- <dispatcher> 指定过滤器所拦截的资源被Servlet容器调用的方式,可以是REQUEST,INCLUDE,FORWARD,和ERROR之一,默认是REQUEST。用户可以设置多个<dispatcher>子元素用来指定Filter对资源的多种调用方式进行拦截。
- 绝对路径匹配:以/开头 不包含通配符 * 是一个绝对访问路径。例如:/demo、/index.jsp
- 目录匹配:以/ 开头,以 * 结尾。例如:/*、/servlet/*、/servlet/xxx/*
- 扩展名匹配:不能以/ 开头,也不能以*结尾 只能以后缀名结尾 例如:*.do、*.demo等
- REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
- INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
- FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
- ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
<filter-mapping><filter-name>testFilter</filter-name><url-pattern>/test.jsp</url-pattern>
</filter-mapping>
<filter-mapping><filter-name>testFilter</filter-name><url-pattern>/index.jsp</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>FORWARD</dispatcher>
</filter-mapping>
代码解析Filter的使用及原理:
package cn.itcast.web.filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
// Filter入门
// 1.创建一个类你,实现Filter接口
// 2.重写方法
// 3.在web.xml文件中配置public class Demo1Filter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {System.out.println("进行过滤操作......");// 放行chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("Demo1Filter初始化创建....");}}
配置Demo1Filter的注册与映射 在web.xml中添加如下配置:
<!-- Filter入门 --><filter> <filter-name>demoFilter</filter-name><filter-class>cn.itcast.web.filter.Demo1Filter</filter-class></filter><filter-mapping><filter-name>demoFilter</filter-name><url-pattern>/index.jsp</url-pattern> <!-- 访问index.jsp页面会被demoFilter过滤 --></filter-mapping>
启动服务器 在后台日志打印中发现调用了init方法
访问主页(index.jsp)
(2)演示FilterChain链的执行顺序 以及Filter的过滤顺序。
创建FirstFilter过滤器
package cn.itcast.web.filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;public class FirstFilter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {System.out.println("firstFilter....");chain.doFilter(request, response);System.out.println("firstFilter end....");}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}}
SecondFilter
package cn.itcast.web.filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;public class SecondFilter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {System.out.println("secondFilter....");chain.doFilter(request, response);System.out.println("secondFilter end....");}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}}
package cn.itcast.web.servlet;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class DemoServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("demo servlet");}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
在web.xml中添加如下配置:
<filter><filter-name>firstFilter</filter-name><filter-class>cn.itcast.web.filter.FirstFilter</filter-class></filter><filter><filter-name>senondFilter</filter-name><filter-class>cn.itcast.web.filter.SecondFilter</filter-class></filter><filter-mapping><filter-name>firstFilter</filter-name><url-pattern>/demo</url-pattern></filter-mapping><filter-mapping><filter-name>senondFilter</filter-name><url-pattern>/demo</url-pattern></filter-mapping><servlet><servlet-name>demoServlet</servlet-name><servlet-class>cn.itcast.web.servlet.DemoServlet</servlet-class></servlet><servlet-mapping><servlet-name>demoServlet</servlet-name><url-pattern>/demo</url-pattern></servlet-mapping>
启动服务器,访问/demo
将FirstFilter的<filter-mapping>标签对放置在SecondFilter的映射标签对的前面 重启服务器 访问/demo
package cn.itcast.web.filter;import java.io.IOException;
import java.util.Enumeration;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
// Filter入门
// 1.创建一个类你,实现Filter接口
// 2.重写方法
// 3.在web.xml文件中配置public class Demo2Filter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {System.out.println("demo2Filter进行过滤操作......");// 放行chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 1. 获取filter名称String filterName = filterConfig.getFilterName();System.out.println(filterName);// 2.获取初始化参数String encoding = filterConfig.getInitParameter("encoding");System.out.println(encoding);Enumeration<String> names = filterConfig.getInitParameterNames();while (names.hasMoreElements()) {System.out.println(names.nextElement());}// 3.获取ServletConfig对象filterConfig.getServletContext();}}
在web.xml中添加如下配置:
<filter><filter-name>demo2Filter</filter-name><filter-class>cn.itcast.web.filter.Demo2Filter</filter-class><!-- 初始化参数 --><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param><init-param><param-name>username</param-name><param-value>liuxun</param-value></init-param></filter><filter-mapping><filter-name>demo2Filter</filter-name><url-pattern>/index.jsp</url-pattern> <!-- 访问index.jsp页面会被demoFilter过滤 --></filter-mapping>
重启服务器:
package cn.itcast.web.servlet;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class DemoServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("demo servlet");// 请求转发到demo1Servletrequest.getRequestDispatcher("/demo1").forward(request, response);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
Demo1Servlet
package cn.itcast.web.servlet;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class Demo1Servlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("Demo1Servlet ......");}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
在web.xml中添加如下配置:
<!-- 使用MyFilter对Demo1Servlet进行拦截 --><filter><filter-name>myFilter</filter-name><filter-class>cn.itcast.web.filter.MyFilter</filter-class></filter><filter-mapping><filter-name>myFilter</filter-name><url-pattern>/demo1</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>FORWARD</dispatcher></filter-mapping><servlet><servlet-name>demoServlet</servlet-name><servlet-class>cn.itcast.web.servlet.DemoServlet</servlet-class></servlet><servlet><servlet-name>Demo1Servlet</servlet-name><servlet-class>cn.itcast.web.servlet.Demo1Servlet</servlet-class></servlet><servlet-mapping><servlet-name>demoServlet</servlet-name><url-pattern>/demo</url-pattern></servlet-mapping><servlet-mapping><servlet-name>Demo1Servlet</servlet-name><url-pattern>/demo1</url-pattern></servlet-mapping>
访问/demo1 后台打印如下:
Filter应用示例:
示例1:全站统一字符编码过滤器
处理请求post乱码代码
request.setCharacterEncoding("utf-8");
设置响应编码集代码
response.setContentType("text/html;charset=utf-8");
经常会使用,而过滤器可以在目标资源之前执行,将很多程序中处理乱码公共代码,提取到过滤器中 ,以后程序中不需要处理编码问题了
代码如下:
package cn.itcast.filter.demo1;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class EncodingFilter implements Filter {private String encode;@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest arg0, ServletResponse arg1,FilterChain arg2) throws IOException, ServletException {// 1.强制转换HttpServletRequest request = (HttpServletRequest) arg0;HttpServletResponse response = (HttpServletResponse) arg1;// 2.操作request.setCharacterEncoding(encode);response.setContentType("text/html;charset=utf-8");// 3.放行arg2.doFilter(request, response);}@Overridepublic void init(FilterConfig arg0) throws ServletException {this.encode = arg0.getInitParameter("encode");}}
Demo1Servlet.java
package cn.itcast.servlet.demo1;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class Demo1Servlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// request.setCharacterEncoding("utf-8");// 1.获取页面的请求参数String username = request.getParameter("username");String msg = request.getParameter("msg");// 显示System.out.println(username);System.out.println(msg);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
demo1.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>My JSP 'demo1.jsp' starting page</title></head><body><form action="${pageContext.request.contextPath }/demo1" method="POST">username:<input type="text" name="username"> <br> msg:<inputtype="text" name="msg"><br> <input type="submit"value="提交"></form>
</body>
</html>
在web.xml中添加如下配置
<!-- post编码过滤器 --><filter><filter-name>encodingFilter</filter-name><filter-class>cn.itcast.filter.demo1.EncodingFilter</filter-class><init-param><param-name>encode</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><servlet><servlet-name>Demo1Servlet</servlet-name><servlet-class>cn.itcast.servlet.demo1.Demo1Servlet</servlet-class></servlet><servlet-mapping><servlet-name>Demo1Servlet</servlet-name><url-pattern>/demo1</url-pattern></servlet-mapping>
访问如下:
示例2:禁用所有JSP页面缓存
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
将禁用缓存代码,提起到过滤器中,通过url配置,禁用所有JSP页面的缓存
CacheFilter
package cn.itcast.filter.demo2;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class CacheFilter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {// 1.强制转换HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;// 2.操作response.setHeader("pragma", "no-cache");response.setHeader("cache-control", "no-cache");response.setDateHeader("expires", 0);// 3.放行chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}}
在web.xml中注册映射filter
<filter><filter-name>cacheFilter</filter-name><filter-class>cn.itcast.filter.demo2.CacheFilter</filter-class></filter><filter-mapping><filter-name>cacheFilter</filter-name><url-pattern>*.jsp</url-pattern></filter-mapping>
示例3:设置图片过期时间
package cn.itcast.filter.demo3;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class ImageCacheFilter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {// 1.强制转换HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;// 2.操作 设置响应的缓存时间为10天response.setDateHeader("expires", System.currentTimeMillis() + 60 * 60* 24 * 10*1000);// 3.放行chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}}
新建一加载图片的jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>My JSP 'index.jsp' starting page</title></head><body><img src="${pageContext.request.contextPath}/filter.jpg"></body>
</html>
配置图片过滤器的注册和映射 在web.xml中添加如下配置
<filter><filter-name>imageFilter</filter-name><filter-class>cn.itcast.filter.demo3.ImageCacheFilter</filter-class></filter><filter-mapping><filter-name>imageFilter</filter-name><url-pattern>*.png</url-pattern><url-pattern>*.jpg</url-pattern><url-pattern>*.bmp</url-pattern></filter-mapping>
重启服务器 访问 查看如下:
示例4:实现用户自动登录(MD5加密)的过滤器
简介:在用户登陆成功后,以cookis形式发送用户名、密码给客户端
编写一个过滤器,filter方法中检查cookie中是否带有用户名、密码信息,如果存在则调用业务层登陆方法,登陆成功后则向session中存入user对象(即用户登陆标记),以实现程序完成自动登陆。
需求:在访问一个站点,登陆时勾选自动登陆(三个月内不用登陆),操作系统后,关闭浏览器;过几天再次访问该站点时,直接进行登陆后状态
思路如下:
在数据库中创建user表
create table user (id int primary key auto_increment,username varchar(20),password varchar(40),role varchar(10)
);insert into user values(null,'admin','123','admin');
insert into user values(null,'aaa','123','user');
insert into user values(null,'bbb','123','user');
在用户完成登陆后,勾选自动登陆复选框,服务器端将用户名和密码 以Cookie形式,保存在客户端 。当用户下次访问该站点,AutoLoginFilter 过滤器从Cookie中获取 自动登陆信息
1、判断用户是否已经登陆,如果已经登陆,没有自动登陆的必要
2、判断Cookie中是否含有自动登陆信息 ,如果没有,无法完成自动登陆
3、使用cookie用户名和密码 完成自动登陆
如果将用户密码保存在cookie文件中,非常不安全的 ,通常情况下密码需要加密后才能保存到客户端
* 使用md5算法对密码进行加密
* md5 加密算法是一个单向加密算法 ,支持明文---密文 不支持密文解密
注意事项:Cookie中是不能保持中文的可以使用URLEncode类进行encode加密,获取后进行解密 可以保存中文用户名 至于密码 使用以MD5进行加密后的密码即可 二者拼接返回客户端。
+----------------------------------+
| md5('123') |
+----------------------------------+
| 202cb962ac59075b964b07152d234b70 |
+----------------------------------+
1 row in set (0.00 sec)
package cn.itcast.utils;import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public class Md5Utils {public static String md5(String plainText) { //明文byte[] secretBytes = null;try {secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes());} catch (NoSuchAlgorithmException e) {throw new RuntimeException("没有md5这个算法!");}String md5code = new BigInteger(1, secretBytes).toString(16);for (int i = 0; i < 32 - md5code.length(); i++) {md5code = "0" + md5code;}return md5code;}public static void main(String[] args) {System.out.println(md5("123"));}}
在classPath路径即src下新建c3p0-config.xml 文件配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config><default-config><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql:///mydb1</property><property name="user">root</property><property name="password">root</property></default-config></c3p0-config>
新建工具包 在包内新建获取数据源的工具类
package cn.itcast.utils;import java.sql.Connection;
import java.sql.SQLException;import javax.sql.DataSource;import com.mchange.v2.c3p0.ComboPooledDataSource;public class DataSourceUtils {private static ComboPooledDataSource cpds = new ComboPooledDataSource();public static Connection getConnection() throws SQLException {return cpds.getConnection();}public static DataSource getDataSource() {return cpds;}}
在工具包内新建MD5加密的工具类
package cn.itcast.utils;import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public class Md5Utils {public static String md5(String plainText) { //明文byte[] secretBytes = null;try {secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes());} catch (NoSuchAlgorithmException e) {throw new RuntimeException("没有md5这个算法!");}String md5code = new BigInteger(1, secretBytes).toString(16);for (int i = 0; i < 32 - md5code.length(); i++) {md5code = "0" + md5code;}return md5code;}public static void main(String[] args) {System.out.println(md5("123"));}}
在工具包内新建根据名称从Cookie[] 数组中取出Cookie的工具类
package cn.itcast.utils;import javax.servlet.http.Cookie;public class CookieUtils {public static Cookie findCookieByName(Cookie[] cs, String name) {if (cs == null || cs.length == 0) {return null;}for (Cookie c : cs) {if (c.getName().equals(name)) {return c;}}return null;}
}
package cn.itcast.domain;public class User {private int id;private String username;private String password;private String role;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getRole() {return role;}public void setRole(String role) {this.role = role;}
}
新建DAO UserDao
package cn.itcast.dao;import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;import cn.itcast.domain.User;
import cn.itcast.utils.DataSourceUtils;public class UserDao {// 根据用户名和密码查找用户public User findUserByUsernameAndPassword(String username, String password)throws SQLException {String sql = "select * from user where username=? and password=?";QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());return runner.query(sql, new BeanHandler<User>(User.class), username,password);}
}
新建业务层类UserService 实现登录功能
package cn.itcast.service;import java.sql.SQLException;import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;public class UserService {public User login(String username, String password) throws SQLException {return new UserDao().findUserByUsernameAndPassword(username, password);}
}
package cn.itcast.servlet.demo4;import java.io.IOException;
import java.net.URLEncoder;
import java.sql.SQLException;import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import cn.itcast.domain.User;
import cn.itcast.service.UserService;
import cn.itcast.utils.Md5Utils;public class LoginServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("utf-8");// 1.得到请求参数String username = request.getParameter("username");String password = request.getParameter("password");// 2.登录UserService service = new UserService();try {User user = service.login(username, Md5Utils.md5(password));if (user != null) {// 登录成功// 判断是否勾选了自动登录String autologin = request.getParameter("autologin");if ("ok".equals(autologin)) {// 勾选了自动登录Cookie cookie = new Cookie("autologin", URLEncoder.encode(username, "utf-8") + "::" + Md5Utils.md5(password));cookie.setMaxAge(60 * 60 * 24 * 10); // 存储10天cookie.setPath("/");response.addCookie(cookie);}request.getSession().setAttribute("user", user);response.sendRedirect(request.getContextPath()+ "/demo4/success.jsp");return;} else {request.setAttribute("login.message", "用户名或密码错误");request.getRequestDispatcher("/demo4/login.jsp").forward(request, response);return;}} catch (SQLException e) {e.printStackTrace();request.setAttribute("login.message", "登录失败");request.getRequestDispatcher("/demo4/login.jsp").forward(request,response);return;}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
新建AutoLoginFilter类 读取Cookie实现自动登录
package cn.itcast.filter.demo4;import java.io.IOException;
import java.net.URLDecoder;
import java.sql.SQLException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import cn.itcast.domain.User;
import cn.itcast.service.UserService;
import cn.itcast.utils.CookieUtils;
import cn.itcast.utils.Md5Utils;public class AutoLoginFilter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {// 1.强制转换HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;// 2.操作// 判断用户访问的是登录操作,不进行自动登录String uri = request.getRequestURI();String contextPath = request.getContextPath();String path = uri.substring(contextPath.length());// System.out.println(uri);
// System.out.println(contextPath);
// System.out.println(path);if (!(path.equals("/demo4/login.jsp") || path.equals("/login"))) {// 判断用户没有登录,才进行自动登录User u = (User) request.getSession().getAttribute("user");System.out.println(u);if (u == null) {// 2.1得到cookie中的username,passwordCookie cookie = CookieUtils.findCookieByName(request.getCookies(), "autologin");if (cookie != null) {// 找到了则进行自动登录String username = URLDecoder.decode(cookie.getValue().split("::")[0], "utf-8");String password = cookie.getValue().split("::")[1];UserService service = new UserService();User user = null;try {user = service.login(username, password);if (user != null) {// 查到了用户,则进行自动登录request.getSession().setAttribute("user", user);return;}} catch (SQLException e) {e.printStackTrace();}}}}// 3.放行chain.doFilter(request, response);}@Overridepublic void init(FilterConfig arg0) throws ServletException {}}
<!-- 自动登录Filter --><filter><filter-name>autoLoginFilter</filter-name><filter-class>cn.itcast.filter.demo4.AutoLoginFilter</filter-class></filter><filter-mapping><filter-name>autoLoginFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><servlet><servlet-name>LoginServlet</servlet-name><servlet-class>cn.itcast.servlet.demo4.LoginServlet</servlet-class></servlet><servlet-mapping><servlet-name>LoginServlet</servlet-name><url-pattern>/login</url-pattern></servlet-mapping>
在WebRoot下新建demo文件夹 在文件夹内新建login.jsp、success.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>
</head><body>${ requestScope["login.message"] }<br><!-- 注意:pageContext.request代表当前页面的请求对象,我们知道JSP是源于Servlet如果不用pageContext对象,直接使用request 则代表其他页面向该JSP请求的对象--><form action="${pageContext.request.contextPath }/login" method="POST">username:<input type="text" name="username"><br>password:<input type="password" name="password"><br><input type="checkbox" name="autologin" value="ok">自动登录<br><input type="submit" value="登录"></form>
</body>
</html>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>
</head><body>
当前用户:${user.username }
</body>
</html>
运行结果如下:
示例5:实现URL级别的权限控制
情景:在实际开发中我们经常把一些执行敏感操作的servlet映射到一些特殊目录中,并用filter把这些特殊目录保护起来,限制只能拥有相应访问权限的用户才能访问这些目录下的资源。从而在我们系统中实现一种URL级别的权限功能。
要求:为使Filter具有通用性,Filter保护的资源和相应的访问权限通过filter参数的形式予以配置。
需求:角色role是admin的只可以实现“书架”增删改 角色为user的用户只能进行查询
package cn.itcast.servlet.demo5;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class BookAddServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("book add ......");}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
BookDeleteServlet url:/book_delete
package cn.itcast.servlet.demo5;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class BookDeleteServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("book delete ......");}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
BookSearchServlet url: /book_search
package cn.itcast.servlet.demo5;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class BookSearchServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("book search ......");}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
BookUpdateServlet url: /book_update
package cn.itcast.servlet.demo5;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class BookUpdateServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("book update ......");}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
新建自定义权限异常类PrivilegeException 继承自RuntimeException
package cn.itcast.exception;import java.io.PrintStream;
import java.io.PrintWriter;public class PrivilegeException extends RuntimeException {@Overridepublic String getMessage() {// TODO Auto-generated method stubreturn super.getMessage();}@Overridepublic String getLocalizedMessage() {// TODO Auto-generated method stubreturn super.getLocalizedMessage();}@Overridepublic synchronized Throwable getCause() {// TODO Auto-generated method stubreturn super.getCause();}@Overridepublic synchronized Throwable initCause(Throwable cause) {// TODO Auto-generated method stubreturn super.initCause(cause);}@Overridepublic String toString() {// TODO Auto-generated method stubreturn super.toString();}@Overridepublic void printStackTrace() {// TODO Auto-generated method stubsuper.printStackTrace();}@Overridepublic void printStackTrace(PrintStream s) {// TODO Auto-generated method stubsuper.printStackTrace(s);}@Overridepublic void printStackTrace(PrintWriter s) {// TODO Auto-generated method stubsuper.printStackTrace(s);}@Overridepublic synchronized Throwable fillInStackTrace() {// TODO Auto-generated method stubreturn super.fillInStackTrace();}@Overridepublic StackTraceElement[] getStackTrace() {// TODO Auto-generated method stubreturn super.getStackTrace();}@Overridepublic void setStackTrace(StackTraceElement[] stackTrace) {// TODO Auto-generated method stubsuper.setStackTrace(stackTrace);}@Overridepublic int hashCode() {// TODO Auto-generated method stubreturn super.hashCode();}@Overridepublic boolean equals(Object obj) {// TODO Auto-generated method stubreturn super.equals(obj);}@Overrideprotected Object clone() throws CloneNotSupportedException {// TODO Auto-generated method stubreturn super.clone();}@Overrideprotected void finalize() throws Throwable {// TODO Auto-generated method stubsuper.finalize();}}
新建自定义权限异常抛出后跳转的页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>My JSP 'privilege.jsp' starting page</title></head><body><h1>权限不足</h1></body>
</html>
最后自定义URL权限访问过滤器package cn.itcast.filter.demo5;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import cn.itcast.domain.User;
import cn.itcast.exception.PrivilegeException;//权限过滤器--垃圾版本
public class PrivilegeFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {// 1.强制转换HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;// 2.操作// 判断当前资源是否需要权限控制.String uri = request.getRequestURI();String contextPath = request.getContextPath();String path = uri.substring(contextPath.length());if (path.equals("/book_add") || path.equals("/book_update")|| path.equals("/book_delete") || path.equals("/book_search")) {// 判断用户是否登录了.User user = (User) request.getSession().getAttribute("user");if (user == null) {throw new PrivilegeException();}// 判断用户的角色,是否可以访问当前资源路径。if ("admin".equals(user.getRole())) {// 这是admin角色if (!(path.equals("/book_add") || path.equals("/book_update") || path.equals("/book_delete"))) {throw new PrivilegeException();}} else {// 这是user角色if (!(path.equals("/book_search"))) {throw new PrivilegeException();}}}// 3.放行chain.doFilter(request, response);}public void init(FilterConfig filterConfig) throws ServletException {}}
注意:以上的这个权限过滤器虽然可以使用 但代码过于臃肿,另外访问路径和filter的耦合性很强不便于维护
url=/book_add,/book_delete,/book_update
user.properties
url=/book_search
(2)修改权限过滤器如下所示:
package cn.itcast.filter.demo5;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import cn.itcast.domain.User;
import cn.itcast.exception.PrivilegeException;//权限过滤器
public class PrivilegeFilter implements Filter {private List<String> admins;private List<String> users;public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {// 1.强制转换HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;// 2.操作// 判断当前资源是否需要权限控制.String uri = request.getRequestURI();String contextPath = request.getContextPath();String path = uri.substring(contextPath.length());if (admins.contains(path) || users.contains(path)) {// 判断用户是否登录了.User user = (User) request.getSession().getAttribute("user");if (user == null) {throw new PrivilegeException();}// 判断用户的角色,是否可以访问当前资源路径。if ("admin".equals(user.getRole())) {// 这是admin角色if (!(admins.contains(path))) {throw new PrivilegeException();}} else {// 这是user角色if (!(users.contains(path))) {throw new PrivilegeException();}}}// 3.放行chain.doFilter(request, response);}public void init(FilterConfig filterConfig) throws ServletException {this.admins = new ArrayList<String>();this.users = new ArrayList<String>();fillPath("user", users);fillPath("admin", admins);}private void fillPath(String baseName, List<String> list) {ResourceBundle bundle = ResourceBundle.getBundle(baseName);String path = bundle.getString("url");String[] paths = path.split(",");for (String p : paths) {list.add(p);}}}
修改示例4中的success.jsp 如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>My JSP 'index.jsp' starting page</title>
</head><body>当前用户:${user.username}<br><a href="${pageContext.request.contextPath}/book_add">book add</a><br><a href="${pageContext.request.contextPath}/book_update">book update</a><br><a href="${pageContext.request.contextPath}/book_delete">book delete</a><br><a href="${pageContext.request.contextPath}/book_search">book search</a>
</body>
</html>
最后进行web.xml的配置(添加异常类配置和权限过滤器配置)
<!-- URL权限访问控制Filter --><filter><filter-name>privilegeFilter</filter-name><filter-class>cn.itcast.filter.demo5.PrivilegeFilter</filter-class></filter><filter-mapping><filter-name>privilegeFilter</filter-name><url-pattern>/book_delete</url-pattern><url-pattern>/book_add</url-pattern><url-pattern>/book_update</url-pattern><url-pattern>/book_search</url-pattern></filter-mapping><servlet><servlet-name>LoginServlet</servlet-name><servlet-class>cn.itcast.servlet.demo4.LoginServlet</servlet-class></servlet><servlet><servlet-name>BookAddServlet</servlet-name><servlet-class>cn.itcast.servlet.demo5.BookAddServlet</servlet-class></servlet><servlet><servlet-name>BookDeleteServlet</servlet-name><servlet-class>cn.itcast.servlet.demo5.BookDeleteServlet</servlet-class></servlet><servlet><servlet-name>BookUpdateServlet</servlet-name><servlet-class>cn.itcast.servlet.demo5.BookUpdateServlet</servlet-class></servlet><servlet><servlet-name>BookSearchServlet</servlet-name><servlet-class>cn.itcast.servlet.demo5.BookSearchServlet</servlet-class></servlet><servlet-mapping><servlet-name>Demo1Servlet</servlet-name><url-pattern>/demo1</url-pattern></servlet-mapping><servlet-mapping><servlet-name>LoginServlet</servlet-name><url-pattern>/login</url-pattern></servlet-mapping><servlet-mapping><servlet-name>BookAddServlet</servlet-name><url-pattern>/book_add</url-pattern></servlet-mapping><servlet-mapping><servlet-name>BookDeleteServlet</servlet-name><url-pattern>/book_delete</url-pattern></servlet-mapping><servlet-mapping><servlet-name>BookUpdateServlet</servlet-name><url-pattern>/book_update</url-pattern></servlet-mapping><servlet-mapping><servlet-name>BookSearchServlet</servlet-name><url-pattern>/book_search</url-pattern></servlet-mapping><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><error-page><exception-type>cn.itcast.exception.PrivilegeException</exception-type><location>/error/privilege.jsp</location></error-page>
分别以admin和aaa 密码123登录运行结果如下:
web.xml中元素的配置顺序
示例6:通用的get和post乱码过滤器
Decorator设计模式的实现
request对象的增强
- Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper , (HttpServletRequestWrapper 类实现了request 接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法)以避免用户在对request对象进行增强时需要实现request接口中的所有方法。
- 使用Decorator模式包装request对象,完全解决get、post请求方式下的乱码问题
开始进行编码过滤器的编写,其中需要注意的事项如下:
getParameter
getParameterValues
getParameterMap
在覆盖的时候可以考虑只遍历getParameterMap中的键值对 使用new String(name.getBytes("iso-8859-1"),"utf-8")方法对参数值进行重新编码,这样做必须注意一条,因为第一次调用就已经将所有参数的值进行重新编码,如果再次调用就会将编码后正常的参数值又进行一次编码 造成除了第一次获取后的参数都是乱码,其解决方案就是 加flag限制符保证一次请求只调用获取参数方法时只遍历一次getParameterMap方法。
编写过滤器如下:
package cn.itcast.filter.demo6;import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;public class EncodingFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {// 1.强制转换HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;// 2.操作HttpServletRequest myrequest = new MyRequest(request); // 增强后的request,解决了编码问题response.setContentType("text/html;charset=utf-8");// 3.放行chain.doFilter(myrequest, response);}public void init(FilterConfig filterConfig) throws ServletException {}}// 装饰类
class MyRequest extends HttpServletRequestWrapper {private HttpServletRequest request;public MyRequest(HttpServletRequest request) {super(request);this.request = request;}// 重写关于获取请求参数的方法.@Overridepublic String getParameter(String name) {Map<String, String[]> map = getParameterMap();if (name == null) {return null;}String[] st = map.get(name);if (st == null || st.length == 0) {return null;}return st[0];}@Overridepublic String[] getParameterValues(String name) {Map<String, String[]> map = getParameterMap();if (name == null) {return null;}String[] st = map.get(name);return st;}private boolean flag = true;@Overridepublic Map getParameterMap() {// 1.得到所有请求参数的Map集合Map<String, String[]> map = request.getParameterMap(); // 有编码问题.// 2.解决编码问题.if (flag) {for (String key : map.keySet()) {String[] values = map.get(key);for (int i = 0; i < values.length; i++) {try {values[i] = new String(values[i].getBytes("iso8859-1"),"utf-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}}}flag = false;}return map;}}
编写Servlet处理表单的示例 进行测试 Demo6Servlet
package cn.itcast.servlet.demo6;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class Demo6Servlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println(request.getParameter("msg1"));System.out.println(request.getParameter("msg2"));}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
demo6.jsp <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>My JSP 'demo6.jsp' starting page</title></head><body><form action="${pageContext.request.contextPath }/demo6" method="GET">msg1:<input type="text" name="msg1"><br>msg1:<input type="text" name="msg2"><br><input type="submit" value="提交"><br></form></body>
</html>
在web.xml添加如下配置 进行注册和映射编码过滤器
<filter><filter-name>EncodingFilter</filter-name><filter-class>cn.itcast.filter.demo6.EncodingFilter</filter-class></filter><filter-mapping><filter-name>EncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
运行结果如下:
示例7:response增强压缩响应
- 通过filter向目标页面传递一个自定义的response对象。
- 在自定义的response对象中,重写getOutputStream方法和getWriter方法,使目标资源调用此方法输出页面内容时,获得的是我们自定义的ServletOutputStream对象。
- 在我们自定义的ServletOuputStream对象中,重写write方法,使写出的数据写出到一个buffer中。
- 当页面完成输出后,在filter中就可得到页面写出的数据,从而我们可以调用GzipOuputStream对数据进行压缩后再写出给浏览器,以此完成响应正文件压缩功能。
这篇关于JAVAWEB开发之Servlet Filter(过滤器)详解包括post和get编码过滤器、URL访问权限控制、自动登录。以及装饰模式的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!