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

你可能感兴趣的:(Spring,Boot,文件上传,JQuery)