Spring Boot 2.0 读书笔记_05:Beetl

本文深入探讨Beetl模板引擎在SpringBoot项目中的集成与使用,包括依赖引入、配置详解、基础语法介绍及安全输出策略,适用于后端开发者提升Web开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3. Beetl

写在开头,Beetl是由《Spring Boot 2精髓》作者所开发并维护的后端模板引擎,主要用于渲染视图模板。

关于模板引擎,博主了解过的主要是JSP 和 FreeMarker,视图渲染技术的了解并不多。

这里谈一下自己对于Web开发的理解:基于现在的Web开发环境,前后端分离开发的思想,相对后端来讲,很多时候是面向接口编程,拿当下火热的前端渐进式组件框架Vue来讲,于后端的交互无异于请求数据并返回,前端框架进行数据解析和视图渲染,后端进行接口数据的获取以及返回。

借此阅读技术书籍以及结合案例Demo的机会,来比较系统的了解一下这个后端模板引擎:Beetl

关于模板介绍,可以移步:http://ibeetl.com/ ,这里就不赘述了,直接上手实操。

  • 依赖引入
    在Spring Boot中,beetl-framework-starter 将自动配置以 btl 结尾的所有视图,将自动使用 Beetl 渲染响应的 resources/templates 目录下的视图文件

      <dependency>
      	<groupId>com.ibeetl</groupId>
      	<artifactId>beetl-framework-starter</artifactId>
      	<version>1.1.57.RELEASE</version>
      </dependency>
    
  • 设置定界符和占位符
    记得当初使用JSP、ftl在页面上写脚本的时候,定界符和占位符的概念就了解过了。
    有图有真相:

    JavaWeb时期用过的JSP
    在这里插入图片描述

    SSM时期用过的FreeMarker
    在这里插入图片描述

    默认配置:
    <% %> 作为定界符,${ }作为占位符

    可以通过配置文件来设置定界符和占位符,需要在 resources 目录下创建 beetl.properties 文件
    案例中给出了一种配置方式:占位符使用:’${’ 和 ‘}’,定界符使用:’@’ 和 ‘回车换行’。

      DELIMITER_PLACEHOLDER_START=${
      DELIMITER_PLACEHOLDER_END=}
      DELIMITER_STATEMENT_START=@
      DELIMITER_STATEMENT_END=
    
  • 配置Beetl
    Beetl为了提高渲染性能,会在模板渲染之后对语法解析结果进行缓存,每次渲染前都会对模板文件进行更新监测,因此这个地方会存在一次I/O操作,线上系统可以取消这个更新监测。application.properties文件中添加:

      beetl-beetlsql.dev = false 
    

    关于Web项目中 target目录 没有同步更新最新目录文件以及资源的问题:IDEA不像Eclipse会自动将新保存的文件或目录及其他资源更新到target目录中,必须在pom.xml中设置

      <build>    
      <resources>
          <resource>
              <directory>src/main/java</directory>
              <includes>
                  <include>**/*.*</include>
              </includes>
          </resource>
          <resource>
              <directory>src/main/resources</directory>
              <includes>
                  <include>**/*.*</include>
              </includes>
          </resource>
      </resources>
      </build>
    

    接下来,maven clean、build就可以了,这个问题和mapper.xml文件无法加载的问题一致,原因都是在resource文件夹不被加入build行列。

  • GroupTemplate
    Beetl的核心是GroupTemplate,是一个重量级对象,实际使用的时候建议使用单例模式创建,创建GroupTemplate需要两个参数,一个是模板资源加载器,一个是配置类。

    模板资源加载器Beetl内置了6种,分别是:

    模板资源加载器说明
    StringTemplateResourceLoader字符串模板加载器,用于加载字符串模板,如本例所示
    FileResourceLoader文件模板加载器,需要一个根目录作为参数构造,传入getTemplate方法的String是模板文件相对于Root目录的相对路径
    ClasspathResourceLoader文件模板加载器,模板文件位于Classpath里
    WebAppResourceLoader用于webapp集成,假定模板根目录就是WebRoot目录,参考web集成章
    MapResourceLoader可以动态存入模板
    CompositeResourceLoader混合使用多种加载方式

    GroupTemplate创建过程:

      // 模板资源加载器
      StringTemplateResourceLoader resourceLoader = new StringTemplateResourceLoader();
      // 配置类
      Configuration cfg = Configuration.defaultConfiguration();
      // 单例模式创建
      GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
    

    配置类:通过自动注入的方式注入GroupTemplate,@PostConstruct作用于Config方法上,会在Spring启动阶段调用此方法,完成对GroupTemplate的拓展。

      @Configuration
      public class BeetlExtConfig {
      	@Autowired
      	GroupTemplate groupTemplate;
    
      	@Autowired
      	ApplicationContext applicationContext;
    
      	@PostConstruct
      	public void config() {
      			
      	}
      }
    

以下内容为Beetl的基础语法相关内容,该部分内容会进行提纲式的笔记整理,不会详细讲述语法相关内容。

  • 变量

    • 全局变量:在模板或者子模板中使用
      • request内置对象通过attribute在模板中均可直接通过name来引用。
      • Session提供了Session会话,这里指的是HTTPSession。
      • parameter,读取用户提交参数。
      • ctxPath,Web应用中的ContextPath。在Spring Boot中,应用默认是 “/”。
      • servlet,WebVariable的实例,包含 HTTPSession、HTTPServletRequest、HTTPServletResponse三个属性。模板中可以通过 request、response、session 来引用。
      • 所有groupTemplate的共享变量
    • 局部变量:只能在当前模板中使用
      • 变量类型同JavaScript类型一致,在Beetl中,任何与高精度数据进行算数运算后的结果会转换为BIgDecimal类型,对应Java中的BigDecimal类型。
    • 共享变量
      • 类似全局变量,可以在任何模板中使用,需要通过groupTemplate的API进行添加。

          定义:在注入GroupTemplate对象的配置类中,config方法中进行设置:
          groupTemplate.getSharedVars().put("key", value);
          使用:在任意末班中,通过占位符进行使用:
          ${key}
        
    • 模板变量
      • 定义:变量的内容是模板对应的输出

          @var a = 1 ; 
          @var template = { 
          <span>${a}</span〉
          @}
          输出:${template}
        

        template是个变量,内容位于${ }中,内容是1。
        模板变量可以用在后面的任何地方,Beetl使用模板变量来完成继承布局方式。

  • 表达式

    • 算数表达式
      • 支持 +、-、*、/、% 等表达式,变量类型与相应的Java类型一致。

      • 需要用到高精度数代替Double时,需要在数字后面添加 “h”,对应Java中BigDecimal类型。

          例如:@var a = 123.25785236h;
        
      • 为保证浮点计算准确,含有高精度数表达式的计算过程全部按照高精度进行计算

    • 逻辑表达式
      • 支持 >、<、==、!=、>=、<=、!、&&、||、?等条件表达式

      • 三元表达式只考虑true情况时,可以进行简化

          例如:
          $var a = 1;
          ${a == 1? "bingo" : ""}
          ${a == 1? "bingo"}
          上述两行代码效果一致,在简化的三元表达式中,false情况时,自动赋值为null。
          Beetl占位符对null值不做输出。
        
  • 控制语句

    • 循环语句
      • for…in [elsefor]、for(exp; exp; exp)、while(exp)
        • for…in 循环中可以得到循环的上下文信息,会自动创建一个变量名+LP后缀的变量,提供循环的上下文信息

            例如:
            @for(user in userList!){
              <span>${userLP.index}</span>
            @}
          

          上面的例子中在表达式:user in userList 后添加了 “!”,来进行安全输出。即若user不存在,或者为空,不要报错,不进入循环体。此外上下文对象userLP还有其他相关信息:

    属性/方法说明
    userLP.index当前索引值,从1开始
    userLP.size集合长度
    userLP.first是否是第一个
    userLP.last是否是最后一个
    userLP.even索引是否是偶数
    userLP.odd索引是奇数
    • 条件语句
      • if…else [else if]
      • 加强版switch case:select-case
        • 允许case中使用逻辑表达式

        • 不需要每个case都break,默认遇到符合条件的case执行后退出

          <%
            var b = 1;
            select {
             case b < 1, b > 10:
               print("out of range");
             default:
               print("error") 
            }
          %>
          
    • try…catch
      • 捕获模板异常

          <%
          try{
            callOtherSystemView();
          } catch (error) {
            print(err.message);
          }
          %>
        
  • 函数调用

    常用函数说明举例
    print/pringln输出对象,若对象为空,则不输出
    has判断是否具有这个全局变量if(has(userList)){…}
    isEmpty判断变量或者表达式是否为空
    debug在控制台打印变量或者表达式,附带所在文件模板路径信息
    date日期函数,获得当前日期
    trim截取一个日期或者数字类型并返回字符串trim(126.18, 1) -> 126.18
    trim(date(),‘yyyy’) -> 2018
    parseInt将字符串或者number转换为对应类型parseLong、parseDouble
    global返回全局变量值,参数是字符串var user = global(“user_” + i)
    cookie返回指定的cookie对象var userCookie = cookie(“user”)
    strutil.*字符串系列函数详情参考Beetl使用手册
    array.*集合相关函数
    shiro.*安全框架shiro的相关方法封装shiroExt类中有说明,并非内置函数
    spring.*Spring框架中可以使用的函数spel表达式
    reg.*正则表达式相关函数

    这里说一下用到过的Shiro.hasPermission()方法吧,首先Shiro安全框架是集成进项目中来的,并配置了ShiroConfig配置类。权限控制的方式上采用基于URL的形式进行控制,在视图层,使用Beetl提供的ShiroExt中的hasPermission方法,对模板中的URL字符串进行权限认证,ShiroExt在这一过程中只是做了封装操作,获取到权限URL参数、和当前Subject,并将参数交给Shiro框架进行处理。

      /**
      * 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用
      *
      * @param permission 权限名
      * @return 拥有权限:true,否则false
      */
      public boolean hasPermission(String permission) {
      	return getSubject() != null && permission != null
      	&& permission.length() > 0
      	&& getSubject().isPermitted(permission);
      }
    
      /**
      * 获取当前 Subject
      *
      * @return Subject
      */
      protected static Subject getSubject() {
      	return SecurityUtils.getSubject();
      }
    
      // isPermitted是接口Subject下的一个实现方法
      boolean isPermitted(String permission);
    
      // 视图层使用
      @if(shiro.hasPermission("/cta/add")){
      	<#button name="添加" icon="fa-plus" clickFun="Cta.openAddCta()"/>
      @}
    
  • 格式化函数
    允许在占位符输出的时候指定格式化函数来格式化输出
    格式化格式:${exp, formatName=“可选参数”}

  • 以Java方式进行调用
    可以在模板中以Java方式调用表达式,使用时必须在表达式前用"@"符号标识

    • 定界符中使用

      <%
      	var size = @a.size();
      %>
      
    • 占位符中使用

      ${ @user.getUserName() }
      
    • 需要注意的是:

      • 对于直接Java调用,GroupTemplate是可以配置进制此功能的。

      • 可以通过安全管理器配置Beetl不允许调用那些类。默认java.lang.Runtime 和 java.lang.Process不允许被调用。

      • 按照Java规范书写类名、方法名以及属性名

      • 内部类访问机制:outerClass$innerClass

      • 表达式是Java风格,参数依然是Beetl表达式。

          ${@user.sayHello(user.name)}
          user.sayHello 是Java调用
          user.name 依然是Beetl表达式
        
  • 标签函数

    • 功能等同于 jsp tag

    • layout:布局标签函数

        @layout("/inc/layout.html", {title:'主题'}){
          <p>Hello Beetl</p>
        @}
      

      layout标签会把标签体{ }部分内容渲染出来之后,传给layout指定的模板页面,默认接收变量名为layoutContent,同时携带title变量进行传递。

        layout.html
        <title>${title}</title>
        <div>
          ${layoutContent}
        </div>
      
    • include:包含标签函数

      @include("/inc/header.html", {title:"page header"}){...}
      <div>
      // main content
      </div>
      @include("/inc/footer.html"){}
      

      include标签第一个参数是公共模板的路径,其后可以接受一个map参数,map中的,每一项值都会传递给子模板作为子模板的全局变量。

  • 安全输出
    Beetl在变量表达式后面使用符号 “!” 来提醒Beetl此变量可能不存在,表达式将返回 “!” 后的表达式值,若没有表达式,则返回null。

      @ var user = null;
      ${user.name!"无此人姓名信息"}
    

    当user为null时,或者user.name为null时,返回 “无此人姓名信息”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小透明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值