一:集成步骤
1.引入依赖:
<dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>3.7.110.ALL</version> </dependency>
2.支付宝app支付参数配置:
#服务器域名地址 server.service-domain = http://127.0.0.1:8080 ##支付宝支付 pay.alipay.gatewayUrl="支付宝gatewayUrl" pay.alipay.appid="商户应用id" pay.alipay.app-private-key="应用RSA私钥,用于对商户请求报文加签" pay.alipay.alipay-public-key="支付宝RSA公钥,用于验签支付宝应答" #支付成功的异步通知回调接口 pay.alipay.notify-url=${server.service-domain}/api/alipay/notify
3.定义配置类:
package com.annaru.upms.payment.config; import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * 支付宝支付的参数配置 * * @author mengday zhang */ @Data @Slf4j @Component @ConfigurationProperties(prefix = "pay.alipay") public class AlipayConfig { /** * 支付宝gatewayUrl */ private String gatewayUrl; /** * 商户应用id */ private String appid; /** * RSA私钥,用于对商户请求报文加签 */ private String appPrivateKey; /** * 支付宝RSA公钥,用于验签支付宝应答 */ private String alipayPublicKey; /** * 签名类型 */ private String signType = "RSA2"; /** * 格式 */ private String formate = "json"; /** * 编码 */ private String charset = "UTF-8"; /** * 同步地址 */ private String returnUrl; /** * 异步地址 */ private String notifyUrl; /** * 最大查询次数 */ private static int maxQueryRetry = 5; /** * 查询间隔(毫秒) */ private static long queryDuration = 5000; /** * 最大撤销次数 */ private static int maxCancelRetry = 3; /** * 撤销间隔(毫秒) */ private static long cancelDuration = 3000; @Bean public AlipayClient alipayClient(){ return new DefaultAlipayClient(this.getGatewayUrl(), this.getAppid(), this.getAppPrivateKey(), this.getFormate(), this.getCharset(), this.getAlipayPublicKey(), this.getSignType()); } }
4. 定义controller:
在调用微信服务接口进行统一下单之前,
1、为保证安全性,建议验证数据库是否存在订单号对应的订单。
package com.annaru.upms.payment.controller; import com.alibaba.dubbo.config.annotation.Reference; import com.annaru.common.base.BaseController; import com.annaru.common.result.ResultMap; import com.annaru.common.util.Constant; import com.annaru.upms.entity.OrderMain; import com.annaru.upms.entity.OrderPayment; import com.annaru.upms.payment.service.AlipayService; import com.annaru.upms.service.IOrderMainService; import com.annaru.upms.service.IOrderPaymentService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.util.Date; @Api(tags = "支付宝支付接口管理") @RestController @RequestMapping("/alipay") public class AlipayController extends BaseController { @Reference private IOrderPaymentService orderPaymentService; @Reference private IOrderMainService orderMainService; @Autowired private AlipayService alipayService; /** * 创建订单 */ @ApiOperation(value = "创建订单", notes = "支付宝支付创建订单") @GetMapping("/createOrder") public ResultMap createOrder(@ApiParam(value = "订单号") @RequestParam String orderNo, @ApiParam(value = "订单金额") @RequestParam double amount, @ApiParam(value = "商品名称") @RequestParam String body) { try { // 1、验证订单是否存在 // 2、创建支付宝订单 String orderStr = alipayService.createOrder(orderNo, amount, body); return ResultMap.ok().put("data", orderStr); } catch (Exception e) { logger.error(e.getMessage()); return ResultMap.error("订单生成失败"); } } /** * 支付异步通知 * 接收到异步通知并验签通过后,一定要检查通知内容, * 包括通知中的app_id、out_trade_no、total_amount是否与请求中的一致,并根据trade_status进行后续业务处理。 * https://docs.open.alipay.com/194/103296 */ @RequestMapping("/notify") public String notify(HttpServletRequest request) { // 验证签名 boolean flag = alipayService.rsaCheckV1(request); if (flag) { String tradeStatus = request.getParameter("trade_status"); // 交易状态 String outTradeNo = request.getParameter("out_trade_no"); // 商户订单号 String tradeNo = request.getParameter("trade_no"); // 支付宝订单号 /** * 还可以从request中获取更多有用的参数,自己尝试 */ boolean notify = alipayService.notify(tradeStatus, outTradeNo, tradeNo); if(notify){ return "success"; } } return "fail"; } @ApiOperation(value = "退款", notes = "退款") @PostMapping("/refund") public ResultMap refund(@ApiParam(value = "订单号") @RequestParam String orderNo, @ApiParam(value = "退款金额") @RequestParam double amount, @ApiParam(value = "退款原因") @RequestParam(required = false) String refundReason) { return alipayService.refund(orderNo, amount, refundReason); } }
5、定义service接口:
package com.annaru.upms.payment.service; import com.alipay.api.AlipayApiException; import javax.servlet.http.HttpServletRequest; /** * 支付宝服务接口 * * Author: * Date:2019/8/1 * Description: */ public interface AlipayService { /** * @Description: 创建支付宝订单 * @param orderNo: 订单编号 * @param amount: 实际支付金额 * @param body: 订单描述 * @Author: * @Date: 2019/8/1 * @return */ String createOrder(String orderNo, double amount, String body) throws AlipayApiException; /** * @Description: * @param tradeStatus: 支付宝交易状态 * @param orderNo: 订单编号 * @param tradeNo: 支付宝订单号 * @Author: * @Date: 2019/8/1 * @return */ boolean notify(String tradeStatus, String orderNo, String tradeNo); /** * @Description: 校验签名 * @param request * @Author: * @Date: 2019/8/1 * @return */ boolean rsaCheckV1(HttpServletRequest request); /** * @Description: 退款 * @param orderNo: 订单编号 * @param amount: 实际支付金额 * @param refundReason: 退款原因 * @Author: XCK * @Date: 2019/8/6 * @return */ ResultMap refund(String orderNo, double amount, String refundReason); }
6、service实现类
package com.annaru.upms.payment.service.impl; import com.alibaba.dubbo.config.annotation.Reference; import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.domain.AlipayTradeAppPayModel; import com.alipay.api.internal.util.AlipaySignature; import com.alipay.api.request.AlipayTradeAppPayRequest; import com.alipay.api.response.AlipayTradeAppPayResponse; import com.annaru.upms.payment.config.AlipayConfig; import com.annaru.upms.payment.service.AlipayService; import com.annaru.upms.service.IOrderPaymentService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * Author:XCK * Date:2019/8/1 * Description: */ @Service public class AlipayServiceImpl implements AlipayService { private final Logger logger = LoggerFactory.getLogger(AlipayServiceImpl.class); @Autowired private AlipayConfig alipayConfig; @Autowired private AlipayClient alipayClient; @Override public String createOrder(String orderNo, double amount, String body) throws AlipayApiException { //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); model.setSubject(body); model.setOutTradeNo(orderNo); model.setTotalAmount(String.valueOf(amount)); model.setProductCode("QUICK_MSECURITY_PAY"); model.setPassbackParams("公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数"); //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest(); ali_request.setBizModel(model); ali_request.setNotifyUrl(alipayConfig.getNotifyUrl());// 回调地址 AlipayTradeAppPayResponse ali_response = alipayClient.sdkExecute(ali_request); //就是orderString 可以直接给客户端请求,无需再做处理。 return ali_response.getBody(); } @Override public boolean notify(String tradeStatus, String orderNo, String tradeNo) { if ("TRADE_FINISHED".equals(tradeStatus) || "TRADE_SUCCESS".equals(tradeStatus)) { // 支付成功,根据业务逻辑修改相应数据的状态 // boolean state = orderPaymentService.updatePaymentState(orderNo, tradeNo); if (state) { return true; } } return false; } @Override public boolean rsaCheckV1(HttpServletRequest request){ try { Map<String, String> params = new HashMap<>(); Map<String, String[]> requestParams = request.getParameterMap(); for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) { String name = (String) iter.next(); String[] values = requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } params.put(name, valueStr); } boolean verifyResult = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType()); return verifyResult; } catch (AlipayApiException e) { logger.debug("verify sigin error, exception is:{}", e); return false; } } @Override public ResultMap refund(String orderNo, double amount, String refundReason) { if(StringUtils.isBlank(orderNo)){ return ResultMap.error("订单编号不能为空"); } if(amount <= 0){ return ResultMap.error("退款金额必须大于0"); } AlipayTradeRefundModel model=new AlipayTradeRefundModel(); // 商户订单号 model.setOutTradeNo(orderNo); // 退款金额 model.setRefundAmount(String.valueOf(amount)); // 退款原因 model.setRefundReason(refundReason); // 退款订单号(同一个订单可以分多次部分退款,当分多次时必传) // model.setOutRequestNo(UUID.randomUUID().toString()); AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest(); alipayRequest.setBizModel(model); AlipayTradeRefundResponse alipayResponse = null; try { alipayResponse = alipayClient.execute(alipayRequest); } catch (AlipayApiException e) { logger.error("订单退款失败,异常原因:{}", e); } if(alipayResponse != null){ String code = alipayResponse.getCode(); String subCode = alipayResponse.getSubCode(); String subMsg = alipayResponse.getSubMsg(); if("10000".equals(code) && StringUtils.isBlank(subCode) && StringUtils.isBlank(subMsg)){ // 表示退款申请接受成功,结果通过退款查询接口查询 // 修改用户订单状态为退款 return ResultMap.ok("订单退款成功"); } return ResultMap.error(subCode + ":" + subMsg); } return ResultMap.error("订单退款失败"); } }
7、定义通用返回结果集 ResultMap
package com.annaru.common.result; import org.apache.http.HttpStatus; import java.util.HashMap; import java.util.Map; /** * @Description 通用返回结果集 * @Author * @Date 2018/6/12 15:13 */ public class ResultMap extends HashMap<String, Object> { public ResultMap() { put("state", true); put("code", 0); put("msg", "success"); } public static ResultMap error(int code, String msg) { ResultMap r = new ResultMap(); r.put("state", false); r.put("code", code); r.put("msg", msg); return r; } public static ResultMap error(String msg) { return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg); } public static ResultMap error() { return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员"); } public static ResultMap ok(String msg) { ResultMap r = new ResultMap(); r.put("msg", msg); return r; } public static ResultMap ok(Map<String, Object> par) { ResultMap r = new ResultMap(); r.putAll(par); return r; } public static ResultMap ok() { return new ResultMap(); } public ResultMap put(String key, Object value) { super.put(key, value); return this; } }