自定义springmvc参数解析器

实现spring HandlerMethodArgumentResolver接口

通过使用@JsonArg自定义注解来解析json数据(通过fastjson的jsonPath),支持多个参数(@RequestBody只支持单个参数)

自定义注解@JsonArg

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JsonArg {
    /**
     * @see <a href="https://github.com/alibaba/fastjson/wiki/JSONPath">https://github.com/alibaba/fastjson/wiki/JSONPath</a>
     */
    String value() default "";
}

参数解析器实现

@Slf4j
public class JsonPathArgumentResolver implements HandlerMethodArgumentResolver {

    private static final String JSONBODYATTRIBUTE = "JSON_REQUEST_BODY";

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(JsonArg.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String body = getRequestBody(webRequest);
        String value = parameter.getParameterAnnotation(JsonArg.class).value();
        if (StringUtils.isBlank(value)) {
            value = parameter.getParameterName();
        }
        Object val = JSONPath.read(body, value);
        if (log.isDebugEnabled()) {
            log.debug("resolveArgument return class type:{}", val == null ? null : val.getClass().getName());
            log.debug("value:{}", val);
        }
        if (val instanceof JSONObject) {
            return JSON.parseObject(((JSONObject) val).toJSONString(), parameter.getParameterType());
        }
        if (val instanceof JSONArray) {
            ParameterizedType genericParameterType = (ParameterizedType) parameter.getGenericParameterType();
            // 泛型参数可能有多个,现在只处理了一个
            Type[] actualTypeArguments = genericParameterType.getActualTypeArguments();
            String typeName = actualTypeArguments[0].getTypeName();
            return JSON.parseArray(((JSONArray) val).toJSONString(), Class.forName(typeName));
        }
        //TODO 未实现基本类型之间互相转换
        return val;
    }

    private String getRequestBody(NativeWebRequest webRequest) {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        String jsonBody = (String) servletRequest.getAttribute(JSONBODYATTRIBUTE);
        if (jsonBody == null) {
            try {
                String body = IOUtils.toString(servletRequest.getInputStream(), StandardCharsets.UTF_8);
                servletRequest.setAttribute(JSONBODYATTRIBUTE, body);
                return body;
            } catch (Exception e) {
                log.error("read request body error:{}", e.getMessage());
                throw new RuntimeException(e);
            }
        }
        return jsonBody;
    }
}

配置

自定义参数解析器优先级低于spring提供的默认解析器,会被默认解析器处理

@Configuration
@EnableWebMvc
// springboot 2.0实现 WebMvcConfigurer 接口
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {

    /**
     * prioritize Custom ArgumentMethodHandlers
     */
    @Autowired
    public void prioritizeCustomArgumentMethodHandlers(RequestMappingHandlerAdapter adapter) {
        List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(adapter.getArgumentResolvers());
        List<HandlerMethodArgumentResolver> customResolvers = adapter.getCustomArgumentResolvers();
        argumentResolvers.removeAll(customResolvers);
        argumentResolvers.addAll(0, customResolvers);
        adapter.setArgumentResolvers(argumentResolvers);
    }

     
    /**
     * registry argumentResolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new JsonPathArgumentResolver());
    }
}

使用

    @PostMapping("/test.do")
    public void test(@JsonArg String name) {
        log.debug("name:{}", name);
    }
posted @ 2019-01-09 15:32  这谁顶着住啊  阅读(1058)  评论(0编辑  收藏  举报