新增 user 模块
调整新的项目结构,将 service 和 dao 模块,从 application 拆除,独立成 service-impl 模块 增加 sdk 模块,用于提供一个封装过的功能。例如说,认证和授权~pull/1/head
							parent
							
								
									2523f8b616
								
							
						
					
					
						commit
						4ae211dbc2
					
				| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
				
			||||||
 | 
					         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
				
			||||||
 | 
					    <parent>
 | 
				
			||||||
 | 
					        <artifactId>common</artifactId>
 | 
				
			||||||
 | 
					        <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					        <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					    </parent>
 | 
				
			||||||
 | 
					    <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <artifactId>common-framework</artifactId>
 | 
				
			||||||
 | 
					    <dependencies>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.springframework</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spring-web</artifactId>
 | 
				
			||||||
 | 
					            <version>5.1.5.RELEASE</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.springframework</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spring-web</artifactId>
 | 
				
			||||||
 | 
					            <version>5.1.5.RELEASE</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.springframework</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spring-webmvc</artifactId>
 | 
				
			||||||
 | 
					            <version>5.1.5.RELEASE</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>javax.servlet</groupId>
 | 
				
			||||||
 | 
					            <artifactId>servlet-api</artifactId>
 | 
				
			||||||
 | 
					            <version>2.5</version>
 | 
				
			||||||
 | 
					            <scope>provided</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.slf4j</groupId>
 | 
				
			||||||
 | 
					            <artifactId>slf4j-api</artifactId>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </dependencies>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					package cn.iocoder.common.framework.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.exception.ServiceException;
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.vo.RestResult;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.MissingServletRequestParameterException;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.ControllerAdvice;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.ExceptionHandler;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.ResponseBody;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletRequest;
 | 
				
			||||||
 | 
					import java.lang.reflect.InvocationTargetException;
 | 
				
			||||||
 | 
					import java.lang.reflect.UndeclaredThrowableException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@ControllerAdvice
 | 
				
			||||||
 | 
					public class GlobalExceptionHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @ResponseBody
 | 
				
			||||||
 | 
					    @ExceptionHandler(value = ServiceException.class)
 | 
				
			||||||
 | 
					    public RestResult serviceExceptionHandler(HttpServletRequest req, ServiceException ex) {
 | 
				
			||||||
 | 
					        return RestResult.error(ex.getCode(), ex.getMessage());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 处理 Spring 动态代理调用时,发生 UndeclaredThrowableException 的情况。
 | 
				
			||||||
 | 
					    // 不了解的胖友,可以看看 https://segmentfault.com/a/1190000012262244 文章
 | 
				
			||||||
 | 
					    @ResponseBody
 | 
				
			||||||
 | 
					    @ExceptionHandler(value = UndeclaredThrowableException.class)
 | 
				
			||||||
 | 
					    public RestResult undeclaredThrowableExceptionHandler(HttpServletRequest req, UndeclaredThrowableException e) {
 | 
				
			||||||
 | 
					        // 尝试获得 ServiceException 异常。如果是,则使用 serviceExceptionHandler 方法处理。
 | 
				
			||||||
 | 
					        Throwable undeclaredThrowable = e.getUndeclaredThrowable();
 | 
				
			||||||
 | 
					        if (undeclaredThrowable instanceof InvocationTargetException) {
 | 
				
			||||||
 | 
					            InvocationTargetException invocationTargetException = (InvocationTargetException) undeclaredThrowable;
 | 
				
			||||||
 | 
					            Throwable targetException = invocationTargetException.getTargetException();
 | 
				
			||||||
 | 
					            if (targetException != null & targetException instanceof ServiceException) {
 | 
				
			||||||
 | 
					                return serviceExceptionHandler(req, (ServiceException) targetException);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 获得不到,使用 异常日志 方法处理。
 | 
				
			||||||
 | 
					        return resultExceptionHandler(req, e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @ResponseBody
 | 
				
			||||||
 | 
					    @ExceptionHandler(value = Exception.class)
 | 
				
			||||||
 | 
					    public RestResult resultExceptionHandler(HttpServletRequest req, Exception e) {
 | 
				
			||||||
 | 
					        // TODO 异常日志
 | 
				
			||||||
 | 
					        e.printStackTrace();
 | 
				
			||||||
 | 
					        // TODO 翻译不同的异常
 | 
				
			||||||
 | 
					        if (e instanceof MissingServletRequestParameterException) {
 | 
				
			||||||
 | 
					            return RestResult.error(SysErrorCodeEnum.MISSING_REQUEST_PARAM_ERROR.getCode(), SysErrorCodeEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 返回
 | 
				
			||||||
 | 
					        return RestResult.error(SysErrorCodeEnum.SYS_ERROR.getCode(), SysErrorCodeEnum.SYS_ERROR.getMessage());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,14 @@
 | 
				
			||||||
package cn.iocoder.mall.product.config;
 | 
					package cn.iocoder.common.framework.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cn.iocoder.mall.product.vo.RestResult;
 | 
					import cn.iocoder.common.framework.vo.RestResult;
 | 
				
			||||||
import org.springframework.core.MethodParameter;
 | 
					import org.springframework.core.MethodParameter;
 | 
				
			||||||
import org.springframework.http.MediaType;
 | 
					import org.springframework.http.MediaType;
 | 
				
			||||||
import org.springframework.http.server.ServerHttpRequest;
 | 
					import org.springframework.http.server.ServerHttpRequest;
 | 
				
			||||||
import org.springframework.http.server.ServerHttpResponse;
 | 
					import org.springframework.http.server.ServerHttpResponse;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.ControllerAdvice;
 | 
				
			||||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
 | 
					import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//@ControllerAdvice
 | 
					@ControllerAdvice
 | 
				
			||||||
public class GlobalResponseBodyAdvice implements ResponseBodyAdvice {
 | 
					public class GlobalResponseBodyAdvice implements ResponseBodyAdvice {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
package cn.iocoder.mall.product.constants;
 | 
					package cn.iocoder.common.framework.constant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 错误码枚举类
 | 
					 * 错误码枚举类
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * 系统级异常,使用 2-001-000-000 段
 | 
					 * 系统级异常,使用 2-001-000-000 段
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public enum ErrorCodeEnum {
 | 
					public enum SysErrorCodeEnum {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SYS_ERROR(2001001000, "服务端发生异常"),
 | 
					    SYS_ERROR(2001001000, "服务端发生异常"),
 | 
				
			||||||
    MISSING_REQUEST_PARAM_ERROR(2001001001, "参数缺失"),
 | 
					    MISSING_REQUEST_PARAM_ERROR(2001001001, "参数缺失"),
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ public enum ErrorCodeEnum {
 | 
				
			||||||
    private final int code;
 | 
					    private final int code;
 | 
				
			||||||
    private final String message;
 | 
					    private final String message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ErrorCodeEnum(int code, String message) {
 | 
					    SysErrorCodeEnum(int code, String message) {
 | 
				
			||||||
        this.code = code;
 | 
					        this.code = code;
 | 
				
			||||||
        this.message = message;
 | 
					        this.message = message;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
package cn.iocoder.mall.product.exception;
 | 
					package cn.iocoder.common.framework.exception;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 服务异常
 | 
					 * 服务异常
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,99 @@
 | 
				
			||||||
 | 
					package cn.iocoder.common.framework.util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.exception.ServiceException;
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.concurrent.ConcurrentHashMap;
 | 
				
			||||||
 | 
					import java.util.concurrent.ConcurrentMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * {@link ServiceException} 工具类
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 目的在于,格式化异常信息提示。
 | 
				
			||||||
 | 
					 * 考虑到 String.format 在参数不正确时会报错,因此使用 {} 作为占位符,并使用 {@link #doFormat(int, String, Object...)} 方法来格式化
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 因为 {@link #messages} 里面默认是没有异常信息提示的模板的,所以需要使用方自己初始化进去。目前想到的有几种方式:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 1. 异常提示信息,写在枚举类中,例如说,cn.iocoder.oceans.user.api.constants.ErrorCodeEnum 类 + ServiceExceptionConfiguration
 | 
				
			||||||
 | 
					 * 2. 异常提示信息,写在 .properties 等等配置文件
 | 
				
			||||||
 | 
					 * 3. 异常提示信息,写在 Apollo 等等配置中心中,从而实现可动态刷新
 | 
				
			||||||
 | 
					 * 4. 异常提示信息,存储在 db 等等数据库中,从而实现可动态刷新
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ServiceExceptionUtil {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceExceptionUtil.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 错误码提示模板
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static ConcurrentMap<Integer, String> messages = new ConcurrentHashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void putAll(Map<Integer, String> messages) {
 | 
				
			||||||
 | 
					        ServiceExceptionUtil.messages.putAll(messages);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void put(Integer code, String message) {
 | 
				
			||||||
 | 
					        ServiceExceptionUtil.messages.put(code, message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建指定编号的 ServiceException 的异常
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param code 编号
 | 
				
			||||||
 | 
					     * @return 异常
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static ServiceException exception(Integer code) {
 | 
				
			||||||
 | 
					        return new ServiceException(code, messages.get(code));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建指定编号的 ServiceException 的异常
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param code 编号
 | 
				
			||||||
 | 
					     * @param params 消息提示的占位符对应的参数
 | 
				
			||||||
 | 
					     * @return 异常
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static ServiceException exception(Integer code, Object... params) {
 | 
				
			||||||
 | 
					        String message = doFormat(code, messages.get(code), params);
 | 
				
			||||||
 | 
					        return new ServiceException(code, message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将错误编号对应的消息使用 params 进行格式化。
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param code           错误编号
 | 
				
			||||||
 | 
					     * @param messagePattern 消息模版
 | 
				
			||||||
 | 
					     * @param params         参数
 | 
				
			||||||
 | 
					     * @return 格式化后的提示
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static String doFormat(int code, String messagePattern, Object... params) {
 | 
				
			||||||
 | 
					        StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
 | 
				
			||||||
 | 
					        int i = 0;
 | 
				
			||||||
 | 
					        int j;
 | 
				
			||||||
 | 
					        int l;
 | 
				
			||||||
 | 
					        for (l = 0; l < params.length; l++) {
 | 
				
			||||||
 | 
					            j = messagePattern.indexOf("{}", i);
 | 
				
			||||||
 | 
					            if (j == -1) {
 | 
				
			||||||
 | 
					                LOGGER.error("[doFormat][参数过多:错误码({})|错误内容({})|参数({})", code, messagePattern, params);
 | 
				
			||||||
 | 
					                if (i == 0) {
 | 
				
			||||||
 | 
					                    return messagePattern;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    sbuf.append(messagePattern.substring(i, messagePattern.length()));
 | 
				
			||||||
 | 
					                    return sbuf.toString();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                sbuf.append(messagePattern.substring(i, j));
 | 
				
			||||||
 | 
					                sbuf.append(params[l]);
 | 
				
			||||||
 | 
					                i = j + 2;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (messagePattern.indexOf("{}", i) != -1) {
 | 
				
			||||||
 | 
					            LOGGER.error("[doFormat][参数过少:错误码({})|错误内容({})|参数({})", code, messagePattern, params);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        sbuf.append(messagePattern.substring(i, messagePattern.length()));
 | 
				
			||||||
 | 
					        return sbuf.toString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
package cn.iocoder.mall.product.vo;
 | 
					package cn.iocoder.common.framework.vo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class RestResult {
 | 
					public class RestResult {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
				
			||||||
 | 
					         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
				
			||||||
 | 
					    <parent>
 | 
				
			||||||
 | 
					        <artifactId>mall-parent</artifactId>
 | 
				
			||||||
 | 
					        <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					        <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					    </parent>
 | 
				
			||||||
 | 
					    <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <artifactId>common</artifactId>
 | 
				
			||||||
 | 
					    <packaging>pom</packaging>
 | 
				
			||||||
 | 
					    <modules>
 | 
				
			||||||
 | 
					        <module>common-framework</module>
 | 
				
			||||||
 | 
					    </modules>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										2
									
								
								pom.xml
								
								
								
								
							
							
						
						
									
										2
									
								
								pom.xml
								
								
								
								
							| 
						 | 
					@ -16,6 +16,8 @@
 | 
				
			||||||
    <modules>
 | 
					    <modules>
 | 
				
			||||||
        <module>product</module>
 | 
					        <module>product</module>
 | 
				
			||||||
        <module>order</module>
 | 
					        <module>order</module>
 | 
				
			||||||
 | 
					        <module>user</module>
 | 
				
			||||||
 | 
					        <module>common</module>
 | 
				
			||||||
    </modules>
 | 
					    </modules>
 | 
				
			||||||
    <packaging>pom</packaging>
 | 
					    <packaging>pom</packaging>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,11 @@
 | 
				
			||||||
            <artifactId>product-service-api</artifactId>
 | 
					            <artifactId>product-service-api</artifactId>
 | 
				
			||||||
            <version>1.0-SNAPSHOT</version>
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>common-framework</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <dependency>
 | 
					        <dependency>
 | 
				
			||||||
            <groupId>org.springframework.boot</groupId>
 | 
					            <groupId>org.springframework.boot</groupId>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,36 +0,0 @@
 | 
				
			||||||
package cn.iocoder.mall.product.config;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import cn.iocoder.mall.product.constants.ErrorCodeEnum;
 | 
					 | 
				
			||||||
import cn.iocoder.mall.product.exception.ServiceException;
 | 
					 | 
				
			||||||
import cn.iocoder.mall.product.vo.RestResult;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.MissingServletRequestParameterException;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.ResponseBody;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.servlet.http.HttpServletRequest;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ControllerAdvice
 | 
					 | 
				
			||||||
public class GlobalExceptionHandler {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ResponseBody
 | 
					 | 
				
			||||||
    @ExceptionHandler(value = ServiceException.class)
 | 
					 | 
				
			||||||
    public RestResult serviceExceptionHandler(HttpServletRequest req, Exception e) {
 | 
					 | 
				
			||||||
        ServiceException ex = (ServiceException) e;
 | 
					 | 
				
			||||||
        return RestResult.error(ex.getCode(), ex.getMessage());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ResponseBody
 | 
					 | 
				
			||||||
    @ExceptionHandler(value = Exception.class)
 | 
					 | 
				
			||||||
    public RestResult resultExceptionHandler(HttpServletRequest req, Exception e) {
 | 
					 | 
				
			||||||
        // TODO 异常日志
 | 
					 | 
				
			||||||
        e.printStackTrace();
 | 
					 | 
				
			||||||
        // TODO 翻译不同的异常
 | 
					 | 
				
			||||||
        if (e instanceof MissingServletRequestParameterException) {
 | 
					 | 
				
			||||||
            return RestResult.error(ErrorCodeEnum.MISSING_REQUEST_PARAM_ERROR.getCode(), ErrorCodeEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // 返回
 | 
					 | 
				
			||||||
        return RestResult.error(ErrorCodeEnum.SYS_ERROR.getCode(), ErrorCodeEnum.SYS_ERROR.getMessage());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,16 @@
 | 
				
			||||||
package cn.iocoder.mall.product.config;
 | 
					package cn.iocoder.mall.product.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.config.GlobalExceptionHandler;
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.config.GlobalResponseBodyAdvice;
 | 
				
			||||||
import org.springframework.context.annotation.Configuration;
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Import;
 | 
				
			||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 | 
					import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 | 
				
			||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 | 
					import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 | 
				
			||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 | 
					import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@EnableWebMvc
 | 
					@EnableWebMvc
 | 
				
			||||||
@Configuration
 | 
					@Configuration
 | 
				
			||||||
 | 
					@Import(value = {GlobalResponseBodyAdvice.class, GlobalExceptionHandler.class}) // 统一全局返回
 | 
				
			||||||
public class MVCConfiguration implements WebMvcConfigurer {
 | 
					public class MVCConfiguration implements WebMvcConfigurer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//    @Autowired
 | 
					//    @Autowired
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ spring:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# server
 | 
					# server
 | 
				
			||||||
server:
 | 
					server:
 | 
				
			||||||
  port: 8081
 | 
					  port: 8080
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# mybatis
 | 
					# mybatis
 | 
				
			||||||
mybatis:
 | 
					mybatis:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
				
			||||||
 | 
					         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
				
			||||||
 | 
					    <parent>
 | 
				
			||||||
 | 
					        <artifactId>mall-parent</artifactId>
 | 
				
			||||||
 | 
					        <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					        <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					    </parent>
 | 
				
			||||||
 | 
					    <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <artifactId>user</artifactId>
 | 
				
			||||||
 | 
					    <packaging>pom</packaging>
 | 
				
			||||||
 | 
					    <modules>
 | 
				
			||||||
 | 
					        <module>user-application</module>
 | 
				
			||||||
 | 
					        <module>user-service-api</module>
 | 
				
			||||||
 | 
					        <module>user-sdk</module>
 | 
				
			||||||
 | 
					        <module>user-service-impl</module>
 | 
				
			||||||
 | 
					    </modules>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,119 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
				
			||||||
 | 
					         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
				
			||||||
 | 
					    <parent>
 | 
				
			||||||
 | 
					        <artifactId>user</artifactId>
 | 
				
			||||||
 | 
					        <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					        <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					    </parent>
 | 
				
			||||||
 | 
					    <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <artifactId>user-application</artifactId>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <properties>
 | 
				
			||||||
 | 
					        <org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
 | 
				
			||||||
 | 
					    </properties>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <dependencies>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>user-service-api</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>user-service-impl</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>common-framework</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.springframework.boot</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spring-boot-starter-web</artifactId>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.springframework.boot</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spring-boot-starter-test</artifactId>
 | 
				
			||||||
 | 
					            <scope>test</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>com.alibaba</groupId>
 | 
				
			||||||
 | 
					            <artifactId>dubbo</artifactId>
 | 
				
			||||||
 | 
					            <version>2.6.5</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>com.alibaba.boot</groupId>
 | 
				
			||||||
 | 
					            <artifactId>dubbo-spring-boot-starter</artifactId>
 | 
				
			||||||
 | 
					            <version>0.2.1.RELEASE</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.apache.curator</groupId>
 | 
				
			||||||
 | 
					            <artifactId>curator-framework</artifactId>
 | 
				
			||||||
 | 
					            <version>2.12.0</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.mapstruct</groupId>
 | 
				
			||||||
 | 
					            <artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
 | 
				
			||||||
 | 
					            <version>${org.mapstruct.version}</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>io.springfox</groupId>
 | 
				
			||||||
 | 
					            <artifactId>springfox-swagger2</artifactId>
 | 
				
			||||||
 | 
					            <version>2.9.2</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>io.springfox</groupId>
 | 
				
			||||||
 | 
					            <artifactId>springfox-swagger-ui</artifactId>
 | 
				
			||||||
 | 
					            <version>2.9.2</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>user-service-api</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>user-sdk</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </dependencies>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <build>
 | 
				
			||||||
 | 
					        <plugins>
 | 
				
			||||||
 | 
					            <!-- 提供给 mapstruct 使用 -->
 | 
				
			||||||
 | 
					            <plugin>
 | 
				
			||||||
 | 
					                <groupId>org.apache.maven.plugins</groupId>
 | 
				
			||||||
 | 
					                <artifactId>maven-compiler-plugin</artifactId>
 | 
				
			||||||
 | 
					                <version>3.5.1</version>
 | 
				
			||||||
 | 
					                <configuration>
 | 
				
			||||||
 | 
					                    <source>1.8</source> <!-- or higher, depending on your project -->
 | 
				
			||||||
 | 
					                    <target>1.8</target> <!-- or higher, depending on your project -->
 | 
				
			||||||
 | 
					                    <annotationProcessorPaths>
 | 
				
			||||||
 | 
					                        <path>
 | 
				
			||||||
 | 
					                            <groupId>org.mapstruct</groupId>
 | 
				
			||||||
 | 
					                            <artifactId>mapstruct-processor</artifactId>
 | 
				
			||||||
 | 
					                            <version>${org.mapstruct.version}</version>
 | 
				
			||||||
 | 
					                        </path>
 | 
				
			||||||
 | 
					                    </annotationProcessorPaths>
 | 
				
			||||||
 | 
					                </configuration>
 | 
				
			||||||
 | 
					            </plugin>
 | 
				
			||||||
 | 
					        </plugins>
 | 
				
			||||||
 | 
					    </build>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.boot.SpringApplication;
 | 
				
			||||||
 | 
					import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@SpringBootApplication(scanBasePackages = "cn.iocoder.mall.user")
 | 
				
			||||||
 | 
					public class UserApplication {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void main(String[] args) {
 | 
				
			||||||
 | 
					        SpringApplication.run(UserApplication.class, args);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.config.GlobalExceptionHandler;
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.config.GlobalResponseBodyAdvice;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.sdk.interceptor.SecurityInterceptor;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Import;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@EnableWebMvc
 | 
				
			||||||
 | 
					@Configuration
 | 
				
			||||||
 | 
					@Import(value = {GlobalResponseBodyAdvice.class, GlobalExceptionHandler.class,  // 统一全局返回
 | 
				
			||||||
 | 
					        SecurityInterceptor.class}) // 安全拦截器,实现认证和授权功能。
 | 
				
			||||||
 | 
					public class MVCConfiguration implements WebMvcConfigurer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private SecurityInterceptor securityInterceptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void addInterceptors(InterceptorRegistry registry) {
 | 
				
			||||||
 | 
					        registry.addInterceptor(securityInterceptor);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.util.ServiceExceptionUtil;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.constant.UserErrorCodeEnum;
 | 
				
			||||||
 | 
					import org.springframework.boot.context.event.ApplicationReadyEvent;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					import org.springframework.context.event.EventListener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Configuration
 | 
				
			||||||
 | 
					public class ServiceExceptionConfiguration {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @EventListener(ApplicationReadyEvent.class) // 可参考 https://www.cnblogs.com/ssslinppp/p/7607509.html
 | 
				
			||||||
 | 
					    public void initMessages() {
 | 
				
			||||||
 | 
					//        从 service_exception_message.properties 加载错误码的方案
 | 
				
			||||||
 | 
					//        Properties properties;
 | 
				
			||||||
 | 
					//        try {
 | 
				
			||||||
 | 
					//            properties = PropertiesLoaderUtils.loadAllProperties("classpath:service_exception_message.properties");
 | 
				
			||||||
 | 
					//        } catch (IOException e) {
 | 
				
			||||||
 | 
					//            throw new RuntimeException(e);
 | 
				
			||||||
 | 
					//        }
 | 
				
			||||||
 | 
					        for (UserErrorCodeEnum item : UserErrorCodeEnum.values()) {
 | 
				
			||||||
 | 
					            ServiceExceptionUtil.put(item.getCode(), item.getMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,95 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.exception.ServiceException;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.sdk.annotation.PermitAll;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.MobileCodeService;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.OAuth2Service;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.UserService;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.constant.UserErrorCodeEnum;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.dto.OAuth2AccessTokenBO;
 | 
				
			||||||
 | 
					import com.alibaba.dubbo.config.annotation.Reference;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.PostMapping;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.RequestMapping;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.RequestParam;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.RestController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@RestController
 | 
				
			||||||
 | 
					@RequestMapping("/passport")
 | 
				
			||||||
 | 
					public class PassportController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Reference
 | 
				
			||||||
 | 
					    private OAuth2Service oauth2Service;
 | 
				
			||||||
 | 
					    @Reference
 | 
				
			||||||
 | 
					    private UserService userService;
 | 
				
			||||||
 | 
					    @Reference
 | 
				
			||||||
 | 
					    private MobileCodeService mobileCodeService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO 功能:手机密码登陆
 | 
				
			||||||
 | 
					//    @PostMapping("/mobile/pwd/login")
 | 
				
			||||||
 | 
					//    public OAuth2AccessToken mobileLogin(@RequestParam("mobile") String mobile,
 | 
				
			||||||
 | 
					//                                         @RequestParam("password") String password) {
 | 
				
			||||||
 | 
					//        return oauth2Service.getAccessToken(clientId, clientSecret, mobile, password);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 手机号 + 验证码登陆
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param mobile 手机号
 | 
				
			||||||
 | 
					     * @param code 验证码
 | 
				
			||||||
 | 
					     * @return 授权信息
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @PermitAll
 | 
				
			||||||
 | 
					    @PostMapping("/mobile/login")
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenBO mobileRegister(@RequestParam("mobile") String mobile,
 | 
				
			||||||
 | 
					                                              @RequestParam("code") String code) {
 | 
				
			||||||
 | 
					        // 尝试直接授权
 | 
				
			||||||
 | 
					        OAuth2AccessTokenBO accessTokenDTO;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            accessTokenDTO = oauth2Service.getAccessToken(mobile, code);
 | 
				
			||||||
 | 
					            return accessTokenDTO;
 | 
				
			||||||
 | 
					        } catch (ServiceException serviceException) {
 | 
				
			||||||
 | 
					            if (!serviceException.getCode().equals(UserErrorCodeEnum.USER_MOBILE_NOT_REGISTERED.getCode())) { // 如果是未注册异常,忽略。下面发起自动注册逻辑。
 | 
				
			||||||
 | 
					                throw serviceException;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 上面尝试授权失败,说明用户未注册,发起自动注册。
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            userService.createUser(mobile, code);
 | 
				
			||||||
 | 
					        } catch (ServiceException serviceException) {
 | 
				
			||||||
 | 
					            if (!serviceException.getCode().equals(UserErrorCodeEnum.USER_MOBILE_ALREADY_REGISTERED.getCode())) { // 如果是已注册异常,忽略。下面再次发起授权
 | 
				
			||||||
 | 
					                throw serviceException;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 再次发起授权
 | 
				
			||||||
 | 
					        accessTokenDTO = oauth2Service.getAccessToken(mobile, code);
 | 
				
			||||||
 | 
					        return accessTokenDTO;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 发送手机验证码
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param mobile 手机号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @PostMapping("mobile/send")
 | 
				
			||||||
 | 
					    public void mobileSend(@RequestParam("mobile") String mobile) {
 | 
				
			||||||
 | 
					        mobileCodeService.send(mobile);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO 功能:qq 登陆
 | 
				
			||||||
 | 
					    @PermitAll
 | 
				
			||||||
 | 
					    @PostMapping("/qq/login")
 | 
				
			||||||
 | 
					    public String qqLogin() {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO 功能:qq 绑定
 | 
				
			||||||
 | 
					    @PermitAll
 | 
				
			||||||
 | 
					    @PostMapping("/qq/bind")
 | 
				
			||||||
 | 
					    public String qqBind() {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO 功能:刷新 token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO 功能:退出,销毁 token
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.GetMapping;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//@RestController
 | 
				
			||||||
 | 
					//@RequestMapping("/user")
 | 
				
			||||||
 | 
					public class UserController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @GetMapping("/info")
 | 
				
			||||||
 | 
					    public Long info() {
 | 
				
			||||||
 | 
					        // TODO 芋艿,正在实现中
 | 
				
			||||||
 | 
					//        return SecurityContextHolder.getContext().getUid();
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					spring:
 | 
				
			||||||
 | 
					  application:
 | 
				
			||||||
 | 
					    name: user-application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# server
 | 
				
			||||||
 | 
					server:
 | 
				
			||||||
 | 
					  port: 8082
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
				
			||||||
 | 
					         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
				
			||||||
 | 
					    <parent>
 | 
				
			||||||
 | 
					        <artifactId>user</artifactId>
 | 
				
			||||||
 | 
					        <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					        <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					    </parent>
 | 
				
			||||||
 | 
					    <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <artifactId>user-sdk</artifactId>
 | 
				
			||||||
 | 
					    <dependencies>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.springframework</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spring-context</artifactId>
 | 
				
			||||||
 | 
					            <version>5.1.5.RELEASE</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.springframework</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spring-webmvc</artifactId>
 | 
				
			||||||
 | 
					            <version>5.1.5.RELEASE</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.springframework</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spring-webmvc</artifactId>
 | 
				
			||||||
 | 
					            <version>5.1.5.RELEASE</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>com.alibaba</groupId>
 | 
				
			||||||
 | 
					            <artifactId>dubbo</artifactId>
 | 
				
			||||||
 | 
					            <version>2.6.5</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>javax.servlet</groupId>
 | 
				
			||||||
 | 
					            <artifactId>servlet-api</artifactId>
 | 
				
			||||||
 | 
					            <version>2.5</version>
 | 
				
			||||||
 | 
					            <scope>provided</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>common-framework</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>user-service-api</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					    </dependencies>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.sdk.annotation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.lang.annotation.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * URL 是否允许所有都可访问。即用户不登陆,就可以访问指定 URL 。
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 例如说,注册接口,用户是不需要登陆,就可以访问的。
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Documented
 | 
				
			||||||
 | 
					@Target({ElementType.METHOD}) // ElementType.TYPE 暂时不支持类级别。为了减少判断,略微提升性能。
 | 
				
			||||||
 | 
					@Retention(RetentionPolicy.RUNTIME)
 | 
				
			||||||
 | 
					public @interface PermitAll {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.sdk.context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Security 上下文
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SecurityContext {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final Long uid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public SecurityContext(Long uid) {
 | 
				
			||||||
 | 
					        this.uid = uid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getUid() {
 | 
				
			||||||
 | 
					        return uid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.sdk.context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * {@link SecurityContext} Holder
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 参考 spring security 的 ThreadLocalSecurityContextHolderStrategy 类,简单实现。
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SecurityContextHolder {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final ThreadLocal<SecurityContext> securityContext = new ThreadLocal<SecurityContext>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void setContext(SecurityContext context) {
 | 
				
			||||||
 | 
					        securityContext.set(context);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static SecurityContext getContext() {
 | 
				
			||||||
 | 
					        SecurityContext ctx = securityContext.get();
 | 
				
			||||||
 | 
					        // 为空时,设置一个空的进去
 | 
				
			||||||
 | 
					        if (ctx == null) {
 | 
				
			||||||
 | 
					            ctx = new SecurityContext(null);
 | 
				
			||||||
 | 
					            securityContext.set(ctx);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ctx;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void clear() {
 | 
				
			||||||
 | 
					        securityContext.remove();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.sdk.interceptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.exception.ServiceException;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.sdk.annotation.PermitAll;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.sdk.context.SecurityContext;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.sdk.context.SecurityContextHolder;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.OAuth2Service;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.dto.OAuth2AuthenticationDTO;
 | 
				
			||||||
 | 
					import com.alibaba.dubbo.config.annotation.Reference;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Component;
 | 
				
			||||||
 | 
					import org.springframework.util.StringUtils;
 | 
				
			||||||
 | 
					import org.springframework.web.method.HandlerMethod;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletRequest;
 | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletResponse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 安全拦截器
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Component
 | 
				
			||||||
 | 
					public class SecurityInterceptor extends HandlerInterceptorAdapter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Reference
 | 
				
			||||||
 | 
					    private OAuth2Service oauth2Service;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 | 
				
			||||||
 | 
					        // 校验访问令牌是否正确。若正确,返回授权信息
 | 
				
			||||||
 | 
					        String accessToken = obtainAccess(request);
 | 
				
			||||||
 | 
					        OAuth2AuthenticationDTO authentication = null;
 | 
				
			||||||
 | 
					        if (accessToken != null) {
 | 
				
			||||||
 | 
					            authentication = oauth2Service.checkToken(accessToken);
 | 
				
			||||||
 | 
					            // 添加到 SecurityContext
 | 
				
			||||||
 | 
					            SecurityContext context = new SecurityContext(authentication.getUid());
 | 
				
			||||||
 | 
					            SecurityContextHolder.setContext(context);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 校验是否需要已授权
 | 
				
			||||||
 | 
					        HandlerMethod method = (HandlerMethod) handler;
 | 
				
			||||||
 | 
					        boolean isPermitAll = method.hasMethodAnnotation(PermitAll.class);
 | 
				
			||||||
 | 
					        if (!isPermitAll && authentication == null) {
 | 
				
			||||||
 | 
					            throw new ServiceException(-1, "未授权"); // TODO 这里要改下
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return super.preHandle(request, response, handler);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
 | 
				
			||||||
 | 
					        // 清空 SecurityContext
 | 
				
			||||||
 | 
					        SecurityContextHolder.clear();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String obtainAccess(HttpServletRequest request) {
 | 
				
			||||||
 | 
					        String authorization = request.getHeader("Authorization");
 | 
				
			||||||
 | 
					        if (!StringUtils.hasText(authorization)) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int index = authorization.indexOf("Bearer ");
 | 
				
			||||||
 | 
					        if (index == -1) { // 未找到
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return authorization.substring(index + 7).trim();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 提供 SDK 给其它服务,使用如下功能:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 1. 通过 {@link } 拦截器,
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.sdk;
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
				
			||||||
 | 
					         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
				
			||||||
 | 
					    <parent>
 | 
				
			||||||
 | 
					        <artifactId>user</artifactId>
 | 
				
			||||||
 | 
					        <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					        <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					    </parent>
 | 
				
			||||||
 | 
					    <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <artifactId>user-service-api</artifactId>
 | 
				
			||||||
 | 
					    <dependencies>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>common-framework</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					    </dependencies>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service.api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.exception.ServiceException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface MobileCodeService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 发送验证码
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param mobile 手机号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void send(String mobile) throws ServiceException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service.api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.exception.ServiceException;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.dto.OAuth2AccessTokenBO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.dto.OAuth2AuthenticationDTO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface OAuth2Service {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 使用手机号 + 验证码,获取访问令牌等信息
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * 如果手机未注册,并且验证码正确,进行自动注册。
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param mobile 手机号
 | 
				
			||||||
 | 
					     * @param code   验证码
 | 
				
			||||||
 | 
					     * @return 授权信息
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    OAuth2AccessTokenBO getAccessToken(String mobile, String code)
 | 
				
			||||||
 | 
					            throws ServiceException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 校验访问令牌,获取身份信息( 不包括 accessToken 等等 )
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param accessToken 访问令牌
 | 
				
			||||||
 | 
					     * @return 授权信息
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    OAuth2AuthenticationDTO checkToken(String accessToken)
 | 
				
			||||||
 | 
					            throws ServiceException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // @see 刷新 token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // @see 移除 token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service.api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.exception.ServiceException;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.dto.UserDTO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface UserService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建用户。一般在用户注册时,调用该方法
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param mobile 手机号
 | 
				
			||||||
 | 
					     * @param code 手机验证码
 | 
				
			||||||
 | 
					     * @return 用户
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    UserDTO createUser(String mobile, String code) throws ServiceException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service.api.constant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ThirdPlatformConstant {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static final int QQ = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static final int WEIBO = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // WECHAT 可能分成好几个
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ....
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service.api.constant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 错误码枚举类
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 用户中心,使用 1-001-000-000 段
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public enum UserErrorCodeEnum {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ========== OAUTH2 模块 ==========
 | 
				
			||||||
 | 
					    OAUTH2_UNKNOWN(1001001000, "未知错误"), // 预留
 | 
				
			||||||
 | 
					    OAUTH2_INVALID_GRANT_BAD_CREDENTIALS(1001001001, "密码不正确"), // 暂时没用到
 | 
				
			||||||
 | 
					    OAUTH2_INVALID_GRANT_USERNAME_NOT_FOUND(1001001002, "账号不存在"), // 暂时没用到
 | 
				
			||||||
 | 
					    OAUTH2_INVALID_GRANT(1001001010, ""), // 预留
 | 
				
			||||||
 | 
					    OAUTH_INVALID_TOKEN_NOT_FOUND(1001001011, "访问令牌不存在"),
 | 
				
			||||||
 | 
					    OAUTH_INVALID_TOKEN_EXPIRED(1001001012, "访问令牌已过期"),
 | 
				
			||||||
 | 
					    OAUTH_INVALID_TOKEN_INVALID(1001001013, "访问令牌已失效"),
 | 
				
			||||||
 | 
					    OAUTH_INVALID_TOKEN(1001001020, ""), // 预留
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ========== 用户模块 ==========
 | 
				
			||||||
 | 
					    USER_MOBILE_NOT_REGISTERED(1001002000, "手机号未注册用户"),
 | 
				
			||||||
 | 
					    USER_MOBILE_ALREADY_REGISTERED(1001002001, "手机号已经注册用户"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ========== 手机验证码模块 ==========
 | 
				
			||||||
 | 
					    MOBILE_CODE_NOT_FOUND(1001003000, "验证码不存在"),
 | 
				
			||||||
 | 
					    MOBILE_CODE_EXPIRED(1001003001, "验证码已过期"),
 | 
				
			||||||
 | 
					    MOBILE_CODE_USED(1001003002, "验证码已使用"),
 | 
				
			||||||
 | 
					    MOBILE_CODE_NOT_CORRECT(1001003003, "验证码不正确"),
 | 
				
			||||||
 | 
					    MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY(1001003004, "超过每日短信发送数量"),
 | 
				
			||||||
 | 
					    MOBILE_CODE_SEND_TOO_FAST(1001003005, "短信发送过于频率")
 | 
				
			||||||
 | 
					    ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final int code;
 | 
				
			||||||
 | 
					    private final String message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UserErrorCodeEnum(int code, String message) {
 | 
				
			||||||
 | 
					        this.code = code;
 | 
				
			||||||
 | 
					        this.message = message;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getCode() {
 | 
				
			||||||
 | 
					        return code;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getMessage() {
 | 
				
			||||||
 | 
					        return message;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service.api.dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class MobileCodeDTO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getCode() {
 | 
				
			||||||
 | 
					        return code;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MobileCodeDTO setCode(String code) {
 | 
				
			||||||
 | 
					        this.code = code;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,47 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service.api.dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.Serializable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class OAuth2AccessTokenBO implements Serializable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 访问令牌
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String accessToken;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 刷新令牌
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String refreshToken;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 过期时间,单位:秒。
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Integer expiresIn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getAccessToken() {
 | 
				
			||||||
 | 
					        return accessToken;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenBO setAccessToken(String accessToken) {
 | 
				
			||||||
 | 
					        this.accessToken = accessToken;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getRefreshToken() {
 | 
				
			||||||
 | 
					        return refreshToken;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenBO setRefreshToken(String refreshToken) {
 | 
				
			||||||
 | 
					        this.refreshToken = refreshToken;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Integer getExpiresIn() {
 | 
				
			||||||
 | 
					        return expiresIn;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenBO setExpiresIn(Integer expiresIn) {
 | 
				
			||||||
 | 
					        this.expiresIn = expiresIn;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service.api.dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.Serializable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class OAuth2AuthenticationDTO implements Serializable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 用户编号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Long uid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getUid() {
 | 
				
			||||||
 | 
					        return uid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AuthenticationDTO setUid(Long uid) {
 | 
				
			||||||
 | 
					        this.uid = uid;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service.api.dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class UserDTO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 用户编号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Long uid;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 手机号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String mobile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getUid() {
 | 
				
			||||||
 | 
					        return uid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserDTO setUid(Long uid) {
 | 
				
			||||||
 | 
					        this.uid = uid;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getMobile() {
 | 
				
			||||||
 | 
					        return mobile;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserDTO setMobile(String mobile) {
 | 
				
			||||||
 | 
					        this.mobile = mobile;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
				
			||||||
 | 
					         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
				
			||||||
 | 
					    <parent>
 | 
				
			||||||
 | 
					        <artifactId>user</artifactId>
 | 
				
			||||||
 | 
					        <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					        <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					    </parent>
 | 
				
			||||||
 | 
					    <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <artifactId>user-service-impl</artifactId>
 | 
				
			||||||
 | 
					    <dependencies>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>com.alibaba</groupId>
 | 
				
			||||||
 | 
					            <artifactId>dubbo</artifactId>
 | 
				
			||||||
 | 
					            <version>2.6.5</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.iocoder.mall</groupId>
 | 
				
			||||||
 | 
					            <artifactId>user-service-api</artifactId>
 | 
				
			||||||
 | 
					            <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>mysql</groupId>
 | 
				
			||||||
 | 
					            <artifactId>mysql-connector-java</artifactId>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.springframework.boot</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spring-boot-starter-jdbc</artifactId>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.mybatis.spring.boot</groupId>
 | 
				
			||||||
 | 
					            <artifactId>mybatis-spring-boot-starter</artifactId>
 | 
				
			||||||
 | 
					            <version>2.0.0</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.mapstruct</groupId>
 | 
				
			||||||
 | 
					            <artifactId>mapstruct</artifactId>
 | 
				
			||||||
 | 
					            <version>1.3.0.Final</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </dependencies>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.mybatis.spring.annotation.MapperScan;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					import org.springframework.transaction.annotation.EnableTransactionManagement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Configuration
 | 
				
			||||||
 | 
					@MapperScan("cn.iocoder.mall.user.dao") // 扫描对应的 Mapper 接口
 | 
				
			||||||
 | 
					@EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理。为什么使用 proxyTargetClass 参数,参见 https://blog.csdn.net/huang_550/article/details/76492600
 | 
				
			||||||
 | 
					public class DatabaseConfiguration {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 数据源,使用 HikariCP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.OAuth2AccessTokenDO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.dto.OAuth2AccessTokenBO;
 | 
				
			||||||
 | 
					import org.mapstruct.Mappings;
 | 
				
			||||||
 | 
					import org.mapstruct.factory.Mappers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface OAuth2Convert {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OAuth2Convert INSTANCE = Mappers.getMapper(OAuth2Convert.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Mappings({})
 | 
				
			||||||
 | 
					    OAuth2AccessTokenBO convert(OAuth2AccessTokenDO oauth2AccessTokenDO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default OAuth2AccessTokenBO convertWithExpiresIn(OAuth2AccessTokenDO oauth2AccessTokenDO) {
 | 
				
			||||||
 | 
					        OAuth2AccessTokenBO bo = this.convert(oauth2AccessTokenDO);
 | 
				
			||||||
 | 
					        bo.setExpiresIn(Math.max((int) ((oauth2AccessTokenDO.getExpiresTime().getTime() - System.currentTimeMillis()) / 1000), 0));
 | 
				
			||||||
 | 
					        return bo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dao;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.MobileCodeDO;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Repository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Repository // 实际不加也没问entity,就是不想 IDEA 那看到有个报错
 | 
				
			||||||
 | 
					public interface MobileCodeMapper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void insert(MobileCodeDO entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 更新手机验证码
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param entity 更新信息
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void update(MobileCodeDO entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获得手机号的最后一个手机验证码
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param mobile 手机号
 | 
				
			||||||
 | 
					     * @return 手机验证码
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    MobileCodeDO selectLast1ByMobile(String mobile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dao;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.OAuth2AccessTokenDO;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Repository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Repository
 | 
				
			||||||
 | 
					public interface OAuth2AccessTokenMapper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void insert(OAuth2AccessTokenDO entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OAuth2AccessTokenDO selectByTokenId(String tokenId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dao;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.OAuth2RefreshTokenDO;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Repository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Repository
 | 
				
			||||||
 | 
					public interface OAuth2RefreshTokenMapper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void insert(OAuth2RefreshTokenDO entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dao;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.UserDO;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Repository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Repository
 | 
				
			||||||
 | 
					public interface UserMapper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void insert(UserDO entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UserDO selectByMobile(String mobile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dao;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.UserRegisterDO;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Repository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Repository
 | 
				
			||||||
 | 
					public interface UserRegisterMapper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void insert(UserRegisterDO entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,113 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dataobject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO 优化,IP
 | 
				
			||||||
 | 
					public class MobileCodeDO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 编号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Long id;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 手机号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String mobile;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 验证码
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String code;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 今日发送的第几条
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Integer todayIndex;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 是否使用
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Boolean used;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 注册的用户编号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Long usedUid;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建时间
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date createTime;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 使用时间
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date usedTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getId() {
 | 
				
			||||||
 | 
					        return id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MobileCodeDO setId(Long id) {
 | 
				
			||||||
 | 
					        this.id = id;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getMobile() {
 | 
				
			||||||
 | 
					        return mobile;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MobileCodeDO setMobile(String mobile) {
 | 
				
			||||||
 | 
					        this.mobile = mobile;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getCode() {
 | 
				
			||||||
 | 
					        return code;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MobileCodeDO setCode(String code) {
 | 
				
			||||||
 | 
					        this.code = code;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Integer getTodayIndex() {
 | 
				
			||||||
 | 
					        return todayIndex;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MobileCodeDO setTodayIndex(Integer todayIndex) {
 | 
				
			||||||
 | 
					        this.todayIndex = todayIndex;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Boolean getUsed() {
 | 
				
			||||||
 | 
					        return used;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MobileCodeDO setUsed(Boolean used) {
 | 
				
			||||||
 | 
					        this.used = used;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getUsedUid() {
 | 
				
			||||||
 | 
					        return usedUid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MobileCodeDO setUsedUid(Long usedUid) {
 | 
				
			||||||
 | 
					        this.usedUid = usedUid;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Date getCreateTime() {
 | 
				
			||||||
 | 
					        return createTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MobileCodeDO setCreateTime(Date createTime) {
 | 
				
			||||||
 | 
					        this.createTime = createTime;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Date getUsedTime() {
 | 
				
			||||||
 | 
					        return usedTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MobileCodeDO setUsedTime(Date usedTime) {
 | 
				
			||||||
 | 
					        this.usedTime = usedTime;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,85 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dataobject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class OAuth2AccessTokenDO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 访问令牌
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String tokenId;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 刷新令牌
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String refreshToken;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 用户编号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Long uid;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 过期时间
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date expiresTime;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 是否有效
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Boolean valid;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建时间
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date createTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getTokenId() {
 | 
				
			||||||
 | 
					        return tokenId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenDO setTokenId(String tokenId) {
 | 
				
			||||||
 | 
					        this.tokenId = tokenId;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getRefreshToken() {
 | 
				
			||||||
 | 
					        return refreshToken;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenDO setRefreshToken(String refreshToken) {
 | 
				
			||||||
 | 
					        this.refreshToken = refreshToken;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getUid() {
 | 
				
			||||||
 | 
					        return uid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenDO setUid(Long uid) {
 | 
				
			||||||
 | 
					        this.uid = uid;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Date getExpiresTime() {
 | 
				
			||||||
 | 
					        return expiresTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenDO setExpiresTime(Date expiresTime) {
 | 
				
			||||||
 | 
					        this.expiresTime = expiresTime;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Boolean getValid() {
 | 
				
			||||||
 | 
					        return valid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenDO setValid(Boolean valid) {
 | 
				
			||||||
 | 
					        this.valid = valid;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Date getCreateTime() {
 | 
				
			||||||
 | 
					        return createTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenDO setCreateTime(Date createTime) {
 | 
				
			||||||
 | 
					        this.createTime = createTime;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,78 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dataobject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 刷新令牌
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * idx_uid
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class OAuth2RefreshTokenDO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 刷新令牌
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String tokenId;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 用户编号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Long uid;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 是否有效
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Boolean valid;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 过期时间
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date expiresTime;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建时间
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date createTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getTokenId() {
 | 
				
			||||||
 | 
					        return tokenId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2RefreshTokenDO setTokenId(String tokenId) {
 | 
				
			||||||
 | 
					        this.tokenId = tokenId;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getUid() {
 | 
				
			||||||
 | 
					        return uid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2RefreshTokenDO setUid(Long uid) {
 | 
				
			||||||
 | 
					        this.uid = uid;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Boolean getValid() {
 | 
				
			||||||
 | 
					        return valid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2RefreshTokenDO setValid(Boolean valid) {
 | 
				
			||||||
 | 
					        this.valid = valid;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Date getExpiresTime() {
 | 
				
			||||||
 | 
					        return expiresTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2RefreshTokenDO setExpiresTime(Date expiresTime) {
 | 
				
			||||||
 | 
					        this.expiresTime = expiresTime;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Date getCreateTime() {
 | 
				
			||||||
 | 
					        return createTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OAuth2RefreshTokenDO setCreateTime(Date createTime) {
 | 
				
			||||||
 | 
					        this.createTime = createTime;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dataobject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 用户实体,存储用户基本数据。
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * idx_mobile 唯一索引
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class UserDO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 用户编号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Long id;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 手机号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String mobile;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建时间
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date createTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getId() {
 | 
				
			||||||
 | 
					        return id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserDO setId(Long id) {
 | 
				
			||||||
 | 
					        this.id = id;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getMobile() {
 | 
				
			||||||
 | 
					        return mobile;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserDO setMobile(String mobile) {
 | 
				
			||||||
 | 
					        this.mobile = mobile;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Date getCreateTime() {
 | 
				
			||||||
 | 
					        return createTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserDO setCreateTime(Date createTime) {
 | 
				
			||||||
 | 
					        this.createTime = createTime;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dataobject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class UserLoginLogDO {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dataobject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 用户注册信息
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class UserRegisterDO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 用户编号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Long id;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建时间
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date createTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO 芋艿 ip
 | 
				
			||||||
 | 
					    // TODO 芋艿 ua
 | 
				
			||||||
 | 
					    // TODO 芋艿 方式,手机注册、qq 等等
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getId() {
 | 
				
			||||||
 | 
					        return id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserRegisterDO setId(Long id) {
 | 
				
			||||||
 | 
					        this.id = id;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Date getCreateTime() {
 | 
				
			||||||
 | 
					        return createTime;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserRegisterDO setCreateTime(Date createTime) {
 | 
				
			||||||
 | 
					        this.createTime = createTime;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.dataobject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 用户三方开放平台授权,例如:QQ / 微博 / 微信等等。
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class UserThirdAuthDO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 用户编号
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * 外键 {@link UserDO#uid}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Long uid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ========== 授权相关字段
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 用户的唯一标识
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String openid;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 开放平台
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @see cn.iocoder.mall.user.constant.ThirdPlatformConstant
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Integer platform;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 访问令牌
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date accessToken;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 过期时间
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date expireTime;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 刷新令牌
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Date refreshToken;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 授权范围。一般情况下,使用逗号分隔
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String scopes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ========== 基础信息
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 用户昵称
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String nickname;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 性别
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * TODO 芋艿,找地方统一枚举。0-未知,1-男,2-女
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Integer gender;
 | 
				
			||||||
 | 
					    // TODO https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
 | 
				
			||||||
 | 
					    // TODO 芋艿,其他字段,国家/省份/城市/地区等
 | 
				
			||||||
 | 
					    // TODO 芋艿,头像
 | 
				
			||||||
 | 
					    // TODO 芋艿,微信独有 unionid
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 统一存储基础信息,使用 JSON 格式化,避免未有效解析的情况。
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String extras;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user;
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,104 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.util.ServiceExceptionUtil;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dao.MobileCodeMapper;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.MobileCodeDO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.MobileCodeService;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.constant.UserErrorCodeEnum;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Value;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * MobileCodeService ,实现用户登陆时需要的验证码
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Service
 | 
				
			||||||
 | 
					@com.alibaba.dubbo.config.annotation.Service
 | 
				
			||||||
 | 
					public class MobileCodeServiceImpl implements MobileCodeService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 每条验证码的过期时间,单位:毫秒
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Value("${modules.mobile-code-service.code-expire-time-millis}")
 | 
				
			||||||
 | 
					    private int codeExpireTimes;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 每日发送最大数量
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Value("${modules.mobile-code-service.send-maximum-quantity-per-day}")
 | 
				
			||||||
 | 
					    private int sendMaximumQuantityPerDay;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 短信发送频率,单位:毫秒
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Value("${modules.mobile-code-service.send-frequency}")
 | 
				
			||||||
 | 
					    private int sendFrequency;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private MobileCodeMapper mobileCodeMapper;
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private UserServiceImpl userService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 校验手机号的最后一个手机验证码是否有效
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param mobile 手机号
 | 
				
			||||||
 | 
					     * @param code 验证码
 | 
				
			||||||
 | 
					     * @return 手机验证码信息
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public MobileCodeDO validLastMobileCode(String mobile, String code) {
 | 
				
			||||||
 | 
					        MobileCodeDO mobileCodePO = mobileCodeMapper.selectLast1ByMobile(mobile);
 | 
				
			||||||
 | 
					        if (mobileCodePO == null) { // 若验证码不存在,抛出异常
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_NOT_FOUND.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (System.currentTimeMillis() - mobileCodePO.getCreateTime().getTime() >= codeExpireTimes) { // 验证码已过期
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_EXPIRED.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (mobileCodePO.getUsed()) { // 验证码已使用
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_USED.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!mobileCodePO.getCode().equals(code)) {
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_NOT_CORRECT.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return mobileCodePO;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 更新手机验证码已使用
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param id 验证码编号
 | 
				
			||||||
 | 
					     * @param uid 用户编号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void useMobileCode(Long id, Long uid) {
 | 
				
			||||||
 | 
					        MobileCodeDO update = new MobileCodeDO().setId(id).setUsed(true).setUsedUid(uid).setUsedTime(new Date());
 | 
				
			||||||
 | 
					        mobileCodeMapper.update(update);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void send(String mobile) {
 | 
				
			||||||
 | 
					        // TODO 芋艿,校验手机格式
 | 
				
			||||||
 | 
					        // 校验手机号码是否已经注册
 | 
				
			||||||
 | 
					        if (userService.getUser(mobile) != null) {
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.USER_MOBILE_ALREADY_REGISTERED.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 校验是否可以发送验证码
 | 
				
			||||||
 | 
					        MobileCodeDO lastMobileCodePO = mobileCodeMapper.selectLast1ByMobile(mobile);
 | 
				
			||||||
 | 
					        if (lastMobileCodePO != null) {
 | 
				
			||||||
 | 
					            if (lastMobileCodePO.getTodayIndex() >= sendMaximumQuantityPerDay) { // 超过当天发送的上限。
 | 
				
			||||||
 | 
					                throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY.getCode());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (System.currentTimeMillis() - lastMobileCodePO.getCreateTime().getTime() < sendFrequency) { // 发送过于频繁
 | 
				
			||||||
 | 
					                throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_SEND_TOO_FAST.getCode());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // TODO 提升,每个 IP 每天可发送数量
 | 
				
			||||||
 | 
					            // TODO 提升,每个 IP 每小时可发送数量
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 创建验证码记录
 | 
				
			||||||
 | 
					        MobileCodeDO newMobileCodePO = new MobileCodeDO().setMobile(mobile)
 | 
				
			||||||
 | 
					                .setCode("9999") // TODO 芋艿,随机 4 位验证码 or 6 位验证码
 | 
				
			||||||
 | 
					                .setTodayIndex(lastMobileCodePO != null ? lastMobileCodePO.getTodayIndex() : 1)
 | 
				
			||||||
 | 
					                .setUsed(false).setCreateTime(new Date());
 | 
				
			||||||
 | 
					        mobileCodeMapper.insert(newMobileCodePO);
 | 
				
			||||||
 | 
					        // TODO 发送验证码短信
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,114 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.exception.ServiceException;
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.util.ServiceExceptionUtil;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.convert.OAuth2Convert;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dao.OAuth2AccessTokenMapper;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dao.OAuth2RefreshTokenMapper;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.MobileCodeDO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.OAuth2AccessTokenDO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.OAuth2RefreshTokenDO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.UserDO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.OAuth2Service;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.constant.UserErrorCodeEnum;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.dto.OAuth2AccessTokenBO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.dto.OAuth2AuthenticationDTO;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Value;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
 | 
					import org.springframework.transaction.annotation.Transactional;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * OAuth2Service ,实现用户授权相关的逻辑
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Service
 | 
				
			||||||
 | 
					@com.alibaba.dubbo.config.annotation.Service
 | 
				
			||||||
 | 
					public class OAuth2ServiceImpl implements OAuth2Service {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 访问令牌过期时间,单位:毫秒
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Value("${modules.oauth2-code-service.access-token-expire-time-millis}")
 | 
				
			||||||
 | 
					    private int accessTokenExpireTimeMillis;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 刷新令牌过期时间,单位:毫秒
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Value("${modules.oauth2-code-service.refresh-token-expire-time-millis}")
 | 
				
			||||||
 | 
					    private int refreshTokenExpireTimeMillis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private UserServiceImpl userService;
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private MobileCodeServiceImpl mobileCodeService;
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private OAuth2AccessTokenMapper oauth2AccessTokenMapper;
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    @Transactional
 | 
				
			||||||
 | 
					    public OAuth2AccessTokenBO getAccessToken(String mobile, String code) {
 | 
				
			||||||
 | 
					        // 校验手机号的最后一个手机验证码是否有效
 | 
				
			||||||
 | 
					        MobileCodeDO mobileCodeDO = mobileCodeService.validLastMobileCode(mobile, code);
 | 
				
			||||||
 | 
					        // 获取用户
 | 
				
			||||||
 | 
					        UserDO userDO = userService.getUser(mobile);
 | 
				
			||||||
 | 
					        if (userDO == null) { // 用户不存在
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.USER_MOBILE_NOT_REGISTERED.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 创建刷新令牌
 | 
				
			||||||
 | 
					        OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(userDO.getId());
 | 
				
			||||||
 | 
					        // 创建访问令牌
 | 
				
			||||||
 | 
					        OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(userDO.getId(), oauth2RefreshTokenDO.getTokenId());
 | 
				
			||||||
 | 
					        // 标记已使用
 | 
				
			||||||
 | 
					        mobileCodeService.useMobileCode(mobileCodeDO.getId(), userDO.getId());
 | 
				
			||||||
 | 
					        // 转换返回
 | 
				
			||||||
 | 
					        return OAuth2Convert.INSTANCE.convertWithExpiresIn(oauth2AccessTokenDO);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public OAuth2AuthenticationDTO checkToken(String accessToken) throws ServiceException {
 | 
				
			||||||
 | 
					        OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByTokenId(accessToken);
 | 
				
			||||||
 | 
					        if (accessTokenDO == null) { // 不存在
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_TOKEN_NOT_FOUND.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (accessTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_TOKEN_EXPIRED.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!accessTokenDO.getValid()) { // 无效
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_TOKEN_INVALID.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 转换返回
 | 
				
			||||||
 | 
					        return new OAuth2AuthenticationDTO().setUid(accessTokenDO.getUid());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OAuth2AccessTokenDO createOAuth2AccessToken(Long uid, String refreshToken) {
 | 
				
			||||||
 | 
					        OAuth2AccessTokenDO accessToken = new OAuth2AccessTokenDO().setTokenId(generateAccessToken())
 | 
				
			||||||
 | 
					                .setRefreshToken(refreshToken)
 | 
				
			||||||
 | 
					                .setUid(uid)
 | 
				
			||||||
 | 
					                .setExpiresTime(new Date(System.currentTimeMillis() + accessTokenExpireTimeMillis))
 | 
				
			||||||
 | 
					                .setValid(true);
 | 
				
			||||||
 | 
					        oauth2AccessTokenMapper.insert(accessToken);
 | 
				
			||||||
 | 
					        return accessToken;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long uid) {
 | 
				
			||||||
 | 
					        OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setTokenId(generateRefreshToken())
 | 
				
			||||||
 | 
					                .setUid(uid)
 | 
				
			||||||
 | 
					                .setExpiresTime(new Date(System.currentTimeMillis() + refreshTokenExpireTimeMillis))
 | 
				
			||||||
 | 
					                .setValid(true);
 | 
				
			||||||
 | 
					        oauth2RefreshTokenMapper.insert(refreshToken);
 | 
				
			||||||
 | 
					        return refreshToken;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String generateAccessToken() {
 | 
				
			||||||
 | 
					        return UUID.randomUUID().toString().replaceAll("-", "");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String generateRefreshToken() {
 | 
				
			||||||
 | 
					        return UUID.randomUUID().toString().replaceAll("-", "");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,60 @@
 | 
				
			||||||
 | 
					package cn.iocoder.mall.user.service;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.common.framework.util.ServiceExceptionUtil;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dao.UserMapper;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dao.UserRegisterMapper;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.UserDO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.dataobject.UserRegisterDO;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.UserService;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.constant.UserErrorCodeEnum;
 | 
				
			||||||
 | 
					import cn.iocoder.mall.user.service.api.dto.UserDTO;
 | 
				
			||||||
 | 
					import com.alibaba.dubbo.config.annotation.Service;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||||
 | 
					import org.springframework.transaction.annotation.Transactional;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * UserService ,实现和用户信息相关的逻辑
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@org.springframework.stereotype.Service
 | 
				
			||||||
 | 
					@com.alibaba.dubbo.config.annotation.Service
 | 
				
			||||||
 | 
					public class UserServiceImpl implements UserService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private UserMapper userMapper;
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private UserRegisterMapper userRegisterMapper;
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    private MobileCodeServiceImpl mobileCodeService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserDO getUser(String mobile) {
 | 
				
			||||||
 | 
					        return userMapper.selectByMobile(mobile);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    @Transactional
 | 
				
			||||||
 | 
					    public UserDTO createUser(String mobile, String code) {
 | 
				
			||||||
 | 
					        // TODO 芋艿,校验手机格式
 | 
				
			||||||
 | 
					        // 校验手机号的最后一个手机验证码是否有效
 | 
				
			||||||
 | 
					        mobileCodeService.validLastMobileCode(mobile, code);
 | 
				
			||||||
 | 
					        // 校验用户是否已经存在
 | 
				
			||||||
 | 
					        if (getUser(mobile) != null) {
 | 
				
			||||||
 | 
					            throw ServiceExceptionUtil.exception(UserErrorCodeEnum.USER_MOBILE_ALREADY_REGISTERED.getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 创建用户
 | 
				
			||||||
 | 
					        UserDO userDO = new UserDO().setMobile(mobile).setCreateTime(new Date());
 | 
				
			||||||
 | 
					        userMapper.insert(userDO);
 | 
				
			||||||
 | 
					        // 插入注册信息
 | 
				
			||||||
 | 
					        createUserRegister(userDO);
 | 
				
			||||||
 | 
					        // 转换返回
 | 
				
			||||||
 | 
					        return new UserDTO().setUid(userDO.getId());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void createUserRegister(UserDO userDO) {
 | 
				
			||||||
 | 
					        UserRegisterDO userRegisterDO = new UserRegisterDO().setId(userDO.getId())
 | 
				
			||||||
 | 
					                .setCreateTime(new Date());
 | 
				
			||||||
 | 
					        userRegisterMapper.insert(userRegisterDO);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					##################### 业务模块 #####################
 | 
				
			||||||
 | 
					## MobileCodeService
 | 
				
			||||||
 | 
					modules.mobile-code-service.code-expire-time-millis = 600000
 | 
				
			||||||
 | 
					modules.mobile-code-service.send-maximum-quantity-per-day = 10
 | 
				
			||||||
 | 
					modules.mobile-code-service.send-frequency = 60000
 | 
				
			||||||
 | 
					## OAuth2CodeService
 | 
				
			||||||
 | 
					modules.oauth2-code-service.access-token-expire-time-millis = 2880000
 | 
				
			||||||
 | 
					modules.oauth2-code-service.refresh-token-expire-time-millis = 43200000
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					spring:
 | 
				
			||||||
 | 
					  # datasource
 | 
				
			||||||
 | 
					  datasource:
 | 
				
			||||||
 | 
					    url: jdbc:mysql://127.0.0.1:33061/mall_user?useSSL=false
 | 
				
			||||||
 | 
					    driver-class-name: com.mysql.jdbc.Driver
 | 
				
			||||||
 | 
					    username: root
 | 
				
			||||||
 | 
					    password: 123456
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# server
 | 
				
			||||||
 | 
					server:
 | 
				
			||||||
 | 
					  port: 8082
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# mybatis
 | 
				
			||||||
 | 
					mybatis:
 | 
				
			||||||
 | 
					  config-location: classpath:mybatis-config.xml
 | 
				
			||||||
 | 
					  mapper-locations: classpath:mapper/*.xml
 | 
				
			||||||
 | 
					  type-aliases-package: cn.iocoder.mall.user.dataobject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# dubbo
 | 
				
			||||||
 | 
					dubbo:
 | 
				
			||||||
 | 
					  application:
 | 
				
			||||||
 | 
					    name: user-service
 | 
				
			||||||
 | 
					  registry:
 | 
				
			||||||
 | 
					    address: zookeeper://127.0.0.1:2181
 | 
				
			||||||
 | 
					  protocol:
 | 
				
			||||||
 | 
					    port: -1
 | 
				
			||||||
 | 
					    name: dubbo
 | 
				
			||||||
 | 
					  scan:
 | 
				
			||||||
 | 
					    base-packages: cn.iocoder.mall.user.service
 | 
				
			||||||
 | 
					demo:
 | 
				
			||||||
 | 
					  service:
 | 
				
			||||||
 | 
					    version: 1.0.0
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					<?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="cn.iocoder.mall.user.dao.MobileCodeMapper">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <insert id="insert" parameterType="MobileCodeDO">
 | 
				
			||||||
 | 
					        INSERT INTO mobile_code (
 | 
				
			||||||
 | 
					          id, mobile, code, today_index, used,
 | 
				
			||||||
 | 
					          used_uid, used_time, create_time
 | 
				
			||||||
 | 
					        ) VALUES (
 | 
				
			||||||
 | 
					          #{id}, #{mobile}, #{code}, #{todayIndex}, #{used},
 | 
				
			||||||
 | 
					          #{usedUid}, #{usedTime}, #{createTime}
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    </insert>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <update id="update" parameterType="MobileCodeDO">
 | 
				
			||||||
 | 
					        UPDATE mobile_code
 | 
				
			||||||
 | 
					        <set>
 | 
				
			||||||
 | 
					            <if test="used != null"> used = #{used}, </if>
 | 
				
			||||||
 | 
					            <if test="usedUid != null"> used_uid = #{usedUid}, </if>
 | 
				
			||||||
 | 
					            <if test="usedTime != null"> used_time = #{usedTime}, </if>
 | 
				
			||||||
 | 
					        </set>
 | 
				
			||||||
 | 
					        WHERE id = #{id}
 | 
				
			||||||
 | 
					    </update>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <select id="selectLast1ByMobile" parameterType="String" resultType="MobileCodeDO">
 | 
				
			||||||
 | 
					      SELECT
 | 
				
			||||||
 | 
					          id, mobile, code, today_index, used,
 | 
				
			||||||
 | 
					          used_uid, used_time, create_time
 | 
				
			||||||
 | 
					      FROM mobile_code
 | 
				
			||||||
 | 
					      WHERE mobile = #{mobile}
 | 
				
			||||||
 | 
					      ORDER BY id DESC
 | 
				
			||||||
 | 
					      LIMIT 1
 | 
				
			||||||
 | 
					    </select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</mapper>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					<?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="cn.iocoder.mall.user.dao.OAuth2AccessTokenMapper">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <insert id="insert" parameterType="OAuth2AccessTokenDO">
 | 
				
			||||||
 | 
					        INSERT INTO oauth2_access_token (
 | 
				
			||||||
 | 
					          token_id, refresh_token, id, valid, expires_time,
 | 
				
			||||||
 | 
					          create_time
 | 
				
			||||||
 | 
					        ) VALUES (
 | 
				
			||||||
 | 
					          #{tokenId}, #{refreshToken}, #{id}, #{valid}, #{expiresTime},
 | 
				
			||||||
 | 
					           #{createTime}
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    </insert>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <select id="selectByTokenId" parameterType="String" resultType="OAuth2AccessTokenDO">
 | 
				
			||||||
 | 
					        SELECT
 | 
				
			||||||
 | 
					          id, valid, expires_time
 | 
				
			||||||
 | 
					        FROM oauth2_access_token
 | 
				
			||||||
 | 
					        WHERE token_id = #{tokenId}
 | 
				
			||||||
 | 
					    </select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</mapper>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					<?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="cn.iocoder.mall.user.dao.OAuth2RefreshTokenMapper">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <insert id="insert" parameterType="OAuth2RefreshTokenDO">
 | 
				
			||||||
 | 
					        INSERT INTO oauth2_refresh_token (
 | 
				
			||||||
 | 
					          token_id, id, valid, expires_time, create_time
 | 
				
			||||||
 | 
					        ) VALUES (
 | 
				
			||||||
 | 
					          #{tokenId}, #{id}, #{valid}, #{expiresTime}, #{createTime}
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    </insert>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</mapper>
 | 
				
			||||||
| 
						 | 
					@ -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="cn.iocoder.mall.user.dao.UserMapper">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <insert id="insert" parameterType="UserDO" useGeneratedKeys="true" keyProperty="id">
 | 
				
			||||||
 | 
					        INSERT INTO users (
 | 
				
			||||||
 | 
					          id, mobile, create_time
 | 
				
			||||||
 | 
					        ) VALUES (
 | 
				
			||||||
 | 
					          #{id}, #{mobile}, #{createTime}
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    </insert>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <select id="selectByMobile" parameterType="String" resultType="UserDO">
 | 
				
			||||||
 | 
					      SELECT
 | 
				
			||||||
 | 
					          id, mobile
 | 
				
			||||||
 | 
					      FROM users
 | 
				
			||||||
 | 
					      WHERE mobile = #{mobile}
 | 
				
			||||||
 | 
					    </select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</mapper>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					<?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="cn.iocoder.mall.user.dao.UserRegisterMapper">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <insert id="insert" parameterType="UserRegisterDO">
 | 
				
			||||||
 | 
					        INSERT INTO user_register (
 | 
				
			||||||
 | 
					          id, create_time
 | 
				
			||||||
 | 
					        ) VALUES (
 | 
				
			||||||
 | 
					          #{id}, #{createTime}
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    </insert>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</mapper>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8" ?>
 | 
				
			||||||
 | 
					<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
 | 
				
			||||||
 | 
					<configuration>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <settings>
 | 
				
			||||||
 | 
					        <!-- 使用驼峰命名法转换字段。 -->
 | 
				
			||||||
 | 
					        <setting name="mapUnderscoreToCamelCase" value="true"/>
 | 
				
			||||||
 | 
					    </settings>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <typeAliases>
 | 
				
			||||||
 | 
					        <typeAlias alias="Integer" type="java.lang.Integer"/>
 | 
				
			||||||
 | 
					        <typeAlias alias="Long" type="java.lang.Long"/>
 | 
				
			||||||
 | 
					        <typeAlias alias="HashMap" type="java.util.HashMap"/>
 | 
				
			||||||
 | 
					        <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap"/>
 | 
				
			||||||
 | 
					        <typeAlias alias="ArrayList" type="java.util.ArrayList"/>
 | 
				
			||||||
 | 
					        <typeAlias alias="LinkedList" type="java.util.LinkedList"/>
 | 
				
			||||||
 | 
					    </typeAliases>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</configuration>
 | 
				
			||||||
		Loading…
	
		Reference in New Issue