在线预览不说了 就一个页面静态化(模型+模板=页面静态化),上篇已经说完了
说一下发布功能的实现
1、用到消息队列RabbitMq ,所以就需要先配置,建议先写消费方
server:
port: 31000
spring:
application:
name: xc-service-manage-cms-client
data:
mongodb:
uri: mongodb://root:123@localhost:27017
database: xc_cms
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
xuecheng:
mq:
#cms客户端监控的队列名称(不同的客户端监控的队列不能重复)
queue: queue_cms_postpage_01
routingKey: 5a751fab6abb5044e0d19ea1 #此routingKey为门户站点ID
2、然后写到交换机和队列的配置,我用的是直接direct,懒得弄那些花里胡哨的,要遵循三点
1、创建“ex_cms_postpage”交换机
2、每个Cms Client创建一个队列与交换机绑定
3、每个Cms Client程序配置队列名称和routingKey,将站点ID作为routingKey。
2.1先搞定配置类
1、RabbitmqConfig
package com.xuecheng.manage_cms_client.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Administrator
* @version 1.0
**/
@Configuration
public class RabbitmqConfig {
//队列bean的名称
public static final String QUEUE_CMS_POSTPAGE = "queue_cms_postpage";
//交换机的名称
public static final String EX_ROUTING_CMS_POSTPAGE="ex_routing_cms_postpage";
//队列的名称
@Value("${xuecheng.mq.queue}")
public String queue_cms_postpage_name;
//routingKey 即站点Id
@Value("${xuecheng.mq.routingKey}")
public String routingKey;
/**
* 交换机配置使用direct类型
* @return the exchange
*/
@Bean(EX_ROUTING_CMS_POSTPAGE)
public Exchange EXCHANGE_TOPICS_INFORM() {
return ExchangeBuilder.directExchange(EX_ROUTING_CMS_POSTPAGE).durable(true).build();
}
//声明队列
@Bean(QUEUE_CMS_POSTPAGE)
public Queue QUEUE_CMS_POSTPAGE() {
return new Queue(queue_cms_postpage_name);
}
/**
* 绑定队列到交换机
*
* @param queue the queue
* @param exchange the exchange
* @return the binding
*/
@Bean
public Binding BINDING_QUEUE_INFORM_SMS(@Qualifier(QUEUE_CMS_POSTPAGE) Queue queue, @Qualifier(EX_ROUTING_CMS_POSTPAGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(routingKey).noargs();
}
}
2、搞定MongConfig,因为GridFSBucket需要连接到它
package com.xuecheng.manage_cms_client.config;
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 MongConfig {
@Value("${spring.data.mongodb.database}")
String db;
@Bean
public GridFSBucket gridFSBucket(MongoClient mongoClient){
MongoDatabase database = mongoClient.getDatabase(db);
GridFSBucket bucket = GridFSBuckets.create(database);
return bucket;
}
}
再来写Service层 需要做的是定义保存页面静态文件到服务器物理路径方法
package com.xuecheng.manage_cms_client.service;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsSite;
import com.xuecheng.framework.domain.cms.response.CmsCode;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.manage_cms_client.dao.CmsPageRepository;
import com.xuecheng.manage_cms_client.dao.CmsSiteRepository;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.Optional;
@Service
public class PageService {
@Autowired
CmsPageRepository cmsPageRepository;
@Autowired
CmsSiteRepository cmsSiteRepository;
@Autowired
GridFSBucket gridFSBucket;
@Autowired
GridFsTemplate gridFsTemplate;
//页面物理路径=站点物理路径+页面物理路径+页面名称。
//将页面html保存到页面物理路径
public void savePageToServerPath(String pageId){
CmsPage cmsPage = this.findCmsPageById(pageId);
String siteId = cmsPage.getSiteId();
//页面所属站点
CmsSite cmsSite = this.getCmsSiteById(siteId);
//页面物理路径
String pagePath=cmsSite.getSitePhysicalPath()+cmsPage.getPagePhysicalPath()+cmsPage.getPageName();
//5ce15dd688cd0b03d44f028a
String htmlFileId = cmsPage.getHtmlFileId();
InputStream inputStream = this.getFileById(htmlFileId);
if (inputStream==null){
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
}
FileOutputStream fileOutputStream=null;
try {
fileOutputStream = new FileOutputStream(new File(pagePath));
try {
//InputStream input, OutputStream output
IOUtils.copy(inputStream, fileOutputStream);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//根据页面id去查询页面信息
public CmsPage findCmsPageById(String pageId){
Optional<CmsPage> optional = cmsPageRepository.findById(pageId);
if (optional.isPresent()){
return optional.get();
}
return null;
}
//根据站点id得到站点
public CmsSite getCmsSiteById(String siteId){
Optional<CmsSite> optional = cmsSiteRepository.findById(siteId);
if (optional.isPresent()){
return optional.get();
}
return null;
}
//根据文件id获取文件内容
public InputStream getFileById(String fileId){
try {
GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
//GridFSFile file, InputStream inputStream
GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
return gridFsResource.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
在写一下mq的监听,也就是消费方的关键
package com.xuecheng.manage_cms_client.mq;
import com.alibaba.fastjson.JSON;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.manage_cms_client.dao.CmsPageRepository;
import com.xuecheng.manage_cms_client.service.PageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Optional;
@Component
public class ConsumerPostPage {
private static final Logger LOGGER= LoggerFactory.getLogger(ConsumerPostPage.class);
@Autowired
PageService pageService;
@RabbitListener(queues = {"${xuecheng.mq.queue}"})
public void postPage(String msg){
//解析消息
Map map = JSON.parseObject(msg, Map.class);
LOGGER.info("receive cms post page:{}",msg.toString());
//取出页面id
String pageId = (String) map.get("pageId");
//查询页面信息
CmsPage cmsPage = pageService.findCmsPageById(pageId);
if(cmsPage == null){
LOGGER.error("receive postpage msg,cmsPage is null,pageId:{}",pageId);
return ;
}
//调用service方法将页面从GridFs中下载到服务器
pageService.savePageToServerPath(pageId);
}
}
消费方到此写完,开始写生产者,说一下需求
1、管理员进入管理界面点击“页面发布”,前端请求cms页面发布接口。
2、cms页面发布接口执行页面静态化,并将静态化页面存储至GridFS中。
3、静态化成功后,向消息队列发送页面发布的消息。
1) 获取页面的信息及页面所属站点ID。
2) 设置消息内容为页面ID。(采用json格式,方便日后扩展)
3) 发送消息给ex_cms_postpage交换机,并将站点ID作为routingKey
配置
server:
port: 31001
spring:
application:
name: xc-service-manage-cms
data:
mongodb:
uri: mongodb://root:123@localhost:27017
database: xc_cms
freemarker:
cache: false #关闭模板缓存,方便测试
settings:
template_update_delay: 0
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
MongConfig配置
package com.xuecheng.manage_cms.config;
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 MongConfig {
@Value("${spring.data.mongodb.database}")
String db;
@Bean
public GridFSBucket gridFSBucket(MongoClient mongoClient ){
MongoDatabase database=mongoClient.getDatabase(db);
GridFSBucket bucket = GridFSBuckets.create(database);
return bucket;
}
}
RabbitMQConfig只需要写交换机就可以了
package com.xuecheng.manage_cms.config;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.ExchangeBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
//交换机的名称
public static final String EX_ROUTING_CMS_POSTPAGE="ex_routing_cms_postpage";
@Bean(EX_ROUTING_CMS_POSTPAGE)
public Exchange EXCHANGE_TOPICS_INFORM(){
return ExchangeBuilder.directExchange(EX_ROUTING_CMS_POSTPAGE).durable(true).build();
}
}
生产者的生成我也贴出来了
//根据id查询配置信息
public CmsConfig getByConfigId(String id) {
Optional<CmsConfig> optional = cmsConfigRepository.findById(id);
if (optional.isPresent()) {
CmsConfig cmsConfig = optional.get();
return cmsConfig;
}
return null;
}
//页面静态化
public String getPageHtml(String pageId) {
//获取页面模型数据
Map model = getModelByPageId(pageId);
if (model == null) {
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
}
//获取页面模型
String template = getTemplateByPageId(pageId);
if (template == null) {
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
}
//执行页面静态化
String html = generateHtml(template, model);
if (StringUtils.isEmpty(html)) {
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
}
return html;
}
//1.获取页面模型数据
private Map getModelByPageId(String pageId) {
CmsPage cmsPage = findById(pageId);
if (cmsPage == null) {
//页面不存在
ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
}
String dataUrl = cmsPage.getDataUrl();
if (StringUtils.isEmpty(dataUrl)) {
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);
}
ResponseEntity<Map> forEntity = restTemplate.getForEntity(dataUrl, Map.class);
Map body = forEntity.getBody();
return body;
}
//2、获取页面模板
public String getTemplateByPageId(String pageId) {
CmsPage cmsPage = findById(pageId);
if (cmsPage == null) {
ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
}
//拿到cms_page的teplateId
String templateId = cmsPage.getTemplateId();
//根据cmstemplate来拿到files_id
Optional<CmsTemplate> optional = cmsTemplateRepository.findById(templateId);
if (optional.isPresent()) {
CmsTemplate cmsTemplate = optional.get();
String templateFileId = cmsTemplate.getTemplateFileId();
//取出模板文件内容
GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));
//打开下载流对象
GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
//获取流对象
GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
// 获取流中的数据
try {
String content = IOUtils.toString(gridFsResource.getInputStream(), "UTF-8");
return content;
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
//3.页面静态化
public String generateHtml(String template, Map model) {
try {
//生成配置类
Configuration configuration = new Configuration(Configuration.getVersion());
//模板加载器
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
stringTemplateLoader.putTemplate("template", template);
//配置模板加载器
configuration.setTemplateLoader(stringTemplateLoader);
Template template1 = configuration.getTemplate("template");
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template1, model);
return html;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//页面发布
public ResponseResult postPage(String pageId) {
//执行静态化
String pageHtml = this.getPageHtml(pageId);
//保存静态化文件
CmsPage cmsPage = this.saveHtml(pageId, pageHtml);
//发送消息
this.sendPostPage(pageId);
return new ResponseResult(CommonCode.SUCCESS);
}
//保存静态化文件
public CmsPage saveHtml(String pageId, String content) {
CmsPage cmsPage = this.findById(pageId);
if (cmsPage == null) {
ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
}
InputStream inputStream = null;
ObjectId objectId = null;
try {
inputStream = IOUtils.toInputStream(content, "UTF-8");
//InputStream var1, String var2
objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
} catch (IOException e) {
e.printStackTrace();
}
//将html文件id更新到cmspage
cmsPage.setHtmlFileId(objectId.toHexString());
cmsPageRepository.save(cmsPage);
return cmsPage;
}
public void sendPostPage(String pageId){
Map<String,String> msg=new HashMap<>();
msg.put("pageId",pageId);
String jsonString = JSON.toJSONString(msg);
CmsPage cmsPage = this.findById(pageId);
//站点id
String siteId = cmsPage.getSiteId();
//发送
rabbitTemplate.convertAndSend(RabbitMQConfig.EX_ROUTING_CMS_POSTPAGE,siteId,jsonString);
}