我有一个控制器,它有以下方法
@RequestMapping(value = "/cases/{caseId}", params = "meta", method = PUT, produces = APPLICATION_JSON_VALUE)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public String updateUIMetadata(@PathVariable("caseId") final String caseId,
@RequestBody @JsonData(schemaLocation = "schema/metadata_schema.json") final String metadataJson) {
}
我正在实施自定义HandlerMethodArgumentResolver
public class ValidateJsonSchema implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(JsonData.class);
}
@Override
public String resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
System.out.println("Inside ValidateJsonSchema");
String json = (String) getRequestResponseBodyMethodProcessor().resolveArgument(parameter, mavContainer, webRequest, binderFactory);
return validateJson(json, parameter);
}
}
我已将其注册为bean,并在配置文件
中注册了参数解析器@Bean
public ValidateJsonSchema validateJsonSchema() {
return new ValidateJsonSchema();
}
@Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(validateJsonSchema());
}
但是由于一些奇怪的原因,参数解析器类从未调用过。有没有我错过的东西?
编辑:JsonData.java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface JsonData {
public String schemaLocation();
}
编辑2:AppInitializer.java
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET, new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(MAPPING_URL);
}
private AnnotationConfigWebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation(CONFIG_FILE_LOCATION);
return context;
}
}
答案 0 :(得分:0)
确保您的配置类使用 @Configuration
进行注释,并且还扩展 WebMvcConfigurationSupport
。
在配置类中也使用 @EnableWebMvc
。
答案 1 :(得分:0)
您的自定义参数解析器未被调用的原因是您的参数已由Spring RequestResponseBodyMethodProcessor
处理。该类负责处理用@RequestBody
注释的参数。
要使您的参数解析器发挥作用,只需删除@RequestBody
注释。
答案 2 :(得分:0)
另一种方法是使用 RequestBodyAdvice 并在方法 beforeBodyRead 中验证 json。唯一的缺点是当验证失败时你会得到响应 500,因为控制器永远不会收到对象。
@ControllerAdvice
class JsonSchemaBodyAdvice : RequestBodyAdvice {
@Autowired
private var jsonValidatorService: JsonValidatorService? = null
override fun supports(parameter: MethodParameter, type: Type, clazz: Class<out HttpMessageConverter<*>>): Boolean {
return parameter.parameter.getAnnotation(RequestBody::class.java) != null
}
override fun beforeBodyRead(
message: HttpInputMessage,
parameter: MethodParameter,
type: Type,
clazz: Class<out HttpMessageConverter<*>>
): HttpInputMessage {
val json = String(message.body.readAllBytes())
// VALIDATE SCHEMA HERE
// we can not reset the original input stream, wrap the json in a new object
return object : HttpInputMessage {
override fun getHeaders() = message.headers
override fun getBody() = ByteArrayInputStream(json.toByteArray(Charsets.UTF_8))
}
}
override fun afterBodyRead(
body: Any,
message: HttpInputMessage,
parameter: MethodParameter,
type: Type,
clazz: Class<out HttpMessageConverter<*>>
): Any {
return body
}
override fun handleEmptyBody(
body: Any?,
message: HttpInputMessage,
parameter: MethodParameter,
type: Type,
clazz: Class<out HttpMessageConverter<*>>
) = body
}
您也可以创建自己的注解来将架构文件设置为参数,例如@ValidRequestBody("schema.json")