Commit aa4d9869dfcee6af8eaf4a0e337f2d0ff84372a8
1 parent
7d925fdd
feat mall user info
Showing
28 changed files
with
936 additions
and
24 deletions
cashier-mall/src/main/java/com/diligrp/cashier/mall/MallConstants.java
| 1 | package com.diligrp.cashier.mall; | 1 | package com.diligrp.cashier.mall; |
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | +/** | ||
| 5 | + * 商城常量 | ||
| 6 | + */ | ||
| 4 | public interface MallConstants { | 7 | public interface MallConstants { |
| 5 | String RESULT_SUCCESS = "success"; | 8 | String RESULT_SUCCESS = "success"; |
| 6 | String RESULT_FAILURE = "fail"; | 9 | String RESULT_FAILURE = "fail"; |
| 7 | 10 | ||
| 8 | Integer RT_MALL_SOURCE = 1; | 11 | Integer RT_MALL_SOURCE = 1; |
| 12 | + | ||
| 13 | + String MALL_TOKEN = "mall_token:"; | ||
| 14 | + String MALL_USER_INFO = "mall_user_info:"; | ||
| 9 | } | 15 | } |
cashier-mall/src/main/java/com/diligrp/cashier/mall/api/MallAuthApi.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.api; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.mall.MallConstants; | ||
| 4 | +import com.diligrp.cashier.mall.context.MallInitializeContext; | ||
| 5 | +import com.diligrp.cashier.mall.domain.rtmall.RtMarkMessage; | ||
| 6 | +import com.diligrp.cashier.mall.domain.rtmall.co.AuthLoginCO; | ||
| 7 | +import com.diligrp.cashier.mall.domain.rtmall.co.UserInfoCO; | ||
| 8 | +import com.diligrp.cashier.mall.domain.rtmall.vo.UserInfoVO; | ||
| 9 | +import com.diligrp.cashier.mall.sign.RtMallSign; | ||
| 10 | +import com.diligrp.cashier.shared.annotation.ParamLogPrint; | ||
| 11 | +import com.diligrp.cashier.shared.annotation.Sign; | ||
| 12 | +import com.diligrp.cashier.shared.domain.Message; | ||
| 13 | +import com.diligrp.cashier.shared.util.JsonUtils; | ||
| 14 | +import jakarta.annotation.Resource; | ||
| 15 | +import jakarta.validation.Valid; | ||
| 16 | +import org.slf4j.Logger; | ||
| 17 | +import org.slf4j.LoggerFactory; | ||
| 18 | +import org.springframework.data.redis.core.RedisTemplate; | ||
| 19 | +import org.springframework.validation.annotation.Validated; | ||
| 20 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 21 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 22 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 23 | +import org.springframework.web.bind.annotation.RestController; | ||
| 24 | + | ||
| 25 | +import java.util.Objects; | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * @ClassName MallAuthApi.java | ||
| 29 | + * @author dengwei | ||
| 30 | + * @version 1.0.0 | ||
| 31 | + * @Description MallAuthApi | ||
| 32 | + */ | ||
| 33 | +@RestController | ||
| 34 | +@RequestMapping("/mall") | ||
| 35 | +@Validated | ||
| 36 | +public class MallAuthApi { | ||
| 37 | + private static final Logger log = LoggerFactory.getLogger(MallAuthApi.class); | ||
| 38 | + @Resource | ||
| 39 | + private RedisTemplate<String, Object> redisTemplate; | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 获取授权连接 | ||
| 43 | + */ | ||
| 44 | + @PostMapping("/auth") | ||
| 45 | + @ParamLogPrint(outPrint = true) | ||
| 46 | + public Message<String> authLogin(@RequestBody @Valid AuthLoginCO authLogin) { | ||
| 47 | + return Message.success(MallInitializeContext.getByChannel(authLogin.getChannel()).authLogin(authLogin)); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 获取用户信息 | ||
| 52 | + */ | ||
| 53 | + @PostMapping("/user/info") | ||
| 54 | + @ParamLogPrint(outPrint = true) | ||
| 55 | + @Sign(sign = RtMallSign.class) | ||
| 56 | + public RtMarkMessage<UserInfoVO> userInfo(@RequestBody @Valid Object req) { | ||
| 57 | + UserInfoCO userInfo = JsonUtils.convertValue(req, UserInfoCO.class); | ||
| 58 | + AuthLoginCO authLogin = JsonUtils.fromJsonString(Objects.requireNonNull(redisTemplate.opsForValue().get(MallConstants.MALL_TOKEN + userInfo.getToken())).toString(), AuthLoginCO.class); | ||
| 59 | + UserInfoVO userInfoVO = MallInitializeContext.getByChannel(authLogin.getChannel()).userInfo(authLogin); | ||
| 60 | + return RtMarkMessage.success(userInfoVO); | ||
| 61 | + } | ||
| 62 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/context/MallInitializeContext.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.context; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.mall.exception.MallException; | ||
| 4 | +import com.diligrp.cashier.mall.service.paychannel.AbstractPayChannel; | ||
| 5 | +import com.diligrp.cashier.mall.service.sourcechannel.AbstractChannel; | ||
| 6 | +import com.diligrp.cashier.shared.util.SpringContextUtils; | ||
| 7 | +import com.google.common.collect.Maps; | ||
| 8 | +import org.slf4j.Logger; | ||
| 9 | +import org.slf4j.LoggerFactory; | ||
| 10 | +import org.springframework.beans.factory.DisposableBean; | ||
| 11 | +import org.springframework.beans.factory.InitializingBean; | ||
| 12 | +import org.springframework.stereotype.Component; | ||
| 13 | + | ||
| 14 | +import java.util.Map; | ||
| 15 | +import java.util.Optional; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * @author dengwei | ||
| 19 | + * @version 1.0.0 | ||
| 20 | + * @ClassName MallInitializeContext.java | ||
| 21 | + * @Description MallInitializeContext | ||
| 22 | + */ | ||
| 23 | +@Component | ||
| 24 | +public class MallInitializeContext implements InitializingBean, DisposableBean { | ||
| 25 | + private static final Logger log = LoggerFactory.getLogger(MallInitializeContext.class); | ||
| 26 | + public static Map<String, AbstractChannel> SOURCE_CHANNEL_MAP = Maps.newConcurrentMap(); | ||
| 27 | + public static Map<Integer, AbstractPayChannel> PAY_CHANNEL_MAP = Maps.newConcurrentMap(); | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 容器启动完成加载 | ||
| 31 | + */ | ||
| 32 | + @Override | ||
| 33 | + public void afterPropertiesSet() throws Exception { | ||
| 34 | + SpringContextUtils.getBeanOfTpe(AbstractChannel.class).forEach((key, value) -> { | ||
| 35 | + SOURCE_CHANNEL_MAP.put(value.channel(), value); | ||
| 36 | + }); | ||
| 37 | + | ||
| 38 | + SpringContextUtils.getBeanOfTpe(AbstractPayChannel.class).forEach((key, value) -> { | ||
| 39 | + PAY_CHANNEL_MAP.put(value.getPayChannel(), value); | ||
| 40 | + }); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 容器销毁加载 | ||
| 45 | + */ | ||
| 46 | + @Override | ||
| 47 | + public void destroy() throws Exception { | ||
| 48 | + log.info("spring container destroy"); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * getByType | ||
| 53 | + */ | ||
| 54 | + public static AbstractChannel getByChannel(String channel) { | ||
| 55 | + return Optional.ofNullable(SOURCE_CHANNEL_MAP.get(channel)).orElseThrow(() -> new MallException("不支持该渠道!")); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * getByPayChannel | ||
| 60 | + */ | ||
| 61 | + public static AbstractPayChannel getByPayChannel(Integer payChannel) { | ||
| 62 | + return Optional.ofNullable(PAY_CHANNEL_MAP.get(payChannel)).orElseThrow(() -> new MallException("不支持该渠道!")); | ||
| 63 | + } | ||
| 64 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/domain/rtmall/RtMarkBaseCO.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.domain.rtmall; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
| 4 | +import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * @ClassName RtMarkBaseCO.java | ||
| 8 | + * @author dengwei | ||
| 9 | + * @version 1.0.0 | ||
| 10 | + * @Description RtMarkBaseCO | ||
| 11 | + * @date 2025-12-25 16:26 | ||
| 12 | + */ | ||
| 13 | +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
| 14 | +public class RtMarkBaseCO { | ||
| 15 | + private String appKey; | ||
| 16 | + private String version; | ||
| 17 | + private String timestamp; | ||
| 18 | + private String nonceStr; | ||
| 19 | + private String sign; | ||
| 20 | + | ||
| 21 | + public String getAppKey() { | ||
| 22 | + return appKey; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public void setAppKey(String appKey) { | ||
| 26 | + this.appKey = appKey; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public String getVersion() { | ||
| 30 | + return version; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public void setVersion(String version) { | ||
| 34 | + this.version = version; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public String getTimestamp() { | ||
| 38 | + return timestamp; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public void setTimestamp(String timestamp) { | ||
| 42 | + this.timestamp = timestamp; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public String getNonceStr() { | ||
| 46 | + return nonceStr; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public void setNonceStr(String nonceStr) { | ||
| 50 | + this.nonceStr = nonceStr; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public String getSign() { | ||
| 54 | + return sign; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public void setSign(String sign) { | ||
| 58 | + this.sign = sign; | ||
| 59 | + } | ||
| 60 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/domain/RtMarkMessage.java renamed to cashier-mall/src/main/java/com/diligrp/cashier/mall/domain/rtmall/RtMarkMessage.java
| 1 | -package com.diligrp.cashier.mall.domain; | 1 | +package com.diligrp.cashier.mall.domain.rtmall; |
| 2 | 2 | ||
| 3 | import com.diligrp.cashier.mall.MallConstants; | 3 | import com.diligrp.cashier.mall.MallConstants; |
| 4 | import com.diligrp.cashier.mall.type.RtMarkErrorCode; | 4 | import com.diligrp.cashier.mall.type.RtMarkErrorCode; |
cashier-mall/src/main/java/com/diligrp/cashier/mall/domain/rtmall/co/AuthLoginCO.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.domain.rtmall.co; | ||
| 2 | + | ||
| 3 | +import jakarta.validation.constraints.NotBlank; | ||
| 4 | +import jakarta.validation.constraints.NotNull; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * @ClassName AuthLoginCO.java | ||
| 8 | + * @author dengwei | ||
| 9 | + * @version 1.0.0 | ||
| 10 | + * @Description AuthLoginCO | ||
| 11 | + * @date 2025-12-25 10:55 | ||
| 12 | + */ | ||
| 13 | +public class AuthLoginCO { | ||
| 14 | + /** | ||
| 15 | + * 用户编号 | ||
| 16 | + */ | ||
| 17 | + @NotBlank(message = "用户编号不能为空!") | ||
| 18 | + private String userCode; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 用户名 | ||
| 22 | + */ | ||
| 23 | + @NotBlank(message = "用户名称不能为空!") | ||
| 24 | + private String username; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 渠道-中瑞 地利 | ||
| 28 | + * @see com.diligrp.cashier.mall.type.OrderChannel | ||
| 29 | + */ | ||
| 30 | + @NotBlank(message = "渠道不能为空!") | ||
| 31 | + private String channel; | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 商户编号 | ||
| 35 | + */ | ||
| 36 | + @NotBlank(message = "商户编号不能为空!") | ||
| 37 | + private String mchId; | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * 订单来源(1大润发 2山姆) | ||
| 41 | + * @see com.diligrp.cashier.mall.type.OrderSource | ||
| 42 | + */ | ||
| 43 | + @NotNull(message = "订单来源不能为空!") | ||
| 44 | + private Integer source; | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 订单类型-1线下扫码购,2 接口扫码购,3小程序 | ||
| 48 | + * @see com.diligrp.cashier.mall.type.OrderType | ||
| 49 | + */ | ||
| 50 | + @NotNull(message = "订单类型不能为空!") | ||
| 51 | + private Integer orderType; | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * 联系电话 | ||
| 55 | + */ | ||
| 56 | + private String mobile; | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * 经度 | ||
| 60 | + */ | ||
| 61 | + private String longitude; | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * 纬度 | ||
| 65 | + */ | ||
| 66 | + private String latitude; | ||
| 67 | + | ||
| 68 | + public String getLatitude() { | ||
| 69 | + return latitude; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + public void setLatitude(String latitude) { | ||
| 73 | + this.latitude = latitude; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + public String getLongitude() { | ||
| 77 | + return longitude; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + public void setLongitude(String longitude) { | ||
| 81 | + this.longitude = longitude; | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + public Integer getOrderType() { | ||
| 85 | + return orderType; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + public void setOrderType(Integer orderType) { | ||
| 89 | + this.orderType = orderType; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + public String getMobile() { | ||
| 93 | + return mobile; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + public void setMobile(String mobile) { | ||
| 97 | + this.mobile = mobile; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + public Integer getSource() { | ||
| 101 | + return source; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + public void setSource(Integer source) { | ||
| 105 | + this.source = source; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + public String getMchId() { | ||
| 109 | + return mchId; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + public void setMchId(String mchId) { | ||
| 113 | + this.mchId = mchId; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + public String getChannel() { | ||
| 117 | + return channel; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + public void setChannel(String channel) { | ||
| 121 | + this.channel = channel; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + public String getUserCode() { | ||
| 125 | + return userCode; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + public void setUserCode(String userCode) { | ||
| 129 | + this.userCode = userCode; | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + public String getUsername() { | ||
| 133 | + return username; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + public void setUsername(String username) { | ||
| 137 | + this.username = username; | ||
| 138 | + } | ||
| 139 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/domain/rtmall/co/UserInfoCO.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.domain.rtmall.co; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.mall.domain.rtmall.RtMarkBaseCO; | ||
| 4 | +import com.diligrp.cashier.shared.jackson.deserializer.SecondToDateDeserializer; | ||
| 5 | +import com.diligrp.cashier.shared.jackson.serialization.DateToSecondSerializer; | ||
| 6 | +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | ||
| 7 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
| 8 | +import jakarta.validation.constraints.NotBlank; | ||
| 9 | + | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * @ClassName UserInfoCO.java | ||
| 14 | + * @author dengwei | ||
| 15 | + * @version 1.0.0 | ||
| 16 | + * @Description UserInfoCO | ||
| 17 | + * @date 2025-12-25 16:28 | ||
| 18 | + */ | ||
| 19 | +public class UserInfoCO extends RtMarkBaseCO { | ||
| 20 | + @NotBlank(message = "token不能为空!") | ||
| 21 | + private String token; | ||
| 22 | + | ||
| 23 | + @JsonSerialize(using = DateToSecondSerializer.class) | ||
| 24 | + @JsonDeserialize(using = SecondToDateDeserializer.class) | ||
| 25 | + private LocalDateTime createTime; | ||
| 26 | + | ||
| 27 | + public String getToken() { | ||
| 28 | + return token; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public void setToken(String token) { | ||
| 32 | + this.token = token; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public LocalDateTime getCreateTime() { | ||
| 36 | + return createTime; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public void setCreateTime(LocalDateTime createTime) { | ||
| 40 | + this.createTime = createTime; | ||
| 41 | + } | ||
| 42 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/domain/rtmall/vo/UserInfoVO.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.domain.rtmall.vo; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
| 4 | +import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * @ClassName UserInfoVO.java | ||
| 8 | + * @author dengwei | ||
| 9 | + * @version 1.0.0 | ||
| 10 | + * @Description UserInfoVO | ||
| 11 | + * @date 2025-12-25 16:31 | ||
| 12 | + */ | ||
| 13 | +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
| 14 | +public class UserInfoVO { | ||
| 15 | + private String userCode; | ||
| 16 | + private String mobile; | ||
| 17 | + private String userName; | ||
| 18 | + private String companyCode; | ||
| 19 | + | ||
| 20 | + public String getUserCode() { | ||
| 21 | + return userCode; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + public void setUserCode(String userCode) { | ||
| 25 | + this.userCode = userCode; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + public String getMobile() { | ||
| 29 | + return mobile; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public void setMobile(String mobile) { | ||
| 33 | + this.mobile = mobile; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public String getUserName() { | ||
| 37 | + return userName; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public void setUserName(String userName) { | ||
| 41 | + this.userName = userName; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + public String getCompanyCode() { | ||
| 45 | + return companyCode; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + public void setCompanyCode(String companyCode) { | ||
| 49 | + this.companyCode = companyCode; | ||
| 50 | + } | ||
| 51 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/exception/MallExceptionHandler.java
| 1 | package com.diligrp.cashier.mall.exception; | 1 | package com.diligrp.cashier.mall.exception; |
| 2 | 2 | ||
| 3 | -import com.diligrp.cashier.mall.domain.RtMarkMessage; | 3 | +import com.diligrp.cashier.mall.domain.rtmall.RtMarkMessage; |
| 4 | import org.slf4j.Logger; | 4 | import org.slf4j.Logger; |
| 5 | import org.slf4j.LoggerFactory; | 5 | import org.slf4j.LoggerFactory; |
| 6 | import org.springframework.core.annotation.Order; | 6 | import org.springframework.core.annotation.Order; |
cashier-mall/src/main/java/com/diligrp/cashier/mall/property/MallDynamicProperty.java renamed to cashier-mall/src/main/java/com/diligrp/cashier/mall/property/RtMallDynamicProperty.java
| @@ -17,8 +17,8 @@ import java.util.Optional; | @@ -17,8 +17,8 @@ import java.util.Optional; | ||
| 17 | */ | 17 | */ |
| 18 | @Configuration | 18 | @Configuration |
| 19 | @RefreshScope | 19 | @RefreshScope |
| 20 | -@ConfigurationProperties(prefix = "sign") | ||
| 21 | -public class MallDynamicProperty { | 20 | +@ConfigurationProperties(prefix = "rtmall.sign") |
| 21 | +public class RtMallDynamicProperty { | ||
| 22 | 22 | ||
| 23 | private List<AppSecretDynamicProperty> appSecrets; | 23 | private List<AppSecretDynamicProperty> appSecrets; |
| 24 | 24 | ||
| @@ -26,12 +26,18 @@ public class MallDynamicProperty { | @@ -26,12 +26,18 @@ public class MallDynamicProperty { | ||
| 26 | @Value("${source:1}") | 26 | @Value("${source:1}") |
| 27 | private Integer source; | 27 | private Integer source; |
| 28 | 28 | ||
| 29 | + @Value("${orderType:3}") | ||
| 30 | + private Integer orderType; | ||
| 31 | + | ||
| 29 | @Value("${appKey:}") | 32 | @Value("${appKey:}") |
| 30 | private String appKey; | 33 | private String appKey; |
| 31 | 34 | ||
| 32 | @Value("${appSecret:}") | 35 | @Value("${appSecret:}") |
| 33 | private String appSecret; | 36 | private String appSecret; |
| 34 | 37 | ||
| 38 | + @Value("${companyCode:}") | ||
| 39 | + private String companyCode; | ||
| 40 | + | ||
| 35 | @Value("${authUrl:https://hourh5-em-shop.feiniugo.com}") | 41 | @Value("${authUrl:https://hourh5-em-shop.feiniugo.com}") |
| 36 | private String authUrl; | 42 | private String authUrl; |
| 37 | 43 | ||
| @@ -66,6 +72,22 @@ public class MallDynamicProperty { | @@ -66,6 +72,22 @@ public class MallDynamicProperty { | ||
| 66 | public void setAuthUrl(String authUrl) { | 72 | public void setAuthUrl(String authUrl) { |
| 67 | this.authUrl = authUrl; | 73 | this.authUrl = authUrl; |
| 68 | } | 74 | } |
| 75 | + | ||
| 76 | + public Integer getOrderType() { | ||
| 77 | + return orderType; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + public void setOrderType(Integer orderType) { | ||
| 81 | + this.orderType = orderType; | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + public String getCompanyCode() { | ||
| 85 | + return companyCode; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + public void setCompanyCode(String companyCode) { | ||
| 89 | + this.companyCode = companyCode; | ||
| 90 | + } | ||
| 69 | } | 91 | } |
| 70 | 92 | ||
| 71 | public List<AppSecretDynamicProperty> getAppSecrets() { | 93 | public List<AppSecretDynamicProperty> getAppSecrets() { |
| @@ -88,4 +110,30 @@ public class MallDynamicProperty { | @@ -88,4 +110,30 @@ public class MallDynamicProperty { | ||
| 88 | .findFirst() | 110 | .findFirst() |
| 89 | .orElse(null); | 111 | .orElse(null); |
| 90 | } | 112 | } |
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * getBySource | ||
| 116 | + * | ||
| 117 | + */ | ||
| 118 | + public AppSecretDynamicProperty getBySourceAndType(Integer source, Integer orderType) { | ||
| 119 | + return Optional.ofNullable(appSecrets) | ||
| 120 | + .orElse(Collections.emptyList()) | ||
| 121 | + .stream() | ||
| 122 | + .filter(item -> item.getSource().equals(source) && item.getOrderType().equals(orderType)) | ||
| 123 | + .findFirst() | ||
| 124 | + .orElse(null); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + /** | ||
| 128 | + * getBySource | ||
| 129 | + * | ||
| 130 | + */ | ||
| 131 | + public AppSecretDynamicProperty getByAppKey(String appKey) { | ||
| 132 | + return Optional.ofNullable(appSecrets) | ||
| 133 | + .orElse(Collections.emptyList()) | ||
| 134 | + .stream() | ||
| 135 | + .filter(item -> item.getAppKey().equals(appKey)) | ||
| 136 | + .findFirst() | ||
| 137 | + .orElse(null); | ||
| 138 | + } | ||
| 91 | } | 139 | } |
cashier-mall/src/main/java/com/diligrp/cashier/mall/service/paychannel/AbstractPayChannel.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.service.paychannel; | ||
| 2 | + | ||
| 3 | +import org.slf4j.Logger; | ||
| 4 | +import org.slf4j.LoggerFactory; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * @ClassName AbstractPayChannel.java | ||
| 8 | + * @author dengwei | ||
| 9 | + * @version 1.0.0 | ||
| 10 | + * @Description AbstractPayChannel | ||
| 11 | + * @date 2025-12-25 17:07 | ||
| 12 | + */ | ||
| 13 | +public abstract class AbstractPayChannel { | ||
| 14 | + protected final Logger log = LoggerFactory.getLogger(getClass()); | ||
| 15 | + | ||
| 16 | + public abstract Integer getPayChannel(); | ||
| 17 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/service/paychannel/CardPayChannel.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.service.paychannel; | ||
| 2 | + | ||
| 3 | +import org.springframework.stereotype.Component; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @ClassName CardPayChannel.java | ||
| 7 | + * @author dengwei | ||
| 8 | + * @version 1.0.0 | ||
| 9 | + * @Description CardPayChannel | ||
| 10 | + * @date 2025-12-25 17:08 | ||
| 11 | + */ | ||
| 12 | +@Component | ||
| 13 | +public class CardPayChannel extends AbstractPayChannel { | ||
| 14 | + @Override | ||
| 15 | + public Integer getPayChannel() { | ||
| 16 | + return 0; | ||
| 17 | + } | ||
| 18 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/service/paychannel/WeChatPayChannel.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.service.paychannel; | ||
| 2 | + | ||
| 3 | +import org.springframework.stereotype.Component; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @ClassName WeChatPayChannel.java | ||
| 7 | + * @author dengwei | ||
| 8 | + * @version 1.0.0 | ||
| 9 | + * @Description WeChatPayChannel | ||
| 10 | + * @date 2025-12-25 17:08 | ||
| 11 | + */ | ||
| 12 | +@Component | ||
| 13 | +public class WeChatPayChannel extends AbstractPayChannel { | ||
| 14 | + @Override | ||
| 15 | + public Integer getPayChannel() { | ||
| 16 | + return 1; | ||
| 17 | + } | ||
| 18 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/service/sourcechannel/AbstractChannel.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.service.sourcechannel; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.IdUtil; | ||
| 4 | +import com.diligrp.cashier.mall.MallConstants; | ||
| 5 | +import com.diligrp.cashier.mall.domain.rtmall.co.AuthLoginCO; | ||
| 6 | +import com.diligrp.cashier.mall.domain.rtmall.vo.UserInfoVO; | ||
| 7 | +import com.diligrp.cashier.mall.property.RtMallDynamicProperty; | ||
| 8 | +import com.diligrp.cashier.shared.util.DateUtils; | ||
| 9 | +import com.diligrp.cashier.shared.util.JsonUtils; | ||
| 10 | +import jakarta.annotation.Resource; | ||
| 11 | +import org.slf4j.Logger; | ||
| 12 | +import org.slf4j.LoggerFactory; | ||
| 13 | +import org.springframework.data.redis.core.RedisTemplate; | ||
| 14 | + | ||
| 15 | +import java.util.concurrent.TimeUnit; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * @ClassName AbstractChannel.java | ||
| 19 | + * @author dengwei | ||
| 20 | + * @version 1.0.0 | ||
| 21 | + * @Description AbstractChannel | ||
| 22 | + * @date 2025-12-25 11:19 | ||
| 23 | + */ | ||
| 24 | +public abstract class AbstractChannel { | ||
| 25 | + private static final Logger log = LoggerFactory.getLogger(AbstractChannel.class); | ||
| 26 | + | ||
| 27 | + @Resource | ||
| 28 | + protected RtMallDynamicProperty rtMallDynamicProperty; | ||
| 29 | + @Resource | ||
| 30 | + protected RedisTemplate<String, Object> redisTemplate; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * authLogin | ||
| 34 | + */ | ||
| 35 | + public String authLogin(AuthLoginCO authLogin) { | ||
| 36 | + String token = IdUtil.fastSimpleUUID(); | ||
| 37 | + long timestamp = DateUtils.timestampInSeconds(); | ||
| 38 | + | ||
| 39 | + String authUrl = authUrl(authLogin, token, timestamp); | ||
| 40 | + | ||
| 41 | + // token 缓存 | ||
| 42 | + String tokenKey = MallConstants.MALL_TOKEN + token; | ||
| 43 | + redisTemplate.opsForValue().set(tokenKey, JsonUtils.toJsonString(authLogin), 1, TimeUnit.DAYS); | ||
| 44 | + | ||
| 45 | + // 用户信息缓存 中瑞、dili是独立系统部署 可能存在相同用户id 所以需要加上渠道 | ||
| 46 | + String userKey = MallConstants.MALL_USER_INFO + authLogin.getUserCode() + "_" + authLogin.getChannel(); | ||
| 47 | + redisTemplate.opsForValue().set(userKey, JsonUtils.toJsonString(authLogin), 1, TimeUnit.DAYS); | ||
| 48 | + return authUrl; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * userInfo | ||
| 53 | + * | ||
| 54 | + */ | ||
| 55 | + public UserInfoVO userInfo(AuthLoginCO authLogin) { | ||
| 56 | + RtMallDynamicProperty.AppSecretDynamicProperty property = rtMallDynamicProperty.getBySourceAndType(authLogin.getSource(), authLogin.getOrderType()); | ||
| 57 | + log.info("authUrl property: {}", JsonUtils.toJsonString(property)); | ||
| 58 | + | ||
| 59 | + UserInfoVO userInfoVO = JsonUtils.convertValue(authLogin, UserInfoVO.class); | ||
| 60 | + userInfoVO.setUserCode(authLogin.getUserCode() + "_" + authLogin.getChannel()); | ||
| 61 | + userInfoVO.setUserName(authLogin.getUsername()); | ||
| 62 | + | ||
| 63 | + userInfoChannel(userInfoVO, property); | ||
| 64 | + return userInfoVO; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + /** | ||
| 68 | + * 渠道 | ||
| 69 | + */ | ||
| 70 | + public abstract String channel(); | ||
| 71 | + | ||
| 72 | + /** | ||
| 73 | + * authLoginUrl | ||
| 74 | + */ | ||
| 75 | + public abstract String authUrl(AuthLoginCO authLogin, String token, long timestamp); | ||
| 76 | + | ||
| 77 | + public abstract void userInfoChannel(UserInfoVO authLogin, RtMallDynamicProperty.AppSecretDynamicProperty userInfoVO); | ||
| 78 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/service/sourcechannel/RtMallChannel.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.service.sourcechannel; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.mall.domain.rtmall.co.AuthLoginCO; | ||
| 4 | +import com.diligrp.cashier.mall.domain.rtmall.vo.UserInfoVO; | ||
| 5 | +import com.diligrp.cashier.mall.property.RtMallDynamicProperty; | ||
| 6 | +import com.diligrp.cashier.mall.type.OrderChannel; | ||
| 7 | +import com.diligrp.cashier.mall.util.RtMallSignMd5Utils; | ||
| 8 | +import com.diligrp.cashier.shared.util.JsonUtils; | ||
| 9 | +import com.diligrp.cashier.shared.util.UrlParamParserUtils; | ||
| 10 | +import org.slf4j.Logger; | ||
| 11 | +import org.slf4j.LoggerFactory; | ||
| 12 | +import org.springframework.stereotype.Component; | ||
| 13 | + | ||
| 14 | +import java.util.Map; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * @ClassName RtMallChannel.java | ||
| 18 | + * @author dengwei | ||
| 19 | + * @version 1.0.0 | ||
| 20 | + * @Description RtMallChannel | ||
| 21 | + * @date 2025-12-25 11:20 | ||
| 22 | + */ | ||
| 23 | +@Component | ||
| 24 | +public class RtMallChannel extends AbstractChannel { | ||
| 25 | + private static final Logger log = LoggerFactory.getLogger(RtMallChannel.class); | ||
| 26 | + | ||
| 27 | + @Override | ||
| 28 | + public String authUrl(AuthLoginCO authLogin, String token, long timestamp) { | ||
| 29 | + RtMallDynamicProperty.AppSecretDynamicProperty property = rtMallDynamicProperty.getBySourceAndType(authLogin.getSource(), authLogin.getOrderType()); | ||
| 30 | + log.info("authUrl property: {}", JsonUtils.toJsonString(property)); | ||
| 31 | + | ||
| 32 | + // 替换参数 | ||
| 33 | + String authUrl = property.getAuthUrl(); | ||
| 34 | + authUrl = String.format(authUrl, token, timestamp, authLogin.getLongitude(), authLogin.getLatitude()); | ||
| 35 | + log.info("authUrl format1: {}", authUrl); | ||
| 36 | + | ||
| 37 | + // 获取参数 | ||
| 38 | + Map<String, String> queryParams = UrlParamParserUtils.parseQueryParams(authUrl); | ||
| 39 | + log.info("authUrl queryParams: {}", JsonUtils.toJsonString(queryParams)); | ||
| 40 | + | ||
| 41 | + // 生成签名 | ||
| 42 | + String sign = RtMallSignMd5Utils.generateSign(queryParams, property.getAppSecret()); | ||
| 43 | + log.info("authUrl sign: {}", sign); | ||
| 44 | + authUrl = authUrl.concat("&sign=").concat(sign); | ||
| 45 | + return authUrl; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * userInfo | ||
| 50 | + */ | ||
| 51 | + @Override | ||
| 52 | + public void userInfoChannel(final UserInfoVO authLogin, | ||
| 53 | + final RtMallDynamicProperty.AppSecretDynamicProperty property) { | ||
| 54 | + authLogin.setCompanyCode(property.getCompanyCode()); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Override | ||
| 58 | + public String channel() { | ||
| 59 | + return OrderChannel.RT_MART.getCode(); | ||
| 60 | + } | ||
| 61 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/sign/RtMallSign.java
| 1 | package com.diligrp.cashier.mall.sign; | 1 | package com.diligrp.cashier.mall.sign; |
| 2 | 2 | ||
| 3 | -import com.diligrp.cashier.mall.MallConstants; | ||
| 4 | import com.diligrp.cashier.mall.exception.RtMartMallException; | 3 | import com.diligrp.cashier.mall.exception.RtMartMallException; |
| 5 | -import com.diligrp.cashier.mall.property.MallDynamicProperty; | 4 | +import com.diligrp.cashier.mall.property.RtMallDynamicProperty; |
| 6 | import com.diligrp.cashier.mall.type.RtMarkErrorCode; | 5 | import com.diligrp.cashier.mall.type.RtMarkErrorCode; |
| 7 | import com.diligrp.cashier.mall.util.RtMallSignMd5Utils; | 6 | import com.diligrp.cashier.mall.util.RtMallSignMd5Utils; |
| 8 | import com.diligrp.cashier.shared.handler.sign.SecuritySign; | 7 | import com.diligrp.cashier.shared.handler.sign.SecuritySign; |
| @@ -31,7 +30,7 @@ public class RtMallSign implements SecuritySign { | @@ -31,7 +30,7 @@ public class RtMallSign implements SecuritySign { | ||
| 31 | private static final Logger log = LoggerFactory.getLogger(RtMallSign.class); | 30 | private static final Logger log = LoggerFactory.getLogger(RtMallSign.class); |
| 32 | 31 | ||
| 33 | @Resource | 32 | @Resource |
| 34 | - private MallDynamicProperty mallDynamicProperty; | 33 | + private RtMallDynamicProperty mallDynamicProperty; |
| 35 | 34 | ||
| 36 | @Override | 35 | @Override |
| 37 | public void sign(HttpServletRequest request, HttpServletResponse response, Object data) { | 36 | public void sign(HttpServletRequest request, HttpServletResponse response, Object data) { |
| @@ -45,15 +44,21 @@ public class RtMallSign implements SecuritySign { | @@ -45,15 +44,21 @@ public class RtMallSign implements SecuritySign { | ||
| 45 | throw new RtMartMallException(RtMarkErrorCode.E4003.getCode(), RtMarkErrorCode.E4003.getMessage()); | 44 | throw new RtMartMallException(RtMarkErrorCode.E4003.getCode(), RtMarkErrorCode.E4003.getMessage()); |
| 46 | } | 45 | } |
| 47 | 46 | ||
| 48 | - MallDynamicProperty.AppSecretDynamicProperty property = mallDynamicProperty.getBySource(MallConstants.RT_MALL_SOURCE); | 47 | + Object sign = paramMap.get("sign"); |
| 48 | + if (Objects.isNull(sign)) { | ||
| 49 | + throw new RtMartMallException(RtMarkErrorCode.E4004.getCode(), RtMarkErrorCode.E4004.getMessage()); | ||
| 50 | + } | ||
| 51 | + paramMap.remove("sign"); | ||
| 52 | + | ||
| 53 | + RtMallDynamicProperty.AppSecretDynamicProperty property = mallDynamicProperty.getByAppKey(appKey.toString()); | ||
| 49 | if (Objects.isNull(property)) { | 54 | if (Objects.isNull(property)) { |
| 50 | - throw new RtMartMallException(RtMarkErrorCode.E4001.getCode(), RtMarkErrorCode.E4001.getMessage()); | 55 | + throw new RtMartMallException(RtMarkErrorCode.E4003.getCode(), RtMarkErrorCode.E4003.getMessage()); |
| 51 | } | 56 | } |
| 52 | 57 | ||
| 53 | try { | 58 | try { |
| 54 | log.info("appKey:{}, secretKey:{}", property.getAppKey(), property.getAppSecret()); | 59 | log.info("appKey:{}, secretKey:{}", property.getAppKey(), property.getAppSecret()); |
| 55 | String signKey = RtMallSignMd5Utils.generateSign(paramMap, property.getAppSecret()); | 60 | String signKey = RtMallSignMd5Utils.generateSign(paramMap, property.getAppSecret()); |
| 56 | - Assert.isTrue(Objects.equals(signKey, paramMap.get("sign").toString()), "验签失败!"); | 61 | + Assert.isTrue(Objects.equals(signKey, sign.toString()), "验签失败!"); |
| 57 | } catch (Exception e) { | 62 | } catch (Exception e) { |
| 58 | throw new RtMartMallException(RtMarkErrorCode.E4004.getCode(), RtMarkErrorCode.E4004.getMessage()); | 63 | throw new RtMartMallException(RtMarkErrorCode.E4004.getCode(), RtMarkErrorCode.E4004.getMessage()); |
| 59 | } | 64 | } |
cashier-mall/src/main/java/com/diligrp/cashier/mall/type/OrderChannel.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.type; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * @ClassName OrderChannel.java | ||
| 5 | + * @author dengwei | ||
| 6 | + * @version 1.0.0 | ||
| 7 | + * @Description OrderChannel | ||
| 8 | + * @date 2025-12-25 11:18 | ||
| 9 | + */ | ||
| 10 | +public enum OrderChannel { | ||
| 11 | + RT_MART("1", "大润发"), | ||
| 12 | + SAM("2", "山姆"); | ||
| 13 | + | ||
| 14 | + public final String code; | ||
| 15 | + public final String description; | ||
| 16 | + | ||
| 17 | + OrderChannel(String code, String description) { | ||
| 18 | + this.code = code; | ||
| 19 | + this.description = description; | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + public String getCode() { | ||
| 23 | + return code; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public String getDescription() { | ||
| 27 | + return description; | ||
| 28 | + } | ||
| 29 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/type/OrderSource.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.type; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * @ClassName OrderSrouce.java | ||
| 5 | + * @author dengwei | ||
| 6 | + * @version 1.0.0 | ||
| 7 | + * @Description OrderSource | ||
| 8 | + * @date 2025-12-25 15:11 | ||
| 9 | + */ | ||
| 10 | +public enum OrderSource { | ||
| 11 | + RT_MART(1, "大润发"), | ||
| 12 | + SAM_CLUB(2, "山姆"); | ||
| 13 | + | ||
| 14 | + public final int code; | ||
| 15 | + public final String name; | ||
| 16 | + | ||
| 17 | + OrderSource(int code, String name) { | ||
| 18 | + this.code = code; | ||
| 19 | + this.name = name; | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + public int getCode() { | ||
| 23 | + return code; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public String getName() { | ||
| 27 | + return name; | ||
| 28 | + } | ||
| 29 | +} |
cashier-mall/src/main/java/com/diligrp/cashier/mall/type/OrderType.java
0 → 100644
| 1 | +package com.diligrp.cashier.mall.type; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * @ClassName OrderType.java | ||
| 5 | + * @author dengwei | ||
| 6 | + * @version 1.0.0 | ||
| 7 | + * @Description OrderType | ||
| 8 | + * @date 2025-12-25 11:17 | ||
| 9 | + */ | ||
| 10 | +public enum OrderType { | ||
| 11 | + OFFLINE_SCAN(1, "线下扫码购"), | ||
| 12 | + API_SCAN(2, "接口扫码购"), | ||
| 13 | + MINI_PROGRAM(3, "小程序"); | ||
| 14 | + | ||
| 15 | + private final int code; | ||
| 16 | + private final String description; | ||
| 17 | + | ||
| 18 | + OrderType(int code, String description) { | ||
| 19 | + this.code = code; | ||
| 20 | + this.description = description; | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + public int getCode() { | ||
| 24 | + return code; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public String getDescription() { | ||
| 28 | + return description; | ||
| 29 | + } | ||
| 30 | +} |
cashier-shared/build.gradle
| @@ -7,8 +7,10 @@ dependencies { | @@ -7,8 +7,10 @@ dependencies { | ||
| 7 | api 'org.springframework.cloud:spring-cloud-starter-loadbalancer' | 7 | api 'org.springframework.cloud:spring-cloud-starter-loadbalancer' |
| 8 | api 'org.springframework.cloud:spring-cloud-starter-openfeign' | 8 | api 'org.springframework.cloud:spring-cloud-starter-openfeign' |
| 9 | api 'org.springframework.boot:spring-boot-starter-aop' | 9 | api 'org.springframework.boot:spring-boot-starter-aop' |
| 10 | + api 'org.springframework.boot:spring-boot-starter-validation' | ||
| 10 | api libs.cache.caffeine | 11 | api libs.cache.caffeine |
| 11 | api libs.common.collections4 | 12 | api libs.common.collections4 |
| 13 | + api libs.google.guava | ||
| 12 | 14 | ||
| 13 | runtimeOnly libs.mysql.driver | 15 | runtimeOnly libs.mysql.driver |
| 14 | } | 16 | } |
cashier-shared/src/main/java/com/diligrp/cashier/shared/ErrorCode.java
| @@ -16,6 +16,8 @@ public class ErrorCode { | @@ -16,6 +16,8 @@ public class ErrorCode { | ||
| 16 | public static final String OBJECT_NOT_FOUND = "300004"; | 16 | public static final String OBJECT_NOT_FOUND = "300004"; |
| 17 | // 对象已存在 | 17 | // 对象已存在 |
| 18 | public static final String OBJECT_ALREADY_EXISTS = "300005"; | 18 | public static final String OBJECT_ALREADY_EXISTS = "300005"; |
| 19 | + // 请求方式 | ||
| 20 | + public static final String METHOD_NOT_SUPPORTED_ERROR = "300006"; | ||
| 19 | // 数据并发修改 | 21 | // 数据并发修改 |
| 20 | public static final String SYSTEM_BUSY_ERROR = "301000"; | 22 | public static final String SYSTEM_BUSY_ERROR = "301000"; |
| 21 | // 无效对象状态 | 23 | // 无效对象状态 |
cashier-shared/src/main/java/com/diligrp/cashier/shared/exception/DefaultExceptionHandler.java
| @@ -2,11 +2,24 @@ package com.diligrp.cashier.shared.exception; | @@ -2,11 +2,24 @@ package com.diligrp.cashier.shared.exception; | ||
| 2 | 2 | ||
| 3 | import com.diligrp.cashier.shared.ErrorCode; | 3 | import com.diligrp.cashier.shared.ErrorCode; |
| 4 | import com.diligrp.cashier.shared.domain.Message; | 4 | import com.diligrp.cashier.shared.domain.Message; |
| 5 | +import jakarta.validation.ConstraintViolation; | ||
| 6 | +import jakarta.validation.ConstraintViolationException; | ||
| 5 | import org.slf4j.Logger; | 7 | import org.slf4j.Logger; |
| 6 | import org.slf4j.LoggerFactory; | 8 | import org.slf4j.LoggerFactory; |
| 9 | +import org.springframework.context.support.DefaultMessageSourceResolvable; | ||
| 10 | +import org.springframework.validation.BindException; | ||
| 11 | +import org.springframework.validation.BindingResult; | ||
| 12 | +import org.springframework.validation.ObjectError; | ||
| 13 | +import org.springframework.web.HttpRequestMethodNotSupportedException; | ||
| 14 | +import org.springframework.web.bind.MethodArgumentNotValidException; | ||
| 15 | +import org.springframework.web.bind.MissingServletRequestParameterException; | ||
| 7 | import org.springframework.web.bind.annotation.ExceptionHandler; | 16 | import org.springframework.web.bind.annotation.ExceptionHandler; |
| 8 | import org.springframework.web.bind.annotation.RestControllerAdvice; | 17 | import org.springframework.web.bind.annotation.RestControllerAdvice; |
| 9 | 18 | ||
| 19 | +import java.util.List; | ||
| 20 | +import java.util.Set; | ||
| 21 | +import java.util.stream.Collectors; | ||
| 22 | + | ||
| 10 | @RestControllerAdvice | 23 | @RestControllerAdvice |
| 11 | public class DefaultExceptionHandler { | 24 | public class DefaultExceptionHandler { |
| 12 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); | 25 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); |
| @@ -23,6 +36,40 @@ public class DefaultExceptionHandler { | @@ -23,6 +36,40 @@ public class DefaultExceptionHandler { | ||
| 23 | return Message.failure(ErrorCode.ILLEGAL_ARGUMENT_ERROR, ex.getMessage()); | 36 | return Message.failure(ErrorCode.ILLEGAL_ARGUMENT_ERROR, ex.getMessage()); |
| 24 | } | 37 | } |
| 25 | 38 | ||
| 39 | + @ExceptionHandler(value = ConstraintViolationException.class) | ||
| 40 | + public Message<?> constraintViolationException(ConstraintViolationException exs) { | ||
| 41 | + Set<ConstraintViolation<?>> violations = exs.getConstraintViolations(); | ||
| 42 | + String msg = violations.stream().map(ConstraintViolation::getMessage) | ||
| 43 | + .collect(Collectors.joining(",")); | ||
| 44 | + return Message.failure(ErrorCode.ILLEGAL_ARGUMENT_ERROR, msg); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class}) | ||
| 48 | + public Message<?> methodArgumentNotValidException(Exception e) { | ||
| 49 | + BindingResult bindingResult; | ||
| 50 | + if (e instanceof MethodArgumentNotValidException) { | ||
| 51 | + bindingResult = ((MethodArgumentNotValidException) e).getBindingResult(); | ||
| 52 | + } else { | ||
| 53 | + bindingResult = ((BindException) e).getBindingResult(); | ||
| 54 | + } | ||
| 55 | + List<ObjectError> allErrors = bindingResult.getAllErrors(); | ||
| 56 | + String msg = allErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage) | ||
| 57 | + .collect(Collectors.joining("、")); | ||
| 58 | + | ||
| 59 | + return Message.failure(ErrorCode.ILLEGAL_ARGUMENT_ERROR, msg); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @ExceptionHandler(MissingServletRequestParameterException.class) | ||
| 63 | + public Message<?> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException ex) { | ||
| 64 | + return Message.failure(ErrorCode.ILLEGAL_ARGUMENT_ERROR, String.format("缺少参数:%s", ex.getParameterName())); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + @ExceptionHandler({HttpRequestMethodNotSupportedException.class}) | ||
| 68 | + public Message<?> handleRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) { | ||
| 69 | + return Message.failure(ErrorCode.METHOD_NOT_SUPPORTED_ERROR, "请求方式错误!"); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + | ||
| 26 | @ExceptionHandler(Exception.class) | 73 | @ExceptionHandler(Exception.class) |
| 27 | public Message<?> defaultExceptionHandler(Exception ex) { | 74 | public Message<?> defaultExceptionHandler(Exception ex) { |
| 28 | LOG.warn("assistant platform service exception", ex); | 75 | LOG.warn("assistant platform service exception", ex); |
cashier-shared/src/main/java/com/diligrp/cashier/shared/exception/PlatformServiceException.java
| @@ -30,10 +30,10 @@ public class PlatformServiceException extends RuntimeException { | @@ -30,10 +30,10 @@ public class PlatformServiceException extends RuntimeException { | ||
| 30 | super(message, ex); | 30 | super(message, ex); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | - @Override | ||
| 34 | - public Throwable fillInStackTrace() { | ||
| 35 | - return stackTrace ? super.fillInStackTrace() : this; | ||
| 36 | - } | 33 | +// @Override |
| 34 | +// public Throwable fillInStackTrace() { | ||
| 35 | +// return stackTrace ? super.fillInStackTrace() : this; | ||
| 36 | +// } | ||
| 37 | 37 | ||
| 38 | public String getCode() { | 38 | public String getCode() { |
| 39 | return code; | 39 | return code; |
cashier-shared/src/main/java/com/diligrp/cashier/shared/jackson/deserializer/SecondToDateDeserializer.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.jackson.deserializer; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.core.JacksonException; | ||
| 4 | +import com.fasterxml.jackson.core.JsonParser; | ||
| 5 | +import com.fasterxml.jackson.databind.DeserializationContext; | ||
| 6 | +import com.fasterxml.jackson.databind.JsonDeserializer; | ||
| 7 | + | ||
| 8 | +import java.io.IOException; | ||
| 9 | +import java.time.Instant; | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | +import java.time.ZoneOffset; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * @ClassName SecondToDateDeserializer.java | ||
| 15 | + * @author dengwei | ||
| 16 | + * @version 1.0.0 | ||
| 17 | + * @Description SecondToDateDeserializer | ||
| 18 | + * @date 2025-12-25 17:54 | ||
| 19 | + */ | ||
| 20 | +public class SecondToDateDeserializer extends JsonDeserializer<LocalDateTime> { | ||
| 21 | + @Override | ||
| 22 | + public LocalDateTime deserialize(JsonParser parser, DeserializationContext deserializationContext) throws IOException, JacksonException { | ||
| 23 | + long timestamp = parser.getValueAsLong(); | ||
| 24 | + return LocalDateTime.ofInstant( | ||
| 25 | + Instant.ofEpochSecond(timestamp), | ||
| 26 | + ZoneOffset.UTC | ||
| 27 | + ); | ||
| 28 | + } | ||
| 29 | +} |
cashier-shared/src/main/java/com/diligrp/cashier/shared/jackson/serialization/DateToSecondSerializer.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.jackson.serialization; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.core.JsonGenerator; | ||
| 4 | +import com.fasterxml.jackson.databind.JsonSerializer; | ||
| 5 | +import com.fasterxml.jackson.databind.SerializerProvider; | ||
| 6 | + | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.time.LocalDateTime; | ||
| 9 | +import java.time.ZoneOffset; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @ClassName DateToSecondSerializer.java | ||
| 13 | + * @author dengwei | ||
| 14 | + * @version 1.0.0 | ||
| 15 | + * @Description DateToSecondSerializer | ||
| 16 | + * @date 2025-12-25 17:57 | ||
| 17 | + */ | ||
| 18 | +public class DateToSecondSerializer extends JsonSerializer<LocalDateTime> { | ||
| 19 | + @Override | ||
| 20 | + public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { | ||
| 21 | + gen.writeNumber(value.toInstant(ZoneOffset.UTC).getEpochSecond()); | ||
| 22 | + } | ||
| 23 | +} |
cashier-shared/src/main/java/com/diligrp/cashier/shared/util/DateUtils.java
| @@ -3,6 +3,7 @@ package com.diligrp.cashier.shared.util; | @@ -3,6 +3,7 @@ package com.diligrp.cashier.shared.util; | ||
| 3 | import com.diligrp.cashier.shared.Constants; | 3 | import com.diligrp.cashier.shared.Constants; |
| 4 | 4 | ||
| 5 | import java.text.SimpleDateFormat; | 5 | import java.text.SimpleDateFormat; |
| 6 | +import java.time.Instant; | ||
| 6 | import java.time.LocalDate; | 7 | import java.time.LocalDate; |
| 7 | import java.time.LocalDateTime; | 8 | import java.time.LocalDateTime; |
| 8 | import java.time.ZoneOffset; | 9 | import java.time.ZoneOffset; |
| @@ -51,11 +52,11 @@ public class DateUtils { | @@ -51,11 +52,11 @@ public class DateUtils { | ||
| 51 | public static String format(Date date) { | 52 | public static String format(Date date) { |
| 52 | return format(date, Constants.DATE_TIME_FORMAT); | 53 | return format(date, Constants.DATE_TIME_FORMAT); |
| 53 | } | 54 | } |
| 54 | - | 55 | + |
| 55 | public static LocalDateTime addDays(long amount) { | 56 | public static LocalDateTime addDays(long amount) { |
| 56 | - LocalDateTime localDateTime = LocalDateTime.now(); | ||
| 57 | - localDateTime.plusDays(amount); | ||
| 58 | - return localDateTime; | 57 | + LocalDateTime localDateTime = LocalDateTime.now(); |
| 58 | + localDateTime.plusDays(amount); | ||
| 59 | + return localDateTime; | ||
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | public static String format(Date date, String format) { | 62 | public static String format(Date date, String format) { |
| @@ -112,17 +113,25 @@ public class DateUtils { | @@ -112,17 +113,25 @@ public class DateUtils { | ||
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | /** | 115 | /** |
| 115 | - * 获取时间戳 | ||
| 116 | - */ | ||
| 117 | - public static long parseMilliSecond(LocalDateTime localDateTime){ | ||
| 118 | - return parseMilliSecond(localDateTime,null); | 116 | + * 获取时间戳 |
| 117 | + */ | ||
| 118 | + public static long parseMilliSecond(LocalDateTime localDateTime) { | ||
| 119 | + return parseMilliSecond(localDateTime, null); | ||
| 119 | } | 120 | } |
| 120 | 121 | ||
| 121 | - public static long parseMilliSecond(LocalDateTime localDateTime, String zoneNumStr){ | 122 | + public static long parseMilliSecond(LocalDateTime localDateTime, String zoneNumStr) { |
| 122 | //默认东八区 | 123 | //默认东八区 |
| 123 | - if (ObjectUtils.isEmpty(zoneNumStr)){ | 124 | + if (ObjectUtils.isEmpty(zoneNumStr)) { |
| 124 | zoneNumStr = "+8"; | 125 | zoneNumStr = "+8"; |
| 125 | } | 126 | } |
| 126 | return localDateTime.toInstant(ZoneOffset.of(zoneNumStr)).toEpochMilli(); | 127 | return localDateTime.toInstant(ZoneOffset.of(zoneNumStr)).toEpochMilli(); |
| 127 | } | 128 | } |
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * 时间戳-秒 | ||
| 132 | + * | ||
| 133 | + */ | ||
| 134 | + public static long timestampInSeconds() { | ||
| 135 | + return Instant.now().getEpochSecond(); | ||
| 136 | + } | ||
| 128 | } | 137 | } |
cashier-shared/src/main/java/com/diligrp/cashier/shared/util/UrlParamParserUtils.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.util; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.exception.PlatformServiceException; | ||
| 4 | + | ||
| 5 | +import java.net.URI; | ||
| 6 | +import java.net.URLDecoder; | ||
| 7 | +import java.nio.charset.StandardCharsets; | ||
| 8 | +import java.util.HashMap; | ||
| 9 | +import java.util.Map; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @ClassName UrlParamParserUtils.java | ||
| 13 | + * @author dengwei | ||
| 14 | + * @version 1.0.0 | ||
| 15 | + * @Description UrlParamParserUtils | ||
| 16 | + * @date 2025-12-25 15:34 | ||
| 17 | + */ | ||
| 18 | +public class UrlParamParserUtils { | ||
| 19 | + public static Map<String, String> parseQueryParams(String url) { | ||
| 20 | + try { | ||
| 21 | + URI uri = new URI(url); | ||
| 22 | + String query = uri.getQuery(); | ||
| 23 | + if (query == null || query.isEmpty()) { | ||
| 24 | + return new HashMap<>(); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + Map<String, String> params = new HashMap<>(); | ||
| 28 | + String[] pairs = query.split("&"); | ||
| 29 | + for (String pair : pairs) { | ||
| 30 | + String[] keyValue = pair.split("=", 2); | ||
| 31 | + String key = URLDecoder.decode(keyValue[0], StandardCharsets.UTF_8); | ||
| 32 | + String value = keyValue.length > 1 ? URLDecoder.decode(keyValue[1], StandardCharsets.UTF_8) : ""; | ||
| 33 | + params.put(key, value); | ||
| 34 | + } | ||
| 35 | + return params; | ||
| 36 | + } catch (Exception e) { | ||
| 37 | + throw new PlatformServiceException("Invalid URL"); | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | +} |
gradle/libs.versions.toml
| @@ -9,6 +9,8 @@ mysqlDriverVersion = "8.0.33" | @@ -9,6 +9,8 @@ mysqlDriverVersion = "8.0.33" | ||
| 9 | redissonVersion = "3.52.0" | 9 | redissonVersion = "3.52.0" |
| 10 | caffeineVersion = "3.2.3" | 10 | caffeineVersion = "3.2.3" |
| 11 | collections4Version= "4.5.0" | 11 | collections4Version= "4.5.0" |
| 12 | +guavaVersion = "33.5.0-jre" | ||
| 13 | + | ||
| 12 | 14 | ||
| 13 | [libraries] | 15 | [libraries] |
| 14 | #spring-boot-starter = {module = 'org.springframework.boot:spring-boot-starter', version.ref = 'springBootVersion'} | 16 | #spring-boot-starter = {module = 'org.springframework.boot:spring-boot-starter', version.ref = 'springBootVersion'} |
| @@ -20,6 +22,7 @@ mysql-driver = {module = 'mysql:mysql-connector-java', version.ref = 'mysqlDrive | @@ -20,6 +22,7 @@ mysql-driver = {module = 'mysql:mysql-connector-java', version.ref = 'mysqlDrive | ||
| 20 | redisson-starter = {module = 'org.redisson:redisson-spring-boot-starter', version.ref = 'redissonVersion'} | 22 | redisson-starter = {module = 'org.redisson:redisson-spring-boot-starter', version.ref = 'redissonVersion'} |
| 21 | cache-caffeine = {module = 'com.github.ben-manes.caffeine:caffeine', version.ref = 'caffeineVersion'} | 23 | cache-caffeine = {module = 'com.github.ben-manes.caffeine:caffeine', version.ref = 'caffeineVersion'} |
| 22 | common-collections4 = {module = 'org.apache.commons:commons-collections4', version.ref = 'collections4Version'} | 24 | common-collections4 = {module = 'org.apache.commons:commons-collections4', version.ref = 'collections4Version'} |
| 25 | +google-guava = {module = 'com.google.guava:guava', version.ref = 'guavaVersion'} | ||
| 23 | 26 | ||
| 24 | [plugins] | 27 | [plugins] |
| 25 | spring-boot = {id = 'org.springframework.boot', version.ref = 'springBootVersion'} | 28 | spring-boot = {id = 'org.springframework.boot', version.ref = 'springBootVersion'} |