搭建和配置开发环境(下载sdk https://docs.open.alipay.com)
alipay-sdk-java*.jar:支付宝sdk编译文件jar
alipay-sdk-java*-source.jar:支付宝sdk源码文件jar包
Commons-logging-1.1.1.jar:sdk依赖的日志jar
Commons-logging-1.1.1-source.jar:sdk依赖的日志源码jar
核心api(以支付宝交易预创建为例)
AlipayClient:封装签名与验证
AlipayTradePrecreateModel:封装业务参数的模型
AlipayTradePrecreateRequest:封装请求支付信息
AlipayTradePrecreateResponse:执行请求并返回给你的响应
提交到支付宝处理后分俩种方式返回通知
1,服务器异步通知(必须要在公网下才能测试)
(1)notify_url
①完成返回结果的参数的接受
②对参数进行验证,通过AlipaySignature.rsaCheckVI(),方法验证,验证中的参数和配置文件中定义的参数会返回一个结果,只要验证成功都要告诉支付宝一个success这个处理结果,验证失败告诉fail
③只有验证成功才能在系统中更改支付状态以及支付成功后的业务处理
④对于支付成功返回了俩种处理信息:trade_finished和trade_success
1)trade_finished:表示这个订单不能进行退款了
2)trade_success:如果签约的协议可以退款返回的就是success
2,页面跳转通知
(1)Return_url
①参数的接受和参数的验证和notify是一样的
②验证成功以后跳转和notify不同,不需要判断返回的状态,只需要知道结果成功跳转到成功的页面失败跳转到失败的页面
支付宝使用get方式,是由客户浏览器触发的一个通知,不保证其到达率
代码实现(参数都是固定的,写在properties文件中)
@RequestMapping("/tradePrecreatePay")
@ResponseBody
public Object tradePrecreatePay(HttpServletRequest req, String subject,
String totalAmount, String storeId,String notifyUrl,String seller_id,String timeout_express) throws UnsupportedEncodingException, AlipayApiException {
Map jsonMap = new HashMap();
// 首先判断参数为空
if (StringUtils.isBlank(subject)) {
jsonMap.put("code", "1");
jsonMap.put("message", "订单标题为空!");
return jsonMap;
}
if (StringUtils.isBlank(totalAmount)) {
jsonMap.put("code", "1");
jsonMap.put("message", "订单总金额为空!");
return jsonMap;
}
//支付宝默认客户端 封装的固定参数(这一步我直接封装在一个类中)
AlipayClient alipayClient = AliPayApi.getAlipayClient(req);
if (alipayClient != null) {
//封装业务参数的模型,==>>request.setBizContent(,,,)
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
model.setSubject(subject);
model.setTotalAmount(totalAmount);
model.setTimeoutExpress(timeout_express);
model.setOutTradeNo(StringUtils.getOutTradeNo());// 设置业务参数
// 根据response中的结果继续业务逻辑处理
try {
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
request.setBizModel(model);// 填充业务参数
if (notifyUrl != null && !"".equals(notifyUrl.trim())) {
request.setNotifyUrl(notifyUrl);
}else{
request.setNotifyUrl("http://47.94.170.104:8080/msss/aliPay/notifyUrl.do");
}
//执行请求并返回响应
AlipayTradePrecreateResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
logger.info("==================支付宝交易预下单接口调用成功:" + response.getMsg());
// 调用预下单方法
String resultStr = response.getBody();
JSONObject jsonObject = JSONObject.fromObject(resultStr);
logger.info("==================支付宝交易预下单返回结果:" + jsonObject);
// 商户订单号
String out_trade_no = response.getOutTradeNo();
// 获得需要的数据,并且插入数据库
OrderInfo orderInfo = new OrderInfo();
orderInfo.setId(UUIDUtil.getUUID());
orderInfo.setOut_trade_no(out_trade_no);
orderInfo.setSeller_id(seller_id);// 卖家支付宝用户号
orderInfo.setMoney(new BigDecimal(totalAmount));// 付款金额
orderInfo.setTrade_status("WAIT_BUYER_PAY");// 代表订单状态是待付款
orderInfo.setSign(jsonObject.getString("sign"));
int n = orderInfoService.addOrderInfo(orderInfo);
if(n > 0){
logger.info("==================数据插入成功");
jsonMap.put("code", "0");
jsonMap.put("message", "success");
jsonMap.put("data", jsonObject);
}else{
logger.info("==================订单表 orderinfo 数据插入失败");
jsonMap.put("code", "1");
jsonMap.put("message", "订单表 orderinfo 数据插入失败");
}
} else {
logger.info("==================支付宝交易预下单接口调用失败:" + response.getSubMsg());
jsonMap.put("code", "1");
jsonMap.put("message", response.getSubMsg());
}
} catch (Exception e) {
e.printStackTrace();
logger.error("==================支付宝预下单接口调用异常:", e);
jsonMap.put("code", "1");
jsonMap.put("message", e.getMessage());
}
} else {
jsonMap.put("code", "1");
jsonMap.put("message", "请求头中 appName is null 或者 传值错误");
}
return jsonMap;
}
支付成功返回的通知(只写异步通知)
@RequestMapping("/notifyUrl")
@ResponseBody
public Object notifyUrl(HttpServletRequest request, HttpServletResponse response)
throws AlipayApiException, IOException {
Map jsonMap = new HashMap();
Map dataMap = new HashMap();
logger.info("==================支付宝异步返回支付结果开始");
try {
Map params = new HashMap();// 将异步通知中收到的所有参数都放到map中
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使用。
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
//Map params = AliPayApi.toMap(request);
logger.info("==================返回参数集合:" + params);
String signType = params.get("sign_type");
String sign = params.get("sign");
// 获取开发者的app_id,进而确定公钥
String appId = params.get("app_id");
//生产环境的appid
String appid_big = PropertiesUtil.getProperty(AlipayConfig.APP_ID_HOSPITAL_BIG);
//沙箱环境的id
String appid_test = PropertiesUtil.getProperty(AlipayConfig.APP_ID_HOSPITAL_TEST);
//切换环境
if (!appId.equals(appid_big) && !appId.equals(appid_test)) {
logger.info("==================与付款时的appid不同,此为异常通知,应忽略!");
jsonMap.put("code", "1");
jsonMap.put("message", "与付款时的appid不同!");
} else {
String alipayPublicKey = "";
if (appid_big.equals(appId)) {
alipayPublicKey = PropertiesUtil.getProperty(AlipayConfig.ALIPAY_PUBLIC_KEY_HOSPITAL_BIG);
} else if (appid_test.equals(appId)) {
alipayPublicKey = PropertiesUtil.getProperty(AlipayConfig.ALIPAY_PUBLIC_KEY_HOSPITAL_TEST);
}
// 验证签名(对支付宝返回的数据验证,确定是支付宝返回的)
boolean flag = AlipaySignature.rsaCheckV1(params, alipayPublicKey, AliPayApi.charset,
AliPayApi.signType);
// 验证成功则继续业务操作:异步请求逻辑处理
if (flag) {
logger.info("==================验签成功!");
// 获取需要保存的数据
// 商户订单号
String outTradeNo = params.get("out_trade_no");
// 卖家支付宝用户号
String sellerId = params.get("seller_id");
// 支付宝交易状态
String tradeStatus = params.get("trade_status");
// 付款金额
BigDecimal totalAmount = new BigDecimal(params.get("total_amount"));
logger.info("==================商户订单号:" + outTradeNo + " 付款金额:" + totalAmount);
logger.info("==================sellerId:" + sellerId + " 交易状态:" + tradeStatus);
// 在数据库中查找订单号对应的订单,并根据支付宝回调更改订单状态
OrderInfo order = orderInfoService.queryOrderInfo(outTradeNo);
if (order == null) {
logger.error("==================系统订单:" + outTradeNo + "不存在!");
jsonMap.put("code", "1");
jsonMap.put("message", "商户订单号不存在");
} else {
logger.info("==================" + outTradeNo + " 订单回调通知!");
logger.info("查找订单号 " + outTradeNo + " 对应的订单:" + order);
// 数据库中订单状态比对
if (order.getTrade_status().equals("TRADE_SUCCESS") || order.getTrade_status().equals("TRADE_FINISHED")) {// 判断当前订单是否已处理,避免重复处理
logger.info("==================系统订单:" + outTradeNo + " 无需重复处理!");
jsonMap.put("code", "1");
jsonMap.put("message", "订单已经处理!");
} else {
if (!order.getMoney().toString().equals(totalAmount.toString())) {
logger.info("==================与付款时的金额不同,此为异常通知,应忽略!");
jsonMap.put("code", "1");
jsonMap.put("message", "付款金额不对");
}
if (!order.getSeller_id().toString().equals(sellerId)) {
logger.info("==================不是订单对应的操作方,此为异常通知,应忽略!");
jsonMap.put("code", "1");
jsonMap.put("message", "操作方不对");
}
// 返回的信息比对订单状态的信息,如果不是就修改状态
if (tradeStatus.equals("TRDE_SUCCESS") || tradeStatus.equals("TRDE_FINISHED")) {
// 修改订单状态为已支付
int n = orderInfoService.updateStatus(outTradeNo, tradeStatus);
if (n > 0) {
logger.info("==================系统订单:" + outTradeNo + " 成功支付!");
dataMap.put("app_id", appId);// 开发者的app_id
dataMap.put("out_trade_no", outTradeNo);//商户订单号
dataMap.put("notify_time", params.get("notify_time"));//通知时间
dataMap.put("notify_type", params.get("notify_type"));//通知类型
dataMap.put("notify_id", params.get("notify_id"));//通知校验ID
dataMap.put("sign_type", signType);// 签名类型
dataMap.put("sign", sign);//签名
dataMap.put("trade_no", params.get("trade_no"));//支付宝交易号
String orderSign = orderInfoService.selectSign(outTradeNo);
if (!orderSign.equals(sign)) {
orderInfoService.updateSign(outTradeNo,sign);
}
jsonMap.put ("code", "0");
jsonMap.put("message", "success");
jsonMap.put("data", dataMap);
} else {
logger.info("==================系统订单:" + outTradeNo + "状态修改失败!");
jsonMap.put("code", "1");
jsonMap.put("message", "数据库状态修改失败!");
}
}else if(tradeStatus.equals("WAIT_BUYER_PAY")){
jsonMap.put("code", "1");
jsonMap.put("message", "交易创建,等待买家付款!");
}else{
jsonMap.put("code", "1");
jsonMap.put("message", "未付款交易超时关闭,或支付完成后全额退款!");
}
}
}
//response.getWriter().println("success");
} else {
logger.info("==================验签失败 !");
jsonMap.put("code", "1");
jsonMap.put("message", "验签失败");
//response.getWriter().println("fail");
}
}
} catch (AlipayApiException e) {
e.printStackTrace();
logger.info("==================支付宝异步通知异常:", e);
jsonMap.put("code", "1");
jsonMap.put("message", e.getMessage());
}
return jsonMap;
}
初始化请求客服端,封装的签名,请求,验签的功能,这样写的好处是测试的时候沙箱和生产环境可以切换,参数都写在properties文件中
public static AlipayClient getAlipayClient(HttpServletRequest request) {
String appId = PropertiesUtil.getProperty(AlipayConfig.APP_ID_HOSPITAL_BIG);
String privateKey = PropertiesUtil.getProperty(AlipayConfig.PRIVATE_KEY_HOSPITAL_BIG);
String alipayPublicKey = PropertiesUtil.getProperty(AlipayConfig.ALIPAY_PUBLIC_KEY_HOSPITAL_BIG);
// 初始化请求客户端,其中封装了签名、请求、验签的功能
alipayClient = new DefaultAlipayClient(serverUrl, appId, privateKey, format, charset, alipayPublicKey,
signType);
return alipayClient;
}