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";
}
}