mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-04-21 19:45:09 +08:00
commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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:扫码支付
|
||||
* APP:APP支付
|
||||
* MICROPAY:付款码支付
|
||||
* MWEB:H5支付
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
// 通过token,code(前端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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
85
jsowell-pile/src/main/java/com/jsowell/wxpay/vo/R.java
Normal file
85
jsowell-pile/src/main/java/com/jsowell/wxpay/vo/R.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user