123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- package com.example.controller;
- import com.alibaba.fastjson.JSONObject;
- import com.alipay.api.AlipayApiException;
- import com.alipay.api.AlipayClient;
- import com.alipay.api.domain.*;
- import com.alipay.api.internal.util.AlipaySignature;
- import com.alipay.api.request.*;
- import com.alipay.api.response.AlipayTradePayResponse;
- import com.alipay.api.response.AlipayTradePrecreateResponse;
- import com.alipay.api.response.AlipayTradeRefundResponse;
- import com.example.base.BaseController;
- import com.example.base.ResponseBase;
- import com.example.config.ali.AlipayProperties;
- import com.example.service.AlipayRefundService;
- import com.example.service.AlipayService;
- import com.example.util.SnowFlake;
- import io.swagger.annotations.ApiOperation;
- import io.swagger.annotations.ApiParam;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.*;
- import springfox.documentation.annotations.ApiIgnore;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.io.UnsupportedEncodingException;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Objects;
- @Controller
- @RequestMapping("/alipay")
- public class AlipayPagePayController extends BaseController {
- private static final Logger logger = LoggerFactory.getLogger(AlipayPagePayController.class);
- @Autowired
- private AlipayProperties alipayProperties;
- @Autowired
- private AlipayClient alipayClient;
- /**
- * 商品定价
- */
- @Value("${pay.alipay.totalAmount}")
- private String totalAmount;
- /**
- * 商品名
- */
- @Value("${pay.subjectName}")
- public String subjectName;
- @GetMapping("/test")
- @ResponseBody
- public String test() {
- return "suucess";
- }
- /**
- * 扫码付款成功后跳转的url
- */
- @Value("${pay.alipay.returnUrlForScan}")
- private String returnUrlForScan;
- @GetMapping("/getPayimg")
- @ResponseBody
- public ResponseBase getPayimg(String outTradeNo) {
- AlipayTradePrecreateRequest req = new AlipayTradePrecreateRequest();
- AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
- model.setOutTradeNo(outTradeNo);
- model.setSubject("测试二维码");
- String amount = String.valueOf(0.01);
- model.setTotalAmount(amount);
- req.setBizModel(model);
- req.setNotifyUrl(alipayProperties.getNotifyUrl());
- logger.info("发起AliPay下单请求");
- AlipayTradePrecreateResponse execute = null;
- String img = null;
- try {
- execute = alipayClient.execute(req);
- String result = execute.getBody();
- JSONObject res = JSONObject.parseObject(result);
- res = res.getJSONObject("alipay_trade_precreate_response");
- String code = res.getString("code");
- String qr_code = res.getString("qr_code");
- if (code.equals("10000") && qr_code != null) {
- img = qr_code;
- }
- } catch (Exception e) {
- return responseSuccess(error("构建二维码失败!"));
- }
- return responseSuccess(success(img));
- }
- /**
- * 条码支付
- *
- * @return
- * @throws AlipayApiException
- */
- @GetMapping("/barcode")
- @ResponseBody
- public ResponseBase barcode(String authCode) throws AlipayApiException {
- SnowFlake snowFlake = new SnowFlake(2, 3);
- String outTradeNo = snowFlake.nextId() + "";
- AlipayTradePayRequest request = new AlipayTradePayRequest();
- AlipayTradePayModel model = new AlipayTradePayModel();
- model.setOutTradeNo(outTradeNo);
- model.setScene("bar_code");
- //扫码枪的二维码
- model.setAuthCode(authCode);
- model.setSubject("条码支付测试");
- String amount = String.valueOf(0.01);
- model.setStoreId("NJ_001");
- model.setTotalAmount(amount);
- model.setTimeoutExpress("2m");
- request.setBizModel(model);
- request.setNotifyUrl(alipayProperties.getNotifyUrl());
- logger.info("发起AliPay下单请求");
- AlipayTradePayResponse response = null;
- try {
- response = alipayClient.execute(request);
- String result = response.getBody();
- JSONObject res = JSONObject.parseObject(result);
- res = res.getJSONObject("alipay_trade_pay_response");
- String code = res.getString("code");
- if (code.equals("10000")) {
- return responseSuccess(success("成功"));
- } else {
- return responseSuccess(error("条幅支付失败"));
- }
- } catch (Exception e) {
- return responseSuccess(error("条幅支付失败!"));
- }
- }
- /**
- * h5 页面支付
- *
- * @param outTradeNo
- * @return
- * @throws AlipayApiException
- */
- @GetMapping("/alipage")
- @ResponseBody
- public ResponseBase gotoPayPage(@RequestParam String outTradeNo) throws AlipayApiException {
- logger.info("支付订单号:{}", outTradeNo);
- // 订单模型
- String productCode = "QUICK_WAP_WAY";
- AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
- //防止传空参数
- if (outTradeNo == null || outTradeNo == "" || outTradeNo.length() < 4) {
- outTradeNo = String.valueOf(System.nanoTime());
- }
- // String outTradeNo = UUID.randomUUID().toString();
- model.setOutTradeNo(outTradeNo);
- model.setSubject(subjectName);
- model.setTotalAmount(totalAmount);
- model.setBody(subjectName + ",共0.01元");
- model.setTimeoutExpress("2m");
- model.setProductCode(productCode);
- AlipayTradeWapPayRequest wapPayRequest = new AlipayTradeWapPayRequest();
- wapPayRequest.setReturnUrl(alipayProperties.getReturnUrl());
- wapPayRequest.setNotifyUrl(alipayProperties.getNotifyUrl());
- wapPayRequest.setBizModel(model);
- // 调用SDK生成表单, 并直接将完整的表单html输出到页面
- String form = alipayClient.pageExecute(wapPayRequest).getBody();
- return responseSuccess(success(form));
- }
- @ApiOperation(value = "网页扫码支付", notes = "跳转到支付宝扫码支付页面,用户可通过扫码进行支付,成功则跳转到成功页面")
- @GetMapping("/gotoPayPage")
- public void gotoPayPage(HttpServletResponse response) throws AlipayApiException, IOException {
- // 订单模型
- String productCode = "FAST_INSTANT_TRADE_PAY";
- AlipayTradePagePayModel model = new AlipayTradePagePayModel();
- SnowFlake snowFlake = new SnowFlake(2, 3);
- model.setOutTradeNo(snowFlake.nextId() + "");
- model.setSubject(subjectName);
- model.setTotalAmount(totalAmount);
- model.setBody(subjectName + ",共0.01元");
- model.setProductCode(productCode);
- AlipayTradePagePayRequest pagePayRequest = new AlipayTradePagePayRequest();
- pagePayRequest.setReturnUrl(returnUrlForScan);
- pagePayRequest.setNotifyUrl(alipayProperties.getNotifyUrl());
- pagePayRequest.setBizModel(model);
- // 调用SDK生成表单, 并直接将完整的表单html输出到页面
- String form = alipayClient.pageExecute(pagePayRequest).getBody();
- response.setContentType("text/html;charset=" + alipayProperties.getCharset());
- response.getWriter().write(form);
- response.getWriter().flush();
- response.getWriter().close();
- }
- /**
- * 支付宝页面跳转同步通知页面
- */
- @ApiIgnore
- @GetMapping("/returnUrl")
- public String returnUrl(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, AlipayApiException {
- response.setContentType("text/html;charset=" + alipayProperties.getCharset());
- //获取支付宝GET过来反馈信息
- Map<String, String> params = new HashMap<>();
- Map requestParams = request.getParameterMap();
- for (Object iter : requestParams.keySet()) {
- String name = (String) iter;
- 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] + ",";
- }
- //乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
- valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
- params.put(name, valueStr);
- }
- logger.info("params is " + params.toString());
- //验签
- boolean verifyResult = AlipaySignature.rsaCheckV1(params, alipayProperties.getAlipayPublicKey(),
- alipayProperties.getCharset(), "RSA2");
- if (verifyResult) {
- //验证成功
- //请在这里加上商户的业务逻辑程序代码,如保存支付宝交易号
- //商户订单号
- String outTradeNo = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
- //支付宝交易号
- String tradeNo = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
- return "success";
- } else {
- return "error";
- }
- }
- @Autowired
- private AlipayService alipayService;
- @Autowired
- private AlipayRefundService alipayRefundService;
- static boolean rsaCheckV1(HttpServletRequest request) {
- return true;
- }
- /**
- * 支付异步通知
- * 接收到异步通知并验签通过后,一定要检查通知内容,包括通知中的app_id、out_trade_no、total_amount是否与请求中的一致,
- * 并根据trade_status进行后续业务处理
- * https://docs.open.alipay.com/194/103296
- */
- @ApiIgnore
- @RequestMapping("/notify")
- @ResponseBody
- public String notify(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
- // 一定要验签,防止黑客篡改参数
- Map<String, String[]> parameterMap = request.getParameterMap();
- StringBuilder notifyBuild = new StringBuilder("/****************************** alipay notify **********" +
- "********************/\n");
- parameterMap.forEach((key, value) -> notifyBuild.append(key + "=" + value[0] + "\n"));
- //订单信息
- logger.info("notifyBuild" + notifyBuild.toString());
- //校验签名
- boolean flag = this.rsaCheckV1(request);
- if (flag) {
- /**
- * 需要严格按照如下描述校验通知数据的正确性
- * 商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
- * 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
- * 同时需要校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
- * 上述有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。
- * 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。
- * 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
- */
- //交易状态
- String tradeStatus = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
- //支付宝交易号
- String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
- String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
- //商户id
- String app_id = new String(request.getParameter("app_id").getBytes("ISO-8859-1"), "UTF-8");
- //退款费用 用于判断是否是退款
- String refund_fee = null;
- try {
- refund_fee = new String(request.getParameter("refund_fee").getBytes("ISO-8859-1"), "UTF-8");
- } catch (Exception e) {
- refund_fee = "";
- }
- /*判断是否是支付异步通知*/
- if (refund_fee == null || refund_fee == "") {
- //付款金额
- String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");
- //判断订单号是否已处理
- if (alipayService.containsByOutTradeNo(trade_no)) {
- logger.warn("订单已处理,支付宝重复调用");
- return "success";
- }
- //判断订单金额是否一致 防止被篡改
- if (!total_amount.equals(totalAmount)) {
- logger.warn("订单金额不一致,请防止黑客恶意篡改信息");
- return "fail";
- }
- //判断商户id是否一致,防止被篡改
- if (!app_id.equals(alipayProperties.getAppid())) {
- logger.warn("操作的商户id不一致,请防止黑客恶意篡改信息");
- return "fail";
- }
- // TRADE_FINISHED(表示交易已经成功结束,并不能再对该交易做后续操作);
- // TRADE_SUCCESS(表示交易已经成功结束,可以对该交易做后续操作,如:分润、退款等);
- if ("TRADE_FINISHED".equals(tradeStatus)) {
- //判断该笔订单是否在商户网站中已经做过处理
- //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,
- // 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),并执行商户的业务程序
- //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
- //如果有做过处理,不执行商户的业务程序
- //注意:
- //如果签约的是可退款协议,退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
- //如果没有签约可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
- } else if ("TRADE_SUCCESS".equals(tradeStatus)) {
- //判断该笔订单是否在商户网站中已经做过处理
- //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,
- // 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),并执行商户的业务程序
- //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
- //如果有做过处理,不执行商户的业务程序
- logger.info("签约可退款协议");
- alipayService.saveToDb(parameterMap);
- //注意:
- //如果签约的是可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
- }
- }
- /*判断是否是退款异步通知*/
- else {
- if (alipayRefundService.containsByOutTradeNo(trade_no)) {
- logger.warn("退款已处理,用户可能重复提交");
- return "have refunded";
- }
- //判断订单金额是否一致 防止被篡改
- if (!refund_fee.equals(totalAmount)) {
- logger.warn("订单金额不一致,请防止黑客恶意篡改信息");
- return "fail";
- }
- //判断商户id是否一致,防止被篡改
- if (!app_id.equals(alipayProperties.getAppid())) {
- logger.warn("操作的商户id不一致,请防止黑客恶意篡改信息");
- return "fail";
- }
- if ("TRADE_FINISHED".equals(tradeStatus)) {
- //判断该笔订单是否在商户网站中已经做过处理
- //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,
- // 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),并执行商户的业务程序
- //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
- //如果有做过处理,不执行商户的业务程序
- //注意:
- //如果签约的是可退款协议,退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
- //如果没有签约可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
- } else if ("TRADE_SUCCESS".equals(tradeStatus)) {
- //判断该笔订单是否在商户网站中已经做过处理
- //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,
- // 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),并执行商户的业务程序
- //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
- //如果有做过处理,不执行商户的业务程序
- alipayRefundService.saveToDb(parameterMap);
- //注意:
- //如果签约的是可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
- }
- }
- return "success";
- }
- return "fail";
- }
- @ApiOperation(value = "退款", notes = "通过商户订单号退款")
- @ApiParam(name = "out_trade_no", value = "商户订单号", required = true)
- @GetMapping("/refund")
- @ResponseBody
- public ResponseBase refund(@RequestParam String outTradeNo) {
- //若订单已处理,直接返回
- if (alipayRefundService.containsByOutTradeNo(outTradeNo)) {
- logger.warn("退款已处理,用户可能重复提交");
- responseSuccess(error("退款已处理,用户可能重复提交"));
- }
- AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
- AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
- //refundModel.setTradeNo(outTradeNo);
- refundModel.setOutTradeNo(outTradeNo);
- refundModel.setRefundAmount(totalAmount);
- refundModel.setRefundReason("用户归还胶片,退还费用");
- request.setBizModel(refundModel);
- AlipayTradeRefundResponse response = null;
- try {
- response = alipayClient.execute(request);
- logger.info(response.getBody());
- } catch (Exception e) {
- logger.error("申请退款出错");
- e.printStackTrace();
- responseSuccess(error("申请退款出错"));
- }
- if (Objects.requireNonNull(response).isSuccess()) {
- logger.info("申请退款成功");
- Map<String, String> responseMap = new HashMap<>(2);
- responseMap.put("return_code", "200");
- responseMap.put("return_msg", "refund success");
- responseSuccess(error("申请退款成功"));
- } else {
- logger.info("申请退款失败");
- Map<String, String> responseMap = new HashMap<>(2);
- responseMap.put("return_code", "200");
- responseMap.put("return_msg", "refund error");
- return responseSuccess(error("申请退款失败"));
- }
- return responseSuccess(success("申请退款成功"));
- }
- }
|