Download file, spring boot e angular 2 - spring-boot

Would you help me?
Hi, I'm having the same problem.
public FileSystemResource patch(#RequestBody List<Especie> especies, HttpServletResponse response) {
filename=\"somefile.pdf\"");
response.setContentType("application/vnd.ms-excel");
response.setHeader("content-disposition", "attachment; filename="+"nomeArquivo"+".xls");
// return new FileSystemResource(new File("xxx"));
Preconditions.checkNotNull(especies);
List<String> nameColumns = especies.get(0).getColumns();
List<IExcel> list = castList(especies);
// List resource = this.service.exportFileExcel(list, nameColumns, response);
File retorno = this.service.exportFileExcel(list, nameColumns, response);
return new FileSystemResource(retorno);
// response.setContentLength(bytes.length); // opcional
// response.getOutputStream().write(bytes);

Related

How to receive an InputStream as #RequestBody in a #PostMapping method in SpringBoot

I am sending an ArrayList object through WebClient in an HTTP POST request after converting it into an InputStream:
List<MyObject> myObjectList = // some data
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutStream = new ObjectOutputStream(byteOutStream);
objectOutStream.writeObject(myObjectList );
objectOutStream.flush();
objectOutStream.close();
byte[] byteArray = byteOutStream.toByteArray();
InputStream inputStream = new ByteArrayInputStream(byteArray);
WebClient client = WebClient.builder()
.baseUrl(URL)
.exchangeStrategies(ExchangeStrategies.builder()
.codecs(configure -> configure.defaultCodecs().maxInMemorySize(64 * 1024 * 1024))
.build())
.build();
Mono<HttpStatus> response = client
.post()
.uri(URI)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
.body(BodyInserters.fromResource(new InputStreamResource(inputStream)))
.exchangeToMono(clientResponse -> Mono.just(clientResponse.statusCode()));
HttpStatus status = response.block();
And at the server side, I am handling this request this way:
#PostMapping(value = "/data", consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Void> saveData(#RequestBody InputStream inputStream) {
try (ObjectInputStream objectInputStream = new ObjectInputStream(inputStream)) {
List<MyObject> myObjectList = (List<MyObject>) objectInputStream.readObject();
LOGGER.info("Payload received : {}", myObjectList);
return new ResponseEntity<>(HttpStatus.OK);
} catch (Exception e) {
LOGGER.error(e.getMessage());
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
But after implementing this, I am getting this error:
[org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream;charset=UTF-8' not supported]
PS: I am converting the ArrayList into an InputStream due to it's large size which is causing java.lang.OutOfMemoryError: Direct buffer memory
First, I tried sending the entire List<> in a request but got OutOfMemoryError. Secondly, using the streaming approach I am getting this error
[org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream;charset=UTF-8' not supported]

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.

Add custom SoapHeader using SpringBoot

Using SoapUI I am able to send a request with a custom SOAP header like this:
<soap:Header>
<To xmlns="http://www.w3.org/2005/08/addressing">ws://xxx.com/PP/QM/GPMService/Vx</To>
<Action xmlns="http://www.w3.org/2005/08/addressing">http://xmldefs.xxx.com/PP/QM/GPMService/Vx/AbcService/GetServiceInfoRequest</Action>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">ITEST-2018-04-16-0001</MessageID>
<Stage xmlns="http://xmldefs.xxx.com/Technical/Addressing/V1">ProdX</Stage>
</soap:Header>
and get a reasonable response.
I can't achieve this in my SpringBoot application.
I have a service extending WebServiceGatewaySupport:
#Service
public class AbcService extends WebServiceGatewaySupport{
private AbcConfiguration abcConfiguration;
#Autowired
public void setAbcConfiguration(final AbcConfiguration abcConfiguration) {
this.abcConfiguration = abcConfiguration;
}
public GetServiceInfoResponse GetServiceInfo() {
final String actionStr = "GetServiceInfo";
final ObjectFactory factory = new ObjectFactory();
GetServiceInfo getServiceInfo = factory.createGetServiceInfo();
JAXBElement<GetServiceInfo> gsiRequest = factory.createGetServiceInfo(getServiceInfo);
WebServiceTemplate wst = this.getWebServiceTemplate();
#SuppressWarnings("unchecked")
JAXBElement<GetServiceInfoResponse> gsiResponse = (JAXBElement<GetServiceInfoResponse>)wst
.marshalSendAndReceive("https://ws-gateway-cert.xxx.com/services/", gsiRequest, new WebServiceMessageCallback() {
#Override
public void doWithMessage(WebServiceMessage message) {
try {
SoapHeader soapHeader = ((SoapMessage) message).getSoapHeader();
SoapHeaderElement toElem = soapHeader.addHeaderElement(new QName("http://www.w3.org/2005/08/addressing", "To"));
toElem.setText("ws://xxx.com/PP/QM/GPMService/Vx");
...
} catch (Exception e) {
logger.error("Error during marshalling of the SOAP headers", e);
}
}
});
return gsiResponse.getValue();
}
}
What am I doing wrong? Can anybody tell me how I can do this?
Okay. I got it working so far and the SOAP XML looks as demanded and running the request (being generated form my SpringBoot app) in SoapUI I get the demanded result.
public GetServiceInfoResponse GetServiceInfo() {
final String actionStr = "GetServiceInfo";
final ObjectFactory factory = new ObjectFactory();
GetServiceInfo getServiceInfo = factory.createGetServiceInfo();
JAXBElement<GetServiceInfo> gsiRequest = factory.createGetServiceInfo(getServiceInfo);
WebServiceTemplate wst = this.getWebServiceTemplate();
#SuppressWarnings("unchecked")
JAXBElement<GetServiceInfoResponse> gsiResponse = (JAXBElement<GetServiceInfoResponse>)wst
.marshalSendAndReceive(kpmConfiguration.getEndpoint(), gsiRequest, new WebServiceMessageCallback() {
#Override
public void doWithMessage(WebServiceMessage message) {
System.out.println(message.toString());
try {
// get the header from the SOAP message
final SoapHeader soapHeader = ((SoapMessage) message).getSoapHeader();
final SaajSoapMessage ssMessage = (SaajSoapMessage)message;
final SOAPEnvelope envelope = ssMessage.getSaajMessage().getSOAPPart().getEnvelope();
System.out.println("envelope.getPrefix(): " + envelope.getPrefix());
envelope.removeNamespaceDeclaration("SOAP-ENV");
envelope.setPrefix(NAMESPACE_PREFIX_SOAP);
System.out.println("envelope.getPrefix(): " + envelope.getPrefix());
envelope.getBody().setPrefix(NAMESPACE_PREFIX_SOAP);
envelope.getHeader().setPrefix(NAMESPACE_PREFIX_SOAP);
envelope.addNamespaceDeclaration(NAMESPACE_PREFIX_SOAP, NAMESPACE_PREFIX_SOAP_DEF);
envelope.addNamespaceDeclaration(NAMESPACE_PREFIX_V2, NAMESPACE_PREFIX_V2_DEF);
envelope.addNamespaceDeclaration(NAMESPACE_PREFIX_WSSE, NAMESPACE_PREFIX_WSSE_DEF);
final SoapHeaderElement toElem = soapHeader.addHeaderElement(new QName(NAMESPACE_PREFIX_ADDRESSING, "To"));
toElem.setText(TO_VALUE);
final SoapHeaderElement actionElem = soapHeader.addHeaderElement(new QName(NAMESPACE_PREFIX_ADDRESSING, "Action"));
actionElem.setText(NAMESPACE_PREFIX_V2_DEF + "/AbcService/" + actionStr + "Request");
final SoapHeaderElement messageIdElem = soapHeader.addHeaderElement(new QName(NAMESPACE_PREFIX_ADDRESSING, "MessageID"));
messageIdElem.setText(MESSAGE_ID_VALUE + UUID.randomUUID());
final SoapHeaderElement stageElem = soapHeader.addHeaderElement(new QName(NAMESPACE_PREFIX_VWA, "Stage"));
stageElem.setText("Production");
final NodeList nl = ssMessage.getSaajMessage().getSOAPPart().getEnvelope().getBody().getChildNodes();
ssMessage.getSaajMessage().getSOAPPart().getEnvelope().getBody().removeChild(nl.item(0));
final SOAPElement se = ssMessage.getSaajMessage().getSOAPPart().getEnvelope().getBody().addBodyElement(new QName(actionStr));
se.setPrefix(NAMESPACE_PREFIX_V2);
final SOAPElement userAuthElem = se.addChildElement(new QName("UserAuthentification"));
final SOAPElement userIdElem = userAuthElem.addChildElement("UserId");
userIdElem.setTextContent(kpmConfiguration.getCredentials().getUsername());
System.out.println(userIdElem.getTextContent());
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(ssMessage.getPayloadSource(), soapHeader.getResult());
} catch (Exception e) {
logger.error("Error during marshalling of the SOAP headers", e);
}
}
});
return gsiResponse.getValue();
}
However, when I submit the request from my SpringBoot app I always get an exception:
java.net.SocketException: Unexpected end of file from server
Am I missing something in the code?
See the answer to the original question above in the edited question.
Concerning the java.net.SocketException: Unexpected end of file from server it seemed to come from redirecting the request through Eclipse's TCP/IP Monitor. When sending the request directly to the server I get a meaningful response with:
INFO_001
Method compelted successfully
:-)

Java Exception getOutputStream() has already been called for this response while downloading file from backend

I have this code in order to download files from backend:
final File file = new File(filePath);
String fileType = Files.probeContentType(file.toPath());
response.setContentType(fileType);
response.setHeader("Content-disposition: attachment;", "filename=\"" + fileName + "\"");
response.setContentLength((int)new File(filePath).length());
final OutputStream os = response.getOutputStream();
IOUtils.copy(is, os);
response.flushBuffer();
os.flush();
os.close();
is.close();
and I get this exception in backend:
java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:578)
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:212)
Does anyone know what I can do in order to prevent this exception?
As far as I know you shouldn't call flush and/or close on the response outputstream
Other way would be to delegate all to Spring controller
I always use this code and I never had problems
#RequestMapping(method = { RequestMethod.GET },
value = { "/file/{idFile}" })
public ResponseEntity<InputStreamResource> downloadCsv(
#PathVariable("idFile") String idFile) {
try {
File file = new File("yourFilePath");
HttpHeaders respHeaders = new HttpHeaders();
//Add your mediaType....mine was csv
MediaType mediaType = new MediaType("text","csv");
respHeaders.setContentType(mediaType);
respHeaders.setContentLength(file.length());
respHeaders.setContentDispositionFormData("attachment", file.getName());
InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
} catch (Exception e) {
String message = "Errore nel download del file "
+ idFile + ".csv; "
+ e.getMessage();
logger.error(message, e);
return new ResponseEntity<InputStreamResource>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
I hope this can be useful
Angelo

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();
}
}
};
}

Resources