SpringBoot 2.X Kotlin系列之数据校验和异常处理

栏目: Java · 发布时间: 6年前

内容简介:在开发项目时,我们经常需要在前后端都校验用户提交的数据,判断提交的数据是否符合我们的标准,包括字符串长度,是否为数字,或者是否为手机号码等;这样做的目的主要是为了减少SQL注入攻击的风险以及脏数据的插入。提到数据校验我们通常还会提到异常处理,因为为了安全起见,后端出现的异常我们通常不希望直接抛到客户端,而是经过我们的处理之后再返回给客户端,这样做主要是提升系统安全性,另外就是给予用户友好的提示。这里首先使用的是基础校验注解,位于

SpringBoot 2.X Kotlin系列之数据校验和异常处理

在开发项目时,我们经常需要在前后端都校验用户提交的数据,判断提交的数据是否符合我们的标准,包括字符串长度,是否为数字,或者是否为手机号码等;这样做的目的主要是为了减少 SQL 注入攻击的风险以及脏数据的插入。提到数据校验我们通常还会提到异常处理,因为为了安全起见,后端出现的异常我们通常不希望直接抛到客户端,而是经过我们的处理之后再返回给客户端,这样做主要是提升系统安全性,另外就是给予用户友好的提示。

定义实体并加上校验注解

class StudentForm() {
    
    @NotBank(message = '生日不能为空')
    var birthday: String = ""

    @NotBlank(message = "Id不能为空")
    var id:String = ""

    @NotBlank(message = "年龄不能为空")
    var age:String = ""

    @NotEmpty(message = "兴趣爱好不能为空")
    var Interests:List<String> = Collections.emptyList()

    @NotBlank(message = "学校不能为空")
    var school: String = ""
    override fun toString(): String {
        return ObjectMapper().writeValueAsString(this)
    }
}

这里首先使用的是基础校验注解,位于 javax.validation.constraints 下,常见注解有 @NotNull@NotEmpty@Max@Email@NotBank@Size@Pattern ,当然出了这些还有很多注解,这里就不在一一讲解,想了解更多的可以咨询查看jar包。

这里简单讲解一下注解的常见用法:

  • @NotNull : 校验一个对象是否为 Null
  • @NotBank : 校验字符串是否为空串
  • @NotEmpty : 校验 ListMapSet 是否为空
  • @Email : 校验是否为邮箱格式
  • @Max @Min : 校验 NumberString 是否在指定范围内
  • @Size : 通常需要配合 @Max @Min 一期使用
  • @Pattern : 配合自定义正则表达式校验

定义返回状态枚举

enum class ResultEnums(var code:Int, var msg:String) {
    SUCCESS(200, "成功"),
    SYSTEM_ERROR(500, "系统繁忙,请稍后再试"),

}

自定义异常

这里主要是参数校验,所以定义一个运行时异常,代码如下:

class ParamException(message: String?) : RuntimeException(message) {
    var code:Int = ResultEnums.SUCCESS.code

    constructor(code:Int, message: String?):this(message) {
        this.code = code
    }
}

统一返回结构体定义

class ResultVo<T> {

    var status:Int = ResultEnums.SUCCESS.code

    var msg:String = ""

    var data:T? = null

    constructor()

    constructor(status:Int, msg:String, data:T) {
        this.status = status
        this.data = data
        this.msg = msg
    }

    override fun toString(): String {
        return ObjectMapper().writeValueAsString(this)
    }
}

全局异常处理

这里的全局异常处理,是指请求到达Controller层之后发生异常处理。代码如下:

@RestControllerAdvice
class RestExceptionHandler {

    private val logger:Logger = LoggerFactory.getLogger(this.javaClass)

    @ExceptionHandler(Exception::class)
    @ResponseBody
    fun handler(exception: Exception): ResultVo<String> {
        logger.error("全局异常:{}", exception)
        return ResultVo(500, "系统异常", "")
    }

    @ExceptionHandler(ParamException::class)
    @ResponseBody
    fun handler(exception: ParamException): ResultVo<String> {
        logger.error("参数异常:{}", exception.localizedMessage)
        return ResultVo(exception.code, exception.localizedMessage, "")
    }

}

这里得和 Java 处理的方式大同小异,无疑就是更加简洁了而已。

编写校验工具

object ValidatorUtils {

    private val validator = Validation.buildDefaultValidatorFactory().validator

    /**
     * 校验对象属性
     * @param obj 被校验对象
     * @param <T> 泛型
     * @return Map
    </T> */
    fun validate(obj: Any): Map<String, String> {
        var errorMap: Map<String, String>? = null
        val set = validator.validate(obj, Default::class.java)
        if (CollectionUtils.isEmpty(set)) {
            return emptyMap()
        }
        errorMap = set.map { it.propertyPath.toString() to it.message }.toMap()
        return errorMap
    }

    /**
     * 校验对象属性
     * @param obj 被校验对象
     * @param <T> 泛型
     * @return List
    </T> */
    fun validata(obj: Any): List<String> {
        val set = validator.validate(obj, Default::class.java)
        return if (CollectionUtils.isEmpty(set)) {
            emptyList()
        } else set.stream()
                .filter {Objects.nonNull(it)}
                .map { it.message  }
                .toList()
    }
}

抽象校验方法

因为校验是通用的,几乎大部分接口都需要检验传入参数,所以我们把校验方法抽出来放在通用Controller层里,通用层这里不建议使用 Class 或者是 抽象类 ,而是使用 interface ,定义如下:

@Throws(ParamException::class)
fun validate(t:Any) {
    val errorMap = ValidatorUtils.validate(t).toMutableMap()
    if (errorMap.isNotEmpty()) {
        throw ParamException(ResultEnums.SYSTEM_ERROR.code, errorMap.toString())
    }
}

这里如果有参数错误就直接抛出参数异常,然后交给全局异常处理器来捕获。

Controller层编写

@PostMapping("/student")
fun create(@RequestBody studentForm: StudentForm): ResultVo<StudentDTO> {
    this.validate(studentForm)
    val studentDTO = StudentDTO()
    BeanUtils.copyProperties(studentForm, studentDTO)
    return ResultVo(200, "", studentDTO)
}

1.传入一个空对象: 返回结果:

{
    "status": 500,
    "msg": "{school=学校不能为空, id=Id不能为空, age=年龄不能为空, Interests=兴趣爱好不能为空}",
    "data": ""
}

自定义校验规则

本篇文章开始之前我们提到过 @Pattern ,这个注解主要是方便我们定义自己的校验规则,假如我这里需要校验前端传入的生日,是否符合我所需要的格式,如下所示:

@NotBlank(message = "生日不能为空")
@Pattern(regexp="^(19|20)\\d{2}-(1[0-2]|0?[1-9])-(0?[1-9]|[1-2][0-9]|3[0-1])$", message="不是生日格式")
var birthday: String = ""

这里的校验逻辑可能不完善,大家使用的时候需要注意。

修改完成后我再次请求

请求示例

空值

入参:

{
    "age": "10",
    "id": "1",
    "school": "学校",
    "interests": ["户外运动"],
    "birthday": ""
}

出参:

{
    "status": 500,
    "msg": "{birthday=生日不能为空}",
    "data": ""
}

错误参数

入参:

{
    "age": "10",
    "id": "1",
    "school": "学校",
    "interests": ["户外运动"],
    "birthday": "1989-20-20"
}

出参:

{
    "status": 500,
    "msg": "{birthday=不是生日格式}",
    "data": ""
}

正确示例

入参:

{
    "age": "10",
    "id": "1",
    "school": "学校",
    "interests": ["户外运动"],
    "birthday": "1999-01-01"
}

出参:

{
    "status": 200,
    "msg": "",
    "data": {
        "id": "1",
        "birthday": "1999-01-01",
        "age": "10",
        "school": "学校"
    }
}

本章内容就到此结束了,如果错误的地方欢迎大家及时指出,觉得有用的话就点个赞,谢谢❤


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Sass and Compass in Action

Sass and Compass in Action

Wynn Netherland、Nathan Weizenbaum、Chris Eppstein、Brandon Mathis / Manning Publications / 2013-8-2 / USD 44.99

Written by Sass and Compass creators * Complete Sass language reference * Covers prominent Compass community plug-ins * Innovative approach to creating stylesheets Cascading Style Sheets paint the we......一起来看看 《Sass and Compass in Action》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具