FreeMarker在项目中实际运用随感

一,FreeMarker百度百科定义

  FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

  假设在一个应用系统中需要一个HTML页面如下:
1
2
3
4
5
6
7
8
9
10
<html>
    <head>
        <title>Welcome!</title>
    </head>
    <body>
        <h1>Welcome Big Joe!</h1>
        <p>Our latest product:
        <a href="products/greenmouse.html">green mouse</a>!
    </body>
</html>
  页面中的用户名(即上面的“Big Joe”)是登录这个网页的访问者的名字, 并且最新产品的数据应该来自于数据库才能随时更新。所以,不能直接在HTML页面中输入“Big Joe”、“greenmouse”及链接, 不能使用静态HTML代码。可以使用要求输出的模板来解决,模板和静态页面是相同的,只是它会包含一些FreeMarker将它们变成动态内容的指令:
1
2
3
4
5
6
7
8
9
10
<html>
    <head>
        <title>Welcome!</title>
    </head>
    <body>
        <h1>Welcome ${user}!</h1>
        <p>Our latest product:
        <a href="${latestProduct.url}">${latestProduct.name}</a>!
    </body>
</html>
  模板文件存放在Web服务器上,当有人来访问这个页面,FreeMarker就会介入执行,然后动态转换模板,用最新的数据内容替换模板中${...}的部分,之后将结果发送到访问者的Web浏览器中。访问者的Web浏览器就会接收到例如第一个HTML示例那样的内容(也就是没有FreeMarker指令的HTML代码),访问者也不会察觉到服务器端使用的FreeMarker。(存储在Web服务器端的模板文件是不会被修改的;替换也仅仅出现在Web服务器的响应中。)
为模板准备的数据整体被称作为数据模型。数据模型是树形结构(就像硬盘上的文件夹和文件),在视觉效果上, 数据模型可以是(这只是一个形象化显示,数据模型不是文本格式,它来自于Java对象):
1
2
3
4
5
6
7
8
9
(root)
  |
  +- user = "Big Joe"
  |
  +- latestProduct
      |
      +- url = "products/greenmouse.html"
      |
      +- name = "green mouse"
  早期版本中,可以从数据模型中选取这些值,使用user和latestProduct.name表达式即可。类比于硬盘的树形结构,数据模型就像一个文件系统,“(root)”和latestProduct就对应着目录(文件夹),而user、url和name就是这些目录中的文件。
总体上,模板和数据模型是FreeMarker来生成输出所必须的组成部分:模板 + 数据模型 = 输出  。

 二,项目的时序图

三,获取模板和数据
(一)dataurl数据获得
1.通过nginx,数据源操作的表先搞清楚根据id获得model
实体
@Data
@ToString
@Document(collection = "cms_config")
public class CmsConfig {

    @Id
    private String id;
    private String name;
    private List<CmsConfigModel> model;

}

其中的

CmsConfigModel
@Data
@ToString
public class CmsConfigModel {
    private String key;
    private String name;
    private String url;
    private Map mapValue;
    private String value;

}
api
1 @Api("Cms配置接口管理")
2 public interface CmsConfigControllerApi {
3     @ApiOperation("根据id查询数据")
4     CmsConfig getModel(String id);
5 
6 }

controller

@RestController
@RequestMapping("/cms/config")
public class CmsConfigController implements CmsConfigControllerApi {
@Autowired
CmsConfigService cmsConfigService;

    @Override
   @GetMapping("/getmodel/{id}")
    public CmsConfig getModel(@PathVariable("id") String id) {
        CmsConfig model = cmsConfigService.getModel(id);
        return model;
    }
}

repository

1 public interface CmsConfigRepository extends MongoRepository<CmsConfig,String> {
2 }

2,远程调用resttemplate

用okhttpclient

2.1添加okhttpclient的pom.xml依赖

2.2启动类上加上bean声明,

@Bean
    public RestTemplate restTemplate(){

        return new RestTemplate(new OkHttp3ClientHttpRequestFactory());

}

2.3测试

restTemplate.getForEntity获得
@SpringBootTest
@RunWith(SpringRunner.class)
public class ResttemplateTest {
@Autowired
    RestTemplate restTemplate;
    @Test
public void resttemplateTest(){
        ResponseEntity<Map> forEntity = restTemplate.getForEntity("http://localhost:31001/cms/config/getmodel/5a", Map.class);
        Object body = forEntity.getBody();

        System.out.println(body); }
}

(二)模板从属于一个站点,

@Controller
public class TestController {
  @Autowired
    RestTemplate restTemplate;



    @RequestMapping("/banner")
    public String banner(Map map){
        //获取数据
        ResponseEntity<Map> responseEntity = restTemplate.getForEntity("http://localhost:31001/cms/config/getmodel/5a", Map.class);
        Map body = responseEntity.getBody();

        map.putAll(body);
        return "index_banner";
    }

index_banner.ftl模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div class="banner-roll">
    <div class="amodel as item>
                <div class="item" style="background-image: url(${item.value});"></div>
            </#list>
        </#if>
    <#-- <div class="item" style="background-image: url(../img/widget-bannerA.jpg);"></div>
        <div class="item" style="background-image: url(../img/widget-banner3.png);"></div>
        <div class="item" style="background-image: url(../img/widget-bannerB.jpg);"></div>
        <div class="item" style="background-image: url(../img/widget-bannerA.jpg);"></div>
        <div class="item" style="background-image: url(../img/widget-banner3.png);"></div>-->
    </div>
    <div class="indicators"></div>
</div>
<script type="text/javascript" src="http://www.x.com/plugins/jquery/dist/jquery.js"></script>
<script type="text/javascript" src="http://www.x.com/plugins/bootstrap/dist/js/bootstrap.js"></script>
<script type="text/javascript">
    var tg = $('.banner-item .item');
    var num = 0;
    for (i = 0; i < tg.length; i++) {
        $('.indicators').append('<span></span>');
        $('.indicators').find('span').eq(num).addClass('active');
    }

    function roll() {
        tg.eq(num).animate({
            'opacity': '1',
            'z-index': num
        }, 1000).siblings().animate({
            'opacity': '0',
            'z-index': 0
        }, 1000);
        $('.indicators').find('span').eq(num).addClass('active').siblings().removeClass('active');
        if (num >= tg.length - 1) {
            num = 0;
        } else {
            num++;
        }
    }
    $('.indicators').find('span').click(function() {
        num = $(this).index();
        roll();
    });
    var timer = setInterval(roll, 3000);
    $('.banner-item').mouseover(function() {
        clearInterval(timer)
    });
    $('.banner-item').mouseout(function() {
        timer = setInterval(roll, 3000)
    });
</script>
</body>
</html>

(三)数据+模板=页面

四,页面文件存在GridFS中,并从GridFS中获取页面文件

(一)GridFS简介

1.GridFS是MongoDB规范用于存储和检索大文件,如图片,音频文件,视频文件等。这是一种文件系统用来存储文件,但数据存储于MongoDB集合中。GridFS存储文件比其文档大小16MB限制的更大能力。

2.GridFS的划分一个文件分成块存储数据每个块在一个单独的文件,每个最大尺寸255K

GridFS默认使用两个集合 fs.files (文件简要信息)和 fs.chunks (具体内容)存储该文件的元数据和块。

(二)存取测试

1.存模板

 1 @SpringBootTest
 2 @RunWith(SpringRunner.class)
 3 public class GridsTest {
 4 @Autowired
 5     private GridFsTemplate gridFsTemplate;
 6 @Autowired
 7   private GridFSBucket gridFSBucket;
 8 @Test
 9     public void saveFile() throws FileNotFoundException{
10 
11     FileInputStream inputStream = new FileInputStream(new File("E:\xuecheng\ce.ftl"));
12     ObjectId store = gridFsTemplate.store(inputStream, "ourse", "");
13     System.out.println(store);
14 
15 }

2.取模板

配置文件

import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MongoConfig {
    @Value("${spring.data.mongodb.database}")
    String db;

    @Bean
    public GridFSBucket getGridFSBucket(MongoClient mongoClient){
         MongoDatabase database = mongoClient.getDatabase(db);
         GridFSBucket bucket = GridFSBuckets.create(database);
         return bucket;
    }
}

测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class GridsTest {
@Autowired
    private GridFsTemplate gridFsTemplate;
@Autowired
  private GridFSBucket gridFSBucket;
@Test
    public void queryFile() throws IOException{
    GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is("5cff9c915321159f")));
    GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
    GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);;
    InputStream inputStream = gridFsResource.getInputStream();
    String template = IOUtils.toString(inputStream, "utf-8");
    System.out.println(template);

}
gridFsTemplate.findOne(Query.query(Criteria.where("_id").is("5cff9c915321159f")));
HQL语句

文件id(fileId)是唯一标识

四,应用

两种页面静态化选择,我们用第二种

    //基于模版文件生成静态化文件
    @Test
    public void generateHtml() throws IOException, TemplateException {

        //声明配置类
        Configuration configuration = new Configuration(Configuration.getVersion());
        //设置默认编码
        configuration.setDefaultEncoding("utf-8");

        //获取模版
        String classpath = this.getClass().getResource("/").getPath();
        configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/"));
        Template template = configuration.getTemplate("test1.ftl");

        //获取数据
        Map map = new HashMap();
        map.put("name","黑马程序员");

        //生成静态化页面
        String htmlContentString = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);

        InputStream inputStream = IOUtils.toInputStream(htmlContentString, "utf-8");
        OutputStream outputStream = new FileOutputStream(new File("E:\xuecheng\test1.html"));
        IOUtils.copy(inputStream,outputStream);
    }

    //基于模版字符串生成静态化页面
    @Test
    public void generateHtmlByString() throws IOException, TemplateException {

        //声明配置类
        Configuration configuration = new Configuration(Configuration.getVersion());
        //设置默认编码
        configuration.setDefaultEncoding("utf-8");

        //模版
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        String content="<!DOCTYPE html>
" +
                "<html lang="en">
" +
                "<head>
" +
                "    <meta charset="UTF-8">
" +
                "    <title>Title</title>
" +
                "</head>
" +
                "<body>
" +
                "        ${name}
" +
                "
" +
                "</body>
" +
                "</html>";
        stringTemplateLoader.putTemplate("myTemplate",content);

        configuration.setTemplateLoader(stringTemplateLoader);

        Template template = configuration.getTemplate("myTemplate");

        //获取数据
        Map map = new HashMap();
        map.put("name","传智播客");

        //生成静态化页面
        String htmlContentString = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);

        InputStream inputStream = IOUtils.toInputStream(htmlContentString, "utf-8");
        OutputStream outputStream = new FileOutputStream(new File("E:\xuecheng\test2.html"));
        IOUtils.copy(inputStream,outputStream);
    }
  2.基于模版字符串生成静态化页面
servcie
/model和数据结合,生成静态化页面,根据id生成静态化页面
    public String getHtml(String pageId) {
        //获取数据
        Map model = this.getModelByPageId(pageId);
        if(model == null){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);

        }
        //获取模版
        String templateById = this.getTemplateById(pageId);
if(StringUtils.isEmpty(templateById)){
    ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);

}
//生成静态页面
        String pageHtml = this.generateHtml(model, templateById);
if (pageHtml.isEmpty()){

    ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);

}
return pageHtml;
    }
    //生成静态页面方法
    private String generateHtml(Map model,String templateString){

        Configuration configuration = new Configuration(Configuration.getVersion());
        configuration.setDefaultEncoding("utf-8");
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("myTemplate",templateString);
        configuration.setTemplateLoader(stringTemplateLoader);
        try{
            Template template = configuration.getTemplate("myTemplate");
            String pageHtml = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
            return pageHtml;
        }
        catch (Exception e){
            e.printStackTrace();
        }
    return null;
    }
    //获取模版方法
private String getTemplateById(String pageId) {
    CmsPage cmsPage = this.findOne(pageId);
    if(cmsPage == null ){
        ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
    }
    String templateId = cmsPage.getTemplateId();
    Optional<CmsTemplate> repositoryById = cmsTemplateRepository.findById(templateId);
if(!repositoryById.isPresent()){
    ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
}
    CmsTemplate cmsTemplate = repositoryById.get();
    String templateFileId = cmsTemplate.getTemplateFileId();

    GridFSFile gridFsTemplateOne = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));
    GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFsTemplateOne.getObjectId());
    GridFsResource gridFsResource=new GridFsResource(gridFsTemplateOne,gridFSDownloadStream);
    try {
        InputStream inputStream = gridFsResource.getInputStream();
        String templateContent = IOUtils.toString(inputStream);
return templateContent;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
    //获取数据
    private Map getModelByPageId(String pageId){
        CmsPage one = this.findOne(pageId);
        if (one == null) {

        ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        String dataUrl = one.getDataUrl();
        if(StringUtils.isEmpty(dataUrl)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);

        }
        ResponseEntity<Map> responseEntity = restTemplate.getForEntity(dataUrl, Map.class);
        return  responseEntity.getBody();

    }
 
当一个男人不再对你啰嗦,不再缠着你,不再没事找你,对你说话也客气了,也不再气你了。那么恭喜你,你已经成功的失去了他。别嫌弃男人幼稚,那是他喜欢你,爱你。女人说男人像小孩子一样不成熟,可又有谁知道,男人在自己喜欢的女人面前才像小孩子,如果不喜欢你了,不爱你了,他比你爸还成熟。
原文地址:https://www.cnblogs.com/fengtangjiang/p/11111203.html