如何利用泛型封裝通用的service層
身為一名開發(fā)人員,大家都知道,我們經(jīng)常會在項(xiàng)目中大量的編寫許多重復(fù)的代碼,比如說
public Entity find(String id);
像這種代碼,簡單,但是寫多了,可能也會容易出錯,那么我們能不能直接編寫一套完整的,通用的方法呢,這樣既不用重復(fù)編寫,還不用出錯,說道通用的方法,泛型是個不錯的選擇.
基礎(chǔ)架構(gòu):spring-boot+spring mvc+spring jpa.
jpa是個好東西,個人感覺它最大的好處是不需要自己手動建表.還能在修改了表字段以后,自動給你添加上上去,它不像mybatis,業(yè)務(wù)改了之后,還需要調(diào)整sql語句,
好了,廢話不多說,上代碼:
一、首先建立一個實(shí)體類WebVisitRecordEntity
繼承BaseEntity.BaseEntity在項(xiàng)目里面,是所有實(shí)體類的最頂層.里面是封裝了一些通用的屬性.
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: 所有實(shí)體的父類
* @Date: Created in 17:03 2018/5/15
*/
@MappedSuperclass
public abstract class BaseEntity implements Serializable{
/**
* id
*/
@Id
@Column(length = 32 )
private String id;
/**
* 創(chuàng)建時間
*/
private Date createTime;
/**
* 創(chuàng)建人
*/
@Column(length = 32 )
private String createUser;
/**
* 更新時間
*/
private Date updateTime;
/**
* 更新人
*/
@Column(length = 32 )
private String updateUser;
/**
* 刪除標(biāo)記 --系統(tǒng)只做邏輯刪除
*/
@Column(length = 8 )
private String delStatus = StatusEnum.FALSE.getStatus();
/**
* 啟用標(biāo)記 --默認(rèn)已啟用
*/
@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;
/**
* 訪問次數(shù)
*/
private int count = 0;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}二、有了實(shí)體類之后
首先建立一個頂層的api接口。所有通用的api方法,可以放在這里(ResultBean是一個封裝了一個結(jié)果的數(shù)據(jù)類,里面包含了定義執(zhí)行是否成功,執(zhí)行返回的數(shù)據(jù),執(zhí)行錯誤提示的消息)
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);
/**
* 創(chuàng)建
* @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);
}三、實(shí)現(xiàn)BaseApi
既然是要定義通用的api,那么不僅僅只是一套接口,我們需要在定義一個可以實(shí)現(xiàn)BaseApi的BaseServiceImpl,之后的所有實(shí)現(xiàn)類,都可以繼承這個BaseServiceImpl.java的泛型,給了我們的項(xiàng)目很好的擴(kuò)展性,而頂層BaseEntity也給了我很好的實(shí)現(xiàn)方案,將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("數(shù)據(jù)為空,無法創(chuàng)建!");
}
if(this.exists(entity.getId())){
return ResultBean.failfure("實(shí)體id相同,無法重復(fù)創(chuàng)建!");
}
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("數(shù)據(jù)為空,無法創(chuàng)建!");
}
if(!this.exists(entity.getId())){
return ResultBean.failfure("數(shù)據(jù)庫不存在該數(shù)據(jù),無法執(zhí)行更新");
}
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,定義實(shí)現(xiàn)類,繼承BaseServiceImpl.并實(shí)現(xiàn)自己的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 {
}五、測試
到這里,代碼已經(jīng)結(jié)束. 測試一下,構(gòu)建下controller層. 并進(jìn)行測試
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("參數(shù)不得為空");
}
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("參數(shù)不得為空");
}
WebVisitRecordEntity entity = this.webVisitRecordService.find(id);
if(ObjectUtil.isNull(entity)){
return this.errorWithMsg("不存在該數(shù)據(jù)");
}
entity.setUpdateTime(new Date());
entity.setCount(entity.getCount()+num);
ResultBean<WebVisitRecordEntity> result = this.webVisitRecordService.update(entity);
return this.result(result.getDate(),result.getMsg());
}
}
三次測試都已經(jīng)成功,但是我們真實(shí)的項(xiàng)目不可能這么簡單.所以我們再次測試下擴(kuò)展性
等等,不知道你們發(fā)現(xiàn)沒有,上面的代碼有一段是錯誤的.
我在controller層的屬性不是api,而是實(shí)現(xiàn)類.......
雖然不影響,但是就無法擴(kuò)展了...此處做修正

六、擴(kuò)展性
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> {
/**
* 統(tǒng)計(jì)所有的記錄之和
* @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(),"執(zhí)行成功");
}4.測試

七、總結(jié)
emmmm.....其實(shí)我上面還有個小錯誤,就留給你們尋找吧
其實(shí),封裝的這個service層,也有很大的局限性,比如說,如果我需要自定義dao層的方法,怎么辦?需要執(zhí)行sql語句怎么辦,仔細(xì)想想,我們能不能再封裝一個BaseRepository呢?然后作為BaseServiceImpl中的屬性傳入??????
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java多線程join()方法的作用和實(shí)現(xiàn)原理解析(應(yīng)用場景)
join方法主要是用于將當(dāng)前線程掛起,等待其他線程結(jié)束后在執(zhí)行當(dāng)前線程,本文通過應(yīng)用場景分析代碼示例講解java多線程join()方法的作用和實(shí)現(xiàn)原理,感興趣的朋友一起看看吧2021-07-07
關(guān)于ThreadLocal對request和response的用法說明
這篇文章主要介紹了關(guān)于ThreadLocal對request和response的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
詳解如何使用tldb數(shù)據(jù)庫的java客戶端
這篇文章主要為大家介紹了如何使用tldb數(shù)據(jù)庫的java客戶端過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Mybatis的parameterType造成線程阻塞問題分析
這篇文章主要詳細(xì)分析了Mybatis的parameterType造成線程阻塞問題,文中有詳細(xì)的解決方法,及相關(guān)的代碼示例,具有一定的參考價值,感興趣的朋友可以借鑒閱讀2023-06-06

