Compare commits
5 Commits
9354169741
...
7f91a73329
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f91a73329 | ||
|
|
a2757a2849 | ||
|
|
16ff649459 | ||
|
|
7d12de1fe6 | ||
|
|
4fadcb5b8e |
@ -63,6 +63,12 @@
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -75,6 +75,7 @@ public interface HDConstant {
|
||||
* 微信服务请求头中权限验证字段
|
||||
*/
|
||||
String WECHAT_SERVER_AUTHORIZATION_KEY = "WXUID";
|
||||
String WECHAT_SERVER_TOKEN_KEY = "WXTOKEN";
|
||||
|
||||
/**
|
||||
* 微信登录缓存数据前缀
|
||||
@ -82,6 +83,8 @@ public interface HDConstant {
|
||||
String openidPrefix = "hd:wechat:login:openid:";
|
||||
String unionidPrefix = "hd:wechat:login:unionid:";
|
||||
String sessionKeyPrefix = "hd:wechat:login:sessionKey:";
|
||||
String wxToken = "hd:wechat:login:token:";
|
||||
String tokenRandomStr = "hd:wechat:login:randomStr:";
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package com.evotech.hd.common.core.dao.wechat;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatPayPreOrder;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2025-01-13
|
||||
*/
|
||||
public interface WechatPayPreOrderDao extends BaseMapper<WechatPayPreOrder> {
|
||||
|
||||
}
|
||||
@ -37,6 +37,9 @@ public class BatteryStationDc implements Serializable {
|
||||
@NotBlank(message = "型号编码不能为空")
|
||||
private String typeCode;
|
||||
|
||||
@Schema(description = "电池型号名称")
|
||||
private String typeName;
|
||||
|
||||
@Schema(description = "电池编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "电池编码不能为空")
|
||||
private String batCode;
|
||||
|
||||
@ -60,6 +60,7 @@ public class OrderSwapBatteryPre implements Serializable {
|
||||
private String stationName;
|
||||
|
||||
@Schema(description = "预约时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date reservationTime;
|
||||
|
||||
|
||||
@ -34,6 +34,9 @@ public class OrderSwapBatteryStep implements Serializable {
|
||||
@Schema(description = "步骤:1-车辆进站,2-车辆到达指定位置,3-对中机构,4-取新电,5-拆旧电,6-装新电,7-放旧电,8-完成")
|
||||
private Integer step;
|
||||
|
||||
@Schema(description = "步骤名称")
|
||||
private String stepName;
|
||||
|
||||
@Schema(description = "步骤时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date stepTime;
|
||||
|
||||
@ -31,18 +31,30 @@ public class TradeDetail implements Serializable {
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "账号编码")
|
||||
private String accountCode;
|
||||
@Schema(description = "交易人")
|
||||
private String trader;
|
||||
|
||||
@Schema(description = "账号")
|
||||
private String accountName;
|
||||
|
||||
@Schema(description = "交易编码")
|
||||
private String outTradeNo;
|
||||
@Schema(description = "交易人编码")
|
||||
private String traderCode;
|
||||
|
||||
@Schema(description = "交易类型:1-充值,2-订单消费,3-提现")
|
||||
private Integer tradeType;
|
||||
|
||||
@Schema(description = "变动金额的钱包账户,钱包金额不变时不需要")
|
||||
private String wallet;
|
||||
|
||||
@Schema(description = "appid")
|
||||
private String appid;
|
||||
|
||||
@Schema(description = "银行类型")
|
||||
private String bankType;
|
||||
|
||||
@Schema(description = "收款商户号")
|
||||
private String mchid;
|
||||
|
||||
@Schema(description = "交易编码")
|
||||
private String outTradeNo;
|
||||
|
||||
@Schema(description = "支付方式:1-账户余额,2-微信,3-支付宝,4-网银,5 -充电补偿")
|
||||
private Integer payType;
|
||||
|
||||
@ -50,17 +62,11 @@ public class TradeDetail implements Serializable {
|
||||
private Integer orderCount;
|
||||
|
||||
@Schema(description = "订单编码")
|
||||
private String orderNums;
|
||||
private String orderNo;
|
||||
|
||||
@Schema(description = "交易金额")
|
||||
private Integer tradeAmount;
|
||||
|
||||
@Schema(description = "交易前账户余额")
|
||||
private Integer preAccountAmount;
|
||||
|
||||
@Schema(description = "交易后账户余额")
|
||||
private Integer afterAccountAmount;
|
||||
|
||||
@Schema(description = "优惠券编码")
|
||||
private String couponCode;
|
||||
|
||||
@ -70,13 +76,21 @@ public class TradeDetail implements Serializable {
|
||||
@Schema(description = "微信支付订单号")
|
||||
private String transactionId;
|
||||
|
||||
@Schema(description = "支付结果: 0-未支付, 1-已支付, 2-支付失败")
|
||||
private Integer payResult;
|
||||
@Schema(description = "支付结果,暂用微信结果的枚举类型")
|
||||
private String payResult;
|
||||
|
||||
@Schema(description = "在微信等支付网关创建支付订单时失败,返回的失败原因")
|
||||
private String payMsg;
|
||||
|
||||
@Schema(description = "删除标识,1-已删除,0-未删除")
|
||||
@Schema(description = "付款人编码,对于个人账户,交易发起人和付款人一般是同一人。公司账户交易发起人是公司,付款人可能是 微信账户")
|
||||
private String payer;
|
||||
|
||||
@Schema(description = "支付完成时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date payTime;
|
||||
|
||||
@Schema(description = "删除标识,1-已删除,0-未删除", hidden = true)
|
||||
private Integer delFlag;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
|
||||
@ -64,7 +64,7 @@ public class WalletAccount implements Serializable {
|
||||
private Integer rent;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private Boolean status;
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "引入站点", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "站点编码不能为空")
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.evotech.hd.cloud.entity.request;
|
||||
package com.evotech.hd.common.core.entity.cloud.request;
|
||||
|
||||
import com.evotech.hd.common.core.entity.BasePageRequest;
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package com.evotech.hd.common.core.entity.wechat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(name = "微信支付附加信息")
|
||||
/**
|
||||
* 附加信息中是交易发起人的信息
|
||||
* 支付回调中的openid 确认 付款人信息
|
||||
* 对于公司账户,这2部分信息可能不一样
|
||||
*/
|
||||
public class WechatPayAttach {
|
||||
|
||||
@Schema(description = "类型:1-充值,2-订单")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "订单号")
|
||||
private String orderNo;
|
||||
|
||||
@Schema(description = "交易发起人")
|
||||
private String trader;
|
||||
|
||||
@Schema(description = "交易人编码")
|
||||
private String traderCode;
|
||||
|
||||
@Schema(description = "钱包编码")
|
||||
private String walletCode;
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
package com.evotech.hd.common.core.entity.wechat;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_wechat_pay_pre_order")
|
||||
@Schema(name = "WechatPayPreOrder", description = "微信预支付订单")
|
||||
public class WechatPayPreOrder implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "用户编码")
|
||||
private String wuid;
|
||||
|
||||
private String openid;
|
||||
|
||||
@Schema(description = "订单总描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "小程序ID")
|
||||
private String appid;
|
||||
|
||||
@Schema(description = "商户号")
|
||||
private String mchid;
|
||||
|
||||
@Schema(description = "商户订单号")
|
||||
private String outTradeNo;
|
||||
|
||||
@Schema(description = "支付的最后时限")
|
||||
private Date timeExpire;
|
||||
|
||||
@Schema(description = "订单附加信息")
|
||||
private String attach;
|
||||
|
||||
@Schema(description = "商户回调地址")
|
||||
private String notifyUrl;
|
||||
|
||||
@Schema(description = "使用的优惠活动编码")
|
||||
private String goodsTag;
|
||||
|
||||
@Schema(description = "订单支付总金额")
|
||||
private Integer total;
|
||||
|
||||
@Schema(description = "商家小票ID")
|
||||
private String invoiceId;
|
||||
|
||||
@Schema(description = "商家小票金额")
|
||||
private Integer costPrice;
|
||||
|
||||
@Schema(description = "商品详情")
|
||||
private String goodsDetail;
|
||||
|
||||
@Schema(description = "门店号或收银设备ID")
|
||||
private String deviceId;
|
||||
|
||||
@Schema(description = "用户的客户端IP")
|
||||
private String payerClientIp;
|
||||
|
||||
@Schema(description = "商户门店信息")
|
||||
private String storeInfo;
|
||||
|
||||
@Schema(description = "支付串")
|
||||
private String prePayResponse;
|
||||
|
||||
@Schema(description = "创建人", hidden = true)
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -63,6 +63,12 @@ public class WechatUser implements Serializable {
|
||||
@Schema(description = "父账户名称")
|
||||
private String pname;
|
||||
|
||||
@Schema(description = "公众号原始ID")
|
||||
private String gzhId;
|
||||
|
||||
@Schema(description = "公众号openid")
|
||||
private String gzhOpenid;
|
||||
|
||||
@Schema(description = "创建人", hidden = true)
|
||||
private String creater;
|
||||
|
||||
|
||||
@ -76,9 +76,12 @@ public enum CodeMsg {
|
||||
REDIS_ERROR("D0410", "REDIS数据出错"),
|
||||
|
||||
// 小程序 w
|
||||
WECHAT_LOGIN_ERROR("W0400", "小程序登录出错"),
|
||||
WECHAT_SERRION_ERROR("W0401", "小程序登录态错误"),
|
||||
WECHAT_API_ERROR("W0402", "小程序接口调用异常");
|
||||
WECHAT_LOGIN_ERROR("W0400", "小程序登录异常"),
|
||||
WECHAT_SERRION_ERROR("W0401", "小程序登录态异常"),
|
||||
WECHAT_API_ERROR("W0402", "小程序接口调用异常"),
|
||||
WECHAT_NOT_LOGIN("W0403", "用户未登陆!"),
|
||||
WECHAT_TOKEN_INVALID("W0404", "无效token!"),
|
||||
WECHAT_TOKEN_EXPIRED("W0405", "token已过期!");
|
||||
|
||||
String code;
|
||||
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
package com.evotech.hd.common.core.enums;
|
||||
|
||||
public enum TradeResultEnums {
|
||||
|
||||
SUCCESS(1, "SUCCESS"),
|
||||
|
||||
REFUND(2, "REFUND"),
|
||||
|
||||
NOTPAY(3, "NOTPAY"),
|
||||
|
||||
CLOSED(4, "CLOSED"),
|
||||
|
||||
REVOKED(5, "REVOKED"),
|
||||
|
||||
USERPAYING(6, "USERPAYING"),
|
||||
|
||||
PAYERROR(7, "PAYERROR"),
|
||||
|
||||
ACCEPT(8, "ACCEPT");
|
||||
|
||||
|
||||
Integer code;
|
||||
|
||||
String name;
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
TradeResultEnums(Integer code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.evotech.hd.common.core.utils;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
|
||||
public class XCXUtil {
|
||||
|
||||
public static String wechatUid(String appid, String openid) {
|
||||
return MD5.create().digestHex(appid + openid + "HBYT");
|
||||
}
|
||||
|
||||
public static String wechatToken(String wuid, String randomStr) {
|
||||
return MD5.create().digestHex(wuid + randomStr + "HBYTXCX");
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信支付订单号:30位,预留2位不用
|
||||
* @param stationCode
|
||||
* @return
|
||||
*/
|
||||
public static String payOutTradeNo(String stationCode) {
|
||||
String prefix = "YTHD" + (StringUtils.hasText(stationCode)?stationCode.substring(stationCode.length() - 4):"1001");
|
||||
return prefix + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN)
|
||||
+ RandomUtil.randomInt(100, 1000) + RandomUtil.randomStringUpper(2);
|
||||
}
|
||||
|
||||
}
|
||||
@ -34,6 +34,12 @@
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- openfein -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-integration</artifactId>
|
||||
|
||||
@ -5,12 +5,14 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
|
||||
@EnableDiscoveryClient
|
||||
@ComponentScan("com.evotech.hd.**")
|
||||
@MapperScan({"com.evotech.hd.cloud.dao.**", "com.evotech.hd.common.core.dao.**"})
|
||||
@EnableFeignClients
|
||||
public class CloudManageServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@ -22,6 +22,7 @@ import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
@ -78,4 +79,20 @@ public class BatteryStationController {
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "获取小程序码")
|
||||
@GetMapping("/xcx/qrcode/get")
|
||||
@ApiOperationSupport(order = 6)
|
||||
public void getQRCode2(String path, @RequestParam(required = false) String width, @RequestParam(required = false)String env_version, HttpServletResponse response) {
|
||||
batteryStationService.getQRCode2(path, width, env_version, response);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "获取小程序二维码")
|
||||
@GetMapping("/xcx/qrcode/create")
|
||||
@ApiOperationSupport(order = 7)
|
||||
public void createQRCode2(String path, @RequestParam(required = false) String width, HttpServletResponse response) {
|
||||
batteryStationService.createQRCode2(path, width, response);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ import com.evotech.hd.common.core.entity.cloud.TradeDetail;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
@ -60,4 +61,13 @@ public class TradeController {
|
||||
return tradeService.list(pltr);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "微信支付回调业务处理")
|
||||
@PostMapping({"/wechatpay/notify"})
|
||||
@ApiOperationSupport(order = 5)
|
||||
@Hidden
|
||||
public Result<String> wechatPayNotifyHandle(@ParameterObject TradeDetail tradeDetail) {
|
||||
return tradeService.wechatPayNotifyHandle(tradeDetail);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.evotech.hd.cloud.entity.request.PageListWalletRequest;
|
||||
import com.evotech.hd.cloud.service.WalletAccountService;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccount;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail;
|
||||
import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ import com.evotech.hd.cloud.mqtt.enums.StateFunctionTypesEnum;
|
||||
import com.evotech.hd.cloud.mqtt.message.MqttMessageHeader;
|
||||
import com.evotech.hd.cloud.mqtt.message.dto.newer.req.order.OrderByPlateNumReq;
|
||||
import com.evotech.hd.cloud.mqtt.message.dto.newer.state.OrderStatus;
|
||||
import com.evotech.hd.cloud.mqtt.message.dto.newer.state.OrderStatusData;
|
||||
import com.evotech.hd.cloud.mqtt.message.dto.newer.state.SwapStep;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
@ -62,10 +63,9 @@ public class MqttMessageTestController {
|
||||
@Operation(summary = "反馈订单状态")
|
||||
@PostMapping("/orderStatus")
|
||||
@ApiOperationSupport(order = 2)
|
||||
public Result<String> orderStatus(@ParameterObject OrderStatus orderStatus, String stationCode) {
|
||||
|
||||
public Result<String> orderStatus(@ParameterObject OrderStatus orderStatus, @ParameterObject OrderStatusData statusData, String stationCode) {
|
||||
orderStatus.setStatusData(statusData);
|
||||
JSONObject jo = JSONUtil.parseObj(orderStatus);
|
||||
|
||||
String topic = mqttTestUtil.getTopic(stationCode, MqttMessageTypeEnum.STATE.getType());
|
||||
MqttMessageHeader header = mqttTestUtil.getHeader(StateFunctionTypesEnum.FUN_ORDERSTATUS.getFunction());
|
||||
|
||||
|
||||
@ -21,5 +21,6 @@ public class OrderStatus {
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date statusTime;
|
||||
|
||||
@Schema(hidden = true)
|
||||
private OrderStatusData statusData;
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.evotech.hd.cloud.mqtt.message.handle;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@ -13,7 +12,6 @@ import org.springframework.util.StringUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.evotech.hd.cloud.dao.BatteryStationDcDao;
|
||||
import com.evotech.hd.cloud.dao.BatteryStationHdFeeStandardDao;
|
||||
import com.evotech.hd.cloud.dao.OrderSwapBatteryDao;
|
||||
import com.evotech.hd.cloud.dao.OrderSwapBatteryPreDao;
|
||||
import com.evotech.hd.cloud.dao.VehicleWechatUserRelationDao;
|
||||
@ -30,9 +28,8 @@ import com.evotech.hd.cloud.mqtt.message.dto.newer.req.order.OrderByPlateNumResp
|
||||
import com.evotech.hd.cloud.mqtt.message.dto.newer.req.order.OrderData;
|
||||
import com.evotech.hd.cloud.service.OrderSwapBatteryService;
|
||||
import com.evotech.hd.cloud.utils.CommonUtil;
|
||||
import com.evotech.hd.cloud.utils.components.SwapOrderBasicFeeComponent;
|
||||
import com.evotech.hd.common.core.entity.cloud.BatteryStationDc;
|
||||
import com.evotech.hd.common.core.entity.cloud.BatteryStationHdFeeStandard;
|
||||
import com.evotech.hd.common.core.entity.cloud.BatteryStationHdFeeStandardDetail;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;
|
||||
import com.evotech.hd.common.core.entity.cloud.VehicleWechatUserRelation;
|
||||
@ -61,7 +58,7 @@ public class RequestMessageService {
|
||||
@Resource
|
||||
private OrderSwapBatteryService orderSwapBatteryService;
|
||||
@Resource
|
||||
private BatteryStationHdFeeStandardDao batteryStationHdFeeStandardDao;
|
||||
private SwapOrderBasicFeeComponent orderBasicFeeComponent;
|
||||
|
||||
@Async("taskExecutor")
|
||||
public void request(MessageTopic topic, MqttMessageHeader header, JSONObject dataBody) {
|
||||
@ -134,26 +131,7 @@ public class RequestMessageService {
|
||||
osb.setStationCode(osbp.getStationCode());
|
||||
osb.setStationName(osbp.getStationName());
|
||||
// 加上费用标准
|
||||
List<BatteryStationHdFeeStandard> list = batteryStationHdFeeStandardDao.listFeeStandard(osbp.getStationCode(), DateUtil.format(d, DatePattern.PURE_DATE_FORMATTER));
|
||||
if (!list.isEmpty()) {
|
||||
BatteryStationHdFeeStandard standard = list.get(0);
|
||||
List<BatteryStationHdFeeStandardDetail> detailList = standard.getDetailList();
|
||||
if (!detailList.isEmpty()) {
|
||||
detailList = detailList.stream().filter(i -> i.getTimeBegin().compareTo(LocalTime.now()) <= 0)
|
||||
.filter(i -> i.getTimeEnd().compareTo(LocalTime.now()) >= 0).toList();
|
||||
if (!detailList.isEmpty()) {
|
||||
BatteryStationHdFeeStandardDetail detail = detailList.get(0);
|
||||
osb.setBasicFee(detail.getEachKwhFee());
|
||||
osb.setServiceFee(detail.getTimeServiceFee());
|
||||
} else {
|
||||
osb.setBasicFee(standard.getEachKwhFee());
|
||||
osb.setServiceFee(standard.getCommonRemainFee());
|
||||
}
|
||||
} else {
|
||||
osb.setBasicFee(standard.getEachKwhFee());
|
||||
osb.setServiceFee(standard.getCommonRemainFee());
|
||||
}
|
||||
}
|
||||
osb = orderBasicFeeComponent.orderBasicFee(osb);
|
||||
|
||||
orderSwapBatteryService.add(osb);
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import com.evotech.hd.cloud.mqtt.message.dto.newer.state.OrderStatus;
|
||||
import com.evotech.hd.cloud.mqtt.message.dto.newer.state.OrderStatusData;
|
||||
import com.evotech.hd.cloud.mqtt.message.dto.newer.state.SwapStep;
|
||||
import com.evotech.hd.cloud.service.BatteryStationDcService;
|
||||
import com.evotech.hd.cloud.utils.components.HDStepDictComponent;
|
||||
import com.evotech.hd.common.core.entity.cloud.BatteryTrace;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;
|
||||
@ -43,6 +44,8 @@ public class StateMessageService {
|
||||
private OrderSwapBatteryStepDao orderSwapBatteryStepDao;
|
||||
@Resource
|
||||
private BatteryStationDcService batteryStationDcService;
|
||||
@Resource
|
||||
private HDStepDictComponent hdStepDictComponent;
|
||||
|
||||
@Async("taskExecutor")
|
||||
public void state(MessageTopic topic, MqttMessageHeader header, JSONObject dataBody) {
|
||||
@ -60,6 +63,7 @@ public class StateMessageService {
|
||||
BeanUtils.copyProperties(swapStep, step);
|
||||
step.setCtime(new Date());
|
||||
step.setCreater("SYS");
|
||||
step.setStepName(hdStepDictComponent.hdStepDictName(step.getStep()));
|
||||
orderSwapBatteryStepDao.insert(step);
|
||||
|
||||
break;
|
||||
@ -90,6 +94,7 @@ public class StateMessageService {
|
||||
step.setStepTime(orderStatus.getStatusTime());
|
||||
step.setCtime(new Date());
|
||||
step.setCreater("SYS");
|
||||
step.setStepName(hdStepDictComponent.hdStepDictName(step.getStep()));
|
||||
orderSwapBatteryStepDao.insert(step);
|
||||
// 添加2块电池的溯源记录
|
||||
addBatteryTrace(orderStatus, statusData, osb);
|
||||
@ -140,13 +145,14 @@ public class StateMessageService {
|
||||
// 修改订单状态
|
||||
OrderSwapBattery osb = alterOrderStatus(orderStatus, null);
|
||||
// 添加换电步骤1-车辆进站
|
||||
OrderSwapBatteryStep osbs = new OrderSwapBatteryStep();
|
||||
osbs.setOrderNo(orderStatus.getOrderNo());
|
||||
osbs.setStep(1);
|
||||
osbs.setStepTime(orderStatus.getStatusTime());
|
||||
osbs.setCtime(new Date());
|
||||
osbs.setCreater("SYS");
|
||||
orderSwapBatteryStepDao.insert(osbs);
|
||||
OrderSwapBatteryStep step = new OrderSwapBatteryStep();
|
||||
step.setOrderNo(orderStatus.getOrderNo());
|
||||
step.setStep(1);
|
||||
step.setStepTime(orderStatus.getStatusTime());
|
||||
step.setCtime(new Date());
|
||||
step.setCreater("SYS");
|
||||
step.setStepName(hdStepDictComponent.hdStepDictName(step.getStep()));
|
||||
orderSwapBatteryStepDao.insert(step);
|
||||
// 修改预约订单为完成
|
||||
OrderSwapBatteryPre osbp = new OrderSwapBatteryPre();
|
||||
osbp.setStatus(2);
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package com.evotech.hd.cloud.rpc;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.resource.dict.Dict;
|
||||
|
||||
@FeignClient(value = "resource-server")
|
||||
public interface ResourceService {
|
||||
|
||||
|
||||
@GetMapping(value = "/resource/dict/listdict",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<List<Dict>> listDict(@RequestParam String typeCode);
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.evotech.hd.cloud.rpc;
|
||||
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;
|
||||
|
||||
@FeignClient(value = "wechat-server")
|
||||
public interface WechatService {
|
||||
|
||||
@GetMapping(value = "/wechat/xcx/qrcode/get2",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public String getQRCode2(@RequestParam String path, @RequestParam String width, @RequestParam String env_version);
|
||||
|
||||
|
||||
@GetMapping(value = "/wechat/xcx/qrcode/create2",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public String createQRCode2(@RequestParam String path, @RequestParam String width);
|
||||
|
||||
@PostMapping(value = "/wechat/gzh/msg/send/preorder2",
|
||||
consumes = {MediaType.APPLICATION_JSON_VALUE})
|
||||
public Result<String> preOrderMessage(OrderSwapBatteryPre osbp);
|
||||
|
||||
@PostMapping(value = "/wechat/gzh/msg/send/order",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<String> orderMessage(@ParameterObject OrderSwapBattery osb, @RequestParam Integer templateType);
|
||||
|
||||
}
|
||||
@ -8,6 +8,8 @@ import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.BatteryStation;
|
||||
import com.evotech.hd.common.core.entity.cloud.vo.BatteryStationVO;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
public interface BatteryStationService {
|
||||
|
||||
public Result<Integer> add(BatteryStation bs);
|
||||
@ -22,4 +24,8 @@ public interface BatteryStationService {
|
||||
|
||||
public Result<Map<String, String>> RsaSecretKey(String stationCode);
|
||||
|
||||
public void getQRCode2(String path, String width, String env_version, HttpServletResponse response);
|
||||
|
||||
public void createQRCode2(String path, String width, HttpServletResponse response);
|
||||
|
||||
}
|
||||
|
||||
@ -16,4 +16,6 @@ public interface TradeService {
|
||||
|
||||
public Result<List<TradeDetail>> list(PageListTradeRequest pltr);
|
||||
|
||||
public Result<String> wechatPayNotifyHandle(TradeDetail tradeDetail);
|
||||
|
||||
}
|
||||
|
||||
@ -2,10 +2,10 @@ package com.evotech.hd.cloud.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.evotech.hd.cloud.entity.request.PageListWalletRequest;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccount;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail;
|
||||
import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest;
|
||||
|
||||
public interface WalletAccountService {
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
@ -29,6 +30,7 @@ public class BatteryStationDcServiceImpl implements BatteryStationDcService {
|
||||
private BatteryTraceDao batteryTraceDao;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<Integer> add(BatteryStationDc bsdc) {
|
||||
Date d = new Date();
|
||||
bsdc.setCtime(d);
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
package com.evotech.hd.cloud.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.security.KeyPair;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
@ -8,6 +11,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
@ -19,6 +23,7 @@ import com.evotech.hd.cloud.dao.BatteryStationSecretKeyDao;
|
||||
import com.evotech.hd.cloud.dao.VehicleInfoDao;
|
||||
import com.evotech.hd.cloud.entity.BatteryStationSecretKey;
|
||||
import com.evotech.hd.cloud.entity.request.PageListBatteryStationRequest;
|
||||
import com.evotech.hd.cloud.rpc.WechatService;
|
||||
import com.evotech.hd.cloud.service.BatteryStationService;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.BatteryStation;
|
||||
@ -26,9 +31,14 @@ import com.evotech.hd.common.core.entity.cloud.VehicleInfo;
|
||||
import com.evotech.hd.common.core.entity.cloud.vo.BatteryStationVO;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.crypto.KeyUtil;
|
||||
import cn.hutool.crypto.asymmetric.AsymmetricAlgorithm;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Service
|
||||
public class BatteryStationServiceImpl implements BatteryStationService {
|
||||
@ -39,6 +49,8 @@ public class BatteryStationServiceImpl implements BatteryStationService {
|
||||
private BatteryStationSecretKeyDao batteryStationSecretKeyDao;
|
||||
@Resource
|
||||
private VehicleInfoDao vehicleInfoDao;
|
||||
@Resource
|
||||
private WechatService wechatService;
|
||||
|
||||
@Override
|
||||
public Result<Integer> add(BatteryStation bs) {
|
||||
@ -142,6 +154,8 @@ public class BatteryStationServiceImpl implements BatteryStationService {
|
||||
res = res.stream().map(i -> {
|
||||
if (StringUtils.hasText(i.getCarTypeCode()) && i.getCarTypeCode().contains(vi.getTypeCode())) {
|
||||
i.setIsSuitable(true);
|
||||
} else {
|
||||
i.setIsSuitable(false);
|
||||
}
|
||||
return i;
|
||||
})
|
||||
@ -152,4 +166,54 @@ public class BatteryStationServiceImpl implements BatteryStationService {
|
||||
return new Result<List<BatteryStationVO>>().success(res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getQRCode2(String path, String width, String env_version, HttpServletResponse response) {
|
||||
String qrCode2Str = wechatService.getQRCode2(path, width, env_version);
|
||||
byte[] res = Base64.getDecoder().decode(qrCode2Str);
|
||||
String fileName = "小程序码" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + ".png";
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
try {
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
ServletOutputStream out = null;
|
||||
try {
|
||||
out = response.getOutputStream();
|
||||
out.write(res);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createQRCode2(String path, String width, HttpServletResponse response) {
|
||||
String qrCode2Str = wechatService.createQRCode2(path, width);
|
||||
byte[] res = Base64.getDecoder().decode(qrCode2Str);
|
||||
String fileName = "小程序二维码" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + ".png";
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
try {
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
ServletOutputStream out = null;
|
||||
try {
|
||||
out = response.getOutputStream();
|
||||
out.write(res);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,8 @@ import com.evotech.hd.cloud.dao.OrderSwapBatteryPreDao;
|
||||
import com.evotech.hd.cloud.dao.OrderSwapBatteryStepDao;
|
||||
import com.evotech.hd.cloud.dao.VehicleInfoDao;
|
||||
import com.evotech.hd.cloud.service.OrderSwapBatteryService;
|
||||
import com.evotech.hd.cloud.service.newthread.GZHTemplateMessageService;
|
||||
import com.evotech.hd.cloud.utils.components.SwapOrderBasicFeeComponent;
|
||||
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
@ -42,6 +44,10 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
|
||||
private VehicleInfoDao vehicleInfoDao;
|
||||
@Resource
|
||||
private WechatUserDao wechatUserDao;
|
||||
@Resource
|
||||
private SwapOrderBasicFeeComponent orderBasicFeeComponent;
|
||||
@Resource
|
||||
private GZHTemplateMessageService templateMessageService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -72,6 +78,9 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
|
||||
osbp.setCtime(d);
|
||||
int n = orderSwapBatteryPreDao.insert(osbp);
|
||||
if (n == 1) {
|
||||
// 发送服务号消息,没有消息队列,先用接口吧
|
||||
osbp.setCtime(null);
|
||||
templateMessageService.preOrderMessageSend(osbp);
|
||||
return new Result<Integer>().success(n);
|
||||
}
|
||||
return new Result<Integer>().error("添加预约换电订单出错!");
|
||||
@ -189,7 +198,10 @@ public class OrderSwapBatteryServiceImpl implements OrderSwapBatteryService {
|
||||
}
|
||||
// 2. 检查数据
|
||||
if (order.getBasicFee() == null || order.getServiceFee() == null) {
|
||||
return new Result<String>().error("订单费用标准异常!");
|
||||
order = orderBasicFeeComponent.orderBasicFee(order);
|
||||
if (order.getBasicFee() == null || order.getServiceFee() == null) {
|
||||
return new Result<String>().error("订单费用标准异常!");
|
||||
}
|
||||
}
|
||||
// 3. 选择费用计算方式 计算费用
|
||||
// 先按电量计算
|
||||
|
||||
@ -4,24 +4,34 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.evotech.hd.cloud.dao.OrderSwapBatteryDao;
|
||||
import com.evotech.hd.cloud.dao.TradeDetailDao;
|
||||
import com.evotech.hd.cloud.entity.request.PageListTradeRequest;
|
||||
import com.evotech.hd.cloud.service.TradeService;
|
||||
import com.evotech.hd.cloud.service.newthread.GZHTemplateMessageService;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
import com.evotech.hd.common.core.entity.cloud.TradeDetail;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
|
||||
import com.evotech.hd.common.core.enums.TradeResultEnums;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class TradeServiceImpl implements TradeService {
|
||||
|
||||
@Resource
|
||||
private TradeDetailDao tradeDetailDao;
|
||||
@Resource
|
||||
private OrderSwapBatteryDao orderSwapBatteryDao;
|
||||
@Resource
|
||||
private GZHTemplateMessageService templateMessageService;
|
||||
|
||||
@Override
|
||||
public Result<Integer> add(TradeDetail td) {
|
||||
@ -72,4 +82,45 @@ public class TradeServiceImpl implements TradeService {
|
||||
return new Result<List<TradeDetail>>().success(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<String> wechatPayNotifyHandle(TradeDetail tradeDetail) {
|
||||
// 1. 添加交易
|
||||
boolean b = tradeDetailDao.exists(new QueryWrapper<TradeDetail>()
|
||||
.eq("out_trade_no", tradeDetail.getOutTradeNo())
|
||||
.eq("transaction_id", tradeDetail.getTransactionId())
|
||||
.eq("pay_result", tradeDetail.getPayResult()));
|
||||
if (b) {
|
||||
log.info("\r\n===>>>已处理过此回调:" + tradeDetail);
|
||||
return new Result<String>().error("重复消息!");
|
||||
}
|
||||
add(tradeDetail);
|
||||
// 2. 业务类型
|
||||
if (tradeDetail.getTradeType() == 1) {
|
||||
// 充值
|
||||
|
||||
} else if (tradeDetail.getTradeType() == 2) {
|
||||
// 支付订单
|
||||
OrderSwapBattery one = orderSwapBatteryDao.selectOne(new QueryWrapper<OrderSwapBattery>().eq("order_no", tradeDetail.getOrderNo()));
|
||||
if (one.getStatus() == 6) {
|
||||
if (TradeResultEnums.SUCCESS.getName().equals(tradeDetail.getPayResult())) {
|
||||
// 支付成功,修改订单
|
||||
OrderSwapBattery osb = new OrderSwapBattery();
|
||||
osb.setStatus(7);
|
||||
osb.setTradeNo(tradeDetail.getOutTradeNo());
|
||||
orderSwapBatteryDao.update(osb, new QueryWrapper<OrderSwapBattery>().eq("order_no", tradeDetail.getOrderNo()));
|
||||
// 发送公众号消息
|
||||
templateMessageService.orderMessageSend(one, 3);
|
||||
}
|
||||
} else {
|
||||
log.info("\r\n===>>>支付订单存在问题:" + tradeDetail);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
return new Result<String>().success("OK");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,11 +12,11 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.evotech.hd.cloud.dao.WalletAccountDao;
|
||||
import com.evotech.hd.cloud.dao.WalletAccountDetailDao;
|
||||
import com.evotech.hd.cloud.entity.request.PageListWalletRequest;
|
||||
import com.evotech.hd.cloud.service.WalletAccountService;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccount;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail;
|
||||
import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
import com.evotech.hd.common.core.utils.SnowflakeUtil;
|
||||
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package com.evotech.hd.cloud.service.newthread;
|
||||
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.evotech.hd.cloud.rpc.WechatService;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Service
|
||||
public class GZHTemplateMessageService {
|
||||
|
||||
@Resource
|
||||
private WechatService wechatService;
|
||||
|
||||
@Async("taskExecutor")
|
||||
public void preOrderMessageSend(OrderSwapBatteryPre osbp) {
|
||||
wechatService.preOrderMessage(osbp);
|
||||
}
|
||||
|
||||
|
||||
@Async("taskExecutor")
|
||||
public void orderMessageSend(OrderSwapBattery osb, Integer type) {
|
||||
wechatService.orderMessage(osb, type);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.evotech.hd.cloud.utils.components;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.evotech.hd.cloud.rpc.ResourceService;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.resource.dict.Dict;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
import com.evotech.hd.common.redis.utils.RedisUtil;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Component
|
||||
public class HDStepDictComponent {
|
||||
|
||||
private static String stepPrefix = "hd:resource:dict:hdstep:step-";
|
||||
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
@Resource
|
||||
private ResourceService resourceService;
|
||||
|
||||
public String hdStepDictName(Integer step) {
|
||||
if (!redisUtil.hasKey(stepPrefix + step)) {
|
||||
Result<List<Dict>> res = resourceService.listDict("hdstate");
|
||||
if (CodeMsg.SUCCESS.getCode().equals(res.getCode())) {
|
||||
List<Dict> list = JSONUtil.toList(JSONUtil.parseArray(res.getData()), Dict.class);
|
||||
list.stream().forEach(i -> redisUtil.set(stepPrefix + i.getDictValue(), i.getDictName()));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return redisUtil.get(stepPrefix + step).toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.evotech.hd.cloud.utils.components;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.evotech.hd.cloud.dao.BatteryStationHdFeeStandardDao;
|
||||
import com.evotech.hd.common.core.entity.cloud.BatteryStationHdFeeStandard;
|
||||
import com.evotech.hd.common.core.entity.cloud.BatteryStationHdFeeStandardDetail;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Component
|
||||
public class SwapOrderBasicFeeComponent {
|
||||
|
||||
@Resource
|
||||
private BatteryStationHdFeeStandardDao batteryStationHdFeeStandardDao;
|
||||
|
||||
|
||||
public OrderSwapBattery orderBasicFee(OrderSwapBattery osb) {
|
||||
List<BatteryStationHdFeeStandard> list = batteryStationHdFeeStandardDao.listFeeStandard(osb.getStationCode(), DateUtil.format(osb.getOrderTime(), DatePattern.PURE_DATE_FORMATTER));
|
||||
if (!list.isEmpty()) {
|
||||
BatteryStationHdFeeStandard standard = list.get(0);
|
||||
List<BatteryStationHdFeeStandardDetail> detailList = standard.getDetailList();
|
||||
if (!detailList.isEmpty()) {
|
||||
detailList = detailList.stream().filter(i -> i.getTimeBegin().compareTo(LocalTime.now()) <= 0)
|
||||
.filter(i -> i.getTimeEnd().compareTo(LocalTime.now()) >= 0).toList();
|
||||
if (!detailList.isEmpty()) {
|
||||
BatteryStationHdFeeStandardDetail detail = detailList.get(0);
|
||||
osb.setBasicFee(detail.getEachKwhFee());
|
||||
osb.setServiceFee(detail.getTimeServiceFee());
|
||||
} else {
|
||||
osb.setBasicFee(standard.getEachKwhFee());
|
||||
osb.setServiceFee(standard.getCommonRemainFee());
|
||||
}
|
||||
} else {
|
||||
osb.setBasicFee(standard.getEachKwhFee());
|
||||
osb.setServiceFee(standard.getCommonRemainFee());
|
||||
}
|
||||
}
|
||||
|
||||
return osb;
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,6 +13,11 @@ spring:
|
||||
# 服务名称必须带上,不然nacos服务列表中没有,也不会有注册成功的信息
|
||||
application:
|
||||
name: cloud-server
|
||||
jackson:
|
||||
timeZone: GMT+08:00
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
serialization:
|
||||
write-dates-as-timestamps: false
|
||||
config:
|
||||
import:
|
||||
- nacos:${spring.application.name}.yaml?refreshEnabled=true
|
||||
|
||||
@ -3,11 +3,24 @@ package com.evotech.hd.cloud;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import com.evotech.hd.cloud.rpc.ResourceService;
|
||||
import com.evotech.hd.cloud.utils.components.HDStepDictComponent;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@SpringBootTest
|
||||
class CloudManageServerApplicationTests {
|
||||
|
||||
@Resource
|
||||
private HDStepDictComponent hdStepDictComponent;
|
||||
@Resource
|
||||
private ResourceService resourceService;
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
for (int i = 1; i < 9; i++) {
|
||||
System.out.println(hdStepDictComponent.hdStepDictName(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -108,6 +108,13 @@
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- openfein -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -3,12 +3,13 @@ package com.evotech.hd.gateway;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@ComponentScan("com.evotech.hd.**")
|
||||
//@EnableFeignClients
|
||||
@EnableFeignClients
|
||||
public class GatewayServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
package com.evotech.hd.gateway.config;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
|
||||
|
||||
|
||||
@Configuration
|
||||
public class FeignConfig {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Spring Cloud Gateway是基于WebFlux的,是ReactiveWeb,所以HttpMessageConverters不会自动注入。
|
||||
* @param converters
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
|
||||
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
}
|
||||
@ -120,8 +120,8 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
|
||||
* %(?![0-9a-fA-F]{2})意思是'%'开始, 不匹配%后面两位为数字或字母(包括大小写)的字符;
|
||||
* 这样就把正确的排除掉了,剩下的就是需要匹配替换的。
|
||||
*/
|
||||
body = body.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
|
||||
body = body.replaceAll("\\+", "%2B");
|
||||
// body = body.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
|
||||
// body = body.replaceAll("\\+", "%2B");
|
||||
// body = URLEncoder.encode(body, "UTF-8");
|
||||
return Mono.just(body);
|
||||
});
|
||||
@ -145,7 +145,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
|
||||
.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build())
|
||||
.then(Mono.fromRunnable(() -> {
|
||||
// 打印日志
|
||||
if (!gatewayLog.getRequestPath().contains("/v2/api-docs") && !gatewayLog.getRequestPath().contains("/dict/")) {
|
||||
if (!gatewayLog.getRequestPath().contains("/v3/api-docs") && !gatewayLog.getRequestPath().contains("/dict/")) {
|
||||
logService.writeGatewayLog(gatewayLog);
|
||||
}
|
||||
}));
|
||||
@ -164,7 +164,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
|
||||
return chain.filter(exchange.mutate().response(decoratedResponse).build())
|
||||
.then(Mono.fromRunnable(() -> {
|
||||
// 打印日志
|
||||
if (!accessLog.getRequestPath().contains("/v2/api-docs") && !accessLog.getRequestPath().contains("/dict/")) {
|
||||
if (!accessLog.getRequestPath().contains("/v3/api-docs") && !accessLog.getRequestPath().contains("/dict/")) {
|
||||
logService.writeGatewayLog(accessLog);
|
||||
}
|
||||
}));
|
||||
|
||||
@ -2,6 +2,8 @@ package com.evotech.hd.gateway.oauth2;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@ -15,13 +17,17 @@ import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.web.server.authorization.AuthorizationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.evotech.hd.common.core.constant.HDConstant;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
import com.evotech.hd.common.core.utils.XCXUtil;
|
||||
import com.evotech.hd.common.redis.utils.RedisUtil;
|
||||
import com.evotech.hd.gateway.oauth2.service.WechatService;
|
||||
import com.evotech.hd.gateway.utils.TokenUtil;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@ -36,6 +42,8 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
|
||||
private RedisUtil redisUtil;
|
||||
@Resource
|
||||
private RSAKeyPair rsaKeyPair;
|
||||
@Resource
|
||||
private WechatService wechatService;
|
||||
|
||||
@Value("${yt.gateway.is_pass:false}")
|
||||
private boolean isPass;
|
||||
@ -48,21 +56,19 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
|
||||
}
|
||||
ServerHttpRequest request = authorizationContext.getExchange().getRequest();
|
||||
String uri = request.getURI().toString();
|
||||
System.out.println("&&&&&&>" + uri);
|
||||
|
||||
// 1. 对应跨域的预检请求直接放行
|
||||
if (request.getMethod() == HttpMethod.OPTIONS) {
|
||||
return Mono.just(new AuthorizationDecision(true));
|
||||
}
|
||||
// 微信服务将UID放入请求头,验证一下
|
||||
// 2. 微信服务token验证
|
||||
if (uri.contains("/gateway/wechat/")) {
|
||||
String wuid = request.getHeaders().getFirst(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY);
|
||||
if (redisUtil.hasKey(HDConstant.sessionKeyPrefix + wuid) ) {
|
||||
return Mono.just(new AuthorizationDecision(true));
|
||||
} else {
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.TOKEN_INVALID.getCode(), CodeMsg.TOKEN_INVALID.getMsg(), uri));
|
||||
}
|
||||
// 提到另一个类了,应该走不到这了
|
||||
return wechatTokenCheck(request, uri);
|
||||
|
||||
}
|
||||
// 2. token验证
|
||||
// 3. 其他服务token验证
|
||||
/**
|
||||
* 这个类主要是处理权限(Authorization)的,对于身份(authentication)
|
||||
* 验证是在 @org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager
|
||||
@ -82,6 +88,56 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
|
||||
.defaultIfEmpty(new AuthorizationDecision(false));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 微信token权限验证逻辑
|
||||
* @param request
|
||||
* @param uri
|
||||
* @return
|
||||
*/
|
||||
private Mono<AuthorizationDecision> wechatTokenCheck(ServerHttpRequest request, String uri) {
|
||||
String wuid = request.getHeaders().getFirst(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY);
|
||||
String wxToken = request.getHeaders().getFirst(HDConstant.WECHAT_SERVER_TOKEN_KEY);
|
||||
if (!StringUtils.hasText(wxToken) || !StringUtils.hasText(wuid)) {
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_NOT_LOGIN.getCode(), CodeMsg.WECHAT_NOT_LOGIN.getMsg(), ""));
|
||||
}
|
||||
// 验证wuid
|
||||
if (!redisUtil.hasKey(HDConstant.openidPrefix + wuid)) {
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_LOGIN_ERROR.getCode(), CodeMsg.WECHAT_LOGIN_ERROR.getMsg(), uri));
|
||||
}
|
||||
// 验证token正确
|
||||
if (!redisUtil.hasKey(HDConstant.wxToken + wuid)) {
|
||||
// 缓存没了,过期了
|
||||
if (!wxToken.equals(XCXUtil.wechatToken(wuid, redisUtil.get(HDConstant.tokenRandomStr + wuid).toString()))) {
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_TOKEN_INVALID.getCode(), CodeMsg.WECHAT_TOKEN_INVALID.getMsg(), "token异常"));
|
||||
}
|
||||
CompletableFuture<Map<String, String>> asyncRes = CompletableFuture.supplyAsync(() -> {
|
||||
return wechatService.tokenBuilder(wuid);
|
||||
});
|
||||
Map<String, String> m = null;
|
||||
try {
|
||||
m = asyncRes.get();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_LOGIN_ERROR.getCode(), CodeMsg.WECHAT_LOGIN_ERROR.getMsg(), "token异常"));
|
||||
}
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_TOKEN_EXPIRED.getCode(), CodeMsg.WECHAT_TOKEN_EXPIRED.getMsg(), JSONUtil.toJsonStr(m)));
|
||||
|
||||
} else {
|
||||
// 缓存还有
|
||||
if (wxToken.equals(redisUtil.get(HDConstant.wxToken + wuid).toString())) {
|
||||
return Mono.just(new AuthorizationDecision(true));
|
||||
} else {
|
||||
// token对不上
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_TOKEN_INVALID.getCode(), CodeMsg.WECHAT_TOKEN_INVALID.getMsg(), "token异常"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 校验权限和client状态
|
||||
* @param token
|
||||
|
||||
@ -20,7 +20,9 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
|
||||
/**
|
||||
* 自定义没有权限访问时的异常,没用到,因为自定义的权限校验
|
||||
* 自定义 oauth2默认权限校验 异常时的处理,
|
||||
* 没用到,因为没用默认权限校验,我们使用的自定义的权限校验
|
||||
* 自定义的权限校验 中的 异常用exception包中的全局异常处理的
|
||||
* 参考{@link org.springframework.security.oauth2.server.resource.web.access.server.BearerTokenServerAccessDeniedHandler}
|
||||
* @author zrb
|
||||
* @date 2024年9月4日10:17:27
|
||||
@ -36,7 +38,7 @@ public class MyAccessDeniedHandler implements ServerAccessDeniedHandler {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
response.setStatusCode(HttpStatus.OK);
|
||||
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
// 为了解决token过期时,前端不出现跨域错误,添加了一些header,注意Access-Control-Allow-Origin的值
|
||||
// 为了解决token过期时,前端不出现跨域错误,添加了一些header,注意Access-Control-Allow-Origin的值
|
||||
response.getHeaders().add("Access-Control-Allow-Origin", "*");
|
||||
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
|
||||
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.evotech.hd.gateway.oauth2;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@ -25,8 +24,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 这个主要处理身份认证(authentication)的异常,权限验证时的异常这里是不处理的
|
||||
* 自定义Token异常,主要处理token验证过程中的异常,因token验证是oauth2的,所以要改它的异常处理响应
|
||||
* 这个主要处理身份认证(authentication)的异常
|
||||
* 权限验证时的异常不经过这个类处理
|
||||
* 参考{@link org.springframework.security.oauth2.server.resource.web.server.BearerTokenServerAuthenticationEntryPoint}
|
||||
* 重写了返回结果中的response内容:
|
||||
* 1. response的HttpStatus改成ok
|
||||
@ -39,12 +39,15 @@ public class MyAuthenticationEntryPoint implements ServerAuthenticationEntryPoin
|
||||
|
||||
@Override
|
||||
public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {
|
||||
// System.out.println("0999990000");
|
||||
e.printStackTrace();
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
Throwable cause = e.getCause();
|
||||
Result<String> res = new Result<String>().exception(e.getMessage());
|
||||
// System.out.println("00");
|
||||
try {
|
||||
if (cause instanceof JwtValidationException) {
|
||||
// System.out.println("11");
|
||||
if (cause.getMessage().contains("Jwt expired at")) {
|
||||
String token = exchange.getRequest().getHeaders().getFirst("Authorization").substring(7);
|
||||
String dateTime = DateUtil.formatDateTime(TokenUtil.getExp(token));
|
||||
@ -53,9 +56,10 @@ public class MyAuthenticationEntryPoint implements ServerAuthenticationEntryPoin
|
||||
res = new Result<String>().error(CodeMsg.TOKEN_INVALID.getCode(), CodeMsg.TOKEN_INVALID.getMsg(), cause.getMessage());
|
||||
}
|
||||
} else if (cause instanceof BadJwtException || cause instanceof JwtEncodingException) {
|
||||
// System.out.println("22");
|
||||
res = new Result<String>().error(CodeMsg.TOKEN_INVALID.getCode(), CodeMsg.TOKEN_INVALID.getMsg(), cause.getMessage());
|
||||
} else if (cause instanceof InvalidBearerTokenException) {
|
||||
System.out.println("8888888");
|
||||
// System.out.println("33");
|
||||
String token = exchange.getRequest().getHeaders().getFirst("Authorization").substring(7);
|
||||
String dateTime = DateUtil.formatDateTime(TokenUtil.getExp(token));
|
||||
res = new Result<String>().bussinessException(CodeMsg.TOKEN_EXPIRED.getCode(), CodeMsg.TOKEN_EXPIRED.getMsg(), "Jwt expired at " + dateTime);
|
||||
@ -63,19 +67,22 @@ public class MyAuthenticationEntryPoint implements ServerAuthenticationEntryPoin
|
||||
res = new Result<String>().error(CodeMsg.AUTHENTICATION_FAILED.getCode(), CodeMsg.AUTHENTICATION_FAILED.getMsg(), e.getMessage());
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
// System.out.println("99");
|
||||
log.info(e1.toString());
|
||||
res = new Result<String>().error(CodeMsg.AUTHENTICATION_FAILED.getCode(), CodeMsg.AUTHENTICATION_FAILED.getMsg(), e.getMessage());
|
||||
}
|
||||
// System.out.println("100");
|
||||
response.setStatusCode(HttpStatus.OK);
|
||||
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
URI uri = exchange.getRequest().getURI();
|
||||
// 为了解决token过期时,前端不出现跨域错误,添加了一些header,注意Access-Control-Allow-Origin的值
|
||||
response.getHeaders().add("Access-Control-Allow-Origin", uri.getScheme() + "://" + uri.getHost());
|
||||
// URI uri = exchange.getRequest().getURI();
|
||||
// 为了解决token过期时,前端不出现跨域错误,添加了一些header,注意Access-Control-Allow-Origin的值: uri.getScheme() + "://" + uri.getHost()
|
||||
response.getHeaders().add("Access-Control-Allow-Origin", "*");
|
||||
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
|
||||
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
|
||||
response.getHeaders().add("Access-Control-Allow-Headers", HttpHeaders.AUTHORIZATION);
|
||||
String body = JSONUtil.toJsonStr(res);
|
||||
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
|
||||
// System.out.println("200");
|
||||
return response.writeWith(Mono.just(buffer));
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,8 @@ public class ResourceServerConfig {
|
||||
@Resource
|
||||
private AuthorizationManager authorizationManager;
|
||||
@Resource
|
||||
private WechatAuthorizationManager wxAuthorizationManager;
|
||||
@Resource
|
||||
private RSAKeyPair rsaKeyPair;
|
||||
|
||||
|
||||
@ -44,9 +46,9 @@ public class ResourceServerConfig {
|
||||
http.httpBasic(httpBasicSpec -> httpBasicSpec.disable());
|
||||
// 资源服务器配置
|
||||
http.oauth2ResourceServer(server -> server
|
||||
// 权限不通过时,自定义返回
|
||||
// 默认的权限校验方法 不通过时,自定义返回,这个用不到,因为没有走默认权限校验
|
||||
.accessDeniedHandler(new MyAccessDeniedHandler())
|
||||
// 未登录或者登陆验证失败时(token有问题),自定义返回
|
||||
// 凭据验证失败时(token有问题),自定义返回
|
||||
.authenticationEntryPoint(new MyAuthenticationEntryPoint())
|
||||
// 使用jwt默认配置
|
||||
// .jwt(Customizer.withDefaults())
|
||||
@ -66,6 +68,7 @@ public class ResourceServerConfig {
|
||||
exchange
|
||||
.pathMatchers(Convert.toStrArray(ignoreUri.getIgnoreUris())).permitAll()
|
||||
.pathMatchers(ignoreFixedUris()).permitAll()
|
||||
.pathMatchers("/gateway/wechat/**").access(wxAuthorizationManager)
|
||||
// .anyExchange().authenticated()
|
||||
// 其他走自定义逻辑
|
||||
.anyExchange().access(authorizationManager)
|
||||
|
||||
@ -0,0 +1,119 @@
|
||||
package com.evotech.hd.gateway.oauth2;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.web.server.authorization.AuthorizationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.evotech.hd.common.core.constant.HDConstant;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
import com.evotech.hd.common.core.utils.XCXUtil;
|
||||
import com.evotech.hd.common.redis.utils.RedisUtil;
|
||||
import com.evotech.hd.gateway.oauth2.service.WechatService;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 微信服务token校验
|
||||
* 鉴权时统一抛出OAuth2AuthorizationException
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class WechatAuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
|
||||
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
@Resource
|
||||
private WechatService wechatService;
|
||||
|
||||
@Value("${yt.gateway.is_pass:false}")
|
||||
private boolean isPass;
|
||||
|
||||
|
||||
@Override
|
||||
public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
|
||||
log.info("\r\n===>>>进微信权限检查的了.........");
|
||||
|
||||
if (isPass) {
|
||||
return Mono.just(new AuthorizationDecision(true));
|
||||
}
|
||||
ServerHttpRequest request = authorizationContext.getExchange().getRequest();
|
||||
String uri = request.getURI().toString();
|
||||
log.info("\r\n*****>" + uri);
|
||||
// 1. 对应跨域的预检请求直接放行
|
||||
if (request.getMethod() == HttpMethod.OPTIONS) {
|
||||
return Mono.just(new AuthorizationDecision(true));
|
||||
}
|
||||
|
||||
return wechatTokenCheck(request, uri);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 微信token权限验证逻辑
|
||||
* @param request
|
||||
* @param uri
|
||||
* @return
|
||||
*/
|
||||
private Mono<AuthorizationDecision> wechatTokenCheck(ServerHttpRequest request, String uri) {
|
||||
String wuid = request.getHeaders().getFirst(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY);
|
||||
String wxToken = request.getHeaders().getFirst(HDConstant.WECHAT_SERVER_TOKEN_KEY);
|
||||
log.info("\r\n---wuid---" + wuid);
|
||||
log.info("\r\n---token---" + wxToken);
|
||||
if (!StringUtils.hasText(wxToken) || !StringUtils.hasText(wuid)) {
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_NOT_LOGIN.getCode(), CodeMsg.WECHAT_NOT_LOGIN.getMsg(), ""));
|
||||
}
|
||||
// 验证wuid
|
||||
if (!redisUtil.hasKey(HDConstant.openidPrefix + wuid)) {
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_LOGIN_ERROR.getCode(), CodeMsg.WECHAT_LOGIN_ERROR.getMsg(), uri));
|
||||
}
|
||||
// 验证token正确
|
||||
if (!redisUtil.hasKey(HDConstant.wxToken + wuid)) {
|
||||
log.info("\r\n===>>>" + redisUtil.get(HDConstant.tokenRandomStr + wuid).toString());
|
||||
// 缓存没了,过期了
|
||||
if (!wxToken.equals(XCXUtil.wechatToken(wuid, redisUtil.get(HDConstant.tokenRandomStr + wuid).toString()))) {
|
||||
log.error("\r\n------555------");
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_TOKEN_INVALID.getCode(), CodeMsg.WECHAT_TOKEN_INVALID.getMsg(), "token异常"));
|
||||
}
|
||||
log.error("\r\n------666------");
|
||||
CompletableFuture<Map<String, String>> asyncRes = CompletableFuture.supplyAsync(() -> {
|
||||
return wechatService.tokenBuilder(wuid);
|
||||
});
|
||||
Map<String, String> m = null;
|
||||
try {
|
||||
m = asyncRes.get();
|
||||
log.error("\r\n---777---" + m);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_LOGIN_ERROR.getCode(), CodeMsg.WECHAT_LOGIN_ERROR.getMsg(), "token异常"));
|
||||
}
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_TOKEN_EXPIRED.getCode(), CodeMsg.WECHAT_TOKEN_EXPIRED.getMsg(), JSONUtil.toJsonStr(m)));
|
||||
|
||||
} else {
|
||||
// 缓存还有
|
||||
if (wxToken.equals(redisUtil.get(HDConstant.wxToken + wuid).toString())) {
|
||||
return Mono.just(new AuthorizationDecision(true));
|
||||
} else {
|
||||
// token对不上
|
||||
log.error("\r\n-----88888----" + wxToken);
|
||||
log.error("\r\n-----" + redisUtil.get(HDConstant.wxToken + wuid).toString());
|
||||
throw new OAuth2AuthorizationException(new OAuth2Error(CodeMsg.WECHAT_TOKEN_INVALID.getCode(), CodeMsg.WECHAT_TOKEN_INVALID.getMsg(), "token异常"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -24,6 +24,7 @@ import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
* 根据{@link}ErrorWebFluxAutoConfiguration的配置 重写
|
||||
* 主要是重写errorWebExceptionHandler()的逻辑
|
||||
* 里面不要DefaultErrorWebExceptionHandler了,用自己写的异常处理类替换
|
||||
* 这个全局异常 主要用来捕获 自定义权限验证{@link AuthorizationManager}类中抛出的异常
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
//@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
|
||||
@ -22,6 +22,7 @@ import reactor.core.publisher.Mono;
|
||||
/**
|
||||
* 异常处理操作,自定义异常中的内容
|
||||
* 重写了{@link}DefaultErrorWebExceptionHandler部分内容
|
||||
* 这个全局异常 主要用来捕获 自定义权限验证{@link AuthorizationManager}类中抛出的异常
|
||||
*/
|
||||
public class GlobalExceptionHandler extends DefaultErrorWebExceptionHandler {
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
|
||||
/**
|
||||
* 统一异常
|
||||
@ -31,7 +33,7 @@ public class GlobalExceptionType {
|
||||
public Result<String> oAuth2AuthorizationHandle(OAuth2AuthorizationException e) {
|
||||
e.printStackTrace();
|
||||
OAuth2Error error = e.getError();
|
||||
return new Result<String>().bussinessException(error.getErrorCode(), error.getDescription(), error.getUri());
|
||||
return new Result<String>().bussinessException(error.getErrorCode(), error.getDescription(), JSONUtil.isTypeJSON(error.getUri())?JSONUtil.parseObj(error.getUri()):error.getUri());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
package com.evotech.hd.gateway.oauth2.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@FeignClient(value = "wechat-server")
|
||||
public interface WechatService {
|
||||
|
||||
@PostMapping(value = "/wechat/login/tokenbuild",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Map<String, String> tokenBuilder(@RequestParam String wuid);
|
||||
|
||||
}
|
||||
@ -1,13 +1,26 @@
|
||||
package com.evotech.hd.gateway;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import com.evotech.hd.gateway.oauth2.service.WechatService;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@SpringBootTest
|
||||
class GatewayServerApplicationTests {
|
||||
|
||||
@Resource
|
||||
private WechatService wechatService;
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
Map<String, String> m = wechatService.tokenBuilder("123");
|
||||
System.out.println("0000000000");
|
||||
System.out.println(m);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -58,6 +58,11 @@
|
||||
<artifactId>hutool-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
|
||||
@ -3,25 +3,34 @@ package com.evotech.hd.resource.controller;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.utils.SnowflakeUtil;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@Tag(name = "ID生成, 测试用")
|
||||
@Tag(name = "工具类")
|
||||
@ApiSupport(order = 199)
|
||||
@RestController
|
||||
@RequestMapping("/id")
|
||||
public class IDController {
|
||||
@RequestMapping("/util")
|
||||
public class UtilController {
|
||||
|
||||
|
||||
@Operation(description = "获取")
|
||||
@GetMapping("/list")
|
||||
@Value("${yt.util.ip-url1}")
|
||||
private String ipUrl;
|
||||
|
||||
|
||||
@Operation(description = "获取id")
|
||||
@GetMapping("/id/list")
|
||||
@ApiOperationSupport(order = 1)
|
||||
public Result<List<String>> getIds(Integer num) {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (int i = 0; i < (num==null?1:num); i++) {
|
||||
@ -30,4 +39,13 @@ public class IDController {
|
||||
return new Result<List<String>>().success(list);
|
||||
}
|
||||
|
||||
|
||||
@Operation(description = "获取ip")
|
||||
@GetMapping("/ip")
|
||||
@ApiOperationSupport(order = 2)
|
||||
public Result<String> getIp() {
|
||||
String res = HttpUtil.get(ipUrl);
|
||||
return new Result<String>().success("OK", res.trim());
|
||||
}
|
||||
|
||||
}
|
||||
@ -56,7 +56,7 @@ public class WechatAgreementController {
|
||||
@Operation(summary = "查询")
|
||||
@GetMapping("/list")
|
||||
@ApiOperationSupport(order = 4)
|
||||
public Result<List<WechatAgreement>> list(@RequestParam String appid, @RequestParam Integer type, @RequestParam Integer status) {
|
||||
public Result<List<WechatAgreement>> list(@RequestParam(required = false) String appid, @RequestParam(required = false) Integer type, @RequestParam(required = false) Integer status) {
|
||||
return wechatAgreementService.list(appid, type, status);
|
||||
}
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ public class WechatSwiperController {
|
||||
@Operation(summary = "查询")
|
||||
@GetMapping("/list")
|
||||
@ApiOperationSupport(order = 4)
|
||||
public Result<List<WechatSwiper>> list(@RequestParam String appid, @RequestParam Integer type, @RequestParam Integer status) {
|
||||
public Result<List<WechatSwiper>> list(@RequestParam(required = false) String appid, @RequestParam(required = false) Integer type, @RequestParam(required = false) Integer status) {
|
||||
return wechatSwiperService.list(appid, type, status);
|
||||
}
|
||||
|
||||
|
||||
@ -78,6 +78,7 @@ public class DictServiceImpl implements DictService {
|
||||
|
||||
@Override
|
||||
public Result<Integer> addDict(Dict d) {
|
||||
d.setCtime(new Date());
|
||||
int n = dictDao.insert(d);
|
||||
return new Result<Integer>().success(n);
|
||||
}
|
||||
|
||||
@ -71,10 +71,6 @@
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-json</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package com.evotech.hd.wechat.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "hbyt.gzh", ignoreUnknownFields = true)
|
||||
@Data
|
||||
@Schema(description = "公众号信息")
|
||||
public class GZHProperties {
|
||||
|
||||
private String appid;
|
||||
|
||||
private String appSecret;
|
||||
|
||||
private String token;
|
||||
|
||||
private String encodingAESKey;
|
||||
|
||||
private String preOrderTemplateId;
|
||||
|
||||
private String orderStartTemplateId;
|
||||
|
||||
private String orderSwapEndTemplateId;
|
||||
|
||||
private String orderToPayTemplateId;
|
||||
|
||||
private String orderEndTemplateId;
|
||||
}
|
||||
@ -16,6 +16,7 @@ import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryStep;
|
||||
import com.evotech.hd.common.core.entity.cloud.PageListSwapOrderRequest;
|
||||
import com.evotech.hd.common.core.entity.cloud.VehicleInfo;
|
||||
import com.evotech.hd.common.core.entity.cloud.vo.BatteryStationVO;
|
||||
import com.evotech.hd.wechat.service.CloudService;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
@ -90,4 +91,12 @@ public class CloudServeController {
|
||||
return cloudService.companyByCode(ccode);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "查询微信用户车辆")
|
||||
@GetMapping("/wechatuser/carlist")
|
||||
@ApiOperationSupport(order = 11)
|
||||
public Result<List<VehicleInfo>> listWechatUserCar(@NotBlank @RequestParam String wuid) {
|
||||
return cloudService.listWechatUserCar(wuid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.evotech.hd.wechat.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@ -26,14 +28,14 @@ public class LoginController {
|
||||
@Operation(summary = "登陆")
|
||||
@PostMapping("/xcxlogin")
|
||||
@Parameter(name="js_code", description = "登录时获取的 code,可通过wx.login获取", example = "")
|
||||
public Result<String> code2Session(String js_code) {
|
||||
public Result<Map<String, String>> code2Session(String js_code) {
|
||||
return loginService.code2Session(js_code);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "检验小程序登录态")
|
||||
@PostMapping("/checksessionkey")
|
||||
public Result<Boolean> checkSessionKey(String wuid) {
|
||||
public Result<Map<String, String>> checkSessionKey(String wuid) {
|
||||
return loginService.checkSessionKey(wuid);
|
||||
}
|
||||
|
||||
@ -44,5 +46,10 @@ public class LoginController {
|
||||
return loginService.phoneNumber(wuid, code);
|
||||
}
|
||||
|
||||
@PostMapping("/tokenbuild")
|
||||
public Map<String, String> tokenBuilder(String wuid) {
|
||||
return loginService.tokenBuilder(wuid);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -44,4 +44,11 @@ public class ResourceServerController {
|
||||
return resourceService.listSwiper(appid, type, 1);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取ip")
|
||||
@GetMapping("/util/ip")
|
||||
@ApiOperationSupport(order = 3)
|
||||
public Result<String> ip() {
|
||||
return resourceService.getIp();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -9,11 +9,10 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.wechat.entity.PrePayVO;
|
||||
import com.evotech.hd.wechat.service.WechatPayService;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.Detail;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@ -35,8 +34,8 @@ public class WechatPayController {
|
||||
@Operation(summary = "小程序预支付订单")
|
||||
@PostMapping("/xcx/prepay")
|
||||
@ApiOperationSupport(order = 1)
|
||||
public Result<String> xcxPrepay(String wuid, String remarks, Integer money, Detail detail) {
|
||||
return wechatPayService.xcxPrepay(wuid, remarks, money, detail);
|
||||
public Result<String> xcxPrepay(@RequestBody PrePayVO prePay) {
|
||||
return wechatPayService.xcxPrepay(prePay);
|
||||
}
|
||||
|
||||
|
||||
@ -44,8 +43,8 @@ public class WechatPayController {
|
||||
@PostMapping("/prepayback/msg")
|
||||
@ApiOperationSupport(order = 2)
|
||||
@Hidden
|
||||
public ResponseEntity<String> prepayBack(@RequestBody String body, HttpServletRequest request) {
|
||||
return wechatPayService.PrepayBack(body, request);
|
||||
public ResponseEntity<String> prepayBack(HttpServletRequest request) {
|
||||
return wechatPayService.PrepayBack(request);
|
||||
}
|
||||
|
||||
|
||||
@ -69,8 +68,8 @@ public class WechatPayController {
|
||||
@PostMapping("/refundsback/msg")
|
||||
@ApiOperationSupport(order = 5)
|
||||
@Hidden
|
||||
public ResponseEntity<String> refundsBack(@RequestBody String body, HttpServletRequest request) {
|
||||
return wechatPayService.refundsBack(body, request);
|
||||
public ResponseEntity<String> refundsBack(HttpServletRequest request) {
|
||||
return wechatPayService.refundsBack(request);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,25 @@
|
||||
package com.evotech.hd.wechat.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.evotech.hd.common.core.entity.BasePageRequest;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccount;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatUser;
|
||||
import com.evotech.hd.wechat.service.WechatUserService;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@Tag(name = "微信用户")
|
||||
@RestController
|
||||
@ -26,6 +33,7 @@ public class WechatUserController {
|
||||
|
||||
@Operation(summary = "修改")
|
||||
@PostMapping("/update")
|
||||
@ApiOperationSupport(order = 1)
|
||||
public Result<String> update(@ParameterObject WechatUser wuser) {
|
||||
return wechatUserService.update(wuser);
|
||||
}
|
||||
@ -33,15 +41,40 @@ public class WechatUserController {
|
||||
|
||||
@Operation(summary = "查询")
|
||||
@PostMapping("/userbyuid")
|
||||
@ApiOperationSupport(order = 2)
|
||||
public Result<WechatUser> userByUid(String wuid) {
|
||||
return wechatUserService.userByUid(wuid);
|
||||
}
|
||||
|
||||
@Operation(summary = "绑定公司")
|
||||
@PostMapping("/bindcompany")
|
||||
@ApiOperationSupport(order = 3)
|
||||
public Result<Integer> bindCompany(String wuid, String code, String name) {
|
||||
return wechatUserService.bindCompany(wuid, code, name);
|
||||
}
|
||||
|
||||
@Operation(summary = "开通钱包账户")
|
||||
@PostMapping("/wallet/open")
|
||||
@ApiOperationSupport(order = 4)
|
||||
public Result<Integer> openWallet(String wuid, HttpServletRequest request) {
|
||||
return wechatUserService.openWallet(wuid, request);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "查询钱包账户")
|
||||
@PostMapping("/wallet/list")
|
||||
@ApiOperationSupport(order = 5)
|
||||
public Result<List<WalletAccount>> listWallet(String wuid, HttpServletRequest request) {
|
||||
return wechatUserService.listWallet(wuid, request);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "查询钱包明细")
|
||||
@PostMapping("/wallet/detail/list")
|
||||
@ApiOperationSupport(order = 6)
|
||||
public Result<List<WalletAccountDetail>> listWalletDetail(String walletCode, @ParameterObject BasePageRequest basePage) {
|
||||
return wechatUserService.listWalletDetail(walletCode, basePage);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
package com.evotech.hd.wechat.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.evotech.hd.wechat.service.XCXQRCodeService;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
//@Tag(name = "小程序码")
|
||||
@RestController
|
||||
@RequestMapping("/xcx/qrcode")
|
||||
@ApiSupport(order = 16)
|
||||
@Hidden
|
||||
public class XCXQRCodeController {
|
||||
|
||||
|
||||
@Resource
|
||||
private XCXQRCodeService xcxQRCodeService;
|
||||
|
||||
|
||||
// @Operation(summary = "获取小程序码")
|
||||
@GetMapping("/get")
|
||||
// @ApiOperationSupport(order = 1)
|
||||
public void getQRCode(String path, @RequestParam(required = false) String width, @RequestParam(required = false)String env_version, HttpServletResponse response) {
|
||||
xcxQRCodeService.getQRCode(path, width, env_version, response);
|
||||
}
|
||||
|
||||
|
||||
// @Operation(summary = "获取小程序二维码")
|
||||
@GetMapping("/create")
|
||||
// @ApiOperationSupport(order = 2)
|
||||
public void createQRCode(String path, @RequestParam(required = false) String width, HttpServletResponse response) {
|
||||
xcxQRCodeService.createQRCode(path, width, response);
|
||||
}
|
||||
|
||||
|
||||
// @Operation(summary = "获取小程序码")
|
||||
@GetMapping("/get2")
|
||||
// @ApiOperationSupport(order = 1)
|
||||
public String getQRCode2(String path, @RequestParam(required = false) String width, @RequestParam(required = false)String env_version) {
|
||||
return xcxQRCodeService.getQRCode2(path, width, env_version);
|
||||
}
|
||||
|
||||
// @Operation(summary = "获取小程序二维码")
|
||||
@GetMapping("/create2")
|
||||
// @ApiOperationSupport(order = 2)
|
||||
public String createQRCode2(String path, @RequestParam(required = false) String width) {
|
||||
return xcxQRCodeService.createQRCode2(path, width);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.evotech.hd.wechat.controller.gzh;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.evotech.hd.wechat.entity.gzh.GZHWechatSigDTO;
|
||||
import com.evotech.hd.wechat.service.gzh.GZHMessageReceiveService;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@Tag(name = "公众号接收消息")
|
||||
@RestController
|
||||
@RequestMapping("/gzh/msg/receive")
|
||||
@ApiSupport(order = 30)
|
||||
@Hidden
|
||||
public class GZHMessageReceiveController {
|
||||
|
||||
@Resource
|
||||
private GZHMessageReceiveService messageReceiveService;
|
||||
|
||||
|
||||
@Operation(summary = "接收微信公众号推送的消息")
|
||||
@RequestMapping(value = "/handle", method = {RequestMethod.GET, RequestMethod.POST})
|
||||
@ApiOperationSupport(order = 1)
|
||||
public String messageHandle(GZHWechatSigDTO sigDto, HttpServletRequest request) {
|
||||
return messageReceiveService.messageHandle(sigDto, request);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.evotech.hd.wechat.controller.gzh;
|
||||
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;
|
||||
import com.evotech.hd.wechat.service.gzh.GZHMessageTemplateService;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Tag(name = "公众号发送消息")
|
||||
@RestController
|
||||
@RequestMapping("/gzh/msg/send")
|
||||
@ApiSupport(order = 31)
|
||||
public class GZHMessageSendController {
|
||||
|
||||
@Resource
|
||||
private GZHMessageTemplateService gzhMessageTemplateService;
|
||||
|
||||
|
||||
@Operation(summary = "预约发送公众号消息")
|
||||
@PostMapping("/preorder")
|
||||
@ApiOperationSupport(order = 1)
|
||||
public Result<String> preOrderMessage(@ParameterObject OrderSwapBatteryPre osbp) {
|
||||
return gzhMessageTemplateService.sendTemplateMessageOrderPre(osbp);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "推送公众号订单消息")
|
||||
@PostMapping("/order")
|
||||
@ApiOperationSupport(order = 2)
|
||||
public Result<String> orderMessage(@ParameterObject OrderSwapBattery osb, @RequestParam Integer templateType) {
|
||||
return gzhMessageTemplateService.sendTemplateMessageOrder(osb, templateType);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "预约发送公众号消息2")
|
||||
@PostMapping("/preorder2")
|
||||
@ApiOperationSupport(order = 3)
|
||||
@Hidden
|
||||
public Result<String> preOrderMessage2(@RequestBody OrderSwapBatteryPre osbp) {
|
||||
return gzhMessageTemplateService.sendTemplateMessageOrderPre(osbp);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package com.evotech.hd.wechat.entity;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.GoodsDetail;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(name = "预下单参数")
|
||||
public class PrePayVO {
|
||||
|
||||
@Schema(description = "用户编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank
|
||||
private String wuid;
|
||||
|
||||
@Schema(description = "订单总描述", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank
|
||||
private String description;
|
||||
|
||||
@Schema(description = "支付金额,单位:分", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
@Min(1)
|
||||
@Max(100000000)
|
||||
private Integer total;
|
||||
|
||||
@Schema(description = "支付结束时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date timeExp;
|
||||
|
||||
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
|
||||
private String StationCode;
|
||||
|
||||
@Schema(description = "订单附加信息")
|
||||
private String attach;
|
||||
|
||||
@Schema(description = "使用的优惠活动编码", hidden = true)
|
||||
private String goodsTag;
|
||||
|
||||
@Schema(description = "商家小票ID", hidden = true)
|
||||
private String invoiceId;
|
||||
|
||||
@Schema(description = "商家小票金额", hidden = true)
|
||||
private Integer costPrice;
|
||||
|
||||
@Schema(description = "商品详情")
|
||||
private List<GoodsDetail> goodsDetail;
|
||||
|
||||
@Schema(description = "用户IP", requiredMode = RequiredMode.REQUIRED)
|
||||
private String payerClientIp;
|
||||
|
||||
@Schema(description = "用户设备型号")
|
||||
private String deviceId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.evotech.hd.wechat.entity.gzh;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(name = "公众号关注事件消息实体")
|
||||
public class GZHSubscribeEvent {
|
||||
|
||||
@Schema(description = "开发者微信号")
|
||||
private String ToUserName;
|
||||
|
||||
@Schema(description = "发送方账号(一个OpenID)")
|
||||
private String FromUserName;
|
||||
|
||||
@Schema(description = "消息创建时间 (整型)")
|
||||
private Integer CreateTime;
|
||||
|
||||
@Schema(description = "消息类型,event")
|
||||
private String MsgType;
|
||||
|
||||
@Schema(description = "事件类型,subscribe(订阅)、unsubscribe(取消订阅)")
|
||||
private String Event;
|
||||
|
||||
private String EventKey;
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.evotech.hd.wechat.entity.gzh;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(name = "公众号签名验证时发送的参数")
|
||||
public class GZHWechatSigDTO {
|
||||
|
||||
@Schema(description = "微信加密签名")
|
||||
private String signature;
|
||||
|
||||
@Schema(description = "时间戳")
|
||||
private String timestamp;
|
||||
|
||||
@Schema(description = "随机数")
|
||||
private String nonce;
|
||||
|
||||
@Schema(description = "随机字符串")
|
||||
private String echostr;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.evotech.hd.wechat.entity.gzh.templatemessage;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 充电完成 模板消息 关键词
|
||||
*/
|
||||
@Getter
|
||||
public class ChargeTemplateData {
|
||||
|
||||
private JSONObject character_string14;
|
||||
|
||||
private JSONObject character_string31;
|
||||
|
||||
private JSONObject character_string25;
|
||||
|
||||
private JSONObject amount34;
|
||||
|
||||
private JSONObject amount28;
|
||||
|
||||
|
||||
public void setCharacter_string14(String value1) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value1);
|
||||
this.character_string14 = jo;
|
||||
}
|
||||
|
||||
public void setCharacter_string31(String value2) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value2);
|
||||
this.character_string31 = jo;
|
||||
}
|
||||
|
||||
public void setCharacter_string25(String value3) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value3);
|
||||
this.character_string25 = jo;
|
||||
}
|
||||
|
||||
public void setAmount34(String value4) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value4);
|
||||
this.amount34 = jo;
|
||||
}
|
||||
|
||||
public void setAmount28(String value5) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value5);
|
||||
this.amount28 = jo;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.evotech.hd.wechat.entity.gzh.templatemessage;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MessageTemplateSendData implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8911097073333862L;
|
||||
|
||||
@Schema(description = "接收者openid", requiredMode = RequiredMode.REQUIRED)
|
||||
private String touser;
|
||||
|
||||
@Schema(description = "模板ID", requiredMode = RequiredMode.REQUIRED)
|
||||
private String template_id;
|
||||
|
||||
@Schema(description = "模板跳转链接")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "跳小程序所需数据,不需跳小程序可不用传该数据")
|
||||
private Miniprogram miniprogram;
|
||||
|
||||
@Schema(description = "防重入id。对于同一个openid + client_msg_id, 只发送一条消息,10分钟有效")
|
||||
private String client_msg_id;
|
||||
|
||||
@Schema(description = "模板数据")
|
||||
private JSONObject data;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
package com.evotech.hd.wechat.entity.gzh.templatemessage;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Miniprogram {
|
||||
|
||||
@Schema(description = "所需跳转到的小程序appid")
|
||||
private String appid;
|
||||
|
||||
@Schema(description = "所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar)")
|
||||
private String path;
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.evotech.hd.wechat.entity.gzh.templatemessage;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 支付完成 模板消息 关键词
|
||||
*/
|
||||
@Getter
|
||||
public class PayTemplateData {
|
||||
|
||||
private JSONObject character_string1;
|
||||
|
||||
private JSONObject car_number10;
|
||||
|
||||
private JSONObject thing2;
|
||||
|
||||
private JSONObject amount6;
|
||||
|
||||
private JSONObject time9;
|
||||
|
||||
|
||||
public void setCharacter_string1(String value1) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value1);
|
||||
this.character_string1 = jo;
|
||||
}
|
||||
|
||||
public void setCar_number10(String value2) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value2);
|
||||
this.car_number10 = jo;
|
||||
}
|
||||
|
||||
public void setThing2(String value3) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value3);
|
||||
this.thing2 = jo;
|
||||
}
|
||||
|
||||
public void setAmount6(String value4) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value4);
|
||||
this.amount6 = jo;
|
||||
}
|
||||
|
||||
public void setTime9(String value5) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value5);
|
||||
this.time9 = jo;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.evotech.hd.wechat.entity.gzh.templatemessage;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class PreOrderTemplateData {
|
||||
|
||||
private JSONObject car_number1;
|
||||
|
||||
private JSONObject thing2;
|
||||
|
||||
private JSONObject time3;
|
||||
|
||||
private JSONObject thing5;
|
||||
|
||||
private JSONObject phone_number4;
|
||||
|
||||
public void setCar_number1(String value1) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value1);
|
||||
this.car_number1 = jo;
|
||||
}
|
||||
|
||||
public void setThing2(String value2) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value2);
|
||||
this.thing2 = jo;
|
||||
}
|
||||
|
||||
public void setTime3(String value3) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value3);
|
||||
this.time3 = jo;
|
||||
}
|
||||
|
||||
public void setThing5(String value4) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value4);
|
||||
this.thing5 = jo;
|
||||
}
|
||||
|
||||
public void setPhone_number4(String value4) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value4);
|
||||
this.phone_number4 = jo;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.evotech.hd.wechat.entity.gzh.templatemessage;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 换电成功 模板消息 关键词
|
||||
*/
|
||||
@Getter
|
||||
public class SwapTemplateData {
|
||||
|
||||
private JSONObject thing2;
|
||||
|
||||
private JSONObject character_string3;
|
||||
|
||||
private JSONObject character_string4;
|
||||
|
||||
private JSONObject time5;
|
||||
|
||||
|
||||
public void setThing2(String value1) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value1);
|
||||
this.thing2 = jo;
|
||||
}
|
||||
|
||||
public void setCharacter_string3(String value2) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value2);
|
||||
this.character_string3 = jo;
|
||||
}
|
||||
|
||||
public void setCharacter_string4(String value3) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value3);
|
||||
this.character_string4 = jo;
|
||||
}
|
||||
|
||||
public void setTime5(String value4) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("value", value4);
|
||||
this.time5 = jo;
|
||||
}
|
||||
|
||||
}
|
||||
@ -19,7 +19,7 @@ public class AccessTokenService {
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
private String accessTokenPrefix = "hd:wechat:accessToken:";
|
||||
private String accessTokenPrefix = "hd:wechat:accessToken:xcx:";
|
||||
|
||||
public String getAccessToken() {
|
||||
if (redisUtil.hasKey(accessTokenPrefix + xcxProperties.getAppid())) {
|
||||
@ -31,7 +31,7 @@ public class AccessTokenService {
|
||||
if (StringUtils.hasText(jo.getStr("errcode"))) {
|
||||
throw new RuntimeException(res);
|
||||
}
|
||||
redisUtil.set(accessTokenPrefix + xcxProperties.getAppid(), jo.getStr("access_token"), 7200L - 15);
|
||||
redisUtil.set(accessTokenPrefix + xcxProperties.getAppid(), jo.getStr("access_token"), 7200L);
|
||||
return jo.getStr("access_token");
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,11 @@ import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryStep;
|
||||
import com.evotech.hd.common.core.entity.cloud.PageListSwapOrderRequest;
|
||||
import com.evotech.hd.common.core.entity.cloud.TradeDetail;
|
||||
import com.evotech.hd.common.core.entity.cloud.VehicleInfo;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccount;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail;
|
||||
import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest;
|
||||
import com.evotech.hd.common.core.entity.cloud.vo.BatteryStationVO;
|
||||
|
||||
@FeignClient(value = "cloud-server")
|
||||
@ -49,4 +54,24 @@ public interface CloudService {
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<Map<String, String>> companyByCode(@RequestParam String ccode);
|
||||
|
||||
@GetMapping(value = "/cloud/vehicle/wechatuser/relation/list",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<List<VehicleInfo>> listWechatUserCar(@RequestParam String wuid);
|
||||
|
||||
@PostMapping(value = "/cloud/wallet/add",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<Integer> addWallet(WalletAccount wa);
|
||||
|
||||
@GetMapping(value = "/cloud/wallet/list",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<List<WalletAccount>> listWallet(@RequestParam String wuid);
|
||||
|
||||
@GetMapping(value = "/cloud/wallet/detail/list",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<List<WalletAccountDetail>> listWalletDetail(@SpringQueryMap PageListWalletRequest plwr);
|
||||
|
||||
@PostMapping(value = "/cloud/trade/wechatpay/notify",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public void wechatPayNotifyHandle(TradeDetail tradeDetail);
|
||||
|
||||
}
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
package com.evotech.hd.wechat.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
|
||||
public interface LoginService {
|
||||
|
||||
public Result<String> code2Session(String js_code);
|
||||
public Result<Map<String, String>> code2Session(String js_code);
|
||||
|
||||
public Result<Boolean> checkSessionKey(String wuid);
|
||||
public Result<Map<String, String>> checkSessionKey(String wuid);
|
||||
|
||||
public Result<String> phoneNumber(String wuid, String code);
|
||||
|
||||
public Map<String, String> tokenBuilder(String wuid);
|
||||
|
||||
}
|
||||
|
||||
@ -21,4 +21,8 @@ public interface ResourceService {
|
||||
@GetMapping(value = "/resource/wechat/swiper/list",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<List<WechatSwiper>> listSwiper(@RequestParam String appid, @RequestParam Integer type, @RequestParam Integer status);
|
||||
|
||||
@GetMapping(value = "/resource/util/ip",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<String> getIp();
|
||||
}
|
||||
|
||||
@ -2,21 +2,20 @@ package com.evotech.hd.wechat.service;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.Detail;
|
||||
|
||||
import com.evotech.hd.wechat.entity.PrePayVO;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public interface WechatPayService {
|
||||
|
||||
public Result<String> xcxPrepay(String wuid, String remarks, Integer money, Detail detail);
|
||||
public Result<String> xcxPrepay(PrePayVO prePay);
|
||||
|
||||
public ResponseEntity<String> PrepayBack(String body, HttpServletRequest request);
|
||||
public ResponseEntity<String> PrepayBack(HttpServletRequest request);
|
||||
|
||||
public Result<String> orderQuery(Integer type, String transactionId, String outTradeNo);
|
||||
|
||||
public Result<String> refunds(String outTradeNo, String transactionId, String reason, Integer money, Integer total);
|
||||
|
||||
public ResponseEntity<String> refundsBack(String body, HttpServletRequest request);
|
||||
public ResponseEntity<String> refundsBack(HttpServletRequest request);
|
||||
|
||||
public Result<String> refundsQuery(String outRefundNo);
|
||||
|
||||
|
||||
@ -1,8 +1,15 @@
|
||||
package com.evotech.hd.wechat.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.evotech.hd.common.core.entity.BasePageRequest;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccount;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatUser;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public interface WechatUserService {
|
||||
|
||||
public Result<String> update(WechatUser wuser);
|
||||
@ -11,4 +18,10 @@ public interface WechatUserService {
|
||||
|
||||
public Result<Integer> bindCompany(String wuid, String code, String name);
|
||||
|
||||
public Result<Integer> openWallet(String wuid, HttpServletRequest request);
|
||||
|
||||
public Result<List<WalletAccount>> listWallet(String wuid, HttpServletRequest request);
|
||||
|
||||
public Result<List<WalletAccountDetail>> listWalletDetail(String walletCode, BasePageRequest basePage);
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
package com.evotech.hd.wechat.service;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
public interface XCXQRCodeService {
|
||||
|
||||
public void getQRCode(String path, String width, String env_version, HttpServletResponse response);
|
||||
|
||||
public void createQRCode(String path, String width, HttpServletResponse response);
|
||||
|
||||
public String getQRCode2(String path, String width, String env_version);
|
||||
|
||||
public String createQRCode2(String path, String width);
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.evotech.hd.wechat.service.gzh;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.evotech.hd.common.redis.utils.RedisUtil;
|
||||
import com.evotech.hd.wechat.config.GZHProperties;
|
||||
import com.evotech.hd.wechat.utils.xcx.AccessTokenUtil;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Service
|
||||
public class GZHAccessTokenService {
|
||||
|
||||
@Resource
|
||||
private GZHProperties gzhProperties;
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
private String accessTokenPrefix = "hd:wechat:accessToken:gzh:";
|
||||
|
||||
public String gzhAccessToken() {
|
||||
if (redisUtil.hasKey(accessTokenPrefix + gzhProperties.getAppid())) {
|
||||
return redisUtil.get(accessTokenPrefix + gzhProperties.getAppid()).toString();
|
||||
}
|
||||
String res = AccessTokenUtil.accessToken(gzhProperties.getAppid(), gzhProperties.getAppSecret());
|
||||
JSONObject jo = JSONUtil.parseObj(res);
|
||||
// {"errcode":40013,"errmsg":"invalid appid rid: 6708ba65-0b425b74-4620599c"}
|
||||
if (StringUtils.hasText(jo.getStr("errcode"))) {
|
||||
throw new RuntimeException(res);
|
||||
}
|
||||
redisUtil.set(accessTokenPrefix + gzhProperties.getAppid(), jo.getStr("access_token"), 7200L);
|
||||
return jo.getStr("access_token");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
package com.evotech.hd.wechat.service.gzh;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatUser;
|
||||
import com.evotech.hd.wechat.config.GZHProperties;
|
||||
import com.evotech.hd.wechat.entity.gzh.GZHWechatSigDTO;
|
||||
import com.evotech.hd.wechat.utils.gzh.OpenId2UnionIdUtil;
|
||||
|
||||
import cn.hutool.core.util.XmlUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@Service
|
||||
public class GZHMessageReceiveService {
|
||||
|
||||
@Resource
|
||||
private GZHProperties gzhProperties;
|
||||
@Resource
|
||||
private GZHAccessTokenService gzhAccessTokenService;
|
||||
@Resource
|
||||
private WechatUserDao wechatUserDao;
|
||||
|
||||
|
||||
public String messageHandle(GZHWechatSigDTO sigDto, HttpServletRequest request) {
|
||||
if (!isFromWechat(sigDto.getSignature(), sigDto.getTimestamp(), sigDto.getNonce())) {
|
||||
System.out.println("XXXXXXXXXXXXXXXXXX");
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
System.out.println("++++++++");
|
||||
String res = HttpUtil.getString(request.getInputStream(), Charset.defaultCharset(), false);
|
||||
Map<String, Object> map = XmlUtil.xmlToMap(res);
|
||||
if ("event".equals(map.get("MsgType").toString())) {
|
||||
switch (map.get("Event").toString()) {
|
||||
case "subscribe":
|
||||
subscribeEventHandle(map);
|
||||
break;
|
||||
case "unsubscribe":
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订阅事件处理
|
||||
* @param map
|
||||
*/
|
||||
private void subscribeEventHandle(Map<String, Object> map) {
|
||||
String openid = map.get("FromUserName").toString();
|
||||
String gzhid = map.get("ToUserName").toString();
|
||||
String res = OpenId2UnionIdUtil.gzhUserInfo(gzhAccessTokenService.gzhAccessToken(), openid);
|
||||
JSONObject jo = JSONUtil.parseObj(res);
|
||||
if (!jo.containsKey("errcode")) {
|
||||
String unionid = jo.getStr("unionid");
|
||||
WechatUser user = new WechatUser();
|
||||
user.setGzhId(gzhid);
|
||||
user.setGzhOpenid(openid);
|
||||
wechatUserDao.update(user, new QueryWrapper<WechatUser>().eq("unionid", unionid));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 验证微信签名
|
||||
* @param signature
|
||||
* @param timestamp
|
||||
* @param nonce
|
||||
* @return
|
||||
*/
|
||||
private Boolean isFromWechat(String signature, String timestamp, String nonce) {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add(gzhProperties.getToken());
|
||||
list.add(timestamp);
|
||||
list.add(nonce);
|
||||
Collections.sort(list);
|
||||
return signature.equals(SecureUtil.sha1(list.get(0) + list.get(1) + list.get(2)));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,164 @@
|
||||
package com.evotech.hd.wechat.service.gzh;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBattery;
|
||||
import com.evotech.hd.common.core.entity.cloud.OrderSwapBatteryPre;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatUser;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
import com.evotech.hd.wechat.config.GZHProperties;
|
||||
import com.evotech.hd.wechat.config.XcxProperties;
|
||||
import com.evotech.hd.wechat.entity.gzh.templatemessage.ChargeTemplateData;
|
||||
import com.evotech.hd.wechat.entity.gzh.templatemessage.MessageTemplateSendData;
|
||||
import com.evotech.hd.wechat.entity.gzh.templatemessage.Miniprogram;
|
||||
import com.evotech.hd.wechat.entity.gzh.templatemessage.PayTemplateData;
|
||||
import com.evotech.hd.wechat.entity.gzh.templatemessage.PreOrderTemplateData;
|
||||
import com.evotech.hd.wechat.entity.gzh.templatemessage.SwapTemplateData;
|
||||
import com.evotech.hd.wechat.utils.gzh.TemplateMessageUtil;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Service
|
||||
public class GZHMessageTemplateService {
|
||||
|
||||
|
||||
private static String preOrderPage = "pages/home/index";
|
||||
|
||||
private static String orderPage = "pages/home/index";
|
||||
|
||||
private static String orderDetailPage = "pages/home/index";
|
||||
|
||||
|
||||
@Resource
|
||||
private GZHAccessTokenService gzhAccessTokenService;
|
||||
@Resource
|
||||
private GZHProperties gzhProperties;
|
||||
@Resource
|
||||
private XcxProperties xcxProperties;
|
||||
@Resource
|
||||
private WechatUserDao wechatUserDao;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 预约完成推送公众号消息
|
||||
* @param osbp
|
||||
* @return
|
||||
*/
|
||||
public Result<String> sendTemplateMessageOrderPre(OrderSwapBatteryPre osbp) {
|
||||
WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper<WechatUser>().eq("wuid", osbp.getUcode()));
|
||||
if (wuser == null) {
|
||||
return null;
|
||||
}
|
||||
if (!StringUtils.hasText(wuser.getGzhOpenid())) {
|
||||
return new Result<String>().error("未关注公众号!");
|
||||
}
|
||||
MessageTemplateSendData sendData = new MessageTemplateSendData();
|
||||
sendData.setTouser(wuser.getGzhOpenid());
|
||||
|
||||
sendData.setTemplate_id(gzhProperties.getPreOrderTemplateId());
|
||||
|
||||
Miniprogram miniprogram = new Miniprogram();
|
||||
miniprogram.setAppid(xcxProperties.getAppid());
|
||||
miniprogram.setPath(preOrderPage);
|
||||
sendData.setMiniprogram(miniprogram);
|
||||
|
||||
PreOrderTemplateData data = new PreOrderTemplateData();
|
||||
data.setCar_number1(osbp.getPlateNum());
|
||||
data.setThing2(osbp.getStationName());
|
||||
data.setTime3(DateUtil.format(osbp.getReservationTime(), DatePattern.NORM_DATETIME_FORMATTER));
|
||||
data.setThing5(osbp.getUname());
|
||||
data.setPhone_number4(osbp.getPhone());
|
||||
sendData.setData(JSONUtil.parseObj(data));
|
||||
|
||||
String res = TemplateMessageUtil.templateMessageSend(gzhAccessTokenService.gzhAccessToken(), sendData);
|
||||
JSONObject jo = JSONUtil.parseObj(res);
|
||||
if (jo.getInt("errcode") == 0) {
|
||||
return new Result<String>().success(jo);
|
||||
}
|
||||
return new Result<String>().error(CodeMsg.WECHAT_API_ERROR, jo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送公众号订单消息
|
||||
* @param osb
|
||||
* @param templateType
|
||||
* @return
|
||||
*/
|
||||
public Result<String> sendTemplateMessageOrder(OrderSwapBattery osb, Integer templateType) {
|
||||
if (!StringUtils.hasText(osb.getOrderPreUid())) {
|
||||
return null;
|
||||
}
|
||||
WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper<WechatUser>().eq("wuid", osb.getOrderPreUid()));
|
||||
if (wuser == null) {
|
||||
return null;
|
||||
}
|
||||
if (!StringUtils.hasText(wuser.getGzhOpenid())) {
|
||||
return new Result<String>().error("未关注公众号!");
|
||||
}
|
||||
|
||||
MessageTemplateSendData sendData = new MessageTemplateSendData();
|
||||
sendData.setTouser(wuser.getGzhOpenid());
|
||||
String templateId = "";
|
||||
Miniprogram miniprogram = new Miniprogram();
|
||||
miniprogram.setAppid(xcxProperties.getAppid());
|
||||
switch (templateType) {
|
||||
// 换电完成
|
||||
case 1:
|
||||
templateId = gzhProperties.getOrderSwapEndTemplateId();
|
||||
miniprogram.setPath(orderPage);
|
||||
SwapTemplateData data = new SwapTemplateData();
|
||||
data.setThing2(osb.getStationName());
|
||||
data.setCharacter_string3(osb.getReturnBatCode());
|
||||
data.setCharacter_string4(osb.getRentBatCode());
|
||||
data.setTime5(DateUtil.format(osb.getOrderTime(), DatePattern.NORM_DATETIME_FORMATTER));
|
||||
sendData.setData(JSONUtil.parseObj(data));
|
||||
break;
|
||||
// 充电完成,待结算
|
||||
case 2:
|
||||
templateId = gzhProperties.getOrderEndTemplateId();
|
||||
miniprogram.setPath(orderPage);
|
||||
ChargeTemplateData chargeData = new ChargeTemplateData();
|
||||
chargeData.setCharacter_string14(osb.getOrderNo());
|
||||
chargeData.setCharacter_string31(osb.getReturnBatCode());
|
||||
chargeData.setCharacter_string25(osb.getElectAmount() + "");
|
||||
chargeData.setAmount34(osb.getServiceFee().toString());
|
||||
chargeData.setAmount28(osb.getAmount() + "");
|
||||
sendData.setData(JSONUtil.parseObj(chargeData));
|
||||
break;
|
||||
// 付款完成
|
||||
case 3:
|
||||
templateId = gzhProperties.getOrderSwapEndTemplateId();
|
||||
miniprogram.setPath(orderDetailPage);
|
||||
PayTemplateData payData = new PayTemplateData();
|
||||
payData.setThing2(osb.getStationName());
|
||||
payData.setCharacter_string1(osb.getOrderNo());
|
||||
payData.setCar_number10(osb.getPlateNum());
|
||||
payData.setAmount6(osb.getAmount() + "");
|
||||
payData.setTime9("");
|
||||
sendData.setData(JSONUtil.parseObj(payData));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sendData.setTemplate_id(templateId);
|
||||
sendData.setMiniprogram(miniprogram);
|
||||
|
||||
String res = TemplateMessageUtil.templateMessageSend(gzhAccessTokenService.gzhAccessToken(), sendData);
|
||||
JSONObject jo = JSONUtil.parseObj(res);
|
||||
if (jo.getInt("errcode") == 0) {
|
||||
return new Result<String>().success(jo);
|
||||
}
|
||||
return new Result<String>().error(CodeMsg.WECHAT_API_ERROR, jo);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,7 +1,10 @@
|
||||
package com.evotech.hd.wechat.service.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@ -11,6 +14,7 @@ import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatUser;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
import com.evotech.hd.common.core.utils.XCXUtil;
|
||||
import com.evotech.hd.common.redis.utils.RedisUtil;
|
||||
import com.evotech.hd.wechat.config.XcxProperties;
|
||||
import com.evotech.hd.wechat.service.AccessTokenService;
|
||||
@ -18,10 +22,11 @@ import com.evotech.hd.wechat.service.LoginService;
|
||||
import com.evotech.hd.wechat.utils.xcx.LoginUtil;
|
||||
import com.evotech.hd.wechat.utils.xcx.PhoneNumberUtil;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import cn.hutool.crypto.digest.HMac;
|
||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
@ -38,12 +43,20 @@ public class LoginServiceImpl implements LoginService {
|
||||
@Resource
|
||||
private AccessTokenService accessTokenService;
|
||||
|
||||
@Value("${hbyt.xcx.token_exp_hour:2}")
|
||||
private Integer tokenExpHour;
|
||||
|
||||
/**
|
||||
* 登陆成功后会生成本地token,返回前端,前端请求携带
|
||||
* 在gateway中对微信服务的token重加一套验证逻辑,
|
||||
* 在gateway验证时,如果是过期,会在那重新生成token返回
|
||||
*/
|
||||
@Override
|
||||
public Result<String> code2Session(String js_code) {
|
||||
public Result<Map<String, String>> code2Session(String js_code) {
|
||||
String res = LoginUtil.code2Session(xcxProperties.getAppid(), xcxProperties.getAppSecret(), js_code);
|
||||
JSONObject jo = JSONUtil.parseObj(res);
|
||||
if (StringUtils.hasText(jo.getStr("errcode"))) {
|
||||
return new Result<String>().error(CodeMsg.WECHAT_LOGIN_ERROR, jo);
|
||||
return new Result<Map<String, String>>().error(CodeMsg.WECHAT_LOGIN_ERROR, jo);
|
||||
}
|
||||
String openid = jo.getStr("openid");
|
||||
String unionid = jo.getStr("unionid");
|
||||
@ -51,7 +64,7 @@ public class LoginServiceImpl implements LoginService {
|
||||
// 是否登陆过
|
||||
WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper<WechatUser>().eq("openid", openid));
|
||||
if (wuser == null) {
|
||||
String wuid = MD5.create().digestHex(xcxProperties.getAppid() + openid + "HBYT");
|
||||
String wuid = XCXUtil.wechatUid(xcxProperties.getAppid(), openid);
|
||||
wuser = new WechatUser();
|
||||
wuser.setAppid(xcxProperties.getAppid());
|
||||
wuser.setCtime(new Date());
|
||||
@ -64,26 +77,35 @@ public class LoginServiceImpl implements LoginService {
|
||||
redisUtil.set(HDConstant.openidPrefix + wuser.getWuid(), openid);
|
||||
redisUtil.set(HDConstant.unionidPrefix + wuser.getWuid(), unionid);
|
||||
redisUtil.set(HDConstant.sessionKeyPrefix + wuser.getWuid(), sessionKey);
|
||||
|
||||
return new Result<String>().success(wuser.getWuid());
|
||||
// token
|
||||
Map<String, String> m = tokenBuilder(wuser.getWuid());
|
||||
return new Result<Map<String, String>>().success(m);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 检查登录态,检查成功后刷新本地token
|
||||
*/
|
||||
@Override
|
||||
public Result<Boolean> checkSessionKey(String wuid) {
|
||||
public Result<Map<String, String>> checkSessionKey(String wuid) {
|
||||
if (!redisUtil.hasKey(HDConstant.openidPrefix + wuid) || !redisUtil.hasKey(HDConstant.sessionKeyPrefix + wuid)) {
|
||||
return new Result<Boolean>().error(CodeMsg.WECHAT_SERRION_ERROR);
|
||||
return new Result<Map<String, String>>().error(CodeMsg.WECHAT_SERRION_ERROR);
|
||||
}
|
||||
String openid = redisUtil.get(HDConstant.openidPrefix + wuid).toString();
|
||||
String sessionKey = redisUtil.get(HDConstant.sessionKeyPrefix + wuid).toString();
|
||||
HMac hmac = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, sessionKey.getBytes());
|
||||
String res = LoginUtil.code2Session(xcxProperties.getAppid(), openid, hmac.digestHex(""));
|
||||
String res = LoginUtil.checkSessionKey(accessTokenService.getAccessToken(), openid, hmac.digestHex(""));
|
||||
JSONObject jo = JSONUtil.parseObj(res);
|
||||
if (jo.getInt("errcode") == 0) {
|
||||
return new Result<Boolean>().success("OK");
|
||||
Map<String, String> m = tokenBuilder(wuid);
|
||||
return new Result<Map<String, String>>().success(m);
|
||||
}
|
||||
return new Result<Boolean>().error(CodeMsg.WECHAT_SERRION_ERROR, jo);
|
||||
return new Result<Map<String, String>>().error(CodeMsg.WECHAT_SERRION_ERROR, jo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Result<String> phoneNumber(String wuid, String code) {
|
||||
WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper<WechatUser>().eq("wuid", wuid));
|
||||
@ -107,6 +129,19 @@ public class LoginServiceImpl implements LoginService {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, String> tokenBuilder(String wuid) {
|
||||
String randomStr = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_FORMATTER);
|
||||
String wxToken = XCXUtil.wechatToken(wuid, randomStr);
|
||||
redisUtil.set(HDConstant.wxToken + wuid, wxToken, tokenExpHour * 3600L);
|
||||
redisUtil.set(HDConstant.tokenRandomStr + wuid, randomStr);
|
||||
Map<String, String> m = new HashMap<String, String>();
|
||||
m.put("wuid", wuid);
|
||||
m.put("wxToken", wxToken);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,30 +1,48 @@
|
||||
package com.evotech.hd.wechat.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.evotech.hd.common.core.dao.wechat.WechatPayPreOrderDao;
|
||||
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.TradeDetail;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatPayAttach;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatPayPreOrder;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatUser;
|
||||
import com.evotech.hd.common.core.utils.XCXUtil;
|
||||
import com.evotech.hd.wechat.config.XcxProperties;
|
||||
import com.evotech.hd.wechat.entity.PrePayVO;
|
||||
import com.evotech.hd.wechat.service.CloudService;
|
||||
import com.evotech.hd.wechat.service.WechatPayService;
|
||||
import com.evotech.hd.wechat.utils.wechatpay.WechatPayUtil;
|
||||
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
||||
import com.wechat.pay.java.core.notification.NotificationParser;
|
||||
import com.wechat.pay.java.core.notification.RequestParam;
|
||||
import com.wechat.pay.java.core.util.IOUtil;
|
||||
import com.wechat.pay.java.service.billdownload.BillDownloadService;
|
||||
import com.wechat.pay.java.service.billdownload.model.GetTradeBillRequest;
|
||||
import com.wechat.pay.java.service.billdownload.model.QueryBillEntity;
|
||||
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.Detail;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.GoodsDetail;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByIdRequest;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.SceneInfo;
|
||||
import com.wechat.pay.java.service.payments.model.Transaction;
|
||||
import com.wechat.pay.java.service.payments.model.Transaction.TradeTypeEnum;
|
||||
import com.wechat.pay.java.service.refund.RefundService;
|
||||
import com.wechat.pay.java.service.refund.model.AmountReq;
|
||||
import com.wechat.pay.java.service.refund.model.CreateRequest;
|
||||
@ -37,37 +55,85 @@ import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.ServletInputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WechatPayServiceImpl implements WechatPayService {
|
||||
|
||||
@Resource
|
||||
private RSAAutoCertificateConfig config;
|
||||
@Resource
|
||||
private XcxProperties xcxProperties;
|
||||
@Resource
|
||||
private WechatUserDao wechatUserDao;
|
||||
@Resource
|
||||
private WechatPayPreOrderDao preOrderDao;
|
||||
@Resource
|
||||
private CloudService cloudService;
|
||||
|
||||
|
||||
@Override
|
||||
public Result<String> xcxPrepay(String wuid, String remarks, Integer money, Detail detail) {
|
||||
public Result<String> xcxPrepay(PrePayVO prePay) {
|
||||
// 校验用户
|
||||
WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper<WechatUser>().eq("wuid", prePay.getWuid()));
|
||||
if (wuser == null || !StringUtils.hasText(wuser.getOpenid())) {
|
||||
return new Result<String>().error("用户信息错误");
|
||||
}
|
||||
WechatPayPreOrder preOrder = new WechatPayPreOrder();
|
||||
// 组装数据
|
||||
PrepayRequest request = new PrepayRequest();
|
||||
Amount amount = new Amount();
|
||||
// amount.setTotal(money);
|
||||
amount.setTotal(1);
|
||||
request.setAmount(amount);
|
||||
request.setAttach(remarks);
|
||||
// 基础信息
|
||||
request.setTimeExpire(prePay.getTimeExp() == null?DateUtil.format(DateUtil.offsetMinute(new Date(), 30), DatePattern.UTC_PATTERN): DateUtil.format(prePay.getTimeExp(), DatePattern.UTC_PATTERN));
|
||||
request.setAttach(prePay.getAttach());
|
||||
request.setAppid(xcxProperties.getAppid());
|
||||
request.setMchid(xcxProperties.getMchid());
|
||||
request.setDescription("测试商品标题");
|
||||
request.setDescription(prePay.getDescription());
|
||||
request.setNotifyUrl(xcxProperties.getNotifyUrl());
|
||||
request.setOutTradeNo("HD1001" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_FORMATTER) + RandomUtil.randomInt(10000, 100000));
|
||||
request.setOutTradeNo(XCXUtil.payOutTradeNo(prePay.getStationCode()));
|
||||
// 金额
|
||||
Amount amount = new Amount();
|
||||
// amount.setTotal(prePay.getMoney());
|
||||
amount.setTotal(1);
|
||||
request.setAmount(amount);
|
||||
// 付款人
|
||||
Payer payer = new Payer();
|
||||
payer.setOpenid("ocEmP7fbW-QD6tbNpi7B665xJu2g");
|
||||
payer.setOpenid(wuser.getOpenid());
|
||||
request.setPayer(payer);
|
||||
// request.setDetail(detail);
|
||||
request.setTimeExpire(DateUtil.format(DateUtil.offsetHour(new Date(), 1), DatePattern.UTC_PATTERN));
|
||||
// 商品信息
|
||||
Detail detail = new Detail();
|
||||
detail.setCostPrice(prePay.getCostPrice());
|
||||
detail.setInvoiceId(prePay.getInvoiceId());
|
||||
List<GoodsDetail> goodsDetail = prePay.getGoodsDetail();
|
||||
if (goodsDetail != null && !goodsDetail.isEmpty()) {
|
||||
detail.setGoodsDetail(goodsDetail);
|
||||
preOrder.setGoodsDetail(JSONUtil.toJsonStr(goodsDetail));
|
||||
request.setDetail(detail);
|
||||
}
|
||||
|
||||
// 场景信息
|
||||
if (StringUtils.hasText(prePay.getPayerClientIp())) {
|
||||
SceneInfo si = new SceneInfo();
|
||||
si.setPayerClientIp(prePay.getPayerClientIp());
|
||||
si.setDeviceId(prePay.getDeviceId());
|
||||
request.setSceneInfo(si);
|
||||
preOrder.setPayerClientIp(prePay.getPayerClientIp());
|
||||
preOrder.setDeviceId(prePay.getDeviceId());
|
||||
}
|
||||
PrepayWithRequestPaymentResponse response = WechatPayUtil.jsapiPrepay(config, request);
|
||||
System.out.println("\r\n=====>>>>>" + response);
|
||||
// System.out.println("\r\n=====response>>>>>" + response);
|
||||
// 写表
|
||||
BeanUtils.copyProperties(request, preOrder);
|
||||
preOrder.setPrePayResponse(JSONUtil.toJsonStr(response));
|
||||
preOrder.setWuid(prePay.getWuid());
|
||||
preOrder.setTotal(amount.getTotal());
|
||||
preOrder.setOpenid(payer.getOpenid());
|
||||
preOrder.setCostPrice(prePay.getCostPrice());
|
||||
preOrder.setCtime(new Date());
|
||||
preOrderDao.insert(preOrder);
|
||||
|
||||
return new Result<String>().success(response);
|
||||
}
|
||||
|
||||
@ -75,7 +141,39 @@ public class WechatPayServiceImpl implements WechatPayService {
|
||||
* 用SDK中封装的NotificationParser解析器进行验签和解密
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<String> PrepayBack(String body, HttpServletRequest request) {
|
||||
public ResponseEntity<String> PrepayBack(HttpServletRequest request) {
|
||||
// 1. 验签解密
|
||||
Transaction transaction;
|
||||
try {
|
||||
transaction = decryptWechatPayNotify(request);
|
||||
} catch (Exception e) {
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("code", "FAIL");
|
||||
jo.set("message", "解析body异常");
|
||||
return new ResponseEntity<String>(jo.toJSONString(0), HttpStatus.FAILED_DEPENDENCY);
|
||||
}
|
||||
// 2. 业务处理逻辑
|
||||
wechatPayBussinessHandle(transaction);
|
||||
|
||||
// 3. 回复微信
|
||||
return new ResponseEntity<String>("", HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信支付回调 解密
|
||||
* @param request
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private Transaction decryptWechatPayNotify(HttpServletRequest request) throws IOException {
|
||||
String body = "";
|
||||
try {
|
||||
ServletInputStream inputStream = request.getInputStream();
|
||||
body = IOUtil.toString(inputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
// 1. 初始化解析器
|
||||
NotificationParser parser = new NotificationParser(config);
|
||||
// 2. 构造解析器所需参数
|
||||
@ -88,46 +186,64 @@ public class WechatPayServiceImpl implements WechatPayService {
|
||||
.signature(request.getHeader("Wechatpay-Signature"))
|
||||
// 时间戳
|
||||
.timestamp(request.getHeader("Wechatpay-Timestamp"))
|
||||
// 默认值为 WECHATPAY2-SHA256-RSA2048
|
||||
.signType(request.getHeader("Wechatpay-Signature-Type"))
|
||||
.body(body)
|
||||
.build();
|
||||
|
||||
// 3. 验签、解密,parse方法中包含2个方法,一个验签,一个解密
|
||||
Transaction transaction;
|
||||
try {
|
||||
transaction = parser.parse(param, Transaction.class);
|
||||
log.info("\r\n===>>>支付回调信息:" + JSONUtil.toJsonStr(transaction));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.set("code", "FAIL");
|
||||
jo.set("message", e.getMessage());
|
||||
return new ResponseEntity<String>(jo.toJSONString(0), HttpStatus.FAILED_DEPENDENCY);
|
||||
throw e;
|
||||
}
|
||||
// 4. 业务处理逻辑
|
||||
System.out.println("\r\n=====>>>>>" + JSONUtil.toJsonPrettyStr(transaction));
|
||||
if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
System.out.println(transaction.toString());
|
||||
// 支付成功,根据订单编号更新订单状态
|
||||
// 查询订单信息
|
||||
// Order orderOld = orderService.selectForUpdateByOrderNumber(transaction.getOutTradeNo());
|
||||
// 校验金额
|
||||
// if (0 == 0) {
|
||||
// // 金额相等 完成支付 更新订单状态
|
||||
//// WechatPayUtil.success(orderOld, transaction);
|
||||
// } else {
|
||||
// // 金额异常 执行退款
|
||||
//// WechatPayUtil.refunded(new WechatPayRedis(transaction.getOutTradeNo(), transaction.getAmount().getTotal(), null));
|
||||
// }
|
||||
} else {
|
||||
// 订单支付失败
|
||||
System.out.println(transaction.getTradeStateDesc());
|
||||
/**
|
||||
* 微信支付回调业务处理
|
||||
* @param transaction
|
||||
*/
|
||||
private void wechatPayBussinessHandle(Transaction transaction) {
|
||||
// 1. 生成交易信息
|
||||
TradeDetail tradeDetail = new TradeDetail();
|
||||
BeanUtils.copyProperties(transaction, tradeDetail);
|
||||
|
||||
WechatUser wuser = wechatUserDao.selectOne(new QueryWrapper<WechatUser>().eq("openid", transaction.getPayer().getOpenid()));
|
||||
if (wuser != null) {
|
||||
tradeDetail.setPayer(wuser.getWuid());
|
||||
} else {
|
||||
tradeDetail.setPayer(transaction.getPayer().getOpenid());
|
||||
}
|
||||
// 附加信息处理
|
||||
WechatPayAttach payAttach = JSONUtil.toBean(transaction.getAttach(), WechatPayAttach.class);
|
||||
tradeDetail.setTradeType(payAttach.getType());
|
||||
tradeDetail.setTrader(payAttach.getTrader());
|
||||
tradeDetail.setTraderCode(payAttach.getTraderCode());
|
||||
tradeDetail.setWallet(payAttach.getWalletCode());
|
||||
if (payAttach.getType() == 2) {
|
||||
tradeDetail.setOrderNo(payAttach.getOrderNo());
|
||||
tradeDetail.setOrderCount(payAttach.getOrderNo().split(",").length);
|
||||
}
|
||||
|
||||
return new ResponseEntity<String>("", HttpStatus.OK);
|
||||
// 发生异常
|
||||
tradeDetail.setTradeAmount(transaction.getAmount().getPayerTotal());
|
||||
|
||||
TradeTypeEnum tradePayType = transaction.getTradeType();
|
||||
if (tradePayType.equals(Transaction.TradeTypeEnum.JSAPI)) {
|
||||
tradeDetail.setPayType(21);
|
||||
}
|
||||
if (tradePayType.equals(Transaction.TradeTypeEnum.NATIVE)) {
|
||||
tradeDetail.setPayType(22);
|
||||
}
|
||||
|
||||
tradeDetail.setPayResult(transaction.getTradeState().name());
|
||||
tradeDetail.setPayMsg(transaction.getTradeStateDesc());
|
||||
tradeDetail.setPayTime(DateUtil.parseUTC(transaction.getSuccessTime()));
|
||||
|
||||
// 2. 处理订单,看要不要异步
|
||||
cloudService.wechatPayNotifyHandle(tradeDetail);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -169,7 +285,14 @@ public class WechatPayServiceImpl implements WechatPayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<String> refundsBack(String body, HttpServletRequest request) {
|
||||
public ResponseEntity<String> refundsBack(HttpServletRequest request) {
|
||||
String body = "";
|
||||
try {
|
||||
ServletInputStream inputStream = request.getInputStream();
|
||||
body = IOUtil.toString(inputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 1. 初始化解析器
|
||||
NotificationParser parser = new NotificationParser(config);
|
||||
// 2. 构造解析器所需参数
|
||||
|
||||
@ -1,16 +1,25 @@
|
||||
package com.evotech.hd.wechat.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.evotech.hd.common.core.constant.HDConstant;
|
||||
import com.evotech.hd.common.core.dao.wechat.WechatUserDao;
|
||||
import com.evotech.hd.common.core.entity.BasePageRequest;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccount;
|
||||
import com.evotech.hd.common.core.entity.cloud.WalletAccountDetail;
|
||||
import com.evotech.hd.common.core.entity.cloud.request.PageListWalletRequest;
|
||||
import com.evotech.hd.common.core.entity.wechat.WechatUser;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
import com.evotech.hd.wechat.service.CloudService;
|
||||
import com.evotech.hd.wechat.service.WechatUserService;
|
||||
|
||||
import cn.hutool.core.util.DesensitizedUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
|
||||
@Service
|
||||
@ -18,6 +27,8 @@ public class WechatUserServiceImpl implements WechatUserService {
|
||||
|
||||
@Resource
|
||||
private WechatUserDao wechatUserDao;
|
||||
@Resource
|
||||
private CloudService cloudService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -59,4 +70,35 @@ public class WechatUserServiceImpl implements WechatUserService {
|
||||
return new Result<Integer>().error("绑定出错!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Integer> openWallet(String wuid, HttpServletRequest request) {
|
||||
if (!wuid.equals(request.getHeader(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY))) {
|
||||
return new Result<Integer>().error("账号错误");
|
||||
}
|
||||
WalletAccount wa = new WalletAccount();
|
||||
wa.setOwnerType(1);
|
||||
wa.setOwnerId(wuid);
|
||||
Result<Integer> res = cloudService.addWallet(wa);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<List<WalletAccount>> listWallet(String wuid, HttpServletRequest request) {
|
||||
if (!wuid.equals(request.getHeader(HDConstant.WECHAT_SERVER_AUTHORIZATION_KEY))) {
|
||||
return new Result<List<WalletAccount>>().error("账号错误");
|
||||
}
|
||||
|
||||
return cloudService.listWallet(wuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<List<WalletAccountDetail>> listWalletDetail(String walletCode, BasePageRequest basePage) {
|
||||
PageListWalletRequest plwr = new PageListWalletRequest();
|
||||
plwr.setCode(walletCode);
|
||||
plwr.setPageSize(basePage.getPageSize());
|
||||
plwr.setPageNo(basePage.getPageNo());
|
||||
|
||||
return cloudService.listWalletDetail(plwr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
package com.evotech.hd.wechat.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.evotech.hd.wechat.service.AccessTokenService;
|
||||
import com.evotech.hd.wechat.service.XCXQRCodeService;
|
||||
import com.evotech.hd.wechat.utils.xcx.QRCodeUtil;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Service
|
||||
public class XCXQRCodeServiceImpl implements XCXQRCodeService {
|
||||
|
||||
|
||||
@Resource
|
||||
private AccessTokenService accessTokenService;
|
||||
|
||||
@Override
|
||||
public void getQRCode(String path, String width, String env_version, HttpServletResponse response) {
|
||||
byte[] res = QRCodeUtil.getQRCode(accessTokenService.getAccessToken(), path, width, env_version);
|
||||
String fileName = "小程序码" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + ".png";
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
try {
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
ServletOutputStream out = null;
|
||||
try {
|
||||
out = response.getOutputStream();
|
||||
out.write(res);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createQRCode(String path, String width, HttpServletResponse response) {
|
||||
byte[] res = QRCodeUtil.createQRCode(accessTokenService.getAccessToken(), path, width);
|
||||
String fileName = "小程序二维码" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + ".png";
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
try {
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
ServletOutputStream out = null;
|
||||
try {
|
||||
out = response.getOutputStream();
|
||||
out.write(res);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQRCode2(String path, String width, String env_version) {
|
||||
byte[] res = QRCodeUtil.getQRCode(accessTokenService.getAccessToken(), path, width, env_version);
|
||||
return Base64.getEncoder().encodeToString(res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createQRCode2(String path, String width) {
|
||||
byte[] res = QRCodeUtil.createQRCode(accessTokenService.getAccessToken(), path, width);
|
||||
return Base64.getEncoder().encodeToString(res);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.evotech.hd.wechat.utils.gzh;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
|
||||
public class OpenId2UnionIdUtil {
|
||||
|
||||
private static String gzhUserInfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=";
|
||||
|
||||
|
||||
/**
|
||||
*获取用户基本信息(UnionID机制) GET
|
||||
* @param accessToken
|
||||
* @param openid
|
||||
* @return
|
||||
*/
|
||||
public static String gzhUserInfo(String accessToken, String openid) {
|
||||
Map<String, Object> m = new HashMap<String, Object>();
|
||||
m.put("openid", openid);
|
||||
m.put("lang", "zh_CN");
|
||||
String res = HttpUtil.get(gzhUserInfoUrl + accessToken, m);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.evotech.hd.wechat.utils.gzh;
|
||||
|
||||
import com.evotech.hd.wechat.entity.gzh.templatemessage.MessageTemplateSendData;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
public class TemplateMessageUtil {
|
||||
|
||||
|
||||
private static String templateSendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
|
||||
|
||||
|
||||
/**
|
||||
* 发送模板消息 POST
|
||||
* @param accessToken
|
||||
* @param templateData
|
||||
* @return
|
||||
*/
|
||||
public static String templateMessageSend(String accessToken, MessageTemplateSendData templateData) {
|
||||
String body = JSONUtil.toJsonStr(templateData);
|
||||
String res = HttpRequest.post(templateSendUrl + accessToken)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(body)
|
||||
.execute()
|
||||
.body();
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.evotech.hd.wechat.utils.xcx;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
public class QRCodeUtil {
|
||||
|
||||
private static String getQRCodeUrl = "https://api.weixin.qq.com/wxa/getwxacode?access_token=";
|
||||
private static String createQRCodeUrl = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=";
|
||||
|
||||
/**
|
||||
* 获取小程序码
|
||||
* POST
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
public static byte[] getQRCode(String access_token, String path, String width, String env_version) {
|
||||
Map<String, Object> m = new HashMap<String, Object>();
|
||||
m.put("path", path);
|
||||
m.put("width", StringUtils.hasText(width)?width:"1280");
|
||||
m.put("env_version", env_version);
|
||||
|
||||
HttpResponse response = HttpRequest.post(getQRCodeUrl + access_token).body(JSONUtil.toJsonStr(m)).execute();
|
||||
byte[] bodyBytes = response.bodyBytes();
|
||||
// HttpRequest.post(getQRCodeUrl + access_token).body(JSONUtil.toJsonStr(m)).execute().bodyBytes();
|
||||
if (bodyBytes == null) {
|
||||
throw new RuntimeException("获取小程序码异常:" + response.body());
|
||||
}
|
||||
if (bodyBytes.length < 200) {
|
||||
throw new RuntimeException("获取小程序码失败!");
|
||||
}
|
||||
|
||||
return bodyBytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取小程序二维码
|
||||
* POST
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
public static byte[] createQRCode(String access_token, String path, String width) {
|
||||
Map<String, Object> m = new HashMap<String, Object>();
|
||||
m.put("path", path);
|
||||
m.put("width", StringUtils.hasText(width)?width:"1280");
|
||||
HttpResponse response = HttpRequest.post(createQRCodeUrl + access_token).body(JSONUtil.toJsonStr(m)).execute();
|
||||
byte[] bodyBytes = response.bodyBytes();
|
||||
// HttpRequest.post(getQRCodeUrl + access_token).body(JSONUtil.toJsonStr(m)).execute().bodyBytes();
|
||||
if (bodyBytes == null) {
|
||||
throw new RuntimeException("获取小程序二维码异常:" + response.body());
|
||||
}
|
||||
if (bodyBytes.length < 200) {
|
||||
throw new RuntimeException("获取小程序二维码失败!");
|
||||
}
|
||||
return bodyBytes;
|
||||
}
|
||||
|
||||
}
|
||||
@ -38,5 +38,50 @@
|
||||
"name": "hbyt.xcx.refund_notify_url",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.xcx.refund_notify_url'"
|
||||
},
|
||||
{
|
||||
"name": "hbyt.xcx.token_exp_hour",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.xcx.token_exp_hour'"
|
||||
},
|
||||
{
|
||||
"name": "hbyt.gzh.appid",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.gzh.appid'"
|
||||
},
|
||||
{
|
||||
"name": "hbyt.gzh.app-secret",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.gzh.app-secret'"
|
||||
},
|
||||
{
|
||||
"name": "hbyt.gzh.pre_order_template_id",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.gzh.pre_order_template_id'"
|
||||
},
|
||||
{
|
||||
"name": "hbyt.gzh.order_start_template_id",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.gzh.order_start_template_id'"
|
||||
},
|
||||
{
|
||||
"name": "hbyt.gzh.order_swap_end_template_id",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.gzh.order_swap_end_template_id'"
|
||||
},
|
||||
{
|
||||
"name": "hbyt.gzh.order_to_pay_template_id",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.gzh.order_to_pay_template_id'"
|
||||
},
|
||||
{
|
||||
"name": "hbyt.gzh.order_end_template_id",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.gzh.order_end_template_id'"
|
||||
},
|
||||
{
|
||||
"name": "hbyt.gzh.encodingAESKey",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'hbyt.gzh.encodingAESKey'"
|
||||
}
|
||||
]}
|
||||
@ -44,6 +44,7 @@ management:
|
||||
|
||||
# 微信
|
||||
hbyt:
|
||||
# 小程序
|
||||
xcx:
|
||||
appid: wx2ab384cf1e6f85a1
|
||||
app-secret: 6c55a398703529358eac398e2bc89ae2
|
||||
@ -56,3 +57,17 @@ hbyt:
|
||||
notify_url: https://api.evo-techina.com/wechat/wechatpay/prepayback/msg
|
||||
# 退款回调地址
|
||||
refund_notify_url: https://api.evo-techina.com/wechat/wechatpay/refundsback/msg
|
||||
# token缓存时效:小时
|
||||
token_exp_hour: 2
|
||||
# 公众号
|
||||
gzh:
|
||||
appid: wx268e32962db19f5f
|
||||
app-secret: 84a6065165ec82862c5e03a010a6dc6c
|
||||
token: r7YASMj3S9vCeeyJPpKeFPR9drhFaSDt
|
||||
encodingAESKey: W3zDuKYFMUlYUXpT4AhRSPkqMS7CgcmnEVQ3enVcTtf
|
||||
pre_order_template_id: 4eknqqZhEqW7_3xSYLskvPUX193irbalhdHjOSY88-g
|
||||
order_start_template_id: L_AsG7s7DOyyz4dXLb8gIi7h4Sy__ifEAL1Mo8gAw4E
|
||||
order_swap_end_template_id: wGll5W3NSHXkHjcEprjUbd1shigGOqywGX7A0BVnzUs
|
||||
order_to_pay_template_id: IE0_RGuN5ufU4GFrCgM9JeUfvlWfbneEuUMDsn0RBQs
|
||||
order_end_template_id: C5-AGh67aFXChQONqSwxaRrJgFrn_Z25VTlTk0jHSUY
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEFDCCAvygAwIBAgIULPZxoLWZRezfaOdWDXnN1oNQGvUwDQYJKoZIhvcNAQEL
|
||||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
|
||||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
|
||||
Q0EwHhcNMjQxMDIxMDIzMzI5WhcNMjkxMDIwMDIzMzI5WjBuMRgwFgYDVQQDDA9U
|
||||
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl
|
||||
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGEwJDTjERMA8GA1UEBwwIU2hlblpo
|
||||
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIsrKwNh8t+mysE46b
|
||||
joB8yqSy+4sL+mfqvc+9bSIbwv5pi2ESwKch73wHObXS1rK3PEt4o+3gF3yNtBWh
|
||||
/IuOFXysZOFySnlw8ii87mIXp5AMQwxUdfvnI/kUuhveLOsDAC8E6uAV1uPFJD2q
|
||||
4uh0MyohwxHSA8V66V0caeoEDj80zW5V0ArV+EWw1/WW/bL2IWHfZ02xPWDCHxYT
|
||||
4XmMtDn7U/gndg8QTOTI+2iPKaUoN12GeBLEuoq3Ot93jgpdh3KVYReSWpNWZ9mT
|
||||
d3wL84DoI+V9IpAfEPOUq9zTdMB5MEr1ZtmxlcbZWhc++upGz10sv46NDnJ1YZBs
|
||||
gs/pAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB
|
||||
kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv
|
||||
aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4
|
||||
RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0
|
||||
MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEACiuWYNkqA2bZPV5EOE8aFXXCFiU8I/sa
|
||||
lNn7qWE42n2qf1BspTihFU2xZhDA8tqcBkQcw2W+quOMNv3Di43jXBFS9d/PI1o0
|
||||
+Pt/UePgpDVLyaZXl1i8Bo739XCVnG7MSB6++TbRnIFZLDp1WXn+jR2OUvQbUsyN
|
||||
pdZr578juOmXCkeZewXtHuhd/zR4iCVD05miB11msIuH0F3f8DD4y6W8hxCEjuE0
|
||||
WV68UT+D90dIFjOQmraRNH9Os9FYRvJ1QwcYvDjPQF4KuyvWM5vC4j/FOR91vg/Q
|
||||
gxKzttDmA7RW/C27HUgNh83bytJsPPkRiUxKmhbHnwgWwa/FdPsmPg==
|
||||
-----END CERTIFICATE-----
|
||||
Loading…
Reference in New Issue
Block a user