4.12新需求修改
This commit is contained in:
parent
8ec2796770
commit
b4eee35c1f
@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.validation.constraints.*;
|
import jakarta.validation.constraints.*;
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import org.asinkj.amz.domain.vo.InquiryRequestItemVo;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.asinkj.common.idempotent.annotation.RepeatSubmit;
|
import org.asinkj.common.idempotent.annotation.RepeatSubmit;
|
||||||
@ -72,6 +73,13 @@ public class BizInquiryRequestController extends BaseController {
|
|||||||
return bizInquiryRequestService.createWithDesAndChannel(destination, channelId,date);
|
return bizInquiryRequestService.createWithDesAndChannel(destination, channelId,date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SaCheckPermission("amz:shipmentPlan:edit")
|
||||||
|
@PostMapping("/create/batch")
|
||||||
|
@RepeatSubmit
|
||||||
|
public R<String> batchCreateWithItems(@RequestBody List<InquiryRequestItemVo> items) {
|
||||||
|
return bizInquiryRequestService.batchCreateWithItems(items);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出物流询价列表
|
* 导出物流询价列表
|
||||||
*/
|
*/
|
||||||
|
@ -89,6 +89,16 @@ public class BizShipmentPlanController extends BaseController {
|
|||||||
return toAjax(bizShipmentPlanService.insertByBo(bo));
|
return toAjax(bizShipmentPlanService.insertByBo(bo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SaCheckPermission("amz:shipmentPlan:add")
|
||||||
|
@Log(title = "货件计划", businessType = BusinessType.INSERT)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PostMapping("/update/list/{status}")
|
||||||
|
public R<Void> updateList( @RequestBody List<String> list, @PathVariable String status) {
|
||||||
|
|
||||||
|
bizShipmentPlanService.updateList(list, status);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改货件计划
|
* 修改货件计划
|
||||||
*/
|
*/
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.asinkj.amz.domain;
|
package org.asinkj.amz.domain;
|
||||||
|
|
||||||
|
import org.asinkj.asinking.entity.FbaShipmentApiResponse;
|
||||||
import org.asinkj.common.tenant.core.TenantEntity;
|
import org.asinkj.common.tenant.core.TenantEntity;
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -7,6 +8,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
@ -104,4 +106,7 @@ public class BizInquiryRequest extends TenantEntity {
|
|||||||
private Date quoteDate;
|
private Date quoteDate;
|
||||||
|
|
||||||
|
|
||||||
|
private FbaShipmentApiResponse.Address shipToAddress;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -110,4 +110,10 @@ public class BizLogisticsQuote extends TenantEntity {
|
|||||||
private Long inquiryId;
|
private Long inquiryId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后端物流类型
|
||||||
|
*/
|
||||||
|
private String backLogisticsType;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,12 @@ package org.asinkj.amz.domain.vo;
|
|||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import org.asinkj.amz.domain.BizInquiryRequest;
|
import org.asinkj.amz.domain.BizInquiryRequest;
|
||||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import org.asinkj.asinking.entity.FbaShipmentApiResponse;
|
||||||
import org.asinkj.common.excel.annotation.ExcelDictFormat;
|
import org.asinkj.common.excel.annotation.ExcelDictFormat;
|
||||||
import org.asinkj.common.excel.convert.ExcelDictConvert;
|
import org.asinkj.common.excel.convert.ExcelDictConvert;
|
||||||
import io.github.linpeilie.annotations.AutoMapper;
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
@ -16,7 +18,6 @@ import java.io.Serializable;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 物流询价视图对象 biz_inquiry_request
|
* 物流询价视图对象 biz_inquiry_request
|
||||||
*
|
*
|
||||||
@ -120,5 +121,7 @@ public class BizInquiryRequestVo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Date quoteDate;
|
private Date quoteDate;
|
||||||
|
|
||||||
|
private FbaShipmentApiResponse.Address shipToAddress;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -129,4 +129,9 @@ public class BizLogisticsQuoteVo implements Serializable {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private String backLogisticsType;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package org.asinkj.amz.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.asinkj.amz.domain.BizInquiryRequest;
|
||||||
|
import org.asinkj.asinking.entity.FbaShipmentApiResponse;
|
||||||
|
import org.asinkj.common.excel.annotation.ExcelDictFormat;
|
||||||
|
import org.asinkj.common.excel.convert.ExcelDictConvert;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物流询价视图对象 biz_inquiry_request
|
||||||
|
*
|
||||||
|
* @author shuo hu
|
||||||
|
* @date 2025-03-21
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
|
@AutoMapper(target = BizInquiryRequest.class)
|
||||||
|
public class InquiryRequestItemVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private String shipmentId;
|
||||||
|
/**
|
||||||
|
* 目的地(存储四级行政编码,如CN310115)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "目的地", converter = ExcelDictConvert.class)
|
||||||
|
@ExcelDictFormat(readConverterExp = "存=储四级行政编码,如CN310115")
|
||||||
|
private String destination;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渠道ID(system=dict_code,custom=自定义渠道ID)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "渠道ID")
|
||||||
|
private Long channelId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 报价目标日期
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||||
|
private Date quoteDate;
|
||||||
|
|
||||||
|
|
||||||
|
private FbaShipmentApiResponse.Address shipToAddress;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -4,6 +4,7 @@ import jakarta.validation.constraints.NotNull;
|
|||||||
import org.asinkj.amz.domain.BizInquiryRequest;
|
import org.asinkj.amz.domain.BizInquiryRequest;
|
||||||
import org.asinkj.amz.domain.vo.BizInquiryRequestVo;
|
import org.asinkj.amz.domain.vo.BizInquiryRequestVo;
|
||||||
import org.asinkj.amz.domain.bo.BizInquiryRequestBo;
|
import org.asinkj.amz.domain.bo.BizInquiryRequestBo;
|
||||||
|
import org.asinkj.amz.domain.vo.InquiryRequestItemVo;
|
||||||
import org.asinkj.common.core.domain.R;
|
import org.asinkj.common.core.domain.R;
|
||||||
import org.asinkj.common.mybatis.core.page.TableDataInfo;
|
import org.asinkj.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.asinkj.common.mybatis.core.page.PageQuery;
|
import org.asinkj.common.mybatis.core.page.PageQuery;
|
||||||
@ -71,5 +72,8 @@ public interface IBizInquiryRequestService {
|
|||||||
|
|
||||||
R<String> createWithDesAndChannel(@NotNull(message = "目的地不能为空") String destination, @NotNull(message = "渠道不能为空") String channelId, @NotNull(message = "日期不能为空") String date);
|
R<String> createWithDesAndChannel(@NotNull(message = "目的地不能为空") String destination, @NotNull(message = "渠道不能为空") String channelId, @NotNull(message = "日期不能为空") String date);
|
||||||
|
|
||||||
|
|
||||||
|
R<String> batchCreateWithItems(List<InquiryRequestItemVo> items);
|
||||||
|
|
||||||
TableDataInfo<BizInquiryRequestVo> queryWithDesAndChannel(@NotNull(message = "目的地不能为空") String destination, @NotNull(message = "渠道不能为空") String channelId, @NotNull(message = "日期不能为空") String date);
|
TableDataInfo<BizInquiryRequestVo> queryWithDesAndChannel(@NotNull(message = "目的地不能为空") String destination, @NotNull(message = "渠道不能为空") String channelId, @NotNull(message = "日期不能为空") String date);
|
||||||
}
|
}
|
||||||
|
@ -77,4 +77,8 @@ public interface IBizShipmentPlanService {
|
|||||||
void takeTodayAmzPlanData();
|
void takeTodayAmzPlanData();
|
||||||
|
|
||||||
TableDataInfo<BizShipmentPlanOrderVo> queryPageListOrder(BizShipmentPlanBo bo, PageQuery pageQuery);
|
TableDataInfo<BizShipmentPlanOrderVo> queryPageListOrder(BizShipmentPlanBo bo, PageQuery pageQuery);
|
||||||
|
|
||||||
|
void updateStatusbyFbaShipmentIds(List<String> fbaShipmentids);
|
||||||
|
|
||||||
|
void updateList(Collection<String> list, String status);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package org.asinkj.amz.service.impl;
|
package org.asinkj.amz.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.date.DateTime;
|
import cn.hutool.core.date.DateTime;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.NumberUtil;
|
import cn.hutool.core.util.NumberUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.asinkj.amz.domain.BizLogisticsQuote;
|
|
||||||
import org.asinkj.amz.domain.vo.BizLogisticsChannelVo;
|
import org.asinkj.amz.domain.vo.BizLogisticsChannelVo;
|
||||||
|
import org.asinkj.amz.domain.vo.InquiryRequestItemVo;
|
||||||
import org.asinkj.amz.mapper.BizLogisticsQuoteMapper;
|
import org.asinkj.amz.mapper.BizLogisticsQuoteMapper;
|
||||||
import org.asinkj.amz.service.IBizLogisticsChannelService;
|
import org.asinkj.amz.service.IBizLogisticsChannelService;
|
||||||
|
import org.asinkj.amz.service.IBizShipmentPlanService;
|
||||||
import org.asinkj.common.core.domain.R;
|
import org.asinkj.common.core.domain.R;
|
||||||
import org.asinkj.common.core.utils.MapstructUtils;
|
import org.asinkj.common.core.utils.MapstructUtils;
|
||||||
import org.asinkj.common.core.utils.StringUtils;
|
import org.asinkj.common.core.utils.StringUtils;
|
||||||
@ -17,10 +20,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.asinkj.common.redis.annotation.DistributedLock;
|
||||||
|
import org.asinkj.common.redis.utils.RedisUtils;
|
||||||
import org.asinkj.common.satoken.utils.LoginHelper;
|
import org.asinkj.common.satoken.utils.LoginHelper;
|
||||||
import org.asinkj.resource.api.RemoteMessageService;
|
import org.asinkj.resource.api.RemoteMessageService;
|
||||||
import org.asinkj.utils.SerialNoGenerator;
|
import org.asinkj.utils.SerialNoGenerator;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.redisson.api.RLock;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.asinkj.amz.domain.bo.BizInquiryRequestBo;
|
import org.asinkj.amz.domain.bo.BizInquiryRequestBo;
|
||||||
import org.asinkj.amz.domain.vo.BizInquiryRequestVo;
|
import org.asinkj.amz.domain.vo.BizInquiryRequestVo;
|
||||||
@ -29,12 +35,12 @@ import org.asinkj.amz.mapper.BizInquiryRequestMapper;
|
|||||||
import org.asinkj.amz.service.IBizInquiryRequestService;
|
import org.asinkj.amz.service.IBizInquiryRequestService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.time.DayOfWeek;
|
import java.time.DayOfWeek;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.temporal.TemporalAdjusters;
|
import java.time.temporal.TemporalAdjusters;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 物流询价Service业务层处理
|
* 物流询价Service业务层处理
|
||||||
@ -64,6 +70,10 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
|||||||
@Resource
|
@Resource
|
||||||
private RemoteMessageService remoteMessageService;
|
private RemoteMessageService remoteMessageService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IBizShipmentPlanService bizShipmentPlanService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询物流询价
|
* 查询物流询价
|
||||||
*
|
*
|
||||||
@ -71,7 +81,7 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
|||||||
* @return 物流询价
|
* @return 物流询价
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BizInquiryRequestVo queryById(Long id){
|
public BizInquiryRequestVo queryById(Long id) {
|
||||||
return baseMapper.selectVoById(id);
|
return baseMapper.selectVoById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +161,7 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
|||||||
/**
|
/**
|
||||||
* 保存前的数据校验
|
* 保存前的数据校验
|
||||||
*/
|
*/
|
||||||
private void validEntityBeforeSave(BizInquiryRequest entity){
|
private void validEntityBeforeSave(BizInquiryRequest entity) {
|
||||||
//TODO 做一些数据校验,如唯一约束
|
//TODO 做一些数据校验,如唯一约束
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,16 +174,14 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||||
if(isValid){
|
if (isValid) {
|
||||||
//TODO 做一些业务上的校验,判断是否需要校验
|
//TODO 做一些业务上的校验,判断是否需要校验
|
||||||
}
|
}
|
||||||
return baseMapper.deleteByIds(ids) > 0;
|
return baseMapper.deleteByIds(ids) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public R<String> createWithDesAndChannel(String destination, String channelId,String date) {
|
public R<String> createWithDesAndChannel(String destination, String channelId, String date) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BizInquiryRequest bizInquiryRequest = new BizInquiryRequest();
|
BizInquiryRequest bizInquiryRequest = new BizInquiryRequest();
|
||||||
@ -192,13 +200,13 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
|||||||
//查询出渠道信息
|
//查询出渠道信息
|
||||||
|
|
||||||
BizLogisticsChannelVo bizLogisticsChannelVo = bizLogisticsChannelService.queryById(bizInquiryRequest.getChannelId());
|
BizLogisticsChannelVo bizLogisticsChannelVo = bizLogisticsChannelService.queryById(bizInquiryRequest.getChannelId());
|
||||||
if (bizLogisticsChannelVo == null){
|
if (bizLogisticsChannelVo == null) {
|
||||||
log.info("渠道信息为空");
|
log.info("渠道信息为空");
|
||||||
}
|
}
|
||||||
if ("air".equals(bizLogisticsChannelVo.getShippingMethod())){
|
if ("air".equals(bizLogisticsChannelVo.getShippingMethod())) {
|
||||||
bizInquiryRequest.setEffectiveStartTime(new Date());
|
bizInquiryRequest.setEffectiveStartTime(new Date());
|
||||||
bizInquiryRequest.setEffectiveEndTime(new Date());
|
bizInquiryRequest.setEffectiveEndTime(new Date());
|
||||||
}else if("sea".equals(bizLogisticsChannelVo.getShippingMethod())){
|
} else if ("sea".equals(bizLogisticsChannelVo.getShippingMethod())) {
|
||||||
//获取本周的周日上个周六的日期
|
//获取本周的周日上个周六的日期
|
||||||
LocalDate sunday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
|
LocalDate sunday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
|
||||||
LocalDate saturday = sunday.plusDays(6);
|
LocalDate saturday = sunday.plusDays(6);
|
||||||
@ -213,18 +221,212 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
|||||||
bizInquiryRequest.setTransportChannel(bizLogisticsChannelVo.getShippingMethod());
|
bizInquiryRequest.setTransportChannel(bizLogisticsChannelVo.getShippingMethod());
|
||||||
//获取当天上午11点的时间 ?
|
//获取当天上午11点的时间 ?
|
||||||
bizInquiryRequest.setDeadline(LocalDate.now()
|
bizInquiryRequest.setDeadline(LocalDate.now()
|
||||||
.atTime(11, 0));
|
.atTime(11, 0));
|
||||||
bizInquiryRequest.setRequesterId(LoginHelper.getUserId());
|
bizInquiryRequest.setRequesterId(LoginHelper.getUserId());
|
||||||
DateTime dateTime = DateUtil.parseDate(date);
|
DateTime dateTime = DateUtil.parseDate(date);
|
||||||
bizInquiryRequest.setQuoteDate(dateTime);
|
bizInquiryRequest.setQuoteDate(dateTime);
|
||||||
|
|
||||||
billingRequestMapper.insert(bizInquiryRequest);
|
billingRequestMapper.insert(bizInquiryRequest);
|
||||||
|
|
||||||
remoteMessageService.publishMessage(LoginHelper.getUserId(), "您好,您的询价单创建成功。具体询价单号为:"+bizInquiryRequest.getInquiryNo());
|
remoteMessageService.publishMessage(LoginHelper.getUserId(), "您好,您的询价单创建成功。具体询价单号为:" + bizInquiryRequest.getInquiryNo());
|
||||||
|
|
||||||
return R.ok(bizInquiryRequest.getInquiryNo());
|
return R.ok(bizInquiryRequest.getInquiryNo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public R<String> batchCreateWithItems(List<InquiryRequestItemVo> items) {
|
||||||
|
//
|
||||||
|
// if (CollectionUtil.isEmpty(items)) {
|
||||||
|
// return R.fail("询价单不能为空");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// List<InquiryRequestItemVo> requests = fiterItemsList(items);
|
||||||
|
// if (CollectionUtil.isEmpty(requests)) {
|
||||||
|
// return R.warn("已经有相同的询价了");
|
||||||
|
// }
|
||||||
|
// List<BizInquiryRequest> bizInquiryRequests = new ArrayList<>();
|
||||||
|
// for (InquiryRequestItemVo request : requests) {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// BizInquiryRequest bizInquiryRequest = new BizInquiryRequest();
|
||||||
|
// bizInquiryRequest.setDestination(request.getDestination());
|
||||||
|
// bizInquiryRequest.setChannelId(request.getChannelId());
|
||||||
|
//
|
||||||
|
// bizInquiryRequest.setRequesterName(LoginHelper.getLoginUser().getNickname());
|
||||||
|
// if (bizInquiryRequest.getChannelId() == null) {
|
||||||
|
// return R.fail("渠道不能为空");
|
||||||
|
// }
|
||||||
|
// if (bizInquiryRequest.getDestination() == null) {
|
||||||
|
// return R.fail("目的地不能为空");
|
||||||
|
// }
|
||||||
|
// //询价单号(规则:INQ+年月+6位序列)
|
||||||
|
// bizInquiryRequest.setInquiryNo(SerialNoGenerator.generateInquiryNo());
|
||||||
|
// //查询出渠道信息
|
||||||
|
//
|
||||||
|
// BizLogisticsChannelVo bizLogisticsChannelVo = bizLogisticsChannelService.queryById(bizInquiryRequest.getChannelId());
|
||||||
|
// if (bizLogisticsChannelVo == null) {
|
||||||
|
// log.info("渠道信息为空");
|
||||||
|
// }
|
||||||
|
// if ("air".equals(bizLogisticsChannelVo.getShippingMethod())) {
|
||||||
|
// bizInquiryRequest.setEffectiveStartTime(new Date());
|
||||||
|
// bizInquiryRequest.setEffectiveEndTime(new Date());
|
||||||
|
// } else if ("sea".equals(bizLogisticsChannelVo.getShippingMethod())) {
|
||||||
|
// //获取本周的周日上个周六的日期
|
||||||
|
// LocalDate sunday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
|
||||||
|
//
|
||||||
|
// LocalDate saturday = sunday.plusDays(6);
|
||||||
|
//
|
||||||
|
// bizInquiryRequest.setEffectiveStartTime(DateUtil.date(sunday));
|
||||||
|
//
|
||||||
|
// bizInquiryRequest.setEffectiveEndTime(DateUtil.date(saturday));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// bizInquiryRequest.setChannelName(bizLogisticsChannelVo.getChannelName());
|
||||||
|
// bizInquiryRequest.setTransportChannel(bizLogisticsChannelVo.getShippingMethod());
|
||||||
|
// //获取当天上午11点的时间 ?
|
||||||
|
// bizInquiryRequest.setDeadline(LocalDate.now()
|
||||||
|
// .atTime(11, 0));
|
||||||
|
//
|
||||||
|
// bizInquiryRequest.setRequesterId(LoginHelper.getUserId());
|
||||||
|
// bizInquiryRequest.setQuoteDate(request.getQuoteDate());
|
||||||
|
// bizInquiryRequest.setShipToAddress(request.getShipToAddress());
|
||||||
|
// bizInquiryRequests.add(bizInquiryRequest);
|
||||||
|
// }
|
||||||
|
// billingRequestMapper.insertBatch(bizInquiryRequests);
|
||||||
|
//
|
||||||
|
//// remoteMessageService.publishMessage(LoginHelper.getUserId(), "您好,您的询价单创建成功。具体询价单号为:" + bizInquiryRequest.getInquiryNo());
|
||||||
|
//
|
||||||
|
// return R.ok();
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建单个询价单(带分布式锁)
|
||||||
|
*/
|
||||||
|
@DistributedLock(
|
||||||
|
prefix = "inquiry:create",
|
||||||
|
params = {"request.channelId", "request.destination"}, // 从request对象提取字段
|
||||||
|
waitTime = 0,
|
||||||
|
leaseTime = 30
|
||||||
|
)
|
||||||
|
private BizInquiryRequest createSingleInquiry(InquiryRequestItemVo request) {
|
||||||
|
// 参数校验
|
||||||
|
if (request.getChannelId() == null) {
|
||||||
|
throw new RuntimeException("渠道不能为空");
|
||||||
|
}
|
||||||
|
if (request.getDestination() == null) {
|
||||||
|
throw new RuntimeException("目的地不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建询价单对象
|
||||||
|
BizInquiryRequest bizInquiryRequest = new BizInquiryRequest();
|
||||||
|
bizInquiryRequest.setDestination(request.getDestination());
|
||||||
|
bizInquiryRequest.setChannelId(request.getChannelId());
|
||||||
|
bizInquiryRequest.setRequesterName(LoginHelper.getLoginUser().getNickname());
|
||||||
|
bizInquiryRequest.setInquiryNo(SerialNoGenerator.generateInquiryNo());
|
||||||
|
|
||||||
|
// 查询渠道信息
|
||||||
|
BizLogisticsChannelVo channelVo = bizLogisticsChannelService.queryById(request.getChannelId());
|
||||||
|
if (channelVo == null) {
|
||||||
|
throw new RuntimeException("渠道不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置运输时效
|
||||||
|
if ("air".equals(channelVo.getShippingMethod())) {
|
||||||
|
bizInquiryRequest.setEffectiveStartTime(new Date());
|
||||||
|
bizInquiryRequest.setEffectiveEndTime(new Date());
|
||||||
|
} else if ("sea".equals(channelVo.getShippingMethod())) {
|
||||||
|
LocalDate sunday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
|
||||||
|
LocalDate saturday = sunday.plusDays(6);
|
||||||
|
bizInquiryRequest.setEffectiveStartTime(DateUtil.date(sunday));
|
||||||
|
bizInquiryRequest.setEffectiveEndTime(DateUtil.date(saturday));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置其他字段
|
||||||
|
bizInquiryRequest.setChannelName(channelVo.getChannelName());
|
||||||
|
bizInquiryRequest.setTransportChannel(channelVo.getShippingMethod());
|
||||||
|
bizInquiryRequest.setDeadline(LocalDate.now().atTime(11, 0));
|
||||||
|
bizInquiryRequest.setRequesterId(LoginHelper.getUserId());
|
||||||
|
bizInquiryRequest.setQuoteDate(request.getQuoteDate());
|
||||||
|
bizInquiryRequest.setShipToAddress(request.getShipToAddress());
|
||||||
|
|
||||||
|
return bizInquiryRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<String> batchCreateWithItems(List<InquiryRequestItemVo> items) {
|
||||||
|
// 1. 参数校验
|
||||||
|
if (CollectionUtil.isEmpty(items)) {
|
||||||
|
return R.fail("询价单不能为空");
|
||||||
|
}
|
||||||
|
Set<String> shipmentIds = items.stream().map(InquiryRequestItemVo::getShipmentId).collect(Collectors.toSet());
|
||||||
|
bizShipmentPlanService.updateList(shipmentIds, "send");
|
||||||
|
|
||||||
|
// 2. 过滤重复请求(前置校验)
|
||||||
|
List<InquiryRequestItemVo> requests = fiterItemsList(items);
|
||||||
|
if (CollectionUtil.isEmpty(requests)) {
|
||||||
|
return R.warn("已有相同询价单");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 批量创建(每个询价单独立加锁)
|
||||||
|
List<BizInquiryRequest> bizInquiryRequests = new ArrayList<>();
|
||||||
|
for (InquiryRequestItemVo request : requests) {
|
||||||
|
try {
|
||||||
|
BizInquiryRequest item = createSingleInquiry(request);
|
||||||
|
bizInquiryRequests.add(item);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// 捕获锁冲突或业务校验异常
|
||||||
|
return R.fail(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 批量插入(兜底:数据库唯一索引)
|
||||||
|
try {
|
||||||
|
billingRequestMapper.insertBatch(bizInquiryRequests);
|
||||||
|
} catch (DuplicateKeyException e) {
|
||||||
|
log.error("唯一索引拦截重复数据: {}", e.getMessage());
|
||||||
|
return R.fail("存在重复的渠道-目的地组合");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 发送通知(可选)
|
||||||
|
// String inquiryNo = bizInquiryRequests.get(0).getInquiryNo();
|
||||||
|
// remoteMessageService.publishMessage(LoginHelper.getUserId(), "询价单创建成功,单号:" + inquiryNo);
|
||||||
|
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private List<InquiryRequestItemVo> fiterItemsList(List<InquiryRequestItemVo> items) {
|
||||||
|
LambdaQueryWrapper<BizInquiryRequest> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
for (InquiryRequestItemVo item : items) {
|
||||||
|
wrapper.or(w -> w
|
||||||
|
.eq(BizInquiryRequest::getDestination, item.getDestination())
|
||||||
|
.eq(BizInquiryRequest::getChannelId, item.getChannelId())
|
||||||
|
.eq(BizInquiryRequest::getQuoteDate, item.getQuoteDate())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询已存在的记录
|
||||||
|
List<BizInquiryRequest> existingList = baseMapper.selectList(wrapper);
|
||||||
|
|
||||||
|
|
||||||
|
// 将已存在的记录转为 Set 方便快速比对(假设三字段组合唯一)
|
||||||
|
Set<String> existingKeys = existingList.stream()
|
||||||
|
.map(e -> e.getDestination() + "_" + e.getChannelId() + "_" + e.getQuoteDate())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
// 过滤掉重复的待插入数据
|
||||||
|
List<InquiryRequestItemVo> filteredItems = items.stream()
|
||||||
|
.filter(item -> !existingKeys.contains(
|
||||||
|
item.getDestination() + "_" + item.getChannelId() + "_" + item.getQuoteDate()
|
||||||
|
))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return filteredItems;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TableDataInfo<BizInquiryRequestVo> queryWithDesAndChannel(String destination, String channelId, String date) {
|
public TableDataInfo<BizInquiryRequestVo> queryWithDesAndChannel(String destination, String channelId, String date) {
|
||||||
LambdaQueryWrapper<BizInquiryRequest> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<BizInquiryRequest> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
@ -75,7 +75,7 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
|||||||
* @return 物流订单
|
* @return 物流订单
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BizLogisticsOrderVo queryById(Long id){
|
public BizLogisticsOrderVo queryById(Long id) {
|
||||||
return baseMapper.selectVoById(id);
|
return baseMapper.selectVoById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +118,9 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
|||||||
lqw.eq(bo.getShipmentQuantity() != null, BizLogisticsOrder::getShipmentQuantity, bo.getShipmentQuantity());
|
lqw.eq(bo.getShipmentQuantity() != null, BizLogisticsOrder::getShipmentQuantity, bo.getShipmentQuantity());
|
||||||
lqw.eq(bo.getAmazonShelfDate() != null, BizLogisticsOrder::getAmazonShelfDate, bo.getAmazonShelfDate());
|
lqw.eq(bo.getAmazonShelfDate() != null, BizLogisticsOrder::getAmazonShelfDate, bo.getAmazonShelfDate());
|
||||||
lqw.eq(bo.getShelfTimeliness() != null, BizLogisticsOrder::getShelfTimeliness, bo.getShelfTimeliness());
|
lqw.eq(bo.getShelfTimeliness() != null, BizLogisticsOrder::getShelfTimeliness, bo.getShelfTimeliness());
|
||||||
lqw.and(wrapper -> wrapper.eq(BizLogisticsOrder::getCreateBy, LoginHelper.getUserId()).or().eq(BizLogisticsOrder::getLogisticsProviderId, LoginHelper.getUserId()));
|
if (!LoginHelper.isSuperAdmin() && !LoginHelper.isManagerAdmin()) {
|
||||||
|
lqw.and(wrapper -> wrapper.eq(BizLogisticsOrder::getCreateBy, LoginHelper.getUserId()).or().eq(BizLogisticsOrder::getLogisticsProviderId, LoginHelper.getUserId()));
|
||||||
|
}
|
||||||
// Set<Long> roleIdSet = LoginHelper.getLoginUser().getRoles().stream().map(RoleDTO::getRoleId).collect(Collectors.toSet());
|
// Set<Long> roleIdSet = LoginHelper.getLoginUser().getRoles().stream().map(RoleDTO::getRoleId).collect(Collectors.toSet());
|
||||||
// log.info("roleIdSet:{}", roleIdSet);
|
// log.info("roleIdSet:{}", roleIdSet);
|
||||||
// if (roleIdSet.contains(3L)){
|
// if (roleIdSet.contains(3L)){
|
||||||
@ -165,7 +167,7 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
|||||||
/**
|
/**
|
||||||
* 保存前的数据校验
|
* 保存前的数据校验
|
||||||
*/
|
*/
|
||||||
private void validEntityBeforeSave(BizLogisticsOrder entity){
|
private void validEntityBeforeSave(BizLogisticsOrder entity) {
|
||||||
//TODO 做一些数据校验,如唯一约束
|
//TODO 做一些数据校验,如唯一约束
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,10 +180,14 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||||
if(isValid){
|
if (isValid) {
|
||||||
//TODO 做一些业务上的校验,判断是否需要校验
|
//TODO 做一些业务上的校验,判断是否需要校验
|
||||||
}
|
}
|
||||||
return baseMapper.deleteByIds(ids) > 0;
|
boolean b = baseMapper.deleteByIds(ids) > 0;
|
||||||
|
List<BizLogisticsOrder> bizLogisticsOrders = baseMapper.selectByIds(ids);
|
||||||
|
List<String> fbaShipmentids = bizLogisticsOrders.stream().map(BizLogisticsOrder::getFbaShipmentId).collect(Collectors.toList());
|
||||||
|
bizShipmentPlanService.updateStatusbyFbaShipmentIds(fbaShipmentids);
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -225,7 +231,7 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
|||||||
bizLogisticsOrder.setOrderId(SerialNoGenerator.generateOrderNo());
|
bizLogisticsOrder.setOrderId(SerialNoGenerator.generateOrderNo());
|
||||||
|
|
||||||
bizLogisticsOrder.setLogisticsProviderId(quoteVo.getUserId());
|
bizLogisticsOrder.setLogisticsProviderId(quoteVo.getUserId());
|
||||||
String nickName = remoteUserService.selectNicknameById(quoteVo.getUserId());
|
String nickName = remoteUserService.selectNicknameById(quoteVo.getUserId());
|
||||||
bizLogisticsOrder.setLogisticsProviderName(nickName);
|
bizLogisticsOrder.setLogisticsProviderName(nickName);
|
||||||
|
|
||||||
bizLogisticsOrder.setQuoteOrderId(Long.valueOf(bo.getLogicQuoteId()));
|
bizLogisticsOrder.setQuoteOrderId(Long.valueOf(bo.getLogicQuoteId()));
|
||||||
@ -240,7 +246,7 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
|||||||
bizLogisticsOrder.setShipmentQuantity(sum);
|
bizLogisticsOrder.setShipmentQuantity(sum);
|
||||||
|
|
||||||
|
|
||||||
ArrayList<BizLogisticsOrderDetail> orderDetailList = new ArrayList<>();
|
ArrayList<BizLogisticsOrderDetail> orderDetailList = new ArrayList<>();
|
||||||
|
|
||||||
for (BizShipmentTracking bizShipmentTracking : trackingList) {
|
for (BizShipmentTracking bizShipmentTracking : trackingList) {
|
||||||
BizLogisticsOrderDetail detail = new BizLogisticsOrderDetail();
|
BizLogisticsOrderDetail detail = new BizLogisticsOrderDetail();
|
||||||
|
@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
|||||||
import cn.hutool.core.date.DateTime;
|
import cn.hutool.core.date.DateTime;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.asinkj.amz.domain.*;
|
import org.asinkj.amz.domain.*;
|
||||||
import org.asinkj.amz.domain.bo.SysAmazonStoreBo;
|
import org.asinkj.amz.domain.bo.SysAmazonStoreBo;
|
||||||
@ -361,8 +362,11 @@ public class BizShipmentPlanServiceImpl implements IBizShipmentPlanService {
|
|||||||
}
|
}
|
||||||
bizShipmentPlanVo.setBoxQuantity(count);
|
bizShipmentPlanVo.setBoxQuantity(count);
|
||||||
bizShipmentPlanVo.setOrder(bizLogisticsOrder);
|
bizShipmentPlanVo.setOrder(bizLogisticsOrder);
|
||||||
BizLogisticsQuote bizLogisticsQuote = quoteMap.get(bizLogisticsOrder.getQuoteOrderId());
|
if (bizLogisticsOrder != null) {
|
||||||
bizShipmentPlanVo.setQuote(bizLogisticsQuote);
|
BizLogisticsQuote bizLogisticsQuote = quoteMap.get(bizLogisticsOrder.getQuoteOrderId());
|
||||||
|
bizShipmentPlanVo.setQuote(bizLogisticsQuote);
|
||||||
|
}
|
||||||
|
|
||||||
if (CollectionUtil.isNotEmpty(sids)) {
|
if (CollectionUtil.isNotEmpty(sids)) {
|
||||||
String storeName = storeNameMap.get(bizShipmentPlanVo.getSid());
|
String storeName = storeNameMap.get(bizShipmentPlanVo.getSid());
|
||||||
bizShipmentPlanVo.setSellerName(storeName);
|
bizShipmentPlanVo.setSellerName(storeName);
|
||||||
@ -371,4 +375,21 @@ public class BizShipmentPlanServiceImpl implements IBizShipmentPlanService {
|
|||||||
}
|
}
|
||||||
return TableDataInfo.build(bizShipmentPlanOrderVoPage);
|
return TableDataInfo.build(bizShipmentPlanOrderVoPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateStatusbyFbaShipmentIds(List<String> fbaShipmentids) {
|
||||||
|
LambdaUpdateWrapper<BizShipmentPlan> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
||||||
|
lambdaUpdateWrapper.in(BizShipmentPlan::getShipmentId, fbaShipmentids)
|
||||||
|
.set(BizShipmentPlan::getFbaStatus, "ask");
|
||||||
|
baseMapper.update(null,lambdaUpdateWrapper);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateList(Collection<String> list, String status) {
|
||||||
|
LambdaUpdateWrapper<BizShipmentPlan> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
||||||
|
lambdaUpdateWrapper.in(BizShipmentPlan::getShipmentId, list)
|
||||||
|
.set(BizShipmentPlan::getFbaStatus, "send");
|
||||||
|
baseMapper.update(null,lambdaUpdateWrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package org.asinkj.common.redis.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.METHOD) // 标注在方法上
|
||||||
|
@Retention(RetentionPolicy.RUNTIME) // 运行时生效
|
||||||
|
public @interface DistributedLock {
|
||||||
|
/**
|
||||||
|
* 锁的Key前缀(默认使用方法名)
|
||||||
|
*/
|
||||||
|
String prefix() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待锁时间(秒),0表示不等待
|
||||||
|
*/
|
||||||
|
long waitTime() default 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 锁持有时间(秒)
|
||||||
|
*/
|
||||||
|
long leaseTime() default 30;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务唯一标识参数名(从方法参数中提取)
|
||||||
|
* 例如:params = {"channelId", "destination"}
|
||||||
|
*/
|
||||||
|
String[] params() default {};
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package org.asinkj.common.redis.aspect;
|
||||||
|
|
||||||
|
import org.asinkj.common.redis.annotation.DistributedLock;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.asinkj.common.redis.utils.RedisUtils;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.springframework.expression.Expression;
|
||||||
|
import org.springframework.expression.ExpressionParser;
|
||||||
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||||
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class DistributedLockAspect {
|
||||||
|
|
||||||
|
private final ExpressionParser parser = new SpelExpressionParser();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 环绕通知,拦截被 @DistributedLock 注解的方法
|
||||||
|
*/
|
||||||
|
@Around("@annotation(distributedLock)")
|
||||||
|
public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
|
||||||
|
// 1. 生成分布式锁Key
|
||||||
|
String lockKey = generateLockKey(joinPoint, distributedLock);
|
||||||
|
|
||||||
|
// 2. 获取 Redisson 锁对象
|
||||||
|
RLock lock = RedisUtils.getClient().getLock(lockKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 3. 尝试加锁
|
||||||
|
boolean isLocked = lock.tryLock(distributedLock.waitTime(), distributedLock.leaseTime(), TimeUnit.SECONDS);
|
||||||
|
if (!isLocked) {
|
||||||
|
throw new RuntimeException("系统繁忙,请稍后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 执行目标方法(业务逻辑)
|
||||||
|
return joinPoint.proceed();
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// 5. 释放锁
|
||||||
|
if (lock.isHeldByCurrentThread()) {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成锁的Key(格式:prefix:param1_value:param2_value)
|
||||||
|
*/
|
||||||
|
private String generateLockKey(ProceedingJoinPoint joinPoint, DistributedLock lock) {
|
||||||
|
// 获取方法参数名和值
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
String[] paramNames = signature.getParameterNames();
|
||||||
|
Object[] args = joinPoint.getArgs();
|
||||||
|
|
||||||
|
// 解析业务唯一标识参数值
|
||||||
|
StringBuilder keyBuilder = new StringBuilder();
|
||||||
|
if (lock.prefix().isEmpty()) {
|
||||||
|
keyBuilder.append(joinPoint.getSignature().getName()); // 默认用方法名
|
||||||
|
} else {
|
||||||
|
keyBuilder.append(lock.prefix());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String param : lock.params()) {
|
||||||
|
Object value = getParamValue(param, paramNames, args);
|
||||||
|
keyBuilder.append(":").append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据参数名获取参数值(支持SpEL表达式)
|
||||||
|
*/
|
||||||
|
private Object getParamValue(String param, String[] paramNames, Object[] args) {
|
||||||
|
// 检查是否是SpEL表达式(例如 #request.channelId)
|
||||||
|
if (param.startsWith("#")) {
|
||||||
|
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||||
|
for (int i = 0; i < paramNames.length; i++) {
|
||||||
|
context.setVariable(paramNames[i], args[i]);
|
||||||
|
}
|
||||||
|
Expression exp = parser.parseExpression(param);
|
||||||
|
return exp.getValue(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 普通参数名匹配
|
||||||
|
for (int i = 0; i < paramNames.length; i++) {
|
||||||
|
if (param.equals(paramNames[i])) {
|
||||||
|
return args[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("未找到参数: " + param);
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,9 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -545,4 +547,22 @@ public class RedisUtils {
|
|||||||
RKeys rKeys = CLIENT.getKeys();
|
RKeys rKeys = CLIENT.getKeys();
|
||||||
return rKeys.countExists(key) > 0;
|
return rKeys.countExists(key) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T executeWithLock(String lockKey, Supplier<T> supplier,
|
||||||
|
long waitTime, long leaseTime) {
|
||||||
|
RLock lock = RedisUtils.getClient().getLock(lockKey);
|
||||||
|
try {
|
||||||
|
if (lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS)) {
|
||||||
|
return supplier.get(); // 执行核心业务逻辑
|
||||||
|
}
|
||||||
|
throw new RuntimeException("获取锁失败");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new RuntimeException("锁等待被中断");
|
||||||
|
} finally {
|
||||||
|
if (lock.isHeldByCurrentThread()) {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user