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>
所以我只是重写了 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;
它使用此处提到的 URL 架构简单地提取 contextPath 和 servletPath:https://theholyjava.wordpress.com/2014/03/24/httpservletrequest-requesturirequesturlcontextpathservletpathpathinfoquerystring/
此外,我必须提供一个自定义的getAlreadyFilteredAttributeName
方法,否则过滤器会被调用两次。 (这导致两次剥离contextPath
)
【讨论】:
以上是关于Spring Boot:注入自定义上下文路径的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Jhipster (spring boot + angular) 应用程序上设置上下文路径
在外部 tomcat 中定义 Spring Boot 应用程序的上下文路径
如何从 AWS API Gateway 自定义授权方检索 Spring Boot 中的上下文对象?