基于Mybatis的通用Service层实现

首先抽象实体Bean的父类BaseModel,包括通用的创建时间、分页等基本信息:

public abstract class BaseModel implements Serializable {
    private static final long serialVersionUID = -665036712667731957L;

    /**
     * 排序 升 降
     */
    private String order;
    /**
     * 排序字段
     */
    private String orderBy;
    private String orderType;
    /**
     * 分页用当前页号
     */
    private Integer page = 1;
    /**
     * 分页用记录开始位置
     */
    private Integer startPos;
    /**
     * 分页用页面大小
     */
    private Integer pageSize = 20;

    /**
     * 记录创建时间
     */
    private Date createTime;
    /**
     * 记录最后一次修改时间
     */
    private Date updateTime;
    /**
     * 创建人ID
     */
    private Integer creatorID;
    /**
     * 创建人用户名
     */
    private String creatorUserName;
    /**
     * 创建人姓名
     */
    private String creatorName;

    public abstract Object getId();

    @Override
    public String toString() {
        ToStringBuilder builder = new ToStringBuilder(this);
        Field[] fields = this.getClass().getDeclaredFields();
        try {
            for (Field f : fields) {
                f.setAccessible(true);
                builder.append(f.getName(), f.get(this));
            }
        } catch (Exception e) { // Suppress
            builder.append("toString builder encounter an error");
        }
        return builder.toString();
    }
}

 之后定义一个通用的泛型化的DAO接口,该接口里包含了比较通用的CRUD操作的方法声明。通过继承该接口,使你的DAO接口免去声明这些比较通用的CRUD方法的工作。

public interface IGenericDao<T extends BaseModel, ID extends Serializable> {
    /**
     * 添加新实体
     */
    void save(T t);

    /**
     * 批量添加新实体
     */
    void batchSave(List<T> list);

    /**
     * 删除实体(软册除status=2)
     */
    void delete(ID id);

    /**
     * 批量删除实体(软删除status=2)
     */
    void batchDelete(List<ID> list);

    /**
     * 修改实体
     */
    void update(T t);

    /**
     * 通过ID获取实体
     */
    T get(ID id);

    /**
     * <p>
     * 带分页的查询列表,与分页相关的语句需要自己编写,mybatis将不会干扰。
     * </p>
     */
    PaginatedArrayList<T> listByLimit(T t);

    /**
     * <p>
     * 不带分页的列表查询。
     * </p>
     */
    List<T> list(T t);

    /**
     * 通过id列表获取实体列表
     */
    List<T> getbyIdList(@Param("ids") List<ID> list);

    /**
     * 根据条件查记录数
     */
    int count(T t);
}

 这样具体业务实体的DAO接口直接继承IGenericDAO即可,当然也可以添加其他的方法,比如根据用户角色查询用户列表:

public interface IUserDAO extends IGenericDao<User, Integer> {
    /**
     * 根据角色获取所有用户
     */
    List<User> getUserByRoleId(Integer roleId);
}

 通用的Service接口与DAO接口基本一样,下面代码是通用Service接口的抽象实现类:

public abstract class AbstractGenericService<T extends BaseModel, ID extends Serializable> implements
        GenericService<T, ID> {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractGenericService.class);

    @SuppressWarnings("unchecked")
    private Class<T> getTClass() {
        return ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }

    @Resource
    protected GenericCacheManager cacheManager;


    @Resource
    private TaskExecutor taskExecutor;

    public abstract IGenericDao<T, ID> getDao();

    @Override
    public void save(T t) {

        if (t == null) {
            LOG.info("待插入的实体为null,class:{}", this.getTClass().getName());
            return;
        }

        this.getDao().save(t);
    }

    @Override
    public void saveOrUpdate(T t) {
        if (t == null) {
            return;
        }

        if (t.getId() == null) {
            this.save(t);
        } else {
            this.update(t);
        }
    }

    /**
     * 删除实体(软册除status=2)
     *
     * @param id
     * @throws Exception
     */
    @Override
    @Transactional
    public void delete(ID id) {

        if (id == null) {
            return;
        }

        this.getDao().delete(id);
        this.cacheManager.remove(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(id));
    }

    /**
     * 批量删除实体
     */
    @Override
    @Transactional
    public void batchDelete(List<ID> list) {

        if (list == null || list.size() <= 0) {
            return;
        }

        this.getDao().batchDelete(list);

        // 从缓存中删除id所管理的实体
        for (ID id : list) {
            this.cacheManager.remove(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(id));
        }
    }

    /**
     * 修改实体
     */
    @Override
    @Transactional
    public void update(T t) {
        if (t == null) {
            LOG.info("待更新的实体为null,class:{}", this.getTClass().getName());
            return;
        }

        // TODO 此处应该填充上修改时间,但是需要BaseModel中有modifytime字段,且子类都继承该字段

        this.getDao().update(t);

        // 从缓存中删除实体,实体会在get的时候再次填入到缓存中
        this.cacheManager.remove(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(t.getId()));
    }

    /**
     * 通过ID获取实体
     */
    @Override
    @SuppressWarnings("unchecked")
    public T get(ID id) {

        if (id == null) {
            return null;
        }

        // 从缓存中读取实体
        T t = (T) this.cacheManager.get(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(id));

        if (t != null) {
            return t;
        }

        // 未从缓存中读取到则从数据库中读取实体
        t = this.getDao().get(id);

        if (t != null) {
            this.cacheManager.put(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(t.getId()), t);
        }

        return t;
    }

    @Override
    public T getDetail(ID id) {
        T t = this.get(id);

        if (t == null) {
            return null;
        }

        this.fillDetail(t);
        return t;
    }

    /**
     * <p>
     * 带分页的列表查询。
     * </p>
     */
    @Override
    public PaginatedList<T> listByLimit(T t) {

        if (t == null) {
            return new PaginatedArrayList<T>(0, 0, 0);
        }

        // 查询数据库中记录的总数
        int total = this.getDao().count(t);

        // 构造带有分页信息的List
        PaginatedList<T> resultList = new PaginatedArrayList<T>(total, t.getPage(), t.getPageSize());
        t.setStartPos(resultList.getStartPos());

        List<T> queryResultList = this.getDao().listByLimit(t);
        resultList.addAll(queryResultList);

        return resultList;
    }

    @Override
    public PaginatedList<T> listDetailByLimit(T t) {
        PaginatedList<T> resultList = this.listByLimit(t);
        for (T item : resultList) {
            this.fillDetail(item);
        }
        return resultList;
    }

    /**
     * <p>
     * 不带分页的列表查询。
     * </p>
     */
    @Override
    public List<T> list(T t) {
        return this.getDao().list(t);
    }

    @Override
    public List<T> listDetail(T t) {
        List<T> resultList = this.list(t);
        for (T item : resultList) {
            this.fillDetail(item);
        }
        return resultList;
    }

    /**
     * 通过id列表获取实体列表
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<T> getbyIdList(List<ID> list) {

        if (list == null || list.size() <= 0) {
            return Collections.EMPTY_LIST;
        }

        List<T> resultList = new ArrayList<T>();
        List<ID> missedIds = new ArrayList<ID>();

        // 先从缓存中读取实体
        T t;
        for (ID id : list) {
            if (id == null) {
                continue;
            }

            // 根据id从缓存中读取实体信息
            t = (T) this.cacheManager.get(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(id));

            if (t != null) {
                resultList.add(t);
            } else {
                missedIds.add(id); // 未从缓存中读取到实体,则将该实体的id放入到missedIds列表中,稍后从数据库中读取这些实体
            }
        }

        // 如果有些实体未从缓存中取到
        if (missedIds.size() > 0) {

            // 则从数据库中读取这些实体
            List<T> missedModels = this.getDao().getbyIdList(missedIds);

            // 如果数据库中有,则添加到缓存中,然后返回
            if (missedModels != null) {
                for (T model : missedModels) {
                    this.cacheManager.put(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(model.getId()), model);
                }
                resultList.addAll(missedModels);
            }
        }
        return resultList;
    }

    /**
     * 根据条件查记录数
     */
    @Override
    public int count(T t) {
        return this.getDao().count(t);
    }

    /**
     * <p>
     * 生成cache中该实体的key。 key生成的规则为: 实体短类名 + ":" + 实体id.
     * 例如:id为123的代理商信息的实体在缓存中的key即为:Agent:123 . 子类可以覆盖该方法以生成特殊的key。
     * </p>
     */
    protected String makeCacheKey(Object id) {
        return CacheKeyHelper.getEntityCacheKey(this.getTClass(), id);
    }

    /**
     * 填充引用信息,抽象类中默认不做任何操作,如需填充引用信息,在子类中覆盖此方法
    protected void fillDetail(T t) {
    }

    @Override
    public <M extends BaseModel> void fillListDetailByMultiThread(List<M> list,
            final FillDetailable<M> fillDetailable) {
        if (!CollectionUtils.isEmpty(list)) {
            Integer size = list.size();
            final CountDownLatch latch = new CountDownLatch(size);
            for (final M u : list) {
                taskExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            fillDetailable.fillDetail(u);
                        } finally {
                            latch.countDown();
                        }
                    }
                });
            }
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
                LOG.error(e.getMessage());
            }
        }
    }
}

 这样使用了缓存,可以是如Ehcache等JVM缓存,也可以使用Memcached等分布式缓存,由于会有一些联表查询,实体Bean中会有一些冗余字段,使用fillDetail()方法来进行相应设置。为了提高效率,使用多线程的方式对列表中的实体对象进行fillDetail操作,因此需要FillDetailable接口:

public interface FillDetailable<T extends BaseModel> {
    void fillDetail(T t);
}

 具体的Service实现是需要继承AbstractGenericService即可:

@Service("userService")
public class UserServiceImpl extends AbstractGenericService<User, Integer> implements IUserService {
    protected static final Logger LOG = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    protected IUserDAO userDAO;

    @Override
    public void fillDetail(User user) {
        UserDepartment filter = new UserDepartment();
        filter.setUserId(user.getId());
        List<UserDepartment> userDepartmentList = userDepartmentService.list(filter);
        final List<Integer> deptIds = new ArrayList<Integer>();
        final List<Integer> deptLevels = new ArrayList<Integer>();
        final List<String> deptNames = new ArrayList<String>();

        this.fillListDetailByMultiThread(userDepartmentList, new FillDetailable<UserDepartment>() {
            @Override
            public void fillDetail(UserDepartment userDepartment) {
                Department department = departmentSerive.get(userDepartment.getDepartmentId());
                if (department != null) {
                    userDepartment.setDepartmentName(department.getName());
                    deptIds.add(userDepartment.getDepartmentId());
                    deptLevels.add(userDepartment.getIndeptlevel());
                    deptNames.add(department.getName());
                }
            }
        });
        user.setDeptIds(deptIds);
        user.setDeptLevels(deptLevels);
        user.setDeptNames(deptNames);
        user.setUserDepartmentList(userDepartmentList);
        List<Role> roles = roleService.getUserRoles(user.getId());
        if (roles != null) {
            user.setRoles(roles);
        }
    }

    @Override
    public IGenericDao<User, Integer> getDao() {
        return userDAO;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Mybatis-Plus是一个基于Mybatis的增强工具,提供了许多实用的功能,如自动生成代码、分页查询、条件构造器、性能分析等。Mybatis-Plus ServiceMybatis-Plus的一个模块,提供了一些常用的Service接口和实现类,如IServiceServiceImpl等,方便开发者快速构建Service。 ### 回答2: Mybatis-Plus是一个开源的、能够和Mybatis无缝衔接并扩展出更多实用功能的框架。在实际项目开发中,通常会使用到基于Mybatis-Plus的Service,以下是关于Mybatis-Plus Service的一些介绍。 Mybatis-Plus的Service是基于Mybatis-Plus框架进行封装的,旨在简化开发者编写Service代码的流程。使用Mybatis-Plus Service可以有效地减少重复代码的编写,提高开发效率。 在Mybatis-Plus Service中,通常包含了一些常见的CRUD方法,如查询列表、根据ID查询、插入、更新和删除等。我们可以通过继承BaseService或者IService来使用这些方法。同时,Mybatis-Plus Service还提供了一些强大的查询构建器,如LambdaQueryWrapper和QueryWrapper等,可以快速构建复杂的查询条件。 另外,Mybatis-Plus Service还支持事务管理。它提供了一种@Transactional注解来实现声明式事务,我们只需在Service的方法上添加该注解,即可完成事务的配置。 除了基本的CRUD操作和事务管理外,Mybatis-Plus Service还具有其他扩展的功能,例如分页查询、批量操作、逻辑删除等。这些功能都能够极大地简化开发者的编码工作。 总而言之,Mybatis-Plus Service是一种基于Mybatis-Plus框架的封装,用于简化Service代码的编写。它提供了一系列的CRUD方法、事务管理以及其他实用功能,可以提高开发效率并减少冗余代码的编写。使用Mybatis-Plus Service,开发者能够更加专注于业务逻辑的实现,提高开发效率和代码质量。 ### 回答3: MyBatis-Plus是一个在MyBatis基础上的增强工具,提供了更加便捷的CRUD操作方式。其中的ServiceMyBatis-Plus提供的一封装,主要用于处理业务逻辑和数据库操作之间的关系。 MyBatis-Plus的Service主要有以下几个功能: 1. 提供通用的CRUD方法:Service提供了常见的增删改查方法,如save、remove、update等,可以直接调用这些方法来操作数据库,无需手写SQL语句。 2. 封装条件构造器:Service的方法中可以使用MyBatis-Plus提供的条件构造器来进行查询条件的组装,例如可以使用eq、like、in等方法来构建查询条件。 3. 支持分页查询:Service提供了分页查询的方法,可以方便地进行数据分页查询操作。可以设置每页的数量、当前页码等参数来实现分页效果。 4. 支持事务控制:Service可以通过注解的方式来对方法添加事务控制,保证在业务逻辑中的多个操作要么全部成功,要么全部失败。可以使用@Transactional注解来标记需要进行事务控制的方法。 总的来说,MyBatis-Plus的Service提供了一种更加便捷的数据库操作方式,简化了开发过程中的数据库操作代码,提高了开发效率。同时,它还具备一些高级功能,如条件构造器、分页查询和事务控制,使得开发者可以更加灵活和方便地进行业务逻辑的处理和数据库操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值