以freemarker和vue为例深入理解后端渲染、前端渲染
目录一、springboot集成freemaker demo二、echarts图表,echarts已由百度迁入apache,官网。三、vue.js 后端使用----非node环境vue-cli构建的vue使用方式 官网四、freemarker后端渲染,vue前端渲染五、案例:html转pdf的几个方案一、springboot集成freemaker demopom.xml<?xml versi
目录
二、echarts图表,echarts已由百度迁入apache,官网。
三、vue.js 后端使用----非node环境vue-cli构建的vue使用方式 官网
一、springboot集成freemaker demo
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置
spring:
freemarker:
suffix: .ftl
content-type: text/html
enabled: true
cache: false #开发阶段不缓存
charset: UTF-8
settings:
number_format: '0.##' #全局数字格式化
template-loader-path: 'classpath:/templates/'
server:
port: 8080
控制器这里不返回json数据,而是视图"demo"或modelAndView,即前后端不分离开发模式,这里返回的视图用的模板引擎可以是thymelyfe,freemarker,velocity,beetle等
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.ModelAndView;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* 前端控制器
* </p>
*
* @author haodongdong
* @since 2021-03-17
*/
@Controller
@RequestMapping("/test")
public class TestController {
@GetMapping("/t1")
public ModelAndView backendRender(){
Map map= new HashMap<String,String>();
map.put("test1","value1");
map.put("test2",null);
map.put("test3",123.456);
map.put("test4", Arrays.asList(1,2,3));
map.put("test5","{\"num\":\"123\"}");
map.put("test6",map);
Map map2= new HashMap<>();
map2.put("mymap","mymapvlue");
map.put("test7",map2);
return new ModelAndView("demo",map);
}
}
模板页面demo.ftl,默认放置在/resources/templates/下面的。该demo.ftl可以使用freemarker的一些语法及少量内建函数进行数据展示,如果需要进行js计算,则需要一些dom操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<#--如果是非基本类型,不要直接取,否则报错-->
<div>${test1}</div>
<#--html非空判断-->
<div>${test2!}</div>
<#--标签上的非空判断-->
<#if !test2??>
<div>非空判断<span>
</#if>
<#--会适用配置文件的全局设置-->
<div>${test3}</div>
<#--freemarker中有些字符串,数字处理内建函数可用-->
<div>${test3?string.percent}</div>
<#--html中遍历集合,-->
<#list test4 as item>
<span>${item}<span>
</#list>
<#--遍历map,拿到keys集合,keys为内置参数-->
<#list test6?keys as mykey>
<#if mykey=="test3">
<div>${mykey}---${test6["${mykey}"]}</div>
</#if>
</#list>
<#--遍历map,拿到values集合,values为内置参数-->
<#list test7?values as myvalue>
<div>${myvalue}</div>
</#list>
</div>
</body>
<script type="text/javascript">
/*script也可以取值,使用各种freemarker语法*/
console.log("${test1}")
console.log(${test5})
/*取json字符串的value*/
console.log(${test5}.num)
console.log(JSON.stringify(${test5}))
<#list test4 as item>
console.log(${item})
</#list>
</script>
</html>
效果图
二、echarts图表,echarts已由百度迁入apache,官网。
这里引入CDN的echarts.js资源,也可以下载echats.comom.min.js(比较小)到本地引入使用。
js部分增加 var myChart = echarts.init(document.getElementById('main'));并对该对象设置各种options属性值即可。这里用freemarker语法进行取值,更多属性设置参考官网。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<#--如果是非基本类型,不要直接取,否则报错-->
<div>${test1}</div>
<#--html非空判断-->
<div>${test2!}</div>
<#--标签上的非空判断-->
<#if !test2??>
<div>非空判断<span>
</#if>
<#--会适用配置文件的全局设置-->
<div>${test3}</div>
<#--freemarker中有些字符串,数字处理内建函数可用-->
<div>${test3?string.percent}</div>
<#--html中遍历集合,-->
<#list test4 as item>
<span>${item}<span>
</#list>
<#--遍历map,拿到keys集合,keys为内置参数-->
<#list test6?keys as mykey>
<#if mykey=="test3">
<div>${mykey}---${test6["${mykey}"]}</div>
</#if>
</#list>
<#--遍历map,拿到values集合,values为内置参数-->
<#list test7?values as myvalue>
<div>${myvalue}</div>
</#list>
<#--echarts图表-->
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="main" style="width: 600px;height:400px;float: right;margin-left: 100px" ></div>
</div>
</body>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@5.1.1/dist/echarts.min.js"></script>
<script type="text/javascript">
/*script也可以取值,使用各种freemarker语法*/
console.log("${test1}")
console.log(${test5})
/*取json字符串的value*/
console.log(${test5}.num)
console.log(JSON.stringify(${test5}))
<#list test4 as item>
console.log(${item})
</#list>
/*echarts图表js*/
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title:{
text:'分组统计'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999'
}
}
},
toolbox: {
feature: {
dataView: {show: true, readOnly: false},
magicType: {show: true, type: ['line', 'bar']},
restore: {show: true},
saveAsImage: {show: true}
}
},
legend: {
data: ['总订单数', '总消费金额', '总优惠金额','总实收金额']
},
xAxis: [
{
type: 'category',
data: [<#list test4 as item>${item},</#list>],
axisPointer: {
type: 'shadow'
}
}
],
yAxis: [
{
type: 'value',
name: '金额(元)',
min: 0,
// max: 250,
// interval: 50,
axisLabel: {
formatter: '{value}'
}
},
{
type: 'value',
name: '数量',
min: 0,
// max: 25,
// interval: 5,
axisLabel: {
formatter: '{value}'
}
}
],
series: [
{
name: '总订单数',
type: 'line',
data: 666,
},
{
name: '总消费金额',
type: 'bar',
data: 999,
markPoint: {
data: [
{type: 'max', name: '最大值'},
{type: 'min', name: '最小值'}
]
},
markLine: {
data: [
{type: 'average', name: '平均值'}
]
}
},
{
name: '总实收金额',
type: 'bar',
data: [11,22,33]
},
{
name: '总优惠金额',
type: 'bar',
yAxisIndex: 1,
data: [111,222,333]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</html>
效果图
三、vue.js 后端使用----非node环境vue-cli构建的vue使用方式 官网
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<#--如果是非基本类型,不要直接取,否则报错-->
<div>${test1}</div>
<#--html非空判断-->
<div>${test2!}</div>
<#--标签上的非空判断-->
<#if !test2??>
<div>非空判断<span>
</#if>
<#--会适用配置文件的全局设置-->
<div>${test3}</div>
<#--freemarker中有些字符串,数字处理内建函数可用-->
<div>${test3?string.percent}</div>
<#--html中遍历集合,-->
<#list test4 as item>
<span>${item}<span>
</#list>
<#--遍历map,拿到keys集合,keys为内置参数-->
<#list test6?keys as mykey>
<#if mykey=="test3">
<div>${mykey}---${test6["${mykey}"]}</div>
</#if>
</#list>
<#--遍历map,拿到values集合,values为内置参数-->
<#list test7?values as myvalue>
<div>${myvalue}</div>
</#list>
<#--echarts图表-->
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="main" style="width: 600px;height:400px;float: right;margin-left: 100px" ></div>
<#--vue数据绑定-->
<div id="myvue">{{aa}}--{{bb}}</div>
</div>
</body>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@5.1.1/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
/*script也可以取值,使用各种freemarker语法*/
console.log("${test1}")
console.log(${test5})
/*取json字符串的value*/
console.log(${test5}.num)
console.log(JSON.stringify(${test5}))
<#list test4 as item>
console.log(${item})
</#list>
/*echarts图表js*/
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title:{
text:'分组统计'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999'
}
}
},
toolbox: {
feature: {
dataView: {show: true, readOnly: false},
magicType: {show: true, type: ['line', 'bar']},
restore: {show: true},
saveAsImage: {show: true}
}
},
legend: {
data: ['总订单数', '总消费金额', '总优惠金额','总实收金额']
},
xAxis: [
{
type: 'category',
data: [<#list test4 as item>${item},</#list>],
axisPointer: {
type: 'shadow'
}
}
],
yAxis: [
{
type: 'value',
name: '金额(元)',
min: 0,
// max: 250,
// interval: 50,
axisLabel: {
formatter: '{value}'
}
},
{
type: 'value',
name: '数量',
min: 0,
// max: 25,
// interval: 5,
axisLabel: {
formatter: '{value}'
}
}
],
series: [
{
name: '总订单数',
type: 'line',
data: 666,
},
{
name: '总消费金额',
type: 'bar',
data: 999,
markPoint: {
data: [
{type: 'max', name: '最大值'},
{type: 'min', name: '最小值'}
]
},
markLine: {
data: [
{type: 'average', name: '平均值'}
]
}
},
{
name: '总实收金额',
type: 'bar',
data: [11,22,33]
},
{
name: '总优惠金额',
type: 'bar',
yAxisIndex: 1,
data: [111,222,333]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
//vue相关
var vm = new Vue({
el: '#myvue',
data: {
aa:'',
bb:'',
},
mounted(){
let data1=${test5};
this.aa=data1.num;
let data2="${test1}";
this.bb=data2
}
})
console.log(vm)
</script>
</html>
效果图
四、freemarker后端渲染,vue前端渲染
有后端返回的数据可以看到,freemarker的${xxx}语法已替换为数值,而vue的{{}}语法并没有被替换,这个是浏览器根据vue.js语法在前端完成的替换,固freemarker后端渲染,vue前端渲染。
五、案例:html转pdf的几个方案参考,参考
方案1:html转pdf,使用vue js工具库html2canvas,效果比较差,该pdf为canvas画得图片,可能会有图表截断现象;
方案2:网页另存为再使用其他三方工具转换,如果网页中有其它js如vue.js引用,则这样另存为会保存一份xx.html及一个存放三方js,css的文件夹,当然这个可以将外部引入的js,css内容全量内嵌到html页面
方案3:使用vue或freemarker生成html,使用vue.js生成的html{{}}是没有替换的,vue是前端渲染,故只能使用后端渲染技术freemarker等。如本例可以使用restemplate请求http://localhost:8080/test/t1接口获取到html字符串,下载到前端,使用其他三方工具转换为pdf,同方案二,外部js,css需要内嵌到html,比较麻烦但较方案2灵活,可以定义要下载的页面内容
更多推荐
所有评论(0)