首先抽象实体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; } }
相关推荐
通用DAO的概念就是基于MyBatis,创建一个可复用的DAO接口和实现类,来处理基本的CRUD(Create、Read、Update、Delete)操作。 首先,我们来看一下通用DAO的简单实现。通常,我们会定义一个基类,如`BaseMapper<T>`...
Mybatis通用Mapper插件是一个基于Mybatis的增强工具,旨在简化数据库操作,提高开发效率。它通过提供通用的CRUD操作接口,减少了手动编写SQL语句的工作量,同时保留了Mybatis的原生特性。 主要功能模块 代码生成...
总的来说,"springboot+mybatis通用注解"项目利用SpringBoot的自动化配置和MyBatis的注解功能,实现了数据库操作的便捷化和代码的复用。通过继承基类,开发者可以快速创建具备完整CRUD功能的服务,显著提高了开发...
MyBatis通用Mapper是基于MyBatis的扩展,它为常见的数据库操作提供了预定义的Mapper接口。这些接口包括了对单表的基本操作,如插入、查询、更新、删除等。通过实现这些接口,开发者可以快速地完成数据访问层的编写...
(5)【Service/ServiceImpl层】带注释的Service和ServiceImpl实现层 4、工具提供生成节点和方式 (1)PowerfulObject主要生成节点:(Controller层、entity实体层、Service/ServiceImpl、Mybatis、mybatisXML) ...
MyBatis通用Mapper是一个基于MyBatis框架的扩展工具,它极大地简化了针对单一表的操作,使得开发人员无需编写繁琐的XML映射文件和接口定义就能实现数据层的增删改查等基本功能。其优势在于简化了开发流程,降低了...
在本项目"springboot-web-jsp01:mybatis通用servicev.1.0"中,我们关注的是基于Spring Boot的Web应用与MyBatis框架的集成,特别是关于通用Service层的设计。这个版本的通用Service是为了减少开发时的重复工作,针对...
在本课程中,我们将深入探讨如何在Spring Cloud项目中整合MyBatis通用Mapper,以便实现高效、便捷的数据访问。Spring Cloud作为一个微服务架构的集合,提供了丰富的工具和服务,帮助开发者构建分布式系统。而MyBatis...
* 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 * 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询...
综上所述,这个项目展示了如何在Spring Boot应用中有效地集成MyBatis,利用通用Mapper简化数据访问层的开发,以及通过PageHelper实现高效分页。这样的集成方案对于快速构建企业级Web应用具有很高的参考价值。
这个系统基于Spring Boot框架,结合了Model-View-Controller(MVC)的设计模式,MyBatis作为持久层框架,通用Mapper简化SQL操作,Druid作为数据源管理工具,以及Bootstrap用于前端界面的美化。以下是对这些技术的...
MyBatis Plus提供了一套基于MyBatis的自动化工具,减少了开发者手动编写SQL和DAO层代码的工作量。它包含了丰富的 CRUD 操作,支持自定义全局通用操作,如分页、条件查询等。MyBatis Plus的核心功能包括自动填充公共...
总的来说,"springboot+mybatis逆向生成controller+service+mapper+entity"是一种高效开发策略,它结合了Spring Boot的便捷性、MyBatis的灵活性以及Swagger的交互性,旨在帮助开发者快速构建基于RESTful的Web服务,...
Mybatis-plus是一个基于Mybatis和Spring的轻量级框架,主要目标是简化对数据库的常规操作,例如增、删、改、查(CRUD),它提供了更为方便的API,使得开发者能够更高效地进行数据库操作。这个框架在Mybatis的基础上...
MyBatis BaseDAO 是一种基于 MyBatis 框架的工具类库,它旨在简化数据库操作,通过封装常见的CRUD(Create、Read、Update、Delete)方法,为开发者提供便利,减少重复代码,提高开发效率。在Java Web 开发中,...
MyBatis是一个基于Java的持久层框架,它简化了对JDBC的直接操作,通过XML或注解的方式将SQL与Java代码绑定,避免了手动设置参数以及获取结果集的烦恼。MyBatis的核心组件包括SqlSessionFactory、SqlSession和Mapper...
本项目是基于Mybatis进行DAO(Data Access Object)层的CRUD(Create、Read、Update、Delete)操作的源码实现,结合了Spring框架,便于管理和集成事务。 在Mybatis中,CRUD操作主要通过Mapper接口和对应的XML配置...
9. **编写Service层**:实现业务逻辑,使用@Autowired注解注入Mapper接口,调用其方法完成数据库操作。 10. **编写Controller层**:处理HTTP请求,调用Service层的方法,将结果返回给前端。 11. **创建视图**:编写...
在项目中引入 `通用Mapper`,这是一个基于 `MyBatis` 的插件,可以自动生成 CRUD 操作,大大减少了为每个表编写 XML 映射文件和对应的 Service 层代码的工作。通用Mapper提供了丰富的API,使得开发人员能够快速实现...
【标题】"spring boot+mybatis+pagehelp分布+通用mapper"揭示了这是一个基于Spring Boot、MyBatis、PageHelper和通用Mapper构建的后端权限管理系统。这些技术栈的组合旨在提供高效、易于维护的数据库操作和分页功能...