springboot打包目录结构和普通web项目结构有区别,所以做文件下载的时候,
往往Windows下测试OK,但是到了Linux就不行了。下面提供一种满足两种系统的通用写法,以供参考。
@Api(tags="文件下载")
@Controller
@RequestMapping({"/downLoad"})
public class DownLoadController {
// 日志
Logger logger = LoggerFactory.getLogger(DownLoadController.class);
@ApiOperation(httpMethod="GET", value="下载文件(模板)-(不需要token令牌)", produces="application/json")
@ApiImplicitParams({@io.swagger.annotations.ApiImplicitParam(name="type", value="模板类型(1:人员导入模板)", required=true, dataType="long", paramType="query")})
@GetMapping({"/downLoadFile"})
public void downLoadFile(Integer type, HttpServletResponse response) throws Exception {
if (type == null) {
throw new BusinessException("下载文件类型不能为空");
}
String fileName = TemplateEnum.valueOf(type);
if (fileName == null) {
throw new BusinessException("下载文件参数不正确,type=" + type);
}
this.logger.info("开始下载文件,fileName=" + fileName + ",type=" + type);
// 重点在这里 windows和Linux环境下的区别,下面这种形式都可以
ClassPathResource resource = new ClassPathResource("template\\" + fileName);
if (resource == null) {
throw new BusinessException("文件不存在");
}
ServletOutputStream sos = null;
InputStream inputStream = null;
try {
fileName = URLDecoder.decode(fileName, "UTF-8");
response.reset();
response.setContentType("application/x-msdownload");
// 添加请求头,避免下载中文乱码
fileName = new String(fileName.getBytes("gbk"), "iso-8859-1");
response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
inputStream = resource.getInputStream();
sos = response.getOutputStream();
int i;
while ((i = inputStream.read()) != -1) {
sos.write(i);
}
sos.flush();
this.logger.info("执行下载正常结束!");
} catch (Exception e) {
this.logger.error("执行下载出错:fileName=" + fileName, e);
}
finally {
closeStream(sos, inputStream);
}
}
private void closeStream(ServletOutputStream sos, InputStream inputStream)
{
try
{
if (sos != null) {
sos.close();
}
if (inputStream != null)
{
inputStream.close();
}
} catch (IOException ex) {
this.logger.info("断开连接出错!");
ex.printStackTrace();
}
}
上面代码可以直接拿来使用,做几点说明:
1. 代码中有个枚举类 TemplateEnum 会编译出错
这个类没什么东西,就是一个 type对应一个文件名字,主要是拿到下载文件的名字,也可以直接通过调用的
时候传参即可。
2. 核心代码
// 重点在这里 windows和Linux环境下的区别,下面这种形式都可以
ClassPathResource resource = new ClassPathResource("template\\" + fileName);
3. 我这里是下载一个导入模板,模板路径在template下,如下: