I was working on a file upload widget for managing images.
I wish that image paths can be received via #PathVariable in Spring MVC, such as http://localhost:8080/show/img/20181106/sample.jpg instead of http://localhost:8080/show?imagePath=/img/20181106/sample.jpg.
But / will be resolved Spring MVC, and it will always return 404 when accessing.
Is there any good way around this?
You can use like below.
#RequestMapping(value = "/show/{path:.+}", method = RequestMethod.GET)
public File getImage(#PathVariable String path) {
// logic goes here
}
Here .+ is a regexp match, it will not truncate .jpg in your path.
Sorry to say that, but I think the answer of #Alien does not the answer the question : it only handle the case of a dot . in the #PathVariable but not the case of slashes /.
I had the problem once and here is how I solved it, it's not very elegant but stil ok I think :
private AntPathMatcher antPathMatcher = new AntPathMatcher();
#GetMapping("/show/**")
public ... image(HttpServletRequest request) {
String uri = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
String path = antPathMatcher.extractPathWithinPattern(pattern, uri);
...
}
Related
I would like to specify get request only for /show-owner/{id}, but every time there is another path added to URL I get 404 not found error and I have to give full path to make it work.
What is the best approach in such cases ?
#GetMapping(value = {"/show-owner/{id}", "/show-item/show-owner/{id}",
"/show-user/user-items-table/show-item/show-owner/{id}",
"/show-user/user-items-table/show-item/show-owner/user-items-table/{id}",
"/show-owner/user-items-table/show-item/show-owner/{id}",
"/user-items-table/show-item/show-owner/{id}"})
public ModelAndView displayOwnerByItemId(#PathVariable String id) {
try {
UserDto user = userDtoMapper.toDto(itemService.getItemById(id).getOwner());
ModelAndView mav = new ModelAndView("show-user");
mav.addObject("user", user);
return mav;
} catch (ItemNotFound e) {
return new ModelAndView("redirect:/items");
}
}
Maybe you are using the wrong url in your HTML form
for example...
<form action="show-owner/{id}">
be sure your URL is correct. It should be
<form action="/show-owner/{id}">
you can do one thing if you want just the last id from the path variable. You will be getting the ids in comma separated string. So the simplest solution will be to split the string based on the comma and get the value of last index like this.
String k[] = id.split(",");
System.out.println(k[k.length-1]);//just to check whether u are getting the last id value or not
Let me know if this helps.
In Spring Boot 1.5.4 I have a request mapping like this:
#RequestMapping(value = "/graph/{graphId}/details/{iri:.+}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public JSONObject getGraph(#PathVariable Long graphId,
#PathVariable String iri) {
log.debug("Details called for graph ID {} for IRI {}", graphId, iri);
return detailsService.getDetails(graphId, iri);
}
Accessing
http://localhost:9000/api/v1/graph/2/details/http%3Anthnth33
works fine and the server maps the request correctly and the code returns the expected result
But accessing
http://localhost:9000/api/v1/graph/2/details/http%3A%2F%2Fserverurl.net%2Fv1%2Fus%2Fh.schumacher%408tsch.net%2Fn%2FLouSchumacher
gives a bad server request (Failed to load resource: the server responded with a status of 400 (Bad Request)). The request mapping to the end point isn't even done in that case.
Obviously the slash '/' encoded as %2F (using encodeURIComponent()) causes trouble. Why? What am I missing? How should uri parameter then be encoded?
The question is not only about how to extract PathVariables but more on how to force String to recognize the correct mapping.
The issue with your example is how Spring is doing path matching. The URL you have provided as example
http://localhost:9000/api/v1/graph/2/details/http%3A%2F%2Fserverurl.net%2Fv1%2Fus%2Fh.schumacher%408tsch.net%2Fn%2FLouSchumacher
will be decoded into by container
http://localhost:9000/api/v1/graph/2/details/http://serverurl.net/v1/us/h.schumacher#8tsch.net/n/LouSchumacher
before processing by Spring matcher. This makes matche think that this only http: corresponds {iri:.+} and as later goes / so it is some longer path you don't have a mapping for.
The approach described here should work for you: Spring 3 RequestMapping: Get path value
#RequestMapping(value = "/graph/{graphId}/details/**",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public JSONObject getGraph(#PathVariable Long graphId,
HttpServletRequest request) {
String iri = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
log.debug("Details called for graph ID {} for IRI {}", graphId, iri);
return detailsService.getDetails(graphId, iri);
}
I am writing a "GET" endpoint looks like following:
#RequestMapping(value = "/{configSetId}/{version}", method = RequestMethod.GET, produces = { "application/json" })
public ResponseEntity<List<Metadata>> getMetadatasByConfigSetIdAndVersion(
#PathVariable("configSetId") final String configSetId,
#PathVariable("version") final String version) {
return ResponseEntity.ok(metadataService.getMetadatasByConfigSetIdAndVersion(configSetId, version));
}
So I can send a "GET" request to localhost:8080/{configSetId}/{version}, for example: localhost:8080/configSet1/v1
But the problem is if the version is "v1.02", then the ".02" will be ignored and the version I got is v1. How can I avoid this behaivor? Thank you!
Since "." is special character so don't use it directly on your request.
Instead of
v1.02
Just try
v1%2E02
Where %2E is URL encoding of ".".
For more information, please refer to this link HTML URL Encoding
I have a Spring controller with two parameter long and String:
#RequestMapping(value = "/webpage")
#Controller
public class WebpageContentController {
//...
#RequestMapping(value = "{webpageId}/{webpageAddress}", method = RequestMethod.GET)
public String contentWebpageById(#PathVariable long webpageId, #PathVariable String webpageAddress) {
System.out.println("webpageId=" + webpageId);
System.out.println("webpageAddress=" + webpageAddress);
//...
}
//...
If I invoke it like this:
http://localhost:8080/webarch/webpage/1/blahblah
All is fine:
webpageId=1
webpageAddress=blahblah
But If I pass String parameter with slash (in this case URL address):
http://localhost:8080/webarch/webpage/1/https://en.wikipedia.org/wiki/Main_Page
I get an error:
org.springframework.web.servlet.PageNotFound.noHandlerFound No mapping found for HTTP request with URI [/webarch/webpage/1/https://en.wikipedia.org/wiki/Main_Page] in DispatcherServlet with name 'appServlet'
How pass such parameter?
Well the error is caused by springs controllers mapping, when Spring sees url like
http://localhost:8080/webarch/webpage/1/https://en.wikipedia.org/wiki/Main_Page
It doesn't 'know' that the 'https://en.wikipedia.org/wiki/Main_Page' should be mapped as parameter to "{webpageId}/{webpageAddress}" mapping since every slash is interpreted as a deeper controler method mapping. It looks for controller method mapping like (webpage/1/http:{anotherMapping}/wiki{anotherMapping}/Main_Page{anotherMapping}) wich this kind of mapping is obviously not handled by "{webpageId}/{webpageAddress}"
EDIT
According to your comment you can try something like this
#RequestMapping(value = "/{webpageId}/**", method = RequestMethod.GET)
public String contentWebpageById(HttpServletRequest request) {
String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
String extractedPathParam = pathMatcher.extractPathWithinPattern(pattern, request.getServletPath());
extractedPathParam = extractedPathParam.replace("http:/", "http://");
extractedPathParam = extractedPathParam.replace("https:/", "https://");
//do whatever you want with parsed string..
}
Using spring 4.2.1
SomeParsing should use some Regular Expression to extract only the URL 'variable'
Just encode all special characters in the URL.
https://en.wikipedia.org/wiki/Main_Page
becomes this:
https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FMain_Page
and you can pass it as URL parameter without any problems. Decoding is done automatically, so if you access the parameter as variable in your controller, it contains the URL already decoded and you can use it without any converting needed.
More information about URL encoding: https://en.wikipedia.org/wiki/Percent-encoding
I'm trying to send a array / list of String to my REST server through Spring RestTemplate.
This is on my android side:
private List<String> articleids = new ArrayList<>();
articleids.add("563e5aeb0eab252dd4368ab7");
articleids.add("563f2dbd9bb0152bb0ea058e");
final String url = "https://10.0.3.2:5000/getsubscribedarticles";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("articleids", articleids);
java.net.URI builtUrl = builder.build().encode().toUri();
Log.e("builtUrl", builtUrl.toString());
The builtUrl is: https://10.0.3.2:5000/getsubscribedarticles?articleids=%5B563e5aeb0eab252dd4368ab7,%20563f2dbd9bb0152bb0ea058e%5D
On the server side:
#RequestMapping(value = "/getsubscribedarticles", method = RequestMethod.GET)
public List<Posts> getSubscribedPostFeed(#RequestParam("articleids") List<String> articleids){
for (String articleid : articleids {
logger.info(" articleid : " + articleid);
}
}
The server logs:
.13:11:35.370 [http-nio-8443-exec-5] INFO c.f.s.i.ServiceGatewayImpl
- articleid : [563e5aeb0eab252dd4368ab7
.13:11:35.370 [http-nio-8443-exec-5] INFO c.f.s.i.ServiceGatewayImpl
- articleid : 563f2dbd9bb0152bb0ea058e]
Which I can see is wrong as the list should not have a '[' on the first item and a ']' on the last item.
I have read this thread How to pass List or String array to getForObject with Spring RestTemplate but it does not actually answer the question.
The selected answer issues out a POST request, but I want to do a GET request , also it requires an additional object to work to hold the list and I would prefer to not create extra objects if I can do it with Spring RestTemplate natively.
Using Java 8, this worked for me :
UriComponentsBuilder builder = fromHttpUrl(url);
builder.queryParam("articleids", String.join(",", articleids));
URI uri = builder.build().encode().toUri();
It forms the URL like:
https://10.0.3.2:5000/getsubscribedarticles?articleids=123,456,789
I would expect that the correct working url is something like:
https://10.0.3.2:5000/getsubscribedarticles?articleids[]=123&articleids[]=456&articleids[]=789
After a quick look at the code of public UriComponentsBuilder queryParam(String name, Object... values), I would solve it by using UriComponentsBuilder this way:
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("articleids[]", articleids.toArray(new String[0]));
It is important that, the second parameter is an array but not an Object/Collection!
You did everything correct. You just need to call it without the [].
Just invoke it with .../getsubscribedarticles/articleids=foo,bar,42
I tested this with Spring Boot 1.2.6 and it works like this.
Thanks to dOx for his suggestion - I managed to solve this with the PathVariable - i set the list in my url for android:
final String url = "https://10.0.3.2:5000/getsubscribedarticles/"+new ArrayList<>(articleids);
For my rest server:
#RequestMapping(value = "/getsubscribedarticles/[{articleids}]", method = RequestMethod.GET)
public List<Posts> getSubscribedPostFeed(#PathVariable String[] articleids){
}