在 Spring Boot 项目中实现文件下载功能 后,项目需要进一步实现 Excel 文件上传功能,已供后端代码读取 Excel 中单元格的数据。本文的代码在下载功能的基础之上继续扩展。
@PostMapping("upload")
public String uploadFile(MultipartFile file) {
String fileName = fileService.storeFile(file);
return "/file/download?fileName=" + fileName;
}
返回值为上传文件的下载链接
@Override
public String storeFile(MultipartFile file) {
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
try {
Path targetPath = filePath.resolve(fileName);
Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
return fileName;
} catch (IOException e) {
throw new FileException("Could not store file " + fileName + ". Please try again!", e);
}
}
在做文件复制时,采用同名文件覆盖旧版本的方式。
单元测试采用 MockMVC 模拟接口测试,下面只列出上传文件的单元测试代码。
基类 BaseControllerTest
@RunWith(SpringRunner.class)
@SpringBootTest
public abstract class BaseControllerTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
/**
* @param paramName 控制层上传文件方法的 Multipart 类型的参数名,一般为 file
* @param fileName 文件名
* @param contentType 内容的类型,如 text/plain application/json text/html 等
* @param content 文件内容
* @return 返回内容为字符串
* @throws Exception 可能不存在接口或上传文件格式有误
*/
String mockMultipart(String paramName, String fileName, String contentType, String content) throws Exception {
MockMultipartFile multipartFile = new MockMultipartFile(
paramName, fileName, contentType, content.getBytes());
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
return mockMvc.perform(MockMvcRequestBuilders.multipart("/file/upload").file(multipartFile))
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn()
.getResponse()
.getContentAsString();
}
}
为控制层创建测试类 FileControllerTest
@RunWith(SpringRunner.class)
@SpringBootTest
public class FileControllerTest extends BaseControllerTest {
@Test
public void uploadFile() throws Exception {
String response = mockMultipart("file", "multipart_test.txt", "text/plain", "Spring Boot 2.x");
assertEquals("/file/download?fileName=multipart_test.txt", response);
}
}
本文采用的是 Bootstrap 样式渲染 输入框和按钮
<script type="text/javascript" src="/js/bootstrap-4.3.1-dist/js/bootstrap.min.js">script>
上传文件功能所在的 form 表单
<form id="uploadForm" class="form-check-inline" enctype="multipart/form-data">
<input id="uploadFile" style="width: 200px" class="input-group-append" type="file" name="file"/>
<button id="uploadTestCase" type="button" class="btn-dark">上传测试用例button>
form>
<button type="button" id="downloadTestCaseBtn" class="btn-outline-success" style="display: none"><a href="/file/download" id="downloadTestCase" download>上传成功,点击下载a>button>
本文的设计在上传按钮后加入一个隐藏的下载按钮,当上传成功后显示下载按钮,让用户能够下载最新的 excel 以供认证。
为按钮绑定点击事件,发起 Ajax 请求。在上传成功后,显示下载按钮。当重新选择 excel 文件后,下载按钮会隐藏。
$(function () {
$('#uploadFile').click(function () {
$('#downloadTestCaseBtn').hide();
});
$('#uploadTestCase').click(function () {
let uploadFileName = $('#uploadFile').val();
if (uploadFileName.length === 0) {
alert('请选择需要上传的测试用例');
return;
}
if (!isExcel(uploadFileName)) {
alert('请上传 excel 文件');
return;
}
$.ajax({
method: 'POST',
url: '/file/upload',
cache: false,
data: new FormData($('#uploadForm')[0]),
processData: false,
contentType: false,
success: function (uri) {
$('#downloadTestCase').attr('href', uri);
$('#downloadTestCaseBtn').show()
},
error: function () {
$('#downloadTestCase').attr('href', '');
$('#downloadTestCaseBtn').hide()
}
})
})
});
在 JQuery 代码中,做了 excel 文件后缀校验。
function isExcel(fileName) {
return fileName.endsWith('.xls') || fileName.endsWith('.xlsx');
}
更多关于 springboot 项目上传、下载文件的功能请参考:Spring Boot File Upload / Download Rest API Example