和手机网站支付很相似,首先我们去网站下载对应的demo电脑网站支付
一.集成步骤
创建应用、配置密钥,这些准备步骤请看我先前写的准备集成支付宝的准备工作
1.添加依赖
<!-- thymeleaf模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
同样的,我们可以直接将demo中jar包导入到项目中,然后给项目使用,也可以将jar包添加到maven中,可以参考我之前写的手机网站支付手机网站支付
2.配置yml文件
# 沙箱账号
pay:
alipay:
gatewayUrl: https://openapi.alipaydev.com/gateway.do
app_id: 2016091500517039
merchant_private_key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCveherLJtuz6kaIpjqK5UoIjCru4jLeCx9rCYDFGN8FIQEh0iHEHbEvZ15zb50wkuhBEFEoRkPLrsg/CdaYl2qQly+OoPqNqFgQhcRu1qYAjO8aJAlajOYaJkcrC67DUlAIsU/yl8j5tc8Ik5RYzN9BjT2zNIXRoxhwytCX5STJT2ZEvQfkFdG0Hduud5eFLGFuC/mhJU+rdP2i6KZsDluf73VYmqC0JUs3pX+bVS1IV85cWpS/7F7mNR7t9hYCMZ9UJa7NLxJhh5JElwgZRozF0rLIkSN4K04VL9IHxwBQU6mFvnyxLzpF9P4HdPbq3w1AVEGUWcF3OGnOS7qCNBTAgMBAAECggEAMmNp1oJ5o6lH0rRqmpunOh4PQdEZJ+w7Ql8jjzDUnHW7rx01y2sD39zfEnHtJdQBKZxyLYXhD0YJACDIICEs6k4iGZHt/VxwnJZ9z16wVgQT3R9dfRDw/evTQ7OBu77F8P/LClVPWpzX43GqcZ5904HrxY7tKTfd6djEXEvb+yB00ErHisCLvaC2QNDq5kXBqNc9qNdULfWEvHOnALdgw39Qk5cIaGLSs/y9L67RtqN0SwdxZDViJkKsf9uhgHvjPfeGJvmT8nsOZpwT/9Woh0BdHPkbpiyocBUf/XVUSjqWzG8PS0Hj/FGac3M4y2yYN68a8LziapT7wUkoty3RsQKBgQDwP3YhPeWgMnXaa9vySUXVdT8O7b7Vv8XGrnfV6P4nlUmgLQaej2l8ju2YqnfbDXOMpWN8r6TSMhaUlwXFFhEL5yllcSFenk42O3VPYqOhkJK2YhIEkFC2+nH8DpXl7m1Tp8U0D/wxMddFccW+oiUHwGL72T0GZZiAvttBD5bGaQKBgQC6+3TOIHHcQUCQjpjuJXoLTOZ3ENY4p/qVbGuFWYHMfLHIPnZgpHkv8vum9H205Bo6XV9ybKVKdWU1uXZu/yEnkHhZGW8bgG+giB432efT2JQqA75IIo8frkuriJSL0ixfx59iJHGhks0N8ieLCKuqK8u35a2rrrxM6D7i7N7hWwKBgGq954BxfdqlUNOQ5JJLl+l1RGUfoJBbukXCMqAp+vIfVC0ElFJSqa2b21jfNI1w9ovg18kISRTTCFFQoFGmskA1nqDhmM/vShSyajaxPr6D+4tpG1RHwnTp5Ub2PAeC3bQzcFznVUeOO3UxTYibhhRhmBkJtiFndlCNe+D2SikxAoGAQFKahwJQSPXFkTUM1PfdeR+2NIV9PDZFFLwcbN4ysba/reQW8v4BloYfHfsDd4P0pdlTKVjIr8mczJOFc3+e1y5yyCvgtfRD8lSBGLOEdbMOnTl2bvg8hih+bX7powPlMfnJEYj58hw/ICoKgmC0NTElvphrWyEcM9S9NXFI5vsCgYEAxnYChqJ+4VXuNBF9wc6oebRYgGYWMEv0uhqa/7A0o6vsvXrd7QtQTdyeYxpBQLcsFJkKc1n5MFsrSY6FAFTVmBPMnYfQwH0OAYxKfytles3wMVxWbAwJwtxhZ1n3nGFHCES8rwPSa+5xZe6vzpYVUTgnjBfr4QL3dlQJKj51a+0=
alipay_public_key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtHjQ2gD1juu9F5Hxr1oy5c8So9EC7G6OlK4rJf98kvFj1GaDxUp9/WY7YMThC1VqTZn+T9FiEO7CI8/EXjiF/4n64NYtJFOtT7dplmQwoVHE5dOvprfR1ugUbeHLcQlUvbctKELCDrUHTe3/p2rCIH7TwKQoUOpP6yunyHardPOddUJEC4C7wZ11KwzTDaa1pU3kLb0Z/0DEte63aEq3fyt1M5UFD5sQgN7FZuW3s7sy5jaIJgkZbNTIl/lpcrNjPGXxZmK6qfiiA8LSFgQj2A0UPSNtDLdUnO0I211tWRfUVVDzviIdV1T9k+JhlPhLsYGRFTvsa9cRgwWL/lt7BQIDAQAB
return_url: http://zhouguoqing.natapp1.cc/callback/return
notify_url: http://zhouguoqing.natapp1.cc/callback/notify
Spring:
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
server:
port: 8888
我想说一下,这个地方的测试都是需要通过外网映射去实现,我这里的地址指定的是8888端口,我们外网映射工具可以使用natapp,具体的使用的方法可以查看我先前写的natapp使用方法natapp使用方法
3.AlipayProperties的基础文件
@Data
@Slf4j
@ConfigurationProperties(prefix = "pay.alipay")
public class AlipayConfig {
/** 支付宝gatewayUrl */
private String gatewayUrl;
/** 商户应用id */
private String app_id;
/** RSA私钥,用于对商户请求报文加签 */
private String merchant_private_key;
/** 支付宝RSA公钥,用于验签支付宝应答 */
private String alipay_public_key;
/** 签名类型 */
private String sign_type = "RSA2";
/** 格式 */
private String formate = "json";
/** 编码 */
private String charset = "UTF-8";
/** 同步地址 */
private String return_url;
/** 异步地址 */
private String notify_url;
/** 最大查询次数 */
private static int maxQueryRetry = 5;
/** 查询间隔(毫秒) */
private static long queryDuration = 5000;
/** 最大撤销次数 */
private static int maxCancelRetry = 3;
/** 撤销间隔(毫秒) */
private static long cancelDuration = 3000;
// 支付宝网关
public static String log_path = "C:\\";
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* @param sWord 要写入日志里的文本内容
*/
public static void logResult(String sWord) {
FileWriter writer = null;
try {
writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
writer.write(sWord);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private AlipayConfig() {}
/**
* PostContruct是spring框架的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。
*/
@PostConstruct
public void init() {
log.info(description());
}
public String description() {
StringBuilder sb = new StringBuilder("\nConfigs{");
sb.append("支付宝网关: ").append(gatewayUrl).append("\n");
sb.append(", appid: ").append(app_id).append("\n");
sb.append(", 商户RSA私钥: ").append(getKeyDescription(merchant_private_key)).append("\n");
sb.append(", 支付宝RSA公钥: ").append(getKeyDescription(alipay_public_key)).append("\n");
sb.append(", 签名类型: ").append(sign_type).append("\n");
sb.append(", 查询重试次数: ").append(maxQueryRetry).append("\n");
sb.append(", 查询间隔(毫秒): ").append(queryDuration).append("\n");
sb.append(", 撤销尝试次数: ").append(maxCancelRetry).append("\n");
sb.append(", 撤销重试间隔(毫秒): ").append(cancelDuration).append("\n");
sb.append("}");
return sb.toString();
}
private String getKeyDescription(String key) {
int showLength = 6;
if (StringUtils.isNotEmpty(key) && key.length() > showLength) {
return new StringBuilder(key.substring(0, showLength)).append("******")
.append(key.substring(key.length() - showLength)).toString();
}
return null;
}
}
4.将我们的配置文件加入Spring的Bean容器中
@Configuration
@EnableConfigurationProperties(AlipayConfig.class)
public class AlipayConfiguration {
@Autowired
private AlipayConfig properties;
@Bean
public AlipayTradeService alipayTradeService() {
return new AlipayTradeServiceImpl.ClientBuilder()
.setGatewayUrl(properties.getGatewayUrl())
.setAppid(properties.getApp_id())
.setPrivateKey(properties.getMerchant_private_key())
.setAlipayPublicKey(properties.getAlipay_public_key())
.setSignType(properties.getSign_type())
.build();
}
@Bean
public AlipayClient alipayClient(){
return new DefaultAlipayClient(properties.getGatewayUrl(),
properties.getApp_id(),
properties.getMerchant_private_key(),
properties.getFormate(),
properties.getCharset(),
properties.getAlipay_public_key(),
properties.getSign_type());
}
}
5.创建支付Controller
@RequestMapping("/pay")
@Controller
public class PayController {
@Autowired
private AlipayConfig properties;
/**
* 跳转到支付页面
* @param request
* @param response
* @throws Exception
*/
@RequestMapping("goPay")
public void goPay(HttpServletRequest request, HttpServletResponse response) throws Exception{
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(properties.getGatewayUrl(), properties.getApp_id(), properties.getMerchant_private_key(), "json", properties.getCharset(), properties.getAlipay_public_key(), properties.getSign_type());
//设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(properties.getReturn_url());
alipayRequest.setNotifyUrl(properties.getNotify_url());
//商户订单号,商户网站订单系统中唯一订单号,必填
String out_trade_no = new String(request.getParameter("WIDout_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//付款金额,必填
String total_amount = new String(request.getParameter("WIDtotal_amount").getBytes("ISO-8859-1"),"UTF-8");
//订单名称,必填
String subject = new String(request.getParameter("WIDsubject").getBytes("ISO-8859-1"),"UTF-8");
//商品描述,可空
String body = new String(request.getParameter("WIDbody").getBytes("ISO-8859-1"),"UTF-8");
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
+ "\"total_amount\":\""+ total_amount +"\","
+ "\"subject\":\""+ subject +"\","
+ "\"body\":\""+ body +"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//若想给BizContent增加其他可选请求参数,以增加自定义超时时间参数timeout_express来举例说明
//alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
// + "\"total_amount\":\""+ total_amount +"\","
// + "\"subject\":\""+ subject +"\","
// + "\"body\":\""+ body +"\","
// + "\"timeout_express\":\"10m\","
// + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//请求参数可查阅【电脑网站支付的API文档-alipay.trade.page.pay-请求参数】章节
//请求
String head="<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head>";
String result = alipayClient.pageExecute(alipayRequest).getBody();
String buttom="<body></body></html>";
//输出
response.getWriter().println(head+result+buttom);
}
/**
* 交易查询
* @param request
* @param trade_no
* @param out_trade_no
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping("query")
public String query(HttpServletRequest request,String trade_no,String out_trade_no) throws Exception{
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(properties.getGatewayUrl(), properties.getApp_id(), properties.getMerchant_private_key(), "json", properties.getCharset(), properties.getAlipay_public_key(), properties.getSign_type());
//设置请求参数
AlipayTradeQueryRequest alipayRequest = new AlipayTradeQueryRequest();
//商户订单号,商户网站订单系统中唯一订单号
String out_trade_no1 = new String(out_trade_no.getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no1 = new String(trade_no.getBytes("ISO-8859-1"),"UTF-8");
//请二选一设置
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no1 +"\","+"\"trade_no\":\""+ trade_no1 +"\"}");
//请求
String result = alipayClient.execute(alipayRequest).getBody();
//输出
//out.println(result);
return result.toString();
}
/**
* 退款
* @param request
* @return
*/
@ResponseBody
@RequestMapping("return")
public String tui(HttpServletRequest request,
String out_trade_no,String trade_no
,String refund_amount, String refund_reason,
String out_request_no) throws Exception{
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(properties.getGatewayUrl(), properties.getApp_id(), properties.getMerchant_private_key(), "json", properties.getCharset(), properties.getAlipay_public_key(), properties.getSign_type());
//设置请求参数
AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
//商户订单号,商户网站订单系统中唯一订单号
String out_trade_no1 = new String(out_trade_no.getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no1 = new String(trade_no.getBytes("ISO-8859-1"),"UTF-8");
//请二选一设置
//需要退款的金额,该金额不能大于订单金额,必填
String refund_amount1 = new String(refund_amount.getBytes("ISO-8859-1"),"UTF-8");
//退款的原因说明
String refund_reason1 = new String(refund_reason.getBytes("ISO-8859-1"),"UTF-8");
//标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
String out_request_no1 = new String(out_request_no.getBytes("ISO-8859-1"),"UTF-8");
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no1 +"\","
+ "\"trade_no\":\""+ trade_no1 +"\","
+ "\"refund_amount\":\""+ refund_amount1 +"\","
+ "\"refund_reason\":\""+ refund_reason1 +"\","
+ "\"out_request_no\":\""+ out_request_no1 +"\"}");
//请求
String result = alipayClient.execute(alipayRequest).getBody();
//输出
//out.println(result);
return result.toString();
}
/**
* 退款交易查询
* @param request
* @param trade_no
* @param out_trade_no
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping("Tkquery")
public String Tkquery(HttpServletRequest request,String trade_no,
String out_trade_no,
String out_request_no) throws Exception{
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(properties.getGatewayUrl(), properties.getApp_id(), properties.getMerchant_private_key(), "json", properties.getCharset(), properties.getAlipay_public_key(), properties.getSign_type());
//设置请求参数
AlipayTradeFastpayRefundQueryRequest alipayRequest = new AlipayTradeFastpayRefundQueryRequest();
//商户订单号,商户网站订单系统中唯一订单号
String out_trade_no1 = new String(out_trade_no.getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no1 = new String(trade_no.getBytes("ISO-8859-1"),"UTF-8");
//请二选一设置
//请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号,必填
String out_request_no1 = new String(out_request_no.getBytes("ISO-8859-1"),"UTF-8");
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no1 +"\","
+"\"trade_no\":\""+ trade_no1 +"\","
+"\"out_request_no\":\""+ out_request_no1 +"\"}");
//请求
String result = alipayClient.execute(alipayRequest).getBody();
//输出
//out.println(result);
return result.toString();
}
/**
* 关闭交易
* @param request
* @param trade_no
* @param out_trade_no
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping("close")
public String close(HttpServletRequest request,String trade_no,
String out_trade_no) throws Exception{
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(properties.getGatewayUrl(), properties.getApp_id(), properties.getMerchant_private_key(), "json", properties.getCharset(), properties.getAlipay_public_key(), properties.getSign_type());
//设置请求参数
AlipayTradeCloseRequest alipayRequest = new AlipayTradeCloseRequest();
//商户订单号,商户网站订单系统中唯一订单号
String out_trade_no1 = new String(out_trade_no.getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no1 = new String(trade_no.getBytes("ISO-8859-1"),"UTF-8");
//请二选一设置
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\"," +"\"trade_no\":\""+ trade_no +"\"}");
//请求
String result = alipayClient.execute(alipayRequest).getBody();
//输出
//out.println(result);
return result.toString();
}
/**
* billDate : 账单时间:日账单格式为yyyy-MM-dd,月账单格式为yyyy-MM。
* 查询对账单下载地址: https://docs.open.alipay.com/api_15/alipay.data.dataservice.bill.downloadurl.query/
* @param billDate
*/
@GetMapping("/bill")
@ResponseBody
public void queryBill(String billDate) {
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(properties.getGatewayUrl(), properties.getApp_id(), properties.getMerchant_private_key(), "json", properties.getCharset(), properties.getAlipay_public_key(), properties.getSign_type());
// 1. 查询对账单下载地址
AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
AlipayDataDataserviceBillDownloadurlQueryModel model = new AlipayDataDataserviceBillDownloadurlQueryModel();
model.setBillType("trade");
model.setBillDate(billDate);
request.setBizModel(model);
try {
AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
String billDownloadUrl = response.getBillDownloadUrl();
System.out.println(billDownloadUrl);
// 2. 下载对账单
List<String> orderList = this.downloadBill(billDownloadUrl);
System.out.println(orderList);
// 3. 先比较支付宝的交易合计/退款合计笔数/实收金额是否和自己数据库中的数据一致,如果不一致证明有异常,再具体找出那些订单有异常
// 查找支付宝支付成功而自己支付失败的记录和支付宝支付失败而自己认为支付成功的异常订单记录到数据库
} else {
// 失败
String code = response.getCode();
String msg = response.getMsg();
String subCode = response.getSubCode();
String subMsg = response.getSubMsg();
}
} catch (AlipayApiException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 下载下来的是一个【账号_日期.csv.zip】文件(zip压缩文件名,里面有多个.csv文件)
* 账号_日期_业务明细 : 支付宝业务明细查询
* 账号_日期_业务明细(汇总):支付宝业务汇总查询
*
* 注意:如果数据量比较大,该方法可能需要更长的执行时间
* @param billDownLoadUrl
* @return
* @throws IOException
*/
private List<String> downloadBill(String billDownLoadUrl) throws IOException {
String ordersStr = "";
CloseableHttpClient httpClient = HttpClients.createDefault();
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(60000)
.setConnectionRequestTimeout(60000)
.setSocketTimeout(60000)
.build();
HttpGet httpRequest = new HttpGet(billDownLoadUrl);
httpRequest.setConfig(config);
CloseableHttpResponse response = null;
byte[] data = null;
try {
response = httpClient.execute(httpRequest);
HttpEntity entity = response.getEntity();
data = EntityUtils.toByteArray(entity);
} finally {
response.close();
httpClient.close();
}
ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(data), Charset.forName("GBK"));
ZipEntry zipEntry = null;
try{
while( (zipEntry = zipInputStream.getNextEntry()) != null){
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try{
String name = zipEntry.getName();
// 只要明细不要汇总
if(name.contains("汇总")){
continue;
}
byte[] byteBuff = new byte[4096];
int bytesRead = 0;
while ((bytesRead = zipInputStream.read(byteBuff)) != -1) {
byteArrayOutputStream.write(byteBuff, 0, bytesRead);
}
ordersStr = byteArrayOutputStream.toString("GBK");
}finally {
byteArrayOutputStream.close();
zipInputStream.closeEntry();
}
}
} finally {
zipInputStream.close();
}
if (ordersStr.equals("")) {
return null;
}
String[] bills = ordersStr.split("\r\n");
List<String> billList = Arrays.asList(bills);
billList = billList.parallelStream().map(item -> item.replace("\t", "")).collect(Collectors.toList());
return billList;
}
}
6.创建通用的同步异步回调方法
@RequestMapping("/callback")
@Controller
public class CallBackController {
@Autowired
private AlipayConfig properties;
/**
* 同步回调,展示页面
* @param request
* @param response
* @return
* @throws Exception
*/
@RequestMapping("/return")
public ModelAndView returnUrl(HttpServletRequest request, HttpServletResponse response)throws Exception{
ModelAndView mv = new ModelAndView();
PrintWriter out = response.getWriter();
//获取支付宝GET过来反馈信息
Map<String,String> params = new HashMap<String,String>();
Map<String,String[]> requestParams = request.getParameterMap();
for (Iterator<String> 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] + ",";
}
//乱码解决,这段代码在出现乱码时使用
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
boolean signVerified = AlipaySignature.rsaCheckV1(params, properties.getAlipay_public_key(), properties.getCharset(), properties.getSign_type()); //调用SDK验证签名
//——请在这里编写您的程序(以下代码仅作参考)——
if(signVerified) {
System.out.println("Return 验签成功");
//商户订单号
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 total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
String result="trade_no:"+trade_no+"<br/>out_trade_no:"+out_trade_no+"<br/>total_amount:"+total_amount;
out.println(result);
mv.addObject("data",result);
mv.addObject("msg","验签成功");
}else {
out.println("验签失败");
}
mv.setViewName("/result");
return mv;
}
/**
* 异步回调
* @param request
* @param response
* @throws Exception
*/
@RequestMapping("/notify")
public void notifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception{
//获取支付宝POST过来反馈信息
Map<String,String> params = new HashMap<String,String>();
Map<String,String[]> requestParams = request.getParameterMap();
for (Iterator<String> 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] + ",";
}
//乱码解决,这段代码在出现乱码时使用
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
boolean signVerified = AlipaySignature.rsaCheckV1(params, properties.getAlipay_public_key(), properties.getCharset(), properties.getSign_type()); //调用SDK验证签名
//——请在这里编写您的程序(以下代码仅作参考)——
/* 实际验证过程建议商户务必添加以下校验:
1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
4、验证app_id是否为该商户本身。
*/
if(signVerified) {//验证成功
System.out.println("Notify 验签成功");
//商户订单号
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");
if(trade_status.equals("TRADE_FINISHED")){
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//如果有做过处理,不执行商户的业务程序
System.out.println("TRADE_FINISHED 执行");
//注意:
//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
}else if (trade_status.equals("TRADE_SUCCESS")){
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//如果有做过处理,不执行商户的业务程序
//处理真实的业务
System.out.println(System.currentTimeMillis()+"-------------"+ "TRADE_SUCCESS 执行");
//注意:
//付款完成后,支付宝系统发送该交易状态通知
}
response.getWriter().println("success");
}else {//验证失败
response.getWriter().println("fail");
//调试用,写文本函数记录程序运行情况是否正常
//String sWord = AlipaySignature.getSignCheckContentV1(params);
//AlipayConfig.logResult(sWord);
}
}
}
7.创建全局地址的转换类
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/pay/index").setViewName("index");
super.addViewControllers(registry);
}
}
8.页面
测试的时候,所有的页面都可以使用demo中的页面,具体业务中我们只需要调用相应的方法就可以了
二.运行效果
备注:项目源码我放在github上
https://github.com/ZGQ1996/netpay.git