• 基于SpringMVC的文件(增删改查)上传、下载、更新、删除


    一、项目背景 

      摘要:最近一直在忙着项目的事,3个项目过去了,发现有一个共同的业务,那就是附件的处理,附件包括各种文档,当然还有图片等特殊文件,由于时间的关系,每次都是匆匆忙忙的搞定上线,称这项目的空档,整理了一份附件上传、下载、删除的项目,主要就是附件的处理,情况包含以下几种:

      1. 表单个附件共存

      2. 只有附件

      3. 只有表单

    其中,后两种处理方式简单,本文主要说明的是第一种的处理方案。

    二、项目需求

      整体来说,项目需求还是不复杂的,这里单独把附件和表单数据提交拿出来说,就是表单中的有附件的情况,表单中的附件随时可以进行替换、删除、添加等操作。折腾了很久,终于把附件上传这档子事理清楚了,这里做个记录,与各位大神共勉。

    三、项目架构

      项目架构采用的是比较常用的传统的javaWeb项目开发框架,Spring4.3.4,hibernate5(ssh),MySQL 5.7,Tomcat7.0,关于该项目的如何整合,就不再多说了,网上都有,搭建一套框架,应该不是问题。该业务实现的思想就是:数据库存放文件路径,这里是物理路径,注意物理路径和虚拟路径的区别,文件存放在服务器,需要的时候通过数据库表中的物理路径可以找到相应的文件,增删改查都是可以的。

    四、技术实现

     4.1 数据库创建

      打开MySQL管理工具或者CMD dos界面进入MySQL创建数据库,这里,我使用管理工具创建的,首先是文件表:

      

      字段可以根据业务的不同适当添加,我做个例子,有这几个字段就够了,其中relationID是和我们的业务表管理的,主外键关联或者普通关联。下面是业务表的创建:

      

    数据库表大概就是这样,附件表和业务表关联,当然关联的方式有很多,我只选择了最简单的主外键关联。

    4.2 后台代码编写

      项目架构使用的hibernate,hibernate主要的有点就是基于对象,非常适合面向对象编程的本质,下面创建对象,采用Spring注解的方式:

    package com.common.model;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Entity
    @Table(name="tab_userinfo")
    public class TabUserinfo {
        
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private int id;
        private String username;
        private String password;
        private String relationID;
        private String remark;
        
        public TabUserinfo() {
            super();
        }
    
        public TabUserinfo(int id, String username, String password, String remark) {
            super();
            this.id = id;
            this.username = username;
            this.password = password;
            this.remark = remark;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String getRelationID() {
            return relationID;
        }
    
        public void setRelationID(String relationID) {
            this.relationID = relationID;
        }
    
        public String getRemark() {
            return remark;
        }
    
        public void setRemark(String remark) {
            this.remark = remark;
        }
    
        @Override
        public String toString() {
            return "TabUserinfo [id=" + id + ", username=" + username + ", password=" + password + ", relationID="
                    + relationID + ", remark=" + remark + "]";
        }
    
        
    
        
        
        
        
        
        
    }
    package com.common.model;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Entity
    @Table(name="tab_userinfo")
    public class TabUserinfo {
        
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private int id;
        private String username;
        private String password;
        private String relationID;
        private String remark;
        
        public TabUserinfo() {
            super();
        }
    
        public TabUserinfo(int id, String username, String password, String remark) {
            super();
            this.id = id;
            this.username = username;
            this.password = password;
            this.remark = remark;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String getRelationID() {
            return relationID;
        }
    
        public void setRelationID(String relationID) {
            this.relationID = relationID;
        }
    
        public String getRemark() {
            return remark;
        }
    
        public void setRemark(String remark) {
            this.remark = remark;
        }
    
        @Override
        public String toString() {
            return "TabUserinfo [id=" + id + ", username=" + username + ", password=" + password + ", relationID="
                    + relationID + ", remark=" + remark + "]";
        }
    
        
    }
    View Code

    文件上传:

    @CrossOrigin(origins = "*", maxAge = 3600)
    @Controller
    @RequestMapping("user")
    public class UserController {
        protected Logger log = Logger.getLogger(UserController.class);
        @Autowired
        ServiceI service;
        
        @RequestMapping(value="userAddFile",produces = {"application/json;charset=UTF-8"},method=RequestMethod.POST)
        @ResponseBody
        public String addFile(TabUserinfo userinfo,@RequestParam(value="file",required=true) MultipartFile [] uploadFile,
                HttpServletRequest request){    
            
            JSONObject jsonRusult=new JSONObject();
            String UUIDString=UUID.randomUUID().toString();
            String date=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            boolean flag=false;
            List<Object> fileList=null;
            ReturnStatus rStatus=null;
            log.info("UUID:"+UUIDString);
            //保存表单数据
            try {
                if(null!=userinfo){
                    log.info("数据userinfo:"+userinfo.toString());
                    userinfo.setRelationID(UUIDString);
                    service.saveOrUpdate(userinfo);
                    flag=true;
                }
                if(flag){
                    //上传附件
                    fileList=FileUtils.uploadFile(service, UUIDString, date, uploadFile, request);
                }
                if(null!=fileList && fileList.size()!=0){
                    rStatus=new ReturnStatus("0000", "文件上传成功!");
                    jsonRusult.put("status", rStatus);
                    jsonRusult.put("fileInfo", fileList);
                }else{
                    rStatus=new ReturnStatus("0003", "文件上传失败!");
                    jsonRusult.put("fileInfo", null);
                }
                
            } catch (IllegalStateException e) {
                log.error("文件上传失败",e);
                service.delete(userinfo);//保证事务
            } catch (IOException e) {
                log.error("文件上传失败",e);
                service.delete(userinfo);
            }
            
            return JSON.toJSONString(jsonRusult,SerializerFeature.WriteMapNullValue);
        }
    View Code

    文件上传工具类:

    public static List<Object> uploadFile(ServiceI service,String relationID,String date, MultipartFile [] uploadFile,HttpServletRequest request) 
                throws IllegalStateException, IOException{
            
            ServletContext servletContext = request.getServletContext();
            List<Object> fileList=new ArrayList<>();
            UploadFile fileEntity=null;
            for(int i=0;i<uploadFile.length;i++){
                String filePath= servletContext.getRealPath("/upload");
                log.info("文件存放磁盘路径:"+filePath);
                String rePath=request.getScheme()+"://"+request.getServerName()+":"+
                        request.getServerPort()+request.getContextPath()+"/upload";
                log.info("取文件路径:"+rePath);
                MultipartFile file=uploadFile[i];
                String fileName=file.getOriginalFilename();
                String fileNameS="";
                String fileType=fileName.split("\.")[fileName.split("\.").length-1];
                if(StringUtil.isNull(fileName,fileType)){
                    fileNameS=UUID.randomUUID()+"."+fileType;
                    if(!file.isEmpty()){
                        if(fileType.contains("jpg") || fileType.contains("png") || fileType.contains("gif")){
                            filePath+="\image\"+fileNameS;
                            rePath+="/image/"+fileNameS;
                        }else{
                            filePath+="\file\"+fileNameS;
                            rePath+="/file/"+fileNameS;
                        }
                        log.info("文件路径filePath:"+filePath);
                        log.info("文件路径rePath:"+rePath);
                        File fileS=new File(filePath);
                        if(!fileS.getParentFile().exists()){
                            fileS.getParentFile().mkdirs();
                        }
                        file.transferTo(fileS);
                        
                        fileEntity=saveFileInfo(service,fileName,filePath,relationID,date);
                        if(null!=fileEntity){
                            fileEntity.setFilePath(rePath);
                            fileList.add(fileEntity);
                        }
                        
                    }else{
                        fileList.add("文件不存在");;
                    }
                }
            }
            return fileList;
        }
        /**
         * 保存文件信息
         * @param fileName
         * @param filePath
         */
        private static UploadFile saveFileInfo(ServiceI service,String fileName,String filePath,String relationID, String date) {
            
            UploadFile fileEntity=new UploadFile();
            fileEntity.setFileName(fileName);
            fileEntity.setFilePath(filePath);
            fileEntity.setRelationID(relationID);
            fileEntity.setUploadTime(date);
            service.saveOrUpdate(fileEntity);
            return fileEntity;
        }
    View Code

    这里需要注意的是:在多文件上上传的时候一定要注意,文件路径的获取,一定是每个文件获取一次,如下图:

    如果一次性获取,会发生意外:如图

    文件路径找不到

     这样只能上传第一个文件,而且业务表中没有成功插入数据。 

    4.3 Postman进行测试:

    下面我们再来看数据库中是否有数据

      证明我们的接口是好用的,这里解释下为什么要返回文件的相关信息,因为对于图片来说,我们会上传完成显示预览图,对于文件来说返回链接,可以下载查看等,因此这么返回的路径。在前段中配置SRC就可以进行下载操作

    如下图:

    我们把链接复制进浏览器首先看图的:

    再来看文件的:

    这样可以方便我们对文件进行后续的操作。

       下面来说正事,我在这个项目上面才过的坑,希望大家引以为戒,不要掉进去。

      1. 文件上传路径

      因为我们的项目是在Eclipse上进行开发测试的,因此上传的文件会存在Eclipse工作空间中去,存到工作空间之后,在E:workspaceeclipse_workspace.metadata.pluginsorg.eclipse.wst.server.core mp0webapps下,是没有权限访问的,因此读取文件的时候会报错,所以最好的办法就是制定一个本地服务器的物理路径,然后通过Tomcat中的server.xml 进行配置映射,存到服务其中的物理路径是:E:servicewebappscommonuploadfilefd6e9dfb-7d1c-4fc6-8954-851258f6acc4.doc,那么只要我们开启的Tomcat服务,就可以通过:IP/common/upload/file/fd6e9dfb-7d1c-4fc6-8954-851258f6acc4.doc访问到我们上传的文件。其中common是项目名称,upload是指定上传的文件夹。

      另一种情况,我们可以直接把项目打成war包部署在Tomcat服务上,上传的文件就可以在我们服务器部署的位置找到,我采取的就是这种方式:

      当然了,我们也可以通过接口的方式对文件进项下载,思想就是:通过相关条件找到数据库中存放的文件路径,拿到文件路径生成文件以二进制的方式返回给浏览器。下面是采用SpringMVC开发的下载文件接口:

    /**
         * 返回下载流的二进制
         * @param path
         * @return
         * @throws UnsupportedEncodingException 
         */
        public static ResponseEntity<byte[]> getStreamByPath(String filePath,HttpServletRequest request,
                HttpServletResponse response,String fileName) throws UnsupportedEncodingException {
            
             response.setCharacterEncoding("utf-8");
             response.setContentType( "application/x-msdownload");
             response.addHeader("Content-Disposition","attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));// 设置文件名
             System.out.println("fdsfdsfsdf:"+filePath);
            URL url=null;
            ResponseEntity<byte[]> entity=null;
            InputStream is =null;
            try {
    //            url=new URL(filePath);
                
    //            System.out.println(url.toString());
    //            File file=new File(url.getPath());
                File file=new File(filePath);
                if(file.exists()){
                    String mimeType = URLConnection.guessContentTypeFromName(fileName);
                    if(mimeType==null){
                        mimeType = "application/octet-stream";
                    }
                    response.setContentType(mimeType);
                    byte[] body = null;
                    is = new FileInputStream(file);
                    body = new byte[is.available()];
                    is.read(body);
                    HttpHeaders headers = new HttpHeaders();
                    headers.add("Content-Disposition", "attchement;filename="+ URLEncoder.encode(fileName, "UTF-8"));
                    HttpStatus statusCode = HttpStatus.OK;
                    headers.setContentDispositionFormData("attachment", file.getName());     
                    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);   
                    entity = new ResponseEntity<byte[]>(body, headers, statusCode);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            
             return entity;
        }
    View Code

    下面是文件删除,文件删除其实很简单了,我们按照相关条件找到文件,然后删除即可。

    /**
         * 文件删除
         * @param path
         * @return
         * @throws UnsupportedEncodingException 
         */
        public static boolean deleteFile(String filePath,HttpServletRequest request,
                HttpServletResponse response,String fileName) throws UnsupportedEncodingException {
            boolean flag=false;
            if(StringUtil.isNull(fileName,filePath)){
                File file=new File(filePath);
                if(file.exists()){
                    flag=file.delete();
                }
            }
            
            return flag;
            
        }
    View Code

    切记:删除文件和数据库中的记录一定是一个事务,删除记录的同时删除数据库中的记录,否则会出现数据不一致的情况。

    最后附上相关配置文件:

    1.  SpringMVC.xml

    2. web.xml

    五、总结

      在做这些项目的时候,遇到的文件上传的坑大概就这么多,目前想到的附件上传只有这一种方式,大家如果有什么好的方法,欢迎评论区讨论!

           源码下载: https://download.csdn.net/download/qq_42389242/10746764

  • 相关阅读:
    Redis必须注意的慢查询问题
    使用kuernetes提供高可用的logstash服务
    使用kuernetes提供高可用的kibana服务
    Docker指定multiple Insecure registry的方法
    ELK系统中kibana展示数据的时区问题
    ElasticSearch快照备份及恢复
    离线安装redis集群
    Elasticsearch静态集群配置
    LCM的个数 (LCM Cardinality,UVa 10892)
    幂和阶乘 (Again Prime?No time.,UVa 10780)
  • 原文地址:https://www.cnblogs.com/10158wsj/p/9857141.html
Copyright © 2020-2023  润新知