I have a servlet to offer images resources via spring:
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/thumbnails", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> getThumbnail(int id) {
return service.find(id);
}
Resulting http headers: Cache-control: "max-age=0".
Question: how can I control the cache header just for that method?
I guess you can implement the check of the last modified, Spring has support for that - ref API
Something like
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/thumbnails", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> getThumbnail(int id) {
youeObject = service.find(id);
ResponseBuilder builder = Response.ok(youeObject);
builder.cacheControl(CacheControl.maxAge(24, TimeUnit.HOURS)).cachePrivate());
return builder.build();
}
I ended as follows, which worked:
ResponseEntity.ok().lastModified(file.lastModified()).header("max-age", "86400");
I don't now why the approach with CacheControl class does not work.
I am using following:
public ResponseEntity getProducts(...) {
...
return ResponseEntity.ok().cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePrivate()).body(productProxy);
}
You can specify the cache's maxage by setMaxAge() of CacheControl class.
Also you can set it to public or private according to your requirement
**Follow the code snippets**
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/thumbnails", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> getThumbnail(int id) {
BodyBuilder builder = (BodyBuilder) ResponseEntity.ok();
CacheControl cc = new CacheControl();
cc.setMaxAge(64, TimeUnit.HOURS);
cc.setPrivate(true);
builder.cacheControl(cc);
return builder.body(service.find(id));
}
Related
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();
I am writing a Spring Boot application. My controller has 2 custom request headers. I was executing a couple of tests only to find out that my application returns a '404' when the headers are not present.
I however was expecting this to lead to a '400' error?
Can anyone elaborate why this is happening? And how I should handle it properly? As in tell the consumer of the service the headers are missing?
#RestController("fundsConfirmationController")
#RequestMapping(
value="/accounts/{accountId}/funds-confirmations",
headers = {"X-CAF-MSGID", "X-AccessToken"}
)
public class FundsConfirmationController implements FundsConfirmationControllerI{
private FundsConfirmationServiceI fundsConfirmationService;
#Autowired
public FundsConfirmationController(FundsConfirmationServiceI fundsConfirmationService){
this.fundsConfirmationService = fundsConfirmationService;
}
#GetMapping(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> fundsConfirmation(#RequestHeader(value="X-CAF-MSGID") String messageId,
#RequestHeader(value="X-AccessToken") String accessToken,
FundsConfirmationRequest requestParams) { ... }
2 solutions to do the same.
First using #RequestHeader with required false
#RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
public void post(#RequestHeader(value="X-CAF-MSGID", required=false) String X-CAF-MSGID) {
if(X-CAF-MSGID == null) {
// Your JSON Error Handling
} else {
// Your Processing
}
}
Second using HttpServletRequest instead of #RequestHeader
#RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
public void post(HttpServletRequest request) {
String X-CAF-MSGID = request.getHeader("X-CAF-MSGID");
if(X-CAF-MSGID == null) {
// Your JSON Error Handling
} else {
// Your Processing
}
}
I'm trying to test a POST and no matter what I do I get the java.lang.AssertionError: Content type not set
My controller:
#RestController
#RequestMapping("/artistas")
public class ArtistaEndpoint {
private final ArtistaService artistaService;
private final ArtistaMapper artistaMapper;
private final AlbumService albumService;
#CrossOrigin(origins = "http://localhost:8080")
#PostMapping
public ResponseEntity<Void> post(#Valid #RequestBody Artista artista) {
artista = artistaService.save(artista);
ArtistaDto artistaDto = artistaMapper.toDtoCompleto(artista);
URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(artistaDto.getId()).toUri();
if(!artista.getAlbuns().isEmpty()) {
Set<Album> albuns = artista.getAlbuns();
for(Album album: albuns) {
album.setArtista(artista);
albumService.save(album);
}
}
return ResponseEntity.created(uri).build();
}
}
and my test:
#Test
public void salvarArtistaSemAlbum() throws Exception {
Artista adicionado = new Artista();
adicionado.setId(1L);
adicionado.setNome("Banda Eva");
adicionado.setDescricao("Viva o carnaval");
when(artistaService.save(Mockito.any(Artista.class))).thenReturn(adicionado);
mockMvc.perform(MockMvcRequestBuilders.post("/artistas")
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)and
.content(TestUtil.asJsonString(adicionado)))
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.id", is(1)))
.andExpect(jsonPath("$.nome", is("Banda Eva")))
.andExpect(jsonPath("$.descricao", is("Viva o carnaval")));
verify(artistaService, times(1)).save(Mockito.any(Artista.class));
verifyNoMoreInteractions(artistaService);
assertNull(adicionado.getId());
assertThat(adicionado.getNome(), is("Banda Eva"));
assertThat(adicionado.getDescricao(), is("Viva o carnaval"));
}
And the response of the httpservlet:
MockHttpServletResponse:
Status = 201
Error message = null
Headers = {Location=[http://localhost/artistas/1]}
Content type = null
Body =
Forwarded URL = null
Redirected URL = http://localhost/artistas/1
Cookies = []
I already did a question but the error was another, and I could resolve. I don't understand why it's returning 201 created and no content body. Smells like some annotation that I haven't, but I already review with no sucess.
Srry about my english and thanks for the help.
EDIT-
I thought the problem was solved but I was wrong
You may add the content type directly in your PostMapping annotation :
#PostMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
add #ResponseBody on top of controller method.
OR
#PostMapping(produces = {MediaType.APPLICATION_JSON_VALUE} )
You can add a #RequestMapping annotation to specify the content type in your RestController to the respective method.
Something like:
#RequestMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST).
UPDATED:
This newer annotation is a shortcut to the #RequestMapping with RequestMethod.POST:
#PostMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes=MediaType.APPLICATION_JSON_UTF8_VALUE)
Problem solved, my problem was on the controller 'cause it was returning a void:
My new controller looks like:
public class ArtistaEndpoint {
private final ArtistaService artistaService;
private final ArtistaMapper artistaMapper;
private final AlbumService albumService;
#CrossOrigin(origins = "http://localhost:8080")
#PostMapping
public ResponseEntity<ArtistaDto> post(#Valid #RequestBody Artista artista) {
artista = artistaService.save(artista);
ArtistaDto artistaDto = artistaMapper.toDtoCompleto(artista);
URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(artistaDto.getId()).toUri();
if(!artista.getAlbuns().isEmpty()) {
Set<Album> albuns = artista.getAlbuns();
for(Album album: albuns) {
album.setArtista(artista);
albumService.save(album);
}
}
return ResponseEntity.created(artistaDto).body();
}
}
thanks for all
I am trying to return response as JSON. After searching I found solution to add headers = "Accept=application/json" in RequestMapping. But still it is not working .
It is throwing error HTTP Status 406 "The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers."
Here is my controller code :
#RestController
public class EmployeeController {
private EmployeeService employeeService;
#Autowired(required = true)
#Qualifier(value = "employeeService")
public void setEmployeeService(EmployeeService employeeService){
this.employeeService = employeeService;
}
#RequestMapping(value = "/test",method = RequestMethod.GET)
public String test(){
return "{\"name\":\"xyz\"}";
}
#RequestMapping(value = "/employees",method = RequestMethod.GET,headers = "Accept=application/json")
public List<Employee> listEmployees(){
List<Employee> employees = this.employeeService.getEmployees();
return employees;
}
}
Where am I doing wrong?
The simple way to generate JSON, XML response is #ResponseBody annotation.
#RequestMapping(value =" /jsonPostSingle", method = RequestMethod.GET)
#ResponseBody
public PostModel generateJSONPostsingle(#ModelAttribute("postModel") PostModel postModel) {
if(postModel.getPostId() == 1) {
postModel.setTitle("post title for id 1");
} else {
postModel.setTitle("default post title");
}
return postModel;
}
This way you will be able to map your request to model class using #ModelAttribute.
Follow the complete tutorial Spring MVC : JSON response using #ResponseBody
I understand that you're trying to send a response from GET request of /employees.
if you are using Spring 3.1, try to use
#RequestMapping(value = "/employees",method = RequestMethod.GET, produces = "application/json")
instead of adding headers = "Accept=application/json"
More info:
if you want to specify type of data that will send with a request, you can use consumes attribute
example:
#RequestMapping(value="/foo", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
this will consumes and response with JSON type only
check this link about spring update http://spring.io/blog/2011/06/13/spring-3-1-m2-spring-mvc-enhancements/
Hope it helps
I need to throw a 405 for all the http methods that are not defined in my controller. I am using spring boot is there a generic way to write it so that i do not have to add a method on my controller to read all the HTTP methods currently i do not get any response but it throws a 200 OK. Below is my controller that only has GET and PUT. I want to throw a 405 for all other methods.
#RestController("CardController")
#RequestMapping("/user/v1")
public class CardController {
#Autowired
ICardService iCardService;
#RequestMapping(value = "/{cardHolderId}/cards", produces = "application/json; charset=utf-8", method = RequestMethod.GET)
#ResponseBody
public AllCardsVO getCards(#PathVariable("cardHolderId") final String id) {
return jsonObj;
}
#RequestMapping(value = "/{cardHolderId}/cards/{cardId}", produces = "application/json; charset=utf-8", method = RequestMethod.GET)
#ResponseBody
public CardVO getCard(#PathVariable("cardHolderId") final String cardHolderId,
#PathVariable("cardId") final String cardId){
return jsonObj;
}
#RequestMapping(value = "/{cardHolderId}/cards/{cardId}", produces = "application/json; charset=utf-8", method = RequestMethod.PUT)
#ResponseBody
public CardVO putCard(#PathVariable("cardHolderId") final String cardHolderId,
#PathVariable("cardId") final String cardId, #RequestBody final RequestVO requestVO) {
return jsonObj;
}
This is what I wrote in the controller but it does not work for PATCH.
#RequestMapping(value = "/**", produces = "application/json; charset=utf-8", method = { RequestMethod.OPTIONS,
RequestMethod.DELETE, RequestMethod.PATCH, RequestMethod.POST })
#ResponseBody
public void options(HttpServletResponse response) {
throw new MethodNotAllowedException();
}
Is there a generic way i can do this in spring boot some sort of configuration override or service having this method in every api controller does not seem correct. IF this is the only way how do i get the PATCH working. I am getting a response for PATCH even though i do not have that defined.
ANy help is appreciated.