四十九、SpingBoot引入第三方filter

最近手头活不多,被其他项目拉去帮忙。他们的需求是,项目中需要加入第三方的过滤器(用于单点登录认证的),项目采用的是spring boot,spring boot之前没深入玩过,所以费了些时间。

需求:

    第三方提供了一个filter以及使用标准web.xml时的配置方法,要求整合到项目中

过程:

    第一步:

    作为不百度(google)不会写代码的程序员,第一反应是去baidu一下,毕竟spring boot的使用停留在写web api的码砖水平上。百度结果,大部分都是用类似下面的方法:

    @Bean
    public FilterRegistrationBean pluginFilter(){
        //将第三方filter实例,配置信息设置到一个FilterRegistrationBean中

        //详细代码省略,网上到处都是
    }

    优点在于:简单。

    缺点:这种第三方的filter,如果是多个的,每个都得重新加这种方法,对于扩展来说,啰嗦

    于是,寻求spring boot项目直接使用web.xml里过滤器配置的方案,百度了好些,都是直接将spring boot项目变为使用web.xml配置的,这个动作有点大,怕把项目给搞乱了,没敢采用。。。

     第二步:

     目标明确为,使用Bean标签返回FilterRegistrationBean(或类似的接口实例)的方向,但是这个Bean要能将多个过滤器注册给spring。稍微读了一下源码,发现FilterRegistrationBean这个鬼,这正起作用的是定义在AbstractFilterRegistrationBean中的方法onStartup方法

public void onStartup(ServletContext servletContext) throws ServletException {
    Filter filter = this.getFilter();
    Assert.notNull(filter, "Filter must not be null");
    String name = this.getOrDeduceName(filter);
    if (!this.isEnabled()) {
        this.logger.info("Filter " + name + " was not registered (disabled)");
    } else {
        Dynamic added = servletContext.addFilter(name, filter);
        if (added == null) {
            this.logger.info("Filter " + name + " was not registered (possibly already registered?)");
        } else {
            this.configure(added);
        }
    }
}

    所以,咱们重写一下这个onStartup方法(类名后缀用的proxy可能不太合适,请不要在意细节):

package com.xxx.common.filter;

import org.dom4j.Document;
import org.dom4j.Element;
import org.springframework.boot.web.servlet.FilterRegistrationBean;

import javax.servlet.Filter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class XxxFilterRegistrationBeanProxy extends FilterRegistrationBean{
    private Document plugin_xml = null;

    //所有需要注册的filter
    private Map<String,FilterRegistrationBean> filterRegistrationBeans;

    public IdssFilterRegistrationBeanProxy() {
    }

    public Document getPlugin_xml() {
        return plugin_xml;
    }

    public void setPlugin_xml(Document plugin_xml) {
        this.plugin_xml = plugin_xml;
    }

    public IdssFilterRegistrationBeanProxy(Document plugin_xml) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        super();
        this.plugin_xml = plugin_xml;
        setFilterRegistrationBeans();
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        if(filterRegistrationBeans == null || filterRegistrationBeans.size()==0) return;
        //执行实际的FilterRegistrationBean的onStartup方法
        for(FilterRegistrationBean bean : filterRegistrationBeans.values()){
            bean.onStartup(servletContext);
        }
    }

    private void setFilterRegistrationBeans() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //读取xml配置文件,实例化FilterRegistrationBean
        if(plugin_xml == null) return;
        filterRegistrationBeans = new HashMap<>();
        Element root = plugin_xml.getRootElement();
        Iterator<Element> filter_roots = root.elementIterator("filter");
        int order = 0;
        while (filter_roots.hasNext()){
            order++;
            Element filter_root = filter_roots.next();
            String filter_name = filter_root.elementText("filter-name").trim();
            String class_name = filter_root.elementText("filter-class").trim();
            Filter filter = (Filter) Class.forName(class_name).newInstance();

            FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
            filterRegistrationBean.setFilter(filter);
            filterRegistrationBean.setName(filter_name);
            filterRegistrationBean.setOrder(order);
            Iterator<Element> parm_settings = filter_root.elementIterator("init-param");
            while (parm_settings.hasNext()){
                Element parm = parm_settings.next();
                filterRegistrationBean.addInitParameter(parm.elementText("param-name").trim(),parm.elementText("param-value").trim());
            }
            filterRegistrationBeans.put(filter_name,filterRegistrationBean);
        }
        Iterator<Element> filter_mappings = root.elementIterator("filter-mapping");
        while (filter_mappings.hasNext()){
            Element filter_mapping = filter_mappings.next();
            String filter_name = filter_mapping.elementText("filter-name");
            if(filterRegistrationBeans.containsKey(filter_name)){
                filterRegistrationBeans.get(filter_name).addUrlPatterns(filter_mapping.elementText("url-pattern"));
            }
        }
    }
}

注入spring boot的单例类中,给出一个Bean注解的方法,返回上面类的实例

package com.xxx.common.filter;

import com.xxx.common.utils.PropertyUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStreamReader;


@Component
public class XxxPluginFilter {

    private XxxFilterRegistrationBeanProxy XxxFilterRegistrationBeanProxy = new XxxFilterRegistrationBeanProxy();
    private Document plugin_xml = null;

    private final static String plugin_filter_path = PropertyUtil.getProperty("plugin_filter_path");


    @Bean
    public FilterRegistrationBean pluginFilter(){
        return XxxFilterRegistrationBeanProxy;
    }


    @PostConstruct
    private void init() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        if(plugin_filter_path == null || plugin_filter_path.isEmpty()) return;
        SAXReader reader = new SAXReader();
        InputStreamReader inputStreamReader = null;
        try {
            inputStreamReader = new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream(plugin_filter_path));
            plugin_xml = reader.read(inputStreamReader);
            xxxFilterRegistrationBeanProxy = new XxxFilterRegistrationBeanProxy(plugin_xml);
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            if(inputStreamReader != null) {
                try {
                    inputStreamReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

filter的xml配置文件示例:

<?xml version="1.0" encoding="UTF-8"?>
<plugin-filter>
   <filter>
        <filter-name>filter1</filter-name>
        <filter-class>
            com.test.Filter1
        </filter-class>
        <init-param>
            <param-name>servername</param-name>
            <param-value>http://localhost:8081</param-value>
        </init-param>
    </filter>
   <filter>
        <filter-name>filter2</filter-name>
        <filter-class>
            com.test.Filter2
        </filter-class>
        <init-param>
            <param-name>initteset</param-name>
            <param-value>yyyy</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <!-- 需要过滤的路径和文件类型 -->
        <filter-name>filter1</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>filter2</filter-name>
        <url-pattern>/api/*</url-pattern>
    </filter-mapping>
</plugin-filter>

简单粗暴而有效

猜你喜欢

转载自blog.csdn.net/u010285974/article/details/85285656
今日推荐