在此模块完成课程及其相关内容管理
内容管理系统(content management system,CMS),是一种位于WEB前端(Web 服务器)和后端办公系统或流程(内容创作、编辑)之间的软件系统。内容的创作人员、编辑人员、发布人员使用内容管理系统来提交、修改、审批、发布内容。这里指的“内容”可能包括文件、表格、图片、数据库中的数据甚至视频等一切你想要发布到Internet、Intranet以及Extranet网站的信息。
本项目作为一个大型的在线教育平台,其内容管理模块主要对课程及相关内容管理,包括:课程的基本信息、课程图片、课程师资信息、课程的授课计划、课程视频、课程文档等内容的管理。
内容管理的业务由教学机构人员和平台的运营人员共同完成。
教学机构人员的业务流程如下:
1、登录教学机构。
2、维护课程信息,添加一门课程需要编辑课程的基本信息、上传课程图片、课程营销信息、课程计划、上传课程视频、课程师资信息等内容。
3、课程信息编辑完成,通过课程预览确认无误后提交课程审核。
4、待运营人员对课程审核通过后方可进行课程发布。
运营人员的业务流程如下:
1、查询待审核的课程信息。
2、审核课程信息。
3、提交审核结果。
下图是课程编辑与发布的整体流程。
共设计到9张表
我们要创建的就是下面标红的内容管理模块
本项目是一个前后端分离项目,前端与后端开发人员之间主要依据接口进行开发。
下图是前后端交互的流程图:
1、前端请求后端服务提供的接口。(通常为http协议 )
2、后端服务的控制层Controller接收前端的请求。
3、Contorller层调用Service层进行业务处理。
4、Service层调用Dao持久层对数据持久化。
对于一个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: 数据模型工程,存储数据模型类、数据传输类型等。
结合项目父工程、项目基础工程后
假如说我们以后部署jar包时,部署xuecheng-plus-content的jar包即可
xuecheng-plus-parent父工程会管理整个大项目的依赖
xuecheng-plus-content负责聚合xuecheng-plus-content-api、xuecheng-plus-content-service、xuecheng-plus-content-model,而且只负责模块的聚合
创建完成,只保留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-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>
创建完成,只保留包和pom.xml文件 ,删除多余的文件。
比如删除启动类和配置文件
修改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与数据库交互层
创建完成,只保留包和pom.xml文件 ,删除多余的文件
比如删除启动类和配置文件
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-api接口工程的父工程是xuecheng-plus-content,它依赖了xuecheng-plus-base基础工程
编辑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、教学机构人员点击课程管理首先进入课程查询界面,如下:
2.在课程进行列表查询页面输入查询条件查询课程信息
当不输入查询条件时输入全部课程信息。
输入查询条件查询符合条件的课程信息。
约束:本教学机构查询本机构的课程信息。
下边从查询条件、查询列表两个方面分析数据模型
包括:课程名称、课程审核状态、课程发布状态
课程名称:可以模糊搜索
课程审核状态:未提交、已提交、审核通过、审核未通过
课程发布状态:未发布、已发布、已下线
因为是分页查询所以查询条件中还要包括当前页码、每页显示记录数。
查询结果中包括:课程id、课程名称、任务数、创建时间、是否付费、审核状态、类型,操作
任务数:该课程所包含的课程计划数,即课程章节数。
是否付费:课程包括免费、收费两种。
类型:录播、直播。
因为是分页查询所以查询结果中还要包括总记录数、当前页、每页显示记录数。
PO即持久对象(Persistent Object),它们是由一组属性和属性的get和set方法组成,PO对应于数据库的表
我们对应的这些类应该添加在xuecheng-plus-content-model工程中
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>
/**
* <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;
}
设计一个接口需要包括以下几个方面:
通常协议采用HTTP,查询类接口通常为get或post,查询条件较少的使用get,较多的使用post。
本接口使用 http post。
还要确定content-type,参数以什么数据格式提交,结果以什么数据格式响应。
一般情况没有特殊情况结果以json 格式响应。
根据前边对数据模型的分析,请求参数为:课程名称、课程审核状态、当前页码、每页显示记录数。
根据分析的请求参数定义模型类。
根据前边对数据模型的分析,响应结果为数据列表加一些分页信息(总记录数、当前页、每页显示记录数)。
数据列表中数据的属性包括:课程id、课程名称、任务数、创建时间、审核状态、类型。
注意:查询结果中的审核状态为数据字典中的代码字段,前端会根据审核状态代码 找到对应的名称显示。
根据分析的响应结果定义模型类。
分析完成,使用SpringBoot注解开发一个Http接口。
使用接口文档工具查看接口的内容。
接口中调用Service方法完成业务处理。
据接口分析需要定义模型类接收请求的参数,并定义模型类用于响应结果
这些一般是公共使用的,所以放在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;
}
}
针对分页查询结果经过分析也存在固定的数据和格式,所以在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;
}
}
这个类只有在是在xuecheng-plus-content工程模块中使用,所以我们把下面这个类添加在xuecheng-plus-content-model模块即可
/**
* @description 课程查询参数Dto
*/
@Data
@ToString
public class QueryCourseParamsDto {
//审核状态
private String auditStatus;
//课程名称
private String courseName;
//发布状态
private String publishStatus;
}
不管在前端向后端传输时间相关参数,还是后端向前端响应参数,时间格式都是如下所示:
为了解决上面默认的时间格式,我们在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());
};
}
}
<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>
<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>
我们定义的接口要写在xuecheng-plus-content-api工程中
接口描述图
PageParams对象接收pageNo字段和pageSize字段
QueryCourseParamsDto对象接收请求体中的auditStatus审核状态字段,courseName课程名称字段,publishStatus发布状态字段
/**
* 课程内容管理
*/
@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;
}
}
在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;
}
}
在xuecheng-plus-content-service层,不在model层
我们要实现课程查询的功能
/**
* <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每页大小和当前页的数据,是否为首页,是否为尾页,总页数等。
public interface CourseBaseMapper extends BaseMapper<CourseBase> {
}
<?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>
下面的文件是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
这是之前在Springboot学习的swaggerSpringboot集成Swagger_springboot项目集成swagger
在前后端分离开发中通常由后端程序员设计接口,完成后需要编写接口文档,最后将文档交给前端工程师,前端工程师参考文档进行开发
可以通过Swagger工具快速生成接口文档
添加到内容管理api工程
<!-- Spring Boot 集成 swagger -->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
在 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
这个文档存在两个问题:
1、接口名称显示course-base-info-controller名称不直观
2、课程查询是post方式只显示post /course/list即可。
这是之前在Springboot学习的swaggerSpringboot集成Swagger_springboot项目集成swagger
/**
* 课程内容管理
*/
@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查看接口信息
@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查看接口信息
@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 | 默认值 |
审核状态在查询条件和查询结果中都存在,审核状态包括:未审核、审核通过、审核未通过三种
思考一个问题:一个课程的审核状态如果是“审核未通过”那么在课程基本信息表记录“审核未通过”三个字合适吗?
如下图所示,合适嘛?
显然是不合适的,万一客户要求把“审核未通过”改成“通过”呢?我们要通过update修改,但是入了库的数据再修改会存在一定的风险,就算成功修改了,那以后客户在要求修改呢?
和审核状态同类的有好多这样的信息,比如:课程状态、课程类型、用户类型等等,这一类数据有一个共同点就是它有一些分类项,且这些分类项较为固定。
针对这些数据,为了提高系统的可扩展性,专门定义数据字典表去维护。
比如课程审核是否通过
[{"code":"202001","desc":"审核未通过"},{"code":"202002","desc":"未提交"},{"code":"202003","desc":"已提交"},{"code":"202004","desc":"审核通过"}]
比如课程发布情况
[{"code":"203001","desc":"未发布"},{"code":"203002","desc":"已发布"},{"code":"203003","desc":"下线"}]
而在我们课程表中会有两个字段与之对应
与之前一样,创建工程
@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);
}
}
@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;
}
}
public interface DictionaryMapper extends BaseMapper<Dictionary> {
}
@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;
}
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>