業務程式碼:基於spring的銀行支付介面模型實現
1.業務邏輯
當用戶選擇某一特定商品後,點選支付按鈕;跳轉到對應的支付頁面,在使用者選擇對應的支付銀行方式後,在頁面實現對應的優惠資訊。同時點選支付後,根據銀行對應的報文要求,進行支付。
2.邏輯分析
3.技術點:
工廠模式,反射,spring手動注入,面向物件思想
3.支付介面
//支付介面
public interface Strategy {
public BigDecimal calRecharge(Integer goodsId , Integer channelId);}
4.實現類1
@Pay(channelId=1)
public class CCBBankServiceImpl implements Strategy {@Override
public BigDecimal calRecharge(Integer goodsId, Integer channelId) {
IAnniversaryService anniversaryDao = (IAnniversaryService) InjectionByHandUtil.getBean(IAnniversaryService.class);
String num = anniversaryDao.selectUserNameByLoginName("ssss");
BigDecimal goodPrice = new BigDecimal(10000);//商品價格
BigDecimal discount = new BigDecimal(0.1);//銀行折扣資訊
return goodPrice.multiply(discount);//返回真實價格
}}
5.實現類2
@Pay(channelId=2)
public class ICBCBankServiceImpl implements Strategy {
@Override
public BigDecimal calRecharge(Integer goodsId, Integer channelId) {
BigDecimal goodPrice = new BigDecimal(10000);//商品價格
BigDecimal discount = new BigDecimal(0.99);//銀行折扣資訊
return goodPrice.multiply(discount);//返回真實價格
}
}
6.pay註解:用於表明該實現類和具體銀行處理方式之間的關係
@Target(ElementType.TYPE)//位置:註解在類檔案中生效
@Retention(RetentionPolicy.RUNTIME)//宣告週期:
/*RetentionPolicy.SOURCE:註解只保留在原始檔,當Java檔案編譯成class檔案的時候,註解被遺棄;
RetentionPolicy.CLASS:註解被保留到class檔案,但jvm載入class檔案時候被遺棄,這是預設的生命週期;
RetentionPolicy.RUNTIME:註解不僅被儲存到class檔案中,jvm載入class檔案之後,仍然存在;*/
public @interface Pay {//定義一個註解,用於標識對應的具體銀行的實現類
int channelId();
}
7.工廠類:通過反射的方式,在載入時,自動配置支付通道id和對應支付方式之間的關係
//工廠模式用於建立具體的銀行實現類
public class StrageFactory {
private static StrageFactory factory = new StrageFactory();//餓漢式不存線上程安全問題;懶漢式-雙重鎖檢查機制處理
private StrageFactory() {}//私有構造方法
public static StrageFactory getInstance(){return factory;}
private static Map<Integer,String> bankMap = new HashMap<Integer,String>();
static{
//bankMap.put(1, "com.lx.pay.ICBCBankServiceImpl");//擴充套件性差
Reflections reflection = new Reflections("com.lx.pay.service.impl");//使用Reflections工具類掃描對應包下的註解
Set<Class<?>> classSet = reflection.getTypesAnnotatedWith(Pay.class);//獲取在類檔案頭部的pay註解
for(Class<?> c : classSet){//便利有Pay註解的class檔案
Pay pay = (Pay)c.getAnnotation(Pay.class);//獲取該包下的有Pay註解的class檔案中的Pay註解資訊
bankMap.put(pay.channelId(), c.getCanonicalName());//該class檔案中定義的註解channelId值
}
}
public Strategy create(Integer channelId) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
Class clazz = Class.forName(bankMap.get(channelId));
return (Strategy)clazz.newInstance();
}
}
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
8.支付模組對外介面,供外部呼叫
public class PayContext {//支付模組對外提供的介面,供外部呼叫
public BigDecimal calRecharge(Integer goodsId , Integer channelId) throws Exception{
StrageFactory factory = StrageFactory.getInstance();
Strategy strategy = factory.create(channelId);
return strategy.calRecharge(goodsId, channelId);
}
}
9.工具類,用於注入已new方式生成的物件的spring例項物件
public class InjectionByHandUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
public static Object getBean(Class c){
return applicationContext.getBean(c);
}
}
<!--Spring中bean獲取的工具類-->
<bean id="injectionByHandUtil" class="com.wpao.shop.util.InjectionByHandUtil" />
10.外部呼叫
@Controller
public class PayTestController {Logger logger = Logger.getLogger(this.getClass());
/*@Resource
private PayContext context;*/
@RequestMapping("/pay")
public String anniversary() throws Exception {
PayContext context = new PayContext();
BigDecimal res = context.calRecharge(1, 1);
System.out.println("***:"+res);
return "user/workshow";
}
}