How to pass url as #PathVariable to spring RestController? - java

I want to put URL in GET Request so I can then redirect the user to the given URL.
This is my code so far:
#RequestMapping(value = { "/mapping/{param1}/{redirectLink}" }, method = { RequestMethod.GET})
public void mapping(HttpServletResponse response, #PathVariable("param1") String param1, #PathVariable("redirectLink") String redirectLink) throws IOException {
// code i wanna run
response.sendRedirect(backLink);
}
Example url i use to GET - http://localhost:8080/app/controller/redirectionTest/1234/http://localhost:3000/main
So when I call the GET method I wanna run some code then be redirected to http://localhost:3000/main but the URL has slashes in it so it makes it impossible.

Replace the slashes with the standard code: %2F.
http://localhost:8080/app/controller/redirectionTest/1234/http%3A%2F%2Flocalhost%3A3000%2Fmain
I have replaced the colons with %3A just in case you have a problem with that one also

You can try this
#RequestMapping(value = { "/mapping/{param1}" }, method = { RequestMethod.GET})
public void mapping(HttpServletResponse response, #PathVariable("param1") String param1, #RequestParam(required = true, value = "redirectLink") String redirectLink) throws IOException {
// code i wanna run
response.sendRedirect(redirectLink);
}
Now, visit http://localhost:8080/app/controller/redirectionTest/1234?redirectLink=http://localhost:3000/main

Related

Spring Boot Path Variable that contains multiple slashes [duplicate]

I have to get params from URL using #PathValiable in SpringBoot application. These params often have slashes. I don't have a control about what a user would enter in URL so I would like to get what he has entered and then I can handle with it.
I have already looked through materials and answers here, I don't think that for me the good solution is to ask users somehow encode the entering params.
The SpringBoot code is simple:
#RequestMapping("/modules/{moduleName}")
#ResponseBody
public String moduleStrings (#PathVariable("moduleName") String moduleName) throws Exception {
...
}
So the URL for example would be the following:
http://localhost:3000/modules/...
The issue is that the param moduleName often has slashes.
For example,
metadata-api\cb-metadata-services OR
app-customization-service-impl\\modules\\expand-link-schemes\\common\\app-customization-service-api
So a user definetely can enter:
http://localhost:3000/modules/metadata-api\cb-metadata-services
Is this possible to get everything what a user has entered in URL after /modules/?
If anyone tell me what are the good ways to handle such issue.
Basing on P.J.Meisch's answer I have come to the simple solution for my case. Also it allows to take into account several slashes in the URL param. It doesn't allow to work with backslashes as in the previous answer too.
#RequestMapping(value = "/modules/**", method = RequestMethod.GET)
#ResponseBody
public String moduleStrings(HttpServletRequest request) {
String requestURL = request.getRequestURL().toString();
String moduleName = requestURL.split("/modules/")[1];
return "module name is: " + moduleName;
}
This code gets the complete path:
#RequestMapping(value = "/modules/{moduleBaseName}/**", method = RequestMethod.GET)
#ResponseBody
public String moduleStrings(#PathVariable String moduleBaseName, HttpServletRequest request) {
final String path =
request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
final String bestMatchingPattern =
request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString();
String arguments = new AntPathMatcher().extractPathWithinPattern(bestMatchingPattern, path);
String moduleName;
if (null != arguments && !arguments.isEmpty()) {
moduleName = moduleBaseName + '/' + arguments;
} else {
moduleName = moduleBaseName;
}
return "module name is: " + moduleName;
}
import org.springframework.web.util.UriUtils;
#RequestMapping(value = "/modules/**", method = RequestMethod.GET)
#ResponseBody
public String moduleStrings(HttpServletRequest request) {
final String url = request.getRequestURL().toString();
final String modules = url.split("/modules")[1];
final String safeModules = UriUtils.decode(modules, StandardCharsets.UTF_8);
return "replaces %20 with space";
}
Is this a school assignment or something? Why would you want to put free text in the path? Instead, why not use a parameter variable?
I am not sure it is a great idea to have the user entering complicated urls that include free text. For one, it is hard for users to remember complicated urls, so it isn't user friendly. Second, they can do some weird stuff.
Instead have a main page they go to that might have links (or something like that) to take them to further page. If they need to enter free text, give them a text box to add data to, a button to click that will make something like an ajax call containing the data. The path would have everything except the free text. You can do that like this...
#RequestMapping(value = "/modules/{moduleBaseName}", method = RequestMethod.GET)
#ResponseBody
public String moduleStrings(#PathVariable String moduleBaseName,
#RequestParam(value = "moduleName", required = false) String moduleName
HttpServletRequest request)
{
return "module name is: " + moduleName;
}
Then on the client side you would just need to set the data attribute in your ajax call to a json that contains the "moduleName" attribute. Something like this.
var params = {};
params.moduleName = userEnteredText;
jQuery.ajax({
type: "GET",
url: 'http://localhost:3000/modules'.json'),
dataType: "json",
data: params,
async: true,
success: function(data) { callback(data); },
error: function() { alert("Error!!!"); }
});

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();

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 {

405 Method Not Allowed with Spring

I have the following test for an HTTP endpoint:
public static final String DATA_PARAMETER = "data";
public static final String ID_PARAMETER = "id";
public static final String VIDEO_SVC_PATH = "/video";
public static final String VIDEO_DATA_PATH = VIDEO_SVC_PATH + "/{id}/data";
#Multipart
#POST(VIDEO_DATA_PATH)
public VideoStatus setVideoData(#Path(ID_PARAMETER) long id, #Part(DATA_PARAMETER) TypedFile videoData);
#Test
public void testAddVideoData() throws Exception {
Video received = videoSvc.addVideo(video);
VideoStatus status = videoSvc.setVideoData(received.getId(),
new TypedFile(received.getContentType(), testVideoData));
assertEquals(VideoState.READY, status.getState());
Response response = videoSvc.getData(received.getId());
assertEquals(200, response.getStatus());
InputStream videoData = response.getBody().in();
byte[] originalFile = IOUtils.toByteArray(new FileInputStream(testVideoData));
byte[] retrievedFile = IOUtils.toByteArray(videoData);
assertTrue(Arrays.equals(originalFile, retrievedFile));
}
I'm trying to implement the requirements defined by this test with the following endpoint defined in Swing:
#RequestMapping(method = RequestMethod.POST, value = "/video/{id}/data")
public void postVideoData(#PathVariable("id") long videoId,
#RequestParam("data") MultipartFile videoData) throws IOException {
if (videoId <= 0 || videoId > videos.size()) {
throw new ResourceNotFoundException("Invalid id: " + videoId);
}
Video video = videos.get((int)videoId - 1);
InputStream in = videoData.getInputStream();
manager.saveVideoData(video, in);
}
The problem is that I get a "405 Method Not Allowed" error. What am I doing wrong so that my POST method is not being recognized?
The problem is that the client interface expects a VideoStatus object returned from the server. I declared the method on the server side to return void.
I don't know if you already fix your problem, but I got the same error, because I am new with Retrofit too :).
The solution for me, was to put an Annotation to specify the response content type, in my case
#ResponseBody
Another change that I must did, was to change void for a custom status.
Hope this helps or at least gives you a light.
Rgds.
I had the same issue. RetroFit request calls must have either a return type or Callback as last argument.
So in the RetroFitted API:
#POST("/path")
public Void saveWhatever(#Body Whatever whatever);
Than in the controller it must be :
#RequestMapping(value = "/path", method = RequestMethod.POST)
public #ResponseBody Void saveWhatever(#RequestBody Whatever whatever) {
repository.save(whatever);
return null;
}

Categories