概念:
快速入门:
过滤器细节:
web.xml配置
demo1 com.emnets.java1115.Filter.FilterDemo1
demo1 /*
过滤器的执行流程
doFilter方法中:req就是请求参数,
// 对request对象的请求消息增强
System.out.println("filterDemo2...");
// 放行
chain.doFilter(request, response);
// 对response对象的响应消息增强
System.out.println("filterDemo2 executing!");
过滤器生命周期方法
过滤器的配置详解(两种配置)
拦截路径配置:
拦截方式配置:资源访问的方式(直接请求、转发是两种不同的方式)
注解配置:设置dispatcherTypes的属性
注解配置多个值:
@WebFilter(value = "/*",dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})
web.xml配置方式:
demo1 com.emnets.java1115.Filter.FilterDemo1 demo1 /* FORWARD REQUEST
思考题:如果同时配置了请求和转发的过滤,那么一次请求触发的转发会触发几次过滤器
过滤器链(配置多个过滤器)
案例一:登录验证
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {// 0.强制转换HttpServletRequest request = (HttpServletRequest)req;// 1.获取请求资源的请求路径String requestURI = request.getRequestURI();// 2.判断是否包含登录相关// 2.1 同时还要注意排除各种css/js/图片/验证码等资源if(requestURI.contains("/login.jsp")||requestURI.contains("/loginServlet")||requestURI.contains("/css/*")||requestURI.contains("/js/*")||requestURI.contains("/checkCodeServlet")){// 放行登录chain.doFilter(req, resp);}else {// 3.session获取Object user = request.getSession().getAttribute("user");if(user!=null){// 已经登录了 ,放行chain.doFilter(req, resp);}else {// 跳转登录request.setAttribute("login_msg","您尚未登录");request.getRequestDispatcher("/login.jsp").forward(request,resp);}}}
代理模式:
理解:在运行期间,对象中方法的动态拦截,在拦截前后执行功能操作,而原有对象不改变
概念:
实现方式:(区别在于代理对象的生成方式)
public class ProxyTest {/**** @param args*/public static void main(String[] args) {// 1.创建真实对象Lenovo lenovo = new Lenovo();/*** 2.动态代理增强lenovo对象* 三个参数:* 1.类加载器 : 真实对象.getClass().getClassLoader()* 2.接口数组 : 真实对象.getClass().getInterfaces()* 3.处理器 :*/SaleComputer proxy_lenovo = (SaleComputer)Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {/*** 代理逻辑编写的方法:代理对象调用的所有方法,都会触发该方法执行。* 增强代码的逻辑就会在这个方法中执行* @param proxy 代理对象,就是指proxy_lenovo这个对象,一般不用* @param method 代理对象调用的方法会封装成对象,变成参数传递进来* @param args 代理对象调用方法时,传递的实际参数,封装进args,这里面就会有8000这种参数* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("该方法执行了.....");System.out.println(method.getName());return null;}});// 3.调用方法String computer = proxy_lenovo.sale(8000);System.out.println(computer);}
}
invoke方法的写法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 相当于使用真实对象调用该方法Object obj = method.invoke(lenovo, args);// 思考:方法应该如何增强// 这个返回值就是调用了方法后接收的返回值,会根据操作方法的不同而完全不同。return obj;
}
方法增强方式:
增强参数列表
@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 首先判断方法是否是需要增强的方法if(method.getName().equals("sale")){// 1.增强参数double money = (double) args[0];money *= 0.85;Object obj = method.invoke(lenovo, money);return obj;}else {// 相当于使用真实对象调用该方法Object obj = method.invoke(lenovo, args);// 这个返回值就是调用了方法后接收的返回值,会根据操作方法的不同而完全不同。return obj;}}
增强返回值类型
@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 首先判断方法是否是需要增强的方法if(method.getName().equals("sale")){// 1.增强返回值double money = (double) args[0];money *= 0.85;String obj = (String)method.invoke(lenovo, money);return obj+"_鼠标垫";}else {// 相当于使用真实对象调用该方法Object obj = method.invoke(lenovo, args);// 这个返回值就是调用了方法后接收的返回值,会根据操作方法的不同而完全不同。return obj;}}
增强方法体执行逻辑
@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 首先判断方法是否是需要增强的方法if(method.getName().equals("sale")){// 1.增强返回值double money = (double) args[0];money *= 0.85;System.out.println("专车接你....");String obj = (String)method.invoke(lenovo, money);System.out.println("免费送货....");return obj+"_鼠标垫";}else {// 相当于使用真实对象调用该方法Object obj = method.invoke(lenovo, args);// 这个返回值就是调用了方法后接收的返回值,会根据操作方法的不同而完全不同。return obj;}}
案例二:过滤敏感词汇
/*** 敏感词汇过滤器*/@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {private List list = new ArrayList(); // 敏感词汇public void init(FilterConfig config) throws ServletException {try {// 加载文件,获取文件真实路径ServletContext servletContext = config.getServletContext();String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");// 读取文件BufferedReader br = new BufferedReader(new FileReader(realPath));// 将文件的每一行数据添加到list中String line = null;while ((line = br.readLine())!=null){list.add(line);}br.close();System.out.println(list);} catch (Exception e){e.printStackTrace();}}public void destroy() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {// 1.创建代理对象,增强getParameter方法ServletRequest proxy_req = (ServletRequest)Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if(method.getName().equals("getParameter")){// 增强返回值// 获取返回值,对返回值进行过滤String value = (String)method.invoke(request, args);if(value!=null){for(String str:list){if(value.contains(str)){value = value.replaceAll(str,"***");} // if} //for}// ifreturn value;}return method.invoke(request,args);}});// 2.放行,传递代理对象chain.doFilter(proxy_req, response);}
}
为了测试编写了一个servlet一起运行:
@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String name = request.getParameter("name");String msg = request.getParameter("msg");System.out.println(name+" : "+msg);}
}
补充了对getParameterMap方法的增强:
@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {// 1.创建代理对象,增强getParameter方法ServletRequest proxy_req = (ServletRequest)Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if(method.getName().equals("getParameter")){// 增强返回值// 获取返回值,对返回值进行过滤String value = (String)method.invoke(request, args);if(value!=null){for(String str:list){if(value.contains(str)){value = value.replaceAll(str,"***");} // if} //for}// ifreturn value;}else if(method.getName().equals("getParameterMap")){Map parameterMap = (Map)method.invoke(request,args);if(!parameterMap.isEmpty()){// 遍历参数列表for(String[] p_value: parameterMap.values()){// 判断是否有子参数if(p_value.length>0){// 遍历子参数for(int i=0;i// 遍历敏感词汇for(String str:list){// 判断是否含有敏感词汇if(p_value[i].contains(str)){// 有则替换p_value[i] = p_value[i].replaceAll(str,"***");}}}}}}return parameterMap;}return method.invoke(request,args);}});// 2.放行,传递代理对象chain.doFilter(proxy_req, response);}
概念:web的三大组件之一。
ServletContextListener:监听ServletContext对象的创建和销毁
步骤:
定义一个类,实现servletContextListener接口
复写方法
配置
web.xml方式
com.emnets.java1115.listener.ContextLoaderListener
注解方式
@WebListener
代码:
public class ContextLoaderListener implements ServletContextListener {/*** 监听servletContext对象创建。ServletContext对象服务器启动后自动创建。* @param sce*/@Overridepublic void contextInitialized(ServletContextEvent sce) {// 1.获取servletContext对象ServletContext servletContext = sce.getServletContext();// 2.加载资源文件String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");// 3.获取真实路径String realPath = servletContext.getRealPath(contextConfigLocation);// 4.加载进内存try {FileInputStream fis = new FileInputStream(realPath);System.out.println(fis);} catch (FileNotFoundException e) {e.printStackTrace();}System.out.println("servletContext对象被创建了");}/*** 服务器关闭后,ServletContext对象被销毁,当服务器正常关闭后该方法被调用* @param sce*/@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("ServletContext对象被销毁了");}
}