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

JSON 2019-06-21 10:04:46 36180

  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 自定义方法 【含源码】
Springboot + Freemarker 集成配置
Springboot JPA 执行原生sql ,自定义SQL占位符增加参数
Shiro教程(八)Shiro Freemarker标签的使用。
N多系统单点登录,实现、解决方案。四种解决方案
iTunes 没有“应用”这个选项解决方案
Jsoup 提交参数乱码,解决思路,解决过程及解决方案
Shiro教程,Shiro 配置文件详细解释,Shiro自定义Filter配置
CDN 请求返回 connection reset by peer,被拦截请求解决方案
JSOUP教程,JSOUP 乱码处理,JSOUP生僻字乱码解决方案
最新文章
C语言的变量和常量 30
PHP变量剖析 113
SQL全外连接剖析 276
SQL自然连接剖析 184
springboot启动原理 416
SQL右连接【RIGHT JOIN】详解及图解 467
SQL左链接【LEFT JOIN】详解及图解 396
SQL非等值连接剖析 285
SQL等链接剖析 291
SQL内连接详解及图解 417
最热文章
最新MyEclipse8.5注册码,有效期到2020年 (已经更新) 680231
苹果电脑Mac怎么恢复出厂系统?苹果系统怎么重装系统? 674611
免费天气API,全国天气 JSON API接口,可以获取五天的天气预报 599966
免费天气API,天气JSON API,不限次数获取十五天的天气预报 568861
Jackson 时间格式化,时间注解 @JsonFormat 用法、时差问题说明 552088
我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比 509262
Elasticsearch教程(四) elasticsearch head 插件安装和使用 479677
Jackson 美化输出JSON,优雅的输出JSON数据,格式化输出JSON数据... ... 263408
Java 信任所有SSL证书,HTTPS请求抛错,忽略证书请求完美解决 244147
Elasticsearch教程(一),全程直播(小白级别) 225254
支付扫码

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

查看我的收藏

正在加载... ...