孝感网站建设软件网站建设服务协议 百度
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();/*** 获取 [拦截路由] 集合*/@Overridepublic List<String> getIncludeList() {return this.setIncludeList();}/*** 获取 [放行路由] 集合*/@Overridepublic 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());};@Overridepublic LjfFilterAuthStrategy getBeforeAuthStrategy() {return this.setBeforeAuth();}@Overridepublic LjfFilterAuthStrategy getAuthStrategy() {return this.setAuthStrategy();}@Overridepublic 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 {@Overridepublic 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{@Overrideprotected List<String> setIncludeList() {return Arrays.asList("/**");}@Overrideprotected List<String> setExcludeList() {return Arrays.asList("/test/security/login");}@Overrideprotected LjfFilterAuthStrategy setBeforeAuth() {return r -> {System.out.println("是否需要执行拦截验证");return true;};}@Overrideprotected LjfFilterAuthStrategy setAuthStrategy() {return r -> {System.out.println("验证通过");return true;};}@Overridepublic Integer getOrder() {return 0;}
}
4、spi
com.ljf.test.LjfFilterDemo
5、查看效果
访问我们之前的登录接口,发现就没有输出我们设置的拦截日志。
访问退出接口,则显示了我们的拦截日志
到此我们想要的基本功能就有了,后面就需要继续完善更新了。