SpringMVC,SpringBoot文件下载

前言

最近严查security, 导致原来暴露出去的s3不能用了,不允许public的s3,暂时的折中方案是自己做跳转。于是需要在SpringMVC中实现文件下载功能。

关于文件存储的设计

文件存储通常用作对象存储,业界标准就是AWS s3, 国内的七牛也差不多。不想自建的话,采用这种第三方存储是很方便的。但是,有写地方需要注意。

安全问题

就像这次整改遇到的,权限问题大概是对象存储必须具备的。s3的权限特别多和复杂,可以做到认证user访问; 指定ip访问; 指定IAM Role访问; 指定第三方登陆比如Facebook,google的认证,设置自己的认证,这里是指Cognito。

地址路径的健壮性

review代码的时候发现了几个严重的问题,地址问题尤为重要,简直就是bug一样。首先,db存储的文件路径不应该包含域名前缀,像这次整改图片存储就导致以前db里的数据不能用了。db只能存储相对路径,即当指定改类型前缀后,变化的部分路径。。 然后就是 需要一个域名,对于公开的地址,需要一个域名来维护,而不是直接指定当前的文件服务器。比如一个公开的s3可能是这样的:https://mybucket.s3.amazonaws.com/keyprefix/key. 如果我们变更了s3的bucket,那么这个地址就废弃了,这个很有可能发生的。因此,用一个我们自己的域名指向s3可以屏蔽这个细节。同理,如果写死了文件服务器的地址,当文件服务器变更的时候,公开的文件将全部失效。

如何使用SpringMVC下载文件

我们可以简单的在HttpServletResponse的OutputStream里写入我们的文件流,这样就可以实现文件下载。但这个做法感觉有点太直接了,推荐使用Spring的ResponseEntity来做。

@RequestMapping(value = "/static/filename")
public ResponseEntity<InputStreamResource>(HttpServletResponse response) {
    final ObjectMetadata objectMetadata = s3Object.getObjectMetadata();

    return ResponseEntity.ok()
            .header("Access-Control-Allow-Origin", "*")
            .cacheControl(CacheControl.maxAge(maxAge, TimeUnit.DAYS).cachePublic())
            .allow(HttpMethod.GET, HttpMethod.OPTIONS)
            .contentLength(objectMetadata.getContentLength())
            .contentType(MediaType.valueOf(objectMetadata.getContentType()))
            .body(new InputStreamResource(s3Object.getObjectContent()));
}
  1. 问题核心在于返回ResponseEntity<InputStreamResource>
  2. ResponseEntity是SpringMVC里统一封装的返回值response信息
  3. InputStreamResource则是接收一个输入流InputStream的结果集
  4. 然后可以设置浏览器缓存,这个对用户刷新页面挺重要的
  5. 对于图片和js等,需要设置contentType为png或者js等

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏AhDung

【手记】让Fiddler抓取入站请求,或者叫用Fiddler做反向代理

最近在弄公众号开发,除了主动去调公众号接口,还存在公众号后台要反过来调你的情形,攻受转换一线间。对于回调的情况,想要知道对方是怎样来请求的很有必要。此前经常用F...

943
来自专栏技术记录

Netty-Websocket 根据URL路由,分发机制的实现

最近在做netty整合websocket,发现网上很多项目都是最简单的demo,单例的一个项目。 然而公司的项目需要接受几个不同功能的ws协议消息,因此最好是用...

4475
来自专栏Netkiller

Linux 应用程序开发入门

我会实现一个守护进程,从这个程序你将了解,Linux 应用程序开发基本流程 我们将实现一个远程shell的功能,可以通过tcp协议,运行远程机器上的命令或she...

4687
来自专栏Java帮帮-微信公众号-技术文章全总结

JavaWeb11-jsp.cookie.session(1)

? Jsp&cookie & session 一.jsp 1. jsp的介绍 JSP全名为Java Server Pages,中文名叫java服务器页面,本质...

2585
来自专栏郭霖

Android Volley完全解析(一),初识Volley的基本用法

1. Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据。And...

2195
来自专栏魂祭心

原 以太坊-rpc原理及实现

3317
来自专栏finleyMa

Laravel Vue 前后端分离 使用token认证

在做前后台分离的项目中,认证是必须的,由于http是无状态的。前台用户登录成功后,后台给前台返回token。之后前台给后台发请求每次携带token。

1132
来自专栏小轻论坛

FTP服务器连不上,那是关闭了这个功能!

一直在使用FlashFXP工具上传源码,最近换了宽带,新的路由器,发现已经登陆不进FTP了。我尝试从服务器后台进FTP,看下是不是我的工具有问题。结果FTP地址...

1001
来自专栏Angular&服务

Angular2 拦截器(页面请求修改Url+headers传值+获取服务器返回的错误信息)

1.我们首先定义一个服务 <b>HttpInterceptorService</b>

1042
来自专栏jeremy的技术点滴

docker源码分析-Client创建与命令执行

3122

扫码关注云+社区