06-学成在线添加课程,包含课程基本信息,营销信息,课程计划信息,师资信息

添加课程基本/营销/计划信息

界面原型

第一步: 用户进入课程查询列表,点击添加课程按钮,选择课程类型是直播还是录播,课程类型不同那么授课方式也不同

  • 添加的课程和教学机构是一对一的关系

在这里插入图片描述

第二步: 用户选完课程形式后,点击下一步填写课程的基本信息和营销信息(两张表)

  • 用户只要填完课程信息就会把数据保存到数据库中,可以在课程管理中查看对应的课程发布信息,当审核状态为通过时发布按钮点亮

在这里插入图片描述

第三步: 填写课程计划信息即课程的大纲目录包括章节和小节,每个小节需要上传课程视频,用户点击小节标题即可开始播放视频,如果是直播课程则会进入直播间

在这里插入图片描述

第四步: 填写课程师资信息

在这里插入图片描述

数据模型

添加课程涉及到的数据表课程基本信息表

在这里插入图片描述

添加课程涉及到的数据表课程营销信息表

在这里插入图片描述

添加课程涉及到的数据表课程计划信息表

在这里插入图片描述

课程分类表course_category是一个树型结构表,通过parantid字段将表中的所有记录组成一个树

在这里插入图片描述

请求/响应模型(model工程)

第一步: 根据请求参数定义对应的请求模型类,添加课程的初始审核状态为未提交,初始发布状态为未发布

// 新增课程
POST {{content_host}}/content/course
Content-Type: application/json
{
  // 机构名称和Id根据当前登陆的用户获取,以下信息对应课程基本信息表	  
  "mt": "",大分类Id
  "st": "",小分类Id
  "name": "",课程名称
  "pic": "",课程图片
  "teachmode": "200002",教育模式
  "users": "初级人员",适用人群
  "tags": "",课程标签
  "grade": "204001",课程等级
  "description": "",课程介绍
   
   //以下信息对应课程营销表 
  "charge": "201000",收费规则
  "price": 0,现价
  "originalPrice":0,原价
  "qq": "",咨询QQ
  "wechat": "",微信
  "phone": "",电话
  "validDays": 365,有效期天数
}
package com.xuecheng.content.model.dto;
/**
 * @version 1.0
 * @description 添加课程dto
 */
@Data
@ApiModel(value = "AddCourseDto", description = "新增课程基本信息")
public class AddCourseDto {
    @ApiModelProperty(value = "课程名称", required = true)
    private String name;
    @ApiModelProperty(value = "适用人群", required = true)
    private String users;
    @ApiModelProperty(value = "课程标签")
    private String tags;
    @ApiModelProperty(value = "大分类", required = true)
    private String mt;
    @ApiModelProperty(value = "小分类", required = true)
    private String st;
    @ApiModelProperty(value = "课程等级", required = true)
    private String grade;
    @ApiModelProperty(value = "教学模式(普通,录播,直播等)", required = true)
    private String teachmode;
    @ApiModelProperty(value = "课程介绍")
    private String description;
    @ApiModelProperty(value = "课程图片", required = true)
    private String pic;
    @ApiModelProperty(value = "收费规则,对应数据字典", required = true)
    private String charge;
    @ApiModelProperty(value = "价格")
    private Float price;
    @ApiModelProperty(value = "原价")
    private Float originalPrice;
    @ApiModelProperty(value = "qq")
    private String qq;
    @ApiModelProperty(value = "微信")
    private String wechat;
    @ApiModelProperty(value = "电话")
    private String phone;

    @ApiModelProperty(value = "有效期")
    private Integer validDays;
}

第二步: 根据响应结果定义对应的响应模型类,由于其大部分信息来自课程基本信息表,所以我们可以将定义的响应结果模型类继承CourseBase

  • 大分类名称和小分类名称来自于课程分类表,需要根据请求参数中携带的大分类Id和小分类Id从数据库中获取
{
  "id": 109,
  "companyId": 1,
  "companyName": null,
  "name": "测试课程103",
  "users": "初级人员",
  "tags": "",
  "mt": "1-1",大分类Id
  "mtName": null,大分类名称,
  "st": "1-1-1",小分类Id
  "stName": null,小分类名称
  "grade": "204001",
  "teachmode": "200002",
  "description": "",
  "pic": "",
    
    
    
  "createDate": "2022-09-08 07:35:16",
  "changeDate": null,
  "createPeople": null,
  "changePeople": null,
  "auditStatus": "202002",
  "status": 1,
    
    
  "coursePubId": null,
  "coursePubDate": null,
  "charge": "201000",
  "price": null,
  "originalPrice":0,
  "qq": "",
  "wechat": "",
  "phone": "",
  "validDays": 365
}
package com.xuecheng.content.model.dto;
/**
 * @version 1.0
 * @description 课程基本信息dto
 */
@Data
public class CourseBaseInfoDto extends CourseBase {
    /**
     * 收费规则,对应数据字典
     */
    private String charge;

    /**
     * 价格
     */
    private Float price;

    /**
     * 原价
     */
    private Float originalPrice;

    /**
     * 咨询qq
     */
    private String qq;

    /**
     * 微信
     */
    private String wechat;

    /**
     * 电话
     */
    private String phone;

    /**
     * 有效期天数
     */
    private Integer validDays;

    /**
     * 大分类名称
     */
    private String mtName;

    /**
     * 小分类名称
     */
    private String stName;

}

接口定义(api工程)

@ApiOperation("新增课程基础信息接口")
@PostMapping("/course")
public CourseBaseInfoDto createCourseBase(@RequestBody AddCourseDto addCourseDto) {
    // 获取机构id(添加的课程和教学机构是一对一的关系),暂时以硬编码的方式指定机构Id后期通过当前登陆的教学机构获取
    Long companyId = 22L;
    return courseBaseInfoService.createCourseBase(companyId, addCourseDto);
}

业务开发(service工程)

第一步: 编写Mapper接口及其SQL映射文件

public interface CourseBaseMapper extends BaseMapper<CourseBase> {
}
public interface CourseCategoryMapper extends BaseMapper<CourseCategory> {
    // 使用递归查询分类
    public List<CourseCategoryTreeDto> selectTreeNodes(String id);
}
public interface CourseMarketMapper extends BaseMapper<CourseMarket> {
}

第二步: 编写Service接口及其实现类, 在业务逻辑代码中实现添加课程基本信息和课程营销信息的逻辑,由于操作两张表所以需要开启事务

  • 首先对请求参数做合法性校验(前端后端都要校验,Service和Controller层都要校验), 即判断一下用户是否输入了表单必填项以及设置一些参数的默认值
  • 然后对请求参数进行封装并调用课程基本信息表和课程营销信息表对应的Mapper接口进行数据持久化,课程基本信息和课程营销信息的Id相同
  • 最后将添加的课程基本信息和课程营销信息以及课程分类信息统一封装到CourseBaseInfoDto对象中并返回给前端
public interface CourseBaseInfoService {
    /**
 	* 新增课程基本信息
  	* @param companyId 教学机构id
 	* @param addCourseDto 课程基本信息
 	* @return
 	*/
    CourseBaseInfoDto createCourseBase(Long companyId, AddCourseDto addCourseDto);
}
@Slf4j
@Service
public class CourseBaseInfoServiceImpl implements CourseBaseInfoService {
    @Resource
    CourseBaseMapper courseBaseMapper;
    @Resource
    CourseMarketMapper courseMarketMapper;
    @Resource
    CourseCategoryMapper courseCategoryMapper;

    @Override
    @Transactional// 操作两张表需要开启事务
    public CourseBaseInfoDto createCourseBase(Long companyId, AddCourseDto addCourseDto) {
        // 1. 合法性校验
        if (StringUtils.isBlank(addCourseDto.getName())) {
            throw new RuntimeException("课程名称为空");
        }
        if (StringUtils.isBlank(addCourseDto.getMt())) {
            throw new RuntimeException("课程分类为空");
        }
        if (StringUtils.isBlank(addCourseDto.getSt())) {
            throw new RuntimeException("课程分类为空");
        }
        if (StringUtils.isBlank(addCourseDto.getGrade())) {
            throw new RuntimeException("课程等级为空");
        }
        if (StringUtils.isBlank(addCourseDto.getTeachmode())) {
            throw new RuntimeException("教育模式为空");
        }
        if (StringUtils.isBlank(addCourseDto.getUsers())) {
            throw new RuntimeException("适应人群为空");
        }
        if (StringUtils.isBlank(addCourseDto.getCharge())) {
            throw new RuntimeException("收费规则为空");
        }
        // 2. 将请求参数中包含的课程基本信息封装到对应的实体类对象当中
        CourseBase courseBase = new CourseBase();
        BeanUtils.copyProperties(addCourseDto, courseBase);
        // 2.1 设置默认审核状态(去数据字典表中查询状态码)
        courseBase.setAuditStatus("202002");
        // 2.2 设置默认发布状态
        courseBase.setStatus("203001");
        // 2.3 设置机构id
        courseBase.setCompanyId(companyId);
        // 2.4 设置添加时间
        courseBase.setCreateDate(LocalDateTime.now());
        // 2.5 向课程基本信息表中插入一条记录
        int baseInsert = courseBaseMapper.insert(courseBase);

        // 3.获取刚添加的课程基本信息记录的Id
        Long courseId = courseBase.getId();

        // 4. 将请求参数中包含的课程营销信息封装到对应的实体类对象当中
        CourseMarket courseMarket = new CourseMarket();
        BeanUtils.copyProperties(addCourseDto, courseMarket);
        // 设置课程营销信息的Id即我们刚添加的课程基本信息
        courseMarket.setId(courseId);
        // 4.1 判断收费规则,若课程收费,则价格必须大于0
        String charge = courseMarket.getCharge();
        if ("201001".equals(charge)) {
            // 价格可以使用Float类型存储,计算的时候使用BigDecimal计算
            Float price = addCourseDto.getPrice();
            if (price == null || price.floatValue() <= 0) {
                throw new RuntimeException("课程设置了收费,价格不能为空,且必须大于0");
            }
        }
        // 4.2 向课程营销信息表中插入一条记录
        int marketInsert = courseMarketMapper.insert(courseMarket);
        // 判断课程基本信息和营销信息是否插入成功
        if (baseInsert <= 0 || marketInsert <= 0) {
            throw new RuntimeException("新增课程基本信息失败");
        }

        // 5.根据插入课程基本信息/课程营销信息的Id,去课程基本信息表和课程营销信息表中查询刚添加的记录,组装成CourseBaseInfoDto对象返回给前端
        return getCourseBaseInfo(courseId);
    }
}

第三步: 根据刚插入的课程基本信息/课程营销信息的Id,去课程基本信息表和课程营销信息表中查询刚添加的记录,组装成CourseBaseInfoDto对象返回给前端

private CourseBaseInfoDto getCourseBaseInfo(Long courseId) {
    // 创建返回的Dto对象
    CourseBaseInfoDto courseBaseInfoDto = new CourseBaseInfoDto();
    // 1. 根据课程id查询课程基本信息
    CourseBase courseBase = courseBaseMapper.selectById(courseId);
    if (courseBase == null)
        return null;
    // 1.1 拷贝属性
    BeanUtils.copyProperties(courseBase, courseBaseInfoDto);
    // 2. 根据课程id查询课程营销信息
    CourseMarket courseMarket = courseMarketMapper.selectById(courseId);
    // 2.1 拷贝属性
    if (courseMarket != null)
        BeanUtils.copyProperties(courseMarket, courseBaseInfoDto);
    // 3. 查询课程分类名称并封装到到CourseBaseInfoDto对象中
    // 3.1 根据小分类id(1-1-1)查询对应的课程分类对象
    CourseCategory courseCategoryBySt = courseCategoryMapper.selectById(courseBase.getSt());
    // 3.2 设置课程的小分类名称
    courseBaseInfoDto.setStName(courseCategoryBySt.getName());
    // 3.3 根据大分类id(1-1)查询对应的课程分类对象
    CourseCategory courseCategoryByMt = courseCategoryMapper.selectById(courseBase.getMt());
    // 3.4 设置课程大分类名称
    courseBaseInfoDto.setMtName(courseCategoryByMt.getName());
    return courseBaseInfoDto;
}

接口测试

使用HTTP Client测试新增课程接口

POST {{content_host}}/content/course
Content-Type: application/json

{
  "mt": "1-1",
  "st": "1-1-1",
  "name": "测试课程tmp",
  "pic": "",
  "teachmode": "200002",
  "users": "初级人员",
  "tags": "",
  "grade": "204001",
  "description": "这是一门测试课程",
  "charge": "201000",
  "price": 99,
  "originalPrice": 999,
  "qq": "123564",
  "wechat": "123654",
  "phone": "156213",
  "validDays": 365
}

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

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

相关文章

在Visual Studio Code中安装加速TypeScript程序开发的插件

在Visual Studio Code中安装加速TypeScript程序开发的插件 Install Extensions on Visual Studio Code for TypeScript Application Development By Jackson 2023-11-28 众所周知&#xff0c;微软的Visual Studio Code是一款轻量级、功能强大的集成开发环境。它支持各种编程语…

ESXi 添加虚拟闪存 无可选设备问题排查

虚拟内存是计算机系统中的一种技术&#xff0c;它可以将计算机硬盘的一部分空间作为临时存储器来使用。当计算机的物理内存&#xff08;RAM&#xff09;不足时&#xff0c;操作系统可以将部分数据从内存移至硬盘的虚拟内存空间中&#xff0c;以释放内存供其他程序使用。虚拟内存…

双通道 12V 直流电机驱动芯片GC8548,可替代LV8548/LV8549/ONSEMI,内置 LDO,不需要逻辑电源,输入 兼容 3.3V 与 5V

GC8548 是一款双通道 12V 直流电机驱动芯 片&#xff0c;为摄像机、消费类产品、玩具和其他低压或 者电池供电的运动控制类应用提供了集成的电机 驱动解决方案。芯片一般用来驱动两个直流电机 或者驱动一个步进电机。 它可以工作在 3.8~12V 的电源电压上&#xff0c; 每通道能提…

全能音乐制作环境——水果编曲软件FL Studio 21.1版本下载安装配置

目录 前言一、FL Studio 安装二、使用配置总结 前言 FL Studio是一款流行的图像线软件制作和编辑音频文件。作为一款领先的创新产品&#xff0c;该软件能够满足在创作音乐方面的需求。有了这个产品&#xff0c;可以完成制作音乐的整个过程。可以使用这个软件进行写作&#xff…

Ubuntu新手使用教程

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Net6.0或Net7.0项目升级到Net8.0 并 消除.Net8中SqlSugar的警告

本文基于NetCore3.1或Net6.0项目升级到Net7.0&#xff0c;参考连接&#xff1a;NetCore3.1或Net6.0项目升级到Net7.0-CSDN博客 所有项目按照此步骤操作一遍&#xff0c;完成后再将所有引用的包&#xff08;即 *.dll&#xff09;更新升级到最新版&#xff08;注意&#xff1a;有…

【软件测试面试】项目经验回答+面试技巧和方法汇总...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、测试面试时问你…

如何设置带有密码的excel只读模式?

Excel只读模式大家都不陌生&#xff0c;那大家知道带有密码的只读模式吗&#xff1f;今天给大家分享如何设置带有密码的只读模式。 打开excel文件&#xff0c;将文件进行【另存为】设置&#xff0c;然后停留在保存路径的界面中&#xff0c;我们点击下面的工具 – 常规选项 在常…

人机交互3——多主题多轮对话

1.主动切换 2.被动切换 3.多轮状态记忆

城市内涝积水监测系统,全方位监测城市内涝

在城市规划与防灾减灾的领域中&#xff0c;城市内涝积水监测系统的构建至关重要。随着城市化进程的加快&#xff0c;城市内涝问题日益凸显&#xff0c;对市民的生活质量和生命财产安全构成威胁。为了应对这一问题&#xff0c;建设一套高效、精准的城市内涝积水监测系统势在必行…

【开发实践】网页预览excel表格原版样式

一、需求分析 由于业务部门需要&#xff0c;在导出excel表格页面&#xff0c;不需要先下载&#xff0c;就可以直接在页面上预览该表格文件。 二、代码实现 使用Luckysheet实现&#xff1a; 什么是Luckysheet Luckysheet &#xff0c;一款纯前端类似excel的在线表格&#xff0…

【已解决】AttributeError: module ‘matplotlib‘ has no attribute ‘imshow‘

首先 在学习OpenCV的第一个程序&#xff0c;碰到这个问题记录一下。首先我已经安装好了matplotlib 如下图&#xff1a; 所以可以排除的就是我已经具备了这个库&#xff0c;那就是我在调用的时候出现的问题。 其次 回到pycharm&#xff0c;检查一下代码并做出如下的修改。 …

el-table,列表合并,根据名称列名称相同的品名讲其它列值相同的进行合并

el-table,列表合并,根据名称列名称相同的品名讲其它列值相同的进行合并,并且不能垮品名合并 如图 用到el-table合并行的方法合并 tableSpanMethod({ row, column, rowIndex, columnIndex }) {if (column.property "materielName") {//合并商品名const _row this…

数据可视化:在Jupyter中使用Matplotlib绘制常用图表

Matplotlib是一个强大的数据可视化库&#xff0c;用于创建各种图表。 在Jupyter中使用Matplotlib可以轻松实现折线图、柱状图、散点图和饼图等常用图表。 本篇文章将为你详细讲解用matlpotlib绘制常用图表的方法。 1、折线图 折线图是展示数据趋势和变化的常见图表类型。 …

从零带你底层实现unordered_map (2)

&#x1f4af; 博客内容&#xff1a;从零带你实现unordered_map &#x1f600; 作  者&#xff1a;陈大大陈 &#x1f680; 个人简介&#xff1a;一个正在努力学技术的准C后端工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎私信&#xff01; &#x1f496; 欢迎大家…

8 有损压缩的.jpg图片文件格式详解,解封装拆包

有损压缩的.jpg文件 作者将狼才鲸创建日期2023-11-28 1&#xff09;简述 JPEG文件描述 JPEG协议格式分为JPEG、渐进式JPEG&#xff08;图片先显示一部分再显示全部&#xff09;、JPEG2000&#xff08;压缩品质更好&#xff0c;压缩率更高&#xff09;压缩模式&#xff1a;顺序…

如何进行无代码开发?有哪些无代码开发工具和无代码软件开发平台?

无代码开发是指不写代码&#xff0c;通过可视化工具进行应用程序开发。无代码开发让非技术用户通过拖拽和选择等简单操作&#xff0c;就能快速创建应用程序。 如何学习无代码开发 随着科技的不断发展&#xff0c;新的技术和工具不断涌现&#xff0c;无代码开发就是其中一种。掌…

C#中的async/await异步编程模型

前言 当谈到异步编程时&#xff0c;C#中的async/await是一个强大且方便的工具。它使得编写并发和异步操作变得更加简单和可读&#xff0c;同时提供良好的可维护性。本文将详细解释async/await的使用&#xff0c;以及如何在C#中有效地利用它来实现异步操作。 目录 前言1. async…

Win7 SP1 x64 Google Chrome 字体模糊

1 打开 Google Chrome &#xff0c;地址栏输入 chrome://version/ &#xff0c;字体模糊。 2 Microsoft Update Catalog 搜索现在更新 kb2670838 &#xff0c;安装&#xff0c;重启电脑。 3 打开 Google Chrome&#xff0c;地址栏输入 chrome://version/ &#xff0c;字体正常。…

Cache学习(4):Cache分配策略Cache更新策略Cache逐出策略

Cache的数据流 常用名词 Allocation 分配Eviction 驱逐分配策略和更新策略分别为当产生Cache miss和Cache hit的时候数据流的具体行为 1 Cache分配策略&#xff08;Cache Allocation Policy&#xff09; Cache的分配策略是指不同情况下为数据分配Cache Line的不同行为。Cac…