欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

学成在线day06,Cms页面发布功能,模块2:课程管理

程序员文章站 2022-06-13 12:31:28
...

页面发布的实现流程图:
学成在线day06,Cms页面发布功能,模块2:课程管理
技术方案说明:
1、平台包括多个站点,页面归属不同的站点。
2、发布一个页面应将该页面发布到所属站点的服务器上。
3、每个站点服务部署cms client程序,并与交换机绑定,绑定时指定站点Id为routingKey。
指定站点id为routingKey就可以实现cms client只能接收到所属站点的页面发布消息。
4、页面发布程序向MQ发布消息时指定页面所属站点Id为routingKey,将该页面发布到它所在服务器上的cms
client。
路由模式分析如下:
发布一个页面,需发布到该页面所属的每个站点服务器,其它站点服务器不发布。
比如:发布一个门户的页面,需要发布到每个门户服务器上,而用户中心服务器则不需要发布。
所以本项目采用routing模式,用站点id作为routingKey,这样就可以匹配页面只发布到所属的站点服务器上。

1.2.2创建Cms Client工程主要功能是吧页面从GridFS下载文件到本地
需要的相关jar包

<dependency>
                <groupId>com.xuecheng</groupId>
                <artifactId>xc-framework-model</artifactId>
                <version>1.0-SNAPSHOT</version>
            </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-amqp</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-mongodb</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-io</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
            </dependency>

数据配置+和日志文件:
学成在线day06,Cms页面发布功能,模块2:课程管理

server:
  port: 31000
spring:
  application:
    name: xc-service-manage-cms-client
  data:
    mongodb:
      uri:  mongodb://root:aaa@qq.comlocalhost:27017
      database: xc_cms
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    virtualHost: /
xuecheng:
  mq:
    #cms客户端监控的队列名称(不同的客户端监控的队列不能重复)
    queue: queue_cms_postpage_01
    routingKey: 5a751fab6abb5044e0d19ea1	#此routingKey为门户站点ID

说明:在配置文件中配置队列的名称,每个 cms client在部署时注意队列名称不要重复
日志文件,去前面的文档找。


3、启动类
学成在线day06,Cms页面发布功能,模块2:课程管理

@SpringBootApplication
@EntityScan("com.xuecheng.framework.domain.cms")//扫描实体类
@ComponentScan(basePackages={"com.xuecheng.framework"})//扫描common包下的类
@ComponentScan(basePackages={"com.xuecheng.manage_cms_client"})//扫描本项目下的所有类
public class ManageCmsClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ManageCmsClientApplication.class,args);
    }
}

RabbitmqConfig 队列交换机的配置类:
消息队列设置如下:
1、创建“ex_cms_postpage”交换机
2、每个Cms Client创建一个队列与交换机绑定
3、每个Cms Client程序配置队列名称和routingKey,将站点ID作为routingKey。
学成在线day06,Cms页面发布功能,模块2:课程管理

//交换机和队列的配置类
@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";
    //队列的名称QUEUE_CMS_POSTPAGE,通过配置文件的内容注入具体的队列
    @Value("${xuecheng.mq.queue}")
    public  String queue_cms_postpage_name;
    //routingKey 即站点Id
    @Value("${xuecheng.mq.routingKey}")
    public  String routingKey;

    //通过常量交换机名,创建新的交换机
    @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() {
        //注意bean的队列名,和队列名称不一样。注意看
        Queue queue = new Queue(queue_cms_postpage_name);
        return queue;
    }

    //绑定队列到交换机
    @Bean
    //通过IOC容器中的队列名和交换机名,注入名称。
        //再由队列绑定交换机,路由key设置为门户站点,扩展参数,不设置
    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();
    }
}

写页面发布需要的Dao,站点的信息库:
学成在线day06,Cms页面发布功能,模块2:课程管理
再写消息消费的监听类ConsumerPostPage:
在cms client工程的mq包下创建ConsumerPostPage类,ConsumerPostPage作为发布页面的消费客户端,监听
页面发布队列的消息,收到消息后从mongodb下载文件,保存在本地
学成在线day06,Cms页面发布功能,模块2:课程管理

@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 map = JSON.parseObject(msg, Map.class);
        //得到消息中的页面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);

    }
}

页面发布生产方

再到cms服务中的service中,加入静态化页面到GridFS服务器,发送消息,更新cmsPage页面数据的方法:

学成在线day06,Cms页面发布功能,模块2:课程管理

//页面发布的方法
    public ResponseResult post(String pageId){
        //先执行页面静态化,调用写好的静态化方法
        String pageHtml = this.getPageHtml(pageId);
        //再把静态化好的html存入gridFs文件管理器中,得到一个新的cmspage,对象
            //传入cmspage页面id,和静态化好的字符串页面
        CmsPage cmsPage = this.saveHtml(pageId, pageHtml);

        //给Mq发消息,喊他,可以去下载页面到,本地客户端的目录下了
        this.sendPostPage(pageId,cmsPage);
        //返回消息发送成功
        return new ResponseResult(CommonCode.SUCCESS);
    }

    //向mq 发送消息
    private void sendPostPage(String pageId,CmsPage cmsPage){
        //消息队列的路由key是站点id,所以需要得到站点id
        String siteId = cmsPage.getSiteId();
        //发送一个map,转的json
        Map<String,String> msg = new HashMap<>();
        //存页面id
        msg.put("pageId",pageId);
        //把map转为json字符串发送
        String jsonString = JSON.toJSONString(msg);
        //发送消息给交换机,交换机,站点id,消息内容
        rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_CMS_POSTPAGE,siteId,jsonString);
    }

    //往gridFs文件管理器中,存静态化好的html方法
    private CmsPage saveHtml(String pageId,String htmlContent){
        //查询要更新哪个cmsPage页面
        CmsPage cmsPage = this.getById(pageId);
        if (cmsPage == null) {
            //传入的参数非法
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }

        //存静态页面,先把字符串页面转换为输入流
        ObjectId objectId = null;
        try {
            InputStream inputStream = IOUtils.toInputStream(htmlContent, "utf-8");
            //通过grid模板,存输入流,页面名称存进去,取得自动生成的静态页面的id,类型为object
            objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
        } catch (IOException e) {
            e.printStackTrace();
        }
        //将html文件id更新到cmsPage中,
        cmsPage.setHtmlFileId(objectId.toHexString());
        cmsPageRepository.save(cmsPage);
        //最后在把,已经更新过FileId列id,的对象进行返回
        return cmsPage;

    }

RabbitMQ配置
1、配置Rabbitmq的连接参数
在application.yml添加如下配置:
学成在线day06,Cms页面发布功能,模块2:课程管理

注意,这个配置是在Spring之下的:
rabbitmq:
      host: 127.0.0.1
      port: 5672
      username: guest
      password: guest
      virtualHost: /

写交换机的配置类:
学成在线day06,Cms页面发布功能,模块2:课程管理

//交换机和队列的配置类
@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();
    }
}

在api工程定义页面发布接口:

//页面发布
    @ApiOperation("发布页面")
    public ResponseResult post(String pageId);

学成在线day06,Cms页面发布功能,模块2:课程管理
CmsPageController
编写Controller实现api接口,接收页面请求,调用service执行页面发布。

@Override
    @PostMapping("/postPage/{pageId}")
    public ResponseResult post(@PathVariable("pageId") String pageId) {
        return pageService.post(pageId);
    }

写页面发布前端:

用户操作流程:
1、用户进入cms页面列表。
2、点击“发布”请求服务端接口,发布页面。
3、提示“发布成功”,或发布失败。
API方法
在 cms前端添加 api方法。
学成在线day06,Cms页面发布功能,模块2:课程管理

//发布页面
export const page_postPage= (id) => {
  return http.requestPost(apiUrl+'/cms/page/postPage/'+id)
}

页面
修改page_list.vue,添加发布按钮

<el-button
            size="small"type="text"
            @click="postPage(page.row.pageId)">发布
          </el-button>

添加页面发布事件:
学成在线day06,Cms页面发布功能,模块2:课程管理

postPage (pageId) {
        this.$confirm('确认发布该页面吗?', '提示', {
        }).then(() => {
          cmsApi.page_postPage(pageId).then((res) => {
            if(res.success){
              console.log('发布页面id='+pageId);
              this.$message.success('发布成功,请稍后查看结果');
            }else{
              this.$message.error('发布失败');
            }
          });
        }).catch(() => {
        });
      },

1.6 思考
1、如果发布到服务器的页面内容不正确怎么办?
2、一个页面需要发布很多服务器,点击“发布”后如何知道详细的发布结果?
3、一个页面发布到多个服务器,其中有一个服务器发布失败时怎么办?


模块2:课程管理