微服务[学成在线] day01:CMS接口开发

2020-08-05 17:28:22 浏览数 (1)

? 写在前面

我为什么要花时间去写这个笔记?

由于在学习该项目的过程中发现了原讲义存在的一些问题,所以该笔记基于「学成在线」微服务项目 PDF 讲义进行编写,并且投入了时间去优化了笔记的格式、代码的高亮、重点的标记等。

以及一些原讲义中所描述的一些知识点使我无法理解的内容,我会对这些内容的表达方式进行修改或者提出一些问题,并且用我自己所理解的一些想法去重新的解释这个问题。

总结一下原 PDF 讲义中已知的一些问题:

  •  从 PDF 中复制出来的代码,部分特殊符号的编码有问题,并且不易被发现,例如横杠 -,从PDF直接复制出来的话是无法运行的。
  •  有时候一些重复且简单的代码,我们需要直接从讲义中直接复制,而部分PDF编辑器复制出来的代码格式可能会变乱,且PDF中没有代码高亮,代码可阅读性差,并且复制出来时会有代码缩进错乱等问题。
  •  部分内容是重点但在讲义中只是简单的描述,这并不方便我们后期回顾该课程的知识点,所以我在一些重点的内容上加上了更多的解释。

如有不足的地方,欢迎小伙伴们补充、填坑。

? 知识点概览

为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。

本章节为【学成在线】项目的 day01 的内容

  •  搭建门户页面
  •  搭建服务端基础工程
  •  页面查询服务的构建
  •  使用MangoDB 进行 CRUD 操作
  • Swagger 的基本使用
  • Postman 的基本使用一、项目架构

0x01 业务架构

0x02 技术架构

二、CMS 门户工程搭建

0x01 安装 WebStorm

参考 WebStorm安装手册.md 安装WebStorm,导入 资料门户xc-ui-pc-static-portal.rar 压缩包下的内容。

0x02 Nginx虚拟主机

在nginx中配置虚拟主机:

代码语言:javascript复制
server{
    listen 80;
    server_name www.xuecheng.com;
    ssi on;
    ssi_silent_errors on;
    location / {
    alias F:/teach/xcEdu/xcEduUI/xc‐ui‐pc‐static‐portal/;
    index index.html;
    }
}

F:/teach/xcEdu/xcEduUI/xc-ui-pc-static-portal/ 本目录即为门户的主目录,自行修改为自己的路径

三、CMS 服务端工程搭建

0x01 基础工程搭建

创建一个项目文件夹 xcEduService01导入 资料基础工程基础工程.zip 中的基础工程,并依次将所有基础工程添加至pom项目中

0x02 导入MongoDB数据

搭建好mongodb数据库后,导入 资料mongodbxc_cms 内的json数据

0x03 定义接口

定义请求以及相应类型

domain.cms.request 下创建 QueryPageRequest 并继承 RequestData

代码语言:javascript复制
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;
}

定义响应接口

com.xuecheng.api.cms 下定义 CmsPageControllerApi 查询列表的响应格式统一为 QueryResponseResult

代码语言:javascript复制
package com.xuecheng.api.cms;

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

/**
 * 分页查询接口
 */
public interface CmsPageControllerApi {
    public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest);
}

四、页面查询服务开发

0x01 创建CMS服务工程

导入 pom.xml 配置

代码语言:javascript复制
<?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>
        <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>
</project>

创建一个 xc-service-manage-cms 的maven工程,依赖父工程 xc-framework-parent

创建在 com.xuecheng.manage_cms 包并在包下创建config、dao、service、controller 等包,目录结构如下

创建入口文件 ManageCmsApplication,并扫描相应的包

代码语言:javascript复制
package com.xuecheng.manage_cms;
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.manage_cms"})  // 扫描本项目下的所有类
public class ManageCmsApplication {
    public static void main(String[] args) {
        SpringApplication.run(ManageCmsApplication.class,args);
    }
}

resources 下创建 application.yml

代码语言:javascript复制
server:
  port: 31001
spring:
  application:
    name: xc-service-manage-cms
  data:
    mongodb:
      uri: mongodb://root:123123@localhost:27017
      database: xc_cms

resources 下导入日志文件,直接复制 资料CMS配置文件 下的 logback-spring.xml

0x02 定义dao

在dao下定义一个接口 CmsPageRepository 继承 MongoRepository

MongoRepository<CmsPage,String> 中的 CmsPage 对应我们mongodb中集合的实体类

代码语言:javascript复制
package com.xuecheng.manage_cms.dao;
import com.xuecheng.framework.domain.cms.CmsPage;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface CmsPageRepository extends MongoRepository<CmsPage,String> {
    
}

0x03 单元测试

查询测试

定义CmsPageRepository 的测试类 CmsPageRepositoryTest

代码语言:javascript复制
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.List;

@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);
        Page<CmsPage> all = cmsPageRepository.findAll(pageable);
        System.out.println(all);
    }
}

运行测试,成功查询到分页数据。

添加

代码语言:javascript复制
//添加
@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);
}

删除

代码语言:javascript复制
//删除
@Test
public void testDelete(){
    cmsPageRepository.deleteById("5e705470cc53e4266c135ee7");
    System.out.println("删除成功!");
}

修改

代码语言:javascript复制
//修改
@Test
public void testUpdate(){
    Optional<CmsPage> optional = cmsPageRepository.findById("5e705470cc53e4266c135ee7");
    if(optional.isPresent()){  //判断是否为空,jdk1.8新特性optional
        CmsPage cmsPage = optional.get();
        cmsPage.setPageName("测试页面02");
        CmsPage save = cmsPageRepository.save(cmsPage);
        System.out.println("修改成功 "   save);
    }
}

0x04 配置 Service

代码语言:javascript复制
package com.xuecheng.manage_cms.service;

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.manage_cms.dao.CmsPageRepository;
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;

@Service
public class PageService {

    @Autowired
    CmsPageRepository cmsPageRepository;

    /**
     * 分页查询
     * @return
     */
    public QueryResponseResult findList(int page,int size,QueryPageRequest queryPageRequest) {
        //过滤条件
        if(page <= 0){
            page = 1;
        }
        if(size <= 0){
            size = 10;
        }

        //创建分页查询参数
        PageRequest pageable = PageRequest.of(page, size);
        //分页查询数据
        Page<CmsPage> all = cmsPageRepository.findAll(pageable);
        //整理查询到的数据
        QueryResult queryResult = new QueryResult();
        queryResult.setList(all.getContent());
        queryResult.setTotal(all.getTotalElements());

        //返回结果
        return new QueryResponseResult(CommonCode.SUCCESS,queryResult);
    }
}

0x05 配置 Controller

代码语言:javascript复制
package com.xuecheng.manage_cms.web.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.manage_cms.service.PageService;
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;

@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);
    }
}

0x06 接口开发规范

Api请求及响应规范

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

  • get 请求时,采用key/value格式请求,SpringMVC可采用基本类型的变量接收,也可以采用对象接收。
  • Post 请求时,可以提交form表单数据(application/x-www-form-urlencoded)和 Json 数据(Content-Type=application/json),文件等多部件类型(multipart/form-data)三种数据格式,SpringMVC接收Json数据使用@RequestBody注解解析请求的json数据。
  • 响应结果统一信息为:是否成功、操作代码、提示信息及自定义数据。
  • 响应结果统一格式为 json

Api定义约束

Api 定义使用SpringMVC来完成,由于此接口后期将作为微服务远程调用使用,在定义接口时有如下限制:

  • @PathVariable 统一指定参数名称,如:@PathVariable("id")
  • @RequestParam 统一指定参数名称,如:@RequestParam("id")

五、Swagger 生成接口文档

0x01 Swagger介绍

OpenAPI规范(OpenAPI Specification 简称OAS)是Linux基金会的一个项目,试图通过定义一种用来描述API格式或API定义的语言,来规范RESTful服务开发过程,目前版本是V3.0,并且已经发布并开源在github上。https://github.com/OAI/OpenAPI-Specification

Swagger是全球最大的OpenAPI规范(OAS)API开发工具框架,支持从设计和文档到测试和部署的整个API生命周期的开发。 (https://swagger.io/)

Spring Boot 可以集成Swagger,生成Swagger接口,Spring Boot是Java领域的神器,它是Spring项目下快速构建项目的框架。

0x02 开启 Swagger

代码语言:javascript复制
package com.xuecheng.api.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

//
@Configuration
@EnableSwagger2
public class Swagger2Configuration {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xuecheng"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("学成网api文档")
                .description("学成网api文档")
//                .termsOfServiceUrl("/")
                .version("1.0")
                .build();
    }

}

开启 swagger 后,它会自动扫描 com.xuecheng 包下所有标记了 @RestController 这个注解的类,根据这个类的方法来生成接口文档。

运行项目,访问 http://localhost:31001/swagger-ui.html 就可以看到我们刚才定义的这个 controller

0x03 Swagger常用注解

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

  • @Api:修饰整个类,描述Controller的作用 @ApiOperation:描述一个类的一个方法,或者说一个接口
  • @ApiParam:单个参数描述 @ApiModel:用对象来接收参数 @ApiModelProperty:用对象接收参数时,描述对象的一个字段
  • @ApiResponse:HTTP响应其中1个描述 @ApiResponses:HTTP响应整体描述
  • @ApiIgnore:使用该注解忽略这个API @ApiError :发生错误返回的信息
  • @ApiImplicitParam:一个请求参数
  • @ApiImplicitParams:多个请求参数
  • @ApiImplicitParam属性:

属性

取值

作用

paramType

查询参数类型

path

以地址的形式提交数据

query

直接跟参数完成自动映射赋值

body

以流的形式提交 仅支持POST

header

参数在request headers 里边提交

form

以form表单的形式提交 仅支持POST

dataType

参数的数据类型 只作为标志说明,并没有实际验证

Long

String

name

接收参数名

value

接收参数的意义描述

required

参数是否必填

true

必填

false

非必填

defaultValue

默认值

0x04 Swagger接口定义

使用 swagger 的常用注解来描述接口信息

代码语言:javascript复制
/**
 * 分页查询接口
 */
@Api(value="cms页面管理接口",description = "cms页面管理接口,提供页面的增、删、改、查")
public interface CmsPageControllerApi {
    @ApiOperation("分页查询页面列表")
    @ApiImplicitParams({
        @ApiImplicitParam(name="page",value = "页码",required=true,paramType="path",dataType="int"),
        @ApiImplicitParam(name="size",value = "每页记录数",required=true,paramType="path",dataType="int")
    })
    public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest);

}

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

代码语言:javascript复制
public class QueryPageRequest extends RequestData {
    //站点id
    @ApiModelProperty("站点id")
    private String siteId;
    //页面ID
    @ApiModelProperty("页面ID")
    private String pageId;
    //页面名称
    @ApiModelProperty("页面名称")
    private String pageName;
    //页面别名
    @ApiModelProperty("页面别名")
    private String pageAliase;
    //模版id
    @ApiModelProperty("模版id")
    private String templateId;
}

重启项目,访问 http://localhost:31001/swagger-ui.html ,可以看到我们添加的描述信息

五、Postman 基本使用

Postman 是一款功能强大的http接口测试工具,使用 postman 可以完成 http 各种请求的功能测试。

官方地址:https://www.getpostman.com/

0 人点赞