該平台面向三類用戶:下家(合作商),上家(代理商),平台管理員。該平台提供給下家的功能包括:合作商入駐、充值價格查詢、充值接口,充值結果查詢、對賬接口等。平台可以接入多個上家,根據每個上家充值接口的服務質量,充值時動態切換上家,目前暫時只接入一個上家。平台還提供了手機號碼歸屬地查詢接口,可以自動切換該接口的多個實現,以實現該接口的高可用。手機話費空中充值的流程如下:用戶在下家網站上輸入手機號碼和充值面值,下家調用平台的充值價格查詢接口,用戶確認價格並支付成功之后,調用平台的充值接口。平台提供了充值結果異步通知接口。下家與平台之間的通訊協議是使用https,平台與上家之間的通訊協議是使用TCP。使用netty封裝了平台與上家之間的通訊,可以自定義協議和很好的解決TCP的拆包,粘包等問題,因為使用l了TCP的keepalive。所以會使用心跳維持這個連接。每次調用上家充值接口,會傳遞一個不重復的有規則的序列號,序列號的生成使用了MySQLMaxValueIncrementer,如下配置所示:
<bean id="messageSequence" class="org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer">
<property name="incrementerName" value="t_message_sequence"/> <!-- 設置維護主鍵的表名 -->
<property name="columnName" value="sequence_val"/><!-- 用於生成主鍵值的列名 -->
<!--<property name="cacheSize" value="10"/>緩存大小 -->
<property name="dataSource" ref="dataSource"/>
</bean>
平台與該上家進行合作時,平台需支付預存款。所以調用上家的充值接口時,需保證賬戶余額大於0,而每次調用上家的充值接口時,會實時更新該余額,為了高性能的進行該操作,使用了樂觀鎖。
同時為了實現調用上家接口的代碼的復用和可擴展性,大量使用了泛型:
public abstract class Message<T1 extends Head,T2 extends Body> { /**報文起始標識**/ public final static byte startFlag[] ={0x55,0x55,0x55,0x55}; /**報文結束標識**/ public final static short endFlag[] ={0xFE,0xFE,0xFE,0xFE}; /**報文頭**/ protected T1 head; /**報文體**/ protected T2 body; public T1 getHead() { return head; } public T2 getBody(){ return body; } void setBody(T2 body) { this.body = body; } /**獲取報文消息內容**/ public String getMessageContent(){ return head.getHeadContent()+body.getBodyContent(); } public String getMessageContentJson(){ return head.getHeadContentJson()+body.getBodyContentJson(); } }
性能方面可以優化的地方:上面的序列號生成和賬戶余額的更新功能,可以使用redis來做。不過對於當前的情況,上面兩種方案已經足夠滿足了 。
因為下家是使用同步方式調用平台的充值接口,而平台調用上家的充值接口是使用異步的方式,這樣就存在將異步轉同步的問題。有多種實現方案,這里就不多說了,留給大家思考。