一. 前言介绍:
前几天突然要做支付宝的支付功能,因为以前一直没有做过支付功能,所以比较茫然,但是后来经过不断摸索和前辈指导,终于做了出来;后来发现,其实做支付宝的支付功能也并不难。
二.正文:
首先你要搞到商家的支付宝账号,合作者ID
(1).第一步要先能够跳转到支付宝的支付界面(可以本地测试)。
(2).第二部完成支付跳转回商家界面(必须线上测试,因为返回回来,支付宝找不到你的localhost:8080;所以必须要有域名(地址))。
首先在支付宝官网下载java的即时支付包,然后根据自己所需要,拷贝进它的源代码,也可以全部拷入,但是不一定全部能用。
对于:数据交互方式可以用jsp,也可以用控制器。支付宝给的demo是用的jsp实现。
而我们用的是控制器实现;线面就用控制器介绍:
代码:
package com...web.alipay;
@Controller
@RequestMapping(value = "/alipay")
public class alipayController {
@Autowired
private AlipayService alipayService;
@Autowired
private ProjectService projectService;
@Autowired
private ProjectAcceleratorService projectAcceleratorService;
//跳转支付宝网站的方法
@RequestMapping(value = "/deposit", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity deposit(HttpServletRequest request,HttpServletResponse response,Model model){
//防钓鱼时间戳
防钓鱼时间戳这里没写,貌似要先去支付宝申请,要审核一个星期左右,通过了才能用
Date date = new Date();
// 支付类型
// 必填,不能修改
String payment_type = "1";
// 服务器异步通知页面路径
// 需http://格式的完整路径,不能加?id=123这类自定义参数
String notify_url = "http://“自己网站的域名”/alipay/async";
// 页面跳转同步通知页面路径
// 需http://格式的完整路径,不能加?id=123这类自定义参数,不能写成http://localhost/
String return_url = "http://“自己网站的域名”/alipay/return_url";
// 商户订单号.
// 商户网站订单系统中唯一订单号,必填
//String out_trade_no = date.getTime() + "";
// 订单名称
// 必填
String projectId = request.getParameter("projectId");
if(projectId != null){
ProjectEntity project = projectService.getProject(projectId);
if(project != null){
//从支付页面获取值
//商品名称
String subject = project.getName();
//String WIDout_trade_no = request.getParameter("WIDout_trade_no");
// 防钓鱼时间戳
// 若要使用请调用类文件submit中的query_timestamp函数
//String anti_phishing_key = "";
// 客户端的IP地址
// 非局域网的外网IP地址,如:
String exter_invoke_ip = ""; 可不填
String total_fee = project.getReward();
String body = project.getSummary();
//商品展示地址
String show_url = "";可不填
//需以http://开头的完整路径,例如:http://www.xxx.com/myorder.html
Map sParaTemp = new HashMap();
sParaTemp.put("service", "create_direct_pay_by_user");//接口服务----即时到账
sParaTemp.put("partner", AlipayConfig.partner);//支付宝PID
sParaTemp.put("_input_charset", AlipayConfig.input_charset);//统一编码
sParaTemp.put("payment_type", payment_type);//支付类型
sParaTemp.put("notify_url", notify_url);//异步通知页面
sParaTemp.put("return_url", return_url);//页面跳转同步通知页面
sParaTemp.put("seller_email", "");//卖家支付宝账号
sParaTemp.put("out_trade_no", date.getTime()+payment_type);//商品订单编号
sParaTemp.put("subject", subject);//商品名称
sParaTemp.put("total_fee", total_fee);//价格
sParaTemp.put("body", body);
sParaTemp.put("extra_common_param", extra_common_param);
sParaTemp.put("show_url", show_url);
//sParaTemp.put("anti_phishing_key", anti_phishing_key);
sParaTemp.put("exter_invoke_ip", exter_invoke_ip);
String sHtmlText = AlipaySubmit.buildRequest(sParaTemp,"get","确认");
try {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setContentType("text/html; charset=utf-8");
response.getWriter().write(sHtmlText);
response.getWriter().close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
@SuppressWarnings("rawtypes")
@RequestMapping(value="/async",method = RequestMethod.POST)
public String async(HttpServletRequest request,HttpServletResponse response){
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] + ",";
}
params.put(name, valueStr);
}
//获取返回数据
String orderTitle = request.getParameter("subject");//订单名称
String payType = request.getParameter("payment_type");//支付类型
String outTradeNo = request.getParameter("out_trade_no");//订单号
String tradeNo = request.getParameter("trade_no");//支付宝交易号
String notifyId = request.getParameter("notify_id");//支付校验id
String amount = request.getParameter("total_fee");//交易金额
String notifyTime = request.getParameter("notify_time");//通知时间
String tradeStatus = request.getParameter("trade_status");//交易状态
String returnId = request.getParameter("extra_common_param");//项目id
String payer = request.getParameter("buyer_email");//支付者账号
//
if(AlipayNotify.verify(params)){//验证成功
if(tradeStatus.equals("TRADE_FINISHED") || tradeStatus.equals("TRADE_SUCCESS")) {
//要写的逻辑。自己按自己的要求写
//封装交易信息实体,存入数据库之类的
System.out.println(">>>>>异步返回:" + tradeNo);
}
return "success/alipay-success";
}else{//验证失败
return "success/alipay-fail";
}
}
@RequestMapping(value="/return_url",method = RequestMethod.GET)
public String Return_url(HttpServletRequest request,HttpServletResponse response){
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] + ",";
}
params.put(name, valueStr);
}
String tradeNo = request.getParameter("trade_no");//支付宝交易号
String tradeStatus = request.getParameter("trade_status");//交易状态
if(AlipayNotify.verify(params)){//验证成功
if(tradeStatus.equals("TRADE_FINISHED") || tradeStatus.equals("TRADE_SUCCESS")) {
//要写的逻辑。自己按自己的要求写
System.out.println(">>>>>充值成功" + tradeNo);
}
return "...";
}else{//验证失败
return "success/fail";
}
}
}
支付流程:
先访问 /deposit 映射下面的方法 ---> 跳转到支付宝的支付界面 ---> 核对支付信息进行支付 (测试一般用1分钱)--->支付成功 --->支付宝同时调用同步和异步方法;
但是异步方法一般要快于同步方法,因为中间还有一个跳转流程。所以这里特别注意的是:如果你要讲支付宝返回来的信息存入数据库,逻辑一般是写在异步方法里面,同步方法作为页面跳转(跳你自己的网站页面)。如果把逻辑写在同步方法里面,客户在支付成功直接关闭窗口,没返回你的网站的话,它是访问不到你的控制器的。
而且对于异步方法访问的方法是要在浏览器上直接访问到的!但是一般我们网站都做了权限过滤的,直接方法方法,要先去判断是否登录,没登录一般跳转登录界面。但是不论你是用的过滤器还是 shiro,还是其它的,总之你要暴露出这个方法要让支付宝能访问(不能够跳登录界面)!
并且这个异步方法返回的jsp不能有其它代码:
我就只写了: <%=%>
支付宝回调问题:
支付宝每个订单异步回调通知的频率是15s 3m 10m 30m 30m 1h 2h 6h 15h
如果不返回 "success" , 支付宝就认为没有回调成功,就会一直回调