Spring Boot:注入自定义上下文路径

Posted

技术标签:

【中文标题】Spring Boot:注入自定义上下文路径【英文标题】:Spring Boot: Inject a custom context path 【发布时间】:2015-08-09 20:08:48 【问题描述】:

我正在运行一个带有嵌入式 Tomcat 的 Spring Boot 1.2.3 应用程序。

我想根据 URL 的第一部分在每个请求上注入一个自定义 contextPath。

例子:

    http://localhost:8080/foo 默认有contextPath="",应该得到contextPath="foo"

    http://localhost:8080/foo/bar 默认有contextPath="",应该得到contextPath="foo"

(没有路径的 URL 应该保持原样)

我尝试用@Order(Ordered.HIGHEST_PRECEDENCE) 编写自定义javax.servlet.Filter,但似乎我缺少了一些东西。代码如下:

@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() 的返回值。


但是 Spring @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 被忽略。不幸的是,servlet 规范没有准确定义 servletPath 和pathInfo 将包含特定请求的 URI。[...] 该策略在 AntPathRequestMatcher 类中实现,该类使用 Spring 的 AntPathMatcher 对连接的 servletPath 和 pathInfo 执行不区分大小写的模式匹配,忽略 queryString。" em>

所以我只是重写了 servletPathcontextPath(即使 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;
    

它使用此处提到的 URL 架构简单地提取 contextPath 和 servletPath:https://theholyjava.wordpress.com/2014/03/24/httpservletrequest-requesturirequesturlcontextpathservletpathpathinfoquerystring/

此外,我必须提供一个自定义的getAlreadyFilteredAttributeName 方法,否则过滤器会被调用两次。 (这导致两次剥离contextPath

【讨论】:

以上是关于Spring Boot:注入自定义上下文路径的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Jhipster (spring boot + angular) 应用程序上设置上下文路径

在外部 tomcat 中定义 Spring Boot 应用程序的上下文路径

将单例注入 Spring Boot 应用程序上下文

如何从 AWS API Gateway 自定义授权方检索 Spring Boot 中的上下文对象?

带有 testcontainers 和 jOOQ 的 Spring Boot 不会注入 DSL 上下文

spring boot 动态注入bean