Pit mining and the use of @WebFilter

@WebFilter
@WebFilter for a class declaration for the filter, the annotation will be processed at the time of the deployment vessel, the vessel will be deployed as the corresponding class according to the specific properties of the filter configuration. The annotation has taken some common attributes given in the following table (all of the following properties are optional, but the value, urlPatterns, servletNames three must contain at least one, and can not coexist urlPatterns value and, if specified, a value of generally negligible value):

Table 3. @WebFilter common properties of

 

 

 

The following is a simple example:

@WebFilter(servletNames = {"SimpleServlet"},filterName="SimpleFilter") 
public class LessThanSixFilter implements Filter{...}

 

After such configuration, it may not be necessary to configure the corresponding <filter> and <filter-mapping> element in web.xml, the container will be released during deployment of the filter in accordance with the class specified attributes. Configurations in web.xml is equivalent to:

<filter> 
  <filter-name>SimpleFilter</filter-name> 
  <filter-class>xxx</filter-class> 
</filter> 
<filter-mapping> 
  <filter-name>SimpleFilter</filter-name> 
  <servlet-name>SimpleServlet</servlet-name> 
</filter-mapping>

 

Seen from above, the configuration is equivalent to using the web.xml @WebFilter, now with automatic generation Filter eclipse, the default is to provide this annotation, as follows

package webcase;
 
import java.io.IOException;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
 
/**
 * Servlet Filter implementation class CountFilter
 */
@WebFilter("/CountFilter")
public class CountFilter implements Filter {
    private int count;
    private String param;
    private FilterConfig fConfig;
    /**
     * Default constructor.
     */
    /*public CountFilter() {
        // TODO Auto-generated constructor stub
    }*/
 
    /**
     * @see Filter#destroy()
     */

We know, tomcat The <filter-mapping> sequence initialization Filter, since the above code comprises @WebFilter ( "/ CountFilter"), corresponds to the same in web.xml filter is provided twice CountFilter <filter> and <filter-mapping>, it initializes the filter twice, so when the filter is disposed @WebFilter initialized, string string param = getInitParameter ( "count") obtained is empty, call Integer.parseInt (param) when triggered NumberFormatException. After removing the @WebFilter ( "/ CountFilter") everything is normal.

Pit record:

Business needs Background:
Project micro-service architecture, configure a gateway in front of each service, implemented by SpringCloud Ecology Zuul components.
The gateway is also responsible for paging, scheduling between pages each single page application sub-products.
ZuulFilter quite interesting, the Service Controller for the request will not be intercepted, it is necessary to do a certification for the authentication page request Filter.

The first edition achieve
first implement a Filter authenticate and redirect the page (under the unregistered state certification to jump to the login page).
General logic is as follows:
① Filter be declared by WebFilter, so that the container will be processed during the deployment of the Filter, create an instance of an object and create the configuration FilterConfig, then the Filter is applied to urlPatterns designated URL;
② the method in the init obtains initialization parameters, custom excludedUrls, when used as a member performing the subsequent filtering logic;
③ url identified in doFilter, the authentication process if the authentication needs to be performed, respective logic is performed. The condition is not satisfied redirected to the login page;
④Filter increase the Component class notes, so that the Filter managed container.

@Component // add this right?
@WebFilter(filterName = "WebAuthFilter", urlPatterns = "/web/*",
        initParams = {
            @WebInitParam(name = "excludedUrls", value = "/web/login")
        }
)
public class WebAuthFilter implements Filter {

    private List<String> excludedUrlList;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String excludedUrls = filterConfig.getInitParameter("excludeUrls");
        excludedUrlList = Splitter.on(",").omitEmptyStrings().splitToList(excludedUrls);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String url = ((HttpServletRequest) request).getRequestURI();
        if (excludedUrlList.contains(url)) {
            chain.doFilter(request, response);
        } else {
            String sToken = ((HttpServletRequest) request).getHeader("Authorization");
            if (sToken != null) {
                Map<String, Object> map = TokenUtils.parseToken(sToken);
                if (map == null) {
                    ((HttpServletResponse)response).sendRedirect("/web/login");
                }
            } else {
                ((HttpServletResponse)response).sendRedirect("/web/login");
            }
        }
    }

    @Override
    public void destroy() {

    }
}

Then add annotations @ServletComponentScan SpringBoot in the Application, so that the container will be scanned annotations @Component Filter.

Problems
question that arises is: url to access / user / * or / product / * when the filter also performed!
In other words, WebFilter annotation configuration urlPatterns did not work.
Locate the problem:
In view of the container to start the log, I found WebAuthFilter was registered twice, twice map:

 

 

 

You can see from the chart, WebAuthFilter this Filter is our own definition, it was made twice mapping, and mapping of the two different names (WebAuthFilter and webAuthFilter), are mapped to the URL is "/ web / *" and "" / * ". WebAuthFilter which is named after our own.
this explains why all of the URL will be processed Filter.

Locate the problem
WebAuthFilter first mapping is easy to understand, through our own @WebFilter defined.
So webAuthFilter who gave mapped it?
Spring container must be handled.
Found in trace the source when AbstractFilterRegistrationBean abstract class, the class has a method onStartup, should be performed when the vessel started, do some Bean registration work. The last method called configure, the mapping process carried out in the process.

if (servletNames.isEmpty() && this.urlPatterns.isEmpty()) {
            this.logger.info("Mapping filter: '" + registration.getName() + "' to: "
                    + Arrays.asList(DEFAULT_URL_MAPPINGS));
            registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,
                    DEFAULT_URL_MAPPINGS);
        }
        else {
            if (!servletNames.isEmpty()) {
                this.logger.info("Mapping filter: '" + registration.getName()
                        + "' to servlets: " + servletNames);
                registration.addMappingForServletNames(dispatcherTypes, this.matchAfter,
                        servletNames.toArray(new String[servletNames.size()]));
            }
            if (!this.urlPatterns.isEmpty()) {
                this.logger.info("Mapping filter: '" + registration.getName()
                        + "' to urls: " + this.urlPatterns);
                registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,
                        this.urlPatterns.toArray(new String[this.urlPatterns.size()]));
            }
        }

In the case of empty urlPatterns servletNames and performs default mapping that maps to "/ *."
Placed in the case servletNames and urlPatterns is empty, there is no get to the bottom.
Why, then, would appear to be the case definition WebAuthFilter twice registered it?
A careful analysis of what that reason might be: @Component and dual registration @WebFilter caused.

Solution
Solution a @WebFilter
In this case, remove the @Component notes, start the service again. View the log and found that the Filter is mapped only once, corresponding url visit through the browser also performed correctly.

Solution two @Component
this case, the retains @Component notes, then to configure the urlPatterns how to deal with it?
@Bean statement carried by FilterRegistrationBean, view the source code to know when onStartup register, and indeed find a variety of RegistrationBean then registered separately, configure the mapping.
There are various types of RegistrationBean:
①AbstractFilterRegistrationBean;
②FilterRegistrationBean;
③ServletListenerRegistrationBean;
④ServletRegistrationBean;
then we naturally a FilterRegistrationBean to register by self-declaration. This approach is as follows:
remove the annotations on @WebFilter FIlter, add the following classes Configuration:

@Configuration
public class WebAuthFilterConfig {

    @Bean
    public FilterRegistrationBean webAuthFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(webAuthFilter());
        registration.setName("WebAuthFilter");
        registration.addUrlPatterns("/web/*");
        registration.addInitParameter("excludeUrls", "/web/login");
        registration.setOrder(0);
        return registration;
    }

    @Bean
    public Filter webAuthFilter() {
        return new WebAuthFilter();
    }
}

So treated, it can achieve the same effect.

By comparison, of course, the first solution is more straightforward, more concise.

Later: the Internet is a lot of things with a pit directly move over a really risky!

Reference links:

https://blog.csdn.net/weixin_42114097/article/details/81530628

https://blog.csdn.net/achang07/article/details/79282789

 

Guess you like

Origin www.cnblogs.com/muxi0407/p/11950627.html