文件上傳的幾種方式


文件上傳

前端提交文件方式

  1. 請求方式為POST:< form action=”uploadServlet” method=”post” />
  2. 使用file的表單域:< input type=”file” name=”file” />
  3. 用multipart/form-data的請求編碼方式:< form action=”uploadServlet” method=”post” enctype=”multipart/form-data” />
< form action="uploadServlet" method="post" enctype="multipart/form-data">
    File: < input type="file" name="file"/>
    < input type="submit" value="Submit"/>
 </ form>

方式一:JavaWeb 的HttpServlet

  1. 需要commons-fileupload-1.4.jar ,commons-io-2.11.0.jar, 使用HttpServletRequest時需要導入servlet-api的包

    commons-fileupload需要commons-io

  2. 需要在web.xml中添加servlet映射路徑

public class FileServlet extends HttpServlet {
    @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       // 文件上傳
       // 1. 判斷上傳的表單是普通表單還是文件表單	
       if(!ServletFileUpload.isMultipartContent(req)){
           return ; // 終止程序,說明這是一個普通的表單
       }	
       // 2. 創建上傳文件的保存路徑,建議在web-inf目錄下,用戶不能直接訪問到
       String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
       File file = new File(uploadPath);
       // 目錄不存在就創建這個目錄,針對第一次上傳時
       if(!file.exists()){
           file.mkdir(); // 創建目錄
       }
       // 緩存,針對上傳的文件較大時,存入緩存文件中,需要永久保存才轉到upload文件夾下
  
       /**處理文件上傳,一般都會通過流的方式進行操作,
        * 這里使用apache提供的組件進行實現 common-fileupload
        * */
       // 3. 獲取DiskFileItemFactory對象,處理文件上傳的路徑或者大小限制,都有默認的
       DiskFileItemFactory factory = new DiskFileItemFactory();
       //4. 獲取ServletFileUpload
       ServletFileUpload upload = new ServletFileUpload(factory);
       // 5. 處理上傳的文件
           //把前端請求解析,封裝成一個FileItem對象,需要從ServletFileUpload對象中獲取
       try {
           List<FileItem> fileItems = upload.parseRequest(req);
           // 遍歷每一個FileItem,表單中的每一項input被封裝成一個FileItem對象
           for (FileItem fileItem : fileItems) {
               // 判斷是否是普通類型,表單中的項
               if (fileItem.isFormField()){
                   // 普通類型
  
               }else {
                   //文件類型
                   // 獲取到上傳的文件的路徑,進而獲取到文件名
                   String filePath = fileItem.getName();
                   String fileName = filePath.substring(filePath.lastIndexOf("/") + 1);
                   // 通過uuid+fileName獲取到新的文件名
                   String newFileName = UUID.randomUUID().toString() + fileName;
  
                   // 獲取FileItem的流
                   InputStream in = fileItem.getInputStream();
  
                   // 把文件復制服務器上
                   String newFilePath = uploadPath+"/" + newFileName;
                       FileOutputStream out = new FileOutputStream(newFilePath);
  
                   byte[] buffer = new byte[1024];
                   int len;
                   while ((len = in.read(buffer)) != -1){
                       out.write(buffer,0,len);
                   }
  
                   // 關閉資源 , 清除fileItem的緩存
                   out.close();
                   in.close();
  
                   fileItem.delete();
               }
           }
       } catch (FileUploadException e) {
           e.printStackTrace();
       }
   }
}

MultipartResolver 是一個接口,它的實現類如下圖所示,分為 CommonsMultipartResolver 類和 StandardServletMultipartResolver

方式二:CommonsMultipartResolver

基於Apache fileupload文件上傳(了解)

在web階段中我們用到的是 Apache fileupload這個組件來實現上傳,在springmvc中對它進行了封裝,讓我們使用起來比較方便,但是底層還是由Apache fileupload來實現的。

  1. 需要commons-fileupload-1.4.jar ,commons-io-2.11.0.jar

    commons-fileupload需要commons-io

  2. 配置MultipartResolver處理器(文件上傳解析器) bean的名字必須為:multipartResolver

<!-- SpringMVC上傳文件時,需要配置MultipartResolver處理器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8" />
        <property name="maxUploadSize" value="10485760000" />
        <property name="maxInMemorySize" value="40960" />
    </bean>

解析HttpServletRequest的方式

@RequestMapping(value = "/addproduct", method = RequestMethod.POST)
@ResponseBody
private Map<String, Object> addProduct(HttpServletRequest request) {
  Map<String, Object> modelMap = new HashMap<String, Object>();
  //接受前端參數的變量的初始化,包括商品、縮略圖、詳情圖列表實體類
  ObjectMapper mapper = new ObjectMapper();
  Product product = null;
  String productStr = HttpServiceRequestUtil.getString(request, "productStr");
  MultipartHttpServletRequest multipartRequest = null;
  ImageHolder thumbnail = null;
  List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
  //通用的解析器
  CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
  try {
      //若請求中存在文件流,則取出相關的文件(包括縮略圖和詳情圖)
      //isMutipart是用來判斷是否有文件上傳
      if (multipartResolver.isMultipart(request)) {
          multipartRequest = (MultipartHttpServletRequest) request;
          //取出縮略圖並構建ImageHolder對象
          CommonsMultipartFile thumbnailFile = (CommonsMultipartFile) multipartRequest.getFile("thumbnail");
          thumbnail = new ImageHolder(thumbnailFile.getOriginalFilename(), thumbnailFile.getInputStream());
          //取出詳情圖列表並構建List<ImageHolder>列表對象,最多支持六張圖片上傳
          for (int i = 0; i < IMAGEMAXCOUNT; i++) {
              CommonsMultipartFile productImgFile = (CommonsMultipartFile) multipartRequest.getFile("productImg" + i);
              if (productImgFile != null) {
                  ImageHolder productImg = new ImageHolder(productImgFile.getOriginalFilename(), productImgFile.getInputStream());
                  productImgList.add(productImg);
              } else {
                  //若取出的第i個詳情圖片文件流為空,則終止循環
                  break;
              }
          }
      } else {
          modelMap.put("success", false);
          modelMap.put("errMsg", "上傳圖片不能為空");
          return modelMap;
      }
  } catch (Exception e) {
      modelMap.put("success", false);
      modelMap.put("errMsg", e.toString());
      return modelMap;
  }
}

狂神文件輸入輸出的上傳:

@Controller
public class FileController {
    //@RequestParam("file") 將name=file控件得到的文件封裝成CommonsMultipartFile 對象
    //批量上傳CommonsMultipartFile則為數組即可
    @RequestMapping("/upload")
    public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {

        //獲取文件名 : file.getOriginalFilename();
        String uploadFileName = file.getOriginalFilename();

        //如果文件名為空,直接回到首頁!
        if ("".equals(uploadFileName)){
            return "redirect:/index.jsp";
        }
        System.out.println("上傳文件名 : "+uploadFileName);

        //上傳路徑保存設置
        String path = request.getServletContext().getRealPath("/upload");
        //如果路徑不存在,創建一個
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }
        System.out.println("上傳文件保存地址:"+realPath);

        InputStream is = file.getInputStream(); //文件輸入流
        OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件輸出流

        //讀取寫出
        int len=0;
        byte[] buffer = new byte[1024];
        while ((len=is.read(buffer))!=-1){
            os.write(buffer,0,len);
            os.flush();
        }
        os.close();
        is.close();
        return "redirect:/index.jsp";
    }
}

transferTo()形式上傳:

/*
 * 采用file.Transto 來保存上傳的文件
 */
@RequestMapping("/upload2")
public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {

    //上傳路徑保存設置
    String path = request.getServletContext().getRealPath("/upload");
    File realPath = new File(path);
    if (!realPath.exists()){
        realPath.mkdir();
    }
    //上傳文件地址
    System.out.println("上傳文件保存地址:"+realPath);

    //通過CommonsMultipartFile的方法直接寫文件(注意這個時候)
    file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));

    return "redirect:/index.jsp";
}

方式三:StandardServletMultipartResolver

基於Servlet3.0以上版本的文件上傳

  1. 需要依賴Servlet3.0以上版本

  2. 配置MultipartResolver處理器(文件上傳解析器) bean的名字必須為:multipartResolver

    <bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
    
  3. Conreoller

@RequestMapping("/upload")
public Result<?> upload(MultipartFile file, HttpServletRequest request) throws IllegalStateException, IOException {
        Result<Object> result = new Result<>();
        result.setSuccess(false);
        //檢查文件是否為空
        if (file.isEmpty()) {
            result.setMessage("上傳文件不能為空");
            return result;
        }
		//檢查文件大小  2097152 =2M
		if(file.getSize() > 2097152) {
            result.setMessage("文件大於2M");
            return result;
		}
		//檢查是否是圖片
		try {
			BufferedImage bi = ImageIO.read(file.getInputStream());
			if(bi == null){
                result.setMessage("不是圖片");
            	return result;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
        // 獲取文件存儲路徑(絕對路徑),實際開發中,建議直接使用一個服務器的絕對地址
        String path = request.getServletContext().getRealPath("/WEB-INF/upload/");
//        System.out.println("服務器中的相對/WEB-INF/upload/完整路徑:"+path);
        //獲取上傳文件后綴名
//        System.out.println("客戶端上傳的文件名:"+file.getOriginalFilename());
        String originalFilename = file.getOriginalFilename();
        String suff = originalFilename.substring(originalFilename.lastIndexOf("."));
        // 獲取文件名
        String fileName = UUID.randomUUID().toString().replaceAll("-","")+suff;
        // 創建文件實例
        File filePath = new File(path, fileName);
        // 如果文件目錄不存在,創建目錄
        if (!filePath.getParentFile().exists()) {
            filePath.getParentFile().mkdirs();
            System.out.println("創建目錄" + filePath);
        }
        // 寫入文件
        file.transferTo(filePath);

        result.setMessage("上傳成功");
        result.setCode(200);
        result.setSuccess(true);
        return result;
    }

說明:如果前端的文件上傳控件的name名和處理器方法參數名不一致可以使用該注解@RequestPart("參數名")或@RequestParam("參數名")

@RequestPart在前后端不分離的文件上傳(基於表單文件上傳)中和@RequestParam意義效果一致

@RequestPart可以處理特殊的數據格式,如JSON

一致:(實際開發中建議方式)

//前端:
<input type="file" name="file">
//后端:
public String upload(MultipartFile file, HttpServletRequest request){}

如果不一致:

//前端:
<input type="file" name="uploadFile">
//后端:
public String upload(@RequestParam("uploadFile") MultipartFile file, ....){}
//或
public String upload(@RequestPart("uploadFile") MultipartFile file, ....){}

多文件上傳

多文件上傳只需要把html代碼中的多個< input type="file" name="file" >name屬性設置為一樣的就好。然后在controller中使用MultipartFile數組接受就行。

@RequestMapping(value="/upload", method=RequestMethod.POST)
public String fileUpload(@RequestParam("file") MultipartFile[] file){
   //遍歷數組單個上傳
    for (MultipartFile multipartFile : file) {
        
    }
}

補充:如果想要限制文件上傳類型

解決思路:

1)基於前端,限制文件類型

2)基於后端,建議使用SpringMVC框架的攔截器進行攔截校驗


免責聲明!

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



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