5 页面查询接口定义
5.1 定义模型
5.1.1 需求分析
在梳理完用户需求后就要去定义前后端的接口,接口定义后前端和后端就可以依据接口去开发功能了。
本次定义页面查询接口,本接口供前端请求查询页面列表,支持分页及自定义条件查询方式。
具体需求如下:
1、分页查询CmsPage 集合下的数据
2、根据站点Id、模板Id、页面别名查询页面信息
3、接口基于Http Get请求,响应Json数据
5.1.2 模型类介绍
CmsSite:站点模型
CmsTemplate:页面模板
CmsPage:页面信息
页面信息如下:
@Data、@ToString、@Document注解表示什么意思?
@Data、@ToString:是Lombok提供的注解,@Data注解可以自动生成getter/setter方法,@ToString生成tostring方法
@Document:是Spring Data mongodb提供的注解,最终CMS的开发会使用Mongodb数据库
@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;
}
5.2.2 定义接口
在 Api接口工程(xc-service-api)专门定义接口,在Api工程单独定义接口的原因如下:
1、接口集中管理
2、Api工程的接口将作为各微服务远程调用使用。
页面查询接口定义如下:
public interface CmsPageControllerApi {
//页面查询
public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest);
}
响应结果类型,分页查询统一使用QueryResponseResult的返回类型的原因:
进入QueryResponseResult的代码发现里面有QueryResult,
@Data
@ToString
public class QueryResponseResult extends ResponseResult {
QueryResult queryResult;
//QueryResult和QueryResponseResult是同一个包下,所以不需要导入
public QueryResponseResult(ResultCode resultCode,QueryResult queryResult){
super(resultCode);
this.queryResult = queryResult;
}
}
而进入QueryResult的内部代码发现里面有list和total,可以放将来返回的列表和total
@Data
@ToString
public class QueryResult<T> {
//数据列表
private List<T> list;
//数据总数
private long total;
}
另外QueryResponseResult还继承了ResponseResult,查看ResponseResult的代码发现它有三个固定属性(操作是否成功,操作代码,提示信息),
@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);
}
}
所以可以发现将来把分页查询返回的类型设成QueryResponseResult类型后,并把该类型的对象转化为json格式输出,它一定有ResponseResult三个固定属性(操作是否成功,操作代码,提示信息)的信息.
因此,这就是项目开发的规范之一:所有查询列表的接口,响应结果都统一定义为QueryResponseResult类型
6 页面查询服务端开发
6.1 创建CMS服务工程
6.1.1 创建CMS工程结构
1.创建maven工程(此处为新建module), CMS工程的名称为 xc-service-manage-cms,父工程为xc-framework-parent(新建时注意Add as module to 选择)。该工程基于Springboot开发.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nx5Gpq6y-1603258272969)(学成在线day01.assets\创建CMS工程结构.png)]
添加pom.xml文件中的依赖
2.创建基本的包结构
3、配置文件
在classpath下配置application.yml
server:
port: 31001
spring:
application:
name: xc-service-manage-cms
data:
mongodb:
uri: mongodb://root:123@localhost:27017
database: xc_cms
4、SpringBoot 启动类
Spring Boot 应用需要创建一个应用启动类,启动过程中会扫描Bean并注入spring 容器
注意:启动类要放在本项目的根路径下面,此类创建在本工程com.xuecheng.manage_cms包下
注意:此类创建在本工程com.xuecheng.manage_cms包下 ,也不能放到xuecheng包下,因为以后需要的微服务会很多,如果放到xuecheng包下,以后在启动的时候会扫描得比较多,也不合适.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JhKIGVA9-1603258272972)(学成在线day01.assets\启动类.png)]
@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);
}
}
6.1.2 测试Controller
使用springMVC完成接口实现开发,这里暂时使用测试数据,稍后会让controller调用service来查询数据。
/**Springmybatis注解
1.@RestController相当于@Controller+@Response
2.@GetMapping相当于@RequestMapping(method = RequestMethod.GET)的缩写
如果我们想使用传统的@RequestMapping注释实现URL处理程序,那么它应该是这样的:
@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
新方法可以简化为:@GetMapping("/get/{id}")
3.@GetMapping("/list/{page}/{size}") 中的/{page}/{size}的意思是通过url来传参,
传递来的参数用@PathVariable("page") int page, @PathVariable("size")int size的形式来接收
**/
@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<>();
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;
}
}
6.2 Dao
6.2.1 分页查询测试
6.2.1.1 定义Dao接口
本项目使用Spring Data Mongodb完成Mongodb数据库的查询,Spring Data Mongodb提供一套快捷操作
mongodb的方法。
创建Dao,继承MongoRepository,并指定实体类型和主键类型。
/**
* 本项目使用Spring Data Mongodb完成Mongodb数据库的查询,
* Spring Data Mongodb提供一套快捷操作mongodb的方法。
* 创建Dao,继承MongoRepository,并指定实体类型和主键类型。
* CmsPage的主键是id,类型是String类型
*/
public interface CmsPageRepository extends MongoRepository<CmsPage,String> {
}
6.2.1.2编写测试类以及 6.2.1.3 分页查询测试
test下的包路径与main下的包路径保持一致。
测试程序使用@SpringBootTest和@RunWith(SpringRunner.class)注解,启动测试类会从main下找springBoot启动类,加载spring容器
/**
* test下的包路径与main下的包路径保持一致。
* 测试程序使用@SpringBootTest和@RunWith(SpringRunner.class)注解,
启动测试类会从main下找springBoot启动类,加载spring容器。
*/
@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=0;//当前页码,从0开始,代表第一页
int size=10;//显示的记录数
Pageable pageable= PageRequest.of(page,size);//注意不要选错包了,要选择Pageable(org.springframework.data.domain)
Page<CmsPage> all = cmsPageRepository.findAll(pageable);//cmsPageRepository.findAll使用的是findAll(Pageable pageable)参数的方法
System.out.println(all);}
}
注意:分页查询时需要注意的两个地方:
1.cmsPageRepository.findAll使用的是findAll(Pageable pageable)参数的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jqTNWWi7-1603258272974)(学成在线day01.assets\findAll方法用的是Pageable参数的.png)]
2.Pageable pageable= PageRequest.of(page,size);//注意不要选错包了,要选择Pageable(org.springframework.data.domain)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KdL74K4F-1603258272976)(学成在线day01.assets\pageable的包名不要选错了.png)]
6.2.3.3 修改
//修改测试
@Test
public void testUpdate(){
//查询对象
Optional<CmsPage> optional= cmsPageRepository.findById("5af942190e661827d8e2f5e3");
if(optional.isPresent()){
//optional的isPresent()方法把判断非空标准化了
CmsPage cmsPage = optional.get();
//设置修改值
cmsPage.setPageAliase("课程预览页面2");
//...
//修改
CmsPage save = cmsPageRepository.save(cmsPage);
System.out.println(save);
}
}
关于Optional:
Optional是jdk1.8引入的类型,Optional是一个容器对象,它包括了我们需要的对象,使用isPresent方法判断所包
含对象是否为空,isPresent方法返回false则表示Optional包含对象为空,否则可以使用get()取出对象进行操作。
Optional的优点是:
1、提醒你非空判断。
2、将对象非空检测标准化。
6.2.3.4 自定义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);
}
注意,使用自定义的方法时要在上面的CmsPageRepository中声明对应的方法.
//自定义方法
@Test
public void testfindByPageName(){
CmsPage byPageName = cmsPageRepository.findByPageName("preview_4028e58161bd3b380161bd3bcd2f0000.html");
System.out.println(byPageName);
}
6.3 Service
定义页面查询方法,根据条件查询暂时不实现:
@Service
public class PageService {
@Autowired
CmsPageRepository cmsPageRepository;
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;
}
}
6.4 Controller
@RestController
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条记录。
6.6 接口开发规范
6.6.1 Api请求及响应规范
为了严格按照接口进行开发,提高效率,对请求及响应格式进行规范化。
1、get 请求时,采用key/value格式请求,SpringMVC可采用基本类型的变量接收,也可以采用对象接收。
2、Post请求时,可以提交form表单数据(application/x-www-form-urlencoded)和Json数据(Content-
Type=application/json),文件等多部件类型(multipart/form-data)三种数据格式,SpringMVC接收Json数据
使用@RequestBody注解解析请求的json数据。
4、响应结果统一信息为:是否成功、操作代码、提示信息及自定义数据。
5、响应结果统一格式为json。
6.6.2 Api定义约束
Api 定义使用SpringMVC来完成,由于此接口后期将作为微服务远程调用使用,在定义接口时有如下限制:
1、@PathVariable 统一指定参数名称,如:@PathVariable(“id”) 2、@RequestParam统一指定参数名称,如:@RequestParam(“id”)
7 页面查询接口测试
上边的代码是基于服务端编写接口,如果前端人员等待服务端人员将接口开发完毕再去开发前端内容这样做效率是
非常低下的,所以当接口定义完成,可以使用工具生成接口文档,前端人员查看接口文档即可进行前端开发,这样
前端和服务人员并行开发,大大提高了生产效率。
本章节介绍两种接口开发工具,Swagger和Postman。
7.1 Swagger
7.1.2 Swagger常用注解
在Java类中添加Swagger的注解即可生成Swagger接口,常用Swagger注解如下:
@Api:修饰整个类,描述Controller的作用
@ApiOperation:描述一个类的一个方法,或者说一个接口
@ApiParam:单个参数描述
@ApiModel:用对象来接收参数
@ApiModelProperty:用对象接收参数时,描述对象的一个字段
@ApiResponse:HTTP响应其中1个描述
@ApiResponses:HTTP响应整体描述
@ApiIgnore:使用该注解忽略这个API
@ApiError :发生错误返回的信息
@ApiImplicitParam:一个请求参数
@ApiImplicitParams:多个请求参数
人员查看接口文档即可进行前端开发,这样
前端和服务人员并行开发,大大提高了生产效率。
本章节介绍两种接口开发工具,Swagger和Postman。
7.1 Swagger
7.1.2 Swagger常用注解
在Java类中添加Swagger的注解即可生成Swagger接口,常用Swagger注解如下:
@Api:修饰整个类,描述Controller的作用
@ApiOperation:描述一个类的一个方法,或者说一个接口
@ApiParam:单个参数描述
@ApiModel:用对象来接收参数
@ApiModelProperty:用对象接收参数时,描述对象的一个字段
@ApiResponse:HTTP响应其中1个描述
@ApiResponses:HTTP响应整体描述
@ApiIgnore:使用该注解忽略这个API
@ApiError :发生错误返回的信息
@ApiImplicitParam:一个请求参数
@ApiImplicitParams:多个请求参数