perf(修改): 使用Redis验证登录

This commit is contained in:
bunny 2024-03-18 18:45:35 +08:00
parent d0f34716a6
commit 1354d10622
36 changed files with 1390 additions and 56 deletions

View File

@ -2,6 +2,7 @@
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile default="true" name="Default" enabled="true" />
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />

View File

@ -0,0 +1,55 @@
package com.sky.common.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
@Configuration
@Slf4j
@EnableKnife4j
public class Knife4jConfiguration {
/**
* 通过knife4j生成接口文档
* 管理端接口
*
* @return Docket
*/
@Bean
public Docket docketAdmin() {
log.info("A管理端接口");
// 添加作者
springfox.documentation.service.Contact contact = new Contact("Bunny", "1319900154@qq.com", "1319900154@qq.com");
ApiInfo apiInfo = new ApiInfoBuilder().title("苍穹外卖项目接口文档").version("2.0").description("苍穹外卖项目接口文档").contact(contact).build();
return new Docket(DocumentationType.SWAGGER_2).groupName("A管理端接口")
.apiInfo(apiInfo).select().apis(RequestHandlerSelectors.basePackage("com.sky.controller.admin"))
.paths(PathSelectors.any()).build();
}
@Bean
public Docket docketUser() {
log.info("B用户端接口");
ApiInfo apiInfo = new ApiInfoBuilder().title("苍穹外卖项目接口文档").version("2.0").description("苍穹外卖项目接口文档").build();
return new Docket(DocumentationType.SWAGGER_2).groupName("B用户端接口")
.apiInfo(apiInfo).select().apis(RequestHandlerSelectors.basePackage("com.sky.controller.user"))
.paths(PathSelectors.any()).build();
}
@Bean
public Docket docketNotify() {
log.info("Pay支付接口");
ApiInfo apiInfo = new ApiInfoBuilder().title("苍穹外卖项目接口文档").version("2.0").description("苍穹外卖项目接口文档").build();
return new Docket(DocumentationType.SWAGGER_2).groupName("Pay支付接口")
.apiInfo(apiInfo).select().apis(RequestHandlerSelectors.basePackage("com.sky.controller.notify"))
.paths(PathSelectors.any()).build();
}
}

View File

@ -0,0 +1,95 @@
package com.sky.common.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Configuration
@Slf4j
public class RedisConfiguration {
/**
* 使用StringRedisSerializer序列化为字符串
*/
@Bean
public RedisTemplate redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(connectionFactory);
// 设置key序列化为string
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 设置value序列化为JSON使用GenericJackson2JsonRedisSerializer替换默认序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
/**
* 解决cache(@Cacheable)把数据缓存到redis中的value是乱码问题
*/
@Bean
@SuppressWarnings("all")
public CacheManager cacheManager(RedisConnectionFactory factory) {
StringRedisSerializer redisSerializer = new StringRedisSerializer();
// json序列化
Jackson2JsonRedisSerializer<Object> serializer = jsonRedisSerializer();
// 配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheConfiguration redisCacheConfiguration = config
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(redisCacheConfiguration).build();
return cacheManager;
}
/**
* 指定的日期模式
*/
public Jackson2JsonRedisSerializer<Object> jsonRedisSerializer() {
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
// 设置ObjectMapper访问权限
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 记录序列化之后的数据类型方便反序列化
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
// LocalDatetime序列化默认不兼容jdk8日期序列化
JavaTimeModule timeModule = new JavaTimeModule();
timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
// 关闭默认的日期格式化方式默认UTC日期格式 yyyy-MM-ddTHH:mm:ss.SSS
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.registerModule(timeModule);
serializer.setObjectMapper(mapper);
return serializer;
}
}

View File

@ -0,0 +1,16 @@
package com.sky.common.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
@Slf4j
public class RestTemplateConfiguration {
@Bean
public RestTemplate restTemplate() {
log.info("注入restTemplate");
return new RestTemplate();
}
}

View File

@ -0,0 +1,59 @@
package com.sky.common.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sky.common.interceptor.JwtTokenUserInterceptor;
import com.sky.common.interceptor.RedisTokenAdminInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Autowired
RedisTokenAdminInterceptor adminInterceptor;
@Autowired
JwtTokenUserInterceptor userInterceptor;
/**
* 注册自定义拦截器
*
* @param registry InterceptorRegistry
*/
protected void addInterceptors(InterceptorRegistry registry) {
log.info("开始注册自定义拦截器...");
registry.addInterceptor(adminInterceptor).addPathPatterns("/admin/**")
.excludePathPatterns("/admin/employee/login");
registry.addInterceptor(userInterceptor).addPathPatterns("/user/**")
.excludePathPatterns("/user/user/login")
.excludePathPatterns("/user/shop/status");
}
/**
* 扩展Spring MVC框架的消息转化器
*
* @param converters 转换器
*/
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
// 创建一个消息转换器对象
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 需要为消息转换器设置一个对象转换器对象转换器可以将Java对象序列化为json数据
converter.setObjectMapper(new ObjectMapper());
// 将自己的消息转化器加入容器中
converters.add(0, converter);
}
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("设置静态资源映射");
registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}

View File

@ -0,0 +1,19 @@
package com.sky.common.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* WebSocket配置类用于注册WebSocket的Bean
*/
@Configuration
@Slf4j
public class WebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
log.info("WebSocket配置类用于注册WebSocket的Bean");
return new ServerEndpointExporter();
}
}

View File

@ -0,0 +1,30 @@
package com.sky.common.context;
public class BaseContext {
public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
/**
* 获取当前用户id
*
* @return 用户id
*/
public static Long getUserId() {
return threadLocal.get();
}
/**
* 设置用户id
*
* @param userId 用户id
*/
public static void setUserId(Long userId) {
threadLocal.set(userId);
}
/**
* 移出当前id
*/
public static void removeCurrentId() {
threadLocal.remove();
}
}

View File

@ -0,0 +1,36 @@
package com.sky.common.handler;
import com.sky.common.constant.MessageConstant;
import com.sky.common.exception.BaseException;
import com.sky.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.sql.SQLIntegrityConstraintViolationException;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
// 捕获业务异常
@ExceptionHandler
public Result<String> exceptionHandler(BaseException exception) {
log.error("异常信息:{}", exception.getMessage());
return Result.error(exception.getMessage());
}
// 处理SQL异常
public Result<String> exceptionHandler(SQLIntegrityConstraintViolationException exception) {
log.error("处理SQL异常:{}", exception.getMessage());
String message = exception.getMessage();
if (message.contains("Duplicate entry")) {
// 截取用户名
String username = message.split(" ")[2];
// 错误信息
String errorMessage = username + MessageConstant.ALREADY_EXISTS;
return Result.error(errorMessage);
} else {
return Result.error(MessageConstant.UNKNOWN_ERROR);
}
}
}

View File

@ -0,0 +1,45 @@
package com.sky.common.interceptor;
import com.sky.common.constant.JwtClaimsConstant;
import com.sky.common.context.BaseContext;
import com.sky.common.properties.RedisTokenProperties;
import com.sky.common.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
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;
@Component
@Slf4j
public class JwtTokenUserInterceptor implements HandlerInterceptor {
@Autowired
RedisTokenProperties redisTokenProperties;
public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) throws Exception {
// 判断当前拦截到的是Controller方法还是其它资源
if (!(handler instanceof HandlerMethod)) {
// 当前拦截到的不是动态方法直接放行
return true;
}
// 1. 从请求头中获取令牌
String token = request.getHeader(redisTokenProperties.getUserTokenName());
// 2. 校验令牌
log.info("jwt校验{}", token);
try {
Claims claims = JwtUtil.parseJWT(redisTokenProperties.getUserSecretKey(), token);
Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
BaseContext.setUserId(userId);
return true;
} catch (Exception exception) {
response.setStatus(HttpStatus.SC_UNAUTHORIZED);
return false;
}
}
}

View File

@ -0,0 +1,49 @@
package com.sky.common.interceptor;
import com.sky.common.context.BaseContext;
import com.sky.common.properties.RedisTokenProperties;
import com.sky.common.utils.InterceptorUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Slf4j
public class RedisTokenAdminInterceptor implements HandlerInterceptor {
@Autowired
private RedisTokenProperties redisTokenProperties;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws IOException, LoginException {
// 判断当前兰街道的是Controller的方法还是其它资源 拦截到的不是动态方法直接放行
if (!(handler instanceof HandlerMethod)) return true;
// 1. 从请求头中获取令牌
String token = request.getHeader(redisTokenProperties.getAdminTokenName());
log.info("jwt校验{}", token);
if (token == null) {
InterceptorUtil.unLoginInterceptor(response);
return false;
}
try {
Long empId = (Long) redisTemplate.opsForValue().get(token);
log.info("当前员工ID{}", empId);
// 3. 通过放行
BaseContext.setUserId(empId);
return true;
} catch (Exception exception) {
return false;
}
}
}

View File

@ -0,0 +1,47 @@
package com.sky.common.json;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
* 对象映射器基于Jackson将Java对象转为JSON或者将JSON转为Java对象
* 将JSON转为Java对象过程--JSON反序列化Java对象
* 将Java对象转为JSON--序列化Java对象到JSON
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
// public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
// 收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
// 反序列化时属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
// 注册功能模块 例如可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}

View File

@ -5,9 +5,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "sky.jwt")
@ConfigurationProperties(prefix = "sky.redis-token")
@Data
public class JwtProperties {
public class RedisTokenProperties {
/**
* 管理端员工生成jwt令牌相关配置
*/

View File

@ -0,0 +1,19 @@
package com.sky.common.result;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* 封装分页查询结果
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult<T> implements Serializable {
private long total; // 总记录数
private List<T> records; // 当前页数据集合
}

View File

@ -0,0 +1,40 @@
package com.sky.common.result;
import lombok.Data;
import java.io.Serializable;
/**
* 后端统一返回结果
*
* @param <T>
*/
@Data
public class Result<T> implements Serializable {
private Integer code; // 编码1成功0和其它数字为失败
private String message; // 错误信息
private T data; // 数据
// 成功
public static <T> Result<T> success() {
Result<T> result = new Result<>();
result.code = 1;
return result;
}
// 有数据返回
public static <T> Result<T> success(T object) {
Result<T> result = new Result<>();
result.code = 1;
result.data = object;
return result;
}
// 错误返回
public static <T> Result<T> error(String message) {
Result<T> result = new Result<>();
result.code = 0;
result.message = message;
return result;
}
}

View File

@ -0,0 +1,168 @@
package com.sky.common.utils;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Http工具类
*/
public class HttpClientUtil {
static final int TIMEOUT_MSEC = 5 * 1000;
/**
* 发送GET方式请求
*/
public static String doGet(String url, Map<String, String> paramMap) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
String result = "";
CloseableHttpResponse response = null;
try {
URIBuilder builder = new URIBuilder(url);
if (paramMap != null) {
for (String key : paramMap.keySet()) {
builder.addParameter(key, paramMap.get(key));
}
}
URI uri = builder.build();
// 创建GET请求
HttpGet httpGet = new HttpGet(uri);
// 发送请求
response = httpClient.execute(httpGet);
// 判断响应状态
if (response.getStatusLine().getStatusCode() == 200) {
result = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 发送POST方式请求
*/
public static String doPost(String url, Map<String, String> paramMap) throws IOException {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建参数列表
if (paramMap != null) {
List<NameValuePair> paramList = new ArrayList();
for (Map.Entry<String, String> param : paramMap.entrySet()) {
paramList.add(new BasicNameValuePair(param.getKey(), param.getValue()));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
httpPost.setEntity(entity);
}
httpPost.setConfig(builderRequestConfig());
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
throw e;
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
/**
* 发送POST方式请求
*/
public static String doPost4Json(String url, Map<String, String> paramMap) throws IOException {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
if (paramMap != null) {
// 构造json格式数据
JSONObject jsonObject = new JSONObject();
for (Map.Entry<String, String> param : paramMap.entrySet()) {
jsonObject.put(param.getKey(), param.getValue());
}
StringEntity entity = new StringEntity(jsonObject.toString(), "utf-8");
// 设置请求编码
entity.setContentEncoding("utf-8");
// 设置数据类型
entity.setContentType("application/json");
httpPost.setEntity(entity);
}
httpPost.setConfig(builderRequestConfig());
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
throw e;
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
private static RequestConfig builderRequestConfig() {
return RequestConfig.custom()
.setConnectTimeout(TIMEOUT_MSEC)
.setConnectionRequestTimeout(TIMEOUT_MSEC)
.setSocketTimeout(TIMEOUT_MSEC).build();
}
}

View File

@ -0,0 +1,42 @@
package com.sky.common.utils;
import com.alibaba.fastjson.JSON;
import com.sky.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
public class InterceptorUtil {
/**
* 用户未登录返回响应
*
* @param response 返回体
*/
public static void unLoginInterceptor(HttpServletResponse response) throws IOException {
log.info("用户未登录");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
Result<String> result = new Result<>();
result.setCode(HttpServletResponse.SC_UNAUTHORIZED);
result.setData("未登录");
result.setMessage("请先登录");
// 将消息写入响应体
response.getWriter().write(JSON.toJSONString(result));
}
public static void otherLoginInterceptor(HttpServletResponse response) throws IOException {
log.info("其它异常");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
Result<String> result = new Result<>();
result.setCode(HttpServletResponse.SC_UNAUTHORIZED);
result.setData("未登录");
result.setMessage("请先登录");
// 将消息写入响应体
response.getWriter().write(JSON.toJSONString(result));
}
}

View File

@ -0,0 +1,53 @@
package com.sky.common.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
/**
* 生成JWT
* 使用Hs256算法, 私匙使用固定秘钥
*
* @param secretKey jwt秘钥
* @param ttlMillis jwt过期时间(毫秒)
* @param claims 设置的信息
* @return 加密后JWT
*/
public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {
// 指定签名的时候使用的签名算法也就是header那部分
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
// 生成JWT的时间
long expMillis = System.currentTimeMillis() + ttlMillis;
Date date = new Date(expMillis);
JwtBuilder builder = Jwts.builder()
// 如果有私有声明一定要先设置这个自己创建的私有的声明这个是给builder的claim赋值一旦写在标准的声明赋值之后就是覆盖了那些标准的声明的
.setClaims(claims)
// 设置签名使用的签名算法和签名使用的秘钥
.signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
// 设置过期时间
.setExpiration(date);
return builder.compact();
}
/**
* Token解密
*
* @param secretKey jwt秘钥
* @param token token
* @return 解密后数据
*/
public static Claims parseJWT(String secretKey, String token) {
// 得到DefaultJwtParser
return Jwts.parser()
// 设置签名的秘钥
.setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
// 设置需要解析的jwt
.parseClaimsJwt(token).getBody();
}
}

View File

@ -0,0 +1,34 @@
package com.sky.common.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5 {
public static String encrypt(String strSrc) {
try {
char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f'};
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (byte b : bytes) {
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出错+" + e);
}
}
public static void main(String[] args) {
System.out.println(MD5.encrypt("111111"));
}
}

View File

@ -0,0 +1,112 @@
package com.sky.common.utils;
import com.sky.common.properties.MinioProperties;
import io.minio.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.InputStream;
@Component
@RequiredArgsConstructor
@Slf4j
public class MinioUtils {
private final MinioClient minioClient;
private final MinioProperties minioProperties;
/**
* 判断桶是否存在
*
* @param bucketName String
* @return found
*/
public boolean bucketExists(String bucketName) {
boolean found = false;
try {
found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
e.printStackTrace();
}
return found;
}
/**
* 如果桶不存在就新建
*
* @param bucketName String
*/
public void bucketCreate(String bucketName) {
boolean exists = bucketExists(bucketName);
if (!exists) {
try {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 上传文件
*
* @param fileName 文件名
* @param inputStream 输入流
* @param size 文件大小
*/
public String uploadFile(String bucketName, String fileName, InputStream inputStream, Long size) {
try {
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.stream(inputStream, size, -1)
.build());
return minioProperties.getEndpointUrl() + "/" + bucketName + "/" + fileName;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 上传文件
*
* @param fileName 文件名
* @param inputStream 输入流
* @param size 文件大小
* @param contentType 文件类型
*/
public String uploadFile(String bucketName, String fileName, InputStream inputStream, Long size, String contentType) {
try {
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.stream(inputStream, size, -1)
.contentType(contentType)
.build());
return minioProperties.getEndpointUrl() + "/" + bucketName + "/" + fileName;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取文件
*
* @param bucketName 桶名称
* @param fileName 对象名称
*/
public InputStream getFile(String bucketName, String fileName) {
try {
return minioClient.getObject(GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,20 @@
package com.sky.common.utils;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Set;
@Component
@RequiredArgsConstructor
public class RedisUtil {
private static final RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
public static void cleanCache(String key) {
Set<Object> keys = redisTemplate.keys(key);
if (keys != null) {
redisTemplate.delete(keys);
}
}
}

View File

@ -0,0 +1,27 @@
package com.sky.common.utils;
import lombok.RequiredArgsConstructor;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.io.Serializable;
@Component
@RequiredArgsConstructor
public class RestTemplateUtil<T> implements Serializable {
private final RestTemplate restTemplate;
public ResponseEntity<?> requestGet(String url, T t) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<T> entity = new HttpEntity<T>(t, headers);
ResponseEntity<?> response = restTemplate.exchange(url, HttpMethod.GET, entity, new ParameterizedTypeReference<T>() {
});
return response.getStatusCode().is2xxSuccessful() ? response : null;
}
}

View File

@ -0,0 +1,225 @@
package com.sky.common.utils;
import com.alibaba.fastjson.JSONObject;
import com.sky.common.context.BaseContext;
import com.sky.common.properties.WeChatProperties;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
/**
* 微信支付工具类
*/
@Component
@RequiredArgsConstructor
public class WeChatPayUtil {
// 微信支付下单接口地址
public static final String JSAPI = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
// 申请退款接口地址
public static final String REFUNDS = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
private final WeChatProperties weChatProperties;
/**
* 获取调用微信接口的客户端工具对象
*/
private CloseableHttpClient getClient() {
PrivateKey merchantPrivateKey = null;
try {
// merchantPrivateKey商户API私钥如何加载商户API私钥请看常见问题
merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath())));
// 加载平台证书文件
X509Certificate x509Certificate = PemUtil.loadCertificate(new FileInputStream(new File(weChatProperties.getWeChatPayCertFilePath())));
// wechatPayCertificates微信支付平台证书列表你也可以使用后面章节提到的定时更新平台证书功能而不需要关心平台证书的来龙去脉
List<X509Certificate> wechatPayCertificates = Collections.singletonList(x509Certificate);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(weChatProperties.getMchid(), weChatProperties.getMchSerialNo(), merchantPrivateKey)
.withWechatPay(wechatPayCertificates);
// 通过WechatPayHttpClientBuilder构造的HttpClient会自动的处理签名和验签
CloseableHttpClient httpClient = builder.build();
return httpClient;
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
/**
* 发送post方式请求
*
* @param url
* @param body
* @return
*/
private String post(String url, String body) throws Exception {
CloseableHttpClient httpClient = getClient();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString());
httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
httpPost.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo());
httpPost.setEntity(new StringEntity(body, "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
return EntityUtils.toString(response.getEntity());
} finally {
httpClient.close();
response.close();
}
}
/**
* 发送get方式请求
*
* @param url
* @return
*/
private String get(String url) throws Exception {
CloseableHttpClient httpClient = getClient();
HttpGet httpGet = new HttpGet(url);
httpGet.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString());
httpGet.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
httpGet.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo());
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
return EntityUtils.toString(response.getEntity());
} finally {
httpClient.close();
response.close();
}
}
/**
* jsapi下单
*
* @param orderNum 商户订单号
* @param total 总金额
* @param description 商品描述
* @param openid 微信用户的openid
*/
private String jsapi(String orderNum, BigDecimal total, String description, String openid) throws Exception {
JSONObject jsonObject = new JSONObject();
jsonObject.put("appid", weChatProperties.getAppid());
jsonObject.put("mchid", weChatProperties.getMchid());
jsonObject.put("description", description);
jsonObject.put("out_trade_no", orderNum);
jsonObject.put("notify_url", weChatProperties.getNotifyUrl());
JSONObject amount = new JSONObject();
amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP).intValue());
amount.put("currency", "CNY");
jsonObject.put("amount", amount);
JSONObject payer = new JSONObject();
payer.put("openid", openid);
jsonObject.put("payer", payer);
String body = jsonObject.toJSONString();
return post(JSAPI, body);
}
/**
* 小程序支付
*
* @param orderNum 商户订单号
* @param total 金额单位
* @param description 商品描述
* @param openid 微信用户的openid
* @return
*/
public JSONObject pay(String orderNum, BigDecimal total, String description, String openid) throws Exception {
// 统一下单生成预支付交易单
// String bodyAsString = jsapi(orderNum, total, description, openid);
// 解析返回结果
// JSONObject jsonObject = JSON.parseObject(bodyAsString);
// String prepayId = jsonObject.getString("prepay_id");
String prepayId = "bunny-" + UUID.randomUUID();
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = RandomStringUtils.randomNumeric(32);
ArrayList<Object> list = new ArrayList<>();
list.add(weChatProperties.getAppid());
list.add(timeStamp);
list.add(nonceStr);
list.add("prepay_id=" + prepayId);
// 二次签名调起支付需要重新签名
// StringBuilder stringBuilder = new StringBuilder();
// for (Object o : list) {
// stringBuilder.append(o).append("\n");
// }
// String signMessage = stringBuilder.toString();
// byte[] message = signMessage.getBytes();
// Signature signature = Signature.getInstance("SHA256withRSA");
// signature.initSign(PemUtil.loadPrivateKey(Files.newInputStream(new File(weChatProperties.getPrivateKeyFilePath()).toPath())));
// signature.update(message);
// String packageSign = Base64.getEncoder().encodeToString(signature.sign());
// 构造数据给微信小程序用于调起微信支付
JSONObject jo = new JSONObject();
jo.put("timeStamp", timeStamp);
jo.put("nonceStr", nonceStr);
jo.put("package", "prepay_id=" + prepayId);
jo.put("signType", "RSA");
jo.put("paySign", BaseContext.getUserId() + "-" + prepayId);
return jo;
// return jsonObject;
}
/**
* 申请退款
*
* @param outTradeNo 商户订单号
* @param outRefundNo 商户退款单号
* @param refund 退款金额
* @param total 原订单金额
* @return
*/
public String refund(String outTradeNo, String outRefundNo, BigDecimal refund, BigDecimal total) throws Exception {
JSONObject jsonObject = new JSONObject();
jsonObject.put("out_trade_no", outTradeNo);
jsonObject.put("out_refund_no", outRefundNo);
JSONObject amount = new JSONObject();
amount.put("refund", refund.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP).intValue());
amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP).intValue());
amount.put("currency", "CNY");
jsonObject.put("amount", amount);
jsonObject.put("notify_url", weChatProperties.getRefundNotifyUrl());
String body = jsonObject.toJSONString();
// 调用申请退款接口
return post(REFUNDS, body);
}
}

View File

@ -1,4 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
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>
<parent>
@ -22,5 +22,9 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,6 +1,9 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>
<parent>
<groupId>com.sky</groupId>
<artifactId>dev-sky-serve-v1</artifactId>
@ -9,26 +12,12 @@
<artifactId>sky-server</artifactId>
<packaging>jar</packaging>
<name>sky-server</name>
<url>http://maven.apache.org</url>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.sky</groupId>
<artifactId>sky-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sky</groupId>
<artifactId>sky-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
@ -131,6 +120,17 @@
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
<dependency>
<groupId>com.sky</groupId>
<artifactId>sky-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sky</groupId>
<artifactId>sky-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
@ -149,4 +149,4 @@
</plugin>
</plugins>
</build>
</project>
</project>

View File

@ -14,6 +14,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@Slf4j
public class SkyApplication {
public static void main(String[] args) {
SpringApplication.run(SkyApplication.class);
SpringApplication.run(SkyApplication.class, args);
}
}

View File

@ -0,0 +1,14 @@
package com.sky.annotation;
import com.sky.common.enumeration.OperationType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
OperationType value();
}

View File

@ -0,0 +1,13 @@
package com.sky.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
* 自定义切面实现公共字段自动填充处理逻辑
*/
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
}

View File

@ -1,10 +1,7 @@
package com.sky.controller.admin;
import com.sky.common.constant.JwtClaimsConstant;
import com.sky.common.properties.JwtProperties;
import com.sky.common.result.PageResult;
import com.sky.common.result.Result;
import com.sky.common.utils.JwtUtil;
import com.sky.pojo.dto.EmployeeDTO;
import com.sky.pojo.dto.EmployeeLoginDTO;
import com.sky.pojo.dto.EmployeePageQueryDTO;
@ -18,9 +15,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
/**
* 员工管理
*/
@ -29,31 +23,14 @@ import java.util.Map;
@Slf4j
@Api(tags = "员工相关接口")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@Autowired
private JwtProperties jwtProperties;
@PostMapping("/login")
@ApiOperation(value = "登录接口")
public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {
log.info("员工登录:{}", employeeLoginDTO);
Employee employee = employeeService.login(employeeLoginDTO);
// 登录成功后生成jwt令牌
Map<String, Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
String token = JwtUtil.createJWT(jwtProperties.getAdminSecretKey(), jwtProperties.getAdminTtl(), claims);
EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()
.id(employee.getId())
.userName(employee.getUsername())
.name(employee.getName())
.token(token).build();
return Result.success(employeeLoginVO);
return Result.success(employeeService.login(employeeLoginDTO));
}
@PostMapping("/logout")

View File

@ -1,7 +1,7 @@
package com.sky.controller.user;
import com.sky.common.constant.JwtClaimsConstant;
import com.sky.common.properties.JwtProperties;
import com.sky.common.properties.RedisTokenProperties;
import com.sky.common.result.Result;
import com.sky.common.utils.JwtUtil;
import com.sky.pojo.dto.UserLoginDTO;
@ -28,7 +28,7 @@ public class UserController {
@Autowired
private UserService userService;
@Autowired
private JwtProperties jwtProperties;
private RedisTokenProperties redisTokenProperties;
@PostMapping("/login")
@ApiOperation("微信登录")
@ -41,7 +41,7 @@ public class UserController {
// 为微信用户生成jwt令牌
Map<String, Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.USER_ID, user.getId());
String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
String token = JwtUtil.createJWT(redisTokenProperties.getUserSecretKey(), redisTokenProperties.getUserTtl(), claims);
UserLoginVO userLoginVO = UserLoginVO.builder()
.id(user.getId())

View File

@ -7,6 +7,7 @@ import com.sky.pojo.dto.EmployeeLoginDTO;
import com.sky.pojo.dto.EmployeePageQueryDTO;
import com.sky.pojo.dto.PasswordEditDTO;
import com.sky.pojo.entity.Employee;
import com.sky.pojo.vo.EmployeeLoginVO;
public interface EmployeeService {
@ -16,7 +17,7 @@ public interface EmployeeService {
* @param employeeLoginDTO 员工等了信息
* @return 员工信息
*/
Employee login(EmployeeLoginDTO employeeLoginDTO);
EmployeeLoginVO login(EmployeeLoginDTO employeeLoginDTO);
/**
* 新增员工

View File

@ -16,21 +16,25 @@ import com.sky.pojo.dto.EmployeeLoginDTO;
import com.sky.pojo.dto.EmployeePageQueryDTO;
import com.sky.pojo.dto.PasswordEditDTO;
import com.sky.pojo.entity.Employee;
import com.sky.pojo.vo.EmployeeLoginVO;
import com.sky.service.EmployeeService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
@Autowired
private RedisTemplate<Object, Long> redisTemplate;
/**
* 员工登录
@ -38,7 +42,7 @@ public class EmployeeServiceImpl implements EmployeeService {
* @param employeeLoginDTO 员工登录时传递的数据模型
* @return 员工信息
*/
public Employee login(EmployeeLoginDTO employeeLoginDTO) {
public EmployeeLoginVO login(EmployeeLoginDTO employeeLoginDTO) {
String username = employeeLoginDTO.getUsername();
String password = employeeLoginDTO.getPassword();
@ -64,8 +68,16 @@ public class EmployeeServiceImpl implements EmployeeService {
throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
}
// TODO 生成token使用userId存入登录信息
String token = UUID.randomUUID().toString();
String userId = employee.getId().toString();
redisTemplate.opsForValue().set(token, Long.valueOf(userId));
// 3返回实体对象
return employee;
return EmployeeLoginVO.builder()
.id(employee.getId())
.userName(employee.getUsername())
.name(employee.getName())
.token(token).build();
}
/**

View File

@ -0,0 +1,54 @@
package com.sky.task;
import com.sky.mapper.OrderMapper;
import com.sky.pojo.entity.Orders;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
@Component
@Slf4j
public class OrderTask {
@Resource
private OrderMapper orderMapper;
/**
* 处理超时订单
*/
@Scheduled(cron = "0 * * * * ?")
// @Scheduled(cron = "0/5 * * * * ?")
public void processTImeOrder() {
log.info("定时处理超时订单:{}", LocalDateTime.now());
LocalDateTime time = LocalDateTime.now().plusMinutes(-15);
List<Orders> list = orderMapper.getByStatusAndOrderTime(Orders.PENDING_PAYMENT, time);
if (list != null && !list.isEmpty()) {
for (Orders orders : list) {
orders.setStatus(Orders.CANCELLED);
orders.setCancelReason("订单超时,自动取消");
orders.setCancelTime(LocalDateTime.now());
orderMapper.update(orders);
}
}
}
/**
* 处理一直派送中的订单
*/
@Scheduled(cron = "0 0 1 * * ?")
// @Scheduled(cron = "0/5 * * * * ?")
public void processDeliveryOrder() {
log.info("定时处理处于派送中的订单:{}", LocalDateTime.now());
LocalDateTime time = LocalDateTime.now().plusMinutes(-60);
List<Orders> list = orderMapper.getByStatusAndOrderTime(Orders.DELIVERY_IN_PROGRESS, time);
if (list != null && !list.isEmpty()) {
for (Orders orders : list) {
orders.setStatus(Orders.COMPLETED);
orderMapper.update(orders);
}
}
}
}

View File

@ -0,0 +1,20 @@
package com.sky.task;
import com.sky.websocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class WebSocketTask {
@Autowired
WebSocketServer webSocketServer;
@Scheduled(cron = "0/2 * * * * ?")
public void sendMessageToClient() {
webSocketServer.sendToAllClient("这是来自服务端消息" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
}
}

View File

@ -0,0 +1,47 @@
package com.sky.websocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@Component
@ServerEndpoint("/ws/{sid}")
@Slf4j
public class WebSocketServer {
// 存放会话对象
private static final Map<String, Session> sessionMap = new HashMap<>();
// 连接建立成功调用的方法
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
log.info("客户端:{}--->建立连接", sid);
sessionMap.put(sid, session);
}
// 收到客户端消息后调用的方法
@OnMessage
public void onMessage(String message, @PathParam("sid") String sid) {
log.info("收到来自客户端:{};信息为:{}", sid, message);
}
// 群发
public void sendToAllClient(String message) {
Collection<Session> sessions = sessionMap.values();
for (Session session : sessions) {
try {
// 服务器向客户端发送消息
session.getBasicRemote().sendText(message);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}

View File

@ -15,7 +15,7 @@ sky:
redis:
host: 106.15.251.123
port: 6378
port: 6379
password: "02120212"
database: 10

View File

@ -37,9 +37,9 @@ logging:
controller: info
sky:
jwt:
redisToken:
# 设置jwt签名加密时使用的秘钥
admin-secret-key: itcast
admin-secret-key: bunny
# 设置jwt过期时间
admin-ttl: 7200000
# 设置前端传递过来的令牌名称