From f3da2519605c1a467c35df372af8389829ea24b7 Mon Sep 17 00:00:00 2001 From: xc-yjs Date: Wed, 31 Jul 2024 18:28:04 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=20=E6=9B=B4=E6=96=B0=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nla-common/pom.xml | 95 ++++++++------ .../cn/nla/common/annotation/EncryptId.java | 28 ++++ .../nla/common/annotation/ResponseResult.java | 20 +++ .../nla/common/config/EncryptIdValidator.java | 23 ++++ .../common/config/SwaggerConfiguration.java | 82 ++++++++++++ .../java/cn/nla/common/config/WebConfig.java | 20 +++ .../java/cn/nla/common/enums/BizCodeEnum.java | 88 +++++++++++++ .../cn/nla/common/exception/BizException.java | 22 ++++ .../exception/CustomExceptionHandler.java | 124 ++++++++++++++++++ .../ResponseResultInterceptor.java | 35 +++++ .../java/cn/nla/common/util/CheckUtil.java | 35 +++++ .../java/cn/nla/common/util/CommonUtil.java | 92 +++++++++++++ .../java/cn/nla/common/util/JsonData.java | 59 +++++++++ nla-user-service/pom.xml | 20 +++ .../java/cn/nla/user/UserApplication.java | 2 + .../cn/nla/user/config/CaptchaConfig.java | 48 +++++++ .../java/cn/nla/user/config/OSSConfig.java | 15 +++ .../user/controller/AddressController.java | 22 +++- .../nla/user/controller/FileController.java | 23 ++++ .../nla/user/controller/NotifyController.java | 112 ++++++++++++++++ .../src/main/java/cn/nla/user/goup/Save.java | 6 + .../main/java/cn/nla/user/goup/Update.java | 7 + .../java/cn/nla/user/model/StudentBean.java | 32 +++++ .../java/cn/nla/user/model/TeacherBean.java | 12 ++ .../java/cn/nla/user/service/FileService.java | 8 ++ .../java/cn/nla/user/service/MailService.java | 6 + .../user/service/impl/FileServiceImpl.java | 55 ++++++++ .../user/service/impl/MailServiceImpl.java | 47 +++++++ .../src/main/resources/application.yml | 34 ++++- .../src/main/resources/logback.xml | 71 ++++++++++ .../src/test/java/AddressTest.java | 26 ++++ pom.xml | 6 + 32 files changed, 1227 insertions(+), 48 deletions(-) create mode 100644 nla-common/src/main/java/cn/nla/common/annotation/EncryptId.java create mode 100644 nla-common/src/main/java/cn/nla/common/annotation/ResponseResult.java create mode 100644 nla-common/src/main/java/cn/nla/common/config/EncryptIdValidator.java create mode 100644 nla-common/src/main/java/cn/nla/common/config/SwaggerConfiguration.java create mode 100644 nla-common/src/main/java/cn/nla/common/config/WebConfig.java create mode 100644 nla-common/src/main/java/cn/nla/common/enums/BizCodeEnum.java create mode 100644 nla-common/src/main/java/cn/nla/common/exception/BizException.java create mode 100644 nla-common/src/main/java/cn/nla/common/exception/CustomExceptionHandler.java create mode 100644 nla-common/src/main/java/cn/nla/common/interceptor/ResponseResultInterceptor.java create mode 100644 nla-common/src/main/java/cn/nla/common/util/CheckUtil.java create mode 100644 nla-common/src/main/java/cn/nla/common/util/CommonUtil.java create mode 100644 nla-common/src/main/java/cn/nla/common/util/JsonData.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/config/CaptchaConfig.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/config/OSSConfig.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/controller/FileController.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/controller/NotifyController.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/goup/Save.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/goup/Update.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/model/StudentBean.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/model/TeacherBean.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/service/FileService.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/service/MailService.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/service/impl/FileServiceImpl.java create mode 100644 nla-user-service/src/main/java/cn/nla/user/service/impl/MailServiceImpl.java create mode 100644 nla-user-service/src/main/resources/logback.xml create mode 100644 nla-user-service/src/test/java/AddressTest.java diff --git a/nla-common/pom.xml b/nla-common/pom.xml index 0467dff..7f3f23b 100644 --- a/nla-common/pom.xml +++ b/nla-common/pom.xml @@ -15,42 +15,63 @@ 11 11 - - - org.projectlombok - lombok - - - - org.springframework.boot - spring-boot-starter-web - - - mysql - mysql-connector-java - - - com.baomidou - mybatis-plus-boot-starter - - - - com.baomidou - mybatis-plus-generator - 3.4.1 - - - - org.apache.velocity - velocity-engine-core - 2.0 - - - - - io.springfox - springfox-boot-starter - - + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-starter-web + + + + org.hibernate + hibernate-validator + 6.0.1.Final + + + mysql + mysql-connector-java + + + com.baomidou + mybatis-plus-boot-starter + + + + com.baomidou + mybatis-plus-generator + 3.4.1 + + + + org.apache.velocity + velocity-engine-core + 2.0 + + + + + io.springfox + springfox-boot-starter + + + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + + + redis.clients + jedis + + diff --git a/nla-common/src/main/java/cn/nla/common/annotation/EncryptId.java b/nla-common/src/main/java/cn/nla/common/annotation/EncryptId.java new file mode 100644 index 0000000..2ff5f27 --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/annotation/EncryptId.java @@ -0,0 +1,28 @@ +package cn.nla.common.annotation; + +import cn.nla.common.config.EncryptIdValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 自定义加密校验 + */ +@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {EncryptIdValidator.class}) +public @interface EncryptId { + // 默认错误消息 + String message() default "加密id格式错误"; + // 分组 + Class[] groups() default {}; + // 负载 + Class[] payload() default {}; +} diff --git a/nla-common/src/main/java/cn/nla/common/annotation/ResponseResult.java b/nla-common/src/main/java/cn/nla/common/annotation/ResponseResult.java new file mode 100644 index 0000000..49715f8 --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/annotation/ResponseResult.java @@ -0,0 +1,20 @@ +package cn.nla.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + + +/** + * 该注解作业于类或者方法上,将返回值对象包装返回体结构 + */ +@Retention(RUNTIME) +@Target({TYPE, METHOD}) +@Documented +public @interface ResponseResult { + +} diff --git a/nla-common/src/main/java/cn/nla/common/config/EncryptIdValidator.java b/nla-common/src/main/java/cn/nla/common/config/EncryptIdValidator.java new file mode 100644 index 0000000..7151bee --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/config/EncryptIdValidator.java @@ -0,0 +1,23 @@ +package cn.nla.common.config; + +import cn.nla.common.annotation.EncryptId; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +/** + * 自定义加密校验的方法 + */ +public class EncryptIdValidator implements ConstraintValidator { + // 字符串的长度: 32~256,以字母a到f或数字0到9开头。 + private static final Pattern PATTERN = Pattern.compile("^[a-f\\d]{32,256}$"); + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + // 不为null才进行校验 + if (value != null) { + Matcher matcher = PATTERN.matcher(value); + return matcher.find(); + } + return true; + } +} diff --git a/nla-common/src/main/java/cn/nla/common/config/SwaggerConfiguration.java b/nla-common/src/main/java/cn/nla/common/config/SwaggerConfiguration.java new file mode 100644 index 0000000..3e038fb --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/config/SwaggerConfiguration.java @@ -0,0 +1,82 @@ +package cn.nla.common.config; + +import lombok.Data; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import springfox.documentation.builders.*; +import springfox.documentation.oas.annotations.EnableOpenApi; +import springfox.documentation.schema.ScalarType; +import springfox.documentation.service.*; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +import java.util.List; + +/** + * Swagger配置 + **/ +@Data +@Component +@EnableOpenApi +public class SwaggerConfiguration { + + /** + * 对用户服务端的接口文档 + */ + @Bean + public Docket userApiDoc() { + return new Docket(DocumentationType.OAS_30) // 版本3.0 + .groupName("用户端接口文档") + .pathMapping("/") + //定义是否开启Swagger,false是关闭,可以通过变量去控制,线上关闭 + .enable(true) + //配置文档的元信息 + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("cn.nla")) + //正则匹配请求路径,并分配到当前项目组 + .paths(PathSelectors.ant("/user/**")) + .build() + // 新版SwaggerUI3.0 + .globalRequestParameters(globalRequestParameters()) + .globalResponses(HttpMethod.GET, getGlobalResponseMessage()) + .globalResponses(HttpMethod.POST, getGlobalResponseMessage()); + } + + + /** + * 接口基本信息配置 + */ + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("电商平台") + .description("微服务接口文档") + .contact(new Contact("yuan", "http://localhost", "yuanjs625@163.com")) + .version("v1.0") + .build(); + } + + /** + * 配置全局通用参数 + */ + private List globalRequestParameters() { + return List.of(new RequestParameterBuilder() + .name("token") + .description("登录令牌") + .in(ParameterType.HEADER) + .query(q -> q.model(m -> m.scalarModel(ScalarType.STRING))) + .required(false) + .build()); + } + + /** + * 生成通用的响应信息 + */ + private List getGlobalResponseMessage() { + return List.of(new ResponseBuilder() + .code("4xx") + .description("请求错误,根据code和msg检查") + .build()); + } +} diff --git a/nla-common/src/main/java/cn/nla/common/config/WebConfig.java b/nla-common/src/main/java/cn/nla/common/config/WebConfig.java new file mode 100644 index 0000000..4d6f8ff --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/config/WebConfig.java @@ -0,0 +1,20 @@ +package cn.nla.common.config; + +import cn.nla.common.interceptor.ResponseResultInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import javax.annotation.Resource; + +/** + * 注册拦截器 + */ +@Configuration +public class WebConfig implements WebMvcConfigurer { + @Resource + private ResponseResultInterceptor responseResultInterceptor; + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(responseResultInterceptor); + } +} diff --git a/nla-common/src/main/java/cn/nla/common/enums/BizCodeEnum.java b/nla-common/src/main/java/cn/nla/common/enums/BizCodeEnum.java new file mode 100644 index 0000000..65b7e65 --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/enums/BizCodeEnum.java @@ -0,0 +1,88 @@ +package cn.nla.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum BizCodeEnum { + + /** + * 通用操作码 + */ + OPS_REPEAT(110001,"重复操作"), + /** + * 系统相关 + */ + SYS_LOGIN(210001,"登录过期,请重新登录"), + SYS_NO_TOKEN(210002,"token不存在,请重新登录"), + SYS_NO_USER(210003,"loginUser对象为空"), + /** + * 购物车 + */ + CART_FAIL(220001,"添加购物车失败"), + /** + *验证码 + */ + CODE_TO_ERROR(240001,"接收号码不合规"), + CODE_LIMITED(240002,"验证码发送过快"), + CODE_ERROR(240003,"验证码错误"), + CODE_CAPTCHA_ERROR(240101,"图形验证码错误"), + + /** + * 账号 + */ + ACCOUNT_REPEAT(250001,"账号已经存在"), + ACCOUNT_UNREGISTER(250002,"账号不存在"), + ACCOUNT_PWD_ERROR(250003,"账号或者密码错误"), + ACCOUNT_UNLOGIN(250004,"账号未登录"), + /** + * 优惠券 + */ + COUPON_CONDITION_ERROR(270001,"优惠券条件错误"), + COUPON_UNAVAILABLE(270002,"没有可用的优惠券"), + COUPON_NO_EXITS(270003,"优惠券不存在"), + COUPON_NO_STOCK(270005,"优惠券库存不足"), + COUPON_OUT_OF_LIMIT(270006,"优惠券领取超过限制次数"), + COUPON_OUT_OF_TIME(270407,"优惠券不在领取时间范围"), + COUPON_GET_FAIL(270407,"优惠券领取失败"), + COUPON_RECORD_LOCK_FAIL(270409,"优惠券锁定失败"), + /** + * 订单 + */ + ORDER_CONFIRM_COUPON_FAIL(280001,"创建订单-优惠券使用失败,不满足价格条件"), + ORDER_CONFIRM_PRICE_FAIL(280002,"创建订单-验价失败"), + ORDER_CONFIRM_LOCK_PRODUCT_FAIL(280003,"创建订单-商品库存不足锁定失败"), + ORDER_CONFIRM_ADD_STOCK_TASK_FAIL(280004,"创建订单-新增商品库存锁定任务"), + ORDER_CONFIRM_TOKEN_NOT_EXIST(280008,"订单令牌缺少"), + ORDER_CONFIRM_TOKEN_EQUAL_FAIL(280009,"订单令牌不正确"), + ORDER_CONFIRM_NOT_EXIST(280010,"订单不存在"), + ORDER_CONFIRM_CART_ITEM_NOT_EXIST(280011,"购物车商品项不存在"), + /** + * 收货地址 + */ + ADDRESS_ADD_FAIL(290001,"新增收货地址失败"), + ADDRESS_DEL_FAIL(290002,"删除收货地址失败"), + ADDRESS_NO_EXITS(290003,"地址不存在"), + /** + * 支付 + */ + PAY_ORDER_FAIL(300001,"创建支付订单失败"), + PAY_ORDER_CALLBACK_SIGN_FAIL(300002,"支付订单回调验证签失败"), + PAY_ORDER_CALLBACK_NOT_SUCCESS(300003,"创建支付订单失败"), + PAY_ORDER_NOT_EXIST(300005,"订单不存在"), + PAY_ORDER_STATE_ERROR(300006,"订单状态不正常"), + PAY_ORDER_PAY_TIMEOUT(300007,"订单支付超时"), + /** + * 流控操作 + */ + CONTROL_FLOW(500101,"限流控制"), + CONTROL_DEGRADE(500201,"降级控制"), + CONTROL_AUTH(500301,"认证控制"), + /** + * 文件相关 + */ + FILE_UPLOAD_USER_IMG_FAIL(600101,"用户头像文件上传失败"); + private int code; + private String message; +} diff --git a/nla-common/src/main/java/cn/nla/common/exception/BizException.java b/nla-common/src/main/java/cn/nla/common/exception/BizException.java new file mode 100644 index 0000000..cc37d9f --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/exception/BizException.java @@ -0,0 +1,22 @@ +package cn.nla.common.exception; + +import cn.nla.common.enums.BizCodeEnum; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class BizException extends RuntimeException { + private int code; + private String msg; + public BizException(int code, String msg){ + super(msg); + this.code = code; + this.msg = msg; + } + public BizException(BizCodeEnum bizCodeEnum){ + super(bizCodeEnum.getMessage()); + this.code = bizCodeEnum.getCode(); + this.msg = bizCodeEnum.getMessage(); + } +} diff --git a/nla-common/src/main/java/cn/nla/common/exception/CustomExceptionHandler.java b/nla-common/src/main/java/cn/nla/common/exception/CustomExceptionHandler.java new file mode 100644 index 0000000..3cce007 --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/exception/CustomExceptionHandler.java @@ -0,0 +1,124 @@ +package cn.nla.common.exception; + +import cn.nla.common.annotation.ResponseResult; +import cn.nla.common.util.JsonData; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +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 org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintViolationException; + +@Slf4j +@ControllerAdvice +public class CustomExceptionHandler implements ResponseBodyAdvice { + @Override + public boolean supports(MethodParameter methodParameter, Class> aClass) { + ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (sra == null) { + return false; + } + HttpServletRequest request = sra.getRequest(); + ResponseResult responseResultAnn = (ResponseResult) request.getAttribute("RESPONSE_RESULT_ANN"); + return responseResultAnn != null; + } + + @Override + public Object beforeBodyWrite(Object body, MethodParameter methodParameter, + MediaType mediaType, Class> aClass, + ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { + log.info("into ResponseResult handle ...."); + if (body instanceof JsonData) { + return body; + } + return JsonData.buildSuccess(body); + } + + + @ExceptionHandler(value = Exception.class) + @ResponseBody + public JsonData handle(Exception e) { + //是不是自定义异常 + if (e instanceof BizException) { + BizException bizException = (BizException) e; + log.error("[业务异常]", e); + return JsonData.buildCodeAndMsg(bizException.getCode(), bizException.getMsg()); + } else { + log.error("[系统异常]", e); + return JsonData.buildError("全局异常,未知错误"); + } + } + + /** + * 忽略参数异常处理器 + * + * @param e 忽略参数异常 + */ + //@ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(MissingServletRequestParameterException.class) + @ResponseBody + public JsonData parameterMissingExceptionHandler(MissingServletRequestParameterException e) { + log.error("参数异常", e); + return JsonData.buildError("请求参数[" + e.getParameterName() + "]不能为空"); + } + + /** + * 缺少请求体异常处理器 + * + * @param e 缺少请求体异常 + */ + //@ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(HttpMessageNotReadableException.class) + @ResponseBody + public JsonData parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) { + log.error("缺少请求体异常", e); + return JsonData.buildError("参数体不能为空"); + } + + /** + * 参数效验异常处理器 + * + * @param e 参数验证异常 + */ + //@ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseBody + public JsonData parameterExceptionHandler(MethodArgumentNotValidException e) { + log.error("参数效验异常", e); + BindingResult bindingResult = e.getBindingResult(); + StringBuilder sb = new StringBuilder("校验失败: "); + for (FieldError fieldError : bindingResult.getFieldErrors()) { +// sb.append(fieldError.getDefaultMessage()).append(", "); + sb.append("[").append(fieldError.getField()).append("]").append(fieldError.getDefaultMessage()).append(", "); + } + return JsonData.buildError(sb.toString()); + } + + /** + * 自定义校验 + * + * @param e 参数验证异常 + */ + @ExceptionHandler({ConstraintViolationException.class}) + @ResponseBody + public JsonData handleConstraintViolationException(ConstraintViolationException e) { + log.error("自定义校验异常", e); + return JsonData.buildError(e.getMessage()); + } + + +} diff --git a/nla-common/src/main/java/cn/nla/common/interceptor/ResponseResultInterceptor.java b/nla-common/src/main/java/cn/nla/common/interceptor/ResponseResultInterceptor.java new file mode 100644 index 0000000..92e7a5e --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/interceptor/ResponseResultInterceptor.java @@ -0,0 +1,35 @@ +package cn.nla.common.interceptor; + +import cn.nla.common.annotation.ResponseResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; + +/** + * 请求拦截,封装响应对象 + */ +@Slf4j +@Component +public class ResponseResultInterceptor implements HandlerInterceptor { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + if (handler instanceof HandlerMethod) { + final HandlerMethod handlerMethod = (HandlerMethod) handler; + final Class clazz = handlerMethod.getBeanType(); + final Method method = handlerMethod.getMethod(); + if (clazz.isAnnotationPresent(ResponseResult.class)) { + // 设置此请求返回体,需要包装,往下传递,在ResponseBodyAdvice接口中进行解析 + request.setAttribute("RESPONSE_RESULT_ANN", clazz.getAnnotation(ResponseResult.class)); + } else if (method.isAnnotationPresent(ResponseResult.class)) { + // 设置此请求返回体,需要包装,往下传递,在ResponseBodyAdvice接口中进行解析 + request.setAttribute("RESPONSE_RESULT_ANN", method.getAnnotation(ResponseResult.class)); + } + } + return true; + } +} diff --git a/nla-common/src/main/java/cn/nla/common/util/CheckUtil.java b/nla-common/src/main/java/cn/nla/common/util/CheckUtil.java new file mode 100644 index 0000000..b343e5e --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/util/CheckUtil.java @@ -0,0 +1,35 @@ +package cn.nla.common.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CheckUtil { + /** + * 邮箱正则 + */ + private static final Pattern MAIL_PATTERN = Pattern.compile("^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"); + /** + * 手机号正则,暂时未用 + */ + private static final Pattern PHONE_PATTERN = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$"); + /** + * @param email 邮箱 + */ + public static boolean isEmail(String email) { + if (null == email || "".equals(email)) { + return false; + } + Matcher m = MAIL_PATTERN.matcher(email); + return m.matches(); + } + /** + * @param phone 手机号 + */ + public static boolean isPhone(String phone) { + if (null == phone || "".equals(phone)) { + return false; + } + Matcher m = PHONE_PATTERN.matcher(phone); + return m.matches(); + } +} diff --git a/nla-common/src/main/java/cn/nla/common/util/CommonUtil.java b/nla-common/src/main/java/cn/nla/common/util/CommonUtil.java new file mode 100644 index 0000000..df7425a --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/util/CommonUtil.java @@ -0,0 +1,92 @@ +package cn.nla.common.util; + +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.MessageDigest; +import java.util.Random; + +/** + * 工具类 + */ +@Slf4j +public class CommonUtil { + + /** + * 获取请求的ip地址 + */ + public static String getIpAddr(HttpServletRequest request) { + String ipAddress; + try { + ipAddress = request.getHeader("x-forwarded-for"); + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + if (ipAddress.equals("127.0.0.1")) { + // 根据网卡取本机配置的IP + InetAddress inet = null; + try { + inet = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + log.error("getIpAddress error", e); + } + if (inet != null) { + ipAddress = inet.getHostAddress(); + } + } + } + // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 + if (ipAddress != null && ipAddress.length() > 15) { + // "***.***.***.***".length() + // = 15 + if (ipAddress.indexOf(",") > 0) { + ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); + } + } + } catch (Exception e) { + log.error(" getIpAddress Exception", e); + ipAddress = ""; + } + return ipAddress; + } + + /** + * MD5加密 + */ + public static String MD5(String data) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] array = md.digest(data.getBytes("UTF-8")); + StringBuilder sb = new StringBuilder(); + for (byte item : array) { + sb.append(Integer.toHexString((item & 0xFF) | 0x100), 1, 3); + } + return sb.toString().toUpperCase(); + } catch (Exception e) { + log.error("MD5 error", e); + } + return null; + } + + /** + * 获取验证码随机数 + * + * @param length 长度 + */ + public static String getRandomCode(int length) { + String sources = "0123456789"; + Random random = new Random(); + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < length; j++) { + sb.append(sources.charAt(random.nextInt(9))); + } + return sb.toString(); + } +} diff --git a/nla-common/src/main/java/cn/nla/common/util/JsonData.java b/nla-common/src/main/java/cn/nla/common/util/JsonData.java new file mode 100644 index 0000000..d0b46c5 --- /dev/null +++ b/nla-common/src/main/java/cn/nla/common/util/JsonData.java @@ -0,0 +1,59 @@ +package cn.nla.common.util; + +import cn.nla.common.enums.BizCodeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class JsonData { + + public static final String SUCCESS_MSG = "成功"; + public static final Integer SUCCESS = 0; + public static final Integer FAIL = -1; + /** + * 状态码 0 表示成功 + */ + private Integer code; + /** + * 数据 + */ + private Object data; + /** + * 描述 + */ + private String msg; + /** + * 成功,不传入数据 + */ + public static JsonData buildSuccess() { + return new JsonData(SUCCESS, null, SUCCESS_MSG); + } + /** + * 成功,传入数据 + */ + public static JsonData buildSuccess(Object data) { + return new JsonData(SUCCESS, data, SUCCESS_MSG); + } + + /** + * 失败,传入描述信息 + */ + public static JsonData buildError(String msg) { + return new JsonData(FAIL, null, msg); + } + /** + * 自定义状态码和错误信息 + */ + public static JsonData buildCodeAndMsg(int code, String msg) { + return new JsonData(code, null, msg); + } + /** + * 传入枚举,返回信息 + */ + public static JsonData buildResult(BizCodeEnum codeEnum) { + return JsonData.buildCodeAndMsg(codeEnum.getCode(), codeEnum.getMessage()); + } +} diff --git a/nla-user-service/pom.xml b/nla-user-service/pom.xml index 2f2ef69..11424a8 100644 --- a/nla-user-service/pom.xml +++ b/nla-user-service/pom.xml @@ -25,5 +25,25 @@ org.projectlombok lombok + + + com.baomidou + kaptcha-spring-boot-starter + 1.1.0 + + + + org.springframework.boot + spring-boot-starter-mail + + + + com.aliyun.oss + aliyun-sdk-oss + + + org.springframework.boot + spring-boot-starter-test + diff --git a/nla-user-service/src/main/java/cn/nla/user/UserApplication.java b/nla-user-service/src/main/java/cn/nla/user/UserApplication.java index c5d708c..7357dea 100644 --- a/nla-user-service/src/main/java/cn/nla/user/UserApplication.java +++ b/nla-user-service/src/main/java/cn/nla/user/UserApplication.java @@ -3,9 +3,11 @@ package cn.nla.user; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @MapperScan("cn.nla.*.mapper") +@ComponentScan(basePackages = {"cn.nla.*"}) public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); diff --git a/nla-user-service/src/main/java/cn/nla/user/config/CaptchaConfig.java b/nla-user-service/src/main/java/cn/nla/user/config/CaptchaConfig.java new file mode 100644 index 0000000..1fd79b2 --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/config/CaptchaConfig.java @@ -0,0 +1,48 @@ +package cn.nla.user.config; + +import com.google.code.kaptcha.Constants; +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + +@Configuration +public class CaptchaConfig { + + /** + * 验证码配置 Kaptcha配置类名 + */ + @Bean + @Qualifier("captchaProducer") + public DefaultKaptcha kaptcha() { + DefaultKaptcha kaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // properties.setProperty(Constants.KAPTCHA_BORDER, "yes"); + // properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "220,220,220"); + // properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "38,29,12"); + // properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "147"); + // properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "34"); + // properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "25"); + // properties.setProperty(Constants.KAPTCHA_SESSION_KEY, "code"); + //验证码个数 + properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); + // properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Courier"); + //字体间隔 + + properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "8"); + //干扰线颜色 + // properties.setProperty(Constants.KAPTCHA_NOISE_COLOR, "white"); + //干扰实现类 + properties.setProperty(Constants.KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); + //图片样式 + properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.WaterRipple"); + //文字来源 + properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789"); + Config config = new Config(properties); + kaptcha.setConfig(config); + return kaptcha; + } +} diff --git a/nla-user-service/src/main/java/cn/nla/user/config/OSSConfig.java b/nla-user-service/src/main/java/cn/nla/user/config/OSSConfig.java new file mode 100644 index 0000000..1a964ee --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/config/OSSConfig.java @@ -0,0 +1,15 @@ +package cn.nla.user.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@ConfigurationProperties(prefix = "aliyun.oss") +@Configuration +@Data +public class OSSConfig { + private String endpoint; + private String accessKeyId; + private String accessKeySecret; + private String bucketname; +} diff --git a/nla-user-service/src/main/java/cn/nla/user/controller/AddressController.java b/nla-user-service/src/main/java/cn/nla/user/controller/AddressController.java index 4917c78..71fbe50 100644 --- a/nla-user-service/src/main/java/cn/nla/user/controller/AddressController.java +++ b/nla-user-service/src/main/java/cn/nla/user/controller/AddressController.java @@ -1,21 +1,35 @@ package cn.nla.user.controller; +import cn.nla.common.annotation.ResponseResult; -import org.springframework.web.bind.annotation.RequestMapping; +import cn.nla.user.service.AddressService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; -import org.springframework.web.bind.annotation.RestController; /** - *

* 电商-公司收发货地址表 前端控制器 - *

* * @author YJs * @since 2024-07-29 */ +@Slf4j +@ResponseResult @RestController @RequestMapping("/addressDO") public class AddressController { + @Resource + private AddressService addressService; + @PostMapping("query") + @ResponseResult + public Object query(@RequestHeader Map headers) { + log.info("请求参数:{}", headers.get("token")); + return List.of(); + } } diff --git a/nla-user-service/src/main/java/cn/nla/user/controller/FileController.java b/nla-user-service/src/main/java/cn/nla/user/controller/FileController.java new file mode 100644 index 0000000..fd7a180 --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/controller/FileController.java @@ -0,0 +1,23 @@ +package cn.nla.user.controller; + +import cn.nla.common.util.JsonData; +import cn.nla.user.service.FileService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; + +@RestController +@RequestMapping("/file/v1") +@Slf4j +public class FileController { + @Resource + private FileService fileService; + @PostMapping(value = "/uploadFile", name = "上传文件") + public JsonData uploadImage(MultipartFile file) { + return JsonData.buildSuccess(fileService.uploadUserHeadImg(file)); + } +} diff --git a/nla-user-service/src/main/java/cn/nla/user/controller/NotifyController.java b/nla-user-service/src/main/java/cn/nla/user/controller/NotifyController.java new file mode 100644 index 0000000..bba6014 --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/controller/NotifyController.java @@ -0,0 +1,112 @@ +package cn.nla.user.controller; + +import cn.nla.common.enums.BizCodeEnum; +import cn.nla.common.util.CheckUtil; +import cn.nla.common.util.CommonUtil; +import cn.nla.common.util.JsonData; +import cn.nla.user.service.MailService; +import com.google.code.kaptcha.Producer; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.imageio.ImageIO; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * + */ +@RestController +@RequestMapping("/user/v1") +@Slf4j +public class NotifyController { + @Resource + private Producer captchaProducer; + @Resource + private MailService mailService; + @Autowired + private StringRedisTemplate redisTemplate; + /** + * 图形验证码有效期10分钟 + */ + private static final long CAPTCHA_CODE_EXPIRED = 60 * 1000 * 10; + + /** + * 获取图形验证码 + * + * @param request 请求参数 + * @param response 响应 + */ + @ApiOperation("获取图形验证码") + @GetMapping("captcha") + public void getCaptcha(HttpServletRequest request, HttpServletResponse response) { + String captchaText = captchaProducer.createText(); + log.info("图形验证码:{}", captchaText); + redisTemplate.opsForValue().set(getCaptchaKey(request), captchaText, CAPTCHA_CODE_EXPIRED, TimeUnit.MILLISECONDS); + BufferedImage bufferedImage = captchaProducer.createImage(captchaText); + ServletOutputStream outputStream; + try { + outputStream = response.getOutputStream(); + ImageIO.write(bufferedImage, "jpg", outputStream); + outputStream.flush(); + outputStream.close(); + } catch (IOException e) { + log.error("获取图形验证码异常", e); + } + } + + + @ApiOperation("获取图形验证码") + @GetMapping("send") + public JsonData sendCode(String from, String to) { + String cacheKey = String.format(from + "_%s", to); + String cacheValue = redisTemplate.opsForValue().get(cacheKey); + //如果不为空,则判断是否60秒内重复发送 + if (StringUtils.isNotBlank(cacheValue)) { + long ttl = Long.parseLong(cacheValue.split("_")[1]); + //当前时间戳-验证码发送时间戳,如果小于60秒,则不给重复发送 + if (System.currentTimeMillis() - ttl < 1000 * 60) { + log.info("重复发送验证码,时间间隔:{} 秒", (System.currentTimeMillis() - ttl) / 1000); + return JsonData.buildResult(BizCodeEnum.CODE_LIMITED); + } + } + //拼接验证码: 验证码+时间戳: 2322_324243232424324 + String code = CommonUtil.getRandomCode(6); + String value = code + "_" + System.currentTimeMillis(); + redisTemplate.opsForValue().set(cacheKey, value, CAPTCHA_CODE_EXPIRED, TimeUnit.MILLISECONDS); + if (CheckUtil.isEmail(to)) { + //邮箱验证码 + mailService.sendMail(to, "电商验证码", code); + log.info("发送邮箱验证码[{}]成功!", code); + return JsonData.buildSuccess(); + } else if (CheckUtil.isPhone(to)) { + //短信验证码 + log.info("要发送短信验证码[{}]", code); + } + return JsonData.buildResult(BizCodeEnum.CODE_TO_ERROR); + } + + /** + * 获取缓存的key + */ + private String getCaptchaKey(HttpServletRequest request) { + String ip = CommonUtil.getIpAddr(request); + String userAgent = request.getHeader("User-Agent"); + String key = "user-service:captcha:" + CommonUtil.MD5(ip + userAgent); + log.info("ip:{}", ip); + log.info("userAgent:{}", userAgent); + log.info("key:{}", key); + return key; + } +} diff --git a/nla-user-service/src/main/java/cn/nla/user/goup/Save.java b/nla-user-service/src/main/java/cn/nla/user/goup/Save.java new file mode 100644 index 0000000..082a1cd --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/goup/Save.java @@ -0,0 +1,6 @@ +package cn.nla.user.goup; +/** + * 保存 + */ +public interface Save { +} diff --git a/nla-user-service/src/main/java/cn/nla/user/goup/Update.java b/nla-user-service/src/main/java/cn/nla/user/goup/Update.java new file mode 100644 index 0000000..4892db2 --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/goup/Update.java @@ -0,0 +1,7 @@ +package cn.nla.user.goup; + +/** + * 更新 + */ +public interface Update { +} diff --git a/nla-user-service/src/main/java/cn/nla/user/model/StudentBean.java b/nla-user-service/src/main/java/cn/nla/user/model/StudentBean.java new file mode 100644 index 0000000..d4aef34 --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/model/StudentBean.java @@ -0,0 +1,32 @@ +package cn.nla.user.model; + +import cn.nla.common.annotation.EncryptId; +import cn.nla.user.goup.Save; +import cn.nla.user.goup.Update; +import lombok.Data; +import org.hibernate.validator.constraints.Length; +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.io.Serializable; +import java.util.List; +@Data +public class StudentBean implements Serializable { + @NotBlank(message = "用户名不能为空") + private String name; + @NotNull(groups = {Save.class, Update.class}) + @Length(min = 6, max = 20, groups = {Save.class, Update.class}) + private String account; + @Min(value = 18, message = "年龄不能小于18岁") + @NotNull(message = "年龄不能为空") + private Integer age; + @Pattern(regexp = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$", message = "手机号格式错误") + private String phoneNum; + @Email(message = "邮箱格式错误") + private String email; + @Valid + @NotNull(message = "任课老师不能为空") + @Size(min = 1, message = "至少有一个老师") + private List teacherBeans; + @EncryptId(message = "密码格式错误") + private String password; +} diff --git a/nla-user-service/src/main/java/cn/nla/user/model/TeacherBean.java b/nla-user-service/src/main/java/cn/nla/user/model/TeacherBean.java new file mode 100644 index 0000000..6ab7c48 --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/model/TeacherBean.java @@ -0,0 +1,12 @@ +package cn.nla.user.model; + +import lombok.Data; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +@Data +public class TeacherBean { + @NotEmpty(message = "老师姓名不能为空") + private String teacherName; + @Min(value = 1, message = "学科类型从1开始计算") + private int type; +} diff --git a/nla-user-service/src/main/java/cn/nla/user/service/FileService.java b/nla-user-service/src/main/java/cn/nla/user/service/FileService.java new file mode 100644 index 0000000..e25d09e --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/service/FileService.java @@ -0,0 +1,8 @@ +package cn.nla.user.service; + +import org.springframework.web.multipart.MultipartFile; + +public interface FileService { + + String uploadUserHeadImg(MultipartFile file); +} diff --git a/nla-user-service/src/main/java/cn/nla/user/service/MailService.java b/nla-user-service/src/main/java/cn/nla/user/service/MailService.java new file mode 100644 index 0000000..e8c8347 --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/service/MailService.java @@ -0,0 +1,6 @@ +package cn.nla.user.service; + +public interface MailService { + + void sendMail(String to, String subject, String content); +} diff --git a/nla-user-service/src/main/java/cn/nla/user/service/impl/FileServiceImpl.java b/nla-user-service/src/main/java/cn/nla/user/service/impl/FileServiceImpl.java new file mode 100644 index 0000000..61bcef9 --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/service/impl/FileServiceImpl.java @@ -0,0 +1,55 @@ +package cn.nla.user.service.impl; + +import cn.nla.user.config.OSSConfig; +import cn.nla.user.service.FileService; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.model.PutObjectResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +@Service +@Slf4j +public class FileServiceImpl implements FileService { + @Resource + private OSSConfig ossConfig; + @Override + public String uploadUserHeadImg(MultipartFile file) { + String originalFilename = file.getOriginalFilename(); + //获取相关配置 + String bucketName = ossConfig.getBucketname(); + String endpoint = ossConfig.getEndpoint(); + String accessKeyId = ossConfig.getAccessKeyId(); + String accessKeySecret = ossConfig.getAccessKeySecret(); + //创建oss对象 + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); + //构建路径 + LocalDateTime ldt = LocalDateTime.now(); + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd"); + String folder = dtf.format(ldt); + String fileName = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); + assert originalFilename != null; + String extension = originalFilename.substring(originalFilename.lastIndexOf(".")); + //在oss上创建文件夹test路径 + String newFileName = "test/" + folder + "/" + fileName + extension; + try { + PutObjectResult result = ossClient.putObject(bucketName, newFileName, file.getInputStream()); + //返回访问路径 + if (null != result) { + return "https://" + bucketName + "." + endpoint + "/" + newFileName; + } + } catch (Exception e) { + log.error("上传头像失败", e); + } finally { + // 关闭OSS服务 + ossClient.shutdown(); + } + return null; + } +} diff --git a/nla-user-service/src/main/java/cn/nla/user/service/impl/MailServiceImpl.java b/nla-user-service/src/main/java/cn/nla/user/service/impl/MailServiceImpl.java new file mode 100644 index 0000000..b73094c --- /dev/null +++ b/nla-user-service/src/main/java/cn/nla/user/service/impl/MailServiceImpl.java @@ -0,0 +1,47 @@ +package cn.nla.user.service.impl; + +import cn.nla.user.service.MailService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 发送邮件 + */ +@Service +@Slf4j +public class MailServiceImpl implements MailService { + /** + * springboot 提供的一个发送邮件的简单抽象,直接注入即可 + */ + @Resource + private JavaMailSender mailSender; + @Value("${spring.mail.from}") + private String from; + /** + * 发送邮件 + * + * @param to 收件人 + * @param subject 主题 + * @param content 内容 + */ + @Override + public void sendMail(String to, String subject, String content) { + //创建一个邮箱消息对象 + SimpleMailMessage message = new SimpleMailMessage(); + //配置邮箱发送人 + message.setFrom(from); + //邮件的收件人 + message.setTo(to); + //邮件的主题 + message.setSubject(subject); + //邮件的内容 + message.setText(content); + mailSender.send(message); + log.info("邮件发送成功:{}", message); + } +} diff --git a/nla-user-service/src/main/resources/application.yml b/nla-user-service/src/main/resources/application.yml index ebce9cc..dcdc1bc 100644 --- a/nla-user-service/src/main/resources/application.yml +++ b/nla-user-service/src/main/resources/application.yml @@ -2,20 +2,40 @@ server: port: 9001 spring: application: - name: nla-user-service + name: nla-user-service + redis: + host: 127.0.0.1 + port: 6379 + database: 0 #数据库配置 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://117.72.43.105:3306/p_nla_user?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: Yuan625621105. - + mail: + host: smtp.qq.com + username: 625621105@qq.com + password: iqaadvnrobajbfef + from: 625621105@qq.com + properties.mail.smtp.starttls.enable: true + properties.mail.smtp.starttls.required: true + properties.mail.smtp.ssl.enable: true + default-encoding: utf-8 #配置plus打印sql⽇志 mybatis-plus: configuration: - log-impl: - org.apache.ibatis.logging.stdout.StdOutImpl + log-impl: + org.apache.ibatis.logging.stdout.StdOutImpl #设置⽇志级别,ERROR/WARN/INFO/DEBUG,默认是INFO以上才显示 -logging: - level: - root: INFO +#logging: +# level: +# root: INFO + +#阿里云OSS配置 +aliyun: + oss: + endpoint: oss-cn-beijing.aliyuncs.com + access-key-id: LTAI5tGbV7aVMVKSnoDwmFUY + access-key-secret: U4W5fsdxjAh5f3udizbYNFdUldD8pZ + bucketname: yzdan diff --git a/nla-user-service/src/main/resources/logback.xml b/nla-user-service/src/main/resources/logback.xml new file mode 100644 index 0000000..4294b00 --- /dev/null +++ b/nla-user-service/src/main/resources/logback.xml @@ -0,0 +1,71 @@ + + + + + + + + + + ${log.pattern} + + + + + ${log.path}/info.log + + + + ${log.path}/info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + ${log.path}/error.log + + + + ${log.path}/error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + + + + + + + + + + + + + diff --git a/nla-user-service/src/test/java/AddressTest.java b/nla-user-service/src/test/java/AddressTest.java new file mode 100644 index 0000000..9447fce --- /dev/null +++ b/nla-user-service/src/test/java/AddressTest.java @@ -0,0 +1,26 @@ +import cn.nla.user.UserApplication; +import cn.nla.user.model.AddressDO; +import cn.nla.user.service.AddressService; +import lombok.extern.slf4j.Slf4j; +import net.minidev.json.JSONArray; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = UserApplication.class) +@Slf4j +public class AddressTest { + + @Resource + private AddressService addressService; + @Test + public void testAddressDetail() { + List list = addressService.list(); + log.info(JSONArray.toJSONString(list)); + } +} diff --git a/pom.xml b/pom.xml index 9af3e22..edd71dd 100644 --- a/pom.xml +++ b/pom.xml @@ -85,6 +85,12 @@ springfox-boot-starter ${springfox.boot.starter.version} + + + com.aliyun.oss + aliyun-sdk-oss + 3.10.2 +