格式化了代码;更改了Redis配置,将原本用到redis的代码改为了现redis配置;添加了devtools的pom配置;添加了对LocalDateTime等时间类的Jackson序列化配置

master
ArgonarioD 2022-06-29 17:40:37 +08:00
parent 132abb270a
commit fc601ba7a8
12 changed files with 198 additions and 70 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?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" <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
@ -144,6 +144,8 @@
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.1</version> <version>2.7.1</version>
<configuration> <configuration>
<fork>true</fork>
<addResources>true</addResources>
<excludes> <excludes>
<exclude> <exclude>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>

View File

@ -1,10 +1,12 @@
package cn.edu.hfut.rmdjzz.projectmanagement.config; package cn.edu.hfut.rmdjzz.projectmanagement.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -16,16 +18,20 @@ import javax.annotation.Resource;
public class RedisConfig { public class RedisConfig {
@Resource @Resource
RedisConnectionFactory factory; private RedisConnectionFactory factory;
@Autowired
private ObjectMapper objectMapper;
@Bean @Bean
public RedisTemplate<String, Object> redisTemplate() { public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>(); RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory); template.setConnectionFactory(factory);
template.setKeySerializer(RedisSerializer.json()); Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
template.setValueSerializer(RedisSerializer.json()); jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
template.setHashKeySerializer(RedisSerializer.json()); template.setKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(RedisSerializer.json()); template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet(); template.afterPropertiesSet();
return template; return template;
} }

View File

@ -0,0 +1,80 @@
package cn.edu.hfut.rmdjzz.projectmanagement.config;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.time.*;
/**
* Jackson{@link LocalDateTime} {@link LocalDate} {@link LocalTime}
*
* @author
* @since 2022/6/28 23:59
*/
@Configuration
public class SerializeConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper om = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
//LocalDataTime
javaTimeModule.addSerializer(LocalDateTime.class, new JsonSerializer<>() {
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value != null) {
gen.writeNumber(value.toEpochSecond(ZoneOffset.UTC));
}
}
});
javaTimeModule.addDeserializer(LocalDateTime.class, new JsonDeserializer<>() {
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return Instant.ofEpochSecond(p.getValueAsLong(), 0).atOffset(ZoneOffset.UTC).toLocalDateTime();
}
});
//LocalDate
javaTimeModule.addSerializer(LocalDate.class, new JsonSerializer<>() {
@Override
public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value != null) {
gen.writeNumber(value.toEpochSecond(LocalTime.MIN, ZoneOffset.UTC));
}
}
});
javaTimeModule.addDeserializer(LocalDate.class, new JsonDeserializer<>() {
@Override
public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return Instant.ofEpochSecond(p.getValueAsLong(), 0).atOffset(ZoneOffset.UTC).toLocalDate();
}
});
//LocalTime处理为1970-1-1
javaTimeModule.addSerializer(LocalTime.class, new JsonSerializer<>() {
@Override
public void serialize(LocalTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value != null) {
gen.writeNumber(value.toEpochSecond(LocalDate.of(1970, 1, 1), ZoneOffset.UTC));
}
}
});
javaTimeModule.addDeserializer(LocalTime.class, new JsonDeserializer<>() {
@Override
public LocalTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return Instant.ofEpochSecond(p.getValueAsLong(), 0).atOffset(ZoneOffset.UTC).toLocalTime();
}
});
om.registerModule(javaTimeModule);
return om;
}
}

View File

@ -2,15 +2,11 @@ package cn.edu.hfut.rmdjzz.projectmanagement.config;
import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.CorsInterceptor; import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.CorsInterceptor;
import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.TokenInterceptor; import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.TokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
import java.security.Permission;
/** /**
* @author * @author
* created at 2022/6/28 19:44 * created at 2022/6/28 19:44
@ -18,16 +14,24 @@ import java.security.Permission;
@Configuration @Configuration
public class WebConfig implements WebMvcConfigurer { public class WebConfig implements WebMvcConfigurer {
@Bean @Bean
public CorsInterceptor getCorsInterceptor(){return new CorsInterceptor();} public CorsInterceptor getCorsInterceptor() {
return new CorsInterceptor();
}
@Bean @Bean
public TokenInterceptor getTokenInterceptor(){return new TokenInterceptor();} public TokenInterceptor getTokenInterceptor() {
return new TokenInterceptor();
}
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getCorsInterceptor()).addPathPatterns("/**"); registry.addInterceptor(getCorsInterceptor()).addPathPatterns("/**");
registry.addInterceptor(getTokenInterceptor()) registry.addInterceptor(getTokenInterceptor())
.addPathPatterns("/**") .addPathPatterns("/**")
.excludePathPatterns("/staff/login") .excludePathPatterns("/staff/login")
.excludePathPatterns("/hello"); .excludePathPatterns("/hello")
.excludePathPatterns("/error")
.excludePathPatterns("/staff/timetest");
} }
/* /*
@Override @Override

View File

@ -6,12 +6,10 @@ import cn.edu.hfut.rmdjzz.projectmanagement.service.impl.StaffServiceImpl;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap; import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
/** /**
* @author * @author
@ -31,12 +29,16 @@ public class StaffController {
@SneakyThrows @SneakyThrows
@PostMapping("/logout") @PostMapping("/logout")
public ResponseMap logout(HttpServletRequest request) { public ResponseMap logout(@RequestHeader("Token") String token) {
String token= request.getHeader("Token"); if (staffServiceImpl.logout(token))
if(staffServiceImpl.logout(token))
return ResponseMap.ofSuccess("操作成功"); return ResponseMap.ofSuccess("操作成功");
else{ else {
throw new TokenException("操作失败"); throw new TokenException("操作失败");
} }
} }
@GetMapping("/timetest")
public LocalDateTime timeTest(){
return LocalDateTime.now();
}
} }

View File

@ -4,6 +4,8 @@ package cn.edu.hfut.rmdjzz.projectmanagement.exception;
* @author * @author
* created at 2022/6/28 21:24 * created at 2022/6/28 21:24
*/ */
public class BadRequestException extends Exception{ public class BadRequestException extends Exception {
public BadRequestException(String message){super(message);} public BadRequestException(String message) {
super(message);
}
} }

View File

@ -4,6 +4,9 @@ package cn.edu.hfut.rmdjzz.projectmanagement.exception;
* @author * @author
* created at 2022/6/28 23:34 * created at 2022/6/28 23:34
*/ */
public class TokenException extends Exception{ //FIXME: 是否加入RequestUrl与RequestMethod作为错误信息log到日志
public TokenException(String message){super(message);} public class TokenException extends Exception {
public TokenException(String message) {
super(message);
}
} }

View File

@ -3,19 +3,11 @@ package cn.edu.hfut.rmdjzz.projectmanagement.interceptor;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException; import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils; import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
@ -26,35 +18,39 @@ import java.util.concurrent.TimeUnit;
* @author * @author
* created at 2022/6/28 18:16 * created at 2022/6/28 18:16
*/ */
//FIXME: objectMapper去掉
@Component @Component
public class TokenInterceptor implements HandlerInterceptor { public class TokenInterceptor implements HandlerInterceptor {
@Resource
private RedisTemplate<Integer,String> redisTemplate; @Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Override @Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws TokenException, IOException { public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws TokenException {
System.out.println(httpServletRequest.getRequestURL()+" "+httpServletRequest.getMethod()); System.out.println(httpServletRequest.getRequestURL() + " " + httpServletRequest.getMethod());
String token = httpServletRequest.getHeader("Token"); String token = httpServletRequest.getHeader("Token");
if (null == token || "".equals(token.trim())) { if (null == token || "".equals(token.trim())) {
throw new TokenException("缺少Token"); throw new TokenException("缺少Token");
} }
if(!TokenUtils.checkToken(token)){ if (!TokenUtils.checkToken(token)) {
throw new TokenException("无效的Token"); throw new TokenException("无效的Token");
} }
if(TokenUtils.checkTimeOut(token)){ if (TokenUtils.checkTimeOut(token)) {
throw new TokenException("Token已过期"); throw new TokenException("Token已过期");
} }
System.out.println(Objects.requireNonNull(TokenUtils.getStaffId(token))); System.out.println(Objects.requireNonNull(TokenUtils.getStaffId(token)));
System.out.println(token); System.out.println(token);
if(!token.equals(redisTemplate.opsForValue().get(Objects.requireNonNull(TokenUtils.getStaffId(token))))){ if (!token.equals(redisTemplate.opsForValue().get(Objects.<Integer>requireNonNull(TokenUtils.getStaffId(token))))) {
throw new TokenException("请重新登录"); throw new TokenException("请重新登录");
} }
String newToken=TokenUtils.autoRequire(token); String newToken = TokenUtils.autoRequire(token);
if(!newToken.equals(token)){ if (!newToken.equals(token)) {
redisTemplate.opsForValue().set(Objects.requireNonNull(TokenUtils.getStaffId(token)), redisTemplate.opsForValue().set(
token,Objects.requireNonNull(TokenUtils.getDuration(token)), TimeUnit.SECONDS); Objects.<Integer>requireNonNull(TokenUtils.getStaffId(token)),
token,
Objects.requireNonNull(TokenUtils.getDuration(token)), TimeUnit.SECONDS
);
} }
httpServletResponse.setHeader("Token",newToken); httpServletResponse.setHeader("Token", newToken);
return true; return true;
} }
} }

View File

@ -12,5 +12,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/ */
public interface IStaffService extends IService<Staff> { public interface IStaffService extends IService<Staff> {
ResponseMap login(String username, String password) throws BadRequestException, TokenException; ResponseMap login(String username, String password) throws BadRequestException, TokenException;
Boolean logout(String token) throws TokenException; Boolean logout(String token) throws TokenException;
} }

View File

@ -9,16 +9,11 @@ import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap; import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils; import org.springframework.util.DigestUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -28,9 +23,10 @@ import java.util.concurrent.TimeUnit;
*/ */
@Service @Service
public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService { public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService {
private static final Long tokenDuration=5*60*60L; private static final Long tokenDuration = 5 * 60 * 60L;
@Resource
private RedisTemplate<Integer,String> redisTemplate; @Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Override @Override
public ResponseMap login(String staffUsername, String password) throws BadRequestException, TokenException { public ResponseMap login(String staffUsername, String password) throws BadRequestException, TokenException {
@ -47,25 +43,28 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
password = DigestUtils.md5DigestAsHex((password + staff.getStaffSalt()).getBytes()); password = DigestUtils.md5DigestAsHex((password + staff.getStaffSalt()).getBytes());
if (!staff.getStaffPassword().equals(password)) if (!staff.getStaffPassword().equals(password))
throw new BadRequestException("密码错误"); throw new BadRequestException("密码错误");
String token=TokenUtils.getToken(staff.getStaffUsername(), staff.getStaffId(),tokenDuration); String token = TokenUtils.getToken(staff.getStaffUsername(), staff.getStaffId(), tokenDuration);
redisTemplate.opsForValue().set(Objects.requireNonNull(TokenUtils.getStaffId(token)), redisTemplate.opsForValue().set(
token,Objects.requireNonNull(TokenUtils.getDuration(token)), TimeUnit.SECONDS); Objects.<Integer>requireNonNull(TokenUtils.getStaffId(token)),
token,
Objects.requireNonNull(TokenUtils.getDuration(token)), TimeUnit.SECONDS
);
return ResponseMap.ofSuccess("ok") return ResponseMap.ofSuccess("ok")
.put("Token",token) .put("Token", token)
.put("staffUsername", staffUsername) .put("staffUsername", staffUsername)
.put("staffFullname", staff.getStaffFullname()) .put("staffFullname", staff.getStaffFullname())
.put("staffId", staff.getStaffId()); .put("staffId", staff.getStaffId());
} }
@Override @Override
public Boolean logout(String token) throws TokenException { public Boolean logout(String token) throws TokenException {
Integer staffId=TokenUtils.getStaffId(token); Integer staffId = TokenUtils.getStaffId(token);
if(staffId==null) if (staffId == null)
return false; return false;
String remoteToken= redisTemplate.opsForValue().get(staffId); String remoteToken = (String) redisTemplate.opsForValue().get(staffId);
if(!token.equals(remoteToken)) if (!token.equals(remoteToken))
return false; return false;
redisTemplate.delete(staffId); redisTemplate.delete(staffId);
return true; return true;
} }
} }

View File

@ -1,10 +1,11 @@
package cn.edu.hfut.rmdjzz.projectmanagement; package cn.edu.hfut.rmdjzz.projectmanagement;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource; import java.time.LocalDateTime;
/** /**
* @author * @author
@ -12,11 +13,16 @@ import javax.annotation.Resource;
*/ */
@SpringBootTest @SpringBootTest
public class RedisTests { public class RedisTests {
@Resource @Autowired
private RedisTemplate<Object, Object> redisTemplate; private RedisTemplate<Object, Object> redisTemplate;
@Test @Test
void test(){ void test() {
redisTemplate.opsForList().rightPush(123456,89); redisTemplate.opsForList().rightPush(123456, 89);
}
@Test
void testValue() {
redisTemplate.opsForValue().set("time", LocalDateTime.now());
} }
} }

View File

@ -0,0 +1,27 @@
package cn.edu.hfut.rmdjzz.projectmanagement;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* @author
* @since 2022/6/29 17:25
*/
@SpringBootTest
public class SerializeTests {
@Autowired
private ObjectMapper objectMapper;
@SneakyThrows
@Test
public void serializeTime() {
System.out.println(objectMapper.readValue("1656523481", LocalDate.class));
}
}