JDK1.5出來后,Java開始支持泛型開發(fā)赘淮,通過將父類聲明為泛型,子類繼承父類睦霎,子類就能擁有父類的方法梢卸,而不需要再寫代碼。泛型開發(fā)能使我們的代碼開發(fā)提供了很大的簡便副女,簡化了我們的代碼蛤高。
在springboot項目中(其他項目也一樣),我們經(jīng)常要用到增刪改查接口,從controller/service/dao層戴陡,每一層都要寫增刪改查代碼塞绿,每一張數(shù)據(jù)表都要重復一遍增刪改查功能。雖然寫起來簡單恤批,但是作為程序員來講异吻,寫重復性的代碼就是在浪費時間,浪費生命喜庞。
程序員的主要精力應該放在如何實現(xiàn)業(yè)務上面诀浪。
下面我們來看下怎樣通過泛型開發(fā)來封裝代碼,簡化開發(fā)赋荆。
一笋妥、聲明泛型父類
泛型父類包括:controller/service/dao三層。
1窄潭、聲明泛型虛基類AbstractController,定義接口方法:
public abstract class AbstractController<T, K>{
/**
* 新增
* @param t
* @return
*/
public abstract RtnData insert(T t);
/**
* 修改
* @param t
* @return
*/
public abstract RtnData update(T t);
/**
* 刪除
* @param
* @return
*/
public abstract RtnData delete(K id);
/**
* 按主鍵查詢
* @param
* @return
*/
public abstract RtnData get(K Id);
/**
* 分頁查詢
* @return
*/
public abstract RtnData queryPageList(int pageSize, int pageIndex, Map<String,Object> params);
/**
* 多條件查詢
* @return
*/
public abstract RtnData queryList(Map<String,Object> params);
}
2酵颁、實現(xiàn)泛型父類BaseController嫉你,繼承 AbstractController
這里我們定義泛型父類BaseController,繼承并實現(xiàn)AbstractController方法躏惋,并且在BaseController中定義每個方法的RequestMapping幽污。這樣業(yè)務類直接繼承BaseController就可以使用默認實現(xiàn)好的增刪改查接口了。
public class BaseController<T, K> extends AbstractController<T, K> {
@Autowired
private IService<T, K> service;
@PostMapping("/insert")
@Override
public RtnData insert(@RequestBody T t) {
return RtnData.ok(service.insert(t));
}
@PostMapping("/update")
@Override
public RtnData update(@RequestBody T t) {
return RtnData.ok(service.update(t));
}
@GetMapping("/delete")
@Override
public RtnData delete(K id) {
return RtnData.ok(service.delete(id));
}
@GetMapping("/get")
@Override
public RtnData get(K id) {
return RtnData.ok(service.get(id));
}
@GetMapping("/page-list")
@Override
public RtnData queryPageList(@RequestParam(required = false, defaultValue = "20") int pageSize,
@RequestParam(required = false, defaultValue = "1") int pageIndex,
@RequestParam Map<String,Object> params) {
return RtnData.ok(service.queryPageList(pageSize, pageIndex, params));
}
@GetMapping("/list")
@Override
public RtnData queryList(@RequestParam Map<String, Object> params) {
return RtnData.ok(service.queryList(params));
}
}
BaseController注入了泛型IService簿姨,用于實現(xiàn)具體的業(yè)務操作
3距误、聲明泛型業(yè)務接口類IService
public interface IService<T,K>{
/**
* 新增
* @param t
* @return
*/
public Object insert(T t);
/**
* 修改
* @param t
* @return
*/
public Object update(T t);
/**
* 刪除
* @param
* @return
*/
public Object delete(K id);
/**
* 按主鍵查詢
* @param
* @return
*/
public T get(K id);
/**
* 分頁查詢
* @param pageSize
* @param pageIndex
* @param params
* @return
*/
Object queryPageList(int pageSize, int pageIndex, Map<String, Object> params);
/**
* 條件查詢
* @param params
* @return
*/
Object queryList(Map<String, Object> params);
}
4、定義泛型業(yè)務類BaseService扁位,實現(xiàn)IService類
BaseService實現(xiàn)IService接口中發(fā)方法准潭,編寫增刪改查操作默認業(yè)務實現(xiàn)。子類通過繼承BaseService就擁有它的方法域仇。
public class BaseService<T,K> implements IService<T,K> {
@Autowired
protected Mapper<T, K> mapper;
private Class<T> modelClass;//當前泛型的真實類型Class
public BaseService() {
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
modelClass = (Class<T>) pt.getActualTypeArguments()[0];
}
@Override
public Object insert(T t) {
return mapper.insert(t);
}
@Override
public Object update(T t) {
return mapper.updateByPrimaryKey(t);
}
@Override
public Object delete(K id) {
return mapper.deleteByPrimaryKey(id);
}
@Override
public T get(K id) {
return mapper.selectByPrimaryKey(id);
}
@Override
public Object queryPageList(int pageSize, int pageIndex, Map<String, Object> params) {
PageHelper.startPage(pageIndex, pageSize);
Page page = mapper.queryPageList(params);//Page本身是一個ArrayList對象刑然,轉(zhuǎn)換為json時不會保留分頁信息
PageInfo pageInfo = page.toPageInfo();//將page轉(zhuǎn)換成pageInfo會保存分頁信息返回
return new PageModel(pageInfo);
}
@Override
public Object queryList(Map<String, Object> params) {
return mapper.queryList(params);
}
}
這里最重要的兩行代碼:
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
modelClass = (Class<T>) pt.getActualTypeArguments()[0];
通過泛型反射,獲取子類中實際要操作的對象class暇务,通過class泼掠,service就知道要對哪個對象進行增刪改查操操作。
另外垦细,我們注入了dao層的泛型Mapper<T, K>择镇,通過Mybatis對數(shù)據(jù)庫進行增刪改查操作
5、聲明Dao層泛型Mapper
public interface Mapper<T, K> {
int deleteByPrimaryKey(K id);
int insert(T record);
int insertSelective(T record);
T selectByPrimaryKey(K id);
int updateByPrimaryKeySelective(T record);
int updateByPrimaryKey(T record);
/**
* 分頁查詢(由子類實現(xiàn))
* @param params
* @return
*/
Page queryPageList(Map<String, Object> params);
/**
* 多條件查詢(由子類實現(xiàn))
* @param params
* @return
*/
List<Map<String,Object>> queryList(Map<String, Object> params);
}
這里我們使用mybatis實現(xiàn)dao層的操作括改,這里的聲明的接口方法名稱與mybatis工具生成mapper.xml一致
到這里腻豌,我們的泛型父類代碼已經(jīng)全部編寫完成。可以將上述代碼達成jar包饲梭,放入項目里面作為基礎包直接引用乘盖。
下面我們來說說怎么在項目里面實際使用。
二憔涉、項目應用
在項目里面引用订框,只需在子類代碼層中繼承上述父類,子類就擁有父類中的功能兜叨。
1穿扳、子類Controller
@RestController
@RequestMapping("/api/dic")
public class DataDicController extends BaseController<DataDic, Integer> {
}
看到?jīng)],里面什么方法也沒寫国旷,只聲明了RequestMapping矛物,另外將泛型用具體對象類型替換。
DataDic是我操作的對象跪但,Integer是DataDic的主鍵類型履羞。
這個BaseController的新增接口地址是/api/dic/insert,/insert是使用父類的RequestMapping屡久。
另外我也沒寫Service的注入忆首,因為容器會根據(jù)要父類中要注入的泛型Service,直接找到IService對應的泛型實例
2被环、子類Service
@Service
public class DataDicService extends BaseService<DataDic, Integer> {
}
同樣糙及,Service也沒有任何代碼,也沒有注入Mapper筛欢,只繼承了泛型
3浸锨、子類Mapper
@Mapper
public interface DataDicMapper extends com.cc.app.base.dao.Mapper<DataDic, Integer> {
}
Mapper需要繼承我們自己定義的泛型Mapper,這樣才能被Service找到版姑。
說明:我們通過工具生成的Mapper對象會包含默認的方法柱搜,大家不用刪除,因為和繼承的Mapper方法名一致漠酿,就當是覆蓋Override
到此冯凹,所有工作結(jié)束,我們的DataDicController的增刪改查接口寫好 炒嘲,下面我們來測試宇姚。
三、接口測試
1夫凸、查詢接口get
2浑劳、插入接口insert