2017年12月26日 星期二

資料挷定 (Spring3.x MVC 六)

※基本資料型別和 Wrapper、String,都能被 springmvc 轉換成功,但日期不行,會出 400且還沒有錯誤訊息

※@InitBinder

※java bean

public class Book {
    private Integer id;
    private String name;
    private Integer price;
    private Date date;
    
    // setter/getter...
}



※controller

@RequestMapping("book")
public String pojo(Book b) {
    System.out.println(b.getId());
    System.out.println(b.getName());
    System.out.println(b.getPrice());
    System.out.println(b.getDate());
    return "hello";
}
    
    
    
@InitBinder
public void binder(WebDataBinder bind) {
    bind.setDisallowedFields("id");
    
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    df.setLenient(false);// 不給打數字
    bind.registerCustomEditor(Date.class, new CustomDateEditor(df, true)); // 第二個參數為可以空
}

※標 @InitBinder 的方法只能回傳 null

※第一個表示 id 設為空,所以前端塞值也沒用

※測試

<a href="ooo/xxx/book.mvc?id=99&name=book&price=500&date=2000-01-01">bind</a>





※@NumberFormat、@DateTimeFormat


@InitBinder 寫好後,每個使用上例的方式,都會去抓,例如我再寫一個 ComicBook,裡面一樣有日期欄位,且名稱也一樣,但可能一個只想要年月日,另一個是年月日時分秒,這時候可以使用這兩個 annotation,都是在 spring-context,jar 包裡的 org.springframework.format.annotation;



public class Book {
    private Integer id;
    private String name;
    
    @NumberFormat(style=Style.CURRENCY, pattern="#,###.#")
    private Integer price;
    
    @DateTimeFormat(iso=ISO.DATE, pattern="yyyy-MM-dd")
    private Date date;
    
    // setter/getter...
}

※@DateTimeFormat 裡的 iso 有預設值,這個 pattern 就是預設值,所以也可以不寫,其他預設值,點進去看有註解



※Hibernate 驗證

官網有說明,要使用必需添加 <mvc:annotation-driven/> ,然後配合 @Valid 使用,但其實還要有 jar 包,否則 import 不到,可看 Hibernate Validator 第六版的文件
hibernate-validator 6.0.7 依賴三個 jar 包,validation-api、jboss-logging、classmate

 ※validation-api 裡的 javax.validation.constraints 的 API,有 22 個,然後每個都有 List,所以總共是 44 個,但 List 我怎麼試都是 500,網上也有說可能是規格錯誤



※教學的部分,我發現 4.3 版翻譯的較完全

※以下是看文檔翻譯的,我沒有每個都試過

空:

@Null:必需是 null
@NotNull:不能是 null
@NotBlank:不能是 null 或全是空格,只支援 CharSequence
@NotEmpty:不能是 null 或空,支援 CharSequence Collection Map Array


布林:

@AssertTrue:必需是 true
@AssertFalse:必需是 false


數字:

.@Mix、@Max 支援 6 種格式,byte short int long BigInteger BigDecimal


@Min(number):最小數字是什麼,所以必需是數字,而且要 >= 設定的數字,@Null是有效的

@Max(number):最大數字是什麼,所以必需是數字,而且要 <= 設定的數字,@Null是有效的



.@DecimalMin、@DecimalMax、@Digits 支援 7 種格式,byte short int long BigInteger BigDecimal CharSequence,要注意,並沒有 float double


@DecimalMin(number):最小數字是什麼,所以必需是數字,而且要 >= 設定的數字,@Null是有效的

@DecimalMax(number):最大數字是什麼,所以必需是數字,而且要 <= 設定的數字,@Null是有效的


.範圍

@Digits:(integer, fraction):必需是數字,且介於指定的範圍,@Null是有效的

@Size(min, max):必需介於指定的範圍,支援 CharSequence Collection Map array



正負數:

有四種,支援 8 種格式,byte short int long float double BigInteger BigDecimal
@Positive:必需為正數且不是0,@Null是有效的
@PositiveOrZero:必需為正數,0有效,@Null是有效的
@Negative:必需為負數且不是0,@Null是有效的
@NegativeOrZero:必需為負數,0有效,@Null是有效的

日期:

有四種,支援 16 種 格式
java.util.Date
java.util.Calendar
java.time.Instant
java.time.LocalDate
java.time.LocalDateTime
java.time.LocalTime
java.time.MonthDay
java.time.OffsetDateTime
java.time.OffsetTime
java.time.Year
java.time.YearMonth
java.time.ZonedDateTime
java.time.chrono.HijrahDate
java.time.chrono.JapaneseDate
java.time.chrono.MinguoDate
java.time.chrono.ThaiBuddhistDate

@PastOrPresent:必需是過去日期(包括現在日期),@Null是有效的
@Past:必需是過去日期,@Null是有效的
@Future:必需是未來日期,@Null是有效的
@FutureOrPresent:必需是未來日期(包括現在日期),@Null是有效的


其他:

@Pattern(regexp):必需合乎正則,只支援 CharSequence,@Null是有效的
@Email(regexp):必需是 email,只支援 CharSequence


※每個 annotation 都一定會有的三個屬性,message、groups、payload
message 是驗證不過時要顯示在控制台的訊息
其他兩個我沒看懂,參考這裡


※範例

設定好<mvc:annotation-driven/>後,如下

※java bean

public class Book {
    @Max(value=5, message="數字太大")
    // @Max.List({@Max(5),@Max(15),@Max(10)})
    private Integer id;
    
    @NotNull(message="不能為空")
    private String name;
    
    private Integer price;
    
    private Date date;
    
    // setter/getter...
}

※List 沒有試成功過

※controller

@RequestMapping("book")
public String pojo(@Valid Book b, BindingResult br) {
    System.out.println(b.getId());
    System.out.println(b.getName());
    System.out.println(b.getPrice());
    System.out.println(b.getDate());
    
    if(br.getErrorCount() > 0) {
        /*
        for(ObjectError oe:br.getAllErrors()) {
            System.out.println(oe.getObjectName());
            System.out.println(oe.getDefaultMessage());
    
            System.out.println();
            System.out.println("Arguments");
            for(Object o:oe.getArguments()) {
                System.out.println(o);
            }
    
            System.out.println();
            System.out.println("Codes");
            for(String s:oe.getCodes()) {
                System.out.println(s);
            }
        }
        */
    
        System.out.println("FieldErrors");
        for(FieldError fe:br.getFieldErrors()) {
            System.out.println(fe.getDefaultMessage());
            return "error";
        }
    }
    
    return "hello";
}

※<a href="ooo/xxx/book.mvc?id=10&name=book&price=100&date=2000-01-01">bind</a>

※如果不寫  @Valid,那 java bean 有寫跟沒寫一樣

※使用 BindingResult 可以判斷有沒有錯,跳轉到其他頁面



※hibernate-validator 裡 org.hibernate.validator.constraints 的 API


也有很多,只列出幾個常用的,標為棄用,我是用第六版試的,有可能第五版是 ok 的

@Length(min, max):必需介於指定的範圍
@Range(min, max):必需介於指定的範圍,應用在數字和字串
@CodePointLength(min, max):字串的長度必需在指定的範圍
@URL:必需是網址
@NotEmpty:標為棄用
@NotBlank:標為棄用
@Email:標為棄用

沒有留言:

張貼留言