全局异常处理+JSR303验证

2023-09-18 16:24:12

一、前言

我们在日常开发中,避不开的就是参数校验,有人说前端不是会在表单中进行校验的吗?在后端中,我们可以直接不管前端怎么样判断过滤,我们后端都需要进行再次判断, 为了安全 。因为前端很容易拜托,当测试使用 PostMan 来测试,如果后端没有校验,不就乱了吗?肯定会有很多异常的。今天小编和大家一起学习一下JSR303专门用于参数校验的,算是一个工具吧!

二、JSR303简介

JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,

三、导入依赖

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>

四、常用注解

约束注解名称约束注解说明
@Null用于验证对象为null
@NotNull用于对象不能为null,无法查检长度为0的字符串
@NotBlank只用于String类型上,不能为null且trim()之后的size>0
@NotEmpty用于集合类、String类不能为null,且size>0。但是带有空格的字符串校验不出来
@Size用于对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length用于String对象的大小必须在指定的范围内
@Pattern用于String对象是否符合正则表达式的规则
@Email用于String对象是否符合邮箱格式
@Min用于Number和String对象是否大等于指定的值
@Max用于Number和String对象是否小等于指定的值
@AssertTrue用于Boolean对象是否为true
@AssertFalse用于Boolean对象是否为false

所有的大家参考jar包

五、@Valid

@Valid:

  • JDK提供的(标准JSR-303规范)
  • 不支持分组校验
  • 可以用在方法、构造函数、方法参数和成员属性(字段)上
  • 可以加在成员属性(字段)上,能够独自完成级联校验

例子:

/**
 * 测试 valid
 */
@ResponseBody
@PostMapping("/valid")
public R valid(@Valid @RequestBody StudentEntity studentEntity, BindingResult result) {
    System.out.println(studentEntity.toString());
    System.out.println(result.getPropertyEditorRegistry());
    System.out.println(result.getGlobalError());
    System.out.println(result.getModel());
    if (result.hasErrors()) {
        Map<String, String> map = new HashMap<>();
        //1、获取校验的错误结果
        result.getFieldErrors().forEach(item -> {
            //FieldError 获取到错误提示
            String message = item.getDefaultMessage();
            //获取错误的属性的名字
            String field = item.getField();
            map.put(field, message);
        });
        return R.error(GlobalExceptionEnume.PROCESSOR_EXCEPTION.getCode(), GlobalExceptionEnume.PROCESSOR_EXCEPTION.getMessage()).put("error", map);
    } else {
        return R.ok();
    }
}

 

抽离全局异常处理

1. 心得体会

上面我们要在每个校验的接口上面写,所以我们要抽离出来做个全局异常。并且要改进一下,原来的是把错误信息放到data里,但是正常情况下的data是返回给前端的数据。!

2. 书写ExceptionControllerAdvice

package com.beijing.gulimall.product.exception;


import com.beijing.common.common.GlobalExceptionEnume;
import com.beijing.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

//@ResponseBody
//@ControllerAdvice
@RestControllerAdvice
@Slf4j
public class GlobalException {


    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R Exception(HttpServletRequest req, MethodArgumentNotValidException e){
        String url = req.getRequestURL().toString();
        String httpMethod = req.getMethod();
        log.info("URL :{} " + url);
        log.info("HTTP_METHOD {}: ",httpMethod);
        BindingResult bindingResult = e.getBindingResult();
        Map<String,String> map = new HashMap<>();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            //FieldError 获取到错误提示
            String message = fieldError.getDefaultMessage();
            //获取错误的属性的名字
            String field = fieldError.getField();
            map.put(field,message);
        }
        return R.error(GlobalExceptionEnume.PROCESSOR_EXCEPTION.getCode(),GlobalExceptionEnume.PROCESSOR_EXCEPTION.getMessage()).put("data",map);
    }
//info 日志
//2023-09-18 17:00:01.245  INFO 18164 --- [nio-4000-exec-3]c.b.g.product.exception.GlobalException  : URL :{}http://127.0.0.1:4000/product/skuinfo/valid2
//2023-09-18 17:00:01.246  INFO 18164 --- [nio-4000-exec-3] c.b.g.product.exception.GlobalException  : HTTP_METHOD POST:

}

测试结果:

{
    "msg": "处理器异常",
    "code": 500,
    "data": {
        "age": "最小不能小于10"
    }
}

定义枚举和R

package com.beijing.common.common;

public enum GlobalExceptionEnume {

    PROCESSOR_EXCEPTION(500,"处理器异常");


    private int code;
    private String message;

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

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }


    public static String getMessageByCode(int code){
        for (GlobalExceptionEnume value : GlobalExceptionEnume.values()) {
            if (value.getCode() == code){
                return value.getMessage();
            }
        }
        return null;
    }

}

R.class


package com.beijing.common.utils;

import org.apache.http.HttpStatus;

import java.util.HashMap;
import java.util.Map;


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, "未知异常,请联系管理员");
	}
	
	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;
	}
}

更多推荐

Vue 使用vue-pdf 显示pdf文件 切换页面 缩放 全屏 自动播放等

<template><divid="container"><!--上一页、下一页--><divclass="right-btn"><div@click="toFullOrExit"class="turn-btn"><span>{{isFull==1?"取消全屏":"全屏"}}</span></div><div@clic

ubuntu 22.04运行opencv4的c++程序遇到的问题

摘要:本文介绍一下在ubuntu系统中,运行一个最简单的opencv4程序都出问题的解决方法,并对其基本原理作简单阐述。解决问题的方法有很多,本文只提供其中一种。opencv版本是4.2.0,ubuntu版本是20.04查询opencv版本的指令是pkg-config--modversionopencv4,pkg-co

CRM客户管理系统主要用途

对于大多数企业而言业绩就是生命线,因此销售环节在企业管理过程中意义重大。面对愈发内卷的市场竞争企业就要借助CRM销售管理系统改善各个环节存在的漏洞,占据优势。那么,销售管理系统的用途有哪些,接下来我们从下面3个功能来介绍。1.客户管理通过销售管理系统中的商机管理等功能可以将系统中的客户信息关联整合,一方面保证客户数据安

性能测试知多少?怎样开展性能测试

看到好多新手,在性能需求模糊的情况下,随便找一个性能测试工具,然后就开始进行性能测试了,在这种情况下得到的性能测试结果很难体现系统真实的能力,或者可能与系统真实的性能相距甚远。与功能测试相比,性能测试在技术层面具有更大的复杂性。在以往的测试流程中,性能测试只是测试流程的一部分,是系统或验收测试的一个可选项。但随着测试技

计算机毕业设计 基于SSM+Vue的志愿者招募网站的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌🍅文末获取源码联系🍅👇🏻精彩专栏推荐订阅👇🏻不然下次找不到哟————————————————计算机毕业设计题目《10

设计模式:装饰器模式

目录组件代码实现源码中使用优缺点总结装饰器模式是一种结构型设计模式,用于在不改变原有对象的基础上,动态地给对象添加额外的功能。装饰器模式通过将对象包装在一个装饰器对象中,然后逐层地添加装饰器,实现对对象的功能进行增强或修改。装饰器模式可以在运行时动态地添加、删除或修改对象的行为,而无需修改原始对象的结构。这种模式常用于

私人云盘系统对比

fileRun、NextCloud、ownCloud、Seafile、CloudReve、可道云https://www.bilibili.com/video/BV1vD4y1e78K/seafile页面不太好看同步功能好seafile的在线预览功能做的很差不支持office在线预览稳定NextCloud(OwnClou

Python —— pytest框架

1、认识pytest框架1、搭建自动化框架的思路与流程1、搭建自动化测试框架的思路和流程,任意测试手段流程都是一致的:手工测试、自动化测试、工具测试手工测试:熟悉业务——写用例——执行用例并记录结果——生成测试报告自动化测试:熟悉业务——写自动化用例(来自于手工测试用例,格式转化为代码)——代码表达用例——代码收集测试

LEETCODE 169 189 121 122 55

169多数元素给定一个大小为n的数组nums,返回其中的多数元素。多数元素是指在数组中出现次数大于⌊n/2⌋的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。classSolution{public:intmajorityElement(vector<int>&nums){sort(nums.begin(

win10如何把繁体字改成简体字

win10如何把繁体字改成简体字WBOY发布:2023-07-0913:17:05转载3431人浏览过win10客户在开展文字输入的时候遇到了字体变为繁体字的状况,那么如何把繁体字改成简体字呢?是否有快捷键呢?win10繁体字改简体字的快捷键是Ctrl+Shift+F,你也可以在系统的语言设置中进行操作,开启微软拼音的

线性搜索简介

概念:线性搜索(LinearSearch)是一种简单直观的搜索算法,用于在一个未排序或已排序的数组中查找目标元素。它从数组的第一个元素开始逐个比较,直到找到匹配的元素或搜索完整个数组。线性搜索解决的问题是在一个集合中查找特定元素的位置或判断元素是否存在。算法特点:简单直观:线性搜索是一种最基本的搜索算法,易于理解和实现

热文推荐