`
liuluo129
  • 浏览: 114975 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

基于Mybatis的通用Service层实现

    博客分类:
  • java
阅读更多

首先抽象实体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;
    }
}

 

1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics