天天看点

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

一、逆向生成前端代码

1.创建品牌管理菜单

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

2.前端逆向代码

将逆向生成的前端代码拷贝到category目录下

3.关闭语法检查

You may use special comments to disable some warnings.
Use // eslint-disable-next-line to ignore the next line.
Use /* eslint-disable */ to ignore all warnings in a file.
           

前端控制台会一直报错,是由于语法检查过于严格,可以关闭语法检查

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

二、调整状态显示按钮

1.使用自定义列模板

通过

Scoped slot

可以获取到 row, column, $index 和 store(table 内部的状态管理)的数据

<el-table-column prop="showStatus" header-align="center" align="center" label="显示状态">
        <template slot-scope="scope">
          <el-switch
            v-model="scope.row.showstatus"
            active-color="#13ce66"
            inactive-color="#ff4949"
            :active-value="1"
            :inactive-value="0"
            @change="updateBrandStatus"
          ></el-switch>
        </template>
      </el-table-column>
           

2.修改权限

暂时将权限改成所有可用

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

3.updateBrandStatus方法编写

@change=“updateBrandStatus(scope.row)”

//更新品牌状态
    updateBrandStatus(data) {
      console.log("数据", data);
      let { brandId, showStatus } = data;
      this.$http({
        url: this.$http.adornUrl("/product/brand/update/status"),
        method: "post",
        data: this.$http.adornData({ brandId, showStatus }, false)
      }).then(({ data }) => {
        //消息提示删除成功
        this.$message({
          message: "修改状态成功!",
          type: "success"
        });
      });
    },
           

三、对象存储OSS文件上传

对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。

1.开通OSS

https://www.aliyun.com/

2.创建Bucket

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]
[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

3.文件上传

1.创建子账户

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

2.添加OSS权限

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

3.简单上传

导入依赖

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.10.2</version>
</dependency>
           
@Test
public void upload() throws FileNotFoundException {
    // Endpoint以北京为例,其它Region请按实际情况填写。在bucket的概览里
    String endpoint = "oss-cn-beijing.aliyuncs.com";
    // 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建。
    String accessKeyId = "<yourAccessKeyId>";
    String accessKeySecret = "<yourAccessKeySecret>";

    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

    // 上传文件流。
    InputStream inputStream = new FileInputStream("<yourlocalFile>");
    ossClient.putObject("<yourBucketName>", "<yourObjectName>", inputStream);

    // 关闭OSSClient。
    ossClient.shutdown();

    //上传成功
    System.out.println("上传成功");

}
           

4.使用starter直传

修改Pom

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
</dependency>

           

Yml配置账号密码

代码:

@AutoWired
    private OSS ossClient;

@Test
public void upload() throws FileNotFoundException {
   
    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

    // 上传文件流。
    InputStream inputStream = new FileInputStream("<yourlocalFile>");
    ossClient.putObject("<yourBucketName>", "<yourObjectName>", inputStream);

    // 关闭OSSClient。
    ossClient.shutdown();

    //上传成功
    System.out.println("上传成功");

}
           

5.服务端签名后直传

将oss文件存储服务放入一个第三方maven模块中

配置bootstrap

spring:
  application:
    name: gulimall-third-party
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        namespace: df45e354-ebe2-4109-bd34-0a18ba549d43
        ext-config:
          - dataId: oss.yml
            group: DEFAULT_GROUP
            refresh: true
           

配置远程config oss.yml

spring:
  config:
    name: gulimall-third-party
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    alicloud:
      access-key: xxxxxxxxxxxxxxxxxxxx
      secret-key: xxxxxxxxxxxxxxxxxxxxxx
      oss:
        endpoint: oss-cn-beijing.aliyuncs.com
        bucket: gulimall-xiaoxiao
server:
  port: 30000
           

配置Controller

@RestController
@RequestMapping("thirdparty/oss")
public class OssController {

    @Autowired
    private OSS ossClient;
    @Value("${spring.cloud.alicloud.access-key}")
    private String accessId;
    @Value("${spring.cloud.alicloud.secret-key}")
    private String accessKey;
    @Value("${spring.cloud.alicloud.oss.endpoint}")
    private String endpoint;
    @Value("${spring.cloud.alicloud.oss.bucket}")
    private String bucket;



    @RequestMapping("/policy")
    public R policy() {
        String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
        // callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
//        String callbackUrl = "http://88.88.88.88:8888";
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = format+"/"; // 用户上传文件时指定的前缀。

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
        Map<String, String> respMap = new LinkedHashMap<String, String>();
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            // PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);


            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            // respMap.put("expire", formatISO8601Date(expiration));


        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        } finally {
            ossClient.shutdown();
        }
        return R.ok().put("data",respMap);
    }
}
           

网关断言

gateway:
  routes:
    - id: thirdparty_route
      uri: lb://gulimall-third-party
      predicates:
        - Path=/api/thirdparty/**
      filters:
        - RewritePath=/api/(?<segment>.*), /$\{segment}
           

6.前端组件配置

获取外网访问oss域名

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

/components下新建一个组件upload

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

multiUpload.vue

<template>
  <div>
    <el-upload
      action="http://gulimall-hello.oss-cn-beijing.aliyuncs.com"//改成你的外网访问域名
      :data="dataObj"
      :list-type="listType"
      :file-list="fileList"
      :before-upload="beforeUpload"
      :on-remove="handleRemove"
      :on-success="handleUploadSuccess"
      :on-preview="handlePreview"
      :limit="maxCount"
      :on-exceed="handleExceed"
      :show-file-list="showFile"
    >
      <i class="el-icon-plus"></i>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="dialogImageUrl" alt />
    </el-dialog>
  </div>
</template>
<script>
import { policy } from "./policy";
import { getUUID } from '@/utils'
export default {
  name: "multiUpload",
  props: {
    //图片属性数组
    value: Array,
    //最大上传图片数量
    maxCount: {
      type: Number,
      default: 30
    },
    listType:{
      type: String,
      default: "picture-card"
    },
    showFile:{
      type: Boolean,
      default: true
    }

  },
  data() {
    return {
      dataObj: {
        policy: "",
        signature: "",
        key: "",
        ossaccessKeyId: "",
        dir: "",
        host: "",
        uuid: ""
      },
      dialogVisible: false,
      dialogImageUrl: null
    };
  },
  computed: {
    fileList() {
      let fileList = [];
      for (let i = 0; i < this.value.length; i++) {
        fileList.push({ url: this.value[i] });
      }

      return fileList;
    }
  },
  mounted() {},
  methods: {
    emitInput(fileList) {
      let value = [];
      for (let i = 0; i < fileList.length; i++) {
        value.push(fileList[i].url);
      }
      this.$emit("input", value);
    },
    handleRemove(file, fileList) {
      this.emitInput(fileList);
    },
    handlePreview(file) {
      this.dialogVisible = true;
      this.dialogImageUrl = file.url;
    },
    beforeUpload(file) {
      let _self = this;
      return new Promise((resolve, reject) => {
        policy()
          .then(response => {
            console.log("这是什么${filename}");
            _self.dataObj.policy = response.data.policy;
            _self.dataObj.signature = response.data.signature;
            _self.dataObj.ossaccessKeyId = response.data.accessid;
            _self.dataObj.key = response.data.dir +getUUID()+"_${filename}";
            _self.dataObj.dir = response.data.dir;
            _self.dataObj.host = response.data.host;
            resolve(true);
          })
          .catch(err => {
            console.log("出错了...",err)
            reject(false);
          });
      });
    },
    handleUploadSuccess(res, file) {
      this.fileList.push({
        name: file.name,
        // url: this.dataObj.host + "/" + this.dataObj.dir + "/" + file.name; 替换${filename}为真正的文件名
        url: this.dataObj.host + "/" + this.dataObj.key.replace("${filename}",file.name)
      });
      this.emitInput(this.fileList);
    },
    handleExceed(files, fileList) {
      this.$message({
        message: "最多只能上传" + this.maxCount + "张图片",
        type: "warning",
        duration: 1000
      });
    }
  }
};
</script>
<style>
</style>



           

policy.js

import http from '@/utils/httpRequest.js'
export function policy() {
   return  new Promise((resolve,reject)=>{
        http({
            url: http.adornUrl("/thirdparty/oss/policy"),
            method: "get",
            params: http.adornParams({})
        }).then(({ data }) => {
            resolve(data);
        })
    });
}
           

singleUpload.vue

<template> 
  <div>
    <el-upload
      action="http://gulimall-hello.oss-cn-beijing.aliyuncs.com"
      :data="dataObj"
      list-type="picture"
      :multiple="false" :show-file-list="showFileList"
      :file-list="fileList"
      :before-upload="beforeUpload"
      :on-remove="handleRemove"
      :on-success="handleUploadSuccess"
      :on-preview="handlePreview">
      <el-button size="small" type="primary">点击上传</el-button>
      <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过10MB</div>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="fileList[0].url" alt="">
    </el-dialog>
  </div>
</template>
<script>
   import {policy} from './policy'
   import { getUUID } from '@/utils'

  export default {
    name: 'singleUpload',
    props: {
      value: String
    },
    computed: {
      imageUrl() {
        return this.value;
      },
      imageName() {
        if (this.value != null && this.value !== '') {
          return this.value.substr(this.value.lastIndexOf("/") + 1);
        } else {
          return null;
        }
      },
      fileList() {
        return [{
          name: this.imageName,
          url: this.imageUrl
        }]
      },
      showFileList: {
        get: function () {
          return this.value !== null && this.value !== ''&& this.value!==undefined;
        },
        set: function (newValue) {
        }
      }
    },
    data() {
      return {
        dataObj: {
          policy: '',
          signature: '',
          key: '',
          ossaccessKeyId: '',
          dir: '',
          host: '',
          // callback:'',
        },
        dialogVisible: false
      };
    },
    methods: {
      emitInput(val) {
        this.$emit('input', val)
      },
      handleRemove(file, fileList) {
        this.emitInput('');
      },
      handlePreview(file) {
        this.dialogVisible = true;
      },
      beforeUpload(file) {
        let _self = this;
        return new Promise((resolve, reject) => {
          policy().then(response => {
            console.log("响应的数据",response);
            _self.dataObj.policy = response.data.policy;
            _self.dataObj.signature = response.data.signature;
            _self.dataObj.ossaccessKeyId = response.data.accessid;
            _self.dataObj.key = response.data.dir +getUUID()+'_${filename}';
            _self.dataObj.dir = response.data.dir;
            _self.dataObj.host = response.data.host;
            console.log("响应的数据222。。。",_self.dataObj);
            resolve(true)
          }).catch(err => {
            reject(false)
          })
        })
      },
      handleUploadSuccess(res, file) {
        console.log("上传成功...")
        this.showFileList = true;
        this.fileList.pop();
        this.fileList.push({name: file.name, url: this.dataObj.host + '/' + this.dataObj.key.replace("${filename}",file.name) });
        this.emitInput(this.fileList[0].url);
      }
    }
  }
</script>
<style>

</style>



           

7.前端引入文件上传

1.导入singleUpload

<script>
import SingleUpload from "@/components/upload/singleUpload";
export default {
  components:{SingleUpload},
           

2.修改标签体

<el-form-item label="品牌logo地址" prop="logo">
        <!-- <el-input v-model="dataForm.logo" placeholder="品牌logo地址"></el-input> -->
        <single-upload v-model="dataForm.logo"></single-upload>
      </el-form-item>
           

8.开启跨域允许

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

9.自定义显示为图片

<el-table-column prop="logo" header-align="center" align="center" label="品牌logo地址">
        <template slot-scope="scope">
          <el-image style="width: 100px; height: 80px" :src="scope.row.logo" fit="fill"></el-image>
        </template>
      </el-table-column>
           

四、表单校验

1.前端自定义校验

firstLetter: [
          {
            validator: (rule, value, callback) => {
              if (value == "") {
                callback(new Error("首字母不能为空"));
              } else if (!/^[a-zA-Z]$/.test(value)) {
                callback(new Error("必须输入a-z或者A-Z的一个字母作为首字母"));
              } else {
                callback();
              }
            }
          }
        ],
        sort: [
          {
            validator: (rule, value, callback) => {
              if (value == "") {
                callback(new Error("排序不能为空"));
              } else if (!Number.isInteger(value) || value < 0) {
                callback(new Error("必须输入一个大于等于0的数字"));
              } else {
                callback();
              }
            }
          }
        ]
      }
    };
  }
           

2.后端JSR303校验

1.给Entity添加注解

给属性添加校验注解,并附上自己的message提示

@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 品牌id
	 */
	@TableId
	private Long brandId;
	/**
	 * 品牌名
	 */
	@NotBlank(message = "品牌名不能为空")
	private String name;
	/**
	 * 品牌logo地址
	 */
	@NotEmpty
	private String logo;
	/**
	 * 介绍
	 */
	@NotEmpty
	private String descript;
	/**
	 * 显示状态[0-不显示;1-显示]
	 */
	@NotNull
	private Integer showStatus;
	/**
	 * 检索首字母
	 */
	@NotEmpty
	@Pattern(regexp = "^[a-zA-Z]$",message = "首字母必须为a-zA-Z的一个字母")
	private String firstLetter;
	/**
	 * 排序
	 */
	@NotNull
	@Min(value = 0,message = "排序数字必须大于等于0")
	private Integer sort;

}
           

2.在接收的Requestbody添加@Valid注解

/**
     * 保存
     */
    @RequestMapping("/save")
    public R save(@Valid @RequestBody BrandEntity brand){
				brandService.save(brand);
        return R.ok();
    }
           

3.添加BindingResult

/**
     * 保存
     */
    @RequestMapping("/save")
    //@RequiresPermissions("product:brand:save")
    public R save(@Valid @RequestBody BrandEntity brand, BindingResult result) {
        if (result.hasErrors()) {
            Map<String, String> map = new HashMap<>();//保存错误信息
            result.getFieldErrors().forEach((error) -> {
                String field = error.getField();
                String eMessage = error.getDefaultMessage();
                map.put(field, eMessage);
            });
            return R.ok().put("error", map);
        } else {
            brandService.save(brand);
            return R.ok();
        }
    }
           
[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

4.校验异常统一处理

所有后台请求只做正确处理,异常直接抛出

@Slf4j
@RestControllerAdvice(basePackages = "com.xiaoxiao.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R handlerValidException(MethodArgumentNotValidException e) {
        log.error("错误异常"+e.getMessage().getClass());
        return R.error(400,"数据校验异常");
    }
    @ExceptionHandler(value = Throwable.class)
    public R handlerException(Throwable t) {
        return R.error(400,"系统未知异常");
    }
}
           

使用枚举列出常用异常

/*错误码和错误信息定义类
    *1.错误码定义规则为5为数字
    *2.前两位表示业务场景,最后三位表示错误码。例如: 10001. 10:通用001:系统未知异常
    *3.维护错误码后需要维护错误描述,将他们定义为枚举形式
    * 错误码列表:*10:通用
        001:参数格式校验
        11:商品
        12:订单
        13:购物车
        14:物流
    */
public enum BizCodeEnum {
    UNKNOWN_EXCEPTION(10000,"系统未知异常"),
    VALID_EXCEPTION(10001,"参数校验出现错误,校验失败");

    private int code;
    private String message;
    BizCodeEnum(int code,String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}
           

使用枚举异常

@Slf4j
@RestControllerAdvice(basePackages = "com.xiaoxiao.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handlerValidException(MethodArgumentNotValidException e) {
        log.error("错误异常"+e.getClass());
        Map<String,String> map = new HashMap<>();
        e.getBindingResult().getFieldErrors().forEach((error)->{
            String field = error.getField();
            String defaultMessage = error.getDefaultMessage();
            map.put(field,defaultMessage);
        });
        return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(),BizCodeEnum.VALID_EXCEPTION.getMessage()).put("errors",map);
    }
    @ExceptionHandler(value = Throwable.class)
    public R handlerException(Throwable t) {
        return R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(),BizCodeEnum.UNKNOWN_EXCEPTION.getMessage());
    }
}
           

5.分组校验

如果标注了分组校验,没有指定分组,则不进行校验

package com.xiaoxiao.gulimall.product.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;

import com.xiaoxiao.common.valid.AddGroup;
import com.xiaoxiao.common.valid.UpdateGroup;
import com.xiaoxiao.common.valid.UpdateStatusGroup;
import lombok.Data;
import org.hibernate.validator.constraints.URL;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import javax.validation.constraints.Pattern;

/**
 * 品牌
 * 
 * @author xiaoxiao
 * @email [email protected]
 * @date 2020-07-07 20:13:06
 */
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
   private static final long serialVersionUID = 1L;

   /**
    * 品牌id
    */
   @TableId
	 @NotNull(message = "必须指定品牌id",groups = {UpdateGroup.class,UpdateStatusGroup.class})
   @Null(message = "新增不能指定id",groups = {AddGroup.class})
   private Long brandId;
   /**
    * 品牌名
    */
   @NotBlank(groups = {AddGroup.class, UpdateGroup.class},message = "品牌名不能为空")
   private String name;
   /**
    * 品牌logo地址
    */
   @NotEmpty(groups = {AddGroup.class})
   @URL(message = "logo地址必须是一个合法的url地址",groups={AddGroup.class,UpdateGroup.class})
   private String logo;
   /**
    * 介绍
    */
   private String descript;
   /**
    * 显示状态[0-不显示;1-显示]
    */
	 @ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class})//自定义校验器
	 @NotNull(groups = {AddGroup.class, UpdateStatusGroup.class})
   private Integer showStatus;
   /**
    * 检索首字母
    */
   @NotEmpty(groups={AddGroup.class})
   @Pattern(regexp = "^[a-zA-Z]$",message = "首字母必须为a-zA-Z的一个字母",groups={AddGroup.class,UpdateGroup.class})
   private String firstLetter;
   /**
    * 排序
    */
   @NotNull(groups={AddGroup.class})
   @Min(value = 0,message = "排序数字必须大于等于0",groups={AddGroup.class,UpdateGroup.class})
   private Integer sort;

}
           
/**
 * 保存
 */
@RequestMapping("/save")
//@RequiresPermissions("product:brand:save")
public R save(@Validated(value = {AddGroup.class}) @RequestBody BrandEntity brand/*, BindingResult result*/) {
    brandService.save(brand);
    return R.ok();
}

/**
 * 修改
 */
@RequestMapping("/update")
//@RequiresPermissions("product:brand:update")
public R update(@Validated(value = {UpdateGroup.class}) @RequestBody BrandEntity brand) {
    brandService.updateById(brand);

    return R.ok();
}

/**
 * 修改状态
 */
@RequestMapping("/update/status")
//@RequiresPermissions("product:brand:update")
public R updateStatus(@Validated(value = {UpdateStatusGroup.class}) @RequestBody BrandEntity brand) {
    brandService.updateById(brand);

    return R.ok();
}
           

6.自定义校验

1.引入依赖
<dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>2.0.1.Final</version>
    </dependency>
           
2.新建一个校验注解
package com.xiaoxiao.common.valid;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;

/**
 * @author xiaoxiao
 * @date 2020/7/17 - 14:23
 */
@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    String message() default "{com.xiaoxiao.common.valid.ListValue.message}";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

    int[] vals() default { };
}
           
3.创建ValidationMessages.properties
com.xiaoxiao.common.valid.ListValue.message=显示状态必须为0或者1
           
4.创建ListValueConstraintValidator
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    private Set<Integer> set = new HashSet<>();
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }

    /**
     * 校验方法
     * @param value
     * @param context
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {

        return set.contains(value);
    }
}
           
[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day08-day09品牌管理(阿里云对象存储OSS上传文件,前后端表单数据校验JSR303)[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]

继续阅读