springMVC中的ModelAndView,Model,ModelMap

写在前面

本文基于springboot环境来进行测试,没有这个环境的,可以参考这里,隔空这位同学的用心总结。下面我们正式开始。

1:整体分析

先看下ModelAndView源码:

public class ModelAndView {
	// 逻辑视图地址
    @Nullable
    private Object view;
    // 数据
    @Nullable
    private ModelMap model;
}

其中的Object view代表的就是视图,在jsp环境中可以认为就是jsp页面,ModelMap model就是数据,来看下ModelMap的定义:

public class ModelMap extends LinkedHashMap<String, Object> {}

可以看到继承了java.util.LinkedHashMap,所以其也是一个java.util.Map。通过Object view就有了页面,通过字典数据结构ModelMap model就有了页面需要的数据,二者结合就可以生成最终展示给用户的页面了。对于数据spring还提供了另外的选择,即接口org.springframework.ui.Model该接口在spring-context模块中,可以认为该接口是ModelMap外的另外一个选择。源码如下:

public interface Model {
	// 添加视图需要的数据
	Model addAttribute(String attributeName, @Nullable Object attributeValue);
}

其实现类

public class ExtendedModelMap extends ModelMap implements Model {}

可以看到其不仅仅实现了Model接口,还继承了类ModelMap,因此兼具二者的能力。接下来我们通过一个完整的例子来看一下。

2:综合例子

2.1:定义jsp

我们先来定义jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Titletitle>
head>
<body>
    ${user.id}---${user.userName}---${user.note}
body>
html>

2.2:定义User

public class User {

    private Long id;
    private String userName;
    private String note;

    ...getter setter toString...
}

2.3:使用ModelAndView

2.3.1:代码

@RequestMapping("/useModelAndView")
public ModelAndView useModelAndView() {
    ModelAndView mv = new ModelAndView();
    // 设置数据模型
    User user = new User();
    user.setId(1L);
    user.setUserName("张三");
    user.setNote("张三的歌");
    mv.addObject("user", user);
    // 设置视图为user.jsp
    mv.setViewName("user");
    return mv;
}

2.3.2:测试

springMVC中的ModelAndView,Model,ModelMap_第1张图片

2.3:使用Model

2.3.1:代码

@RequestMapping("/userModel")
public String userModel(Model model) {
    User user = new User();
    user.setId(2L);
    user.setUserName("李四");
    user.setNote("李四的小姨子");
    model.addAttribute("user", user);
    return "user";
}

2.3.2:测试

springMVC中的ModelAndView,Model,ModelMap_第2张图片

2.4:使用ModelMap

2.4.1:代码

@RequestMapping("/useModelMap")
public ModelAndView useModelMap(ModelMap modelMap) {
    User user = new User();
    user.setId(3L);
    user.setUserName("王五");
    user.setNote("王五的表姐");
    ModelAndView mv = new ModelAndView();
    // 设置视图
    mv.setViewName("user");
    // 通过ModelMap设置数据
    modelMap.addAttribute("user", user);
    return mv;
}

2.4.2:测试

springMVC中的ModelAndView,Model,ModelMap_第3张图片

3:其它视图

除了我们例子中的jsp视图(逻辑视图,即需要视图解析器),还有很多其它的视图,比如json视图,pdf视图,excel视图,但是这些视图都是非逻辑视图,即不需要视图解析器,所有的视图都会实现View接口,源码如下:

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";

    @Nullable
    default String getContentType() {
        return null;
    }
	// 渲染数据方法
    void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception;
}

这里我们以pdf为例进行说明,pdf视图定义了接口AbstractPdfView,源码如下:

public abstract class AbstractPdfView extends AbstractView {
	protected abstract void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer,
				HttpServletRequest request, HttpServletResponse response) throws Exception;
}

如果想要自定义PDF视图,只需要继承该抽象类,并实现抽象方法buildPdfDocument就可以了。

3.1:定义导出pdf的服务层接口

@FunctionalInterface
public interface PdfExportService {
    public void make(
            Map<String, Object> model,
                     Document document,
                     PdfWriter pdfWriter,
                     HttpServletRequest request,
                     HttpServletResponse response);
}

3.2:定义pdf视图

/**
 * 通过集成AbstractPdfView定义pdf视图
 */
public class PdfView extends AbstractPdfView {
    private PdfExportService pdfExportService;

    public PdfView(PdfExportService pdfExportService) {
        this.pdfExportService = pdfExportService;
    }

    // pdf数据渲染接口
    @Override
    protected void buildPdfDocument(Map<String, Object> model,
                                    Document document,
                                    PdfWriter pdfWriter,
                                    HttpServletRequest request,
                                    HttpServletResponse response
    ) throws Exception {
        pdfExportService.make(model, document, pdfWriter, request, response);
    }
}

3.3:定义控制器

// 导出pdf
@RequestMapping("/export/pdf")
public ModelAndView exportPdf() {
    ModelAndView mv = new ModelAndView();

    // 需要渲染到pdf文档上的用户列表数据
    List<User> userList = new ArrayList<>();
    userList.add(new User(1L, "zhangsan", "the song of zhangsan"));
    userList.add(new User(2L, "lisi", "the xiaoyizi of lisi"));
    userList.add(new User(3L, "wangwu", "the biaojie of wangwu"));
    userList.add(new User(4L, "zhaoliu", "the guma of wangwu"));
    mv.addObject("userList", userList);

    // 定义PDF视图并设置
    View pdfView = new PdfView(exportService());
    mv.setView(pdfView);

    return mv;
}

private PdfExportService exportService() {
    return (model, document, pdfWriter, request, response) -> {
        try {
            // A4纸张
            document.setPageSize(PageSize.A4);
            // 设置页面标题
            document.addTitle("用户信息");
            // 换行
            document.add(new Chunk("\n"));
            // 表格4行
            PdfPTable pdfPTable = new PdfPTable(3);
            // 单元格
            //PdfPCell cell = null;
            // 字体,定义为蓝色加粗
            Font f8 = new Font();
            f8.setColor(Color.BLUE);
            f8.setStyle(Font.BOLD);
            String[] headTileArr = new String[]
                    { "id", "username", "note" };
            for (String headTitle : headTileArr) {
                // 表格的表头标题
                PdfPCell cell = new PdfPCell(new Paragraph(headTitle, f8));
                // 居中
                cell.setHorizontalAlignment(1);
                // 添加到表格中
                pdfPTable.addCell(cell);
            }

            // 设置数据到表格中
            List<User> userList = (List<User>) model.get("userList");
            for (User user : userList) {
                PdfPCell idCell = new PdfPCell(new Paragraph(user.getId() + ""));
                pdfPTable.addCell(idCell);
                PdfPCell usernameCell = new PdfPCell(new Paragraph(user.getUserName()));
                pdfPTable.addCell(usernameCell);
                PdfPCell noteCell = new PdfPCell(new Paragraph(user.getNote()));
                pdfPTable.addCell(noteCell);
            }
            // 添加表格到文档中
            document.add(pdfPTable);
        } catch (Exception e) {
            e.printStackTrace();
        }
    };
}

3.4:测试

springMVC中的ModelAndView,Model,ModelMap_第4张图片

你可能感兴趣的:(springmvc,spring,springmvc,java)