it_lv 3 settimane fa
commit
aa6da7f662
100 ha cambiato i file con 5081 aggiunte e 0 eliminazioni
  1. 35 0
      .gitignore
  2. 38 0
      common/common-log/pom.xml
  3. 39 0
      common/common-log/src/main/java/com/atguigu/tingshu/common/annotation/Log.java
  4. 184 0
      common/common-log/src/main/java/com/atguigu/tingshu/common/aspect/LogAspect.java
  5. 52 0
      common/common-log/src/main/java/com/atguigu/tingshu/common/enums/BusinessType.java
  6. 21 0
      common/common-log/src/main/java/com/atguigu/tingshu/common/enums/OperatorType.java
  7. 47 0
      common/common-util/pom.xml
  8. 85 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/result/Result.java
  9. 59 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/result/ResultCodeEnum.java
  10. 22 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/AuthContextHolder.java
  11. 31 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/Decimal2Serializer.java
  12. 38 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/ExceptionUtil.java
  13. 318 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/HttpClientUtils.java
  14. 82 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/IpUtil.java
  15. 39 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/MD5.java
  16. 38 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/MongoUtil.java
  17. 65 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/RandomUtil.java
  18. 23 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/ResponseUtil.java
  19. 191 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/SensitiveWordFilterUtil.java
  20. 31 0
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/UploadFileUtil.java
  21. 22 0
      common/pom.xml
  22. 48 0
      common/rabbit-util/pom.xml
  23. 139 0
      common/rabbit-util/src/main/java/com/atguigu/tingshu/common/rabbit/config/RabbitInitConfigApplicationListener.java
  24. 80 0
      common/rabbit-util/src/main/java/com/atguigu/tingshu/common/rabbit/constant/MqConst.java
  25. 21 0
      common/rabbit-util/src/main/java/com/atguigu/tingshu/common/rabbit/entity/GuiguCorrelationData.java
  26. 74 0
      common/rabbit-util/src/main/java/com/atguigu/tingshu/common/rabbit/service/RabbitService.java
  27. 92 0
      common/service-util/pom.xml
  28. 49 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/config/knife4j/Knife4jConfig.java
  29. 32 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/config/mybatisPlus/MybatisPlusConfig.java
  30. 39 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/config/redis/RedisConfig.java
  31. 70 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/config/thread/ThreadPoolConfig.java
  32. 72 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/constant/RedisConstant.java
  33. 78 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/constant/SystemConstant.java
  34. 45 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/execption/GuiguException.java
  35. 88 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/handler/GlobalExceptionHandler.java
  36. 25 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/interceptor/FeignInterceptor.java
  37. 23 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/login/GuiGuLogin.java
  38. 91 0
      common/service-util/src/main/java/com/atguigu/tingshu/common/login/GuiGuLoginAspect.java
  39. 180 0
      lesson.sql
  40. 58 0
      model/pom.xml
  41. 38 0
      model/src/main/java/com/atguigu/tingshu/model/account/RechargeInfo.java
  42. 42 0
      model/src/main/java/com/atguigu/tingshu/model/account/UserAccount.java
  43. 38 0
      model/src/main/java/com/atguigu/tingshu/model/account/UserAccountDetail.java
  44. 35 0
      model/src/main/java/com/atguigu/tingshu/model/album/AlbumAttributeValue.java
  45. 108 0
      model/src/main/java/com/atguigu/tingshu/model/album/AlbumInfo.java
  46. 28 0
      model/src/main/java/com/atguigu/tingshu/model/album/AlbumStat.java
  47. 29 0
      model/src/main/java/com/atguigu/tingshu/model/album/BaseAttribute.java
  48. 24 0
      model/src/main/java/com/atguigu/tingshu/model/album/BaseAttributeValue.java
  49. 24 0
      model/src/main/java/com/atguigu/tingshu/model/album/BaseCategory1.java
  50. 28 0
      model/src/main/java/com/atguigu/tingshu/model/album/BaseCategory2.java
  51. 31 0
      model/src/main/java/com/atguigu/tingshu/model/album/BaseCategory3.java
  52. 50 0
      model/src/main/java/com/atguigu/tingshu/model/album/BaseCategoryView.java
  53. 28 0
      model/src/main/java/com/atguigu/tingshu/model/album/BaseDic.java
  54. 81 0
      model/src/main/java/com/atguigu/tingshu/model/album/TrackInfo.java
  55. 28 0
      model/src/main/java/com/atguigu/tingshu/model/album/TrackStat.java
  56. 36 0
      model/src/main/java/com/atguigu/tingshu/model/base/BaseEntity.java
  57. 55 0
      model/src/main/java/com/atguigu/tingshu/model/comment/Comment.java
  58. 39 0
      model/src/main/java/com/atguigu/tingshu/model/comment/CommentPraise.java
  59. 44 0
      model/src/main/java/com/atguigu/tingshu/model/dispatch/XxlJobConfig.java
  60. 32 0
      model/src/main/java/com/atguigu/tingshu/model/dispatch/XxlJobLog.java
  61. 14 0
      model/src/main/java/com/atguigu/tingshu/model/live/FromUser.java
  62. 74 0
      model/src/main/java/com/atguigu/tingshu/model/live/LiveRoom.java
  63. 28 0
      model/src/main/java/com/atguigu/tingshu/model/live/LiveTag.java
  64. 49 0
      model/src/main/java/com/atguigu/tingshu/model/live/SocketMsg.java
  65. 34 0
      model/src/main/java/com/atguigu/tingshu/model/order/OrderDerate.java
  66. 38 0
      model/src/main/java/com/atguigu/tingshu/model/order/OrderDetail.java
  67. 69 0
      model/src/main/java/com/atguigu/tingshu/model/order/OrderInfo.java
  68. 59 0
      model/src/main/java/com/atguigu/tingshu/model/payment/PaymentInfo.java
  69. 91 0
      model/src/main/java/com/atguigu/tingshu/model/search/AlbumInfoIndex.java
  70. 18 0
      model/src/main/java/com/atguigu/tingshu/model/search/AttributeValueIndex.java
  71. 32 0
      model/src/main/java/com/atguigu/tingshu/model/search/SuggestIndex.java
  72. 50 0
      model/src/main/java/com/atguigu/tingshu/model/system/SysDept.java
  73. 38 0
      model/src/main/java/com/atguigu/tingshu/model/system/SysLoginLog.java
  74. 61 0
      model/src/main/java/com/atguigu/tingshu/model/system/SysMenu.java
  75. 74 0
      model/src/main/java/com/atguigu/tingshu/model/system/SysOperLog.java
  76. 32 0
      model/src/main/java/com/atguigu/tingshu/model/system/SysPost.java
  77. 31 0
      model/src/main/java/com/atguigu/tingshu/model/system/SysRole.java
  78. 25 0
      model/src/main/java/com/atguigu/tingshu/model/system/SysRoleMenu.java
  79. 66 0
      model/src/main/java/com/atguigu/tingshu/model/system/SysUser.java
  80. 24 0
      model/src/main/java/com/atguigu/tingshu/model/system/SysUserRole.java
  81. 40 0
      model/src/main/java/com/atguigu/tingshu/model/user/UserCertification.java
  82. 28 0
      model/src/main/java/com/atguigu/tingshu/model/user/UserCollect.java
  83. 70 0
      model/src/main/java/com/atguigu/tingshu/model/user/UserInfo.java
  84. 41 0
      model/src/main/java/com/atguigu/tingshu/model/user/UserListenProcess.java
  85. 28 0
      model/src/main/java/com/atguigu/tingshu/model/user/UserPaidAlbum.java
  86. 32 0
      model/src/main/java/com/atguigu/tingshu/model/user/UserPaidTrack.java
  87. 28 0
      model/src/main/java/com/atguigu/tingshu/model/user/UserStat.java
  88. 28 0
      model/src/main/java/com/atguigu/tingshu/model/user/UserSubscribe.java
  89. 42 0
      model/src/main/java/com/atguigu/tingshu/model/user/UserVipService.java
  90. 46 0
      model/src/main/java/com/atguigu/tingshu/model/user/VipServiceConfig.java
  91. 18 0
      model/src/main/java/com/atguigu/tingshu/query/album/AlbumInfoQuery.java
  92. 18 0
      model/src/main/java/com/atguigu/tingshu/query/album/TrackInfoQuery.java
  93. 15 0
      model/src/main/java/com/atguigu/tingshu/query/order/OrderInfoQuery.java
  94. 33 0
      model/src/main/java/com/atguigu/tingshu/query/search/AlbumIndexQuery.java
  95. 21 0
      model/src/main/java/com/atguigu/tingshu/query/user/UserInfoQuery.java
  96. 19 0
      model/src/main/java/com/atguigu/tingshu/validation/NotEmptyPaid.java
  97. 16 0
      model/src/main/java/com/atguigu/tingshu/validation/NotEmptyPaidValidator.java
  98. 24 0
      model/src/main/java/com/atguigu/tingshu/vo/account/AccountDeductVo.java
  99. 21 0
      model/src/main/java/com/atguigu/tingshu/vo/account/AccountLockResultVo.java
  100. 24 0
      model/src/main/java/com/atguigu/tingshu/vo/account/AccountLockVo.java

+ 35 - 0
.gitignore

@@ -0,0 +1,35 @@
+# Created by .ignore support plugin (hsz.mobi)
+### Maven template
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+
+.idea/
+
+## File-based project format:
+*.iws
+*.iml
+*.ipr
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties

+ 38 - 0
common/common-log/pom.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>common</artifactId>
+        <groupId>com.atguigu.tingshu</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>common-log</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.atguigu.tingshu</groupId>
+            <artifactId>model</artifactId>
+            <version>1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.atguigu.tingshu</groupId>
+            <artifactId>common-util</artifactId>
+            <version>1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 39 - 0
common/common-log/src/main/java/com/atguigu/tingshu/common/annotation/Log.java

@@ -0,0 +1,39 @@
+package com.atguigu.tingshu.common.annotation;
+
+import com.atguigu.tingshu.common.enums.BusinessType;
+import com.atguigu.tingshu.common.enums.OperatorType;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义操作日志记录注解
+ */
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Log {
+    /**
+     * 模块
+     */
+    public String title() default "";
+
+    /**
+     * 功能
+     */
+    public BusinessType businessType() default BusinessType.OTHER;
+
+    /**
+     * 操作人类别
+     */
+    public OperatorType operatorType() default OperatorType.MANAGE;
+
+    /**
+     * 是否保存请求的参数
+     */
+    public boolean isSaveRequestData() default true;
+
+    /**
+     * 是否保存响应的参数
+     */
+    public boolean isSaveResponseData() default true;
+}

+ 184 - 0
common/common-log/src/main/java/com/atguigu/tingshu/common/aspect/LogAspect.java

@@ -0,0 +1,184 @@
+package com.atguigu.tingshu.common.aspect;
+
+import com.alibaba.fastjson.JSON;
+//import com.atguigu.tingshu.system.client.SysOperLogFeignClient;
+import com.atguigu.tingshu.common.annotation.Log;
+import com.atguigu.tingshu.common.util.IpUtil;
+import com.atguigu.tingshu.model.system.SysOperLog;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Collection;
+import java.util.Map;
+
+
+/**
+ * 操作日志记录处理
+ */
+@Aspect
+@Component
+public class LogAspect {
+    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
+
+    //微服务切换为feign调用接口
+    //@Resource
+    //private SysOperLogFeignClient sysOperLogFeignClient;
+
+    /**
+     * 处理完请求后执行
+     *
+     * @param joinPoint 切点
+     */
+    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
+        handleLog(joinPoint, controllerLog, null, jsonResult);
+    }
+
+    /**
+     * 拦截异常操作
+     *
+     * @param joinPoint 切点
+     * @param e         异常
+     */
+    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
+        handleLog(joinPoint, controllerLog, e, null);
+    }
+
+    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
+        try {
+            RequestAttributes ra = RequestContextHolder.getRequestAttributes();
+            ServletRequestAttributes sra = (ServletRequestAttributes) ra;
+            HttpServletRequest request = sra.getRequest();
+
+            // *========数据库日志=========*//
+            SysOperLog operLog = new SysOperLog();
+            operLog.setStatus(1);
+            // 请求的地址
+            String ip = IpUtil.getIpAddress(request);//IpUtil.getIpAddr(ServletUtils.getRequest());
+            operLog.setOperIp(ip);
+            operLog.setOperUrl(request.getRequestURI());
+
+            if (e != null) {
+                operLog.setStatus(0);
+                operLog.setErrorMsg(e.getMessage());
+            }
+            // 设置方法名称
+            String className = joinPoint.getTarget().getClass().getName();
+            String methodName = joinPoint.getSignature().getName();
+            operLog.setMethod(className + "." + methodName + "()");
+            // 设置请求方式
+            operLog.setRequestMethod(request.getMethod());
+            // 处理设置注解上的参数
+            getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
+            // 保存数据库
+            //sysOperLogFeignClient.saveSysLog(operLog);
+            log.info("操作日志:"+JSON.toJSONString(operLog));
+        } catch (Exception exp) {
+            // 记录本地异常日志
+            log.error("==前置通知异常==");
+            log.error("异常信息:{}", exp.getMessage());
+            exp.printStackTrace();
+        }
+    }
+
+    /**
+     * 获取注解中对方法的描述信息 用于Controller层注解
+     *
+     * @param log     日志
+     * @param operLog 操作日志
+     * @throws Exception
+     */
+    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception {
+        // 设置action动作
+        operLog.setBusinessType(log.businessType().name());
+        // 设置标题
+        operLog.setTitle(log.title());
+        // 设置操作人类别
+        operLog.setOperatorType(log.operatorType().name());
+        // 是否需要保存request,参数和值
+        if (log.isSaveRequestData()) {
+            // 获取参数的信息,传入到数据库中。
+            setRequestValue(joinPoint, operLog);
+        }
+        // 是否需要保存response,参数和值
+        if (log.isSaveResponseData() && !StringUtils.isEmpty(jsonResult)) {
+            operLog.setJsonResult(JSON.toJSONString(jsonResult));
+        }
+    }
+
+    /**
+     * 获取请求的参数,放到log中
+     *
+     * @param operLog 操作日志
+     * @throws Exception 异常
+     */
+    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception {
+        String requestMethod = operLog.getRequestMethod();
+        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
+            String params = argsArrayToString(joinPoint.getArgs());
+            operLog.setOperParam(params);
+        }
+    }
+
+    /**
+     * 参数拼装
+     */
+    private String argsArrayToString(Object[] paramsArray) {
+        String params = "";
+        if (paramsArray != null && paramsArray.length > 0) {
+            for (Object o : paramsArray) {
+                if (!StringUtils.isEmpty(o) && !isFilterObject(o)) {
+                    try {
+                        Object jsonObj = JSON.toJSON(o);
+                        params += jsonObj.toString() + " ";
+                    } catch (Exception e) {
+                    }
+                }
+            }
+        }
+        return params.trim();
+    }
+
+    /**
+     * 判断是否需要过滤的对象。
+     *
+     * @param o 对象信息。
+     * @return 如果是需要过滤的对象,则返回true;否则返回false
+     */
+    @SuppressWarnings("rawtypes")
+    public boolean isFilterObject(final Object o) {
+        Class<?> clazz = o.getClass();
+        if (clazz.isArray()) {
+            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
+        } else if (Collection.class.isAssignableFrom(clazz)) {
+            Collection collection = (Collection) o;
+            for (Object value : collection) {
+                return value instanceof MultipartFile;
+            }
+        } else if (Map.class.isAssignableFrom(clazz)) {
+            Map map = (Map) o;
+            for (Object value : map.entrySet()) {
+                Map.Entry entry = (Map.Entry) value;
+                return entry.getValue() instanceof MultipartFile;
+            }
+        }
+        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
+                || o instanceof BindingResult;
+    }
+}

+ 52 - 0
common/common-log/src/main/java/com/atguigu/tingshu/common/enums/BusinessType.java

@@ -0,0 +1,52 @@
+package com.atguigu.tingshu.common.enums;
+
+/**
+ * 业务操作类型
+ */
+public enum BusinessType {
+    /**
+     * 其它
+     */
+    OTHER,
+
+    /**
+     * 新增
+     */
+    INSERT,
+
+    /**
+     * 修改
+     */
+    UPDATE,
+
+    /**
+     * 删除
+     */
+    DELETE,
+
+    /**
+     * 授权
+     */
+    ASSGIN,
+
+    /**
+     * 导出
+     */
+    EXPORT,
+
+    /**
+     * 导入
+     */
+    IMPORT,
+
+
+    /**
+     * 更新状态
+     */
+    STATUS,
+
+    /**
+     * 清空数据
+     */
+    CLEAN,
+}

+ 21 - 0
common/common-log/src/main/java/com/atguigu/tingshu/common/enums/OperatorType.java

@@ -0,0 +1,21 @@
+package com.atguigu.tingshu.common.enums;
+
+/**
+ * 操作人类别
+ */
+public enum OperatorType {
+    /**
+     * 其它
+     */
+    OTHER,
+
+    /**
+     * 后台用户
+     */
+    MANAGE,
+
+    /**
+     * 手机端用户
+     */
+    MOBILE
+}

+ 47 - 0
common/common-util/pom.xml

@@ -0,0 +1,47 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>common</artifactId>
+        <groupId>com.atguigu.tingshu</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>common-util</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>provided </scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.7.22</version>
+        </dependency>
+    </dependencies>
+</project>

+ 85 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/result/Result.java

@@ -0,0 +1,85 @@
+package com.atguigu.tingshu.common.result;
+
+
+import lombok.Data;
+
+/**
+ * 全局统一返回结果类
+ *
+ */
+@Data
+public class Result<T> {
+
+    //返回码
+    private Integer code;
+
+    //返回消息
+    private String message;
+
+    //返回数据
+    private T data;
+
+    public Result(){}
+
+    // 返回数据
+    protected static <T> Result<T> build(T data) {
+        Result<T> result = new Result<T>();
+        if (data != null)
+            result.setData(data);
+        return result;
+    }
+
+    public static <T> Result<T> build(T body, Integer code, String message) {
+        Result<T> result = build(body);
+        result.setCode(code);
+        result.setMessage(message);
+        return result;
+    }
+
+    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
+        Result<T> result = build(body);
+        result.setCode(resultCodeEnum.getCode());
+        result.setMessage(resultCodeEnum.getMessage());
+        return result;
+    }
+
+    public static<T> Result<T> ok(){
+        return Result.ok(null);
+    }
+
+    /**
+     * 操作成功
+     * @param data  baseCategory1List
+     * @param <T>
+     * @return
+     */
+    public static<T> Result<T> ok(T data){
+        Result<T> result = build(data);
+        return build(data, ResultCodeEnum.SUCCESS);
+    }
+
+    public static<T> Result<T> fail(){
+        return Result.fail(null);
+    }
+
+    /**
+     * 操作失败
+     * @param data
+     * @param <T>
+     * @return
+     */
+    public static<T> Result<T> fail(T data){
+        Result<T> result = build(data);
+        return build(data, ResultCodeEnum.FAIL);
+    }
+
+    public Result<T> message(String msg){
+        this.setMessage(msg);
+        return this;
+    }
+
+    public Result<T> code(Integer code){
+        this.setCode(code);
+        return this;
+    }
+}

+ 59 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/result/ResultCodeEnum.java

@@ -0,0 +1,59 @@
+package com.atguigu.tingshu.common.result;
+
+import lombok.Getter;
+
+/**
+ * 统一返回结果状态信息类
+ *
+ */
+@Getter
+public enum ResultCodeEnum {
+
+    SUCCESS(200,"成功"),
+    FAIL(201, "失败"),
+    SERVICE_ERROR(2012, "服务异常"),
+    DATA_ERROR(204, "数据异常"),
+    ILLEGAL_REQUEST(205, "非法请求"),
+    REPEAT_SUBMIT(206, "重复提交"),
+    ARGUMENT_VALID_ERROR(210, "参数校验异常"),
+    SIGN_ERROR(300, "签名错误"),
+    SIGN_OVERDUE(301, "签名已过期"),
+
+    LOGIN_AUTH(208, "未登陆"),
+    PERMISSION(209, "没有权限"),
+    ACCOUNT_ERROR(214, "账号不正确"),
+    PASSWORD_ERROR(215, "密码不正确"),
+    PHONE_CODE_ERROR(215, "手机验证码不正确"),
+    LOGIN_MOBLE_ERROR( 216, "账号不正确"),
+    ACCOUNT_STOP( 216, "账号已停用"),
+    NODE_ERROR( 217, "该节点下有子节点,不可以删除"),
+
+    VOD_FILE_ID_ERROR( 220, "声音媒体id不正确"),
+
+    XXL_JOB_ERROR(210, "调度操作失败"),
+
+    ACCOUNT_LESS(220, "账户余额不足"),
+    ACCOUNT_LOCK_ERROR(221, "账户余额锁定失败"),
+    ACCOUNT_UNLOCK_ERROR(221, "账户余额解锁失败"),
+    ACCOUNT_MINUSLOCK_ERROR(221, "账户余额扣减失败"),
+    ACCOUNT_LOCK_REPEAT(221, "重复锁定"),
+    ACCOUNT_LOCK_RESULT_NULL(221, "锁定账号结果对象为空"),
+    ORDER_SUBMIT_REPEAT(221, "超时或重复提交订单"),
+
+    NO_BUY_NOT_SEE(230, "未购买不能观看"),
+
+    EXIST_NO_EXPIRE_LIVE(230, "当前存在未过期直播"),
+
+    REPEAT_BUY_ERROR(231, "已经购买过该专辑"),
+
+    ;
+
+    private Integer code;
+
+    private String message;
+
+    private ResultCodeEnum(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+}

+ 22 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/AuthContextHolder.java

@@ -0,0 +1,22 @@
+package com.atguigu.tingshu.common.util;
+
+/**
+ * 获取当前用户信息帮助类
+ */
+public class AuthContextHolder {
+
+    private static ThreadLocal<Long> userId = new ThreadLocal<Long>();
+
+    public static void setUserId(Long _userId) {
+        userId.set(_userId);
+    }
+
+    public static Long getUserId() {
+        return userId.get();
+    }
+
+    public static void removeUserId() {
+        userId.remove();
+    }
+
+}

+ 31 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/Decimal2Serializer.java

@@ -0,0 +1,31 @@
+package com.atguigu.tingshu.common.util;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+
+/**
+ * @description 小数保留2位返回给前端序列化器
+ */
+public class Decimal2Serializer extends JsonSerializer<Object> {
+
+    /**
+     * 将返回的BigDecimal保留两位小数,再返回给前端
+     * @param value
+     * @param jsonGenerator
+     * @param serializerProvider
+     * @throws IOException
+     * @throws JsonProcessingException
+     */
+    @Override
+    public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
+        if (value != null) {
+            BigDecimal bigDecimal = new BigDecimal(value.toString()).setScale(2,BigDecimal.ROUND_HALF_UP);
+            jsonGenerator.writeString(bigDecimal.toString());
+        }
+    }
+}

+ 38 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/ExceptionUtil.java

@@ -0,0 +1,38 @@
+package com.atguigu.tingshu.common.util;
+
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Exception工具类
+ */
+public class ExceptionUtil {
+
+    /**
+     * 获取异常信息
+     * @param e  异常
+     * @return    返回异常信息
+     */
+    public static String getErrorMessage(Exception e){
+        StringWriter sw = null;
+        PrintWriter pw = null;
+        try {
+            sw = new StringWriter();
+            pw = new PrintWriter(sw, true);
+            e.printStackTrace(pw);
+        }finally {
+            try {
+                if(pw != null) {
+                    pw.close();
+                }
+                if(sw != null) {
+                    sw.close();
+                }
+            } catch (Exception e1) {
+                e1.printStackTrace();
+            }
+        }
+        return sw.toString();
+    }
+}

+ 318 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/HttpClientUtils.java

@@ -0,0 +1,318 @@
+//package com.atguigu.tingshu.common.util;
+//
+//
+//import org.apache.commons.io.IOUtils;
+//import org.apache.http.Consts;
+//import org.apache.http.HttpEntity;
+//import org.apache.http.HttpResponse;
+//import org.apache.http.NameValuePair;
+//import org.apache.http.client.HttpClient;
+//import org.apache.http.client.config.RequestConfig;
+//import org.apache.http.client.config.RequestConfig.Builder;
+//import org.apache.http.client.entity.UrlEncodedFormEntity;
+//import org.apache.http.client.methods.HttpGet;
+//import org.apache.http.client.methods.HttpPost;
+//import org.apache.http.conn.ConnectTimeoutException;
+//import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+//import org.apache.http.conn.ssl.SSLContextBuilder;
+//import org.apache.http.conn.ssl.TrustStrategy;
+//import org.apache.http.conn.ssl.X509HostnameVerifier;
+//import org.apache.http.entity.ContentType;
+//import org.apache.http.entity.StringEntity;
+//import org.apache.http.impl.client.CloseableHttpClient;
+//import org.apache.http.impl.client.HttpClients;
+//import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+//import org.apache.http.message.BasicNameValuePair;
+//import org.springframework.util.StringUtils;
+//
+//import javax.net.ssl.SSLContext;
+//import javax.net.ssl.SSLException;
+//import javax.net.ssl.SSLSession;
+//import javax.net.ssl.SSLSocket;
+//import java.io.IOException;
+//import java.net.SocketTimeoutException;
+//import java.security.GeneralSecurityException;
+//import java.security.cert.CertificateException;
+//import java.security.cert.X509Certificate;
+//import java.util.ArrayList;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Map.Entry;
+//import java.util.Set;
+//
+//public class HttpClientUtils {
+//
+//	public static final int connTimeout=10000;
+//	public static final int readTimeout=10000;
+//	public static final String charset="UTF-8";
+//	private static HttpClient client = null;
+//
+//	static {
+//		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
+//		cm.setMaxTotal(128);
+//		cm.setDefaultMaxPerRoute(128);
+//		client = HttpClients.custom().setConnectionManager(cm).build();
+//	}
+//
+//	public static String postParameters(String url, String parameterStr) throws ConnectTimeoutException, SocketTimeoutException, Exception{
+//		return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
+//	}
+//
+//	public static String postParameters(String url, String parameterStr,String charset, Integer connTimeout, Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception{
+//		return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
+//	}
+//
+//	public static String postParameters(String url, Map<String, String> params) throws ConnectTimeoutException,
+//			SocketTimeoutException, Exception {
+//		return postForm(url, params, null, connTimeout, readTimeout);
+//	}
+//
+//	public static String postParameters(String url, Map<String, String> params, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
+//			SocketTimeoutException, Exception {
+//		return postForm(url, params, null, connTimeout, readTimeout);
+//	}
+//
+//	public static String get(String url) throws Exception {
+//		return get(url, charset, null, null);
+//	}
+//
+//	public static String get(String url, String charset) throws Exception {
+//		return get(url, charset, connTimeout, readTimeout);
+//	}
+//
+//	/**
+//	 * 发送一个 Post 请求, 使用指定的字符集编码.
+//	 *
+//	 * @param url
+//	 * @param body RequestBody
+//	 * @param mimeType 例如 application/xml "application/x-www-form-urlencoded" a=1&b=2&c=3
+//	 * @param charset 编码
+//	 * @param connTimeout 建立链接超时时间,毫秒.
+//	 * @param readTimeout 响应超时时间,毫秒.
+//	 * @return ResponseBody, 使用指定的字符集编码.
+//	 * @throws ConnectTimeoutException 建立链接超时异常
+//	 * @throws SocketTimeoutException  响应超时
+//	 * @throws Exception
+//	 */
+//	public static String post(String url, String body, String mimeType,String charset, Integer connTimeout, Integer readTimeout)
+//			throws ConnectTimeoutException, SocketTimeoutException, Exception {
+//		HttpClient client = null;
+//		HttpPost post = new HttpPost(url);
+//		String result = "";
+//		try {
+//			if (!StringUtils.isEmpty(body)) {
+//				HttpEntity entity = new StringEntity(body, ContentType.create(mimeType, charset));
+//				post.setEntity(entity);
+//			}
+//			// 设置参数
+//			Builder customReqConf = RequestConfig.custom();
+//			if (connTimeout != null) {
+//				customReqConf.setConnectTimeout(connTimeout);
+//			}
+//			if (readTimeout != null) {
+//				customReqConf.setSocketTimeout(readTimeout);
+//			}
+//			post.setConfig(customReqConf.build());
+//
+//			HttpResponse res;
+//			if (url.startsWith("https")) {
+//				// 执行 Https 请求.
+//				client = createSSLInsecureClient();
+//				res = client.execute(post);
+//			} else {
+//				// 执行 Http 请求.
+//				client = HttpClientUtils.client;
+//				res = client.execute(post);
+//			}
+//			result = IOUtils.toString(res.getEntity().getContent(), charset);
+//		} finally {
+//			post.releaseConnection();
+//			if (url.startsWith("https") && client != null&& client instanceof CloseableHttpClient) {
+//				((CloseableHttpClient) client).close();
+//			}
+//		}
+//		return result;
+//	}
+//
+//
+//	/**
+//	 * 提交form表单
+//	 *
+//	 * @param url
+//	 * @param params
+//	 * @param connTimeout
+//	 * @param readTimeout
+//	 * @return
+//	 * @throws ConnectTimeoutException
+//	 * @throws SocketTimeoutException
+//	 * @throws Exception
+//	 */
+//	public static String postForm(String url, Map<String, String> params, Map<String, String> headers, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
+//			SocketTimeoutException, Exception {
+//
+//		HttpClient client = null;
+//		HttpPost post = new HttpPost(url);
+//		try {
+//			if (params != null && !params.isEmpty()) {
+//				List<NameValuePair> formParams = new ArrayList<NameValuePair>();
+//				Set<Entry<String, String>> entrySet = params.entrySet();
+//				for (Entry<String, String> entry : entrySet) {
+//					formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
+//				}
+//				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
+//				post.setEntity(entity);
+//			}
+//
+//			if (headers != null && !headers.isEmpty()) {
+//				for (Entry<String, String> entry : headers.entrySet()) {
+//					post.addHeader(entry.getKey(), entry.getValue());
+//				}
+//			}
+//			// 设置参数
+//			Builder customReqConf = RequestConfig.custom();
+//			if (connTimeout != null) {
+//				customReqConf.setConnectTimeout(connTimeout);
+//			}
+//			if (readTimeout != null) {
+//				customReqConf.setSocketTimeout(readTimeout);
+//			}
+//			post.setConfig(customReqConf.build());
+//			HttpResponse res = null;
+//			if (url.startsWith("https")) {
+//				// 执行 Https 请求.
+//				client = createSSLInsecureClient();
+//				res = client.execute(post);
+//			} else {
+//				// 执行 Http 请求.
+//				client = HttpClientUtils.client;
+//				res = client.execute(post);
+//			}
+//			return IOUtils.toString(res.getEntity().getContent(), "UTF-8");
+//		} finally {
+//			post.releaseConnection();
+//			if (url.startsWith("https") && client != null
+//					&& client instanceof CloseableHttpClient) {
+//				((CloseableHttpClient) client).close();
+//			}
+//		}
+//	}
+//
+//
+//
+//
+//	/**
+//	 * 发送一个 GET 请求
+//	 *
+//	 * @param url
+//	 * @param charset
+//	 * @param connTimeout  建立链接超时时间,毫秒.
+//	 * @param readTimeout  响应超时时间,毫秒.
+//	 * @return
+//	 * @throws ConnectTimeoutException   建立链接超时
+//	 * @throws SocketTimeoutException   响应超时
+//	 * @throws Exception
+//	 */
+//	public static String get(String url, String charset, Integer connTimeout,Integer readTimeout)
+//			throws ConnectTimeoutException,SocketTimeoutException, Exception {
+//
+//		HttpClient client = null;
+//		HttpGet get = new HttpGet(url);
+//		String result = "";
+//		try {
+//			// 设置参数
+//			Builder customReqConf = RequestConfig.custom();
+//			if (connTimeout != null) {
+//				customReqConf.setConnectTimeout(connTimeout);
+//			}
+//			if (readTimeout != null) {
+//				customReqConf.setSocketTimeout(readTimeout);
+//			}
+//			get.setConfig(customReqConf.build());
+//
+//			HttpResponse res = null;
+//
+//			if (url.startsWith("https")) {
+//				// 执行 Https 请求.
+//				client = createSSLInsecureClient();
+//				res = client.execute(get);
+//			} else {
+//				// 执行 Http 请求.
+//				client = HttpClientUtils.client;
+//				res = client.execute(get);
+//			}
+//
+//			result = IOUtils.toString(res.getEntity().getContent(), charset);
+//		} finally {
+//			get.releaseConnection();
+//			if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) {
+//				((CloseableHttpClient) client).close();
+//			}
+//		}
+//		return result;
+//	}
+//
+//
+//	/**
+//	 * 从 response 里获取 charset
+//	 *
+//	 * @param ressponse
+//	 * @return
+//	 */
+//	@SuppressWarnings("unused")
+//	private static String getCharsetFromResponse(HttpResponse ressponse) {
+//		// Content-Type:text/html; charset=GBK
+//		if (ressponse.getEntity() != null  && ressponse.getEntity().getContentType() != null && ressponse.getEntity().getContentType().getValue() != null) {
+//			String contentType = ressponse.getEntity().getContentType().getValue();
+//			if (contentType.contains("charset=")) {
+//				return contentType.substring(contentType.indexOf("charset=") + 8);
+//			}
+//		}
+//		return null;
+//	}
+//
+//
+//
+//	/**
+//	 * 创建 SSL连接
+//	 * @return
+//	 * @throws GeneralSecurityException
+//	 */
+//	private static CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException {
+//		try {
+//			SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
+//				public boolean isTrusted(X509Certificate[] chain,String authType) throws CertificateException {
+//					return true;
+//				}
+//			}).build();
+//
+//			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
+//
+//				@Override
+//				public boolean verify(String arg0, SSLSession arg1) {
+//					return true;
+//				}
+//
+//				@Override
+//				public void verify(String host, SSLSocket ssl)
+//						throws IOException {
+//				}
+//
+//				@Override
+//				public void verify(String host, X509Certificate cert)
+//						throws SSLException {
+//				}
+//
+//				@Override
+//				public void verify(String host, String[] cns,
+//								   String[] subjectAlts) throws SSLException {
+//				}
+//
+//			});
+//
+//			return HttpClients.custom().setSSLSocketFactory(sslsf).build();
+//
+//		} catch (GeneralSecurityException e) {
+//			throw e;
+//		}
+//	}
+//}

+ 82 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/IpUtil.java

@@ -0,0 +1,82 @@
+package com.atguigu.tingshu.common.util;
+
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * 获取ip地址
+ */
+public class IpUtil {
+
+    public static String getIpAddress(HttpServletRequest request) {
+        String ipAddress = null;
+        try {
+            ipAddress = request.getHeader("x-forwarded-for");
+            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+                ipAddress = request.getHeader("Proxy-Client-IP");
+            }
+            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+                ipAddress = request.getHeader("WL-Proxy-Client-IP");
+            }
+            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+                ipAddress = request.getRemoteAddr();
+                if (ipAddress.equals("127.0.0.1")) {
+                    // 根据网卡取本机配置的IP
+                    InetAddress inet = null;
+                    try {
+                        inet = InetAddress.getLocalHost();
+                    } catch (UnknownHostException e) {
+                        e.printStackTrace();
+                    }
+                    ipAddress = inet.getHostAddress();
+                }
+            }
+            // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
+            if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
+                // = 15
+                if (ipAddress.indexOf(",") > 0) {
+                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
+                }
+            }
+        } catch (Exception e) {
+            ipAddress="";
+        }
+        // ipAddress = this.getRequest().getRemoteAddr();
+
+        return ipAddress;
+    }
+
+    public static String getGatwayIpAddress(ServerHttpRequest request) {
+        HttpHeaders headers = request.getHeaders();
+        String ip = headers.getFirst("x-forwarded-for");
+        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
+            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
+            if (ip.indexOf(",") != -1) {
+                ip = ip.split(",")[0];
+            }
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("HTTP_CLIENT_IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("X-Real-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddress().getAddress().getHostAddress();
+        }
+        return ip;
+    }
+}

+ 39 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/MD5.java

@@ -0,0 +1,39 @@
+package com.atguigu.tingshu.common.util;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+
+public final class MD5 {
+
+    public static String encrypt(String strSrc) {
+        try {
+            char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
+                    '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+            byte[] bytes = strSrc.getBytes();
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            md.update(bytes);
+            bytes = md.digest();
+            int j = bytes.length;
+            char[] chars = new char[j * 2];
+            int k = 0;
+            for (int i = 0; i < bytes.length; i++) {
+                byte b = bytes[i];
+                chars[k++] = hexChars[b >>> 4 & 0xf];
+                chars[k++] = hexChars[b & 0xf];
+            }
+            return new String(chars);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            throw new RuntimeException("MD5加密出错!!+" + e);
+        }
+    }
+
+    public static void main(String[] args) {
+        String msg = "{\"liveRoomId\":1,\"msgContent\":1,\"msgType\":\"4\",\"timestamp\":1679969941853}";
+        System.out.println(msg);
+        msg = msg.replaceAll("\\\\", "");
+        System.out.println(msg);
+        System.out.println(MD5.encrypt("111111"));
+    }
+}

+ 38 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/MongoUtil.java

@@ -0,0 +1,38 @@
+package com.atguigu.tingshu.common.util;
+
+import lombok.Getter;
+
+public class MongoUtil {
+
+    @Getter
+    public enum MongoCollectionEnum {
+
+        USER_SUBSCRIBE(100,"userSubscribe"),
+        USER_COLLECT(100,"userCollect"),
+        USER_LISTEN_PROCESS(100,"userListenProcess"),
+        COMMENT(100,"comment"),
+        COMMENT_PRAISE(100,"commentPraise"),
+        ;
+
+        private Integer partition;
+        private String collectionPrefix;
+
+        MongoCollectionEnum(Integer partition, String collectionPrefix) {
+            this.partition = partition;
+            this.collectionPrefix = collectionPrefix;
+        }
+
+    }
+
+
+    /**
+     * 获取mongo表名
+     * @param mongoCollection Collection前缀
+     * @param userId 用户ID
+     * @return
+     */
+    public static String getCollectionName(MongoCollectionEnum mongoCollection, Long userId) {
+        return mongoCollection.getCollectionPrefix() + "_" + userId;
+    }
+}
+

+ 65 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/RandomUtil.java

@@ -0,0 +1,65 @@
+package com.atguigu.tingshu.common.util;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * 获取随机数
+ * 
+ * @author qianyi
+ *
+ */
+public class RandomUtil {
+
+	private static final Random random = new Random();
+
+	private static final DecimalFormat fourdf = new DecimalFormat("0000");
+
+	private static final DecimalFormat sixdf = new DecimalFormat("000000");
+
+	public static String getFourBitRandom() {
+		return fourdf.format(random.nextInt(10000));
+	}
+
+	public static String getSixBitRandom() {
+		return sixdf.format(random.nextInt(1000000));
+	}
+
+	/**
+	 * 给定数组,抽取n个数据
+	 * 
+	 * @param swQidsList
+	 * @param n
+	 * @return
+	 */
+	public static ArrayList getRandom(List list, int n) {
+
+		Random random = new Random();
+
+		HashMap<Object, Object> hashMap = new HashMap<Object, Object>();
+
+		// 生成随机数字并存入HashMap
+		for (int i = 0; i < list.size(); i++) {
+
+			int number = random.nextInt(100) + 1;
+
+			hashMap.put(number, i);
+		}
+
+		// 从HashMap导入数组
+		Object[] robjs = hashMap.values().toArray();
+
+		ArrayList r = new ArrayList();
+
+		// 遍历数组并打印数据
+		for (int i = 0; i < n; i++) {
+			r.add(list.get((int) robjs[i]));
+			System.out.print(list.get((int) robjs[i]) + "\t");
+		}
+		System.out.print("\n");
+		return r;
+	}
+}

+ 23 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/ResponseUtil.java

@@ -0,0 +1,23 @@
+package com.atguigu.tingshu.common.util;
+
+import com.atguigu.tingshu.common.result.Result;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+
+import java.io.IOException;
+
+public class ResponseUtil {
+
+    public static void out(HttpServletResponse response, Result r) {
+        ObjectMapper mapper = new ObjectMapper();
+        response.setStatus(HttpStatus.OK.value());
+        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
+        try {
+            mapper.writeValue(response.getWriter(), r);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 191 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/SensitiveWordFilterUtil.java

@@ -0,0 +1,191 @@
+package com.atguigu.tingshu.common.util;
+
+import java.util.*;
+
+public class SensitiveWordFilterUtil {
+
+    //构建一个DFA算法模型
+    private static Map sensitiveWordMap = null;
+
+    /**
+     * 敏感词替换
+     * @param txt
+     * @return
+     */
+    public static String replaceSensitiveWord(String txt){
+        if(null == sensitiveWordMap) return txt;
+        return replaceSensitiveWord(txt, 1, "*");
+    }
+
+    /**
+     * 读取敏感词库,将敏感词放入HashSet中,构建一个DFA算法模型:<br>
+     * 中 = {
+     *      isEnd = 0
+     *      国 = {<br>
+     *      	 isEnd = 1
+     *           人 = {isEnd = 0
+     *                民 = {isEnd = 1}
+     *                }
+     *           男  = {
+     *           	   isEnd = 0
+     *           		人 = {
+     *           			 isEnd = 1
+     *           			}
+     *           	}
+     *           }
+     *      }
+     *  五 = {
+     *      isEnd = 0
+     *      星 = {
+     *      	isEnd = 0
+     *      	红 = {
+     *              isEnd = 0
+     *              旗 = {
+     *                   isEnd = 1
+     *                  }
+     *              }
+     *      	}
+     *      }
+     */
+    public static void buildDFAModel(List<String> keyWordList) {
+        sensitiveWordMap = new HashMap(keyWordList.size());     //初始化敏感词容器,减少扩容操作
+        String key = null;
+        Map nowMap = null;
+        Map<String, String> newWorMap = null;
+        //迭代keyWordSet
+        Iterator<String> iterator = keyWordList.iterator();
+        while(iterator.hasNext()){
+            key = iterator.next();    //关键字
+            nowMap = sensitiveWordMap;
+            for(int i = 0 ; i < key.length() ; i++){
+                char keyChar = key.charAt(i);       //转换成char型
+                Object wordMap = nowMap.get(keyChar);       //获取
+
+                if(wordMap != null){        //如果存在该key,直接赋值
+                    nowMap = (Map) wordMap;
+                }
+                else{     //不存在则,则构建一个map,同时将isEnd设置为0,因为他不是最后一个
+                    newWorMap = new HashMap<String,String>();
+                    newWorMap.put("isEnd", "0");     //不是最后一个
+                    nowMap.put(keyChar, newWorMap);
+                    nowMap = newWorMap;
+                }
+
+                if(i == key.length() - 1){
+                    nowMap.put("isEnd", "1");    //最后一个
+                }
+            }
+        }
+    }
+
+    /**
+     * 获取文字中的敏感词
+     * @param txt 文字
+     * @param matchType 匹配规则&nbsp;1:最小匹配规则,2:最大匹配规则
+     * @return
+     */
+    private static Set<String> getSensitiveWord(String txt , int matchType){
+        Set<String> sensitiveWordList = new HashSet<String>();
+
+        for(int i = 0 ; i < txt.length() ; i++){
+            int length = CheckSensitiveWord(txt, i, matchType);    //判断是否包含敏感字符
+            if(length > 0){    //存在,加入list中
+                sensitiveWordList.add(txt.substring(i, i+length));
+                i = i + length - 1;    //减1的原因,是因为for会自增
+            }
+        }
+
+        return sensitiveWordList;
+    }
+
+    /**
+     * 替换敏感字字符
+     * @param txt
+     * @param matchType
+     * @param replaceChar 替换字符,默认*
+     */
+    private static String replaceSensitiveWord(String txt,int matchType,String replaceChar){
+        String resultTxt = txt;
+        Set<String> set = getSensitiveWord(txt, matchType);     //获取所有的敏感词
+        Iterator<String> iterator = set.iterator();
+        String word = null;
+        String replaceString = null;
+        while (iterator.hasNext()) {
+            word = iterator.next();
+            replaceString = getReplaceChars(replaceChar, word.length());
+            resultTxt = resultTxt.replaceAll(word, replaceString);
+        }
+
+        return resultTxt;
+    }
+
+    /**
+     * 获取替换字符串
+     * @param replaceChar
+     * @param length
+     * @return
+     */
+    private static String getReplaceChars(String replaceChar,int length){
+        String resultReplace = replaceChar;
+        for(int i = 1 ; i < length ; i++){
+            resultReplace += replaceChar;
+        }
+
+        return resultReplace;
+    }
+
+    /**
+     * 检查文字中是否包含敏感字符,检查规则如下:<br>
+     * @param txt
+     * @param beginIndex
+     * @param matchType
+     * @return,如果存在,则返回敏感词字符的长度,不存在返回0
+     */
+    private static int CheckSensitiveWord(String txt,int beginIndex,int matchType){
+        boolean  flag = false;    //敏感词结束标识位:用于敏感词只有1位的情况
+        int matchFlag = 0;     //匹配标识数默认为0
+        char word = 0;
+        Map nowMap = sensitiveWordMap;
+        for(int i = beginIndex; i < txt.length() ; i++){
+            word = txt.charAt(i);
+            nowMap = (Map) nowMap.get(word);     //获取指定key
+            if(nowMap != null){     //存在,则判断是否为最后一个
+                matchFlag++;     //找到相应key,匹配标识+1
+                if("1".equals(nowMap.get("isEnd"))){       //如果为最后一个匹配规则,结束循环,返回匹配标识数
+                    flag = true;       //结束标志位为true
+                    if(matchType == 1){    //最小规则,直接返回,最大规则还需继续查找
+                        break;
+                    }
+                }
+            }
+            else{     //不存在,直接返回
+                break;
+            }
+        }
+        if(matchFlag < 2 || !flag){        //长度必须大于等于1,为词
+            matchFlag = 0;
+        }
+        return matchFlag;
+    }
+
+    public static void main(String[] args) {
+        //System.out.println("敏感词的数量:" + filter.sensitiveWordMap.size());
+        String string = "太多的伤感情怀也许只局限于饲养基地 荧幕中的情节,主人公尝试着去用某种方式渐渐的很潇洒地释自杀指南怀那些自己经历的伤感。"
+                + "然后法轮功 我们的扮演的角色就是跟随着主人公的喜红客联盟 怒哀乐而过于牵强的把自己的情感也附加于银幕情节中,然后感动就流泪,"
+                + "难过就躺在某一个人的怀里尽情的阐述心扉或者手机卡复制器一个人一杯红酒一部电影在夜三级片 深人静的晚上,关上电话静静的发呆着。";
+        System.out.println("待检测语句字数:" + string.length());
+        long beginTime = System.currentTimeMillis();
+
+        List<String> keyWordSet = new ArrayList<>();
+        keyWordSet.add("黄色");
+        keyWordSet.add("自杀");
+        keyWordSet.add("法轮功");
+        keyWordSet.add("三级片");
+        SensitiveWordFilterUtil.buildDFAModel(keyWordSet);
+
+        String content = SensitiveWordFilterUtil.replaceSensitiveWord(string);
+        System.out.println("替换后:" + content);
+        long endTime = System.currentTimeMillis();
+        System.out.println("总共消耗时间为:" + (endTime - beginTime));
+    }
+}

+ 31 - 0
common/common-util/src/main/java/com/atguigu/tingshu/common/util/UploadFileUtil.java

@@ -0,0 +1,31 @@
+package com.atguigu.tingshu.common.util;
+
+import lombok.SneakyThrows;
+import org.joda.time.DateTime;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+
+
+public class UploadFileUtil {
+
+    /**
+     * 文件上传到临时路径
+     * @param file
+     * @return
+     */
+    @SneakyThrows
+    public static String uploadTempPath(String tempPath, MultipartFile file) {
+        if (null == file) return "";
+        String date = new DateTime().toString("yyyyMMdd");
+        String filePath = tempPath + File.separator + date;
+        File curFlie = new File(filePath);
+        if (!curFlie.exists()) {
+            curFlie.mkdirs();
+        }
+        filePath = filePath + File.separator + file.getOriginalFilename();
+        file.transferTo(new File(filePath));
+        return filePath;
+    }
+
+}

+ 22 - 0
common/pom.xml

@@ -0,0 +1,22 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>tingshu-parent</artifactId>
+        <groupId>com.atguigu.tingshu</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>common</artifactId>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>service-util</module>
+        <module>common-util</module>
+        <module>rabbit-util</module>
+        <module>common-log</module>
+    </modules>
+
+</project>

+ 48 - 0
common/rabbit-util/pom.xml

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>common</artifactId>
+        <groupId>com.atguigu.tingshu</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rabbit-util</artifactId>
+    <version>1.0</version>
+    <packaging>jar</packaging>
+
+    <description>
+        rabbit-util服务
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!--rabbitmq消息队列-->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>

+ 139 - 0
common/rabbit-util/src/main/java/com/atguigu/tingshu/common/rabbit/config/RabbitInitConfigApplicationListener.java

@@ -0,0 +1,139 @@
+package com.atguigu.tingshu.common.rabbit.config;
+
+import com.alibaba.fastjson.JSON;
+import com.atguigu.tingshu.common.rabbit.entity.GuiguCorrelationData;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.rabbit.connection.CorrelationData;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+
+@Slf4j
+@Component
+public class RabbitInitConfigApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
+
+    @Autowired
+    private RabbitTemplate rabbitTemplate;
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    @Override
+    public void onApplicationEvent(ApplicationReadyEvent event) {
+        this.setupCallbacks();
+    }
+
+    private void setupCallbacks() {
+
+        /**
+         * 只确认消息是否正确到达 Exchange 中,成功与否都会回调
+         *
+         * @param correlation 相关数据  非消息本身业务数据
+         * @param ack             应答结果
+         * @param reason           如果发送消息到交换器失败,错误原因
+         */
+        this.rabbitTemplate.setConfirmCallback((correlationData, ack, reason) -> {
+            if (ack) {
+                //消息到交换器成功
+                log.info("消息发送到Exchange成功:{}", correlationData);
+            } else {
+                //消息到交换器失败
+                log.error("消息发送到Exchange失败:{}", reason);
+
+                //执行消息重发
+                this.retrySendMsg(correlationData);
+            }
+        });
+
+        /**
+         * 消息没有正确到达队列时触发回调,如果正确到达队列不执行
+         */
+        this.rabbitTemplate.setReturnsCallback(returned -> {
+            log.error("Returned: " + returned.getMessage() + "\nreplyCode: " + returned.getReplyCode()
+                    + "\nreplyText: " + returned.getReplyText() + "\nexchange/rk: "
+                    + returned.getExchange() + "/" + returned.getRoutingKey());
+
+            //当路由队列失败 也需要重发
+            //1.构建相关数据对象
+            String redisKey = returned.getMessage().getMessageProperties().getHeader("spring_returned_message_correlation");
+            String correlationDataStr = (String) redisTemplate.opsForValue().get(redisKey);
+            GuiguCorrelationData guiguCorrelationData = JSON.parseObject(correlationDataStr, GuiguCorrelationData.class);
+            //todo 方式一:如果不考虑延迟消息重发 直接返回
+            if(guiguCorrelationData.isDelay()){
+                return;
+            }
+            //2.调用消息重发方法
+            this.retrySendMsg(guiguCorrelationData);
+        });
+    }
+
+//    /**
+//     * 消息重新发送
+//     *
+//     * @param correlationData
+//     */
+//    private void retrySendMsg(CorrelationData correlationData) {
+//        //获取相关数据
+//        GuiguCorrelationData gmallCorrelationData = (GuiguCorrelationData) correlationData;
+//
+//        //获取redis中存放重试次数
+//        //先重发,在写会到redis中次数
+//        int retryCount = gmallCorrelationData.getRetryCount();
+//        if (retryCount >= 3) {
+//            //超过最大重试次数
+//            log.error("生产者超过最大重试次数,将失败的消息存入数据库用人工处理;给管理员发送邮件;给管理员发送短信;");
+//            return;
+//        }
+//        //重发消息
+//        rabbitTemplate.convertAndSend(gmallCorrelationData.getExchange(), gmallCorrelationData.getRoutingKey(), gmallCorrelationData.getMessage(), gmallCorrelationData);
+//        //重发次数+1
+//        retryCount += 1;
+//        gmallCorrelationData.setRetryCount(retryCount);
+//        redisTemplate.opsForValue().set(gmallCorrelationData.getId(), JSON.toJSONString(gmallCorrelationData), 10, TimeUnit.MINUTES);
+//        log.info("进行消息重发!");
+//    }
+
+    /**
+     * 消息重新发送
+     *
+     * @param correlationData
+     */
+    private void retrySendMsg(CorrelationData correlationData) {
+        //获取相关数据
+        GuiguCorrelationData gmallCorrelationData = (GuiguCorrelationData) correlationData;
+
+        //获取redis中存放重试次数
+        //先重发,在写会到redis中次数
+        int retryCount = gmallCorrelationData.getRetryCount();
+        if (retryCount >= 3) {
+            //超过最大重试次数
+            log.error("生产者超过最大重试次数,将失败的消息存入数据库用人工处理;给管理员发送邮件;给管理员发送短信;");
+            return;
+        }
+        //重发次数+1
+        retryCount += 1;
+        gmallCorrelationData.setRetryCount(retryCount);
+        redisTemplate.opsForValue().set(gmallCorrelationData.getId(), JSON.toJSONString(gmallCorrelationData), 10, TimeUnit.MINUTES);
+        log.info("进行消息重发!");
+        //重发消息
+        //todo 方式二:如果是延迟消息,依然需要设置消息延迟时间
+        if (gmallCorrelationData.isDelay()) {
+            //延迟消息
+            rabbitTemplate.convertAndSend(gmallCorrelationData.getExchange(), gmallCorrelationData.getRoutingKey(), gmallCorrelationData.getMessage(), message -> {
+                message.getMessageProperties().setDelay(gmallCorrelationData.getDelayTime() * 1000);
+                return message;
+            }, gmallCorrelationData);
+        } else {
+            //普通消息
+            rabbitTemplate.convertAndSend(gmallCorrelationData.getExchange(), gmallCorrelationData.getRoutingKey(), gmallCorrelationData.getMessage(), gmallCorrelationData);
+        }
+    }
+
+}
+

+ 80 - 0
common/rabbit-util/src/main/java/com/atguigu/tingshu/common/rabbit/constant/MqConst.java

@@ -0,0 +1,80 @@
+package com.atguigu.tingshu.common.rabbit.constant;
+
+public class MqConst {
+
+    /**
+     * 专辑
+     */
+    public static final String EXCHANGE_ALBUM = "tingshu.album";
+    public static final String ROUTING_ALBUM_UPPER  = "tingshu.album.upper";
+    public static final String ROUTING_ALBUM_LOWER  = "tingshu.album.lower";
+    public static final String ROUTING_ALBUM_STAT_UPDATE = "tingshu.album.stat.update";
+    public static final String ROUTING_ALBUM_ES_STAT_UPDATE = "tingshu.album.es.stat.update";
+    public static final String ROUTING_ALBUM_RANKING_UPDATE = "tingshu.album.ranking.update";
+    //队列
+    public static final String QUEUE_ALBUM_UPPER  = "tingshu.album.upper";
+    public static final String QUEUE_ALBUM_LOWER  = "tingshu.album.lower";
+    public static final String QUEUE_ALBUM_STAT_UPDATE = "tingshu.album.stat.update";
+    public static final String QUEUE_ALBUM_ES_STAT_UPDATE = "tingshu.album.es.stat.update";
+    public static final String QUEUE_ALBUM_RANKING_UPDATE = "tingshu.album.ranking.update";
+
+    /**
+     * 声音
+     */
+    public static final String EXCHANGE_TRACK = "tingshu.track";
+    public static final String ROUTING_TRACK_STAT_UPDATE = "tingshu.track.stat.update";
+    public static final String QUEUE_TRACK_STAT_UPDATE = "tingshu.track.stat.update";
+
+    /**
+     * 取消订单
+     */
+    //延迟取消订单队列
+    /**
+     * 取消订单延迟消息
+     */
+    public static final String EXCHANGE_CANCEL_ORDER = "tingshu.cancel.order";
+    public static final String ROUTING_CANCEL_ORDER = "tingshu.cancel.order";
+    public static final String QUEUE_CANCEL_ORDER = "tingshu.cancel.order";
+    public static final Integer CANCEL_ORDER_DELAY_TIME = 15 * 60;
+
+    /**
+     * 支付
+     */
+    public static final String EXCHANGE_ORDER = "tingshu.order";
+    public static final String ROUTING_ORDER_PAY_SUCCESS  = "tingshu.order.pay.success";
+    public static final String ROUTING_RECHARGE_PAY_SUCCESS  = "tingshu.recharge.pay.success";
+    public static final String QUEUE_ORDER_PAY_SUCCESS  = "tingshu.order.pay.success";
+    public static final String QUEUE_RECHARGE_PAY_SUCCESS  = "tingshu.recharge.pay.success";
+
+
+    /**
+     * 账户
+     */
+    public static final String EXCHANGE_ACCOUNT = "tingshu.account";
+    public static final String ROUTING_ACCOUNT_UNLOCK  = "tingshu.account.unlock";
+    public static final String ROUTING_ACCOUNT_MINUS  = "tingshu.account.minus";
+    public static final String QUEUE_ACCOUNT_UNLOCK  = "tingshu.account.unlock";
+    public static final String QUEUE_ACCOUNT_MINUS  = "tingshu.account.minus";
+
+    /**
+     * 用户
+     */
+    public static final String EXCHANGE_USER = "tingshu.user";
+    public static final String ROUTING_USER_PAY_RECORD  = "tingshu.user.pay.record";
+    public static final String ROUTING_USER_REGISTER  = "tingshu.user.register";
+    public static final String ROUTING_USER_VIP_EXPIRE_STATUS = "tingshu.user.vip.expire.status";
+    public static final String QUEUE_USER_PAY_RECORD  = "tingshu.user.pay.record";
+    public static final String QUEUE_USER_REGISTER  = "tingshu.user.register";
+    public static final String QUEUE_USER_VIP_EXPIRE_STATUS = "tingshu.user.vip.expire.status";
+
+    /**
+     * 热门关键字
+     */
+    public static final String EXCHANGE_KEYWORD = "tingshu.keyword";
+    public static final String ROUTING_KEYWORD_INPUT  = "tingshu.keyword.input";
+    public static final String ROUTING_KEYWORD_OUT  = "tingshu.keyword.out";
+    public static final String QUEUE_KEYWORD_INPUT  = "tingshu.keyword.input";
+    public static final String QUEUE_KEYWORD_OUT  = "tingshu.keyword.out";
+
+
+}

+ 21 - 0
common/rabbit-util/src/main/java/com/atguigu/tingshu/common/rabbit/entity/GuiguCorrelationData.java

@@ -0,0 +1,21 @@
+package com.atguigu.tingshu.common.rabbit.entity;
+
+import lombok.Data;
+import org.springframework.amqp.rabbit.connection.CorrelationData;
+
+@Data
+public class GuiguCorrelationData extends CorrelationData {
+
+    //消息体
+    private Object message;
+    //交换机
+    private String exchange;
+    //路由键
+    private String routingKey;
+    //重试次数
+    private int retryCount = 0;
+    //是否延迟消息
+    private boolean isDelay = false;
+    //延迟时长
+    private int delayTime = 10;
+}

+ 74 - 0
common/rabbit-util/src/main/java/com/atguigu/tingshu/common/rabbit/service/RabbitService.java

@@ -0,0 +1,74 @@
+package com.atguigu.tingshu.common.rabbit.service;
+
+
+import com.alibaba.fastjson.JSON;
+import com.atguigu.tingshu.common.rabbit.entity.GuiguCorrelationData;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class RabbitService {
+
+    @Autowired
+    private RabbitTemplate rabbitTemplate;
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    /**
+     * 发送消息
+     *
+     * @param exchange   交换机
+     * @param routingKey 路由键
+     * @param message    消息
+     */
+    public boolean sendMessage(String exchange, String routingKey, Object message) {
+        //1.创建自定义相关消息对象-包含业务数据本身,交换器名称,路由键,队列类型,延迟时间,重试次数
+        GuiguCorrelationData correlationData = new GuiguCorrelationData();
+        String uuid = "mq:" + UUID.randomUUID().toString().replaceAll("-", "");
+        correlationData.setId(uuid);
+        correlationData.setMessage(message);
+        correlationData.setExchange(exchange);
+        correlationData.setRoutingKey(routingKey);
+        //2.将相关消息存入Redis  Key:UUID  相关消息对象  10 分钟
+        redisTemplate.opsForValue().set(uuid, JSON.toJSONString(correlationData), 10, TimeUnit.MINUTES);
+        //3.将相关消息封装到发送消息方法中
+        rabbitTemplate.convertAndSend(exchange, routingKey, message, correlationData);
+        return true;
+    }
+
+    /**
+     * 发送延迟消息方法
+     *
+     * @param exchange   交换机
+     * @param routingKey 路由键
+     * @param message    消息数据
+     * @param delayTime  延迟时间,单位为:秒
+     */
+    public boolean sendDealyMessage(String exchange, String routingKey, Object message, int delayTime) {
+        //1.创建自定义相关消息对象-包含业务数据本身,交换器名称,路由键,队列类型,延迟时间,重试次数
+        GuiguCorrelationData correlationData = new GuiguCorrelationData();
+        String uuid = "mq:" + UUID.randomUUID().toString().replaceAll("-", "");
+        correlationData.setId(uuid);
+        correlationData.setMessage(message);
+        correlationData.setExchange(exchange);
+        correlationData.setRoutingKey(routingKey);
+        correlationData.setDelay(true);
+        correlationData.setDelayTime(delayTime);
+
+        //2.将相关消息存入Redis  Key:UUID  相关消息对象  10 分钟
+        redisTemplate.opsForValue().set(uuid, JSON.toJSONString(correlationData), 10, TimeUnit.MINUTES);
+        //3.将相关消息封装到发送消息方法中
+        rabbitTemplate.convertAndSend(exchange, routingKey, message, message1 -> {
+            message1.getMessageProperties().setDelay(delayTime * 1000);
+            return message1;
+        }, correlationData);
+        return true;
+    }
+
+}

+ 92 - 0
common/service-util/pom.xml

@@ -0,0 +1,92 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>common</artifactId>
+        <groupId>com.atguigu.tingshu</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>service-util</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.atguigu.tingshu</groupId>
+            <artifactId>common-util</artifactId>
+            <version>1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.atguigu.tingshu</groupId>
+            <artifactId>model</artifactId>
+            <version>1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+        <!--mysql-->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
+        </dependency>
+        <!-- 校验参数 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!-- redis -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <!-- redisson -->
+<!--        <dependency>-->
+<!--            <groupId>org.redisson</groupId>-->
+<!--            <artifactId>redisson-spring-boot-starter</artifactId>-->
+<!--        </dependency>-->
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <!-- 服务调用feign -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
+        </dependency>
+
+        <!-- 服务注册 -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+
+        <!-- 服务配置 -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 49 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/config/knife4j/Knife4jConfig.java

@@ -0,0 +1,49 @@
+package com.atguigu.tingshu.common.config.knife4j;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Contact;
+import io.swagger.v3.oas.models.info.Info;
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class Knife4jConfig {
+
+    @Value("${spring.application.name}")
+    private String appName;
+
+    @Bean
+    public GroupedOpenApi webApi() {
+        return GroupedOpenApi.builder()
+                .group("web-api")
+                .pathsToMatch("/api/**")
+                .build();
+    }
+
+    /*后台管理相关文档 接口地址以/admin开头 */
+    //@Bean
+    //public GroupedOpenApi adminApi() {
+    //    return GroupedOpenApi.builder()
+    //            .group("admin-api")
+    //            .pathsToMatch("/admin/**")
+    //            .build();
+    //}
+
+    /***
+     * @description 自定义接口信息
+     */
+    @Bean
+    public OpenAPI customOpenAPI() {
+
+        return new OpenAPI()
+                .info(new Info()
+                        .title(appName + "听书API接口文档")
+                        .version("1.0")
+                        .description("听书API接口文档")
+                        .contact(new Contact().name("atguigu")));
+    }
+
+
+}

+ 32 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/config/mybatisPlus/MybatisPlusConfig.java

@@ -0,0 +1,32 @@
+package com.atguigu.tingshu.common.config.mybatisPlus;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+/**
+ * MybatisPlus配置类
+ *
+ */
+@EnableTransactionManagement
+@Configuration
+@MapperScan("com.atguigu.tingshu.*.mapper")
+public class MybatisPlusConfig {
+
+    /**
+     *
+     * @return
+     */
+    @Bean
+    public MybatisPlusInterceptor optimisticLockerInnerInterceptor(){
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        //向Mybatis过滤器链中添加分页拦截器
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+        return interceptor;
+    }
+
+}

+ 39 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/config/redis/RedisConfig.java

@@ -0,0 +1,39 @@
+package com.atguigu.tingshu.common.config.redis;
+
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.*;
+
+
+/**
+ * Redis配置类
+ */
+@Configuration
+@EnableCaching
+public class RedisConfig {
+
+    @Bean
+    @Primary
+    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+
+        //String的序列化方式
+        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+        // 使用GenericJackson2JsonRedisSerializer 替换默认序列化(默认采用的是JDK序列化)
+        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
+
+        //序列号key value
+        redisTemplate.setKeySerializer(stringRedisSerializer);
+        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
+        redisTemplate.setHashKeySerializer(stringRedisSerializer);
+        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
+
+        redisTemplate.afterPropertiesSet();
+        return redisTemplate;
+    }
+}

+ 70 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/config/thread/ThreadPoolConfig.java

@@ -0,0 +1,70 @@
+package com.atguigu.tingshu.common.config.thread;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.*;
+
+/**
+ * @author: atguigu
+ * @create: 2024-08-09 11:28
+ */
+@Slf4j
+@Configuration
+public class ThreadPoolConfig {
+
+    /**
+     * 基于JDK(JUC)提供线程池Class
+     */
+    /*@Bean
+    public Executor threadPoolExecutor() {
+        //1.获取当前服务器核心数确定核心线程数
+        int cpuCoreCount = Runtime.getRuntime().availableProcessors();
+        int threadCount = cpuCoreCount * 2;
+        //2.通过构造方法创建线程池对象
+        ThreadPoolExecutor threadPoolExecutor =
+                new ThreadPoolExecutor(
+                        threadCount,
+                        threadCount,
+                        0,
+                        TimeUnit.SECONDS,
+                        new ArrayBlockingQueue<>(200),
+                        Executors.defaultThreadFactory(),
+                        new ThreadPoolExecutor.CallerRunsPolicy()
+                );
+        //3.可选:提交创建核心线程
+        threadPoolExecutor.prestartCoreThread();
+        return threadPoolExecutor;
+    }*/
+
+
+    /**
+     * 基于Spring提供线程池Class-threadPoolTaskExecutor 功能更强
+     */
+    @Bean
+    public Executor threadPoolTaskExecutor() {
+        int count = Runtime.getRuntime().availableProcessors();
+        int threadCount = count*2+1;
+        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
+        // 核心池大小
+        taskExecutor.setCorePoolSize(threadCount);
+        // 最大线程数
+        taskExecutor.setMaxPoolSize(threadCount);
+        // 队列程度
+        taskExecutor.setQueueCapacity(300);
+        // 线程空闲时间
+        taskExecutor.setKeepAliveSeconds(0);
+        // 线程前缀名称
+        taskExecutor.setThreadNamePrefix("async-tingshu-Executor--");
+        // 该方法用来设置 线程池关闭 的时候 等待 所有任务都完成后,再继续 销毁 其他的 Bean,
+        // 这样这些 异步任务 的 销毁 就会先于 数据库连接池对象 的销毁。
+        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
+        // 任务的等待时间 如果超过这个时间还没有销毁就 强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
+        taskExecutor.setAwaitTerminationSeconds(300);
+        // 线程不够用时由调用的线程处理该任务
+        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        return taskExecutor;
+    }
+}

+ 72 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/constant/RedisConstant.java

@@ -0,0 +1,72 @@
+package com.atguigu.tingshu.common.constant;
+
+public class RedisConstant {
+
+    public static final String ALBUM_INFO_PREFIX = "album:info:";
+
+    public static final String CACHE_INFO_PREFIX = "cache:info:";
+    public static final String CACHE_LOCK_SUFFIX = ":lock";
+
+    //单位:秒
+    //单位:秒 尝试获取锁的最大等待时间
+    public static final long ALBUM_LOCK_WAIT_PX1 = 1;
+    //单位:秒 锁的持有时间
+    public static final long ALBUM_LOCK_EXPIRE_PX2 = 3;
+
+    public static final long ALBUM_TIMEOUT = 1 * 60 * 60;
+    // 商品如果在数据库中不存在那么会缓存一个空对象进去,但是这个对象是没有用的,所以这个对象的过期时间应该不能太长,
+    // 如果太长会占用内存。
+    // 定义变量,记录空对象的缓存过期时间
+    public static final long ALBUM_TEMPORARY_TIMEOUT = 10 * 60;
+    //  布隆过滤器使用!
+    public static final String ALBUM_BLOOM_FILTER = "album:bloom:filter";
+
+
+    //订单防重流水号前缀
+    public static final String ORDER_TRADE_NO_PREFIX = "user:trade:";
+    //订单流水号有效期
+    public static final int ORDER_TRADE_EXPIRE = 5;
+
+
+    //单位:秒
+    //单位:秒 尝试获取锁的最大等待时间
+    public static final long CACHE_LOCK_EXPIRE_PX1 = 1;
+    //单位:秒 锁的持有时间
+    public static final long CACHE_LOCK_EXPIRE_PX2 = 1;
+
+    public static final long CACHE_TIMEOUT = 24 * 60 * 60;
+    // 商品如果在数据库中不存在那么会缓存一个空对象进去,但是这个对象是没有用的,所以这个对象的过期时间应该不能太长,
+    // 如果太长会占用内存。
+    // 定义变量,记录空对象的缓存过期时间
+    public static final long CACHE_TEMPORARY_TIMEOUT = 10 * 60;
+
+    //用户登录
+    public static final String USER_LOGIN_KEY_PREFIX = "user:login:";
+    public static final String USER_LOGIN_REFRESH_KEY_PREFIX = "user:login:refresh:";
+    public static final int USER_LOGIN_KEY_TIMEOUT = 60 * 60 * 24 * 7;
+    public static final int USER_LOGIN_REFRESH_KEY_TIMEOUT = 60 * 60 * 24 * 365;
+
+    public static final String RANKING_KEY_PREFIX = "ranking:";
+    public static final String ALBUM_STAT_ENDTIME = "album:stat:endTime";
+
+
+    //更新声音统计前缀
+    public static final String USER_TRACK_REPEAT_STAT_PREFIX = "user:track:";
+
+
+    //重复锁定账户
+    public static final String ACCOUNT_MUTIPLE_CHECK = "account:rechecklock:";
+    //账户锁定对象
+    public static final String ACCOUNT_CHECK_DATA = "account:check:";
+
+    //重复扣减锁定金额
+    public static final String ACCOUNT_MUTIPLE_MINUS = "account:deductlock";
+
+
+    //公用的业务标识前缀
+    public static final String BUSINESS_PREFIX = "biz:";
+
+
+
+
+}

+ 78 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/constant/SystemConstant.java

@@ -0,0 +1,78 @@
+package com.atguigu.tingshu.common.constant;
+
+public class SystemConstant {
+
+    //专辑付费类型  0101-免费、0102-vip免费、0103-付费
+    public static final String  ALBUM_PAY_TYPE_FREE="0101";  // 免费
+    public static final String  ALBUM_PAY_TYPE_VIPFREE="0102";  // vip免费
+    public static final String  ALBUM_PAY_TYPE_REQUIRE="0103";  // 付费
+
+    //专辑价格类型 0201-单集 0202-整专辑
+    public static final String  ALBUM_PRICE_TYPE_ONE="0201";  // 单级
+    public static final String  ALBUM_PRICE_TYPE_ALL="0202";  // 整专辑
+
+    //专辑状态 0301-审核通过 0302-审核不通过
+    public static final String  ALBUM_STATUS_PASS="0301";  // 审核通过
+    public static final String  ALBUM_STATUS_NO_PASS="0302";  // 审核不通过
+
+    public static final String  ALBUM_STATUS_REVIEWING="0303";  // 审核中
+
+    //专辑统计 0401-播放量 0402-订阅量 0403-购买量 0403-评论数
+    public static final String  ALBUM_STAT_PLAY="0401";  // 播放量
+    public static final String  ALBUM_STAT_SUBSCRIBE="0402";  // 订阅量
+    public static final String  ALBUM_STAT_BUY="0403";  // 购买量
+    public static final String  ALBUM_STAT_COMMENT="0404";  // 评论数
+
+    //声音状态 0501-审核通过 0502"-审核不通过
+    public static final String  TRACK_STATUS_PASS="0501";  // 审核通过
+    public static final String  TRACK_STATUS_NO_PASS="0502";  // 审核不通过
+    public static final String  TRACK_STATUS_REVIEWING ="0503";  // 审核中 已发起审核任务
+    public static final String  TRACK_STATUS_MANUAL ="0504";  // 需要人工审核
+
+    //声音来源 0601-用户原创 0602-上传
+    public static final String  TRACK_SOURCE_USER="0601";  // 用户原创
+    public static final String  TRACK_SOURCE_UPLOAD="0602";  // 上传
+
+    // 声音统计 0701-播放量 0702-收藏量 0703-点赞量 0704-评论数
+    public static final String  TRACK_STAT_PLAY="0701";  // 播放量
+    public static final String  TRACK_STAT_COLLECT="0702";  // 收藏量
+    public static final String  TRACK_STAT_PRAISE="0703";  // 点赞量
+    public static final String  TRACK_STAT_COMMENT="0704";  // 评论数
+
+    //用户状态 0801-正常 0802-锁定
+    public static final String  USER_STATUS_NORMAL="0801";  // 正常
+    public static final String  USER_STATUS_LOCK="0802";  // 锁定
+
+    //订单状态 0901-正常 0902-已支付 0903-已取消
+    public static final String  ORDER_STATUS_UNPAID="0901";  // 未支付
+    public static final String  ORDER_STATUS_PAID="0902";  // 已支付
+    public static final String  ORDER_STATUS_CANCEL="0903";  // 已取消
+
+    //订单付款项目类型 1001-专辑 1002-声音 1003-vip会员
+    public static final String  ORDER_ITEM_TYPE_ALBUM="1001";  // 专辑
+    public static final String  ORDER_ITEM_TYPE_TRACK="1002";  // 声音
+    public static final String  ORDER_ITEM_TYPE_VIP="1003";  // vip会员
+
+    //订单支付方式 1101-微信 1102-支付宝 1103-账户余额
+    public static final String  ORDER_PAY_WAY_WEIXIN="1101";  // 微信
+    public static final String  ORDER_PAY_WAY_ALIPAY="1102";  // 支付宝
+    public static final String  ORDER_PAY_ACCOUNT="1103";  // 账户余额
+
+    //账号交易类型 1201-充值 1202-锁定 1203-解锁 1204-消费
+    public static final String  ACCOUNT_TRADE_TYPE_DEPOSIT="1201";  // 充值
+    public static final String  ACCOUNT_TRADE_TYPE_LOCK="1202";  // 锁定
+    public static final String  ACCOUNT_TRADE_TYPE_UNLOCK="1203";  // 解锁
+    public static final String  ACCOUNT_TRADE_TYPE_MINUS="1204";  // 消费
+
+    //支付类型 1301-订单 1302-充值
+    public static final String  PAYMENT_TYPE_ORDER="1301";  // 订单
+    public static final String  PAYMENT_TYPE_RECHARGE="1302";  // 充值
+
+    //支付表支付状态 1401-未支付 1402-已支付
+    public static final String  PAYMENT_STATUS_UNPAID="1401";  // 未支付
+    public static final String  PAYMENT_STATUS_PAID="1402";  // 已支付
+
+    //订单减免类型 1405-专辑折扣 1406-VIP服务折
+    public static final String  ORDER_DERATE_ALBUM_DISCOUNT="1405";  // 专辑折扣
+    public static final String  ORDER_DERATE_VIP_SERVICE_DISCOUNT="1406";  // VIP服务折扣
+}

+ 45 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/execption/GuiguException.java

@@ -0,0 +1,45 @@
+package com.atguigu.tingshu.common.execption;
+
+import com.atguigu.tingshu.common.result.ResultCodeEnum;
+import lombok.Data;
+
+/**
+ * 自定义全局异常类
+ *
+ */
+@Data
+public class GuiguException extends RuntimeException {
+
+    private Integer code;
+
+    private String message;
+
+    /**
+     * 通过状态码和错误消息创建异常对象
+     * @param code
+     * @param message
+     */
+    public GuiguException(Integer code, String message) {
+        super(message);
+        this.code = code;
+        this.message = message;
+    }
+
+    /**
+     * 接收枚举类型对象
+     * @param resultCodeEnum
+     */
+    public GuiguException(ResultCodeEnum resultCodeEnum) {
+        super(resultCodeEnum.getMessage());
+        this.code = resultCodeEnum.getCode();
+        this.message = resultCodeEnum.getMessage();
+    }
+
+    @Override
+    public String toString() {
+        return "GuliException{" +
+                "code=" + code +
+                ", message=" + this.getMessage() +
+                '}';
+    }
+}

+ 88 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/handler/GlobalExceptionHandler.java

@@ -0,0 +1,88 @@
+package com.atguigu.tingshu.common.handler;
+
+import com.atguigu.tingshu.common.execption.GuiguException;
+import com.atguigu.tingshu.common.result.Result;
+import com.atguigu.tingshu.common.result.ResultCodeEnum;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.BindException;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * 全局异常处理类
+ */
+@Slf4j
+@ControllerAdvice
+//@RestControllerAdvice = @ControllerAdvice+@ResponseBody
+public class GlobalExceptionHandler {
+
+    /**
+     * 自定义异常处理方法
+     *
+     * @param e
+     * @return
+     */
+    @ExceptionHandler(GuiguException.class)
+    @ResponseBody
+    public Result error(GuiguException e) {
+        log.error("触发GuiguException异常拦截:{}", e);
+        return Result.build(null, e.getCode(), e.getMessage());
+    }
+
+
+    @ExceptionHandler(Exception.class)
+    @ResponseBody
+    public Result error(Exception e) {
+        log.error("触发Exception异常拦截:{}", e);
+        return Result.fail();
+    }
+
+
+
+    @ExceptionHandler({IllegalArgumentException.class})
+    @ResponseBody
+    public Result llegalArgumentException(Exception e) {
+        log.error("触发异常拦截: " + e.getMessage(), e);
+        return Result.build(null, ResultCodeEnum.ARGUMENT_VALID_ERROR);
+    }
+
+
+    @ExceptionHandler(value = BindException.class)
+    @ResponseBody
+    public Result error(BindException exception) {
+        BindingResult result = exception.getBindingResult();
+        Map<String, Object> errorMap = new HashMap<>();
+        List<FieldError> fieldErrors = result.getFieldErrors();
+        fieldErrors.forEach(error -> {
+            log.error("field: " + error.getField() + ", msg:" + error.getDefaultMessage());
+            errorMap.put(error.getField(), error.getDefaultMessage());
+        });
+
+        log.error("触发BindException异常拦截: {}" + errorMap);
+        return Result.build(errorMap, ResultCodeEnum.ARGUMENT_VALID_ERROR);
+    }
+
+    @ExceptionHandler(value = MethodArgumentNotValidException.class)
+    @ResponseBody
+    public Result error(MethodArgumentNotValidException exception) {
+        BindingResult result = exception.getBindingResult();
+        Map<String, Object> errorMap = new HashMap<>();
+        List<FieldError> fieldErrors = result.getFieldErrors();
+        fieldErrors.forEach(error -> {
+            log.error("field: " + error.getField() + ", msg:" + error.getDefaultMessage());
+            errorMap.put(error.getField(), error.getDefaultMessage());
+        });
+        log.error("触发MethodArgumentNotValidException异常拦截: {}" + errorMap);
+        return Result.build(errorMap, ResultCodeEnum.ARGUMENT_VALID_ERROR);
+    }
+}

+ 25 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/interceptor/FeignInterceptor.java

@@ -0,0 +1,25 @@
+package com.atguigu.tingshu.common.interceptor;
+
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+@Component
+public class FeignInterceptor implements RequestInterceptor {
+
+    public void apply(RequestTemplate requestTemplate){
+        //  获取请求对象
+        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+        //异步编排 与 MQ消费者端 为 null
+        if(null != requestAttributes) {
+            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)requestAttributes;
+            HttpServletRequest request = servletRequestAttributes.getRequest();
+            String token = request.getHeader("token");
+            requestTemplate.header("token", token);
+        }
+    }
+}

+ 23 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/login/GuiGuLogin.java

@@ -0,0 +1,23 @@
+package com.atguigu.tingshu.common.login;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义注解:修饰方法,判断用户是否登录
+ * @Target: 定义注解所修饰的对象范围 ElementType.TYPE:类或接口;ElementType.FIELD:字段;ElementType.METHOD:方法;ElementType.PARAMETER:参数;ElementType.CONSTRUCTOR:构造方法;ElementType.LOCAL_VARIABLE:局部变量;ElementType.ANNOTATION_TYPE:注解;ElementType.PACKAGE:包
+ * @Retention: 定义注解存活保留阶段,SOURCE:源代码;CLASS:class文件;RUNTIME:运行时
+ * @Inherited: 子类可以继承父类中的注解
+ * @Documented: 注解是否被包含在JavaDoc中
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface GuiGuLogin {
+
+    /**
+     * 是否需要登录
+     * @return
+     */
+    boolean required() default true;
+}

+ 91 - 0
common/service-util/src/main/java/com/atguigu/tingshu/common/login/GuiGuLoginAspect.java

@@ -0,0 +1,91 @@
+package com.atguigu.tingshu.common.login;
+
+import com.atguigu.tingshu.common.constant.RedisConstant;
+import com.atguigu.tingshu.common.execption.GuiguException;
+import com.atguigu.tingshu.common.result.ResultCodeEnum;
+import com.atguigu.tingshu.common.util.AuthContextHolder;
+import com.atguigu.tingshu.vo.user.UserInfoVo;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 切面:通知+切入点
+ *
+ * @author: atguigu
+ * @create: 2025-03-11 10:09
+ */
+@Slf4j
+@Aspect
+@Component
+public class GuiGuLoginAspect {
+
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    /**
+     * 认证状态校验环绕通知
+     * 1.对所有控制层且使用@GuiGuLogin注解方法进行增强
+     *
+     * @param pjp        目标方法对象
+     * @param guiGuLogin 注解对象,作用在目标方法上注解对象
+     * @return
+     * @throws Throwable
+     */
+    @Around("execution(* com.atguigu.tingshu.*.api.*.*(..)) && @annotation(guiGuLogin)")
+    public Object doBasicProfiling(ProceedingJoinPoint pjp, GuiGuLogin guiGuLogin) throws Throwable {
+        //一、前置逻辑
+        //1.获取请求对象
+        //1.1 通过请求上下文对象获取RequestAttributes(接口)
+        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+        //1.2 将接口转为实现类ServletRequestAttributes(实现类)
+        ServletRequestAttributes rsa = (ServletRequestAttributes) requestAttributes;
+        //1.3 获取请求对象
+        HttpServletRequest request = rsa.getRequest();
+        //2.从请求对象中获取请求头中的token  业界约定俗成授权头:Authorization
+        String token = request.getHeader("token");
+
+        //3.查询Redis中用户信息
+        //3.1 构建当时登录存入Redis用户信息Key 形式:前缀+令牌
+        String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
+        //3.2 查询Redis中用户基本信息
+        UserInfoVo userInfoVo = (UserInfoVo) redisTemplate.opsForValue().get(loginKey);
+
+        //4.如果用户信息为空且目标方法需登录方可访问。则抛出异常,响应业务状态码:208
+        if(userInfoVo==null && guiGuLogin.required()){
+            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
+        }
+
+        //5.如果用户存在说明是在登录状态,将用户ID存入ThreadLocal
+        if(userInfoVo!=null){
+            //5.1 判断key存活时间,如果小于规定阈值:6小时,则刷新key存活时间
+            Long expireHours = redisTemplate.getExpire(loginKey, TimeUnit.HOURS);
+            if(expireHours<=6){
+                redisTemplate.expire(loginKey, RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);
+            }
+            AuthContextHolder.setUserId(userInfoVo.getId());
+        }
+
+        //二、目标方法执行
+        //6.执行JavaEE三层逻辑
+        Object retVal = pjp.proceed();
+
+        //三、后置逻辑
+        //7.清理ThreadLocal 避免出现内存泄漏 造成OOM
+        AuthContextHolder.removeUserId();
+        return retVal;
+    }
+
+
+}

+ 180 - 0
lesson.sql

@@ -0,0 +1,180 @@
+#封装所有1,2,3级分类到视图中 包含:分类ID,分类名称 其他辅助字段
+create or replace view base_category_view as
+select bc3.id,
+       bc1.id   category1_id,
+       bc1.name category1_name,
+       bc2.id   category2_id,
+       bc2.name category2_name,
+       bc3.id   category3_id,
+       bc3.name category3_name,
+       bc3.create_time,
+       bc3.update_time,
+       bc3.is_deleted
+from base_category1 bc1
+         inner join base_category2 bc2 on bc2.category1_id = bc1.id and bc2.is_deleted = 0
+         inner join base_category3 bc3 on bc3.category2_id = bc2.id and bc3.is_deleted = 0
+where bc1.is_deleted = 0;
+
+#执行计划
+explain select bc3.id,
+               bc1.id   category1_id,
+               bc1.name category1_name,
+               bc2.id   category2_id,
+               bc2.name category2_name,
+               bc3.id   category3_id,
+               bc3.name category3_name,
+               bc3.create_time,
+               bc3.update_time,
+               bc3.is_deleted
+        from base_category1 bc1
+                 inner join base_category2 bc2 on bc2.category1_id = bc1.id and bc2.is_deleted = 0
+                 inner join base_category3 bc3 on bc3.category2_id = bc2.id and bc3.is_deleted = 0
+        where bc1.is_deleted = 0;
+
+
+#需求:根据1级分类ID查询该分类下关联标签及标签值列表
+select
+    ba.id,
+    ba.attribute_name,
+    bav.id base_attribute_value_id,
+    bav.attribute_id,
+    bav.value_name
+from base_attribute ba inner join base_attribute_value bav
+                                  on bav.attribute_id = ba.id and bav.is_deleted = 0
+where ba.category1_id = 2 and ba.is_deleted = 0;
+
+explain select
+            ba.id,
+            ba.attribute_name,
+            bav.id base_attribute_value_id,
+            bav.attribute_id,
+            bav.value_name
+        from base_attribute ba inner join base_attribute_value bav
+                                          on bav.attribute_id = ba.id and bav.is_deleted = 0
+        where ba.category1_id = 2 and ba.is_deleted = 0
+
+#需求:根据查询条件(用户ID、关键字、状态)查询专辑列表,包含:专辑信息以及专辑统计信息
+
+#第一步:查询业务数据来源专辑表跟专辑统计表 关联条件:统计表专辑ID跟专辑表主键  过滤条件:用户ID、关键字、状态 封装AlbumListVo
+select
+    ai.id album_id,
+    ai.album_title,
+    ai.cover_url,
+    ai.include_track_count,
+    ai.is_finished,
+    ai.status,
+    stat.stat_type,
+    stat.stat_num
+from album_info ai inner join album_stat stat on stat.album_id = ai.id;
+
+
+#第二步,上面得到统计是4条记录,需要封装成1条记录,封装到AlbumListVo中,封装字段:播放量、点赞量、收藏量、评论量  行转为列
+#2.1 尝试根据专辑ID分组 问题:违背SQL严格模式语法规则only_full_group_by,select中只能分组字段、聚合函数 由于查询列中包含多方统计类型,统计数值
+
+select
+    ai.id album_id,
+    ai.album_title,
+    ai.cover_url,
+    ai.include_track_count,
+    ai.is_finished,
+    ai.status,
+    stat.stat_type,
+    stat.stat_num
+from album_info ai inner join album_stat stat on stat.album_id = ai.id
+group by ai.id;
+
+
+#2.2 无法再Group by增加分组字段,从Select作为切入点  Select部分可以使用聚合函数
+# 采用判断函数 if(条件,满足结果,不满足结果)
+select if(1=2, 'true', 'false');
+
+# 以其中某条统计数值为例 得到统计类型及数值 转为列
+select * from album_stat where album_id = 2;
+select if(stat_type='0401', stat_num, 0) play_stat_num,if(stat_type='0402', stat_num, 0) subscribeStatNum  from album_stat where album_id = 2;
+
+# 完善SQL 对统计每行记录进行判断
+explain select
+            ai.id album_id,
+            ai.album_title,
+            ai.cover_url,
+            ai.include_track_count,
+            ai.is_finished,
+            ai.status,
+            max(if(stat.stat_type='0401', stat_num, 0)) playStatNum,
+            max(if(stat.stat_type='0402', stat_num, 0)) subscribeStatNum,
+            sum(if(stat.stat_type='0403', stat_num, 0)) buyStatNum,
+            max(if(stat.stat_type='0404', stat_num, 0)) commentStatNum
+        from album_info ai inner join album_stat stat on stat.album_id = ai.id
+        group by ai.id;
+
+
+#第三步:增加过滤条件,排序
+explain select
+            ai.id album_id,
+            ai.album_title,
+            ai.cover_url,
+            ai.include_track_count,
+            ai.is_finished,
+            ai.status,
+            max(if(stat.stat_type='0401', stat_num, 0)) playStatNum,
+            max(if(stat.stat_type='0402', stat_num, 0)) subscribeStatNum,
+            sum(if(stat.stat_type='0403', stat_num, 0)) buyStatNum,
+            max(if(stat.stat_type='0404', stat_num, 0)) commentStatNum
+        from album_info ai inner join album_stat stat on stat.album_id = ai.id
+        where ai.user_id = ?
+          and ai.album_title like concat('%','世界','%')
+          and ai.status = ?
+          and ai.is_deleted = 0
+        group by ai.id
+        order by ai.id desc;
+
+
+#需求:条件分页查询声音列表,包含声音统计信息 封装到TrackListVo对象中
+
+#第一步:关联查询声音表跟统计表 关联条件:声音表ID跟统计表声音ID
+select
+    ti.id track_id,
+    ti.track_title,
+    ti.cover_url,
+    ti.media_duration,
+    ti.status,
+    stat.stat_type,
+    stat.stat_num
+from track_info ti inner join track_stat stat on stat.track_id = ti.id;
+
+#第二步:先根据声音ID分组,借助if函数获取某种统计类型对应数值(4个数值) + max函数获取有效统计数值
+select
+    ti.id track_id,
+    ti.track_title,
+    ti.cover_url,
+    ti.media_duration,
+    ti.status,
+    max(if(stat_type='0701', stat_num, 0)) playStatNum,
+    max(if(stat_type='0702', stat_num, 0)) collectStatNum,
+    max(if(stat_type='0703', stat_num, 0)) praiseStatNum,
+    max(if(stat_type='0704', stat_num, 0)) commentStatNum
+from track_info ti inner join track_stat stat on stat.track_id = ti.id
+group by ti.id
+order by ti.id desc;
+
+
+#第三步过滤条件
+explain select
+            ti.id track_id,
+            ti.track_title,
+            ti.cover_url,
+            ti.media_duration,
+            ti.status,
+            max(if(stat_type='0701', stat_num, 0)) playStatNum,
+            max(if(stat_type='0702', stat_num, 0)) collectStatNum,
+            max(if(stat_type='0703', stat_num, 0)) praiseStatNum,
+            max(if(stat_type='0704', stat_num, 0)) commentStatNum
+        from track_info ti inner join track_stat stat on stat.track_id = ti.id and stat.is_deleted = 0
+        where
+                ti.user_id = 1
+          and ti.status = '0501'
+          and ti.track_title like concat('%','世界','%')
+          and ti.is_deleted = 0
+        group by ti.id
+        order by ti.id desc;
+

+ 58 - 0
model/pom.xml

@@ -0,0 +1,58 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>tingshu-parent</artifactId>
+        <groupId>com.atguigu.tingshu</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>model</artifactId>
+
+    <dependencies>
+        <!--lombok用来简化实体类-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.atguigu.tingshu</groupId>
+            <artifactId>common-util</artifactId>
+            <version>1.0</version>
+            <scope>provided </scope>
+        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>com.github.xiaoymin</groupId>-->
+<!--            <artifactId>knife4j-spring-boot-starter</artifactId>-->
+<!--            <scope>provided </scope>-->
+<!--        </dependency>-->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
+            <scope>provided </scope>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <scope>provided </scope>
+        </dependency>
+        <!-- 校验参数 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+            <scope>provided </scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
+            <scope>provided </scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+            <scope>provided </scope>
+        </dependency>
+    </dependencies>
+</project>

+ 38 - 0
model/src/main/java/com/atguigu/tingshu/model/account/RechargeInfo.java

@@ -0,0 +1,38 @@
+package com.atguigu.tingshu.model.account;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "RechargeInfo")
+@TableName("recharge_info")
+public class RechargeInfo extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户ID")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "充值订单编号")
+	@TableField("order_no")
+	private String orderNo;
+
+	@Schema(description = "充值状态:0901-未支付 0902-已支付 0903-已取消")
+	@TableField("recharge_status")
+	private String rechargeStatus;
+
+	@Schema(description = "充值金额")
+	@TableField("recharge_amount")
+	private BigDecimal rechargeAmount;
+
+	@Schema(description = "支付方式:1101-微信 1102-支付宝")
+	@TableField("pay_way")
+	private String payWay;
+
+}

+ 42 - 0
model/src/main/java/com/atguigu/tingshu/model/account/UserAccount.java

@@ -0,0 +1,42 @@
+package com.atguigu.tingshu.model.account;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "UserAccount")
+@TableName("user_account")
+public class UserAccount extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "账户总金额")
+	@TableField("total_amount")
+	private BigDecimal totalAmount;
+
+	@Schema(description = "锁定金额")
+	@TableField("lock_amount")
+	private BigDecimal lockAmount;
+
+	@Schema(description = "可用金额")
+	@TableField("available_amount")
+	private BigDecimal availableAmount;
+
+	@Schema(description = "总收入")
+	@TableField("total_income_amount")
+	private BigDecimal totalIncomeAmount;
+
+	@Schema(description = "总支出")
+	@TableField("total_pay_amount")
+	private BigDecimal totalPayAmount;
+
+}

+ 38 - 0
model/src/main/java/com/atguigu/tingshu/model/account/UserAccountDetail.java

@@ -0,0 +1,38 @@
+package com.atguigu.tingshu.model.account;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "UserAccountDetail")
+@TableName("user_account_detail")
+public class UserAccountDetail extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "交易标题")
+	@TableField("title")
+	private String title;
+
+	@Schema(description = "交易类型:1201-充值 1202-锁定 1203-解锁 1204-消费")
+	@TableField("trade_type")
+	private String tradeType;
+
+	@Schema(description = "金额")
+	@TableField("amount")
+	private BigDecimal amount;
+
+	@Schema(description = "订单编号")
+	@TableField("order_no")
+	private String orderNo;
+
+}

+ 35 - 0
model/src/main/java/com/atguigu/tingshu/model/album/AlbumAttributeValue.java

@@ -0,0 +1,35 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+
+@Data
+@Schema(description = "专辑属性值")
+public class AlbumAttributeValue extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "专辑id")
+	private Long albumId;
+
+	@NotNull(message = "属性id不能为空")
+	@Schema(description = "属性id")
+	private Long attributeId;
+
+	@NotNull(message = "属性值id不能为空")
+	@Schema(description = "属性值id")
+	private Long valueId;
+
+	@Schema(description = "属性名称")
+	@TableField(exist = false)
+	private String attributeName;
+
+	@Schema(description = "属性值名称")
+	@TableField(exist = false)
+	private String valueName;
+
+}

+ 108 - 0
model/src/main/java/com/atguigu/tingshu/model/album/AlbumInfo.java

@@ -0,0 +1,108 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+@Schema(description = "AlbumInfo")
+@TableName("album_info")
+@JsonInclude(JsonInclude.Include.NON_NULL) //不为空属性才会转json
+public class AlbumInfo extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "标题")
+	@TableField("album_title")
+	private String albumTitle;
+
+	@Schema(description = "三级分类id")
+	@TableField("category3_id")
+	private Long category3Id;
+
+	@Schema(description = "专辑简介")
+	@TableField("album_intro")
+	private String albumIntro;
+
+	@Schema(description = "专辑封面原图,尺寸不固定,最大尺寸为960*960(像素)")
+	@TableField("cover_url")
+	private String coverUrl;
+
+	@Schema(description = "专辑包含声音总数")
+	@TableField("include_track_count")
+	private Integer includeTrackCount;
+
+	@Schema(description = "专辑是否完结:0-否;1-完结;")
+	@TableField("is_finished")
+	private String isFinished;
+
+	@Schema(description = "预计更新多少集")
+	@TableField("estimated_track_count")
+	private Integer estimatedTrackCount;
+
+	@Schema(description = "专辑简介,富文本")
+	@TableField("album_rich_intro")
+	private String albumRichIntro;
+
+	@Schema(description = "专辑评分")
+	@TableField("quality_score")
+	private String qualityScore;
+
+	@Schema(description = "付费类型: 0101-免费、0102-vip免费、0103-付费")
+	@TableField("pay_type")
+	private String payType;
+
+	@Schema(description = "价格类型: 0201-单集 0202-整专辑")
+	@TableField("price_type")
+	private String priceType;
+
+	@Schema(description = "原价")
+	@TableField("price")
+	private BigDecimal price;
+
+	@Schema(description = "0.1-9.9  不打折 -1")
+	@TableField("discount")
+	private BigDecimal discount;
+
+	@Schema(description = "0.1-9.9 不打折 -1")
+	@TableField("vip_discount")
+	private BigDecimal vipDiscount;
+
+	@Schema(description = "免费试听集数")
+	@TableField("tracks_for_free")
+	private Integer tracksForFree;
+
+	@Schema(description = "每集免费试听秒数")
+	@TableField("seconds_for_free")
+	private Integer secondsForFree;
+
+	@Schema(description = "购买须知,富文本")
+	@TableField("buy_notes")
+	private String buyNotes;
+
+	@Schema(description = "专辑卖点,富文本")
+	@TableField("selling_point")
+	private String sellingPoint;
+
+	@Schema(description = "是否公开:0-否 1-是")
+	@TableField("is_open")
+	private String isOpen;
+
+	@Schema(description = "状态  0301-审核通过(上架) 0302-审核不通过  0303-审核中  0304-下架状态")
+	@TableField("status")
+	private String status;
+
+	@Schema(description = "属性值集合")
+	@TableField(exist = false)
+	private List<AlbumAttributeValue> albumAttributeValueVoList;
+}

+ 28 - 0
model/src/main/java/com/atguigu/tingshu/model/album/AlbumStat.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "AlbumStat")
+@TableName("album_stat")
+public class AlbumStat extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "专辑id")
+	@TableField("album_id")
+	private Long albumId;
+
+	@Schema(description = "统计类型")
+	@TableField("stat_type")
+	private String statType;
+
+	@Schema(description = "统计数目")
+	@TableField("stat_num")
+	private Integer statNum;
+
+}

+ 29 - 0
model/src/main/java/com/atguigu/tingshu/model/album/BaseAttribute.java

@@ -0,0 +1,29 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Schema(description = "BaseAttribute")
+@TableName("base_attribute")
+public class BaseAttribute extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "一级分类id")
+	@TableField("category1_id")
+	private Long category1Id;
+
+	@Schema(description = "属性显示名称")
+	@TableField("attribute_name")
+	private String attributeName;
+
+	@TableField(exist = false)
+	private List<BaseAttributeValue> attributeValueList;
+
+}

+ 24 - 0
model/src/main/java/com/atguigu/tingshu/model/album/BaseAttributeValue.java

@@ -0,0 +1,24 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "BaseAttributeValue")
+@TableName("base_attribute_value")
+public class BaseAttributeValue extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "属性id")
+	@TableField("attribute_id")
+	private Long attributeId;
+
+	@Schema(description = "属性值名称")
+	@TableField("value_name")
+	private String valueName;
+
+}

+ 24 - 0
model/src/main/java/com/atguigu/tingshu/model/album/BaseCategory1.java

@@ -0,0 +1,24 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "BaseCategory1")
+@TableName("base_category1")
+public class BaseCategory1 extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "分类名称")
+	@TableField("name")
+	private String name;
+
+	@Schema(description = "排序")
+	@TableField("order_num")
+	private Integer orderNum;
+
+}

+ 28 - 0
model/src/main/java/com/atguigu/tingshu/model/album/BaseCategory2.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "BaseCategory2")
+@TableName("base_category2")
+public class BaseCategory2 extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "二级分类名称")
+	@TableField("name")
+	private String name;
+
+	@Schema(description = "一级分类编号")
+	@TableField("category1_id")
+	private Long category1Id;
+
+	@Schema(description = "orderNum")
+	@TableField("order_num")
+	private Integer orderNum;
+
+}

+ 31 - 0
model/src/main/java/com/atguigu/tingshu/model/album/BaseCategory3.java

@@ -0,0 +1,31 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "BaseCategory3")
+@TableName("base_category3")
+public class BaseCategory3 extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "三级分类名称")
+	@TableField("name")
+	private String name;
+
+	@Schema(description = "二级分类编号")
+	@TableField("category2_id")
+	private Long category2Id;
+
+	@Schema(description = "排序")
+	@TableField("order_num")
+	private Integer orderNum;
+
+	@Schema(description = "是否置顶")
+	@TableField("is_top")
+	private Integer isTop;
+}

+ 50 - 0
model/src/main/java/com/atguigu/tingshu/model/album/BaseCategoryView.java

@@ -0,0 +1,50 @@
+//
+//
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * <p>
+ * BaseCategoryView
+ * </p>
+ *
+ * @author atguigu
+ */
+@Data
+@Schema(description = "分类视图")
+@TableName("base_category_view")
+public class BaseCategoryView extends BaseEntity {
+	
+	private static final long serialVersionUID = 1L;
+	
+	@Schema(description = "一级分类编号")
+	@TableField("category1_id")
+	private Long category1Id;
+
+	@Schema(description = "一级分类名称")
+	@TableField("category1_name")
+	private String category1Name;
+
+	@Schema(description = "二级分类编号")
+	@TableField("category2_id")
+	private Long category2Id;
+
+	@Schema(description = "二级分类名称")
+	@TableField("category2_name")
+	private String category2Name;
+
+	@Schema(description = "三级分类编号")
+	@TableField("category3_id")
+	private Long category3Id;
+
+	@Schema(description = "三级分类名称")
+	@TableField("category3_name")
+	private String category3Name;
+
+}
+

+ 28 - 0
model/src/main/java/com/atguigu/tingshu/model/album/BaseDic.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "BaseDic")
+@TableName("base_dic")
+public class BaseDic extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "code")
+	@TableField("code")
+	private String code;
+
+	@Schema(description = "编码名称")
+	@TableField("dic_name")
+	private String dicName;
+
+	@Schema(description = "父编号")
+	@TableField("parent_code")
+	private String parentCode;
+
+}

+ 81 - 0
model/src/main/java/com/atguigu/tingshu/model/album/TrackInfo.java

@@ -0,0 +1,81 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "TrackInfo")
+@TableName("track_info")
+public class TrackInfo extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "专辑id")
+	@TableField("album_id")
+	private Long albumId;
+
+	@Schema(description = "声音标题")
+	@TableField("track_title")
+	private String trackTitle;
+
+	@Schema(description = "声音在专辑中的排序值,从0开始依次递增,值越小排序越前")
+	@TableField("order_num")
+	private Integer orderNum;
+
+	@Schema(description = "声音简介")
+	@TableField("track_intro")
+	private String trackIntro;
+
+	@Schema(description = "声音简介,富文本")
+	@TableField("track_rich_intro")
+	private String trackRichIntro;
+
+	@Schema(description = "声音封面图url")
+	@TableField("cover_url")
+	private String coverUrl;
+
+	@Schema(description = "声音媒体时长,单位秒")
+	@TableField("media_duration")
+	private BigDecimal mediaDuration;
+
+	@Schema(description = "媒体文件的唯一标识")
+	@TableField("media_file_id")
+	private String mediaFileId;
+
+	@Schema(description = "媒体播放地址")
+	@TableField("media_url")
+	private String mediaUrl;
+
+	@Schema(description = "音频文件大小,单位字节")
+	@TableField("media_size")
+	private Long mediaSize;
+
+	@Schema(description = "声音媒体类型")
+	@TableField("media_type")
+	private String mediaType;
+
+	@Schema(description = "声音来源,1-用户原创,2-上传")
+	@TableField("source")
+	private String source;
+
+	@Schema(description = "状态")
+	@TableField("status")
+	private String status;
+
+	@Schema(description = "是否公开:0-否 1-是")
+	@TableField("is_open")
+	private String isOpen;
+	
+	@Schema(description = "发起审核任务ID")
+	@TableField("review_task_id")
+	private String reviewTaskId;
+}

+ 28 - 0
model/src/main/java/com/atguigu/tingshu/model/album/TrackStat.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.model.album;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "TrackStat")
+@TableName("track_stat")
+public class TrackStat extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "声音id")
+	@TableField("track_id")
+	private Long trackId;
+
+	@Schema(description = "统计类型")
+	@TableField("stat_type")
+	private String statType;
+
+	@Schema(description = "统计数目")
+	@TableField("stat_num")
+	private Integer statNum;
+
+}

+ 36 - 0
model/src/main/java/com/atguigu/tingshu/model/base/BaseEntity.java

@@ -0,0 +1,36 @@
+package com.atguigu.tingshu.model.base;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+@Data
+public class BaseEntity implements Serializable {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @TableField("create_time")
+    private Date createTime;
+
+    @JsonIgnore
+    @TableField("update_time")
+    private Date updateTime;
+
+    @JsonIgnore
+    @TableLogic
+    @TableField("is_deleted")
+    private Integer isDeleted;
+
+    @JsonIgnore
+    @TableField(exist = false)
+    private Map<String,Object> param = new HashMap<>();
+}

+ 55 - 0
model/src/main/java/com/atguigu/tingshu/model/comment/Comment.java

@@ -0,0 +1,55 @@
+package com.atguigu.tingshu.model.comment;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.Transient;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+@Schema(description = "专辑评论")
+@Document
+public class Comment {
+
+	@Schema(description = "id")
+	@Id
+	private String id;
+
+	@Schema(description = "专辑id")
+	private Long albumId;
+
+	@Schema(description = "用户id")
+	private Long userId;
+
+	@Schema(description = "发表评论用户的昵称,已脱敏")
+	private String nickname;
+
+	@Schema(description = "发表评论用户的头像图片地址")
+	private String avatarUrl;
+
+	@Schema(description = "评论内容")
+	private String content;
+
+	@Schema(description = "被回复的评论id")
+	private String replyCommentId;
+
+	@Schema(description = "点赞数量")
+	private Integer praiseCount = 0;
+
+	@Schema(description = "评论中对专辑的评分 (十分制,建议采用五星制,如10分显示五颗星,7分显示三颗半星)")
+	private Integer albumCommentScore;
+
+	@Schema(description = "创建时间")
+	private Date createTime;
+
+	@Schema(description = "当前用户是否点赞")
+	@Transient
+	private Boolean isPraise;
+
+	@Schema(description = "回复评论列表")
+	@Transient //被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性
+	private List<Comment> replyCommentList;
+}

+ 39 - 0
model/src/main/java/com/atguigu/tingshu/model/comment/CommentPraise.java

@@ -0,0 +1,39 @@
+package com.atguigu.tingshu.model.comment;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * CommentPraise
+ * </p>
+ *
+ * @author atguigu
+ */
+@Data
+@Schema(description = "专辑评论点赞")
+@Document
+public class CommentPraise {
+
+	@Schema(description = "id")
+	@Id
+	private String id;
+	
+	@Schema(description = "动态id")
+	private Long albumId;
+
+	@Schema(description = "评论id")
+	private String commentId;
+
+	@Schema(description = "点赞者id")
+	private Long userId;
+
+	@Schema(description = "创建时间")
+	private Date createTime;
+
+}
+

+ 44 - 0
model/src/main/java/com/atguigu/tingshu/model/dispatch/XxlJobConfig.java

@@ -0,0 +1,44 @@
+package com.atguigu.tingshu.model.dispatch;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "XxlJobConfig")
+@TableName("xxl_job_config")
+public class XxlJobConfig extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "调度任务标题")
+	@TableField("title")
+	private String title;
+
+	@Schema(description = "调度执行handler")
+	@TableField("executor_handler")
+	private String executorHandler;
+
+	@Schema(description = "调度任务参数")
+	@TableField("executor_param")
+	private String executorParam;
+
+	@Schema(description = "调度表达式")
+	@TableField("cron")
+	private String cron;
+
+	@Schema(description = "备注")
+	@TableField("remark")
+	private String remark;
+
+	@Schema(description = "任务状态    0:失败    1:成功")
+	@TableField("status")
+	private Integer status;
+
+	@Schema(description = "xxl任务平台id")
+	@TableField("xxl_job_id")
+	private Long xxlJobId;
+
+}

+ 32 - 0
model/src/main/java/com/atguigu/tingshu/model/dispatch/XxlJobLog.java

@@ -0,0 +1,32 @@
+package com.atguigu.tingshu.model.dispatch;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "XxlJobLog")
+@TableName("xxl_job_log")
+public class XxlJobLog extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "任务配置id")
+	@TableField("job_config_id")
+	private Long jobConfigId;
+
+	@Schema(description = "任务状态    0:失败    1:成功")
+	@TableField("status")
+	private Integer status;
+
+	@Schema(description = "失败信息")
+	@TableField("error")
+	private String error;
+
+	@Schema(description = "耗时(单位:毫秒)")
+	@TableField("times")
+	private Integer times;
+
+}

+ 14 - 0
model/src/main/java/com/atguigu/tingshu/model/live/FromUser.java

@@ -0,0 +1,14 @@
+package com.atguigu.tingshu.model.live;
+
+import lombok.Data;
+
+@Data
+public class FromUser {
+
+    //用户id
+    private Long userId;
+    //昵称
+    private String nickname;
+    //头像地址
+    private String avatarUrl;
+}

+ 74 - 0
model/src/main/java/com/atguigu/tingshu/model/live/LiveRoom.java

@@ -0,0 +1,74 @@
+package com.atguigu.tingshu.model.live;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@Schema(description = "LiveRoom")
+@TableName("live_room")
+public class LiveRoom extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "直播间封面")
+	@TableField("cover_url")
+	private String coverUrl;
+
+	@Schema(description = "直播标题")
+	@TableField("live_title")
+	private String liveTitle;
+
+	@Schema(description = "当前直播场次的总访问人次")
+	@TableField("view_count")
+	private Integer viewCount;
+
+	@Schema(description = "直播状态:1-直播正在进行,2-直播结束")
+	@TableField("status")
+	private String status;
+
+	@Schema(description = "直播间标签id")
+	@TableField("tag_id")
+	private String tagId;
+
+	@Schema(description = "直播应用名称")
+	@TableField("app_name")
+	private String appName;
+
+	@Schema(description = "直播流名称")
+	@TableField("stream_name")
+	private String streamName;
+
+	@Schema(description = "过期时间")
+	@TableField("expire_time")
+	private Date expireTime;
+
+	@Schema(description = "推流地址")
+	@TableField("push_url")
+	private String pushUrl;
+
+	@Schema(description = "播放地址")
+	@TableField("play_url")
+	private String playUrl;
+
+	@Schema(description = "经度")
+	@TableField("longitude")
+	private String longitude;
+
+	@Schema(description = "纬度")
+	@TableField("latitude")
+	private String latitude;
+
+	@Schema(description = "位置")
+	@TableField("location")
+	private String location;
+
+}

+ 28 - 0
model/src/main/java/com/atguigu/tingshu/model/live/LiveTag.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.model.live;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "LiveTag")
+@TableName("live_tag")
+public class LiveTag extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "标签名称")
+	@TableField("name")
+	private String name;
+
+	@Schema(description = "标签图标url")
+	@TableField("icon_url")
+	private String iconUrl;
+
+	@Schema(description = "排序")
+	@TableField("order_num")
+	private Integer orderNum;
+
+}

+ 49 - 0
model/src/main/java/com/atguigu/tingshu/model/live/SocketMsg.java

@@ -0,0 +1,49 @@
+package com.atguigu.tingshu.model.live;
+
+
+import lombok.Data;
+import lombok.Getter;
+
+/**
+ * 这里我们就不能使用简单的文本消息进行消息的发送了,我们使用json进行消息的发送。
+ * 所以需要先创建一个消息对象,里面包含了消息发送者,消息接受者,消息类型(单聊还是群聊),还是就是消息,如下:
+ */
+@Data
+public class SocketMsg {
+
+    @Getter
+    public enum MsgTypeEnum {
+
+        HEART_BEAT("0","心跳信息"),
+        PUBLIC_MSG("1","公共聊天消息"),
+        JOIN_CHAT("2","加入聊天室"),
+        CLOSE_SOCKET("3","退出聊天室"),
+        ONLINE_NUM("4","在线用户数"),
+        TOKEN_INVALID("-1","token无效"),
+        ;
+
+        private String code;
+        private String data;
+
+        MsgTypeEnum(String code, String data) {
+            this.code = code;
+            this.data = data;
+        }
+
+    }
+
+    //直播房间id
+    private Long liveRoomId;
+//    //消息体
+//    private MsgBody msgBody;
+
+    //消息类型
+    private String msgType;
+    //消息内容
+    private Object msgContent;
+
+    //发送者
+    private FromUser fromUser;
+    //时间戳
+    private Long timestamp;
+}

+ 34 - 0
model/src/main/java/com/atguigu/tingshu/model/order/OrderDerate.java

@@ -0,0 +1,34 @@
+package com.atguigu.tingshu.model.order;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "OrderDerate")
+@TableName("order_derate")
+public class OrderDerate extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "订单id")
+	@TableField("order_id")
+	private Long orderId;
+
+	@Schema(description = "订单减免类型 1405-专辑折扣 1406-VIP服务折")
+	@TableField("derate_type")
+	private String derateType;
+
+	@Schema(description = "减免金额")
+	@TableField("derate_amount")
+	private BigDecimal derateAmount;
+
+	@Schema(description = "备注")
+	@TableField("remarks")
+	private String remarks;
+
+}

+ 38 - 0
model/src/main/java/com/atguigu/tingshu/model/order/OrderDetail.java

@@ -0,0 +1,38 @@
+package com.atguigu.tingshu.model.order;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "OrderDetail")
+@TableName("order_detail")
+public class OrderDetail extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "订单id")
+	@TableField("order_id")
+	private Long orderId;
+
+	@Schema(description = "付费项目id")
+	@TableField("item_id")
+	private Long itemId;
+
+	@Schema(description = "付费项目名称")
+	@TableField("item_name")
+	private String itemName;
+
+	@Schema(description = "付费项目图片url")
+	@TableField("item_url")
+	private String itemUrl;
+
+	@Schema(description = "付费项目价格")
+	@TableField("item_price")
+	private BigDecimal itemPrice;
+
+}

+ 69 - 0
model/src/main/java/com/atguigu/tingshu/model/order/OrderInfo.java

@@ -0,0 +1,69 @@
+package com.atguigu.tingshu.model.order;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+@Schema(description = "OrderInfo")
+@TableName("order_info")
+public class OrderInfo extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户ID")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "订单标题")
+	@TableField("order_title")
+	private String orderTitle;
+
+	@Schema(description = "订单号")
+	@TableField("order_no")
+	private String orderNo;
+
+	@Schema(description = "订单状态:0901-未支付 0902-已支付 0903-已取消")
+	@TableField("order_status")
+	private String orderStatus;
+
+	@Schema(description = "订单原始金额")
+	@TableField("original_amount")
+	private BigDecimal originalAmount;
+
+	@Schema(description = "减免总金额")
+	@TableField("derate_amount")
+	private BigDecimal derateAmount;
+
+	@Schema(description = "订单总价")
+	@TableField("order_amount")
+	private BigDecimal orderAmount;
+
+	@Schema(description = "付款项目类型: 1001-专辑 1002-声音 1003-vip会员")
+	@TableField("item_type")
+	private String itemType;
+
+	@Schema(description = "支付方式:1101-微信 1102-支付宝 1103-账户余额")
+	@TableField("pay_way")
+	private String payWay;
+
+
+	@Schema(description = "订单明细列表")
+	@TableField(exist = false)
+	private List<OrderDetail> orderDetailList;
+
+	@Schema(description = "订单减免明细列表")
+	@TableField(exist = false)
+	private List<OrderDerate> orderDerateList;
+
+	@TableField(exist = false)
+	private String orderStatusName;
+	@TableField(exist = false)
+	private String payWayName;
+
+}

+ 59 - 0
model/src/main/java/com/atguigu/tingshu/model/payment/PaymentInfo.java

@@ -0,0 +1,59 @@
+package com.atguigu.tingshu.model.payment;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@Schema(description = "PaymentInfo")
+@TableName("payment_info")
+public class PaymentInfo extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "支付类型:1301-订单 1302-充值")
+	@TableField("payment_type")
+	private String paymentType;
+
+	@Schema(description = "订单号")
+	@TableField("order_no")
+	private String orderNo;
+
+	@Schema(description = "付款方式:1101-微信 1102-支付宝")
+	@TableField("pay_way")
+	private String payWay;
+
+	@Schema(description = "交易编号(微信或支付)")
+	@TableField("out_trade_no")
+	private String outTradeNo;
+
+	@Schema(description = "支付金额")
+	@TableField("amount")
+	private BigDecimal amount;
+
+	@Schema(description = "交易内容")
+	@TableField("content")
+	private String content;
+
+	@Schema(description = "支付状态:1401-未支付 1402-已支付")
+	@TableField("payment_status")
+	private String paymentStatus;
+
+	@Schema(description = "回调时间")
+	@TableField("callback_time")
+	private Date callbackTime;
+
+	@Schema(description = "回调信息")
+	@TableField("callback_content")
+	private String callbackContent;
+
+}

+ 91 - 0
model/src/main/java/com/atguigu/tingshu/model/search/AlbumInfoIndex.java

@@ -0,0 +1,91 @@
+package com.atguigu.tingshu.model.search;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.elasticsearch.annotations.DateFormat;
+import org.springframework.data.elasticsearch.annotations.Document;
+import org.springframework.data.elasticsearch.annotations.Field;
+import org.springframework.data.elasticsearch.annotations.FieldType;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+@Data
+@Document(indexName = "albuminfo")
+@JsonIgnoreProperties(ignoreUnknown = true)//目的:防止json字符串转成实体对象时因未识别字段报错
+public class AlbumInfoIndex implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    // 专辑Id
+    @Id
+    private Long id;
+
+    //  es 中能分词的字段,这个字段数据类型必须是 text!keyword 不分词! analyzer = "ik_max_word"
+    @Field(type = FieldType.Text, analyzer = "ik_max_word")
+    private String albumTitle;
+
+    @Field(type = FieldType.Text, analyzer = "ik_max_word")
+    private String albumIntro;
+
+
+    //专辑封面
+    @Field(type = FieldType.Keyword, index = false)
+    private String coverUrl;
+
+    //专辑包含声音总数
+    @Field(type = FieldType.Long, index = false)
+    private Integer includeTrackCount;
+
+    //专辑是否完结:0-否;1-完结
+    @Field(type = FieldType.Long, index = false)
+    private String isFinished;
+
+    //付费类型:免费、vip免费、付费
+    @Field(type = FieldType.Keyword, index = false)
+    private String payType;
+
+    @Field(type = FieldType.Date,format = DateFormat.date_time, pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime; //
+
+
+    @Field(type = FieldType.Keyword)
+    private String announcerName;
+
+    @Field(type = FieldType.Long)
+    private Long category1Id;
+
+    @Field(type = FieldType.Long)
+    private Long category2Id;
+
+    @Field(type = FieldType.Long)
+    private Long category3Id;
+
+    //播放量
+    @Field(type = FieldType.Integer)
+    private Integer playStatNum = 0;
+
+    //订阅量
+    @Field(type = FieldType.Integer)
+    private Integer subscribeStatNum = 0;
+
+    //购买量
+    @Field(type = FieldType.Integer)
+    private Integer buyStatNum = 0;
+
+    //评论数
+    @Field(type = FieldType.Integer)
+    private Integer commentStatNum = 0;
+
+    //  商品的热度!
+    @Field(type = FieldType.Double)
+    private Double hotScore = 0d;
+
+    //专辑属性值
+    // Nested 支持嵌套查询
+    @Field(type = FieldType.Nested)
+    private List<AttributeValueIndex> attributeValueIndexList;
+
+}

+ 18 - 0
model/src/main/java/com/atguigu/tingshu/model/search/AttributeValueIndex.java

@@ -0,0 +1,18 @@
+package com.atguigu.tingshu.model.search;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.data.elasticsearch.annotations.Field;
+import org.springframework.data.elasticsearch.annotations.FieldType;
+
+@Data
+@Schema(description = "专辑属性值")
+public class AttributeValueIndex {
+
+	@Field(type = FieldType.Long)
+	private Long attributeId;
+
+	@Field(type = FieldType.Long)
+	private Long valueId;
+
+}

+ 32 - 0
model/src/main/java/com/atguigu/tingshu/model/search/SuggestIndex.java

@@ -0,0 +1,32 @@
+package com.atguigu.tingshu.model.search;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.elasticsearch.annotations.CompletionField;
+import org.springframework.data.elasticsearch.annotations.Document;
+import org.springframework.data.elasticsearch.annotations.Field;
+import org.springframework.data.elasticsearch.annotations.FieldType;
+import org.springframework.data.elasticsearch.core.suggest.Completion;
+
+@Data
+@Document(indexName = "suggestinfo")
+@JsonIgnoreProperties(ignoreUnknown = true)//目的:防止json字符串转成实体对象时因未识别字段报错
+public class SuggestIndex {
+
+    @Id
+    private String id;
+
+    @Field(type = FieldType.Text, analyzer = "standard")
+    private String title;
+
+    @CompletionField(analyzer = "standard", searchAnalyzer = "standard", maxInputLength = 20)
+    private Completion keyword;
+
+    @CompletionField(analyzer = "standard", searchAnalyzer = "standard", maxInputLength = 20)
+    private Completion keywordPinyin;
+
+    @CompletionField(analyzer = "standard", searchAnalyzer = "standard", maxInputLength = 20)
+    private Completion keywordSequence;
+
+}

+ 50 - 0
model/src/main/java/com/atguigu/tingshu/model/system/SysDept.java

@@ -0,0 +1,50 @@
+package com.atguigu.tingshu.model.system;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Schema(description = "部门")
+@TableName("sys_dept")
+public class SysDept extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "部门名称")
+	@TableField("name")
+	private String name;
+
+	@Schema(description = "上级部门id")
+	@TableField("parent_id")
+	private Long parentId;
+
+	@Schema(description = "树结构")
+	@TableField("tree_path")
+	private String treePath;
+
+	@Schema(description = "排序")
+	@TableField("sort_value")
+	private Integer sortValue;
+
+	@Schema(description = "负责人")
+	@TableField("leader")
+	private String leader;
+
+	@Schema(description = "电话")
+	@TableField("phone")
+	private String phone;
+
+	@Schema(description = "状态(1正常 0停用)")
+	@TableField("status")
+	private Integer status;
+
+	@Schema(description = "下级部门")
+	@TableField(exist = false)
+	private List<SysDept> children;
+
+}

+ 38 - 0
model/src/main/java/com/atguigu/tingshu/model/system/SysLoginLog.java

@@ -0,0 +1,38 @@
+package com.atguigu.tingshu.model.system;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@Schema(description = "SysLoginLog")
+@TableName("sys_login_log")
+public class SysLoginLog extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户账号")
+	@TableField("username")
+	private String username;
+
+	@Schema(description = "登录IP地址")
+	@TableField("ipaddr")
+	private String ipaddr;
+
+	@Schema(description = "登录状态(0成功 1失败)")
+	@TableField("status")
+	private Integer status;
+
+	@Schema(description = "提示信息")
+	@TableField("msg")
+	private String msg;
+
+	@Schema(description = "访问时间")
+	@TableField("access_time")
+	private Date accessTime;
+
+}

+ 61 - 0
model/src/main/java/com/atguigu/tingshu/model/system/SysMenu.java

@@ -0,0 +1,61 @@
+package com.atguigu.tingshu.model.system;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Schema(description = "菜单")
+@TableName("sys_menu")
+public class SysMenu extends BaseEntity {
+	
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "所属上级")
+	@TableField("parent_id")
+	private Long parentId;
+
+	@Schema(description = "名称")
+	@TableField("name")
+	private String name;
+
+	@Schema(description = "类型(1:菜单,2:按钮)")
+	@TableField("type")
+	private Integer type;
+
+	@Schema(description = "路由地址")
+	@TableField("path")
+	private String path;
+
+	@Schema(description = "组件路径")
+	@TableField("component")
+	private String component;
+
+	@Schema(description = "权限标识")
+	@TableField("perms")
+	private String perms;
+
+	@Schema(description = "图标")
+	@TableField("icon")
+	private String icon;
+
+	@Schema(description = "排序")
+	@TableField("sort_value")
+	private Integer sortValue;
+
+	@Schema(description = "状态(0:禁止,1:正常)")
+	@TableField("status")
+	private Integer status;
+
+	// 下级列表
+	@TableField(exist = false)
+	private List<SysMenu> children;
+	//是否选中
+	@TableField(exist = false)
+	private boolean isSelect;
+}
+

+ 74 - 0
model/src/main/java/com/atguigu/tingshu/model/system/SysOperLog.java

@@ -0,0 +1,74 @@
+package com.atguigu.tingshu.model.system;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@Schema(description = "SysOperLog")
+@TableName("sys_oper_log")
+public class SysOperLog extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "模块标题")
+	@TableField("title")
+	private String title;
+
+	@Schema(description = "业务类型(0其它 1新增 2修改 3删除)")
+	@TableField("business_type")
+	private String businessType;
+
+	@Schema(description = "方法名称")
+	@TableField("method")
+	private String method;
+
+	@Schema(description = "请求方式")
+	@TableField("request_method")
+	private String requestMethod;
+
+	@Schema(description = "操作类别(0其它 1后台用户 2手机端用户)")
+	@TableField("operator_type")
+	private String operatorType;
+
+	@Schema(description = "操作人员")
+	@TableField("oper_name")
+	private String operName;
+
+	@Schema(description = "部门名称")
+	@TableField("dept_name")
+	private String deptName;
+
+	@Schema(description = "请求URL")
+	@TableField("oper_url")
+	private String operUrl;
+
+	@Schema(description = "主机地址")
+	@TableField("oper_ip")
+	private String operIp;
+
+	@Schema(description = "请求参数")
+	@TableField("oper_param")
+	private String operParam;
+
+	@Schema(description = "返回参数")
+	@TableField("json_result")
+	private String jsonResult;
+
+	@Schema(description = "操作状态(0正常 1异常)")
+	@TableField("status")
+	private Integer status;
+
+	@Schema(description = "错误消息")
+	@TableField("error_msg")
+	private String errorMsg;
+
+	@Schema(description = "操作时间")
+	@TableField("oper_time")
+	private Date operTime;
+
+}

+ 32 - 0
model/src/main/java/com/atguigu/tingshu/model/system/SysPost.java

@@ -0,0 +1,32 @@
+package com.atguigu.tingshu.model.system;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "岗位")
+@TableName("sys_post")
+public class SysPost extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "岗位编码")
+	@TableField("post_code")
+	private String postCode;
+
+	@Schema(description = "岗位名称")
+	@TableField("name")
+	private String name;
+
+	@Schema(description = "显示顺序")
+	@TableField("description")
+	private String description;
+
+	@Schema(description = "状态(1正常 0停用)")
+	@TableField("status")
+	private Integer status;
+
+}

+ 31 - 0
model/src/main/java/com/atguigu/tingshu/model/system/SysRole.java

@@ -0,0 +1,31 @@
+package com.atguigu.tingshu.model.system;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+
+@Data
+@Schema(description = "角色")
+@TableName("sys_role")
+public class SysRole extends BaseEntity {
+	
+	private static final long serialVersionUID = 1L;
+
+	//@NotBlank(message = "角色名称不能为空")
+	@Schema(description = "角色名称")
+	@TableField("role_name")
+	private String roleName;
+
+	@Schema(description = "角色编码")
+	@TableField("role_code")
+	private String roleCode;
+
+	@Schema(description = "描述")
+	@TableField("description")
+	private String description;
+
+}
+

+ 25 - 0
model/src/main/java/com/atguigu/tingshu/model/system/SysRoleMenu.java

@@ -0,0 +1,25 @@
+package com.atguigu.tingshu.model.system;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "角色菜单")
+@TableName("sys_role_menu")
+public class SysRoleMenu extends BaseEntity {
+	
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "角色id")
+	@TableField("role_id")
+	private Long roleId;
+
+	@Schema(description = "菜单id")
+	@TableField("menu_id")
+	private Long menuId;
+
+}
+

+ 66 - 0
model/src/main/java/com/atguigu/tingshu/model/system/SysUser.java

@@ -0,0 +1,66 @@
+package com.atguigu.tingshu.model.system;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Schema(description = "用户")
+@TableName("sys_user")
+public class SysUser extends BaseEntity {
+	
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户名")
+	@TableField("username")
+	private String username;
+
+	@Schema(description = "密码")
+	@TableField("password")
+	private String password;
+
+	@Schema(description = "姓名")
+	@TableField("name")
+	private String name;
+
+	@Schema(description = "手机")
+	@TableField("phone")
+	private String phone;
+
+	@Schema(description = "头像地址")
+	@TableField("head_url")
+	private String headUrl;
+
+	@Schema(description = "部门id")
+	@TableField("dept_id")
+	private Long deptId;
+
+	@Schema(description = "岗位id")
+	@TableField("post_id")
+	private Long postId;
+
+	@Schema(description = "描述")
+	@TableField("description")
+	private String description;
+
+	@Schema(description = "状态(1:正常 0:停用)")
+	@TableField("status")
+	private Integer status;
+
+	@TableField(exist = false)
+	private List<SysRole> roleList;
+	//岗位
+	@TableField(exist = false)
+	private String postName;
+	//部门
+	@TableField(exist = false)
+	private String deptName;
+
+	@TableField(exist = false)
+	List<String> userPermsList;
+}
+

+ 24 - 0
model/src/main/java/com/atguigu/tingshu/model/system/SysUserRole.java

@@ -0,0 +1,24 @@
+package com.atguigu.tingshu.model.system;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "用户角色")
+@TableName("sys_user_role")
+public class SysUserRole extends BaseEntity {
+	
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "角色id")
+	@TableField("role_id")
+	private Long roleId;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+}
+

+ 40 - 0
model/src/main/java/com/atguigu/tingshu/model/user/UserCertification.java

@@ -0,0 +1,40 @@
+package com.atguigu.tingshu.model.user;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "UserCertification")
+@TableName("user_certification")
+public class UserCertification extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "身份证地址1")
+	@TableField("id_card1_url")
+	private String idCard1Url;
+
+	@Schema(description = "身份证地址2")
+	@TableField("id_card2_url")
+	private String idCard2Url;
+
+	@Schema(description = "人脸图片地址")
+	@TableField("face_url")
+	private String faceUrl;
+
+	@Schema(description = "比对结果数据")
+	@TableField("result_data")
+	private String resultData;
+
+	@Schema(description = "日志操作用户")
+	@TableField("operate_user_id")
+	private Long operateUserId;
+
+}

+ 28 - 0
model/src/main/java/com/atguigu/tingshu/model/user/UserCollect.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.model.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Date;
+
+@Data
+@Schema(description = "用户收藏")
+@Document
+public class UserCollect {
+
+	@Schema(description = "id")
+	@Id
+	private String id;
+
+	@Schema(description = "用户ID")
+	private Long userId;
+
+	@Schema(description = "声音ID")
+	private Long trackId;
+
+	@Schema(description = "创建时间")
+	private Date createTime;
+
+}

+ 70 - 0
model/src/main/java/com/atguigu/tingshu/model/user/UserInfo.java

@@ -0,0 +1,70 @@
+package com.atguigu.tingshu.model.user;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@Schema(description = "UserInfo")
+@TableName("user_info")
+public class UserInfo extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "手机")
+	@TableField("phone")
+	private String phone;
+
+	@Schema(description = "密码")
+	@TableField("password")
+	private String password;
+
+	@Schema(description = "微信openId")
+	@TableField("wx_open_id")
+	private String wxOpenId;
+
+	@Schema(description = "nickname")
+	@TableField("nickname")
+	private String nickname;
+
+	@Schema(description = "主播用户头像图片")
+	@TableField("avatar_url")
+	private String avatarUrl;
+
+	@Schema(description = "用户是否为VIP会员 0:普通用户  1:VIP会员")
+	@TableField("is_vip")
+	private Integer isVip;
+
+	@Schema(description = "当前VIP到期时间,即失效时间")
+	@TableField("vip_expire_time")
+	private Date vipExpireTime;
+
+	@Schema(description = "性别")
+	@TableField("gender")
+	private Integer gender;
+
+	@Schema(description = "出生年月")
+	@TableField("birthday")
+	private Date birthday;
+
+	@Schema(description = "简介")
+	@TableField("intro")
+	private String intro;
+
+	@Schema(description = "主播认证类型")
+	@TableField("certification_type")
+	private Integer certificationType;
+
+	@Schema(description = "认证状态")
+	@TableField("certification_status")
+	private Integer certificationStatus;
+
+	@Schema(description = "状态")
+	@TableField("status")
+	private String status;
+
+}

+ 41 - 0
model/src/main/java/com/atguigu/tingshu/model/user/UserListenProcess.java

@@ -0,0 +1,41 @@
+package com.atguigu.tingshu.model.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@Schema(description = "UserListenProcess")
+@Document
+public class UserListenProcess {
+
+	@Schema(description = "id")
+	@Id
+	private String id;
+
+	@Schema(description = "用户id")
+	private Long userId;
+
+	@Schema(description = "专辑id")
+	private Long albumId;
+
+	@Schema(description = "声音id,声音id为0时,浏览的是专辑")
+	private Long trackId;
+
+	@Schema(description = "相对于音频开始位置的播放跳出位置,单位为秒。比如当前音频总时长60s,本次播放到音频第25s处就退出或者切到下一首,那么break_second就是25")
+	private BigDecimal breakSecond;
+
+	@Schema(description = "是否显示")
+	private Integer isShow;
+
+	@Schema(description = "创建时间")
+	private Date createTime;
+
+	@Schema(description = "更新时间")
+	private Date updateTime;
+
+}

+ 28 - 0
model/src/main/java/com/atguigu/tingshu/model/user/UserPaidAlbum.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.model.user;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "UserPaidAlbum")
+@TableName("user_paid_album")
+public class UserPaidAlbum extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "订单号")
+	@TableField("order_no")
+	private String orderNo;
+
+	@Schema(description = "用户ID")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "专辑id")
+	@TableField("album_id")
+	private Long albumId;
+
+}

+ 32 - 0
model/src/main/java/com/atguigu/tingshu/model/user/UserPaidTrack.java

@@ -0,0 +1,32 @@
+package com.atguigu.tingshu.model.user;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "UserPaidTrack")
+@TableName("user_paid_track")
+public class UserPaidTrack extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "订单号")
+	@TableField("order_no")
+	private String orderNo;
+
+	@Schema(description = "用户ID")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "专辑id")
+	@TableField("album_id")
+	private Long albumId;
+
+	@Schema(description = "声音id")
+	@TableField("track_id")
+	private Long trackId;
+
+}

+ 28 - 0
model/src/main/java/com/atguigu/tingshu/model/user/UserStat.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.model.user;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "UserStat")
+@TableName("user_stat")
+public class UserStat extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "统计类型")
+	@TableField("stat_type")
+	private Integer statType;
+
+	@Schema(description = "统计数目")
+	@TableField("stat_num")
+	private Integer statNum;
+
+}

+ 28 - 0
model/src/main/java/com/atguigu/tingshu/model/user/UserSubscribe.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.model.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Date;
+
+@Data
+@Schema(description = "用户订阅")
+@Document
+public class UserSubscribe {
+
+	@Schema(description = "id")
+	@Id
+	private String id;
+
+	@Schema(description = "用户ID")
+	private Long userId;
+
+	@Schema(description = "专辑ID")
+	private Long albumId;
+
+	@Schema(description = "创建时间")
+	private Date createTime;
+
+}

+ 42 - 0
model/src/main/java/com/atguigu/tingshu/model/user/UserVipService.java

@@ -0,0 +1,42 @@
+package com.atguigu.tingshu.model.user;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@Schema(description = "UserVipService")
+@TableName("user_vip_service")
+public class UserVipService extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "订单号")
+	@TableField("order_no")
+	private String orderNo;
+
+	@Schema(description = "用户id")
+	@TableField("user_id")
+	private Long userId;
+
+	@Schema(description = "开始生效日期")
+	@TableField("start_time")
+	private Date startTime;
+
+	@Schema(description = "到期时间")
+	@TableField("expire_time")
+	private Date expireTime;
+
+	@Schema(description = "是否自动续费")
+	@TableField("is_auto_renew")
+	private Integer isAutoRenew;
+
+	@Schema(description = "下次自动续费时间")
+	@TableField("next_renew_time")
+	private Date nextRenewTime;
+
+}

+ 46 - 0
model/src/main/java/com/atguigu/tingshu/model/user/VipServiceConfig.java

@@ -0,0 +1,46 @@
+package com.atguigu.tingshu.model.user;
+
+import com.atguigu.tingshu.model.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "VipServiceConfig")
+@TableName("vip_service_config")
+public class VipServiceConfig extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "服务名称")
+	@TableField("name")
+	private String name;
+
+	@Schema(description = "原价,单位元,用于营销展示")
+	@TableField("price")
+	private BigDecimal price;
+
+	@Schema(description = "折后价,单位元,即实际价格")
+	@TableField("discount_price")
+	private BigDecimal discountPrice;
+
+	@Schema(description = "优惠简介")
+	@TableField("intro")
+	private String intro;
+
+	@Schema(description = "服务简介,富文本")
+	@TableField("rich_intro")
+	private String richIntro;
+
+	@Schema(description = "服务月数")
+	@TableField("service_month")
+	private Integer serviceMonth;
+
+	@Schema(description = "服务图片url")
+	@TableField("image_url")
+	private String imageUrl;
+
+}

+ 18 - 0
model/src/main/java/com/atguigu/tingshu/query/album/AlbumInfoQuery.java

@@ -0,0 +1,18 @@
+package com.atguigu.tingshu.query.album;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "专辑信息")
+public class AlbumInfoQuery {
+
+	@Schema(description = "标题")
+	private String albumTitle;
+
+	@Schema(description = "状态")
+	private String status;
+
+	@Schema(description = "用户id")
+	private Long userId;
+}

+ 18 - 0
model/src/main/java/com/atguigu/tingshu/query/album/TrackInfoQuery.java

@@ -0,0 +1,18 @@
+package com.atguigu.tingshu.query.album;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "声音信息")
+public class TrackInfoQuery {
+
+	@Schema(description = "标题")
+	private String trackTitle;
+
+	@Schema(description = "状态")
+	private String status;
+
+	@Schema(description = "用户id")
+	private Long userId;
+}

+ 15 - 0
model/src/main/java/com/atguigu/tingshu/query/order/OrderInfoQuery.java

@@ -0,0 +1,15 @@
+package com.atguigu.tingshu.query.order;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "订单信息")
+public class OrderInfoQuery {
+
+	@Schema(description = "创建时间")
+	private String createTimeBegin;
+
+	@Schema(description = "创建时间")
+	private String createTimeEnd;
+}

+ 33 - 0
model/src/main/java/com/atguigu/tingshu/query/search/AlbumIndexQuery.java

@@ -0,0 +1,33 @@
+package com.atguigu.tingshu.query.search;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Schema(description = "专辑信息搜索")
+public class AlbumIndexQuery {
+
+	@Schema(description = "关键字")
+	private String keyword;
+
+	@Schema(description = "一级分类")
+	private Long category1Id;
+
+	@Schema(description = "二级分类")
+	private Long category2Id;
+
+	@Schema(description = "三级分类")
+	private Long category3Id;
+
+	@Schema(description = "属性(属性id:属性值id)")
+	private List<String> attributeList;
+
+	// order=1:asc  排序规则   0:asc
+	@Schema(description = "排序(综合排序[1:desc] 播放量[2:desc] 发布时间[3:desc];asc:升序 desc:降序)")
+	private String order = "";// 1:综合排序 2:播放量 3:最近更新
+
+	private Integer pageNo = 1;//分页信息
+	private Integer pageSize = 10;
+}

+ 21 - 0
model/src/main/java/com/atguigu/tingshu/query/user/UserInfoQuery.java

@@ -0,0 +1,21 @@
+package com.atguigu.tingshu.query.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "声音信息")
+public class UserInfoQuery {
+
+	@Schema(description = "手机")
+	private String phone;
+
+	@Schema(description = "昵称")
+	private String nickname;
+
+	@Schema(description = "创建时间")
+	private String createTimeBegin;
+
+	@Schema(description = "创建时间")
+	private String createTimeEnd;
+}

+ 19 - 0
model/src/main/java/com/atguigu/tingshu/validation/NotEmptyPaid.java

@@ -0,0 +1,19 @@
+package com.atguigu.tingshu.validation;
+
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.*;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD })
+@Constraint(validatedBy = NotEmptyPaidValidator.class)
+public @interface NotEmptyPaid {
+
+    String message() default "不能为空";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}

+ 16 - 0
model/src/main/java/com/atguigu/tingshu/validation/NotEmptyPaidValidator.java

@@ -0,0 +1,16 @@
+package com.atguigu.tingshu.validation;
+
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+
+
+public class NotEmptyPaidValidator implements ConstraintValidator<NotEmptyPaid, String> {
+
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
+        String[] array = value.split("_");
+        if(array.length == 0 || "0101".equals(array[0])) return true;
+        if(array.length != 2) return false;
+        return true;
+    }
+}

+ 24 - 0
model/src/main/java/com/atguigu/tingshu/vo/account/AccountDeductVo.java

@@ -0,0 +1,24 @@
+package com.atguigu.tingshu.vo.account;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "扣减金额对象")
+public class AccountDeductVo {
+
+	@Schema(description = "订单号")
+	private String orderNo;
+
+	@Schema(description = "用户id")
+	private Long userId;
+
+	@Schema(description = "扣减金额")
+	private BigDecimal amount;
+
+	@Schema(description = "扣减内容")
+	private String content;
+
+}

+ 21 - 0
model/src/main/java/com/atguigu/tingshu/vo/account/AccountLockResultVo.java

@@ -0,0 +1,21 @@
+package com.atguigu.tingshu.vo.account;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "锁定金额返回对象")
+public class AccountLockResultVo {
+
+	@Schema(description = "用户id")
+	private Long userId;
+
+	@Schema(description = "锁定金额")
+	private BigDecimal amount;
+
+	@Schema(description = "锁定内容")
+	private String content;
+
+}

+ 24 - 0
model/src/main/java/com/atguigu/tingshu/vo/account/AccountLockVo.java

@@ -0,0 +1,24 @@
+package com.atguigu.tingshu.vo.account;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "锁定金额对象")
+public class AccountLockVo {
+
+	@Schema(description = "订单号")
+	private String orderNo;
+
+	@Schema(description = "用户id")
+	private Long userId;
+
+	@Schema(description = "锁定金额")
+	private BigDecimal amount;
+
+	@Schema(description = "锁定内容")
+	private String content;
+
+}

Some files were not shown because too many files changed in this diff