爱旅行项目中实现支付宝支付

在ssm框架的基础上,按照以下步骤完成支付功能
1.配置文件
applicationContext-alipay.xml


		
		
		
		
		
		
		
		
		
		
		
		
	

2.AlipayConfig.java

public class AlipayConfig {
    // 商户appid
    private  String appID;
    // 私钥 pkcs8格式的
    private  String rsaPrivateKey ;
    // 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    private  String notifyUrl;
    //public static String notify_url = "http://itrip.project.bdqn.cn/trade/api/notify";
    // 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
    private  String returnUrl ;
    // 请求网关地址
    private  String url ;
    // 编码
    private  String charset ;
    // 返回格式
    private  String format ;
    // 支付宝公钥
    private  String alipayPublicKey;
    // 日志记录目录
    private  String logPath ;
    // RSA2
    private  String signType ;

    private  String paymentSuccessUrl;

    private  String paymentFailureUrl;
...省略get set方法
    }

3.在AlipaymentController.java中完成订单确认,发送支付请求,异步通知,同步通知

@Controller
@RequestMapping("/api")
public class AlipaymentController {
    @Resource
    private OrderService orderService;

    @Resource
    private AlipayConfig alipayConfig;

    //订单确认
    @RequestMapping(value = "/prepay/{orderNo}", method = RequestMethod.GET)
    public String prePay(@PathVariable String orderNo, ModelMap model) {
        try {
            ItripHotelOrder order = orderService.loadItripHotelOrder(orderNo);
            //System.out.println("=======>order:"+order.getOrderNo());
            if (!EmptyUtils.isEmpty(order)) {
                model.addAttribute("hotelName", order.getHotelName());
                model.addAttribute("roomId", order.getRoomId());
                model.addAttribute("count", order.getCount());
                model.addAttribute("payAmount", order.getPayAmount());
                return "pay";
            }else
                return "notfound";
        } catch (Exception e) {
            e.printStackTrace();
            return "error";
        }
    }

    //发送支付请求
    @RequestMapping(value = "/pay", method = RequestMethod.POST)
    public void pay(@RequestParam String WIDout_trade_no,
                    @RequestParam String WIDsubject,
                    @RequestParam String WIDtotal_amount,
                    HttpServletResponse response) {
        // 超时时间 可空
        String timeout_express = "2m";
        // 销售产品码 必填
        String product_code = "QUICK_WAP_PAY";
        /**********************/
        // SDK 公共请求类,包含公共请求参数,以及封装了签名与验签,开发者无需关注签名与验签
        // 调用RSA签名方式
        AlipayClient client = new DefaultAlipayClient(alipayConfig.getUrl(),
                alipayConfig.getAppID(), alipayConfig.getRsaPrivateKey(),
                alipayConfig.getFormat(), alipayConfig.getCharset(),
                alipayConfig.getAlipayPublicKey(), alipayConfig.getSignType());

        AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();

        // 封装请求支付信息
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(WIDout_trade_no);
        model.setSubject("subject");
        model.setTotalAmount(WIDtotal_amount);
        model.setTimeoutExpress(timeout_express);
        model.setProductCode(product_code);

        alipay_request.setBizModel(model);
        // 设置异步通知地址
        alipay_request.setNotifyUrl(alipayConfig.getNotifyUrl());
        // 设置同步地址
        alipay_request.setReturnUrl(alipayConfig.getReturnUrl());
        // form表单生产
        String form = "";
        try {
            // 调用SDK生成表单
            form = client.pageExecute(alipay_request).getBody();
            System.out.println(form);
            response.setContentType("text/html;charset="
                    + alipayConfig.getCharset());
            response.getWriter().write(form);// 直接将完整的表单html输出到页面
            response.getWriter().flush();
            response.getWriter().close();
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    //异步通知
    @RequestMapping(value = "/notify",method=RequestMethod.POST)
    public void trackPaymentStatus(HttpServletRequest request,
                                   HttpServletResponse response) {
        try {
            // 获取支付宝POST过来反馈信息
            Map params = new HashMap();
            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] + ",";
                }
                // 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
                // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
                params.put(name, valueStr);
            }
            // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
            // 商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no")
                    .getBytes("ISO-8859-1"), "UTF-8");
            // 支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes(
                    "ISO-8859-1"), "UTF-8");
            // 交易状态
            String trade_status = new String(request.getParameter("trade_status")
                    .getBytes("ISO-8859-1"), "UTF-8");

            // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
            // 计算得出通知验证结果
            // boolean AlipaySignature.rsaCheckV1(Map params, String
            // publicKey, String charset, String sign_type)
            boolean verify_result = AlipaySignature.rsaCheckV1(params,
                    alipayConfig.getAlipayPublicKey(),
                    alipayConfig.getCharset(), "RSA2");

            if (verify_result) {// 验证成功
                // ////////////////////////////////////////////////////////////////////////////////////////
                // 请在这里加上商户的业务逻辑程序代码

                //即时到账普通版,那么这时的交易状态值为:  TRADE_FINISHED;如果是即时到账高级版,此时的交易状态值就为:TRADE_SUCCESS
                //收到TRADE_FINISHED请求后,这笔订单就结束了,支付宝不会再主动请求商户网站了;收到TRADE_SUCCESS请求后,后续一定还有至少一条通知记录,即TRADE_FINISHED。
                if (trade_status.equals("TRADE_FINISHED")) {
                    // 判断该笔订单是否在商户网站中已经做过处理
                    // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                    // 请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                    // 如果有做过处理,不执行商户的业务程序
                    if(!orderService.processed(out_trade_no))
                    {
                        orderService.paySuccess(out_trade_no, 2,trade_no);
                    }
                    // 注意:
                    // 如果签约的是可退款协议,退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
                    // 如果没有签约可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
                } else if (trade_status.equals("TRADE_SUCCESS")) {
                    // 判断该笔订单是否在商户网站中已经做过处理
                    // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                    // 请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                    // 如果有做过处理,不执行商户的业务程序
                    if(!orderService.processed(out_trade_no))
                    {
                        orderService.paySuccess(out_trade_no, 2,trade_no);
                    }

                    // 注意:
                    // 如果签约的是可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
                }

                response.getWriter().println("success"); // 请不要修改或删除

                // ////////////////////////////////////////////////////////////////////////////////////////
            } else {// 验证失败
                orderService.payFailed(out_trade_no, 1,trade_no);
                response.getWriter().println("fail");
            }
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @RequestMapping(value = "/return", method = RequestMethod.GET)
    public void callback(HttpServletRequest request,
                         HttpServletResponse response) {
        System.out.println("=========>同步通知");
        try {
            //获取支付宝GET过来反馈信息
            Map params = new HashMap();
            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] + ",";
                }
                //乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
                valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                params.put(name, valueStr);
            }

            //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
            //计算得出通知验证结果
            //boolean AlipaySignature.rsaCheckV1(Map params, String publicKey, String charset, String sign_type)
            boolean verify_result = AlipaySignature.rsaCheckV1(params,
                    alipayConfig.getAlipayPublicKey(),
                    alipayConfig.getCharset(), "RSA2");

            if(verify_result){//验证成功
                String id=orderService.loadItripHotelOrder(out_trade_no).getId().toString();
                //提示支付成功

                response.sendRedirect(
                        String.format(alipayConfig.getPaymentSuccessUrl(),out_trade_no,id));
            }else{
                //提示支付失败
                response.sendRedirect(alipayConfig.getPaymentFailureUrl());
            }
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

4.在Controller层需要依赖业务层的方法,所以需要在业务层完成加载酒店订单,判断订单是否已经被处理过,支付成功修改订单状态,支付失败修改订单状态。
接口OrderService.java

public interface OrderService {
    /**
     * 加载酒店订单
     * @param  orderNo
     * @return
     * @throws Exception
     */
    public ItripHotelOrder loadItripHotelOrder(String orderNo) throws Exception;

    /**
     * 判断该订单是否已被处理过(被更新为已支付状态)
     * @param orderNo
     * @return
     * @throws Exception
     */
    public boolean processed(String orderNo) throws Exception;
    /**
     * 支付成功
     * @param orderNo 订单编号
     * @param payType 支付方式:1:支付宝 2:微信 3:到店付
     * @param tradeNo 支付平台返回的交易码
     * @throws Exception
     */
    public void paySuccess(String orderNo, int payType, String tradeNo) throws Exception;
    /**
     * 支付失败
     * @param orderNo 订单编号
     * @param payType 支付方式:1:支付宝 2:微信 3:到店付
     * @param tradeNo 支付平台返回的交易码
     * @throws Exception
     */
    public void payFailed(String orderNo, int payType, String tradeNo) throws Exception;

}

实现类OrderServiceImpl.java

@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private ItripHotelOrderMapper itripHotelOrderMapper;
    @Resource
    private SystemConfig systemConfig;

    @Override
    public ItripHotelOrder loadItripHotelOrder(String orderNo) throws Exception {
        Map map = new HashMap();
        map.put("orderNo",orderNo);
        List orderList = itripHotelOrderMapper.getItripHotelOrderListByMap(map);
        if(orderList.size()>0){
            return orderList.get(0);
        }
        return null;
    }

    @Override
    public void paySuccess(String orderNo, int payType,String tradeNo) throws Exception {
        ItripHotelOrder itripHotelOrder=this.loadItripHotelOrder(orderNo);
        itripHotelOrder.setOrderStatus(2);//支付成功
        itripHotelOrder.setPayType(payType);
        itripHotelOrder.setTradeNo(tradeNo);//交易号(如支付宝交易号)
        itripHotelOrderMapper.updateItripHotelOrder(itripHotelOrder);

        //增加订单后续待处理记录
        /*ItripTradeEnds itripTradeEnds=new ItripTradeEnds();
        itripTradeEnds.setId(itripHotelOrder.getId());
        itripTradeEnds.setOrderNo(itripHotelOrder.getOrderNo());
        itripTradeEndsMapper.insertItripTradeEnds(itripTradeEnds);*/
        //通知业务模块后续处理
        //sendGet(systemConfig.getTradeEndsUrl(),"orderNo="+orderNo);
    }

    @Override
    public void payFailed(String orderNo, int payType,String tradeNo) throws Exception {
        ItripHotelOrder itripHotelOrder=this.loadItripHotelOrder(orderNo);
        itripHotelOrder.setOrderStatus(1);//支付状态:已取消
        itripHotelOrder.setPayType(payType);
        itripHotelOrder.setTradeNo(tradeNo);//交易号(如支付宝交易号)
        itripHotelOrderMapper.updateItripHotelOrder(itripHotelOrder);
    }

    @Override
    public boolean processed(String orderNo) throws Exception {
        // TODO Auto-generated method stub
        ItripHotelOrder itripHotelOrder=this.loadItripHotelOrder(orderNo);
        return itripHotelOrder.getOrderStatus().equals(2)
                &&!EmptyUtils.isEmpty(itripHotelOrder.getTradeNo());
    }
    }

5.页面
确认支付页面pay.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>



	
	支付宝手机网站支付接口
	



确认订单信息

订单编号:
${orderNo}

酒店名称:
${hotelName}

付款金额:
¥${payAmount}

订房描述:
房间ID:${roomId},数量:${count}

如果您点击“确认”按钮,即表示您同意该次的执行操作。

支付失败页面:failure.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>


支付失败!

支付成功页面:success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>


支付成功!

6.测试需要将itrip-trade模块打成war包上传到云服务器
需要在数据中订单表中插入一条数据,表示用户的下单,该订单状态为0(未支付)

INSERT INTO `itrip_hotel_order`(`id`,`userId`,`orderNo`,`hotelId`,`hotelName`,`roomId`, `count`,`bookingDays`,`payAmount`,`checkInDate`,`checkOutDate`,`orderStatus`, `creationDate`) 
VALUES (302,29,'D10000012019022301114314aff8',1,'北京首都大酒店',2,1,1,600,NOW(),DATE_ADD(NOW(),INTERVAL 1 DAY),0,NOW())

浏览器地址栏输入:
http://服务器ip:端口/tradedemo/api/prepay/需要支付的订单号
完成整个支付过程后,查看是否跳转到支付成功页success.jsp,及数据库中订单状态orderStatus是否修改为2,交易号tradeNo是否有值。如果正确说明整个支付代码无误。

你可能感兴趣的:(爱旅行项目)