h преди 2 седмици
ревизия
dbd6f188bd

+ 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/

+ 122 - 0
pom.xml

@@ -0,0 +1,122 @@
+<?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.zhentao</groupId>
+    <artifactId>XiaoETong9</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>XiaoETong9</name>
+    <description>XiaoETong9</description>
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <spring-boot.version>2.6.13</spring-boot.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>com.sun.xml.bind</groupId>
+            <artifactId>jaxb-impl</artifactId>
+            <version>2.2.3-1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.80</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.5.4</version>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.7.15</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tomcat.embed</groupId>
+            <artifactId>tomcat-embed-core</artifactId>
+            <version>9.0.102</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-extension</artifactId>
+            <version>3.4.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-redis</artifactId>
+            <version>2.7.18</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>2.0.38</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2</artifactId>
+            <version>2.0.53</version>
+        </dependency>
+    </dependencies>
+    <dependencyManagement>
+        <dependencies>
+            <!--Spring Boot-->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>2.3.2.RELEASE</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid</artifactId>
+                <version>1.2.23</version>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version> <!-- 使用最新稳定版本 -->
+                <configuration>
+                    <source>8</source> <!-- 你想要的Java版本,例如Java 11 -->
+                    <target>8</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 13 - 0
src/main/java/com/zhentao/XiaoETong9Application.java

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

+ 11 - 0
src/main/java/com/zhentao/common/annotation/NonLoginRequired.java

@@ -0,0 +1,11 @@
+package com.zhentao.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface NonLoginRequired {
+}

+ 230 - 0
src/main/java/com/zhentao/common/constant/BestConstants.java

@@ -0,0 +1,230 @@
+package com.zhentao.common.constant;
+
+/**
+ * @className: BestConstants
+ * @Description:
+ * @author: zhangxiong
+ * @date: 2022/4/23/0023 20:58
+ */
+public class BestConstants {
+    public static final Integer BASE_SHOW = 1;
+    public static final Integer BASE_FALSE = 0;
+    public static final int MAX_QUERY_SIZE = 10;
+    public static final int MIN_QUERY_CURRENT = 1;
+    public static final String OVER_QUERY_SIZE = "超出最大查询长度";
+    //销售规格
+    public static final Integer ITEM_TYPE_SPECIFICATIONS = 1;
+    //基础属性
+    public static final Integer ITEM_TYPE_PROPERTIES = 2;
+
+    public static final String BTB_MINI_CAROUSEL = "btb_mini_carousel";
+    public static final String BTB_MINI_ADVERTS = "btb_mini_adverts";
+    public static final String BTB_MINI_NAVIGATION = "btb_mini_navigation";
+    public static final String BTB_TEAMBUY = "btb_teambuy";
+    public static final String BTB_CONFIG_FOOTER = "btb_config_footer";
+    public static final String BTB_MINI_CONFIG = "btb_mini_config";
+
+    public static final String GOODS_NOT_FOUND = "商品已下架!";
+    public static final String TB_GOODS_NOT_FOUND = "团购商品不存在!";
+    public static final String CART_ITEM_ERROR_MSG = "购物车不存在!";
+    public static final String ORDER_NOT_FOUND = "订单不存在!";
+    public static final String NUM_ERROR_MSG = "数量异常!";
+    public static final String TYPE_ERROR_MSG = "类型异常!";
+    public static final String FILE_UPLOAD_ERROR = "文件上传异常!";
+    public static final String DATA_NOT_FOUND_MSG = "数据未找到!";
+    public static final String CURRENT_ADDRESS_CANT = "当前区域无法购买!";
+    //立即购买
+    public static final Integer PACKAGE_TYPE_NOW = 1;
+    //购物车购买
+    public static final Integer PACKAGE_TYPE_CART = 2;
+    public static final String PACKAGE_TYPE_ERROR = "状态异常!";
+    //删除购物车
+    public static final Integer REMOVE_CART = 1;
+    //删除购物车明细
+    public static final Integer REMOVE_CART_ITEM = 2;
+    //编辑购物车数量
+    public static final Integer MODIFY_CART_ITEM = 3;
+    //正常购买
+    public static final Integer TYPE_NORMAL_BUY = 1;
+    //团购类型
+    public static final Integer TYPE_BUY_TEAM = 2;
+    //狐狸金抵用
+    public static final Integer TYPE_FOX_DEDUCT = 1;
+    //自定义返回码
+    public static final Integer OTHER_RESULT_CODE = 2;
+    public static final String COUPON_OVER_MSG = "优惠券已过期!";
+    public static final String COUPON_NOT_FOUND_MSG = "优惠券不存在!";
+    public static final String COUPON_USED_ERROR_MSG = "优惠券已被使用!";
+    public static final String COUPON_TEBUY_ERROR_MSG = "优惠券专场不匹配!";
+    public static final String COUPON_GOOD_ERROR_MSG = "优惠券商品不匹配!";
+    public static final String COUPON_LIMIT_ERROR_MSG = "优惠券满减未达标!";
+    public static final String COUPON_USED_MONEY_ERROR_MSG = "优惠券抵用金额异常!";
+    public static final Integer FOX_RECEIVE_TYPE_USER = 6;
+    //狐狸金企业扫码
+    public static final Integer FOX_RECEIVE_TYPE_ENTERPRISE = 7;
+    //所有商品
+    public static final Integer COUPON_TYPE_ALL = 0;
+    //指定商品
+    public static final Integer COUPON_TYPE_GOOD = 1;
+    //指定分类
+    public static final Integer COUPON_TYPE_CATE = 2;
+    //指定专场
+    public static final Integer COUPON_TYPE_TEBUY = 3;
+
+    //指定标签
+    public static final Integer COUPON_TYPE_TAG=4;
+    //限制消费金额
+    public static final Integer COUPON_LIMIT_TRUE = 1;
+    public static final Integer ORDER_TYPE_ALL = 0;
+    public static final Integer ORDER_TYPE_PAY = 1;
+    //待发货
+    public static final Integer ORDER_TYPE_DELIVERY = 2;
+    //待收货
+    public static final Integer ORDER_TYPE_RECEIPT = 3;
+    //退款
+    public static final Integer ORDER_TYPE_REFUND = 4;
+    //售后
+    public static final Integer ORDER_TYPE_AFTER_SALES = 5;
+    //取消订单
+    public static final Integer ORDER_TYPE_CANCEL = 6;
+    //订单完成
+    public static final Integer ORDER_TYPE_FINISH = 7;
+
+    public static final Integer ORDER_HAS_PAY = 1;
+    //订单有退款
+    public static final Integer ORDER_NOT_REFUND = 0;
+    public static final Integer ORDER_HAS_REFUND = 1;
+    public static final String ORDER_CANCEL_ERROR_MSG = "取消订单失败!";
+    public static final String ORDER_STOCK_CANCEL_ERROR_MSG = "取消订单失败!!";
+    public static final Integer TYPE_PROVINCE = 1;
+    public static final Integer TYPE_CITY = 2;
+    public static final Integer TYPE_AREA = 3;
+    public static final Integer TYPE_STREET = 4;
+    public static final int DEFAULT_QR_CODE_SIZE = 176;
+    public static final String GOODS_CATE_IMG = "goods_cate_img";
+    public static final String GOODS_DETAIL_LOGO = "goods_detail_logo";
+    public static final String MINI_PATH_KEY = "mini_path";
+    //内购会跳转链接
+    public static final String INSIDE_PATH_KEY = "inside_path";
+
+    public static final String TOKEN_IS_NULL = "token is null";
+    //配置表内剔除提现手续费的比例
+    public static final String SERVICE_CHARGE = "service_charge";
+    //推荐分佣比例
+    public static final String RECOMMEND_C = "recommend_c";
+    public static final String TB_PROCESS_BEGIN = "tb_process_begin";
+    public static final String TB_PROCESS_END = "tb_process_end";
+    public static final Integer TB_PROCESS_BEGIN_VAL = 1;
+    public static final Integer TB_PROCESS_OTHER_VAL = 2;
+    public static final Integer TB_PROCESS_END_VAL = 3;
+    public static final String WEIXIN_ENTERPRISE_DEFAULT_IMG = "default_weixin_img";
+    public static final String WEIXIN_ENTERPRISE_DEFAULT_NAME = "default_weixin_name";
+    public static final String WEIXIN_ENTERPRISE_DEFAULT_URL = "default_weixin_url";
+    public static final String WEIXIN_ENTERPRISE_DEFAULT_PIC = "default_weixin_pic";
+
+    //运费加价按数量加
+    public static final Integer EXPENSES_TYPE_COUNT = 1;
+    //超级推手业务员分享
+    public static final Integer SHARE_BY_PUSHER = 1;
+    //惟客优品超级推手业务员分享
+    public static final Integer SHARE_BY_BEST_PUSHER = 2;
+    //惟客优品普通用户分享
+    public static final Integer SHARE_BY_BEST = 2;
+    //惟客优品短链接分享进入
+    public static final Integer SHARE_BY_SHORT_LINK = 2;
+    //微信返回错误码为0为正常
+    public static final Integer WX_MINI_CODE_NO_ERROR = 0;
+    //分享商品时间
+    public static final String SHARE_CONFIG_KEY = "share";
+    //今日主推
+    public static final String TODAY_FEATURED_KEY = "1";
+    public static final Integer TEAMBUY_TODAY_FEATURED = 1;
+    //品牌专场
+    public static final String BRAND_SPECIAL_KEY = "2";
+    public static final Integer TEAMBUY_BRAND_SPECIAL = 2;
+    //内购会
+    public static final Integer TEAMBUY_INSIDER = 3;
+    //日常购买,带商品分类
+    public static final String DAILY_BUY_KEY = "3";
+    //供应商分组
+    public static final String CONFIG_SUPPLIER_GROUP = "supplier_group";
+    //团购类型内购会
+    public static final Integer TEBUY_TYPE_INSIDE = 3;
+    //购物金已被使用
+    public static final Integer INSIDE_SHOPPING_USED = 2;
+    //优惠券领用限制
+    public static final String CONFIG_COUPON_LIMIT = "coupon_limit";
+    public static final Integer COUPON_SEND_AUTO_TYPE = 3;
+    //按天领取优惠卷
+    public static final Integer COUPON_VALID_FLAG_DAY_TYPE = 0;
+    //扫企业卡
+    public static final Integer SCAN_CARD_TYPE_ENTER = 1;
+    //短链接邀请
+    public static final Integer SCAN_CARD_TYPE_INVITE = 2;
+    public static final String USER_NOT_FOUND = "用户不存在!";
+    public static final String PARAMS_ERROR_MSG = "参数异常!";
+    public static final String LOTTERY_NOT_FOUND = "此抽奖活动不存在!";
+    public static final String LOTTERY_NOT_CHANCE = "没有抽奖次数!";
+    public static final String LOTTERY_DREW_SUCCESS ="抽奖成功!";
+    public static final String LOTTERY_DREW_FAILED="抽奖失败!";
+    public static final String LOTTERY_DREW_ERROR="点击太快,请重新尝试!";
+    public static final String LOTTERY_CHANCE_SUCCESS ="成功获得抽奖次数!";
+    public static final String LOTTERY_CHANCE_FAILED ="获得抽奖次数失败!";
+    public static final String LOTTERY_CHANCE_REPEAT ="无法重复获得次数!";
+    public static final String BASE_NOT_LOGIN = "账号未登录!";
+    //企业发放狐狸金
+    public static final Integer FOX_RECEIVE_ENTERPRISE = 1;
+    //个人转发狐狸金
+    public static final Integer FOX_RECEIVE_USER = 2;
+    //主卡
+    public static final Integer CARD_TYPE_MASTER = 1;
+    //副卡
+    public static final Integer CARD_TYPE_SLAVE =2;
+    //副卡在会员中心看到的卡片
+    public static final Integer CARD_TYPE_SLAVE_SHOW =3;
+    public static final Integer CARD_VIP_HALF_MONTH =1;
+    public static final Integer CARD_VIP_ONE_YEAR =2;
+    public static final Integer CARD_VIP_TWO_YEARS =3;
+    //扫会员卡
+    public static final Integer CARD_SCAN_VIP = 1;
+    //扫企业卡
+    public static final Integer CARD_SCAN_ENTERPRISE = 2;
+    //已领取
+    public static final Integer CARD_STATUS_HAS = 2;
+    //待领取
+    public static final Integer CARD_STATUS_CAN = 1;
+    //不能领
+    public static final Integer CARD_STATUS_CANT = 0;
+
+    public static final Long SAN_XIANG_BANK_ID = 443611075020201984L;
+    public static final Integer USER_NOT_PHONE_CODE = 110;
+    public static final String USER_NOT_PHONE_MSG = "请先绑定手机号!";
+
+    //企业价
+    public static final Integer priceTypeEnterAdd=1;
+    //普通京东价
+    public static final Integer priceTypeNormalAdd=2;
+    //活动优惠券
+    public static final String activeCoupon="activeCoupon";
+    //删除标识
+    public static final Integer delFlag=1;
+    //过期
+    public static final Integer invalidLosed=1;
+    //结算版本
+    public static final Integer setNewVersion3=3;
+    //第一结算版
+    public static final Integer setVersion1=0;
+
+    //默认过期时间
+    public static final Integer defaultExpDate=7;
+    //会员过期key
+    public static final String memberDownGrade="member_down_grade";
+    //过期扣狐豆数
+    public static final String memberDownGradeDeductFoxBean="member_down_fox_bean";
+
+    public static final String expTimeException="过期时间异常";
+    public static final Integer newUserLimitBuy=9;
+    public static final String payFullMoneyGive="pay_full_money_give";
+    public static final String isNewUser="is_new_user";
+
+}

+ 20 - 0
src/main/java/com/zhentao/common/entity/IErrorCode.java

@@ -0,0 +1,20 @@
+package com.zhentao.common.entity;
+
+/**
+ * @className: IErrorCode
+ * @Description:
+ * @author: zhangxiong
+ * @date: 2022/4/24/0024 15:43
+ */
+public interface IErrorCode {
+
+    /**
+     * 错误编码 -1、失败 0、成功
+     */
+    long getCode();
+
+    /**
+     * 错误描述
+     */
+    String getMsg();
+}

+ 94 - 0
src/main/java/com/zhentao/common/entity/R.java

@@ -0,0 +1,94 @@
+package com.zhentao.common.entity;
+
+import com.baomidou.mybatisplus.extension.api.IErrorCode;
+import com.baomidou.mybatisplus.extension.enums.ApiErrorCode;
+
+import com.zhentao.common.exception.ApiException;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Optional;
+
+/**
+ * @className: R
+ * @Description:
+ * @author: zhangxiong
+ * @date: 2022/4/23/0023 20:52
+ */
+@Data
+public class R<T> implements Serializable {
+
+    /**
+     * serialVersionUID
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 业务错误码
+     */
+    private long code;
+    /**
+     * 结果集
+     */
+    private T data;
+    /**
+     * 描述
+     */
+    private String msg;
+
+    public R() {
+        // to do nothing
+    }
+
+    public R(IErrorCode errorCode) {
+        errorCode = Optional.ofNullable(errorCode).orElse(ApiErrorCode.FAILED);
+        this.code = errorCode.getCode();
+        this.msg = errorCode.getMsg();
+    }
+
+    public static <T> R<T> ok(T data) {
+        ApiErrorCode aec = ApiErrorCode.SUCCESS;
+        if (data instanceof Boolean && Boolean.FALSE.equals(data)) {
+            aec = ApiErrorCode.FAILED;
+        }
+        return restResult(data, aec);
+    }
+
+    public static <T> R<T> failed(String msg) {
+        return restResult(null, ApiErrorCode.FAILED.getCode(), msg);
+    }
+
+    public static <T> R<T> failed(int code,String msg) {
+        return restResult(null, code, msg);
+    }
+
+    public static <T> R<T> failed(IErrorCode errorCode) {
+        return restResult(null, errorCode);
+    }
+
+    public static <T> R<T> restResult(T data, IErrorCode errorCode) {
+        return restResult(data, errorCode.getCode(), errorCode.getMsg());
+    }
+
+    public static <T> R<T> restResult(T data, long code, String msg) {
+        R<T> apiResult = new R<>();
+        apiResult.setCode(code);
+        apiResult.setData(data);
+        apiResult.setMsg(msg);
+        return apiResult;
+    }
+
+    public boolean ok() {
+        return ApiErrorCode.SUCCESS.getCode() == code;
+    }
+
+    /**
+     * 服务间调用非业务正常,异常直接释放
+     */
+    public T serviceData() {
+        if (!ok()) {
+            throw new ApiException(this.msg);
+        }
+        return data;
+    }
+}

+ 29 - 0
src/main/java/com/zhentao/common/exception/ApiException.java

@@ -0,0 +1,29 @@
+package com.zhentao.common.exception;
+
+
+import com.zhentao.common.entity.IErrorCode;
+
+public class ApiException extends RuntimeException{
+    private static final long serialVersionUID = -5885155226898287919L;
+    private IErrorCode errorCode;
+    public ApiException(IErrorCode errorCode) {
+        super(errorCode.getMsg());
+        this.errorCode = errorCode;
+    }
+
+    public ApiException(String message) {
+        super(message);
+    }
+
+    public ApiException(Throwable cause) {
+        super(cause);
+    }
+
+    public ApiException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public IErrorCode getErrorCode() {
+        return errorCode;
+    }
+}

+ 101 - 0
src/main/java/com/zhentao/common/exception/GlobalExceptionHandler.java

@@ -0,0 +1,101 @@
+package com.zhentao.common.exception;
+
+
+import com.zhentao.common.constant.BestConstants;
+import com.zhentao.common.entity.R;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.BadSqlGrammarException;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import java.sql.SQLException;
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+
+    /**
+     * 拦截未知的运行时异常
+     */
+    @ExceptionHandler(RuntimeException.class)
+    public R handleRuntimeException(RuntimeException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',发生未知异常.", requestURI, e);
+        return R.failed(e.getMessage() == null ? "发生未知错误,请联系管理员!" : e.getMessage());
+    }
+
+    /**
+     * 处理自定义异常
+     */
+    @ExceptionHandler(RRException.class)
+    public R handleRRException(RRException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+//        log.error("请求地址'{}',发生系统异常.", requestURI, e);
+
+        log.info("自定义异常");
+        return R.failed(e.getCode(), e.getMsg());
+    }
+
+    /**
+     * 系统异常
+     */
+    @ExceptionHandler(Exception.class)
+    public R handleException(Exception e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',发生系统异常.", requestURI, e);
+        return R.failed("系统错误,请联系管理员!");
+    }
+
+    /**
+     * 系统异常
+     */
+    @ExceptionHandler(BadSqlGrammarException.class)
+    public R handleBadSQLException(BadSqlGrammarException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',发生系统异常.", requestURI, e);
+        return R.failed("系统错误,请联系管理员!");
+    }
+
+    /**
+     * 系统异常
+     */
+    @ExceptionHandler(SQLException.class)
+    public R handleSQLException(SQLException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',发生系统异常.", requestURI, e);
+        return R.failed("系统错误,请联系管理员!");
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(BindException.class)
+    public R handleBindException(BindException e) {
+//        log.error(e.getMessage(), e);
+        String message = e.getAllErrors().get(0).getDefaultMessage();
+        return R.failed(message);
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(UnBindPhoneException.class)
+    public R handleUnBindPhoneException(UnBindPhoneException e) {
+//        log.error(e.getMessage(), e);
+        return R.failed(BestConstants.USER_NOT_PHONE_CODE,BestConstants.USER_NOT_PHONE_MSG);
+    }
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
+//        log.error(e.getMessage(), e);
+        log.info("自定义验证异常");
+        String message = e.getBindingResult().getFieldError().getDefaultMessage();
+        return R.failed(message);
+    }
+}

+ 37 - 0
src/main/java/com/zhentao/common/exception/RRException.java

@@ -0,0 +1,37 @@
+package com.zhentao.common.exception;
+
+public class RRException extends RuntimeException{
+    private static final long serialVersionUID = 1L;
+    private String msg;
+    private int code = 500;
+    public RRException(String msg){
+        super(msg);
+        this.msg = msg;
+    }
+    public RRException(String msg, Throwable e){
+        super(msg, e);
+        this.msg = msg;
+    }
+    public RRException(String msg, int code){
+        super(msg);
+        this.msg = msg;
+        this.code = code;
+    }
+    public RRException(String msg, int code, Throwable e){
+        super(msg, e);
+        this.msg = msg;
+        this.code = code;
+    }
+    public String getMsg(){
+        return msg;
+    }
+    public void setMsg(String msg){
+        this.msg = msg;
+    }
+    public int getCode(){
+        return code;
+    }
+    public void setCode(int code){
+        this.code = code;
+    }
+}

+ 19 - 0
src/main/java/com/zhentao/common/exception/UnBindPhoneException.java

@@ -0,0 +1,19 @@
+package com.zhentao.common.exception;
+
+public class UnBindPhoneException extends RRException{
+    public UnBindPhoneException(String msg) {
+        super(msg);
+    }
+
+    public UnBindPhoneException(String msg, Throwable e) {
+        super(msg, e);
+    }
+
+    public UnBindPhoneException(String msg, int code) {
+        super(msg, code);
+    }
+
+    public UnBindPhoneException(String msg, int code, Throwable e) {
+        super(msg, code, e);
+    }
+}

+ 113 - 0
src/main/java/com/zhentao/common/intercepter/AuthIntercepter.java

@@ -0,0 +1,113 @@
+package com.zhentao.common.intercepter;
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.zhentao.common.annotation.NonLoginRequired;
+import com.zhentao.common.exception.RRException;
+import com.zhentao.utils.RedisUtil;
+import com.zhentao.utils.TokenUtils;
+import com.zhentao.vo.UserLoginVo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+
+
+@Component
+@Slf4j
+public class AuthIntercepter implements HandlerInterceptor {
+
+    @Autowired
+    protected RedisTemplate redisTemplate;
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+    public final static String ACCESSTOKEN = "token";
+
+    public AuthIntercepter() {
+
+    }
+
+    public AuthIntercepter(RedisTemplate redisTemplate) {
+        this.redisTemplate = redisTemplate;
+    }
+
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
+            throws Exception {
+        //System.out.println("preHandle");
+//        String deviceId = request.getHeader("deviceId");
+        String token = request.getHeader(ACCESSTOKEN);
+//        String time = request.getHeader("time");
+        log.info(request.getRequestURI());
+        //log.info("deviceId={},token={},time={}",deviceId,token,time);
+        try {
+
+            if (!(handler instanceof HandlerMethod)) {
+                return true;
+            }
+
+            HandlerMethod handlerMethod = (HandlerMethod) handler;
+
+            Method method = handlerMethod.getMethod();
+
+            NonLoginRequired loginRequired = method.getAnnotation(NonLoginRequired.class);
+            //有@LoginRequired注解,需要认证
+            if (loginRequired != null) {
+
+                return true;
+            }
+
+            log.info("---interceptertoken");
+            log.info(token);
+//            if (StringUtils.isEmpty(deviceId)) {
+//
+//                //response.getWriter().print("");
+//                log.info("*********************》deviceId错误");
+//                throw new RRException("deviceId错误", 102);
+//                //return false;
+//            }
+            if (StringUtils.isEmpty(token)) {
+                log.info("*********************》token为空");
+                throw new RRException("token错误,请重新登录", 101);
+            }
+//            if (StringUtils.isEmpty(time)) {
+//                throw new RRException("时间错误", 103);
+//            }
+
+            log.info("调用token**********************》");
+            log.info(token);
+            log.info("************************************》");
+            Long userId = TokenUtils.getUserId(token);
+            log.info("userId={}",userId);
+            Object obj = redisTemplate.opsForValue().get(Long.toString(userId));
+            if (obj == null) {
+                log.info("************************用户token不存在");
+                throw new RRException("token过期", 101);
+            }
+            UserLoginVo userLoginVo = JSONObject.parseObject(JSON.toJSONString(obj), UserLoginVo.class);
+            if (!token.equals(userLoginVo.getToken())) {
+                log.info("**************************>token错误");
+                throw new RRException("token错误", 101);
+            }
+
+
+        } catch (RRException e) {
+            log.info("调用了异常通知" + e.getMessage());
+
+            throw e;
+        }
+
+        return true;
+    }
+
+
+}

+ 152 - 0
src/main/java/com/zhentao/utils/CacheKey.java

@@ -0,0 +1,152 @@
+package com.zhentao.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;
+	}
+}

+ 1075 - 0
src/main/java/com/zhentao/utils/RedisUtil.java

@@ -0,0 +1,1075 @@
+package com.zhentao.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============
+
+}

+ 111 - 0
src/main/java/com/zhentao/utils/TokenUtils.java

@@ -0,0 +1,111 @@
+package com.zhentao.utils;
+
+import com.zhentao.common.exception.RRException;
+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"));
+    }
+}

+ 104 - 0
src/main/java/com/zhentao/vo/UserLoginVo.java

@@ -0,0 +1,104 @@
+
+package com.zhentao.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 用户登录
+ * 
+ * @author stevenlaw
+ * @version 1.0 2021-05-25
+ */
+
+@Data
+@Accessors(chain = true)
+public class UserLoginVo implements Serializable {
+
+    private String token;
+    @JsonSerialize(using= ToStringSerializer.class)
+    private Long userId;
+
+    private String openId;
+
+    private String unionId;
+
+    private String sessionPwd;
+    /**
+     * 推手ID
+     */
+    private String spUserId;
+    /**
+     * 推手绑定到期日
+     */
+    private String spExpTime;
+    /**
+     * 用户名称
+     */
+    private String userName;
+    /**
+     * 用户昵称
+     */
+    private String nickName;
+    /**
+     * 个性签名
+     */
+    private String userIntro;
+    /**
+     * 头像图片
+     */
+    private String avatar;
+    /**
+     * 手机号
+     */
+    private String phone;
+    /**
+     * 用户状态
+     */
+    private Integer userStatus;
+    /**
+     * 累计消费金额
+     */
+    private BigDecimal totalCostAmt;
+    /**
+     * 最后登录时间
+     */
+    private Date lastLoginTime;
+    /**
+     * 乐观锁
+     */
+    private String revision;
+//    /**
+//     * 创建人
+//     */
+//    private String createdBy;
+//    /**
+//     * 创建时间
+//     */
+//    private Date createdTime;
+//    /**
+//     * 更新人
+//     */
+//    private String updatedBy;
+//    /**
+//     * 更新时间
+//     */
+//    private Date updatedTime;
+
+     //private List<BtmAddressEntity> addressList;
+    private String birthDay;
+    @TableField(exist = false)
+    private Integer isNewUser=0;
+
+   // private BtbMiniAdverts href;
+
+
+}

+ 13 - 0
src/test/java/com/zhentao/XiaoETong9ApplicationTests.java

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