Springboot 集成Freemarker 自定义标签解决方案

soゝso 2019-06-21 10:04:46 459

  Freemarker  不是  Springboot  主推的,但是对于我们用习惯了  Freemarker  的同学,还是很喜欢  Freemarker  ,  Freemarker  的Macro,自定义标签都是非常好用的。

Springboot + Freemarker 配置

spring:
  mvc:
    view:
      prefix: /templates/
      suffix: .ftl
    #错误直接抛出异常
    #    throw-exception-if-no-handler-found: true
    favicon:
      enabled: false
  freemarker:
    cache: false
    request-context-attribute: request

Springboot 集成 Freemarker Maven配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId> 
</dependency>

定义Freemarker 标签注解

我们采用优雅的方式,用注解去实现。要实现一个标签只需要增加 @FreemarkerTag("tag name") 注解即可。tag name为自定义内容,根据您自己业务而定。

import org.springframework.stereotype.Component;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface FreemarkerTag {

    String value() default "";
}

定义Freemarker config

这个配置是把所有 @FreemarkerTag("tag name") 注解的对象加载到 Freemarker Configuration 中去,方便前端使用。

import freemarker.template.Configuration;
import freemarker.template.TemplateModelException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;

@Component
public class FreeMarkerConfig implements ApplicationContextAware {


    ApplicationContext applicationContext ;
    @Autowired
    Configuration configuration;

    
    /** 启动加载 **/
    @PostConstruct 
    public void setSharedVariable() throws TemplateModelException {
        

        /**
         * 根据注解获取Freemarker Tag对象
         */
        Map<String, Object> map = applicationContext.getBeansWithAnnotation(FreemarkerTag.class);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            configuration.setSharedVariable(entry.getKey(), entry.getValue());
        }

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}


定义Freemarker标签父类

1.此类采用 interface 实现,也可以采用 abstract 实现,为了用模版设计模式,定义业务骨架,委派变化业务给子类实现。

2.里面提供了 getLong、 getString、 getInt 等方法,您也可以自己实现Boolean等,按需求实现。这里是没办法把 SimpleScalar 直接转换为基础包装类。


import freemarker.core.Environment;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.template.*;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;



/**
 * Freemarker 标签父类
 *
 * 让子类实现后,利用模版设计模式,委派给子类
 *
 *
 */
@Component
public interface FreemarkerSupperTag extends TemplateDirectiveModel {

    // 此变量不可和其他变量冲突
    String DEFAULT_KEY_SO = "so";

    @Override
    default void execute(Environment environment,
                         Map params,
                            TemplateModel[] model,
                                TemplateDirectiveBody body)
                                    throws TemplateException, IOException {

        /**
         * 模版方法设计模式
         *
         * 此处这么写是把业务委派下去让子类实现,子类加工业务数据直接返回,这里包装返回到前端
         *
         * 有疑惑请断点此处和子类
         *
         *
         */
        Object paramWrap = getParms(params);


        /**
         *
         * 把得到的值 wrap 输出前端
         *
         *
         * freemarker.template.ObjectWrapper.DEFAULT_WRAPPER 已经过期
         * The legacy default object wrapper implementation, focusing on backward compatibility and out-of-the W3C DOM
         * wrapping box extra features. See {@link DefaultObjectWrapper} for more information.
         *
         * @deprecated Use {@link DefaultObjectWrapperBuilder#build()} instead; this instance isn't read-only and thus can't
         *             be trusted.
         */
        TemplateModel templateModel = new  BeansWrapperBuilder(Configuration.VERSION_2_3_28).build().wrap(paramWrap);


        /**
         * 输出,为了防止用户定义的变量 KEY 和 冲突,所以包起来赋值给自定义的变量给 so
         */
        environment.setVariable(DEFAULT_KEY_SO,templateModel);
        body.render(environment.getOut());
    }


    /**
     * 委派下去让子类实现,并且返回加工后的返回值
     * 可返回业务对象,或者集合
     *
     * @param params
     * @return
     */
    Object getParms(Map params);

    /**
     * 获取 long 参数
     * @param params   前端提交来的参数<Key,Value>
     * @param key      key
     * @return
     */
    default Long getLong(Map params,String key){
        return new Long(getString(params,key));
    }
    /**
     * 获取 String 参数
     * @param params   前端提交来的参数<Key,Value>
     * @param key      key
     * @return
     */
    default String getString(Map params,String key){
        Object element = params.get(key);
        String value;
        if(element instanceof SimpleScalar){
            value = ((SimpleScalar) element).getAsString();
        }else{
            value = element.toString();
        }
        return value;
    }
    /**
     * 获取 int 参数
     * @param params   前端提交来的参数<Key,Value>
     * @param key      key
     * @return
     */
    default Integer getInt(Map params,String key){
        return new Integer(getString(params,key));
    }
}

Freemarker Demo 标签

自定义标签,需要实现父类 FreemarkerTag 实现 getParms(Map params) 即可,params 为前端标签传参。

/**
 * 备案类型处理
 */
@FreemarkerTag(value = "bizType")
public class BizType implements FreemarkerSupperTag {


    /**
     * 业务处理
     * @param params Map<String,SimpleScalar>
     * @return
     */
    @Override
    public Object getParms(Map params) {
        /**
         *
         * 获取参数,因为此处 Value 为 SimpleScalar 类型,不能直接转换为  String  Integer 等类型
         */
        Integer type = getInt(params, "type");
        //返回
        return TYPES_K_V.get(type);
    }
}

页面  Freemarker  使用:

<@bizType type="1">${so!'-'}</@bizType>

这样 type 会转参到标签内的 parms ,获取即可,自定义标签中getParms函数中的return的值会赋值给 so,如果有点模糊,请断点执行多看几次。有问题加群。

输出的列表中单位性质为数值,去后端获取对应的类型。


代码如下:

    <#--输出列表-->
    <table class="layui-table">
        <thead>
        <tr>
            <td colspan="2">
                <h3>网站备案信息(ICP)查询结果
                    <#--<small>注:当前信息仅供参考</small>-->
                    <span class=" fr"><small>更新时间:${inDate?string('yyyy-MM-dd HH:mm:ss')}&nbsp;&nbsp; </small></span>
                </h3>
            </td>
        </tr>
        </thead>
    </table>
    <hr>
    <#--数据输出-->
    <table class="layui-table">
        <thead>
        <tr>
            <td>#</td>
            <td>单位名称</td>
            <td>单位性质</td>
            <td>网站备案/许可证号</td>
            <td>网站名称</td>
            <td>网站首页网址</td>
            <td>审核时间</td>
        </tr>
        </thead>
        <tbody>
        <#list data as it>
            <tr>
                <td>${it_index+1}</td>
                <td>${it.orgName}</td>
                <td>
                    <#if it.orgType??>
                        <@bizType type="${it.orgType}">${so!'-'}</@bizType>
                    </#if>
                </td>
                <td>${it.icpSubNumber}</td>
                <td>${it.name}</td>
                <td>${it.siteIndex}</td>
                <td>${it.checkTime}</td>
            </tr>
        </#list>

        </tbody>
    </table>

有疑问加群和我说。


版权所属:SO JSON在线解析

原文地址:https://www.sojson.com/blog/335.html

转载时必须以链接形式注明原始出处及本声明。

本文主题:

如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。

相关文章
Freemarker教程,Freemarker 自定义方法 【含源码】
Shiro教程(八)Shiro Freemarker标签的使用。
N多系统单点登录,实现、解决方案。四种解决方案
Shiro教程,Shiro 配置文件详细解释,Shiro自定义Filter配置
火狐(Firefox )浏览器提示。此链接是不受信任的,站长和用户的解决方案。SSL申请
使用zxing解析二维码抛出com.google.zxing.NotFoundException 解决方案
JSOUP教程,JSOUP 乱码处理,JSOUP生僻字乱码解决方案
Shiro教程(九)Shiro JSP标签的使用。
Java API接口返回不是JSON的解决方案,SpringMVC返回JSON配置。
Springboot 打Jar包,Maven完美解决本地Jar包自动打入Springboot Jar包中
最新文章
Linux Centos 使用 Redis service 启动,Redis service 脚本编写 24
恭喜SOJSON获得阿里云618“上云接力赛”第一名,获得代金券6.18万 176
Springboot 集成Freemarker 自定义标签解决方案 459
七牛云到底有多垃圾?用七牛云需要知道的事,不然不小心就一套房没了 28150
JavaScript怎么识别360浏览器?JS识别360急速模式方案,360流氓浏览器 1075
关于本站所有JavaScript 加密、混淆、解密、美化等安全说明 1766
Jsoup 提交参数乱码,解决思路,解决过程及解决方案 833
生成新浪短网址、百度短网址,t.cn / dwz.cn 的生成方式,短链还原 751
ICP怎么操作取消备案,企业、个人怎么自己申请取消备案? 623
Javascript 加密/压缩后运行不了,JavaScript报错排查讲解 573
最热文章
免费天气API,全国天气 JSON API接口,可以获取五天的天气预报 179679
Elasticsearch教程(四) elasticsearch head 插件安装和使用 140330
我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比 136612
苹果电脑Mac怎么恢复出厂系统?苹果系统怎么重装系统? 88245
Elasticsearch教程(六) elasticsearch Client创建 82495
Elasticsearch教程(一),全程直播(小白级别) 78737
Elasticsearch教程(二),IK分词器安装 77672
Elasticsearch教程(八) elasticsearch delete 删除数据(Java) 77130
Elasticsearch教程(五) elasticsearch Mapping的创建 70643
免费天气API,天气JSON API,不限次数获取十五天的天气预报 60057

骚码加入我们 / 千人QQ群:259217951

入群需要5元,如果没有QQ钱包,可以先Alipay、微信,赞助然后加群主拉进。

二维码生成 来自 >> 二维码生成器

支付扫码

所有赞助/开支都讲公开明细,用于网站维护:赞助名单查看

正在加载... ...