• SpringBootMVC+thymeleaf模板初探


      我们已经学习了SpringBoo的基础概念和连接数据库。那么我们怎么利用SpringBoot实现我们的MVC架构,完成web站点的编码?今天就要介绍SpringMVC登场。

    SpringMVC不是SpringBoot的一部分,但是SpringBoot让SpringMVC的编码更加快捷和方便。这中间的关系同SpringBoot与千千万万其他的Spring程序一样。
    我们先来看SpringBoot的概念
    Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中。正式名称“ Spring Web MVC”来自其源模块的名称,但更通常称为“ Spring MVC”。
    概念很绕,也没有说个所以然,所以我们通过上手实战来进一步了解:
    1. 首先我们要有一个SpingBoot的项目.引入web的Start配置。
    2. 接下来我们就要创建一个Controller文件了,同asp.netMvc一样:从代码整洁角度上来说,应该按照约定将Contoller文件创建到专门的Contoller文件夹中,并以Conttoller结尾命名。只要我们给一个类打上@Controller的标志,Spring就会认为这是一个控制器并初始化它。
    @Controller
    public class IndexController {
    }
    

         3.  紧接着我们创建具体的控制器方法,并打上@RequestMapping的标志路由地址。

    @Controller
    public class IndexController {
        @RequestMapping("/")
        public  String index(Model model){
            System.out.println("控制器方法被调用");
            return "index";
        }
    }
    

      4. 创建对应的index页面

      5. 编译运行。

    一个简单的mvc页面已经被创建并运行了,虽然目前什么也没有。但是我们已经得到一个极其简单的、空的mvc程序了。
    为了把我们的例子显得更加正式一点,更加接近真实的程序,我们进一步引入一个帮手:Thymeleaf模板。
    我们先来看看Thymeleaf的概念。
    Thymeleaf是面向 Web 和独立环境的现代服务器端 Java 模板 引 擎,能够处理 HTML 、XML 、JavaScript 、 css 甚至纯文本,可 以作为 MVC Web 应用层的 View 层显示数据。Spring Boot 建议使用 HTtml 来完成动态页面。 Spring Boot 提供了大量的模板 引 擎, 包括 Thymeleaf、 FreeMarker 、 Velocity 等。Spring Boot 官方推荐使用 Thymeleaf 模板引 擎来完成动态页面,并且为 Thymeleaf 提供 了完美的 SpringMVC 的支持, Thymeleaf模板 引擎可以支持纯 HTML 浏览器展现 (模板表达式在脱离运行环境下不污染 HTML 结构)。
    Thymeleaf它是一个模板引擎,和vue等前端框架不是一回事,也不冲突。完全可以将Thymeleaf和Vue并存,甚至抛开Thymeleaf,完全采用html+前端框架的Rest前后端分离。
    在正式把Thymeleaf加入到SpringBoot之前,我们先大致了解一下Thymeleaf的语法。
    我们看一段html
    <input type="text" name="username" value="fkjava" th:value="${ user.username }" />
    

      这一段的意思是:Thymeleaf模板会把存储在它上下文中的user对象的username作为value赋值给name为username的text控件(如果user对象的username有数据,否则显示默认的fkjava)。

    再看一个字符串拼接操作
    <span th:text="'Welcome to fkit, '+ ${user.name} +'!'">
    

      再看一个静态资源引入的例子:

    <link rel="stylesheet" th:href="@{bootstrap/dist/css/bootstrap.css}"/>
    <link rel="stylesheet" th:href="@{bootstrap/dist/css/bootstrap-theme.css}"/>
    <script type="text/javascript" th:src="@{jquery/dist/jquery.js}"></script>
    <script type="text/javascript" th:src="@{bootstrap/dist/js/bootstrap.js}"></script>

      th:href还可以带参数

    代码分析
    1.最终解析的href为:    
      /seconddemo/    
      /seconddemo/usethymeleaf?name=Dear 相对路径,带一个参数   
      /seconddemo/usethymeleaf?name=Dear&alis=Dear 相对路径,带多个参数
      /seconddemo/usethymeleaf?name=Dear&alis=Dear 相对路径,带多个参数
      /seconddemo/usethymeleaf/Dear 相对路径,替换URL一个变量
      /seconddemo/usethymeleaf/Dear/Dear 相对路径,替换URL多个变量
    2.URL最后的(name=${name})表示将括号内的内容作为URL参数处理,该语法避免使用字符串拼接,大大提高了可读性
    3.@{/usethymeleaf}是Context相关的相对路径,在渲染时会自动添加上当前Web应用的Context名字,假设context名字为seconddemo,那么结果应该是/seconddemo/usethymeleaf,即URL中以”/“开头的路径(比如/usethymeleaf将会加上服务器地址和域名和应用cotextpath,形成完整的URL。
    4.th:href属性修饰符:它将计算并替换使用href链接URL 值,并放入的href属性中。
    5.th:href中可以直接使用静态地址

      Thymeleaf模板的语法以th开头。${} 表示要处理的数据。

    具体可以看下表
    th:with 赋值的一种,将prodStat.cout的值%2之后判断的布尔值赋值给isEvents,并将isEvents加入到Thymeleaf的上下文。
    th:each 循环users的值,并将循环结果赋值到user变量中。
    th:if 满足则显示,th:unless 不满足则显示
    $表达式只能写在 th 标签内部,否则不会生效。
    Thymeleaf还有很多功能,如内置对象:#dates 日期格式化内置对象等等。具体可以看看:https://fanlychie.github.io/post/thymeleaf.html
     
    语法大致了解之后,我们来看看如何将Thymeleaf引入SpringBoot项目中。
    1. 修改pom.xml
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

        2. Html页面上增加Thymeleaf开关。

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">

      

      我们重新回到SpringMVC,并尝试将它和Thymeleaf模板引擎结合起来。我们看之前的入门代码

    @Controller
    public class IndexController {
        @RequestMapping("/")
        public  String index(Model model){
            System.out.println("控制器方法被调用");
            return "index2";
        }
    }

      有几个关键点值得注意:

    @Controller标签 表示这是一个控制器,并且最终控制器会将信息转发到return的页面,如本例中,index控制器运行完毕之后,最后会转跳到index2.html
    @RequestMapping和路由相关,SpringMVC的路由通过@RequestMapping标签来控制。/代表根目录默认地址,如localhost:8080,如果我们把标签改成@RequestMapping(/test),那么就必须访问localhost:8080/test才可以访问到该控制器。
     
    那么SpringMVC如何实现前后台值的传递呢?
    Model是每次请求中都存在的默认参数,利用其addAttribute()方法即可将服务器的值传递到页面中。这是一种前后台传值的办法。类似的还有很多如:
    @RequestMapping("/iftest")
    public String iftest(WebRequest webRequest){
        webRequest.setAttribute("username","fkit",webRequest.SCOPE_REQUEST);
        webRequest.setAttribute("age",21,webRequest.SCOPE_REQUEST);
        webRequest.setAttribute("role","admin",webRequest.SCOPE_REQUEST);
        return  "success2";
    }
    
    @RequestMapping("/eachtest")
    public  String eachtest(WebRequest webRequest){
        List<Book> books = new ArrayList<>();
        books.add(new Book(1,"Book1","1.jpg","wenpeng",108.00));
        books.add(new Book(2,"Book2","2.jpg","wenpeng",18.00));
        books.add(new Book(3,"Book3","3.jpg","wenpeng",128.00));
        books.add(new Book(4,"Book4","4.jpg","wenpeng",118.00));
        books.add(new Book(5,"Book5","5.jpg","wenpeng",8.00));
        webRequest.setAttribute("books",books,webRequest.SCOPE_REQUEST);
        return "success3";
    }

      WebRequst通过setAttribute封装信息到username,age,甚至是books这种类的结合变量中。前台就可以接受并处理。

      sucess2.html
    <div class="container">
        <div class="row">
            <div class="col-md-4">
                <p>th:if中条件成立时才显示结果</p><br/>
                <span th:if="${username != null}">username 不为空</span><br/>
                <span th:if="${age != null}">age不为空</span><br/>
                <p>th:unless与th:if相反,只有条件不成立,才会显示</p><br/>
                <span th:unless="${address != null}">address为空</span><br/>
                <p>th:swich,默认选中为*</p><br/>
                <div th:switch="${role}">
                    <p th:case="'admin'">管理员</p>
                    <p th:case="'guest'">来宾</p>
                    <p th:case="'*'">其他</p>
                </div>
            </div>
        </div>
    </div>

      success3.html

    <div class="table table-responsive">
        <table class="table table-bordered table-hover">
            <thead>
                <th class="text-center">封面</th>
                <th class="text-center">书名</th>
                <th class="text-center">作者</th>
                <th class="text-center">价格</th>
            </thead>
            <tbody class="text-center">
                <tr th:each="book:${books}">
                    <td><img src="img/1.jpg" th:src="@{'img/'+${book.image}}" height="60"></td>
                    <td th:id="${book.id}" th:text="${book.title}" >书名</td>
                    <td th:id="${book.id+'name'}" th:text="${book.author}">作者</td>
                    <td th:text="${book.price}">价格</td>
                </tr>
            </tbody>
        </table>
    </div>

      再譬如

    @RequestMapping("/regexptest")
    public  String regexptest(HttpServletRequest request,
                              HttpSession session){
        request.setAttribute("book","Spring boot 教材");
        session.setAttribute("school","中地数码");
        request.getServletContext().setAttribute("name","Thymeleaf 模板引擎");
        return "success1";
    }

      通过HttpServletRequest ,HttpSession 等封装消息,在前台使用。

      succes1
    <div class="container">
        <div class="row">
            <div class="col-md-4">
                <p>${param.x}将返回一个名为x的请求参数</p>
                访问页面传递的参数:<span th:text="${param.loginName[0]}">登录名</span>
                &nbsp;<span th:text="${param.password[0]}">密码</span>
                <p>${x}将返回存储在Thymeleaf上下文中的变量x或作为请求Request作用范围域中的属性</p>
                访问request作用域中的变量:<span th:text="${book}">图书信息</span>
                <p>$ {session.x }将返回一个名为 x 的会话 HttpSession作用范围域中的属性。</p>
                访问 sessioni 作用范围域中的变量:<span th:text="${ session .school}">培训中心</span>
                <p>${app lication.xi 将返回一个名为 x 的全局 ServletContext 上下文作用范围域中的属性。</p>
                访问 application 作用范围城中的变量:<span th:text="${application.name}">动态页面模板</span><br/>
            </div>
        </div>
    </div>

      再比如

    @PostMapping("login")
    public ModelAndView login(@RequestParam("loginName") String loginName,
                              @RequestParam("password") String password,
                              ModelAndView mv)
    {
        System.out.println("登录验证后台方法被调用");
        System.out.println("登录名:"+loginName+"密码:"+password);
        mv.setViewName("redirect:/main");
        return mv;
    }

      这个地方肯能有人要问了,怎么一会postMapping一会requestmapping呢?

    其实不止有@PostMapping,还有@GetMapping,@PutMapping、@DeleteMapping、@PatchMapping等等。但是他们都可以通过@RequestMapping(method=RequestMethod)用@RequestMapping代替。如@GetMapping等于@RequestMapping(method = RequestMethod.GET)
     
      前台页面
    <div class="panel panel-primary">
        <div class="panel-heading">
            <h3 class="panel-title">Spring Boot thymeleaf 示例</h3>
        </div>
    </div>
    <div class="container">
        <div class="row">
            <div class="page-header">
                <h2>用户登录</h2>
                <form class="form-horizontal" action="login" method="post" id="loginform">
                    <div class="form-group">
                        <div class="input-group col-md-4">
                            <span class="input-group-addon">
                                <i class="glyphicon glyphicon-user"></i>
                            </span>
                            <input class="form-control" placeholder="用户名/邮箱" type="text" name="loginName" id="loginName"/>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="input-group col-md-4">
                            <span class="input-group-addon">
                                <i class="glyphicon glyphicon-lock"></i>
                            </span>
                            <input class="form-control" placeholder="密码" type="password" name="password" id="password"/>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-md-4">
                            <div class="btn-group btn-group-justified">
                                <div class="btn-group">
                                    <button type="button" class="btn btn-success" id="loginbtn">
                                        <span class="glyphicon glyphicon-log-in"></span>
                                        登录
                                    </button>
                                </div>
                                <div class="btn-group">
                                    <button type="button" class="btn btn-danger" id="regiserbtn">
                                        <span class="glyphicon glyphicon-edit"></span>
                                        注册
                                    </button>
                                </div>
                            </div>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>

      但是上面的方法都属于前后端严重耦合的,不适用于前后端分离的大趋势。我们想要做出标准的前后段分离的Rest请求怎么办?

    @RestController
    public class JsonController {
        @RequestMapping("/findBook")
        public Book findBook(@RequestBody Book book){
            System.out.println(book);
            book.setAuthor("文菜鸟");
            book.setImage("1.jpg");
            book.setPrice(58.0);
            return book;
        }
    }

      需要注意到@Controller,@RestController标注的区别。@Controller是传统控制器,turn返回的是具体的页面地址,通过路由转跳;@RestController是Rest风格的WebAPI,返回是json格式化的对象。

      前台页面
    <script type="text/javascript">
        $(document).ready(function () {
            $("#2").click(function () {
                findBook();
            });
        })
    
        function findBook() {
            $.ajax({
                url:"/findBook",
                dataType:"json",
                type:"post",
                contentType:"application/json",
                data:JSON.stringify({id:2,title:"Book2"}),
                async:true,
                success:function (data) {
                    console.log(data);
                    $("#2name").html(data.author)
                },
                error:function (er,a,b) {
                    alert("数据发送失败");
                }
            })
        }
    </script>

      总结一下,今天我们学习了如何使用SpringBoot搭建一个简单的MVC程序,以及如何配合thymeleaf模板工作,并且学习了SpringMVC前后端数据交互的方法。以及前后端分离情况下,如果使用WebAPI进行开发的模式。但是使用thymeleaf和SpringMVC真的是唯一的方式么?欢迎大家讨论。

  • 相关阅读:
    个人作业Week2-代码复审
    个人项目-数独
    个人作业-Week1
    第零次个人作业
    mysql统计某个指标之和大于指定值的记录
    Redis命令行查询缓存值
    Grep命令
    Log4j配置文件中指定日志路径
    Cadence OrCAD17.2禁止和启用start page的设置方法
    Linux内核实现透视---kthread_work
  • 原文地址:https://www.cnblogs.com/wenpeng/p/12176832.html
Copyright © 2020-2023  润新知