如何利用泛型封装通用的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中的属性传入??????

以上为个人经验,希望能给大家一个参考,也希望大家多多支持易知道(ezd.cc)。

推荐阅读