X723595506 hai 1 semana
achega
7f3787527f

+ 33 - 0
.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

+ 192 - 0
pom.xml

@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.futu.course</groupId>
+    <artifactId>xkl_sale</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>xkl_sale</name>
+    <description>xkl_sale</description>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+        <mybatisplus.version>3.4.1</mybatisplus.version>
+        <hutool.version>5.7.15</hutool.version>
+        <druid.version>1.1.21</druid.version>
+        <swagger.version>2.8.0</swagger.version>
+        <fastjson.version>1.2.80</fastjson.version>
+        <commons-lang3.version>3.3.2</commons-lang3.version>
+        <commons.io.version>2.11.0</commons.io.version>
+        <jedis.version>3.8.0</jedis.version>
+        <qcloud.cos.version>5.6.69</qcloud.cos.version>
+        <spring-boot-admin.version>2.6.10</spring-boot-admin.version>
+        <mysql.connector.version>8.0.29</mysql.connector.version>
+    </properties>
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>2.5.12</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    <dependencies>
+        <dependency>
+            <groupId>de.codecentric</groupId>
+            <artifactId>spring-boot-admin-starter-client</artifactId>
+            <version>${spring-boot-admin.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>${jedis.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>${mysql.connector.version}</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>${druid.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <!--  腾讯第三方上传  -->
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>cos_api</artifactId>
+            <version>${qcloud.cos.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!--  生成二维码  -->
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+            <version>3.3.3</version>
+        </dependency>
+        <!--  io常用工具类  -->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>${commons.io.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${commons-lang3.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>${fastjson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>2.1.3</version>
+        </dependency>
+        <!--         <dependency> -->
+        <!--             <groupId>org.hibernate.validator</groupId> -->
+        <!--             <artifactId>hibernate-validator</artifactId> -->
+        <!--             <version>6.1.5.Final</version> -->
+        <!--         </dependency> -->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.9</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-httpclient</groupId>
+            <artifactId>commons-httpclient</artifactId>
+            <version>3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>1.64</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>${mybatisplus.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.baomidou</groupId>
+                    <artifactId>mybatis-plus-generator</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 13 - 0
src/main/java/com/futu/course/XklSaleApplication.java

@@ -0,0 +1,13 @@
+package com.futu.course;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class XklSaleApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(XklSaleApplication.class, args);
+    }
+
+}

+ 125 - 0
src/main/java/com/futu/course/common/AppJwtUtil.java

@@ -0,0 +1,125 @@
+package com.futu.course.common;
+
+import io.jsonwebtoken.*;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.*;
+
+public class AppJwtUtil {
+
+    // TOKEN的有效期一天(S)
+    private static final int TOKEN_TIME_OUT = 3_600;
+    // 加密KEY
+    private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";
+    // 最小刷新间隔(S)
+    private static final int REFRESH_TIME = 300;
+
+    // 生产ID
+    public static String getToken(Long id){
+        Map<String, Object> claimMaps = new HashMap<>();
+        claimMaps.put("id",id);
+        long currentTime = System.currentTimeMillis();
+        return Jwts.builder()
+                .setId(UUID.randomUUID().toString())
+                .setIssuedAt(new Date(currentTime))  //签发时间
+                .setSubject("system")  //说明
+                .setIssuer("heima") //签发者信息
+                .setAudience("app")  //接收用户
+                .compressWith(CompressionCodecs.GZIP)  //数据压缩方式
+                .signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式
+                .setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000))  //过期时间戳
+                .addClaims(claimMaps) //cla信息
+                .compact();
+    }
+
+    /**
+     * 获取token中的claims信息
+     *
+     * @param token
+     * @return
+     */
+    private static Jws<Claims> getJws(String token) {
+            return Jwts.parser()
+                    .setSigningKey(generalKey())
+                    .parseClaimsJws(token);
+    }
+
+    /**
+     * 获取payload body信息
+     *
+     * @param token
+     * @return
+     */
+    public static Claims getClaimsBody(String token) {
+        try {
+            return getJws(token).getBody();
+        }catch (ExpiredJwtException e){
+            return null;
+        }
+    }
+
+    /**
+     * 获取hearder body信息
+     *
+     * @param token
+     * @return
+     */
+    public static JwsHeader getHeaderBody(String token) {
+        return getJws(token).getHeader();
+    }
+
+    /**
+     * 是否过期
+     *
+     * @param claims
+     * @return -1:有效,0:有效,1:过期,2:过期
+     */
+    public static int verifyToken(Claims claims) {
+        if(claims==null){
+            return 1;
+        }
+        try {
+            claims.getExpiration()
+                    .before(new Date());
+            // 需要自动刷新TOKEN
+            if((claims.getExpiration().getTime()-System.currentTimeMillis())>REFRESH_TIME*1000){
+                return -1;
+            }else {
+                return 0;
+            }
+        } catch (ExpiredJwtException ex) {
+            return 1;
+        }catch (Exception e){
+            return 2;
+        }
+    }
+
+    /**
+     * 由字符串生成加密key
+     *
+     * @return
+     */
+    public static SecretKey generalKey() {
+        byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());
+        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
+        return key;
+    }
+
+    public static void main(String[] args) {
+       /* Map map = new HashMap();
+        map.put("id","11");*/
+        System.out.println(AppJwtUtil.getToken(1102L));
+        Jws<Claims> jws = AppJwtUtil.getJws("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAC2L0QqDMAwA_yXPFkw6a-LfxDawDoRCK2yM_bsR9nbHcV94jQobRGHKO-UwG1F4mEkQ1hJy4ZjKWjRyggmqDtgwIQuvssgE_dz97p8-7Lh7765Pq4e66VnctDVne7f_KbjcZ_WGONPvAsM25luDAAAA._HLSpxHpSl4KZbYtSx1xnyeaRpsJTQ5xz6wMfFehqUr5etW6pOhCuP4EdrhSBefJZ5evmfYcUAj_dbHkLVdxSQ");
+        Claims claims = jws.getBody();
+        int i = AppJwtUtil.verifyToken(claims);
+        System.out.println(i);
+        System.out.println(claims.get("id"));
+        /*Date date = new Date(20000000000000L);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        String format = sdf.format(date);
+        System.out.println(format);*/
+
+    }
+
+}

+ 374 - 0
src/main/java/com/futu/course/common/DateUtils.java

@@ -0,0 +1,374 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.futu.course.common;
+
+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;
+	}
+	public static Date getDateAfterDays(Date d,int days){
+		long t=d.getTime()+days*24*60*60*1000L;
+		Date afterTime=new Date(t);
+		return afterTime;
+	}
+	/**
+	 * 指定时间之后多少天的时间
+	 * @param days
+	 * @return
+	 */
+	public static long getAfterDays(Date d,int days){
+		long t=d.getTime()+days*24*60*60*1000L;
+		return t;
+	}
+
+	public static long diffDate(Date nowTime,Date extTime){
+	long time=	nowTime.getTime()-extTime.getTime();
+	return time;
+	}
+
+	/**
+	 * 之前多少天的时间
+	 * @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;
+	}
+	public static Date getBeforeDaysDate(Date d,int days){
+		long t=d.getTime()-days*24*60*60*1000L;
+		Date beforeDays=new Date(t);
+		return beforeDays;
+	}
+	/**
+	 *
+	 * @param d
+	 * @param days
+	 * @return
+	 */
+	public static long getSpecificAfterDays(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));
+	}
+}

+ 50 - 0
src/main/java/com/futu/course/common/MD5Utils.java

@@ -0,0 +1,50 @@
+package com.futu.course.common;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class MD5Utils {
+
+    /**
+     * MD5加密
+     * @param str
+     * @return
+     */
+    public final static String encode(String str) {
+        try {
+            //创建具有指定算法名称的摘要
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            //使用指定的字节数组更新摘要
+            md.update(str.getBytes());
+            //进行哈希计算并返回一个字节数组
+            byte mdBytes[] = md.digest();
+            String hash = "";
+            //循环字节数组
+            for (int i = 0; i < mdBytes.length; i++) {
+                int temp;
+                //如果有小于0的字节,则转换为正数
+                if (mdBytes[i] < 0)
+                    temp = 256 + mdBytes[i];
+                else
+                    temp = mdBytes[i];
+                if (temp < 16)
+                    hash += "0";
+                //将字节转换为16进制后,转换为字符串
+                hash += Integer.toString(temp, 16);
+            }
+            return hash;
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+    public static String encodeWithSalt(String numStr, String salt) {
+        return encode(encode(numStr) + salt);
+    }
+
+    public static void main(String[] args) {
+        System.out.println(encode("test"));//e10adc3949ba59abbe56e057f20f883e
+        System.out.println(encodeWithSalt("123456","123456"));//5f1d7a84db00d2fce00b31a7fc73224f
+    }
+}

+ 1075 - 0
src/main/java/com/futu/course/common/RedisUtil.java

@@ -0,0 +1,1075 @@
+package com.futu.course.common;
+
+import com.futu.common.utils.CacheKey;
+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 javax.annotation.Resource;
+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============
+
+}

+ 111 - 0
src/main/java/com/futu/course/common/TokenUtils.java

@@ -0,0 +1,111 @@
+package com.futu.course.common;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.bind.DatatypeConverter;
+import java.security.Key;
+import java.util.Date;
+
+/**
+ * 生成Token工具类
+ */
+public class TokenUtils {
+
+    /**
+     * 签名秘钥
+     */
+    public static final String SECRET = "cjyfutu1688";
+
+    /**
+     * 生成token
+     * @param id 一般传入userName
+     * @return
+     */
+    public static String createJwtToken(String id){
+        String issuer = "www.futureading.com";
+        String subject = "65532781@qq.com";
+        long ttlMillis = System.currentTimeMillis();
+        return createJwtToken(id, issuer, subject, ttlMillis);
+    }
+
+    /**
+     * 生成Token
+     *
+     * @param id
+     *            编号
+     * @param issuer
+     *            该JWT的签发者,是否使用是可选的
+     * @param subject
+     *            该JWT所面向的用户,是否使用是可选的;
+     * @param ttlMillis
+     *            签发时间
+     * @return token String
+     */
+    public static String createJwtToken(String id, String issuer, String subject, long ttlMillis) {
+
+        // 签名算法 ,将对token进行签名
+        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
+
+        // 生成签发时间
+        long nowMillis = System.currentTimeMillis();
+        Date now = new Date(nowMillis);
+
+        // 通过秘钥签名JWT
+        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SECRET);
+        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
+
+        // Let's set the JWT Claims
+        JwtBuilder builder = Jwts.builder().setId(id)
+                .setIssuedAt(now)
+                .setSubject(subject)
+                .setIssuer(issuer)
+                .signWith(signatureAlgorithm, signingKey);
+
+        // if it has been specified, let's add the expiration
+        if (ttlMillis >= 0) {
+            long expMillis = nowMillis + ttlMillis;
+            Date exp = new Date(expMillis);
+            builder.setExpiration(exp);
+        }
+
+        // Builds the JWT and serializes it to a compact, URL-safe string
+        return builder.compact();
+
+    }
+
+    // Sample method to validate and read the JWT
+    public static Claims parseJWT(String jwt) {
+        // This line will throw an exception if it is not a signed JWS (as expected)
+        Claims claims = Jwts.parser()
+                .setSigningKey(DatatypeConverter.parseBase64Binary(SECRET))
+                .parseClaimsJws(jwt).getBody();
+        return claims;
+    }
+
+    public static Long getUserId(String token){
+        Claims claims = null;
+        try {
+            claims = TokenUtils.parseJWT(token);
+        } catch (Exception e) {
+//            throw new RRException("token错误,请重新登录",101);
+        }
+
+        if(null==claims) {
+//            throw new RRException("token错误,请重新登录",101);
+        }
+        String id = claims.getId();
+        Long userId=Long.valueOf(id);
+
+        return userId;
+
+
+    }
+
+    public static void main(String[] args) {
+        System.out.println(TokenUtils.createJwtToken("admin"));
+    }
+}

+ 20 - 0
src/main/resources/application.yml

@@ -0,0 +1,20 @@
+server:
+  port: 8080
+
+spring:
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://localhost:3306/day0509?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
+    username: root
+    password: root
+  redis:
+    host: 127.0.0.1
+    port: 6379
+    database: 0
+    password:
+mybatis-plus:
+  type-aliases-package: cn.zhentao.pojo
+  configuration:
+    map-underscore-to-camel-case: true
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+  mapper-locations: classpath:mapper/*.xml

+ 20 - 0
src/main/resources/mapper/CouponMapper.xml

@@ -0,0 +1,20 @@
+<?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.futu.course.dao.CouponMapper">
+
+    <resultMap id="BaseResultMap" type="com.futu.course.domain.Coupon">
+            <id property="couponId" column="coupon_id" jdbcType="INTEGER"/>
+            <result property="couponName" column="coupon_name" jdbcType="VARCHAR"/>
+            <result property="couponPrice" column="coupon_price" jdbcType="DECIMAL"/>
+            <result property="couponType" column="coupon_type" jdbcType="TINYINT"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        coupon_id,coupon_name,coupon_price,
+        coupon_type,create_time,update_time
+    </sql>
+</mapper>

+ 24 - 0
src/main/resources/mapper/OrderInfoMapper.xml

@@ -0,0 +1,24 @@
+<?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.futu.course.dao.OrderInfoMapper">
+
+    <resultMap id="BaseResultMap" type="com.futu.course.domain.OrderInfo">
+            <id property="orderInfoId" column="order_info_id" jdbcType="BIGINT"/>
+            <result property="userId" column="user_id" jdbcType="BIGINT"/>
+            <result property="couponId" column="coupon_id" jdbcType="BIGINT"/>
+            <result property="totalAmount" column="total_amount" jdbcType="DECIMAL"/>
+            <result property="payAmount" column="pay_amount" jdbcType="DECIMAL"/>
+            <result property="couponAmount" column="coupon_amount" jdbcType="VARCHAR"/>
+            <result property="status" column="status" jdbcType="VARCHAR"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        order_info_id,user_id,coupon_id,
+        total_amount,pay_amount,coupon_amount,
+        status,create_time,update_time
+    </sql>
+</mapper>

+ 24 - 0
src/main/resources/mapper/OrderItemMapper.xml

@@ -0,0 +1,24 @@
+<?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.futu.course.dao.OrderItemMapper">
+
+    <resultMap id="BaseResultMap" type="com.futu.course.domain.OrderItem">
+            <id property="orderItemId" column="order_item_id" jdbcType="BIGINT"/>
+            <result property="orderInfoId" column="order_info_id" jdbcType="BIGINT"/>
+            <result property="userId" column="user_id" jdbcType="BIGINT"/>
+            <result property="skuCount" column="sku_count" jdbcType="BIGINT"/>
+            <result property="skuPrice" column="sku_price" jdbcType="DECIMAL"/>
+            <result property="totalPrice" column="total_price" jdbcType="DECIMAL"/>
+            <result property="status" column="status" jdbcType="TINYINT"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        order_item_id,order_info_id,user_id,
+        sku_count,sku_price,total_price,
+        status,create_time,update_time
+    </sql>
+</mapper>

+ 20 - 0
src/main/resources/mapper/SkuMapper.xml

@@ -0,0 +1,20 @@
+<?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.futu.course.dao.SkuMapper">
+
+    <resultMap id="BaseResultMap" type="com.futu.course.domain.Sku">
+            <id property="skuId" column="sku_id" jdbcType="BIGINT"/>
+            <result property="skuName" column="sku_name" jdbcType="VARCHAR"/>
+            <result property="skuPrice" column="sku_price" jdbcType="DECIMAL"/>
+            <result property="skuCount" column="sku_count" jdbcType="INTEGER"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        sku_id,sku_name,sku_price,
+        sku_count,create_time,update_time
+    </sql>
+</mapper>

+ 20 - 0
src/main/resources/mapper/UserCouponMapper.xml

@@ -0,0 +1,20 @@
+<?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.futu.course.dao.UserCouponMapper">
+
+    <resultMap id="BaseResultMap" type="com.futu.course.domain.UserCoupon">
+            <id property="userCouponId" column="user_coupon_id" jdbcType="BIGINT"/>
+            <result property="userId" column="user_id" jdbcType="BIGINT"/>
+            <result property="couponType" column="coupon_type" jdbcType="VARCHAR"/>
+            <result property="couponPrice" column="coupon_price" jdbcType="DECIMAL"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        user_coupon_id,user_id,coupon_type,
+        coupon_price,create_time,update_time
+    </sql>
+</mapper>

+ 23 - 0
src/main/resources/mapper/UserLoginMapper.xml

@@ -0,0 +1,23 @@
+<?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.futu.course.dao.UserLoginMapper">
+
+    <resultMap id="BaseResultMap" type="com.futu.course.domain.UserLogin">
+            <id property="id" column="id" jdbcType="BIGINT"/>
+            <result property="openid" column="openid" jdbcType="BIGINT"/>
+            <result property="unionid" column="unionid" jdbcType="BIGINT"/>
+            <result property="nickname" column="nickname" jdbcType="VARCHAR"/>
+            <result property="phone" column="phone" jdbcType="VARCHAR"/>
+            <result property="password" column="password" jdbcType="VARCHAR"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,openid,unionid,
+        nickname,phone,password,
+        create_time,update_time
+    </sql>
+</mapper>

+ 13 - 0
src/test/java/com/futu/course/XklSaleApplicationTests.java

@@ -0,0 +1,13 @@
+package com.futu.course;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class XklSaleApplicationTests {
+
+    @Test
+    void contextLoads() {
+    }
+
+}