Download A File On click of a link using spring mvc - spring

When I click on any link the content should be downloaded
But this is what I get.
MastercourseController.java
#RequestMapping(value = { ControllerUriConstant.download_file }, method = RequestMethod.GET)
#ResponseBody
public void downloadingAFileById(#RequestParam("id") String id, Model model, HttpServletRequest request)
throws TechnoShineException, IOException {
String filePath = "D:/dev/testFIle.txt";
long download = Long.parseLong(id);
byte[] b = masterCourseFileFormService.getAllDownloadable(download);
OutputStream outputStream = new FileOutputStream(filePath);
outputStream.write(b);
outputStream.close();
}
MasterCourseService
public byte[] getAllDownloadable(long id) throws TechnoShineException
{
return masterCourseFormUploadDao.getAllDownloadableFiles(id);
}
MasterCourseDao
public byte[] getAllDownloadableFiles(long id) throws TechnoShineException
{
return masterCourseFormUploadMapper.getAllDownloadable(id);
}
MasterCourseMapper
public byte[] getAllDownloadable(long id) throws TechnoShineException;

You are writing the data returned by getAllDownloadable(..) to a hard-coded file. Are you sure that is what you want? I think you want to write the content returned by getAllDownloadable(..) to be written into the response. That can be done by adding a method parameter of the type HttpServletResponse to your mapping and writing into the output stream returned by HttpServletResponse#getOutputStream() and flushing (not closing!) that stream at the end.
Furthermore you have to remove the #ResponseBody annotation as this is meant to be used if the value that is returned by the mapping method returns the data that should directly be sent to the client (i.e. when sending a JSON data object or a string) without passing it to the template engine. As you are not returning anything you can remove this annotation.
Furthermore you have to set the content type of your response by invoking HttpServletResponse#setContentType(contentType: String).
In your case, the invocation would be the following:
response.setContentType("text/plain");
You complete method would look like this:
#RequestMapping(
value = ControllerUriConstant.download_file,
method = RequestMethod.GET
)
public void downloadingAFileById(#RequestParam("id") String id, HttpServletResponse response)
throws TechnoShineException, IOException {
long download = Long.parseLong(id);
byte[] b = masterCourseFileFormService.getAllDownloadable(download);
response.getOutputStream().write(b);
response.getOutputStream().flush();
}

Related

How to get data from a void returning get request in spring?

A micro-service is providing an api(get request) to download a file which is having a return type as void. It is populating HttpServletResponse but not returning it. How can I get the data from such api?
#GetMapping(value="/download/{id}")
public void download(#PathVariable(value = "id") String id, HttpServletResponse response) {
FileDTO file = downloadFile(id, response);
response.setContentType("text/html");
....
....
}
How can we get the html/text data from the above sample snippet? (Assume all required parameters are set.)

MockMvc Test does not get to the endpoint for a Multipart file in a RestController

I am calling a service in an orders controller which receives a multipart file and processes it and saving it into a database. I am trying to create a Spring Rest Doc for it but it is not even hitting the endpoint. I am creating a list of orders which is what the service expects. It receives the order as a stream as shown and converts into a stream of orders before saving it into a database. I have shown the main part of the controller and my code for generating the rest docs. When I run the code I get the following exception, it never even hits the endpoint when I set a breakpoint. I also used fileupload() but that did not work either.
Exception is:
Content type = application/json
Body = {"path":"/orders/order_reception","exceptionName":
"MissingServletRequestPartException","message":"Required request part 'uploadFile' is not
present",
"rootExceptionName":"MissingServletRequestPartException",
"rootMessage":"MissingServletRequestPartException: Required request part 'uploadFile' is not present"}
#RestController
#RequestMapping(value = "/orders")
#Validated
class OrderController{
#PostMapping(path = "/order_reception")
public ResponseEntity receiveData(#RequestPart MultipartFile uploadFile,
HttpServletRequest request,
HttpServletResponse response) {
if (!uploadFile.isEmpty()) {
try {
Reader reader = new InputStreamReader(request.getInputStream()));
... save file
return new ResponseEntity<>(HttpStatus.HttpStatus.CREATED);
} catch (Exception e) {
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
return new ResponseEntity(HttpStatus.BAD_REQUEST);
}
#Test
public void sendData() throws Exception {
ObjectMapper mapper = new ObjectMapper();
Order order = repository.getOrder("1233333");
List<Order> orderList = new ArrayList<>():
resourceList.add(order);
MockMultipartFile orderFile = new MockMultipartFile("order-data", "order.json", "application/json",
mapper.writeValueAsString(orderList).getBytes(Charset.defaultCharset()));
mockMvc.perform(multipart("/orders/order_reception")
.file(orderFile))
.andExpect(status().isCreated())
.andDo(document("send-order",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint())));
}
Thank you Marten Deinum, your suggestion that the file name was wrong fixed it.
I simply changed name in the MockMultipartFile( "uploadsFile", ...)

How to reject the request and send custom message if extra params present in Spring boot REST Api

#PostMapping()
public ResponseEntity<ApiResponse> createContact(
#RequestBody ContactRequest contactRequest) throws IOException {
}
How to reject the API request, if extra params present in the request, by default spring boot ignoring extra parameters.
I believe you can add an HttpServletRequest as a parameter to the controller method (createContact in this case). Then you'll get access to all the parameters that come with the requests (query params, headers, etc.):
#PostMapping
public ResponseEntity<ApiResponse> createContact(HttpServletRequest request,
#RequestBody ContactRequest contactRequest) throws IOException {
boolean isValid = ...// validate for extra parameters
if(!isValid) {
// "reject the request" as you call it...
}
}
First add an additional parameter to the method. This gives you access to information about the request. If Spring sees this parameter then it provides it.
#PostMapping()
public ResponseEntity<ApiResponse> createContact(
#RequestBody ContactRequest contactRequest,
WebRequest webRequest) throws IOException {
if (reportUnknownParameters(webRequest) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
I do something like this to get the bad request into the log.
private boolean reportUnknownParameters(WebRequest webRequest) {
LongAdder unknownCount = new LongAdder();
webRequest.getParameterMap().keySet().stream()
.filter(key -> !knownParameters.contains(key))
.forEach(key -> {
unknownCount.increment();
log.trace("unknown request parameter \"{}\"=\"{}\"", key, webRequest.getParameter(key));});
return unknownCount.longValue() > 0;
}
add #RequestParam annotation in your methods parameter list and add it as a map, then you can access for it's key list and check if it contains anything else other than your required params.
public ResponseEntity<ApiResponse> createContact(#RequestParam Map<String,String> requestParams, #RequestBody ContactRequest contactRequest) throws IOException {
//Check for requestParams maps keyList and then pass accordingly.
}

Receive/Send MultiRow data along with file in SpringBoot Controller

I want to receive multi rows in spring boot controller, tried different approached but unable to do it. i am testing with postman.
Controller
#PostMapping(URLConstant.URL_SC_ATTACHMENT_POST)
public ResponseEntity<ApiResponse> storeFile(#RequestParam("attachmentDto") List<BudgetSceAttachmentDto> attachmentDto) throws IOException {
System.out.println(attachmentDto);
return ResponseUtil.getResponse(HttpStatus.OK, MsgConstant.BUDGET_MSG_FILE_UPLOADED, null);
}
DTO
private Integer versionId;
private String fileName;
private String pathUploadedFile;
private String uploadedFileName;
private MultipartFile file;
First of all, request's content-type should be multipart/form-data.
Then Let's simplify this problem - check upload multiple file first.
#PostMapping(URLConstant.URL_SC_ATTACHMENT_POST)
public ResponseEntity<ApiResponse> storeFile(#RequestParam MultipartFile[] files) throws IOException {
Assert.isTrue(files.length == 2, "files length should be 2");
System.out.println(files.length);
return ResponseUtil.getResponse(HttpStatus.OK, MsgConstant.BUDGET_MSG_FILE_UPLOADED, null);
}
If it works well, now time to bring the DTO again.
#PostMapping(URLConstant.URL_SC_ATTACHMENT_POST)
public ResponseEntity<ApiResponse> storeFile(#ModelAttribute List<BudgetSceAttachmentDto> params) throws IOException {
Assert.isTrue(params.length == 2, "files length should be 2");
System.out.println(params.length);
return ResponseUtil.getResponse(HttpStatus.OK, MsgConstant.BUDGET_MSG_FILE_UPLOADED, null);
}

Different encoding of an HTTP request result, depending on the Accept header

I have a controller with a method to upload files, using, on the client side, the dojo Uploader class that supports ajax uploads for all browsers except IE, and uploads with an IFrame for IE.
The result is a JSON object, but when the IFrame mechanism is used, the JSON must be enclosed in a <textarea>:
#RequestMapping(value = "/documentation/{appId:.+}/", method = RequestMethod.POST)
#ResponseBody
public String uploadDocumentation(HttpServletRequest request,
#PathVariable String appId, #RequestParam("uploadedfile") MultipartFile file)
throws Exception {
// ....
String json = JsonUtils.jsonify(map);
if (accepts(request, "application/json")) {
return json;
} else if (accepts(request, "text/html")) {
return "<textarea>" + json + "</textarea>";
} else {
throw new GinaException("Type de retour non supporté");
}
I was wondering if there is a way to register this encoding mechanism in the framework, so that we would just have to return an object, and let the framework do the rest.
Thanks in advance.
For the record, I simply added a second method:
#RequestMapping(value = "/documentation/{appId:.+}/", method = RequestMethod.POST,
produces="application/json")
#ResponseBody
public UploadResult uploadDocumentation(#PathVariable String appId,
#RequestParam("uploadedfile") MultipartFile file) throws Exception {
...
return new UploadResult(filename);
}
#RequestMapping(value = "/documentation/{appId:.+}/", method = RequestMethod.POST,
produces="text/html")
#ResponseBody
public String uploadDocumentationIE(#PathVariable String appId,
#RequestParam("uploadedfile") MultipartFile file) throws Exception {
UploadResult obj = uploadDocumentation(appId, file);
String json = JsonUtils.jsonify(obj);
return "<textarea>" + json + "</textarea>";
}

Resources