diff --git a/.gitignore b/.gitignore
index 50e85cf..075e000 100644
--- a/.gitignore
+++ b/.gitignore
@@ -140,3 +140,5 @@ gradle-app.setting
# JDT-specific (Eclipse Java Development Tools)
.classpath
+# Running
+run/
\ No newline at end of file
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..b813e49
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ mysql.8
+ true
+ true
+ $PROJECT_DIR$/src/main/resources/application.properties
+ com.mysql.cj.jdbc.Driver
+ jdbc:mysql://wzpmc.cn:3306/itzx
+
+
+
+
+
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..4ac183f
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index fdc392f..096c6cc 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -16,5 +16,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..b1ac391
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/clubs.iml b/.idea/modules/clubs.iml
new file mode 100644
index 0000000..f192152
--- /dev/null
+++ b/.idea/modules/clubs.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/clubs.main.iml b/.idea/modules/clubs.main.iml
new file mode 100644
index 0000000..afc1871
--- /dev/null
+++ b/.idea/modules/clubs.main.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 808c9f5..4c5e8ba 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,33 @@
# ITZX-Clubs-Home-Server
-A clubs home for Hangzhou Electron & Information Vocational School
-building by springboot3.0 with mysql db
\ No newline at end of file
+A clubs home for Hangzhou Electron & Information Vocational School
+building by springboot3.0 with mysql db
+---
+## Usage
+
+### 1.Create user table
+
+```mysql
+create table user
+(
+ id int comment '用户ID(自增)',
+ name varchar(20) not null comment '用户名',
+ password char(40) not null comment '密码(使用SHA1)',
+ auth int default 0 not null comment '用户对应权限组ID',
+ avatar char(40) null comment '用户头像sha1',
+ create_time datetime default now() not null comment '用户创建时间',
+ update_time datetime default now() not null on update now() comment '用户数据更新时间'
+)
+ comment '用户表';
+
+create unique index user_id_index
+ on user (id)
+ comment '用户表主键';
+
+alter table user
+ add constraint user_pk
+ primary key (id) comment '用户表主键';
+
+alter table user
+ modify id int auto_increment comment '用户ID(自增)';
+```
diff --git a/build.gradle.kts b/build.gradle.kts
index 5e1afd8..d12190c 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,6 +4,7 @@ plugins {
id("io.spring.dependency-management") version "1.1.4"
id("org.graalvm.buildtools.native") version "0.9.28"
id("org.asciidoctor.jvm.convert") version "3.3.2"
+ id("org.springdoc.openapi-gradle-plugin") version "1.8.0"
}
group = "org.mmga"
@@ -20,6 +21,10 @@ configurations {
}
repositories {
+ maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
+ maven { url = uri("https://maven.aliyun.com/repository/public/") }
+ maven { url = uri("https://repo.huaweicloud.com/repository/maven/") }
+ maven { url = uri("https://mirrors.cloud.tencent.com/repository/maven/") }
mavenCentral()
}
@@ -32,13 +37,18 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-websocket")
implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3")
implementation("org.springframework.shell:spring-shell-starter")
+ implementation("org.springdoc:springdoc-openapi-starter-webmvc-api:2.5.0")
+ implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0")
+ // https://mvnrepository.com/artifact/commons-codec/commons-codec
+ implementation("commons-codec:commons-codec:1.16.1")
+ // https://mvnrepository.com/artifact/com.auth0/java-jwt
+ implementation("com.auth0:java-jwt:4.4.0")
compileOnly("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("com.mysql:mysql-connector-j")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3")
- testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
}
dependencyManagement {
diff --git a/src/main/java/org/mmga/clubs/commands/UserCommands.java b/src/main/java/org/mmga/clubs/commands/UserCommands.java
new file mode 100644
index 0000000..7105c2b
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/commands/UserCommands.java
@@ -0,0 +1,31 @@
+package org.mmga.clubs.commands;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.mmga.clubs.controller.UserController;
+import org.mmga.clubs.entities.BaseResponse;
+import org.mmga.clubs.entities.user.User;
+import org.mmga.clubs.entities.user.UserLoginVo;
+import org.mmga.clubs.entities.user.UserRegVo;
+import org.mmga.clubs.utils.ShellUtils;
+import org.springframework.shell.standard.ShellComponent;
+import org.springframework.shell.standard.ShellMethod;
+
+@ShellComponent
+@Slf4j
+public class UserCommands {
+ private final UserController userController;
+ public UserCommands(UserController userController){
+ this.userController = userController;
+ }
+ @ShellMethod("创建用户")
+ public void createUser(String name, String password) {
+ BaseResponse user = this.userController.createUser(new UserRegVo(name, DigestUtils.md5Hex(password), 1), null);
+ ShellUtils.logToResult(log, user);
+ }
+ @ShellMethod("登录")
+ public void login(String name, String password) {
+ BaseResponse user = this.userController.login(new UserLoginVo(name, DigestUtils.md5Hex(password)), null);
+ ShellUtils.logToResult(log, user);
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/configuration/DocsConfiguration.java b/src/main/java/org/mmga/clubs/configuration/DocsConfiguration.java
new file mode 100644
index 0000000..90b68dc
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/configuration/DocsConfiguration.java
@@ -0,0 +1,16 @@
+package org.mmga.clubs.configuration;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class DocsConfiguration {
+ @Bean
+ public OpenAPI api(){
+ return new OpenAPI().info(new Info()
+ .title("ITZX-Clubs-Home")
+ .description("杭州电子信息职业学校社团主页"));
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/configuration/ECKeyProviderConfiguration.java b/src/main/java/org/mmga/clubs/configuration/ECKeyProviderConfiguration.java
new file mode 100644
index 0000000..b0b0d6c
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/configuration/ECKeyProviderConfiguration.java
@@ -0,0 +1,81 @@
+package org.mmga.clubs.configuration;
+
+import lombok.SneakyThrows;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+@Configuration
+public class ECKeyProviderConfiguration {
+ private KeyPair keyPair;
+ private ECPublicKey publicKey;
+ private ECPrivateKey privateKey;
+ @SneakyThrows
+ public KeyPair keyPair(){
+ if (this.keyPair != null){
+ return this.keyPair;
+ }
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
+ ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256r1");
+ keyPairGenerator.initialize(ecGenParameterSpec);
+ this.keyPair = keyPairGenerator.generateKeyPair();
+ return this.keyPair;
+ }
+ @SneakyThrows
+ @Bean
+ public ECPublicKey ecPublicKey(){
+ if (this.publicKey == null){
+ File file = new File("jwt_pub.pem");
+ if (file.exists()){
+ FileInputStream publicKeyInputStream = new FileInputStream(file);
+ byte[] publicKeyData = publicKeyInputStream.readAllBytes();
+ publicKeyInputStream.close();
+ KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ this.publicKey = (ECPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyData));
+ }else {
+ this.publicKey = (ECPublicKey) keyPair().getPublic();
+ if (!file.createNewFile()) {
+ throw new RuntimeException("Can't create public key file");
+ }
+ FileOutputStream fileOutputStream = new FileOutputStream(file);
+ fileOutputStream.write(publicKey.getEncoded());
+ fileOutputStream.close();
+ }
+ }
+ return this.publicKey;
+ }
+ @SneakyThrows
+ @Bean
+ public ECPrivateKey ecPrivateKey(){
+ if (this.privateKey == null){
+ File file = new File("jwt_pri.pem");
+ if (file.exists()){
+ FileInputStream publicKeyInputStream = new FileInputStream(file);
+ byte[] publicKeyData = publicKeyInputStream.readAllBytes();
+ publicKeyInputStream.close();
+ KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ this.privateKey = (ECPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(publicKeyData));
+ }else {
+ this.privateKey = (ECPrivateKey) keyPair().getPrivate();
+ if (!file.createNewFile()) {
+ throw new RuntimeException("Can't create private key file");
+ }
+ FileOutputStream fileOutputStream = new FileOutputStream(file);
+ fileOutputStream.write(privateKey.getEncoded());
+ fileOutputStream.close();
+ }
+ }
+ return this.privateKey;
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/controller/UserController.java b/src/main/java/org/mmga/clubs/controller/UserController.java
new file mode 100644
index 0000000..702e41c
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/controller/UserController.java
@@ -0,0 +1,36 @@
+package org.mmga.clubs.controller;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.mmga.clubs.entities.BaseResponse;
+import org.mmga.clubs.entities.user.User;
+import org.mmga.clubs.entities.user.UserLoginVo;
+import org.mmga.clubs.entities.user.UserRegVo;
+import org.mmga.clubs.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/api/user")
+@Tag(name = "用户", description = "用户相关接口")
+@Slf4j
+public class UserController {
+ private final UserService service;
+ @Autowired
+ public UserController(UserService userService){
+ this.service = userService;
+ }
+ @PostMapping("/login")
+ @Operation(description = "用户登录", responses = {@ApiResponse(description = "返回是否登录成功", responseCode = "200")})
+ public BaseResponse login(@RequestBody UserLoginVo user, HttpServletResponse response){
+ return service.login(user, response);
+ }
+ @PutMapping("/create")
+ @Operation(description = "创建用户", responses = {@ApiResponse(description = "返回创建后的用户")})
+ public BaseResponse createUser(@RequestBody UserRegVo user, HttpServletResponse response){
+ return service.createUser(user, response);
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/dao/AuthDao.java b/src/main/java/org/mmga/clubs/dao/AuthDao.java
new file mode 100644
index 0000000..e4790c0
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/dao/AuthDao.java
@@ -0,0 +1,9 @@
+package org.mmga.clubs.dao;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.mmga.clubs.entities.auth.AuthVo;
+
+@Mapper
+public interface AuthDao {
+ AuthVo getAuthById(int id);
+}
diff --git a/src/main/java/org/mmga/clubs/dao/AuthPermissionDao.java b/src/main/java/org/mmga/clubs/dao/AuthPermissionDao.java
new file mode 100644
index 0000000..b7ee5ea
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/dao/AuthPermissionDao.java
@@ -0,0 +1,12 @@
+package org.mmga.clubs.dao;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.mmga.clubs.entities.permission.Permission;
+import org.mmga.clubs.entities.permission.PermissionVo;
+
+import java.util.List;
+
+@Mapper
+public interface AuthPermissionDao {
+ List getAllPermissionByAuthId(int authId);
+}
diff --git a/src/main/java/org/mmga/clubs/dao/PermissionDao.java b/src/main/java/org/mmga/clubs/dao/PermissionDao.java
new file mode 100644
index 0000000..9af6502
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/dao/PermissionDao.java
@@ -0,0 +1,10 @@
+package org.mmga.clubs.dao;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.mmga.clubs.entities.permission.Permission;
+
+import java.util.List;
+
+@Mapper
+public interface PermissionDao {
+}
diff --git a/src/main/java/org/mmga/clubs/dao/PermissionRouterDao.java b/src/main/java/org/mmga/clubs/dao/PermissionRouterDao.java
new file mode 100644
index 0000000..3be2fbc
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/dao/PermissionRouterDao.java
@@ -0,0 +1,11 @@
+package org.mmga.clubs.dao;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.mmga.clubs.entities.router.RouterVo;
+
+import java.util.List;
+
+@Mapper
+public interface PermissionRouterDao {
+ List getRouterByPermissionId(int permissionId);
+}
diff --git a/src/main/java/org/mmga/clubs/dao/RouterDao.java b/src/main/java/org/mmga/clubs/dao/RouterDao.java
new file mode 100644
index 0000000..e4e3de8
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/dao/RouterDao.java
@@ -0,0 +1,7 @@
+package org.mmga.clubs.dao;
+
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface RouterDao {
+}
diff --git a/src/main/java/org/mmga/clubs/dao/UserDao.java b/src/main/java/org/mmga/clubs/dao/UserDao.java
new file mode 100644
index 0000000..832cf83
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/dao/UserDao.java
@@ -0,0 +1,13 @@
+package org.mmga.clubs.dao;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.mmga.clubs.entities.user.UserRegResponseVo;
+import org.mmga.clubs.entities.user.UserVo;
+
+@Mapper
+public interface UserDao {
+ UserVo getUser(String username, String password);
+ void addUser(UserRegResponseVo userVo);
+ int countUser(String username);
+ UserVo getUserById(int id);
+}
diff --git a/src/main/java/org/mmga/clubs/entities/AuthPermissionVo.java b/src/main/java/org/mmga/clubs/entities/AuthPermissionVo.java
new file mode 100644
index 0000000..5183fad
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/AuthPermissionVo.java
@@ -0,0 +1,6 @@
+package org.mmga.clubs.entities;
+
+import java.util.Date;
+
+public record AuthPermissionVo(int authId, int permissionId, Date createTime, Date updateTime) {
+}
diff --git a/src/main/java/org/mmga/clubs/entities/BaseResponse.java b/src/main/java/org/mmga/clubs/entities/BaseResponse.java
new file mode 100644
index 0000000..65dc0b7
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/BaseResponse.java
@@ -0,0 +1,28 @@
+package org.mmga.clubs.entities;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.mmga.clubs.entities.user.User;
+
+@Data
+@Schema(description = "基础返回值")
+public class BaseResponse {
+ @Schema(description = "返回代码(参考HTTP响应码)", examples = {"200", "404", "500", "403"})
+ private int code;
+ @Schema(description = "返回信息(自定义)")
+ private String msg;
+ @Schema(description = "返回数据")
+ private T data;
+ private BaseResponse(int code, String msg, T data){
+ this.code = code;
+ this.msg = msg;
+ this.data = data;
+ }
+ public static BaseResponse success(T data){
+ return new BaseResponse<>(200, "接口执行成功", data);
+ }
+
+ public static BaseResponse failed(int code, String msg) {
+ return new BaseResponse<>(code, msg, null);
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/entities/PermissionRouterVo.java b/src/main/java/org/mmga/clubs/entities/PermissionRouterVo.java
new file mode 100644
index 0000000..4aebccf
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/PermissionRouterVo.java
@@ -0,0 +1,6 @@
+package org.mmga.clubs.entities;
+
+import java.util.Date;
+
+public record PermissionRouterVo (int permissionId, int routerId, Date createTime, Date updateTime) {
+}
diff --git a/src/main/java/org/mmga/clubs/entities/auth/Auth.java b/src/main/java/org/mmga/clubs/entities/auth/Auth.java
new file mode 100644
index 0000000..3d57868
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/auth/Auth.java
@@ -0,0 +1,20 @@
+package org.mmga.clubs.entities.auth;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.mmga.clubs.entities.permission.Permission;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@Schema(description = "用户权限组")
+public class Auth {
+ @Schema(description = "权限组ID")
+ private int id;
+ @Schema(description = "权限组名称")
+ private String name;
+ @Schema(description = "权限组所拥有的权限")
+ private List permissions;
+}
diff --git a/src/main/java/org/mmga/clubs/entities/auth/AuthVo.java b/src/main/java/org/mmga/clubs/entities/auth/AuthVo.java
new file mode 100644
index 0000000..0ec535f
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/auth/AuthVo.java
@@ -0,0 +1,7 @@
+package org.mmga.clubs.entities.auth;
+
+import java.util.Date;
+
+public record AuthVo(int id, String name, Date createTime, Date updateTime) {
+
+}
diff --git a/src/main/java/org/mmga/clubs/entities/permission/Permission.java b/src/main/java/org/mmga/clubs/entities/permission/Permission.java
new file mode 100644
index 0000000..06fba63
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/permission/Permission.java
@@ -0,0 +1,20 @@
+package org.mmga.clubs.entities.permission;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.mmga.clubs.entities.router.Router;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@Schema(description = "单个权限")
+public class Permission {
+ @Schema(description = "权限ID")
+ private int id;
+ @Schema(description = "权限名称")
+ private String name;
+ @Schema(description = "此权限可访问的Router")
+ private List routers;
+}
diff --git a/src/main/java/org/mmga/clubs/entities/permission/PermissionVo.java b/src/main/java/org/mmga/clubs/entities/permission/PermissionVo.java
new file mode 100644
index 0000000..cbf0273
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/permission/PermissionVo.java
@@ -0,0 +1,6 @@
+package org.mmga.clubs.entities.permission;
+
+import java.util.Date;
+
+public record PermissionVo(int id, String name, Date createTime, Date updateTime) {
+}
diff --git a/src/main/java/org/mmga/clubs/entities/router/Router.java b/src/main/java/org/mmga/clubs/entities/router/Router.java
new file mode 100644
index 0000000..5fa92fb
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/router/Router.java
@@ -0,0 +1,21 @@
+package org.mmga.clubs.entities.router;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@Schema(description = "路由节点")
+public class Router {
+ @Schema(description = "节点ID")
+ private int id;
+ @Schema(description = "节点名称")
+ private String name;
+ @Schema(description = "节点对应组件名称")
+ private String component;
+ @Schema(description = "节点的子节点")
+ private List children;
+}
diff --git a/src/main/java/org/mmga/clubs/entities/router/RouterVo.java b/src/main/java/org/mmga/clubs/entities/router/RouterVo.java
new file mode 100644
index 0000000..a53b30b
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/router/RouterVo.java
@@ -0,0 +1,6 @@
+package org.mmga.clubs.entities.router;
+
+import java.util.Date;
+
+public record RouterVo(int id, String name, Integer parent, String component, Date createTime, Date updateTime) {
+}
diff --git a/src/main/java/org/mmga/clubs/entities/user/User.java b/src/main/java/org/mmga/clubs/entities/user/User.java
new file mode 100644
index 0000000..c59298c
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/user/User.java
@@ -0,0 +1,18 @@
+package org.mmga.clubs.entities.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.mmga.clubs.entities.auth.Auth;
+
+@Data
+@Schema(description = "用户")
+public class User {
+ @Schema(description = "用户ID")
+ private int id;
+ @Schema(description = "用户名")
+ private String name;
+ @Schema(description = "用户所在权限组")
+ private Auth auth;
+ @Schema(description = "用户头像SHA1值")
+ private String avatar;
+}
diff --git a/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java b/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java
new file mode 100644
index 0000000..1174fcb
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java
@@ -0,0 +1,7 @@
+package org.mmga.clubs.entities.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(description = "用户登录参数类")
+public record UserLoginVo(@Schema(description = "用户名") String username,@Schema(description = "用户密码(使用MD5摘要后的hex字符串)") String password) {
+}
diff --git a/src/main/java/org/mmga/clubs/entities/user/UserRegResponseVo.java b/src/main/java/org/mmga/clubs/entities/user/UserRegResponseVo.java
new file mode 100644
index 0000000..9d2cf83
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/user/UserRegResponseVo.java
@@ -0,0 +1,17 @@
+package org.mmga.clubs.entities.user;
+
+import lombok.Data;
+import org.apache.commons.codec.digest.DigestUtils;
+
+@Data
+public class UserRegResponseVo {
+ private int id;
+ private final String username;
+ private final String password;
+ private final int auth;
+ public UserRegResponseVo(UserRegVo userRegVo) {
+ this.username = userRegVo.username();
+ this.password = DigestUtils.sha1Hex(userRegVo.password());
+ this.auth = userRegVo.auth();
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/entities/user/UserRegVo.java b/src/main/java/org/mmga/clubs/entities/user/UserRegVo.java
new file mode 100644
index 0000000..8bc3033
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/user/UserRegVo.java
@@ -0,0 +1,7 @@
+package org.mmga.clubs.entities.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(description = "用户注册参数")
+public record UserRegVo(@Schema(description = "用户名") String username,@Schema(description = "密码(使用MD5摘要后的hex字符串)") String password,@Schema(description = "用户的权限组ID") int auth) {
+}
diff --git a/src/main/java/org/mmga/clubs/entities/user/UserVo.java b/src/main/java/org/mmga/clubs/entities/user/UserVo.java
new file mode 100644
index 0000000..8afcce0
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/entities/user/UserVo.java
@@ -0,0 +1,6 @@
+package org.mmga.clubs.entities.user;
+
+import java.util.Date;
+
+public record UserVo(int id, String name, String password, int auth, String avatar, Date createTime, Date updateTime) {
+}
diff --git a/src/main/java/org/mmga/clubs/service/AuthService.java b/src/main/java/org/mmga/clubs/service/AuthService.java
new file mode 100644
index 0000000..c3c8a4e
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/service/AuthService.java
@@ -0,0 +1,32 @@
+package org.mmga.clubs.service;
+
+import org.mmga.clubs.dao.AuthDao;
+import org.mmga.clubs.dao.AuthPermissionDao;
+import org.mmga.clubs.entities.auth.Auth;
+import org.mmga.clubs.entities.auth.AuthVo;
+import org.mmga.clubs.entities.permission.Permission;
+import org.mmga.clubs.entities.permission.PermissionVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class AuthService {
+ private final AuthDao authDao;
+ private final AuthPermissionDao authPermissionDao;
+ private final PermissionService permissionService;
+ @Autowired
+ public AuthService(AuthDao authDao, AuthPermissionDao authPermissionDao, PermissionService permissionService) {
+ this.authDao = authDao;
+ this.authPermissionDao = authPermissionDao;
+ this.permissionService = permissionService;
+ }
+
+ public Auth getAuthById(int auth) {
+ AuthVo authVo = this.authDao.getAuthById(auth);
+ List permissionVos = this.authPermissionDao.getAllPermissionByAuthId(auth);
+ List permissions = permissionVos.stream().map(permissionService::packagePermission).toList();
+ return new Auth(authVo.id(), authVo.name(), permissions);
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/service/PermissionService.java b/src/main/java/org/mmga/clubs/service/PermissionService.java
new file mode 100644
index 0000000..30c393a
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/service/PermissionService.java
@@ -0,0 +1,29 @@
+package org.mmga.clubs.service;
+
+import org.mmga.clubs.dao.PermissionDao;
+import org.mmga.clubs.dao.PermissionRouterDao;
+import org.mmga.clubs.entities.permission.Permission;
+import org.mmga.clubs.entities.permission.PermissionVo;
+import org.mmga.clubs.entities.router.Router;
+import org.mmga.clubs.entities.router.RouterVo;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class PermissionService {
+ private final PermissionDao permissionDao;
+ private final PermissionRouterDao permissionRouterDao;
+ private final RouterService routerService;
+ public PermissionService(PermissionDao permissionDao, PermissionRouterDao permissionRouterDao, RouterService routerService) {
+ this.permissionDao = permissionDao;
+ this.permissionRouterDao = permissionRouterDao;
+ this.routerService = routerService;
+ }
+ public Permission packagePermission(PermissionVo vo){
+ int id = vo.id();
+ List routerVos = permissionRouterDao.getRouterByPermissionId(id);
+ List routers = this.routerService.packageRouter(routerVos);
+ return new Permission(id, vo.name(), routers);
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/service/RouterService.java b/src/main/java/org/mmga/clubs/service/RouterService.java
new file mode 100644
index 0000000..e1d01bc
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/service/RouterService.java
@@ -0,0 +1,36 @@
+package org.mmga.clubs.service;
+
+import org.mmga.clubs.dao.RouterDao;
+import org.mmga.clubs.entities.router.Router;
+import org.mmga.clubs.entities.router.RouterVo;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class RouterService {
+ private final RouterDao routerDao;
+ public RouterService(RouterDao routerDao) {
+ this.routerDao = routerDao;
+ }
+ public List packageRouter(List routerVos) {
+ Map idRouterMap = new HashMap<>();
+ List rootId = new ArrayList<>();
+ for (RouterVo routerVo : routerVos) {
+ idRouterMap.put(routerVo.id(), new Router(routerVo.id(), routerVo.name(), routerVo.component(), new ArrayList<>()));
+ if (routerVo.parent() == null){
+ rootId.add(routerVo.id());
+ }
+ }
+ for (RouterVo routerVo : routerVos) {
+ Integer parent = routerVo.parent();
+ if (parent != null) {
+ idRouterMap.get(parent).getChildren().add(idRouterMap.get(routerVo.id()));
+ }
+ }
+ return rootId.stream().map(idRouterMap::get).toList();
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/service/UserService.java b/src/main/java/org/mmga/clubs/service/UserService.java
new file mode 100644
index 0000000..c3373e4
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/service/UserService.java
@@ -0,0 +1,57 @@
+package org.mmga.clubs.service;
+
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.mmga.clubs.dao.UserDao;
+import org.mmga.clubs.entities.BaseResponse;
+import org.mmga.clubs.entities.user.*;
+import org.mmga.clubs.utils.JwtUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UserService {
+ private final UserDao userDao;
+ private final AuthService authService;
+ private final JwtUtils jwtUtils;
+ @Autowired
+ public UserService(UserDao userDao, AuthService authService, JwtUtils jwtUtils){
+ this.userDao = userDao;
+ this.authService = authService;
+ this.jwtUtils = jwtUtils;
+ }
+
+ public BaseResponse login(UserLoginVo user, HttpServletResponse response) {
+ UserVo userVo = userDao.getUser(user.username(), DigestUtils.sha1Hex(user.password()));
+ User u = packageUser(userVo);
+ if (response != null && u != null){
+ response.addHeader("Set-Authorization", jwtUtils.createToken(u));
+ }
+ return u == null ? BaseResponse.failed(404, "无效用户") : BaseResponse.success(u);
+ }
+
+ public BaseResponse createUser(UserRegVo user, HttpServletResponse response) {
+ String username = user.username();
+ if (userDao.countUser(username) > 0) {
+ return BaseResponse.failed(409, "用户已存在");
+ }
+ UserRegResponseVo responseVo = new UserRegResponseVo(user);
+ userDao.addUser(responseVo);
+ int newUserId = responseVo.getId();
+ User newUser = packageUser(userDao.getUserById(newUserId));
+ if (newUser != null && response != null) {
+ response.addHeader("Set-Authorization", jwtUtils.createToken(newUser));
+ }
+ return BaseResponse.success(newUser);
+ }
+ private User packageUser(UserVo vo) {
+ if (vo == null){
+ return null;
+ }
+ User result = new User();
+ result.setId(vo.id());
+ result.setName(vo.name());
+ result.setAuth(authService.getAuthById(vo.auth()));
+ return result;
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/utils/JwtUtils.java b/src/main/java/org/mmga/clubs/utils/JwtUtils.java
new file mode 100644
index 0000000..b085014
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/utils/JwtUtils.java
@@ -0,0 +1,28 @@
+package org.mmga.clubs.utils;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import lombok.extern.slf4j.Slf4j;
+import org.mmga.clubs.entities.user.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+
+@Component
+@Slf4j
+public class JwtUtils {
+ private final ECPublicKey ecPublicKey;
+ private final ECPrivateKey ecPrivateKey;
+ @Autowired
+ public JwtUtils(ECPublicKey ecPublicKey, ECPrivateKey ecPrivateKey){
+ this.ecPublicKey = ecPublicKey;
+ this.ecPrivateKey = ecPrivateKey;
+ }
+ public String createToken(User user){
+ String jwt = JWT.create().withClaim("uid", user.getId()).sign(Algorithm.ECDSA512(ecPublicKey, ecPrivateKey));
+ log.debug("对用户:{},生成JWT:{}", user.getName(), jwt);
+ return jwt;
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/utils/ShellUtils.java b/src/main/java/org/mmga/clubs/utils/ShellUtils.java
new file mode 100644
index 0000000..5f3f4b5
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/utils/ShellUtils.java
@@ -0,0 +1,13 @@
+package org.mmga.clubs.utils;
+
+import org.mmga.clubs.entities.BaseResponse;
+import org.slf4j.Logger;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ShellUtils {
+ public static void logToResult(Logger logger, BaseResponse> response){
+ logger.info("返回代码:{},返回信息:{}", response.getCode(), response.getMsg());
+ logger.info("返回结果:{}", response.getData());
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 4417e0c..58de871 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1 +1,2 @@
spring.application.name=ITZX-Clubs-Home-Server
+springdoc.swagger-ui.path=/docs
\ No newline at end of file
diff --git a/src/main/resources/org/mmga/clubs/dao/AuthDao.xml b/src/main/resources/org/mmga/clubs/dao/AuthDao.xml
new file mode 100644
index 0000000..7f088dd
--- /dev/null
+++ b/src/main/resources/org/mmga/clubs/dao/AuthDao.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/org/mmga/clubs/dao/AuthPermissionDao.xml b/src/main/resources/org/mmga/clubs/dao/AuthPermissionDao.xml
new file mode 100644
index 0000000..761de38
--- /dev/null
+++ b/src/main/resources/org/mmga/clubs/dao/AuthPermissionDao.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/org/mmga/clubs/dao/PermissionDao.xml b/src/main/resources/org/mmga/clubs/dao/PermissionDao.xml
new file mode 100644
index 0000000..66e547d
--- /dev/null
+++ b/src/main/resources/org/mmga/clubs/dao/PermissionDao.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/org/mmga/clubs/dao/PermissionRouterDao.xml b/src/main/resources/org/mmga/clubs/dao/PermissionRouterDao.xml
new file mode 100644
index 0000000..5e5b9a7
--- /dev/null
+++ b/src/main/resources/org/mmga/clubs/dao/PermissionRouterDao.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/org/mmga/clubs/dao/RouterDao.xml b/src/main/resources/org/mmga/clubs/dao/RouterDao.xml
new file mode 100644
index 0000000..dc0a90d
--- /dev/null
+++ b/src/main/resources/org/mmga/clubs/dao/RouterDao.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/org/mmga/clubs/dao/UserDao.xml b/src/main/resources/org/mmga/clubs/dao/UserDao.xml
new file mode 100644
index 0000000..a1f60ec
--- /dev/null
+++ b/src/main/resources/org/mmga/clubs/dao/UserDao.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ insert into `user`(`name`, `password`, `auth`) values(#{username}, #{password}, #{auth});
+
+
+
+
+
\ No newline at end of file