在Spring中,为什么我们不能简单地使用请求对象在应用程序中携带数据?为什么我们切换到使用模型对象?另外,我在一本流行的Spring书中读到,它仍然是一个请求对象(即使在Spring应用程序中),它可以完成大部分的数据传输工作。这是否意味着我们在Spring中创建的模型以某种方式链接到引擎盖下的请求对象?
答案 0 :(得分:2)
在Spring中,为什么我们不能简单地使用请求对象来传输数据 在应用程序中?
您可以使用HttpServletRequest
甚至WebRequest
作为方法参数,然后检查这两个以便从中提取数据。例如,如果要获取名为page
的查询字符串的值:
@RequestMapping("/users")
public void listUsers(HttpServletRequest request) {
String page = request.getParameter("page");
...
}
为什么我们切换到使用模型对象?
您可以简单地从HttpServletRequest
读取并最终在任何控制器方法中写入HttpServletResponse
,但spring也提供了更好的抽象来处理典型的Web场景。例如,如果您的page
参数是必需的int参数,默认值为1
,那么您只需编写:
@RequestMapping("/users")
public void listUsers(@RequestParam(defaultValue = "1") Integer page) {
...
}
Spring会自动执行所有字符串到int的转换,并为您填充默认值。或者假设您要自动验证json或xml Request Body
并返回验证错误。通过这些更高的抽象,您将定义一个包含其中所有验证逻辑的model object
,并在引用它的方法参数之前简单地添加@Valid
注释,就是这样!
@RequestMappting(value = "/users", method = POST)
public void addNewUser(@RequestBody @Valid User user) {
// automatically validates the user
// and send validation error, if user wasn't valid
}
当然,您可以通过检查HttpServletRequest
来做同样的事情,但这会非常麻烦。
这是否意味着我们在Spring中创建的模型以某种方式链接到 引擎盖下的请求对象?
它们不一定是链接到它们,但通常这些模型对象将从请求参数填充。
例如,spring使用HttpMessageConverter
将请求主体转换为方法参数。 HttpMessageConverter
负责从HTTP请求消息转换为对象并从对象转换为HTTP响应主体。例如,FormHttpMessageConverter
将表单数据转换为MultiValueMap<String, String>
。此类有一个read
方法,用于读取请求正文并将其转换为MultiValueMap<String, String>
。此方法如下所示:
public MultiValueMap<String, String> read(Class<? extends MultiValueMap<String, ?>> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = (contentType.getCharSet() != null ? contentType.getCharSet() : this.charset);
String body = StreamUtils.copyToString(inputMessage.getBody(), charset);
String[] pairs = StringUtils.tokenizeToStringArray(body, "&");
MultiValueMap<String, String> result = new LinkedMultiValueMap<String, String>(pairs.length);
for (String pair : pairs) {
int idx = pair.indexOf('=');
if (idx == -1) {
result.add(URLDecoder.decode(pair, charset.name()), null);
}
else {
String name = URLDecoder.decode(pair.substring(0, idx), charset.name());
String value = URLDecoder.decode(pair.substring(idx + 1), charset.name());
result.add(name, value);
}
}
return result;
}
按String body = StreamUtils.copyToString(inputMessage.getBody(), charset);
,它实际上会读取请求正文并将其转换为String
。