WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name)
;
WebDataBinder :web数据绑定器,将请求参数的值绑定到指定的JavaBean里面
WebDataBinder 利用它里面的 Converters 将请求数据转成指定的数据类型。再次封装到JavaBean中
GenericConversionService(转换器
):在设置每一个值的时候,找它里面的所有converter
那个可以将这个数据类型(request带来参数的字符串)转换到指定的类型(JavaBean – Integer)
byte – > file
具有124个类型转换、
自动类型转换
赋值
以 kv 键值对的方式进行赋值
未来我们可以给WebDataBinder里面放自己的Converter;
private static final class StringToNumber implements Converter<String, T>。 就是说String转换成T类型
自定义conterver 转换器
由于公司业务的需要,我们在提交宠物表单的时候不使用级联的方式。要求名字是都好前面的。年龄是逗号后面的,这个时候我们可以使用SpringMVC的conterver转换器进行转换我们表单的类型
<form action="/saveuser" method="post"> 姓名: <input name="userName" value="jsxs"> 年龄: <input name="age" value="18"> 生日: <input name="birth" value="2019/12/17"> <!-- 宠物姓名: <input name="pet.name" value="阿猫">--> <!-- 宠物年龄: <input name="pet.age" value="5">--> 宠物: <input name="pet" value="阿毛,5"> <input type="submit" value="保存"> </form>
配置类转换器
@Bean public WebMvcConfigurer webMvcConfigurer(){ return new WebMvcConfigurer(){ // 配置支持我们的矩阵注解 @Override public void configurePathMatch(PathMatchConfigurer configurer) { UrlPathHelper helper = new UrlPathHelper(); helper.setRemoveSemicolonContent(false); configurer.setUrlPathHelper(helper); } // 配置支持我们的自定义converter转换器 @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new Converter<String, Pet>() { @Override public Pet convert(String source) { //source 就是页面提交过来的值。只获得过来的值 if (!StringUtils.isEmpty(source)){ // 假如说提交的数据不为空 Pet pet = new Pet(); String[] split = source.split(","); pet.setName(split[0]); // 逗号之前的设置成姓名 pet.setAge(Integer.parseInt(split[1])); return pet; } return null; } }); } }; }
// 数据绑定: 页面提交的请求数据(GET、POST)都可以和对象属性进行绑定 @PostMapping("/saveuser") // 我们的想法是: 因为传递过来的都是实体类的数据 public Person saveUser(Person person,@RequestBody String content){ return person; }
当124个找不到的时候就会找 配置文件看看有没有配置的。
(6).目标方法执行完成
HandlerMethodArgumentResolverComposite 类
将所有的数据都放在 ModelAndViewContainer;包含要去的页面地址View。还包含Model数据
。
(7).处理派发结果
这里解释了为什么我们Map 和 Model的值会变成 请求域中的值。
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
InternalResourceView 类 @Override protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // Expose the model object as request attributes. ⭐ exposeModelAsRequestAttributes(model, request); // Expose helpers as request attributes, if any. exposeHelpers(request); // Determine the path for the request dispatcher. String dispatcherPath = prepareForRendering(request, response); // Obtain a RequestDispatcher for the target resource (typically a JSP). RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); if (rd == null) { throw new ServletException("Could not get RequestDispatcher for [" + getUrl() + "]: Check that the corresponding file exists within your web application archive!"); } // If already included or response already committed, perform include, else forward. if (useInclude(request, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including [" + getUrl() + "]"); } rd.include(request, response); } else { // Note: The forwarded resource is supposed to determine the content type itself. if (logger.isDebugEnabled()) { logger.debug("Forwarding to [" + getUrl() + "]"); } rd.forward(request, response); } }
暴露模型作为请求域属性 // Expose the model object as request attributes. // 这个Model值就是Map 和 Model 一直追踪的值。 ⭐ exposeModelAsRequestAttributes(model, request);
protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception { // ⭐model中的所有数据遍历挨个放在请求域中 model.forEach((name, value) -> { if (value != null) { ⭐⭐ request.setAttribute(name, value); } else { request.removeAttribute(name); } }); }