前后端封装上传下载
前端:
js
export const download = (url, data = {}, method = 'get') => {
return request({
url,
method,
//上传下载只用 GET 和 POST,不会用 PUT/DELETE。
[method === 'get' ? 'params' : 'data']: data,
responseType: 'blob'
}).then((response) => { // 【修改点】这里接收到的是完整的 response 对象
const blob = response.data // 从 response 中取出 blob
const link = document.createElement('a')
const blobUrl = URL.createObjectURL(blob)
link.href = blobUrl
// 【修改点】从 response.headers 中获取文件名
const contentDisposition = response.headers?.['content-disposition']
let filename = 'file' // 默认文件名
if (contentDisposition) {
const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
if (match && match[1]) {
filename = decodeURIComponent(match[1].replace(/['"]/g, '')) // 顺便解码防止中文乱码
}
}
link.download = filename
document.body.appendChild(link) // 兼容 Firefox
link.click()
document.body.removeChild(link) // 清理 DOM
URL.revokeObjectURL(blobUrl) // 释放内存
})
}
// 不用get,get长度有限,put虽然也是放在请求体的数据,但put都是修改为主,delete是删除所以用post
export function uploadFile(url, file, extraData ={}){
const formData = new FormData();
formData.append('file', file);
// 用于放置额外参数,追加到 formData 中
Object.keys(extraData).forEach(key => {
formData.append(key, extraData[key])
})
return request({
url,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
后端:
java
package com.demo.common;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
/**
* @Description:
* @Author:sfk
* @Data:2026/7/2
**/
public class FileUtils {
public static void downloadPdf(HttpServletResponse response, String fileName, byte[] outPutContent) throws IOException {
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename="+ fileName+".pdf");
response.getOutputStream().write(outPutContent);
response.getOutputStream().flush();
}
// T 可以接收任意Java类型
public static <T> void downloadExcel(HttpServletResponse response,String fileName, Class<T> clazz, List<T> dataList) throws IOException {
setExcelResponseHeader(response, fileName);
// 内容样式:居中 + 字体大小16
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
WriteFont contentWriteFont = new WriteFont();
contentWriteFont.setFontHeightInPoints((short) 16);
contentWriteCellStyle.setWriteFont(contentWriteFont);
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 表头样式:不设置任何样式,保持默认
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 创建策略
HorizontalCellStyleStrategy horizontalCellStyleStrategy =
new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
// 输出文件
EasyExcel.write(response.getOutputStream(), clazz)
.registerWriteHandler(horizontalCellStyleStrategy)
.sheet(fileName)
.doWrite(dataList);
}
public static <T> void exportExcel(HttpServletResponse response,String fileName,Class<T> clazz,List<T> datalist) throws IOException {
setExcelResponseHeader(response, fileName);
EasyExcel.write(response.getOutputStream(), clazz)
.sheet(fileName)
.doWrite(datalist);
}
public static void setExcelResponseHeader(HttpServletResponse response,String fileName){
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// + 时间戳区别区别重复下载
String name = URLEncoder.encode(fileName + "_" +LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".xlsx", StandardCharsets.UTF_8);
// 去空格 + 指定编码
String encodedName = URLEncoder.encode(name, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
response.setHeader("Content-Disposition", "attachment; filename=" + encodedName);
}
}
controller调用处:
java
@Operation(summary = "导出PDF成绩单")
@GetMapping("/downloadGradePdf")
public void downloadGradeById(@RequestParam Long gradeId, HttpServletResponse response) throws IOException {
try {
byte[] pdfBytes = gradeService.generateGradePdf(gradeId);
FileUtils.downloadPdf(response,"成绩单_"+gradeId,pdfBytes);
} catch(Exception e) {
e.printStackTrace();
}
}
JAVA
@Operation(summary = "导出Excel成绩单")
@PostMapping("/downloadGradeExcel")
public void downloadGradeExcel(HttpServletResponse response,@RequestBody GradeQueryReq queryDTO) throws IOException {
// 调用业务
List<GradeExportVO> gradeExportVOS = gradeService.generateGradeExcel(queryDTO);
if (gradeExportVOS == null){
throw new BusinessException("没有数据!");
}
String fileName = "成绩单";
FileUtils.downloadExcel(response,fileName,GradeExportVO.class,gradeExportVOS);
}
java
@GetMapping("/downloadTemplate")
public void downloadTemplate(HttpServletResponse response) throws IOException {
List<UserImportDto> dataList = new ArrayList<>();
// 示例数据
UserImportDto example1 = new UserImportDto();
example1.setUserName("zhangsan");
example1.setRealName("张三");
example1.setRole("学生");
example1.setClassName("计算机科学与技术1班");
dataList.add(example1);
FileUtils.exportExcel(response,"userImportTemplate",UserImportDto.class,dataList);
}