热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

SpringBoot2.XKotlin系列之数据校验和异常处理详解

这篇文章主要介绍了SpringBoot2.XKotlin系列之数据校验和异常处理详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

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

定义实体并加上校验注解

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

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

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

 @NotEmpty(message = "兴趣爱好不能为空")
 var Interests:List = 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: 校验List、Map、Set是否为空
  • @Email: 校验是否为邮箱格式
  • @Max @Min: 校验Number或String是否在指定范围内
  • @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 {

 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 {
  logger.error("全局异常:{}", exception)
  return ResultVo(500, "系统异常", "")
 }

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

}

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

编写校验工具

object ValidatorUtils {

 private val validator = Validation.buildDefaultValidatorFactory().validator

 /**
  * 校验对象属性
  * @param obj 被校验对象
  * @param  泛型
  * @return Map
  */
 fun validate(obj: Any): Map {
  var errorMap: Map? = 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  泛型
  * @return List
  */
 fun validata(obj: Any): List {
  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 {
 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": "学校"
 }
}

本章内容就到此结束了,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • mybatis相关面试题 ... [详细]
  • Pikachu平台SQL注入漏洞详解
    本文详细介绍了SQL注入漏洞的基本原理、攻击流程、不同类型注入点的识别与利用方法,以及基于union联合查询、报错信息、布尔盲注、时间盲注等多种技术手段的信息获取方式。同时,探讨了如何通过SQL注入获取操作系统权限,以及HTTP Header注入和宽字节注入等高级技巧。最后,提供了使用SQLMap自动化工具进行漏洞测试的方法和常见的SQL注入防御措施。 ... [详细]
  • Python安全实践:Web安全与SQL注入防御
    本文旨在介绍Web安全的基础知识,特别是如何使用Python和相关工具来识别和防止SQL注入攻击。通过实际案例分析,帮助读者理解SQL注入的危害,并掌握有效的防御策略。 ... [详细]
  • 本文详细介绍了PHP中的几种超全局变量,包括$GLOBAL、$_SERVER、$_POST、$_GET等,并探讨了AJAX的工作原理及其优缺点。通过具体示例,帮助读者更好地理解和应用这些技术。 ... [详细]
  • 2023年1月28日网络安全热点
    涵盖最新的网络安全动态,包括OpenSSH和WordPress的安全更新、VirtualBox提权漏洞、以及谷歌推出的新证书验证机制等内容。 ... [详细]
  • 本文档详细介绍了如何在MongoDB命令行中执行基本操作,包括数据库的选择与创建、文档的插入与查询、文档的更新与删除等。同时,还涵盖了条件查询、统计、模糊查询等高级功能。 ... [详细]
  • 本文档详细规划了从基础到高级的软件测试学习路径,包括但不限于测试基础、Linux和数据库、功能测试、Python编程、接口测试、性能测试、金融项目实战、UI自动化测试等内容,旨在为初学者和进阶者提供全面的学习指导。 ... [详细]
  • Linux环境下PostgreSQL的安装、配置及日常管理
    本文详细介绍了在Linux环境下安装、配置PostgreSQL数据库的过程,包括环境准备、安装步骤、配置数据库访问以及日常服务管理等方面的内容。适合初学者和有一定经验的数据库管理员参考。 ... [详细]
  • 地理信息、定位技术及其在物联网中的应用
    地理位置信息是物联网系统中不可或缺的关键要素,它不仅提供了物理世界的坐标,还增强了物联网应用的实用性和准确性。本文探讨了位置服务的基本概念、关键技术及其在物联网中的重要作用,特别介绍了定位技术的最新进展。 ... [详细]
  • Python与MySQL交互指南:从基础到进阶
    本文深入探讨了Python与MySQL数据库的集成方法,包括数据库连接、数据表创建、索引管理、数据操作以及如何防止SQL注入等关键内容。适合初学者及希望提升数据库操作技能的开发者。 ... [详细]
  • 本文探讨了Flutter和Angular这两个流行框架的主要区别,包括它们的设计理念、适用场景及技术实现。 ... [详细]
  • 本文详细介绍如何在Spring Boot项目中集成和使用JPA,涵盖JPA的基本概念、Spring Data JPA的功能以及具体的操作步骤,帮助开发者快速掌握这一强大的持久化技术。 ... [详细]
  • 帝国cms各数据表有什么用
    CMS教程|帝国CMS帝国cmsCMS教程-帝国CMS精易编程助手源码,ubuntu桥接设置,500错误是tomcat吗,爬虫c原理,php会话包括什么,营销seo关键词优化一般多 ... [详细]
  • 本文介绍了如何在Laravel框架中使用Select方法进行数据库查询,特别是当需要根据传入的分类ID查询相关产品时的正确做法和注意事项。 ... [详细]
  • 深入解析 RuntimeClass 及多容器运行时应用
    本文旨在探讨RuntimeClass的起源、功能及其在多容器运行时环境中的实际应用。通过详细的案例分析,帮助读者理解如何在Kubernetes集群中高效管理不同类型的容器运行时。 ... [详细]
author-avatar
mobiledu2502890887
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有