Spring Boot + JQuery Ajax 實現文件上傳功能

(一)需求

在 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章