过滤器 Filter
前置参考:
过滤器(最外层的 web 过滤或拦截,范围包括了静态文档),可用于全局,也可用于局部(Local gateway、Action)。
1、接口声明
package org.noear.solon.core.handle;
@FunctionalInterface
public interface Filter {
    /**
     * 过滤
     *
     * @param ctx 上下文
     * @param chain 过滤器调用链
     * */
    void doFilter(Context ctx, FilterChain chain) throws Throwable;
}
2、应用范围
- 全局过滤
@Component
public class DemoFilter1 implements Filter { ... }
- 本地网关过滤
public class DemoFilter2 implements Filter { ... }
@Component
@Mapping("/api/v2/**")
public class DemoLocalGateway2 extends Gateway {
    @Override
    protected void register() {
        filter(new DemoFilter2());
        ...
    }
}
- 动作过滤(“@Addition” 可参考:@Addition 使用说明(AOP))
public class DemoFilter31 implements Filter { ... }
public class DemoFilter32 implements Filter { ... }
public class DemoFilter33 implements Filter { ... }
//可加在类上
@Addition(DemoFilter31.class)
@Controller
public class DemoController3 {
    //可加在方法上
    @Addition(DemoFilter32.class)
    @Mapping("hello")
    public String hello(){
        ...
    }
}
//或者使用注解别名(用一个新注解,替代 "@Addition(DemoFilter33.class)")
@Addition(DemoFilter33.class)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Whitelist {
}
//可加在类上
@Whitelist
@Controller
public class DemoController3 {
    //可加在方法上
    @Whitelist
    @Mapping("hello")
    public String hello(){
        ...
    }
}
3、定制参考1:
public class I18nFilter implements Filter {
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        //尝试自动完成地区解析
        I18nUtil.getLocaleResolver().getLocale(ctx);
        chain.doFilter(ctx);
    }
}
4、定制参考2:
public class ContextPathFilter implements Filter {
    private final String contextPath0;
    private final String contextPath1;
    private final boolean forced;
    public ContextPathFilter() {
        this(Solon.cfg().serverContextPath(), Solon.cfg().serverContextPathForced());
    }
    /**
     * @param contextPath '/demo/'
     */
    public ContextPathFilter(String contextPath, boolean forced) {
        this.forced = forced;
        if (Utils.isEmpty(contextPath)) {
            contextPath0 = null;
            contextPath1 = null;
        } else {
            String newPath = null;
            if (contextPath.endsWith("/")) {
                newPath = contextPath;
            } else {
                newPath = contextPath + "/";
            }
            if (newPath.startsWith("/")) {
                this.contextPath1 = newPath;
            } else {
                this.contextPath1 = "/" + newPath;
            }
            this.contextPath0 = contextPath1.substring(0, contextPath1.length() - 1);
            //有可能是 ContextPathFilter 是用户手动添加的!需要补一下配置
            Solon.cfg().serverContextPath(this.contextPath1);
        }
    }
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        if (contextPath0 != null) {
            if (ctx.pathNew().equals(contextPath0)) {
                //www:888 加 abc 后,仍可以用 www:888/abc 打开
                ctx.pathNew("/");
            } else if (ctx.pathNew().startsWith(contextPath1)) {
                ctx.pathNew(ctx.pathNew().substring(contextPath1.length() - 1));
            } else {
                if (forced) {
                    ctx.status(404);
                    return;
                }
            }
        }
        chain.doFilter(ctx);
    }
}
 Solon
 Solon