Spring 3 RequestMapping:获取路径值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3686808/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring 3 RequestMapping: Get path value
提问by Spring Monkey
Is there a way to get the complete path value after the requestMapping@PathVariablevalues have been parsed?
有没有办法requestMapping@PathVariable在解析完值后获得完整的路径值?
That is:
/{id}/{restOfTheUrl}should be able to parse /1/dir1/dir2/file.htmlinto id=1and restOfTheUrl=/dir1/dir2/file.html
那就是:
/{id}/{restOfTheUrl}应该能够解析/1/dir1/dir2/file.html成id=1和restOfTheUrl=/dir1/dir2/file.html
Any ideas would be appreciated.
任何想法,将不胜感激。
回答by axtavt
Non-matched part of the URL is exposed as a request attribute named HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE:
URL 的不匹配部分作为名为 的请求属性公开HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE:
@RequestMapping("/{id}/**")
public void foo(@PathVariable("id") int id, HttpServletRequest request) {
String restOfTheUrl = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
...
}
回答by Fabien Kruba
Just found that issue corresponding to my problem. Using HandlerMapping constants I was able to wrote a small utility for that purpose:
刚刚发现与我的问题相对应的问题。使用 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;
}
回答by Daniel Jay Marcaida
This has been here quite a while but posting this. Might be useful for someone.
这已经在这里很长一段时间了,但张贴这个。可能对某人有用。
@RequestMapping( "/{id}/**" )
public void foo( @PathVariable String id, HttpServletRequest request ) {
String urlTail = new AntPathMatcher()
.extractPathWithinPattern( "/{id}/**", request.getRequestURI() );
}
回答by thejonwithnoh
Building upon Fabien Kruba's already excellent answer, I thought it would be nice if the **portion of the URL could be given as a parameter to the controller method via an annotation, in a way which was similar to @RequestParamand @PathVariable, rather than always using a utility method which explicitly required the HttpServletRequest. So here's an example of how that might be implemented. Hopefully someone finds it useful.
基于Fabien Kruba 已经很好的答案,我认为如果**URL的部分可以通过注释作为控制器方法的参数以类似于@RequestParamand 的方式提供@PathVariable,而不是总是使用实用程序方法,那就太好了其中明确要求HttpServletRequest. 下面是一个如何实施的示例。希望有人觉得它有用。
Create the annotation, along with the argument resolver:
创建注释以及参数解析器:
@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));
}
}
}
Register the method argument resolver:
注册方法参数解析器:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new WildcardParam.Resolver());
}
}
Use the annotation in your controller handler methods to have easy access to the **portion of the URL:
使用控制器处理程序方法中的注释可以轻松访问**URL 部分:
@RestController
public class SomeController {
@GetMapping("/**")
public void someHandlerMethod(@WildcardParam String wildcardParam) {
// use wildcardParam here...
}
}
回答by Grim
You need to use built-in pathMatcher:
您需要使用内置的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)));
回答by sdouglass
I have used the Tuckey URLRewriteFilter to handle path elements that contain '/' characters, as I don't think Spring 3 MVC supports them yet.
我已经使用 Tuckey URLRewriteFilter 来处理包含 '/' 字符的路径元素,因为我认为 Spring 3 MVC 还不支持它们。
You put this filter in to your app, and provide an XML config file. In that file you provide rewrite rules, which you can use to translate path elements containing '/' characters into request parameters that Spring MVC can deal with properly using @RequestParam.
您将此过滤器放入您的应用程序,并提供一个 XML 配置文件。在该文件中,您提供了重写规则,您可以使用这些规则将包含“/”字符的路径元素转换为 Spring MVC 可以使用 @RequestParam 正确处理的请求参数。
WEB-INF/web.xml:
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:
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">/?restOfTheUrl=</to>
</urlrewrite>
Controller method:
控制器方法:
@RequestMapping("/{id}")
public void handler(@PathVariable("id") int id, @RequestParam("restOfTheUrl") String pathToFile) {
...
}
回答by Anil Kumar Pandey
Yes the restOfTheUrlis not returning only required value but we can get the value by using UriTemplatematching.
是的,restOfTheUrl它不仅返回所需的值,而且我们可以通过使用UriTemplate匹配来获取该值。
I have solved the problem, so here the working solution for the problem:
我已经解决了这个问题,所以这里是这个问题的有效解决方案:
@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.*/
}
}
回答by neoneye
Here is how I did it. You can see how I convert the requestedURI to a filesystem path (what this SO question is about). Bonus: and also how to respond with the file.
这是我如何做到的。您可以看到我如何将请求的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");
}
}
回答by xsampedro
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;
}
回答by Nico's
I have a similar problem and I resolved in this way:
我有一个类似的问题,我是这样解决的:
@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
}
Note that req.getPathInfo()will return the complete path (with {siteCode}and {fileName}.{fileExtension}) so you will have to process conveniently.
请注意,这req.getPathInfo()将返回完整路径(带有{siteCode}和{fileName}.{fileExtension}),因此您必须方便地进行处理。

