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

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

  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包中
最新文章
阿里云和腾讯云哪个好? 93
2019年9月16日新浪短链API已经恢复使用,新浪短链服务官方已经宣布停用。本站已经攻克 1424
2019年 中秋节、国庆节放假通知来了,拼假攻略 182
记一次小失误导致的大事件,Mysql SQL Error: 0, SQLState: null 排查过程 319
Springboot Maven 增加本地依赖包,Springboot Maven打包本地包 174
Java 获取图片属性、获取图片EXIF属性操作方法[metadata-extractor] 88
又拍云(Upyun)CDN、云存储刷新链接缓存,API实例讲解 124
Linux Centos 使用 Redis service 启动,Redis service 脚本编写 181
恭喜SOJSON获得阿里云618“上云接力赛”第一名,获得代金券6.18万 436
Springboot 集成Freemarker 自定义标签解决方案 1267
最热文章
免费天气API,全国天气 JSON API接口,可以获取五天的天气预报 184129
我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比 162811
Elasticsearch教程(四) elasticsearch head 插件安装和使用 142597
苹果电脑Mac怎么恢复出厂系统?苹果系统怎么重装系统? 100953
Elasticsearch教程(六) elasticsearch Client创建 83035
Elasticsearch教程(一),全程直播(小白级别) 80472
Elasticsearch教程(二),IK分词器安装 78372
Elasticsearch教程(八) elasticsearch delete 删除数据(Java) 77561
免费天气API,天气JSON API,不限次数获取十五天的天气预报 71983
Elasticsearch教程(五) elasticsearch Mapping的创建 71938

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

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

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

支付扫码

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

正在加载... ...