Springboot 集成Freemarker 自定义标签解决方案
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')} </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
转载时必须以链接形式注明原始出处及本声明。
如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。