how to return only HTTP Status code, if we hit one pre-defined endpoint - spring-boot

When I hit
#FeignClient(name = "abc_abc", url = "${abc.host}")
public interface validateClient {
#PostMapping(path = "/api/abc/validate",
consumes = "application/json",
produces = "application/json")
**public <?> validateResponse**(#RequestHeader HttpHeaders htppHeaders, #RequestParam Map<String, Object> params,
#RequestBody String request);
}
in this example API: /api/abc/validate
i just want to return only HTTP status code
what is the return type of validateResponse method ? please some one plz suggest

Try use ResponseEntity without any "body", here an example.
#PostMapping(path = "/api/abc/validate",
consumes = "application/json",
produces = "application/json")
public ResponseEntity validateResponse(#RequestHeader HttpHeaders htppHeaders, #RequestParam Map<String, Object> params,
#RequestBody String request) {
return ResponseEntity.status(HttpStatus.FOUND).build();
}
You can choose from standard HttpStatus enum, or simply insert an integer for your custom needs

Related

Passing Spring pageable in get request

If I send a request from Spring application:
public ResponseEntity<RestResponsePage<Result>> readDocs(
Pageable pageable
) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Authorization", getToken());
String requestUri =
baseAppUrl + "/api/k" + "?page={page}&pageSize={pageSize}&sort={sort}&pageable={pageable}";
Map<String, Object> urlParameters = new HashMap<>();
urlParameters.put("page", Integer.toString(pageable.getPageNumber()));
urlParameters.put("pageSize", Long.toString(pageable.getPageSize()));
urlParameters.put("sort", pageable.getSort());
urlParameters.put("pageable", pageable);
HttpEntity<Void> requestEntity = new HttpEntity<>(requestHeaders);
ResponseEntity<RestResponsePage<Result>> response = restTemplate.exchange( RestResponsePage
requestUri,
HttpMethod.GET,
requestEntity,
new ParameterizedTypeReference<RestResponsePage<Result>>() {},
urlParameters
);
return response;
}
to another Spring application:
#GetMapping("/")
#PageableAsQueryParam
public ResponseEntity<Page<Result>> getAll(
#RequestHeader("Authorization") String token,
#RequestParam("page") Integer page,
#RequestParam("pageSize") Integer pageSize,
#RequestParam("sort") String sort,
#RequestParam("pageable") Pageable pageable
) {
...
}
I have got an error saying:
Resolved [org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'org.springframework.data.domain.Pageable'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.data.domain.Pageable': no matching editors or conversion strategy found]
I know i can pass it seperately by fields like in example above:
page, pageSize etc.
But i want also to send Sort that's is inside Pageable object - that's also not correctly deserialized as a Type Sort.
How can I make it so Pageable is correctly deserialized ?
EDIT:
regarding answer, I added function like:
UriComponentsBuilder withPageable(UriComponentsBuilder builder,
Pageable pageable) {
builder.queryParam("page", pageable.getPageNumber()).queryParam("size",
pageable.getPageSize());
if (pageable.getSort() != null) {
StringBuilder sb = new StringBuilder();
pageable.getSort().forEach(order -> {
sb.append(order.getProperty()).append(",").append(order.getDirection());
});
builder.queryParam("sort", sb.toString());
}
return builder;
}
to make sort properly deserialize.
Do not need to use #RequestParam("pageable").
Pageable Abstract interface for pagination information.
pageSize, pageNumber, sort already provided on the Pageable
Sample Controller
#Controller
public class Controller {
#GetMapping("/...")
public List<...> findAll(Pageable pageable) {
log.debug("pageable: {}", pageable);
// ...
}
}
MockRequetBuilders
RequestBuilder request = MockMvcRequestBuilders.get("/url")
.param("page", "1")
.param("size", "5")
.param("sort", "name,DESC"); // column, ASC|DESC
ResultActions actions = mockMvc.perform(request);
actions.andExpect(...);
RestTemplate
URI uri = UriComponentsBuilder.fromHttpUrl("/url")
.queryParam("page", pageable.getPageNumber())
.queryParam("size", pageable.getPageSize())
.queryParam("sort", pageable.getSort())
.build()
.toUri();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> entity = new HttpEntity<>(headers);
ResponseEntity<...> response = restTemplate.exchange(uri, HttpMethod.GET, entity, ...);
https://reflectoring.io/spring-boot-paging/
https://cursos.alura.com.br/forum/topico-no-primary-or-single-unique-constructor-found-for-interface-org-springframework-data-domain-pageable-195442

Spring boot: Sending a JSON to a post request that uses a model as a param

Lets say I have a predefined post mapping as such:
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> addVal(#RequestBody final valDetail newVal) {
//Do Stuff
}
and the valDetail object as follows:
#Data
#Component
#Entity
#Table(name = "val_portal")
public class valDetail {
#Id
#Column(name = "valcode")
private String valCode;
#Column(name = "valname")
private String valName;
}
How would I go about actually sending JSON values from a separate service to this /add endpoint so that they are properly received as a valDetail object?
Currently I tried this implementation but I keep getting a 415 response code.
JSONObject valDetail = new JSONObject();
valDetail.put("valCode",request.getAppCode().toLowerCase());
valDetail.put("valName", request.getProjectName());
String accessToken = this.jwtUtility.retrieveToken().get("access_token").toString();
HttpHeaders authHeaders = new HttpHeaders();
authHeaders.setBearerAuth(accessToken);
authHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(valDetail.toString(), authHeaders);
ResponseEntity<String> loginResponse = restTemplate.exchange(uri,
HttpMethod.POST,
entity,
String.class);
If you want to pass data as json you don't want to take Model try to use #ResponseBody annotation to transfer data through json.
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<String> addVal(#RequestBody final valDetail newVal) {
//Do Stuff
}

Spring get MediaType of received body

Following this answer I've set my method in controller this way:
#PostMapping(path = PathConstants.START_ACTION, consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<BaseResponse<ProcessInstance>> start(#PathVariable String processDefinitionId,
#RequestBody(required = false) String params)
Now I need to behave differently according to my #RequestBody being of one MediaType or the other, so I need to know whether my params body is json o urlencoded. Is there a way to do this?
You can simply inject Content-Type header.
#PostMapping(path = "/{processDefinitionId}", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> start(#PathVariable String processDefinitionId,
#RequestBody(required = false) String params,
#RequestHeader("Content-Type") String contentType) {
if (contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) {
System.out.println("json");
} else {
// ...
}
return ResponseEntity.ok(params);
}
But I would suggest to split this method on two methods with different consumes values:
#PostMapping(path = "/v2/{processDefinitionId}", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> startV2Json(#PathVariable String processDefinitionId,
#RequestBody(required = false) String params) {
return ResponseEntity.ok(params);
}
#PostMapping(path = "/v2/{processDefinitionId}", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<String> startV2UrlEncoded(#PathVariable String processDefinitionId,
#RequestBody(required = false) String params) {
return ResponseEntity.ok(params);
}

400 (Bad Request) while sending json in Spring

I'm trying to send json string to Spring controller, i'm getting 400 - bad request as response
i'm using Spring 4.0.3
This is my controller
#Controller
public class Customer{
#RequestMapping(value = "/apis/test", method = RequestMethod.GET, produces = "application/json")
public #ResponseBody String test(HttpServletRequest params) throws JsonIOException {
String json = params.getParameter("json");
JsonParser jObj = new JsonParser();
JsonArray jsonObj = (JsonArray ) jObj.parse(json);
for(int i = 0; i < jsonObj.size(); i++) {
JsonObject jsonObject = jsonObj.get(i).getAsJsonObject();
System.out.println(jsonObject.get("name").getAsString());
}
return json;
}
}
Please help me to solve this
#RequestMapping(value = "/apis/test", method = RequestMethod.GET, produces = "application/json")
The above means this is a HTTP GET method which does not normally accept data. You should be using a HTTP POST method eg:
#RequestMapping(value = "/apis/test", method = RequestMethod.POST, consumes = "application/json")
public #ResponseBody String test(#RequestParam final String param1, #RequestParam final String param2, #RequestBody final String body) throws JsonIOException {
then you can execute POST /apis/test?param1=one&param2=two and adding strings in the RequestBody of the request
I hope this helps!

#RequestPart with mixed multipart request, Spring MVC 3.2

I'm developing a RESTful service based on Spring 3.2. I'm facing a problem with a controller handling mixed multipart HTTP request, with a Second part with XMLor JSON formatted data and a second part with a Image file .
I am using #RequestPart annotation for receiving the request
#RequestMapping(value = "/User/Image", method = RequestMethod.POST, consumes = {"multipart/mixed"},produces="applcation/json")
public
ResponseEntity<List<Map<String, String>>> createUser(
#RequestPart("file") MultipartFile file, #RequestPart(required=false) User user) {
System.out.println("file" + file);
System.out.println("user " + user);
System.out.println("received file with original filename: "
+ file.getOriginalFilename());
// List<MultipartFile> files = uploadForm.getFiles();
List<Map<String, String>> response = new ArrayList<Map<String, String>>();
Map<String, String> responseMap = new HashMap<String, String>();
List<String> fileNames = new ArrayList<String>();
if (null != file) {
// for (MultipartFile multipartFile : files) {
String fileName = file.getOriginalFilename();
fileNames.add(fileName);
try {
file.transferTo(new File("C:/" + file.getOriginalFilename()));
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
responseMap.put("displayText", file.getOriginalFilename());
responseMap.put("fileSize", "" + file.getSize());
response.add(responseMap);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Accept", "application/json");
return new ResponseEntity<List<Map<String, String>>>(response,
httpHeaders, HttpStatus.OK);
}
User.java will be like this-
#XmlRootElement(name = "User")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int userId;
private String name;
private String email;
private String company;
private String gender;
//getter setter of the data members
}
To my understanding, using the #RequestPart annotation I would expect the XML multipart section to be evaluated depending on its Content-Type and finally un-marshalled into my User class (I'm using Jaxb2, the marshaller/unmarhaller is properly configured in the application context and the procedure is working fine for all the other controller methods when I pass the XML data as body and use the #RequestBody annotation).
But what is actually happening is that, although the file is correctly found and parsed as MultipartFile, the "user" part is never seen and the request is always failing, not matching the controller method signature.
I reproduced the problem with several clients type and I am confident the format of the multipart request is ok.
Please help me to solve this issue, Maybe some workaround will be there to receive mixed/multipart request.
Thanks and Regards,
Raghvendra
I have managed to solve the problem
Endpoint example:
#PostMapping("/")
public Document create(#RequestPart Document document,
#RequestPart(required = false) MultipartFile file) {
log.debug("#create: document({}), file({})", delegation, file);
//custom logic
return document;
}
Exception:
"error_message": "Content type 'application/octet-stream' not supported"
Exception is thrown from the next method:
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(HttpInputMessage,MethodParameter,Type)
Solution:
We have to create custom converter #Component, which implements HttpMessageConverter or HttpMessageConverter and knows about MediaType.APPLICATION_OCTET_STREAM. For simple workaround it's enough to extend AbstractJackson2HttpMessageConverter
#Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
/**
* Converter for support http request with header Content-Type: multipart/form-data
*/
public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
}
#Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return false;
}
#Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
return false;
}
#Override
protected boolean canWrite(MediaType mediaType) {
return false;
}
}
Not sure if you had fixed your problem, but I also had a similar problem where my JSON object was not getting picked up by my controller when mixing #RequestPart and MultipartFile together.
The method signature for your call looks correct:
public ResponseEntity<List<Map<String, String>>> createUser(
#RequestPart("file") MultipartFile file, #RequestPart(required=false) User user) {
// ... CODE ...
}
However make sure your request looks something like this:
POST /createUser
Content-Type: multipart/mixed; boundary=B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="user";
Content-Type: application/xml; charset=UTF-8
<user><!-- your user xml --></user>
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="file"; filename="A551A700-46D4-470A-86E7-52AD2B445847.dat"
Content-Type: application/octet-stream
/// FILE DATA
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E--
You can use #RequestPart from
org.springframework.web.bind.annotation.RequestPart;
It is used as Combining #RequestBody and file upload.
Using #RequestParam like this
#RequestParam("file") MultipartFile file
you can upload only file and multiple single data (key value )
like
#RequestMapping(value = "/uploadFile", method = RequestMethod.POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public void saveFile(
#RequestParam("userid") String userid,
#RequestParam("file") MultipartFile file) {
}
you can post JSON Object data and and File both using #RequestPart like
#RequestMapping(value = "/patientp", method = RequestMethod.POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<?> insertPatientInfo(
#RequestPart PatientInfoDTO patientInfoDTO,
#RequestPart("file") MultipartFile file) {
}
You are not limited to using multipart file uploads directly as controller method parameters. Your form objects can contain Part or MultipartFile fields, and Spring knows automatically that it must obtain the values from file parts and converts the values appropriately.
Above method can respond to the previously demonstrated multipart request containing a single file. This works because Spring has a built-in HTTP message converter that recognizes file parts. In addition to the javax.servlet.http.Part type, you can also convert file uploads to org.springframework.web.multipart.MultipartFile. If the file field permits multiple file uploads, as demonstrated in the second multipart request, simply use an array or Collection of Parts or MultipartFiles.
#RequestMapping(value = "/patientp", method = RequestMethod.POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<?> insertPatientInfo(
#RequestPart PatientInfoDTO patientInfoDTO,
#RequestPart("files") List<MultipartFile> files) {
}
Happy To Help...
I have managed to solve problem:
#SuppressWarnings("rawtypes")
#RequestMapping(value = "/DataTransfer", method = RequestMethod.POST, produces = {
MediaType.APPLICATION_JSON_UTF8_VALUE }, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE} )
#ApiOperation(value = "Sbm Data Transfer Service", response = Iterable.class)
#ApiResponses(value = { #ApiResponse(code = 200, message = "Successfully find."),
#ApiResponse(code = 400, message = "There has been an error."),
#ApiResponse(code = 401, message = "You are not authorized to save the resource"),
#ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
#ApiResponse(code = 404, message = "The resource you were trying to reach is not found") })
ResponseEntity processDataTransfer(#RequestPart(name="file") MultipartFile file, #RequestPart(name="param") DataTransferInputDto param);
have you tried
ResponseEntity<List<Map<String, String>>> createUser(
#RequestPart("file") MultipartFile file, #RequestBody(required=false) User user) {
or
ResponseEntity<List<Map<String, String>>> createUser(
#RequestPart("file") MultipartFile file, #RequestParam(required=false) User user) {
If this does not work can you show us mapping.xml

Resources