《Spring实战》读书笔记-第6章 渲染Web视图(1)

| XsltViewResolver | 将视图解析为XSLT转换后的结果 |

Spring 4和Spring 3.2支持表6的所有视图解析器。Spring 3.1支持除Tiles 3 TilesViewResolver之外的所有视图解析器。

6.2 创建JSP视图


Spring提供了两种支持JSP视图的方式:

  • InternalResourceViewResolver会将视图名解析为JSP文件。另外,如果在你的JSP页面中使用了JSP标准标签库(JavaServer Pages Standard Tag Library, JSTL)的话,InternalResourceViewResolver能够将视图名解析为JstlView形式的JSP文件,从而将JSTL本地化和资源bundle变量暴露给JSTL的格式化(formatting)和信息(message) 标签。

  • Spring提供了两个JSP标签库,一个用于表单到模型的绑定,另一个提供了通用的工具类特性。

不管使用JSTL,还是准备使用Spring的JSP标签库,配置解析JSP的视图解析器都是非常重要的。尽管Spring还有其他的几个视图解析器都能将视图名映射为JSP文件,但就这项任务来讲,InternalResourceViewResolver是最简单和最常用的视图解析器。

配置适用于JSP的视图解析器

InternalResourceViewResolver遵循一种约定,会在视图名上添加前缀和后缀,进而确定一个Web应用中视图资源的物理路径。

通用的实践是将JSP文件放到Web应用的WEB-INF目录下,防止对它的直接访问。假设逻辑视图名为home,那么可以确定物理视图的路径就是逻辑视图名home再加上“/WEB-INF/views/”前缀和“.jsp”后缀。

img

InternalResourceViewResolver解析视图时,会在视图名上添加前缀和后缀

当使用@Bean注解的时候,我们可以按照如下的方法配置InternalResourceViewResolver,使其在解析视图时,遵循上述的约定。

@Bean

public ViewResolver viewResolver(){ // 配置jsp视图解析器

InternalResourceViewResolver resolver = new InternalResourceViewResolver();

resolver.setPrefix(“/WEB-INF/views/”);

resolver.setSuffix(“.jsp”);

return resolver;

}

作为替代方案,如果更喜欢使用基于XML的Spring配置,那么可以按照如下的方式配置InternalResourceViewResolver

InternalResourceViewResolver配置就绪之后,它就会将逻辑视图名解析为JSP文件,如下所示:

  • home将会解析为“/WEB-INF/views/home.jsp”

  • productList将会解析为“/WEB-INF/views/productList.jsp”

  • books/detail将会解析为“/WEB-INF/views/books/detail.jsp”

重点看一下最后一个样例。当逻辑视图名中包含斜线时,这个斜线也会带到资源的路径名中。因此,它会对应到prefix属性所引用目录的子目录下的JSP文件。这样的话,我们就可以很方便地将视图模板组织为层级目录,而不是将它们都放到同一个目录之中。

解析JSTL视图

如果JSP使用JSTL标签来处理格式化和信息的话,那么我们会希望InternalResourceViewResolver将视图解析为JstlView。

JSTL的格式化标签需要一个Locale对象,以便于恰当地格式化地域相关的值,如日期和货币。信息标签可以借助Spring的信息资源和Locale,从而选择适当的信息渲染到HTML之中。通过解析JstlView,JSTL能够获得Locale对象以及Spring中配置的信息资源。

如果想让InternalResourceViewResolver将视图解析为JstlView,而不是InternalResourceView的话,那么我们只需设置它的viewClass属性即可:

@Bean

public ViewResolver viewResolver(){ // 配置jsp视图解析器

InternalResourceViewResolver resolver = new InternalResourceViewResolver();

resolver.setPrefix(“/WEB-INF/views/”);

resolver.setSuffix(“.jsp”);

resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);

return resolver;

}

同样,我们也可以使用XML完成这一个任务:

不管使用Java配置还是使用XML,都能确保JSTL的格式化和信息标签能够获得Locale对象以及Spring中配置的信息资源。

使用Spring的JSP库

Spring提供了两个JSP标签库,用来帮助定义Spring MVC Web的视图。其中一个标签库会用来渲染HTML表单便签,这些标签可以绑定model中的某个属性。另外一个标签库包含了一些工具类标签,我们随时都可以非常便利地使用它们。

我们将会看到如何将Spittr应用的注册表单绑定到模型上,这样表单就可以预先填充值,并且在表单提交失败后,能够展现校验错误。

将表单绑定到模型上

Spring的表单绑定JSP标签库包含了14个标签,它们中的大多数都用来渲染HTML中的表单标签。但是,它们与原生HTML标签的区别在于它们会绑定模型中的一个对象,能够根据模型中对象的属性填充值。标签库中还包含了一个为用户展示错误的标签,它会将错误信息渲染到最终的HTML之中。

为了使用表单绑定库,需要在JSP页面中对其进行声明:

<%@ taglib prefix=“sf” uri=“http://www.springframework.org/tags/form” %>

需要注意,我们将前缀指定为“sf”,但通常也可能使用“form”前缀,可以自定义前缀。

在声明完表单绑定标签库之后,你就可以使用14个相关的便签了。如下表

| JSP标签 | 描述 |

| — | — |

| <sf:checkbox> | 渲染成一个HTML 标签,其中type属性设置为checkbox |

| <sf:checkboxes> | 渲染成多个HTML 标签,其中type属性设置为checkbox |

| <sf:errors> | 在一个HTML 中渲染输入域的错误 |

| <sf:form> | 渲染成一个HTML 标签,并为其内部标签暴露绑定路径,用于数据绑定 |

| <sf:hidden> | 渲染成一个HTML 标签,其中type属性设置为hidden |

| <sf:input> | 渲染成一个HTML 标签,其中type属性设置为text |

| <sf:label> | 渲染成一个HTML 标签 |

| <sf:option> | 渲染成一个HTML 标签,其中selected属性根据所绑定的值进行设置 |

| <sf:options> | 按照绑定的集合、数组或Map,渲染成一个HTML 标签的列表 |

| <sf:password> | 渲染成一个标签,其中type属性设置为password |

| <sf:radiobutton> | 渲染成一个标签,其中type属性设置为radio |

| <sf:select> | 渲染为一个HTML 标签 |

| <sf:textarea> | 渲染为一个HTML 标签 |

我们在Spittr的样例中,在注册JSP中可以使用<sf:form><sf:input><sf:password>WW

<sf:form method=“POST” commandName=“spitter” >

First Name:<sf:input path=“firstName”/>

Last Name:<sf:input path=“lastName” />

Email:<sf:input type=“email” path=“email” />

Username: <sf:input path=“username”/>

Password: <sf:password path=“password”/>

</sf:form>

<sf:form>会渲染一个HTML <form>标签,但它也会通过commandName属性构建针对某个模型对象的上下文信息。在其他的表单绑定标签中,会引用这个模型对象的属性。

在之前的代码中,我们将commandName属性设置为spitter。因此,在模型中必须要有一个key为spitter的对象,否则的话,表单不能正常渲染(会出现JSP错误)。这意味着我们需要修改一下SpitterController,以确保模型中存在以spitter为key的Spitter对象:

@RequestMapping(value=“/register”, method=GET)

public String showRegistrationForm(Model model) {

model.addAttribute(new Spitter());

return “registerForm”;

}

修改后,模型中的key根据对象类型推断得出spitter就是新增的Spitter实例。

回到这个表单中,前四个输入域将HTML<input>标签改成了<sf:input>。这个标签会渲染成一个HTML <input>标签,并且type属性将会设置为text。我们在这里设置了path属性,<input>标签的value属性值将会设置为模型对象中path属性所对应的值。

对于password输入域,我们使用<sf:password>来代替<sf:input><sf:password><sf:input>类似,但是它所渲染的HTML <input>标签中,会将type属性为password,这样当输入的时候,它的值不会直接明文显示。

值得注意的是,从Spring 3.1开始,<sf:input>标签能够允许我们指定type属性,这样的话,除了其他可选的类型外,还能指定HTML5特定类型的文本域,如date、range和email。

Email: <sf:input path=“email” type=“email” />

为了指导用户矫正错误,我们需要使用<sf:errors>

如果存在校验错误的话,请求中会包含错误的详细信息,这些信息是与模型数据放到一起的。我们所需要做的就是到模型中将这些数据抽取出来,并展现给用户。

<sf:form method=“POST” commandName=“spitter”>

First Name: <sf:input path=“firstName” />

<sf:errors path=“firstName”/>

</sf:form>

尽管值展示了将<sf:errors>用到First Name输入域的场景,但是它可以按照同样简单的方式用到注册表单的其他输入域中。在这里,它的path属性设置成了firstName,也就是指定了要显示Spitter模型对象中哪个属性的错误。如果firstName属性没有错误的话,那么<sf:errors>不会渲染任何内容。但如果有校验错误的话,那么将会在HTML<span>标签中显示错误信息。

现在,我们已经可以为用户展现错误信息,这样他们就能修正这些错误了。我们还可以修改错误的样式,使其更加突出显示。为了做到这一点,可以设置cssClass属性:

<sf:form method=“POST” commandName=“spitter”>

First Name: <sf:input path=“firstName” />

<sf:errors path=“firstName” cssClass=“error”/>

</sf:form>

定义这个css样式

span.error {

color: red;

}

展示显示结果

img

在表单输入域的旁边展现校验错误信息

除了这种方式,还有另一种处理校验错误方式就是将所有的错误信息在同一个地方进行显示。为了做到这一点,我们可以移除每个输入域上的<sf:errors>元素,并将其放到表单的顶部

<sf:form method=“POST” commandName=“spitter”>

<sf:errors path=“*” element=“div” cssClass=“error”/>

</sf:form>

跟之前相比,值得注意的不同之处在于它的path被设置成了“*”。这是一个通配符选择器,会告诉<sf:errors>展现所有属性的所有错误。

同样需要注意的是,我们将element属性设置成了div。默认情况下,错误都会渲染在HTML 标签中,如果只显示一个错误的话,这是不错的选择。但是,如果要渲染所有输入域的错误的话,很可能要展现不止一个错误,这时候使用<span>标签(行内元素)就不合适了。像<div>这样的块级元素会更为合适。因此,我们可以将element属性设置成了div。

像之前一样,cssClass属性被设置errors,这样我们就能为<div>设置样式了。

div.errors {

background-color: #ffcccc;

border: 2px solid red;

}

现在,我们在表单的上方显示所有的错误,这样页面布局可能会更加容易一些。但是,我们还没有着重显示需要修正的输入域。通过为每个输入域设置cssErrorClass属性,这个问题很容易解决。我们也可以将每个label都替换为<sf: label>,并设置它的cssErrorClass属性。如下就是做完必要修改后的FirstName输入域:

<sf:form method=“POST” commandName=“spitter”>

<sf:label path=“firstName” cssErrorClass=“error”>First Name</sf:label>:

<sf:input path=“firstName” cssErrorClass=“error” />

</sf:form>

<sf:label>标签像其他的表单绑定标签一样,使用path来指定它属于模型对象中的哪个属性。在本例中,我们将其设置为firstName,因此它会绑定Spitter对象的firstName属性。假设没有校验错误的话,它将会渲染为如下的HTML <label>元素:

就其自身来说,设置<sf:label>的path属性并没有完成太多的功能,但是,我们还同时设置了cssErrorClass属性。如果它所绑定的属性有任何错误的话,在渲染得到的<label>元素中,class属性将会被设置为 error,如下所示:

与之类似,<sf:input>标签的cssErrorClass属性被设置为error,如果有任何校验错误,class属性将会被设置为error。下面设置css

label.error {

color: red;

}

input.error {

background-color: #ffcccc;

}

为了让这些错误信息更加易读,我们重新改造Spitter类

@NotNull

@Size(min=5, max=16,message = “{username.size}”)

private String username;

@NotNull

@Size(min=5, max=25,message = “{password.size}”)

private String password;

@NotNull

@Size(min=2, max=30,message = “{firstName.size}”)

private String firstName;

@NotNull

@Size(min=2, max=30,message = “{lastName.size}”)

private String lastName;

@NotNull

@Email(message = “{email.valid}”)

private String email;

对于上面每个域,我们都将其@Size注解的messgae设置为一个字符串,这个字符串是用大括号括起来的。如果没有大括号的话,message中的值将会作为展现给用户的错误信息。但是使用了大括号之后,我们使用的就是属性文件中的某一属性,该属性包含了实际的信息。

接下来需要做的就是创建一个名为ValidationMessage.properties的文件,并将其放在根类路径下:

firstName.size=First name must be between {min} and {max} characters long.

lastName.size=Last name must be between {min} and {max} characters long.

username.size=Username must be between {min} and {max} characters long.

password.size=Password must be between {min} and {max} characters long.

email.valid=The email address must be valid.

ValidationMessage.properties文件中每天信息的key值对应于注解中message属性占位符的值。同时,最小和最大长度以占位符的方式({min}和{max})保存文件中,它们会引用@Size注解上所设置的min和max属性。

当用户提交的注册表单校验失败的话,他们在浏览器中应该可以看到如下界面。

img

显示校验错误,其中这些对用户友好的信息是从属性文件中获取到的

我们可以按需创建任意数量的ValidationMessage.properties文件,使其涵盖我们想支持的所有语言和地域。

Spring通用的标签库

除了表单绑定标签库之外,Spring还提供了更为通用的JSP标签库。

要使用Spring通用的标签库,我们必须要在页面上对其进行声明:

<%@ taglib uri=“http://www.springframework.org/tags” prefix=“s” %>

标签库声明之后,我们就可以使用下表的十个JSP标签了。

| JSP标签 | 描述 |

| — | — |

| <s:bind> | 将绑定属性的状态导出到一个名为status的页面作用域属性中,与<s:path>组合使用获取绑定属性的值 |

| <s:escapeBody> | 将标签体中的内容进行HTML和/或JavaScript转义 |

| <s:hasBindErrors> | 根据指定模型对象(在请求属性中)是否有绑定错误,有条件地渲染内容 |

| <s:htmlEscape> | 为当前页面设置默认的HTML转义值 |

| <s:message> | 根据给定的编码获取信息,然后要么进行渲染(默认行为),要么将其设置为页面作用域、请求作用域、会话作用域应用作用域的变量(通过使用var和scope属性实现) |

| <s:nestedPath> | 设置嵌入式的path,用于<s:bind>之中 |

| <s:theme> | 根据给定的编码获取主题信息,然后要么进行渲染(默认行为),要么将其设置为页面作用域、请求作用域、会话作用域应用作用域的变量(通过使用var和scope属性实现) |

| <s:transform> | 使用命名对象的属性编辑器转换命令对象中不包含的属性 |

| <s:url> | 创建相对于上下文的URL,支持URI模板变量以及HTML/XML/JavaScript转义。可以渲染URL(默认行为),要么将其设置为页面作用域、请求作用域、会话作用域应用作用域的变量(通过使用var和scope属性实现) |

| <s:eval> | 计算符合Spring表达式语言(Spring Expression Language SpEL)语法的某个表达式的值,然后要么进行渲染(默认行为),要么将其设置为页面作用域、请求作用域、会话作用域应用作用域的变量(通过使用var和scope属性实现) |

展现国际化信息

如果要修改JSP模板中的文本,就不那么容易,而且,没有办法根据用户的语言设置国际化这些文本。

例如:

Welcome to Spitter!

如果想把其中的文本做成国际化的版本,对于渲染文本来说,是很好的方案,文本能够位于一个或多个属性文件中。借助<s:message>,我们可以将硬编码的欢迎信息替换为如下的形式:

按照这里的方式,<s:message>将会根据key为spitter.welcome的信息源来渲染文本。

Spring有多个信息源的类,它们都实现了MessageSource接口。在这些类中,更为常见和有用的是ResourceBundleMessageSource。它会从一个属性文件中加载信息,这个属性文件的名称是根据基础名称(base name)衍生而来的。如下的@Bean方法配置了ResourceBundleMessageSource:

@Bean

public MessageSource messageSource(){

ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();

messageSource.setBasename(“message”);

messageSource.setDefaultEncoding(“UTF-8”);

return messageSource;

}

在这个bean声明中,核心在于设置basename属性。你可以将其设置为任意你喜欢的值,在这里,我将其设置为message。将其设置为message后,ResourceBundleMessageSource就会试图在根路径的属性文件中解析信息,这些属性文件的名称是根据这个基础名称衍生得到的。

另外的可选方案是使用ReloadableResourceBundleMessageSource,它的工作方式与ResourceBundleMessageSource非常类似,但是它能够重新加载信息属性,而不必重新编译或重启应用。如下是配置ReloadableResourceBundleMessageSource的样例:

@Bean

public MessageSource messageSource(){

ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();

messageSource.setBasename(“file:///etc/spittr/messages”);

messageSource.setCacheSeconds(10);

return messageSource;

}

这里的关键区别在于basename属性设置为在应用的外部查找。basename属性可以设置为类路径下(以“classpath:”作为前缀)、文件系统中(以“file:”作为前缀)或Web应用的根路径下(没有前缀)查找属性。

现在,我们来创建这些属性文件。首先创建默认的属性文件,名为message.properties。它要们位于根类路径下(如果使用ResourceBundleMessageSource的话),要么位于basename属性指定的路径下(如果使用ReloadableResourceBundleMessageSource的话)。对spittr.welcome信息来讲,它需要如下的条目:

spittr.welcome=Welcome to Spittr!

我们已经具备了对信息进行国际化的重要组成部分。例如,如果想要为语言设置为西班牙语的用户展示西班牙语的欢迎信息,那么需要创建另外一个名为message_es.properties的属性文件,并包含如下的条目:

spittr.welcome=Bienvenidos a Spittr!

创建URL

<s:url>的主要任务就是创建URL,然后将其赋值给一个变量或者渲染到响应中。它是JSTL中<c:url>标签的替代者,但是它具备几项特殊的技巧。

<s:url>会接受一个相对Servlet上下文的URL,并在渲染的时候,预先添加上Servlet上下文路径。例如,考虑如下<s:url>的基本用法:

<a href=“<s:url href=”/spitter/register" />">Register

如果应用的Servlet上下文名为spittr,那么在响应中将会渲染如下的HTML:

Register

这样,我们在创建URL的时候,就不必再担心Servlet上下文路径是什么了,<s:url>将会负责这件事。

另外,我们还可以使用<s:url>创建URL,并将其赋值给一个变量供模板在稍后使用:

<s:url href=“/spitter/register” var=“registerUrl” />

Register

默认情况下,URL是在页面作用域内创建的。但是通过设置scope属性,我们可以让<s:url>在应用作用域内、会话作用域内或请求作用域内创建URL:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

文末

篇幅有限没有列举更多的前端面试题,小编把整理的前端大厂面试题PDF分享出来,一共有269页

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

朋友,同时减轻大家的负担。**
[外链图片转存中…(img-fRCiDwKY-1712874276537)]
[外链图片转存中…(img-TtFfPrV6-1712874276538)]
[外链图片转存中…(img-AYnXcy5D-1712874276538)]
[外链图片转存中…(img-R6A7PQXK-1712874276538)]
[外链图片转存中…(img-7Rx1yBZB-1712874276539)]
[外链图片转存中…(img-zebX5hJ3-1712874276539)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-1KoRv3lc-1712874276539)]

文末

篇幅有限没有列举更多的前端面试题,小编把整理的前端大厂面试题PDF分享出来,一共有269页

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-YPNDU8ht-1712874276540)]

  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值