如何将 HttpServletRequest 参数添加到复杂的 RestController bean?

How to add HttpServletRequest param to complex RestController bean?

我有一个包含其余参数的复杂 bean,例如:

public class MyRestParams {
    private HttpServletRequest req;
    private @NotBlank String name;

    //getter, setter
}

用法:

@RestController 
@RequestMapping("/xml")
public class MyServlet {
    @RequestMapping(value = "/")
    public void getTest(@Valid MyRestParams p) {
        Sysout(p.getName()); //works when invoked with /xml?name=test
        Sysout(p.getReq()); //always null
    }
}

问题:HttpServletRequest 始终为空。不能在 bean 本身中添加此参数吗?

您可以为 HandlerMethodArgumentResolver 提供一个实现来解决您的 MyRestParams:

public class MyRestParamsArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(MyRestParams.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, 
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        MyRestParams restParam = new MyRestParams();
        restParam.setReq((HttpServletRequest) webRequest.getNativeRequest());

        return restParam;
    }
}

然后在您的WebMvcConfigurerAdapter中注册:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new MyRestParamsArgumentResolver());
    }
}

当使用那种形式的方法签名时 Spring 将使用您的 bean 作为模型属性。 Spring 将使用 WebDataBinder(例如 ServletRequestDataBinder)将您的请求参数绑定到匹配名称的 bean 属性。

因为没有与您的 bean 匹配的请求参数 属性 req 永远不会设置该字段。即使您的请求中存在名为 req 的请求参数,它也不会转换为 HttpServletRequest。

要接收实际请求,请将 HttpServletRequest 类型的参数添加到您的处理程序方法

 @RequestMapping(value = "/")
 public void getTest(@Valid MyRestParams p , HttpServletRequest request) {
    Sysout(p.getName()); //works when invoked with /xml?name=test
    Sysout(request); //always null
 }

如果您不想将自己绑定到 Servlet,则可以使用 WebRequest 类型的参数 API。