2015-05-27 2 views
3

Я запускаю приложение Spring Boot 1.2.3 со встроенным Tomcat.Весенняя загрузка: введите собственный путь к контексту

Я хотел бы ввести пользовательский contextPath для каждого запроса, основываясь на первой части URL-адреса.

Примеры:

  1. http://localhost:8080/foo имеет по умолчанию contextPath="" и должен получить contextPath="foo"

  2. http://localhost:8080/foo/bar имеет по умолчанию contextPath="" и должен получить contextPath="foo"

(URL, без пути должны остаться в есть)

Я попытался написать обычай javax.servlet.Filter с @Order(Ordered.HIGHEST_PRECEDENCE), но похоже, что я что-то упустил. Вот код:

@Component @Order(Ordered.HIGHEST_PRECEDENCE) 
public class MultiTenancyFilter implements Filter { 
    private final static Pattern pattern = Pattern.compile("^/(?<contextpath>[^/]+).*$"); 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     final HttpServletRequest req = (HttpServletRequest) request; 
     final String requestURI = req.getRequestURI(); 

     Matcher matcher = pattern.matcher(requestURI); 
     if(matcher.matches()) { 
      chain.doFilter(new HttpServletRequestWrapper(req) { 
       @Override 
       public String getContextPath() { 
        return "/"+matcher.group("contextpath"); 
       } 
      }, response); 
     } 
    } 

    @Override public void init(FilterConfig filterConfig) throws ServletException {} 
    @Override public void destroy() {} 
} 

Это должно просто взять строку после первого / и раньше (если таковые имеются) второй /, а затем использовать его в качестве возвращаемого значения для getContextPath().


Но весна @Controller @RequestMapping и Spring Security-х antMatchers("/"), кажется, не уважает его. Оба по-прежнему работают как contextPath="".


Как я могу динамически переопределить путь контекста для каждого запроса?

ответ

1

Получил это!

документы

Spring Security (http://docs.spring.io/spring-security/site/docs/3.1.x/reference/security-filter-chain.html) говорят:. «Spring Security заинтересован только в обеспечении путей в приложении, поэтому contextPath игнорируется К сожалению, сервлет спецификации не определяет, какие именно значения servletPath и Pathinfo будет содержать для конкретного запроса URI. [...] Стратегия реализована в классе AntPathRequestMatcher, который использует AntPathMatcher Spring для выполнения нечувствительного к регистру совпадения шаблона с конкатенированным servletPath и pathInfo, игнорируя queryString. "

Так что я просто переопределял servletPath и contextPath (даже если он не используется Spring Security). Кроме того, я добавил небольшую переадресацию, потому что обычно при ударе http://localhost:8080/myContext вы перенаправляетесь на http://localhost:8080/myContext/, а Spring Securities Ant Matcher не любит отсутствующую конечную косую черту.

Так вот мой MultiTenancyFilter код:

@Component @Order(Ordered.HIGHEST_PRECEDENCE) 
public class MultiTenancyFilter extends OncePerRequestFilter { 
    private final static Pattern pattern = Pattern.compile("^(?<contextPath>/[^/]+)(?<servletPath>.*)$"); 

    @Override 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 
     Matcher matcher = pattern.matcher(request.getServletPath()); 
     if(matcher.matches()) { 
      final String contextPath = matcher.group("contextPath"); 
      final String servletPath = matcher.group("servletPath"); 

      if(servletPath.trim().isEmpty()) { 
       response.sendRedirect(contextPath+"/"); 
       return; 
      } 

      filterChain.doFilter(new HttpServletRequestWrapper(request) { 
       @Override 
       public String getContextPath() { 
        return contextPath; 
       } 
       @Override 
       public String getServletPath() { 
        return servletPath; 
       } 
      }, response); 
     } else { 
      filterChain.doFilter(request, response); 
     } 
    } 

    @Override 
    protected String getAlreadyFilteredAttributeName() { 
     return "multiTenancyFilter" + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX; 
    } 
} 

Он просто извлекает contextPath и servletPath с помощью URL-схемы упомянутого здесь: https://theholyjava.wordpress.com/2014/03/24/httpservletrequest-requesturirequesturlcontextpathservletpathpathinfoquerystring/

Кроме того, я должен был предоставить способ пользовательского getAlreadyFilteredAttributeName, потому что еще фильтр вызвали дважды. (Это привело к зачистке contextPath дважды)

Смежные вопросы