0

I am using Spring MVC 3.2.2.RELEASE, and this is my first attempt at using Spring's Java based configuration (@Configuration).

I have a controller that I use to handle certain files. The content of the files is read by my service method MyContentService.getResource(String). At the moment, the content type is always text/html.

How can I config my Spring MVC application so that it correctly sets the type of the content returned? The content type can only be determined at runtime.

My controller at the moment, which incorrectly always sets the type to text/html:

@Controller
public class MyContentController {

    MyContentService contentService;

    @RequestMapping(value = "content/{contentId}")
    @ResponseBody
    public byte[] index(@PathVariable String contentId) {
        return contentService.getResource(contentId);
    }
}

EDIT: The following method works (with PNG and JPEG files), but I am not comfortable with URLConnection determining the content type (e.g. PDF, SWF, etc):

@RequestMapping(value = "content/{contentId}/{filename}.{ext}")
public ResponseEntity<byte[]> index2(@PathVariable String contentId, @PathVariable String filename, @PathVariable String ext, HttpServletRequest request) throws IOException {
    byte[] bytes = contentService.getResource(contentId);

    String mimeType = URLConnection.guessContentTypeFromName(filename + "." + ext);
    if (mimeType != null) {
        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.valueOf(mimeType));
        return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
    } else {
        logger.warn("Unable to determine the mimeType for " + getRequestedUrl(request));
        return new ResponseEntity<byte[]>(HttpStatus.NOT_FOUND);
    }
}
vegemite4me
  • 6,621
  • 5
  • 53
  • 79
  • Return a `ResponseEntity` or `HttpEntity` and set the content type. – M. Deinum Aug 27 '14 at 12:33
  • You may try the `produces` attribute, which sets the `Content-Type` header of the response to the provided value, e.g.: `@RequestMapping(value = "content/{contentId}", produces = "application/octet-stream")`. – sp00m Aug 27 '14 at 12:34
  • You may add `consumes` and `produces` to your `RequestMapping`. – TJ- Aug 27 '14 at 12:34
  • @sp00m & @TJ: The problem with setting the `produces` attribute is that I do not know the type of file being requested. It could be an image, MP4, PDF, whatever, etc. – vegemite4me Aug 27 '14 at 12:56
  • @M.Deinum I have got `ResponseEntity` working (see my edit), but I am not sure how reliable `URLConnection.guessContentFromName()` is. – vegemite4me Aug 27 '14 at 12:58
  • 1
    You might want to use the `javax.activitation.FileTypeMap` instead. – M. Deinum Aug 27 '14 at 13:06
  • @M.Deinum Please submit `FileTypeMap` as an answer. It appears to handle far more types than `URLConnection`. – vegemite4me Aug 27 '14 at 13:14

1 Answers1

2

Currently you are only returning a byte[] which doesn't hold much information, only the actual content (as a byte[]).

You can wrap the byte[] in a HttpEntity or ResponseEntity and set the appropriate content type on that. Spring MVC will use the content type of the entity to set the actual content type to the response.

To determine the filetype you can use the FileTypeMap of the javax.activation framework or use a library (see Getting A File's Mime Type In Java).

@RequestMapping(value = "content/{contentId}")
@ResponseBody
public HttpEntity index(@PathVariable String contentId) {
    String filepath = // get path to file somehow
    String contentType = FileTypeMap.getDefaultFileTypeMap().getContentType(filePath);
    byte[] content = contentService.getResource(contentId);
    final HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.valueOf(mimeType));
    return new HttpEntity(content, headers);
}
Community
  • 1
  • 1
M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • @vegemite4me does [this](http://stackoverflow.com/questions/25522309/converting-json-between-string-and-byte-with-gson/25524340#25524340) help you – Ankur Singhal Aug 27 '14 at 13:56