业务场景:
在实际请求中,应当对每一个请求的合法性进行验证,保证请求的正确。而我在使用过程中使用的为spring+spring mvc+mybatis结合使用,所有就理所应当的使用spring mvc的过滤器来充当这个路径过滤的执行者。
在使用遇到的第一个问题:
过滤器实例如何实例化以及如何在启动时如何执行过滤?
查阅资料(连接)
一、自定义过滤器实现过滤,继承OncePerRequestFilter类
@Component
public class SessionFilter extends OncePerRequestFilter implements Filter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//不过滤的uri
String[] notFilter = new String[]{"/login","/lib","/static","/ping"};
//请求的uri
String uri = request.getRequestURI();
System.out.println("filter>>>uri>>>"+uri);
//是否过滤
boolean doFilter = true;
for(String s : notFilter){
//在给定符串中查找另一个字符串
if(uri.indexOf(s) != -1){
//uri中包含不过滤uri,则不进行过滤
doFilter = false;
break;
}
}
if(doFilter){
System.out.println("doFilter>>>");
//过滤操作
//从session中获取登陆者实体
Object obj = request.getSession().getAttribute("token");
if(obj==null){
//todo
System.out.println("doFilter>>>obj is null");
}else{
// 对象实体存在,执行的操作
// 验证token是否合法
String token = (String) obj;
if(token==null){
response.sendRedirect("/login");
//跳转到登录页面
return ;
}
// 如果session中存在登录者实体,则继续
filterChain.doFilter(request, response);
}
}else
//不执行过滤操作
filterChain.doFilter(request, response);
}
}
}
二、在web.xml中告知此过滤器。
<filter>
<filter-name>DelegatingFilterProxy</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>SessionFilter</param-value>
</init-param>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
到此完成了基本的spring mvc的filter基本的拦截。(这里我使用的redis作为缓存来存放token。)
下面就要从缓存中获取token,进行对比验证请求的合法性。
一开始,我使用spring的注解初始化实例,我想在过滤器中得到redis实例进行token的获取。经过几次的操作,都是报错了。通过在控制台进行实例的打印,发现并没有生成实例。所以问题了,为什么没有生成实例?
最后在我的不懈努力下,解决了。
一、使用spring-jedis.xml配置SessionFilter中Jedis实例,如下
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="${redis_maxTotal}"/>
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="${redis_maxIdle}"/>
<!-- 最小空闲连接数 -->
<property name="minIdle" value="${redis_minIdle}"/>
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="${redis_numTestsPerEvictionRun}"/>
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="${redis_timeBetweenEvictionRunsMillis}"/>
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="${redis_minEvictableIdleTimeMillis}"/>
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="${redis_softMinEvictableIdleTimeMillis}"/>
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="${redis_maxWaitMillis}"/>
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="${redis_testOnBorrow}"/>
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="${redis_testWhileIdle}"/>
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="${redis_blockWhenExhausted}"/>
</bean>
<!--连接池配置-->
<bean id="jedisPoolAdmin" class="redis.clients.jedis.JedisPool">
<constructor-arg name="poolConfig" ref="poolConfig"/>
<constructor-arg name="host" value="${redis_admin_ip}"/>
<constructor-arg name="port" value="${redis_port}"/>
<!--超时时间-->
<constructor-arg name="timeout" value="${redis_timeout}"/>
<constructor-arg name="password" value="${redis_admin_auth}"/>
<constructor-arg name="database" value="${redis_admin_database}"/>
</bean>
<!--实例连接池配置-->
<bean id="JedisClientImplAdmin" class="tbcloud.admin.until.JedisClientImplAdmin">
<property name="jedisPool" ref="jedisPoolAdmin"></property>
</bean>
<!--redis实例配置-->
<bean id="SessionFilter" class="tbcloud.admin.filter.SessionFilter">
<property name="jedisClient" ref="JedisClientImplAdmin"></property>
</bean>
二、SessionFilter中redis实例配置:
private JedisClient jedisClient;
public JedisClient getJedisClient() {
return jedisClient;
}
public void setJedisClient(JedisClient jedisClient) {
this.jedisClient = jedisClient;
}
至此,在SessionFilter中得到redis实例,可以进行jedis的操作了。
(https://blog.csdn.net/xiaoyi52/article/details/76686001)
经过测试,此时是可以拿到spring中的redisTemplate 这个bean的,说明spring容器确实先于过滤器初始化的。那么回到过滤器中不能注入bean的问题,原因究竟是什么呢?可以看到,这里获取bean是通过applicationContext获取的,而不是直接注入的。个人理解是:过滤器是servlet规范中定义的,并不归spring容器管理,也无法直接注入spring中的bean(会报错)。当然,要想通过spring注入的方式来使用过滤器也是有办法的,先在web.xml中定义(保证filter在spring中初始化)
<filter>
<filter-name>DelegatingFilterProxy</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>SessionFilter</param-value>
</init-param>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
参照上面配置redis实例。至此完成了token的较,保证请求的合法性————————————>哦也!!!!!!