Spring实战-读书笔记(六)-渲染Web视图

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fly_zxy/article/details/78754552

渲染Web视图

理解视图解析

我们知道Controller方法返回逻辑视图的名称,DispatcherServlet将视图逻辑名称传递给视图实现类处理获得物理视图资源。Controller并不直接返回物理视图,而是返回逻辑视图名称,这样就很好的实现了解耦,保证了在不影响请求处理逻辑的情况下维护和修改视图。那么视图实现如果根据逻辑视图名称解析物理视图资源呢?Spring自带了13个视图解析器,能够将逻辑视图名转换为物理实现。

BeanNameViewResolver 
将视图解析为Spring应用上下文中的bean,其中bean的ID与视图的名字相同

ContentNegotiatingViewResolver 
通过考虑客户端需要的内容类型来解析视图,委托给另外一个能够产生对应内容类型的视图解析器

FreeMarkerViewResolver 
将视图解析为FreeMarker模板

InternalResourceViewResolver 
将视图解析为Web应用的内部资源(一般为JSP)

JasperReportsViewResolver 
将视图解析为JasperReports定义

ResourceBundleViewResolver 
将视图解析为资源bundle(一般为属性文件)

TilesViewResolver
将视图解析为Apache Tile定义,其中tileID与视图名称相同。注意有两个不同的TilesViewResolver实现,分别对应于Tiles 2.0和Tiles 3.0

UrlBasedViewResolver 
直接根据视图的名称解析视图,视图的名称会匹配一个物理视图的定义

VelocityLayoutViewResolver 
将视图解析为Velocity布局,从不同的Velocity模板中组合页面

VelocityViewResolver 
将视图解析为Velocity模板

XmlViewResolver 
将视图解析为特定XML文件中的bean定义。类似于BeanName-ViewResolver

XsltViewResolver 
将视图解析为XSLT转换后的结果
以上所有的视图实现类都是些了ViewResolver接口。这个接口的作用就是根据逻辑视图名称返回物理视图(即View接口)。
package org.springframework.web.servlet;

import java.util.Locale;

public interface ViewResolver {
	View resolveViewName(String viewName, Locale locale) throws Exception;
}
View接口的任务就是接受模型以及Servlet的request和response对象,并将输出结果渲染到response中。View接口有两个核心方法:
String getContentType();

void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;

InternalResourceViewResolver视图实现

我们在java中最常用的视图技术就是jsp。InternalResourceViewResolver视图实现的作用就是将逻辑视图名称解析成一个jsp资源。我么看一下如果在Spring MVC中使用InternalResourceViewResolver。
	/**
	 * 配置视图解析器
	 * 
	 * @return
	 */
	@Bean
	public ViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setPrefix("/WEB-INF/views/"); 	// 在视图路径添加前缀
		viewResolver.setSuffix(".jsp"); 		// 在视图路径添加后缀
		viewResolver.setExposePathVariables(true);
		viewResolver.setExposeContextBeansAsAttributes(true);
		viewResolver.setViewClass(JstlView.class); 	//jsp中使用JSTL,将物理视图解析成JstlView
		return viewResolver;
	} 
我们对InternalResourceViewResolver的配置都很基础和简单。它最终会将逻辑视图名解析为InternalResourceView实例,这个实例会引用JSP文件。但是如果这些JSP使用JSTL标签来处理格式化和信息的话,那么我们会希望InternalResourceViewResolver将视图解析为JstlView。JSTL的格式化标签需要一个Locale对象,以便于恰当地格式化地域相关的值,如日期和货币。信息标签可以借助Spring的信息资源和Locale,从而选择适当的信息渲染到HTML之中。通过解析JstlView,JSTL能够获得Locale对象以及Spring中配置的信息资源。如果想让InternalResourceViewResolver将视图解析为JstlView,而不是InternalResourceView的话,那么我们只需设置它的viewClass属性即可。

使用Spring的JSP库

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

表单标签

使用表单标签需要在jsp导入如下两行代码:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf"%>

Sping web MVC提供的的表单标签库
<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:label> 
渲染成一个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>标签

使用表单标签

我们使用Spring提供的表单标签实现博客发布功能。实现后的界面如下。

jsp代码实现。
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="s"%>

<%@ page session="false"%>
<%@page isELIgnored="false"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<title>博客发布</title>
<style type="text/css">
div .error {
	color: red;
}
</style>
</head>
<body>
	<h2>
		<s:message code="showWirteForm.title"></s:message>
	</h2>
	<%--  modelAttribute="aboutBlog" commandName="aboutBlogModel" --%>
	<sf:form method="POST" commandName="aboutBlog">
		<div>
			<sf:label path="name" cssErrorClass="error">
				<s:message code="showWirteForm.form.name"></s:message>
			</sf:label>
			<sf:input path="name" />
			<sf:errors path="name" cssClass="error"></sf:errors>
		</div>
		<div>
			<sf:label path="title" cssErrorClass="error">
				<s:message code="showWirteForm.form.title"></s:message>
			</sf:label>
			<sf:input path="title" />
			<sf:errors path="title" cssClass="error"></sf:errors>

		</div>
		<div>
			<sf:label path="content" cssErrorClass="error">
				<s:message code="showWirteForm.form.content"></s:message>
			</sf:label>
			<br>
			<sf:input type="textarea" path="content"
				style="width:300px;height:140px;" />
			<sf:errors path="content" cssClass="error"></sf:errors>
		</div>
		<div>
			<sf:label path="description" cssErrorClass="error">
				<s:message code="showWirteForm.form.description"></s:message>
			</sf:label>
			<sf:input path="description" />
			<sf:errors path="description" cssClass="error"></sf:errors>
		</div>
		<div>
			<sf:label path="keyword" cssErrorClass="error">
				<s:message code="showWirteForm.form.keyword"></s:message>
			</sf:label>
			<sf:input path="keyword" />
			<sf:errors path="keyword" cssClass="error"></sf:errors>
		</div>
		<div>
			<button type="submit"><s:message code="showWirteForm.form.submit"></s:message></button>
		</div>
	</sf:form>
</body>
</html>
sf:from标签的commandName属性指定model名称,sf:from标签中的其它绑定标签会以这个model作为上下文。
sf:label标签中的path属性表示model中的属性值,如果这个属性没有通过校验,标签内容会按cssErrorClass指定的样式显示。一般配合Spring校验一起使用。
sf:input标签中的path属性表示model中的属性值。
sf:erors标签中的path属性表示model中的属性值,如果这个属性没有通过校验,将会显示不通过提示信息,提示信息会按cssClass指定的样式显示。一般配合Spring校验一起使用。
cssErrorClass

返回视图的Controller方法。
	/**
	 * 博客发布视图
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/wirte", method = GET)
	public String showWirteForm(HttpServletRequest request,Model model) {
		model.addAttribute("aboutBlog", new AboutBlogModel());
		return "showWirteForm";
	}
在返回视图的同时想model里添加了new AboutBlogModel()对象,并以aboutBlog为key。这样在转发到jsp视图中sf:from的commandName属性不会因为找不到aboutBlog而报错。

处理博客发布的Controller方法。
/**
	 * 博客发布操作
	 * 使用Spring MVC处理表单参数
	 * @param aboutBlogModel
	 * @param errors
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/wirte", method = POST)
	public String wirte(@Valid @ModelAttribute("aboutBlog") AboutBlogModel aboutBlogModel,Errors  errors,Model model) {
		if(errors.hasErrors()) {
			return "showWirteForm";
		}
		String id = aboutBlogReq.add(aboutBlogModel);
		// 这里使用重定向,防止用户重复提交(比如多次点击刷新按钮)
		return "redirect:/blogManager/queryOne/" + id;
	}
@Valid注解表示对AboutBlogModel进行校验,如果有校验不通过将会产生一个Errors对象,不通过的提示信息封装在Errors对象中。注意AboutBlogModel aboutBlogModel形参使用了@Valid注解标记,那么这个参数后边要紧跟着一个Errors对象,表示errors对象代表的是aboutBlogModel对象校验不通过信息。wirte()方法如果还有User对象需要校验,添加@Valid User user,Errors userErrors参数即可。
@ModelAttribute注解表示aboutBlogModel对象在model中的key名称。如果不指定名称Spring将会按照对象类型生成key名称,例如AboutBlogModel对象的key名称为aboutBlogModel,User对象的key名称为user。
注意:这里@ModelAtrribute注解将aboutBlogModel对象在model里的key命名为aboutBlog,是为了能够在效验不通过的时候回显用户填写的信息(<sf:form method="POST" commandName="aboutBlog">)。

Spring web 实现国际化

我们注意到博客发布功能的jsp界面利用<s:message code=""/>标签引用了国际化信息。这里的国际化包括界面文字和效验不通过的提示信息。web是世界性的网络,应该根据不同地域用户在界面显示对应的语言,提供良好的交互,我们来看一下Spring如何实现信息的国际化。

第一步:编写国际化资源文件

message目录下的文件是国际化文件。validationMessages目录是效验提示信息的国际化资源文件。文件名称带_zh_CH后缀的是简体中文的国际化资源文件,zh表示中国,CH表示大陆城市。不带有后缀的message.properties、ValidationMessages.properties为默认的国际化资源文件(我这里默认是英文)。

第二步:在Spring中配置国际化资源
/**
	 * 配置国际化资源资源
	 * @return
	 */
	@Bean
	public MessageSource messageSource() {
		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
		//设置国际化资源文件的基础名称,默认在classpath查找指定的properties文件
		//"message/message"表示在classpath路径下的message目录查询已message开头properties文件
		//"validationMessages/ValidationMessages"表示在classpath路径下的validationMessages目录查询已ValidationMessages开头properties文件
		messageSource.setBasenames("message/message","validationMessages/ValidationMessages");	
		//设置国际化资源文件编码
		//注意:国际化资源文件的编码也要已UTF-8编码,否则会出现乱码
		messageSource.setDefaultEncoding("UTF-8");
		return messageSource;
	}
	
	/**
	 * 配置Spring web效验功能提示信息的国际化资源
	 */
	@Override
	public Validator getValidator() {
		LocalValidatorFactoryBean lv = new LocalValidatorFactoryBean();
		lv.setProviderClass(HibernateValidator.class);
		lv.setValidationMessageSource(messageSource());
		return lv;
	}
另外的可选方案是使用ReloadableResourceBundleMessageSource,它的工作方式与ResourceBundleMessageSource非常类似,但是它能够重新加载信息属性,而不必重新编译或重启应用。如下是配置ReloadableResourceBundleMessageSource的样例:
	/**
	 * 配置国际化资源资源
	 * @return
	 */
	@Bean
	public MessageSource messageSource() {
		ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
		messageSource.setBasenames("classpath:message/message","classpath:validationMessages/ValidationMessages");	
		messageSource.setDefaultEncoding("UTF-8");
		return messageSource;
	}

这里的关键区别在于basename属性设置为在应用的外部查找(而不ResourceBundleMessageSource那样在类路径下查找)。basename属性可以设置为在类路径下(以“classpath:”作为前缀)、文件系统中(以“file:”作为前缀)或Web应用的根路径下(没有前缀)查找属性。
第三部:引用国际化资源
在jsp中使用<s:message code="showWirteForm.form.name"></s:message>标签引用国际资源。
<sf:errors path="description" cssClass="error"></sf:errors>标签引用效验提示信息国际化资源。通过在效验注解的message属性引用,例如:
	@NotBlank(message="{blog.model.AboutBlogModel.name.NotBlank}")
	private String name;
国际化相关知识点可以参考: http://blog.csdn.net/gaoshanliushui2009/article/details/46276583

中文国际化效果展示。


猜你喜欢

转载自blog.csdn.net/fly_zxy/article/details/78754552
今日推荐