I am facing problem while sending an Image using Spring Web Service.
I have written controller as below
#Controller
public class WebService {
#RequestMapping(value = "/image", headers = "Accept=image/jpeg, image/jpg, image/png, image/gif", method = RequestMethod.GET)
public #ResponseBody byte[] getImage() {
try {
InputStream inputStream = this.getClass().getResourceAsStream("myimage.jpg");
BufferedImage bufferedImage = ImageIO.read(inputStream);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write( bufferedImage , "jpg", byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
#ResponseBody converts response into JSON.
I am using RestClient to test Web Service.
But When I'm hitting with http://localhost:8080/my-war-name/rest/image URL.
Header
Accept=image/jpg
I facing following error on RestClient
Response body conversion to string using windows-1252 encoding failed. Response body not set!
When i'm using browsers Chrome and Firefox
Headers are not added so error was expected (Please guide me on this)
HTTP Status 405 - Request method 'GET' not supported
type Status report
message Request method 'GET' not supported
description The specified HTTP method is not allowed for the requested resource (Request method 'GET' not supported).
I have also faced below error once
The resource identified by this request is only capable
of generating responses with characteristics not acceptable according to the request "accept" headers ()
I have followed
http://krams915.blogspot.com/2011/02/spring-3-rest-web-service-provider-and.html tutorial.
My requirment is to send image in byte format to Android Client.
In addition to answer provided by soulcheck. Spring has added produces property to #RequestMapping annotation. Therefore solution is more easier now:
#RequestMapping(value = "/image", method = RequestMethod.GET, produces = "image/jpg")
public #ResponseBody byte[] getFile() {
try {
// Retrieve image from the classpath.
InputStream is = this.getClass().getResourceAsStream("/test.jpg");
// Prepare buffered image.
BufferedImage img = ImageIO.read(is);
// Create a byte array output stream.
ByteArrayOutputStream bao = new ByteArrayOutputStream();
// Write to output stream
ImageIO.write(img, "jpg", bao);
return bao.toByteArray();
} catch (IOException e) {
logger.error(e);
throw new RuntimeException(e);
}
}
The answer by #soulcheck is partially right. The configuration won't work in the latest version of Spring as it would clash with mvc-annotation element. Try the below configuration.
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
Once you have above configuration in your config file. The below code will work:
#RequestMapping(value = "/image", headers = "Accept=image/jpeg, image/jpg, image/png, image/gif", method = RequestMethod.GET)
public #ResponseBody BufferedImage getImage() {
try {
InputStream inputStream = this.getClass().getResourceAsStream("myimage.jpg");
return ImageIO.read(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
See this article on the excellent baeldung.com website.
You can use the following code in your Spring Controller:
#RequestMapping(value = "/rest/getImgAsBytes/{id}", method = RequestMethod.GET)
public ResponseEntity<byte[]> getImgAsBytes(#PathVariable("id") final Long id, final HttpServletResponse response) {
HttpHeaders headers = new HttpHeaders();
headers.setCacheControl(CacheControl.noCache().getHeaderValue());
response.setContentType(MediaType.IMAGE_JPEG_VALUE);
try (InputStream in = imageService.getImageById(id);) { // Spring service call
if (in != null) {
byte[] media = IOUtils.toByteArray(in);
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(media, headers, HttpStatus.OK);
return responseEntity;
}
} catch (IOException e) {
e.printStackTrace();
}
return new ResponseEntity<>(null, headers, HttpStatus.NOT_FOUND);
}
Notes: IOUtils comes from common-io apache library. I am using a Spring Service to retrieve img/pdf Blobs from a database.
Similar handling for pdf files, except that you need to use MediaType.APPLICATION_PDF_VALUE in the content type. And you can refer the image file or the pdf file from an html page:
<html>
<head>
</head>
<body>
<img src="https://localhost/rest/getImgDetectionAsBytes/img-id.jpg" />
<br/>
Download pdf
</body>
</html>
... or you can call the web service method directly from your browser.
Drop conversion to json and sent the byte array as-is.
The only drawback is that it sends application/octet-stream content type by default.
If that doesn't suite you you can use BufferedImageHttpMessageConverter which can send any image type supported by registered image readers.
Then you can change your method to:
#RequestMapping(value = "/image", headers = "Accept=image/jpeg, image/jpg, image/png, image/gif", method = RequestMethod.GET)
public #ResponseBody BufferedImage getImage() {
try {
InputStream inputStream = this.getClass().getResourceAsStream("myimage.jpg");
return ImageIO.read(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
while having :
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="order" value="1"/>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
</list>
</property>
</bean>
in your spring config.
Here's the method I wrote for this.
I needed to both display the image inline on a page, and optionally download it to the client, so I take an optional parameter to set the appropriate header for that.
Document is my entity model to represent documents. I have the files themselves stored on disc named after the ID of the record that stores that document. The original filename and mime type are stored in the Document object.
#RequestMapping("/document/{docId}")
public void downloadFile(#PathVariable Integer docId, #RequestParam(value="inline", required=false) Boolean inline, HttpServletResponse resp) throws IOException {
Document doc = Document.findDocument(docId);
File outputFile = new File(Constants.UPLOAD_DIR + "/" + docId);
resp.reset();
if (inline == null) {
resp.setHeader("Content-Disposition", "attachment; filename=\"" + doc.getFilename() + "\"");
}
resp.setContentType(doc.getContentType());
resp.setContentLength((int)outputFile.length());
BufferedInputStream in = new BufferedInputStream(new FileInputStream(outputFile));
FileCopyUtils.copy(in, resp.getOutputStream());
resp.flushBuffer();
}
If you are using spring boot, just placing the images in the right folder in your classpath will do the trick. Check https://www.baeldung.com/spring-mvc-static-resources
Related
I'm using SpringBoot 3.0.1 and I'm trying to get a file stored in the backend using Axios.
The controller is the following:
#GetMapping(value = "/api/files/{fileName}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<?> getFile(final #PathVariable("fileName") String fileName) {
try {
Path filePath = Path.of(fileName);
File file = filePath.toFile();
HttpHeaders responseHeaders = new HttpHeaders();
String filename = filePath.getFileName().toString();
responseHeaders
.setContentDisposition(ContentDisposition.builder("attachment")
.filename(filename, StandardCharsets.UTF_8)
.build());
FileSystemResource fileSystemResource = new FileSystemResource(file);
return ResponseEntity
.ok()
.headers(responseHeaders)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(file.length())
.lastModified(file.lastModified())
.body(fileSystemResource);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
When I get the answer (status is 200), the header I've set in the controller is not given. In particular, the Content-Disposition header is not defined in the answer.
I'm wondering if there is any missing configuration that must be set in Sprint Boot in order to be allowed to set a custom header. Anyone who knows what can cause this and how to fix it?
I am getting this error:
the request was rejected because no multipart boundary was found
when I upload an image through postman like this: I have saveImage as url, in header I have content/type and multipart/form-data and choossed raw and uploaded an image.
This is my controller:
#RequestMapping(value = "/saveImage",
method = RequestMethod.POST,
consumes = "application/json", produces = "application/json;charset=UTF-8")
public #ResponseBody ResponseEntity<GenericResponseVO<? extends IServiceVO>> getImage(
#RequestBody(required = false) GenericRequestVO<ImageCriteriaVO> imageCriteriaVO,HttpServletRequest request, HttpServletResponse response ) {
return requestHandlerInvoker.callHandler(
HandlerName.SAVE_IMAGE_HANDLER,request,response,imageCriteriaVO);
}
This my handler:
public GenericResponseVO<? extends IServiceVO> handleRequest(
UserContext userCtx, HttpServletRequest httpRequest,
HttpServletResponse httpResponse,
GenericRequestVO<? extends IServiceVO> requestVO)
throws O2Exception {
GenericResponseVO<ImageResultVO> imageVO = new GenericResponseVO<ImageResultVO>();
ImageResultVO imageResultVO = (ImageResultVO) serviceInvoker
.callService(ServiceName.IMAGE_SERVICE, userCtx,requestVO.getBody());
imageVO.setBody(imageResultVO);
imageVO.getHeader().setStatus(new Status(Status.SUCCESS, "Token"));
return imageVO;
This my service:
public IServiceVO service(UserContext userCtx, IServiceVO inputVO)
throws O2Exception {
LOG.info(LoggingEvent.Image_INPROGRESS,"Inside get list of treasure hunt for corporate service");
ImageCriteriaVO imageCriteriaVO = (ImageCriteriaVO) inputVO;
System.out.println(imageCriteriaVO.getFile());
ImageResultVO imageResultVO = new ImageResultVO();
CommonsMultipartFile file = null;
String fileName = null;
if (!file.isEmpty()) {
try {
fileName = file.getOriginalFilename();
byte[] bytes = file.getBytes();
BufferedOutputStream buffStream =
new BufferedOutputStream(new FileOutputStream(new File("F:/" + fileName)));
buffStream.write(bytes);
buffStream.close();
}catch (Exception e) {
}
}
return imageResultVO;
}
This my criteria class:
public class ImageCriteriaVO implements IServiceVO{
private byte[] file;
public byte[] getFile() {
return file;
}
public void setFile(byte[] file) {
this.file = file;
}
}
I hope this answer may help
Remove Content-Type from header when you are trying to upload, Postman will do it automatically.
if you set Content-Type: undefined, Postman will automatically sets Content-Type to multipart/form-data and depending upon the media it will set boundary.
Mail user agents ignore content-disposition headers in the messages.
File name should be mentioned in filename parameter. Otherwise should be mentioned in both filename and the name parameters5
multipart/form-data with Angular JS
I have write a simple Spring + Angular application just for learn more about it.
I have a spring controller which is mapped to a URL and when an request comes it returns an image.
I have written all the codes and the spring controller returns me the image but when i set it in the HTML it is not displayed correctly
here is my spring controller
#RequestMapping(value = "image/", method = RequestMethod.GET)
public ResponseEntity<byte[]> getChequeImage(HttpSessionsession,#PathVariable("itemId") Integer itemId,
HttpServletResponse response) {
try{
InputStream in = new FileInputStream(new File("path_to_image.jpg"));
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.OK);
}catch (IOException e){
LOGGER.error(e);
e.getMessage(), response);
return null;
}
}
here is my HTML code
<img src="{{image}}"/>
image is an Angular variable. Angular service is sending the request and binding the data to the image variable
here is the angular code
#scope.image = "data:image/jpg," + data_from_the_api;
You can't use raw image bytes directly on the page, but you can do Base64 encoding, this would be the adaptations
#RequestMapping(value = "image/", method = RequestMethod.GET)
public ResponseEntity<String> getChequeImage(HttpSessionsession,#PathVariable("itemId") Integer itemId,
HttpServletResponse response) {
try{
InputStream in = new FileInputStream(new File("path_to_image.jpg"));
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
byte[] binaryData = IOUtils.toByteArray(in)
byte[] encodeBase64 = Base64.encodeBase64(binaryData);
String base64Encoded = new String(encodeBase64, "UTF-8");
return new ResponseEntity<String>(base64Encoded , headers, HttpStatus.OK);
}catch (IOException e){
LOGGER.error(e);
e.getMessage(), response);
return null;
}
}
and as TechMa9iac said in the comment you should set #scope.image = "data:image/jpg;base64," + data_from_the_api;
i have a requirement where i get byte array (byte[]) data from database, i need to save this data in a file and allow the user to save where ever he want to save, same as downloading the attachments.The file name and extension also i'm retrieving from database. I'm using java,spring-mvc for this.
Below is the code:
spring controller:
#RequestMapping(value="/getFile", method = RequestMethod.GET)
public ModelAndView getFile(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//logic to get the data from database
byte[] documentData = document.getDOCUMENTData();
String documentName = document.getDOCUMENTTITLE();
String documentExt = document.getDocumentExtension();
}
Please suggest, i know that using java.io.*, i can write the byte[] data in file and give file name and extension by taking the values declared above, but how can i allow users when clicked on "download file" icon to write the data and save that file where ever he wants same as downloading the attachment.Please suggest. Once user clicks on download file icon control comes to above controller.Thanks.
--EDIT--
Modified code:
#RequestMapping(value="/getFile", method = RequestMethod.GET)
public ModelAndView getFile(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//logic to get the data from database
byte[] documentData = document.getDOCUMENTData();
String documentName = document.getDOCUMENTTITLE();
String documentExt = document.getDocumentExtension();
response.setHeader("Content-Disposition", "attachment;filename="+userDoc.getDOCUMENT_TITLE());
long l = userDoc.getDOCUMENT_SIZE();
int size = (int)l;
response.setContentLength(size);
response.getWriter().write("hello");//i need to write byte[] but for test i kept string.
}
I want user to see save window so that he can save where ever he want same as downloading the attachments from mail.Thanks.
This is a code I'm usign for the same request
HTML page:
<h:commandButton value="Click Here to Download" action="#{reportBean.download}" />
BEAN:
public void download(){
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.setHeader("Content-Disposition", "attachment;filename="+file.getName());
response.setContentLength((int) file.length());
ServletOutputStream out = null;
try {
FileInputStream input = new FileInputStream(file);
byte[] buffer = new byte[1024];
out = response.getOutputStream();
int i = 0;
while ((i = input.read(buffer)) != -1) {
out.write(buffer);
out.flush();
}
FacesContext.getCurrentInstance().getResponseComplete();
input.close();
} catch (IOException err) {
err.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException err) {
err.printStackTrace();
}
}
}
Just make sure you have a File object named file
You have two options to achieve this:
One is to write the file in your server's local filesystem in an internet accesible folder. You can configure which of your server's local folders are accesible from internet in your Apache/IIS serttings. Then you update your HTML so your "download file" link points to that file through an URL.
The other option is, like #an3sarmiento did, to return the file as a byte[] stream to the browser. For this option to work, you have to send, along with the file content, a response header in which you tell the browser you are returning a downloadable file as a stream. You do that with the line:
response.setHeader("Content-Disposition", "attachment;filename="+[your file name]);
response.setContentLength([your file's length or bytes count]);
response.getWriter.write([your file's content as byte array]);
In the line above I assume you are working with Java Servlets and you have an HttpServletResponse variable named reponse, which you will respond to the browser's HTTP POST or GET request.
My goal is to merge/minify all css files and return the result as String.
Here's my Spring test method :
#RequestMapping(value = "/stylesheet.css", method = RequestMethod.GET, produces = "text/css")
#ResponseBody
public void css(HttpServletResponse response) {
File path = new File(servletContext.getRealPath("/WEB-INF/includes/css/"));
File[] files = path.listFiles(...);
for (File file : files) {
InputStream is = new FileInputStream(file);
IOUtils.copy(is, response.getOutputStream());
response.flushBuffer();
is.close();
}
}
This is working with Chrome, Firefox and Safari but not with IE and Opera.
After some checks in the inspectors, the URL https://host/project/stylesheet.css is loading in each browsers. I can see the content but it does not seem to be recognized as text/css.
Also, even with produces = "text/css", I can not see the content-type http header in all browsers.
Error log in IE :
CSS ignored because of mime type incompatibility
Does anyone know how to correctly do this?
Working code :
#RequestMapping(value = "/stylesheet.css", method = RequestMethod.GET)
public ResponseEntity<Void> css(HttpServletResponse response) {
response.setContentType("text/css");
File path = new File(servletContext.getRealPath("/WEB-INF/includes/css/"));
File[] files = path.listFiles(...);
for (File file : files) {
InputStream is = new FileInputStream(file);
IOUtils.copy(is, response.getOutputStream());
IOUtils.closeQuietly(is);
}
response.flushBuffer();
return new ResponseEntity<Void>(HttpStatus.OK);
}
I suspect the problem is due to your usage of HttpServletResponse.flushBuffer().
As the API of HttpServletRequest states:
Forces any content in the buffer to be written to the client. A call
to this method automatically commits the response, meaning the status
code and headers will be written.
My assumption would be that Spring attempts to set the Content-Type header on the HttpServletResponse after the method on your controller has returned. However, because you have committed the response with your call to HttpServletResponse.flushBuffer(), it cannot do this.
I would try either:
Injecting the HttpServletResponse into your controller and setting the header yourself in code before calling HttpServletResponse.flushBuffer()
Removing your usage of HttpServletRequest.flushBuffer()
Since you're writing the content directly to the output stream, you don't need to use #ResponseBody. You just need to ensure that you set the Content-Type response header. Also, it'd be better to return a ResponseEntity (rather than void) to indicate to Spring that you're handling the response yourself.
#RequestMapping(value = "/stylesheet.css", method = RequestMethod.GET)
public ResponseEntity css(HttpServletResponse response) {
// Set the content-type
response.setHeader("Content-Type", "text/css");
File path = new File(servletContext.getRealPath("/WEB-INF/includes/css/"));
File[] files = path.listFiles(...);
for (File file : files) {
InputStream is = new FileInputStream(file);
IOUtils.copy(is, response.getOutputStream());
IOUtils.closeQuietly(is);
}
response.flushBuffer();
return new ResponseEntity(HttpStatus.OK)
}