feat(product): 添加商品链接生成功能
- 新增商品链接实体类MtProductLink,包含链接码、URL、有效期等字段 - 创建商品链接Mapper接口,支持基础CRUD操作 - 实现商品链接服务接口ProductLinkService及其实现类 - 支持创建或获取现有有效链接,避免重复生成 - 提供链接有效性校验和过期处理机制 - 添加响应码枚举ResultCode,定义相关业务异常码 - 补充风控信息DTO类RiskInfoDTO及相关子DTO - 编写Service层结构说明文档,明确接口与实现分离的设计原则
This commit is contained in:
135
mt-pay/SERVICE_STRUCTURE.md
Normal file
135
mt-pay/SERVICE_STRUCTURE.md
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# Service层结构说明
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
service/
|
||||||
|
├── SignatureService.java # 签名服务接口
|
||||||
|
├── PingPongPayService.java # PingPong支付服务接口
|
||||||
|
├── PaymentOrderService.java # 支付订单服务接口
|
||||||
|
├── CallbackService.java # 回调处理服务接口
|
||||||
|
└── impl/ # 实现类目录
|
||||||
|
├── SignatureServiceImpl.java # 签名服务实现类
|
||||||
|
├── PingPongPayServiceImpl.java # PingPong支付服务实现类
|
||||||
|
├── PaymentOrderServiceImpl.java # 支付订单服务实现类
|
||||||
|
└── CallbackServiceImpl.java # 回调处理服务实现类
|
||||||
|
```
|
||||||
|
|
||||||
|
## 设计原则
|
||||||
|
|
||||||
|
### 1. 接口与实现分离
|
||||||
|
- **service文件夹**:只存放接口文件
|
||||||
|
- **service/impl文件夹**:存放所有实现类
|
||||||
|
|
||||||
|
### 2. 命名规范
|
||||||
|
- 接口:`XxxService`
|
||||||
|
- 实现类:`XxxServiceImpl`
|
||||||
|
|
||||||
|
### 3. 依赖注入
|
||||||
|
- Controller层注入接口,不直接依赖实现类
|
||||||
|
- Spring会自动根据接口找到对应的实现类(通过@Service注解)
|
||||||
|
|
||||||
|
## Service接口说明
|
||||||
|
|
||||||
|
### SignatureService
|
||||||
|
**功能**:签名生成和验证服务
|
||||||
|
|
||||||
|
**方法**:
|
||||||
|
- `generateSign(Map<String, Object> params)` - 生成签名
|
||||||
|
- `generateSign(Map<String, Object> params, String secret, String signType)` - 生成签名(指定密钥和类型)
|
||||||
|
- `verifySign(Map<String, Object> params)` - 验证签名
|
||||||
|
|
||||||
|
### PingPongPayService
|
||||||
|
**功能**:PingPong支付API调用服务
|
||||||
|
|
||||||
|
**方法**:
|
||||||
|
- `checkout(CheckoutRequestDTO request)` - 创建支付订单
|
||||||
|
|
||||||
|
### PaymentOrderService
|
||||||
|
**功能**:支付订单业务服务
|
||||||
|
|
||||||
|
**方法**:
|
||||||
|
- `createPaymentOrder(CheckoutRequestDTO request)` - 创建支付订单
|
||||||
|
- `findByMerchantTransactionId(String merchantTransactionId)` - 根据商户订单号查询
|
||||||
|
- `findByTransactionId(String transactionId)` - 根据PingPong交易流水号查询
|
||||||
|
- `updateOrderStatus(String merchantTransactionId, String status, String transactionId)` - 更新订单状态
|
||||||
|
|
||||||
|
### CallbackService
|
||||||
|
**功能**:回调处理服务
|
||||||
|
|
||||||
|
**方法**:
|
||||||
|
- `handleCallback(Map<String, Object> callbackData)` - 处理支付回调
|
||||||
|
|
||||||
|
## 实现类说明
|
||||||
|
|
||||||
|
### SignatureServiceImpl
|
||||||
|
- 实现签名生成和验证逻辑
|
||||||
|
- 支持MD5和SHA256签名算法
|
||||||
|
- 自动筛选参与签名的参数
|
||||||
|
|
||||||
|
### PingPongPayServiceImpl
|
||||||
|
- 实现PingPong API调用
|
||||||
|
- 自动生成请求签名
|
||||||
|
- 验证响应签名
|
||||||
|
|
||||||
|
### PaymentOrderServiceImpl
|
||||||
|
- 实现支付订单业务逻辑
|
||||||
|
- 调用PingPong API创建订单
|
||||||
|
- 保存订单和支付记录
|
||||||
|
|
||||||
|
### CallbackServiceImpl
|
||||||
|
- 实现回调处理逻辑
|
||||||
|
- 验证回调签名
|
||||||
|
- 更新订单状态
|
||||||
|
- 保存回调记录
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### Controller中使用Service
|
||||||
|
|
||||||
|
```java
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PaymentController {
|
||||||
|
// 注入接口,Spring会自动找到对应的实现类
|
||||||
|
private final PaymentOrderService paymentOrderService;
|
||||||
|
|
||||||
|
@PostMapping("/checkout")
|
||||||
|
public ResponseEntity<?> checkout(@RequestBody CheckoutRequestDTO request) {
|
||||||
|
PaymentOrder order = paymentOrderService.createPaymentOrder(request);
|
||||||
|
return ResponseEntity.ok(order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service实现类中注入其他Service
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PaymentOrderServiceImpl implements PaymentOrderService {
|
||||||
|
// 注入其他Service接口
|
||||||
|
private final PingPongPayService pingPongPayService;
|
||||||
|
|
||||||
|
// 实现接口方法
|
||||||
|
@Override
|
||||||
|
public PaymentOrder createPaymentOrder(CheckoutRequestDTO request) {
|
||||||
|
// 实现逻辑
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 优势
|
||||||
|
|
||||||
|
1. **解耦**:Controller只依赖接口,不依赖具体实现
|
||||||
|
2. **扩展性**:可以轻松替换实现类,不影响调用方
|
||||||
|
3. **测试**:可以方便地创建Mock实现进行单元测试
|
||||||
|
4. **规范**:统一的代码结构,便于维护
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. 所有Service实现类必须使用`@Service`注解
|
||||||
|
2. 实现类必须实现对应的接口
|
||||||
|
3. Controller中注入的是接口类型,不是实现类
|
||||||
|
4. 如果接口有多个实现类,需要使用`@Qualifier`指定
|
||||||
|
|
||||||
98
mt-pay/src/main/java/com/mtkj/mtpay/common/ResultCode.java
Normal file
98
mt-pay/src/main/java/com/mtkj/mtpay/common/ResultCode.java
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package com.mtkj.mtpay.common;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应码枚举
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ResultCode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功
|
||||||
|
*/
|
||||||
|
SUCCESS("0000", "操作成功"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败
|
||||||
|
*/
|
||||||
|
FAIL("9999", "操作失败"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数错误
|
||||||
|
*/
|
||||||
|
PARAM_ERROR("4000", "参数错误"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数验证失败
|
||||||
|
*/
|
||||||
|
VALIDATION_ERROR("4001", "参数验证失败"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未授权
|
||||||
|
*/
|
||||||
|
UNAUTHORIZED("4002", "未授权"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁止访问
|
||||||
|
*/
|
||||||
|
FORBIDDEN("4003", "禁止访问"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源不存在
|
||||||
|
*/
|
||||||
|
NOT_FOUND("4004", "资源不存在"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据不存在
|
||||||
|
*/
|
||||||
|
DATA_NOT_FOUND("4005", "数据不存在"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单不存在
|
||||||
|
*/
|
||||||
|
ORDER_NOT_FOUND("1001", "订单不存在"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单已存在
|
||||||
|
*/
|
||||||
|
ORDER_EXISTS("1002", "订单已存在"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单状态错误
|
||||||
|
*/
|
||||||
|
ORDER_STATUS_ERROR("1003", "订单状态错误"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签名验证失败
|
||||||
|
*/
|
||||||
|
SIGNATURE_ERROR("2001", "签名验证失败"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PingPong API调用失败
|
||||||
|
*/
|
||||||
|
PINGPONG_API_ERROR("2002", "PingPong API调用失败"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统异常
|
||||||
|
*/
|
||||||
|
SYSTEM_ERROR("5000", "系统异常"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务不可用
|
||||||
|
*/
|
||||||
|
SERVICE_UNAVAILABLE("5001", "服务不可用");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应码
|
||||||
|
*/
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应消息
|
||||||
|
*/
|
||||||
|
private final String message;
|
||||||
|
}
|
||||||
|
|
||||||
33
mt-pay/src/main/java/com/mtkj/mtpay/dto/RiskInfoDTO.java
Normal file
33
mt-pay/src/main/java/com/mtkj/mtpay/dto/RiskInfoDTO.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package com.mtkj.mtpay.dto;
|
||||||
|
|
||||||
|
import com.mtkj.mtpay.dto.risk.*;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风控信息DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class RiskInfoDTO implements Serializable {
|
||||||
|
|
||||||
|
private DeviceDTO device;
|
||||||
|
|
||||||
|
private CustomerDTO customer;
|
||||||
|
|
||||||
|
private List<GoodsDTO> goods;
|
||||||
|
|
||||||
|
private ShippingDTO shipping;
|
||||||
|
|
||||||
|
private BillingDTO billing;
|
||||||
|
|
||||||
|
private EcommerceDTO ecommerce;
|
||||||
|
|
||||||
|
private AirlineDTO airline;
|
||||||
|
|
||||||
|
private RechargeDTO reCharge;
|
||||||
|
|
||||||
|
private CarRentalDTO carRental;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.mtkj.mtpay.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品链接实体类(用于持久化商品详情页链接)
|
||||||
|
*/
|
||||||
|
@TableName(value = "mt_product_link")
|
||||||
|
@Data
|
||||||
|
public class MtProductLink {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 链接ID
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品ID
|
||||||
|
*/
|
||||||
|
@TableField(value = "product_id", jdbcType = org.apache.ibatis.type.JdbcType.BIGINT)
|
||||||
|
private Long productId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短链接码(唯一标识,用于生成URL)
|
||||||
|
*/
|
||||||
|
@TableField(value = "link_code", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
|
||||||
|
private String linkCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完整URL
|
||||||
|
*/
|
||||||
|
@TableField(value = "full_url", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
|
||||||
|
private String fullUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有效期(天数,默认90天)
|
||||||
|
*/
|
||||||
|
@TableField(value = "expire_days", jdbcType = org.apache.ibatis.type.JdbcType.INTEGER)
|
||||||
|
private Integer expireDays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过期时间(创建时间 + 有效期)
|
||||||
|
*/
|
||||||
|
@TableField(value = "expire_time", jdbcType = org.apache.ibatis.type.JdbcType.TIMESTAMP)
|
||||||
|
private LocalDateTime expireTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态:ACTIVE-有效,EXPIRED-已过期,INACTIVE-已禁用
|
||||||
|
*/
|
||||||
|
@TableField(value = "status", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "create_time", fill = FieldFill.INSERT)
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.mtkj.mtpay.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.mtkj.mtpay.entity.MtProductLink;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品链接Mapper接口
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface MtProductLinkMapper extends BaseMapper<MtProductLink> {
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.mtkj.mtpay.service;
|
||||||
|
|
||||||
|
import com.mtkj.mtpay.entity.MtProductLink;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品链接服务接口
|
||||||
|
*/
|
||||||
|
public interface ProductLinkService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为商品创建链接(如果已存在有效链接则返回现有链接,否则创建新链接)
|
||||||
|
* @param productId 商品ID
|
||||||
|
* @param expireDays 有效期(天数,默认90天)
|
||||||
|
* @return 商品链接对象
|
||||||
|
*/
|
||||||
|
MtProductLink createOrGetProductLink(Long productId, Integer expireDays);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据链接码获取商品链接
|
||||||
|
* @param linkCode 链接码
|
||||||
|
* @return 商品链接对象
|
||||||
|
*/
|
||||||
|
MtProductLink getProductLinkByCode(String linkCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据链接码获取商品ID(验证链接有效性)
|
||||||
|
* @param linkCode 链接码
|
||||||
|
* @return 商品ID,如果链接无效则返回null
|
||||||
|
*/
|
||||||
|
Long getProductIdByLinkCode(String linkCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查链接是否有效(未过期且状态为ACTIVE)
|
||||||
|
* @param linkCode 链接码
|
||||||
|
* @return true-有效,false-无效
|
||||||
|
*/
|
||||||
|
boolean isLinkValid(String linkCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新链接状态为已过期
|
||||||
|
* @param linkCode 链接码
|
||||||
|
*/
|
||||||
|
void markLinkAsExpired(String linkCode);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
package com.mtkj.mtpay.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.mtkj.mtpay.common.ResultCode;
|
||||||
|
import com.mtkj.mtpay.entity.MtProductLink;
|
||||||
|
import com.mtkj.mtpay.exception.BusinessException;
|
||||||
|
import com.mtkj.mtpay.mapper.MtProductLinkMapper;
|
||||||
|
import com.mtkj.mtpay.service.ProductLinkService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品链接服务实现类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class ProductLinkServiceImpl implements ProductLinkService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MtProductLinkMapper productLinkMapper;
|
||||||
|
|
||||||
|
@Value("${app.frontend.url:http://localhost:3000}")
|
||||||
|
private String frontendUrl;
|
||||||
|
|
||||||
|
private static final int DEFAULT_EXPIRE_DAYS = 90;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public MtProductLink createOrGetProductLink(Long productId, Integer expireDays) {
|
||||||
|
log.debug("创建或获取商品链接,商品ID: {}, 有效期: {}天", productId, expireDays);
|
||||||
|
|
||||||
|
if (expireDays == null || expireDays <= 0) {
|
||||||
|
expireDays = DEFAULT_EXPIRE_DAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找是否已存在有效的链接
|
||||||
|
LambdaQueryWrapper<MtProductLink> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(MtProductLink::getProductId, productId)
|
||||||
|
.eq(MtProductLink::getStatus, "ACTIVE")
|
||||||
|
.gt(MtProductLink::getExpireTime, LocalDateTime.now())
|
||||||
|
.orderByDesc(MtProductLink::getCreateTime)
|
||||||
|
.last("LIMIT 1");
|
||||||
|
|
||||||
|
MtProductLink existingLink = productLinkMapper.selectOne(wrapper);
|
||||||
|
|
||||||
|
if (existingLink != null) {
|
||||||
|
log.debug("找到现有有效链接,链接码: {}, 商品ID: {}", existingLink.getLinkCode(), productId);
|
||||||
|
return existingLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新链接
|
||||||
|
MtProductLink newLink = new MtProductLink();
|
||||||
|
newLink.setProductId(productId);
|
||||||
|
|
||||||
|
// 生成唯一链接码(使用UUID去掉横线,取前32位)
|
||||||
|
String linkCode = UUID.randomUUID().toString().replace("-", "").substring(0, 32);
|
||||||
|
newLink.setLinkCode(linkCode);
|
||||||
|
|
||||||
|
// 构建完整URL
|
||||||
|
String fullUrl = frontendUrl + "/product/" + linkCode;
|
||||||
|
newLink.setFullUrl(fullUrl);
|
||||||
|
|
||||||
|
// 设置有效期
|
||||||
|
newLink.setExpireDays(expireDays);
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
newLink.setExpireTime(now.plusDays(expireDays));
|
||||||
|
newLink.setStatus("ACTIVE");
|
||||||
|
|
||||||
|
int result = productLinkMapper.insert(newLink);
|
||||||
|
if (result <= 0) {
|
||||||
|
log.error("创建商品链接失败,商品ID: {}", productId);
|
||||||
|
throw new BusinessException(ResultCode.SYSTEM_ERROR, "创建商品链接失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("创建商品链接成功,商品ID: {}, 链接码: {}, 过期时间: {}",
|
||||||
|
productId, linkCode, newLink.getExpireTime());
|
||||||
|
|
||||||
|
return newLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MtProductLink getProductLinkByCode(String linkCode) {
|
||||||
|
log.debug("根据链接码获取商品链接,链接码: {}", linkCode);
|
||||||
|
|
||||||
|
LambdaQueryWrapper<MtProductLink> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(MtProductLink::getLinkCode, linkCode)
|
||||||
|
.last("LIMIT 1");
|
||||||
|
|
||||||
|
MtProductLink link = productLinkMapper.selectOne(wrapper);
|
||||||
|
|
||||||
|
if (link == null) {
|
||||||
|
log.warn("商品链接不存在,链接码: {}", linkCode);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否过期
|
||||||
|
if (link.getExpireTime().isBefore(LocalDateTime.now())) {
|
||||||
|
log.warn("商品链接已过期,链接码: {}, 过期时间: {}", linkCode, link.getExpireTime());
|
||||||
|
// 更新状态为已过期
|
||||||
|
link.setStatus("EXPIRED");
|
||||||
|
productLinkMapper.updateById(link);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查状态
|
||||||
|
if (!"ACTIVE".equals(link.getStatus())) {
|
||||||
|
log.warn("商品链接状态无效,链接码: {}, 状态: {}", linkCode, link.getStatus());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getProductIdByLinkCode(String linkCode) {
|
||||||
|
MtProductLink link = getProductLinkByCode(linkCode);
|
||||||
|
return link != null ? link.getProductId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLinkValid(String linkCode) {
|
||||||
|
MtProductLink link = getProductLinkByCode(linkCode);
|
||||||
|
return link != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void markLinkAsExpired(String linkCode) {
|
||||||
|
log.debug("标记链接为已过期,链接码: {}", linkCode);
|
||||||
|
|
||||||
|
LambdaQueryWrapper<MtProductLink> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(MtProductLink::getLinkCode, linkCode);
|
||||||
|
|
||||||
|
MtProductLink link = productLinkMapper.selectOne(wrapper);
|
||||||
|
if (link != null) {
|
||||||
|
link.setStatus("EXPIRED");
|
||||||
|
productLinkMapper.updateById(link);
|
||||||
|
log.info("链接已标记为过期,链接码: {}", linkCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user