现在流行的前后端分离架构,但在一些小的,简单的系统,非分离的单体系统在开发效率和维护性上实际更具优势
本文讲解非前后端系统的搭建及Freemarker模板技术和springboot的集成。
一、静态资源的存放地址
静态资源如js,img,css等
(1)公共js通过pom文件引用

源代码解析:
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration自动配置类
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!
this.resourceProperties.isAddMappings()) {
logger.debug(
"Default resource handling disabled");
}
else {
Duration cachePeriod =
this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl =
this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern(
"/webjars/**")) {
this
.customizeResourceHandlerRegistration(registry.addResourceHandler(
new
String[]{
"/webjars/**"
}).addResourceLocations(
new
String[]{
"classpath:/META-INF/resources/webjars/"
}).setCachePeriod(
this
.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern =
this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(
new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(
this.resourceProperties.getStaticLocations())).setCachePeriod(
this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
}
|
1.maven
|
<!--
以
jar
的方式引入
query-->
<
dependency>
<
groupId>org.webjars</
groupId>
<
artifactId>jquery</
artifactId>
<
version>3.2.0</
version>
</
dependency>
|
2.查看jar结构
|
![]()
观察其js路径为
resource/webjars/jquery/3.2.0/jqery.js
|
3.调用
|
注意:其网络lur路径为
/webjars/jquery/3.2.0/jqery.js
|
springboot有默认的几个静态资源存放路径
项目下的:
JAVA、RESOURCES都是classpath
classpath:/META-INF/resources/
//下面这个几个文件夹是在resources子文件夹里,resources是maven的资源标志,不是文件路径
classpath:/resources/
classpath:/static/
classpath:/public/
/ 项目根路径
springboot为以上所有路径都默认映射了起始面文件:index.html,即如果这些目录中有index.html时,访问这个目录时,页面会显示index.html的内容。
有相同资源时文件时,优先级: resouce>static>public
|
![]()
注意:
![]() |
访问:
注意:访问不得加resource/public/static这些路径哈,他们相当于WEBAPP
resources这些路径下可加子路径
|
源码解析
org.springframework.boot.autoconfigure.web.ResourceProperties类里约定了几个可以存放静态文件的目录
|
private static final
String[] CLASSPATH_RESOURCE_LOCATIONS =
new
String[]{
"classpath:/META-INF/resources/"
,
"classpath:/resources/"
,
"classpath:/static/"
,
"classpath:/public/"
};
|
![]() |
访问:
|
注意:如果跟Controller里冲突,以Controller里为准
@RestController
public class IndexControl {
WebMvcAutoConfiguration
g;
@Autowired
private Person
person;
@RequestMapping(
"/")
public String index(){
)
|
源码解析
org.springframework.boot.autoconfigure.web.servlet.
WebMvcAutoConfiguration
|
![]() |
源码解析
org.springframework.boot.autoconfigure.web.servlet.
WebMvcAutoConfiguration
|
![]() |
HTML
<head>
<meta
charset=
"UTF-8"
>
<link
rel=
"icon"
href=
"favicon.ico"
>
</head>
|
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
|

#热部署生效
spring.devtools.restart.enabled: true
#设置重启的目录
#spring.devtools.restart.additional-paths: src/main/java
#classpath目录下的WEB-INF文件夹内容修改不重启
spring.devtools.restart.exclude: WEB-INF/**
|
二、 springboot2集成freemarker
1.pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
2.
(1)配置application.properties配置文件
# 是否允许HttpServletRequest属性覆盖(隐藏)控制器生成的同名模型属性。
spring.freemarker.allow-request-override=false
# 是否允许HttpSession属性覆盖(隐藏)控制器生成的同名模型属性。
spring.freemarker.allow-session-override=false
# 是否启用模板缓存。
spring.freemarker.cache=false
# 模板编码。
spring.freemarker.charset=UTF-8
# 是否检查模板位置是否存在。
spring.freemarker.check-template-location=true
# Content-Type value.
spring.freemarker.content-type=text/html
# 是否启用freemarker
spring.freemarker.enabled=true
# 设定所有request的属性在merge到模板的时候,是否要都添加到model中.
spring.freemarker.expose-request-attributes=false
# 是否在merge模板的时候,将HttpSession属性都添加到model中
spring.freemarker.expose-session-attributes=false
# 设定是否以springMacroRequestContext的形式暴露RequestContext给Spring’s macro library使用
spring.freemarker.expose-spring-macro-helpers=true
# 是否优先从文件系统加载template,以支持热加载,默认为true
spring.freemarker.prefer-file-system-access=true
# 设定模板的后缀.
spring.freemarker.suffix=.ftl
# 设定模板的加载路径,多个以逗号分隔,默认:
spring.freemarker.template-loader-path=classpath:/templates/
# 设定FreeMarker keys.
spring.freemarker.settings.template_update_delay=0
spring.freemarker.settings.default_encoding=UTF-8
spring.freemarker.settings.classic_compatible=true
spring.freemarker.settings.datetime_format=yyyy-MM-dd HH:mm:ss
spring.freemarker.settings.date_format=yyyy-MM-dd
spring.freemarker.settings.time_format=HH:mm:ss
#可采用<#或者[#作为标签
spring.freemarker.settings.tag_syntax=auto_detect
(2)application.properties文件可能不是非常的强大,可用bean配置freemarker.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- springmvc 与freemarker绑定的配置 --> <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="classpath:/templates/" /><!--模板文件存放的根路径- --> <property name="defaultEncoding" value="utf-8" /> <property name="freemarkerSettings"> <props> <prop key="tag_syntax">auto_detect</prop><!-- <改成[符号 --> <prop key="template_update_delay">10</prop> <prop key="locale">zh_CN</prop> <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop> <prop key="date_format">yyyy-MM-dd</prop> <prop key="number_format">#.##</prop> <!-- 配置自定义的freemarker异常处理--> <!-- <prop key = "template_exception_handler">com.xbsoft.comm.freemark.FreemarkerExceptionHandler</prop> --> </props> </property> </bean> <!-- FreeMarker视图解析 在这里配置后缀名ftl和视图解析器。。--> <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"></property> <property name="suffix" value=".html" /> <property name="contentType" value="text/html;charset=utf-8" /> <property name="exposeRequestAttributes" value="true" /> <property name="exposeSessionAttributes" value="true" /> <property name="exposeSpringMacroHelpers" value="true" /> <property name="attributesMap"> <!-- 自定义方法和宏注入 --> <map> <!-- <entry key="to_date" > <bean class=" com.xbsoft.comm.freemark.ToDateMethod" /></entry> <entry key="to_dateTime" > <bean class=" com.xbsoft.comm.freemark.ToDateTimeMethod" /></entry> <entry key="dict_show" > <bean class=" com.xbsoft.comm.freemark.DictMethod" /></entry> <entry key="formDict" > <bean class=" com.xbsoft.comm.freemark.SRCDirective" /></entry> --> </map> </property> </bean> </beans>
在启动类引入
//启动入口注解 @ImportResource(locations = {"classpath:config/freemarker.xml"}) @SpringBootApplication public class GirlApplication { public static void main(String[] args) { //应用启动 SpringApplication.run(GirlApplication.class, args); } }
freemarker模板一般放在templates文件目录下
三、freemarker基础语法
1.打印
1.eg
${user.address!}
2、null判断
特别注意,如果属性从map取出来为null,不处理将会出错,
所以一般输出加!
${user.name},异常
${(user.name)!},显示空白 等价${book.name?if_exists } //用于判断如果存在,就输出这个值
${user.name!'vakin'},若user.name不为空则显示本身的值,否则显示vakin
${user.name?default('vakin')},同上
3.时间展示
${(obj.birthday?string("yyyy-MM-dd"))!}
${(obj.tt?string("yyyy-MM-dd HH:mm:ss"))!}
注意是整个值括起来加!,这样为null才不出错
4.在if里面判断
<#if user.xueli??> #如果user.xueli不为空
user.xueli存在值
</#if>
2.if语法
<#if user.name?? && user.name=="蒋增奎"> //注意判断时都要加user.name?? 属性存在的前提
真鸡巴帅
</#if>
注意:
<#if... #号和if必须挨着,不用有空格
<#if condition>...
<#elseif condition2>...
<#elseif condition3>......
<#else>...
</#if>
<#assign age=23>
<#if (age>60)>老年人
<#elseif (age>40)>中年人
<#elseif (age>20)>青年人
<#else> 少年人
</#if>
3.switch语句
<#switch value>
<#case refValue1>
...
<#break> //break退出
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
4.list语法
<#list users as user> //usaer是迭代对象里面的别名
</#list>
users即可以是一个list对象,也可以是个数组
如
List<User> list=new Vector<User>();
或者
<@my.list items=["mouse", "elephant", "python"] title="Animals"/>
list还有数组循环如
<#macro repeat count=5>
<#list 1..count as x>
<li>${x}</li>
</#list>
</#macro>
判断list是否有值
[#if newss?size==0]
机构暂无新闻
[/#if]
List指令还隐含了两个循环变量:
item_index:当前迭代项在所有迭代项中的位置,是数字值。
item_has_next:用于判断当前迭代项是否是所有迭代项中的最后一项。
注意:在使用上述两个循环变量时,一定要将item换成你自己定义的循环变量名,item其实就是前缀罢了。
例如,如果你使用<# list list as l>..</#list>定义,那么就要使用l_index,l_has_next。
在循环过程中,如果您想跳出循环,那么可以使用结合break指令,即<#break>来完成。
注意:boolean不是直接用${}输出,只能用于判断
<#if user_has_next>
还有下一个
</#if>
这样写是错的${user_has_next} ;
这样写可以:${user_has_next?String("yes","no")}
include和import包含文件
include指令的作用类似于JSP的包含指令,用于包含指定页,include指令的语法格式如下
<#include filename [options]
在上面的语法格式中,两个参数的解释如下
a、filename:该参数指定被包含的模板文件
b、options:该参数可以省略,指定包含时的选项,包含encoding和parse两个选项,encoding指定包含页面时所使用的解码集,而parse指定被
包含是否作为FTL文件来解析。如果省略了parse选项值,则该选项值默认是true
例:<#include "inc.ftl">
<#include "/inc/inc1.ftl">
<#include "/inc/inc2.ftl">
${username}
两个里面都有相同变量,则将实现先后覆盖
出现这种情况,在两个模版中都分别存在变量名都相同的变量的时候,include包含进来,会进行覆盖,include只时候将其公共的静态文件进行包含,而里面不涉及到内部函数以及变量声明之类的,当涉及到这种问题,我们就要用import进行导入
注意1:controller里面的绑定数据,在include里面也可以读取
@RequestMapping("/include")
public String include(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception{
User user=new User(1,"jzk",new Date(),new BigDecimal("34.56"));
model.addAttribute("user",user);
return "main";
}
在包含文件里:
${user.userName!}
注意2:include会把包含页面的所有html代码读取过来,不仅仅是显示值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
老子有敢抢:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
jzk
</body>
</html></body>
</html>
而里面不涉及到内部函数以及变量声明之类的,当涉及到这种问题,我们就要用import进行导入会在主命名空间中创建两个变量. 如果再引入同名的变量时就会被后引入的或者新定义的覆盖.这样就不是很好,因为只想让它们在"My Test Library"命名空间中.就需要用 import代替include了1. my_test.ftl< #macro copyright date >< p > Copyright (C) ${date} Julia Smith. All rights reserved.< br > Email: ${mail} </ p ></ #macro >2.new file< #import "/lib/my_test.ftl" as my >< @my .copyright date ="1999-2002" />${my.mail}${mail}输出:<p>Copyright (C) 1999-2002 Julia Smith.All rights reserved.<br>Email : jsmith@acme.com</p>
宏的定义
|
宏就是可以反复使用的代码块,类似其他语言的函数或者方法
<#--第一个参数[name]表示这个macro的name,后面为参数,可以N个-->
<#macro name param1,param2,param3,....>
$ {param1}
$ {param2}
</#macro>
注意:
使用的参数一定要事先定义;
定义的参数在使用的时候一定要进行赋值,除非在创建macro的时候给参数默认值;
参数所能赋予的值不一定是字符串,也可以是其他类型,还可以是一个预运算表达式
在使用的时候,对参数赋值顺序不确定,可随意
参数是局部变量,只能在宏定义中有效
如果变量没有默认值,则要放在有默认值的变量前面,否则要出错
如:
|
宏的基本案例-code
|
[#macro greet]
<
font
size=
"+2"
>
Hello Joe!
</
font
>
[/#macro]
[#macro greet person]
<
font
size=
"+2"
>
Hello ${person}!
</
font
>
[/#macro]
[#macro user name address]
<
font
size=
"+2"
>
Hello ${name},your address:${address}!
</
font
>
[/#macro]
[#macro emp name address="
九眼桥
"]
<
font
size=
"+2"
>
Hello ${name},your address:${address}!
</
font
>
[/#macro]
[#macro border]
<
table
border=
4
cellspacing=
0
cellpadding=
4
><
tr
><
td
>
[#nested]
</
tr
></
td
></
table
>
[/#macro]
1.
不带参数的宏
<
br
>
[@greet][/@greet]
<
p
></
p
>
2.
带参数的宏
<
br
>
[@greet person="
蒋增奎
"/]
<
p
></
p
>
3.
带多参数的宏
,
参数顺序无所谓
<
br
>
[@user address="
天府大道
" name="
蒋增奎
"/]
<
p
></
p
>
4.
可以指定默认值
<
br
>
[@emp address="
天府大道
" name="
蒋增奎
"/]
<
p
></
p
>
不传递参数,则使用默认值
<
br
>
[@emp name="
蒋增奎
"/]
<
p
></
p
>
5.
宏可以嵌套内容
,nested
<
br
>
[@border]
我才你吗
[/@border]
<
p
></
p
>
|
生成html
|
1.不带参数的宏<br>
<font size="+2">Hello !</font>
<p></p>
2.带参数的宏<br>
<font size="+2">Hello 蒋增奎!</font>
<p></p>
3.带多参数的宏,参数顺序无所谓<br>
<font size="+2">Hello 蒋增奎,your address:天府大道!</font>
<p></p>
4.可以指定默认值<br>
<font size="+2">Hello 蒋增奎,your address:天府大道!</font>
<p></p>
不传递参数,则使用默认值<br>
<font size="+2">Hello 蒋增奎,your address:九眼桥!</font>
<p></p>
5.宏可以嵌套内容<br>
<table border=4 cellspacing=0 cellpadding=4><tr><td>
我才你吗</tr></td></table>
<p></p>
|
名字空间
|
<#macro copyright date>
<p>Copyright (C) ${date} Julia Smith. All rights reserved.
<br>Email: ${mail}</p>
</#macro>
使用import指令导入库到模板中,Freemarker会为导入的库创建新的名字空间,并可以通过import指令中指定的散列变量访问库中的变量:
<#import "/lib/my_test.ftl" as
my
>
<@my.copyright date="1999-2002"/>
${my.mail}
${mail}
输出结果:
<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
|
注意
|
宏的参数不一定是字符串,一定非得有初始值
|
Java
|
@RequestMapping
(
"/macro"
)
public
String macro(HttpServletRequest request, HttpServletResponse response, Model model)
throws
Exception{
List<User> list=
new
ArrayList<User>();
User user1=
new
User(
1
,
"jzk1"
,
new
Date(),
new
BigDecimal(
"34.56"
));
list.add(user1);
User user2=
new
User(
1
,
"jzk2"
,
new
Date(),
new
BigDecimal(
"34.56"
));
list.add(user2);
User user3=
new
User(
1
,
"jzk3"
,
new
Date(),
new
BigDecimal(
"34.56"
));
list.add(user3);
model.addAttribute(
"userList1"
,list);
model.addAttribute(
"tblId1"
,
"3"
);
return
"macro"
;
}
|
macro.html
|
<!--定义宏-->
[#macro usertTbl
userList id]
<
table
border=
1
cellspacing=
0
cellpadding=
4
style=
"
width
:
100
%
"
id=
"${id}"
>
<
tr
><
td
>
id
</
td
><
td
>
name
</
td
><
td
>
birth
</
td
><
td
>
age
</
td
></
tr
>
[#list userList as user]
<
tr
>
<
td
>
${user.userId!}
</
td
>
<
td
>
${user.userName!}
</
td
>
<
td
>
${(user.birth?string("yyyy-MM-dd"))!}
</
td
>
<
td
>
${user.age!}
</
td
>
</
tr
>
[/#list]
</
table
>
[/#macro]
<!--展示-->
6.
宏复杂参数
<
br
>
[@usertTbl userList=userList1 id=tblId1][/@usertTbl]
输出代码
<table border=1 cellspacing=0 cellpadding=4 style="width:100%" id="3">
<tr><td>id</td><td>name</td><td>birth</td><td>age</td></tr>
<tr>
<td>1</td>
<td>jzk1</td>
<td>2020-05-03</td>
<td>34.56</td>
</tr>
<tr>
<td>1</td>
<td>jzk2</td>
<td>2020-05-03</td>
<td>34.56</td>
</tr>
<tr>
<td>1</td>
<td>jzk3</td>
<td>2020-05-03</td>
<td>34.56</td>
</tr>
</table>
|
说明
|
1.参数可以没有初始值及类型,根据传入参数而定
[#macro usertTbl
userList id]
2.在引用宏的时候,参数变量就是后端的定义变量,不需要加${}符号
[@usertTbl userList=userList1 id=tblId1][/@usertTbl]
3.在宏定义里面使用变量,首先去找对应的后台使用有这个变量名,如果有的话会自动匹配,其次才找传递参数
[#macro usertTbl
userList id]
<
table
border=
1
cellspacing=
0
cellpadding=
4
style=
"
width
:
100
%
"
id=
"${id}"
>
<
tr
><
td
>
id
</
td
><
td
>
name
</
td
><
td
>
birth
</
td
><
td
>
age
</
td
></
tr
>
[#list userList as user]
。。。
如果对应java类里有
userList变量,则能直接使用
|
注意
|
定义的参数在使用的时候一定要进行赋值,除非在创建macro的时候给参数默认值;
参数所能赋予的值不一定是字符串,也可以是其他类型,还可以是一个预运算表达式
在使用的时候,对参数赋值顺序不确定,可随意
参数是局部变量,只能在宏定义中有效
如果变量没有默认值,则要放在有默认值的变量前面,否则要出错
如:
<#macro radio name="" dicts xxx val="" >会报错
正确写法
<#macro radio dicts xxx name="" val="" >
|
自定义类
|
要继承
freemarker.template.TemplateMethodModelEx类,实现
exec方法
import
freemarker.template.TemplateMethodModelEx;
import
freemarker.template.TemplateModelException;
import
java.util.List;
/**
*
@class:
com.jyj.controll.ToDate
*
@author:
jiangzengkui
*
@company:
教育家
*
@create:
2020-05-03 09:41
*
@description:
*
@updateRemark:
*/
public class
ToDate
implements
TemplateMethodModelEx {
@Override
public
Object exec(List params)
throws
TemplateModelException {
String ret =
"
返回值
"
;
return
ret;
}
}
|
自定义绑定
|
1.单页面使用
如果在一个页面使用,可以直接在ctroller对应方法里绑定
model.addAttribute(
"dictShow"
,
new
com.jyj.controll.ToDate());
2.设置成全局变量
springmvc的xml配置
<!-- FreeMarker视图解析 在这里配置后缀名ftl和视图解析器。。-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"></property>
<property name="suffix" value=".html" />
<property name="contentType" value="text/html;charset=utf-8" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="attributesMap">
<!-- 自定义方法和宏注入 -->
<map>
<!-- 把日期类型显示成yyyy-mm-dd格式 -->
<!-- 把日期类型显示成yyyy-mm-dd HH:mm:ss格式 -->
<!-- 把数据字典的编码显示成对应中文 -->
</map>
</property>
</bean>
3.springBoot2集成全局变量
import
org.springframework.context.annotation.
Bean
;
import
org.springframework.context.annotation.
Configuration
;
import
org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import
javax.annotation.
PostConstruct
;
import
java.util.HashMap;
import
java.util.Map;
/**
*
@class:
com.jyj.config.FreemarkerConfig
*
@author:
jiangzengkui
*
@company:
教育家
*
@create:
2020-05-03 10:52
*
@description:
*
@updateRemark:
*/
@Configuration
public class
FreemarkerConfig {
/**
*
增加自定义视图变量和方法
*
*
@return
*/
@Bean
public
CommandLineRunner customFreemarker(FreeMarkerViewResolver resolver) {
return new
CommandLineRunner() {
@Override
public void
run(String... strings)
throws
Exception {
Map map =
resolver
.getAttributesMap();
//把自定义函数压入map
map.put("dictShow", new com.jyj.controll.ToDate());
}
};
}
}
|
页面使用
|
直接用${声明的行数名(参数.......)}即可
${dictShow()}
|
自定义函数
|
import java.util.*;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModelException;
/**
* 数据字典自定义函数
*
@author
jiangzengkui
*
@date
2016年9月2日 下午11:02:36
*
@Description
: 显示编码对应的中文值
* 调用如:${dict_show("BM044",form.service_type!)}
*
*/
public
class DictMethod
implements TemplateMethodModelEx {
/**
*
params
[0]=字典名称:,如:BM
-
001
* params1]=字典编码 如1
*/
@Override
public Object exec(
List
params)
throws TemplateModelException {
String
ret=
"";
String
dictName=
"";
//字典名称:,如:BM-001
String
dictCode=
"";
//字典编码 如1
if(
params==
null ||
params.size()<2){
throw
new TemplateModelException(
"参数个数不够");
}
Object
obj1=
params.get(0);
//参数1
Object
obj2=
params.get(1);
//参数2
if(
"freemarker.core.DefaultToExpression$EmptyStringAndSequence".equals(
obj2.getClass().getName())){
return
ret;
}
if(
obj2==
null ||
obj2.toString().trim().length()==0){
//如果没有编码值,则直接返回
return
ret;
}
if(
obj1==
null ||
obj1.toString().trim().length()==0)
throw
new TemplateModelException(
"必须传递数据字典值");
dictName=
obj1.toString().trim();
dictCode=
obj2.toString().trim();
ret=(String)DictManager.
getInstance().getDictShow(
dictName,
dictCode);
return
ret;
}
}
|
绑定
|
<!-- FreeMarker视图解析 在这里配置后缀名
ftl
和视图解析器。。-->
<
bean
id=
"viewResolver"
class=
"org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"
>
<
property
name=
"viewClass"
value=
"org.springframework.web.servlet.view.freemarker.FreeMarkerView"
></
property
>
<
property
name=
"suffix"
value=
".html"
/>
<
property
name=
"contentType"
value=
"text/html;charset=utf-8"
/>
<
property
name=
"exposeRequestAttributes"
value=
"true"
/>
<
property
name=
"exposeSessionAttributes"
value=
"true"
/>
<
property
name=
"exposeSpringMacroHelpers"
value=
"true"
/>
<
property
name=
"attributesMap"
>
<!-- 自定义方法和宏注入 -->
<
map
>
<!-- 把日期类型显示成
yyyy
-
mm
-
dd
格式 -->
<!-- 把日期类型显示成
yyyy
-
mm
-
dd
HH:mm:ss格式 -->
<
entry
key=
"to_dateTime"
>
<
bean
class=
"
com.xbsoft.comm.freemark.ToDateTimeMethod
"
/></
entry
>
<!-- 把数据字典的编码显示成对应中文 -->
<!-- 机构课程的选择 业务通用类 -->
</
map
>
</
property
>
</
bean
>
|
HTML
|
${dict_show("BM202",car.biansu_type!"")}
|
注意
|
在html里面传递参数,直接从ctroller里的绑定变量名即可,不需要用${}等
|
TemplateDirectiveModel
|
这个类和TemplateMethodModelEx 作用类似,都是用于自定义标签,但其扩展性更好
|
类
|
import
freemarker.core.Environment;
import
freemarker.template.TemplateDirectiveBody;
import
freemarker.template.TemplateDirectiveModel;
import
freemarker.template.TemplateException;
import
freemarker.template.TemplateModel;
import
java.io.IOException;
import
java.io.Writer;
import
java.util.Iterator;
import
java.util.Map;
/**
*
@author:
jiangzengkui
*
@company:
教育家
*
@create:
2020-05-03 16:33
*
@description:
*
@updateRemark:
*/
public class
TestDirectiveModel
implements
TemplateDirectiveModel {
/**
*
*
@param
env
运行环境
*
@param
params
标签传递过来的参数
*
@param
loopVars
*
@param
body
*
@throws
TemplateException
*
@throws
IOException
*/
@Override
public void
execute(Environment env, Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body)
throws
TemplateException, IOException {
String out=
""
;
//
向页面输出内容
out=
"
输出内容
"
;
/**
*
打印输入的标签参数测试
*/
Iterator<Map.Entry<String, Object>> it = params.entrySet().iterator();
while
(it.hasNext()){
Map.Entry<String, Object> entry = it.next();
System.
out
.println(
"key:"
+entry.getKey()+
" val:"
+entry.getValue());
}
//
内容输出到页面
Writer print=env.getOut();
print.write(out);
}
}
|
绑定
|
绑定方法和
TemplateMethodModelEx一致
@Bean
public
CommandLineRunner customFreemarker(FreeMarkerViewResolver resolver) {
return new
CommandLineRunner() {
@Override
public void
run(String... strings)
throws
Exception {
Map map =
resolver
.getAttributesMap();
map.put(
"dictShow"
,
new
com.jyj.controll.ToDate());
}
};
}
|
页面引用,和其他freemarker标签一致
|
[@标签名 参数....]
[@formDict etype="select" dictName="BM031" name="class_week"
id="${t.class_week!}" value="${t.class_week!}" isEmpty="true" class="input_text" /]
注意:这里传递值需要用${}取出来,这个和自定义函数不一样
|
比较运算符号
|
1 =或者==:判断两个值是否相等.
2 !=:判断两个值是否不等.
3 >或者gt:判断左边值是否大于右边值
4 >=或者gte:判断左边值是否大于等于右边值
5 <或者lt:判断左边值是否小于右边值
6 <=或者lte:判断左边值是否小于等于右边值
注意
: =和!=可以用于字符串,数值和日期来比较是否相等,但=和!=两边必须是相同类型的值,否则会产生错误,而且FreeMarker是精确比较,"x","x ","X"是不等的.其它的运行符可以作用于数字和日期,但不能作用于字符串,大部分的时候,使用gt等字母运算符代替>会有更好的效果,因为 FreeMarker会把>解释成FTL标签的结束字符,当然,也可以使用括号来避免这种情况,如:<#if (x>y)>
|
并且或者或者
|
逻辑与:&&
逻辑或:||
逻辑非:!
逻辑运算符只能作用于布尔值,否则将产生错误
<#if user.name?? && user.name=="蒋增奎"> //注意判断时都要加user.name?? 属性存在的前提
[#if newsList?size==0] //list长度等于零
<#if user.name??> 变量是否存在
</#if>
[#if form.role_code??
&& form.role_code !=""]
存在并且不等于空
[/#if]
|