JAVA后端实现微信支付(微信扫码及微信App支付)开发(模式二
一,准备工作
事前申请一个商家版的微信公众号(目前微信支付只有商家版公众号可开通),然后开通微信支付功能,并做相应的配置。
image申请开通微信公众号和开通微信支付需要等待审核,一般都5个工作日左右。开通成功后,需要获取配置信息:wx.pay.appid=********
wx.pay.mchid=******
wx.pay.key=**************
wx.pay.secret=*********
其中appid和secret可以在公众平台找着,mchid和key则在商户平台找到,特别是key(即API_KEY)要在商户平台设置好。本项目中这些配置通过properties文件放在***-payment-service工程的resource根路径下。
在编码之前,还需要登录微信商户平台配置支付回调URL,此配置作为支付成功后回调接口的域名。如果配置的URL为:http://www.abc.com/, 你的支付回调路径则可设置为:http://www.abc.com/api/payment/wxNotify。
二,编写代码
本项目我是用SpringBoot的微服务开发的,项目结构如下:
image我们先看看Service接口
image再看看Service的实现类:
@Service(value = "paymentService")
public class PaymentServiceImpl implements PaymentService {
private static Logger LOGGER = LoggerFactory.getLogger(PaymentServiceImpl.class);
@Value("${project.service.env}")
private String PROJECT_ENV;
@Value("${hcc.pay.domain}")
private String payDomain;
@Autowired
private PaymentRecordMapper paymentRecordMapper;
@Autowired
private PaymentNotifyMapper paymentNotifyMapper;
@Override
@Transactional(readOnly=false,rollbackFor={Exception.class})
public Map<String,String> wxAppPayment(String orderId, double money) throws Exception {
LOGGER.info("【微信App支付】 统一下单开始, 订单编号="+orderId);
SortedMap<String, String> resultMap = new TreeMap<String, String>();
//生成支付金额
double payAmount = PayUtil.getPayAmountByEnv(PROJECT_ENV, money);
//添加或更新支付记录
int flag = this.addOrUpdatePaymentRecord(orderId, payAmount, PayConstant.PAY_METHOD_WX,PayConstant.PAY_TRADE_TYPE_APP, false, null);
if(flag < 0){
resultMap.put("returnCode", "FAIL");
resultMap.put("returnMsg", "此订单已支付!");
LOGGER.info("【微信App支付】 此订单已支付!");
}else if(flag == 0){
resultMap.put("returnCode", "FAIL");
resultMap.put("returnMsg", "支付记录生成或更新失败!");
LOGGER.info("【微信App支付】 支付记录生成或更新失败!");
}else{
//统一下单
Map<String,String> resMap = this.wxUnifieldOrder(orderId, PayConfig.TRADE_TYPE_APP, payAmount);
if(PayConstant.SUCCESS.equals(resMap.get("return_code")) && PayConstant.OK.equals(resMap.get("return_msg"))){
//封装参数返回
resultMap.put("appid", PayConfig.WX_APP_ID);//前面配置中的appid
resultMap.put("partnerid", PayConfig.WX_MCH_ID);//前面配置中的mchid
resultMap.put("prepayid", resMap.get("prepay_id"));
resultMap.put("package", "Sign=WXPay");
resultMap.put("noncestr", PayUtil.makeUUID(32));
resultMap.put("timestamp", PayUtil.getCurrentTimeStamp());
resultMap.put("sign", PayUtil.createSign(resultMap,PayConfig.WX_KEY));
resultMap.put("returnCode", "SUCCESS");
resultMap.put("returnMsg", "OK");
LOGGER.info("【微信App支付】统一下单成功,返回参数:"+resultMap);
}else{
resultMap.put("returnCode", resMap.get("return_code"));
resultMap.put("returnMsg", resMap.get("return_msg"));
LOGGER.info("【微信App支付】统一下单失败,失败原因:"+resMap.get("return_msg"));
}
}
return resultMap;
}
@Override
public Map<String, String> wxQrPayment(String orderId, double money) throws Exception {
LOGGER.info("【微信扫码支付】 开始下单, 订单编号="+orderId+",支付金额="+money);
double payAmount = PayUtil.getPayAmountByEnv(PROJECT_ENV,money);
Map<String,String> retMap = new HashMap<String, String>();
//添加或更新支付记录
int flag = this.addOrUpdatePaymentRecord(orderId, payAmount, PayConstant.PAY_METHOD_WX,PayConstant.PAY_TRADE_TYPE_QR,false, null);
if(flag < 0){
retMap.put("returnCode", "FAIL");
retMap.put("returnMsg", "此订单已支付!");
LOGGER.info("【微信扫码支付】 此订单已支付!");
}else if(flag == 0){
retMap.put("returnCode", "FAIL");
retMap.put("returnMsg", "支付记录生成或更新失败!");
LOGGER.info("【微信扫码支付】 支付记录生成或更新失败!");
}else{
//微信统一下单
Map<String,String> map = this.wxUnifieldOrder(orderId,PayConfig.TRADE_TYPE_NATIVE,payAmount);
//下单后返回状态
if(PayConstant.SUCCESS.equals(map.get("return_code")) && PayConstant.OK.equals(map.get("return_msg"))) {
retMap.put("returnCode", map.get("return_code"));
retMap.put("returnMsg", PayConstant.OK);
retMap.put("codeUrl",map.get("code_url"));
retMap.put("payAmount",String.valueOf(payAmount));
retMap.put("orderName", BaseConstants.PLATFORM_COMPANY_NAME);
retMap.put("payMethod", "微信扫码支付");
retMap.put("queryUrl", this.getNotifyUrl(PayConstant.PAY_TYPE_WX));
LOGGER.info("【微信扫码支付】统一下单成功!");
}else{
retMap.put("returnCode", map.get("return_code"));
retMap.put("returnMsg", map.get("return_msg"));
LOGGER.info("【微信扫码支付】统一下单失败,失败原因:"+map.get("return_msg"));
}
retMap.put("orderNo",orderId);
}
return retMap;
}
@Override
@Transactional(readOnly=false,rollbackFor={Exception.class})
public int wxNotify(Map<String,Object> map) throws Exception{
Integer flag = 0;
//支付订单编号
String orderNo = (String)map.get("out_trade_no");
//检验是否需要回调
if(this.isNotifyAgain(orderNo)){
//此处写更新支付信息和订单状态逻辑
}
return flag;
}
/**
* <p>微信支付统一下单</p>
*
* @param orderId 订单编号
* @param tradeType 支付类型
* @return
* @throws Exception
*/
private Map<String,String> wxUnifieldOrder(String orderId,String tradeType, double payAmount) throws Exception{
//封装参数
SortedMap<String,String> paramMap = new TreeMap<String,String>();
paramMap.put("appid", PayConfig.WX_APP_ID);
paramMap.put("mch_id", PayConfig.WX_MCH_ID);
paramMap.put("nonce_str", PayUtil.makeUUID(32));
paramMap.put("body", BaseConstants.PLATFORM_COMPANY_NAME);
paramMap.put("out_trade_no", orderId);
paramMap.put("total_fee", PayUtil.moneyToIntegerStr(payAmount));
paramMap.put("spbill_create_ip", PayUtil.getLocalIp());
paramMap.put("notify_url", this.getNotifyUrl(PayConstant.PAY_TYPE_WX));//此处为要配置的回调地址
paramMap.put("trade_type", tradeType);
paramMap.put("sign", PayUtil.createSign(paramMap,PayConfig.WX_KEY));
//转换为xml
String xmlData = PayUtil.mapToXml(paramMap);
//请求微信后台
String resXml = HttpUtils.postData(PayConfig.WX_PAY_UNIFIED_ORDER, xmlData);
LOGGER.info("【微信支付】 统一下单响应:\n"+resXml);
return PayUtil.xmlStrToMap(resXml);
}
@Override
public int addOrUpdatePaymentRecord(String orderNo, double payAmount, int payType, String tradeType, boolean isPayment, String tradeNo) throws Exception{
PaymentRecord record = null;
if(null == (record = paymentRecordMapper.findPaymentRecordByorderNo(orderNo)))
{
record = new PaymentRecord();
//封装对应参数,并添加一条支付信息,状态为“待支付”
return paymentRecordMapper.insert(record);
}else{
record.set...();
//此处是对已改变的参数进行更新
record.setUpdateTime(new Date());
return paymentRecordMapper.updateByPrimaryKey(record);
}
}
/**
* <p>检查是否需要再次回调更新订单</p>
*
* @param orderNo
* @return
*/
private boolean isNotifyAgain(String orderNo){
//根据订单编号,查询对应支付信息,如果此条支付状态为已支付,返回TRUE,否则返回false
//这样做的目的是防止多次调回调接口平凡刷新支付信息
}
/**
* <p>根据不同环境获取回调Api地址</p>
*
* @return
*/
private String getNotifyUrl(){
//服务域名
String serverDomain = PayConfig.PRO_SERVER_DOMAIN;
if(BaseConstants.PLATFORM_ENV_DEV.equals(PROJECT_ENV)){
serverDomain = PayConfig.TEST_SERVER_DOMAIN;
}
return serverDomain + PayConstant.WX_PAY_CALLBACK_URL;
}
}
再看看这里的PayUtil工具类:
public class PayUtil {
static Logger log = LogManager.getLogger(PayUtil.class.getName());
/**
* 获取当前机器的ip
*
* @return String
*/
public static String getLocalIp(){
InetAddress ia=null;
String localip = null;
try {
ia=ia.getLocalHost();
localip=ia.getHostAddress();
} catch (Exception e) {
e.printStackTrace();
}
return localip;
}
/**
* Map转换为 Xml
*
* @param data
* @return Xml
* @throws Exception
*/
public static String mapToXml(SortedMap<String, String> map) throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//防止XXE攻击
documentBuilderFactory.setXIncludeAware(false);
documentBuilderFactory.setExpandEntityReferences(false);
DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
org.w3c.dom.Document document = documentBuilder.newDocument();
org.w3c.dom.Element root = document.createElement("xml");
document.appendChild(root);
for (String key: map.keySet()) {
String value = map.get(key);
if (value == null) {
value = "";
}
value = value.trim();
org.w3c.dom.Element filed = document.createElement(key);
filed.appendChild(document.createTextNode(value));
root.appendChild(filed);
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
String output = writer.getBuffer().toString();
try {
writer.close();
}
catch (Exception ex) {
}
return output;
}
/**
* 创建签名Sign
*
* @param key
* @param parameters
* @return
*/
public static String createSign(SortedMap<String,String> parameters,String key){
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
Iterator<?> it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
if(entry.getValue() != null || !"".equals(entry.getValue())) {
String v = String.valueOf(entry.getValue());
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
}
sb.append("key=" + key);
String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
return sign;
}
/**
* XML转换为Map
*
* @param strXML
* @return Map
* @throws Exception
*/
public static Map<String, Object> getMapFromXML(String strXML) throws Exception {
try {
Map<String, Object> data = new HashMap<String, Object>();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//防止XXE攻击
documentBuilderFactory.setXIncludeAware(false);
documentBuilderFactory.setExpandEntityReferences(false);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return data;
} catch (Exception ex) {
throw ex;
}
}
/**
* 生成随机数
*
* @return
*/
public static String makeUUID(int len) {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, len);
}
/**
* 获取当前的Timestamp
*
* @return
*/
public static String getCurrentTimeStamp() {
return Long.toString(System.currentTimeMillis()/1000);
}
/**
* 获取当前的时间
* @return
*/
public static long getCurrentTimestampMs() {
return System.currentTimeMillis();
}
/**
* 获取当前工程url
*
* @param request
* @return
*/
public static String getCurrentUrl(HttpServletRequest request){
return request.getScheme() +"://" + request.getServerName() + ":" +request.getServerPort() +request.getContextPath();
}
/**
* Xml字符串转换为Map
*
* @param xmlStr
* @return
*/
public static Map<String,String> xmlStrToMap(String xmlStr){
Map<String,String> map = new HashMap<String,String>();
Document doc;
try {
doc = DocumentHelper.parseText(xmlStr);
Element root = doc.getRootElement();
List children = root.elements();
if(children != null && children.size() > 0) {
for(int i = 0; i < children.size(); i++) {
Element child = (Element)children.get(i);
map.put(child.getName(), child.getTextTrim());
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
return map;
}
public static String getSceneInfo(String wapUrl,String name){
Map<String,Map<String,String>> map = new HashMap<String, Map<String,String>>();
if(!StringUtils.isEmpty(wapUrl) && !StringUtils.isEmpty(name)){
/*{"h5_info": {"type":"Wap","wap_url": "https://pay.qq.com","wap_name": "腾讯充值"}}*/
Map<String,String> childmap = new TreeMap<String, String>();
childmap.put("type", "Wap");
childmap.put("wap_url",wapUrl);
childmap.put("wap_name", name);
map.put("h5_info", childmap);
return JSON.toJSONString(map);
}
return null;
}
/**
* 转换金额型到整型
* @param money
* @return
*/
public static String moneyToIntegerStr(Double money){
BigDecimal decimal = new BigDecimal(money);
int amount = decimal.multiply(new BigDecimal(100))
.setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
return String.valueOf(amount);
}
/**
* 除去数组中的空值和签名参数
* @param sArray 签名参数组
* @return 去掉空值与签名参数后的新签名参数组
*/
public static Map<String, String> paraFilter(Map<String, String> sArray) {
Map<String, String> result = new HashMap<String, String>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
|| key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
/**
* 根据不同环境生成支付金额
* 生产环境支付金额为实际要支付钱数,测试环境做了处理便于测试人员测试
*
* @param env
* @param money
* @param payType
* @return
*/
public static double getPayAmountByEnv(String env,Double money){
double pay_money = 0.01;
//测试环境
if(BaseConstants.PLATFORM_ENV_DEV.equals(env)){
if(money>10000){
pay_money = 0.03;
}else if(money>1000){
pay_money = 0.02;
}else{
pay_money = 0.01;
}
return pay_money;
}else{
//生成环境
return money;
}
}
}
支付配置类PayConfig:
public class PayConfig {
//微信支付类型
//NATIVE--原生支付
//JSAPI--公众号支付
//MWEB--H5支付
//APP -- app支付
public static final String TRADE_TYPE_NATIVE = "NATIVE";
public static final String TRADE_TYPE_JSAPI = "JSAPI";
public static final String TRADE_TYPE_MWEB = "MWEB";
public static final String TRADE_TYPE_APP = "APP";
//服务器域名
public static String PRO_SERVER_DOMAIN;
public static String TEST_SERVER_DOMAIN;
//微信公众号参数
public static String WX_APP_ID;
public static String WX_MCH_ID;
public static String WX_KEY;
public static String WX_APP_SECRET;
//微信支付API
public static final String WX_PAY_UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
//参数
static{
Properties properties = new Properties();
try {
properties.load(PayConstant.class.getClassLoader().getResourceAsStream("payment_config.properties"));
PRO_SERVER_DOMAIN = (String) properties.get("pro.server.domain");
TEST_SERVER_DOMAIN = (String) properties.get("test.server.domain");
//wx pay
WX_APP_ID = (String) properties.get("wx.pay.appid");
WX_MCH_ID = (String) properties.get("wx.pay.mchid");
WX_KEY = (String) properties.get("wx.pay.key");
WX_APP_SECRET = (String) properties.get("wx.pay.secret");
} catch (Exception e) {
e.printStackTrace();
}
}
}
到这里为止,业务实现基本已经写完了,现在我们去看看接口层吧!
@RestController
@RequestMapping(value = "/app/payment/")
public class PaymentController {
private static Logger logger = LoggerFactory.getLogger(PaymentController.class);
@Value("${project.service.env}")
private String PROJECT_ENV;
@Value("${error.page}")
private String error_page;
@Value("${hcc.app.domain}")
private String orderDomain;
@Autowired
private PaymentService paymentService;
@Autowired
private RedisCacheService cacheService;
/**
* App支付接口
* 微信和支付宝统一下单入口
*
* @param request
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping(value="appPay", method=RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
public JSONObject toPay(HttpServletRequest request) throws Exception {
String requestStr = RequestStr.getRequestStr(request);
if (StringUtils.isEmpty(requestStr)) {
throw new ParamException();
}
JSONObject jsonObj = JSONObject.parseObject(requestStr);
if(StringUtils.isEmpty(jsonObj.getString("payType")) || StringUtils.isEmpty(jsonObj.getString("orderNo"))){
throw new ParamException();
}
//验证订单是否存在
String orderId = jsonObj.getString("orderNo");
OrderInfo orderInfo = getPayOrder(orderId);
if(orderInfo == null){
return AjaxUtil.renderFailMsg("订单不存在!");
}else if(orderInfo.getPayPrice() == null || orderInfo.getPayPrice() < 0.01){
return AjaxUtil.renderFailMsg("订单有误,请确认!");
}else if(orderInfo.getpStatus() != OrderConstant.PORDER_STATUS_YTJ){
String msg = orderInfo.getpStatus() == OrderConstant.PORDER_STATUS_YFK?"此订单已支付!":"无效的订单,请确认!";
return AjaxUtil.renderFailMsg(msg);
}else{
//微信支付
if(PayConstant.PAY_TYPE_WX.equals(jsonObj.getString("payType"))){
Map<String, String> resMap = paymentService.wxAppPayment(orderInfo.getOrderNo(),orderInfo.getPayPrice());
//判断微信统一下单是否成功
if("SUCCESS".equals(resMap.get("returnCode")) && "OK".equals(resMap.get("returnMsg"))){
//统一下单成功
resMap.remove("returnCode");
resMap.remove("returnMsg");
logger.info("【App支付服务】微信支付下单成功!");
return AjaxUtil.renderSuccessMsg(resMap);
}else{
return AjaxUtil.renderFailMsg(resMap.get("returnMsg"));
}
}else if(PayConstant.PAY_TYPE_ALI.equals(jsonObj.getString("payType"))){
//支付宝支付
}else{
return AjaxUtil.renderParamFailMsg("请选择支付方式!");
}
}
}
/**
* 扫码支付接口
* 微信和支付宝统一下单入口
*
* @param request
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping(value="qrPay", method=RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
public JSONObject qrPay(HttpServletRequest request) throws Exception {
String requestStr = RequestStr.getRequestStr(request);
if (StringUtils.isEmpty(requestStr)) {
throw new ParamException();
}
JSONObject jsonObj = JSONObject.parseObject(requestStr);
if(StringUtils.isEmpty(jsonObj.getString("payType")) || StringUtils.isEmpty(jsonObj.getString("orderNo"))){
throw new ParamException();
}
//验证订单是否存在
String orderId = jsonObj.getString("orderNo");
OrderInfo orderInfo = getPayOrder(orderId);
if(orderInfo == null){
return AjaxUtil.renderFailMsg("订单不存在!");
}else if(orderInfo.getPayPrice() == null || orderInfo.getPayPrice() < 0.01){
return AjaxUtil.renderFailMsg("订单有误,请确认!");
}else if(orderInfo.getpStatus() != OrderConstant.PORDER_STATUS_YTJ){
String msg = orderInfo.getpStatus() == OrderConstant.PORDER_STATUS_YFK?"此订单已支付!":"无效的订单,请确认!";
return AjaxUtil.renderFailMsg(msg);
}else{
if(PayConstant.PAY_TYPE_WX.equals(jsonObj.getString("payType"))){
//微信支付扫码支付
Map<String, String> resMap = paymentService.wxQrPayment(orderInfo.getOrderNo(), orderInfo.getPayPrice());
//判断微信统一下单是否成功
if(PayConstant.SUCCESS.equals(resMap.get("returnCode")) && PayConstant.OK.equals(resMap.get("returnMsg"))){
resMap.remove("returnCode");
resMap.remove("returnMsg");
logger.info("【Web扫码支付服务】微信支付下单成功!");
return AjaxUtil.renderSuccessMsg(resMap);
}else{
return AjaxUtil.renderFailMsg(resMap.get("returnMsg"));
}
}else if(PayConstant.PAY_TYPE_ALI.equals(jsonObj.getString("payType"))){
//支付宝扫码支付
}else{
return AjaxUtil.renderParamFailMsg("请选择支付方式!");
}
}
}
/**
* <p>获取二维码</p>
*
* @param request
* @param response
* @throws Exception
*/
@ResponseBody
@RequestMapping(value="qrCodeImg", method=RequestMethod.GET, produces = {"application/json;charset=UTF-8"})
public void getQrCodeImg(HttpServletRequest request,HttpServletResponse response) throws Exception{
//获取参数
String codeUrl = request.getParameter("codeUrl");
if(!StringUtils.isEmpty(codeUrl)){
CodeUtil.generateQrCodeImg(codeUrl,response.getOutputStream());
}else{
throw new ParamException();
}
}
/**
* 微信支付完成回调Api
*
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(value="wxNotify")
public void wxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception {
InputStream inputStream = request.getInputStream();
//获取请求输入流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len=inputStream.read(buffer))!=-1){
outputStream.write(buffer,0,len);
}
outputStream.close();
inputStream.close();
Map<String,Object> map = BeanToMap.getMapFromXML(new String(outputStream.toByteArray(),"utf-8"));
logger.info("【微信支付回调】 回调数据: \n"+map);
String resXml = "";
String returnCode = (String) map.get("return_code");
if ("SUCCESS".equalsIgnoreCase(returnCode)) {
String returnmsg = (String) map.get("result_code");
if("SUCCESS".equals(returnmsg)){
//更新数据
int result = paymentService.wxNotify(map);
if(result > 0){
//支付成功
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>"+"</xml>";
}
}else{
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>";
logger.info("支付失败:"+resXml);
}
}else{
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>";
logger.info("【订单支付失败】");
}
logger.info("【微信支付回调响应】 响应内容:\n"+resXml);
//做出响应
response.getWriter().print(resXml);
}
/**
* <p>查询订单支付是否完成</p>
*
* @param request
* @param response
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping(value="queryPayStatus")
public JSONObject queryPayStatus(HttpServletRequest request,HttpServletResponse response) throws Exception {
String requestStr = RequestStr.getRequestStr(request);
if (StringUtils.isEmpty(requestStr)) {
throw new ParamException();
}
JSONObject jsonObj = JSONObject.parseObject(requestStr);
if(StringUtils.isEmpty(jsonObj.getString("orderNo"))){
throw new ParamException();
}
PaymentRecord record = paymentService.queryPaymentStatusById(jsonObj.getString("orderNo"));
if(record != null && record.getStatus){
//此处可根据自己想要返回的数据封装返回,“已支付”可用封装的Map返回
return AjaxUtil.renderSuccessMsg(“已支付”);
}else{
return AjaxUtil.renderFailMsg("未支付!");
}
}
/**
* <p>通过Http请求订单服务获取订单信息</p>
*
* @param orderNo
* @return
* @throws Exception
*/
private OrderInfo getPayOrder(String orderNo) throws Exception{
//更新订单状态
String reqUrl = orderDomain + "order/findOrderByPrimary";
SortedMap<String, String> params = new TreeMap<String, String>();
params.put("orderId", orderNo);
JSONObject json = JSONObject.parseObject(HttpUtils.sendPostWithSign(reqUrl, params));
if("0000".equals(json.get("responseCode"))){
OrderInfo orderInfo = JSONObject.parseObject(json.getString("data"),OrderInfo.class);
if(orderInfo != null){
return orderInfo;
}
}
return null;
}
}
到此为止,所有的编码工作已完成。
三,测试(用扫码支付)
选择要购买的商品,然后下单,再去发起支付。
image单击“去支付”按钮,跳转到二维码支付页面:
image扫码支付完成后,显示二维码的页面会跳转到支付成功页面(带微信支付成功logo),并有3s的倒计时,然后跳转到“订单详情”页。
image**本人有完整的电商支付微服务代码(微信支付和支付宝支付),如果需要,请关注本人微信公众号留言,或通过公众号加我私人微信联系,希望能和大家一起学习进步! **
image