@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); } }