
写在前面源码 。截至当前我们的mvc还不支持接收来自request中的参数本文来实现这部分内容。最终实现如下效果1正文来定义类WebDataBinder作为数据绑定的总入口如下// com.hc.minispring.web.v5_databind.WebDataBinder// 1负责完成值绑定职责的类大一统的类publicclassWebDataBinder{// 要绑定的目标对象privateObjecttarget;privateClass?clz;privateStringobjectName;AbstractPropertyAccessorpropertyAccessor;publicWebDataBinder(Objecttarget){this(target,);}publicWebDataBinder(Objecttarget,StringtargetName){// ...}publicvoidbind(HttpServletRequestrequest){PropertyValuesmpvsassignParameters(request);// addBindValues(mpvs, request);doBind(mpvs);}privatevoiddoBind(PropertyValuesmpvs){applyPropertyValues(mpvs);}protectedvoidapplyPropertyValues(PropertyValuesmpvs){getPropertyAccessor().setPropertyValues(mpvs);}// ...}这里我们通过bind方法完成绑定首先解析request中的参数转换到PropertyValuesname,value等中然后通过doBind方法完成绑定。现在我们已经有了要绑定的对象也有了需要绑定的数据接下来就是怎么绑定的问题了。首先request中的数据类型到目标对象的数据类型是需要一个转换操作的为此定义接口/** * string-其他类型 接口 * 如string-Integer通过setText方法完成转换通过getValue方法获取转换结果 * 这里方法名称起的有些欠考虑不是特别的见名知意 */publicinterfacePropertyEditor{// 先调用该方法完成转换通过该方法完成转换具体实现类需要在本地定义变量存储转化结果已被用voidsetAsText(Stringtext);// 不依赖输入直接设置一个合理的数据比如期望获取方法执行的时间场景voidsetValue(Objectvalue);// 通过该方法获取转换后的结果必须在setAsText方法后调用ObjectgetValue();// 获取原始值StringgetAsText();}接着我们就可以定义各种实现类了为了管理这些实现类再来定义类PropertyEditorRegistrySupport负责维护并返回这些实现类们packagecom.hc.minispring.web.v5_databind.beans;// ...publicclassPropertyEditorRegistrySupport{privateMapClass?,PropertyEditordefaultEditors;privateMapClass?,PropertyEditorcustomEditors;publicPropertyEditorRegistrySupport(){registerDefaultEditors();}protectedvoidregisterDefaultEditors(){createDefaultEditors();}publicPropertyEditorgetDefaultEditor(Class?requiredType){returnthis.defaultEditors.get(requiredType);}privatevoidcreateDefaultEditors(){this.defaultEditorsnewHashMap(64);// Default instances of collection editors.this.defaultEditors.put(int.class,newCustomNumberEditor(Integer.class,false));this.defaultEditors.put(Integer.class,newCustomNumberEditor(Integer.class,true));this.defaultEditors.put(long.class,newCustomNumberEditor(Long.class,false));this.defaultEditors.put(Long.class,newCustomNumberEditor(Long.class,true));// this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));// this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));// this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));// this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));// this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));// this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));this.defaultEditors.put(String.class,newStringEditor(String.class,true));}// ...}defaultEditors作为了内置的属性转换实现customEditors作为用户自定义的属性转换实现这种预留扩展口子的方式在我们日常工作中也要考虑用起来。再来定义PropertyEditorRegistrySupport类的子类com.hc.minispring.web.v5_databind.BeanWrapperImpl完成真正的绑定工作packagecom.hc.minispring.web.v5_databind;importjava.lang.reflect.Field;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;importcom.hc.minispring.web.v5_databind.beans.AbstractPropertyAccessor;importcom.hc.minispring.web.v5_databind.beans.PropertyValue;publicclassBeanWrapperImplextendsAbstractPropertyAccessor{ObjectwrappedObject;Class?clz;publicBeanWrapperImpl(Objectobject){super();this.wrappedObjectobject;this.clzobject.getClass();}OverridepublicvoidsetPropertyValue(PropertyValuepv){BeanPropertyHandlerpropertyHandlernewBeanPropertyHandler(pv.getName());PropertyEditorpethis.getCustomEditor(propertyHandler.getPropertyClz());if(penull){pethis.getDefaultEditor(propertyHandler.getPropertyClz());}if(penull){thrownewIllegalArgumentException(can not find property editor for type: propertyHandler.getPropertyClz() ,please consider register one!);}if(pe!null){pe.setAsText((String)pv.getValue());propertyHandler.setValue(pe.getValue());}else{propertyHandler.setValue(pv.getValue());}}// 负责设置值到目标对象中反射classBeanPropertyHandler{MethodwriteMethodnull;MethodreadMethodnull;Class?propertyClznull;publicClass?getPropertyClz(){returnpropertyClz;}publicBeanPropertyHandler(StringpropertyName){try{Fieldfieldclz.getDeclaredField(propertyName);propertyClzfield.getType();this.writeMethodclz.getDeclaredMethod(setpropertyName.substring(0,1).toUpperCase()propertyName.substring(1),propertyClz);this.readMethodclz.getDeclaredMethod(getpropertyName.substring(0,1).toUpperCase()propertyName.substring(1));}catch(NoSuchMethodExceptione){// ...}}publicvoidsetValue(Objectvalue){writeMethod.setAccessible(true);try{writeMethod.invoke(wrappedObject,value);}catch(IllegalAccessExceptione){// ...}}}}类BeanPropertyHandler负责通过反射设置值到目标对象中接着就是通过具体数据类型获取对应的属性编辑器转换为目标类型值最后反射设置搞定还有一个问题就是如何预留自定义编辑器的口子为此定义接口/** * 负责注册自定义编辑器 */publicinterfaceWebBindingInitializer{voidinitBinder(WebDataBinderbinder);}string转java.util.Date实现类publicclassDateInitializerimplementsWebBindingInitializer{publicvoidinitBinder(WebDataBinderbinder){binder.registerCustomEditor(Date.class,newCustomDateEditor(Date.class,yyyy-MM-dd,false));}}CustomDateEditor自定义类packagecom.hc.minispring.web.v5_databind;// ...publicclassCustomDateEditorimplementsPropertyEditor{privateClassDatedateClass;privateDateTimeFormatterdatetimeFormatter;privatebooleanallowEmpty;privateDatevalue;publicCustomDateEditor()throwsIllegalArgumentException{this(Date.class,yyyy-MM-dd,true);}// ...}注册到bean中?xml version1.0 encodingUTF-8?beansbeanidaserviceclasscom.hc.minispring.web.v5_databind.test.AServiceImpl/beanidwebBindingInitializerclasscom.hc.minispring.web.v5_databind.DateInitializer/bean/beans接着我们还需要完成对应类型初始化器的注册工作这个工作我们在webdatabinder的工厂类中完成创建webdatabinder类后完成注册如下// com.hc.minispring.web.v5_databind.WebDataBinderFactorypackagecom.hc.minispring.web.v5_databind;// ...publicclassWebDataBinderFactory{// public WebDataBinder createBinder(HttpServletRequest request, Object target, String objectName) {publicWebDataBindercreateBinder(HttpServletRequestrequest,Objecttarget,StringobjectName,WebApplicationContextwac){WebDataBinderwbdnewWebDataBinder(target,objectName);// initBinder(wbd, request);initBinder(wbd,request,wac);returnwbd;}protectedvoidinitBinder(WebDataBinderdataBinder,HttpServletRequestrequest,WebApplicationContextwac){try{// WebBindingInitializer webBindingInitializer (WebBindingInitializer) wac.getBean(webBindingInitializer);// MapString, WebBindingInitializer webBindingInitializerMap wac.getBeansOfType(WebBindingInitializer.class);String[]beanNameswac.getBeanDefinitionNames();String[]parentBeanNames((AnnotationConfigWebApplicationContext)wac).getParentApplicationContext().getBeanDefinitionNames();String[]mergedBeanNamesnewString[beanNames.lengthparentBeanNames.length];System.arraycopy(beanNames,0,mergedBeanNames,0,beanNames.length);System.arraycopy(parentBeanNames,0,mergedBeanNames,beanNames.length,parentBeanNames.length);// 注册自定义数据绑定编辑器for(StringmergedBeanName:mergedBeanNames){if(mergedBeanName.indexOf(webBindingInitializer)0){((WebBindingInitializer)wac.getBean(webBindingInitializer)).initBinder(dataBinder);}}/*for (Map.EntryString, WebBindingInitializer stringWebBindingInitializerEntry : webBindingInitializerMap.entrySet()) { stringWebBindingInitializerEntry.getValue().initBinder(dataBinder); }*/// webBindingInitializer.initBinder(dataBinder);}catch(BeansExceptione){e.printStackTrace();}}}那么我们应该在哪里切入修改呢因为是调用目标方法时设置参数所以自然应该是在负责方法执行的HandlerAdapter中了这里是基于RequestMapping的实现类RequestMappingHandlerAdapter,修改如下// com.hc.minispring.web.v4_split_dispatcher.RequestMappingHandlerAdapterpackagecom.hc.minispring.web.v4_split_dispatcher;// .../** * 基于RequestMapping注解的具具体执行方法实现类 */publicclassRequestMappingHandlerAdapterimplementsHandlerAdapter{WebApplicationContextwac;// 负责注册数据绑定自定义编辑器WebBindingInitializerwebBindingInitializer;publicRequestMappingHandlerAdapter(WebApplicationContextwac){this.wacwac;try{this.webBindingInitializer(WebBindingInitializer)this.wac.getBean(webBindingInitializer);}catch(BeansExceptione){e.printStackTrace();}}Overridepublicvoidhandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{handleInternal(request,response,(HandlerMethod)handler);}privatevoidhandleInternal(HttpServletRequestrequest,HttpServletResponseresponse,HandlerMethodhandlerMethod)throwsException{/* Method method handler.getMethod(); Object obj handler.getBean(); Object objResult null; try { objResult method.invoke(obj); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } try { response.getWriter().append(objResult.toString()); } catch (IOException e) { e.printStackTrace(); }*/WebDataBinderFactorybinderFactorynewWebDataBinderFactory();Parameter[]methodParametershandlerMethod.getMethod().getParameters();Object[]methodParamObjsnewObject[methodParameters.length];inti0;//对调用方法里的每一个参数处理绑定for(ParametermethodParameter:methodParameters){ObjectmethodParamObjmethodParameter.getType().newInstance();//给这个参数创建WebDataBinderWebDataBinderwdbbinderFactory.createBinder(request,methodParamObj,methodParameter.getName(),wac);// // 注册自定义数据绑定编辑器// this.webBindingInitializer.initBinder(wdb);wdb.bind(request);methodParamObjs[i]methodParamObj;i;}MethodinvocableMethodhandlerMethod.getMethod();ObjectreturnObjinvocableMethod.invoke(handlerMethod.getBean(),methodParamObjs);response.getWriter().append(returnObj.toString());}}定义一个controller测试下publicclassHelloController{AutowiredprivateAServiceaservice;RequestMapping(/hello1527)// public String doTest(String name) {publicStringdoTest(Useruser){returnaservice.sayHello()--user;}}publicclassUser{privateStringname;privateIntegerage;privateDatebirthday;// ...}启动测试写在后面参考文章列表手把手带你写一个 MiniSpring 。