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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 04:08:01  来源:igfitidea点击:

Spring 3 RequestMapping: Get path value

springspring-mvcrequest-mapping

提问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.htmlid=1restOfTheUrl=/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 还不支持它们。

http://www.tuckey.org/

http://www.tuckey.org/

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}),因此您必须方便地进行处理。