1.页面静态化
1.1.为什么要使用页面静态化
程主页的访问人数非常多, 以不发请求静态页面代替要发请求静态页面或者动态页面.没有对后台数据获取。有的页面访问人数很多,但是在一定时间段内不会改变(数据没变化)所以我们要使用页面静态化.
1.2.页面静态化好处
①降低数据库或缓存压力
②提高响应速度,增强用户体验.
1.3.原型模板
静态页面=模板(结构)+数据(内容).
模板技术:freemaker,velocity,thymeleaf等
模板(velocity)+数据=静态页面(初始化,数据改变)
1.4.主要代码
pom:
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
CourseService:
/**
* 初始化站点主页
*/
void selectIndexPageInit();
impl:
@Override
public void selectIndexPageInit() {
//页面名称写死
String pageName = "CourseSiteIndex";
//准备一个保存到redis数据库的key
String dataKey = "CourseSiteIndex_data";
//从redis获取课程类型数据
List<CourseType> courseTypes = this.treeData(0L);
//对课程数据进行处理,放入redis
Map<String,Object> map = new HashMap<>();
map.put("courseTypes", courseTypes);
//调用redis并将map转换成json形式存入
redisClient.add("dataKey", JSONArray.toJSONString(map));
//最后调用模板方法生成静态化页面
pageConfigClient.staticPage(pageName, dataKey);
}
controller层调用service即可
@PostMapping("/staticIndexPageInit")
public AjaxResult staticIndexPageInit(){
try {
courseTypeService.selectIndexPageInit();
return AjaxResult.me();
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.me().setSuccess(false).setMessage("页面静态化失败!" + e.getMessage());
}
}
hrm-page-client下的PageConfigClient用于接收页面名与key
package com.penny.client;
import com.penny.util.AjaxResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "HRM-PAGE",fallbackFactory =PageConfigClientFallbackFactory.class )
@RequestMapping("/pageConfig")
public interface PageConfigClient {
/**
* 通过pageName获取模块
* 通过dataKey获取数据
* @param pageName
* @param dataKey
* @return
*/
@PostMapping("/pageStatic")
AjaxResult staticPage(
@RequestParam(value = "pageName",required = true) String pageName,
@RequestParam(value = "dataKey",required = true) String dataKey
);
}
同时提供托底类PageConfigClientFallbackFactory
package com.penny.client;
import com.penny.util.AjaxResult;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
//托底处理,实现PageConfigClient
@Component
public class PageConfigClientFallbackFactory implements FallbackFactory {
@Override
public Object create(Throwable throwable) {
return new PageConfigClient() {
@Override
public AjaxResult staticPage(String pageName, String dataKey) {
return AjaxResult.me().setSuccess(false).setMessage("静态化失败!");
}
};
}
}
IPageConfigService用来定义接收参数的接口
package com.penny.service;
import com.penny.domain.PageConfig;
import com.baomidou.mybatisplus.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author Penny
* @since 2020-02-25
*/
public interface IPageConfigService extends IService<PageConfig> {
void staticPage(String pageName,String dataKey);
}
impl(超长逻辑,偷懒不想抽取了)用来处理从redis缓存中获取数据,下载模板,上传模板等
package com.penny.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.penny.client.FastDfsClient;
import com.penny.client.RedisClient;
import com.penny.domain.PageConfig;
import com.penny.domain.Pager;
import com.penny.mapper.PageConfigMapper;
import com.penny.mapper.PagerMapper;
import com.penny.service.IPageConfigService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.penny.util.AjaxResult;
import com.penny.utils.VelocityUtils;
import com.penny.utils.ZipUtil;
import feign.Response;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import java.io.*;
import java.util.List;
import java.util.Map;
/**
* <p>
* 服务实现类
* </p>
*
* @author Penny
* @since 2020-02-25
*/
@Service
public class PageConfigServiceImpl extends ServiceImpl<PageConfigMapper, PageConfig> implements IPageConfigService {
@Autowired
private PagerMapper pagerMapper;
@Autowired
private FastDfsClient fastDfsClient;
@Autowired
private RedisClient redisClient;
@Autowired
private PageConfigMapper pageConfigMapper;
@Override
public void staticPage(String pageName, String dataKey) {
InputStream inputStream = null;
FileOutputStream fos = null;
try {
//通过pageName获取Page并从中获取模板 url(zip)+name(home.vm)
//查询page对象
List<Pager> pagers = pagerMapper.selectList(new EntityWrapper<Pager>().eq("name", pageName));
if (pagers != null || pagers.size()<1) {
return;
}
//获取所有页面
Pager pager = pagers.get(0);
//获取fastfds地址模板zip包
String templateUrl = pager.getTemplateUrl();
//从fastfds上下载模板
Response res = fastDfsClient.download("templateUrl");
//转换成流的形式
inputStream = res.body().asInputStream();
//跨操作系统存放临时文件
String tmpdir = System.getProperty("java.io.tmpdir");
String unzipFile = tmpdir+"/temp.zip";
//转换成输出流
fos = new FileOutputStream(unzipFile);
//定义解压缩文件存放路径
String unzipDir = tmpdir+"/temp/";
//解压缩
ZipUtil.unzip(unzipFile,unzipDir);
System.out.println("解压路径:" + unzipDir);
//解压路径拼接模板名称得到完整的模板地址
String templatePath = unzipDir+"/"+pager.getTemplateName();//c://temp/home.vm
System.out.println("模板路径:" + templatePath);
//通过dataKey获取数据
String jsonStr = redisClient.get(dataKey);
//获取传递的map数据
Map map = JSONObject.parseObject(jsonStr, Map.class);
// 往map里面追加参数
map.put("staticRoot", unzipDir);
//页面静态化到本地
String staticPath = templatePath+".html";
System.out.println("静态化页面地址:"+staticPath);
//生成静态化页面
VelocityUtils.staticByTemplate(map,templatePath,staticPath);
//把静态化好的页面上传到fastdfs
AjaxResult ajaxResult = fastDfsClient.upload(new CommonsMultipartFile(createFileItem(new File(staticPath))));
//存放pageConfig
PageConfig pageConfig = new PageConfig();
//设置模板地址
pageConfig.setTemplateUrl(templateUrl);
//设置模板名称
pageConfig.setTemplateName(pager.getTemplateName());
//设置dayaKey
pageConfig.setDataKey(dataKey);
//设置物理路径
pageConfig.setPhysicalPath(pager.getPhysicalPath());
//设置dfs类型
pageConfig.setDfsType(0L);
pageConfig.setPageUrl((String) ajaxResult.getResultObj()); //上传完的地址
pageConfig.setPageId(pager.getId());
pageConfigMapper.insert(pageConfig);
//发送Message到mq中
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private FileItem createFileItem(File file) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
String textFieldName = "textField";
FileItem item = factory.createItem("file", "text/plain", true, file.getName());
int bytesRead = 0;
byte[] buffer = new byte[8192];
try {
FileInputStream fis = new FileInputStream(file);
OutputStream os = item.getOutputStream();
while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
return item;
}
}
最后controller层调用service层方法即可
@PostMapping("/pageStatic")
AjaxResult staticPage(
@RequestParam(value = "pageName",required = true) String pageName,
@RequestParam(value = "dataKey",required = true)String dataKey){
try {
pageConfigService.staticPage(pageName,dataKey);
return AjaxResult.me();
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.me().setMessage("静态化失败!"+e.getMessage());
}
}