本文主要依据《Spring实战》第六章内容进行总结
1、Spring MVC视图解析器
上一节主要介绍了Spring MVC中的控制器,介绍了控制器如何获取用户的请求数据,进行业务逻辑处理之后,将处理结果也就是模型传递给用来渲染的视图,但是控制器返回的只是一个逻辑视图名称,不会直接引用具体的视图实现。而要确定使用哪一个视图实现来渲染模型是视图解析器的任务。将控制器中请求处理的逻辑和视图中渲染实现解耦是Spring MVC的一个重要特性。
Spring MVC定义了一个ViewResolver接口:
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}
当给resolveViewName()方法传入一个视图名和Locale对象时,它会返回一个View实例,View也是一个接口:
public interface View {
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}
View接口的任务就是接受模型以及Servlet的request和response对象,并将输出结果渲染到response中。
可以看到,要将模型数据展示到浏览器中,只需实现ViewResolver和View,将要渲染的内容放到response中,进而展现到用户的浏览器中。实际上,Spring提供了多个内置的实现,能够适应大多数的场景,在这里我们就不一一详细地介绍了,着重介绍一下InternalResourceViewResolver,它主要用来解析JSP视图。
2、创建JSP视图
Spring提供了两种支持JSP视图的方式:
- InternalResourceViewResolver会将视图名解析为JSP文件。另外,如果在JSP页面中使用了JSP标准标签库(JSTL),InternalResourceViewResolver能够将视图名解析为JstlView形式的JSP文件,从而将JSTL本地化和资源bundle变量暴露给JSTL的格式化和信息标签。
- Spring提供了两个JSP标签库,一个用于表单到模型的绑定,另一个提供了通用的工具类特性。
2.1、配置适用于JSP的视图解析器
有一些视图解析器,如ResourceBundleViewResolver会直接将逻辑视图名映射为特定的View接口实现,而InternalResourceViewResolver所采取方式并不那么直接,它遵循一种约定,会在视图名上添加前缀和后缀,进而确定一个Web应用中视图资源的物理路径。
例如,在上一节的例子中,我们要访问的home.jsp,放在/WEB-INF/views目录下:
这样能够防止对它的直接访问,如果我们将所有的JSP文件都放在/WEB-INF/views目录下,并且home页的JSP名为home.jsp,那么我们可以确定物理视图的路径就是逻辑视图名home再加上“/WEB-INF/views”前缀和“.jsp”后缀。
在上一节中,我们使用Java配置的方式配置InternalResourceViewResolver,使其在解析视图时,遵循上述的约定:
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");//配置前缀
resolver.setSuffix(".jsp");//配置后缀
return resolver;
}
我们也可以通过xml的方式来配置InternalResourceViewResolver:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
InternalResourceViewResolver配置好之后,它就会将逻辑视图名称解析为JSP文件,例如:home会被解析为/WEB-INF/views/home.jsp,books/detail会被解析为/WEB-INF/views/books/detail.jsp,在这里,当逻辑视图名中包含斜线时,这个斜线也会带到资源的路径中。
2.1.1、解析JSTL视图
到目前为止,我们对InternalResourceViewResolver的配置都很基础和简单,它最终会将逻辑视图名解析为InternalResourceView实例,这个实例会引用JSP文件。但是,如果这些JSP使用JSTL标签来处理格式化和信息的话,那么我们会希望InternalResourceViewResolver将视图解析为JstlView。要使InternalResourceViewResolver将视图解析为JstlView,只需要设置它的viewClass属性即可:
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
我们也可以通过xml来配置viewClass属性:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
2.2、使用Spring的JSP标签库
Spring提供了两个JSP标签库,一个标签库会用来渲染HTML表单标签,这些标签可以绑定model中的某个属性,另外一个标签包含了一些工具类标签,我们随时可以非常便利地使用它们。
2.2.1、将表单绑定到模型上
Spring的表单绑定JSP标签库主要用来渲染HTML中的表单标签,它会绑定模型中的一个对象,能够根据模型中对象的属性填充值,标签库中还包含了一个为用户展现错误的标签,它会将错误信息渲染到最终的HTML中。
为了使用表单绑定标签,需要在JSP页面中对其进行声明:
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf"%>
在这里,我们将前缀指定为”sf”,实际上,前缀可以指定为任意值,在这里为了简洁方便,我们才指定为”sf”。声明了表单绑定标签库之后,我们就可以使用这些标签了:
JSP标签 | 描述 |
---|---|
<sf:checkbox> | 渲染成一个HTML<input> 标签,其中type属性设置为checkbox |
<sf:checkboxes> | 渲染成多个HTML<input> 标签,其中type属性设置为checkbox |
<sf:errors> | 在一个HTML<span> 中渲染输入域的错误 |
<sf:form> | 渲染成一个HTML<form> 标签,并为其内部标签暴露绑定路径,用于数据绑定 |
<sf:hidden> | 渲染成一个HTML<input> 标签,其中type属性设置为hidden |
<sf:input> | 渲染成一个HTML<input> 标签,其中type属性设置为text |
<sf:lable> | 渲染成一个HTML<label> 标签 |
<sf:option> | 渲染成一个HTML<option> 标签,其selected属性根据所绑定的值进行设置 |
<sf:options> | 按照绑定的集合、数组或Map,渲染成一个HTML<option> 标签的列表 |
<sf:password> | 渲染成一个HTML<input> 标签,其中type属性设置为password |
<sf:radiobutton> | 渲染成一个HTML<input> 标签,其中type属性设置为radio |
<sf:radiobuttons> | 渲染成多个HTML<input> 标签,其中type属性设置为radio |
<sf:select> | 渲染为一个HTML<select> 标签 |
<sf:textarea> | 渲染为一个HTML<textarea> 标签 |
在这里我们就不详细介绍每一个标签的用法了,我们根据上节介绍的学生信息录入功能来介绍几个常用的表单绑定标签,首先,我们需要改写一下学生信息录入的页面,之前的页面由原生的HTML标签组成:
<form action="addStudent" method="post">
ID:<input type="text" name="id"/><br/>
姓名:<input type="text" name="name"/><br/>
性别:<input type="text" name="sex"/><br/>
<input type="submit" value="提交"/>
</form>
现在我们使用上面表格中介绍的表单绑定标签改写上述内容:
<sf:form action="addStudent" method="post" commandName="student">
ID:<sf:input path="id"/><br/>
姓名:<sf:input path="name"/><br/>
性别:<sf:input path="sex"/><br/>
<input type="submit" value="提交">
</sf:form>
我们使用了<sf:form>
标签来渲染一个HTML<form>
标签,它通过commandName属性构建针对某个模型对象的上下文信息,在这里,我们将commandName设置为student,因此,在模型中必须要有一个key为student的对象,否则,表单不能正常渲染,所以我们在Controller中添加如下的处理方法:
@RequestMapping(value="/addStudent",method=RequestMethod.GET)
public String toAddStudent(Model model) {
model.addAttribute(new Student());
return "addStudent";
}
在这个方法中我们没有指定key值,但是,Spring可以通过返回类型推断得到,因为返回的是一个Student对象,所以key为student。
另外,我们将HTML的<input>
标签改写为<sf:input>
,它会渲染为一个HTML的<input>
标签,并且type属性为text。在这里,我们还设置了<sf:input>
的path属性,<input>
标签的value属性值将会设置为模型对象中path属性所对应的值。
为了能够看到表单绑定标签的实际效果,我们在学生信息录入页面录入一些不合法的信息,如下所示:
点击提交,因为录入的信息不合法,所以页面不会跳转到录入成功页面,而是重定向到录入页面,并且表单中会预先填充之前输入的值,我们可以通过生成的HTML元素来确认:
<form id="student" action="addStudent" method="post">
ID:<input id="id" name="id" type="text" value="0"/><br/>
姓名:<input id="name" name="name" type="text" value="aa"/><br/>
性别:<input id="sex" name="sex" type="text" value="1234567890"/><br/>
<input type="submit" value="提交">
</form>
2.2.2、展现错误
在上一节的案例中,我们录入了一些不合法的要素,Spring对这些要素校验不通过之后,会直接重定向到录入页面,但是有两点我们没有介绍:首先,我们没有介绍Spring是如何校验表单的;其次,虽然Spring对表单元素进行了校验,但是校验的结果没有展示在前台页面,我们也不知道哪里录入的有问题。在本节中,我们将详细介绍这两点。
2.2.2.1、校验表单
校验表单要素的方法有很多,最简单的方法就是直接在控制器的处理方法中校验录入元素的合法性,然后将校验结果返回给页面,但是这样处理会使处理方法变得异常复杂。
我们可以使用Spring对Java校验API(Java Validation API,又称为JSR-303)的支持来进行校验,从Spring 3.0开始,在Spring MVC中提供了对Java校验API的支持,我们不需要额外的配置,只要在类路径下包含Java校验API的实现即可,比如Hibernate Validator,在这里,我们需要引入相应的依赖包:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>
一开始我们引入的Hibernage Validator版本为4.3.1.Final,但是启动服务器之后就出现如下异常:
Caused by: java.lang.AbstractMethodError: org.hibernate.validator.engine.ConfigurationImpl.getDefaultParameterNameProvider()
在网上查了资料之后,初步判断应该是Hibernage Validator版本兼容性问题,将版本升至5.1.0.Final之后问题解决。
Java校验API定义了多个注解,这些注解可以放到属性上,从而限制这些属性的值,所有的注解都位于javax.validation.constraints包中,下表列出了这些校验注解:
注解 | 描述 |
---|---|
@AssertFalse | 所注解的元素必须是Boolean类型,并且值为false |
@AssertTrue | 所注解的元素必须是Boolean类型,并且值为true |
@DecimalMax | 所注解的元素必须是数字,并且它的值要小于或等于给定的BigDecimalString值 |
@DecimalMin | 所注解的元素必须是数字,并且它的值要大于或等于给定的BigDecimalString值 |
@Digits | 所注解的元素必须是数字,并且它的值必须有指定的位数 |
@Future | 所注解的元素的值必须是一个将来的日期 |
@Max | 所注解的元素必须是数字,并且它的值要小于或等于给定的值 |
@Min | 所注解的元素必须是数字,并且它的值要大于或等于给定的值 |
@NotNull | 所注解的元素的值必须不能为null |
@Null | 所注解的元素的值必须为null |
@Past | 所注解的元素的值必须是一个一过去的日期 |
@Pattern | 所注解的元素的值必须匹配给定的正则表达式 |
@Size | 所注解的元素的值必须是String、集合或数组,并且它的长度要符合给定的范围 |
有了这些注解,我们可以修改Student类,为它的属性添加一些校验注解:
package model;
import java.util.ArrayList;
import java.util.List;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class Student {
@NotNull
@Min(value=1) //非空,必须是数字,最小值为1
private int id;
@NotNull
@Size(min=5, max=16) //非空,5到16个字符
private String name;
@NotNull
@Size(min=1, max=8) //非空,1到8个字符
private String sex;
……
}
在修改后的Student类中,我们使用@NotNull注解以确保属性的值都不能为null,另外使用@Min注解表示id属性的值最小为1,使用@Size注解限制name和sex的长度,也就是说在信息录入页面,用户必须录入指定长度的name和sex信息。
在Student中添加了校验注解之后,我们需要修改控制器的addStudent()方法来启用校验功能:
@RequestMapping(value="/addStudent",method=RequestMethod.POST)
public String addStudent(@Valid Student student, Errors errors, Model model) {
//校验表单提交的数据,如果校验出现错误,则返回录入页面
if(errors.hasErrors()) {
model.addAttribute(student);
return "addStudent";
}
……
//添加学生信息
}
在上面的代码中,我们首先在表单参数类Student前面添加了@Valid注解,这会告知Spring,需要确保这个对象满足校验限制。如果校验出现错误的话,这些错误可以通过Errors对象进行访问,所以我们将Errors作为参数传入addStudent()方法中,值得注意的是,Errors参数要紧跟在带有@Valid注解的参数后面,@Valid注解所标注的就是要校验的参数。完成了表单的校验之后,接下来我们就看一下如何将校验的结果显示在页面上。
2.2.2.2、展现错误
如果存在校验错误的话,请求中会包含错误的详细信息,这些信息是与模型数据放到一起的,我们需要做的就是到模型中将这些数据抽取出来,并展现给用户。我们可以通过<sf:errors>
标签来完成。例如,我们修改录入学生信息页面:
<sf:form action="addStudent" method="post" commandName="student">
ID:<sf:input path="id"/><sf:errors path="id" /><br/>
姓名:<sf:input path="name"/><sf:errors path="name" /><br/>
性别:<sf:input path="sex"/><sf:errors path="sex" /><br/>
<input type="submit" value="提交">
</sf:form>
可以看到,我们在每一个输入域后面都新增了一个<sf:errors>
标签,它的path属性设置为Student模型对象中对应的属性,也就是说,通过path属性指定Student模型对象中哪个属性的错误。如果属性没有错误的话,那么<sf:errors>
不会渲染任何内容。但如果有校验错误的话,那么它将会在一个HTML<span>
标签中显示错误信息。例如,如果我们在上面的学生信息录入页面录入不合法的信息,<sf:errors>
会渲染相应的格式错误信息:
而生成的HTML中也会加入相应的错误信息:
<form id="student" action="addStudent" method="post">
ID:<input id="id" name="id" type="text" value="0"/><span id="id.errors">最小不能小于1</span><br/>
姓名:<input id="name" name="name" type="text" value="aa"/><span id="name.errors">个数必须在5和16之间</span><br/>
性别:<input id="sex" name="sex" type="text" value="1234567890"/><span id="sex.errors">个数必须在1和8之间</span><br/>
<input type="submit" value="提交">
</form>
在上面这个例子中,错误信息的样式是默认的HTML样式,并没有突出显示,我们可以通过设置<sf:errors>
标签的cssClass属性来为其指定样式,我们修改一下代码:
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<style>
span.error {
color:red;
}
</style>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<h1>请录入学生信息</h1>
<sf:form action="addStudent" method="post" commandName="student">
ID:<sf:input path="id"/><sf:errors path="id" cssClass="error"/><br/>
姓名:<sf:input path="name"/><sf:errors path="name" cssClass="error"/><br/>
性别:<sf:input path="sex"/><sf:errors path="sex" cssClass="error"/><br/>
<input type="submit" value="提交">
</sf:form>
</body>
</html>
这样如果出现格式错误的话,错误信息会标红显示:
上面这种方式是在每个输入域旁边显示错误信息,我们还可以将所有的错误信息在同一个地方显示,要做到这一点,我们可以移除每个输入域上的<sf:errors>
元素,并将其放到表单的顶部:
<sf:form action="addStudent" method="post" commandName="student">
<sf:errors path="*" cssClass="error" element="div"/>
ID:<sf:input path="id"/><br/>
姓名:<sf:input path="name"/><br/>
性别:<sf:input path="sex"/><br/>
<input type="submit" value="提交">
</sf:form>
在这里,我们将path属性设置为”*”,这是一个通配符选择器,会告诉<sf:errors>
展现所有属性的所有错误。另外我们还是用了element属性将错误信息渲染在一个<div>
标签中,我们再修改一下样式信息:
div.error {
color:red;
}
这样,当我们录入非法要素时,页面会在表单头显示错误信息:
如果出现校验错误,我们还想要着重显示需要修正的输入域,我们可以通过为每个输入域设置cssErrorClass属性,另外,我们还可以使用<sf:label>
标签来渲染<label>
元素:
<sf:form action="addStudent" method="post" commandName="student">
<sf:errors path="*" cssClass="error" element="div"/>
<sf:label path="id" cssErrorClass="error">ID:</sf:label><sf:input path="id" cssErrorClass="error"/><br/>
<sf:label path="name" cssErrorClass="error">姓名:</sf:label><sf:input path="name" cssErrorClass="error"/><br/>
<sf:label path="sex" cssErrorClass="error">性别:</sf:label><sf:input path="sex" cssErrorClass="error"/><br/>
<input type="submit" value="提交">
</sf:form>
<sf:label>
标签像其他的表单绑定标签一样,使用path来指定它属于模型对象中哪个属性,如果没有出现校验错误,那么它会渲染为如下的HTML:
<label for="id">ID:</label>
如果出现校验错误,它也会根据cssErrorClass属性设置的样式显示为相应的效果,并将渲染的<label>
标签class属性设置为cssErrorClass属性的值:
<label for="name" class="error">姓名:</label>
我们再为label和input设置样式:
label.error {
color:red;
}
input.error {
background-color: #ffcccc;
}
接下来我们尝试在录入页面录入一些不合法的元素,页面会集中显示错误信息并着重显示需要修正的输入域:
上面的例子中我们已经能够对页面录入的元素进行校验,但是如果错误信息集中显式在表单开头的话,我们很难确认每条错误信息对应的是哪一个输入域,而且错误信息的内容并不友好,例如上图中显示的错误信息,我们很难定位“个数必须在5和16之间”还有“个数必须在1和8之间”分别是指哪一个输入域的格式错误。为了使错误信息更加易读友好,我们需要修改一下Student类中定义的格式校验:
public class Student {
@NotNull
@Min(value=1, message="ID格式错误")
private int id;
@NotNull
@Size(min=5, max=16, message="姓名格式错误")
private String name;
@NotNull
@Size(min=1, max=8, message="性别格式错误")
private String sex;
……
}
我们在每个校验注解中添加了message属性,并为其制定了对应的内容,这样修改之后,如果出现格式错误,message属性中的错误信息将会展现给用户:
上面的错误信息仍然存在一个问题,现在虽然已经友好地提示了用户哪些输入域存在问题,但是并没有指出具体的输入域正确格式是什么,还有就是虽然在Student类中指定了相关输入域的长度限制,但是如果长度限制修改之后,页面的错误提示也需要能够同步更新,要做到以上两点,我们需要重新配置一下message属性:
public class Student {
@NotNull
@Min(value=1, message="{id.min}")
private int id;
@NotNull
@Size(min=5, max=16, message="{name.size}")
private String name;
@NotNull
@Size(min=1, max=8, message="{sex.size}")
private String sex;
……
}
这一次,我们将message属性中值使用大括号括了起来,这样message中的值是属性文件中的某一个属性,该属性包含了实际的信息,接下来我们就需要在根类路径下创建一个名为ValidationMessages.properties的文件,文件内容为:
id.min=ID最小为{value}
name.size=姓名长度要在{min}到{max}之间
sex.size=性别长度要在{min}到{max}之间
ValidationMessages.properties文件中每条信息的key值对应于注解中message属性占位符的值,同时最大和最小长度等信息也没有硬编码在ValidationMessages.properties文件中,在这个用户友好的信息中也有自己的占位符{value}、{min}、{max},它会引用@Min和@Size注解上所设置的value、min和max属性。因此,我们测试录入页面,可以得到我们想要的校验结果:
将这些错误信息抽取到属性文件中还会带来一个好处,那就是我们可以通过创建地域相关的属性文件,为用户展现特定语言和地域的信息,例如,如果用户的浏览器设置为英语,那就应该展示英语的报错信息,我们就需要创建一个名为ValidationMessages_en_US.properties的配置文件。我们可以按需创建任意数量的ValidationMessages.properties文件,使其涵盖我们想支持的所有语言和地域。
2.2.3、Spring通用标签库
除了表单绑定标签库之外,Spring还提供了更为通用的JSP标签库,而要使用Spring通用的标签库,我们必须在页面上对其进行声明:
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
当然,和声明表单绑定标签库一样,这里声明的前缀可以为任意值,我们为了使用方便设置为“s”。
Spring提供了多个通用标签,在这里我们只介绍几个常用的标签,其余的标签在使用时查阅相关手册文档即可。
2.2.3.1、展现国际化信息
目前我们的JSP页面中,很多文本内容都是硬编码在JSP中的,如果Web系统需要根据用户的语言环境显示相应语言的信息,现有的JSP页面很难满足我们的需求,所以我们需要能够在页面上展示国际化的信息。例如,在home.jsp页面中,我们原有的页面如下:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>主页</title>
</head>
<body>
<h1>这是主页</h1>
</body>
</html>
我们只显示了中文的信息,现在,我们在英文的语言环境下想显示英文的主页提示,我们可以借助<s:message>
标签来完成:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title><s:message code="homepage" /></title>
</head>
<body>
<h1><s:message code="thisIsHomepage" /></h1>
</body>
</html>
我们使用<s:message>
标签来替换原有的硬编码文本,这样<s:message>
就会根据key值为<s:message>
标签中code属性的值去信息源中查找文本信息,然后渲染文本,现在我们需要配置一个信息源。
Spring有多个配置信息源的类,它们都实现了MessageSource接口,在这些类中,最常用的是ResourceBundleMessageSource。它会从一个属性文件中加载信息,这个属性文件的名称是根据基础名称衍生而来的:
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("message");
return messageSource;
}
在这里我们使用Java配置的方式声明了一个信息源,在这个声明中,核心在于设置basename属性,可以将其设置为任意喜欢的值,在这里我们设置的是message,ResourceBundleMessageSource会试图在根路径的属性文件中解析信息,这些属性文件的名称是根据这个基础名称衍生得到的,例如,对于中文的环境,我们有message_zh_CN.properties,英文的环境我们有message_en_US.properties等等。
英文环境的message_en_US.properties:
homepage=homepage
thisIsHomepage=This is Homepage
中文环境的message_zh_CN.properties:
homepage=主页
thisIsHomepage=这是主页
接下来,我们可以访问主页,如果我们的浏览器语言环境为中文,则显示中文信息:
如果浏览器语言环境为英文,则显示英文的主页信息:
另一个信息源的类是ReloadableResourceBundleMessageSource,它的工作方式和ResourceBundleMessageSource非常相似,但是它能够重新加载信息属性,而不必重新编译或重启应用:
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("file:f:/config/message");
messageSource.setCacheSeconds(10);
return messageSource;
}
在上面的配置中,我们basename设置为外部路径file:f:/config/message,而不是ResourceBundleMessageSource在类路径下查找,实际上ReloadableResourceBundleMessageSource的basename属性可以设置为在类路径下(以“classpath:”作为前缀)、文件系统中(以“file:”作为前缀)或Web应用的根路径下(没有前缀)查找属性。ResourceBundleMessageSource只能在类路径下查找属性。
2.2.3.2、创建URL
<s:url>
标签可以创建URL,然后将其赋值给一个变量或者渲染到响应中。<s:url>
会接受一个相对于Servlet上下文的URL,并在渲染的时候,预先添加上Servlet上下文路径。例如,下面这个例子就是<s:url>
标签的基本用法:
<a href="<s:url value="/addStudent" />">添加学生</a>
如果Servlet上下文名为spring_mvc1,那么在响应中将会渲染如下的HTML:
<a href="/spring_mvc1/addStudent">添加学生</a>
这样,我们在创建URL的时候,就不用再担心Servlet上下文路径是什么了,<s:url>
将会负责这件事。
另外,我们还可以使用<s:url>
创建URL,并将其赋值给一个变量供页面在稍后使用:
<s:url value="/addStudent" var="add"/>
<a href="${add }">添加学生</a>
默认情况下,URL是在页面作用域内创建的,但是通过设置scope属性,我们可以让<s:url>
在应用作用域内、会话作用域内或请求作用域内创建URL:
<s:url value="/addStudent" var="add" scope="request"/>
如果希望URL上添加参数的话,我们可以使用<s:param>
标签,例如我们想为上面的URL添加两个参数:ID和姓名,我们可以在<s:url>
标签上添加两个内嵌的<s:param>
标签:
<s:url value="/addStudent" var="add" >
<s:param name="id" value="1" />
<s:param name="name" value="Tom" />
</s:url>
<a href="${add }">添加学生</a>
这样的话,渲染得到的HTML内容即为:
<a href="/spring_mvc1/addStudent?id=1&name=Tom">添加学生</a>
如果我们创建带有路径参数的URL,我们也可以使用<s:param>
标签:
<s:url value="/addStudent/{id}" var="add" >
<s:param name="id" value="1" />
<s:param name="name" value="Tom" />
</s:url>
<a href="${add }">添加学生</a>
当value属性中的占位符匹配<s:param>
中所指定的参数时,这个参数会插入到占位符的位置中,如果<s:param>
参数无法匹配value中的任何占位符,那么这个参数将会作为查询参数,所以,上面的例子最终渲染得到的HTML为:
<a href="/spring_mvc1/addStudent/1?name=Tom">添加学生</a>
如果我们希望渲染得到的URL内容展现在Web页面上,而不是作为超链接,我们需要将<s:url>
进行HTML转义,即将htmlEscape属性设置为true:
<s:url value="/addStudent" var="add" htmlEscape="true">
<s:param name="id" value="1" />
<s:param name="name" value="Tom" />
</s:url>
这时页面显示内容为:/spring_mvc1/addStudent?id=1&name=Tom,而渲染得到的HTML内容为:/spring_mvc1/addStudent?id=1& ;name=Tom,可以看到,它将&符号进行了转义。
如果希望在JavaScript代码中使用URL的话,应该将javaScriptEscape属性设置为true:
<s:url value="/addStudent" var="add" javaScriptEscape="true">
<s:param name="id" value="1" />
<s:param name="name" value="Tom" />
</s:url>
这样在下面的这段JavaScript:
<script type="text/javascript">
var url = "${add }";
</script>
就可以转换为如下的内容返回给响应:
<script type="text/javascript">
var url = "\/spring_mvc1\/addStudent?id=1&name=Tom";
</script>
2.2.3.3、转义内容
<s:escapeBody>
标签是一个通用的转义标签,它会渲染标签体中内嵌的内容,并且在必要时进行转义,例如,我们想在页面上显示一段HTML代码段,如果直接写“<“、”>“,浏览器将不能正确显示,需要将其转换为”< ;“、”> ;“,这项工作很繁琐,并且代码难以阅读,所以我们可以使用<s:escapeBody>
来完成这项任务:
<s:escapeBody htmlEscape="true">
<h1>Hello</h1>
</s:escapeBody>
这样,在渲染得到的HTML中将会得到如下内容:
<h1>Hello</h1>
通过javaScriptEscape属性,<s:escapeBody>
标签还支持JavaScript转义:
<s:escapeBody javaScriptEscape="true">
<h1>Hello</h1>
</s:escapeBody>
<s:escapeBody>
标签和<s:url>
标签不同的地方在于,它只会渲染内容,并不能将内容设置为变量。