JSON to CSV API with Spring RestTemplate - spring

I want to hit a JSON to CSV API after grabbing a JSON from my own API. The JSON to CSV API requires email and JSON passed in a POST request. Now I am able to store JSON locally but, how do I pass in both the email and JSON in the request and how do I handle the CSV from the response?
Controller
#PostMapping("/generateExcel")
public String getEmployeeCsv(#RequestBody String email) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
String json = restTemplate.exchange("http://localhost:8080/SwaggerTest/employees", HttpMethod.GET, entity, String.class).getBody();
entity = new HttpEntity<String>(json, email, headers);
return restTemplate.exchange("https://json-csv.com/api/getcsv", HttpMethod.POST, entity, String.class).getBody();
}
Update:
I created a EmployeeCsvParams class with email and json String fields as suggested by #Adrien but I still need to handle the CSV from the response.
#PostMapping("/generateExcel")
public String getEmployeeCsv(#RequestBody String email) {
HttpHeaders headers = new HttpHeaders();
EmployeeCsvParams params = new EmployeeCsvParams();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
String json = restTemplate.exchange("http://localhost:8080/SwaggerTest/employees", HttpMethod.GET, entity, String.class).getBody();
params.setEmail(email);
params.setJson(json);
HttpEntity<EmployeeCsvParams> entity2 = new HttpEntity<EmployeeCsvParams>(params, headers);
return restTemplate.exchange("https://json-csv.com/api/getcsv", HttpMethod.POST, entity2, String.class).getBody();
}

From spring docs #RequestBody "You can use the #RequestBody annotation to have the request body read and deserialized into an Object through an HttpMessageConverter. ..."
So i assume you can create the object bellow and use it as argument in your endpoint.
public class EmployeeCsvParams {
/* Fields */
private String email;
private String json;
/* Getters and Setters */
public String getEmail() { return this.email; }
public void setEmail(String email) { this.email = email; }
public String getJson() { return this.json; }
public void setJson(String json) { this.json = json; }
}
#PostMapping("/generateExcel")
public String getEmployeeCsv(#RequestBody EmployeeCsvParams employeeCsvParams)
{
/* ... */
}

Related

What to do when post request returns with error

what is the best practice when I send post request to rest api and want to use message from error response?
I have method with post request:
public boolean create(CreateDriverForm createDriverForm) {
HttpHeaders httpHeaders = new HttpHeaders();
DriverRequestModel driverRequestModel = new DriverRequestModel(createDriverForm.getPesel(),
createDriverForm.getName(), createDriverForm.getSurname(), createDriverForm.getEmail());
HttpEntity entity = new HttpEntity(driverRequestModel, httpHeaders);
ResponseEntity<DriverDTO> responseEntity =
restTemplate.postForEntity("http://localhost:8081/drivers", entity, DriverDTO.class);
return responseEntity.getStatusCode().is2xxSuccessful();
}
and if everything with my form is ok it works, I am getting 201, Created.
But what if my form has any errors and want to use message from error response? I created ExceptionHandler with method:
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status,
WebRequest request) {
List<String> errors = ex.getBindingResult().getFieldErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.toList());
ExceptionResponseObject exceptionResponseObject = new ExceptionResponseObject(
status.value(), "MethodArgumentNotValidException", errors.toString());
return new ResponseEntity<>(exceptionResponseObject, headers, status);
}
ExceptionResponseObject is:
#Data
public class ExceptionResponseObject {
private LocalDateTime timestamp;
private int status;
private String errorName;
private String message;
public ExceptionResponseObject(int status, String errorName, String message) {
this.timestamp = LocalDateTime.now();
this.status = status;
this.errorName = errorName;
this.message = message;
}
}
But what should I do in my "create" method? I would like to use message from that error code but I am expecting DriverDTO class object

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
}

How to perform an http request to another server from spring boot controller

i want to perform a get request on a server hosted on localhost:80 (for example but could be every host) from my spring boot application hosted on localhost:8080.
For example i want to get an image hosted on locahost:80/image.jpg from my spring application. How can i handle this?
You can use RestTemplate for that.
RestTemplate restTemplate = new RestTemplate();
String uri = localhost:80; // or any other uri
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
ResponseEntity<?> result =
restTemplate.exchange(uri, HttpMethod.GET, entity, returnClass);
return result.getBody();
If you want to get images then use following method:
String url = "http://img.championat.com/news/big/l/c/ujejn-runi_1439911080563855663.jpg";
byte[] imageBytes = restTemplate.getForObject(url, byte[].class);
Files.write(Paths.get("image.jpg"), imageBytes);
You will also need to configure ByteArrayHttpMessageConverter in application config:
#Bean
public RestTemplate restTemplate(List<HttpMessageConverter<?>> messageConverters) {
return new RestTemplate(messageConverters);
}
#Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
return new ByteArrayHttpMessageConverter();
}
If you want to send a request with spring you can do
//first create e restemplate variable
RestTemplate restTemplate=new RestTemplate();
//you can create and edit header
HttpHeaders header= new HttpHeaders();
header.add("Authorization", "*****************");
header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
header.add("Accept", "application/json");
//you can create and edit body to
MultiValueMap<String, String> body= new LinkedMultiValueMap<String, String>();
body.add("grant_type", "client_credentials");
HttpEntity<MultiValueMap<String, String>> requeteHttp =new HttpEntity<MultiValueMap<String, String>>(body, header);
//After you can create a request
ResponseEntity<Response_class> reponse = restTemplate.postForEntity("your api link", requeteHttp , Response_class.class);
//if you want to send a get request you can edit postForEntity to get
About Response_class
if you know the return type of the request, you can create a class and use it here, otherwise you can use string instead
if your request returns a json like this
{
"token_type":"***",
"access_token":"***",
"expires_in":"***",
}
you can create a Response_class controller(class) and call it like we did above otherwise you can use string instead
public class Response_class{
private String token_type;
private String access_token;
private String expires_in;
public Response_class(String token_type, String access_token, String expires_in) {
this.token_type = token_type;
this.access_token = access_token;
this.expires_in = expires_in;
}
public Response_class() {
}
public String getToken_type() {
return token_type;
}
public void setToken_type(String token_type) {
this.token_type = token_type;
}
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public String getExpires_in() {
return expires_in;
}
public void setExpires_in(String expires_in) {
this.expires_in = expires_in;
}
}
You can use WebClient:
byte[] image = WebClient.create("locahost:80/image.jpg")
.get()
.accept(MediaType.IMAGE_JPEG)
.retrieve()
.bodyToMono(byte[].class)
.block();

Spring RestTemplate Handling Multiple Responses

I'm consuming a restful service, What I observed is based on the request I see multiple responses for the same end point.
For Ex : I request a GET call with the some parameters for a PDF document.
if the response is good and the content type is application/pdf its giving a pdf document.
if the document is not available, the content type is application/xml and the response is giving the error code, error description.
Any input is much appreciated !
Thanks,
Sudheer.
You can use the ResponseEntity class of Spring, you can set the class to return the object what you want. You can change the content type, and everything you want.
here there is an example of file
#RequestMapping(value = URIConstansts.GET_FILE, produces = { "application/json" }, method = RequestMethod.GET)
public #ResponseBody ResponseEntity getFile(#RequestParam(value="fileName", required=false) String fileName,HttpServletRequest request) throws IOException{
ResponseEntity respEntity = null;
byte[] reportBytes = null;
File result=new File("/home/arpit/Documents/PCAP/dummyPath/"+fileName);
if(result.exists()){
InputStream inputStream = new FileInputStream("/home/arpit/Documents/PCAP/dummyPath/"+fileName);
String type=result.toURL().openConnection().guessContentTypeFromName(fileName);
byte[]out=org.apache.commons.io.IOUtils.toByteArray(inputStream);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("content-disposition", "attachment; filename=" + fileName);
responseHeaders.add("Content-Type",type);
respEntity = new ResponseEntity(out, responseHeaders,HttpStatus.OK);
}else{
respEntity = new ResponseEntity ("File Not Found", HttpStatus.OK);
}
return respEntity;
}
Here there is an example of Json
#ResponseBody ResponseEntity<? extends AbstractResponse> createUser(#RequestBody String requestBody) {
if(!valid(requestBody) {
ErrorResponse errResponse = new ErrorResponse();
//populate with error information
return new ResponseEntity<ErrorResponse> (errResponse, HTTPStatus.BAD_REQUEST);
}
createUser();
CreateUserSuccessResponse successResponse = new CreateUserSuccessResponse();
// populate with more info
return new ResponseEntity<CreateUserSuccessResponse> (successResponse, HTTPSatus.OK);
}

#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