94781 字
约 315 分钟
50
servlet:
2026-09-26
无标签
附录D 内容管理服务模块源码详解
模块概览(面向 0 基础读者):
- 负责课程信息、分类、教学计划、课程发布管理。
- 拆分为 content-api、content-service、content-model 三层。
- 集成 MyBatis-Plus、Feign、XXL-Job、FreeMarker 实现课程发布全流程。
核心目录:
xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/apixuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/servicexuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/feignclientxuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/modelxuecheng-plus-content/xuecheng-plus-content-api/src/main/resources/templates
文件:xuecheng-plus-content/api/com/xuecheng/content/api/CourseBaseInfoController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.xuecheng.base.exception.ValidationGroups; // 导入 ValidationGroups 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.model.dto.AddCourseDto; // 导入 AddCourseDto 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.EditCourseDto; // 导入 EditCourseDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.apache.commons.lang.StringUtils; // 导入 StringUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.security.access.prepost.PreAuthorize; // 导入 PreAuthorize 类
import org.springframework.security.core.context.SecurityContextHolder; // 导入 SecurityContextHolder 类
import org.springframework.validation.annotation.Validated; // 导入 Validated 类
import org.springframework.web.bind.annotation.*; // 导入 * 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
import java.util.ArrayList; // 导入 ArrayList 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/11 15:44 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Api(value = "课程信息管理接口",tags = "课程信息管理接口") // 使用注解 @Api(value = "课程信息管理接口",tags = "课程信息管理接口")
@RestController // 使用注解 @RestController
public class CourseBaseInfoController { // 定义 class CourseBaseInfoController
@Autowired // 使用注解 @Autowired
CourseBaseInfoService courseBaseInfoService; // 执行语句
@ApiOperation("课程分页查询接口") // 使用注解 @ApiOperation("课程分页查询接口")
@PreAuthorize("hasAuthority('xc_teachmanager_course_list')")//指定权限标识符,拥有此权限才可以访问此方法 // 使用注解 @PreAuthorize("hasAuthority('xc_teachmanager_course_list')")
@PostMapping("/course/list") // 使用注解 @PostMapping("/course/list")
public PageResult<CourseBase> list(PageParams pageParams, @RequestBody(required=false) QueryCourseParamsDto queryCourseParamsDto) { // 定义方法 list(...)
//当前登录用户 // 保留原作者写的行内注释
SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
//用户所属机构id // 保留原作者写的行内注释
Long companyId = null; // 把变量 companyId 初始化为 null
if(StringUtils.isNotEmpty(user.getCompanyId())){ // 定义方法 方法(...)
companyId = Long.parseLong(user.getCompanyId()); // 把 Long.parseLong(user.getCompanyId()) 赋值给 companyId
} // 代码块结束
PageResult<CourseBase> courseBasePageResult = courseBaseInfoService.queryCourseBaseList(companyId,pageParams, queryCourseParamsDto); // 把 courseBaseInfoService.queryCourseBaseList(companyId,pageParams, queryCourseParamsDto) 赋值给 courseBasePageResult
return courseBasePageResult; // 返回 courseBasePageResult
} // 代码块结束
@ApiOperation("新增课程") // 使用注解 @ApiOperation("新增课程")
@PostMapping("/course") // 使用注解 @PostMapping("/course")
public CourseBaseInfoDto createCourseBase(@RequestBody @Validated(ValidationGroups.Inster.class) AddCourseDto addCourseDto){ // 定义方法 createCourseBase(...)
//获取到用户所属机构的id // 保留原作者写的行内注释
Long companyId = 1232141425L; // 把 1232141425L 赋值给 companyId
// int i = 1/0; // 保留原作者写的行内注释
CourseBaseInfoDto courseBase = courseBaseInfoService.createCourseBase(companyId, addCourseDto); // 把 courseBaseInfoService.createCourseBase(companyId, addCourseDto) 赋值给 courseBase
return courseBase; // 返回 courseBase
} // 代码块结束
@ApiOperation("根据课程id查询接口") // 使用注解 @ApiOperation("根据课程id查询接口")
@GetMapping("/course/{courseId}") // 使用注解 @GetMapping("/course/{courseId}")
public CourseBaseInfoDto getCourseBaseById(@PathVariable Long courseId){ // 定义方法 getCourseBaseById(...)
//获取当前用户的身份 // 保留原作者写的行内注释
// Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); // 保留原作者写的行内注释
// System.out.println(principal); // 保留原作者写的行内注释
SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
System.out.println(user.getUsername()); // 执行语句
CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId); // 把 courseBaseInfoService.getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
return courseBaseInfo; // 返回 courseBaseInfo
} // 代码块结束
@ApiOperation("修改课程") // 使用注解 @ApiOperation("修改课程")
@PutMapping("/course") // 使用注解 @PutMapping("/course")
public CourseBaseInfoDto modifyCourseBase(@RequestBody @Validated(ValidationGroups.Update.class) EditCourseDto editCourseDto){ // 定义方法 modifyCourseBase(...)
//获取到用户所属机构的id // 保留原作者写的行内注释
Long companyId = 1232141425L; // 把 1232141425L 赋值给 companyId
CourseBaseInfoDto courseBaseInfoDto = courseBaseInfoService.updateCourseBase(companyId, editCourseDto); // 把 courseBaseInfoService.updateCourseBase(companyId, editCourseDto) 赋值给 courseBaseInfoDto
return courseBaseInfoDto; // 返回 courseBaseInfoDto
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/com/xuecheng/content/api/CourseCategoryController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.service.CourseCategoryService; // 导入 CourseCategoryService 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程分类相关接口 // 保留原作者写的块注释
* @date 2023/2/12 11:54 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@RestController // 使用注解 @RestController
public class CourseCategoryController { // 定义 class CourseCategoryController
@Autowired // 使用注解 @Autowired
CourseCategoryService courseCategoryService; // 执行语句
@GetMapping("/course-category/tree-nodes") // 使用注解 @GetMapping("/course-category/tree-nodes")
public List<CourseCategoryTreeDto> queryTreeNodes() { // 定义方法 queryTreeNodes(...)
return courseCategoryService.queryTreeNodes("1"); // 返回 courseCategoryService.queryTreeNodes("1")
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/com/xuecheng/content/api/CourseOpenController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.PathVariable; // 导入 PathVariable 类
import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 类
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/21 10:33 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
// 获取课程信息接口 // 保留原作者写的行内注释
@RestController // 使用注解 @RestController
@RequestMapping("/open") // 使用注解 @RequestMapping("/open")
public class CourseOpenController { // 定义 class CourseOpenController
@Autowired // 使用注解 @Autowired
private CourseBaseInfoService courseBaseInfoService; // 执行语句
@Autowired // 使用注解 @Autowired
private CoursePublishService coursePublishService; // 执行语句
//根据课程id查询课程信息 // 保留原作者写的行内注释
@GetMapping("/course/whole/{courseId}") // 使用注解 @GetMapping("/course/whole/{courseId}")
public CoursePreviewDto getPreviewInfo(@PathVariable("courseId") Long courseId) { // 定义方法 getPreviewInfo(...)
//获取课程预览信息 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(courseId); // 把 coursePublishService.getCoursePreviewInfo(courseId) 赋值给 coursePreviewInfo
return coursePreviewInfo; // 返回 coursePreviewInfo
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/com/xuecheng/content/api/CoursePublishController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Controller; // 导入 Controller 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.PathVariable; // 导入 PathVariable 类
import org.springframework.web.bind.annotation.PostMapping; // 导入 PostMapping 类
import org.springframework.web.bind.annotation.ResponseBody; // 导入 ResponseBody 类
import org.springframework.web.servlet.ModelAndView; // 导入 ModelAndView 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程发布相关接口 // 保留原作者写的块注释
* @date 2023/2/21 9:28 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Controller // 使用注解 @Controller
public class CoursePublishController { // 定义 class CoursePublishController
@Autowired // 使用注解 @Autowired
CoursePublishService coursePublishService; // 执行语句
@ApiOperation("获取课程发布信息") // 使用注解 @ApiOperation("获取课程发布信息")
@ResponseBody // 使用注解 @ResponseBody
@GetMapping("/course/whole/{courseId}") // 使用注解 @GetMapping("/course/whole/{courseId}")
public CoursePreviewDto getCoursePublish(@PathVariable("courseId") Long courseId) { // 定义方法 getCoursePublish(...)
//封装数据 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewDto = new CoursePreviewDto(); // 创建 CoursePreviewDto 对象并赋值给 coursePreviewDto
//查询课程发布表 // 保留原作者写的行内注释
// CoursePublish coursePublish = coursePublishService.getCoursePublish(courseId); // 保留原作者写的行内注释
//先从缓存查询,缓存中有直接返回,没有再查询数据库 // 保留原作者写的行内注释
CoursePublish coursePublish = coursePublishService.getCoursePublishCache(courseId); // 把 coursePublishService.getCoursePublishCache(courseId) 赋值给 coursePublish
if(coursePublish == null){ // 定义方法 方法(...)
return coursePreviewDto; // 返回 coursePreviewDto
} // 代码块结束
//开始向coursePreviewDto填充数据 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfoDto = new CourseBaseInfoDto(); // 创建 CourseBaseInfoDto 对象并赋值给 courseBaseInfoDto
BeanUtils.copyProperties(coursePublish,courseBaseInfoDto); // 执行语句
//课程计划信息 // 保留原作者写的行内注释
String teachplanJson = coursePublish.getTeachplan(); // 把 coursePublish.getTeachplan() 的返回值赋给 teachplanJson
//转成List<TeachplanDto> // 保留原作者写的行内注释
List<TeachplanDto> teachplanDtos = JSON.parseArray(teachplanJson, TeachplanDto.class); // 把 JSON.parseArray(teachplanJson, TeachplanDto.class) 赋值给 teachplanDtos
coursePreviewDto.setCourseBase(courseBaseInfoDto); // 执行语句
coursePreviewDto.setTeachplans(teachplanDtos); // 执行语句
return coursePreviewDto; // 返回 coursePreviewDto
} // 代码块结束
// 课程预览接口 // 保留原作者写的行内注释
// 传入课程id,表示预览哪门课程 // 保留原作者写的行内注释
@GetMapping("/coursepreview/{courseId}") // 使用注解 @GetMapping("/coursepreview/{courseId}")
public ModelAndView preview(@PathVariable("courseId") Long courseId) { // 定义方法 preview(...)
ModelAndView modelAndView = new ModelAndView(); // 创建 ModelAndView 对象并赋值给 modelAndView
//查询课程的信息作为模型数据 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(courseId); // 把 coursePublishService.getCoursePreviewInfo(courseId) 赋值给 coursePreviewInfo
//指定模型 // 保留原作者写的行内注释
modelAndView.addObject("model", coursePreviewInfo); // 执行语句
//指定模板 // 保留原作者写的行内注释
modelAndView.setViewName("course_template");//根据视图名称加.ftl找到模板 // 执行语句
return modelAndView; // 返回 modelAndView
} // 代码块结束
// 提交审核 // 保留原作者写的行内注释
@ResponseBody // 使用注解 @ResponseBody
@PostMapping("/courseaudit/commit/{courseId}") // 使用注解 @PostMapping("/courseaudit/commit/{courseId}")
public void commitAudit(@PathVariable("courseId") Long courseId) { // 定义方法 commitAudit(...)
Long companyId = 1232141425L; // 把 1232141425L 赋值给 companyId
coursePublishService.commitAudit(companyId, courseId); // 执行语句
} // 代码块结束
@ApiOperation("课程发布") // 使用注解 @ApiOperation("课程发布")
@ResponseBody // 使用注解 @ResponseBody
@PostMapping ("/coursepublish/{courseId}") // 使用注解 @PostMapping ("/coursepublish/{courseId}")
public void coursepublish(@PathVariable("courseId") Long courseId){ // 定义方法 coursepublish(...)
Long companyId = 1232141425L; // 把 1232141425L 赋值给 companyId
coursePublishService.publish(companyId,courseId); // 执行语句
} // 代码块结束
@ApiOperation("查询课程发布信息") // 使用注解 @ApiOperation("查询课程发布信息")
@ResponseBody // 使用注解 @ResponseBody
@GetMapping("/r/coursepublish/{courseId}") // 使用注解 @GetMapping("/r/coursepublish/{courseId}")
public CoursePublish getCoursepublish(@PathVariable("courseId") Long courseId) { // 定义方法 getCoursepublish(...)
//查询课程发布信息 // 保留原作者写的行内注释
CoursePublish coursePublish = coursePublishService.getCoursePublish(courseId); // 把 coursePublishService.getCoursePublish(courseId) 赋值给 coursePublish
return coursePublish; // 返回 coursePublish
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/com/xuecheng/content/api/FreemarkerController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import org.springframework.stereotype.Controller; // 导入 Controller 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.servlet.ModelAndView; // 导入 ModelAndView 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description Freemarker入门程序 // 保留原作者写的块注释
* @date 2023/2/19 16:12 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Controller // 使用注解 @Controller
public class FreemarkerController { // 定义 class FreemarkerController
@GetMapping("/testfreemarker") // 使用注解 @GetMapping("/testfreemarker")
public ModelAndView test() { // 定义方法 test(...)
ModelAndView modelAndView = new ModelAndView(); // 创建 ModelAndView 对象并赋值给 modelAndView
//指定模型 // 保留原作者写的行内注释
modelAndView.addObject("name","小明"); // 执行语句
//指定模板 // 保留原作者写的行内注释
modelAndView.setViewName("test");//根据视图名称加.ftl找到模板 // 执行语句
return modelAndView; // 返回 modelAndView
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/com/xuecheng/content/api/SecurityUtil.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.alibaba.fastjson.JSON; // 导入 JSON 类
import lombok.Data; // 导入 Data 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.security.core.context.SecurityContextHolder; // 导入 SecurityContextHolder 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/24 11:26 // 保留原作者写的块注释
* 获取当前用户身份工具类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
public class SecurityUtil { // 定义 class SecurityUtil
public static XcUser getUser() { // 定义方法 getUser(...)
try { // 尝试执行可能抛出异常的代码
//拿到当前用户身份 // 保留原作者写的行内注释
Object principalObj = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); // 把 SecurityContextHolder.getContext().getAuthentication().getPrincipal() 的返回值赋给 principalObj
if (principalObj instanceof String) { // 定义方法 方法(...)
//取出用户身份信息 // 保留原作者写的行内注释
String principal = principalObj.toString(); // 把 principalObj.toString() 的返回值赋给 principal
//将json转成对象 // 保留原作者写的行内注释
XcUser user = JSON.parseObject(principal, XcUser.class); // 把 JSON.parseObject(principal, XcUser.class) 赋值给 user
return user; // 返回 user
} // 代码块结束
} catch (Exception e) { // 定义方法 catch(...)
log.error("获取当前登录用户身份出错:{}", e.getMessage()); // 执行语句
e.printStackTrace(); // 执行语句
} // 代码块结束
return null; // 返回 null
} // 代码块结束
@Data // 使用注解 @Data
public static class XcUser implements Serializable { // 代码逻辑
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
private String id; // 执行语句
private String username; // 执行语句
private String password; // 执行语句
private String salt; // 执行语句
private String name; // 执行语句
private String nickname; // 执行语句
private String wxUnionid; // 执行语句
private String companyId; // 执行语句
/** // 保留原作者写的块注释
* 头像 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String userpic; // 执行语句
private String utype; // 执行语句
private LocalDateTime birthday; // 执行语句
private String sex; // 执行语句
private String email; // 执行语句
private String cellphone; // 执行语句
private String qq; // 执行语句
/** // 保留原作者写的块注释
* 用户状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
private LocalDateTime createTime; // 执行语句
private LocalDateTime updateTime; // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/com/xuecheng/content/api/TeachplanController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.xuecheng.content.model.dto.BindTeachplanMediaDto; // 导入 BindTeachplanMediaDto 类
import com.xuecheng.content.model.dto.SaveTeachplanDto; // 导入 SaveTeachplanDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.service.TeachplanService; // 导入 TeachplanService 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.web.bind.annotation.*; // 导入 * 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程计划管理相关的接口 // 保留原作者写的块注释
* @date 2023/2/14 11:25 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Api(value = "课程计划编辑接口",tags = "课程计划编辑接口") // 使用注解 @Api(value = "课程计划编辑接口",tags = "课程计划编辑接口")
@RestController // 使用注解 @RestController
public class TeachplanController { // 定义 class TeachplanController
@Autowired // 使用注解 @Autowired
TeachplanService teachplanService; // 执行语句
@ApiOperation("查询课程计划树形结构") // 使用注解 @ApiOperation("查询课程计划树形结构")
//查询课程计划 GET /teachplan/22/tree-nodes // 保留原作者写的行内注释
@GetMapping("/teachplan/{courseId}/tree-nodes") // 使用注解 @GetMapping("/teachplan/{courseId}/tree-nodes")
public List<TeachplanDto> getTreeNodes(@PathVariable Long courseId){ // 定义方法 getTreeNodes(...)
List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId); // 把 teachplanService.findTeachplanTree(courseId) 赋值给 teachplanTree
return teachplanTree; // 返回 teachplanTree
} // 代码块结束
@ApiOperation("课程计划创建或修改") // 使用注解 @ApiOperation("课程计划创建或修改")
@PostMapping("/teachplan") // 使用注解 @PostMapping("/teachplan")
public void saveTeachplan( @RequestBody SaveTeachplanDto teachplan){ // 定义方法 saveTeachplan(...)
teachplanService.saveTeachplan(teachplan); // 执行语句
} // 代码块结束
@ApiOperation(value = "课程计划和媒资信息绑定") // 使用注解 @ApiOperation(value = "课程计划和媒资信息绑定")
@PostMapping("/teachplan/association/media") // 使用注解 @PostMapping("/teachplan/association/media")
public void associationMedia(@RequestBody BindTeachplanMediaDto bindTeachplanMediaDto){ // 定义方法 associationMedia(...)
teachplanService.associationMedia(bindTeachplanMediaDto); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/com/xuecheng/content/config/ResouceServerConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; // 导入 EnableGlobalMethodSecurity 类
import org.springframework.security.config.annotation.web.builders.HttpSecurity; // 导入 HttpSecurity 类
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; // 导入 EnableResourceServer 类
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; // 导入 ResourceServerConfigurerAdapter 类
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; // 导入 ResourceServerSecurityConfigurer 类
import org.springframework.security.oauth2.provider.token.TokenStore; // 导入 TokenStore 类
/** // 保留原作者写的块注释
* @description 资源服务配置 // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/10/18 16:33 // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
@EnableResourceServer // 使用注解 @EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) // 使用注解 @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class ResouceServerConfig extends ResourceServerConfigurerAdapter { // 定义 class ResouceServerConfig
//资源服务标识 // 保留原作者写的行内注释
public static final String RESOURCE_ID = "xuecheng-plus"; // 把 "xuecheng-plus" 赋值给 RESOURCE_ID
@Autowired // 使用注解 @Autowired
TokenStore tokenStore; // 执行语句
@Override // 使用注解 @Override
public void configure(ResourceServerSecurityConfigurer resources) { // 定义方法 configure(...)
resources.resourceId(RESOURCE_ID)//资源 id // 代码逻辑
.tokenStore(tokenStore) // 代码逻辑
.stateless(true); // 执行语句
} // 代码块结束
@Override // 使用注解 @Override
public void configure(HttpSecurity http) throws Exception { // 定义方法 configure(...)
http.csrf().disable() // 代码逻辑
.authorizeRequests() // 代码逻辑
// .antMatchers("/r/**","/course/**").authenticated()//所有/r/**的请求必须认证通过 // 保留原作者写的行内注释
.anyRequest().permitAll() // 代码逻辑
; // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/com/xuecheng/content/config/TokenConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; // 导入 AuthorizationServerTokenServices 类
import org.springframework.security.oauth2.provider.token.DefaultTokenServices; // 导入 DefaultTokenServices 类
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; // 导入 TokenEnhancerChain 类
import org.springframework.security.oauth2.provider.token.TokenStore; // 导入 TokenStore 类
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; // 导入 JwtAccessTokenConverter 类
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; // 导入 JwtTokenStore 类
import java.util.Arrays; // 导入 Arrays 类
/** // 保留原作者写的块注释
* @author Administrator // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
**/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
public class TokenConfig { // 定义 class TokenConfig
String SIGNING_KEY = "mq123"; // 把 "mq123" 赋值给 SIGNING_KEY
// @Bean // 保留原作者写的行内注释
// public TokenStore tokenStore() { // 保留原作者写的行内注释
// //使用内存存储令牌(普通令牌) // 保留原作者写的行内注释
// return new InMemoryTokenStore(); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
@Autowired // 使用注解 @Autowired
private JwtAccessTokenConverter accessTokenConverter; // 执行语句
@Bean // 使用注解 @Bean
public TokenStore tokenStore() { // 定义方法 tokenStore(...)
return new JwtTokenStore(accessTokenConverter()); // 返回 new JwtTokenStore(accessTokenConverter())
} // 代码块结束
@Bean // 使用注解 @Bean
public JwtAccessTokenConverter accessTokenConverter() { // 定义方法 accessTokenConverter(...)
JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); // 创建 JwtAccessTokenConverter 对象并赋值给 converter
converter.setSigningKey(SIGNING_KEY); // 执行语句
return converter; // 返回 converter
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/com/xuecheng/ContentApplication.java
package com.xuecheng; // 声明类所在的包路径
import com.spring4all.swagger.EnableSwagger2Doc; // 导入 EnableSwagger2Doc 类
import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类
import org.springframework.cloud.openfeign.EnableFeignClients; // 导入 EnableFeignClients 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 内容管理服务启动类 // 保留原作者写的块注释
* @date 2023/2/11 15:49 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@EnableFeignClients(basePackages={"com.xuecheng.content.feignclient"}) // 使用注解 @EnableFeignClients(basePackages={"com.xuecheng.content.feignclient"})
@EnableSwagger2Doc // 使用注解 @EnableSwagger2Doc
@SpringBootApplication // 使用注解 @SpringBootApplication
public class ContentApplication { // 定义 class ContentApplication
public static void main(String[] args) { // 定义方法 main(...)
SpringApplication.run(ContentApplication.class, args); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/api/resources/bootstrap.yml
spring: # Spring Boot 顶层配置前缀
application:
name: content-api # 注册到 Nacos 的服务名称
cloud:
nacos:
server-addr: 192.168.101.65:8848 # Nacos 服务器地址
discovery: # 服务发现配置
namespace: dev402 # 使用 dev402 命名空间隔离环境
group: xuecheng-plus-project # 服务分组,方便统一管理
config: # 配置中心相关设置
namespace: dev402 # 与服务发现保持一致
group: xuecheng-plus-project # 配置归属的分组
file-extension: yaml # 默认从 yaml 文件加载配置
refresh-enabled: true # 允许运行时刷新配置
extension-configs: # 额外加载的业务配置
- data-id: content-service-${spring.profiles.active}.yaml # 内容服务内部业务配置
group: xuecheng-plus-project
refresh: true
shared-configs: # 跨模块共享的通用配置
- data-id: swagger-${spring.profiles.active}.yaml # Swagger 文档配置
group: xuecheng-plus-common
refresh: true
- data-id: logging-${spring.profiles.active}.yaml # 日志级别与输出配置
group: xuecheng-plus-common
refresh: true
- data-id: freemarker-config-dev.yaml # Freemarker 模板渲染配置
group: xuecheng-plus-common
refresh: true
- data-id: feign-${spring.profiles.active}.yaml # OpenFeign 超时、负载等配置
group: xuecheng-plus-common
refresh: true
- data-id: redis-${spring.profiles.active}.yaml # Redis 连接信息
group: xuecheng-plus-common
refresh: true
profiles:
active: dev # 激活 dev 开发环境
文件:xuecheng-plus-content/api/resources/log4j2-dev.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- 声明日志配置使用的 XML 版本 -->
<Configuration monitorInterval="180" packages=""> <!-- 每 180 秒自动检测配置是否更新 -->
<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"/> <!-- 只接收 ERROR 级别以上 -->
<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"/> <!-- 接收 DEBUG 及以上日志 -->
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<Async name="AsyncAppender" includeLocation="true"> <!-- 采用异步输出,降低主线程压力 -->
<AppenderRef ref="ErrorAppender"/>
<AppenderRef ref="DebugAppender"/>
</Async>
</Appenders>
<Loggers> <!-- 自定义日志级别 -->
<logger name="org.springframework" level="INFO"/>
<logger name="org.mybatis" level="INFO"/>
<logger name="cn.itcast.wanxinp2p.consumer.mapper" level="DEBUG"/>
<logger name="springfox" level="INFO"/>
<logger name="org.apache.http" level="INFO"/>
<logger name="com.netflix.discovery" level="INFO"/>
<logger name="RocketmqCommon" level="INFO" />
<logger name="RocketmqRemoting" level="INFO" />
<logger name="RocketmqClient" level="WARN"/>
<logger name="org.dromara.hmily" level="WARN"/>
<logger name="org.dromara.hmily.lottery" level="WARN"/>
<logger name="org.dromara.hmily.bonuspoint" level="WARN"/>
<Root level="DEBUG" includeLocation="true"> <!-- 根日志器,默认 DEBUG 级别 -->
<AppenderRef ref="AsyncAppender"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="DebugAppender"/>
</Root>
</Loggers>
</Configuration>
文件:xuecheng-plus-content/api/resources/singleServerConfig.yaml
singleServerConfig: # ElasticJob Lite 单机配置
appName: content-job # 执行器名称
namespace: content-job-namespace # 注册中心命名空间
serverLists: 192.168.101.65:2181 # ZooKeeper 地址
operationTimeoutMilliseconds: 5000 # 操作超时时间
maxRetries: 3 # 失败重试次数
baseSleepTimeMilliseconds: 1000 # 初始重试间隔
maxSleepTimeMilliseconds: 3000 # 最大重试间隔
文件:xuecheng-plus-content/api/templates/course_template.ftl
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="/static/img/asset-favicon.ico">
<title>学成在线-${model.courseBase.name}</title>
<link rel="stylesheet" href="/static/plugins/normalize-css/normalize.css" />
<link rel="stylesheet" href="/static/plugins/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="/static/css/page-learing-article.css" />
</head>
<body data-spy="scroll" data-target="#articleNavbar" data-offset="150">
<!-- 页面头部 -->
<!--#include virtual="/include/header.html"-->
<!--页面头部结束sss-->
<div id="learningArea">
<div class="article-banner">
<div class="banner-bg"></div>
<div class="banner-info">
<div class="banner-left">
<p>${model.courseBase.mtName}<span>\ ${model.courseBase.stName}</span></p>
<p class="tit">${model.courseBase.name}</p>
<p class="pic">
<#if model.courseBase.charge=='201000'>
<span class="new-pic">免费</span>
<#else>
<span class="new-pic">特惠价格¥${model.courseBase.price!''}</span>
<span class="old-pic">原价¥${model.courseBase.originalPrice!''}</span>
</#if>
</p>
<p class="info">
<a href="#" @click.prevent="startLearning()">马上学习</a>
<span><em>难度等级</em>
<#if model.courseBase.grade=='204001'>
初级
<#elseif model.courseBase.grade=='204002'>
中级
<#elseif model.courseBase.grade=='204003'>
高级
</#if>
</span>
<span><em>课程时长</em>2小时27分</span>
<span><em>评分</em>4.7分</span>
<span><em>授课模式</em>
<#if model.courseBase.teachmode=='200002'>
录播
<#elseif model.courseBase.teachmode=='200003'>
直播
</#if>
</span>
</p>
</div>
<div class="banner-rit">
<p>
<a href="http://www.51xuecheng.cn/course/preview/learning.html?id=${model.courseBase.id}" target="_blank">
<#if model.courseBase.pic??>
<img src="http://file.51xuecheng.cn${model.courseBase.pic}" alt="" width="270" height="156">
<#else>
<img src="/static/img/widget-video.png" alt="" width="270" height="156">
</#if>
</a>
</p>
<p class="vid-act"><span> <i class="i-heart"></i>收藏 23 </span> <span>分享 <i class="i-weixin"></i><i class="i-qq"></i></span></p>
</div>
</div>
</div>
<div class="article-cont">
<div class="tit-list">
<a href="javascript:;" id="articleClass" class="active">课程介绍</a>
<a href="javascript:;" id="articleItem">目录</a>
<a href="javascript:;" id="artcleAsk">问答</a>
<a href="javascript:;" id="artcleNot">笔记</a>
<a href="javascript:;" id="artcleCod">评价</a>
<!--<div class="down-fill">
<span>资料下载</span>
<ul>
<li>java视频资料</li>
<li>java视频资料</li>
<li>java视频资料</li>
</ul>
</div>-->
</div>
<div class="article-box">
<div class="articleClass" style="display: block">
<!--<div class="rit-title">评价</div>-->
<div class="article-cont">
<div class="article-left-box">
<div class="content">
<div class="content-com suit">
<div class="title"><span>适用人群</span></div>
<div class="cont cktop">
<div >
<p>${model.courseBase.users!""}</p>
</div>
<!--<span class="on-off">更多 <i class="i-chevron-bot"></i></span>-->
</div>
</div>
<div class="content-com course">
<div class="title"><span>课程制作</span></div>
<div class="cont">
<div class="img-box"><img src="/static/img/widget-myImg.jpg" alt=""></div>
<div class="info-box">
<p class="name">教学方:<em>XX老师</em></p>
<!-- <p class="lab">高级前端开发工程师 10年开发经验</p>-->
<p class="info">JavaEE开发与教学多年,精通JavaEE技术体系,对流行框架JQuery、DWR、Struts1/2,Hibernate,Spring,MyBatis、JBPM、Lucene等有深入研究。授课逻辑严谨,条理清晰,注重学生独立解决问题的能力。</p>
<!-- <p><span>难度等级</span>中级</p>
<p><span>课程时长</span>8-16小时/周,共4周</p>
<p><span>如何通过</span>通过所有的作业及考核,作业共4份,考核为一次终极考核</p>
<p><span>用户评分</span>平均用户评分 <em>4.9</em> <a href="#">查看全部评价</a></p>
<p><span>课程价格</span>特惠价格<em>¥999</em> <i> 原价1999 </i></p>-->
</div>
</div>
</div>
<div class="content-com about">
<div class="title"><span>课程介绍</span></div>
<div class="cont cktop">
<div >
<p>${model.courseBase.description!""}</p>
</div>
<!--<span class="on-off">更多 <i class="i-chevron-bot"></i></span>-->
</div>
</div>
<div class="content-com prob">
<div class="title"><span>常见问题</span></div>
<div class="cont">
<ul>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 我什么时候能够访问课程视频与作业?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 如何需要额外的时间来完成课程会怎么样?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 我支付次课程之后会得到什么?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 退款条例是如何规定的?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 有助学金?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
<div class="articleItem" style="display: none">
<div class="article-cont-catalog">
<div class="article-left-box">
<div class="content">
<#list model.teachplans as firstNode>
<div class="item">
<div class="title act"><i class="i-chevron-top"></i>${firstNode.pname}<span class="time">x小时</span></div>
<div class="drop-down" style="height: 260px;">
<ul class="list-box">
<#list firstNode.teachPlanTreeNodes as secondNode>
<li><a href="http://www.51xuecheng.cn/course/preview/learning.html?id=${model.courseBase.id}&chapter=${secondNode.teachplanMedia.teachplanId!''}" target="_blank">${secondNode.pname}</a></li>
</#list>
</ul>
</div>
</div>
</#list>
<#-- <div class="item">
<div class="title act"><i class="i-chevron-top"></i>第一阶段 HTTP协议基础详解<span class="time">8小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down" style="height: 260px;">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>-->
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
<#--<div class="articleItem" style="display: none">
<div class="article-cont-catalog">
<div class="article-left-box">
<div class="content">
<div class="item">
<div class="title act"><i class="i-chevron-top"></i>第一阶段 HTTP协议基础详解<span class="time">8小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down" style="height: 260px;">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<div class="title"><i class="i-chevron-bot"></i>第二阶段 HTTP协议基础详解<span class="time">8小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<div class="title"><i class="i-chevron-bot"></i>第三阶段 HTTP协议基础详解<span class="time">3小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<div class="title"><i class="i-chevron-bot"></i>第四阶段 HTTP协议基础详解<span class="time">3小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<div class="title"><i class="i-chevron-bot"></i>第五阶段 HTTP协议基础详解<span class="time">3小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<a href="#" class="overwrite">毕业考核</a>
</div>
</div>
</div>
<!--侧边栏–>
<!--#include virtual="/include/course_detail_side.html"–>
<!--侧边栏–>
</div>
</div>-->
<div class="artcleAsk" style="display: none">
<div class="article-cont-ask">
<div class="article-left-box">
<div class="content">
<div class="content-title">
<p><a class="all">全部</a><a>精选</a><a>我的</a></p>
<p><a class="all">全部</a><span><a>1.1</a><a>1.2</a><a>1.3</a><a>1.4</a><a>1.5</a></span><a href="$" class="more">更多 <i class="i-chevron-bot"></i></a></p>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p><span>我来回答</span></p>
<p>2017-3-20 <span><i></i>回答2</span><span><i></i>浏览2</span></p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="itemlast">
<a href="#" class="overwrite">显示更多问题</a>
</div>
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
<div class="artcleNot" style="display: none;">
<div class="article-cont-note">
<div class="article-left-box">
<div class="content">
<div class="content-title">
<p><a class="all">全部</a><a>精选</a><a>我的</a></p>
<p><a class="all">全部</a><span><a>1.1</a><a>1.2</a><a>1.3</a><a>1.4</a><a>1.5</a></span><a href="$" class="more">更多 <i class="i-chevron-bot"></i></a></p>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<span class="video-time"><i class="i-play"></i>2`10`</span>
<p><img src="/static/img/widget-demo.png" width="221" alt=""></p>
<p class="action-box">4小时前 <span class="active-box"><span><i class="i-coll"></i>采集</span><span><i class="i-laud"></i>赞</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p>在讨论如何将重构转化为微服务之前,退后一步,<br>仔细观察微服务的内容和时间是很重要的。<br>以下两个要点将会对任何微服务重构策略产生重大影响。 </p>
<p class="action-box">4小时前 <span class="active-box"><span><i class="i-edt"></i>编辑</span><span><i class="i-del"></i>删除</span><span><i class="i-laud"></i>赞</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p>在讨论如何将重构转化为微服务之前,退后一步,<br>仔细观察微服务的内容和时间是很重要的。<br>以下两个要点将会对任何微服务重构策略产生重大影响。 </p>
<p class="action-box">4小时前 <span class="active-box"><span><i class="i-edt"></i>编辑</span><span><i class="i-del"></i>删除</span><span><i class="i-laud"></i>赞</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p>在讨论如何将重构转化为微服务之前,退后一步,<br>仔细观察微服务的内容和时间是很重要的。<br>以下两个要点将会对任何微服务重构策略产生重大影响。 </p>
<p class="action-box">4小时前 <span class="active-box"><span><i class="i-edt"></i>编辑</span><span><i class="i-del"></i>删除</span><span><i class="i-laud"></i>赞</span></span>
</p>
</div>
</div>
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
<div class="artcleCod" style="display: none;">
<div class="article-cont">
<div class="article-left-box">
<div class="comment-box">
<div class="evaluate">
<div class="eva-top">
<div class="tit">课程评分 </div>
<div class="star">
<div class="score"><i>5</i></div>
</div><span class="star-score"> <i>5</i> 分</span></div>
<div class="eva-cont">
<div class="tit">学员评语 </div>
<div class="text-box">
<textarea class="form-control" rows="5" placeholder="扯淡、吐槽、表扬、鼓励......想说啥说啥!"></textarea>
<div class="text-right"><span>发表评论</span></div>
</div>
</div>
</div>
<div class="course-evaluate">
<div class="top-tit">评论
<span>
<label><input name="eval" type="radio" value="" checked /> 所有学生 </label>
<label><input name="eval" type="radio" value="" /> 完成者 </label>
</span>
</div>
<div class="top-cont">
<div class="cont-top-left">
<div class="star-scor">
<div class="star-show">
<div class="score"><i>5</i></div>
</div>
<div class="scor">4.9分</div>
</div>
<div class="all-scor">总评分:12343</div>
</div>
<div class="cont-top-right">
<div class="star-grade">五星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>95</i>%</div>
</div>
</div>
<div class="star-grade">四星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>5</i>%</div>
</div>
</div>
<div class="star-grade">三星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>0</i>%</div>
</div>
</div>
<div class="star-grade">二星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>2</i>%</div>
</div>
</div>
<div class="star-grade">一星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>1</i>%</div>
</div>
</div>
</div>
</div>
<div class="comment-item-box">
<div class="title">评论 <span>12453条评论</span></div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-pic.png" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-cent">
<p>很受用,如果再深入下就更好了。虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!</p>
<p class="time">2017-2-43</p>
</div>
<div class="item-rit">
<p>
<div class="star-show">
<div class="score"><i>4</i></div>
</div>
</p>
<p>评分 <span>5星</span></p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-pic.png" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-cent">
<p>很受用,如果再深入下就更好了。虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!</p>
<p class="time">2017-2-43</p>
</div>
<div class="item-rit">
<p>
<div class="star-show">
<div class="score"><i>5</i></div>
</div>
</p>
<p>评分 <span>5星</span></p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-pic.png" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-cent">
<p>很受用,如果再深入下就更好了。虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!</p>
<p class="time">2017-2-43</p>
</div>
<div class="item-rit">
<p>
<div class="star-show">
<div class="score"><i>5</i></div>
</div>
</p>
<p>评分 <span>5星</span></p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-pic.png" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-cent">
<p>很受用,如果再深入下就更好了。虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!</p>
<p class="time">2017-2-43</p>
</div>
<div class="item-rit">
<p>
<div class="star-show">
<div class="score"><i>5</i></div>
</div>
</p>
<p>评分 <span>5星</span></p>
</div>
</div>
<div class="get-more">页面加载中...</div>
</div>
</div>
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
</div>
</div>
<div class="popup-course">
<div class="mask"></div>
<!--欢迎访问课程弹窗- start -->
<div class="popup-course-box">
<div class="title">${model.courseBase.name} <span class="close-popup-course-box">×</span></div>
<div class="content">
<p>欢迎学习本课程,本课程免费您可以立即学习,也可加入我的课程表享受更优质的服务。</p>
<p><a href="#" @click.prevent="addCourseTable()">加入我的课程表</a> <a href="#" @click.prevent="startLearngin()">立即学习</a></p>
</div>
</div>
</div>
<div class="popup-box">
<div class="mask"></div>
<!--支付弹窗- start -->
<div class="popup-pay-box">
<div class="title">${model.courseBase.name} <span class="close-popup-pay-box">×</span></div>
<div class="content">
<img :src="qrcode" width="200" height="200" alt="请点击支付宝支付按钮,并完成扫码支付。"/>
<div class="info">
<p class="info-tit">${model.courseBase.name}<span>课程有效期:${model.courseBase.validDays}天</span></p>
<p class="info-pic">课程价格 : <span>¥${model.courseBase.originalPrice!''}元</span></p>
<p class="info-new-pic">优惠价格 : <span>¥${model.courseBase.price!''}元</span></p>
</div>
</div>
<div class="fact-pic">实际支付: <span>¥${model.courseBase.price!''}元</span></div>
<div class="go-pay"><a href="#" @click.prevent="wxPay()">微信支付</a><a href="#" @click.prevent="aliPay()">支付宝支付</a><a href="#" @click.prevent="querypayresult()">支付完成</a><a href="#" @click.prevent="startLearngin()">试学</a></div>
</div>
<!--支付弹窗- end -->
<div class="popup-comment-box">
</div>
</div>
<!-- 页面底部 -->
<!--底部版权-->
<!--#include virtual="/include/footer.html"-->
<!--底部版权-->
</div>
<script>var courseId = "${model.courseBase.id}";var courseCharge = "${model.courseBase.charge}"</script>
<!--#include virtual="/include/course_detail_dynamic.html"-->
</body>
文件:xuecheng-plus-content/api/templates/test.ftl
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World!</title>
</head>
<body>
Hello ${name}!
</body>
</html>
文件:xuecheng-plus-content/api_pom.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- 内容 API 模块 -->
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId> <!-- 资源服务认证 -->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId> <!-- OAuth2 授权能力 -->
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <!-- 注册中心 -->
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <!-- 配置中心 -->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId> <!-- 支持动态刷新、环境变量 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <!-- 提供 Web MVC 能力 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId> <!-- 改用 log4j2 -->
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <!-- 参数校验 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId> <!-- 日志输出 -->
</dependency>
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.0.RELEASE</version> <!-- 自动生成接口文档 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId> <!-- 页面静态化渲染 -->
</dependency>
</dependencies>
</project>
文件:xuecheng-plus-content/com/xuecheng/content/model/dto/AddCourseDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import com.xuecheng.base.exception.ValidationGroups; // 导入 ValidationGroups 类
import io.swagger.annotations.ApiModel; // 导入 ApiModel 类
import io.swagger.annotations.ApiModelProperty; // 导入 ApiModelProperty 类
import lombok.Data; // 导入 Data 类
import javax.validation.constraints.NotEmpty; // 导入 NotEmpty 类
import javax.validation.constraints.Size; // 导入 Size 类
import java.math.BigDecimal; // 导入 BigDecimal 类
/** // 保留原作者写的块注释
* @description 添加课程dto // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/7 17:40 // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ApiModel(value="AddCourseDto", description="新增课程基本信息") // 使用注解 @ApiModel(value="AddCourseDto", description="新增课程基本信息")
public class AddCourseDto { // 定义 class AddCourseDto
@NotEmpty(message = "新增课程名称不能为空",groups={ValidationGroups.Inster.class}) // 使用注解 @NotEmpty(message = "新增课程名称不能为空",groups={ValidationGroups.Inster.class})
@NotEmpty(message = "修改课程名称不能为空",groups={ValidationGroups.Update.class}) // 使用注解 @NotEmpty(message = "修改课程名称不能为空",groups={ValidationGroups.Update.class})
// @NotEmpty(message = "课程名称不能为空") // 保留原作者写的行内注释
@ApiModelProperty(value = "课程名称", required = true) // 使用注解 @ApiModelProperty(value = "课程名称", required = true)
private String name; // 执行语句
@NotEmpty(message = "适用人群不能为空") // 使用注解 @NotEmpty(message = "适用人群不能为空")
@Size(message = "适用人群内容过少",min = 10) // 使用注解 @Size(message = "适用人群内容过少",min = 10)
@ApiModelProperty(value = "适用人群", required = true) // 使用注解 @ApiModelProperty(value = "适用人群", required = true)
private String users; // 执行语句
@ApiModelProperty(value = "课程标签") // 使用注解 @ApiModelProperty(value = "课程标签")
private String tags; // 执行语句
@NotEmpty(message = "课程分类不能为空") // 使用注解 @NotEmpty(message = "课程分类不能为空")
@ApiModelProperty(value = "大分类", required = true) // 使用注解 @ApiModelProperty(value = "大分类", required = true)
private String mt; // 执行语句
@NotEmpty(message = "课程分类不能为空") // 使用注解 @NotEmpty(message = "课程分类不能为空")
@ApiModelProperty(value = "小分类", required = true) // 使用注解 @ApiModelProperty(value = "小分类", required = true)
private String st; // 执行语句
@NotEmpty(message = "课程等级不能为空") // 使用注解 @NotEmpty(message = "课程等级不能为空")
@ApiModelProperty(value = "课程等级", required = true) // 使用注解 @ApiModelProperty(value = "课程等级", required = true)
private String grade; // 执行语句
@ApiModelProperty(value = "教学模式(普通,录播,直播等)", required = true) // 使用注解 @ApiModelProperty(value = "教学模式(普通,录播,直播等)", required = true)
private String teachmode; // 执行语句
@ApiModelProperty(value = "课程介绍") // 使用注解 @ApiModelProperty(value = "课程介绍")
@Size(message = "课程描述内容过少",min = 10) // 使用注解 @Size(message = "课程描述内容过少",min = 10)
private String description; // 执行语句
@ApiModelProperty(value = "课程图片", required = true) // 使用注解 @ApiModelProperty(value = "课程图片", required = true)
private String pic; // 执行语句
@NotEmpty(message = "收费规则不能为空") // 使用注解 @NotEmpty(message = "收费规则不能为空")
@ApiModelProperty(value = "收费规则,对应数据字典", required = true) // 使用注解 @ApiModelProperty(value = "收费规则,对应数据字典", required = true)
private String charge; // 执行语句
@ApiModelProperty(value = "价格") // 使用注解 @ApiModelProperty(value = "价格")
private Float price; // 执行语句
@ApiModelProperty(value = "原价") // 使用注解 @ApiModelProperty(value = "原价")
private Float originalPrice; // 执行语句
@ApiModelProperty(value = "qq") // 使用注解 @ApiModelProperty(value = "qq")
private String qq; // 执行语句
@ApiModelProperty(value = "微信") // 使用注解 @ApiModelProperty(value = "微信")
private String wechat; // 执行语句
@ApiModelProperty(value = "电话") // 使用注解 @ApiModelProperty(value = "电话")
private String phone; // 执行语句
@ApiModelProperty(value = "有效期") // 使用注解 @ApiModelProperty(value = "有效期")
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/dto/BindTeachplanMediaDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import io.swagger.annotations.ApiModel; // 导入 ApiModel 类
import io.swagger.annotations.ApiModelProperty; // 导入 ApiModelProperty 类
import lombok.Data; // 导入 Data 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 绑定媒资和课程计划的模型类 // 保留原作者写的块注释
* @date 2023/2/19 15:37 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ApiModel(value="BindTeachplanMediaDto", description="教学计划-媒资绑定提交数据") // 使用注解 @ApiModel(value="BindTeachplanMediaDto", description="教学计划-媒资绑定提交数据")
public class BindTeachplanMediaDto { // 定义 class BindTeachplanMediaDto
@ApiModelProperty(value = "媒资文件id", required = true) // 使用注解 @ApiModelProperty(value = "媒资文件id", required = true)
private String mediaId; // 执行语句
@ApiModelProperty(value = "媒资文件名称", required = true) // 使用注解 @ApiModelProperty(value = "媒资文件名称", required = true)
private String fileName; // 执行语句
@ApiModelProperty(value = "课程计划标识", required = true) // 使用注解 @ApiModelProperty(value = "课程计划标识", required = true)
private Long teachplanId; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/dto/CourseBaseInfoDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import io.swagger.annotations.ApiModelProperty; // 导入 ApiModelProperty 类
import lombok.Data; // 导入 Data 类
import java.math.BigDecimal; // 导入 BigDecimal 类
/** // 保留原作者写的块注释
* @description 课程基本信息dto // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/7 17:44 // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CourseBaseInfoDto extends CourseBase { // 定义 class CourseBaseInfoDto
/** // 保留原作者写的块注释
* 收费规则,对应数据字典 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
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; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/dto/CourseCategoryTreeDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import com.xuecheng.content.model.po.CourseCategory; // 导入 CourseCategory 类
import lombok.Data; // 导入 Data 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 11:51 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CourseCategoryTreeDto extends CourseCategory implements java.io.Serializable { // 定义 class CourseCategoryTreeDto
//子节点 // 保留原作者写的行内注释
List<CourseCategoryTreeDto> childrenTreeNodes; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/dto/CoursePreviewDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import lombok.Data; // 导入 Data 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程预览模型类 // 保留原作者写的块注释
* @date 2023/2/21 10:00 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CoursePreviewDto { // 定义 class CoursePreviewDto
//课程基本信息,营销信息 // 保留原作者写的行内注释
private CourseBaseInfoDto courseBase; // 执行语句
//课程计划信息 // 保留原作者写的行内注释
private List<TeachplanDto> teachplans; // 执行语句
//课程师资信息... // 保留原作者写的行内注释
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/dto/EditCourseDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import io.swagger.annotations.ApiModelProperty; // 导入 ApiModelProperty 类
import lombok.Data; // 导入 Data 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/14 10:22 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class EditCourseDto extends AddCourseDto { // 定义 class EditCourseDto
@ApiModelProperty(value = "课程id", required = true) // 使用注解 @ApiModelProperty(value = "课程id", required = true)
private Long id; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/dto/QueryCourseParamsDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程查询条件模型类 // 保留原作者写的块注释
* @date 2023/2/11 15:37 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class QueryCourseParamsDto { // 定义 class QueryCourseParamsDto
//审核状态 // 保留原作者写的行内注释
private String auditStatus; // 执行语句
//课程名称 // 保留原作者写的行内注释
private String courseName; // 执行语句
//发布状态 // 保留原作者写的行内注释
private String publishStatus; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/dto/SaveTeachplanDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import lombok.Data; // 导入 Data 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 新增大章节、小章节、修改章节信息 // 保留原作者写的块注释
* @date 2023/2/14 14:54 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class SaveTeachplanDto { // 定义 class SaveTeachplanDto
/*** // 保留原作者写的块注释
* 教学计划id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 课程计划名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pname; // 执行语句
/** // 保留原作者写的块注释
* 课程计划父级Id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long parentid; // 执行语句
/** // 保留原作者写的块注释
* 层级,分为1、2、3级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer grade; // 执行语句
/** // 保留原作者写的块注释
* 课程类型:1视频、2文档 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mediaType; // 执行语句
/** // 保留原作者写的块注释
* 课程标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long courseId; // 执行语句
/** // 保留原作者写的块注释
* 课程发布标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long coursePubId; // 执行语句
/** // 保留原作者写的块注释
* 是否支持试学或预览(试看) // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String isPreview; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/dto/TeachplanDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import com.xuecheng.content.model.po.Teachplan; // 导入 Teachplan 类
import com.xuecheng.content.model.po.TeachplanMedia; // 导入 TeachplanMedia 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程计划信息模型类 // 保留原作者写的块注释
* @date 2023/2/14 11:23 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class TeachplanDto extends Teachplan { // 定义 class TeachplanDto
//与媒资管理的信息 // 保留原作者写的行内注释
private TeachplanMedia teachplanMedia; // 执行语句
//小章节list // 保留原作者写的行内注释
private List<TeachplanDto> teachPlanTreeNodes; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/po/CourseBase.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.*; // 导入 * 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程基本信息 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_base") // 使用注解 @TableName("course_base")
public class CourseBase implements Serializable { // 定义 class CourseBase
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableId(value = "id", type = IdType.AUTO) // 使用注解 @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) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 修改时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT_UPDATE) // 使用注解 @TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime changeDate; // 执行语句
/** // 保留原作者写的块注释
* 创建人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String createPeople; // 执行语句
/** // 保留原作者写的块注释
* 更新人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String changePeople; // 执行语句
/** // 保留原作者写的块注释
* 审核状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String auditStatus; // 执行语句
/** // 保留原作者写的块注释
* 课程发布状态 未发布 已发布 下线 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/po/CourseCategory.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.TableName; // 导入 TableName 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程分类 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_category") // 使用注解 @TableName("course_category")
public class CourseCategory implements Serializable { // 定义 class CourseCategory
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String id; // 执行语句
/** // 保留原作者写的块注释
* 分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String name; // 执行语句
/** // 保留原作者写的块注释
* 分类标签默认和名称一样 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String label; // 执行语句
/** // 保留原作者写的块注释
* 父结点id(第一级的父节点是0,自关联字段id) // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String parentid; // 执行语句
/** // 保留原作者写的块注释
* 是否显示 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer isShow; // 执行语句
/** // 保留原作者写的块注释
* 排序字段 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer orderby; // 执行语句
/** // 保留原作者写的块注释
* 是否叶子 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer isLeaf; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/po/CourseMarket.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.TableName; // 导入 TableName 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程营销信息 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_market") // 使用注解 @TableName("course_market")
public class CourseMarket implements Serializable { // 定义 class CourseMarket
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键,课程id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 收费规则,对应数据字典 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String charge; // 执行语句
/** // 保留原作者写的块注释
* 现价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float price; // 执行语句
/** // 保留原作者写的块注释
* 原价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float originalPrice; // 执行语句
/** // 保留原作者写的块注释
* 咨询qq // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String qq; // 执行语句
/** // 保留原作者写的块注释
* 微信 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String wechat; // 执行语句
/** // 保留原作者写的块注释
* 电话 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String phone; // 执行语句
/** // 保留原作者写的块注释
* 有效期天数 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/po/CoursePublish.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.FieldFill; // 导入 FieldFill 类
import com.baomidou.mybatisplus.annotation.TableField; // 导入 TableField 类
import com.baomidou.mybatisplus.annotation.TableName; // 导入 TableName 类
import com.fasterxml.jackson.annotation.JsonFormat; // 导入 JsonFormat 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程发布 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_publish") // 使用注解 @TableName("course_publish")
public class CoursePublish implements Serializable { // 定义 class CoursePublish
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 机构ID // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long companyId; // 执行语句
/** // 保留原作者写的块注释
* 公司名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String companyName; // 执行语句
/** // 保留原作者写的块注释
* 课程名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String name; // 执行语句
/** // 保留原作者写的块注释
* 适用人群 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String users; // 执行语句
/** // 保留原作者写的块注释
* 标签 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String tags; // 执行语句
/** // 保留原作者写的块注释
* 创建人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String username; // 执行语句
/** // 保留原作者写的块注释
* 大分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mt; // 执行语句
/** // 保留原作者写的块注释
* 大分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mtName; // 执行语句
/** // 保留原作者写的块注释
* 小分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String st; // 执行语句
/** // 保留原作者写的块注释
* 小分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String stName; // 执行语句
/** // 保留原作者写的块注释
* 课程等级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String grade; // 执行语句
/** // 保留原作者写的块注释
* 教育模式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachmode; // 执行语句
/** // 保留原作者写的块注释
* 课程图片 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pic; // 执行语句
/** // 保留原作者写的块注释
* 课程介绍 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String description; // 执行语句
/** // 保留原作者写的块注释
* 课程营销信息,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String market; // 执行语句
/** // 保留原作者写的块注释
* 所有课程计划,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachplan; // 执行语句
/** // 保留原作者写的块注释
* 教师信息,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachers; // 执行语句
/** // 保留原作者写的块注释
* 发布时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 上架时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime onlineDate; // 执行语句
/** // 保留原作者写的块注释
* 下架时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime offlineDate; // 执行语句
/** // 保留原作者写的块注释
* 发布状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
/** // 保留原作者写的块注释
* 备注 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String remark; // 执行语句
/** // 保留原作者写的块注释
* 收费规则,对应数据字典--203 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String charge; // 执行语句
/** // 保留原作者写的块注释
* 现价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float price; // 执行语句
/** // 保留原作者写的块注释
* 原价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float originalPrice; // 执行语句
/** // 保留原作者写的块注释
* 课程有效期天数 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/po/CoursePublishPre.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.FieldFill; // 导入 FieldFill 类
import com.baomidou.mybatisplus.annotation.TableField; // 导入 TableField 类
import com.baomidou.mybatisplus.annotation.TableName; // 导入 TableName 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程发布 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_publish_pre") // 使用注解 @TableName("course_publish_pre")
public class CoursePublishPre implements Serializable { // 定义 class CoursePublishPre
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 机构ID // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long companyId; // 执行语句
/** // 保留原作者写的块注释
* 公司名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String companyName; // 执行语句
/** // 保留原作者写的块注释
* 课程名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String name; // 执行语句
/** // 保留原作者写的块注释
* 适用人群 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String users; // 执行语句
/** // 保留原作者写的块注释
* 标签 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String tags; // 执行语句
/** // 保留原作者写的块注释
* 创建人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String username; // 执行语句
/** // 保留原作者写的块注释
* 大分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mt; // 执行语句
/** // 保留原作者写的块注释
* 大分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mtName; // 执行语句
/** // 保留原作者写的块注释
* 小分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String st; // 执行语句
/** // 保留原作者写的块注释
* 小分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String stName; // 执行语句
/** // 保留原作者写的块注释
* 课程等级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String grade; // 执行语句
/** // 保留原作者写的块注释
* 教育模式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachmode; // 执行语句
/** // 保留原作者写的块注释
* 课程图片 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pic; // 执行语句
/** // 保留原作者写的块注释
* 课程介绍 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String description; // 执行语句
/** // 保留原作者写的块注释
* 课程营销信息,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String market; // 执行语句
/** // 保留原作者写的块注释
* 所有课程计划,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachplan; // 执行语句
/** // 保留原作者写的块注释
* 教师信息,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachers; // 执行语句
/** // 保留原作者写的块注释
* 提交时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 审核时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private LocalDateTime auditDate; // 执行语句
/** // 保留原作者写的块注释
* 状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
/** // 保留原作者写的块注释
* 备注 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String remark; // 执行语句
/** // 保留原作者写的块注释
* 收费规则,对应数据字典--203 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String charge; // 执行语句
/** // 保留原作者写的块注释
* 现价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float price; // 执行语句
/** // 保留原作者写的块注释
* 原价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float originalPrice; // 执行语句
/** // 保留原作者写的块注释
* 课程有效期天数 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/po/CourseTeacher.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.*; // 导入 * 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程-教师关系表 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_teacher") // 使用注解 @TableName("course_teacher")
public class CourseTeacher implements Serializable { // 定义 class CourseTeacher
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableId(value = "id", type = IdType.AUTO) // 使用注解 @TableId(value = "id", type = IdType.AUTO)
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 课程标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long courseId; // 执行语句
/** // 保留原作者写的块注释
* 教师标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teacherName; // 执行语句
/** // 保留原作者写的块注释
* 教师职位 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String position; // 执行语句
/** // 保留原作者写的块注释
* 教师简介 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String introduction; // 执行语句
/** // 保留原作者写的块注释
* 照片 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String photograph; // 执行语句
/** // 保留原作者写的块注释
* 创建时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/po/Teachplan.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.*; // 导入 * 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程计划 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("teachplan") // 使用注解 @TableName("teachplan")
public class Teachplan implements Serializable { // 定义 class Teachplan
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
@TableId(value = "id", type = IdType.AUTO) // 使用注解 @TableId(value = "id", type = IdType.AUTO)
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 课程计划名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pname; // 执行语句
/** // 保留原作者写的块注释
* 课程计划父级Id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long parentid; // 执行语句
/** // 保留原作者写的块注释
* 层级,分为1、2、3级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer grade; // 执行语句
/** // 保留原作者写的块注释
* 课程类型:1视频、2文档 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mediaType; // 执行语句
/** // 保留原作者写的块注释
* 开始直播时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private LocalDateTime startTime; // 执行语句
/** // 保留原作者写的块注释
* 直播结束时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private LocalDateTime endTime; // 执行语句
/** // 保留原作者写的块注释
* 章节及课程时介绍 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String description; // 执行语句
/** // 保留原作者写的块注释
* 时长,单位时:分:秒 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String timelength; // 执行语句
/** // 保留原作者写的块注释
* 排序字段 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer orderby; // 执行语句
/** // 保留原作者写的块注释
* 课程标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long courseId; // 执行语句
/** // 保留原作者写的块注释
* 课程发布标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long coursePubId; // 执行语句
/** // 保留原作者写的块注释
* 状态(1正常 0删除) // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer status; // 执行语句
/** // 保留原作者写的块注释
* 是否支持试学或预览(试看) // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String isPreview; // 执行语句
/** // 保留原作者写的块注释
* 创建时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 修改时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT_UPDATE) // 使用注解 @TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime changeDate; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/com/xuecheng/content/model/po/TeachplanMedia.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.*; // 导入 * 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("teachplan_media") // 使用注解 @TableName("teachplan_media")
public class TeachplanMedia implements Serializable { // 定义 class TeachplanMedia
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableId(value = "id", type = IdType.AUTO) // 使用注解 @TableId(value = "id", type = IdType.AUTO)
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 媒资文件id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mediaId; // 执行语句
/** // 保留原作者写的块注释
* 课程计划标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long teachplanId; // 执行语句
/** // 保留原作者写的块注释
* 课程标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long courseId; // 执行语句
/** // 保留原作者写的块注释
* 媒资文件原始名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField("media_fileName") // 使用注解 @TableField("media_fileName")
private String mediaFilename; // 执行语句
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 创建人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String createPeople; // 执行语句
/** // 保留原作者写的块注释
* 修改人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String changePeople; // 执行语句
} // 代码块结束
文件: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-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>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId> <!-- 支持 MyBatis-Plus 注解 -->
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId> <!-- MyBatis-Plus 核心包 -->
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <!-- 模型类使用 Lombok 简化代码 -->
</dependency>
</dependencies>
</project>
文件:xuecheng-plus-content/pom.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <!-- SQL 语句片段 -->
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- SQL 语句片段 -->
<modelVersion>4.0.0</modelVersion> <!-- SQL 语句片段 -->
<parent> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-parent</artifactId> <!-- SQL 语句片段 -->
<groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
<version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
<relativePath>../xuecheng-plus-parent</relativePath> <!-- SQL 语句片段 -->
</parent> <!-- SQL 语句片段 -->
<packaging>pom</packaging> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-content</artifactId> <!-- SQL 语句片段 -->
<modules> <!-- SQL 语句片段 -->
<module>xuecheng-plus-content-api</module> <!-- SQL 语句片段 -->
<module>xuecheng-plus-content-model</module> <!-- SQL 语句片段 -->
<module>xuecheng-plus-content-service</module> <!-- SQL 语句片段 -->
</modules> <!-- SQL 语句片段 -->
</project> <!-- SQL 语句片段 -->
文件:xuecheng-plus-content/root_pom.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- 聚合模块 POM 声明 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <!-- Maven 命名空间 -->
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> <!-- 使用 Maven4 模型 -->
<parent> <!-- 继承平台父工程,复用统一版本与插件 -->
<artifactId>xuecheng-plus-parent</artifactId>
<groupId>com.xuecheng</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../xuecheng-plus-parent</relativePath>
</parent>
<packaging>pom</packaging> <!-- 聚合模块本身不打包为 jar -->
<artifactId>xuecheng-plus-content</artifactId> <!-- 课程内容模块父工程 -->
<modules> <!-- 声明子模块 -->
<module>xuecheng-plus-content-api</module> <!-- 对外 REST API -->
<module>xuecheng-plus-content-model</module> <!-- 公共 DTO/PO 模型 -->
<module>xuecheng-plus-content-service</module> <!-- 业务实现与定时任务 -->
</modules>
</project>
文件:xuecheng-plus-content/service/com/xuecheng/content/config/MultipartSupportConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import feign.codec.Encoder; // 导入 Encoder 类
import feign.form.spring.SpringFormEncoder; // 导入 SpringFormEncoder 类
import org.apache.commons.fileupload.FileItem; // 导入 FileItem 类
import org.apache.commons.fileupload.disk.DiskFileItemFactory; // 导入 DiskFileItemFactory 类
import org.apache.commons.io.IOUtils; // 导入 IOUtils 类
import org.springframework.beans.factory.ObjectFactory; // 导入 ObjectFactory 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.autoconfigure.http.HttpMessageConverters; // 导入 HttpMessageConverters 类
import org.springframework.cloud.openfeign.support.SpringEncoder; // 导入 SpringEncoder 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
import org.springframework.context.annotation.Primary; // 导入 Primary 类
import org.springframework.context.annotation.Scope; // 导入 Scope 类
import org.springframework.http.MediaType; // 导入 MediaType 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import org.springframework.web.multipart.commons.CommonsMultipartFile; // 导入 CommonsMultipartFile 类
import java.io.File; // 导入 File 类
import java.io.FileInputStream; // 导入 FileInputStream 类
import java.io.OutputStream; // 导入 OutputStream 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2022/10/15 22:13 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
public class MultipartSupportConfig { // 定义 class MultipartSupportConfig
@Autowired // 使用注解 @Autowired
private ObjectFactory<HttpMessageConverters> messageConverters; // 执行语句
@Bean // 使用注解 @Bean
@Primary//注入相同类型的bean时优先使用 // 使用注解 @Primary
@Scope("prototype") // 使用注解 @Scope("prototype")
public Encoder feignEncoder() { // 定义方法 feignEncoder(...)
return new SpringFormEncoder(new SpringEncoder(messageConverters)); // 返回 new SpringFormEncoder(new SpringEncoder(messageConverters))
} // 代码块结束
//将file转为Multipart // 保留原作者写的行内注释
public static MultipartFile getMultipartFile(File file) { // 定义方法 getMultipartFile(...)
FileItem item = new DiskFileItemFactory().createItem("file", MediaType.MULTIPART_FORM_DATA_VALUE, true, file.getName()); // 创建 DiskFileItemFactory 对象并赋值给 item
try (FileInputStream inputStream = new FileInputStream(file); // 尝试执行可能抛出异常的代码
OutputStream outputStream = item.getOutputStream();) { // 定义方法 方法(...)
IOUtils.copy(inputStream, outputStream); // 执行语句
} catch (Exception e) { // 定义方法 catch(...)
e.printStackTrace(); // 执行语句
} // 代码块结束
return new CommonsMultipartFile(item); // 返回 new CommonsMultipartFile(item)
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/config/MybatisPlusConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.DbType; // 导入 DbType 类
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; // 导入 MybatisPlusInterceptor 类
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; // 导入 PaginationInnerInterceptor 类
import org.mybatis.spring.annotation.MapperScan; // 导入 MapperScan 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:23 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
@MapperScan("com.xuecheng.content.mapper") // 使用注解 @MapperScan("com.xuecheng.content.mapper")
public class MybatisPlusConfig { // 定义 class MybatisPlusConfig
/** // 保留原作者写的块注释
* 定义分页拦截器 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Bean // 使用注解 @Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() { // 定义方法 mybatisPlusInterceptor(...)
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 创建 MybatisPlusInterceptor 对象并赋值给 interceptor
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 执行语句
return interceptor; // 返回 interceptor
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/config/XxlJobConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; // 导入 XxlJobSpringExecutor 类
import org.slf4j.Logger; // 导入 Logger 类
import org.slf4j.LoggerFactory; // 导入 LoggerFactory 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
/** // 保留原作者写的块注释
* xxl-job config // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author xuxueli 2017-04-28 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
public class XxlJobConfig { // 定义 class XxlJobConfig
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class); // 把 LoggerFactory.getLogger(XxlJobConfig.class) 赋值给 logger
@Value("${xxl.job.admin.addresses}") // 使用注解 @Value("${xxl.job.admin.addresses}")
private String adminAddresses; // 执行语句
@Value("${xxl.job.accessToken}") // 使用注解 @Value("${xxl.job.accessToken}")
private String accessToken; // 执行语句
@Value("${xxl.job.executor.appname}") // 使用注解 @Value("${xxl.job.executor.appname}")
private String appname; // 执行语句
@Value("${xxl.job.executor.address}") // 使用注解 @Value("${xxl.job.executor.address}")
private String address; // 执行语句
@Value("${xxl.job.executor.ip}") // 使用注解 @Value("${xxl.job.executor.ip}")
private String ip; // 执行语句
@Value("${xxl.job.executor.port}") // 使用注解 @Value("${xxl.job.executor.port}")
private int port; // 执行语句
@Value("${xxl.job.executor.logpath}") // 使用注解 @Value("${xxl.job.executor.logpath}")
private String logPath; // 执行语句
@Value("${xxl.job.executor.logretentiondays}") // 使用注解 @Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays; // 执行语句
@Bean // 使用注解 @Bean
public XxlJobSpringExecutor xxlJobExecutor() { // 定义方法 xxlJobExecutor(...)
logger.info(">>>>>>>>>>> xxl-job config init."); // 执行语句
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); // 创建 XxlJobSpringExecutor 对象并赋值给 xxlJobSpringExecutor
xxlJobSpringExecutor.setAdminAddresses(adminAddresses); // 执行语句
xxlJobSpringExecutor.setAppname(appname); // 执行语句
xxlJobSpringExecutor.setAddress(address); // 执行语句
xxlJobSpringExecutor.setIp(ip); // 执行语句
xxlJobSpringExecutor.setPort(port); // 执行语句
xxlJobSpringExecutor.setAccessToken(accessToken); // 执行语句
xxlJobSpringExecutor.setLogPath(logPath); // 执行语句
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays); // 执行语句
return xxlJobSpringExecutor; // 返回 xxlJobSpringExecutor
} // 代码块结束
/** // 保留原作者写的块注释
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP; // 保留原作者写的块注释
* // 保留原作者写的块注释
* 1、引入依赖: // 保留原作者写的块注释
* <dependency> // 保留原作者写的块注释
* <groupId>org.springframework.cloud</groupId> // 保留原作者写的块注释
* <artifactId>spring-cloud-commons</artifactId> // 保留原作者写的块注释
* <version>${version}</version> // 保留原作者写的块注释
* </dependency> // 保留原作者写的块注释
* // 保留原作者写的块注释
* 2、配置文件,或者容器启动变量 // 保留原作者写的块注释
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.' // 保留原作者写的块注释
* // 保留原作者写的块注释
* 3、获取IP // 保留原作者写的块注释
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); // 保留原作者写的块注释
*/ // 保留原作者写的块注释
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/feignclient/CourseIndex.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import com.alibaba.fastjson.annotation.JSONField; // 导入 JSONField 类
import com.fasterxml.jackson.annotation.JsonFormat; // 导入 JsonFormat 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程索引信息 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CourseIndex implements Serializable { // 定义 class CourseIndex
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 机构ID // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long companyId; // 执行语句
/** // 保留原作者写的块注释
* 公司名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String companyName; // 执行语句
/** // 保留原作者写的块注释
* 课程名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String name; // 执行语句
/** // 保留原作者写的块注释
* 适用人群 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String users; // 执行语句
/** // 保留原作者写的块注释
* 标签 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String tags; // 执行语句
/** // 保留原作者写的块注释
* 大分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mt; // 执行语句
/** // 保留原作者写的块注释
* 大分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mtName; // 执行语句
/** // 保留原作者写的块注释
* 小分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String st; // 执行语句
/** // 保留原作者写的块注释
* 小分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String stName; // 执行语句
/** // 保留原作者写的块注释
* 课程等级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String grade; // 执行语句
/** // 保留原作者写的块注释
* 教育模式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachmode; // 执行语句
/** // 保留原作者写的块注释
* 课程图片 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pic; // 执行语句
/** // 保留原作者写的块注释
* 课程介绍 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String description; // 执行语句
/** // 保留原作者写的块注释
* 发布时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@JSONField(format="yyyy-MM-dd HH:mm:ss") // 使用注解 @JSONField(format="yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
/** // 保留原作者写的块注释
* 备注 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String remark; // 执行语句
/** // 保留原作者写的块注释
* 收费规则,对应数据字典--203 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String charge; // 执行语句
/** // 保留原作者写的块注释
* 现价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float price; // 执行语句
/** // 保留原作者写的块注释
* 原价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float originalPrice; // 执行语句
/** // 保留原作者写的块注释
* 课程有效期天数 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/feignclient/MediaServiceClient.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import com.xuecheng.content.config.MultipartSupportConfig; // 导入 MultipartSupportConfig 类
import org.springframework.cloud.openfeign.FeignClient; // 导入 FeignClient 类
import org.springframework.http.MediaType; // 导入 MediaType 类
import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 类
import org.springframework.web.bind.annotation.RequestParam; // 导入 RequestParam 类
import org.springframework.web.bind.annotation.RequestPart; // 导入 RequestPart 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.IOException; // 导入 IOException 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 远程调用媒资服务的接口 // 保留原作者写的块注释
* @date 2023/2/22 10:26 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
//使用fallback定义降级类是无法拿到熔断异常,使用FallbackFactory可以拿到熔断的异常信息 // 保留原作者写的行内注释
@FeignClient(value = "media-api",configuration = {MultipartSupportConfig.class},fallbackFactory = MediaServiceClientFallbackFactory.class) // 使用注解 @FeignClient(value = "media-api",configuration = {MultipartSupportConfig.class},fallbackFactory = MediaServiceClientFallbackFactory.class)
public interface MediaServiceClient { // 定义 interface MediaServiceClient
@RequestMapping(value = "/media/upload/coursefile",consumes = MediaType.MULTIPART_FORM_DATA_VALUE) // 使用注解 @RequestMapping(value = "/media/upload/coursefile",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String upload(@RequestPart("filedata") MultipartFile filedata, // 代码逻辑
@RequestParam(value= "objectName",required=false) String objectName) throws IOException; // 使用注解 @RequestParam(value= "objectName",required=false) String objectName) throws IOException;
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/feignclient/MediaServiceClientFallback.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.IOException; // 导入 IOException 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/22 11:06 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public class MediaServiceClientFallback implements MediaServiceClient{ // 定义 class MediaServiceClientFallback
@Override // 使用注解 @Override
public String upload(MultipartFile filedata, String objectName) throws IOException { // 定义方法 upload(...)
return null; // 返回 null
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/feignclient/MediaServiceClientFallbackFactory.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import feign.hystrix.FallbackFactory; // 导入 FallbackFactory 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.stereotype.Component; // 导入 Component 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.IOException; // 导入 IOException 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/22 11:09 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class MediaServiceClientFallbackFactory implements FallbackFactory<MediaServiceClient> { // 定义 class MediaServiceClientFallbackFactory
//拿到了熔断的异常信息throwable // 保留原作者写的行内注释
@Override // 使用注解 @Override
public MediaServiceClient create(Throwable throwable) { // 定义方法 create(...)
return new MediaServiceClient() { // 定义方法 MediaServiceClient(...)
//发生熔断上传服务调用此方法执行降级逻辑 // 保留原作者写的行内注释
@Override // 使用注解 @Override
public String upload(MultipartFile filedata, String objectName) throws IOException { // 定义方法 upload(...)
log.debug("远程调用上传文件的接口发生熔断:{}",throwable.toString(),throwable); // 执行语句
return null; // 返回 null
} // 代码块结束
}; // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/feignclient/SearchServiceClient.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import org.springframework.cloud.openfeign.FeignClient; // 导入 FeignClient 类
import org.springframework.web.bind.annotation.PostMapping; // 导入 PostMapping 类
import org.springframework.web.bind.annotation.RequestBody; // 导入 RequestBody 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/22 14:47 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@FeignClient(value = "search",fallbackFactory = SearchServiceClientFallbackFactory.class) // 使用注解 @FeignClient(value = "search",fallbackFactory = SearchServiceClientFallbackFactory.class)
public interface SearchServiceClient { // 定义 interface SearchServiceClient
@PostMapping("/search/index/course") // 使用注解 @PostMapping("/search/index/course")
public Boolean add(@RequestBody CourseIndex courseIndex); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/feignclient/SearchServiceClientFallbackFactory.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import feign.hystrix.FallbackFactory; // 导入 FallbackFactory 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.stereotype.Component; // 导入 Component 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/22 14:50 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class SearchServiceClientFallbackFactory implements FallbackFactory<SearchServiceClient> { // 定义 class SearchServiceClientFallbackFactory
@Override // 使用注解 @Override
public SearchServiceClient create(Throwable throwable) { // 定义方法 create(...)
return new SearchServiceClient() { // 定义方法 SearchServiceClient(...)
@Override // 使用注解 @Override
public Boolean add(CourseIndex courseIndex) { // 定义方法 add(...)
log.error("添加课程索引发生熔断,索引信息:{},熔断异常:{}",courseIndex,throwable.toString(),throwable); // 执行语句
//走降级了返回 false // 保留原作者写的行内注释
return false; // 返回 false
} // 代码块结束
}; // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CourseBaseMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程基本信息 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
// 课程预览使用的dao层 // 保留原作者写的行内注释
public interface CourseBaseMapper extends BaseMapper<CourseBase> { // 定义 interface CourseBaseMapper
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CourseBaseMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CourseBaseMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CourseBase"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
<result column="company_name" property="companyName" /> <!-- 字段与属性的映射规则 -->
<result column="name" property="name" /> <!-- 字段与属性的映射规则 -->
<result column="users" property="users" /> <!-- 字段与属性的映射规则 -->
<result column="tags" property="tags" /> <!-- 字段与属性的映射规则 -->
<result column="mt" property="mt" /> <!-- 字段与属性的映射规则 -->
<result column="st" property="st" /> <!-- 字段与属性的映射规则 -->
<result column="grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="teachmode" property="teachmode" /> <!-- 字段与属性的映射规则 -->
<result column="description" property="description" /> <!-- 字段与属性的映射规则 -->
<result column="pic" property="pic" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="change_date" property="changeDate" /> <!-- 字段与属性的映射规则 -->
<result column="create_people" property="createPeople" /> <!-- 字段与属性的映射规则 -->
<result column="change_people" property="changePeople" /> <!-- 字段与属性的映射规则 -->
<result column="audit_status" property="auditStatus" /> <!-- 字段与属性的映射规则 -->
<result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, company_id, company_name, name, users, tags, mt, st, grade, teachmode, description, pic, create_date, change_date, create_people, change_people, audit_status, status <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CourseCategoryMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.model.po.CourseCategory; // 导入 CourseCategory 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程分类 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseCategoryMapper extends BaseMapper<CourseCategory> { // 定义 interface CourseCategoryMapper
//使用递归查询分类 // 保留原作者写的行内注释
public List<CourseCategoryTreeDto> selectTreeNodes(String id); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CourseCategoryMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CourseCategoryMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CourseCategory"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="name" property="name" /> <!-- 字段与属性的映射规则 -->
<result column="label" property="label" /> <!-- 字段与属性的映射规则 -->
<result column="parentid" property="parentid" /> <!-- 字段与属性的映射规则 -->
<result column="is_show" property="isShow" /> <!-- 字段与属性的映射规则 -->
<result column="orderby" property="orderby" /> <!-- 字段与属性的映射规则 -->
<result column="is_leaf" property="isLeaf" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, name, label, parentid, is_show, orderby, is_leaf <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
<select id="selectTreeNodes" parameterType="string" resultType="com.xuecheng.content.model.dto.CourseCategoryTreeDto"> <!-- 定义 select 查询语句 -->
with recursive t1 as ( <!-- SQL 语句片段 -->
select * from course_category where id=#{id} <!-- 占位符参数 -->
union all <!-- SQL 语句片段 -->
select t2.* from course_category t2 inner join t1 on t1.id = t2.parentid <!-- SQL 语句片段 -->
) <!-- SQL 语句片段 -->
select * from t1 <!-- SQL 语句片段 -->
order by t1.id <!-- SQL 语句片段 -->
</select> <!-- SQL 语句片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CourseMarketMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CourseMarket; // 导入 CourseMarket 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程营销信息 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseMarketMapper extends BaseMapper<CourseMarket> { // 定义 interface CourseMarketMapper
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CourseMarketMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CourseMarketMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CourseMarket"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="charge" property="charge" /> <!-- 字段与属性的映射规则 -->
<result column="price" property="price" /> <!-- 字段与属性的映射规则 -->
<result column="original_price" property="originalPrice" /> <!-- 字段与属性的映射规则 -->
<result column="qq" property="qq" /> <!-- 字段与属性的映射规则 -->
<result column="wechat" property="wechat" /> <!-- 字段与属性的映射规则 -->
<result column="phone" property="phone" /> <!-- 字段与属性的映射规则 -->
<result column="valid_days" property="validDays" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, charge, price, original_price, qq, wechat, phone, valid_days <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CoursePublishMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程发布 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CoursePublishMapper extends BaseMapper<CoursePublish> { // 定义 interface CoursePublishMapper
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CoursePublishMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CoursePublishMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CoursePublish"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
<result column="company_name" property="companyName" /> <!-- 字段与属性的映射规则 -->
<result column="name" property="name" /> <!-- 字段与属性的映射规则 -->
<result column="users" property="users" /> <!-- 字段与属性的映射规则 -->
<result column="tags" property="tags" /> <!-- 字段与属性的映射规则 -->
<result column="username" property="username" /> <!-- 字段与属性的映射规则 -->
<result column="mt" property="mt" /> <!-- 字段与属性的映射规则 -->
<result column="mt_name" property="mtName" /> <!-- 字段与属性的映射规则 -->
<result column="st" property="st" /> <!-- 字段与属性的映射规则 -->
<result column="st_name" property="stName" /> <!-- 字段与属性的映射规则 -->
<result column="grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="teachmode" property="teachmode" /> <!-- 字段与属性的映射规则 -->
<result column="pic" property="pic" /> <!-- 字段与属性的映射规则 -->
<result column="description" property="description" /> <!-- 字段与属性的映射规则 -->
<result column="market" property="market" /> <!-- 字段与属性的映射规则 -->
<result column="teachplan" property="teachplan" /> <!-- 字段与属性的映射规则 -->
<result column="teachers" property="teachers" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="online_date" property="onlineDate" /> <!-- 字段与属性的映射规则 -->
<result column="offline_date" property="offlineDate" /> <!-- 字段与属性的映射规则 -->
<result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
<result column="remark" property="remark" /> <!-- 字段与属性的映射规则 -->
<result column="charge" property="charge" /> <!-- 字段与属性的映射规则 -->
<result column="price" property="price" /> <!-- 字段与属性的映射规则 -->
<result column="original_price" property="originalPrice" /> <!-- 字段与属性的映射规则 -->
<result column="valid_days" property="validDays" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, company_id, company_name, name, users, tags, username, mt, mt_name, st, st_name, grade, teachmode, pic, description, market, teachplan, teachers, create_date, online_date, offline_date, status, remark, charge, price, original_price, valid_days <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CoursePublishPreMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CoursePublishPre; // 导入 CoursePublishPre 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程发布 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CoursePublishPreMapper extends BaseMapper<CoursePublishPre> { // 定义 interface CoursePublishPreMapper
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CoursePublishPreMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CoursePublishPreMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CoursePublishPre"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
<result column="company_name" property="companyName" /> <!-- 字段与属性的映射规则 -->
<result column="name" property="name" /> <!-- 字段与属性的映射规则 -->
<result column="users" property="users" /> <!-- 字段与属性的映射规则 -->
<result column="tags" property="tags" /> <!-- 字段与属性的映射规则 -->
<result column="username" property="username" /> <!-- 字段与属性的映射规则 -->
<result column="mt" property="mt" /> <!-- 字段与属性的映射规则 -->
<result column="mt_name" property="mtName" /> <!-- 字段与属性的映射规则 -->
<result column="st" property="st" /> <!-- 字段与属性的映射规则 -->
<result column="st_name" property="stName" /> <!-- 字段与属性的映射规则 -->
<result column="grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="teachmode" property="teachmode" /> <!-- 字段与属性的映射规则 -->
<result column="pic" property="pic" /> <!-- 字段与属性的映射规则 -->
<result column="description" property="description" /> <!-- 字段与属性的映射规则 -->
<result column="market" property="market" /> <!-- 字段与属性的映射规则 -->
<result column="teachplan" property="teachplan" /> <!-- 字段与属性的映射规则 -->
<result column="teachers" property="teachers" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="audit_date" property="auditDate" /> <!-- 字段与属性的映射规则 -->
<result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
<result column="remark" property="remark" /> <!-- 字段与属性的映射规则 -->
<result column="charge" property="charge" /> <!-- 字段与属性的映射规则 -->
<result column="price" property="price" /> <!-- 字段与属性的映射规则 -->
<result column="original_price" property="originalPrice" /> <!-- 字段与属性的映射规则 -->
<result column="valid_days" property="validDays" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, company_id, company_name, name, users, tags, username, mt, mt_name, st, st_name, grade, teachmode, pic, description, market, teachplan, teachers, create_date, audit_date, status, remark, charge, price, original_price, valid_days <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CourseTeacherMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CourseTeacher; // 导入 CourseTeacher 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程-教师关系表 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseTeacherMapper extends BaseMapper<CourseTeacher> { // 定义 interface CourseTeacherMapper
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/CourseTeacherMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CourseTeacherMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CourseTeacher"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="teacher_name" property="teacherName" /> <!-- 字段与属性的映射规则 -->
<result column="position" property="position" /> <!-- 字段与属性的映射规则 -->
<result column="introduction" property="introduction" /> <!-- 字段与属性的映射规则 -->
<result column="photograph" property="photograph" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, course_id, teacher_name, position, introduction, photograph, create_date <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/TeachplanMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.model.po.Teachplan; // 导入 Teachplan 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程计划 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface TeachplanMapper extends BaseMapper<Teachplan> { // 定义 interface TeachplanMapper
//课程计划查询 // 保留原作者写的行内注释
public List<TeachplanDto> selectTreeNodes(Long courseId); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/TeachplanMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.TeachplanMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.Teachplan"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="pname" property="pname" /> <!-- 字段与属性的映射规则 -->
<result column="parentid" property="parentid" /> <!-- 字段与属性的映射规则 -->
<result column="grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="media_type" property="mediaType" /> <!-- 字段与属性的映射规则 -->
<result column="start_time" property="startTime" /> <!-- 字段与属性的映射规则 -->
<result column="end_time" property="endTime" /> <!-- 字段与属性的映射规则 -->
<result column="description" property="description" /> <!-- 字段与属性的映射规则 -->
<result column="timelength" property="timelength" /> <!-- 字段与属性的映射规则 -->
<result column="orderby" property="orderby" /> <!-- 字段与属性的映射规则 -->
<result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="course_pub_id" property="coursePubId" /> <!-- 字段与属性的映射规则 -->
<result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
<result column="is_preview" property="isPreview" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="change_date" property="changeDate" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, pname, parentid, grade, media_type, start_time, end_time, description, timelength, orderby, course_id, course_pub_id, status, is_preview, create_date, change_date <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
<resultMap id="treeNodeResultMap" type="com.xuecheng.content.model.dto.TeachplanDto"> <!-- 定义结果映射 -->
<id column="one_id" property="id" /> <!-- 主键列的映射规则 -->
<result column="one_pname" property="pname" /> <!-- 字段与属性的映射规则 -->
<result column="one_parentid" property="parentid" /> <!-- 字段与属性的映射规则 -->
<result column="one_grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="one_mediaType" property="mediaType" /> <!-- 字段与属性的映射规则 -->
<result column="one_stratTime" property="stratTime" /> <!-- 字段与属性的映射规则 -->
<result column="one_endTime" property="endTime" /> <!-- 字段与属性的映射规则 -->
<result column="one_orderby" property="orderby" /> <!-- 字段与属性的映射规则 -->
<result column="one_courseId" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="one_coursePubId" property="coursePubId" /> <!-- 字段与属性的映射规则 -->
<!--映射子节点,一对多映射,ofType list中的对象类型-->
<collection property="teachPlanTreeNodes" ofType="com.xuecheng.content.model.dto.TeachplanDto"> <!-- SQL 语句片段 -->
<id column="two_id" property="id" /> <!-- 主键列的映射规则 -->
<result column="two_pname" property="pname" /> <!-- 字段与属性的映射规则 -->
<result column="two_parentid" property="parentid" /> <!-- 字段与属性的映射规则 -->
<result column="two_grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="two_mediaType" property="mediaType" /> <!-- 字段与属性的映射规则 -->
<result column="two_stratTime" property="stratTime" /> <!-- 字段与属性的映射规则 -->
<result column="two_endTime" property="endTime" /> <!-- 字段与属性的映射规则 -->
<result column="two_orderby" property="orderby" /> <!-- 字段与属性的映射规则 -->
<result column="two_courseId" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="two_coursePubId" property="coursePubId" /> <!-- 字段与属性的映射规则 -->
<!--一对一映射-->
<association property="teachplanMedia" javaType="com.xuecheng.content.model.po.TeachplanMedia"> <!-- SQL 语句片段 -->
<id column="teachplanMeidaId" property="id"/> <!-- 主键列的映射规则 -->
<result column="mediaFilename" property="mediaFilename"/> <!-- 字段与属性的映射规则 -->
<result column="mediaId" property="mediaId"/> <!-- 字段与属性的映射规则 -->
</association> <!-- SQL 语句片段 -->
</collection> <!-- SQL 语句片段 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<select id="selectTreeNodes" parameterType="long" resultMap="treeNodeResultMap"> <!-- 定义 select 查询语句 -->
select <!-- SQL 语句片段 -->
one.id one_id, <!-- SQL 语句片段 -->
one.pname one_pname, <!-- SQL 语句片段 -->
one.parentid one_parentid, <!-- SQL 语句片段 -->
one.grade one_grade, <!-- SQL 语句片段 -->
one.media_type one_mediaType, <!-- SQL 语句片段 -->
one.start_time one_stratTime, <!-- SQL 语句片段 -->
one.end_time one_endTime, <!-- SQL 语句片段 -->
one.orderby one_orderby, <!-- SQL 语句片段 -->
one.course_id one_courseId, <!-- SQL 语句片段 -->
one.course_pub_id one_coursePubId, <!-- SQL 语句片段 -->
two.id two_id, <!-- SQL 语句片段 -->
two.pname two_pname, <!-- SQL 语句片段 -->
two.parentid two_parentid, <!-- SQL 语句片段 -->
two.grade two_grade, <!-- SQL 语句片段 -->
two.media_type two_mediaType, <!-- SQL 语句片段 -->
two.start_time two_stratTime, <!-- SQL 语句片段 -->
two.end_time two_endTime, <!-- SQL 语句片段 -->
two.orderby two_orderby, <!-- SQL 语句片段 -->
two.course_id two_courseId, <!-- SQL 语句片段 -->
two.course_pub_id two_coursePubId, <!-- SQL 语句片段 -->
m1.media_fileName mediaFilename, <!-- SQL 语句片段 -->
m1.id teachplanMeidaId, <!-- SQL 语句片段 -->
m1.media_id mediaId <!-- SQL 语句片段 -->
from teachplan one <!-- SQL 语句片段 -->
left join teachplan two on two.parentid = one.id <!-- SQL 语句片段 -->
left join teachplan_media m1 on two.id = m1.teachplan_id <!-- SQL 语句片段 -->
where one.parentid = 0 <!-- SQL 语句片段 -->
and one.course_id = #{id} <!-- 占位符参数 -->
order by one.orderby,two.orderby <!-- SQL 语句片段 -->
</select> <!-- SQL 语句片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/TeachplanMediaMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.TeachplanMedia; // 导入 TeachplanMedia 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface TeachplanMediaMapper extends BaseMapper<TeachplanMedia> { // 定义 interface TeachplanMediaMapper
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/mapper/TeachplanMediaMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.TeachplanMediaMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.TeachplanMedia"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="media_id" property="mediaId" /> <!-- 字段与属性的映射规则 -->
<result column="teachplan_id" property="teachplanId" /> <!-- 字段与属性的映射规则 -->
<result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="media_fileName" property="mediaFilename" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="create_people" property="createPeople" /> <!-- 字段与属性的映射规则 -->
<result column="change_people" property="changePeople" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, media_id, teachplan_id, course_id, media_fileName, create_date, create_people, change_people <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/service/com/xuecheng/content/service/CourseBaseInfoService.java
package com.xuecheng.content.service; // 声明类所在的包路径
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.model.dto.AddCourseDto; // 导入 AddCourseDto 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.EditCourseDto; // 导入 EditCourseDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程信息管理接口 // 保留原作者写的块注释
* @date 2023/2/12 10:14 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseBaseInfoService { // 定义 interface CourseBaseInfoService
/** // 保留原作者写的块注释
* 课程分页查询 // 保留原作者写的块注释
* @param pageParams 分页查询参数 // 保留原作者写的块注释
* @param courseParamsDto 查询条件 // 保留原作者写的块注释
* @param companyId 培训机构id // 保留原作者写的块注释
* @return 查询结果 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public PageResult<CourseBase> queryCourseBaseList(Long companyId,PageParams pageParams, QueryCourseParamsDto courseParamsDto); // 执行语句
/** // 保留原作者写的块注释
* 新增课程 // 保留原作者写的块注释
* @param companyId 机构id // 保留原作者写的块注释
* @param addCourseDto 课程信息 // 保留原作者写的块注释
* @return 课程详细信息 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CourseBaseInfoDto createCourseBase(Long companyId,AddCourseDto addCourseDto); // 执行语句
/** // 保留原作者写的块注释
* 根据课程id查询课程信息 // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return 课程详细信息 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CourseBaseInfoDto getCourseBaseInfo(Long courseId); // 执行语句
/** // 保留原作者写的块注释
* 修改课程 // 保留原作者写的块注释
* @param companyId 机构id // 保留原作者写的块注释
* @param editCourseDto 修改课程信息 // 保留原作者写的块注释
* @return 课程详细信息 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CourseBaseInfoDto updateCourseBase(Long companyId,EditCourseDto editCourseDto); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/service/CourseCategoryService.java
package com.xuecheng.content.service; // 声明类所在的包路径
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 14:49 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseCategoryService { // 定义 interface CourseCategoryService
/** // 保留原作者写的块注释
* 课程分类树形结构查询 // 保留原作者写的块注释
* // 保留原作者写的块注释
* @return // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public List<CourseCategoryTreeDto> queryTreeNodes(String id); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/service/CoursePublishService.java
package com.xuecheng.content.service; // 声明类所在的包路径
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import java.io.File; // 导入 File 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程发布相关的接口 // 保留原作者写的块注释
* @date 2023/2/21 10:03 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CoursePublishService { // 定义 interface CoursePublishService
/** // 保留原作者写的块注释
* @description 获取课程预览信息 // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return com.xuecheng.content.model.dto.CoursePreviewDto // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/16 15:36 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
// service接口层只关注业务 // 保留原作者写的行内注释
// controller层和service层的联系是controller层调用service实现类 // 保留原作者写的行内注释
public CoursePreviewDto getCoursePreviewInfo(Long courseId); // 执行语句
/** // 保留原作者写的块注释
* @description 提交审核 // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return void // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/18 10:31 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void commitAudit(Long companyId,Long courseId); // 执行语句
/** // 保留原作者写的块注释
* @description 课程发布接口 // 保留原作者写的块注释
* @param companyId 机构id // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return void // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/20 16:23 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void publish(Long companyId,Long courseId); // 执行语句
/** // 保留原作者写的块注释
* @description 课程静态化 // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return File 静态化文件 // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/23 16:59 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public File generateCourseHtml(Long courseId); // 执行语句
/** // 保留原作者写的块注释
* @description 上传课程静态化页面 // 保留原作者写的块注释
* @param file 静态化文件 // 保留原作者写的块注释
* @return void // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/23 16:59 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void uploadCourseHtml(Long courseId, File file); // 执行语句
/** // 保留原作者写的块注释
* 根据课程 id查询课程发布信息 // 保留原作者写的块注释
* @param courseId // 保留原作者写的块注释
* @return // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CoursePublish getCoursePublish(Long courseId); // 执行语句
public CoursePublish getCoursePublishCache(Long courseId); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/service/impl/CourseBaseInfoServiceImpl.java
package com.xuecheng.content.service.impl; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 Page 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.mapper.CourseCategoryMapper; // 导入 CourseCategoryMapper 类
import com.xuecheng.content.mapper.CourseMarketMapper; // 导入 CourseMarketMapper 类
import com.xuecheng.content.model.dto.AddCourseDto; // 导入 AddCourseDto 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.EditCourseDto; // 导入 EditCourseDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.model.po.CourseCategory; // 导入 CourseCategory 类
import com.xuecheng.content.model.po.CourseMarket; // 导入 CourseMarket 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类
import org.springframework.transaction.annotation.Transactional; // 导入 Transactional 类
import javax.annotation.Resources; // 导入 Resources 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 10:16 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class CourseBaseInfoServiceImpl implements CourseBaseInfoService { // 定义 class CourseBaseInfoServiceImpl
@Autowired // 使用注解 @Autowired
CourseBaseMapper courseBaseMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CourseMarketMapper courseMarketMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CourseCategoryMapper courseCategoryMapper; // 执行语句
@Override // 使用注解 @Override
public PageResult<CourseBase> queryCourseBaseList(Long companyId,PageParams pageParams, QueryCourseParamsDto courseParamsDto) { // 定义方法 queryCourseBaseList(...)
//拼装查询条件 // 保留原作者写的行内注释
LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>(); // 创建 LambdaQueryWrapper<> 对象并赋值给 queryWrapper
//根据名称模糊查询,在sql中拼接 course_base.name like '%值%' // 保留原作者写的行内注释
queryWrapper.like(StringUtils.isNotEmpty(courseParamsDto.getCourseName()),CourseBase::getName,courseParamsDto.getCourseName()); // 执行语句
//根据课程审核状态查询 course_base.audit_status = ? // 保留原作者写的行内注释
queryWrapper.eq(StringUtils.isNotEmpty(courseParamsDto.getAuditStatus()), CourseBase::getAuditStatus,courseParamsDto.getAuditStatus()); // 执行语句
//todo:按课程发布状态查询 // 保留原作者写的行内注释
//根据培训机构id拼装查询条件 // 保留原作者写的行内注释
queryWrapper.eq(CourseBase::getCompanyId,companyId); // 执行语句
//创建page分页参数对象,参数:当前页码,每页记录数 // 保留原作者写的行内注释
Page<CourseBase> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize()); // 创建 Page<> 对象并赋值给 page
//开始进行分页查询 // 保留原作者写的行内注释
Page<CourseBase> pageResult = courseBaseMapper.selectPage(page, queryWrapper); // 把 courseBaseMapper.selectPage(page, queryWrapper) 赋值给 pageResult
//数据列表 // 保留原作者写的行内注释
List<CourseBase> items = pageResult.getRecords(); // 把 pageResult.getRecords() 的返回值赋给 items
//总记录数 // 保留原作者写的行内注释
long total = pageResult.getTotal(); // 把 pageResult.getTotal() 的返回值赋给 total
//List<T> items, long counts, long page, long pageSize // 保留原作者写的行内注释
PageResult<CourseBase> courseBasePageResult = new PageResult<CourseBase>(items,total,pageParams.getPageNo(), pageParams.getPageSize()); // 创建 PageResult<CourseBase> 对象并赋值给 courseBasePageResult
return courseBasePageResult; // 返回 courseBasePageResult
} // 代码块结束
@Transactional // 使用注解 @Transactional
@Override // 使用注解 @Override
public CourseBaseInfoDto createCourseBase(Long companyId, AddCourseDto dto){ // 定义方法 createCourseBase(...)
//参数的合法性校验 // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getName())) { // 保留原作者写的行内注释
//// throw new RuntimeException("课程名称为空"); // 保留原作者写的行内注释
// XueChengPlusException.cast("课程名称为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getMt())) { // 保留原作者写的行内注释
// throw new RuntimeException("课程分类为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getSt())) { // 保留原作者写的行内注释
// throw new RuntimeException("课程分类为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getGrade())) { // 保留原作者写的行内注释
// throw new RuntimeException("课程等级为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getTeachmode())) { // 保留原作者写的行内注释
// throw new RuntimeException("教育模式为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getUsers())) { // 保留原作者写的行内注释
// throw new RuntimeException("适应人群为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getCharge())) { // 保留原作者写的行内注释
// throw new RuntimeException("收费规则为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
//向课程基本信息表course_base写入数据 // 保留原作者写的行内注释
CourseBase courseBaseNew = new CourseBase(); // 创建 CourseBase 对象并赋值给 courseBaseNew
//将传入的页面的参数放到courseBaseNew对象 // 保留原作者写的行内注释
// courseBaseNew.setName(dto.getName()); // 保留原作者写的行内注释
// courseBaseNew.setDescription(dto.getDescription()); // 保留原作者写的行内注释
//上边的从原始对象中get拿数据向新对象set,比较复杂 // 保留原作者写的行内注释
BeanUtils.copyProperties(dto,courseBaseNew);//只要属性名称一致就可以拷贝 // 执行语句
courseBaseNew.setCompanyId(companyId); // 执行语句
courseBaseNew.setCreateDate(LocalDateTime.now()); // 执行语句
//审核状态默认为未提交 // 保留原作者写的行内注释
courseBaseNew.setAuditStatus("202002"); // 执行语句
//发布状态为未发布 // 保留原作者写的行内注释
courseBaseNew.setStatus("203001"); // 执行语句
//插入数据库 // 保留原作者写的行内注释
int insert = courseBaseMapper.insert(courseBaseNew); // 把 courseBaseMapper.insert(courseBaseNew) 赋值给 insert
if(insert<=0){ // 定义方法 方法(...)
throw new RuntimeException("添加课程失败"); // 主动抛出异常
} // 代码块结束
//向课程营销系courese_market写入数据 // 保留原作者写的行内注释
CourseMarket courseMarketNew = new CourseMarket(); // 创建 CourseMarket 对象并赋值给 courseMarketNew
//将页面输入的数据拷贝到courseMarketNew // 保留原作者写的行内注释
BeanUtils.copyProperties(dto,courseMarketNew); // 执行语句
//课程的id // 保留原作者写的行内注释
Long courseId = courseBaseNew.getId(); // 把 courseBaseNew.getId() 的返回值赋给 courseId
courseMarketNew.setId(courseId); // 执行语句
//保存营销信息 // 保留原作者写的行内注释
saveCourseMarket(courseMarketNew); // 执行语句
//从数据库查询课程的详细信息,包括两部分 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfo = getCourseBaseInfo(courseId); // 把 getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
return courseBaseInfo; // 返回 courseBaseInfo
} // 代码块结束
//查询课程信息 // 保留原作者写的行内注释
public CourseBaseInfoDto getCourseBaseInfo(Long courseId){ // 定义方法 getCourseBaseInfo(...)
//从课程基本信息表查询 // 保留原作者写的行内注释
CourseBase courseBase = courseBaseMapper.selectById(courseId); // 把 courseBaseMapper.selectById(courseId) 赋值给 courseBase
if(courseBase==null){ // 定义方法 方法(...)
return null; // 返回 null
} // 代码块结束
//从课程营销表查询 // 保留原作者写的行内注释
CourseMarket courseMarket = courseMarketMapper.selectById(courseId); // 把 courseMarketMapper.selectById(courseId) 赋值给 courseMarket
//组装在一起 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfoDto = new CourseBaseInfoDto(); // 创建 CourseBaseInfoDto 对象并赋值给 courseBaseInfoDto
BeanUtils.copyProperties(courseBase,courseBaseInfoDto); // 执行语句
if(courseMarket!=null){ // 定义方法 方法(...)
BeanUtils.copyProperties(courseMarket,courseBaseInfoDto); // 执行语句
} // 代码块结束
//通过courseCategoryMapper查询分类信息,将分类名称放在courseBaseInfoDto对象 // 保留原作者写的行内注释
CourseCategory mtObj = courseCategoryMapper.selectById(courseBase.getMt()); // 把 courseCategoryMapper.selectById(courseBase.getMt()) 赋值给 mtObj
String mtName = mtObj.getName();//大分类名称 // 把 mtObj.getName() 的返回值赋给 mtName
courseBaseInfoDto.setMtName(mtName); // 执行语句
CourseCategory stObj = courseCategoryMapper.selectById(courseBase.getSt()); // 把 courseCategoryMapper.selectById(courseBase.getSt()) 赋值给 stObj
String stName = stObj.getName();//小分类名称 // 把 stObj.getName() 的返回值赋给 stName
courseBaseInfoDto.setStName(stName); // 执行语句
return courseBaseInfoDto; // 返回 courseBaseInfoDto
} // 代码块结束
@Override // 使用注解 @Override
public CourseBaseInfoDto updateCourseBase(Long companyId, EditCourseDto editCourseDto) { // 定义方法 updateCourseBase(...)
//拿到课程id // 保留原作者写的行内注释
Long courseId = editCourseDto.getId(); // 把 editCourseDto.getId() 的返回值赋给 courseId
//查询课程信息 // 保留原作者写的行内注释
CourseBase courseBase = courseBaseMapper.selectById(courseId); // 把 courseBaseMapper.selectById(courseId) 赋值给 courseBase
if(courseBase == null){ // 定义方法 方法(...)
XueChengPlusException.cast("课程不存在"); // 执行语句
} // 代码块结束
//数据合法性校验 // 保留原作者写的行内注释
//根据具体的业务逻辑去校验 // 保留原作者写的行内注释
//本机构只能修改本机构的课程 // 保留原作者写的行内注释
if(!companyId.equals(courseBase.getCompanyId())){ // 定义方法 方法(...)
XueChengPlusException.cast("本机构只能修改本机构的课程"); // 执行语句
} // 代码块结束
//封装数据 // 保留原作者写的行内注释
BeanUtils.copyProperties(editCourseDto,courseBase); // 执行语句
//修改时间 // 保留原作者写的行内注释
courseBase.setChangeDate(LocalDateTime.now()); // 执行语句
//更新数据库 // 保留原作者写的行内注释
int i = courseBaseMapper.updateById(courseBase); // 把 courseBaseMapper.updateById(courseBase) 赋值给 i
if(i<=0){ // 定义方法 方法(...)
XueChengPlusException.cast("修改课程失败"); // 执行语句
} // 代码块结束
//更新营销信息 // 保留原作者写的行内注释
CourseMarket courseMarket = new CourseMarket(); // 创建 CourseMarket 对象并赋值给 courseMarket
BeanUtils.copyProperties(editCourseDto,courseMarket); // 执行语句
saveCourseMarket(courseMarket); // 执行语句
//查询课程信息 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfo = getCourseBaseInfo(courseId); // 把 getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
return courseBaseInfo; // 返回 courseBaseInfo
} // 代码块结束
//单独写一个方法保存营销信息,逻辑:存在则更新,不存在则添加 // 保留原作者写的行内注释
private int saveCourseMarket(CourseMarket courseMarketNew){ // 定义方法 saveCourseMarket(...)
//参数的合法性校验 // 保留原作者写的行内注释
String charge = courseMarketNew.getCharge(); // 把 courseMarketNew.getCharge() 的返回值赋给 charge
if(StringUtils.isEmpty(charge)){ // 定义方法 方法(...)
throw new RuntimeException("收费规则为空"); // 主动抛出异常
} // 代码块结束
//如果课程收费,价格没有填写也需要抛出异常 // 保留原作者写的行内注释
if(charge.equals("201001")){ // 定义方法 方法(...)
if(courseMarketNew.getPrice() ==null || courseMarketNew.getPrice().floatValue()<=0){ // 定义方法 方法(...)
// throw new RuntimeException("课程的价格不能为空并且必须大于0"); // 保留原作者写的行内注释
XueChengPlusException.cast("课程的价格不能为空并且必须大于0"); // 执行语句
} // 代码块结束
} // 代码块结束
//从数据库查询营销信息,存在则更新,不存在则添加 // 保留原作者写的行内注释
Long id = courseMarketNew.getId();//主键 // 把 courseMarketNew.getId() 的返回值赋给 id
CourseMarket courseMarket = courseMarketMapper.selectById(id); // 把 courseMarketMapper.selectById(id) 赋值给 courseMarket
if(courseMarket == null){ // 定义方法 方法(...)
//插入数据库 // 保留原作者写的行内注释
int insert = courseMarketMapper.insert(courseMarketNew); // 把 courseMarketMapper.insert(courseMarketNew) 赋值给 insert
return insert; // 返回 insert
}else{ // 代码逻辑
//将courseMarketNew拷贝到courseMarket // 保留原作者写的行内注释
BeanUtils.copyProperties(courseMarketNew,courseMarket); // 执行语句
courseMarket.setId(courseMarketNew.getId()); // 执行语句
//更新 // 保留原作者写的行内注释
int i = courseMarketMapper.updateById(courseMarket); // 把 courseMarketMapper.updateById(courseMarket) 赋值给 i
return i; // 返回 i
} // 代码块结束
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/service/impl/CourseCategoryServiceImpl.java
package com.xuecheng.content.service.impl; // 声明类所在的包路径
import com.xuecheng.content.mapper.CourseCategoryMapper; // 导入 CourseCategoryMapper 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.service.CourseCategoryService; // 导入 CourseCategoryService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类
import java.util.ArrayList; // 导入 ArrayList 类
import java.util.List; // 导入 List 类
import java.util.Map; // 导入 Map 类
import java.util.stream.Collectors; // 导入 Collectors 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 14:49 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class CourseCategoryServiceImpl implements CourseCategoryService { // 定义 class CourseCategoryServiceImpl
@Autowired // 使用注解 @Autowired
CourseCategoryMapper courseCategoryMapper; // 执行语句
@Override // 使用注解 @Override
public List<CourseCategoryTreeDto> queryTreeNodes(String id) { // 定义方法 queryTreeNodes(...)
//调用mapper递归查询出分类信息 // 保留原作者写的行内注释
List<CourseCategoryTreeDto> courseCategoryTreeDtos = courseCategoryMapper.selectTreeNodes(id); // 把 courseCategoryMapper.selectTreeNodes(id) 赋值给 courseCategoryTreeDtos
//找到每个节点的子节点,最终封装成List<CourseCategoryTreeDto> // 保留原作者写的行内注释
//先将list转成map,key就是结点的id,value就是CourseCategoryTreeDto对象,目的就是为了方便从map获取结点,filter(item->!id.equals(item.getId()))把根结点排除 // 保留原作者写的行内注释
Map<String, CourseCategoryTreeDto> mapTemp = courseCategoryTreeDtos.stream().filter(item -> !id.equals(item.getId())).collect(Collectors.toMap(key -> key.getId(), value -> value, (key1, key2) -> key2)); // 把 courseCategoryTreeDtos.stream().filter(item -> !id.equals(item.getId())).collect(Collectors.toMap(key -> key.getId(), value -> value, (key1, key2) -> key2)) 赋值给 mapTemp
//定义一个list作为最终返回的list // 保留原作者写的行内注释
List<CourseCategoryTreeDto> courseCategoryList = new ArrayList<>(); // 创建 ArrayList<> 对象并赋值给 courseCategoryList
//从头遍历 List<CourseCategoryTreeDto> ,一边遍历一边找子节点放在父节点的childrenTreeNodes // 保留原作者写的行内注释
courseCategoryTreeDtos.stream().filter(item -> !id.equals(item.getId())).forEach(item -> { // 定义方法 方法(...)
if (item.getParentid().equals(id)) { // 定义方法 方法(...)
courseCategoryList.add(item); // 执行语句
} // 代码块结束
//找到节点的父节点 // 保留原作者写的行内注释
CourseCategoryTreeDto courseCategoryParent = mapTemp.get(item.getParentid()); // 把 mapTemp.get(item.getParentid()) 赋值给 courseCategoryParent
if(courseCategoryParent!=null){ // 定义方法 方法(...)
if(courseCategoryParent.getChildrenTreeNodes()==null){ // 定义方法 方法(...)
//如果该父节点的ChildrenTreeNodes属性为空要new一个集合,因为要向该集合中放它的子节点 // 保留原作者写的行内注释
courseCategoryParent.setChildrenTreeNodes(new ArrayList<CourseCategoryTreeDto>()); // 执行语句
} // 代码块结束
//到每个节点的子节点放在父节点的childrenTreeNodes属性中 // 保留原作者写的行内注释
courseCategoryParent.getChildrenTreeNodes().add(item); // 执行语句
} // 代码块结束
}); // 执行语句
return courseCategoryList; // 返回 courseCategoryList
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/service/impl/CoursePublishServiceImpl.java
package com.xuecheng.content.service.impl; // 声明类所在的包路径
import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.base.exception.CommonError; // 导入 CommonError 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.content.config.MultipartSupportConfig; // 导入 MultipartSupportConfig 类
import com.xuecheng.content.feignclient.MediaServiceClient; // 导入 MediaServiceClient 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.mapper.CourseMarketMapper; // 导入 CourseMarketMapper 类
import com.xuecheng.content.mapper.CoursePublishMapper; // 导入 CoursePublishMapper 类
import com.xuecheng.content.mapper.CoursePublishPreMapper; // 导入 CoursePublishPreMapper 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.model.po.CourseMarket; // 导入 CourseMarket 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.content.model.po.CoursePublishPre; // 导入 CoursePublishPre 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import com.xuecheng.content.service.TeachplanService; // 导入 TeachplanService 类
import com.xuecheng.messagesdk.model.po.MqMessage; // 导入 MqMessage 类
import com.xuecheng.messagesdk.service.MqMessageService; // 导入 MqMessageService 类
import freemarker.cache.ClassTemplateLoader; // 导入 ClassTemplateLoader 类
import freemarker.template.Configuration; // 导入 Configuration 类
import freemarker.template.Template; // 导入 Template 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.apache.commons.io.IOUtils; // 导入 IOUtils 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.redisson.api.RLock; // 导入 RLock 类
import org.redisson.api.RedissonClient; // 导入 RedissonClient 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.data.redis.core.RedisTemplate; // 导入 RedisTemplate 类
import org.springframework.stereotype.Service; // 导入 Service 类
import org.springframework.transaction.annotation.Transactional; // 导入 Transactional 类
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; // 导入 FreeMarkerTemplateUtils 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.File; // 导入 File 类
import java.io.FileOutputStream; // 导入 FileOutputStream 类
import java.io.InputStream; // 导入 InputStream 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
import java.util.HashMap; // 导入 HashMap 类
import java.util.List; // 导入 List 类
import java.util.Random; // 导入 Random 类
import java.util.concurrent.TimeUnit; // 导入 TimeUnit 类
import java.util.concurrent.locks.ReentrantLock; // 导入 ReentrantLock 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程发布相关接口实现 // 保留原作者写的块注释
* @date 2023/2/21 10:04 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class CoursePublishServiceImpl implements CoursePublishService { // 定义 class CoursePublishServiceImpl
@Autowired // 使用注解 @Autowired
CourseBaseInfoService courseBaseInfoService; // 执行语句
@Autowired // 使用注解 @Autowired
TeachplanService teachplanService; // 执行语句
@Autowired // 使用注解 @Autowired
CourseBaseMapper courseBaseMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CourseMarketMapper courseMarketMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CoursePublishPreMapper coursePublishPreMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CoursePublishMapper coursePublishMapper; // 执行语句
@Autowired // 使用注解 @Autowired
MqMessageService mqMessageService; // 执行语句
@Autowired // 使用注解 @Autowired
MediaServiceClient mediaServiceClient; // 执行语句
@Autowired // 使用注解 @Autowired
RedisTemplate redisTemplate; // 执行语句
@Autowired // 使用注解 @Autowired
RedissonClient redissonClient; // 执行语句
// 课程预览 // 保留原作者写的行内注释
@Override // 使用注解 @Override
public CoursePreviewDto getCoursePreviewInfo(Long courseId) { // 定义方法 getCoursePreviewInfo(...)
CoursePreviewDto coursePreviewDto = new CoursePreviewDto(); // 创建 CoursePreviewDto 对象并赋值给 coursePreviewDto
//课程基本信息,营销信息 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId); // 把 courseBaseInfoService.getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
coursePreviewDto.setCourseBase(courseBaseInfo); // 执行语句
//课程计划信息 // 保留原作者写的行内注释
List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId); // 把 teachplanService.findTeachplanTree(courseId) 赋值给 teachplanTree
coursePreviewDto.setTeachplans(teachplanTree); // 执行语句
return coursePreviewDto; // 返回 coursePreviewDto
} // 代码块结束
// 提交审核 // 保留原作者写的行内注释
@Transactional // 使用注解 @Transactional
@Override // 使用注解 @Override
public void commitAudit(Long companyId, Long courseId) { // 定义方法 commitAudit(...)
CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId); // 把 courseBaseInfoService.getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
if (courseBaseInfo == null) { // 定义方法 方法(...)
XueChengPlusException.cast("课程找不到"); // 执行语句
} // 代码块结束
//审核状态 // 保留原作者写的行内注释
String auditStatus = courseBaseInfo.getAuditStatus(); // 把 courseBaseInfo.getAuditStatus() 的返回值赋给 auditStatus
//如果课程的审核状态为已提交则不允许提交 // 保留原作者写的行内注释
if (auditStatus.equals("202003")) { // 定义方法 方法(...)
XueChengPlusException.cast("课程已提交请等待审核"); // 执行语句
} // 代码块结束
//本机构只能提交本机构的课程 // 保留原作者写的行内注释
//todo:本机构只能提交本机构的课程 // 保留原作者写的行内注释
//课程的图片、计划信息没有填写也不允许提交 // 保留原作者写的行内注释
String pic = courseBaseInfo.getPic(); // 把 courseBaseInfo.getPic() 的返回值赋给 pic
if (StringUtils.isEmpty(pic)) { // 定义方法 方法(...)
XueChengPlusException.cast("请求上传课程图片"); // 执行语句
} // 代码块结束
//查询课程计划 // 保留原作者写的行内注释
//课程计划信息 // 保留原作者写的行内注释
List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId); // 把 teachplanService.findTeachplanTree(courseId) 赋值给 teachplanTree
if (teachplanTree == null || teachplanTree.size() == 0) { // 定义方法 方法(...)
XueChengPlusException.cast("请编写课程计划"); // 执行语句
} // 代码块结束
//查询到课程基本信息、营销信息、计划等信息插入到课程预发布表 // 保留原作者写的行内注释
CoursePublishPre coursePublishPre = new CoursePublishPre(); // 创建 CoursePublishPre 对象并赋值给 coursePublishPre
BeanUtils.copyProperties(courseBaseInfo, coursePublishPre); // 执行语句
//设置机构id // 保留原作者写的行内注释
coursePublishPre.setCompanyId(companyId); // 执行语句
//营销信息 // 保留原作者写的行内注释
CourseMarket courseMarket = courseMarketMapper.selectById(courseId); // 把 courseMarketMapper.selectById(courseId) 赋值给 courseMarket
//转json // 保留原作者写的行内注释
String courseMarketJson = JSON.toJSONString(courseMarket); // 把 JSON.toJSONString(courseMarket) 赋值给 courseMarketJson
coursePublishPre.setMarket(courseMarketJson); // 执行语句
//计划信息 // 保留原作者写的行内注释
//转json // 保留原作者写的行内注释
String teachplanTreeJson = JSON.toJSONString(teachplanTree); // 把 JSON.toJSONString(teachplanTree) 赋值给 teachplanTreeJson
coursePublishPre.setTeachplan(teachplanTreeJson); // 执行语句
//状态为已提交 // 保留原作者写的行内注释
coursePublishPre.setStatus("202003"); // 执行语句
//提交时间 // 保留原作者写的行内注释
coursePublishPre.setCreateDate(LocalDateTime.now()); // 执行语句
//查询预发布表,如果有记录则更新,没有则插入 // 保留原作者写的行内注释
CoursePublishPre coursePublishPreObj = coursePublishPreMapper.selectById(courseId); // 把 coursePublishPreMapper.selectById(courseId) 赋值给 coursePublishPreObj
if (coursePublishPreObj == null) { // 定义方法 方法(...)
//插入 // 保留原作者写的行内注释
coursePublishPreMapper.insert(coursePublishPre); // 执行语句
} else { // 代码逻辑
//更新 // 保留原作者写的行内注释
coursePublishPreMapper.updateById(coursePublishPre); // 执行语句
} // 代码块结束
//更新课程基本信息表的审核状态为已提交 // 保留原作者写的行内注释
CourseBase courseBase = courseBaseMapper.selectById(courseId); // 把 courseBaseMapper.selectById(courseId) 赋值给 courseBase
courseBase.setAuditStatus("202003");//审核状态为已提交 // 执行语句
courseBaseMapper.updateById(courseBase); // 执行语句
} // 代码块结束
@Transactional // 使用注解 @Transactional
@Override // 使用注解 @Override
public void publish(Long companyId, Long courseId) { // 定义方法 publish(...)
//查询预发布表 // 保留原作者写的行内注释
CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId); // 把 coursePublishPreMapper.selectById(courseId) 赋值给 coursePublishPre
if (coursePublishPre == null) { // 定义方法 方法(...)
XueChengPlusException.cast("课程没有审核记录,无法发布"); // 执行语句
} // 代码块结束
//状态 // 保留原作者写的行内注释
String status = coursePublishPre.getStatus(); // 把 coursePublishPre.getStatus() 的返回值赋给 status
//课程如果没有审核通过不允许发布 // 保留原作者写的行内注释
if (!status.equals("202004")) { // 定义方法 方法(...)
XueChengPlusException.cast("课程没有审核通过不允许发布"); // 执行语句
} // 代码块结束
//向课程发布表写入数据 // 保留原作者写的行内注释
CoursePublish coursePublish = new CoursePublish(); // 创建 CoursePublish 对象并赋值给 coursePublish
BeanUtils.copyProperties(coursePublishPre, coursePublish); // 执行语句
//先查询课程发布,如果有则更新,没有再添加 // 保留原作者写的行内注释
CoursePublish coursePublishObj = coursePublishMapper.selectById(courseId); // 把 coursePublishMapper.selectById(courseId) 赋值给 coursePublishObj
if (coursePublishObj == null) { // 定义方法 方法(...)
coursePublishMapper.insert(coursePublish); // 执行语句
} else { // 代码逻辑
coursePublishMapper.updateById(coursePublish); // 执行语句
} // 代码块结束
//向消息表写入数据 // 保留原作者写的行内注释
// mqMessageService.addMessage("course_publish",String.valueOf(courseId),null,null); // 保留原作者写的行内注释
saveCoursePublishMessage(courseId); // 执行语句
//将预发布表数据删除 // 保留原作者写的行内注释
coursePublishPreMapper.deleteById(courseId); // 执行语句
} // 代码块结束
@Override // 使用注解 @Override
public File generateCourseHtml(Long courseId) { // 定义方法 generateCourseHtml(...)
Configuration configuration = new Configuration(Configuration.getVersion()); // 创建 Configuration 对象并赋值给 configuration
//最终的静态文件 // 保留原作者写的行内注释
File htmlFile = null; // 把变量 htmlFile 初始化为 null
try { // 尝试执行可能抛出异常的代码
//拿到classpath路径 // 保留原作者写的行内注释
// String classpath = this.getClass().getResource("/").getPath(); // 保留原作者写的行内注释
// //指定模板的目录 // 保留原作者写的行内注释
// configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/")); // 保留原作者写的行内注释
//更改为如下方式 // 保留原作者写的行内注释
configuration.setTemplateLoader(new ClassTemplateLoader(this.getClass().getClassLoader(), "/templates")); // 执行语句
//指定编码 // 保留原作者写的行内注释
configuration.setDefaultEncoding("utf-8"); // 执行语句
//得到模板 // 保留原作者写的行内注释
Template template = configuration.getTemplate("course_template.ftl"); // 把 configuration.getTemplate("course_template.ftl") 赋值给 template
//准备数据 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewInfo = this.getCoursePreviewInfo(courseId); // 把 this.getCoursePreviewInfo(courseId) 赋值给 coursePreviewInfo
HashMap<String, Object> map = new HashMap<>(); // 创建 HashMap<> 对象并赋值给 map
map.put("model", coursePreviewInfo); // 执行语句
//Template template 模板, Object model 数据 // 保留原作者写的行内注释
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, map); // 把 FreeMarkerTemplateUtils.processTemplateIntoString(template, map) 赋值给 html
//输入流 // 保留原作者写的行内注释
InputStream inputStream = IOUtils.toInputStream(html, "utf-8"); // 把 IOUtils.toInputStream(html, "utf-8") 赋值给 inputStream
htmlFile = File.createTempFile("coursepublish", ".html"); // 把 File.createTempFile("coursepublish", ".html") 赋值给 htmlFile
//输出文件 // 保留原作者写的行内注释
FileOutputStream outputStream = new FileOutputStream(htmlFile); // 创建 FileOutputStream 对象并赋值给 outputStream
//使用流将html写入文件 // 保留原作者写的行内注释
IOUtils.copy(inputStream, outputStream); // 执行语句
} catch (Exception ex) { // 定义方法 catch(...)
log.error("页面静态化出现问题,课程id:{}", courseId, ex); // 执行语句
ex.printStackTrace(); // 执行语句
} // 代码块结束
return htmlFile; // 返回 htmlFile
} // 代码块结束
@Override // 使用注解 @Override
public void uploadCourseHtml(Long courseId, File file) { // 定义方法 uploadCourseHtml(...)
try { // 尝试执行可能抛出异常的代码
//将file转成MultipartFile // 保留原作者写的行内注释
MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file); // 把 MultipartSupportConfig.getMultipartFile(file) 赋值给 multipartFile
//远程调用得到返回值 // 保留原作者写的行内注释
String upload = mediaServiceClient.upload(multipartFile, "course/" + courseId + ".html"); // 把 mediaServiceClient.upload(multipartFile, "course/" + courseId + ".html") 赋值给 upload
if (upload == null) { // 定义方法 方法(...)
log.debug("远程调用走降级逻辑得到上传的结果为null,课程id:{}", courseId); // 执行语句
XueChengPlusException.cast("上传静态文件过程中存在异常"); // 执行语句
} // 代码块结束
} catch (Exception ex) { // 定义方法 catch(...)
ex.printStackTrace(); // 执行语句
XueChengPlusException.cast("上传静态文件过程中存在异常"); // 执行语句
} // 代码块结束
} // 代码块结束
/** // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return void // 保留原作者写的块注释
* @description 保存消息表记录 // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/20 16:32 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private void saveCoursePublishMessage(Long courseId) { // 定义方法 saveCoursePublishMessage(...)
MqMessage mqMessage = mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null); // 把 mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null) 赋值给 mqMessage
if (mqMessage == null) { // 定义方法 方法(...)
XueChengPlusException.cast(CommonError.UNKOWN_ERROR); // 执行语句
} // 代码块结束
} // 代码块结束
/** // 保留原作者写的块注释
* 根据课程 id查询课程发布信息 // 保留原作者写的块注释
* // 保留原作者写的块注释
* @param courseId // 保留原作者写的块注释
* @return // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CoursePublish getCoursePublish(Long courseId) { // 定义方法 getCoursePublish(...)
CoursePublish coursePublish = coursePublishMapper.selectById(courseId); // 把 coursePublishMapper.selectById(courseId) 赋值给 coursePublish
return coursePublish; // 返回 coursePublish
} // 代码块结束
//解决缓存穿透 // 保留原作者写的行内注释
// @Override // 保留原作者写的行内注释
// public CoursePublish getCoursePublishCache(Long courseId) { // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// //从缓存中查询 // 保留原作者写的行内注释
// Object jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 保留原作者写的行内注释
// //缓存中有 // 保留原作者写的行内注释
// if(jsonObj!=null){ // 保留原作者写的行内注释
//// System.out.println("=============从缓存中查询============="); // 保留原作者写的行内注释
// //缓存中有直接返回数据 // 保留原作者写的行内注释
// String jsonString = jsonObj.toString(); // 保留原作者写的行内注释
// if("null".equals(jsonString)){ // 保留原作者写的行内注释
// return null; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// }else{ // 保留原作者写的行内注释
// System.out.println("==查询数据库=="); // 保留原作者写的行内注释
// //从数据库查询 // 保留原作者写的行内注释
// CoursePublish coursePublish = getCoursePublish(courseId); // 保留原作者写的行内注释
//// if(coursePublish!=null){ // 保留原作者写的行内注释
// //查询完成再存储到redis // 保留原作者写的行内注释
// redisTemplate.opsForValue().set("course:"+courseId,JSON.toJSONString(coursePublish),30, TimeUnit.SECONDS); // 保留原作者写的行内注释
//// } // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
//使用同步锁解决缓存击穿 // 保留原作者写的行内注释
// @Override // 保留原作者写的行内注释
// public CoursePublish getCoursePublishCache(Long courseId) { // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// //从缓存中查询 // 保留原作者写的行内注释
// Object jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 保留原作者写的行内注释
// //缓存中有 // 保留原作者写的行内注释
// if(jsonObj!=null){ // 保留原作者写的行内注释
//// System.out.println("=============从缓存中查询============="); // 保留原作者写的行内注释
// //缓存中有直接返回数据 // 保留原作者写的行内注释
// String jsonString = jsonObj.toString(); // 保留原作者写的行内注释
// if("null".equals(jsonString)){ // 保留原作者写的行内注释
// return null; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// }else{ // 保留原作者写的行内注释
// synchronized (this){ // 保留原作者写的行内注释
// //再次查询一下缓存 // 保留原作者写的行内注释
// //从缓存中查询 // 保留原作者写的行内注释
// jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 保留原作者写的行内注释
// //缓存中有 // 保留原作者写的行内注释
// if(jsonObj!=null) { // 保留原作者写的行内注释
// //缓存中有直接返回数据 // 保留原作者写的行内注释
// String jsonString = jsonObj.toString(); // 保留原作者写的行内注释
// if("null".equals(jsonString)){ // 保留原作者写的行内注释
// return null; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// System.out.println("==查询数据库=="); // 保留原作者写的行内注释
// //从数据库查询 // 保留原作者写的行内注释
// CoursePublish coursePublish = getCoursePublish(courseId); // 保留原作者写的行内注释
// //查询完成再存储到redis // 保留原作者写的行内注释
// redisTemplate.opsForValue().set("course:"+courseId,JSON.toJSONString(coursePublish),300, TimeUnit.SECONDS); // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
//使用redisson实现分布式锁 // 保留原作者写的行内注释
@Override // 使用注解 @Override
public CoursePublish getCoursePublishCache(Long courseId) { // 定义方法 getCoursePublishCache(...)
//从缓存中查询 // 保留原作者写的行内注释
Object jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 把 redisTemplate.opsForValue().get("course:" + courseId) 赋值给 jsonObj
//缓存中有 // 保留原作者写的行内注释
if (jsonObj != null) { // 定义方法 方法(...)
// System.out.println("=============从缓存中查询============="); // 保留原作者写的行内注释
//缓存中有直接返回数据 // 保留原作者写的行内注释
String jsonString = jsonObj.toString(); // 把 jsonObj.toString() 的返回值赋给 jsonString
if ("null".equals(jsonString)) { // 定义方法 方法(...)
return null; // 返回 null
} // 代码块结束
CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 把 JSON.parseObject(jsonString, CoursePublish.class) 赋值给 coursePublish
return coursePublish; // 返回 coursePublish
} else { // 代码逻辑
RLock lock = redissonClient.getLock("coursequerylock:" + courseId); // 把 redissonClient.getLock("coursequerylock:" + courseId) 赋值给 lock
//获取分布式锁 // 保留原作者写的行内注释
lock.lock(); // 执行语句
try { // 尝试执行可能抛出异常的代码
//再次查询一下缓存 // 保留原作者写的行内注释
//从缓存中查询 // 保留原作者写的行内注释
jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 把 redisTemplate.opsForValue().get("course:" + courseId) 赋值给 jsonObj
//缓存中有 // 保留原作者写的行内注释
if (jsonObj != null) { // 定义方法 方法(...)
//缓存中有直接返回数据 // 保留原作者写的行内注释
String jsonString = jsonObj.toString(); // 把 jsonObj.toString() 的返回值赋给 jsonString
if ("null".equals(jsonString)) { // 定义方法 方法(...)
return null; // 返回 null
} // 代码块结束
CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 把 JSON.parseObject(jsonString, CoursePublish.class) 赋值给 coursePublish
return coursePublish; // 返回 coursePublish
} // 代码块结束
System.out.println("==查询数据库=="); // 执行语句
// try { // 保留原作者写的行内注释
// //手动延迟,测试锁的续期功能 // 保留原作者写的行内注释
// Thread.sleep(60000); // 保留原作者写的行内注释
// } catch (InterruptedException e) { // 保留原作者写的行内注释
// throw new RuntimeException(e); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
//从数据库查询 // 保留原作者写的行内注释
CoursePublish coursePublish = getCoursePublish(courseId); // 把 getCoursePublish(courseId) 赋值给 coursePublish
//查询完成再存储到redis // 保留原作者写的行内注释
redisTemplate.opsForValue().set("course:" + courseId, JSON.toJSONString(coursePublish), 300, TimeUnit.SECONDS); // 执行语句
return coursePublish; // 返回 coursePublish
} finally { // 代码逻辑
//手动释放锁 // 保留原作者写的行内注释
lock.unlock(); // 执行语句
} // 代码块结束
} // 代码块结束
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/service/impl/TeachplanServiceImpl.java
package com.xuecheng.content.service.impl; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.content.mapper.TeachplanMapper; // 导入 TeachplanMapper 类
import com.xuecheng.content.mapper.TeachplanMediaMapper; // 导入 TeachplanMediaMapper 类
import com.xuecheng.content.model.dto.BindTeachplanMediaDto; // 导入 BindTeachplanMediaDto 类
import com.xuecheng.content.model.dto.SaveTeachplanDto; // 导入 SaveTeachplanDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.model.po.Teachplan; // 导入 Teachplan 类
import com.xuecheng.content.model.po.TeachplanMedia; // 导入 TeachplanMedia 类
import com.xuecheng.content.service.TeachplanService; // 导入 TeachplanService 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类
import org.springframework.transaction.annotation.Transactional; // 导入 Transactional 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/14 12:11 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Service // 使用注解 @Service
public class TeachplanServiceImpl implements TeachplanService { // 定义 class TeachplanServiceImpl
@Autowired // 使用注解 @Autowired
TeachplanMapper teachplanMapper; // 执行语句
@Autowired // 使用注解 @Autowired
TeachplanMediaMapper teachplanMediaMapper; // 执行语句
@Override // 使用注解 @Override
public List<TeachplanDto> findTeachplanTree(Long courseId) { // 定义方法 findTeachplanTree(...)
List<TeachplanDto> teachplanDtos = teachplanMapper.selectTreeNodes(courseId); // 把 teachplanMapper.selectTreeNodes(courseId) 赋值给 teachplanDtos
return teachplanDtos; // 返回 teachplanDtos
} // 代码块结束
private int getTeachplanCount(Long courseId,Long parentId){ // 定义方法 getTeachplanCount(...)
LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>(); // 创建 LambdaQueryWrapper<> 对象并赋值给 queryWrapper
queryWrapper = queryWrapper.eq(Teachplan::getCourseId, courseId).eq(Teachplan::getParentid, parentId); // 把 queryWrapper.eq(Teachplan::getCourseId, courseId).eq(Teachplan::getParentid, parentId) 赋值给 queryWrapper
Integer count = teachplanMapper.selectCount(queryWrapper); // 把 teachplanMapper.selectCount(queryWrapper) 赋值给 count
return count+1; // 返回 count+1
} // 代码块结束
@Override // 使用注解 @Override
public void saveTeachplan(SaveTeachplanDto saveTeachplanDto) { // 定义方法 saveTeachplan(...)
//通过课程计划id判断是新增和修改 // 保留原作者写的行内注释
Long teachplanId = saveTeachplanDto.getId(); // 把 saveTeachplanDto.getId() 的返回值赋给 teachplanId
if(teachplanId ==null){ // 定义方法 方法(...)
//新增 // 保留原作者写的行内注释
Teachplan teachplan = new Teachplan(); // 创建 Teachplan 对象并赋值给 teachplan
BeanUtils.copyProperties(saveTeachplanDto,teachplan); // 执行语句
//确定排序字段,找到它的同级节点个数,排序字段就是个数加1 select count(1) from teachplan where course_id=117 and parentid=268 // 保留原作者写的行内注释
Long parentid = saveTeachplanDto.getParentid(); // 把 saveTeachplanDto.getParentid() 的返回值赋给 parentid
Long courseId = saveTeachplanDto.getCourseId(); // 把 saveTeachplanDto.getCourseId() 的返回值赋给 courseId
int teachplanCount = getTeachplanCount(courseId, parentid); // 把 getTeachplanCount(courseId, parentid) 赋值给 teachplanCount
teachplan.setOrderby(teachplanCount); // 执行语句
teachplanMapper.insert(teachplan); // 执行语句
}else{ // 代码逻辑
//修改 // 保留原作者写的行内注释
Teachplan teachplan = teachplanMapper.selectById(teachplanId); // 把 teachplanMapper.selectById(teachplanId) 赋值给 teachplan
//将参数复制到teachplan // 保留原作者写的行内注释
BeanUtils.copyProperties(saveTeachplanDto,teachplan); // 执行语句
teachplanMapper.updateById(teachplan); // 执行语句
} // 代码块结束
} // 代码块结束
@Transactional // 使用注解 @Transactional
@Override // 使用注解 @Override
public void associationMedia(BindTeachplanMediaDto bindTeachplanMediaDto) { // 定义方法 associationMedia(...)
//课程计划id // 保留原作者写的行内注释
Long teachplanId = bindTeachplanMediaDto.getTeachplanId(); // 把 bindTeachplanMediaDto.getTeachplanId() 的返回值赋给 teachplanId
Teachplan teachplan = teachplanMapper.selectById(teachplanId); // 把 teachplanMapper.selectById(teachplanId) 赋值给 teachplan
if(teachplan == null){ // 定义方法 方法(...)
XueChengPlusException.cast("课程计划不存在"); // 执行语句
} // 代码块结束
//先删除原有记录,根据课程计划id删除它所绑定的媒资 // 保留原作者写的行内注释
int delete = teachplanMediaMapper.delete(new LambdaQueryWrapper<TeachplanMedia>().eq(TeachplanMedia::getTeachplanId, bindTeachplanMediaDto.getTeachplanId())); // 把 teachplanMediaMapper.delete(new LambdaQueryWrapper<TeachplanMedia>().eq(TeachplanMedia::getTeachplanId, bindTeachplanMediaDto.getTeachplanId())) 赋值给 delete
//再添加新记录 // 保留原作者写的行内注释
TeachplanMedia teachplanMedia = new TeachplanMedia(); // 创建 TeachplanMedia 对象并赋值给 teachplanMedia
BeanUtils.copyProperties(bindTeachplanMediaDto,teachplanMedia); // 执行语句
teachplanMedia.setCourseId(teachplan.getCourseId()); // 执行语句
teachplanMedia.setMediaFilename(bindTeachplanMediaDto.getFileName()); // 执行语句
teachplanMediaMapper.insert(teachplanMedia); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/service/jobhandler/CoursePublishTask.java
package com.xuecheng.content.service.jobhandler; // 声明类所在的包路径
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.content.feignclient.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.content.feignclient.SearchServiceClient; // 导入 SearchServiceClient 类
import com.xuecheng.content.mapper.CoursePublishMapper; // 导入 CoursePublishMapper 类
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import com.xuecheng.messagesdk.model.po.MqMessage; // 导入 MqMessage 类
import com.xuecheng.messagesdk.service.MessageProcessAbstract; // 导入 MessageProcessAbstract 类
import com.xuecheng.messagesdk.service.MqMessageService; // 导入 MqMessageService 类
import com.xxl.job.core.context.XxlJobHelper; // 导入 XxlJobHelper 类
import com.xxl.job.core.handler.annotation.XxlJob; // 导入 XxlJob 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Component; // 导入 Component 类
import java.io.File; // 导入 File 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程发布的任务类 // 保留原作者写的块注释
* @date 2023/2/21 16:15 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class CoursePublishTask extends MessageProcessAbstract { // 定义 class CoursePublishTask
@Autowired // 使用注解 @Autowired
CoursePublishService coursePublishService; // 执行语句
@Autowired // 使用注解 @Autowired
SearchServiceClient searchServiceClient; // 执行语句
@Autowired // 使用注解 @Autowired
CoursePublishMapper coursePublishMapper; // 执行语句
//任务调度入口 // 保留原作者写的行内注释
@XxlJob("CoursePublishJobHandler") // 使用注解 @XxlJob("CoursePublishJobHandler")
public void coursePublishJobHandler() throws Exception { // 定义方法 coursePublishJobHandler(...)
// 分片参数 // 保留原作者写的行内注释
int shardIndex = XxlJobHelper.getShardIndex();//执行器的序号,从0开始 // 把 XxlJobHelper.getShardIndex() 的返回值赋给 shardIndex
int shardTotal = XxlJobHelper.getShardTotal();//执行器总数 // 把 XxlJobHelper.getShardTotal() 的返回值赋给 shardTotal
//调用抽象类的方法执行任务 // 保留原作者写的行内注释
process(shardIndex,shardTotal, "course_publish",30,60); // 执行语句
} // 代码块结束
//课程发布任务处理 // 保留原作者写的行内注释
//执行课程发布任务的逻辑,如果此方法抛出异常说明任务执行失败 // 保留原作者写的行内注释
@Override // 使用注解 @Override
public boolean execute(MqMessage mqMessage) { // 定义方法 execute(...)
//从mqMessage拿到课程id // 保留原作者写的行内注释
Long courseId = Long.parseLong(mqMessage.getBusinessKey1()); // 把 Long.parseLong(mqMessage.getBusinessKey1()) 赋值给 courseId
//课程静态化上传到minio // 保留原作者写的行内注释
generateCourseHtml(mqMessage,courseId); // 执行语句
//向elasticsearch写索引数据 // 保留原作者写的行内注释
saveCourseIndex(mqMessage,courseId); // 执行语句
//向redis写缓存 // 保留原作者写的行内注释
//返回true表示任务完成 // 保留原作者写的行内注释
return true; // 返回 true
} // 代码块结束
//生成课程静态化页面并上传至文件系统 // 保留原作者写的行内注释
private void generateCourseHtml(MqMessage mqMessage,long courseId){ // 定义方法 generateCourseHtml(...)
//消息id // 保留原作者写的行内注释
Long taskId = mqMessage.getId(); // 把 mqMessage.getId() 的返回值赋给 taskId
MqMessageService mqMessageService = this.getMqMessageService(); // 把 this.getMqMessageService() 的返回值赋给 mqMessageService
//做任务幂等性处理 // 保留原作者写的行内注释
//查询数据库取出该阶段执行状态 // 保留原作者写的行内注释
int stageOne = mqMessageService.getStageOne(taskId); // 把 mqMessageService.getStageOne(taskId) 赋值给 stageOne
if(stageOne>0){ // 定义方法 方法(...)
log.debug("课程静态化任务完成,无需处理..."); // 执行语句
return ; // 返回
} // 代码块结束
//开始进行课程静态化 生成html页面 // 保留原作者写的行内注释
File file = coursePublishService.generateCourseHtml(courseId); // 把 coursePublishService.generateCourseHtml(courseId) 赋值给 file
if(file == null){ // 定义方法 方法(...)
XueChengPlusException.cast("生成的静态页面为空"); // 执行语句
} // 代码块结束
// 将html上传到minio // 保留原作者写的行内注释
coursePublishService.uploadCourseHtml(courseId,file); // 执行语句
//..任务处理完成写任务状态为完成 // 保留原作者写的行内注释
mqMessageService.completedStageOne(taskId); // 执行语句
} // 代码块结束
//保存课程索引信息 第二个阶段任务 // 保留原作者写的行内注释
private void saveCourseIndex(MqMessage mqMessage,long courseId){ // 定义方法 saveCourseIndex(...)
//任务id // 保留原作者写的行内注释
Long taskId = mqMessage.getId(); // 把 mqMessage.getId() 的返回值赋给 taskId
MqMessageService mqMessageService = this.getMqMessageService(); // 把 this.getMqMessageService() 的返回值赋给 mqMessageService
//取出第二个阶段状态 // 保留原作者写的行内注释
int stageTwo = mqMessageService.getStageTwo(taskId); // 把 mqMessageService.getStageTwo(taskId) 赋值给 stageTwo
//任务幂等性处理 // 保留原作者写的行内注释
if(stageTwo>0){ // 定义方法 方法(...)
log.debug("课程索引信息已写入,无需执行..."); // 执行语句
return; // 直接返回不带结果
} // 代码块结束
//查询课程信息,调用搜索服务添加索引接口 // 保留原作者写的行内注释
//从课程发布表查询课程信息 // 保留原作者写的行内注释
CoursePublish coursePublish = coursePublishMapper.selectById(courseId); // 把 coursePublishMapper.selectById(courseId) 赋值给 coursePublish
CourseIndex courseIndex = new CourseIndex(); // 创建 CourseIndex 对象并赋值给 courseIndex
BeanUtils.copyProperties(coursePublish,courseIndex); // 执行语句
//远程调用 // 保留原作者写的行内注释
Boolean add = searchServiceClient.add(courseIndex); // 把 searchServiceClient.add(courseIndex) 赋值给 add
if(!add){ // 定义方法 方法(...)
XueChengPlusException.cast("远程调用搜索服务添加课程索引失败"); // 执行语句
} // 代码块结束
//完成本阶段的任务 // 保留原作者写的行内注释
mqMessageService.completedStageTwo(taskId); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/service/com/xuecheng/content/service/TeachplanService.java
package com.xuecheng.content.service; // 声明类所在的包路径
import com.xuecheng.content.model.dto.BindTeachplanMediaDto; // 导入 BindTeachplanMediaDto 类
import com.xuecheng.content.model.dto.SaveTeachplanDto; // 导入 SaveTeachplanDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程计划管理相关接口 // 保留原作者写的块注释
* @date 2023/2/14 12:10 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface TeachplanService { // 定义 interface TeachplanService
/** // 保留原作者写的块注释
* 根据课程id查询课程计划 // 保留原作者写的块注释
* @param courseId 课程计划 // 保留原作者写的块注释
* @return // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public List<TeachplanDto> findTeachplanTree(Long courseId); // 执行语句
/** // 保留原作者写的块注释
* 新增/修改/保存课程计划 // 保留原作者写的块注释
* @param saveTeachplanDto // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void saveTeachplan(SaveTeachplanDto saveTeachplanDto); // 执行语句
/** // 保留原作者写的块注释
* @description 教学计划绑定媒资 // 保留原作者写的块注释
* @param bindTeachplanMediaDto // 保留原作者写的块注释
* @return com.xuecheng.content.model.po.TeachplanMedia // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/14 22:20 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void associationMedia(BindTeachplanMediaDto bindTeachplanMediaDto); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/service_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.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <!-- 读取配置中心配置 -->
</dependency>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xuecheng-plus-content-model</artifactId> <!-- 复用 DTO/PO -->
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xuecheng-plus-message-sdk</artifactId> <!-- 发送消息到 MQ -->
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId> <!-- 定时任务框架 -->
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope> <!-- 运行时才需要数据库驱动 -->
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId> <!-- MyBatis-Plus 自动配置 -->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId> <!-- Spring Cloud 上下文支持 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <!-- 单元测试依赖 -->
</dependency>
<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-data-redis</artifactId> <!-- Redis 客户端 -->
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.2</version> <!-- Redis 连接池 -->
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.11.2</version> <!-- 分布式锁 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId> <!-- 使用 log4j2 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId> <!-- 页面静态化 -->
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <!-- 注册中心 -->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId> <!-- 远程调用 -->
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId> <!-- 使用 Apache HttpClient 实现 -->
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.8.0</version> <!-- Feign 表单支持 -->
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.8.0</version> <!-- Spring 集成的表单支持 -->
</dependency>
</dependencies>
</project>
文件:xuecheng-plus-content/test_service/com/xuecheng/content/CourseBaseInfoServiceTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 Page 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.junit.jupiter.api.Assertions; // 导入 Assertions 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class CourseBaseInfoServiceTests { // 定义 class CourseBaseInfoServiceTests
@Autowired // 使用注解 @Autowired
CourseBaseInfoService courseBaseInfoService; // 执行语句
@Test // 使用注解 @Test
public void testCourseBaseInfoService() { // 定义方法 testCourseBaseInfoService(...)
//查询条件 // 保留原作者写的行内注释
QueryCourseParamsDto courseParamsDto = new QueryCourseParamsDto(); // 创建 QueryCourseParamsDto 对象并赋值给 courseParamsDto
courseParamsDto.setCourseName("java");//课程名称查询条件 // 执行语句
courseParamsDto.setAuditStatus("202004");//202004表示课程审核通过 // 执行语句
//分页参数对象 // 保留原作者写的行内注释
PageParams pageParams = new PageParams(); // 创建 PageParams 对象并赋值给 pageParams
pageParams.setPageNo(2L); // 执行语句
pageParams.setPageSize(2L); // 执行语句
PageResult<CourseBase> courseBasePageResult = courseBaseInfoService.queryCourseBaseList(null,pageParams, courseParamsDto); // 把 courseBaseInfoService.queryCourseBaseList(null,pageParams, courseParamsDto) 赋值给 courseBasePageResult
System.out.println(courseBasePageResult); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/test_service/com/xuecheng/content/CourseBaseMapperTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 Page 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.junit.jupiter.api.Assertions; // 导入 Assertions 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class CourseBaseMapperTests { // 定义 class CourseBaseMapperTests
@Autowired // 使用注解 @Autowired
CourseBaseMapper courseBaseMapper; // 执行语句
@Test // 使用注解 @Test
public void testCourseBaseMapper() { // 定义方法 testCourseBaseMapper(...)
CourseBase courseBase = courseBaseMapper.selectById(18); // 把 courseBaseMapper.selectById(18) 赋值给 courseBase
Assertions.assertNotNull(courseBase); // 执行语句
//详细进行分页查询的单元测试 // 保留原作者写的行内注释
//查询条件 // 保留原作者写的行内注释
QueryCourseParamsDto courseParamsDto = new QueryCourseParamsDto(); // 创建 QueryCourseParamsDto 对象并赋值给 courseParamsDto
courseParamsDto.setCourseName("java");//课程名称查询条件 // 执行语句
//拼装查询条件 // 保留原作者写的行内注释
LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>(); // 创建 LambdaQueryWrapper<> 对象并赋值给 queryWrapper
//根据名称模糊查询,在sql中拼接 course_base.name like '%值%' // 保留原作者写的行内注释
queryWrapper.like(StringUtils.isNotEmpty(courseParamsDto.getCourseName()),CourseBase::getName,courseParamsDto.getCourseName()); // 执行语句
//根据课程审核状态查询 course_base.audit_status = ? // 保留原作者写的行内注释
queryWrapper.eq(StringUtils.isNotEmpty(courseParamsDto.getAuditStatus()), CourseBase::getAuditStatus,courseParamsDto.getAuditStatus()); // 执行语句
//todo:按课程发布状态查询 // 保留原作者写的行内注释
//分页参数对象 // 保留原作者写的行内注释
PageParams pageParams = new PageParams(); // 创建 PageParams 对象并赋值给 pageParams
pageParams.setPageNo(1L); // 执行语句
pageParams.setPageSize(2L); // 执行语句
//创建page分页参数对象,参数:当前页码,每页记录数 // 保留原作者写的行内注释
Page<CourseBase> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize()); // 创建 Page<> 对象并赋值给 page
//开始进行分页查询 // 保留原作者写的行内注释
Page<CourseBase> pageResult = courseBaseMapper.selectPage(page, queryWrapper); // 把 courseBaseMapper.selectPage(page, queryWrapper) 赋值给 pageResult
//数据列表 // 保留原作者写的行内注释
List<CourseBase> items = pageResult.getRecords(); // 把 pageResult.getRecords() 的返回值赋给 items
//总记录数 // 保留原作者写的行内注释
long total = pageResult.getTotal(); // 把 pageResult.getTotal() 的返回值赋给 total
//List<T> items, long counts, long page, long pageSize // 保留原作者写的行内注释
PageResult<CourseBase> courseBasePageResult = new PageResult<CourseBase>(items,total,pageParams.getPageNo(), pageParams.getPageSize()); // 创建 PageResult<CourseBase> 对象并赋值给 courseBasePageResult
System.out.println(courseBasePageResult); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/test_service/com/xuecheng/content/CourseCategoryMapperTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 Page 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.mapper.CourseCategoryMapper; // 导入 CourseCategoryMapper 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.junit.jupiter.api.Assertions; // 导入 Assertions 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class CourseCategoryMapperTests { // 定义 class CourseCategoryMapperTests
@Autowired // 使用注解 @Autowired
CourseCategoryMapper courseCategoryMapper; // 执行语句
@Test // 使用注解 @Test
public void testCourseCategoryMapper() { // 定义方法 testCourseCategoryMapper(...)
List<CourseCategoryTreeDto> courseCategoryTreeDtos = courseCategoryMapper.selectTreeNodes("1"); // 把 courseCategoryMapper.selectTreeNodes("1") 赋值给 courseCategoryTreeDtos
System.out.println(courseCategoryTreeDtos); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/test_service/com/xuecheng/content/CourseCategoryServiceTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import com.xuecheng.content.service.CourseCategoryService; // 导入 CourseCategoryService 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class CourseCategoryServiceTests { // 定义 class CourseCategoryServiceTests
@Autowired // 使用注解 @Autowired
CourseCategoryService courseCategoryService; // 执行语句
@Test // 使用注解 @Test
public void testCourseCategoryService() { // 定义方法 testCourseCategoryService(...)
List<CourseCategoryTreeDto> courseCategoryTreeDtos = courseCategoryService.queryTreeNodes("1"); // 把 courseCategoryService.queryTreeNodes("1") 赋值给 courseCategoryTreeDtos
System.out.println(courseCategoryTreeDtos); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/test_service/com/xuecheng/content/FeignUploadTest.java
package com.xuecheng.content; // 声明类所在的包路径
import com.xuecheng.content.config.MultipartSupportConfig; // 导入 MultipartSupportConfig 类
import com.xuecheng.content.feignclient.MediaServiceClient; // 导入 MediaServiceClient 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.File; // 导入 File 类
import java.io.IOException; // 导入 IOException 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 测试远程调用媒资服务 // 保留原作者写的块注释
* @date 2023/2/22 10:30 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class FeignUploadTest { // 定义 class FeignUploadTest
@Autowired // 使用注解 @Autowired
MediaServiceClient mediaServiceClient; // 执行语句
@Test // 使用注解 @Test
public void test() throws IOException { // 定义方法 test(...)
//将file转成MultipartFile // 保留原作者写的行内注释
File file = new File("D:\\develop\\upload\\120.html"); // 创建 File 对象并赋值给 file
MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file); // 把 MultipartSupportConfig.getMultipartFile(file) 赋值给 multipartFile
//远程调用得到返回值 // 保留原作者写的行内注释
String upload = mediaServiceClient.upload(multipartFile, "course/120.html"); // 把 mediaServiceClient.upload(multipartFile, "course/120.html") 赋值给 upload
if(upload==null){ // 定义方法 方法(...)
System.out.println("走了降级逻辑"); // 执行语句
} // 代码块结束
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/test_service/com/xuecheng/content/FreemarkerTest.java
package com.xuecheng.content; // 声明类所在的包路径
import com.xuecheng.content.mapper.TeachplanMapper; // 导入 TeachplanMapper 类
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import freemarker.template.Configuration; // 导入 Configuration 类
import freemarker.template.Template; // 导入 Template 类
import freemarker.template.TemplateException; // 导入 TemplateException 类
import org.apache.commons.io.IOUtils; // 导入 IOUtils 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; // 导入 FreeMarkerTemplateUtils 类
import java.io.File; // 导入 File 类
import java.io.FileOutputStream; // 导入 FileOutputStream 类
import java.io.IOException; // 导入 IOException 类
import java.io.InputStream; // 导入 InputStream 类
import java.util.HashMap; // 导入 HashMap 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 测试freemarker页面静态化方法 // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class FreemarkerTest { // 定义 class FreemarkerTest
@Autowired // 使用注解 @Autowired
CoursePublishService coursePublishService; // 执行语句
@Test // 使用注解 @Test
public void testGenerateHtmlByTemplate() throws IOException, TemplateException { // 定义方法 testGenerateHtmlByTemplate(...)
Configuration configuration = new Configuration(Configuration.getVersion()); // 创建 Configuration 对象并赋值给 configuration
//拿到classpath路径 // 保留原作者写的行内注释
String classpath = this.getClass().getResource("/").getPath(); // 把 this.getClass().getResource("/").getPath() 的返回值赋给 classpath
//指定模板的目录 // 保留原作者写的行内注释
configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/")); // 执行语句
//指定编码 // 保留原作者写的行内注释
configuration.setDefaultEncoding("utf-8"); // 执行语句
//得到模板 // 保留原作者写的行内注释
Template template = configuration.getTemplate("course_template.ftl"); // 把 configuration.getTemplate("course_template.ftl") 赋值给 template
//准备数据 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(120L); // 把 coursePublishService.getCoursePreviewInfo(120L) 赋值给 coursePreviewInfo
HashMap<String, Object> map = new HashMap<>(); // 创建 HashMap<> 对象并赋值给 map
map.put("model",coursePreviewInfo); // 执行语句
//Template template 模板, Object model 数据 // 保留原作者写的行内注释
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, map); // 把 FreeMarkerTemplateUtils.processTemplateIntoString(template, map) 赋值给 html
//输入流 // 保留原作者写的行内注释
InputStream inputStream = IOUtils.toInputStream(html, "utf-8"); // 把 IOUtils.toInputStream(html, "utf-8") 赋值给 inputStream
//输出文件 // 保留原作者写的行内注释
FileOutputStream outputStream = new FileOutputStream(new File("D:\\develop\\upload\\120.html")); // 创建 FileOutputStream 对象并赋值给 outputStream
//使用流将html写入文件 // 保留原作者写的行内注释
IOUtils.copy(inputStream,outputStream); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/test_service/com/xuecheng/content/TeachplanMapperTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.xuecheng.content.mapper.CourseCategoryMapper; // 导入 CourseCategoryMapper 类
import com.xuecheng.content.mapper.TeachplanMapper; // 导入 TeachplanMapper 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程计划mapper测试 // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class TeachplanMapperTests { // 定义 class TeachplanMapperTests
@Autowired // 使用注解 @Autowired
TeachplanMapper teachplanMapper; // 执行语句
@Test // 使用注解 @Test
public void testSelectTreeNodes() { // 定义方法 testSelectTreeNodes(...)
List<TeachplanDto> teachplanDtos = teachplanMapper.selectTreeNodes(117L); // 把 teachplanMapper.selectTreeNodes(117L) 赋值给 teachplanDtos
System.out.println(teachplanDtos); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/test_service/com/xuecheng/ContentApplication.java
package com.xuecheng; // 声明类所在的包路径
import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类
import org.springframework.cloud.openfeign.EnableFeignClients; // 导入 EnableFeignClients 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 内容管理服务启动类 // 保留原作者写的块注释
* @date 2023/2/11 15:49 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@EnableFeignClients(basePackages={"com.xuecheng.content.feignclient"}) // 使用注解 @EnableFeignClients(basePackages={"com.xuecheng.content.feignclient"})
@SpringBootApplication // 使用注解 @SpringBootApplication
public class ContentApplication { // 定义 class ContentApplication
public static void main(String[] args) { // 定义方法 main(...)
SpringApplication.run(ContentApplication.class, args); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/test_service/resources/bootstrap.yml
spring: # Spring Boot 顶层配置
application:
name: content-service # 测试环境注册的服务名
cloud:
nacos:
server-addr: 192.168.101.65:8848 # Nacos 地址
discovery: # 注册中心设置
namespace: dev402 # 使用 dev402 命名空间
group: xuecheng-plus-project # 服务分组
config: # 配置中心设置
namespace: dev402
group: xuecheng-plus-project
file-extension: yaml # 使用 yaml 配置格式
refresh-enabled: true # 支持动态刷新
shared-configs: # 引入公共配置
- data-id: feign-${spring.profiles.active}.yaml # Feign 统一配置
group: xuecheng-plus-common
refresh: true
profiles:
active: dev # 激活 dev 环境
logging:
config: classpath:log4j2-dev.xml # 指定测试环境的 log4j2 配置
文件:xuecheng-plus-content/test_service/resources/log4j2-dev.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- 测试环境 log4j2 配置入口 -->
<Configuration monitorInterval="180" packages=""> <!-- 每 180 秒检测配置变更 -->
<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"/> <!-- 仅记录 ERROR -->
<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>
<Async name="AsyncAppender" includeLocation="true"> <!-- 异步包装 -->
<AppenderRef ref="ErrorAppender"/>
<AppenderRef ref="DebugAppender"/>
</Async>
</Appenders>
<Loggers>
<logger name="cn.itcast.wanxinp2p.consumer.mapper" level="DEBUG"/> <!-- 示例保留 -->
<logger name="springfox" level="INFO"/>
<logger name="org.apache.http" level="INFO"/>
<logger name="com.netflix.discovery" level="INFO"/>
<logger name="RocketmqCommon" level="INFO" />
<logger name="RocketmqRemoting" level="INFO" />
<logger name="RocketmqClient" level="WARN"/>
<logger name="org.dromara.hmily" level="WARN"/>
<logger name="org.dromara.hmily.lottery" level="WARN"/>
<logger name="org.dromara.hmily.bonuspoint" level="WARN"/>
<Root level="DEBUG" includeLocation="true"> <!-- 根记录器 -->
<AppenderRef ref="AsyncAppender"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="DebugAppender"/>
</Root>
</Loggers>
</Configuration>
文件:xuecheng-plus-content/test_service/resources/templates/course_template.ftl
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="/static/img/asset-favicon.ico">
<title>学成在线-${model.courseBase.name}</title>
<link rel="stylesheet" href="/static/plugins/normalize-css/normalize.css" />
<link rel="stylesheet" href="/static/plugins/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="/static/css/page-learing-article.css" />
</head>
<body data-spy="scroll" data-target="#articleNavbar" data-offset="150">
<!-- 页面头部 -->
<!--#include virtual="/include/header.html"-->
<!--页面头部结束sss-->
<div id="learningArea">
<div class="article-banner">
<div class="banner-bg"></div>
<div class="banner-info">
<div class="banner-left">
<p>${model.courseBase.mtName!''}<span>\ ${model.courseBase.stName!''}</span></p>
<p class="tit">${model.courseBase.name}</p>
<p class="pic">
<#if model.courseBase.charge=='201000'>
<span class="new-pic">免费</span>
<#else>
<span class="new-pic">特惠价格¥${model.courseBase.price!''}</span>
<span class="old-pic">原价¥${model.courseBase.originalPrice!''}</span>
</#if>
</p>
<p class="info">
<a href="#" @click.prevent="startLearning()">马上学习</a>
<span><em>难度等级</em>
<#if model.courseBase.grade=='204001'>
初级
<#elseif model.courseBase.grade=='204002'>
中级
<#elseif model.courseBase.grade=='204003'>
高级
</#if>
</span>
<span><em>课程时长</em>2小时27分</span>
<span><em>评分</em>4.7分</span>
<span><em>授课模式</em>
<#if model.courseBase.teachmode=='200002'>
录播
<#elseif model.courseBase.teachmode=='200003'>
直播
</#if>
</span>
</p>
</div>
<div class="banner-rit">
<p>
<a href="http://www.51xuecheng.cn/course/preview/learning.html?id=${model.courseBase.id}" target="_blank">
<#if model.courseBase.pic??>
<img src="http://file.51xuecheng.cn${model.courseBase.pic}" alt="" width="270" height="156">
<#else>
<img src="/static/img/widget-video.png" alt="" width="270" height="156">
</#if>
</a>
</p>
<p class="vid-act"><span> <i class="i-heart"></i>收藏 23 </span> <span>分享 <i class="i-weixin"></i><i class="i-qq"></i></span></p>
</div>
</div>
</div>
<div class="article-cont">
<div class="tit-list">
<a href="javascript:;" id="articleClass" class="active">课程介绍</a>
<a href="javascript:;" id="articleItem">目录</a>
<a href="javascript:;" id="artcleAsk">问答</a>
<a href="javascript:;" id="artcleNot">笔记</a>
<a href="javascript:;" id="artcleCod">评价</a>
<!--<div class="down-fill">
<span>资料下载</span>
<ul>
<li>java视频资料</li>
<li>java视频资料</li>
<li>java视频资料</li>
</ul>
</div>-->
</div>
<div class="article-box">
<div class="articleClass" style="display: block">
<!--<div class="rit-title">评价</div>-->
<div class="article-cont">
<div class="article-left-box">
<div class="content">
<div class="content-com suit">
<div class="title"><span>适用人群</span></div>
<div class="cont cktop">
<div >
<p>${model.courseBase.users!""}</p>
</div>
<!--<span class="on-off">更多 <i class="i-chevron-bot"></i></span>-->
</div>
</div>
<div class="content-com course">
<div class="title"><span>课程制作</span></div>
<div class="cont">
<div class="img-box"><img src="/static/img/widget-myImg.jpg" alt=""></div>
<div class="info-box">
<p class="name">教学方:<em>XX老师</em></p>
<!-- <p class="lab">高级前端开发工程师 10年开发经验</p>-->
<p class="info">JavaEE开发与教学多年,精通JavaEE技术体系,对流行框架JQuery、DWR、Struts1/2,Hibernate,Spring,MyBatis、JBPM、Lucene等有深入研究。授课逻辑严谨,条理清晰,注重学生独立解决问题的能力。</p>
<!-- <p><span>难度等级</span>中级</p>
<p><span>课程时长</span>8-16小时/周,共4周</p>
<p><span>如何通过</span>通过所有的作业及考核,作业共4份,考核为一次终极考核</p>
<p><span>用户评分</span>平均用户评分 <em>4.9</em> <a href="#">查看全部评价</a></p>
<p><span>课程价格</span>特惠价格<em>¥999</em> <i> 原价1999 </i></p>-->
</div>
</div>
</div>
<div class="content-com about">
<div class="title"><span>课程介绍</span></div>
<div class="cont cktop">
<div >
<p>${model.courseBase.description!""}</p>
</div>
<!--<span class="on-off">更多 <i class="i-chevron-bot"></i></span>-->
</div>
</div>
<div class="content-com prob">
<div class="title"><span>常见问题</span></div>
<div class="cont">
<ul>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 我什么时候能够访问课程视频与作业?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 如何需要额外的时间来完成课程会怎么样?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 我支付次课程之后会得到什么?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 退款条例是如何规定的?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
<li class="item"><span class="on-off"><i class="i-chevron-bot"></i> 有助学金?</span>
<div class="drop-down">
<p>课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。</p>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
<div class="articleItem" style="display: none">
<div class="article-cont-catalog">
<div class="article-left-box">
<div class="content">
<#list model.teachplans as firstNode>
<div class="item">
<div class="title act"><i class="i-chevron-top"></i>${firstNode.pname}<span class="time">x小时</span></div>
<div class="drop-down" style="height: 260px;">
<ul class="list-box">
<#list firstNode.teachPlanTreeNodes as secondNode>
<li><a href="http://www.51xuecheng.cn/course/preview/learning.html?id=${model.courseBase.id}&chapter=${secondNode.teachplanMedia.teachplanId!''}" target="_blank">${secondNode.pname}</a></li>
</#list>
</ul>
</div>
</div>
</#list>
<#-- <div class="item">
<div class="title act"><i class="i-chevron-top"></i>第一阶段 HTTP协议基础详解<span class="time">8小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down" style="height: 260px;">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>-->
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
<#--<div class="articleItem" style="display: none">
<div class="article-cont-catalog">
<div class="article-left-box">
<div class="content">
<div class="item">
<div class="title act"><i class="i-chevron-top"></i>第一阶段 HTTP协议基础详解<span class="time">8小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down" style="height: 260px;">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<div class="title"><i class="i-chevron-bot"></i>第二阶段 HTTP协议基础详解<span class="time">8小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<div class="title"><i class="i-chevron-bot"></i>第三阶段 HTTP协议基础详解<span class="time">3小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<div class="title"><i class="i-chevron-bot"></i>第四阶段 HTTP协议基础详解<span class="time">3小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<div class="title"><i class="i-chevron-bot"></i>第五阶段 HTTP协议基础详解<span class="time">3小时</span></div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。</div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”</span></li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”</span></li>
<li>1.3 视频:软件安装介绍 <span>86’42”</span></li>
<li>1.4 阅读:Emacs安装 <span>59’00”</span></li>
<li>1.5 作业1:Emacs安装 <span>93’29”</span></li>
<li>阶段测试</li>
</ul>
</div>
</div>
<div class="item">
<a href="#" class="overwrite">毕业考核</a>
</div>
</div>
</div>
<!--侧边栏–>
<!--#include virtual="/include/course_detail_side.html"–>
<!--侧边栏–>
</div>
</div>-->
<div class="artcleAsk" style="display: none">
<div class="article-cont-ask">
<div class="article-left-box">
<div class="content">
<div class="content-title">
<p><a class="all">全部</a><a>精选</a><a>我的</a></p>
<p><a class="all">全部</a><span><a>1.1</a><a>1.2</a><a>1.3</a><a>1.4</a><a>1.5</a></span><a href="$" class="more">更多 <i class="i-chevron-bot"></i></a></p>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p><span>我来回答</span></p>
<p>2017-3-20 <span><i></i>回答2</span><span><i></i>浏览2</span></p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p class="title">如何用微服务重构应用程序?</p>
<p>在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的。以下两个要点将会对任何微服务重构策略产生重大影响。 【最新 <i class="new">心跳347890</i> 的回答】</p>
<p>2017-3-20 <span class="action-box"><span><i class="i-answer"></i>回答 2</span><span><i class="i-browse"></i>浏览 12</span></span>
</p>
</div>
</div>
<div class="itemlast">
<a href="#" class="overwrite">显示更多问题</a>
</div>
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
<div class="artcleNot" style="display: none;">
<div class="article-cont-note">
<div class="article-left-box">
<div class="content">
<div class="content-title">
<p><a class="all">全部</a><a>精选</a><a>我的</a></p>
<p><a class="all">全部</a><span><a>1.1</a><a>1.2</a><a>1.3</a><a>1.4</a><a>1.5</a></span><a href="$" class="more">更多 <i class="i-chevron-bot"></i></a></p>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<span class="video-time"><i class="i-play"></i>2`10`</span>
<p><img src="/static/img/widget-demo.png" width="221" alt=""></p>
<p class="action-box">4小时前 <span class="active-box"><span><i class="i-coll"></i>采集</span><span><i class="i-laud"></i>赞</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p>在讨论如何将重构转化为微服务之前,退后一步,<br>仔细观察微服务的内容和时间是很重要的。<br>以下两个要点将会对任何微服务重构策略产生重大影响。 </p>
<p class="action-box">4小时前 <span class="active-box"><span><i class="i-edt"></i>编辑</span><span><i class="i-del"></i>删除</span><span><i class="i-laud"></i>赞</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p>在讨论如何将重构转化为微服务之前,退后一步,<br>仔细观察微服务的内容和时间是很重要的。<br>以下两个要点将会对任何微服务重构策略产生重大影响。 </p>
<p class="action-box">4小时前 <span class="active-box"><span><i class="i-edt"></i>编辑</span><span><i class="i-del"></i>删除</span><span><i class="i-laud"></i>赞</span></span>
</p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-right">
<p>在讨论如何将重构转化为微服务之前,退后一步,<br>仔细观察微服务的内容和时间是很重要的。<br>以下两个要点将会对任何微服务重构策略产生重大影响。 </p>
<p class="action-box">4小时前 <span class="active-box"><span><i class="i-edt"></i>编辑</span><span><i class="i-del"></i>删除</span><span><i class="i-laud"></i>赞</span></span>
</p>
</div>
</div>
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
<div class="artcleCod" style="display: none;">
<div class="article-cont">
<div class="article-left-box">
<div class="comment-box">
<div class="evaluate">
<div class="eva-top">
<div class="tit">课程评分 </div>
<div class="star">
<div class="score"><i>5</i></div>
</div><span class="star-score"> <i>5</i> 分</span></div>
<div class="eva-cont">
<div class="tit">学员评语 </div>
<div class="text-box">
<textarea class="form-control" rows="5" placeholder="扯淡、吐槽、表扬、鼓励......想说啥说啥!"></textarea>
<div class="text-right"><span>发表评论</span></div>
</div>
</div>
</div>
<div class="course-evaluate">
<div class="top-tit">评论
<span>
<label><input name="eval" type="radio" value="" checked /> 所有学生 </label>
<label><input name="eval" type="radio" value="" /> 完成者 </label>
</span>
</div>
<div class="top-cont">
<div class="cont-top-left">
<div class="star-scor">
<div class="star-show">
<div class="score"><i>5</i></div>
</div>
<div class="scor">4.9分</div>
</div>
<div class="all-scor">总评分:12343</div>
</div>
<div class="cont-top-right">
<div class="star-grade">五星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>95</i>%</div>
</div>
</div>
<div class="star-grade">四星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>5</i>%</div>
</div>
</div>
<div class="star-grade">三星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>0</i>%</div>
</div>
</div>
<div class="star-grade">二星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>2</i>%</div>
</div>
</div>
<div class="star-grade">一星
<div class="grade">
<div class="grade-percent"><span></span></div>
<div class="percent-num"><i>1</i>%</div>
</div>
</div>
</div>
</div>
<div class="comment-item-box">
<div class="title">评论 <span>12453条评论</span></div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-pic.png" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-cent">
<p>很受用,如果再深入下就更好了。虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!</p>
<p class="time">2017-2-43</p>
</div>
<div class="item-rit">
<p>
<div class="star-show">
<div class="score"><i>4</i></div>
</div>
</p>
<p>评分 <span>5星</span></p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-pic.png" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-cent">
<p>很受用,如果再深入下就更好了。虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!</p>
<p class="time">2017-2-43</p>
</div>
<div class="item-rit">
<p>
<div class="star-show">
<div class="score"><i>5</i></div>
</div>
</p>
<p>评分 <span>5星</span></p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-pic.png" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-cent">
<p>很受用,如果再深入下就更好了。虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!</p>
<p class="time">2017-2-43</p>
</div>
<div class="item-rit">
<p>
<div class="star-show">
<div class="score"><i>5</i></div>
</div>
</p>
<p>评分 <span>5星</span></p>
</div>
</div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-pic.png" width="60px" alt=""></p>
<p>毛老师</p>
</div>
<div class="item-cent">
<p>很受用,如果再深入下就更好了。虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!虽然都是入门级别的,但是也很使用,后续就需要自己发挥了!</p>
<p class="time">2017-2-43</p>
</div>
<div class="item-rit">
<p>
<div class="star-show">
<div class="score"><i>5</i></div>
</div>
</p>
<p>评分 <span>5星</span></p>
</div>
</div>
<div class="get-more">页面加载中...</div>
</div>
</div>
</div>
</div>
<!--侧边栏-->
<!--#include virtual="/include/course_detail_side.html"-->
<!--侧边栏-->
</div>
</div>
</div>
</div>
<div class="popup-course">
<div class="mask"></div>
<!--欢迎访问课程弹窗- start -->
<div class="popup-course-box">
<div class="title">${model.courseBase.name} <span class="close-popup-course-box">×</span></div>
<div class="content">
<p>欢迎学习本课程,本课程免费您可以立即学习,也可加入我的课程表享受更优质的服务。</p>
<p><a href="#" @click.prevent="addCourseTable()">加入我的课程表</a> <a href="#" @click.prevent="startLearngin()">立即学习</a></p>
</div>
</div>
</div>
<div class="popup-box">
<div class="mask"></div>
<!--支付弹窗- start -->
<div class="popup-pay-box">
<div class="title">${model.courseBase.name} <span class="close-popup-pay-box">×</span></div>
<div class="content">
<img :src="qrcode" width="200" height="200" alt="请点击支付宝支付按钮,并完成扫码支付。"/>
<div class="info">
<p class="info-tit">${model.courseBase.name}<span>课程有效期:${model.courseBase.validDays}天</span></p>
<p class="info-pic">课程价格 : <span>¥${model.courseBase.originalPrice!''}元</span></p>
<p class="info-new-pic">优惠价格 : <span>¥${model.courseBase.price!''}元</span></p>
</div>
</div>
<div class="fact-pic">实际支付: <span>¥${model.courseBase.price!''}元</span></div>
<div class="go-pay"><a href="#" @click.prevent="wxPay()">微信支付</a><a href="#" @click.prevent="aliPay()">支付宝支付</a><a href="#" @click.prevent="startLearngin()">试学</a></div>
</div>
<!--支付弹窗- end -->
<div class="popup-comment-box">
</div>
</div>
<!-- 页面底部 -->
<!--底部版权-->
<!--#include virtual="/include/footer.html"-->
<!--底部版权-->
</div>
<script>var courseId = "${model.courseBase.id}";var courseCharge = "${model.courseBase.charge}"</script>
<!--#include virtual="/include/course_detail_dynamic.html"-->
</body>
文件:xuecheng-plus-content/test_service/resources/templates/test.ftl
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World!</title>
</head>
<body>
Hello ${name}!
</body>
</html>
文件:xuecheng-plus-content/xuecheng-plus-content-api/pom.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <!-- SQL 语句片段 -->
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- SQL 语句片段 -->
<modelVersion>4.0.0</modelVersion> <!-- SQL 语句片段 -->
<parent> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-content</artifactId> <!-- SQL 语句片段 -->
<groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
<version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
</parent> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-content-api</artifactId> <!-- SQL 语句片段 -->
<dependencies> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-content-service</artifactId> <!-- SQL 语句片段 -->
<version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!--认证相关-->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.cloud</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-cloud-starter-security</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.cloud</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-cloud-starter-oauth2</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.alibaba.cloud</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.alibaba.cloud</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!--cloud的基础环境包-->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.cloud</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-cloud-context</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- Spring Boot 的 Spring Web MVC 集成 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-web</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- 排除 Spring Boot 依赖的日志包冲突 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter</artifactId> <!-- SQL 语句片段 -->
<exclusions> <!-- SQL 语句片段 -->
<exclusion> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-logging</artifactId> <!-- SQL 语句片段 -->
</exclusion> <!-- SQL 语句片段 -->
</exclusions> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-validation</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- Spring Boot 集成 log4j2 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-log4j2</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- Spring Boot 集成 swagger -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.spring4all</groupId> <!-- SQL 语句片段 -->
<artifactId>swagger-spring-boot-starter</artifactId> <!-- SQL 语句片段 -->
<version>1.9.0.RELEASE</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- Spring Boot 对结果视图 Freemarker 集成 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-freemarker</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
</dependencies> <!-- SQL 语句片段 -->
<build> <!-- SQL 语句片段 -->
<finalName>${project.artifactId}-${project.version}</finalName> <!-- SQL 语句片段 -->
<plugins> <!-- SQL 语句片段 -->
<plugin> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-maven-plugin</artifactId> <!-- SQL 语句片段 -->
<version>${spring-boot.version}</version> <!-- SQL 语句片段 -->
<executions> <!-- SQL 语句片段 -->
<execution> <!-- SQL 语句片段 -->
<goals> <!-- SQL 语句片段 -->
<goal>repackage</goal> <!-- SQL 语句片段 -->
</goals> <!-- SQL 语句片段 -->
</execution> <!-- SQL 语句片段 -->
</executions> <!-- SQL 语句片段 -->
</plugin> <!-- SQL 语句片段 -->
<plugin> <!-- SQL 语句片段 -->
<groupId>com.spotify</groupId> <!-- SQL 语句片段 -->
<artifactId>docker-maven-plugin</artifactId> <!-- SQL 语句片段 -->
<version>1.2.2</version> <!-- SQL 语句片段 -->
<configuration> <!-- SQL 语句片段 -->
<!--修改imageName节点的内容,改为私有仓库地址和端口,再加上镜像id和 TAG,我们要直接传到私服-->
<!--配置最后生成的镜像名,docker images里的,我们这边取项目名:版本-->
<!--<imageName>${project.artifactId}:${project.version}</imageName>-->
<imageName>192.168.101.65:5000/${project.artifactId}:${project.version}</imageName> <!-- SQL 语句片段 -->
<!--也可以通过以下方式定义image的tag信息。 -->
<!-- <imageTags>
<imageTag>${project.version}</imageTag> <!-- SQL 语句片段 -->
<!–build 时强制覆盖 tag,配合 imageTags 使用–> <!-- SQL 语句片段 -->
<forceTags>true</forceTags> <!-- SQL 语句片段 -->
<!–build 完成后,push 指定 tag 的镜像,配合 imageTags 使用–> <!-- SQL 语句片段 -->
<pushImageTag>true</pushImageTag> <!-- SQL 语句片段 -->
</imageTags>--> <!-- SQL 语句片段 -->
<baseImage>java:8u20</baseImage> <!-- SQL 语句片段 -->
<maintainer>docker_maven [email protected]</maintainer> <!-- SQL 语句片段 -->
<workdir>/root</workdir> <!-- SQL 语句片段 -->
<cmd>["java", "-version"]</cmd> <!-- SQL 语句片段 -->
<!--来指明Dockerfile文件的所在目录,如果配置了dockerDirectory则忽略baseImage,maintainer等配置-->
<!--<dockerDirectory>./</dockerDirectory>-->
<!--2375是docker的远程端口,插件生成镜像时连接docker,这里需要指定docker远程端口-->
<dockerHost>http://192.168.101.65:2375</dockerHost> <!-- SQL 语句片段 -->
<!--入口点,project.build.finalName就是project标签下的build标签下 的filename标签内容,testDocker-->
<!--相当于启动容器后,会自动执行java -jar ...-->
<entryPoint>["java", "-Dfile.encoding=utf-8","-jar", "/root/${project.build.finalName}.jar"]</entryPoint> <!-- SQL 语句片段 -->
<!--是否推送到docker私有仓库,旧版本插件要配置maven的settings文件。 -->
<pushImage>true</pushImage> <!-- SQL 语句片段 -->
<registryUrl>192.168.101.65:5000</registryUrl> <!-- 这里是复制 jar 包到 docker 容器指定目录配置 --> <!-- SQL 语句片段 -->
<resources> <!-- SQL 语句片段 -->
<resource> <!-- SQL 语句片段 -->
<targetPath>/root</targetPath> <!-- SQL 语句片段 -->
<directory>${project.build.directory}</directory> <!-- SQL 语句片段 -->
<!--把哪个文件上传到docker,相当于Dockerfile里的add app.jar /-->
<include>${project.build.finalName}.jar</include> <!-- 引用公共 SQL 片段 -->
</resource> <!-- SQL 语句片段 -->
</resources> <!-- SQL 语句片段 -->
</configuration> <!-- SQL 语句片段 -->
</plugin> <!-- SQL 语句片段 -->
</plugins> <!-- SQL 语句片段 -->
</build> <!-- SQL 语句片段 -->
</project> <!-- SQL 语句片段 -->
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/api/CourseBaseInfoController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.xuecheng.base.exception.ValidationGroups; // 导入 ValidationGroups 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.model.dto.AddCourseDto; // 导入 AddCourseDto 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.EditCourseDto; // 导入 EditCourseDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.apache.commons.lang.StringUtils; // 导入 StringUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.security.access.prepost.PreAuthorize; // 导入 PreAuthorize 类
import org.springframework.security.core.context.SecurityContextHolder; // 导入 SecurityContextHolder 类
import org.springframework.validation.annotation.Validated; // 导入 Validated 类
import org.springframework.web.bind.annotation.*; // 导入 * 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
import java.util.ArrayList; // 导入 ArrayList 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/11 15:44 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Api(value = "课程信息管理接口",tags = "课程信息管理接口") // 使用注解 @Api(value = "课程信息管理接口",tags = "课程信息管理接口")
@RestController // 使用注解 @RestController
public class CourseBaseInfoController { // 定义 class CourseBaseInfoController
@Autowired // 使用注解 @Autowired
CourseBaseInfoService courseBaseInfoService; // 执行语句
@ApiOperation("课程分页查询接口") // 使用注解 @ApiOperation("课程分页查询接口")
@PreAuthorize("hasAuthority('xc_teachmanager_course_list')")//指定权限标识符,拥有此权限才可以访问此方法 // 使用注解 @PreAuthorize("hasAuthority('xc_teachmanager_course_list')")
@PostMapping("/course/list") // 使用注解 @PostMapping("/course/list")
public PageResult<CourseBase> list(PageParams pageParams, @RequestBody(required=false) QueryCourseParamsDto queryCourseParamsDto) { // 定义方法 list(...)
//当前登录用户 // 保留原作者写的行内注释
SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
//用户所属机构id // 保留原作者写的行内注释
Long companyId = null; // 把变量 companyId 初始化为 null
if(StringUtils.isNotEmpty(user.getCompanyId())){ // 定义方法 方法(...)
companyId = Long.parseLong(user.getCompanyId()); // 把 Long.parseLong(user.getCompanyId()) 赋值给 companyId
} // 代码块结束
PageResult<CourseBase> courseBasePageResult = courseBaseInfoService.queryCourseBaseList(companyId,pageParams, queryCourseParamsDto); // 把 courseBaseInfoService.queryCourseBaseList(companyId,pageParams, queryCourseParamsDto) 赋值给 courseBasePageResult
return courseBasePageResult; // 返回 courseBasePageResult
} // 代码块结束
@ApiOperation("新增课程") // 使用注解 @ApiOperation("新增课程")
@PostMapping("/course") // 使用注解 @PostMapping("/course")
public CourseBaseInfoDto createCourseBase(@RequestBody @Validated(ValidationGroups.Inster.class) AddCourseDto addCourseDto){ // 定义方法 createCourseBase(...)
//获取到用户所属机构的id // 保留原作者写的行内注释
Long companyId = 1232141425L; // 把 1232141425L 赋值给 companyId
// int i = 1/0; // 保留原作者写的行内注释
CourseBaseInfoDto courseBase = courseBaseInfoService.createCourseBase(companyId, addCourseDto); // 把 courseBaseInfoService.createCourseBase(companyId, addCourseDto) 赋值给 courseBase
return courseBase; // 返回 courseBase
} // 代码块结束
@ApiOperation("根据课程id查询接口") // 使用注解 @ApiOperation("根据课程id查询接口")
@GetMapping("/course/{courseId}") // 使用注解 @GetMapping("/course/{courseId}")
public CourseBaseInfoDto getCourseBaseById(@PathVariable Long courseId){ // 定义方法 getCourseBaseById(...)
//获取当前用户的身份 // 保留原作者写的行内注释
// Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); // 保留原作者写的行内注释
// System.out.println(principal); // 保留原作者写的行内注释
SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
System.out.println(user.getUsername()); // 执行语句
CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId); // 把 courseBaseInfoService.getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
return courseBaseInfo; // 返回 courseBaseInfo
} // 代码块结束
@ApiOperation("修改课程") // 使用注解 @ApiOperation("修改课程")
@PutMapping("/course") // 使用注解 @PutMapping("/course")
public CourseBaseInfoDto modifyCourseBase(@RequestBody @Validated(ValidationGroups.Update.class) EditCourseDto editCourseDto){ // 定义方法 modifyCourseBase(...)
//获取到用户所属机构的id // 保留原作者写的行内注释
Long companyId = 1232141425L; // 把 1232141425L 赋值给 companyId
CourseBaseInfoDto courseBaseInfoDto = courseBaseInfoService.updateCourseBase(companyId, editCourseDto); // 把 courseBaseInfoService.updateCourseBase(companyId, editCourseDto) 赋值给 courseBaseInfoDto
return courseBaseInfoDto; // 返回 courseBaseInfoDto
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/api/CourseCategoryController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.service.CourseCategoryService; // 导入 CourseCategoryService 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程分类相关接口 // 保留原作者写的块注释
* @date 2023/2/12 11:54 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@RestController // 使用注解 @RestController
public class CourseCategoryController { // 定义 class CourseCategoryController
@Autowired // 使用注解 @Autowired
CourseCategoryService courseCategoryService; // 执行语句
@GetMapping("/course-category/tree-nodes") // 使用注解 @GetMapping("/course-category/tree-nodes")
public List<CourseCategoryTreeDto> queryTreeNodes() { // 定义方法 queryTreeNodes(...)
return courseCategoryService.queryTreeNodes("1"); // 返回 courseCategoryService.queryTreeNodes("1")
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/api/CourseOpenController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.PathVariable; // 导入 PathVariable 类
import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 类
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/21 10:33 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
// 获取课程信息接口 // 保留原作者写的行内注释
@RestController // 使用注解 @RestController
@RequestMapping("/open") // 使用注解 @RequestMapping("/open")
public class CourseOpenController { // 定义 class CourseOpenController
@Autowired // 使用注解 @Autowired
private CourseBaseInfoService courseBaseInfoService; // 执行语句
@Autowired // 使用注解 @Autowired
private CoursePublishService coursePublishService; // 执行语句
//根据课程id查询课程信息 // 保留原作者写的行内注释
@GetMapping("/course/whole/{courseId}") // 使用注解 @GetMapping("/course/whole/{courseId}")
public CoursePreviewDto getPreviewInfo(@PathVariable("courseId") Long courseId) { // 定义方法 getPreviewInfo(...)
//获取课程预览信息 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(courseId); // 把 coursePublishService.getCoursePreviewInfo(courseId) 赋值给 coursePreviewInfo
return coursePreviewInfo; // 返回 coursePreviewInfo
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/api/CoursePublishController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Controller; // 导入 Controller 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.PathVariable; // 导入 PathVariable 类
import org.springframework.web.bind.annotation.PostMapping; // 导入 PostMapping 类
import org.springframework.web.bind.annotation.ResponseBody; // 导入 ResponseBody 类
import org.springframework.web.servlet.ModelAndView; // 导入 ModelAndView 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程发布相关接口 // 保留原作者写的块注释
* @date 2023/2/21 9:28 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Controller // 使用注解 @Controller
public class CoursePublishController { // 定义 class CoursePublishController
@Autowired // 使用注解 @Autowired
CoursePublishService coursePublishService; // 执行语句
@ApiOperation("获取课程发布信息") // 使用注解 @ApiOperation("获取课程发布信息")
@ResponseBody // 使用注解 @ResponseBody
@GetMapping("/course/whole/{courseId}") // 使用注解 @GetMapping("/course/whole/{courseId}")
public CoursePreviewDto getCoursePublish(@PathVariable("courseId") Long courseId) { // 定义方法 getCoursePublish(...)
//封装数据 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewDto = new CoursePreviewDto(); // 创建 CoursePreviewDto 对象并赋值给 coursePreviewDto
//查询课程发布表 // 保留原作者写的行内注释
// CoursePublish coursePublish = coursePublishService.getCoursePublish(courseId); // 保留原作者写的行内注释
//先从缓存查询,缓存中有直接返回,没有再查询数据库 // 保留原作者写的行内注释
CoursePublish coursePublish = coursePublishService.getCoursePublishCache(courseId); // 把 coursePublishService.getCoursePublishCache(courseId) 赋值给 coursePublish
if(coursePublish == null){ // 定义方法 方法(...)
return coursePreviewDto; // 返回 coursePreviewDto
} // 代码块结束
//开始向coursePreviewDto填充数据 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfoDto = new CourseBaseInfoDto(); // 创建 CourseBaseInfoDto 对象并赋值给 courseBaseInfoDto
BeanUtils.copyProperties(coursePublish,courseBaseInfoDto); // 执行语句
//课程计划信息 // 保留原作者写的行内注释
String teachplanJson = coursePublish.getTeachplan(); // 把 coursePublish.getTeachplan() 的返回值赋给 teachplanJson
//转成List<TeachplanDto> // 保留原作者写的行内注释
List<TeachplanDto> teachplanDtos = JSON.parseArray(teachplanJson, TeachplanDto.class); // 把 JSON.parseArray(teachplanJson, TeachplanDto.class) 赋值给 teachplanDtos
coursePreviewDto.setCourseBase(courseBaseInfoDto); // 执行语句
coursePreviewDto.setTeachplans(teachplanDtos); // 执行语句
return coursePreviewDto; // 返回 coursePreviewDto
} // 代码块结束
// 课程预览接口 // 保留原作者写的行内注释
// 传入课程id,表示预览哪门课程 // 保留原作者写的行内注释
@GetMapping("/coursepreview/{courseId}") // 使用注解 @GetMapping("/coursepreview/{courseId}")
public ModelAndView preview(@PathVariable("courseId") Long courseId) { // 定义方法 preview(...)
ModelAndView modelAndView = new ModelAndView(); // 创建 ModelAndView 对象并赋值给 modelAndView
//查询课程的信息作为模型数据 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(courseId); // 把 coursePublishService.getCoursePreviewInfo(courseId) 赋值给 coursePreviewInfo
//指定模型 // 保留原作者写的行内注释
modelAndView.addObject("model", coursePreviewInfo); // 执行语句
//指定模板 // 保留原作者写的行内注释
modelAndView.setViewName("course_template");//根据视图名称加.ftl找到模板 // 执行语句
return modelAndView; // 返回 modelAndView
} // 代码块结束
// 提交审核 // 保留原作者写的行内注释
@ResponseBody // 使用注解 @ResponseBody
@PostMapping("/courseaudit/commit/{courseId}") // 使用注解 @PostMapping("/courseaudit/commit/{courseId}")
public void commitAudit(@PathVariable("courseId") Long courseId) { // 定义方法 commitAudit(...)
Long companyId = 1232141425L; // 把 1232141425L 赋值给 companyId
coursePublishService.commitAudit(companyId, courseId); // 执行语句
} // 代码块结束
@ApiOperation("课程发布") // 使用注解 @ApiOperation("课程发布")
@ResponseBody // 使用注解 @ResponseBody
@PostMapping ("/coursepublish/{courseId}") // 使用注解 @PostMapping ("/coursepublish/{courseId}")
public void coursepublish(@PathVariable("courseId") Long courseId){ // 定义方法 coursepublish(...)
Long companyId = 1232141425L; // 把 1232141425L 赋值给 companyId
coursePublishService.publish(companyId,courseId); // 执行语句
} // 代码块结束
@ApiOperation("查询课程发布信息") // 使用注解 @ApiOperation("查询课程发布信息")
@ResponseBody // 使用注解 @ResponseBody
@GetMapping("/r/coursepublish/{courseId}") // 使用注解 @GetMapping("/r/coursepublish/{courseId}")
public CoursePublish getCoursepublish(@PathVariable("courseId") Long courseId) { // 定义方法 getCoursepublish(...)
//查询课程发布信息 // 保留原作者写的行内注释
CoursePublish coursePublish = coursePublishService.getCoursePublish(courseId); // 把 coursePublishService.getCoursePublish(courseId) 赋值给 coursePublish
return coursePublish; // 返回 coursePublish
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/api/FreemarkerController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import org.springframework.stereotype.Controller; // 导入 Controller 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.servlet.ModelAndView; // 导入 ModelAndView 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description Freemarker入门程序 // 保留原作者写的块注释
* @date 2023/2/19 16:12 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Controller // 使用注解 @Controller
public class FreemarkerController { // 定义 class FreemarkerController
@GetMapping("/testfreemarker") // 使用注解 @GetMapping("/testfreemarker")
public ModelAndView test() { // 定义方法 test(...)
ModelAndView modelAndView = new ModelAndView(); // 创建 ModelAndView 对象并赋值给 modelAndView
//指定模型 // 保留原作者写的行内注释
modelAndView.addObject("name","小明"); // 执行语句
//指定模板 // 保留原作者写的行内注释
modelAndView.setViewName("test");//根据视图名称加.ftl找到模板 // 执行语句
return modelAndView; // 返回 modelAndView
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/api/SecurityUtil.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.alibaba.fastjson.JSON; // 导入 JSON 类
import lombok.Data; // 导入 Data 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.security.core.context.SecurityContextHolder; // 导入 SecurityContextHolder 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/24 11:26 // 保留原作者写的块注释
* 获取当前用户身份工具类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
public class SecurityUtil { // 定义 class SecurityUtil
public static XcUser getUser() { // 定义方法 getUser(...)
try { // 尝试执行可能抛出异常的代码
//拿到当前用户身份 // 保留原作者写的行内注释
Object principalObj = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); // 把 SecurityContextHolder.getContext().getAuthentication().getPrincipal() 的返回值赋给 principalObj
if (principalObj instanceof String) { // 定义方法 方法(...)
//取出用户身份信息 // 保留原作者写的行内注释
String principal = principalObj.toString(); // 把 principalObj.toString() 的返回值赋给 principal
//将json转成对象 // 保留原作者写的行内注释
XcUser user = JSON.parseObject(principal, XcUser.class); // 把 JSON.parseObject(principal, XcUser.class) 赋值给 user
return user; // 返回 user
} // 代码块结束
} catch (Exception e) { // 定义方法 catch(...)
log.error("获取当前登录用户身份出错:{}", e.getMessage()); // 执行语句
e.printStackTrace(); // 执行语句
} // 代码块结束
return null; // 返回 null
} // 代码块结束
@Data // 使用注解 @Data
public static class XcUser implements Serializable { // 代码逻辑
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
private String id; // 执行语句
private String username; // 执行语句
private String password; // 执行语句
private String salt; // 执行语句
private String name; // 执行语句
private String nickname; // 执行语句
private String wxUnionid; // 执行语句
private String companyId; // 执行语句
/** // 保留原作者写的块注释
* 头像 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String userpic; // 执行语句
private String utype; // 执行语句
private LocalDateTime birthday; // 执行语句
private String sex; // 执行语句
private String email; // 执行语句
private String cellphone; // 执行语句
private String qq; // 执行语句
/** // 保留原作者写的块注释
* 用户状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
private LocalDateTime createTime; // 执行语句
private LocalDateTime updateTime; // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/api/TeachplanController.java
package com.xuecheng.content.api; // 声明类所在的包路径
import com.xuecheng.content.model.dto.BindTeachplanMediaDto; // 导入 BindTeachplanMediaDto 类
import com.xuecheng.content.model.dto.SaveTeachplanDto; // 导入 SaveTeachplanDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.service.TeachplanService; // 导入 TeachplanService 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.web.bind.annotation.*; // 导入 * 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程计划管理相关的接口 // 保留原作者写的块注释
* @date 2023/2/14 11:25 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Api(value = "课程计划编辑接口",tags = "课程计划编辑接口") // 使用注解 @Api(value = "课程计划编辑接口",tags = "课程计划编辑接口")
@RestController // 使用注解 @RestController
public class TeachplanController { // 定义 class TeachplanController
@Autowired // 使用注解 @Autowired
TeachplanService teachplanService; // 执行语句
@ApiOperation("查询课程计划树形结构") // 使用注解 @ApiOperation("查询课程计划树形结构")
//查询课程计划 GET /teachplan/22/tree-nodes // 保留原作者写的行内注释
@GetMapping("/teachplan/{courseId}/tree-nodes") // 使用注解 @GetMapping("/teachplan/{courseId}/tree-nodes")
public List<TeachplanDto> getTreeNodes(@PathVariable Long courseId){ // 定义方法 getTreeNodes(...)
List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId); // 把 teachplanService.findTeachplanTree(courseId) 赋值给 teachplanTree
return teachplanTree; // 返回 teachplanTree
} // 代码块结束
@ApiOperation("课程计划创建或修改") // 使用注解 @ApiOperation("课程计划创建或修改")
@PostMapping("/teachplan") // 使用注解 @PostMapping("/teachplan")
public void saveTeachplan( @RequestBody SaveTeachplanDto teachplan){ // 定义方法 saveTeachplan(...)
teachplanService.saveTeachplan(teachplan); // 执行语句
} // 代码块结束
@ApiOperation(value = "课程计划和媒资信息绑定") // 使用注解 @ApiOperation(value = "课程计划和媒资信息绑定")
@PostMapping("/teachplan/association/media") // 使用注解 @PostMapping("/teachplan/association/media")
public void associationMedia(@RequestBody BindTeachplanMediaDto bindTeachplanMediaDto){ // 定义方法 associationMedia(...)
teachplanService.associationMedia(bindTeachplanMediaDto); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/config/ResouceServerConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; // 导入 EnableGlobalMethodSecurity 类
import org.springframework.security.config.annotation.web.builders.HttpSecurity; // 导入 HttpSecurity 类
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; // 导入 EnableResourceServer 类
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; // 导入 ResourceServerConfigurerAdapter 类
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; // 导入 ResourceServerSecurityConfigurer 类
import org.springframework.security.oauth2.provider.token.TokenStore; // 导入 TokenStore 类
/** // 保留原作者写的块注释
* @description 资源服务配置 // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/10/18 16:33 // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
@EnableResourceServer // 使用注解 @EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) // 使用注解 @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class ResouceServerConfig extends ResourceServerConfigurerAdapter { // 定义 class ResouceServerConfig
//资源服务标识 // 保留原作者写的行内注释
public static final String RESOURCE_ID = "xuecheng-plus"; // 把 "xuecheng-plus" 赋值给 RESOURCE_ID
@Autowired // 使用注解 @Autowired
TokenStore tokenStore; // 执行语句
@Override // 使用注解 @Override
public void configure(ResourceServerSecurityConfigurer resources) { // 定义方法 configure(...)
resources.resourceId(RESOURCE_ID)//资源 id // 代码逻辑
.tokenStore(tokenStore) // 代码逻辑
.stateless(true); // 执行语句
} // 代码块结束
@Override // 使用注解 @Override
public void configure(HttpSecurity http) throws Exception { // 定义方法 configure(...)
http.csrf().disable() // 代码逻辑
.authorizeRequests() // 代码逻辑
// .antMatchers("/r/**","/course/**").authenticated()//所有/r/**的请求必须认证通过 // 保留原作者写的行内注释
.anyRequest().permitAll() // 代码逻辑
; // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/content/config/TokenConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; // 导入 AuthorizationServerTokenServices 类
import org.springframework.security.oauth2.provider.token.DefaultTokenServices; // 导入 DefaultTokenServices 类
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; // 导入 TokenEnhancerChain 类
import org.springframework.security.oauth2.provider.token.TokenStore; // 导入 TokenStore 类
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; // 导入 JwtAccessTokenConverter 类
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; // 导入 JwtTokenStore 类
import java.util.Arrays; // 导入 Arrays 类
/** // 保留原作者写的块注释
* @author Administrator // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
**/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
public class TokenConfig { // 定义 class TokenConfig
String SIGNING_KEY = "mq123"; // 把 "mq123" 赋值给 SIGNING_KEY
// @Bean // 保留原作者写的行内注释
// public TokenStore tokenStore() { // 保留原作者写的行内注释
// //使用内存存储令牌(普通令牌) // 保留原作者写的行内注释
// return new InMemoryTokenStore(); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
@Autowired // 使用注解 @Autowired
private JwtAccessTokenConverter accessTokenConverter; // 执行语句
@Bean // 使用注解 @Bean
public TokenStore tokenStore() { // 定义方法 tokenStore(...)
return new JwtTokenStore(accessTokenConverter()); // 返回 new JwtTokenStore(accessTokenConverter())
} // 代码块结束
@Bean // 使用注解 @Bean
public JwtAccessTokenConverter accessTokenConverter() { // 定义方法 accessTokenConverter(...)
JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); // 创建 JwtAccessTokenConverter 对象并赋值给 converter
converter.setSigningKey(SIGNING_KEY); // 执行语句
return converter; // 返回 converter
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/java/com/xuecheng/ContentApplication.java
package com.xuecheng; // 声明类所在的包路径
import com.spring4all.swagger.EnableSwagger2Doc; // 导入 EnableSwagger2Doc 类
import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类
import org.springframework.cloud.openfeign.EnableFeignClients; // 导入 EnableFeignClients 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 内容管理服务启动类 // 保留原作者写的块注释
* @date 2023/2/11 15:49 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@EnableFeignClients(basePackages={"com.xuecheng.content.feignclient"}) // 使用注解 @EnableFeignClients(basePackages={"com.xuecheng.content.feignclient"})
@EnableSwagger2Doc // 使用注解 @EnableSwagger2Doc
@SpringBootApplication // 使用注解 @SpringBootApplication
public class ContentApplication { // 定义 class ContentApplication
public static void main(String[] args) { // 定义方法 main(...)
SpringApplication.run(ContentApplication.class, args); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/resources/bootstrap.yml
#server:
# servlet:
# context-path: /content
# port: 63041
#微服务配置
spring:
application:
name: content-api #服务名content-api-dev.yaml
cloud:
nacos:
server-addr: 192.168.101.65:8848
discovery: #服务注册相关配置
namespace: dev402
group: xuecheng-plus-project
config: #配置文件相关配置
namespace: dev402
group: xuecheng-plus-project
file-extension: yaml
refresh-enabled: true
extension-configs:
- data-id: content-service-${spring.profiles.active}.yaml
group: xuecheng-plus-project
refresh: true
shared-configs:
- data-id: swagger-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true
- data-id: logging-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true
- data-id: freemarker-config-dev.yaml
group: xuecheng-plus-common
refresh: true
- data-id: feign-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true #profiles默认为dev
- data-id: redis-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true
# datasource:
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://192.168.101.65:3306/xc402_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
# username: root
# password: mysql
profiles:
active: dev #环境名
#logging:
# config: classpath:log4j2-dev.xml # 日志文件配置路径
#swagger:
# title: "学成在线内容管理系统"
# description: "内容系统管理系统对课程相关信息进行管理"
# base-package: com.xuecheng.content
# enabled: true
# version: 1.0.0
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/resources/log4j2-dev.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<Configuration monitorInterval="180" packages=""> <!-- SQL 语句片段 -->
<properties> <!-- SQL 语句片段 -->
<property name="logdir">logs</property> <!-- SQL 语句片段 -->
<property name="PATTERN">%date{YYYY-MM-dd HH:mm:ss,SSS} %level [%thread][%file:%line] - %msg%n%throwable</property> <!-- SQL 语句片段 -->
</properties> <!-- SQL 语句片段 -->
<Appenders> <!-- SQL 语句片段 -->
<Console name="Console" target="SYSTEM_OUT"> <!-- SQL 语句片段 -->
<PatternLayout pattern="${PATTERN}"/> <!-- SQL 语句片段 -->
</Console> <!-- SQL 语句片段 -->
<RollingFile name="ErrorAppender" fileName="${logdir}/error.log" <!-- SQL 语句片段 -->
filePattern="${logdir}/$${date:yyyy-MM-dd}/error.%d{yyyy-MM-dd-HH}.log" append="true"> <!-- SQL 语句片段 -->
<PatternLayout pattern="${PATTERN}"/> <!-- SQL 语句片段 -->
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> <!-- SQL 语句片段 -->
<Policies> <!-- SQL 语句片段 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" /> <!-- SQL 语句片段 -->
</Policies> <!-- SQL 语句片段 -->
</RollingFile> <!-- SQL 语句片段 -->
<RollingFile name="DebugAppender" fileName="${logdir}/info.log" <!-- SQL 语句片段 -->
filePattern="${logdir}/$${date:yyyy-MM-dd}/info.%d{yyyy-MM-dd-HH}.log" append="true"> <!-- SQL 语句片段 -->
<PatternLayout pattern="${PATTERN}"/> <!-- SQL 语句片段 -->
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/> <!-- SQL 语句片段 -->
<Policies> <!-- SQL 语句片段 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" /> <!-- SQL 语句片段 -->
</Policies> <!-- SQL 语句片段 -->
</RollingFile> <!-- SQL 语句片段 -->
<!--异步appender-->
<Async name="AsyncAppender" includeLocation="true"> <!-- SQL 语句片段 -->
<AppenderRef ref="ErrorAppender"/> <!-- SQL 语句片段 -->
<AppenderRef ref="DebugAppender"/> <!-- SQL 语句片段 -->
</Async> <!-- SQL 语句片段 -->
</Appenders> <!-- SQL 语句片段 -->
<Loggers> <!-- SQL 语句片段 -->
<!--过滤掉spring和mybatis的一些无用的debug信息
<logger name="org.springframework" level="INFO"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.mybatis" level="INFO"> <!-- SQL 语句片段 -->
</logger>--> <!-- SQL 语句片段 -->
<logger name="cn.itcast.wanxinp2p.consumer.mapper" level="DEBUG"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="springfox" level="INFO"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.apache.http" level="INFO"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="com.netflix.discovery" level="INFO"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="RocketmqCommon" level="INFO" > <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="RocketmqRemoting" level="INFO" > <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="RocketmqClient" level="WARN"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.dromara.hmily" level="WARN"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.dromara.hmily.lottery" level="WARN"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.dromara.hmily.bonuspoint" level="WARN"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<!--OFF 0-->
<!--FATAL 100-->
<!--ERROR 200-->
<!--WARN 300-->
<!--INFO 400-->
<!--DEBUG 500-->
<!--TRACE 600-->
<!--ALL Integer.MAX_VALUE-->
<Root level="info" includeLocation="true"> <!-- SQL 语句片段 -->
<AppenderRef ref="AsyncAppender"/> <!-- SQL 语句片段 -->
<AppenderRef ref="Console"/> <!-- SQL 语句片段 -->
<AppenderRef ref="DebugAppender"/> <!-- SQL 语句片段 -->
</Root> <!-- SQL 语句片段 -->
</Loggers> <!-- SQL 语句片段 -->
</Configuration> <!-- SQL 语句片段 -->
文件:xuecheng-plus-content/xuecheng-plus-content-api/src/main/resources/singleServerConfig.yaml
---
singleServerConfig:
#如果当前连接池里的连接数量超过了最小空闲连接数,而同时有连接空闲时间超过了该数值,
#那么这些连接将会自动被关闭,并从连接池里去掉。时间单位是毫秒。
#默认值:10000
idleConnectionTimeout: 10000
pingTimeout: 1000
#同任何节点建立连接时的等待超时。时间单位是毫秒。
#默认值:10000
connectTimeout: 10000
#等待节点回复命令的时间。该时间从命令发送成功时开始计时。
#默认值:3000
timeout: 3000
#如果尝试达到 retryAttempts(命令失败重试次数)
#仍然不能将命令发送至某个指定的节点时,将抛出错误。如果尝试在此限制之内发送成功,
#则开始启用 timeout(命令等待超时) 计时。
#默认值:3
retryAttempts: 3
#在某个节点执行相同或不同命令时,连续失败failedAttempts(执行失败最大次数)时,
#该节点将被从可用节点列表里清除,直到 reconnectionTimeout(重新连接时间间隔) 超时以后再次尝试。
#默认值:1500
retryInterval: 1500
#重新连接时间间隔
reconnectionTimeout: 3000
#执行失败最大次数
failedAttempts: 3
#密码
password: redis
#数据库选择 select 4
database: 0
#每个连接的最大订阅数量。
#默认值:5
subscriptionsPerConnection: 5
#在Redis节点里显示的客户端名称。
clientName: null
#在Redis节点
address: "redis://192.168.101.65:6379"
#从节点发布和订阅连接的最小空闲连接数
#默认值:1
subscriptionConnectionMinimumIdleSize: 1
#用于发布和订阅连接的连接池最大容量。连接池的连接数量自动弹性伸缩。
#默认值:50
subscriptionConnectionPoolSize: 50
#节点最小空闲连接数
#默认值:32
connectionMinimumIdleSize: 32
#节点连接池大小
#默认值:64
connectionPoolSize: 64
#这个线程池数量被所有RTopic对象监听器,RRemoteService调用者和RExecutorService任务共同共享。
#默认值: 当前处理核数量 * 2
threads: 8
#这个线程池数量是在一个Redisson实例内,被其创建的所有分布式数据类型和服务,
#以及底层客户端所一同共享的线程池里保存的线程数量。
#默认值: 当前处理核数量 * 2
nettyThreads: 8
#Redisson的对象编码类是用于将对象进行序列化和反序列化,以实现对该对象在Redis里的读取和存储。
#默认值: org.redisson.codec.JsonJacksonCodec
codec: !<org.redisson.codec.JsonJacksonCodec> {}
#传输模式
#默认值:TransportMode.NIO
transportMode: "NIO"
文件:xuecheng-plus-content/xuecheng-plus-content-model/pom.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <!-- SQL 语句片段 -->
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- SQL 语句片段 -->
<modelVersion>4.0.0</modelVersion> <!-- SQL 语句片段 -->
<parent> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-content</artifactId> <!-- SQL 语句片段 -->
<groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
<version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
</parent> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-content-model</artifactId> <!-- SQL 语句片段 -->
<dependencies> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-base</artifactId> <!-- SQL 语句片段 -->
<version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!--存在mybatisplus注解添加相关注解保证不报错-->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.baomidou</groupId> <!-- SQL 语句片段 -->
<artifactId>mybatis-plus-annotation</artifactId> <!-- SQL 语句片段 -->
<version>${mybatis-plus-boot-starter.version}</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.baomidou</groupId> <!-- SQL 语句片段 -->
<artifactId>mybatis-plus-core</artifactId> <!-- SQL 语句片段 -->
<version>${mybatis-plus-boot-starter.version}</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.projectlombok</groupId> <!-- SQL 语句片段 -->
<artifactId>lombok</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
</dependencies> <!-- SQL 语句片段 -->
</project> <!-- SQL 语句片段 -->
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/dto/AddCourseDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import com.xuecheng.base.exception.ValidationGroups; // 导入 ValidationGroups 类
import io.swagger.annotations.ApiModel; // 导入 ApiModel 类
import io.swagger.annotations.ApiModelProperty; // 导入 ApiModelProperty 类
import lombok.Data; // 导入 Data 类
import javax.validation.constraints.NotEmpty; // 导入 NotEmpty 类
import javax.validation.constraints.Size; // 导入 Size 类
import java.math.BigDecimal; // 导入 BigDecimal 类
/** // 保留原作者写的块注释
* @description 添加课程dto // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/7 17:40 // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ApiModel(value="AddCourseDto", description="新增课程基本信息") // 使用注解 @ApiModel(value="AddCourseDto", description="新增课程基本信息")
public class AddCourseDto { // 定义 class AddCourseDto
@NotEmpty(message = "新增课程名称不能为空",groups={ValidationGroups.Inster.class}) // 使用注解 @NotEmpty(message = "新增课程名称不能为空",groups={ValidationGroups.Inster.class})
@NotEmpty(message = "修改课程名称不能为空",groups={ValidationGroups.Update.class}) // 使用注解 @NotEmpty(message = "修改课程名称不能为空",groups={ValidationGroups.Update.class})
// @NotEmpty(message = "课程名称不能为空") // 保留原作者写的行内注释
@ApiModelProperty(value = "课程名称", required = true) // 使用注解 @ApiModelProperty(value = "课程名称", required = true)
private String name; // 执行语句
@NotEmpty(message = "适用人群不能为空") // 使用注解 @NotEmpty(message = "适用人群不能为空")
@Size(message = "适用人群内容过少",min = 10) // 使用注解 @Size(message = "适用人群内容过少",min = 10)
@ApiModelProperty(value = "适用人群", required = true) // 使用注解 @ApiModelProperty(value = "适用人群", required = true)
private String users; // 执行语句
@ApiModelProperty(value = "课程标签") // 使用注解 @ApiModelProperty(value = "课程标签")
private String tags; // 执行语句
@NotEmpty(message = "课程分类不能为空") // 使用注解 @NotEmpty(message = "课程分类不能为空")
@ApiModelProperty(value = "大分类", required = true) // 使用注解 @ApiModelProperty(value = "大分类", required = true)
private String mt; // 执行语句
@NotEmpty(message = "课程分类不能为空") // 使用注解 @NotEmpty(message = "课程分类不能为空")
@ApiModelProperty(value = "小分类", required = true) // 使用注解 @ApiModelProperty(value = "小分类", required = true)
private String st; // 执行语句
@NotEmpty(message = "课程等级不能为空") // 使用注解 @NotEmpty(message = "课程等级不能为空")
@ApiModelProperty(value = "课程等级", required = true) // 使用注解 @ApiModelProperty(value = "课程等级", required = true)
private String grade; // 执行语句
@ApiModelProperty(value = "教学模式(普通,录播,直播等)", required = true) // 使用注解 @ApiModelProperty(value = "教学模式(普通,录播,直播等)", required = true)
private String teachmode; // 执行语句
@ApiModelProperty(value = "课程介绍") // 使用注解 @ApiModelProperty(value = "课程介绍")
@Size(message = "课程描述内容过少",min = 10) // 使用注解 @Size(message = "课程描述内容过少",min = 10)
private String description; // 执行语句
@ApiModelProperty(value = "课程图片", required = true) // 使用注解 @ApiModelProperty(value = "课程图片", required = true)
private String pic; // 执行语句
@NotEmpty(message = "收费规则不能为空") // 使用注解 @NotEmpty(message = "收费规则不能为空")
@ApiModelProperty(value = "收费规则,对应数据字典", required = true) // 使用注解 @ApiModelProperty(value = "收费规则,对应数据字典", required = true)
private String charge; // 执行语句
@ApiModelProperty(value = "价格") // 使用注解 @ApiModelProperty(value = "价格")
private Float price; // 执行语句
@ApiModelProperty(value = "原价") // 使用注解 @ApiModelProperty(value = "原价")
private Float originalPrice; // 执行语句
@ApiModelProperty(value = "qq") // 使用注解 @ApiModelProperty(value = "qq")
private String qq; // 执行语句
@ApiModelProperty(value = "微信") // 使用注解 @ApiModelProperty(value = "微信")
private String wechat; // 执行语句
@ApiModelProperty(value = "电话") // 使用注解 @ApiModelProperty(value = "电话")
private String phone; // 执行语句
@ApiModelProperty(value = "有效期") // 使用注解 @ApiModelProperty(value = "有效期")
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/dto/BindTeachplanMediaDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import io.swagger.annotations.ApiModel; // 导入 ApiModel 类
import io.swagger.annotations.ApiModelProperty; // 导入 ApiModelProperty 类
import lombok.Data; // 导入 Data 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 绑定媒资和课程计划的模型类 // 保留原作者写的块注释
* @date 2023/2/19 15:37 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ApiModel(value="BindTeachplanMediaDto", description="教学计划-媒资绑定提交数据") // 使用注解 @ApiModel(value="BindTeachplanMediaDto", description="教学计划-媒资绑定提交数据")
public class BindTeachplanMediaDto { // 定义 class BindTeachplanMediaDto
@ApiModelProperty(value = "媒资文件id", required = true) // 使用注解 @ApiModelProperty(value = "媒资文件id", required = true)
private String mediaId; // 执行语句
@ApiModelProperty(value = "媒资文件名称", required = true) // 使用注解 @ApiModelProperty(value = "媒资文件名称", required = true)
private String fileName; // 执行语句
@ApiModelProperty(value = "课程计划标识", required = true) // 使用注解 @ApiModelProperty(value = "课程计划标识", required = true)
private Long teachplanId; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/dto/CourseBaseInfoDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import io.swagger.annotations.ApiModelProperty; // 导入 ApiModelProperty 类
import lombok.Data; // 导入 Data 类
import java.math.BigDecimal; // 导入 BigDecimal 类
/** // 保留原作者写的块注释
* @description 课程基本信息dto // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/7 17:44 // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CourseBaseInfoDto extends CourseBase { // 定义 class CourseBaseInfoDto
/** // 保留原作者写的块注释
* 收费规则,对应数据字典 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
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; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/dto/CourseCategoryTreeDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import com.xuecheng.content.model.po.CourseCategory; // 导入 CourseCategory 类
import lombok.Data; // 导入 Data 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 11:51 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CourseCategoryTreeDto extends CourseCategory implements java.io.Serializable { // 定义 class CourseCategoryTreeDto
//子节点 // 保留原作者写的行内注释
List<CourseCategoryTreeDto> childrenTreeNodes; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/dto/CoursePreviewDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import lombok.Data; // 导入 Data 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程预览模型类 // 保留原作者写的块注释
* @date 2023/2/21 10:00 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CoursePreviewDto { // 定义 class CoursePreviewDto
//课程基本信息,营销信息 // 保留原作者写的行内注释
private CourseBaseInfoDto courseBase; // 执行语句
//课程计划信息 // 保留原作者写的行内注释
private List<TeachplanDto> teachplans; // 执行语句
//课程师资信息... // 保留原作者写的行内注释
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/dto/EditCourseDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import io.swagger.annotations.ApiModelProperty; // 导入 ApiModelProperty 类
import lombok.Data; // 导入 Data 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/14 10:22 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class EditCourseDto extends AddCourseDto { // 定义 class EditCourseDto
@ApiModelProperty(value = "课程id", required = true) // 使用注解 @ApiModelProperty(value = "课程id", required = true)
private Long id; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/dto/QueryCourseParamsDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程查询条件模型类 // 保留原作者写的块注释
* @date 2023/2/11 15:37 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class QueryCourseParamsDto { // 定义 class QueryCourseParamsDto
//审核状态 // 保留原作者写的行内注释
private String auditStatus; // 执行语句
//课程名称 // 保留原作者写的行内注释
private String courseName; // 执行语句
//发布状态 // 保留原作者写的行内注释
private String publishStatus; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/dto/SaveTeachplanDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import lombok.Data; // 导入 Data 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 新增大章节、小章节、修改章节信息 // 保留原作者写的块注释
* @date 2023/2/14 14:54 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class SaveTeachplanDto { // 定义 class SaveTeachplanDto
/*** // 保留原作者写的块注释
* 教学计划id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 课程计划名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pname; // 执行语句
/** // 保留原作者写的块注释
* 课程计划父级Id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long parentid; // 执行语句
/** // 保留原作者写的块注释
* 层级,分为1、2、3级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer grade; // 执行语句
/** // 保留原作者写的块注释
* 课程类型:1视频、2文档 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mediaType; // 执行语句
/** // 保留原作者写的块注释
* 课程标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long courseId; // 执行语句
/** // 保留原作者写的块注释
* 课程发布标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long coursePubId; // 执行语句
/** // 保留原作者写的块注释
* 是否支持试学或预览(试看) // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String isPreview; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/dto/TeachplanDto.java
package com.xuecheng.content.model.dto; // 声明类所在的包路径
import com.xuecheng.content.model.po.Teachplan; // 导入 Teachplan 类
import com.xuecheng.content.model.po.TeachplanMedia; // 导入 TeachplanMedia 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程计划信息模型类 // 保留原作者写的块注释
* @date 2023/2/14 11:23 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class TeachplanDto extends Teachplan { // 定义 class TeachplanDto
//与媒资管理的信息 // 保留原作者写的行内注释
private TeachplanMedia teachplanMedia; // 执行语句
//小章节list // 保留原作者写的行内注释
private List<TeachplanDto> teachPlanTreeNodes; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/po/CourseBase.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.*; // 导入 * 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程基本信息 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_base") // 使用注解 @TableName("course_base")
public class CourseBase implements Serializable { // 定义 class CourseBase
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableId(value = "id", type = IdType.AUTO) // 使用注解 @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) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 修改时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT_UPDATE) // 使用注解 @TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime changeDate; // 执行语句
/** // 保留原作者写的块注释
* 创建人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String createPeople; // 执行语句
/** // 保留原作者写的块注释
* 更新人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String changePeople; // 执行语句
/** // 保留原作者写的块注释
* 审核状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String auditStatus; // 执行语句
/** // 保留原作者写的块注释
* 课程发布状态 未发布 已发布 下线 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/po/CourseCategory.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.TableName; // 导入 TableName 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程分类 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_category") // 使用注解 @TableName("course_category")
public class CourseCategory implements Serializable { // 定义 class CourseCategory
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String id; // 执行语句
/** // 保留原作者写的块注释
* 分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String name; // 执行语句
/** // 保留原作者写的块注释
* 分类标签默认和名称一样 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String label; // 执行语句
/** // 保留原作者写的块注释
* 父结点id(第一级的父节点是0,自关联字段id) // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String parentid; // 执行语句
/** // 保留原作者写的块注释
* 是否显示 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer isShow; // 执行语句
/** // 保留原作者写的块注释
* 排序字段 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer orderby; // 执行语句
/** // 保留原作者写的块注释
* 是否叶子 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer isLeaf; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/po/CourseMarket.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.TableName; // 导入 TableName 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程营销信息 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_market") // 使用注解 @TableName("course_market")
public class CourseMarket implements Serializable { // 定义 class CourseMarket
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键,课程id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 收费规则,对应数据字典 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String charge; // 执行语句
/** // 保留原作者写的块注释
* 现价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float price; // 执行语句
/** // 保留原作者写的块注释
* 原价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float originalPrice; // 执行语句
/** // 保留原作者写的块注释
* 咨询qq // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String qq; // 执行语句
/** // 保留原作者写的块注释
* 微信 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String wechat; // 执行语句
/** // 保留原作者写的块注释
* 电话 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String phone; // 执行语句
/** // 保留原作者写的块注释
* 有效期天数 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/po/CoursePublish.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.FieldFill; // 导入 FieldFill 类
import com.baomidou.mybatisplus.annotation.TableField; // 导入 TableField 类
import com.baomidou.mybatisplus.annotation.TableName; // 导入 TableName 类
import com.fasterxml.jackson.annotation.JsonFormat; // 导入 JsonFormat 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程发布 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_publish") // 使用注解 @TableName("course_publish")
public class CoursePublish implements Serializable { // 定义 class CoursePublish
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 机构ID // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long companyId; // 执行语句
/** // 保留原作者写的块注释
* 公司名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String companyName; // 执行语句
/** // 保留原作者写的块注释
* 课程名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String name; // 执行语句
/** // 保留原作者写的块注释
* 适用人群 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String users; // 执行语句
/** // 保留原作者写的块注释
* 标签 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String tags; // 执行语句
/** // 保留原作者写的块注释
* 创建人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String username; // 执行语句
/** // 保留原作者写的块注释
* 大分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mt; // 执行语句
/** // 保留原作者写的块注释
* 大分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mtName; // 执行语句
/** // 保留原作者写的块注释
* 小分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String st; // 执行语句
/** // 保留原作者写的块注释
* 小分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String stName; // 执行语句
/** // 保留原作者写的块注释
* 课程等级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String grade; // 执行语句
/** // 保留原作者写的块注释
* 教育模式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachmode; // 执行语句
/** // 保留原作者写的块注释
* 课程图片 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pic; // 执行语句
/** // 保留原作者写的块注释
* 课程介绍 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String description; // 执行语句
/** // 保留原作者写的块注释
* 课程营销信息,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String market; // 执行语句
/** // 保留原作者写的块注释
* 所有课程计划,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachplan; // 执行语句
/** // 保留原作者写的块注释
* 教师信息,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachers; // 执行语句
/** // 保留原作者写的块注释
* 发布时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 上架时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime onlineDate; // 执行语句
/** // 保留原作者写的块注释
* 下架时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime offlineDate; // 执行语句
/** // 保留原作者写的块注释
* 发布状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
/** // 保留原作者写的块注释
* 备注 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String remark; // 执行语句
/** // 保留原作者写的块注释
* 收费规则,对应数据字典--203 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String charge; // 执行语句
/** // 保留原作者写的块注释
* 现价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float price; // 执行语句
/** // 保留原作者写的块注释
* 原价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float originalPrice; // 执行语句
/** // 保留原作者写的块注释
* 课程有效期天数 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/po/CoursePublishPre.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.FieldFill; // 导入 FieldFill 类
import com.baomidou.mybatisplus.annotation.TableField; // 导入 TableField 类
import com.baomidou.mybatisplus.annotation.TableName; // 导入 TableName 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程发布 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_publish_pre") // 使用注解 @TableName("course_publish_pre")
public class CoursePublishPre implements Serializable { // 定义 class CoursePublishPre
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 机构ID // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long companyId; // 执行语句
/** // 保留原作者写的块注释
* 公司名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String companyName; // 执行语句
/** // 保留原作者写的块注释
* 课程名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String name; // 执行语句
/** // 保留原作者写的块注释
* 适用人群 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String users; // 执行语句
/** // 保留原作者写的块注释
* 标签 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String tags; // 执行语句
/** // 保留原作者写的块注释
* 创建人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String username; // 执行语句
/** // 保留原作者写的块注释
* 大分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mt; // 执行语句
/** // 保留原作者写的块注释
* 大分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mtName; // 执行语句
/** // 保留原作者写的块注释
* 小分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String st; // 执行语句
/** // 保留原作者写的块注释
* 小分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String stName; // 执行语句
/** // 保留原作者写的块注释
* 课程等级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String grade; // 执行语句
/** // 保留原作者写的块注释
* 教育模式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachmode; // 执行语句
/** // 保留原作者写的块注释
* 课程图片 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pic; // 执行语句
/** // 保留原作者写的块注释
* 课程介绍 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String description; // 执行语句
/** // 保留原作者写的块注释
* 课程营销信息,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String market; // 执行语句
/** // 保留原作者写的块注释
* 所有课程计划,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachplan; // 执行语句
/** // 保留原作者写的块注释
* 教师信息,json格式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachers; // 执行语句
/** // 保留原作者写的块注释
* 提交时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 审核时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private LocalDateTime auditDate; // 执行语句
/** // 保留原作者写的块注释
* 状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
/** // 保留原作者写的块注释
* 备注 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String remark; // 执行语句
/** // 保留原作者写的块注释
* 收费规则,对应数据字典--203 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String charge; // 执行语句
/** // 保留原作者写的块注释
* 现价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float price; // 执行语句
/** // 保留原作者写的块注释
* 原价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float originalPrice; // 执行语句
/** // 保留原作者写的块注释
* 课程有效期天数 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/po/CourseTeacher.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.*; // 导入 * 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程-教师关系表 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("course_teacher") // 使用注解 @TableName("course_teacher")
public class CourseTeacher implements Serializable { // 定义 class CourseTeacher
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableId(value = "id", type = IdType.AUTO) // 使用注解 @TableId(value = "id", type = IdType.AUTO)
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 课程标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long courseId; // 执行语句
/** // 保留原作者写的块注释
* 教师标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teacherName; // 执行语句
/** // 保留原作者写的块注释
* 教师职位 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String position; // 执行语句
/** // 保留原作者写的块注释
* 教师简介 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String introduction; // 执行语句
/** // 保留原作者写的块注释
* 照片 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String photograph; // 执行语句
/** // 保留原作者写的块注释
* 创建时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/po/Teachplan.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.*; // 导入 * 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程计划 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("teachplan") // 使用注解 @TableName("teachplan")
public class Teachplan implements Serializable { // 定义 class Teachplan
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
@TableId(value = "id", type = IdType.AUTO) // 使用注解 @TableId(value = "id", type = IdType.AUTO)
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 课程计划名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pname; // 执行语句
/** // 保留原作者写的块注释
* 课程计划父级Id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long parentid; // 执行语句
/** // 保留原作者写的块注释
* 层级,分为1、2、3级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer grade; // 执行语句
/** // 保留原作者写的块注释
* 课程类型:1视频、2文档 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mediaType; // 执行语句
/** // 保留原作者写的块注释
* 开始直播时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private LocalDateTime startTime; // 执行语句
/** // 保留原作者写的块注释
* 直播结束时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private LocalDateTime endTime; // 执行语句
/** // 保留原作者写的块注释
* 章节及课程时介绍 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String description; // 执行语句
/** // 保留原作者写的块注释
* 时长,单位时:分:秒 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String timelength; // 执行语句
/** // 保留原作者写的块注释
* 排序字段 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer orderby; // 执行语句
/** // 保留原作者写的块注释
* 课程标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long courseId; // 执行语句
/** // 保留原作者写的块注释
* 课程发布标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long coursePubId; // 执行语句
/** // 保留原作者写的块注释
* 状态(1正常 0删除) // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer status; // 执行语句
/** // 保留原作者写的块注释
* 是否支持试学或预览(试看) // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String isPreview; // 执行语句
/** // 保留原作者写的块注释
* 创建时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 修改时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField(fill = FieldFill.INSERT_UPDATE) // 使用注解 @TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime changeDate; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-model/src/main/java/com/xuecheng/content/model/po/TeachplanMedia.java
package com.xuecheng.content.model.po; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.*; // 导入 * 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
@TableName("teachplan_media") // 使用注解 @TableName("teachplan_media")
public class TeachplanMedia implements Serializable { // 定义 class TeachplanMedia
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableId(value = "id", type = IdType.AUTO) // 使用注解 @TableId(value = "id", type = IdType.AUTO)
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 媒资文件id // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mediaId; // 执行语句
/** // 保留原作者写的块注释
* 课程计划标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long teachplanId; // 执行语句
/** // 保留原作者写的块注释
* 课程标识 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long courseId; // 执行语句
/** // 保留原作者写的块注释
* 媒资文件原始名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@TableField("media_fileName") // 使用注解 @TableField("media_fileName")
private String mediaFilename; // 执行语句
@TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 创建人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String createPeople; // 执行语句
/** // 保留原作者写的块注释
* 修改人 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String changePeople; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/pom.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <!-- SQL 语句片段 -->
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- SQL 语句片段 -->
<modelVersion>4.0.0</modelVersion> <!-- SQL 语句片段 -->
<parent> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-content</artifactId> <!-- SQL 语句片段 -->
<groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
<version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
</parent> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-content-service</artifactId> <!-- SQL 语句片段 -->
<dependencies> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.alibaba.cloud</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-content-model</artifactId> <!-- SQL 语句片段 -->
<version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
<artifactId>xuecheng-plus-message-sdk</artifactId> <!-- SQL 语句片段 -->
<version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.xuxueli</groupId> <!-- SQL 语句片段 -->
<artifactId>xxl-job-core</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- MySQL 驱动 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>mysql</groupId> <!-- SQL 语句片段 -->
<artifactId>mysql-connector-java</artifactId> <!-- SQL 语句片段 -->
<scope>runtime</scope> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- mybatis plus的依赖 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.baomidou</groupId> <!-- SQL 语句片段 -->
<artifactId>mybatis-plus-boot-starter</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.cloud</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-cloud-context</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- Spring Boot 集成 Junit -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-test</artifactId> <!-- SQL 语句片段 -->
<scope>test</scope> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- 排除 Spring Boot 依赖的日志包冲突 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter</artifactId> <!-- SQL 语句片段 -->
<exclusions> <!-- SQL 语句片段 -->
<exclusion> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-logging</artifactId> <!-- SQL 语句片段 -->
</exclusion> <!-- SQL 语句片段 -->
</exclusions> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-data-redis</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.apache.commons</groupId> <!-- SQL 语句片段 -->
<artifactId>commons-pool2</artifactId> <!-- SQL 语句片段 -->
<version>2.6.2</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.redisson</groupId> <!-- SQL 语句片段 -->
<artifactId>redisson-spring-boot-starter</artifactId> <!-- SQL 语句片段 -->
<version>3.11.2</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- Spring Boot 集成 log4j2 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-log4j2</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-boot-starter-freemarker</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>com.alibaba.cloud</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!-- Spring Cloud 微服务远程调用 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>org.springframework.cloud</groupId> <!-- SQL 语句片段 -->
<artifactId>spring-cloud-starter-openfeign</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>io.github.openfeign</groupId> <!-- SQL 语句片段 -->
<artifactId>feign-httpclient</artifactId> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<!--feign支持Multipart格式传参-->
<dependency> <!-- SQL 语句片段 -->
<groupId>io.github.openfeign.form</groupId> <!-- SQL 语句片段 -->
<artifactId>feign-form</artifactId> <!-- SQL 语句片段 -->
<version>3.8.0</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
<dependency> <!-- SQL 语句片段 -->
<groupId>io.github.openfeign.form</groupId> <!-- SQL 语句片段 -->
<artifactId>feign-form-spring</artifactId> <!-- SQL 语句片段 -->
<version>3.8.0</version> <!-- SQL 语句片段 -->
</dependency> <!-- SQL 语句片段 -->
</dependencies> <!-- SQL 语句片段 -->
</project> <!-- SQL 语句片段 -->
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/config/MultipartSupportConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import feign.codec.Encoder; // 导入 Encoder 类
import feign.form.spring.SpringFormEncoder; // 导入 SpringFormEncoder 类
import org.apache.commons.fileupload.FileItem; // 导入 FileItem 类
import org.apache.commons.fileupload.disk.DiskFileItemFactory; // 导入 DiskFileItemFactory 类
import org.apache.commons.io.IOUtils; // 导入 IOUtils 类
import org.springframework.beans.factory.ObjectFactory; // 导入 ObjectFactory 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.autoconfigure.http.HttpMessageConverters; // 导入 HttpMessageConverters 类
import org.springframework.cloud.openfeign.support.SpringEncoder; // 导入 SpringEncoder 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
import org.springframework.context.annotation.Primary; // 导入 Primary 类
import org.springframework.context.annotation.Scope; // 导入 Scope 类
import org.springframework.http.MediaType; // 导入 MediaType 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import org.springframework.web.multipart.commons.CommonsMultipartFile; // 导入 CommonsMultipartFile 类
import java.io.File; // 导入 File 类
import java.io.FileInputStream; // 导入 FileInputStream 类
import java.io.OutputStream; // 导入 OutputStream 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2022/10/15 22:13 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
public class MultipartSupportConfig { // 定义 class MultipartSupportConfig
@Autowired // 使用注解 @Autowired
private ObjectFactory<HttpMessageConverters> messageConverters; // 执行语句
@Bean // 使用注解 @Bean
@Primary//注入相同类型的bean时优先使用 // 使用注解 @Primary
@Scope("prototype") // 使用注解 @Scope("prototype")
public Encoder feignEncoder() { // 定义方法 feignEncoder(...)
return new SpringFormEncoder(new SpringEncoder(messageConverters)); // 返回 new SpringFormEncoder(new SpringEncoder(messageConverters))
} // 代码块结束
//将file转为Multipart // 保留原作者写的行内注释
public static MultipartFile getMultipartFile(File file) { // 定义方法 getMultipartFile(...)
FileItem item = new DiskFileItemFactory().createItem("file", MediaType.MULTIPART_FORM_DATA_VALUE, true, file.getName()); // 创建 DiskFileItemFactory 对象并赋值给 item
try (FileInputStream inputStream = new FileInputStream(file); // 尝试执行可能抛出异常的代码
OutputStream outputStream = item.getOutputStream();) { // 定义方法 方法(...)
IOUtils.copy(inputStream, outputStream); // 执行语句
} catch (Exception e) { // 定义方法 catch(...)
e.printStackTrace(); // 执行语句
} // 代码块结束
return new CommonsMultipartFile(item); // 返回 new CommonsMultipartFile(item)
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/config/MybatisPlusConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import com.baomidou.mybatisplus.annotation.DbType; // 导入 DbType 类
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; // 导入 MybatisPlusInterceptor 类
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; // 导入 PaginationInnerInterceptor 类
import org.mybatis.spring.annotation.MapperScan; // 导入 MapperScan 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:23 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
@MapperScan("com.xuecheng.content.mapper") // 使用注解 @MapperScan("com.xuecheng.content.mapper")
public class MybatisPlusConfig { // 定义 class MybatisPlusConfig
/** // 保留原作者写的块注释
* 定义分页拦截器 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Bean // 使用注解 @Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() { // 定义方法 mybatisPlusInterceptor(...)
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 创建 MybatisPlusInterceptor 对象并赋值给 interceptor
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 执行语句
return interceptor; // 返回 interceptor
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/config/XxlJobConfig.java
package com.xuecheng.content.config; // 声明类所在的包路径
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; // 导入 XxlJobSpringExecutor 类
import org.slf4j.Logger; // 导入 Logger 类
import org.slf4j.LoggerFactory; // 导入 LoggerFactory 类
import org.springframework.beans.factory.annotation.Value; // 导入 Value 类
import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
/** // 保留原作者写的块注释
* xxl-job config // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author xuxueli 2017-04-28 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
public class XxlJobConfig { // 定义 class XxlJobConfig
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class); // 把 LoggerFactory.getLogger(XxlJobConfig.class) 赋值给 logger
@Value("${xxl.job.admin.addresses}") // 使用注解 @Value("${xxl.job.admin.addresses}")
private String adminAddresses; // 执行语句
@Value("${xxl.job.accessToken}") // 使用注解 @Value("${xxl.job.accessToken}")
private String accessToken; // 执行语句
@Value("${xxl.job.executor.appname}") // 使用注解 @Value("${xxl.job.executor.appname}")
private String appname; // 执行语句
@Value("${xxl.job.executor.address}") // 使用注解 @Value("${xxl.job.executor.address}")
private String address; // 执行语句
@Value("${xxl.job.executor.ip}") // 使用注解 @Value("${xxl.job.executor.ip}")
private String ip; // 执行语句
@Value("${xxl.job.executor.port}") // 使用注解 @Value("${xxl.job.executor.port}")
private int port; // 执行语句
@Value("${xxl.job.executor.logpath}") // 使用注解 @Value("${xxl.job.executor.logpath}")
private String logPath; // 执行语句
@Value("${xxl.job.executor.logretentiondays}") // 使用注解 @Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays; // 执行语句
@Bean // 使用注解 @Bean
public XxlJobSpringExecutor xxlJobExecutor() { // 定义方法 xxlJobExecutor(...)
logger.info(">>>>>>>>>>> xxl-job config init."); // 执行语句
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); // 创建 XxlJobSpringExecutor 对象并赋值给 xxlJobSpringExecutor
xxlJobSpringExecutor.setAdminAddresses(adminAddresses); // 执行语句
xxlJobSpringExecutor.setAppname(appname); // 执行语句
xxlJobSpringExecutor.setAddress(address); // 执行语句
xxlJobSpringExecutor.setIp(ip); // 执行语句
xxlJobSpringExecutor.setPort(port); // 执行语句
xxlJobSpringExecutor.setAccessToken(accessToken); // 执行语句
xxlJobSpringExecutor.setLogPath(logPath); // 执行语句
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays); // 执行语句
return xxlJobSpringExecutor; // 返回 xxlJobSpringExecutor
} // 代码块结束
/** // 保留原作者写的块注释
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP; // 保留原作者写的块注释
* // 保留原作者写的块注释
* 1、引入依赖: // 保留原作者写的块注释
* <dependency> // 保留原作者写的块注释
* <groupId>org.springframework.cloud</groupId> // 保留原作者写的块注释
* <artifactId>spring-cloud-commons</artifactId> // 保留原作者写的块注释
* <version>${version}</version> // 保留原作者写的块注释
* </dependency> // 保留原作者写的块注释
* // 保留原作者写的块注释
* 2、配置文件,或者容器启动变量 // 保留原作者写的块注释
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.' // 保留原作者写的块注释
* // 保留原作者写的块注释
* 3、获取IP // 保留原作者写的块注释
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); // 保留原作者写的块注释
*/ // 保留原作者写的块注释
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/feignclient/CourseIndex.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import com.alibaba.fastjson.annotation.JSONField; // 导入 JSONField 类
import com.fasterxml.jackson.annotation.JsonFormat; // 导入 JsonFormat 类
import lombok.Data; // 导入 Data 类
import java.io.Serializable; // 导入 Serializable 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程索引信息 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Data // 使用注解 @Data
public class CourseIndex implements Serializable { // 定义 class CourseIndex
private static final long serialVersionUID = 1L; // 把 1L 赋值给 serialVersionUID
/** // 保留原作者写的块注释
* 主键 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long id; // 执行语句
/** // 保留原作者写的块注释
* 机构ID // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Long companyId; // 执行语句
/** // 保留原作者写的块注释
* 公司名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String companyName; // 执行语句
/** // 保留原作者写的块注释
* 课程名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String name; // 执行语句
/** // 保留原作者写的块注释
* 适用人群 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String users; // 执行语句
/** // 保留原作者写的块注释
* 标签 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String tags; // 执行语句
/** // 保留原作者写的块注释
* 大分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mt; // 执行语句
/** // 保留原作者写的块注释
* 大分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String mtName; // 执行语句
/** // 保留原作者写的块注释
* 小分类 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String st; // 执行语句
/** // 保留原作者写的块注释
* 小分类名称 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String stName; // 执行语句
/** // 保留原作者写的块注释
* 课程等级 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String grade; // 执行语句
/** // 保留原作者写的块注释
* 教育模式 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String teachmode; // 执行语句
/** // 保留原作者写的块注释
* 课程图片 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String pic; // 执行语句
/** // 保留原作者写的块注释
* 课程介绍 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String description; // 执行语句
/** // 保留原作者写的块注释
* 发布时间 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@JSONField(format="yyyy-MM-dd HH:mm:ss") // 使用注解 @JSONField(format="yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 使用注解 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate; // 执行语句
/** // 保留原作者写的块注释
* 状态 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String status; // 执行语句
/** // 保留原作者写的块注释
* 备注 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String remark; // 执行语句
/** // 保留原作者写的块注释
* 收费规则,对应数据字典--203 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private String charge; // 执行语句
/** // 保留原作者写的块注释
* 现价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float price; // 执行语句
/** // 保留原作者写的块注释
* 原价 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Float originalPrice; // 执行语句
/** // 保留原作者写的块注释
* 课程有效期天数 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private Integer validDays; // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/feignclient/MediaServiceClient.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import com.xuecheng.content.config.MultipartSupportConfig; // 导入 MultipartSupportConfig 类
import org.springframework.cloud.openfeign.FeignClient; // 导入 FeignClient 类
import org.springframework.http.MediaType; // 导入 MediaType 类
import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 类
import org.springframework.web.bind.annotation.RequestParam; // 导入 RequestParam 类
import org.springframework.web.bind.annotation.RequestPart; // 导入 RequestPart 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.IOException; // 导入 IOException 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 远程调用媒资服务的接口 // 保留原作者写的块注释
* @date 2023/2/22 10:26 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
//使用fallback定义降级类是无法拿到熔断异常,使用FallbackFactory可以拿到熔断的异常信息 // 保留原作者写的行内注释
@FeignClient(value = "media-api",configuration = {MultipartSupportConfig.class},fallbackFactory = MediaServiceClientFallbackFactory.class) // 使用注解 @FeignClient(value = "media-api",configuration = {MultipartSupportConfig.class},fallbackFactory = MediaServiceClientFallbackFactory.class)
public interface MediaServiceClient { // 定义 interface MediaServiceClient
@RequestMapping(value = "/media/upload/coursefile",consumes = MediaType.MULTIPART_FORM_DATA_VALUE) // 使用注解 @RequestMapping(value = "/media/upload/coursefile",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String upload(@RequestPart("filedata") MultipartFile filedata, // 代码逻辑
@RequestParam(value= "objectName",required=false) String objectName) throws IOException; // 使用注解 @RequestParam(value= "objectName",required=false) String objectName) throws IOException;
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/feignclient/MediaServiceClientFallback.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.IOException; // 导入 IOException 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/22 11:06 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public class MediaServiceClientFallback implements MediaServiceClient{ // 定义 class MediaServiceClientFallback
@Override // 使用注解 @Override
public String upload(MultipartFile filedata, String objectName) throws IOException { // 定义方法 upload(...)
return null; // 返回 null
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/feignclient/MediaServiceClientFallbackFactory.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import feign.hystrix.FallbackFactory; // 导入 FallbackFactory 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.stereotype.Component; // 导入 Component 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.IOException; // 导入 IOException 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/22 11:09 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class MediaServiceClientFallbackFactory implements FallbackFactory<MediaServiceClient> { // 定义 class MediaServiceClientFallbackFactory
//拿到了熔断的异常信息throwable // 保留原作者写的行内注释
@Override // 使用注解 @Override
public MediaServiceClient create(Throwable throwable) { // 定义方法 create(...)
return new MediaServiceClient() { // 定义方法 MediaServiceClient(...)
//发生熔断上传服务调用此方法执行降级逻辑 // 保留原作者写的行内注释
@Override // 使用注解 @Override
public String upload(MultipartFile filedata, String objectName) throws IOException { // 定义方法 upload(...)
log.debug("远程调用上传文件的接口发生熔断:{}",throwable.toString(),throwable); // 执行语句
return null; // 返回 null
} // 代码块结束
}; // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/feignclient/SearchServiceClient.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import org.springframework.cloud.openfeign.FeignClient; // 导入 FeignClient 类
import org.springframework.web.bind.annotation.PostMapping; // 导入 PostMapping 类
import org.springframework.web.bind.annotation.RequestBody; // 导入 RequestBody 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/22 14:47 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@FeignClient(value = "search",fallbackFactory = SearchServiceClientFallbackFactory.class) // 使用注解 @FeignClient(value = "search",fallbackFactory = SearchServiceClientFallbackFactory.class)
public interface SearchServiceClient { // 定义 interface SearchServiceClient
@PostMapping("/search/index/course") // 使用注解 @PostMapping("/search/index/course")
public Boolean add(@RequestBody CourseIndex courseIndex); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/feignclient/SearchServiceClientFallbackFactory.java
package com.xuecheng.content.feignclient; // 声明类所在的包路径
import feign.hystrix.FallbackFactory; // 导入 FallbackFactory 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.stereotype.Component; // 导入 Component 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/22 14:50 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class SearchServiceClientFallbackFactory implements FallbackFactory<SearchServiceClient> { // 定义 class SearchServiceClientFallbackFactory
@Override // 使用注解 @Override
public SearchServiceClient create(Throwable throwable) { // 定义方法 create(...)
return new SearchServiceClient() { // 定义方法 SearchServiceClient(...)
@Override // 使用注解 @Override
public Boolean add(CourseIndex courseIndex) { // 定义方法 add(...)
log.error("添加课程索引发生熔断,索引信息:{},熔断异常:{}",courseIndex,throwable.toString(),throwable); // 执行语句
//走降级了返回 false // 保留原作者写的行内注释
return false; // 返回 false
} // 代码块结束
}; // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CourseBaseMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程基本信息 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
// 课程预览使用的dao层 // 保留原作者写的行内注释
public interface CourseBaseMapper extends BaseMapper<CourseBase> { // 定义 interface CourseBaseMapper
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CourseBaseMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CourseBaseMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CourseBase"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
<result column="company_name" property="companyName" /> <!-- 字段与属性的映射规则 -->
<result column="name" property="name" /> <!-- 字段与属性的映射规则 -->
<result column="users" property="users" /> <!-- 字段与属性的映射规则 -->
<result column="tags" property="tags" /> <!-- 字段与属性的映射规则 -->
<result column="mt" property="mt" /> <!-- 字段与属性的映射规则 -->
<result column="st" property="st" /> <!-- 字段与属性的映射规则 -->
<result column="grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="teachmode" property="teachmode" /> <!-- 字段与属性的映射规则 -->
<result column="description" property="description" /> <!-- 字段与属性的映射规则 -->
<result column="pic" property="pic" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="change_date" property="changeDate" /> <!-- 字段与属性的映射规则 -->
<result column="create_people" property="createPeople" /> <!-- 字段与属性的映射规则 -->
<result column="change_people" property="changePeople" /> <!-- 字段与属性的映射规则 -->
<result column="audit_status" property="auditStatus" /> <!-- 字段与属性的映射规则 -->
<result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, company_id, company_name, name, users, tags, mt, st, grade, teachmode, description, pic, create_date, change_date, create_people, change_people, audit_status, status <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CourseCategoryMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.model.po.CourseCategory; // 导入 CourseCategory 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程分类 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseCategoryMapper extends BaseMapper<CourseCategory> { // 定义 interface CourseCategoryMapper
//使用递归查询分类 // 保留原作者写的行内注释
public List<CourseCategoryTreeDto> selectTreeNodes(String id); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CourseCategoryMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CourseCategoryMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CourseCategory"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="name" property="name" /> <!-- 字段与属性的映射规则 -->
<result column="label" property="label" /> <!-- 字段与属性的映射规则 -->
<result column="parentid" property="parentid" /> <!-- 字段与属性的映射规则 -->
<result column="is_show" property="isShow" /> <!-- 字段与属性的映射规则 -->
<result column="orderby" property="orderby" /> <!-- 字段与属性的映射规则 -->
<result column="is_leaf" property="isLeaf" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, name, label, parentid, is_show, orderby, is_leaf <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
<select id="selectTreeNodes" parameterType="string" resultType="com.xuecheng.content.model.dto.CourseCategoryTreeDto"> <!-- 定义 select 查询语句 -->
with recursive t1 as ( <!-- SQL 语句片段 -->
select * from course_category where id=#{id} <!-- 占位符参数 -->
union all <!-- SQL 语句片段 -->
select t2.* from course_category t2 inner join t1 on t1.id = t2.parentid <!-- SQL 语句片段 -->
) <!-- SQL 语句片段 -->
select * from t1 <!-- SQL 语句片段 -->
order by t1.id <!-- SQL 语句片段 -->
</select> <!-- SQL 语句片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CourseMarketMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CourseMarket; // 导入 CourseMarket 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程营销信息 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseMarketMapper extends BaseMapper<CourseMarket> { // 定义 interface CourseMarketMapper
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CourseMarketMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CourseMarketMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CourseMarket"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="charge" property="charge" /> <!-- 字段与属性的映射规则 -->
<result column="price" property="price" /> <!-- 字段与属性的映射规则 -->
<result column="original_price" property="originalPrice" /> <!-- 字段与属性的映射规则 -->
<result column="qq" property="qq" /> <!-- 字段与属性的映射规则 -->
<result column="wechat" property="wechat" /> <!-- 字段与属性的映射规则 -->
<result column="phone" property="phone" /> <!-- 字段与属性的映射规则 -->
<result column="valid_days" property="validDays" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, charge, price, original_price, qq, wechat, phone, valid_days <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CoursePublishMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程发布 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CoursePublishMapper extends BaseMapper<CoursePublish> { // 定义 interface CoursePublishMapper
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CoursePublishMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CoursePublishMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CoursePublish"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
<result column="company_name" property="companyName" /> <!-- 字段与属性的映射规则 -->
<result column="name" property="name" /> <!-- 字段与属性的映射规则 -->
<result column="users" property="users" /> <!-- 字段与属性的映射规则 -->
<result column="tags" property="tags" /> <!-- 字段与属性的映射规则 -->
<result column="username" property="username" /> <!-- 字段与属性的映射规则 -->
<result column="mt" property="mt" /> <!-- 字段与属性的映射规则 -->
<result column="mt_name" property="mtName" /> <!-- 字段与属性的映射规则 -->
<result column="st" property="st" /> <!-- 字段与属性的映射规则 -->
<result column="st_name" property="stName" /> <!-- 字段与属性的映射规则 -->
<result column="grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="teachmode" property="teachmode" /> <!-- 字段与属性的映射规则 -->
<result column="pic" property="pic" /> <!-- 字段与属性的映射规则 -->
<result column="description" property="description" /> <!-- 字段与属性的映射规则 -->
<result column="market" property="market" /> <!-- 字段与属性的映射规则 -->
<result column="teachplan" property="teachplan" /> <!-- 字段与属性的映射规则 -->
<result column="teachers" property="teachers" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="online_date" property="onlineDate" /> <!-- 字段与属性的映射规则 -->
<result column="offline_date" property="offlineDate" /> <!-- 字段与属性的映射规则 -->
<result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
<result column="remark" property="remark" /> <!-- 字段与属性的映射规则 -->
<result column="charge" property="charge" /> <!-- 字段与属性的映射规则 -->
<result column="price" property="price" /> <!-- 字段与属性的映射规则 -->
<result column="original_price" property="originalPrice" /> <!-- 字段与属性的映射规则 -->
<result column="valid_days" property="validDays" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, company_id, company_name, name, users, tags, username, mt, mt_name, st, st_name, grade, teachmode, pic, description, market, teachplan, teachers, create_date, online_date, offline_date, status, remark, charge, price, original_price, valid_days <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CoursePublishPreMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CoursePublishPre; // 导入 CoursePublishPre 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程发布 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CoursePublishPreMapper extends BaseMapper<CoursePublishPre> { // 定义 interface CoursePublishPreMapper
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CoursePublishPreMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CoursePublishPreMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CoursePublishPre"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
<result column="company_name" property="companyName" /> <!-- 字段与属性的映射规则 -->
<result column="name" property="name" /> <!-- 字段与属性的映射规则 -->
<result column="users" property="users" /> <!-- 字段与属性的映射规则 -->
<result column="tags" property="tags" /> <!-- 字段与属性的映射规则 -->
<result column="username" property="username" /> <!-- 字段与属性的映射规则 -->
<result column="mt" property="mt" /> <!-- 字段与属性的映射规则 -->
<result column="mt_name" property="mtName" /> <!-- 字段与属性的映射规则 -->
<result column="st" property="st" /> <!-- 字段与属性的映射规则 -->
<result column="st_name" property="stName" /> <!-- 字段与属性的映射规则 -->
<result column="grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="teachmode" property="teachmode" /> <!-- 字段与属性的映射规则 -->
<result column="pic" property="pic" /> <!-- 字段与属性的映射规则 -->
<result column="description" property="description" /> <!-- 字段与属性的映射规则 -->
<result column="market" property="market" /> <!-- 字段与属性的映射规则 -->
<result column="teachplan" property="teachplan" /> <!-- 字段与属性的映射规则 -->
<result column="teachers" property="teachers" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="audit_date" property="auditDate" /> <!-- 字段与属性的映射规则 -->
<result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
<result column="remark" property="remark" /> <!-- 字段与属性的映射规则 -->
<result column="charge" property="charge" /> <!-- 字段与属性的映射规则 -->
<result column="price" property="price" /> <!-- 字段与属性的映射规则 -->
<result column="original_price" property="originalPrice" /> <!-- 字段与属性的映射规则 -->
<result column="valid_days" property="validDays" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, company_id, company_name, name, users, tags, username, mt, mt_name, st, st_name, grade, teachmode, pic, description, market, teachplan, teachers, create_date, audit_date, status, remark, charge, price, original_price, valid_days <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CourseTeacherMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.CourseTeacher; // 导入 CourseTeacher 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程-教师关系表 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseTeacherMapper extends BaseMapper<CourseTeacher> { // 定义 interface CourseTeacherMapper
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/CourseTeacherMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.CourseTeacherMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.CourseTeacher"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="teacher_name" property="teacherName" /> <!-- 字段与属性的映射规则 -->
<result column="position" property="position" /> <!-- 字段与属性的映射规则 -->
<result column="introduction" property="introduction" /> <!-- 字段与属性的映射规则 -->
<result column="photograph" property="photograph" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, course_id, teacher_name, position, introduction, photograph, create_date <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/TeachplanMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.model.po.Teachplan; // 导入 Teachplan 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* 课程计划 Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface TeachplanMapper extends BaseMapper<Teachplan> { // 定义 interface TeachplanMapper
//课程计划查询 // 保留原作者写的行内注释
public List<TeachplanDto> selectTreeNodes(Long courseId); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/TeachplanMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.TeachplanMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.Teachplan"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="pname" property="pname" /> <!-- 字段与属性的映射规则 -->
<result column="parentid" property="parentid" /> <!-- 字段与属性的映射规则 -->
<result column="grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="media_type" property="mediaType" /> <!-- 字段与属性的映射规则 -->
<result column="start_time" property="startTime" /> <!-- 字段与属性的映射规则 -->
<result column="end_time" property="endTime" /> <!-- 字段与属性的映射规则 -->
<result column="description" property="description" /> <!-- 字段与属性的映射规则 -->
<result column="timelength" property="timelength" /> <!-- 字段与属性的映射规则 -->
<result column="orderby" property="orderby" /> <!-- 字段与属性的映射规则 -->
<result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="course_pub_id" property="coursePubId" /> <!-- 字段与属性的映射规则 -->
<result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
<result column="is_preview" property="isPreview" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="change_date" property="changeDate" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, pname, parentid, grade, media_type, start_time, end_time, description, timelength, orderby, course_id, course_pub_id, status, is_preview, create_date, change_date <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
<resultMap id="treeNodeResultMap" type="com.xuecheng.content.model.dto.TeachplanDto"> <!-- 定义结果映射 -->
<id column="one_id" property="id" /> <!-- 主键列的映射规则 -->
<result column="one_pname" property="pname" /> <!-- 字段与属性的映射规则 -->
<result column="one_parentid" property="parentid" /> <!-- 字段与属性的映射规则 -->
<result column="one_grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="one_mediaType" property="mediaType" /> <!-- 字段与属性的映射规则 -->
<result column="one_stratTime" property="stratTime" /> <!-- 字段与属性的映射规则 -->
<result column="one_endTime" property="endTime" /> <!-- 字段与属性的映射规则 -->
<result column="one_orderby" property="orderby" /> <!-- 字段与属性的映射规则 -->
<result column="one_courseId" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="one_coursePubId" property="coursePubId" /> <!-- 字段与属性的映射规则 -->
<!--映射子节点,一对多映射,ofType list中的对象类型-->
<collection property="teachPlanTreeNodes" ofType="com.xuecheng.content.model.dto.TeachplanDto"> <!-- SQL 语句片段 -->
<id column="two_id" property="id" /> <!-- 主键列的映射规则 -->
<result column="two_pname" property="pname" /> <!-- 字段与属性的映射规则 -->
<result column="two_parentid" property="parentid" /> <!-- 字段与属性的映射规则 -->
<result column="two_grade" property="grade" /> <!-- 字段与属性的映射规则 -->
<result column="two_mediaType" property="mediaType" /> <!-- 字段与属性的映射规则 -->
<result column="two_stratTime" property="stratTime" /> <!-- 字段与属性的映射规则 -->
<result column="two_endTime" property="endTime" /> <!-- 字段与属性的映射规则 -->
<result column="two_orderby" property="orderby" /> <!-- 字段与属性的映射规则 -->
<result column="two_courseId" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="two_coursePubId" property="coursePubId" /> <!-- 字段与属性的映射规则 -->
<!--一对一映射-->
<association property="teachplanMedia" javaType="com.xuecheng.content.model.po.TeachplanMedia"> <!-- SQL 语句片段 -->
<id column="teachplanMeidaId" property="id"/> <!-- 主键列的映射规则 -->
<result column="mediaFilename" property="mediaFilename"/> <!-- 字段与属性的映射规则 -->
<result column="mediaId" property="mediaId"/> <!-- 字段与属性的映射规则 -->
</association> <!-- SQL 语句片段 -->
</collection> <!-- SQL 语句片段 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<select id="selectTreeNodes" parameterType="long" resultMap="treeNodeResultMap"> <!-- 定义 select 查询语句 -->
select <!-- SQL 语句片段 -->
one.id one_id, <!-- SQL 语句片段 -->
one.pname one_pname, <!-- SQL 语句片段 -->
one.parentid one_parentid, <!-- SQL 语句片段 -->
one.grade one_grade, <!-- SQL 语句片段 -->
one.media_type one_mediaType, <!-- SQL 语句片段 -->
one.start_time one_stratTime, <!-- SQL 语句片段 -->
one.end_time one_endTime, <!-- SQL 语句片段 -->
one.orderby one_orderby, <!-- SQL 语句片段 -->
one.course_id one_courseId, <!-- SQL 语句片段 -->
one.course_pub_id one_coursePubId, <!-- SQL 语句片段 -->
two.id two_id, <!-- SQL 语句片段 -->
two.pname two_pname, <!-- SQL 语句片段 -->
two.parentid two_parentid, <!-- SQL 语句片段 -->
two.grade two_grade, <!-- SQL 语句片段 -->
two.media_type two_mediaType, <!-- SQL 语句片段 -->
two.start_time two_stratTime, <!-- SQL 语句片段 -->
two.end_time two_endTime, <!-- SQL 语句片段 -->
two.orderby two_orderby, <!-- SQL 语句片段 -->
two.course_id two_courseId, <!-- SQL 语句片段 -->
two.course_pub_id two_coursePubId, <!-- SQL 语句片段 -->
m1.media_fileName mediaFilename, <!-- SQL 语句片段 -->
m1.id teachplanMeidaId, <!-- SQL 语句片段 -->
m1.media_id mediaId <!-- SQL 语句片段 -->
from teachplan one <!-- SQL 语句片段 -->
left join teachplan two on two.parentid = one.id <!-- SQL 语句片段 -->
left join teachplan_media m1 on two.id = m1.teachplan_id <!-- SQL 语句片段 -->
where one.parentid = 0 <!-- SQL 语句片段 -->
and one.course_id = #{id} <!-- 占位符参数 -->
order by one.orderby,two.orderby <!-- SQL 语句片段 -->
</select> <!-- SQL 语句片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/TeachplanMediaMapper.java
package com.xuecheng.content.mapper; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.content.model.po.TeachplanMedia; // 导入 TeachplanMedia 类
/** // 保留原作者写的块注释
* <p> // 保留原作者写的块注释
* Mapper 接口 // 保留原作者写的块注释
* </p> // 保留原作者写的块注释
* // 保留原作者写的块注释
* @author itcast // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface TeachplanMediaMapper extends BaseMapper<TeachplanMedia> { // 定义 interface TeachplanMediaMapper
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/mapper/TeachplanMediaMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- SQL 语句片段 -->
<mapper namespace="com.xuecheng.content.mapper.TeachplanMediaMapper"> <!-- MyBatis 映射文件的根标签 -->
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xuecheng.content.model.po.TeachplanMedia"> <!-- 定义结果映射 -->
<id column="id" property="id" /> <!-- 主键列的映射规则 -->
<result column="media_id" property="mediaId" /> <!-- 字段与属性的映射规则 -->
<result column="teachplan_id" property="teachplanId" /> <!-- 字段与属性的映射规则 -->
<result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
<result column="media_fileName" property="mediaFilename" /> <!-- 字段与属性的映射规则 -->
<result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
<result column="create_people" property="createPeople" /> <!-- 字段与属性的映射规则 -->
<result column="change_people" property="changePeople" /> <!-- 字段与属性的映射规则 -->
</resultMap> <!-- 结束 resultMap 区块 -->
<!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
id, media_id, teachplan_id, course_id, media_fileName, create_date, create_people, change_people <!-- SQL 语句片段 -->
</sql> <!-- 结束 SQL 片段 -->
</mapper> <!-- 结束 mapper 标签 -->
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/service/CourseBaseInfoService.java
package com.xuecheng.content.service; // 声明类所在的包路径
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.model.dto.AddCourseDto; // 导入 AddCourseDto 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.EditCourseDto; // 导入 EditCourseDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程信息管理接口 // 保留原作者写的块注释
* @date 2023/2/12 10:14 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseBaseInfoService { // 定义 interface CourseBaseInfoService
/** // 保留原作者写的块注释
* 课程分页查询 // 保留原作者写的块注释
* @param pageParams 分页查询参数 // 保留原作者写的块注释
* @param courseParamsDto 查询条件 // 保留原作者写的块注释
* @param companyId 培训机构id // 保留原作者写的块注释
* @return 查询结果 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public PageResult<CourseBase> queryCourseBaseList(Long companyId,PageParams pageParams, QueryCourseParamsDto courseParamsDto); // 执行语句
/** // 保留原作者写的块注释
* 新增课程 // 保留原作者写的块注释
* @param companyId 机构id // 保留原作者写的块注释
* @param addCourseDto 课程信息 // 保留原作者写的块注释
* @return 课程详细信息 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CourseBaseInfoDto createCourseBase(Long companyId,AddCourseDto addCourseDto); // 执行语句
/** // 保留原作者写的块注释
* 根据课程id查询课程信息 // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return 课程详细信息 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CourseBaseInfoDto getCourseBaseInfo(Long courseId); // 执行语句
/** // 保留原作者写的块注释
* 修改课程 // 保留原作者写的块注释
* @param companyId 机构id // 保留原作者写的块注释
* @param editCourseDto 修改课程信息 // 保留原作者写的块注释
* @return 课程详细信息 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CourseBaseInfoDto updateCourseBase(Long companyId,EditCourseDto editCourseDto); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/service/CourseCategoryService.java
package com.xuecheng.content.service; // 声明类所在的包路径
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 14:49 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CourseCategoryService { // 定义 interface CourseCategoryService
/** // 保留原作者写的块注释
* 课程分类树形结构查询 // 保留原作者写的块注释
* // 保留原作者写的块注释
* @return // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public List<CourseCategoryTreeDto> queryTreeNodes(String id); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/service/CoursePublishService.java
package com.xuecheng.content.service; // 声明类所在的包路径
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import java.io.File; // 导入 File 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程发布相关的接口 // 保留原作者写的块注释
* @date 2023/2/21 10:03 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface CoursePublishService { // 定义 interface CoursePublishService
/** // 保留原作者写的块注释
* @description 获取课程预览信息 // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return com.xuecheng.content.model.dto.CoursePreviewDto // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/16 15:36 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
// service接口层只关注业务 // 保留原作者写的行内注释
// controller层和service层的联系是controller层调用service实现类 // 保留原作者写的行内注释
public CoursePreviewDto getCoursePreviewInfo(Long courseId); // 执行语句
/** // 保留原作者写的块注释
* @description 提交审核 // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return void // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/18 10:31 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void commitAudit(Long companyId,Long courseId); // 执行语句
/** // 保留原作者写的块注释
* @description 课程发布接口 // 保留原作者写的块注释
* @param companyId 机构id // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return void // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/20 16:23 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void publish(Long companyId,Long courseId); // 执行语句
/** // 保留原作者写的块注释
* @description 课程静态化 // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return File 静态化文件 // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/23 16:59 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public File generateCourseHtml(Long courseId); // 执行语句
/** // 保留原作者写的块注释
* @description 上传课程静态化页面 // 保留原作者写的块注释
* @param file 静态化文件 // 保留原作者写的块注释
* @return void // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/23 16:59 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void uploadCourseHtml(Long courseId, File file); // 执行语句
/** // 保留原作者写的块注释
* 根据课程 id查询课程发布信息 // 保留原作者写的块注释
* @param courseId // 保留原作者写的块注释
* @return // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CoursePublish getCoursePublish(Long courseId); // 执行语句
public CoursePublish getCoursePublishCache(Long courseId); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/service/impl/CourseBaseInfoServiceImpl.java
package com.xuecheng.content.service.impl; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 Page 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.mapper.CourseCategoryMapper; // 导入 CourseCategoryMapper 类
import com.xuecheng.content.mapper.CourseMarketMapper; // 导入 CourseMarketMapper 类
import com.xuecheng.content.model.dto.AddCourseDto; // 导入 AddCourseDto 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.EditCourseDto; // 导入 EditCourseDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.model.po.CourseCategory; // 导入 CourseCategory 类
import com.xuecheng.content.model.po.CourseMarket; // 导入 CourseMarket 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类
import org.springframework.transaction.annotation.Transactional; // 导入 Transactional 类
import javax.annotation.Resources; // 导入 Resources 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 10:16 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class CourseBaseInfoServiceImpl implements CourseBaseInfoService { // 定义 class CourseBaseInfoServiceImpl
@Autowired // 使用注解 @Autowired
CourseBaseMapper courseBaseMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CourseMarketMapper courseMarketMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CourseCategoryMapper courseCategoryMapper; // 执行语句
@Override // 使用注解 @Override
public PageResult<CourseBase> queryCourseBaseList(Long companyId,PageParams pageParams, QueryCourseParamsDto courseParamsDto) { // 定义方法 queryCourseBaseList(...)
//拼装查询条件 // 保留原作者写的行内注释
LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>(); // 创建 LambdaQueryWrapper<> 对象并赋值给 queryWrapper
//根据名称模糊查询,在sql中拼接 course_base.name like '%值%' // 保留原作者写的行内注释
queryWrapper.like(StringUtils.isNotEmpty(courseParamsDto.getCourseName()),CourseBase::getName,courseParamsDto.getCourseName()); // 执行语句
//根据课程审核状态查询 course_base.audit_status = ? // 保留原作者写的行内注释
queryWrapper.eq(StringUtils.isNotEmpty(courseParamsDto.getAuditStatus()), CourseBase::getAuditStatus,courseParamsDto.getAuditStatus()); // 执行语句
//todo:按课程发布状态查询 // 保留原作者写的行内注释
//根据培训机构id拼装查询条件 // 保留原作者写的行内注释
queryWrapper.eq(CourseBase::getCompanyId,companyId); // 执行语句
//创建page分页参数对象,参数:当前页码,每页记录数 // 保留原作者写的行内注释
Page<CourseBase> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize()); // 创建 Page<> 对象并赋值给 page
//开始进行分页查询 // 保留原作者写的行内注释
Page<CourseBase> pageResult = courseBaseMapper.selectPage(page, queryWrapper); // 把 courseBaseMapper.selectPage(page, queryWrapper) 赋值给 pageResult
//数据列表 // 保留原作者写的行内注释
List<CourseBase> items = pageResult.getRecords(); // 把 pageResult.getRecords() 的返回值赋给 items
//总记录数 // 保留原作者写的行内注释
long total = pageResult.getTotal(); // 把 pageResult.getTotal() 的返回值赋给 total
//List<T> items, long counts, long page, long pageSize // 保留原作者写的行内注释
PageResult<CourseBase> courseBasePageResult = new PageResult<CourseBase>(items,total,pageParams.getPageNo(), pageParams.getPageSize()); // 创建 PageResult<CourseBase> 对象并赋值给 courseBasePageResult
return courseBasePageResult; // 返回 courseBasePageResult
} // 代码块结束
@Transactional // 使用注解 @Transactional
@Override // 使用注解 @Override
public CourseBaseInfoDto createCourseBase(Long companyId, AddCourseDto dto){ // 定义方法 createCourseBase(...)
//参数的合法性校验 // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getName())) { // 保留原作者写的行内注释
//// throw new RuntimeException("课程名称为空"); // 保留原作者写的行内注释
// XueChengPlusException.cast("课程名称为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getMt())) { // 保留原作者写的行内注释
// throw new RuntimeException("课程分类为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getSt())) { // 保留原作者写的行内注释
// throw new RuntimeException("课程分类为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getGrade())) { // 保留原作者写的行内注释
// throw new RuntimeException("课程等级为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getTeachmode())) { // 保留原作者写的行内注释
// throw new RuntimeException("教育模式为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getUsers())) { // 保留原作者写的行内注释
// throw new RuntimeException("适应人群为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// if (StringUtils.isBlank(dto.getCharge())) { // 保留原作者写的行内注释
// throw new RuntimeException("收费规则为空"); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
//向课程基本信息表course_base写入数据 // 保留原作者写的行内注释
CourseBase courseBaseNew = new CourseBase(); // 创建 CourseBase 对象并赋值给 courseBaseNew
//将传入的页面的参数放到courseBaseNew对象 // 保留原作者写的行内注释
// courseBaseNew.setName(dto.getName()); // 保留原作者写的行内注释
// courseBaseNew.setDescription(dto.getDescription()); // 保留原作者写的行内注释
//上边的从原始对象中get拿数据向新对象set,比较复杂 // 保留原作者写的行内注释
BeanUtils.copyProperties(dto,courseBaseNew);//只要属性名称一致就可以拷贝 // 执行语句
courseBaseNew.setCompanyId(companyId); // 执行语句
courseBaseNew.setCreateDate(LocalDateTime.now()); // 执行语句
//审核状态默认为未提交 // 保留原作者写的行内注释
courseBaseNew.setAuditStatus("202002"); // 执行语句
//发布状态为未发布 // 保留原作者写的行内注释
courseBaseNew.setStatus("203001"); // 执行语句
//插入数据库 // 保留原作者写的行内注释
int insert = courseBaseMapper.insert(courseBaseNew); // 把 courseBaseMapper.insert(courseBaseNew) 赋值给 insert
if(insert<=0){ // 定义方法 方法(...)
throw new RuntimeException("添加课程失败"); // 主动抛出异常
} // 代码块结束
//向课程营销系courese_market写入数据 // 保留原作者写的行内注释
CourseMarket courseMarketNew = new CourseMarket(); // 创建 CourseMarket 对象并赋值给 courseMarketNew
//将页面输入的数据拷贝到courseMarketNew // 保留原作者写的行内注释
BeanUtils.copyProperties(dto,courseMarketNew); // 执行语句
//课程的id // 保留原作者写的行内注释
Long courseId = courseBaseNew.getId(); // 把 courseBaseNew.getId() 的返回值赋给 courseId
courseMarketNew.setId(courseId); // 执行语句
//保存营销信息 // 保留原作者写的行内注释
saveCourseMarket(courseMarketNew); // 执行语句
//从数据库查询课程的详细信息,包括两部分 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfo = getCourseBaseInfo(courseId); // 把 getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
return courseBaseInfo; // 返回 courseBaseInfo
} // 代码块结束
//查询课程信息 // 保留原作者写的行内注释
public CourseBaseInfoDto getCourseBaseInfo(Long courseId){ // 定义方法 getCourseBaseInfo(...)
//从课程基本信息表查询 // 保留原作者写的行内注释
CourseBase courseBase = courseBaseMapper.selectById(courseId); // 把 courseBaseMapper.selectById(courseId) 赋值给 courseBase
if(courseBase==null){ // 定义方法 方法(...)
return null; // 返回 null
} // 代码块结束
//从课程营销表查询 // 保留原作者写的行内注释
CourseMarket courseMarket = courseMarketMapper.selectById(courseId); // 把 courseMarketMapper.selectById(courseId) 赋值给 courseMarket
//组装在一起 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfoDto = new CourseBaseInfoDto(); // 创建 CourseBaseInfoDto 对象并赋值给 courseBaseInfoDto
BeanUtils.copyProperties(courseBase,courseBaseInfoDto); // 执行语句
if(courseMarket!=null){ // 定义方法 方法(...)
BeanUtils.copyProperties(courseMarket,courseBaseInfoDto); // 执行语句
} // 代码块结束
//通过courseCategoryMapper查询分类信息,将分类名称放在courseBaseInfoDto对象 // 保留原作者写的行内注释
CourseCategory mtObj = courseCategoryMapper.selectById(courseBase.getMt()); // 把 courseCategoryMapper.selectById(courseBase.getMt()) 赋值给 mtObj
String mtName = mtObj.getName();//大分类名称 // 把 mtObj.getName() 的返回值赋给 mtName
courseBaseInfoDto.setMtName(mtName); // 执行语句
CourseCategory stObj = courseCategoryMapper.selectById(courseBase.getSt()); // 把 courseCategoryMapper.selectById(courseBase.getSt()) 赋值给 stObj
String stName = stObj.getName();//小分类名称 // 把 stObj.getName() 的返回值赋给 stName
courseBaseInfoDto.setStName(stName); // 执行语句
return courseBaseInfoDto; // 返回 courseBaseInfoDto
} // 代码块结束
@Override // 使用注解 @Override
public CourseBaseInfoDto updateCourseBase(Long companyId, EditCourseDto editCourseDto) { // 定义方法 updateCourseBase(...)
//拿到课程id // 保留原作者写的行内注释
Long courseId = editCourseDto.getId(); // 把 editCourseDto.getId() 的返回值赋给 courseId
//查询课程信息 // 保留原作者写的行内注释
CourseBase courseBase = courseBaseMapper.selectById(courseId); // 把 courseBaseMapper.selectById(courseId) 赋值给 courseBase
if(courseBase == null){ // 定义方法 方法(...)
XueChengPlusException.cast("课程不存在"); // 执行语句
} // 代码块结束
//数据合法性校验 // 保留原作者写的行内注释
//根据具体的业务逻辑去校验 // 保留原作者写的行内注释
//本机构只能修改本机构的课程 // 保留原作者写的行内注释
if(!companyId.equals(courseBase.getCompanyId())){ // 定义方法 方法(...)
XueChengPlusException.cast("本机构只能修改本机构的课程"); // 执行语句
} // 代码块结束
//封装数据 // 保留原作者写的行内注释
BeanUtils.copyProperties(editCourseDto,courseBase); // 执行语句
//修改时间 // 保留原作者写的行内注释
courseBase.setChangeDate(LocalDateTime.now()); // 执行语句
//更新数据库 // 保留原作者写的行内注释
int i = courseBaseMapper.updateById(courseBase); // 把 courseBaseMapper.updateById(courseBase) 赋值给 i
if(i<=0){ // 定义方法 方法(...)
XueChengPlusException.cast("修改课程失败"); // 执行语句
} // 代码块结束
//更新营销信息 // 保留原作者写的行内注释
CourseMarket courseMarket = new CourseMarket(); // 创建 CourseMarket 对象并赋值给 courseMarket
BeanUtils.copyProperties(editCourseDto,courseMarket); // 执行语句
saveCourseMarket(courseMarket); // 执行语句
//查询课程信息 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfo = getCourseBaseInfo(courseId); // 把 getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
return courseBaseInfo; // 返回 courseBaseInfo
} // 代码块结束
//单独写一个方法保存营销信息,逻辑:存在则更新,不存在则添加 // 保留原作者写的行内注释
private int saveCourseMarket(CourseMarket courseMarketNew){ // 定义方法 saveCourseMarket(...)
//参数的合法性校验 // 保留原作者写的行内注释
String charge = courseMarketNew.getCharge(); // 把 courseMarketNew.getCharge() 的返回值赋给 charge
if(StringUtils.isEmpty(charge)){ // 定义方法 方法(...)
throw new RuntimeException("收费规则为空"); // 主动抛出异常
} // 代码块结束
//如果课程收费,价格没有填写也需要抛出异常 // 保留原作者写的行内注释
if(charge.equals("201001")){ // 定义方法 方法(...)
if(courseMarketNew.getPrice() ==null || courseMarketNew.getPrice().floatValue()<=0){ // 定义方法 方法(...)
// throw new RuntimeException("课程的价格不能为空并且必须大于0"); // 保留原作者写的行内注释
XueChengPlusException.cast("课程的价格不能为空并且必须大于0"); // 执行语句
} // 代码块结束
} // 代码块结束
//从数据库查询营销信息,存在则更新,不存在则添加 // 保留原作者写的行内注释
Long id = courseMarketNew.getId();//主键 // 把 courseMarketNew.getId() 的返回值赋给 id
CourseMarket courseMarket = courseMarketMapper.selectById(id); // 把 courseMarketMapper.selectById(id) 赋值给 courseMarket
if(courseMarket == null){ // 定义方法 方法(...)
//插入数据库 // 保留原作者写的行内注释
int insert = courseMarketMapper.insert(courseMarketNew); // 把 courseMarketMapper.insert(courseMarketNew) 赋值给 insert
return insert; // 返回 insert
}else{ // 代码逻辑
//将courseMarketNew拷贝到courseMarket // 保留原作者写的行内注释
BeanUtils.copyProperties(courseMarketNew,courseMarket); // 执行语句
courseMarket.setId(courseMarketNew.getId()); // 执行语句
//更新 // 保留原作者写的行内注释
int i = courseMarketMapper.updateById(courseMarket); // 把 courseMarketMapper.updateById(courseMarket) 赋值给 i
return i; // 返回 i
} // 代码块结束
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/service/impl/CourseCategoryServiceImpl.java
package com.xuecheng.content.service.impl; // 声明类所在的包路径
import com.xuecheng.content.mapper.CourseCategoryMapper; // 导入 CourseCategoryMapper 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.service.CourseCategoryService; // 导入 CourseCategoryService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类
import java.util.ArrayList; // 导入 ArrayList 类
import java.util.List; // 导入 List 类
import java.util.Map; // 导入 Map 类
import java.util.stream.Collectors; // 导入 Collectors 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 14:49 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class CourseCategoryServiceImpl implements CourseCategoryService { // 定义 class CourseCategoryServiceImpl
@Autowired // 使用注解 @Autowired
CourseCategoryMapper courseCategoryMapper; // 执行语句
@Override // 使用注解 @Override
public List<CourseCategoryTreeDto> queryTreeNodes(String id) { // 定义方法 queryTreeNodes(...)
//调用mapper递归查询出分类信息 // 保留原作者写的行内注释
List<CourseCategoryTreeDto> courseCategoryTreeDtos = courseCategoryMapper.selectTreeNodes(id); // 把 courseCategoryMapper.selectTreeNodes(id) 赋值给 courseCategoryTreeDtos
//找到每个节点的子节点,最终封装成List<CourseCategoryTreeDto> // 保留原作者写的行内注释
//先将list转成map,key就是结点的id,value就是CourseCategoryTreeDto对象,目的就是为了方便从map获取结点,filter(item->!id.equals(item.getId()))把根结点排除 // 保留原作者写的行内注释
Map<String, CourseCategoryTreeDto> mapTemp = courseCategoryTreeDtos.stream().filter(item -> !id.equals(item.getId())).collect(Collectors.toMap(key -> key.getId(), value -> value, (key1, key2) -> key2)); // 把 courseCategoryTreeDtos.stream().filter(item -> !id.equals(item.getId())).collect(Collectors.toMap(key -> key.getId(), value -> value, (key1, key2) -> key2)) 赋值给 mapTemp
//定义一个list作为最终返回的list // 保留原作者写的行内注释
List<CourseCategoryTreeDto> courseCategoryList = new ArrayList<>(); // 创建 ArrayList<> 对象并赋值给 courseCategoryList
//从头遍历 List<CourseCategoryTreeDto> ,一边遍历一边找子节点放在父节点的childrenTreeNodes // 保留原作者写的行内注释
courseCategoryTreeDtos.stream().filter(item -> !id.equals(item.getId())).forEach(item -> { // 定义方法 方法(...)
if (item.getParentid().equals(id)) { // 定义方法 方法(...)
courseCategoryList.add(item); // 执行语句
} // 代码块结束
//找到节点的父节点 // 保留原作者写的行内注释
CourseCategoryTreeDto courseCategoryParent = mapTemp.get(item.getParentid()); // 把 mapTemp.get(item.getParentid()) 赋值给 courseCategoryParent
if(courseCategoryParent!=null){ // 定义方法 方法(...)
if(courseCategoryParent.getChildrenTreeNodes()==null){ // 定义方法 方法(...)
//如果该父节点的ChildrenTreeNodes属性为空要new一个集合,因为要向该集合中放它的子节点 // 保留原作者写的行内注释
courseCategoryParent.setChildrenTreeNodes(new ArrayList<CourseCategoryTreeDto>()); // 执行语句
} // 代码块结束
//到每个节点的子节点放在父节点的childrenTreeNodes属性中 // 保留原作者写的行内注释
courseCategoryParent.getChildrenTreeNodes().add(item); // 执行语句
} // 代码块结束
}); // 执行语句
return courseCategoryList; // 返回 courseCategoryList
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/service/impl/CoursePublishServiceImpl.java
package com.xuecheng.content.service.impl; // 声明类所在的包路径
import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.base.exception.CommonError; // 导入 CommonError 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.content.config.MultipartSupportConfig; // 导入 MultipartSupportConfig 类
import com.xuecheng.content.feignclient.MediaServiceClient; // 导入 MediaServiceClient 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.mapper.CourseMarketMapper; // 导入 CourseMarketMapper 类
import com.xuecheng.content.mapper.CoursePublishMapper; // 导入 CoursePublishMapper 类
import com.xuecheng.content.mapper.CoursePublishPreMapper; // 导入 CoursePublishPreMapper 类
import com.xuecheng.content.model.dto.CourseBaseInfoDto; // 导入 CourseBaseInfoDto 类
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.model.po.CourseMarket; // 导入 CourseMarket 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.content.model.po.CoursePublishPre; // 导入 CoursePublishPre 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import com.xuecheng.content.service.TeachplanService; // 导入 TeachplanService 类
import com.xuecheng.messagesdk.model.po.MqMessage; // 导入 MqMessage 类
import com.xuecheng.messagesdk.service.MqMessageService; // 导入 MqMessageService 类
import freemarker.cache.ClassTemplateLoader; // 导入 ClassTemplateLoader 类
import freemarker.template.Configuration; // 导入 Configuration 类
import freemarker.template.Template; // 导入 Template 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.apache.commons.io.IOUtils; // 导入 IOUtils 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.redisson.api.RLock; // 导入 RLock 类
import org.redisson.api.RedissonClient; // 导入 RedissonClient 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.data.redis.core.RedisTemplate; // 导入 RedisTemplate 类
import org.springframework.stereotype.Service; // 导入 Service 类
import org.springframework.transaction.annotation.Transactional; // 导入 Transactional 类
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; // 导入 FreeMarkerTemplateUtils 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.File; // 导入 File 类
import java.io.FileOutputStream; // 导入 FileOutputStream 类
import java.io.InputStream; // 导入 InputStream 类
import java.time.LocalDateTime; // 导入 LocalDateTime 类
import java.util.HashMap; // 导入 HashMap 类
import java.util.List; // 导入 List 类
import java.util.Random; // 导入 Random 类
import java.util.concurrent.TimeUnit; // 导入 TimeUnit 类
import java.util.concurrent.locks.ReentrantLock; // 导入 ReentrantLock 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程发布相关接口实现 // 保留原作者写的块注释
* @date 2023/2/21 10:04 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class CoursePublishServiceImpl implements CoursePublishService { // 定义 class CoursePublishServiceImpl
@Autowired // 使用注解 @Autowired
CourseBaseInfoService courseBaseInfoService; // 执行语句
@Autowired // 使用注解 @Autowired
TeachplanService teachplanService; // 执行语句
@Autowired // 使用注解 @Autowired
CourseBaseMapper courseBaseMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CourseMarketMapper courseMarketMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CoursePublishPreMapper coursePublishPreMapper; // 执行语句
@Autowired // 使用注解 @Autowired
CoursePublishMapper coursePublishMapper; // 执行语句
@Autowired // 使用注解 @Autowired
MqMessageService mqMessageService; // 执行语句
@Autowired // 使用注解 @Autowired
MediaServiceClient mediaServiceClient; // 执行语句
@Autowired // 使用注解 @Autowired
RedisTemplate redisTemplate; // 执行语句
@Autowired // 使用注解 @Autowired
RedissonClient redissonClient; // 执行语句
// 课程预览 // 保留原作者写的行内注释
@Override // 使用注解 @Override
public CoursePreviewDto getCoursePreviewInfo(Long courseId) { // 定义方法 getCoursePreviewInfo(...)
CoursePreviewDto coursePreviewDto = new CoursePreviewDto(); // 创建 CoursePreviewDto 对象并赋值给 coursePreviewDto
//课程基本信息,营销信息 // 保留原作者写的行内注释
CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId); // 把 courseBaseInfoService.getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
coursePreviewDto.setCourseBase(courseBaseInfo); // 执行语句
//课程计划信息 // 保留原作者写的行内注释
List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId); // 把 teachplanService.findTeachplanTree(courseId) 赋值给 teachplanTree
coursePreviewDto.setTeachplans(teachplanTree); // 执行语句
return coursePreviewDto; // 返回 coursePreviewDto
} // 代码块结束
// 提交审核 // 保留原作者写的行内注释
@Transactional // 使用注解 @Transactional
@Override // 使用注解 @Override
public void commitAudit(Long companyId, Long courseId) { // 定义方法 commitAudit(...)
CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId); // 把 courseBaseInfoService.getCourseBaseInfo(courseId) 赋值给 courseBaseInfo
if (courseBaseInfo == null) { // 定义方法 方法(...)
XueChengPlusException.cast("课程找不到"); // 执行语句
} // 代码块结束
//审核状态 // 保留原作者写的行内注释
String auditStatus = courseBaseInfo.getAuditStatus(); // 把 courseBaseInfo.getAuditStatus() 的返回值赋给 auditStatus
//如果课程的审核状态为已提交则不允许提交 // 保留原作者写的行内注释
if (auditStatus.equals("202003")) { // 定义方法 方法(...)
XueChengPlusException.cast("课程已提交请等待审核"); // 执行语句
} // 代码块结束
//本机构只能提交本机构的课程 // 保留原作者写的行内注释
//todo:本机构只能提交本机构的课程 // 保留原作者写的行内注释
//课程的图片、计划信息没有填写也不允许提交 // 保留原作者写的行内注释
String pic = courseBaseInfo.getPic(); // 把 courseBaseInfo.getPic() 的返回值赋给 pic
if (StringUtils.isEmpty(pic)) { // 定义方法 方法(...)
XueChengPlusException.cast("请求上传课程图片"); // 执行语句
} // 代码块结束
//查询课程计划 // 保留原作者写的行内注释
//课程计划信息 // 保留原作者写的行内注释
List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId); // 把 teachplanService.findTeachplanTree(courseId) 赋值给 teachplanTree
if (teachplanTree == null || teachplanTree.size() == 0) { // 定义方法 方法(...)
XueChengPlusException.cast("请编写课程计划"); // 执行语句
} // 代码块结束
//查询到课程基本信息、营销信息、计划等信息插入到课程预发布表 // 保留原作者写的行内注释
CoursePublishPre coursePublishPre = new CoursePublishPre(); // 创建 CoursePublishPre 对象并赋值给 coursePublishPre
BeanUtils.copyProperties(courseBaseInfo, coursePublishPre); // 执行语句
//设置机构id // 保留原作者写的行内注释
coursePublishPre.setCompanyId(companyId); // 执行语句
//营销信息 // 保留原作者写的行内注释
CourseMarket courseMarket = courseMarketMapper.selectById(courseId); // 把 courseMarketMapper.selectById(courseId) 赋值给 courseMarket
//转json // 保留原作者写的行内注释
String courseMarketJson = JSON.toJSONString(courseMarket); // 把 JSON.toJSONString(courseMarket) 赋值给 courseMarketJson
coursePublishPre.setMarket(courseMarketJson); // 执行语句
//计划信息 // 保留原作者写的行内注释
//转json // 保留原作者写的行内注释
String teachplanTreeJson = JSON.toJSONString(teachplanTree); // 把 JSON.toJSONString(teachplanTree) 赋值给 teachplanTreeJson
coursePublishPre.setTeachplan(teachplanTreeJson); // 执行语句
//状态为已提交 // 保留原作者写的行内注释
coursePublishPre.setStatus("202003"); // 执行语句
//提交时间 // 保留原作者写的行内注释
coursePublishPre.setCreateDate(LocalDateTime.now()); // 执行语句
//查询预发布表,如果有记录则更新,没有则插入 // 保留原作者写的行内注释
CoursePublishPre coursePublishPreObj = coursePublishPreMapper.selectById(courseId); // 把 coursePublishPreMapper.selectById(courseId) 赋值给 coursePublishPreObj
if (coursePublishPreObj == null) { // 定义方法 方法(...)
//插入 // 保留原作者写的行内注释
coursePublishPreMapper.insert(coursePublishPre); // 执行语句
} else { // 代码逻辑
//更新 // 保留原作者写的行内注释
coursePublishPreMapper.updateById(coursePublishPre); // 执行语句
} // 代码块结束
//更新课程基本信息表的审核状态为已提交 // 保留原作者写的行内注释
CourseBase courseBase = courseBaseMapper.selectById(courseId); // 把 courseBaseMapper.selectById(courseId) 赋值给 courseBase
courseBase.setAuditStatus("202003");//审核状态为已提交 // 执行语句
courseBaseMapper.updateById(courseBase); // 执行语句
} // 代码块结束
@Transactional // 使用注解 @Transactional
@Override // 使用注解 @Override
public void publish(Long companyId, Long courseId) { // 定义方法 publish(...)
//查询预发布表 // 保留原作者写的行内注释
CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId); // 把 coursePublishPreMapper.selectById(courseId) 赋值给 coursePublishPre
if (coursePublishPre == null) { // 定义方法 方法(...)
XueChengPlusException.cast("课程没有审核记录,无法发布"); // 执行语句
} // 代码块结束
//状态 // 保留原作者写的行内注释
String status = coursePublishPre.getStatus(); // 把 coursePublishPre.getStatus() 的返回值赋给 status
//课程如果没有审核通过不允许发布 // 保留原作者写的行内注释
if (!status.equals("202004")) { // 定义方法 方法(...)
XueChengPlusException.cast("课程没有审核通过不允许发布"); // 执行语句
} // 代码块结束
//向课程发布表写入数据 // 保留原作者写的行内注释
CoursePublish coursePublish = new CoursePublish(); // 创建 CoursePublish 对象并赋值给 coursePublish
BeanUtils.copyProperties(coursePublishPre, coursePublish); // 执行语句
//先查询课程发布,如果有则更新,没有再添加 // 保留原作者写的行内注释
CoursePublish coursePublishObj = coursePublishMapper.selectById(courseId); // 把 coursePublishMapper.selectById(courseId) 赋值给 coursePublishObj
if (coursePublishObj == null) { // 定义方法 方法(...)
coursePublishMapper.insert(coursePublish); // 执行语句
} else { // 代码逻辑
coursePublishMapper.updateById(coursePublish); // 执行语句
} // 代码块结束
//向消息表写入数据 // 保留原作者写的行内注释
// mqMessageService.addMessage("course_publish",String.valueOf(courseId),null,null); // 保留原作者写的行内注释
saveCoursePublishMessage(courseId); // 执行语句
//将预发布表数据删除 // 保留原作者写的行内注释
coursePublishPreMapper.deleteById(courseId); // 执行语句
} // 代码块结束
@Override // 使用注解 @Override
public File generateCourseHtml(Long courseId) { // 定义方法 generateCourseHtml(...)
Configuration configuration = new Configuration(Configuration.getVersion()); // 创建 Configuration 对象并赋值给 configuration
//最终的静态文件 // 保留原作者写的行内注释
File htmlFile = null; // 把变量 htmlFile 初始化为 null
try { // 尝试执行可能抛出异常的代码
//拿到classpath路径 // 保留原作者写的行内注释
// String classpath = this.getClass().getResource("/").getPath(); // 保留原作者写的行内注释
// //指定模板的目录 // 保留原作者写的行内注释
// configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/")); // 保留原作者写的行内注释
//更改为如下方式 // 保留原作者写的行内注释
configuration.setTemplateLoader(new ClassTemplateLoader(this.getClass().getClassLoader(), "/templates")); // 执行语句
//指定编码 // 保留原作者写的行内注释
configuration.setDefaultEncoding("utf-8"); // 执行语句
//得到模板 // 保留原作者写的行内注释
Template template = configuration.getTemplate("course_template.ftl"); // 把 configuration.getTemplate("course_template.ftl") 赋值给 template
//准备数据 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewInfo = this.getCoursePreviewInfo(courseId); // 把 this.getCoursePreviewInfo(courseId) 赋值给 coursePreviewInfo
HashMap<String, Object> map = new HashMap<>(); // 创建 HashMap<> 对象并赋值给 map
map.put("model", coursePreviewInfo); // 执行语句
//Template template 模板, Object model 数据 // 保留原作者写的行内注释
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, map); // 把 FreeMarkerTemplateUtils.processTemplateIntoString(template, map) 赋值给 html
//输入流 // 保留原作者写的行内注释
InputStream inputStream = IOUtils.toInputStream(html, "utf-8"); // 把 IOUtils.toInputStream(html, "utf-8") 赋值给 inputStream
htmlFile = File.createTempFile("coursepublish", ".html"); // 把 File.createTempFile("coursepublish", ".html") 赋值给 htmlFile
//输出文件 // 保留原作者写的行内注释
FileOutputStream outputStream = new FileOutputStream(htmlFile); // 创建 FileOutputStream 对象并赋值给 outputStream
//使用流将html写入文件 // 保留原作者写的行内注释
IOUtils.copy(inputStream, outputStream); // 执行语句
} catch (Exception ex) { // 定义方法 catch(...)
log.error("页面静态化出现问题,课程id:{}", courseId, ex); // 执行语句
ex.printStackTrace(); // 执行语句
} // 代码块结束
return htmlFile; // 返回 htmlFile
} // 代码块结束
@Override // 使用注解 @Override
public void uploadCourseHtml(Long courseId, File file) { // 定义方法 uploadCourseHtml(...)
try { // 尝试执行可能抛出异常的代码
//将file转成MultipartFile // 保留原作者写的行内注释
MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file); // 把 MultipartSupportConfig.getMultipartFile(file) 赋值给 multipartFile
//远程调用得到返回值 // 保留原作者写的行内注释
String upload = mediaServiceClient.upload(multipartFile, "course/" + courseId + ".html"); // 把 mediaServiceClient.upload(multipartFile, "course/" + courseId + ".html") 赋值给 upload
if (upload == null) { // 定义方法 方法(...)
log.debug("远程调用走降级逻辑得到上传的结果为null,课程id:{}", courseId); // 执行语句
XueChengPlusException.cast("上传静态文件过程中存在异常"); // 执行语句
} // 代码块结束
} catch (Exception ex) { // 定义方法 catch(...)
ex.printStackTrace(); // 执行语句
XueChengPlusException.cast("上传静态文件过程中存在异常"); // 执行语句
} // 代码块结束
} // 代码块结束
/** // 保留原作者写的块注释
* @param courseId 课程id // 保留原作者写的块注释
* @return void // 保留原作者写的块注释
* @description 保存消息表记录 // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/20 16:32 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
private void saveCoursePublishMessage(Long courseId) { // 定义方法 saveCoursePublishMessage(...)
MqMessage mqMessage = mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null); // 把 mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null) 赋值给 mqMessage
if (mqMessage == null) { // 定义方法 方法(...)
XueChengPlusException.cast(CommonError.UNKOWN_ERROR); // 执行语句
} // 代码块结束
} // 代码块结束
/** // 保留原作者写的块注释
* 根据课程 id查询课程发布信息 // 保留原作者写的块注释
* // 保留原作者写的块注释
* @param courseId // 保留原作者写的块注释
* @return // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public CoursePublish getCoursePublish(Long courseId) { // 定义方法 getCoursePublish(...)
CoursePublish coursePublish = coursePublishMapper.selectById(courseId); // 把 coursePublishMapper.selectById(courseId) 赋值给 coursePublish
return coursePublish; // 返回 coursePublish
} // 代码块结束
//解决缓存穿透 // 保留原作者写的行内注释
// @Override // 保留原作者写的行内注释
// public CoursePublish getCoursePublishCache(Long courseId) { // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// //从缓存中查询 // 保留原作者写的行内注释
// Object jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 保留原作者写的行内注释
// //缓存中有 // 保留原作者写的行内注释
// if(jsonObj!=null){ // 保留原作者写的行内注释
//// System.out.println("=============从缓存中查询============="); // 保留原作者写的行内注释
// //缓存中有直接返回数据 // 保留原作者写的行内注释
// String jsonString = jsonObj.toString(); // 保留原作者写的行内注释
// if("null".equals(jsonString)){ // 保留原作者写的行内注释
// return null; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// }else{ // 保留原作者写的行内注释
// System.out.println("==查询数据库=="); // 保留原作者写的行内注释
// //从数据库查询 // 保留原作者写的行内注释
// CoursePublish coursePublish = getCoursePublish(courseId); // 保留原作者写的行内注释
//// if(coursePublish!=null){ // 保留原作者写的行内注释
// //查询完成再存储到redis // 保留原作者写的行内注释
// redisTemplate.opsForValue().set("course:"+courseId,JSON.toJSONString(coursePublish),30, TimeUnit.SECONDS); // 保留原作者写的行内注释
//// } // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
//使用同步锁解决缓存击穿 // 保留原作者写的行内注释
// @Override // 保留原作者写的行内注释
// public CoursePublish getCoursePublishCache(Long courseId) { // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// //从缓存中查询 // 保留原作者写的行内注释
// Object jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 保留原作者写的行内注释
// //缓存中有 // 保留原作者写的行内注释
// if(jsonObj!=null){ // 保留原作者写的行内注释
//// System.out.println("=============从缓存中查询============="); // 保留原作者写的行内注释
// //缓存中有直接返回数据 // 保留原作者写的行内注释
// String jsonString = jsonObj.toString(); // 保留原作者写的行内注释
// if("null".equals(jsonString)){ // 保留原作者写的行内注释
// return null; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// }else{ // 保留原作者写的行内注释
// synchronized (this){ // 保留原作者写的行内注释
// //再次查询一下缓存 // 保留原作者写的行内注释
// //从缓存中查询 // 保留原作者写的行内注释
// jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 保留原作者写的行内注释
// //缓存中有 // 保留原作者写的行内注释
// if(jsonObj!=null) { // 保留原作者写的行内注释
// //缓存中有直接返回数据 // 保留原作者写的行内注释
// String jsonString = jsonObj.toString(); // 保留原作者写的行内注释
// if("null".equals(jsonString)){ // 保留原作者写的行内注释
// return null; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// System.out.println("==查询数据库=="); // 保留原作者写的行内注释
// //从数据库查询 // 保留原作者写的行内注释
// CoursePublish coursePublish = getCoursePublish(courseId); // 保留原作者写的行内注释
// //查询完成再存储到redis // 保留原作者写的行内注释
// redisTemplate.opsForValue().set("course:"+courseId,JSON.toJSONString(coursePublish),300, TimeUnit.SECONDS); // 保留原作者写的行内注释
// return coursePublish; // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
//使用redisson实现分布式锁 // 保留原作者写的行内注释
@Override // 使用注解 @Override
public CoursePublish getCoursePublishCache(Long courseId) { // 定义方法 getCoursePublishCache(...)
//从缓存中查询 // 保留原作者写的行内注释
Object jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 把 redisTemplate.opsForValue().get("course:" + courseId) 赋值给 jsonObj
//缓存中有 // 保留原作者写的行内注释
if (jsonObj != null) { // 定义方法 方法(...)
// System.out.println("=============从缓存中查询============="); // 保留原作者写的行内注释
//缓存中有直接返回数据 // 保留原作者写的行内注释
String jsonString = jsonObj.toString(); // 把 jsonObj.toString() 的返回值赋给 jsonString
if ("null".equals(jsonString)) { // 定义方法 方法(...)
return null; // 返回 null
} // 代码块结束
CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 把 JSON.parseObject(jsonString, CoursePublish.class) 赋值给 coursePublish
return coursePublish; // 返回 coursePublish
} else { // 代码逻辑
RLock lock = redissonClient.getLock("coursequerylock:" + courseId); // 把 redissonClient.getLock("coursequerylock:" + courseId) 赋值给 lock
//获取分布式锁 // 保留原作者写的行内注释
lock.lock(); // 执行语句
try { // 尝试执行可能抛出异常的代码
//再次查询一下缓存 // 保留原作者写的行内注释
//从缓存中查询 // 保留原作者写的行内注释
jsonObj = redisTemplate.opsForValue().get("course:" + courseId); // 把 redisTemplate.opsForValue().get("course:" + courseId) 赋值给 jsonObj
//缓存中有 // 保留原作者写的行内注释
if (jsonObj != null) { // 定义方法 方法(...)
//缓存中有直接返回数据 // 保留原作者写的行内注释
String jsonString = jsonObj.toString(); // 把 jsonObj.toString() 的返回值赋给 jsonString
if ("null".equals(jsonString)) { // 定义方法 方法(...)
return null; // 返回 null
} // 代码块结束
CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class); // 把 JSON.parseObject(jsonString, CoursePublish.class) 赋值给 coursePublish
return coursePublish; // 返回 coursePublish
} // 代码块结束
System.out.println("==查询数据库=="); // 执行语句
// try { // 保留原作者写的行内注释
// //手动延迟,测试锁的续期功能 // 保留原作者写的行内注释
// Thread.sleep(60000); // 保留原作者写的行内注释
// } catch (InterruptedException e) { // 保留原作者写的行内注释
// throw new RuntimeException(e); // 保留原作者写的行内注释
// } // 保留原作者写的行内注释
//从数据库查询 // 保留原作者写的行内注释
CoursePublish coursePublish = getCoursePublish(courseId); // 把 getCoursePublish(courseId) 赋值给 coursePublish
//查询完成再存储到redis // 保留原作者写的行内注释
redisTemplate.opsForValue().set("course:" + courseId, JSON.toJSONString(coursePublish), 300, TimeUnit.SECONDS); // 执行语句
return coursePublish; // 返回 coursePublish
} finally { // 代码逻辑
//手动释放锁 // 保留原作者写的行内注释
lock.unlock(); // 执行语句
} // 代码块结束
} // 代码块结束
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/service/impl/TeachplanServiceImpl.java
package com.xuecheng.content.service.impl; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.content.mapper.TeachplanMapper; // 导入 TeachplanMapper 类
import com.xuecheng.content.mapper.TeachplanMediaMapper; // 导入 TeachplanMediaMapper 类
import com.xuecheng.content.model.dto.BindTeachplanMediaDto; // 导入 BindTeachplanMediaDto 类
import com.xuecheng.content.model.dto.SaveTeachplanDto; // 导入 SaveTeachplanDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.model.po.Teachplan; // 导入 Teachplan 类
import com.xuecheng.content.model.po.TeachplanMedia; // 导入 TeachplanMedia 类
import com.xuecheng.content.service.TeachplanService; // 导入 TeachplanService 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类
import org.springframework.transaction.annotation.Transactional; // 导入 Transactional 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/14 12:11 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Service // 使用注解 @Service
public class TeachplanServiceImpl implements TeachplanService { // 定义 class TeachplanServiceImpl
@Autowired // 使用注解 @Autowired
TeachplanMapper teachplanMapper; // 执行语句
@Autowired // 使用注解 @Autowired
TeachplanMediaMapper teachplanMediaMapper; // 执行语句
@Override // 使用注解 @Override
public List<TeachplanDto> findTeachplanTree(Long courseId) { // 定义方法 findTeachplanTree(...)
List<TeachplanDto> teachplanDtos = teachplanMapper.selectTreeNodes(courseId); // 把 teachplanMapper.selectTreeNodes(courseId) 赋值给 teachplanDtos
return teachplanDtos; // 返回 teachplanDtos
} // 代码块结束
private int getTeachplanCount(Long courseId,Long parentId){ // 定义方法 getTeachplanCount(...)
LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>(); // 创建 LambdaQueryWrapper<> 对象并赋值给 queryWrapper
queryWrapper = queryWrapper.eq(Teachplan::getCourseId, courseId).eq(Teachplan::getParentid, parentId); // 把 queryWrapper.eq(Teachplan::getCourseId, courseId).eq(Teachplan::getParentid, parentId) 赋值给 queryWrapper
Integer count = teachplanMapper.selectCount(queryWrapper); // 把 teachplanMapper.selectCount(queryWrapper) 赋值给 count
return count+1; // 返回 count+1
} // 代码块结束
@Override // 使用注解 @Override
public void saveTeachplan(SaveTeachplanDto saveTeachplanDto) { // 定义方法 saveTeachplan(...)
//通过课程计划id判断是新增和修改 // 保留原作者写的行内注释
Long teachplanId = saveTeachplanDto.getId(); // 把 saveTeachplanDto.getId() 的返回值赋给 teachplanId
if(teachplanId ==null){ // 定义方法 方法(...)
//新增 // 保留原作者写的行内注释
Teachplan teachplan = new Teachplan(); // 创建 Teachplan 对象并赋值给 teachplan
BeanUtils.copyProperties(saveTeachplanDto,teachplan); // 执行语句
//确定排序字段,找到它的同级节点个数,排序字段就是个数加1 select count(1) from teachplan where course_id=117 and parentid=268 // 保留原作者写的行内注释
Long parentid = saveTeachplanDto.getParentid(); // 把 saveTeachplanDto.getParentid() 的返回值赋给 parentid
Long courseId = saveTeachplanDto.getCourseId(); // 把 saveTeachplanDto.getCourseId() 的返回值赋给 courseId
int teachplanCount = getTeachplanCount(courseId, parentid); // 把 getTeachplanCount(courseId, parentid) 赋值给 teachplanCount
teachplan.setOrderby(teachplanCount); // 执行语句
teachplanMapper.insert(teachplan); // 执行语句
}else{ // 代码逻辑
//修改 // 保留原作者写的行内注释
Teachplan teachplan = teachplanMapper.selectById(teachplanId); // 把 teachplanMapper.selectById(teachplanId) 赋值给 teachplan
//将参数复制到teachplan // 保留原作者写的行内注释
BeanUtils.copyProperties(saveTeachplanDto,teachplan); // 执行语句
teachplanMapper.updateById(teachplan); // 执行语句
} // 代码块结束
} // 代码块结束
@Transactional // 使用注解 @Transactional
@Override // 使用注解 @Override
public void associationMedia(BindTeachplanMediaDto bindTeachplanMediaDto) { // 定义方法 associationMedia(...)
//课程计划id // 保留原作者写的行内注释
Long teachplanId = bindTeachplanMediaDto.getTeachplanId(); // 把 bindTeachplanMediaDto.getTeachplanId() 的返回值赋给 teachplanId
Teachplan teachplan = teachplanMapper.selectById(teachplanId); // 把 teachplanMapper.selectById(teachplanId) 赋值给 teachplan
if(teachplan == null){ // 定义方法 方法(...)
XueChengPlusException.cast("课程计划不存在"); // 执行语句
} // 代码块结束
//先删除原有记录,根据课程计划id删除它所绑定的媒资 // 保留原作者写的行内注释
int delete = teachplanMediaMapper.delete(new LambdaQueryWrapper<TeachplanMedia>().eq(TeachplanMedia::getTeachplanId, bindTeachplanMediaDto.getTeachplanId())); // 把 teachplanMediaMapper.delete(new LambdaQueryWrapper<TeachplanMedia>().eq(TeachplanMedia::getTeachplanId, bindTeachplanMediaDto.getTeachplanId())) 赋值给 delete
//再添加新记录 // 保留原作者写的行内注释
TeachplanMedia teachplanMedia = new TeachplanMedia(); // 创建 TeachplanMedia 对象并赋值给 teachplanMedia
BeanUtils.copyProperties(bindTeachplanMediaDto,teachplanMedia); // 执行语句
teachplanMedia.setCourseId(teachplan.getCourseId()); // 执行语句
teachplanMedia.setMediaFilename(bindTeachplanMediaDto.getFileName()); // 执行语句
teachplanMediaMapper.insert(teachplanMedia); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/service/jobhandler/CoursePublishTask.java
package com.xuecheng.content.service.jobhandler; // 声明类所在的包路径
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.content.feignclient.CourseIndex; // 导入 CourseIndex 类
import com.xuecheng.content.feignclient.SearchServiceClient; // 导入 SearchServiceClient 类
import com.xuecheng.content.mapper.CoursePublishMapper; // 导入 CoursePublishMapper 类
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import com.xuecheng.messagesdk.model.po.MqMessage; // 导入 MqMessage 类
import com.xuecheng.messagesdk.service.MessageProcessAbstract; // 导入 MessageProcessAbstract 类
import com.xuecheng.messagesdk.service.MqMessageService; // 导入 MqMessageService 类
import com.xxl.job.core.context.XxlJobHelper; // 导入 XxlJobHelper 类
import com.xxl.job.core.handler.annotation.XxlJob; // 导入 XxlJob 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.beans.BeanUtils; // 导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Component; // 导入 Component 类
import java.io.File; // 导入 File 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程发布的任务类 // 保留原作者写的块注释
* @date 2023/2/21 16:15 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class CoursePublishTask extends MessageProcessAbstract { // 定义 class CoursePublishTask
@Autowired // 使用注解 @Autowired
CoursePublishService coursePublishService; // 执行语句
@Autowired // 使用注解 @Autowired
SearchServiceClient searchServiceClient; // 执行语句
@Autowired // 使用注解 @Autowired
CoursePublishMapper coursePublishMapper; // 执行语句
//任务调度入口 // 保留原作者写的行内注释
@XxlJob("CoursePublishJobHandler") // 使用注解 @XxlJob("CoursePublishJobHandler")
public void coursePublishJobHandler() throws Exception { // 定义方法 coursePublishJobHandler(...)
// 分片参数 // 保留原作者写的行内注释
int shardIndex = XxlJobHelper.getShardIndex();//执行器的序号,从0开始 // 把 XxlJobHelper.getShardIndex() 的返回值赋给 shardIndex
int shardTotal = XxlJobHelper.getShardTotal();//执行器总数 // 把 XxlJobHelper.getShardTotal() 的返回值赋给 shardTotal
//调用抽象类的方法执行任务 // 保留原作者写的行内注释
process(shardIndex,shardTotal, "course_publish",30,60); // 执行语句
} // 代码块结束
//课程发布任务处理 // 保留原作者写的行内注释
//执行课程发布任务的逻辑,如果此方法抛出异常说明任务执行失败 // 保留原作者写的行内注释
@Override // 使用注解 @Override
public boolean execute(MqMessage mqMessage) { // 定义方法 execute(...)
//从mqMessage拿到课程id // 保留原作者写的行内注释
Long courseId = Long.parseLong(mqMessage.getBusinessKey1()); // 把 Long.parseLong(mqMessage.getBusinessKey1()) 赋值给 courseId
//课程静态化上传到minio // 保留原作者写的行内注释
generateCourseHtml(mqMessage,courseId); // 执行语句
//向elasticsearch写索引数据 // 保留原作者写的行内注释
saveCourseIndex(mqMessage,courseId); // 执行语句
//向redis写缓存 // 保留原作者写的行内注释
//返回true表示任务完成 // 保留原作者写的行内注释
return true; // 返回 true
} // 代码块结束
//生成课程静态化页面并上传至文件系统 // 保留原作者写的行内注释
private void generateCourseHtml(MqMessage mqMessage,long courseId){ // 定义方法 generateCourseHtml(...)
//消息id // 保留原作者写的行内注释
Long taskId = mqMessage.getId(); // 把 mqMessage.getId() 的返回值赋给 taskId
MqMessageService mqMessageService = this.getMqMessageService(); // 把 this.getMqMessageService() 的返回值赋给 mqMessageService
//做任务幂等性处理 // 保留原作者写的行内注释
//查询数据库取出该阶段执行状态 // 保留原作者写的行内注释
int stageOne = mqMessageService.getStageOne(taskId); // 把 mqMessageService.getStageOne(taskId) 赋值给 stageOne
if(stageOne>0){ // 定义方法 方法(...)
log.debug("课程静态化任务完成,无需处理..."); // 执行语句
return ; // 返回
} // 代码块结束
//开始进行课程静态化 生成html页面 // 保留原作者写的行内注释
File file = coursePublishService.generateCourseHtml(courseId); // 把 coursePublishService.generateCourseHtml(courseId) 赋值给 file
if(file == null){ // 定义方法 方法(...)
XueChengPlusException.cast("生成的静态页面为空"); // 执行语句
} // 代码块结束
// 将html上传到minio // 保留原作者写的行内注释
coursePublishService.uploadCourseHtml(courseId,file); // 执行语句
//..任务处理完成写任务状态为完成 // 保留原作者写的行内注释
mqMessageService.completedStageOne(taskId); // 执行语句
} // 代码块结束
//保存课程索引信息 第二个阶段任务 // 保留原作者写的行内注释
private void saveCourseIndex(MqMessage mqMessage,long courseId){ // 定义方法 saveCourseIndex(...)
//任务id // 保留原作者写的行内注释
Long taskId = mqMessage.getId(); // 把 mqMessage.getId() 的返回值赋给 taskId
MqMessageService mqMessageService = this.getMqMessageService(); // 把 this.getMqMessageService() 的返回值赋给 mqMessageService
//取出第二个阶段状态 // 保留原作者写的行内注释
int stageTwo = mqMessageService.getStageTwo(taskId); // 把 mqMessageService.getStageTwo(taskId) 赋值给 stageTwo
//任务幂等性处理 // 保留原作者写的行内注释
if(stageTwo>0){ // 定义方法 方法(...)
log.debug("课程索引信息已写入,无需执行..."); // 执行语句
return; // 直接返回不带结果
} // 代码块结束
//查询课程信息,调用搜索服务添加索引接口 // 保留原作者写的行内注释
//从课程发布表查询课程信息 // 保留原作者写的行内注释
CoursePublish coursePublish = coursePublishMapper.selectById(courseId); // 把 coursePublishMapper.selectById(courseId) 赋值给 coursePublish
CourseIndex courseIndex = new CourseIndex(); // 创建 CourseIndex 对象并赋值给 courseIndex
BeanUtils.copyProperties(coursePublish,courseIndex); // 执行语句
//远程调用 // 保留原作者写的行内注释
Boolean add = searchServiceClient.add(courseIndex); // 把 searchServiceClient.add(courseIndex) 赋值给 add
if(!add){ // 定义方法 方法(...)
XueChengPlusException.cast("远程调用搜索服务添加课程索引失败"); // 执行语句
} // 代码块结束
//完成本阶段的任务 // 保留原作者写的行内注释
mqMessageService.completedStageTwo(taskId); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/main/java/com/xuecheng/content/service/TeachplanService.java
package com.xuecheng.content.service; // 声明类所在的包路径
import com.xuecheng.content.model.dto.BindTeachplanMediaDto; // 导入 BindTeachplanMediaDto 类
import com.xuecheng.content.model.dto.SaveTeachplanDto; // 导入 SaveTeachplanDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程计划管理相关接口 // 保留原作者写的块注释
* @date 2023/2/14 12:10 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public interface TeachplanService { // 定义 interface TeachplanService
/** // 保留原作者写的块注释
* 根据课程id查询课程计划 // 保留原作者写的块注释
* @param courseId 课程计划 // 保留原作者写的块注释
* @return // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public List<TeachplanDto> findTeachplanTree(Long courseId); // 执行语句
/** // 保留原作者写的块注释
* 新增/修改/保存课程计划 // 保留原作者写的块注释
* @param saveTeachplanDto // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void saveTeachplan(SaveTeachplanDto saveTeachplanDto); // 执行语句
/** // 保留原作者写的块注释
* @description 教学计划绑定媒资 // 保留原作者写的块注释
* @param bindTeachplanMediaDto // 保留原作者写的块注释
* @return com.xuecheng.content.model.po.TeachplanMedia // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @date 2022/9/14 22:20 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
public void associationMedia(BindTeachplanMediaDto bindTeachplanMediaDto); // 执行语句
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/java/com/xuecheng/content/CourseBaseInfoServiceTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 Page 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.junit.jupiter.api.Assertions; // 导入 Assertions 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class CourseBaseInfoServiceTests { // 定义 class CourseBaseInfoServiceTests
@Autowired // 使用注解 @Autowired
CourseBaseInfoService courseBaseInfoService; // 执行语句
@Test // 使用注解 @Test
public void testCourseBaseInfoService() { // 定义方法 testCourseBaseInfoService(...)
//查询条件 // 保留原作者写的行内注释
QueryCourseParamsDto courseParamsDto = new QueryCourseParamsDto(); // 创建 QueryCourseParamsDto 对象并赋值给 courseParamsDto
courseParamsDto.setCourseName("java");//课程名称查询条件 // 执行语句
courseParamsDto.setAuditStatus("202004");//202004表示课程审核通过 // 执行语句
//分页参数对象 // 保留原作者写的行内注释
PageParams pageParams = new PageParams(); // 创建 PageParams 对象并赋值给 pageParams
pageParams.setPageNo(2L); // 执行语句
pageParams.setPageSize(2L); // 执行语句
PageResult<CourseBase> courseBasePageResult = courseBaseInfoService.queryCourseBaseList(null,pageParams, courseParamsDto); // 把 courseBaseInfoService.queryCourseBaseList(null,pageParams, courseParamsDto) 赋值给 courseBasePageResult
System.out.println(courseBasePageResult); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/java/com/xuecheng/content/CourseBaseMapperTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 Page 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.junit.jupiter.api.Assertions; // 导入 Assertions 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class CourseBaseMapperTests { // 定义 class CourseBaseMapperTests
@Autowired // 使用注解 @Autowired
CourseBaseMapper courseBaseMapper; // 执行语句
@Test // 使用注解 @Test
public void testCourseBaseMapper() { // 定义方法 testCourseBaseMapper(...)
CourseBase courseBase = courseBaseMapper.selectById(18); // 把 courseBaseMapper.selectById(18) 赋值给 courseBase
Assertions.assertNotNull(courseBase); // 执行语句
//详细进行分页查询的单元测试 // 保留原作者写的行内注释
//查询条件 // 保留原作者写的行内注释
QueryCourseParamsDto courseParamsDto = new QueryCourseParamsDto(); // 创建 QueryCourseParamsDto 对象并赋值给 courseParamsDto
courseParamsDto.setCourseName("java");//课程名称查询条件 // 执行语句
//拼装查询条件 // 保留原作者写的行内注释
LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>(); // 创建 LambdaQueryWrapper<> 对象并赋值给 queryWrapper
//根据名称模糊查询,在sql中拼接 course_base.name like '%值%' // 保留原作者写的行内注释
queryWrapper.like(StringUtils.isNotEmpty(courseParamsDto.getCourseName()),CourseBase::getName,courseParamsDto.getCourseName()); // 执行语句
//根据课程审核状态查询 course_base.audit_status = ? // 保留原作者写的行内注释
queryWrapper.eq(StringUtils.isNotEmpty(courseParamsDto.getAuditStatus()), CourseBase::getAuditStatus,courseParamsDto.getAuditStatus()); // 执行语句
//todo:按课程发布状态查询 // 保留原作者写的行内注释
//分页参数对象 // 保留原作者写的行内注释
PageParams pageParams = new PageParams(); // 创建 PageParams 对象并赋值给 pageParams
pageParams.setPageNo(1L); // 执行语句
pageParams.setPageSize(2L); // 执行语句
//创建page分页参数对象,参数:当前页码,每页记录数 // 保留原作者写的行内注释
Page<CourseBase> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize()); // 创建 Page<> 对象并赋值给 page
//开始进行分页查询 // 保留原作者写的行内注释
Page<CourseBase> pageResult = courseBaseMapper.selectPage(page, queryWrapper); // 把 courseBaseMapper.selectPage(page, queryWrapper) 赋值给 pageResult
//数据列表 // 保留原作者写的行内注释
List<CourseBase> items = pageResult.getRecords(); // 把 pageResult.getRecords() 的返回值赋给 items
//总记录数 // 保留原作者写的行内注释
long total = pageResult.getTotal(); // 把 pageResult.getTotal() 的返回值赋给 total
//List<T> items, long counts, long page, long pageSize // 保留原作者写的行内注释
PageResult<CourseBase> courseBasePageResult = new PageResult<CourseBase>(items,total,pageParams.getPageNo(), pageParams.getPageSize()); // 创建 PageResult<CourseBase> 对象并赋值给 courseBasePageResult
System.out.println(courseBasePageResult); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/java/com/xuecheng/content/CourseCategoryMapperTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 导入 LambdaQueryWrapper 类
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 Page 类
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.mapper.CourseBaseMapper; // 导入 CourseBaseMapper 类
import com.xuecheng.content.mapper.CourseCategoryMapper; // 导入 CourseCategoryMapper 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.junit.jupiter.api.Assertions; // 导入 Assertions 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class CourseCategoryMapperTests { // 定义 class CourseCategoryMapperTests
@Autowired // 使用注解 @Autowired
CourseCategoryMapper courseCategoryMapper; // 执行语句
@Test // 使用注解 @Test
public void testCourseCategoryMapper() { // 定义方法 testCourseCategoryMapper(...)
List<CourseCategoryTreeDto> courseCategoryTreeDtos = courseCategoryMapper.selectTreeNodes("1"); // 把 courseCategoryMapper.selectTreeNodes("1") 赋值给 courseCategoryTreeDtos
System.out.println(courseCategoryTreeDtos); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/java/com/xuecheng/content/CourseCategoryServiceTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.xuecheng.base.model.PageParams; // 导入 PageParams 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.model.dto.QueryCourseParamsDto; // 导入 QueryCourseParamsDto 类
import com.xuecheng.content.model.po.CourseBase; // 导入 CourseBase 类
import com.xuecheng.content.service.CourseBaseInfoService; // 导入 CourseBaseInfoService 类
import com.xuecheng.content.service.CourseCategoryService; // 导入 CourseCategoryService 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description TODO // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class CourseCategoryServiceTests { // 定义 class CourseCategoryServiceTests
@Autowired // 使用注解 @Autowired
CourseCategoryService courseCategoryService; // 执行语句
@Test // 使用注解 @Test
public void testCourseCategoryService() { // 定义方法 testCourseCategoryService(...)
List<CourseCategoryTreeDto> courseCategoryTreeDtos = courseCategoryService.queryTreeNodes("1"); // 把 courseCategoryService.queryTreeNodes("1") 赋值给 courseCategoryTreeDtos
System.out.println(courseCategoryTreeDtos); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/java/com/xuecheng/content/FeignUploadTest.java
package com.xuecheng.content; // 声明类所在的包路径
import com.xuecheng.content.config.MultipartSupportConfig; // 导入 MultipartSupportConfig 类
import com.xuecheng.content.feignclient.MediaServiceClient; // 导入 MediaServiceClient 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类
import java.io.File; // 导入 File 类
import java.io.IOException; // 导入 IOException 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 测试远程调用媒资服务 // 保留原作者写的块注释
* @date 2023/2/22 10:30 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class FeignUploadTest { // 定义 class FeignUploadTest
@Autowired // 使用注解 @Autowired
MediaServiceClient mediaServiceClient; // 执行语句
@Test // 使用注解 @Test
public void test() throws IOException { // 定义方法 test(...)
//将file转成MultipartFile // 保留原作者写的行内注释
File file = new File("D:\\develop\\upload\\120.html"); // 创建 File 对象并赋值给 file
MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file); // 把 MultipartSupportConfig.getMultipartFile(file) 赋值给 multipartFile
//远程调用得到返回值 // 保留原作者写的行内注释
String upload = mediaServiceClient.upload(multipartFile, "course/120.html"); // 把 mediaServiceClient.upload(multipartFile, "course/120.html") 赋值给 upload
if(upload==null){ // 定义方法 方法(...)
System.out.println("走了降级逻辑"); // 执行语句
} // 代码块结束
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/java/com/xuecheng/content/FreemarkerTest.java
package com.xuecheng.content; // 声明类所在的包路径
import com.xuecheng.content.mapper.TeachplanMapper; // 导入 TeachplanMapper 类
import com.xuecheng.content.model.dto.CoursePreviewDto; // 导入 CoursePreviewDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import com.xuecheng.content.service.CoursePublishService; // 导入 CoursePublishService 类
import freemarker.template.Configuration; // 导入 Configuration 类
import freemarker.template.Template; // 导入 Template 类
import freemarker.template.TemplateException; // 导入 TemplateException 类
import org.apache.commons.io.IOUtils; // 导入 IOUtils 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; // 导入 FreeMarkerTemplateUtils 类
import java.io.File; // 导入 File 类
import java.io.FileOutputStream; // 导入 FileOutputStream 类
import java.io.IOException; // 导入 IOException 类
import java.io.InputStream; // 导入 InputStream 类
import java.util.HashMap; // 导入 HashMap 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 测试freemarker页面静态化方法 // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class FreemarkerTest { // 定义 class FreemarkerTest
@Autowired // 使用注解 @Autowired
CoursePublishService coursePublishService; // 执行语句
@Test // 使用注解 @Test
public void testGenerateHtmlByTemplate() throws IOException, TemplateException { // 定义方法 testGenerateHtmlByTemplate(...)
Configuration configuration = new Configuration(Configuration.getVersion()); // 创建 Configuration 对象并赋值给 configuration
//拿到classpath路径 // 保留原作者写的行内注释
String classpath = this.getClass().getResource("/").getPath(); // 把 this.getClass().getResource("/").getPath() 的返回值赋给 classpath
//指定模板的目录 // 保留原作者写的行内注释
configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/")); // 执行语句
//指定编码 // 保留原作者写的行内注释
configuration.setDefaultEncoding("utf-8"); // 执行语句
//得到模板 // 保留原作者写的行内注释
Template template = configuration.getTemplate("course_template.ftl"); // 把 configuration.getTemplate("course_template.ftl") 赋值给 template
//准备数据 // 保留原作者写的行内注释
CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(120L); // 把 coursePublishService.getCoursePreviewInfo(120L) 赋值给 coursePreviewInfo
HashMap<String, Object> map = new HashMap<>(); // 创建 HashMap<> 对象并赋值给 map
map.put("model",coursePreviewInfo); // 执行语句
//Template template 模板, Object model 数据 // 保留原作者写的行内注释
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, map); // 把 FreeMarkerTemplateUtils.processTemplateIntoString(template, map) 赋值给 html
//输入流 // 保留原作者写的行内注释
InputStream inputStream = IOUtils.toInputStream(html, "utf-8"); // 把 IOUtils.toInputStream(html, "utf-8") 赋值给 inputStream
//输出文件 // 保留原作者写的行内注释
FileOutputStream outputStream = new FileOutputStream(new File("D:\\develop\\upload\\120.html")); // 创建 FileOutputStream 对象并赋值给 outputStream
//使用流将html写入文件 // 保留原作者写的行内注释
IOUtils.copy(inputStream,outputStream); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/java/com/xuecheng/content/TeachplanMapperTests.java
package com.xuecheng.content; // 声明类所在的包路径
import com.xuecheng.content.mapper.CourseCategoryMapper; // 导入 CourseCategoryMapper 类
import com.xuecheng.content.mapper.TeachplanMapper; // 导入 TeachplanMapper 类
import com.xuecheng.content.model.dto.CourseCategoryTreeDto; // 导入 CourseCategoryTreeDto 类
import com.xuecheng.content.model.dto.TeachplanDto; // 导入 TeachplanDto 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类
import java.util.List; // 导入 List 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 课程计划mapper测试 // 保留原作者写的块注释
* @date 2023/2/12 9:24 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class TeachplanMapperTests { // 定义 class TeachplanMapperTests
@Autowired // 使用注解 @Autowired
TeachplanMapper teachplanMapper; // 执行语句
@Test // 使用注解 @Test
public void testSelectTreeNodes() { // 定义方法 testSelectTreeNodes(...)
List<TeachplanDto> teachplanDtos = teachplanMapper.selectTreeNodes(117L); // 把 teachplanMapper.selectTreeNodes(117L) 赋值给 teachplanDtos
System.out.println(teachplanDtos); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/java/com/xuecheng/ContentApplication.java
package com.xuecheng; // 声明类所在的包路径
import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类
import org.springframework.cloud.openfeign.EnableFeignClients; // 导入 EnableFeignClients 类
/** // 保留原作者写的块注释
* @author Mr.M // 保留原作者写的块注释
* @version 1.0 // 保留原作者写的块注释
* @description 内容管理服务启动类 // 保留原作者写的块注释
* @date 2023/2/11 15:49 // 保留原作者写的块注释
*/ // 保留原作者写的块注释
@EnableFeignClients(basePackages={"com.xuecheng.content.feignclient"}) // 使用注解 @EnableFeignClients(basePackages={"com.xuecheng.content.feignclient"})
@SpringBootApplication // 使用注解 @SpringBootApplication
public class ContentApplication { // 定义 class ContentApplication
public static void main(String[] args) { // 定义方法 main(...)
SpringApplication.run(ContentApplication.class, args); // 执行语句
} // 代码块结束
} // 代码块结束
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/resources/bootstrap.yml
spring:
application:
name: content-service
cloud:
nacos:
server-addr: 192.168.101.65:8848
discovery: #服务注册相关配置
namespace: dev402
group: xuecheng-plus-project
config: #配置文件相关配置
namespace: dev402
group: xuecheng-plus-project
file-extension: yaml
refresh-enabled: true
shared-configs:
- data-id: feign-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true
profiles:
active: dev #环境名
# datasource:
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://192.168.101.65:3306/xc402_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
# username: root
# password: mysql
# 日志文件配置路径
logging:
config: classpath:log4j2-dev.xml
文件:xuecheng-plus-content/xuecheng-plus-content-service/src/test/resources/log4j2-dev.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- XML 声明 -->
<Configuration monitorInterval="180" packages=""> <!-- SQL 语句片段 -->
<properties> <!-- SQL 语句片段 -->
<property name="logdir">logs</property> <!-- SQL 语句片段 -->
<property name="PATTERN">%date{YYYY-MM-dd HH:mm:ss,SSS} %level [%thread][%file:%line] - %msg%n%throwable</property> <!-- SQL 语句片段 -->
</properties> <!-- SQL 语句片段 -->
<Appenders> <!-- SQL 语句片段 -->
<Console name="Console" target="SYSTEM_OUT"> <!-- SQL 语句片段 -->
<PatternLayout pattern="${PATTERN}"/> <!-- SQL 语句片段 -->
</Console> <!-- SQL 语句片段 -->
<RollingFile name="ErrorAppender" fileName="${logdir}/error.log" <!-- SQL 语句片段 -->
filePattern="${logdir}/$${date:yyyy-MM-dd}/error.%d{yyyy-MM-dd-HH}.log" append="true"> <!-- SQL 语句片段 -->
<PatternLayout pattern="${PATTERN}"/> <!-- SQL 语句片段 -->
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> <!-- SQL 语句片段 -->
<Policies> <!-- SQL 语句片段 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" /> <!-- SQL 语句片段 -->
</Policies> <!-- SQL 语句片段 -->
</RollingFile> <!-- SQL 语句片段 -->
<RollingFile name="DebugAppender" fileName="${logdir}/info.log" <!-- SQL 语句片段 -->
filePattern="${logdir}/$${date:yyyy-MM-dd}/info.%d{yyyy-MM-dd-HH}.log" append="true"> <!-- SQL 语句片段 -->
<PatternLayout pattern="${PATTERN}"/> <!-- SQL 语句片段 -->
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/> <!-- SQL 语句片段 -->
<Policies> <!-- SQL 语句片段 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" /> <!-- SQL 语句片段 -->
</Policies> <!-- SQL 语句片段 -->
</RollingFile> <!-- SQL 语句片段 -->
<!--异步appender-->
<Async name="AsyncAppender" includeLocation="true"> <!-- SQL 语句片段 -->
<AppenderRef ref="ErrorAppender"/> <!-- SQL 语句片段 -->
<AppenderRef ref="DebugAppender"/> <!-- SQL 语句片段 -->
</Async> <!-- SQL 语句片段 -->
</Appenders> <!-- SQL 语句片段 -->
<Loggers> <!-- SQL 语句片段 -->
<!--过滤掉spring和mybatis的一些无用的debug信息
<logger name="org.springframework" level="INFO"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.mybatis" level="INFO"> <!-- SQL 语句片段 -->
</logger>--> <!-- SQL 语句片段 -->
<logger name="cn.itcast.wanxinp2p.consumer.mapper" level="DEBUG"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="springfox" level="INFO"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.apache.http" level="INFO"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="com.netflix.discovery" level="INFO"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="RocketmqCommon" level="INFO" > <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="RocketmqRemoting" level="INFO" > <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="RocketmqClient" level="WARN"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.dromara.hmily" level="WARN"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.dromara.hmily.lottery" level="WARN"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<logger name="org.dromara.hmily.bonuspoint" level="WARN"> <!-- SQL 语句片段 -->
</logger> <!-- SQL 语句片段 -->
<!--OFF 0-->
<!--FATAL 100-->
<!--ERROR 200-->
<!--WARN 300-->
<!--INFO 400-->
<!--DEBUG 500-->
<!--TRACE 600-->
<!--ALL Integer.MAX_VALUE-->
<Root level="DEBUG" includeLocation="true"> <!-- SQL 语句片段 -->
<AppenderRef ref="AsyncAppender"/> <!-- SQL 语句片段 -->
<AppenderRef ref="Console"/> <!-- SQL 语句片段 -->
<AppenderRef ref="DebugAppender"/> <!-- SQL 语句片段 -->
</Root> <!-- SQL 语句片段 -->
</Loggers> <!-- SQL 语句片段 -->
</Configuration> <!-- SQL 语句片段 -->
评论
0 条
还没有评论,先写一条吧。