如何利用泛型封装通用的service层

目录
  • 一、首先建立一个实体类WebVisitRecordEntity
  • 二、有了实体类之后
  • 三、实现BaseApi
  • 四、定义类自己的api
  • 五、测试
  • 六、扩展性
  • 七、总结

身为一名开发人员,大家都知道,我们经常会在项目中大量的编写许多重复的代码,比如说

public Entity find(String id);

像这种代码,简单,但是写多了,可能也会容易出错,那么我们能不能直接编写一套完整的,通用的方法呢,这样既不用重复编写,还不用出错,说道通用的方法,泛型是个不错的选择.

基础架构:spring-boot+spring mvc+spring jpa.

jpa是个好东西,个人感觉它最大的好处是不需要自己手动建表.还能在修改了表字段以后,自动给你添加上上去,它不像mybatis,业务改了之后,还需要调整sql语句,

好了,废话不多说,上代码:

一、首先建立一个实体类WebVisitRecordEntity

继承BaseEntity.BaseEntity在项目里面,是所有实体类的最顶层.里面是封装了一些通用的属性.

1.BaseEntity

package cn.yxw.function;
import cn.yxw.function.Enum.status.StatusEnum;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.util.Date;

/**
 * @Author : yuanxw
 * @Description: 所有实体的父类
 * @Date: Created in 17:03 2018/5/15
 */
@MappedSuperclass
public abstract class BaseEntity implements Serializable{

    /**
     * id
     */
    @Id
    @Column(length = 32 )
    private String id;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 创建人
     */
    @Column(length = 32 )
    private String createUser;

    /**
     * 更新时间
     */
    private Date updateTime;

    /**
     * 更新人
     */
    @Column(length = 32 )
    private String updateUser;

    /**
     * 删除标记 --系统只做逻辑删除
     */
    @Column(length = 8 )
    private String delStatus = StatusEnum.FALSE.getStatus();

    /**
     * 启用标记 --默认已启用
     */
    @Column(length = 8 )
    private String enAbleStatus = StatusEnum.TRUE.getStatus();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getCreateUser() {
        return createUser;
    }

    public void setCreateUser(String createUser) {
        this.createUser = createUser;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public String getUpdateUser() {
        return updateUser;
    }

    public void setUpdateUser(String updateUser) {
        this.updateUser = updateUser;
    }

    public String getDelStatus() {
        return delStatus;
    }

    public void setDelStatus(String delStatus) {
        this.delStatus = delStatus;
    }

    public String getEnAbleStatus() {
        return enAbleStatus;
    }

    public void setEnAbleStatus(String enAbleStatus) {
        this.enAbleStatus = enAbleStatus;
    }
}

2.WebVisitRecordEntity

package cn.yxw.function.domain.plugins;
import cn.yxw.function.BaseEntity;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

/**
 * @Author : yuanxw
 * @Description:
 * @Date: Created in 15:16 2018/6/20
 */
@Entity()
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Table(name = "web_visit_Record")
public class WebVisitRecordEntity extends BaseEntity {

    private static final long serialVersionUID = 341666498307329777L;
    /**
     * 访问次数
     */
    private int count = 0;

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

二、有了实体类之后

首先建立一个顶层的api接口。所有通用的api方法,可以放在这里(ResultBean是一个封装了一个结果的数据类,里面包含了定义执行是否成功,执行返回的数据,执行错误提示的消息)

package cn.yxw.function;
import cn.yxw.function.result.ResultBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

/**
 * @Author : yuanxw
 * @Description:
 * @Date: Created in 10:32 2018/5/25
 */
public interface BaseApi<T extends BaseEntity> {

    /**
     * 查询
     * @param id
     * @return
     */
    T get(String id);

    /**
     * 查询
     * @param id
     * @return
     */
    T find(String id);

    /**
     * 删除
     * @param id
     * @return
     */
    ResultBean<T> delete(String id);

    ResultBean<T> delete(T entity);

    /**
     * 创建
     * @param entity
     * @return
     */
    ResultBean<T> create(T entity);

    /**
     * 更新
     * @param entity
     * @return
     */
    ResultBean<T> update(T entity);

    /**
     * 读取所有
     * @param pageable
     * @return
     */
    Page<T> page(Pageable pageable);

    /**
     * 判断id是否存在
     * @param id
     * @return
     */
    boolean exists(String id);

}

三、实现BaseApi

既然是要定义通用的api,那么不仅仅只是一套接口,我们需要在定义一个可以实现BaseApi的BaseServiceImpl,之后的所有实现类,都可以继承这个BaseServiceImpl.java的泛型,给了我们的项目很好的扩展性,而顶层BaseEntity也给了我很好的实现方案,将BaseEntity作为泛型的入口

1.基本时限BaseApi

package cn.yxw.function.service.impl.domain.userCenter;
import cn.yxw.function.BaseApi;
import cn.yxw.function.BaseEntity;
import cn.yxw.function.result.ResultBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; 

/**
 * @Author : yuanxw
 * @Description:
 * @Date: Created in 14:31 2018/6/20
 */
public class BaseServiceImpl<T extends BaseEntity> implements BaseApi<T> { 

    @Override
    public T get(String id) {
        return null;
    }

    @Override
    public T find(String id) {
        return null;
    }

    @Override
    public ResultBean<T> delete(String id) {
        return null;
    }

    @Override
    public ResultBean<T> delete(T entity) {
        return null;
    }

    @Override
    public ResultBean<T> create(T entity) {
        return null;
    }

    @Override
    public ResultBean<T> update(T entity) {
        return null;
    }

    @Override
    public Page<T> page(Pageable pageable) {
        return null;
    }

    @Override
    public boolean exists(String id) {
        return false;
    }
}

2.使用jpa作为BaseServiceImpl的属性.

package cn.yxw.function.service.impl.domain.userCenter;
import cn.yxw.function.BaseApi;
import cn.yxw.function.BaseEntity;
import cn.yxw.function.Enum.code.ServiceCodeEnum;
import cn.yxw.function.result.ResultBean;
import cn.yxw.function.util.ObjectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @Author : yuanxw
 * @Description:
 * @Date: Created in 14:31 2018/6/20
 */
public class BaseServiceImpl<T extends BaseEntity> implements BaseApi<T> {

    @Autowired
    private JpaRepository<T, String> baseRepository;

    @Override
    public T get(String id) {
        T entity =  this.baseRepository.getOne(id);
        return entity;
    }

    @Override
    public T find(String id) {
        return this.baseRepository.findById(id).get();
    }

    @Override
    public ResultBean<T> delete(String id) {
        this.baseRepository.deleteById(id);
        return ResultBean.success("");
    }

    @Override
    public ResultBean<T> delete(T entity) {
        this.baseRepository.delete(entity);
        return ResultBean.success(entity);
    }

    @Override
    public ResultBean<T> create(T entity) {
        if(ObjectUtil.isNull(entity)){
            return ResultBean.failfure("数据为空,无法创建!");
        }
        if(this.exists(entity.getId())){
            return ResultBean.failfure("实体id相同,无法重复创建!");
        }
        entity = this.baseRepository.saveAndFlush(entity);
        if(ObjectUtil.isNull(entity)){
            return ResultBean.failfure(ServiceCodeEnum.CORE_SYSTEM_FAILURE);
        }
        return ResultBean.success(entity);
    }

    @Override
    public ResultBean<T> update(T entity) {
        if(ObjectUtil.isNull(entity)){
            return ResultBean.failfure("数据为空,无法创建!");
        }
        if(!this.exists(entity.getId())){
            return ResultBean.failfure("数据库不存在该数据,无法执行更新");
        }
        entity = this.baseRepository.saveAndFlush(entity);
        if(ObjectUtil.isNull(entity)){
            return ResultBean.failfure(ServiceCodeEnum.CORE_SYSTEM_FAILURE);
        }
        return ResultBean.success(entity);
    }

    @Override
    public Page<T> page(Pageable pageable) {
        return null;
    }

    @Override
    public boolean exists(String id) {
        return this.baseRepository.existsById(id);
    }
}

四、定义类自己的api

继承BaseApi,定义实现类,继承BaseServiceImpl.并实现自己的api

package cn.yxw.function.domain.userCenter;
import cn.yxw.function.BaseApi;
import cn.yxw.function.domain.plugins.WebVisitRecordEntity;

/**
 * @Author : yuanxw
 * @Description:
 * @Date: Created in 14:44 2018/6/22
 */
public interface WebVisitRecordApi extends BaseApi<WebVisitRecordEntity> {
}
package cn.yxw.function.service.impl.domain.userCenter;
import cn.yxw.function.domain.plugins.WebVisitRecordEntity;
import cn.yxw.function.domain.userCenter.WebVisitRecordApi;
import org.springframework.stereotype.Service;

/**
 * @Author : yuanxw
 * @Description:
 * @Date: Created in 15:22 2018/6/20
 */
@Service
public class WebVisitRecordServiceImpl extends BaseServiceImpl<WebVisitRecordEntity> implements WebVisitRecordApi {
}

五、测试

到这里,代码已经结束. 测试一下,构建下controller层. 并进行测试

package cn.yxw.function.controller.System.admin;
import cn.yxw.function.controller.BaseController;
import cn.yxw.function.domain.plugins.WebVisitRecordEntity;
import cn.yxw.function.result.ResultBean;
import cn.yxw.function.service.impl.domain.userCenter.WebVisitRecordServiceImpl;
import cn.yxw.function.util.ObjectUtil;
import com.alibaba.druid.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.Map;

/**
 * @Author : yuanxw
 * @Description:
 * @Date: Created in 15:23 2018/6/20
 */
@RestController()
@RequestMapping(value = "web/record")
public class WebVisitRecordsController extends BaseController {

    @Autowired
    private WebVisitRecordServiceImpl webVisitRecordService; 

    @GetMapping(value = "/get")
    public Map get(String id){
        if(StringUtils.isEmpty(id)){
            return this.errorWithMsg("参数不得为空");
        }
        WebVisitRecordEntity entity = this.webVisitRecordService.find(id);
        return this.result(entity,"");
    }

    @PostMapping(value = "/create")
    public Map create(int num){
        WebVisitRecordEntity entity = new WebVisitRecordEntity();
        entity.setId(System.currentTimeMillis()+"");
        entity.setCreateTime(new Date());
        entity.setCount(num);
        ResultBean<WebVisitRecordEntity> result = this.webVisitRecordService.create(entity);
        return this.result(result.getDate(),result.getMsg());
    } 

    @PostMapping(value = "/update")
    public Map update(String id, int num){
        if(StringUtils.isEmpty(id)){
            return this.errorWithMsg("参数不得为空");
        }
        WebVisitRecordEntity entity = this.webVisitRecordService.find(id);
        if(ObjectUtil.isNull(entity)){
            return this.errorWithMsg("不存在该数据");
        }
        entity.setUpdateTime(new Date());
        entity.setCount(entity.getCount()+num);
        ResultBean<WebVisitRecordEntity> result = this.webVisitRecordService.update(entity);
        return this.result(result.getDate(),result.getMsg());
    }
}

三次测试都已经成功,但是我们真实的项目不可能这么简单.所以我们再次测试下扩展性

等等,不知道你们发现没有,上面的代码有一段是错误的.

我在controller层的属性不是api,而是实现类.......

虽然不影响,但是就无法扩展了...此处做修正

六、扩展性

1. WebVisitRecordApi

package cn.yxw.function.domain.userCenter;
import cn.yxw.function.BaseApi;
import cn.yxw.function.domain.plugins.WebVisitRecordEntity;

/**
 * @Author : yuanxw
 * @Description:
 * @Date: Created in 14:44 2018/6/22
 */
public interface WebVisitRecordApi extends BaseApi<WebVisitRecordEntity> {

    /**
     * 统计所有的记录之和
     * @return
     */
    int countAll();
}

2. WebVisitRecordServiceImpl

package cn.yxw.function.service.impl.domain.userCenter;

import cn.yxw.function.domain.plugins.WebVisitRecordEntity;
import cn.yxw.function.domain.userCenter.WebVisitRecordApi;
import cn.yxw.function.util.ObjectUtil;
import org.springframework.stereotype.Service;
import java.util.List;

/**
 * @Author : yuanxw
 * @Description:
 * @Date: Created in 15:22 2018/6/20
 */
@Service
public class WebVisitRecordServiceImpl extends BaseServiceImpl<WebVisitRecordEntity> implements WebVisitRecordApi { 

    @Override
    public int countAll() {
        List<WebVisitRecordEntity> list = super.baseRepository.findAll();
        int count = 0;
        if(ObjectUtil.isNull(list) || list.size() <= 0){
            return count;
        }
        for (WebVisitRecordEntity entity : list){
            count += entity.getCount();
        }
        return count;
    }
}

3. WebVisitRecordController

    @GetMapping(value = "count")
    public Map count(){
        return this.result(this.webVisitRecordService.countAll(),"执行成功");
    }

4.测试

七、总结

emmmm.....其实我上面还有个小错误,就留给你们寻找吧

其实,封装的这个service层,也有很大的局限性,比如说,如果我需要自定义dao层的方法,怎么办?需要执行sql语句怎么办,仔细想想,我们能不能再封装一个BaseRepository呢?然后作为BaseServiceImpl中的属性传入??????

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Mybatis-Plus实体类注解方法与mapper层和service层的CRUD方法

    目录 1 注解 1.1 @TableName 1.2 @TableId 1.3 @TableField 1.4 @TableLogic 2 mapper层的CRUD方法 2.1 增(insert) 2.2 删(delete) 2.3 改(update) 2.4 查(select) 3 service层的CRUD方法 3.1 批量添加或者更新 3.2 查询表中总记录数 1 注解 1.1 @TableName   之前在入门案例中我们分析过:使用mp底层方法生成的SQL语句中,表名为mapper或者

  • Mybatis-Plus接口BaseMapper与Services使用详解

    最近在工作开发中遇到一个批量新增修改的处理,我使用的是 mybatis-plus,但是在用的 BaseMapper 接口里是没有这个方法的,后来发现 Service 接口里有这个方法,今天整理一下这2种用法. 一.使用 BaseMapper 接口 MyBatis Plus 提供了通用的 Mapper 接口(即 BaseMapper 接口),该接口对应我们的 DAO 层.在该接口中,定义了我们常见的方法签名,这样就可以方便我们对表进行操作.例如:查询(select).插入(insert).更新(u

  • 详解关于mybatis-plus中Service和Mapper的分析

    在后端开发过程中,如果有用到mybatis-plus,肯定会发现在其内部存在着两种数据库操作接口,Iservice和BaseMapper,如果只是用增删改查会发现两者的功能是一致的,除了方法名称有所不同,其他的基本相似.对此,我颇为好奇,便打开两个接口的源码进行对比. 先演示一下基本开发中的继承关系,手动创建的Service继承于ServiceImpl,并加载自己创建的Mapper @Service public class RestDeptService extends ServiceImpl

  • 如何利用泛型封装通用的service层

    目录 一.首先建立一个实体类WebVisitRecordEntity 二.有了实体类之后 三.实现BaseApi 四.定义类自己的api 五.测试 六.扩展性 七.总结 身为一名开发人员,大家都知道,我们经常会在项目中大量的编写许多重复的代码,比如说 public Entity find(String id); 像这种代码,简单,但是写多了,可能也会容易出错,那么我们能不能直接编写一套完整的,通用的方法呢,这样既不用重复编写,还不用出错,说道通用的方法,泛型是个不错的选择. 基础架构:sprin

  • 详解Python如何利用pymysql封装项目通用的连接和查询

    目录 前言 pymysql 介绍与安装 pymysql 的使用 封装项目通用的连接和查询 结语 前言 一个项目通常都需要有数据库,而对于python这门语言,除了一些框架自带orm或者扩展的orm(像django自带orm,flask则需要扩展的orm),使用orm必然有他的好处,但毫无疑问你要花时间学习这个orm,那么接下来阿牛带你们用pymysql简单分装一个通用的连接,关闭和查询! pymysql 介绍与安装 PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一

  • 如何让CI框架支持service层

    大家知道CodeIgniter框架式MVC分层的,通常大家把业务逻辑写到Controller中,而Model只负责和数据库打交道. 但是随着业务越来越复杂,controller越来越臃肿,举一个简单的例子,比如说用户下订单,这必然会有一系列的操作:更新购物车.添加订单记录.会员添加积分等等,且下订单的过程可能在多种场景出现,如果这样的代码放controller中则很臃肿难以复用,如果放model会让持久层和业务层耦合.现在公司的项目就是,很多人将一些业务逻辑写到model中去了,model中又调

  • springmvc 中dao层和service层的区别说明

    springmvc dao层和service层的区别 首先解释面上意思,service是业务层,dao是数据访问层 这个问题我曾经也有过,记得以前刚学编程的时候,都是在service里直接调用dao,service里面就new一个dao类对象,调用,其他有意义的事没做,也不明白有这个有什么用,参加工作久了以后就会知道,业务才是工作中的重中之重. 我们都知道,标准主流现在的编程方式都是采用MVC综合设计模式,MVC本身不属于设计模式的一种,它描述的是一种结构,最终目的达到解耦,解耦说的意思是你更改

  • 关于MVC的dao层、service层和controller层详解

    目录 MVC的dao层.service层和controller层 1.dao层 2.service层 3.controller层 4.view层 5.它们之间的关系 关于dao层/mapper层的一些笔记 1.BaseMapper 2.@mapper MVC的dao层.service层和controller层 1.dao层 dao层主要做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,dao层的设计首先是设计dao层的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可以

  • spring配置不扫描service层的原因解答

    目录 spring配置自动扫描原理介绍 自动扫描组件的使用 细节问题总结 spring配置不扫描service层原因 我将contoller给springmvc进行扫描,然后其余所有交给spring扫描 然后发现service层的EmployeeService并没有扫描到出现以下问题 Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘spr

  • TypeScript利用TS封装Axios实战

    目录 简介 Axios几个常用类型 AxiosRequestConfig AxiosInstance AxiosStatic AxiosResponse AxiosError 基础封装 拦截器封装 常用方法封装 总结 简介 这是TypeScript实战的第三篇文章.前面两篇笔者分别介绍了在Vuex和Pinia中怎么使用TypeScript以及Vuex和Pinia的区别.今天我们再用TypeScript封装一遍Axios.希望能进一步巩固TypeScript的基础知识. Axios几个常用类型 在

  • Java 中利用泛型和反射机制抽象DAO的实例

    Java 中利用泛型和反射机制抽象DAO的实例 一般的DAO都有CRUD操作,在每个实体DAO接口中重复定义这些方法,不如提供一个通用的DAO接口,具体的实体DAO可以扩展这个通用DAO以提供特殊的操作,从而将DAO抽象到另一层次,令代码质量有很好的提升 1.通用接口 import java.io.Serializable; import java.util.List; public interface BaseDao<T> { T get(Serializable id); List<

  • SpringBoot在自定义类中调用service层等Spring其他层操作

    背景: 做了一个TCP服务器来接入智能设备,然后需要将设备实时发送的定位等关键信息存储到数据库. 为了考虑将来可能对外提供rest接口,采用将TCP服务器集成到SpringBoot框架,当然,也是为了能最快利用mybatis框架实现数据访问,然后依次解决了如何启动,如何注销等各种问题,然后在TCP服务器消息处理时,需要写数据库,直接调用DAO层,编译报错. 改为调用Service层,编译正常,运行到调用的地方,报空指针异常,跟踪到异常位置,发现service为空,也就是按照之前controlle

随机推荐