1.需求场景:项目中联系人模块需要导入导出excel和下载excel模板功能
此处只记录 下载模板和导出excel功能
2.流程:前台用超链接形式 点击后发送get请求 然后后台实现功能。
3.代码:项目使用的是Idea+springboot+kotlin
3.1 controller:
@Value("\${download.template.xls.sms_link}")
private var smsLinkTemplate: String = ""
@GetMapping("export/{id}")
fun exportFile(@PathVariable("id") id: Int, resp: HttpServletResponse) {
when (id) {
1 -> callCenterService.exportOutLinker(resp, "outLinker.xls")
}
}
@GetMapping("download/{id}")
fun downloadFile(@PathVariable("id") id: Int, resp: HttpServletResponse) {
when (id) {
1 -> callCenterService.downLoadExcel(resp, smsLinkTemplate)
}
}
3.2 service:
//poi导出excel
fun exportOutLinker(resp: HttpServletResponse, excelName: String) {
val workbook = HSSFWorkbook()
val sheet = workbook.createSheet("通讯录")
val linkerList = ****//查表
var rowNum = 1
val headers = arrayOf("姓名", "手机号", "标签", "备注")
val row = sheet.createRow(0)
headers.indices.map { i ->
val cell = row.createCell(i)
val text = HSSFRichTextString(headers[i])
cell.setCellValue(text)
}
linkerList.map { link ->
val row = sheet.createRow(rowNum)
row.createCell(0).setCellValue(link.name)
row.createCell(1).setCellValue(link.phone)
.....//其他字段
rowNum++
}
resp.setContentType("application/octet-stream")//告诉浏览器输出内容为流
resp.setHeader("Content-disposition", "attachment;filename=$excelName")
try {
val out = resp.outputStream
workbook.write(out)
out.flush()
out.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
//下载excel模板
fun downLoadExcel(resp: HttpServletResponse, excelName: String) {
try {
val file = ResourceUtils.getFile("classpath:temp/$excelName")
if (file.exists()) {
val inStream = FileInputStream(file)
resp.setContentType("multipart/form-data")//自动判断下载文件类型
resp.setHeader("Content-Disposition", "attachment;filename=${URLEncoder.encode(excelName, "UTF-8")}")
val out = resp.outputStream
var b = 0
val buffer = ByteArray(100000)
while (b != -1) {
b = inStream.read(buffer);
if (b != -1) out.write(buffer, 0, b)
}
inStream.close();
out.flush();
out.close();
}
} catch (e: IOException) {
e.printStackTrace()
}
}
3.3 application.properties
# project download template file name
download.template.xls.sms_link=sms_link_template.xls
3.4 文件位置
3.5 前台使用的是超链接,所以提供请求路径给前台
前台:
controller:
@GetMapping("address/{id}")
fun address(@PathVariable("id") id: Int, req: HttpServletRequest): Map<String, Any> {
val result = HashMap<String, Any>()
var url = ""
val addr = "${req.scheme}://${req.serverName}:${req.serverPort}${req.contextPath}"
when (id) {
1 -> url = "$addr/file/download/1"
2 -> url = "$addr/file/export/1"
}
val encode = URLEncoder.encode(url, "utf-8")
result["returnCode"] = 0
result["addr"] = encode
return result
}
3.6 解决请求token限制
在InterceptorConfig中使用excludePathPatterns
override fun addInterceptors(registry: InterceptorRegistry?) {
registry?.addInterceptor(csrfInterceptor)
?.excludePathPatterns("/test/**", "/file/download/**", "/file/export/**")
?.addPathPatterns("/**")
}
或者在拦截器中解决
if (request?.getHeader("token").equals(encryptBkToken)) {
//token校验
} else if (request?.requestURI.equals("****")){
//允许下载
} else {}
3.7 关于下载的另一种方法:使用tomcat虚拟目录
从上文可以发现,模板文件是放在项目里面的,如果文件很多那么项目就会很大;并且下载时调用了downLoadExcel方法,多了读取文件输出文件流的操作。使用tomcat虚拟目录可以解决以上问题。
3.7.1 在服务器上创建资源文件夹
3.7.2 在tomcat下的/conf/Catalina/localhost中增加xml
如图,docBase为资源路径,path和文件名保持一致,这里注意path随便写也没关系,因为用不到
3.7.3 不需要重启服务器就可以访问到文件,在浏览器输入:http://ip:端口/download/sms_link_template.xls
就可以下载到sms_link_template.xls文件,注意这里的download指的是download.xml的名称,如果xml名称变更,这边路径也要变,和xml中的path无关
3.7.4根据3.7.3的原理改变代码
@Value("\${download.template.xls.sms_link}")
private var smsLinkTemplate: String = ""
@GetMapping("address/{id}")
fun address(@PathVariable("id") id: Int, req: HttpServletRequest): Map<String, Any> {
val result = HashMap<String, Any>()
var url = ""
val addr = "${req.scheme}://${req.serverName}:${req.serverPort}"
when (id) {
1 -> url = "$addr/download/smsLinkTemplate"//注意这个就是3.7.3的访问路径
}
val encode = URLEncoder.encode(url, "utf-8")
result["returnCode"] = 0
result["addr"] = encode
return result
}
然后前台直接调用这个接口返回组合好的路径,直接超链接就能下载了,3.6的token限制也不用管了。
但是我并没有把我代码改了,因为项目简单而且我懒啊