文章目录
- 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;}@Beanpublic 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;}@BeanRedisMessageListenerContainer 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 {@Autowiredprivate AutoIdempotentInterceptor autoIdempotentInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(autoIdempotentInterceptor).addPathPatterns("/**") .excludePathPatterns("/js/**").excludePathPatterns("/error").excludePathPatterns("/order_save.jsp");}@Overridepublic 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 {@Autowiredprivate IdempotentTokenService tokenService;@GetMapping("getIdempodentToken")@ResponseBodypublic 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 {
@Autowiredprivate IdempotentTokenService tokenService;@Overridepublic 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 {@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Overridepublic String createToken() {String token = UUID.randomUUID().toString().replace("-","");redisTemplate.opsForValue().set(token,token,1, TimeUnit.MINUTES);return token;}@Overridepublic 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: 8080spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/dict?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456redis:host: localhostport: 6379database: 0connect-timeout: 1800000jackson:serialization:write-dates-as-timestamps: falselogging: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>