From 5e5fb9a07da46b8a3feef0c4e0066305aabeae4a Mon Sep 17 00:00:00 2001
From: soul2 <1052986332@qq.com>
Date: Sun, 7 Apr 2024 14:20:26 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=99=BB=E5=BD=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../jyjc/admin/annotation/SkinLogin.java | 15 +++
.../soul2/jyjc/admin/config/CorsConfig.java | 45 +--------
.../admin/config/UserLoginStatusBean.java | 92 +++++++++++++++++
.../soul2/jyjc/admin/config/WebMvcConfig.java | 24 +++++
.../admin/controller/AnswerController.java | 32 ++++++
.../jyjc/admin/controller/UserController.java | 47 +++++++++
.../soul2/jyjc/admin/dto/AnswerDetailDTO.java | 45 +++++++++
.../soul2/jyjc/admin/dto/AnswerSubmitDTO.java | 37 +++++++
.../cn/soul2/jyjc/admin/dto/UserLoginDTO.java | 30 ++++++
.../jyjc/admin/dto/UserLoginOutPageDTO.java | 21 ++++
.../soul2/jyjc/admin/dto/UserLogoutDTO.java | 25 +++++
.../cn/soul2/jyjc/admin/dto/UserPageDTO.java | 37 +++++++
.../cn/soul2/jyjc/admin/dto/UserSaveDTO.java | 45 +++++++++
.../jyjc/admin/entity/AnswerDetailsDO.java | 8 +-
.../cn/soul2/jyjc/admin/entity/SubjectDO.java | 16 ++-
.../jyjc/admin/entity/SubjectItemsDO.java | 2 +-
.../cn/soul2/jyjc/admin/entity/UserDO.java | 93 +++++++++++++++++
.../jyjc/admin/entity/UserLoginOutDO.java | 87 ++++++++++++++++
.../admin/interceptor/TokenInterceptor.java | 63 ++++++++++++
.../jyjc/admin/mapper/UserLoginOutMapper.java | 16 +++
.../soul2/jyjc/admin/mapper/UserMapper.java | 16 +++
.../repository/IUserLoginOutRepository.java | 62 ++++++++++++
.../admin/repository/IUserRepository.java | 54 ++++++++++
.../impl/UserLoginOutRepositoryImpl.java | 99 +++++++++++++++++++
.../repository/impl/UserRepositoryImpl.java | 60 +++++++++++
.../jyjc/admin/service/IAnswerService.java | 20 ++++
.../jyjc/admin/service/IUserService.java | 46 +++++++++
.../admin/service/impl/AnswerServiceImpl.java | 58 +++++++++++
.../admin/service/impl/UserServiceImpl.java | 87 ++++++++++++++++
.../cn/soul2/jyjc/admin/utils/AesUtils.java | 52 ++++++++++
.../cn/soul2/jyjc/admin/utils/Md5Utils.java | 33 +++++++
.../admin/utils/MybatisFastGenerator.java | 10 +-
.../cn/soul2/jyjc/admin/utils/SaltUtils.java | 35 +++++++
.../java/cn/soul2/jyjc/admin/vo/UserVO.java | 38 +++++++
src/main/resources/application-cors.yml | 7 +-
src/main/resources/application.yml | 1 +
36 files changed, 1401 insertions(+), 57 deletions(-)
create mode 100644 src/main/java/cn/soul2/jyjc/admin/annotation/SkinLogin.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/config/UserLoginStatusBean.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/config/WebMvcConfig.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/controller/AnswerController.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/controller/UserController.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/dto/AnswerDetailDTO.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/dto/AnswerSubmitDTO.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/dto/UserLoginDTO.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/dto/UserLoginOutPageDTO.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/dto/UserLogoutDTO.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/dto/UserPageDTO.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/dto/UserSaveDTO.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/entity/UserDO.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/entity/UserLoginOutDO.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/interceptor/TokenInterceptor.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/mapper/UserLoginOutMapper.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/mapper/UserMapper.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/repository/IUserLoginOutRepository.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/repository/IUserRepository.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/repository/impl/UserLoginOutRepositoryImpl.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/repository/impl/UserRepositoryImpl.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/service/IAnswerService.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/service/IUserService.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/service/impl/AnswerServiceImpl.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/service/impl/UserServiceImpl.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/utils/AesUtils.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/utils/Md5Utils.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/utils/SaltUtils.java
create mode 100644 src/main/java/cn/soul2/jyjc/admin/vo/UserVO.java
diff --git a/src/main/java/cn/soul2/jyjc/admin/annotation/SkinLogin.java b/src/main/java/cn/soul2/jyjc/admin/annotation/SkinLogin.java
new file mode 100644
index 0000000..db845a4
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/annotation/SkinLogin.java
@@ -0,0 +1,15 @@
+package cn.soul2.jyjc.admin.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author Soul2
+ * @date 2024-04-02
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SkinLogin {
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/config/CorsConfig.java b/src/main/java/cn/soul2/jyjc/admin/config/CorsConfig.java
index acc3f82..1f56696 100644
--- a/src/main/java/cn/soul2/jyjc/admin/config/CorsConfig.java
+++ b/src/main/java/cn/soul2/jyjc/admin/config/CorsConfig.java
@@ -5,10 +5,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
/**
* @author Soul2
* @date 2024-03-25
@@ -16,47 +12,14 @@ import java.util.List;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
- @Value("${cors.allow-origins}")
- private String[] allowOriginArray;
-
- /**
- * 将数组转换为List进行动态添加
- */
- private final List allowOriginList = new ArrayList<>();
-
-// private static boolean isLocalV4Address(String ipAddress) {
-// // todo 为进行手机测试而增加的读取内网IP,正式上线时须注释掉
-// String[] parts = ipAddress.split("\\.");
-// // 判断是否是有效的IPv4地址并且属于局域网
-// return parts.length == 4 && parts[0].equals("192") && parts[1].equals("168");
-// }
+ @Value("${cors.allow-origin}")
+ private String[] allowOrigin;
@Override
public void addCorsMappings(CorsRegistry registry) {
- allowOriginList.addAll(Arrays.asList(allowOriginArray));
-// // todo 为进行手机测试而增加的读取内网IP,正式上线时须注释掉
-// try {
-// Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces();
-// while (networkInterfaces.hasMoreElements()) {
-// NetworkInterface networkInterface = networkInterfaces.nextElement();
-// Enumeration inetAddresses = networkInterface.getInetAddresses();
-// while (inetAddresses.hasMoreElements()) {
-// InetAddress inetAddress = inetAddresses.nextElement();
-// if (isLocalV4Address(inetAddress.getHostAddress())) {
-// System.out.println("Local IPv4 Address: " + inetAddress.getHostAddress());
-// allowOriginList.add("http://" + inetAddress.getHostAddress() + ":7620");
-// }
-// }
-// }
-// } catch (Exception e) {
-// e.printStackTrace();
-// }
-
- // 打印 allowOriginList 到控制台
-// System.out.println("allowOriginList: " + allowOriginList);
-
registry.addMapping("/**")
- .allowedOrigins(allowOriginList.toArray(new String[0]))
+ .allowedHeaders("*")
+ .allowedOrigins(allowOrigin)
.allowCredentials(true)
.allowedMethods("POST")
.maxAge(3600);
diff --git a/src/main/java/cn/soul2/jyjc/admin/config/UserLoginStatusBean.java b/src/main/java/cn/soul2/jyjc/admin/config/UserLoginStatusBean.java
new file mode 100644
index 0000000..3937559
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/config/UserLoginStatusBean.java
@@ -0,0 +1,92 @@
+package cn.soul2.jyjc.admin.config;
+
+import cn.soul2.jyjc.admin.entity.UserLoginOutDO;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+public class UserLoginStatusBean {
+
+ private ConcurrentHashMap loginStatusMap = new ConcurrentHashMap<>();
+
+ /**
+ * 缓存登录信息
+ *
+ * @param token token
+ * @param loginOutStatus 登录信息
+ */
+ public void login(String token, UserLoginOutDO loginOutStatus) {
+ loginStatusMap.put(token, loginOutStatus);
+ }
+
+ /**
+ * 从缓存读取登录信息
+ *
+ * @param token token
+ * @return {@link UserLoginOutDO}
+ */
+ public UserLoginOutDO getStatus(String token) {
+ UserLoginOutDO loginStatus = loginStatusMap.getOrDefault(token, null);
+ if (loginStatus.getLapseTime() != null) {
+ LocalDateTime now = LocalDateTime.now();
+ if (now.isAfter(loginStatus.getLapseTime())) {
+ logout(token);
+ return null;
+ }
+ }
+ return loginStatus;
+ }
+
+ /**
+ * 为key设置登出
+ *
+ * @param token token
+ * @return {@link Boolean}
+ */
+ public Boolean logout(String token) {
+ if (StringUtils.isNotBlank(token) && loginStatusMap.containsKey(token)) {
+ UserLoginOutDO removedUser = loginStatusMap.remove(token);
+ // 返回true表示成功登出,返回false表示未成功登出
+ return removedUser != null;
+ }
+ return Boolean.TRUE;
+ }
+
+ public Boolean logoutByUserId(String userId) {
+ final String[] targetKey = {null};
+ loginStatusMap.forEach((k, v) -> {
+ if (targetKey[0] == null && v.getUserId().equals(userId)) {
+ targetKey[0] = k;
+ }
+ });
+ return logout(targetKey[0]);
+ }
+
+ public String getTokenByUsername(String username) {
+ final String[] token = {null};
+ loginStatusMap.forEach((k, v) -> {
+ if (token[0] == null && v.getUserName().equals(username)) {
+ token[0] = k;
+ }
+ });
+ return token[0];
+ }
+
+ public Boolean containsToken(String token) {
+ if (StringUtils.isBlank(token)) {
+ return Boolean.FALSE;
+ }
+ UserLoginOutDO loginStatus = loginStatusMap.getOrDefault(token, null);
+ if (loginStatus.getLapseTime() != null) {
+ LocalDateTime now = LocalDateTime.now();
+ if (now.isAfter(loginStatus.getLapseTime())) {
+ logout(token);
+ }
+ }
+ return loginStatusMap.containsKey(token);
+ }
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/config/WebMvcConfig.java b/src/main/java/cn/soul2/jyjc/admin/config/WebMvcConfig.java
new file mode 100644
index 0000000..a8e0b1c
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/config/WebMvcConfig.java
@@ -0,0 +1,24 @@
+package cn.soul2.jyjc.admin.config;
+
+import cn.soul2.jyjc.admin.interceptor.TokenInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * 注册请求拦截器
+ *
+ * @author Soul2
+ * @date 2024-04-02
+ */
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(new TokenInterceptor())
+ // 拦截所有路径
+ .addPathPatterns("/**");
+ }
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/controller/AnswerController.java b/src/main/java/cn/soul2/jyjc/admin/controller/AnswerController.java
new file mode 100644
index 0000000..3dd0c9e
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/controller/AnswerController.java
@@ -0,0 +1,32 @@
+package cn.soul2.jyjc.admin.controller;
+
+import cn.soul2.jyjc.admin.dto.AnswerSubmitDTO;
+import cn.soul2.jyjc.admin.service.IAnswerService;
+import cn.soul2.jyjc.admin.utils.base.BackUtils;
+import cn.soul2.jyjc.admin.vo.base.Back;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author Soul2
+ * @date 2024-03-27 13:24
+ */
+
+@Slf4j
+@RestController
+@RequestMapping("/answer")
+public class AnswerController {
+
+ @Autowired
+ private IAnswerService answerService;
+
+ @PostMapping("submit")
+ public Back submit(@RequestBody AnswerSubmitDTO dto) {
+ return BackUtils.success(answerService.handleSubmit(dto));
+ }
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/controller/UserController.java b/src/main/java/cn/soul2/jyjc/admin/controller/UserController.java
new file mode 100644
index 0000000..1b5a152
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/controller/UserController.java
@@ -0,0 +1,47 @@
+package cn.soul2.jyjc.admin.controller;
+
+import cn.soul2.jyjc.admin.annotation.SkinLogin;
+import cn.soul2.jyjc.admin.dto.UserLoginDTO;
+import cn.soul2.jyjc.admin.dto.UserLogoutDTO;
+import cn.soul2.jyjc.admin.service.IUserService;
+import cn.soul2.jyjc.admin.utils.base.BackUtils;
+import cn.soul2.jyjc.admin.vo.UserVO;
+import cn.soul2.jyjc.admin.vo.base.Back;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author Soul2
+ * @date 2024-03-31 15:48
+ */
+
+@Slf4j
+@RestController
+@RequestMapping("/user")
+public class UserController {
+
+ @Autowired
+ private IUserService userService;
+
+ @PostMapping("login")
+ @SkinLogin
+ public Back login(@RequestBody UserLoginDTO dto) {
+ return BackUtils.success(userService.login(dto));
+ }
+
+ @PostMapping("register")
+ @SkinLogin
+ public Back register(@RequestBody UserLoginDTO dto) {
+ return BackUtils.success(userService.register(dto));
+ }
+
+ @PostMapping("logout")
+ public Back logout(@RequestBody UserLogoutDTO dto) {
+ return BackUtils.success(userService.logout(dto));
+ }
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/dto/AnswerDetailDTO.java b/src/main/java/cn/soul2/jyjc/admin/dto/AnswerDetailDTO.java
new file mode 100644
index 0000000..d279f46
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/dto/AnswerDetailDTO.java
@@ -0,0 +1,45 @@
+package cn.soul2.jyjc.admin.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author Soul2
+ * @date 2024-03-27 13:31
+ */
+
+@Data
+@Accessors(chain = true)
+public class AnswerDetailDTO {
+
+ /**
+ * 回答内容(文字/选项id,多选时以,分隔)
+ */
+ private String content;
+
+ /**
+ * 得分
+ */
+ private Integer points;
+
+ /**
+ * 题目id
+ */
+ private String subjectId;
+
+ /**
+ * 题目类型:0-单选;1-多选;2-文字
+ */
+ private Integer subjectType;
+
+ /**
+ * 题目分值
+ */
+ private Integer subjectPoints;
+
+ /**
+ * 权重
+ */
+ private Double weights;
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/dto/AnswerSubmitDTO.java b/src/main/java/cn/soul2/jyjc/admin/dto/AnswerSubmitDTO.java
new file mode 100644
index 0000000..2b605fc
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/dto/AnswerSubmitDTO.java
@@ -0,0 +1,37 @@
+package cn.soul2.jyjc.admin.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * @author Soul2
+ * @date 2024-03-27 13:26
+ */
+
+@Data
+@Accessors(chain = true)
+public class AnswerSubmitDTO {
+
+ /**
+ * 二维码id
+ */
+ private String qrId;
+
+ /**
+ * 问卷Id
+ */
+ private String qnId;
+
+ /**
+ * openid, 即答卷人
+ */
+ private String openid;
+
+ /**
+ * 答题内容
+ */
+ private List details;
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/dto/UserLoginDTO.java b/src/main/java/cn/soul2/jyjc/admin/dto/UserLoginDTO.java
new file mode 100644
index 0000000..b2789a8
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/dto/UserLoginDTO.java
@@ -0,0 +1,30 @@
+package cn.soul2.jyjc.admin.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author Soul2
+ * @date 2024-03-29 21:55
+ */
+
+@Data
+@Accessors(chain = true)
+public class UserLoginDTO {
+
+ /**
+ * userName
+ */
+ private String username;
+
+ /**
+ * password
+ */
+ private String password;
+
+ /**
+ * 密码错误次数(暂未使用)
+ */
+ private Integer pswErrorCount;
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/dto/UserLoginOutPageDTO.java b/src/main/java/cn/soul2/jyjc/admin/dto/UserLoginOutPageDTO.java
new file mode 100644
index 0000000..5ee7529
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/dto/UserLoginOutPageDTO.java
@@ -0,0 +1,21 @@
+package cn.soul2.jyjc.admin.dto;
+
+import cn.soul2.jyjc.admin.dto.base.PageParams;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author Soul2
+ * @date 2024-03-29 21:50
+ */
+
+@Data
+@Accessors(chain = true)
+public class UserLoginOutPageDTO extends PageParams {
+
+ /**
+ * userId
+ */
+ private String userId;
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/dto/UserLogoutDTO.java b/src/main/java/cn/soul2/jyjc/admin/dto/UserLogoutDTO.java
new file mode 100644
index 0000000..3b8c029
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/dto/UserLogoutDTO.java
@@ -0,0 +1,25 @@
+package cn.soul2.jyjc.admin.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author Soul2
+ * @date 2024-03-29 21:56
+ */
+
+@Data
+@Accessors(chain = true)
+public class UserLogoutDTO {
+
+ /**
+ * userName
+ */
+ private String username;
+
+ /**
+ * token
+ */
+ private String token;
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/dto/UserPageDTO.java b/src/main/java/cn/soul2/jyjc/admin/dto/UserPageDTO.java
new file mode 100644
index 0000000..7fd23b3
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/dto/UserPageDTO.java
@@ -0,0 +1,37 @@
+package cn.soul2.jyjc.admin.dto;
+
+import cn.soul2.jyjc.admin.dto.base.PageParams;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author Soul2
+ * @date 2024-03-29 20:50
+ */
+
+@Data
+@Accessors(chain = true)
+public class UserPageDTO extends PageParams {
+
+ /**
+ * id
+ */
+ private String id;
+ /**
+ * 用户名
+ */
+ private String username;
+ /**
+ * 状态;0(默认):正常;4:封号;9:异常;
+ */
+ private Integer status;
+
+ /**
+ * 注册时间
+ */
+ private LocalDateTime startTime;
+ private LocalDateTime endTime;
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/dto/UserSaveDTO.java b/src/main/java/cn/soul2/jyjc/admin/dto/UserSaveDTO.java
new file mode 100644
index 0000000..47567d3
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/dto/UserSaveDTO.java
@@ -0,0 +1,45 @@
+package cn.soul2.jyjc.admin.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author Soul2
+ * @date 2024-03-29 20:50
+ */
+
+@Data
+@Accessors(chain = true)
+public class UserSaveDTO {
+
+ /**
+ * id
+ */
+ private String id;
+
+ /**
+ * 用户名
+ */
+ private String username;
+
+ /**
+ * 密码
+ */
+ private String password;
+
+ /**
+ * 状态;0(默认):正常;4:封号;9:异常;
+ */
+ private Integer status;
+
+ /**
+ * 权限等级,默认200
+ */
+ private Integer authorityLevel;
+
+ /**
+ * 密码修改次数
+ */
+ private Integer pswChange;
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/entity/AnswerDetailsDO.java b/src/main/java/cn/soul2/jyjc/admin/entity/AnswerDetailsDO.java
index 6078772..ef63e7c 100644
--- a/src/main/java/cn/soul2/jyjc/admin/entity/AnswerDetailsDO.java
+++ b/src/main/java/cn/soul2/jyjc/admin/entity/AnswerDetailsDO.java
@@ -15,7 +15,7 @@ import java.time.LocalDateTime;
*
*
* @author Soul2
- * @since 2024-03-12 10:10:24
+ * @since 2024-03-27 15:38:51
*/
@Getter
@Setter
@@ -32,10 +32,10 @@ public class AnswerDetailsDO extends Model {
private String id;
/**
- * 状态:0:禁用;1:启用;
+ * 题目类型:0-单选;1-多选;2-文字
*/
- @TableField("status")
- private Short status;
+ @TableField("subject_type")
+ private Integer subjectType;
/**
* 更新时间
diff --git a/src/main/java/cn/soul2/jyjc/admin/entity/SubjectDO.java b/src/main/java/cn/soul2/jyjc/admin/entity/SubjectDO.java
index d4abd9a..253d766 100644
--- a/src/main/java/cn/soul2/jyjc/admin/entity/SubjectDO.java
+++ b/src/main/java/cn/soul2/jyjc/admin/entity/SubjectDO.java
@@ -15,7 +15,7 @@ import java.time.LocalDateTime;
*
*
* @author Soul2
- * @since 2024-03-12 10:10:24
+ * @since 2024-03-27 15:38:52
*/
@Getter
@Setter
@@ -80,8 +80,20 @@ public class SubjectDO extends Model {
@TableField("type")
private Short type;
+ /**
+ * 权重
+ */
+ @TableField("weights")
+ private Double weights;
+
+ /**
+ * 分值
+ */
+ @TableField("points")
+ private Integer points;
+
@Override
public Serializable pkVal() {
- return null;
+ return this.id;
}
}
diff --git a/src/main/java/cn/soul2/jyjc/admin/entity/SubjectItemsDO.java b/src/main/java/cn/soul2/jyjc/admin/entity/SubjectItemsDO.java
index dc43e7f..72c4101 100644
--- a/src/main/java/cn/soul2/jyjc/admin/entity/SubjectItemsDO.java
+++ b/src/main/java/cn/soul2/jyjc/admin/entity/SubjectItemsDO.java
@@ -72,7 +72,7 @@ public class SubjectItemsDO extends Model {
* 权重
*/
@TableField("weights")
- private Object weights;
+ private Double weights;
/**
* 分值
diff --git a/src/main/java/cn/soul2/jyjc/admin/entity/UserDO.java b/src/main/java/cn/soul2/jyjc/admin/entity/UserDO.java
new file mode 100644
index 0000000..51c3314
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/entity/UserDO.java
@@ -0,0 +1,93 @@
+package cn.soul2.jyjc.admin.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ * 用户表
+ *
+ *
+ * @author Soul2
+ * @since 2024-03-30 14:34:13
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+@TableName("tb_user")
+public class UserDO extends Model {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @TableId(value = "id", type = IdType.ASSIGN_UUID)
+ private String id;
+
+ /**
+ * 用户名
+ */
+ @TableField("username")
+ private String username;
+
+ /**
+ * 密码
+ */
+ @TableField("password")
+ private String password;
+
+ /**
+ * 状态;0(默认):正常;4:封号;9:异常;
+ */
+ @TableField("status")
+ private Integer status;
+
+ /**
+ * 权限等级,默认200
+ */
+ @TableField("authority_level")
+ private Integer authorityLevel;
+
+ /**
+ * 密码修改次数
+ */
+ @TableField("psw_change")
+ private Integer pswChange;
+
+ /**
+ * 更新时间
+ */
+ @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
+ private LocalDateTime updatedTime;
+
+ /**
+ * 创建时间
+ */
+ @TableField(value = "created_time", fill = FieldFill.INSERT)
+ private LocalDateTime createdTime;
+
+ /**
+ * 删除标记
+ */
+ @TableField("removed")
+ @TableLogic
+ private Integer removed;
+
+ /**
+ * 盐,用于密码加密,未启用
+ */
+ @TableField("salt")
+ private String salt;
+
+ @Override
+ public Serializable pkVal() {
+ return this.id;
+ }
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/entity/UserLoginOutDO.java b/src/main/java/cn/soul2/jyjc/admin/entity/UserLoginOutDO.java
new file mode 100644
index 0000000..cf3e801
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/entity/UserLoginOutDO.java
@@ -0,0 +1,87 @@
+package cn.soul2.jyjc.admin.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ * 用户登入登出表
+ *
+ *
+ * @author Soul2
+ * @since 2024-03-30 13:57:00
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+@TableName("tb_user_login_out")
+public class UserLoginOutDO extends Model {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @TableId(value = "id", type = IdType.ASSIGN_UUID)
+ private String id;
+
+ /**
+ * 用户id
+ */
+ @TableField("user_id")
+ private String userId;
+
+ /**
+ * 用户名称
+ */
+ @TableField("user_name")
+ private String userName;
+
+ /**
+ * 登录时间,登录成功才写入
+ */
+ @TableField("login_time")
+ private LocalDateTime loginTime;
+
+ /**
+ * 登录失效时间
+ */
+ @TableField("lapse_time")
+ private LocalDateTime lapseTime;
+
+ /**
+ * 用户操作登出时间
+ */
+ @TableField("logout_time")
+ private LocalDateTime logoutTime;
+
+ /**
+ * 密码错误次数
+ */
+ @TableField("psw_error_count")
+ private Integer pswErrorCount;
+
+ /**
+ * 创建时间
+ */
+ @TableField(value = "created_time", fill = FieldFill.INSERT)
+ private LocalDateTime createdTime;
+
+ /**
+ * 1=删除;0=未删除
+ */
+ @TableField("removed")
+ @TableLogic
+ private Integer removed;
+
+ @Override
+ public Serializable pkVal() {
+ return this.id;
+ }
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/interceptor/TokenInterceptor.java b/src/main/java/cn/soul2/jyjc/admin/interceptor/TokenInterceptor.java
new file mode 100644
index 0000000..69d7d60
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/interceptor/TokenInterceptor.java
@@ -0,0 +1,63 @@
+package cn.soul2.jyjc.admin.interceptor;
+
+import cn.soul2.jyjc.admin.annotation.SkinLogin;
+import cn.soul2.jyjc.admin.config.UserLoginStatusBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author Soul2
+ * @date 2024-04-02 15:31
+ */
+
+public class TokenInterceptor implements HandlerInterceptor {
+
+ @Autowired
+ private UserLoginStatusBean userLoginStatusBean;
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ // 允许OPTIONS请求通过
+ if (isCorsRequest(request)) {
+ return true;
+ }
+
+ // 跳过登录
+ // 如果处理器是一个方法处理器
+ if (handler instanceof HandlerMethod) {
+ HandlerMethod handlerMethod = (HandlerMethod) handler;
+ // 检查方法上是否存在SkinLogin注解
+ if (handlerMethod.getMethod().isAnnotationPresent(SkinLogin.class)) {
+ // 如果存在,绕过拦截器
+ return true;
+ }
+ }
+ // 验证token
+ // 从请求头中获取 token
+ String token = request.getHeader("jyjc-Token");
+ // 检查 token 是否存在并且有效,这里可以根据实际情况自行实现验证逻辑
+ if (token != null && isValidToken(token)) {
+ // Token 有效,允许请求通过
+ return true;
+ } else {
+ // Token 无效,拒绝请求,可以返回特定的响应状态码,例如 401 Unauthorized
+ response.setStatus(40401);
+ return false;
+ }
+ }
+
+ private boolean isValidToken(String token) {
+ // 实现 token 验证逻辑,例如验证 token 的签名或者在数据库中验证 token 的有效性
+ return userLoginStatusBean.containsToken(token);
+ // 返回 true 表示 token 有效,返回 false 表示 token 无效
+ }
+
+ private boolean isCorsRequest(HttpServletRequest request) {
+ // 检查请求头中是否包含 Origin 字段,如果存在,则认为是跨域请求
+ return request.getHeader("Origin") != null;
+ }
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/mapper/UserLoginOutMapper.java b/src/main/java/cn/soul2/jyjc/admin/mapper/UserLoginOutMapper.java
new file mode 100644
index 0000000..585bbcd
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/mapper/UserLoginOutMapper.java
@@ -0,0 +1,16 @@
+package cn.soul2.jyjc.admin.mapper;
+
+import cn.soul2.jyjc.admin.entity.UserLoginOutDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 用户登入登出表 Mapper 接口
+ *
+ *
+ * @author Soul2
+ * @since 2024-03-29 20:46:42
+ */
+public interface UserLoginOutMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/mapper/UserMapper.java b/src/main/java/cn/soul2/jyjc/admin/mapper/UserMapper.java
new file mode 100644
index 0000000..65a4563
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/mapper/UserMapper.java
@@ -0,0 +1,16 @@
+package cn.soul2.jyjc.admin.mapper;
+
+import cn.soul2.jyjc.admin.entity.UserDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 用户表 Mapper 接口
+ *
+ *
+ * @author Soul2
+ * @since 2024-03-29 20:46:42
+ */
+public interface UserMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/repository/IUserLoginOutRepository.java b/src/main/java/cn/soul2/jyjc/admin/repository/IUserLoginOutRepository.java
new file mode 100644
index 0000000..b2a9bf0
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/repository/IUserLoginOutRepository.java
@@ -0,0 +1,62 @@
+package cn.soul2.jyjc.admin.repository;
+
+import cn.soul2.jyjc.admin.dto.UserLoginDTO;
+import cn.soul2.jyjc.admin.dto.UserLoginOutPageDTO;
+import cn.soul2.jyjc.admin.dto.UserLogoutDTO;
+import cn.soul2.jyjc.admin.entity.UserDO;
+import cn.soul2.jyjc.admin.entity.UserLoginOutDO;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 用户登入登出表 服务类
+ *
+ *
+ * @author Soul2
+ * @since 2024-03-29 20:46:42
+ */
+public interface IUserLoginOutRepository extends IService {
+
+ /**
+ * 分页查询
+ *
+ * @param dto 查询条件
+ * @return {@link IPage}<{@link UserLoginOutDO}>
+ */
+ IPage page(UserLoginOutPageDTO dto);
+
+ /**
+ * 用户登录
+ *
+ * @param dto 用户信息
+ * @param user 用户
+ * @return {@link String}
+ */
+ String login(UserLoginDTO dto, UserDO user);
+
+ /**
+ * 用户登出
+ *
+ * @param dto 用户信息
+ * @return {@link String}
+ */
+ String logout(UserLogoutDTO dto);
+
+ /**
+ * 用户登出
+ *
+ * @param userId 用户id
+ * @return {@link String}
+ */
+ Boolean logoutByUserId(String userId);
+
+ /**
+ * 删除目标用户的所有登录记录
+ *
+ * @param userId 用户id
+ * @return {@link Boolean}
+ */
+ Boolean removeByUserId(String userId);
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/repository/IUserRepository.java b/src/main/java/cn/soul2/jyjc/admin/repository/IUserRepository.java
new file mode 100644
index 0000000..4d541b0
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/repository/IUserRepository.java
@@ -0,0 +1,54 @@
+package cn.soul2.jyjc.admin.repository;
+
+import cn.soul2.jyjc.admin.dto.UserPageDTO;
+import cn.soul2.jyjc.admin.dto.UserSaveDTO;
+import cn.soul2.jyjc.admin.dto.base.UpdateStatusDTO;
+import cn.soul2.jyjc.admin.entity.UserDO;
+import cn.soul2.jyjc.admin.vo.base.VPage;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 用户表 服务类
+ *
+ *
+ * @author Soul2
+ * @since 2024-03-29 20:46:42
+ */
+public interface IUserRepository extends IService {
+
+ /**
+ * 分页查询
+ *
+ * @param dto 查询条件
+ * @return {@link VPage}<{@link UserDO}>
+ */
+ IPage page(UserPageDTO dto);
+
+ /**
+ * 保存或更新
+ *
+ * @param dto 有/无id区分更新/新增
+ * @return {@link Boolean}
+ */
+ Boolean saveOrUpdate(UserSaveDTO dto);
+
+ /**
+ * 更新状态
+ *
+ * @param dto 新状态
+ * @return {@link Boolean}
+ */
+ Boolean updateStatus(UpdateStatusDTO dto);
+
+ /**
+ * 读取指定名字的用户
+ *
+ * @param username 用户名
+ * @return {@link UserDO}
+ */
+ UserDO getOneByUsername(String username);
+
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/repository/impl/UserLoginOutRepositoryImpl.java b/src/main/java/cn/soul2/jyjc/admin/repository/impl/UserLoginOutRepositoryImpl.java
new file mode 100644
index 0000000..356e10a
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/repository/impl/UserLoginOutRepositoryImpl.java
@@ -0,0 +1,99 @@
+package cn.soul2.jyjc.admin.repository.impl;
+
+import cn.soul2.jyjc.admin.config.UserLoginStatusBean;
+import cn.soul2.jyjc.admin.dto.UserLoginDTO;
+import cn.soul2.jyjc.admin.dto.UserLoginOutPageDTO;
+import cn.soul2.jyjc.admin.dto.UserLogoutDTO;
+import cn.soul2.jyjc.admin.entity.UserDO;
+import cn.soul2.jyjc.admin.entity.UserLoginOutDO;
+import cn.soul2.jyjc.admin.mapper.UserLoginOutMapper;
+import cn.soul2.jyjc.admin.repository.IUserLoginOutRepository;
+import cn.soul2.jyjc.admin.utils.base.PageUtils;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+
+/**
+ *
+ * 用户登入登出表 服务实现类
+ *
+ *
+ * @author Soul2
+ * @since 2024-03-29 20:46:42
+ */
+@Service
+public class UserLoginOutRepositoryImpl extends ServiceImpl implements IUserLoginOutRepository {
+
+ @Autowired
+ private UserLoginStatusBean userLoginStatusBean;
+
+ @Override
+ public IPage page(UserLoginOutPageDTO dto) {
+ LambdaQueryWrapper query = Wrappers.lambdaQuery();
+ query.eq(StringUtils.isNotBlank(dto.getUserId()), UserLoginOutDO::getUserId, dto.getUserId())
+ .orderByDesc(UserLoginOutDO::getCreatedTime);
+ return super.page(PageUtils.build(dto), query);
+ }
+
+ @Override
+ public String login(UserLoginDTO dto, UserDO user) {
+ UserLoginOutDO loginOutDO;
+ boolean saved;
+ LocalDateTime now = LocalDateTime.now();
+ // 判断是否登陆过,在缓存无法读取到目标用户名时即未登录,若登录过则令之前的登录记录失效
+ String token = userLoginStatusBean.getTokenByUsername(dto.getUsername());
+ if (token != null) {
+ userLoginStatusBean.logout(token);
+ UserLoginOutDO oldLoginOut = super.getById(token);
+ oldLoginOut.setLapseTime(now).setLogoutTime(now);
+ super.updateById(oldLoginOut);
+ }
+ loginOutDO = new UserLoginOutDO();
+ loginOutDO.setUserId(user.getId())
+ .setUserName(user.getUsername())
+ .setLoginTime(now)
+ .setLapseTime(now.plusHours(2))
+ ;
+ saved = super.save(loginOutDO);
+ if (saved) {
+ userLoginStatusBean.login(loginOutDO.getId(), loginOutDO);
+ return loginOutDO.getId();
+ }
+ return null;
+ }
+
+ @Override
+ public String logout(UserLogoutDTO dto) {
+ // 清除缓存内的登录信息
+ Boolean logout = userLoginStatusBean.logout(dto.getToken());
+ // 保存退出登录的时间
+ LocalDateTime now = LocalDateTime.now();
+ UserLoginOutDO oldLoginOut = super.getById(dto.getToken());
+ oldLoginOut.setLogoutTime(now);
+ super.updateById(oldLoginOut);
+
+ return logout ? dto.getUsername() : null;
+ }
+
+ @Override
+ public Boolean logoutByUserId(String userId) {
+ return userLoginStatusBean.logoutByUserId(userId);
+ }
+
+ @Override
+ public Boolean removeByUserId(String userId) {
+ if (org.apache.commons.lang3.StringUtils.isBlank(userId)) {
+ return Boolean.TRUE;
+ }
+ LambdaUpdateWrapper update = Wrappers.lambdaUpdate();
+ update.eq(UserLoginOutDO::getUserId, userId);
+ return super.remove(update);
+ }
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/repository/impl/UserRepositoryImpl.java b/src/main/java/cn/soul2/jyjc/admin/repository/impl/UserRepositoryImpl.java
new file mode 100644
index 0000000..f2c86dd
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/repository/impl/UserRepositoryImpl.java
@@ -0,0 +1,60 @@
+package cn.soul2.jyjc.admin.repository.impl;
+
+import cn.soul2.jyjc.admin.dto.UserPageDTO;
+import cn.soul2.jyjc.admin.dto.UserSaveDTO;
+import cn.soul2.jyjc.admin.dto.base.UpdateStatusDTO;
+import cn.soul2.jyjc.admin.entity.UserDO;
+import cn.soul2.jyjc.admin.mapper.UserMapper;
+import cn.soul2.jyjc.admin.repository.IUserRepository;
+import cn.soul2.jyjc.admin.utils.base.PageUtils;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 用户表 服务实现类
+ *
+ *
+ * @author Soul2
+ * @since 2024-03-29 20:46:42
+ */
+@Service
+public class UserRepositoryImpl extends ServiceImpl implements IUserRepository {
+
+ @Override
+ public IPage page(UserPageDTO dto) {
+ LambdaQueryWrapper query = Wrappers.lambdaQuery();
+ query.eq(dto.getStatus() != null, UserDO::getStatus, dto.getStatus())
+ .like(StringUtils.isNotBlank(dto.getUsername()), UserDO::getUsername, dto.getUsername())
+ .orderByDesc(UserDO::getUpdatedTime);
+ return super.page(PageUtils.build(dto), query);
+ }
+
+ @Override
+ public Boolean saveOrUpdate(UserSaveDTO dto) {
+ UserDO user = new UserDO();
+ BeanUtils.copyProperties(dto, user);
+ return super.saveOrUpdate(user);
+ }
+
+ @Override
+ public Boolean updateStatus(UpdateStatusDTO dto) {
+ LambdaUpdateWrapper update = Wrappers.lambdaUpdate();
+ update.set(UserDO::getStatus, dto.getStatus())
+ .eq(UserDO::getId, dto.getId());
+ return super.update(update);
+ }
+
+ @Override
+ public UserDO getOneByUsername(String username) {
+ LambdaQueryWrapper query = Wrappers.lambdaQuery();
+ query.eq(UserDO::getUsername, username);
+ return super.getOne(query, false);
+ }
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/service/IAnswerService.java b/src/main/java/cn/soul2/jyjc/admin/service/IAnswerService.java
new file mode 100644
index 0000000..7dbe407
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/service/IAnswerService.java
@@ -0,0 +1,20 @@
+package cn.soul2.jyjc.admin.service;
+
+import cn.soul2.jyjc.admin.dto.AnswerSubmitDTO;
+
+/**
+ * @author Soul2
+ * @date 2024-03-27 14:43
+ */
+
+public interface IAnswerService {
+
+ /**
+ * 提交答卷
+ *
+ * @param dto 答卷内容
+ * @return {@link Boolean}
+ */
+ Boolean handleSubmit(AnswerSubmitDTO dto);
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/service/IUserService.java b/src/main/java/cn/soul2/jyjc/admin/service/IUserService.java
new file mode 100644
index 0000000..53a3392
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/service/IUserService.java
@@ -0,0 +1,46 @@
+package cn.soul2.jyjc.admin.service;
+
+import cn.soul2.jyjc.admin.dto.UserLoginDTO;
+import cn.soul2.jyjc.admin.dto.UserLogoutDTO;
+import cn.soul2.jyjc.admin.vo.UserVO;
+
+/**
+ * @author Soul2
+ * @date 2024-03-29 20:47
+ */
+
+public interface IUserService {
+
+ /**
+ * 注册一个用户
+ *
+ * @param dto 用户名和密码
+ * @return {@link UserVO}
+ */
+ UserVO register(UserLoginDTO dto);
+
+ /**
+ * 用户登录
+ *
+ * @param dto 用户名和密码
+ * @return {@link UserVO}
+ */
+ UserVO login(UserLoginDTO dto);
+
+ /**
+ * 用户退出登录
+ *
+ * @param dto 登录key
+ * @return {@link Boolean}
+ */
+ Boolean logout(UserLogoutDTO dto);
+
+ /**
+ * 删除用户并退出登录,同时将登录记录一并删除
+ *
+ * @param userId 用户id
+ * @return {@link Boolean}
+ */
+ Boolean remove(String userId);
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/service/impl/AnswerServiceImpl.java b/src/main/java/cn/soul2/jyjc/admin/service/impl/AnswerServiceImpl.java
new file mode 100644
index 0000000..39bb0dd
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/service/impl/AnswerServiceImpl.java
@@ -0,0 +1,58 @@
+package cn.soul2.jyjc.admin.service.impl;
+
+import cn.soul2.jyjc.admin.dto.AnswerSubmitDTO;
+import cn.soul2.jyjc.admin.entity.AnswerDetailsDO;
+import cn.soul2.jyjc.admin.entity.AnswerSheetDO;
+import cn.soul2.jyjc.admin.repository.IAnswerDetailsRepository;
+import cn.soul2.jyjc.admin.repository.IAnswerSheetRepository;
+import cn.soul2.jyjc.admin.service.IAnswerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Soul2
+ * @date 2024-03-27 14:43
+ */
+
+@Service
+public class AnswerServiceImpl implements IAnswerService {
+
+ @Autowired
+ private IAnswerSheetRepository sheetRepository;
+
+ @Autowired
+ private IAnswerDetailsRepository detailsRepository;
+
+ @Override
+ @Transactional
+ public Boolean handleSubmit(AnswerSubmitDTO dto) {
+ AnswerSheetDO sheet = new AnswerSheetDO();
+ sheet.setRespondent(dto.getOpenid())
+ .setQnId(dto.getQnId())
+ .setQrId(dto.getQrId());
+ boolean sheetSaved = sheetRepository.save(sheet);
+ if (sheetSaved) {
+ List details = dto.getDetails().stream().map(d -> {
+ AnswerDetailsDO detail = new AnswerDetailsDO();
+ detail.setAnswerContent(d.getContent())
+ .setAnswerSheetId(sheet.getId())
+ .setSubjectType(d.getSubjectType())
+ .setSubjectId(d.getSubjectId());
+ return detail;
+ }).collect(Collectors.toList());
+ boolean detailsSaved = detailsRepository.saveBatch(details);
+ if (!detailsSaved) {
+ TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+ return Boolean.FALSE;
+ }
+ } else {
+ return Boolean.FALSE;
+ }
+ return Boolean.TRUE;
+ }
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/service/impl/UserServiceImpl.java b/src/main/java/cn/soul2/jyjc/admin/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..f44fd05
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/service/impl/UserServiceImpl.java
@@ -0,0 +1,87 @@
+package cn.soul2.jyjc.admin.service.impl;
+
+import cn.soul2.jyjc.admin.dto.UserLoginDTO;
+import cn.soul2.jyjc.admin.dto.UserLogoutDTO;
+import cn.soul2.jyjc.admin.entity.UserDO;
+import cn.soul2.jyjc.admin.repository.IUserLoginOutRepository;
+import cn.soul2.jyjc.admin.repository.IUserRepository;
+import cn.soul2.jyjc.admin.service.IUserService;
+import cn.soul2.jyjc.admin.utils.Md5Utils;
+import cn.soul2.jyjc.admin.vo.UserVO;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author Soul2
+ * @date 2024-03-29 20:47
+ */
+
+@Service
+public class UserServiceImpl implements IUserService {
+
+ @Autowired
+ private IUserRepository userRepository;
+
+ @Autowired
+ private IUserLoginOutRepository loginOutRepository;
+
+ @Override
+ public UserVO register(UserLoginDTO dto) {
+ UserVO vo = new UserVO();
+ if (userRepository.getOneByUsername(dto.getUsername()) == null) {
+ UserDO user = new UserDO();
+ user.setUsername(dto.getUsername())
+ .setPassword(Md5Utils.md5(dto.getPassword()));
+ boolean saved = userRepository.save(user);
+ if (!saved) {
+ vo.setLoginFail("注册失败!");
+ } else {
+ String loginKey = loginOutRepository.login(dto, user);
+ if (loginKey != null) {
+ BeanUtils.copyProperties(user, vo);
+ vo.setToken(loginKey);
+ } else {
+ vo.setLoginFail("注册成功但登录失败!");
+ }
+ }
+ } else {
+ vo.setLoginFail("用户名已存在!");
+ }
+ return vo;
+ }
+
+ @Override
+ public UserVO login(UserLoginDTO dto) {
+ UserVO vo = new UserVO();
+ UserDO user = userRepository.getOneByUsername(dto.getUsername());
+ if (user != null) {
+ if (Md5Utils.verify(user.getPassword(), dto.getPassword())) {
+ String loginKey = loginOutRepository.login(dto, user);
+ if (loginKey != null) {
+ BeanUtils.copyProperties(user, vo);
+ vo.setToken(loginKey);
+ } else {
+ vo.setLoginFail("登录失败!");
+ }
+ } else {
+ vo.setLoginFail("密码错误!");
+ }
+ } else {
+ vo.setLoginFail("该用户尚未注册!");
+ }
+ return vo;
+ }
+
+ @Override
+ public Boolean logout(UserLogoutDTO dto) {
+ return loginOutRepository.logout(dto) != null;
+ }
+
+ @Override
+ public Boolean remove(String userId) {
+ loginOutRepository.logoutByUserId(userId);
+ loginOutRepository.removeByUserId(userId);
+ return userRepository.removeById(userId);
+ }
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/utils/AesUtils.java b/src/main/java/cn/soul2/jyjc/admin/utils/AesUtils.java
new file mode 100644
index 0000000..a4dcf04
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/utils/AesUtils.java
@@ -0,0 +1,52 @@
+package cn.soul2.jyjc.admin.utils;
+
+import org.springframework.beans.factory.annotation.Value;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.Base64;
+
+/**
+ * @author Soul2
+ * @date 2024-03-30 14:02
+ */
+
+public class AesUtils {
+
+ @Value("${encrypt.keys.aes}")
+ private String aesKey;
+
+ private static final String AES_ALGORITHM = "AES";
+
+ private SecretKeySpec generateKey(String key) {
+ return new SecretKeySpec(key.getBytes(), AES_ALGORITHM);
+ }
+
+ public String encrypt(String source) throws Exception {
+ return encrypt(source, aesKey);
+ }
+
+ public String decrypt(String encrypted) throws Exception {
+ return decrypt(encrypted, aesKey);
+ }
+
+ private String encrypt(String source, String key) throws Exception {
+ Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, generateKey(key));
+ byte[] encryptedBytes = cipher.doFinal(source.getBytes());
+ return Base64.getEncoder().encodeToString(encryptedBytes);
+ }
+
+ private String decrypt(String encrypted, String key) throws Exception {
+ Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
+ cipher.init(Cipher.DECRYPT_MODE, generateKey(key));
+ byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encrypted));
+ return new String(decryptedBytes);
+ }
+
+ public static void main(String[] args) {
+
+ }
+
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/utils/Md5Utils.java b/src/main/java/cn/soul2/jyjc/admin/utils/Md5Utils.java
new file mode 100644
index 0000000..16ea763
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/utils/Md5Utils.java
@@ -0,0 +1,33 @@
+package cn.soul2.jyjc.admin.utils;
+
+import org.springframework.util.DigestUtils;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+/**
+ * @author fuzongyao
+ * @date 2021/10/14 11:19
+ * @since 1.0
+ */
+public class Md5Utils {
+
+ /**
+ * 加盐
+ */
+ private static final String SALT = "4v6dKAOn+tEiVH58/XKeUw==";
+
+ public static String md5(String body) {
+ body += SALT;
+ return DigestUtils.md5DigestAsHex(body.getBytes(StandardCharsets.UTF_8)).toUpperCase();
+ }
+
+ public static boolean verify(String md5, String body) {
+ return Objects.equals(md5, md5(body));
+ }
+
+ public static void main(String[] args) {
+ System.out.println(md5("123456"));
+ }
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/utils/MybatisFastGenerator.java b/src/main/java/cn/soul2/jyjc/admin/utils/MybatisFastGenerator.java
index 89d136f..da067e5 100644
--- a/src/main/java/cn/soul2/jyjc/admin/utils/MybatisFastGenerator.java
+++ b/src/main/java/cn/soul2/jyjc/admin/utils/MybatisFastGenerator.java
@@ -19,16 +19,16 @@ public class MybatisFastGenerator {
private static final DatasourceConfig DATASOURCE_CONFIG = new DatasourceConfig(
"Soul2",
- "jdbc:mysql://localhost:3306/pioneer?characterEncoding=utf8&serverTimezone=GMT%2B8",
- "root",
- "123456"
+ "jdbc:mysql://soul2.cn:3306/thli_upline?characterEncoding=utf8&serverTimezone=GMT%2B8",
+ "thli",
+ "thli@20180913"
);
/**
* 设置需要生成的表名
*/
private static final String[] TABLE_NAMES = {
"tb_user",
- "tb_user_login_out",
+// "tb_user_login_out",
};
/**
* 是否为表更新
@@ -37,7 +37,7 @@ public class MybatisFastGenerator {
/**
* 模块名称
*/
- private static final String MODULE_NAME = "demo";
+ private static final String MODULE_NAME = "jyjc.admin";
/**
* 设置过滤表前缀
diff --git a/src/main/java/cn/soul2/jyjc/admin/utils/SaltUtils.java b/src/main/java/cn/soul2/jyjc/admin/utils/SaltUtils.java
new file mode 100644
index 0000000..58cefd7
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/utils/SaltUtils.java
@@ -0,0 +1,35 @@
+package cn.soul2.jyjc.admin.utils;
+
+import java.security.SecureRandom;
+import java.util.Base64;
+
+/**
+ * 盐值生成
+ *
+ * @author Soul2
+ * @date 2024-03-30 14:30
+ */
+
+public class SaltUtils {
+
+ /**
+ * 生成指定长度的盐值
+ *
+ * @param length 盐值长度
+ * @return {@link String}
+ */
+ public static String generateSalt(int length) {
+ SecureRandom random = new SecureRandom();
+ byte[] salt = new byte[length];
+ random.nextBytes(salt);
+ return Base64.getEncoder().encodeToString(salt);
+ }
+
+ public static void main(String[] args) {
+ // 设置盐值长度
+ int saltLength = 16;
+ String salt = generateSalt(saltLength);
+ System.out.println("Generated Salt: " + salt);
+ }
+
+}
diff --git a/src/main/java/cn/soul2/jyjc/admin/vo/UserVO.java b/src/main/java/cn/soul2/jyjc/admin/vo/UserVO.java
new file mode 100644
index 0000000..e1874d0
--- /dev/null
+++ b/src/main/java/cn/soul2/jyjc/admin/vo/UserVO.java
@@ -0,0 +1,38 @@
+package cn.soul2.jyjc.admin.vo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author Soul2
+ * @date 2024-03-30 14:40
+ */
+
+@Data
+@Accessors(chain = true)
+public class UserVO {
+
+ /**
+ * username
+ */
+ private String username;
+
+ /**
+ * token
+ * 其实就是'UserLoginOut'表的id
+ */
+ private String token;
+
+ /**
+ * 权限等级
+ */
+ private String authorityLevel;
+
+ /**
+ * 状态;0(默认):正常;4:封号;9:异常;
+ */
+ private Integer status;
+
+ private String loginFail;
+
+}
diff --git a/src/main/resources/application-cors.yml b/src/main/resources/application-cors.yml
index df0211a..4db7a92 100644
--- a/src/main/resources/application-cors.yml
+++ b/src/main/resources/application-cors.yml
@@ -1,7 +1,7 @@
# 允许跨域的地址
cors:
- allow-origins: http://localhost
+ allow-origin: http://localhost
---
spring:
@@ -9,13 +9,12 @@ spring:
activate:
on-profile: dev
cors:
- allow-origins: http://localhost:6100, http://localhost:7620, http://192.168.10.104:7620
+ allow-origin: http://localhost:6100, http://localhost:7620, http://192.168.10.104:7620
---
spring:
config:
activate:
on-profile: prod
-
cors:
- allow-origins: http://test.soul2.cn
+ allow-origin: http://test.soul2.cn
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index a67f663..396d044 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -4,6 +4,7 @@ server:
#上下文
servlet.context-path: /thli/jyjc/api
+encrypt.keys.aes: 98478f8a45887eda446501bcb44010520c3f53c7b45ff36215e86ce4f049b0f2
spring:
application.name: jyjc-admin