Day57.表述层(MVC)、Thymeleaf: 逻辑视图、对象图(OGNL)、分支迭代...

目录

一、MVC概念

二、Thymeleaf

1. HelloThymeleaf、逻辑视图

2. th表达式基本语法   th:?="? {?}" 

3. 在Thymeleaf中操作域对象

域对象在Thymeleaf中的使用

4. 设置首页(index.html)的thymeleaf的渲染

5. 获取请求参数  ${param.参数名}

6. 内置对象   th:?="${#?.?}"

7. 对象图导航语言(OGNL)   th:text="${list[1].obj.name}"

8. 分支 (th:if、th:switch | th:case)

9. 迭代    th:each="e : ${ list }"

10. 代码片段     th:fragment  th:insert

11. 在Vue中使用 Thymeleaf 


一、MVC概念

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写

  • Model(模型)表示应用程序核心(用来存储数据供视图层渲染)。
  • View(视图)显示数据,而本篇使用的就是Thymeleaf作为视图。
  • Controller(控制器)处理输入请求,将模型和视图分离。

务必理解:三层架构。Thymeleaf 在表述层内,对视图层进行封装。目的是为了让各个组件可以单独维护,解耦合,动态的向网页传递数据。 

二、Thymeleaf

Thymeleaf 3 ten-minute migration guide - Thymeleaf

作用:它的主要作用是在静态页面上渲染显示动态数据,简化视图层(MVC)操作。

1. HelloThymeleaf、逻辑视图

逻辑视图:

视图前缀 + 逻辑视图 + 视图后缀 ==> 物理视图

1、导入Jar包,建立依赖关系

2、创建视图基础类 (笔记复制即可)

重点关注前缀后缀设置,后期会使用框架替代该类。


//视图基础类 继承了HttpServlet, 本质还是一个Servlet
public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override//在初始化中 读取全局上下文参数
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀 (重要)
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀 (重要)
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    /**
     * 进行视图解析(渲染)的方法
     * @param templateName 逻辑视图
     * @param req 请求
     * @param resp 响应
     * @throws IOException
     */
    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

3、web.xml中通过全局初始化参数 ,配置视图前缀后缀

    <!--配置视图前缀、后缀-->
    <context-param>    <!--视图前缀-->
        <param-name>view-prefix</param-name> <!--name需要与ViewBaseServlet内保持一致-->
        <param-value>/pages/</param-value>
    </context-param>
    <context-param>     <!--视图后缀-->
        <param-name>view-suffix</param-name>
        <param-value>.html</param-value>
    </context-param>

4、创建HelloServlet 继承视图基础类,调用processTemplate()方法跳转访问的页面

processTemplate("逻辑视图",请求对象,响应对象);
底层为请求转发 (连接不会发生改变,可以访问WEB-INF) getRequestDispatcher("路径").forward()

public class Thy01HelloServlet extends ViewBaseServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("------ Thy01HelloServlet ------");
        //1.解决乱码
        request.setCharacterEncoding("utf-8");
        //调用业务层方法...
        
        //请求域传递参数,修改msg所渲染的值
        request.setAttribute("msg","一行白鹭上青天"); 

        //2.processTemplate("逻辑视图",请求对象,响应对象),底层是请求转发
        processTemplate("hello",request,response);
    }

5、在对应的页面中 html 标签内引入命名空间,使用 thymeaf 将动态数据渲染到静态页面上

hello.html
<!DOCTYPE html>
<!--1、html标签内加入 Thymeleaf 名称空间的声明-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>hello</title>
</head>
<body>
<h1>Hello</h1>

<!--2、在页面中使用 thymeaf 将动态数据渲染到静态页面上-->
<h1 th:text="${msg}">等待渲染</h1>  <br>

</body>
index首页
<body>
<a href="thy01">HelloThymeleaf</a> <br>

</body>

 

 注:1.如果此处500报错,前缀 后缀没有问题,就是逻辑视图问题,请检查web.xml配置文件与视             图基础类对象中的参数名是否匹配前后缀与processTemplate()传入的参数是否正确
        2.如果出现其他未知问题,可能是Toncat、Jar包、jdk版本兼容性问题。

2. th表达式基本语法   th:?="? {?}" 

1、th名称空间:

  • 不经过服务器解析,直接用浏览器打开HTML文件,看到的是『标签体原始值』
  • 经过服务器解析, Thymeleaf引擎根据th:text属性指定的 标签体新值 去替换 标签体原始值

2、修改标签文本值:th:text="${key}"  

<p th:text="${msg}">等待渲染</p>

3、修改标签属性值:th:属性名="${key}" 

<input type="text" th:value="${value}">

4、解析url

   4.1. 动态获取应用名:@{/}:

<span th:text="@{/}">应用名(上下文路径)</span>

   4.2. 附加参数发起请求:th:href= "${/资源名(参数名=参数值,.....)}"

<a th:href="@{/thy03(uname='张三',pwd='123456',hobby='swim',hobby='read')}">

   4.3. 携带动态数据作为参数发起请求: th:href="${/资源名(参数名=${key},.....)}"

<a th:href="@{/thy03(uname='张三',pwd='123456',message=${msg})}">

3. 在Thymeleaf中操作域对象

在Servlet中将数据存储到域对象中,在Thymeleaf 前端页面中取出域对象中的数据并展示

processTemplate 底层是请求转发。(连接不会发生改变,可以访问WEB-INF)

Servlet  (继承了视图基础类)
//请求域传递参数,修改msg所渲染的值
request.setAttribute("msg","一行白鹭上青天"); 

//processTemplate("逻辑视图",请求对象,响应对象),底层是请求转发
processTemplate("hello",request,response);
hello.html
<!--在页面中使用 thymeaf 将动态数据渲染到静态页面上-->
<h1 th:text="${msg}">等待渲染</h1>  <br>

域对象在Thymeleaf中的使用

域对象是在服务器中有一定作用域范围的对象,在这个范围内的所有动态资源都能够共享域对象中保存的数据

① 请求域

在请求转发的场景下,我们可以借助HttpServletRequest对象内部给我们提供的存储空间,帮助我们携带数据,把数据发送给转发的目标资源 (request.setAttribute("msg","一行白鹭上青天"))

② 会话域(后面学)
会话域的范围是一次会话

 

 ③ 应用域(后面学)
可用于统计在线人数

4. 设置首页(index.html)的thymeleaf的渲染

访问首页时,需要展示项目数据,而数据一般是存在于数据库的因此在访问前要先执行Servlet 获取数据,再将数据渲染到首页上

<servlet>
    <servlet-name>IndexServlet</servlet-name>
    <servlet-class>com.atguigu.servlet.IndexServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>IndexServlet</servlet-name>
    服务器启动会自动加载 当前项目下index.html 然后直接访问 IndexServlet
    <url-pattern>/index.html</url-pattern>
</servlet-mapping>

5. 获取请求参数  ${param.参数名}

根据参数名 获取对应参数值 (ker -> value)

getParameter.thml
<!--获取请求参数-->
<!--获取从Index传来的参数-->
<p><span>获取请求参数1</span> <span th:text="${param.uname}"></span></p>      
<p><span>获取请求参数2</span> <span th:text="${param.pwd}"></span></p>

<!--获取当前名字的所有参数,-->
<p><span>获取请求参数3</span> <span th:text="${param.hobby}"></span></p>   
   
<!--获取当前名字参数的第[0]位,-->
<p><span>获取请求参数4</span> <span th:text="${param.hobby[0]}"></span></p>   

url:
http://localhost:8080/day09Thymeleaf/thy05?uname=zs&pwd=123&hobby=swim&hobby=read&hobby=run
index.html
<!--转发并传入参数,发送到hty05,再跳转到getParameter-->
<a th:href="@{/thy05(uname='zs',pwd=123,hobby='swim',hobby='read',hobby='run')}">访问Thy05</a> <br>
public class Thy05ParameterServlet extends ViewBaseServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("------ Thy05 ------");


        //注意此处,hello02为逻辑视图,  视图前缀 + 逻辑视图 + 视图后缀 ==> 物理视图
        // 转发到getParameter.thml
        processTemplate("getParameter", request, response);
    }

6. 内置对象   th:?="${#?.?}"

内置对象:在Thymeleaf的表达式中可以直接使用的对象

基本内置对象:

<!--当前地区-->
<p><span>内置对象1:</span> <span th:text="${#locale.country}"></span></p>   
<!--获取请求域数据1-->
<p><span>内置对象2:</span> <span th:text="${msg}"></span></p>       
<!--获取请求域数据2-->
<p><span>内置对象3:</span> <span th:text="${#request.getAttribute('msg')}"></span></p> 
<!--获取上下文对象1-->
<p><span>内置对象3:</span> <span th:text="${#request.getServletContext()}"></span></p> 
<!--获取上下文对象2-->  
<p><span>内置对象4:</span> <span th:text="${#servletContext}"></span></p>    
 <!--获取上下文路径(应用名)-->
<p><span>内置对象3:</span> <span th:text="${#request.getContextPath()}"></span></p>    
<!-- request等同于HttpServletRequest ,它有什么方法就可以用什么方法-->

公共内置对象:

request:<span th:text="${#request.getAttribute('msg')}"></span>
lists:     <span th:text="${#lists.size(list1)}"></span>
strings:<span th:text="${#strings.indexOf(msg,'e')}"></span>

<p><span>公共的内置对象list1 </span> <span th:text="${#lists.isEmpty(list1)}"></span></p>
<p><span>公共的内置对象list2 </span> <span th:text="${#lists.isEmpty(list2)}"></span></p>  <!--可以调用List方法-->
<p><span>公共的内置对象list2 </span> <span th:text="${#lists.size(list1)}"></span></p>
<p><span>公共的内置对象string </span> <span th:text="${#strings.indexOf(msg,'黄')}"></span></p> <!--同理-->

7. 对象图导航语言(OGNL)   th:text="${list[1].obj.name}"

OGNL:Object-Graph Navigation Language对象-图 导航语言

从根对象触发,通过特定的语法,逐层访问对象的各种属性。  快速访问对象属性值。

底层调用了对象的 get()方法 

${对象名.属性名}
${listkey[下标].属性名}
${map.key.属性名}
${map[map集合的key].属性名}

<body>
    <h1>简单对象</h1>
    <p><span>获取对象的属性值:</span> <span th:text="${p.name}"></span></p>
    <p><span>获取对象的属性值:</span> <span th:text="${p.sex}"></span></p>
    <p><span>获取对象的属性值:</span> <span th:text="${p.a}"></span></p>
    <hr>
    <h1>复杂对象</h1>
    <p>复杂对象 <span th:text="${p2}"></span></p>
    <p>复杂对象 <span th:text="${p2.name}"></span></p>
    <p>复杂对象 <span th:text="${p2.computer}"></span></p>
    <p>复杂对象 <span th:text="${p2.computer.cname}"></span></p>

    <hr>
    <h1>集合对象</h1>
    <p>集合对象 <span th:text="${list}"></span></p>
    <p>集合对象 <span th:text="${list[0]}"></span></p>
    <p>集合对象 <span th:text="${list[1].name}"></span></p>
    <p>集合对象 <span th:text="${list[1].computer}"></span></p>
    <p>集合对象 <span th:text="${list[1].computer.cprice}"></span></p>

    <p>集合对象?? <span th:text="${list[0]}"></span></p>

    <hr>
    <h1>Map</h1>
    <p>Map <span th:text="${map}"></span></p>
    <p>Map <span th:text="${map.p1}"></span></p>
    <p>Map <span th:text="${map['p-2']}"></span></p>


    <!--如果key是特殊字符则需要使用 中括号包裹-->
    <p>Map <span th:text="${map['p-2'].sex}"></span></p>
    <p>Map <span th:text="${map.p-2}"></span></p>

</body>
public class Thy06ObjectServlet extends ViewBaseServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("------ Thy06Object ------");
        //1.解决乱码
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //创建Person 对象
        Person p1 = new Person("李白", 20, "男");
        request.setAttribute("p", p1);

        //复杂对象
        Computer c1 = new Computer("联想", 6666.6, "黑色");
        Person p2 = new Person("安琪拉", 20, "女", c1);

        request.setAttribute("p2", p2);

        //复杂对象2 List
        ArrayList<Person> list = new ArrayList<>();
        Computer c3 = new Computer("华硕", 9999.9, "金色");
        Person p3 = new Person("伊娃", 200, "女", c3);
        list.add(p2);
        list.add(p3);

        request.setAttribute("list", list);

        //复杂对象3 Map
        Map<String,Person> map = new HashMap<>();

        Computer c4 = new Computer("华硕", 9999.9, "金色");
        Person p4 = new Person("妲己", 300, "女", c3);

        map.put("p1", p3);//"伊娃",
        map.put("p-2", p4);//"妲己",
        request.setAttribute("map", map);

        processTemplate("object",request,response);
    }

8. 分支 (th:if、th:switch | th:case)

 ① if 和 unless 、not

if配合not关键词和unless配合原表达式效果是一样的,看自己的喜好。

<body>
<!-- if true可进 -->
<div th:if="${#lists.isEmpty(list1)}">
    无数据 th:if
</div>
<!-- unless false可进 -->
<div th:unless="${#lists.isEmpty(list1)}">
    有数据 th:unless
</div>
<!-- not 对后续结果取反 -->
<div th:if="${not #lists.isEmpty(list1)}">
    有数据 th:if="${not
</div>

<span th:if="${1==2}">th:if="${1==2}"</span> <br>   <!--不显示-->
<span th:if="${1!=2}">th:if="${1!=2}"</span> <br>   <!--显示-->
<span th:if="${not(1==2)}">th:if="${not 1==2}"</span> <br>  <!--显示-->
<span th:unless="${1==2}">th:unless="${1==2}"</span> <br>   <!--显示-->

② switch

<div th:switch="${list1[0].cname}">
    <span th:case="联想">联想666</span>
    <span th:case="华硕">华硕666</span>
    <span th:case="宏碁">宏碁666</span>
</div>

9. 迭代    th:each="e : ${ list }"

<tr th:each="e :${list1}">                 e:集合中的元素
<tr th:each="e,status :${list1}">      status:在进行遍历时的状态信息

<h3>list集合遍历</h3>
<table width="400px" border="1">
    <tr>
        <td>品牌</td>
        <td>价格</td>
        <td>颜色</td>
    </tr>
    <tr th:each="e : ${list1}">   <!--each迭代-->
        <td th:text="${e.cname}"></td>
        <td th:text="${e.cprice}"></td>
        <td th:text="${e.color}"></td>
    </tr>
</table>
<h3>迭代状态 status</h3>
<table width="1000px" border="1">
    <tr>
        <td>品牌</td>
        <td>价格</td>
        <td>颜色</td>
        <td>下标</td>
        <td>第几个元素</td>
        <td>总数量</td>
        <td>当前元素</td>
        <td>奇数</td>
        <td>偶数</td>
        <td>是不是第一个</td>
        <td>是不是最后一个</td>
    </tr>
    <tr th:each="e,status : ${list1}">   <!--each迭代,status状态-->
        <td th:text="${e.cname}"></td>
        <td th:text="${e.cprice}"></td>
        <td th:text="${e.color}"></td>
        <td th:text="${status.index}"></td>
        <td th:text="${status.count}"></td>
        <td th:text="${status.current}"></td>
        <td th:text="${status.size}"></td>
        <td th:text="${status.odd}"></td>
        <td th:text="${status.even}"></td>
        <td th:text="${status.first}"></td>
        <td th:text="${status.last}"></td>
    </tr>
</table>

10. 代码片段     th:fragment  th:insert

th:fragment="片段名"   th:insert="逻辑视图::片段名"

作用:抽取各个页面的公共部分,解耦合
例如:

① 创建页面的公共代码片段

使用th:fragment来给这个片段命名:

<div th:fragment="header">
    <p>被抽取出来的头部内容</p>
</div>

② 在需要的页面中进行包含

语法效果特点
th:insert把目标的代码片段整个插入到当前标签内部它会保留页面自身的标签
th:replace用目标的代码替换当前标签它不会保留页面自身的标签
th:include把目标的代码片段去除最外层标签,然后再插入到当前标签内部(只替换内容)它会去掉片段外层标记,同时保留页面自身标记

代码:

创建页面的公共代码片段
<div th:fragment="header1" id="baseDiv1">
    <p>头部样式1</p>
</div>

<div th:fragment="header2" id="baseDiv2">
    <p>头部样式2</p>
</div>

使用: th:操作="代码片段的逻辑视图::代码片段的名字"

使用公共代码片段
<div th:include="temp/BaseHtml::header1" id="div1">
    <p>标题头</p>
</div>

11. 在Vue中使用 Thymeleaf 

"data":{
        "key" :"[ [ ${thymeleaf} ] ]"
}

    "el":"#content",
    "data":{
      //服务器端渲染 vue 渲染  vue 覆盖 服务器端渲染的值
      "errorMsg": "[[${msg==null?'请输入用户名密码':msg}]]", //数据回显,获取请求域内异常信息
      "username": "[[${param.uname}]]",   //注册失败获取页面参数: 之前填入的数据
      "password": "[[${param.upwd}]]"
    },

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值