83 lines
3.1 KiB
Java
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());
|
|
}
|
|
}
|