├── doc └── imgs │ ├── 01登录.png │ ├── 02首页.png │ ├── 03用户管理.png │ ├── 04试卷列表.png │ ├── 05试题列表.png │ ├── 06添加试题.png │ ├── 07开始考试.png │ ├── 08查看成绩.png │ └── 09技术交流.png ├── exam-ning-springcloud-auth ├── docker │ ├── stop.sh │ ├── run.sh │ ├── start.sh │ ├── Dockerfile │ └── docker-compose.yml ├── src │ └── main │ │ ├── resources │ │ ├── application.yml │ │ └── application-docker.yml │ │ └── java │ │ └── com │ │ └── ning │ │ ├── ExamNingAuthApplication.java │ │ ├── security │ │ └── CustomAuthenticationEntryPoint.java │ │ ├── config │ │ ├── redis │ │ │ └── ResourceServerRedisConfig.java │ │ ├── jwt │ │ │ ├── ResourceServerJwtConfig.java │ │ │ └── JwtConfig.java │ │ └── WebSecurityConfig.java │ │ ├── service │ │ └── UserDetailsServiceImpl.java │ │ ├── utils │ │ └── ServletUtils.java │ │ └── controller │ │ └── OauthController.java └── assembly │ └── assembly.xml ├── exam-ning-springcloud-gateway ├── docker │ ├── stop.sh │ ├── run.sh │ ├── start.sh │ ├── Dockerfile │ └── docker-compose.yml ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── ning │ │ │ ├── ExamNingGatewayApplication.java │ │ │ ├── handler │ │ │ └── SwaggerHandler.java │ │ │ └── config │ │ │ └── SwaggerProvider.java │ │ └── resources │ │ ├── application.yml │ │ └── application-docker.yml └── assembly │ └── assembly.xml ├── exam-ning-springcloud-system-exam ├── docker │ ├── stop.sh │ ├── run.sh │ ├── start.sh │ ├── Dockerfile │ └── docker-compose.yml ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── ning │ │ │ │ ├── dao │ │ │ │ ├── ExamTestPaperDao.java │ │ │ │ ├── ExamTestPaperItemDao.java │ │ │ │ ├── ExamTestPaperItemResultDao.java │ │ │ │ ├── ExamQuestionDao.java │ │ │ │ └── ExamTestPaperResultDao.java │ │ │ │ ├── common │ │ │ │ ├── mark │ │ │ │ │ ├── Check.java │ │ │ │ │ ├── CheckChoiceQuestion.java │ │ │ │ │ ├── CheckHandler.java │ │ │ │ │ ├── CheckChoiceMultiQuestion.java │ │ │ │ │ └── CheckFillBlankQuestion.java │ │ │ │ ├── model │ │ │ │ │ ├── ExamTestPaperModel.java │ │ │ │ │ └── MarkScoreModel.java │ │ │ │ ├── event │ │ │ │ │ └── MarkTestPaperStartEvent.java │ │ │ │ └── enums │ │ │ │ │ ├── ExamTestPaperTypeEnum.java │ │ │ │ │ ├── ExamTestPaperResultStatusEnum.java │ │ │ │ │ └── ExamQuestionTypeEnum.java │ │ │ │ ├── controller │ │ │ │ ├── ExamController.java │ │ │ │ ├── ExamResultController.java │ │ │ │ └── ExamQuestionController.java │ │ │ │ ├── ExamNingSystemExamApplication.java │ │ │ │ ├── security │ │ │ │ ├── CustomRestTemplateResponseErrorHandler.java │ │ │ │ ├── CustomAccessTokenConverter.java │ │ │ │ ├── CustomAccessDeniedHandler.java │ │ │ │ ├── CustomAuthenticationEntryPoint.java │ │ │ │ └── CommonUserConverter.java │ │ │ │ ├── config │ │ │ │ ├── DataSourceConfig.java │ │ │ │ └── jwt │ │ │ │ │ ├── JwtConfig.java │ │ │ │ │ └── ResourceServerJwtConfig.java │ │ │ │ ├── manager │ │ │ │ ├── ExamTestPaperItemManager.java │ │ │ │ ├── ExamTestPaperItemResultManager.java │ │ │ │ ├── ExamQuestionManager.java │ │ │ │ └── ExamTestPaperResultManager.java │ │ │ │ ├── entity │ │ │ │ ├── ExamTestPaperItem.java │ │ │ │ ├── ExamTestPaperItemResult.java │ │ │ │ ├── ExamTestPaperResult.java │ │ │ │ ├── ExamTestPaper.java │ │ │ │ └── ExamQuestion.java │ │ │ │ ├── utils │ │ │ │ ├── SecurityUtils.java │ │ │ │ └── ServletUtils.java │ │ │ │ └── generator │ │ │ │ └── ExamCodeGeneration.java │ │ └── resources │ │ │ ├── mapper │ │ │ ├── ExamTestPaperItemMapper.xml │ │ │ ├── ExamTestPaperItemResultMapper.xml │ │ │ ├── ExamTestPaperMapper.xml │ │ │ ├── ExamQuestionMapper.xml │ │ │ └── ExamTestPaperResultMapper.xml │ │ │ ├── application.yml │ │ │ └── application-docker.yml │ └── test │ │ └── java │ │ └── com │ │ └── ning │ │ └── manager │ │ └── ExamTestPaperItemManagerTest.java └── assembly │ └── assembly.xml ├── exam-ning-springcloud-system-user ├── docker │ ├── stop.sh │ ├── run.sh │ ├── start.sh │ ├── Dockerfile │ └── docker-compose.yml ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── ning │ │ │ ├── dao │ │ │ ├── UserDao.java │ │ │ ├── RoleMenuDao.java │ │ │ ├── UserRoleDao.java │ │ │ ├── MenuDao.java │ │ │ └── RoleDao.java │ │ │ ├── security │ │ │ ├── CustomRestTemplateResponseErrorHandler.java │ │ │ ├── CustomAccessTokenConverter.java │ │ │ ├── CustomAccessDeniedHandler.java │ │ │ ├── CustomAuthenticationEntryPoint.java │ │ │ └── CommonUserConverter.java │ │ │ ├── common │ │ │ └── model │ │ │ │ ├── MetaVo.java │ │ │ │ ├── TreeSelect.java │ │ │ │ └── RouterVo.java │ │ │ ├── config │ │ │ ├── DataSourceConfig.java │ │ │ └── jwt │ │ │ │ ├── JwtConfig.java │ │ │ │ └── ResourceServerJwtConfig.java │ │ │ ├── entity │ │ │ ├── RoleMenu.java │ │ │ ├── UserRole.java │ │ │ ├── Role.java │ │ │ ├── User.java │ │ │ └── Menu.java │ │ │ ├── manager │ │ │ ├── UserRoleManager.java │ │ │ ├── RoleMenuManager.java │ │ │ ├── UserManager.java │ │ │ ├── RoleManager.java │ │ │ └── MenuManager.java │ │ │ ├── handler │ │ │ └── GlobalExceptionHandler.java │ │ │ ├── ExamNingSystemUserApplication.java │ │ │ ├── utils │ │ │ ├── SecurityUtils.java │ │ │ └── ServletUtils.java │ │ │ ├── controller │ │ │ ├── IndexController.java │ │ │ ├── RoleController.java │ │ │ ├── UserController.java │ │ │ └── MenuController.java │ │ │ └── generator │ │ │ └── UserCodeGeneration.java │ │ └── resources │ │ ├── mapper │ │ ├── RoleMenuMapper.xml │ │ ├── UserRoleMapper.xml │ │ ├── UserMapper.xml │ │ ├── RoleMapper.xml │ │ └── MenuMapper.xml │ │ ├── application.yml │ │ └── application-docker.yml └── assembly │ └── assembly.xml ├── exam-ning-springcloud-api ├── src │ └── main │ │ └── java │ │ └── com │ │ └── ning │ │ ├── constant │ │ ├── ServiceNameConstants.java │ │ ├── CommonConstants.java │ │ └── Constants.java │ │ ├── factory │ │ └── user │ │ │ └── RemoteUserFallbackFactory.java │ │ ├── api │ │ └── user │ │ │ └── RemoteUserService.java │ │ ├── model │ │ ├── LoginUser.java │ │ ├── User.java │ │ └── Result.java │ │ ├── handler │ │ └── GlobalExceptionHandler.java │ │ └── exception │ │ └── BaseException.java └── pom.xml ├── .gitignore ├── LICENSE └── readme.md /doc/imgs/01登录.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzuoxin/exam-ning-springcloud-v1/HEAD/doc/imgs/01登录.png -------------------------------------------------------------------------------- /doc/imgs/02首页.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzuoxin/exam-ning-springcloud-v1/HEAD/doc/imgs/02首页.png -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/docker/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname $0` 4 | 5 | docker-compose down -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/docker/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname $0` 4 | 5 | docker-compose down -------------------------------------------------------------------------------- /doc/imgs/03用户管理.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzuoxin/exam-ning-springcloud-v1/HEAD/doc/imgs/03用户管理.png -------------------------------------------------------------------------------- /doc/imgs/04试卷列表.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzuoxin/exam-ning-springcloud-v1/HEAD/doc/imgs/04试卷列表.png -------------------------------------------------------------------------------- /doc/imgs/05试题列表.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzuoxin/exam-ning-springcloud-v1/HEAD/doc/imgs/05试题列表.png -------------------------------------------------------------------------------- /doc/imgs/06添加试题.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzuoxin/exam-ning-springcloud-v1/HEAD/doc/imgs/06添加试题.png -------------------------------------------------------------------------------- /doc/imgs/07开始考试.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzuoxin/exam-ning-springcloud-v1/HEAD/doc/imgs/07开始考试.png -------------------------------------------------------------------------------- /doc/imgs/08查看成绩.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzuoxin/exam-ning-springcloud-v1/HEAD/doc/imgs/08查看成绩.png -------------------------------------------------------------------------------- /doc/imgs/09技术交流.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ningzuoxin/exam-ning-springcloud-v1/HEAD/doc/imgs/09技术交流.png -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/docker/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname $0` 4 | 5 | docker-compose down -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/docker/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname $0` 4 | 5 | docker-compose down -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | JAR_PATH='exam-ning-springcloud-auth.jar' 3 | JVM_OPTS=" -Xmx256m -Xms256m -XX:+UseG1GC " 4 | echo "Starting the $JAR_PATH ...\c" 5 | exec java -jar $JVM_OPTS $JAR_PATH 6 | -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | JAR_PATH='exam-ning-springcloud-gateway.jar' 3 | JVM_OPTS=" -Xmx256m -Xms256m -XX:+UseG1GC " 4 | echo "Starting the $JAR_PATH ...\c" 5 | exec java -jar $JVM_OPTS $JAR_PATH 6 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | JAR_PATH='exam-ning-springcloud-system-exam.jar' 3 | JVM_OPTS=" -Xmx256m -Xms256m -XX:+UseG1GC " 4 | echo "Starting the $JAR_PATH ...\c" 5 | exec java -jar $JVM_OPTS $JAR_PATH -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | JAR_PATH='exam-ning-springcloud-system-user.jar' 3 | JVM_OPTS=" -Xmx256m -Xms256m -XX:+UseG1GC " 4 | echo "Starting the $JAR_PATH ...\c" 5 | exec java -jar $JVM_OPTS $JAR_PATH -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname $0` 4 | 5 | IMAGE=$1 6 | 7 | if [[ ! -n "${IMAGE}" ]]; then 8 | echo "IMAGE not set." 9 | exit 1 10 | fi 11 | 12 | rm -f .env 13 | echo "image=${IMAGE}" >> .env 14 | 15 | docker-compose pull 16 | docker-compose config 17 | docker-compose up -d 18 | docker-compose ps 19 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # 打包镜像命令 2 | # docker build -t exam-auth -f docker/Dockerfile . 3 | 4 | FROM openjdk:8-jdk-alpine 5 | LABEL maintainer="zuoxin.ning" 6 | WORKDIR /opt/app 7 | COPY docker/* . 8 | COPY target/exam-ning-springcloud-auth.jar . 9 | 10 | # 设置环境变量 11 | ENV SPRING_PROFILES_ACTIVE=docker 12 | 13 | CMD ["sh", "-x", "run.sh"] -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname $0` 4 | 5 | IMAGE=$1 6 | 7 | if [[ ! -n "${IMAGE}" ]]; then 8 | echo "IMAGE not set." 9 | exit 1 10 | fi 11 | 12 | rm -f .env 13 | echo "image=${IMAGE}" >> .env 14 | 15 | docker-compose pull 16 | docker-compose config 17 | docker-compose up -d 18 | docker-compose ps 19 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname $0` 4 | 5 | IMAGE=$1 6 | 7 | if [[ ! -n "${IMAGE}" ]]; then 8 | echo "IMAGE not set." 9 | exit 1 10 | fi 11 | 12 | rm -f .env 13 | echo "image=${IMAGE}" >> .env 14 | 15 | docker-compose pull 16 | docker-compose config 17 | docker-compose up -d 18 | docker-compose ps 19 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname $0` 4 | 5 | IMAGE=$1 6 | 7 | if [[ ! -n "${IMAGE}" ]]; then 8 | echo "IMAGE not set." 9 | exit 1 10 | fi 11 | 12 | rm -f .env 13 | echo "image=${IMAGE}" >> .env 14 | 15 | docker-compose pull 16 | docker-compose config 17 | docker-compose up -d 18 | docker-compose ps 19 | -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # 打包镜像命令 2 | # docker build -t exam-gateway -f docker/Dockerfile . 3 | 4 | FROM openjdk:8-jdk-alpine 5 | LABEL maintainer="zuoxin.ning" 6 | WORKDIR /opt/app 7 | COPY docker/* . 8 | COPY target/exam-ning-springcloud-gateway.jar . 9 | 10 | # 设置环境变量 11 | ENV SPRING_PROFILES_ACTIVE=docker 12 | 13 | CMD ["sh", "-x", "run.sh"] -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # 打包镜像命令 2 | # docker build -t exam-service -f docker/Dockerfile . 3 | 4 | FROM openjdk:8-jdk-alpine 5 | LABEL maintainer="zuoxin.ning" 6 | WORKDIR /opt/app 7 | COPY docker/* . 8 | COPY target/exam-ning-springcloud-system-exam.jar . 9 | 10 | # 设置环境变量 11 | ENV SPRING_PROFILES_ACTIVE=docker 12 | 13 | CMD ["sh", "-x", "run.sh"] -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # 打包镜像命令 2 | # docker build -t user-service -f docker/Dockerfile . 3 | 4 | FROM openjdk:8-jdk-alpine 5 | LABEL maintainer="zuoxin.ning" 6 | WORKDIR /opt/app 7 | COPY docker/* . 8 | COPY target/exam-ning-springcloud-system-user.jar . 9 | 10 | # 设置环境变量 11 | ENV SPRING_PROFILES_ACTIVE=docker 12 | 13 | CMD ["sh", "-x", "run.sh"] -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.User; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * 用户表 Mapper 接口 9 | *

10 | * 11 | * @author ningning 12 | * @since 2020-09-15 13 | */ 14 | public interface UserDao extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/dao/RoleMenuDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.RoleMenu; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * 角色和菜单关联表 Mapper 接口 9 | *

10 | * 11 | * @author ningning 12 | * @since 2021-06-16 13 | */ 14 | public interface RoleMenuDao extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/dao/UserRoleDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.UserRole; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * 用户和角色关联表 Mapper 接口 9 | *

10 | * 11 | * @author ningning 12 | * @since 2021-06-16 13 | */ 14 | public interface UserRoleDao extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/dao/ExamTestPaperDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.ExamTestPaper; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * 试卷表 Mapper 接口 9 | *

10 | * 11 | * @author ningning 12 | * @since 2021-06-03 13 | */ 14 | public interface ExamTestPaperDao extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/dao/ExamTestPaperItemDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.ExamTestPaperItem; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * 试卷项目表 Mapper 接口 9 | *

10 | * 11 | * @author ningning 12 | * @since 2021-05-14 13 | */ 14 | public interface ExamTestPaperItemDao extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/constant/ServiceNameConstants.java: -------------------------------------------------------------------------------- 1 | package com.ning.constant; 2 | 3 | /** 4 | * 服务名称 5 | */ 6 | public class ServiceNameConstants { 7 | 8 | /** 9 | * 用户服务的serviceid 10 | */ 11 | public static final String USER_SERVICE = "exam-ning-system-user"; 12 | 13 | /** 14 | * 考试服务的serviceid 15 | */ 16 | public static final String EXAM_SERVICE = "exam-ning-system-exam"; 17 | } 18 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/dao/ExamTestPaperItemResultDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.ExamTestPaperItemResult; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * 试卷项目结果表 Mapper 接口 9 | *

10 | * 11 | * @author ningning 12 | * @since 2021-06-01 13 | */ 14 | public interface ExamTestPaperItemResultDao extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/mark/Check.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.mark; 2 | 3 | import com.ning.entity.ExamQuestion; 4 | import com.ning.entity.ExamTestPaperItem; 5 | import com.ning.entity.ExamTestPaperItemResult; 6 | 7 | /** 8 | * 判题接口 9 | */ 10 | public interface Check { 11 | 12 | ExamTestPaperItemResult check(ExamTestPaperItemResult examTestPaperItemResult, ExamQuestion examQuestion, ExamTestPaperItem examTestPaperItem); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9527 3 | 4 | spring: 5 | application: 6 | name: exam-ning-auth 7 | cloud: 8 | nacos: 9 | discovery: 10 | server-addr: 127.0.0.1:8848 # 服务注册中心 11 | redis: 12 | host: 127.0.0.1 13 | port: 6379 14 | database: 15 15 | 16 | feign: 17 | client: 18 | config: 19 | default: 20 | connectTimeout: 30000 21 | readTimeout: 30000 22 | hystrix: 23 | enabled: false 24 | 25 | -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/src/main/java/com/ning/ExamNingGatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.ning; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.cloud.client.SpringCloudApplication; 5 | 6 | @SpringCloudApplication 7 | public class ExamNingGatewayApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ExamNingGatewayApplication.class, args); 11 | System.out.println("exam-ning-gateway start success !!!"); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/resources/application-docker.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9527 3 | 4 | spring: 5 | application: 6 | name: exam-ning-auth 7 | cloud: 8 | nacos: 9 | discovery: 10 | server-addr: host.docker.internal:8848 # 服务注册中心 11 | redis: 12 | host: host.docker.internal 13 | port: 6379 14 | database: 15 15 | 16 | feign: 17 | client: 18 | config: 19 | default: 20 | connectTimeout: 30000 21 | readTimeout: 30000 22 | hystrix: 23 | enabled: false 24 | 25 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/dao/MenuDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.Menu; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 菜单权限表 Mapper 接口 12 | *

13 | * 14 | * @author ningning 15 | * @since 2021-06-16 16 | */ 17 | public interface MenuDao extends BaseMapper { 18 | 19 | List selectMenusByUserId(@Param("userId") Long userId); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/controller/ExamController.java: -------------------------------------------------------------------------------- 1 | package com.ning.controller; 2 | 3 | import com.ning.model.Result; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | public class ExamController { 9 | 10 | @GetMapping(value = {"/", "/index"}) 11 | public Result index() { 12 | System.out.println(" ========== exam index ========== "); 13 | return Result.ok("exam index"); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/dao/RoleDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.Role; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | /** 8 | *

9 | * 角色信息表 Mapper 接口 10 | *

11 | * 12 | * @author ningning 13 | * @since 2021-06-16 14 | */ 15 | public interface RoleDao extends BaseMapper { 16 | 17 | /** 18 | * 根据用户id查询角色代码 19 | * 20 | * @param userId 21 | * @return 22 | */ 23 | String getRoleKeyByUserId(@Param("userId") Long userId); 24 | } 25 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/java/com/ning/ExamNingAuthApplication.java: -------------------------------------------------------------------------------- 1 | package com.ning; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.cloud.client.SpringCloudApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | 7 | @EnableFeignClients 8 | @SpringCloudApplication 9 | public class ExamNingAuthApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ExamNingAuthApplication.class, args); 13 | System.out.println("exam-ning-springcloud-auth start success !!!"); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/model/ExamTestPaperModel.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.model; 2 | 3 | import com.ning.entity.*; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | public class ExamTestPaperModel extends ExamTestPaper { 10 | 11 | private ExamTestPaperResult examTestPaperResult; 12 | 13 | private List examTestPaperItems; 14 | 15 | private List examQuestions; 16 | 17 | private List examTestPaperItemResults; 18 | 19 | // 考试结果次数 20 | private Integer resultTimes; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/resources/mapper/RoleMenuMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | role_id, menu_id 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/resources/mapper/UserRoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | user_id, role_id 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/ExamNingSystemExamApplication.java: -------------------------------------------------------------------------------- 1 | package com.ning; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.cloud.client.SpringCloudApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | 7 | @EnableFeignClients 8 | @SpringCloudApplication 9 | public class ExamNingSystemExamApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ExamNingSystemExamApplication.class, args); 13 | System.out.println("exam-ning-springcloud-system-exam start success !!!"); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/security/CustomRestTemplateResponseErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import org.springframework.http.client.ClientHttpResponse; 4 | import org.springframework.web.client.DefaultResponseErrorHandler; 5 | 6 | import java.io.IOException; 7 | 8 | public class CustomRestTemplateResponseErrorHandler extends DefaultResponseErrorHandler { 9 | 10 | @Override 11 | public void handleError(ClientHttpResponse response) throws IOException { 12 | if (response.getRawStatusCode() != 400) { 13 | super.handleError(response); 14 | } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/security/CustomRestTemplateResponseErrorHandler.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import org.springframework.http.client.ClientHttpResponse; 4 | import org.springframework.web.client.DefaultResponseErrorHandler; 5 | 6 | import java.io.IOException; 7 | 8 | public class CustomRestTemplateResponseErrorHandler extends DefaultResponseErrorHandler { 9 | 10 | @Override 11 | public void handleError(ClientHttpResponse response) throws IOException { 12 | if (response.getRawStatusCode() != 400) { 13 | super.handleError(response); 14 | } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/dao/ExamQuestionDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.ExamQuestion; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 考题表 Mapper 接口 12 | *

13 | * 14 | * @author ningning 15 | * @since 2021-06-04 16 | */ 17 | public interface ExamQuestionDao extends BaseMapper { 18 | 19 | /** 20 | * 批量修改题目使用数 21 | * 22 | * @param ids 23 | * @return 24 | */ 25 | Integer updateUsedNumBatchIds(@Param("ids") List ids); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/security/CustomAccessTokenConverter.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 4 | import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; 5 | 6 | import java.util.Map; 7 | 8 | public class CustomAccessTokenConverter extends DefaultAccessTokenConverter { 9 | 10 | @Override 11 | public OAuth2Authentication extractAuthentication(Map claims) { 12 | OAuth2Authentication authentication = super.extractAuthentication(claims); 13 | authentication.setDetails(claims); 14 | return authentication; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/security/CustomAccessTokenConverter.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 4 | import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; 5 | 6 | import java.util.Map; 7 | 8 | public class CustomAccessTokenConverter extends DefaultAccessTokenConverter { 9 | 10 | @Override 11 | public OAuth2Authentication extractAuthentication(Map claims) { 12 | OAuth2Authentication authentication = super.extractAuthentication(claims); 13 | authentication.setDetails(claims); 14 | return authentication; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/factory/user/RemoteUserFallbackFactory.java: -------------------------------------------------------------------------------- 1 | package com.ning.factory.user; 2 | 3 | import com.ning.api.user.RemoteUserService; 4 | import com.ning.model.Result; 5 | import feign.hystrix.FallbackFactory; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * 用户服务降级处理 11 | */ 12 | @Slf4j 13 | @Component 14 | public class RemoteUserFallbackFactory implements FallbackFactory { 15 | 16 | @Override 17 | public RemoteUserService create(Throwable throwable) { 18 | 19 | log.info(" ====== RemoteUserFallbackFactory # create ====== " + throwable.getMessage()); 20 | 21 | return username -> Result.fail(""); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | # Build Tools 3 | 4 | .gradle 5 | /build/ 6 | !gradle/wrapper/gradle-wrapper.jar 7 | 8 | target/ 9 | !.mvn/wrapper/maven-wrapper.jar 10 | 11 | ###################################################################### 12 | # IDE 13 | 14 | ### STS ### 15 | .apt_generated 16 | .classpath 17 | .factorypath 18 | .project 19 | .settings 20 | .springBeans 21 | 22 | ### IntelliJ IDEA ### 23 | .idea 24 | *.iws 25 | *.iml 26 | *.ipr 27 | 28 | ### NetBeans ### 29 | nbproject/private/ 30 | build/* 31 | nbbuild/ 32 | dist/ 33 | nbdist/ 34 | .nb-gradle/ 35 | 36 | ###################################################################### 37 | # Others 38 | *.log 39 | *.xml.versionsBackup 40 | 41 | !*/build/*.java 42 | !*/build/*.html 43 | !*/build/*.xml -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/dao/ExamTestPaperResultDao.java: -------------------------------------------------------------------------------- 1 | package com.ning.dao; 2 | 3 | import com.ning.entity.ExamTestPaperResult; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | *

12 | * 试卷结果表 Mapper 接口 13 | *

14 | * 15 | * @author ningning 16 | * @since 2021-06-01 17 | */ 18 | 19 | public interface ExamTestPaperResultDao extends BaseMapper { 20 | 21 | /** 22 | * 查询用户的考试结果次数 23 | * 24 | * @param testPaperIds 25 | * @param userId 26 | * @return 27 | */ 28 | List> selectExamResultTimes(@Param("testPaperIds") List testPaperIds, @Param("userId") Integer userId); 29 | } 30 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/api/user/RemoteUserService.java: -------------------------------------------------------------------------------- 1 | package com.ning.api.user; 2 | 3 | import com.ning.constant.ServiceNameConstants; 4 | import com.ning.factory.user.RemoteUserFallbackFactory; 5 | import com.ning.model.Result; 6 | import com.ning.model.User; 7 | import org.springframework.cloud.openfeign.FeignClient; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | 11 | @FeignClient(contextId = "remoteUserService", path = "/system", value = ServiceNameConstants.USER_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class) 12 | public interface RemoteUserService { 13 | 14 | @PostMapping(value = "/user/selectUserByUsername") 15 | Result selectUserByUsername(@RequestParam("username") String username); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/event/MarkTestPaperStartEvent.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | /** 6 | * 阅卷开始事件 7 | */ 8 | public class MarkTestPaperStartEvent extends ApplicationEvent { 9 | 10 | private static final long serialVersionUID = 1L; 11 | // 试卷结果id 12 | private Integer testPaperResultId; 13 | 14 | public MarkTestPaperStartEvent(Object source, Integer testPaperResultId) { 15 | super(source); 16 | this.testPaperResultId = testPaperResultId; 17 | } 18 | 19 | public Integer getTestPaperResultId() { 20 | return testPaperResultId; 21 | } 22 | 23 | public void setTestPaperResultId(Integer testPaperResultId) { 24 | this.testPaperResultId = testPaperResultId; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/assembly/assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | assembly 3 | 4 | dir 5 | 6 | false 7 | 8 | 9 | docker 10 | ./ 11 | 12 | run.sh 13 | 14 | 0755 15 | unix 16 | 17 | 18 | target 19 | ./ 20 | 21 | *.jar 22 | 23 | 0711 24 | 25 | 26 | -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/assembly/assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | assembly 3 | 4 | dir 5 | 6 | false 7 | 8 | 9 | docker 10 | ./ 11 | 12 | run.sh 13 | 14 | 0755 15 | unix 16 | 17 | 18 | target 19 | ./ 20 | 21 | *.jar 22 | 23 | 0711 24 | 25 | 26 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/assembly/assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | assembly 3 | 4 | dir 5 | 6 | false 7 | 8 | 9 | docker 10 | ./ 11 | 12 | run.sh 13 | 14 | 0755 15 | unix 16 | 17 | 18 | target 19 | ./ 20 | 21 | *.jar 22 | 23 | 0711 24 | 25 | 26 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/assembly/assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | assembly 3 | 4 | dir 5 | 6 | false 7 | 8 | 9 | docker 10 | ./ 11 | 12 | run.sh 13 | 14 | 0755 15 | unix 16 | 17 | 18 | target 19 | ./ 20 | 21 | *.jar 22 | 23 | 0711 24 | 25 | 26 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/common/model/MetaVo.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.model; 2 | 3 | /** 4 | * 路由显示信息 5 | * 6 | * @author ruoyi 7 | */ 8 | public class MetaVo { 9 | 10 | /** 11 | * 设置该路由在侧边栏和面包屑中展示的名字 12 | */ 13 | private String title; 14 | 15 | /** 16 | * 设置该路由的图标,对应路径src/icons/svg 17 | */ 18 | private String icon; 19 | 20 | public MetaVo() { 21 | } 22 | 23 | public MetaVo(String title, String icon) { 24 | this.title = title; 25 | this.icon = icon; 26 | } 27 | 28 | public String getTitle() { 29 | return title; 30 | } 31 | 32 | public void setTitle(String title) { 33 | this.title = title; 34 | } 35 | 36 | public String getIcon() { 37 | return icon; 38 | } 39 | 40 | public void setIcon(String icon) { 41 | this.icon = icon; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | spring: 5 | application: 6 | name: exam-ning-gateway 7 | cloud: 8 | nacos: 9 | discovery: 10 | server-addr: 127.0.0.1:8848 # 服务注册中心 11 | gateway: 12 | discovery: 13 | locator: 14 | lowerCaseServiceId: true 15 | enabled: true 16 | routes: 17 | # 认证服务 18 | - id: exam-ning-auth 19 | uri: lb://exam-ning-auth 20 | predicates: 21 | - Path=/auth/** 22 | filters: 23 | - StripPrefix=1 24 | # 考试服务 25 | - id: exam-ning-system-exam 26 | uri: lb://exam-ning-system-exam 27 | predicates: 28 | - Path=/exam/** 29 | # 用户服务 30 | - id: exam-ning-system-user 31 | uri: lb://exam-ning-system-user 32 | predicates: 33 | - Path=/system/** 34 | -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/src/main/resources/application-docker.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | spring: 5 | application: 6 | name: exam-ning-gateway 7 | cloud: 8 | nacos: 9 | discovery: 10 | server-addr: host.docker.internal:8848 # 服务注册中心 11 | gateway: 12 | discovery: 13 | locator: 14 | lowerCaseServiceId: true 15 | enabled: true 16 | routes: 17 | # 认证服务 18 | - id: exam-ning-auth 19 | uri: lb://exam-ning-auth 20 | predicates: 21 | - Path=/auth/** 22 | filters: 23 | - StripPrefix=1 24 | # 考试服务 25 | - id: exam-ning-system-exam 26 | uri: lb://exam-ning-system-exam 27 | predicates: 28 | - Path=/exam/** 29 | # 用户服务 30 | - id: exam-ning-system-user 31 | uri: lb://exam-ning-system-user 32 | predicates: 33 | - Path=/system/** 34 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/mark/CheckChoiceQuestion.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.mark; 2 | 3 | import com.ning.entity.ExamQuestion; 4 | import com.ning.entity.ExamTestPaperItem; 5 | import com.ning.entity.ExamTestPaperItemResult; 6 | 7 | /** 8 | * 判单选题和判断题 9 | */ 10 | public class CheckChoiceQuestion implements Check { 11 | 12 | @Override 13 | public ExamTestPaperItemResult check(ExamTestPaperItemResult examTestPaperItemResult, ExamQuestion examQuestion, ExamTestPaperItem examTestPaperItem) { 14 | examTestPaperItemResult.setStatus("wrong"); 15 | examTestPaperItemResult.setScore(0F); 16 | 17 | String userAnswer = examTestPaperItemResult.getAnswer(); 18 | if (examQuestion.getAnswer().equals(userAnswer)) { 19 | examTestPaperItemResult.setStatus("right"); 20 | examTestPaperItemResult.setScore(examTestPaperItem.getScore()); 21 | } 22 | return examTestPaperItemResult; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/config/DataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config; 2 | 3 | import com.baomidou.mybatisplus.annotation.DbType; 4 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 5 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; 6 | import org.mybatis.spring.annotation.MapperScan; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * 数据源相关配置 12 | */ 13 | @Configuration 14 | @MapperScan(value = "com.ning.dao") // 扫描Mapper接口 15 | public class DataSourceConfig { 16 | 17 | /** 18 | * 分页插件 19 | */ 20 | @Bean 21 | public MybatisPlusInterceptor mybatisPlusInterceptor() { 22 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); 23 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); 24 | return interceptor; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/config/DataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config; 2 | 3 | import com.baomidou.mybatisplus.annotation.DbType; 4 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 5 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; 6 | import org.mybatis.spring.annotation.MapperScan; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * 数据源相关配置 12 | */ 13 | @Configuration 14 | @MapperScan(value = "com.ning.dao") // 扫描Mapper接口 15 | public class DataSourceConfig { 16 | 17 | /** 18 | * 分页插件 19 | */ 20 | @Bean 21 | public MybatisPlusInterceptor mybatisPlusInterceptor() { 22 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); 23 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); 24 | return interceptor; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/resources/mapper/ExamTestPaperItemMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | id, test_paper_id, seq, question_id, question_type, score, miss_score 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/enums/ExamTestPaperTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.enums; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public enum ExamTestPaperTypeEnum { 9 | 10 | TRAINING("training", "日常练习"), 11 | MOCK("mock", "模拟考试"), 12 | FORMAL("formal", "正式考试"); 13 | 14 | private String type; 15 | private String title; 16 | 17 | ExamTestPaperTypeEnum(String type, String title) { 18 | this.type = type; 19 | this.title = title; 20 | } 21 | 22 | public static List> listExamTestPaperTypes() { 23 | List> types = new ArrayList<>(); 24 | for (ExamTestPaperTypeEnum value : values()) { 25 | Map map = new HashMap<>(); 26 | map.put("type", value.type); 27 | map.put("title", value.title); 28 | types.add(map); 29 | } 30 | return types; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/model/LoginUser.java: -------------------------------------------------------------------------------- 1 | package com.ning.model; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | 5 | import java.util.Collection; 6 | 7 | /** 8 | * 登录用户身份权限 9 | */ 10 | public class LoginUser extends org.springframework.security.core.userdetails.User { 11 | 12 | private static final long serialVersionUID = 1L; 13 | 14 | /** 15 | * 用户ID 16 | */ 17 | private Long userId; 18 | 19 | public LoginUser(Long userId, String username, String password, boolean enabled, boolean accountNonExpired, 20 | boolean credentialsNonExpired, boolean accountNonLocked, Collection authorities) { 21 | super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); 22 | this.userId = userId; 23 | } 24 | 25 | public Long getUserId() { 26 | return userId; 27 | } 28 | 29 | public void setUserId(Long userId) { 30 | this.userId = userId; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/model/User.java: -------------------------------------------------------------------------------- 1 | package com.ning.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.Accessors; 6 | 7 | import java.io.Serializable; 8 | import java.util.Set; 9 | 10 | /** 11 | *

12 | * 用户表 13 | *

14 | * 15 | * @author ningning 16 | * @since 2020-09-15 17 | */ 18 | @Data 19 | @EqualsAndHashCode(callSuper = false) 20 | @Accessors(chain = true) 21 | public class User implements Serializable { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | private Integer id; 26 | private String username; 27 | private String password; 28 | private String email; 29 | private String mobile; 30 | private String salt; 31 | private String nickname; 32 | private String idcard; 33 | private Integer gender; 34 | private String avatar; 35 | private Integer isDelete; 36 | private Integer createTime; 37 | private Integer updateTime; 38 | private Set roles; 39 | private Set permissions; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/security/CustomAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.ning.model.Result; 5 | import com.ning.utils.ServletUtils; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.security.access.AccessDeniedException; 8 | import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | /** 14 | * AccessDeniedHandler 该类用来统一处理 AccessDeniedException 异常 15 | */ 16 | public class CustomAccessDeniedHandler extends OAuth2AccessDeniedHandler { 17 | 18 | @Override 19 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException authException) { 20 | String msg = authException.getMessage(); 21 | Result result = Result.fail(HttpStatus.FORBIDDEN.value(), msg); 22 | result.setData(""); 23 | ServletUtils.renderString(response, JSON.toJSONString(result)); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/security/CustomAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.ning.model.Result; 5 | import com.ning.utils.ServletUtils; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.security.access.AccessDeniedException; 8 | import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | /** 14 | * AccessDeniedHandler 该类用来统一处理 AccessDeniedException 异常 15 | */ 16 | public class CustomAccessDeniedHandler extends OAuth2AccessDeniedHandler { 17 | 18 | @Override 19 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException authException) { 20 | String msg = authException.getMessage(); 21 | Result result = Result.fail(HttpStatus.FORBIDDEN.value(), msg); 22 | result.setData(""); 23 | ServletUtils.renderString(response, JSON.toJSONString(result)); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/entity/RoleMenu.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableField; 6 | 7 | import java.io.Serializable; 8 | 9 | import io.swagger.annotations.ApiModel; 10 | import io.swagger.annotations.ApiModelProperty; 11 | import lombok.Data; 12 | import lombok.EqualsAndHashCode; 13 | import lombok.experimental.Accessors; 14 | 15 | /** 16 | *

17 | * 角色和菜单关联表 18 | *

19 | * 20 | * @author ningning 21 | * @since 2021-06-16 22 | */ 23 | @Data 24 | @EqualsAndHashCode(callSuper = false) 25 | @Accessors(chain = true) 26 | @TableName("role_menu") 27 | @ApiModel(value = "RoleMenu对象", description = "角色和菜单关联表") 28 | public class RoleMenu implements Serializable { 29 | 30 | private static final long serialVersionUID = 1L; 31 | 32 | @ApiModelProperty(value = "角色ID") 33 | @TableId("role_id") 34 | private Long roleId; 35 | 36 | @ApiModelProperty(value = "菜单ID") 37 | @TableField("menu_id") 38 | private Long menuId; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/entity/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableField; 6 | 7 | import java.io.Serializable; 8 | 9 | import io.swagger.annotations.ApiModel; 10 | import io.swagger.annotations.ApiModelProperty; 11 | import lombok.Data; 12 | import lombok.EqualsAndHashCode; 13 | import lombok.experimental.Accessors; 14 | 15 | /** 16 | *

17 | * 用户和角色关联表 18 | *

19 | * 20 | * @author ningning 21 | * @since 2021-06-16 22 | */ 23 | @Data 24 | @EqualsAndHashCode(callSuper = false) 25 | @Accessors(chain = true) 26 | @TableName("user_role") 27 | @ApiModel(value = "UserRole对象", description = "用户和角色关联表") 28 | public class UserRole implements Serializable { 29 | 30 | private static final long serialVersionUID = 1L; 31 | 32 | @ApiModelProperty(value = "用户ID") 33 | @TableId("user_id") 34 | private Long userId; 35 | 36 | @ApiModelProperty(value = "角色ID") 37 | @TableField("role_id") 38 | private Long roleId; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ningzx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/java/com/ning/security/CustomAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.ning.model.Result; 5 | import com.ning.utils.ServletUtils; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.security.core.AuthenticationException; 8 | import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint; 9 | 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | 15 | public class CustomAuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint { 16 | 17 | @Override 18 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 19 | String msg = authException.getMessage(); 20 | Result result = Result.fail(HttpStatus.UNAUTHORIZED.value(), msg); 21 | result.setData(""); 22 | ServletUtils.renderString(response, JSON.toJSONString(result)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/handler/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.ning.handler; 2 | 3 | import com.ning.constant.CommonConstants; 4 | import com.ning.exception.BaseException; 5 | import com.ning.model.Result; 6 | import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | 11 | @ControllerAdvice 12 | public class GlobalExceptionHandler { 13 | 14 | @ResponseBody 15 | @ExceptionHandler(value = BaseException.class) 16 | public Result handle(BaseException e) { 17 | return Result.fail("", e.getDefaultMessage()); 18 | } 19 | 20 | @ResponseBody 21 | @ExceptionHandler(value = InvalidGrantException.class) 22 | public Result handle(InvalidGrantException e) { 23 | String msg = e.getMessage(); 24 | if (CommonConstants.BAD_CREDENTIALS.equals(msg)) { 25 | msg = CommonConstants.BAD_PASSWORD; 26 | } 27 | return Result.fail("", msg); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/constant/CommonConstants.java: -------------------------------------------------------------------------------- 1 | package com.ning.constant; 2 | 3 | /** 4 | * 公共常量 5 | */ 6 | public class CommonConstants { 7 | 8 | // client_id 9 | public static final String CLIENT_ID = "ning666888"; 10 | 11 | // client_secret 12 | public static final String CLIENT_SECRET = "888666"; 13 | 14 | // scopes 15 | public static final String SCOPES = "ningning"; 16 | 17 | // signing_key 18 | public static final String SIGNING_KEY = "ningning"; 19 | 20 | // RedisTokenStore prefix 21 | public static final String REDIS_STORE_PREFIX = "oauth:access:"; 22 | 23 | // user_id 24 | public static final String USER_ID = "user_id"; 25 | 26 | // user_name 27 | public static final String USER_NAME = "user_name"; 28 | 29 | // Bad credentials 30 | public static final String BAD_CREDENTIALS = "Bad credentials"; 31 | 32 | // Bad Password 33 | public static final String BAD_PASSWORD = "密码错误"; 34 | 35 | // Bad Token 36 | public static final String BAD_TOKEN = "令牌失效"; 37 | 38 | // Default salt 39 | public static final String DEFAULT_SALT = "123456"; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/security/CustomAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.ning.constant.CommonConstants; 5 | import com.ning.model.Result; 6 | import com.ning.utils.ServletUtils; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.security.core.AuthenticationException; 9 | import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint; 10 | 11 | import javax.servlet.ServletException; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.IOException; 15 | 16 | public class CustomAuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint { 17 | 18 | @Override 19 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 20 | Result result = Result.fail(HttpStatus.UNAUTHORIZED.value(), CommonConstants.BAD_TOKEN); 21 | result.setData(authException.getMessage()); 22 | ServletUtils.renderString(response, JSON.toJSONString(result)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/security/CustomAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.ning.constant.CommonConstants; 5 | import com.ning.model.Result; 6 | import com.ning.utils.ServletUtils; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.security.core.AuthenticationException; 9 | import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint; 10 | 11 | import javax.servlet.ServletException; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.IOException; 15 | 16 | public class CustomAuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint { 17 | 18 | @Override 19 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 20 | Result result = Result.fail(HttpStatus.UNAUTHORIZED.value(), CommonConstants.BAD_TOKEN); 21 | result.setData(authException.getMessage()); 22 | ServletUtils.renderString(response, JSON.toJSONString(result)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # docker-compose 启动命令 2 | # docker-compose -p exam-cloud -f docker/docker-compose.yml up -d 3 | services: 4 | auth: 5 | image: "exam-auth:latest" 6 | container_name: "auth-service" 7 | restart: unless-stopped 8 | ports: 9 | - "9527:9527" 10 | volumes: 11 | - "/tmp/logs/exam-ning-springcloud-auth:/opt/logs" 12 | gateway: 13 | image: "exam-gateway:latest" 14 | depends_on: 15 | - auth 16 | container_name: "gateway-service" 17 | restart: unless-stopped 18 | ports: 19 | - "8080:8080" 20 | volumes: 21 | - "/tmp/logs/exam-ning-springcloud-gateway:/opt/logs" 22 | exam: 23 | image: "exam-service:latest" 24 | depends_on: 25 | - auth 26 | - gateway 27 | container_name: "exam-service" 28 | restart: unless-stopped 29 | ports: 30 | - "9202:9202" 31 | volumes: 32 | - "/tmp/logs/exam-ning-springcloud-system-exam:/opt/logs" 33 | user: 34 | image: "user-service:latest" 35 | depends_on: 36 | - auth 37 | - gateway 38 | container_name: "user-service" 39 | restart: unless-stopped 40 | ports: 41 | - "9201:9201" 42 | volumes: 43 | - "/tmp/logs/exam-ning-springcloud-system-user:/opt/logs" -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # docker-compose 启动命令 2 | # docker-compose -p exam-cloud -f docker/docker-compose.yml up -d 3 | services: 4 | auth: 5 | image: "exam-auth:latest" 6 | container_name: "auth-service" 7 | restart: unless-stopped 8 | ports: 9 | - "9527:9527" 10 | volumes: 11 | - "/tmp/logs/exam-ning-springcloud-auth:/opt/logs" 12 | gateway: 13 | image: "exam-gateway:latest" 14 | depends_on: 15 | - auth 16 | container_name: "gateway-service" 17 | restart: unless-stopped 18 | ports: 19 | - "8080:8080" 20 | volumes: 21 | - "/tmp/logs/exam-ning-springcloud-gateway:/opt/logs" 22 | exam: 23 | image: "exam-service:latest" 24 | depends_on: 25 | - auth 26 | - gateway 27 | container_name: "exam-service" 28 | restart: unless-stopped 29 | ports: 30 | - "9202:9202" 31 | volumes: 32 | - "/tmp/logs/exam-ning-springcloud-system-exam:/opt/logs" 33 | user: 34 | image: "user-service:latest" 35 | depends_on: 36 | - auth 37 | - gateway 38 | container_name: "user-service" 39 | restart: unless-stopped 40 | ports: 41 | - "9201:9201" 42 | volumes: 43 | - "/tmp/logs/exam-ning-springcloud-system-user:/opt/logs" -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # docker-compose 启动命令 2 | # docker-compose -p exam-cloud -f docker/docker-compose.yml up -d 3 | services: 4 | auth: 5 | image: "exam-auth:latest" 6 | container_name: "auth-service" 7 | restart: unless-stopped 8 | ports: 9 | - "9527:9527" 10 | volumes: 11 | - "/tmp/logs/exam-ning-springcloud-auth:/opt/logs" 12 | gateway: 13 | image: "exam-gateway:latest" 14 | depends_on: 15 | - auth 16 | container_name: "gateway-service" 17 | restart: unless-stopped 18 | ports: 19 | - "8080:8080" 20 | volumes: 21 | - "/tmp/logs/exam-ning-springcloud-gateway:/opt/logs" 22 | exam: 23 | image: "exam-service:latest" 24 | depends_on: 25 | - auth 26 | - gateway 27 | container_name: "exam-service" 28 | restart: unless-stopped 29 | ports: 30 | - "9202:9202" 31 | volumes: 32 | - "/tmp/logs/exam-ning-springcloud-system-exam:/opt/logs" 33 | user: 34 | image: "user-service:latest" 35 | depends_on: 36 | - auth 37 | - gateway 38 | container_name: "user-service" 39 | restart: unless-stopped 40 | ports: 41 | - "9201:9201" 42 | volumes: 43 | - "/tmp/logs/exam-ning-springcloud-system-user:/opt/logs" -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # docker-compose 启动命令 2 | # docker-compose -p exam-cloud -f docker/docker-compose.yml up -d 3 | services: 4 | auth: 5 | image: "exam-auth:latest" 6 | container_name: "auth-service" 7 | restart: unless-stopped 8 | ports: 9 | - "9527:9527" 10 | volumes: 11 | - "/tmp/logs/exam-ning-springcloud-auth:/opt/logs" 12 | gateway: 13 | image: "exam-gateway:latest" 14 | depends_on: 15 | - auth 16 | container_name: "gateway-service" 17 | restart: unless-stopped 18 | ports: 19 | - "8080:8080" 20 | volumes: 21 | - "/tmp/logs/exam-ning-springcloud-gateway:/opt/logs" 22 | exam: 23 | image: "exam-service:latest" 24 | depends_on: 25 | - auth 26 | - gateway 27 | container_name: "exam-service" 28 | restart: unless-stopped 29 | ports: 30 | - "9202:9202" 31 | volumes: 32 | - "/tmp/logs/exam-ning-springcloud-system-exam:/opt/logs" 33 | user: 34 | image: "user-service:latest" 35 | depends_on: 36 | - auth 37 | - gateway 38 | container_name: "user-service" 39 | restart: unless-stopped 40 | ports: 41 | - "9201:9201" 42 | volumes: 43 | - "/tmp/logs/exam-ning-springcloud-system-user:/opt/logs" -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/resources/mapper/ExamTestPaperItemResultMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | id, testpaper_result_id, testpaper_id, testpaper_item_id, question_id, user_id, answer, status, score, teacher_say 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/manager/UserRoleManager.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 5 | import com.ning.dao.UserRoleDao; 6 | import com.ning.entity.UserRole; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.annotation.Resource; 10 | 11 | @Component 12 | public class UserRoleManager { 13 | 14 | @Resource 15 | UserRoleDao userRoleDao; 16 | 17 | public Long countByRoleId(Long roleId) { 18 | // 查询对象 19 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 20 | wrapper.eq(UserRole::getRoleId, roleId); 21 | return userRoleDao.selectCount(wrapper); 22 | } 23 | 24 | public Integer insert(UserRole userRole) { 25 | return userRoleDao.insert(userRole); 26 | } 27 | 28 | public UserRole selectOne(Long userId) { 29 | // 查询对象 30 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 31 | wrapper.eq(UserRole::getUserId, userId); 32 | return userRoleDao.selectOne(wrapper); 33 | } 34 | 35 | public Integer updateById(UserRole userRole) { 36 | return userRoleDao.updateById(userRole); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/resources/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | id, username, password, email, mobile, salt, nickname, idcard, gender, avatar, is_delete, create_time, update_time 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/manager/ExamTestPaperItemManager.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 5 | import com.ning.dao.ExamTestPaperItemDao; 6 | import com.ning.entity.ExamTestPaperItem; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.annotation.Resource; 10 | import java.util.List; 11 | 12 | @Component 13 | public class ExamTestPaperItemManager { 14 | 15 | @Resource 16 | ExamTestPaperItemDao examTestPaperItemDao; 17 | 18 | public Integer add(ExamTestPaperItem examTestPaperItem) { 19 | return examTestPaperItemDao.insert(examTestPaperItem); 20 | } 21 | 22 | /** 23 | * 根据试卷id查询试卷项目 24 | * 25 | * @param testPaperId 26 | * @return 27 | */ 28 | public List listByTestPaperId(Integer testPaperId) { 29 | // 查询对象 30 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 31 | wrapper.eq(ExamTestPaperItem::getTestPaperId, testPaperId); 32 | wrapper.orderByAsc(ExamTestPaperItem::getSeq); 33 | return examTestPaperItemDao.selectList(wrapper); 34 | } 35 | 36 | public ExamTestPaperItem selectById(Integer id) { 37 | return examTestPaperItemDao.selectById(id); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | exam-ning-springcloud-v1 8 | com.ning 9 | 1.0-SNAPSHOT 10 | 11 | 12 | exam-ning-springcloud-api 13 | 14 | 15 | 16 | 17 | cn.hutool 18 | hutool-all 19 | 20 | 21 | 22 | org.springframework.cloud 23 | spring-cloud-starter-openfeign 24 | 25 | 26 | 27 | org.projectlombok 28 | lombok 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-oauth2 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/model/MarkScoreModel.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | * 问答题打分对象 8 | */ 9 | public class MarkScoreModel implements Serializable { 10 | 11 | // 试卷结果id 12 | private Integer resultId; 13 | 14 | // 试卷打分项目 15 | private List markScoreItems; 16 | 17 | public Integer getResultId() { 18 | return resultId; 19 | } 20 | 21 | public void setResultId(Integer resultId) { 22 | this.resultId = resultId; 23 | } 24 | 25 | public List getMarkScoreItems() { 26 | return markScoreItems; 27 | } 28 | 29 | public void setMarkScoreItems(List markScoreItems) { 30 | this.markScoreItems = markScoreItems; 31 | } 32 | 33 | public static class MarkScoreItemModel implements Serializable { 34 | 35 | // 试卷结果项目id 36 | private Integer id; 37 | 38 | // 分数 39 | private Float score; 40 | 41 | public Integer getId() { 42 | return id; 43 | } 44 | 45 | public void setId(Integer id) { 46 | this.id = id; 47 | } 48 | 49 | public Float getScore() { 50 | return score; 51 | } 52 | 53 | public void setScore(Float score) { 54 | this.score = score; 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/test/java/com/ning/manager/ExamTestPaperItemManagerTest.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import com.ning.common.enums.ExamQuestionTypeEnum; 4 | import com.ning.entity.ExamTestPaperItem; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | import java.util.List; 10 | 11 | @SpringBootTest 12 | class ExamTestPaperItemManagerTest { 13 | 14 | @Autowired 15 | ExamTestPaperItemManager examTestPaperItemManager; 16 | 17 | @Test 18 | void listByTestPaperId() { 19 | List examTestPaperItems = examTestPaperItemManager.listByTestPaperId(107); 20 | examTestPaperItems.sort((t1, t2) -> { 21 | int i1 = ExamQuestionTypeEnum.getIndex(t1.getQuestionType()); 22 | int i2 = ExamQuestionTypeEnum.getIndex(t2.getQuestionType()); 23 | return i1 - i2; 24 | }); 25 | for (ExamTestPaperItem examTestPaperItem : examTestPaperItems) { 26 | System.out.println(examTestPaperItem); 27 | } 28 | } 29 | 30 | @Test 31 | void testFindAny() { 32 | List examTestPaperItems = examTestPaperItemManager.listByTestPaperId(107); 33 | ExamTestPaperItem examTestPaperItem = examTestPaperItems.stream().filter(t -> t.getId() == 1830).findAny().get(); 34 | System.out.println(examTestPaperItem); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/enums/ExamTestPaperResultStatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.enums; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * 试卷批阅状态 doing、paused、reviewing、finished 10 | */ 11 | public enum ExamTestPaperResultStatusEnum { 12 | 13 | DOING("doing", "即将开始"), 14 | PAUSED("paused", "暂停阅卷"), 15 | REVIEWING("reviewing", "批阅中"), 16 | FINISHED("finished", "阅卷结束"); 17 | 18 | private String type; 19 | private String title; 20 | 21 | ExamTestPaperResultStatusEnum(String type, String title) { 22 | this.type = type; 23 | this.title = title; 24 | } 25 | 26 | public static List> listExamTestPaperTypes() { 27 | List> types = new ArrayList<>(); 28 | for (ExamTestPaperResultStatusEnum value : values()) { 29 | Map map = new HashMap<>(); 30 | map.put("type", value.type); 31 | map.put("title", value.title); 32 | types.add(map); 33 | } 34 | return types; 35 | } 36 | 37 | public String getType() { 38 | return type; 39 | } 40 | 41 | public void setType(String type) { 42 | this.type = type; 43 | } 44 | 45 | public String getTitle() { 46 | return title; 47 | } 48 | 49 | public void setTitle(String title) { 50 | this.title = title; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/mark/CheckHandler.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.mark; 2 | 3 | import com.ning.common.enums.ExamQuestionTypeEnum; 4 | import com.ning.entity.ExamQuestion; 5 | import com.ning.entity.ExamTestPaperItem; 6 | import com.ning.entity.ExamTestPaperItemResult; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class CheckHandler { 11 | 12 | public ExamTestPaperItemResult check(ExamTestPaperItemResult examTestPaperItemResult, ExamQuestion examQuestion, ExamTestPaperItem examTestPaperItem) { 13 | if (ExamQuestionTypeEnum.CHOICE.getType().equals(examTestPaperItem.getQuestionType()) || ExamQuestionTypeEnum.TRUE_FALSE.getType().equals(examTestPaperItem.getQuestionType())) { 14 | Check check = new CheckChoiceQuestion(); 15 | return check.check(examTestPaperItemResult, examQuestion, examTestPaperItem); 16 | } 17 | 18 | if (ExamQuestionTypeEnum.CHOICE_MULTI.getType().equals(examTestPaperItem.getQuestionType())) { 19 | Check check = new CheckChoiceMultiQuestion(); 20 | return check.check(examTestPaperItemResult, examQuestion, examTestPaperItem); 21 | } 22 | 23 | if (ExamQuestionTypeEnum.FILL_BLANK.getType().equals(examTestPaperItem.getQuestionType())) { 24 | Check check = new CheckFillBlankQuestion(); 25 | return check.check(examTestPaperItemResult, examQuestion, examTestPaperItem); 26 | } 27 | 28 | return null; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/manager/ExamTestPaperItemResultManager.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 5 | import com.ning.dao.ExamTestPaperItemResultDao; 6 | import com.ning.entity.ExamTestPaperItemResult; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.annotation.Resource; 10 | import java.util.List; 11 | 12 | @Component 13 | public class ExamTestPaperItemResultManager { 14 | 15 | @Resource 16 | ExamTestPaperItemResultDao examTestPaperItemResultDao; 17 | 18 | public Integer insert(ExamTestPaperItemResult examTestPaperItemResult) { 19 | return examTestPaperItemResultDao.insert(examTestPaperItemResult); 20 | } 21 | 22 | public List selectByExamTestPaperItemResultId(Integer testPaperResultId) { 23 | // 查询对象 24 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 25 | wrapper.eq(ExamTestPaperItemResult::getTestpaperResultId, testPaperResultId); 26 | return examTestPaperItemResultDao.selectList(wrapper); 27 | } 28 | 29 | public Integer updateById(ExamTestPaperItemResult examTestPaperItemResult) { 30 | return examTestPaperItemResultDao.updateById(examTestPaperItemResult); 31 | } 32 | 33 | public ExamTestPaperItemResult selectById(Integer id) { 34 | return examTestPaperItemResultDao.selectById(id); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/resources/mapper/ExamTestPaperMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | id, type, name, limited_time, times, total_score, passed_score, item_count, copy_id, is_used, is_delete, create_user_id, create_time, update_user_id, update_time 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/manager/RoleMenuManager.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 5 | import com.ning.dao.RoleMenuDao; 6 | import com.ning.entity.RoleMenu; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.annotation.Resource; 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | @Component 14 | public class RoleMenuManager { 15 | 16 | @Resource 17 | RoleMenuDao roleMenuDao; 18 | 19 | public Integer insert(RoleMenu roleMenu) { 20 | return roleMenuDao.insert(roleMenu); 21 | } 22 | 23 | /** 24 | * 查询角色拥有的菜单id列表 25 | * 26 | * @param roleId 27 | * @return 28 | */ 29 | public List listOwnedMenuIdByRoleId(Long roleId) { 30 | // 查询对象 31 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 32 | wrapper.eq(RoleMenu::getRoleId, roleId); 33 | return roleMenuDao.selectList(wrapper).stream().map(t -> t.getMenuId()).collect(Collectors.toList()); 34 | } 35 | 36 | /** 37 | * 根据角色id删除角色菜单关联记录 38 | * 39 | * @param roleId 40 | * @return 41 | */ 42 | public Integer deleteByRoleId(Long roleId) { 43 | // 查询对象 44 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 45 | wrapper.eq(RoleMenu::getRoleId, roleId); 46 | return roleMenuDao.delete(wrapper); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/java/com/ning/config/redis/ResourceServerRedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config.redis; 2 | 3 | import com.ning.security.CustomAuthenticationEntryPoint; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 9 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 10 | 11 | /** 12 | * 认证服务,提供了用户信息,所以也是资源服务器。 13 | * 使用redis授权服务配置时,打开下面的注释。 14 | */ 15 | //@Configuration 16 | //@EnableResourceServer 17 | //@EnableGlobalMethodSecurity(prePostEnabled = true) 18 | public class ResourceServerRedisConfig extends ResourceServerConfigurerAdapter { 19 | 20 | @Override 21 | public void configure(HttpSecurity http) throws Exception { 22 | http.authorizeRequests() 23 | .antMatchers("/v2/api-docs").permitAll() 24 | .antMatchers("/oauth/user").authenticated(); // 配置oauth访问控制,必须认证后才可以访问 25 | } 26 | 27 | @Override 28 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 29 | // 处理 Invalid access token 方面异常 30 | resources.authenticationEntryPoint(new CustomAuthenticationEntryPoint()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/common/model/TreeSelect.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.ning.entity.Menu; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * Treeselect树结构实体类 12 | */ 13 | public class TreeSelect implements Serializable { 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | /** 18 | * 节点ID 19 | */ 20 | private Long id; 21 | 22 | /** 23 | * 节点名称 24 | */ 25 | private String label; 26 | 27 | /** 28 | * 子节点 29 | */ 30 | @JsonInclude(JsonInclude.Include.NON_EMPTY) 31 | private List children; 32 | 33 | public TreeSelect() { 34 | 35 | } 36 | 37 | public TreeSelect(Menu menu) { 38 | this.id = menu.getMenuId(); 39 | this.label = menu.getMenuName(); 40 | this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); 41 | } 42 | 43 | public Long getId() { 44 | return id; 45 | } 46 | 47 | public void setId(Long id) { 48 | this.id = id; 49 | } 50 | 51 | public String getLabel() { 52 | return label; 53 | } 54 | 55 | public void setLabel(String label) { 56 | this.label = label; 57 | } 58 | 59 | public List getChildren() { 60 | return children; 61 | } 62 | 63 | public void setChildren(List children) { 64 | this.children = children; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/handler/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.ning.handler; 2 | 3 | import com.ning.model.Result; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.core.annotation.Order; 6 | import org.springframework.web.bind.MethodArgumentNotValidException; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | 11 | import javax.validation.ConstraintViolationException; 12 | 13 | /** 14 | * 全局异常处理 15 | */ 16 | @Slf4j 17 | @Order(-1) 18 | @ControllerAdvice 19 | public class GlobalExceptionHandler { 20 | 21 | /** 22 | * 请求方法中校验抛出的异常 23 | * 24 | * @param e 25 | * @return 26 | */ 27 | @ResponseBody 28 | @ExceptionHandler(ConstraintViolationException.class) 29 | public Result constraintViolationExceptionHandler(ConstraintViolationException e) { 30 | // 获取异常中第一个错误信息 31 | String message = e.getConstraintViolations().iterator().next().getMessage(); 32 | return Result.fail(message); 33 | } 34 | 35 | /** 36 | * POST请求参数校验抛出的异常 37 | * 38 | * @param e 39 | * @return 40 | */ 41 | @ResponseBody 42 | @ExceptionHandler(MethodArgumentNotValidException.class) 43 | public Result methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) { 44 | // 获取异常中随机一个异常信息 45 | String message = e.getBindingResult().getFieldError().getDefaultMessage(); 46 | return Result.fail(message); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/resources/mapper/RoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | role_id, role_name, role_key, role_sort, data_scope, status, del_flag, create_by, create_time, update_by, update_time, remark 24 | 25 | 26 | 27 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/config/jwt/JwtConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config.jwt; 2 | 3 | import com.ning.constant.CommonConstants; 4 | import com.ning.security.CommonUserConverter; 5 | import com.ning.security.CustomAccessTokenConverter; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.oauth2.provider.token.TokenStore; 9 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 10 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 11 | 12 | import javax.annotation.Resource; 13 | 14 | @Configuration 15 | public class JwtConfig { 16 | 17 | @Resource 18 | JwtAccessTokenConverter jwtAccessTokenConverter; 19 | 20 | @Bean(name = "jwtTokenStore") 21 | public TokenStore tokenStore() { 22 | return new JwtTokenStore(jwtAccessTokenConverter); 23 | } 24 | 25 | /** 26 | * 可以自主选择使用非对称密钥或对称密钥进行加密,此处不设置加密。 27 | * 必须往容器中注入JwtAccessTokenConverter。 28 | * 29 | * @return 30 | */ 31 | @Bean 32 | public JwtAccessTokenConverter jwtAccessTokenConverter() { 33 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 34 | CustomAccessTokenConverter accessTokenConverter = new CustomAccessTokenConverter(); 35 | accessTokenConverter.setUserTokenConverter(new CommonUserConverter()); 36 | converter.setAccessTokenConverter(accessTokenConverter); 37 | // 对称加密 38 | converter.setSigningKey(CommonConstants.SIGNING_KEY); 39 | return converter; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/config/jwt/JwtConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config.jwt; 2 | 3 | import com.ning.constant.CommonConstants; 4 | import com.ning.security.CommonUserConverter; 5 | import com.ning.security.CustomAccessTokenConverter; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.oauth2.provider.token.TokenStore; 9 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 10 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 11 | 12 | import javax.annotation.Resource; 13 | 14 | @Configuration 15 | public class JwtConfig { 16 | 17 | @Resource 18 | JwtAccessTokenConverter jwtAccessTokenConverter; 19 | 20 | @Bean(name = "jwtTokenStore") 21 | public TokenStore tokenStore() { 22 | return new JwtTokenStore(jwtAccessTokenConverter); 23 | } 24 | 25 | /** 26 | * 可以自主选择使用非对称密钥或对称密钥进行加密,此处不设置加密。 27 | * 必须往容器中注入JwtAccessTokenConverter。 28 | * 29 | * @return 30 | */ 31 | @Bean 32 | public JwtAccessTokenConverter jwtAccessTokenConverter() { 33 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 34 | CustomAccessTokenConverter accessTokenConverter = new CustomAccessTokenConverter(); 35 | accessTokenConverter.setUserTokenConverter(new CommonUserConverter()); 36 | converter.setAccessTokenConverter(accessTokenConverter); 37 | // 对称加密 38 | converter.setSigningKey(CommonConstants.SIGNING_KEY); 39 | return converter; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/exception/BaseException.java: -------------------------------------------------------------------------------- 1 | package com.ning.exception; 2 | 3 | /** 4 | * 基础异常 5 | */ 6 | public class BaseException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = 1L; 9 | 10 | /** 11 | * 所属模块 12 | */ 13 | private String module; 14 | 15 | /** 16 | * 错误码 17 | */ 18 | private String code; 19 | 20 | /** 21 | * 错误码对应的参数 22 | */ 23 | private Object[] args; 24 | 25 | /** 26 | * 错误消息 27 | */ 28 | private String defaultMessage; 29 | 30 | public BaseException(String module, String code, Object[] args, String defaultMessage) { 31 | this.module = module; 32 | this.code = code; 33 | this.args = args; 34 | this.defaultMessage = defaultMessage; 35 | } 36 | 37 | public BaseException(String module, String code, Object[] args) { 38 | this(module, code, args, null); 39 | } 40 | 41 | public BaseException(String module, String defaultMessage) { 42 | this(module, null, null, defaultMessage); 43 | } 44 | 45 | public BaseException(String code, Object[] args) { 46 | this(null, code, args, null); 47 | } 48 | 49 | public BaseException(String defaultMessage) { 50 | this(null, null, null, defaultMessage); 51 | } 52 | 53 | public String getModule() { 54 | return module; 55 | } 56 | 57 | public String getCode() { 58 | return code; 59 | } 60 | 61 | public Object[] getArgs() { 62 | return args; 63 | } 64 | 65 | public String getDefaultMessage() { 66 | return defaultMessage; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/java/com/ning/config/jwt/ResourceServerJwtConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config.jwt; 2 | 3 | import com.ning.security.CustomAuthenticationEntryPoint; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.core.annotation.Order; 7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 10 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 11 | import org.springframework.security.oauth2.provider.token.TokenStore; 12 | 13 | import javax.annotation.Resource; 14 | 15 | @Configuration 16 | @EnableResourceServer 17 | @Order(3) 18 | public class ResourceServerJwtConfig extends ResourceServerConfigurerAdapter { 19 | 20 | @Resource 21 | @Qualifier(value = "jwtTokenStore") 22 | TokenStore tokenStore; 23 | 24 | @Override 25 | public void configure(HttpSecurity http) throws Exception { 26 | http.authorizeRequests() 27 | .antMatchers("/v2/api-docs").permitAll() 28 | .antMatchers("/oauth/user").authenticated(); // 配置oauth访问控制,必须认证后才可以访问 29 | } 30 | 31 | @Override 32 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 33 | resources.tokenStore(tokenStore); 34 | 35 | // 处理 Invalid access token 方面异常 36 | resources.authenticationEntryPoint(new CustomAuthenticationEntryPoint()); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9201 3 | servlet: 4 | context-path: /system 5 | 6 | spring: 7 | application: 8 | name: exam-ning-system-user 9 | cloud: 10 | nacos: 11 | discovery: 12 | server-addr: 127.0.0.1:8848 # 服务注册中心 13 | datasource: 14 | type: com.zaxxer.hikari.HikariDataSource 15 | hikari: 16 | minimum-idle: 5 17 | idle-timeout: 600000 18 | maximum-pool-size: 10 19 | auto-commit: true 20 | pool-name: EXAM_SC_USER_HikariCP 21 | max-lifetime: 1800000 22 | connection-timeout: 30000 23 | connection-test-query: SELECT 1 24 | driver-class-name: com.mysql.cj.jdbc.Driver 25 | url: jdbc:mysql://127.0.0.1:3306/exam-ning-springcloud-user?autoReconnect=true&useUnicode=true&characterEncoding=utf8 26 | username: root 27 | password: 123456 28 | 29 | # mybatis-plus 30 | mybatis-plus: 31 | mapper-locations: classpath*:/mapper/*.xml 32 | type-aliases-package: com.ning.entity 33 | 34 | # 使用基于Redis的统一认证服务时,放开以下注释 35 | #security: 36 | # oauth2: 37 | # resource: 38 | # # user-info-uri: http://localhost:8080/auth/oauth/user 39 | # token-info-uri: http://exam-ning-auth/oauth/check_token 40 | # client: 41 | # client-id: ning666888 42 | # client-secret: 888666 43 | # scope: ningning 44 | 45 | # swagger配置 46 | swagger: 47 | title: 系统设置模块接口文档 48 | license: Powered By ning 49 | licenseUrl: https://gitee.com/ningzxspace/exam-ning-springcloud-v1 50 | authorization: 51 | name: ning 52 | auth-regex: ^.*$ 53 | authorization-scope-list: 54 | - scope: server 55 | description: 客户端授权范围 56 | token-url-list: 57 | - http://localhost:8080/auth/oauth/token 58 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/resources/application-docker.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9201 3 | servlet: 4 | context-path: /system 5 | 6 | spring: 7 | application: 8 | name: exam-ning-system-user 9 | cloud: 10 | nacos: 11 | discovery: 12 | server-addr: host.docker.internal:8848 # 服务注册中心 13 | datasource: 14 | type: com.zaxxer.hikari.HikariDataSource 15 | hikari: 16 | minimum-idle: 5 17 | idle-timeout: 600000 18 | maximum-pool-size: 10 19 | auto-commit: true 20 | pool-name: EXAM_SC_USER_HikariCP 21 | max-lifetime: 1800000 22 | connection-timeout: 30000 23 | connection-test-query: SELECT 1 24 | driver-class-name: com.mysql.cj.jdbc.Driver 25 | url: jdbc:mysql://host.docker.internal:3306/exam-ning-springcloud-user?autoReconnect=true&useUnicode=true&characterEncoding=utf8 26 | username: root 27 | password: Su5I6oOtFU33ckBpZyRe 28 | 29 | # mybatis-plus 30 | mybatis-plus: 31 | mapper-locations: classpath*:/mapper/*.xml 32 | type-aliases-package: com.ning.entity 33 | 34 | # 使用基于Redis的统一认证服务时,放开以下注释 35 | #security: 36 | # oauth2: 37 | # resource: 38 | # # user-info-uri: http://localhost:8080/auth/oauth/user 39 | # token-info-uri: http://exam-ning-auth/oauth/check_token 40 | # client: 41 | # client-id: ning666888 42 | # client-secret: 888666 43 | # scope: ningning 44 | 45 | # swagger配置 46 | swagger: 47 | title: 系统设置模块接口文档 48 | license: Powered By ning 49 | licenseUrl: https://gitee.com/ningzxspace/exam-ning-springcloud-v1 50 | authorization: 51 | name: ning 52 | auth-regex: ^.*$ 53 | authorization-scope-list: 54 | - scope: server 55 | description: 客户端授权范围 56 | token-url-list: 57 | - http://localhost:8080/auth/oauth/token 58 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/entity/ExamTestPaperItem.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableField; 7 | 8 | import java.io.Serializable; 9 | 10 | import io.swagger.annotations.ApiModel; 11 | import io.swagger.annotations.ApiModelProperty; 12 | import lombok.Data; 13 | import lombok.EqualsAndHashCode; 14 | import lombok.experimental.Accessors; 15 | 16 | /** 17 | *

18 | * 试卷项目表 19 | *

20 | * 21 | * @author ningning 22 | * @since 2021-05-14 23 | */ 24 | @Data 25 | @EqualsAndHashCode(callSuper = false) 26 | @Accessors(chain = true) 27 | @TableName("exam_test_paper_item") 28 | @ApiModel(value = "ExamTestPaperItem对象", description = "试卷项目表") 29 | public class ExamTestPaperItem implements Serializable { 30 | 31 | private static final long serialVersionUID = 1L; 32 | 33 | @ApiModelProperty(value = "主键") 34 | @TableId(value = "id", type = IdType.AUTO) 35 | private Integer id; 36 | 37 | @ApiModelProperty(value = "试卷ID") 38 | @TableField("test_paper_id") 39 | private Integer testPaperId; 40 | 41 | @ApiModelProperty(value = "题目顺序") 42 | @TableField("seq") 43 | private Integer seq; 44 | 45 | @ApiModelProperty(value = "题目ID") 46 | @TableField("question_id") 47 | private Integer questionId; 48 | 49 | @ApiModelProperty(value = "题目类别") 50 | @TableField("question_type") 51 | private String questionType; 52 | 53 | @ApiModelProperty(value = "得分") 54 | @TableField("score") 55 | private Float score; 56 | 57 | @ApiModelProperty(value = "漏选得分") 58 | @TableField("miss_score") 59 | private Float missScore; 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/ExamNingSystemUserApplication.java: -------------------------------------------------------------------------------- 1 | package com.ning; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.web.cors.CorsConfiguration; 9 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 10 | import org.springframework.web.filter.CorsFilter; 11 | 12 | @Slf4j 13 | @EnableDiscoveryClient 14 | @SpringBootApplication 15 | public class ExamNingSystemUserApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(ExamNingSystemUserApplication.class, args); 19 | log.info("exam-ning-springcloud-system-user start success !!!"); 20 | } 21 | 22 | /** 23 | * 跨域请求过滤器 24 | * 25 | * @return 26 | */ 27 | @Bean 28 | public CorsFilter corsFilter() { 29 | UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 30 | source.registerCorsConfiguration("/**", buildConfig()); 31 | return new CorsFilter(source); 32 | } 33 | 34 | /** 35 | * 跨域请求配置 36 | * 37 | * @return 38 | */ 39 | private CorsConfiguration buildConfig() { 40 | CorsConfiguration corsConfiguration = new CorsConfiguration(); 41 | // * 表示对所有的地址都可以访问 42 | corsConfiguration.addAllowedOrigin("*"); 43 | // 跨域的请求头 44 | corsConfiguration.addAllowedHeader("*"); 45 | // 跨域的请求方法 46 | corsConfiguration.addAllowedMethod("*"); 47 | // 大致意思是可以携带验证信息 cookie、token等等 48 | corsConfiguration.setAllowCredentials(true); 49 | return corsConfiguration; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9202 3 | servlet: 4 | context-path: /exam 5 | 6 | spring: 7 | application: 8 | name: exam-ning-system-exam 9 | cloud: 10 | nacos: 11 | discovery: 12 | server-addr: 127.0.0.1:8848 # 服务注册中心 13 | datasource: 14 | type: com.zaxxer.hikari.HikariDataSource 15 | hikari: 16 | minimum-idle: 5 17 | idle-timeout: 600000 18 | maximum-pool-size: 10 19 | auto-commit: true 20 | pool-name: EXAM_SC_EXAM_HikariCP 21 | max-lifetime: 1800000 22 | connection-timeout: 30000 23 | connection-test-query: SELECT 1 24 | driver-class-name: com.mysql.cj.jdbc.Driver 25 | url: jdbc:mysql://127.0.0.1:3306/exam-ning-springcloud-exam?autoReconnect=true&useUnicode=true&characterEncoding=utf8 26 | username: root 27 | password: 123456 28 | 29 | # mybatis-plus 30 | mybatis-plus: 31 | mapper-locations: classpath*:/mapper/*.xml 32 | type-aliases-package: com.ning.entity 33 | configuration: 34 | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 35 | 36 | feign: 37 | hystrix: 38 | enabled: true 39 | 40 | # 使用基于Redis的统一认证服务时,放开以下注释 41 | #security: 42 | # oauth2: 43 | # resource: 44 | # # user-info-uri: http://localhost:8080/auth/oauth/user 45 | # token-info-uri: http://exam-ning-auth/oauth/check_token 46 | # client: 47 | # client-id: ning666888 48 | # client-secret: 888666 49 | # scope: ningning 50 | 51 | # swagger配置 52 | swagger: 53 | title: 考试模块接口文档 54 | license: Powered By ning 55 | licenseUrl: https://gitee.com/ningzxspace/exam-ning-springcloud-v1 56 | authorization: 57 | name: ning 58 | auth-regex: ^.*$ 59 | authorization-scope-list: 60 | - scope: server 61 | description: 客户端授权范围 62 | token-url-list: 63 | - http://localhost:8080/auth/oauth/token 64 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/enums/ExamQuestionTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.enums; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.*; 6 | 7 | public enum ExamQuestionTypeEnum { 8 | 9 | CHOICE(0, "choice", "单选题"), 10 | CHOICE_MULTI(1, "choice_multi", "多选题"), 11 | TRUE_FALSE(2, "true_false", "判断题"), 12 | FILL_BLANK(3, "fill_blank", "填空题"), 13 | QUESTION(4, "question", "问答题"); 14 | 15 | private int index; 16 | private String type; 17 | private String title; 18 | 19 | ExamQuestionTypeEnum(int index, String type, String title) { 20 | this.index = index; 21 | this.type = type; 22 | this.title = title; 23 | } 24 | 25 | public static List> listExamQuestionTypes() { 26 | List> types = new ArrayList<>(); 27 | for (ExamQuestionTypeEnum value : values()) { 28 | Map map = new HashMap<>(); 29 | map.put("type", value.type); 30 | map.put("title", value.title); 31 | types.add(map); 32 | } 33 | return types; 34 | } 35 | 36 | public static int getIndex(String type) { 37 | for (ExamQuestionTypeEnum en : values()) { 38 | if (en.type.equals(type)) { 39 | return en.index; 40 | } 41 | } 42 | return -1; 43 | } 44 | 45 | public int getIndex() { 46 | return index; 47 | } 48 | 49 | public void setIndex(int index) { 50 | this.index = index; 51 | } 52 | 53 | public String getType() { 54 | return type; 55 | } 56 | 57 | public void setType(String type) { 58 | this.type = type; 59 | } 60 | 61 | public String getTitle() { 62 | return title; 63 | } 64 | 65 | public void setTitle(String title) { 66 | this.title = title; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/resources/mapper/ExamQuestionMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | id, type, stem, score, answer, analysis, metas, category_id, used_num, is_delete, is_show, create_user_id, create_time, update_user_id, update_time, copy_id 28 | 29 | 30 | 31 | 32 | update exam_question t set t.used_num = t.used_num + 1 33 | where t.id in 34 | 35 | #{id} 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/mark/CheckChoiceMultiQuestion.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.mark; 2 | 3 | import cn.hutool.json.JSONArray; 4 | import cn.hutool.json.JSONUtil; 5 | import com.ning.entity.ExamQuestion; 6 | import com.ning.entity.ExamTestPaperItem; 7 | import com.ning.entity.ExamTestPaperItemResult; 8 | 9 | /** 10 | * 判多选题 11 | */ 12 | public class CheckChoiceMultiQuestion implements Check { 13 | 14 | @Override 15 | public ExamTestPaperItemResult check(ExamTestPaperItemResult examTestPaperItemResult, ExamQuestion examQuestion, ExamTestPaperItem examTestPaperItem) { 16 | examTestPaperItemResult.setStatus("wrong"); 17 | examTestPaperItemResult.setScore(0F); 18 | 19 | String userAnswer = examTestPaperItemResult.getAnswer(); 20 | if (examQuestion.getAnswer().equals(userAnswer)) { 21 | examTestPaperItemResult.setStatus("right"); 22 | examTestPaperItemResult.setScore(examTestPaperItem.getScore()); 23 | } else if (isPartRight(examQuestion.getAnswer(), userAnswer)) { 24 | examTestPaperItemResult.setStatus("partRight"); 25 | examTestPaperItemResult.setScore(examTestPaperItem.getScore() / 2); 26 | } 27 | return examTestPaperItemResult; 28 | } 29 | 30 | private Boolean isPartRight(String rightAnswer, String userAnswer) { 31 | boolean result = false; 32 | 33 | JSONArray rightAnswerArray = JSONUtil.parseArray(rightAnswer); // 正确答案 34 | JSONArray userAnswerArray = JSONUtil.parseArray(userAnswer); // 用户答案 35 | for (int i = 0; i < userAnswerArray.size(); i++) { 36 | if (rightAnswerArray.indexOf(userAnswerArray.get(i)) == -1) { 37 | result = false; 38 | break; 39 | } else { 40 | result = true; 41 | } 42 | } 43 | 44 | return result; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/resources/application-docker.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9202 3 | servlet: 4 | context-path: /exam 5 | 6 | spring: 7 | application: 8 | name: exam-ning-system-exam 9 | cloud: 10 | nacos: 11 | discovery: 12 | server-addr: host.docker.internal:8848 # 服务注册中心 13 | datasource: 14 | type: com.zaxxer.hikari.HikariDataSource 15 | hikari: 16 | minimum-idle: 5 17 | idle-timeout: 600000 18 | maximum-pool-size: 10 19 | auto-commit: true 20 | pool-name: EXAM_SC_EXAM_HikariCP 21 | max-lifetime: 1800000 22 | connection-timeout: 30000 23 | connection-test-query: SELECT 1 24 | driver-class-name: com.mysql.cj.jdbc.Driver 25 | url: jdbc:mysql://host.docker.internal:3306/exam-ning-springcloud-exam?autoReconnect=true&useUnicode=true&characterEncoding=utf8 26 | username: root 27 | password: Su5I6oOtFU33ckBpZyRe 28 | 29 | # mybatis-plus 30 | mybatis-plus: 31 | mapper-locations: classpath*:/mapper/*.xml 32 | type-aliases-package: com.ning.entity 33 | configuration: 34 | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 35 | 36 | feign: 37 | hystrix: 38 | enabled: true 39 | 40 | # 使用基于Redis的统一认证服务时,放开以下注释 41 | #security: 42 | # oauth2: 43 | # resource: 44 | # # user-info-uri: http://localhost:8080/auth/oauth/user 45 | # token-info-uri: http://exam-ning-auth/oauth/check_token 46 | # client: 47 | # client-id: ning666888 48 | # client-secret: 888666 49 | # scope: ningning 50 | 51 | # swagger配置 52 | swagger: 53 | title: 考试模块接口文档 54 | license: Powered By ning 55 | licenseUrl: https://gitee.com/ningzxspace/exam-ning-springcloud-v1 56 | authorization: 57 | name: ning 58 | auth-regex: ^.*$ 59 | authorization-scope-list: 60 | - scope: server 61 | description: 客户端授权范围 62 | token-url-list: 63 | - http://localhost:8080/auth/oauth/token 64 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/model/Result.java: -------------------------------------------------------------------------------- 1 | package com.ning.model; 2 | 3 | 4 | import com.ning.constant.Constants; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 响应信息主体 11 | */ 12 | @Data 13 | public class Result implements Serializable { 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | /** 18 | * 成功 19 | */ 20 | public static final int SUCCESS = Constants.SUCCESS; 21 | 22 | /** 23 | * 失败 24 | */ 25 | public static final int FAIL = Constants.FAIL; 26 | 27 | private int code; 28 | 29 | private String msg; 30 | 31 | private T data; 32 | 33 | public static Result ok() { 34 | return restResult(null, SUCCESS, "success"); 35 | } 36 | 37 | public static Result ok(T data) { 38 | return restResult(data, SUCCESS, "success"); 39 | } 40 | 41 | public static Result ok(T data, String msg) { 42 | return restResult(data, SUCCESS, msg); 43 | } 44 | 45 | public static Result fail() { 46 | return restResult(null, FAIL, "failure"); 47 | } 48 | 49 | public static Result fail(String msg) { 50 | return restResult(null, FAIL, msg); 51 | } 52 | 53 | public static Result fail(T data) { 54 | return restResult(data, FAIL, "failure"); 55 | } 56 | 57 | public static Result fail(T data, String msg) { 58 | return restResult(data, FAIL, msg); 59 | } 60 | 61 | public static Result fail(int code, String msg) { 62 | return restResult(null, code, msg); 63 | } 64 | 65 | private static Result restResult(T data, int code, String msg) { 66 | Result apiResult = new Result<>(); 67 | apiResult.setCode(code); 68 | apiResult.setData(data); 69 | apiResult.setMsg(msg); 70 | return apiResult; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/config/jwt/ResourceServerJwtConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config.jwt; 2 | 3 | import com.ning.security.CustomAccessDeniedHandler; 4 | import com.ning.security.CustomAuthenticationEntryPoint; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.core.annotation.Order; 8 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 12 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 13 | import org.springframework.security.oauth2.provider.token.TokenStore; 14 | 15 | import javax.annotation.Resource; 16 | 17 | @Configuration 18 | @EnableResourceServer 19 | @Order(3) 20 | @EnableGlobalMethodSecurity(prePostEnabled = true) 21 | public class ResourceServerJwtConfig extends ResourceServerConfigurerAdapter { 22 | 23 | @Resource 24 | @Qualifier(value = "jwtTokenStore") 25 | TokenStore tokenStore; 26 | 27 | @Override 28 | public void configure(HttpSecurity http) throws Exception { 29 | http.authorizeRequests().antMatchers("/exam/**").authenticated(); // 配置exam访问控制,必须认证后才可以访问 30 | } 31 | 32 | @Override 33 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 34 | resources.tokenStore(tokenStore); 35 | 36 | // 处理 Invalid access token 方面异常 37 | resources.authenticationEntryPoint(new CustomAuthenticationEntryPoint()); 38 | 39 | // 处理 access_denied 方面异常 40 | resources.accessDeniedHandler(new CustomAccessDeniedHandler()); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/src/main/java/com/ning/handler/SwaggerHandler.java: -------------------------------------------------------------------------------- 1 | package com.ning.handler; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import reactor.core.publisher.Mono; 10 | import springfox.documentation.swagger.web.*; 11 | 12 | import java.util.Optional; 13 | 14 | @RestController 15 | @RequestMapping("/swagger-resources") 16 | public class SwaggerHandler { 17 | 18 | @Autowired(required = false) 19 | private SecurityConfiguration securityConfiguration; 20 | 21 | @Autowired(required = false) 22 | private UiConfiguration uiConfiguration; 23 | 24 | private final SwaggerResourcesProvider swaggerResources; 25 | 26 | @Autowired 27 | public SwaggerHandler(SwaggerResourcesProvider swaggerResources) { 28 | this.swaggerResources = swaggerResources; 29 | } 30 | 31 | @GetMapping("/configuration/security") 32 | public Mono> securityConfiguration() { 33 | return Mono.just(new ResponseEntity<>( 34 | Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), 35 | HttpStatus.OK)); 36 | } 37 | 38 | @GetMapping("/configuration/ui") 39 | public Mono> uiConfiguration() { 40 | return Mono.just(new ResponseEntity<>( 41 | Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); 42 | } 43 | 44 | @SuppressWarnings("rawtypes") 45 | @GetMapping("") 46 | public Mono swaggerResources() { 47 | return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/resources/mapper/MenuMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | menu_id, menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark 29 | 30 | 31 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/resources/mapper/ExamTestPaperResultMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | id, testpaper_id, testpaper_name, user_id, score, objective_score, subjective_score, teacher_say, right_item_count, used_time, status, check_user_id, checked_time, update_time 26 | 27 | 28 | 29 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/config/jwt/ResourceServerJwtConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config.jwt; 2 | 3 | import com.ning.security.CustomAccessDeniedHandler; 4 | import com.ning.security.CustomAuthenticationEntryPoint; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.core.annotation.Order; 8 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 12 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 13 | import org.springframework.security.oauth2.provider.token.TokenStore; 14 | 15 | import javax.annotation.Resource; 16 | 17 | @Configuration 18 | @EnableResourceServer 19 | @Order(3) 20 | @EnableGlobalMethodSecurity(prePostEnabled = true) 21 | public class ResourceServerJwtConfig extends ResourceServerConfigurerAdapter { 22 | 23 | @Resource 24 | @Qualifier(value = "jwtTokenStore") 25 | TokenStore tokenStore; 26 | 27 | @Override 28 | public void configure(HttpSecurity http) throws Exception { 29 | http.authorizeRequests().antMatchers("/index", "/user/selectUserByUsername").permitAll() 30 | .antMatchers("/user/**", "/getInfo").authenticated(); // 配置user访问控制,必须认证后才可以访问 31 | } 32 | 33 | @Override 34 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 35 | resources.tokenStore(tokenStore); 36 | 37 | // 处理 Invalid access token 方面异常 38 | resources.authenticationEntryPoint(new CustomAuthenticationEntryPoint()); 39 | 40 | // 处理 access_denied 方面异常 41 | resources.accessDeniedHandler(new CustomAccessDeniedHandler()); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/controller/ExamResultController.java: -------------------------------------------------------------------------------- 1 | package com.ning.controller; 2 | 3 | import com.ning.common.model.MarkScoreModel; 4 | import com.ning.model.Result; 5 | import com.ning.service.ExamResultService; 6 | import com.ning.utils.SecurityUtils; 7 | import io.swagger.annotations.ApiOperation; 8 | import io.swagger.annotations.ApiParam; 9 | import org.springframework.security.access.prepost.PreAuthorize; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import javax.annotation.Resource; 13 | 14 | @RequestMapping(value = "/result/") 15 | @RestController 16 | public class ExamResultController { 17 | 18 | @Resource 19 | ExamResultService examResultService; 20 | 21 | @GetMapping(value = "/list") 22 | @ApiOperation(value = "查询考试结果列表") 23 | public Result list(@RequestParam(value = "id", defaultValue = "1") @ApiParam(name = "id", example = "1") Integer id) { 24 | return examResultService.list(id, SecurityUtils.getLoginUser().getUserId().intValue()); 25 | } 26 | 27 | @PreAuthorize("@ss.hasPermi('exam:result:detail')") 28 | @GetMapping(value = "/detail") 29 | @ApiOperation(value = "查询考试结果详情") 30 | public Result detail(@RequestParam(value = "id", defaultValue = "1") @ApiParam(name = "id", example = "1") Integer id) { 31 | return examResultService.detail(id); 32 | } 33 | 34 | @PreAuthorize("@ss.hasPermi('exam:result:marks')") 35 | @GetMapping(value = "/marks") 36 | @ApiOperation(value = "查询待批阅试卷列表") 37 | public Result marks(@RequestParam(value = "pNum", defaultValue = "1") @ApiParam(name = "pNum", example = "1") Integer pNum, 38 | @RequestParam(value = "pSize", defaultValue = "10") @ApiParam(name = "pSize", example = "10") Integer pSize) { 39 | return examResultService.selectPage(pNum, pSize); 40 | } 41 | 42 | @PreAuthorize("@ss.hasPermi('exam:result:doMark')") 43 | @PostMapping(value = "/doMark") 44 | @ApiOperation(value = "打分") 45 | public Result doMark(@RequestBody MarkScoreModel markScoreModel) { 46 | return examResultService.doMark(markScoreModel); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/java/com/ning/config/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.core.annotation.Order; 6 | import org.springframework.security.authentication.AuthenticationManager; 7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.core.userdetails.UserDetailsService; 12 | import org.springframework.security.crypto.password.NoOpPasswordEncoder; 13 | import org.springframework.security.crypto.password.PasswordEncoder; 14 | 15 | import javax.annotation.Resource; 16 | 17 | /** 18 | * Security 安全认证相关配置 19 | * Oauth2依赖于Security 默认情况下WebSecurityConfig执行比ResourceServerConfig优先 20 | */ 21 | @Order(99) 22 | @Configuration 23 | @EnableWebSecurity 24 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 25 | 26 | @Resource 27 | private UserDetailsService userDetailsService; 28 | 29 | @Override 30 | protected void configure(HttpSecurity http) throws Exception { 31 | http.authorizeRequests() 32 | .antMatchers("/actuator/**", "/oauth/*", "/token/**").permitAll() 33 | .anyRequest().authenticated() 34 | .and().csrf().disable(); 35 | } 36 | 37 | @Override 38 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 39 | auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); 40 | } 41 | 42 | @Bean 43 | public PasswordEncoder passwordEncoder() { 44 | return NoOpPasswordEncoder.getInstance(); 45 | } 46 | 47 | @Bean 48 | @Override 49 | protected AuthenticationManager authenticationManager() throws Exception { 50 | return super.authenticationManager(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/entity/ExamTestPaperItemResult.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableField; 7 | 8 | import java.io.Serializable; 9 | 10 | import io.swagger.annotations.ApiModel; 11 | import io.swagger.annotations.ApiModelProperty; 12 | import lombok.Data; 13 | import lombok.EqualsAndHashCode; 14 | import lombok.experimental.Accessors; 15 | 16 | /** 17 | *

18 | * 试卷项目结果表 19 | *

20 | * 21 | * @author ningning 22 | * @since 2021-06-01 23 | */ 24 | @Data 25 | @EqualsAndHashCode(callSuper = false) 26 | @Accessors(chain = true) 27 | @TableName("exam_test_paper_item_result") 28 | @ApiModel(value = "ExamTestPaperItemResult对象", description = "试卷项目结果表") 29 | public class ExamTestPaperItemResult implements Serializable { 30 | 31 | private static final long serialVersionUID = 1L; 32 | 33 | @ApiModelProperty(value = "主键") 34 | @TableId(value = "id", type = IdType.AUTO) 35 | private Integer id; 36 | 37 | @ApiModelProperty(value = "试卷结果ID") 38 | @TableField("testpaper_result_id") 39 | private Integer testpaperResultId; 40 | 41 | @ApiModelProperty(value = "试卷ID") 42 | @TableField("testpaper_id") 43 | private Integer testpaperId; 44 | 45 | @ApiModelProperty(value = "试卷项目ID") 46 | @TableField("testpaper_item_id") 47 | private Integer testpaperItemId; 48 | 49 | @ApiModelProperty(value = "题目ID") 50 | @TableField("question_id") 51 | private Integer questionId; 52 | 53 | @ApiModelProperty(value = "答题人ID") 54 | @TableField("user_id") 55 | private Integer userId; 56 | 57 | @ApiModelProperty(value = "答题结果") 58 | @TableField("answer") 59 | private String answer; 60 | 61 | @ApiModelProperty(value = "结果状态(none、right、partRight、wrong、noAnswer)") 62 | @TableField("status") 63 | private String status; 64 | 65 | @ApiModelProperty(value = "得分") 66 | @TableField("score") 67 | private Float score; 68 | 69 | @ApiModelProperty(value = "老师评价") 70 | @TableField("teacher_say") 71 | private String teacherSay; 72 | 73 | } 74 | -------------------------------------------------------------------------------- /exam-ning-springcloud-api/src/main/java/com/ning/constant/Constants.java: -------------------------------------------------------------------------------- 1 | package com.ning.constant; 2 | 3 | /** 4 | * 通用常量信息 5 | */ 6 | public class Constants { 7 | 8 | /** 9 | * UTF-8 字符集 10 | */ 11 | public static final String UTF8 = "UTF-8"; 12 | 13 | /** 14 | * GBK 字符集 15 | */ 16 | public static final String GBK = "GBK"; 17 | 18 | /** 19 | * http请求 20 | */ 21 | public static final String HTTP = "http://"; 22 | 23 | /** 24 | * https请求 25 | */ 26 | public static final String HTTPS = "https://"; 27 | 28 | /** 29 | * 成功标记 30 | */ 31 | public static final Integer SUCCESS = 20000; 32 | 33 | /** 34 | * 失败标记 35 | */ 36 | public static final Integer FAIL = 500; 37 | 38 | /** 39 | * 登录成功 40 | */ 41 | public static final String LOGIN_SUCCESS = "Success"; 42 | 43 | /** 44 | * 注销 45 | */ 46 | public static final String LOGOUT = "Logout"; 47 | 48 | /** 49 | * 注册 50 | */ 51 | public static final String REGISTER = "Register"; 52 | 53 | /** 54 | * 登录失败 55 | */ 56 | public static final String LOGIN_FAIL = "Error"; 57 | 58 | /** 59 | * 当前记录起始索引 60 | */ 61 | public static final String PAGE_NUM = "pageNum"; 62 | 63 | /** 64 | * 每页显示记录数 65 | */ 66 | public static final String PAGE_SIZE = "pageSize"; 67 | 68 | /** 69 | * 排序列 70 | */ 71 | public static final String ORDER_BY_COLUMN = "orderByColumn"; 72 | 73 | /** 74 | * 排序的方向 "desc" 或者 "asc". 75 | */ 76 | public static final String IS_ASC = "isAsc"; 77 | 78 | /** 79 | * 验证码 redis key 80 | */ 81 | public static final String CAPTCHA_CODE_KEY = "captcha_codes:"; 82 | 83 | /** 84 | * 验证码有效期(分钟) 85 | */ 86 | public static final Integer CAPTCHA_EXPIRATION = 2; 87 | 88 | /** 89 | * 参数管理 cache key 90 | */ 91 | public static final String SYS_CONFIG_KEY = "sys_config:"; 92 | 93 | /** 94 | * 字典管理 cache key 95 | */ 96 | public static final String SYS_DICT_KEY = "sys_dict:"; 97 | 98 | /** 99 | * 资源映射路径 前缀 100 | */ 101 | public static final String RESOURCE_PREFIX = "/profile"; 102 | 103 | } 104 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/common/mark/CheckFillBlankQuestion.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.mark; 2 | 3 | import cn.hutool.core.convert.Convert; 4 | import cn.hutool.core.util.ObjectUtil; 5 | import cn.hutool.json.JSONArray; 6 | import cn.hutool.json.JSONUtil; 7 | import com.ning.entity.ExamQuestion; 8 | import com.ning.entity.ExamTestPaperItem; 9 | import com.ning.entity.ExamTestPaperItemResult; 10 | 11 | /** 12 | * 判填空题 13 | */ 14 | public class CheckFillBlankQuestion implements Check { 15 | 16 | @Override 17 | public ExamTestPaperItemResult check(ExamTestPaperItemResult examTestPaperItemResult, ExamQuestion examQuestion, ExamTestPaperItem examTestPaperItem) { 18 | examTestPaperItemResult.setStatus("wrong"); 19 | examTestPaperItemResult.setScore(0F); 20 | 21 | try { 22 | String userAnswer = examTestPaperItemResult.getAnswer(); 23 | 24 | JSONArray rightAnswerArray = JSONUtil.parseArray(examQuestion.getAnswer()); // 正确答案 25 | JSONArray userAnswerArray = JSONUtil.parseArray(userAnswer); // 用户答案 26 | 27 | String tempStandardAnswer = ""; 28 | String tempAnswer = ""; 29 | int count = 0; 30 | for (int i = 0; i < rightAnswerArray.size(); i++) { 31 | tempStandardAnswer = Convert.toStr(rightAnswerArray.get(i), ""); 32 | if (ObjectUtil.isNotEmpty(userAnswerArray.get(i))) { 33 | tempAnswer = Convert.toStr(userAnswerArray.get(i), ""); 34 | } 35 | if (tempStandardAnswer.equals(tempAnswer)) { 36 | count++; 37 | } 38 | } 39 | 40 | // 全对 41 | if (count == rightAnswerArray.size()) { 42 | examTestPaperItemResult.setStatus("right"); 43 | examTestPaperItemResult.setScore(examTestPaperItem.getScore()); 44 | } else if (count > 0 && count < rightAnswerArray.size()) { // 部分正确 45 | examTestPaperItemResult.setStatus("partRight"); 46 | examTestPaperItemResult.setScore(count * examTestPaperItem.getScore() / rightAnswerArray.size()); 47 | } 48 | } catch (Exception e) { 49 | System.out.println("CheckFillBlankQuestion # check exception=" + e.getMessage()); 50 | } 51 | return examTestPaperItemResult; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/java/com/ning/config/jwt/JwtConfig.java: -------------------------------------------------------------------------------- 1 | package com.ning.config.jwt; 2 | 3 | import com.ning.constant.CommonConstants; 4 | import com.ning.model.LoginUser; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; 8 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 9 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 10 | import org.springframework.security.oauth2.provider.token.TokenStore; 11 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 12 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 13 | 14 | import javax.annotation.Resource; 15 | import java.util.LinkedHashMap; 16 | import java.util.Map; 17 | 18 | @SuppressWarnings("ALL") 19 | @Configuration 20 | public class JwtConfig { 21 | 22 | @Resource 23 | JwtAccessTokenConverter jwtAccessTokenConverter; 24 | 25 | @Bean(name = "jwtTokenStore") 26 | public TokenStore tokenStore() { 27 | return new JwtTokenStore(jwtAccessTokenConverter); 28 | } 29 | 30 | /** 31 | * 可以自主选择使用非对称密钥或对称密钥进行加密,此处对称密钥加密。 32 | * 33 | * @return 34 | */ 35 | @Bean 36 | public JwtAccessTokenConverter jwtAccessTokenConverter() { 37 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter() { 38 | // 增强 jwt token 39 | @Override 40 | public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { 41 | DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken; 42 | LoginUser user = (LoginUser) authentication.getUserAuthentication().getPrincipal(); 43 | Map additionalInformation = new LinkedHashMap(); 44 | additionalInformation.put(CommonConstants.USER_NAME, authentication.getName()); 45 | additionalInformation.put(CommonConstants.USER_ID, user.getUserId()); 46 | token.setAdditionalInformation(additionalInformation); 47 | return super.enhance(accessToken, authentication); 48 | } 49 | }; 50 | 51 | // 对称加密 52 | converter.setSigningKey(CommonConstants.SIGNING_KEY); 53 | return converter; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/utils/SecurityUtils.java: -------------------------------------------------------------------------------- 1 | package com.ning.utils; 2 | 3 | import com.ning.model.LoginUser; 4 | import org.springframework.security.core.Authentication; 5 | import org.springframework.security.core.context.SecurityContextHolder; 6 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 7 | 8 | /** 9 | * 权限获取工具类 10 | * 11 | * @author ruoyi 12 | */ 13 | public class SecurityUtils { 14 | 15 | /** 16 | * 获取Authentication 17 | */ 18 | public static Authentication getAuthentication() { 19 | return SecurityContextHolder.getContext().getAuthentication(); 20 | } 21 | 22 | /** 23 | * 获取用户 24 | */ 25 | public static String getUsername() { 26 | return getLoginUser().getUsername(); 27 | } 28 | 29 | /** 30 | * 获取用户 31 | */ 32 | public static LoginUser getLoginUser(Authentication authentication) { 33 | Object principal = authentication.getPrincipal(); 34 | if (principal instanceof LoginUser) { 35 | return (LoginUser) principal; 36 | } 37 | return null; 38 | } 39 | 40 | /** 41 | * 获取用户 42 | */ 43 | public static LoginUser getLoginUser() { 44 | Authentication authentication = getAuthentication(); 45 | if (authentication == null) { 46 | return null; 47 | } 48 | return getLoginUser(authentication); 49 | } 50 | 51 | /** 52 | * 生成BCryptPasswordEncoder密码 53 | * 54 | * @param password 密码 55 | * @return 加密字符串 56 | */ 57 | public static String encryptPassword(String password) { 58 | BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 59 | return passwordEncoder.encode(password); 60 | } 61 | 62 | /** 63 | * 判断密码是否相同 64 | * 65 | * @param rawPassword 真实密码 66 | * @param encodedPassword 加密后字符 67 | * @return 结果 68 | */ 69 | public static boolean matchesPassword(String rawPassword, String encodedPassword) { 70 | BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 71 | return passwordEncoder.matches(rawPassword, encodedPassword); 72 | } 73 | 74 | /** 75 | * 是否为管理员 76 | * 77 | * @param userId 用户ID 78 | * @return 结果 79 | */ 80 | public static boolean isAdmin(Long userId) { 81 | return userId != null && 1L == userId; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/utils/SecurityUtils.java: -------------------------------------------------------------------------------- 1 | package com.ning.utils; 2 | 3 | import com.ning.model.LoginUser; 4 | import org.springframework.security.core.Authentication; 5 | import org.springframework.security.core.context.SecurityContextHolder; 6 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 7 | 8 | /** 9 | * 权限获取工具类 10 | * 11 | * @author ruoyi 12 | */ 13 | public class SecurityUtils { 14 | 15 | /** 16 | * 获取Authentication 17 | */ 18 | public static Authentication getAuthentication() { 19 | return SecurityContextHolder.getContext().getAuthentication(); 20 | } 21 | 22 | /** 23 | * 获取用户 24 | */ 25 | public static String getUsername() { 26 | return getLoginUser().getUsername(); 27 | } 28 | 29 | /** 30 | * 获取用户 31 | */ 32 | public static LoginUser getLoginUser(Authentication authentication) { 33 | Object principal = authentication.getPrincipal(); 34 | if (principal instanceof LoginUser) { 35 | return (LoginUser) principal; 36 | } 37 | return null; 38 | } 39 | 40 | /** 41 | * 获取用户 42 | */ 43 | public static LoginUser getLoginUser() { 44 | Authentication authentication = getAuthentication(); 45 | if (authentication == null) { 46 | return null; 47 | } 48 | return getLoginUser(authentication); 49 | } 50 | 51 | /** 52 | * 生成BCryptPasswordEncoder密码 53 | * 54 | * @param password 密码 55 | * @return 加密字符串 56 | */ 57 | public static String encryptPassword(String password) { 58 | BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 59 | return passwordEncoder.encode(password); 60 | } 61 | 62 | /** 63 | * 判断密码是否相同 64 | * 65 | * @param rawPassword 真实密码 66 | * @param encodedPassword 加密后字符 67 | * @return 结果 68 | */ 69 | public static boolean matchesPassword(String rawPassword, String encodedPassword) { 70 | BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 71 | return passwordEncoder.matches(rawPassword, encodedPassword); 72 | } 73 | 74 | /** 75 | * 是否为管理员 76 | * 77 | * @param userId 用户ID 78 | * @return 结果 79 | */ 80 | public static boolean isAdmin(Long userId) { 81 | return userId != null && 1L == userId; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package com.ning.controller; 2 | 3 | import cn.hutool.core.convert.Convert; 4 | import cn.hutool.core.util.StrUtil; 5 | import com.ning.manager.MenuManager; 6 | import com.ning.manager.RoleManager; 7 | import com.ning.manager.UserManager; 8 | import com.ning.model.Result; 9 | import com.ning.utils.SecurityUtils; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.security.access.prepost.PreAuthorize; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import javax.annotation.Resource; 16 | import java.util.HashMap; 17 | import java.util.HashSet; 18 | import java.util.Map; 19 | import java.util.Set; 20 | 21 | @RestController 22 | public class IndexController { 23 | 24 | @Value("${server.port}") 25 | private String port; 26 | 27 | @Resource 28 | UserManager userManager; 29 | @Resource 30 | RoleManager roleManager; 31 | @Resource 32 | MenuManager menuManager; 33 | 34 | @GetMapping(value = "/index") 35 | public Result index() { 36 | return Result.ok("system user index " + port); 37 | } 38 | 39 | @GetMapping(value = "/getInfo") 40 | public Result getInfo() { 41 | Long userId = SecurityUtils.getLoginUser().getUserId(); 42 | 43 | // 角色集合 44 | Set roles = new HashSet<>(); 45 | String role = roleManager.getRoleKeyByUserId(userId); 46 | roles.add(StrUtil.isNotEmpty(role) ? role : ""); 47 | 48 | // 权限集合 49 | Set permissions = new HashSet<>(); 50 | permissions.addAll(menuManager.listPermissionsByUserId(userId)); 51 | 52 | Map map = new HashMap<>(); 53 | map.put("user", userManager.getUserById(Convert.toInt(userId))); 54 | map.put("roles", roles); 55 | map.put("permissions", permissions); 56 | 57 | return Result.ok(map); 58 | } 59 | 60 | @PreAuthorize("@ss.hasPermi('test1')") 61 | @GetMapping(value = "/test1") 62 | public String test1() { 63 | return "test1"; 64 | } 65 | 66 | @PreAuthorize("@ss.hasPermi('test2')") 67 | @GetMapping(value = "/test2") 68 | public String test2() { 69 | return "test2"; 70 | } 71 | 72 | @PreAuthorize("@ss.hasPermi('test3')") 73 | @GetMapping(value = "/test3") 74 | public String test3() { 75 | return "test3"; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/java/com/ning/service/UserDetailsServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.ning.service; 2 | 3 | import cn.hutool.core.util.ObjectUtil; 4 | import com.ning.api.user.RemoteUserService; 5 | import com.ning.exception.BaseException; 6 | import com.ning.model.LoginUser; 7 | import com.ning.model.Result; 8 | import com.ning.model.User; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.security.core.GrantedAuthority; 11 | import org.springframework.security.core.authority.AuthorityUtils; 12 | import org.springframework.security.core.userdetails.UserDetails; 13 | import org.springframework.security.core.userdetails.UserDetailsService; 14 | import org.springframework.stereotype.Service; 15 | 16 | import javax.annotation.Resource; 17 | import java.util.Collection; 18 | import java.util.HashSet; 19 | import java.util.Set; 20 | 21 | @Slf4j 22 | @Service(value = "userDetailsService") 23 | public class UserDetailsServiceImpl implements UserDetailsService { 24 | 25 | @Resource 26 | RemoteUserService remoteUserService; 27 | 28 | @Override 29 | public UserDetails loadUserByUsername(String s) { 30 | Result userResult = remoteUserService.selectUserByUsername(s); 31 | checkUser(userResult, s); 32 | return getUserDetails(userResult); 33 | } 34 | 35 | public void checkUser(Result userResult, String username) { 36 | if (ObjectUtil.isNull(userResult) || ObjectUtil.isNull(userResult.getData())) { 37 | log.info("登录用户:{} 不存在.", username); 38 | throw new BaseException("登录用户:" + username + " 不存在"); 39 | } else if (userResult.getData().getIsDelete() == 1) { 40 | log.info("登录用户:{} 已被删除.", username); 41 | throw new BaseException("对不起,您的账号:" + username + " 已被删除"); 42 | } 43 | } 44 | 45 | private UserDetails getUserDetails(Result result) { 46 | User user = result.getData(); 47 | Set dbAuthsSet = new HashSet<>(); 48 | // 获取角色 49 | dbAuthsSet.addAll(ObjectUtil.isNotEmpty(user.getRoles()) ? user.getRoles() : new HashSet<>()); 50 | 51 | // 获取权限 52 | dbAuthsSet.addAll(ObjectUtil.isNotEmpty(user.getPermissions()) ? user.getPermissions() : new HashSet<>()); 53 | 54 | Collection authorities = AuthorityUtils.createAuthorityList(dbAuthsSet.toArray(new String[0])); 55 | return new LoginUser((long) user.getId(), user.getUsername(), user.getPassword(), true, true, true, true, authorities); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /exam-ning-springcloud-gateway/src/main/java/com/ning/config/SwaggerProvider.java: -------------------------------------------------------------------------------- 1 | package com.ning.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.cloud.gateway.config.GatewayProperties; 5 | import org.springframework.cloud.gateway.route.RouteLocator; 6 | import org.springframework.cloud.gateway.support.NameUtils; 7 | import org.springframework.stereotype.Component; 8 | import springfox.documentation.swagger.web.SwaggerResource; 9 | import springfox.documentation.swagger.web.SwaggerResourcesProvider; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | @Component 15 | public class SwaggerProvider implements SwaggerResourcesProvider { 16 | 17 | /** 18 | * Swagger2默认的url后缀 19 | */ 20 | public static final String SWAGGER2URL = "/v2/api-docs"; 21 | /** 22 | * 网关路由 23 | */ 24 | @Autowired 25 | private RouteLocator routeLocator; 26 | 27 | @Autowired 28 | private GatewayProperties gatewayProperties; 29 | 30 | /** 31 | * 聚合其他服务接口 32 | * 33 | * @return 34 | */ 35 | @Override 36 | public List get() { 37 | List resourceList = new ArrayList<>(); 38 | List routes = new ArrayList<>(); 39 | // 获取网关中配置的route 40 | routeLocator.getRoutes().subscribe(route -> routes.add(route.getId())); 41 | gatewayProperties.getRoutes().stream() 42 | .filter(routeDefinition -> routes 43 | .contains(routeDefinition.getId())) 44 | .forEach(routeDefinition -> routeDefinition.getPredicates().stream() 45 | .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName())) 46 | // 过滤掉认证服务的swagger 47 | .filter(predicateDefinition -> !"exam-ning-auth".equalsIgnoreCase(routeDefinition.getId())) 48 | .forEach(predicateDefinition -> resourceList 49 | .add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs() 50 | .get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL))))); 51 | return resourceList; 52 | } 53 | 54 | private SwaggerResource swaggerResource(String name, String location) { 55 | SwaggerResource swaggerResource = new SwaggerResource(); 56 | swaggerResource.setName(name); 57 | swaggerResource.setLocation(location); 58 | swaggerResource.setSwaggerVersion("2.0"); 59 | return swaggerResource; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/common/model/RouterVo.java: -------------------------------------------------------------------------------- 1 | package com.ning.common.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 路由配置信息 9 | * 10 | * @author ruoyi 11 | */ 12 | @JsonInclude(JsonInclude.Include.NON_EMPTY) 13 | public class RouterVo { 14 | 15 | /** 16 | * 路由名字 17 | */ 18 | private String name; 19 | 20 | /** 21 | * 路由地址 22 | */ 23 | private String path; 24 | 25 | /** 26 | * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现 27 | */ 28 | private boolean hidden; 29 | 30 | /** 31 | * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 32 | */ 33 | private String redirect; 34 | 35 | /** 36 | * 组件地址 37 | */ 38 | private String component; 39 | 40 | /** 41 | * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 42 | */ 43 | private Boolean alwaysShow; 44 | 45 | /** 46 | * 其他元素 47 | */ 48 | private MetaVo meta; 49 | 50 | /** 51 | * 子路由 52 | */ 53 | private List children; 54 | 55 | public String getName() { 56 | return name; 57 | } 58 | 59 | public void setName(String name) { 60 | this.name = name; 61 | } 62 | 63 | public String getPath() { 64 | return path; 65 | } 66 | 67 | public void setPath(String path) { 68 | this.path = path; 69 | } 70 | 71 | public boolean getHidden() { 72 | return hidden; 73 | } 74 | 75 | public void setHidden(boolean hidden) { 76 | this.hidden = hidden; 77 | } 78 | 79 | public String getRedirect() { 80 | return redirect; 81 | } 82 | 83 | public void setRedirect(String redirect) { 84 | this.redirect = redirect; 85 | } 86 | 87 | public String getComponent() { 88 | return component; 89 | } 90 | 91 | public void setComponent(String component) { 92 | this.component = component; 93 | } 94 | 95 | public Boolean getAlwaysShow() { 96 | return alwaysShow; 97 | } 98 | 99 | public void setAlwaysShow(Boolean alwaysShow) { 100 | this.alwaysShow = alwaysShow; 101 | } 102 | 103 | public MetaVo getMeta() { 104 | return meta; 105 | } 106 | 107 | public void setMeta(MetaVo meta) { 108 | this.meta = meta; 109 | } 110 | 111 | public List getChildren() { 112 | return children; 113 | } 114 | 115 | public void setChildren(List children) { 116 | this.children = children; 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/entity/ExamTestPaperResult.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableField; 7 | 8 | import java.io.Serializable; 9 | 10 | import io.swagger.annotations.ApiModel; 11 | import io.swagger.annotations.ApiModelProperty; 12 | import lombok.Data; 13 | import lombok.EqualsAndHashCode; 14 | import lombok.experimental.Accessors; 15 | 16 | /** 17 | *

18 | * 试卷结果表 19 | *

20 | * 21 | * @author ningning 22 | * @since 2021-06-01 23 | */ 24 | @Data 25 | @EqualsAndHashCode(callSuper = false) 26 | @Accessors(chain = true) 27 | @TableName("exam_test_paper_result") 28 | @ApiModel(value = "ExamTestPaperResult对象", description = "试卷结果表") 29 | public class ExamTestPaperResult implements Serializable { 30 | 31 | private static final long serialVersionUID = 1L; 32 | 33 | @ApiModelProperty(value = "主键") 34 | @TableId(value = "id", type = IdType.AUTO) 35 | private Integer id; 36 | 37 | @ApiModelProperty(value = "试卷ID") 38 | @TableField("testpaper_id") 39 | private Integer testpaperId; 40 | 41 | @ApiModelProperty(value = "试卷名") 42 | @TableField("testpaper_name") 43 | private String testpaperName; 44 | 45 | @ApiModelProperty(value = "答卷人ID") 46 | @TableField("user_id") 47 | private Integer userId; 48 | 49 | @ApiModelProperty(value = "总分") 50 | @TableField("score") 51 | private Float score; 52 | 53 | @ApiModelProperty(value = "主观题得分") 54 | @TableField("objective_score") 55 | private Float objectiveScore; 56 | 57 | @ApiModelProperty(value = "客观题得分") 58 | @TableField("subjective_score") 59 | private Float subjectiveScore; 60 | 61 | @ApiModelProperty(value = "老师评价") 62 | @TableField("teacher_say") 63 | private String teacherSay; 64 | 65 | @ApiModelProperty(value = "正确题目数") 66 | @TableField("right_item_count") 67 | private Integer rightItemCount; 68 | 69 | @ApiModelProperty(value = "答卷耗时(秒)") 70 | @TableField("used_time") 71 | private Integer usedTime; 72 | 73 | @ApiModelProperty(value = "试卷批阅状态(doing、paused、reviewing、finished)") 74 | @TableField("status") 75 | private String status; 76 | 77 | @ApiModelProperty(value = "批卷老师ID") 78 | @TableField("check_user_id") 79 | private Integer checkUserId; 80 | 81 | @ApiModelProperty(value = "批卷时间") 82 | @TableField("checked_time") 83 | private Integer checkedTime; 84 | 85 | @ApiModelProperty(value = "更新时间") 86 | @TableField("update_time") 87 | private Integer updateTime; 88 | 89 | } 90 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/java/com/ning/utils/ServletUtils.java: -------------------------------------------------------------------------------- 1 | package com.ning.utils; 2 | 3 | import cn.hutool.core.convert.Convert; 4 | import org.springframework.web.context.request.RequestAttributes; 5 | import org.springframework.web.context.request.RequestContextHolder; 6 | import org.springframework.web.context.request.ServletRequestAttributes; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import javax.servlet.http.HttpSession; 11 | import java.io.IOException; 12 | 13 | /** 14 | * 客户端工具类 15 | */ 16 | public class ServletUtils { 17 | 18 | /** 19 | * 获取String参数 20 | */ 21 | public static String getParameter(String name) { 22 | return getRequest().getParameter(name); 23 | } 24 | 25 | /** 26 | * 获取String参数 27 | */ 28 | public static String getParameter(String name, String defaultValue) { 29 | return Convert.toStr(getRequest().getParameter(name), defaultValue); 30 | } 31 | 32 | /** 33 | * 获取Integer参数 34 | */ 35 | public static Integer getParameterToInt(String name) { 36 | return Convert.toInt(getRequest().getParameter(name)); 37 | } 38 | 39 | /** 40 | * 获取Integer参数 41 | */ 42 | public static Integer getParameterToInt(String name, Integer defaultValue) { 43 | return Convert.toInt(getRequest().getParameter(name), defaultValue); 44 | } 45 | 46 | /** 47 | * 获取request 48 | */ 49 | public static HttpServletRequest getRequest() { 50 | return getRequestAttributes().getRequest(); 51 | } 52 | 53 | /** 54 | * 获取response 55 | */ 56 | public static HttpServletResponse getResponse() { 57 | return getRequestAttributes().getResponse(); 58 | } 59 | 60 | /** 61 | * 获取session 62 | */ 63 | public static HttpSession getSession() { 64 | return getRequest().getSession(); 65 | } 66 | 67 | public static ServletRequestAttributes getRequestAttributes() { 68 | RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); 69 | return (ServletRequestAttributes) attributes; 70 | } 71 | 72 | /** 73 | * 将字符串渲染到客户端 74 | * 75 | * @param response 渲染对象 76 | * @param string 待渲染的字符串 77 | * @return null 78 | */ 79 | public static String renderString(HttpServletResponse response, String string) { 80 | try { 81 | response.setStatus(200); 82 | response.setContentType("application/json"); 83 | response.setCharacterEncoding("utf-8"); 84 | response.getWriter().print(string); 85 | } catch (IOException e) { 86 | e.printStackTrace(); 87 | } 88 | return null; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/utils/ServletUtils.java: -------------------------------------------------------------------------------- 1 | package com.ning.utils; 2 | 3 | import cn.hutool.core.convert.Convert; 4 | import org.springframework.web.context.request.RequestAttributes; 5 | import org.springframework.web.context.request.RequestContextHolder; 6 | import org.springframework.web.context.request.ServletRequestAttributes; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import javax.servlet.http.HttpSession; 11 | import java.io.IOException; 12 | 13 | /** 14 | * 客户端工具类 15 | */ 16 | public class ServletUtils { 17 | 18 | /** 19 | * 获取String参数 20 | */ 21 | public static String getParameter(String name) { 22 | return getRequest().getParameter(name); 23 | } 24 | 25 | /** 26 | * 获取String参数 27 | */ 28 | public static String getParameter(String name, String defaultValue) { 29 | return Convert.toStr(getRequest().getParameter(name), defaultValue); 30 | } 31 | 32 | /** 33 | * 获取Integer参数 34 | */ 35 | public static Integer getParameterToInt(String name) { 36 | return Convert.toInt(getRequest().getParameter(name)); 37 | } 38 | 39 | /** 40 | * 获取Integer参数 41 | */ 42 | public static Integer getParameterToInt(String name, Integer defaultValue) { 43 | return Convert.toInt(getRequest().getParameter(name), defaultValue); 44 | } 45 | 46 | /** 47 | * 获取request 48 | */ 49 | public static HttpServletRequest getRequest() { 50 | return getRequestAttributes().getRequest(); 51 | } 52 | 53 | /** 54 | * 获取response 55 | */ 56 | public static HttpServletResponse getResponse() { 57 | return getRequestAttributes().getResponse(); 58 | } 59 | 60 | /** 61 | * 获取session 62 | */ 63 | public static HttpSession getSession() { 64 | return getRequest().getSession(); 65 | } 66 | 67 | public static ServletRequestAttributes getRequestAttributes() { 68 | RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); 69 | return (ServletRequestAttributes) attributes; 70 | } 71 | 72 | /** 73 | * 将字符串渲染到客户端 74 | * 75 | * @param response 渲染对象 76 | * @param string 待渲染的字符串 77 | * @return null 78 | */ 79 | public static String renderString(HttpServletResponse response, String string) { 80 | try { 81 | response.setStatus(200); 82 | response.setContentType("application/json"); 83 | response.setCharacterEncoding("utf-8"); 84 | response.getWriter().print(string); 85 | } catch (IOException e) { 86 | e.printStackTrace(); 87 | } 88 | return null; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/utils/ServletUtils.java: -------------------------------------------------------------------------------- 1 | package com.ning.utils; 2 | 3 | import cn.hutool.core.convert.Convert; 4 | import org.springframework.web.context.request.RequestAttributes; 5 | import org.springframework.web.context.request.RequestContextHolder; 6 | import org.springframework.web.context.request.ServletRequestAttributes; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import javax.servlet.http.HttpSession; 11 | import java.io.IOException; 12 | 13 | /** 14 | * 客户端工具类 15 | */ 16 | public class ServletUtils { 17 | 18 | /** 19 | * 获取String参数 20 | */ 21 | public static String getParameter(String name) { 22 | return getRequest().getParameter(name); 23 | } 24 | 25 | /** 26 | * 获取String参数 27 | */ 28 | public static String getParameter(String name, String defaultValue) { 29 | return Convert.toStr(getRequest().getParameter(name), defaultValue); 30 | } 31 | 32 | /** 33 | * 获取Integer参数 34 | */ 35 | public static Integer getParameterToInt(String name) { 36 | return Convert.toInt(getRequest().getParameter(name)); 37 | } 38 | 39 | /** 40 | * 获取Integer参数 41 | */ 42 | public static Integer getParameterToInt(String name, Integer defaultValue) { 43 | return Convert.toInt(getRequest().getParameter(name), defaultValue); 44 | } 45 | 46 | /** 47 | * 获取request 48 | */ 49 | public static HttpServletRequest getRequest() { 50 | return getRequestAttributes().getRequest(); 51 | } 52 | 53 | /** 54 | * 获取response 55 | */ 56 | public static HttpServletResponse getResponse() { 57 | return getRequestAttributes().getResponse(); 58 | } 59 | 60 | /** 61 | * 获取session 62 | */ 63 | public static HttpSession getSession() { 64 | return getRequest().getSession(); 65 | } 66 | 67 | public static ServletRequestAttributes getRequestAttributes() { 68 | RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); 69 | return (ServletRequestAttributes) attributes; 70 | } 71 | 72 | /** 73 | * 将字符串渲染到客户端 74 | * 75 | * @param response 渲染对象 76 | * @param string 待渲染的字符串 77 | * @return null 78 | */ 79 | public static String renderString(HttpServletResponse response, String string) { 80 | try { 81 | response.setStatus(200); 82 | response.setContentType("application/json"); 83 | response.setCharacterEncoding("utf-8"); 84 | response.getWriter().print(string); 85 | } catch (IOException e) { 86 | e.printStackTrace(); 87 | } 88 | return null; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/entity/ExamTestPaper.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableField; 7 | 8 | import java.io.Serializable; 9 | 10 | import io.swagger.annotations.ApiModel; 11 | import io.swagger.annotations.ApiModelProperty; 12 | import lombok.Data; 13 | import lombok.EqualsAndHashCode; 14 | import lombok.experimental.Accessors; 15 | 16 | /** 17 | *

18 | * 试卷表 19 | *

20 | * 21 | * @author ningning 22 | * @since 2021-06-03 23 | */ 24 | @Data 25 | @EqualsAndHashCode(callSuper = false) 26 | @Accessors(chain = true) 27 | @TableName("exam_test_paper") 28 | @ApiModel(value = "ExamTestPaper对象", description = "试卷表") 29 | public class ExamTestPaper implements Serializable { 30 | 31 | private static final long serialVersionUID = 1L; 32 | 33 | @ApiModelProperty(value = "主键") 34 | @TableId(value = "id", type = IdType.AUTO) 35 | private Integer id; 36 | 37 | @ApiModelProperty(value = "试卷类型(training、mock)") 38 | @TableField("type") 39 | private String type; 40 | 41 | @ApiModelProperty(value = "试卷名") 42 | @TableField("name") 43 | private String name; 44 | 45 | @ApiModelProperty(value = "限时(秒)") 46 | @TableField("limited_time") 47 | private Integer limitedTime; 48 | 49 | @ApiModelProperty(value = "允许考试次数 0 不限制次数") 50 | @TableField("times") 51 | private Integer times; 52 | 53 | @ApiModelProperty(value = "总分") 54 | @TableField("total_score") 55 | private Float totalScore; 56 | 57 | @ApiModelProperty(value = "及格分") 58 | @TableField("passed_score") 59 | private Float passedScore; 60 | 61 | @ApiModelProperty(value = "题目数量") 62 | @TableField("item_count") 63 | private Integer itemCount; 64 | 65 | @ApiModelProperty(value = "复制试卷ID") 66 | @TableField("copy_id") 67 | private Integer copyId; 68 | 69 | @ApiModelProperty(value = "是否使用 0 未使用 1 使用") 70 | @TableField("is_used") 71 | private Integer isUsed; 72 | 73 | @ApiModelProperty(value = "是否删除 0 未删除 1 已删除") 74 | @TableField("is_delete") 75 | private Integer isDelete; 76 | 77 | @ApiModelProperty(value = "创建者ID") 78 | @TableField("create_user_id") 79 | private Integer createUserId; 80 | 81 | @ApiModelProperty(value = "创建时间") 82 | @TableField("create_time") 83 | private Integer createTime; 84 | 85 | @ApiModelProperty(value = "更新者ID") 86 | @TableField("update_user_id") 87 | private Integer updateUserId; 88 | 89 | @ApiModelProperty(value = "更新时间") 90 | @TableField("update_time") 91 | private Integer updateTime; 92 | 93 | } 94 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/entity/Role.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | import com.baomidou.mybatisplus.annotation.TableField; 10 | 11 | import java.io.Serializable; 12 | import java.util.List; 13 | 14 | import com.fasterxml.jackson.annotation.JsonFormat; 15 | import io.swagger.annotations.ApiModel; 16 | import io.swagger.annotations.ApiModelProperty; 17 | import lombok.Data; 18 | import lombok.EqualsAndHashCode; 19 | import lombok.experimental.Accessors; 20 | 21 | /** 22 | *

23 | * 角色信息表 24 | *

25 | * 26 | * @author ningning 27 | * @since 2021-06-16 28 | */ 29 | @Data 30 | @EqualsAndHashCode(callSuper = false) 31 | @Accessors(chain = true) 32 | @TableName("role") 33 | @ApiModel(value = "Role对象", description = "角色信息表") 34 | public class Role implements Serializable { 35 | 36 | private static final long serialVersionUID = 1L; 37 | 38 | @ApiModelProperty(value = "角色ID") 39 | @TableId(value = "role_id", type = IdType.AUTO) 40 | private Long roleId; 41 | 42 | @ApiModelProperty(value = "角色名称") 43 | @TableField("role_name") 44 | private String roleName; 45 | 46 | @ApiModelProperty(value = "角色权限字符串") 47 | @TableField("role_key") 48 | private String roleKey; 49 | 50 | @ApiModelProperty(value = "显示顺序") 51 | @TableField("role_sort") 52 | private Integer roleSort; 53 | 54 | @ApiModelProperty(value = "数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)") 55 | @TableField("data_scope") 56 | private String dataScope; 57 | 58 | @ApiModelProperty(value = "角色状态(0正常 1停用)") 59 | @TableField("status") 60 | private String status; 61 | 62 | @ApiModelProperty(value = "删除标志(0代表存在 2代表删除)") 63 | @TableField("del_flag") 64 | private String delFlag; 65 | 66 | @ApiModelProperty(value = "创建者") 67 | @TableField("create_by") 68 | private String createBy; 69 | 70 | @ApiModelProperty(value = "创建时间") 71 | @TableField("create_time") 72 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 73 | private LocalDateTime createTime; 74 | 75 | @ApiModelProperty(value = "更新者") 76 | @TableField("update_by") 77 | private String updateBy; 78 | 79 | @ApiModelProperty(value = "更新时间") 80 | @TableField("update_time") 81 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 82 | private LocalDateTime updateTime; 83 | 84 | @ApiModelProperty(value = "备注") 85 | @TableField("remark") 86 | private String remark; 87 | 88 | @ApiModelProperty(value = "拥有的菜单id列表") 89 | @TableField(exist = false) 90 | private List ownedMenuIds; 91 | 92 | } 93 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/generator/ExamCodeGeneration.java: -------------------------------------------------------------------------------- 1 | package com.ning.generator; 2 | 3 | import com.baomidou.mybatisplus.generator.FastAutoGenerator; 4 | import com.baomidou.mybatisplus.generator.config.OutputFile; 5 | import com.baomidou.mybatisplus.generator.config.TemplateType; 6 | 7 | import java.util.Collections; 8 | 9 | /** 10 | * Exam模块代码生成器 11 | */ 12 | @SuppressWarnings("ALL") 13 | public class ExamCodeGeneration { 14 | 15 | private final static String MODULE = "/exam-ning-springcloud-system-exam"; 16 | 17 | private final static String DB_URL = "jdbc:mysql://127.0.0.1:3306/exam-ning-springcloud-exam?autoReconnect=true&useUnicode=true&characterEncoding=utf8"; 18 | private final static String DB_USERNAME = "root"; 19 | private final static String DB_PASSWORD = "123456"; 20 | 21 | public static void main(String[] args) { 22 | String projectPath = System.getProperty("user.dir") + MODULE; 23 | 24 | FastAutoGenerator.create(DB_URL, DB_USERNAME, DB_PASSWORD) 25 | .globalConfig(builder -> { 26 | builder.author("ningning") // 设置作者 27 | .disableOpenDir() // 禁止打开输出目录 28 | .fileOverride() // 覆盖已生成文件 29 | .outputDir(projectPath + "/src/main/java"); // 指定输出目录 30 | }) 31 | .packageConfig(builder -> { 32 | builder.parent("com.ning") // 设置父包名 33 | .mapper("dao") // 设置dao名 34 | .entity("entity") // 设置entity名 35 | .pathInfo(Collections.singletonMap(OutputFile.mapperXml, projectPath + "/src/main/resources/mapper/")); // 设置mapperXml生成路径 36 | }) 37 | .templateConfig(builder -> { 38 | builder.disable(TemplateType.CONTROLLER, TemplateType.SERVICE, TemplateType.SERVICEIMPL); // 排除controller、service、service impl 39 | }) 40 | .strategyConfig(builder -> { 41 | builder.entityBuilder() 42 | .enableLombok() // 开启lombok 43 | .enableTableFieldAnnotation() // 生成字段注解 44 | .formatFileName("%s"); // 格式化entity名称 45 | builder.mapperBuilder() 46 | .enableBaseColumnList() // 启用 BaseColumnList 47 | .enableBaseResultMap() // 启用 BaseResultMap 生成 48 | .formatMapperFileName("%sDao") // Mapper xml 命名方式 49 | .formatXmlFileName("%sMapper"); // mapper 命名方式 50 | builder.addInclude("") // 设置需要生成的表名 51 | .addTablePrefix(""); // 设置过滤表前缀 52 | }) 53 | .execute(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/generator/UserCodeGeneration.java: -------------------------------------------------------------------------------- 1 | package com.ning.generator; 2 | 3 | import com.baomidou.mybatisplus.generator.FastAutoGenerator; 4 | import com.baomidou.mybatisplus.generator.config.OutputFile; 5 | import com.baomidou.mybatisplus.generator.config.TemplateType; 6 | 7 | import java.util.Collections; 8 | 9 | /** 10 | * User模块代码生成器 11 | */ 12 | @SuppressWarnings("ALL") 13 | public class UserCodeGeneration { 14 | 15 | private final static String MODULE = "/exam-ning-springcloud-system-user"; 16 | 17 | private final static String DB_URL = "jdbc:mysql://127.0.0.1:3306/exam-ning-springcloud-user?autoReconnect=true&useUnicode=true&characterEncoding=utf8"; 18 | private final static String DB_USERNAME = "root"; 19 | private final static String DB_PASSWORD = "123456"; 20 | 21 | public static void main(String[] args) { 22 | String projectPath = System.getProperty("user.dir") + MODULE; 23 | 24 | FastAutoGenerator.create(DB_URL, DB_USERNAME, DB_PASSWORD) 25 | .globalConfig(builder -> { 26 | builder.author("ningning") // 设置作者 27 | .disableOpenDir() // 禁止打开输出目录 28 | .fileOverride() // 覆盖已生成文件 29 | .outputDir(projectPath + "/src/main/java"); // 指定输出目录 30 | }) 31 | .packageConfig(builder -> { 32 | builder.parent("com.ning") // 设置父包名 33 | .mapper("dao") // 设置dao名 34 | .entity("entity") // 设置entity名 35 | .pathInfo(Collections.singletonMap(OutputFile.mapperXml, projectPath + "/src/main/resources/mapper/")); // 设置mapperXml生成路径 36 | }) 37 | .templateConfig(builder -> { 38 | builder.disable(TemplateType.CONTROLLER, TemplateType.SERVICE, TemplateType.SERVICEIMPL); // 排除controller、service、service impl 39 | }) 40 | .strategyConfig(builder -> { 41 | builder.entityBuilder() 42 | .enableLombok() // 开启lombok 43 | .enableTableFieldAnnotation() // 生成字段注解 44 | .formatFileName("%s"); // 格式化entity名称 45 | builder.mapperBuilder() 46 | .enableBaseColumnList() // 启用 BaseColumnList 47 | .enableBaseResultMap() // 启用 BaseResultMap 生成 48 | .formatMapperFileName("%sDao") // Mapper xml 命名方式 49 | .formatXmlFileName("%sMapper"); // mapper 命名方式 50 | builder.addInclude("") // 设置需要生成的表名 51 | .addTablePrefix(""); // 设置过滤表前缀 52 | }) 53 | .execute(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/manager/ExamQuestionManager.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 | import com.baomidou.mybatisplus.core.metadata.IPage; 7 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 8 | import com.ning.dao.ExamQuestionDao; 9 | import com.ning.entity.ExamQuestion; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | 15 | @Component 16 | public class ExamQuestionManager { 17 | 18 | @Resource 19 | ExamQuestionDao examQuestionDao; 20 | 21 | /** 22 | * 分页查询考题列表 23 | * 24 | * @param type 25 | * @param keyword 26 | * @param pNum 27 | * @param pSize 28 | * @return 29 | */ 30 | public IPage selectExamQuestionPage(String type, String keyword, Integer pNum, Integer pSize) { 31 | // 分页对象 32 | IPage iPage = new Page<>(pNum, pSize); 33 | 34 | // 查询对象 35 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 36 | wrapper.eq(ExamQuestion::getIsDelete, 0); 37 | if (StrUtil.isNotEmpty(type)) { 38 | wrapper.eq(ExamQuestion::getType, type); 39 | } 40 | if (StrUtil.isNotEmpty(keyword)) { 41 | wrapper.like(ExamQuestion::getStem, keyword); 42 | } 43 | wrapper.orderByDesc(ExamQuestion::getCreateTime); 44 | 45 | return examQuestionDao.selectPage(iPage, wrapper); 46 | } 47 | 48 | /** 49 | * 添加考题 50 | * 51 | * @param examQuestion 52 | * @return 53 | */ 54 | public Integer add(ExamQuestion examQuestion) { 55 | return examQuestionDao.insert(examQuestion); 56 | } 57 | 58 | /** 59 | * 修改考题 60 | * 61 | * @param examQuestion 62 | * @return 63 | */ 64 | public Integer update(ExamQuestion examQuestion) { 65 | return examQuestionDao.updateById(examQuestion); 66 | } 67 | 68 | /** 69 | * 获取考题 70 | * 71 | * @param id 72 | * @return 73 | */ 74 | public ExamQuestion get(Integer id) { 75 | return examQuestionDao.selectById(id); 76 | } 77 | 78 | /** 79 | * 批量查询题目 80 | * 81 | * @param ids 82 | * @return 83 | */ 84 | public List selectBatchIds(List ids) { 85 | return examQuestionDao.selectBatchIds(ids); 86 | } 87 | 88 | /** 89 | * 批量修改题目使用数 90 | * 91 | * @param ids 92 | * @return 93 | */ 94 | public Integer updateUsedNumBatchIds(List ids) { 95 | return examQuestionDao.updateUsedNumBatchIds(ids); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/manager/ExamTestPaperResultManager.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 5 | import com.baomidou.mybatisplus.core.metadata.IPage; 6 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 7 | import com.ning.common.enums.ExamTestPaperResultStatusEnum; 8 | import com.ning.dao.ExamTestPaperResultDao; 9 | import com.ning.entity.ExamTestPaperResult; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | @Component 17 | public class ExamTestPaperResultManager { 18 | 19 | @Resource 20 | ExamTestPaperResultDao examTestPaperResultDao; 21 | 22 | public Integer insert(ExamTestPaperResult examTestPaperResult) { 23 | return examTestPaperResultDao.insert(examTestPaperResult); 24 | } 25 | 26 | public ExamTestPaperResult selectById(Integer id) { 27 | return examTestPaperResultDao.selectById(id); 28 | } 29 | 30 | public Integer updateById(ExamTestPaperResult examTestPaperResult) { 31 | return examTestPaperResultDao.updateById(examTestPaperResult); 32 | } 33 | 34 | /** 35 | * 查询用户的考试结果次数 36 | * 37 | * @param testPaperIds 38 | * @param userId 39 | * @return 40 | */ 41 | public List> selectExamResultTimes(List testPaperIds, Integer userId) { 42 | return examTestPaperResultDao.selectExamResultTimes(testPaperIds, userId); 43 | } 44 | 45 | /** 46 | * 查询考试结果列表 47 | * 48 | * @param id 49 | * @param userId 50 | * @return 51 | */ 52 | public List list(Integer id, Integer userId) { 53 | // 查询对象 54 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 55 | wrapper.eq(ExamTestPaperResult::getTestpaperId, id); 56 | wrapper.eq(ExamTestPaperResult::getUserId, userId); 57 | wrapper.orderByDesc(ExamTestPaperResult::getUpdateTime); 58 | return examTestPaperResultDao.selectList(wrapper); 59 | } 60 | 61 | /** 62 | * 分页查询待批阅列表 63 | * 64 | * @param pNum 65 | * @param pSize 66 | * @return 67 | */ 68 | public IPage selectPage(Integer pNum, Integer pSize) { 69 | // 分页对象 70 | IPage iPage = new Page<>(pNum, pSize); 71 | 72 | // 查询对象 73 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 74 | wrapper.eq(ExamTestPaperResult::getStatus, ExamTestPaperResultStatusEnum.REVIEWING.getType()); 75 | wrapper.orderByDesc(ExamTestPaperResult::getUpdateTime); 76 | return examTestPaperResultDao.selectPage(iPage, wrapper); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## 系统简介 2 | * 采用前后端分离的模式,前端框架选型vue-element-admin,前端代码地址: 3 | Gitee:https://gitee.com/ningzxspace/exam-ning-web-v1 4 | Github:https://github.com/ningzuoxin/exam-ning-web-v1 5 | * 后端采用Spring Boot、Spring Cloud & Alibaba、Mybatis-plus。 6 | * 注册中心、配置中心选型Nacos,权限认证使用OAuth2。 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 21 | 22 |
后端代码地址 11 | https://gitee.com/ningzxspace/exam-ning-springcloud-v1
12 | https://github.com/ningzuoxin/exam-ning-springcloud-v1 13 |
前端代码地址 18 | https://gitee.com/ningzxspace/exam-ning-web-v1
19 | https://github.com/ningzuoxin/exam-ning-web-v1 20 |
23 | 24 | ## 系统模块 25 | ~~~ 26 | exam-ning-springcloud-v1 27 | ├── doc // 文档 28 | ├── exam-ning-springcloud-api // 公共模块 29 | ├── exam-ning-springcloud-auth // 认证中心[9527] 30 | ├── exam-ning-springcloud-gateway // 网关模块[8080] 31 | ├── exam-ning-springcloud-system-exam // 考试模块[9201] 32 | ├── exam-ning-springcloud-system-user // 系统模块[9202] 33 | ~~~ 34 | 35 | ## 系统功能 36 | 1. 用户管理:添加用户及用户基本信息的维护。 37 | 2. 角色管理:角色信息的维护及对应权限范围的控制。 38 | 3. 菜单管理:菜单权限信息的维护。 39 | 4. 试卷管理:添加试卷、预览试卷、发布试卷、删除试卷。 40 | 5. 试题管理:试题的管理,分为单选、多线、填空、判断、简答5钟题型。 41 | 6. 考试管理:考试、阅卷(客观题自动阅卷)、查看错题。 42 | 43 | ## 演示图 44 | ![登录](doc/imgs/01登录.png) 45 | *** 46 | ![首页](doc/imgs/02首页.png) 47 | *** 48 | ![用户管理](doc/imgs/03用户管理.png) 49 | *** 50 | ![试卷列表](doc/imgs/04试卷列表.png) 51 | *** 52 | ![试题列表](doc/imgs/05试题列表.png) 53 | *** 54 | ![添加试题](doc/imgs/06添加试题.png) 55 | *** 56 | ![开始考试](doc/imgs/07开始考试.png) 57 | *** 58 | ![查看成绩](doc/imgs/08查看成绩.png) 59 | 60 | ## 部署文档 61 | 1. 初始化数据库,数据库脚本文件在doc/sql目录,分别创建 exam-ning-springcloud-exam 和 exam-ning-springcloud-user 数据库,导入对应sql文件。 62 | 2. 启动Nacos,下载Nacos,运行startup.cmd。参考:https://nacos.io/zh-cn/docs/quick-start.html 63 | ``` 64 | 【注意事项】 65 | 1、注意下 nacos 的版本,本项目依赖升级后 nacos-client 的版本是 2.0.3。 66 | 2、在使用 docker 启动 nacos 时,要注意同时暴露 9848 端口,参考如下命令: 67 | docker run --name nacos-server -e MODE=standalone -p 8848:8848 -p 9848:9848 -d nacos/nacos-server:latest 68 | ``` 69 | 3. 启动Redis。参考:https://www.cnblogs.com/skmobi/p/11696620.html 70 | 4. 依次启动exam-ning-springcloud-gateway、exam-ning-springcloud-auth、exam-ning-springcloud-system-exam、exam-ning-springcloud-system-user。 71 | 5. 下载前端代码:https://gitee.com/ningzxspace/exam-ning-web-v1 或 https://github.com/ningzuoxin/exam-ning-web-v1,安装依赖【npm install】,本地运行【npm run dev】。 72 | 6. 浏览器访问http://localhost:9528/,学生【student1/123456】、老师【teacher1/123456】、管理员【system/system】。 73 | 7. 接口文档地址:http://127.0.0.1:8080/swagger-ui.html 74 | 75 | ## 欢迎Star留言入群交流 76 | *** 77 | ![技术交流](doc/imgs/09技术交流.png) 78 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableField; 7 | 8 | import java.io.Serializable; 9 | import java.util.Set; 10 | 11 | import io.swagger.annotations.ApiModel; 12 | import io.swagger.annotations.ApiModelProperty; 13 | import lombok.Data; 14 | import lombok.EqualsAndHashCode; 15 | import lombok.experimental.Accessors; 16 | 17 | import javax.validation.constraints.NotEmpty; 18 | 19 | /** 20 | *

21 | * 用户表 22 | *

23 | * 24 | * @author ningning 25 | * @since 2020-09-15 26 | */ 27 | @Data 28 | @EqualsAndHashCode(callSuper = false) 29 | @Accessors(chain = true) 30 | @TableName("user") 31 | @ApiModel(value = "User对象", description = "用户表") 32 | public class User implements Serializable { 33 | 34 | private static final long serialVersionUID = 1L; 35 | 36 | @ApiModelProperty(value = "用户ID") 37 | @TableId(value = "id", type = IdType.AUTO) 38 | private Integer id; 39 | 40 | @NotEmpty(message = "账号不能为空") 41 | @ApiModelProperty(value = "账号") 42 | @TableField("username") 43 | private String username; 44 | 45 | @NotEmpty(message = "密码不能为空") 46 | @ApiModelProperty(value = "密码") 47 | @TableField("password") 48 | private String password; 49 | 50 | @NotEmpty(message = "邮箱不能为空") 51 | @ApiModelProperty(value = "邮箱") 52 | @TableField("email") 53 | private String email; 54 | 55 | @NotEmpty(message = "手机不能为空") 56 | @ApiModelProperty(value = "手机") 57 | @TableField("mobile") 58 | private String mobile; 59 | 60 | @ApiModelProperty(value = "密码盐") 61 | @TableField("salt") 62 | private String salt; 63 | 64 | @NotEmpty(message = "昵称不能为空") 65 | @ApiModelProperty(value = "昵称") 66 | @TableField("nickname") 67 | private String nickname; 68 | 69 | @ApiModelProperty(value = "身份证号") 70 | @TableField("idcard") 71 | private String idcard; 72 | 73 | @ApiModelProperty(value = "性别 0 未知 1 男 2 女") 74 | @TableField("gender") 75 | private Integer gender; 76 | 77 | @ApiModelProperty(value = "头像") 78 | @TableField("avatar") 79 | private String avatar; 80 | 81 | @ApiModelProperty(value = "是否删除 0 未删除 1 已删除") 82 | @TableField("is_delete") 83 | private Integer isDelete; 84 | 85 | @ApiModelProperty(value = "注册时间") 86 | @TableField("create_time") 87 | private Integer createTime; 88 | 89 | @ApiModelProperty(value = "最后更新时间") 90 | @TableField("update_time") 91 | private Integer updateTime; 92 | 93 | // 角色id 94 | @TableField(exist = false) 95 | private Long roleId; 96 | 97 | // 角色代码 98 | @TableField(exist = false) 99 | private Set roles; 100 | 101 | // 权限代码 102 | @TableField(exist = false) 103 | private Set permissions; 104 | 105 | } 106 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/security/CommonUserConverter.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import cn.hutool.core.convert.Convert; 4 | import cn.hutool.core.util.ObjectUtil; 5 | import com.ning.model.LoginUser; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.GrantedAuthority; 9 | import org.springframework.security.core.authority.AuthorityUtils; 10 | import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter; 11 | import org.springframework.util.StringUtils; 12 | 13 | import java.util.Collection; 14 | import java.util.LinkedHashMap; 15 | import java.util.Map; 16 | 17 | /** 18 | * https://my.oschina.net/giegie/blog/3023768 根据checktoken 的结果转化用户信息 19 | * 20 | * @author lengleng 21 | */ 22 | public class CommonUserConverter implements UserAuthenticationConverter { 23 | 24 | private static final String N_A = "N/A"; 25 | 26 | /** 27 | * 将授权信息返回到资源服务 28 | */ 29 | @Override 30 | public Map convertUserAuthentication(Authentication userAuthentication) { 31 | Map authMap = new LinkedHashMap<>(); 32 | authMap.put(USERNAME, userAuthentication.getName()); 33 | if (userAuthentication.getAuthorities() != null && !userAuthentication.getAuthorities().isEmpty()) { 34 | authMap.put(AUTHORITIES, AuthorityUtils.authorityListToSet(userAuthentication.getAuthorities())); 35 | } 36 | return authMap; 37 | } 38 | 39 | /** 40 | * 获取用户认证信息 41 | */ 42 | @Override 43 | public Authentication extractAuthentication(Map map) { 44 | if (map.containsKey(USERNAME)) { 45 | Collection authorities = getAuthorities(map); 46 | 47 | Long userId = Convert.toLong(map.get("user_id")); 48 | String username = (String) map.get("user_name"); 49 | LoginUser user = new LoginUser(userId, username, N_A, true, true, true, true, authorities); 50 | return new UsernamePasswordAuthenticationToken(user, N_A, authorities); 51 | } 52 | return null; 53 | } 54 | 55 | /** 56 | * 获取权限资源信息 57 | */ 58 | private Collection getAuthorities(Map map) { 59 | Object authorities = map.get(AUTHORITIES); 60 | if (authorities instanceof String) { 61 | return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities); 62 | } 63 | if (authorities instanceof Collection) { 64 | return AuthorityUtils.commaSeparatedStringToAuthorityList( 65 | StringUtils.collectionToCommaDelimitedString((Collection) authorities)); 66 | } 67 | if (ObjectUtil.isEmpty(authorities)) { 68 | return AuthorityUtils.commaSeparatedStringToAuthorityList(""); 69 | } 70 | throw new IllegalArgumentException("Authorities must be either a String or a Collection"); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/manager/UserManager.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 | import com.baomidou.mybatisplus.core.metadata.IPage; 7 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 8 | import com.ning.dao.UserDao; 9 | import com.ning.entity.User; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | 15 | @Component 16 | public class UserManager { 17 | 18 | @Resource 19 | UserDao userDao; 20 | 21 | /** 22 | * 根据账号查询用户信息 23 | * 24 | * @param username 25 | * @return 26 | */ 27 | public User selectUserByUsername(String username) { 28 | QueryWrapper wrapper = new QueryWrapper<>(); 29 | wrapper.eq("username", username); 30 | wrapper.eq("is_delete", 0); 31 | return userDao.selectOne(wrapper); 32 | } 33 | 34 | /** 35 | * 查询用户列表 36 | * 37 | * @return 38 | */ 39 | public List selectUsers() { 40 | return userDao.selectList(null); 41 | } 42 | 43 | /** 44 | * 分页查询用户列表 45 | * 46 | * @param keyword 47 | * @param pNum 48 | * @param pSize 49 | * @return 50 | */ 51 | public IPage selectUserPage(String keyword, Integer pNum, Integer pSize) { 52 | // 分页对象 53 | IPage iPage = new Page<>(pNum, pSize); 54 | 55 | // 查询对象 56 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 57 | wrapper.eq(User::getIsDelete, 0); 58 | if (StrUtil.isNotEmpty(keyword)) { 59 | wrapper.like(User::getNickname, keyword).or().like(User::getUsername, keyword).or().like(User::getEmail, keyword).or().like(User::getMobile, keyword); 60 | } 61 | wrapper.orderByDesc(User::getCreateTime); 62 | 63 | return userDao.selectPage(iPage, wrapper); 64 | } 65 | 66 | /** 67 | * 根据账号统计用户数 68 | * 69 | * @param username 70 | * @return 71 | */ 72 | public Long count(String username) { 73 | return userDao.selectCount(new QueryWrapper().lambda().eq(User::getIsDelete, 0).eq(User::getUsername, username)); 74 | } 75 | 76 | /** 77 | * 添加用户 78 | * 79 | * @param user 80 | * @return 81 | */ 82 | public Integer add(User user) { 83 | return userDao.insert(user); 84 | } 85 | 86 | /** 87 | * 修改用户 88 | * 89 | * @param user 90 | * @return 91 | */ 92 | public Integer edit(User user) { 93 | return userDao.updateById(user); 94 | } 95 | 96 | /** 97 | * 根据id查询用户 98 | * 99 | * @param id 100 | * @return 101 | */ 102 | public User getUserById(Integer id) { 103 | return userDao.selectById(id); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/security/CommonUserConverter.java: -------------------------------------------------------------------------------- 1 | package com.ning.security; 2 | 3 | import cn.hutool.core.convert.Convert; 4 | import cn.hutool.core.util.ObjectUtil; 5 | import com.ning.model.LoginUser; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.GrantedAuthority; 9 | import org.springframework.security.core.authority.AuthorityUtils; 10 | import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter; 11 | import org.springframework.util.StringUtils; 12 | 13 | import java.util.Collection; 14 | import java.util.LinkedHashMap; 15 | import java.util.Map; 16 | 17 | /** 18 | * https://my.oschina.net/giegie/blog/3023768 根据checktoken 的结果转化用户信息 19 | * 20 | * @author lengleng 21 | */ 22 | public class CommonUserConverter implements UserAuthenticationConverter { 23 | 24 | private static final String N_A = "N/A"; 25 | 26 | /** 27 | * 将授权信息返回到资源服务 28 | */ 29 | @Override 30 | public Map convertUserAuthentication(Authentication userAuthentication) { 31 | Map authMap = new LinkedHashMap<>(); 32 | authMap.put(USERNAME, userAuthentication.getName()); 33 | if (userAuthentication.getAuthorities() != null && !userAuthentication.getAuthorities().isEmpty()) { 34 | authMap.put(AUTHORITIES, AuthorityUtils.authorityListToSet(userAuthentication.getAuthorities())); 35 | } 36 | return authMap; 37 | } 38 | 39 | /** 40 | * 获取用户认证信息 41 | */ 42 | @Override 43 | public Authentication extractAuthentication(Map map) { 44 | if (map.containsKey(USERNAME)) { 45 | Collection authorities = getAuthorities(map); 46 | 47 | Long userId = Convert.toLong(map.get("user_id")); 48 | String username = (String) map.get("user_name"); 49 | LoginUser user = new LoginUser(userId, username, N_A, true, true, true, true, authorities); 50 | return new UsernamePasswordAuthenticationToken(user, N_A, authorities); 51 | } 52 | return null; 53 | } 54 | 55 | /** 56 | * 获取权限资源信息 57 | */ 58 | private Collection getAuthorities(Map map) { 59 | Object authorities = map.get(AUTHORITIES); 60 | if (authorities instanceof String) { 61 | return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities); 62 | } 63 | if (authorities instanceof Collection) { 64 | return AuthorityUtils.commaSeparatedStringToAuthorityList( 65 | StringUtils.collectionToCommaDelimitedString((Collection) authorities)); 66 | } 67 | if (ObjectUtil.isEmpty(authorities)) { 68 | return AuthorityUtils.commaSeparatedStringToAuthorityList(""); 69 | } 70 | throw new IllegalArgumentException("Authorities must be either a String or a Collection"); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/controller/RoleController.java: -------------------------------------------------------------------------------- 1 | package com.ning.controller; 2 | 3 | import com.ning.entity.Role; 4 | import com.ning.model.Result; 5 | import com.ning.service.RoleService; 6 | import com.ning.utils.SecurityUtils; 7 | import io.swagger.annotations.ApiOperation; 8 | import io.swagger.annotations.ApiParam; 9 | import org.springframework.security.access.prepost.PreAuthorize; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import javax.annotation.Resource; 13 | import java.time.LocalDateTime; 14 | import java.util.List; 15 | 16 | @RestController 17 | @RequestMapping(value = "/role/") 18 | public class RoleController { 19 | 20 | @Resource 21 | RoleService roleService; 22 | 23 | @PreAuthorize("@ss.hasPermi('system:role:page')") 24 | @GetMapping(value = "/page") 25 | @ApiOperation(value = "分页查询角色列表") 26 | public Result page(@RequestParam(value = "keyword", required = false) @ApiParam(name = "keyword", example = "") String keyword, 27 | @RequestParam(value = "pNum", defaultValue = "1") @ApiParam(name = "pNum", example = "1") Integer pNum, 28 | @RequestParam(value = "pSize", defaultValue = "10") @ApiParam(name = "pSize", example = "10") Integer pSize) { 29 | return roleService.selectPage(keyword, pNum, pSize); 30 | } 31 | 32 | @PreAuthorize("@ss.hasPermi('system:role:add')") 33 | @PostMapping(value = "/add") 34 | @ApiOperation(value = "添加角色") 35 | public Result add(@RequestBody Role role, @RequestParam List menuIds) { 36 | LocalDateTime now = LocalDateTime.now(); 37 | 38 | role.setDataScope("1"); // 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) 39 | role.setStatus("0"); // 角色状态(0正常 1停用) 40 | role.setDelFlag("0"); // 删除标志(0代表存在 2代表删除) 41 | role.setCreateTime(now); 42 | role.setUpdateTime(now); 43 | role.setCreateBy(SecurityUtils.getLoginUser().getUserId() + ""); 44 | role.setUpdateBy(SecurityUtils.getLoginUser().getUserId() + ""); 45 | return roleService.add(role, menuIds); 46 | } 47 | 48 | @GetMapping(value = "/get") 49 | @ApiOperation(value = "查询角色") 50 | public Result get(@RequestParam(value = "id") @ApiParam(name = "id", example = "1") Long id) { 51 | return roleService.get(id); 52 | } 53 | 54 | @PreAuthorize("@ss.hasPermi('system:role:delete')") 55 | @GetMapping(value = "/delete") 56 | @ApiOperation(value = "删除角色") 57 | public Result delete(@RequestParam(value = "id") @ApiParam(name = "id", example = "1") Long id) { 58 | return roleService.delete(id); 59 | } 60 | 61 | @PreAuthorize("@ss.hasPermi('system:role:update')") 62 | @PostMapping(value = "/update") 63 | @ApiOperation(value = "修改角色") 64 | public Result update(@RequestBody Role role, @RequestParam List menuIds) { 65 | return roleService.update(role, menuIds); 66 | } 67 | 68 | @GetMapping(value = "/list") 69 | @ApiOperation(value = "查询所有角色") 70 | public Result list() { 71 | return roleService.list(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/entity/ExamQuestion.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableField; 7 | 8 | import java.io.Serializable; 9 | 10 | import io.swagger.annotations.ApiModel; 11 | import io.swagger.annotations.ApiModelProperty; 12 | import lombok.Data; 13 | import lombok.EqualsAndHashCode; 14 | import lombok.experimental.Accessors; 15 | 16 | import javax.validation.constraints.NotEmpty; 17 | 18 | /** 19 | *

20 | * 考题表 21 | *

22 | * 23 | * @author ningning 24 | * @since 2021-06-04 25 | */ 26 | @Data 27 | @EqualsAndHashCode(callSuper = false) 28 | @Accessors(chain = true) 29 | @TableName("exam_question") 30 | @ApiModel(value = "ExamQuestion对象", description = "考题表") 31 | public class ExamQuestion implements Serializable { 32 | 33 | private static final long serialVersionUID = 1L; 34 | 35 | @ApiModelProperty(value = "主键") 36 | @TableId(value = "id", type = IdType.AUTO) 37 | private Integer id; 38 | 39 | @NotEmpty(message = "题目类型不能为空") 40 | @ApiModelProperty(value = "题目类型") 41 | @TableField("type") 42 | private String type; 43 | 44 | @NotEmpty(message = "题干不能为空") 45 | @ApiModelProperty(value = "题干") 46 | @TableField("stem") 47 | private String stem; 48 | 49 | @ApiModelProperty(value = "分数") 50 | @TableField("score") 51 | private Float score; 52 | 53 | @NotEmpty(message = "参考答案不能为空") 54 | @ApiModelProperty(value = "参考答案") 55 | @TableField("answer") 56 | private String answer; 57 | 58 | @ApiModelProperty(value = "解析") 59 | @TableField("analysis") 60 | private String analysis; 61 | 62 | @ApiModelProperty(value = "题目元信息") 63 | @TableField("metas") 64 | private String metas; 65 | 66 | @ApiModelProperty(value = "分类ID") 67 | @TableField("category_id") 68 | private Integer categoryId; 69 | 70 | @ApiModelProperty(value = "被试卷使用数") 71 | @TableField("used_num") 72 | private Integer usedNum; 73 | 74 | @ApiModelProperty(value = "是否删除 0 未删除 1 已删除") 75 | @TableField("is_delete") 76 | private Integer isDelete; 77 | 78 | @ApiModelProperty(value = "是否显示 0 显示 1 不显示") 79 | @TableField("is_show") 80 | private Integer isShow; 81 | 82 | @ApiModelProperty(value = "创建者ID") 83 | @TableField("create_user_id") 84 | private Integer createUserId; 85 | 86 | @ApiModelProperty(value = "创建时间") 87 | @TableField("create_time") 88 | private Integer createTime; 89 | 90 | @ApiModelProperty(value = "更新者ID") 91 | @TableField("update_user_id") 92 | private Integer updateUserId; 93 | 94 | @ApiModelProperty(value = "更新时间") 95 | @TableField("update_time") 96 | private Integer updateTime; 97 | 98 | @ApiModelProperty(value = "复制题目ID") 99 | @TableField("copy_id") 100 | private Integer copyId; 101 | 102 | } 103 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/manager/RoleManager.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 | import com.baomidou.mybatisplus.core.metadata.IPage; 7 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 8 | import com.ning.dao.RoleDao; 9 | import com.ning.entity.Role; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | 15 | @Component 16 | public class RoleManager { 17 | 18 | @Resource 19 | RoleDao roleDao; 20 | 21 | /** 22 | * 分页查询角色列表 23 | * 24 | * @param keyword 25 | * @param pNum 26 | * @param pSize 27 | * @return 28 | */ 29 | public IPage selectPage(String keyword, Integer pNum, Integer pSize) { 30 | // 分页对象 31 | IPage iPage = new Page<>(pNum, pSize); 32 | 33 | // 查询对象 34 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 35 | wrapper.eq(Role::getDelFlag, 0); 36 | if (StrUtil.isNotEmpty(keyword)) { 37 | wrapper.like(Role::getRoleName, keyword); 38 | } 39 | wrapper.orderByDesc(Role::getUpdateTime); 40 | wrapper.orderByAsc(Role::getRoleSort); 41 | 42 | return roleDao.selectPage(iPage, wrapper); 43 | } 44 | 45 | /** 46 | * 根据角色代码统计 47 | * 48 | * @param roleKey 49 | * @return 50 | */ 51 | public Long selectCount(String roleKey) { 52 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 53 | wrapper.eq(Role::getDelFlag, 0); 54 | wrapper.eq(Role::getRoleKey, roleKey); 55 | 56 | return roleDao.selectCount(wrapper); 57 | } 58 | 59 | /** 60 | * 添加角色 61 | * 62 | * @param role 63 | * @return 64 | */ 65 | public Integer insert(Role role) { 66 | return roleDao.insert(role); 67 | } 68 | 69 | /** 70 | * 查询角色 71 | * 72 | * @param id 73 | * @return 74 | */ 75 | public Role selectById(Long id) { 76 | return roleDao.selectById(id); 77 | } 78 | 79 | /** 80 | * 修改角色 81 | * 82 | * @param role 83 | * @return 84 | */ 85 | public Integer updateById(Role role) { 86 | return roleDao.updateById(role); 87 | } 88 | 89 | /** 90 | * 查询所有角色 91 | * 92 | * @return 93 | */ 94 | public List listAllRole() { 95 | // 查询对象 96 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 97 | wrapper.eq(Role::getDelFlag, 0); 98 | return roleDao.selectList(wrapper); 99 | } 100 | 101 | /** 102 | * 根据用户id查询角色代码 103 | * 104 | * @param userId 105 | * @return 106 | */ 107 | public String getRoleKeyByUserId(Long userId) { 108 | return roleDao.getRoleKeyByUserId(userId); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.ning.controller; 2 | 3 | import cn.hutool.core.date.DateUtil; 4 | import com.ning.constant.CommonConstants; 5 | import com.ning.entity.User; 6 | import com.ning.model.Result; 7 | import com.ning.service.UserService; 8 | import io.swagger.annotations.ApiOperation; 9 | import io.swagger.annotations.ApiParam; 10 | import org.springframework.security.access.prepost.PreAuthorize; 11 | import org.springframework.web.bind.annotation.*; 12 | 13 | import javax.annotation.Resource; 14 | import javax.validation.Valid; 15 | import java.util.List; 16 | 17 | @RestController 18 | @RequestMapping(value = "/user/") 19 | public class UserController { 20 | 21 | @Resource 22 | UserService userService; 23 | 24 | @PostMapping(value = "/selectUserByUsername") 25 | @ApiOperation(value = "根据用户名查询用户信息") 26 | public Result selectUserByUsername(@RequestParam(value = "username") @ApiParam(name = "username", example = "admin") String username) { 27 | return userService.selectUserByUsername(username); 28 | } 29 | 30 | @GetMapping(value = "/selectUsers") 31 | @ApiOperation(value = "查询用户列表") 32 | public Result> selectUsers() { 33 | return userService.selectUsers(); 34 | } 35 | 36 | @PreAuthorize("@ss.hasPermi('system:user:page')") 37 | @GetMapping(value = "/page") 38 | @ApiOperation(value = "分页查询用户列表") 39 | public Result selectPage(@RequestParam(value = "keyword", required = false) @ApiParam(name = "keyword", example = "") String keyword, 40 | @RequestParam(value = "pNum", defaultValue = "1") @ApiParam(name = "pNum", example = "1") Integer pNum, 41 | @RequestParam(value = "pSize", defaultValue = "10") @ApiParam(name = "pSize", example = "10") Integer pSize) { 42 | return userService.selectUserPage(keyword, pNum, pSize); 43 | } 44 | 45 | @PreAuthorize("@ss.hasPermi('system:user:add')") 46 | @PostMapping(value = "/add") 47 | @ApiOperation(value = "添加用户") 48 | public Result addUser(@RequestBody @Valid User user) { 49 | int now = (int) DateUtil.currentSeconds(); 50 | 51 | user.setSalt(CommonConstants.DEFAULT_SALT); 52 | user.setIsDelete(0); 53 | user.setCreateTime(now); 54 | user.setUpdateTime(now); 55 | return userService.addUser(user); 56 | } 57 | 58 | @PreAuthorize("@ss.hasPermi('system:user:edit')") 59 | @PostMapping(value = "/update") 60 | @ApiOperation(value = "修改用户") 61 | public Result update(@RequestBody @Valid User user) { 62 | return userService.update(user); 63 | } 64 | 65 | @PreAuthorize("@ss.hasPermi('system:user:delete')") 66 | @PostMapping(value = "/delete") 67 | @ApiOperation(value = "删除用户") 68 | public Result delete(@RequestParam(value = "id") @ApiParam(name = "id", example = "1") Integer id) { 69 | return userService.delete(id); 70 | } 71 | 72 | @GetMapping(value = "/get") 73 | @ApiOperation(value = "获取单个用户") 74 | public Result get(@RequestParam(value = "id") @ApiParam(name = "id", example = "1") Integer id) { 75 | return userService.get(id); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /exam-ning-springcloud-auth/src/main/java/com/ning/controller/OauthController.java: -------------------------------------------------------------------------------- 1 | package com.ning.controller; 2 | 3 | import cn.hutool.core.util.ObjectUtil; 4 | import cn.hutool.core.util.StrUtil; 5 | import com.ning.model.Result; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 8 | import org.springframework.security.oauth2.common.OAuth2RefreshToken; 9 | import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint; 10 | import org.springframework.security.oauth2.provider.token.TokenStore; 11 | import org.springframework.web.HttpRequestMethodNotSupportedException; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import javax.annotation.Resource; 15 | import java.security.Principal; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | @Slf4j 20 | @RestController 21 | @RequestMapping("/oauth") 22 | public class OauthController { 23 | 24 | @Resource 25 | private TokenStore tokenStore; 26 | 27 | @Resource 28 | private TokenEndpoint tokenEndpoint; 29 | 30 | @RequestMapping("/user") 31 | public Principal user(Principal user) { 32 | log.info("OauthController # user Principal={}", user); 33 | return user; 34 | } 35 | 36 | /** 37 | * 重写认证端口(/oauth/token),以自定义格式返回数据 38 | * 39 | * @param principal 40 | * @param parameters 41 | * @return 42 | * @throws HttpRequestMethodNotSupportedException 43 | */ 44 | @RequestMapping(value = "/token", method = RequestMethod.POST) 45 | public Result postAccessToken(Principal principal, @RequestParam Map parameters) throws HttpRequestMethodNotSupportedException { 46 | OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody(); 47 | Map additionalInformation = oAuth2AccessToken.getAdditionalInformation(); 48 | 49 | Map map = new HashMap<>(); 50 | map.put("access_token", oAuth2AccessToken.getValue()); 51 | map.put("expires_in", oAuth2AccessToken.getExpiresIn()); 52 | map.put("user_id", additionalInformation.get("user_id")); 53 | map.put("user_name", additionalInformation.get("user_name")); 54 | return Result.ok(map); 55 | } 56 | 57 | @GetMapping("/logout") 58 | public Result logout(@RequestHeader(value = "Authorization", required = false) String token) { 59 | if (StrUtil.isEmpty(token)) { 60 | return Result.ok(""); 61 | } 62 | 63 | String tokenValue = token.replace(OAuth2AccessToken.BEARER_TYPE, StrUtil.EMPTY).trim(); 64 | OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue); 65 | if (accessToken == null || StrUtil.isEmpty(accessToken.getValue())) { 66 | return Result.ok(""); 67 | } 68 | 69 | // 清空 access token 70 | tokenStore.removeAccessToken(accessToken); 71 | 72 | // 清空 refresh token 73 | OAuth2RefreshToken refreshToken = accessToken.getRefreshToken(); 74 | if (ObjectUtil.isNotEmpty(refreshToken)) { 75 | tokenStore.removeRefreshToken(refreshToken); 76 | } 77 | 78 | return Result.ok(""); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/controller/MenuController.java: -------------------------------------------------------------------------------- 1 | package com.ning.controller; 2 | 3 | import com.ning.entity.Menu; 4 | import com.ning.model.Result; 5 | import com.ning.service.MenuService; 6 | import com.ning.utils.SecurityUtils; 7 | import io.swagger.annotations.ApiOperation; 8 | import io.swagger.annotations.ApiParam; 9 | import org.springframework.security.access.prepost.PreAuthorize; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import javax.annotation.Resource; 13 | import java.time.LocalDateTime; 14 | 15 | /** 16 | * 菜单管理 17 | */ 18 | @RestController 19 | @RequestMapping(value = "/menu/") 20 | public class MenuController { 21 | 22 | @Resource 23 | MenuService menuService; 24 | 25 | @PreAuthorize("@ss.hasPermi('system:menu:page')") 26 | @GetMapping(value = "/page") 27 | @ApiOperation(value = "分页查询菜单列表") 28 | public Result page(@RequestParam(value = "keyword", required = false) @ApiParam(name = "keyword", example = "") String keyword, 29 | @RequestParam(value = "pNum", defaultValue = "1") @ApiParam(name = "pNum", example = "1") Integer pNum, 30 | @RequestParam(value = "pSize", defaultValue = "10") @ApiParam(name = "pSize", example = "10") Integer pSize) { 31 | return menuService.selectPage(keyword, pNum, pSize); 32 | } 33 | 34 | @PreAuthorize("@ss.hasPermi('system:menu:add')") 35 | @PostMapping(value = "/add") 36 | @ApiOperation(value = "添加菜单") 37 | public Result add(@RequestBody Menu menu) { 38 | LocalDateTime now = LocalDateTime.now(); 39 | menu.setCreateBy(SecurityUtils.getLoginUser().getUserId() + ""); 40 | menu.setUpdateBy(SecurityUtils.getLoginUser().getUserId() + ""); 41 | menu.setCreateTime(now); 42 | menu.setUpdateTime(now); 43 | return menuService.add(menu); 44 | } 45 | 46 | @GetMapping(value = "/queryMC") 47 | @ApiOperation(value = "查询目录和菜单") 48 | public Result queryMC() { 49 | return menuService.queryMC(); 50 | } 51 | 52 | @GetMapping(value = "/tree") 53 | @ApiOperation(value = "查询菜单树形列表") 54 | public Result tree() { 55 | return menuService.tree(); 56 | } 57 | 58 | @GetMapping(value = "/getRouters") 59 | @ApiOperation(value = "查询路由") 60 | public Result getRouters() { 61 | return menuService.getRouters(SecurityUtils.getLoginUser().getUserId()); 62 | } 63 | 64 | @GetMapping(value = "/get") 65 | @ApiOperation(value = "根据id查询菜单") 66 | public Result get(@RequestParam(value = "id") @ApiParam(name = "id", example = "1") Long id) { 67 | return menuService.get(id); 68 | } 69 | 70 | @PreAuthorize("@ss.hasPermi('system:menu:update')") 71 | @PostMapping(value = "/update") 72 | @ApiOperation(value = "修改菜单") 73 | public Result update(@RequestBody Menu menu) { 74 | menu.setUpdateBy(SecurityUtils.getLoginUser().getUserId() + ""); 75 | menu.setUpdateTime(LocalDateTime.now()); 76 | return menuService.update(menu); 77 | } 78 | 79 | @PreAuthorize("@ss.hasPermi('system:menu:delete')") 80 | @GetMapping(value = "/delete") 81 | @ApiOperation(value = "删除菜单") 82 | public Result delete(@RequestParam(value = "id") @ApiParam(name = "id", example = "1") Long id) { 83 | return menuService.delete(id); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/entity/Menu.java: -------------------------------------------------------------------------------- 1 | package com.ning.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | import com.baomidou.mybatisplus.annotation.TableField; 10 | 11 | import java.io.Serializable; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | import com.fasterxml.jackson.annotation.JsonFormat; 16 | import io.swagger.annotations.ApiModel; 17 | import io.swagger.annotations.ApiModelProperty; 18 | import lombok.Data; 19 | import lombok.EqualsAndHashCode; 20 | import lombok.experimental.Accessors; 21 | 22 | /** 23 | *

24 | * 菜单权限表 25 | *

26 | * 27 | * @author ningning 28 | * @since 2021-06-16 29 | */ 30 | @Data 31 | @EqualsAndHashCode(callSuper = false) 32 | @Accessors(chain = true) 33 | @TableName("menu") 34 | @ApiModel(value = "Menu对象", description = "菜单权限表") 35 | public class Menu implements Serializable { 36 | 37 | private static final long serialVersionUID = 1L; 38 | 39 | @ApiModelProperty(value = "菜单ID") 40 | @TableId(value = "menu_id", type = IdType.AUTO) 41 | private Long menuId; 42 | 43 | @ApiModelProperty(value = "菜单名称") 44 | @TableField("menu_name") 45 | private String menuName; 46 | 47 | @ApiModelProperty(value = "父菜单ID") 48 | @TableField("parent_id") 49 | private Long parentId; 50 | 51 | @ApiModelProperty(value = "显示顺序") 52 | @TableField("order_num") 53 | private Integer orderNum; 54 | 55 | @ApiModelProperty(value = "路由地址") 56 | @TableField("path") 57 | private String path; 58 | 59 | @ApiModelProperty(value = "组件路径") 60 | @TableField("component") 61 | private String component; 62 | 63 | @ApiModelProperty(value = "是否为外链(0是 1否)") 64 | @TableField("is_frame") 65 | private Integer isFrame; 66 | 67 | @ApiModelProperty(value = "菜单类型(M目录 C菜单 F按钮)") 68 | @TableField("menu_type") 69 | private String menuType; 70 | 71 | @ApiModelProperty(value = "菜单状态(0显示 1隐藏)") 72 | @TableField("visible") 73 | private String visible; 74 | 75 | @ApiModelProperty(value = "菜单状态(0正常 1停用)") 76 | @TableField("status") 77 | private String status; 78 | 79 | @ApiModelProperty(value = "权限标识") 80 | @TableField("perms") 81 | private String perms; 82 | 83 | @ApiModelProperty(value = "菜单图标") 84 | @TableField("icon") 85 | private String icon; 86 | 87 | @ApiModelProperty(value = "创建者") 88 | @TableField("create_by") 89 | private String createBy; 90 | 91 | @ApiModelProperty(value = "创建时间") 92 | @TableField("create_time") 93 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 94 | private LocalDateTime createTime; 95 | 96 | @ApiModelProperty(value = "更新者") 97 | @TableField("update_by") 98 | private String updateBy; 99 | 100 | @ApiModelProperty(value = "更新时间") 101 | @TableField("update_time") 102 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 103 | private LocalDateTime updateTime; 104 | 105 | @ApiModelProperty(value = "备注") 106 | @TableField("remark") 107 | private String remark; 108 | 109 | @TableField(exist = false) 110 | private List children = new ArrayList<>(); 111 | 112 | } 113 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-exam/src/main/java/com/ning/controller/ExamQuestionController.java: -------------------------------------------------------------------------------- 1 | package com.ning.controller; 2 | 3 | import cn.hutool.core.date.DateUtil; 4 | import com.ning.common.enums.ExamQuestionTypeEnum; 5 | import com.ning.entity.ExamQuestion; 6 | import com.ning.model.Result; 7 | import com.ning.service.ExamQuestionService; 8 | import com.ning.utils.SecurityUtils; 9 | import io.swagger.annotations.ApiOperation; 10 | import io.swagger.annotations.ApiParam; 11 | import org.springframework.security.access.prepost.PreAuthorize; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import javax.annotation.Resource; 15 | import javax.validation.Valid; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | @RequestMapping(value = "/question/") 20 | @RestController 21 | public class ExamQuestionController { 22 | 23 | @Resource 24 | ExamQuestionService examQuestionService; 25 | 26 | @GetMapping(value = "/type") 27 | @ApiOperation(value = "查询题型") 28 | public Result>> types() { 29 | return Result.ok(ExamQuestionTypeEnum.listExamQuestionTypes()); 30 | } 31 | 32 | @PreAuthorize("@ss.hasPermi('exam:question:page')") 33 | @GetMapping(value = "/page") 34 | @ApiOperation(value = "分页查询考题列表") 35 | public Result selectPage(@RequestParam(value = "type", required = false) @ApiParam(name = "type", example = "") String type, 36 | @RequestParam(value = "keyword", required = false) @ApiParam(name = "keyword", example = "") String keyword, 37 | @RequestParam(value = "pNum", defaultValue = "1") @ApiParam(name = "pNum", example = "1") Integer pNum, 38 | @RequestParam(value = "pSize", defaultValue = "10") @ApiParam(name = "pSize", example = "10") Integer pSize) { 39 | return examQuestionService.selectExamQuestionPage(type, keyword, pNum, pSize); 40 | } 41 | 42 | @PreAuthorize("@ss.hasPermi('exam:question:add')") 43 | @PostMapping(value = "/add") 44 | @ApiOperation(value = "添加考题") 45 | public Result add(@RequestBody @Valid ExamQuestion examQuestion) { 46 | int now = (int) DateUtil.currentSeconds(); 47 | examQuestion.setIsDelete(0); 48 | examQuestion.setCreateTime(now); 49 | examQuestion.setUpdateTime(now); 50 | examQuestion.setCreateUserId(SecurityUtils.getLoginUser().getUserId().intValue()); 51 | examQuestion.setUpdateUserId(SecurityUtils.getLoginUser().getUserId().intValue()); 52 | return examQuestionService.add(examQuestion); 53 | } 54 | 55 | @PostMapping(value = "/updateIsShow") 56 | @ApiOperation(value = "修改考题显示状态") 57 | public Result updateIsShow(@RequestParam(value = "id") @ApiParam(name = "id", example = "1") Integer id, 58 | @RequestParam(value = "isShow") @ApiParam(name = "isShow", example = "1") Integer isShow) { 59 | return examQuestionService.updateIsShow(id, isShow); 60 | } 61 | 62 | @GetMapping(value = "/delete") 63 | @ApiOperation(value = "删除考题") 64 | public Result delete(@RequestParam(value = "id") @ApiParam(name = "id", example = "1") Integer id) { 65 | return examQuestionService.delete(id); 66 | } 67 | 68 | @GetMapping(value = "/detail") 69 | @ApiOperation(value = "考题详情") 70 | public Result detail(@RequestParam(value = "id") @ApiParam(name = "id", example = "1") Integer id) { 71 | return examQuestionService.detail(id); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /exam-ning-springcloud-system-user/src/main/java/com/ning/manager/MenuManager.java: -------------------------------------------------------------------------------- 1 | package com.ning.manager; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 | import com.baomidou.mybatisplus.core.metadata.IPage; 7 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 8 | import com.ning.dao.MenuDao; 9 | import com.ning.entity.Menu; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | import java.util.stream.Collectors; 15 | 16 | @Component 17 | public class MenuManager { 18 | 19 | @Resource 20 | MenuDao menuDao; 21 | 22 | /** 23 | * 分页查询菜单列表 24 | * 25 | * @param keyword 26 | * @param pNum 27 | * @param pSize 28 | * @return 29 | */ 30 | public IPage selectPage(String keyword, Integer pNum, Integer pSize) { 31 | // 分页对象 32 | IPage iPage = new Page<>(pNum, pSize); 33 | 34 | // 查询对象 35 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 36 | wrapper.eq(Menu::getStatus, "0"); 37 | if (StrUtil.isNotEmpty(keyword)) { 38 | wrapper.like(Menu::getMenuName, keyword); 39 | } 40 | wrapper.orderByAsc(Menu::getParentId, Menu::getOrderNum, Menu::getUpdateTime); 41 | 42 | return menuDao.selectPage(iPage, wrapper); 43 | } 44 | 45 | /** 46 | * 添加菜单 47 | * 48 | * @param menu 49 | * @return 50 | */ 51 | public Integer insert(Menu menu) { 52 | return menuDao.insert(menu); 53 | } 54 | 55 | /** 56 | * 查询目录和菜单 57 | * 58 | * @return 59 | */ 60 | public List queryMC() { 61 | // 查询对象 62 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 63 | wrapper.eq(Menu::getStatus, "0"); 64 | wrapper.like(Menu::getMenuType, "M").or().like(Menu::getMenuType, "C"); 65 | wrapper.orderByAsc(Menu::getParentId, Menu::getOrderNum, Menu::getUpdateTime); 66 | return menuDao.selectList(wrapper); 67 | } 68 | 69 | /** 70 | * 查询所有菜单 71 | * 72 | * @return 73 | */ 74 | public List selectAll() { 75 | // 查询对象 76 | LambdaQueryWrapper wrapper = new QueryWrapper().lambda(); 77 | wrapper.eq(Menu::getStatus, "0"); 78 | return menuDao.selectList(wrapper); 79 | } 80 | 81 | /** 82 | * 根据用户id查询菜单列表 83 | * 84 | * @param userId 85 | * @return 86 | */ 87 | public List selectMenusByUserId(Long userId) { 88 | return menuDao.selectMenusByUserId(userId); 89 | } 90 | 91 | public Menu selectById(Long id) { 92 | return menuDao.selectById(id); 93 | } 94 | 95 | public Integer updateById(Menu menu) { 96 | return menuDao.updateById(menu); 97 | } 98 | 99 | /** 100 | * 根据用户id查询拥有的权限 101 | * 102 | * @param userId 103 | * @return 104 | */ 105 | public List listPermissionsByUserId(Long userId) { 106 | List menus = this.selectMenusByUserId(userId); 107 | List permissions = menus.stream().filter(m -> !"M".equals(m.getMenuType())).map(m -> m.getPerms()).collect(Collectors.toList()); 108 | return permissions; 109 | } 110 | 111 | } 112 | --------------------------------------------------------------------------------