SpringMVC系列--註解

其他網址

springmvc 註解總結 - SpringMVC中文官網

@RequestMapping

1.1、@RequestMapping 標註位置

        RequestMapping是一個用來處理請求地址映射的註解,將請求映射到對應的控制器方法中,可用於類或方法上。用於類上,表示類中的所有響應請求的方法都是以該地址作爲父路徑。

        RequestMapping請求路徑映射,如果標註在某個controller的類級別上,則表明訪問此類路徑下的方法都要加上其配置的路徑;如果標註在方法上,表明哪個具體的方法來接受處理某次請求。最常用是標註在方法上,表明哪個具體的方法來接受處理某次請求。如下所示:

@Controller
@RequestMapping(value="/book")
public class BookController {
    @RequestMapping(value="/title")
    public String getTitle(){
        return "title";
    }           
    
    @RequestMapping(value="/content")
    public String getContent(){
        return "content";
    } 
}

由於BookController類加了value="/book"的@RequestMapping的註解,所以相關路徑都要加上"/book",即請求的url分別爲:

  • (1) http://localhost:8080/book/title
  • (2) http://localhost:8080/book/content

注意:@RequestMapping的value值前後是否有"/"對請求的路徑沒有影響,即value="book" 、"/book"、"/book/"其效果是一樣的。

1.2、RequestMapping的屬性value:

屬性value指定請求的實際url,分爲以下幾種情況:

(1)url可以是普通的具體值。如前面的value="/book",

(2)url也可以含某變量的一類值,如下所示:

@RequestMapping(value="/get/{bookId}")
public String getBookById(@PathVariable String bookId,Model model){
    model.addAttribute("bookId", bookId);
    return "book";
} 

路徑中的bookId可以當變量,@PathVariable註解即提取路徑中的變量值。

(3)ant風格

  • @RequestMapping(value="/get/id?"):可匹配"/get/id1"或"/get/ida",但不匹配"/get/id"或"/get/idaa";
  • @RequestMapping(value="/get/id*"):可匹配"/get/idabc"或"/get/id",但不匹配"/get/idabc/abc";
  • @RequestMapping(value="/get/id/*"):可匹配"/get/id/abc",但不匹配"/get/idabc";
  • @RequestMapping(value="/get/id/**/{id}"):可匹配"/get/id/abc/abc/123"或"/get/id/123",也就是Ant風格和URI模板變量風格可混用。

(4)含正則表達式的一類值

@RequestMapping(value="/get/{idPre:\\d+}-{idNum:\\d+}"):可以匹配"/get/123-1",但不能匹配"/get/abc-1",這樣可以設計更加嚴格的規則。可以通過@PathVariable 註解提取路徑中的變量(idPre,idNum)

(5)或關係

@RequestMapping(value={"/get","/fetch"}):即 /get或/fetch 都會映射到該方法上。

1.3、RequestMapping的method屬性:

method:指定請求的method類型,包括 GET、POST、PUT、DELETE 等;

@RequestMapping(value="/get/{bookid}",method={RequestMethod.GET,RequestMethod.POST})

1.4、RequestMapping的params屬性:

params:指定request中必須包含某些參數值時,才讓該方法處理。

@RequestMapping(params="action=del"),請求參數包含"action=del",如:"http://localhost:8080/book?action=del"

@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {

  @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue")
  public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {    
    // implementation omitted
  }
}

僅處理請求中包含了名爲"myParam",值爲"myValue"的請求。

1.5、RequestMapping的headers屬性:

headers:指定request中必須包含某些指定的header值,才能讓該方法處理請求。@RequestMapping(value="/header/id", headers = "Accept=application/json")

上述註解表示請求的URL必須爲 "/header/id 且請求頭中必須有"Accept =application/json"參數即可匹配。

@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {

@RequestMapping(value = "/pets", method = RequestMethod.GET, headers="Referer=http://www.ifeng.com/")
  public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {    
    // implementation omitted
  }
}

上述代碼僅處理請求的header中包含了指定"Refer"請求頭和對應值爲"http://www.ifeng.com/"的請求。

1.6、RequestMapping的consumes屬性:

consumes:指定處理請求的提交內容類型(Content-Type),例如 application/json,text/html 等。

@Controller
@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {    
    // implementation omitted
}

上述方法僅處理request請求中Content-Type爲"application/json"類型的請求。

1.7、RequestMapping的produces屬性:

produces: 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回。 

@Controller
@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {    
    // implementation omitted
}

上述方法僅處理request請求中Accept頭中包含了"application/json"的請求,同時暗示了返回的內容類型爲 application/json。

1.8 RequestMapping的name屬性:

此屬性基本用不到,想了解見:

你知道@RequestMapping的name屬性有什麼用嗎?【享學Spring MVC】 - YourBatman - 博客園

獲得請求參數註解

@RequestParam

@RequestParam用於將請求參數區數據映射到功能處理方法的參數上。

示例

public String requestparam1(@RequestParam(value="user_name" String username)

請求中包含username參數(如/requestparam1?user_name=zhang),則username自動設爲zhang。

@RequestParam有以下三個參數:

  • value:請求的參數名字。請求參數名和形參名不同時,要用該項來指定請求參數名。相同時可以不使用。
  • required:參數是否是必需的。默認是true(必需有);若爲true而沒有改參數則報400,BadRequest
  • defaultValue:參數默認值。請求中沒有相應名字的參數時,形參的值就爲該默認值。設置該參數時,自動將required設爲false。

 請求參數是否是必須的

public String requestparam4(@RequestParam(value="username",required=false) String username)

上邊表示請求中可以沒有名字爲username的參數,如果沒有默認爲null,此處需要注意如下幾點:原子類型:必須有值,否則拋出異常,如果允許空值請使用包裝類代替。Boolean包裝類型:默認Boolean.FALSE,其他引用類型默認爲null。

@PathVariable綁定URI模板變量值

@PathVariable用於將請求URL中的模板變量映射到功能處理方法的參數上。每個佔位符/{}/{}中的值,必須和@PathVariable的value的值相同

@RequestMapping(value="/users/{userId}/topics/{topicId}")
public String test(
       @PathVariable(value="userId") int userId, 
       @PathVariable(value="topicId") int topicId)   

        如請求的URL爲"控制器URL/users/123/topics/456",則自動將URL中模板變量{userId}和{topicId}綁定到通過@PathVariable註解的value同名參數上,即入參後userId=123、topicId=456。

@RequestBody

簡介

 @RequestBody 將HTTP請求正文轉換爲適合的HttpMessageConverter對象。@ResponseBody 將內容或對象作爲 HTTP 響應正文返回,並調用適合HttpMessageConverter的Adapter轉換對象,寫入輸出流。

@RequestBody作用:

(1)該註解用於讀取Request請求的body部分數據,使用系統默認配置的HttpMessageConverter進行解析,然後把相應的數據綁定到要返回的對象上; 
(2)再把HttpMessageConverter返回的對象數據綁定到 controller中方法的參數上。

@RequestBody使用時機:

(1)GET、POST方式提時,根據request header Content-Type的值來判斷:

application/x-www-form-urlencoded,不能處理(即使用@RequestBody不能處理這種格式的數據);
multipart/form-data,可選(@RequestParam, @ModelAttribute也可以處理,當然@RequestBody也能處理);
其他格式,必須(其他格式包括application/json, application/xml等,必須使用@RequestBody來處理);

(2)PUT方式提交時,根據request header Content-Type的值來判斷:application/x-www-form-urlencoded,必須;multipart/form-data,不能處理;其他格式,必須;

說明:request的body部分的數據編碼格式由header部分的Content-Type指定;

@CookieValue

@CookieValue註解用於將請求的cookie數據映射到功能處理方法的參數上。有value,name,required,defaultValue四個屬性

@RequestMapping(value="/testCookieValue")
public String testCookieValue(@CookieValue(value="JSESSIONID") String cookieValue){
    System.out.println("執行了...");
    System.out.println(cookieValue);
    return "success";
}

響應註解

@ResponseBody

簡介

@Responsebody表示該方法的返回結果直接寫入HTTP response body中。一般在異步獲取數據時使用,在使用@RequestMapping後,返回值通常解析爲跳轉路徑,加上@Responsebody後返回結果不會被解析爲跳轉路徑,而是直接寫入HTTP response body中。比如前端異步獲取json數據,後端加上@Responsebody後,會直接返回json數據。

@ResponseBody原理:

該註解用於將Controller的方法返回的對象,通過適當的HttpMessageConverter轉換爲指定格式後,寫入到Response對象的body數據區。

@ResponseBody使用時機:

返回的數據不是html標籤的頁面,而是其他某種格式的數據時(如json、xml等)使用;

屬性

@ModelAttribute

作用

        ModelAttribute可以應用在方法參數上或方法上,它的作用主要是當註解在方法參數上時會將註解的參數對象添加到Model中;當註解在請求處理方法Action上時會將該方法變成一個非請求處理的方法,但其它Action被調用時會首先調用該方法。

使用場景

        當@ModelAttribute註解用於方法時,與其處於同一個處理類的所有請求方法執行前都會執行一次此方法,這可能並不是我們想要的,因此,我們使用更多的是將其應用在請求方法的參數上,而它的一部分功能與@RequestParam註解是一致的,只不過@RequestParam用於綁定單個參數值,而@ModelAttribute註解可以綁定所有名稱匹配的,此外它自動將綁定後的數據添加到模型中,無形中也給我們提供了便利,這也可能是它命名爲ModelAttribute的原因。

@ModelAttribute用在參數上

        @ModelAttribute註釋方法的一個參數表示應從模型model中取得。若在model中未找到,那麼這個參數將先被實例化後加入到model中。若在model中找到,則請求參數名稱和model屬性字段若相匹配就會自動填充。這個機制對於表單提交數據綁定到對象屬性上很有效。

        當@ModelAttribute註解用於方法參數時,它有了雙重功能,即"存/取"。首先,它從模型中取出數據並賦予對應的參數,如果模型中尚不存在,則實例化一個,並存放於模型中;其次,一旦模型中已存在此數據對象,接下來一個很重要的步驟便是將請求參數綁定到此對象上(請求參數名映射對象屬性名),這是Spring MVC提供的一個非常便利的機制--數據綁定。

@RequestMapping(value = "/login.htm", method = RequestMethod.GET)
public String doLogin(@ModelAttribute("baseMember") BaseMember member) {
    member.setLoginName("loginName");
    return "home";
}

        上述代碼中,如果模型中尚不存在鍵名爲"baseMember"的數據,則首先會調用BaseMember類的默認構造器創建一個對象,如果不存在默認構造器會拋出異常。因此,給實體類提供一個默認構造器是一個好的編程習慣。當請求路徑的請求參數或提交的表單與BaseMember的屬性名匹配時,將自動將其值綁定到baseMember對象中,非常的便利!這可能是我們使用@ModelAttribute最主要的原因之一。

        比如:請求路徑爲http://localhost:8080/spring-web/login.htm?loginName=myLoginName,baseMember對象中的loginName屬性的值將被設置爲myLoginName。

@ModelAttribute用在方法上

        被@ModelAttribute註釋的方法表示這個方法的目的是增加一個或多個模型(model)屬性。這個方法和被@RequestMapping註釋的方法一樣也支持@RequestParam參數,但是它不能直接被請求映射。實際上,控制器中的@ModelAttribute方法是在同一控制器中的@RequestMapping方法被調用之前調用的。

        被@ModelAttribute註釋的方法用於填充model屬性,例如,爲下拉菜單填充內容,或檢索一個command對象(如,Account),用它來表示一個HTML表單中的數據。一個控制器可以有任意數量的@ModelAttribute方法。所有這些方法都在@RequestMapping方法被調用之前調用。

        有兩種類型的@ModelAttribute方法。一種是:只加入一個屬性,用方法的返回類型隱含表示。另一種是:方法接受一個Model類型的參數,這個model可以加入任意多個model屬性。

(1)@ModelAttribute註釋void返回值的方法

@Controller
@RequestMapping(value="/test")
public class TestController {
    
    /**
     * 1.@ModelAttribute註釋void返回值的方法
      * @param abc
     * @param model
     */
    @ModelAttribute
    public void populateModel(@RequestParam String abc, Model model) {
        model.addAttribute("attributeName", abc);
    }
    
    @RequestMapping(value = "/helloWorld")
    public String helloWorld() {
       return "test/helloWorld";
    }
}

        這個例子,在獲得請求/helloWorld 後,populateModel方法在helloWorld方法之前先被調用,它把請求參數(/helloWorld?abc=text)加入到一個名爲attributeName的model屬性中,在它執行後helloWorld被調用,返回視圖名helloWorld和model已由@ModelAttribute方法生產好了。這個例子中model屬性名稱和model屬性對象由model.addAttribute()實現,不過前提是要在方法中加入一個Model類型的參數。

(2)@ModelAttribute註釋返回具體類的方法

/**
 * 2.@ModelAttribute註釋返回具體類的方法
 * @param id
 * @return
 */
@ModelAttribute
public User getUserInfo(String id){
    if(id!=null && !id.equals("")){
        return userService.getUserInfo(id);
    }
    return null;
}

        這種情況,model屬性的名稱沒有指定,它由返回類型隱含表示,如這個方法返回User類型,那麼這個model屬性的名稱是user。這個例子中model屬性名稱有返回對象類型隱含表示,model屬性對象就是方法的返回值。它無須要特定的參數。

(3)@ModelAttribute(value="")註釋返回具體類的方法

@Controller
@RequestMapping(value="/test")
public class TestController {
    
    /**
     * 3.@ModelAttribute(value="")註釋返回具體類的方法
      * @param abc
     * @return
     */
    @ModelAttribute("str")
    public String getParam(@RequestParam String param) {
        return param;
    }
    
    @RequestMapping(value = "/helloWorld")
    public String helloWorld() {
       return "test/helloWorld";
    }
}

這個例子中使用@ModelAttribute註釋的value屬性,來指定model屬性的名稱。model屬性對象就是方法的返回值。它無須要特定的參數。完整的代碼:

package demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import demo.model.User;
import demo.service.IUserService;

@Controller
@RequestMapping(value="/test")
public class TestController {
    
    @Autowired
    private IUserService userService;
    
    /**
     * 1.@ModelAttribute註釋void返回值的方法
      * @param abc
     * @param model
     */
    @ModelAttribute
    public void populateModel(@RequestParam String abc, Model model) {
        model.addAttribute("attributeName", abc);
    }
    
    /**
     * 2.@ModelAttribute註釋返回具體類的方法
      * @param id
     * @return
     */
    @ModelAttribute
    public User getUserInfo(String id){
        if(id!=null && !id.equals("")){
            return userService.getUserInfo(id);
        }
        return null;
    }
    
    /**
     * 3.@ModelAttribute(value="")註釋返回具體類的方法
      * @param abc
     * @return
     */
    @ModelAttribute("str")
    public String getParam(@RequestParam String param) {
        return param;
    }
    
    @RequestMapping(value = "/helloWorld")
    public String helloWorld() {
       return "test/helloWorld";
    }
}

Jsp前臺取值:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head> 
    <title>helloWorld</title>
  </head>
  
  <body>
       1.The attributeValue is:  ${attributeName}
       <br/><br/>
       
       2.用戶信息:<br/>
       姓名:${user.user_name}<br/>
       年齡:${user.user_age}<br/>
       郵箱:${user.user_email}<br/><br/>
      
      3.The param is:  ${str}
  </body>
</html>

頁面效果圖:

URL格式:http://localhost/SSMDemo/test/helloWorld?abc=text&id=1&param=aaa 

注:當url或者post中不包含參數abc和參數param時,會報錯。

(4)@ModelAttribute和@RequestMapping同時註釋一個方法

@Controller
@RequestMapping(value="/test")
public class TestController {

    @RequestMapping(value = "/helloWorld")
    @ModelAttribute("attributeName")
    public String helloWorld() {
       return "hi";
    }
}

        這時這個方法的返回值並不是表示一個視圖名稱,而是model屬性的值,視圖名稱由RequestToViewNameTranslator根據請求"/helloWorld"轉換爲helloWorld。Model屬性名稱由@ModelAttribute(value="")指定,相當於在request中封裝了key=attributeName,value=hi。
Jsp頁面:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head> 
    <title>helloWorld</title>
  </head>
  
  <body>
      The attributeValue is:  ${attributeName}
  </body>
</html>

@SessionAttributes

簡介

        在默認情況下,ModelMap中的屬性作用域是request級別,也就是說,當本次請求結束後,ModelMap 中的屬性將銷燬。如果希望在多個請求中共享ModelMap中的屬性,必須將其屬性轉存到session 中,這樣 ModelMap 的屬性纔可以被跨請求訪問。Spring 允許我們有選擇地指定 ModelMap 中的哪些屬性需要轉存到 session 中,以便下一個請求屬對應的 ModelMap 的屬性列表中還能訪問到這些屬性。這一功能是通過類定義處標註 @SessionAttributes 註解來實現的。

Controller

@Controller
@RequestMapping("/anno")
@SessionAttributes(value={"msg"})   // 把Mapmodel中名字爲msg的屬性存入到session屬性列表中
public class AnnoController {
@RequestMapping(value="/testSessionAttributes")
    public String testSessionAttributes(Model model){
        System.out.println("testSessionAttributes...");
        // 底層會存儲到request域對象中
        model.addAttribute("msg","testSessionAttributes");
        return "success";
    }

	@RequestMapping(value="/getSessionAttributes")
	public String getSessionAttributes(ModelMap modelMap){
	    System.out.println("getSessionAttributes...");
	    String msg = (String) modelMap.get("msg");
	    System.out.println(msg);
	    return "success";
	}

	@RequestMapping(value="/delSessionAttributes")
	public String delSessionAttributes(SessionStatus status){
	    status.setComplete();//刪除session域中的存入的數據
	    return "success";
	}
}

success.html

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>入門成功</h3>
    ${ msg }
    ${sessionScope}
</body>
</html>

測試1

訪問:http://localhost:8080/anno/testSessionAttributes/

前端

測試2

訪問:http://localhost:8080/anno/getSessionAttributes/

後端打印

getSessionAttributes...
testSessionAttributes

 測試3

訪問:http://localhost:8080/anno/getSessionAttributes/

測試4

再次訪問:http://localhost:8080/anno/getSessionAttributes/

後端打印

getSessionAttributes...
null

前端

參數驗證

其他網址

Springboot @Validated和@Valid的區別 及使用_大菠蘿一號-CSDN博客_@valid

簡介

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

@Valid

簡介

@Valid @Validated
簡介 Hibernate-validator實現了java的JSR303聲明瞭@Valid這類接口。(此處的Hibernate 不是 Hibernate ORM) 對@Valid進行了二次封裝
所屬依賴/包

依賴:org.hibernate.validator.hibernate-validator

包名:

javax.validation.Valid

javax.validation.constraints.NotBlank...

依賴:org.springframework.spring-context

包名:

org.springframework.validation.annotation.Validated

沒有NotBlank、NotNull等註解。也需要引入org.hibernate.validator.hibernate-validator

使用位置

方法、參數、構造函數、成員屬性(field)。

不能用於類。

類、方法、參數。

不能用於構造函數與成員屬性(field)。

功能

可用於嵌套驗證。

沒有分組功能。

不能用於嵌套驗證。

有分組功能。

所需依賴(有的地方說,springboot已經有@Valid,但我發現並沒有):

        <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.1.2.Final</version>
        </dependency>

字段註解(所屬包:javax.validation.constraints.*)

字段註解

說明

@AssertFalse

限制必須爲false

@AssertTrue

限制必須爲true

@DecimalMax(value)

限制必須爲一個不大於指定值的數字

@DecimalMin(value)

限制必須爲一個不小於指定值的數字

@Digits(integer,fraction)

限制必須爲一個小數,且整數部分的位數不能超過integer,

小數部分的位數不能超過fraction

@Email

驗證註解的元素值是Email,也可以通過正則表達式和flag指定自定義的email格式

@Future

限制必須是一個將來的日期

@Max(value)

限制必須爲一個不大於指定值的數字

@Min(value)

限制必須爲一個不小於指定值的數字

@Past

限制必須是一個過去的日期

@Pattern(value)

限制必須符合指定的正則表達式

@NotEmpty

驗證註解的元素值不爲null或者空(isEmpty()方法)。

可用於字符串,Collection,Map,數組

@NotBlank

驗證註解的元素值不爲null且包含除了空格之外至少一個字符。

只用於字符串

@Null

限制只能爲null

@NotNull

限制必須不爲null

@Past

驗證註解的元素值(日期類型)比當前時間早

@Size(max,min)

限制字符長度必須在min到max之間

@Validated

簡介

spring-boot-starter-web中已有rg.springframework.validation.annotation.Validated。但沒有NotBlank、NotNull等註解。也需要引入org.hibernate.validator.hibernate-validator。

自定義校驗器

public class User {
    private String id;
 
    @MyConstraint(message = "這是一個測試")
    private String username;
}

 註解的具體內容:

@Constraint(validatedBy = {MyConstraintValidator.class})
@Target({ELementtype.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyConstraint {
    String message();
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {}; 
}

 校驗器:

public class MyConstraintValidator implements ConstraintValidator<MyConstraint, Object> {
    @Autowired
    private UserService userService;
    
    @Override
    public void initialie(@MyConstraint constarintAnnotation) {
        System.out.println("my validator init");
    }
    
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        userService.getUserByUsername("seina");
        System.out.println("valid");
        return false;
    }
}

對List的驗證

其他網址

@Validated和@Valid校驗參數、級聯屬性、List_慕課手記

@Valid與@Validated只能校驗JavaBean,而List不是JavaBean所以校驗會失敗,介紹三種解決辦法。

方法1:對List進行Wrapper

既然List不是JavaBean,那我們就把它封裝成JavaBean,我們定義一個ListWrapper類如下:

import lombok.Getter;
import lombok.Setter;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;

@Setter
@Getter
public class ListWrapper {
	@Valid
	private List list;

	public ListWrapper() {
	    list = new ArrayList<>();
	}

	public  ListWrapper(List<E> list) {
	    this.list = list;
	}
}

 Controller

// 使用包裝類對list進行驗證
@PostMapping("/insert/all")
public ServerResponse<String> insertList(@Valid @RequestBody ListWrapper<UserEntity> listWrapper, 
                                         BindingResult bindingResult) {
    if(bindingResult.hasErrors()) {
        log.error(bindingResult.getFieldError().toString());
        return ServerResponse.createByErrorMessage(bindingResult.getFieldError().getDefaultMessage());
    }

    userService.insertList(listWrapper.getList());
    return ServerResponse.createBySuccess();
}

由於對list進行了包裝,如果我們傳參的時候[{},{}…]要改爲{“list”: [{},{}…]}。

方法2:使用@Validated+@Valid

在controller類上面增加@Validated註解,並且刪除方法參數中的BindingResult bindingResult(因爲這個參數已經沒有用了,異常統一有controller返回了)

可以看到可以對參數進行校驗了,但還還有一個問題,那就是這個不是我們想要的返回格式,它controller自己返回的格式,所以我們需要做一個統一異常處理,代碼如下:
 

import com.wyq.firstdemo.common.ServerResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

@Slf4j
@RestControllerAdvice
public class ControllerExceptionHandler {
	@ExceptionHandler
	@ResponseBody
	public ServerResponse<String> handle(ConstraintViolationException exception) {
	    log.error(String.valueOf(exception));
	    Set<ConstraintViolation<?>> violations = exception.getConstraintViolations();
	    StringBuilder builder = new StringBuilder();
	    for (ConstraintViolation violation : violations) {
	        builder.append(violation.getMessage());
	        break;
	    }
	    return ServerResponse.createByErrorMessage(builder.toString());
	}
}

經過統一異常處理,我們這邊的返回結果就是我們想要的格式了

方法3:自定義一個List

先上代碼後說明,先定義一個ValidList 

import javax.validation.Valid;
import java.util.*;

public class ValidList implements List {

	@Valid
	private List<E> list;

	public ValidList() {
	    this.list = new ArrayList<>();
	}

	public ValidList(List<E> list) {
	    this.list = list;
	}

	public List<E> getList() {
	    return list;
	}

	public void setList(List<E> list) {
	    this.list = list;
	}

	@Override
	public int size() {
	    return list.size();
	}

	@Override
	public boolean isEmpty() {
	    return list.isEmpty();
	}

	//覆寫list的所有方法(全都直接調用list的方法,例如上邊的list.isEmpty)
	...
}

        對比方法3和方法1,有沒有覺得代碼有點相似,新建一個類,並且讓他實現List接口,使這個類即具有了JavaBean的特性,又具有了List的特性,比方法1簡單優雅很多。

只需要把List換成ValidList就可以了,還不需要多統一異常處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章