首先抽象实体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; } }
相关推荐
(5)【Service/ServiceImpl层】带注释的Service和ServiceImpl实现层 4、工具提供生成节点和方式 (1)PowerfulObject主要生成节点:(Controller层、entity实体层、Service/ServiceImpl、Mybatis、mybatisXML) ...
内置分页插件:基于Mybatis物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通List查询 内置性能分析插件:可输出Sql语句以及其执行时间,建议开发测试时启用该功能,能有效解决慢查询 内置...
实现功能 实现角色分配功能 实现角色分配功能权限 实现角色数据权限设置 实现用户单独分配功能 实现用户单独分配功能权限 实现用户单独数据权限设置 数据同步功能,方便系统整合 后端部署 创建数据库git-xtp 导入 ...
基于java的高级知识, 对Mybatis+SpringBoot+Restful风格的增强其中MybatisPlus中常见的案例,通用Mapper通用Service,以及XML书写SQL语句进行增删改查常见操作
它简化了基于 MyBatis 框架进行持久层开发的过程,提供了许多增强功能,使得开发者能够更高效地编写数据库相关的代码。 MybatisPlus 提供的一些主要功能包括: 简化的 CRUD 操作:MybatisPlus 提供了一种简化的...
集成MyBatis、通用Mapper插件、PageHelper分页插件,实现单表业务零SQL 提供代码生成器根据表名生成的Model、Mapper、MapperXML、Service、ServiceImpl、Controller等基础代码,其中Controller模板默认提供POST和...
此项目基于springboot-dubbo-mybatis构架一个通用的开发 分布式框架 项目介绍 基于springboot+dubbo+Mybatis提供整套公共微服务服务模块:服务模块,控制层模块。 组织结构 springboot-dubbo-mybatis └──...
全面贴心,提供 Service 层的封装方便业务使用和理解 Mapper; 简单直观,提供 ActiveRecord 模式,结合 Spring Boot 自动配置直接上手用。 1.2 系统要求 MyBatis Mapper 要求 MyBatis 最低版本为 3.5.1,推荐使用...
Spring:业务层,管理service,dao,工具类对象;依赖注入来管理各层,面向切面编程管理事务,日志和权限 MyBatis:持久层;访问数据库;基于jdbc的框架,主要用来操作数据库,并且将业务实体和数据表联系起来 1、...
Spring:业务层,管理service,dao,工具类对象;依赖注入来管理各层,面向切面编程管理事务,日志和权限 MyBatis:持久层;访问数据库;基于jdbc的框架,主要用来操作数据库,并且将业务实体和数据表联系起来 1、...
Spring:业务层,管理service,dao,工具类对象;依赖注入来管理各层,面向切面编程管理事务,日志和权限 MyBatis:持久层;访问数据库;基于jdbc的框架,主要用来操作数据库,并且将业务实体和数据表联系起来 1、...
.MyBatis-Plus(简称 MP)是一...强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 支持 Lambda 形式调用:通过 Lambda 表达
实现了 BaseService 类对 Service 层进行抽象。通过拦截器实现了方法级粒度的鉴权,通过AOP实现了参数校验。 --------------------------- **演示**:[https://small.ડ.com/][1] 可自行注册账号,或使用后台查看...
技术选型后端技术技术名称版本官网Spring Boot应用框架2.3.2.RELEASEMyBatis持久层框架3.2.1MyBatis-Ext基于MyBatis的增强扩展1.6.5Maven项目构建管理4.0.0Apache Shiro安全框架1.6.0Logback日志组件1.1.3Hibernate ...
实现了 BaseService 类对 Service 层进行抽象。通过拦截器实现了方法级粒度的鉴权,通过AOP实现了参数校验。 演示: 可自行注册账号,或使用后台查看权限账号 demo 密码 demo (后台入口登陆后显示) 兄弟项目: 本...
SpringBoot 快速整合Mybatis(去XML化+通用Service) SpringBoot 快速整合SpringDataJPA (优雅篇) SpringBoot 快速开启事务(附常见坑点) 模板引擎 SpringBoot 添加对JSP的支持(附常见坑点) SpringBoot ...
MBOOG 是基于 实现的敏捷开发工具,释放开发中对于数据增、删、改、查所占用的时间,提高代码质量。解决原生工具中多种不足,是数据访问层快速开发、标准化开发的一大利器。 设计 MBOOG 包含两个模块。 ...
集成MyBatis、通用Mapper插件、PageHelper分页插件,实现单表业务零SQL 集成quartz任务调度动态管理,动态传参。 集成swagger-bootstrap-ui使文档管理界面更直观、易读。 加入参数校验统一处理
2.ENGINE层用作封装通用方法,包括安全,鉴权,工具,数据加密同步等操作。 3.FACADE层用于封装传输层与显示层数据,屏蔽掉ENGINE层对数据的复杂操作,提高安全性。 4.SERVICE层用于封装暴露给外部调用的服务接口...
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,...