3.1 内容管理模块 - 工程搭建、课程查询、配置Swagger、数据字典

文章目录

  • 内容管理模块
  • 一、基础工程搭建
    • 1.1 需求分析
    • 1.2 业务流程
    • 1.3 数据模型
    • 1.4 创建模块工程
      • 1.4.1 介绍
      • 1.4.2 xuecheng-plus-content 聚合工程
      • 1.4.3 模块演示
  • 二、课程查询准备
    • 2.1 需求分析
      • 2.1.1 业务流程
      • 2.1.2 数据模型
    • 2.2 生成PO类
      • 2.2.1 新增Maven配置
      • 2.2.2 课程基本信息表
    • 2.3 接口设计分析
    • 2.4 创建模型类
      • 2.4.1 分页查询公用参数
      • 2.4.2 分页查询结果模型类
      • 2.4.2 查询条件模型类
    • 2.5 LocalDataTime工具类
  • 三、课程查询
    • 3.1Maven依赖
      • 3.1.1 api工程
      • 3.1.2 service工程
    • 3.2 课程查询Controller
    • 3.3 Service
    • 3.4 Mapper接口
      • 3.4.1 分页插件
      • 3.4.2 Mapper接口
    • 3.5 效果图
  • 四、api工程配置文件
    • 4.1 log4j2-dev.xml
    • 4.2 bootstrap.yml
  • 五、Swagger接口文档
    • 5.1 Maven坐标
    • 5.2 配置swagger
    • 5.3 添加接口说明
      • 5.3.1 @Api与@ApiOperation接口注释
      • 5.3.2 @ApiModel与@ApiModelProperty字段注释
      • 5.3.3 其他参数
  • 六、数据字典
    • 6.1 介绍
    • 6.2 创建工程
    • 6.3 Controller
    • 6.4 Service
    • 6.5 Mapper
    • 6.6 实体类
  • 七、解决Swagger报错

内容管理模块

在此模块完成课程及其相关内容管理

一、基础工程搭建

1.1 需求分析

内容管理系统(content management system,CMS),是一种位于WEB前端(Web 服务器)和后端办公系统或流程(内容创作、编辑)之间的软件系统。内容的创作人员、编辑人员、发布人员使用内容管理系统来提交、修改、审批、发布内容。这里指的“内容”可能包括文件、表格、图片、数据库中的数据甚至视频等一切你想要发布到Internet、Intranet以及Extranet网站的信息。

本项目作为一个大型的在线教育平台,其内容管理模块主要对课程及相关内容管理,包括:课程的基本信息、课程图片、课程师资信息、课程的授课计划、课程视频、课程文档等内容的管理。

1.2 业务流程

内容管理的业务由教学机构人员和平台的运营人员共同完成。

教学机构人员的业务流程如下

1、登录教学机构。

2、维护课程信息,添加一门课程需要编辑课程的基本信息、上传课程图片、课程营销信息、课程计划、上传课程视频、课程师资信息等内容。

3、课程信息编辑完成,通过课程预览确认无误后提交课程审核。

4、待运营人员对课程审核通过后方可进行课程发布。

运营人员的业务流程如下

1、查询待审核的课程信息。

2、审核课程信息。

3、提交审核结果。

下图是课程编辑与发布的整体流程。

img

1.3 数据模型

共设计到9张表

image-20231029210826042

1.4 创建模块工程

1.4.1 介绍

我们要创建的就是下面标红的内容管理模块

image-20231029211540123

本项目是一个前后端分离项目,前端与后端开发人员之间主要依据接口进行开发。

下图是前后端交互的流程图

1、前端请求后端服务提供的接口。(通常为http协议 )

2、后端服务的控制层Controller接收前端的请求。

3、Contorller层调用Service层进行业务处理。

4、Service层调用Dao持久层对数据持久化。

image-20231029211908225

对于一个Springcloud工程,对于此模块我们会单独创建一个Controller接口层工程xuecheng-plus-content-api,这个模块里面只是接口,这个工程会调用Service

xuecheng-plus-content-service模块式Service模块,处理业务逻辑

Controller工程调用Service工程时需要传输一些数据,而完成此传输功能的模块式xuecheng-plus-content-mode模块工程,里面都是一些传输对象

总结

xuecheng-plus-content-api:接口工程,为前端提供接口。

xuecheng-plus-content-service: 业务工程,为接口工程提供业务支撑。

xuecheng-plus-content-model: 数据模型工程,存储数据模型类、数据传输类型等。

image-20231029212238183

结合项目父工程、项目基础工程后

假如说我们以后部署jar包时,部署xuecheng-plus-content的jar包即可

xuecheng-plus-parent父工程会管理整个大项目的依赖

xuecheng-plus-content负责聚合xuecheng-plus-content-api、xuecheng-plus-content-service、xuecheng-plus-content-model,而且只负责模块的聚合

image-20231029212840781

1.4.2 xuecheng-plus-content 聚合工程

  • 首先在项目根目录创建内容管理模块的父工程xuecheng-plus-content

image-20231029214827080

image-20231029215219848

  1. 创建完成,只保留pom.xml文件,删除多余的文件

    image-20231029215423159

image-20231029214903484

  1. Maven坐标。内容管理父工程的主要职责是聚合内容管理接口和内容管理接口实现两个工程,它的父工程是xuecheng-plus-parent
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <artifactId>xuecheng-plus-parent</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../xuecheng-plus-parent</relativePath>
    </parent>
    
    <artifactId>xuecheng-plus-content</artifactId>
    <name>xuecheng-plus-content</name>
    <description>xuecheng-plus-content</description>
    <packaging>pom</packaging>

  <modules>
    <module>xuecheng-plus-content-api</module>
    <module>xuecheng-plus-content-model</module>
    <module>xuecheng-plus-content-service</module>
   </modules>
</project>

  • 在xuecheng-plus-content下创建xuecheng-plus-content-model数据模型工程

image-20231029215647710

  1. 创建完成,只保留包和pom.xml文件 ,删除多余的文件。

    比如删除启动类和配置文件

  2. 修改pom.xml文件

    我们在配置文件中并没有配置relativePath,因为此项目和父工程的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>xuecheng-plus-content</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>xuecheng-plus-content-model</artifactId>
    

    <dependencies>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xuecheng-plus-base</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

  • 在xuecheng-plus-content下创建xuecheng-plus-content-service接口实现工程

    这个工程主要是写Service层和Mapper与数据库交互层

image-20231029220130200

  1. 创建完成,只保留包和pom.xml文件 ,删除多余的文件

    比如删除启动类和配置文件

  2. pom.xml如下:

    我们在配置文件中并没有配置relativePath,因为此项目和父工程的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>xuecheng-plus-content</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>xuecheng-plus-content-service</artifactId>
    
        <dependencies>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xuecheng-plus-content-model</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
     </dependencies>
</project>

  • 在xuecheng-plus-content下创建xuecheng-plus-content-api接口工程

xuecheng-plus-content-api接口工程的父工程是xuecheng-plus-content,它依赖了xuecheng-plus-base基础工程

image-20231029220529121

  1. 编辑pom.xml

    我们在配置文件中并没有配置relativePath,因为此项目和父工程的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>xuecheng-plus-content</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>xuecheng-plus-content-api</artifactId>


    <dependencies>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xuecheng-plus-content-service</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

1.4.3 模块演示

四个功能模块如下所示

image-20231029221637895

二、课程查询准备

2.1 需求分析

2.1.1 业务流程

课程查询的业务流程如下:

1、教学机构人员点击课程管理首先进入课程查询界面,如下:

image-20231029224218893

2.在课程进行列表查询页面输入查询条件查询课程信息

当不输入查询条件时输入全部课程信息。

输入查询条件查询符合条件的课程信息。

约束:本教学机构查询本机构的课程信息。

img

2.1.2 数据模型

下边从查询条件、查询列表两个方面分析数据模型

  • 查询条件

包括:课程名称、课程审核状态、课程发布状态

课程名称:可以模糊搜索

课程审核状态:未提交、已提交、审核通过、审核未通过

课程发布状态:未发布、已发布、已下线

因为是分页查询所以查询条件中还要包括当前页码、每页显示记录数。

  • 查询结果

查询结果中包括:课程id、课程名称、任务数、创建时间、是否付费、审核状态、类型,操作

任务数:该课程所包含的课程计划数,即课程章节数。

是否付费:课程包括免费、收费两种。

类型:录播、直播。

因为是分页查询所以查询结果中还要包括总记录数、当前页、每页显示记录数。

2.2 生成PO类

PO即持久对象(Persistent Object),它们是由一组属性和属性的get和set方法组成,PO对应于数据库的表

我们对应的这些类应该添加在xuecheng-plus-content-model工程中

2.2.1 新增Maven配置

xuecheng-plus-content-model模块引入mybatis的核心包和注解包,保证代码不出错即可,不用将Mybatis的包全部引进来

<!--存在mybatisplus注解添加相关注解保证不报错-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-annotation</artifactId>
            <version>${mybatis-plus-boot-starter.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-core</artifactId>
            <version>${mybatis-plus-boot-starter.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

2.2.2 课程基本信息表

image-20231029231721091

/**
 * <p>
 * 课程基本信息
 * </p>
 */
@Data
@TableName("course_base")
public class CourseBase implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 机构ID
     */
    private Long companyId;

    /**
     * 机构名称
     */
    private String companyName;

    /**
     * 课程名称
     */
    private String name;

    /**
     * 适用人群
     */
    private String users;

    /**
     * 课程标签
     */
    private String tags;

    /**
     * 大分类
     */
    private String mt;

    /**
     * 小分类
     */
    private String st;

    /**
     * 课程等级
     */
    private String grade;

    /**
     * 教育模式(common普通,record 录播,live直播等)
     */
    private String teachmode;

    /**
     * 课程介绍
     */
    private String description;

    /**
     * 课程图片
     */
    private String pic;

    /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createDate;

    /**
     * 修改时间
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime changeDate;

    /**
     * 创建人
     */
    private String createPeople;

    /**
     * 更新人
     */
    private String changePeople;

    /**
     * 审核状态
     */
    private String auditStatus;

    /**
     * 课程发布状态 未发布  已发布 下线
     */
    private String status;


}

2.3 接口设计分析

设计一个接口需要包括以下几个方面

  • 协议

通常协议采用HTTP,查询类接口通常为get或post,查询条件较少的使用get,较多的使用post。

本接口使用 http post。

还要确定content-type,参数以什么数据格式提交,结果以什么数据格式响应。

一般情况没有特殊情况结果以json 格式响应。

  • 分析请求参数

根据前边对数据模型的分析,请求参数为:课程名称、课程审核状态、当前页码、每页显示记录数。

根据分析的请求参数定义模型类。

  • 分析响应结果

根据前边对数据模型的分析,响应结果为数据列表加一些分页信息(总记录数、当前页、每页显示记录数)。

数据列表中数据的属性包括:课程id、课程名称、任务数、创建时间、审核状态、类型。

注意查询结果中的审核状态为数据字典中的代码字段,前端会根据审核状态代码 找到对应的名称显示

根据分析的响应结果定义模型类。

  • 分析完成,使用SpringBoot注解开发一个Http接口

  • 使用接口文档工具查看接口的内容

  • 接口中调用Service方法完成业务处理

2.4 创建模型类

2.4.1 分页查询公用参数

据接口分析需要定义模型类接收请求的参数,并定义模型类用于响应结果

这些一般是公共使用的,所以放在xuecheng-plus-base工程中

/**
 * @description 分页查询通用参数
 */
@Data
@ToString
public class PageParams {

  //当前页码
  private Long pageNo = 1L;

  //每页记录数默认值
  private Long pageSize =10L;

  public PageParams(){

  }

  public PageParams(long pageNo,long pageSize){
      this.pageNo = pageNo;
      this.pageSize = pageSize;
  }
  
}

2.4.2 分页查询结果模型类

针对分页查询结果经过分析也存在固定的数据和格式,所以在base工程定义一个基础的模型类

据接口分析需要定义模型类接收请求的参数,并定义模型类用于响应结果

这些一般是公共使用的,所以放在xuecheng-plus-base工程中

/**
 * @description 分页查询结果模型类
 */
@Data
@ToString
public class PageResult<T> implements Serializable {

    // 数据列表
    private List<T> items;

    //总记录数
    private long counts;

    //当前页码
    private long page;

    //每页记录数
    private long pageSize;

    public PageResult(List<T> items, long counts, long page, long pageSize) {
        this.items = items;
        this.counts = counts;
        this.page = page;
        this.pageSize = pageSize;
    }

}

2.4.2 查询条件模型类

这个类只有在是在xuecheng-plus-content工程模块中使用,所以我们把下面这个类添加在xuecheng-plus-content-model模块即可

/**
 * @description 课程查询参数Dto
 */
 @Data
 @ToString
public class QueryCourseParamsDto {

  //审核状态
 private String auditStatus;
 //课程名称
 private String courseName;
  //发布状态
 private String publishStatus;

}

2.5 LocalDataTime工具类

不管在前端向后端传输时间相关参数,还是后端向前端响应参数,时间格式都是如下所示:

image-20231030232503171

为了解决上面默认的时间格式,我们在xuecheng-plus-base工程中添加如下所示配置类

@Configuration
public class LocalDateTimeConfig {

    /*
     * 序列化内容
     *   LocalDateTime -> String
     * 服务端返回给客户端内容
     * */
    @Bean
    public LocalDateTimeSerializer localDateTimeSerializer() {
        return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    /*
     * 反序列化内容
     *   String -> LocalDateTime
     * 客户端传入服务端数据
     * */
    @Bean
    public LocalDateTimeDeserializer localDateTimeDeserializer() {
        return new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }


    // 配置
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> {
            builder.serializerByType(LocalDateTime.class, localDateTimeSerializer());
            builder.deserializerByType(LocalDateTime.class, localDateTimeDeserializer());
        };
    }

}

三、课程查询

3.1Maven依赖

3.1.1 api工程

<dependencies>
    <dependency>
        <groupId>com.xuecheng</groupId>
        <artifactId>xuecheng-plus-content-service</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <!--cloud的基础环境包-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-context</artifactId>
    </dependency>
    <!-- Spring Boot 的 Spring Web MVC 集成 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


    <!-- 排除 Spring Boot 依赖的日志包冲突 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <!-- Spring Boot 集成 log4j2 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>

    <!-- Spring Boot 集成 swagger -->
    <dependency>
        <groupId>com.spring4all</groupId>
        <artifactId>swagger-spring-boot-starter</artifactId>
        <version>1.9.0.RELEASE</version>
    </dependency>


</dependencies>

3.1.2 service工程

<dependencies>
    <dependency>
        <groupId>com.xuecheng</groupId>
        <artifactId>xuecheng-plus-content-model</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- mybatis plus的依赖 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-context</artifactId>
    </dependency>
    <!-- Spring Boot 集成 Junit -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- 排除 Spring Boot 依赖的日志包冲突 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- Spring Boot 集成 log4j2 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>

</dependencies>

3.2 课程查询Controller

我们定义的接口要写在xuecheng-plus-content-api工程中

接口描述图

PageParams对象接收pageNo字段和pageSize字段

QueryCourseParamsDto对象接收请求体中的auditStatus审核状态字段,courseName课程名称字段,publishStatus发布状态字段

image-20231030213209269

/**
 * 课程内容管理
 */
@Api(value = "课程信息编辑接口",tags = "课程信息编辑接口")
@Slf4j
@RequestMapping
@RestController //@Controller+@Response
public class CourseBaseInfoController {

    @Autowired
    private CourseBaseInfoService courseBaseInfoService;
    
    /**
     * 课程分页查询接口
     *
     * @RequestBody(required = false) 含义:不传QueryCourseParamsDto请求体也行
     *
     * @param pageParams           pageNo字段和pageSize字段
     * @param queryCourseParamsDto auditStatus审核状态字段,courseName课程名称字段,publishStatus发布状态字段
     * @return 分页结果
     */
    @ApiOperation("课程查询接口")
    @PostMapping("/course/list")
    public PageResult<CourseBase> list(PageParams pageParams, @RequestBody(required = false) QueryCourseParamsDto queryCourseParamsDto) {
        PageResult<CourseBase> pageResult = courseBaseInfoService.queryCourseBaseList(pageParams, queryCourseParamsDto);
        return pageResult;

    }

}

3.3 Service

在xuecheng-plus-content-service层

/**
 * 课程信息管理业务接口实现类
 */
@Service
public class CourseBaseInfoServiceImpl implements CourseBaseInfoService {


    @Autowired
    CourseBaseMapper courseBaseMapper;

    @Override
    public PageResult<CourseBase> queryCourseBaseList(PageParams pageParams, QueryCourseParamsDto queryCourseParamsDto) {


        //构建查询条件对象
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        //构建查询条件,根据课程名称查询
        queryWrapper.like(StringUtils.isNotEmpty(queryCourseParamsDto.getCourseName()), CourseBase::getName, queryCourseParamsDto.getCourseName());
        //构建查询条件,根据课程审核状态查询
        queryWrapper.eq(StringUtils.isNotEmpty(queryCourseParamsDto.getAuditStatus()), CourseBase::getAuditStatus, queryCourseParamsDto.getAuditStatus());
        //构建查询条件,根据课程发布状态查询
        queryWrapper.eq(StringUtils.isNotEmpty(queryCourseParamsDto.getPublishStatus()), CourseBase::getStatus, queryCourseParamsDto.getPublishStatus());


        //分页对象
        Page<CourseBase> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());
        // 查询数据内容获得结果
        Page<CourseBase> pageResult = courseBaseMapper.selectPage(page, queryWrapper);
        // 获取数据列表
        List<CourseBase> list = pageResult.getRecords();
        // 获取数据总数
        long total = pageResult.getTotal();
        // 构建结果集
        PageResult<CourseBase> courseBasePageResult = new PageResult<>(list, total, pageParams.getPageNo(), pageParams.getPageSize());
        
        return courseBasePageResult;
        
    }
}

3.4 Mapper接口

在xuecheng-plus-content-service层,不在model层

我们要实现课程查询的功能

3.4.1 分页插件

/**
 * <P>
 *        Mybatis-Plus 配置
 * </p>
 */
@Configuration
@MapperScan("com.xuecheng.content.mapper")//不加这个配置,后面可能会报错
public class MybatisPlusConfig {
   /**
    * 定义分页拦截器
    */
   @Bean
   public MybatisPlusInterceptor mybatisPlusInterceptor() {
      MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
      interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
      return interceptor;
   }
   

}

分页插件的原理

首先分页参数放到ThreadLocal中,拦截执行的sql,根据数据库类型添加对应的分页语句重写sql,例如:(select * from table where a) 转换为 (select count(*) from table where a)和(select * from table where a limit ,)

计算出了total总条数、pageNum当前第几页、pageSize每页大小和当前页的数据,是否为首页,是否为尾页,总页数等。

3.4.2 Mapper接口

public interface CourseBaseMapper extends BaseMapper<CourseBase> {

}

3.5 效果图

image-20231101235720152

四、api工程配置文件

4.1 log4j2-dev.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="180" packages="">
    <properties>
        <property name="logdir">logs</property>
        <property name="PATTERN">%date{YYYY-MM-dd HH:mm:ss,SSS} %level [%thread][%file:%line] - %msg%n%throwable</property>
    </properties>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${PATTERN}"/>
        </Console>

        <RollingFile name="ErrorAppender" fileName="${logdir}/error.log"
            filePattern="${logdir}/$${date:yyyy-MM-dd}/error.%d{yyyy-MM-dd-HH}.log" append="true">
            <PatternLayout pattern="${PATTERN}"/>
            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
        </RollingFile>

        <RollingFile name="DebugAppender" fileName="${logdir}/info.log"
            filePattern="${logdir}/$${date:yyyy-MM-dd}/info.%d{yyyy-MM-dd-HH}.log" append="true">
            <PatternLayout pattern="${PATTERN}"/>
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
        </RollingFile>
        
        <!--异步appender-->
         <Async name="AsyncAppender" includeLocation="true">
            <AppenderRef ref="ErrorAppender"/>
            <AppenderRef ref="DebugAppender"/>
        </Async>
    </Appenders>
    
    <Loggers>
         <!--过滤掉spring和mybatis的一些无用的debug信息
        <logger name="org.springframework" level="INFO">
        </logger>
        <logger name="org.mybatis" level="INFO">
        </logger>-->
        <logger name="cn.itcast.wanxinp2p.consumer.mapper" level="DEBUG">
        </logger>

        <logger name="springfox" level="INFO">
        </logger>
      <logger name="org.apache.http" level="INFO">
        </logger>
        <logger name="com.netflix.discovery" level="INFO">
        </logger>
        
        <logger name="RocketmqCommon"  level="INFO" >
      </logger>
      
      <logger name="RocketmqRemoting" level="INFO"  >
      </logger>
      
      <logger name="RocketmqClient" level="WARN">
      </logger>

        <logger name="org.dromara.hmily" level="WARN">
        </logger>

        <logger name="org.dromara.hmily.lottery" level="WARN">
        </logger>

        <logger name="org.dromara.hmily.bonuspoint" level="WARN">
        </logger>
      
        <!--OFF   0-->
        <!--FATAL   100-->
        <!--ERROR   200-->
        <!--WARN   300-->
        <!--INFO   400-->
        <!--DEBUG   500-->
        <!--TRACE   600-->
        <!--ALL   Integer.MAX_VALUE-->
        <Root level="DEBUG" includeLocation="true">
            <AppenderRef ref="AsyncAppender"/>
            <AppenderRef ref="Console"/>
            <AppenderRef ref="DebugAppender"/>
        </Root>
    </Loggers>
</Configuration>

4.2 bootstrap.yml

下面的文件是springcloud识别出来的文件

server:
  servlet:
    context-path: /content
  port: 63040
#微服务配置
spring:
  application:
    name: content-api
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.101.65:3306/xcplus_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
    username: root
    password: mysql
# 日志文件配置路径
logging:
  config: classpath:log4j2-dev.xml

五、Swagger接口文档

这是之前在Springboot学习的swaggerSpringboot集成Swagger_springboot项目集成swagger

在前后端分离开发中通常由后端程序员设计接口,完成后需要编写接口文档,最后将文档交给前端工程师,前端工程师参考文档进行开发

可以通过Swagger工具快速生成接口文档

5.1 Maven坐标

添加到内容管理api工程

<!-- Spring Boot 集成 swagger -->
<dependency>
            <groupId>com.spring4all</groupId>
            <artifactId>swagger-spring-boot-starter</artifactId>
            <version>1.9.0.RELEASE</version>
        </dependency>

5.2 配置swagger

在 bootstrap.yml中配置swagger的扫描包路径及其它信息,base-package为扫描的包路径,扫描Controller类

swagger:
  title: "学成在线内容管理系统"
  description: "内容系统管理系统对课程相关信息进行管理"
  base-package: com.xuecheng.content
  enabled: true
  version: 1.0.0

在启动类中添加@EnableSwagger2Doc注解

@EnableSwagger2Doc
@SpringBootApplication
public class ContentApplication {
    public static void main(String[] args) {
        SpringApplication.run(ContentApplication.class, args);
    }

}

工程启动起来,访问http://localhost:63040/content/swagger-ui.html

image-20231030225305069

这个文档存在两个问题:

1、接口名称显示course-base-info-controller名称不直观

2、课程查询是post方式只显示post /course/list即可。

5.3 添加接口说明

这是之前在Springboot学习的swaggerSpringboot集成Swagger_springboot项目集成swagger

5.3.1 @Api与@ApiOperation接口注释

/**
 * 课程内容管理
 */
@Api(value = "课程信息编辑接口",tags = "课程信息编辑接口")
@Slf4j
@RequestMapping
@RestController //@Controller+@Response
public class CourseBaseInfoController {

    /**
     * 课程分页查询接口
     *
     * @RequestBody(required = false) 含义:不传QueryCourseParamsDto请求体也行
     *
     * @param pageParams           pageNo字段和pageSize字段
     * @param queryCourseParamsDto auditStatus审核状态字段,courseName课程名称字段,publishStatus发布状态字段
     * @return 分页结果
     */
    @ApiOperation("课程查询接口")
    @PostMapping("/course/list")
    public PageResult<CourseBase> list(PageParams pageParams, @RequestBody(required = false) QueryCourseParamsDto queryCourseParamsDto) {
        return null;
    }

}

再次启动服务,工程启动起来,访问http://localhost:63040/content/swagger-ui.html查看接口信息

image-20231030225842129

5.3.2 @ApiModel与@ApiModelProperty字段注释

@ApiModel注解与@ApiModelProperty注解

@ApiModel("分页查询通用参数")
@Data
@ToString
public class PageParams {

  //当前页码
  @ApiModelProperty("当前页码")
  private Long pageNo = 1L;

  //每页记录数默认值
  @ApiModelProperty("每页记录数默认值")
  private Long pageSize =10L;

  public PageParams(){

  }

  public PageParams(long pageNo,long pageSize){
      this.pageNo = pageNo;
      this.pageSize = pageSize;
  }

}
/**
 * @description 课程查询参数Dto
 */
@Data
@ApiModel("课程查询参数Dto")
@ToString
public class QueryCourseParamsDto {

    //审核状态
    @ApiModelProperty("审核状态")
    private String auditStatus;
    //课程名称
    @ApiModelProperty("课程名称")
    private String courseName;
    //发布状态
    @ApiModelProperty("发布状态")
    private String publishStatus;

}

再次启动服务,工程启动起来,访问http://localhost:63040/content/swagger-ui.html查看接口信息

5.3.3 其他参数

@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默认值

六、数据字典

6.1 介绍

审核状态在查询条件和查询结果中都存在,审核状态包括:未审核、审核通过、审核未通过三种

思考一个问题:一个课程的审核状态如果是“审核未通过”那么在课程基本信息表记录“审核未通过”三个字合适吗

如下图所示,合适嘛?

显然是不合适的,万一客户要求把“审核未通过”改成“通过”呢?我们要通过update修改,但是入了库的数据再修改会存在一定的风险,就算成功修改了,那以后客户在要求修改呢?

image-20231031224641775

和审核状态同类的有好多这样的信息,比如:课程状态、课程类型、用户类型等等,这一类数据有一个共同点就是它有一些分类项,且这些分类项较为固定

针对这些数据,为了提高系统的可扩展性,专门定义数据字典表去维护

image-20231031225148581

比如课程审核是否通过

[{"code":"202001","desc":"审核未通过"},{"code":"202002","desc":"未提交"},{"code":"202003","desc":"已提交"},{"code":"202004","desc":"审核通过"}]

image-20231031225247347

比如课程发布情况

[{"code":"203001","desc":"未发布"},{"code":"203002","desc":"已发布"},{"code":"203003","desc":"下线"}]

image-20231031225530355

而在我们课程表中会有两个字段与之对应

image-20231031225705184

image-20231031225721109

6.2 创建工程

与之前一样,创建工程

image-20231101224223002

6.3 Controller

@Slf4j
@RestController
public class DictionaryController  {

    @Autowired
    private DictionaryService  dictionaryService;
    
    //查询数据字典的所有内容
    @GetMapping("/dictionary/all")
    public List<Dictionary> queryAll() {
        return dictionaryService.queryAll();
    }
    //查询数据字典代码查询数据字典
    @GetMapping("/dictionary/code/{code}")
    public Dictionary getByCode(@PathVariable String code) {
        return dictionaryService.getByCode(code);
    }
}

6.4 Service

@Slf4j
@Service
public class DictionaryServiceImpl extends ServiceImpl<DictionaryMapper, Dictionary> implements DictionaryService {

    @Override
    public List<Dictionary> queryAll() {

        List<Dictionary> list = this.list();


        return list;
    }

    @Override
    public Dictionary getByCode(String code) {


        LambdaQueryWrapper<Dictionary> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Dictionary::getCode, code);

        Dictionary dictionary = this.getOne(queryWrapper);


        return dictionary;
    }
}

6.5 Mapper

public interface DictionaryMapper extends BaseMapper<Dictionary> {

}

6.6 实体类

@Data
@TableName("dictionary")
public class Dictionary implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * id标识
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 数据字典名称
     */
    private String name;

    /**
     * 数据字典代码
     */
    private String code;

    /**
     * 数据字典项--json格式
            [{
                  "sd_name": "低级",
                  "sd_id": "200001",
                  "sd_status": "1"
               }, {
                  "sd_name": "中级",
                  "sd_id": "200002",
                  "sd_status": "1"
               }, {
                  "sd_name": "高级",
                  "sd_id": "200003",
                  "sd_status": "1"
               }]
     */
    private String itemValues;


}

七、解决Swagger报错

swagger2报错Illegal DefaultValue null for parameter type integer…

虽然是报错了,但是并不影响swagger功能的使用,但是每次刷新swagger控制台就会报这个错误,看着控制台的异常比较难受,便搜索了一下

百度的原因是说swagger2官方有bug,下面是解决方法

用到swagger的地方可以酌情的复制下面的坐标或继承

<dependency>
    <groupId>com.spring4all</groupId>
    <artifactId>swagger-spring-boot-starter</artifactId>
    <version>${swagger-spring-boot-starter.version}</version>
    <exclusions>
        <exclusion>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
        </exclusion>
        <exclusion>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-annotations</artifactId>
    <version>${swagger-annotations.version}</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-models</artifactId>
    <version>1.5.22</version>
</dependency>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/251285.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文档安全加固:零容忍盗窃,如何有效预防重要信息外泄

文档安全保护不仅需要从源头着手&#xff0c;杜绝文档在使用和传播过程中产生的泄密风险&#xff0c;同时还需要对文档内容本身进行有效的保护。为了防范通过拷贝、截屏、拍照等手段盗窃重要文档内容信息的风险&#xff0c;迅软DSE加密软件提供了文档加密保护功能&#xff0c;能…

用23种设计模式打造一个cocos creator的游戏框架----(十八)责任链模式

1、模式标准 模式名称&#xff1a;责任链模式 模式分类&#xff1a;行为型 模式意图&#xff1a;使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处…

MLX:苹果 专为统一内存架构(UMA) 设计的机器学习框架

“晨兴理荒秽&#xff0c;带月荷锄归” 夜深闻讯&#xff0c;有点兴奋&#xff5e; 苹果为 UMA 设计的深度学习框架真的来了 统一内存架构 得益于 CPU 与 GPU 内存的共享&#xff0c;同时与 MacOS 和 M 芯片 交相辉映&#xff0c;在效率上&#xff0c;实现对其他框架的降维打…

Redis设计与实现之压缩列表

目录 一、 压缩列表 1、ziplist的构成 2、节点的构成 pre_entry_length encoding 和 length content 3、创建新 ziplist 4、将节点添加到末端 5、将节点添加到某个/某些节点的前面 6、删除节点 7、遍历 8、查找元素、根据值定位节点 二、小结 一、 压缩列表 Zipli…

论文降重同义词替换的实践经验与改进建议 快码论文

大家好&#xff0c;今天来聊聊论文降重同义词替换的实践经验与改进建议&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 标题&#xff1a;论文降重同义词替换的实践经验与改…

TS类型体操-简单-实现pick

文章目录 问题描述举例实现 问题描述 不使用 Pick<T, K> &#xff0c;实现 TS 内置的 Pick<T, K> 的功能。 从类型T 中选出符合 K 的属性&#xff0c;构造一个新的类型。 举例 interface Todo {title: stringdescription: stringcompleted: boolean }type TodoPre…

挖矿木马应急响应-案例分析

挖矿木马应急响应-案例分析 linux 终端无法使用系统资源使用异常高 首先解决linux命令无法使用的问题&#xff0c;显示libc.so.6 没有重新连接一下libc文件 查看日志 发现木马运行成功后就日志一直报libc错误 根据信息向上插在日志 向上发现&#xff0c;root用户被爆破后…

【Spring教程30】Spring框架实战:从零开始学习SpringMVC 之 Rest风格简介与RESTful入门案例

目录 1 REST简介2 RESTful入门案例2.1 环境准备2.2 思路分析2.3 修改RESTful风格 3 知识点总结 欢迎大家回到《Java教程之Spring30天快速入门》&#xff0c;本教程所有示例均基于Maven实现&#xff0c;如果您对Maven还很陌生&#xff0c;请移步本人的博文《如何在windows11下安…

windows 10 安装和配置nginx

1 下载nginx 1.1 下载地址&#xff1a;http://nginx.org/en/download.html 1.2 使用解压到安装目录 1.3 更改配置 conf目录下nginx.conf 修改为未被占用的端口&#xff0c;地址改成你的地址 server {listen 9999;server_name localhost;#charset koi8-r;#access_lo…

SQL进阶理论篇(八):SQL查询的IO成本

文章目录 简介数据库缓冲池查看缓冲池的大小数据页加载的三种方式通过 last_query_cost 统计 SQL 语句的查询成本总结参考文献 简介 本节将介绍磁盘IO是如何加载数据的&#xff0c;重点介绍一下数据库缓冲池的概念。主要包括&#xff1a; 什么是数据库缓冲池&#xff0c;它在…

云架构俭约之道七法则(The Frugal Architect)

授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 文章目录 一、前言关于 Law 与 Rule 的区别 二、云架构俭约之道七法…

【算法刷题】每日打卡——动态规划(1)

背包问题 例题一 有 N件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式 第一行两个整数…

深度学习python编译器的配置及法宝函数的作用

一、python编辑器的配置&#xff08;pycharm 和 jupyter&#xff09; &#xff08;1&#xff09;pycharm 在pycharm导入conda环境&#xff1a; 新建项目&#xff0c;更改编译器&#xff0c;选择已有的编译器 选择python.exe时会出现错误&#xff1a;找不到conda可执行文件 …

太空旅行:计算机技术的崭新航程

太空旅行&#xff1a;计算机技术的崭新航程 一、引言 自古以来&#xff0c;人类就对浩渺的宇宙充满了无尽的好奇和渴望。随着科技的飞速发展&#xff0c;太空旅行已经从科幻小说中的构想变为现实。在这个过程中&#xff0c;计算机技术起到了不可或缺的作用。从阿波罗时代的初…

EDT:On Efficient Transformer-Based Image Pre-training for Low-Level Vision

EDT&#xff1a;On Efficient Transformer-Based Image Pre-training for Low-Level Vision 论文地址&#xff1a;On Efficient Transformer-Based Image Pre-training for Low-Level Vision 代码地址&#xff1a;fenglinglwb/EDT: On Efficient Transformer-Based Image Pre…

知识付费小程序开发:技术实践示例

随着知识付费小程序的兴起&#xff0c;让我们一起来看一个简单的示例&#xff0c;使用Node.js和Express框架搭建一个基础的知识付费小程序后端。 首先&#xff0c;确保你已经安装了Node.js和npm。接下来&#xff0c;创建一个新的项目文件夹&#xff0c;然后通过以下步骤创建你…

LabVIEW实时建模检测癌细胞的异常

LabVIEW实时建模检测癌细胞的异常 癌症是全球健康的主要挑战之一&#xff0c;每年导致许多人死亡。世界卫生组织指出&#xff0c;不健康的生活方式和日益严重的环境污染是癌症发生的主要原因之一。癌症的发生通常与基因突变有关&#xff0c;这些突变导致细胞失去正常的增长和分…

excel手撕神经网络(只需高中数学基础)

神经网络最基础部分是由神经元组成&#xff0c;一个神经元相当于是一个一次函数&#xff0c;yaxb 即在已知x&#xff0c;和y情况下&#xff0c;怎么使用神经网络求解a和b 如下是使用excel求解的神经网络&#xff0c;可以方便理解神经网络运行原理 excel玩具神经网络下载地址 百…

蓝桥杯专题-真题版含答案-【排序法 - 改良的选择排序】【插补搜寻法】【稀疏矩阵】【欧拉与鸡蛋】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

centos8stream 升级 sqlite3 ,解决 SQLite 3.27 or later is required (found 3.26.0).

服务器环境是centos8stream, 默认的sqlite是 3.26 &#xff0c;因此&#xff0c;需要升级。 sqlite官网&#xff1a;SQLite Download Page 1.从官网下载最新源码包 cd /opt/ wget https://www.sqlite.org/2023/sqlite-autoconf-3440200.tar.gz tar xvf sqlite-autoconf-344020…