基于Mybatis的通用Service层实现
程序员文章站
2022-05-17 19:37:07
...
首先抽象实体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; } }
上一篇: 常用的设计模式
下一篇: 设计模式——模板模式(Template)
推荐阅读
-
C#基于DBContext(EF)实现通用增删改查的REST方法实例
-
asp.net基于Web Service实现远程上传图片的方法
-
基于Mybatis plus 自动代码生成器的实现代码
-
基于C#实现的三层架构实例
-
C#基于DBContext(EF)实现通用增删改查的REST方法实例
-
基于Mybatis plus 自动代码生成器的实现代码
-
基于Java实现的一层简单人工神经网络算法示例
-
golang实现基于channel的通用连接池详解
-
Springboot集成通用Mapper与Pagehelper,实现mybatis+Druid的多数据源配置
-
在基于Spring架构的通用查询系统中用DWR实现查询条件的动态显示