1.使用 InternalResourceViewResoIver
JSP 是最常见的视图技术,其配置如下:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>
若程序返回名为user/createSuccess的逻辑视图名,则 InternalResourceViewResolver 负责对此进行解析,将得到如下图所示的解析结果。
public String handle61(@ModelAttribute("user") User user) { user.setUserId("1000"); return "/user/createSuccess"; }
InternalResourceViewResolver 默认使用 InternalResourceView 作为视图实现类。如果 JSP 文件使用了 JSTL 的国际化功能,确切地说,当 JSP 页面使用 JSTL 的 <fmt:message/> 标签时,用户需要使用 JstlView 替换默认的视图实现类,如下:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:viewClass="org.springframework.web.servlet.view.JstlView" p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>
下面通过一个例子演示使用 JSTL 的 <fmt:message/> 标签让 JSP 页面实现本地化输出。首先在 UserController 中添加一个方法。
@RequestMapping(value = "/showUserList") public String showUserList(ModelMap mm) { Calendar calendar = new GregorianCalendar(); List<User> userList = new ArrayList<User>(); User user1 = new User(); user1.setUserName("tom"); user1.setRealName("汤姆"); calendar.set(1980, 1, 1); user1.setBirthday(calendar.getTime()); User user2 = new User(); user2.setUserName("john"); user2.setRealName("约翰"); user2.setBirthday(calendar.getTime()); userList.add(user1); userList.add(user2); mm.addAttribute("userList", userList); return "user/userList"; }
userList.jsp 的代码如下所示。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> <html> <head> <title><fmt:message key="website.title"/></title> </head> <body> <fmt:message key="user.userList.title"/> <table> <c:forEach items="${userList}" var="user"> <tr> <td> <a href="<c:url value="/user/showUser/${user.userName}.html"/>"> ${user.userName} </a> </td> <td> ${user.realName} </td> <td> <fmt:formatDate value="${topic.createDate}" pattern="yyyy-MM-dd" /> </td> </tr> </c:forEach> <table> </body> </html>
userList.jsp 所使用的国际化资源在 content 资源文件中定义,更改 smart-servlet.xml 中 ResourceBundleMessageSource 的配置,添加此国际化资源。
<!--国际化资源 --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>i18n/messages</value> <value>i18n/content</value> </list> </property> </bean>
这样,userList.jsp 就可以根据客户端的不同显示相应的本地化页面。除了可以使用 JSTL 的标签外,Spring 也提供了一个轻量级的标签库,可以在 JSP 文件中使用这些标签。
2.使用 Spring 表单标签
通过 Spring 表单标签,可以很容易地将模型数据中的表单/命令对象绑定到 HTML 表单元素中。在前面的内容中,我们已经使用了一些 Spring 表单标签,本节将对 Spring 表单标签进行全面的介绍,首先从 <form:form> 标签开始。
和使用任何 JSP 扩展标签一样,在使用 Spring 表单标签之前,用户必须在 JSP 页面中添加一行引用 Spring 表单标签的声明。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> ①引用表单标签的声明 <html> ②声明后,在页面中就可以使用Spring表单标签了 </html>
下面是一个使用 <form:form> 表单标签的实例,它将最终生成一个 HTML 的 form 表单。
<form:form modelAttribute="user"> 用户名:<form:input path="userName" /> 密码:<form:password path="password" /> <input type="submit" name="提交"/></td> </form:form>
一般情况下,通过 GET 请求获取表单页面,通过 POST 请求提交表单页面,因此,获取表单页面和提交表单页面的 URL 地址是相同的。只要满足这条最佳实践的契约,<form:form> 标签就无须通过 action 属性指定表单提交的目标 URL。
可以通过 modelAttribute 指定绑定的模型属性。如果 modelAttribute 属性不指定,那么默认从模型中尝试获取名为 command 的表单对象。如果不存在此表单对象,则将发生错误。通过 action 指定处理表单提交的 URL 地址。此外,<form:form> 标签还拥有多个可设置的属性,这些属性大都是 HTML 表单标签属性的镜像,如 id、onclick、 ondblclick、tabindex 等。需要注意的是,这些属性都是小写的,而对应 HTML 标签的属性名则没有这个限制。
Spring 提供了十多个表单组件标签,如<form:input/>、<form:select/>等,用以绑定表单对象的属性值。这些标签大都拥有以下属性。
1)path:用属性路径表示的表单对象属性,如 userName、dept.deptName、dept.address、telephone、userName 等。
2)htmlEscape:绑定的表单属性值是否要对 HTML 特殊字符进行转换,默认值为 true。
3)cssClass:表单组件对应的 CSS 样式类名。
4)cssErrorClass:当表单组件的数据存在相应的错误时(提交表单后由服务器端产生)采用的 CSS 样式类。
5)cssStyIe:表单组件对应的 CSS 样式串。
此外,表单组件标签也拥有 HTML 镜像标签的各种属性,如 id、onclick、ondblclick、tabindex 等·。通过下表对 Spring 表单标签进行说明。
3.关于复选框、单选框及下拉框和表单对象属性的映射问题
对于以下复选框标签:
<form:checkboxes path="preferences.interests" items="${interests}"
其生成的对应 HTML 如下:
<input id="favorites1" name="favorites" type="checkbox" value="1" checked="checked"/> <input id="favorites2" name="favorites" type="checkbox" value="2"/> <input id="favorites3" name="favorites" type="checkbox" value="3" checked="checked"/> <input id="favorites4" name="favorites" type="checkbox" value="4"/> <input type="hidden" value="1" name="_favorites"/>
读者可能已经注意到复选框组件的后面附加了一个 hidden 组件,如粗体部分所示。这是因为当 HTML 页面中的所有复选框都没有勾选时,表单提交所对应的 HTTP 请求报文不会包含该复选框的参数名,这给 Spring 的表单数据绑定机制带来了麻烦,因为无法触发 setFavorites() 方法的调用(如果这个表单对象已经缓存在 Session 中,且该属性已经有值,那么这个属性值将不会被设置为空)。
解决方法就是在每个复选框后添加一个隐藏组件,并且在对应的复选框名字前添加一个下画线作为隐藏组件的名字。这样一来,相当于告诉 Spring MVC:在这个表单中存在这样一个复选框,Spring MVC 可以据此保证服务器端的表单对象和页面中的表单组件数据的一致性。
复选框、单选框及下拉框的组件标签都拥有类似的功能。如果手工编写 HTML 代码,在碰到单选框、复选框及下拉框时,也应该采用类似的方式,以保证 Spring MVC 数据绑定机制正常工作。当然,如果表单对象没有缓存在 Session 中,而是每次提交都重新创建,则不存在这个问题,也就无须添加一个带下画线的隐藏组件。