实现用户文件和图片上传

请注意,本文编写于 824 天前,最后修改于 822 天前,其中某些信息可能已经过时。

一、目录

  • 实现用户文件和图片上传

二、实验结果和学习内容

首先,文件上传的功能主要作用是为了实现用户能够上传相关图片和自定义的头像。而为了方便后续功能的实现,接收文件的时候就默认全部按照多文件上传的方式处理,虽然可能效率会比单文件处理要低一些。

首先,在SpringMVC中实现文件上传的功能需要用到几个包,添加进pom.xml

        <!-- 上传组件包 -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.9</version>
    </dependency>

然后需要进行相应的配置,在spring-web.xml文件中:

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 最大内存大小 -->
        <property name="maxInMemorySize" value="10240"/>
        <!-- 最大文件大小,-1为不限制大小 -->
        <!--设置上传文件的最大尺寸为10MB 10*1024*1024-->
        <property name="maxUploadSize" value="10485760"/>
          <!--设置临时文件存放目录-->
        <property name="uploadTempDir" value="/uploadTemp"></property>
    </bean>

然后就可以开始开发图片上传功能了。不过我在这之前,做了点别的事情,因为询问过字节跳动的老师,他们存储图片的时候是以文件的形式存储在服务器上的,而不是base64或是其他编码方式存在数据库中。那么为了方便,需要创建一个新的目录,而为了方便管理以及后续的迁移,使得图片目录和项目目录分开,我创建了一个虚拟目录。

屏幕快照 2019-06-07 03.39.01
屏幕快照 2019-06-07 03.39.01

然后就能直接通过localhost:8080/mySSMphoto/xxx.jpg来直接获取到图片了。

然后开始实现文件上传的代码

首先是一个工具类FileUploadUtil.java

public class FileUploadUtil {
    // 使用日志工厂获取日志对象
    private static Log log = LogFactory.getLog(FileUploadUtil.class);

    private static String imgPath = "/Users/wangjing/Desktop/mySSMphoto";

    /**
     * 批量上传文件
     *
     * @param request
     * 用户名; 用于区分用户上传的图片
     * 模块名称; 用于区分该图片是位于那个模块进行上传
     * @return
     * @throws FileNotFoundException
     */
    public static List<String> uploadFile(HttpServletRequest request) throws FileNotFoundException {

        // 创建list集合,用于接收上传文件的路径
        List<String> filePathList = new ArrayList<String>();

        // 拼接文件上传位置,这里使用Tomcat服务器,将文件上传到webapps中,和项目同目录,files将用于保存上传的文件,将上传的文件于项目分开
        //String strPath = ",webapps,files," + moduleName + "," + username;

        // 解析出文件存放路径位置
        //String filepath = System.getProperty("catalina.base") + strPath.replace(',', File.separatorChar);

        String filepath = imgPath;

        log.debug("文件上传路劲位置-------->>>>>>>>>>>>" + filepath);

        // 转换request,解析出request中的文件
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;

        // 获取文件map集合
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();

        String fileName = null;

        // 循环遍历,取出单个文件
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {

            // 获取单个文件
            MultipartFile mf = entity.getValue();

            // 获得原始文件名
            fileName = mf.getOriginalFilename();

            // 截取文件类型; 这里可以根据文件类型进行判断
            String fileType = fileName.substring(fileName.lastIndexOf('.'));

            try {
                // 截取上传的文件名称
                String newFileName = fileName.substring(0, fileName.lastIndexOf('.'));

                log.debug("上传来的文件名称------->>>>>>>>>" + newFileName);

                // 拼接上传文件位置
                String newfilePath = filepath + File.separatorChar + newFileName + fileType;

                log.debug("拼接好的文件路径地址------------->>>>>>>>" + newfilePath);

                // 重新组装文件路径,用于保存在list集合中
                String filepathUrl = "mySSMphoto" + File.separatorChar  + newFileName + fileType;

                log.debug("文件位置---------------->>>>>>>>>>" + filepathUrl);

                // 创建文件存放路径实例
                File dest = new File(filepath);

                // 判断文件夹不存在就创建
                if (!dest.exists()) {
                    dest.mkdirs();
                }

                // 创建文件实例
                File uploadFile = new File(newfilePath);

                // 判断文件已经存在,则删除该文件
                if (uploadFile.exists()) {
                    uploadFile.delete();
                }

                log.debug("start upload file-------------->>>>>>> " + fileName);

                // 利于spring中的FileCopyUtils.copy()将文件复制
               // FileCopyUtils.copy(mf.getBytes(), uploadFile);

                mf.transferTo(uploadFile);

                // 将文件路径存入list集合中
                filePathList.add(filepathUrl);

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();

                log.error("upload failed. filename: " + fileName+"---->>>error message ----->>>>> "+ e.getMessage());

                return null;
            }
        }

        return filePathList;
    }
}

然后在Controller中实现对应的Handler

         /**
     * 批量文件上传
     *
     * @param request
     * @param session
     * @return
     */
    @RequestMapping(value = "/secure/upload-file", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<String> uploadFiles(Model model,HttpServletRequest request, HttpSession session) {

        // 获取session中保存的用户信息
        //User user = (User) session.getAttribute("user");

        // 创建list集合用于获取文件上传返回路径名
        List<String> list = new ArrayList<String>();

        try {

            // 获取上传完文件返回的路径,判断module模块名称是否为空,如果为空则给default作为文件夹名
            list = FileUploadUtil.uploadFile(request);
            // model属性也行
            model.addAttribute("fileUrlList", list);

        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            logger.error("上传文件发生错误=》》" + e.getMessage());

        }

        // 转发到uploadTest.jsp页面
        return list;
    }

这里能够直接返回List是用到了jackson包。

而我测试的时候是通过jsp测试的,在一个web网页上进行文件上传,并将图片位置放在model中返回给用户,然后通过el表达式可以直接附到img的src中,就能显示出图片了。

效果如下:

屏幕快照 2019-06-07 03.47.10
屏幕快照 2019-06-07 03.47.10

然后选择文件:

屏幕快照 2019-06-07 03.47.51
屏幕快照 2019-06-07 03.47.51

然后提交:

屏幕快照 2019-06-07 03.49.16
屏幕快照 2019-06-07 03.49.16

就能显示图片了,然后看看虚拟目录下的情况:

屏幕快照 2019-06-07 03.50.02
屏幕快照 2019-06-07 03.50.02

就成功了


三、实验思考及感想

底层功能基本都实现了,数据也基本完善了,可能还要用到redis或者ehcache,还有kafka等,算是额外功能吧,目的当然是为了体验更加舒适,使得获取数据更加快速和敏捷。

此处评论已关闭