Spring MVC文件上传与junit测试

本文探讨了使用MockMultipartFile进行单元测试时遇到的文件上传问题,对比了MockMultipartFile与CommonsMultipartFile在transferTo方法上的差异,并给出了可能的解决方案。

控制层

    @RequestMapping(value = "/onModify", method = RequestMethod.POST)
    @ResponseBody
    public String editMapManager(@RequestParam MultipartFile[] mapUrl, HttpServletRequest request) {
        try {
            if (mapUrl.length > 0) {
                for (MultipartFile mf : mapUrl) {
                    if (mf.getSize() > 0) {
                        String path = getPhotoUrl();//存储路径
                        String fileName = mf.getOriginalFilename();//文件名
                        String type = fileName.substring(fileName.lastIndexOf(".") + 1);// 文件类型
                        fileName = UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."));//拼接文件名
                       File targetFile = new File(path, fileName);//
                        if (!targetFile.exists()) {
                            targetFile.mkdirs();
                        }
                        mf.transferTo(targetFile);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return getReturnJSON(2, JsMessage.C0006, false);
        }
        return getReturnJSON(1, JsMessage.C0005, true);
    }

Junit测试

    

    @Test
    public void editMapManaxger() throws Exception {
        MockMultipartFile firstFile = null;
        File file = new File("D:/jd1.svg");
        firstFile = new MockMultipartFile("mapUrl", MAP_NAME , "multipart/form-data", new FileInputStream(file));
//        File file = new File(FILE_BASE_PATH+MAP_NAME);
//        firstFile = new MockMultipartFile("filePath", MAP_NAME , "multipart/form-data", new FileInputStream(file));
        MockHttpServletRequestBuilder request = null;
        request = MockMvcRequestBuilders.fileUpload("/mapManager/onModify").file(firstFile)
                .param("mapVariety", "1").param("id", "2")
                .param("name", "test").param("scale", "1000");
        MvcResult result = mvc.perform(request
                .session((MockHttpSession) getLoginSession()))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andReturn(); 
    }

问题说明

以上代码项目正常运行时没有问题 。倒是运行上面测试用例,会抛出“拒绝访问”。

原因

   if (!targetFile.exists()) {
       targetFile.mkdirs();//递归生成文件夹,上传的文件也会先生成个文件夹
   }

项目正常运行时文件传入的对象是CommonsMultipartFile,而测试用的对象是MockMultipartFile。两者都实现MultipartFile接口,但是transferTo的方法实现不同。

CommonsMultipartFile的transferTo 实现源码

@Override
    public void transferTo(File dest) throws IOException, IllegalStateException {
        if (!isAvailable()) {
            throw new IllegalStateException("File has already been moved - cannot be transferred again");
        }

        if (dest.exists() && !dest.delete()) {//这一步会将上传文件生成的文件夹删除,所以可以写入。
            throw new IOException(
                    "Destination file [" + dest.getAbsolutePath() + "] already exists and could not be deleted");
        }

        try {
            this.fileItem.write(dest);
            if (logger.isDebugEnabled()) {
                String action = "transferred";
                if (!this.fileItem.isInMemory()) {
                    action = isAvailable() ? "copied" : "moved";
                }
                logger.debug("Multipart file '" + getName() + "' with original filename [" +
                        getOriginalFilename() + "], stored " + getStorageDescription() + ": " +
                        action + " to [" + dest.getAbsolutePath() + "]");
            }
        }
        catch (FileUploadException ex) {
            throw new IllegalStateException(ex.getMessage());
        }
        catch (IOException ex) {
            throw ex;
        }
        catch (Exception ex) {
            logger.error("Could not transfer to file", ex);
            throw new IOException("Could not transfer to file: " + ex.getMessage());
        }
    }

MockMultipartFile 的 transferTo 实现源码

向文件夹写入,所以抛出异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值