Spring MVC 视图和视图解析器

会有一股神秘感。 提交于 2021-02-12 07:00:46

视图和视图解析器

  • 视图是业务处理后展现给用户的内容,而在此之前,要通过控制器得到对应的数据模型,如果是非逻辑视图,则不会经过 视力解析器定位视图,而是直接将数据模型渲染便结束了;而逻辑视图则要对其进一步解析,以定位真实视图,这就是视 图解析器的作用.而视图则是把从控制器查询回来的数据模型进行渲染,以显示给请求者查看.

视图

  • 在请求之后,Spring MVC 控制器获取了对应的数据,绑定到数据模型中,那么视图就可以展示数据模型的信息了.

  • Spring MVC中定义了多种视图,只是常用的并不是太多,它们都要满足视图的定义,它就是接口------View,

视图接口定义

    package org.springframework.web.servlet;
    
    import java.util.Map;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public interface View {
        //响应状态属性
        String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
        //定义数据模型下取出变量路径
        String PATH_VARIABLES = View.class.getName() + ".pathVariables";
        //选择响应内容类型
        String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
        //响应客户端的类型;getContentType表示返回一个 字符串,标明给用户佬类型的文件响应,可以是HTML,JSON,PDF等
        String getContentType();
        //渲染方法, var1是数据模型;render方法是一个渲染视图的方法,通过它就可以渲染视图了.
        void render(Map<String, ?> var1, HttpServletRequest var2, HttpServletResponse var3) throws Exception;
    }

  • 当控制器返回ModelAndView的时候,视图解析器就会解析它,然后将数据模型传递给render方法,这样就能够渲染视图了. 在Spring MVC中实现视图的类很多,比如JSTL视图JstlView, JSON视图MappingJackson2JsonView, PDF视图 AbstractPdfView等,通过它们的render方法,Spring MVC就可以将数据模型渲染成为各类视图,以满足各种需求.

视图解析器

视图解析器定义

    package org.springframework.web.servlet;
    
    import java.util.Locale;
    /**
     * 视图解析器定义
     * @param var1 视图名称
     * @param var2 用于国际化的  
     */
    public interface ViewResolver {
        View resolveViewName(String var1, Locale var2) throws Exception;
    }
  • Spring MVC自带了很多视图解析器,所以它能够解析各种各样需要逻辑视图的控制器返回.之前我们配置了InternalResourceViewResolver, 有时候在控制器中并没有返回一个ModelAndView,而只是返回了一个字符串,它也能够渲染视图,因为视力解析器生成了对应的视图.

不返回ModelAndView的视图

    @RequestMapping("/getHeaderAndCookie")
    public String testHeaderAndCookie(
            @RequestHeader(value = "User-Agent", required = false, defaultValue = "attribute") String userAgent,
            @CookieValue(value = "JSESSIONID", required = false, defaultValue = "MyJsessionId") String jsessionId) {
        System.out.println("User-Agent: " + userAgent);
        System.out.println("JSESSIONID: " + jsessionId);
        return "index";
    }    
    

实例: Excel视图的使用

  • 视图和视图渲染器是Spring MVC中重要的一步,JSTL视图和JSON视图,这是最常用的视图技术.有时候还需要导出Excel的功能,这也是常用的 功能,主要的功能是导出数据库中所有角色的信息.

  • 对于Excel而言,Spring MVC所推荐的是使用AbstractXlsView,它实现了视图接口,从其命名也可以知道它只是一个抽象类,不能生成实例对象. 它自己定义了一个抽象方法------buildExcelDocument要去实现.其它的方法Spring的AbstractXlsView已经实现了,所以完成这个方法便 可以使用Excel的视图功能了, AbstractXlsView类定义的buildExcelDocument方法:

   /**
    * 创建Excel文件
    * @param model -------Spring MVC数据模型
    * @param workbook --------  POI workbook对象
    * @param request ----------- http请求对象
    * @param response ----------- http响应对象
    * @throws Execption 异常
    */
    protected abstract void buildExcelDocument(Map<String, Object> model,Workbook workbook,
    HttpServletRequest request, HttpServletResponse response) throws Exception 
    
  • 这个方法的主要任务是创建一个Workbook,它要用到POI的API,这需要我们自行下载架包:
    <dependencies>
        <!-- 使用Apache POI生成和解析Excel文件 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>${poi}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${poi}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>3.9</version>
        </dependency>
    </dependencies>      
  • 假设需要一个所有角色信息的功能,但是将来也许还有其他的导出功能。为了方便,先定义一个接口,这个接口主要是让开发者自定义生成Excel的规则,
    package top.bfylu.chapter15.view;
    
    import org.apache.poi.ss.usermodel.Workbook;
    
    import java.util.Map;
    
    /**
     * @author bfy
     * @version 1.0.0
     * 创建时间: 18-5-7 下午10:03
     * @email bfyjian@gmail.com
     */
    public interface ExcelExportService {
    
        public void makeWorkBook(Map<String, Object> model, Workbook workbook);
    }
  • 有了这个接口还需要完成一个可实例化的Excel视图类-----ExcelView,对于导出而言还需要一个下载文件名称,所以不会定义一个文件名(fileName) 属性,由于该视图不是一个逻辑视图,所以无须视图解析器也可以运行它,其定义:
    package top.bfylu.chapter15.view;
    
    import org.apache.commons.lang.StringUtils;
    import org.apache.poi.ss.usermodel.Workbook;
    import org.springframework.web.servlet.view.document.AbstractXlsView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Map;
    
    /**
     * 定义Excel视图
     *
     * @author bfy
     * @version 1.0.0
     * 创建时间: 18-5-7 下午10:20
     * @email bfyjian@gmail.com
     */
    public class ExcelView extends AbstractXlsView {
    
        //文件名
        private String fileName = null;
    
        //导出视图自定义接口
        private ExcelExportService excelExportService = null;
    
    
        //构造方法1
        public ExcelView(ExcelExportService excelExportService) {
            this.excelExportService = excelExportService;
        }
    
        //构造方法2
        public ExcelView(String viewName, ExcelExportService excelExportService) {
            this.setBeanName(viewName);
        }
    
        @Override
        protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request,
                                          HttpServletResponse response) throws Exception {
            //没有自定义接口
            if (excelExportService == null)
                throw new RuntimeException("导出服务接口不能为null!!");
            //文件名不为空,为空则使用请求路径中的字符串作为文件名
            if (!StringUtils.isEmpty(fileName)) {
                //进行字符转换
                String reqCharset = request.getCharacterEncoding();
                reqCharset = reqCharset == null ? "UTF-8" : reqCharset;
                fileName = new String(fileName.getBytes(reqCharset), "ISO8859-1");
                //设置下面文件名
                response.setHeader("Content-disposition", "attachment;filename=" + fileName);
            }
            //回调接口方法,使用自定义生成Excel文档
            excelExportService.makeWorkBook(model, workbook);
        }
    
        /********Setter and Getter***************/
        public String getFileName() {
            return fileName;
        }
    
        public void setFileName(String fileName) {
            this.fileName = fileName;
        }
    
        public ExcelExportService getExcelExportService() {
            return excelExportService;
        }
    
        public void setExcelExportService(ExcelExportService excelExportService) {
            this.excelExportService = excelExportService;
        }
    }

使用ExcelView导出Excel

    /**
     * @author bfy
     * @version 1.0.0
     * 创建时间: 2018/5/4 下午5:07
     * @email bfyjian@gmail.com
     */
    @Controller
    @RequestMapping("role")
    public class RoleController {
    
        @Autowired
        private RoleService roleService = null;
        /***********使用ExcelView导出Excel*************/
        @RequestMapping(value = "/export", method = RequestMethod.GET)
        public ModelAndView export() {
            
            //模型和视图
            ModelAndView mv = new ModelAndView();
            //Excel视图,并设置自定义导出接口
            ExcelView ev = new ExcelView(exportService());
            //文件名
            ev.setFileName("所有角色.xlsx");
            //设置SQL后台参数
            RoleParams roleParams = new RoleParams();
            //限制1万条
            PageParams page = new PageParams();
            page.setStart(0);
            page.setLimit(10000);
            roleParams.setPageParams(page);
            //查询
            List<Role> roleList = roleService.findRoles(roleParams);
            //加入数据模型
            mv.addObject("roleList", roleList);
            mv.setView(ev);
            return mv;
        }
    
        @SuppressWarnings({"unchecked"})
        public ExcelExportService exportService() {
            //使用Lambda表达式自定义导出excel规则
            return (Map<String, Object> model, Workbook workbook) -> {
                //获取用户列表
                List<Role> roleList = (List<Role>) model.get("roleList");
                //生成Sheet
                Sheet sheet = workbook.createSheet("所有角色");
                //加载标题
                Row title = sheet.createRow(0);
                title.createCell(0).setCellValue("编号");
                title.createCell(1).setCellValue("名称");
                title.createCell(2).setCellValue("备注");
                //便历角色列表,生成一行行的数据
                for (int i = 0; i<roleList.size(); i++) {
                    Role role = roleList.get(i);
                    int roleIdx = i + 1;
                    Row row = sheet.createRow(roleIdx);
                    row.createCell(0).setCellValue(role.getId());
                    row.createCell(1).setCellValue(role.getRoleName());
                    row.createCell(2).setCellValue(role.getNote());
    
                }
            };
        }
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!