Files
timi-spring/src/main/java/com/imyeyu/spring/annotation/RequestBodyValueArgumentResolver.java
2026-04-08 11:22:22 +08:00

83 lines
3.1 KiB
Java

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());
}
}