mybatis-plus实现 相似实体类使用泛型操作同样的逻辑代码更新保存修改的方法

场景

假设有3个类似的实体类,某处需要处理的业务逻辑(增删改)是一样的,业务还比较复杂,如果单独写,则需要写3个大致一样的长代码段,此处想利用泛型解决。

问题

相似的实体类有不同的字段,而泛型不能获取其属性方法,所以有些不好解决,尝试许久,终于可行,示例代码如下。

PS:系统使用了mybatis plus框架,所以有extends IService,并能使用其提供的便利方法。

一、Entity准备

  1. 其实我自己涉及到的是为角色配置各种权限的逻辑,为方便这里随意设计三个表:
    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;
}
  1. 使用了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()判断具体的类来实现个性化,即可生成通用的逻辑代码了

最后的最后,如果我的文章帮到了你,拜托拜托给个赞吧~~在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mybatis-plus是Mybatis的增强工具,它在Mybatis的基础上添加了许多功能,包括强大的条件构造器、内置的Mapper和通用的Service等。它可以简化开发,提高效率。\[1\]\[2\] 要实现多对多多查询,可以使用Mybatis-plus提供的注解和方法。首先,需要在实体类使用@TableName注解指定名,并使用@TableId注解标识主键。然后,在Mapper接口中继承BaseMapper,并指定泛型为对应的实体类。这样就可以使用Mybatis-plus提供的方法进行多查询了。\[3\] 例如,假设有两个实体类User和Role,它们之间是多对多的关系。可以在User实体类中添加一个List<Role>类型的属性,并使用@TableField注解指定关联的字段。然后,在UserMapper接口中定义一个方法使用@Select注解编写SQL语句进行多查询。 ```java @TableName("user") public class User { @TableId(type = IdType.AUTO) private Integer cid; private String cname; private String password; private String telephone; private String money; private Integer version; @TableField(exist = false) private List<Role> roles; // 省略getter和setter } @TableName("role") public class Role { @TableId(type = IdType.AUTO) private Integer rid; private String rname; // 省略getter和setter } @Mapper public interface UserMapper extends BaseMapper<User> { @Select("SELECT u.*, r.* FROM user u JOIN user_role ur ON u.cid = ur.user_id JOIN role r ON ur.role_id = r.rid WHERE u.cid = #{cid}") User selectUserWithRoles(Integer cid); } ``` 在上述代码中,通过使用@Select注解编写了一个多查询的SQL语句,查询了用户和角色的信息,并使用JOIN关键字连接了user、user_role和role三张。通过调用selectUserWithRoles方法,就可以实现多对多多查询了。 总结起来,使用Mybatis-plus实现多对多多查询的步骤包括:定义实体类、添加注解、编写SQL语句、调用方法进行查询。希望对你有帮助! #### 引用[.reference_title] - *1* *2* *3* [【MyBatis】 MyBatis与MyBatis-Plus的区别](https://blog.csdn.net/zsy3757486/article/details/126813667)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值