概念:
快速入门:
过滤器细节:
web.xml配置
<filter>
<filter-name>demo1filter-name>
<filter-class>com.emnets.java1115.Filter.FilterDemo1filter-class>
filter>
<filter-mapping>
<filter-name>demo1filter-name>
<url-pattern>/*url-pattern>
filter-mapping>
过滤器的执行流程
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配置方式:
<filter>
<filter-name>demo1filter-name>
<filter-class>com.emnets.java1115.Filter.FilterDemo1filter-class>
filter>
<filter-mapping>
<filter-name>demo1filter-name>
<url-pattern>/*url-pattern>
<dispatcher>FORWARDdispatcher>
<dispatcher>REQUESTdispatcher>
filter-mapping>
思考题:如果同时配置了请求和转发的过滤,那么一次请求触发的转发会触发几次过滤器
过滤器链(配置多个过滤器)
案例一:登录验证
@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
*/
@Override
public 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;
}
方法增强方式:
增强参数列表
@Override
public 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;
}
}
增强返回值类型
@Override
public 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;
}
}
增强方法体执行逻辑
@Override
public 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<String> list = new ArrayList<String>(); // 敏感词汇
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() {
}
@Override
public 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() {
@Override
public 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
}// if
return value;
}
return method.invoke(request,args);
}
});
// 2.放行,传递代理对象
chain.doFilter(proxy_req, response);
}
}
为了测试编写了一个servlet一起运行:
@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected 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方法的增强:
@Override
public 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() {
@Override
public 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
}// if
return value;
}else if(method.getName().equals("getParameterMap")){
Map<String, String[]> parameterMap = (Map<String, String[]>)method.invoke(request,args);
if(!parameterMap.isEmpty()){
// 遍历参数列表
for(String[] p_value: parameterMap.values()){
// 判断是否有子参数
if(p_value.length>0){
// 遍历子参数
for(int i=0;i<p_value.length;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方式
<listener>
<listener-class>com.emnets.java1115.listener.ContextLoaderListenerlistener-class>
listener>
注解方式
@WebListener
代码:
public class ContextLoaderListener implements ServletContextListener {
/**
* 监听servletContext对象创建。ServletContext对象服务器启动后自动创建。
* @param sce
*/
@Override
public 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
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext对象被销毁了");
}
}