我正在使用 Spring Boot 1.5.15 开发REST API。我已经实现了一个客户HandlerMethodArgumentResolver
来映射HTTP标头。详细地说,我分配了HTTP标头Some-Header
的值,删除了前缀“ XXX”。
首先,我定义了一个自定义注释。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface SomeHeader {
}
然后,我实现了一个自定义解析器。
public class SomeHeaderArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(SomeHeader.class) != null;
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
final String headerValue = request.getHeader("Some-Header");
return headerValue.replace("XXX ", "");
}
}
最后,我让Spring在配置类中意识到了解析器。
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new SomeHeaderArgumentResolver());
}
}
现在,我可以在所需的任何控制器中使用以下映射。
@PostMapping("/some/paath")
public void someMethod(@SomeHeader String someHeaderValue) {
// Method body...
}
但是,Some-Header
信息对我来说是必填项。我希望,如果不存在,Spring会向调用者返回400 Bad Request响应。我可以使用@RequestHeader("Some-Header")
批注获得相同的行为。
我可以复制相同的行为吗?可能,我不想使用专门的控制器建议。
答案 0 :(得分:1)
对于任何情况,您都可以声明自己的异常,并在控制器中设置ExceptionHandler以返回正确的http状态。
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({SameHeaderException.class})
public Object onSameHeaderException(SameHeaderException e) {
return ImmutableMap.of("reason", e.getMessage());
}
因此,如果标题不存在,则可以引发此异常:
if (someHeaderValue == null) { throw new SameHeaderException(); }
答案 1 :(得分:1)
如果您看到用于RequestHeaderMethodArgumentResolver
的{{1}}的实现,则会看到@RequestHeader
抽象类的handleMissingValue
方法的重写实现,如下所示:< / p>
AbstractNamedValueMethodArgumentResolver
根据某些条件,此@Override
protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
throw new ServletRequestBindingException("Missing request header '" + name +
"' for method parameter of type " + parameter.getNestedParameterType().getSimpleName());
}
方法用在handleMissingValue
扩展的resolveArgument
的{{1}}方法中。因此,当标题不存在并且抛出AbstractNamedValueMethodArgumentResolver
时,Spring的RequestHeaderMethodArgumentResolver
会处理该问题并发送 400 响应。
这就是ServletRequestBindingException
时验证的工作方式。因此,您可以在DefaultHandlerExceptionResolver
类的@RequestHeader
方法中实现类似的操作,如下所示:
resolveArgument
答案 2 :(得分:0)
由于@ madhu-bhat给出的建议,我知道哪个是可以扩展的让Spring发挥作用的正确类。
Spring用于在Java对象中解析HTTP标头值的类RequestHeaderMethodArgumentResolver
扩展了抽象类AbstractNamedValueMethodArgumentResolver
。此类允许您使用createNamedValueInfo
方法指定标头值是否具有某些默认值。
因此,它遵循了代码。
public class SomeHeaderArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
@Override
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
// The second parameter specifies if the value is required,
// and the third if there is some default value.
return new NamedValueInfo("", true, null);
}
@Override
protected Object resolveName(String name,
MethodParameter parameter,
NativeWebRequest request) {
final String headerValue = request.getHeader("Some-Value");
if (StringUtils.isEmpty(headerValue)) {
// Returning null tells Spring that there is no value for the parameter
return null;
}
return headerValue.replace("XXX ", "");
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.hasParameterAnnotation(SomeHeader.class) &&
!Map.class.isAssignableFrom(
parameter.nestedIfOptional().getNestedParameterType()));
}
}
我唯一不喜欢的是我正在使用开发用于处理命名值的结构,但是我没有命名值。
希望有帮助。