GridFSDBFile cannot be cast to org.springframework.web.multipart.MultipartFile - spring

I'm coding a spring mvc webapp that uses images of type MultipartFile which i convert to byte[] and then to Inputstream and store it in MongoDB using GridFsTemplate.
Now the problem is I want to display the stored images in a webpage but whenever I try to, the database returns the image file as GridFSDBFiles and so tosses the following exception:
java.lang.ClassCastException: com.mongodb.gridfs.GridFSDBFile cannot be cast to org.springframework.web.multipart.MultipartFile
This is my DAO for storing images:
public void saveScan(Scan scan) throws IOException {
String owner = String.valueOf(scan.getPatientId());
String fileName = String.valueOf(scan.getPatientId() + "" + scan.getScanType());
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/YYYY HH:mm a");
String uploadTime = simpleDateFormat.format(date);
System.out.println("the scan type is " + scan.getScanType());
DBObject metaData = new BasicDBObject();
metaData.put("owner", owner);
metaData.put("fileName", fileName);
metaData.put("uploadTime", uploadTime);
byte[] scanBytes = scan.getScan().getBytes();
InputStream inputStream = new ByteArrayInputStream(scanBytes);
scanDaoImpl.SaveScan(inputStream, fileName, "image/jpeg", metaData);
}
And this is for retrieving the images:
public MultipartFile findOneScan(BigInteger patientId) {
MultipartFile multipartFile = (MultipartFile) gridFsTemplate
.findOne(new Query(Criteria.where("metadata.owner").is(patientId)));
return multipartFile;
And this is my controller for getting images
#ResponseBody
#RequestMapping(value = "/patients/{id}/scan", produces = MediaType.IMAGE_JPEG_VALUE)
public ResponseEntity<byte[]> scanImage(#PathVariable("id") BigInteger id) throws IOException {
logger.debug("scanImage() is finding Image to display");
byte[] bs = patientScanServiceImpl.findOne(id).getBytes();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.IMAGE_JPEG);
httpHeaders.setCacheControl(CacheControl.noCache().getHeaderValue());
return new ResponseEntity<byte[]>(bs, httpHeaders, HttpStatus.OK);
}
This is my thymeleaf image tag:
<span>
<img th:src="#{/patients/{patientid}/scan(patientid=${patient.id})}" width="250" height="250"/>
</span>

Now I have more insight in this, and I have finally found a solution. You cannot directly cast a gridFSDBFile straight to byte[ ]; it must first be converted to OutputStream and then byte[ ] if it must be displayed. So I allowed my DAO method to return a GridFSDBFile but in the service layer I converted the GridFSDBFile to ByteArrayOutputStream and then to byte[ ].
Now my DAO method for retrieving images is
public GridFSDBFile findOneScan(BigInteger patientId, String scanType) {
String fileName = String.valueOf(patientId + "" + scanType);
GridFSDBFile gridFSDBFile = gridFsTemplate.findOne(new Query(Criteria.where("metadata.fileName").is(fileName)));
return gridFSDBFile;
And my service layer which feeds the controller is
public byte[] findOne(BigInteger patientId, String scanType) throws IOException {
GridFSDBFile gridFSDBFile = scanRepository.findOneScan(patientId, scanType);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
gridFSDBFile.writeTo(outputStream);
byte[] bs = outputStream.toByteArray();
return bs;
}
And the whole thing works fine.

Related

SpringBoot REST produces pdf

I want to generate a dynamic PDF from a SpringBoot REST endpoint. The below generates a file but not a PDF. Any pointers in how to get a PDF file by altering the below code. Thanks in advance.
#GetMapping(value = "/generatePDF", produces = "application/pdf")
#SneakyThrows
public ResponseEntity<InputStreamResource> generatePDF(HttpServletRequest httpRequest,
HttpServletResponse response) {
String str = "Some test data goes here...";
byte[] pdf = str.getBytes();
File file = new File("C:\\test\\test.pdf");
FileUtils.writeByteArrayToFile(file, pdf);
FileInputStream fileInputStream = new FileInputStream(file);
return ResponseEntity.ok().contentLength(file.length())
.contentType(MediaType.APPLICATION_PDF)
.header("content-disposition", "filename=report.pdf")
.body(new InputStreamResource(fileInputStream));
try this
#GetMapping(value = "/generatePDF", produces = "application/pdf")
#SneakyThrows
public ResponseEntity<byte[]> generatePDF(HttpServletRequest httpRequest, HttpServletResponse response) {
String str = "Some test data goes here...";
byte[] pdf = str.getBytes();
File file = new File("C:\\test\\test.pdf");
FileUtils.writeByteArrayToFile(file, pdf);
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_OCTET_STREAM);
header.setContentLength(pdf.length);
header.set("Content-Disposition", "attachment; filename=" + "pdf-" + id + ".pdf");
return new ResponseEntity<>(pdf, header, HttpStatus.OK);
}

Client side code for multipart REST operation

Hi I need to consume a REST operation which accepts a xml payload and a pdf file. Basically a JAXB object is converted to xml string and uploaded in a xml file. So in a multipart request, a xml file and pdf file are uploaded.
The REST operation server side code is as follows:
server side:
public class CompanyType extends MediaType {
public final static final XML_STRING = "applicaiton/company+xml";
}
#POST
#Path("/upload")
#Consumes("multipart/mixed")
#Produces(CompanyType.XML_STRING)
public UploadResponseObject upload(MultiPart multiPart){
UploadRequestObject req = multiPart.getBodyParts().get(0).getEntityAs(UploadRequestObject.class);
BodyPartEntity bpe = (BodyPartEntity) multiPart.getBodyParts().get(1).getEntity();
byte[] pdfBytes = IOUtils.toByteArray(bpe.getInputStream());
....
....
}
client side code to consume REST operation:
#Autowired
private RestTemplate rt;
public UploadResponseObject callMultipartUploadOperation(UploadRequestObject req, java.io.File target) throws Exception {
String url = "http://<host-name>:<port>/service-name/upload");
MultiValueMap<String, Object> mv = new LinkedMultiValueMap<String, Object>();
this.rt = new RestTemplate();
this.rt.setMessageConverters(getMessageConverter());
String id = <random number generated from 1 to 50000>;
// Add xml entity
org.springframework.http.HttpHeaders xmlFileHeaders = new org.springframework.http.HttpHeaders();
xmlFileHeaders.add(MeditType.CONTENT_TYPE, "applicaiton/company+xml");
HttpEntity<String> xmlFile = new HttpEntity<String>(createXMLString(req), xmlFileHeaders);
mv.add(id + ".xml", xmlFile);
// Add pdf file
org.springframework.http.HttpHeaders fileHeaders = new org.springframework.http.HttpHeaders();
fileHeaders.add(MediaType.CONTENT_TYPE, "application/pdf");
FileSystemResource fsr = new FileSystemResource(target);
HttpEntity<FileSystemResource> fileEntity = new HttpEntity<FileSystemResource>(
fsr, fileHeaders);
String filename = target.getName();
mv.add(filename, fileEntity);
HttpEntity<UploadRequestObject> ereq = new HttpEntity<UploadRequestObject>(req, getRequestHeaders());
ResponseEntity<UploadResponseObject> res= this.restTemplate.postForEntity(url, ereq, UploadResponseObject.class);
return res.getBody();
}
private List<HttpMessageConverter<?>> getMessageConverter() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setClassesToBeBound(UploadResponseObject.class);
MarshallingHttpMessageConverter mhmc = new MarshallingHttpMessageConverter(jaxb2Marshaller);
List<org.springframework.http.MediaType> supportedMediaTypes = new ArrayList<org.springframework.http.MediaType>();
supportedMediaTypes.add(new org.springframework.http.MediaType("application", "company+xml"));
mhmc.setSupportedMediaTypes(supportedMediaTypes);
messageConverters.add(mhmc);
// Add Form and Part converters
FormHttpMessageConverter fmc = new FormHttpMessageConverter();
fmc.addPartConverter(new Jaxb2RootElementHttpMessageConverter());
messageConverters.add(fmc);
return messageConverters;
}
When the below line is executed from client code,
ResponseEntity<UploadResponseObject> res= this.rt.postForEntity(url, ereq, UploadResponseObject.class);
the following exception is thrown
org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter
found for request
type [org..types.UploadRequestObject]
and content type [application/company+xml]
Please advise the changes to make the client side code work.
After much trial and error, was able to find the solution for the same.
Client side code:
#Autowired
private RestTemplate rt;
public UploadResponseObject callMultipartUploadOperation(UploadRequestObject req, java.io.File target) throws Exception {
String url = "http://<host-name>:<port>/service-name/upload");
MultiValueMap<String, Object> mv = new LinkedMultiValueMap<String, Object>();
this.rt = new RestTemplate();
this.rt.setMessageConverters(getMessageConverter());
String id = <random number generated from 1 to 50000>;
// Add xml entity
org.springframework.http.HttpHeaders xmlFileHeaders = new org.springframework.http.HttpHeaders();
xmlFileHeaders.add(MeditType.CONTENT_TYPE, "applicaiton/company+xml");
HttpEntity<String> xmlFile = new HttpEntity<String>(createXMLString(req), xmlFileHeaders);
mv.add(id + ".xml", xmlFile);
// Add pdf file
org.springframework.http.HttpHeaders fileHeaders = new org.springframework.http.HttpHeaders();
fileHeaders.add(MediaType.CONTENT_TYPE, "application/pdf");
FileSystemResource fsr = new FileSystemResource(target);
HttpEntity<FileSystemResource> fileEntity = new HttpEntity<FileSystemResource>(
fsr, fileHeaders);
String filename = target.getName();
mv.add(filename, fileEntity);
HttpEntity<UploadRequestObject> ereq = new HttpEntity<UploadRequestObject>(req, getRequestHeaders());
ResponseEntity<UploadResponseObject> res= this.restTemplate.postForEntity(url, ereq, UploadResponseObject.class);
return res.getBody();
}
Message converters:
private List<HttpMessageConverter<?>> getMessageConverter() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setClassesToBeBound(UploadResponseObject.class);
MarshallingHttpMessageConverter mhmc = new MarshallingHttpMessageConverter(jaxb2Marshaller);
List<org.springframework.http.MediaType> supportedMediaTypes = new ArrayList<org.springframework.http.MediaType>();
supportedMediaTypes.add(new org.springframework.http.MediaType("application", "company+xml"));
supportedMediaTypes.add(new org.springframework.http.MediaType("multipart", "form-data"));
mhmc.setSupportedMediaTypes(supportedMediaTypes);
messageConverters.add(mhmc);
// Add Form and Part converters
FormHttpMessageConverter fmc = new FormHttpMessageConverter();
fmc.addPartConverter(new Jaxb2RootElementHttpMessageConverter());
fmc.addPartConverter(new ResourceHttpMessageConverter());
messageConverters.add(fmc);
return messageConverters;
}
Request headers :
private org.springframework.http.HttpHeaders getRequestHeaders(String contentType) throws Exception {
....
.....
org.springframework.http.HttpHeaders httpHeaders = new org.springframework.http.HttpHeaders();
httpHeaders.set("Accept", "applicaiton/company+xml");
httpHeaders.set("Content-Type", "multipart/form-data");
String consumer = "<AppUserId>";
httpHeaders.set("consumer", consumer);
String tmStamp= getCurrentTimeStamp();
httpHeaders.set("timestamp", tmStamp);
...
...
return httpHeaders;
}

How to convert collection to csv with jackson in java spring?

I have a problem to convert a java.util.Collection to a csv file with jackson.
In the following code you can see a method to convert the collection to a csv-string.
But i need a method to convert the collection with com.fasterxml.jackson.
The Enum "DownloadType" get the column and headerlines for csv file.
Do you have an idea to fix them?
#RequestMapping(value = "/csv",
produces = {"text/csv"},
consumes = {"application/json"},
method = RequestMethod.POST)
public ResponseEntity<Object> exportCsv()
{
ResponseEntity<Object> response = null;
try
{
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, "text/csv; charset=UTF-8");
headers.add(HttpHeaders.CACHE_CONTROL, "no-store, must-revalidate");
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=\"export.csv\"");
headers.add(HttpHeaders.EXPIRES, "0");
byte[] csvBytes = null;
byte[] headerBytes = null;
byte[] lineBytes = null;
CsvMapper mapper = new
Collection<User> users = getUsers()
headerBytes = DownloadType.USER.getHeaderLine().getBytes("UTF-8");
lineBytes = mapper.writer(DownloadType.USER.getCsvSchema()).writeValueAsBytes(users);
if (headerBytes != null && lineBytes != null)
{
csvBytes = new byte[headerBytes.length + lineBytes.length];
System.arraycopy(headerBytes, 0, csvBytes, 0, headerBytes.length);
System.arraycopy(lineBytes, 0, csvBytes, headerBytes.length, lineBytes.length);
}
response = new ResponseEntity<>(csvBytes, headers, HttpStatus.OK);
}
catch (Exception e)
{
LOG.error(e.getMessage(), e);
}
return response;
}
Maybe try something like this. By writing the data directly to the servlet response the string will get returned directly back to the client as is without formatting or post-processing.
#RequestMapping(value = "/csv",
produces = {"text/csv"},
consumes = {"application/json"},
method = RequestMethod.POST)
public void exportCsv(HttpServletResponse response)
{
...
String headerString = DownloadType.USER.getHeaderLine()
String data = mapper.writer(DownloadType.USER.getCsvSchema()).writeValueAsString(users);
response.setContentType("text/plain; charset=utf-8");
response.getWriter().print(headerString);
response.getWriter().print(data);
Adapted from:
How to Return CSV Data in Browser From Spring Controller

How to return an Image to browser in rest API in JAVA?

I want to an image while I hit an API like localhost:8080:/getImage/app/path={imagePath}
While I hit this API it will return me an Image.
Is this possible?
Actually, I have tried this but it is giving me an ERROR.
Here is my code,
#GET
#Path("/app")
public BufferedImage getFullImage(#Context UriInfo info) throws MalformedURLException, IOException {
String objectKey = info.getQueryParameters().getFirst("path");
return resizeImage(300, 300, objectKey);
}
public static BufferedImage resizeImage(int width, int height, String imagePath)
throws MalformedURLException, IOException {
BufferedImage bufferedImage = ImageIO.read(new URL(imagePath));
final Graphics2D graphics2D = bufferedImage.createGraphics();
graphics2D.setComposite(AlphaComposite.Src);
// below three lines are for RenderingHints for better image quality at cost of
// higher processing time
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.drawImage(bufferedImage, 0, 0, width, height, null);
graphics2D.dispose();
System.out.println(bufferedImage.getWidth());
return bufferedImage;
}
My ERROR,
java.io.IOException: The image-based media type image/webp is not supported for writing
Is there any way to return an Image while hitting any URL in java?
You can use IOUtils. Here is code sample.
#RequestMapping(path = "/getImage/app/path/{filePath}", method = RequestMethod.GET)
public void getImage(HttpServletResponse response, #PathVariable String filePath) throws IOException {
File file = new File(filePath);
if(file.exists()) {
String contentType = "application/octet-stream";
response.setContentType(contentType);
OutputStream out = response.getOutputStream();
FileInputStream in = new FileInputStream(file);
// copy from in to out
IOUtils.copy(in, out);
out.close();
in.close();
}else {
throw new FileNotFoundException();
}
}
i didn't test it due to i don't have the environment in this machine, but logically it should work like the following, read it as input stream and let your method returns #ResponseBody byte[]
#GET
#Path("/app")
public #ResponseBody byte[] getFullImage(#Context UriInfo info) throws MalformedURLException, IOException {
String objectKey = info.getQueryParameters().getFirst("path");
BufferedImage image = resizeImage(300, 300, objectKey);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", os);
InputStream is = new ByteArrayInputStream(os.toByteArray());
return IOUtils.toByteArray(is);
}
UPDATE
depending on #Habooltak Ana suggestion there is no need to create an input stream, the code should be look like the following
#GET
#Path("/app")
public #ResponseBody byte[] getFullImage(#Context UriInfo info) throws
MalformedURLException, IOException {
String objectKey = info.getQueryParameters().getFirst("path");
BufferedImage image = resizeImage(300, 300, objectKey);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", os);
return os.toByteArray();
}
Just return a file object with correct HTTP-Headers (Content-Type and Content-Disposition) will work in most cases/environments.
Pseudocode
File result = createSomeJPEG();
/*
e.g.
RenderedImage rendImage = bufferedImage;
File file = new File("filename.jpg");
ImageIO.write(rendImage, "jpg", file);
*/
response().setHeader("Content-Disposition", "attachment;filename=filename.jpg;");
response().setHeader("Content-Type", "image/jpeg");
return ok(result);
See also:
file downloading in restful web services
what's the correct way to send a file from REST web service to client?

Spring MVC Thymeleaf: Displaying Buffered Image to HTML file

Can't display the image in the html file. Where did I go wrong?
#RequestMapping(value = "/image/{usr.id}", headers = "Accept=image/jpeg, image/jpg, image/png, image/gif", method = RequestMethod.GET)
public #ResponseBody BufferedImage getImage(#PathVariable("usr.id") Long id) {
Attachment att = attSvc.getPicById(id);
try {
InputStream in = new ByteArrayInputStream(att.getAttachmentFile());
return ImageIO.read(in);
} catch (IOException e) {
System.out.println("ERROR:" + e);
throw new RuntimeException(e);
}
}
Please tell me if you need more references! Thank you so much.
This should solve your issue.
...
public #ResponseBody byte[] getImage(#PathVariable("usr.id") Long id) {
...
InputStream in = new ByteArrayInputStream(att.getAttachmentFile());
BufferedImage img = ImageIO.read(in);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ImageIO.write(img, "jpg", bao);
return bao.toByteArray();
...

Resources