开发完短信平台,开始做一个汇聚平台。现在开始大量使用设计模式来做了,其实也就是那些比较常用的。设计模式,用的合适的话,对扩展性和维护,带来了很大的便利。
短信平台使用模板方法和观察者模式,现在汇聚平台简单使用一个工厂模式,之前做了一个生产者消费者,但是发现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中的数据。不再详细描述。
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");
}
}
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;
}
}
字符串转对象的时候,需要自建几个对象,去接收这些数据。不再详述。