AliPay - Java支付宝接口开发(一)
AliPay - Java支付宝接口开发(二)
二、支付宝沙箱环境集成Web项目1、将支付宝Demo中的相关文件复制到我们的项目中
1.1 Maven以外的Jar包(红框部分)(主要2个,还有2个是对应的源码)
1.2 Maven以内的Jar包(最好版本号都一样,以免出现意想不到的事)
<dependencies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
1.3 上面是jar包的配置,接下来我们在pom.xml里面配置一个插件,使项目编译需要的jar在项目部署的时候自动将 lib 包里的Jar添加到项目依赖中
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<extdirs>${project.basedir}/src/main/webapp/WEB-INF/lib</extdirs>
</compilerArguments>
</configuration>
</plugin>
1.4 zhifubao.properties这个配置文件方法我们项目中的 resources目录下
open_api_domain = https://openapi.alipaydev.com/gateway.do
mcloud_api_domain = http://mcloudmonitor.com/gateway.do
pid = 2088102180444972
appid = 2016102100728313
private_key = MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCKQ2pEIzXM4IoN1cMzOFXdlk8yVX2cKXWITZ92EGAQQcRytaV07yQOaz3UE9KTeT9Nu628G+HZMsJUxQjEUETagmY5nLtbeL35M2UcibYpM3e2gVTtUW86CA65GCdLzUhdIug8yf2F9zWayzG4sHZ9DcTezG6ZjFu+EtDpFgg+CtqY7n/ihjTIqeE1lX0C2ZIKpIYs7QjR8AztB/qRcpOJKRfMKGDgmT9GALN8LeFEYCbQ+W/GJHN8bQ0Bk1Ll6EKQ4cHXZ1Yko+aXaRfbXfUZYgD9hwAVlxtwZndgeFX8KapOCw0J25pzV4WkutIjMlt7I2Q1jaWNoKLuxtz4M2mzAgMBAAECggEAAhnsL4TpeGehMXyiLtEYXPm/0mACPLFUm/GyDrVJAHY/ag7gqNpJjf6LPgHfHWamU6Qai9VQpWBkG62y6Gjf4wJAU3fSUR2QpYzmaHyfTBkAJMHqbIDkU9lzf9SiJEDGbMPvC512QOb05ZlY9Bmac2QWLdylgafkbQsUKbawAWFa/BAOMIp0tgYLW8/yY2aG6jeLqhOgTo8MWIW5d1qHtX5m/x7g97dYYMdX3kTo2i1dFLUVfEOvZe4US6VBvLg71dMxwadVF5YMaY9jq/ShPD0Gkf29wdThwsjcH6u9Tq/KArQTK+z02DAGkdWOcue3pHql+gvoIA8U5uFDdIeYwQKBgQDri3jPkDKi48efdKQk38rn+CJYeNFNRAhlly3h2AHaFEY92XRlBsho/vGFg43BvHu+cMz0Run4SS8Vo09vcTIY6p2xNMffjR0w2gQqx6PUdGHBFtw7FavxN4uVtVhL6uTAqfBv97mqQO0bq+DhOGwSRNIWqvnzfXywqwmXhKYECwKBgQCWRTl6tNv8scxPq4fpRL/uw71TU6XqSS/nME7KT4uyQPAXPk0mXVVwdmyST9Crlr6O6WJopPe9nMIFUYdjdkLfGKLCR96AH3U7frr4jf60eDYEhfHGIzln/ptrTJLvvbXTaPctAaZd6TIv63QVz3yim4MMl3VSdRlrE+O9R5ZR+QKBgQDjEP8TyUSnNsJX+4/JZFwsp04kz8OlorIdjVHT5/JREz5rnVfRlGpanXqjZSCg5Vy9R+ysiDhA+/wB9f87xXmv/2ypSeJspZLAZ0uhGffbdZ5PEASaiNfKn+tWFQ3bkcOX37tDlSJM+G4bQOR2+XdlXSbSZ1yx2AT+IsQKZvvL5QKBgQCPZEUiEz0sV1kX2R2a+XCQ3RVnUxWqh+X/HPjCUr+B/DdeZqPl7QAfjdGymBkN842o/4lZQ7nnpJL70j14KpxLGM4Ox9fIuLv8ZsTxc0XOXjtle48nO+uGkc0qyWoY/RVpQ+tBdiaTzHeIhIxEV7adz/lwZYKdiYIUzGjv8ES/uQKBgCgeWysXjahCQItxx5fTrS8SQFP7Dx5vDW+UkqQ2pbL0AlHyUS7pWJj3AAe3pn4AJZZp4SZPoQP+Z8JPqDA6MrQWHYMi0XkMuMYwLWbGCkmf1MnjUxgOaLXoItjxS/y3jQfeOmHhmOAVkjnEvAh+BWlZxFMv2kiuHRU72bNa0rDI
public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAikNqRCM1zOCKDdXDMzhV3ZZPMlV9nCl1iE2fdhBgEEHEcrWldO8kDms91BPSk3k/TbutvBvh2TLCVMUIxFBE2oJmOZy7W3i9+TNlHIm2KTN3toFU7VFvOggOuRgnS81IXSLoPMn9hfc1mssxuLB2fQ3E3sxumYxbvhLQ6RYIPgramO5/4oY0yKnhNZV9AtmSCqSGLO0I0fAM7Qf6kXKTiSkXzChg4Jk/RgCzfC3hRGAm0PlvxiRzfG0NAZNS5ehCkOHB12dWJKPml2kX2131GWIA/YcAFZcbcGZ3YHhV/CmqTgsNCduac1eFpLrSIzJbeyNkNY2ljaCi7sbc+DNpswIDAQAB
alipay_public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzWgVL/NWrJAeyEImwtaK3IDwj0dKkqUDIfqqWn5SiLaWMYi9RmKhn+jY9VM7JXEIkYYeVlqIL6Xn7OvYFRTi4buTCXGKvFLn95aDcaur77/S/0ibcdN1K2wIoHzaqQhXAb1ezKxTnFP7OLJsAL22b0NzrQDj2OH9SA06gJb8nHBfR+7Sx7DfwcqE0OtTcDHjbbcB24Qgg/dfItxoEnKuSyRVrf6BtpUnJxSzG/Ge7FfF+VBq8re1t4ZTSxaDEjto071I5VFBxr7I4SyqZsc7WpAmZL8AqUgEbQ1XYBWx2LnpJXM5GQW/thUvcDDqzea7LJNWJOQPM5DaZQgu7QuuwIDAQAB
sign_type = RSA2
max_query_retry = 5
query_duration = 5000
max_cancel_retry = 3
cancel_duration = 2000
heartbeat_delay = 5
heartbeat_duration = 900
1.5 继而我们运行一下复制过来的Main.class,发现Demo是可以跑起来的~
2、编写支付接口
2.1 OrderController类
@Controller
@RequestMapping("/order/")
public class OrderController {
private static final Logger logger = LoggerFactory.getLogger(OrderController.class);
@RequestMapping("pay.do")
@ResponseBody
public ServerResponse pay(HttpSession session, Long orderNo, HttpServletRequest request){
User user = (User)session.getAttribute(Const.CURRENT_USER);
if(user == null){
return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc());
}
String path = request.getSession().getServletContext().getRealPath("upload");
return iOrderService.pay(orderNo,user.getId(),path);
}
@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 ServerResponse.createByErrorMessage("非法请求,验证不通过,再恶意请求我就报警找网警了");
}
} catch (AlipayApiException e) {
logger.error("支付宝验证回调异常",e);
}
ServerResponse serverResponse = iOrderService.aliCallback(params);
if(serverResponse.isSuccess()){
return Const.AlipayCallback.RESPONSE_SUCCESS;
}
return Const.AlipayCallback.RESPONSE_FAILED;
}
@RequestMapping("query_order_pay_status.do")
@ResponseBody
public ServerResponse<Boolean> queryOrderPayStatus(HttpSession session, Long orderNo){
User user = (User)session.getAttribute(Const.CURRENT_USER);
if(user ==null){
return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc());
}
ServerResponse serverResponse = iOrderService.queryOrderPayStatus(user.getId(),orderNo);
if(serverResponse.isSuccess()){
return ServerResponse.createBySuccess(true);
}
return ServerResponse.createBySuccess(false);
}
}
2.2 IOrderService接口类
package com.mmall.service;
import com.github.pagehelper.PageInfo;
import com.mmall.common.ServerResponse;
import com.mmall.vo.OrderVo;
import java.util.Map;
public interface IOrderService {
ServerResponse pay(Long orderNo, Integer userId, String path);
ServerResponse aliCallback(Map<String,String> params);
ServerResponse queryOrderPayStatus(Integer userId,Long orderNo);
}
2.3 OrderServiceImpl实现类
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.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mmall.common.Const;
import com.mmall.common.ServerResponse;
import com.mmall.dao.CartMapper;
import com.mmall.dao.OrderItemMapper;
import com.mmall.dao.OrderMapper;
import com.mmall.dao.PayInfoMapper;
import com.mmall.dao.ProductMapper;
import com.mmall.dao.ShippingMapper;
import com.mmall.pojo.Cart;
import com.mmall.pojo.Order;
import com.mmall.pojo.OrderItem;
import com.mmall.pojo.PayInfo;
import com.mmall.pojo.Product;
import com.mmall.pojo.Shipping;
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 com.mmall.vo.OrderItemVo;
import com.mmall.vo.OrderProductVo;
import com.mmall.vo.OrderVo;
import com.mmall.vo.ShippingVo;
import org.apache.commons.collections.CollectionUtils;
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.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
@Service("iOrderService")
public class OrderServiceImpl implements IOrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
private static AlipayTradeService tradeService;
static {
Configs.init("zfbinfo.properties");
tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
}
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderItemMapper orderItemMapper;
public ServerResponse pay(Long orderNo,Integer userId,String path){
Map<String,String> resultMap = Maps.newHashMap();
Order order = orderMapper.selectByUserIdAndOrderNo(userId,orderNo);
if(order == null){
return ServerResponse.createByErrorMessage("用户没有该订单");
}
resultMap.put("orderNo",String.valueOf(order.getOrderNo()));
String outTradeNo = order.getOrderNo().toString();
String subject = new StringBuilder().append("happymmall扫码支付,订单号:").append(outTradeNo).toString();
String totalAmount = order.getPayment().toString();
String undiscountableAmount = "0";
String sellerId = "";
String body = new StringBuilder().append("订单").append(outTradeNo).append("购买商品共").append(totalAmount).append("元").toString();
String operatorId = "test_operator_id";
String storeId = "test_store_id";
ExtendParams extendParams = new ExtendParams();
extendParams.setSysServiceProviderId("2088100200300400500");
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);
}
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"))
.setGoodsDetailList(goodsDetailList);
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();
}
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);
try {
FTPUtil.uploadFile(Lists.newArrayList(targetFile));
} catch (IOException e) {
logger.error("上传二维码异常",e);
}
logger.info("qrPath:" + qrPath);
String qrUrl = PropertiesUtil.getProperty("ftp.server.http.prefix")+targetFile.getName();
resultMap.put("qrUrl",qrUrl);
return ServerResponse.createBySuccess(resultMap);
case FAILED:
logger.error("支付宝预下单失败!!!");
return ServerResponse.createByErrorMessage("支付宝预下单失败!!!");
case UNKNOWN:
logger.error("系统异常,预下单状态未知!!!");
return ServerResponse.createByErrorMessage("系统异常,预下单状态未知!!!");
default:
logger.error("不支持的交易状态,交易返回异常!!!");
return ServerResponse.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 ServerResponse 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 ServerResponse.createByErrorMessage("非快乐慕商城的订单,回调忽略");
}
if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){
return ServerResponse.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 ServerResponse.createBySuccess();
}
public ServerResponse queryOrderPayStatus(Integer userId,Long orderNo){
Order order = orderMapper.selectByUserIdAndOrderNo(userId,orderNo);
if(order == null){
return ServerResponse.createByErrorMessage("用户没有该订单");
}
if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){
return ServerResponse.createBySuccess();
}
return ServerResponse.createByError();
}
}
我们会发现,上面的大多数是直接从支付宝Demo中的Main类中复制过来的,我们只是更改了对应的参数。上面第四行代码我们用到了自己封装了一个根据订单号和用户Id来查询订单的方法。
2.4 *Mapper
Order selectByUserIdAndOrderNo(@Param("userId") Integer userId,@Param("orderNo") Long orderNo);
Order selectByOrderNo(Long orderNo);
2.5 *Mapper.xml
<select id="selectByUserIdAndOrderNo" parameterType="map" resultMap="BaseResultMap">
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>
2.6 Const类
public enum OrderStatusEnum{
CANCELED(0,"已取消"),
NO_PAY(10,"未支付"),
PAID(20,"已付款"),
SHIPPED(40,"已发货"),
ORDER_SUCCESS(50,"订单完成"),
ORDER_CLOSE(60,"订单关闭");
OrderStatusEnum(int code,String value){
this.code = code;
this.value = value;
}
private String value;
private int code;
public String getValue() {
return value;
}
public int getCode() {
return code;
}
public static OrderStatusEnum codeOf(int code){
for(OrderStatusEnum orderStatusEnum : values()){
if(orderStatusEnum.getCode() == code){
return orderStatusEnum;
}
}
throw new RuntimeException("么有找到对应的枚举");
}
}
public interface AlipayCallback{
String TRADE_STATUS_WAIT_BUYER_PAY = "WAIT_BUYER_PAY";
String TRADE_STATUS_TRADE_SUCCESS = "TRADE_SUCCESS";
String RESPONSE_SUCCESS = "success";
String RESPONSE_FAILED = "failed";
}
public enum PayPlatformEnum{
ALIPAY(1,"支付宝");
PayPlatformEnum(int code,String value){
this.code = code;
this.value = value;
}
private String value;
private int code;
public String getValue() {
return value;
}
public int getCode() {
return code;
}
}
public enum PaymentTypeEnum{
ONLINE_PAY(1,"在线支付");
PaymentTypeEnum(int code,String value){
this.code = code;
this.value = value;
}
private String value;
private int code;
public String getValue() {
return value;
}
public int getCode() {
return code;
}
public static PaymentTypeEnum codeOf(int code){
for(PaymentTypeEnum paymentTypeEnum : values()){
if(paymentTypeEnum.getCode() == code){
return paymentTypeEnum;
}
}
throw new RuntimeException("么有找到对应的枚举");
}
}
3、支付接口测试(一)
打开地址,显示二维码。
4、支付接口测试(二)
给沙箱环境配置我们的回调地址。
打开沙箱环境:登录 - 支付宝
在图上所示配置我们的回调地址。
由于我们是在本地开发,所以需要将本地IP映射到公网,这个教程有讲怎么将本地IP映射到公网:https://blog.csdn.net/czjlghndcy/article/details/81130029
映射好公网IP之后,我们就将对应生成的共网IP以及定义的接口访问地址粘贴到沙箱环境中的回调地址中即可~
支付一个未支付的案例
对生成的二维码进行支付
查询订单状态
显示已支付,So,我们的回调接口以及订单状态查询接口测试成功啦~
相关知识
花好网帮助中心—支付方式
广州百合花鸿运酒店服务设施
广州南沙花园酒店服务设施
武汉五月花大酒店服务设施
花好网帮助中心—投诉处理
博客园美化 背景Sakura JS樱花特效
Hello Kitty 永生花束
web支付基础教程
kylinH5框架之项目组件理解
珠芽繁殖(关于珠芽繁殖介绍)
网址: AliPay https://m.huajiangbk.com/newsview849396.html
上一篇: 微信小程序集成V3支付接口 |
下一篇: java如何第三方支付 |