From 3f97bb1356da5269708c25a573f33bf4be483eb0 Mon Sep 17 00:00:00 2001 From: Timi Date: Wed, 8 Apr 2026 11:22:04 +0800 Subject: [PATCH 1/4] fix Redis instance --- src/main/java/com/imyeyu/spring/util/Redis.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/imyeyu/spring/util/Redis.java b/src/main/java/com/imyeyu/spring/util/Redis.java index 3d35ba8..a8f452b 100644 --- a/src/main/java/com/imyeyu/spring/util/Redis.java +++ b/src/main/java/com/imyeyu/spring/util/Redis.java @@ -3,6 +3,9 @@ package com.imyeyu.spring.util; import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.timi.TimiException; import com.imyeyu.spring.config.AbstractRedisConfig; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.RedisTemplate; @@ -27,7 +30,13 @@ import java.util.function.Consumer; * @author 夜雨 * @version 2021-11-21 09:58 */ -public record Redis(RedisTemplate redis, RedisSerializer serializer) { +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Redis { + + private RedisTemplate redis; + private RedisSerializer serializer; /** * 加锁 -- 2.49.1 From b94849d69c3c128aa89bdebca1ce85a42cc4567d Mon Sep 17 00:00:00 2001 From: Timi Date: Wed, 8 Apr 2026 11:22:22 +0800 Subject: [PATCH 2/4] add @RequestBodyValue --- .../spring/annotation/RequestBodyValue.java | 43 ++++++++++ .../RequestBodyValueArgumentResolver.java | 82 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/main/java/com/imyeyu/spring/annotation/RequestBodyValue.java create mode 100644 src/main/java/com/imyeyu/spring/annotation/RequestBodyValueArgumentResolver.java diff --git a/src/main/java/com/imyeyu/spring/annotation/RequestBodyValue.java b/src/main/java/com/imyeyu/spring/annotation/RequestBodyValue.java new file mode 100644 index 0000000..5b6b89d --- /dev/null +++ b/src/main/java/com/imyeyu/spring/annotation/RequestBodyValue.java @@ -0,0 +1,43 @@ +package com.imyeyu.spring.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 读取 JSON 请求体中的单个字段并绑定到接口参数。 + * + *

默认使用方法参数名作为 JSON 字段名,也可以手动指定字段名。 + * + *

+ * public void run(@RequestBodyValue String data) {
+ * }
+ *
+ * public void run(@RequestBodyValue("value") Long id) {
+ * }
+ * 
+ * + * @author 夜雨 + * @version 2026-04-08 11:00 + */ +@Documented +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface RequestBodyValue { + + /** + * JSON 字段名,为空时使用方法参数名。 + * + * @return JSON 字段名 + */ + String value() default ""; + + /** + * 是否必须存在该字段。 + * + * @return true 表示必须存在 + */ + boolean required() default true; +} diff --git a/src/main/java/com/imyeyu/spring/annotation/RequestBodyValueArgumentResolver.java b/src/main/java/com/imyeyu/spring/annotation/RequestBodyValueArgumentResolver.java new file mode 100644 index 0000000..49b6df9 --- /dev/null +++ b/src/main/java/com/imyeyu/spring/annotation/RequestBodyValueArgumentResolver.java @@ -0,0 +1,82 @@ +package com.imyeyu.spring.annotation; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.imyeyu.java.TimiJava; +import com.imyeyu.java.bean.timi.TimiCode; +import com.imyeyu.java.bean.timi.TimiException; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.core.MethodParameter; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +/** + * {@link RequestBodyValue} 参数解析器。 + * + * @author 夜雨 + * @version 2026-04-08 11:00 + */ +@Component +public class RequestBodyValueArgumentResolver implements HandlerMethodArgumentResolver { + + private static final String REQUEST_BODY_JSON_NODE_ATTR = RequestBodyValueArgumentResolver.class.getName() + ".REQUEST_BODY_JSON_NODE"; + + private final ObjectMapper objectMapper; + + /** + * 创建 {@link RequestBodyValue} 参数解析器。 + * + * @param objectMapper Jackson 对象映射器 + */ + public RequestBodyValueArgumentResolver(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @Override + public boolean supportsParameter(@NonNull MethodParameter parameter) { + return parameter.hasParameterAnnotation(RequestBodyValue.class); + } + + @Override + public Object resolveArgument(@NonNull MethodParameter parameter, ModelAndViewContainer mavContainer, @NonNull NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + RequestBodyValue bodyValue = parameter.getParameterAnnotation(RequestBodyValue.class); + if (bodyValue == null) { + return null; + } + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + TimiException.required(request, "not found request"); + assert request != null; + + JsonNode requestBody; + { + Object cached = request.getAttribute(REQUEST_BODY_JSON_NODE_ATTR); + if (cached instanceof JsonNode jsonNode) { + return jsonNode; + } + byte[] bodyBytes = request.getInputStream().readAllBytes(); + TimiException.requiredTrue(1 < bodyBytes.length, "empty request body"); + requestBody = objectMapper.readTree(bodyBytes); + TimiException.requiredTrue(requestBody != null && requestBody.isObject(), "not object request body"); + request.setAttribute(REQUEST_BODY_JSON_NODE_ATTR, requestBody); + } + String fieldName = bodyValue.value(); + { + if (TimiJava.isEmpty(fieldName)) { + fieldName = parameter.getParameterName(); + } + TimiException.required(fieldName, "not found @RequestBodyValue parameter name"); + } + JsonNode fieldNode = requestBody.get(fieldName); + if (fieldNode == null || fieldNode.isMissingNode() || fieldNode.isNull()) { + if (!bodyValue.required()) { + return null; + } + throw new TimiException(TimiCode.ARG_MISS, "not found json field: %s".formatted(fieldName)); + } + return objectMapper.treeToValue(fieldNode, parameter.getParameterType()); + } +} -- 2.49.1 From 8a6e148d6c325e801e6231474a1ef02e5bcf69de Mon Sep 17 00:00:00 2001 From: Timi Date: Wed, 8 Apr 2026 11:50:27 +0800 Subject: [PATCH 3/4] add ObjectMapper arg for RedisSerializers.jacksonSerializer --- .../imyeyu/spring/util/RedisSerializers.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/imyeyu/spring/util/RedisSerializers.java b/src/main/java/com/imyeyu/spring/util/RedisSerializers.java index bb157ed..b0a56ef 100644 --- a/src/main/java/com/imyeyu/spring/util/RedisSerializers.java +++ b/src/main/java/com/imyeyu/spring/util/RedisSerializers.java @@ -87,19 +87,29 @@ public class RedisSerializers { /** * Json 序列化 * - * @param 数据类型 + * @param 数据类型 * @param clazz 数据类型 * @return Redis 序列化器 */ public static RedisSerializer jacksonSerializer(Class clazz) { - return new RedisSerializer<>() { + return jacksonSerializer(new ObjectMapper(), clazz); + } - private static final ObjectMapper JACKSON = new ObjectMapper(); + /** + * Json 序列化 + * + * @param 数据类型 + * @param mapper 序列化对象 + * @param clazz 数据类型 + * @return Redis 序列化器 + */ + public static RedisSerializer jacksonSerializer(ObjectMapper mapper, Class clazz) { + return new RedisSerializer<>() { @Override public byte[] serialize(T object) throws SerializationException { try { - return JACKSON.writeValueAsString(object).getBytes(StandardCharsets.UTF_8); + return mapper.writeValueAsString(object).getBytes(StandardCharsets.UTF_8); } catch (JsonProcessingException e) { throw new RuntimeException(e); } @@ -111,7 +121,7 @@ public class RedisSerializers { return null; } try { - return JACKSON.readValue(new String(bytes, StandardCharsets.UTF_8), clazz); + return mapper.readValue(new String(bytes, StandardCharsets.UTF_8), clazz); } catch (IOException e) { throw new RuntimeException(e); } -- 2.49.1 From 31bb990d82d0bdb01637f50699ee52ed67579fc3 Mon Sep 17 00:00:00 2001 From: Timi Date: Wed, 8 Apr 2026 20:33:33 +0800 Subject: [PATCH 4/4] v0.0.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f2a8b3c..32b0404 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ com.imyeyu.spring timi-spring - 0.0.8 + 0.0.9 jar -- 2.49.1