requestMapping
@PathVariable
値が解析された後に完全なパス値を取得する方法はありますか?
つまり:/{id}/{restOfTheUrl}
は/1/dir1/dir2/file.html
をid=1
とrestOfTheUrl=/dir1/dir2/file.html
に解析できるはずです
任意のアイデアをいただければ幸いです。
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);
...
}
ちょうど私の問題に対応する問題を見つけました。 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;
}
これはかなり前からありましたが、これを投稿しています。誰かに役立つかもしれません。
@RequestMapping( "/{id}/**" )
public void foo( @PathVariable String id, HttpServletRequest request ) {
String urlTail = new AntPathMatcher()
.extractPathWithinPattern( "/{id}/**", request.getRequestURI() );
}
組み込みの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 3 MVCがまだサポートしていないと思われるため、Tuckey URLRewriteFilterを使用して「/」文字を含むパス要素を処理しました。
このフィルターをアプリに配置し、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) {
...
}
はい、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.*/
}
}
Fabien Krubaのすでに優れた答え に基づいて、URLの**
部分がアノテーションを介してコントローラメソッドへのパラメータとして与えられればいいと思いましたHttpServletRequest
を明示的に必要とするユーティリティメソッドを常に使用するのではなく、@RequestParam
および@PathVariable
に似ていました。そのため、これを実装する方法の例を次に示します。うまくいけば誰かがそれを見つけてくれることでしょう。
引数リゾルバとともに注釈を作成します。
@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...
}
}
これが私がやった方法です。 requestedURIをファイルシステムパスに変換する方法を確認できます(この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");
}
}
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;
}