7 Commits

  1. 2
      src/main/java/com/example/demo/DemoApplication.java
  2. 89
      src/main/java/com/example/demo/Util/ProductRemoteClient.java
  3. 74
      src/main/java/com/example/demo/config/MarketConverter.java
  4. 82
      src/main/java/com/example/demo/config/OrderStatusConverter.java
  5. 60
      src/main/java/com/example/demo/config/RefundModelConverter.java
  6. 6
      src/main/java/com/example/demo/controller/coin/GeneralController.java
  7. 29
      src/main/java/com/example/demo/domain/DTO/ProductDTO.java
  8. 13
      src/main/java/com/example/demo/domain/vo/bean/BeanConsumeCart.java
  9. 5
      src/main/java/com/example/demo/domain/vo/bean/BeanConsumeCartVo.java
  10. 21
      src/main/java/com/example/demo/domain/vo/cash/CashRecordDTO.java
  11. 3
      src/main/java/com/example/demo/mapper/bean/BeanConsumeMapper.java
  12. 7
      src/main/java/com/example/demo/mapper/coin/BeanRechargeMapper1.java
  13. 11
      src/main/java/com/example/demo/mapper/coin/GeneralMapper.java
  14. 2
      src/main/java/com/example/demo/service/coin/GeneralService.java
  15. 5
      src/main/java/com/example/demo/serviceImpl/bean/BeanConsumeServiceImpl.java
  16. 2
      src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java
  17. 48
      src/main/java/com/example/demo/serviceImpl/coin/GeneralServiceImpl.java
  18. 46
      src/main/java/com/example/demo/serviceImpl/coin/RechargeActivityCenterServiceImpl.java
  19. 19
      src/main/resources/cashMapper/CashRefundMapper.xml
  20. 9
      src/main/resources/cashMapper/MessageMapper.xml
  21. 6
      src/main/resources/jindouMapper/BeanConsumeMapper.xml
  22. 10
      src/main/resources/mapper/BeanRechargeMapper1.xml
  23. 33
      src/main/resources/mapper/GeneralMapper.xml

2
src/main/java/com/example/demo/DemoApplication.java

@ -19,7 +19,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
public class DemoApplication { public class DemoApplication {
public static void main(String[] args) { public static void main(String[] args) {
System.setProperty("https.protocols", "TLSv1");
System.setProperty("https.protocols", "TLSv1,TLSv1.2,TLSv1.3");
SpringApplication.run(DemoApplication.class, args); SpringApplication.run(DemoApplication.class, args);
} }

89
src/main/java/com/example/demo/Util/ProductRemoteClient.java

@ -0,0 +1,89 @@
package com.example.demo.Util;
import com.example.demo.domain.DTO.ProductDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j
@Component
@RequiredArgsConstructor
public class ProductRemoteClient {
private final RestTemplate restTemplate;
/**
* 获取远端全部商品全量
*/
public List<ProductDTO> fetchAll() {
// 1. 去掉 url 尾部空格
String url = "https://api.homilychart.com/live_mall/api/product/all";
// 2. 构造日志
log.info("[ProductRemote] 开始拉取远端全量商品");
try {
// 3. 指定返回类型避免 Map Raw Type 警告
ResponseEntity<Map> resp =
restTemplate.getForEntity(url, Map.class);
// 4. 状态码校验
if (resp.getStatusCode() != HttpStatus.OK || resp.getBody() == null) {
throw new RuntimeException("远端返回异常,状态码:" + resp.getStatusCode());
}
// 5. 安全取值
Object dataObj = resp.getBody().get("data");
if (!(dataObj instanceof List)) {
throw new RuntimeException("远端 data 字段不是数组");
}
List<Map<String, Object>> data = (List<Map<String, Object>>) dataObj;
// 6. 空数组直接返回避免 NPE
if (data.isEmpty()) {
log.warn("[ProductRemote] 远端返回空数组");
return Collections.emptyList();
}
// 7. 映射 + 空指针保护
long now = System.currentTimeMillis();
return data.stream()
.filter(Objects::nonNull) // 过滤 null 元素
.map(m -> {
ProductDTO dto = new ProductDTO();
dto.setId((Integer) m.get("id"));
dto.setName((String) m.get("name"));
dto.setCover((String) m.get("cover"));
Object priceObj = m.get("price");
dto.setPrice(priceObj != null ? new BigDecimal(priceObj.toString()) : BigDecimal.ZERO);
dto.setUpdatedAt(now);
return dto;
})
.collect(Collectors.toList());
} catch (ResourceAccessException e) {
// 网络/超时异常
log.error("拉取商品失败,真实原因:", e);
throw new RuntimeException("拉取商品失败:" + e.getMessage(), e);
} catch (RestClientException e) {
// 4xx/5xx/解析异常
log.error("[ProductRemote] 远端异常:{}", e.getMessage());
throw new RuntimeException("拉取商品失败:远端返回异常", e);
} catch (Exception e) {
// 兜底
log.error("[ProductRemote] 未知异常", e);
throw new RuntimeException("拉取商品失败:未知错误", e);
}}
}

74
src/main/java/com/example/demo/config/MarketConverter.java

@ -0,0 +1,74 @@
package com.example.demo.config;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import java.util.HashMap;
import java.util.Map;
/**
* 所属地区转换器Integer地区ID 地区名称EasyExcel导出用
*/
public class MarketConverter implements Converter<Integer> {
// 地区ID 地区名称 映射表从数据库表中提取
private static final Map<Integer, String> MARKET_MAP = new HashMap<>();
static {
// 初始化映射关系严格对应数据库表中的id和name
MARKET_MAP.put(1, "Capt");
MARKET_MAP.put(2, "公司");
MARKET_MAP.put(3, "市场部");
MARKET_MAP.put(4, "新加坡");
MARKET_MAP.put(5, "马来西亚");
MARKET_MAP.put(9, "研发部");
MARKET_MAP.put(999, "总部");
MARKET_MAP.put(24016, "加拿大");
MARKET_MAP.put(24018, "泰国");
MARKET_MAP.put(24022, "越南HCM");
MARKET_MAP.put(24027, "韩国");
MARKET_MAP.put(24028, "深圳运营");
MARKET_MAP.put(24030, "非网");
MARKET_MAP.put(24031, "其他");
MARKET_MAP.put(24032, "市场部");
}
/**
* 支持的Java类型Integer与market字段类型一致
*/
@Override
public Class<?> supportJavaTypeKey() {
return Integer.class;
}
/**
* Excel单元格数据类型字符串显示地区名称
*/
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
/**
* 导出时Integer地区ID 地区名称
*/
@Override
public WriteCellData<?> convertToExcelData(Integer marketId, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
// 未匹配到的ID显示未知地区ID值便于排查异常
String marketName = MARKET_MAP.getOrDefault(marketId, "未知地区(" + marketId + ")");
return new WriteCellData<>(marketName);
}
/**
* 导入时地区名称 Integer地区ID可选实现如需导入可启用
*/
@Override
public Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
// 若需支持导入可实现反向映射此处仅导出用返回null即可
return null;
}
}

82
src/main/java/com/example/demo/config/OrderStatusConverter.java

@ -0,0 +1,82 @@
package com.example.demo.config;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import java.util.HashMap;
import java.util.Map;
/**
* 订单状态转换器Integer值 中文描述EasyExcel导出用
*/
public class OrderStatusConverter implements Converter<Integer> {
// 状态值 中文描述 映射表严格对应注释中的状态
private static final Map<Integer, String> STATUS_MAP = new HashMap<>();
static {
// 初始化映射关系复制注释中的状态避免遗漏
STATUS_MAP.put(0, "线下财务待审核");
STATUS_MAP.put(1, "线下财务审核通过待填手续费");
STATUS_MAP.put(2, "线下财务审核驳回");
STATUS_MAP.put(5, "手动撤回待编辑提交");
STATUS_MAP.put(3, "link线上财务复核待填手续费");
STATUS_MAP.put(4, "收款流程全部结束");
STATUS_MAP.put(6, "退款");
STATUS_MAP.put(10, "地区财务待审核");
STATUS_MAP.put(11, "地区财务手动撤回待编辑提交");
STATUS_MAP.put(12, "地区财务驳回");
STATUS_MAP.put(20, "地区负责人待审核");
STATUS_MAP.put(22, "地区负责人驳回");
STATUS_MAP.put(30, "总部财务待审核");
STATUS_MAP.put(32, "总部财务驳回");
STATUS_MAP.put(40, "执行人待处理");
STATUS_MAP.put(41, "执行人已处理,退款结束");
}
/**
* 支持的Java类型Integer与status字段类型一致
*/
@Override
public Class<?> supportJavaTypeKey() {
return Integer.class;
}
/**
* Excel单元格数据类型字符串显示中文描述
*/
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
/**
* 导出时Integer状态值 中文描述
*/
@Override
public WriteCellData<?> convertToExcelData(Integer status, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
// 未匹配到的状态显示未知状态避免导出空值
String statusDesc = STATUS_MAP.getOrDefault(status, "未知状态(" + status + ")");
return new WriteCellData<>(statusDesc);
}
/**
* 导入时中文描述 Integer状态值可选实现如需导入可启用
*/
@Override
public Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
String statusDesc = cellData.getStringValue();
// 反向映射根据中文描述找状态值如果需要导入功能
for (Map.Entry<Integer, String> entry : STATUS_MAP.entrySet()) {
if (entry.getValue().equals(statusDesc)) {
return entry.getKey();
}
}
// 未匹配到返回null或自定义默认值
return null;
}
}

60
src/main/java/com/example/demo/config/RefundModelConverter.java

@ -0,0 +1,60 @@
package com.example.demo.config;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import java.util.HashMap;
import java.util.Map;
/**
* 退款方式转换器0全额1部分EasyExcel导出用
*/
public class RefundModelConverter implements Converter<Integer> {
// 退款方式映射表严格对应0=全额1=部分
private static final Map<Integer, String> REFUND_MODEL_MAP = new HashMap<>();
static {
REFUND_MODEL_MAP.put(0, "全额");
REFUND_MODEL_MAP.put(1, "部分");
}
@Override
public Class<?> supportJavaTypeKey() {
return Integer.class; // 支持的Java类型与refundModel字段类型一致
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING; // Excel显示为字符串中文描述
}
/**
* 导出时Integer值 中文描述
*/
@Override
public WriteCellData<?> convertToExcelData(Integer refundModel, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
// 未匹配到的异常值如2null等显示未知退款方式便于排查
String desc = REFUND_MODEL_MAP.getOrDefault(refundModel, "未知退款方式(" + (refundModel == null ? "null" : refundModel) + ")");
return new WriteCellData<>(desc);
}
/**
* 导入时中文描述 Integer值可选实现如需导入可启用
*/
@Override
public Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
String desc = cellData.getStringValue();
// 反向映射根据中文找对应数值
for (Map.Entry<Integer, String> entry : REFUND_MODEL_MAP.entrySet()) {
if (entry.getValue().equals(desc)) {
return entry.getKey();
}
}
return null; // 未匹配返回null可根据业务调整默认值
}
}

6
src/main/java/com/example/demo/controller/coin/GeneralController.java

@ -86,4 +86,10 @@ public class GeneralController {
{ {
return Result.success(generalService.getRate()); return Result.success(generalService.getRate());
} }
//手动同步link商品表
@PostMapping("/syncLinkProducts")
public void syncLinkProducts(){
generalService.fullSyncProducts();
}
} }

29
src/main/java/com/example/demo/domain/DTO/ProductDTO.java

@ -0,0 +1,29 @@
package com.example.demo.domain.DTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.poi.hpsf.Decimal;
import java.math.BigDecimal;
/**
* @program: gold-java
* @ClassName ProductDTO
* @description:
* @author: Ethan
* @create: 202511-21 10:54
* @Version 1.0
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductDTO {
private Integer id; //id
private String name; //商品名
private String cover;
private BigDecimal price; //价格
private Long updatedAt;
private Long syncTime; //更新
}

13
src/main/java/com/example/demo/domain/vo/bean/BeanConsumeCart.java

@ -2,6 +2,7 @@ package com.example.demo.domain.vo.bean;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.netty.util.collection.LongObjectHashMap;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -54,10 +55,10 @@ public class BeanConsumeCart {
private String transactionNo; // 备用交易号 private String transactionNo; // 备用交易号
private Integer productVersion; // 1半年 2终免 private Integer productVersion; // 1半年 2终免
private Integer autoUpdate; // 是否同步过 0否 1是 private Integer autoUpdate; // 是否同步过 0否 1是
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime createdAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime updatedAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime tradeTime; // 支付成功时间
private Long createdAt;
private Long updatedAt;
private Long tradeTime; // 支付成功时间
} }

5
src/main/java/com/example/demo/domain/vo/bean/BeanConsumeCartVo.java

@ -29,6 +29,7 @@ public class BeanConsumeCartVo {
private BigDecimal totalMoney; // 应付金额 private BigDecimal totalMoney; // 应付金额
private String liveName; // 直播间名称 private String liveName; // 直播间名称
private String sourceName; // 班级或频道名称 private String sourceName; // 班级或频道名称
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime tradeTime; // 支付成功时间
private Long tradeTime; // 支付成功时间
private Long createdAt; // 创建时间
} }

21
src/main/java/com/example/demo/domain/vo/cash/CashRecordDTO.java

@ -2,6 +2,9 @@ package com.example.demo.domain.vo.cash;
import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.example.demo.config.MarketConverter;
import com.example.demo.config.OrderStatusConverter;
import com.example.demo.config.RefundModelConverter;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@ -26,11 +29,11 @@ import java.util.List;
public class CashRecordDTO{ public class CashRecordDTO{
@ExcelIgnore @ExcelIgnore
private String activity;// 活动 private String activity;// 活动
@ExcelProperty("品名称")
@ExcelProperty("品名称")
private String goodsName;// 商品名称 private String goodsName;// 商品名称
@ExcelProperty("品数量")
@ExcelProperty("品数量")
private Integer goodsNum;// 商品数量 private Integer goodsNum;// 商品数量
@ExcelProperty("品单位")
@ExcelProperty("品单位")
private String numUnit;// 商品单位 private String numUnit;// 商品单位
@ExcelIgnore @ExcelIgnore
private BigDecimal gold;//永久金币 private BigDecimal gold;//永久金币
@ -93,15 +96,15 @@ public class CashRecordDTO{
/** /**
* 姓名 * 姓名
*/ */
@ExcelProperty("姓名")
private String userName;
@ExcelIgnore @ExcelIgnore
private String userName;
@ExcelProperty("姓名")
private String name; private String name;
/** /**
* 所属地区 * 所属地区
*/ */
@ExcelProperty("所属地区")
@ExcelProperty(value = "所属地区",converter = MarketConverter.class)
private Integer market; private Integer market;
/** /**
@ -146,7 +149,7 @@ public class CashRecordDTO{
30总部财务待审核32总部财务驳回 30总部财务待审核32总部财务驳回
40执行人待处理41执行人已处理退款结束 40执行人待处理41执行人已处理退款结束
*/ */
@ExcelProperty("订单状态")
@ExcelProperty(value="订单状态",converter = OrderStatusConverter.class)
private Integer status; private Integer status;
/** /**
@ -182,13 +185,13 @@ public class CashRecordDTO{
/** /**
* 退款备注理由,客服填写 * 退款备注理由,客服填写
*/ */
@ExcelProperty("退款备注")
@ExcelProperty("退款理由")
private String refundReason; private String refundReason;
/** /**
* 退款方式0全额/1部分 * 退款方式0全额/1部分
*/ */
@ExcelProperty("退款方式")
@ExcelProperty(value = "退款方式",converter = RefundModelConverter.class)
private Integer refundModel; private Integer refundModel;
/** /**

3
src/main/java/com/example/demo/mapper/bean/BeanConsumeMapper.java

@ -25,8 +25,7 @@ public interface BeanConsumeMapper {
List<BeanConsumeFan> selectFanBy(@Param("beanConsumeFan") BeanConsumeFan beanConsumeFan); List<BeanConsumeFan> selectFanBy(@Param("beanConsumeFan") BeanConsumeFan beanConsumeFan);
//筛选查询文章消费 //筛选查询文章消费
List<BeanConsumeArticle> selectArticleBy(@Param("beanConsumeArticle") BeanConsumeArticle beanConsumeArticle); List<BeanConsumeArticle> selectArticleBy(@Param("beanConsumeArticle") BeanConsumeArticle beanConsumeArticle);
//筛选查询小黄车消费
List<BeanConsumeCartVo> selectCartBy(BeanConsumeCart beanConsumeCart);
//查询金豆直播消费金额 //查询金豆直播消费金额
BeanConsumeGold selectSumLiveBy(@Param("beanConsumeLive") BeanConsumeLive beanConsumeLive); BeanConsumeGold selectSumLiveBy(@Param("beanConsumeLive") BeanConsumeLive beanConsumeLive);
//查询金豆铁粉消费金额 //查询金豆铁粉消费金额

7
src/main/java/com/example/demo/mapper/coin/BeanRechargeMapper1.java

@ -1,9 +1,13 @@
package com.example.demo.mapper.coin; package com.example.demo.mapper.coin;
import com.example.demo.domain.vo.bean.BeanConsumeCart;
import com.example.demo.domain.vo.bean.BeanConsumeCartVo;
import com.example.demo.domain.vo.bean.BeanRecharge; import com.example.demo.domain.vo.bean.BeanRecharge;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/** /**
* @program: gold-java * @program: gold-java
* @ClassName BeanRechargeMapper * @ClassName BeanRechargeMapper
@ -15,6 +19,7 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface BeanRechargeMapper1 { public interface BeanRechargeMapper1 {
//筛选查询小黄车消费
List<BeanConsumeCartVo> selectCartBy(BeanConsumeCart beanConsumeCart);
int add(BeanRecharge recharge); int add(BeanRecharge recharge);
} }

11
src/main/java/com/example/demo/mapper/coin/GeneralMapper.java

@ -1,9 +1,13 @@
package com.example.demo.mapper.coin; package com.example.demo.mapper.coin;
import com.example.demo.domain.DTO.ProductDTO;
import com.example.demo.domain.entity.Rate; import com.example.demo.domain.entity.Rate;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* @program: GOLD * @program: GOLD
@ -31,4 +35,11 @@ public interface GeneralMapper {
List<String> getAllRoleMarket(); List<String> getAllRoleMarket();
List<Rate> getRate(); List<Rate> getRate();
//查找最新更新时间
Long maxUpdatedAt();
// 批量插入
void replaceBatch(@Param("list") List<ProductDTO> list,
@Param("syncTime") long syncTime);
//删除已删掉的产品
void deleteNotIn(@Param("ids") Collection<Integer> ids);
} }

2
src/main/java/com/example/demo/service/coin/GeneralService.java

@ -43,4 +43,6 @@ public interface GeneralService {
List<String> getAllRoleMarket(); List<String> getAllRoleMarket();
//获取汇率 //获取汇率
List<Rate> getRate(); List<Rate> getRate();
void fullSyncProducts();
} }

5
src/main/java/com/example/demo/serviceImpl/bean/BeanConsumeServiceImpl.java

@ -5,6 +5,7 @@ import com.example.demo.domain.vo.bean.*;
import com.example.demo.domain.vo.coin.*; import com.example.demo.domain.vo.coin.*;
import com.example.demo.mapper.bean.BeanConsumeMapper; import com.example.demo.mapper.bean.BeanConsumeMapper;
import com.example.demo.mapper.bean.BeanUserMapper; import com.example.demo.mapper.bean.BeanUserMapper;
import com.example.demo.mapper.coin.BeanRechargeMapper1;
import com.example.demo.mapper.coin.UserMapper; import com.example.demo.mapper.coin.UserMapper;
import com.example.demo.mapper.live.LiveMapper; import com.example.demo.mapper.live.LiveMapper;
import com.example.demo.service.bean.BeanConsumeService; import com.example.demo.service.bean.BeanConsumeService;
@ -42,6 +43,8 @@ public class BeanConsumeServiceImpl implements BeanConsumeService {
@Autowired @Autowired
private LiveMapper liveMapper; private LiveMapper liveMapper;
@Autowired @Autowired
private BeanRechargeMapper1 beanRechargeMapper1;
@Autowired
private UserMapper userMapper; private UserMapper userMapper;
@Autowired @Autowired
private RestTemplate restTemplate; private RestTemplate restTemplate;
@ -176,7 +179,7 @@ public class BeanConsumeServiceImpl implements BeanConsumeService {
@Override @Override
public Object selectCartBy(Integer pageNum, Integer pageSize, BeanConsumeCart beanConsumeCart) { public Object selectCartBy(Integer pageNum, Integer pageSize, BeanConsumeCart beanConsumeCart) {
PageHelper.startPage(pageNum, pageSize); PageHelper.startPage(pageNum, pageSize);
List<BeanConsumeCartVo> beanConsumeCarts = beanConsumeMapper.selectCartBy(beanConsumeCart);
List<BeanConsumeCartVo> beanConsumeCarts = beanRechargeMapper1.selectCartBy(beanConsumeCart);
return new PageInfo<>(beanConsumeCarts); return new PageInfo<>(beanConsumeCarts);
} }
@Override @Override

2
src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java

@ -206,7 +206,7 @@ public class CashRefundServiceImpl implements RefundService {
message.setStatus(cashRecordRefund.getStatus()); message.setStatus(cashRecordRefund.getStatus());
message.setDesc(cashRecordRefund.getJwcode()+"用户有条退款订单需审核"); message.setDesc(cashRecordRefund.getJwcode()+"用户有条退款订单需审核");
message.setTitle("现金退款--新增退款"); message.setTitle("现金退款--新增退款");
message.setType(1);
message.setType(0);
message.setTypeId(cashRecordRefund.getId()); message.setTypeId(cashRecordRefund.getId());
message.setMarket(Integer.valueOf(cashRecordRefund.getMarket())); message.setMarket(Integer.valueOf(cashRecordRefund.getMarket()));
rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message); rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);

48
src/main/java/com/example/demo/serviceImpl/coin/GeneralServiceImpl.java

@ -1,17 +1,22 @@
package com.example.demo.serviceImpl.coin; package com.example.demo.serviceImpl.coin;
import com.example.demo.Util.ProductRemoteClient;
import com.example.demo.domain.DTO.ProductDTO;
import com.example.demo.domain.entity.Rate; import com.example.demo.domain.entity.Rate;
import com.example.demo.mapper.coin.GeneralMapper; import com.example.demo.mapper.coin.GeneralMapper;
import com.example.demo.service.coin.GeneralService; import com.example.demo.service.coin.GeneralService;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -28,8 +33,15 @@ import java.util.stream.Collectors;
public class GeneralServiceImpl implements GeneralService { public class GeneralServiceImpl implements GeneralService {
private static final Logger log = LoggerFactory.getLogger(GeneralServiceImpl.class); private static final Logger log = LoggerFactory.getLogger(GeneralServiceImpl.class);
private final ProductRemoteClient remoteClient;
@Autowired @Autowired
private GeneralMapper generalMapper; private GeneralMapper generalMapper;
public GeneralServiceImpl(ProductRemoteClient remoteClient) {
this.remoteClient = remoteClient;
}
@Override @Override
public List<String> getMarket() { public List<String> getMarket() {
List<String> list = generalMapper.getMarket(); List<String> list = generalMapper.getMarket();
@ -220,4 +232,40 @@ public class GeneralServiceImpl implements GeneralService {
List<Rate> list = generalMapper.getRate(); List<Rate> list = generalMapper.getRate();
return list; return list;
} }
@Override
@Scheduled(cron = "0 0 2 * * *") // 02:00
public void fullSyncProducts() {
StopWatch sw = StopWatch.createStarted();
log.info("【全量商品同步】开始");
try {
// 1. 拉取远端全量
List<ProductDTO> remoteList = remoteClient.fetchAll();
if (remoteList.isEmpty()) {
log.warn("远端无数据,跳过");
return;
}
Map<Integer, ProductDTO> remoteMap = remoteList.stream()
.collect(Collectors.toMap(ProductDTO::getId, Function.identity()));
// 2. 覆盖本地含新增 & 修改
long syncTime = System.currentTimeMillis();
generalMapper.replaceBatch(remoteList, syncTime);
// 3. 删除本地已下架的品
Set<Integer> remoteIds = remoteMap.keySet();
generalMapper.deleteNotIn(remoteIds);
// 4. 统计
int total = remoteList.size();
log.info("【全量商品同步】完成,远端 {} 条,本地覆盖 {} 条,耗时 {} ms",
total, total, sw.getTime());
} catch (Exception e) {
log.error("【全量商品同步】失败", e);
// 可钉钉/邮件告警
}
}
} }

46
src/main/java/com/example/demo/serviceImpl/coin/RechargeActivityCenterServiceImpl.java

@ -29,7 +29,7 @@ public class RechargeActivityCenterServiceImpl implements RechargeActivityCenter
@Autowired @Autowired
private RechargeActivityCenterMapper rechargeActivityCenterMapper; private RechargeActivityCenterMapper rechargeActivityCenterMapper;
private static final String ACTIVITY_NAME_REGEX = "^[\\u4e00-\\u9fa5a-zA-Z0-9,。!?、;:\"'()《》【】——~,.:;!'()\\[\\]-_&+=]{1,100}$";
private static final String ACTIVITY_NAME_REGEX = "^[\\u4e00-\\u9fa5a-zA-Z0-9,。!?、;:\"'‘’“”()《》【】——~,.:;!()\\[\\]-_&+=]{1,100}$";
private static final Pattern ACTIVITY_NAME_PATTERN = Pattern.compile(ACTIVITY_NAME_REGEX); private static final Pattern ACTIVITY_NAME_PATTERN = Pattern.compile(ACTIVITY_NAME_REGEX);
// 根据ID查询活动 // 根据ID查询活动
@Override @Override
@ -43,35 +43,51 @@ public class RechargeActivityCenterServiceImpl implements RechargeActivityCenter
// 新增活动 // 新增活动
@Override @Override
public void addActivity(RechargeActivity activity) { public void addActivity(RechargeActivity activity) {
String activityName = activity.getActivityName();
if (activity.getActivityName().length() > 100) {
// 1. 长度校验
if (activityName.length() > 100) {
throw new IllegalArgumentException("活动名称不能超过100个字符"); throw new IllegalArgumentException("活动名称不能超过100个字符");
} }
// 2. 名称重复校验
RechargeActivity activityByName = rechargeActivityCenterMapper.queryActivityByName(activity); RechargeActivity activityByName = rechargeActivityCenterMapper.queryActivityByName(activity);
if (activityByName != null) { if (activityByName != null) {
throw new IllegalArgumentException("活动名称已存在"); throw new IllegalArgumentException("活动名称已存在");
} }
// 3. 字符格式校验
if (!ACTIVITY_NAME_PATTERN.matcher(activity.getActivityName()).matches()) {
throw new IllegalArgumentException("活动名称仅允许包含汉字、英文字母、数字及常见标点符号(中英文标点:,。!?、;:\"'()《》【】——~,.:;!'()[]-_&+=)");
// 3. 字符格式校验提取非法字符
if (!ACTIVITY_NAME_PATTERN.matcher(activityName).matches()) {
// 反向匹配提取所有不符合规则的字符
StringBuilder illegalChars = new StringBuilder();
for (char c : activityName.toCharArray()) {
if (!ACTIVITY_NAME_PATTERN.matcher(String.valueOf(c)).matches()) {
// 去重避免重复输出同一非法字符
if (illegalChars.indexOf(String.valueOf(c)) == -1) {
illegalChars.append(c).append("、");
}
}
}
// 去除最后一个顿号拼接提示信息
String illegalStr = illegalChars.deleteCharAt(illegalChars.length() - 1).toString();
throw new IllegalArgumentException(
String.format("活动名称包含非法字符:%s,仅允许包含汉字、英文字母、数字及常见标点符号(中英文标点:,。!?、;:\"'‘’“”()《》【】——~,.:;!()[]-_&+=)", illegalStr)
);
} }
// 4. 时间范围判断设置对应状态
Date startTime = activity.getStartTime(); Date startTime = activity.getStartTime();
Date endTime = activity.getEndTime(); Date endTime = activity.getEndTime();
Date now = new Date(); // 当前系统本地时间
//获取当前系统时间本地时间与活动时间时区保持一致
Date now = new Date();
//时间范围判断设置对应状态
if (now.before(startTime)) { if (now.before(startTime)) {
// 当前时间 < 开始时间 未开始状态0
activity.setStatus("0");
activity.setStatus("0"); // 未开始
} else if (now.after(endTime)) { } else if (now.after(endTime)) {
// 当前时间 > 结束时间 已结束状态2
activity.setStatus("2");
activity.setStatus("2"); // 已结束
} else { } else {
// 开始时间 当前时间 结束时间 进行中状态1
activity.setStatus("1");
activity.setStatus("1"); // 进行中
} }
rechargeActivityCenterMapper.addActivity(activity); rechargeActivityCenterMapper.addActivity(activity);
} }

19
src/main/resources/cashMapper/CashRefundMapper.xml

@ -173,7 +173,7 @@
and crr.status = #{status} and crr.status = #{status}
</if> </if>
<if test="name != null and name.length() > 0"> <if test="name != null and name.length() > 0">
and crr.name = #{name}
and crr.name like CONCAT('%', #{name}, '%')
</if> </if>
<if test="jwcode != null"> <if test="jwcode != null">
and crr.jwcode = #{jwcode} and crr.jwcode = #{jwcode}
@ -250,7 +250,7 @@
and crr.status = #{status} and crr.status = #{status}
</if> </if>
<if test="name != null and name.length() > 0"> <if test="name != null and name.length() > 0">
and crr.name = #{name}
and crr.name like CONCAT('%', #{name}, '%')
</if> </if>
<if test="jwcode != null"> <if test="jwcode != null">
and crr.jwcode = #{jwcode} and crr.jwcode = #{jwcode}
@ -271,11 +271,14 @@
AND crc.payment_currency LIKE CONCAT('%', #{paymentCurrency}, '%') AND crc.payment_currency LIKE CONCAT('%', #{paymentCurrency}, '%')
</if> </if>
<if test="goodsNames!= null and goodsNames.size > 0">
AND crc.goods_name IN
<foreach collection="goodsNames" item="goodsNames" open="(" separator="," close=")">
#{goodsNames}
</foreach>
<!-- <if test="goodsNames!= null and goodsNames.size > 0">-->
<!-- AND crc.goods_name IN-->
<!-- <foreach collection="goodsNames" item="goodsNames" open="(" separator="," close=")">-->
<!-- #{goodsNames}-->
<!-- </foreach>-->
<!-- </if>-->
<if test="goodsName!= null and goodsName.length() > 0">
and crc.goods_name = #{goodsName}
</if> </if>
<if test="payType != null and payType.length()>0"> <if test="payType != null and payType.length()>0">
and crc.pay_type = #{payType} and crc.pay_type = #{payType}
@ -337,7 +340,7 @@
and crr.status = #{status} and crr.status = #{status}
</if> </if>
<if test="name != null and name.length() > 0"> <if test="name != null and name.length() > 0">
and crr.name = #{name}
and crr.name like CONCAT('%', #{name}, '%')
</if> </if>
<if test="jwcode != null"> <if test="jwcode != null">
and crr.jwcode = #{jwcode} and crr.jwcode = #{jwcode}

9
src/main/resources/cashMapper/MessageMapper.xml

@ -10,6 +10,7 @@
SELECT id, jwcode, name, title, `desc`, status, market,type, type_id,flag,cz_time SELECT id, jwcode, name, title, `desc`, status, market,type, type_id,flag,cz_time
FROM message FROM message
<where> <where>
flag=0
<choose> <choose>
<when test="markets != null and markets.size() > 0"> <when test="markets != null and markets.size() > 0">
market IN market IN
@ -18,6 +19,14 @@
</foreach> </foreach>
</when> </when>
</choose> </choose>
<choose>
<when test="sortField != null and sortField.length > 0 or sortOrder != null and sortOrder.length > 0">
ORDER BY ${sortField} ${sortOrder}
</when>
<otherwise>
ORDER BY cz_time DESC
</otherwise>
</choose>
</where> </where>
</select> </select>
</mapper> </mapper>

6
src/main/resources/jindouMapper/BeanConsumeMapper.xml

@ -329,11 +329,7 @@
</choose> </choose>
) as t ) as t
</select> </select>
<!--筛选查询小黄车消费数据-->
<select id="selectCartBy" resultType="com.example.demo.domain.vo.bean.BeanConsumeCartVo">
select
co.nickname,co.jwcode,m.name AS market,co.product_id,co.total_money,co.live_name,co.source_name,co.trade_time
</select>
<!--获取直播礼物--> <!--获取直播礼物-->

10
src/main/resources/mapper/BeanRechargeMapper1.xml

@ -25,4 +25,14 @@
0 0
</trim> </trim>
</insert> </insert>
<!--筛选查询小黄车消费数据-->
<select id="selectCartBy" resultType="com.example.demo.domain.vo.bean.BeanConsumeCartVo">
select
co.nickname,co.jwcode,m.name AS market,pd.name AS productName,co.total_money,co.live_name,co.source_name,co.created_at
from cart_order co
left join user u on u.jwcode = co.jwcode
left join market m on m.id = u.market
left join product_dict pd on pd.id = co.product_id
</select>
</mapper> </mapper>

33
src/main/resources/mapper/GeneralMapper.xml

@ -1,6 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.coin.GeneralMapper"> <mapper namespace="com.example.demo.mapper.coin.GeneralMapper">
<!--批量插入产品-->
<insert id="replaceBatch">
INSERT INTO product_dict
(id, name, cover, price, updated_at, sync_time)
VALUES
<foreach collection="list" item="p" separator=",">
(#{p.id},
#{p.name},
#{p.cover},
#{p.price},
#{p.updatedAt},
#{syncTime})
</foreach>
ON DUPLICATE KEY UPDATE
name = VALUES(name),
cover = VALUES(cover),
price = VALUES(price),
updated_at = VALUES(updated_at),
sync_time = VALUES(sync_time)
</insert>
<!--删除已清除的产品-->
<delete id="deleteNotIn">
DELETE FROM product_dict
WHERE id NOT IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<select id="getMarket" resultType="java.lang.String"> <select id="getMarket" resultType="java.lang.String">
select DISTINCT name from market where type=2 select DISTINCT name from market where type=2
@ -32,5 +60,10 @@
<select id="getRate" resultType="com.example.demo.domain.entity.Rate"> <select id="getRate" resultType="com.example.demo.domain.entity.Rate">
select id,rate_name from rate select id,rate_name from rate
</select> </select>
<!--查最新更新时间-->
<select id="maxUpdatedAt" resultType="java.lang.Long">
SELECT IFNULL(MAX(updated_at), 0)
FROM product_dict
</select>
</mapper> </mapper>
Loading…
Cancel
Save