Send file path as #PathVariable in Spring MVC - java

There is a task to pass file path as #PathVariable in Spring MVC to REST Service with GET request.
We can easily do it with POST sending String of file path in JSON.
How we can do with GET request and #Controller like this?
#RequestMapping(value = "/getFile", method = RequestMethod.GET)
public File getFile(#PathVariable String path) {
// do something
}
Request:
GET /file/getFile/"/Users/user/someSourceFolder/8.jpeg"
Content-Type: application/json

You should define your controller like this:
#RequestMapping(value = "/getFile/{path:.+}", method = RequestMethod.GET)
public File getFile(#PathVariable String path) {
// do something
}

Ok.
you use to get pattern.
sending get pattern url.
Use #RequestParam.
#RequestMapping(value = "/getFile", method = RequestMethod.GET)
public File getFile(#RequestParam("path") String path) {
// do something
}
and if you use #PathVariable.
#RequestMapping(value = "/getFile/{path}", method = RequestMethod.POST)
public File getFile(#PathVariable String path) {
// do something
}

What I did works with relative paths to download/upload files in Spring.
#RequestMapping(method = RequestMethod.GET, path = "/files/**")
#NotNull
public RepositoryFile get(#PathVariable final String repositoryId,
#PathVariable final String branchName,
#RequestParam final String authorEmail,
HttpServletRequest request) {
String filePath = extractFilePath(request);
....
}
And the utilitary function I created within the controller :
private static String extractFilePath(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();
return apm.extractPathWithinPattern(bestMatchPattern, path);
}

Related

How to handle requests that contain forward slashes?

My URL request is http://localhost:8080/login/verify/212,32,/cntv5tag07rmy791wbme7xa8x,/SSNZclzqhhH7v6uHIkUsIcPusKo=
I need get the following part: **212,32,/cntv5tag07rmy791wbme7xa8x,/SSNZclzqhhH7v6uHIkUsIcPusKo=**.
The following code doesn't work:
#RequestMapping(value = "/login/verify/{request:.+}", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
public ResponseEntity verifyLogin(#PathVariable(value = "request") String request)
throws InvalidSignatureException
{
}
Error: HTTP Status 404.
Spring can't handle this request.
To match the uri with the slashes, use the double *
#RequestMapping(value = "/login/verify/**",
Then, in the body to get the value, you will use
String str = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)
Sample code:
#RequestMapping(value = "/login/verify/**", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
public ResponseEntity verifyLogin(HttpServletRequest httpServletRequest) throws InvalidSignatureException {
String str = (String) request.getAttribute( HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)
}
You have forward slashes in your url and those strings will be considered as path variables. Try the following code if there is a possibility that you'll have only 3 path variables. Please have a look at here and here
#RequestMapping(value = {"/login/verify/{string1:.+}",
"/login/verify/{string1:.+}/{string2:.+}",
"/login/verify/{string1:.+}/{string2:.+}/{string3:.+}"}, method = RequestMethod.POST)
public ResponseEntity verifyLogin(HttpServletRequest request, HttpServletResponse httpresponse,
#PathVariable("string1") String string1,
#PathVariable("string2") String string2,
#PathVariable("string3") String string3) {
System.out.println("***************************************************I am called: "+string1+" "+string2+" "+string3);
}
Try this URL instead: http://localhost:8080/login/verify?req=212,32,/cntv5tag07rmy791wbme7xa8x,/SSNZclzqhhH7v6uHIkUsIcPusKo=
And handle it like this:
#RequestMapping("/login/verify")
public String test(#RequestParam("req") String data) {
//'data' will contains '212,32,/cntv5tag07rmy791wbme7xa8x,/SSNZclzqhhH7v6uHIkUsIcPusKo='
String params[] = data.split(",");
}

How to send POST request to relative URL with RestTemplate?

How can I send a POST request to the application itself?
If I just send a relative post request: java.lang.IllegalArgumentException: URI is not absolute.
#RestController
public class TestServlet {
#RequestMapping("value = "/test", method = RequestMethod.GET)
public void test() {
String relativeUrl = "/posting"; //TODO how to generate like "localhost:8080/app/posting"?
new RestTemplate().postForLocation(relativeUrl, null);
}
}
So using the example above, how can I prefix the url with the absolute server url path localhost:8080/app? I have to find the path dynamically.
You can rewrite your method like below.
#RequestMapping("value = "/test", method = RequestMethod.GET)
public void test(HttpServletRequest request) {
String url = request.getRequestURL().toString();
String relativeUrl = url+"/posting";
new RestTemplate().postForLocation(relativeUrl, null);
}
Found a neat way that basically automates the task using ServletUriComponentsBuilder:
#RequestMapping("value = "/test", method = RequestMethod.GET)
public void test(HttpServletRequest req) {
UriComponents url = ServletUriComponentsBuilder.fromServletMapping(req).path("/posting").build();
new RestTemplate().postForLocation(url.toString(), null);
}
If you want to refresh application.properties, you should AutoWire the RefreshScope into you controller, and call it explicitly, it make it much easier to see what it going on.
Here is an example
#Autowired
public RefreshScope refreshScope;
refreshScope.refreshAll();

How to get a path variable that is the remainder of the path in Spring MVC?

How can I get my last path variable to be the remaining path? I have something like this, but it's not getting hit:
#RequestMapping(value = "{storageId}/{repositoryId}/{path}/**",
method = RequestMethod.PUT)
#RequestMapping(value = "{storageId}/{repositoryId}/{path}/**", method = RequestMethod.PUT)
public ResponseEntity upload(#PathVariable(name = "storageId") String storageId,
#PathVariable(name = "repositoryId") String repositoryId,
#PathVariable(name = "path") String path,
MultipartFile multipartFile)
throws ...
{
...
}
In Jersey, I could do it easily like this:
#Path("{storageId}/{repositoryId}/{path:.*}")
... but I have to migrate some code over to Spring MVC.
The problem is that if my URL is:
http://localhost:48080/storages/storage0/snapshots/org/foo/bar/metadata/metadata-foo/3.1-SNAPSHOT/metadata-foo-3.1-20161017.182007-1.jar
my path gets truncated to:
metadata/metadata-foo/3.1-SNAPSHOT/metadata-foo-3.1-20161017.182007-1.jar
Which is obviously incorrect, as it should be:
org/foo/bar/metadata/metadata-foo/3.1-SNAPSHOT/metadata-foo-3.1-20161017.182007-1.jar
Any advice would be welcome!
It's easy with the new(ish) matching algorithms that started to show up in Spring 5. You just use {*foo} as the path pattern.
#RequestMapping(value = "{storageId}/{repositoryId}/{path}/{*rest}",
method = RequestMethod.PUT)
public ResponseEntity upload(#PathVariable(name = "storageId") String storageId,
#PathVariable(name = "repositoryId") String repositoryId,
#PathVariable(name = "path") String path,
#PathVariable(name = "rest") String rest,
MultipartFile multipartFile)
throws ...
{
...
}
This works by default in Webflux. With MVC you have to switch on the PathPattern matcher with spring.mvc.pathmatch.matching-strategy=path_pattern_parser. I understand this will be the default in Spring Boot 2.6.
#RequestMapping(value = "{storageId}/{repositoryId}/{path}/**",
method = RequestMethod.PUT)
public ResponseEntity upload(#PathVariable(name = "storageId") String storageId,
#PathVariable(name = "repositoryId") String repositoryId,MultipartFile multipartFile,HttpServletRequest request)
throws ...
{
String restOfTheUrl = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
}

dynamic path to resource in springmvc

In Java-Jersey, it is possible to receive a dynamic path to a resource, e.g.
localhost:8080/webservice/this/is/my/dynamic/path
#GET
#Path("{dynamicpath : .+}")
#Produces(MediaType.APPLICATION_JSON)
public String get(#PathParam("dynamicpath") String p_dynamicpath) {
return p_dynamicpath;
}
prints out: this/is/my/dynamic/path
Question: how to do this in Spring MVC?
For multiple items inside your path you can access the dynamic path values like this:
#RequestMapping(value="/**", method = RequestMethod.GET)
public String get(HttpServletRequest request) throws Exception {
String dynPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
System.out.println("Dynamic Path: " + dynPath );
return dynPath;
}
If you know beforehand hoe many levels of path variables you'll have you can code them explicit like
#RequestMapping(value="/{path1}/{path2}/**", method = RequestMethod.GET)
public String get(#PathVariable("path1") String path1,
#PathVariable("path2") String path2,
HttpServletRequest request) throws Exception {
String dynPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
System.out.println("Dynamic Path: " + dynPath );
return dynPath;
}
If you want to see the String returned in your browser, you need to declare the method #ResponseBody as well (so the String you return is the content of your response):
#RequestMapping(value="/**", method = RequestMethod.GET, produces = "text/plain")
#ResponseBody
public String get(HttpServletRequest request) throws Exception {

Spring request mapping catching part of uri to PathVariable

I need something similar to enter link description here
So my path would be: /something/else/and/some/more
I would like to map it like so:
#RequestMapping(value="/something/**", method=RequestMethod.GET)
public String handleRequest(String theRestOfPath){ /***/ }
Or
#RequestMapping(value="/something/**", method=RequestMethod.GET)
public String handleRequest(String[] theRestOfPathArr){ /***/ }
The thing is ... I would like everything matched by ** to be passed to the method either:
1. as a string (theRestOfPath = "/else/and/some/more"),
2. or as an array (theRestOfPathArr = ["else","and","some","more"]).
The number of path variables can vary, so I can't do:
#RequestMapping(value="/something/{a}/{b}/{c}", method=RequestMethod.GET)
public String handleRequest(String a, String b, String c){ /***/ }
Is there a way to do that?
Thanks :)
---EDIT---
The solution I ended up with:
#RequestMapping(value = "/something/**", method = RequestMethod.GET)
#ResponseBody
public TextStory getSomething(HttpServletRequest request) {
final String URI_PATTERN = "^.*/something(/.+?)(\\.json|\\.xml)?$";
String uri = request.getRequestURI().replaceAll(URI_PATTERN, "$1");
return doSomethingWithStuff(uri);
}
If you include an HttpServletRequest as an argument to your method, then you can access the path being used. i.e.:
#RequestMapping(value="/something/**", method=RequestMethod.GET)
public String handleRequest(HttpServletRequest request){
String pattern = (String) request.getAttribute(
HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
String path = new AntPathMatcher()
.extractPathWithinPattern(pattern, request.getServletPath());
path = path.replaceAll("%2F", "/");
path = path.replaceAll("%2f", "/");
StringTokenizer st = new StringTokenizer(path, "/");
while (st.hasMoreElements()) {
String token = st.nextToken();
// ...
}
}
There's feature in spring MVC which will do parsing for you. Just use #PathVariable annotation.
Refer: Spring mvc #PathVariable

Categories