修正项目

This commit is contained in:
2024-01-07 01:10:08 +08:00
parent 2f29241806
commit b22014e976
943 changed files with 27699 additions and 28227 deletions

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yovinchen</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>common-util</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>com.yovinchen</groupId>
<artifactId>model</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -0,0 +1,126 @@
package com.yovinchen.xlcs.common.utils;
import org.apache.commons.lang.time.DateUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* ClassName: DateUtil
* Package: com.yovinchen.xlcs.common.utils
* 日期操作工具类
*
* @author yovinchen
* @Create 2023/10/12 18:04
*/
public class DateUtil {
private static final String dateFormat = "yyyy-MM-dd";
private static final String timeFormat = "HH:mm:ss";
/**
* 格式化日期
*
* @param date
* @return
*/
public static String formatDate(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
return sdf.format(date);
}
/**
* 格式化日期
*
* @param date
* @return
*/
public static String formatTime(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
return sdf.format(date);
}
public static Date parseTime(String date) {
SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
try {
return sdf.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
/**
* 截取比较断两个日期对象的field处的值 。
* 如果第一个日期小于、等于、大于第二个则对应返回负整数、0、正整数
*
* @param date1 第一个日期对象非null
* @param date2 第二个日期对象非null
* @param field Calendar中的阈值
* <p>
* date1 > date2 返回1
* date1 = date2 返回0
* date1 < date2 返回:-1
*/
public static int truncatedCompareTo(final Date date1, final Date date2, final int field) {
return DateUtils.truncatedCompareTo(date1, date2, field);
}
/**
* 比对日期与时间大小
*
* @param beginDate
* @param endDate
* @return
*/
public static boolean dateCompare(Date beginDate, Date endDate) {
// endDate > beginDate
return DateUtil.truncatedCompareTo(beginDate, endDate, Calendar.SECOND) != 1;
}
/**
* 比对日期与时间大小
*
* @param beginDate
* @param endDate
* @return
*/
public static boolean timeCompare(Date beginDate, Date endDate) {
Calendar instance1 = Calendar.getInstance();
instance1.setTime(beginDate); //设置时间为当前时间
instance1.set(Calendar.YEAR, 0);
instance1.set(Calendar.MONTH, 0);
instance1.set(Calendar.DAY_OF_MONTH, 0);
Calendar instance2 = Calendar.getInstance();
instance2.setTime(endDate); //设置时间为当前时间
instance2.set(Calendar.YEAR, 0);
instance2.set(Calendar.MONTH, 0);
instance2.set(Calendar.DAY_OF_MONTH, 0);
// endDate > beginDate
return DateUtil.truncatedCompareTo(instance1.getTime(), instance2.getTime(), Calendar.SECOND) != 1;
}
/**
* 获取当前时间到晚上23点59分59秒的时间间隔单位
*
* @return
*/
public static Long getCurrentExpireTimes() {
//过期截止时间
Calendar instance = Calendar.getInstance();
instance.setTime(new Date()); //设置时间为当前时间
instance.set(Calendar.HOUR_OF_DAY, 23);
instance.set(Calendar.MINUTE, 59);
instance.set(Calendar.SECOND, 59);
Date endTime = instance.getTime();
//当前时间与截止时间间隔,单位:秒
long interval = (endTime.getTime() - new Date().getTime()) / 1000;
return 100 * 60 * 60 * 24 * 365L;
}
}

View File

@@ -0,0 +1,64 @@
package com.yovinchen.xlcs.common.utils;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;
/**
* ClassName: JwtHelper
* Package: com.yovinchen.xlcs.common.utils
*
* @author yovinchen
* @Create 2023/9/22 15:50
*/
public class JwtHelper {
private static final long tokenExpiration = 365L * 24 * 60 * 60 * 1000;
private static final String tokenSignKey = "xlcs";
public static String createToken(Long userId, String userName) {
String token = Jwts.builder()
.setSubject("xlcs-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
.claim("userName", userName)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
public static Long getUserId(String token) {
if (StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer) claims.get("userId");
return userId.longValue();
// return 1L;
}
public static String getUserName(String token) {
if (StringUtils.isEmpty(token)) return "";
Jws<Claims> claimsJws = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String) claims.get("userName");
}
public static void removeToken(String token) {
//jwttoken无需删除客户端扔掉即可。
}
public static void main(String[] args) {
String token = JwtHelper.createToken(7L, "admin");
System.out.println(token);
System.out.println(JwtHelper.getUserId(token));
System.out.println(JwtHelper.getUserName(token));
}
}

View File

@@ -0,0 +1,32 @@
package com.yovinchen.xlcs.common.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5 {
public static String encrypt(String strSrc) {
try {
char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f'};
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出错+" + e);
}
}
}

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yovinchen</groupId>
<artifactId>xlcs-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>common</artifactId>
<packaging>pom</packaging>
<modules>
<module>common-util</module>
<module>service-util</module>
<module>rabbit_util</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<!--lombok用来简化实体类需要安装lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- https://doc.xiaominfo.com/knife4j/documentation/ -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<!--用来转换json使用 {JavaObject - json | json - JavaObject}-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- 服务调用feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yovinchen</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>rabbit_util</artifactId>
<dependencies>
<!--rabbitmq消息队列-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -0,0 +1,22 @@
package com.yovinchen.xlcs.mq.config;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* ClassName: MQConfig
* Package: com.yovinchen.xlcs.mq.config
*
* @author yovinchen
* @Create 2023/9/16 23:32
*/
@Configuration
public class MQConfig {
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}

View File

@@ -0,0 +1,66 @@
package com.yovinchen.xlcs.mq.config;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* ClassName: MQProducerAckConfig
* Package: com.yovinchen.xlcs.mq.config
*
* @author yovinchen
* @Create 2023/9/16 23:33
*/
@Component
public class MQProducerAckConfig implements RabbitTemplate.ReturnCallback, RabbitTemplate.ConfirmCallback {
// 我们发送消息使用的是 private RabbitTemplate rabbitTemplate; 对象
// 如果不做设置的话 当前的rabbitTemplate 与当前的配置类没有任何关系!
@Autowired
private RabbitTemplate rabbitTemplate;
// 设置 表示修饰一个非静态的void方法在服务器加载Servlet的时候运行。并且只执行一次
@PostConstruct
public void init() {
rabbitTemplate.setReturnCallback(this);
rabbitTemplate.setConfirmCallback(this);
}
/**
* 表示消息是否正确发送到了交换机上
*
* @param correlationData 消息的载体
* @param ack 判断是否发送到交换机上
* @param cause 原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
System.out.println("消息发送成功!");
} else {
System.out.println("消息发送失败!" + cause);
}
}
/**
* 消息如果没有正确发送到队列中,则会走这个方法!如果消息被正常处理,则这个方法不会走!
*
* @param message
* @param replyCode
* @param replyText
* @param exchange
* @param routingKey
*/
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println("消息主体: " + new String(message.getBody()));
System.out.println("应答码: " + replyCode);
System.out.println("描述:" + replyText);
System.out.println("消息使用的交换器 exchange : " + exchange);
System.out.println("消息使用的路由键 routing : " + routingKey);
}
}

View File

@@ -0,0 +1,68 @@
package com.yovinchen.xlcs.mq.constant;
/**
* ClassName: MqConst
* Package: com.yovinchen.xlcs.mq.constant
*
* @author yovinchen
* @Create 2023/9/16 23:34
*/
public class MqConst {
/**
* 消息补偿
*/
public static final String MQ_KEY_PREFIX = "xlcs.mq:list";
public static final int RETRY_COUNT = 3;
/**
* 商品上下架
*/
public static final String EXCHANGE_GOODS_DIRECT = "xlcs.goods.direct";
public static final String ROUTING_GOODS_UPPER = "xlcs.goods.upper";
public static final String ROUTING_GOODS_LOWER = "xlcs.goods.lower";
//队列
public static final String QUEUE_GOODS_UPPER = "xlcs.goods.upper";
public static final String QUEUE_GOODS_LOWER = "xlcs.goods.lower";
/**
* 团长上下线
*/
public static final String EXCHANGE_LEADER_DIRECT = "xlcs.leader.direct";
public static final String ROUTING_LEADER_UPPER = "xlcs.leader.upper";
public static final String ROUTING_LEADER_LOWER = "xlcs.leader.lower";
//队列
public static final String QUEUE_LEADER_UPPER = "xlcs.leader.upper";
public static final String QUEUE_LEADER_LOWER = "xlcs.leader.lower";
//订单
public static final String EXCHANGE_ORDER_DIRECT = "xlcs.order.direct";
public static final String ROUTING_ROLLBACK_STOCK = "xlcs.rollback.stock";
public static final String ROUTING_MINUS_STOCK = "xlcs.minus.stock";
public static final String ROUTING_DELETE_CART = "xlcs.delete.cart";
//解锁普通商品库存
public static final String QUEUE_ROLLBACK_STOCK = "xlcs.rollback.stock";
public static final String QUEUE_SECKILL_ROLLBACK_STOCK = "xlcs.seckill.rollback.stock";
public static final String QUEUE_MINUS_STOCK = "xlcs.minus.stock";
public static final String QUEUE_DELETE_CART = "xlcs.delete.cart";
//支付
public static final String EXCHANGE_PAY_DIRECT = "xlcs.pay.direct";
public static final String ROUTING_PAY_SUCCESS = "xlcs.pay.success";
public static final String QUEUE_ORDER_PAY = "xlcs.order.pay";
public static final String QUEUE_LEADER_BILL = "xlcs.leader.bill";
//取消订单
public static final String EXCHANGE_CANCEL_ORDER_DIRECT = "xlcs.cancel.order.direct";
public static final String ROUTING_CANCEL_ORDER = "xlcs.cancel.order";
//延迟取消订单队列
public static final String QUEUE_CANCEL_ORDER = "xlcs.cancel.order";
/**
* 定时任务
*/
public static final String EXCHANGE_DIRECT_TASK = "xlcs.exchange.direct.task";
public static final String ROUTING_TASK_23 = "xlcs.task.23";
//队列
public static final String QUEUE_TASK_23 = "xlcs.queue.task.23";
}

View File

@@ -0,0 +1,56 @@
package com.yovinchen.xlcs.mq.service;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* ClassName: RabbitService
* Package: com.yovinchen.xlcs.common.service
*
* @author yovinchen
* @Create 2023/9/16 18:12
*/
@Service
public class RabbitService {
// 引入操作rabbitmq 的模板
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息
*
* @param exchange 交换机
* @param routingKey 路由键
* @param message 消息
* @return
*/
public boolean sendMessage(String exchange, String routingKey, Object message) {
// 调用发送数据的方法
rabbitTemplate.convertAndSend(exchange, routingKey, message);
return true;
}
/**
* 发送延迟消息的方法
*
* @param exchange 交换机
* @param routingKey 路由键
* @param message 消息内容
* @param delayTime 延迟时间
* @return
*/
public boolean sendDelayMessage(String exchange, String routingKey, Object message, int delayTime) {
// 在发送消息的时候设置延迟时间
rabbitTemplate.convertAndSend(exchange, routingKey, message, message1 -> {
// 设置一个延迟时间
message1
.getMessageProperties()
.setDelay(delayTime * 1000);
return message1;
});
return true;
}
}

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yovinchen</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>service-util</artifactId>
<dependencies>
<dependency>
<groupId>com.yovinchen</groupId>
<artifactId>common-util</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring2.X集成redis所需common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>
<!-- redisson 分布式锁-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.11.2</version>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.yovinchen</groupId>
<artifactId>model</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!-- 代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -0,0 +1,50 @@
package com.yovinchen.xlcs.common.auth;
import com.yovinchen.xlcs.vo.user.UserLoginVo;
/**
* ClassName: AuthContextHolder
* Package: com.yovinchen.xlcs.common.auth
*
* @author yovinchen
* @Create 2023/9/22 17:40
*/
//ThreadLocal工具类
public class AuthContextHolder {
//用户id
private static final ThreadLocal<Long> userId = new ThreadLocal<>();
//用户仓库id
private static final ThreadLocal<Long> wareId = new ThreadLocal<>();
//用户信息对象
private static final ThreadLocal<UserLoginVo> userLoginVo = new ThreadLocal<>();
public static Long getUserId() {
return userId.get();
}
//userId操作的方法
public static void setUserId(Long _userId) {
userId.set(_userId);
}
public static Long getWareId() {
return wareId.get();
}
public static void setWareId(Long _wareId) {
wareId.set(_wareId);
}
public static UserLoginVo getUserLoginVo() {
return userLoginVo.get();
}
public static void setUserLoginVo(UserLoginVo _userLoginVo) {
userLoginVo.set(_userLoginVo);
}
}

View File

@@ -0,0 +1,30 @@
package com.yovinchen.xlcs.common.auth;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import javax.annotation.Resource;
/**
* ClassName: LoginMvcConfigurerAdapter
* Package: com.yovinchen.xlcs.common.auth
*
* @author yovinchen
* @Create 2023/9/22 23:58
*/
@Configuration
public class LoginMvcConfigurerAdapter extends WebMvcConfigurationSupport {
@Resource
private RedisTemplate redisTemplate;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserLoginInterceptor(redisTemplate))
.addPathPatterns("/api/**")
.excludePathPatterns("/api/user/weixin/wxLogin/*");
super.addInterceptors(registry);
}
}

View File

@@ -0,0 +1,53 @@
package com.yovinchen.xlcs.common.auth;
import com.yovinchen.xlcs.common.constant.RedisConst;
import com.yovinchen.xlcs.common.utils.JwtHelper;
import com.yovinchen.xlcs.vo.user.UserLoginVo;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* ClassName: UserLoginInterceptor
* Package: com.yovinchen.xlcs.common.auth
*
* @author yovinchen
* @Create 2023/9/22 23:47
*/
public class UserLoginInterceptor implements HandlerInterceptor {
private final RedisTemplate redisTemplate;
public UserLoginInterceptor(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
this.getUserLoginVo(request);
return true;
}
private void getUserLoginVo(HttpServletRequest request) {
//从请求头获取token
String token = request.getHeader("token");
//判断token不为空
if (!StringUtils.isEmpty(token)) {
//从token获取userId
Long userId = JwtHelper.getUserId(token);
//根据userId到Redis获取用户信息
UserLoginVo userLoginVo = (UserLoginVo) redisTemplate.opsForValue()
.get(RedisConst.USER_LOGIN_KEY_PREFIX + userId);
//获取数据放到ThreadLocal里面
if (userLoginVo != null) {
AuthContextHolder.setUserId(userLoginVo.getUserId());
AuthContextHolder.setWareId(userLoginVo.getWareId());
AuthContextHolder.setUserLoginVo(userLoginVo);
}
}
}
}

View File

@@ -0,0 +1,34 @@
package com.yovinchen.xlcs.common.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* ClassName: MyBatisPlusConfig
* Package: com.yovinchen.xlcs.common.config
* MybatisPlus配置类
*
* @author yovinchen
* @Create 2023/9/13 12:56
*/
@EnableTransactionManagement
@Configuration
@MapperScan(value = {"com.yovinchen.xlcs.*.mapper"})
public class MybatisPlusConfig {
/**
* mp插件
*/
@Bean
public MybatisPlusInterceptor optimisticLockerInnerInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//向Mybatis过滤器链中添加分页拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}

View File

@@ -0,0 +1,105 @@
package com.yovinchen.xlcs.common.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.time.Duration;
/**
* ClassName: RedisConfig
* Package: com.yovinchen.xlcs.common.config
* Redis配置类
*
* @author yovinchen
* @Create 2023/9/22 15:55
*/
@Configuration
@EnableCaching
public class RedisConfig {
// 使用默认标签做缓存
@Bean
public KeyGenerator wiselyKeyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass()
.getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
// 声明模板
/*
ref = 表示引用
value = 具体的值
<bean class="org.springframework.data.redis.core.RedisTemplate" >
<property name="defaultSerializer" ref = "">
</bean>
*/
// 工具类:
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 将Redis 中 string hash 数据类型,自动序列化!
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(365))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}

View File

@@ -0,0 +1,60 @@
package com.yovinchen.xlcs.common.config;
import lombok.Data;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
/**
* ClassName: RedissonConfig
* Package: com.yovinchen.xlcs.common.config
*
* @author yovinchen
* @Create 2023/10/12 16:48
*/
@Data
@Configuration
@ConfigurationProperties("spring.redis")
public class RedissonConfig {
private static String ADDRESS_PREFIX = "redis://";
private String host;
private String addresses;
private String password;
private String port;
private int timeout = 3000;
private int connectionPoolSize = 64;
private int connectionMinimumIdleSize = 10;
private int pingConnectionInterval = 60000;
/**
* 自动装配
*/
@Bean
RedissonClient redissonSingle() {
Config config = new Config();
// 判断redis 的host是否为空
if (StringUtils.isEmpty(host)) {
throw new RuntimeException("host is empty");
}
// 配置hostport等参数
SingleServerConfig serverConfig = config.useSingleServer()
//redis://127.0.0.1:7181
.setAddress(ADDRESS_PREFIX + this.host + ":" + port)
.setTimeout(this.timeout)
.setPingConnectionInterval(pingConnectionInterval)
.setConnectionPoolSize(this.connectionPoolSize)
.setConnectionMinimumIdleSize(this.connectionMinimumIdleSize);
// 判断进入redis 是否密码
if (!StringUtils.isEmpty(this.password)) {
serverConfig.setPassword(this.password);
}
// RedissonClient redisson = Redisson.create(config);
return Redisson.create(config);
}
}

View File

@@ -0,0 +1,101 @@
package com.yovinchen.xlcs.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
import java.util.ArrayList;
import java.util.List;
/**
* ClassName: Swagger2Config
* Package: com.yovinchen.xlcs.common.config
*
* @author yovinchen
* @Create 2023/9/13 13:18
*/
@Configuration
@EnableSwagger2WebMvc
public class Swagger2Config {
@Bean
public Docket webApiConfig() {
List<Parameter> pars = new ArrayList<>();
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar
.name("userId")
.description("用户token")
//.defaultValue(JwtHelper.createToken(1L, "admin"))
.defaultValue("1")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.build();
pars.add(tokenPar.build());
Docket webApi = new Docket(DocumentationType.SWAGGER_2)
.groupName("webApi")
.apiInfo(webApiInfo())
.select()
//只显示api路径下的页面
.apis(RequestHandlerSelectors.basePackage("com.yovinchen.xlcs"))
.paths(PathSelectors.regex("/api/.*"))
.build()
.globalOperationParameters(pars);
return webApi;
}
@Bean
public Docket adminApiConfig() {
List<Parameter> pars = new ArrayList<>();
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar
.name("adminId")
.description("用户token")
.defaultValue("1")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.build();
pars.add(tokenPar.build());
Docket adminApi = new Docket(DocumentationType.SWAGGER_2)
.groupName("adminApi")
.apiInfo(adminApiInfo())
.select()
//只显示admin路径下的页面
.apis(RequestHandlerSelectors.basePackage("com.yovinchen.xlcs"))
.paths(PathSelectors.regex("/admin/.*"))
.build()
.globalOperationParameters(pars);
return adminApi;
}
private ApiInfo webApiInfo() {
return new ApiInfoBuilder()
.title("网站-API文档")
.description("本文档描述了尚上优选网站微服务接口定义")
.version("1.0")
.contact(new Contact("yovinchen", "http://yovinchen.com", "yovinchen"))
.build();
}
private ApiInfo adminApiInfo() {
return new ApiInfoBuilder()
.title("后台管理系统-API文档")
.description("本文档描述了尚上优选后台系统服务接口定义")
.version("1.0")
.contact(new Contact("yovinchen", "http://yovinchen.com", "yovinchen"))
.build();
}
}

View File

@@ -0,0 +1,49 @@
package com.yovinchen.xlcs.common.constant;
/**
* ClassName: RedisConst
* Package: com.yovinchen.xlcs.common.constant
* Redis常量配置类
*
* @author yovinchen
* @Create 2023/9/22 15:57
*/
public class RedisConst {
public static final String SKUKEY_PREFIX = "sku:";
public static final String SKUKEY_SUFFIX = ":info";
//单位:秒
public static final long SKUKEY_TIMEOUT = 24 * 60 * 60;
// 定义变量,记录空对象的缓存过期时间 缓存穿透key的过期时间
public static final long SKUKEY_TEMPORARY_TIMEOUT = 10 * 60;
//单位:秒 尝试获取锁的最大等待时间
public static final long SKULOCK_EXPIRE_PX1 = 1;
//单位:秒 锁的持有时间
public static final long SKULOCK_EXPIRE_PX2 = 1;
public static final String SKULOCK_SUFFIX = ":lock";
public static final String USER_KEY_PREFIX = "user:";
public static final String USER_CART_KEY_SUFFIX = ":cart";
public static final long USER_CART_EXPIRE = 60 * 60 * 24 * 7;
public static final String SROCK_INFO = "stock:info:";
public static final String ORDER_REPEAT = "order:repeat:";
//用户登录
public static final String USER_LOGIN_KEY_PREFIX = "user:login:";
public static final String ADMIN_LOGIN_KEY_PREFIX = "admin:login:";
// public static final String userinfoKey_suffix = ":info";
public static final int USERKEY_TIMEOUT = 365;
public static final String ORDER_SKU_MAP = "order:sku:";
//秒杀商品前缀
public static final String SECKILL_TIME_MAP = "seckill:time:map";
public static final String SECKILL_SKU_MAP = "seckill:sku:map";
public static final String SECKILL_SKU_LIST = "seckill:sku:list:";
public static final String SECKILL_USER_MAP = "seckill:user:map:";
public static final String SECKILL_ORDERS_USERS = "seckill:orders:users";
public static final String SECKILL_STOCK_PREFIX = "seckill:stock:";
public static final String SECKILL_USER = "seckill:user:";
//用户锁定时间 单位:秒
public static final int SECKILL__TIMEOUT = 60 * 60;
}

View File

@@ -0,0 +1,38 @@
package com.yovinchen.xlcs.common.exception;
import com.yovinchen.xlcs.common.result.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* ClassName: GlobalExceptionHandler
* Package: com.yovinchen.xlcs.common.exception
* 统一异常处理类
*
* @author yovinchen
* @Create 2023/9/13 13:03
*/
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Result error(Exception e) {
e.printStackTrace();
return Result.fail(null);
}
/**
* 自定义异常处理方法
*
* @param e
* @return
*/
@ExceptionHandler(xlcsException.class)
@ResponseBody
public Result error(xlcsException e) {
return Result.build(null, e.getCode(), e.getMessage());
}
}

View File

@@ -0,0 +1,46 @@
package com.yovinchen.xlcs.common.exception;
import com.yovinchen.xlcs.common.result.ResultCodeEnum;
import lombok.Data;
/**
* ClassName: xlcsException
* Package: com.yovinchen.xlcs.common.exception
* 自定义异常类
*
* @author yovinchen
* @Create 2023/9/13 13:05
*/
@Data
public class xlcsException extends RuntimeException {
//异常状态码
private Integer code;
/**
* 通过状态码和错误消息创建异常对象
*
* @param message
* @param code
*/
public xlcsException(String message, Integer code) {
super(message);
this.code = code;
}
/**
* 接收枚举类型对象
*
* @param resultCodeEnum
*/
public xlcsException(ResultCodeEnum resultCodeEnum) {
super(resultCodeEnum.getMessage());
this.code = resultCodeEnum.getCode();
}
@Override
public String toString() {
return "GuliException{" + "code=" + code + ", message=" + this.getMessage() + '}';
}
}

View File

@@ -0,0 +1,71 @@
package com.yovinchen.xlcs.common.result;
import lombok.Data;
/**
* ClassName: Result
* Package: com.yovinchen.xlcs.common.result
* 统一返回结果类
*
* @author yovinchen
* @Create 2023/9/13 13:01
*/
@Data
public class Result<T> {
//状态码
private Integer code;
//信息
private String message;
//数据
private T data;
//构造私有化
private Result() {
}
//设置数据,返回对象的方法
public static <T> Result<T> build(T data, Integer code, String message) {
//创建Resullt对象设置值返回对象
Result<T> result = new Result<>();
//判断返回结果中是否需要数据
if (data != null) {
//设置数据到result对象
result.setData(data);
}
//设置其他值
result.setCode(code);
result.setMessage(message);
//返回设置值之后的对象
return result;
}
//设置数据,返回对象的方法
public static <T> Result<T> build(T data, ResultCodeEnum resultCodeEnum) {
//创建Resullt对象设置值返回对象
Result<T> result = new Result<>();
//判断返回结果中是否需要数据
if (data != null) {
//设置数据到result对象
result.setData(data);
}
//设置其他值
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
//返回设置值之后的对象
return result;
}
//成功的方法
public static <T> Result<T> ok(T data) {
Result<T> result = build(data, ResultCodeEnum.SUCCESS);
return result;
}
//失败的方法
public static <T> Result<T> fail(T data) {
return build(data, ResultCodeEnum.FAIL);
}
}

View File

@@ -0,0 +1,56 @@
package com.yovinchen.xlcs.common.result;
import lombok.Getter;
/**
* ClassName: ResultCodeEnum
* Package: com.yovinchen.xlcs.common.result
* 统一返回结果状态信息类
*
* @author yovinchen
* @Create 2023/9/13 12:59
*/
@Getter
public enum ResultCodeEnum {
SUCCESS(200, "成功"),
FAIL(201, "失败"),
SERVICE_ERROR(2012, "服务异常"),
DATA_ERROR(204, "数据异常"),
ILLEGAL_REQUEST(205, "非法请求"),
REPEAT_SUBMIT(206, "重复提交"),
LOGIN_AUTH(208, "未登陆"),
PERMISSION(209, "没有权限"),
ORDER_PRICE_ERROR(210, "订单商品价格变化"),
ORDER_STOCK_FALL(204, "订单库存锁定失败"),
CREATE_ORDER_FAIL(210, "创建订单失败"),
COUPON_GET(220, "优惠券已经领取"),
COUPON_LIMIT_GET(221, "优惠券已发放完毕"),
URL_ENCODE_ERROR(216, "URL编码失败"),
ILLEGAL_CALLBACK_REQUEST_ERROR(217, "非法回调请求"),
FETCH_ACCESSTOKEN_FAILD(218, "获取accessToken失败"),
FETCH_USERINFO_ERROR(219, "获取用户信息失败"),
SKU_LIMIT_ERROR(230, "购买个数不能大于限购个数"),
REGION_OPEN(240, "该区域已开通"),
REGION_NO_OPEN(240, "该区域未开通"),
PAYMENT_WAITING(242, "订单支付中"),
PAYMENT_SUCCESS(241, "订单支付成功"),
PAYMENT_FAIL(243, "订单支付失败"),
;
private final Integer code;
private final String message;
ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}

View File

@@ -0,0 +1,73 @@
package com.yovinchen.xlcs;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
/**
* ClassName: CodeGet
* Package: com.yovinchen.xlcs
*
* @author yovinchen
* @Create 2023/9/14 08:49
*/
public class CodeGet {
public static void main(String[] args) {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
// 全局配置
GlobalConfig gc = new GlobalConfig();
gc.setOutputDir("yovinchen-xlcs-parent/service/service-order" + "/src/main/java");
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setAuthor("yovinchen");
gc.setOpen(false);
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://82.157.68.223:3306/shequ-order?serverTimezone=GMT%2B8&useSSL=false");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("shequ-order");
dsc.setPassword("shequ-order");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.yovinchen.xlcs");
pc.setModuleName("order"); //模块名
pc.setController("controller");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("cart_info", "order_info", "order_deliver", "order_item", "order_log", "order_return_apply", "order_return_reason", "order_set", "payment_info", "refund_info");
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}