How to send POST request to relative URL with RestTemplate? - java

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

Related

How to create a URL pointing to a REST endpoint in your system at runtime with Spring Boot?

I'm using Spring Boot to build a REST API. In my situation, there are 2 controllers: ExportController and ImportController. Please check the example code here:
Export Controller:
#RestController
public class ExportController {
#GetMapping(value = "/export", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Resource> export(#RequestParam("id") String id) {
// Processing...
}
}
Import Controller:
#RestController
public class ImportController {
#PostMapping(value = "/import", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> importData(HttpServletRequest request) {
// Processing...
// What should I do here?
String url = ...
}
}
Inside my ImportController, I want to generate a URL pointing to the /export endpoint, e.g. http://www.example.com/export?id=1234.
I don't configure anything about the host or port in the application.properties. I want to get them at runtime.
Could you please show me how to achieve it? I searched a lot on the Internet but couldn't find the answer. Thank you for your help.
If you can live with bringing spring-hateoas into your project then this will work:
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
#RestController
public class ImportController {
#PostMapping(value = "/import", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> importData(HttpServletRequest request) {
String someId = "1234";
ControllerLinkBuilder linkBuilder = ControllerLinkBuilder.linkTo(methodOn(ExportController.class).export(someId));
URI uri = linkBuilder.toUri();
return ResponseEntity.ok(uri);
}
}
This yields http://localhost:8080/export?id=1234
#RestController
public class ImportController {
#PostMapping(value = "/import", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> importData(HttpServletRequest request) {
// Processing...
String url = request.getScheme() + "://" +
request.getServerName() + ":" +
request.getServerPort() + "/export";
}
}
You can make use of ServletUriComponentsBuilder that comes with Spring framework since 3.1.RELEASE.
Given that you have access to current request, You can do something like below.
UriComponents uriComponents = ServletUriComponentsBuilder
.fromRequest(httpServletRequest)
.replacePath("/export")
.queryParam("id",1234)
.build();
String url = uriComponents.toUri();

How get rerouted link of a web url

I have a link
String url = "original_internet_url";
if I visit that link then the browser will redirect to another_url.
My question is how to use Java, or Spring to get the redirected another_url programmatically.
Update: I want to get the redirected url, not "how to redirect url with Spring". For example: If you visit https://www.fb.com/ then you will be redirected to https://www.facebook.com/. Given https://www.fb.com/, how to know that the final url is https://www.facebook.com/.
You can do it with two ways.
First:
#RequestMapping(value = "/redirect", method = RequestMethod.GET)
public void method(HttpServletResponse httpServletResponse) {
httpServletResponse.setHeader("Location", projectUrl);
}
Second:
#RequestMapping(value = "/redirect", method = RequestMethod.GET)
public ModelAndView method() {
return new ModelAndView("redirect:" + projectUrl);
}

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(",");
}

Send file path as #PathVariable in Spring MVC

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

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