This commit is contained in:
2023-03-04 16:29:55 +08:00
commit 397ba75479
1007 changed files with 109050 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
package com.jsowell.wxpay.common;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author 徐柯
* @Description 定义微信支付参数配置类
* @Date 21:06 2021/5/10
* @Param
* @return
**/
public class WeChatPayParameter {
/**
* 微信商户号
*/
public static String mchId;
/**
* 商户在微信公众平台申请服务号对应的APPID
*/
public static String appId;
/**
* 回调报文解密V3密钥key
*/
public static String v3Key;
/**
* 微信获取平台证书列表地址
*/
public static String certificatesUrl;
/**
* 微信APP下单URL
*/
public static String unifiedOrderUrl;
/**
* 微信小程序的单URL
*/
public static String unifiedOrderUrlJS;
/**
* 异步接收微信支付结果通知的回调地址
*/
public static String notifyUrl;
/**
* 微信证书私钥
*/
public static PrivateKey privateKey;
/**
* 微信商家api序列号
*/
public static String mchSerialNo;
// 定义全局容器 保存微信平台证书公钥
public static Map<String, X509Certificate> certificateMap = new ConcurrentHashMap<>();
/**
* jsapi支付 申请退款api
*/
public static String refundJsUrl;
/**
* 异步接收微信退款结果通知的回调地址
*/
public static String refundNotifyUrl;
}

View File

@@ -0,0 +1,98 @@
package com.jsowell.wxpay.config;
import com.jsowell.wxpay.common.WeChatPayParameter;
import com.jsowell.wxpay.utils.WechatPayUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Order(value = 2)
@Component
public class WechatPayConfig implements CommandLineRunner {
/**
* 公众号appid
*/
@Value("${wechat.appId}")
private String wechatAppId;
/**
* 商户号id
*/
@Value("${wechat.mchId}")
private String wechatMchId;
/**
* 商户序列号
*/
@Value("${wechat.mchSerialNo}")
private String mchSerialNo;
/**
* 支付key
*/
@Value("${wechat.v3Key}")
private String wechatV3Key;
/**
* 微信支付回调url
*/
@Value("${wechat.callback}")
private String payCallbackUrl;
/**
* 微信退款回调url
*/
@Value("${wechat.refundCallback}")
private String refundCallbackUrl;
/**
* 统一下单url
*/
@Value("${wechat.unifiedOrder.url}")
private String wechatUnifiedOrderUrl;
/**
* 统一下单url
*/
@Value("${wechat.unifiedOrder.jsurl}")
private String wechatUnifiedOrderUrlJS;
/**
* jsapi申请退款url
*/
@Value("${wechat.refund.jsurl}")
private String wechatRefundJsUrl;
/**
* 平台证书列表地址
*/
@Value("${wechat.certificates.url}")
private String wechatCertificatesUrl;
/**
* 商户私钥路径
*/
@Value("${wechat.key.path}")
private String wechatKeyPath;
@Override
public void run(String... args) throws Exception {
// System.out.println(">>>>>>>>>>>>>>>服务启动执行,执行加载数据等操作 MyStartupRunner1 order 2 <<<<<<<<<<<<<");
//微信支付
WeChatPayParameter.mchId = wechatMchId;
WeChatPayParameter.appId = wechatAppId;
WeChatPayParameter.v3Key = wechatV3Key;
WeChatPayParameter.certificatesUrl = wechatCertificatesUrl;
WeChatPayParameter.unifiedOrderUrl = wechatUnifiedOrderUrl;
WeChatPayParameter.unifiedOrderUrlJS = wechatUnifiedOrderUrlJS;
WeChatPayParameter.notifyUrl = payCallbackUrl;
WeChatPayParameter.refundJsUrl = wechatRefundJsUrl;
WeChatPayParameter.refundNotifyUrl = refundCallbackUrl;
//加载商户私钥
WeChatPayParameter.privateKey = WechatPayUtils.getPrivateKey(wechatKeyPath);
WeChatPayParameter.mchSerialNo = mchSerialNo;
//获取平台证书
WeChatPayParameter.certificateMap = WechatPayUtils.refreshCertificate();
}
}

View File

@@ -0,0 +1,34 @@
package com.jsowell.wxpay.config;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class WeixinLoginProperties implements InitializingBean {
@Value("${weixin.login.gateway}")
private String gateway;
@Value("${weixin.login.appid}")
private String appid;
@Value("${weixin.login.appsecret}")
private String appsecret;
@Value("${weixin.login.redirectUrl}")
private String redirectUrl;
public static String WX_OPEN_GATEWAY;
public static String WX_OPEN_APP_ID;
public static String WX_OPEN_APP_SECRET;
public static String WX_OPEN_REDIRECT_URL;
@Override
public void afterPropertiesSet() throws Exception {
WX_OPEN_APP_ID = appid;
WX_OPEN_GATEWAY = gateway;
WX_OPEN_APP_SECRET = appsecret;
WX_OPEN_REDIRECT_URL = redirectUrl;
}
}

View File

@@ -0,0 +1,70 @@
package com.jsowell.wxpay.dto;
import lombok.Data;
import java.io.Serializable;
/**
* 小程序模板消息发送模板
*/
@Data
public class AppletTemplateMessageSendDTO implements Serializable {
private static final long serialVersionUID = 2234575457450378840L;
// 场景类型1-开始充电2-结束充电)
private String type;
//接收者(用户)的 openid
private String touser;
//所需下发的订阅模板id
private String template_id;
//所跳转的页面
private String page;
//模板消息内容
private Object data;
private StartChargingMessage startChargingMessage;
private StopChargingMessage stopChargingMessage;
@Data
public static class StartChargingMessage {
/**
* 站点名称
* thing5
*/
private String stationName;
/**
* 开始时间
* time2
*/
private String startTime;
}
@Data
public static class StopChargingMessage {
/**
* 充电费用
* amount17
*/
private String chargingAmount;
/**
* 结束时间
* time3
*/
private String endTime;
/**
* 结束原因
* thing7
*/
private String endReason;
}
}

View File

@@ -0,0 +1,35 @@
package com.jsowell.wxpay.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class WeChatRefundDTO {
/**
* 会员id
*/
private String memberId;
/**
* 订单编号
*/
private String orderCode;
/**
* 退款类型
* 1-订单结算退款 2-用户余额退款
*/
private String refundType;
/**
* 退款金额
*/
private BigDecimal refundAmount;
}

View File

@@ -0,0 +1,27 @@
package com.jsowell.wxpay.dto;
import lombok.Data;
/**
* 小程序下发消息DTO
*
* @author JS-ZZA
* @date 2023/2/15 9:50
*/
@Data
public class WechatSendMsgDTO {
/**
* 用户code
*/
private String code;
/**
* 用户openid
*/
private String openId;
/**
* 订单号
*/
private String orderCode;
}

View File

@@ -0,0 +1,67 @@
package com.jsowell.wxpay.response;
import lombok.Data;
/**
* 微信支付通知参数
*/
@Data
public class WechatPayNotifyParameter {
/**
* 通知ID 通知的唯一ID
*/
private String id;
/**
* 通知创建时间 格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE
*/
private String create_time;
/**
* 通知数据类型 支付成功通知为encrypt-resource
*/
private String resource_type;
/**
* 通知类型 支付成功通知的类型为TRANSACTION.SUCCESS
*/
private String event_type;
/**
* 回调摘要 回调摘要 示例值:支付成功
*/
private String summary;
/**
* 通知数据 通知资源数据json格式
*/
private Resource resource;
@Data
public static class Resource {
/**
* 原始类型 原始回调类型为transaction
*/
private String original_type;
/**
* 加密算法类型 对开启结果数据进行加密的加密算法目前只支持AEAD_AES_256_GCM
*/
private String algorithm;
/**
* 数据密文 Base64编码后的开启/停用结果数据密文
*/
private String ciphertext;
/**
* 附加数据
*/
private String associated_data;
/**
* 随机串 加密使用的随机串
*/
private String nonce;
}
}

View File

@@ -0,0 +1,112 @@
package com.jsowell.wxpay.response;
import lombok.Data;
@Data
public class WechatPayNotifyResource {
/**
* 商户号
*/
private String mchid;
/**
* 应用ID
*/
private String appid;
/**
* 商户订单号 商户系统内部订单号只能是数字、大小写字母_-*且在同一个商户号下唯一。
*/
private String out_trade_no;
/**
* 微信支付订单号 微信支付系统生成的订单号。
*/
private String transaction_id;
/**
* 交易类型
* JSAPI公众号支付
* NATIVE扫码支付
* APPAPP支付
* MICROPAY付款码支付
* MWEBH5支付
* FACEPAY刷脸支付
*/
private String trade_type;
/**
* 交易状态,枚举值:
* SUCCESS支付成功
* REFUND转入退款
* NOTPAY未支付
* CLOSED已关闭
* REVOKED已撤销付款码支付
* USERPAYING用户支付中付款码支付
* PAYERROR支付失败(其他原因,如银行返回失败)
*/
private String trade_state;
/**
* 交易状态描述
*/
private String trade_state_desc;
/**
* 付款银行 银行类型,采用字符串类型的银行标识。
* https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml#part-6
*/
private String bank_type;
/**
* 附加数据
*/
private String attach;
/**
* 支付完成时间 支付完成时间遵循rfc3339标准格式格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE
*/
private String success_time;
/**
* 支付者信息
*/
private Payer payer;
/**
* 订单金额
*/
private Amount amount;
@Data
public static class Payer {
/**
* 用户标识 用户在直连商户appid下的唯一标识。
*/
private String openid;
}
@Data
public static class Amount {
/**
* 总金额 订单总金额,单位为分。
*/
private String total;
/**
* 用户支付金额 用户支付金额,单位为分。
*/
private String payer_total;
/**
* 货币类型 CNY人民币境内商户号仅支持人民币。
*/
private String currency;
/**
* 用户支付币种
*/
private String payer_currency;
}
}

View File

@@ -0,0 +1,83 @@
package com.jsowell.wxpay.response;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 微信退款通知参数
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class WechatPayRefundNotifyResource {
/**
* 直连商户号
*/
private String mchid;
/**
* 商户订单号
*/
private String out_trade_no;
/**
* 微信支付订单号
*/
private String transaction_id;
/**
* 商户退款单号
*/
private String out_refund_no;
/**
* 微信支付退款单号
*/
private String refund_id;
/**
* 退款状态
*/
private String refund_status;
/**
* 退款成功时间
*/
private String success_time;
/**
* 退款入账账户
*/
private String user_received_account;
/**
* 金额信息
*/
private Amount amount;
@Data
public static class Amount {
/**
* 订单金额
*/
private int total;
/**
* 退款金额
*/
private int refund;
/**
* 用户支付金额
*/
private int payer_total;
/**
* 用户退款金额
*/
private int payer_refund;
}
}

View File

@@ -0,0 +1,59 @@
package com.jsowell.wxpay.response;
import lombok.Data;
@Data
public class WechatPayRefundRequest {
/**
* 微信支付订单号
*/
private String transaction_id;
/**
* 商户订单号
*/
private String out_trade_no;
/**
* 商户退款单号
*/
private String out_refund_no;
/**
* 退款原因
*/
private String reason;
/**
* 退款结果回调url
*/
private String notify_url;
/**
* 退款资金来源
*/
private String funds_account;
/**
* 金额信息
*/
private Amount amount;
@Data
public static class Amount {
/**
* 退款金额
*/
private int refund;
/**
* 原订单金额
*/
private int total;
/**
* 退款币种
*/
private String currency = "CNY";
}
}

View File

@@ -0,0 +1,161 @@
package com.jsowell.wxpay.response;
import lombok.Data;
import java.util.List;
@Data
public class WechatPayRefundResponse {
/**
* 微信支付退款单号
*/
private String refund_id;
/**
* 商户退款单号
*/
private String out_refund_no;
/**
* 微信支付订单号
*/
private String transaction_id;
/**
* 商户订单号
*/
private String out_trade_no;
/**
* 退款渠道
* 枚举值:
* ORIGINAL原路退款
* BALANCE退回到余额
* OTHER_BALANCE原账户异常退到其他余额账户
* OTHER_BANKCARD原银行卡异常退到其他银行卡
*/
private String channel;
/**
* 退款入账账户
* 取当前退款单的退款入账方,有以下几种情况:
* 1退回银行卡{银行名称}{卡类型}{卡尾号}
* 2退回支付用户零钱:支付用户零钱
* 3退还商户:商户基本账户商户结算银行账户
* 4退回支付用户零钱通:支付用户零钱通
*/
private String user_received_account;
/**
* 退款成功时间
*/
private String success_time;
/**
* 退款创建时间
*/
private String create_time;
/**
* 退款状态
* 退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
* 枚举值:
* SUCCESS退款成功
* CLOSED退款关闭
* PROCESSING退款处理中
* ABNORMAL退款异常
*/
private String status;
/**
* 资金账户
* 退款所使用资金对应的资金账户类型
* 枚举值:
* UNSETTLED : 未结算资金
* AVAILABLE : 可用余额
* UNAVAILABLE : 不可用余额
* OPERATION : 运营户
* BASIC : 基本账户(含可用余额和不可用余额)
*/
private String funds_account;
/**
* 金额详细信息
*/
private Amount amount;
@Data
public static class Amount {
/**
* 订单金额
*/
private int total;
/**
* 退款金额
*/
private int refund;
/**
* 退款出资账户及金额
*/
private List<From> from;
/**
* 用户支付金额
*/
private int payer_total;
/**
* 用户退款金额
*/
private int payer_refund;
/**
* 应结退款金额
*/
private int settlement_refund;
/**
* 应结订单金额
*/
private int settlement_total;
/**
* 优惠退款金额
*/
private int discount_refund;
/**
* 退款币种
*/
private String currency;
/**
* 手续费退款金额
*/
private int refund_fee;
}
/**
* 退款出资的账户类型及金额信息
*/
@Data
public static class From {
/**
* 出资账户类型
* 下面枚举值多选一。
* 枚举值:
* AVAILABLE : 可用余额
* UNAVAILABLE : 不可用余额
*/
private String account;
/**
* 出资金额
*/
private int amount;
}
}

View File

@@ -0,0 +1,288 @@
package com.jsowell.wxpay.service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.http.HttpUtils;
import com.jsowell.pile.service.IOrderBasicInfoService;
import com.jsowell.pile.vo.uniapp.SendMessageVO;
import com.jsowell.wxpay.config.WeixinLoginProperties;
import com.jsowell.wxpay.dto.AppletTemplateMessageSendDTO;
import com.jsowell.wxpay.dto.WechatSendMsgDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Service
public class WxAppletRemoteService {
private Logger log = LoggerFactory.getLogger(WxAppletRemoteService.class);
private static final String WX_APPLET_URl = "https://api.weixin.qq.com/cgi-bin";
private static final String GET_USER_PHONE_NUMBER_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";
@Autowired
private ObjectMapper objectMapper;
@Autowired
private RedisCache redisCache;
@Autowired
private IOrderBasicInfoService orderBasicInfoService;
@Value("${weixin.login.appid}")
private String appid;
@Value("${weixin.login.appsecret}")
private String secret;
@Value("${weixin.sendMsg.startChargingTmpId}")
private String startChargingTmpId;
@Value("${weixin.sendMsg.stopChargingTmpId}")
private String stopChargingTmpId;
/**
* 获取accessToken
*
* @return
*/
public String getAccessToken() {
// String appid = Constants.APP_ID;
// String secret = Constants.APP_SECRET;
// 这里我是从配置文件中取得appid和appsecret
// appid = properties.getAppId();
// secret = properties.getAppSecret();
//查询token是否存在
String redisKey = "AccessToken_" + appid;
// 使用缓存先查询AccessToken是否存在
String accessToken = redisCache.getCacheObject(redisKey);
// 存在直接返回不存在重新获取AccessToken
if (!Strings.isNullOrEmpty(accessToken)) {
return accessToken;
}
// 获取AccessToken的url
String grantType = "client_credential";
// https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=
String url = WX_APPLET_URl + "/token?grant_type=" + grantType + "&appid=" + appid + "&secret=" + secret;
// 获取到AccessToken
String token = HttpUtils.sendGet(url);
Map<String, Object> map = null;
try {
map = objectMapper.readValue(token, Map.class);
} catch (IOException e) {
log.error("小程序异常通知-获取AccessToken-转化异常", e);
}
String access_token = String.valueOf(map.get("access_token"));
// 把AccessToken存入缓存中并设置过期时间因为access_token的过期时间是两小时我们缓存的时间一定要小于两小时
redisCache.setCacheObject(redisKey, access_token, 300);
if (map.get("errcode") != null || map.get("errmsg") != null) {
String errcode = String.valueOf(map.get("errcode"));
String errmsg = String.valueOf(map.get("errmsg"));
if (!errcode.equals("0")) {
log.error("获取token失败code=" + errcode + "msg=" + errmsg);
return null;
}
}
return access_token;
}
/**
* 获取手机号
*
* @param code
* @return
*/
public String getMobileNumberByCode(String code) {
if (StringUtils.isBlank(code)) {
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
}
// 请求获取令牌
String access_token = getAccessToken();
// 通过tokencode前端getPhoneNum按钮返回的code而不是登录的code发送post请求到官方获取到手机号码
String postUrl = GET_USER_PHONE_NUMBER_URL + "?access_token=" + access_token;
JSONObject paramJson = new JSONObject();
paramJson.put("code", code);
String postResult = HttpUtils.sendPost(postUrl, paramJson.toJSONString());
JSONObject postResultJson = JSONObject.parseObject(postResult);
String errCode = postResultJson.getString("errcode");
if (!StringUtils.equals(errCode, Constants.ZERO)) {
// errCode不为0表示有错误
String errMsg = postResultJson.getString("errmsg");
log.info("发送Post请求失败,错误消息:{}", errMsg);
throw new BusinessException(errCode, errMsg);
}
JSONObject phoneInfoJson = (JSONObject) postResultJson.get("phone_info");
return phoneInfoJson.getString("phoneNumber");
}
/**
* 获取openId
*
* @param code
* @return
*/
public String getOpenIdByCode(String code) {
String baseAccessTokenUrl = WeixinLoginProperties.WX_OPEN_GATEWAY +
"?appid=%s" +
"&secret=%s" +
"&js_code=%s" +
"&grant_type=authorization_code";
log.info("appid:{},appscrect:{}", WeixinLoginProperties.WX_OPEN_APP_ID, WeixinLoginProperties.WX_OPEN_APP_SECRET);
String accessTokenUrl = String.format(baseAccessTokenUrl, WeixinLoginProperties.WX_OPEN_APP_ID, WeixinLoginProperties.WX_OPEN_APP_SECRET, code);
//2执行请求获取微信请求返回得数据
String result = HttpUtils.sendGet(accessTokenUrl);
// 3 对微信返回得数据进行转换
Map<String, Object> resultMap = JSONObject.parseObject(result, HashMap.class);
log.info("微信返回的日志信息是code:{}resultMap{}", code, resultMap);
if (resultMap.get("errcode") != null) {
throw new BusinessException("22006", "微信登录出错!");
}
// 4: 解析微信用户得唯一凭证openid
String openid = (String) resultMap.get("openid");
if (StringUtils.isBlank(openid)) {
throw new BusinessException("22009", "登录失败,尝试刷新重新扫码登录!!!");
}
// 5封装返回
return openid;
}
/**
* 开始充电发送消息
* @param dto
* @return
*/
public Map<String, String> startChargingSendMsg(WechatSendMsgDTO dto) {
// 通过code查询openId并set
String openId = getOpenIdByCode(dto.getCode());
if (StringUtils.isBlank(openId)) {
return null;
}
AppletTemplateMessageSendDTO msgInfo = new AppletTemplateMessageSendDTO();
msgInfo.setType("1"); // 1-开始充电推送消息
msgInfo.setTouser(openId);
// 通过orderCode查询到充电站点和开始时间并set
String orderCode = dto.getOrderCode();
SendMessageVO sendMessageVO = orderBasicInfoService.selectOrderInfoByOrderCode(orderCode);
AppletTemplateMessageSendDTO.StartChargingMessage startChargingMessage = new AppletTemplateMessageSendDTO.StartChargingMessage();
msgInfo.setStartChargingMessage(startChargingMessage);
if (StringUtils.isBlank(sendMessageVO.getChargeStartTime())) {
startChargingMessage.setStartTime(DateUtils.dateTimeNow("yyyy-MM-dd HH:mm"));
}else {
startChargingMessage.setStartTime(sendMessageVO.getChargeStartTime()); // 开始时间
}
startChargingMessage.setStationName(sendMessageVO.getStationName()); // 站点名称
return uniAppSendMsg(msgInfo);
}
/**
* 停止充电发送消息
* @param dto
* @return
*/
public Map<String, String> stopChargingSendMsg(WechatSendMsgDTO dto) {
// 通过订单号查询订单金额
AppletTemplateMessageSendDTO msgInfo = new AppletTemplateMessageSendDTO();
SendMessageVO sendMessageVO = orderBasicInfoService.selectOrderInfoByOrderCode(dto.getOrderCode());
msgInfo.setType("2"); // 2-结束充电推送消息
msgInfo.setTouser(sendMessageVO.getOpenId());
// 封装对象并调用发送消息的方法
AppletTemplateMessageSendDTO.StopChargingMessage stopChargingMessage = new AppletTemplateMessageSendDTO.StopChargingMessage();
msgInfo.setStopChargingMessage(stopChargingMessage);
stopChargingMessage.setChargingAmount(sendMessageVO.getOrderAmount());
stopChargingMessage.setEndReason(sendMessageVO.getStopReason());
if (StringUtils.isBlank(sendMessageVO.getChargeStopTime())) {
stopChargingMessage.setEndTime(DateUtils.dateTimeNow("yyyy-MM-dd HH:mm"));
}else {
stopChargingMessage.setEndTime(sendMessageVO.getChargeStopTime());
}
return uniAppSendMsg(msgInfo);
}
/**
* 小程序发送消息方法
* @param dto
* @return
*/
private Map<String, String> uniAppSendMsg(AppletTemplateMessageSendDTO dto) {
// 判断是什么场景调用此方法1-开始充电推送消息2-充电结束推送消息)
String type = dto.getType();
// 根据不同的场景set不同的对象
if (StringUtils.equals("1", type)) {
// 开始充电
String templateId = startChargingTmpId;
dto.setTemplate_id(templateId);
// dto.setPage("跳转的页面");
Map<String, Object> map = new HashMap<>();
map.put("thing5", ImmutableMap.of("value", dto.getStartChargingMessage().getStationName())); // 充电站名称
map.put("time2", ImmutableMap.of("value", dto.getStartChargingMessage().getStartTime())); // 开始时间
dto.setData(map);
} else if (StringUtils.equals("2", type)) {
// 结束充电
String templateId = stopChargingTmpId;
dto.setTemplate_id(templateId);
// dto.setPage("跳转的页面");
Map<String, Object> map = new HashMap<>();
map.put("amount17", ImmutableMap.of("value", dto.getStopChargingMessage().getChargingAmount())); // 充电金额
map.put("time3", ImmutableMap.of("value", dto.getStopChargingMessage().getEndTime())); // 结束时间
map.put("thing7", ImmutableMap.of("value", dto.getStopChargingMessage().getEndReason())); // 结束原因
dto.setData(map);
}
// 调用下面的发送消息接口
return uniformMessageSend(dto);
}
/**
* 同一消息发送接口
* AppletTemplateMessageSendDTO 是一个传输类
*/
public Map<String, String> uniformMessageSend(AppletTemplateMessageSendDTO data) {
String token = getAccessToken();
// 调用发型接口
String url = WX_APPLET_URl + "/message/subscribe/send?access_token=" + token;
String returnData = HttpUtils.sendPost(url, JSON.toJSONString(data));
Map<String, Object> map = null;
try {
map = objectMapper.readValue(returnData, Map.class);
} catch (IOException e) {
log.error("小程序异常通知-同一消息发送-转化异常", e);
}
String errcode = String.valueOf(map.get("errcode"));
String errmsg = String.valueOf(map.get("errmsg"));
if (!errcode.equals(Constants.ZERO)) {
log.error("消息发送失败code=" + errcode + "msg=" + errmsg);
}
Map<String, String> resultMap = new HashMap<>();
resultMap.put("code", errcode);
resultMap.put("message", errmsg);
return resultMap;
}
}

View File

@@ -0,0 +1,45 @@
package com.jsowell.wxpay.utils;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class AesUtil {
static final int KEY_LENGTH_BYTE = 32;
static final int TAG_LENGTH_BIT = 128;
private final byte[] aesKey;
public AesUtil(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);
}
}
}

View File

@@ -0,0 +1,87 @@
package com.jsowell.wxpay.utils;
import com.google.zxing.LuminanceSource;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
public class BufferedImageLuminanceSource extends LuminanceSource {
private final BufferedImage image;
private final int left;
private final int top;
public BufferedImageLuminanceSource(BufferedImage image) {
this(image, 0, 0, image.getWidth(), image.getHeight());
}
public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
super(width, height);
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
if (left + width > sourceWidth || top + height > sourceHeight) {
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
}
for (int y = top; y < top + height; y++) {
for (int x = left; x < left + width; x++) {
if ((image.getRGB(x, y) & 0xFF000000) == 0) {
image.setRGB(x, y, 0xFFFFFFFF); // = white
}
}
}
this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
this.image.getGraphics().drawImage(image, 0, 0, null);
this.left = left;
this.top = top;
}
public byte[] getRow(int y, byte[] row) {
if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
int width = getWidth();
if (row == null || row.length < width) {
row = new byte[width];
}
image.getRaster().getDataElements(left, top + y, width, 1, row);
return row;
}
public byte[] getMatrix() {
int width = getWidth();
int height = getHeight();
int area = width * height;
byte[] matrix = new byte[area];
image.getRaster().getDataElements(left, top, width, height, matrix);
return matrix;
}
public boolean isCropSupported() {
return true;
}
public LuminanceSource crop(int left, int top, int width, int height) {
return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
}
public boolean isRotateSupported() {
return true;
}
public LuminanceSource rotateCounterClockwise() {
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g = rotatedImage.createGraphics();
g.drawImage(image, transform, null);
g.dispose();
int width = getWidth();
return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
}
}

View File

@@ -0,0 +1,137 @@
package com.jsowell.wxpay.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class HttpUtils {
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
private static final ObjectMapper JSON = new ObjectMapper();
/**
* get方法
*
* @param url
* @return
*/
public static JsonNode doGet(String url) {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpGet httpget = new HttpGet(url);
httpget.addHeader("Content-Type", "application/json;charset=UTF-8");
httpget.addHeader("Accept", "application/json");
try {
String token = WechatPayUtils.getToken("GET", new URL(url), "");
httpget.addHeader("Authorization", token);
CloseableHttpResponse httpResponse = httpClient.execute(httpget);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
String jsonResult = EntityUtils.toString(httpResponse.getEntity());
return JSON.readTree(jsonResult);
} else {
log.warn(EntityUtils.toString(httpResponse.getEntity()));
}
} catch (Exception e) {
log.error("HttpUtils.doGet error", e);
} finally {
try {
httpClient.close();
} catch (Exception e) {
log.error("httpClient.close() error", e);
}
}
return null;
}
/**
* 封装post
*
* @return
*/
public static Map<String, Object> doPost(String url, String body) {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json;chartset=utf-8");
httpPost.addHeader("Accept", "application/json");
try {
String token = WechatPayUtils.getToken("POST", new URL(url), body);
httpPost.addHeader("Authorization", token);
if (body == null) {
throw new IllegalArgumentException("data参数不能为空");
}
StringEntity stringEntity = new StringEntity(body, "utf-8");
httpPost.setEntity(stringEntity);
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if (httpResponse.getStatusLine().getStatusCode() == 200) {
String jsonResult = EntityUtils.toString(httpEntity);
return JSON.readValue(jsonResult, HashMap.class);
} else {
log.warn("微信支付错误信息" + EntityUtils.toString(httpEntity));
}
} catch (Exception e) {
log.error("HttpUtils.doPost error", e);
} finally {
try {
httpClient.close();
} catch (Exception e) {
log.error("httpClient.close() error", e);
}
}
return null;
}
/**
* 封装post
*
* @return
*/
public static Map<String, Object> doPostWexin(String url, String body) {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json;chartset=utf-8");
httpPost.addHeader("Accept", "application/json");
try {
String token = WechatPayUtils.getToken("POST", new URL(url), body);
httpPost.addHeader("Authorization", token);
if (body == null) {
throw new IllegalArgumentException("data参数不能为空");
}
StringEntity stringEntity = new StringEntity(body, "utf-8");
httpPost.setEntity(stringEntity);
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if (httpResponse.getStatusLine().getStatusCode() == 200) {
String jsonResult = EntityUtils.toString(httpEntity);
return JSON.readValue(jsonResult, HashMap.class);
} else {
log.error("微信支付错误信息:{}", EntityUtils.toString(httpEntity));
}
} catch (Exception e) {
log.error("HttpUtils.doPostWexin error", e);
} finally {
try {
httpClient.close();
} catch (Exception e) {
log.error("httpClient.close() error", e);
}
}
return null;
}
}

View File

@@ -0,0 +1,147 @@
package com.jsowell.wxpay.utils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.Hashtable;
public class QRCodeUtil {
private static final String CHARSET = "utf-8";
private static final String FORMAT_NAME = "JPG";
// 二维码尺寸
private static final int QRCODE_SIZE = 300;
// LOGO宽度
private static final int WIDTH = 90;
// LOGO高度
private static final int HEIGHT = 90;
private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {
Hashtable hints = new Hashtable();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
hints);
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
if (imgPath == null || "".equals(imgPath)) {
return image;
}
// 插入图片
QRCodeUtil.insertImage(image, imgPath, needCompress);
return image;
}
private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
File file = new File(imgPath);
if (!file.exists()) {
System.err.println("" + imgPath + " 该文件不存在!");
return;
}
Image src = ImageIO.read(new File(imgPath));
int width = src.getWidth(null);
int height = src.getHeight(null);
if (needCompress) { // 压缩LOGO
if (width > WIDTH) {
width = WIDTH;
}
if (height > HEIGHT) {
height = HEIGHT;
}
Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(image, 0, 0, null); // 绘制缩小后的图
g.dispose();
src = image;
}
// 插入LOGO
Graphics2D graph = source.createGraphics();
int x = (QRCODE_SIZE - width) / 2;
int y = (QRCODE_SIZE - height) / 2;
graph.drawImage(src, x, y, width, height, null);
Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
graph.setStroke(new BasicStroke(3f));
graph.draw(shape);
graph.dispose();
}
public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
mkdirs(destPath);
ImageIO.write(image, FORMAT_NAME, new File(destPath));
}
public static BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception {
BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
return image;
}
public static void mkdirs(String destPath) {
File file = new File(destPath);
// 当文件夹不存在时mkdirs会自动创建多层目录区别于mkdir(mkdir如果父目录不存在则会抛出异常)
if (!file.exists() && !file.isDirectory()) {
file.mkdirs();
}
}
public static void encode(String content, String imgPath, String destPath) throws Exception {
QRCodeUtil.encode(content, imgPath, destPath, false);
}
public static void encode(String content, String destPath) throws Exception {
QRCodeUtil.encode(content, null, destPath, false);
}
public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
throws Exception {
BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
ImageIO.write(image, FORMAT_NAME, output);
}
public static void encode(String content, OutputStream output) throws Exception {
QRCodeUtil.encode(content, null, output, false);
}
public static String decode(File file) throws Exception {
BufferedImage image;
image = ImageIO.read(file);
if (image == null) {
return null;
}
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result result;
Hashtable hints = new Hashtable();
hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
result = new MultiFormatReader().decode(bitmap, hints);
String resultStr = result.getText();
return resultStr;
}
public static String decode(String path) throws Exception {
return QRCodeUtil.decode(new File(path));
}
}

View File

@@ -0,0 +1,243 @@
package com.jsowell.wxpay.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.jsowell.wxpay.common.WeChatPayParameter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
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;
/**
* 参考官网 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml
*/
public class WechatPayUtils {
/**
* 获取私钥。
*
* @param filename 私钥文件路径 (required)
* @return 私钥对象
*/
public static PrivateKey getPrivateKey(String filename) throws IOException {
// System.out.println("filename:" + filename);
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("无效的密钥格式");
}
}
/**
* 生成token 也就是生成签名
*
* @param method
* @param url
* @param body
* @return
* @throws Exception
*/
public static String getToken(String method, URL url, String body) throws Exception {
String nonceStr = getNonceStr();
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = sign(message.getBytes("utf-8"));
return "WECHATPAY2-SHA256-RSA2048 " + "mchid=\"" + WeChatPayParameter.mchId + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + WeChatPayParameter.mchSerialNo + "\","
+ "signature=\"" + signature + "\"";
}
/**
* 生成token
*
* @param method
* @param url
* @param body
* @return
* @throws Exception
*/
public static Map<String, Object> getTokenWeixin(String method, URL url, String body, String prepay_id) throws Exception {
String nonceStr = getNonceStr();
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = sign(message.getBytes("utf-8"));
Map<String, Object> map = new HashMap<>();
map.put("timeStamp", String.valueOf(timestamp));
map.put("nonceStr", nonceStr);
map.put("package", "prepay_id=" + prepay_id);
map.put("signType", "RSA");
map.put("paySign", signature);
return map;
}
/**
* 生成签名
*
* @param message
* @return
* @throws Exception
*/
public static String sign(byte[] message) throws Exception {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(WeChatPayParameter.privateKey);
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
/**
* 生成签名串
*
* @param method
* @param url
* @param timestamp
* @param nonceStr
* @param body
* @return
*/
public static String buildMessage(String method, URL url, long timestamp, String nonceStr, String body) {
String canonicalUrl = url.getPath();
if (url.getQuery() != null) {
canonicalUrl += "?" + url.getQuery();
}
return method + "\n"
+ canonicalUrl + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
}
/**
* 生成随机数
*
* @return
*/
public static String getNonceStr() {
return UUID.randomUUID().toString()
.replaceAll("-", "")
.substring(0, 32);
}
/**
* 获取平台证书
*
* @return
*/
public static Map<String, X509Certificate> refreshCertificate() throws Exception {
Map<String, X509Certificate> certificateMap = new HashMap();
// 1: 执行get请求
JsonNode jsonNode = HttpUtils.doGet(WeChatPayParameter.certificatesUrl);
// 2: 获取平台验证的相关参数信息
JsonNode data = jsonNode.get("data");
if (data != null) {
for (int i = 0; i < data.size(); i++) {
JsonNode encrypt_certificate = data.get(i).get("encrypt_certificate");
//对关键信息进行解密
AesUtil aesUtil = new AesUtil(WeChatPayParameter.v3Key.getBytes());
String associated_data = encrypt_certificate.get("associated_data").toString().replaceAll("\"", "");
String nonce = encrypt_certificate.get("nonce").toString().replaceAll("\"", "");
String ciphertext = encrypt_certificate.get("ciphertext").toString().replaceAll("\"", "");
//证书内容
String certStr = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
//证书内容转成证书对象
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate x509Cert = (X509Certificate) cf.generateCertificate(
new ByteArrayInputStream(certStr.getBytes("utf-8"))
);
String serial_no = data.get(i).get("serial_no").toString().replaceAll("\"", "");
certificateMap.put(serial_no, x509Cert);
}
}
return certificateMap;
}
/**
* 验证签名
*
* @param certificate
* @param message
* @param signature
* @return
*/
public static boolean verify(X509Certificate certificate, byte[] message, String signature) {
try {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initVerify(certificate);
sign.update(message);
return sign.verify(Base64.getDecoder().decode(signature));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
} catch (SignatureException e) {
throw new RuntimeException("签名验证过程发生了错误", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("无效的证书", e);
}
}
/**
* 参考网站 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml
*
* @param appId
* @param prepay_id
* @return
* @throws IOException
* @throws SignatureException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static HashMap<String, Object> getTokenWeixin(String appId, String prepay_id) throws Exception {
// 获取随机字符串
String nonceStr = getNonceStr();
// 获取微信小程序支付package
String packagestr = "prepay_id=" + prepay_id;
long timestamp = System.currentTimeMillis() / 1000;
//签名使用字段appId、timeStamp、nonceStr、package计算得出的签名值
String message = buildMessageTwo(appId, timestamp, nonceStr, packagestr);
//获取对应的签名
String signature = sign(message.getBytes("utf-8"));
// 组装返回
HashMap<String, Object> map = new HashMap<>();
map.put("timeStamp", String.valueOf(timestamp));
map.put("nonceStr", nonceStr);
map.put("package", packagestr);
map.put("signType", "RSA");
map.put("paySign", signature);
return map;
}
private static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
return appId + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ packag + "\n";
}
}

View File

@@ -0,0 +1,85 @@
package com.jsowell.wxpay.vo;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName BaseController
* @Author xuke
* @Date 2021/1/17 13:01
* @Description通用数据返回格式
* @Version: 1.0
*/
@Data
@ToString
public class R implements Serializable {
private Boolean success;
private Integer code;
private String message;
private Map<String, Object> data = new HashMap<String, Object>();
private R() {
}
public static R ok() {
R r = new R();
r.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());
r.setCode(ResultCodeEnum.SUCCESS.getCode());
r.setMessage(ResultCodeEnum.SUCCESS.getMessage());
return r;
}
public static R error() {
R r = new R();
r.setSuccess(ResultCodeEnum.UNKNOWN_REASON.getSuccess());
r.setCode(ResultCodeEnum.UNKNOWN_REASON.getCode());
r.setMessage(ResultCodeEnum.UNKNOWN_REASON.getMessage());
return r;
}
public static R setResult(ResultCodeEnum resultCodeEnum) {
R r = new R();
r.setSuccess(resultCodeEnum.getSuccess());
r.setCode(resultCodeEnum.getCode());
r.setMessage(resultCodeEnum.getMessage());
return r;
}
public R success(Boolean success) {
this.setSuccess(success);
return this;
}
public R message(String message) {
this.setMessage(message);
return this;
}
public R code(Integer code) {
this.setCode(code);
return this;
}
public R data(String key, Object value) {
this.data.put(key, value);
return this;
}
public R data(Map<String, Object> map) {
this.setData(map);
return this;
}
public Map<String,Object> toMap(){
return this.data;
}
}

View File

@@ -0,0 +1,42 @@
package com.jsowell.wxpay.vo;
import lombok.Getter;
@Getter
public enum ResultCodeEnum {
SUCCESS(true, 20000,"成功"),
UNKNOWN_REASON(false, 20001, "未知错误"),
LOGIN_PHONE_ERRROR(false, 20002, "手机号码不能为空"),
ACCOUNT_PHONE_ERRROR(false, 20002, "账号信息不能为空"),
LOGIN_PHONE_PATTARN_ERRROR(false, 20003, "手机号码格式不正确"),
VALIDATION_CODE_ERROR(false, 20004, "验证码不正确"),
LOGIN_CODE_ERROR(false, 20005, "短信验证码不能为空"),
LOGIN_CAPATA_ERROR(false, 20006, "图形验证码不能为空"),
LOGIN_CODE_FAIL_ERROR(false, 20007, "短信验证码失效,请重新发送"),
LOGIN_CODE_INPUT_ERROR(false, 20008, "输入的短信码有误"),
PHONE_ERROR_MSG(false, 20009, "该手机号未绑定账户"),
USER_FORBIDDEN(false, 20010, "该用户已被禁用,请联系平台客服"),
LOGIN_PWD_ERROR(false, 200011, "密码不允许为空"),
LOGIN_PWD_INPUT_ERROR(false, 200012, "密码输入有误"),
LOGIN_PWD_ACCOUNT_INPUT_ERROR(false, 200012, "输入的账号或者密码有误"),
LOGIN_PWD_NO_INPUT_ERROR(false, 200013, "检测到没有完善密码信息"),
BAD_SQL_GRAMMAR(false, 21001, "sql语法错误"),
JSON_PARSE_ERROR(false, 21002, "json解析异常"),
PARAM_ERROR(false, 21003, "参数不正确"),
USER_PWD_ERROR(false, 21003, "尚未找到对应的用户信息");
private Boolean success;
private Integer code;
private String message;
private ResultCodeEnum(Boolean success, Integer code, String message) {
this.success = success;
this.code = code;
this.message = message;
}
}