一败徊、環(huán)境
- jdk1.8
- idea2018.2.2
- maven3.5.3
- mybatsi-plus3.4.1
- mysql5.7
二、項目配置
- pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yxl</groupId>
<artifactId>yxl</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<modules>
<module>yxl_project01</module>
</modules>
<name>yxl</name>
<description>公共項目</description>
<properties>
<druid-version>1.2.6</druid-version>
<mybatis-plus-version>3.4.1</mybatis-plus-version>
<mysql-connector-version>8.0.23</mysql-connector-version>
<lombok-version>1.18.18</lombok-version>
<hutool-version>5.6.5</hutool-version>
<httpcore-version>4.4.12</httpcore-version>
<validation-version>2.0.1.Final</validation-version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.6</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid-version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>${httpcore-version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
注:
spirngboot升級到2.3之后李皇,hibernate-validator消失吓著,需要自己手動加入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
或者是自己手動引入依賴
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
- 統(tǒng)一返回結(jié)果
package com.yxl.common.util;
import org.apache.http.HttpStatus;
import java.util.HashMap;
import java.util.Map;
/**
* @Classname R
* @Description TODO
* @Date 2021-12-20 17:19
* @Created by yxl
*/
public class R extends HashMap<String,Object> {
private static final long serialVersionUID = 1L;
public R(){
put("code",0);
put("msg","success");
}
public static R error() {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知異常习贫,請聯(lián)系管理員");
}
public static R error(String msg) {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
}
- controller
package com.yxl.project01.controller;
import com.yxl.common.util.R;
import com.yxl.project01.entity.User;
import com.yxl.project01.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @Classname UserController
* @Description TODO
* @Date 2021-12-20 17:14
* @Created by yxl
*/
@RestController
@RequestMapping("/user")
public class UserController {
}
- dao
package com.yxl.project01.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yxl.project01.entity.User;
import org.apache.ibatis.annotations.Mapper;
/**
* @Classname UserMapper
* @Description TODO
* @Date 2021-12-20 17:10
* @Created by yxl
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
- entity
package com.yxl.project01.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* @Classname User
* @Description TODO
* @Date 2021-12-20 17:07
* @Created by yxl
*/
@Data
@TableName("tb_user")
public class User {
@TableId
private Long id;
private String name;
private Integer age;
private Date birthday;
private String icon;
private Integer status;
private String description;
}
- service
package com.yxl.project01.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yxl.project01.entity.User;
/**
* @Classname UserService
* @Description TODO
* @Date 2021-12-20 17:11
* @Created by yxl
*/
public interface UserService extends IService<User> {
}
- serviceImpl
package com.yxl.project01.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yxl.project01.dao.UserMapper;
import com.yxl.project01.entity.User;
import com.yxl.project01.service.UserService;
import org.springframework.stereotype.Service;
/**
* @Classname UserServiceImpl
* @Description TODO
* @Date 2021-12-20 17:12
* @Created by yxl
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
- 啟動類
package com.yxl.project01;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Classname yxlProject01Application
* @Description TODO
* @Date 2021-12-20 17:03
* @Created by yxl
*/
@SpringBootApplication
@MapperScan("com.yxl.project01.dao")
public class yxlProject01Application {
public static void main(String[] args) {
SpringApplication.run(yxlProject01Application.class,args);
}
}
三乳愉、JSR303參數(shù)校驗配置
1兄淫、在UserController中新增save接口用來添加用戶
/**
* JSR303配置案例
*/
@PostMapping("/save")
public R save(@RequestBody User user){
userService.save(user);
return R.ok();
}
2屯远、使用Postman對接口進行測試
測試數(shù)據(jù)
{
"name": "張三",
"age": 20,
"birthday": "1995-03-02",
"icon": "http://www.baidu.com",
"status": "0",
"description": "描述"
}
測試結(jié)果如下:
從上邊圖可以看出來執(zhí)行成功了,也新增到數(shù)據(jù)庫了捕虽。
那么我們現(xiàn)在把所有新增的字段都置空慨丐,看新增的時候會怎么樣?
{
"name": "",
"age": "",
"birthday": "",
"icon": "",
"status": "",
"description": ""
}
從執(zhí)行結(jié)果中可以看出泄私,新增依舊是執(zhí)行成功的房揭,但是數(shù)據(jù)庫加入的都是空數(shù)據(jù),這樣肯定是不行的挖滤,那么我們怎么樣能限制到新增的時候給每個屬性加限制呢崩溪?就比如說名稱不能為空浅役,url必須是合法的url地址等等斩松。這時候我們就用到了JSR303參數(shù)校驗注解了。演示如下:
1觉既、在User.Class中新增校驗注解如下:
package com.yxl.project01.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* @Classname User
* @Description TODO
* @Date 2021-12-20 17:07
* @Created by yxl
*/
@Data
@TableName("tb_user")
public class User {
@TableId
private Long id;
@NotBlank(message = "用戶名不能為空")
private String name;
@NotNull(message = "年齡不能為空")
private Integer age;
@NotNull(message = "出生日期不能為空")
private Date birthday;
@NotBlank(message = "頭像不能為空")
private String icon;
private Integer status;
private String description;
}
再此對@NotBlank惧盹、@NotNull、@NotEmpty三個注解做一個解釋
@NotBlank:只用于String,不能為null且trim()之后size>0
@NotNull:用在基本數(shù)據(jù)類型上面瞪讼。不能為null钧椰,但可以為empty,沒有Size的約束
@NotEmpty:用在集合類上面。加了@NotEmpty的String類符欠、Collection嫡霞、Map、數(shù)組希柿,是不能為null或者長度為0的(String Collection Map的isEmpty()方法)
2诊沪、在Controller中使用校驗注解
/**
* JSR303配置案例
*/
@PostMapping("/save")
public R save(@Valid @RequestBody User user){
userService.save(user);
return R.ok();
}
3、重啟服務(wù)器曾撤,再次使用空數(shù)值測試結(jié)果如下:
{
"timestamp": "2021-12-22T07:19:17.464+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"NotNull.user.age",
"NotNull.age",
"NotNull.java.lang.Integer",
"NotNull"
],
"arguments": [
{
"codes": [
"user.age",
"age"
],
"arguments": null,
"defaultMessage": "age",
"code": "age"
}
],
"defaultMessage": "年齡不能為空",
"objectName": "user",
"field": "age",
"rejectedValue": null,
"bindingFailure": false,
"code": "NotNull"
},
{
"codes": [
"NotNull.user.birthday",
"NotNull.birthday",
"NotNull.java.util.Date",
"NotNull"
],
"arguments": [
{
"codes": [
"user.birthday",
"birthday"
],
"arguments": null,
"defaultMessage": "birthday",
"code": "birthday"
}
],
"defaultMessage": "出生日期不能為空",
"objectName": "user",
"field": "birthday",
"rejectedValue": null,
"bindingFailure": false,
"code": "NotNull"
},
{
"codes": [
"NotBlank.user.icon",
"NotBlank.icon",
"NotBlank.java.lang.String",
"NotBlank"
],
"arguments": [
{
"codes": [
"user.icon",
"icon"
],
"arguments": null,
"defaultMessage": "icon",
"code": "icon"
}
],
"defaultMessage": "頭像不能為空",
"objectName": "user",
"field": "icon",
"rejectedValue": "",
"bindingFailure": false,
"code": "NotBlank"
},
{
"codes": [
"NotBlank.user.name",
"NotBlank.name",
"NotBlank.java.lang.String",
"NotBlank"
],
"arguments": [
{
"codes": [
"user.name",
"name"
],
"arguments": null,
"defaultMessage": "name",
"code": "name"
}
],
"defaultMessage": "用戶名不能為空",
"objectName": "user",
"field": "name",
"rejectedValue": "",
"bindingFailure": false,
"code": "NotBlank"
}
],
"message": "Validation failed for object='user'. Error count: 4",
"path": "/user/save"
}
從結(jié)果看參數(shù)校驗注解已生效端姚。
但是回過頭來香,如果是前后端分離項目的話挤悉,返回給前端這種格式是不行的渐裸,那么我們就可以利用全局異常處理,統(tǒng)一來返回結(jié)果給前端了装悲。
4昏鹃、在全局異常處理類中增加異常處理方法專門對MethodArgumentNotValidException.Class異常類進行處理,如下:
package com.yxl.project01.exception;
import com.yxl.common.exception.BizCodeEnume;
import com.yxl.common.util.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
/**
* @Classname GlobalExceptionHandler
* @Description TODO
* @Date 2021-12-22 11:13
* @Created by yxl
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
public R arithmeticExceptionHandler(ArithmeticException e){
return R.error(BizCodeEnume.ARITHMETIC_EXCEPTION.getCode(),BizCodeEnume.ARITHMETIC_EXCEPTION.getMsg());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public R methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e){
log.error("數(shù)據(jù)校驗出現(xiàn)問題{}诀诊,異常類型:{}",e.getMessage().getClass());
BindingResult result = e.getBindingResult();
Map<String,String> map = new HashMap<>();
result.getFieldErrors().forEach(fieldError -> {
map.put(fieldError.getField(),fieldError.getDefaultMessage());
});
return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",map);
}
}
其中BizCodeEnume枚舉類如下:
package com.yxl.common.exception;
/**
* @Classname BizCodeEnume
* @Description TODO
* @Date 2021-12-22 11:29
* @Created by yxl
*/
public enum BizCodeEnume {
UNKNOW_EXCEPTION(10000,"系統(tǒng)未知異常"),
VAILD_EXCEPTION(10001,"參數(shù)格式校驗失敗"),
ARITHMETIC_EXCEPTION(10001,"算術(shù)異常"),;
private int code;
private String msg;
private BizCodeEnume(int code, String msg){
this.code = code;
this.msg = msg;
}
public int getCode(){
return code;
}
public String getMsg(){
return msg;
}
}
新增全局異常處理后我們再測試一下盆顾,結(jié)果如下:
{
"msg": "參數(shù)格式校驗失敗",
"code": 10001,
"data": {
"birthday": "出生日期不能為空",
"icon": "頭像不能為空",
"name": "用戶名不能為空",
"age": "年齡不能為空"
}
}
這就達到了我們想要的結(jié)果。
三畏梆、參數(shù)校驗分組功能
參數(shù)校驗分組功能主要是針對哪些方法使用哪些參數(shù)校驗的您宪,比如:新增用戶前端不需要傳id等字段奈懒,修改的時候前端必須傳id,新增和修改都必須要傳name等宪巨。這種場景的話磷杏,我們就需要用到分組功能了。
1捏卓、我們在UserController.class中新增修改接口极祸,如下:
/**
* 參數(shù)校驗分組功能
*/
@PostMapping("/update")
public R update(@RequestBody User user){
userService.updateById(user);
return R.ok();
}
2、配置User實體類
package com.yxl.project01.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yxl.common.valid.SaveGroup;
import com.yxl.common.valid.UpdateGroup;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import java.util.Date;
/**
* @Classname User
* @Description TODO
* @Date 2021-12-20 17:07
* @Created by yxl
*/
@Data
@TableName("tb_user")
public class User {
@TableId
@NotNull(message = "修改需要傳遞id",groups = {UpdateGroup.class})
@Null(message = "新增不需要傳遞id",groups = {SaveGroup.class})
private Long id;
@NotBlank(message = "用戶名不能為空",groups = {SaveGroup.class,UpdateGroup.class})
private String name;
@NotNull(message = "年齡不能為空")
private Integer age;
@NotNull(message = "出生日期不能為空")
private Date birthday;
@NotBlank(message = "頭像不能為空")
private String icon;
private Integer status;
private String description;
}
其中SaveGroup.class和UpdateGroup.class為groups分組需要傳遞的標(biāo)識符怠晴,即一個空的接口遥金。如下:
package com.yxl.common.valid;
/**
* @Classname SaveGroup
* @Description TODO
* @Date 2021-12-22 15:42
* @Created by yxl
*/
public interface SaveGroup {
}
package com.yxl.common.valid;
/**
* @Classname UpdateGroup
* @Description TODO
* @Date 2021-12-22 15:42
* @Created by yxl
*/
public interface UpdateGroup {
}
3、在UserController中save接口和update接口增加注解
/**
* JSR303配置案例
*/
@PostMapping("/save")
public R save(@Validated({SaveGroup.class}) @RequestBody User user){
userService.save(user);
return R.ok();
}
/**
* 參數(shù)校驗分組功能
*/
@PostMapping("/update")
public R update(@Validated({UpdateGroup.class}) @RequestBody User user){
userService.updateById(user);
return R.ok();
}
4蒜田、執(zhí)行修改接口稿械,提示修改需要傳遞id。如下:
我們傳一個id進去冲粤,修改一條數(shù)據(jù)試試:
數(shù)據(jù)庫數(shù)據(jù)已更改
5美莫、執(zhí)行新增接口,提示新增不需要傳id梯捕。如下:
我們把Id去掉在測試
數(shù)據(jù)庫已新增成功