Commit d6c1ff21 authored by zhouxudong's avatar zhouxudong

提交代码

parents
Pipeline #93 failed with stages
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lyy</groupId>
<artifactId>liyeyun-user-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--mysql连接驱动-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis增强器依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!-- hutool工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.20</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<!-- SpringBoot 拦截器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- ## 类型转换-->
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
<!-- jwt-->
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.23</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.lyy.user;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Author:zhouxudong
* @version: 1.0
* @Date: 2023/11/17 15:41
* @Description:
*/
@SpringBootApplication
public class LyyUserApplication {
public static void main(String[] args) {
SpringApplication.run(LyyUserApplication.class, args);
}
}
package com.lyy.user.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 全局配置类
*
* @author ruoyi
*/
@Data
@Component
@ConfigurationProperties(prefix = "lyy")
public class LyyConfig
{
private String profile;
private String obsPath;
private String passwordSalt;
private Integer tokenExpireTimeDays;
private Boolean enableUrlFilter;
}
package com.lyy.user.config.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author:zhouxudong
* @version: 1.0
* @Date: 2023/11/17 16:45
* @Description: 自定义注解,添加注解后不包装返回对象
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface ResponseAnnotation {
}
package com.lyy.user.config.async;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/17 15:56
* @description: 自定义线程池
*/
@Configuration
@Slf4j
@EnableAsync
public class AsyncConfig {
private static final int COREPOOLSIZE = 6;
private static final int MAXPOOLSIZE = 12;
private static final int QUEUECAPACITY = 16;
private static final int KEEPALIVESECONDS = 60;
private static final String THREADNAMEPREFIX = "taskExecutor-";
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(COREPOOLSIZE);
executor.setMaxPoolSize(MAXPOOLSIZE);
executor.setQueueCapacity(QUEUECAPACITY);
executor.setKeepAliveSeconds(KEEPALIVESECONDS);
executor.setThreadNamePrefix(THREADNAMEPREFIX);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setTaskDecorator(new ContextDecorator());
executor.initialize();
return executor;
}
static class ContextDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
RequestAttributes requestContext = RequestContextHolder.currentRequestAttributes();
return () -> {
try {
RequestContextHolder.setRequestAttributes(requestContext);
runnable.run();
} finally {
RequestContextHolder.resetRequestAttributes();
}
};
}
}
}
package com.lyy.user.config.auth;
import com.lyy.user.config.exception.ServiceException;
import com.lyy.user.config.other.BaseContextHandler;
import com.lyy.user.util.jwt.JwtTokenUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** 服务拦截器,根据配置的请求路径,进行请求的拦截,执行preHandle方法 */
public class CurrentUserInterceptor implements AsyncHandlerInterceptor {
private static final String TOKEN_HEADER = "Authorization";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 从header中获取权限请求头
String token = request.getHeader(TOKEN_HEADER);
if(StringUtils.isBlank(token)){
throw new ServiceException("未授权,登录失败");
}
// 根据token信息,生成当前登录用户信息的设置,存放容器threadlocal
BaseContextHandler.setCurrentUserInfo(JwtTokenUtil.getJwtUser(token));
return true;
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
BaseContextHandler.removeCurrentUserInfo();
}
}
package com.lyy.user.config.auth;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.Collections;
/** Web层配置类 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加需要拦截的路径,以及处理拦截的拦截器
registry
.addInterceptor(getCurrentUserInterceptor())
.addPathPatterns(getIncludePathPatterns())
.excludePathPatterns(getExcludePathPatterns());
}
@Bean
CurrentUserInterceptor getCurrentUserInterceptor() {
return new CurrentUserInterceptor();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/**")
.addResourceLocations("classpath:/template/")
.addResourceLocations("classpath:/templates/");
}
/** 需要拦截的信息 */
private ArrayList<String> getIncludePathPatterns() {
ArrayList<String> list = new ArrayList<>();
String[] urls = {"/**"};
Collections.addAll(list, urls);
return list;
}
/** 不需要任何用户信息 白名单 */
private ArrayList<String> getExcludePathPatterns() {
ArrayList<String> list = new ArrayList<>();
String[] urls = {"/pc/**"};
Collections.addAll(list, urls);
return list;
}
}
package com.lyy.user.config.exception;
import lombok.*;
/**
* @description:
* @date: 2023/11/17 16:30
* @param:
* @return:
**/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class BaseException extends RuntimeException {
private Integer code;
private String message;
public BaseException(String message){
super(message);
this.message = message;
}
}
package com.lyy.user.config.exception;
import com.lyy.user.domain.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ValidationException;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/17 16:32
* @description: 统一异常处理
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(value = BaseException.class)
public BaseResult handlerException(BaseException e){
log.error("发生异常BaseException:",e);
return new BaseResult(false,e.getMessage(),null);
}
@ExceptionHandler(value = ValidationException.class)
public BaseResult handlerException(ValidationException e){
log.error("发生参数校验异常Exception:",e);
return new BaseResult(false,e.getMessage(),null);
}
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public BaseResult handlerException(MethodArgumentNotValidException e){
log.error("发生参数校验异常:",e);
return new BaseResult(false,e.getBindingResult().getFieldError().getDefaultMessage(),null);
}
@ExceptionHandler(value = Exception.class)
public BaseResult handlerException(Exception e){
log.error("发生异常Exception:",e);
return new BaseResult(false,e.getMessage(),null);
}
}
package com.lyy.user.config.exception;
/**
* @description: 业务异常
* @date: 2023/11/17 16:31
* @param:
* @return:
**/
public class ServiceException extends BaseException {
public ServiceException(String message) {
super(message);
}
}
package com.lyy.user.config.mybatis;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@Slf4j
public class MyBatisPlusConfig {
/**
* @description:
* @date: 2023/11/17 16:22
* @param: []
* @return: com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor
**/
@Bean
public MybatisPlusInterceptor optimisticLockerInterceptor() {
//1 创建MybatisPlusInterceptor拦截器对象
MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
//2 乐观锁
mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
//3.分页
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mpInterceptor;
}
}
package com.lyy.user.config.mybatis;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.lyy.user.config.other.BaseContextHandler;
import com.lyy.user.domain.JwtInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Arrays;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/17 16:46
* @description:
*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
private final String[] createNeedToFill = {
"createPerson", "createTime", "updatePerson", "updateTime", "version"
};
private final String[] updateNeedToFill = {"updatePerson", "updateTime"};
private final Class[] ignoreAutoFillEntity = {};
@Override
public void insertFill(MetaObject metaObject) {
if (!ignoreAutoFill(metaObject)) {
autofill(metaObject, createNeedToFill);
}
}
@Override
public void updateFill(MetaObject metaObject) {
if (!ignoreAutoFill(metaObject)) {
autofill(metaObject, updateNeedToFill);
}
}
private void autofill(MetaObject metaObject, String[] arrayNeedToFill) {
JwtInfo userInfo = BaseContextHandler.getCurrentUserInfo();
Arrays.stream(arrayNeedToFill)
.forEach(
property -> {
if (metaObject.hasSetter(property)) {
if (property.endsWith("Person")) {
this.setFieldValByName(property, userInfo.getUserName(), metaObject);
}
if (property.endsWith("Time")) {
this.setFieldValByName(property, LocalDateTime.now(), metaObject);
}
if (property.equals("version")) {
this.setFieldValByName(property, 1, metaObject);
}
}
});
}
private Boolean ignoreAutoFill(MetaObject metaObject) {
return Arrays.stream(ignoreAutoFillEntity)
.anyMatch(entity -> metaObject.getOriginalObject().getClass() == entity);
}
}
package com.lyy.user.config.other;
import com.lyy.user.domain.JwtInfo;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/17 17:16
* @description: 当前登录人信息
*/
public class BaseContextHandler {
private static final ThreadLocal<JwtInfo> currentUserInfoThreadLocal = new ThreadLocal<>();
public static void setCurrentUserInfo(JwtInfo currentUserInfo) throws Exception {
if (currentUserInfo != null) {
try {
currentUserInfoThreadLocal.set(currentUserInfo);
} catch (Exception e) {
throw new Exception("失效");
}
}
}
public static JwtInfo getCurrentUserInfo() {
JwtInfo currentUserInfo = currentUserInfoThreadLocal.get();
if (currentUserInfo == null) {
currentUserInfo = new JwtInfo();
currentUserInfoThreadLocal.set(currentUserInfo);
}
return currentUserInfo;
}
public static void removeCurrentUserInfo() {
currentUserInfoThreadLocal.remove();
}
}
package com.lyy.user.config.other;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.CustomConverter;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.metadata.Type;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
@Configuration
@Slf4j
@Order(30)
public class CustomerConvertConfig {
private static final DateTimeFormatter df_datetime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final DateTimeFormatter df_date = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final DateTimeFormatter df_time = DateTimeFormatter.ofPattern("HH:mm:ss");
/**
* String -> LocalDateTime 转换器
*
* @return
*/
@Bean("localDateTimeConvert")
public CustomConverter localDateTimeConvert() {
return new CustomConverter<String, LocalDateTime>() {
@Override
public boolean canConvert(Type sourceType, Type destinationType) {
return ((String.class).isAssignableFrom(sourceType.getClass()))
&& ((LocalDateTime.class).isAssignableFrom(destinationType.getClass()));
}
@Override
public LocalDateTime convert(String o, Type<? extends LocalDateTime> type, MappingContext mappingContext) {
return LocalDateTime.parse(o, df_datetime);
}
};
}
/**
* String -> LocalDate 转换器
*/
@Bean("localDateConvert")
public CustomConverter localDateConvert() {
return new CustomConverter<String, LocalDate>() {
@Override
public boolean canConvert(Type sourceType, Type destinationType) {
return ((String.class).isAssignableFrom(sourceType.getClass()))
&& ((LocalDate.class).isAssignableFrom(destinationType.getClass()));
}
@Override
public LocalDate convert(String o, Type<? extends LocalDate> type, MappingContext mappingContext) {
return LocalDate.parse(o, df_date);
}
};
}
/**
* String -> LocalTime 转换器
*
* @return
*/
@Bean("localTimeConvert")
public CustomConverter localTimeConvert() {
return new CustomConverter<String, LocalTime>() {
@Override
public boolean canConvert(Type sourceType, Type destinationType) {
return ((String.class).isAssignableFrom(sourceType.getClass()))
&& ((LocalTime.class).isAssignableFrom(destinationType.getClass()));
}
@Override
public LocalTime convert(String o, Type<? extends LocalTime> type, MappingContext mappingContext) {
return LocalTime.parse(o, df_time);
}
};
}
}
package com.lyy.user.config.other;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lyy.user.config.annotation.ResponseAnnotation;
import com.lyy.user.domain.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.HashMap;
/**
* @author chaus
* @date
*/
@RestControllerAdvice
@Slf4j
public class GlobalResponseBodyAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class converterType) {
boolean isIntercept = true;
Method method = methodParameter.getMethod();
AnnotatedElement annotatedElement = methodParameter.getAnnotatedElement();
ResponseAnnotation annotation =
AnnotationUtils.findAnnotation(annotatedElement, ResponseAnnotation.class);
if (!ObjectUtils.isEmpty(annotation)) {
isIntercept = false;
}
// methodParameter.getMethodAnnotations();
// if(AntPathMatcher)
return isIntercept;
}
@Override
public Object beforeBodyWrite(
Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
log.debug(returnType.toString()); // controller方法签名
log.debug(selectedContentType.toString()); // 要转换成的数据格式
log.debug(selectedConverterType.getName()); // 转换器
if (!(body instanceof BaseResult)) {
BaseResult baseResult = new BaseResult(true, null, body);
if (body instanceof String) {
try {
log.debug(" o instanceof String is true");
return new ObjectMapper().writeValueAsString(baseResult);
} catch (JsonProcessingException e) {
log.error("返回结果包装失败,body: {}", body);
}
} else if (body instanceof HashMap) {
HashMap map = (HashMap) body;
Boolean success = (Boolean) map.get("success");
String msg = (String) map.get("message");
if (success != null) {
baseResult.setSuccess(success);
map.remove("success");
}
baseResult.setMessage(msg);
map.remove("message");
}
return baseResult;
}
return body;
}
}
package com.lyy.user.config.other;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.CustomConverter;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.converter.ConverterFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/17 16:53
* @description: 类型转换
*/
@Configuration
@Slf4j
@Order(31)
public class OrikaConfig {
@Autowired
@Qualifier("localDateTimeConvert")
private CustomConverter localDateTimeConvert;
@Autowired
@Qualifier("localDateConvert")
private CustomConverter localDateConvert;
@Autowired
@Qualifier("localTimeConvert")
private CustomConverter localTimeConvert;
@Bean
public MapperFactory mapperFactory() {
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
// 注册自定义转换器
ConverterFactory converterFactory = mapperFactory.getConverterFactory();
converterFactory.registerConverter(localDateTimeConvert);
converterFactory.registerConverter(localDateConvert);
converterFactory.registerConverter(localTimeConvert);
return mapperFactory;
}
}
package com.lyy.user.config.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* redis配置
*
* @author garden
*/
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer); // key的序列化类型
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
template.setValueSerializer(jackson2JsonRedisSerializer); // value的序列化类型
template.setHashKeySerializer(stringRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
package com.lyy.user.config.sms;
import lombok.*;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author:zhouxudong
* @version: 1.0
* @Date: 2023/11/17 10:54
* @Description:
*/
@Component
@ConfigurationProperties(prefix = "sms")
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class SmsConfig {
private String appKey;
private String appSecret;
//app接入地址 //APP接入地址(在控制台"应用管理"页面获取)+接口访问URI
private String appUrl;
/** 签名通道号 //国内短信签名通道号*/
private String sender;
/** 短信签名 国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称*/
private String signature;
}
package com.lyy.user.config.webflux;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
@Slf4j
public class WebClientConfig {
@Bean
public WebClient webClient() {
return WebClient.builder().build();
}
}
package com.lyy.user.constant;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/20 9:43
* @description: 通用常量信息
*/
public class Constants {
/**
* UTF-8 字符集
*/
public static final String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
public static final String GBK = "GBK";
/**
* http请求
*/
public static final String HTTP = "http://";
/**
* https请求
*/
public static final String HTTPS = "https://";
/**
* 通用成功标识
*/
public static final String SUCCESS = "0";
/**
* 通用失败标识
*/
public static final String FAIL = "1";
/**
* 登录成功
*/
public static final String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
public static final String LOGOUT = "Logout";
/**
* 注册
*/
public static final String REGISTER = "Register";
/**
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
/**
* 系统用户授权缓存
*/
public static final String SYS_AUTH_CACHE = "sys-authCache";
/**
* 参数管理 cache name
*/
public static final String SYS_CONFIG_CACHE = "sys-config";
/**
* 参数管理 cache key
*/
public static final String SYS_CONFIG_KEY = "sys_config:";
/**
* 字典管理 cache name
*/
public static final String SYS_DICT_CACHE = "sys-dict";
/**
* 字典管理 cache key
*/
public static final String SYS_DICT_KEY = "sys_dict:";
/**
* 资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX = "/profile";
/**
* RMI 远程方法调用
*/
public static final String LOOKUP_RMI = "rmi:";
/**
* LDAP 远程方法调用
*/
public static final String LOOKUP_LDAP = "ldap:";
/**
* LDAPS 远程方法调用
*/
public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
*/
public static final String[] JOB_WHITELIST_STR = { "com.ruoyi" };
/**
* 定时任务违规的字符
*/
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config" };
//token信息
public static final String token="bearer ";
//手机验证码 规则: 手机验证码:验证码类型:手机号
public static final String MSG_KEY="phone:message:";
}
package com.lyy.user.constant;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/17 17:14
* @description:
*/
public class TokenConstants {
public static final byte[] SECRET = "03jh6Uf6#4z9^c6!gGA|BYc!@q3Sl4IDR".getBytes();
public static final String DETAILS = "details";
public static final String AUTHORITIES = "authorities";
public static final String EXPIRE_TIME = "expire_time";
public static final String RESULT = "message";
public static final String SUCCESS = "success";
public static final class TOKEN_RESULT {
public static final String TOKEN_PARSE_SUCCESS = "token解析成功";
public static final String TOKEN_EXPIRED = "token已过期";
public static final String TOKEN_PARSE_FAILED = "无效的token";
}
public static final String DATA = "data";
}
package com.lyy.user.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class BaseResult<T> {
private boolean success;// 状态说明:true 执行成功; false 发生异常
private String message; // 异常说明
private T data; // 业务数据
/** 成功 */
public static final boolean SUCCESS = true;
/** 失败 */
public static final boolean FAIL = false;
public static <T> BaseResult<T> ok()
{
return restResult(null, SUCCESS, null);
}
public static <T> BaseResult<T> ok(T data)
{
return restResult(data, SUCCESS, null);
}
public static <T> BaseResult<T> ok(T data, String msg)
{
return restResult(data, SUCCESS, msg);
}
public static <T> BaseResult<T> fail()
{
return restResult(null, FAIL, null);
}
public static <T> BaseResult<T> fail(String msg)
{
return restResult(null, FAIL, msg);
}
public static <T> BaseResult<T> fail(T data)
{
return restResult(data, FAIL, null);
}
public static <T> BaseResult<T> fail(T data, String msg)
{
return restResult(data, FAIL, msg);
}
private static <T> BaseResult<T> restResult(T data, boolean success, String msg)
{
BaseResult<T> baseResult = new BaseResult<>();
baseResult.setSuccess(success);
baseResult.setData(data);
baseResult.setMessage(msg);
return baseResult;
}
}
package com.lyy.user.domain;
import lombok.*;
import lombok.experimental.Accessors;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/17 17:13
* @description: jwt 信息
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
public class JwtInfo {
/** 人员id */
private Integer userId;
/** 人员名称 */
private String userName;
private String loginName;
/** 手机号 */
private String phone;
}
package com.lyy.user.enums;
import lombok.Getter;
@Getter
public enum SendMsgTypeEnum {
REGISTER(1,"345","注册"),
LOGIN(2,"234","登录");
private final Integer code;
private final String templateId;
private final String name;
SendMsgTypeEnum(Integer code, String templateId, String name) {
this.code = code;
this.templateId = templateId;
this.name = name;
}
public static String getTemplateId(Integer code){
for (SendMsgTypeEnum bt: values()){
if (bt.code.equals(code)){
return bt.templateId;
}
}
return null;
}
}
package com.lyy.user.moudle.login.controller;
import com.lyy.user.moudle.user.service.SysUserInfoService;
import com.lyy.user.moudle.user.vo.LoginVo;
import com.lyy.user.moudle.user.vo.PhoneLoginVo;
import com.lyy.user.moudle.user.vo.RegisterVo;
import com.lyy.user.moudle.user.vo.SendPhoneVo;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
* @Author:zhouxudong
*
* @version: 1.0 @Date: 2023/11/16 14:09 @Description:pc登录
*/
@RestController
@RequestMapping("/pc")
@RequiredArgsConstructor
public class SysPcLoginController {
private final SysUserInfoService sysUserInfoService;
/**
* @description: pc-用户密码登录
* @date: 2023/11/20 9:39
* @param: [loginVo]
* @return: java.lang.String
*/
@PostMapping("/login")
public String login(@Validated @RequestBody LoginVo loginVo) {
return this.sysUserInfoService.loginPc(loginVo);
}
/**
* @description: 手机号登录
* @date: 2023/11/20 9:40
* @param: [phoneLoginVo]
* @return: java.lang.String
*/
// 测试手机格式
@PostMapping("/phoneLogin")
public String phoneLogin(@Validated @RequestBody PhoneLoginVo phoneLoginVo) {
return sysUserInfoService.phoneLogin(phoneLoginVo);
}
/**
* @description: pc-退出登录
* @date: 2023/11/20 9:40
* @param: [request]
* @return: boolean
*/
@PostMapping("logout")
public boolean logout(HttpServletRequest request) {
return this.sysUserInfoService.logout(request.getHeader("token"));
}
/**
* @description: 核对手机号是否已经注册
* @date: 2023/11/20 9:40
* @param: [phone]
* @return: boolean
*/
@GetMapping("/check/{phone}")
public boolean checkPhone(@PathVariable("phone") String phone) {
return this.sysUserInfoService.checkPhone(phone);
}
/**
* @description: 发送短信
* @date: 2023/11/20 9:40
* @param: [sendPhoneVo]
* @return: boolean
*/
@PostMapping("/sendMsg")
public boolean sendMsg(@RequestBody @Validated SendPhoneVo sendPhoneVo) {
return this.sysUserInfoService.sendMsg(sendPhoneVo);
}
/**
* @description: 注册
* @date: 2023/11/20 9:40
* @param: [registerVo]
* @return: boolean
*/
@PostMapping("/sign")
public boolean sign(@RequestBody @Validated RegisterVo registerVo) {
return this.sysUserInfoService.sign(registerVo);
}
}
package com.lyy.user.moudle.user.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 用户信息表
* @TableName sys_user_info
*/
@TableName(value ="sys_user")
@Data
public class SysUserInfo implements Serializable {
/**
* 用户ID
*/
@TableId(type = IdType.AUTO)
private Integer userId;
/**
* 部门ID
*/
private Integer deptId;
/**
* 登录账号
*/
private String loginName;
/**
* 用户昵称
*/
private String userName;
/**
* 用户类型(00系统用户 01注册用户)
*/
private String userType;
/**
* 用户邮箱
*/
private String email;
/**
* 手机号码
*/
private String phonenumber;
/**
* 用户性别(0男 1女 2未知)
*/
private String sex;
/**
* 头像路径
*/
private String avatar;
/**
* 密码
*/
private String password;
/**
* 盐加密
*/
private String salt;
/**
* 帐号状态(0正常 1停用)
*/
private String status;
/**
* 删除标志(0代表存在 2代表删除)
*/
private String delFlag;
/**
* 最后登录IP
*/
private String loginIp;
/**
* 最后登录时间
*/
private Date loginDate;
/**
* 密码最后更新时间
*/
private Date pwdUpdateDate;
/**
* 创建者
*/
private String createBy;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新者
*/
private String updateBy;
/**
* 更新时间
*/
private Date updateTime;
/**
* 备注
*/
private String remark;
/**
* 数据来源(1-微信;2-立业云)
*/
private Integer source;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
package com.lyy.user.moudle.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lyy.user.moudle.user.entity.SysUserInfo;
import org.apache.ibatis.annotations.Mapper;
/**
* @author 26996
* @description 针对表【sys_user_info(用户信息表)】的数据库操作Mapper
* @createDate 2023-09-17 18:50:52
* @Entity com.lyy.admin.domain.SysUserInfo
*/
@Mapper
public interface SysUserInfoMapper extends BaseMapper<SysUserInfo> {
}
package com.lyy.user.moudle.user.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lyy.user.moudle.user.entity.SysUserInfo;
import com.lyy.user.moudle.user.vo.LoginVo;
import com.lyy.user.moudle.user.vo.PhoneLoginVo;
import com.lyy.user.moudle.user.vo.RegisterVo;
import com.lyy.user.moudle.user.vo.SendPhoneVo;
/**
* @author 26996
* @description 针对表【sys_user_info(用户信息表)】的数据库操作Service
* @createDate 2023-09-17 18:50:52
*/
public interface SysUserInfoService extends IService<SysUserInfo> {
public String login (String username,String password,Integer type) throws Exception;
public void resetPassword(Integer userId,String password);
/**
* @description: pc端登录
* @date: 2023/11/16 17:32
* @param: [loginVo]
* @return: java.lang.String
**/
String loginPc(LoginVo loginVo);
/**
* @description: pc 手机端登录
* @date: 2023/11/16 17:46
* @param: [phoneLoginVo]
* @return: java.lang.String
**/
String phoneLogin(PhoneLoginVo phoneLoginVo);
/**
* @description: 退出登录
* @date: 2023/11/16 18:14
* @param: []
* @return: boolean
**/
boolean logout(String token);
/**
* @description: 核对手机号是否已经注册
* @date: 2023/11/16 18:36
* @param: [phone]
* @return: boolean
**/
boolean checkPhone(String phone);
/**
* @description: 发送短信
* @date: 2023/11/16 18:36
* @param: [phone]
* @return: boolean
**/
boolean sendMsg(SendPhoneVo sendPhoneVo);
//用户注册
boolean sign(RegisterVo registerVo);
}
package com.lyy.user.moudle.user.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.jwt.JWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lyy.user.config.LyyConfig;
import com.lyy.user.config.exception.ServiceException;
import com.lyy.user.constant.Constants;
import com.lyy.user.enums.SendMsgTypeEnum;
import com.lyy.user.moudle.user.entity.SysUserInfo;
import com.lyy.user.moudle.user.mapper.SysUserInfoMapper;
import com.lyy.user.moudle.user.service.SysUserInfoService;
import com.lyy.user.moudle.user.vo.*;
import com.lyy.user.util.jwt.JwtTokenUtil;
import com.lyy.user.util.sms.SendMsgUtils;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/20 9:50
* @description: 用户模块
*/
@Service
@Slf4j
public class SysUserInfoServiceImpl extends ServiceImpl<SysUserInfoMapper, SysUserInfo>
implements SysUserInfoService {
@Autowired LyyConfig lyyConfig;
@Autowired(required = false)
private StringRedisTemplate stringRedisTemplate;
@Autowired private SendMsgUtils sendMsgUtils;
@Override
public String login(String loginName, String password, Integer type) {
// 判断当前用户是否存在
QueryWrapper<SysUserInfo> sysUserInfoQW = new QueryWrapper<>();
sysUserInfoQW.eq("login_name", loginName);
SysUserInfo sysUserInfo = this.getOne(sysUserInfoQW);
if (sysUserInfo == null) {
throw new ServiceException("当前用户不存在");
}
// 验证失败
if (!checkPassword(sysUserInfo.getPassword(), password)) {
throw new ServiceException("当前用户密码输入错误");
}
// 设置token
// String token = getToken(sysUserInfo, type);
String token = JwtTokenUtil.createToken(sysUserInfo,null);
stringRedisTemplate
.opsForValue()
.set(Constants.token + token, sysUserInfo.getUserId().toString(), 15, TimeUnit.DAYS);
return token;
}
public boolean checkPassword(String realPassword, String password) {
String md5Password =
DigestUtils.md5DigestAsHex((password + lyyConfig.getPasswordSalt()).getBytes());
return realPassword.equals(md5Password);
}
public void resetPassword(Integer userId, String password) {
SysUserInfo sysUserInfo = this.getById(userId);
String newPassword =
DigestUtils.md5DigestAsHex((password + lyyConfig.getPasswordSalt()).getBytes());
sysUserInfo.setPassword(newPassword);
sysUserInfo.setUpdateTime(DateUtil.date());
this.updateById(sysUserInfo);
}
/**
* @description: pc端登录--->复用登录
* @date: 2023/11/16 17:32
* @param: [loginVo]
* @return: java.lang.String token
*/
@Override
public String loginPc(LoginVo loginVo) {
return login(loginVo.getUserName(), loginVo.getPassWord(), 1);
}
/**
* @description: pc 手机端登录
* @date: 2023/11/16 17:46
* @param: [phoneLoginVo]
* @return: java.lang.String
*/
@Override
public String phoneLogin(PhoneLoginVo phoneLoginVo) {
LambdaQueryWrapper<SysUserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SysUserInfo::getPhonenumber, phoneLoginVo.getPhone());
SysUserInfo sysUserInfo = this.getOne(lambdaQueryWrapper);
if (ObjectUtils.isEmpty(sysUserInfo)) {
throw new ServiceException("手机号未注册,请先注册");
}
String phone = phoneLoginVo.getPhone();
String code = phoneLoginVo.getCode();
String msgCode =
stringRedisTemplate
.opsForValue()
.get(Constants.MSG_KEY + SendMsgTypeEnum.LOGIN.getCode() + ":" + phone);
if (StringUtils.isBlank(msgCode)) {
throw new ServiceException("验证码失效,请重新发送");
}
if (!code.equals(msgCode)) {
throw new ServiceException("验证码有误");
}
return JwtTokenUtil.createToken(sysUserInfo,null);
}
/**
* @description: 退出
* @date: 2023/11/16 18:17
* @param: [token]
* @return: boolean
*/
@Override
public boolean logout(String token) {
return Boolean.TRUE.equals(stringRedisTemplate.delete(Constants.token + token));
}
/**
* @description: 核对手机号是否已经注册
* @date: 2023/11/16 18:36
* @param: [phone]
* @return: boolean
*/
@Override
public boolean checkPhone(String phone) {
check(phone);
LambdaQueryWrapper<SysUserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SysUserInfo::getPhonenumber, phone);
return this.count(lambdaQueryWrapper) > 0;
}
/**
* @description: 发送短信
* @date: 2023/11/16 18:36
* @param: [phone]
* @return: boolean
*/
@Override
public boolean sendMsg(SendPhoneVo sendPhoneVo) {
check(sendPhoneVo.getPhone());
if (StringUtils.isEmpty(SendMsgTypeEnum.getTemplateId(sendPhoneVo.getType()))) {
throw new ServiceException("参数有误");
}
String key = Constants.MSG_KEY + sendPhoneVo.getType() + ":" + sendPhoneVo.getPhone();
String code = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(code)) {
throw new ServiceException("短信以发送,请勿重复发送");
}
int randomInt = RandomUtil.randomInt(100000, 999999);
List<Integer> temp = new ArrayList<>();
temp.add(randomInt);
// 发送短信
String result =
sendMsgUtils.sendMsg(
sendPhoneVo.getPhone(),
SendMsgTypeEnum.getTemplateId(sendPhoneVo.getType()),
temp.toString());
if (ObjectUtils.isEmpty(result)) {
throw new ServiceException("短信发送失败");
}
log.info("发送短信返回结果:{}", result);
stringRedisTemplate.opsForValue().set(key, String.valueOf(randomInt), 5, TimeUnit.MINUTES);
return true;
}
/**
* @description: 注册
* @date: 2023/11/17 9:53
* @param: [registerVo]
* @return: boolean
*/
@Override
@Transactional
public boolean sign(RegisterVo registerVo) {
String phone = registerVo.getPhone();
if (checkPhone(phone)) {
throw new ServiceException("手机号已经注册");
}
String key = Constants.MSG_KEY + SendMsgTypeEnum.REGISTER.getCode() + ":" + phone;
String code = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isBlank(code)) {
throw new ServiceException("验证码已失效");
}
if (!registerVo.getCode().equals(code)) {
throw new ServiceException("验证码有误");
}
String userName = registerVo.getUserName();
LambdaQueryWrapper<SysUserInfo> userLambdaQuery = new LambdaQueryWrapper<>();
userLambdaQuery.eq(SysUserInfo::getLoginName, userName);
long count = this.count(userLambdaQuery);
if (count > 0) {
throw new ServiceException("用户名重复");
}
SysUserInfo userInfo = new SysUserInfo();
userInfo.setLoginName(registerVo.getUserName());
userInfo.setUserName(registerVo.getUserName());
userInfo.setUserType("00");
userInfo.setPhonenumber(phone);
userInfo.setSex("0");
userInfo.setPassword(
DigestUtils.md5DigestAsHex(
(registerVo.getPassWord() + lyyConfig.getPasswordSalt()).getBytes()));
userInfo.setSalt(lyyConfig.getPasswordSalt());
return this.save(userInfo);
}
private void check(String phone) {
if (StringUtils.isEmpty(phone)) {
throw new ServiceException("手机号不能为空");
}
boolean match = ReUtil.isMatch("^1[3-9]\\d{9}$", phone);
if (!match) {
throw new ServiceException("手机号码格式有误");
}
}
}
package com.lyy.user.moudle.user.vo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.NotEmpty;
/**
* @Author:zhouxudong
* @version: 1.0
* @Date: 2023/11/16 14:43
* @Description: 用户密码登录
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class LoginVo {
@NotEmpty(message = "用户名不能为空")
private String userName;
@NotEmpty(message = "密码不能为空")
private String passWord;
}
package com.lyy.user.moudle.user.vo;
import lombok.*;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
/**
* @Author:zhouxudong
* @version: 1.0
* @Date: 2023/11/16 17:40
* @Description:
*/
@Getter
@Setter
@AllArgsConstructor
@ToString
@NoArgsConstructor
@Accessors(chain = true)
public class PhoneLoginVo {
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3456789]\\d{9}$", message = "手机号格式不正确")
private String phone;
@NotEmpty(message ="验证码不能为空")
private String code;
}
package com.lyy.user.moudle.user.vo;
import lombok.*;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* @Author:zhouxudong
* @version: 1.0
* @Date: 2023/11/17 9:38
* @Description: 注册信息
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class RegisterVo {
@NotEmpty(message = "用户名不能为空")
@Size(min = 6,max = 12,message = "用户名长度需要在6到12之间")
@Pattern(regexp = "^[a-zA-Z0-9_]{6,12}$", message = "用户名只能包含字母和数字")
private String userName;
@NotEmpty(message = "密码不能为空")
private String passWord;
@NotEmpty(message = "手机号不能为空")
@Pattern(regexp = "^1[3456789]\\d{9}$", message = "手机号格式不正确")
private String phone;
@NotEmpty(message = "验证码不能为空")
private String code;
}
package com.lyy.user.moudle.user.vo;
import lombok.*;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.Pattern;
/**
* @Author:zhouxudong
* @version: 1.0
* @Date: 2023/11/17 9:14
* @Description: 发送短信 vo
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class SendPhoneVo {
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3456789]\\d{9}$", message = "手机号格式不正确")
private String phone;
//发送短信的类型 1:注册 2:登录
private Integer type;
}
package com.lyy.user.util.jwt;
import cn.hutool.core.bean.BeanUtil;
import com.lyy.user.constant.TokenConstants;
import com.lyy.user.domain.JwtInfo;
import com.lyy.user.moudle.user.entity.SysUserInfo;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jose.shaded.json.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author: zhouxudong
* @version: 1.0
* @createTime: 2023/11/17 17:11
* @description:
*/
@Slf4j
public class JwtTokenUtil {
private static Long expireTime = 28800000L;
/**
* 采用HS256算法生成token
*
* @param
* @return
* @throws JOSEException
*/
public static String createToken(SysUserInfo sysUserInfo, List authorities) {
JwtInfo jwtUser =
new JwtInfo()
.setUserId(sysUserInfo.getUserId())
.setUserName(sysUserInfo.getUserName())
.setPhone(sysUserInfo.getPhonenumber())
.setLoginName(sysUserInfo.getLoginName());
JWSHeader jwsHeader = new JWSHeader(JWSAlgorithm.HS256);
JSONObject jsonObject = new JSONObject();
jsonObject.appendField(TokenConstants.DETAILS, jwtUser);
jsonObject.appendField(TokenConstants.AUTHORITIES, authorities);
Long current_time = System.currentTimeMillis();
Long expire_time = current_time + expireTime;
jsonObject.appendField(TokenConstants.EXPIRE_TIME, expire_time);
Payload payload = new Payload(jsonObject);
JWSObject jwsObject = new JWSObject(jwsHeader, payload);
JWSSigner jwsSigner;
try {
jwsSigner = new MACSigner(TokenConstants.SECRET);
try {
jwsObject.sign(jwsSigner);
} catch (JOSEException e) {
log.error("生成token异常", e);
}
} catch (KeyLengthException e) {
log.error("生成token,密钥长度异常", e);
}
return jwsObject.serialize();
}
/**
* 解析token
*
* @param token
* @return
* @throws ParseException
* @throws JOSEException
*/
public static Map<String, Object> parseToken(String token) {
/*if (!ObjectUtils.isEmpty(token) && StringUtils.startsWithIgnoreCase(token, "Bearer ")) {
token = token.substring(7);
}*/
JWSObject jwsObject;
JWSVerifier jwsVerifier;
try {
jwsObject = JWSObject.parse(token);
jwsVerifier = new MACVerifier(TokenConstants.SECRET);
} catch (ParseException | JOSEException e) {
log.error("解析token报错", e);
return null;
}
return verify(jwsObject, jwsVerifier);
}
/**
* 验证token
*
* @param jwsObject
* @param jwsVerifier
* @return
* @throws JOSEException
*/
private static Map<String, Object> verify(JWSObject jwsObject, JWSVerifier jwsVerifier) {
Map<String, Object> resultMap = new HashMap<>();
Payload payload = jwsObject.getPayload();
boolean flag = Boolean.TRUE;
try {
if (jwsObject.verify(jwsVerifier)) {
resultMap.put(TokenConstants.RESULT, TokenConstants.TOKEN_RESULT.TOKEN_PARSE_SUCCESS);
Map<String, Object> jsonObject = payload.toJSONObject();
resultMap.put(TokenConstants.DATA, jsonObject);
if (jsonObject.containsKey(TokenConstants.EXPIRE_TIME)) {
Long expireTime = Long.valueOf(jsonObject.get(TokenConstants.EXPIRE_TIME).toString());
Long nowTime = System.currentTimeMillis();
log.debug("nowTime : " + nowTime);
if (nowTime > expireTime) {
resultMap.clear();
flag = false;
resultMap.put(TokenConstants.RESULT, TokenConstants.TOKEN_RESULT.TOKEN_EXPIRED);
}
}
} else {
flag = false;
resultMap.put(TokenConstants.RESULT, TokenConstants.TOKEN_RESULT.TOKEN_PARSE_FAILED);
}
} catch (JOSEException e) {
log.error("解析token报错", e);
}
resultMap.put(TokenConstants.SUCCESS, flag);
return resultMap;
}
/**
* 返回jwtUser
*
* @param token
* @return
*/
public static JwtInfo getJwtUser(String token) {
Map<String, Object> objectMap = parseToken(token);
Map<String, Object> data = (Map<String, Object>) objectMap.get(TokenConstants.DATA);
JwtInfo jwtUser = BeanUtil.toBean(data.get(TokenConstants.DETAILS), JwtInfo.class);
/*Map<String, Object> detail = (Map<String, Object>) data.get(TokenConstants.DETAILS);
JwtUser jwtUser = new JwtUser();
jwtUser.setUserId(detail.get("userId").toString());
jwtUser.setUserName(detail.get("userName").toString());
jwtUser.setPhone(detail.get("phone").toString());*/
return jwtUser;
}
}
package com.lyy.user.util.redis;
import cn.hutool.extra.spring.SpringUtil;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @Author:zhouxudong
*
* @version: 1.0 @Date: 2023/11/20 9:27 @Description: redis 工具类
*/
public class RedisUtil {
private RedisUtil() {}
@SuppressWarnings("unchecked")
private static RedisTemplate<String, Object> redisTemplate =
SpringUtil.getBean("redisTemplate", RedisTemplate.class);
/**
* 设置有效时间 单位默认秒
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public static boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public static boolean expire(final String key, final long timeout, final TimeUnit unit) {
Boolean ret = redisTemplate.expire(key, timeout, unit);
return ret != null && ret;
}
/**
* 删除单个key
*
* @param key 键
* @return true=删除成功;false=删除失败
*/
public static boolean del(final String key) {
Boolean ret = redisTemplate.delete(key);
return ret != null && ret;
}
/**
* 删除多个key
*
* @param keys 键集合
* @return 成功删除的个数
*/
public static long del(final Collection<String> keys) {
Long ret = redisTemplate.delete(keys);
return ret == null ? 0 : ret;
}
/**
* 存入普通对象
*
* @param key Redis键
* @param value 值
*/
public static void set(final String key, final Object value) {
redisTemplate.opsForValue().set(key, value);
}
// 存储普通对象操作
/**
* 存入普通对象
*
* @param key 键
* @param value 值
* @param timeout 有效期,单位秒
*/
public static void set(final String key, final Object value, final long timeout) {
redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
/**
* 获取普通对象
*
* @param key 键
* @return 对象
*/
public static Object get(final String key) {
return redisTemplate.opsForValue().get(key);
}
// 存储Hash操作
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param filed Hash filed键
* @param value 值
*/
public static void hPut(final String key, final String filed, final Object value) {
redisTemplate.opsForHash().put(key, filed, value);
}
/**
* 往Hash中存入多个数据
*
* @param key Redis键
* @param filedMap Hash键值对
*/
public static void hPutAll(final String key, final Map<String, Object> filedMap) {
redisTemplate.opsForHash().putAll(key, filedMap);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param filed Hash filed键
* @return Hash中的对象
*/
public static Object hGet(final String key, final String filed) {
return redisTemplate.opsForHash().get(key, filed);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param fileds Hash filed键集合
* @return Hash对象集合
*/
public static List<Object> hMultiGet(final String key, final Collection<Object> fileds) {
return redisTemplate.opsForHash().multiGet(key, fileds);
}
// 存储Set相关操作
/**
* 往Set中存入数据
*
* @param key Redis键
* @param values 值
* @return 存入的个数
*/
public static long sSet(final String key, final Object... values) {
Long count = redisTemplate.opsForSet().add(key, values);
return count == null ? 0 : count;
}
/**
* 删除Set中的数据
*
* @param key Redis键
* @param values 值
* @return 移除的个数
*/
public static long sDel(final String key, final Object... values) {
Long count = redisTemplate.opsForSet().remove(key, values);
return count == null ? 0 : count;
}
// 存储List相关操作
/**
* 往List左侧中存入数据
*
* @param key Redis键
* @param value 数据
* @return 存入的个数
*/
public static long lPush(final String key, final Object value) {
Long count = redisTemplate.opsForList().leftPush(key, value);
return count == null ? 0 : count;
}
/**
* 往List右侧中存入数据
*
* @param key Redis键
* @param value 数据
* @return 存入的个数
*/
public static long rPush(final String key, final Object value) {
Long count = redisTemplate.opsForList().rightPush(key, value);
return count == null ? 0 : count;
}
/**
* 往List中左侧存入多个数据
*
* @param key Redis键
* @param values 多个数据
* @return 存入的个数
*/
public static long lPushAll(final String key, final Collection<Object> values) {
Long count = redisTemplate.opsForList().leftPushAll(key, values);
return count == null ? 0 : count;
}
/**
* 往List中左侧存入多个数据
*
* @param key Redis键
* @param values 多个数据
* @return 存入的个数
*/
public static long lPushAll(final String key, final Object... values) {
Long count = redisTemplate.opsForList().leftPushAll(key, values);
return count == null ? 0 : count;
}
/**
* 往List中右侧存入多个数据
*
* @param key Redis键
* @param values 多个数据
* @return 存入的个数
*/
public static long rPushAll(final String key, final Collection<Object> values) {
Long count = redisTemplate.opsForList().rightPushAll(key, values);
return count == null ? 0 : count;
}
/**
* 往List中右侧存入多个数据
*
* @param key Redis键
* @param values 多个数据
* @return 存入的个数
*/
public static long rPushAll(final String key, final Object... values) {
Long count = redisTemplate.opsForList().rightPushAll(key, values);
return count == null ? 0 : count;
}
/**
* 从List中获取begin到end之间的元素
*
* @param key Redis键
* @param start 开始位置
* @param end 结束位置(start=0,end=-1表示获取全部元素)
* @return List对象
*/
public static List<Object> listGetRange(final String key, final int start, final int end) {
return redisTemplate.opsForList().range(key, start, end);
}
/**
* 从List左侧弹出数据
*
* @param key Redis键
* @return 对象
*/
public static Object listGetL(final String key) {
return redisTemplate.opsForList().leftPop(key);
}
/**
* 从List右侧弹出数据
*
* @param key Redis键
* @return 对象
*/
public static Object listGetR(final String key) {
return redisTemplate.opsForList().rightPop(key);
}
}
package com.lyy.user.util.sms;
import com.lyy.user.config.sms.SmsConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @Author:zhouxudong
* @version: 1.0
* @Date: 2023/11/17 10:40
* @Description: 发送短信 工具
*/
@Configuration
@RequiredArgsConstructor
@Slf4j
public class SendMsgUtils {
private final SmsConfig smsConfig;
//无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值
private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"";
//无需修改,用于格式化鉴权头域,给"Authorization"参数赋值
private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\"";
/**
* @description:
* @date: 2023/11/17 11:02
* @param: [receiver 手机号 多个用逗号隔开 并且添加国家码(86), templateId 模板id, templateParas 模板替换符]
* 选填,使用无变量模板时请赋空值 String templateParas = "";
* 单变量模板示例:模板内容为"您的验证码是${1}"时,templateParas可填写为"[\"369751\"]"
* 双变量模板示例:模板内容为"您有${1}件快递请到${2}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]"
* 模板中的每个变量都必须赋值,且取值不能为空
* @return: void
**/
public String sendMsg(String phone, String templateId, String templateParas) {
//选填,statusCallBack短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
//请求Body,不携带签名名称时,signature请填null
String body = buildRequestBody(smsConfig.getSender(), phone, templateId, templateParas, "", smsConfig.getSignature());
if (null == body || body.isEmpty()) {
log.error("构建短信消息体为空");
return null;
}
//请求Headers中的X-WSSE参数值
String wsseHeader = buildWsseHeader(smsConfig.getAppKey(), smsConfig.getAppSecret());
if (null == wsseHeader || wsseHeader.isEmpty()) {
log.error("构建短信消息头为空");
return null;
}
Writer out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
HttpsURLConnection connection;
InputStream is = null;
HostnameVerifier hv = (hostname, session) -> true;
// trustAllHttpsCertificates();
try {
URL realUrl = new URL(smsConfig.getAppUrl());
connection = (HttpsURLConnection) realUrl.openConnection();
connection.setHostnameVerifier(hv);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(true);
//请求方法
connection.setRequestMethod("POST");
//请求Headers参数
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Authorization", AUTH_HEADER_VALUE);
connection.setRequestProperty("X-WSSE", wsseHeader);
connection.connect();
out = new OutputStreamWriter(connection.getOutputStream());
out.write(body); //发送请求Body参数
out.flush();
out.close();
int status = connection.getResponseCode();
if (200 == status) { //200
is = connection.getInputStream();
} else { //400/401
is = connection.getErrorStream();
}
in = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info(result.toString()); //打印响应消息实体
return result.toString();
} catch (Exception e) {
log.error("发送短信异常:", e);
} finally {
try {
if (null != out) {
out.close();
}
if (null != is) {
is.close();
}
if (null != in) {
in.close();
}
} catch (Exception e) {
log.error("发送短信异常:", e);
}
}
return null;
}
/**
* 构造请求Body体
*
* @param sender 签名通道号
* @param phone 手机号
* @param templateId 模板id
* @param templateParas 模板参数
* @param statusCallBack 回调 默认为空
* @param signature | 签名名称,使用国内短信通用模板时填写
*/
static String buildRequestBody(String sender, String phone, String templateId, String templateParas,
String statusCallBack, String signature) {
if (null == sender || null == phone || null == templateId || sender.isEmpty() || phone.isEmpty()
|| templateId.isEmpty()) {
System.out.println("buildRequestBody(): sender, receiver or templateId is null.");
return null;
}
Map<String, String> map = new HashMap<String, String>();
map.put("from", sender);
map.put("to", phone);
map.put("templateId", templateId);
if (null != templateParas && !templateParas.isEmpty()) {
map.put("templateParas", templateParas);
}
if (null != statusCallBack && !statusCallBack.isEmpty()) {
map.put("statusCallback", statusCallBack);
}
if (null != signature && !signature.isEmpty()) {
map.put("signature", signature);
}
StringBuilder sb = new StringBuilder();
String temp = "";
for (String s : map.keySet()) {
try {
temp = URLEncoder.encode(map.get(s), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
sb.append(s).append("=").append(temp).append("&");
}
return sb.deleteCharAt(sb.length() - 1).toString();
}
/**
* 构造X-WSSE参数值
*
* @param appKey key
* @param appSecret secret
*/
static String buildWsseHeader(String appKey, String appSecret) {
if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) {
System.out.println("buildWsseHeader(): appKey or appSecret is null.");
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
String time = sdf.format(new Date()); //Created
String nonce = UUID.randomUUID().toString().replace("-", ""); //Nonce
MessageDigest md;
byte[] passwordDigest = null;
try {
md = MessageDigest.getInstance("SHA-256");
md.update((nonce + time + appSecret).getBytes());
passwordDigest = md.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//如果JDK版本是1.8,请加载原生Base64类,并使用如下代码
String passwordDigestBase64Str = Base64.getEncoder().encodeToString(passwordDigest); //PasswordDigest
return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time);
}
/*** @throws Exception
*/
static void trustAllHttpsCertificates() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
}
spring:
config:
activate:
on-profile: dev
#spring 默认数据库连接池
datasource:
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://rm-2ze10ohzb1898j5qdfo.mysql.rds.aliyuncs.com:3306/liyeyun?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false
username: liyeyun
password: CF**ldcn
hikari:
maximum-pool-size: 10
minimum-idle: 5
connection-timeout: 10000
redis:
host: r-2zekq6swp5wr808a3lpd.redis.rds.aliyuncs.com
port: 6379
password: techbook4redis#&20190909
timeout: 3000
database: 3
lettuce:
pool:
# 连接池中最大连接数,负数表示没有限制
max-active: 12
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 0
# 最大阻塞等待时间,负数表示没有限制
max-wait: 5000
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印日志
spring:
config:
activate:
on-profile: pro
#spring 默认数据库连接池
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://rm-2ze10ohzb1898j5qdfo.mysql.rds.aliyuncs.com:3306/liyeyun?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true
username: liyeyun
password: CF**ldcn
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
minimum-idle: 5
connection-timeout: 10000
redis:
host: r-2zekq6swp5wr808a3lpd.redis.rds.aliyuncs.com
port: 6379
password: techbook4redis#&20190909
timeout: 3000
database: 3
lettuce:
pool:
max-active: 12
max-idle: 8
min-idle: 0
max-wait: 5000
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl # 打印日志
spring:
config:
activate:
on-profile: test
#spring 默认数据库连接池
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://rm-2ze10ohzb1898j5qdfo.mysql.rds.aliyuncs.com:3306/liyeyun?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true
username: liyeyun
password: CF**ldcn
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
minimum-idle: 5
connection-timeout: 10000
redis:
host: r-2zekq6swp5wr808a3lpd.redis.rds.aliyuncs.com
port: 6379
password: techbook4redis#&20190909
timeout: 3000
database: 3
lettuce:
pool:
max-active: 12
max-idle: 8
min-idle: 0
max-wait: 5000
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印日志
spring:
profiles:
active: dev
application:
name: liyeyun-user-service
main:
allow-bean-definition-overriding: true
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
server:
port: 8083
servlet:
# 应用的访问路径
context-path: /lyy
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
cache-enabled: true
call-setters-on-nulls: true
return-instance-for-empty-row: true
jdbc-type-for-null: varchar
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
#注解自增
id-type: ASSIGN_ID
#数据库大写下划线转换
capital-mode: true
#表名是否使用驼峰转下划线命名
table-underline: true
#逻辑已删除值
logic-delete-value: 0
logic-not-delete-value: 1
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="projectName" value="liyeyun-user-service"/>
<springProperty scope="context" name="moduleName" source="spring.application.name"
defaultValue="liyeyun-user-service"/>
<springProperty scope="context" name="logNum" source="log.num" defaultValue="01"/>
<springProfile name="test">
<property name="logPathPrefix" value="/usr/local/webapps/logs"/>
</springProfile>
<springProfile name="pro">
<property name="logPathPrefix" value="/usr/local/webapps/logs"/>
</springProfile>
<property name="logger.path" value="${logPathPrefix}/${projectName}"/>
<property name="maxHistory" value="30"/>
<property name="maxFileSize" value="50MB"/>
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logger.path}/debug/${moduleName}-${logNum}-debug.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logger.path}/debug/${moduleName}-${logNum}-debug-%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logger.path}/info/${moduleName}-${logNum}-info.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logger.path}/info/${moduleName}-${logNum}-info-%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logger.path}/warn/${moduleName}-${logNum}-warn.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logger.path}/warn/${moduleName}-${logNum}-warn-%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logger.path}/error/${moduleName}-${logNum}-error.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logger.path}/error/${moduleName}-${logNum}-error-%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<springProfile name="dev">
<root level="info">
<appender-ref ref="CONSOLE"/>
</root>
<logger name="com.lyy.user" level="debug" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
</springProfile>
<springProfile name="test">
<root level="info">
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<logger name="com.lyy.user" level="debug" additivity="false">
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</logger>
</springProfile>
<springProfile name="pro">
<root level="info">
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<logger name="com.lyy.user" level="info" additivity="false">
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</logger>
</springProfile>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lyy.user.moudle.user.mapper.SysUserInfoMapper">
<resultMap id="BaseResultMap" type="com.lyy.user.moudle.user.entity.SysUserInfo">
<id property="userId" column="user_id" jdbcType="INTEGER"/>
<result property="deptId" column="dept_id" jdbcType="INTEGER"/>
<result property="loginName" column="login_name" jdbcType="VARCHAR"/>
<result property="userName" column="user_name" jdbcType="VARCHAR"/>
<result property="userType" column="user_type" jdbcType="VARCHAR"/>
<result property="email" column="email" jdbcType="VARCHAR"/>
<result property="phonenumber" column="phonenumber" jdbcType="VARCHAR"/>
<result property="sex" column="sex" jdbcType="CHAR"/>
<result property="avatar" column="avatar" jdbcType="VARCHAR"/>
<result property="password" column="password" jdbcType="VARCHAR"/>
<result property="salt" column="salt" jdbcType="VARCHAR"/>
<result property="status" column="status" jdbcType="CHAR"/>
<result property="delFlag" column="del_flag" jdbcType="CHAR"/>
<result property="loginIp" column="login_ip" jdbcType="VARCHAR"/>
<result property="loginDate" column="login_date" jdbcType="TIMESTAMP"/>
<result property="pwdUpdateDate" column="pwd_update_date" jdbcType="TIMESTAMP"/>
<result property="createBy" column="create_by" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
<result property="remark" column="remark" jdbcType="VARCHAR"/>
</resultMap>
<sql id="Base_Column_List">
user_id,dept_id,login_name,
user_name,user_type,email,
phonenumber,sex,avatar,
password,salt,status,
del_flag,login_ip,login_date,
pwd_update_date,create_by,create_time,
update_by,update_time,remark
</sql>
</mapper>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment