Browse Source

refactor: 基于新的需求重构

ChenSiTong 6 years ago
parent
commit
cc506d4221
100 changed files with 1790 additions and 1912 deletions
  1. 4 10
      .gitignore
  2. 118 0
      .mvn/wrapper/MavenWrapperDownloader.java
  3. BIN
      .mvn/wrapper/maven-wrapper.jar
  4. 2 0
      .mvn/wrapper/maven-wrapper.properties
  5. 3 3
      mvnw
  6. 4 4
      mvnw.cmd
  7. 0 23
      package.json
  8. 36 46
      pom.xml
  9. 1 7
      src/main/java/nju/seec/helper/HelperApplication.java
  10. 72 71
      src/main/java/nju/seec/helper/InitDataComponent.java
  11. 4 2
      src/main/java/nju/seec/helper/ServletInitializer.java
  12. 0 41
      src/main/java/nju/seec/helper/aop/log/LogAspect.java
  13. 17 0
      src/main/java/nju/seec/helper/aspect/auth/Auth.java
  14. 50 0
      src/main/java/nju/seec/helper/aspect/auth/AuthAspect.java
  15. 8 0
      src/main/java/nju/seec/helper/constant/Consts.java
  16. 19 0
      src/main/java/nju/seec/helper/constant/OssProperties.java
  17. 37 0
      src/main/java/nju/seec/helper/controller/CodeController.java
  18. 8 3
      src/main/java/nju/seec/helper/controller/ControllerAdvice.java
  19. 75 0
      src/main/java/nju/seec/helper/controller/CourseController.java
  20. 63 0
      src/main/java/nju/seec/helper/controller/SlideController.java
  21. 55 0
      src/main/java/nju/seec/helper/controller/UserController.java
  22. 2 5
      src/main/java/nju/seec/helper/controller/response/EmptyResponse.java
  23. 1 1
      src/main/java/nju/seec/helper/controller/response/ErrorResponse.java
  24. 6 2
      src/main/java/nju/seec/helper/controller/response/PageResourceResponse.java
  25. 1 1
      src/main/java/nju/seec/helper/controller/response/ResourceResponse.java
  26. 1 1
      src/main/java/nju/seec/helper/controller/response/Response.java
  27. 1 1
      src/main/java/nju/seec/helper/controller/response/SuccessResponse.java
  28. 32 0
      src/main/java/nju/seec/helper/dao/ChooseDAO.java
  29. 65 0
      src/main/java/nju/seec/helper/dao/CourseDAO.java
  30. 49 0
      src/main/java/nju/seec/helper/dao/SlideDAO.java
  31. 51 0
      src/main/java/nju/seec/helper/dao/UserDAO.java
  32. 0 24
      src/main/java/nju/seec/helper/data/convert/IntMapConverter.java
  33. 0 24
      src/main/java/nju/seec/helper/data/convert/MapConverter.java
  34. 0 24
      src/main/java/nju/seec/helper/data/convert/SetConverter.java
  35. 0 33
      src/main/java/nju/seec/helper/data/dao/CourseDAO.java
  36. 0 46
      src/main/java/nju/seec/helper/data/dao/NoteDAO.java
  37. 0 32
      src/main/java/nju/seec/helper/data/dao/QuestionDAO.java
  38. 0 23
      src/main/java/nju/seec/helper/data/dao/QuizDAO.java
  39. 0 80
      src/main/java/nju/seec/helper/data/dao/SlideDAO.java
  40. 0 20
      src/main/java/nju/seec/helper/data/dao/SubmitAnswerDAO.java
  41. 0 25
      src/main/java/nju/seec/helper/data/entity/Course.java
  42. 0 38
      src/main/java/nju/seec/helper/data/entity/Item.java
  43. 0 46
      src/main/java/nju/seec/helper/data/entity/Note.java
  44. 0 49
      src/main/java/nju/seec/helper/data/entity/Question.java
  45. 0 39
      src/main/java/nju/seec/helper/data/entity/Quiz.java
  46. 0 38
      src/main/java/nju/seec/helper/data/entity/SubmitAnswer.java
  47. 17 0
      src/main/java/nju/seec/helper/dto/ChooseDTO.java
  48. 23 0
      src/main/java/nju/seec/helper/dto/CourseDTO.java
  49. 16 0
      src/main/java/nju/seec/helper/dto/LoginDTO.java
  50. 14 0
      src/main/java/nju/seec/helper/dto/LoginUser.java
  51. 27 0
      src/main/java/nju/seec/helper/dto/RegisterDTO.java
  52. 22 0
      src/main/java/nju/seec/helper/dto/SlideDTO.java
  53. 25 0
      src/main/java/nju/seec/helper/entity/Choose.java
  54. 45 0
      src/main/java/nju/seec/helper/entity/Course.java
  55. 23 0
      src/main/java/nju/seec/helper/entity/Page.java
  56. 16 15
      src/main/java/nju/seec/helper/entity/Slide.java
  57. 36 0
      src/main/java/nju/seec/helper/entity/User.java
  58. 0 29
      src/main/java/nju/seec/helper/logic/service/CourseService.java
  59. 0 59
      src/main/java/nju/seec/helper/logic/service/NoteService.java
  60. 0 18
      src/main/java/nju/seec/helper/logic/service/QuestionService.java
  61. 0 46
      src/main/java/nju/seec/helper/logic/service/QuizService.java
  62. 0 104
      src/main/java/nju/seec/helper/logic/service/SlideService.java
  63. 0 40
      src/main/java/nju/seec/helper/logic/service/impl/CourseServiceImpl.java
  64. 0 81
      src/main/java/nju/seec/helper/logic/service/impl/NoteServiceImpl.java
  65. 0 30
      src/main/java/nju/seec/helper/logic/service/impl/QuestionServiceImpl.java
  66. 0 113
      src/main/java/nju/seec/helper/logic/service/impl/QuizServiceImpl.java
  67. 0 149
      src/main/java/nju/seec/helper/logic/service/impl/SlideServiceImpl.java
  68. 0 18
      src/main/java/nju/seec/helper/logic/vo/CourseVO.java
  69. 0 28
      src/main/java/nju/seec/helper/logic/vo/ItemVO.java
  70. 0 33
      src/main/java/nju/seec/helper/logic/vo/NoAnswerQuestionVO.java
  71. 0 36
      src/main/java/nju/seec/helper/logic/vo/NoteVO.java
  72. 0 37
      src/main/java/nju/seec/helper/logic/vo/QuestionVO.java
  73. 0 33
      src/main/java/nju/seec/helper/logic/vo/QuizVO.java
  74. 0 40
      src/main/java/nju/seec/helper/logic/vo/SlideVO.java
  75. 0 69
      src/main/java/nju/seec/helper/logic/vo/StudentQuizVO.java
  76. 0 31
      src/main/java/nju/seec/helper/logic/vo/SubmitAnswerVO.java
  77. 20 0
      src/main/java/nju/seec/helper/service/CodeService.java
  78. 61 0
      src/main/java/nju/seec/helper/service/CourseService.java
  79. 52 0
      src/main/java/nju/seec/helper/service/SlideService.java
  80. 34 0
      src/main/java/nju/seec/helper/service/UserService.java
  81. 51 0
      src/main/java/nju/seec/helper/service/impl/CodeServiceImpl.java
  82. 103 0
      src/main/java/nju/seec/helper/service/impl/CourseServiceImpl.java
  83. 150 0
      src/main/java/nju/seec/helper/service/impl/SlideServiceImpl.java
  84. 80 0
      src/main/java/nju/seec/helper/service/impl/UserServiceImpl.java
  85. 19 0
      src/main/java/nju/seec/helper/util/EncryptUtils.java
  86. 0 18
      src/main/java/nju/seec/helper/util/FakerUtils.java
  87. 0 28
      src/main/java/nju/seec/helper/util/HttpUtils.java
  88. 39 0
      src/main/java/nju/seec/helper/util/OssUtils.java
  89. 30 0
      src/main/java/nju/seec/helper/util/RedisUtils.java
  90. 0 8
      src/main/java/nju/seec/helper/util/enums/ItemTransition.java
  91. 0 19
      src/main/java/nju/seec/helper/util/enums/ItemType.java
  92. 0 8
      src/main/java/nju/seec/helper/util/enums/NoteType.java
  93. 0 8
      src/main/java/nju/seec/helper/util/enums/QuestionType.java
  94. 0 8
      src/main/java/nju/seec/helper/util/enums/QuizType.java
  95. 1 0
      src/main/java/nju/seec/helper/util/enums/UserType.java
  96. 1 1
      src/main/java/nju/seec/helper/util/exception/HelperException.java
  97. 26 0
      src/main/java/nju/seec/helper/vo/CourseVO.java
  98. 49 0
      src/main/java/nju/seec/helper/vo/SlideVO.java
  99. 25 0
      src/main/java/nju/seec/helper/vo/UserVO.java
  100. 0 43
      src/main/java/nju/seec/helper/web/controller/CourseController.java

+ 4 - 10
.gitignore

@@ -1,6 +1,8 @@
 HELP.md
-/target/
+target/
 !.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
 
 ### STS ###
 .apt_generated
@@ -23,15 +25,7 @@ HELP.md
 /dist/
 /nbdist/
 /.nb-gradle/
-/build/
+build/
 
 ### VS Code ###
 .vscode/
-
-
-### MacOS ###
-.DS_Store
-
-### NPM ###
-node_modules/
-package-lock.json

+ 118 - 0
.mvn/wrapper/MavenWrapperDownloader.java

@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+    private static final String WRAPPER_VERSION = "0.5.6";
+    /**
+     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+     */
+    private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+            + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+    /**
+     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+     * use instead of the default one.
+     */
+    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+            ".mvn/wrapper/maven-wrapper.properties";
+
+    /**
+     * Path where the maven-wrapper.jar will be saved to.
+     */
+    private static final String MAVEN_WRAPPER_JAR_PATH =
+            ".mvn/wrapper/maven-wrapper.jar";
+
+    /**
+     * Name of the property which should be used to override the default download url for the wrapper.
+     */
+    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+    public static void main(String args[]) {
+        System.out.println("- Downloader started");
+        File baseDirectory = new File(args[0]);
+        System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+        // If the maven-wrapper.properties exists, read it and check if it contains a custom
+        // wrapperUrl parameter.
+        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+        String url = DEFAULT_DOWNLOAD_URL;
+        if (mavenWrapperPropertyFile.exists()) {
+            FileInputStream mavenWrapperPropertyFileInputStream = null;
+            try {
+                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+                Properties mavenWrapperProperties = new Properties();
+                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+            } catch (IOException e) {
+                System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+            } finally {
+                try {
+                    if (mavenWrapperPropertyFileInputStream != null) {
+                        mavenWrapperPropertyFileInputStream.close();
+                    }
+                } catch (IOException e) {
+                    // Ignore ...
+                }
+            }
+        }
+        System.out.println("- Downloading from: " + url);
+
+        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+        if (!outputFile.getParentFile().exists()) {
+            if (!outputFile.getParentFile().mkdirs()) {
+                System.out.println(
+                        "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+            }
+        }
+        System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+        try {
+            downloadFileFromURL(url, outputFile);
+            System.out.println("Done");
+            System.exit(0);
+        } catch (Throwable e) {
+            System.out.println("- Error downloading");
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+        if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+            String username = System.getenv("MVNW_USERNAME");
+            char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+            Authenticator.setDefault(new Authenticator() {
+                @Override
+                protected PasswordAuthentication getPasswordAuthentication() {
+                    return new PasswordAuthentication(username, password);
+                }
+            });
+        }
+        URL website = new URL(urlString);
+        ReadableByteChannel rbc;
+        rbc = Channels.newChannel(website.openStream());
+        FileOutputStream fos = new FileOutputStream(destination);
+        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+        fos.close();
+        rbc.close();
+    }
+
+}

BIN
.mvn/wrapper/maven-wrapper.jar


+ 2 - 0
.mvn/wrapper/maven-wrapper.properties

@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

+ 3 - 3
mvnw

@@ -19,7 +19,7 @@
 # ----------------------------------------------------------------------------
 
 # ----------------------------------------------------------------------------
-# Maven2 Start Up Batch script
+# Maven Start Up Batch script
 #
 # Required ENV vars:
 # ------------------
@@ -221,9 +221,9 @@ else
     echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
   fi
   if [ -n "$MVNW_REPOURL" ]; then
-    jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
   else
-    jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
   fi
   while IFS="=" read key value; do
     case "$key" in wrapperUrl)

+ 4 - 4
mvnw.cmd

@@ -18,7 +18,7 @@
 @REM ----------------------------------------------------------------------------
 
 @REM ----------------------------------------------------------------------------
-@REM Maven2 Start Up Batch script
+@REM Maven Start Up Batch script
 @REM
 @REM Required ENV vars:
 @REM JAVA_HOME - location of a JDK home dir
@@ -26,7 +26,7 @@
 @REM Optional ENV vars
 @REM M2_HOME - location of maven2's installed home dir
 @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
-@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
 @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
 @REM     e.g. to debug Maven itself, use
 @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@@ -120,7 +120,7 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
 set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
 set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
 
-set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
 
 FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
     IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
@@ -134,7 +134,7 @@ if exist %WRAPPER_JAR% (
     )
 ) else (
     if not "%MVNW_REPOURL%" == "" (
-        SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
     )
     if "%MVNW_VERBOSE%" == "true" (
         echo Couldn't find %WRAPPER_JAR%, downloading it ...

+ 0 - 23
package.json

@@ -1,23 +0,0 @@
-{
-  "name": "backend",
-  "version": "1.0.0",
-  "description": "",
-  "main": "index.js",
-  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
-  },
-  "repository": {
-    "type": "git",
-    "url": "http://47.100.18.120:3000/SEEC-HELPER/backend.git"
-  },
-  "author": "cst",
-  "license": "ISC",
-  "devDependencies": {
-    "cz-conventional-changelog": "^3.0.2"
-  },
-  "config": {
-    "commitizen": {
-      "path": "./node_modules/cz-conventional-changelog"
-    }
-  }
-}

+ 36 - 46
pom.xml

@@ -5,68 +5,74 @@
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>2.2.2.RELEASE</version>
+        <version>2.2.4.RELEASE</version>
         <relativePath/> <!-- lookup parent from repository -->
     </parent>
     <groupId>nju.seec</groupId>
     <artifactId>helper</artifactId>
     <version>0.0.1-SNAPSHOT</version>
-    <name>helper</name>
-    <description>Demo project for Spring Boot</description>
     <packaging>war</packaging>
+    <name>helper</name>
+    <description>backend</description>
 
     <properties>
         <java.version>1.8</java.version>
+        <swagger.version>2.8.0</swagger.version>
     </properties>
 
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-aop</artifactId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-actuator</artifactId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-tomcat</artifactId>
-            <scope>provided</scope>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-data-jpa</artifactId>
+            <artifactId>spring-boot-starter-mail</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-cache</artifactId>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>2.0.18</version>
         </dependency>
-
-        <!-- 开发阶段使用内存数据库 -->
         <dependency>
-            <groupId>com.h2database</groupId>
-            <artifactId>h2</artifactId>
-            <scope>runtime</scope>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.8.1</version>
         </dependency>
+
         <!--        <dependency>-->
-        <!--            <groupId>mysql</groupId>-->
-        <!--            <artifactId>mysql-connector-java</artifactId>-->
+        <!--            <groupId>com.h2database</groupId>-->
+        <!--            <artifactId>h2</artifactId>-->
         <!--            <scope>runtime</scope>-->
         <!--        </dependency>-->
         <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-configuration-processor</artifactId>
-            <optional>true</optional>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
@@ -79,31 +85,16 @@
             </exclusions>
         </dependency>
 
-        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
-        <dependency>
-            <groupId>com.google.code.gson</groupId>
-            <artifactId>gson</artifactId>
-            <version>2.8.6</version>
-        </dependency>
-        <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-            <version>28.1-jre</version>
-        </dependency>
-
-        <!-- 开发阶段用于接口展示和调用 -->
-        <dependency>
-            <groupId>io.springfox</groupId>
-            <artifactId>springfox-swagger2</artifactId>
-            <version>2.8.0</version>
-        </dependency>
-
-        <dependency>
-            <groupId>io.springfox</groupId>
-            <artifactId>springfox-swagger-ui</artifactId>
-            <version>2.8.0</version>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>io.springfox</groupId>-->
+<!--            <artifactId>springfox-swagger2</artifactId>-->
+<!--            <version>${swagger.version}</version>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>io.springfox</groupId>-->
+<!--            <artifactId>springfox-swagger-ui</artifactId>-->
+<!--            <version>${swagger.version}</version>-->
+<!--        </dependency>-->
 
         <!-- 开发阶段用于假数据生成 -->
         <!-- https://mvnrepository.com/artifact/com.github.javafaker/javafaker -->
@@ -115,7 +106,6 @@
     </dependencies>
 
     <build>
-        <finalName>seec_helper</finalName>
         <plugins>
             <plugin>
                 <groupId>org.springframework.boot</groupId>

+ 1 - 7
src/main/java/nju/seec/helper/HelperApplication.java

@@ -2,21 +2,15 @@ package nju.seec.helper;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cache.annotation.EnableCaching;
-import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 
 /**
  * @author cst
  */
-@SpringBootApplication
-@EnableJpaRepositories(basePackages = "nju.seec.helper.data.dao")
-@EnableCaching
 @EnableTransactionManagement
+@SpringBootApplication
 public class HelperApplication {
-
     public static void main(String[] args) {
         SpringApplication.run(HelperApplication.class, args);
     }
-
 }

+ 72 - 71
src/main/java/nju/seec/helper/InitDataComponent.java

@@ -1,71 +1,72 @@
-package nju.seec.helper;
-
-import com.google.common.collect.ImmutableMap;
-import nju.seec.helper.data.dao.CourseDAO;
-import nju.seec.helper.data.dao.QuestionDAO;
-import nju.seec.helper.data.entity.Course;
-import nju.seec.helper.data.entity.Question;
-import nju.seec.helper.util.FakerUtils;
-import nju.seec.helper.util.enums.QuestionType;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
-import org.springframework.stereotype.Component;
-
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Random;
-
-/**
- * @author cst
- */
-@Component
-public class InitDataComponent implements ApplicationRunner {
-    private final CourseDAO courseDAO;
-
-    private final QuestionDAO questionDAO;
-
-    public InitDataComponent(CourseDAO courseDAO, QuestionDAO questionDAO) {
-        this.courseDAO = courseDAO;
-        this.questionDAO = questionDAO;
-    }
-
-    @Override
-    public void run(ApplicationArguments args) {
-        // init course
-        int size = 10;
-        List<Course> courses = new ArrayList<>(size);
-        for (int i = 1; i <= size; i++) {
-            Course course = new Course();
-            course.setId(i);
-            course.setName(FakerUtils.getFaker().job().field());
-            course.setTeacherId(1);
-            courses.add(course);
-        }
-        courseDAO.saveAll(courses);
-
-        // init question
-        size = 10;
-        List<Question> questions = new ArrayList<>(size);
-        for (int i = 1; i <= size; i++) {
-            Question fakerQuestion = new Question();
-            fakerQuestion.setId(i);
-            int a = new Random().nextInt(10);
-            int b = new Random().nextInt(10);
-            int answer = a + b;
-            fakerQuestion.setStem(String.format("%d+%d=?", a, b));
-            fakerQuestion.setType(QuestionType.choice);
-            int offset = new Random().nextInt(4);
-            int index = 0;
-            fakerQuestion.setOptions(ImmutableMap.of("A", answer - offset + index++ + "", "B", answer - offset + index++ + "", "C", answer - offset + index++ + "", "D", answer - offset + index + ""));
-            fakerQuestion.setTags(Collections.singleton("加法"));
-            fakerQuestion.setKnowledgeId(Collections.singleton("plus"));
-            fakerQuestion.setAnswer((char) ('A' + offset) + "");
-            fakerQuestion.setAnalysis(String.format("%d+%d=%d", a, b, answer));
-            fakerQuestion.setLastModified(LocalDateTime.now());
-            questions.add(fakerQuestion);
-        }
-        questionDAO.saveAll(questions);
-    }
-}
+//package nju.seec.helper;
+//
+//import com.github.javafaker.Faker;
+//import com.google.common.collect.ImmutableList;
+//import nju.seec.helper.dao.CourseDAO;
+//import nju.seec.helper.dao.UserDAO;
+//import nju.seec.helper.entity.Course;
+//import nju.seec.helper.entity.User;
+//import nju.seec.helper.util.EncryptUtils;
+//import nju.seec.helper.util.enums.UserType;
+//import org.springframework.boot.ApplicationArguments;
+//import org.springframework.boot.ApplicationRunner;
+//import org.springframework.stereotype.Component;
+//
+//import java.util.List;
+//
+///**
+// * @author cst
+// */
+//@Component
+//public class InitDataComponent implements ApplicationRunner {
+//    private final UserDAO userDAO;
+//    private final CourseDAO courseDAO;
+//
+//    public InitDataComponent(UserDAO userDAO, CourseDAO courseDAO) {
+//        this.userDAO = userDAO;
+//        this.courseDAO = courseDAO;
+//    }
+//
+//    @Override
+//    public void run(ApplicationArguments args) {
+//        Faker faker = new Faker();
+//        // init user
+//        String teacherName = faker.name().name();
+//        List<User> users = ImmutableList.of(
+//                new User().setName(teacherName)
+//                        .setEmail(faker.internet().emailAddress())
+//                        .setPhone(faker.phoneNumber().phoneNumber())
+//                        .setPassword(EncryptUtils.encode("teacher"))
+//                        .setType(UserType.TEACHER),
+//                new User().setName(faker.name().name())
+//                        .setEmail(faker.internet().emailAddress())
+//                        .setPhone(faker.phoneNumber().phoneNumber())
+//                        .setPassword(EncryptUtils.encode("student"))
+//                        .setType(UserType.STUDENT)
+//        );
+//        userDAO.saveAll(users);
+//
+//        // init course
+//        List<Course> courses = ImmutableList.of(
+//                new Course().setTeacherId(1)
+//                        .setTeacherName(teacherName)
+//                        .setName(faker.educator().course())
+//                        .setBio("")
+//                        .setCode(EncryptUtils.encode("123456"))
+//                        .setCover(""),
+//                new Course().setTeacherId(1)
+//                        .setTeacherName(teacherName)
+//                        .setName(faker.educator().course())
+//                        .setBio("")
+//                        .setCode(EncryptUtils.encode("123456"))
+//                        .setCover(""),
+//                new Course().setTeacherId(1)
+//                        .setTeacherName(teacherName)
+//                        .setName(faker.educator().course())
+//                        .setBio("")
+//                        .setCode(EncryptUtils.encode("123456"))
+//                        .setCover("")
+//        );
+//        courseDAO.saveAll(courses);
+//    }
+//}

+ 4 - 2
src/main/java/nju/seec/helper/ServletInitializer.java

@@ -7,8 +7,10 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
  * @author cst
  */
 public class ServletInitializer extends SpringBootServletInitializer {
+
     @Override
-    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
-        return builder.sources(HelperApplication.class);
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+        return application.sources(HelperApplication.class);
     }
+
 }

+ 0 - 41
src/main/java/nju/seec/helper/aop/log/LogAspect.java

@@ -1,41 +0,0 @@
-package nju.seec.helper.aop.log;
-
-import lombok.extern.slf4j.Slf4j;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.AfterThrowing;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.springframework.stereotype.Component;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * @author cst
- */
-@Aspect
-@Component
-@Slf4j
-public class LogAspect {
-    @Before("execution(public * nju.seec.helper.web.controller..*.*(..))")
-    public void logControllerRequest(JoinPoint joinPoint) {
-        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)
-                RequestContextHolder.getRequestAttributes();
-
-        if (requestAttributes != null) {
-            HttpServletRequest request = requestAttributes.getRequest();
-            log.info("IP地址 " + request.getRemoteAddr() + " 访问 " +
-                    joinPoint.getTarget().getClass().getName() + " 类 " +
-                    joinPoint.getSignature().getName() + " 方法");
-        }
-    }
-
-    @AfterThrowing(pointcut = "execution(public * nju.seec.helper.logic.service.impl..*.*(..))", throwing = "e")
-    public void logServiceThrowing(JoinPoint joinPoint, Throwable e) {
-        log.error(joinPoint.getTarget().getClass().getName() + " 类 " +
-                joinPoint.getSignature().getName() + " 方法出现异常:" +
-                e.getLocalizedMessage()
-        );
-    }
-}

+ 17 - 0
src/main/java/nju/seec/helper/aspect/auth/Auth.java

@@ -0,0 +1,17 @@
+package nju.seec.helper.aspect.auth;
+
+import nju.seec.helper.util.enums.UserType;
+
+import java.lang.annotation.*;
+
+/**
+ * @author cst
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Auth {
+    UserType[] roles() default {};
+
+    String message();
+}

+ 50 - 0
src/main/java/nju/seec/helper/aspect/auth/AuthAspect.java

@@ -0,0 +1,50 @@
+package nju.seec.helper.aspect.auth;
+
+import nju.seec.helper.constant.Consts;
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.util.exception.HelperException;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpSession;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @author cst
+ */
+@Aspect
+@Component
+public class AuthAspect {
+    @Before("execution(public * nju.seec.helper.controller.*.*(..)) && @annotation(auth)")
+    public void authCheck(JoinPoint joinPoint, Auth auth) {
+        HttpSession session =
+                ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))
+                        .getRequest()
+                        .getSession();
+
+        LoginUser user = (LoginUser) session.getAttribute(Consts.SESSION_USER_NAME);
+        if (user == null) {
+            throw HelperException.of(HelperException.ExceptionType.NOT_LOGIN, "您未登录");
+        } else if (!Arrays
+                .stream(auth.roles())
+                .collect(Collectors.toSet())
+                .contains(user.getType())) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, String.format("您暂时无法%s,请重新登录", auth.message()));
+        }
+
+        Object[] objects = joinPoint.getArgs();
+        for (Object o : objects) {
+            if (o.getClass() == LoginUser.class) {
+                BeanUtils.copyProperties(user, o);
+                break;
+            }
+        }
+    }
+}

+ 8 - 0
src/main/java/nju/seec/helper/constant/Consts.java

@@ -0,0 +1,8 @@
+package nju.seec.helper.constant;
+
+/**
+ * @author cst
+ */
+public class Consts {
+    public static final String SESSION_USER_NAME = "helper_user";
+}

+ 19 - 0
src/main/java/nju/seec/helper/constant/OssProperties.java

@@ -0,0 +1,19 @@
+package nju.seec.helper.constant;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author cst
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "aliyun.oss")
+public class OssProperties {
+    private String endpoint;
+    private String accessKeyId;
+    private String accessKeySecret;
+    private String bucketName;
+    private Integer expirationMinutes;
+}

+ 37 - 0
src/main/java/nju/seec/helper/controller/CodeController.java

@@ -0,0 +1,37 @@
+package nju.seec.helper.controller;
+
+import io.swagger.annotations.Api;
+import nju.seec.helper.controller.response.EmptyResponse;
+import nju.seec.helper.service.CodeService;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author cst
+ */
+@Api(tags = "验证码")
+@RestController
+@RequestMapping("/api/code")
+public class CodeController {
+    private final CodeService codeService;
+
+    public CodeController(CodeService codeService) {
+        this.codeService = codeService;
+    }
+
+    @PostMapping("/email")
+    public EmptyResponse sendEmailCode(@Email String email) {
+        codeService.sendEmailCode(email);
+        return EmptyResponse.getInstance();
+    }
+
+    @PostMapping("/phone")
+    public EmptyResponse sendPhoneCode(@NotBlank String phone) {
+        codeService.sendPhoneCode(phone);
+        return EmptyResponse.getInstance();
+    }
+}

+ 8 - 3
src/main/java/nju/seec/helper/web/HelperExceptionHandler.java → src/main/java/nju/seec/helper/controller/ControllerAdvice.java

@@ -1,7 +1,7 @@
-package nju.seec.helper.web;
+package nju.seec.helper.controller;
 
+import nju.seec.helper.controller.response.ErrorResponse;
 import nju.seec.helper.util.exception.HelperException;
-import nju.seec.helper.web.response.ErrorResponse;
 import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
@@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
  * @author cst
  */
 @RestControllerAdvice
-public class HelperExceptionHandler {
+public class ControllerAdvice {
     @ExceptionHandler(MethodArgumentNotValidException.class)
     public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
         return ErrorResponse.of(400, ex.getLocalizedMessage());
@@ -20,4 +20,9 @@ public class HelperExceptionHandler {
     public ErrorResponse handleHelperException(HelperException ex) {
         return ErrorResponse.of(ex.getType().getCode(), ex.getMsg());
     }
+
+    @ExceptionHandler(Exception.class)
+    public ErrorResponse handleException(Exception e) {
+        return ErrorResponse.of(500, e.getLocalizedMessage());
+    }
 }

+ 75 - 0
src/main/java/nju/seec/helper/controller/CourseController.java

@@ -0,0 +1,75 @@
+package nju.seec.helper.controller;
+
+import nju.seec.helper.aspect.auth.Auth;
+import nju.seec.helper.controller.response.EmptyResponse;
+import nju.seec.helper.controller.response.PageResourceResponse;
+import nju.seec.helper.controller.response.ResourceResponse;
+import nju.seec.helper.dto.ChooseDTO;
+import nju.seec.helper.dto.CourseDTO;
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.service.CourseService;
+import nju.seec.helper.util.enums.UserType;
+import nju.seec.helper.util.exception.HelperException;
+import nju.seec.helper.vo.CourseVO;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author cst
+ */
+@RestController
+@RequestMapping("/api/course")
+public class CourseController {
+    private final CourseService courseService;
+
+    public CourseController(CourseService courseService) {
+        this.courseService = courseService;
+    }
+
+    @Auth(roles = UserType.TEACHER, message = "创建课程")
+    @PostMapping
+    public ResourceResponse<CourseVO> createCourse(LoginUser user,
+                                                   @RequestBody CourseDTO courseDTO) {
+        CourseVO courseVO = courseService.createCourse(user, courseDTO);
+        return ResourceResponse.of(courseVO);
+    }
+
+    @Auth(roles = UserType.STUDENT, message = "选课")
+    @PostMapping("/choose")
+    public EmptyResponse chooseCourse(LoginUser user,
+                                      @RequestBody ChooseDTO chooseDTO) {
+        courseService.chooseCourse(user, chooseDTO);
+        return EmptyResponse.getInstance();
+    }
+
+    @Auth(roles = {UserType.TEACHER, UserType.STUDENT}, message = "查看课程")
+    @GetMapping
+    public PageResourceResponse<CourseVO> teacherGetCourses(LoginUser user,
+                                                            @RequestParam(required = false, defaultValue = "") String key,
+                                                            @PageableDefault(Integer.MAX_VALUE) Pageable pageable) {
+        List<CourseVO> courseVOList;
+        switch (user.getType()) {
+            case TEACHER:
+                courseVOList = courseService.teacherGetCourses(user, key, pageable);
+                break;
+            case STUDENT:
+                courseVOList = courseService.studentGetCourses(user, key, pageable);
+                break;
+            default:
+                throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您暂时无法查看课程");
+        }
+        return PageResourceResponse.of(courseVOList, pageable.getPageNumber(), pageable.getPageSize());
+    }
+
+    @Auth(roles = UserType.STUDENT, message = "获取所选课程")
+    @GetMapping("/choose")
+    public PageResourceResponse<CourseVO> studentGetChooseCourses(LoginUser user,
+                                                                  @RequestParam(required = false, defaultValue = "") String key,
+                                                                  @PageableDefault(Integer.MAX_VALUE) Pageable pageable) {
+        List<CourseVO> courseVOList = courseService.studentGetChooseCourses(user, key, pageable);
+        return PageResourceResponse.of(courseVOList, pageable.getPageNumber(), pageable.getPageSize());
+    }
+}

+ 63 - 0
src/main/java/nju/seec/helper/controller/SlideController.java

@@ -0,0 +1,63 @@
+package nju.seec.helper.controller;
+
+import nju.seec.helper.aspect.auth.Auth;
+import nju.seec.helper.controller.response.PageResourceResponse;
+import nju.seec.helper.controller.response.ResourceResponse;
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.dto.SlideDTO;
+import nju.seec.helper.service.SlideService;
+import nju.seec.helper.util.enums.UserType;
+import nju.seec.helper.vo.SlideVO;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author cst
+ */
+@RestController
+@RequestMapping("/api/slide")
+public class SlideController {
+    private final SlideService slideService;
+
+    public SlideController(SlideService slideService) {
+        this.slideService = slideService;
+    }
+
+    @Auth(roles = UserType.TEACHER, message = "创建幻灯片")
+    @PostMapping
+    public ResourceResponse<SlideVO> createSlide(LoginUser user,
+                                                 SlideDTO slideDTO) {
+        SlideVO slideVO = slideService.createSlide(user, slideDTO);
+        return ResourceResponse.of(slideVO);
+    }
+
+    @Auth(roles = UserType.TEACHER, message = "获取幻灯片列表")
+    @GetMapping
+    public PageResourceResponse<SlideVO> teacherGetSlides(LoginUser user,
+                                                          @RequestParam(required = false, defaultValue = "") String key,
+                                                          @PageableDefault(size = Integer.MAX_VALUE) Pageable pageable) {
+        List<SlideVO> slideVOList = slideService.teacherGetSlides(user, key, pageable);
+        return PageResourceResponse.of(slideVOList, pageable.getPageNumber(), pageable.getPageSize());
+    }
+
+    @Auth(roles = UserType.STUDENT, message = "获取幻灯片列表")
+    @GetMapping("/course/{courseId}")
+    public PageResourceResponse<SlideVO> studentGetSlides(LoginUser user,
+                                                          @PathVariable Integer courseId,
+                                                          @RequestParam(required = false, defaultValue = "") String key,
+                                                          @PageableDefault(size = Integer.MAX_VALUE) Pageable pageable) {
+        List<SlideVO> slideVOList = slideService.studentGetSlides(user, courseId, key, pageable);
+        return PageResourceResponse.of(slideVOList, pageable.getPageNumber(), pageable.getPageSize());
+    }
+
+    @Auth(roles = {UserType.TEACHER, UserType.STUDENT}, message = "获取幻灯片链接")
+    @GetMapping("/url/{slideId}")
+    public ResourceResponse<String> getSlideUrl(LoginUser user,
+                                                @PathVariable Integer slideId) {
+        String slideUrl = slideService.getSlideUrl(user, slideId);
+        return ResourceResponse.of(slideUrl);
+    }
+}

+ 55 - 0
src/main/java/nju/seec/helper/controller/UserController.java

@@ -0,0 +1,55 @@
+package nju.seec.helper.controller;
+
+import nju.seec.helper.aspect.auth.Auth;
+import nju.seec.helper.constant.Consts;
+import nju.seec.helper.controller.response.ResourceResponse;
+import nju.seec.helper.dto.LoginDTO;
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.dto.RegisterDTO;
+import nju.seec.helper.service.UserService;
+import nju.seec.helper.util.enums.UserType;
+import nju.seec.helper.vo.UserVO;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * @author cst
+ */
+@RestController
+@RequestMapping("/api/user")
+public class UserController {
+    private final UserService userService;
+
+    public UserController(UserService userService) {
+        this.userService = userService;
+    }
+
+    @PostMapping("/register")
+    public ResourceResponse<UserVO> register(@RequestBody RegisterDTO registerDTO) {
+        UserVO userVO = userService.createUser(registerDTO);
+        return ResourceResponse.of(userVO);
+    }
+
+    @PostMapping("/login/email")
+    public ResourceResponse<UserVO> emailLogin(@RequestBody LoginDTO loginDTO,
+                                               HttpSession session) {
+        UserVO userVO = userService.getUserByEmailAndPassword(loginDTO.getUsername(), loginDTO.getPassword());
+        LoginUser user = new LoginUser();
+        user.setId(userVO.getId());
+        user.setName(userVO.getName());
+        user.setType(userVO.getType());
+
+        session.setAttribute(Consts.SESSION_USER_NAME, user);
+        // 20分钟有效期
+        session.setMaxInactiveInterval(1200);
+        return ResourceResponse.of(userVO);
+    }
+
+    @Auth(roles = {UserType.TEACHER, UserType.STUDENT}, message = "获取自身用户信息")
+    @GetMapping
+    public ResourceResponse<UserVO> getUserInfo(LoginUser user) {
+        UserVO userVO = userService.getUserById(user.getId());
+        return ResourceResponse.of(userVO);
+    }
+}

+ 2 - 5
src/main/java/nju/seec/helper/web/response/EmptyResponse.java → src/main/java/nju/seec/helper/controller/response/EmptyResponse.java

@@ -1,4 +1,4 @@
-package nju.seec.helper.web.response;
+package nju.seec.helper.controller.response;
 
 import lombok.AccessLevel;
 import lombok.Data;
@@ -12,12 +12,9 @@ import lombok.NoArgsConstructor;
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 @EqualsAndHashCode(callSuper = true)
 public class EmptyResponse extends SuccessResponse {
-    private static EmptyResponse instance;
+    private static EmptyResponse instance = new EmptyResponse();
 
     public static EmptyResponse getInstance() {
-        if (instance == null) {
-            instance = new EmptyResponse();
-        }
         return instance;
     }
 }

+ 1 - 1
src/main/java/nju/seec/helper/web/response/ErrorResponse.java → src/main/java/nju/seec/helper/controller/response/ErrorResponse.java

@@ -1,4 +1,4 @@
-package nju.seec.helper.web.response;
+package nju.seec.helper.controller.response;
 
 import lombok.Data;
 import lombok.EqualsAndHashCode;

+ 6 - 2
src/main/java/nju/seec/helper/web/response/PageResourceResponse.java → src/main/java/nju/seec/helper/controller/response/PageResourceResponse.java

@@ -1,4 +1,4 @@
-package nju.seec.helper.web.response;
+package nju.seec.helper.controller.response;
 
 import lombok.AllArgsConstructor;
 import lombok.Data;
@@ -11,11 +11,15 @@ import java.util.List;
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
-@AllArgsConstructor(staticName = "of")
+@AllArgsConstructor
 public class PageResourceResponse<T> extends SuccessResponse {
     private List<T> data;
     private PageInfo pager;
 
+    public static <T> PageResourceResponse<T> of(List<T> data, int page, int size) {
+        return new PageResourceResponse<>(data, PageInfo.of(page, size));
+    }
+
     @Data
     @AllArgsConstructor(staticName = "of")
     public static class PageInfo {

+ 1 - 1
src/main/java/nju/seec/helper/web/response/ResourceResponse.java → src/main/java/nju/seec/helper/controller/response/ResourceResponse.java

@@ -1,4 +1,4 @@
-package nju.seec.helper.web.response;
+package nju.seec.helper.controller.response;
 
 import lombok.Data;
 import lombok.EqualsAndHashCode;

+ 1 - 1
src/main/java/nju/seec/helper/web/response/Response.java → src/main/java/nju/seec/helper/controller/response/Response.java

@@ -1,4 +1,4 @@
-package nju.seec.helper.web.response;
+package nju.seec.helper.controller.response;
 
 import lombok.Data;
 

+ 1 - 1
src/main/java/nju/seec/helper/web/response/SuccessResponse.java → src/main/java/nju/seec/helper/controller/response/SuccessResponse.java

@@ -1,4 +1,4 @@
-package nju.seec.helper.web.response;
+package nju.seec.helper.controller.response;
 
 import lombok.Data;
 import lombok.EqualsAndHashCode;

+ 32 - 0
src/main/java/nju/seec/helper/dao/ChooseDAO.java

@@ -0,0 +1,32 @@
+package nju.seec.helper.dao;
+
+import nju.seec.helper.entity.Choose;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.Set;
+
+/**
+ * @author cst
+ */
+@Repository
+public interface ChooseDAO extends JpaRepository<Choose, Integer> {
+    /**
+     * 检查学生的选课信息是否存在
+     *
+     * @param studentId
+     * @param courseId
+     * @return
+     */
+    boolean existsByStudentIdAndCourseId(Integer studentId, Integer courseId);
+
+    /**
+     * 查询学生选课信息
+     *
+     * @param studentId
+     * @return
+     */
+    @Query("select distinct choose.courseId from Choose choose where choose.studentId=?1")
+    Set<Integer> findCourseIdsByStudentId(Integer studentId);
+}

+ 65 - 0
src/main/java/nju/seec/helper/dao/CourseDAO.java

@@ -0,0 +1,65 @@
+package nju.seec.helper.dao;
+
+import nju.seec.helper.entity.Course;
+import nju.seec.helper.util.exception.HelperException;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Set;
+
+/**
+ * @author cst
+ */
+@Repository
+public interface CourseDAO extends JpaRepository<Course, Integer> {
+    /**
+     * 封装findById
+     *
+     * @param id
+     * @return
+     */
+    default Course findCourseById(Integer id) {
+        return this.findById(id)
+                .orElseThrow(() -> HelperException.of(HelperException.ExceptionType.NOT_FOUND, "找不到课程"));
+    }
+
+    /**
+     * 检查老师是否已创建同名课程
+     *
+     * @param name
+     * @param teacherId
+     * @return
+     */
+    boolean existsByNameAndTeacherId(String name, Integer teacherId);
+
+    /**
+     * 查询老师创建的课程
+     *
+     * @param teacherId
+     * @param key
+     * @param pageable
+     * @return
+     */
+    Page<Course> findByTeacherIdAndNameContains(Integer teacherId, String key, Pageable pageable);
+
+    /**
+     * 查询课程
+     *
+     * @param key
+     * @param pageable
+     * @return
+     */
+    Page<Course> findByNameContains(String key, Pageable pageable);
+
+    /**
+     * 按ID列表查询
+     *
+     * @param courseIds
+     * @param key
+     * @param pageable
+     * @return
+     */
+    Page<Course> findByIdInAndNameContains(Set<Integer> courseIds, String key, Pageable pageable);
+}

+ 49 - 0
src/main/java/nju/seec/helper/dao/SlideDAO.java

@@ -0,0 +1,49 @@
+package nju.seec.helper.dao;
+
+import nju.seec.helper.entity.Slide;
+import nju.seec.helper.util.enums.SlideState;
+import nju.seec.helper.util.exception.HelperException;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Set;
+
+/**
+ * @author cst
+ */
+@Repository
+public interface SlideDAO extends JpaRepository<Slide, Integer> {
+    /**
+     * 封装findById
+     *
+     * @param id
+     * @return
+     */
+    default Slide findSlideById(Integer id) {
+        return this.findById(id)
+                .orElseThrow(() -> HelperException.of(HelperException.ExceptionType.NOT_FOUND, "找不到幻灯片"));
+    }
+
+    /**
+     * 查询教师创建的幻灯片
+     *
+     * @param teacherId
+     * @param key
+     * @param pageable
+     * @return
+     */
+    Page<Slide> findByTeacherIdAndNameContains(Integer teacherId, String key, Pageable pageable);
+
+    /**
+     * 根据课程和幻灯片状态查询
+     *
+     * @param courseId
+     * @param exclusiveStates
+     * @param key
+     * @param pageable
+     * @return
+     */
+    Page<Slide> findByCourseIdAndStateNotInAndNameContains(Integer courseId, Set<SlideState> exclusiveStates, String key, Pageable pageable);
+}

+ 51 - 0
src/main/java/nju/seec/helper/dao/UserDAO.java

@@ -0,0 +1,51 @@
+package nju.seec.helper.dao;
+
+import nju.seec.helper.entity.User;
+import nju.seec.helper.util.exception.HelperException;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+/**
+ * @author cst
+ */
+@Repository
+public interface UserDAO extends JpaRepository<User, Integer> {
+    /**
+     * 封装findById
+     *
+     * @param id
+     * @return
+     */
+    default User findUserById(Integer id) {
+        return this.findById(id)
+                .orElseThrow(() -> HelperException.of(HelperException.ExceptionType.NOT_FOUND, "找不到用户信息"));
+    }
+
+    /**
+     * 检查邮箱是否已存在
+     *
+     * @param email
+     * @return
+     */
+    boolean existsByEmail(String email);
+
+
+    /**
+     * 检查手机号是否已存在
+     *
+     * @param phone
+     * @return
+     */
+    boolean existsByPhone(String phone);
+
+    /**
+     * 邮箱密码匹配
+     *
+     * @param email
+     * @param password
+     * @return
+     */
+    Optional<User> findByEmailAndPassword(String email, String password);
+}

+ 0 - 24
src/main/java/nju/seec/helper/data/convert/IntMapConverter.java

@@ -1,24 +0,0 @@
-package nju.seec.helper.data.convert;
-
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-
-import javax.persistence.AttributeConverter;
-import java.util.Map;
-
-/**
- * @author cst
- */
-public class IntMapConverter implements AttributeConverter<Map<Integer, String>, String> {
-    @Override
-    public String convertToDatabaseColumn(Map<Integer, String> attribute) {
-        return new Gson().toJson(attribute);
-    }
-
-    @Override
-    public Map<Integer, String> convertToEntityAttribute(String dbData) {
-        return new Gson().fromJson(dbData,
-                new TypeToken<Map<Integer, String>>() {
-                }.getType());
-    }
-}

+ 0 - 24
src/main/java/nju/seec/helper/data/convert/MapConverter.java

@@ -1,24 +0,0 @@
-package nju.seec.helper.data.convert;
-
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-
-import javax.persistence.AttributeConverter;
-import java.util.Map;
-
-/**
- * @author cst
- */
-public class MapConverter implements AttributeConverter<Map<String, String>, String> {
-    @Override
-    public String convertToDatabaseColumn(Map<String, String> attribute) {
-        return new Gson().toJson(attribute);
-    }
-
-    @Override
-    public Map<String, String> convertToEntityAttribute(String dbData) {
-        return new Gson().fromJson(dbData,
-                new TypeToken<Map<String, String>>() {
-                }.getType());
-    }
-}

+ 0 - 24
src/main/java/nju/seec/helper/data/convert/SetConverter.java

@@ -1,24 +0,0 @@
-package nju.seec.helper.data.convert;
-
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-
-import javax.persistence.AttributeConverter;
-import java.util.Set;
-
-/**
- * @author cst
- */
-public class SetConverter implements AttributeConverter<Set<String>, String> {
-    @Override
-    public String convertToDatabaseColumn(Set<String> attribute) {
-        return new Gson().toJson(attribute);
-    }
-
-    @Override
-    public Set<String> convertToEntityAttribute(String dbData) {
-        return new Gson().fromJson(dbData,
-                new TypeToken<Set<String>>() {
-                }.getType());
-    }
-}

+ 0 - 33
src/main/java/nju/seec/helper/data/dao/CourseDAO.java

@@ -1,33 +0,0 @@
-package nju.seec.helper.data.dao;
-
-import nju.seec.helper.data.entity.Course;
-import nju.seec.helper.util.exception.HelperException;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-/**
- * @author cst
- */
-@Repository
-public interface CourseDAO extends JpaRepository<Course, Integer> {
-    /**
-     * 封装findById方法
-     *
-     * @param courseId 课程ID
-     * @return 课程
-     */
-    default Course findCourseById(Integer courseId) {
-        return this.findById(courseId).orElseThrow(() -> HelperException.of(HelperException.ExceptionType.NOT_FOUND, "找不到课程"));
-    }
-
-    /**
-     * 根据教师ID取得课程分页列表
-     *
-     * @param teacherId 教师ID
-     * @param pageable  分页
-     * @return 课程列表
-     */
-    Page<Course> findByTeacherId(Integer teacherId, Pageable pageable);
-}

+ 0 - 46
src/main/java/nju/seec/helper/data/dao/NoteDAO.java

@@ -1,46 +0,0 @@
-package nju.seec.helper.data.dao;
-
-import nju.seec.helper.data.entity.Note;
-import nju.seec.helper.util.exception.HelperException;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.stereotype.Repository;
-
-/**
- * @author cst
- */
-@Repository
-public interface NoteDAO extends JpaRepository<Note, Integer> {
-    /**
-     * 封装findById
-     *
-     * @param noteId
-     * @return
-     */
-    default Note findNoteById(Integer noteId) {
-        return findById(noteId).orElseThrow(() -> HelperException.of(HelperException.ExceptionType.NOT_FOUND, "找不到评论"));
-    }
-
-    /**
-     * 查询公开帖子
-     *
-     * @param itemId
-     * @param pageable
-     * @return
-     */
-    @Query("select n from Note n where n.itemId=?1 and n.type='PUBLIC'")
-    Page<Note> findByItemIdPublic(Integer itemId, Pageable pageable);
-
-    /**
-     * 查询私人帖子
-     *
-     * @param itemId
-     * @param userId
-     * @param pageable
-     * @return
-     */
-    @Query("select n from Note n where n.itemId=?1 and n.userId=?2 and n.type='PRIVATE'")
-    Page<Note> findByItemIdAndUserIdPrivate(Integer itemId, Integer userId, Pageable pageable);
-}

+ 0 - 32
src/main/java/nju/seec/helper/data/dao/QuestionDAO.java

@@ -1,32 +0,0 @@
-package nju.seec.helper.data.dao;
-
-import nju.seec.helper.data.entity.Question;
-import nju.seec.helper.util.exception.HelperException;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-import java.util.List;
-
-/**
- * @author cst
- */
-@Repository
-public interface QuestionDAO extends JpaRepository<Question, Integer> {
-    /**
-     * 封装findById方法
-     *
-     * @param questionId
-     * @return
-     */
-    default Question findQuestionById(int questionId) {
-        return this.findById(questionId).orElseThrow(() -> HelperException.of(HelperException.ExceptionType.NOT_FOUND, "找不到题目"));
-    }
-
-    /**
-     * 根据关键字搜索题目
-     *
-     * @param key
-     * @return
-     */
-    List<Question> findByStemContains(String key);
-}

+ 0 - 23
src/main/java/nju/seec/helper/data/dao/QuizDAO.java

@@ -1,23 +0,0 @@
-package nju.seec.helper.data.dao;
-
-import nju.seec.helper.data.entity.Quiz;
-import nju.seec.helper.util.enums.QuizType;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-import java.util.Optional;
-
-/**
- * @author cst
- */
-@Repository
-public interface QuizDAO extends JpaRepository<Quiz, Integer> {
-    /**
-     * 根据幻灯片ID和测验类型查询测验
-     *
-     * @param slideId
-     * @param type
-     * @return
-     */
-    Optional<Quiz> findBySlideIdAndType(int slideId, QuizType type);
-}

+ 0 - 80
src/main/java/nju/seec/helper/data/dao/SlideDAO.java

@@ -1,80 +0,0 @@
-package nju.seec.helper.data.dao;
-
-import nju.seec.helper.data.entity.Slide;
-import nju.seec.helper.util.enums.SlideState;
-import nju.seec.helper.util.exception.HelperException;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-import java.util.Set;
-
-/**
- * @author cst
- */
-@Repository
-public interface SlideDAO extends JpaRepository<Slide, Integer> {
-    /**
-     * 封装findById方法
-     *
-     * @param slideId 幻灯片ID
-     * @return
-     */
-    default Slide findSlideById(Integer slideId) {
-        return this.findById(slideId).orElseThrow(() -> HelperException.of(
-                HelperException.ExceptionType.NOT_FOUND, "找不到幻灯片")
-        );
-    }
-
-    /**
-     * 根据课程ID和幻灯片名是否包含关键字分页查询
-     *
-     * @param teacherId
-     * @param courseId
-     * @param key
-     * @param pageable
-     * @return
-     */
-    Page<Slide> findByTeacherIdAndCourseIdAndNameContains(Integer teacherId, Integer courseId, String key, Pageable pageable);
-
-    /**
-     * 根据幻灯片名是否包含关键字分页查询
-     *
-     * @param teacherId
-     * @param key
-     * @param pageable
-     * @return
-     */
-    Page<Slide> findByTeacherIdAndNameContains(Integer teacherId, String key, Pageable pageable);
-
-    /**
-     * 判断是否存在相同幻灯片名
-     *
-     * @param courseId
-     * @param name
-     * @return
-     */
-    boolean existsByCourseIdAndName(Integer courseId, String name);
-
-
-    /**
-     * 根据课程ID、幻灯片状态、幻灯片名是否包含关键字分页查询
-     *
-     * @param courseId
-     * @param states
-     * @param key
-     * @param pageable
-     * @return
-     */
-    Page<Slide> findByCourseIdAndStateNotInAndNameContains(Integer courseId, Set<SlideState> states, String key, Pageable pageable);
-
-    /**
-     * 根据幻灯片ID,幻灯片状态查询
-     *
-     * @param slideId
-     * @param states
-     * @return
-     */
-    Slide findByIdAndStateNotIn(Integer slideId, Set<SlideState> states);
-}

+ 0 - 20
src/main/java/nju/seec/helper/data/dao/SubmitAnswerDAO.java

@@ -1,20 +0,0 @@
-package nju.seec.helper.data.dao;
-
-import nju.seec.helper.data.entity.SubmitAnswer;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-import java.util.Optional;
-
-/**
- * @author cst
- */
-public interface SubmitAnswerDAO extends JpaRepository<SubmitAnswer, Integer> {
-    /**
-     * 根据测验ID和学生ID查询提交结果
-     *
-     * @param quizId
-     * @param studentId
-     * @return
-     */
-    Optional<SubmitAnswer> findByQuizIdAndStudentId(Integer quizId, Integer studentId);
-}

+ 0 - 25
src/main/java/nju/seec/helper/data/entity/Course.java

@@ -1,25 +0,0 @@
-package nju.seec.helper.data.entity;
-
-import lombok.Data;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-/**
- * @author cst
- */
-@Data
-@Entity
-@Table(name = "course")
-public class Course {
-    @Id
-    private Integer id;
-
-    @Column(nullable = false)
-    private String name;
-
-    @Column(nullable = false, name = "teacher_id")
-    private Integer teacherId;
-}

+ 0 - 38
src/main/java/nju/seec/helper/data/entity/Item.java

@@ -1,38 +0,0 @@
-package nju.seec.helper.data.entity;
-
-import lombok.Data;
-import nju.seec.helper.util.enums.ItemTransition;
-import nju.seec.helper.util.enums.ItemType;
-
-import javax.persistence.*;
-
-/**
- * @author cst
- */
-@Data
-@Entity
-@Table(name = "item")
-public class Item {
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Integer id;
-
-    @Column(name = "frontend_id")
-    private String frontendId;
-
-    private String placeholder;
-
-    @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
-    private ItemTransition transition = ItemTransition.NONE;
-
-    @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
-    private ItemType type = ItemType.MD;
-
-    private String content;
-
-    @ManyToOne
-    @JoinColumn(name = "slide_id")
-    private Slide slide;
-}

+ 0 - 46
src/main/java/nju/seec/helper/data/entity/Note.java

@@ -1,46 +0,0 @@
-package nju.seec.helper.data.entity;
-
-import lombok.Data;
-import nju.seec.helper.util.enums.NoteType;
-import nju.seec.helper.util.enums.UserType;
-import org.hibernate.annotations.CreationTimestamp;
-
-import javax.persistence.*;
-import java.time.LocalDateTime;
-
-/**
- * @author cst
- */
-@Data
-@Entity
-@Table(name = "note")
-public class Note {
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Integer id;
-
-    @Column(name = "item_id")
-    private Integer itemId;
-
-    @Column(name = "user_id")
-    private Integer userId;
-
-    @Column(name = "username")
-    private String username;
-
-    @Enumerated(EnumType.STRING)
-    @Column(name = "user_type")
-    private UserType userType;
-
-    @Enumerated(EnumType.STRING)
-    private NoteType type;
-
-    private String content;
-
-    @Column(name = "publish_time", updatable = false)
-    @CreationTimestamp
-    private LocalDateTime publishTime;
-
-    @Column(name = "reference_note_id")
-    private Integer referenceNoteId;
-}

+ 0 - 49
src/main/java/nju/seec/helper/data/entity/Question.java

@@ -1,49 +0,0 @@
-package nju.seec.helper.data.entity;
-
-import lombok.Data;
-import nju.seec.helper.data.convert.MapConverter;
-import nju.seec.helper.data.convert.SetConverter;
-import nju.seec.helper.util.enums.QuestionType;
-import org.hibernate.annotations.UpdateTimestamp;
-
-import javax.persistence.*;
-import java.time.LocalDateTime;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @author cst
- */
-@Data
-@Entity
-@Table(name = "question")
-public class Question {
-    @Id
-    private Integer id;
-
-    @Enumerated(EnumType.STRING)
-    private QuestionType type;
-
-    @Column(nullable = false)
-    private String stem;
-
-    @Convert(converter = MapConverter.class)
-    private Map<String, String> options;
-
-    @Convert(converter = SetConverter.class)
-    @Column(nullable = false)
-    private Set<String> tags;
-
-    @Convert(converter = SetConverter.class)
-    @Column(name = "knowledge_id", nullable = false)
-    private Set<String> knowledgeId;
-
-    @Column(name = "last_modified")
-    @UpdateTimestamp
-    private LocalDateTime lastModified;
-
-    @Column(nullable = false)
-    private String answer;
-
-    private String analysis;
-}

+ 0 - 39
src/main/java/nju/seec/helper/data/entity/Quiz.java

@@ -1,39 +0,0 @@
-package nju.seec.helper.data.entity;
-
-import lombok.Data;
-import nju.seec.helper.util.enums.QuizType;
-import org.hibernate.annotations.UpdateTimestamp;
-
-import javax.persistence.*;
-import java.time.LocalDateTime;
-import java.util.List;
-
-/**
- * @author cst
- */
-@Data
-@Entity
-@Table(name = "quiz")
-public class Quiz {
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Integer id;
-
-    @Column(name = "slide_id", nullable = false)
-    private Integer slideId;
-
-    @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
-    private QuizType type;
-
-    @ManyToMany(cascade = CascadeType.ALL)
-    @JoinTable(name = "quiz_question",
-            joinColumns = @JoinColumn(name = "quiz_id"),
-            inverseJoinColumns = @JoinColumn(name = "question_id"))
-    @OrderColumn(name = "number")
-    private List<Question> questions;
-
-    @Column(name = "update_time")
-    @UpdateTimestamp
-    private LocalDateTime updateTime;
-}

+ 0 - 38
src/main/java/nju/seec/helper/data/entity/SubmitAnswer.java

@@ -1,38 +0,0 @@
-package nju.seec.helper.data.entity;
-
-import lombok.Data;
-import nju.seec.helper.data.convert.IntMapConverter;
-import org.hibernate.annotations.UpdateTimestamp;
-
-import javax.persistence.*;
-import java.time.LocalDateTime;
-import java.util.Map;
-
-/**
- * @author cst
- */
-@Data
-@Entity
-@Table(name = "submit_answer")
-public class SubmitAnswer {
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Integer id;
-
-    @Column(name = "student_id", nullable = false)
-    private Integer studentId;
-
-    @Column(name = "quiz_id", nullable = false)
-    private Integer quizId;
-
-    @Column(name = "submit_num", nullable = false)
-    private Integer submitNum;
-
-    @Column(name = "submit_time")
-    @UpdateTimestamp
-    private LocalDateTime submitTime;
-
-    @Convert(converter = IntMapConverter.class)
-    @Column(name = "choose_options", nullable = false)
-    private Map<Integer, String> chooseOptions;
-}

+ 17 - 0
src/main/java/nju/seec/helper/dto/ChooseDTO.java

@@ -0,0 +1,17 @@
+package nju.seec.helper.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author cst
+ */
+@Data
+public class ChooseDTO {
+    @NotNull
+    private Integer courseId;
+    @NotBlank
+    private String code;
+}

+ 23 - 0
src/main/java/nju/seec/helper/dto/CourseDTO.java

@@ -0,0 +1,23 @@
+package nju.seec.helper.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author cst
+ */
+@Data
+public class CourseDTO {
+    private Integer id;
+
+    @NotBlank
+    private String name;
+    @NotNull
+    private String bio;
+    @NotBlank
+    private String code;
+
+    private String cover;
+}

+ 16 - 0
src/main/java/nju/seec/helper/dto/LoginDTO.java

@@ -0,0 +1,16 @@
+package nju.seec.helper.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author cst
+ */
+@Data
+public class LoginDTO {
+    @NotBlank
+    private String username;
+    @NotBlank
+    private String password;
+}

+ 14 - 0
src/main/java/nju/seec/helper/dto/LoginUser.java

@@ -0,0 +1,14 @@
+package nju.seec.helper.dto;
+
+import lombok.Data;
+import nju.seec.helper.util.enums.UserType;
+
+/**
+ * @author cst
+ */
+@Data
+public class LoginUser {
+    private Integer id;
+    private String name;
+    private UserType type;
+}

+ 27 - 0
src/main/java/nju/seec/helper/dto/RegisterDTO.java

@@ -0,0 +1,27 @@
+package nju.seec.helper.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author cst
+ */
+@Data
+public class RegisterDTO {
+    @NotBlank(message = "姓名不能为空")
+    private String name;
+    @Email(message = "邮箱格式不正确")
+    private String email;
+    @NotBlank
+    private String emailCode;
+    @NotBlank
+    private String phone;
+    @NotNull
+    private String phoneCode;
+
+    @NotBlank
+    private String password;
+}

+ 22 - 0
src/main/java/nju/seec/helper/dto/SlideDTO.java

@@ -0,0 +1,22 @@
+package nju.seec.helper.dto;
+
+import lombok.Data;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author cst
+ */
+@Data
+public class SlideDTO {
+    private Integer id;
+
+    @NotNull
+    private Integer courseId;
+    @NotBlank
+    private String name;
+    @NotNull
+    private MultipartFile file;
+}

+ 25 - 0
src/main/java/nju/seec/helper/entity/Choose.java

@@ -0,0 +1,25 @@
+package nju.seec.helper.entity;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import javax.persistence.*;
+
+/**
+ * @author cst
+ */
+@Data
+@Accessors(chain = true)
+@Entity
+@Table(name = "choose")
+public class Choose {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    @Column(name = "course_id", nullable = false)
+    private Integer courseId;
+
+    @Column(name = "student_id", nullable = false)
+    private Integer studentId;
+}

+ 45 - 0
src/main/java/nju/seec/helper/entity/Course.java

@@ -0,0 +1,45 @@
+package nju.seec.helper.entity;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.hibernate.annotations.CreationTimestamp;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+/**
+ * @author cst
+ */
+@Data
+@Accessors(chain = true)
+@Entity
+@Table(name = "course")
+public class Course {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    @Column(nullable = false)
+    private String name;
+
+    @Column(nullable = false)
+    private String bio;
+
+    @Column(nullable = false)
+    private String code;
+
+    private String cover;
+
+    @Column(name = "create_at", nullable = false, updatable = false)
+    @CreationTimestamp
+    private LocalDateTime createAt;
+
+    @Column(name = "teacher_id", nullable = false)
+    private Integer teacherId;
+
+    /**
+     * 冗余信息,有利于课程搜索和信息展示
+     */
+    @Column(name = "teacher_name")
+    private String teacherName;
+}

+ 23 - 0
src/main/java/nju/seec/helper/entity/Page.java

@@ -0,0 +1,23 @@
+package nju.seec.helper.entity;
+
+import lombok.Data;
+
+import javax.persistence.*;
+
+/**
+ * @author cst
+ */
+@Data
+@Entity
+@Table(name = "page")
+public class Page {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    private Integer number;
+
+    @ManyToOne
+    @JoinColumn(name = "slide_id", nullable = false)
+    private Slide slide;
+}

+ 16 - 15
src/main/java/nju/seec/helper/data/entity/Slide.java → src/main/java/nju/seec/helper/entity/Slide.java

@@ -1,19 +1,20 @@
-package nju.seec.helper.data.entity;
+package nju.seec.helper.entity;
 
 import lombok.Data;
+import lombok.experimental.Accessors;
 import nju.seec.helper.util.enums.SlideState;
 import org.hibernate.annotations.CreationTimestamp;
 import org.hibernate.annotations.UpdateTimestamp;
 
 import javax.persistence.*;
 import java.time.LocalDateTime;
-import java.util.Collections;
 import java.util.List;
 
 /**
  * @author cst
  */
 @Data
+@Accessors(chain = true)
 @Entity
 @Table(name = "slide")
 public class Slide {
@@ -21,31 +22,31 @@ public class Slide {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
-    @Column(name = "teacher_id", nullable = false)
-    private Integer teacherId;
-
     @Column(name = "course_id", nullable = false)
     private Integer courseId;
 
-    @Column(name = "course_name", nullable = false)
-    private String courseName;
+    @Column(name = "teacher_id", nullable = false)
+    private Integer teacherId;
 
     @Enumerated(EnumType.STRING)
     @Column(nullable = false)
-    private SlideState state = SlideState.DRAFT;
+    private SlideState state;
 
     @Column(nullable = false)
     private String name;
 
-    @OneToMany(mappedBy = "slide", cascade = CascadeType.ALL)
-    @OrderColumn(name = "number")
-    private List<Item> items = Collections.emptyList();
+    @Column(name = "object_name", nullable = false)
+    private String objectName;
 
-    @Column(name = "create_time", updatable = false)
+    @Column(name = "create_at", nullable = false, updatable = false)
     @CreationTimestamp
-    private LocalDateTime createTime;
+    private LocalDateTime createAt;
 
-    @Column(name = "update_time")
+    @Column(name = "update_at", nullable = false)
     @UpdateTimestamp
-    private LocalDateTime updateTime;
+    private LocalDateTime updateAt;
+
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "slide")
+    @OrderBy("number asc")
+    private List<Page> pages;
 }

+ 36 - 0
src/main/java/nju/seec/helper/entity/User.java

@@ -0,0 +1,36 @@
+package nju.seec.helper.entity;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+import nju.seec.helper.util.enums.UserType;
+
+import javax.persistence.*;
+
+/**
+ * @author cst
+ */
+@Data
+@Accessors(chain = true)
+@Entity
+@Table(name = "user")
+public class User {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    @Column(nullable = false)
+    private String name;
+
+    @Column(nullable = false, unique = true)
+    private String email;
+
+    @Enumerated(EnumType.STRING)
+    @Column(nullable = false)
+    private UserType type;
+
+    @Column(nullable = false, unique = true)
+    private String phone;
+
+    @Column(nullable = false)
+    private String password;
+}

+ 0 - 29
src/main/java/nju/seec/helper/logic/service/CourseService.java

@@ -1,29 +0,0 @@
-package nju.seec.helper.logic.service;
-
-import nju.seec.helper.logic.vo.CourseVO;
-import org.springframework.data.domain.Pageable;
-
-import java.util.List;
-
-/**
- * @author cst
- */
-public interface CourseService {
-    /**
-     * 教师获取创建的课程
-     *
-     * @param teacherId 教师ID
-     * @param pageable  分页
-     * @return List<CourseVO>
-     */
-    List<CourseVO> getTeacherCourses(Integer teacherId, Pageable pageable);
-
-    /**
-     * 学生获取所选的课程
-     *
-     * @param studentId 学生ID
-     * @param pageable  分页
-     * @return {@link CourseVO}
-     */
-    List<CourseVO> getStudentCourses(Integer studentId, Pageable pageable);
-}

+ 0 - 59
src/main/java/nju/seec/helper/logic/service/NoteService.java

@@ -1,59 +0,0 @@
-package nju.seec.helper.logic.service;
-
-import nju.seec.helper.logic.vo.NoteVO;
-import nju.seec.helper.util.enums.UserType;
-import nju.seec.helper.web.dto.NoteDTO;
-import org.springframework.data.domain.Pageable;
-
-import java.util.List;
-
-/**
- * @author cst
- */
-public interface NoteService {
-    /**
-     * 发布评论
-     *
-     * @param userId
-     * @param username
-     * @param userType
-     * @param noteDTO
-     * @return
-     */
-    NoteVO create(Integer userId, String username, UserType userType, NoteDTO noteDTO);
-
-    /**
-     * 获取公开评论
-     *
-     * @param itemId
-     * @param pageable
-     * @return
-     */
-    List<NoteVO> getPublicNotes(Integer itemId, Pageable pageable);
-
-    /**
-     * 获取私有评论
-     *
-     * @param userId
-     * @param itemId
-     * @param pageable
-     * @return
-     */
-    List<NoteVO> getPrivateNotes(Integer userId, Integer itemId, Pageable pageable);
-
-    /**
-     * 获取评论
-     *
-     * @param userId
-     * @param noteId
-     * @return
-     */
-    NoteVO getNote(Integer userId, Integer noteId);
-
-    /**
-     * 删除评论
-     *
-     * @param noteId
-     */
-    void deleteNote(Integer noteId);
-}

+ 0 - 18
src/main/java/nju/seec/helper/logic/service/QuestionService.java

@@ -1,18 +0,0 @@
-package nju.seec.helper.logic.service;
-
-import nju.seec.helper.logic.vo.QuestionVO;
-
-import java.util.List;
-
-/**
- * @author cst
- */
-public interface QuestionService {
-    /**
-     * 根据关键字获取问题
-     *
-     * @param key
-     * @return
-     */
-    List<QuestionVO> getQuestions(String key);
-}

+ 0 - 46
src/main/java/nju/seec/helper/logic/service/QuizService.java

@@ -1,46 +0,0 @@
-package nju.seec.helper.logic.service;
-
-import nju.seec.helper.logic.vo.QuizVO;
-import nju.seec.helper.logic.vo.StudentQuizVO;
-import nju.seec.helper.util.enums.QuizType;
-import nju.seec.helper.web.dto.QuizDTO;
-import nju.seec.helper.web.dto.SubmitAnswerDTO;
-
-/**
- * @author cst
- */
-public interface QuizService {
-    /**
-     * 创建幻灯片对应的测验
-     *
-     * @param quizDTO
-     * @return
-     */
-    QuizVO createQuiz(QuizDTO quizDTO);
-
-    /**
-     * 教师获取幻灯片中的测验
-     *
-     * @param slideId
-     * @param quizType
-     * @return
-     */
-    QuizVO teacherGetQuiz(int slideId, QuizType quizType);
-
-    /**
-     * 学生获取幻灯片中的测验
-     *
-     * @param slideId
-     * @param quizType
-     * @return
-     */
-    StudentQuizVO studentGetQuiz(int slideId, QuizType quizType);
-
-    /**
-     * 学生回答测验
-     *
-     * @param studentId
-     * @param submitAnswerDTO
-     */
-    void answerQuiz(Integer studentId, SubmitAnswerDTO submitAnswerDTO);
-}

+ 0 - 104
src/main/java/nju/seec/helper/logic/service/SlideService.java

@@ -1,104 +0,0 @@
-package nju.seec.helper.logic.service;
-
-import nju.seec.helper.logic.vo.SlideVO;
-import nju.seec.helper.util.enums.SlideState;
-import nju.seec.helper.web.dto.SlideDTO;
-import org.springframework.data.domain.Pageable;
-
-import java.util.List;
-
-/**
- * @author cst
- */
-public interface SlideService {
-    // 教师
-
-    /**
-     * 教师根据课程ID和关键字取得幻灯片列表
-     *
-     * @param teacherId 教师ID
-     * @param courseId  课程ID
-     * @param key       关键字
-     * @param pageable  分页
-     * @return 幻灯片列表
-     */
-    List<SlideVO> teacherGetSlides(Integer teacherId, Integer courseId, String key, Pageable pageable);
-
-    /**
-     * 教师根据关键字取得幻灯片列表
-     *
-     * @param teacherId 教师ID
-     * @param key       关键字
-     * @param pageable  分页
-     * @return 幻灯片列表
-     */
-    List<SlideVO> teacherGetSlides(Integer teacherId, String key, Pageable pageable);
-
-    /**
-     * 根据ID取得幻灯片
-     *
-     * @param teacherId 教师ID
-     * @param slideId   幻灯片ID
-     * @return {@link SlideVO}
-     */
-    SlideVO teacherGetOneSlide(Integer teacherId, Integer slideId);
-
-    /**
-     * 创建新的幻灯片
-     *
-     * @param teacherId
-     * @param slideDTO
-     * @return
-     */
-    SlideVO create(Integer teacherId, SlideDTO slideDTO);
-
-    /**
-     * 更新幻灯片
-     *
-     * @param teacherId
-     * @param slideDTO
-     * @return
-     */
-    SlideVO update(Integer teacherId, SlideDTO slideDTO);
-
-    /**
-     * 更新幻灯片状态
-     *
-     * @param teacherId
-     * @param slideId
-     * @param state
-     * @return
-     */
-    SlideVO updateState(Integer teacherId, Integer slideId, SlideState state);
-
-
-    /**
-     * 删除幻灯片
-     *
-     * @param teacherId
-     * @param slideId
-     */
-    void delete(Integer teacherId, Integer slideId);
-
-    // 学生
-
-    /**
-     * 学生根据课程ID和关键字取得幻灯片列表
-     *
-     * @param studentId
-     * @param courseId
-     * @param key
-     * @param pageable
-     * @return
-     */
-    List<SlideVO> studentGetSlides(Integer studentId, Integer courseId, String key, Pageable pageable);
-
-    /**
-     * 学生根据幻灯片ID查看幻灯片
-     *
-     * @param studentId
-     * @param slideId
-     * @return
-     */
-    SlideVO studentGetOneSlide(Integer studentId, Integer slideId);
-}

+ 0 - 40
src/main/java/nju/seec/helper/logic/service/impl/CourseServiceImpl.java

@@ -1,40 +0,0 @@
-package nju.seec.helper.logic.service.impl;
-
-import nju.seec.helper.data.dao.CourseDAO;
-import nju.seec.helper.logic.service.CourseService;
-import nju.seec.helper.logic.vo.CourseVO;
-import org.springframework.data.domain.Pageable;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author cst
- * <p> 该实现类完全基于伪造数据
- */
-@Service
-public class CourseServiceImpl implements CourseService {
-    private final CourseDAO courseDAO;
-
-    public CourseServiceImpl(CourseDAO courseDAO) {
-        this.courseDAO = courseDAO;
-    }
-
-    @Override
-    public List<CourseVO> getTeacherCourses(Integer teacherId, Pageable pageable) {
-        // TODO
-        return courseDAO
-                .findByTeacherId(teacherId, pageable)
-                .getContent()
-                .stream()
-                .map(CourseVO::new)
-                .collect(Collectors.toList());
-    }
-
-    @Override
-    public List<CourseVO> getStudentCourses(Integer studentId, Pageable pageable) {
-        // TODO
-        return getTeacherCourses(studentId, pageable);
-    }
-}

+ 0 - 81
src/main/java/nju/seec/helper/logic/service/impl/NoteServiceImpl.java

@@ -1,81 +0,0 @@
-package nju.seec.helper.logic.service.impl;
-
-import nju.seec.helper.data.dao.NoteDAO;
-import nju.seec.helper.data.entity.Note;
-import nju.seec.helper.logic.service.NoteService;
-import nju.seec.helper.logic.vo.NoteVO;
-import nju.seec.helper.util.enums.NoteType;
-import nju.seec.helper.util.enums.UserType;
-import nju.seec.helper.web.dto.NoteDTO;
-import org.springframework.data.domain.Pageable;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author cst
- */
-@Service
-public class NoteServiceImpl implements NoteService {
-    private final NoteDAO noteDAO;
-
-    public NoteServiceImpl(NoteDAO noteDAO) {
-        this.noteDAO = noteDAO;
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    @Override
-    public NoteVO create(Integer userId, String username, UserType userType, NoteDTO noteDTO) {
-        Note note = new Note();
-        note.setUserId(userId);
-        note.setUsername(username);
-        note.setUserType(userType);
-        note.setItemId(noteDTO.getItemId());
-        note.setType(noteDTO.getType());
-        note.setContent(noteDTO.getContent());
-        note.setReferenceNoteId(noteDTO.getReferenceNoteId());
-        note = noteDAO.save(note);
-        return new NoteVO(note);
-    }
-
-    @Transactional(readOnly = true)
-    @Override
-    public List<NoteVO> getPublicNotes(Integer itemId, Pageable pageable) {
-        return noteDAO
-                .findByItemIdPublic(itemId, pageable)
-                .getContent()
-                .stream()
-                .map(NoteVO::new)
-                .collect(Collectors.toList());
-    }
-
-    @Transactional(readOnly = true)
-    @Override
-    public List<NoteVO> getPrivateNotes(Integer userId, Integer itemId, Pageable pageable) {
-        return noteDAO
-                .findByItemIdAndUserIdPrivate(itemId, userId, pageable)
-                .getContent()
-                .stream()
-                .map(NoteVO::new)
-                .collect(Collectors.toList());
-    }
-
-    @Transactional(readOnly = true)
-    @Override
-    public NoteVO getNote(Integer userId, Integer noteId) {
-        Note note = noteDAO.findNoteById(noteId);
-        if (note.getType() != NoteType.PUBLIC && !note.getUserId().equals(userId)) {
-            return null;
-        } else {
-            return new NoteVO(note);
-        }
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    @Override
-    public void deleteNote(Integer noteId) {
-        noteDAO.deleteById(noteId);
-    }
-}

+ 0 - 30
src/main/java/nju/seec/helper/logic/service/impl/QuestionServiceImpl.java

@@ -1,30 +0,0 @@
-package nju.seec.helper.logic.service.impl;
-
-import nju.seec.helper.data.dao.QuestionDAO;
-import nju.seec.helper.logic.service.QuestionService;
-import nju.seec.helper.logic.vo.QuestionVO;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author cst
- */
-@Service
-public class QuestionServiceImpl implements QuestionService {
-    private final QuestionDAO questionDAO;
-
-    public QuestionServiceImpl(QuestionDAO questionDAO) {
-        this.questionDAO = questionDAO;
-    }
-
-    @Override
-    public List<QuestionVO> getQuestions(String key) {
-        return questionDAO
-                .findByStemContains(key)
-                .stream()
-                .map(QuestionVO::new)
-                .collect(Collectors.toList());
-    }
-}

+ 0 - 113
src/main/java/nju/seec/helper/logic/service/impl/QuizServiceImpl.java

@@ -1,113 +0,0 @@
-package nju.seec.helper.logic.service.impl;
-
-import nju.seec.helper.data.dao.QuestionDAO;
-import nju.seec.helper.data.dao.QuizDAO;
-import nju.seec.helper.data.dao.SlideDAO;
-import nju.seec.helper.data.dao.SubmitAnswerDAO;
-import nju.seec.helper.data.entity.Question;
-import nju.seec.helper.data.entity.Quiz;
-import nju.seec.helper.data.entity.SubmitAnswer;
-import nju.seec.helper.logic.service.QuizService;
-import nju.seec.helper.logic.vo.QuizVO;
-import nju.seec.helper.logic.vo.StudentQuizVO;
-import nju.seec.helper.util.enums.QuizType;
-import nju.seec.helper.util.exception.HelperException;
-import nju.seec.helper.web.dto.QuizDTO;
-import nju.seec.helper.web.dto.SubmitAnswerDTO;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author cst
- */
-@Service
-public class QuizServiceImpl implements QuizService {
-    private final QuestionDAO questionDAO;
-    private final SlideDAO slideDAO;
-    private final QuizDAO quizDAO;
-    private final SubmitAnswerDAO submitAnswerDAO;
-
-    public QuizServiceImpl(QuestionDAO questionDAO, SlideDAO slideDAO, QuizDAO quizDAO, SubmitAnswerDAO submitAnswerDAO) {
-        this.questionDAO = questionDAO;
-        this.slideDAO = slideDAO;
-        this.quizDAO = quizDAO;
-        this.submitAnswerDAO = submitAnswerDAO;
-    }
-
-    @Override
-    public QuizVO createQuiz(QuizDTO quizDTO) {
-        List<Question> questions = quizDTO
-                .getQuestionIds()
-                .stream()
-                .map(questionDAO::findQuestionById)
-                .collect(Collectors.toList());
-        Quiz quiz = quizDAO
-                .findBySlideIdAndType(quizDTO.getSlideId(), quizDTO.getType())
-                .orElseGet(() -> {
-                    Quiz newQuiz = new Quiz();
-                    newQuiz.setSlideId(quizDTO.getSlideId());
-                    newQuiz.setType(quizDTO.getType());
-                    return newQuiz;
-                });
-        quiz.setQuestions(questions);
-        quiz = quizDAO.save(quiz);
-        return new QuizVO(quiz);
-    }
-
-    @Override
-    public QuizVO teacherGetQuiz(int slideId, QuizType quizType) {
-        return quizDAO
-                .findBySlideIdAndType(slideId, quizType)
-                .map(QuizVO::new)
-                .orElseThrow(() -> HelperException.of(HelperException.ExceptionType.NOT_FOUND, "找不到测验"));
-    }
-
-    @Override
-    public StudentQuizVO studentGetQuiz(int slideId, QuizType quizType) {
-//        Slide slide = slideDAO.findSlideById(slideId);
-//        HelperException forbiddenException = HelperException.of(HelperException.ExceptionType.FORBIDDEN, "你暂时无权限查看该测验");
-//        switch (slide.getState()) {
-//            case DRAFT:
-//                throw forbiddenException;
-//            case BEFORE_CLASS:
-//                if (quizType != QuizType.PREVIEW) {
-//                    throw forbiddenException;
-//                }
-//                break;
-//            case IN_CLASS:
-//                if (quizType != QuizType.PREVIEW && quizType != QuizType.STUDY) {
-//                    throw forbiddenException;
-//                }
-//                break;
-//            case AFTER_CLASS:
-//                if (quizType != QuizType.PREVIEW && quizType != QuizType.STUDY && quizType != QuizType.REVIEW) {
-//                    throw forbiddenException;
-//                }
-//            default:
-//                break;
-//        }
-
-        Quiz quiz = quizDAO
-                .findBySlideIdAndType(slideId, quizType)
-                .orElseThrow(() -> HelperException.of(HelperException.ExceptionType.NOT_FOUND, "找不到测验"));
-        return submitAnswerDAO
-                .findByQuizIdAndStudentId(quiz.getId(), 1)
-                .map(submitAnswer -> new StudentQuizVO(quiz, submitAnswer))
-                .orElseGet(() -> new StudentQuizVO(quiz));
-    }
-
-    @Override
-    public void answerQuiz(Integer studentId, SubmitAnswerDTO submitAnswerDTO) {
-        SubmitAnswer submitAnswer = submitAnswerDAO
-                .findByQuizIdAndStudentId(submitAnswerDTO.getQuizId(), studentId)
-                .orElse(new SubmitAnswer());
-        Integer submitNum = submitAnswer.getSubmitNum();
-        submitAnswer.setSubmitNum((submitNum == null ? 0 : submitNum) + 1);
-        submitAnswer.setChooseOptions(submitAnswerDTO.getChooseOptions());
-        submitAnswer.setQuizId(submitAnswerDTO.getQuizId());
-        submitAnswer.setStudentId(1);
-        submitAnswerDAO.save(submitAnswer);
-    }
-}

+ 0 - 149
src/main/java/nju/seec/helper/logic/service/impl/SlideServiceImpl.java

@@ -1,149 +0,0 @@
-package nju.seec.helper.logic.service.impl;
-
-import nju.seec.helper.data.dao.CourseDAO;
-import nju.seec.helper.data.dao.SlideDAO;
-import nju.seec.helper.data.entity.Course;
-import nju.seec.helper.data.entity.Item;
-import nju.seec.helper.data.entity.Slide;
-import nju.seec.helper.logic.service.SlideService;
-import nju.seec.helper.logic.vo.SlideVO;
-import nju.seec.helper.util.enums.SlideState;
-import nju.seec.helper.util.exception.HelperException;
-import nju.seec.helper.web.dto.SlideDTO;
-import org.springframework.beans.BeanUtils;
-import org.springframework.data.domain.Pageable;
-import org.springframework.stereotype.Service;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author cst
- */
-@Service
-public class SlideServiceImpl implements SlideService {
-    private final SlideDAO slideDAO;
-    private final CourseDAO courseDAO;
-
-    public SlideServiceImpl(SlideDAO slideDAO, CourseDAO courseDAO) {
-        this.slideDAO = slideDAO;
-        this.courseDAO = courseDAO;
-    }
-
-    @Override
-    public List<SlideVO> teacherGetSlides(Integer teacherId, Integer courseId, String key, Pageable pageable) {
-        return slideDAO
-                .findByTeacherIdAndCourseIdAndNameContains(teacherId, courseId, key, pageable)
-                .getContent()
-                .stream()
-                .map(SlideVO::new)
-                .collect(Collectors.toList());
-    }
-
-    @Override
-    public List<SlideVO> teacherGetSlides(Integer teacherId, String key, Pageable pageable) {
-        return slideDAO
-                .findByTeacherIdAndNameContains(teacherId, key, pageable)
-                .getContent()
-                .stream()
-                .map(SlideVO::new)
-                .collect(Collectors.toList());
-    }
-
-    @Override
-    public SlideVO teacherGetOneSlide(Integer teacherId, Integer slideId) {
-        Slide slide = slideDAO.findSlideById(slideId);
-
-        if (!slide.getTeacherId().equals(teacherId)) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "你无权查看该幻灯片");
-        }
-        return new SlideVO(slide);
-    }
-
-    @Override
-    public SlideVO create(Integer teacherId, SlideDTO slideDTO) {
-        if (slideDAO.existsByCourseIdAndName(slideDTO.getCourseId(), slideDTO.getName())) {
-            throw HelperException.of(HelperException.ExceptionType.CONFLICT, "该幻灯片名已被使用");
-        }
-
-        Slide slide = new Slide();
-        slide.setTeacherId(teacherId);
-        slide.setName(slideDTO.getName());
-        slide.setState(SlideState.DRAFT);
-
-        Course course = courseDAO.findCourseById(slideDTO.getCourseId());
-        slide.setCourseId(course.getId());
-        slide.setCourseName(course.getName());
-        slide.setItems(Collections.emptyList());
-        slide = slideDAO.save(slide);
-        return new SlideVO(slide);
-    }
-
-    @Override
-    public SlideVO update(Integer teacherId, SlideDTO slideDTO) {
-        if (slideDAO.existsByCourseIdAndName(slideDTO.getCourseId(), slideDTO.getName())) {
-            throw HelperException.of(HelperException.ExceptionType.CONFLICT, "该幻灯片名已被使用");
-        }
-        final Slide slide = slideDAO.findSlideById(slideDTO.getId());
-        if (!slide.getTeacherId().equals(teacherId)) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "你无权修改该幻灯片");
-        }
-        slide.setState(slideDTO.getState());
-        slide.setName(slideDTO.getName());
-        slide.setItems(
-                slideDTO
-                        .getItems()
-                        .stream()
-                        .map(itemDTO -> {
-                            Item item = new Item();
-                            BeanUtils.copyProperties(itemDTO, item);
-                            item.setSlide(slide);
-                            return item;
-                        })
-                        .collect(Collectors.toList())
-        );
-        return new SlideVO(slideDAO.save(slide));
-    }
-
-    @Override
-    public SlideVO updateState(Integer teacherId, Integer slideId, SlideState state) {
-        Slide slide = slideDAO.findSlideById(slideId);
-        if (!slide.getTeacherId().equals(teacherId)) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "你无权修改该幻灯片");
-        }
-        slide.setState(state);
-        slide = slideDAO.save(slide);
-        return new SlideVO(slide);
-    }
-
-    @Override
-    public void delete(Integer teacherId, Integer slideId) {
-        Slide slide = slideDAO.findSlideById(slideId);
-        if (!slide.getTeacherId().equals(teacherId)) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "你无权删除该幻灯片");
-        }
-        slideDAO.deleteById(slideId);
-    }
-
-    @Override
-    public List<SlideVO> studentGetSlides(Integer studentId, Integer courseId, String key, Pageable pageable) {
-        return slideDAO
-                .findByCourseIdAndStateNotInAndNameContains(courseId, Collections.singleton(SlideState.DRAFT), key, pageable)
-                .getContent()
-                .stream()
-                .map(SlideVO::new)
-                .collect(Collectors.toList());
-    }
-
-    @Override
-    public SlideVO studentGetOneSlide(Integer studentId, Integer slideId) {
-        Slide slide = slideDAO.findByIdAndStateNotIn(slideId, Collections.singleton(SlideState.DRAFT));
-
-        if (slide == null) {
-            throw HelperException.of(HelperException.ExceptionType.NOT_FOUND, "找不到幻灯片");
-        } else {
-            return new SlideVO(slide);
-        }
-    }
-}

+ 0 - 18
src/main/java/nju/seec/helper/logic/vo/CourseVO.java

@@ -1,18 +0,0 @@
-package nju.seec.helper.logic.vo;
-
-import lombok.Data;
-import nju.seec.helper.data.entity.Course;
-
-/**
- * @author cst
- */
-@Data
-public class CourseVO {
-    private Integer id;
-    private String name;
-
-    public CourseVO(Course course) {
-        this.id = course.getId();
-        this.name = course.getName();
-    }
-}

+ 0 - 28
src/main/java/nju/seec/helper/logic/vo/ItemVO.java

@@ -1,28 +0,0 @@
-package nju.seec.helper.logic.vo;
-
-import lombok.Data;
-import nju.seec.helper.data.entity.Item;
-import nju.seec.helper.util.enums.ItemTransition;
-import nju.seec.helper.util.enums.ItemType;
-
-/**
- * @author cst
- */
-@Data
-public class ItemVO {
-    private Integer id;
-    private String frontendId;
-    private String placeholder;
-    private ItemTransition transition;
-    private ItemType type;
-    private String content;
-
-    public ItemVO(Item item) {
-        this.id = item.getId();
-        this.frontendId = item.getFrontendId();
-        this.placeholder = item.getPlaceholder();
-        this.transition = item.getTransition();
-        this.type = item.getType();
-        this.content = item.getContent();
-    }
-}

+ 0 - 33
src/main/java/nju/seec/helper/logic/vo/NoAnswerQuestionVO.java

@@ -1,33 +0,0 @@
-package nju.seec.helper.logic.vo;
-
-import lombok.Data;
-import nju.seec.helper.data.entity.Question;
-import nju.seec.helper.util.enums.QuestionType;
-
-import java.time.LocalDateTime;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @author cst
- */
-@Data
-public class NoAnswerQuestionVO {
-    private Integer id;
-    private QuestionType type;
-    private String stem;
-    private Map<String, String> options;
-    private Set<String> tags;
-    private Set<String> knowledgeId;
-    private LocalDateTime lastModified;
-
-    public NoAnswerQuestionVO(Question question) {
-        this.id = question.getId();
-        this.type = question.getType();
-        this.stem = question.getStem();
-        this.options = question.getOptions();
-        this.tags = question.getTags();
-        this.knowledgeId = question.getKnowledgeId();
-        this.lastModified = question.getLastModified();
-    }
-}

+ 0 - 36
src/main/java/nju/seec/helper/logic/vo/NoteVO.java

@@ -1,36 +0,0 @@
-package nju.seec.helper.logic.vo;
-
-import lombok.Data;
-import nju.seec.helper.data.entity.Note;
-import nju.seec.helper.util.enums.NoteType;
-import nju.seec.helper.util.enums.UserType;
-
-import java.time.LocalDateTime;
-
-/**
- * @author cst
- */
-@Data
-public class NoteVO {
-    private Integer id;
-    private Integer itemId;
-    private Integer userId;
-    private String username;
-    private UserType userType;
-    private String content;
-    private NoteType type;
-    private LocalDateTime publishTime;
-    private Integer referenceNoteId;
-
-    public NoteVO(Note note) {
-        this.id = note.getId();
-        this.itemId = note.getItemId();
-        this.userId = note.getUserId();
-        this.username = note.getUsername();
-        this.userType = note.getUserType();
-        this.content = note.getContent();
-        this.type = note.getType();
-        this.publishTime = note.getPublishTime();
-        this.referenceNoteId = note.getReferenceNoteId();
-    }
-}

+ 0 - 37
src/main/java/nju/seec/helper/logic/vo/QuestionVO.java

@@ -1,37 +0,0 @@
-package nju.seec.helper.logic.vo;
-
-import lombok.Data;
-import nju.seec.helper.data.entity.Question;
-import nju.seec.helper.util.enums.QuestionType;
-
-import java.time.LocalDateTime;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @author cst
- */
-@Data
-public class QuestionVO {
-    private Integer id;
-    private QuestionType type;
-    private String stem;
-    private Map<String, String> options;
-    private Set<String> tags;
-    private Set<String> knowledgeId;
-    private LocalDateTime lastModified;
-    private String answer;
-    private String analysis;
-
-    public QuestionVO(Question question) {
-        this.id = question.getId();
-        this.type = question.getType();
-        this.stem = question.getStem();
-        this.options = question.getOptions();
-        this.tags = question.getTags();
-        this.knowledgeId = question.getKnowledgeId();
-        this.lastModified = question.getLastModified();
-        this.answer = question.getAnswer();
-        this.analysis = question.getAnalysis();
-    }
-}

+ 0 - 33
src/main/java/nju/seec/helper/logic/vo/QuizVO.java

@@ -1,33 +0,0 @@
-package nju.seec.helper.logic.vo;
-
-import lombok.Data;
-import nju.seec.helper.data.entity.Quiz;
-import nju.seec.helper.util.enums.QuizType;
-
-import java.time.LocalDateTime;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author cst
- */
-@Data
-public class QuizVO {
-    private Integer id;
-    private Integer slideId;
-    private List<QuestionVO> questions;
-    private QuizType type;
-    private LocalDateTime updateTime;
-
-    public QuizVO(Quiz quiz) {
-        this.id = quiz.getId();
-        this.slideId = quiz.getSlideId();
-        this.type = quiz.getType();
-        this.updateTime = quiz.getUpdateTime();
-        this.questions = quiz
-                .getQuestions()
-                .stream()
-                .map(QuestionVO::new)
-                .collect(Collectors.toList());
-    }
-}

+ 0 - 40
src/main/java/nju/seec/helper/logic/vo/SlideVO.java

@@ -1,40 +0,0 @@
-package nju.seec.helper.logic.vo;
-
-import lombok.Data;
-import nju.seec.helper.data.entity.Slide;
-import nju.seec.helper.util.enums.SlideState;
-
-import java.time.LocalDateTime;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author cst
- */
-@Data
-public class SlideVO {
-    private Integer id;
-    private Integer courseId;
-    private String courseName;
-    private SlideState state;
-    private String name;
-    private List<ItemVO> items;
-    private LocalDateTime createTime;
-    private LocalDateTime updateTime;
-
-    public SlideVO(Slide slide) {
-        this.id = slide.getId();
-        this.courseId = slide.getCourseId();
-        this.courseName = slide.getCourseName();
-        this.state = slide.getState();
-        this.name = slide.getName();
-        this.createTime = slide.getCreateTime();
-        this.updateTime = slide.getUpdateTime();
-        this.items = slide
-                .getItems()
-                .stream()
-                .map(ItemVO::new)
-                .collect(Collectors.toList());
-
-    }
-}

+ 0 - 69
src/main/java/nju/seec/helper/logic/vo/StudentQuizVO.java

@@ -1,69 +0,0 @@
-package nju.seec.helper.logic.vo;
-
-import lombok.Data;
-import lombok.NonNull;
-import nju.seec.helper.data.entity.Question;
-import nju.seec.helper.data.entity.Quiz;
-import nju.seec.helper.data.entity.SubmitAnswer;
-import nju.seec.helper.util.enums.QuizType;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * @author cst
- */
-@Data
-public class StudentQuizVO {
-    private Integer quizId;
-    private Integer slideId;
-    private List<NoAnswerQuestionVO> questions;
-    private QuizType type;
-
-    private SubmitAnswerVO submitAnswer;
-
-    public StudentQuizVO(Quiz quiz) {
-        this.quizId = quiz.getId();
-        this.slideId = quiz.getSlideId();
-        this.type = quiz.getType();
-        this.questions = quiz
-                .getQuestions()
-                .stream()
-                .map(NoAnswerQuestionVO::new)
-                .collect(Collectors.toList());
-        this.submitAnswer = null;
-    }
-
-    public StudentQuizVO(Quiz quiz, @NonNull SubmitAnswer submitAnswer) {
-        this.quizId = quiz.getId();
-        this.slideId = quiz.getSlideId();
-        this.type = quiz.getType();
-
-        SubmitAnswerVO submitAnswerVO = new SubmitAnswerVO();
-        submitAnswerVO.setId(submitAnswer.getId());
-        submitAnswerVO.setStudentId(submitAnswer.getStudentId());
-        submitAnswerVO.setSubmitTime(submitAnswer.getSubmitTime());
-        submitAnswerVO.setSubmitNum(submitAnswer.getSubmitNum());
-
-        List<Question> questions = quiz.getQuestions();
-        Map<Integer, String> chooseOptionsMap = submitAnswer.getChooseOptions();
-        this.questions = new ArrayList<>();
-        List<String> chooseOptions = new ArrayList<>(chooseOptionsMap.size());
-
-        int rightNum = 0;
-        for (Question question : questions) {
-            this.questions.add(new NoAnswerQuestionVO(question));
-            String chooseOption = chooseOptionsMap.get(question.getId());
-            chooseOptions.add(chooseOption);
-            if (question.getAnswer().equals(chooseOption)) {
-                rightNum++;
-            }
-        }
-        submitAnswerVO.setChooseOptions(chooseOptions);
-        submitAnswerVO.setRightNum(rightNum);
-        this.submitAnswer = submitAnswerVO;
-    }
-
-}

+ 0 - 31
src/main/java/nju/seec/helper/logic/vo/SubmitAnswerVO.java

@@ -1,31 +0,0 @@
-package nju.seec.helper.logic.vo;
-
-import lombok.Data;
-
-import java.time.LocalDateTime;
-import java.util.List;
-
-@Data
-public class SubmitAnswerVO {
-    private Integer id;
-    /**
-     * 提交学生编号
-     */
-    private Integer studentId;
-    /**
-     * 学生上次提交选项列表,与问题列表一一对应
-     */
-    private List<String> chooseOptions;
-    /**
-     * 上次提交时间
-     */
-    private LocalDateTime submitTime;
-    /**
-     * 已提交次数
-     */
-    private Integer submitNum;
-    /**
-     * 正确个数
-     */
-    private Integer rightNum;
-}

+ 20 - 0
src/main/java/nju/seec/helper/service/CodeService.java

@@ -0,0 +1,20 @@
+package nju.seec.helper.service;
+
+/**
+ * @author cst
+ */
+public interface CodeService {
+    /**
+     * 发送邮箱验证码
+     *
+     * @param email
+     */
+    void sendEmailCode(String email);
+
+    /**
+     * 发送手机验证码
+     *
+     * @param phone
+     */
+    void sendPhoneCode(String phone);
+}

+ 61 - 0
src/main/java/nju/seec/helper/service/CourseService.java

@@ -0,0 +1,61 @@
+package nju.seec.helper.service;
+
+import nju.seec.helper.dto.ChooseDTO;
+import nju.seec.helper.dto.CourseDTO;
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.vo.CourseVO;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+
+/**
+ * @author cst
+ */
+public interface CourseService {
+    /**
+     * 创建课程
+     *
+     * @param teacher
+     * @param courseDTO
+     * @return
+     */
+    CourseVO createCourse(LoginUser teacher, CourseDTO courseDTO);
+
+    /**
+     * 学生选课
+     *
+     * @param student
+     * @param chooseDTO
+     */
+    void chooseCourse(LoginUser student, ChooseDTO chooseDTO);
+
+    /**
+     * 教师获取创建课程
+     *
+     * @param teacher
+     * @param key
+     * @param pageable
+     * @return
+     */
+    List<CourseVO> teacherGetCourses(LoginUser teacher, String key, Pageable pageable);
+
+    /**
+     * 学生获取所有课程
+     *
+     * @param student
+     * @param key
+     * @param pageable
+     * @return
+     */
+    List<CourseVO> studentGetCourses(LoginUser student, String key, Pageable pageable);
+
+    /**
+     * 学生获取已选课程
+     *
+     * @param student
+     * @param key
+     * @param pageable
+     * @return
+     */
+    List<CourseVO> studentGetChooseCourses(LoginUser student, String key, Pageable pageable);
+}

+ 52 - 0
src/main/java/nju/seec/helper/service/SlideService.java

@@ -0,0 +1,52 @@
+package nju.seec.helper.service;
+
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.dto.SlideDTO;
+import nju.seec.helper.vo.SlideVO;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+
+/**
+ * @author cst
+ */
+public interface SlideService {
+    /**
+     * 创建幻灯片
+     *
+     * @param teacher
+     * @param slideDTO
+     * @return
+     */
+    SlideVO createSlide(LoginUser teacher, SlideDTO slideDTO);
+
+    /**
+     * 教师获取幻灯片
+     *
+     * @param teacher
+     * @param key
+     * @param pageable
+     * @return
+     */
+    List<SlideVO> teacherGetSlides(LoginUser teacher, String key, Pageable pageable);
+
+    /**
+     * 教师获取幻灯片
+     *
+     * @param student
+     * @param courseId
+     * @param key
+     * @param pageable
+     * @return
+     */
+    List<SlideVO> studentGetSlides(LoginUser student, Integer courseId, String key, Pageable pageable);
+
+    /**
+     * 获取幻灯片链接
+     *
+     * @param user
+     * @param slideId
+     * @return
+     */
+    String getSlideUrl(LoginUser user, Integer slideId);
+}

+ 34 - 0
src/main/java/nju/seec/helper/service/UserService.java

@@ -0,0 +1,34 @@
+package nju.seec.helper.service;
+
+import nju.seec.helper.dto.RegisterDTO;
+import nju.seec.helper.vo.UserVO;
+
+/**
+ * @author cst
+ */
+public interface UserService {
+    /**
+     * 创建用户
+     *
+     * @param registerDTO
+     * @return
+     */
+    UserVO createUser(RegisterDTO registerDTO);
+
+    /**
+     * 根据邮箱和密码匹配用户
+     *
+     * @param email
+     * @param password
+     * @return
+     */
+    UserVO getUserByEmailAndPassword(String email, String password);
+
+    /**
+     * 根据ID获取用户信息
+     *
+     * @param userId
+     * @return
+     */
+    UserVO getUserById(Integer userId);
+}

+ 51 - 0
src/main/java/nju/seec/helper/service/impl/CodeServiceImpl.java

@@ -0,0 +1,51 @@
+package nju.seec.helper.service.impl;
+
+import nju.seec.helper.service.CodeService;
+import nju.seec.helper.util.RedisUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.stereotype.Service;
+
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author cst
+ */
+@Service
+public class CodeServiceImpl implements CodeService {
+    private static final int MAIL_CODE_LIVING_MINUTES = 5;
+    @Value("${spring.mail.username}")
+    private String from;
+
+    private final JavaMailSender mailSender;
+
+    private final RedisUtils redisUtils;
+
+    public CodeServiceImpl(JavaMailSender mailSender, RedisUtils redisUtils) {
+        this.mailSender = mailSender;
+        this.redisUtils = redisUtils;
+    }
+
+    @Override
+    public void sendEmailCode(String email) {
+        String code = getSixBitsCode();
+        SimpleMailMessage mail = new SimpleMailMessage();
+        mail.setFrom(from);
+        mail.setTo(email);
+        mail.setSubject("【南京大学】");
+        mail.setText(String.format("您的验证码:%s,该验证码%d分钟内有效,请勿泄漏于他人!", code, MAIL_CODE_LIVING_MINUTES));
+        mailSender.send(mail);
+        redisUtils.set(email, code, MAIL_CODE_LIVING_MINUTES, TimeUnit.MINUTES);
+    }
+
+    private String getSixBitsCode() {
+        return String.valueOf(new Random().nextInt(900000) + 100000);
+    }
+
+    @Override
+    public void sendPhoneCode(String phone) {
+
+    }
+}

+ 103 - 0
src/main/java/nju/seec/helper/service/impl/CourseServiceImpl.java

@@ -0,0 +1,103 @@
+package nju.seec.helper.service.impl;
+
+import nju.seec.helper.dao.ChooseDAO;
+import nju.seec.helper.dao.CourseDAO;
+import nju.seec.helper.dto.ChooseDTO;
+import nju.seec.helper.dto.CourseDTO;
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.entity.Choose;
+import nju.seec.helper.entity.Course;
+import nju.seec.helper.service.CourseService;
+import nju.seec.helper.util.EncryptUtils;
+import nju.seec.helper.util.exception.HelperException;
+import nju.seec.helper.vo.CourseVO;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author cst
+ */
+@Service
+public class CourseServiceImpl implements CourseService {
+    private final CourseDAO courseDAO;
+    private final ChooseDAO chooseDAO;
+
+    public CourseServiceImpl(CourseDAO courseDAO, ChooseDAO chooseDAO) {
+        this.courseDAO = courseDAO;
+        this.chooseDAO = chooseDAO;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public CourseVO createCourse(LoginUser user, CourseDTO courseDTO) {
+        Integer teacherId = user.getId();
+        if (courseDAO.existsByNameAndTeacherId(courseDTO.getName(), teacherId)) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "该课程名已使用");
+        }
+        Course course = new Course();
+        course.setTeacherId(teacherId)
+                .setTeacherName(user.getName())
+                .setName(courseDTO.getName())
+                .setBio(courseDTO.getBio())
+                .setCode(EncryptUtils.encode(courseDTO.getCode()));
+        course = courseDAO.save(course);
+        return new CourseVO(course);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void chooseCourse(LoginUser student, ChooseDTO chooseDTO) {
+        Integer studentId = student.getId();
+        if (chooseDAO.existsByStudentIdAndCourseId(studentId, chooseDTO.getCourseId())) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您已选课");
+        }
+
+        Course course = courseDAO.findCourseById(chooseDTO.getCourseId());
+
+        if (!course.getCode().equals(EncryptUtils.encode(chooseDTO.getCode()))) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "选课码错误");
+        }
+
+        Choose choose = new Choose();
+        choose.setCourseId(chooseDTO.getCourseId())
+                .setStudentId(studentId);
+        chooseDAO.save(choose);
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public List<CourseVO> teacherGetCourses(LoginUser teacher, String key, Pageable pageable) {
+        return courseDAO
+                .findByTeacherIdAndNameContains(teacher.getId(), key, pageable)
+                .stream()
+                .map(CourseVO::new)
+                .collect(Collectors.toList());
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public List<CourseVO> studentGetCourses(LoginUser student, String key, Pageable pageable) {
+        return courseDAO
+                .findByNameContains(key, pageable)
+                .stream()
+                .map(CourseVO::new)
+                .collect(Collectors.toList());
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public List<CourseVO> studentGetChooseCourses(LoginUser student, String key, Pageable pageable) {
+        return courseDAO
+                .findByIdInAndNameContains(
+                        chooseDAO.findCourseIdsByStudentId(student.getId()),
+                        key,
+                        pageable)
+                .stream()
+                .map(CourseVO::new)
+                .collect(Collectors.toList());
+    }
+}

+ 150 - 0
src/main/java/nju/seec/helper/service/impl/SlideServiceImpl.java

@@ -0,0 +1,150 @@
+package nju.seec.helper.service.impl;
+
+import com.google.common.collect.ImmutableSet;
+import lombok.SneakyThrows;
+import nju.seec.helper.dao.ChooseDAO;
+import nju.seec.helper.dao.CourseDAO;
+import nju.seec.helper.dao.SlideDAO;
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.dto.SlideDTO;
+import nju.seec.helper.entity.Course;
+import nju.seec.helper.entity.Page;
+import nju.seec.helper.entity.Slide;
+import nju.seec.helper.service.SlideService;
+import nju.seec.helper.util.OssUtils;
+import nju.seec.helper.util.enums.SlideState;
+import nju.seec.helper.util.exception.HelperException;
+import nju.seec.helper.vo.SlideVO;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * @author cst
+ */
+@Service
+public class SlideServiceImpl implements SlideService {
+    private final CourseDAO courseDAO;
+    private final SlideDAO slideDAO;
+    private final ChooseDAO chooseDAO;
+
+    private final OssUtils ossUtils;
+
+    private final static Set<String> SLIDE_FILE_TYPE_SET = ImmutableSet.of(
+            "application/pdf"
+    );
+
+    public SlideServiceImpl(CourseDAO courseDAO, SlideDAO slideDAO, ChooseDAO chooseDAO, OssUtils ossUtils) {
+        this.courseDAO = courseDAO;
+        this.slideDAO = slideDAO;
+        this.chooseDAO = chooseDAO;
+        this.ossUtils = ossUtils;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @SneakyThrows
+    @Override
+    public SlideVO createSlide(LoginUser teacher, SlideDTO slideDTO) {
+        Course course = courseDAO.findCourseById(slideDTO.getCourseId());
+        if (!course.getTeacherId().equals(teacher.getId())) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权创建该课程的幻灯片");
+        }
+
+        Slide slide = new Slide();
+        slide.setCourseId(slideDTO.getCourseId())
+                .setTeacherId(teacher.getId())
+                .setName(slideDTO.getName())
+                .setState(SlideState.DRAFT);
+
+        // 解析文件页数
+        MultipartFile file = slideDTO.getFile();
+        int pageNum;
+        switch (Objects.requireNonNull(file.getContentType())) {
+            // pdf
+            case "application/pdf":
+                PDDocument doc = PDDocument.load(file.getInputStream());
+                pageNum = doc.getNumberOfPages();
+                break;
+            default:
+                throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "不支持的文件类型");
+        }
+
+        System.out.println(pageNum);
+
+        slide.setPages(IntStream.rangeClosed(1, pageNum)
+                .mapToObj(number -> {
+                    Page page = new Page();
+                    page.setSlide(slide);
+                    page.setNumber(number);
+                    return page;
+                })
+                .collect(Collectors.toList())
+        );
+
+        // 上传文件
+        String objectName = ossUtils.upload(file.getOriginalFilename(), file.getInputStream());
+        slide.setObjectName(objectName);
+
+        return new SlideVO(slideDAO.save(slide));
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public List<SlideVO> teacherGetSlides(LoginUser teacher, String key, Pageable pageable) {
+        return slideDAO
+                .findByTeacherIdAndNameContains(teacher.getId(), key, pageable)
+                .stream()
+                .map(SlideVO::new)
+                .collect(Collectors.toList());
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public List<SlideVO> studentGetSlides(LoginUser student, Integer courseId, String key, Pageable pageable) {
+        if (!chooseDAO.existsByStudentIdAndCourseId(student.getId(), courseId)) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "你无权查看该课程下的幻灯片");
+        }
+
+        return slideDAO
+                .findByCourseIdAndStateNotInAndNameContains(courseId, ImmutableSet.of(SlideState.DRAFT), key, pageable)
+                .stream()
+                .map(SlideVO::new)
+                .collect(Collectors.toList());
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public String getSlideUrl(LoginUser user, Integer slideId) {
+        checkDataAccessAuth(user, slideId);
+        Slide slide = slideDAO.findSlideById(slideId);
+        return ossUtils.getUrl(slide.getObjectName());
+    }
+
+    private void checkDataAccessAuth(LoginUser user, Integer slideId) {
+        HelperException forbiddenEx = HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权访问该幻灯片");
+
+        Slide slide = slideDAO.findSlideById(slideId);
+        switch (user.getType()) {
+            case TEACHER:
+                if (!slide.getTeacherId().equals(user.getId())) {
+                    throw forbiddenEx;
+                }
+                break;
+            case STUDENT:
+                if (!chooseDAO.existsByStudentIdAndCourseId(user.getId(), slide.getCourseId())) {
+                    throw forbiddenEx;
+                }
+                break;
+            default:
+                throw forbiddenEx;
+        }
+    }
+}

+ 80 - 0
src/main/java/nju/seec/helper/service/impl/UserServiceImpl.java

@@ -0,0 +1,80 @@
+package nju.seec.helper.service.impl;
+
+import com.google.common.collect.ImmutableMap;
+import nju.seec.helper.dao.UserDAO;
+import nju.seec.helper.dto.RegisterDTO;
+import nju.seec.helper.entity.User;
+import nju.seec.helper.service.UserService;
+import nju.seec.helper.util.EncryptUtils;
+import nju.seec.helper.util.RedisUtils;
+import nju.seec.helper.util.enums.UserType;
+import nju.seec.helper.util.exception.HelperException;
+import nju.seec.helper.vo.UserVO;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Map;
+
+/**
+ * @author cst
+ */
+@Service
+public class UserServiceImpl implements UserService {
+    private final RedisUtils redisUtils;
+    private final UserDAO userDAO;
+    private final static Map<String, UserType> EMAIL_SUFFIX_AND_USER_TYPE_MAP =
+            ImmutableMap.of(
+                    "smail.nju.edu.cn", UserType.STUDENT,
+                    "nju.edu.cn", UserType.TEACHER
+            );
+
+    public UserServiceImpl(UserDAO userDAO, RedisUtils redisUtils) {
+        this.userDAO = userDAO;
+        this.redisUtils = redisUtils;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public UserVO createUser(RegisterDTO registerDTO) {
+        if (userDAO.existsByEmail(registerDTO.getEmail())) {
+            throw HelperException.of(HelperException.ExceptionType.CONFLICT, "该邮箱已注册");
+        } else if (userDAO.existsByPhone(registerDTO.getPhone())) {
+            throw HelperException.of(HelperException.ExceptionType.CONFLICT, "该手机号已注册");
+        }
+
+        String email = registerDTO.getEmail();
+        if (!registerDTO.getEmailCode().equals(redisUtils.get(email))) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "邮箱验证码错误");
+        }
+
+        User user = new User();
+        user.setName(registerDTO.getName())
+                .setEmail(registerDTO.getEmail())
+                .setPhone(registerDTO.getPhone())
+                .setPassword(EncryptUtils.encode(registerDTO.getPassword()))
+                .setType(getUserType(email));
+
+        user = userDAO.save(user);
+        redisUtils.remove(email);
+        return new UserVO(user);
+    }
+
+    private UserType getUserType(String email) {
+        return EMAIL_SUFFIX_AND_USER_TYPE_MAP.get(email.substring(email.indexOf("@") + 1));
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public UserVO getUserByEmailAndPassword(String email, String password) {
+        return userDAO
+                .findByEmailAndPassword(email, EncryptUtils.encode(password))
+                .map(UserVO::new)
+                .orElseThrow(() -> HelperException.of(HelperException.ExceptionType.FORBIDDEN, "邮箱或密码错误"));
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public UserVO getUserById(Integer userId) {
+        return new UserVO(userDAO.findUserById(userId));
+    }
+}

+ 19 - 0
src/main/java/nju/seec/helper/util/EncryptUtils.java

@@ -0,0 +1,19 @@
+package nju.seec.helper.util;
+
+import lombok.experimental.UtilityClass;
+
+import java.util.Base64;
+
+/**
+ * @author cst
+ */
+@UtilityClass
+public class EncryptUtils {
+    public String encode(String string) {
+        return Base64.getEncoder().encodeToString(string.getBytes());
+    }
+
+    public String decode(String string) {
+        return new String(Base64.getDecoder().decode(string));
+    }
+}

+ 0 - 18
src/main/java/nju/seec/helper/util/FakerUtils.java

@@ -1,18 +0,0 @@
-package nju.seec.helper.util;
-
-import com.github.javafaker.Faker;
-import lombok.experimental.UtilityClass;
-
-import java.util.Locale;
-
-/**
- * @author cst
- */
-@UtilityClass
-public class FakerUtils {
-    private static final Faker FAKER = new Faker(new Locale("zh-CN"));
-
-    public Faker getFaker() {
-        return FAKER;
-    }
-}

+ 0 - 28
src/main/java/nju/seec/helper/util/HttpUtils.java

@@ -1,28 +0,0 @@
-package nju.seec.helper.util;
-
-import lombok.experimental.UtilityClass;
-import org.springframework.web.client.RestTemplate;
-
-/**
- * @author cst
- */
-@UtilityClass
-public class HttpUtils {
-    private static final RestTemplate REST_TEMPLATE = new RestTemplate();
-
-    public <T> T get(String url, Class<T> responseType, Object... uriVariables) {
-        return REST_TEMPLATE.getForObject(url, responseType, uriVariables);
-    }
-
-    public <T> T post(String url, Object request, Class<T> responseType, Object... uriVariables) {
-        return REST_TEMPLATE.postForObject(url, request, responseType, uriVariables);
-    }
-
-    public void put(String url, Object request, Object... uriVariables) {
-        REST_TEMPLATE.put(url, request, uriVariables);
-    }
-
-    public void delete(String url, Object... uriVariables) {
-        REST_TEMPLATE.delete(url, uriVariables);
-    }
-}

+ 39 - 0
src/main/java/nju/seec/helper/util/OssUtils.java

@@ -0,0 +1,39 @@
+package nju.seec.helper.util;
+
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.model.PutObjectRequest;
+import nju.seec.helper.constant.OssProperties;
+import org.springframework.stereotype.Component;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Date;
+
+/**
+ * @author cst
+ */
+@Component
+public class OssUtils {
+    private final OssProperties ossProperties;
+
+    public OssUtils(OssProperties ossProperties) {
+        this.ossProperties = ossProperties;
+    }
+
+    public String upload(String objectName, InputStream inputStream) {
+        OSS ossClient = new OSSClientBuilder().build(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
+        PutObjectRequest putObjectRequest = new PutObjectRequest(ossProperties.getBucketName(), objectName, inputStream);
+        ossClient.putObject(putObjectRequest);
+        ossClient.shutdown();
+        return objectName;
+    }
+
+    public String getUrl(String objectName) {
+        OSS ossClient = new OSSClientBuilder().build(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
+        Date expiration = new Date(System.currentTimeMillis() + ossProperties.getExpirationMinutes() * 60 * 1000);
+        URL url = ossClient.generatePresignedUrl(ossProperties.getBucketName(), objectName, expiration);
+        ossClient.shutdown();
+        return url.toString();
+    }
+}

+ 30 - 0
src/main/java/nju/seec/helper/util/RedisUtils.java

@@ -0,0 +1,30 @@
+package nju.seec.helper.util;
+
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author cst
+ */
+@Component
+public class RedisUtils {
+    private final RedisTemplate<String, String> redisTemplate;
+
+    public RedisUtils(RedisTemplate<String, String> redisTemplate) {
+        this.redisTemplate = redisTemplate;
+    }
+
+    public void set(String key, String value, long expireTime, TimeUnit timeUnit) {
+        redisTemplate.opsForValue().set(key, value, expireTime, timeUnit);
+    }
+
+    public String get(String key) {
+        return redisTemplate.opsForValue().get(key);
+    }
+
+    public void remove(String key) {
+        redisTemplate.delete(key);
+    }
+}

+ 0 - 8
src/main/java/nju/seec/helper/util/enums/ItemTransition.java

@@ -1,8 +0,0 @@
-package nju.seec.helper.util.enums;
-
-/**
- * @author cst
- */
-public enum ItemTransition {
-    NONE
-}

+ 0 - 19
src/main/java/nju/seec/helper/util/enums/ItemType.java

@@ -1,19 +0,0 @@
-package nju.seec.helper.util.enums;
-
-/**
- * @author cst
- */
-public enum ItemType {
-    /**
-     * 普通MD
-     */
-    MD,
-    /**
-     * 问题
-     */
-    QUIZ,
-    /**
-     * 分栏
-     */
-    SUBFIELD
-}

+ 0 - 8
src/main/java/nju/seec/helper/util/enums/NoteType.java

@@ -1,8 +0,0 @@
-package nju.seec.helper.util.enums;
-
-/**
- * @author cst
- */
-public enum NoteType {
-    PUBLIC, PRIVATE
-}

+ 0 - 8
src/main/java/nju/seec/helper/util/enums/QuestionType.java

@@ -1,8 +0,0 @@
-package nju.seec.helper.util.enums;
-
-/**
- * @author cst
- */
-public enum QuestionType {
-    choice
-}

+ 0 - 8
src/main/java/nju/seec/helper/util/enums/QuizType.java

@@ -1,8 +0,0 @@
-package nju.seec.helper.util.enums;
-
-/**
- * @author cst
- */
-public enum QuizType {
-    PREVIEW, STUDY, REVIEW
-}

+ 1 - 0
src/main/java/nju/seec/helper/util/enums/UserType.java

@@ -3,6 +3,7 @@ package nju.seec.helper.util.enums;
 /**
  * @author cst
  */
+
 public enum UserType {
     TEACHER, STUDENT
 }

+ 1 - 1
src/main/java/nju/seec/helper/util/exception/HelperException.java

@@ -15,7 +15,7 @@ public class HelperException extends RuntimeException {
     @Getter
     public enum ExceptionType {
         // http code
-        NOT_LOGIN(401), FORBIDDEN(403), NOT_FOUND(404), CONFLICT(409), SYSTEM_ERROR(500);
+        NOT_LOGIN(401), FORBIDDEN(403), NOT_FOUND(404), CONFLICT(409), ERROR(500);
 
         private int code;
 

+ 26 - 0
src/main/java/nju/seec/helper/vo/CourseVO.java

@@ -0,0 +1,26 @@
+package nju.seec.helper.vo;
+
+import lombok.Data;
+import nju.seec.helper.entity.Course;
+
+/**
+ * @author cst
+ */
+@Data
+public class CourseVO {
+    private Integer id;
+    private String name;
+    private String bio;
+
+    private Integer teacherId;
+    private String teacherName;
+
+    public CourseVO(Course course) {
+        this.id = course.getId();
+        this.name = course.getName();
+        this.bio = course.getBio();
+
+        this.teacherId = course.getTeacherId();
+        this.teacherName = course.getTeacherName();
+    }
+}

+ 49 - 0
src/main/java/nju/seec/helper/vo/SlideVO.java

@@ -0,0 +1,49 @@
+package nju.seec.helper.vo;
+
+import lombok.Data;
+import nju.seec.helper.entity.Page;
+import nju.seec.helper.entity.Slide;
+import nju.seec.helper.util.enums.SlideState;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author cst
+ */
+@Data
+public class SlideVO {
+    private Integer id;
+    private Integer courseId;
+    private SlideState state;
+    private String name;
+    private LocalDateTime createAt;
+    private LocalDateTime updateAt;
+    private List<PageVO> pages;
+
+    public SlideVO(Slide slide) {
+        this.id = slide.getId();
+        this.courseId = slide.getCourseId();
+        this.state = slide.getState();
+        this.name = slide.getName();
+        this.createAt = slide.getCreateAt();
+        this.updateAt = slide.getUpdateAt();
+        this.pages = slide
+                .getPages()
+                .stream()
+                .map(PageVO::new)
+                .collect(Collectors.toList());
+    }
+
+    @Data
+    static class PageVO {
+        private Integer id;
+        private Integer number;
+
+        public PageVO(Page page) {
+            this.id = page.getId();
+            this.number = page.getNumber();
+        }
+    }
+}

+ 25 - 0
src/main/java/nju/seec/helper/vo/UserVO.java

@@ -0,0 +1,25 @@
+package nju.seec.helper.vo;
+
+import lombok.Data;
+import nju.seec.helper.entity.User;
+import nju.seec.helper.util.enums.UserType;
+
+/**
+ * @author cst
+ */
+@Data
+public class UserVO {
+    private Integer id;
+    private String name;
+    private String email;
+    private String phone;
+    private UserType type;
+
+    public UserVO(User user) {
+        this.id = user.getId();
+        this.name = user.getName();
+        this.email = user.getEmail();
+        this.phone = user.getPhone();
+        this.type = user.getType();
+    }
+}

+ 0 - 43
src/main/java/nju/seec/helper/web/controller/CourseController.java

@@ -1,43 +0,0 @@
-package nju.seec.helper.web.controller;
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import nju.seec.helper.logic.service.CourseService;
-import nju.seec.helper.logic.vo.CourseVO;
-import nju.seec.helper.web.response.PageResourceResponse;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.web.PageableDefault;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * @author cst
- */
-@Api(tags = "课程")
-@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST})
-@RestController
-@RequestMapping("/api/course")
-public class CourseController {
-    private final CourseService courseService;
-
-    public CourseController(CourseService courseService) {
-        this.courseService = courseService;
-    }
-
-    @ApiOperation(value = "教师获取创建课程", notes = "支持定制化分页排序,例:?page=3&size=10&sort=id,asc&sort=name,desc,即以id正向排序再以name倒序排序,请求第3页,返回10条数据")
-    @GetMapping("/teacher")
-    public PageResourceResponse<CourseVO> teacherGetCourses(@ApiParam(hidden = true) @PageableDefault(size = Integer.MAX_VALUE) Pageable pageable) {
-        List<CourseVO> courseVOs = courseService.getTeacherCourses(1, pageable);
-        return PageResourceResponse.of(courseVOs, PageResourceResponse.PageInfo.of(pageable.getPageNumber(), courseVOs.size()));
-    }
-
-    @ApiOperation(value = "学生获取所选课程", notes = "支持定制化分页排序,例:?page=3&size=10&sort=id,asc&sort=name,desc,即以id正向排序再以name倒序排序,请求第3页,返回10条数据")
-    @GetMapping("/student")
-    public PageResourceResponse<CourseVO> studentGetCourses(@ApiParam(hidden = true) @PageableDefault(size = Integer.MAX_VALUE) Pageable pageable) {
-        List<CourseVO> courseVOs = courseService.getStudentCourses(1, pageable);
-        return PageResourceResponse.of(courseVOs, PageResourceResponse.PageInfo.of(pageable.getPageNumber(), courseVOs.size()));
-
-    }
-}

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