与上游系统常有数据对接的需求,对接的接口在入参 返回值 数据处理逻辑上常有一定的规律性,使用模板方法 可以减少样本代码 提高代码效率
这里给出一个示例
同步上游系统的账号 组织(业务方请求接口)
抽象类
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
public abstract class AbstractSync<T,K extends ServiceImpl<? extends BaseMapper<T>,T>> {
@Value("${xxx}")
private String appId;
@Value("${xxx}")
private String appSecret;
abstract protected void sync();
abstract protected String getReqUrl();
abstract protected String getCallbackUrl();
abstract protected String getReqFailedMsg();
abstract protected String getCallbackFailedMsg();
abstract protected Class<T> entityClass();
abstract protected K getBaseService();
abstract protected Function<T,Date> sortFunc();
abstract protected SFunction<T,String> bizIdFunc();
abstract protected Function<T,String> callbackIdFunc();
public void doSync() {
JSONArray dataJsonArray = new JSONArray();
this.getReqData(dataJsonArray,1,100,
LocalDateTime.now().plusMinutes(-30).toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
List<T> tList = dataJsonArray.toJavaList(this.entityClass());
tList.sort(Comparator.comparing(this.sortFunc()));
K baseService = this.getBaseService();
tList.forEach(t -> {
T existedT = baseService.lambdaQuery()
.eq(this.bizIdFunc(), this.bizIdFunc().apply(t))
.one();
if(Objects.nonNull(existedT)){
baseService.lambdaUpdate()
.eq(this.bizIdFunc(),this.bizIdFunc().apply(t))
.update(t);
}else{
baseService.save(t);
}
});
this.callback(tList,this.callbackIdFunc());
}
public void callback(List<T> tList, Function<T,String> func){
if(CollectionUtil.isNotEmpty(tList)){
String ids = tList.stream()
.map(func).collect(Collectors.joining(","));
JSONObject reqParamsJson = new JSONObject();
reqParamsJson.put("ids",ids);
String response = this.doReq(reqParamsJson,this.getCallbackUrl());
String code = JSONObject.parseObject(response)
.getString("code");
if(!"0".equals(code)){
throw new RuntimeException(this.getCallbackFailedMsg());
}
}
}
public JSONArray getReqData(JSONArray dataJsonArray, Integer page, Integer pageSize, Long startTime){
String response = this.request(page,pageSize,startTime);
JSONObject resultJson = JSONObject.parseObject(response);
JSONObject dataJson = resultJson.getJSONObject("data");
String code = resultJson.getString("code");
JSONArray data = dataJson.getJSONArray("list");
if(!"0".equals(code)){
throw new RuntimeException(this.getReqFailedMsg());
}
if(!data.isEmpty()){
dataJsonArray.addAll(data);
}
if(data.size() >= pageSize){
getReqData(dataJsonArray,++page,pageSize,startTime);
}
return dataJsonArray;
}
public String request(Integer page,Integer size,Long startTime){
JSONObject reqParamsJson = new JSONObject();
reqParamsJson.put("page",page.toString());
reqParamsJson.put("size",size.toString());
reqParamsJson.put("startTime",startTime.toString());
return this.doReq(reqParamsJson,this.getReqUrl());
}
private String doReq(JSONObject reqParamsJson,String url){
return HttpUtil.createPost(url)
.header("Authorization","Bearer "+ generateToken())
.header(Header.CONTENT_TYPE, ContentType.JSON.toString())
.body(reqParamsJson.toString())
.execute().body();
}
private String generateToken(){
return JWT.create()
.withIssuer(appId)
.withIssuedAt(new Date())
.withJWTId(UUID.randomUUID().toString())
.sign(Algorithm.HMAC256(appSecret));
}
}
账号同步子类
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
import java.util.function.Function;
@Service
@Slf4j
public class SyncAccountService extends AbstractSync<SyncAccount,SyncAccountBaseService> {
@Resource
private SyncAccountBaseService syncAccountBaseService;
@Value("${xxx}")
private String reqUrl;
@Value("${xxx}")
private String callbackUrl;
@Override
protected String getReqUrl() {
return reqUrl;
}
@Override
protected String getCallbackUrl() {
return callbackUrl;
}
@Override
protected String getReqFailedMsg() {
return "调用账号同步-回调接口失败,请查看";
}
@Override
protected String getCallbackFailedMsg() {
return "调用账号同步接口失败,请查看";
}
@Override
protected Class<SyncAccount> entityClass() {
return SyncAccount.class;
}
@Override
protected SyncAccountBaseService getBaseService() {
return syncAccountBaseService;
}
@Override
protected Function<SyncAccount, Date> sortFunc() {
return SyncAccount::getRequestLogCreateTime;
}
@Override
protected SFunction<SyncAccount, String> bizIdFunc() {
return SyncAccount::getAppAccountId;
}
@Override
protected Function<SyncAccount, String> callbackIdFunc() {
return SyncAccount::getRequestLogId;
}
@Override
@Transactional
@Scheduled(cron = "0 */30 * * * ?")
public void sync() {
this.doSync();
}
}
组织同步子类
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
import java.util.function.Function;
@Service
@Slf4j
public class SyncOrgService extends AbstractSync<SyncOrg,SyncOrgBaseService> {
@Resource
private SyncOrgBaseService syncOrgBaseService;
@Value("xxx")
String reqUrl;
@Value("xxx")
String callbackUrl;
@Override
public String getReqUrl() {
return reqUrl;
}
@Override
public String getCallbackUrl() {
return callbackUrl;
}
@Override
public String getReqFailedMsg() {
return "调用组织同步-回调接口失败,请查看";
}
@Override
public String getCallbackFailedMsg() {
return "调用组织同步接口失败,请查看";
}
@Override
protected Class<SyncOrg> entityClass() {
return SyncOrg.class;
}
@Override
protected SyncOrgBaseService getBaseService() {
return syncOrgBaseService;
}
@Override
protected Function<SyncOrg, Date> sortFunc() {
return SyncOrg::getRequestLogCreateTime;
}
@Override
protected SFunction<SyncOrg, String> bizIdFunc() {
return SyncOrg::getIdtOrgId;
}
@Override
protected Function<SyncOrg, String> callbackIdFunc() {
return SyncOrg::getRequestLogId;
}
@Override
@Transactional
@Scheduled(cron = "0 */30 * * * ?")
public void sync() {
this.doSync();
}
}
模板方法还有一个典型运用场景 AQS(抽象队列同步器)