I'm trying to add links to every record in my databse, as I am trying to implement the HATEOAS concept. However, I have been experiencing some trouble with this. I tried following this guide https://spring.io/guides/gs/rest-hateoas/. But with no success. How and where should I write the code for adding links? Because it doesn't seem to work when I try to write it in my controller method because withSelfRel() is undefined.
Basically I'm trying to add a link to every account made in my database.
//Create account
#RequestMapping(value="/accounts", method = RequestMethod.POST)
public ResponseEntity<?> accountInsert(#RequestBody Account account) {
account = new Account(account.getFirstName(), account.getLastName(), account.getEmail(), account.getPassword(), account.getBirthDate(), account.getActivities(), account.getFriends());
accountRepository.save(account);
//account.add(linkTo(methodOn(AccountController.class, accountInsert(account)).withSelfRel())); /// HERE IS MY TRY
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setLocation(ServletUriComponentsBuilder.fromCurrentRequest().build().toUri());
return new ResponseEntity<>(null, httpHeaders, HttpStatus.CREATED);
}
Thank you in advance!
you can not use method inside the same one
Try this :-
Link self=linkTo(AccountController.class).slash(account.getId()).withSelfRel();
Or you can refer from given link
Related
I have the following controller method:
#PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, path = "/upload")
public Mono<SomeResponse> saveEnhanced(#RequestPart("file") Mono<FilePart> file) {
return documentService.save(file);
}
which calls a service method where I try to use a WebClient to put some data in another application:
public Mono<SomeResponse> save(Mono<FilePart> file) {
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
bodyBuilder.asyncPart("file", file, FilePart.class);
bodyBuilder.part("identifiers", "some static content");
return WebClient.create("some-url").put()
.uri("/remote-path")
.syncBody(bodyBuilder.build())
.retrieve()
.bodyToMono(SomeResponse.class);
}
but I get the error:
org.springframework.core.codec.CodecException: No suitable writer found for part: file
I tried all variants of the MultipartBodyBuilder (part, asyncpart, with or without headers) and I cannot get it to work.
Am I using it wrong, what am I missing?
Regards,
Alex
I found the solution after getting a reply from one of the contributes on the Spring Framework Github issues section.
For this to work:
The asyncPart method is expecting actual content, i.e. file.content(). I'll update it to unwrap the part content automatically.
bodyBuilder.asyncPart("file", file.content(), DataBuffer.class)
.headers(h -> {
h.setContentDispositionFormData("file", file.name());
h.setContentType(file.headers().getContentType());
});
If both headers are not set then the request will fail on the remote side, saying it cannot find the form part.
Good luck to anyone needing this!
I am trying to display an image in a Thymeleaf template that is coming from a MySql Database.
Most of it is working but I have a problem with the controller code :
#GetMapping(value = "/image/{someId}", produces = {MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE})
public ResponseEntity<byte[]> getPicture(#PathVariable("someId") long someId) throws IOException {
byte[] imageContent = //Getting the blob element from the Repo through a service
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
headers.set("Content-Disposition", "attachment; filename=fileName.jpg");
headers.setContentLength(imageContent.length);
return new ResponseEntity<byte[]>(imageContent, headers, HttpStatus.OK);
}
My code is similar to solutions that ware suggested here (see this answer or this one) but my template won't display the image as its content is most probably not valid. If I reach the endpoint directly from the browser, a "filename.jpg" image will download (makes sense following the code above) but that only contains the original name of the image if I open it with a text editor. It's not an image.
There's surely something that I am missing in the configuration of the ResponseEntity. Do you perhaps have some documentation I could read about the process because I don't understand fully what is going on.
I am working on spring boot. I don't know what is spring hateoas why we go for spring hateoas.
#RequestMapping(value= "/accounts/{id}/{userId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Resource<AccountHolder> findAccountHolderById(#PathVariable("id") Long id, #PathVariable("userId") int i) {
logger.info("accounts findAccountHolderById() invoked: " + id);
Account account = accountRepository.getAccount(id.toString());
AccountHolder accountHolder = account.getAccountHolder();
Resource<AccountHolder> resource = new Resource<AccountHolder>(accountHolder);
resource.add(linkTo(methodOn(AccountController.class).byId(account.getAccountId())).withRel("account"));
logger.info("accounts findAccountHolderById() found: " + account);
return resource;
}
HATEOAS means that a REST webservice not only provides the answer you asked for (e.g. the account) but also links to related data like the customer or subaccounts of that account. You can also provide links to actions like "disable account". That way the clients can navigate through the data more easily.
See https://spring.io/understanding/HATEOAS or https://en.wikipedia.org/wiki/HATEOAS
P.S.: When copy & pasting code, use the "{}" symbol in the edit box to format it correctly.
Hi please help am new to spring social,i am getting the 400 error while getting the access token from the AUTHORIZATION_CODE..
my code is as follows
#RequestMapping(value = "/facebook", method = RequestMethod.POST, produces = "application/json")
#ResponseBody
public Object getFacebookLoginPage(#RequestBody SocialCommand socialCommand) throws Exception {
loggerService.debug("In ShareController", "getFacebookLoginPage method for facebook", "returns the JSON response for the input socialCommand");
Result result = new Result();
result.status = "OK";
dataObject = socialCommand;
FacebookConnectionFactory connectionFactory = new FacebookConnectionFactory(msgprop.getProperty("facebook.appId"), msgprop.getProperty("facebook.appSecrete"), msgprop.getProperty("facebook.namespace"));
oAuth2Operations = connectionFactory.getOAuthOperations();
OAuth2Parameters params = new OAuth2Parameters();
params.setScope(msgprop.getProperty("facebook.scope"));
params.setRedirectUri(msgprop.getProperty("facebook.redirectURI"));
// params.set("Content-Type", MediaType.MULTIPART_FORM_DATA.getType());
String authorizeUrl = oAuth2Operations.buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, params);
System.out.println(authorizeUrl);
SuccessResponse successResponse = new SuccessResponse();
successResponse.resultObj = authorizeUrl;
result.response = successResponse;
return result;
}
and the callback controller is as follows
#RequestMapping(value = "/facebook/callback", params = "code", method = RequestMethod.GET)
public Object faceBookCallback(#RequestParam(value = "code") String callBackCode, Model model) throws IOException {
loggerService.debug("In ShareController", "faceBookCallback method for facebook", "returns the JSON response for the input socialCommand");
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("client_id", msgprop.getProperty("facebook.appId"));
formData.add("client_secret", msgprop.getProperty("facebook.appSecrete"));
formData.add("scope", msgprop.getProperty("facebook.scope"));
formData.add("redirect_uri", msgprop.getProperty("facebook.redirectURI"));
formData.set("grant_type", "authorization_code");
formData.set("Content-Type", MediaType.MULTIPART_FORM_DATA.getType());
AccessGrant accessGrant = oAuth2Operations.exchangeForAccess(callBackCode, msgprop.getProperty("facebook.redirectURI"), formData);
System.out.println(accessGrant.getAccessToken());
appStatus.getActivityId();
SocialCommand socialCommand = (SocialCommand) dataObject;
socialCommand.setAppType("facebook");
socialCommand.setAccessToken(accessGrant.getAccessToken());
getImageLocation(socialCommand);
model.addAttribute("activityId", appStatus.getActivityId());
return "backToViewDetails";
}
oAuth2Operations.exchangeForAccess giving the 400 bad request
A couple of things I notice...
First, why are you writing your own controller for performing the OAuth dance instead of using ConnectController that Spring Social provides? ConnectController can handle all of the redirects for you and has been part of Spring Social from the beginning. Spring Social Showcase (https://github.com/spring-projects/spring-social-samples/tree/master/spring-social-showcase) is an example of a project that uses ConnectController.
Even so, assuming you have good reason for writing your own connection controller, I see nothing in getFacebookLoginPage() that performs the actual redirect to Facebook, so I can only assume that happens in code not shown. Then when the redirect comes back from Facebook, I'm puzzled as to why you set the content type and most of those parameters before calling exchangeForAccess(). (Even then, you're setting what looks like a request header, but you're setting it as a form parameter...not necessary, but also not what you had in mind.)
Again, I encourage you to take a look at ConnectController (https://github.com/spring-projects/spring-social/blob/master/spring-social-web/src/main/java/org/springframework/social/connect/web/ConnectController.java). It will probably do what you need it to do. And even if you still feel the need to writing your own controller, you can look at how ConnectController works as a guide to how to write your own controller.
I am new to RESTful services and their implementation on Spring 3. I would like your opinion on the best practices for returning type when a client creates a new resource in my server.
#RequestMapping(method = RequestMethod.POST,
value = "/organisation",
headers = "content-type=application/xml")
#ResponseStatus(HttpStatus.CREATED)
public ??? createOrganisation(#RequestBody String xml)
{
StreamSource source = new StreamSource(new StringReader(xml));
Organisation organisation = (Organisation) castorMarshaller.unmarshal(source);
// save
return ???;
}
A simple choice would be javax.ws.rs.core.Response, found in the Java EE's own restful services package. It - simply - tells what the web server should answer to the HTTP request.
For instance:
if (organisation != null)
return Response.ok().build();
else
return Response.serverError().build();
Custom response headers and other exotic things like that are possible with that return type too, but I don't think that would match with "best practices".
uh, I missed that #ResponseStatus(HttpStatus.CREATED)... I guess my answer was not much of help.
Maybe this will help instead: How to return generated ID in RESTful POST?
I would go for a ResponseEntity<byte[]> and you would have take care of the marshalling of your response on your controller method. Notice that you are basically scrapping the V in MVC, there is a MarshallingView on Spring but from experience I consider the previous solution much more flexible and easier to understand.
It is a good idea to return the newly created entity(with the generated id) wrapped in ResponseEntity. You can also set the HttpStatus in ResponseEntity based on the result of the operation.
#RequestMapping(method = RequestMethod.POST,
value = "/organization",
headers = "content-type=application/xml")
public ResponseEntity<Organization> createOrganisation(#RequestBody String xml) {
StreamSource source = new StreamSource(new StringReader(xml));
Organization organisation = (Organization) castorMarshaller.unmarshal(source);
// save
return new ResponseEntity<Organization>(organization, HttpStatus.OK);
}