赞
踩
先看效果:
相关代码
配置redis
- server:
- port: 8282
-
- spring:
- # redis 配置
- redis:
- # 地址
- host: 192.168.1.7
- # 密码
- password: 123456
- # 端口,默认为6379
- port: 6379
- # 数据库索引
- database: 0
- # 连接超时时间
- timeout: 10s
- lettuce:
- pool:
- # 连接池中的最小空闲连接
- min-idle: 0
- # 连接池中的最大空闲连接
- max-idle: 8
- # 连接池的最大数据库连接数
- max-active: 8
- # #连接池最大阻塞等待时间(使用负值表示没有限制)
- max-wait: -1ms
pom文件
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <!-- aop切面 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-aop</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-all</artifactId>
- <version>5.8.5</version>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-pool2</artifactId>
- <version>2.0</version>
- </dependency>
具体代码,拿去就可以用
- package org.example.repeatsubmit;
-
- import cn.hutool.core.convert.Convert;
-
- /**
- * 类型转换工具类
- */
- public class ConvertUtils extends Convert {
-
- }
- package org.example.repeatsubmit;
-
- import lombok.extern.slf4j.Slf4j;
-
- import javax.servlet.ServletRequest;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.nio.charset.StandardCharsets;
-
- /**
- * 通用http工具封装
- */
- @Slf4j
- public class HttpHelperUtils {
-
- /**
- * 获取请求Body
- *
- * @param request 请求
- * @return 目标字符串
- */
- public static String getBodyString(ServletRequest request) {
- try (InputStream inputStream = request.getInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
- String line;
- StringBuilder sb = new StringBuilder();
-
- while (StringUtils.isNotEmpty(line = reader.readLine())) {
- sb.append(line);
- }
-
- return sb.toString();
- } catch (IOException e) {
- log.warn("getBodyString出现异常:!", e);
- }
-
- return StringUtils.EMPTY;
- }
-
- }
- package org.example.repeatsubmit;
-
- public class JsonConvertException extends RuntimeException {
-
- private static final long serialVersionUID = 1L;
-
- protected final String message;
-
- public JsonConvertException(String message) {
- this.message = message;
- }
-
- public JsonConvertException(String message, Throwable e) {
- super(message, e);
- this.message = message;
- }
-
- @Override
- public String getMessage() {
- return message;
- }
-
- }
- package org.example.repeatsubmit;
-
- import cn.hutool.json.JSONUtil;
- import com.fasterxml.jackson.core.JsonProcessingException;
- import com.fasterxml.jackson.core.type.TypeReference;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import lombok.extern.slf4j.Slf4j;
- import org.example.rate.SpringUtils;
-
- import java.io.IOException;
-
- @Slf4j
- public class JSONUtils extends JSONUtil {
-
- private final static ObjectMapper OBJECT_MAPPER;
-
- static {
- OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class);
- }
-
- /**
- * jackson
- * <p>
- * 传入对象直接返回Json
- *
- * @param object 待转换对象
- * @return json字符串
- */
- public static <T> String serialize(T object) {
- try {
- return OBJECT_MAPPER.writeValueAsString(object);
- } catch (JsonProcessingException e) {
- log.error("JSON序列化异常:", e);
- throw new JsonConvertException("JSON序列化异常!");
- }
- }
-
- /**
- * jackson
- * <p>
- * 传入Json字符串直接返回bean对象
- *
- * @param json 待转换Json字符
- * @param clazz 待转换对象类型
- * @return bean对象
- */
- public static <T> T deserialize(String json, Class<T> clazz) {
- try {
- return OBJECT_MAPPER.readValue(json, clazz);
- } catch (JsonProcessingException e) {
- log.error("JSON反序列化异常:", e);
- throw new JsonConvertException("JSON反序列化异常!");
- } catch (IOException e) {
- e.printStackTrace();
- throw new JsonConvertException("JSON反序列化异常!");
- }
- }
-
- /**
- * jackson
- * json转bean或list
- *
- * @param str 带转换字符串
- * @param typeReference 转换类型
- * @return T 转换后对象
- */
- public static <T> T getTypeReference(String str, TypeReference<T> typeReference) {
- try {
- return OBJECT_MAPPER.readValue(str, typeReference);
- } catch (JsonProcessingException e) {
- log.error("JSON反序列化异常:", e);
- throw new JsonConvertException("JSON反序列化异常!");
- } catch (IOException e) {
- e.printStackTrace();
- throw new JsonConvertException("JSON反序列化异常!");
- }
- }
-
- }
- package org.example.repeatsubmit;
-
- import cn.hutool.core.map.MapUtil;
-
- public class MapUtils extends MapUtil {
-
- }
- package org.example.repeatsubmit;
-
- import cn.hutool.core.lang.TypeReference;
- import org.example.rate.ConvertUtils;
- import org.example.rate.SpringUtils;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.data.redis.core.ValueOperations;
- import org.springframework.data.redis.core.script.RedisScript;
-
- import java.util.List;
- import java.util.concurrent.TimeUnit;
-
- public class RedisUtils {
-
- /**
- * redisTemplate名称
- */
- public static final String REDIS_TEMPLATE_NAME = "redisTemplate";
-
- private final static RedisTemplate<Object, Object> redisTemplate;
-
- static {
- redisTemplate = org.example.rate.ConvertUtils.convert(new TypeReference<RedisTemplate<Object, Object>>() {},
- SpringUtils.getBean(REDIS_TEMPLATE_NAME, RedisTemplate.class));
- }
-
- /**
- * 缓存基本的对象,Integer、String、实体类等
- *
- * @param key 缓存的键值
- * @param value 缓存的值
- */
- public static <T> void setCacheObject(final String key, final T value) {
- redisTemplate.opsForValue().set(key, value);
- }
-
- /**
- * 缓存基本的对象,Integer、String、实体类等
- *
- * @param key 缓存的键值
- * @param value 缓存的值
- * @param timeout 时间
- * @param timeUnit 时间颗粒度
- */
- public static <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
- redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
- }
-
- /**
- * 获得缓存的基本对象。
- *
- * @param key 缓存键值
- * @return 缓存键值对应的数据
- */
- public static <T> T getCacheObject(final String key) {
- ValueOperations<String, T> operation = ConvertUtils.convert(new TypeReference<ValueOperations<String, T>>() {},
- redisTemplate.opsForValue());
- return operation.get(key);
- }
-
- /**
- * 删除单个对象
- *
- * @param key 缓存键值
- */
- public static boolean deleteObject(final String key) {
- return Boolean.TRUE.equals(redisTemplate.delete(key));
- }
-
- /**
- * redis 原生脚本执行
- *
- * @param script RedisScript脚本
- * @param keys 缓存键值
- * @param args 参数
- */
- public static <T> T execute(RedisScript<T> script, List<Object> keys, Object... args) {
- return redisTemplate.execute(script, keys, args);
- }
-
- }
- package org.example.repeatsubmit;
-
- import javax.servlet.ReadListener;
- import javax.servlet.ServletInputStream;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletRequestWrapper;
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.nio.charset.StandardCharsets;
-
- /**
- * 构建可重复读取inputStream的request
- *
- */
- public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
-
- private final byte[] body;
-
- public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
- super(request);
- request.setCharacterEncoding(StandardCharsets.UTF_8.name());
- response.setCharacterEncoding(StandardCharsets.UTF_8.name());
- body = HttpHelperUtils.getBodyString(request).getBytes(StandardCharsets.UTF_8.name());
- }
-
- @Override
- public BufferedReader getReader() {
- return new BufferedReader(new InputStreamReader(getInputStream()));
- }
-
- @Override
- public ServletInputStream getInputStream() {
- final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
-
- return new ServletInputStream() {
- @Override
- public int read() {
- return byteArrayInputStream.read();
- }
-
- @Override
- public int available() {
- return body.length;
- }
-
- @Override
- public boolean isFinished() {
- return false;
- }
-
- @Override
- public boolean isReady() {
- return false;
- }
-
- @Override
- public void setReadListener(ReadListener readListener) {
-
- }
- };
- }
- }
- package org.example.repeatsubmit;
-
- import java.lang.annotation.*;
-
- /**
- * 防止表单重复提交注解
- */
- @Inherited
- @Documented
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface RepeatSubmit {
-
- /**
- * 间隔时间(ms),小于此时间视为重复提交
- */
- int interval() default 5000;
-
- /**
- * 提示消息
- */
- String message() default "不允许重复提交,请稍候再试";
-
- }
- package org.example.repeatsubmit;
-
- import org.springframework.lang.NonNull;
- 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;
- import java.util.Objects;
-
- public abstract class RepeatSubmitInterceptor implements HandlerInterceptor {
-
- @Override
- public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
- if (handler instanceof HandlerMethod) {
- HandlerMethod handlerMethod = (HandlerMethod) handler;
- Method method = handlerMethod.getMethod();
- RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
-
- if (Objects.nonNull(annotation)) {
- if (this.isRepeatSubmit(request, annotation)) {
- Response<String> result = Response.fail(ResponseCode.FAIL, annotation.message());
- ServletUtils.responseJson(response, result);
- return false;
- }
- }
- }
-
- return true;
- }
-
- /**
- * 验证是否重复提交由子类实现具体的防重复提交的规则
- *
- * @param request 请求
- * @param annotation 重复提交注解
- * @return 是否是重复提交
- */
- public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);
-
- }
- package org.example.repeatsubmit;
-
- import java.io.Serializable;
-
- public class Response<T> implements Serializable {
-
- private Integer code;
-
- private String message;
-
- private T data;
-
- private Response() {
-
- }
-
- public Integer getCode() {
- return code;
- }
-
- public void setCode(Integer code) {
- this.code = code;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- public T getData() {
- return data;
- }
-
- public void setData(T data) {
- this.data = data;
- }
-
- public static <T> Response<T> ok() {
- return createResult(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMessage(), null);
- }
-
- public static <T> Response<T> ok(T data) {
- return createResult(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMessage(), data);
- }
-
- public static <T> Response<T> ok(String message) {
- return createResult(ResponseCode.SUCCESS.getCode(), message, null);
- }
-
- public static <T> Response<T> ok(T data, String message) {
- return createResult(ResponseCode.SUCCESS.getCode(), message, data);
- }
-
- public static <T> Response<T> fail() {
- return createResult(ResponseCode.FAIL.getCode(), ResponseCode.FAIL.getMessage(), null);
- }
-
- public static <T> Response<T> fail(String message) {
- return createResult(null, message, null);
- }
-
- public static <T> Response<T> fail(Integer code, String message) {
- return createResult(code, message, null);
- }
-
- public static <T> Response<T> fail(ResponseCode responseCode) {
- return createResult(responseCode.getCode(), responseCode.getMessage(), null);
- }
-
- public static <T> Response<T> fail(ResponseCode responseCode, T data) {
- return createResult(responseCode.getCode(), responseCode.getMessage(), data);
- }
-
- public static <T> Response<T> fail(ResponseCode responseCode, String message) {
- return createResult(responseCode.getCode(), String.format("%s,%s", responseCode.getMessage(), message), null);
- }
-
- private static <T> Response<T> createResult(Integer code, String message, T data) {
- Response<T> response = new Response<>();
- response.setCode(code);
- response.setMessage(message);
- response.setData(data);
- return response;
- }
-
- }
- package org.example.repeatsubmit;
-
- public enum ResponseCode {
-
- /**
- * 成功
- */
- SUCCESS(200, "成功"),
-
- /**
- * 失败
- */
- FAIL(201, "失败"),
-
- /**
- * 未授权
- */
- UNAUTHORIZED(202, "未授权"),
-
- /**
- * 服务器运行异常
- */
- RUN_TIME_EXCEPTION(500, "服务器运行异常");
-
- ResponseCode(Integer code, String message) {
- this.code = code;
- this.message = message;
- }
-
- /**
- * code
- */
- final Integer code;
-
- /**
- * message desc
- */
- final String message;
-
- public Integer getCode() {
- return code;
- }
-
- public String getMessage() {
- return message;
- }
-
- }
- package org.example.repeatsubmit;
-
- import cn.hutool.core.lang.TypeReference;
- import lombok.RequiredArgsConstructor;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- import org.springframework.web.context.request.NativeWebRequest;
- import org.springframework.web.context.request.RequestAttributes;
- import org.springframework.web.context.request.ServletWebRequest;
- import org.springframework.web.servlet.HandlerMapping;
- import javax.servlet.http.HttpServletRequest;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Objects;
- import java.util.concurrent.TimeUnit;
-
- /**
- * 判断请求url和数据是否和上一次相同,
- * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
- */
- @Component
- @RequiredArgsConstructor(onConstructor_ = {@Autowired})
- public class SameUrlDataInterceptor extends RepeatSubmitInterceptor {
-
-
- /**
- * 防重提交 redis key
- */
- public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
-
- /**
- * 重复提交参数key
- */
- public static final String REPEAT_PARAMS = "repeatParams";
-
- /**
- * 重复提交时间key
- */
- public static final String REPEAT_TIME = "repeatTime";
-
- @Override
- public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) {
- String nowParams = StringUtils.EMPTY;
-
- if (request instanceof RepeatedlyRequestWrapper) {
- RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
- nowParams = HttpHelperUtils.getBodyString(repeatedlyRequest);
- }
-
- // body参数为空,获取Parameter的数据
- if (StringUtils.isEmpty(nowParams)) {
- if (MapUtils.isNotEmpty(request.getParameterMap())) {
- nowParams = JSONUtils.serialize(request.getParameterMap());
- }
- }
-
- // Parameter参数为空,获取@PathVariable的数据
- if (StringUtils.isEmpty(nowParams)) {
- NativeWebRequest webRequest = new ServletWebRequest(request);
- Map<String, Object> mapParams = ConvertUtils.convert(new TypeReference<Map<String, Object>>() {},
- webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST));
-
- if (MapUtils.isNotEmpty(mapParams)) {
- nowParams = JSONUtils.serialize(mapParams);
- }
- }
-
- Map<String, Object> nowDataMap = new HashMap<>(2);
- nowDataMap.put(REPEAT_PARAMS, nowParams);
- nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
-
- // 请求地址(作为存放cache的key值)
- String url = request.getRequestURI();
-
- // 唯一值(没有消息头则使用请求地址)--------系统可以自定义,目前这里定义:Authorization
- String submitKey = StringUtils.trimToEmpty(request.getHeader("Authorization"));
-
- // 唯一标识(指定key + url + 消息头)
- String cacheRepeatKey = REPEAT_SUBMIT_KEY + url + submitKey;
-
- Object sessionObj = RedisUtils.getCacheObject(cacheRepeatKey);
-
- if (Objects.nonNull(sessionObj)) {
- Map<String, Object> sessionMap = ConvertUtils.convert(new TypeReference<Map<String, Object>>() {}, sessionObj);
-
- if (sessionMap.containsKey(url)) {
- Map<String, Object> preDataMap = ConvertUtils.convert(new TypeReference<Map<String, Object>>() {}, sessionMap.get(url));
-
- if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) {
- return true;
- }
- }
- }
-
- Map<String, Object> cacheMap = new HashMap<>(1);
- cacheMap.put(url, nowDataMap);
- RedisUtils.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
- return false;
- }
-
- /**
- * 判断参数是否相同
- */
- private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap) {
- String nowParams = (String) nowMap.get(REPEAT_PARAMS);
- String preParams = (String) preMap.get(REPEAT_PARAMS);
- return nowParams.equals(preParams);
- }
-
- /**
- * 判断两次间隔时间
- */
- private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval) {
- long time1 = (Long) nowMap.get(REPEAT_TIME);
- long time2 = (Long) preMap.get(REPEAT_TIME);
- return (time1 - time2) < interval;
- }
-
- }
- package org.example.repeatsubmit;
-
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.http.MediaType;
- import org.springframework.web.context.request.RequestAttributes;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import java.io.PrintWriter;
- import java.io.UnsupportedEncodingException;
- import java.net.URLDecoder;
- import java.net.URLEncoder;
- import java.nio.charset.StandardCharsets;
- import java.util.Objects;
-
- /**
- * 客户端响应工具类
- */
- @Slf4j
- public class ServletUtils {
-
- /**
- * 获取String参数
- */
- public static String getParameter(String name) {
- return getRequest().getParameter(name);
- }
-
- /**
- * 获取String参数
- */
- public static String getHeader(String name) {
- return getRequest().getHeader(name);
- }
-
- /**
- * 获取String参数
- */
- public static String getParameter(String name, String defaultValue) {
- return ConvertUtils.toStr(getRequest().getParameter(name), defaultValue);
- }
-
- /**
- * 获取Integer参数
- */
- public static Integer getParameterToInt(String name) {
- return ConvertUtils.toInt(getRequest().getParameter(name));
- }
-
- /**
- * 获取Integer参数
- */
- public static Integer getParameterToInt(String name, Integer defaultValue) {
- return ConvertUtils.toInt(getRequest().getParameter(name), defaultValue);
- }
-
- /**
- * 获取Boolean参数
- */
- public static Boolean getParameterToBool(String name) {
- return ConvertUtils.toBool(getRequest().getParameter(name));
- }
-
- /**
- * 获取Boolean参数
- */
- public static Boolean getParameterToBool(String name, Boolean defaultValue) {
- return ConvertUtils.toBool(getRequest().getParameter(name), defaultValue);
- }
-
- /**
- * 获取request
- */
- public static HttpServletRequest getRequest() {
- return getRequestAttributes().getRequest();
- }
-
- /**
- * 获取response
- */
- public static HttpServletResponse getResponse() {
- return getRequestAttributes().getResponse();
- }
-
- /**
- * 获取session
- */
- public static HttpSession getSession() {
- return getRequest().getSession();
- }
-
- public static ServletRequestAttributes getRequestAttributes() {
- RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
- return (ServletRequestAttributes) attributes;
- }
-
- /**
- * 将字符串渲染到客户端
- *
- * @param response 渲染对象
- * @param failed 响应消息
- */
- public static void responseJson(HttpServletResponse response, Response<String> failed) {
- if (Objects.isNull(failed)) {
- return;
- }
-
- response.setCharacterEncoding(StandardCharsets.UTF_8.name());
- response.setContentType(MediaType.APPLICATION_JSON_VALUE);
-
- try (PrintWriter writer = response.getWriter()) {
- String json = JSONUtils.serialize(failed);
- writer.write(json);
- writer.flush();
- } catch (Exception e) {
- log.info("响应失败:", e);
- }
- }
-
- /**
- * 内容编码
- *
- * @param str 内容
- * @return 编码后的内容
- */
- public static String urlEncode(String str) {
- try {
- return URLEncoder.encode(str, StandardCharsets.UTF_8.name());
- } catch (UnsupportedEncodingException e) {
- log.info("内容编码失败:", e);
- return StringUtils.EMPTY;
- }
- }
-
- /**
- * 内容解码
- *
- * @param str 内容
- * @return 解码后的内容
- */
- public static String urlDecode(String str) {
- try {
- return URLDecoder.decode(str, StandardCharsets.UTF_8.name());
- } catch (UnsupportedEncodingException e) {
- log.info("内容解码失败:", e);
- return StringUtils.EMPTY;
- }
- }
-
- }
- package org.example.repeatsubmit;
-
- import cn.hutool.core.text.StrFormatter;
- import org.springframework.util.AntPathMatcher;
-
- import java.util.Collection;
- import java.util.List;
- import java.util.Objects;
-
- public class StringUtils extends org.apache.commons.lang3.StringUtils {
-
- /**
- * 斜杠
- */
- public static final String SLASH = "/";
-
- /**
- * 点
- */
- public static final String SPOT = ".";
-
- /**
- * 逗号
- */
- public static final String COMMA = ",";
-
- /**
- * 星号
- */
- public static final String ASTERISK = "*";
-
- /**
- * 与符号
- */
- public static final String AMPERSAND = "&";
-
- /**
- * 等号
- */
- public static final String EQUAL = "=";
-
- /**
- * 横杠
- */
- public static final String TRANSVERSE = "-";
-
- /**
- * 下划线
- */
- public static final String SEPARATOR = "_";
-
- /**
- * 空格
- */
- public static final String SPACE = " ";
-
- /**
- * 冒号
- */
- public static final String COLON = ":";
-
- /**
- * * 判断一个对象数组是否为空
- *
- * @param objects 要判断的对象数组
- * * @return true:为空 false:非空
- */
- public static boolean isEmpty(Object[] objects) {
- return isNull(objects) || (objects.length == 0);
- }
-
- /**
- * * 判断一个对象是否为空
- *
- * @param object Object
- * @return true:为空 false:非空
- */
- public static boolean isNull(Object object) {
- return object == null;
- }
-
- /**
- * * 判断一个Collection是否为空, 包含List,Set,Queue
- *
- * @param coll 要判断的Collection
- * @return true:为空 false:非空
- */
- public static boolean isEmpty(Collection<?> coll) {
- return Objects.isNull(coll) || coll.isEmpty();
- }
-
- /**
- * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
- *
- * @param str 指定字符串
- * @param characters 需要检查的字符串数组
- * @return 是否匹配
- */
- public static boolean matches(String str, List<String> characters) {
- if (isEmpty(str) || isEmpty(characters)) {
- return false;
- }
-
- for (String pattern : characters) {
- if (isMatch(pattern, str)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * 判断url是否与规则配置:
- * ? 表示单个字符;
- * * 表示一层路径内的任意字符串,不可跨层级;
- * ** 表示任意层路径;
- *
- * @param pattern 匹配规则
- * @param url 需要匹配的url
- * @return 是否与规则配置结果
- */
- public static boolean isMatch(String pattern, String url) {
- AntPathMatcher matcher = new AntPathMatcher();
- return matcher.match(pattern, url);
- }
-
- /**
- * 格式化文本, {} 表示占位符<br>
- * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
- * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
- * 例:<br>
- * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
- * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
- * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
- *
- * @param template 文本模板,被替换的部分用 {} 表示
- * @param params 参数值
- * @return 格式化后的文本
- */
- public static String format(String template, Object... params) {
- if (isEmpty(params) || isEmpty(template)) {
- return template;
- }
-
- return StrFormatter.format(template, params);
- }
-
-
- /**
- * 驼峰转下划线命名
- */
- public static String toUnderScoreCase(String str) {
- if (Objects.isNull(str)) {
- return null;
- }
-
- StringBuilder sb = new StringBuilder();
- // 前置字符是否大写
- boolean preCharIsUpperCase;
- // 当前字符是否大写
- boolean currentCharIsUpperCase;
- // 下一字符是否大写
- boolean nextCharIsUpperCase = true;
-
- for (int i = 0; i < str.length(); i++) {
- char c = str.charAt(i);
-
- if (i > 0) {
- preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
- } else {
- preCharIsUpperCase = false;
- }
-
- currentCharIsUpperCase = Character.isUpperCase(c);
-
- if (i < (str.length() - 1)) {
- nextCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
- }
-
- if (preCharIsUpperCase && currentCharIsUpperCase && !nextCharIsUpperCase) {
- sb.append(SEPARATOR);
- } else if ((i != 0 && !preCharIsUpperCase) && currentCharIsUpperCase) {
- sb.append(SEPARATOR);
- }
-
- sb.append(Character.toLowerCase(c));
- }
-
- return sb.toString();
- }
-
- }
- package org.example.rate;
-
- import org.springframework.aop.framework.AopContext;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
- import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.lang.NonNull;
- import org.springframework.stereotype.Component;
-
- /**
- * spring 工具类
- */
- @Component
- public class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
-
- /**
- * Spring应用上下文环境
- */
- private static ConfigurableListableBeanFactory beanFactory;
-
- private static ApplicationContext applicationContext;
-
- @Override
- public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException {
- SpringUtils.beanFactory = beanFactory;
- }
-
- /**
- * private static ConfigurableListableBeanFactory beanFactory;
- * SpringUtils.applicationContext = applicationContext;
- */
- @Override
- public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
- SpringUtils.applicationContext = applicationContext;
- }
-
- /**
- * 获取对象
- *
- * @param name bean名称
- * @param clazz 待获取类型
- * @return Object 一个以所给名字注册的bean的实例
- */
- public static <T> T getBean(String name, Class<T> clazz) {
- return beanFactory.getBean(name, clazz);
- }
-
- /**
- * 获取类型为requiredType的对象
- *
- * @param clz 类型
- * @return Object 一个以所给类型注册的bean的实例
- */
- public static <T> T getBean(Class<T> clz) {
- return beanFactory.getBean(clz);
- }
-
- /**
- * 发布一个事件
- *
- * @param event 事件
- */
- public static void publishEvent(Object event) {
- applicationContext.publishEvent(event);
- }
-
- /**
- * 获取当前代理bean
- * @param t 待获取bean类型
- * @param <T> 泛型
- * @return 当前代理bean
- */
- public static <T> T getCurrentProxyBean(Class<T> t) {
- return ConvertUtils.convert(t, AopContext.currentProxy());
- }
-
- }
最后写springmvc拦截
- package org.example.repeatsubmit;
-
- import lombok.RequiredArgsConstructor;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.http.MediaType;
- 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.WebMvcConfigurer;
-
- import java.nio.charset.StandardCharsets;
- import java.util.ArrayList;
- import java.util.List;
-
- @Configuration
- @RequiredArgsConstructor(onConstructor_ = {@Autowired})
- public class WebMvcConfig implements WebMvcConfigurer {
-
- private final RepeatSubmitInterceptor repeatSubmitInterceptor;
-
- /**
- * 解决低版本ie @ResponseBody返回json的时候提示下载问题 Jackson处理
- */
- public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
- MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
- List<MediaType> supportedMediaTypes = new ArrayList<>();
- MediaType media = new MediaType(MediaType.TEXT_PLAIN, StandardCharsets.UTF_8);
- supportedMediaTypes.add(media);
- jsonConverter.setSupportedMediaTypes(supportedMediaTypes);
- return jsonConverter;
- }
-
- @Override
- public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
- converters.add(customJackson2HttpMessageConverter());
- }
-
- /**
- * 自定义拦截规则
- */
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- registry.addInterceptor(repeatSubmitInterceptor)
- .addPathPatterns("/**");
- }
-
- }
测试代码
- @RepeatSubmit(interval = 1000)
- @PostMapping("/repeatSubmit")
- public String repeatSubmit(@RequestParam String test){
- log.info("repeatSubmit--test--->"+test);
- return "ok";
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。