diff --git a/.gitignore b/.gitignore index 08c97607f..3a7404079 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ *.iws *.iml *.ipr +target/* ### NetBeans ### /nbproject/private/ diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/config/GlobalExceptionHandler.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/config/GlobalExceptionHandler.java index fed118e8d..3e3123e24 100644 --- a/common/common-framework/src/main/java/cn/iocoder/common/framework/config/GlobalExceptionHandler.java +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/config/GlobalExceptionHandler.java @@ -2,6 +2,7 @@ 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.util.ExceptionUtil; import cn.iocoder.common.framework.vo.RestResult; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ControllerAdvice; @@ -9,7 +10,6 @@ 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 @@ -21,19 +21,13 @@ public class GlobalExceptionHandler { 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); - } + ServiceException serviceException = ExceptionUtil.getServiceException(e); + if (serviceException != null) { + return serviceExceptionHandler(req, serviceException); } // 获得不到,使用 异常日志 方法处理。 return resultExceptionHandler(req, e); diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/config/GlobalResponseBodyAdvice.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/config/GlobalResponseBodyAdvice.java index decfcc14e..7c55e1bb5 100644 --- a/common/common-framework/src/main/java/cn/iocoder/common/framework/config/GlobalResponseBodyAdvice.java +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/config/GlobalResponseBodyAdvice.java @@ -1,5 +1,6 @@ package cn.iocoder.common.framework.config; +import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.common.framework.vo.RestResult; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; @@ -21,6 +22,9 @@ public class GlobalResponseBodyAdvice implements ResponseBodyAdvice { if (body instanceof RestResult) { return body; } + if (body instanceof CommonResult) { // TODO 芋艿,后续要改下 + return body; + } return RestResult.ok(body); } diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ExceptionUtil.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ExceptionUtil.java new file mode 100644 index 000000000..02f9af696 --- /dev/null +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ExceptionUtil.java @@ -0,0 +1,34 @@ +package cn.iocoder.common.framework.util; + +import cn.iocoder.common.framework.exception.ServiceException; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; + +public class ExceptionUtil { + + public static ServiceException getServiceException(Exception e) { + if (e instanceof UndeclaredThrowableException) { + return getServiceException((UndeclaredThrowableException) e); + } + return null; + } + + // 处理 Spring 动态代理调用时,发生 UndeclaredThrowableException 的情况。 + // 不了解的胖友,可以先看看 https://segmentfault.com/a/1190000012262244 文章 + // 原因是: + // 1. Dubbo 动态代理 Wrapper 会将抛出的异常,包装成 InvocationTargetException 异常 + // 2. Spring AOP 发现是 InvocationTargetException 异常是非方法定义的异常,则会包装成 UndeclaredThrowableException 异常。 + public static ServiceException getServiceException(UndeclaredThrowableException e) { + Throwable undeclaredThrowable = e.getUndeclaredThrowable(); + if (undeclaredThrowable instanceof InvocationTargetException) { + InvocationTargetException invocationTargetException = (InvocationTargetException) undeclaredThrowable; + Throwable targetException = invocationTargetException.getTargetException(); + if (targetException != null & targetException instanceof ServiceException) { + return (ServiceException) targetException; + } + } + return null; + } + +} \ No newline at end of file diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ServiceExceptionUtil.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ServiceExceptionUtil.java index d4db96532..d26800cf7 100644 --- a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ServiceExceptionUtil.java +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ServiceExceptionUtil.java @@ -1,6 +1,7 @@ package cn.iocoder.common.framework.util; import cn.iocoder.common.framework.exception.ServiceException; +import cn.iocoder.common.framework.vo.CommonResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,6 +39,16 @@ public class ServiceExceptionUtil { ServiceExceptionUtil.messages.put(code, message); } + // TODO 芋艿,可能不是目前最优解,目前暂时这样 + public static CommonResult error(Integer code) { + return CommonResult.error(code, messages.get(code)); + } + + public static CommonResult error(Integer code, Object... params) { + String message = doFormat(code, messages.get(code), params); + return CommonResult.error(code, message); + } + /** * 创建指定编号的 ServiceException 的异常 * diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/CommonResult.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/CommonResult.java new file mode 100644 index 000000000..6e13134ce --- /dev/null +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/CommonResult.java @@ -0,0 +1,83 @@ +package cn.iocoder.common.framework.vo; + +import org.springframework.util.Assert; + +public class CommonResult { + + public static Integer CODE_SUCCESS = 0; + + /** + * 错误码 + */ + private Integer code; + /** + * 错误提示 + */ + private String message; + /** + * 返回数据 + */ + private T data; + + /** + * 将传入的 result 对象,转换成另外一个泛型结果的对象 + * + * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。 + * + * @param result 传入的 result 对象 + * @param 返回的泛型 + * @return 新的 CommonResult 对象 + */ + public static CommonResult error(CommonResult result) { + return error(result.getCode(), result.getMessage()); + } + + public static CommonResult error(Integer code, String message) { + Assert.isTrue(!CODE_SUCCESS.equals(code), "code 必须是错误的!"); + CommonResult result = new CommonResult<>(); + result.code = code; + result.message = message; + return result; + } + + public static CommonResult success(T data) { + CommonResult result = new CommonResult<>(); + result.code = CODE_SUCCESS; + result.data = data; + result.message = ""; + return result; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public boolean isSuccess() { + return CODE_SUCCESS.equals(code); + } + + public boolean isError() { + return !isSuccess(); + } + +} \ No newline at end of file diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/RestResult.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/RestResult.java index 5e527b33d..813af6b80 100644 --- a/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/RestResult.java +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/RestResult.java @@ -53,4 +53,5 @@ public class RestResult { public void setData(Object data) { this.data = data; } + } \ No newline at end of file diff --git a/user/user-application/pom.xml b/user/user-application/pom.xml index 8e725f866..8e0070b11 100644 --- a/user/user-application/pom.xml +++ b/user/user-application/pom.xml @@ -92,6 +92,12 @@ compile + + org.mapstruct + mapstruct + ${org.mapstruct.version} + + diff --git a/user/user-application/src/main/java/cn/iocoder/mall/user/controller/PassportController.java b/user/user-application/src/main/java/cn/iocoder/mall/user/controller/PassportController.java index d77e00f1d..856dfe4ca 100644 --- a/user/user-application/src/main/java/cn/iocoder/mall/user/controller/PassportController.java +++ b/user/user-application/src/main/java/cn/iocoder/mall/user/controller/PassportController.java @@ -1,12 +1,14 @@ package cn.iocoder.mall.user.controller; import cn.iocoder.common.framework.exception.ServiceException; +import cn.iocoder.common.framework.util.ExceptionUtil; +import cn.iocoder.common.framework.vo.CommonResult; 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.bo.OAuth2AccessTokenBO; 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; @@ -35,7 +37,7 @@ public class PassportController { * 手机号 + 验证码登陆 * * @param mobile 手机号 - * @param code 验证码 + * @param code 验证码 * @return 授权信息 */ @PermitAll @@ -47,7 +49,11 @@ public class PassportController { try { accessTokenDTO = oauth2Service.getAccessToken(mobile, code); return accessTokenDTO; - } catch (ServiceException serviceException) { + } catch (Exception ex) { + ServiceException serviceException = ExceptionUtil.getServiceException(ex); + if (serviceException == null) { + throw ex; + } if (!serviceException.getCode().equals(UserErrorCodeEnum.USER_MOBILE_NOT_REGISTERED.getCode())) { // 如果是未注册异常,忽略。下面发起自动注册逻辑。 throw serviceException; } @@ -55,7 +61,11 @@ public class PassportController { // 上面尝试授权失败,说明用户未注册,发起自动注册。 try { userService.createUser(mobile, code); - } catch (ServiceException serviceException) { + } catch (Exception ex) { + ServiceException serviceException = ExceptionUtil.getServiceException(ex); + if (serviceException == null) { + throw ex; + } if (!serviceException.getCode().equals(UserErrorCodeEnum.USER_MOBILE_ALREADY_REGISTERED.getCode())) { // 如果是已注册异常,忽略。下面再次发起授权 throw serviceException; } @@ -65,11 +75,26 @@ public class PassportController { return accessTokenDTO; } + /** + * 手机号 + 验证码登陆 + * + * @param mobile 手机号 + * @param code 验证码 + * @return 授权信息 + */ + @PermitAll + @PostMapping("/mobile/login2") + public CommonResult mobileRegister2(@RequestParam("mobile") String mobile, + @RequestParam("code") String code) { + return oauth2Service.getAccessToken2(mobile, code); + } + /** * 发送手机验证码 * * @param mobile 手机号 */ + @PermitAll @PostMapping("mobile/send") public void mobileSend(@RequestParam("mobile") String mobile) { mobileCodeService.send(mobile); diff --git a/user/user-application/src/main/java/cn/iocoder/mall/user/controller/UserController.java b/user/user-application/src/main/java/cn/iocoder/mall/user/controller/UserController.java index 9c53ed6a5..4caf39635 100644 --- a/user/user-application/src/main/java/cn/iocoder/mall/user/controller/UserController.java +++ b/user/user-application/src/main/java/cn/iocoder/mall/user/controller/UserController.java @@ -1,16 +1,18 @@ package cn.iocoder.mall.user.controller; +import cn.iocoder.mall.user.sdk.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; -//@RestController -//@RequestMapping("/user") +@RestController +@RequestMapping("/user") public class UserController { @GetMapping("/info") public Long info() { // TODO 芋艿,正在实现中 -// return SecurityContextHolder.getContext().getUid(); - return null; + return SecurityContextHolder.getContext().getUid(); } } \ No newline at end of file diff --git a/user/user-sdk/src/main/java/cn/iocoder/mall/user/sdk/interceptor/SecurityInterceptor.java b/user/user-sdk/src/main/java/cn/iocoder/mall/user/sdk/interceptor/SecurityInterceptor.java index c207a4d41..f2a6db8ab 100644 --- a/user/user-sdk/src/main/java/cn/iocoder/mall/user/sdk/interceptor/SecurityInterceptor.java +++ b/user/user-sdk/src/main/java/cn/iocoder/mall/user/sdk/interceptor/SecurityInterceptor.java @@ -5,7 +5,7 @@ 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 cn.iocoder.mall.user.service.api.bo.OAuth2AuthenticationBO; import com.alibaba.dubbo.config.annotation.Reference; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -29,7 +29,7 @@ public class SecurityInterceptor extends HandlerInterceptorAdapter { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 校验访问令牌是否正确。若正确,返回授权信息 String accessToken = obtainAccess(request); - OAuth2AuthenticationDTO authentication = null; + OAuth2AuthenticationBO authentication = null; if (accessToken != null) { authentication = oauth2Service.checkToken(accessToken); // 添加到 SecurityContext diff --git a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/OAuth2Service.java b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/OAuth2Service.java index c36aafef5..7cd568291 100644 --- a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/OAuth2Service.java +++ b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/OAuth2Service.java @@ -2,8 +2,9 @@ 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; +import cn.iocoder.common.framework.vo.CommonResult; +import cn.iocoder.mall.user.service.api.bo.OAuth2AccessTokenBO; +import cn.iocoder.mall.user.service.api.bo.OAuth2AuthenticationBO; public interface OAuth2Service { @@ -19,13 +20,15 @@ public interface OAuth2Service { OAuth2AccessTokenBO getAccessToken(String mobile, String code) throws ServiceException; + CommonResult getAccessToken2(String mobile, String code); + /** * 校验访问令牌,获取身份信息( 不包括 accessToken 等等 ) * * @param accessToken 访问令牌 * @return 授权信息 */ - OAuth2AuthenticationDTO checkToken(String accessToken) + OAuth2AuthenticationBO checkToken(String accessToken) throws ServiceException; // @see 刷新 token diff --git a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/UserService.java b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/UserService.java index ceeccb715..bbd479d59 100644 --- a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/UserService.java +++ b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/UserService.java @@ -1,17 +1,19 @@ package cn.iocoder.mall.user.service.api; import cn.iocoder.common.framework.exception.ServiceException; -import cn.iocoder.mall.user.service.api.dto.UserDTO; +import cn.iocoder.mall.user.service.api.bo.UserBO; public interface UserService { /** * 创建用户。一般在用户注册时,调用该方法 * + * TODO 芋艿,此处要传递一些用户注册时的相关信息,例如说 ip、ua、客户端来源等等。用于数据分析、风控等等。 + * * @param mobile 手机号 * @param code 手机验证码 * @return 用户 */ - UserDTO createUser(String mobile, String code) throws ServiceException; + UserBO createUser(String mobile, String code) throws ServiceException; } \ No newline at end of file diff --git a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/OAuth2AccessTokenBO.java b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/bo/OAuth2AccessTokenBO.java similarity index 95% rename from user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/OAuth2AccessTokenBO.java rename to user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/bo/OAuth2AccessTokenBO.java index 9723ff6d2..d192a4d6f 100644 --- a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/OAuth2AccessTokenBO.java +++ b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/bo/OAuth2AccessTokenBO.java @@ -1,4 +1,4 @@ -package cn.iocoder.mall.user.service.api.dto; +package cn.iocoder.mall.user.service.api.bo; import java.io.Serializable; diff --git a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/OAuth2AuthenticationDTO.java b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/bo/OAuth2AuthenticationBO.java similarity index 54% rename from user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/OAuth2AuthenticationDTO.java rename to user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/bo/OAuth2AuthenticationBO.java index ca9990b91..8c649b730 100644 --- a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/OAuth2AuthenticationDTO.java +++ b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/bo/OAuth2AuthenticationBO.java @@ -1,8 +1,8 @@ -package cn.iocoder.mall.user.service.api.dto; +package cn.iocoder.mall.user.service.api.bo; import java.io.Serializable; -public class OAuth2AuthenticationDTO implements Serializable { +public class OAuth2AuthenticationBO implements Serializable { /** * 用户编号 @@ -13,7 +13,7 @@ public class OAuth2AuthenticationDTO implements Serializable { return uid; } - public OAuth2AuthenticationDTO setUid(Long uid) { + public OAuth2AuthenticationBO setUid(Long uid) { this.uid = uid; return this; } diff --git a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/UserDTO.java b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/bo/UserBO.java similarity index 69% rename from user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/UserDTO.java rename to user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/bo/UserBO.java index f331fd0ac..c28bb8d40 100644 --- a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/UserDTO.java +++ b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/bo/UserBO.java @@ -1,6 +1,6 @@ -package cn.iocoder.mall.user.service.api.dto; +package cn.iocoder.mall.user.service.api.bo; -public class UserDTO { +public class UserBO { /** * 用户编号 @@ -15,7 +15,7 @@ public class UserDTO { return uid; } - public UserDTO setUid(Long uid) { + public UserBO setUid(Long uid) { this.uid = uid; return this; } @@ -24,7 +24,7 @@ public class UserDTO { return mobile; } - public UserDTO setMobile(String mobile) { + public UserBO setMobile(String mobile) { this.mobile = mobile; return this; } diff --git a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/MobileCodeDTO.java b/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/MobileCodeDTO.java deleted file mode 100644 index 0b78623b9..000000000 --- a/user/user-service-api/src/main/java/cn/iocoder/mall/user/service/api/dto/MobileCodeDTO.java +++ /dev/null @@ -1,15 +0,0 @@ -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; - } -} \ No newline at end of file diff --git a/user/user-service-impl/pom.xml b/user/user-service-impl/pom.xml index a4675d3a2..78bc287de 100644 --- a/user/user-service-impl/pom.xml +++ b/user/user-service-impl/pom.xml @@ -9,6 +9,10 @@ 4.0.0 + + 1.3.0.Final + + user-service-impl @@ -41,11 +45,31 @@ org.mapstruct mapstruct - 1.3.0.Final - compile + ${org.mapstruct.version} + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + + + + \ No newline at end of file diff --git a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/convert/OAuth2Convert.java b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/convert/OAuth2Convert.java index 5a15dd206..53183f5f1 100644 --- a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/convert/OAuth2Convert.java +++ b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/convert/OAuth2Convert.java @@ -1,21 +1,29 @@ package cn.iocoder.mall.user.convert; import cn.iocoder.mall.user.dataobject.OAuth2AccessTokenDO; -import cn.iocoder.mall.user.service.api.dto.OAuth2AccessTokenBO; +import cn.iocoder.mall.user.service.api.bo.OAuth2AccessTokenBO; +import cn.iocoder.mall.user.service.api.bo.OAuth2AuthenticationBO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; +@Mapper public interface OAuth2Convert { OAuth2Convert INSTANCE = Mappers.getMapper(OAuth2Convert.class); - @Mappings({}) - OAuth2AccessTokenBO convert(OAuth2AccessTokenDO oauth2AccessTokenDO); + @Mappings({ + @Mapping(source = "id", target = "accessToken") + }) + OAuth2AccessTokenBO convertToAccessToken(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; + default OAuth2AccessTokenBO convertToAccessTokenWithExpiresIn(OAuth2AccessTokenDO oauth2AccessTokenDO) { + return this.convertToAccessToken(oauth2AccessTokenDO) + .setExpiresIn(Math.max((int) ((oauth2AccessTokenDO.getExpiresTime().getTime() - System.currentTimeMillis()) / 1000), 0)); } + @Mappings({}) + OAuth2AuthenticationBO convertToAuthentication(OAuth2AccessTokenDO oauth2AccessTokenDO); + } \ No newline at end of file diff --git a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/convert/UserConvert.java b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/convert/UserConvert.java new file mode 100644 index 000000000..b5bb64230 --- /dev/null +++ b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/convert/UserConvert.java @@ -0,0 +1,17 @@ +package cn.iocoder.mall.user.convert; + +import cn.iocoder.mall.user.dataobject.UserDO; +import cn.iocoder.mall.user.service.api.bo.UserBO; +import org.mapstruct.Mapper; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface UserConvert { + + UserConvert INSTANCE = Mappers.getMapper(UserConvert.class); + + @Mappings({}) + UserBO convert(UserDO userDO); + +} \ No newline at end of file diff --git a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/dataobject/OAuth2AccessTokenDO.java b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/dataobject/OAuth2AccessTokenDO.java index 2164fd9c2..77fd16515 100644 --- a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/dataobject/OAuth2AccessTokenDO.java +++ b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/dataobject/OAuth2AccessTokenDO.java @@ -7,7 +7,7 @@ public class OAuth2AccessTokenDO { /** * 访问令牌 */ - private String tokenId; + private String id; /** * 刷新令牌 */ @@ -29,12 +29,12 @@ public class OAuth2AccessTokenDO { */ private Date createTime; - public String getTokenId() { - return tokenId; + public String getId() { + return id; } - public OAuth2AccessTokenDO setTokenId(String tokenId) { - this.tokenId = tokenId; + public OAuth2AccessTokenDO setId(String id) { + this.id = id; return this; } diff --git a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/dataobject/OAuth2RefreshTokenDO.java b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/dataobject/OAuth2RefreshTokenDO.java index 46724ddd2..d63b21524 100644 --- a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/dataobject/OAuth2RefreshTokenDO.java +++ b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/dataobject/OAuth2RefreshTokenDO.java @@ -12,7 +12,7 @@ public class OAuth2RefreshTokenDO { /** * 刷新令牌 */ - private String tokenId; + private String id; /** * 用户编号 */ @@ -30,12 +30,12 @@ public class OAuth2RefreshTokenDO { */ private Date createTime; - public String getTokenId() { - return tokenId; + public String getId() { + return id; } - public OAuth2RefreshTokenDO setTokenId(String tokenId) { - this.tokenId = tokenId; + public OAuth2RefreshTokenDO setId(String id) { + this.id = id; return this; } diff --git a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/MobileCodeServiceImpl.java b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/MobileCodeServiceImpl.java index 75f97cd02..e497a134b 100644 --- a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/MobileCodeServiceImpl.java +++ b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/MobileCodeServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.mall.user.service; import cn.iocoder.common.framework.util.ServiceExceptionUtil; +import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.mall.user.dao.MobileCodeMapper; import cn.iocoder.mall.user.dataobject.MobileCodeDO; import cn.iocoder.mall.user.service.api.MobileCodeService; @@ -63,6 +64,30 @@ public class MobileCodeServiceImpl implements MobileCodeService { return mobileCodePO; } + /** + * 校验手机号的最后一个手机验证码是否有效 + * + * @param mobile 手机号 + * @param code 验证码 + * @return 手机验证码信息 + */ + public CommonResult validLastMobileCode2(String mobile, String code) { + MobileCodeDO mobileCodePO = mobileCodeMapper.selectLast1ByMobile(mobile); + if (mobileCodePO == null) { // 若验证码不存在,抛出异常 + return ServiceExceptionUtil.error(UserErrorCodeEnum.MOBILE_CODE_NOT_FOUND.getCode()); + } + if (System.currentTimeMillis() - mobileCodePO.getCreateTime().getTime() >= codeExpireTimes) { // 验证码已过期 + return ServiceExceptionUtil.error(UserErrorCodeEnum.MOBILE_CODE_EXPIRED.getCode()); + } + if (mobileCodePO.getUsed()) { // 验证码已使用 + return ServiceExceptionUtil.error(UserErrorCodeEnum.MOBILE_CODE_USED.getCode()); + } + if (!mobileCodePO.getCode().equals(code)) { + return ServiceExceptionUtil.error(UserErrorCodeEnum.MOBILE_CODE_NOT_CORRECT.getCode()); + } + return CommonResult.success(mobileCodePO); + } + /** * 更新手机验证码已使用 * diff --git a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/OAuth2ServiceImpl.java b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/OAuth2ServiceImpl.java index 5d8c612d0..7eabd7ca2 100644 --- a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/OAuth2ServiceImpl.java +++ b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/OAuth2ServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.mall.user.service; import cn.iocoder.common.framework.exception.ServiceException; import cn.iocoder.common.framework.util.ServiceExceptionUtil; +import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.mall.user.convert.OAuth2Convert; import cn.iocoder.mall.user.dao.OAuth2AccessTokenMapper; import cn.iocoder.mall.user.dao.OAuth2RefreshTokenMapper; @@ -11,12 +12,13 @@ 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 cn.iocoder.mall.user.service.api.bo.OAuth2AccessTokenBO; +import cn.iocoder.mall.user.service.api.bo.OAuth2AuthenticationBO; 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 org.springframework.util.Assert; import java.util.Date; import java.util.UUID; @@ -61,15 +63,39 @@ public class OAuth2ServiceImpl implements OAuth2Service { // 创建刷新令牌 OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(userDO.getId()); // 创建访问令牌 - OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(userDO.getId(), oauth2RefreshTokenDO.getTokenId()); + OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(userDO.getId(), oauth2RefreshTokenDO.getId()); // 标记已使用 mobileCodeService.useMobileCode(mobileCodeDO.getId(), userDO.getId()); // 转换返回 - return OAuth2Convert.INSTANCE.convertWithExpiresIn(oauth2AccessTokenDO); + return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO); } @Override - public OAuth2AuthenticationDTO checkToken(String accessToken) throws ServiceException { + @Transactional + public CommonResult getAccessToken2(String mobile, String code) { + // 校验传入的 mobile 和 code 是否合法 + CommonResult result = mobileCodeService.validLastMobileCode2(mobile, code); + if (result.isError()) { + return CommonResult.error(result); + } + // 获取用户 + UserDO userDO = userService.getUser(mobile); + if (userDO == null) { // 用户不存在,则进行创建用户 + userDO = userService.createUser(mobile); + Assert.notNull(userDO, "创建用户必然成功"); + } + // 创建刷新令牌 + OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(userDO.getId()); + // 创建访问令牌 + OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(userDO.getId(), oauth2RefreshTokenDO.getId()); + // 标记已使用 +// mobileCodeService.useMobileCode(result.getData().getId(), userDO.getId()); + // 转换返回 + return CommonResult.success(OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO)); + } + + @Override + public OAuth2AuthenticationBO checkToken(String accessToken) throws ServiceException { OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByTokenId(accessToken); if (accessTokenDO == null) { // 不存在 throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_TOKEN_NOT_FOUND.getCode()); @@ -81,11 +107,11 @@ public class OAuth2ServiceImpl implements OAuth2Service { throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_TOKEN_INVALID.getCode()); } // 转换返回 - return new OAuth2AuthenticationDTO().setUid(accessTokenDO.getUid()); + return OAuth2Convert.INSTANCE.convertToAuthentication(accessTokenDO); } private OAuth2AccessTokenDO createOAuth2AccessToken(Long uid, String refreshToken) { - OAuth2AccessTokenDO accessToken = new OAuth2AccessTokenDO().setTokenId(generateAccessToken()) + OAuth2AccessTokenDO accessToken = new OAuth2AccessTokenDO().setId(generateAccessToken()) .setRefreshToken(refreshToken) .setUid(uid) .setExpiresTime(new Date(System.currentTimeMillis() + accessTokenExpireTimeMillis)) @@ -95,7 +121,7 @@ public class OAuth2ServiceImpl implements OAuth2Service { } private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long uid) { - OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setTokenId(generateRefreshToken()) + OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setId(generateRefreshToken()) .setUid(uid) .setExpiresTime(new Date(System.currentTimeMillis() + refreshTokenExpireTimeMillis)) .setValid(true); @@ -111,4 +137,4 @@ public class OAuth2ServiceImpl implements OAuth2Service { return UUID.randomUUID().toString().replaceAll("-", ""); } -} +} \ No newline at end of file diff --git a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/UserServiceImpl.java b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/UserServiceImpl.java index f67d0b787..bd9066caa 100644 --- a/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/UserServiceImpl.java +++ b/user/user-service-impl/src/main/java/cn/iocoder/mall/user/service/UserServiceImpl.java @@ -1,14 +1,14 @@ package cn.iocoder.mall.user.service; import cn.iocoder.common.framework.util.ServiceExceptionUtil; +import cn.iocoder.mall.user.convert.UserConvert; 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 cn.iocoder.mall.user.service.api.bo.UserBO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -34,7 +34,7 @@ public class UserServiceImpl implements UserService { @Override @Transactional - public UserDTO createUser(String mobile, String code) { + public UserBO createUser(String mobile, String code) { // TODO 芋艿,校验手机格式 // 校验手机号的最后一个手机验证码是否有效 mobileCodeService.validLastMobileCode(mobile, code); @@ -48,7 +48,22 @@ public class UserServiceImpl implements UserService { // 插入注册信息 createUserRegister(userDO); // 转换返回 - return new UserDTO().setUid(userDO.getId()); + return UserConvert.INSTANCE.convert(userDO); + } + + @Transactional + public UserDO createUser(String mobile) { + // 校验用户是否已经存在 + 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 userDO; } private void createUserRegister(UserDO userDO) { diff --git a/user/user-service-impl/src/main/resources/mapper/OAuth2AccessTokenMapper.xml b/user/user-service-impl/src/main/resources/mapper/OAuth2AccessTokenMapper.xml index 4ded75083..d942e9ed3 100644 --- a/user/user-service-impl/src/main/resources/mapper/OAuth2AccessTokenMapper.xml +++ b/user/user-service-impl/src/main/resources/mapper/OAuth2AccessTokenMapper.xml @@ -4,10 +4,10 @@ INSERT INTO oauth2_access_token ( - token_id, refresh_token, id, valid, expires_time, + id, refresh_token, uid, valid, expires_time, create_time ) VALUES ( - #{tokenId}, #{refreshToken}, #{id}, #{valid}, #{expiresTime}, + #{id}, #{refreshToken}, #{uid}, #{valid}, #{expiresTime}, #{createTime} ) @@ -16,7 +16,7 @@ SELECT id, valid, expires_time FROM oauth2_access_token - WHERE token_id = #{tokenId} + WHERE token_id = #{id} \ No newline at end of file diff --git a/user/user-service-impl/src/main/resources/mapper/OAuth2RefreshTokenMapper.xml b/user/user-service-impl/src/main/resources/mapper/OAuth2RefreshTokenMapper.xml index 117ee94ba..3d9277070 100644 --- a/user/user-service-impl/src/main/resources/mapper/OAuth2RefreshTokenMapper.xml +++ b/user/user-service-impl/src/main/resources/mapper/OAuth2RefreshTokenMapper.xml @@ -4,9 +4,9 @@ INSERT INTO oauth2_refresh_token ( - token_id, id, valid, expires_time, create_time + id, uid, valid, expires_time, create_time ) VALUES ( - #{tokenId}, #{id}, #{valid}, #{expiresTime}, #{createTime} + #{id}, #{uid}, #{valid}, #{expiresTime}, #{createTime} )