Mil*_*daD 354 java spring controller file download
我有一个要求,我需要从网站上下载PDF.PDF需要在代码中生成,我认为这将是freemarker和像iText这样的PDF生成框架的组合.有更好的方法吗?
但是,我的主要问题是如何允许用户通过Spring Controller下载文件?
Inf*_*igo 374
@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
public void getFile(
@PathVariable("file_name") String fileName,
HttpServletResponse response) {
try {
// get your file as InputStream
InputStream is = ...;
// copy it to response's OutputStream
org.apache.commons.io.IOUtils.copy(is, response.getOutputStream());
response.flushBuffer();
} catch (IOException ex) {
log.info("Error writing file to output stream. Filename was '{}'", fileName, ex);
throw new RuntimeException("IOError writing file to output stream");
}
}
Run Code Online (Sandbox Code Playgroud)
一般来说,当你有response.getOutputStream(),你可以在那里写任何东西.您可以将此输出流作为将生成的PDF放入生成器的位置.此外,如果您知道要发送的文件类型,则可以进行设置
response.setContentType("application/pdf");
Run Code Online (Sandbox Code Playgroud)
Sco*_*son 285
通过使用Spring的内置支持和ResourceHttpMessageConverter,我能够对此进行流式处理.如果它可以确定mime类型,这将设置content-length和content-type
@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
@ResponseBody
public FileSystemResource getFile(@PathVariable("file_name") String fileName) {
return new FileSystemResource(myService.getFileFor(fileName));
}
Run Code Online (Sandbox Code Playgroud)
lob*_*234 76
您应该能够直接在响应上写入文件.就像是
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"somefile.pdf\"");
Run Code Online (Sandbox Code Playgroud)
然后将文件写为二进制流response.getOutputStream().记得response.flush()最后做,应该这样做.
Ral*_*lph 73
使用Spring 3.0,您可以使用HttpEntity返回对象.如果使用它,那么您的控制器不需要HttpServletResponse对象,因此更容易测试.
除此之外,这个答案相对于Infeligo的答案.
如果你的pdf框架的返回值是一个字节数组(读取我的答案的第二部分为其他返回值):
@RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
public HttpEntity<byte[]> createPdf(
@PathVariable("fileName") String fileName) throws IOException {
byte[] documentBody = this.pdfFramework.createPdf(filename);
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_PDF);
header.set(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + fileName.replace(" ", "_"));
header.setContentLength(documentBody.length);
return new HttpEntity<byte[]>(documentBody, header);
}
Run Code Online (Sandbox Code Playgroud)
如果PDF Framework(documentBbody)的返回类型不是字节数组(也没有ByteArrayInputStream),那么最好不要先将它作为字节数组.相反,最好使用:
InputStreamResource,PathResource (自Spring 4.0起)或FileSystemResource, 示例FileSystemResource:
@RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
public HttpEntity<byte[]> createPdf(
@PathVariable("fileName") String fileName) throws IOException {
File document = this.pdfFramework.createPdf(filename);
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_PDF);
header.set(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + fileName.replace(" ", "_"));
header.setContentLength(document.length());
return new HttpEntity<byte[]>(new FileSystemResource(document),
header);
}
Run Code Online (Sandbox Code Playgroud)
acd*_*ior 58
如果你:
byte[]在发送到响应之前将整个文件加载到a中;InputStream;@ControllerAdvice人为你挑选例外.以下代码是您所需要的:
@RequestMapping(value = "/stuff/{stuffId}", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> downloadStuff(@PathVariable int stuffId)
throws IOException {
String fullPath = stuffService.figureOutFileNameFor(stuffId);
File file = new File(fullPath);
HttpHeaders respHeaders = new HttpHeaders();
respHeaders.setContentType("application/pdf");
respHeaders.setContentLength(12345678);
respHeaders.setContentDispositionFormData("attachment", "fileNameIwant.pdf");
InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
}
Run Code Online (Sandbox Code Playgroud)
另请注意,为了避免读取整个文件只是为了计算它的长度,你最好先存储它.请务必查看文档InputStreamResource.
Sun*_*nil 18
此代码可以正常工作,从弹簧控制器上单击jsp上的链接自动下载文件.
@RequestMapping(value="/downloadLogFile")
public void getLogFile(HttpSession session,HttpServletResponse response) throws Exception {
try {
String filePathToBeServed = //complete file name with path;
File fileToDownload = new File(filePathToBeServed);
InputStream inputStream = new FileInputStream(fileToDownload);
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment; filename="+fileName+".txt");
IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
inputStream.close();
} catch (Exception e){
LOGGER.debug("Request could not be completed at this moment. Please try again.");
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
cac*_*co3 15
不要手工做任何事情,而是将工作委托给框架:
ResponseEntity<Resource>从处理程序方法返回Content-Type明确指定Content-Disposition必要时设置:
inline 在浏览器中强制预览attachment 强制下载@Controller
public class DownloadController {
@GetMapping("/downloadPdf.pdf")
// 1.
public ResponseEntity<Resource> downloadPdf() {
FileSystemResource resource = new FileSystemResource("/home/caco3/Downloads/JMC_Tutorial.pdf");
// 2.
MediaType mediaType = MediaTypeFactory
.getMediaType(resource)
.orElse(MediaType.APPLICATION_OCTET_STREAM);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(mediaType);
// 3
ContentDisposition disposition = ContentDisposition
// 3.2
.inline() // or .attachment()
// 3.1
.filename(resource.getFilename())
.build();
headers.setContentDisposition(disposition);
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}
}
Run Code Online (Sandbox Code Playgroud)
返回 ResponseEntity<Resource>
当您返回 a 时ResponseEntity<Resource>,它会ResourceHttpMessageConverter启动并写入适当的响应。
的resource可能是:
如果您需要从应用程序资源目录下载文件,请查看我的答案:它解释了如何使用ClassPathResource
请注意可能错误的Content-Type标头集(请参阅FileSystemResource 以内容类型 json 返回)。这就是为什么这个答案建议Content-Type明确设置。
Content-Type明确指定:
一些选项是:
MediaTypeFactory来自 Spring。在MediaTypeFactory允许探索MediaType适合Resource(见/org/springframework/http/mime.types文件)
Content-Disposition必要时设置:
有时需要在浏览器中强制下载或让浏览器打开文件作为预览。您可以使用Content-Disposition标题来满足此要求:
HTTP 上下文中的第一个参数是
inline(默认值,表明它可以显示在网页内,或作为网页)或attachment(表明它应该被下载;大多数浏览器呈现“另存为”对话框,预填充文件名参数的值(如果存在)。
在 Spring FrameworkContentDisposition中可以使用 a。
要在浏览器中预览文件:
ContentDisposition disposition = ContentDisposition
.builder("inline") // Or .inline() if you're on Spring MVC 5.3+
.filename(resource.getFilename())
.build();
Run Code Online (Sandbox Code Playgroud)
强制下载:
ContentDisposition disposition = ContentDisposition
.builder("attachment") // Or .attachment() if you're on Spring MVC 5.3+
.filename(resource.getFilename())
.build();
Run Code Online (Sandbox Code Playgroud)
InputStreamResource小心使用:
由于 anInputStream只能读取一次,因此Content-Length如果您返回 an ,Spring 将不会写入标头InputStreamResource(这是来自 的代码片段ResourceHttpMessageConverter):
@Override
protected Long getContentLength(Resource resource, @Nullable MediaType contentType) throws IOException {
// Don't try to determine contentLength on InputStreamResource - cannot be read afterwards...
// Note: custom InputStreamResource subclasses could provide a pre-calculated content length!
if (InputStreamResource.class == resource.getClass()) {
return null;
}
long contentLength = resource.contentLength();
return (contentLength < 0 ? null : contentLength);
}
Run Code Online (Sandbox Code Playgroud)
在其他情况下它工作正常:
~ $ curl -I localhost:8080/downloadPdf.pdf | grep "Content-Length"
Content-Length: 7554270
Run Code Online (Sandbox Code Playgroud)
小智 12
下面的代码为我生成和下载文本文件.
@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<byte[]> getDownloadData() throws Exception {
String regData = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
byte[] output = regData.getBytes();
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("charset", "utf-8");
responseHeaders.setContentType(MediaType.valueOf("text/html"));
responseHeaders.setContentLength(output.length);
responseHeaders.set("Content-disposition", "attachment; filename=filename.txt");
return new ResponseEntity<byte[]>(output, responseHeaders, HttpStatus.OK);
}
Run Code Online (Sandbox Code Playgroud)
我可以很快想到的是,生成pdf并将其存储在代码中的webapp/downloads/<RANDOM-FILENAME> .pdf中,并使用HttpServletRequest将转发发送到此文件
request.getRequestDispatcher("/downloads/<RANDOM-FILENAME>.pdf").forward(request, response);
Run Code Online (Sandbox Code Playgroud)
或者,如果您可以配置您的视图解析器,如,
<bean id="pdfViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="order" value=”2?/>
<property name="prefix" value="/downloads/" />
<property name="suffix" value=".pdf" />
</bean>
Run Code Online (Sandbox Code Playgroud)
然后回来
return "RANDOM-FILENAME";
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
413025 次 |
| 最近记录: |