1. 项目的技术架构
1.1 技术架构
学成在线采用当前流行的前后端分离架构开发,由用户层、UI层、微服务层、数据层等部分组成,为PC、App、H5等客户端用户提供服务。
业务流程举例:
- 用户可以通过pc、手机等客户端访问系统进行在线学习。
- 系统应用CDN技术,对一些图片、CSS、视频等资源从CDN调度访问。
- 所有的请求全部经过负载均衡器。
- 对于PC、H5等客户端请求,首先请求UI层,渲染用户界面。
- 客户端UI请求服务层获取进行具体的业务操作。
- 服务层将数据持久化到数据库。
1.2 技术栈
重点了解微服务技术栈:
- 学成在线服务端基于
Spring Boot
构建,采用Spring Cloud
微服务框架。 - 持久层:
MySQL
、MongoDB
、Redis
、ElasticSearch
- 数据访问层:使用
Spring Data JPA
、Mybatis
、Spring Data Mongodb
等 - 业务层:
Spring IOC
、Aop
事务控制、Spring Task
任务调度、Feign
、Ribbon
、Spring AMQP
、Spring Data Redis
等。 - 控制层:
Spring MVC
、FastJSON
、RestTemplate
、Spring Security Oauth2
+JWT
等 - 微服务治理:
Eureka
、Zuul
、Hystrix
、Spring Cloud Config
等
2. CMS需求分析
2.1 什么是CMS
-
CMS是什么 ?
CMS (Content Management System)即内容管理系统,不同的项目对CMS的定位不同,比如:一个在线教育网站,有些公司认为CMS系统是对所有的课程资源进行管理,而在早期网站刚开始盛行时很多公司的业务是网站制作,当时对CMS的定位是创建网站,即对网站的页面、图片等静态资源进行管理。
-
CMS有哪些类型?
上边也谈到每个公司对每个项目的CMS定位不同,CMS基本上分为:针对后台数据内容的管理、针对前端页面的管理、针对样式风格的管理等 。比如:一个给企业做网站的公司,其CMS系统主要是网站页面管理及样式风格的管理。
-
本项目CMS的定位是什么?
本项目作为一个大型的在线教育平台,对CMS系统的定位是对各各网站(子站点)页面的管理,主要管理由于运营需要而经常变动的页面,从而实现根据运营需要快速进行页面开发、上线的需求。
2.2 静态门户工程搭建
本项目CMS是对页面进行管理,对页面如何进行管理呢?我们首先搭建学成网的静态门户工程,根据门户的页面结构来分析页面的管理方案。
门户,是一个网站的入口,一般网站都有一个对外的门户,学成在线门户效果图如下:
2.3 导入门户工程
-
安装WebStorm
-
安装Nginx
本项目下载 nginx-1.14.0.zip(http://nginx.org/download/nginx-1.14.0.zip)
解压nginx-1.14.0.zip到自己的计算机,双击nginx.exe即可运行。
访问 :http://localhost
-
导入门户工程
2.4 配置虚拟主机
在nginx中配置虚拟主机:
server{
listen 80;
server_name www.xuecheng.com;
ssi on;
ssi_silent_errors on;
location / {
alias E:/Users/WebstormProjects/xcEduUI/xc-ui-pc-static-portal/xc-ui-pc-static-portal/;
index index.html;
}
}
E:/Users/WebstormProjects/xcEduUI/xc-ui-pc-static-portal/xc-ui-pc-static-portal/
本目录即为门户的主目录。
配置hosts文件:
修改C:\Windows\System32\drivers\etc\hosts文件
127.0.0.1 www.xuecheng.com
进入浏览器,输入http://www.xuecheng.com
3. SSI 服务端包含技术
-
页面内容多如何管理?
将页面拆分成一个一个的小页面,通过cms去管理这些小页面,当要更改部分页面内容时只需要更改具体某个小页面即可。
-
页面拆出来怎么样通过web服务浏览呢?
使用web服务(例如nginx)的SSI技术,将多个子页面合并渲染输出。
-
SSI是什么?
SSI(Server Side Include),通常称为服务器端嵌入,是一种类似于ASP的基于服务器的网页制作技术。大多数(尤其是基于Unix平台)的WEB服务器如Netscape Enterprise Server等均支持SSI命令。
SSI工作原理:
将内容发送到浏览器之前,可以使用“服务器端包含 (SSI)”指令将文本、图形或应用程序信息包含到网页中。例如,可以使用 SSI 包含时间/日期戳、版权声明或供客户填写并返回的表单。对于在多个文件中重复出现的文本或图形,使用包含文件是一种简便的方法。将内容存入一个包含文件中即可,而不必将内容输入所有文件。通过一个非常简单的语句即可调用包含文件,此语句指示 Web 服务器将内容插入适当网页。而且,使用包含文件时,对内容的所有更改只需在一个地方就能完成。
因为包含 SSI 指令的文件要求特殊处理,所以必须为所有 SSI 文件赋予SSI 文件扩展名。默认扩展名是.stm、.shtm 和.shtml
ssi 包含类似于jsp页面中的incluce指令,ssi是在web服务端将include指定 的页面包含在网页中,渲染html网页响应给客户端 。nginx、apache等多数web容器都支持SSI指令。
-
将首页拆分成
index.html:首页主体内容 include/header.html:头部区域 include/index_banner.html:轮播图 include/index_category.html:左侧列表导航 include/footer.html:页尾
-
在nginx虚拟主机中开通SSI
server{ listen 80; server_name www.xuecheng.com; ssi on; ssi_silent_errors on; ......
ssi的配置参数如下: ssi on: 开启ssi支持 ssi_silent_errors on:默认为off,设置为on则在处理SSI文件出错时不输出错误信息 ssi_types:默认为 ssi_types text/html,如果需要支持shtml(服务器执行脚本,类似于jsp)则需要设置为ssi_types text/shtml
-
测试
去掉某个#include查看页面效果。
4. CMS 服务端工程搭建
4.1 导入基础工程
4.1.1 工程结构
CMS及其它服务端工程基于maven进行构建,首先需要创建如下基础工程:
- parent工程:父工程,提供依赖管理。
- common工程:通用工程,提供各层封装
- model工程:模型工程,提供统一的模型类管理
- utils工程:工具类工程,提供本项目所使用的工具类
- Api工程:接口工程,统一管理本项目的服务接口。
工程结果如下:
4.1.2 导入父工程
- 将课程资料中的parent工程拷贝到代码目录
- 点击Import Model,选择parent工程目录
选择Maven,下一步。
-
导入成功
4.1.3 导入其它工程
依次导入utils、model、common、api工程,方法同parent工和的导入。
5. MongoDB 入门
5.1 安装MongoDB
CMS采用MongoDB数据库存储CMS页面信息,CMS选用Mongodb的原因如下:
- Mongodb是非关系型数据库,存储Json格式数据 ,数据格式灵活。
- 相比课程管理等核心数据CMS数据不重要,且没有事务管理要求。
官方地址:https://www.mongodb.com/
本教程下载 3.4版本:http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-v3.4-latest-signed.msi
5.2 启动MongoDB
创建几个文件夹具体如下:数据库路径(data目录)、日志路径(logs目录)和日志文件(mongo.log文件)
创建配置文件 mongo.conf,文件内容如下:
#数据库路径
dbpath=d:\MongoDB\Server\3.4\data
#日志输出文件路径
logpath=d:\MongoDB\Server\3.4\logs\mongo.log
#错误日志采用追加模式
logappend=true
#启用日志文件,默认启用
journal=true
#这个选项可以过滤掉一些无用的日志信息,若需要调试使用请设置为false
quiet=true
#端口号 默认为27017
port=27017
安装 MongoDB服务
通过执行bin/mongod.exe,使用--install选项来安装服务,使用--config选项来指定之前创建的配置文件。 cmd进
入d:\MongoDB\Server\3.4\bin
以管理员模式打开cmd,cd到mongodb bin目录下,运行:
mongod --config "D:\Mongo\mongo.conf" --install --serviceName "MongoDB"
启动MongoDB服务
net start MongoDB
关闭MongoDB服务
net stop MongoDB
移除MongoDB服务
" d:\MongoDB\Server\3.4\bin\mongod.exe" ‐‐remove
启动mongodb服务,命令执行后,浏览器中输入http://127.0.0.1:27017看到如下界面即说明启动成功
5.3 安装studio3t
studio3t是mongodb优秀的客户端工具。官方地址在https://studio3t.com/
5.4 基础概念
在mongodb中是通过数据库、集合、文档的方式来管理数据,下边是mongodb与关系数据库的一些概念对比:
SQL 术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接(MongoDB不支持) | |
primary key | primary key | 主键,MongoDB自动在每个集合中添加_id的主键 |
- 一个mongodb实例可以创建多个数据库
- 一个数据库可以创建多个集合
- 一个集合可以包括多个文档。
5.5 连接mongodb
mongodb的使用方式是客户服务器模式,即使用一个客户端连接mongodb数据库(服务端)。
- 命令格式
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?
options]]
- mongodb:// 固定前缀
- username:账号,可不填
- password:密码,可不填
- host:主机名或ip地址,只有host主机名为必填项。
- port:端口,可不填,默认27017
- /database:连接某一个数据库
- ?options:连接参数,key/value对
例子:
mongodb://localhost 连接本地数据库27017端口
mongodb://root:itcast@localhost 使用用户名root密码为itcast连接本地数据库27017端口
mongodb://localhost,localhost:27018,localhost:27019,连接三台主从服务器,端口为27017、27018、27019
- 使用mongodb自带的javascript shell(mongo.exe)连接
windows 版本的mongodb安装成功,在安装目录下的bin目录有mongo.exe客户端程序
cmd状态执行mongo.exe:
此时就可以输入命令来操作mongodb数据库了,javascript shell可以运行javascript程序。
使用studio3T连接
-
使用java程序连接
详细参数:http://mongodb.github.io/mongo-java-driver/3.4/driver/tutorials/connect-to-mongodb/
添加依赖:
<dependency> <groupId>org.mongodb</groupId> <artifactId>mongo‐java‐driver</artifactId> <version>3.4.3</version> </dependency>
测试程序:
@Test public void testConnection(){ //创建mongodb 客户端 MongoClient mongoClient = new MongoClient( "localhost" , 27017 ); //或者采用连接字符串 //MongoClientURI connectionString = new MongoClientURI("mongodb://root:root@localhost:27017"); //MongoClient mongoClient = new MongoClient(connectionString); //连接数据库 MongoDatabase database = mongoClient.getDatabase("test"); // 连接collection MongoCollection<Document> collection = database.getCollection("student"); //查询第一个文档 Document myDoc = collection.find().first(); //得到文件内容 json串 String json = myDoc.toJson(); System.out.println(json); }
5.6 数据库
-
查询数据库
show dbs
查询全部数据库
db
显示当前数据库 -
创建数据库
命令格式:
use DATABASE_NAME
例子:
use test02
有test02数据库则切换到此数据库,没有则创建。
注意:
新创建的数据库不显示,需要至少包括一个集合。
-
删除数据库(慎用!!!)
命令格式:
db.dropDatabase()
例子:
删除test02数据库
先切换数据库:
use test02
再执行删除:
db.dropDatabase()
-
5.6 集合
集合相当于关系数据库中的表,一个数据库可以创建多个集合,一个集合是将相同类型的文档管理起来。
-
创建集合
db.createCollection(name, options) name: 新创建的集合名称 options: 创建参数
-
删除集合
db.collection.drop()
例子:
db.student.drop() 删除student集合
5.7 文档
5.7.1 插入文档
mongodb中文档的格式是json格式,下边就是一个文档,包括两个key:_id主键和name
{
"_id" : ObjectId("5b2cc4bfa6a44812707739b5"),
"name" : "黑马程序员"
}
插入命令:
db.COLLECTION_NAME.insert(document)
每个文档默认以_id作为主键,主键默认类型为ObjectId(对象类型),mongodb会自动生成主键值。
例子:
db.student.insert({"name":"黑马程序员","age":10})
注意:同一个集合中的文档的key可以不相同!但是建议设置为相同的。
5.7.2 更新文档
命令格式:
db.collection.update(
<query>,
<update>,
<options>
)
query:查询条件,相当于sql语句的where
update:更新文档内容
options:选项
-
替换文档
将符合条件 "name":"北京黑马程序"的第一个文档替换为{"name":"北京黑马程序员","age":10}。
db.student.update({"name":"黑马程序员"},{"name":"北京黑马程序员","age":10})
-
$set修改器
使用$set修改器指定要更新的key,key不存在则创建,存在则更新。
将符合条件 "name":"北京黑马程序"的所有文档更新name和age的值。db.student.update({"name":"黑马程序员"},{$set:{"name":"北京黑马程序员","age":10}},{multi:true})
multi:false表示更新第一个匹配的文档,true表示更新所有匹配的文档。
5.7.3 删除文档
命令格式:
db.student.remove(<query>)
query:删除条件,相当于sql语句中的where
-
删除所有文档
db.student.remove({})
-
删除符合条件的文档
db.student.remove({"name":"黑马程序员"})
5.7.4 查询文档
命令格式:
db.collection.find(query, projection)
query:查询条件,可不填
projection:投影查询key,可不填
-
查询全部
db.student.find()
-
查询符合条件的记录
db.student.find({"name":"黑马程序员"})
-
投影查询
只显示name和age两个key,_id主键不显示。
db.student.find({"name":"黑马程序员"},{name:1,age:1,_id:0})
6. 用户
6.1 创建用户
语法格式:
mongo>db.createUser(
{ user: "<name>",
pwd: "<cleartext password>",
customData: { <any information> },
roles: [
{ role: "<role>", db: "<database>" } | "<role>",
...
]}
)
例子:
创建root用户,角色为root
use admin
db.createUser(
{
user:"root",
pwd:"root",
roles:[{role:"root",db:"admin"}]
}
)
内置角色如下:
- 数据库用户角色:
read
、readWrite
; - 数据库管理角色:
dbAdmin
、dbOwner
、userAdmin
; - 集群管理角色:
clusterAdmin
、clusterManager
、clusterMonitor
、hostManager
; - 备份恢复角色:
backup
、restore
; - 所有数据库角色:
readAnyDatabase
、readWriteAnyDatabase
、userAdminAnyDatabase
、dbAdminAnyDatabase
- 超级用户角色:root
6.2 查询用户
查询当前库下的所有用户:
show users
6.3 删除用户
语法格式:
db.dropUser("用户名")
例子:
删除root1用户
db.dropUser("root1")
6.4 修改用户
语法格式:
db.updateUser(
"<username>",
{
customData : { <any information> },
roles : [
{ role: "<role>", db: "<database>" } | "<role>",
...
],
pwd: "<cleartext password>"
},
writeConcern: { <write concern> })
例子:
修改root用户的角色为readWriteAnyDatabase
use admin
db.updateUser("root",{roles:[{role:"readWriteAnyDatabase",db:"admin"}]})
6.5 修改密码
语法格式:
db.changeUserPassword("username","newPasswd")
例子:
修改root用户的密码为123
use admin
db.changeUserPassword("root","123")
6.6 认证登陆
为了安全需要,Mongodb要打开认证开关,即用户连接Mongodb要进行认证,其中就可以通过账号密码方式进行认证。
在mono.conf中设置auth=true
重启Mongodb
-
使用账号和密码连接数据库
-
mongo.exe连接
mongo.exe -u root -p 123 --authenticationDatabase admin
-
Studio 3T连接
-
7. 导入CMS数据库
导入cms数据库:
使用Studio 3T软件导入cms数据库
创建xc_cms数据库
-
导入 cms数据库
右键数据库,点击导入数据库
打开窗口,选择第一个 json。
下一步,选择要导入的数据文件(json文件)
8. 页面查询接口定义
8.1 需求分析
在梳理完用户需求后就要去定义前后端的接口,接口定义后前端和后端就可以依据接口去开发功能了。 本次定义页面查询接口,本接口供前端请求查询页面列表,支持分页及自定义条件查询方式。
具体需求如下:
- 分页查询CmsPage 集合下的数据
- 根据站点Id、模板Id、页面别名查询页面信息
- 接口基于Http Get请求,响应Json数据
8.2 模型类介绍
接口的定义离不开数据模型,根据前边对需求的分析,整个页面管理模块的数据模型如下:
-
CmsSite
:站点模型 -
CmsTemplate
:页面模板 -
CmsPage
:页面信息
页面信息如下:
package com.xuecheng.framework.domain.cms;
@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;
}
属性说明:
-
定义一个页面需要指定页面所属站点
一个站点包括多个页面,比如:学成在线的门户站点(网站)包括了多个页面。
-
定义一个页面需要指定页面使用的模板
多个页面可以使用相同的模板,比如:商品信息模板,每个商品就是一个页面,所有商品使用同一个商品信息模板
-
注解说明:
@Document
:是Spring Data mongodb提供的注解,最终CMS的开发会使用Mongodb数据库。
8.3 定义请求及响应类型
定义请求模型QueryPageRequest
,此模型作为查询条件类型 为后期扩展需求,请求类型统一继承RequestData
类型。
package com.xuecheng.framework.domain.cms.request;
import com.xuecheng.framework.model.request.RequestData;
import lombok.Data;
@Data
public class QueryPageRequest extends RequestData {
//站点id
private String siteId;
//页面ID
private String pageId;
//页面名称
private String pageName;
//别名
private String pageAliase;
//模版id
private String templateId;
}
响应结果类型,分页查询统一使用QueryResponseResult
8.4 定义接口
在Api接口工程专门定义接口,在Api工程单独定义接口的原因如下:
- 接口集中管理
- Api工程的接口将作为各微服务远程调用使用。
页面查询接口定义如下:
package com.xuecheng.api.cms;
public interface CmsPageControllerApi {
//页面查询
QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest);
}
以下规定了本项目响应的数据模型
QueryResponseResult
继承ResponseResult
package com.xuecheng.framework.model.response;
@Data
@ToString
public class QueryResponseResult extends ResponseResult {
QueryResult queryResult;
public QueryResponseResult(ResultCode resultCode,QueryResult queryResult){
super(resultCode);
this.queryResult = queryResult;
}
}
package com.xuecheng.framework.model.response;
@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);
}
}
QueryResult
package com.xuecheng.framework.model.response;
@Data
@ToString
public class QueryResult<T> {
//数据列表
private List<T> list;
//数据总数
private long total;
}
接口Response
package com.xuecheng.framework.model.response;
public interface Response {
public static final boolean SUCCESS = true;
public static final int SUCCESS_CODE = 10000;
}
CommonCode
枚举
package com.xuecheng.framework.model.response;
@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;
private 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;
}
}
ResultCode
接口:
package com.xuecheng.framework.model.response;
/**
* Created by mrt on 2018/3/5.
* 10000-- 通用错误代码
* 22000-- 媒资错误代码
* 23000-- 用户中心错误代码
* 24000-- cms错误代码
* 25000-- 文件系统
*/
public interface ResultCode {
//操作是否成功,true为成功,false操作失败
boolean success();
//操作代码
int code();
//提示信息
String message();
}
9. 页面查询服务端开发
9.1 创建CMS服务工程
创建maven工程, CMS工程的名称为 xc-service-manage-cms,父工程为xc-framework-parent。
pom.xml如下:
<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>
<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>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
创建基本包结构
配置文件 application.yml
server:
port: 31001
spring:
application:
name: xc‐service‐manage‐cms
data:
mongodb:
uri: mongodb://root:123@localhost:27017
database: xc_cms
SpringBoot 启动类
package com.xuecheng.manage_cms;
@SpringBootApplication
@EntityScan("com.xuecheng.framework.domain.cms")//扫描实体类
@ComponentScan(basePackages={"com.xuecheng.api"})//扫描接口
@ComponentScan(basePackages={"com.xuecheng.manage_cms"})//扫描本项目下的所有类
public class ManageCmsApplication {
public static void main(String[] args) {
SpringApplication.run(ManageCmsApplication.class,args);
}
}
测试Controller
package com.xuecheng.manage_cms.controller;
@RestController
@RequestMapping("/cms/page")
public class CmsPageController implements CmsPageControllerApi {
// @Autowired
// PageService pageService;
@Override
@GetMapping("/list/{page}/{size}")
public QueryResponseResult findList(@PathVariable("page") int page, @PathVariable("size")int size, QueryPageRequest queryPageRequest) {
//暂时用静态数据
//定义queryResult
QueryResult<CmsPage> queryResult =new QueryResult<>();
List<CmsPage> list = new ArrayList<>();
CmsPage cmsPage = new CmsPage();
cmsPage.setPageName("测试页面");
list.add(cmsPage);
queryResult.setList(list);
queryResult.setTotal(1);
QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS,queryResult);
return queryResponseResult;
//调用service
//return pageService.findList(page,size,queryPageRequest);
}
}
10. Dao
10.1 分页查询测试
本项目使用Spring Data Mongodb完成Mongodb数据库的查询,Spring Data Mongodb提供一套快捷操作mongodb的方法。
创建Dao,继承MongoRepository,并指定实体类型和主键类型。
package com.xuecheng.manage_cms.dao;
public interface CmsPageRepository extends MongoRepository<CmsPage,String> {
}
10.1.1 编写测试类
test下的包路径与main下的包路径保持一致。
测试程序使用@SpringBootTest
和@RunWith(SpringRunner.class)
注解,启动测试类会从main下找springBoot启动类,加载spring容器。
测试代码如下:
package com.xuecheng.manage_cms;
@SpringBootTest
@RunWith(SpringRunner.class)
public class CmsPageRepositoryTest {
@Autowired
CmsPageRepository cmsPageRepository;
@Test
public void testFindAll(){
List<CmsPage> all = cmsPageRepository.findAll();
System.out.println(all);
}
//分页查询
@Test
public void testFindPage(){
//分页参数
int page = 1;//从0开始
int size = 10;
Pageable pageable = PageRequest.of(page,size);
Page<CmsPage> all = cmsPageRepository.findAll(pageable);
System.out.println(all);
}
}
10.1.2 基础方法测试
这里Dao接口继承了MongoRepository,在MongoRepository中定义了很多现成的方法,如save、delete等,通过下边的代码来测试这里父类方法。
-
添加
//添加@Test public void testInsert(){ //定义实体类 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 testDelete() { cmsPageRepository.deleteById("5b17a2c511fe5e0c409e5eb3"); }
-
修改
@Test public void testUpdate() { Optional<CmsPage> optional = cmsPageRepository.findOne("5b17a34211fe5e2ee8c116c9"); if(optional.isPresent()){ CmsPage cmsPage = optional.get(); cmsPage.setPageName("测试页面01"); cmsPageRepository.save(cmsPage); } }
关于Optional:
Optional是jdk1.8引入的类型,Optional是一个容器对象,它包括了我们需要的对象,使用isPresent方法判断所包含对象是否为空,isPresent方法返回false则表示Optional包含对象为空,否则可以使用get()取出对象进行操作。
Optional的优点是:
- 提醒你非空判断。
- 将对象非空检测标准化。
10.1.3 自定义Dao方法
同Spring Data JPA一样Spring Data mongodb也提供自定义方法的规则,如下:
按照findByXXX,findByXXXAndYYY、countByXXXAndYYY等规则定义方法,实现查询操作。
public interface CmsPageRepository extends MongoRepository<CmsPage,String> {
//根据页面名称查询
CmsPage findByPageName(String pageName);
//根据页面名称和类型查询
CmsPage findByPageNameAndPageType(String pageName,String pageType);
//根据站点和页面类型查询记录数
int countBySiteIdAndPageType(String siteId,String pageType);
//根据站点和页面类型分页查询
Page<CmsPage> findBySiteIdAndPageType(String siteId,String pageType, Pageable pageable);
}
11. Service
定义页面查询方法,根据条件查询暂时不实现:
package com.xuecheng.manage_cms.service;
@Service
public class PageService {
@Autowired
CmsPageRepository cmsPageRepository;
/**
* 页面查询方法
* @param page 页码,从1开始记数
* @param size 每页记录数
* @param queryPageRequest 查询条件
* @return
*/
public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest){
//分页参数
if(page <=0){
page = 1;
}
page = page -1;
if(size<=0){
size = 10;
}
Pageable pageable = PageRequest.of(page,size);
Page<CmsPage> all = cmsPageRepository.findAll(pageable);
QueryResult queryResult = new QueryResult();
queryResult.setList(all.getContent());//数据列表
queryResult.setTotal(all.getTotalElements());//数据总记录数
QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS,queryResult);
return queryResponseResult;
}
}
12. Controller
使用springMVC完成接口实现开发。
package com.xuecheng.manage_cms.controller;
@RestController
@RequestMapping("/cms/page")
public class CmsPageController implements CmsPageControllerApi {
@Autowired
PageService pageService;
@Override
@GetMapping("/list/{page}/{size}")
public QueryResponseResult findList(@PathVariable("page") int page, @PathVariable("size")int size, QueryPageRequest queryPageRequest) {
return pageService.findList(page,size,queryPageRequest);
}
}
使用浏览器测试
输入:http://localhost:31001/cms/page/list/1/10 查询第1页,每页显示10条记录。