Spring Boot Validator参数校验以及分组校验的使用

转:阿里技术 一 前言 做web开发有一点很烦人就是要对前端输入参数进行校验,基本上每个接口都要对参数进行校验,比如一些非空校验、格式校验等。如果参数比较少的话还是容易处理的一但参数比较多了的话代码中就会出现大量的if-else语句。 使用这种方式虽然简单直接,但是也有不好的地方,一是降低了开发效率,因为我们需要校验的参数会存在很多地方,并且不同地方会有重复校验,其次降低了代码可读性,因为在业务代码中掺杂了太多额外工作的代码。 所以我们可以使用validator组件来代替我们进行不必要的coding操作。本文基于validator的介绍资料,也结合自己在项目中的实际使用经验进行了总结,希望能帮到大家。 1 什么是validator Bean Validation是Java定义的一套基于注解的数据校验规范,目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),已经经历了三个版本 。需要注意的是,JSR只是一项标准,它规定了一些校验注解的规范,但没有实现,比如@Null、@NotNull、@Pattern等,它们位于 javax.validation.constraints这个包下。而hibernate validator是对这个规范的实现,并增加了一些其他校验注解,如 @NotBlank、@NotEmpty、@Length等,它们位于org.hibernate.validator.constraints这个包下。 如果我们的项目使用了Spring Boot,hibernate validator框架已经集成在 spring-boot-starter-web中,所以无需再添加其他依赖。如果不是Spring Boot项目,需要添加如下依赖。 二 注解介绍 1 validator内置注解 注解 说明 @Null 被注释的元素必须为null @NotNull 被注释的元素不能为null @AssertTrue 被注释的元素必须为true @AssertFalse 被注释的元素必须为false @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 @Size(max,min) 被注释的元素的大小必须在指定的范围内 @Digits(integer, fraction) 被注释的元素必须是一个数字,其值必须必须在可接受的范围内 @Past 被注释的元素必须是一个过去的日期 @Future 被注释的元素必须是一个将来的日期 @Pattern(value) 被注释的元素必须符合指定的正则表达式 […]

Spring中定义Bean的方式

转:Java技术迷 前言 在庞大的 Java 技术体系中,Spring 有着举足轻重的地位,它给每位开发者带来了极大的便利和惊喜。 我们都知道 Spring 是创建和管理bean的工厂,它提供了多种方式定义 bean,能够满足我们日常工作中的多种业务场景。 那么问题来了,你知道 Spring 中有哪些方式可以定义 bean? 我估计很多人会说出以下三种: 没错,但我想说的是以上三种方式只是开胃小菜,。实际上 Spring 的功能远比你想象中更强大。 各位看官如果不信,请继续往下看。 1. XML 文件配置 bean 我们先从 XML 配置 bean开始。 它是 Spring 最早支持的方式。后来,随着 Spring Boot 越来越受欢迎,该方法目前已经用得很少了,但我建议我们还是有必要了解一下。 1.1 构造器 如果你之前有在 bean.xml 文件中配置过 bea n的经历,那么对如下的配置肯定不会陌生: 这种方式是以前使用最多的方式,它默认使用了无参构造器创建 bean。 当然我们还可以使用有参的构造器,通过 标签来完成配置。 其中: index 表示下标,从 0 开始; value 表示常量值; ref 表示引用另一个 bean。 1.2 […]

关于spring.jpa.open-in-view

在springboot中,spring.jpa.open-in-view值是默认开启的 开启open-in-view的意义: 在事务外也可以访问懒加载的数据 hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web 层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session 已经关闭,这些导致延迟加载数据的访问异常。 把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。目的是为了实现”Open Session in View”的模式。例如: 它允许在事务提交之后延迟加载显示所需要的对象。 OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中,它将自动被 spring 的事务管理器探测到。所以 OpenSessionInViewFilter 适用于 Service 层使用HibernateTransactionManager 或 JtaTransactionManager 进行事务管理的环境,也可以用于非事务只读的数据操作中。 采用Controller-Service-Dao三层结构,事务配置在Service层 使用前 使用后 Controller中的各Service独享Session Controller中的各Service共享Session Controller中的各Service独享一级缓存 Controller中的各Service共享一级缓存 Controller中通过Service查找的实体为游离状态 Controller中通过Service查找的实体为托管状态 Controller中通过Service查找的实体Lazy异常 Controller中通过Service查找的实体Lazy正常 Controller中通过Service查找的实体修改后不会同步到数据库 Controller中通过Service查找的实体修改后若存在可写事务则会同步到数据库 Controller中各Service事务独立 Controller中各Service事务独立 实现原理, 通过OpenEntityManagerInViewInterceptor这个拦截器处理, 他继承自 […]

Java对象转换方案分析与mapstruct实践

转 阿里技术 一 前言 随着系统模块分层不断细化,在Java日常开发中不可避免地涉及到各种对象的转换,如:DO、DTO、VO等等,编写映射转换代码是一个繁琐重复且还易错的工作,一个好的工具辅助,减轻了工作量、提升开发工作效率的同时还能减少bug的发生。 二 常用方案及分析 1 fastjson 这种方案因为通过生成中间json格式字符串,然后再转化成目标对象,性能非常差,同时因为中间会生成json格式字符串,如果转化过多,gc会非常频繁,同时针对复杂场景支持能力不足,基本很少用。 2 BeanUtil类 BeanUtil.copyProperties()结合手写get、set,对于简单的转换直接使用BeanUtil,复杂的转换自己手工写get、set。该方案的痛点就在于代码编写效率低、冗余繁杂还略显丑陋,并且BeanUtil因为使用了反射invoke去赋值性能不高。 只能适合bean数量较少、内容不多、转换不频繁的场景。 apache.BeanUtils 这种方案因为用到反射的原因,同时本身设计问题,性能比较差。集团开发规约明确规定禁止使用。 spring.BeanUtils 这种方案针对apache的BeanUtils做了很多优化,整体性能提升不少,不过还是使用反射实现比不上原生代码处理,其次针对复杂场景支持能力不足。 3 beanCopier 这种方案动态生成一个要代理类的子类,其实就是通过字节码方式转换成性能最好的get和set方式,重要的开销在创建BeanCopier,整体性能接近原生代码处理,比BeanUtils要好很多,尤其在数据量很大时,但是针对复杂场景支持能力不足。 4 各种Mapping框架 分类 Object Mapping 技术从大的角度来说分为两类,一类是运行期转换,另一类则是编译期转换: 运行期反射调用 set/get 或者是直接对成员变量赋值。这种方式通过invoke执行赋值,实现时一般会采用beanutil, Javassist等开源库。运行期对象转换的代表主要是Dozer和ModelMaper。 编译期动态生成 set/get 代码的class文件,在运行时直接调用该class的 set/get 方法。该方式实际上仍会存在 set/get 代码,只是不需要开发人员自己写了。这类的代表是:MapStruct,Selma,Orika。 分析 无论哪种Mapping框架,基本都是采用xml配置文件 or 注解的方式供用户配置,然后生成映射关系。 编译期生成class文件方式需要DTO仍然有set/get方法,只是调用被屏蔽;而运行期反射方式在某些直接填充 field的方案中,set/get代码也可以省略。 编译期生成class方式会有源代码在本地,方便排查问题。 编译期生成class方式因为在编译期才出现java和class文件,所以热部署会受到一定影响。 反射型由于很多内容是黑盒,在排查问题时,不如编译期生成class方式方便。参考GitHub上工程java-object-mapper-benchmark可以看出主要框架性能比较。 反射型调用由于是在运行期根据映射关系反射执行,其执行速度会明显下降N个量级。 通过编译期生成class代码的方式,本质跟直接写代码区别不大,但由于代码都是靠模板生成,所以代码质量没有手工写那么高,这也会造成一定的性能损失。 综合性能、成熟度、易用性、扩展性,mapstruct是比较优秀的一个框架。 三 Mapstruct使用指南 1 Maven引入 2 […]

lWoHvYe 无悔,专一