创建自己的 class 将 HTTP 请求转换为 Spring 中的对象?
Create own class that transforms HTTP request to object in Spring?
我想创建自己的 class,它将在我的 Spring MVC 应用程序中转换 HTTP 请求并根据此 HTTP 请求初始化对象。我可以通过在方法中定义参数来创建对象,但我需要以我自己的方式进行映射并手动进行。
我如何使用我自己的实现来完成它,它将传递给 Spring 并且它会无缝地使用它?
更新1
友情提供的解决方案Bohuslav Burghardt
无效:
HTTP Status 500 - Request processing failed; nested exception is
java.lang.IllegalStateException: An Errors/BindingResult argument is
expected to be declared immediately after the model attribute, the
@RequestBody or the @RequestPart arguments to which they apply: public
java.lang.String
cz.deriva.derivis.api.oauth2.provider.controllers.OAuthController.authorize(api.oauth2.provider.domain.AuthorizationRequest,org.springframework.ui.Model,org.springframework.validation.BindingResult,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
也许我应该提到我使用自己的验证器:
public class RequestValidator {
public boolean supports(Class clazz) {
return AuthorizationRequest.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
AuthorizationRequest request = (AuthorizationRequest) obj;
if ("foobar".equals(request.getClientId())) {
e.reject("clientId", "nomatch");
}
}
}
和我在控制器中的方法声明(请不要需要验证 - @Valid
):
@RequestMapping(value = "/authorize", method = {RequestMethod.GET, RequestMethod.POST})
public String authorize(
@Valid AuthorizationRequest authorizationRequest,
BindingResult result
) {
}
我的应用程序中有两个配置 class。
@Configuration
@EnableAutoConfiguration
@EnableWebMvc
@PropertySource("classpath:/jdbc.properties")
public class ApplicationConfig {
}
和
@Configuration
@EnableWebMvc
public class WebappConfig extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthorizationRequestArgumentResolver());
}
}
怎么了?
更新 2
问题出在参数 BindingResult result
上,当我删除它时它可以正常工作。但是当出现一些错误时,我需要结果来处理它。
如果我正确理解了您的要求,您可以为此目的实施自定义 HandlerMethodArgumentResolver
。有关实施细节,请参见下面的示例:
模型对象
public class AuthorizationRequestHolder {
@Valid
private AuthorizationRequest authorizationRequest;
private BindingResult bindingResult;
// Constructors, accessors omitted
}
解析器
public class AuthorizationRequestMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return AuthorizationRequestHolder.class.isAssignableFrom(parameter.getParameterType());
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
// Map the authorization request
AuthorizationRequest authRequest = mapFromServletRequest(request);
AuthorizationRequestHolder authRequestHolder = new AuthorizationRequestHolder(authRequest);
// Validate the request
if (parameter.hasParameterAnnotation(Valid.class)) {
WebDataBinder binder = binderFactory.createBinder(webRequest, authRequestHolder, parameter.getParameterName());
binder.validate();
authRequestHolder.setBindingResult(binder.getBindingResult());
}
return authRequestHolder;
}
}
配置
@Configuration
@EnableWebMvc
public class WebappConfig extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthorizationRequestMethodArgumentResolver());
}
}
用法
@RequestMapping("/auth")
public void doSomething(@Valid AuthRequestHolder authRequestHolder) {
if (authRequestHolder.getBindingResult().hasErrors()) {
// Process errors
}
AuthorizationRequest authRequest = authRequestHolder.getAuthRequest();
// Do something with the authorization request
}
编辑:更新了带有 HandlerMethodArgumentResolver
参数的 @Valid
不支持用法的解决方法的答案。
我想创建自己的 class,它将在我的 Spring MVC 应用程序中转换 HTTP 请求并根据此 HTTP 请求初始化对象。我可以通过在方法中定义参数来创建对象,但我需要以我自己的方式进行映射并手动进行。
我如何使用我自己的实现来完成它,它将传递给 Spring 并且它会无缝地使用它?
更新1
友情提供的解决方案Bohuslav Burghardt
无效:
HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments to which they apply: public java.lang.String cz.deriva.derivis.api.oauth2.provider.controllers.OAuthController.authorize(api.oauth2.provider.domain.AuthorizationRequest,org.springframework.ui.Model,org.springframework.validation.BindingResult,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
也许我应该提到我使用自己的验证器:
public class RequestValidator {
public boolean supports(Class clazz) {
return AuthorizationRequest.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
AuthorizationRequest request = (AuthorizationRequest) obj;
if ("foobar".equals(request.getClientId())) {
e.reject("clientId", "nomatch");
}
}
}
和我在控制器中的方法声明(请不要需要验证 - @Valid
):
@RequestMapping(value = "/authorize", method = {RequestMethod.GET, RequestMethod.POST})
public String authorize(
@Valid AuthorizationRequest authorizationRequest,
BindingResult result
) {
}
我的应用程序中有两个配置 class。
@Configuration
@EnableAutoConfiguration
@EnableWebMvc
@PropertySource("classpath:/jdbc.properties")
public class ApplicationConfig {
}
和
@Configuration
@EnableWebMvc
public class WebappConfig extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthorizationRequestArgumentResolver());
}
}
怎么了?
更新 2
问题出在参数 BindingResult result
上,当我删除它时它可以正常工作。但是当出现一些错误时,我需要结果来处理它。
如果我正确理解了您的要求,您可以为此目的实施自定义 HandlerMethodArgumentResolver
。有关实施细节,请参见下面的示例:
模型对象
public class AuthorizationRequestHolder {
@Valid
private AuthorizationRequest authorizationRequest;
private BindingResult bindingResult;
// Constructors, accessors omitted
}
解析器
public class AuthorizationRequestMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return AuthorizationRequestHolder.class.isAssignableFrom(parameter.getParameterType());
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
// Map the authorization request
AuthorizationRequest authRequest = mapFromServletRequest(request);
AuthorizationRequestHolder authRequestHolder = new AuthorizationRequestHolder(authRequest);
// Validate the request
if (parameter.hasParameterAnnotation(Valid.class)) {
WebDataBinder binder = binderFactory.createBinder(webRequest, authRequestHolder, parameter.getParameterName());
binder.validate();
authRequestHolder.setBindingResult(binder.getBindingResult());
}
return authRequestHolder;
}
}
配置
@Configuration
@EnableWebMvc
public class WebappConfig extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthorizationRequestMethodArgumentResolver());
}
}
用法
@RequestMapping("/auth")
public void doSomething(@Valid AuthRequestHolder authRequestHolder) {
if (authRequestHolder.getBindingResult().hasErrors()) {
// Process errors
}
AuthorizationRequest authRequest = authRequestHolder.getAuthRequest();
// Do something with the authorization request
}
编辑:更新了带有 HandlerMethodArgumentResolver
参数的 @Valid
不支持用法的解决方法的答案。