现在流行的前后端分离架构,但在一些小的,简单的系统,非分离的单体系统在开发效率和维护性上实际更具优势
本文讲解非前后端系统的搭建及Freemarker模板技术和springboot的集成。
一、静态资源的存放地址
静态资源如js,img,css等
(1)公共js通过pom文件引用
通过webjars的方式引入第三方资源 访问其官网: https://www.webjars.org/ 找到对应需要引入的静态资源:bootstrap、Jquery等,选择maven方式,把相应配置文件复制到我们项目的pom.xml文件中。源代码解析: 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.调用 | http://localhost:9999/demo/webjars/jquery/3.2.0/jquery.js 注意:其网络lur路径为 /webjars/jquery/3.2.0/jqery.js |
(2)自己写静态资源放在springboot路径 也可以自己打成jar包,但太麻烦。 推荐:springboot约定将一些目录设置为静态资源的存放地
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 |
注意: 这个是maven路径,不是class里面的路径哈 |
访问: http://localhost:9999/demo/hello.html 注意:访问不得加resource/public/static这些路径哈,他们相当于WEBAPP resources这些路径下可加子路径 http://localhost:9999/demo/son/son.html |
源码解析 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/" }; |
访问: http://localhost:9999/demo/ |
注意:如果跟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 > < #assign mail =" fred@acme.com " > < @my .copyright date ="1999-2002" /> ${my.mail} ${mail} 输出: <p> Copyright (C) 1999-2002 Julia Smith.All rights reserved. <br>Email : jsmith@acme.com </p> jsmith@acme.com fred@acme.com7、宏定义
宏的定义 | 宏就是可以反复使用的代码块,类似其他语言的函数或者方法 <#--第一个参数[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> <#assign mail = " jsmith@acme.com "> 使用import指令导入库到模板中,Freemarker会为导入的库创建新的名字空间,并可以通过import指令中指定的散列变量访问库中的变量: <#import "/lib/my_test.ftl" as my > <#assign mail=" fred@acme.com "> <@my.copyright date="1999-2002"/> ${my.mail} ${mail} 输出结果: <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved. <br>Email: jsmith@acme.com </p> jsmith@acme.com fred@acme.com |
注意 | 宏的参数不一定是字符串,一定非得有初始值 |
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格式 --> <entry key="to_date" > <bean class=" com.xbsoft.comm.freemark.ToDateMethod " /></entry> <!-- 把日期类型显示成yyyy-mm-dd HH:mm:ss格式 --> <entry key="to_dateTime" > <bean class=" com.xbsoft.comm.freemark.ToDateTimeMethod " /></entry> <!-- 把数据字典的编码显示成对应中文 --> <entry key="dict_show" > <bean class=" com.xbsoft.comm.freemark.DictMethod " /></entry> </map> </property> </bean> 3.springBoot2集成全局变量 import org.springframework.boot.CommandLineRunner; 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 com.xbsoft.comm.dict.DictManager; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModelException; /** * 数据字典自定义函数 * @ClassName : com.xbsoft.comm.freemark.DictMethod * @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 格式 --> < entry key= "to_date" > < bean class= " com.xbsoft.comm.freemark.ToDateMethod " /></ entry > <!-- 把日期类型显示成 yyyy - mm - dd HH:mm:ss格式 --> < 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 > <!-- 机构课程的选择 业务通用类 --> < entry key= "courseDict" > < bean class= " com.xbsoft.xqb.comm.OrgCourseDirective " /></ entry > < entry key= "addressDict" > < bean class= " com.xbsoft.xqb.comm.OrgAddressDirective " /></ entry > < entry key= "teaDict" > < bean class= " com.xbsoft.xqb.comm.OrgTeaDirective " /></ entry > < entry key= "tgDict" > < bean class= " com.xbsoft.xqb.comm.TgDirective " /></ entry > < entry key= "pcDict" > < bean class= " com.xbsoft.xqb.comm.PbCourseDirective " /></ 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; /** * @class: com.jyj.comm.TestDirectiveModel * @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()); map.put( "to_date" , new com.jyj.comm.ToDateMethod()); map.put( "testTag" , new com.jyj.comm.TestDirectiveModel()); } }; } |
页面引用,和其他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] |