集成validation做参数校验

集成spring-boot-starter-validation

在pom.xml中添加依赖,如下

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
对保存接口和查询接口增加参数校验

pagesize添加限制:

  • page不能为空
  • size不能为空,且最大不能超过1000

SpringBoot很多功能都是通过注解完成的,本例也是通过注解给pagesize添加校验规则,如下,

package com.jepcc.test.req;

import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;

public class PageReq {
    @NotNull(message="页码 不能为空")
    private int page;

    @NotNull(message="每页条数 不能为空")
    @Max(value=1000,message="每页条数 不能超过1000")
    private int size;

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    @Override
    public String toString() {
        return "PageReq{" +
                "page=" + page +
                ", size=" + size +
                '}';
    }
}

在这里插入图片描述
在这里插入图片描述

  • @NotNull
    被注释的元素不能为空,且使用message配置提示语句。
  • @Max(value)
    被注释的元素必须是一个数字,其值必须小于等于指定的值。
  • @Valid
    接口参数加入@Valid注解,启用校验规则,表示当前实体类接收的参数需要根据配置的@NotNull@Max进行判断。

添加完校验规则后,将size值设置为1001,即超过既定的最大值1000,然后调用下接口试试。
在这里插入图片描述
在这里插入图片描述
可以看到,报了BindException异常 ,接口返回400。

2021-06-18 10:55:54.184  WARN 12600 --- [nio-8088-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'ebookReq' on field 'size': rejected value [1001]; codes [Max.ebookReq.size,Max.size,Max.int,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [ebookReq.size,size]; arguments []; default message [size],1000]; default message [每页条数 不能超过1000]]
校验不通过时,前端弹出错误提示

接口参数在后台校验不通过,抛出BindException异常,那我们如何捕获这个异常并将对应的提示信息返回给前端呢?这就需要实现一个统一异常处理的类。
@ControllerAdvice+@ExceptionHandler,可以实现异常捕获和处理。
@ControllerAdvice@Component标记,所以由@ControllerAdvice注解的类可以被扫描并放入Spring容器。
@ExceptionHandler用来标记异常类型对应的处理方法。
具体代码如下,

package com.jepcc.test.controller;

import com.jepcc.test.resp.CommonResp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.*;


@ControllerAdvice
public class ControllerExceptionHandler {
    private final static Logger LOG  = LoggerFactory.getLogger(ControllerExceptionHandler.class);
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public CommonResp validExceptionHandler(BindException e){
        CommonResp commonResp = new CommonResp();
        LOG.warn("参数校验失败:{}",e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
        commonResp.setSuccess(false);
        commonResp.setMessage(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
        return commonResp;
    }
}

接着,调用接口试试。
在这里插入图片描述
注意哈,本例中的BindException,是org.springframework.validation.BindException,不是java.net.BindException
最后就是添加前端代码了。

<template>
  <a-layout>
    <a-layout-content
        :style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
    >
      <p>
        <a-button type="primary" size="large" @click="add">新增</a-button>
      </p>
      <a-table :columns="columns" 
        :dataSource="ebooks"
        :row-key="record=>record.id"
        :pagination="pagination"
        :loading="loading"
        @change="handleTableChange">
        <template #cover="{text:cover}">
          <img v-if="cover" :src="cover" alt="avatar">
        </template>
        <template #action="{text,record}">
          <a-space>
            <a-button type="primary" @click="edit(record)">编辑</a-button>
            <a-popconfirm
              title="删除后不可恢复,确认删除?"
              ok-text="确定"
              cancel-text="取消"
              @confirm="handleDelete(record)"
            >
            <a-button type="danger">删除</a-button>
            </a-popconfirm>
            
          </a-space>
        </template>
      </a-table>
    </a-layout-content>

  </a-layout>

  <a-modal
    title="电子书表单"
    v-model:visible="visible"
    :confirm-loading="confirmLoading"
    @ok="handleOk"
  >
    <a-form :model="ebook" :label-col="{span:4}" :wrapper-col="{span:16}">
      <a-form-item label="封面">
        <a-input v-model:value="ebook.cover" />
      </a-form-item>
      <a-form-item label="名称">
        <a-input v-model:value="ebook.name" />
      </a-form-item>
      <a-form-item label="分类一">
        <a-input v-model:value="ebook.category1Id" />
      </a-form-item>  
      <a-form-item label="分类二">
        <a-input v-model:value="ebook.category2Id" />
      </a-form-item>     
      <a-form-item label="描述">
        <a-input v-model:value="ebook.description" />
      </a-form-item>      
    </a-form>
  </a-modal>

</template>


<script lang="ts">

import { defineComponent,ref,onMounted} from 'vue';
import axios from "axios";
import {message} from "ant-design-vue";

export default defineComponent({
  name:"AdminEbook",
  setup() {
    const ebooks = ref();
    const pagination = ref({
      current:1,
      pageSize:4,
      total:0
    });
    const loading = ref(false);
    const columns = [
      {
        title:"封面",
        dataIndex:"cover",
        key:"cover",
        slots:{customRender:'cover'}
      },
      {
        title:"名称",
        key:"name",
        dataIndex:"name"
      },
      {
        title:"分类一",
        key:"category1Id",
        dataIndex:"category1Id"
      },
      {
        title:"分类二",
        key:"category2Id",
        dataIndex:"category2Id"
      },
      {
        title:"文档数",
        key:"docCount",
        dataIndex:"docCount"
      },
      {
        title:"阅读数",
        key:"viewCount",
        dataIndex:"viewCount"
      },
      {
        title:"点赞数",
        key:"vouteCount",
        dataIndex:"voteCount"
      },
      {
        title:"操作",
        key:"action",
        dataIndex:"action",
        slots:{customRender:'action'}

      }
    ];

    const visible = ref(false);
    const modalText = ref('test');
    const confirmLoading = ref(false);
    const ebook= ref({});

    const handleQuery = (params:any) => {
      loading.value = true;
      axios.get("/ebook/list",{params:params}).then(response => {
        loading.value = false;
        const data = response.data;
        const content = data.content;
        if(data.success){
          ebooks.value = content.list;
          pagination.value.total = content.total;
          pagination.value.current = params.page;         
        }else{
          message.warn(data.message);
        }
      })
    };

    const handleTableChange = (pagination:any) => {
      handleQuery({
        page:pagination.current,
        size:pagination.pageSize
      });
    }

    const edit = (record:any) => {
      visible.value = true;
      ebook.value = record;
    }
    const add = () => {
      visible.value = true;
      ebook.value = {};
    }
    const handleDelete = (record:any) => {
      axios.delete("ebook/delete/"+record.id).then(response => {
        const data = response.data;
        if(data.success){
          handleQuery({
            page:pagination.value.current,
            size:pagination.value.pageSize
          })
        }
      })
    }
    const handleOk = () => {
      // modalText.value = 'The modal will be closed after two seconds';
      // confirmLoading.value = true;
      axios.post("/ebook/save",ebook.value).then(response => {
        const data = response.data;
        if(data.success){
          visible.value = false;
          confirmLoading.value = false;

          handleQuery({
            page:pagination.value.current,
            size:pagination.value.pageSize
          })
        }
        
      })
      // setTimeout(() => {
      //   visible.value = false;
      //   confirmLoading.value = false;
      // }, 2000);
    };
    
    onMounted(() => {
      handleQuery({
        page:1,
        size:pagination.value.pageSize
      });
    })

    return {
      columns,
      ebooks,
      loading,
      pagination,
      handleTableChange,
      visible,
      modalText,
      confirmLoading,
      edit,
      add,
      handleDelete,
      handleOk,
      ebook
    }
  }
})
</script>


<style scoped>
img{
  width: 48px;
  height: 48px;
}
</style>

在这里插入图片描述
现在,将查询的条数修改为1001,测试下效果。
在这里插入图片描述
在这里插入图片描述
同样的,在新增电子书的时候,给电子书名称添加校验限制:名称不能为空。
所以
在这里插入图片描述
在这里插入图片描述
现在来验证下,
在这里插入图片描述
不过,如果给名称输入一个空字符串,这里也能保存,如下,
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值