Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >从原理层面掌握@InitBinder的使用【享学Spring MVC】

从原理层面掌握@InitBinder的使用【享学Spring MVC】

作者头像
YourBatman
发布于 2019-09-18 06:49:10
发布于 2019-09-18 06:49:10
3.4K00
代码可运行
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦
运行总次数:0
代码可运行

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

代码语言:txt
AI代码解释
复制
                 本文链接:[https://blog.csdn.net/f641385712/article/details/95473929](https://blog.csdn.net/f641385712/article/details/95473929) 
每篇一句

大魔王张怡宁:女儿,这堆金牌你拿去玩吧,但我的银牌不能给你玩。你要想玩银牌就去找你王浩叔叔吧,他那银牌多

前言

为了讲述好Spring MVC最为复杂的数据绑定这块,我前面可谓是做足了功课,对此部分知识此处给小伙伴留一个学习入口,有兴趣可以点开看看:聊聊Spring中的数据绑定 — WebDataBinder、ServletRequestDataBinder、WebBindingInitializer…【享学Spring】

@InitBinder这个注解是Spring 2.5后推出来,用于数据绑定、设置数据转换器等,字面意思是“初始化绑定器”。

关于数据绑定器的概念,前面的功课中有重点详细讲解,此处默认小伙伴是熟悉了的~

Spring MVC的web项目中,相信小伙伴们经常会遇到一些前端给后端传值比较棘手的问题:比如最经典的问题:

  • Date类型(或者LocalDate类型)前端如何传?后端可以用Date类型接收吗?
  • 字符串类型,如何保证前段传入的值两端没有空格呢?(99.99%的情况下多余的空格都是木有用的)

对于这些看似不太好弄的问题,看了这篇文章你就可以优雅的搞定了~



说明:关于Date类型的传递,业界也有两个通用的解决方案

  1. 使用时间戳
  2. 使用String字符串(传值的万能方案)

使用者两种方式总感觉不优雅,且不够面向对象。那么本文就介绍一个黑科技:使用@InitBinder来便捷的实现各种数据类型的数据绑定(咱们Java是强类型语言且面向对象的,如果啥都用字符串,是不是也太low了~)

一般的string, int, long会自动绑定到参数,但是自定义的格式spring就不知道如何绑定了 .所以要继承PropertyEditorSupport,实现自己的属性编辑器PropertyEditor,绑定到WebDataBinder ( binder.registerCustomEditor),覆盖方法setAsText



@InitBinder原理

本文先原理,再案例的方式,让你能够彻头彻尾的掌握到该注解的使用。

1、**@InitBinder**是什么时候生效的?

这就是前面文章埋下的伏笔:Spring在绑定请求参数到HandlerMethod的时候(此处以RequestParamMethodArgumentResolver为例),会借助WebDataBinder进行数据转换:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// RequestParamMethodArgumentResolver的父类就是它,resolveArgument方法在父类上
// 子类仅仅只需要实现抽象方法resolveName,即:从request里根据name拿值
AbstractNamedValueMethodArgumentResolver:

	@Override
	@Nullable
	public final Object resolveArgument( ... ) {
		...
		Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
		...
		if (binderFactory != null) {
			// 创建出一个WebDataBinder
			WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
			// 完成数据转换(比如String转Date、String转...等等)
			arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
			...
		}
		...
		return arg;
	}

它从请求request拿值得方法便是:request.getParameterValues(name)

2、web环境使用的数据绑定工厂是:**ServletRequestDataBinderFactory**

虽然在前面功课中有讲到,但此处为了连贯性还是有必要再简单过一遍:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// @since 3.1 org.springframework.web.bind.support.DefaultDataBinderFactory 
public class DefaultDataBinderFactory implements WebDataBinderFactory {

	@Override
	@SuppressWarnings("deprecation")
	public final WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception {
		WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
		
		// WebBindingInitializer initializer在此处解析完成了 全局生效
		if (this.initializer != null) {
			this.initializer.initBinder(dataBinder, webRequest);
		}
		// 解析@InitBinder注解,它是个protected空方法,交给子类复写实现
		// InitBinderDataBinderFactory对它有复写
		initBinder(dataBinder, webRequest);
		return dataBinder;
	}
}

public class InitBinderDataBinderFactory extends DefaultDataBinderFactory {
	// 保存所有的,
	private final List<InvocableHandlerMethod> binderMethods;
	...
	@Override
	public void initBinder(WebDataBinder dataBinder, NativeWebRequest request) throws Exception {
		for (InvocableHandlerMethod binderMethod : this.binderMethods) {
			if (isBinderMethodApplicable(binderMethod, dataBinder)) {
				// invokeForRequest这个方法不用多说了,和调用普通控制器方法一样
				// 方法入参上也可以写格式各样的参数~~~~
				Object returnValue = binderMethod.invokeForRequest(request, null, dataBinder);
			
				// 标注有@InitBinder注解方法必须返回void
				if (returnValue != null) {
					throw new IllegalStateException("@InitBinder methods must not return a value (should be void): " + binderMethod);
				}
			}
		}
	}

	// dataBinder.getObjectName()在此处终于起效果了  通过这个名称来匹配
	// 也就是说可以做到让@InitBinder注解只作用在指定的入参名字的数据绑定上~~~~~
	// 而dataBinder的这个ObjectName,一般就是入参的名字(注解指定的value值~~)

	// 形参名字的在dataBinder,所以此处有个简单的过滤~~~~~~~
	protected boolean isBinderMethodApplicable(HandlerMethod initBinderMethod, WebDataBinder dataBinder) {
		InitBinder ann = initBinderMethod.getMethodAnnotation(InitBinder.class);
		Assert.state(ann != null, "No InitBinder annotation");
		String[] names = ann.value();
		return (ObjectUtils.isEmpty(names) || ObjectUtils.containsElement(names, dataBinder.getObjectName()));
	}
}

WebBindingInitializer接口方式是优先于@InitBinder注解方式执行的(API方式是去全局的,注解方式可不一定,所以更加的灵活些)

子类ServletRequestDataBinderFactory就做了一件事:new ExtendedServletRequestDataBinder(target, objectName)

ExtendedServletRequestDataBinder只做了一件事:处理path变量。

binderMethods是通过构造函数进来的,它表示和本次请求有关的所有的标注有@InitBinder的方法,所以需要了解它的实例是如何被创建的,那就是接下来这步。

3、**ServletRequestDataBinderFactory**的创建

任何一个请求进来,最终交给了HandlerAdapter.handle()方法去处理,它的创建流程如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
	...
	@Override
	protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		...
		// 处理请求,最终其实就是执行控制器的方法,得到一个ModelAndView
		mav = invokeHandlerMethod(request, response, handlerMethod);
		...
	}
	
	// 执行控制器的方法,挺复杂的。但本文我只关心WebDataBinderFactory的创建,方法第一句便是
	@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		...
	}

	// 创建一个WebDataBinderFactory 
	// Global methods first(放在前面最先执行) 然后再执行本类自己的
	private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
		// handlerType:方法所在的类(控制器方法所在的类,也就是xxxController)
		// 由此可见,此注解的作用范围是类级别的。会用此作为key来缓存
		Class<?> handlerType = handlerMethod.getBeanType();
		Set<Method> methods = this.initBinderCache.get(handlerType);
		if (methods == null) { // 缓存没命中,就去selectMethods找到所有标注有@InitBinder的方法们~~~~
			methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
			this.initBinderCache.put(handlerType, methods); // 缓存起来
		}
		
		// 此处注意:Method最终都被包装成了InvocableHandlerMethod,从而具有执行的能力
		List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
		
		// 上面找了本类的,现在开始看看全局里有木有@InitBinder
		// Global methods first(先把全局的放进去,再放个性化的~~~~ 所以小细节:有覆盖的效果哟~~~)
		// initBinderAdviceCache它是一个缓存LinkedHashMap(有序哦~~~),缓存着作用于全局的类。
		// 如@ControllerAdvice,注意和`RequestBodyAdvice`、`ResponseBodyAdvice`区分开来

		// methodSet:说明一个类里面是可以定义N多个标注有@InitBinder的方法~~~~~
		this.initBinderAdviceCache.forEach((clazz, methodSet) -> {
			
			// 简单的说就是`RestControllerAdvice`它可以指定:basePackages之类的属性,看本类是否能被扫描到吧~~~~
			if (clazz.isApplicableToBeanType(handlerType)) {
			
				// 这个resolveBean() 有点意思:它持有的Bean若是个BeanName的话,会getBean()一下的
				// 大多数情况下都是BeanName,这在@ControllerAdvice的初始化时会讲~~~
				Object bean = clazz.resolveBean();
				for (Method method : methodSet) {
					// createInitBinderMethod:把Method适配为可执行的InvocableHandlerMethod
					
					// 特点是把本类的HandlerMethodArgumentResolverComposite传进去了
					// 当然还有DataBinderFactory和ParameterNameDiscoverer等
					initBinderMethods.add(createInitBinderMethod(bean, method));
				}
			}
		});
		// 后一步:再条件标注有@InitBinder的方法
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			initBinderMethods.add(createInitBinderMethod(bean, method));
		}

		// protected方法,就一句代码:new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer())
		return createDataBinderFactory(initBinderMethods);
	}
	...
}

到这里,整个@InitBinder的解析过程就算可以全部理解了。关于这个过程,我有如下几点想说:

  • 对于binderMethods每次请求过来都会新new一个(具有第一次惩罚效果),它既可以来自于全局(Advice),也可以来自于Controller本类
  • 倘若Controller上的和Advice上标注有次注解的方法名一毛一样,也是不会覆盖的(因为类不一样)
  • 关于注解有@InitBinder的方法的执行,它和执行控制器方法差不多,都是调用了InvocableHandlerMethod#invokeForRequest方法,因此可以自行类比

目前方法执行的核心,无非就是对参数的解析、封装,也就是对HandlerMethodArgumentResolver的理解。强烈推荐你可以参考 这个系列的所有文章~


有了这些基础理论的支撑,接下来当然就是它的使用Demo Show

@InitBinder的使用案例

我抛出两个需求,借助@InitBinder来实现:

  1. 请求进来的所有字符串trim一下
  2. yyyy-MM-dd这种格式的字符串能直接用Date类型接收(不用先用String接收再自己转换,不优雅)

为了实现如上两个需求,我需要先自定义两个属性编辑器:

1、**StringTrimmerEditor**

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class StringTrimmerEditor extends PropertyEditorSupport {

    // 将属性对象用一个字符串表示,以便外部的属性编辑器能以可视化的方式显示。缺省返回null,表示该属性不能以字符串表示
    //@Override
    //public String getAsText() {
    //    Object value = getValue();
    //    return (value != null ? value.toString() : null);
    //}

    // 用一个字符串去更新属性的内部值,这个字符串一般从外部属性编辑器传入
    // 处理请求的入参:test就是你传进来的值(并不是super.getValue()哦~)
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        text = text == null ? text : text.trim();
        setValue(text);
    }
}

说明:Spring内置有org.springframework.beans.propertyeditors.StringTrimmerEditor,默认情况下它并没有装配进来,若你有需要可以直接使用它的(此处为了演示,我就用自己的)。Spring内置注册了哪些?参照PropertyEditorRegistrySupport#createDefaultEditors方法 Spring的属性编辑器和传统的用于IDE开发时的属性编辑器不同,它们没有UI界面,仅负责将配置文件中的文本配置值转换为Bean属性的对应值,所以Spring的属性编辑器并非传统意义上的JavaBean属性编辑器

2、**CustomDateEditor**

关于这个属性编辑器,你也可以像我一样自己实现。本文就直接使用Spring提供了的,参见:org.springframework.beans.propertyeditors.CustomDateEditor

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// @since 28.04.2003
// @see java.util.Date
public class CustomDateEditor extends PropertyEditorSupport {
	...
	@Override
	public void setAsText(@Nullable String text) throws IllegalArgumentException {
		...
		setValue(this.dateFormat.parse(text));
		...
	}
	...
	@Override
	public String getAsText() {
		Date value = (Date) getValue();
		return (value != null ? this.dateFormat.format(value) : "");
	}
}

定义好后,如何使用呢?有两种方式:

  1. API方式WebBindingInitializer ,关于它的使用,请参阅这里,本文略。
  2. 重写initBinder注册的属性编辑器是全局的属性编辑器,对所有的**Controller**都有效(全局的)
  3. @InitBinder**注解方式**

Controller本类上使用@InitBinder,形如这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Controller
@RequestMapping
public class HelloController {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        //binder.setDisallowedFields("name"); // 不绑定name属性
        binder.registerCustomEditor(String.class, new StringTrimmerEditor());

        // 此处使用Spring内置的CustomDateEditor
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }

    @ResponseBody
    @GetMapping("/test/initbinder")
    public String testInitBinder(String param, Date date) {
        return param + ":" + date;
    }
}

请求:/test/initbinder?param= ds&date=2019-12-12。结果为:ds:Thu Dec 12 00: 00: 00 CST 2019,符合预期。

注意,若date为null返回值为ds: null(因为我设置了允许为null) 但若你不是yyyy-MM-dd格式,那就抛错喽(格式化异常)

本例的@InitBinder方法只对当前Controller生效。要想全局生效,可以使用**@ControllerAdvice/WebBindingInitializer**。

通过@ControllerAdvice可以将对于控制器的全局配置放置在同一个位置,注解了@ControllerAdvice的类的方法可以使用@ExceptionHandler@InitBinder@ModelAttribute等注解到方法上,这对所有注解了@RequestMapping的控制器内的方法有效(关于全局的方式本文略,建议各位自己实践~)。

@InitBinder的value属性的作用

获取你可能还不知道,它还有个value属性呢,并且还是数组

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public @interface InitBinder {
	// 用于限定次注解标注的方法作用于哪个模型key上
	String[] value() default {};
}

说人话:若指定了value值,那么只有方法参数名(或者模型名)匹配上了此注解方法才会执行(若不指定,都执行)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Controller
@RequestMapping
public class HelloController {

    @InitBinder({"param", "user"})
    public void initBinder(WebDataBinder binder, HttpServletRequest request) {
        System.out.println("当前key:" + binder.getObjectName());
    }

    @ResponseBody
    @GetMapping("/test/initbinder")
    public String testInitBinder(String param, String date,
                                 @ModelAttribute("user") User user, @ModelAttribute("person") Person person) {
        return param + ":" + date;
    }
}

请求:/test/initbinder?param=fsx&date=2019&user.name=demoUser,控制台打印:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
当前key:param
当前key:user

从打印结果中很清楚的看出了value属性的作用~

需要说明一点:虽然此处有key是user.name,但是User对象可是不会封装到此值的(因为request.getParameter('user')没这个key嘛~)。如何解决???需要绑定前缀,原理可参考这里

其它应用场景

上面例举的场景是此注解最为常用的场景,大家务必掌握。它还有一些奇淫技巧的使用,心有余力的小伙伴不妨也可以消化消化:

若你一次提交需要提交两个"模型"数据,并且它们有重名的属性。形如下面例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Controller
@RequestMapping
public class HelloController {

    @Getter
    @Setter
    @ToString
    public static class User {
        private String id;
        private String name;
    }

    @Getter
    @Setter
    @ToString
    public static class Addr {
        private String id;
        private String name;
    }

    @InitBinder("user")
    public void initBinderUser(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("user.");
    }

    @InitBinder("addr")
    public void initBinderAddr(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("addr.");
    }

    @ResponseBody
    @GetMapping("/test/initbinder")
    public String testInitBinder(@ModelAttribute("user") User user, @ModelAttribute("addr") Addr addr) {
        return user + ":" + addr;
    }
}

请求:/test/initbinder?user.id=1&user.name=demoUser&addr.id=10&addr.name=北京市海淀区,结果为:HelloController.User(id=1, name=demoUser):HelloController.Addr(id=10, name=北京市海淀区)

至于加了前缀为何能绑定上,这里简要说说:

1、ModelAttributeMethodProcessor#resolveArgument里依赖attribute = createAttribute(name, parameter, binderFactory, webRequest)方法完成数据的封装、转换

2、createAttributerequest.getParameter(attributeName)看请求域里是否有值(此处为null),若木有就反射创建一个空实例,回到resolveArgument方法。

3、继续利用WebDataBinder来完成对这个空对象的数据值绑定,这个时候这些FieldDefaultPrefix就起作用了。执行方法是:bindRequestParameters(binder, webRequest),实际上是((WebRequestDataBinder) binder).bind(request);。对于bind方法的原理,就不陌生了~

4、完成Model数据的封装后,再进行@Valid校验…

参考解析类:ModelAttributeMethodProcessor对参数部分的处理

总结

本文花大篇幅从原理层面总结了@InitBinder这个注解的使用,虽然此注解在当下的环境中出镜率并不是太高,但我还是期望小伙伴能理解它,特别是我本文举例说明的例子的场景一定能做到运用自如。

最后,此注解的使用的注意事项我把它总结如下,供各位使用过程中参考:

  1. @InitBinder标注的方法执行是多次的,一次请求来就执行一次(第一次惩罚)
  2. Controller实例中的所有@InitBinder只对当前所在的Controller有效
  3. @InitBinder的value属性控制的是模型Model里的key,而不是方法名(不写代表对所有的生效)
  4. @InitBinder标注的方法不能有返回值(只能是void或者returnValue=null
  5. @InitBinder@RequestBody这种基于消息转换器的请求参数无效
  6. 因为@InitBinder它用于初始化DataBinder数据绑定、类型转换等功能,而@RequestBody它的数据解析、转换时消息转换器来完成的,所以即使你自定义了属性编辑器,对它是不生效的(它的**WebDataBinder**只用于数据校验,不用于数据绑定和数据转换。它的数据绑定转换若是json,一般都是交给了**jackson**来完成的
  7. 只有AbstractNamedValueMethodArgumentResolver才会调用binder.convertIfNecessary进行数据转换,从而属性编辑器才会生效
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年09月10日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring数据绑定之 WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...---02
上一篇我们对DataBinder的源码进行了详细的分析,下面我们对DataBinder的实现子类来做一下具体分析:
大忽悠爱学习
2022/08/23
4730
Spring数据绑定之 WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...---02
聊聊Spring中的数据绑定 --- WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...【享学Spring】
上篇文章聊了DataBinder,这篇文章继续聊聊实际应用中的数据绑定主菜:WebDataBinder。
YourBatman
2019/09/03
1.9K1
聊聊Spring中的数据绑定 --- WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...【享学Spring】
从原理层面掌握@ModelAttribute的使用(核心原理篇)【享学Spring MVC】
Spring MVC提供的基于注释的编程模型,极大的简化了web应用的开发,我们都是受益者。比如我们在@RestController标注的Controller控制器组件上用@RequestMapping、@ExceptionHandler等注解来表示请求映射、异常处理等等。 使用这种注解的方式来开发控制器我认为最重要的优势是:
YourBatman
2019/09/03
1.5K0
从原理层面掌握@ModelAttribute的使用(核心原理篇)【享学Spring MVC】
【工作篇】再次熟悉 SpringMVC 参数绑定
主要现在项目中使用的参数绑定五花八门的,搞得很头大,例如有些用字符串接收日期,用字符串接受数组等等,完全没有利用好 SpringMVC 的优势,这里自己也总结一下,免得到时又要百度谷歌查找。
玖柒的小窝
2021/12/17
6650
Spring MVC注解Controller源码流程解析--HandlerAdapter执行流程--上
前面已经详细介绍过了RequestMappingHandlerMapping是如何在初始化方法中搜集容器中所有标注了@Controller或者@RequestMapping注解的Bean的,然后解析将映射关系保存到映射中心。
大忽悠爱学习
2023/02/13
7930
Spring MVC注解Controller源码流程解析--HandlerAdapter执行流程--上
Spring Boot的数据绑定和参数传递(一)
Spring Boot 是一款基于Spring框架的开源框架,它可以帮助开发者快速搭建、配置和部署各种类型的应用程序。其中,数据绑定和参数传递是Spring Boot的两个核心功能之一,也是RESTful API开发中非常重要的一部分。
堕落飞鸟
2023/04/05
9990
你真的了解Spring MVC处理请求流程吗?
前言 阅读本文章大概需要8分钟左右。相信会让你对Spring MVC的理解更加深刻,更上一层楼。 SpringMVC图解 粒度很粗的图解 自己画的.png
用户2032165
2018/07/02
2K0
从原理层面掌握@SessionAttributes的使用【享学Spring MVC】
该注解顾名思义,作用是将Model中的属性同步到session会话当中,方便在下一次请求中使用(比如重定向场景~)。 虽然说Session的概念在当下前后端完全分离的场景中已经变得越来越弱化了,但是若为web开发者来说,我仍旧强烈不建议各位扔掉这个知识点,so我自然就建议大家能够熟练使用@SessionAttributes来简化平时的开发,本文带你入坑~
YourBatman
2019/09/03
2.2K0
从原理层面掌握@SessionAttributes的使用【享学Spring MVC】
从SpringMVC获取用户信息谈起
上周末拜读了一位牛人的公众号文章<[Token认证,如何快速方便获取用户信息](https://mp.weixin.qq.com/s/Qi82d5xmlYwiuaGRSn54uw)>,语言风趣,引人入胜,为了表示涛涛敬仰之情,已经转载到自己的公众号了。
A稻田守望者
2019/09/30
1.5K0
从SpringMVC获取用户信息谈起
SpringMvc 注解 @InitBinder 表单多对象精准绑定接收
@InitBinder用于在@Controller中标注于方法,表示为当前控制器注册一个属性编辑器或者其他,只对当前的Controller有效。
微风-- 轻许--
2019/07/02
1.8K0
@Validated和@Valid的区别?教你使用它完成Controller参数校验(含级联属性校验)以及原理分析【享学Spring】
上篇文章 介绍了Spring环境下实现优雅的方法级别的数据校验,并且埋下一个伏笔:它在Spring MVC(Controller层)里怎么应用呢?本文为此继续展开讲解Spring MVC中的数据校验~
YourBatman
2019/09/03
3.6K0
web九大组件之---RequestMappingHandlerAdapter详尽解析【享学Spring MVC】
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
YourBatman
2019/10/22
4.2K0
web九大组件之---RequestMappingHandlerAdapter详尽解析【享学Spring MVC】
解决:Failed to convert value of type ‘java.lang.String‘ to required type ‘java.util.Date‘;
发生这一错误的主要原因是Controller类中需要接收的是Date类型,但是在页面端传过来的是String类型,最终导致了这个错误。
全栈程序员站长
2022/09/14
6.5K0
解决:Failed to convert value of type ‘java.lang.String‘ to required type ‘java.util.Date‘;
spring 之 spring-mvc
spring-mvc的核心便是DispatcherServlet,所以初始化也是围绕其展开的。类图:
MickyInvQ
2021/10/22
1.1K0
spring 之 spring-mvc
解决:Failed to convert value of type 'java.lang.String' to required type 'java.util.Date';的方法
解决:Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; 发生这一错误的主要原因是Controller类中需要接收的是Date类型,但是在页面端传过来的是String类型,最终导致了这个错误。 这里提供两种解决方案,一种是局部转换,一种是全局转换。 <form action="login.do" method="post"> <input type="text" name=
Dream城堡
2018/09/10
131K2
从原理层面掌握HandlerMethod、InvocableHandlerMethod、ServletInvocableHandlerMethod的使用【享学Spring MVC】
HandlerMethod它作为Spring MVC的非公开API,可能绝大多数小伙伴都对它比较陌生,但我相信你对它又不是那么的生疏,因为你可能没用过但肯定见过。 比如Spring MVC的拦截器HandlerInterceptor的拦截方法的第三个入参Object handler,虽然它是Object类型,但其实绝大部分情况下我们都会当作HandlerMethod来使用;又比如我之前的这篇讲RequestMappingHandlerMapping的文章也大量的提到过HandlerMethod这个类。
YourBatman
2019/09/03
1.6K0
从原理层面掌握HandlerMethod、InvocableHandlerMethod、ServletInvocableHandlerMethod的使用【享学Spring MVC】
SpringMVC注解@initbinder解决类型转换问题
在使用SpringMVC的时候,经常会遇到表单中的日期字符串和JavaBean的Date类型的转换,而SpringMVC默认不支持这个格式的转换,所以需要手动配置,自定义数据的绑定才能解决这个问题。 在需要日期转换的Controller中使用SpringMVC的注解@initbinder和Spring自带的WebDateBinder类来操作。 WebDataBinder是用来绑定请求参数到指定的属性编辑器.由于前台传到controller里的值是String类型的,当往Model里Set这个值的时候,如果set的这个属性是个对象,Spring就会去找到对应的editor进行转换,然后再SET进去。 代码如下:
wuweixiang
2018/08/14
3430
SpringMVC注解 @initbinder 解决类型转换问题
使用 SpringMVC 时,常遇到表单中日期字符串和 JavaBean 的 Date 类型的转换,而 SpringMVC 默认不支持这个格式的转换,故需要手动配置,自定义数据的绑定才能解决这个问题。 在需要日期转换的 Controller 中使用 SpringMVC 的注解 @initbinder 和 Spring 自带的 WebDateBinder 类来操作。 WebDataBinder 是用来绑定请求参数到指定的属性编辑器.由于前端传到 controller 里的值是 String 类型的,当往 Model 里 Set这个值的时候,如果 set 的这个属性是个对象,Spring 就会去找到对应的 editor 进行转换,然后再 SET 进去。 代码如下:
微风-- 轻许--
2019/07/02
6030
Spring Boot搭建Web项目常用功能
     首先要弄清楚为什么要包装统一结构结果数据,这是因为当任意的ajax请求超时或者越权操作时,系统能返回统一的错误信息给到前端,前端通过封装统一的ajax请求统一处理这类错误信息(这样统一就避免每次都需要额外处理)。
hbbliyong
2018/07/24
1.1K0
SpringMVC数据绑定定义支持的数据绑定方式
定义 百度百科定义: 简单绑定是将一个用户界面元素(控件)的属性绑定到一个类型(对象)实例上的某个属性的方法。 例如,如果一个开发者有一个Customer类型的实例,那么他就可以把Customer的“Name”属性绑定到一个TextBox的“Text”属性上。“绑定”了这2个属性之后,对TextBox的Text属性的更改将“传播”到Customer的Name属性,而对Customer的Name属性的更改同样会“传播”到TextBox的Text属性。 支持的数据绑定方式 SpringMVC的各种参数包括对
JavaEdge
2018/04/28
5.6K0
SpringMVC数据绑定定义支持的数据绑定方式
推荐阅读
Spring数据绑定之 WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...---02
4730
聊聊Spring中的数据绑定 --- WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...【享学Spring】
1.9K1
从原理层面掌握@ModelAttribute的使用(核心原理篇)【享学Spring MVC】
1.5K0
【工作篇】再次熟悉 SpringMVC 参数绑定
6650
Spring MVC注解Controller源码流程解析--HandlerAdapter执行流程--上
7930
Spring Boot的数据绑定和参数传递(一)
9990
你真的了解Spring MVC处理请求流程吗?
2K0
从原理层面掌握@SessionAttributes的使用【享学Spring MVC】
2.2K0
从SpringMVC获取用户信息谈起
1.5K0
SpringMvc 注解 @InitBinder 表单多对象精准绑定接收
1.8K0
@Validated和@Valid的区别?教你使用它完成Controller参数校验(含级联属性校验)以及原理分析【享学Spring】
3.6K0
web九大组件之---RequestMappingHandlerAdapter详尽解析【享学Spring MVC】
4.2K0
解决:Failed to convert value of type ‘java.lang.String‘ to required type ‘java.util.Date‘;
6.5K0
spring 之 spring-mvc
1.1K0
解决:Failed to convert value of type 'java.lang.String' to required type 'java.util.Date';的方法
131K2
从原理层面掌握HandlerMethod、InvocableHandlerMethod、ServletInvocableHandlerMethod的使用【享学Spring MVC】
1.6K0
SpringMVC注解@initbinder解决类型转换问题
3430
SpringMVC注解 @initbinder 解决类型转换问题
6030
Spring Boot搭建Web项目常用功能
1.1K0
SpringMVC数据绑定定义支持的数据绑定方式
5.6K0
相关推荐
Spring数据绑定之 WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...---02
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验