概述
在过去的一篇文章写过《Java 优雅地分离验证代码与业务核心代码,减少过多的if-else》,利用文章中提及的方式做业务验证,在后续的开发中,慢慢演化诞生了优化版。这个优化版方式,在原来的基础上,结合对Spring IOC容器托管的对象实例处理,达到一个业务验证代码多次复用,而且拓展更好的目的。
废话不多说,看Demo。
验证接口类:Condition.java
/**
* 业务验证接口
* @author rocky
*/
public interface Condition<T> {
/**
* 验证
* @param t 参数
*/
void apply(T t);
}
业务验证工具类:ConditionValidator.java
/**
* 业务验证工具类
* @author rocky
*/
public class ConditionValidator {
// 为什么这里有个默认私有构造方法?因为,ConditionValidator不允许实例化。
private ConditionValidator() {}
/**
* 业务验证
* @param t 参数
* @param conditions 具体的业务验证
* @param <T> 参数类型
*/
public static <T> void apply(T t, List<Condition<T>> conditions) {
conditions.forEach(c -> c.apply(t));
}
/**
* 业务验证
* @param t 参数
* @param clazz 类对象
* @param <T> 参数类型
*/
public static <T> void apply(T t, Class< ? extends Condition<T>> clazz) {
// SpringContextUtils是我这边封装的Spring Ioc 容器管理的一个工具类
// 核心内容是org.springframework.context.ApplicationContext,有兴趣的同学可以去了解下
Condition<T> condition = null;
if (SpringContextUtils.containsBean(clazz)) {
condition = SpringContextUtils.getBean(clazz);
}
// 为NULL,说明Spring IOC容器没有托管对象实例
if (condition == null) {
try {
condition = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new NullPointerException("The clazz can not instantiated");
}
}
condition.apply(t);
}
/**
* 业务验证
* @param t 参数
* @param classes 可变类参数对象
* @param <T> 参数类型
*/
public static <T> void apply(T t, Class<? extends Condition<T>>... classes) {
for (Class<? extends Condition<T>> clazz : classes) {
apply(t, clazz);
}
}
}
某业务验证类:BookingTimeCondition.java
/**
* 预约时间段数据验证
* @author rocky
*/
public class BookingTimeCondition implements Condition<BookingTime> {
@Override
public void apply(BookingTime bookingTime) {
// BookingTime是一个简单的pojo类,里面带有java bean validator的注解
// hibernate-validator 验证
ValidatorUtils.validateEntity(bookingTime);
// 业务验证,判断预约时间是否符合数据规范
String timeSlot = bookingTime.getTimeSlot();
String[] timeArray = timeSlot.split("-");
if (timeArray.length < 2) {
throw new ValidatorException("预约时间段格式错误");
}
Object orderTime = bookingTime.getOrderTime();
String orderTimeStr;
// 这样是为了兼容不同类型的时间数据
if (orderTime instanceof String) {
orderTimeStr = (String) orderTime;
} else if (orderTime instanceof Date) {
Date date = (Date) orderTime;
orderTimeStr = DateFormatUtils.format(date, "yyyy-MM-dd");
} else if (orderTime instanceof LocalDate) {
LocalDate date = (LocalDate) orderTime;
orderTimeStr = date.toString();
} else {
orderTimeStr = orderTime.toString();
}
String bt = orderTimeStr + " " + timeArray[1];
Date orderDate = null;
try {
orderDate = DateUtils.parseDate(bt, "yyyy-MM-dd HH:mm");
} catch (ParseException ex) {
throw new ValidatorException("预约时间格式错误");
}
if (new Date().after(orderDate)) {
throw new ValidatorException("预约时间只能在当前时间之后");
}
}
}
用法如下:
BookingTime bookingTime = new BookingTime(form.getOrderTime(), form.getTimeSlot());
// 验证预约时间是否合法
// 用法1,推荐这个方法
ConditionValidator.apply(bookingTime, BookingTimeCondition.class);
// 用法2,如果验证条件已有实例,可以采用这个方式复用实例,减少系统资源消耗
ConditionValidator.apply(bookingTime, Arrays.asList(new BookingTimeCondition()));
如果你的业务验证需要注入Service层或者Dao的对象去查库校验,那么实现Condition接口的子类实例需要交给Spring Ioc容器来管理。
代码如下:
/**
* 用户账号资格验证
* @author rocky
*/
@Component
public class UserBalanceCondition implements Condition<UserEntity> {
@Resource
private UserWalletService userWalletService;
public void apply(UserEntity user) {
// 以下是业务验证内容,这里只是举例说明
UserWalletEntity wallet = userWalletService.getByUserId(user.getId());
if (userWalletService.isAllowTranfter(wallet)) {
throw new ValidatorException("用户xx不允许操作流动资金");
}
...
}
}
用法:
// 执行验证操作,如果UserBalanceCondition被Spring Ioc托管,取Spring Ioc里面的实例进行运算,否则通过反射来实例化进行运算。
ConditionValidator.apply(user, UserBalanceCondition.class);
这样,在不同的子业务中,需要相同的业务验证,可以通过这样的方式,来提高代码复用率和开发效率。
最后
以上就是寒冷红牛为你收集整理的Java 优雅地分离验证代码与业务核心代码,减少过多的if-else(优化版)的全部内容,希望文章能够帮你解决Java 优雅地分离验证代码与业务核心代码,减少过多的if-else(优化版)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复