LJF-Framework 第12章 LjfFilter拦截器设计
一、不成熟的想一下
当请求服务时,得进行拦截筛选、认证一下请求的合法性或者其他处理,我们自定义一个LjfFilter接口,然后实现该接口,当请求时,通过配置拦截顺序,依次执行我们的自定义实现。
首先我们需要一个路由管理器,来管理请求路径
二、路由管理
1、LjfRouter
package com.ljf.framework.router;
import com.ljf.framework.LjfManager;
import com.ljf.framework.fun.LjfParamFunction;
import java.util.List;
/**
* 说明:路由匹配器
*
* @Auther: lijinfeng
* @Date: 2024/4/22
*/
public class LjfRouter {
private boolean isMatch;
public boolean isContinueMatch() {
return ! isMatch;
}
public LjfRouter(){
this.isMatch = true;
}
/**
* 路由匹配
* @param pattern 路由匹配符
* @param path 被匹配的路由
* @return 是否匹配成功
*/
public boolean isMatch(String pattern, String path) {
return LjfManager.getLjfContext().matchPath(pattern, path);
}
/**
* 路由匹配
* @param patterns 路由匹配符集合
* @param path 被匹配的路由
* @return 是否匹配成功
*/
public boolean isMatch(List<String> patterns, String path) {
if(patterns == null) {
return false;
}
for (String pattern : patterns) {
if(isMatch(pattern, path)) {
return true;
}
}
return false;
}
/**
* 路由匹配
* @param patterns 路由匹配符数组
* @param path 被匹配的路由
* @return 是否匹配成功
*/
public boolean isMatch(String[] patterns, String path) {
if(patterns == null) {
return false;
}
for (String pattern : patterns) {
if(isMatch(pattern, path)) {
return true;
}
}
return false;
}
// ------ 使用当前URI匹配
/**
* 路由匹配 (使用当前URI)
* @param pattern 路由匹配符
* @return 是否匹配成功
*/
public boolean isMatchCurrURI(String pattern) {
return isMatch(pattern, LjfManager.getLjfContext().getRequestPath());
}
/**
* 路由匹配 (使用当前URI)
* @param patterns 路由匹配符集合
* @return 是否匹配成功
*/
public boolean isMatchCurrURI(List<String> patterns) {
return isMatch(patterns, LjfManager.getLjfContext().getRequestPath());
}
/**
* 路由匹配 (使用当前URI)
* @param patterns 路由匹配符数组
* @return 是否匹配成功
*/
public boolean isMatchCurrURI(String[] patterns) {
return isMatch(patterns, LjfManager.getLjfContext().getRequestPath());
}
public LjfRouter match(List<String> includeList) {
if (isMatch){
if (isMatchCurrURI(includeList)) {
return this;
}
isMatch = false;
}
return this;
}
public LjfRouter notMatch(List<String> excludeList) {
if (isMatch){
if (!isMatchCurrURI(excludeList)) {
return this;
}
isMatch = false;
}
return this;
}
public LjfRouter check(LjfParamFunction<LjfRouter> fun){
if(isMatch) {
fun.run(this);
}
return this;
}
}
像这样就可以对访问路径进行一些匹配判断
2、LjfRouterManager
package com.ljf.framework.router;
import java.util.Arrays;
import java.util.List;
/**
* 说明:路由管理器
*
* @Auther: lijinfeng
* @Date: 2024/4/23
*/
public class LjfRouterManager {
/**
* 创建路由
* @return
*/
public static LjfRouter createRouter(){
return new LjfRouter();
}
}
三、LjfContext更新
/**
* 校验指定路由匹配符是否可以匹配成功指定路径
*
* @param pattern 路由匹配符
* @param path 需要匹配的路径
*/
public boolean matchPath(String pattern, String path);
添加个路径匹配接口,方便进行请求的路径判断
四、LjfFilter
1、LjfFilter
package com.ljf.framework.filter;
import java.util.List;
/**
* 说明:ljf 拦截器接口
*
* 功能:指定拦截路劲、放行路劲,设置对拦截路劲的处理策略和异常策略
*
* @Auther: lijinfeng
* @Date: 2024/4/26
*/
public interface LjfFilter {
public Integer getOrder();
/**
* 获取 [拦截路由]
*
*/
public List getIncludeList();
/**
* 获取 [放行路由]
*
*/
public List getExcludeList();
public LjfFilterAuthStrategy getBeforeAuthStrategy();
public LjfFilterAuthStrategy getAuthStrategy();
public LjfFilterErrorStrategy getErrorStrategy();
}
2、LjfAbstractFilter
package com.ljf.framework.filter;
import com.ljf.framework.exception.LjfException;
import com.ljf.framework.exception.LjfExceptionEnum;
import com.ljf.framework.exception.LjfFilterException;
import java.util.ArrayList;
import java.util.List;
/**
* 说明:客制化应用的filter可以实现改类
*
*
* @Auther: lijinfeng
* @Date: 2024/4/23
*/
public abstract class LjfAbstractFilter implements LjfFilter {
// ------------------------ 设置此过滤器 拦截 & 放行 的路由
protected abstract List<String> setIncludeList();
protected abstract List<String> setExcludeList();
/**
* 获取 [拦截路由] 集合
*/
@Override
public List<String> getIncludeList() {
return this.setIncludeList();
}
/**
* 获取 [放行路由] 集合
*/
@Override
public List<String> getExcludeList() {
return this.setExcludeList();
}
// ------------------------ 钩子函数
protected abstract LjfFilterAuthStrategy setBeforeAuth();
protected abstract LjfFilterAuthStrategy setAuthStrategy();
/**
* 异常处理函数:每次[认证函数]发生异常时执行此函数
*/
public LjfFilterErrorStrategy errorStrategy = e -> {
throw new LjfFilterException(LjfExceptionEnum.FILTER_ERROR,e.getMessage());
};
@Override
public LjfFilterAuthStrategy getBeforeAuthStrategy() {
return this.setBeforeAuth();
}
@Override
public LjfFilterAuthStrategy getAuthStrategy() {
return this.setAuthStrategy();
}
@Override
public LjfFilterErrorStrategy getErrorStrategy() {
return errorStrategy;
}
}
3、LjfFilterAuthStrategy
package com.ljf.framework.filter;
/**
* 全局过滤器-认证策略
*/
public interface LjfFilterAuthStrategy {
/**
* 执行方法
* @param r 无含义参数,留作扩展
*/
public boolean run(Object r);
}
4、LjfFilterErrorStrategy
package com.ljf.framework.filter;
/**
* 全局过滤器-异常处理策略
*/
public interface LjfFilterErrorStrategy {
/**
* 执行方法
* @param e 异常对象
* @return 输出对象(请提前序列化)
*/
public Object run(Throwable e);
}
5、LjfFilterManager
package com.ljf.framework.filter;
import com.ljf.framework.router.LjfRouterManager;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 说明:拦截器管理器
*
* @Auther: lijinfeng
* @Date: 2024/4/23
*/
public class LjfFilterManager {
private static boolean isInit = false;
private static List<LjfFilter> ljfFilterList = new ArrayList<>();
public static List<LjfFilter> getLjfFilterList() {
return ljfFilterList;
}
public static void addLjfFilter(LjfFilter ljfFilter) {
LjfFilterManager.ljfFilterList.add(ljfFilter);
}
public static boolean doLjfFilter() {
if(!isInit){
loadFilter();
isInit = true;
}
// 标记是否终止
AtomicBoolean suc = new AtomicBoolean(true);
for (LjfFilter filter : ljfFilterList) {
// 执行全局过滤器
LjfRouterManager.createRouter().match(filter.getIncludeList()).notMatch(filter.getExcludeList()).check(r -> {
try {
if (filter.getBeforeAuthStrategy().run(null)) {
boolean toRun = filter.getAuthStrategy().run(null);
if (!toRun){
suc.set(false);
}
}
} catch (Exception e) {
filter.getErrorStrategy().run(e);
suc.set(false);
}
});
if (!suc.get())
break;
}
return suc.get();
}
public static void loadFilter() {
ServiceLoader<LjfFilter> serviceLoader = ServiceLoader.load(LjfFilter.class);
//加载的是多个服务,遍历每个服务
for (LjfFilter service : serviceLoader) {
//取出一个服务,启动服务
LjfFilterManager.addLjfFilter(service);
}
// 拦截器排序
ljfFilterList.sort(Comparator.comparingInt(LjfFilter::getOrder));
}
public static void clearFilter() {
ljfFilterList.clear();
}
}
五、测试一下
1、启动类
package com.ljf.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 描述 :
* <p>
* 版本 作者 时间 内容
* 1.0 lijinfeng 2025-03-24 09:47 create
*/
@SpringBootApplication
public class LjfFilterTest {
public static void main(String[] args) {
SpringApplication.run(LjfFilterTest.class, args);
}
}
2、配置拦截器
package com.ljf.test;
import com.ljf.framework.filter.LjfFilterManager;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
/**
* 描述 :
* <p>
* 版本 作者 时间 内容
* 1.0 lijinfeng 2025-03-27 15:40 create
*/
@Component
@Order(-100)
public class MyServletFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 执行拦截器
boolean continueRun = LjfFilterManager.doLjfFilter();
if (!continueRun) return;
// 继续执行
filterChain.doFilter(servletRequest, servletResponse);
}
}
3、写个测试实现类
package com.ljf.test;
import com.ljf.framework.filter.LjfAbstractFilter;
import com.ljf.framework.filter.LjfFilterAuthStrategy;
import java.util.Arrays;
import java.util.List;
/**
* 描述 :
* <p>
* 版本 作者 时间 内容
* 1.0 lijinfeng 2025-03-27 15:44 create
*/
public class LjfFilterDemo extends LjfAbstractFilter{
@Override
protected List<String> setIncludeList() {
return Arrays.asList("/**");
}
@Override
protected List<String> setExcludeList() {
return Arrays.asList("/test/security/login");
}
@Override
protected LjfFilterAuthStrategy setBeforeAuth() {
return r -> {
System.out.println("是否需要执行拦截验证");
return true;
};
}
@Override
protected LjfFilterAuthStrategy setAuthStrategy() {
return r -> {
System.out.println("验证通过");
return true;
};
}
@Override
public Integer getOrder() {
return 0;
}
}
4、spi
com.ljf.test.LjfFilterDemo
5、查看效果
访问我们之前的登录接口,发现就没有输出我们设置的拦截日志。
访问退出接口,则显示了我们的拦截日志
到此我们想要的基本功能就有了,后面就需要继续完善更新了。