Browse Source

perf: 升级hutool、poi版本

master
zhangsan 3 years ago
parent
commit
4628ba22e8
  1. 24
      ptos_tall/src/main/java/com/ccsens/ptos_tall/service/UserService.java
  2. 16
      ptos_tall/src/main/java/com/ccsens/ptos_tall/service/WxUserService.java
  3. 2
      util/src/main/java/com/ccsens/util/WebConstant.java
  4. 20
      util/src/main/java/com/ccsens/util/bean/wx/po/WxApiTicket.java
  5. 16
      util/src/main/java/com/ccsens/util/bean/wx/po/WxGetIp.java
  6. 15
      util/src/main/java/com/ccsens/util/wx/WxGzhUtil.java
  7. 3
      util_cloud/src/main/resources/application-util-green.yml
  8. 145
      util_wechat/src/main/java/com/ccsens/wechatutil/bean/dto/NoticeResourceDecode.java
  9. 43
      util_wechat/src/main/java/com/ccsens/wechatutil/bean/dto/WxNativePayNotice.java
  10. 22
      util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/NativePayNoticeVo.java
  11. 120
      util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/WxNativePay.java
  12. 47
      util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxnative/NativePay.java
  13. 224
      util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxnative/NativeUtils.java
  14. 1
      util_wechat/src/main/java/com/ccsens/wechatutil/util/WxCodeError.java
  15. 10
      util_wechat/src/main/java/com/ccsens/wechatutil/util/WxConstant.java
  16. 67
      util_wechat/src/main/java/com/ccsens/wechatutil/wxcommon/WxCommonUtil.java
  17. 39
      util_wechat/src/main/java/com/ccsens/wechatutil/wxofficial/OfficialAccountMessageUtil.java

24
ptos_tall/src/main/java/com/ccsens/ptos_tall/service/UserService.java

@ -242,23 +242,35 @@ public class UserService implements IUserService {
UserVo.UserSign userSignVo;
//获取微信信息并保存
log.info("公众号登陆,{}", code);
WxOauth2UserInfo wxOauth2UserInfo = WxGzhUtil.getOauth2UserInfo(identifyType, code);
WxOauth2UserInfo wxOauth2UserInfo = WxGzhUtil.getOauth2UserInfo(identifyType, code, null, null);
log.info("获取用户的微信信息,{}", wxOauth2UserInfo);
SysAuth theAuth;
if (ObjectUtil.isNull(wxOauth2UserInfo)) {
throw new BaseException(CodeEnum.NOT_SELECT_WX);
}
if(wxOauth2UserInfo.getUnionId() == null){
wxOauth2UserInfo.setUnionId("");
}
SysAuthExample authExample = new SysAuthExample();
authExample.createCriteria().andIdentifyTypeEqualTo((byte) WebConstant.IDENTIFY_TYPE.OAUTH2_Wx.value)
.andIdentifierEqualTo(wxOauth2UserInfo.getOpenId()).andCredentialEqualTo(wxOauth2UserInfo.getUnionId());
if(wxOauth2UserInfo.getUnionId() == null){
authExample.createCriteria().andIdentifyTypeEqualTo((byte) WebConstant.IDENTIFY_TYPE.OAUTH2_Wx.value)
.andIdentifierEqualTo(wxOauth2UserInfo.getOpenId());
}else {
authExample.createCriteria().andIdentifyTypeEqualTo((byte) WebConstant.IDENTIFY_TYPE.OAUTH2_Wx.value)
.andIdentifierEqualTo(wxOauth2UserInfo.getOpenId()).andCredentialEqualTo(wxOauth2UserInfo.getUnionId());
}
List<SysAuth> authList = sysAuthDao.selectByExample(authExample);
if (CollectionUtil.isNotEmpty(authList)) {
theAuth = authList.get(0);
log.info("该用户已有微信登录的auth信息,{}", theAuth);
} else {
SysAuthExample sysAuthExample = new SysAuthExample();
sysAuthExample.createCriteria().andCredentialEqualTo(wxOauth2UserInfo.getUnionId());
List<SysAuth> sysAuthList = sysAuthDao.selectByExample(sysAuthExample);
List<SysAuth> sysAuthList = null;
if(wxOauth2UserInfo.getUnionId() != null){
SysAuthExample sysAuthExample = new SysAuthExample();
sysAuthExample.createCriteria().andCredentialEqualTo(wxOauth2UserInfo.getUnionId());
sysAuthList = sysAuthDao.selectByExample(sysAuthExample);
}
if (CollectionUtil.isNotEmpty(sysAuthList)) {
//添加认证方式
theAuth = new SysAuth();

16
ptos_tall/src/main/java/com/ccsens/ptos_tall/service/WxUserService.java

@ -125,14 +125,16 @@ public class WxUserService implements IWxUserService {
tokenBean.setAvatarUrl(userSign.getAvatarUrl());
log.info("生成token成功");
//根据eventKey更新redis内的用户关注信息
String eventKey = notice.getEventKey();
if (notice.getEventKey().startsWith(PtOsConstant.EVENT_KEY_PREFIX)) {
eventKey = eventKey.substring(PtOsConstant.EVENT_KEY_PREFIX.length());
if(StrUtil.isNotEmpty(notice.getEventKey())){
String eventKey = notice.getEventKey();
if (notice.getEventKey().startsWith(PtOsConstant.EVENT_KEY_PREFIX)) {
eventKey = eventKey.substring(PtOsConstant.EVENT_KEY_PREFIX.length());
}
String key = PtOsConstant.OFFICIAL_EVENT_KEY + eventKey;
long seconds = 60L * 100L;
redisUtil.set(key,tokenBean,seconds);
log.info("存reids--key:{}",key);
}
String key = PtOsConstant.OFFICIAL_EVENT_KEY + eventKey;
long seconds = 60L * 100L;
redisUtil.set(key,tokenBean,seconds);
log.info("存reids--key:{}",key);
break;
case "unsubscribe":
//用openId查找用户

2
util/src/main/java/com/ccsens/util/WebConstant.java

@ -361,7 +361,7 @@ public class WebConstant {
public enum IDENTIFY_TYPE {
Wxmp(0,"微信小程序"), Phone(1,"电话")
, Email(2,"Email"), Account(3,"账号")
,OAUTH2_Wx(4,"微信公众号网页授权登录"),Wx_H5(5,"网页微信登陆")
,OAUTH2_Wx(8,"微信公众号网页授权登录"),Wx_H5(5,"网页微信登陆")
,OAUTH2_WeiBo(6,"微博"),WxEnterprise(7, "企业微信"),
OFFICIAL_ACCOUNT_WX(9,"微信公众号登录"),Wx_H5_TEST(10,"网页微信登陆测试");
// 钉钉是11

20
util/src/main/java/com/ccsens/util/bean/wx/po/WxApiTicket.java

@ -0,0 +1,20 @@
package com.ccsens.util.bean.wx.po;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* @author
*/
@Data
public class WxApiTicket {
@JsonProperty("errcode")
private Integer errcode;
@JsonProperty("errmsg")
private String errmsg;
@JsonProperty("ticket")
private String ticket;
@JsonProperty("expires_in")
private Long expiresIn;
}

16
util/src/main/java/com/ccsens/util/bean/wx/po/WxGetIp.java

@ -0,0 +1,16 @@
package com.ccsens.util.bean.wx.po;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* @author __zHangSan
*/
@Data
public class WxGetIp extends WxBaseEntity{
@JsonProperty("ipList")
private List<String> ip_list;
}

15
util/src/main/java/com/ccsens/util/wx/WxGzhUtil.java

@ -1,5 +1,6 @@
package com.ccsens.util.wx;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONException;
@ -80,6 +81,8 @@ public class WxGzhUtil {
private static final String APPID = "wx7af1bf1e14facf82";
private static final String SECRET = "a6613fae11b497639c0224b820aaf6d9";
private static final String APPID_H5_TEST = "wxd1842e073e0e6d91";
private static final String SECRET_H5_TEST = "96d69b79039caf92a2abafa999880cad";
@ -295,9 +298,9 @@ public class WxGzhUtil {
* @param code OAuth2授权码
* @return WxOauth2AccessToken
*/
public static WxOauth2AccessToken getOauth2AccessToken(WebConstant.IDENTIFY_TYPE identifyType,String code) throws BaseException {
public static WxOauth2AccessToken getOauth2AccessToken(WebConstant.IDENTIFY_TYPE identifyType,String code,String appId, String secret) throws BaseException {
WxOauth2AccessToken wxOauth2AccessToken = null;
String url = String.format(URL_GET_OAUTH2_ACCESS_TOKEN,appId(identifyType),secret(identifyType),code);
String url = String.format(URL_GET_OAUTH2_ACCESS_TOKEN,appId,secret,code);
String response = HttpRequest.get(url).execute().body();
log.info("url: {}\nresponse: {}",url,response);
try {
@ -355,11 +358,15 @@ public class WxGzhUtil {
* @return WxOauth2UserInfo
* @throws BaseException 异常
*/
public static WxOauth2UserInfo getOauth2UserInfo(WebConstant.IDENTIFY_TYPE identifyType,String code) throws BaseException {
public static WxOauth2UserInfo getOauth2UserInfo(WebConstant.IDENTIFY_TYPE identifyType,String code,String appId, String secret) throws BaseException {
if (StrUtil.isNotBlank(PropUtil.wxH5) && "0".equals(PropUtil.wxH5)){
identifyType = WebConstant.IDENTIFY_TYPE.Wx_H5_TEST;
}
WxOauth2AccessToken wxOauth2AccessToken = getOauth2AccessToken(identifyType,code);
if(ObjectUtil.isNull(appId) || ObjectUtil.isNull(secret)){
appId = appId(identifyType);
secret = secret(identifyType);
}
WxOauth2AccessToken wxOauth2AccessToken = getOauth2AccessToken(identifyType,code,appId,secret);
return getOauth2UserInfo(wxOauth2AccessToken.getAccessToken(),wxOauth2AccessToken.getOpenId());
}

3
util_cloud/src/main/resources/application-util-green.yml

@ -1,4 +1,3 @@
#<<<<<<< HEAD
##服务端点暴露
#management:
# endpoints:
@ -59,7 +58,7 @@
## probability: 1.0
# cloud:
# inetutils:
#=======
#服务端点暴露
management:
endpoints:

145
util_wechat/src/main/java/com/ccsens/wechatutil/bean/dto/NoticeResourceDecode.java

@ -0,0 +1,145 @@
package com.ccsens.wechatutil.bean.dto;
import lombok.Data;
import java.util.List;
/**
* @author
*/
@Data
public class NoticeResourceDecode {
public enum TRADE_STATE {
/*** 支付成功 */
SUCCESS("SUCCESS","支付成功"),
/*** 转入退款 */
REFUND("REFUND","转入退款"),
/*** 未支付 */
NOTPAY("NOTPAY","未支付"),
/*** 已关闭 */
CLOSED("CLOSED","已关闭"),
/*** 已撤销 */
REVOKED("REVOKED","已撤销"),
/*** 用户支付中 */
USERPAYING("USERPAYING","用户支付中"),
/*** 支付失败 */
PAYERROR("PAYERROR","支付失败");
public String value;
public String phase;
TRADE_STATE(String value,String thePhase){
this.value =value;
this.phase = thePhase;
}
}
/*** 微信支付订单号 微信支付系统生成的订单号 */
private String transaction_id;
/*** 订单金额 */
private AmountBean amount;
/*** 应用ID */
private String mchid;
/***
* 交易状态枚举值
* SUCCESS支付成功
* REFUND转入退款
* NOTPAY未支付
* CLOSED已关闭
* REVOKED已撤销付款码支付
* USERPAYING用户支付中付款码支付
* PAYERROR支付失败(其他原因如银行返回失败)
*/
private String trade_state;
/*** 银行类型,采用字符串类型的银行标识 */
private String bank_type;
/*** 支付完成时间 yyyy-MM-DDTHH:mm:ss+TIMEZONE*/
private String success_time;
/*** 支付者 */
private PayerBean payer;
/*** 商户订单号 商户系统内部订单号 */
private String out_trade_no;
/*** 应用ID */
private String appid;
/*** 交易状态描述*/
private String trade_state_desc;
/***
* 交易类型枚举值
* JSAPI公众号支付
* NATIVE扫码支付
* APPAPP支付
* MICROPAY付款码支付
* MWEBH5支付
* FACEPAY刷脸支付
*/
private String trade_type;
/*** 附加数据 */
private String attach;
/*** 场景信息 */
private SceneInfoBean scene_info;
/*** 优惠功能 */
private List<PromotionDetailBean> promotion_detail;
@Data
public static class AmountBean {
/*** 用户支付金额,单位为分 */
private int payer_total;
/*** 订单总金额,单位为分 */
private int total;
/*** 货币类型 */
private String currency;
/*** 用户支付币种 */
private String payer_currency;
}
@Data
public static class PayerBean {
/*** 用户标识 */
private String openid;
}
@Data
public static class SceneInfoBean {
/*** 终端设备号(门店号或收银设备ID) */
private String device_id;
}
@Data
public static class PromotionDetailBean {
/*** 优惠券面额 */
private int amount;
/*** 微信出资 */
private int wechatpay_contribute;
/*** 券ID */
private String coupon_id;
/*** 优惠范围 */
private String scope;
/*** 商户出资 */
private int merchant_contribute;
/*** 优惠名称 */
private String name;
/*** 优惠类型 */
private String type;
/*** 其他出资 */
private int other_contribute;
/*** 优惠币种 */
private String currency;
/*** 活动ID */
private String stock_id;
/*** 单品列表 */
private List<GoodsDetailBean> goods_detail;
@Data
public static class GoodsDetailBean {
/*** 商品备注 */
private String goods_remark;
/*** 商品数量 */
private int quantity;
/*** 商品优惠金额 */
private int discount_amount;
/*** 商品编码 */
private String goods_id;
/*** 商品单价 */
private int unit_price;
}
}
}

43
util_wechat/src/main/java/com/ccsens/wechatutil/bean/dto/WxNativePayNotice.java

@ -0,0 +1,43 @@
package com.ccsens.wechatutil.bean.dto;
import lombok.Data;
/**
* @author
*/
@Data
public class WxNativePayNotice {
/**"消息id"*/
private String id;
/**"通知创建的时间,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE"*/
private String create_time;
/**"通知的类型 SUCCESS"*/
private String event_type;
/**"通知的资源数据类型 encrypt-resource"*/
private String resource_type;
/**"回调摘要"*/
private String summary;
/**"微信支付回调消息"*/
private NoticeResource resource;
@Data
public static class NoticeResource {
//"对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM ")
private String algorithm;
//"Base64编码后的开启/停用结果数据密文")
private String ciphertext;
//"附加数据")
private String associated_data;
//"原始回调类型 为transaction")
private String original_type;
//"加密使用的随机串")
private String nonce;
}
@Data
public static class NoticeResourceDecode {
}
}

22
util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/NativePayNoticeVo.java

@ -0,0 +1,22 @@
package com.ccsens.wechatutil.bean.vo;
import lombok.Data;
/**
* @author
*/
@Data
public class NativePayNoticeVo {
/**"code"*/
private String code;
/**消息*/
private String message;
public NativePayNoticeVo() {
}
public NativePayNoticeVo(String code, String message) {
this.code = code;
this.message = message;
}
}

120
util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/WxNativePay.java

@ -0,0 +1,120 @@
package com.ccsens.wechatutil.bean.vo;
import lombok.Data;
import java.util.List;
/**
* @author
*/
@Data
public class WxNativePay {
/**
* 应用ID
*/
private String appid;
/**
* 直连商户号
*/
private String mchid;
/**
* 商品描述
*/
private String description;
/**
* 商户订单号 商户系统内部订单号只能是数字大小写字母_-*且在同一个商户号下唯一
*/
private String out_trade_no;
/**
* 交易结束时间
*/
private String time_expire;
/**
* 附加数据
*/
private String attach;
/**
* 通知地址
*/
private String notify_url;
/**
* 订单优惠标记
*/
private String goods_tag;
/**
* 订单金额
*/
private Amount amount;
/**
* 优惠功能
*/
private Detail detail;
/**
* 场景信息
*/
private SceneInfo scene_info;
/**
* 结算信息
*/
private SceneInfo settle_info;
@Data
public static class Amount{
//总金额 是 单位为分。
private int total;
//货币类型
private String currency;
}
@Data
public static class Detail{
//订单原价 单位为分。
private int cost_price;
//商品小票ID
private String invoice_id;
//单品列表
private List<GoodsDetail> goods_detail;
}
@Data
public static class GoodsDetail{
//商户侧商品编码 是
private String merchant_goods_id;
//微信支付商品编码 否
private String wechatpay_goods_id;
//商品名称
private String goods_name;
//商品数量 是
private int quantity;
//商品单价 是
private int unit_price;
}
@Data
public static class SceneInfo{
//用户终端IP
private String payer_client_ip;
//商户端设备号
private String device_id;
//商户门店信息
private StoreInfo store_info;
}
@Data
public static class StoreInfo{
//门店编号 是
private String id;
//门店名称
private String name;
//地区编码
private String area_code;
//详细地址
private String address;
}
@Data
public static class SettleInfo{
//是否指定分账
private boolean profit_sharing;
}
}

47
util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxnative/NativePay.java

@ -0,0 +1,47 @@
package com.ccsens.wechatutil.payutil.wxnative;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ccsens.util.QrCodeUtil;
import com.ccsens.wechatutil.bean.vo.WxNativePay;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
/**
* @author
*/
@Slf4j
public class NativePay {
/**
* 生成订单返回收款二维码
* @param serialNo 证书序列号
* @param pathPem 秘钥文件地址
* @param wxNativePay 订单信息
* @param filePath 二维码存放地址前缀路径
* @return 返回二维码访问路径不包含前缀
*/
public static String generateOrder( String serialNo, String pathPem, WxNativePay wxNativePay, String filePath){
String path = "";
try {
HttpUrl httpurl = HttpUrl.parse(NativeUtils.NATIVE_URL);
String body = String.valueOf(JSON.parseObject(JSON.toJSONString(wxNativePay)));
String authorization = NativeUtils.schema + " " +
NativeUtils.getToken("POST", httpurl, body, wxNativePay.getOut_trade_no(), wxNativePay.getMchid(), serialNo, pathPem);
//下单调用的接口,JSON格式
String codeUrl = NativeUtils.nativePostBody(NativeUtils.NATIVE_URL, body, authorization);
log.info("调用微信下单返回:{}", codeUrl);
JSONObject jsonObject = JSONObject.parseObject(codeUrl);
String url = jsonObject.getString("code_url");
if(StrUtil.isNotBlank(url)){
path = QrCodeUtil.getQrCodeWithUtf8(url,filePath);
}else {
path = String.valueOf(jsonObject);
}
} catch (Exception e) {
e.printStackTrace();
}
return path;
}
}

224
util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxnative/NativeUtils.java

@ -0,0 +1,224 @@
package com.ccsens.wechatutil.payutil.wxnative;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import okhttp3.HttpUrl;
import org.apache.commons.lang3.RandomStringUtils;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author
*/
public class NativeUtils {
static String schema = "WECHATPAY2-SHA256-RSA2048";
/**
* 请求地址
*/
static String NATIVE_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/native";
/**
* 获取签名信息所有值
*
* @param method 请求方法
* @param url URL地址
* @param body BOdy参数
* @return
*/
static String getToken(String method, HttpUrl url, String body, String orderId, String mchId, String serialNo, String pathPem) throws Exception {
//获得系统时间,把毫秒换算成秒 /1000
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessage(method, url, timestamp, orderId, body);
String signature = sign(message.getBytes("utf-8"), pathPem);
return "mchid=\"" + mchId + "\","
+ "nonce_str=\"" + orderId + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + serialNo + "\","
+ "signature=\"" + signature + "\"";
}
/**
* 拼接明文数值
*
* @param method 请求方法 GET or POST
* @param url 网络请求方法地址 取除域名项
* @param timestamp 时间戳
* @param nonceStr 随机数
* @param body GET请求不需要Body参数POST需要Body
* @return
*/
static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
String canonicalUrl = url.encodedPath();
//get请求自动做了校验,会把空字符串进行识别,注意是空字符串!!!!!
if (url.encodedQuery() != null) {
canonicalUrl += "?" + url.encodedQuery();
}
//官方的方法自动做了换行的所有动作,注意唤起支付的参数不一样需要更换(这里是统一下单所以直接照搬即可)
return method + "\n"
+ canonicalUrl + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
}
/**
* 签名加密
*
* @param message
* @return
* @throws NoSuchAlgorithmException
* @throws SignatureException
* @throws IOException
* @throws InvalidKeyException
*/
static String sign(byte[] message, String pathPem) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
//加密方式
Signature sign = Signature.getInstance("SHA256withRSA");
//私钥,通过getPrivateKey来获取,这是个方法可以接调用 ,需要的是_key.pem文件的绝对路径配上文件名
sign.initSign(getPrivateKey(pathPem));
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
/**
* 获取私钥
*
* @param filename 私钥文件路径 (required)
* @return 私钥对象
* <p>
* 完全不需要修改注意此方法也是去掉了头部和尾部注意文件路径名
*/
public static PrivateKey getPrivateKey(String filename) throws IOException {
String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}
/**
* Post请求带Body参数
*
* @param actionUrl
* @param params
* @param requestString
* @return
* @throws IOException
*/
public static String nativePostBody(String actionUrl, String params, String requestString)
throws IOException {
String serverURL = actionUrl;
StringBuffer sbf = new StringBuffer();
String strRead = null;
URL url = new URL(serverURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//请求post方式
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
//header内的的参数在这里set
connection.setRequestProperty("Content-Type", "application/json");
//Native支付需要的参数表头参数
connection.setRequestProperty("Authorization", requestString);
connection.connect();
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
//body参数放这里
writer.write(params);
writer.flush();
InputStream is = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while ((strRead = reader.readLine()) != null) {
sbf.append(strRead);
sbf.append("\r\n");
}
reader.close();
connection.disconnect();
String results = sbf.toString();
return results;
}
// public static void main(String[] args) throws Exception {
// String apiV3 = "Bb507Ek1mr95aAvvv9OMp2i9eWxZSv1G";
// String nonce = "bexg7pfYD50D";
// String ciphertext="i01zjaHjODHIkNkIXal6lKrfxrYtp2IZFe2NeUL/tU7si3p/G52XXqxTRQLuM03D1MTImmzLXocxVOgjNmAT3wb5/2RB6ty0HT2RJzGDnAkR0OxMQseUyiOUNRW3skJtj2/somJ/O1yHI2uktJLd1hitfu2TqoFe18ueBZdFYFHqnSKoayc3qTCKFsNLQ/gArvM0ODG3qCa2x9PypmcpDEx2U0KKdNmn/kLqDjIE6RdW9RpAhG+5wqOw3717sD5uvIg66PvUp7MdGMDiDi1SdcUqRm8x7Fl43uSIq9bAcsJxW4IT877tzkDHNjSY37iOFr9vuFpjMwLnhkZfClCfivh2R9ShrmFVlR1sXikr7rYQQGn0coSQZJ09UVd0UuwSxd5SNiLISkB/MzuLfvFSe2YTFvM/MR4iJy+JLQIEBZc7ZNhv4qrcRUOnjQlWO7G9+iUpFrviItzC7eN1KTkyOBs6QPI28uUDOt/OV548i+0Pf6xmD+rOS+6vvl1WR9F4LFUvCWr3w5uMmejyCRJmWoQY12boiwT+FxsdF0NJnoSheiY+bBZfcDJ/udpo2PBHuryJ";
// String associated_data = "transaction";
//
// byte[] key = apiV3.getBytes("UTF-8");
// WxAPIV3AesUtil aesUtil = new WxAPIV3AesUtil(key);
// String decryptToString = aesUtil.decryptToString(associated_data.getBytes("UTF-8"),nonce.getBytes("UTF-8"),ciphertext);
// System.out.println(decryptToString);
// }
/**
* 解密微信ApiV3消息
*/
public static class WxAPIV3AesUtil {
static final int KEY_LENGTH_BYTE = 32;
static final int TAG_LENGTH_BIT = 128;
private final byte[] aesKey;
public WxAPIV3AesUtil(byte[] key) {
if (key.length != KEY_LENGTH_BYTE) {
throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
}
this.aesKey = key;
}
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
throws GeneralSecurityException, IOException {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData);
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
}
}

1
util_wechat/src/main/java/com/ccsens/wechatutil/util/WxCodeError.java

@ -10,6 +10,7 @@ public class WxCodeError extends CodeError {
public static final Code WX_HTTP_ERROR = new Code(1,"微信接口请求失败", true);
public static final Code ACCESS_TOKEN_ERROR = new Code(2,"accessToken获取失败", true);
public static final Code OPENID_ERROR = new Code(2,"openId获取失败", true);
public static final Code API_TICKET_ERROR = new Code(3,"API_TICKET获取失败", true);
}

10
util_wechat/src/main/java/com/ccsens/wechatutil/util/WxConstant.java

@ -16,16 +16,20 @@ public class WxConstant {
/*** 默认小程序 */
public static final String ANYRING = "anyring";
/*** 获取微信服务器IP地址 */
public static final String URL_GET_WX_IP = "https://api.weixin.qq.com/cgi-bin/get_api_domain_ip?access_token=%1$s";
/*** 公众号获取accessToken */
public static final String URL_GET_OAUTH2_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%1$s&secret=%2$s&code=%3$s&grant_type=authorization_code";
/*** 公众号发送订阅消息 */
/*** 公众号通过模板发送订阅消息 */
public static final String MESSAGE_TEMPLATE_SEND = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%1$s";
/*** 公众号发送订阅消息 */
public static final String OFFICIAL_MESSAGE_SEND = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%1$s";
/** 创建二维码 */
public static final String QR_CODE_CREATE = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={}";
/**根据openId获取用户信息*/
public static final String USER_INFO = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%1$s&openid=%2$s&lang=zh_CN";
/*** 获取临时票据api_ticket */
public static final String URL_GET_API_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%1$s&type=jsapi";
/*** 小程序登录路径 */

67
util_wechat/src/main/java/com/ccsens/wechatutil/wxcommon/WxCommonUtil.java

@ -1,11 +1,14 @@
package com.ccsens.wechatutil.wxcommon;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.ccsens.util.JacksonUtil;
import com.ccsens.util.RedisUtil;
import com.ccsens.util.WebConstant;
import com.ccsens.util.bean.wx.po.WxAccessToken;
import com.ccsens.util.bean.wx.po.WxApiTicket;
import com.ccsens.util.bean.wx.po.WxGetIp;
import com.ccsens.util.exception.BaseException;
import com.ccsens.wechatutil.util.WxCodeError;
import com.ccsens.wechatutil.util.WxConstant;
@ -39,7 +42,20 @@ public class WxCommonUtil {
public static String getAccessToken(String appId, String secret) throws BaseException {
log.info("获取accessToken,appid:{}", appId.substring(appId.length() - 4));
Object obj = util.redisUtil.get(WxConstant.ACCESS_TOKEN + appId);
if (obj == null || StrUtil.isBlank((String) obj)) {
//使用redis内的token获取微信的服务器id,验证是否正确
boolean flag = false;
if (obj != null && StrUtil.isNotBlank((String) obj)) {
WxGetIp wxGetIp = null;
try {
wxGetIp = getWxIp((String) obj);
}catch (Exception e){
log.error("accessToken不正确,需要重新获取");
}
if(ObjectUtil.isNotNull(wxGetIp)){
flag = true;
}
}
if (!flag) {
WxAccessToken wxAccessToken;
String url = String.format(WxConstant.URL_GET_ACCESS_TOKEN, appId, secret);
String response = HttpRequest.get(url).execute().body();
@ -65,4 +81,53 @@ public class WxCommonUtil {
log.info("读取reids的token:{}", obj);
return (String) obj;
}
/**
* 获取微信服务器IP地址
*/
public static WxGetIp getWxIp(String accessToken) throws BaseException {
log.info("获取微信服务器IP地址");
WxGetIp wxGetIp;
String url = String.format(WxConstant.URL_GET_WX_IP, accessToken);
String response = HttpRequest.get(url).execute().body();
log.info("获取微信服务器IP地址返回: {}", response);
try {
if (StrUtil.isEmpty(response) || null == (wxGetIp = JacksonUtil.jsonToBean(response, WxGetIp.class))) {
return null;
}
} catch (IOException e) {
return null;
}
if (null != wxGetIp.getErrcode()) {
return null;
}
return wxGetIp;
}
/**
* 通过accessToken获取临时票据ticket
*/
public static String getTicketByAccessToken(String accessToken) throws BaseException {
log.info("获取ticket");
WxApiTicket wxApiTicket;
String url = String.format(WxConstant.URL_GET_API_TICKET, accessToken);
String response = HttpRequest.get(url).execute().body();
log.info("getApiTicke: {}", response);
try {
if (StrUtil.isEmpty(response) || null == (wxApiTicket = JacksonUtil.jsonToBean(response, WxApiTicket.class))) {
throw new BaseException(WxCodeError.WX_HTTP_ERROR);
}
} catch (IOException e) {
throw new BaseException(e.getMessage());
}
if (null != wxApiTicket.getErrcode() && wxApiTicket.getErrcode() != 0) {
throw new BaseException(wxApiTicket.getErrcode(), wxApiTicket.getErrmsg());
}
if (StrUtil.isEmpty(wxApiTicket.getTicket())) {
throw new BaseException(WxCodeError.API_TICKET_ERROR);
}
return wxApiTicket.getTicket();
}
}

39
util_wechat/src/main/java/com/ccsens/wechatutil/wxofficial/OfficialAccountMessageUtil.java

@ -2,10 +2,12 @@ package com.ccsens.wechatutil.wxofficial;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.ccsens.util.*;
import com.ccsens.util.exception.BaseException;
import com.ccsens.wechatutil.bean.dto.WxTemplateMessage;
import com.ccsens.wechatutil.bean.po.WxBaseEntity;
import com.ccsens.wechatutil.bean.vo.wxmini.Custom;
import com.ccsens.wechatutil.util.WxCodeError;
import com.ccsens.wechatutil.util.WxConstant;
import com.ccsens.wechatutil.wxcommon.WxCommonUtil;
@ -116,8 +118,43 @@ public class OfficialAccountMessageUtil {
} catch (IOException e) {
throw new BaseException(e.getMessage());
}
if (null != wxBaseEntity.getErrcode()) {
if (null != wxBaseEntity.getErrcode() && wxBaseEntity.getErrcode() != 0) {
throw new BaseException(wxBaseEntity.getErrcode(), wxBaseEntity.getErrmsg());
}
}
public static WxBaseEntity send(String openId, Custom.Type type, Object data, String appId, String secret){
log.info("发送客服消息:{},{},{}", openId, type, data);
if (StrUtil.isEmpty(openId) || type == null || data == null) {
throw new BaseException(CodeError.PARAM_ERROR);
}
String url = String.format(WxConstant.OFFICIAL_MESSAGE_SEND, WxCommonUtil.getAccessToken(appId, secret));
Custom.Message message = new Custom.Message();
message.setTouser(openId);
message.setMsgtype(type.getType());
switch (type) {
case IMAGE:
message.setImage((Custom.Image) data);
break;
case TEXT:
message.setText((Custom.Text) data);
break;
case LINK:
message.setLink((Custom.Link) data);
break;
case MINI_PROGRAM_PAGE:
message.setMiniprogrampage((Custom.MiniProgramPage) data);
break;
default:
throw new BaseException(CodeError.PARAM_ERROR);
}
log.info("发送客服消息路径:{}, 请求:{}", url, message);
String result = RestTemplateUtil.postBody(url, message);
log.info("发送客服消息结果:{}", result);
WxBaseEntity wxBaseEntity = JSONObject.parseObject(result, WxBaseEntity.class);
return wxBaseEntity;
}
}

Loading…
Cancel
Save