文章目录
RedisConfig.java WebConfiguration.java AutoIdempotentTokenController.java MyOrderController.java MyOrder.java AutoIdempotentInterceptor.java AutoIdempotent IdempotentTokenService.java IdempotentTokenServiceImpl.java SpringbootRedisDemoApplication.java application.yaml order_save.jsp
RedisConfig.java
package com. example. 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. 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 org. springframework. cache. annotation. CachingConfigurerSupport ;
import org. springframework. cache. annotation. EnableCaching ;
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. core. RedisTemplate ;
import org. springframework. data. redis. listener. RedisMessageListenerContainer ;
import org. springframework. data. redis. serializer. * ;
import java. time. Duration ;
import java. time. LocalDate ;
import java. time. LocalDateTime ;
import java. time. format. DateTimeFormatter ;
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
private Duration timeToLive = Duration . ofDays ( - 1 ) ;
@Bean
@SuppressWarnings ( "all" )
public RedisTemplate < String , Object > redisTemplate ( RedisConnectionFactory factory) {
RedisTemplate < String , Object > template = new RedisTemplate < String , Object > ( ) ;
template. setConnectionFactory ( factory) ;
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer ( Object . class ) ;
ObjectMapper om = new ObjectMapper ( ) ;
om. setVisibility ( PropertyAccessor . ALL , JsonAutoDetect. Visibility . ANY ) ;
om. enableDefaultTyping ( ObjectMapper. DefaultTyping . NON_FINAL ) ;
JavaTimeModule timeModule = new JavaTimeModule ( ) ;
timeModule. addDeserializer ( LocalDate . class ,
new LocalDateDeserializer ( DateTimeFormatter . ofPattern ( "yyyy-MM-dd" ) ) ) ;
timeModule. addDeserializer ( LocalDateTime . class ,
new LocalDateTimeDeserializer ( DateTimeFormatter . ofPattern ( "yyyy-MM-dd HH:mm:ss" ) ) ) ;
timeModule. addSerializer ( LocalDate . class ,
new LocalDateSerializer ( DateTimeFormatter . ofPattern ( "yyyy-MM-dd" ) ) ) ;
timeModule. addSerializer ( LocalDateTime . class ,
new LocalDateTimeSerializer ( DateTimeFormatter . ofPattern ( "yyyy-MM-dd HH:mm:ss" ) ) ) ;
om. disable ( SerializationFeature . WRITE_DATES_AS_TIMESTAMPS ) ;
om. registerModule ( timeModule) ;
jackson2JsonRedisSerializer. setObjectMapper ( om) ;
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer ( ) ;
template. setKeySerializer ( stringRedisSerializer) ;
template. setHashKeySerializer ( stringRedisSerializer) ;
template. setValueSerializer ( jackson2JsonRedisSerializer) ;
template. setHashValueSerializer ( jackson2JsonRedisSerializer) ;
template. afterPropertiesSet ( ) ;
return template;
}
@Bean
public RedisCacheManager cacheManager ( RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration . defaultCacheConfig ( )
. entryTtl ( timeToLive)
. serializeKeysWith ( RedisSerializationContext. SerializationPair . fromSerializer ( keySerializer ( ) ) )
. serializeValuesWith ( RedisSerializationContext. SerializationPair . fromSerializer ( valueSerializer ( ) ) )
. disableCachingNullValues ( ) ;
RedisCacheManager redisCacheManager = RedisCacheManager . builder ( connectionFactory)
. cacheDefaults ( config)
. transactionAware ( )
. build ( ) ;
return redisCacheManager;
}
@Bean
RedisMessageListenerContainer listenerContainer ( RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer ( ) ;
listenerContainer. setConnectionFactory ( connectionFactory) ;
return listenerContainer;
}
private RedisSerializer < String > keySerializer ( ) {
return new StringRedisSerializer ( ) ;
}
private RedisSerializer < Object > valueSerializer ( ) {
return new GenericJackson2JsonRedisSerializer ( ) ;
}
}
WebConfiguration.java
package com. example. config ;
import com. example. interceptor. AutoIdempotentInterceptor ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. context. annotation. Configuration ;
import org. springframework. web. servlet. config. annotation. EnableWebMvc ;
import org. springframework. web. servlet. config. annotation. InterceptorRegistry ;
import org. springframework. web. servlet. config. annotation. ResourceHandlerRegistry ;
import org. springframework. web. servlet. config. annotation. WebMvcConfigurer ;
@EnableWebMvc
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Autowired
private AutoIdempotentInterceptor autoIdempotentInterceptor;
@Override
public void addInterceptors ( InterceptorRegistry registry) {
registry. addInterceptor ( autoIdempotentInterceptor) . addPathPatterns ( "/**" )
. excludePathPatterns ( "/js/**" ) . excludePathPatterns ( "/error" ) . excludePathPatterns ( "/order_save.jsp" ) ;
}
@Override
public void addResourceHandlers ( ResourceHandlerRegistry registry) {
registry. addResourceHandler ( "/**" ) . addResourceLocations ( "/" , "classpath:webapp/" ) ;
WebMvcConfigurer . super . addResourceHandlers ( registry) ;
}
}
AutoIdempotentTokenController.java
package com. example. controller ;
import com. example. util. IdempotentTokenService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Controller ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. ResponseBody ;
@Controller
public class AutoIdempotentTokenController {
@Autowired
private IdempotentTokenService tokenService;
@GetMapping ( "getIdempodentToken" )
@ResponseBody
public String getIdempodentToken ( ) {
System . out. println ( "创建token" ) ;
return tokenService. createToken ( ) ;
}
}
MyOrderController.java
package com. example. controller ;
import com. example. entity. MyOrder ;
import com. example. util. AutoIdempotent ;
import org. springframework. web. bind. annotation. PatchMapping ;
import org. springframework. web. bind. annotation. PostMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping
public class MyOrderController {
@AutoIdempotent
@PostMapping ( "myorder" )
public String save ( MyOrder myOrder) {
System . out. println ( "接收到了订单信息,正在生成订单service-mapper" ) ;
return myOrder. toString ( ) ;
}
}
MyOrder.java
package com. example. entity ;
import java. time. LocalDateTime ;
public class MyOrder {
private Integer orderId;
private Integer custId;
private Integer proId;
private String proName;
private Float proPrice;
private String proColor;
private Float proCapacity;
private Integer mycouponId;
private Float couponPrice;
private Float orderPrice;
private Integer proCount;
private Integer status;
private Integer version;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private String other1;
private String other2;
}
AutoIdempotentInterceptor.java
package com. example. interceptor ;
import com. example. util. AutoIdempotent ;
import com. example. util. IdempotentTokenService ;
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 ;
import java. lang. reflect. Method ;
@Component
public class AutoIdempotentInterceptor implements HandlerInterceptor {
@Autowired
private IdempotentTokenService tokenService;
@Override
public boolean preHandle ( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System . out. println ( "======AutoIdempotentInterceptor 拦截器正在拦截=======" ) ;
if ( ! ( handler instanceof HandlerMethod ) )
return true ;
HandlerMethod handlerMethod = ( HandlerMethod ) handler;
Method method = ( ( HandlerMethod ) handler) . getMethod ( ) ;
if ( method. getAnnotation ( AutoIdempotent . class ) != null ) {
boolean result = tokenService. checkToken ( request) ;
if ( result) {
System . out. println ( "这是第一次提交表单,可以放行" ) ;
return true ;
} else {
System . out. println ( "这是重复提交表单,不可以放行" ) ;
return false ;
}
}
return true ;
}
}
AutoIdempotent
package com. example. util ;
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 AutoIdempotent {
}
IdempotentTokenService.java
package com. example. util ;
import javax. servlet. http. HttpServletRequest ;
public interface IdempotentTokenService {
public String createToken ( ) ;
public boolean checkToken ( HttpServletRequest request) ;
}
IdempotentTokenServiceImpl.java
package com. example. util ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. data. redis. core. RedisTemplate ;
import org. springframework. stereotype. Service ;
import javax. servlet. http. HttpServletRequest ;
import java. util. UUID ;
import java. util. concurrent. TimeUnit ;
@Service
public class IdempotentTokenServiceImpl implements IdempotentTokenService {
@Autowired
private RedisTemplate < String , Object > redisTemplate;
@Override
public String createToken ( ) {
String token = UUID . randomUUID ( ) . toString ( ) . replace ( "-" , "" ) ;
redisTemplate. opsForValue ( ) . set ( token, token, 1 , TimeUnit . MINUTES ) ;
return token;
}
@Override
public boolean checkToken ( HttpServletRequest request) {
System . out. println ( "=====正在验证token========" ) ;
String token = request. getParameter ( "toke" ) ;
System . out. println ( "获得到的幂等token的值是:" + token) ;
if ( redisTemplate. hasKey ( token) ) {
redisTemplate. delete ( token) ;
return true ;
} else {
System . out. println ( "该请求是重复的,token不在Redis中" ) ;
return false ;
}
}
}
SpringbootRedisDemoApplication.java
package com. example ;
import org. mybatis. spring. annotation. MapperScan ;
import org. springframework. boot. SpringApplication ;
import org. springframework. boot. autoconfigure. SpringBootApplication ;
import org. springframework. cache. annotation. EnableCaching ;
import org. springframework. scheduling. annotation. EnableScheduling ;
@SpringBootApplication
@MapperScan ( "com.example.mapper" )
@EnableCaching
@EnableScheduling
public class SpringbootRedisDemoApplication {
public static void main ( String [ ] args) {
SpringApplication . run ( SpringbootRedisDemoApplication . class , args) ;
}
}
application.yaml
server :
servlet :
context-path : /app
port : 8080
spring :
datasource :
driver-class-name : com.mysql.cj.jdbc.Driver
url : jdbc: mysql: //localhost: 3306/dict? useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username : root
password : 123456
redis :
host : localhost
port : 6379
database : 0
connect-timeout : 1800000
jackson :
serialization :
write-dates-as-timestamps : false
logging :
file :
path : d: //logger
level :
com.example : debug
order_save.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<script src="js/jquery-3.7.0.min.js" ></script>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>下订单</h2>
<form action="myorder" method="post">
用户id: <input type="text" name="custId">
商品id: <input type="text" name="proId">
商品名称: <input type="text" name="proName">
商品价格: <input type="text" name="proPrice">
购买数量: <input type="text" name="proCount">
<input type="hidden" name="toke" class="token">
<input type="submit" value="去下订单">
</form>
<script>
createIdempodentToken();
function createIdempodentToken() {
$.ajax({
type: "get",
url: "getIdempodentToken",
success: function (result) {
console.log(result)
$(".token").val(result)
}
})
}
</script>
</body>
</html>