(一)需求
在 Spring Boot 項目中實現文件下載功能 後,項目需要進一步實現 Excel 文件上傳功能,已供後端代碼讀取 Excel 中單元格的數據。本文的代碼在下載功能的基礎之上繼續擴展。
(二)代碼
2.1 後端代碼
控制層
@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);
}
}
2.2 前端代碼
HTML頁面
本文采用的是 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 以供認證。
JQuery 代碼
爲按鈕綁定點擊事件,發起 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