`
liuluo129
  • 浏览: 115895 次
  • 性别: 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
分享到:
评论

相关推荐

    mybatis 通用DAO 简单实现

    通用DAO的概念就是基于MyBatis,创建一个可复用的DAO接口和实现类,来处理基本的CRUD(Create、Read、Update、Delete)操作。 首先,我们来看一下通用DAO的简单实现。通常,我们会定义一个基类,如`BaseMapper&lt;T&gt;`...

    基于Java的Mybatis通用Mapper插件.zip

    Mybatis通用Mapper插件是一个基于Mybatis的增强工具,旨在简化数据库操作,提高开发效率。它通过提供通用的CRUD操作接口,减少了手动编写SQL语句的工作量,同时保留了Mybatis的原生特性。 主要功能模块 代码生成...

    springboot+mybatis通用注解

    总的来说,"springboot+mybatis通用注解"项目利用SpringBoot的自动化配置和MyBatis的注解功能,实现了数据库操作的便捷化和代码的复用。通过继承基类,开发者可以快速创建具备完整CRUD功能的服务,显著提高了开发...

    mybatis通用mapper

    MyBatis通用Mapper是基于MyBatis的扩展,它为常见的数据库操作提供了预定义的Mapper接口。这些接口包括了对单表的基本操作,如插入、查询、更新、删除等。通过实现这些接口,开发者可以快速地完成数据访问层的编写...

    PowerfulObject全自动基于Mybatis生成Java代码工具.rar

    (5)【Service/ServiceImpl层】带注释的Service和ServiceImpl实现层 4、工具提供生成节点和方式 (1)PowerfulObject主要生成节点:(Controller层、entity实体层、Service/ServiceImpl、Mybatis、mybatisXML) ...

    mybatis 通用mapper

    MyBatis通用Mapper是一个基于MyBatis框架的扩展工具,它极大地简化了针对单一表的操作,使得开发人员无需编写繁琐的XML映射文件和接口定义就能实现数据层的增删改查等基本功能。其优势在于简化了开发流程,降低了...

    springboot-web-jsp01:mybatis通用servicev.1.0

    在本项目"springboot-web-jsp01:mybatis通用servicev.1.0"中,我们关注的是基于Spring Boot的Web应用与MyBatis框架的集成,特别是关于通用Service层的设计。这个版本的通用Service是为了减少开发时的重复工作,针对...

    SpringBoot集成MyBatis-Plus实现国产数据库适配.docx

    * 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 * 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询...

    (代码)SpringCloud第03讲:整合MyBatis通用Mapper

    在本课程中,我们将深入探讨如何在Spring Cloud项目中整合MyBatis通用Mapper,以便实现高效、便捷的数据访问。Spring Cloud作为一个微服务架构的集合,提供了丰富的工具和服务,帮助开发者构建分布式系统。而MyBatis...

    MyBatis基于Spring-boot集成通用Mapper以及pagehelper分页插件

    综上所述,这个项目展示了如何在Spring Boot应用中有效地集成MyBatis,利用通用Mapper简化数据访问层的开发,以及通过PageHelper实现高效分页。这样的集成方案对于快速构建企业级Web应用具有很高的参考价值。

    整合springboot+mvc+mybatis(通用mapper)+druid+jsp+bootstrap实现权限管理文件上传下载

    这个系统基于Spring Boot框架,结合了Model-View-Controller(MVC)的设计模式,MyBatis作为持久层框架,通用Mapper简化SQL操作,Druid作为数据源管理工具,以及Bootstrap用于前端界面的美化。以下是对这些技术的...

    mybatis_plus_demo自动生成实体类,mapper,service,controller

    MyBatis Plus提供了一套基于MyBatis的自动化工具,减少了开发者手动编写SQL和DAO层代码的工作量。它包含了丰富的 CRUD 操作,支持自定义全局通用操作,如分页、条件查询等。MyBatis Plus的核心功能包括自动填充公共...

    springboot+mybatis逆向生成controller+service+mapper+entity

    总的来说,"springboot+mybatis逆向生成controller+service+mapper+entity"是一种高效开发策略,它结合了Spring Boot的便捷性、MyBatis的灵活性以及Swagger的交互性,旨在帮助开发者快速构建基于RESTful的Web服务,...

    mybatis basedao

    MyBatis BaseDAO 是一种基于 MyBatis 框架的工具类库,它旨在简化数据库操作,通过封装常见的CRUD(Create、Read、Update、Delete)方法,为开发者提供便利,减少重复代码,提高开发效率。在Java Web 开发中,...

    通用mybatis-MySQL增删改查CRUD源码

    MyBatis是一个基于Java的持久层框架,它简化了对JDBC的直接操作,通过XML或注解的方式将SQL与Java代码绑定,避免了手动设置参数以及获取结果集的烦恼。MyBatis的核心组件包括SqlSessionFactory、SqlSession和Mapper...

    mybatis基于Dao的crud操作源码

    本项目是基于Mybatis进行DAO(Data Access Object)层的CRUD(Create、Read、Update、Delete)操作的源码实现,结合了Spring框架,便于管理和集成事务。 在Mybatis中,CRUD操作主要通过Mapper接口和对应的XML配置...

    maven、spring、spring mvc、mybatis 整合实现ssm通用增删改查基础开发框架

    9. **编写Service层**:实现业务逻辑,使用@Autowired注解注入Mapper接口,调用其方法完成数据库操作。 10. **编写Controller层**:处理HTTP请求,调用Service层的方法,将结果返回给前端。 11. **创建视图**:编写...

    spring boot+mybatis+pagehelp分布+通用mapper

    【标题】"spring boot+mybatis+pagehelp分布+通用mapper"揭示了这是一个基于Spring Boot、MyBatis、PageHelper和通用Mapper构建的后端权限管理系统。这些技术栈的组合旨在提供高效、易于维护的数据库操作和分页功能...

    基于 spring,spring mvc,mybatis 权限管理系统

    【标题】:“基于Spring,Spring MVC,MyBatis权限管理系统”是一个使用Java技术栈实现的权限管理解决方案。这个系统利用了Spring框架的核心功能,Spring MVC的MVC设计模式,以及MyBatis作为持久层框架,旨在提供...

    数据库框架Mybatis-plus,实现java代码对数据库的增删改查

    Mybatis-plus是一个基于Mybatis和Spring的轻量级框架,主要目标是简化对数据库的常规操作,例如增、删、改、查(CRUD),它提供了更为方便的API,使得开发者能够更高效地进行数据库操作。这个框架在Mybatis的基础上...

Global site tag (gtag.js) - Google Analytics