Spring 3 RequestMapping:获取路径值
Posted
技术标签:
【中文标题】Spring 3 RequestMapping:获取路径值【英文标题】:Spring 3 RequestMapping: Get path value 【发布时间】:2011-04-10 20:25:29 【问题描述】:requestMapping
@PathVariable
的值被解析后有没有办法得到完整的路径值?
即:
/id/restOfTheUrl
应该能够将/1/dir1/dir2/file.html
解析为id=1
和restOfTheUrl=/dir1/dir2/file.html
任何想法都将不胜感激。
【问题讨论】:
【参考方案1】:URL 的不匹配部分被暴露为名为@987654321@ 的请求属性:
@RequestMapping("/id/**")
public void foo(@PathVariable("id") int id, HttpServletRequest request)
String restOfTheUrl = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
...
【讨论】:
否,属性 HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE 包含整个匹配路径。 uthark 是对的。restOfTheUrl
中的值将是整个路径,而不仅仅是**
捕获的剩余部分
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE 是可选的,对于某些实现可能为 NULL 或 ""。 request.getRequestURI() 返回相同的值,不是可选的。
此解决方案不再有效且不可靠。【参考方案2】:
我使用 Tuckey URLRewriteFilter 来处理包含“/”字符的路径元素,因为我认为 Spring 3 MVC 还不支持它们。
http://www.tuckey.org/
您将此过滤器放入您的应用程序中,并提供一个 XML 配置文件。在该文件中,您提供了重写规则,您可以使用这些规则将包含“/”字符的路径元素转换为 Spring MVC 可以使用 @RequestParam 正确处理的请求参数。
WEB-INF/web.xml:
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<!-- map to /* -->
WEB-INF/urlrewrite.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite
PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
"http://tuckey.org/res/dtds/urlrewrite3.0.dtd">
<urlrewrite>
<rule>
<from>^/(.*)/(.*)$</from>
<to last="true">/$1?restOfTheUrl=$2</to>
</urlrewrite>
控制器方法:
@RequestMapping("/id")
public void handler(@PathVariable("id") int id, @RequestParam("restOfTheUrl") String pathToFile)
...
【讨论】:
【参考方案3】:刚刚发现与我的问题相对应的问题。使用 HandlerMapping 常量,我可以为此目的编写一个小实用程序:
/**
* Extract path from a controller mapping. /controllerUrl/** => return matched **
* @param request incoming request.
* @return extracted path
*/
public static String extractPathFromPattern(final HttpServletRequest request)
String path = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String bestMatchPattern = (String ) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
AntPathMatcher apm = new AntPathMatcher();
String finalPath = apm.extractPathWithinPattern(bestMatchPattern, path);
return finalPath;
【讨论】:
【参考方案4】:我有类似的问题,我是这样解决的:
@RequestMapping(value = "siteCode/**/fileName.fileExtension")
public HttpEntity<byte[]> getResource(@PathVariable String siteCode,
@PathVariable String fileName, @PathVariable String fileExtension,
HttpServletRequest req, HttpServletResponse response ) throws IOException
String fullPath = req.getPathInfo();
// Calling http://localhost:8080/SiteXX/images/argentine/flag.jpg
// fullPath conentent: /SiteXX/images/argentine/flag.jpg
请注意,req.getPathInfo()
将返回完整路径(带有siteCode
和fileName.fileExtension
),因此您必须方便地处理。
【讨论】:
这个答案并不比接受的答案差 - 它还返回完整路径,请参阅:javaee.github.io/javaee-spec/javadocs/javax/servlet/http/… 返回与客户端在发出此请求时发送的 URL 关联的任何额外路径信息。额外的路径信息在 servlet 路径之后,但在查询字符串之前,并以“/”字符开头。【参考方案5】:private final static String MAPPING = "/foo/*";
@RequestMapping(value = MAPPING, method = RequestMethod.GET)
public @ResponseBody void foo(HttpServletRequest request, HttpServletResponse response)
final String mapping = getMapping("foo").replace("*", "");
final String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
final String restOfPath = url.replace(mapping, "");
System.out.println(restOfPath);
private String getMapping(String methodName)
Method methods[] = this.getClass().getMethods();
for (int i = 0; i < methods.length; i++)
if (methods[i].getName() == methodName)
String mapping[] = methods[i].getAnnotation(RequestMapping.class).value();
if (mapping.length > 0)
return mapping[mapping.length - 1];
return null;
【讨论】:
【参考方案6】:是的,restOfTheUrl
不仅返回所需的值,但我们可以通过使用 UriTemplate
匹配来获取该值。
我已经解决了这个问题,所以这里是该问题的有效解决方案:
@RequestMapping("/id/**")
public void foo(@PathVariable("id") int id, HttpServletRequest request)
String restOfTheUrl = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
/*We can use UriTemplate to map the restOfTheUrl*/
UriTemplate template = new UriTemplate("/id/value");
boolean isTemplateMatched = template.matches(restOfTheUrl);
if(isTemplateMatched)
Map<String, String> matchTemplate = new HashMap<String, String>();
matchTemplate = template.match(restOfTheUrl);
String value = matchTemplate.get("value");
/*variable `value` will contain the required detail.*/
【讨论】:
【参考方案7】:这就是我的做法。您可以看到我如何将请求的URI 转换为文件系统路径(这个 SO 问题是关于什么的)。奖励:以及如何响应文件。
@RequestMapping(value = "/file/userId/**", method = RequestMethod.GET)
public void serveFile(@PathVariable("userId") long userId, HttpServletRequest request, HttpServletResponse response)
assert request != null;
assert response != null;
// requestURL: http://192.168.1.3:8080/file/54/documents/tutorial.pdf
// requestURI: /file/54/documents/tutorial.pdf
// servletPath: /file/54/documents/tutorial.pdf
// logger.debug("requestURL: " + request.getRequestURL());
// logger.debug("requestURI: " + request.getRequestURI());
// logger.debug("servletPath: " + request.getServletPath());
String requestURI = request.getRequestURI();
String relativePath = requestURI.replaceFirst("^/file/", "");
Path path = Paths.get("/user_files").resolve(relativePath);
try
InputStream is = new FileInputStream(path.toFile());
org.apache.commons.io.IOUtils.copy(is, response.getOutputStream());
response.flushBuffer();
catch (IOException ex)
logger.error("Error writing file to output stream. Path: '" + path + "', requestURI: '" + requestURI + "'");
throw new RuntimeException("IOError writing file to output stream");
【讨论】:
【参考方案8】:这已经在这里很长一段时间了,但发布了这个。可能对某人有用。
@RequestMapping( "/id/**" )
public void foo( @PathVariable String id, HttpServletRequest request )
String urlTail = new AntPathMatcher()
.extractPathWithinPattern( "/id/**", request.getRequestURI() );
【讨论】:
这段代码的问题是它不处理servlet前缀和映射前缀。【参考方案9】:你需要使用内置的pathMatcher
:
@RequestMapping("/id/**")
public void test(HttpServletRequest request, @PathVariable long id) throws Exception
ResourceUrlProvider urlProvider = (ResourceUrlProvider) request
.getAttribute(ResourceUrlProvider.class.getCanonicalName());
String restOfUrl = urlProvider.getPathMatcher().extractPathWithinPattern(
String.valueOf(request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)),
String.valueOf(request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)));
【讨论】:
确认这适用于最新版本的 Spring Boot 还确认此方法从 Spring Boot 2.2.4 RELEASE 开始有效。【参考方案10】:在Fabien Kruba's already excellent answer 的基础上,我认为如果URL 的**
部分可以通过注释作为参数提供给控制器方法会很好,其方式类似于@RequestParam
和@ 987654324@,而不是总是使用明确需要HttpServletRequest
的实用程序方法。所以这里有一个如何实现的例子。希望有人觉得它有用。
创建注释以及参数解析器:
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WildcardParam
class Resolver implements HandlerMethodArgumentResolver
@Override
public boolean supportsParameter(MethodParameter methodParameter)
return methodParameter.getParameterAnnotation(WildcardParam.class) != null;
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception
HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
return request == null ? null : new AntPathMatcher().extractPathWithinPattern(
(String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE),
(String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE));
注册方法参数解析器:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers)
resolvers.add(new WildcardParam.Resolver());
在控制器处理程序方法中使用注释可以轻松访问 URL 的 **
部分:
@RestController
public class SomeController
@GetMapping("/**")
public void someHandlerMethod(@WildcardParam String wildcardParam)
// use wildcardParam here...
【讨论】:
【参考方案11】:改进@Daniel Jay Marcaida 的回答
@RequestMapping( "/id/**" )
public void foo( @PathVariable String id, HttpServletRequest request )
String restOfUrl = new AntPathMatcher()
.extractPathWithinPattern(
request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString(),
request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString());
或
@RequestMapping( "/id/**" )
public void foo( @PathVariable String id, HttpServletRequest request )
String restOfUrl = new AntPathMatcher()
.extractPathWithinPattern(
request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString(),
request.getServletPath());
【讨论】:
以上是关于Spring 3 RequestMapping:获取路径值的主要内容,如果未能解决你的问题,请参考以下文章
Spring MVC 3 RequestMapping 与正则表达式量词
Spring MVC RequestMapping的使用方法
Spring,@Controller,@RequestMapping, @ResponseBody,@RequestParam