网页、小程序支付链接等相关;新增测试鉴权、支付demo类

master
yclimb 2018-08-17 16:24:56 +08:00
parent 4887cd8b20
commit 4c161e4aed
9 changed files with 1090 additions and 0 deletions

26
pom.xml
View File

@ -72,6 +72,32 @@
<version>3.1.0</version> <version>3.1.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -0,0 +1,47 @@
package com.weixin.pay.constants;
/**
*
*
* @author yclimb
* @date 2018/8/17
*/
public class WXConstants {
/**
* 访使stringjson
*/
public static final String SUCCESS = "success";
public static final String ERROR = "error";
/**
* openid
**/
public static final String OAUTH_BASE_SCOPE = "snsapi_base";
/**
*
**/
public static final String OAUTH_USERINFO_SCOPE = "snsapi_userinfo";
/**
* state
*/
public static final String OAUTH_STATE = "xxx";
/**
* accessToken
*/
public static final String WECHAT_ACCESSTOKEN = OAUTH_STATE + ":wx:accessToken:";
/**
* accessTokenLock
*/
public static final String WECHAT_ACCESSTOKEN_LOCK = OAUTH_STATE + ":wx:accessTokenLock:";
/**
* openid7200
*/
public static final String WECHAT_JSAPI_OPENID = OAUTH_STATE + ":wx:jsapi:openid:";
}

View File

@ -0,0 +1,90 @@
package com.weixin.pay.constants;
/**
* URL
*
* @author yclimb
* @date 2018/8/17
*/
public class WXURL {
/**
* URLjsapi_ticket
*/
public static final String PAGE_URL_SIGN = "jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}";
/**
* URLaccess_token
*/
public static final String BASE_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
/**
* URLjsapi_ticket
*/
public static final String BASE_JSAPI_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi";
/**
* URL
*/
public static final String MENU_CREATE = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}";
/**
* URL
*/
public static final String MENU_QUERY = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}";
/**
* URL
*/
public static final String MENU_DELETE = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}";
/**
* code
*/
public static final String OAUTH_CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=" + WXConstants.OAUTH_STATE + "#wechat_redirect";
/**
* codeaccess_token
*/
public static final String OAUTH_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code";
/**
*
*/
public static final String OAUTH_GET_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN";
/**
* access_token
*/
public static final String GET_USERINFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
/**
*
*/
public static final String WX_TEMPLATE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}";
/**
*
*/
public static final String WX_CUSTMOER_SERVICE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={0}";
/***
* ticket
*/
public static final String WX_TICKET_CREATE = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={0}";
/**
*
*/
public static final String WX_MINI_LOGIN = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
/**
*
*/
public static final String WX_MINI_TEMPLATE_MSG = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={0}";
/**
*
*/
public static final String WX_MINI_QR_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={0}";
}

View File

@ -0,0 +1,76 @@
package com.weixin.pay.redis;
/**
* Redis
*
* @author yclimb
* @date 2018/4/19
*/
public enum RedisKeyEnum {
/**
* KEY
*/
XXX_MINI_WX_CODE(RedisKeyUtil.KEY_PREFIX, "mini", "getwxacodeunlimit", "生成永久无限制微信二维码")
;
/**
*
*/
private String keyPrefix;
/**
*
*/
private String module;
/**
*
*/
private String func;
/**
* remark
*/
private String remark;
RedisKeyEnum(String keyPrefix, String module, String func, String remark) {
this.keyPrefix = keyPrefix;
this.module = module;
this.func = func;
this.remark = remark;
}
public String getKeyPrefix() {
return keyPrefix;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public String getModule() {
return module;
}
public void setModule(String module) {
this.module = module;
}
public String getFunc() {
return func;
}
public void setFunc(String func) {
this.func = func;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
}

View File

@ -0,0 +1,122 @@
package com.weixin.pay.redis;
/**
* Redis
*
* @author yclimb
* @date 2018/4/19
*/
public class RedisKeyUtil {
/**
*
*/
public static final String KEY_PREFIX = "xxx";
/**
* [:]
*/
public static final String KEY_SPLIT_CHAR = ":";
/**
* rediskey
*
* @param module
* @param func
* @return key
*/
public static String keyBuilder(String module, String func) {
return keyBuilder(null, module, func, (String[]) null);
}
/**
* rediskey
*
* @param module
* @param func
* @param args ..
* @return key
*/
public static String keyBuilder(String module, String func, String... args) {
return keyBuilder(null, module, func, args);
}
/**
* rediskey
*
* @param module
* @param func
* @param objStr .toString()
* @return key
*/
public static String keyBuilder(String module, String func, String objStr) {
return keyBuilder(null, module, func, new String[]{objStr});
}
/**
* rediskey
*
* @param prefix
* @param module
* @param func
* @param objStr .toString()
* @return key
*/
public static String keyBuilder(String prefix, String module, String func, String objStr) {
return keyBuilder(prefix, module, func, new String[]{objStr});
}
/**
* rediskey
*
* @param prefix
* @param module
* @param func
* @param args ..
* @return key
*/
public static String keyBuilder(String prefix, String module, String func, String... args) {
// 项目前缀
if (prefix == null) {
prefix = KEY_PREFIX;
}
StringBuilder key = new StringBuilder(prefix);
// KEY_SPLIT_CHAR 为分割字符
key.append(KEY_SPLIT_CHAR).append(module).append(KEY_SPLIT_CHAR).append(func);
// args 为空时不需要循环
if (args == null || args.length <= 0) {
return key.toString();
}
// args 不为空时循环拼接字符
for (String arg : args) {
key.append(KEY_SPLIT_CHAR).append(arg);
}
return key.toString();
}
/**
* rediskey
*
* @param redisEnum
* @return key
*/
public static String keyBuilder(RedisKeyEnum redisEnum) {
return keyBuilder(redisEnum.getKeyPrefix(), redisEnum.getModule(), redisEnum.getFunc(), (String[]) null);
}
/**
* rediskey
*
* @param redisEnum
* @param objStr .toString()
* @return key
*/
public static String keyBuilder(RedisKeyEnum redisEnum, String objStr) {
return keyBuilder(redisEnum.getKeyPrefix(), redisEnum.getModule(), redisEnum.getFunc(), objStr);
}
}

View File

@ -0,0 +1,41 @@
package com.weixin.pay.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import java.io.UnsupportedEncodingException;
/**
* emoji
*
* @author yclimb
* @date 2018/8/17
*/
@Slf4j
public class WXUserUtil {
/**
*
*
* @param nickName
* @return base64 str
*/
public static String encodeNickName(String nickName) {
try {
return Base64.encodeBase64String(nickName.toString().getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
log.error("编码用户昵称报错", e);
}
return null;
}
/**
*
*
* @param nickName base64 str
* @return
*/
public static String decodeNickName(String nickName) {
return new String(Base64.decodeBase64(nickName));
}
}

View File

@ -0,0 +1,279 @@
package com.weixin.pay.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.weixin.pay.constants.WXConstants;
import com.weixin.pay.constants.WXPayConstants;
import com.weixin.pay.constants.WXURL;
import com.weixin.pay.redis.RedisKeyEnum;
import com.weixin.pay.redis.RedisKeyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author yclimb
* @date 2018/8/17
*/
@Slf4j
@Component
public class WXUtils {
@Resource
private RestTemplate restTemplate;
@Resource
private RedisTemplate redisTemplate;
/**
* accessToken
* accessToken accessToken
*
* @param code
* @return
* @throws Exception
*/
public String getAccessToken(String code) throws Exception {
// 取redis数据
String key = WXConstants.WECHAT_ACCESSTOKEN + code;
String accessToken = (String) redisTemplate.opsForValue().get(key);
if (accessToken != null) {
return accessToken;
}
// 通过接口取得access_token
JSONObject jsonObject = restTemplate.getForObject(MessageFormat.format(WXURL.BASE_ACCESS_TOKEN, WXPayConstants.APP_ID, WXPayConstants.SECRET), JSONObject.class);
String token = (String) jsonObject.get("access_token");
if (StringUtils.isNotBlank(token)) {
// 存储redis
redisTemplate.opsForValue().set(key, token, 7000, TimeUnit.SECONDS);
return token;
} else {
log.error("获取微信accessToken出错微信返回信息为[{}]", jsonObject.toString());
}
return null;
}
/**
*
*
* @param code code
* @param appId appId
* @param appSecret appSecret
* @return json
*/
public JSONObject getMiniBaseUserInfo(String code, String appId, String appSecret) {
log.info("getMiniBaseUserInfo:params:[{}]", code);
String data = restTemplate.getForObject(WXURL.WX_MINI_LOGIN, String.class, appId, appSecret, code);
log.info("getMiniBaseUserInfo:result:[{}]", data);
return JSONObject.parseObject(data);
}
/**
* access_tokenopenid
* https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code(最后一个参数不变)
* @param code c
* @return access_token json obj
*
* @author yclimb
* @date 2018/7/30
*/
public JSONObject getJsapiAccessTokenByCode(String code) {
if (StringUtils.isBlank(code)) {
return null;
}
try {
// 获取access_token
String access_token_json = restTemplate.getForObject(WXURL.OAUTH_ACCESS_TOKEN_URL, String.class,
WXPayConstants.APP_ID_XXX, WXPayConstants.SECRET_XXX, code);
log.info("getAccessToken:access_token_json:{}", access_token_json);
if (StringUtils.isBlank(access_token_json)) {
return null;
}
JSONObject jsonObject = JSON.parseObject(access_token_json);
if (StringUtils.isBlank(jsonObject.getString("access_token"))) {
return null;
}
return jsonObject;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
/**
* access_tokenopenid
* https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
* @param access_token t
* @param openid o
* @return userinfo json obj
*
* @author yclimb
* @date 2018/7/30
*/
public JSONObject getJsapiUserinfo(String access_token, String openid) {
if (StringUtils.isBlank(access_token) || StringUtils.isBlank(openid)) {
return null;
}
try {
// 获取access_token和openid
String userinfo_json = restTemplate.getForObject(WXURL.OAUTH_GET_USERINFO_URL, String.class, access_token, openid);
log.info("getUserinfo:userinfo_json:{}", userinfo_json);
if (StringUtils.isBlank(userinfo_json)) {
return null;
}
JSONObject jsonObject = JSON.parseObject(userinfo_json);
if (0 != jsonObject.getIntValue("errcode")) {
return null;
}
return jsonObject;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
/**
* []
*
* @param scene
* @param page
* @return img path
*/
public String getWxMiniQRImg(String scene, String page) {
InputStream inputStream = null;
String imgUrl = "";
try {
// redis key
String redisKey = RedisKeyUtil.keyBuilder(RedisKeyEnum.XXX_MINI_WX_CODE, scene + RedisKeyUtil.KEY_SPLIT_CHAR + page);
// 从redis中获取缓存图片
Object obj = redisTemplate.opsForValue().get(redisKey);
if (obj != null) {
return obj.toString();
}
// 获取微信永久无限制二维码
byte[] code = this.getwxacodeunlimit(scene, page);
if (code == null || code.length <= 0) {
return imgUrl;
}
// 将返回字节数组转为输入流
inputStream = new ByteArrayInputStream(code);
// 取得uuid的文件名称
String newFileName = UUID.randomUUID().toString().replaceAll("-", "").replace(".", "") + ".png";
log.info("getWxMiniQRImg:fileName:" + newFileName);
// 上传图片到OSS服务器
// imgUrl = ossUtils.uploadOss(inputStream, ossUtils.getImgPathYYYYMMDD(), newFileName);
// 图片为空直接返回
if (StringUtils.isBlank(imgUrl)) {
return imgUrl;
}
// 设置到redis中下次取直接拿缓存即可防止多次生成
redisTemplate.opsForValue().set(redisKey, imgUrl);
} catch (Exception e) {
log.error("getWxMiniQRImg:调用小程序生成微信永久小程序码URL接口异常", e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
return imgUrl;
}
/**
* application/json;charset=UTF-8 HttpHeaders
*
* @return HttpHeaders
* @author yclimb
* @date 2018/7/18
*/
public HttpHeaders getHttpHeadersUTF8JSON() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
return headers;
}
/**
* <br>
*
* https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
* https://developers.weixin.qq.com/miniprogram/dev/api/qrcode.html
*
* @param scene 32!#$&'()*+,/:;=?@-._~%使 urlencode 使
* @param page "pages/index/index" ,'/',scene
* @return
* @author yclimb
* @date 2018/7/18
*/
public byte[] getwxacodeunlimit(String scene, String page) {
try {
// 获取access token
String accessToken = this.getAccessToken("xxx");
// 拼接传入参数
Map<String, Object> param = new HashMap<>(5);
param.put("scene", scene);
param.put("page", page);
// 默认430二维码的宽度最小为280
param.put("width", 280);
// 默认false自动配置线条颜色如果颜色依然是黑色则说明不建议配置主色调
param.put("auto_color", false);
// 默认:{"r":"0","g":"0","b":"0"}二维码图片颜色参数auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示
Map<String, Object> line_color = new HashMap<>(3);
line_color.put("r", 0);
line_color.put("g", 0);
line_color.put("b", 0);
param.put("line_color", line_color);
// map转换为json传输
String jsonParam = JSON.toJSONString(param);
log.info("getwxacodeunlimit:param:" + jsonParam);
// 请求微信接口,得到返回结果[二进制流]
HttpEntity<String> entity = new HttpEntity<>(jsonParam, this.getHttpHeadersUTF8JSON());
ResponseEntity<byte[]> responseEntity = restTemplate.postForEntity(WXURL.WX_MINI_QR_CODE_URL, entity, byte[].class, accessToken);
// return byte[]
return responseEntity.getBody();
} catch (Exception e) {
log.error("getwxacodeunlimit:postForEntity:" + e.getMessage(), e);
}
return null;
}
}

View File

@ -0,0 +1,107 @@
package controller;
import com.alibaba.fastjson.JSONObject;
import com.weixin.pay.constants.WXConstants;
import com.weixin.pay.util.WXUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
*
*
* @author yclimb
* @date 2018/7/30
*/
@Slf4j
@RestController
@RequestMapping("/weixin/auth")
public class WXAuthController {
@Resource
private WXUtils wxUtils;
/**
*
* https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
* code
* codeaccess_token
* @return str
*
* @author yclimb
* @date 2018/7/30
*/
/*@ApiOperation(value = "微信支付|网页授权", httpMethod = "GET", notes = "获取前端微信用户的网页授权,得到用户基础信息")*/
@GetMapping("/authorize")
public String authorize(HttpServletRequest request) throws Exception {
// 跳转页面标识
String state = request.getParameter("state");
// 通过code获取access_token
String code = request.getParameter("code");
log.info("authorize:code:{}", code);
// 获取access_token和openid
JSONObject jsonToken = wxUtils.getJsapiAccessTokenByCode(code);
if (null == jsonToken) {
return WXConstants.ERROR;
}
return WXConstants.SUCCESS;
}
/**
* access_tokenopenid(scope snsapi_userinfo)
* @return str
*
* @author yclimb
* @date 2018/7/31
*/
/*@ApiOperation(value = "微信支付|通过access_token和openid请求获取用户信息", httpMethod = "POST", notes = "通过access_token和openid请求获取用户信息")*/
@PostMapping("/userinfo/{access_token}/{openid}")
public String userinfo(@PathVariable String access_token, @PathVariable String openid) {
// 通过access_token和openid请求获取用户信息
JSONObject jsonUserinfo = wxUtils.getJsapiUserinfo(access_token, openid);
if (null == jsonUserinfo) {
return WXConstants.ERROR;
}
// 判断用户是否在系统中是一个用户
String unionid = jsonUserinfo.getString("unionid");
if (StringUtils.isBlank(unionid)) {
return WXConstants.ERROR;
}
/*
// 存储用户信息到数据库
User user = userService.queryByUnionId(unionid);
if (user == null) {
user = JSON.parseObject(jsonUserinfo.toJSONString(), User.class);
user.setUserId(user.getId());
user.setCreateDate(new Date());
user.setIsDel(CommonConstantEnum.UNDELETED.getCode());
// 处理微信昵称emoji表情
if (StringUtils.isNotBlank(user.getNickName())) {
// 编码Base64.decodeBase64()
user.setNickName(UserNickUtil.encodeNickName(user.getNickName()));
}
userService.createEntity(user);
}
// 用户账户信息
Map<String, Object> map = new HashMap<>(2);
// 用户名称解码
user.setNickName(UserNickUtil.decodeNickName(user.getNickName()));
UserAccount userAccount = userAccountService.queryByUserId(user.getId());
map.put("user", user);
return AppMessage.success(map);*/
return WXConstants.SUCCESS;
}
}

View File

@ -0,0 +1,302 @@
package controller;
import com.weixin.pay.constants.WXConstants;
import com.weixin.pay.constants.WXPayConstants;
import com.weixin.pay.util.AESUtil;
import com.weixin.pay.util.WXPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
/**
* Controller
*
* @author yclimb
* @date 2018/6/15
*/
@Slf4j
@RestController
@RequestMapping("/weixin/pay")
public class WXPayController {
/**
* xml
*/
private String resSuccessXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
/**
* xml
*/
private String resFailXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
/**
* APInotify_url访
* url访urlnotify_urlhttps://pay.weixin.qq.com/wxpay/pay.action”
* <p>
*
*
* 15/15/30/180/1800/1800/1800/1800/3600
*
*
*
*
* @author yclimb
* @date 2018/6/15
*/
/*@ApiOperation(value = "微信支付|支付回调接口", httpMethod = "POST", notes = "该链接是通过【统一下单API】中提交的参数notify_url设置如果链接无法访问商户将无法接收到微信通知。")*/
@RequestMapping("/wxnotify")
public void wxnotify(HttpServletRequest request, HttpServletResponse response) {
String resXml = "";
InputStream inStream;
try {
inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
WXPayUtil.getLogger().info("wxnotify:微信支付----start----");
// 获取微信调用我们notify_url的返回信息
String result = new String(outSteam.toByteArray(), "utf-8");
WXPayUtil.getLogger().info("wxnotify:微信支付----result----=" + result);
// 关闭流
outSteam.close();
inStream.close();
// xml转换为map
Map<String, String> map = WXPayUtil.xmlToMap(result);
boolean isSuccess = false;
if (WXPayConstants.SUCCESS.equalsIgnoreCase(map.get(WXPayConstants.RESULT_CODE))) {
WXPayUtil.getLogger().info("wxnotify:微信支付----返回成功");
if (WXPayUtil.isSignatureValid(map, WXPayConstants.API_KEY)) {
// 订单处理 操作 orderconroller 的回写操作?
WXPayUtil.getLogger().info("wxnotify:微信支付----验证签名成功");
// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = resSuccessXml;
isSuccess = true;
} else {
WXPayUtil.getLogger().error("wxnotify:微信支付----判断签名错误");
}
} else {
WXPayUtil.getLogger().error("wxnotify:支付失败,错误信息:" + map.get(WXPayConstants.ERR_CODE_DES));
resXml = resFailXml;
}
/*// 根据付款单号查询付款记录
Payment payment = paymentService.queryPaymentByFlowNumer(map.get("out_trade_no"), PaymentConstantEnum.PAYMENT_TYPE_ORDER.getCode());
// 付款记录修改 & 记录付款日志
int resultPay = paymentService.modifyPaymentByWxnotify(payment, isSuccess);
if (resultPay > 0) {
// 处理业务 - 修改订单状态
WXPayUtil.getLogger().info("wxnotify:微信支付回调:修改的订单===>" + map.get("out_trade_no"));
int updateResult = tradeService.modifyWxnotifyByRelationId(payment.getRelationId(), payment.getPrepayId(), isSuccess);
if (updateResult > 0) {
WXPayUtil.getLogger().info("wxnotify:微信支付回调:修改订单支付状态成功");
} else {
WXPayUtil.getLogger().error("wxnotify:微信支付回调:修改订单支付状态失败");
}
}*/
} catch (Exception e) {
WXPayUtil.getLogger().error("wxnotify:支付回调发布异常:", e);
} finally {
try {
// 处理业务完毕
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} catch (IOException e) {
WXPayUtil.getLogger().error("wxnotify:支付回调发布异常:out", e);
}
}
}
/**
* 退
* <p>
* 退notify_url
* 访
* url访urlnotify_urlhttps://pay.weixin.qq.com/wxpay/pay.action”
* <p>
* 退
*
* 15/15/30/180/1800/1800/1800/1800/3600
*
*
* 退
* @param request req
* @param response resp
* @return res xml
*
* @author yclimb
* @date 2018/6/21
*/
/*@ApiOperation(value = "微信支付|微信退款回调接口", httpMethod = "POST", notes = "该链接是通过【微信退款API】中提交的参数notify_url设置如果参数中传了notify_url则商户平台上配置的回调地址将不会生效。")*/
@RequestMapping("/refund")
public void refund(HttpServletRequest request, HttpServletResponse response) {
String resXml = "";
InputStream inStream;
try {
inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
WXPayUtil.getLogger().info("refund:微信退款----start----");
// 获取微信调用我们notify_url的返回信息
String result = new String(outSteam.toByteArray(), "utf-8");
WXPayUtil.getLogger().info("refund:微信退款----result----=" + result);
// 关闭流
outSteam.close();
inStream.close();
// xml转换为map
Map<String, String> map = WXPayUtil.xmlToMap(result);
boolean isSuccess = false;
if (WXPayConstants.SUCCESS.equalsIgnoreCase(map.get(WXPayConstants.RETURN_CODE))) {
WXPayUtil.getLogger().info("refund:微信退款----返回成功");
/*if (WXPayUtil.isSignatureValid(map, WXPayConstants.API_KEY)) {*/
/** 以下字段在return_code为SUCCESS的时候有返回 **/
// 加密信息:加密信息请用商户秘钥进行解密,详见解密方式
String req_info = map.get("req_info");
/**
*
*
* 1Abase64B
* 2keymd532key* ( key(pay.weixin.qq.com)-->-->API--> )
* 3key*BAES-256-ECBPKCS7Padding
*/
String resultStr = AESUtil.decryptData(req_info);
// WXPayUtil.getLogger().info("refund:解密后的字符串:" + resultStr);
Map<String, String> aesMap = WXPayUtil.xmlToMap(resultStr);
/** 以下为返回的加密字段: **/
// 商户退款单号 是 String(64) 1.21775E+27 商户退款单号
String out_refund_no = aesMap.get("out_refund_no");
// 退款状态 是 String(16) SUCCESS SUCCESS-退款成功、CHANGE-退款异常、REFUNDCLOSE—退款关闭
String refund_status = aesMap.get("refund_status");
/*// 微信订单号 是 String(32) 1.21775E+27 微信订单号
String transaction_id = null;
// 商户订单号 是 String(32) 1.21775E+27 商户系统内部的订单号
String out_trade_no = null;
// 微信退款单号 是 String(32) 1.21775E+27 微信退款单号
String refund_id = null;
// 订单金额 是 Int 100 订单总金额,单位为分,只能为整数,详见支付金额
String total_fee = null;
// 应结订单金额 否 Int 100 当该订单有使用非充值券时,返回此字段。应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。
String settlement_total_fee = null;
// 申请退款金额 是 Int 100 退款总金额,单位为分
String refund_fee = null;
// 退款金额 是 Int 100 退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
String settlement_refund_fee = null;*/
// 退款是否成功
if (!WXPayConstants.SUCCESS.equals(refund_status)) {
resXml = resFailXml;
} else {
// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = resSuccessXml;
isSuccess = true;
}
/*// 根据付款单号查询付款记录
Payment payment = paymentService.queryPaymentByFlowNumer(out_refund_no, PaymentConstantEnum.PAYMENT_TYPE_REFUND.getCode());
// 付款记录修改 & 记录付款日志
int resultPay = paymentService.modifyPaymentByWxnotify(payment, isSuccess);
if (resultPay > 0) {
// 退款订单记录
List<PaymentOrderRefund> paymentOrderRefundList = paymentOrderRefundService.queryListByPaymentId(payment.getId());
// 处理业务 - 修改订单状态
WXPayUtil.getLogger().info("refund:微信支付回调:修改的订单===>" + out_refund_no);
int updateResult = tradeService.modifyWxrefundByRelationId(payment.getRelationId(), paymentOrderRefundList, isSuccess);
if (updateResult > 0) {
WXPayUtil.getLogger().info("refund:微信支付回调:修改订单支付状态成功");
} else {
WXPayUtil.getLogger().error("refund:微信支付回调:修改订单支付状态失败");
}
}*/
/*} else {
WXPayUtil.getLogger().error("refund:微信支付----判断签名错误");
}*/
} else {
WXPayUtil.getLogger().error("refund:支付失败,错误信息:" + map.get(WXPayConstants.RETURN_MSG));
resXml = resFailXml;
}
} catch (Exception e) {
WXPayUtil.getLogger().error("refund:微信退款回调发布异常:", e);
} finally {
try {
// 处理业务完毕
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} catch (IOException e) {
WXPayUtil.getLogger().error("refund:微信退款回调发布异常:out", e);
}
}
}
/**
*
* @return msg
*
* @author yclimb
* @date 2018/7/30
*/
/*@Token(remove = true)
@ApiOperation(value = "微信支付|企业付款到零钱", httpMethod = "POST", notes = "用于企业向微信用户个人付款")*/
@PostMapping("/transfers")
public String transfers(HttpServletRequest request) {
try {
String remoteAddr = request.getRemoteAddr();
return WXConstants.SUCCESS;
} catch (Exception e) {
WXPayUtil.getLogger().error("transfers:微信提现支付异常:", e);
}
return WXConstants.ERROR;
}
}