通过注解实现POST请求传递单个参数

由于spring中没有提供类似于@RequestParam注解,对单个参数的POST请求数据进行绑定的注解,所以自定义注解@RequestPostSingleParam实现POST请求的单个注解绑定。

一、创建注解

/**
 * post请求单参数绑定
 *
 * @Author zhaoxz
 * @Data 2023/3/21 16:13
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestPostSingleParam {

    @AliasFor("name")
    String value() default "";

    /**
     * The name of the request parameter to bind to.
     *
     * @since 4.2
     */
    @AliasFor("value")
    String name() default "";

    /**
     * Whether the parameter is required.
     * <p>Defaults to {@code true}, leading to an exception being thrown
     * if the parameter is missing in the request. Switch this to
     * {@code false} if you prefer a {@code null} value if the parameter is
     * not present in the request.
     * <p>Alternatively, provide a {@link #defaultValue}, which implicitly
     * sets this flag to {@code false}.
     */
    boolean required() default true;

    /**
     * The default value to use as a fallback when the request parameter is
     * not provided or has an empty value.
     * <p>Supplying a default value implicitly sets {@link #required} to
     * {@code false}.
     */
    String defaultValue() default ValueConstants.DEFAULT_NONE;
}

二、RequestPostSingleParam参数解析器

/**
 * RequestPostSingleParam参数解析器
 *
 * @Author zhaoxz
 * @Data 2023/3/21 16:18
 */
public class RequestPostSingleParamMethodArgumentResolver implements HandlerMethodArgumentResolver {
    private final Logger log = LoggerFactory.getLogger(RequestPostSingleParamMethodArgumentResolver.class);
    private static final String POST = "post";
    private static final String APPLICATION_JSON = "application/json";

    /**
     * 判断是否需要处理该参数
     *
     * @param parameter
     * @return boolean
     * @Author zhaoxz
     * @Date 2023/3/21 16:20
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 只处理带有@RequestPostSingleParam注解的参数
        return parameter.hasParameterAnnotation(RequestPostSingleParam.class);
    }

    /**
     * 参数绑定
     *
     * @param parameter     要解析的方法参数
     * @param mavContainer  当前请求的ModelAndViewContainer
     * @param webRequest    当前请求
     * @param binderFactory 用于创建WebDataBinder实例的工厂
     * @return
     * @throws Exception
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 请求对象
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        // 请求对象空判
        String contentType = Objects.requireNonNull(servletRequest).getContentType();

        if (contentType == null || !contentType.contains(APPLICATION_JSON)) {
            log.error("请求: {}格式错误, contentType需为 {}", servletRequest.getRequestURL().toString(), APPLICATION_JSON);
            throw new RuntimeException("请求contentType错误");
        }

        if (!POST.equalsIgnoreCase(servletRequest.getMethod())) {
            log.error("请求: {}格式错误, 请求方式需为 {}", servletRequest.getRequestURL().toString(), POST);
            throw new RuntimeException("请求方式错误");
        }
        // 创建请求
        return this.bindRequestParams(parameter, servletRequest);
    }

    /**
     * 创建请求
     *
     * @param parameter      请求参数
     * @param servletRequest 请求对象
     * @return Object
     * @Author zhaoxz
     * @Date 2023/3/21 16:31
     */
    private Object bindRequestParams(MethodParameter parameter, HttpServletRequest servletRequest) {
        // 获取RequestPostSingleParam注解信息
        RequestPostSingleParam requestPostSingleParam = parameter.getParameterAnnotation(RequestPostSingleParam.class);
        // 参数类型
        Class<?> parameterType = parameter.getParameterType();
        // 获取body数据
        String requestBody = this.getRequestBody(servletRequest);
        // str -> json
        JSONObject paramObj = JSONObject.parseObject(requestBody);
        // 请求参数为空判定
        if (paramObj == null) {
            paramObj = new JSONObject();
        }

        // 绑定参数名称获取
        String parameterName = StringUtils.isBlank(requestPostSingleParam.value()) ? parameter.getParameterName()
                : requestPostSingleParam.value();
        // 获取参数值
        Object value = paramObj.get(parameterName);

        // 必填判定
        if (requestPostSingleParam.required()) {
            if (ObjectUtils.isEmpty(value)) {
                log.error("请求: {}, {}参数不可为空", servletRequest.getRequestURL().toString(), parameterName);
                throw new CustomException("参数【%s】不能为空", parameterName);
            }
        }
        return ConvertUtils.convert(value, parameterType);
    }

    /**
     * 获取请求body
     *
     * @param servletRequest 请求对象
     * @return String body信息
     * @Author zhaoxz
     * @Date 2023/3/21 16:33
     */
    private String getRequestBody(HttpServletRequest servletRequest) {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            BufferedReader reader = servletRequest.getReader();
            char[] buf = new char[1024];
            int length;
            while ((length = reader.read(buf)) != -1) {
                stringBuilder.append(buf, 0, length);
            }
        } catch (IOException e) {
            log.error("请求对象读取异常", e);
            throw new RuntimeException("获取请求body数据异常");
        }
        return stringBuilder.toString();
    }
}

三、注册参数解析器

@Configuration
public class SpringMvcConfiguration implements WebMvcConfigurer {
    /**
     * 注册参数解析器
     *
     * @param resolvers 解析器列表
     * @return void
     * @Author zhaoxz
     * @Date 2023/3/21 16:51
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new RequestPostSingleParamMethodArgumentResolver());
        WebMvcConfigurer.super.addArgumentResolvers(resolvers);
    }

四、使用测试

    @PostMapping("/test")
    public ResponseBO<Void> test(@RequestPostSingleParam("testId") String testId) {
        log.info("/api/test, 测试【{}】", contestId);
        return new ResponseBO<>(SysErrEnum.SUCCESS);
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值