@TOC
场景
假设有3个类似的实体类,某处需要处理的业务逻辑(增删改)是一样的,业务还比较复杂,如果单独写,则需要写3个大致一样的长代码段,此处想利用泛型解决。
问题
相似的实体类有不同的字段,而泛型不能获取其属性方法,所以有些不好解决,尝试许久,终于可行,示例代码如下。
PS:系统使用了mybatis plus框架,所以有extends IService,并能使用其提供的便利方法。
一、Entity准备
- 其实我自己涉及到的是为角色配置各种权限的逻辑,为方便这里随意设计三个表: UserOrder - 订单,UserShop - 店铺,UserGoods - 商品。 都是一(userId)对多的关系,都有字段id和userId,不同的是每个表里还有自己独特的字段,如下。
@Data
public class UserOrder{
public UserOrder() {}
public UserOrder(Long id, Long userId, Long orderId, Date createDate) {
this.id = id;
this.userId= userId;
this.orderId= orderId;
this.createDate = createDate;
}
private Long id;
private Long userId;
@ApiModelProperty("订单id")
private Long orderId;
@ApiModelProperty("创建时间")
private Date createDate;
}
@Data
public class UserShop{
public UserShop() {}
public UserShop(Long id, Long userId, Long shopId) {
this.id = id;
this.userId= userId;
this.shopId= shopId;
}
private Long id;
private Long userId;
@ApiModelProperty("店铺id")
private Long shopId;
}
@Data
public class UserGoods{
public UserGoods() {}
public UserGoods(Long id, Long userId, Long goodsId) {
this.id = id;
this.userId= userId;
this.goodsId= goodsId;
}
private Long id;
private Long userId;
@ApiModelProperty("商品id")
private Long goodsId;
}
- 使用了mybatis-plus框架后的service写法:
public interface IUserOrderService extends IService<UserOrder> {
}
二、具体泛型写法
假设有一个复杂逻辑,这三个实体都需要过一遍,中间的操作都是一样的,只是字段不同。
中间的操作基本上是根据各种条件判断,然后进行增删改。
其中一个逻辑是,如果前端页面选中了所有选项,则数据库不保存所选项目 即为:如果数据库查出来user关联的项目为空,则为全选。
1. 实现类
@Autowired
private IUserOrderService userOrderService;
@Autowired
private IUserGoodsService userGoodsService;
@Autowired
private IUserShopService userShopService;
/**
* 更新用户
*
* @param userId 用户 - id
* @param orderIds 订单 - 前端页面上选中的idList
* @param shopIds 店铺 - 前端页面上选中的idList
* @param goodsIds 商品 - 前端页面上选中的idList
* /
@Transactional
@Override
public User modifyUser(Long userId, List<Long> orderIds, List<Long> goodsIds, List<Long> shopIds) {
User user = new User();
// 1.针对user表的逻辑1
// 2.针对user表的逻辑2
// ......
// n.更新关联关系
this.handleUserAssociat(userId, orderIds, UserOrder.class, userOrderService);
this.handleUserAssociat(userId, goodsIds, UserGoods.class, userGoodsService);
this.handleUserAssociat(userId, shopIds, UserShop.class, userShopService);
return user;
}
2.handleUserAssociat - 处理关联关系
/**
* 处理关联关系
* 之前数据库全选,现在数据库部分选 纯增
* 之前数据库部分选,现在数据库全选 纯减
* 之前数据库部分选,现在数据库部分选 saveOrUpdate已有+没有的,删除之前有现在没有的
* 之前数据库全选,现在数据库全选 不变
*
* @param userId 用户 - id
* @param chooseIds 前端页面上选中的idList
* @param clz 关联表的class
* @param service 关联的service
*/
private <T> void handleUserAssociat(Long userId, List<Long> chooseIds, Class<T> clz, IService<T> service) {
// 1.判断逻辑1
// 2.判断逻辑2
// ......
// n.判断之前和现在的数据库全选状态
Boolean selectAllOld = true; // 之前是否全选(此处直接赋值)
Boolean selectAllNow = false; // 现在是否全选(此处直接赋值)
List<Long> oldChoseAsoIds = new ArrayList<>(); // 之前保存的idList(此处直接赋值)
// n+1.根据全选状态判断决定操作
// PS: 此处逻辑:如果前端页面选中了所有选项,则数据库不保存所选项目,即为:如果数据库查出来user关联的项目为空,则为全选。
if (selectAllOld && !selectAllNow) {
// 1.之前数据库全选,现在数据库部分选 纯增
this.saveOrUpdateBatchUserAsos(userId, chooseIds, clz, service);
} else if (!selectAllOld && selectAllNow) {
// 2.之前数据库部分选,现在数据库全选 纯减
bol = service.removeByIds(oldChoseAsoIds);
} else if (!selectAllOld && !selectAllNow) {
// 3.之前数据库部分选,现在数据库部分选 saveOrUpdate已有+没有的,删除之前有现在没有的
List<Long> dels = new ArrayList<>(); // fcacIds
for (Long oldId : oldChoseAsoIds) {
if (!chooseIds.contains(oldId)) { // 现在不包含以前所选的,删除此项
dels.add(oldId);
} else { // 现在已包含以前所选的,从list中移除
Boolean b = chooseIds.remove(oldId);
if (!b) throw new ApiException("保存失败");
}
}
// 删除 - 现在不包含以前所选的list
String asoIdName = "goods_id";
if (UserOrder.class.getName().equals(clz.getName())) {
asoIdName = "order_id";
} else if (UserShop.class.getName().equals(clz.getName())) {
asoIdName = "shop_id";
}
bol = service.remove(new QueryWrapper<T>().eq("user_id", userId).in(asoIdName, dels));
// 新增 - 现在新增的
this.saveOrUpdateBatchUserAsos(userId, chooseIds, clz, service);
}
if (!bol) {
throw new ApiException("保存失败");
}
}
3.saveOrUpdateBatchUserAsos - 批量保存关联关系(重要)
/**
* 批量保存关联关系,实例化成具体对象
*
* @param userId 用户
* @param chooseIds 选中的关联ids
* @param clz
* @param service
*/
private <T> void saveOrUpdateBatchUserAsos (Long userId, List<Long> chooseIds , Class<T> clz, IService<T> service) {
List<T> saveList = new ArrayList<>();
for (Long id : chooseIds) {
// 具体实例化
if (UserOrder.class.getName().equals(clz.getName())) {
saveList.add((T) new UserOrder(null, userId, id, new Date()));
} else if (UserGoods.class.getName().equals(clz.getName())) {
saveList.add((T) new UserGoods(null, userId, id));
} else if (UserShop.class.getName().equals(clz.getName())) {
saveList.add((T) new UserShop(null, userId, id));
}
}
Boolean bol = service.saveBatch(saveList);
if (!bol) {
throw new ApiException("保存失败");
}
}
总结
使用mybatis-plus(其他框架也可,只要有统一的实现方法就行) 再应用上泛型通配,用class.getName()判断具体的类来实现个性化,即可生成通用的逻辑代码了
最后的最后,如果我的文章帮到了你,拜托拜托给个赞吧~~