X723595506 1 week ago
parent
commit
6c5e0559f1
58 changed files with 4284 additions and 136 deletions
  1. 6 0
      pom.xml
  2. 30 0
      src/main/java/com/example/demo/common/config/RedisConfig.java
  3. 152 0
      src/main/java/com/example/demo/common/utils/CacheKey.java
  4. 350 0
      src/main/java/com/example/demo/common/utils/DateUtils.java
  5. 312 0
      src/main/java/com/example/demo/common/utils/HttpUtils.java
  6. 288 0
      src/main/java/com/example/demo/common/utils/RedisClient.java
  7. 1075 0
      src/main/java/com/example/demo/common/utils/RedisUtil.java
  8. 30 0
      src/main/java/com/example/demo/coupon/controller/UserCouponController.java
  9. 20 0
      src/main/java/com/example/demo/coupon/dao/CouponMapper.java
  10. 20 0
      src/main/java/com/example/demo/coupon/dao/UserCouponMapper.java
  11. 161 0
      src/main/java/com/example/demo/coupon/domain/Coupon.java
  12. 74 0
      src/main/java/com/example/demo/coupon/domain/UserCoupon.java
  13. 9 0
      src/main/java/com/example/demo/coupon/dto/PageDto.java
  14. 8 0
      src/main/java/com/example/demo/coupon/dto/UserCouponDto.java
  15. 16 0
      src/main/java/com/example/demo/coupon/service/CouponService.java
  16. 16 0
      src/main/java/com/example/demo/coupon/service/UserCouponService.java
  17. 44 0
      src/main/java/com/example/demo/coupon/service/impl/CouponServiceImpl.java
  18. 65 0
      src/main/java/com/example/demo/coupon/service/impl/UserCouponServiceImpl.java
  19. 36 0
      src/main/java/com/example/demo/order/controller/OrderController.java
  20. 20 0
      src/main/java/com/example/demo/order/dao/OrderInfoMapper.java
  21. 22 0
      src/main/java/com/example/demo/order/dao/OrderItemMapper.java
  22. 145 0
      src/main/java/com/example/demo/order/domain/OrderInfo.java
  23. 78 0
      src/main/java/com/example/demo/order/domain/OrderItem.java
  24. 11 0
      src/main/java/com/example/demo/order/dto/OrderInfoDto.java
  25. 15 0
      src/main/java/com/example/demo/order/dto/OrderInfoUpDto.java
  26. 13 0
      src/main/java/com/example/demo/order/dto/OrderItemDto.java
  27. 23 0
      src/main/java/com/example/demo/order/service/OrderInfoService.java
  28. 13 0
      src/main/java/com/example/demo/order/service/OrderItemService.java
  29. 241 0
      src/main/java/com/example/demo/order/service/impl/OrderInfoServiceImpl.java
  30. 22 0
      src/main/java/com/example/demo/order/service/impl/OrderItemServiceImpl.java
  31. 58 45
      src/main/java/com/example/demo/product/controller/ProductController.java
  32. 12 0
      src/main/java/com/example/demo/product/dto/TrainDto.java
  33. 4 2
      src/main/java/com/example/demo/product/service/ProductFlightService.java
  34. 6 2
      src/main/java/com/example/demo/product/service/ProductTrainService.java
  35. 86 34
      src/main/java/com/example/demo/product/service/impl/ProductFlightServiceImpl.java
  36. 106 24
      src/main/java/com/example/demo/product/service/impl/ProductTrainServiceImpl.java
  37. 9 5
      src/main/java/com/example/demo/scenic_spot/controller/ScenicSpotController.java
  38. 8 0
      src/main/java/com/example/demo/scenic_spot/dto/ScenicSpotDto.java
  39. 3 1
      src/main/java/com/example/demo/scenic_spot/service/ScenicSpotService.java
  40. 54 4
      src/main/java/com/example/demo/scenic_spot/service/impl/ScenicSpotServiceImpl.java
  41. 48 3
      src/main/java/com/example/demo/user/controller/UserController.java
  42. 20 0
      src/main/java/com/example/demo/user/dao/UserFavoriteMapper.java
  43. 88 0
      src/main/java/com/example/demo/user/domain/UserFavorite.java
  44. 9 0
      src/main/java/com/example/demo/user/dto/CollectDto.java
  45. 9 0
      src/main/java/com/example/demo/user/dto/PhoneDto.java
  46. 2 12
      src/main/java/com/example/demo/user/dto/UserDto.java
  47. 20 0
      src/main/java/com/example/demo/user/service/UserFavoriteService.java
  48. 3 0
      src/main/java/com/example/demo/user/service/UserService.java
  49. 5 0
      src/main/java/com/example/demo/user/service/ValidateCodeService.java
  50. 72 0
      src/main/java/com/example/demo/user/service/impl/UserFavoriteServiceImpl.java
  51. 82 4
      src/main/java/com/example/demo/user/service/impl/UserServiceImpl.java
  52. 21 0
      src/main/java/com/example/demo/user/service/impl/ValidateCodeServiceImpl.java
  53. 29 0
      src/main/resources/com/example/demo/coupon/mapper/CouponMapper.xml
  54. 25 0
      src/main/resources/com/example/demo/coupon/mapper/UserCouponMapper.xml
  55. 27 0
      src/main/resources/com/example/demo/order/mapper/OrderInfoMapper.xml
  56. 26 0
      src/main/resources/com/example/demo/order/mapper/OrderItemMapper.xml
  57. 18 0
      src/main/resources/com/example/demo/user/mapper/UserFavoriteMapper.xml
  58. 119 0
      src/main/resources/logback-spring.xml

+ 6 - 0
pom.xml

@@ -170,6 +170,12 @@
             <artifactId>elasticsearch</artifactId>
             <version>7.14.0</version>
         </dependency>
+        <!--集成 logstash 日志-->
+        <dependency>
+            <groupId>net.logstash.logback</groupId>
+            <artifactId>logstash-logback-encoder</artifactId>
+            <version>5.3</version>
+        </dependency>
         <dependency>
             <groupId>org.locationtech.jts</groupId>
             <artifactId>jts-core</artifactId>

+ 30 - 0
src/main/java/com/example/demo/common/config/RedisConfig.java

@@ -0,0 +1,30 @@
+package com.example.demo.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+@Configuration
+public class RedisConfig {
+    
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        RedisTemplate<String, Object> template = new RedisTemplate<>();
+        template.setConnectionFactory(redisConnectionFactory);
+        
+        // 设置key的序列化器
+        template.setKeySerializer(new StringRedisSerializer());
+        
+        // 设置value的序列化器
+        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
+        
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
+        
+        template.afterPropertiesSet();
+        return template;
+    }
+}

+ 152 - 0
src/main/java/com/example/demo/common/utils/CacheKey.java

@@ -0,0 +1,152 @@
+package com.example.demo.common.utils;
+
+/**
+ * 缓存key 定义
+ */
+public final class CacheKey {
+
+	/**
+	 * 1秒
+	 */
+	public static final int	SEC1		= 1;
+
+	/**
+	 * 3秒
+	 */
+	public static final int	SEC3		= SEC1 * 3;
+
+	/**
+	 * 5秒
+	 */
+	public static final int	SEC5		= SEC1 * 5;
+
+	/**
+	 * 15秒
+	 */
+	public static final int	SEC15		= SEC1 * 15;
+
+	/**
+	 * 30秒
+	 */
+	public static final int	SEC30		= SEC1 * 30;
+
+	/**
+	 * 1分钟
+	 */
+	public static final int	MINUTES1	= 60 * SEC1;
+	
+	/**
+	 * 3分钟
+	 */
+	public static final int	MINUTES3	= 60 * SEC3;
+	
+	/**
+	 * 5分钟
+	 */
+	public static final int	MINUTES5	= 5 * MINUTES1;
+	/**
+	 * 10分钟
+	 */
+	public static final int	MINUTES10	= 10 * MINUTES1;
+	/**
+	 * 30分钟
+	 */
+	public static final int	MINUTES30	= 30 * MINUTES1;
+	/**
+	 * 1小时
+	 */
+	public static final int	HOUR1		= 60 * MINUTES1;
+	/**
+	 * 半天
+	 */
+	public static final int	HOUR12		= 12 * HOUR1;
+	/**
+	 * 1天
+	 */
+	public static final int	DAY1		= 24 * HOUR1;
+
+	/**
+	 * 3天
+	 */
+	public static final int	DAY3		= 3 * DAY1;
+	/**
+	 * 7天
+	 */
+	public static final int	DAY7		= 7 * DAY1;
+
+	/**
+	 * 15天
+	 */
+	public static final int	DAY15		= 15 * DAY1;
+
+	/**
+	 * 30天
+	 */
+	public static final int	DAY30		= 30 * DAY1;
+
+	/**
+	 * 最大值
+	 */
+	public static final int	MAX			= Integer.MAX_VALUE;
+
+	/**
+	 * 超时时间
+	 */
+	private Integer			expire;
+
+	/**
+	 * 缓存 key,通常是一个前缀或后缀
+	 */
+	private String			key;
+
+	private CacheKey() {
+	}
+
+	public CacheKey(String key, Integer expire) {
+		this.expire = expire;
+		this.key = key;
+	}
+
+	public CacheKey(String key) {
+		this.key = key;
+	}
+
+	@Override
+	public String toString() {
+		return key;
+	}
+
+	public String getKey() {
+		return key;
+	}
+
+	public Integer getExpire() {
+		return expire;
+	}
+
+	/**
+	 * key+appendKey
+	 * 
+	 * @param appendKey
+	 * @return
+	 */
+	public String getKeyPrefix(Object appendKey) {
+		if (appendKey == null) {
+			throw new IllegalArgumentException("appendKey 不能为空......");
+		}
+		return key + appendKey;
+	}
+
+	/**
+	 * appendKey+key
+	 * 
+	 * @param appendKey
+	 * @return
+	 */
+	public String getKeySuffix(Object appendKey) {
+		if (appendKey == null) {
+			throw new IllegalArgumentException("appendKey 不能为空......");
+		}
+		return appendKey + key;
+	}
+}

+ 350 - 0
src/main/java/com/example/demo/common/utils/DateUtils.java

@@ -0,0 +1,350 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.example.demo.common.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * 日期工具类, 继承org.apache.commons.lang.time.DateUtils类
+ * @author jeeplus
+ * @version 2014-4-15
+ */
+public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
+	
+	private static String[] parsePatterns = {
+		"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", 
+		"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+		"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+	/**
+	 * 得到当前日期字符串 格式(yyyy-MM-dd)
+	 */
+	public static String getDate() {
+		return getDate("yyyy-MM-dd");
+	}
+	
+	/**
+	 * 得到当前日期字符串 格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E"
+	 */
+	public static String getDate(String pattern) {
+		return DateFormatUtils.format(new Date(), pattern);
+	}
+	
+	/**
+	 * 得到日期字符串 默认格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E"
+	 */
+	public static String formatDate(Date date, Object... pattern) {
+		String formatDate = null;
+		if (pattern != null && pattern.length > 0) {
+			formatDate = DateFormatUtils.format(date, pattern[0].toString());
+		} else {
+			formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
+		}
+		return formatDate;
+	}
+
+	/**
+	 * 获取年月
+	 */
+	public static String getYearMonth(Date date) {
+
+		return formatDate(date,"yyyy")+formatDate(date,"MM");
+	}
+	
+	/**
+	 * 得到日期时间字符串,转换格式(yyyy-MM-dd HH:mm:ss)
+	 */
+	public static String formatDateTime(Date date) {
+		return formatDate(date, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	/**
+	 * 得到当前时间字符串 格式(HH:mm:ss)
+	 */
+	public static String getTime() {
+		return formatDate(new Date(), "HH:mm:ss");
+	}
+
+	/**
+	 * 得到当前日期和时间字符串 格式(yyyy-MM-dd HH:mm:ss)
+	 */
+	public static String getDateTime() {
+		return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
+	}
+
+	public static String getDateTimeNum(){
+		String date=formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
+		date=StringUtils.replace(date,"-","");
+		date=StringUtils.replace(date,":","");
+		date=StringUtils.replace(date," ","");
+
+		return date;
+	}
+	public static String getYearMonthDayNum(){
+		String date=formatDate(new Date(), "yyyy-MM-dd");
+		date=StringUtils.replace(date,"-","");
+
+		return date;
+	}
+
+	/**
+	 * 得到当前年份字符串 格式(yyyy)
+	 */
+	public static String getYear() {
+		return formatDate(new Date(), "yyyy");
+	}
+
+	public static String getYear(Date date) {
+		return formatDate(date, "yyyy");
+	}
+
+	/**
+	 * 得到当前月份字符串 格式(MM)
+	 */
+	public static String getMonth() {
+		return formatDate(new Date(), "MM");
+	}
+
+	/**
+	 * 得到当天字符串 格式(dd)
+	 */
+	public static String getDay() {
+		return formatDate(new Date(), "dd");
+	}
+
+	/**
+	 * 得到当前星期字符串 格式(E)星期几
+	 */
+	public static String getWeek() {
+		return formatDate(new Date(), "E");
+	}
+	
+	/**
+	 * 日期型字符串转化为日期 格式
+	 * { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", 
+	 *   "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm",
+	 *   "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm" }
+	 */
+	public static Date parseDate(Object str) {
+		if (str == null){
+			return null;
+		}
+		try {
+			return parseDate(str.toString(), parsePatterns);
+		} catch (ParseException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * 获取过去的天数
+	 * @param date
+	 * @return
+	 */
+	public static long pastDays(Date date) {
+		long t = new Date().getTime()-date.getTime();
+		return t/(24*60*60*1000L);
+	}
+
+
+	/**
+	 * 之后多少天的时间
+	 * @param days
+	 * @return
+	 */
+	public static long getAfterDays(int days){
+		long t=new Date().getTime()+days*24*60*60*1000L;
+		return t;
+	}
+	/**
+	 * 指定时间之后多少天的时间
+	 * @param days
+	 * @return
+	 */
+	public static long getAfterDays(Date d,int days){
+		long t=d.getTime()+days*24*60*60*1000L;
+		return t;
+	}
+
+	/**
+	 * 之前多少天的时间
+	 * @param days
+	 * @return
+	 */
+	public static long getBeforeDays(int days){
+		long t=new Date().getTime()-days*24*60*60*1000L;
+		return t;
+	}
+
+	/**
+	 * 指定时间之前多少天的时间
+	 * @param days
+	 * @return
+	 */
+	public static long getBeforeDays(Date d,int days){
+		long t=d.getTime()-days*24*60*60*1000L;
+		return t;
+	}
+
+	/**
+	 * 获取过去的小时
+	 * @param date
+	 * @return
+	 */
+	public static long pastHour(Date date) {
+		long t = new Date().getTime()-date.getTime();
+		return t/(60*60*1000L);
+	}
+	
+	/**
+	 * 获取过去的分钟
+	 * @param date
+	 * @return
+	 */
+	public static long pastMinutes(Date date) {
+		long t = new Date().getTime()-date.getTime();
+		return t/(60*1000L);
+	}
+
+	/**
+	 * 获取过去的分钟
+	 * @param date
+	 * @return
+	 */
+	public static long pastSecond(Date date) {
+		long t = new Date().getTime()-date.getTime();
+		return t/(1*1000L);
+	}
+	
+	/**
+	 * 转换为时间(天,时:分:秒.毫秒)
+	 * @param timeMillis
+	 * @return
+	 */
+    public static String formatDateTime(long timeMillis){
+		long day = timeMillis/(24*60*60*1000L);
+		long hour = (timeMillis/(60*60*1000L)-day*24);
+		long min = ((timeMillis/(60*1000))-day*24*60-hour*60);
+		long s = (timeMillis/1000-day*24*60*60-hour*60*60-min*60);
+		long sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000);
+		return (day>0?day+",":"")+hour+":"+min+":"+s+"."+sss;
+    }
+
+	/**
+	 * 时长
+	 * @param timeMillis
+	 * @return
+	 */
+	public static String formatDateTimeToString(long timeMillis){
+
+		long day = timeMillis/(24*60*60*1000L);
+		long hour = (timeMillis/(60*60*1000L)-day*24);
+		long min = ((timeMillis/(60*1000))-day*24*60-hour*60);
+		long s = (timeMillis/1000-day*24*60*60-hour*60*60-min*60);
+		long sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000);
+		return (day>0?day+"天":"")+(hour>0?hour+"时":"")+(min>0?min+"分":"")+(s>0?s+"秒":"");
+	}
+
+	/**
+	 * 过去多少时间转换为时间(天,时:分:秒.毫秒)
+	 * @param timeMillis
+	 * @return
+	 */
+	public static String pastTime(long timeMillis){
+		long tempTimeMillis=timeMillis;
+		timeMillis=new Date().getTime()-timeMillis;
+		long day = timeMillis/(24*60*60*1000L);
+		long hour = (timeMillis/(60*60*1000L)-day*24);
+		long min = ((timeMillis/(60*1000L))-day*24*60-hour*60);
+		long s = (timeMillis/1000L-day*24*60*60-hour*60*60-min*60);
+		long sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000L);
+		if(day>31){
+			return DateUtils.formateDate("yyyy-MM-dd",tempTimeMillis);
+		}
+		if(day>0){
+			return day+"天前";
+		}
+		if(hour>0){
+			return hour+"小时前";
+		}
+		if(min>0){
+			return min+"分钟前";
+		}
+		return "刚刚";
+	}
+	/**
+	 * 过去的时间
+
+	 * @return
+	 */
+	public static String pastTimeForDate(Date date){
+
+		long timeMillis=new Date().getTime()-date.getTime();
+		long day = timeMillis/(24*60*60*1000L);
+		long hour = (timeMillis/(60*60*1000)-day*24);
+		long min = ((timeMillis/(60*1000))-day*24*60-hour*60);
+		long s = (timeMillis/1000-day*24*60*60-hour*60*60-min*60);
+		long sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000);
+		if(day>31){
+			return DateUtils.formatDate(date,"yyyy-MM-dd");
+		}
+		if(day>0){
+			return day+"天前";
+		}
+		if(hour>0){
+			return hour+"小时前";
+		}
+		if(min>0){
+			return min+"分钟前";
+		}
+		return "刚刚";
+	}
+
+	/**
+	 * 时长
+	 * @param timeMillis
+	 * @return
+	 */
+	public static String formatDateToHHMM(long timeMillis){
+		long day = timeMillis/(24*60*60*1000L);
+		long hour = (timeMillis/(60*60*1000));
+		long min = ((timeMillis/(60*1000))-day*24*60-hour*60);
+		long s = (timeMillis/1000-day*24*60*60-hour*60*60-min*60);
+		long sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000);
+		return (hour>0?hour+"时":"0时")+(min>0?min+"分":"0分");
+	}
+    public static String formateDate(String dateFormat,long timeMillis){
+		SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
+		      Date date = new Date(timeMillis);
+		     return sdf.format(date);
+	}
+	
+	/**
+	 * 获取两个日期之间的天数
+	 * 
+	 * @param before
+	 * @param after
+	 * @return
+	 */
+	public static double getDistanceOfTwoDate(Date before, Date after) {
+		long beforeTime = before.getTime();
+		long afterTime = after.getTime();
+		return (afterTime - beforeTime) / (1000 * 60 * 60 * 24L);
+	}
+	
+	/**
+	 * @param args
+	 * @throws ParseException
+	 */
+	public static void main(String[] args) throws ParseException {
+		long timelong=0;
+	System.out.println(	DateUtils.formatDateTime(timelong));
+	System.out.println(DateUtils.formatDateToHHMM(timelong));
+	}
+}

+ 312 - 0
src/main/java/com/example/demo/common/utils/HttpUtils.java

@@ -0,0 +1,312 @@
+package com.example.demo.common.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+
+public class HttpUtils {
+	
+	/**
+	 * get
+	 * 
+	 * @param host
+	 * @param path
+	 * @param method
+	 * @param headers
+	 * @param querys
+	 * @return
+	 * @throws Exception
+	 */
+	public static HttpResponse doGet(String host, String path, String method, 
+			Map<String, String> headers, 
+			Map<String, String> querys)
+            throws Exception {    	
+    	HttpClient httpClient = wrapClient(host);
+
+    	HttpGet request = new HttpGet(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+        	request.addHeader(e.getKey(), e.getValue());
+        }
+        
+        return httpClient.execute(request);
+    }
+	
+	/**
+	 * post form
+	 * 
+	 * @param host
+	 * @param path
+	 * @param method
+	 * @param headers
+	 * @param querys
+	 * @param bodys
+	 * @return
+	 * @throws Exception
+	 */
+	public static HttpResponse doPost(String host, String path, String method, 
+			Map<String, String> headers, 
+			Map<String, String> querys, 
+			Map<String, String> bodys)
+            throws Exception {    	
+    	HttpClient httpClient = wrapClient(host);
+
+    	HttpPost request = new HttpPost(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+        	request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (bodys != null) {
+            List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();
+
+            for (String key : bodys.keySet()) {
+                nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));
+            }
+            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
+            formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
+            request.setEntity(formEntity);
+        }
+
+        return httpClient.execute(request);
+    }	
+	
+	/**
+	 * Post String
+	 * 
+	 * @param host
+	 * @param path
+	 * @param method
+	 * @param headers
+	 * @param querys
+	 * @param body
+	 * @return
+	 * @throws Exception
+	 */
+	public static HttpResponse doPost(String host, String path, String method, 
+			Map<String, String> headers, 
+			Map<String, String> querys, 
+			String body)
+            throws Exception {    	
+    	HttpClient httpClient = wrapClient(host);
+
+    	HttpPost request = new HttpPost(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+        	request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (StringUtils.isNotBlank(body)) {
+        	request.setEntity(new StringEntity(body, "utf-8"));
+        }
+
+        return httpClient.execute(request);
+    }
+	
+	/**
+	 * Post stream
+	 * 
+	 * @param host
+	 * @param path
+	 * @param method
+	 * @param headers
+	 * @param querys
+	 * @param body
+	 * @return
+	 * @throws Exception
+	 */
+	public static HttpResponse doPost(String host, String path, String method, 
+			Map<String, String> headers, 
+			Map<String, String> querys, 
+			byte[] body)
+            throws Exception {    	
+    	HttpClient httpClient = wrapClient(host);
+
+    	HttpPost request = new HttpPost(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+        	request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (body != null) {
+        	request.setEntity(new ByteArrayEntity(body));
+        }
+
+        return httpClient.execute(request);
+    }
+	
+	/**
+	 * Put String
+	 * @param host
+	 * @param path
+	 * @param method
+	 * @param headers
+	 * @param querys
+	 * @param body
+	 * @return
+	 * @throws Exception
+	 */
+	public static HttpResponse doPut(String host, String path, String method, 
+			Map<String, String> headers, 
+			Map<String, String> querys, 
+			String body)
+            throws Exception {    	
+    	HttpClient httpClient = wrapClient(host);
+
+    	HttpPut request = new HttpPut(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+        	request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (StringUtils.isNotBlank(body)) {
+        	request.setEntity(new StringEntity(body, "utf-8"));
+        }
+
+        return httpClient.execute(request);
+    }
+	
+	/**
+	 * Put stream
+	 * @param host
+	 * @param path
+	 * @param method
+	 * @param headers
+	 * @param querys
+	 * @param body
+	 * @return
+	 * @throws Exception
+	 */
+	public static HttpResponse doPut(String host, String path, String method, 
+			Map<String, String> headers, 
+			Map<String, String> querys, 
+			byte[] body)
+            throws Exception {    	
+    	HttpClient httpClient = wrapClient(host);
+
+    	HttpPut request = new HttpPut(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+        	request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (body != null) {
+        	request.setEntity(new ByteArrayEntity(body));
+        }
+
+        return httpClient.execute(request);
+    }
+	
+	/**
+	 * Delete
+	 *  
+	 * @param host
+	 * @param path
+	 * @param method
+	 * @param headers
+	 * @param querys
+	 * @return
+	 * @throws Exception
+	 */
+	public static HttpResponse doDelete(String host, String path, String method, 
+			Map<String, String> headers, 
+			Map<String, String> querys)
+            throws Exception {    	
+    	HttpClient httpClient = wrapClient(host);
+
+    	HttpDelete request = new HttpDelete(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+        	request.addHeader(e.getKey(), e.getValue());
+        }
+        
+        return httpClient.execute(request);
+    }
+	
+	private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
+    	StringBuilder sbUrl = new StringBuilder();
+    	sbUrl.append(host);
+    	if (!StringUtils.isBlank(path)) {
+    		sbUrl.append(path);
+        }
+    	if (null != querys) {
+    		StringBuilder sbQuery = new StringBuilder();
+        	for (Map.Entry<String, String> query : querys.entrySet()) {
+        		if (0 < sbQuery.length()) {
+        			sbQuery.append("&");
+        		}
+        		if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
+        			sbQuery.append(query.getValue());
+                }
+        		if (!StringUtils.isBlank(query.getKey())) {
+        			sbQuery.append(query.getKey());
+        			if (!StringUtils.isBlank(query.getValue())) {
+        				sbQuery.append("=");
+        				sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
+        			}        			
+                }
+        	}
+        	if (0 < sbQuery.length()) {
+        		sbUrl.append("?").append(sbQuery);
+        	}
+        }
+    	
+    	return sbUrl.toString();
+    }
+	
+	private static HttpClient wrapClient(String host) {
+		HttpClient httpClient = new DefaultHttpClient();
+		if (host.startsWith("https://")) {
+			sslClient(httpClient);
+		}
+		
+		return httpClient;
+	}
+	
+	private static void sslClient(HttpClient httpClient) {
+        try {
+            SSLContext ctx = SSLContext.getInstance("TLS");
+            X509TrustManager tm = new X509TrustManager() {
+                public X509Certificate[] getAcceptedIssuers() {
+                    return null;
+                }
+                public void checkClientTrusted(X509Certificate[] xcs, String str) {
+                	
+                }
+                public void checkServerTrusted(X509Certificate[] xcs, String str) {
+                	
+                }
+            };
+            ctx.init(null, new TrustManager[] { tm }, null);
+            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
+            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+            ClientConnectionManager ccm = httpClient.getConnectionManager();
+            SchemeRegistry registry = ccm.getSchemeRegistry();
+            registry.register(new Scheme("https", 443, ssf));
+        } catch (KeyManagementException ex) {
+            throw new RuntimeException(ex);
+        } catch (NoSuchAlgorithmException ex) {
+        	throw new RuntimeException(ex);
+        }
+    }
+}

+ 288 - 0
src/main/java/com/example/demo/common/utils/RedisClient.java

@@ -0,0 +1,288 @@
+package com.example.demo.common.utils;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class RedisClient {
+
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+
+    /**
+     * 指定缓存失效时间
+     * @param key 键
+     * @param time 时间(秒)
+     * @return
+     */
+    public boolean expire(String key,long time){
+        try {
+            if(time>0){
+                redisTemplate.expire(key, time, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据key 获取过期时间
+     * @param key 键 不能为null
+     * @return 时间(秒) 返回0代表为永久有效
+     */
+    public long ttl(String key){
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 判断key是否存在
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public Boolean exists(String key){
+        return redisTemplate.hasKey(key);
+    }
+
+    //============================String=============================
+    /**
+     * 普通缓存获取
+     * @param key 键
+     * @return 值
+     */
+    public Object get(String key){
+        return key==null?null:redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * 普通缓存放入
+     * @param key 键
+     * @param value 值
+     * @return true成功 false失败
+     */
+    public boolean set(String key,Object value) {
+        try {
+            redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除缓存
+     * @param key 可以传一个值 或多个
+     */
+    public Boolean del(String key){
+        return redisTemplate.delete(key);
+    }
+
+    /**
+     * 递增
+     * @param key 键
+     * @param delta 要增加几(大于0)
+     * @return
+     */
+    public long incr(String key, long delta){
+        if(delta<0){
+            throw new RuntimeException("递增因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+    /**
+     * 递减
+     * @param key 键
+     * @param delta 要减少几(小于0)
+     * @return
+     */
+    public long decr(String key, long delta){
+        if(delta<0){
+            throw new RuntimeException("递减因子必须大于0");
+        }
+        return redisTemplate.opsForValue().decrement(key, -delta);
+    }
+
+    //================================hash=================================
+    /**
+     * HashGet
+     * @param key 键 不能为null
+     * @param item 项 不能为null
+     * @return 值
+     */
+    public Object hget(String key,String item){
+        return redisTemplate.opsForHash().get(key, item);
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     * @param key 键
+     * @param item 项
+     * @param value 值
+     * @return true 成功 false失败
+     */
+    public boolean hset(String key,String item,Object value) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除hash表中的值
+     * @param key 键 不能为null
+     * @param item 项 可以使多个 不能为null
+     */
+    public void hdel(String key, Object... item){
+        redisTemplate.opsForHash().delete(key,item);
+    }
+
+    //============================set=============================
+    /**
+     * 根据key获取Set中的所有值
+     * @param key 键
+     * @return
+     */
+    public Set<Object> smembers(String key){
+        try {
+            return redisTemplate.opsForSet().members(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 将数据放入set缓存
+     * @param key 键
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+    public long sadd(String key, Object...values) {
+        try {
+            return redisTemplate.opsForSet().add(key, values);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+
+    /**
+     * 移除值为value的
+     * @param key 键
+     * @param values 值 可以是多个
+     * @return 移除的个数
+     */
+    public long srem(String key, Object ...values) {
+        try {
+            Long count = redisTemplate.opsForSet().remove(key, values);
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 求差集
+     * @param key1
+     * @param key2
+     * @return
+     */
+    public Set<Object> diff(String key1, String key2) {
+        try {
+            return redisTemplate.opsForSet().difference(key1, key2);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+    //===============================list=================================
+
+    /**
+     * 获取list缓存的内容
+     * @param key 键
+     * @param start 开始
+     * @param end 结束  0 到 -1代表所有值
+     * @return
+     */
+    public List<Object> lrange(String key, long start, long end){
+        try {
+            return redisTemplate.opsForList().range(key, start, end);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     * @param key 键
+     * @param value 值
+     * @return
+     */
+    public boolean rpush(String key, Object value) {
+        try {
+            redisTemplate.opsForList().rightPush(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     * @param key 键
+     * @param value 值
+     * @return
+     */
+    public boolean lpush(String key, List<Object> value) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    public Set<Object> sdiff(String keya,String keyb){
+        try {
+            return   redisTemplate.opsForSet().difference(keya,keyb);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+
+    /**
+     * 移除N个值为value
+     * @param key 键
+     * @param count 移除多少个
+     * @param value 值
+     * @return 移除的个数
+     */
+    public long lrem(String key,long count,Object value) {
+        try {
+            Long remove = redisTemplate.opsForList().remove(key, count, value);
+            return remove;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+}

+ 1075 - 0
src/main/java/com/example/demo/common/utils/RedisUtil.java

@@ -0,0 +1,1075 @@
+package com.example.demo.common.utils;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.core.BoundListOperations;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
+import org.springframework.data.redis.support.atomic.RedisAtomicLong;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * redisTemplate封装
+ */
+@Component
+public class RedisUtil {
+
+    @Autowired
+    private final RedisTemplate redisTemplate;
+
+    //锁名称前缀
+    public static final String LOCK_PREFIX = "redis_lock";
+    //加锁失效时间,毫秒
+    public static final int LOCK_EXPIRE = 10; // ms
+
+    public static Integer workId=0;
+    public static Integer dataId=0;
+
+
+    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
+        this.redisTemplate = redisTemplate;
+    }
+
+
+
+    /**
+     * redis发布消息
+     *
+     * @param channel
+     * @param message
+     */
+    public void sendMessage(String channel, String message) {
+        redisTemplate.convertAndSend(channel, message);
+    }
+
+    /**
+     * 指定缓存失效时间
+     *
+     * @param key  键
+     * @param time 时间(秒)
+     * @return
+     */
+    public boolean expire(String key, long time, TimeUnit timeUnit) {
+        try {
+            if (time > 0) {
+                redisTemplate.expire(key, time, timeUnit);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据key 获取过期时间
+     *
+     * @param key 键 不能为null
+     * @return 时间(秒) 返回0代表为永久有效
+     */
+    public long getExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 判断key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public boolean hasKey(String key) {
+        try {
+            return redisTemplate.hasKey(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除缓存
+     *
+     * @param key 可以传一个值 或多个
+     */
+    @SuppressWarnings("unchecked")
+    public void del(String... key) {
+        if (key != null && key.length > 0) {
+            if (key.length == 1) {
+                redisTemplate.delete(key[0]);
+            } else {
+                redisTemplate.delete(CollectionUtils.arrayToList(key));
+            }
+        }
+    }
+
+    /**
+     * 删除缓存
+     *
+     * @param keys 集合
+     */
+    public void del(Collection<String> keys) {
+        redisTemplate.delete(keys);
+    }
+
+    //============================String=============================
+
+    /**
+     * 普通缓存获取
+     *
+     * @param key 键
+     * @return 值
+     */
+    public Object get(String key) {
+        return key == null ? null : redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * 普通缓存放入
+     *
+     * @param key   键
+     * @param value 值
+     * @return true成功 false失败
+     */
+    public boolean set(String key, Object value) {
+        try {
+            redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 普通缓存放入并设置时间
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
+     * @return true成功 false 失败
+     */
+    public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForValue().set(key, value, time, timeUnit);
+            } else {
+                set(key, value);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 递增
+     *
+     * @param key   键
+     * @param delta 要增加几(大于0)
+     * @return
+     */
+    public long incr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递增因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+    /**
+     * 递减
+     *
+     * @param key   键
+     * @param delta 要减少几(小于0)
+     * @return
+     */
+    public long decr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递减因子必须大于0");
+        }
+        return redisTemplate.opsForValue().decrement(key, delta);
+    }
+
+    //================================Map=================================
+
+    /**
+     * HashGet
+     *
+     * @param key  键 不能为null
+     * @param item 项 不能为null
+     * @return 值
+     */
+    public Object hget(String key, String item) {
+        return redisTemplate.opsForHash().get(key, item);
+    }
+
+    /**
+     * 获取hashKey对应的所有键值
+     *
+     * @param key 键
+     * @return 对应的多个键值
+     */
+    public Map<Object, Object> hmget(String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * HashSet
+     *
+     * @param key 键
+     * @param map 对应多个键值
+     * @return true 成功 false 失败
+     */
+    public boolean hmset(String key, Map<String, Object> map) {
+        try {
+            redisTemplate.opsForHash().putAll(key, map);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * HashSet 并设置时间
+     *
+     * @param key  键
+     * @param map  对应多个键值
+     * @param time 时间(秒)
+     * @return true成功 false失败
+     */
+    public boolean hmset(String key, Map<String, Object> map, long time, TimeUnit timeUnit) {
+        try {
+            redisTemplate.opsForHash().putAll(key, map);
+            if (time > 0) {
+                expire(key, time, timeUnit);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key   键
+     * @param item  项
+     * @param value 值
+     * @return true 成功 false失败
+     */
+    public boolean hset(String key, String item, Object value) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key   键
+     * @param item  项
+     * @param value 值
+     * @param time  时间(秒)  注意:如果已存在的hash表有时间,这里将会替换原有的时间
+     * @return true 成功 false失败
+     */
+    public boolean hset(String key, String item, Object value, long time, TimeUnit timeUnit) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            if (time > 0) {
+                expire(key, time, timeUnit);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除hash表中的值
+     *
+     * @param key  键 不能为null
+     * @param item 项 可以使多个 不能为null
+     */
+    public void hdel(String key, Object... item) {
+        redisTemplate.opsForHash().delete(key, item);
+    }
+
+    /**
+     * 判断hash表中是否有该项的值
+     *
+     * @param key  键 不能为null
+     * @param item 项 不能为null
+     * @return true 存在 false不存在
+     */
+    public boolean hHasKey(String key, String item) {
+        return redisTemplate.opsForHash().hasKey(key, item);
+    }
+
+    /**
+     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
+     *
+     * @param key  键
+     * @param item 项
+     * @param by   要增加几(大于0)
+     * @return
+     */
+    public double hincr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, by);
+    }
+
+    /**
+     * hash递减
+     *
+     * @param key  键
+     * @param item 项
+     * @param by   要减少记(小于0)
+     * @return
+     */
+    public double hdecr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, -by);
+    }
+
+    //============================set=============================
+
+    /**
+     * 根据key获取Set中的所有值
+     *
+     * @param key 键
+     * @return
+     */
+    public Set<Object> sGet(String key) {
+        try {
+            return redisTemplate.opsForSet().members(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 根据value从一个set中查询,是否存在
+     *
+     * @param key   键
+     * @param value 值
+     * @return true 存在 false不存在
+     */
+    public boolean sHasKey(String key, Object value) {
+        try {
+            return redisTemplate.opsForSet().isMember(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将数据放入set缓存
+     *
+     * @param key    键
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+    public long sSet(String key, Object... values) {
+        try {
+            return redisTemplate.opsForSet().add(key, values);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 获得锁
+     *
+     * @param lock
+     * @return
+     */
+    public boolean lock(String lock) {
+        return (boolean) redisTemplate.execute((RedisCallback) connection -> {
+            //获取时间毫秒值
+            long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
+            //获取锁
+            Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
+            if (acquire) {
+                return true;
+            } else {
+                byte[] bytes = connection.get(lock.getBytes());
+                //非空判断
+                if (Objects.nonNull(bytes) && bytes.length > 0) {
+                    long expireTime = Long.parseLong(new String(bytes));
+                    // 如果锁已经过期
+                    if (expireTime < System.currentTimeMillis()) {
+                        // 重新加锁,防止死锁
+                        byte[] set = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
+                        return Long.parseLong(new String(set)) < System.currentTimeMillis();
+                    }
+                }
+            }
+            return false;
+        });
+    }
+
+    /**
+     * 获得锁
+     *
+     * @param lock
+     * @return
+     */
+    public boolean lock(String lock,Long timeOut) {
+        return (boolean) redisTemplate.execute((RedisCallback) connection -> {
+            //获取时间毫秒值
+            long expireAt = System.currentTimeMillis() + timeOut + 1;
+            //获取锁
+            Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
+            if (acquire) {
+                return true;
+            } else {
+                byte[] bytes = connection.get(lock.getBytes());
+                //非空判断
+                if (Objects.nonNull(bytes) && bytes.length > 0) {
+                    long expireTime = Long.parseLong(new String(bytes));
+                    // 如果锁已经过期
+                    if (expireTime < System.currentTimeMillis()) {
+                        // 重新加锁,防止死锁
+                        byte[] set = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
+                        return Long.parseLong(new String(set)) < System.currentTimeMillis();
+                    }
+                }
+            }
+            return false;
+        });
+    }
+
+
+    /**
+     * 删除锁
+     *
+     * @param key
+     */
+    public void deleteLock(String key) {
+
+            redisTemplate.delete(key);
+
+    }
+
+
+    /**
+     * 加锁,⽆阻塞
+     * <p>
+     * 锁
+     *
+     * @param key        请求标识
+     * @param userId  超期时间
+     * @param expireTime 上锁时间,单位TimeUnit.SECONDS
+     * @param timeout 等待时间,单位TimeUnit.SECONDS
+     * @return
+     */
+    public Boolean lock(String key, long expireTime, Long userId, long timeout) {
+        Long start = System.currentTimeMillis();
+        //在⼀定时间内获取锁,超时则返回错误
+//
+        for (; ; ) {
+//,则证明获取锁成功
+//Set
+            //     OK
+            Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, userId, expireTime, TimeUnit.SECONDS);
+            if (ret != null && ret) {
+                return true;
+            }
+            //  否则循环等待,在
+            // 时间内仍未获取到锁,则获取失败
+            long end = System.currentTimeMillis() - start;
+            if (end >= timeout * 1000) {
+                return false;
+            }
+        }
+    }
+    public Boolean lock(String key, long expireTime, Long userId) {
+        Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, userId, expireTime, TimeUnit.SECONDS);
+        return ret != null && ret;
+    }
+
+    public Boolean unlock(String key, Long userId) {
+        Object o = redisTemplate.opsForValue().get(key);
+        if(userId.equals(o)){
+            return redisTemplate.delete(key);
+        }else{
+            return false;
+        }
+    }
+    /**
+     * 将set数据放入缓存
+     *
+     * @param key    键
+     * @param time   时间(秒)
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+    public long sSetAndTime(String key, long time, TimeUnit timeUnit, Object... values) {
+        try {
+            Long count = redisTemplate.opsForSet().add(key, values);
+            if (time > 0) {
+                expire(key, time, timeUnit);
+            }
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 获取set缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+    public long sGetSetSize(String key) {
+        try {
+            return redisTemplate.opsForSet().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 移除值为value的
+     *
+     * @param key    键
+     * @param values 值 可以是多个
+     * @return 移除的个数
+     */
+    public long setRemove(String key, Object... values) {
+        try {
+            Long count = redisTemplate.opsForSet().remove(key, values);
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+    //===============================list=================================
+
+    /**
+     * 获取list缓存的内容
+     *
+     * @param key   键
+     * @param start 开始
+     * @param end   结束  0 到 -1代表所有值
+     * @return
+     */
+    public List<Object> listGet(String key, long start, long end) {
+        try {
+            return redisTemplate.opsForList().range(key, start, end);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+
+    /**
+     * 弹出对象
+     * @param key
+     * @return
+     */
+    public Object popLeftList(String key){
+        return redisTemplate.opsForList().leftPop(key);
+    }
+
+    /**
+     * 获取list缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+    public long listSize(String key) {
+        try {
+            return redisTemplate.opsForList().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 通过索引 获取list中的值
+     *
+     * @param key   键
+     * @param index 索引  index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
+     * @return
+     */
+    public Object listGetIndex(String key, long index) {
+        try {
+            return redisTemplate.opsForList().index(key, index);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @return
+     */
+    public boolean listSet(String key, Object value) {
+        try {
+
+            redisTemplate.opsForList().rightPush(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    public void listTrim(String key, long start,long end) {
+        try {
+
+            redisTemplate.opsForList().trim(key,start,end);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒)
+     * @return
+     */
+    public boolean listSet(String key, Object value, long time, TimeUnit timeUnit) {
+        try {
+            redisTemplate.opsForList().rightPush(key, value);
+            if (time > 0) {
+                expire(key, time, timeUnit);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @return
+     */
+    public boolean listSet(String key, List<Object> value) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * list大小
+     * @param key
+     * @return
+     */
+    public Long getListSize(String key){
+        return redisTemplate.opsForList().size(key);
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒)
+     * @return
+     */
+    public boolean listSet(String key, List<Object> value, long time, TimeUnit timeUnit) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            if (time > 0) {
+                expire(key, time, timeUnit);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据索引修改list中的某条数据
+     *
+     * @param key   键
+     * @param index 索引
+     * @param value 值
+     * @return
+     */
+    public boolean listUpdateIndex(String key, long index, Object value) {
+        try {
+            redisTemplate.opsForList().set(key, index, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 移除N个值为value
+     *
+     * @param key   键
+     * @param count 移除多少个
+     * @param value 值
+     * @return 移除的个数
+     */
+    public long listRemove(String key, long count, Object value) {
+        try {
+            Long remove = redisTemplate.opsForList().remove(key, count, value);
+            return remove;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 模糊查询获取key值
+     *
+     * @param pattern
+     * @return
+     */
+    public Set keys(String pattern) {
+        return redisTemplate.keys(pattern);
+    }
+
+    /**
+     * 使用Redis的消息队列
+     *
+     * @param channel
+     * @param message 消息内容
+     */
+    public void convertAndSend(String channel, Object message) {
+        redisTemplate.convertAndSend(channel, message);
+    }
+
+
+    //=========BoundListOperations 用法 start============
+
+    /**
+     * 将数据添加到Redis的list中(从右边添加)
+     *
+     * @param listKey
+     * @param time    过期时间
+     * @param values  待添加的数据
+     */
+    public void addToListRight(String listKey, long time, Object... values) {
+        //绑定操作
+        BoundListOperations<String, Object> boundValueOperations = redisTemplate.boundListOps(listKey);
+        //插入数据
+        boundValueOperations.rightPushAll(values);
+        //设置过期时间
+        boundValueOperations.expire(time, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 根据起始结束序号遍历Redis中的list
+     *
+     * @param listKey
+     * @param start   起始序号
+     * @param end     结束序号
+     * @return
+     */
+    public List<Object> rangeList(String listKey, long start, long end) {
+        //绑定操作
+        BoundListOperations<String, Object> boundValueOperations = redisTemplate.boundListOps(listKey);
+        //查询数据
+        return boundValueOperations.range(start, end);
+    }
+
+    /**
+     * 弹出右边的值 --- 并且移除这个值
+     *
+     * @param listKey
+     */
+    public Object rifhtPop(String listKey) {
+        //绑定操作
+        BoundListOperations<String, Object> boundValueOperations = redisTemplate.boundListOps(listKey);
+        return boundValueOperations.rightPop();
+    }
+
+    /**
+     * @param key
+     * @return
+     */
+    public Long getIncr(String key) {
+        RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
+        Long increment = entityIdCounter.getAndIncrement();
+        return increment;
+    }
+
+    /**
+     * @return
+     */
+    public synchronized Integer getSequenceId() {
+        String key = "sms_sequence_id";
+        RedisAtomicInteger idCount = new RedisAtomicInteger(key, redisTemplate.getConnectionFactory());
+        int sequenceId = idCount.getAndIncrement();
+        if (sequenceId <= 1000 || sequenceId >= 1000000000) {
+            idCount.set(1000);
+            sequenceId = idCount.getAndIncrement();
+            return sequenceId;
+        }
+        return sequenceId;
+    }
+
+    public void setCount(String key ,int initValue){
+        RedisAtomicInteger idCount = new RedisAtomicInteger(key, redisTemplate.getConnectionFactory());
+        idCount.set(initValue);
+    }
+    /**
+     * @return
+     */
+    public  Integer getCount(String key) {
+        RedisAtomicInteger idCount = new RedisAtomicInteger(key, redisTemplate.getConnectionFactory());
+        int count = idCount.getAndIncrement();
+        if (count ==Integer.MAX_VALUE-1) {
+            idCount.set(0);
+            count = idCount.getAndIncrement();
+            return count;
+        }
+        return count;
+    }
+    public  Integer getStartCount(String key) {
+        RedisAtomicInteger idCount = new RedisAtomicInteger(key, redisTemplate.getConnectionFactory());
+
+        int count = idCount.getAndIncrement();
+        if(count<=1){
+            this.expire(key, CacheKey.DAY1,TimeUnit.DAYS);
+        }
+        if (count ==Integer.MAX_VALUE-1) {
+
+            idCount.set(0);
+            count = idCount.getAndIncrement();
+            return count;
+        }
+
+        return count;
+    }
+    public String getStartNum(Integer num){
+
+        String str=num.toString();
+        int len=str.length();
+        if(str.length()<5){
+            StringBuilder sb = new StringBuilder();
+            for(int i=0;i<5-len;i++){
+
+                sb.append("0");
+
+            }
+            sb.append(str);
+            return sb.toString();
+        }
+        return str;
+    }
+    public String getStartNum(String key){
+        Integer num=getStartCount(key);
+        String str=num.toString();
+        int len=str.length();
+        if(str.length()<5){
+            StringBuilder sb = new StringBuilder();
+            for(int i=0;i<5-len;i++){
+
+                    sb.append("0");
+
+            }
+            sb.append(str);
+            return sb.toString();
+        }
+        return str;
+    }
+
+
+    public synchronized Integer getSequenceNumber3(String key) {
+        RedisAtomicInteger idCount = new RedisAtomicInteger(key, redisTemplate.getConnectionFactory());
+        int sequenceId = idCount.getAndIncrement();
+        if (sequenceId < 0 || sequenceId >= Integer.MAX_VALUE) {
+            idCount.set(0);
+            sequenceId = idCount.getAndIncrement();
+            return sequenceId;
+        }
+        return sequenceId;
+    }
+    public synchronized  Integer getWorkId(String key) {
+        RedisAtomicInteger idCount = new RedisAtomicInteger(key, redisTemplate.getConnectionFactory());
+        int sequenceId = idCount.getAndIncrement();
+        if (sequenceId < 0 || sequenceId >= 31) {
+            idCount.set(0);
+            sequenceId = idCount.getAndIncrement();
+            return sequenceId;
+        }
+        return sequenceId;
+    }
+
+    /**
+     * 14      * @Description: 初始化自增长值
+     * 15      * @param key key
+     * 16      * @param value 当前值
+     * 17
+     */
+    public void setIncr(String key, int value) {
+        RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
+        counter.set(value);
+    }
+
+    /**
+     * 14      * @Description: 初始化自增长值
+     * 15      * @param key key
+     * 16      * @param value 当前值
+     * 17
+     */
+    public void setInteger(String key, int value) {
+        RedisAtomicInteger counter = new RedisAtomicInteger(key, redisTemplate.getConnectionFactory());
+        counter.set(value);
+    }
+
+
+    /**
+     * 保存到hash
+     * @param key
+     * @param hashKey
+     * @param value
+     */
+    public void setHashMap(String key,Object hashKey,Object value){
+        redisTemplate.opsForHash().put(key,hashKey,value);
+    }
+
+    /**
+     * 获取hashvalue
+     * @param key
+     * @param hashKey
+     * @return
+     */
+    public Object getHashValue(String key,Object hashKey){
+       return  redisTemplate.opsForHash().get(key,hashKey);
+    }
+
+    /**
+     * 删除hash中单个对象
+     * @param key
+     * @param hashKey
+     */
+    public void remove(String key,Object hashKey){
+        redisTemplate.opsForHash().delete(key,hashKey);
+    }
+
+    /**
+     * 获取redisTemplate
+     * @return
+     */
+    public RedisTemplate getRedisTemplate(){
+        return redisTemplate;
+    }
+
+    /**
+     * 存储数据或修改数据
+     *
+     * @param modelMap
+     * @param mapName
+     */
+    public void setMap(String mapName, Map<String, Object> modelMap) {
+        HashOperations<String, Object, Object> hps = redisTemplate.opsForHash();
+        hps.putAll(mapName, modelMap);
+    }
+
+    /**
+     * 获取数据Map
+     *
+     * @param mapName
+     * @return
+     */
+    public Map<Object, Object> getMapValue(String mapName) {
+        HashOperations<String, Object, Object> hps = this.redisTemplate.opsForHash();
+        return hps.entries(mapName);
+
+    }
+
+    /**
+     * 获取数据Map size
+     *
+     * @param mapName
+     * @return
+     */
+    public int getMapSize(String mapName) {
+        HashOperations<String, Object, Object> hps = this.redisTemplate.opsForHash();
+        return hps.entries(mapName).size();
+
+    }
+
+    /**
+     * 获取数据value
+     *
+     * @param mapName
+     * @param hashKey
+     * @return
+     */
+    public Object getValue(String mapName, String hashKey) {
+        HashOperations<String, Object, Object> hps = this.redisTemplate.opsForHash();
+        return hps.get(mapName, hashKey);
+
+    }
+
+    /**
+     * 批量删除缓存数据
+     *
+     * @param keys
+     */
+    public long deleteData(String key,Object ...keys) {
+        // 执行批量删除操作时先序列化template
+       long b= redisTemplate.opsForHash().delete(key,keys);
+       return b;
+    }
+
+    private void batchCacheMarketInfo(List<Object > dataList, long expire) {
+        //使用pipeline方式
+        redisTemplate.executePipelined(new RedisCallback<List<Object>>() {
+            @Override
+            public List<Object> doInRedis(RedisConnection connection) throws DataAccessException {
+                for (Object marketInfo : dataList) {
+                    String key = "";
+                    byte[] rawKey = redisTemplate.getKeySerializer().serialize(key);
+                    connection.setEx(rawKey, expire, redisTemplate.getValueSerializer().serialize(marketInfo));
+                }
+                return null;
+            }
+        });
+
+    }
+
+
+
+    //=========BoundListOperations 用法 End============
+
+}

+ 30 - 0
src/main/java/com/example/demo/coupon/controller/UserCouponController.java

@@ -0,0 +1,30 @@
+package com.example.demo.coupon.controller;
+
+import com.example.demo.coupon.dto.PageDto;
+import com.example.demo.coupon.dto.UserCouponDto;
+import com.example.demo.coupon.service.impl.CouponServiceImpl;
+import com.example.demo.coupon.service.impl.UserCouponServiceImpl;
+import com.example.demo.user.vo.ResultVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/coupon")
+public class UserCouponController {
+    @Autowired
+    private CouponServiceImpl couponService;
+    @Autowired
+    private UserCouponServiceImpl userCouponService;
+    @RequestMapping("/getCouponList")
+    public ResultVo getCouponList(@RequestBody PageDto dto, @RequestHeader("token") String token) {
+        return couponService.getCouponList(dto,token);
+    }
+
+    @RequestMapping("/userGetCoupon")
+    public ResultVo userGetCoupon(@RequestBody UserCouponDto dto, @RequestHeader("token")String token){
+        return userCouponService.userGetCoupon(dto,token);
+    }
+}

+ 20 - 0
src/main/java/com/example/demo/coupon/dao/CouponMapper.java

@@ -0,0 +1,20 @@
+package com.example.demo.coupon.dao;
+
+import com.example.demo.coupon.domain.Coupon;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @author 徐乐
+* @description 针对表【coupon(优惠券主表)】的数据库操作Mapper
+* @createDate 2025-06-17 18:40:22
+* @Entity com.example.demo.coupon.domain.Coupon
+*/
+@Mapper
+public interface CouponMapper extends BaseMapper<Coupon> {
+
+}
+
+
+
+

+ 20 - 0
src/main/java/com/example/demo/coupon/dao/UserCouponMapper.java

@@ -0,0 +1,20 @@
+package com.example.demo.coupon.dao;
+
+import com.example.demo.coupon.domain.UserCoupon;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @author 徐乐
+* @description 针对表【user_coupon(用户优惠券记录表)】的数据库操作Mapper
+* @createDate 2025-06-17 18:40:22
+* @Entity com.example.demo.coupon.domain.UserCoupon
+*/
+@Mapper
+public interface UserCouponMapper extends BaseMapper<UserCoupon> {
+
+}
+
+
+
+

+ 161 - 0
src/main/java/com/example/demo/coupon/domain/Coupon.java

@@ -0,0 +1,161 @@
+package com.example.demo.coupon.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.math.BigDecimal;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 优惠券主表
+ * @TableName coupon
+ */
+@TableName(value ="coupon")
+@Data
+public class Coupon {
+    /**
+     * 优惠券ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 优惠券类型:1-满减券 2-折扣券 3-无门槛券
+     */
+    private Integer couponType;
+
+    /**
+     * 优惠券名称
+     */
+    private String couponName;
+
+    /**
+     * 优惠券描述
+     */
+    private String couponDesc;
+
+    /**
+     * 优惠金额(满减/无门槛)
+     */
+    private BigDecimal amount;
+
+    /**
+     * 折扣率(折扣券,如0.8表示8折)
+     */
+    private BigDecimal discount;
+
+    /**
+     * 最低消费金额
+     */
+    private BigDecimal minAmount;
+
+    /**
+     * 总发行量
+     */
+    private Integer totalCount;
+
+    /**
+     * 剩余数量
+     */
+    private Integer remainCount;
+
+    /**
+     * 发放开始时间
+     */
+    private Date issueStartTime;
+
+    /**
+     * 发放结束时间
+     */
+    private Date issueEndTime;
+
+    /**
+     * 状态:1-生效中 2-已过期 3-已停用
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        Coupon other = (Coupon) that;
+        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+            && (this.getCouponType() == null ? other.getCouponType() == null : this.getCouponType().equals(other.getCouponType()))
+            && (this.getCouponName() == null ? other.getCouponName() == null : this.getCouponName().equals(other.getCouponName()))
+            && (this.getCouponDesc() == null ? other.getCouponDesc() == null : this.getCouponDesc().equals(other.getCouponDesc()))
+            && (this.getAmount() == null ? other.getAmount() == null : this.getAmount().equals(other.getAmount()))
+            && (this.getDiscount() == null ? other.getDiscount() == null : this.getDiscount().equals(other.getDiscount()))
+            && (this.getMinAmount() == null ? other.getMinAmount() == null : this.getMinAmount().equals(other.getMinAmount()))
+            && (this.getTotalCount() == null ? other.getTotalCount() == null : this.getTotalCount().equals(other.getTotalCount()))
+            && (this.getRemainCount() == null ? other.getRemainCount() == null : this.getRemainCount().equals(other.getRemainCount()))
+            && (this.getIssueStartTime() == null ? other.getIssueStartTime() == null : this.getIssueStartTime().equals(other.getIssueStartTime()))
+            && (this.getIssueEndTime() == null ? other.getIssueEndTime() == null : this.getIssueEndTime().equals(other.getIssueEndTime()))
+            && (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus()))
+            && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime()))
+            && (this.getUpdateTime() == null ? other.getUpdateTime() == null : this.getUpdateTime().equals(other.getUpdateTime()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+        result = prime * result + ((getCouponType() == null) ? 0 : getCouponType().hashCode());
+        result = prime * result + ((getCouponName() == null) ? 0 : getCouponName().hashCode());
+        result = prime * result + ((getCouponDesc() == null) ? 0 : getCouponDesc().hashCode());
+        result = prime * result + ((getAmount() == null) ? 0 : getAmount().hashCode());
+        result = prime * result + ((getDiscount() == null) ? 0 : getDiscount().hashCode());
+        result = prime * result + ((getMinAmount() == null) ? 0 : getMinAmount().hashCode());
+        result = prime * result + ((getTotalCount() == null) ? 0 : getTotalCount().hashCode());
+        result = prime * result + ((getRemainCount() == null) ? 0 : getRemainCount().hashCode());
+        result = prime * result + ((getIssueStartTime() == null) ? 0 : getIssueStartTime().hashCode());
+        result = prime * result + ((getIssueEndTime() == null) ? 0 : getIssueEndTime().hashCode());
+        result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode());
+        result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode());
+        result = prime * result + ((getUpdateTime() == null) ? 0 : getUpdateTime().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", couponType=").append(couponType);
+        sb.append(", couponName=").append(couponName);
+        sb.append(", couponDesc=").append(couponDesc);
+        sb.append(", amount=").append(amount);
+        sb.append(", discount=").append(discount);
+        sb.append(", minAmount=").append(minAmount);
+        sb.append(", totalCount=").append(totalCount);
+        sb.append(", remainCount=").append(remainCount);
+        sb.append(", issueStartTime=").append(issueStartTime);
+        sb.append(", issueEndTime=").append(issueEndTime);
+        sb.append(", status=").append(status);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 74 - 0
src/main/java/com/example/demo/coupon/domain/UserCoupon.java

@@ -0,0 +1,74 @@
+package com.example.demo.coupon.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 用户优惠券记录表
+ * @TableName user_coupon
+ */
+@TableName(value ="user_coupon")
+@Data
+public class UserCoupon {
+    /**
+     * 用户优惠券ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 优惠券ID
+     */
+    private Long couponId;
+
+    /**
+     * 优惠券名称
+     */
+    private String couponName;
+
+    /**
+     * 优惠金额
+     */
+    private BigDecimal amount;
+
+    /**
+     * 领取时间
+     */
+    private Date obtainTime;
+
+    /**
+     * 使用时间
+     */
+    private Date useTime;
+
+    /**
+     * 过期时间
+     */
+    private Date expireTime;
+
+    /**
+     * 状态:1-未使用 2-已使用 3-已过期 4-已作废
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+}

+ 9 - 0
src/main/java/com/example/demo/coupon/dto/PageDto.java

@@ -0,0 +1,9 @@
+package com.example.demo.coupon.dto;
+
+import lombok.Data;
+
+@Data
+public class PageDto {
+    private int pageNum;
+    private int pageSize;
+}

+ 8 - 0
src/main/java/com/example/demo/coupon/dto/UserCouponDto.java

@@ -0,0 +1,8 @@
+package com.example.demo.coupon.dto;
+
+import lombok.Data;
+
+@Data
+public class UserCouponDto {
+    private Long couponId;
+}

+ 16 - 0
src/main/java/com/example/demo/coupon/service/CouponService.java

@@ -0,0 +1,16 @@
+package com.example.demo.coupon.service;
+
+import com.example.demo.coupon.domain.Coupon;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.demo.coupon.dto.PageDto;
+import com.example.demo.user.vo.ResultVo;
+
+/**
+* @author 徐乐
+* @description 针对表【coupon(优惠券主表)】的数据库操作Service
+* @createDate 2025-06-17 18:40:22
+*/
+public interface CouponService extends IService<Coupon> {
+
+    ResultVo getCouponList(PageDto dto, String Token);
+}

+ 16 - 0
src/main/java/com/example/demo/coupon/service/UserCouponService.java

@@ -0,0 +1,16 @@
+package com.example.demo.coupon.service;
+
+import com.example.demo.coupon.domain.UserCoupon;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.demo.coupon.dto.UserCouponDto;
+import com.example.demo.user.vo.ResultVo;
+
+/**
+* @author 徐乐
+* @description 针对表【user_coupon(用户优惠券记录表)】的数据库操作Service
+* @createDate 2025-06-17 18:40:22
+*/
+public interface UserCouponService extends IService<UserCoupon> {
+
+    ResultVo userGetCoupon(UserCouponDto dto, String token);
+}

+ 44 - 0
src/main/java/com/example/demo/coupon/service/impl/CouponServiceImpl.java

@@ -0,0 +1,44 @@
+package com.example.demo.coupon.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.demo.common.utils.TokenUtils;
+import com.example.demo.coupon.domain.Coupon;
+import com.example.demo.coupon.dto.PageDto;
+import com.example.demo.coupon.service.CouponService;
+import com.example.demo.coupon.dao.CouponMapper;
+import com.example.demo.user.vo.ResultVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+* @author 徐乐
+* @description 针对表【coupon(优惠券主表)】的数据库操作Service实现
+* @createDate 2025-06-17 18:40:22
+*/
+@Service
+public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon>
+    implements CouponService{
+    @Autowired
+    private CouponMapper couponMapper;
+
+    @Override
+    public ResultVo getCouponList(PageDto dto, String token) {
+        Long userId = TokenUtils.getUserId(token);
+        if (userId==null){
+            return ResultVo.error(101,"请先登录");
+        }
+        Page<Coupon> page = new Page<>(dto.getPageNum(),dto.getPageSize());
+        QueryWrapper<Coupon> queryWrapper = new QueryWrapper<>();
+        couponMapper.selectPage(page,queryWrapper);
+        List<Coupon> couponList = page.getRecords();
+        return ResultVo.success(couponList);
+    }
+}
+
+
+
+

+ 65 - 0
src/main/java/com/example/demo/coupon/service/impl/UserCouponServiceImpl.java

@@ -0,0 +1,65 @@
+package com.example.demo.coupon.service.impl;
+
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.demo.common.utils.TokenUtils;
+import com.example.demo.coupon.dao.CouponMapper;
+import com.example.demo.coupon.domain.Coupon;
+import com.example.demo.coupon.domain.UserCoupon;
+import com.example.demo.coupon.dto.UserCouponDto;
+import com.example.demo.coupon.service.UserCouponService;
+import com.example.demo.coupon.dao.UserCouponMapper;
+import com.example.demo.user.vo.ResultVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+* @author 徐乐
+* @description 针对表【user_coupon(用户优惠券记录表)】的数据库操作Service实现
+* @createDate 2025-06-17 18:40:22
+*/
+@Service
+public class UserCouponServiceImpl extends ServiceImpl<UserCouponMapper, UserCoupon>
+    implements UserCouponService{
+
+    @Autowired
+    private CouponMapper couponMapper;
+    @Autowired
+    private UserCouponMapper userCouponMapper;
+
+    @Override
+    public ResultVo userGetCoupon(UserCouponDto dto, String token) {
+        Long userId = TokenUtils.getUserId(token);
+        if (userId==null){
+            return ResultVo.error(101,"请先登录");
+        }
+        UserCoupon userCoupon = new UserCoupon();
+        userCoupon.setId(IdUtil.getSnowflake().nextId());
+        userCoupon.setUserId(userId);
+        Coupon coupon = couponMapper.selectById(dto.getCouponId());
+        userCoupon.setCouponId(coupon.getId());
+        userCoupon.setCouponName(coupon.getCouponName());
+        userCoupon.setAmount(coupon.getAmount());
+        coupon.setRemainCount(coupon.getRemainCount()-1);
+        userCoupon.setObtainTime(new Date());
+        userCoupon.setUseTime(null);
+        // 处理 endTime:基于 startTime 延长 7 天
+        Date startTime = userCoupon.getObtainTime();
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(startTime);
+        // 关键:Calendar.DAY_OF_MONTH 代表日期字段,加 7 天
+        calendar.add(Calendar.DAY_OF_MONTH, 7);
+        Date endTime = calendar.getTime();
+        userCoupon.setExpireTime(endTime);
+        userCouponMapper.insert(userCoupon);
+        couponMapper.updateById(coupon);
+        return ResultVo.success("用户领取优惠券成功");
+    }
+}
+
+
+
+

+ 36 - 0
src/main/java/com/example/demo/order/controller/OrderController.java

@@ -0,0 +1,36 @@
+package com.example.demo.order.controller;
+
+import com.example.demo.order.dto.OrderInfoDto;
+import com.example.demo.order.dto.OrderInfoUpDto;
+import com.example.demo.order.service.impl.OrderInfoServiceImpl;
+import com.example.demo.user.vo.ResultVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+@RestController
+@RequestMapping("/order")
+public class OrderController {
+    @Autowired
+    private OrderInfoServiceImpl orderInfoService;
+    @RequestMapping("/orderAdd")
+    public ResultVo orderAdd(@RequestBody OrderInfoDto dto,@RequestHeader("token") String token){
+        return orderInfoService.orderAdd(dto,token);
+    }
+    @RequestMapping("/orderUp")
+    public ResultVo orderUp(@RequestBody OrderInfoUpDto dto, @RequestHeader("token") String token){
+        return orderInfoService.orderUp(dto,token);
+    }
+    @RequestMapping("/orderGetList")
+    public ResultVo orderGetList(@RequestHeader("token") String token){
+        return orderInfoService.orderGetList(token);
+    }
+    @RequestMapping("/pay/{orderId}")
+    public ResultVo orderPay(@PathVariable("orderId") Long orderId,
+                            @RequestParam("paymentMethod") Integer paymentMethod,
+                            HttpServletRequest request) {
+        String token = request.getHeader("token");
+        return orderInfoService.orderPay(orderId, paymentMethod, token);
+    }
+}

+ 20 - 0
src/main/java/com/example/demo/order/dao/OrderInfoMapper.java

@@ -0,0 +1,20 @@
+package com.example.demo.order.dao;
+
+import com.example.demo.order.domain.OrderInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @author 徐乐
+* @description 针对表【order_info(订单主表)】的数据库操作Mapper
+* @createDate 2025-06-17 19:27:10
+* @Entity com.example.demo.order.domain.OrderInfo
+*/
+@Mapper
+public interface OrderInfoMapper extends BaseMapper<OrderInfo> {
+
+}
+
+
+
+

+ 22 - 0
src/main/java/com/example/demo/order/dao/OrderItemMapper.java

@@ -0,0 +1,22 @@
+package com.example.demo.order.dao;
+
+import com.example.demo.order.domain.OrderItem;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+* @author 徐乐
+* @description 针对表【order_item(订单详情表)】的数据库操作Mapper
+* @createDate 2025-06-17 19:27:10
+* @Entity com.example.demo.order.domain.OrderItem
+*/
+@Mapper
+public interface OrderItemMapper extends BaseMapper<OrderItem> {
+}
+
+
+
+

+ 145 - 0
src/main/java/com/example/demo/order/domain/OrderInfo.java

@@ -0,0 +1,145 @@
+package com.example.demo.order.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.math.BigDecimal;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 订单主表
+ * @TableName order_info
+ */
+@TableName(value ="order_info")
+@Data
+public class OrderInfo {
+    /**
+     * 订单ID
+     */
+    @TableId
+    private Long id;
+
+    /**
+     * 订单编号
+     */
+    private String orderNo;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 订单总金额
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 优惠金额
+     */
+    private BigDecimal discountAmount;
+
+    /**
+     * 实际支付金额
+     */
+    private BigDecimal actualAmount;
+
+    /**
+     * 支付方式:1-微信 3-银行卡
+     */
+    private Integer paymentMethod;
+
+    /**
+     * 支付时间
+     */
+    private Date paymentTime;
+
+    /**
+     * 订单状态:1-待支付 2-已支付  4-已完成 5-已取消
+     */
+    private Integer orderStatus;
+
+    /**
+     * 使用的用户优惠券ID
+     */
+    private Long userCouponId;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        OrderInfo other = (OrderInfo) that;
+        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+            && (this.getOrderNo() == null ? other.getOrderNo() == null : this.getOrderNo().equals(other.getOrderNo()))
+            && (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId()))
+            && (this.getTotalAmount() == null ? other.getTotalAmount() == null : this.getTotalAmount().equals(other.getTotalAmount()))
+            && (this.getDiscountAmount() == null ? other.getDiscountAmount() == null : this.getDiscountAmount().equals(other.getDiscountAmount()))
+            && (this.getActualAmount() == null ? other.getActualAmount() == null : this.getActualAmount().equals(other.getActualAmount()))
+            && (this.getPaymentMethod() == null ? other.getPaymentMethod() == null : this.getPaymentMethod().equals(other.getPaymentMethod()))
+            && (this.getPaymentTime() == null ? other.getPaymentTime() == null : this.getPaymentTime().equals(other.getPaymentTime()))
+            && (this.getOrderStatus() == null ? other.getOrderStatus() == null : this.getOrderStatus().equals(other.getOrderStatus()))
+            && (this.getUserCouponId() == null ? other.getUserCouponId() == null : this.getUserCouponId().equals(other.getUserCouponId()))
+            && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime()))
+            && (this.getUpdateTime() == null ? other.getUpdateTime() == null : this.getUpdateTime().equals(other.getUpdateTime()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+        result = prime * result + ((getOrderNo() == null) ? 0 : getOrderNo().hashCode());
+        result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode());
+        result = prime * result + ((getTotalAmount() == null) ? 0 : getTotalAmount().hashCode());
+        result = prime * result + ((getDiscountAmount() == null) ? 0 : getDiscountAmount().hashCode());
+        result = prime * result + ((getActualAmount() == null) ? 0 : getActualAmount().hashCode());
+        result = prime * result + ((getPaymentMethod() == null) ? 0 : getPaymentMethod().hashCode());
+        result = prime * result + ((getPaymentTime() == null) ? 0 : getPaymentTime().hashCode());
+        result = prime * result + ((getOrderStatus() == null) ? 0 : getOrderStatus().hashCode());
+        result = prime * result + ((getUserCouponId() == null) ? 0 : getUserCouponId().hashCode());
+        result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode());
+        result = prime * result + ((getUpdateTime() == null) ? 0 : getUpdateTime().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", orderNo=").append(orderNo);
+        sb.append(", userId=").append(userId);
+        sb.append(", totalAmount=").append(totalAmount);
+        sb.append(", discountAmount=").append(discountAmount);
+        sb.append(", actualAmount=").append(actualAmount);
+        sb.append(", paymentMethod=").append(paymentMethod);
+        sb.append(", paymentTime=").append(paymentTime);
+        sb.append(", orderStatus=").append(orderStatus);
+        sb.append(", userCouponId=").append(userCouponId);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 78 - 0
src/main/java/com/example/demo/order/domain/OrderItem.java

@@ -0,0 +1,78 @@
+package com.example.demo.order.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.math.BigDecimal;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 订单详情表
+ * @TableName order_item
+ */
+@TableName(value ="order_item")
+@Data
+public class OrderItem {
+    /**
+     * 订单详情ID
+     */
+    @TableId
+    private Long id;
+
+    /**
+     * 订单ID
+     */
+    private Long orderId;
+
+    /**
+     * 商品ID
+     */
+    private Long productId;
+
+    /**
+     * 商品名称
+     */
+    private String productName;
+
+    /**
+     * 商品单价
+     */
+    private BigDecimal price;
+
+    /**
+     * 商品数量
+     */
+    private Integer quantity;
+
+    /**
+     * 商品小计金额
+     */
+    private BigDecimal itemAmount;
+
+    /**
+     * 优惠券id
+     */
+    private Long couponId;
+
+    /**
+     * 优惠金额
+     */
+    private BigDecimal discountAmount;
+
+    /**
+     * 实付金额
+     */
+    private BigDecimal payAmount;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+}

+ 11 - 0
src/main/java/com/example/demo/order/dto/OrderInfoDto.java

@@ -0,0 +1,11 @@
+package com.example.demo.order.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class OrderInfoDto {
+    private List<OrderItemDto> orderItemDtos;
+    private Integer paymentMethod;
+}

+ 15 - 0
src/main/java/com/example/demo/order/dto/OrderInfoUpDto.java

@@ -0,0 +1,15 @@
+package com.example.demo.order.dto;
+
+import lombok.Data;
+
+@Data
+public class OrderInfoUpDto {
+
+    private Long id;
+
+    private Integer orderStatus;
+
+    private Integer quantity;
+
+    private Long couponId;
+}

+ 13 - 0
src/main/java/com/example/demo/order/dto/OrderItemDto.java

@@ -0,0 +1,13 @@
+package com.example.demo.order.dto;
+
+import lombok.Data;
+
+@Data
+public class OrderItemDto {
+
+    private Long productId;
+
+    private Integer quantity;
+
+    private Long couponId;
+}

+ 23 - 0
src/main/java/com/example/demo/order/service/OrderInfoService.java

@@ -0,0 +1,23 @@
+package com.example.demo.order.service;
+
+import com.example.demo.order.domain.OrderInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.demo.order.dto.OrderInfoDto;
+import com.example.demo.order.dto.OrderInfoUpDto;
+import com.example.demo.user.vo.ResultVo;
+
+/**
+* @author 徐乐
+* @description 针对表【order_info(订单主表)】的数据库操作Service
+* @createDate 2025-06-17 19:27:10
+*/
+public interface OrderInfoService extends IService<OrderInfo> {
+
+    ResultVo orderAdd(OrderInfoDto dto, String token);
+
+    ResultVo orderUp(OrderInfoUpDto dto, String token);
+
+    ResultVo orderGetList(String token);
+
+    ResultVo orderPay(Long orderId, Integer paymentMethod, String token);
+}

+ 13 - 0
src/main/java/com/example/demo/order/service/OrderItemService.java

@@ -0,0 +1,13 @@
+package com.example.demo.order.service;
+
+import com.example.demo.order.domain.OrderItem;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+* @author 徐乐
+* @description 针对表【order_item(订单详情表)】的数据库操作Service
+* @createDate 2025-06-17 19:27:10
+*/
+public interface OrderItemService extends IService<OrderItem> {
+
+}

+ 241 - 0
src/main/java/com/example/demo/order/service/impl/OrderInfoServiceImpl.java

@@ -0,0 +1,241 @@
+package com.example.demo.order.service.impl;
+
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.demo.common.utils.DateUtils;
+import com.example.demo.common.utils.RedisUtil;
+import com.example.demo.common.utils.TokenUtils;
+import com.example.demo.coupon.dao.CouponMapper;
+import com.example.demo.coupon.dao.UserCouponMapper;
+import com.example.demo.coupon.domain.UserCoupon;
+import com.example.demo.order.dao.OrderItemMapper;
+import com.example.demo.order.domain.OrderInfo;
+import com.example.demo.order.domain.OrderItem;
+import com.example.demo.order.dto.OrderInfoDto;
+import com.example.demo.order.dto.OrderInfoUpDto;
+import com.example.demo.order.dto.OrderItemDto;
+import com.example.demo.order.service.OrderInfoService;
+import com.example.demo.order.dao.OrderInfoMapper;
+import com.example.demo.product.dao.ProductMapper;
+import com.example.demo.product.domain.Product;
+import com.example.demo.user.vo.ResultVo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+* @author 徐乐
+* @description 针对表【order_info(订单主表)】的数据库操作Service实现
+* @createDate 2025-06-17 19:27:10
+*/
+@Service
+public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo>
+    implements OrderInfoService{
+
+    private static final Logger log = LoggerFactory.getLogger(OrderInfoServiceImpl.class);
+
+    @Autowired
+    private OrderInfoMapper orderInfoMapper;
+    @Autowired
+    private OrderItemMapper orderItemMapper;
+    @Autowired
+    private ProductMapper productMapper;
+    @Autowired
+    private RedisUtil redisUtil;
+    @Autowired
+    private UserCouponMapper userCouponMapper;
+    @Autowired
+    private CouponMapper couponMapper;
+
+    @Override
+    public ResultVo orderAdd(OrderInfoDto dto, String token) {
+        Long userId = TokenUtils.getUserId(token);
+        if (userId==null){
+            return ResultVo.error(101,"请先登录");
+        }
+        OrderInfo orderInfo = new OrderInfo();
+        orderInfo.setId(IdUtil.getSnowflake().nextId());
+        String yyMMddHHmmss = DateUtils.getDateTimeNum();
+        String startNum = redisUtil.getStartNum(yyMMddHHmmss);
+        //订单编号
+        String orderNo = yyMMddHHmmss + startNum;
+        orderInfo.setOrderNo(orderNo);
+        orderInfo.setUserId(userId);
+        //总金额
+        BigDecimal totalAmount = BigDecimal.ZERO;
+        //优惠金额
+        BigDecimal discountAmount = BigDecimal.ZERO;
+        //实付金额
+        BigDecimal actualAmount = BigDecimal.ZERO;
+        List<OrderItemDto> orderItemDtoList = dto.getOrderItemDtos();
+        List<OrderItem> orderItemList = new ArrayList<>();
+        for (OrderItemDto orderItemDto : orderItemDtoList) {
+            OrderItem orderItem = new OrderItem();
+            orderItem.setId(IdUtil.getSnowflake().nextId());
+            orderItem.setOrderId(orderInfo.getId());
+            System.err.println(orderItem.getOrderId());
+            Product product = productMapper.selectById(orderItemDto.getProductId());
+            if (product.getStock()==0){
+                return ResultVo.error(102,"商品已售罄");
+            }
+            orderItem.setProductId(product.getId());
+            orderItem.setProductName(product.getTitle());
+            orderItem.setPrice(product.getPrice());
+            product.setStock(product.getStock()-orderItemDto.getQuantity());
+            orderItem.setQuantity(orderItemDto.getQuantity());
+            orderItem.setItemAmount(orderItem.getPrice().multiply(new BigDecimal(orderItemDto.getQuantity())));
+            totalAmount = totalAmount.add(orderItem.getItemAmount());
+            QueryWrapper<UserCoupon> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("coupon_id",orderItemDto.getCouponId());
+            UserCoupon userCoupon = userCouponMapper.selectOne(queryWrapper);
+            orderInfo.setUserCouponId(userCoupon.getId());
+            orderItem.setCouponId(userCoupon.getCouponId());
+            orderItem.setDiscountAmount(userCoupon.getAmount());
+            userCoupon.setUseTime(new Date());
+            userCoupon.setStatus(2);
+            discountAmount = discountAmount.add(orderItem.getDiscountAmount());
+            orderItem.setPayAmount(orderItem.getItemAmount().subtract(orderItem.getDiscountAmount()));
+            actualAmount = actualAmount.add(orderItem.getPayAmount());
+            orderItemList.add(orderItem);
+            productMapper.updateById(product);
+            userCouponMapper.updateById(userCoupon);
+        }
+        orderInfo.setTotalAmount(totalAmount);
+        orderInfo.setDiscountAmount(discountAmount);
+        orderInfo.setActualAmount(actualAmount);
+        orderInfo.setPaymentMethod(dto.getPaymentMethod());
+        orderInfoMapper.insert(orderInfo);
+        for (OrderItem orderItem : orderItemList) {
+            orderItemMapper.insert(orderItem);
+        }
+        return ResultVo.success("订单创建成功");
+    }
+
+    @Override
+    public ResultVo orderUp(OrderInfoUpDto dto, String token) {
+        Long userId = TokenUtils.getUserId(token);
+        if (userId==null){
+            return ResultVo.error(101,"请先登录");
+        }
+        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("id",dto.getId());
+        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
+        if (orderInfo==null){
+            return ResultVo.error(102,"订单不存在");
+        }
+        orderInfo.setPaymentTime(new Date());
+        orderInfo.setOrderStatus(dto.getOrderStatus());
+//        orderInfoMapper.updateById(orderInfo);
+        return ResultVo.success("订单修改成功");
+    }
+
+    @Override
+    public ResultVo orderGetList(String token) {
+        Long userId = TokenUtils.getUserId(token);
+        if (userId==null){
+            return ResultVo.error(101,"请先登录");
+        }
+        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("user_id",userId);
+        List<OrderInfo> orderInfoList = orderInfoMapper.selectList(queryWrapper);
+        return ResultVo.success(orderInfoList);
+    }
+    
+    @Override
+    @Transactional
+    public ResultVo orderPay(Long orderId, Integer paymentMethod, String token) {
+        // 验证用户身份
+        Long userId = TokenUtils.getUserId(token);
+        if (userId == null) {
+            return ResultVo.error(101, "请先登录");
+        }
+        
+        // 查询订单信息
+        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
+        if (orderInfo == null) {
+            return ResultVo.error(102, "订单不存在");
+        }
+        
+        // 验证订单归属
+        if (!orderInfo.getUserId().equals(userId)) {
+            return ResultVo.error(103, "无权操作此订单");
+        }
+        
+        // 检查订单状态
+        if (orderInfo.getOrderStatus() != 1) {  // 1是待支付状态
+            return ResultVo.error(104, "订单状态不允许支付");
+        }
+        
+        // 获取支付金额
+        BigDecimal payAmount = orderInfo.getActualAmount();
+        
+        // 根据支付方式调用不同的支付接口
+        boolean payResult = false;
+        
+        try {
+            // 模拟调用支付接口
+            Map<String, Object> payResponse = callPaymentApi(paymentMethod, payAmount, orderInfo.getOrderNo());
+            payResult = (boolean) payResponse.get("success");
+            
+            if (!payResult) {
+                return ResultVo.error(105, "支付失败:" + payResponse.get("message"));
+            }
+            
+            // 更新订单状态
+            orderInfo.setOrderStatus(2);  // 2是已支付状态
+            orderInfo.setPaymentTime(new Date());
+            orderInfo.setPaymentMethod(paymentMethod);
+            orderInfoMapper.updateById(orderInfo);
+            
+            // 可以在这里添加其他业务逻辑,如发送通知、更新库存等
+            
+            return ResultVo.success("支付成功");
+        } catch (Exception e) {
+            // 记录支付异常
+            log.error("订单支付异常: orderId={}, error={}", orderId, e.getMessage(), e);
+            return ResultVo.error(106, "支付处理异常:" + e.getMessage());
+        }
+    }
+    
+    /**
+     * 模拟调用支付API
+     * 
+     * @param paymentMethod 支付方式:1-微信支付 3-银行卡
+     * @param amount 支付金额
+     * @param orderNo 订单编号
+     * @return 支付结果
+     */
+    private Map<String, Object> callPaymentApi(Integer paymentMethod, BigDecimal amount, String orderNo) {
+        // 这里模拟支付过程,实际项目中应该调用真实的支付接口
+        Map<String, Object> result = new HashMap<>();
+        
+        // 模拟成功率95%
+        boolean isSuccess = Math.random() > 0.05;
+        
+        if (isSuccess) {
+            result.put("success", true);
+            result.put("paymentNo", "PAY" + System.currentTimeMillis());
+            result.put("message", "支付成功");
+        } else {
+            result.put("success", false);
+            result.put("message", "支付失败,请重试");
+        }
+        
+        return result;
+    }
+}
+
+
+
+

+ 22 - 0
src/main/java/com/example/demo/order/service/impl/OrderItemServiceImpl.java

@@ -0,0 +1,22 @@
+package com.example.demo.order.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.demo.order.domain.OrderItem;
+import com.example.demo.order.service.OrderItemService;
+import com.example.demo.order.dao.OrderItemMapper;
+import org.springframework.stereotype.Service;
+
+/**
+* @author 徐乐
+* @description 针对表【order_item(订单详情表)】的数据库操作Service实现
+* @createDate 2025-06-17 19:27:10
+*/
+@Service
+public class OrderItemServiceImpl extends ServiceImpl<OrderItemMapper, OrderItem>
+    implements OrderItemService{
+
+}
+
+
+
+

+ 58 - 45
src/main/java/com/example/demo/product/controller/ProductController.java

@@ -1,8 +1,11 @@
 package com.example.demo.product.controller;
 
+import com.example.demo.product.dto.TrainDto;
 import com.example.demo.product.service.impl.*;
 import com.example.demo.user.vo.ResultVo;
+import org.apache.http.HttpResponse;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestHeader;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -21,53 +24,63 @@ public class ProductController {
     @Autowired
     private ProductTrainServiceImpl productTrainService;
 
-    @RequestMapping("/syncDataToEs")
-    public ResultVo syncDataToEs() {
-        return productService.syncDataToEs();
+//    @RequestMapping("/syncDataToEs")
+//    public ResultVo syncDataToEs() {
+//        return productService.syncDataToEs();
+//    }
+//
+//    @RequestMapping("/getProductList")
+//    public ResultVo getProductList(@RequestHeader("token") String token) {
+//        return productService.getProductList(token);
+//    }
+//
+//    @RequestMapping("/flightSyncDataToEs")
+//    public ResultVo FlightSyncDataToEs(){
+//        return productFlightService.flightSyncDataToEs();
+//    }
+//
+//    @RequestMapping("/getFlightList")
+//    public ResultVo getFlightList(@RequestHeader("token") String token) {
+//        return productFlightService.getFlightList(token);
+//    }
+    @RequestMapping("/getFlight")
+    public ResultVo getFlight(@RequestHeader("token") String token,  String endCity, String endDate,String startCity, String startDate){
+        return productFlightService.getFlight(token, endCity, endDate,startCity, startDate);
     }
+//
+//    @RequestMapping("/hotelSyncDataToEs")
+//    public ResultVo hotelSyncDataToEs(){
+//        return productHotelService.hotelSyncDataToEs();
+//    }
+//
+//    @RequestMapping("/getHotelList")
+//    public ResultVo getHotelList(@RequestHeader("token") String token) {
+//        return productHotelService.getHotelList(token);
+//    }
+//
+//    @RequestMapping("/ticketSyncDataToEs")
+//    public ResultVo ticketSyncDataToEs(){
+//        return productTicketService.ticketSyncDataToEs();
+//    }
+//
+//    @RequestMapping("/getTicketList")
+//    public ResultVo getTicketList(@RequestHeader("token") String token) {
+//        return productTicketService.getTicketList(token);
+//    }
 
-    @RequestMapping("/getProductList")
-    public ResultVo getProductList(@RequestHeader("token") String token) {
-        return productService.getProductList(token);
+    //查询火车票
+    @RequestMapping("/getTrain")
+    public ResultVo getTrain(@RequestHeader("token") String token, HttpResponse response, @RequestBody TrainDto dto){
+        return productTrainService.getTrain(token,response,dto);
     }
 
-    @RequestMapping("/flightSyncDataToEs")
-    public ResultVo FlightSyncDataToEs(){
-        return productFlightService.flightSyncDataToEs();
-    }
-
-    @RequestMapping("/getFlightList")
-    public ResultVo getFlightList(@RequestHeader("token") String token) {
-        return productFlightService.getFlightList(token);
-    }
-
-    @RequestMapping("/hotelSyncDataToEs")
-    public ResultVo hotelSyncDataToEs(){
-        return productHotelService.hotelSyncDataToEs();
-    }
-
-    @RequestMapping("/getHotelList")
-    public ResultVo getHotelList(@RequestHeader("token") String token) {
-        return productHotelService.getHotelList(token);
-    }
-
-    @RequestMapping("/ticketSyncDataToEs")
-    public ResultVo ticketSyncDataToEs(){
-        return productTicketService.ticketSyncDataToEs();
-    }
-
-    @RequestMapping("/getTicketList")
-    public ResultVo getTicketList(@RequestHeader("token") String token) {
-        return productTicketService.getTicketList(token);
-    }
-
-    @RequestMapping("/trainSyncDataToEs")
-    public ResultVo trainSyncDataToEs(){
-        return productTrainService.trainSyncDataToEs();
-    }
-
-    @RequestMapping("/getTrainList")
-    public ResultVo getTrainList(@RequestHeader("token") String token) {
-        return productTrainService.getTrainList(token);
-    }
+//    @RequestMapping("/trainSyncDataToEs")
+//    public ResultVo trainSyncDataToEs(){
+//        return productTrainService.trainSyncDataToEs();
+//    }
+//
+//    @RequestMapping("/getTrainList")
+//    public ResultVo getTrainList(@RequestHeader("token") String token) {
+//        return productTrainService.getTrainList(token);
+//    }
 }

+ 12 - 0
src/main/java/com/example/demo/product/dto/TrainDto.java

@@ -0,0 +1,12 @@
+package com.example.demo.product.dto;
+
+import lombok.Data;
+
+@Data
+public class TrainDto {
+    private String start;
+
+    private String end;
+
+    private String date;
+}

+ 4 - 2
src/main/java/com/example/demo/product/service/ProductFlightService.java

@@ -10,7 +10,9 @@ import com.example.demo.user.vo.ResultVo;
 * @createDate 2025-06-10 20:12:01
 */
 public interface ProductFlightService extends IService<ProductFlight> {
-    ResultVo flightSyncDataToEs();
+//    ResultVo flightSyncDataToEs();
+//
+//    ResultVo getFlightList(String token);
 
-    ResultVo getFlightList(String token);
+    ResultVo getFlight(String token, String endCity, String endDate,String startCity, String startDate);
 }

+ 6 - 2
src/main/java/com/example/demo/product/service/ProductTrainService.java

@@ -2,7 +2,9 @@ package com.example.demo.product.service;
 
 import com.example.demo.product.domain.ProductTrain;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.demo.product.dto.TrainDto;
 import com.example.demo.user.vo.ResultVo;
+import org.apache.http.HttpResponse;
 
 /**
 * @author 徐乐
@@ -10,7 +12,9 @@ import com.example.demo.user.vo.ResultVo;
 * @createDate 2025-06-10 20:12:01
 */
 public interface ProductTrainService extends IService<ProductTrain> {
-    ResultVo trainSyncDataToEs();
+//    ResultVo trainSyncDataToEs();
+//
+//    ResultVo getTrainList(String token);
 
-    ResultVo getTrainList(String token);
+    ResultVo getTrain(String token, HttpResponse response, TrainDto dto);
 }

+ 86 - 34
src/main/java/com/example/demo/product/service/impl/ProductFlightServiceImpl.java

@@ -1,20 +1,20 @@
 package com.example.demo.product.service.impl;
 
-import cn.easyes.core.biz.EsPageInfo;
-import cn.easyes.core.conditions.LambdaEsQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.example.demo.common.utils.TokenUtils;
+import com.example.demo.common.utils.HttpUtils;
 import com.example.demo.product.domain.ProductFlight;
-import com.example.demo.product.entity.ProductFlightEntity;
 import com.example.demo.product.esmapper.ProductFlightEsMapper;
 import com.example.demo.product.service.ProductFlightService;
 import com.example.demo.product.dao.ProductFlightMapper;
 import com.example.demo.user.vo.ResultVo;
+import org.apache.http.HttpResponse;
+import org.apache.http.util.EntityUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
 * @author 徐乐
@@ -27,37 +27,89 @@ public class ProductFlightServiceImpl extends ServiceImpl<ProductFlightMapper, P
     @Autowired
     private ProductFlightEsMapper productFlightEsMapper;
 
-    @Override
-    public ResultVo flightSyncDataToEs() {
-        //创建索引
-        productFlightEsMapper.createIndex();
-        List<ProductFlight> flightList = this.list();
-        List<ProductFlightEntity> productFlightEntityList = new ArrayList<>();
-        for (ProductFlight productFlight : flightList) {
-            ProductFlightEntity productFlightEntity = new ProductFlightEntity();
-            productFlightEntity.setId(productFlight.getId());
-            productFlightEntity.setProductId(productFlight.getProductId());
-            productFlightEntity.setFlightNo(productFlight.getFlightNo());
-            productFlightEntity.setDepartureAirport(productFlight.getDepartureAirport());
-            productFlightEntity.setArrivalAirport(productFlight.getArrivalAirport());
-            productFlightEntity.setDepartureTime(productFlight.getDepartureTime());
-            productFlightEntity.setArrivalTime(productFlight.getArrivalTime());
-            productFlightEntity.setSeatType(productFlight.getSeatType());
-            productFlightEntityList.add(productFlightEntity);
-        }
-        productFlightEsMapper.insertBatch(productFlightEntityList);
-        return ResultVo.success("同步数据成功");
-    }
+//    @Override
+//    public ResultVo flightSyncDataToEs() {
+//        //创建索引
+//        productFlightEsMapper.createIndex();
+//        List<ProductFlight> flightList = this.list();
+//        List<ProductFlightEntity> productFlightEntityList = new ArrayList<>();
+//        for (ProductFlight productFlight : flightList) {
+//            ProductFlightEntity productFlightEntity = new ProductFlightEntity();
+//            productFlightEntity.setId(productFlight.getId());
+//            productFlightEntity.setProductId(productFlight.getProductId());
+//            productFlightEntity.setFlightNo(productFlight.getFlightNo());
+//            productFlightEntity.setDepartureAirport(productFlight.getDepartureAirport());
+//            productFlightEntity.setArrivalAirport(productFlight.getArrivalAirport());
+//            productFlightEntity.setDepartureTime(productFlight.getDepartureTime());
+//            productFlightEntity.setArrivalTime(productFlight.getArrivalTime());
+//            productFlightEntity.setSeatType(productFlight.getSeatType());
+//            productFlightEntityList.add(productFlightEntity);
+//        }
+//        productFlightEsMapper.insertBatch(productFlightEntityList);
+//        return ResultVo.success("同步数据成功");
+//    }
+//
+//    @Override
+//    public ResultVo getFlightList(String token) {
+//        Long userId = TokenUtils.getUserId(token);
+//        if (userId==null){
+//            return ResultVo.error(101,"请先登录");
+//        }
+//        LambdaEsQueryWrapper<ProductFlightEntity> wrapper = new LambdaEsQueryWrapper();
+//        EsPageInfo<ProductFlightEntity> pageInfo = productFlightEsMapper.pageQuery(wrapper,1,20);
+//        return ResultVo.success(pageInfo);
+//    }
 
     @Override
-    public ResultVo getFlightList(String token) {
-        Long userId = TokenUtils.getUserId(token);
-        if (userId==null){
-            return ResultVo.error(101,"请先登录");
+    public ResultVo getFlight(String token, String endCity, String endDate,String startCity, String startDate) {
+        //API产品路径
+        String host = "http://plane.market.alicloudapi.com";
+        String path = "/ai_market/ai_airplane/get_airplane_list";
+        String method = "GET";
+        //阿里云APPCODE
+        String appcode = "a1595e6d28984e07ba4f939fa53ccb55";
+        Map<String, String> headers = new HashMap<String, String>();
+        headers.put("Authorization", "APPCODE " + appcode);
+        Map<String, String> querys = new HashMap<String, String>();
+        //参数配置
+        //抵达城市,如:上海
+        querys.put("END_CITY", endCity);
+        //返程日期,如:20190208,若无返回日期,则填写出发日期
+        querys.put("END_DATE", endDate);
+        //出发城市,如:北京
+        querys.put("START_CITY", startCity);
+        //出发日期,如:20190208
+        querys.put("START_DATE", startDate);
+
+        try {
+            /**
+             * 重要提示如下:
+             * HttpUtils请从
+             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
+             * 下载
+             *
+             * 相应的依赖请参照
+             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
+             */
+            HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);
+            int statusCode = response.getStatusLine().getStatusCode();
+
+            // 检查HTTP状态码
+            if (statusCode != 200) {
+                return ResultVo.error("API请求失败,状态码:" + statusCode);
+            }
+
+            // 解析响应体
+            String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+            System.out.println("API原始响应:" + responseBody);
+
+            // 直接返回API的原始JSON数据(或按需解析后返回)
+            return ResultVo.success(responseBody);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResultVo.error("调用航班API时出错:" + e.getMessage());
         }
-        LambdaEsQueryWrapper<ProductFlightEntity> wrapper = new LambdaEsQueryWrapper();
-        EsPageInfo<ProductFlightEntity> pageInfo = productFlightEsMapper.pageQuery(wrapper,1,20);
-        return ResultVo.success(pageInfo);
     }
 }
 

+ 106 - 24
src/main/java/com/example/demo/product/service/impl/ProductTrainServiceImpl.java

@@ -5,16 +5,25 @@ import cn.easyes.core.conditions.LambdaEsQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.example.demo.common.utils.TokenUtils;
 import com.example.demo.product.domain.ProductTrain;
+import com.example.demo.product.dto.TrainDto;
 import com.example.demo.product.entity.ProductTrainEntity;
 import com.example.demo.product.esmapper.ProductTrainEsMapper;
 import com.example.demo.product.service.ProductTrainService;
 import com.example.demo.product.dao.ProductTrainMapper;
 import com.example.demo.user.vo.ResultVo;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
 * @author 徐乐
@@ -27,36 +36,109 @@ public class ProductTrainServiceImpl extends ServiceImpl<ProductTrainMapper, Pro
     @Autowired
     private ProductTrainEsMapper productTrainEsMapper;
 
-    @Override
-    public ResultVo trainSyncDataToEs() {
-        //创建索引
-        productTrainEsMapper.createIndex();
-        List<ProductTrain> trainList = this.list();
-        List<ProductTrainEntity> productTrainEntityList = new ArrayList<>();
-        for (ProductTrain productTrain : trainList) {
-            ProductTrainEntity productTrainEntity = new ProductTrainEntity();
-            productTrainEntity.setId(productTrain.getId());
-            productTrainEntity.setProductId(productTrain.getProductId());
-            productTrainEntity.setTrainNo(productTrain.getTrainNo());
-            productTrainEntity.setDepartureStation(productTrain.getDepartureStation());
-            productTrainEntity.setArrivalStation(productTrain.getArrivalStation());
-            productTrainEntity.setDepartureTime(productTrain.getDepartureTime());
-            productTrainEntity.setArrivalTime(productTrain.getArrivalTime());
-            productTrainEntityList.add(productTrainEntity);
-        }
-        productTrainEsMapper.insertBatch(productTrainEntityList);
-        return ResultVo.success("同步数据成功");
-    }
+//    @Override
+//    public ResultVo trainSyncDataToEs() {
+//        //创建索引
+//        productTrainEsMapper.createIndex();
+//        List<ProductTrain> trainList = this.list();
+//        List<ProductTrainEntity> productTrainEntityList = new ArrayList<>();
+//        for (ProductTrain productTrain : trainList) {
+//            ProductTrainEntity productTrainEntity = new ProductTrainEntity();
+//            productTrainEntity.setId(productTrain.getId());
+//            productTrainEntity.setProductId(productTrain.getProductId());
+//            productTrainEntity.setTrainNo(productTrain.getTrainNo());
+//            productTrainEntity.setDepartureStation(productTrain.getDepartureStation());
+//            productTrainEntity.setArrivalStation(productTrain.getArrivalStation());
+//            productTrainEntity.setDepartureTime(productTrain.getDepartureTime());
+//            productTrainEntity.setArrivalTime(productTrain.getArrivalTime());
+//            productTrainEntityList.add(productTrainEntity);
+//        }
+//        productTrainEsMapper.insertBatch(productTrainEntityList);
+//        return ResultVo.success("同步数据成功");
+//    }
+//
+//    @Override
+//    public ResultVo getTrainList(String token) {
+//        Long userId = TokenUtils.getUserId(token);
+//        if (userId==null){
+//            return ResultVo.error(101,"请先登录");
+//        }
+//        LambdaEsQueryWrapper<ProductTrainEntity> wrapper = new LambdaEsQueryWrapper<>();
+//        EsPageInfo<ProductTrainEntity> pageInfo = productTrainEsMapper.pageQuery(wrapper, 1, 20);
+//        return ResultVo.success(pageInfo);
+//    }
 
     @Override
-    public ResultVo getTrainList(String token) {
+    public ResultVo getTrain(String token, HttpResponse response, TrainDto dto) {
         Long userId = TokenUtils.getUserId(token);
         if (userId==null){
             return ResultVo.error(101,"请先登录");
         }
-        LambdaEsQueryWrapper<ProductTrainEntity> wrapper = new LambdaEsQueryWrapper<>();
-        EsPageInfo<ProductTrainEntity> pageInfo = productTrainEsMapper.pageQuery(wrapper, 1, 20);
-        return ResultVo.success(pageInfo);
+        String host = "https://jisutrain.market.alicloudapi.com";
+        String path = "/train/ticket";
+        String method = "ANY";
+        String appcode = "a1595e6d28984e07ba4f939fa53ccb55";
+        Map<String, String> headers = new HashMap<String, String>();
+        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
+        headers.put("Authorization", "APPCODE " + appcode);
+        //根据API的要求,定义相对应的Content-Type
+        headers.put("Content-Type", "application/json; charset=UTF-8");
+        Map<String, String> querys = new HashMap<String, String>();
+        querys.put("date", dto.getDate());
+        querys.put("end", dto.getEnd());
+        querys.put("start", dto.getStart());
+
+
+        try {
+            /**
+             * 重要提示如下:
+             * HttpUtils请从
+             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
+             * 下载
+             *
+             * 相应的依赖请参照
+             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
+             */
+
+            System.out.println(response.toString());
+            // 构建请求URI
+            URIBuilder uriBuilder = new URIBuilder(host + path);
+            for (Map.Entry<String, String> entry : querys.entrySet()) {
+                uriBuilder.addParameter(entry.getKey(), entry.getValue());
+            }
+
+            // 创建HTTP客户端和请求
+            HttpClient httpClient = HttpClients.createDefault();
+            HttpPost httpPost = new HttpPost(uriBuilder.build());
+
+            // 设置请求头
+            for (Map.Entry<String, String> entry : headers.entrySet()) {
+                httpPost.setHeader(entry.getKey(), entry.getValue());
+            }
+
+            // 执行请求
+            HttpResponse response1 = httpClient.execute(httpPost);
+
+            // 处理响应
+            if (response1.getStatusLine().getStatusCode() == 200) {
+                String responseBody = EntityUtils.toString(response1.getEntity(), "UTF-8");
+                System.out.println("API返回结果:");
+                System.out.println(responseBody);
+                return ResultVo.success(responseBody);
+            } else {
+                System.out.println("请求失败,状态码: " + response1.getStatusLine().getStatusCode());
+                System.out.println(EntityUtils.toString(response1.getEntity(), "UTF-8"));
+                return ResultVo.error(response1.getStatusLine().getStatusCode(),"请求失败");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResultVo.error();
+        }
+//            //获取response的body
+////            System.out.println(EntityUtils.toString(response.getEntity(),"utf-8"));
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
     }
 }
 

+ 9 - 5
src/main/java/com/example/demo/scenic_spot/controller/ScenicSpotController.java

@@ -1,24 +1,28 @@
 package com.example.demo.scenic_spot.controller;
 
+import com.example.demo.scenic_spot.dto.ScenicSpotDto;
 import com.example.demo.scenic_spot.service.impl.ScenicSpotServiceImpl;
 import com.example.demo.user.vo.ResultVo;
+import org.apache.http.HttpResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestHeader;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @RestController
 @RequestMapping("/scenicSpot")
 public class ScenicSpotController {
     @Autowired
     private ScenicSpotServiceImpl scenicSpotService;
+    private static final Logger logger = LoggerFactory.getLogger(ScenicSpotController.class);
 
     @RequestMapping("/syncDataToEs")
     public ResultVo syncDataToEs() {
         return scenicSpotService.syncDataToEs();
     }
     @RequestMapping("/getScenicSpotList")
-    public ResultVo getScenicSpotList(@RequestHeader("token") String token) {
-        return scenicSpotService.getScenicSpotList(token);
+    public ResultVo getScenicSpotList(@RequestHeader("token") String token, HttpResponse response, String keyword) {
+        logger.info("获取景点信息列表");
+        return scenicSpotService.getScenicSpotList(token,response,keyword);
     }
 }

+ 8 - 0
src/main/java/com/example/demo/scenic_spot/dto/ScenicSpotDto.java

@@ -0,0 +1,8 @@
+package com.example.demo.scenic_spot.dto;
+
+import lombok.Data;
+
+@Data
+public class ScenicSpotDto {
+    private String keyword;
+}

+ 3 - 1
src/main/java/com/example/demo/scenic_spot/service/ScenicSpotService.java

@@ -2,7 +2,9 @@ package com.example.demo.scenic_spot.service;
 
 import com.example.demo.scenic_spot.domain.ScenicSpot;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.demo.scenic_spot.dto.ScenicSpotDto;
 import com.example.demo.user.vo.ResultVo;
+import org.apache.http.HttpResponse;
 
 /**
 * @author 徐乐
@@ -13,5 +15,5 @@ public interface ScenicSpotService extends IService<ScenicSpot> {
 
     ResultVo syncDataToEs();
 
-    ResultVo getScenicSpotList(String token);
+    ResultVo getScenicSpotList(String token, HttpResponse response, String keyword);
 }

+ 54 - 4
src/main/java/com/example/demo/scenic_spot/service/impl/ScenicSpotServiceImpl.java

@@ -3,21 +3,30 @@ package com.example.demo.scenic_spot.service.impl;
 import cn.easyes.core.biz.EsPageInfo;
 import cn.easyes.core.conditions.LambdaEsQueryWrapper;
 import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.demo.common.utils.HttpUtils;
 import com.example.demo.common.utils.TokenUtils;
 import com.example.demo.scenic_spot.domain.ScenicSpot;
+import com.example.demo.scenic_spot.dto.ScenicSpotDto;
 import com.example.demo.scenic_spot.entity.ScenicSpotEntity;
 import com.example.demo.scenic_spot.esmapper.ScenicSpotEsMapper;
 import com.example.demo.scenic_spot.service.ScenicSpotService;
 import com.example.demo.scenic_spot.dao.ScenicSpotMapper;
 import com.example.demo.user.vo.ResultVo;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.util.EntityUtils;
 import org.elasticsearch.client.indices.GetIndexResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
 * @author 徐乐
@@ -32,6 +41,7 @@ public class ScenicSpotServiceImpl extends ServiceImpl<ScenicSpotMapper, ScenicS
     private ScenicSpotEsMapper scenicSpotEsMapper;
     @Override
     public ResultVo syncDataToEs() {
+
         //创建索引
         scenicSpotEsMapper.createIndex();
         List<ScenicSpot> scenicSpotList = this.list();
@@ -74,14 +84,54 @@ public class ScenicSpotServiceImpl extends ServiceImpl<ScenicSpotMapper, ScenicS
     }
 
     @Override
-    public ResultVo getScenicSpotList(String token) {
+    public ResultVo getScenicSpotList(String token, HttpResponse response, String keyword) {
         Long userId = TokenUtils.getUserId(token);
         if (userId==null){
             return ResultVo.error(101,"请先登录");
         }
-        LambdaEsQueryWrapper<ScenicSpotEntity> wrapper = new LambdaEsQueryWrapper<>();
-        EsPageInfo<ScenicSpotEntity> pageInfo = scenicSpotEsMapper.pageQuery(wrapper, 1, 20);
-        return ResultVo.success(pageInfo);
+        String host = "https://ali-spot.showapi.com";
+        String path = "/spotList";
+        String method = "GET";
+        String appcode = "a1595e6d28984e07ba4f939fa53ccb55";
+        Map<String, String> headers = new HashMap<String, String>();
+        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
+        headers.put("Authorization", "APPCODE " + appcode);
+        Map<String, String> querys = new HashMap<String, String>();
+        querys.put("keyword", keyword);
+//        querys.put("proId", "proId");
+//        querys.put("cityId", "cityId");
+//        querys.put("areaId", "areaId");
+//        querys.put("page", "page");
+
+
+        try {
+            /**
+             * 重要提示如下:
+             * HttpUtils请从
+             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
+             * 下载
+             *
+             * 相应的依赖请参照
+             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
+             */
+            HttpResponse response1 = HttpUtils.doGet(host, path, method, headers, querys);
+            System.out.println(response1.toString());
+            //获取response的body
+//            System.out.println(EntityUtils.toString(response.getEntity()));
+            // 获取响应体内容,注意处理异常
+            String responseBody = EntityUtils.toString(response1.getEntity(), "UTF-8");
+            // 打印响应体,方便调试查看
+            System.out.println("接口返回数据:" + responseBody);
+
+            // 解析响应体(这里假设返回的是 JSON 格式,根据实际情况调整解析逻辑)
+            // 如果是 JSON 字符串,转成 JSONObject 或者 Java 实体类
+            JSONObject resultJson = JSON.parseObject(responseBody);
+            // 假设你的 ResultVo 的 obj 字段可以接收解析后的 JSON 数据或者 Map 等
+            return ResultVo.success(resultJson);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResultVo.error();
+        }
     }
 }
 

+ 48 - 3
src/main/java/com/example/demo/user/controller/UserController.java

@@ -1,15 +1,18 @@
 package com.example.demo.user.controller;
 
+import com.example.demo.common.utils.RedisClient;
+import com.example.demo.user.dto.CollectDto;
 import com.example.demo.user.dto.LoginDto;
+import com.example.demo.user.dto.PhoneDto;
 import com.example.demo.user.dto.UserDto;
 import com.example.demo.user.service.UserService;
+import com.example.demo.user.service.ValidateCodeService;
+import com.example.demo.user.service.impl.UserFavoriteServiceImpl;
 import com.example.demo.user.service.impl.UserServiceImpl;
 import com.example.demo.user.vo.ResultVo;
 import io.swagger.annotations.Api;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @Api(tags = "用户管理")
 @RestController
@@ -17,6 +20,14 @@ import org.springframework.web.bind.annotation.RestController;
 public class UserController {
     @Autowired
     private UserServiceImpl userService;
+    @Autowired
+    private UserFavoriteServiceImpl userFavoriteService;
+
+    @Autowired
+    private ValidateCodeService validateCodeService;
+
+    @Autowired
+    private RedisClient redisClient;
 
     @RequestMapping("/register")
     public ResultVo register(@RequestBody UserDto dto){
@@ -28,4 +39,38 @@ public class UserController {
         return userService.login(dto);
     }
 
+    @RequestMapping("/collect")
+    public ResultVo collect(@RequestBody CollectDto dto, @RequestHeader("token") String token){
+        return userFavoriteService.collect(dto,token);
+    }
+
+    @RequestMapping("/delCollect")
+    public ResultVo delCollect(Integer targetId, @RequestHeader("token") String token){
+        return userFavoriteService.delCollect(targetId,token);
+    }
+
+    @RequestMapping("/selCollect")
+    public ResultVo selCollect(@RequestHeader("token") String token){
+        return userFavoriteService.selCollect(token);
+    }
+
+    @RequestMapping("/phoneLogin")
+    public ResultVo phoneLogin(@RequestBody PhoneDto dto){
+        return userService.phoneLogin(dto);
+    }
+
+    /**
+     * 生成验证码
+     * @param phone
+     * @return
+     */
+    @RequestMapping("/send4Order")
+    public ResultVo send4Order(@RequestParam("phone") String phone) {
+        Integer code = validateCodeService.send4Order(phone);
+        String key = "CODE:" + phone;
+        redisClient.set(key, code);
+        redisClient.expire(key, 60);
+        System.out.println("您的验证码为:------"+code);
+        return ResultVo.success("验证码发送成功");
+    }
 }

+ 20 - 0
src/main/java/com/example/demo/user/dao/UserFavoriteMapper.java

@@ -0,0 +1,20 @@
+package com.example.demo.user.dao;
+
+import com.example.demo.user.domain.UserFavorite;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @author 徐乐
+* @description 针对表【user_favorite(用户收藏记录表)】的数据库操作Mapper
+* @createDate 2025-06-24 18:47:01
+* @Entity com.example.demo.user.domain.UserFavorite
+*/
+@Mapper
+public interface UserFavoriteMapper extends BaseMapper<UserFavorite> {
+
+}
+
+
+
+

+ 88 - 0
src/main/java/com/example/demo/user/domain/UserFavorite.java

@@ -0,0 +1,88 @@
+package com.example.demo.user.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 用户收藏记录表
+ * @TableName user_favorite
+ */
+@TableName(value ="user_favorite")
+@Data
+public class UserFavorite {
+    /**
+     * 收藏记录ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 收藏目标类型:1-产品 2-攻略 3-目的地
+     */
+    private Integer targetType;
+
+    /**
+     * 收藏目标ID
+     */
+    private Long targetId;
+
+    /**
+     * 收藏时间
+     */
+    private Date createTime;
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        UserFavorite other = (UserFavorite) that;
+        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+            && (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId()))
+            && (this.getTargetType() == null ? other.getTargetType() == null : this.getTargetType().equals(other.getTargetType()))
+            && (this.getTargetId() == null ? other.getTargetId() == null : this.getTargetId().equals(other.getTargetId()))
+            && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+        result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode());
+        result = prime * result + ((getTargetType() == null) ? 0 : getTargetType().hashCode());
+        result = prime * result + ((getTargetId() == null) ? 0 : getTargetId().hashCode());
+        result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", userId=").append(userId);
+        sb.append(", targetType=").append(targetType);
+        sb.append(", targetId=").append(targetId);
+        sb.append(", createTime=").append(createTime);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 9 - 0
src/main/java/com/example/demo/user/dto/CollectDto.java

@@ -0,0 +1,9 @@
+package com.example.demo.user.dto;
+
+import lombok.Data;
+
+@Data
+public class CollectDto {
+    private Integer targetType;
+    private Long targetId;
+}

+ 9 - 0
src/main/java/com/example/demo/user/dto/PhoneDto.java

@@ -0,0 +1,9 @@
+package com.example.demo.user.dto;
+
+import lombok.Data;
+
+@Data
+public class PhoneDto {
+    private String phone;
+    private String code;
+}

+ 2 - 12
src/main/java/com/example/demo/user/dto/UserDto.java

@@ -5,22 +5,12 @@ import lombok.Data;
 @Data
 public class UserDto {
     /**
-     * 登录用户名
-     */
-    private String username;
-
-    /**
-     * 加密后的密码
-     */
-    private String password;
-
-    /**
      * 用户手机号
      */
     private String phone;
 
     /**
-     * 头像地址
+     * 加密后的密码
      */
-    private String avatar;
+    private String password;
 }

+ 20 - 0
src/main/java/com/example/demo/user/service/UserFavoriteService.java

@@ -0,0 +1,20 @@
+package com.example.demo.user.service;
+
+import com.example.demo.user.domain.UserFavorite;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.demo.user.dto.CollectDto;
+import com.example.demo.user.vo.ResultVo;
+
+/**
+* @author 徐乐
+* @description 针对表【user_favorite(用户收藏记录表)】的数据库操作Service
+* @createDate 2025-06-24 18:47:01
+*/
+public interface UserFavoriteService extends IService<UserFavorite> {
+
+    ResultVo collect(CollectDto dto, String token);
+
+    ResultVo delCollect(Integer targetId, String token);
+
+    ResultVo selCollect(String token);
+}

+ 3 - 0
src/main/java/com/example/demo/user/service/UserService.java

@@ -3,6 +3,7 @@ package com.example.demo.user.service;
 import com.example.demo.user.domain.User;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.example.demo.user.dto.LoginDto;
+import com.example.demo.user.dto.PhoneDto;
 import com.example.demo.user.dto.UserDto;
 import com.example.demo.user.vo.ResultVo;
 
@@ -16,4 +17,6 @@ public interface UserService extends IService<User> {
     ResultVo register(UserDto dto);
 
     ResultVo login(LoginDto dto);
+
+    ResultVo phoneLogin(PhoneDto dto);
 }

+ 5 - 0
src/main/java/com/example/demo/user/service/ValidateCodeService.java

@@ -0,0 +1,5 @@
+package com.example.demo.user.service;
+
+public interface ValidateCodeService {
+    Integer send4Order(String phone);
+}

+ 72 - 0
src/main/java/com/example/demo/user/service/impl/UserFavoriteServiceImpl.java

@@ -0,0 +1,72 @@
+package com.example.demo.user.service.impl;
+
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.demo.common.utils.TokenUtils;
+import com.example.demo.user.domain.UserFavorite;
+import com.example.demo.user.dto.CollectDto;
+import com.example.demo.user.service.UserFavoriteService;
+import com.example.demo.user.dao.UserFavoriteMapper;
+import com.example.demo.user.vo.ResultVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+* @author 徐乐
+* @description 针对表【user_favorite(用户收藏记录表)】的数据库操作Service实现
+* @createDate 2025-06-24 18:47:01
+*/
+@Service
+public class UserFavoriteServiceImpl extends ServiceImpl<UserFavoriteMapper, UserFavorite>
+    implements UserFavoriteService{
+    @Autowired
+    private UserFavoriteMapper userFavoriteMapper;
+
+    @Override
+    public ResultVo collect(CollectDto dto, String token) {
+        Long userId = TokenUtils.getUserId(token);
+        if (userId==null){
+            return ResultVo.error(101,"请先登录");
+        }
+        UserFavorite favorite = new UserFavorite();
+        favorite.setId(IdUtil.getSnowflake().nextId());
+        favorite.setUserId(userId);
+        favorite.setTargetType(dto.getTargetType());
+        favorite.setTargetId(dto.getTargetId());
+        favorite.setCreateTime(new Date());
+        userFavoriteMapper.insert(favorite);
+        return ResultVo.success("用户收藏成功");
+    }
+
+    @Override
+    public ResultVo delCollect(Integer targetId, String token) {
+        Long userId = TokenUtils.getUserId(token);
+        if (userId==null){
+            return ResultVo.error(101,"请先登录");
+        }
+        QueryWrapper<UserFavorite> wrapper = new QueryWrapper<>();
+        wrapper.eq("target_id",targetId);
+        userFavoriteMapper.delete(wrapper);
+        return ResultVo.success("用户取消收藏成功");
+    }
+
+    @Override
+    public ResultVo selCollect(String token) {
+        Long userId = TokenUtils.getUserId(token);
+        if (userId==null){
+            return ResultVo.error(101,"请先登录");
+        }
+        QueryWrapper<UserFavorite> wrapper = new QueryWrapper<>();
+        List<UserFavorite> favoriteList = userFavoriteMapper.selectList(wrapper);
+        return ResultVo.success(favoriteList);
+    }
+
+}
+
+
+
+

+ 82 - 4
src/main/java/com/example/demo/user/service/impl/UserServiceImpl.java

@@ -4,9 +4,11 @@ import cn.hutool.core.util.IdUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.example.demo.common.utils.Md5Util;
+import com.example.demo.common.utils.RedisClient;
 import com.example.demo.common.utils.TokenUtils;
 import com.example.demo.user.domain.User;
 import com.example.demo.user.dto.LoginDto;
+import com.example.demo.user.dto.PhoneDto;
 import com.example.demo.user.dto.UserDto;
 import com.example.demo.user.service.UserService;
 import com.example.demo.user.dao.UserMapper;
@@ -18,6 +20,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
@@ -37,6 +41,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
     private RedissonClient redissonClient;
     @Autowired
     private RedisTemplate<String,String> redisTemplate;
+    @Autowired
+    private RedisClient redisClient;
     @Override
     public ResultVo register(UserDto dto) {
         QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
@@ -56,7 +62,6 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
             log.info("注册");
             User u = new User();
             u.setId(IdUtil.getSnowflake().nextId());
-            u.setUsername(dto.getUsername());
             //生成盐值
             String uuid = UUID.randomUUID().toString().replaceAll("-", "");
             u.setSalt(uuid);
@@ -65,9 +70,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
             //加密
             String md5Password = Md5Util.MD5(uuid + password);
             u.setPassword(md5Password);
-            u.setEmail(dto.getUsername()+"@example.com");
             u.setPhone(dto.getPhone());
-            u.setAvatar(dto.getAvatar());
             userMapper.insert(u);
             return ResultVo.success("注册成功");
         } catch (Exception e) {
@@ -81,6 +84,25 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
         }
     }
 
+    /**
+     * 统一获取验证码方法
+     * @param phone 手机号
+     * @return 验证码
+     */
+    private Object getVerificationCode(String phone) {
+        String key = "CODE:" + phone;
+        return redisClient.get(key);
+    }
+
+    /**
+     * 统一删除验证码方法
+     * @param phone 手机号
+     */
+    private void deleteVerificationCode(String phone) {
+        String key = "CODE:" + phone;
+        redisClient.del(key);
+    }
+
     @Override
     public ResultVo login(LoginDto dto) {
         QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
@@ -98,10 +120,66 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
         if (encryptedPassword.equals(user.getPassword())){
             String token = TokenUtils.createJwtToken(user.getId().toString());
             redisTemplate.opsForValue().set("userToken:",token);
-            return ResultVo.success("登录成功");
+            return ResultVo.success(token);
         }
         return ResultVo.error("用户名或密码有误");
     }
+
+    @Override
+    public ResultVo phoneLogin(PhoneDto dto) {
+        // 参数校验
+        if (dto.getPhone() == null ||!dto.getPhone().matches("1[3-9]\\d{9}")) {
+            return ResultVo.error(400, "手机号格式错误");
+        }
+
+        // 获取验证码
+        Integer collect = (Integer) getVerificationCode(dto.getPhone());
+        if (collect == null) {
+//            logger.info("手机号 {} 验证码已过期", dto.getPhone());
+            return ResultVo.error(201, "验证码已过期");
+        }
+
+        // 验证验证码
+        String codeStr = String.valueOf(collect);
+        String userCode = dto.getCode();
+        if (userCode == null ||!userCode.matches("\\d{6}")) {
+//            logger.info("手机号 {} 输入的验证码格式错误", dto.getPhone());
+            return ResultVo.error(201, "验证码格式错误");
+        }
+
+        if (!codeStr.equals(userCode)) {
+//            logger.info("手机号 {} 验证码错误,Redis: {}, 用户输入: {}",
+//                    dto.getPhone(), codeStr, userCode);
+            return ResultVo.error(201, "验证码错误");
+        }
+
+        // 验证通过后删除验证码
+        deleteVerificationCode(dto.getPhone());
+
+
+        // 先判断账号是否存在
+        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(User::getPhone, dto.getPhone());
+        User user = userMapper.selectOne(queryWrapper);
+//        if (user == null) {
+//            user.setUsername("随机账户"+String.valueOf(IdUtil.getSnowflake().nextId()));
+//            user.setId(IdUtil.getSnowflake().nextId());
+//            userMapper.insert(user);
+//            redisClient.set("uid",  user.getId());
+//            redisClient.expire("uid", 60*60);
+//            Long id = user.getId();
+//            String token = AppJwtUtil.getToken(id);
+//            redisClient.set("token",  token);
+//            Map<String, String> map = new HashMap<>();
+//            map.put("token",token);
+//            return ResultVo.success(map);
+//        }
+//        redisClient.set("uid",  user.getId());
+//        redisClient.expire("uid", 60*60);
+        String token = TokenUtils.createJwtToken(user.getId().toString());
+        redisTemplate.opsForValue().set("userToken:",token);
+        return ResultVo.success(token);
+    }
 }
 
 

+ 21 - 0
src/main/java/com/example/demo/user/service/impl/ValidateCodeServiceImpl.java

@@ -0,0 +1,21 @@
+package com.example.demo.user.service.impl;
+
+import com.example.demo.user.service.ValidateCodeService;
+import org.springframework.stereotype.Service;
+
+import java.util.Random;
+
+
+@Service
+public class ValidateCodeServiceImpl implements ValidateCodeService {
+    @Override
+    public Integer send4Order(String phone) {
+        String substring = phone.substring(2, 8);
+        Random random = new Random();
+        int j = random.nextInt(Integer.valueOf(substring));
+        if (j < 1000) {
+            j += 1000;
+        }
+        return j;
+    }
+}

+ 29 - 0
src/main/resources/com/example/demo/coupon/mapper/CouponMapper.xml

@@ -0,0 +1,29 @@
+<?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">
+<mapper namespace="com.example.demo.coupon.dao.CouponMapper">
+
+    <resultMap id="BaseResultMap" type="com.example.demo.coupon.domain.Coupon">
+            <id property="id" column="id" />
+            <result property="couponType" column="coupon_type" />
+            <result property="couponName" column="coupon_name" />
+            <result property="couponDesc" column="coupon_desc" />
+            <result property="amount" column="amount" />
+            <result property="discount" column="discount" />
+            <result property="minAmount" column="min_amount" />
+            <result property="totalCount" column="total_count" />
+            <result property="remainCount" column="remain_count" />
+            <result property="issueStartTime" column="issue_start_time" />
+            <result property="issueEndTime" column="issue_end_time" />
+            <result property="status" column="status" />
+            <result property="createTime" column="create_time" />
+            <result property="updateTime" column="update_time" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,coupon_type,coupon_name,coupon_desc,amount,discount,
+        min_amount,total_count,remain_count,issue_start_time,issue_end_time,
+        status,create_time,update_time
+    </sql>
+</mapper>

+ 25 - 0
src/main/resources/com/example/demo/coupon/mapper/UserCouponMapper.xml

@@ -0,0 +1,25 @@
+<?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">
+<mapper namespace="com.example.demo.coupon.dao.UserCouponMapper">
+
+    <resultMap id="BaseResultMap" type="com.example.demo.coupon.domain.UserCoupon">
+            <id property="id" column="id" />
+            <result property="userId" column="user_id" />
+            <result property="couponId" column="coupon_id" />
+            <result property="couponName" column="coupon_name" />
+            <result property="amount" column="amount" />
+            <result property="obtainTime" column="obtain_time" />
+            <result property="useTime" column="use_time" />
+            <result property="expireTime" column="expire_time" />
+            <result property="status" column="status" />
+            <result property="createTime" column="create_time" />
+            <result property="updateTime" column="update_time" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,user_id,coupon_id,coupon_name,amount,obtain_time,
+        use_time,expire_time,status,create_time,update_time
+    </sql>
+</mapper>

+ 27 - 0
src/main/resources/com/example/demo/order/mapper/OrderInfoMapper.xml

@@ -0,0 +1,27 @@
+<?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">
+<mapper namespace="com.example.demo.order.dao.OrderInfoMapper">
+
+    <resultMap id="BaseResultMap" type="com.example.demo.order.domain.OrderInfo">
+            <id property="id" column="id" />
+            <result property="orderNo" column="order_no" />
+            <result property="userId" column="user_id" />
+            <result property="totalAmount" column="total_amount" />
+            <result property="discountAmount" column="discount_amount" />
+            <result property="actualAmount" column="actual_amount" />
+            <result property="paymentMethod" column="payment_method" />
+            <result property="paymentTime" column="payment_time" />
+            <result property="orderStatus" column="order_status" />
+            <result property="userCouponId" column="user_coupon_id" />
+            <result property="createTime" column="create_time" />
+            <result property="updateTime" column="update_time" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,order_no,user_id,total_amount,discount_amount,actual_amount,
+        payment_method,payment_time,order_status,user_coupon_id,create_time,
+        update_time
+    </sql>
+</mapper>

+ 26 - 0
src/main/resources/com/example/demo/order/mapper/OrderItemMapper.xml

@@ -0,0 +1,26 @@
+<?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">
+<mapper namespace="com.example.demo.order.dao.OrderItemMapper">
+
+    <resultMap id="BaseResultMap" type="com.example.demo.order.domain.OrderItem">
+            <id property="id" column="id" />
+            <result property="orderId" column="order_id" />
+            <result property="productId" column="product_id" />
+            <result property="productName" column="product_name" />
+            <result property="price" column="price" />
+            <result property="quantity" column="quantity" />
+            <result property="itemAmount" column="item_amount" />
+            <result property="couponId" column="coupon_id" />
+            <result property="discountAmount" column="discount_amount" />
+            <result property="payAmount" column="pay_amount" />
+            <result property="createTime" column="create_time" />
+            <result property="updateTime" column="update_time" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,order_id,product_id,product_name,price,quantity,
+        item_amount,coupon_id,discount_amount,pay_amount,create_time,update_time
+    </sql>
+</mapper>

+ 18 - 0
src/main/resources/com/example/demo/user/mapper/UserFavoriteMapper.xml

@@ -0,0 +1,18 @@
+<?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">
+<mapper namespace="com.example.demo.user.dao.UserFavoriteMapper">
+
+    <resultMap id="BaseResultMap" type="com.example.demo.user.domain.UserFavorite">
+            <id property="id" column="id" />
+            <result property="userId" column="user_id" />
+            <result property="targetType" column="target_type" />
+            <result property="targetId" column="target_id" />
+            <result property="createTime" column="create_time" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,user_id,target_type,target_id,create_time
+    </sql>
+</mapper>

+ 119 - 0
src/main/resources/logback-spring.xml

@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<configuration>
+    <!--指定property属性变量-->
+    <property name="log.path" value="/logs/logdemo"/>
+
+    <!-- 日志输出格式
+     %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+     -->
+    <!-- 控制台 appender-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+
+    <!-- 文件 滚动日志 (all)-->
+    <appender name="allLog"  class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 当前日志输出路径、文件名 -->
+        <file>${log.path}/all.log</file>
+        <!--日志输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <!--历史日志归档策略-->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- 历史日志: 归档文件名 -->
+            <fileNamePattern>${log.path}/%d{yyyy-MM, aux}/all.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
+            <!--单个文件的最大大小-->
+            <maxFileSize>64MB</maxFileSize>
+            <!--日志文件保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+
+
+    </appender>
+
+
+    <!-- 文件 滚动日志 (仅error)-->
+    <appender name="errorLog"  class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 当前日志输出路径、文件名 -->
+        <file>${log.path}/error.log</file>
+        <!--日志输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+
+        <!--历史日志归档策略-->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- 历史日志: 归档文件名 -->
+            <fileNamePattern>${log.path}/%d{yyyy-MM, aux}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
+            <!--单个文件的最大大小-->
+            <maxFileSize>64MB</maxFileSize>
+            <!--日志文件保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+
+        <!-- 此日志文档只记录error级别的  level过滤器-->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>error</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+
+
+
+    </appender>
+
+
+    <!-- 文件 异步日志(async) -->
+    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"
+              immediateFlush="false" neverBlock="true">
+        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
+        <discardingThreshold>0</discardingThreshold>
+        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
+        <queueSize>1024</queueSize>
+        <neverBlock>true</neverBlock>
+        <!-- 添加附加的appender,最多只能添加一个 -->
+        <appender-ref ref="allLog" />
+    </appender>
+
+
+
+    <!--输出到logstash的appender-->
+    <appender name="logstash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
+        <!--可以访问的logstash日志收集端口-->
+        <destination>localhost:4560</destination>
+        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
+            <!--自定义字段,区分应用名称-->
+            <customFields>{"appname":"logdemo"}</customFields>
+        </encoder>
+
+    </appender>
+
+
+
+    <!-- root 级别的配置 -->
+    <root level="INFO">
+        <appender-ref ref="CONSOLE" />
+        <!--<appender-ref ref="allLog" />-->
+        <appender-ref  ref="ASYNC"/>
+        <appender-ref ref="errorLog" />
+
+        <appender-ref ref="logstash" />
+    </root>
+
+    <!--可输出mapper层sql语句等-->
+    <logger name="com.example.demo" level="debug">
+    </logger>
+
+    <!--输出jdbc 事务相关信息-->
+    <logger name="org.springframework.jdbc" level="debug">
+    </logger>
+
+</configuration>