每周一约!哈哈!小白又来啦!这周我们来聊聊Javaweb的三大组件——servlet、filter、listener。servlet之前的文章已经讲过了,这次来聊聊剩下的两个吧!
当访问服务器资源的时候,过滤器可以将请求拦截下来,完成一些特殊的功能。
一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤...
(1)定义一个类,实现接口Filter
(2)复写方法
(3)配置拦截路径
@WebFilter("/*")//访问所有的资源之前,都被执行该过滤器
public class FileterDemo1 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("过滤器被执行了......");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
<filter>
<filter-name>demo1</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo1</filter-class>
</filter>
<filter-mapping>
<filter-name>demo1</filter-name>
<!-- 拦截路径 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
(1)执行过滤器
(2)执行放行后的资源
(3)回来执行过滤器放行代码下边的代码
(1)init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次,用于加载资源
(2)doFilter:每一次请求被拦截资源时,会执行。执行多次
(3)destroy:在服务器关闭后,Filter对象被销毁,用于释放资源
(1)拦截路径配置
* 具体资源路径(/index.jsp):只有访问index.jsp资源时,过滤器才会被执行
* 拦截目录(/user/*):访问/user下的所有资源时,过滤器都会被执行
* 后缀名拦截(*.jsp): 访问所有后缀名为jsp资源时,过滤器都会被执行
* 拦截所有资源(/*): 访问所有资源时,过滤器都会被执行
(2)拦截方式配置:资源被访问的方式
1. REQUEST:默认值。浏览器直接请求资源
2. FORWORD:转发访问资源
3. INCLUDE:包含访问资源
4. ERROR:错误跳转资源
5. ASYNC:异步访问资源
<dispatcher></dispatcher>
标签即可(1)执行顺序:如果有两个过滤器,过滤器1和过滤器2,则按照下面的顺序执行
1. 过滤器1
2. 过滤器2
3. 资源执行
4. 过滤器2
5. 过滤器1
(2)过滤器先后顺序
(1)需求
(2)代码实现
/**
* 登录验证的过滤器
*/
@WebFilter("/*")
public class loginFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//0.强制转换req
HttpServletRequest request = (HttpServletRequest) req;
//1.获取请求路径
String uri = request.getRequestURI();
//2.判断是否包含登录相关的资源路径,要注意排除掉 css/js/图片/验证码等资源
if(uri.contains("/login.jsp") || uri.contains("/loginServlet") || uri.contains("/css/") || uri.contains("/fonts/") || uri.contains("/js/")|| uri.contains("/checkCodeServlet")){
//包含,说明当前用户就是想登录
chain.doFilter(req,resp);
}else{
//不包含,需要判断是否已经登录
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 void destroy() {
}
public void init(FilterConfig config) throws ServletException {
}
}
(1)需求
(2)分析
(3)代码实现
/**
* 敏感词汇过滤器
*/
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.创建代理对象,增强getParameter方法
ServletRequest proxy_req =(ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.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(req, args);
if (value != null) {
for (String str : list) {
if (value.contains(str)){
value = value.replaceAll(str, "***");
}
}
}
return value;
}
return method.invoke(req,args);
}
});
//2.放行
chain.doFilter(proxy_req, resp);
}
public void destroy() {
}
private List<String> list = new ArrayList<String>();//敏感词汇
public void init(FilterConfig config) throws ServletException {
//1.获取文件真实路径
try {
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
//2.读取文件
BufferedReader br = new BufferedReader(new FileReader(realPath));
String line = null;
while((line = br.readLine())!=null){
//3.将文件的每一行数据添加到list中
list.add(line);
}
br.close();
System.out.println(list);
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上面的代码实现中,我们对request对象进行了增强的改进。主要是因为request对象自带的getParameter方法不足以完成我们的替换操作。并且,request对象的getParameter方法需要我们对获取到的value值进行遍历替换,较为麻烦。所以我们对此方法进行了一定的增强,具体的实现代码在上面已经给出。下面我们主要详解一下增强功能对象方法的逻辑。
在对对象进行增强功能的时候,我们一般使用的是设计模式来完成,主要有装饰模式和代理模式两种方法,我们此处使用的是代理模式,下面我们详解一下代理模式。
(1)概念
1. 真实对象:被代理的对象
2. 代理对象:代理真实对象
3. 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
(2)实现方式
(3)增强方式
(4)代码实现方式
public interface SaleComputer {
public String sale(double money);
void show();
}
2. 创建一个真实类
/**
* 真实类
*/
public class Lenovo implements SaleComputer {
@Override
public String sale(double money) {
System.out.println("花了"+money+"元买了一台联想电脑....");
return "联想电脑";
}
@Override
public void show() {
System.out.println("展示电脑.....");
}
}
3. 实现代理
public class ProxyTest {
public static void main(String[] args) {
//1.创建真实对象
Lenovo lenovo = new Lenovo();
//2.动态代理增强Lenovo对象
/*
三个参数:
1. 类加载器:真实对象.getClass().getClassLoader()
2. 接口数组:真实对象.getClass().getInterfaces()
3. 处理器:new InvocationHandler()
*/
SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
/*
代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
参数:
1. proxy:代理对象,即为proxy_lenovo
2. method:代理对象调用的方法,被封装为Method对象
3. args:代理对象调用方法时,传递的实际参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//判断是否是sale方法
if (method.getName().equals("sale")){
//1.增强参数
double money = (double)args[0];
money = money * 0.85;
//增强方法体业务逻辑
System.out.println("专车接你");
//使用真实对象调用该方法
String obj = (String) method.invoke(lenovo,money);
System.out.println("免费送货");
//2.增强返回值
return obj+"_鼠标垫";
}else{
//使用真实对象调用该方法
Object obj = method.invoke(lenovo,args);
return obj;
}
}
});
//3.调用方法
String computer = proxy_lenovo.sale(8000);
System.out.println(computer);
proxy_lenovo.show();
}
}
web的三大组件之一。
事件监听机制
监听器有很多种类,我们重点讲解一个ServletContextListener监听器,此监听器的主要功能是监听ServletContext对象的创建和销毁。
(1)定义一个类,实现ServletContextListener接口
(2)复写方法
(3)配置
<listener>
<listener-class>cn.itcast.web.listener.ContextLoaderListener</listener-class>
</listener>
以上就是本周总结啦!喜欢本公众号的小伙伴欢迎关注呀!