基於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:\workspace\eclipse_workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\webapps下,是沒有權限訪問的,因此讀取文件的時候會報錯,所以最好的辦法就是制定一個本地服務器的物理路徑,然后通過Tomcat中的server.xml 進行配置映射,存到服務其中的物理路徑是:E:\service\webapps\common\upload\file\fd6e9dfb-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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM