@RequestParam @ModelAttribute @RequestBodyjava
简单类型,复杂类型web
get;post:form-data x-www-form-urlencodedspring
@RequestMapping("test1") @ResponseBody public String test1(@RequestParam String p, @RequestParam Date date) { return p+"#"+date; }
解析@RequestParam参数经过RequestParamMethodArgumentResolver。json
先获取参数名数组
解析参数mvc
RequestParamMethodArgumentResolver#resolveNameapp
String[] paramValues = request.getParameterValues(name);ide
就是从request中获取值,注意返回的是String[],多是相同name放到一个数组中?post
类型转换ui
使用WebDataBinder,其中有typeConverter(TypeConverterSupport)
TypeConverterSupport其中有TypeConverterDelegate(PropertyEditorRegistrySupport)
PropertyEditorRegistrySupport有conversionService 和 PropertyEditor
//org.springframework.beans.PropertyEditorRegistrySupport private ConversionService conversionService; private boolean defaultEditorsActive = false; private boolean configValueEditorsActive = false; private Map<Class<?>, PropertyEditor> defaultEditors; private Map<Class<?>, PropertyEditor> overriddenDefaultEditors; private Map<Class<?>, PropertyEditor> customEditors; private Map<String, CustomEditorHolder> customEditorsForPath; private Map<Class<?>, PropertyEditor> customEditorCache;
先判断有没有PropertyEditor,没有再使用conversionService。
##经过post:form-data方式访问
解析post form-data中的值要配置,
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="${web.maxUploadSize}" /> </bean>
在DispatcherServlet中首先就检查是不是post,是否Content-Type 以multipart/ 开头。
若是是则将原来的HttpServletRequest 转变为MultipartHttpServletRequest
解析@RequestParam 主题步骤都同样,只不过从request获取数据的时候从DefaultMultipartHttpServletRequest中获取
//org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest#getParameterValues @Override public String[] getParameterValues(String name) { //从内部的map中获取 String[] values = getMultipartParameters().get(name); if (values != null) { return values; } return super.getParameterValues(name); }
static class DataWrapper { private String p; private Date date; public String getP() { return p; } public void setP(String p) { this.p = p; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } } @RequestMapping("test2") @ResponseBody public String test2(@RequestParam DataWrapper d) { return d.getP()+"#"+d.date; } @RequestMapping("test3") @ResponseBody public String test3(DataWrapper d) { return d.getP()+"#"+d.date; }
Test2 不能绑定,由于@RequestParam 只支持简单类型
去掉@RequestParam,test3就能够绑定。
InvokeHandlerMethod中注册的ArgumentResolvers
先判断哪一个Resolver能处理这个参数
没有@RequestParam 是ServletModelAttributeMethodProcessor来解析,为啥不是RequestParamMethodArgumentResolver?
Resolvers中最后一个annotationNotRequired= true来处理没有注解的参数。
而倒数第二个RequestParamMethodArgumentResolver useDefaultResolution = true,来处理没有注解的简单类型参数
ServletModelAttributeMethodProcessor中的类型转换,也是经过WebDataBinder作转换。
```java @InitBinder public void initBinder(WebDataBinder dataBinder) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); simpleDateFormat.setLenient(false); dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(simpleDateFormat, false)); }
### 添加自定义converter ```java /** * @author Arnold */ public class StringToDateConverter implements Converter<String,Date> { private String datePattern; public String getDatePattern() { return datePattern; } public void setDatePattern(String datePattern) { this.datePattern = datePattern; } @Override public Date convert(String source) { SimpleDateFormat dateFormat = new SimpleDateFormat(datePattern); try { Date parse = dateFormat.parse(source); return parse; } catch (ParseException e) { e.printStackTrace(); } return null; } }
或者在参数上加上@DateTimeFormat
@RequestMapping("test9") @ResponseBody public String test9( @DateTimeFormat(pattern = "yyyy=MM=dd") Date date) { return "#"+date; }
还须要在xml中配置
<mvc:annotation-driven conversion-service="conversionService"/> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="com.arnold.Converter.StringToDateConverter"> <property name="datePattern" value="yyyy=MM=dd"/> </bean> </list> </property> </bean>
<!--将ConversionServiceFactoryBean换为FormattingConversionServiceFactoryBean--> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> </bean>
public static class DataWrapper { private String p; @DateTimeFormat(pattern = "yyyy+MM+dd") private Date date; public DataWrapper() {} public DataWrapper(String p, String d) throws ParseException { this.p = p; SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); date = simpleDateFormat.parse(d); } public String getP() { return p; } public void setP(String p) { this.p = p; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
添加格式化注解
有两个名字,属性重复怎么办?
@RequestMapping("test4") @ResponseBody public String test4(DataWrapper d, DataWrapper d2) { return d.getP()+"#"+d.date + "@" + d2.p + "#" + d2.date; }
能够经过@InitBinder实现精确绑定
@InitBinder("d") public void initd(WebDataBinder binder){ binder.setFieldDefaultPrefix("xd."); } @InitBinder("d2") public void initd2(WebDataBinder binder){ binder.setFieldDefaultPrefix("xd2."); } @RequestMapping("test4") @ResponseBody public String test4(DataWrapper d, @ModelAttribute("d2") DataWrapper d2) { return d.getP()+"#"+d.date + "@" + d2.p + "#" + d2.date; }
注意不但要添加@InitBinder 还要 添加@ModelAttribute。
public static class DataBasket { private DataWrapper a; private DataWrapper b; public DataWrapper getA() { return a; } public void setA(DataWrapper a) { this.a = a; } public DataWrapper getB() { return b; } public void setB(DataWrapper b) { this.b = b; } } @RequestMapping("test5") @ResponseBody public String test5(DataBasket b) { return b.a.getP()+"#"+b.a.date + "@" + b.b.p + "#" + b.b.date; }
和前面的重复属性名请求方式好像差很少。
@RequestMapping("test7") @ResponseBody public String test7(@RequestBody DataBasket b) { return b.a.getP()+"#"+b.a.date + "@" + b.b.p + "#" + b.b.date; }
如何对json中的Date对象作自定义格式转换呢?
首先要配置jackson的converter
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> </bean> </mvc:message-converters> </mvc:annotation-driven>
自定义JsonDeserializer
public class CustomJsonDateDeserializer extends JsonDeserializer<Date> { @Override public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { SimpleDateFormat format = new SimpleDateFormat("yyyy=MM=dd"); String date = jsonParser.getText(); try { return format.parse(date); } catch (ParseException e) { throw new RuntimeException(e); } } }
配置注解 @JsonDeserialize(using = CustomJsonDateDeserializer.class)
public static class DataWrapper { private String p; @DateTimeFormat(pattern = "yyyy=MM=dd") @JsonDeserialize(using = CustomJsonDateDeserializer.class) private Date date; public DataWrapper() {} public DataWrapper(String p, String d) throws ParseException { this.p = p; SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); date = simpleDateFormat.parse(d); } public String getP() { return p; } public void setP(String p) { this.p = p; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
controllerTest
@RequestMapping("test7") @ResponseBody public String test7(@RequestBody DataBasket b) { return b.a.getP()+"#"+b.a.date + "@" + b.b.p + "#" + b.b.date; }
结果:
相似,实现JsonSerializer便可
public class CustomJsonDateSerializer extends JsonSerializer<Date>{ @Override public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy=#MM=#dd"); String format = simpleDateFormat.format(value); gen.writeString(format); } }