一、CMS需求分析
1.1 什么是CMS
CMS (Content Management System)即内容管理系统,不同的项目对CMS的定位不同,比如:一个在线教育网站,有些公司认为CMS系统是对所有的课程资源进行管理,而在早期网站刚开始盛行时很多公司的业务是网站制作,当时对CMS的定位是创建网站,即对网站的页面、图片等静态资源进行管理。
CMS有哪些类型?上边也谈到每个公司对每个项目的CMS定位不同,CMS基本上分为:针对后台数据内容的管理、针对前端页面的管理、针对样式风格的管理等 。比如:一个给企业做网站的公司,其CMS系统主要是网站页面管理及样式风格的管理
本项目作为一个大型的在线教育平台,对CMS系统的定位是对各个网站(子站点)页面的管理,主要管理由于运营需要而经常变动的页面,从而实现根据运营需要快速进行页面开发、上线的需求。
1.2 静态门户工程搭建
本项目CMS是对页面进行管理,对页面如何进行管理呢?我们首先搭建学成网的静态门户工程,根据门户的页面结构来分析页面的管理方案。
门户,是一个网站的入口,一般网站都有一个对外的门户,学成在线门户效果图如下
1.2.1 静态原型导入
下载地址:
1.2.2 nginx反向代理
nginx配置文件中添加:
修改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
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工程:接口工程,统一管理本项目的服务接口。
工程结果如下:
2.1.2 基础工程
2.2 MongoDB数据导入
三、页面查询接口定义
3.1 定义模型
3.1.1 需求分析
定义页面查询接口,本接口供前端请求查询页面列表,支持分页及自定义条件查询方式。
具体需求如下:
- 分页查询CmsPage集合下的数据
- 根据站点Id、模板Id、页面别名查询页面信息
- 接口基于Http Get请求,响应Json数据
3.1.2 模型类介绍
接口的定义离不开数据模型,根据前边对需求的分析,整个页面管理模块的数据模型如下:
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>
包结构:
application.yml配置文件:
server:
port: 31001
spring:
application:
name: xc-service-manage-cms
data:
mongodb:
uri: mongodb://root:123@localhost: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;
}
}
结果:
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
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属性:
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