Web项目支付模块开发(JAVA)----------------(3)支付宝对接之项目实践 ||支付以及回调实现

1.下面是controller层,可以参考一下:

package com.mmall.controller.protal;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.demo.trade.config.Configs;
import com.google.common.collect.Maps;
import com.mmall.common.Const;
import com.mmall.common.ResponseCode;
import com.mmall.common.ServiceResponse;
import com.mmall.pojo.User;
import com.mmall.service.IOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Iterator;
import java.util.Map;

/**
 * @program: mmall
 * @description: 支付宝模块
 * @author: Hailong
 * @create: 2018-08-03 10:57
 **/
@Controller
@RequestMapping("/order/")
public class OrderController {

    private  static final Logger logger = LoggerFactory.getLogger(OrderController.class);


    @Autowired
     private IOrderService iOrderService;


    /**
     * 支付宝支付接口
     * @param session
     * @param orderNo
     * @param request
     * @return
     */
    @RequestMapping("pay.do")
    @ResponseBody
    public ServiceResponse pay(HttpSession session, Long orderNo, HttpServletRequest request){
        User user = (User)session.getAttribute(Const.CURRENT_USER);
        if (user == null){
            return ServiceResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc());
        }
        String path = request.getSession().getServletContext().getRealPath("upload");
        return iOrderService.pay(orderNo,user.getId(),path);
    }

    /**
     * 支付宝回调接口
     * @param request
     * @return
     */
    @RequestMapping("alipay_callback.do")
    @ResponseBody
     public Object alipayCallback(HttpServletRequest request){
         Map<String,String> params = Maps.newHashMap();

         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]+",";
             }
             params.put(name,valueStr);
         }
         logger.info("支付宝回调,sign:{},trade_status:{},参数:{}",params.get("sign"),params.get("trade_status"),params.toString());

         //非常重要,验证回调的正确性,是不是支付宝发的,并且还要避免重复通知
         params.remove("sign_type");
         try {
             boolean alipayRSACheckedV2 = AlipaySignature.rsaCheckV2(params, Configs.getAlipayPublicKey(),"utf-8",Configs.getSignType());

             if (!alipayRSACheckedV2){
                 return ServiceResponse.createByErrorMessage("非法请求,验证不通过,再恶意请求我就报警了");
             }
         } catch (AlipayApiException e) {
             logger.error("支付宝回调异常",e);

         }

         //todo验证各种数据
         ServiceResponse serviceResponse = iOrderService.aliCallback(params);
         if (serviceResponse.isSuccess()){
             return Const.AlipayCallback.RESPONSE_SUCCESS;
         }
         return Const.AlipayCallback.RESPONSE_FAILED;

     }

    @RequestMapping("query_order_pay_status.do")
    public ServiceResponse<Boolean> queryOrderPayStatus(HttpSession session, Long orderNo){
        User user = (User)session.getAttribute(Const.CURRENT_USER);
        if (user == null){
            return ServiceResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc());
        }
       ServiceResponse serviceResponse = iOrderService.queryOrderPayStatus(user.getId(),orderNo);
        if (serviceResponse.isSuccess()){
            return ServiceResponse.createBySuccess(true);
        }
        return ServiceResponse.createBySuccess(false);
    }

}

2.下面是service层:

package com.mmall.service.impl;

import com.alipay.api.AlipayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.utils.ZxingUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mmall.common.Const;
import com.mmall.common.ServiceResponse;
import com.mmall.dao.OrderItemMapper;
import com.mmall.dao.OrderMapper;
import com.mmall.dao.PayInfoMapper;
import com.mmall.pojo.Order;
import com.mmall.pojo.OrderItem;
import com.mmall.pojo.PayInfo;
import com.mmall.service.IOrderService;
import com.mmall.util.BigDecimalUtil;
import com.mmall.util.DateTimeUtil;
import com.mmall.util.FTPUtil;
import com.mmall.util.PropertiesUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * @program: mmall
 * @description: 订单接口
 * @author: Hailong
 * @create: 2018-08-03 11:02
 **/
@Service("iOrderService")
public class OrderServiceImpl implements IOrderService{

   private static final org.slf4j.Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);


    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private PayInfoMapper payInfoMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;
   public ServiceResponse pay(Long orderNo,Integer userId, String path) {
       Map<String, String> resultMap = Maps.newHashMap();
       Order order = orderMapper.selectByUserIdAndOrderNo(userId, orderNo);
       if (order == null) {
           return ServiceResponse.createByErrorMessage("用户没有改订单");
       }
       resultMap.put("orderNo", String.valueOf(order.getOrderNo()));


       // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线,
       // 需保证商户系统端不能重复,建议通过数据库sequence生成,
       String outTradeNo = order.getOrderNo().toString();

       // (必填) 订单标题,粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
       String subject = new StringBuilder().append("happymmall扫码支付,订单号:").append(outTradeNo).toString();

       // (必填) 订单总金额,单位为元,不能超过1亿元
       // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
       String totalAmount = order.getPayment().toString();

       // (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段
       // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
       String undiscountableAmount = "0";

       // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号)
       // 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID
       String sellerId = "";

       // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元"
       String body = new StringBuilder().append("订单").append(outTradeNo).append("购买商品共:").append(totalAmount).append("元").toString();


       // 商户操作员编号,添加此参数可以为商户操作员做销售统计
       String operatorId = "test_operator_id";

       // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
       String storeId = "test_store_id";

       // 业务扩展参数,目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法),详情请咨询支付宝技术支持
       ExtendParams extendParams = new ExtendParams();
       extendParams.setSysServiceProviderId("2088100200300400500");

       // 支付超时,定义为120分钟
       String timeoutExpress = "120m";

       // 商品明细列表,需填写购买商品详细信息,
       List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();

       List<OrderItem> orderItemList = orderItemMapper.getByOrderNoUserId(orderNo, userId);
       for (OrderItem orderItem : orderItemList
               ) {
           GoodsDetail goods = GoodsDetail.newInstance(orderItem.getProductId().toString(), orderItem.getProductName(),
                   BigDecimalUtil.mul(orderItem.getCurrentUnitPrice().doubleValue(), new Double(100).doubleValue()).longValue(),
                   orderItem.getQuantity());
           goodsDetailList.add(goods);

       }
       // 创建扫码支付请求builder,设置请求参数
       AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
               .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
               .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
               .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
               .setTimeoutExpress(timeoutExpress)
               .setNotifyUrl(PropertiesUtil.getProperty("alipay.callback.url"))//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
               .setGoodsDetailList(goodsDetailList);

       /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
        *  Configs会读取classpath下的zfbinfo.properties文件配置信息,如果找不到该文件则确认该文件是否在classpath目录
        */
       Configs.init("zfbinfo.properties");

       /** 使用Configs提供的默认参数
        *  AlipayTradeService可以使用单例或者为静态成员对象,不需要反复new
        */
       AlipayTradeService tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();

       AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
       switch (result.getTradeStatus()) {
           case SUCCESS:
               logger.info("支付宝预下单成功: )");

               AlipayTradePrecreateResponse response = result.getResponse();
               dumpResponse(response);

               File folder = new File(path);
               if (!folder.exists()) {
                   folder.setWritable(true);
                   folder.mkdirs();
               }

               // 需要修改为运行机器上的路径
               //细节路径问题
               //根据外部订单号,生成路径,根据路径生成二维码,创建好文件加上新的文件名传到FTP服务器上
               //拼出URL地址
               String qrPath = String.format(path + "/qr-%s.png", response.getOutTradeNo());
               String qrFileName = String.format("qr-%s.png", response.getOutTradeNo());
               ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath);

               File targetFile = new File(path, qrFileName);
               FTPUtil.uploadFile(Lists.newArrayList(targetFile));
               logger.info("filePath:" + qrPath);
               String qrUrl = PropertiesUtil.getProperty("ftp.server.http.prefix") + targetFile.getName();
               resultMap.put("qrUrl", qrUrl);
               return ServiceResponse.createBySuccess(resultMap);

           case FAILED:
               logger.error("支付宝预下单失败!!!");
               return ServiceResponse.createByErrorMessage("支付宝预下单失败!!!");
           case UNKNOWN:
               logger.error("系统异常,预下单状态未知!!!");
               return ServiceResponse.createByErrorMessage("系统异常,预下单状态未知!!!");

           default:
               logger.error("不支持的交易状态,交易返回异常!!!");
               return ServiceResponse.createByErrorMessage("不支持的交易状态,交易返回异常!!!");
       }
   }
       // 简单打印应答
    private void dumpResponse(AlipayResponse response) {
        if (response != null) {
            logger.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
            if (StringUtils.isNotEmpty(response.getSubCode())) {
                logger.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
                        response.getSubMsg()));
            }
            logger.info("body:" + response.getBody());
        }
    }
    public  ServiceResponse aliCallback(Map<String ,String> params) {
        Long orderNo = Long.parseLong(params.get("out_trade_ no"));
        String tradeNo = params.get("trade_no");
        String tradeStatus = params.get("trade_status");
        Order order = orderMapper.selectByOrderNo(orderNo);
        if (order == null) {
            return ServiceResponse.createByErrorMessage("非快乐慕商城的订单,回调忽略");
        }
        if (order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()) {
            return ServiceResponse.createBySuccess("支付宝重复调用");
        }
        if (Const.AlipayCallback.TRADE_STATUS_TRADE_SUCCESS.equals(tradeStatus)) {
            order.setPaymentTime(DateTimeUtil.strToDate(params.get("gmt_payment")));
            order.setStatus(Const.OrderStatusEnum.PAID.getCode());
            orderMapper.updateByPrimaryKeySelective(order);
        }
        PayInfo payInfo = new PayInfo();
        payInfo.setUserId(order.getUserId());
        payInfo.setOrderNo(order.getOrderNo());
        payInfo.setPayPlatform(Const.PayPlatformEnum.ALIPAY.getCode());
        payInfo.setPlatformNumber(tradeNo);
        payInfo.setPlatformStatus(tradeStatus);

        payInfoMapper.insert(payInfo);

        return ServiceResponse.createBySuccess();
    }

    public ServiceResponse queryOrderPayStatus(Integer userId,Long orderNo){
       Order order = orderMapper.selectByUserIdAndOrderNo(userId,orderNo);
       if (order == null){
           return ServiceResponse.createByErrorMessage("用户没有该订单");
       }
        if (order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()) {
            return ServiceResponse.createBySuccess();
        }
        return ServiceResponse.createByError();
    }
}

3.下面是没有自动生成的两个sql语句

  <select id="selectByUserIdAndOrderNo" resultMap="BaseResultMap" parameterType="map">
    SELECT
    <include refid="Base_Column_List"/>
    FROM mmall_order
    where order_no = #{orderNo}
    and user_id = #{userId}

  </select>


  <select id="selectByOrderNo" resultMap="BaseResultMap" parameterType="long">
    SELECT 
    <include refid="Base_Column_List"/>
    FROM mmall_order
    WHERE order_no=#{orderNo}

  </select>

猜你喜欢

转载自blog.csdn.net/qq_41166135/article/details/81391124