直觀,先上代碼:
public interface:
public interface ChannelsPayService {
<T extends Serializable> T tradeCreate(TradeOrderDto order);
<R extends Serializable> NotifyHandleResultDto<R> notifyHandle(TradeOrderDto order, Map<String, String> params);
TradePaymentChannelsEntity getCurrentChannels();
}
public abstract class:
public abstract class AbsChannelsPayService implements ChannelsPayService {
protected Logger logger = LoggerFactory.getLogger(getClass());
private volatile PayChannel payType;
@Autowired
private PaymentChannelDao paymentChannelDao;
@Autowired
protected CommonMqInfoSender commonMqInfoSender;
@Override
public TradePaymentChannelsEntity getCurrentChannels() {
PayChannel payeChannelType = getOrderPayType();
TradePaymentChannelsEntity paymentChannels = paymentChannelDao.queryByChannelsCode(payeChannelType.name());
TipAssert.notNull(paymentChannels, "系統尚未配置該支付渠道:" + payeChannelType.name());
return paymentChannels;
}
/**
* 獲取key文件信息
*
* @param filePath
* @return
*/
public String readKeyFileContent(String filePath) {
TipAssert.hasLength(filePath, getOrderPayType() + "密鑰文件地址不能爲空");
try {
Path path = Paths.get(getClass().getResource("/").toURI()).resolve(filePath);
List<String> lines = Files.readAllLines(path);
StringBuilder stringBuilder = new StringBuilder();
if (lines != null) {
lines.forEach(i -> stringBuilder.append(i));
}
return stringBuilder.toString();
} catch (Exception e) {
logger.error("讀取文件失敗,filePath={}", filePath, e);
TipAssert.isTrue(false, "讀取支付渠道配置密鑰文件失敗,filePath" + filePath);
}
return null;
}
/**
* 獲取支付類型
*
* @return
*/
public PayChannel getOrderPayType() {
if (null == payType) {
synchronized (this) {
if (null == payType) {
Class<? extends AbsChannelsPayService> current = getClass();
ChannelsFlag channelsFlag = current.getAnnotation(ChannelsFlag.class);
TipAssert.isTrue(null != channelsFlag && null != channelsFlag.value(),
current.getSimpleName() + ",支付渠道未指定渠道標識");
payType = channelsFlag.value();
}
}
}
return payType;
}
}
@ChannelsFlag(PayChannel.ALI_PAY)
public class AliChannelsPayService extends AbsChannelsPayService implements InitializingBean {
private static final String ORDER_NOT_EXIST_CODE = "ACQ.TRADE_NOT_EXIST";// 訂單不存在
private static final String REFUND_NOT_ALLOW = "ACQ.TRADE_NOT_ALLOW_REFUND";// 不允許退款
private static final String ORDER_FINISHED = "ACQ.TRADE_HAS_FINISHED";// 訂單已完結
private static final String INVALID_PARAMETER = "ACQ.INVALID_PARAMETER"; // 參數非法
@Value("${payment.callback.notify.url}")
private String callbackNotifyUrl;
private AliPayConfig aliPayConfig;
@Override
public <T extends Serializable> T tradeCreate(TradeOrderDto order) {
AlipayClient alipayClient = build();
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
String billNo = order.getBillNo();
request.setNotifyUrl(
buildOrderNotifyUrl(order.getPayChannel().getValue(), billNo, aliPayConfig.getNotifyUrl()));
model.setSubject(order.getSubject());
String body = order.getBody();
if (StringUtils.isNotBlank(body)) {
model.setBody(body);
}
model.setOutTradeNo(billNo);
model.setTimeoutExpress(aliPayConfig.getTimeoutExpress());
model.setTotalAmount(order.getRealPayment().setScale(2, RoundingMode.HALF_UP) + "");
model.setProductCode(aliPayConfig.getProductCode());
request.setBizModel(model);
try {
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
logger.info("發起支付寶[創建交易]請求,serverUrl={},orderNo={},返回信息={}", aliPayConfig.getServerUrl(),
order.getOrderNo(), JsonUtils.toJson(response));
TipAssert.isTrue(response.isSuccess(), response.getMsg());
return (T) response.getBody();
} catch (Exception e) {
logger.error("發起支付寶[創建交易]請求,處理異常OrderNo={},exception:", order.getOrderNo(), e);
TipAssert.isTrue(false, "調用支付寶支付請求失敗");
}
return null;
}
}
@ChannelsFlag(PayChannel.WE_CHAT_PAY)
public class WxChannelsPayService extends AbsChannelsPayService implements InitializingBean {
private WxpayProperties wxpayProperties;
private WXPay wxPayClient;
@SuppressWarnings("unchecked")
@Override
public <T extends Serializable> T tradeCreate(TradeOrderDto order) {
String requestBody = "";
String responseBody = "";
String payBody = "";
String billNo = order.getBillNo();
String clientIp = order.getClientIp();
try {
WxPayCreateRequest wxPayCreateRequest = new WxPayCreateRequest();
wxPayCreateRequest.setBody(order.getSubject());
wxPayCreateRequest.setOutTradeNo(billNo);
wxPayCreateRequest.setSpbillCreateIp(clientIp);
wxPayCreateRequest.setTotalFee(
order.getRealPayment().multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP).longValue()
+ "");
requestBody = JsonUtils.toJson(wxPayCreateRequest);
WXPay wxPay = new WXPay(DefaultWeChatConfig.getInstance(wxpayProperties),
buildOrderNotifyUrl(order.getPayChannel().name(), billNo, wxpayProperties.getNotifyUrl()), true,
false);
Map<String, String> unifiedResult = wxPay.unifiedOrder(JsonUtils.formatFiledtoMap(wxPayCreateRequest));
responseBody = JsonUtils.toJson(unifiedResult);
Map<String, String> tradeMap = Maps.newHashMap();
tradeMap.put("appid", wxpayProperties.getAppid());
tradeMap.put("partnerid", wxpayProperties.getMerchantId());
tradeMap.put("prepayid", unifiedResult.get("prepay_id"));
tradeMap.put("package", "Sign=WXPay");
tradeMap.put("noncestr", RandomStringUtils.randomNumeric(32));
tradeMap.put("timestamp", System.currentTimeMillis() / 1000 + "");
tradeMap.put("sign",
WXPayUtil.generateSignature(tradeMap, wxpayProperties.getMerchantKey(), SignType.HMACSHA256));
payBody = JsonUtils.toJson(tradeMap);
return (T) payBody;
} catch (Exception e) {
logger.error("單號={},發起微信支付發生異常", billNo, e);
} finally {
logger.info("請求微信APP支付,單號={},請求報文={},響應報文={},發起支付請求體={}", billNo, requestBody, responseBody, payBody);
}
return null;
}
}
在Java語言中,abstract class和interface是支持抽象類定義的兩種機制。
不能創建abstract類的實例,然而可以創建一個變量,其類型是一個抽象類,並讓它指向具體子類的一個實例。
不能有抽象構造函數或抽象靜態方法。
Abstract 類的子類爲它們父類中的所有抽象方法提供實現,否則它們也是抽象類。
接口(interface)是抽象類的變體。
在接口中,所有方法都是抽象,公開的。多繼承性可通過實現這樣的接口而獲得。
接口中的所有方法都沒有一個有程序體。接口只可以定義staticfinal成員變量。
接口的實現與子類相似,除了該實現類不能從接口定義中繼承行爲。
當類實現特殊接口時,它定義(即將程序體給予)所有這種接口的方法。然後,它可以在實現了該接口的類的任何對象上調用接口的方法。
由於有抽象類,它允許使用接口名作爲引用變量的類型。通常的動態聯編將生效。
引用可以轉換到接口類型或從接口類型轉換,instanceof運算符可以用來決定某對象的類是否實現了接口。
接口可以繼承接口。抽象類可以實現(implements)接口,抽象類是可以繼承實體類,但前提是實體類必須有明確的構造函數。接口更關注“能實現什麼功能”,而不管“怎麼實現的”。
1.相同點
A. 兩者都是抽象類,都不能實例化。
B. interface實現類及abstrctclass的子類都必須要實現已經聲明的抽象方法。
2. 不同點
A. interface需要實現,要用implements,而abstract class需要繼承,要用extends。
B. 一個類可以實現多個interface,但一個類只能繼承一個abstract class。
C. interface強調特定功能的實現,而abstractclass強調所屬關係。
D. 儘管interface實現類及abstrct class的子類都必須要實現相應的抽象方法,但實現的形式不同。interface中的每一個方法都是抽象方法,都只是聲明的(declaration,沒有方法體),實現類必須要實現。而abstractclass的子類可以有選擇地實現。
這個選擇有兩點含義:
一是Abastract class中並非所有的方法都是抽象的,只有那些冠有abstract的方法纔是抽象的,子類必須實現。那些沒有abstract的方法,在Abstrct class中必須定義方法體。
二是abstract class的子類在繼承它時,對非抽象方法既可以直接繼承,也可以覆蓋;而對抽象方法,可以選擇實現,也可以通過再次聲明其方法爲抽象的方式,無需實現,留給其子類來實現,但此類必須也聲明爲抽象類。既是抽象類,當然也不能實例化。
E. abstract class是interface與Class的中介。
interface是完全抽象的,只能聲明方法,而且只能聲明pulic的方法,不能聲明private及protected的方法,不能定義方法體,也不能聲明實例變量。然而,interface卻可以聲明常量變量,並且在JDK中不難找出這種例子。但將常量變量放在interface中違背了其作爲接口的作用而存在的宗旨,也混淆了interface與類的不同價值。如果的確需要,可以將其放在相應的abstractclass或Class中。
abstract class在interface及Class中起到了承上啓下的作用。一方面,abstract class是抽象的,可以聲明抽象方法,以規範子類必須實現的功能;另一方面,它又可以定義缺省的方法體,供子類直接使用或覆蓋。另外,它還可以定義自己的實例變量,以供子類通過繼承來使用。
3. interface的應用場合
A. 類與類之前需要特定的接口進行協調,而不在乎其如何實現。
B. 作爲能夠實現特定功能的標識存在,也可以是什麼接口方法都沒有的純粹標識。
C. 需要將一組類視爲單一的