鉴于ajax对于前端的重要性,我们经常需要对网页的小部分内容进行刷新处理,此时返回jsp视图已经并不合适,json视图的重要性被凸显出来,但同时网页之前的重定向处理可以一定程度地控制用户网站操作的流程,所以我们并不希望直接砍掉jsp视图处理器,以及我们不希望通过复制代码的方式或是太多判断选择分支在代码中泛滥,spring在3.1中提供的多视图同时处理可以解决以上问题。
请求某一种视图,一个可以通过Header中的Accept进行设置,但是在网络请求中我们并没有太多地关注header并修改,反而是地址的使用和修改更频繁,于是有了使用extension进行区分请求视图的方法。
<bean id="contentNegotiatingResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="ignoreAcceptHeader" value="true" />
<property name="favorParameter" value="false" />
<property name="contentNegotiationManager">
<bean class="org.springframework.web.accept.ContentNegotiationManager">
<constructor-arg>
<bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
<constructor-arg>
<map>
<entry key="html" value="text/html"/>
<entry key="pdf" value="application/pdf"/>
<entry key="xsl" value="application/vnd.ms-excel"/>
<entry key="xml" value="application/xml"/>
<entry key="json" value="application/json"/>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
</list>
</property>
</bean>
</constructor-arg>
</bean>
<bean class="com.xuyuan.spring3.recipes.mvc.web.views.ExcelReservationSummary"/>
<bean class="com.xuyuan.spring3.recipes.mvc.web.views.PdfReservationSummary"/>
</list>
</property>
</bean>
<bean id="internalResourceResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> -->
<property name="prefix" value="/springmvc/" />
<property name="suffix" value=".jsp" />
<property name="order" value="5" />
</bean>
以上部分我们自定义了exl和pdf的输出视图,但是这个视图是针对某些特定class对象的,无法写入其它的复杂对象,当然我们可以控制反转,定义流程、流出接口,然后有意向写入excel/pdf视图的对象实现该接口即可。
@RequestMapping("/members/list")
public String getRestMembersList(Model model) {
Member member = new Member();
member.setName("John Doe members");
member.setPhone("1-800-800-800");
member.setEmail("[email protected]");
Member member2 = new Member();
member.setName("Jenry Doe members");
member.setPhone("1-800-823-856");
member.setEmail("[email protected]");
List<Member> members = new ArrayList<Member>();
members.add(member2);
members.add(member);
model.addAttribute("member2", member2);
model.addAttribute("member1", member);
model.addAttribute("member", members);
return "memberlist";
}
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
结论:此处不必写注解@ResponseBody,同时我们也一般不会在网络请求处理方法中直接完成一个ResponseBody,如果使用ModelAndView返回,返回值不方便被转化成一个json或xml,ModelMap的实例是由bboss mvc框架自动创建并作为控制器方法参数传入,用户无需自己创建。ModelAndView需用户手动创建.但是网上博客的以下说法2-3条并不准确:
1.使用 String 作为请求处理方法的返回值类型是比较通用的方法,这样返回的逻辑视图名不会和请求 URL 绑定,具有很大的灵活性,而模型数据又可以通过 ModelMap 控制。
2.使用void,map,Model 时,返回对应的逻辑视图名称真实url为:prefix前缀+视图名称 +suffix后缀组成。
3.使用String,ModelAndView返回视图名称可以不受请求的url绑定,ModelAndView可以设置返回的视图名称。
String是三者中比较合适的返回值,会具体跟随请求的内容及视图处理器的顺序来解析要返回的具体内容,但是ModelAndVew不会
@XmlRootElement
public class Member {
@NotNull
@Size(min=2)
private Integer id;
/**
* @uml.property name="name"
*/
@NotNull
@Size(min=2)
private String name;
/**
* @uml.property name="phone"
*/
@NotNull
@Size(min = 9, max = 14)
private String phone;
/**
* @uml.property name="email"
*/
@Pattern(regexp=".+@.+\\.[a-z]+")
private String email;
}
该函数中,我们虽然放置了List到Model中,但是xml视图处理器无法处理,xml视图处理器只会去取key值member的value,然后默认value为一个Member对象,但是我们放置的对象是个list,故报错找不到name值
org.springframework.beans.NotReadablePropertyException: Invalid property 'name' of bean class [java.util.ArrayList]: Bean property 'name' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:709)
如果非得在xml中显示list等集合对象,要封装一个新类,看以下代码可以看出,该list要有一个name,猜测上方的name并非Member类中的name
@XmlRootElement
public class ReservationList {
/**
* @uml.property name="name"
*/
private String name;
/**
* @uml.property name="list"
*/
private List<Reservation> list;
public ReservationList(){}
public ReservationList(String name, List<Reservation> list) {
this.name = name;
this.list = list;
}
@XmlElements({
@XmlElement(name = "reservations", type = Reservation.class),
})
public List<Reservation> getList() {
return list;
}
public void setList(List<Reservation> list) {
this.list = list;
}
/**
* @return
* @uml.property name="name"
*/
public String getName() {
return name;
}
/**
* @param name
* @uml.property name="name"
*/
public void setName(String name) {
this.name = name;
}
}
Member对象虽然被网络传输,但是该对象没有实现Serializable
网络请求映射注解处没有使用@Responsebody,根据调试可知,在处理返回值处,该处注解会让框架设置request的handled为真,后面不会继续寻找视图处理器进行视图处理。
未完等填坑。