32583 字
约 108 分钟
44
appendix_F
无标签

附录F 学习服务模块源码详解

模块概览(面向 0 基础读者):

  • 负责学员选课、课程表、学习记录以及播放鉴权。
  • 整合支付回调、课程服务,实现学习资格校验。
  • 提供学习端 API,支持 PC/移动端统一调用。

核心目录:

  • xuecheng-plus-learning/xuecheng-plus-learning-api/src/main/java/com/xuecheng/learning/api
  • xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/service
  • xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/feignclient
  • xuecheng-plus-learning/xuecheng-plus-learning-model/src/main/java/com/xuecheng/learning/model
  • xuecheng-plus-learning/xuecheng-plus-learning-api/src/main/resources

文件:xuecheng-plus-learning/api/main/com/xuecheng/learning/api/MyCourseTablesController.java

package com.xuecheng.learning.api; // 声明类所在的包路径

import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.learning.model.dto.MyCourseTableParams; // 导入 MyCourseTableParams 类
import com.xuecheng.learning.model.dto.XcChooseCourseDto; // 导入 XcChooseCourseDto 类
import com.xuecheng.learning.model.dto.XcCourseTablesDto; // 导入 XcCourseTablesDto 类
import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类
import com.xuecheng.learning.service.MyCourseTablesService; // 导入 MyCourseTablesService 类
import com.xuecheng.learning.util.SecurityUtil; // 导入 SecurityUtil 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
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.PostMapping; // 导入 PostMapping 类
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 我的课程表接口 // 保留原作者写的块注释
 * @date 2022/10/25 9:40 // 保留原作者写的块注释
 */ // 保留原作者写的块注释

@Api(value = "我的课程表接口", tags = "我的课程表接口") // 使用注解 @Api(value = "我的课程表接口", tags = "我的课程表接口")
@Slf4j // 使用注解 @Slf4j
@RestController // 使用注解 @RestController
public class MyCourseTablesController { // 定义 class MyCourseTablesController

    @Autowired // 使用注解 @Autowired
    MyCourseTablesService myCourseTablesService; // 执行语句


    @ApiOperation("添加选课") // 使用注解 @ApiOperation("添加选课")
    @PostMapping("/choosecourse/{courseId}") // 使用注解 @PostMapping("/choosecourse/{courseId}")
    public XcChooseCourseDto addChooseCourse(@PathVariable("courseId") Long courseId) { // 定义方法 addChooseCourse(...)

        //当前登录的用户 // 保留原作者写的行内注释
        SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
        if(user == null){ // 定义方法 方法(...)
            XueChengPlusException.cast("请登录"); // 执行语句
        } // 代码块结束
        //用户id // 保留原作者写的行内注释
        String userId = user.getId(); // 把 user.getId() 的返回值赋给 userId
        //添加选课 // 保留原作者写的行内注释
        XcChooseCourseDto xcChooseCourseDto = myCourseTablesService.addChooseCourse(userId, courseId); // 把 myCourseTablesService.addChooseCourse(userId, courseId) 赋值给 xcChooseCourseDto
        return xcChooseCourseDto; // 返回 xcChooseCourseDto
    } // 代码块结束

    @ApiOperation("查询学习资格") // 使用注解 @ApiOperation("查询学习资格")
    @PostMapping("/choosecourse/learnstatus/{courseId}") // 使用注解 @PostMapping("/choosecourse/learnstatus/{courseId}")
    public XcCourseTablesDto getLearnstatus(@PathVariable("courseId") Long courseId) { // 定义方法 getLearnstatus(...)
        //当前登录的用户 // 保留原作者写的行内注释
        SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
        if(user == null){ // 定义方法 方法(...)
            XueChengPlusException.cast("请登录"); // 执行语句
        } // 代码块结束
        //用户id // 保留原作者写的行内注释
        String userId = user.getId(); // 把 user.getId() 的返回值赋给 userId

        XcCourseTablesDto learningStatus = myCourseTablesService.getLearningStatus(userId, courseId); // 把 myCourseTablesService.getLearningStatus(userId, courseId) 赋值给 learningStatus

        return learningStatus; // 返回 learningStatus

    } // 代码块结束

    @ApiOperation("我的课程表") // 使用注解 @ApiOperation("我的课程表")
    @GetMapping("/mycoursetable") // 使用注解 @GetMapping("/mycoursetable")
    public PageResult<XcCourseTables> mycoursetable(MyCourseTableParams params) { // 定义方法 mycoursetable(...)
        //当前登录的用户 // 保留原作者写的行内注释
        SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
        if(user == null){ // 定义方法 方法(...)
            XueChengPlusException.cast("请登录"); // 执行语句
        } // 代码块结束
        //用户id // 保留原作者写的行内注释
        String userId = user.getId(); // 把 user.getId() 的返回值赋给 userId
        params.setUserId(userId); // 执行语句

        PageResult<XcCourseTables> mycoursetables = myCourseTablesService.mycoursetables(params); // 把 myCourseTablesService.mycoursetables(params) 赋值给 mycoursetables
        return mycoursetables; // 返回 mycoursetables
    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-learning/api/main/com/xuecheng/learning/api/MyLearningController.java

package com.xuecheng.learning.api; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类
import com.xuecheng.learning.service.LearningService; // 导入 LearningService 类
import com.xuecheng.learning.util.SecurityUtil; // 导入 SecurityUtil 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
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.RestController; // 导入 RestController 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 我的学习接口 // 保留原作者写的块注释
 * @date 2022/10/27 8:59 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Api(value = "学习过程管理接口", tags = "学习过程管理接口") // 使用注解 @Api(value = "学习过程管理接口", tags = "学习过程管理接口")
@Slf4j // 使用注解 @Slf4j
@RestController // 使用注解 @RestController
public class MyLearningController { // 定义 class MyLearningController

    @Autowired // 使用注解 @Autowired
    LearningService learningService; // 执行语句

    /** // 保留原作者写的块注释
     * // 保留原作者写的块注释
     * @param courseId 课程id // 保留原作者写的块注释
     * @param teachplanId 课程计划id // 保留原作者写的块注释
     * @param mediaId 媒资文件id // 保留原作者写的块注释
     * @return // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    @ApiOperation("获取视频") // 使用注解 @ApiOperation("获取视频")
    @GetMapping("/open/learn/getvideo/{courseId}/{teachplanId}/{mediaId}") // 使用注解 @GetMapping("/open/learn/getvideo/{courseId}/{teachplanId}/{mediaId}")
    public RestResponse<String> getvideo(@PathVariable("courseId") Long courseId, @PathVariable("teachplanId") Long teachplanId, @PathVariable("mediaId") String mediaId) { // 定义方法 getvideo(...)

        SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user

        String userId = user.getId(); // 把 user.getId() 的返回值赋给 userId

        //获取视频 // 保留原作者写的行内注释
        RestResponse<String> restResponse = learningService.getVideo(userId, courseId, teachplanId, mediaId); // 把 learningService.getVideo(userId, courseId, teachplanId, mediaId) 赋值给 restResponse

        return restResponse; // 返回 restResponse

    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-learning/api/main/com/xuecheng/learning/config/ResouceServerConfig.java

package com.xuecheng.learning.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 类

/** // 保留原作者写的块注释
 * @author Administrator // 保留原作者写的块注释
 * @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-learning/api/main/com/xuecheng/learning/config/TokenConfig.java

package com.xuecheng.learning.config; // 声明类所在的包路径

import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
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 类

/** // 保留原作者写的块注释
 * @author Administrator // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 **/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
public class TokenConfig { // 定义 class TokenConfig

    //jwt签名密钥,与认证服务保持一致 // 保留原作者写的行内注释
    private String SIGNING_KEY = "mq123"; // 把 "mq123" 赋值给 SIGNING_KEY

    @Bean // 使用注解 @Bean
    public TokenStore tokenStore() { // 定义方法 tokenStore(...)
        //JWT令牌存储方案 // 保留原作者写的行内注释
        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
    } // 代码块结束

   /* @Bean // 保留原作者写的块注释
    public TokenStore tokenStore() { // 定义方法 tokenStore(...)
        //使用内存存储令牌(普通令牌) // 保留原作者写的行内注释
        return new InMemoryTokenStore(); // 返回 new InMemoryTokenStore()
    }*/ // 代码逻辑
} // 代码块结束

文件:xuecheng-plus-learning/api/main/com/xuecheng/learning/util/SecurityUtil.java

package com.xuecheng.learning.util; // 声明类所在的包路径

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 用户身份信息获取工具类 // 保留原作者写的块注释
 * @date 2022/10/20 11:41 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
public class SecurityUtil { // 定义 class SecurityUtil

    public static XcUser getUser() { // 定义方法 getUser(...)
        //拿jwt中的用户身份 // 保留原作者写的行内注释
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); // 把 SecurityContextHolder.getContext().getAuthentication().getPrincipal() 的返回值赋给 principal

        if (principal instanceof String){ // 定义方法 方法(...)
            String jsonString = (String) principal; // 把 (String) principal 赋值给 jsonString
            XcUser xcUser = null; // 把变量 xcUser 初始化为 null
            try { // 尝试执行可能抛出异常的代码
                xcUser = JSON.parseObject(jsonString, XcUser.class); // 把 JSON.parseObject(jsonString, XcUser.class) 赋值给 xcUser
            } catch (Exception e) { // 定义方法 catch(...)
                log.debug("解析jwt中的用户身份无法转成XcUser对象:{}",jsonString); // 执行语句
            } // 代码块结束
            return xcUser; // 返回 xcUser

        } // 代码块结束
        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-learning/api/main/com/xuecheng/LearningApiApplication.java

package com.xuecheng; // 声明类所在的包路径

import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类
import org.springframework.cloud.openfeign.EnableFeignClients; // 导入 EnableFeignClients 类

@EnableFeignClients(basePackages={"com.xuecheng.*.feignclient"}) // 使用注解 @EnableFeignClients(basePackages={"com.xuecheng.*.feignclient"})
@SpringBootApplication // 使用注解 @SpringBootApplication
public class LearningApiApplication { // 定义 class LearningApiApplication

    public static void main(String[] args) { // 定义方法 main(...)
        SpringApplication.run(LearningApiApplication.class, args); // 执行语句
    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-learning/api/resources/bootstrap.yml


#微服务配置
spring:
  application:
    name: learning-api
  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: learning-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: feign-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true
          - data-id: rabbitmq-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true

  profiles:
    active: dev


文件:xuecheng-plus-learning/api/resources/log4j2-dev.xml

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

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

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

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

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

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

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

文件:xuecheng-plus-learning/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-learning</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>xuecheng-plus-learning-api</artifactId>
    <dependencies>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xuecheng-plus-learning-service</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId> <!-- 接入统一认证 -->
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
    </dependencies>
</project>

文件:xuecheng-plus-learning/model/com/xuecheng/learning/model/dto/MyCourseTableItemDto.java

package com.xuecheng.learning.model.dto; // 声明类所在的包路径

import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

import java.time.LocalDateTime; // 导入 LocalDateTime 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 我的课程查询条件 // 保留原作者写的块注释
 * @date 2022/10/6 9:42 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class MyCourseTableItemDto extends XcCourseTables { // 定义 class MyCourseTableItemDto

    /** // 保留原作者写的块注释
     * 最近学习时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime learnDate; // 执行语句

    /** // 保留原作者写的块注释
     * 学习时长 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long learnLength; // 执行语句

    /** // 保留原作者写的块注释
     * 章节id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long teachplanId; // 执行语句

    /** // 保留原作者写的块注释
     * 章节名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String teachplanName; // 执行语句


} // 代码块结束

文件:xuecheng-plus-learning/model/com/xuecheng/learning/model/dto/MyCourseTableParams.java

package com.xuecheng.learning.model.dto; // 声明类所在的包路径

import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

/** // 保留原作者写的块注释
 * @description 我的课程查询条件 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/10/6 9:42 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @Data // 使用注解 @Data
 @ToString // 使用注解 @ToString
public class MyCourseTableParams { // 定义 class MyCourseTableParams

     String userId; // 执行语句

   //课程类型  [{"code":"700001","desc":"免费课程"},{"code":"700002","desc":"收费课程"}] // 保留原作者写的行内注释
   private String courseType; // 执行语句

   //排序 1按学习时间进行排序 2按加入时间进行排序 // 保留原作者写的行内注释
   private String sortType; // 执行语句

   //1即将过期、2已经过期 // 保留原作者写的行内注释
   private String expiresType; // 执行语句

   int page=1; // 把 1 赋值给 page
   int startIndex; // 执行语句
   int size=4; // 把 4 赋值给 size

} // 代码块结束

文件:xuecheng-plus-learning/model/com/xuecheng/learning/model/dto/XcChooseCourseDto.java

package com.xuecheng.learning.model.dto; // 声明类所在的包路径

import com.xuecheng.learning.model.po.XcChooseCourse; // 导入 XcChooseCourse 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @date 2022/10/2 16:10 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class XcChooseCourseDto extends XcChooseCourse { // 定义 class XcChooseCourseDto

    //学习资格,[{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的行内注释
    public String learnStatus; // 执行语句

} // 代码块结束

文件:xuecheng-plus-learning/model/com/xuecheng/learning/model/dto/XcCourseTablesDto.java

package com.xuecheng.learning.model.dto; // 声明类所在的包路径

import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

/** // 保留原作者写的块注释
 * @description 我的课程表模型类 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/10/2 16:09 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class XcCourseTablesDto extends XcCourseTables { // 定义 class XcCourseTablesDto
    //学习资格,[{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的行内注释
    public String learnStatus; // 执行语句
} // 代码块结束

文件:xuecheng-plus-learning/model/com/xuecheng/learning/model/po/XcChooseCourse.java

package com.xuecheng.learning.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("xc_choose_course") // 使用注解 @TableName("xc_choose_course")
public class XcChooseCourse implements Serializable { // 定义 class XcChooseCourse

    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 courseId; // 执行语句

    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String courseName; // 执行语句

    /** // 保留原作者写的块注释
     * 用户id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String userId; // 执行语句

    /** // 保留原作者写的块注释
     * 机构id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long companyId; // 执行语句

    /** // 保留原作者写的块注释
     * 选课类型 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String orderType; // 执行语句

    /** // 保留原作者写的块注释
     * 添加时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    @TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createDate; // 执行语句

    /** // 保留原作者写的块注释
     * 课程有效期(天) // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Integer validDays; // 执行语句

    private Float coursePrice; // 执行语句

    /** // 保留原作者写的块注释
     * 选课状态 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String status; // 执行语句

    /** // 保留原作者写的块注释
     * 开始服务时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime validtimeStart; // 执行语句

    /** // 保留原作者写的块注释
     * 结束服务时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime validtimeEnd; // 执行语句

    /** // 保留原作者写的块注释
     * 备注 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String remarks; // 执行语句


} // 代码块结束

文件:xuecheng-plus-learning/model/com/xuecheng/learning/model/po/XcCourseTables.java

package com.xuecheng.learning.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("xc_course_tables") // 使用注解 @TableName("xc_course_tables")
public class XcCourseTables implements Serializable { // 定义 class XcCourseTables

    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 chooseCourseId; // 执行语句

    /** // 保留原作者写的块注释
     * 用户id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String userId; // 执行语句

    /** // 保留原作者写的块注释
     * 课程id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long courseId; // 执行语句

    /** // 保留原作者写的块注释
     * 机构id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long companyId; // 执行语句

    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String courseName; // 执行语句
    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String courseType; // 执行语句


    /** // 保留原作者写的块注释
     * 添加时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    @TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createDate; // 执行语句

    /** // 保留原作者写的块注释
     * 开始服务时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime validtimeStart; // 执行语句

    /** // 保留原作者写的块注释
     * 到期时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime validtimeEnd; // 执行语句

    /** // 保留原作者写的块注释
     * 更新时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime updateDate; // 执行语句

    /** // 保留原作者写的块注释
     * 备注 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String remarks; // 执行语句


} // 代码块结束

文件:xuecheng-plus-learning/model/com/xuecheng/learning/model/po/XcLearnRecord.java

package com.xuecheng.learning.model.po; // 声明类所在的包路径

import com.baomidou.mybatisplus.annotation.IdType; // 导入 IdType 类
import com.baomidou.mybatisplus.annotation.TableId; // 导入 TableId 类
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("xc_learn_record") // 使用注解 @TableName("xc_learn_record")
public class XcLearnRecord implements Serializable { // 定义 class XcLearnRecord

    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 courseId; // 执行语句

    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String courseName; // 执行语句

    /** // 保留原作者写的块注释
     * 用户id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String userId; // 执行语句

    /** // 保留原作者写的块注释
     * 最近学习时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime learnDate; // 执行语句

    /** // 保留原作者写的块注释
     * 学习时长 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long learnLength; // 执行语句

    /** // 保留原作者写的块注释
     * 章节id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long teachplanId; // 执行语句

    /** // 保留原作者写的块注释
     * 章节名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String teachplanName; // 执行语句


} // 代码块结束

文件:xuecheng-plus-learning/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-learning</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>xuecheng-plus-learning-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>
            <version>${mybatis-plus-boot-starter.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-core</artifactId>
            <version>${mybatis-plus-boot-starter.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId> <!-- 使用 Lombok 简化 PO/DTO -->
        </dependency>
    </dependencies>
</project>

文件:xuecheng-plus-learning/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 语句片段 -->
    <artifactId>xuecheng-plus-learning</artifactId> <!-- SQL 语句片段 -->
    <packaging>pom</packaging> <!-- SQL 语句片段 -->
    <modules> <!-- SQL 语句片段 -->
        <module>xuecheng-plus-learning-api</module> <!-- SQL 语句片段 -->
        <module>xuecheng-plus-learning-service</module> <!-- SQL 语句片段 -->
        <module>xuecheng-plus-learning-model</module> <!-- SQL 语句片段 -->
    </modules> <!-- SQL 语句片段 -->


</project> <!-- SQL 语句片段 -->

文件:xuecheng-plus-learning/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"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent> <!-- 继承父工程统一版本与插件管理 -->
        <artifactId>xuecheng-plus-parent</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../xuecheng-plus-parent</relativePath>
    </parent>
    <packaging>pom</packaging> <!-- 聚合模块本身不打包 -->
    <artifactId>xuecheng-plus-learning</artifactId> <!-- 学习服务父工程 -->
    <modules> <!-- 子模块列表 -->
        <module>xuecheng-plus-learning-api</module>
        <module>xuecheng-plus-learning-model</module>
        <module>xuecheng-plus-learning-service</module>
    </modules>
</project>

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/config/MybatisPlusConfig.java

package com.xuecheng.learning.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 类

/** // 保留原作者写的块注释
 * <P> // 保留原作者写的块注释
 * 		Mybatis-Plus 配置 // 保留原作者写的块注释
 * </p> // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
@MapperScan("com.xuecheng.learning.mapper") // 使用注解 @MapperScan("com.xuecheng.learning.mapper")
public class MybatisPlusConfig { // 定义 class MybatisPlusConfig
	/** // 保留原作者写的块注释
	 * 新的分页插件 // 保留原作者写的块注释
	 * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false // 保留原作者写的块注释
	 * 避免缓存出现问题(该属性会在旧插件移除后一同移除) // 保留原作者写的块注释
	 */ // 保留原作者写的块注释
	@Bean // 使用注解 @Bean
	public MybatisPlusInterceptor mybatisPlusInterceptor() { // 定义方法 mybatisPlusInterceptor(...)
		MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 创建 MybatisPlusInterceptor 对象并赋值给 interceptor
		interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 执行语句
		return interceptor; // 返回 interceptor
	} // 代码块结束


} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/config/PayNotifyConfig.java

package com.xuecheng.learning.config; // 声明类所在的包路径

import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.amqp.core.*; // 导入 * 类
import org.springframework.beans.factory.annotation.Qualifier; // 导入 Qualifier 类
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/23 16:59 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Configuration // 使用注解 @Configuration
public class PayNotifyConfig { // 定义 class PayNotifyConfig

    //交换机 // 保留原作者写的行内注释
    public static final String PAYNOTIFY_EXCHANGE_FANOUT = "paynotify_exchange_fanout"; // 把 "paynotify_exchange_fanout" 赋值给 PAYNOTIFY_EXCHANGE_FANOUT
    //支付结果通知消息类型 // 保留原作者写的行内注释
    public static final String MESSAGE_TYPE = "payresult_notify"; // 把 "payresult_notify" 赋值给 MESSAGE_TYPE
    //支付通知队列 // 保留原作者写的行内注释
    public static final String PAYNOTIFY_QUEUE = "paynotify_queue"; // 把 "paynotify_queue" 赋值给 PAYNOTIFY_QUEUE

    //声明交换机,且持久化 // 保留原作者写的行内注释
    @Bean(PAYNOTIFY_EXCHANGE_FANOUT) // 使用注解 @Bean(PAYNOTIFY_EXCHANGE_FANOUT)
    public FanoutExchange paynotify_exchange_fanout() { // 定义方法 paynotify_exchange_fanout(...)
        // 三个参数:交换机名称、是否持久化、当没有queue与其绑定时是否自动删除 // 保留原作者写的行内注释
        return new FanoutExchange(PAYNOTIFY_EXCHANGE_FANOUT, true, false); // 返回 new FanoutExchange(PAYNOTIFY_EXCHANGE_FANOUT, true, false)
    } // 代码块结束
    //支付通知队列,且持久化 // 保留原作者写的行内注释
    @Bean(PAYNOTIFY_QUEUE) // 使用注解 @Bean(PAYNOTIFY_QUEUE)
    public Queue course_publish_queue() { // 定义方法 course_publish_queue(...)
        return QueueBuilder.durable(PAYNOTIFY_QUEUE).build(); // 返回 QueueBuilder.durable(PAYNOTIFY_QUEUE).build()
    } // 代码块结束

    //交换机和支付通知队列绑定 // 保留原作者写的行内注释
    @Bean // 使用注解 @Bean
    public Binding binding_course_publish_queue(@Qualifier(PAYNOTIFY_QUEUE) Queue queue, @Qualifier(PAYNOTIFY_EXCHANGE_FANOUT) FanoutExchange exchange) { // 定义方法 binding_course_publish_queue(...)
        return BindingBuilder.bind(queue).to(exchange); // 返回 BindingBuilder.bind(queue).to(exchange)
    } // 代码块结束


} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/feignclient/ContentServiceClient.java

package com.xuecheng.learning.feignclient; // 声明类所在的包路径

import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import org.springframework.cloud.openfeign.FeignClient; // 导入 FeignClient 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.PathVariable; // 导入 PathVariable 类
import org.springframework.web.bind.annotation.ResponseBody; // 导入 ResponseBody 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 内容管理远程接口 // 保留原作者写的块注释
 * @date 2022/10/25 9:13 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@FeignClient(value = "content-api",fallbackFactory = ContentServiceClientFallbackFactory.class) // 使用注解 @FeignClient(value = "content-api",fallbackFactory = ContentServiceClientFallbackFactory.class)
public interface ContentServiceClient { // 定义 interface ContentServiceClient

    //查询已经发布的课程 // 保留原作者写的行内注释
    @ResponseBody // 使用注解 @ResponseBody
    @GetMapping("/content/r/coursepublish/{courseId}") // 使用注解 @GetMapping("/content/r/coursepublish/{courseId}")
    public CoursePublish getCoursepublish(@PathVariable("courseId") Long courseId); // 执行语句

} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/feignclient/ContentServiceClientFallbackFactory.java

package com.xuecheng.learning.feignclient; // 声明类所在的包路径

import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
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 2022/10/25 9:14 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class ContentServiceClientFallbackFactory implements FallbackFactory<ContentServiceClient> { // 定义 class ContentServiceClientFallbackFactory
    @Override // 使用注解 @Override
    public ContentServiceClient create(Throwable throwable) { // 定义方法 create(...)
        return new ContentServiceClient() { // 定义方法 ContentServiceClient(...)

            @Override // 使用注解 @Override
            public CoursePublish getCoursepublish(Long courseId) { // 定义方法 getCoursepublish(...)
                log.error("调用内容管理服务发生熔断:{}", throwable.toString(),throwable); // 执行语句
                return null; // 返回 null
            } // 代码块结束
        }; // 执行语句
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/feignclient/MediaServiceClient.java

package com.xuecheng.learning.feignclient; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类
import org.springframework.cloud.openfeign.FeignClient; // 导入 FeignClient 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.PathVariable; // 导入 PathVariable 类
import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 类

/** // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/10/27 9:04 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @FeignClient(value = "media-api",fallbackFactory = MediaServiceClientFallbackFactory.class) // 使用注解 @FeignClient(value = "media-api",fallbackFactory = MediaServiceClientFallbackFactory.class)
 @RequestMapping("/media") // 使用注解 @RequestMapping("/media")
 public interface MediaServiceClient { // 定义 interface MediaServiceClient

  @GetMapping("/open/preview/{mediaId}") // 使用注解 @GetMapping("/open/preview/{mediaId}")
  public RestResponse<String> getPlayUrlByMediaId(@PathVariable("mediaId") String mediaId); // 执行语句

 } // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/feignclient/MediaServiceClientFallbackFactory.java

package com.xuecheng.learning.feignclient; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类
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 2022/10/27 9:05 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class MediaServiceClientFallbackFactory implements FallbackFactory<MediaServiceClient> { // 定义 class MediaServiceClientFallbackFactory
    @Override // 使用注解 @Override
    public MediaServiceClient create(Throwable throwable) { // 定义方法 create(...)
        return new MediaServiceClient() { // 定义方法 MediaServiceClient(...)
            @Override // 使用注解 @Override
            public RestResponse<String> getPlayUrlByMediaId(String mediaId) { // 定义方法 getPlayUrlByMediaId(...)
                log.error("远程调用媒资管理服务熔断异常:{}", throwable.getMessage()); // 执行语句
                return null; // 返回 null
            } // 代码块结束
        }; // 执行语句
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/mapper/XcChooseCourseMapper.java

package com.xuecheng.learning.mapper; // 声明类所在的包路径

import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.learning.model.po.XcChooseCourse; // 导入 XcChooseCourse 类

/** // 保留原作者写的块注释
 * <p> // 保留原作者写的块注释
 *  Mapper 接口 // 保留原作者写的块注释
 * </p> // 保留原作者写的块注释
 * // 保留原作者写的块注释
 * @author itcast // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface XcChooseCourseMapper extends BaseMapper<XcChooseCourse> { // 定义 interface XcChooseCourseMapper

} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/mapper/XcChooseCourseMapper.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.learning.mapper.XcChooseCourseMapper"> <!-- MyBatis 映射文件的根标签 -->

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.xuecheng.learning.model.po.XcChooseCourse"> <!-- 定义结果映射 -->
        <id column="id" property="id" /> <!-- 主键列的映射规则 -->
        <result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
        <result column="course_name" property="courseName" /> <!-- 字段与属性的映射规则 -->
        <result column="user_id" property="userId" /> <!-- 字段与属性的映射规则 -->
        <result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
        <result column="order_type" property="orderType" /> <!-- 字段与属性的映射规则 -->
        <result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
        <result column="valid_days" property="validDays" /> <!-- 字段与属性的映射规则 -->
        <result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
        <result column="validtime_start" property="validtimeStart" /> <!-- 字段与属性的映射规则 -->
        <result column="validtime_end" property="validtimeEnd" /> <!-- 字段与属性的映射规则 -->
        <result column="remarks" property="remarks" /> <!-- 字段与属性的映射规则 -->
    </resultMap> <!-- 结束 resultMap 区块 -->

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
        id, course_id, course_name, user_id, company_id, order_type, create_date, valid_days, status, validtime_start, validtime_end, remarks <!-- SQL 语句片段 -->
    </sql> <!-- 结束 SQL 片段 -->

</mapper> <!-- 结束 mapper 标签 -->

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/mapper/XcCourseTablesMapper.java

package com.xuecheng.learning.mapper; // 声明类所在的包路径

import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类

/** // 保留原作者写的块注释
 * <p> // 保留原作者写的块注释
 *  Mapper 接口 // 保留原作者写的块注释
 * </p> // 保留原作者写的块注释
 * // 保留原作者写的块注释
 * @author itcast // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface XcCourseTablesMapper extends BaseMapper<XcCourseTables> { // 定义 interface XcCourseTablesMapper

} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/mapper/XcCourseTablesMapper.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.learning.mapper.XcCourseTablesMapper"> <!-- MyBatis 映射文件的根标签 -->

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.xuecheng.learning.model.po.XcCourseTables"> <!-- 定义结果映射 -->
        <id column="id" property="id" /> <!-- 主键列的映射规则 -->
        <result column="choose_course_id" property="chooseCourseId" /> <!-- 字段与属性的映射规则 -->
        <result column="user_id" property="userId" /> <!-- 字段与属性的映射规则 -->
        <result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
        <result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
        <result column="course_name" property="courseName" /> <!-- 字段与属性的映射规则 -->
        <result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
        <result column="validtime_end" property="validtimeEnd" /> <!-- 字段与属性的映射规则 -->
        <result column="update_date" property="updateDate" /> <!-- 字段与属性的映射规则 -->
        <result column="remarks" property="remarks" /> <!-- 字段与属性的映射规则 -->
    </resultMap> <!-- 结束 resultMap 区块 -->

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
        id, choose_course_id, user_id, course_id, company_id, course_name, create_date, validtime_end, update_date, remarks <!-- SQL 语句片段 -->
    </sql> <!-- 结束 SQL 片段 -->

</mapper> <!-- 结束 mapper 标签 -->

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/service/impl/LearningServiceImpl.java

package com.xuecheng.learning.service.impl; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.learning.feignclient.ContentServiceClient; // 导入 ContentServiceClient 类
import com.xuecheng.learning.feignclient.MediaServiceClient; // 导入 MediaServiceClient 类
import com.xuecheng.learning.model.dto.XcCourseTablesDto; // 导入 XcCourseTablesDto 类
import com.xuecheng.learning.service.LearningService; // 导入 LearningService 类
import com.xuecheng.learning.service.MyCourseTablesService; // 导入 MyCourseTablesService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 在线学习接口 // 保留原作者写的块注释
 * @date 2023/2/28 10:20 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class LearningServiceImpl implements LearningService { // 定义 class LearningServiceImpl

    @Autowired // 使用注解 @Autowired
    MyCourseTablesService myCourseTablesService; // 执行语句

    @Autowired // 使用注解 @Autowired
    ContentServiceClient contentServiceClient; // 执行语句

    @Autowired // 使用注解 @Autowired
    MediaServiceClient mediaServiceClient; // 执行语句

    @Override // 使用注解 @Override
    public RestResponse<String> getVideo(String userId, Long courseId, Long teachplanId, String mediaId) { // 定义方法 getVideo(...)

        //查询课程信息 // 保留原作者写的行内注释
        CoursePublish coursepublish = contentServiceClient.getCoursepublish(courseId); // 把 contentServiceClient.getCoursepublish(courseId) 赋值给 coursepublish
        //判断如果为null不再继续 // 保留原作者写的行内注释
        if(coursepublish == null){ // 定义方法 方法(...)
            return RestResponse.validfail("课程不存在"); // 返回 RestResponse.validfail("课程不存在")
        } // 代码块结束

        //远程调用内容管理服务根据课程计划id(teachplanId)去查询课程计划信息,如果is_preview的值为1表示支持试学 // 保留原作者写的行内注释
        //也可以从coursepublish对象中解析出课程计划信息去判断是否支持试学 // 保留原作者写的行内注释
        //todo:如果支持试学调用媒资服务查询视频的播放地址,返回 // 保留原作者写的行内注释

        //用户已登录 // 保留原作者写的行内注释
        if(StringUtils.isNotEmpty(userId)){ // 定义方法 方法(...)
            //获取学习资格 // 保留原作者写的行内注释
            XcCourseTablesDto learningStatus = myCourseTablesService.getLearningStatus(userId, courseId); // 把 myCourseTablesService.getLearningStatus(userId, courseId) 赋值给 learningStatus
            //学习资格,[{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的行内注释
            String learnStatus = learningStatus.getLearnStatus(); // 把 learningStatus.getLearnStatus() 的返回值赋给 learnStatus
            if("702002".equals(learnStatus)){ // 定义方法 方法(...)
                return RestResponse.validfail("无法学习,因为没有选课或选课后没有支付"); // 返回 RestResponse.validfail("无法学习,因为没有选课或选课后没有支付")
            }else if("702003".equals(learnStatus)){ // 定义方法 if(...)
                return RestResponse.validfail("已过期需要申请续期或重新支付"); // 返回 RestResponse.validfail("已过期需要申请续期或重新支付")
            }else{ // 代码逻辑
                //有资格学习,要返回视频的播放地址 // 保留原作者写的行内注释
                //程调用媒资获取视频播放地址 // 保留原作者写的行内注释
                RestResponse<String> playUrlByMediaId = mediaServiceClient.getPlayUrlByMediaId(mediaId); // 把 mediaServiceClient.getPlayUrlByMediaId(mediaId) 赋值给 playUrlByMediaId
                return playUrlByMediaId; // 返回 playUrlByMediaId

            } // 代码块结束

        } // 代码块结束
        //如果用户没有登录 // 保留原作者写的行内注释
       //取出课程的收费规则 // 保留原作者写的行内注释
        String charge = coursepublish.getCharge(); // 把 coursepublish.getCharge() 的返回值赋给 charge
        if("201000".equals(charge)){ // 定义方法 方法(...)
            //有资格学习,要返回视频的播放地址 // 保留原作者写的行内注释
            //远程调用媒资获取视频播放地址 // 保留原作者写的行内注释
            RestResponse<String> playUrlByMediaId = mediaServiceClient.getPlayUrlByMediaId(mediaId); // 把 mediaServiceClient.getPlayUrlByMediaId(mediaId) 赋值给 playUrlByMediaId
            return playUrlByMediaId; // 返回 playUrlByMediaId
        } // 代码块结束
        return RestResponse.validfail("课程需要购买"); // 返回 RestResponse.validfail("课程需要购买")
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/service/impl/MyCourseTablesServiceImpl.java

package com.xuecheng.learning.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.PageResult; // 导入 PageResult 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.learning.feignclient.ContentServiceClient; // 导入 ContentServiceClient 类
import com.xuecheng.learning.mapper.XcChooseCourseMapper; // 导入 XcChooseCourseMapper 类
import com.xuecheng.learning.mapper.XcCourseTablesMapper; // 导入 XcCourseTablesMapper 类
import com.xuecheng.learning.model.dto.MyCourseTableParams; // 导入 MyCourseTableParams 类
import com.xuecheng.learning.model.dto.XcChooseCourseDto; // 导入 XcChooseCourseDto 类
import com.xuecheng.learning.model.dto.XcCourseTablesDto; // 导入 XcCourseTablesDto 类
import com.xuecheng.learning.model.po.XcChooseCourse; // 导入 XcChooseCourse 类
import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类
import com.xuecheng.learning.service.MyCourseTablesService; // 导入 MyCourseTablesService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
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.time.LocalDateTime; // 导入 LocalDateTime 类
import java.util.List; // 导入 List 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 选课相关接口实现 // 保留原作者写的块注释
 * @date 2023/2/25 12:02 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class MyCourseTablesServiceImpl implements MyCourseTablesService { // 定义 class MyCourseTablesServiceImpl

    @Autowired // 使用注解 @Autowired
    XcChooseCourseMapper chooseCourseMapper; // 执行语句

    @Autowired // 使用注解 @Autowired
    XcCourseTablesMapper courseTablesMapper; // 执行语句

    @Autowired // 使用注解 @Autowired
    ContentServiceClient contentServiceClient; // 执行语句

    // 添加选课 // 保留原作者写的行内注释
    @Transactional // 使用注解 @Transactional
    @Override // 使用注解 @Override
    public XcChooseCourseDto addChooseCourse(String userId, Long courseId) { // 定义方法 addChooseCourse(...)

        //选课调用内容管理查询课程的收费规则 // 保留原作者写的行内注释
        CoursePublish coursepublish = contentServiceClient.getCoursepublish(courseId); // 把 contentServiceClient.getCoursepublish(courseId) 赋值给 coursepublish
        if(coursepublish == null){ // 定义方法 方法(...)
            XueChengPlusException.cast("课程不存在"); // 执行语句
        } // 代码块结束
        //收费规则 // 保留原作者写的行内注释
        String charge = coursepublish.getCharge(); // 把 coursepublish.getCharge() 的返回值赋给 charge
        //选课记录 // 保留原作者写的行内注释
        XcChooseCourse chooseCourse = null; // 把变量 chooseCourse 初始化为 null
        if("201000".equals(charge)){//免费课程 // 定义方法 方法(...)
            //向选课记录表写 // 保留原作者写的行内注释
            chooseCourse = addFreeCoruse(userId, coursepublish); // 把 addFreeCoruse(userId, coursepublish) 赋值给 chooseCourse
            //向我的课程表写 // 保留原作者写的行内注释
            XcCourseTables xcCourseTables = addCourseTabls(chooseCourse); // 把 addCourseTabls(chooseCourse) 赋值给 xcCourseTables

        }else{ // 代码逻辑
            //如果收费课程,会向选课记录表写数据 // 保留原作者写的行内注释
            chooseCourse = addChargeCoruse(userId, coursepublish); // 把 addChargeCoruse(userId, coursepublish) 赋值给 chooseCourse
        } // 代码块结束

        //判断学生的学习资格 // 保留原作者写的行内注释
        XcCourseTablesDto xcCourseTablesDto = getLearningStatus(userId, courseId); // 把 getLearningStatus(userId, courseId) 赋值给 xcCourseTablesDto

        //构造返回值 // 保留原作者写的行内注释
        XcChooseCourseDto xcChooseCourseDto = new XcChooseCourseDto(); // 创建 XcChooseCourseDto 对象并赋值给 xcChooseCourseDto
        BeanUtils.copyProperties(chooseCourse,xcChooseCourseDto); // 执行语句
        //设置学习资格状态 // 保留原作者写的行内注释
        xcChooseCourseDto.setLearnStatus(xcCourseTablesDto.getLearnStatus()); // 执行语句

        return xcChooseCourseDto; // 返回 xcChooseCourseDto
    } // 代码块结束

    //返回//学习资格,[{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的行内注释
    @Override // 使用注解 @Override
    public XcCourseTablesDto getLearningStatus(String userId, Long courseId) { // 定义方法 getLearningStatus(...)
        //返回的结果 // 保留原作者写的行内注释
        XcCourseTablesDto courseTablesDto = new XcCourseTablesDto(); // 创建 XcCourseTablesDto 对象并赋值给 courseTablesDto

        //查询我的课程表,如果查不到说明没有选课 // 保留原作者写的行内注释
        XcCourseTables xcCourseTables = getXcCourseTables(userId, courseId); // 把 getXcCourseTables(userId, courseId) 赋值给 xcCourseTables
        if(xcCourseTables == null){ // 定义方法 方法(...)
            //"code":"702002","desc":"没有选课或选课后没有支付" // 保留原作者写的行内注释
            courseTablesDto.setLearnStatus("702002"); // 执行语句
            return courseTablesDto; // 返回 courseTablesDto
        } // 代码块结束
        //如果查到了,判断是否过期,如果过期不能继续学习,没有过期可以继续学习 // 保留原作者写的行内注释

        boolean before = xcCourseTables.getValidtimeEnd().isBefore(LocalDateTime.now()); // 把 xcCourseTables.getValidtimeEnd().isBefore(LocalDateTime.now()) 赋值给 before
        if(before){ // 定义方法 方法(...)
            //"code":"702003","desc":"已过期需要申请续期或重新支付" // 保留原作者写的行内注释
            BeanUtils.copyProperties(xcCourseTables,courseTablesDto); // 执行语句
            courseTablesDto.setLearnStatus("702003"); // 执行语句
            return courseTablesDto; // 返回 courseTablesDto
        }else{ // 代码逻辑
            //"code":"702001","desc":"正常学习" // 保留原作者写的行内注释
            BeanUtils.copyProperties(xcCourseTables,courseTablesDto); // 执行语句
            courseTablesDto.setLearnStatus("702001"); // 执行语句
            return courseTablesDto; // 返回 courseTablesDto
        } // 代码块结束

    } // 代码块结束

    // 支付完毕添加到课程表 // 保留原作者写的行内注释
    @Override // 使用注解 @Override
    public boolean saveChooseCourseSuccess(String chooseCourseId) { // 定义方法 saveChooseCourseSuccess(...)

        //根据选课id查询选课表 // 保留原作者写的行内注释
        XcChooseCourse chooseCourse = chooseCourseMapper.selectById(chooseCourseId); // 把 chooseCourseMapper.selectById(chooseCourseId) 赋值给 chooseCourse
        if(chooseCourse == null){ // 定义方法 方法(...)
            log.debug("接收购买课程的消息,根据选课id从数据库找不到选课记录,选课id:{}",chooseCourseId); // 执行语句
            return false; // 返回 false
        } // 代码块结束
        //选课状态 // 保留原作者写的行内注释
        String status = chooseCourse.getStatus(); // 把 chooseCourse.getStatus() 的返回值赋给 status
        //只有当未支付时才更新为已支付 // 保留原作者写的行内注释
        if("701002".equals(status)){ // 定义方法 方法(...)
            //更新选课记录的状态为支付成功 // 保留原作者写的行内注释
            chooseCourse.setStatus("701001"); // 执行语句
            int i = chooseCourseMapper.updateById(chooseCourse); // 把 chooseCourseMapper.updateById(chooseCourse) 赋值给 i
            if(i<=0){ // 定义方法 方法(...)
                log.debug("添加选课记录失败:{}",chooseCourse); // 执行语句
                XueChengPlusException.cast("添加选课记录失败"); // 执行语句
            } // 代码块结束

            //向我的课程表插入记录 // 保留原作者写的行内注释
            XcCourseTables xcCourseTables = addCourseTabls(chooseCourse); // 把 addCourseTabls(chooseCourse) 赋值给 xcCourseTables
            return true; // 返回 true
        } // 代码块结束


        return false; // 返回 false
    } // 代码块结束

    // 分页 // 保留原作者写的行内注释
    @Override // 使用注解 @Override
    public PageResult<XcCourseTables> mycoursetables(MyCourseTableParams params) { // 定义方法 mycoursetables(...)
        //用户id // 保留原作者写的行内注释
        String userId = params.getUserId(); // 把 params.getUserId() 的返回值赋给 userId
        //当前页码 // 保留原作者写的行内注释
        int pageNo = params.getPage(); // 把 params.getPage() 的返回值赋给 pageNo
        //每页记录数 // 保留原作者写的行内注释
        int size = params.getSize(); // 把 params.getSize() 的返回值赋给 size

        Page<XcCourseTables> courseTablesPage = new Page<>(pageNo, size); // 创建 Page<> 对象并赋值给 courseTablesPage
        LambdaQueryWrapper<XcCourseTables> lambdaQueryWrapper = new LambdaQueryWrapper<XcCourseTables>().eq(XcCourseTables::getUserId, userId); // 创建 LambdaQueryWrapper<XcCourseTables> 对象并赋值给 lambdaQueryWrapper

        //查询数据 // 保留原作者写的行内注释
        Page<XcCourseTables> result = courseTablesMapper.selectPage(courseTablesPage, lambdaQueryWrapper); // 把 courseTablesMapper.selectPage(courseTablesPage, lambdaQueryWrapper) 赋值给 result

        //数据列表 // 保留原作者写的行内注释
        List<XcCourseTables> records = result.getRecords(); // 把 result.getRecords() 的返回值赋给 records
        //总记录数 // 保留原作者写的行内注释
        long total = result.getTotal(); // 把 result.getTotal() 的返回值赋给 total

        //List<T> items, long counts, long page, long pageSize // 保留原作者写的行内注释
        PageResult pageResult = new PageResult(records, total, pageNo, size); // 创建 PageResult 对象并赋值给 pageResult

        return pageResult; // 返回 pageResult
    } // 代码块结束


    //添加免费课程,免费课程加入选课记录表、我的课程表 // 保留原作者写的行内注释
    public XcChooseCourse addFreeCoruse(String userId, CoursePublish coursepublish) { // 定义方法 addFreeCoruse(...)
        //课程id // 保留原作者写的行内注释
        Long courseId = coursepublish.getId(); // 把 coursepublish.getId() 的返回值赋给 courseId
        //判断,如果存在免费的选课记录且选课状态为成功,直接返回了 // 保留原作者写的行内注释
        LambdaQueryWrapper<XcChooseCourse> queryWrapper = new LambdaQueryWrapper<XcChooseCourse>().eq(XcChooseCourse::getUserId, userId) // 代码逻辑
                .eq(XcChooseCourse::getCourseId, courseId) // 代码逻辑
                .eq(XcChooseCourse::getOrderType, "700001")//免费课程 // 代码逻辑
                .eq(XcChooseCourse::getStatus, "701001");//选课成功 // 执行语句
        List<XcChooseCourse> xcChooseCourses = chooseCourseMapper.selectList(queryWrapper); // 把 chooseCourseMapper.selectList(queryWrapper) 赋值给 xcChooseCourses
        if(xcChooseCourses.size()>0){ // 定义方法 方法(...)
            return xcChooseCourses.get(0); // 返回 xcChooseCourses.get(0)
        } // 代码块结束

        //向选课记录表写数据 // 保留原作者写的行内注释
        XcChooseCourse chooseCourse = new XcChooseCourse(); // 创建 XcChooseCourse 对象并赋值给 chooseCourse

        chooseCourse.setCourseId(courseId); // 执行语句
        chooseCourse.setCourseName(coursepublish.getName()); // 执行语句
        chooseCourse.setUserId(userId); // 执行语句
        chooseCourse.setCompanyId(coursepublish.getCompanyId()); // 执行语句
        chooseCourse.setOrderType("700001");//免费课程 // 执行语句
        chooseCourse.setCreateDate(LocalDateTime.now()); // 执行语句
        chooseCourse.setCoursePrice(coursepublish.getPrice()); // 执行语句
        chooseCourse.setValidDays(365); // 执行语句
        chooseCourse.setStatus("701001");//选课成功 // 执行语句
        chooseCourse.setValidtimeStart(LocalDateTime.now());//有效期的开始时间 // 执行语句
        chooseCourse.setValidtimeEnd(LocalDateTime.now().plusDays(365));//有效期的结束时间 // 执行语句

        int insert = chooseCourseMapper.insert(chooseCourse); // 把 chooseCourseMapper.insert(chooseCourse) 赋值给 insert
        if(insert<=0){ // 定义方法 方法(...)
            XueChengPlusException.cast("添加选课记录失败"); // 执行语句
        } // 代码块结束

        return chooseCourse; // 返回 chooseCourse
    } // 代码块结束

    //添加到我的课程表 // 保留原作者写的行内注释
    public XcCourseTables addCourseTabls(XcChooseCourse xcChooseCourse){ // 定义方法 addCourseTabls(...)

        //选课成功了才可以向我的课程表添加 // 保留原作者写的行内注释
        String status = xcChooseCourse.getStatus(); // 把 xcChooseCourse.getStatus() 的返回值赋给 status
        if(!"701001".equals(status)){ // 定义方法 方法(...)
            XueChengPlusException.cast("选课没有成功无法添加到课程表"); // 执行语句
        } // 代码块结束
        XcCourseTables xcCourseTables = getXcCourseTables(xcChooseCourse.getUserId(), xcChooseCourse.getCourseId()); // 把 getXcCourseTables(xcChooseCourse.getUserId(), xcChooseCourse.getCourseId()) 赋值给 xcCourseTables
        if(xcCourseTables!=null){ // 定义方法 方法(...)
            return xcCourseTables; // 返回 xcCourseTables
        } // 代码块结束

        xcCourseTables = new XcCourseTables(); // 创建 XcCourseTables 对象并赋值给 xcCourseTables
        BeanUtils.copyProperties(xcChooseCourse,xcCourseTables); // 执行语句
        xcCourseTables.setChooseCourseId(xcChooseCourse.getId());//记录选课表的逐渐 // 执行语句
        xcCourseTables.setCourseType(xcChooseCourse.getOrderType());//选课类型 // 执行语句
        xcCourseTables.setUpdateDate(LocalDateTime.now()); // 执行语句
        int insert = courseTablesMapper.insert(xcCourseTables); // 把 courseTablesMapper.insert(xcCourseTables) 赋值给 insert
        if(insert<=0){ // 定义方法 方法(...)
            XueChengPlusException.cast("添加我的课程表失败"); // 执行语句
        } // 代码块结束

        return xcCourseTables; // 返回 xcCourseTables
    } // 代码块结束

    /** // 保留原作者写的块注释
     * @description 根据课程和用户查询我的课程表中某一门课程 // 保留原作者写的块注释
     * @param userId // 保留原作者写的块注释
     * @param courseId // 保留原作者写的块注释
     * @return com.xuecheng.learning.model.po.XcCourseTables // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/10/2 17:07 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public XcCourseTables getXcCourseTables(String userId,Long courseId){ // 定义方法 getXcCourseTables(...)
        XcCourseTables xcCourseTables = courseTablesMapper.selectOne(new LambdaQueryWrapper<XcCourseTables>().eq(XcCourseTables::getUserId, userId).eq(XcCourseTables::getCourseId, courseId)); // 把 courseTablesMapper.selectOne(new LambdaQueryWrapper<XcCourseTables>().eq(XcCourseTables::getUserId, userId).eq(XcCourseTables::getCourseId, courseId)) 赋值给 xcCourseTables
        return xcCourseTables; // 返回 xcCourseTables

    } // 代码块结束


    //添加收费课程 // 保留原作者写的行内注释
    public XcChooseCourse addChargeCoruse(String userId,CoursePublish coursepublish){ // 定义方法 addChargeCoruse(...)

        //课程id // 保留原作者写的行内注释
        Long courseId = coursepublish.getId(); // 把 coursepublish.getId() 的返回值赋给 courseId
        //判断,如果存在收费的选课记录且选课状态为待支付,直接返回了 // 保留原作者写的行内注释
        LambdaQueryWrapper<XcChooseCourse> queryWrapper = new LambdaQueryWrapper<XcChooseCourse>().eq(XcChooseCourse::getUserId, userId) // 代码逻辑
                .eq(XcChooseCourse::getCourseId, courseId) // 代码逻辑
                .eq(XcChooseCourse::getOrderType, "700002")//收费课程 // 代码逻辑
                .eq(XcChooseCourse::getStatus, "701002");//待支付 // 执行语句
        List<XcChooseCourse> xcChooseCourses = chooseCourseMapper.selectList(queryWrapper); // 把 chooseCourseMapper.selectList(queryWrapper) 赋值给 xcChooseCourses
        if(xcChooseCourses.size()>0){ // 定义方法 方法(...)
            return xcChooseCourses.get(0); // 返回 xcChooseCourses.get(0)
        } // 代码块结束

        //向选课记录表写数据 // 保留原作者写的行内注释
        XcChooseCourse chooseCourse = new XcChooseCourse(); // 创建 XcChooseCourse 对象并赋值给 chooseCourse

        chooseCourse.setCourseId(courseId); // 执行语句
        chooseCourse.setCourseName(coursepublish.getName()); // 执行语句
        chooseCourse.setUserId(userId); // 执行语句
        chooseCourse.setCompanyId(coursepublish.getCompanyId()); // 执行语句
        chooseCourse.setOrderType("700002");//收费课程 // 执行语句
        chooseCourse.setCreateDate(LocalDateTime.now()); // 执行语句
        chooseCourse.setCoursePrice(coursepublish.getPrice()); // 执行语句
        chooseCourse.setValidDays(365); // 执行语句
        chooseCourse.setStatus("701002");//待支付 // 执行语句
        chooseCourse.setValidtimeStart(LocalDateTime.now());//有效期的开始时间 // 执行语句
        chooseCourse.setValidtimeEnd(LocalDateTime.now().plusDays(365));//有效期的结束时间 // 执行语句

        int insert = chooseCourseMapper.insert(chooseCourse); // 把 chooseCourseMapper.insert(chooseCourse) 赋值给 insert
        if(insert<=0){ // 定义方法 方法(...)
            XueChengPlusException.cast("添加选课记录失败"); // 执行语句
        } // 代码块结束

        return chooseCourse; // 返回 chooseCourse

    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/service/impl/ReceivePayNotifyService.java

package com.xuecheng.learning.service.impl; // 声明类所在的包路径

import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.learning.config.PayNotifyConfig; // 导入 PayNotifyConfig 类
import com.xuecheng.learning.service.MyCourseTablesService; // 导入 MyCourseTablesService 类
import com.xuecheng.messagesdk.model.po.MqMessage; // 导入 MqMessage 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.amqp.core.Message; // 导入 Message 类
import org.springframework.amqp.rabbit.annotation.RabbitListener; // 导入 RabbitListener 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 接收消息通知处理类 // 保留原作者写的块注释
 * @date 2023/2/26 16:42 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class ReceivePayNotifyService { // 定义 class ReceivePayNotifyService

    @Autowired // 使用注解 @Autowired
    MyCourseTablesService myCourseTablesService; // 执行语句


    @RabbitListener(queues = PayNotifyConfig.PAYNOTIFY_QUEUE) // 使用注解 @RabbitListener(queues = PayNotifyConfig.PAYNOTIFY_QUEUE)
    public void receive(Message message) { // 定义方法 receive(...)

        try { // 尝试执行可能抛出异常的代码
            Thread.sleep(5000); // 执行语句
        } catch (InterruptedException e) { // 定义方法 catch(...)
            e.printStackTrace(); // 执行语句
        } // 代码块结束

        //解析出消息 // 保留原作者写的行内注释
        byte[] body = message.getBody(); // 把 message.getBody() 的返回值赋给 body
        String jsonString = new String(body); // 创建 String 对象并赋值给 jsonString
        //转成对象 // 保留原作者写的行内注释
        MqMessage mqMessage = JSON.parseObject(jsonString, MqMessage.class); // 把 JSON.parseObject(jsonString, MqMessage.class) 赋值给 mqMessage
        //解析消息的内容 // 保留原作者写的行内注释
        //选课id // 保留原作者写的行内注释
        String chooseCourseId = mqMessage.getBusinessKey1(); // 把 mqMessage.getBusinessKey1() 的返回值赋给 chooseCourseId
        //订单类型 // 保留原作者写的行内注释
        String orderType = mqMessage.getBusinessKey2(); // 把 mqMessage.getBusinessKey2() 的返回值赋给 orderType
        //学习中心服务只要购买课程类的支付订单的结果 // 保留原作者写的行内注释
        if (orderType.equals("60201")) { // 定义方法 方法(...)
            //根据消息内容,更新选课记录、向我的课程表插入记录 // 保留原作者写的行内注释
            boolean b = myCourseTablesService.saveChooseCourseSuccess(chooseCourseId); // 把 myCourseTablesService.saveChooseCourseSuccess(chooseCourseId) 赋值给 b
            if (!b) { // 定义方法 方法(...)
                XueChengPlusException.cast("保证选课记录状态失败"); // 执行语句
            } // 代码块结束


        } // 代码块结束


    } // 代码块结束


} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/service/LearningService.java

package com.xuecheng.learning.service; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 在线学习相关的接口 // 保留原作者写的块注释
 * @date 2023/2/28 10:17 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface LearningService { // 定义 interface LearningService

    /** // 保留原作者写的块注释
     * @description 获取教学视频 // 保留原作者写的块注释
     * @param courseId 课程id // 保留原作者写的块注释
     * @param teachplanId 课程计划id // 保留原作者写的块注释
     * @param mediaId 视频文件id // 保留原作者写的块注释
     * @return com.xuecheng.base.model.RestResponse<java.lang.String> // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/10/5 9:08 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public RestResponse<String> getVideo(String userId, Long courseId, Long teachplanId, String mediaId); // 执行语句

} // 代码块结束

文件:xuecheng-plus-learning/service/main/com/xuecheng/learning/service/MyCourseTablesService.java

package com.xuecheng.learning.service; // 声明类所在的包路径

import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.learning.model.dto.MyCourseTableParams; // 导入 MyCourseTableParams 类
import com.xuecheng.learning.model.dto.XcChooseCourseDto; // 导入 XcChooseCourseDto 类
import com.xuecheng.learning.model.dto.XcCourseTablesDto; // 导入 XcCourseTablesDto 类
import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 选课相关的接口 // 保留原作者写的块注释
 * @date 2023/2/25 12:00 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface MyCourseTablesService { // 定义 interface MyCourseTablesService

    /** // 保留原作者写的块注释
     * @description 添加选课 // 保留原作者写的块注释
     * @param userId 用户id // 保留原作者写的块注释
     * @param courseId 课程id // 保留原作者写的块注释
     * @return com.xuecheng.learning.model.dto.XcChooseCourseDto // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * 响应选课结果 // 保留原作者写的块注释
     * @date 2022/10/24 17:33 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public XcChooseCourseDto addChooseCourse(String userId, Long courseId); // 执行语句

    /** // 保留原作者写的块注释
     * @description 判断学习资格 // 保留原作者写的块注释
     * @param userId // 保留原作者写的块注释
     * @param courseId // 保留原作者写的块注释
     * @return XcCourseTablesDto 学习资格状态 [{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/10/3 7:37 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public XcCourseTablesDto getLearningStatus(String userId, Long courseId); // 执行语句

    /** // 保留原作者写的块注释
     * 保存选课成功状态 // 保留原作者写的块注释
     * @param chooseCourseId // 保留原作者写的块注释
     * @return // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public boolean saveChooseCourseSuccess(String chooseCourseId); // 执行语句

    /** // 保留原作者写的块注释
     * @description 我的课程表 // 保留原作者写的块注释
     * @param params // 保留原作者写的块注释
     * @return com.xuecheng.base.model.PageResult<com.xuecheng.learning.model.po.XcCourseTables> // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/10/27 9:24 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public PageResult<XcCourseTables> mycoursetables(MyCourseTableParams params); // 执行语句

} // 代码块结束

文件:xuecheng-plus-learning/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-learning</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>xuecheng-plus-learning-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-learning-model</artifactId>
           <version>0.0.1-SNAPSHOT</version>
       </dependency>
       <dependency>
           <groupId>com.xuecheng</groupId>
           <artifactId>xuecheng-plus-base</artifactId>
           <version>0.0.1-SNAPSHOT</version>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-openfeign</artifactId> <!-- 调用内容/媒资接口 -->
       </dependency>
       <dependency>
           <groupId>com.baomidou</groupId>
           <artifactId>mybatis-plus-boot-starter</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-redis</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-log4j2</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
    </dependencies>
</project>

文件:xuecheng-plus-learning/test_service/com/xuecheng/learning/FeignClientTest.java

package com.xuecheng.learning; // 声明类所在的包路径

import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; // 导入 LocalDateTimeSerializer 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.learning.feignclient.ContentServiceClient; // 导入 ContentServiceClient 类
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.time.LocalDateTime; // 导入 LocalDateTime 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @date 2023/2/22 20:14 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class FeignClientTest { // 定义 class FeignClientTest

    @Autowired // 使用注解 @Autowired
    ContentServiceClient contentServiceClient; // 执行语句


    @Test // 使用注解 @Test
    public void testContentServiceClient() { // 定义方法 testContentServiceClient(...)
        CoursePublish coursepublish = contentServiceClient.getCoursepublish(120L); // 把 contentServiceClient.getCoursepublish(120L) 赋值给 coursepublish
        Assertions.assertNotNull(coursepublish); // 执行语句
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/test_service/com/xuecheng/learning/LearningApplication.java

package com.xuecheng.learning; // 声明类所在的包路径


import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类
import org.springframework.cloud.openfeign.EnableFeignClients; // 导入 EnableFeignClients 类

@EnableFeignClients(basePackages={"com.xuecheng.*.feignclient"}) // 使用注解 @EnableFeignClients(basePackages={"com.xuecheng.*.feignclient"})
@SpringBootApplication // 使用注解 @SpringBootApplication
public class LearningApplication { // 定义 class LearningApplication
	public static void main(String[] args) { // 定义方法 main(...)
		SpringApplication.run(LearningApplication.class, args); // 执行语句
	} // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/test_service/com/xuecheng/learning/Test1.java

package com.xuecheng.learning; // 声明类所在的包路径

import com.xuecheng.learning.mapper.XcChooseCourseMapper; // 导入 XcChooseCourseMapper 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类

/** // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/10/2 10:32 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @SpringBootTest // 使用注解 @SpringBootTest
public class Test1 { // 定义 class Test1

  @Autowired // 使用注解 @Autowired
 XcChooseCourseMapper xcChooseCourseMapper; // 执行语句

  @Test // 使用注解 @Test
 public void test(){ // 定义方法 test(...)

  } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-learning/test_service/resources/bootstrap.yml


#微服务配置
spring:
  application:
    name: learning-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
        extension-configs:
          - data-id: learning-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: feign-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true

  profiles:
    active: dev


文件:xuecheng-plus-learning/test_service/resources/log4j2-dev.xml

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

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

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

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

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

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

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

文件:xuecheng-plus-learning/xuecheng-plus-learning-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-learning</artifactId> <!-- SQL 语句片段 -->
        <groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
        <version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
    </parent> <!-- SQL 语句片段 -->
    <artifactId>xuecheng-plus-learning-api</artifactId> <!-- SQL 语句片段 -->

    <dependencies> <!-- 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 语句片段 -->
        <!--认证相关-->
        <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.xuecheng</groupId> <!-- SQL 语句片段 -->
            <artifactId>xuecheng-plus-learning-model</artifactId> <!-- SQL 语句片段 -->
            <version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
            <artifactId>xuecheng-plus-learning-service</artifactId> <!-- SQL 语句片段 -->
            <version>0.0.1-SNAPSHOT</version> <!-- 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 语句片段 -->

        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-boot-starter-validation</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 语句片段 -->

        <!-- 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 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
    </dependencies> <!-- SQL 语句片段 -->

</project> <!-- SQL 语句片段 -->

文件:xuecheng-plus-learning/xuecheng-plus-learning-api/src/main/java/com/xuecheng/learning/api/MyCourseTablesController.java

package com.xuecheng.learning.api; // 声明类所在的包路径

import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.learning.model.dto.MyCourseTableParams; // 导入 MyCourseTableParams 类
import com.xuecheng.learning.model.dto.XcChooseCourseDto; // 导入 XcChooseCourseDto 类
import com.xuecheng.learning.model.dto.XcCourseTablesDto; // 导入 XcCourseTablesDto 类
import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类
import com.xuecheng.learning.service.MyCourseTablesService; // 导入 MyCourseTablesService 类
import com.xuecheng.learning.util.SecurityUtil; // 导入 SecurityUtil 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
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.PostMapping; // 导入 PostMapping 类
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 我的课程表接口 // 保留原作者写的块注释
 * @date 2022/10/25 9:40 // 保留原作者写的块注释
 */ // 保留原作者写的块注释

@Api(value = "我的课程表接口", tags = "我的课程表接口") // 使用注解 @Api(value = "我的课程表接口", tags = "我的课程表接口")
@Slf4j // 使用注解 @Slf4j
@RestController // 使用注解 @RestController
public class MyCourseTablesController { // 定义 class MyCourseTablesController

    @Autowired // 使用注解 @Autowired
    MyCourseTablesService myCourseTablesService; // 执行语句


    @ApiOperation("添加选课") // 使用注解 @ApiOperation("添加选课")
    @PostMapping("/choosecourse/{courseId}") // 使用注解 @PostMapping("/choosecourse/{courseId}")
    public XcChooseCourseDto addChooseCourse(@PathVariable("courseId") Long courseId) { // 定义方法 addChooseCourse(...)

        //当前登录的用户 // 保留原作者写的行内注释
        SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
        if(user == null){ // 定义方法 方法(...)
            XueChengPlusException.cast("请登录"); // 执行语句
        } // 代码块结束
        //用户id // 保留原作者写的行内注释
        String userId = user.getId(); // 把 user.getId() 的返回值赋给 userId
        //添加选课 // 保留原作者写的行内注释
        XcChooseCourseDto xcChooseCourseDto = myCourseTablesService.addChooseCourse(userId, courseId); // 把 myCourseTablesService.addChooseCourse(userId, courseId) 赋值给 xcChooseCourseDto
        return xcChooseCourseDto; // 返回 xcChooseCourseDto
    } // 代码块结束

    @ApiOperation("查询学习资格") // 使用注解 @ApiOperation("查询学习资格")
    @PostMapping("/choosecourse/learnstatus/{courseId}") // 使用注解 @PostMapping("/choosecourse/learnstatus/{courseId}")
    public XcCourseTablesDto getLearnstatus(@PathVariable("courseId") Long courseId) { // 定义方法 getLearnstatus(...)
        //当前登录的用户 // 保留原作者写的行内注释
        SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
        if(user == null){ // 定义方法 方法(...)
            XueChengPlusException.cast("请登录"); // 执行语句
        } // 代码块结束
        //用户id // 保留原作者写的行内注释
        String userId = user.getId(); // 把 user.getId() 的返回值赋给 userId

        XcCourseTablesDto learningStatus = myCourseTablesService.getLearningStatus(userId, courseId); // 把 myCourseTablesService.getLearningStatus(userId, courseId) 赋值给 learningStatus

        return learningStatus; // 返回 learningStatus

    } // 代码块结束

    @ApiOperation("我的课程表") // 使用注解 @ApiOperation("我的课程表")
    @GetMapping("/mycoursetable") // 使用注解 @GetMapping("/mycoursetable")
    public PageResult<XcCourseTables> mycoursetable(MyCourseTableParams params) { // 定义方法 mycoursetable(...)
        //当前登录的用户 // 保留原作者写的行内注释
        SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user
        if(user == null){ // 定义方法 方法(...)
            XueChengPlusException.cast("请登录"); // 执行语句
        } // 代码块结束
        //用户id // 保留原作者写的行内注释
        String userId = user.getId(); // 把 user.getId() 的返回值赋给 userId
        params.setUserId(userId); // 执行语句

        PageResult<XcCourseTables> mycoursetables = myCourseTablesService.mycoursetables(params); // 把 myCourseTablesService.mycoursetables(params) 赋值给 mycoursetables
        return mycoursetables; // 返回 mycoursetables
    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-api/src/main/java/com/xuecheng/learning/api/MyLearningController.java

package com.xuecheng.learning.api; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类
import com.xuecheng.learning.service.LearningService; // 导入 LearningService 类
import com.xuecheng.learning.util.SecurityUtil; // 导入 SecurityUtil 类
import io.swagger.annotations.Api; // 导入 Api 类
import io.swagger.annotations.ApiOperation; // 导入 ApiOperation 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
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.RestController; // 导入 RestController 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 我的学习接口 // 保留原作者写的块注释
 * @date 2022/10/27 8:59 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Api(value = "学习过程管理接口", tags = "学习过程管理接口") // 使用注解 @Api(value = "学习过程管理接口", tags = "学习过程管理接口")
@Slf4j // 使用注解 @Slf4j
@RestController // 使用注解 @RestController
public class MyLearningController { // 定义 class MyLearningController

    @Autowired // 使用注解 @Autowired
    LearningService learningService; // 执行语句

    /** // 保留原作者写的块注释
     * // 保留原作者写的块注释
     * @param courseId 课程id // 保留原作者写的块注释
     * @param teachplanId 课程计划id // 保留原作者写的块注释
     * @param mediaId 媒资文件id // 保留原作者写的块注释
     * @return // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    @ApiOperation("获取视频") // 使用注解 @ApiOperation("获取视频")
    @GetMapping("/open/learn/getvideo/{courseId}/{teachplanId}/{mediaId}") // 使用注解 @GetMapping("/open/learn/getvideo/{courseId}/{teachplanId}/{mediaId}")
    public RestResponse<String> getvideo(@PathVariable("courseId") Long courseId, @PathVariable("teachplanId") Long teachplanId, @PathVariable("mediaId") String mediaId) { // 定义方法 getvideo(...)

        SecurityUtil.XcUser user = SecurityUtil.getUser(); // 把 SecurityUtil.getUser() 的返回值赋给 user

        String userId = user.getId(); // 把 user.getId() 的返回值赋给 userId

        //获取视频 // 保留原作者写的行内注释
        RestResponse<String> restResponse = learningService.getVideo(userId, courseId, teachplanId, mediaId); // 把 learningService.getVideo(userId, courseId, teachplanId, mediaId) 赋值给 restResponse

        return restResponse; // 返回 restResponse

    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-api/src/main/java/com/xuecheng/learning/config/ResouceServerConfig.java

package com.xuecheng.learning.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 类

/** // 保留原作者写的块注释
 * @author Administrator // 保留原作者写的块注释
 * @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-learning/xuecheng-plus-learning-api/src/main/java/com/xuecheng/learning/config/TokenConfig.java

package com.xuecheng.learning.config; // 声明类所在的包路径

import org.springframework.context.annotation.Bean; // 导入 Bean 类
import org.springframework.context.annotation.Configuration; // 导入 Configuration 类
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 类

/** // 保留原作者写的块注释
 * @author Administrator // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 **/ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
public class TokenConfig { // 定义 class TokenConfig

    //jwt签名密钥,与认证服务保持一致 // 保留原作者写的行内注释
    private String SIGNING_KEY = "mq123"; // 把 "mq123" 赋值给 SIGNING_KEY

    @Bean // 使用注解 @Bean
    public TokenStore tokenStore() { // 定义方法 tokenStore(...)
        //JWT令牌存储方案 // 保留原作者写的行内注释
        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
    } // 代码块结束

   /* @Bean // 保留原作者写的块注释
    public TokenStore tokenStore() { // 定义方法 tokenStore(...)
        //使用内存存储令牌(普通令牌) // 保留原作者写的行内注释
        return new InMemoryTokenStore(); // 返回 new InMemoryTokenStore()
    }*/ // 代码逻辑
} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-api/src/main/java/com/xuecheng/learning/util/SecurityUtil.java

package com.xuecheng.learning.util; // 声明类所在的包路径

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 用户身份信息获取工具类 // 保留原作者写的块注释
 * @date 2022/10/20 11:41 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
public class SecurityUtil { // 定义 class SecurityUtil

    public static XcUser getUser() { // 定义方法 getUser(...)
        //拿jwt中的用户身份 // 保留原作者写的行内注释
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); // 把 SecurityContextHolder.getContext().getAuthentication().getPrincipal() 的返回值赋给 principal

        if (principal instanceof String){ // 定义方法 方法(...)
            String jsonString = (String) principal; // 把 (String) principal 赋值给 jsonString
            XcUser xcUser = null; // 把变量 xcUser 初始化为 null
            try { // 尝试执行可能抛出异常的代码
                xcUser = JSON.parseObject(jsonString, XcUser.class); // 把 JSON.parseObject(jsonString, XcUser.class) 赋值给 xcUser
            } catch (Exception e) { // 定义方法 catch(...)
                log.debug("解析jwt中的用户身份无法转成XcUser对象:{}",jsonString); // 执行语句
            } // 代码块结束
            return xcUser; // 返回 xcUser

        } // 代码块结束
        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-learning/xuecheng-plus-learning-api/src/main/java/com/xuecheng/LearningApiApplication.java

package com.xuecheng; // 声明类所在的包路径

import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类
import org.springframework.cloud.openfeign.EnableFeignClients; // 导入 EnableFeignClients 类

@EnableFeignClients(basePackages={"com.xuecheng.*.feignclient"}) // 使用注解 @EnableFeignClients(basePackages={"com.xuecheng.*.feignclient"})
@SpringBootApplication // 使用注解 @SpringBootApplication
public class LearningApiApplication { // 定义 class LearningApiApplication

    public static void main(String[] args) { // 定义方法 main(...)
        SpringApplication.run(LearningApiApplication.class, args); // 执行语句
    } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-api/src/main/resources/bootstrap.yml


#微服务配置
spring:
  application:
    name: learning-api
  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: learning-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: feign-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true
          - data-id: rabbitmq-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true

  profiles:
    active: dev


文件:xuecheng-plus-learning/xuecheng-plus-learning-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="DEBUG" includeLocation="true"> <!-- SQL 语句片段 -->
            <AppenderRef ref="AsyncAppender"/> <!-- SQL 语句片段 -->
            <AppenderRef ref="Console"/> <!-- SQL 语句片段 -->
            <AppenderRef ref="DebugAppender"/> <!-- SQL 语句片段 -->
        </Root> <!-- SQL 语句片段 -->
    </Loggers> <!-- SQL 语句片段 -->
</Configuration> <!-- SQL 语句片段 -->

文件:xuecheng-plus-learning/xuecheng-plus-learning-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-learning</artifactId> <!-- SQL 语句片段 -->
        <groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
        <version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
    </parent> <!-- SQL 语句片段 -->
    <artifactId>xuecheng-plus-learning-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-learning/xuecheng-plus-learning-model/src/main/java/com/xuecheng/learning/model/dto/MyCourseTableItemDto.java

package com.xuecheng.learning.model.dto; // 声明类所在的包路径

import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

import java.time.LocalDateTime; // 导入 LocalDateTime 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 我的课程查询条件 // 保留原作者写的块注释
 * @date 2022/10/6 9:42 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class MyCourseTableItemDto extends XcCourseTables { // 定义 class MyCourseTableItemDto

    /** // 保留原作者写的块注释
     * 最近学习时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime learnDate; // 执行语句

    /** // 保留原作者写的块注释
     * 学习时长 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long learnLength; // 执行语句

    /** // 保留原作者写的块注释
     * 章节id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long teachplanId; // 执行语句

    /** // 保留原作者写的块注释
     * 章节名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String teachplanName; // 执行语句


} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-model/src/main/java/com/xuecheng/learning/model/dto/MyCourseTableParams.java

package com.xuecheng.learning.model.dto; // 声明类所在的包路径

import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

/** // 保留原作者写的块注释
 * @description 我的课程查询条件 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/10/6 9:42 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @Data // 使用注解 @Data
 @ToString // 使用注解 @ToString
public class MyCourseTableParams { // 定义 class MyCourseTableParams

     String userId; // 执行语句

   //课程类型  [{"code":"700001","desc":"免费课程"},{"code":"700002","desc":"收费课程"}] // 保留原作者写的行内注释
   private String courseType; // 执行语句

   //排序 1按学习时间进行排序 2按加入时间进行排序 // 保留原作者写的行内注释
   private String sortType; // 执行语句

   //1即将过期、2已经过期 // 保留原作者写的行内注释
   private String expiresType; // 执行语句

   int page=1; // 把 1 赋值给 page
   int startIndex; // 执行语句
   int size=4; // 把 4 赋值给 size

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-model/src/main/java/com/xuecheng/learning/model/dto/XcChooseCourseDto.java

package com.xuecheng.learning.model.dto; // 声明类所在的包路径

import com.xuecheng.learning.model.po.XcChooseCourse; // 导入 XcChooseCourse 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @date 2022/10/2 16:10 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class XcChooseCourseDto extends XcChooseCourse { // 定义 class XcChooseCourseDto

    //学习资格,[{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的行内注释
    public String learnStatus; // 执行语句

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-model/src/main/java/com/xuecheng/learning/model/dto/XcCourseTablesDto.java

package com.xuecheng.learning.model.dto; // 声明类所在的包路径

import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类
import lombok.Data; // 导入 Data 类
import lombok.ToString; // 导入 ToString 类

/** // 保留原作者写的块注释
 * @description 我的课程表模型类 // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/10/2 16:09 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Data // 使用注解 @Data
@ToString // 使用注解 @ToString
public class XcCourseTablesDto extends XcCourseTables { // 定义 class XcCourseTablesDto
    //学习资格,[{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的行内注释
    public String learnStatus; // 执行语句
} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-model/src/main/java/com/xuecheng/learning/model/po/XcChooseCourse.java

package com.xuecheng.learning.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("xc_choose_course") // 使用注解 @TableName("xc_choose_course")
public class XcChooseCourse implements Serializable { // 定义 class XcChooseCourse

    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 courseId; // 执行语句

    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String courseName; // 执行语句

    /** // 保留原作者写的块注释
     * 用户id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String userId; // 执行语句

    /** // 保留原作者写的块注释
     * 机构id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long companyId; // 执行语句

    /** // 保留原作者写的块注释
     * 选课类型 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String orderType; // 执行语句

    /** // 保留原作者写的块注释
     * 添加时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    @TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createDate; // 执行语句

    /** // 保留原作者写的块注释
     * 课程有效期(天) // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Integer validDays; // 执行语句

    private Float coursePrice; // 执行语句

    /** // 保留原作者写的块注释
     * 选课状态 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String status; // 执行语句

    /** // 保留原作者写的块注释
     * 开始服务时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime validtimeStart; // 执行语句

    /** // 保留原作者写的块注释
     * 结束服务时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime validtimeEnd; // 执行语句

    /** // 保留原作者写的块注释
     * 备注 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String remarks; // 执行语句


} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-model/src/main/java/com/xuecheng/learning/model/po/XcCourseTables.java

package com.xuecheng.learning.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("xc_course_tables") // 使用注解 @TableName("xc_course_tables")
public class XcCourseTables implements Serializable { // 定义 class XcCourseTables

    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 chooseCourseId; // 执行语句

    /** // 保留原作者写的块注释
     * 用户id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String userId; // 执行语句

    /** // 保留原作者写的块注释
     * 课程id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long courseId; // 执行语句

    /** // 保留原作者写的块注释
     * 机构id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long companyId; // 执行语句

    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String courseName; // 执行语句
    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String courseType; // 执行语句


    /** // 保留原作者写的块注释
     * 添加时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    @TableField(fill = FieldFill.INSERT) // 使用注解 @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createDate; // 执行语句

    /** // 保留原作者写的块注释
     * 开始服务时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime validtimeStart; // 执行语句

    /** // 保留原作者写的块注释
     * 到期时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime validtimeEnd; // 执行语句

    /** // 保留原作者写的块注释
     * 更新时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime updateDate; // 执行语句

    /** // 保留原作者写的块注释
     * 备注 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String remarks; // 执行语句


} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-model/src/main/java/com/xuecheng/learning/model/po/XcLearnRecord.java

package com.xuecheng.learning.model.po; // 声明类所在的包路径

import com.baomidou.mybatisplus.annotation.IdType; // 导入 IdType 类
import com.baomidou.mybatisplus.annotation.TableId; // 导入 TableId 类
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("xc_learn_record") // 使用注解 @TableName("xc_learn_record")
public class XcLearnRecord implements Serializable { // 定义 class XcLearnRecord

    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 courseId; // 执行语句

    /** // 保留原作者写的块注释
     * 课程名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String courseName; // 执行语句

    /** // 保留原作者写的块注释
     * 用户id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String userId; // 执行语句

    /** // 保留原作者写的块注释
     * 最近学习时间 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private LocalDateTime learnDate; // 执行语句

    /** // 保留原作者写的块注释
     * 学习时长 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long learnLength; // 执行语句

    /** // 保留原作者写的块注释
     * 章节id // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private Long teachplanId; // 执行语句

    /** // 保留原作者写的块注释
     * 章节名称 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    private String teachplanName; // 执行语句


} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-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-learning</artifactId> <!-- SQL 语句片段 -->
        <groupId>com.xuecheng</groupId> <!-- SQL 语句片段 -->
        <version>0.0.1-SNAPSHOT</version> <!-- SQL 语句片段 -->
    </parent> <!-- SQL 语句片段 -->
    <artifactId>xuecheng-plus-learning-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.alibaba.cloud</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <!-- 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.xuecheng</groupId> <!-- SQL 语句片段 -->
            <artifactId>xuecheng-plus-learning-model</artifactId> <!-- SQL 语句片段 -->
            <version>0.0.1-SNAPSHOT</version> <!-- 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 语句片段 -->
        <!-- 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 语句片段 -->
        <!-- 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 语句片段 -->

        <!-- 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-amqp</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->

        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-boot-starter-freemarker</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>com.xuxueli</groupId> <!-- SQL 语句片段 -->
            <artifactId>xxl-job-core</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
        <dependency> <!-- SQL 语句片段 -->
            <groupId>org.springframework.boot</groupId> <!-- SQL 语句片段 -->
            <artifactId>spring-boot-starter-amqp</artifactId> <!-- SQL 语句片段 -->
        </dependency> <!-- SQL 语句片段 -->
    </dependencies> <!-- SQL 语句片段 -->

</project> <!-- SQL 语句片段 -->

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/config/MybatisPlusConfig.java

package com.xuecheng.learning.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 类

/** // 保留原作者写的块注释
 * <P> // 保留原作者写的块注释
 * 		Mybatis-Plus 配置 // 保留原作者写的块注释
 * </p> // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Configuration // 使用注解 @Configuration
@MapperScan("com.xuecheng.learning.mapper") // 使用注解 @MapperScan("com.xuecheng.learning.mapper")
public class MybatisPlusConfig { // 定义 class MybatisPlusConfig
	/** // 保留原作者写的块注释
	 * 新的分页插件 // 保留原作者写的块注释
	 * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false // 保留原作者写的块注释
	 * 避免缓存出现问题(该属性会在旧插件移除后一同移除) // 保留原作者写的块注释
	 */ // 保留原作者写的块注释
	@Bean // 使用注解 @Bean
	public MybatisPlusInterceptor mybatisPlusInterceptor() { // 定义方法 mybatisPlusInterceptor(...)
		MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 创建 MybatisPlusInterceptor 对象并赋值给 interceptor
		interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 执行语句
		return interceptor; // 返回 interceptor
	} // 代码块结束


} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/config/PayNotifyConfig.java

package com.xuecheng.learning.config; // 声明类所在的包路径

import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.amqp.core.*; // 导入 * 类
import org.springframework.beans.factory.annotation.Qualifier; // 导入 Qualifier 类
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/23 16:59 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Configuration // 使用注解 @Configuration
public class PayNotifyConfig { // 定义 class PayNotifyConfig

    //交换机 // 保留原作者写的行内注释
    public static final String PAYNOTIFY_EXCHANGE_FANOUT = "paynotify_exchange_fanout"; // 把 "paynotify_exchange_fanout" 赋值给 PAYNOTIFY_EXCHANGE_FANOUT
    //支付结果通知消息类型 // 保留原作者写的行内注释
    public static final String MESSAGE_TYPE = "payresult_notify"; // 把 "payresult_notify" 赋值给 MESSAGE_TYPE
    //支付通知队列 // 保留原作者写的行内注释
    public static final String PAYNOTIFY_QUEUE = "paynotify_queue"; // 把 "paynotify_queue" 赋值给 PAYNOTIFY_QUEUE

    //声明交换机,且持久化 // 保留原作者写的行内注释
    @Bean(PAYNOTIFY_EXCHANGE_FANOUT) // 使用注解 @Bean(PAYNOTIFY_EXCHANGE_FANOUT)
    public FanoutExchange paynotify_exchange_fanout() { // 定义方法 paynotify_exchange_fanout(...)
        // 三个参数:交换机名称、是否持久化、当没有queue与其绑定时是否自动删除 // 保留原作者写的行内注释
        return new FanoutExchange(PAYNOTIFY_EXCHANGE_FANOUT, true, false); // 返回 new FanoutExchange(PAYNOTIFY_EXCHANGE_FANOUT, true, false)
    } // 代码块结束
    //支付通知队列,且持久化 // 保留原作者写的行内注释
    @Bean(PAYNOTIFY_QUEUE) // 使用注解 @Bean(PAYNOTIFY_QUEUE)
    public Queue course_publish_queue() { // 定义方法 course_publish_queue(...)
        return QueueBuilder.durable(PAYNOTIFY_QUEUE).build(); // 返回 QueueBuilder.durable(PAYNOTIFY_QUEUE).build()
    } // 代码块结束

    //交换机和支付通知队列绑定 // 保留原作者写的行内注释
    @Bean // 使用注解 @Bean
    public Binding binding_course_publish_queue(@Qualifier(PAYNOTIFY_QUEUE) Queue queue, @Qualifier(PAYNOTIFY_EXCHANGE_FANOUT) FanoutExchange exchange) { // 定义方法 binding_course_publish_queue(...)
        return BindingBuilder.bind(queue).to(exchange); // 返回 BindingBuilder.bind(queue).to(exchange)
    } // 代码块结束


} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/feignclient/ContentServiceClient.java

package com.xuecheng.learning.feignclient; // 声明类所在的包路径

import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import org.springframework.cloud.openfeign.FeignClient; // 导入 FeignClient 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.PathVariable; // 导入 PathVariable 类
import org.springframework.web.bind.annotation.ResponseBody; // 导入 ResponseBody 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 内容管理远程接口 // 保留原作者写的块注释
 * @date 2022/10/25 9:13 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@FeignClient(value = "content-api",fallbackFactory = ContentServiceClientFallbackFactory.class) // 使用注解 @FeignClient(value = "content-api",fallbackFactory = ContentServiceClientFallbackFactory.class)
public interface ContentServiceClient { // 定义 interface ContentServiceClient

    //查询已经发布的课程 // 保留原作者写的行内注释
    @ResponseBody // 使用注解 @ResponseBody
    @GetMapping("/content/r/coursepublish/{courseId}") // 使用注解 @GetMapping("/content/r/coursepublish/{courseId}")
    public CoursePublish getCoursepublish(@PathVariable("courseId") Long courseId); // 执行语句

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/feignclient/ContentServiceClientFallbackFactory.java

package com.xuecheng.learning.feignclient; // 声明类所在的包路径

import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
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 2022/10/25 9:14 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class ContentServiceClientFallbackFactory implements FallbackFactory<ContentServiceClient> { // 定义 class ContentServiceClientFallbackFactory
    @Override // 使用注解 @Override
    public ContentServiceClient create(Throwable throwable) { // 定义方法 create(...)
        return new ContentServiceClient() { // 定义方法 ContentServiceClient(...)

            @Override // 使用注解 @Override
            public CoursePublish getCoursepublish(Long courseId) { // 定义方法 getCoursepublish(...)
                log.error("调用内容管理服务发生熔断:{}", throwable.toString(),throwable); // 执行语句
                return null; // 返回 null
            } // 代码块结束
        }; // 执行语句
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/feignclient/MediaServiceClient.java

package com.xuecheng.learning.feignclient; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类
import org.springframework.cloud.openfeign.FeignClient; // 导入 FeignClient 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 类
import org.springframework.web.bind.annotation.PathVariable; // 导入 PathVariable 类
import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 类

/** // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/10/27 9:04 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @FeignClient(value = "media-api",fallbackFactory = MediaServiceClientFallbackFactory.class) // 使用注解 @FeignClient(value = "media-api",fallbackFactory = MediaServiceClientFallbackFactory.class)
 @RequestMapping("/media") // 使用注解 @RequestMapping("/media")
 public interface MediaServiceClient { // 定义 interface MediaServiceClient

  @GetMapping("/open/preview/{mediaId}") // 使用注解 @GetMapping("/open/preview/{mediaId}")
  public RestResponse<String> getPlayUrlByMediaId(@PathVariable("mediaId") String mediaId); // 执行语句

 } // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/feignclient/MediaServiceClientFallbackFactory.java

package com.xuecheng.learning.feignclient; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类
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 2022/10/27 9:05 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Component // 使用注解 @Component
public class MediaServiceClientFallbackFactory implements FallbackFactory<MediaServiceClient> { // 定义 class MediaServiceClientFallbackFactory
    @Override // 使用注解 @Override
    public MediaServiceClient create(Throwable throwable) { // 定义方法 create(...)
        return new MediaServiceClient() { // 定义方法 MediaServiceClient(...)
            @Override // 使用注解 @Override
            public RestResponse<String> getPlayUrlByMediaId(String mediaId) { // 定义方法 getPlayUrlByMediaId(...)
                log.error("远程调用媒资管理服务熔断异常:{}", throwable.getMessage()); // 执行语句
                return null; // 返回 null
            } // 代码块结束
        }; // 执行语句
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/mapper/XcChooseCourseMapper.java

package com.xuecheng.learning.mapper; // 声明类所在的包路径

import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.learning.model.po.XcChooseCourse; // 导入 XcChooseCourse 类

/** // 保留原作者写的块注释
 * <p> // 保留原作者写的块注释
 *  Mapper 接口 // 保留原作者写的块注释
 * </p> // 保留原作者写的块注释
 * // 保留原作者写的块注释
 * @author itcast // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface XcChooseCourseMapper extends BaseMapper<XcChooseCourse> { // 定义 interface XcChooseCourseMapper

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/mapper/XcChooseCourseMapper.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.learning.mapper.XcChooseCourseMapper"> <!-- MyBatis 映射文件的根标签 -->

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.xuecheng.learning.model.po.XcChooseCourse"> <!-- 定义结果映射 -->
        <id column="id" property="id" /> <!-- 主键列的映射规则 -->
        <result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
        <result column="course_name" property="courseName" /> <!-- 字段与属性的映射规则 -->
        <result column="user_id" property="userId" /> <!-- 字段与属性的映射规则 -->
        <result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
        <result column="order_type" property="orderType" /> <!-- 字段与属性的映射规则 -->
        <result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
        <result column="valid_days" property="validDays" /> <!-- 字段与属性的映射规则 -->
        <result column="status" property="status" /> <!-- 字段与属性的映射规则 -->
        <result column="validtime_start" property="validtimeStart" /> <!-- 字段与属性的映射规则 -->
        <result column="validtime_end" property="validtimeEnd" /> <!-- 字段与属性的映射规则 -->
        <result column="remarks" property="remarks" /> <!-- 字段与属性的映射规则 -->
    </resultMap> <!-- 结束 resultMap 区块 -->

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
        id, course_id, course_name, user_id, company_id, order_type, create_date, valid_days, status, validtime_start, validtime_end, remarks <!-- SQL 语句片段 -->
    </sql> <!-- 结束 SQL 片段 -->

</mapper> <!-- 结束 mapper 标签 -->

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/mapper/XcCourseTablesMapper.java

package com.xuecheng.learning.mapper; // 声明类所在的包路径

import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 BaseMapper 类
import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类

/** // 保留原作者写的块注释
 * <p> // 保留原作者写的块注释
 *  Mapper 接口 // 保留原作者写的块注释
 * </p> // 保留原作者写的块注释
 * // 保留原作者写的块注释
 * @author itcast // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface XcCourseTablesMapper extends BaseMapper<XcCourseTables> { // 定义 interface XcCourseTablesMapper

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/mapper/XcCourseTablesMapper.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.learning.mapper.XcCourseTablesMapper"> <!-- MyBatis 映射文件的根标签 -->

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.xuecheng.learning.model.po.XcCourseTables"> <!-- 定义结果映射 -->
        <id column="id" property="id" /> <!-- 主键列的映射规则 -->
        <result column="choose_course_id" property="chooseCourseId" /> <!-- 字段与属性的映射规则 -->
        <result column="user_id" property="userId" /> <!-- 字段与属性的映射规则 -->
        <result column="course_id" property="courseId" /> <!-- 字段与属性的映射规则 -->
        <result column="company_id" property="companyId" /> <!-- 字段与属性的映射规则 -->
        <result column="course_name" property="courseName" /> <!-- 字段与属性的映射规则 -->
        <result column="create_date" property="createDate" /> <!-- 字段与属性的映射规则 -->
        <result column="validtime_end" property="validtimeEnd" /> <!-- 字段与属性的映射规则 -->
        <result column="update_date" property="updateDate" /> <!-- 字段与属性的映射规则 -->
        <result column="remarks" property="remarks" /> <!-- 字段与属性的映射规则 -->
    </resultMap> <!-- 结束 resultMap 区块 -->

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List"> <!-- 声明可复用的 SQL 片段 -->
        id, choose_course_id, user_id, course_id, company_id, course_name, create_date, validtime_end, update_date, remarks <!-- SQL 语句片段 -->
    </sql> <!-- 结束 SQL 片段 -->

</mapper> <!-- 结束 mapper 标签 -->

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/service/impl/LearningServiceImpl.java

package com.xuecheng.learning.service.impl; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.learning.feignclient.ContentServiceClient; // 导入 ContentServiceClient 类
import com.xuecheng.learning.feignclient.MediaServiceClient; // 导入 MediaServiceClient 类
import com.xuecheng.learning.model.dto.XcCourseTablesDto; // 导入 XcCourseTablesDto 类
import com.xuecheng.learning.service.LearningService; // 导入 LearningService 类
import com.xuecheng.learning.service.MyCourseTablesService; // 导入 MyCourseTablesService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 在线学习接口 // 保留原作者写的块注释
 * @date 2023/2/28 10:20 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class LearningServiceImpl implements LearningService { // 定义 class LearningServiceImpl

    @Autowired // 使用注解 @Autowired
    MyCourseTablesService myCourseTablesService; // 执行语句

    @Autowired // 使用注解 @Autowired
    ContentServiceClient contentServiceClient; // 执行语句

    @Autowired // 使用注解 @Autowired
    MediaServiceClient mediaServiceClient; // 执行语句

    @Override // 使用注解 @Override
    public RestResponse<String> getVideo(String userId, Long courseId, Long teachplanId, String mediaId) { // 定义方法 getVideo(...)

        //查询课程信息 // 保留原作者写的行内注释
        CoursePublish coursepublish = contentServiceClient.getCoursepublish(courseId); // 把 contentServiceClient.getCoursepublish(courseId) 赋值给 coursepublish
        //判断如果为null不再继续 // 保留原作者写的行内注释
        if(coursepublish == null){ // 定义方法 方法(...)
            return RestResponse.validfail("课程不存在"); // 返回 RestResponse.validfail("课程不存在")
        } // 代码块结束

        //远程调用内容管理服务根据课程计划id(teachplanId)去查询课程计划信息,如果is_preview的值为1表示支持试学 // 保留原作者写的行内注释
        //也可以从coursepublish对象中解析出课程计划信息去判断是否支持试学 // 保留原作者写的行内注释
        //todo:如果支持试学调用媒资服务查询视频的播放地址,返回 // 保留原作者写的行内注释

        //用户已登录 // 保留原作者写的行内注释
        if(StringUtils.isNotEmpty(userId)){ // 定义方法 方法(...)
            //获取学习资格 // 保留原作者写的行内注释
            XcCourseTablesDto learningStatus = myCourseTablesService.getLearningStatus(userId, courseId); // 把 myCourseTablesService.getLearningStatus(userId, courseId) 赋值给 learningStatus
            //学习资格,[{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的行内注释
            String learnStatus = learningStatus.getLearnStatus(); // 把 learningStatus.getLearnStatus() 的返回值赋给 learnStatus
            if("702002".equals(learnStatus)){ // 定义方法 方法(...)
                return RestResponse.validfail("无法学习,因为没有选课或选课后没有支付"); // 返回 RestResponse.validfail("无法学习,因为没有选课或选课后没有支付")
            }else if("702003".equals(learnStatus)){ // 定义方法 if(...)
                return RestResponse.validfail("已过期需要申请续期或重新支付"); // 返回 RestResponse.validfail("已过期需要申请续期或重新支付")
            }else{ // 代码逻辑
                //有资格学习,要返回视频的播放地址 // 保留原作者写的行内注释
                //程调用媒资获取视频播放地址 // 保留原作者写的行内注释
                RestResponse<String> playUrlByMediaId = mediaServiceClient.getPlayUrlByMediaId(mediaId); // 把 mediaServiceClient.getPlayUrlByMediaId(mediaId) 赋值给 playUrlByMediaId
                return playUrlByMediaId; // 返回 playUrlByMediaId

            } // 代码块结束

        } // 代码块结束
        //如果用户没有登录 // 保留原作者写的行内注释
       //取出课程的收费规则 // 保留原作者写的行内注释
        String charge = coursepublish.getCharge(); // 把 coursepublish.getCharge() 的返回值赋给 charge
        if("201000".equals(charge)){ // 定义方法 方法(...)
            //有资格学习,要返回视频的播放地址 // 保留原作者写的行内注释
            //远程调用媒资获取视频播放地址 // 保留原作者写的行内注释
            RestResponse<String> playUrlByMediaId = mediaServiceClient.getPlayUrlByMediaId(mediaId); // 把 mediaServiceClient.getPlayUrlByMediaId(mediaId) 赋值给 playUrlByMediaId
            return playUrlByMediaId; // 返回 playUrlByMediaId
        } // 代码块结束
        return RestResponse.validfail("课程需要购买"); // 返回 RestResponse.validfail("课程需要购买")
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/service/impl/MyCourseTablesServiceImpl.java

package com.xuecheng.learning.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.PageResult; // 导入 PageResult 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.learning.feignclient.ContentServiceClient; // 导入 ContentServiceClient 类
import com.xuecheng.learning.mapper.XcChooseCourseMapper; // 导入 XcChooseCourseMapper 类
import com.xuecheng.learning.mapper.XcCourseTablesMapper; // 导入 XcCourseTablesMapper 类
import com.xuecheng.learning.model.dto.MyCourseTableParams; // 导入 MyCourseTableParams 类
import com.xuecheng.learning.model.dto.XcChooseCourseDto; // 导入 XcChooseCourseDto 类
import com.xuecheng.learning.model.dto.XcCourseTablesDto; // 导入 XcCourseTablesDto 类
import com.xuecheng.learning.model.po.XcChooseCourse; // 导入 XcChooseCourse 类
import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类
import com.xuecheng.learning.service.MyCourseTablesService; // 导入 MyCourseTablesService 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
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.time.LocalDateTime; // 导入 LocalDateTime 类
import java.util.List; // 导入 List 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 选课相关接口实现 // 保留原作者写的块注释
 * @date 2023/2/25 12:02 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class MyCourseTablesServiceImpl implements MyCourseTablesService { // 定义 class MyCourseTablesServiceImpl

    @Autowired // 使用注解 @Autowired
    XcChooseCourseMapper chooseCourseMapper; // 执行语句

    @Autowired // 使用注解 @Autowired
    XcCourseTablesMapper courseTablesMapper; // 执行语句

    @Autowired // 使用注解 @Autowired
    ContentServiceClient contentServiceClient; // 执行语句

    // 添加选课 // 保留原作者写的行内注释
    @Transactional // 使用注解 @Transactional
    @Override // 使用注解 @Override
    public XcChooseCourseDto addChooseCourse(String userId, Long courseId) { // 定义方法 addChooseCourse(...)

        //选课调用内容管理查询课程的收费规则 // 保留原作者写的行内注释
        CoursePublish coursepublish = contentServiceClient.getCoursepublish(courseId); // 把 contentServiceClient.getCoursepublish(courseId) 赋值给 coursepublish
        if(coursepublish == null){ // 定义方法 方法(...)
            XueChengPlusException.cast("课程不存在"); // 执行语句
        } // 代码块结束
        //收费规则 // 保留原作者写的行内注释
        String charge = coursepublish.getCharge(); // 把 coursepublish.getCharge() 的返回值赋给 charge
        //选课记录 // 保留原作者写的行内注释
        XcChooseCourse chooseCourse = null; // 把变量 chooseCourse 初始化为 null
        if("201000".equals(charge)){//免费课程 // 定义方法 方法(...)
            //向选课记录表写 // 保留原作者写的行内注释
            chooseCourse = addFreeCoruse(userId, coursepublish); // 把 addFreeCoruse(userId, coursepublish) 赋值给 chooseCourse
            //向我的课程表写 // 保留原作者写的行内注释
            XcCourseTables xcCourseTables = addCourseTabls(chooseCourse); // 把 addCourseTabls(chooseCourse) 赋值给 xcCourseTables

        }else{ // 代码逻辑
            //如果收费课程,会向选课记录表写数据 // 保留原作者写的行内注释
            chooseCourse = addChargeCoruse(userId, coursepublish); // 把 addChargeCoruse(userId, coursepublish) 赋值给 chooseCourse
        } // 代码块结束

        //判断学生的学习资格 // 保留原作者写的行内注释
        XcCourseTablesDto xcCourseTablesDto = getLearningStatus(userId, courseId); // 把 getLearningStatus(userId, courseId) 赋值给 xcCourseTablesDto

        //构造返回值 // 保留原作者写的行内注释
        XcChooseCourseDto xcChooseCourseDto = new XcChooseCourseDto(); // 创建 XcChooseCourseDto 对象并赋值给 xcChooseCourseDto
        BeanUtils.copyProperties(chooseCourse,xcChooseCourseDto); // 执行语句
        //设置学习资格状态 // 保留原作者写的行内注释
        xcChooseCourseDto.setLearnStatus(xcCourseTablesDto.getLearnStatus()); // 执行语句

        return xcChooseCourseDto; // 返回 xcChooseCourseDto
    } // 代码块结束

    //返回//学习资格,[{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的行内注释
    @Override // 使用注解 @Override
    public XcCourseTablesDto getLearningStatus(String userId, Long courseId) { // 定义方法 getLearningStatus(...)
        //返回的结果 // 保留原作者写的行内注释
        XcCourseTablesDto courseTablesDto = new XcCourseTablesDto(); // 创建 XcCourseTablesDto 对象并赋值给 courseTablesDto

        //查询我的课程表,如果查不到说明没有选课 // 保留原作者写的行内注释
        XcCourseTables xcCourseTables = getXcCourseTables(userId, courseId); // 把 getXcCourseTables(userId, courseId) 赋值给 xcCourseTables
        if(xcCourseTables == null){ // 定义方法 方法(...)
            //"code":"702002","desc":"没有选课或选课后没有支付" // 保留原作者写的行内注释
            courseTablesDto.setLearnStatus("702002"); // 执行语句
            return courseTablesDto; // 返回 courseTablesDto
        } // 代码块结束
        //如果查到了,判断是否过期,如果过期不能继续学习,没有过期可以继续学习 // 保留原作者写的行内注释

        boolean before = xcCourseTables.getValidtimeEnd().isBefore(LocalDateTime.now()); // 把 xcCourseTables.getValidtimeEnd().isBefore(LocalDateTime.now()) 赋值给 before
        if(before){ // 定义方法 方法(...)
            //"code":"702003","desc":"已过期需要申请续期或重新支付" // 保留原作者写的行内注释
            BeanUtils.copyProperties(xcCourseTables,courseTablesDto); // 执行语句
            courseTablesDto.setLearnStatus("702003"); // 执行语句
            return courseTablesDto; // 返回 courseTablesDto
        }else{ // 代码逻辑
            //"code":"702001","desc":"正常学习" // 保留原作者写的行内注释
            BeanUtils.copyProperties(xcCourseTables,courseTablesDto); // 执行语句
            courseTablesDto.setLearnStatus("702001"); // 执行语句
            return courseTablesDto; // 返回 courseTablesDto
        } // 代码块结束

    } // 代码块结束

    // 支付完毕添加到课程表 // 保留原作者写的行内注释
    @Override // 使用注解 @Override
    public boolean saveChooseCourseSuccess(String chooseCourseId) { // 定义方法 saveChooseCourseSuccess(...)

        //根据选课id查询选课表 // 保留原作者写的行内注释
        XcChooseCourse chooseCourse = chooseCourseMapper.selectById(chooseCourseId); // 把 chooseCourseMapper.selectById(chooseCourseId) 赋值给 chooseCourse
        if(chooseCourse == null){ // 定义方法 方法(...)
            log.debug("接收购买课程的消息,根据选课id从数据库找不到选课记录,选课id:{}",chooseCourseId); // 执行语句
            return false; // 返回 false
        } // 代码块结束
        //选课状态 // 保留原作者写的行内注释
        String status = chooseCourse.getStatus(); // 把 chooseCourse.getStatus() 的返回值赋给 status
        //只有当未支付时才更新为已支付 // 保留原作者写的行内注释
        if("701002".equals(status)){ // 定义方法 方法(...)
            //更新选课记录的状态为支付成功 // 保留原作者写的行内注释
            chooseCourse.setStatus("701001"); // 执行语句
            int i = chooseCourseMapper.updateById(chooseCourse); // 把 chooseCourseMapper.updateById(chooseCourse) 赋值给 i
            if(i<=0){ // 定义方法 方法(...)
                log.debug("添加选课记录失败:{}",chooseCourse); // 执行语句
                XueChengPlusException.cast("添加选课记录失败"); // 执行语句
            } // 代码块结束

            //向我的课程表插入记录 // 保留原作者写的行内注释
            XcCourseTables xcCourseTables = addCourseTabls(chooseCourse); // 把 addCourseTabls(chooseCourse) 赋值给 xcCourseTables
            return true; // 返回 true
        } // 代码块结束


        return false; // 返回 false
    } // 代码块结束

    // 分页 // 保留原作者写的行内注释
    @Override // 使用注解 @Override
    public PageResult<XcCourseTables> mycoursetables(MyCourseTableParams params) { // 定义方法 mycoursetables(...)
        //用户id // 保留原作者写的行内注释
        String userId = params.getUserId(); // 把 params.getUserId() 的返回值赋给 userId
        //当前页码 // 保留原作者写的行内注释
        int pageNo = params.getPage(); // 把 params.getPage() 的返回值赋给 pageNo
        //每页记录数 // 保留原作者写的行内注释
        int size = params.getSize(); // 把 params.getSize() 的返回值赋给 size

        Page<XcCourseTables> courseTablesPage = new Page<>(pageNo, size); // 创建 Page<> 对象并赋值给 courseTablesPage
        LambdaQueryWrapper<XcCourseTables> lambdaQueryWrapper = new LambdaQueryWrapper<XcCourseTables>().eq(XcCourseTables::getUserId, userId); // 创建 LambdaQueryWrapper<XcCourseTables> 对象并赋值给 lambdaQueryWrapper

        //查询数据 // 保留原作者写的行内注释
        Page<XcCourseTables> result = courseTablesMapper.selectPage(courseTablesPage, lambdaQueryWrapper); // 把 courseTablesMapper.selectPage(courseTablesPage, lambdaQueryWrapper) 赋值给 result

        //数据列表 // 保留原作者写的行内注释
        List<XcCourseTables> records = result.getRecords(); // 把 result.getRecords() 的返回值赋给 records
        //总记录数 // 保留原作者写的行内注释
        long total = result.getTotal(); // 把 result.getTotal() 的返回值赋给 total

        //List<T> items, long counts, long page, long pageSize // 保留原作者写的行内注释
        PageResult pageResult = new PageResult(records, total, pageNo, size); // 创建 PageResult 对象并赋值给 pageResult

        return pageResult; // 返回 pageResult
    } // 代码块结束


    //添加免费课程,免费课程加入选课记录表、我的课程表 // 保留原作者写的行内注释
    public XcChooseCourse addFreeCoruse(String userId, CoursePublish coursepublish) { // 定义方法 addFreeCoruse(...)
        //课程id // 保留原作者写的行内注释
        Long courseId = coursepublish.getId(); // 把 coursepublish.getId() 的返回值赋给 courseId
        //判断,如果存在免费的选课记录且选课状态为成功,直接返回了 // 保留原作者写的行内注释
        LambdaQueryWrapper<XcChooseCourse> queryWrapper = new LambdaQueryWrapper<XcChooseCourse>().eq(XcChooseCourse::getUserId, userId) // 代码逻辑
                .eq(XcChooseCourse::getCourseId, courseId) // 代码逻辑
                .eq(XcChooseCourse::getOrderType, "700001")//免费课程 // 代码逻辑
                .eq(XcChooseCourse::getStatus, "701001");//选课成功 // 执行语句
        List<XcChooseCourse> xcChooseCourses = chooseCourseMapper.selectList(queryWrapper); // 把 chooseCourseMapper.selectList(queryWrapper) 赋值给 xcChooseCourses
        if(xcChooseCourses.size()>0){ // 定义方法 方法(...)
            return xcChooseCourses.get(0); // 返回 xcChooseCourses.get(0)
        } // 代码块结束

        //向选课记录表写数据 // 保留原作者写的行内注释
        XcChooseCourse chooseCourse = new XcChooseCourse(); // 创建 XcChooseCourse 对象并赋值给 chooseCourse

        chooseCourse.setCourseId(courseId); // 执行语句
        chooseCourse.setCourseName(coursepublish.getName()); // 执行语句
        chooseCourse.setUserId(userId); // 执行语句
        chooseCourse.setCompanyId(coursepublish.getCompanyId()); // 执行语句
        chooseCourse.setOrderType("700001");//免费课程 // 执行语句
        chooseCourse.setCreateDate(LocalDateTime.now()); // 执行语句
        chooseCourse.setCoursePrice(coursepublish.getPrice()); // 执行语句
        chooseCourse.setValidDays(365); // 执行语句
        chooseCourse.setStatus("701001");//选课成功 // 执行语句
        chooseCourse.setValidtimeStart(LocalDateTime.now());//有效期的开始时间 // 执行语句
        chooseCourse.setValidtimeEnd(LocalDateTime.now().plusDays(365));//有效期的结束时间 // 执行语句

        int insert = chooseCourseMapper.insert(chooseCourse); // 把 chooseCourseMapper.insert(chooseCourse) 赋值给 insert
        if(insert<=0){ // 定义方法 方法(...)
            XueChengPlusException.cast("添加选课记录失败"); // 执行语句
        } // 代码块结束

        return chooseCourse; // 返回 chooseCourse
    } // 代码块结束

    //添加到我的课程表 // 保留原作者写的行内注释
    public XcCourseTables addCourseTabls(XcChooseCourse xcChooseCourse){ // 定义方法 addCourseTabls(...)

        //选课成功了才可以向我的课程表添加 // 保留原作者写的行内注释
        String status = xcChooseCourse.getStatus(); // 把 xcChooseCourse.getStatus() 的返回值赋给 status
        if(!"701001".equals(status)){ // 定义方法 方法(...)
            XueChengPlusException.cast("选课没有成功无法添加到课程表"); // 执行语句
        } // 代码块结束
        XcCourseTables xcCourseTables = getXcCourseTables(xcChooseCourse.getUserId(), xcChooseCourse.getCourseId()); // 把 getXcCourseTables(xcChooseCourse.getUserId(), xcChooseCourse.getCourseId()) 赋值给 xcCourseTables
        if(xcCourseTables!=null){ // 定义方法 方法(...)
            return xcCourseTables; // 返回 xcCourseTables
        } // 代码块结束

        xcCourseTables = new XcCourseTables(); // 创建 XcCourseTables 对象并赋值给 xcCourseTables
        BeanUtils.copyProperties(xcChooseCourse,xcCourseTables); // 执行语句
        xcCourseTables.setChooseCourseId(xcChooseCourse.getId());//记录选课表的逐渐 // 执行语句
        xcCourseTables.setCourseType(xcChooseCourse.getOrderType());//选课类型 // 执行语句
        xcCourseTables.setUpdateDate(LocalDateTime.now()); // 执行语句
        int insert = courseTablesMapper.insert(xcCourseTables); // 把 courseTablesMapper.insert(xcCourseTables) 赋值给 insert
        if(insert<=0){ // 定义方法 方法(...)
            XueChengPlusException.cast("添加我的课程表失败"); // 执行语句
        } // 代码块结束

        return xcCourseTables; // 返回 xcCourseTables
    } // 代码块结束

    /** // 保留原作者写的块注释
     * @description 根据课程和用户查询我的课程表中某一门课程 // 保留原作者写的块注释
     * @param userId // 保留原作者写的块注释
     * @param courseId // 保留原作者写的块注释
     * @return com.xuecheng.learning.model.po.XcCourseTables // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/10/2 17:07 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public XcCourseTables getXcCourseTables(String userId,Long courseId){ // 定义方法 getXcCourseTables(...)
        XcCourseTables xcCourseTables = courseTablesMapper.selectOne(new LambdaQueryWrapper<XcCourseTables>().eq(XcCourseTables::getUserId, userId).eq(XcCourseTables::getCourseId, courseId)); // 把 courseTablesMapper.selectOne(new LambdaQueryWrapper<XcCourseTables>().eq(XcCourseTables::getUserId, userId).eq(XcCourseTables::getCourseId, courseId)) 赋值给 xcCourseTables
        return xcCourseTables; // 返回 xcCourseTables

    } // 代码块结束


    //添加收费课程 // 保留原作者写的行内注释
    public XcChooseCourse addChargeCoruse(String userId,CoursePublish coursepublish){ // 定义方法 addChargeCoruse(...)

        //课程id // 保留原作者写的行内注释
        Long courseId = coursepublish.getId(); // 把 coursepublish.getId() 的返回值赋给 courseId
        //判断,如果存在收费的选课记录且选课状态为待支付,直接返回了 // 保留原作者写的行内注释
        LambdaQueryWrapper<XcChooseCourse> queryWrapper = new LambdaQueryWrapper<XcChooseCourse>().eq(XcChooseCourse::getUserId, userId) // 代码逻辑
                .eq(XcChooseCourse::getCourseId, courseId) // 代码逻辑
                .eq(XcChooseCourse::getOrderType, "700002")//收费课程 // 代码逻辑
                .eq(XcChooseCourse::getStatus, "701002");//待支付 // 执行语句
        List<XcChooseCourse> xcChooseCourses = chooseCourseMapper.selectList(queryWrapper); // 把 chooseCourseMapper.selectList(queryWrapper) 赋值给 xcChooseCourses
        if(xcChooseCourses.size()>0){ // 定义方法 方法(...)
            return xcChooseCourses.get(0); // 返回 xcChooseCourses.get(0)
        } // 代码块结束

        //向选课记录表写数据 // 保留原作者写的行内注释
        XcChooseCourse chooseCourse = new XcChooseCourse(); // 创建 XcChooseCourse 对象并赋值给 chooseCourse

        chooseCourse.setCourseId(courseId); // 执行语句
        chooseCourse.setCourseName(coursepublish.getName()); // 执行语句
        chooseCourse.setUserId(userId); // 执行语句
        chooseCourse.setCompanyId(coursepublish.getCompanyId()); // 执行语句
        chooseCourse.setOrderType("700002");//收费课程 // 执行语句
        chooseCourse.setCreateDate(LocalDateTime.now()); // 执行语句
        chooseCourse.setCoursePrice(coursepublish.getPrice()); // 执行语句
        chooseCourse.setValidDays(365); // 执行语句
        chooseCourse.setStatus("701002");//待支付 // 执行语句
        chooseCourse.setValidtimeStart(LocalDateTime.now());//有效期的开始时间 // 执行语句
        chooseCourse.setValidtimeEnd(LocalDateTime.now().plusDays(365));//有效期的结束时间 // 执行语句

        int insert = chooseCourseMapper.insert(chooseCourse); // 把 chooseCourseMapper.insert(chooseCourse) 赋值给 insert
        if(insert<=0){ // 定义方法 方法(...)
            XueChengPlusException.cast("添加选课记录失败"); // 执行语句
        } // 代码块结束

        return chooseCourse; // 返回 chooseCourse

    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/service/impl/ReceivePayNotifyService.java

package com.xuecheng.learning.service.impl; // 声明类所在的包路径

import com.alibaba.fastjson.JSON; // 导入 JSON 类
import com.xuecheng.base.exception.XueChengPlusException; // 导入 XueChengPlusException 类
import com.xuecheng.learning.config.PayNotifyConfig; // 导入 PayNotifyConfig 类
import com.xuecheng.learning.service.MyCourseTablesService; // 导入 MyCourseTablesService 类
import com.xuecheng.messagesdk.model.po.MqMessage; // 导入 MqMessage 类
import lombok.extern.slf4j.Slf4j; // 导入 Slf4j 类
import org.springframework.amqp.core.Message; // 导入 Message 类
import org.springframework.amqp.rabbit.annotation.RabbitListener; // 导入 RabbitListener 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.stereotype.Service; // 导入 Service 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 接收消息通知处理类 // 保留原作者写的块注释
 * @date 2023/2/26 16:42 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@Slf4j // 使用注解 @Slf4j
@Service // 使用注解 @Service
public class ReceivePayNotifyService { // 定义 class ReceivePayNotifyService

    @Autowired // 使用注解 @Autowired
    MyCourseTablesService myCourseTablesService; // 执行语句


    @RabbitListener(queues = PayNotifyConfig.PAYNOTIFY_QUEUE) // 使用注解 @RabbitListener(queues = PayNotifyConfig.PAYNOTIFY_QUEUE)
    public void receive(Message message) { // 定义方法 receive(...)

        try { // 尝试执行可能抛出异常的代码
            Thread.sleep(5000); // 执行语句
        } catch (InterruptedException e) { // 定义方法 catch(...)
            e.printStackTrace(); // 执行语句
        } // 代码块结束

        //解析出消息 // 保留原作者写的行内注释
        byte[] body = message.getBody(); // 把 message.getBody() 的返回值赋给 body
        String jsonString = new String(body); // 创建 String 对象并赋值给 jsonString
        //转成对象 // 保留原作者写的行内注释
        MqMessage mqMessage = JSON.parseObject(jsonString, MqMessage.class); // 把 JSON.parseObject(jsonString, MqMessage.class) 赋值给 mqMessage
        //解析消息的内容 // 保留原作者写的行内注释
        //选课id // 保留原作者写的行内注释
        String chooseCourseId = mqMessage.getBusinessKey1(); // 把 mqMessage.getBusinessKey1() 的返回值赋给 chooseCourseId
        //订单类型 // 保留原作者写的行内注释
        String orderType = mqMessage.getBusinessKey2(); // 把 mqMessage.getBusinessKey2() 的返回值赋给 orderType
        //学习中心服务只要购买课程类的支付订单的结果 // 保留原作者写的行内注释
        if (orderType.equals("60201")) { // 定义方法 方法(...)
            //根据消息内容,更新选课记录、向我的课程表插入记录 // 保留原作者写的行内注释
            boolean b = myCourseTablesService.saveChooseCourseSuccess(chooseCourseId); // 把 myCourseTablesService.saveChooseCourseSuccess(chooseCourseId) 赋值给 b
            if (!b) { // 定义方法 方法(...)
                XueChengPlusException.cast("保证选课记录状态失败"); // 执行语句
            } // 代码块结束


        } // 代码块结束


    } // 代码块结束


} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/service/LearningService.java

package com.xuecheng.learning.service; // 声明类所在的包路径

import com.xuecheng.base.model.RestResponse; // 导入 RestResponse 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 在线学习相关的接口 // 保留原作者写的块注释
 * @date 2023/2/28 10:17 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface LearningService { // 定义 interface LearningService

    /** // 保留原作者写的块注释
     * @description 获取教学视频 // 保留原作者写的块注释
     * @param courseId 课程id // 保留原作者写的块注释
     * @param teachplanId 课程计划id // 保留原作者写的块注释
     * @param mediaId 视频文件id // 保留原作者写的块注释
     * @return com.xuecheng.base.model.RestResponse<java.lang.String> // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/10/5 9:08 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public RestResponse<String> getVideo(String userId, Long courseId, Long teachplanId, String mediaId); // 执行语句

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/main/java/com/xuecheng/learning/service/MyCourseTablesService.java

package com.xuecheng.learning.service; // 声明类所在的包路径

import com.xuecheng.base.model.PageResult; // 导入 PageResult 类
import com.xuecheng.learning.model.dto.MyCourseTableParams; // 导入 MyCourseTableParams 类
import com.xuecheng.learning.model.dto.XcChooseCourseDto; // 导入 XcChooseCourseDto 类
import com.xuecheng.learning.model.dto.XcCourseTablesDto; // 导入 XcCourseTablesDto 类
import com.xuecheng.learning.model.po.XcCourseTables; // 导入 XcCourseTables 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description 选课相关的接口 // 保留原作者写的块注释
 * @date 2023/2/25 12:00 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
public interface MyCourseTablesService { // 定义 interface MyCourseTablesService

    /** // 保留原作者写的块注释
     * @description 添加选课 // 保留原作者写的块注释
     * @param userId 用户id // 保留原作者写的块注释
     * @param courseId 课程id // 保留原作者写的块注释
     * @return com.xuecheng.learning.model.dto.XcChooseCourseDto // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * 响应选课结果 // 保留原作者写的块注释
     * @date 2022/10/24 17:33 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public XcChooseCourseDto addChooseCourse(String userId, Long courseId); // 执行语句

    /** // 保留原作者写的块注释
     * @description 判断学习资格 // 保留原作者写的块注释
     * @param userId // 保留原作者写的块注释
     * @param courseId // 保留原作者写的块注释
     * @return XcCourseTablesDto 学习资格状态 [{"code":"702001","desc":"正常学习"},{"code":"702002","desc":"没有选课或选课后没有支付"},{"code":"702003","desc":"已过期需要申请续期或重新支付"}] // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/10/3 7:37 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public XcCourseTablesDto getLearningStatus(String userId, Long courseId); // 执行语句

    /** // 保留原作者写的块注释
     * 保存选课成功状态 // 保留原作者写的块注释
     * @param chooseCourseId // 保留原作者写的块注释
     * @return // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public boolean saveChooseCourseSuccess(String chooseCourseId); // 执行语句

    /** // 保留原作者写的块注释
     * @description 我的课程表 // 保留原作者写的块注释
     * @param params // 保留原作者写的块注释
     * @return com.xuecheng.base.model.PageResult<com.xuecheng.learning.model.po.XcCourseTables> // 保留原作者写的块注释
     * @author Mr.M // 保留原作者写的块注释
     * @date 2022/10/27 9:24 // 保留原作者写的块注释
     */ // 保留原作者写的块注释
    public PageResult<XcCourseTables> mycoursetables(MyCourseTableParams params); // 执行语句

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/test/java/com/xuecheng/learning/FeignClientTest.java

package com.xuecheng.learning; // 声明类所在的包路径

import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; // 导入 LocalDateTimeSerializer 类
import com.xuecheng.content.model.po.CoursePublish; // 导入 CoursePublish 类
import com.xuecheng.learning.feignclient.ContentServiceClient; // 导入 ContentServiceClient 类
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.time.LocalDateTime; // 导入 LocalDateTime 类

/** // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @date 2023/2/22 20:14 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
@SpringBootTest // 使用注解 @SpringBootTest
public class FeignClientTest { // 定义 class FeignClientTest

    @Autowired // 使用注解 @Autowired
    ContentServiceClient contentServiceClient; // 执行语句


    @Test // 使用注解 @Test
    public void testContentServiceClient() { // 定义方法 testContentServiceClient(...)
        CoursePublish coursepublish = contentServiceClient.getCoursepublish(120L); // 把 contentServiceClient.getCoursepublish(120L) 赋值给 coursepublish
        Assertions.assertNotNull(coursepublish); // 执行语句
    } // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/test/java/com/xuecheng/learning/LearningApplication.java

package com.xuecheng.learning; // 声明类所在的包路径


import org.springframework.boot.SpringApplication; // 导入 SpringApplication 类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入 SpringBootApplication 类
import org.springframework.cloud.openfeign.EnableFeignClients; // 导入 EnableFeignClients 类

@EnableFeignClients(basePackages={"com.xuecheng.*.feignclient"}) // 使用注解 @EnableFeignClients(basePackages={"com.xuecheng.*.feignclient"})
@SpringBootApplication // 使用注解 @SpringBootApplication
public class LearningApplication { // 定义 class LearningApplication
	public static void main(String[] args) { // 定义方法 main(...)
		SpringApplication.run(LearningApplication.class, args); // 执行语句
	} // 代码块结束
} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/test/java/com/xuecheng/learning/Test1.java

package com.xuecheng.learning; // 声明类所在的包路径

import com.xuecheng.learning.mapper.XcChooseCourseMapper; // 导入 XcChooseCourseMapper 类
import org.junit.jupiter.api.Test; // 导入 Test 类
import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 类
import org.springframework.boot.test.context.SpringBootTest; // 导入 SpringBootTest 类

/** // 保留原作者写的块注释
 * @description TODO // 保留原作者写的块注释
 * @author Mr.M // 保留原作者写的块注释
 * @date 2022/10/2 10:32 // 保留原作者写的块注释
 * @version 1.0 // 保留原作者写的块注释
 */ // 保留原作者写的块注释
 @SpringBootTest // 使用注解 @SpringBootTest
public class Test1 { // 定义 class Test1

  @Autowired // 使用注解 @Autowired
 XcChooseCourseMapper xcChooseCourseMapper; // 执行语句

  @Test // 使用注解 @Test
 public void test(){ // 定义方法 test(...)

  } // 代码块结束

} // 代码块结束

文件:xuecheng-plus-learning/xuecheng-plus-learning-service/src/test/resources/bootstrap.yml


#微服务配置
spring:
  application:
    name: learning-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
        extension-configs:
          - data-id: learning-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: feign-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true

  profiles:
    active: dev


文件:xuecheng-plus-learning/xuecheng-plus-learning-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 语句片段 -->
appendix_F
https://clxhxhhr.top/posts/4373/
作者
clxstart
发布于
2026-09-26
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。