Spring MVC(5):视图 & 视图解析

Spring MVC 支持的视图技术

Spring MVC 请求处理方法处理完成后,会返回一个 ModelAndView 对象,该对象包含了模型对象的信息,和视图逻辑名,再借助视图解析器(ViewResolver)得到最终的视图(View),该视图可以是一个 JSP,也可以是一个基于 FreeMarker、Velocity 模板技术的视图,或者XML,JSON,Excel,PDF等;

以下示例代码地址:
https://gitee.com/assad/springframework-test-mvc-extra

JSP和JSTL

Spring 借助 InternelResourceViewResolver 视图解析器解析 JSP 视图页面,在 spring-mvc上下文中的常用配置如下:  

 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/views/"  p:suffix=".jsp"  />

Spring MVC 支持在 JSP 页面中使用 JSTL 标签,配合 EL 表达式可以很方便地进行流程控制,数据绑定,数据处理等,当用到<fmt:message>进行国际化输出时,需要更改 InternalResourceViewResoulver 的默认视图实现类为 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" />

Spring 本身还提供了一套
表单标签<from>,可以很方便地将模型数据中的表单/命令对象绑定到 HTML 表单元素中,他们共有的属性如下:

path用属性路径表示的表单对象属性;
htmlEscape绑定的表单属性值是是否要对 HTML 特殊字符进行转换,默认值为 true;
cssClass表单组件对应的CSS样式类名
cssErrorClass当表单组件的数据存在相应的验证错误时,采用的 CSS 样式类
cssStyle表单组件对应的 CSS 样式串

其中的一些常用的表单标签如下:

<form:input>输入框标签组件,如 <form:input path=”userName” />
<form:password>密码框输入组件,如 <form:passowrd path=”password” />
<form:hidden>隐藏框组件,如 <form:input path=”userId” />
<form:textarea>多行输入框组件,如 <form:textarea path=”userNote” rows=”3″ cols=”20″ />
<form:radiobutton>单选框组件,当表单的对应属性和value值相同时,该单选框被选中,如:
<form:radiobutton path=”sex” value=”0″ label=”“/>
<form:radiobutton path=”sex” value=”1″ label=”女”/>
当表单对象sex=0,第一个单选框被选中;
<form:raidobuttons>单选框组件组,用于构造多个的单选框,如下:
<form:radiobuttons path=”sex” items=”${sexOptions}” delimiter=”<br/>” />
sexOptions 可以在jsp中定义,该对象可以是一个List,String[],或Map,用于产生和该变量元素相同的单选框组件;
默认情况下,如果 sexOptions 为 List / String[] ,单选框的 value 和 label 相同;
如果 sexOptions 为 Map 类型,单选框的 value 为 Map 的 key,label 为 Map 的 value;

也可以通过 itemValue,itemLabel 来更改以上Map这个行为:
<form:radiobuttons path=”sex” items=”${sexOptions}” delimiter=”<br/>”
itemValue=”value” itemLabel=”key”/>

<form:checkbox>复选框组件,如:
<form:checkbox path=”like” value=”1″ />  
<form:checkbox path=”like” value=”2″ />
一般来说,like
<form:checkboxs>复选框组件组,用于够着多个复选框,如下:
<form:checkboxs path=”like” items=”${likeOptions}” delimeter=”<br/>”>
用法类似于<form:raidobuttons>
<form:select>下拉框组件,如:
<form:select path=”city” items=”${citys}”>
   <form:option value=”” label=”–请选择–“>
   <form:options items=”${cityMap}” itemValue=”key” itemLabel=”value” />
</form:select>
用法类似于<form:raidobuttons>
<form:errors>显示表单错误校验信息,如:
<form:errors path=”userName”/>  表示“userName”属性的错误
<form:errors path=”*/”>         表示绑定对象所有属性错误
<form:errors path=”user*”>      表示所有“user”前缀的属性的错误

示例使用代码:  

<jsp:useBean id="user" class="site.assad.domain.User" scope="request" />
<form:form action="/user/handleRegister" method="post" modelAttribute="user">
    
    用户名:<form:input path="userName" /><br/>
    <form:errors path="userName" cssClass="error"/><br /> 
    密码:<form:input path="password" /><br/>
    <form:errors path="password"/><br />
    Email:<form:input path="email" cssClass="error" /><br/>
    <form:errors path="email"/><br />
    生日(格式"yyyy-MM-dd"):<form:input path="birthday" /><br/>
    <form:errors path="birthday" cssClass="error"/><br />
    <input type="submit" value="提交" />
    <input type="reset" value="重置" /><br/>
</form:form>

模板视图 FreeMarker,Velocity

Spring MVC 支持 FreeMarker ,Velocity 视图引擎,他们是基于模板生成文本输出地通用工具,FreeMarker 可以基于模板生成 HTML,XML,Java 源码等多种类型的输出内容,该内容可以是一段字符模板,也可以是一个文件;

以下示例在 Spring MVC 中使用 Freemarker 作为视图输出: 示例代码模块:
site.assad.web.UserController(控制器)
webapp/views/user/ftl/userListFtl.ftl(FreeMarker模板视图)
webapp/assad-servlet.xml(spring-mvc配置文件)

FreeMarker 视图模板 userListFtl.ftl 如下:  

<html>
<head>
    <title>User Lists</title>
</head>
<body>
<#list userList as user>
    <p>user id:${user.userId}</p>
    <p>user name:${user.userName}</p>
    <p>user password:${user.password}</p>
    <p>user birthday:${user.birthday?string("yyyy-MM-dd")}</p>
    <br/>
</#list>
</body>
</html>

控制器  

package site.assad.web;
@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    //转发到 FreeMarker 模板视图
    @RequestMapping("/showUserListByFtl")
    public ModelAndView showUserListByFtl(){
        List<User> userList = userService.getAllUser();
        return new ModelAndView("/user/ftl/userListFtl","userList",userList);
    }
}

在spring-mvc配置文件中配置 Freemarker 基础设施和解析器,assad-servlet.xml  

    <!--配置FreeMarker基础设施-->
    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"
          p:templateLoaderPath="/WEB-INF/views"
          p:defaultEncoding="UTF-8">
        <property name="freemarkerSettings">
            <props>
                <prop key="classic_compatible">true</prop>
            </props>
        </property>
    </bean>
    <!--配置FreeMarker解析器-->
    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"
          p:order="5"
          p:suffix=".ftl"
          p:contentType="text/html;charset=utf-8"
    />

同时 Spring 还提供了一系列的宏,特别是表单宏,类似于JSP中的标签,参考:
https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#views-form-macros

输出XML

Spring 支持将模型数据以 XML 的格式输出,对应的视图解析器为 MarshallingView ,以下是一个使用示例:

需要导入的依赖:
org.springframework:spring-oxm
com.thoughtworks.xstream:xstream:1.4.10(XStream,POJO与XML转换类)


在spring-mvc配置文件中添加如下:
assad-servlet.xml  

<bean id="xmlMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
        <property name="streamDriver">
            <bean class="com.thoughtworks.xstream.io.xml.StaxDriver" />
        </property>
        <property name="annotatedClasses">
            <list>
                <value>site.assad.domain.User</value>
            </list>
        </property>
    </bean>
<bean id="userListXML" class="org.springframework.web.servlet.view.xml.MarshallingView"
          p:modelKey="userList"
          p:marshaller-ref="xmlMarshaller"
    />

控制器类中的相关处理器代码:
UserController  

package site.assad.web;
@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    //转发到 XML 视图
    @RequestMapping("/showUserListByXML")
    public ModelAndView showUserListByXML(){
        List<User> userList = userService.getAllUser();
        return new ModelAndView("userListXML");
    }
}

输出JSON

Spring 支持将模型数据以 JSON 的格式输出,对应的解析器为 MappingJackson2JsonView,即使用 Jackson 框架;


需要导入的依赖:
com.fasterxml.jackson.core:jackson-core

com.fasterxml.jackson.core:jackson-databind

在spring-mvc配置文件中添加如下:
assad-servlet.xml  

    <bean id="userListJSON" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"
          p:modelKey="userList"
    />

控制器类中的相关处理器代码:
UserController  

package site.assad.web;
@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    //转发到 JSON 视图
    @RequestMapping("/showUserListByJSON")
    public ModelAndView showUserListByJSON(){
        List<User> userList = userService.getAllUser();
        return new ModelAndView("userListJSON");
    }
}


输出Excel

Spring mvc 中可以借助 apache.poi API 来实现使用 Excel 作为视图,具体只需要拓展 Spring 的 AbstractExcelView 或 AbstractJExcelView 即可;

需要导入的依赖:
org.apache.poi:poi



实现 AbstractExcelView 拓展类:
 

package site.assad.web;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import site.assad.domain.User;
public class UserListExcelView extends AbstractExcelView {
    @Override
    protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
        //excel 文件编码必须为“iso8859-1“,否则会出现乱码
        response.setHeader("Content-Disposition","inline;filename=" + new String("用户列表".getBytes(),"iso8859-1"));
        List<User> userList = (List<User>) model.get("userList");
        //创建excel表格
        HSSFSheet sheet = workbook.createSheet("users");
        //创建行首
        HSSFRow header = sheet.createRow(0);
        header.createCell(0).setCellValue("账号");
        header.createCell(1).setCellValue("用户名");
        header.createCell(2).setCellValue("生日");
        //填充模型
        int rowNum = 1;
        for(User user : userList){
            HSSFRow row = sheet.createRow(rowNum++);
            row.createCell(0).setCellValue(user.getUserId());
            row.createCell(1).setCellValue(user.getUserName());
            row.createCell(2).setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(user.getBirthday()));
        }
    }
}

在spring-mvc配置文件中添加如下:
assad-servlet.xml  

<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="10" />
<bean id="userListExcel" class="site.assad.web.UserListExcelView" />

控制器类中的相关处理器代码:
UserController  

 //转发到 Excel 视图
    @RequestMapping("/showUserListByExcel")
    public ModelAndView showUserListByExcel(){
        List<User> userList = userService.getAllUser();
        return new ModelAndView("userListExcel");
    }


输出PDF

Spring mvc 中实现PDF视图类似于 Excel,同样使用 BeanNameViewResolver 解析器;

需要导入的依赖:
com.lowagie:itext:2.1.7
itextasian-1.5.2.jar
※默认itext库是不支持亚洲文字(中文、日文、韩文等)的输出的,需要添加itextasian用于支持亚洲文字的输出;


实现 AbstractPdfView 拓展类:
 

package site.assad.web;
import com.lowagie.text.*;
import com.lowagie.text.Font;
import com.lowagie.text.pdf.BaseFont;
import org.springframework.web.servlet.view.document.AbstractPdfView;
import com.lowagie.text.pdf.PdfWriter;
import site.assad.domain.User;
public class UserListPDFView extends AbstractPdfView{
    @Override
    protected void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setHeader("Content-Disposition","inline;filename=" + new String("用户列表".getBytes(),"iso8859-1"));
        List<User> userList =(List<User>) model.get("userList");
        //创建表格,并设置表格格式
        Table table = new Table(3);
        table.setWidth(80);         //设置表格宽度
        table.setBorder(1);         //设置表格边框
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);  //设置对齐格式
        table.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE);
        //设置中文字体
        BaseFont cnBaseFont = BaseFont.createFont("STSongStd-Light","UniGB-UCS2-H",false);
        Font cnFont = new Font(cnBaseFont,10,Font.NORMAL, Color.BLUE);
        //填充表头,中文字符需要使用转换器构造Cell,否则会产生乱码
        table.addCell(buildFontCell("账号",cnFont));
        table.addCell(buildFontCell("名称",cnFont));
        table.addCell(buildFontCell("生日",cnFont));
        //填充表格数据
        for(User user : userList){
            table.addCell(user.getUserId()+"");  //英文字符直接添加
            table.addCell(buildFontCell(user.getUserName(),cnFont));
            table.addCell(new SimpleDateFormat("yyyy-MM-dd").format(user.getBirthday()));
        }
    }
    private Cell buildFontCell(String content,Font font) throws RuntimeException{
        try {
            return new Cell(new Phrase(content,font));
        } catch (BadElementException e) {
            throw new RuntimeException(e);
        }
    }
}

在spring-mvc配置文件中添加如下:
assad-servlet.xml  

<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="10" />
<bean id="userListPDF" class="site.assad.web.UserListPDFView" />>

控制器类中的相关处理器代码:
UserController  

    //转发到 PDF 视图
    @RequestMapping("/showUserListByPDF")
    public ModelAndView showUserListByPDF(){
        List<User> userList = userService.getAllUser();
        return new ModelAndView("userListPDF");
    }

混合多种视图技术

Spring 支持对于 REST 编程的风格的支持,REST 风格的应用对于资源的 URL 由严格的定义:一个资源对象对应一个 URL; Spring 提供了 ContentNegotiationManager 用于支持基于 REST 风格的混合资源请求视图;

假设希望使用以下 REST 风格的 URL 以不同的 MIME 格式获取相同的资源:
/user/showUserListMix:返回一个 HTML 页面显示的用户列表
/user/showUserListMix?content=xml:返回一个 XML 格式的用户列表
/user/showUserListMix?content=json:返回一个 JSON 格式的用户列表


控制器类中的相关处理器代码:
UserController  

    //使用同一URL获取不同格式的返回内容
    @RequestMapping("/showUserListMix")
    public ModelAndView showUserListMix(){
        List<User> userList = userService.getAllUser();
        return new ModelAndView("userListMix");
    }

在spring-mvc配置文件中添加如下:
assad-servlet.xml  

    <!--配置 ContentNegontiatingVieqResolver -->
    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"
          p:ignoreAcceptHeader="true"  
          p:favorPathExtension="false"
          p:favorParameter="true"
          p:parameterName="format"
          p:defaultContentType="text/html" >
        <!--不支持 Accept 报文头指定的 MIME 类型,仅通过请求参数指定 MIME 类型,参数名为content,以下为请求参数列表-->
        <property name="mediaTypes">
            <value>
                html=text/html
                xml=application/xml
                json=application/json
            </value>
        </property>
    </bean>
    <!--配置混合视图解析器,并设置为最高优先级-->
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
          p:order="0"
          p:contentNegotiationManager-ref="contentNegotiationManager" >
        <property name="defaultViews">
            <list>
                <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"
                    p:modelKey="userList" />
                <bean class="org.springframework.web.servlet.view.xml.MarshallingView"
                    p:modelKey="userList" p:marshaller-ref="xmlMarshaller" />
            </list>
        </property>
    </bean>
    <!--配置jsp,xml,json 解析器,略,可以通过设置order属性来设定优先级-->
    .......

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/al_assad/article/details/79013060
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞