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

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

  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生僻字乱码解决方案
最新文章
DNS TXT记录添加方法,ICP备案信息屏蔽查询处理方案讲解 634
SEO优化的最佳时间段即将来临,春节最佳SEO优化讲解 855
SEO实战分析-排名最近突然掉光了问题排查,几个大站关键词下降SEO问题分析 1399
Java模拟WSS websocket ssl请求,Java WSS模拟请求代码示例 2728
Springboot 集成 Ehcache 代码讲解 2294
阿里云 RDS Specified key was too long; max key length is 767 bytes 解决方案 458
Springboot HTTP Get/Post 请求讲解,Springboot几行代码完成Http请求 2492
天气免费API接口,天气API接口请求讲解及源码下载 14399
最近Google adsense 西联汇款从光大银行提取不了?怎么操作? 11679
阿里云双11活动购买详细说明,阿里云最低86元起一年服务器购买详情 2144
最热文章
我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比 296814
苹果电脑Mac怎么恢复出厂系统?苹果系统怎么重装系统? 248895
免费天气API,全国天气 JSON API接口,可以获取五天的天气预报 235941
Elasticsearch教程(四) elasticsearch head 插件安装和使用 162251
免费天气API,天气JSON API,不限次数获取十五天的天气预报 161245
最新MyEclipse8.5注册码,有效期到2020年 (已经更新) 147039
Elasticsearch教程(一),全程直播(小白级别) 93691
Jackson 时间格式化,时间注解 @JsonFormat 用法、时差问题说明 92629
Elasticsearch教程(六) elasticsearch Client创建 88243
Elasticsearch教程(二),IK分词器安装 85091

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

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

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

支付扫码

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

正在加载... ...