read data from MultipartFile which has csv uploaded from browser - spring

May be I am doing it worng by using MultipartFile upload feature.
I have to read data from csv file which will be chosen by the client through the browser. I used MultipartFile to upload file. The file is coming to the controller but now I am unable to read csv data from it. Please guide the best way to do it or help me read csv data from MultipartFile.
The jsp has
<form method="POST" action="uploadFile" enctype="multipart/form-data">
File to upload: <input type="file" name="file"> <input
type="submit" value="Upload"> Press here to upload the
file!
</form>
The controller has
#RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
public String uploadFileHandler(#RequestParam("file") MultipartFile file) {
Thanks.

I used a buffer to read line by line and get from multipart the inputstream. Maybe is more code, but I find helpful read text file by lines.
BufferedReader br;
List<String> result = new ArrayList<>();
try {
String line;
InputStream is = multipart.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
result.add(line);
}
} catch (IOException e) {
System.err.println(e.getMessage());
}

I figured out a workaround. I converted the file to bytes and then converted the bytes to String. From String I applied string.split() to get what I wanted out of the file.
#RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
public String uploadFileHandler(#RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
String completeData = new String(bytes);
String[] rows = completeData.split("#");
String[] columns = rows[0].split(",");

The best solution that I found was
#PostMapping(value="/csv")
public ResponseEntity<Void> processUpload(#RequestParam MultipartFile file) {
BufferedReader fileReader = new BufferedReader(new
InputStreamReader(file.getInputStream(), "UTF-8"));
CSVParser csvParser = new CSVParser(fileReader, CSVFormat.DEFAULT);
Iterable<CSVRecord> csvRecords = csvParser.getRecords();
for (CSVRecord csvRecord : csvRecords) {
System.out.println(csvRecord);
}
...
This is an adaptative solution from https://bezkoder.com/spring-boot-upload-csv-file/

Related

How to use MockMVC test the controller which use org.apache.commons.fileupload?

My Controller use " org.apache.commons.fileupload " realized the file UPload.
see it:
#PostMapping("/upload")
public String upload2(HttpServletRequest request) throws Exception {
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iter = upload.getItemIterator(request);
boolean uploaded = false;
while (iter.hasNext() && !uploaded) {
FileItemStream item = iter.next();
if (item.isFormField()) {
item.openStream().close();
} else {
String fieldName = item.getFieldName();
if (!"file".equals(fieldName)) {
item.openStream().close();
} else {
InputStream stream = item.openStream();
// dosomething here.
uploaded = true;
}
}
}
if (uploaded) {
return "ok";
} else {
throw new BaseResponseException(HttpStatus.BAD_REQUEST, "400", "no file field or data file is empty.");
}
}
and my MockMvc code is
public void upload() throws Exception {
File file = new File("/Users/jianxiaowen/Documents/a.txt");
MockMultipartFile multipartFile = new MockMultipartFile("file", new FileInputStream(file));
HashMap<String, String> contentTypeParams = new HashMap<String, String>();
contentTypeParams.put("boundary", "----WebKitFormBoundaryaDEFKSFMY18ehkjt");
MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post(baseUrl+"/upload")
.content(multipartFile.getBytes())
.contentType(mediaType)
.header(Origin,OriginValue)
.cookie(cookie))
.andReturn();
logResult(mvcResult);
}
my controller is right , it has successed in my web project,
but I want to test it use MvcMock, it has some mistake, see :
can someOne can help me?
"status":"400","msg":"no file field or data file is empty.","data":null
I don't know why it says my file is empty.
my English is poor, thank you very much if someone can help me.
The MockMvc can be used for integration testing for controllers using Apache Commons Fileupload too!
Import the org.apache.httpcomponents:httpmime into your pom.xml or gradle.properties
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.13</version>
</dependency>
Update the code to use MultipartEntityBuilder to build the multipart request on the client, and then serialize the entity into bytes, which is then set in the request content
public void upload() throws Exception {
File file = new File("/Users/jianxiaowen/Documents/a.txt");
String boundary = "----WebKitFormBoundaryaDEFKSFMY18ehkjt";
// create 'Content-Type' header for multipart along with boundary
HashMap<String, String> contentTypeParams = new HashMap<String, String>();
contentTypeParams.put("boundary", boundary); // set boundary in the header
MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);
// create a multipart entity builder, and add parts (file/form data)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
HttpEntity multipartEntity = MultipartEntityBuilder.create()
.addPart("file", new FileBody(file, ContentType.create("text/plain"), file.getName())) // add file
// .addTextBody("param1", "value1") // optionally add form data
.setBoundary(boundary) // set boundary to be used
.build();
multipartEntity.writeTo(outputStream); // or getContent() to get content stream
byte[] content = outputStream.toByteArray(); // serialize the content to bytes
MvcResult mvcResult = mockMvc.perform(
MockMvcRequestBuilders.post(baseUrl + "/upload")
.contentType(mediaType)
.content(content) // finally set the content
.header(Origin,OriginValue)
.cookie(cookie)
).andReturn();
logResult(mvcResult);
}
Can you try the below?
mockMvc.perform(
MockMvcRequestBuilders.multipart(baseUrl+"/upload")
.file(multiPartFile)
).andReturn();
Update:
You need to update the controller to handle the MultipartFile:
#PostMapping("/upload")
public String upload2(#RequestParam(name="nameOfRequestParamWhichContainsFileData")
MultipartFile uploadedFile, HttpServletRequest request) throws Exception {
//the uploaded file gets copied to uploadedFile object.
}
You need not use another library for managing file uploads. You can use the file upload capabilities provided by Spring MVC.

SpringBoot base64 pdf downloading

When user makes a get request this should download a pdf file, so far I am getting base64 of the pdf file but I don't know how to download. Can someone help me out?
#ResponseBody
#GetMapping("/download/pdf/{uuid}/{userid}")
public String downloadPdf (#PathVariable String uuid,#PathVariable String userid, Model model) {
JSONObject jsonObject = RequestHelper.getResponse("pdf", uuid);
JSONArray d =(JSONArray) jsonObject.get("data");
String str = (String) d.get(0);
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
// I have base64 pdf how can I start downloading this pdf
return("file downloaded");
}
Add Rest Controller to spring boot project and below method to download pdf file from base64 content.
Assign the pdf base64 string to content variable.
#GetMapping(value = "/donw1")
public ResponseEntity<Resource> donw1() {
logger.info("Start the file processing");
String content = "<<Add_pdf_base64 content here>>";
byte[] decoder = Base64.getDecoder().decode(content);
InputStream is = new ByteArrayInputStream(decoder);
InputStreamResource resource = new InputStreamResource(is);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
ContentDisposition disposition = ContentDisposition.attachment().filename("textdown.pdf").build();
headers.setContentDisposition(disposition);
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}

Angular 4 and Spring Rest: How to post FormData containing File and model object in a single request

I would like to send a File object along with custom model object in a single request.
let formData:FormData = new FormData();
let file = this.fileList[0];
formData.append('file', file, file.name);
formData.append('address', JSON.stringify(customObj));
...
this.http.post(fileServeUrl, formData)
My backend is in Spring Rest as below
#RequestMapping(value = "/fileServe",
produces = {"application/json"},
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE},
method = RequestMethod.POST)
ResponseEntity<Image> uploadFile(#RequestPart("file") MultipartFile imageData, #RequestPart("address") Address address) throws IOException {...}
I was able to receive the data if I pass simple String along with File though.
formData.append('file', file, file.name);
formData.append('address', addressText);
Backend
#RequestMapping(value = "/fileServe",
produces = {"application/json"},
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE},
method = RequestMethod.POST)
ResponseEntity<Image> uploadFile(#RequestPart("file") MultipartFile imageData, #RequestPart("address") String addressText) throws IOException {...}
I tried #RequestBody for my custom object but even that didn't work. Any advise please.
The problem with #Requestbody and #RequestPart annotation is that spring use the HttpMessageConverter to take convert the incoming json message into the your object. As you send form data with a file and a text value spring can not convert it into your object. I am afraid you have to pass the value of address seperatetly.
#RequestMapping(value = "/fileupload", headers = ("content-type=multipart/*"), method = RequestMethod.POST)
public ResponseEntity<AjaxResponseBody> upload(#RequestParam("file") MultipartFile file, #RequestParam String name, #RequestParam String postCode) {
AjaxResponseBody result = new AjaxResponseBody();
HttpHeaders headers = new HttpHeaders();
if (!file.isEmpty()) {
try {
Address address = new Address();
address.setName(name);
result.setMsg("ok");
return new ResponseEntity<AjaxResponseBody>(result, headers, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<AjaxResponseBody>(HttpStatus.BAD_REQUEST);
}
} else {
return new ResponseEntity<AjaxResponseBody>(HttpStatus.BAD_REQUEST);
}
}
Expept if you find a way your client app send a file with MimeType of image/jpg and and an address of application/json which allow spring to parse the json and map to your Address object which i couldn't do it.

spring : get response as Multipart File from REST WebService

I am creating POC for RESTFUL Web service using Spring 4.0. Requirement is to receive MultipartFile as Response from REST WEB-Service.
REST Service Controller
#RequestMapping(value="/getcontent/file", method=RequestMapping.post)
public MultipartFile getMultipartAsFileAsObject() {
File file = new File("src/test/resources/input.docx");
FileInputStream input = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile("file",file.getName(),
"application/docx", IOUtils.toByteArray(input));
return multipartFile
}
I call this service using third party Clients and Apache Http Client as well. kindly have a look on output.
Using Third party REST client ie. Postman
output looks like Json -
{
"name" : "file",
"originalfilename" : "sample.docx",
"contentType" : "application/docx",
"content" : [
82,
101,
97,
100,
101,
32,
32,
.
.
.
.
.
]
}
Apache HTTP Client Sample code
private static void executeClient() {
HttpClient client = new DefaultHttpClient();
HttpPost postReqeust = new HttpPost(SERVER_URI);
try{
// Set Various Attributes
HttpResponse response = client.execute(postReqeust) ;
//Verify response if any
if (response != null)
{
InputStream inputStream = response.getEntity().getContent();
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
OutputStream outputStream = new FileOutputStream
(new File("src/main/resource/sample.docx"));
outputStream.write(buffer);
outputStream.flush();
outputStream.close();
}
}
catch(Exception ex){
ex.printStackTrace();
}
Output of Apache Http client
file is getting Created but It is empty. (0 bytes).
I found some interesting answers from multiple stackoverflow questions.
Links are given below
file downloading in restful web services
what's the correct way to send a file from REST web service to client?
For Sending single file : (copied from above sources)
#GET
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile() {
File file = ... // Initialize this to the File path you want to serve.
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();
}
For Sending Zip file : (copied from above sources)
1) Approach First :
You can use above method to send any file / Zip.
private static final String FILE_PATH = "d:\\Test2.zip";
#GET
#Path("/get")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile() {
File file = new File(FILE_PATH);
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename=newfile.zip");
return response.build();
}
2) Approach Second :
#GET
#Path("/get")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public StreamingOutput helloWorldZip() throws Exception {
return new StreamingOutput(){
#Override
public void write(OutputStream arg0) throws IOException, WebApplicationException {
// TODO Auto-generated method stub
BufferedOutputStream bus = new BufferedOutputStream(arg0);
try {
Thread.currentThread().getContextClassLoader().getResource("");
File file = new File("d:\\Test1.zip");
FileInputStream fizip = new FileInputStream(file);
byte[] buffer2 = IOUtils.toByteArray(fizip);
bus.write(buffer2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}

SpringBoot: Large Streaming File Upload Using Apache Commons FileUpload

Am trying to upload a large file using the 'streaming' Apache Commons File Upload API.
The reason I am using the Apache Commons File Uploader and not the default Spring Multipart uploader is that it fails when we upload very large file sizes (~2GB). I working on a GIS application where such file uploads are pretty common.
The full code for my file upload controller is as follows:
#Controller
public class FileUploadController {
#RequestMapping(value="/upload", method=RequestMethod.POST)
public void upload(HttpServletRequest request) {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
// Inform user about invalid request
return;
}
//String filename = request.getParameter("name");
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
try {
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (item.isFormField()) {
System.out.println("Form field " + name + " with value " + Streams.asString(stream) + " detected.");
} else {
System.out.println("File field " + name + " with file name " + item.getName() + " detected.");
// Process the input stream
OutputStream out = new FileOutputStream("incoming.gz");
IOUtils.copy(stream, out);
stream.close();
out.close();
}
}
}catch (FileUploadException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
#RequestMapping(value = "/uploader", method = RequestMethod.GET)
public ModelAndView uploaderPage() {
ModelAndView model = new ModelAndView();
model.setViewName("uploader");
return model;
}
}
The trouble is that the getItemIterator(request) always returns an iterator that does not have any items (i.e. iter.hasNext() ) always returns false.
My application.properties file is as follows:
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:19095/authdb
spring.datasource.username=georbis
spring.datasource.password=asdf123
logging.level.org.springframework.web=DEBUG
spring.jpa.hibernate.ddl-auto=update
multipart.maxFileSize: 128000MB
multipart.maxRequestSize: 128000MB
server.port=19091
The JSP view for the /uploader is as follows:
<html>
<body>
<form method="POST" enctype="multipart/form-data" action="/upload">
File to upload: <input type="file" name="file"><br />
Name: <input type="text" name="name"><br /> <br />
Press here to upload the file!<input type="submit" value="Upload">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
</html>
What might I be doing wrong?
Thanks to some very helpful comments by M.Deinum, I managed to solve the problem. I have cleaned up some of my original post and am posting this as a complete answer for future reference.
The first mistake I was making was not disabling the default MultipartResolver that Spring provides. This ended up in the resolver processing the HttpServeletRequest and thus consuming it before my controller could act on it.
The way to disable it, thanks to M. Deinum was as follows:
multipart.enabled=false
However, there was still another hidden pitfall waiting for me after this. As soon as I disabled default multipart resolver, I started getting the following error when trying to make an upload:
Fri Sep 25 20:23:47 IST 2015
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported
In my security configuration, I had enabled CSRF protection. That necessitated that I send my POST request in the following manner:
<html>
<body>
<form method="POST" enctype="multipart/form-data" action="/upload?${_csrf.parameterName}=${_csrf.token}">
<input type="file" name="file"><br>
<input type="submit" value="Upload">
</form>
</body>
</html>
I also modified my controller a bit:
#Controller
public class FileUploadController {
#RequestMapping(value="/upload", method=RequestMethod.POST)
public #ResponseBody Response<String> upload(HttpServletRequest request) {
try {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
// Inform user about invalid request
Response<String> responseObject = new Response<String>(false, "Not a multipart request.", "");
return responseObject;
}
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (!item.isFormField()) {
String filename = item.getName();
// Process the input stream
OutputStream out = new FileOutputStream(filename);
IOUtils.copy(stream, out);
stream.close();
out.close();
}
}
} catch (FileUploadException e) {
return new Response<String>(false, "File upload error", e.toString());
} catch (IOException e) {
return new Response<String>(false, "Internal server IO error", e.toString());
}
return new Response<String>(true, "Success", "");
}
#RequestMapping(value = "/uploader", method = RequestMethod.GET)
public ModelAndView uploaderPage() {
ModelAndView model = new ModelAndView();
model.setViewName("uploader");
return model;
}
}
where Response is just a simple generic response type I use:
public class Response<T> {
/** Boolean indicating if request succeeded **/
private boolean status;
/** Message indicating error if any **/
private String message;
/** Additional data that is part of this response **/
private T data;
public Response(boolean status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
// Setters and getters
...
}
If you're using a recent version of spring boot (I'm using 2.0.0.M7) then the property names have changed.
Spring started using technology specific names
spring.servlet.multipart.maxFileSize=-1
spring.servlet.multipart.maxRequestSize=-1
spring.servlet.multipart.enabled=false
If you're getting StreamClosed exceptions caused by multiple implementations being active, then the last option allows you to disable the default spring implementation
Please try to add spring.http.multipart.enabled=false in application.properties file.
I use kindeditor + springboot. When I use (MultipartHttpServletRequest) request. I could get the file, but I use appeche-common-io:upload.parse(request) the return value is null.
public BaseResult uploadImg(HttpServletRequest request,String type){
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultiValueMap<String, MultipartFile> multiFileMap = multipartRequest.getMultiFileMap();
You Can simply add spring properties:
spring.servlet.multipart.max-file-size=20000KB
spring.servlet.multipart.max-request-size=20000KB
here my maximum file size is 20000KB, you can change if required.

Resources