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

<bean class="cn.itrip.trade.config.AlipayConfig"><property name="appID" value="沙箱账号中的appid"/><property name="rsaPrivateKey" value="应用私钥"/><property name="notifyUrl" value="http://服务器ip:端口/tradedemo/api/notify"/><property name="returnUrl" value="http://服务器ip:端口/tradedemo/api/return"/><property name="url" value="沙箱账号中的支付宝网关"/><property name="charset" value="GBK"/><property name="format" value="json"/><property name="alipayPublicKey" value="支付宝公钥"/><property name="logPath" value="/logs"/><property name="signType" value="RSA2"/><property name="paymentSuccessUrl" value="http://服务器ip:端口/tradedemo/success.jsp"/><property name="paymentFailureUrl" value="http://服务器ip:端口/tradedemo/fail.jsp"/></bean>

2.AlipayConfig.java

public class AlipayConfig {// 商户appidprivate  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 ;// RSA2private  String signType ;private  String paymentSuccessUrl;private  String paymentFailureUrl;
...省略get set方法}

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

@Controller
@RequestMapping("/api")
public class AlipaymentController {@Resourceprivate OrderService orderService;@Resourceprivate 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";}elsereturn "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 blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//异步通知@RequestMapping(value = "/notify",method=RequestMethod.POST)public void trackPaymentStatus(HttpServletRequest request,HttpServletResponse response) {try {// 获取支付宝POST过来反馈信息Map<String, String> params = new HashMap<String, String>();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<String, String> 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 blocke.printStackTrace();} catch (AlipayApiException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}@RequestMapping(value = "/return", method = RequestMethod.GET)public void callback(HttpServletRequest request,HttpServletResponse response) {System.out.println("=========>同步通知");try {//获取支付宝GET过来反馈信息Map<String,String> params = new HashMap<String,String>();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<String, String> 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 blocke.printStackTrace();} catch (AlipayApiException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (Exception e) {// TODO Auto-generated catch blocke.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 {@Resourceprivate ItripHotelOrderMapper itripHotelOrderMapper;@Resourceprivate SystemConfig systemConfig;@Overridepublic ItripHotelOrder loadItripHotelOrder(String orderNo) throws Exception {Map map = new HashMap();map.put("orderNo",orderNo);List<ItripHotelOrder> orderList = itripHotelOrderMapper.getItripHotelOrderListByMap(map);if(orderList.size()>0){return orderList.get(0);}return null;}@Overridepublic 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);}@Overridepublic 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);}@Overridepublic boolean processed(String orderNo) throws Exception {// TODO Auto-generated method stubItripHotelOrder 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"%><!DOCTYPE html>
<html><head><title>支付宝手机网站支付接口</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>*{margin:0;padding:0;}ul,ol{list-style:none;}body{font-family: "Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;}.hidden{display:none;}.new-btn-login-sp{padding: 1px;display: inline-block;width: 75%;}.new-btn-login {background-color: #02aaf1;color: #FFFFFF;font-weight: bold;border: none;width: 100%;height: 30px;border-radius: 5px;font-size: 16px;}#main{width:100%;margin:0 auto;font-size:14px;}.red-star{color:#f00;width:10px;display:inline-block;}.null-star{color:#fff;}.content{margin-top:5px;}.content dt{width:100px;display:inline-block;float: left;margin-left: 20px;color: #666;font-size: 13px;margin-top: 8px;}.content dd{margin-left:120px;margin-bottom:5px;}.content dd input {width: 85%;height: 28px;border: 0;-webkit-border-radius: 0;-webkit-appearance: none;}#foot{margin-top:10px;position: absolute;bottom: 15px;width: 100%;}.foot-ul{width: 100%;}.foot-ul li {width: 100%;text-align:center;color: #666;}.note-help {color: #999999;font-size: 12px;line-height: 130%;margin-top: 5px;width: 100%;display: block;}#btn-dd{margin: 20px;text-align: center;}.foot-ul{width: 100%;}.one_line{display: block;height: 1px;border: 0;border-top: 1px solid #eeeeee;width: 100%;margin-left: 20px;}.am-header {display: -webkit-box;display: -ms-flexbox;display: box;width: 100%;position: relative;padding: 7px 0;-webkit-box-sizing: border-box;-ms-box-sizing: border-box;box-sizing: border-box;background: #1D222D;height: 50px;text-align: center;-webkit-box-pack: center;-ms-flex-pack: center;box-pack: center;-webkit-box-align: center;-ms-flex-align: center;box-align: center;}.am-header h1 {-webkit-box-flex: 1;-ms-flex: 1;box-flex: 1;line-height: 18px;text-align: center;font-size: 18px;font-weight: 300;color: #fff;}
</style>
</head>
<body text=#000000 bgColor="#ffffff" leftMargin=0 topMargin=4>
<header class="am-header"><h1>确认订单信息</h1>
</header>
<div id="main"><form name=alipayment action='../pay' method="post"><div id="body" style="clear:left"><dl class="content"><dt>订单编号:</dt><dd>${orderNo}<input type="hidden" name="WIDout_trade_no" value="${orderNo}"><input type="hidden" name="WIDsubject" value="${hotelName}"><input type="hidden" name="WIDtotal_amount" value="${payAmount}"></dd><hr class="one_line"><dt>酒店名称:</dt><dd>${hotelName}</dd><hr class="one_line"><dt>付款金额:</dt><dd>¥${payAmount}</dd><hr class="one_line"/><dt>订房描述:</dt><dd>房间ID:${roomId},数量:${count}</dd><hr class="one_line"><dt></dt><dd id="btn-dd"><span class="new-btn-login-sp"><button class="new-btn-login" type="submit" style="text-align:center;">确 认</button></span><span class="note-help">如果您点击“确认”按钮,即表示您同意该次的执行操作。</span></dd></dl></div></form><div id="foot"><ul class="foot-ul"><li>版权信息</li></ul></div></div>
</body></html>

支付失败页面:failure.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<html>
<body>
<h2>支付失败!</h2>
</body>
</html>

支付成功页面:success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<html>
<body>
<h2>支付成功!</h2>
</body>
</html>

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是否有值。如果正确说明整个支付代码无误。

爱旅行项目中实现支付宝支付相关推荐

  1. 爱旅行项目中完成微信支付

    1.配置微信支付的部分请求参数 <!-- 微信手机网站支付 --><bean class="cn.itrip.trade.config.WXPayConfig" ...

  2. java项目中使用支付宝支付(手机端,web端)--菜鸟小回

    java项目中使用支付宝支付(手机端,web端) 文章目录 java项目中使用支付宝支付(手机端,web端) @[toc] 一.Spring boot项目代码 二.支付宝沙箱环境配置 1. 因为上面c ...

  3. 手把手教你如何在自己的项目中引入支付宝支付

    一 登录支付宝开发平台 首先我们需要进入支付宝开发平台https://open.alipay.com/,使用自己的支付宝登录扫码后,进入到此界面,单击控制台 接着拉到最后,选择沙箱 选择沙箱工具-支付 ...

  4. 爱旅行项目中使用任务调度

    在itrip-biz模块中搭建起SSM环境,将下面素材复制到工程中resources目录下: 2.下面进行注解式任务调度的配置 在springmvc-servlet.xml中添加如下配置: <b ...

  5. 爱旅行项目中实现邮箱注册

    实现邮箱注册需要发送电子邮件,使用spring发送电子邮件会使用到两个类,JavaMailSenderImpl这个类用来发送电子邮件,org.springframework.mail.SimpleMa ...

  6. 爱旅行项目中使用solr实现酒店搜索

    准备工作: 在酒店搜索业务中,搜索内容来自于多张表,查询语句比较复杂.素材中会有提供 我们只需要把提供的solr_home覆盖掉练习时的solr_home即可. 接下来即可在itrip-search模 ...

  7. 爱旅行项目中实现手机注册

    实现手机注册的流程图: 客户端向应用服务器发出手机注册申请,在应用服务器生成短信验证码,通过短信服务商将短信发送到手机,并且回调通知给应用程序. 接入步骤 1)注册开发者账号 注册账号网址:www.y ...

  8. 爱旅行项目-环境搭建

    爱旅行项目-环境搭建 B2C 商家对客户 professional专业的 前后端分离:前端只负责进行数据显示 后端只负责接口的提供 后端通常以一个对象来返回数据 酒店模块: 1.注册 登录 首页查看推 ...

  9. 项目中的第三方支付接口

    在项目中遇到需要进行支付的场景,需要接入第三方资金管理平台,这里以支付宝为例介绍一下项目中遇到资金管理接口的使用: 进入支付宝官网(https://www.alipay.com/),进入"我 ...

最新文章

  1. 戴着口罩如何进行人脸识别?快进来看看吧!
  2. P1291 [SHOI2002]百事世界杯之旅
  3. rocksdb和leveldb的bloom filter比较
  4. Less (一种动态样式语言)
  5. 《终身成长》读书笔记(part3)--如果一个人能学会什么东西,那么世界上其他人也都可以学会
  6. 使用MinGW编译Psycopg2
  7. 太阳直射点纬度计算公式_全纬度昼夜长短通用公式
  8. java 只有日期的类_【你不知道的事系列】Java中处理日期的类
  9. SpringApplication#run⽅法的第6步,创建ApplicationContext(五)
  10. 温度冲击试验箱军标GJB 150与GB 2423区别
  11. 你真的懂Linux吗?Linux运维从业方向与前景
  12. Dbgview 罕见的一次报错问题解决
  13. 应重视物联网的负面影响
  14. FBReader工程结构解析
  15. FormData兼容性问题
  16. RTX3070深度学习环境配置
  17. Processing 入门教程(二十一) 利用数组产生雪花坠落效果
  18. chrome浏览器扩展打包成crx
  19. [前端基础] 浏览器篇
  20. 003 C语言 输出名言

热门文章

  1. Unity3D打砖块游戏入门教程
  2. C# 高仿腾讯QQ (TextBox控件美化)(附源码)
  3. Oracle数据库练习题
  4. git多台电脑代码同步php,如何在多台电脑同步代码
  5. MySQL长途售票系统_基于SSH的长途汽车票务售票系统的设计(Struts2,MySQL)(含录像)...
  6. SAS数据清洗和加工
  7. CAD中怎么设置线宽?CAD图纸打印出来线条太粗怎么办?
  8. sklearn预测pima糖尿病
  9. idea怎么和mysql连接并执行_IDEA 与MySQL连接问题
  10. iOS的影片播放 MediaPlayer 和 AVPlayer