背景
開發完短信平台,開始做一個匯聚平台。現在開始大量使用設計模式來做了,其實也就是那些比較常用的。設計模式,用的合適的話,對擴展性和維護,帶來了很大的便利。
短信平台使用模板方法和觀察者模式,現在匯聚平台簡單使用一個工廠模式,之前做了一個生產者消費者,但是發現queue有點問題,還是舍棄了。
既然是總結,還是多記錄些代碼。
接口
匯聚平台做數據服務,最主要的是數據接口。這里,做的時候是模仿支付寶的支付接口。
接口處,采用工廠模式,方便擴展,不同的服務根據服務名稱進行區分。
主入口的類,只是對數據進行一些校驗,並不是做業務邏輯。
//參數驗證通過,驗證接口服務
if (!valiService(service)){
return getRespCode(ErrorCode.SERVICE_ERR,key);
}
//接口服務通過,驗證接入商
Access access = getAccess(commuCode);
if (access == null){
return getRespCode(ErrorCode.VALIDATE_ERR,key);
}
key = access.getAccessKey();
//驗證簽名
if (!valiSign(data,key)){
return getRespCode(ErrorCode.SIGN_ERR,key);
}
//處理業務邏輯
String result ;
try {
result = doBusi(service,data);
} catch (ParamException e) {
return getRespCode(ErrorCode.PARAM_ERR,key);
} catch (SystemException e1){
return getRespCode(ErrorCode.SYS_ERR,key);
}
logger.info("Cost Time:" + (System.currentTimeMillis() - a));
//流量數據不需要返回具體的業務數據,對外服務需要返回特定的數據
return "".equals(result) ? getRespCode(ErrorCode.SUCCESS,key) : result;
這里定義了兩個自定義的異常,分別由處理業務的時候拋出來。這里的業務采用工廠方式,根據不同的服務來產生。
private String doBusi(String service,String data) throws ParamException, SystemException {
//處理不同業務
setServiceMap(serviceMap);
Business business = ServiceFactory.produce(service);
return business.doProcess(serviceMap,data);
}
所有業務實現業務接口就可以:
public interface Business {
//返回處理數據
String doProcess(Map<String,BaseService> services,String data) throws ParamException, SystemException;
}
然后配一個簡單的工廠類:
public class ServiceFactory {
private static Logger logger = Logger.getLogger(ServiceFactory.class);
public static Business produce(String type){
if (Services.FLOW_DATA.key.equals(type)){
return new FlowDataProcess();
}
else if (Services.PARK_AROUND.key.equals(type)){
return new ParkAroundProcess();
}
else if (Services.PARK_ALL.key.equals(type)){
return new ParkAllProcess();
}
else {
logger.error("Error Type When DoProcess in Factory");
return null;
}
}
}
這樣就將業務的耦合性降低了很多。
數據格式
對外服務的接口,數據格式都有一定的約束。所以,就寫了一個工具包,將字符串數據轉換為相應的對象,或者將對象轉為字符串。不只是為自己使用,也為客戶端提供。使用泛型寫一個,比較通用。
這個時候,規定兩個接口Encoder和Decoder 。
其中,有涉及到多個數據,使用list來存放,具體放的類型,也要有上界規定。這樣容易統一list中的數據。不再詳細描述。
1,數據進行格式化,將對象轉換為字符串
public class DataEncoder<T, V> implements Encoder<T, V> {
private StringBuilder dataEncode(T o, String pattern) throws IllegalAccessException {
StringBuilder sb = new StringBuilder();
Field[] fields = o.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (field.get(o) == null) {
sb.append("");
} else if ("java.util.Date".equals(field.getType().getName())) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
sb.append(sdf.format(field.get(o)));
} else {
sb.append(field.get(o));
}
sb.append(pattern);
}
//sb.deleteCharAt(sb.lastIndexOf(pattern));
return sb;
}
public String requestEncode(V o,String k) throws IllegalAccessException {
StringBuilder sb = new StringBuilder();
Field[] fields = o.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (field.get(o) == null) {
sb.append("");
} else if ("java.util.List".equals(field.getType().getName())) {
StringBuilder sb2 = new StringBuilder();
List<T> obj = (List) field.get(o);
for (T o1 : obj) {
StringBuilder stringBuilder = dataEncode(o1,"|");
stringBuilder.deleteCharAt(stringBuilder.lastIndexOf("|"));
//sb2.append(dataEncode(o1, "|").toString());
sb2.append(stringBuilder.toString());
sb2.append(";");
}
sb2.deleteCharAt(sb2.lastIndexOf(";"));
sb.append(sb2.toString());
} else {
sb.append(field.get(o));
}
sb.append("&");
}
System.out.println("Pre data:"+sb.toString());
if (!"".equals(k) && k != null){
signSb(sb,k);
}
//sb.deleteCharAt(sb.lastIndexOf("&"));
return sb.toString();
}
public String responseEncode(T t,String k) throws IllegalAccessException {
StringBuilder sb = dataEncode(t, "&");
if (!"".equals(k) && k != null){
signSb(sb,k);
}
return sb.toString();
}
//為字符串增加簽名
private void signSb(StringBuilder data,String k){
String s = data.toString();
String sign = MD5.sign(s, k, "utf-8");
data.append(sign);
}
//參數為string的簽名
public String sign(String s,String k){
return MD5.sign(s+"&key="+k,k,"utf-8");
}
}
2,數據轉換,將字符串數據解析,轉換為對象
public class DataDecoder implements Decoder {
public MsgDecoder deReq(String data) throws NoSuchFieldException, IllegalAccessException {
MsgDecoder decoder = new MsgDecoder();
String[] outer = data.split("&");
decoder.setServiceName(outer[0]);
decoder.setCommuCode(outer[1]);
List<MsgData> inner = new ArrayList<MsgData>();
String datas = outer[2];
String[] inners = datas.split(";");
for (String s : inners) {
MsgData msgData = new MsgData();
String[] sa = s.split("\\|");
for (int i = 0; i < sa.length; i++) {
Field field = msgData.getClass().getDeclaredField("arg" + i);
field.setAccessible(true);
field.set(msgData, sa[i]);
}
inner.add(msgData);
}
decoder.setDatas(inner);
decoder.setSign(outer[3]);
return decoder;
}
public RespDecoder deResp(String data) {
RespDecoder decoder = new RespDecoder();
String[] strings = data.split("&");
decoder.setCode(Integer.parseInt(strings[0]));
decoder.setDesc(strings[1]);
//異常數據中,第三個字段會為空
if (strings.length >2){
decoder.setSign(strings[2]);
}
return decoder;
}
}
字符串轉對象的時候,需要自建幾個對象,去接收這些數據。不再詳述。