基于Mybatis的通用Service层实现【未验证】

来源:互联网 发布:cf数据异常什么原因 编辑:程序博客网 时间:2024/05/16 07:42

文章来源:http://www.tuicool.com/articles/BJzQFf


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