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!!!"); }
});
Related
I am getting a following GET request
http://localhost:8080/flamingo-json/en/web/Mobile/our-program/Tiers-recognition-Redesigned/rewards-program-new.html
For the above url I have defined the following Mapping in spring rest controller
#GetMapping(value = "/flamingo-json/{language}/{platform}/{page:.+}")
#ResponseBody
public String getAboutUs(#PathVariable(value = "language", required = false) String language,#PathVariable String platform,
#PathVariable String page){
logger.info("Serving " + page + " page for the request");
return aboutUsService.getPageFromDb(page, language, platform);
but I am unable to get "Mobile/our-program/Tiers-recognition-Redesigned/rewards-program-new.html" value in the Path variable 'page' and I am getting 404.
if you want to jump to other page, delete the annotation #ResponseBody;if you want to get the value(like json) from this request,change the annotation to #PostMapping. hope the ans works.
Small question regarding how to get the Spring request mapping (GET mapping, POST mapping...), the path (route) parameter(s) as variable(s). A bit of background, we currently have a use case where we take a route, compute some information, (the Disaster Recovery URL, the test URL, the most available URL, but the question is not here) and respond back. This is just a partial example to have something a bit more concrete in the question.
Query at http://the-main-host.com/firstRoute
We return http://go-to-region-us-west3.com/firstRoute and maybe minutes later, we return http://go-to-region-eu-central.com/firstRoute , but again, this is not the question.
#GetMapping(path = "/{id}/firstRoute", produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<String> question(#PathVariable #NotBlank final String id, String url) {
String theUrlEnrichedWithOtherInformation = computeExtraInformationForURL(id, url);
return Mono.just(theUrlEnrichedWithOtherInformation + id + "/firstRoute");
}
With time, we are now at some 300 of those handlers, all with real use cases
#PostMapping(path = "/{id}/twoHundredAndFiveRoute", produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<String> question(#PathVariable #NotBlank final String id, String url) {
String theUrlEnrichedWithOtherInformation = computeExtraInformationForURL(id, url);
return Mono.just(theUrlEnrichedWithOtherInformation + id + "/twoHundredAndFiveRoute");
}
#GetMapping(path = "/{id}/twoHundredSixtySevenRoute", produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<String> question(#PathVariable #NotBlank final String id, String url) {
String theUrlEnrichedWithOtherInformation = computeExtraInformationForURL(id, url);
return Mono.just(theUrlEnrichedWithOtherInformation + id + "/twoHundredSixtySevenRoute");
}
We managed to make it more maintainable by using the Spring array of the path annotation. This way of doing is a bit nicer, it brought down our two hundred methods down to a single digit. We would like to keep using this way is possible. However, we lose the information what was the path being invoked.
#GetMapping(path = {"/{id}/firstRoute", "/{id}/twoHundredSixtySevenRoute"}, produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<String> question(#PathVariable #NotBlank final String id, String url) {
String theUrlEnrichedWithOtherInformation = computeExtraInformationForURL(id, url);
return Mono.just(theUrlEnrichedWithOtherInformation + id + getThePathThatWasUsedFromTheArrayPlease());
}
Is it possible to get it back, like in this speculative example?
What you need is to access the HttpServletRequest instance. This has a lot of information about http invocation.
Spring allow us an easy way to access to this instance:
#RequestMapping(value = "/report/{objectId}", method = RequestMethod.GET)
public #ResponseBody void generateReport(
#PathVariable("objectId") Long objectId,
HttpServletRequest request) {
}
If you have access to HttpServletRequest, you can get any part of the url:
Example: http://myhost:8080/people?lastname=Fox&age=30
String uri = request.getScheme() + "://" + // "http" + "://
request.getServerName() + // "myhost"
":" + // ":"
request.getServerPort() + // "8080"
request.getRequestURI() + // "/people"
"?" + // "?"
request.getQueryString(); // "lastname=Fox&age=30"
request.getRequestURI() should have the path value that you need.
You can get it from HttpServletRequest - request.getRequestURI(). Either autowire it or use it from method parameter.
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
I have a weird situation that may be because I missed something that I didn't realized or know.
I am creating a simple login UI using Angular and call the Web API created in java.
The java web API function is as follows
#RequestMapping(value = "/logon", method = RequestMethod.POST, produces = {"application/json"})
#ResponseBody
public String logon(
#RequestParam(value = "userID", required = true) String userID,
#RequestParam(value = "password", required = true) String password,
HttpServletRequest request)
Now if I use the http.post as follows
login(username: string, password: string) {
return this.http.post(this.url+"/security/logon/",
JSON.stringify({ userID: username, password: password }) )
Then I get the following error in the Google Chrome browser:
POST http://localhost:8080/logon/ 400 (Required String parameter 'userID' is not present)
But if I change the code as follows:
login(username: string, password: string) {
var usrpwd = "userID=" + username + "&password=" + password;
return this.http.post(this.url+"/security/logon?"+usrpwd, usrpwd )
It work perfectly.
Am I missing something? Why the second parameter of http.post that should be the parameter passed not seems to be working?
Thanks in advance for any reply or feedback.
You are defining your endpoint url with two mandatory parameters, and such parameters must be in the url (check here), so when you make a request to your endpoint, the url must be :
http://localhost:8080/logon?userID=yourUserId&password=yourUserPassword
In the first implementation you are not adding the query parameters to the url so the request is made to the url http://localhost:8080/logon/ as it doesn't have the required parameters, your web tier is returning the 400 http code, which implies a bad request (because again, your url doesn't contains the required parameters).
constructor(private http:HttpClient){
}
login(usrName,usrPwd){
let body = {userName:usrName, userPwd:usrPwd};
this.http.post("http://localhost:5000/security/login", body)
.subscribe(
res => console.log(res),
error => console.log(error)
)
}
Given a method like:
#RequestMapping(value = {"/foo"}, method = RequestMethod.GET)
public String getMappingValueInMethod() {
log.debug("requested "+foo); //how can I make this refer to /foo programmatically?
return "bar";
}
The use case is for refactoring some lengthly code. I have several GET methods doing roughly the same thing and only the request mapping value is different.
I've looked at using path variables, but this is not really what I want (unless there's some clever use of it that I don't see). I could also get a value from the HttpServletRequest like in this post, but not sure whether there's a better way.
Solution 1
With HttpServletRequest.
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public String fooMethod(HttpServletRequest request) {
String path = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
System.out.println("path foo: " + path);
return "bar";
}
Solution 2
With reflection.
#RequestMapping(value = "/foo2", method = RequestMethod.GET)
public String fooMethod2() {
try {
Method m = YourClassController.class.getMethod("fooMethod2");
String path = m.getAnnotation(RequestMapping.class).value()[0];
System.out.println("foo2 path: " + path);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return "bar";
}
If you want get path from class (instead method) you can use:
String path = YourClassController.class.getAnnotation(RequestMapping.class).value();
Solution 3
With #PathVariable.
#RequestMapping(value = {"/{foo3}"}, method = RequestMethod.GET)
public #ResponseBody String fooMethod3(#PathVariable("foo3") String path) {
path = "/" + path; // if you need "/"
System.out.println("foo3 path: " + path);
return "bar";
}
The simplest way of doing this would be putting the array directly in the request mapping i am assuming this is what you want.
#RequestMapping(value = {"/foo","/foo1","/foo2"}, method = RequestMethod.GET)
public String getMappingValueInMethod(HttpServletRequest request) {
log.debug("requested "+request.getRequestURI());
return request.getRequestURI();
}
Then name the jsp files similar to the uri or other wise you could store the mapping between the request uri and the name of the page in the db .