文章目录
-
静态化优化方案设计
-
为什么要使用页面静态化
- 静态化好处
- 分析
-
静态页面生成时机
* 单体项目方案分析
* 集群项目架构分析- 实现准备
-
数据库
* 生成代码
* 技术准备
* Fastdfs
* Velocity -
准备模板
1
21 * 准备前端页面
2 -
页面静态化的整体流程
-
后端代码
- 前端准备
静态化优化方案设计
为什么要使用页面静态化
课程主页的访问人数非常多, 以不发请求静态页面代替要发请求静态页面或者动态页面.没有对后台数据获取.
课程详情页:只要课程信息不改,详情页就不会改变.
官网主页:一定的时间段是不可变
招聘主页:一定的时间段是不可变
职位详情:只要职位信息不改,详情页就不会改变.
有的页面访问人数很多,但是在一定时间段内不会改变(数据没变化).页面静态化.
静态化好处
降低数据库或缓存压力
提高响应速度,增强用户体验.
分析
页面静态化是这一种方案,而模板技术是实现这种方案的技术
静态页面=模板(结构)+数据(内容)
静态页面生成时机
①当部署并启动,需要在后台管理里面触发一个按钮,初始化静态页面. 初始化
②当数据(类型,广告等)发生改变后(后台做了增删改),要覆盖原来静态页面. 替换
方案:页面静态化,通过模板技术来实现.
模板技术:freemaker,velocity,thymeleaf等
单体项目方案分析
集群项目架构分析
实现准备
新建模块
hrm-page-parent
需要的配置
首先在网关中添加
然后是Swagger
数据库
为了数据库查询的一个效率 我们采用了反三范式的设计
数据库说明:
t_site:前端站点 主站 课程 职位 要做页面静态化的前端网站
t_page 页面, 在站点下面有多个页面要做静态化。 定义了模板
t_page_config 每做一次页面静态化,都要添加一个对象。一个页面一次持久化所需要数据保存。
生成代码
此处省略
技术准备
模板技术 velocity
RabbitMq
Nosql — redis
Dfs技术-fastdfs
Fastdfs
使用feign实现文件的上传和下载 放在公共的服务里面
hrm-common-common需要导入的依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1<!--客户端feign支持-->
2<dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-starter-openfeign</artifactId>
5</dependency>
6<dependency>
7 <groupId>io.github.openfeign.form</groupId>
8 <artifactId>feign-form</artifactId>
9 <version>2.1.0</version>
10</dependency>
11<dependency>
12 <groupId>io.github.openfeign.form</groupId>
13 <artifactId>feign-form-spring</artifactId>
14 <version>2.1.0</version>
15</dependency>
16
17
hrm-common-client 模块
注意 这里使用的配置是我们自己的配置
configuration = FeignMultipartSupportConfig.class
FastDfsClient.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 1@FeignClient(value = "HRM-COMMON", configuration = FeignMultipartSupportConfig.class,
2 fallbackFactory = FastDfsClientFallbackFactory.class )
3@RequestMapping("/fastDfs")
4public interface FastDfsClient {
5 //上传
6 @PostMapping(produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}
7 , consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
8 AjaxResult upload(@RequestPart(required = true,value = "file")MultipartFile file);
9
10
11 //下载 以Response来接收数据
12 @GetMapping
13 Response download(@RequestParam(required = true,value = "path") String path);
14}
15
16
FastDfsClientFallbackFactory.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 1@Component
2public class FastDfsClientFallbackFactory implements FallbackFactory<FastDfsClient> {
3 @Override
4 public FastDfsClient create(Throwable throwable) {
5 return new FastDfsClient() {
6 @Override
7 public AjaxResult upload(MultipartFile file) {
8 return new AjaxResult().setSuccess(false).setMessage("上传失败");
9 }
10
11 @Override
12 public Response download(String path) {
13 return null;
14 }
15 };
16 }
17}
18
19
FeignMultipartSupportConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 1@Configuration
2public class FeignMultipartSupportConfig {
3
4 //form编码格式
5 @Bean
6 @Primary
7 @Scope("prototype")
8 public Encoder multipartFormEncoder() {
9 return new SpringFormEncoder();
10 }
11
12 @Bean
13 public feign.Logger.Level multipartLoggerLevel() {
14 return feign.Logger.Level.FULL;
15 }
16}
17
18
hrm-common-service-2090模块 上传下载的实现
需要导入的依赖
1
2
3
4
5
6
7
8 1<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
2<dependency>
3 <groupId>commons-io</groupId>
4 <artifactId>commons-io</artifactId>
5 <version>2.4</version>
6</dependency>
7
8
实现
FastDfsController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 1@RestController
2@RequestMapping("/fastDfs")
3public class FastDfsController {
4 //crud 上传 下载(查看) 删除 修改(先删除后添加)
5 /**
6 * 参数:上传文件
7 * 返回值:成功与否,还要返回地址
8 */
9 @PostMapping(produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}
10 , consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
11 public AjaxResult upload(@RequestPart(required = true,value = "file")MultipartFile file){
12 try {
13 System.out.println(file.getOriginalFilename() + ":" + file.getSize());
14 String originalFilename = file.getOriginalFilename();
15 // xxx.jpg
16 String extName = originalFilename.substring(originalFilename.lastIndexOf(".")+1);
17 System.out.println(extName);
18 String filePath = FastDfsApiOpr.upload(file.getBytes(), extName);
19 return AjaxResult.me().setResultObj(filePath); //把上传后的路径返回回去
20 } catch (IOException e) {
21 e.printStackTrace();
22 return AjaxResult.me().setSuccess(false).setMessage("上传失败!"+e.getMessage());
23 }
24 }
25
26 //下载
27 @GetMapping
28 void download(@RequestParam(required = true,value = "path") String path, HttpServletResponse response){
29 ByteArrayInputStream bis = null;
30 ServletOutputStream outputStream = null;
31 try{
32 String pathTmp = path.substring(1); // goup1/xxxxx/yyyy
33 String groupName = pathTmp.substring(0, pathTmp.indexOf("/")); //goup1
34 String remotePath = pathTmp.substring(pathTmp.indexOf("/")+1);// xxxxx/yyyy
35 System.out.println(groupName);
36 System.out.println(remotePath);
37 byte[] data = FastDfsApiOpr.download(groupName, remotePath);
38
39
40 //以流方式直接做响应 不需要返回Response
41 bis = new ByteArrayInputStream(data);
42 outputStream = response.getOutputStream();
43 IOUtils.copy(bis,outputStream);
44 }catch (Exception e
45 ){
46 e.printStackTrace();
47 }
48 finally {
49 if (outputStream != null) {
50 try {
51 outputStream.close();
52 } catch (IOException e) {
53 e.printStackTrace();
54 }
55 }
56 if (bis != null) {
57 try {
58 bis.close();
59 } catch (IOException e) {
60 e.printStackTrace();
61 }
62 }
63 }
64 }
65 /**
66 * 参数:完整路径 /goup1/xxxxx/yyyy
67 * 返回值:成功与否,还要返回地址
68 *
69 */
70 @DeleteMapping
71 public AjaxResult del(@RequestParam(required = true,value = "path") String path){
72 String pathTmp = path.substring(1); // goup1/xxxxx/yyyy
73 String groupName = pathTmp.substring(0, pathTmp.indexOf("/")); //goup1
74 String remotePath = pathTmp.substring(pathTmp.indexOf("/")+1);// /xxxxx/yyyy
75 System.out.println(groupName);
76 System.out.println(remotePath);
77 FastDfsApiOpr.delete(groupName, remotePath);
78 return AjaxResult.me();
79 }
80}
81
82
FastDfsApiOpr.java在上一篇文章中有写到
Velocity
Velocity是一个基于java的模板引擎(template engine),它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。作为一个比较完善的模板引擎,Velocity的功能是比较强大的,但强大的同时也增加了应用复杂性。
准备模板
准备前端页面
Pager.vue
基本上的准备都已完成 接下来我们正式开始
页面静态化的整体流程
后端代码
搭建一个
hrm-page-parent模块
也是三个子模块
hrm-page-common模块放domain 和Query
导入依赖 其余两个模块也是依赖这个模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 1<dependencies>
2
3 <!--不能直接依赖starter,有自动配置,而消费者是不需要额。-->
4
5 <dependency>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-web</artifactId>
8 </dependency>
9
10 <dependency>
11 <groupId>org.springframework.boot</groupId>
12 <artifactId>spring-boot-starter-test</artifactId>
13 <scope>test</scope>
14 </dependency>
15
16 <dependency>
17 <groupId>org.leryoo</groupId>
18 <artifactId>hrm-basic-util</artifactId>
19 <version>1.0-SNAPSHOT</version>
20 </dependency>
21
22 <!--不能全部引入mybatis-plus,这是要做数据库操作,这里是不需要的,只需引入核心包解决错误而已-->
23 <dependency>
24 <groupId>com.baomidou</groupId>
25 <artifactId>mybatis-plus</artifactId>
26 <version>2.2.0</version>
27 </dependency>
28</dependencies>
29
30
hrm-page-service-2030
首先是配置文件
bootstrap.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 1spring:
2 profiles:
3 active: dev
4 cloud:
5 config:
6 name: application-page #github上面名称
7 profile: ${spring.profiles.active} #环境 java -jar -D xxx jar
8 label: master #分支
9 discovery:
10 enabled: true #从eureka上面找配置服务
11 service-id: hrm-config-server #指定服务名
12 #uri: http://127.0.0.1:1299 #配置服务器 单机配置
13eureka: #eureka不能放到远程配置中
14 client:
15 service-url:
16 defaultZone: http://localhost:1010/eureka #告诉服务提供者要把服务注册到哪儿 #单机环境
17 instance:
18 prefer-ip-address: true #显示客户端真实ip
19feign:
20 hystrix:
21 enabled: true #开启熔断支持
22 client:
23 config:
24 remote-service: #服务名,填写default为所有服务
25 connectTimeout: 3000
26 readTimeout: 3000
27hystrix:
28 command:
29 default:
30 execution:
31 isolation:
32 thread:
33 timeoutInMilliseconds: 3000
34
35
在码云的配置仓库中添加
application-page-dev.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1server:
2 port: 2030
3spring:
4 application:
5 name: hrm-page
6 datasource:
7 driver-class-name: com.mysql.jdbc.Driver
8 url: jdbc:mysql://localhost:3306/hrm-page
9 username: root
10 password: root
11mybatis-plus:
12 mapper-locations: classpath:org/leryoo/mapper/*Mapper.xml
13 type-aliases-package: org.leryoo.domain,org.leryoo.query
14
15
注意 记得要先提交到码云
然后是导入两个工具类
一个是文件解压的工具类
ZipUtil.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 1import java.io.*;
2import java.util.Enumeration;
3import java.util.zip.ZipEntry;
4import java.util.zip.ZipException;
5import java.util.zip.ZipFile;
6import java.util.zip.ZipOutputStream;
7
8public final class ZipUtil
9{
10
11 /**
12 * 缓冲大小
13 */
14 private static int BUFFERSIZE = 2 << 10;
15
16 /**
17 * 压缩
18 * @param paths
19 * @param fileName
20 */
21 public static void zip(String[] paths, String fileName)
22 {
23
24 ZipOutputStream zos = null;
25 try
26 {
27 zos = new ZipOutputStream(new FileOutputStream(fileName));
28 for(String filePath : paths)
29 {
30 //递归压缩文件
31 File file = new File(filePath);
32 String relativePath = file.getName();
33 if(file.isDirectory())
34 {
35 relativePath += File.separator;
36 }
37 zipFile(file, relativePath, zos);
38 }
39 }
40 catch (IOException e)
41 {
42 e.printStackTrace();
43 }
44 finally
45 {
46 try
47 {
48 if(zos != null)
49 {
50 zos.close();
51 }
52 }
53 catch (IOException e)
54 {
55 e.printStackTrace();
56 }
57 }
58 }
59
60 public static void zipFile(File file, String relativePath, ZipOutputStream zos)
61 {
62 InputStream is = null;
63 try
64 {
65 if(!file.isDirectory())
66 {
67 ZipEntry zp = new ZipEntry(relativePath);
68 zos.putNextEntry(zp);
69 is = new FileInputStream(file);
70 byte[] buffer = new byte[BUFFERSIZE];
71 int length = 0;
72 while ((length = is.read(buffer)) >= 0)
73 {
74 zos.write(buffer, 0, length);
75 }
76 zos.flush();
77 zos.closeEntry();
78 }
79 else
80 {
81 for(File f: file.listFiles())
82 {
83 zipFile(f, relativePath + f.getName() + File.separator, zos);
84 }
85 }
86 }
87 catch (IOException e)
88 {
89 e.printStackTrace();
90 }
91 finally
92 {
93 try
94 {
95 if(is != null)
96 {
97 is.close();
98 }
99 }
100 catch (IOException e)
101 {
102 e.printStackTrace();
103 }
104 }
105 }
106
107 /**
108 * 解压缩
109 * @param fileName
110 * @param path
111 */
112 public static void unzip(String fileName, String path)
113 {
114 FileOutputStream fos = null;
115 InputStream is = null;
116 try
117 {
118 ZipFile zf = new ZipFile(new File(fileName));
119 Enumeration en = zf.entries();
120 while (en.hasMoreElements())
121 {
122 ZipEntry zn = (ZipEntry) en.nextElement();
123 if (!zn.isDirectory())
124 {
125 is = zf.getInputStream(zn);
126 File f = new File(path + zn.getName());
127 File file = f.getParentFile();
128 file.mkdirs();
129 fos = new FileOutputStream(path + zn.getName());
130 int len = 0;
131 byte bufer[] = new byte[BUFFERSIZE];
132 while (-1 != (len = is.read(bufer)))
133 {
134 fos.write(bufer, 0, len);
135 }
136 fos.close();
137 }
138 }
139 }
140 catch (ZipException e)
141 {
142 e.printStackTrace();
143 }
144 catch (IOException e)
145 {
146 e.printStackTrace();
147 }
148 finally
149 {
150 try
151 {
152 if(null != is)
153 {
154 is.close();
155 }
156 if(null != fos)
157 {
158 fos.close();
159 }
160 }
161 catch (IOException e)
162 {
163 e.printStackTrace();
164 }
165 }
166 }
167
168 /**
169 * @param args
170 */
171// public static void main(String[] args)
172// {
173// //zip(new String[] {"D:/tmp/20150418/logs/file/2015-08-28/debug-log.log","D:/tmp/20150418/logs/file/2015-08-28/error-log.log"}, "D:/tmp/20150418/logs/file/2015-08-28/test.zip");
174// //unzip("D://tmep.zip", "D:/temp/");
175//
176// Map<String, Object> modelMap = new HashMap<>(); //封装两个参数作为一个对象传入进去
177// String templatePagePath = "D://temp/home.vm.html"; //本地静态页面地址
178// String staticRoot = "D://temp/";
179// modelMap.put("staticRoot", staticRoot);
180// modelMap.put("courseTypes", null);
181// VelocityUtils.staticByTemplate(modelMap,"D://temp/home.vm",templatePagePath); //进行页面静态化
182// }
183}
184
185
一个是生成静态页面的工具类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 1package org.leryoo.utils;
2
3import org.apache.velocity.Template;
4import org.apache.velocity.VelocityContext;
5import org.apache.velocity.app.Velocity;
6import org.apache.velocity.app.VelocityEngine;
7
8import java.io.*;
9import java.util.Properties;
10
11public class VelocityUtils {
12 private static Properties p = new Properties();
13 static {
14 p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "");
15 p.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
16 p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
17 p.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
18 }
19
20 /**
21 * 返回通过模板,将model中的数据替换后的内容
22 * @param model
23 * @param templateFilePathAndName
24 * @return
25 */
26 public static String getContentByTemplate(Object model, String templateFilePathAndName){
27 try {
28 Velocity.init(p);
29 Template template = Velocity.getTemplate(templateFilePathAndName);
30 VelocityContext context = new VelocityContext();
31 context.put("model", model);
32 StringWriter writer = new StringWriter();
33 template.merge(context, writer);
34 String retContent = writer.toString();
35 writer.close();
36 return retContent;
37 } catch (Exception e) {
38 e.printStackTrace();
39 }
40 return "";
41 }
42
43 /**
44 * 根据模板,静态化model到指定的文件 模板文件中通过访问model来访问设置的内容
45 *
46 * @param model
47 * 数据对象
48 * @param templateFilePathAndName
49 * 模板文件的物理路径
50 * @param targetFilePathAndName
51 * 目标输出文件的物理路径
52 */
53 public static void staticByTemplate(Object model, String templateFilePathAndName, String targetFilePathAndName) {
54 try {
55 Velocity.init(p);
56 Template template = Velocity.getTemplate(templateFilePathAndName);
57
58 VelocityContext context = new VelocityContext();
59 context.put("model", model);
60 FileOutputStream fos = new FileOutputStream(targetFilePathAndName);
61 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, "UTF-8"));// 设置写入的文件编码,解决中文问题
62 template.merge(context, writer);
63 writer.close();
64 } catch (Exception e) {
65 e.printStackTrace();
66 }
67 }
68
69 /**
70 * 静态化内容content到指定的文件
71 *
72 * @param content
73 * @param targetFilePathAndName
74 */
75 public static void staticBySimple(Object content, String targetFilePathAndName) {
76 VelocityEngine ve = new VelocityEngine();
77 ve.init(p);
78 String template = "${content}";
79 VelocityContext context = new VelocityContext();
80 context.put("content", content);
81 StringWriter writer = new StringWriter();
82 ve.evaluate(context, writer, "", template);
83 try {
84 FileWriter fileWriter = new FileWriter(new File(targetFilePathAndName));
85 fileWriter.write(writer.toString());
86 fileWriter.close();
87 } catch (IOException e) {
88 e.printStackTrace();
89 }
90 }
91}
92
93
然后写一个静态化的全家桶
Controller层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1@Autowired
2private IPageConfigService pageConfigService;
3
4@PostMapping("/pageStatic")
5AjaxResult staticPage(
6 @RequestParam(value = "pageName",required = true) String pageName,
7 @RequestParam(value = "dataKey",required = true)String dataKey){
8 try {
9 pageConfigService.staticPage(pageName,dataKey);
10 return AjaxResult.me();
11 } catch (Exception e) {
12 e.printStackTrace();
13 return AjaxResult.me().setMessage("静态化失败!"+e.getMessage());
14 }
15}
16
17
Service层 也是整个页面静态化的核心
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 1package org.leryoo.service.impl;
2
3import com.alibaba.fastjson.JSONObject;
4import com.baomidou.mybatisplus.mapper.EntityWrapper;
5import com.baomidou.mybatisplus.service.impl.ServiceImpl;
6import feign.Response;
7import org.apache.commons.fileupload.FileItem;
8import org.apache.commons.fileupload.FileItemFactory;
9import org.apache.commons.fileupload.disk.DiskFileItemFactory;
10import org.apache.commons.io.IOUtils;
11import org.leryoo.client.FastDfsClient;
12import org.leryoo.client.RedisClient;
13import org.leryoo.domain.PageConfig;
14import org.leryoo.domain.Pager;
15import org.leryoo.mapper.PageConfigMapper;
16import org.leryoo.mapper.PagerMapper;
17import org.leryoo.service.IPageConfigService;
18import org.leryoo.util.AjaxResult;
19import org.leryoo.utils.VelocityUtils;
20import org.leryoo.utils.ZipUtil;
21import org.springframework.beans.factory.annotation.Autowired;
22import org.springframework.stereotype.Service;
23import org.springframework.web.multipart.commons.CommonsMultipartFile;
24
25import java.io.*;
26import java.util.List;
27import java.util.Map;
28
29/**
30 * <p>
31 * 服务实现类
32 * </p>
33 *
34 * @author yhptest
35 * @since 2020-02-24
36 */
37@Service
38public class PageConfigServiceImpl extends ServiceImpl<PageConfigMapper, PageConfig> implements IPageConfigService {
39
40
41 @Autowired
42 private PagerMapper pagerMapper;
43
44 @Autowired
45 private FastDfsClient fastDfsClient;
46
47 @Autowired
48 private RedisClient redisClient;
49
50 @Autowired
51 private PageConfigMapper pageConfigMapper;
52 //正在做页面静态化
53 @Override //courseTypes- xxx jobTypes=yyy
54 public void staticPage(String pageName, String dataKey){
55 InputStream inputStream = null;
56 FileOutputStream os = null;
57 try{
58 //一 通过pageName获取Page并从中获取模板 url(zip)+name(home.vm)
59 //1.1 查询page对象
60 List<Pager> pagers = pagerMapper.selectList(new EntityWrapper<Pager>().eq("name", pageName));
61 if (pagers == null || pagers.size()<1) return;
62 Pager pager = pagers.get(0);
63 //1.2 获取模板zip包,它是fastdfs的地址
64 String templateUrl = pager.getTemplateUrl();
65 //1.3 使用fastdfsclient下载它
66 Response response = fastDfsClient.download(templateUrl);
67 inputStream = response.body().asInputStream();
68 String tmpdir=System.getProperty("java.io.tmpdir"); //跨操作系统
69 String unzipFile = tmpdir+"/temp.zip";
70 os = new FileOutputStream(unzipFile);
71 IOUtils.copy(inputStream, os);
72 System.out.println("下载路径:" + unzipFile);
73 //1.4 解压缩
74 String unzipDir = tmpdir+"/temp/";
75 ZipUtil.unzip(unzipFile,unzipDir);
76 System.out.println("解压路径:" + unzipDir);
77 //1.5 解压路径拼接模板名称得到完整的模板地址
78 String tempatePath = unzipDir+"/"+pager.getTemplateName(); //c://temp/home.vm
79 System.out.println("模板路径:" + tempatePath);
80 //二 通过dataKey获取数据
81 //{"courseTypes":[]}
82 String jsonStr = redisClient.get(dataKey);
83 Map model = JSONObject.parseObject(jsonStr,Map.class); //获取传递的map数据
84 //{"courseTypes":[],"staticRoot":"xxx"}
85 model.put("staticRoot",unzipDir); // 往map里面追加参数
86 //三 做页面静态化到本地
87 String staticPath = tempatePath+".html";//c://temp/home.vm.html
88 System.out.println("静态化页面地址:"+staticPath);
89 VelocityUtils.staticByTemplate(model,tempatePath,staticPath);
90
91 //四 把静态化好的页面上传到fast dfs
92 AjaxResult ajaxResult = fastDfsClient
93 .upload(new CommonsMultipartFile(createFileItem(new File(staticPath))));
94
95 //五 存放pageConfig
96 PageConfig pageConfig = new PageConfig();
97 pageConfig.setTemplateUrl(templateUrl);
98 pageConfig.setTemplateName(pager.getTemplateName());
99 pageConfig.setDataKey(dataKey);
100 pageConfig.setPhysicalPath(pager.getPhysicalPath());
101 pageConfig.setDfsType(0L); //0表示fastDfs
102 pageConfig.setPageUrl((String) ajaxResult.getResultObj()); //上传完的地址
103 pageConfig.setPageId(pager.getId());
104 pageConfigMapper.insert(pageConfig);
105 //@TODO 六 发送Message到mq中
106 }catch (Exception e){
107 e.printStackTrace();
108 }finally {
109
110 if (os != null) {
111 try {
112 os.close();
113 } catch (IOException e) {
114 e.printStackTrace();
115 }
116 }
117 if (inputStream != null) {
118 try {
119 inputStream.close();
120 } catch (IOException e) {
121 e.printStackTrace();
122 }
123 }
124 }
125
126 }
127
128 /*
129创建FileItem
130*/
131 private FileItem createFileItem(File file) {
132 FileItemFactory factory = new DiskFileItemFactory(16, null);
133 String textFieldName = "textField";
134 FileItem item = factory.createItem("file", "text/plain", true, file.getName());
135 int bytesRead = 0;
136 byte[] buffer = new byte[8192];
137 try {
138 FileInputStream fis = new FileInputStream(file);
139 OutputStream os = item.getOutputStream();
140 while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
141 os.write(buffer, 0, bytesRead);
142 }
143 os.close();
144 fis.close();
145 } catch (IOException e) {
146 e.printStackTrace();
147 }
148 return item;
149 }
150
151}
152
153
154
hrm-page-client
page客户端 通过feign完成服务之间的调用 将这个服务暴露出去
导入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13 1<dependency>
2 <groupId>org.leryoo</groupId>
3 <artifactId>hrm-page-common</artifactId>
4 <version>1.0-SNAPSHOT</version>
5</dependency>
6
7<!--客户端feign支持-->
8<dependency>
9 <groupId>org.springframework.cloud</groupId>
10 <artifactId>spring-cloud-starter-openfeign</artifactId>
11</dependency>
12
13
PageConfigClient.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1@FeignClient(value = "HRM-PAGE",fallbackFactory = PageConfigClientFallbackFactory.class )//服务提供
2@RequestMapping("/pageConfig")
3public interface PageConfigClient {
4 /**
5 * 有了pageName就可以获取模块
6 * 有了datakey就可以获取数据
7 * @param pageName
8 * @param dataKey
9 * @return
10 */
11 @PostMapping("/pageStatic")
12 AjaxResult staticPage(
13 @RequestParam(value = "pageName",required = true) String pageName,
14 @RequestParam(value = "dataKey",required = true)String dataKey);
15}
16
17
PageConfigClientFallbackFactory.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14 1@Component
2public class PageConfigClientFallbackFactory implements FallbackFactory<PageConfigClient> {
3 @Override
4 public PageConfigClient create(Throwable throwable) {
5 return new PageConfigClient() {
6 @Override
7 public AjaxResult staticPage(String pageName, String dataKey) {
8 return AjaxResult.me().setSuccess(false).setMessage("静态化失败!");
9 }
10 };
11 }
12}
13
14
前端准备
我们可以通过页面点击按钮 或者测试方法生成静态页面 这里我们选择用页面点击按钮的方式
首先 我们先创建一个页面 只加一个按钮
前端代码
课程中心的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1/**
2 * 页面静态化方法
3 */
4@PostMapping("/staticIndexPageInit")
5public AjaxResult staticIndexPageInit()
6{
7 try{
8 courseTypeService.staticIndexPageInit();
9 //调用页面静态化的逻辑
10 return AjaxResult.me();
11 }catch (Exception e){
12 e.printStackTrace();
13 return AjaxResult.me().setSuccess(false).setMessage(e.getMessage());
14 }
15}
16
17
Service层 通过feign去调用page模块的方法 完成静态页面的生成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 1@Override
2public void staticIndexPageInit() {
3
4 //1页面名称写死,约定大于配置
5 String pageName = "CourseSiteIndex";
6
7 //2 需要一个保存到redis数据库的key
8 String dataKey="CourseSiteIndex_data";
9 //本来就是从redis获取,还要在放一次,其他页面静态化的场景不一定有缓冲
10 List<CourseType> courseTypes = this.treeData(0L);
11 //课程处理
12 Map<String,Object> courseTypeSdata = new HashMap<>();
13 courseTypeSdata.put("courseTypes",courseTypes);
14 //职位
15 redisClient.add(dataKey, JSONArray.toJSONString(courseTypeSdata)); //{courseTypes:[]}
16
17 //3 调用方法模板+数据=静态页面
18 pageConfigClient.staticPage(pageName,dataKey);
19}
20
21
然后点击按钮 就会在临时文件夹里生成
这也就ok了