1. 程式人生 > 其它 >Spring MVC 學習總結(五)——校驗與檔案上傳

Spring MVC 學習總結(五)——校驗與檔案上傳

目錄

Spring MVC不僅是在架構上改變了專案,使程式碼變得可複用、可維護與可擴充套件,其實在功能上也加強了不少。 驗證與檔案上傳是許多專案中不可缺少的一部分。在專案中驗證非常重要,首先是安全性考慮,如防止注入攻擊,XSS等;其次還可以確保資料的完整性,如輸入的格式,內容,長度,大小等。Spring MVC可以使用驗證器Validator與JSR303完成後臺驗證功能。這裡也會介紹方便的前端驗證方法。

一、Spring MVC驗證器Validator

Spring MVC驗證器Validator是一個介面,通過實現該介面來定義對實體物件的驗證,介面如下所示:

package org.springframework.validation;

/**
 * Spring MVC內建的驗證器介面
 */
public interface Validator {

    /**
     * 是否可以驗證該型別
     */
    boolean supports(Class<?> clazz);

    /**
     * 執行驗證 target表示要驗證的物件 error表示錯誤資訊
     */
    void validate(Object target, Errors errors);
}

1.1、定義驗證器

package com.zhangguo.springmvc51.entities;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

/**
 * 產品驗證器
 *
 */
public class ProductValidator implements Validator {

    //當前驗證器可以驗證的型別
    @Override
    public boolean supports(Class<?> clazz) {
        return Product.class.isAssignableFrom(clazz);
    }

    //執行校驗
    @Override
    public void validate(Object target, Errors errors) {
        //將要驗證的物件轉換成Product型別
        Product entity=(Product)target;
        //如果產品名稱為空或為空格,使用工具類
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required", "產品名稱必須填寫");
        //價格,手動判斷
        if(entity.getPrice()<0){
            errors.rejectValue("price", "product.price.gtZero", "產品價格必須大於等於0");
        }
        //產品型別必須選擇
        if(entity.getProductType().getId()==0){
            errors.rejectValue("productType.id", "product.productType.id.required", "請選擇產品型別");
        }
    }

}

ValidationUtils是一個工具類,中間有一些方可以用於判斷內容是否有誤。

1.2、執行校驗

// 新增儲存,如果新增成功轉回列表頁,如果失敗回新增頁,保持頁面資料
    @RequestMapping("/addSave")
    public String addSave(Model model, Product product, BindingResult bindingResult) {

        // 建立一個產品驗證器
        ProductValidator validator = new ProductValidator();
        // 執行驗證,將驗證的結果給bindingResult,該型別繼承Errors
        validator.validate(product, bindingResult);

        // 獲得所有的欄位錯誤資訊,非必要
        for (FieldError fielderror : bindingResult.getFieldErrors()) {
            System.out.println(fielderror.getField() + "," + fielderror.getCode() + "," + fielderror.getDefaultMessage());
        }

        // 是否存在錯誤,如果沒有,執行新增
        if (!bindingResult.hasErrors()) {
            // 根據型別的編號獲得型別物件
            product.setProductType(productTypeService.getProductTypeById(product.getProductType().getId()));
            productService.addProduct(product);
            return "redirect:/";
        } else {
            // 與form繫結的模型
            model.addAttribute("product", product);
            // 用於生成下拉列表
            model.addAttribute("productTypes", productTypeService.getAllProductTypes());
            return "product/add";
        }
    }

注意在引數中增加了一個BindingResult型別的物件,該型別繼承自Errors,獲得繫結結果,承載錯誤資訊,該物件中有一些方法可以獲得完整的錯誤資訊,可以使用hasErrors方法判斷是否產生了錯誤。

1.3、在UI中新增錯誤標籤

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<link href="styles/main.css" type="text/css" rel="stylesheet" />
<title>新增產品</title>
</head>
<body>
    <div class="main">
        <h2 class="title"><span>新增產品</span></h2>
        <form:form action="addSave" modelAttribute="product">
        <fieldset>
            <legend>產品</legend>
            <p>
                <label for="name">產品名稱:</label>
                <form:input path="name"/>
                <form:errors path="name" cssClass="error"></form:errors>
            </p>
            <p>
                <label for="title">產品型別:</label>
                <form:select path="productType.id">
                     <form:option value="0">--請選擇--</form:option>
                     <form:options items="${productTypes}"  itemLabel="name" itemValue="id"/>
                </form:select>
                <form:errors path="productType.id" cssClass="error"></form:errors>
            </p>
            <p>
                <label for="price">產品價格:</label>
                <form:input path="price"/>
                <form:errors path="price" cssClass="error"></form:errors>
            </p>
            <p>
              <input type="submit" value="儲存" class="btn out">
            </p>
        </fieldset>
        </form:form>
        <p style="color: red">${message}</p>
        <p>
            <a href="<c:url value="/" />"  class="abtn out">返回列表</a>
        </p>
    </div>
</body>
</html>

發生錯誤時解析的結果:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<link href="styles/main.css" type="text/css" rel="stylesheet" />
<title>新增產品</title>
</head>
<body>
    <div class="main">
        <h2 class="title"><span>新增產品</span></h2>
        <form id="product" action="addSave" method="post">
        <fieldset>
            <legend>產品</legend>
            <p>
                <label for="name">產品名稱:</label>
                <input id="name" name="name" type="text" value=""/>
                <span id="name.errors" class="error">產品名稱必須填寫</span>
            </p>
            <p>
                <label for="title">產品型別:</label>
                <select id="productType.id" name="productType.id">
                     <option value="0" selected="selected">--請選擇--</option>
                     <option value="11">數碼電子</option><option value="21">鞋帽服飾</option><option value="31">圖書音像</option><option value="41">五金家電</option><option value="51">生鮮水果</option>
                </select>
                <span id="productType.id.errors" class="error">請選擇產品型別</span>
            </p>
            <p>
                <label for="price">產品價格:</label>
                <input id="price" name="price" type="text" value="-10.0"/>
                <span id="price.errors" class="error">產品價格必須大於等於0</span>
            </p>
            <p>
              <input type="submit" value="儲存" class="btn out">
            </p>
        </fieldset>
        </form>
        <p style="color: red"></p>
        <p>
            <a href="/SpringMVC51/"  class="abtn out">返回列表</a>
        </p>
    </div>
</body>
</html>

1.4、測試執行

控制檯輸出:

二、JSR303驗證器

JSR是Java Specification Requests的縮寫,意思是Java 規範提案。是指向JCP(Java Community Process)提出新增一個標準化技術規範的正式請求。任何人都可以提交JSR,以向Java平臺增添新的API和服務。JSR已成為Java界的一個重要標準。https://jcp.org/en/home/index

JSR 303 – Bean Validation 是一個數據驗證的規範。JSR303只是一個標準,是一驗證規範,對這個標準的實現有:

hibernate-validatorApache BVal等。這裡我們使用hibernate-validator實現校驗。

2.1、新增hibernate-validator依賴

修改配置pom.xml配置檔案,新增依賴。

        <!--JSR303 Bean校驗-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.2.Final</version>
        </dependency>

2.2、註解Bean

在bean中設定驗證規則,示例程式碼如下:

package com.zhangguo.springmvc51.entities;

import java.io.Serializable;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Range;

/**
 * 產品
 */
public class Product implements Serializable {
    private static final long serialVersionUID = 1L;
    /*
     * 編號
     */
    private int id;
    /*
     * 名稱
     */
    @Size(min=1,max=50,message="名稱長度必須介於{2}-{1}之間")
    @Pattern(regexp="^[\\w\\u4e00-\\u9fa5]{0,10}$",message="格式錯誤,必須是字母數字與中文")
    private String name;
    /*
     * 價格
     */
    @Range(min=0,max=1000000,message="價格只允許在{2}-{1}之間")
    private double price;
    /*
     * 產品型別
     */
    private ProductType productType;

    public Product() {
        productType=new ProductType();
    }

    public Product(String name, double price) {
        super();
        this.name = name;
        this.price = price;
    }

    public Product(int id, String name, double price, ProductType type) {
        super();
        this.id = id;
        this.name = name;
        this.price = price;
        this.productType = type;
    }

    @Override
    public String toString() {
        return "編號(id):" + this.getId() + ",名稱(name):" + this.getName() + ",價格(price):" + this.getPrice()
                + ",型別(productType.Name):" + this.getProductType().getName();
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public ProductType getProductType() {
        return productType;
    }

    public void setProductType(ProductType productType) {
        this.productType = productType;
    }
}

更多的驗證註解如下所示:

2.2.1、空值檢查

@Null 驗證物件是否為null

@NotNull 驗證物件是否不為null, 無法查檢長度為0的字串

@NotBlank 檢查約束字串是不是Null還有被Trim的長度是否大於0,只對字串,且會去掉前後空格.

@NotEmpty 檢查約束元素是否為NULL或者是EMPTY.

2.2.2、Booelan檢查

@AssertTrue 驗證 Boolean 物件是否為 true

@AssertFalse 驗證 Boolean 物件是否為 false

2.2.3、長度檢查

@Size(min=, max=) 驗證物件(Array,Collection,Map,String)長度是否在給定的範圍之內

@Length(min=, max=) Validates that the annotated string is between min and max included.

2.2.4、日期檢查

@Past 驗證 Date 和 Calendar 物件是否在當前時間之前

@Future 驗證 Date 和 Calendar 物件是否在當前時間之後

2.2.5、正則

@Pattern 驗證 String 物件是否符合正則表示式的規則

2.2.6、數值檢查

建議使用在Stirng,Integer型別,不建議使用在int型別上,因為表單值為“”時無法轉換為int,但可以轉換為String為"",Integer為null

@Min 驗證 Number 和 String 物件是否大等於指定的值

@Max 驗證 Number 和 String 物件是否小等於指定的值

@DecimalMax 被標註的值必須不大於約束中指定的最大值. 這個約束的引數是一個通過BigDecimal定義的最大值的字串表示.小數存在精度

@DecimalMin 被標註的值必須不小於約束中指定的最小值. 這個約束的引數是一個通過BigDecimal定義的最小值的字串表示.小數存在精度

@Digits 驗證 Number 和 String 的構成是否合法

@Digits(integer=,fraction=) 驗證字串是否是符合指定格式的數字,interger指定整數精度,fraction指定小數精度。

2.2.7、範圍

@Range(min=, max=) 檢查被註解物件的值是否處於min與max之間,閉區間,包含min與max值

@Range(min=10000,max=50000,message="必須介於{2}-{1}之間")

2.2.8、其它註解

@Valid 遞迴的對關聯物件進行校驗, 如果關聯物件是個集合或者陣列,那麼對其中的元素進行遞迴校驗,如果是一個map,則對其中的值部分進行校驗.(是否進行遞迴驗證),該註解使用在Action的引數上。

@CreditCardNumber信用卡驗證

@Email 驗證是否是郵件地址,如果為null,不進行驗證,算通過驗證。

@ScriptAssert(lang= ,script=, alias=)

@URL(protocol=,host=, port=,regexp=, flags=)

2.3、註解控制器引數

在需要使用Bean驗證的引數物件上註解@Valid,觸發驗證,示例程式碼如下:

package com.zhangguo.springmvc51.controllers;

import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.zhangguo.springmvc51.entities.Product;
import com.zhangguo.springmvc51.services.ProductService;
import com.zhangguo.springmvc51.services.ProductTypeService;

@Controller
@RequestMapping("/goods")
public class GoodsController {
    @Autowired
    ProductService productService;
    @Autowired
    ProductTypeService productTypeService;
    
    // 新增,渲染出新增介面
    @RequestMapping("/add")
    public String add(Model model) {
        // 與form繫結的模型
        model.addAttribute("product", new Product());
        // 用於生成下拉列表
        model.addAttribute("productTypes", productTypeService.getAllProductTypes());
        return "product/addGoods";
    }

    // 新增儲存,如果新增成功轉回列表頁,如果失敗回新增頁,保持頁面資料
    @RequestMapping("/addGoodsSave")
    public String addSave(Model model, @Valid Product product, BindingResult bindingResult) {

        // 是否存在錯誤,如果沒有,執行新增
        if (!bindingResult.hasErrors()) {
            // 根據型別的編號獲得型別物件
            product.setProductType(productTypeService.getProductTypeById(product.getProductType().getId()));
            productService.addProduct(product);
            return "redirect:/";
        } else {
            // 與form繫結的模型
            model.addAttribute("product", product);
            // 用於生成下拉列表
            model.addAttribute("productTypes", productTypeService.getAllProductTypes());
            return "product/addGoods";
        }
    }
    
    @RequestMapping("/products")
    @ResponseBody
    public List<Product> getProduct(){
        return productService.getAllProducts();
    }
}

2.4、在UI中新增錯誤標籤

這裡與Spring MVC Validator基本一致,在product目錄下新增一個名為addGoods.jsp的頁面,指令碼如下所示:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<link href="<c:url value="/styles/main.css" />" type="text/css" rel="stylesheet" />
<title>新增產品</title>
</head>
<body>
    <div class="main">
        <h2 class="title"><span>新增產品</span></h2>
        <form:form action="addGoodsSave" modelAttribute="product">
        <fieldset>
            <legend>產品</legend>
            <p>
                <label for="name">產品名稱:</label>
                <form:input path="name"/>
                <form:errors path="name" cssClass="error"></form:errors>
            </p>
            <p>
                <label for="title">產品型別:</label>
                <form:select path="productType.id">
                     <form:option value="0">--請選擇--</form:option>
                     <form:options items="${productTypes}"  itemLabel="name" itemValue="id"/>
                </form:select>
                <form:errors path="productType.id" cssClass="error"></form:errors>
            </p>
            <p>
                <label for="price">產品價格:</label>
                <form:input path="price"/>
                <form:errors path="price" cssClass="error"></form:errors>
            </p>
            <p>
              <input type="submit" value="儲存" class="btn out">
            </p>
        </fieldset>
        </form:form>
        <p style="color: red">${message}</p>
        <p>
            <a href="<c:url value="/" />"  class="abtn out">返回列表</a>
        </p>
    </div>
</body>
</html>

2.5、測試執行

小結:從上面的示例可以看出這種驗證更加方便直觀,一次定義反覆使用,以編輯更新時驗證同樣可以使用;另外驗證的具體資訊可以存放在配置檔案中,如message.properties,這樣便於國際化與修改。

三、使用jQuery擴充套件外掛Validate實現前端校驗

jquery.validate是基於jQuery的一個B/S客戶端驗證外掛,藉助jQuery的優勢,我們可以迅速驗證一些常見的輸入,大大提高了開發效率,下面是很多年前本人做的學習筆記:

3.1、jQuery擴充套件外掛validate—1基本使用方法

3.2、jQuery擴充套件外掛validate—2通過引數設定驗證規則

3.3、jQuery擴充套件外掛validate—3通過引數設定錯誤資訊

3.4、jQuery擴充套件外掛validate—4設定錯誤提示的樣式

3.5、jQuery擴充套件外掛validate—5新增自定義驗證方法

3.6、jQuery擴充套件外掛validate—6radio、checkbox、select的驗證

示例下載

注意:validate只是使驗證變得方便,簡單,本質還是使用js,不論多麼強大的js驗證,當用戶把js禁用或使用機器直接發起請求時都不能確保資料的完整性,所有不要把希望寄託在客戶端驗證,個人認為每一個客戶端驗證都要伺服器進行再次驗證。

四、檔案上傳

在Spring MVC中有兩種實現上傳檔案的辦法,第一種是Servlet3.0以下的版本通過commons-fileupload與commons-io完成的通用上傳,第二種是Servlet3.0以上的版本的Spring內建標準上傳,不需藉助第3方元件。通用上傳也相容Servlet3.0以上的版本。

4.1、Servlet3.0以下的通過commons-fileupload上傳

4.1.1、新增上傳依賴包

因為需要藉助第三方上傳元件commons-fileupload與commons-io,所以要修改pom.xml檔案新增依賴,依賴的內容如下:

        <!--檔案上傳 -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>

依賴成功後的結果:

4.1.2、新增上傳頁面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>上傳檔案</title>
</head>
<body>
<h2>上傳檔案</h2>
<form action="fileSave" method="post"  enctype="multipart/form-data">
  <p>
     <label for="files">檔案:</label>
     <input type="file" name="files" id="files" multiple="multiple" />
   </p>
   <p>
   <button>提交</button>
   </p>
   <p>
     ${message}
   </p>
</form>
</body>
</html>

如果有成功上傳,頁面中有幾個關鍵點要注意:method的值必為Post;enctype必須為multipart/form-data,該型別的編碼格式專門用於二進位制資料型別;上傳表單元素必須擁有name屬性;

4.1.3、修改配置檔案,增加上傳配置

預設情總下Spring MVC對檔案上傳的檢視內容是不能解析的,要配置一個特別的解析器解析上傳的內容,修改springmvc-servlet.xml配置檔案,增加如下配置內容:

    <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>

增加了一個型別為CommonsMultipartResolver型別的解析器,各屬性的意義:

defaultEncoding:預設編碼格式

maxUploadSize:上傳檔案最大限制(位元組byte)

maxInMemorySize:緩衝區大小

當Spring的前置中心控制器檢查到客戶端傳送了一個多分部請求,定義在上下文中的解析器將被啟用並接手處理。解析器將當前的HttpServletRequest包裝成一個支援多部分檔案上傳的MultipartHttpServletRequest物件。在控制器中可以獲得上傳的檔案資訊。

CommonsMultipartResolver用於通用的檔案上傳,支援各種版本的Servlet。

StandardServletMultipartResolver用於Servlet3.0以上的版本上傳檔案。

4.1.4、增加控制器與Action

package com.zhangguo.springmvc51.controllers;

import java.io.File;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/up")
public class UpFileController {
    
    @RequestMapping("/file")
    public String file(Model model){
        return "up/upfile";
    }
    
    @RequestMapping(value="/fileSave",method=RequestMethod.POST)
    public String fileSave(Model model,MultipartFile[] files,HttpServletRequest request) throws Exception{
        
        //檔案存放的位置
        String path=request.getServletContext().getRealPath("/files");
        for (MultipartFile file : files) {
            System.out.println(file.getOriginalFilename());
            System.out.println(file.getSize());
            System.out.println("--------------------------");
            File tempFile=new File(path, file.getOriginalFilename());
            file.transferTo(tempFile);
        }
        
        System.out.println(path);
        return "up/upfile";
    }
    
}

注意這裡定義的是一個數組,可以接受多個檔案上傳,如果單檔案上傳可以修改為MultipartFile型別;另外上傳檔案的細節在這裡並沒有花時間處理,比如檔案重名的問題,路徑問題,關於重名最簡單的辦法是重新命名為GUID檔名。

4.1.5、測試執行

4.2、Servlet3.0以上檔案上傳

Servlet3.0以上的版本不再需要第三方元件Commons.io和commons-fileupload,上傳的方式與4.1提到基本一樣,但配置稍有區別,可以使用@MultipartConfig註解在Servlet上進行配置上傳,也可以在web.xml上進行配置。

4.2.1、修改web.xml配置上傳引數

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:springmvc-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <!--Servlet3.0以上檔案上傳配置 -->
        <multipart-config>
            <max-file-size>5242880</max-file-size><!--上傳單個檔案的最大限制5MB -->
            <max-request-size>20971520</max-request-size><!--請求的最大限制20MB,一次上傳多個檔案時一共的大小 -->
            <file-size-threshold>0</file-size-threshold><!--當檔案的大小超過臨界值時將寫入磁碟 -->
        </multipart-config>
    </servlet>

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
  • file-size-threshold:數字型別,當檔案大小超過指定的大小後將寫入到硬碟上。預設是0,表示所有大小的檔案上傳後都會作為一個臨時檔案寫入到硬碟上。

  • location:指定上傳檔案存放的目錄。當我們指定了location後,我們在呼叫Part的write(String fileName)方法把檔案寫入到硬碟的時候可以,檔名稱可以不用帶路徑,但是如果fileName帶了絕對路徑,那將以fileName所帶路徑為準把檔案寫入磁碟,不建議指定。

  • max-file-size:數值型別,表示單個檔案的最大大小。預設為-1,表示不限制。當有單個檔案的大小超過了max-file-size指定的值時將丟擲IllegalStateException異常。

  • max-request-size:數值型別,表示一次上傳檔案的最大大小。預設為-1,表示不限制。當上傳時所有檔案的大小超過了max-request-size時也將丟擲IllegalStateException異常。

4.2.2、修改pom.xml依賴資訊

把pom.xml中對檔案上傳第三方的依賴刪除,刪除依賴儲存後的結果:

4.2.3、修改springmvc-servlet.xml配置資訊

將原有的檔案上傳通用解析器更換為標準解析器,修改後的配置如下所示:

    <!--檔案上傳解析器 -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
    </bean>

定義了一個標準的檔案上傳解析器,更多屬性可以檢視這個類的原始碼。這步非常關鍵,否則上傳會失敗。另外id不要換成別的名稱,更換後可能會上傳失敗。

4.2.4、定義檢視

在views/up/下定義名稱為file3.jsp檔案,內容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>上傳檔案 - Servlet3.0</title>
</head>
<body>
<h2>上傳檔案 - Servlet3.0</h2>
<form action="file3Save" method="post"  enctype="multipart/form-data">
  <p>
     <label for="files">檔案:</label>
     <input type="file" name="files" id="files" multiple="multiple" />
   </p>
   <p>
   <button>提交</button>
   </p>
   <p>
     ${message}
   </p>
</form>
</body>
</html>

multiple="multiple"這個屬性是HTML5新增加的屬性,一些舊版的瀏覽器可能不支援,使用JavaScript可以處理一下。

4.2.5、定義Action

在UpFileController中定義兩個action,一個叫file3用於展示上傳頁面,一個叫file3Save用於處理上傳文,程式碼如下:

package com.zhangguo.springmvc51.controllers;

import java.io.File;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/up")
public class UpFileController {
    
    @RequestMapping("/file")
    public String file(Model model){
        return "up/upfile";
    }
    
    @RequestMapping(value="/fileSave",method=RequestMethod.POST)
    public String fileSave(Model model,MultipartFile[] files,HttpServletRequest request) throws Exception{
        
        //檔案存放的位置
        String path=request.getServletContext().getRealPath("/files");
        for (MultipartFile file : files) {
            System.out.println(file.getOriginalFilename());
            System.out.println(file.getSize());
            System.out.println("--------------------------");
            File tempFile=new File(path, file.getOriginalFilename());
            file.transferTo(tempFile);
        }
        
        System.out.println(path);
        return "up/upfile";
    }
    
    
    @RequestMapping("/file3")
    public String file3(Model model){
        return "up/upfile3";
    }
    
    @RequestMapping(value="/file3Save",method=RequestMethod.POST)
    public String file3Save(Model model,MultipartFile[] files,HttpServletRequest request) throws Exception{
        
        //檔案存放的位置
        String path=request.getSession().getServletContext().getRealPath("/files");
        System.out.println(path);
        String msg="";
        for (MultipartFile file : files) {
            //儲存檔案
            File tempFile=new File(path, file.getOriginalFilename());
            file.transferTo(tempFile);
            msg+="<img src='../files/"+file.getOriginalFilename()+"' width='200' />";
        }
        model.addAttribute("message", msg);
        return "up/upfile3";
    }
    
}

4.2.6、測試執行

五、示例下載

點選下載

github直接預覽或下載