第一天CMS服务端开发

一、CMS需求分析

1.1 什么是CMS

CMS (Content Management System)即内容管理系统,不同的项目对CMS的定位不同,比如:一个在线教育网站,有些公司认为CMS系统是对所有的课程资源进行管理,而在早期网站刚开始盛行时很多公司的业务是网站制作,当时对CMS的定位是创建网站,即对网站的页面、图片等静态资源进行管理。

CMS有哪些类型?上边也谈到每个公司对每个项目的CMS定位不同,CMS基本上分为:针对后台数据内容的管理、针对前端页面的管理、针对样式风格的管理等 。比如:一个给企业做网站的公司,其CMS系统主要是网站页面管理及样式风格的管理

本项目作为一个大型的在线教育平台,对CMS系统的定位是对各个网站(子站点)页面的管理,主要管理由于运营需要而经常变动的页面,从而实现根据运营需要快速进行页面开发、上线的需求。

1.2 静态门户工程搭建

本项目CMS是对页面进行管理,对页面如何进行管理呢?我们首先搭建学成网的静态门户工程,根据门户的页面结构来分析页面的管理方案。

门户,是一个网站的入口,一般网站都有一个对外的门户,学成在线门户效果图如下

第一天CMS服务端开发

1.2.1 静态原型导入

下载地址:

1.2.2 nginx反向代理

nginx配置文件中添加:

第一天CMS服务端开发

修改host文件:

127.0.0.1 www.xuecheng.com

1.3 SSI服务端包含技术

1、页面内容多如何进行管理?

将页面拆分成一个个小的页面,通过CMS去管理这些小页面,当要更改部分页面内容时只需要更改具体某个小页面即可。

2、页面拆出来怎么样通过web服务浏览呢?

使用web服务(例如nginx)的SSI技术,将多个子页面合并渲染输出。

3、什么是SSI?

服务器端嵌入:Server Side Include,是一种类似于ASP的基于服务器的网页制作技术。大多数(尤其是基于Unix平台)的WEB服务器如Netscape Enterprise Server等均支持SSI命令。

4、SSI的原理

将内容发送到浏览器之前,可以使用“服务器端包含 (SSI)”指令将文本、图形或应用程序信息包含到网页中。例如,可以使用 SSI 包含时间/日期戳、版权声明或供客户填写并返回的表单。对于在多个文件中重复出现的文本或图形,使用包含文件是一种简便的方法。将内容存入一个包含文件中即可,而不必将内容输入所有文件。通过一个非常简单的语句即可调用包含文件,此语句指示 Web 服务器将内容插入适当网页。而且,使用包含文件时,对内容的所有更改只需在一个地方就能完成。因为包含 SSI 指令的文件要求特殊处理,所以必须为所有 SSI 文件赋予 SSI 文件扩展名。默认扩展名是 .stm、.shtm 和 .shtml

ssi指令如下:

<!‐‐#include virtual="/../....html"‐‐>

5、将首页拆分:

index.html:首页主体内容
include/header.html:头部区
include/index_banner.html:轮播图
include/index_category.html:左侧列表导航
include/footer.html:页尾

6、在nginx中配置SSI

第一天CMS服务端开发

SSI的配置参数如下:

ssi on:开启ssi支持

ssi_silent_errors on:默认为off,设置为on则在处理SSI文件出错时不输出错误信息

ssi_types:默认为ssi_types text/html,如果需要支持shtml(服务器执行脚本,类似于jsp)则需要设置为ssi_types text/shtml

1.4 CMS页面管理需求

1、这些页面的管理流程是什么

1)创建站点:一个网站有很多子站点,比如:学成在线有主门户、学习中心、问答系统等子站点。具体的哪个页面是归属于具体的站点,所以要管理页面,先要管理页面所属的站点。

2)创建模板:页面如何创建呢?比如电商网站的商品详情页面,每个页面的内容布局、板式是相同的,不同的只是内容,这个页面的布局、板式就是页面模板,模板+数据就组成一个完整的页面,最终要创建一个页面文件需要先定义此页面的模板,最终拿到页面的数据再结合模板就拼装成一个完整的页面。

3)创建页面:创建页面是指填写页面的基本信息,如:页面的名称、页面的url地址等。

4)页面预览:页面预览是页面发布前的一项工作,页面预览使用静态化技术根据页面模板和数据生成页面内容,并通览页面。页面发布前进行页面预览的目的是为了保证页面发布后的正确性。

5)页面发布:将页面发送到页面所在站点的服务器,页面发布成功就可以通过浏览器来访问了。

2、本项目要实现什么样的功能?

1)页面管理

管理员在后台添加、修改、删除页面信息

2)页面预览

管理员通过页面预览功能预览页面发布后的效果。

3)页面发布

管理员通过页面发布功能将页面发布到远程门户服务器。

页面发布成功,用户即可在浏览器浏览到最新发布的页面,整个页面添加、发布的过程由软件自动执行,无需人工登录服务器操作。

二、CMS服务端工程搭建

2.1 导入基础工程

2.1.1 工程结构

CMS及其它服务端工程基于maven进行构建,首先需要创建如下基础工程:

parent工程:父工程,提供依赖管理。

common工程:通用工程,提供各层封装。

model工程:模型工程,提供统一的模型类管理。

utils工程:工具类工程,提供本项目所使用的工具类

api工程:接口工程,统一管理本项目的服务接口。

工程结果如下:

第一天CMS服务端开发

2.1.2 基础工程

第一天CMS服务端开发

2.2 MongoDB数据导入

第一天CMS服务端开发

三、页面查询接口定义

3.1 定义模型

3.1.1 需求分析

定义页面查询接口,本接口供前端请求查询页面列表,支持分页及自定义条件查询方式。

具体需求如下:

  1. 分页查询CmsPage集合下的数据
  2. 根据站点Id、模板Id、页面别名查询页面信息
  3. 接口基于Http Get请求,响应Json数据

3.1.2 模型类介绍

接口的定义离不开数据模型,根据前边对需求的分析,整个页面管理模块的数据模型如下:

第一天CMS服务端开发

CmsSite:站点模型

@Data
@ToString
@Document(collection = "cms_site")
public class CmsSite {

    //站点ID
    @Id
    private String siteId;
    //站点名称
    private String siteName;
    //站点名称
    private String siteDomain;
    //站点端口
    private String sitePort;
    //站点访问地址
    private String siteWebPath;
    //创建时间
    private Date siteCreateTime;

}

CmsTemplate:页面模型

@Data
@ToString
@Document(collection = "cms_template")
public class CmsTemplate {

    //站点ID
    private String siteId;
    //模版ID
    @Id
    private String templateId;
    //模版名称
    private String templateName;
    //模版参数
    private String templateParameter;

    //模版文件Id
    private String templateFileId;
}

CmsPage:页面信息

@Data
@ToString
@Document(collection = "cms_page")
public class CmsPage {
    /**
     * 页面名称、别名、访问地址、类型(静态/动态)、页面模版、状态
     */
    //站点ID
    private String siteId;
    //页面ID
    @Id
    private String pageId;
    //页面名称
    private String pageName;
    //别名
    private String pageAliase;
    //访问地址
    private String pageWebPath;
    //参数
    private String pageParameter;
    //物理路径
    private String pagePhysicalPath;
    //类型(静态/动态)
    private String pageType;
    //页面模版
    private String pageTemplate;
    //页面静态化内容
    private String pageHtml;
    //状态
    private String pageStatus;
    //创建时间
    private Date pageCreateTime;
    //模版id
    private String templateId;
    //参数列表
    private List<CmsPageParam> pageParams;
    //模版文件Id
//    private String templateFileId;
    //静态文件Id
    private String htmlFileId;
    //数据Url
    private String dataUrl;

}

属性说明:

1、定义一个页面需要指定页面所属站点

一个站点包括多个页面,比如:学成在线的门户站点包括了多个页面

2、定义一个页面需要指定页面使用的模板

多个页面可以使用相同的模板,比如:商品信息模板,每个商品就是一个页面,所有商品使用同一个商品信息模板

3.2 定义接口

3.2.1 定义请求及响应类型

定义请求模型QueryPageRequest,对可能的请求参数进行统一封装,作为查询的条件类型。为了后期便于扩展,请求类型统一继承RequestData类型。

package com.xuecheng.framework.domain.cms.request;

import com.xuecheng.framework.model.request.RequestData;
import lombok.Data;

/**
 * @Author: 98050
 * @Time: 2019-03-19 14:43
 * @Feature:
 */
@Data
public class QueryPageRequest extends RequestData {

    private String siteId;
    private String pageId;
    private String pageName;
    private String pageAlias;
    private String templateId;
}

响应结果类型,分页查询统一使用QueryResponseResult。

package com.xuecheng.framework.model.response;

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class QueryResponseResult extends ResponseResult {

    QueryResult queryResult;

    public QueryResponseResult(ResultCode resultCode,QueryResult queryResult){
        super(resultCode);
       this.queryResult = queryResult;
    }

}

3.2.2 定义接口

在api接口工程专门定义接口,一方面可以将接口进行集中管理,另一方面方便各种微服务进行调用。

页面查询接口如下:

package com.xuecheng.api.cms;

import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.model.response.QueryResponseResult;

/**
 * @Author: 98050
 * @Time: 2019-03-19 15:00
 * @Feature: 页面查询接口
 */
public interface CmsPageControllerApi {
    /**
     * 页面分页查询
     * @param page 页码
     * @param size 页大小
     * @param queryPageRequest  查询参数
     * @return
     */
    QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest);
}

以后在CMS服务工程编写Controller类实现此接口。

3.3 返回结果封装

返回结果包含什么?

状态码和数据集

3.3.1 返回状态码

package com.xuecheng.framework.model.response;

/**
 *
 * @author 98050
 * 10000-- 通用错误代码
 * 22000-- 媒资错误代码
 * 23000-- 用户中心错误代码
 * 24000-- cms错误代码
 * 25000-- 文件系统
 */
public interface ResultCode {
    /**
     * 操作是否成功,true为成功,false操作失败
     * @return
     */
    boolean success();

    /**
     * 操作代码
     * @return
     */
    int code();

    /**
     * 返回提示信息
     * @return
     */
    String message();

}

实现:

package com.xuecheng.framework.model.response;

import lombok.ToString;

/**
 * @Author: 98050
 * @Modified By:
 */

@ToString
public enum CommonCode implements ResultCode{
    /**
     * 操作成功
     */
    SUCCESS(true,10000,"操作成功!"),
    /**
     * 操作失败
     */
    FAIL(false,11111,"操作失败!"),
    UNAUTHENTICATED(false,10001,"此操作需要登陆系统!"),
    UNAUTHORISE(false,10002,"权限不足,无权操作!"),
    SERVER_ERROR(false,99999,"抱歉,系统繁忙,请稍后重试!");
//    private static ImmutableMap<Integer, CommonCode> codes ;
    /**
     * 操作是否成功
     */
    boolean success;
    /**
     * 操作代码
     */
    int code;
    /**
     * 提示信息
     */
    String message;

    CommonCode(boolean success,int code, String message){
        this.success = success;
        this.code = code;
        this.message = message;
    }

    @Override
    public boolean success() {
        return success;
    }
    @Override
    public int code() {
        return code;
    }

    @Override
    public String message() {
        return message;
    }


}

3.3.2 返回数据结果

查询结果封装

package com.xuecheng.framework.model.response;

import lombok.Data;
import lombok.ToString;

import java.util.List;

/**
 * @Author: 98050
 */
@Data
@ToString
public class QueryResult<T> {
    /**
     * 数据列表
     */
    private List<T> list;
    /**
     * 数据总数
     */
    private long total;
}

一个接收泛型的list,还有就是数据总数。

3.3.3 返回接口

返回成功还是失败,附带具体的状态码

package com.xuecheng.framework.model.response;

/**
 *
 * @author 9805
 */
public interface Response {
     boolean SUCCESS = true;
     int SUCCESS_CODE = 10000;
}

实现

package com.xuecheng.framework.model.response;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 * @Author: 9805
 * @Description: 返回结果封装
 */
@Data
@ToString
@NoArgsConstructor
public class ResponseResult implements Response {

    /**
     * 操作是否成功
     */
    boolean success = SUCCESS;

    /**
     * 操作代码
     */
    int code = SUCCESS_CODE;

    /**
     * 提示信息
     */
    String message;

    public ResponseResult(ResultCode resultCode){
        this.success = resultCode.success();
        this.code = resultCode.code();
        this.message = resultCode.message();
    }

    public static ResponseResult SUCCESS(){
        return new ResponseResult(CommonCode.SUCCESS);
    }
    public static ResponseResult FAIL(){
        return new ResponseResult(CommonCode.FAIL);
    }

}

3.3.4 返回结果

返回的状态码+查询结果

四、页面查询服务端开发

4.1 创建CMS服务工程

4.1.1 创建CMS工程结构

创建maven工程,CMS工程的名称为xc-service-manage-cms,父工程为xc-framework-parent。

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>xc-framework-parent</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../xc-framework-parent/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>xc-service-manage-cms</artifactId>

    <dependencies>
        <!--基础工程依赖导入-->
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-service-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-framework-model</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-framework-utils</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-framework-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!--开发依赖导入-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

        <!--mongodb-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

        <!--消息中间件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

        <!--HTTP客户端-->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
</project>

包结构:

第一天CMS服务端开发

application.yml配置文件:

server:
  port: 31001
spring:
  application:
    name: xc-service-manage-cms
  data:
    mongodb:
      uri: mongodb://root:[email protected]:27017
      database: xc_cms

日志配置文件:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>
    <!--定义日志文件的存储地址,使用绝对路径-->
    <property name="LOG_HOME" value="d:/logs"/>

    <!-- Console 输出设置 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- 按照每天生成日志文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <fileNamePattern>${LOG_HOME}/xc.%d{yyyy-MM-dd}.log</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 异步输出 -->
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>512</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="FILE"/>
    </appender>


    <logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>
    <logger name="org.springframework.boot" level="DEBUG"/>
    <root level="info">
        <!--<appender-ref ref="ASYNC"/>-->
        <appender-ref ref="FILE"/>
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

创建SpringBoot启动类

package com.xuecheng.managecms;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
/**
 * 扫描实体类
 */
@EntityScan("com.xuecheng.framework.domain.cms")
/**
 * 扫描接口
 */
@ComponentScan(basePackages = {"com.xuecheng.api"})
/**
 * 扫描本项目下的所有包
 */
@ComponentScan(basePackages = {"com.xuecheng.managecms"})
/**
 * @Author: 98050
 * @Time: 2019-03-19 18:58
 * @Feature: CMS服务启动器
 */
public class ManageCmsApplication {

    public static void main(String[] args) {
        SpringApplication.run(ManageCmsApplication.class,args);
    }
}

4.1.2 测试Controller

package com.xuecheng.managecms.controller;

import com.xuecheng.api.cms.CmsPageControllerApi;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: 98050
 * @Time: 2019-03-19 19:06
 * @Feature:
 */
@RestController
@RequestMapping("/cms/page")
public class CmsPageController implements CmsPageControllerApi {

    @Override
    @GetMapping("/list/{page}/{size}")
    public QueryResponseResult findList(@PathVariable("page") int page, @PathVariable("size") int size, QueryPageRequest queryPageRequest) {
        QueryResult<CmsPage> queryResult = new QueryResult<>();
        queryResult.setTotal(2);
        List<CmsPage> list = new ArrayList<>();
        CmsPage cmsPage = new CmsPage();
        cmsPage.setPageName("测试页面");
        list.add(cmsPage);
        queryResult.setList(list);
        QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS, queryResult);
        return queryResponseResult;
    }
}

结果:

第一天CMS服务端开发

4.2 Dao

4.2.1 分页查询测试

4.2.1.1 定义Dao接口

创建Dao,继承MongoRepository,并指定实体类型和主键类型

package com.xuecheng.managecms.dao;

import com.xuecheng.framework.domain.cms.CmsPage;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 * @Author: 98050
 * @Time: 2019-03-19 22:10
 * @Feature: mongodb  dao
 */
public interface CmsPageRepository extends MongoRepository<CmsPage,String> {
}

4.2.1.2 编写测试类

package com.xuecheng.managecms;

import com.xuecheng.managecms.dao.CmsPageRepository;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Author: 98050
 * @Time: 2019-03-20 14:12
 * @Feature: 测试类
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class CmsPageRepositoryTest {
    @Autowired
    private CmsPageRepository cmsPageRepository;
}

4.2.1.3 分页查询测试

package com.xuecheng.managecms;

import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsPageParam;
import com.xuecheng.managecms.dao.CmsPageRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @Author: 98050
 * @Time: 2019-03-20 14:12
 * @Feature: 测试类
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class CmsPageRepositoryTest {
    @Autowired
    private CmsPageRepository cmsPageRepository;

    /**
     * 分页查询
     */
    @Test
    public void testFindPage(){
        int page = 0;
        int size = 10;
        Pageable pageable = PageRequest.of(page, size);
        Page<CmsPage> pages = cmsPageRepository.findAll(pageable);
        for (CmsPage cmsPage : pages){
            System.out.println(cmsPage);
        }
    }
}

4.2.2 CRUD测试

/**
 * 添加
 */
@Test
public void add(){
    //定义实体类
    CmsPage cmsPage = new CmsPage();
    cmsPage.setSiteId("s01");
    cmsPage.setTemplateId("t01");
    cmsPage.setPageName("测试页面");
    cmsPage.setPageCreateTime(new Date());
    List<CmsPageParam> cmsPageParams = new ArrayList<>();
    CmsPageParam cmsPageParam = new CmsPageParam();
    cmsPageParam.setPageParamName("param1");
    cmsPageParam.setPageParamValue("value1");
    cmsPageParams.add(cmsPageParam);
    cmsPage.setPageParams(cmsPageParams);
    cmsPageRepository.save(cmsPage);
    System.out.println(cmsPage);
}

@Test
public void get(){
    System.out.println(cmsPageRepository.findById("5c91de185019c208f80da99e"));
}

@Test
public void delete(){
    cmsPageRepository.deleteById("5c91de185019c208f80da99e");
}


@Test
public void update(){
    Optional<CmsPage> optionalCmsPage = cmsPageRepository.findById("5c91df435019c26ff0b8a2d0");
    if (optionalCmsPage.isPresent()){
        CmsPage cmsPage = optionalCmsPage.get();
        cmsPage.setPageName("修改页面001");
        cmsPageRepository.save(cmsPage);
    }
}

4.3.3 自定义查询

package com.xuecheng.managecms.dao;

import com.xuecheng.framework.domain.cms.CmsPage;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 * @Author: 98050
 * @Time: 2019-03-19 22:10
 * @Feature: mongodb  dao
 */
public interface CmsPageRepository extends MongoRepository<CmsPage,String> {
    /**
     * 根据页面名称查询
     * @param pageName
     * @return
     */
    CmsPage findByPageNameAnd(String pageName);

    /**
     * 根据页面名称和类型查询
     * @param pageName
     * @param pageType
     * @return
     */
    CmsPage findByPageNameAndPageType(String pageName,String pageType);

    /**
     * 根据站点和页面类型查询记录数
     * @param siteId
     * @param pageType
     * @return
     */
    int countBySiteIdAndPageType(String siteId,String pageType);

    /**
     * 根据站点和页面类型分页查询
     * @param siteId
     * @param pageType
     * @param pageable
     * @return
     */
    Page<CmsPage> findBySiteIdAndPageType(String siteId, String pageType, Pageable pageable);
}

4.3 Service

实现分页查询,条件查询目前不实现:

4.3.1 定义接口

package com.xuecheng.managecms.service;

import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.model.response.QueryResponseResult;

/**
 * @Author: 98050
 * @Time: 2019-03-20 14:54
 * @Feature: CMS服务端
 */
public interface CmsService {

    /**
     * 页面分页查询
     * @param page 页码
     * @param size 页大小
     * @param queryPageRequest 具体请求参数
     * @return
     */
    QueryResponseResult queryByPage(int page, int size, QueryPageRequest queryPageRequest);
}

4.3.2 实现接口

package com.xuecheng.managecms.service.impl;

import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;
import com.xuecheng.managecms.dao.CmsPageRepository;
import com.xuecheng.managecms.service.CmsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

/**
 * @Author: 98050
 * @Time: 2019-03-20 14:55
 * @Feature:
 */
@Service
public class CmsServiceImpl implements CmsService {

    @Autowired
    private CmsPageRepository cmsPageRepository;


    @Override
    public QueryResponseResult queryByPage(int page, int size, QueryPageRequest queryPageRequest) {
        if (queryPageRequest == null){
            queryPageRequest = new QueryPageRequest();
        }
        if (page <= 0){
            page = 1;
        }
        /**
         * mongodb的页数从0开始
         */
        page -= 1;
        if (size <= 0){
            size = 10;
        }
        /**
         * 1.构建分页对象
         */
        Pageable pageable = PageRequest.of(page, size);
        /**
         * 2.分页查询
         */
        Page<CmsPage> pages = this.cmsPageRepository.findAll(pageable);
        /**
         * 3.组装返回结果
         */
        QueryResult<CmsPage> queryResult = new QueryResult<>();
        queryResult.setList(pages.getContent());
        queryResult.setTotal(pages.getTotalElements());
        /**
         * 4.返回
         */
        return new QueryResponseResult(CommonCode.SUCCESS, queryResult);
    }
}

4.4 Controller

调用Service方法:

package com.xuecheng.managecms.controller;

import com.xuecheng.api.cms.CmsPageControllerApi;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;
import com.xuecheng.managecms.service.CmsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: 98050
 * @Time: 2019-03-19 19:06
 * @Feature:
 */
@RestController
@RequestMapping("/cms/page")
public class CmsPageController implements CmsPageControllerApi {

    @Autowired
    private CmsService cmsService;

    @Override
    @GetMapping("/list/{page}/{size}")
    public QueryResponseResult findList(@PathVariable("page") int page, @PathVariable("size") int size, QueryPageRequest queryPageRequest) {
        return cmsService.queryByPage(page, size, queryPageRequest);
    }
}

结果:http://localhost:31001/cms/page/list/1/10

第一天CMS服务端开发

4.5 接口开发规范

4.5.1 api请求及响应规范

为了严格按照接口进行开发,提高效率,对请求及响应格式进行规范化。

1、get 请求时,采用key/value格式请求,SpringMVC可采用基本类型的变量接收,也可以采用对象接收。

2、Post请求时,可以提交form表单数据(application/x-www-form-urlencoded)和Json数据(ContentType=application/json),文件等多部件类型(multipart/form-data)三种数据格式,SpringMVC接收Json数据使用@RequestBody注解解析请求的json数据。

3、响应结果统一信息为:是否成功、操作代码、提示信息及自定义数据。

4、响应结果统一格式为json。

4.5.2 api定义约束

Api定义使用SpringMVC来完成,由于此接口后期将作为微服务远程调用使用,在定义接口时有如下限制:1、@PathVariable 统一指定参数名称,如:@PathVariable(“id”)

2、@RequestParam统一指定参数名称,如:@RequestParam(“id”)

五、页面查询接口测试

5.1 Swagger

5.1.1 常用注解

在Java类中添加Swagger的注解即可生成Swagger接口,常用Swagger注解如下:

@Api:修饰整个类,描述Controller的作用

@ApiOperation:描述一个类的一个方法,或者说一个接口

@ApiParam:单个参数描述

@ApiModel:用对象来接收参数

@ApiModelProperty:用对象接收参数时,描述对象的一个字段

@ApiResponse:HTTP响应其中1个描述

@ApiResponses:HTTP响应整体描述

@ApiIgnore:使用该注解忽略这个API

@ApiError :发生错误返回的信息

@ApiImplicitParams:多个请求参数

@ApiImplicitParam属性:

第一天CMS服务端开发

5.1.2 Swagger接口定义

修改接口工程中页面查询接口,添加Swagger注解。

package com.xuecheng.api.cms;

import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.model.response.QueryResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @Author: 98050
 * @Time: 2019-03-19 15:00
 * @Feature: 页面查询接口
 */
@RequestMapping("/cms/page")
@Api(value = "cms页面管理接口",description = "cms页面管理接口,提供对页面的CRUD")
public interface CmsPageControllerApi {
    /**
     * 页面分页查询
     * @param page 页码
     * @param size 页大小
     * @param queryPageRequest  查询参数
     * @return
     */
    @GetMapping("/list/{page}/{size}")
    @ApiOperation("分页查询页面列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page",value = "页码",required = true,paramType = "path",dataType = "int"),
            @ApiImplicitParam(name = "size",value = "页大小",required = true,paramType = "path",dataType = "int")
    })
    @ApiResponses({
            @ApiResponse(code = 10000,message = "操作成功")
    })
    QueryResponseResult findList(@PathVariable("page") int page, @PathVariable("size") int size, QueryPageRequest queryPageRequest);
}

在接口上还加上了@GetMapping注解,是为了方便以后微服务进行调用

在QueryPageRequest类中使用注解 ApiModelProperty 对属性注释:

package com.xuecheng.framework.domain.cms.request;

import com.xuecheng.framework.model.request.RequestData;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * @Author: 98050
 * @Time: 2019-03-19 14:43
 * @Feature:
 */
@Data
public class QueryPageRequest extends RequestData {

    @ApiModelProperty("站点Id")
    private String siteId;
    @ApiModelProperty("页面Id")
    private String pageId;
    @ApiModelProperty("页面名称")
    private String pageName;
    @ApiModelProperty("页面别名")
    private String pageAlias;
    @ApiModelProperty("模板Id")
    private String templateId;
}

5.2 测试

启动cms服务,然后打开http://localhost:31001/swagger-ui.html

第一天CMS服务端开发