commit 6d0159ad3469687180ba6bfeccdf7421557ce533
Author: mingchen <3177583214@qq.com>
Date: Fri Apr 18 09:11:40 2025 +0800
feat(*):基本代码完成
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..c716fec
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..b9d561c
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..be5f5c6
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..0abcc97
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api/log/blog-dev/spring.log-2025-04-17-0.log b/api/log/blog-dev/spring.log-2025-04-17-0.log
new file mode 100644
index 0000000..b7e9c00
--- /dev/null
+++ b/api/log/blog-dev/spring.log-2025-04-17-0.log
@@ -0,0 +1,57 @@
+2025-04-17 09:39:41.724 INFO 5255 --- [main] com.mingchen.BlogApiApplicationTests : Starting BlogApiApplicationTests on mingchendeMac-mini.local with PID 5255 (started by mingchen in /Users/mingchen/code/java/other/legalAid/api)
+2025-04-17 09:39:41.724 DEBUG 5255 --- [main] com.mingchen.BlogApiApplicationTests : Running with Spring Boot v2.2.7.RELEASE, Spring v5.2.6.RELEASE
+2025-04-17 09:39:41.724 INFO 5255 --- [main] com.mingchen.BlogApiApplicationTests : The following profiles are active: dev
+2025-04-17 09:39:41.975 INFO 5255 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
+2025-04-17 09:39:41.977 INFO 5255 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
+2025-04-17 09:39:41.991 INFO 5255 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 9ms. Found 0 Redis repository interfaces.
+2025-04-17 09:39:42.303 ERROR 5255 --- [main] c.b.m.core.MybatisConfiguration : mapper[com.mingchen.mapper.CategoriesMapper.getAllCategoriesWithLaws] is ignored, because it exists, maybe from xml file
+2025-04-17 09:39:42.999 INFO 5255 --- [main] n.b.p.u.AbstractUserAgentAnalyzerDirect : - Loaded 90 files in 390 msec using expression: classpath*:UserAgents/**/*.yaml
+2025-04-17 09:39:43.000 INFO 5255 --- [main] n.b.parse.useragent.utils.YauaaVersion :
+2025-04-17 09:39:43.000 INFO 5255 --- [main] n.b.parse.useragent.utils.YauaaVersion : /-----------------------------------------------------------\
+2025-04-17 09:39:43.000 INFO 5255 --- [main] n.b.parse.useragent.utils.YauaaVersion : | Yauaa 5.20 (v5.20 @ 2020-11-22T15:39:16Z) |
+2025-04-17 09:39:43.000 INFO 5255 --- [main] n.b.parse.useragent.utils.YauaaVersion : +-----------------------------------------------------------+
+2025-04-17 09:39:43.000 INFO 5255 --- [main] n.b.parse.useragent.utils.YauaaVersion : | For more information: https://yauaa.basjes.nl |
+2025-04-17 09:39:43.000 INFO 5255 --- [main] n.b.parse.useragent.utils.YauaaVersion : | Copyright (C) 2013-2020 Niels Basjes - License Apache 2.0 |
+2025-04-17 09:39:43.000 INFO 5255 --- [main] n.b.parse.useragent.utils.YauaaVersion : \-----------------------------------------------------------/
+2025-04-17 09:39:43.000 INFO 5255 --- [main] n.b.parse.useragent.utils.YauaaVersion :
+2025-04-17 09:39:43.006 INFO 5255 --- [main] n.b.p.u.AbstractUserAgentAnalyzerDirect : Building all needed matchers for the requested 11 fields.
+2025-04-17 09:39:43.150 INFO 5255 --- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2025-04-17 09:39:43.312 INFO 5255 --- [main] org.quartz.impl.StdSchedulerFactory : Using default implementation for ThreadExecutor
+2025-04-17 09:39:43.315 INFO 5255 --- [main] org.quartz.core.SchedulerSignalerImpl : Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
+2025-04-17 09:39:43.316 INFO 5255 --- [main] org.quartz.core.QuartzScheduler : Quartz Scheduler v.2.3.2 created.
+2025-04-17 09:39:43.316 INFO 5255 --- [main] org.quartz.simpl.RAMJobStore : RAMJobStore initialized.
+2025-04-17 09:39:43.316 INFO 5255 --- [main] org.quartz.core.QuartzScheduler : Scheduler meta-data: Quartz Scheduler (v2.3.2) 'quartzScheduler' with instanceId 'NON_CLUSTERED'
+ Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
+ NOT STARTED.
+ Currently in standby mode.
+ Number of jobs executed: 0
+ Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
+ Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
+
+2025-04-17 09:39:43.316 INFO 5255 --- [main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'quartzScheduler' initialized from an externally provided properties instance.
+2025-04-17 09:39:43.316 INFO 5255 --- [main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.3.2
+2025-04-17 09:39:43.316 INFO 5255 --- [main] org.quartz.core.QuartzScheduler : JobFactory set to: org.springframework.scheduling.quartz.SpringBeanJobFactory@665902eb
+2025-04-17 09:39:43.367 INFO 5255 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3ad9f06a, org.springframework.security.web.context.SecurityContextPersistenceFilter@68769265, org.springframework.security.web.header.HeaderWriterFilter@5d6de24e, org.springframework.web.filter.CorsFilter@72cb5d7d, org.springframework.security.web.authentication.logout.LogoutFilter@4603845b, com.mingchen.common.config.JwtLoginFilter@19b89a23, com.mingchen.common.config.JwtFilter@6d1a4522, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@68c1d547, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@7951a08c, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1835b24b, org.springframework.security.web.session.SessionManagementFilter@6dd0d9a2, org.springframework.security.web.access.ExceptionTranslationFilter@5680228, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@b88d294]
+2025-04-17 09:39:43.391 INFO 5255 --- [main] o.s.s.quartz.SchedulerFactoryBean : Starting Quartz Scheduler now
+2025-04-17 09:39:43.391 INFO 5255 --- [main] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED started.
+2025-04-17 09:39:43.395 INFO 5255 --- [main] com.mingchen.BlogApiApplicationTests : Started BlogApiApplicationTests in 1.84 seconds (JVM running for 2.462)
+2025-04-17 09:39:43.499 INFO 5255 --- [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
+2025-04-17 09:39:43.996 INFO 5255 --- [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
+2025-04-17 09:39:44.000 DEBUG 5255 --- [main] c.m.m.C.getAllCategoriesWithLaws : ==> Preparing: SELECT c.category_id, c.name, c.description, l.law_id, l.category_id AS law_category_id, l.title, l.summary, l.content, l.effective_date, l.reference_url FROM categories c LEFT JOIN laws l ON c.category_id = l.category_id ORDER BY c.category_id, l.law_id
+2025-04-17 09:39:44.009 DEBUG 5255 --- [main] c.m.m.C.getAllCategoriesWithLaws : ==> Parameters:
+2025-04-17 09:39:44.078 DEBUG 5255 --- [main] c.m.m.C.getAllCategoriesWithLaws : <== Total: 5
+2025-04-17 09:39:44.088 INFO 5255 --- [SpringContextShutdownHook] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED paused.
+2025-04-17 09:39:44.088 INFO 5255 --- [SpringContextShutdownHook] o.s.s.quartz.SchedulerFactoryBean : Shutting down Quartz Scheduler
+2025-04-17 09:39:44.089 INFO 5255 --- [SpringContextShutdownHook] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED shutting down.
+2025-04-17 09:39:44.089 INFO 5255 --- [SpringContextShutdownHook] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED paused.
+2025-04-17 09:39:44.089 INFO 5255 --- [SpringContextShutdownHook] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED shutdown complete.
+2025-04-17 09:39:44.089 INFO 5255 --- [SpringContextShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
+2025-04-17 09:39:44.098 INFO 5255 --- [SpringContextShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
+2025-04-17 09:39:44.102 INFO 5255 --- [SpringContextShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
+2025-04-17 09:42:54.720 INFO 5460 --- [main] com.mingchen.BlogApiApplicationTests : Starting BlogApiApplicationTests on mingchendeMac-mini.local with PID 5460 (started by mingchen in /Users/mingchen/code/java/other/legalAid/api)
+2025-04-17 09:42:54.722 DEBUG 5460 --- [main] com.mingchen.BlogApiApplicationTests : Running with Spring Boot v2.2.7.RELEASE, Spring v5.2.6.RELEASE
+2025-04-17 09:42:54.722 INFO 5460 --- [main] com.mingchen.BlogApiApplicationTests : The following profiles are active: dev
+2025-04-17 09:42:54.991 INFO 5460 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
+2025-04-17 09:42:54.993 INFO 5460 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
+2025-04-17 09:42:55.011 INFO 5460 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 12ms. Found 0 Redis repository interfaces.
+2025-04-17 09:42:55.355 ERROR 5460 --- [main] c.b.m.core.MybatisConfiguration : mapper[com.mingchen.mapper.CategoriesMapper.getAllCategoriesWithLaws] is ignored, because it exists, maybe from xml file
diff --git a/api/pom.xml b/api/pom.xml
new file mode 100644
index 0000000..1f65bdd
--- /dev/null
+++ b/api/pom.xml
@@ -0,0 +1,202 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.7.RELEASE
+
+
+ com.mingchen
+ api
+ 0.0.1
+ api
+ https://mingchen.com/
+ API
+
+
+ 1.8
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+
+ mingchen
+ common
+ 1.1-SNAPSHOT
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.4.3
+
+
+ com.baomidou
+ mybatis-plus-core
+ 3.5.5
+
+
+ com.baomidou
+ mybatis-plus-extension
+ 3.4.3
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 2.3.0
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+ 1.2.12
+
+
+
+ mysql
+ mysql-connector-java
+ runtime
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.20
+ true
+
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.1
+
+
+
+ com.atlassian.commonmark
+ commonmark
+ 0.15.2
+
+
+ com.atlassian.commonmark
+ commonmark-ext-heading-anchor
+ 0.15.2
+
+
+ com.atlassian.commonmark
+ commonmark-ext-gfm-tables
+ 0.15.2
+
+
+ com.atlassian.commonmark
+ commonmark-ext-gfm-strikethrough
+ 0.15.2
+
+
+ com.atlassian.commonmark
+ commonmark-ext-task-list-items
+ 0.15.2
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+ org.springframework.boot
+ spring-boot-starter-mail
+
+
+
+ org.springframework.boot
+ spring-boot-starter-quartz
+
+
+
+ org.lionsoul
+ ip2region
+ 1.7.2
+
+
+
+ nl.basjes.parse.useragent
+ yauaa
+ 5.20
+
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+ javax.xml.bind
+ jaxb-api
+ 2.3.1
+
+
+ org.glassfish.jaxb
+ jaxb-runtime
+ 2.3.1
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 9
+ 9
+
+
+
+
+
+
diff --git a/api/src/main/java/com/mingchen/BlogApiApplication.java b/api/src/main/java/com/mingchen/BlogApiApplication.java
new file mode 100644
index 0000000..5803c75
--- /dev/null
+++ b/api/src/main/java/com/mingchen/BlogApiApplication.java
@@ -0,0 +1,15 @@
+package com.mingchen;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.mingchen.mapper")
+public class BlogApiApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(BlogApiApplication.class, args);
+ }
+
+}
diff --git a/api/src/main/java/com/mingchen/api/open/ApiController.java b/api/src/main/java/com/mingchen/api/open/ApiController.java
new file mode 100644
index 0000000..fbf142f
--- /dev/null
+++ b/api/src/main/java/com/mingchen/api/open/ApiController.java
@@ -0,0 +1,25 @@
+package com.mingchen.api.open;
+
+import com.mingchen.model.vo.Result;
+import com.mingchen.service.impl.PlatformServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/admin/ai")
+public class ApiController {
+ @Autowired
+ private PlatformServiceImpl platformService;
+ @PostMapping()
+ public Result getChat(@RequestParam String content) {
+ return platformService.getChat(content);
+
+ }
+
+ @GetMapping("/test")
+ public Result test(){
+ return Result.ok("test");
+ }
+
+}
diff --git a/api/src/main/java/com/mingchen/api/open/CategoriesController.java b/api/src/main/java/com/mingchen/api/open/CategoriesController.java
new file mode 100644
index 0000000..c82d17b
--- /dev/null
+++ b/api/src/main/java/com/mingchen/api/open/CategoriesController.java
@@ -0,0 +1,30 @@
+package com.mingchen.api.open;
+
+
+import com.mingchen.model.vo.Result;
+import com.mingchen.service.ICategoriesService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author mingchen
+ * @since 2025-04-17
+ */
+@RestController
+@RequestMapping("admin/categories")
+public class CategoriesController {
+ @Autowired
+ private ICategoriesService categoriesService;
+ @GetMapping()
+ public Result getCategories(){
+ return categoriesService.getCategories();
+ }
+
+}
diff --git a/api/src/main/java/com/mingchen/api/open/LawsController.java b/api/src/main/java/com/mingchen/api/open/LawsController.java
new file mode 100644
index 0000000..8ad88f7
--- /dev/null
+++ b/api/src/main/java/com/mingchen/api/open/LawsController.java
@@ -0,0 +1,20 @@
+package com.mingchen.api.open;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author mingchen
+ * @since 2025-04-17
+ */
+@RestController
+@RequestMapping("/laws")
+public class LawsController {
+
+}
diff --git a/api/src/main/java/com/mingchen/api/open/LearningResourcesController.java b/api/src/main/java/com/mingchen/api/open/LearningResourcesController.java
new file mode 100644
index 0000000..4561fb7
--- /dev/null
+++ b/api/src/main/java/com/mingchen/api/open/LearningResourcesController.java
@@ -0,0 +1,33 @@
+package com.mingchen.api.open;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.mingchen.entity.LearningResources;
+import com.mingchen.model.vo.Result;
+import com.mingchen.service.ILearningResourcesService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author mingchen
+ * @since 2025-04-17
+ */
+@RestController
+@RequestMapping("admin/learningResources")
+public class LearningResourcesController {
+ @Autowired
+ private ILearningResourcesService learningResourcesService;
+ @GetMapping("/page")
+ public Result getLearningResources(@RequestParam(defaultValue = "1") int current,
+ @RequestParam(defaultValue = "10") int size){
+ return learningResourcesService.getLearningResources(current, size);
+ }
+}
diff --git a/api/src/main/java/com/mingchen/api/open/LegalAidResourcesController.java b/api/src/main/java/com/mingchen/api/open/LegalAidResourcesController.java
new file mode 100644
index 0000000..21cc520
--- /dev/null
+++ b/api/src/main/java/com/mingchen/api/open/LegalAidResourcesController.java
@@ -0,0 +1,35 @@
+package com.mingchen.api.open;
+
+
+import com.mingchen.model.vo.Result;
+import com.mingchen.service.ILegalAidResourcesService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author mingchen
+ * @since 2025-04-17
+ */
+@RestController
+@RequestMapping("admin/legalAidResources")
+public class LegalAidResourcesController {
+ @Autowired
+ private ILegalAidResourcesService legalAidResourcesService;
+
+ @GetMapping("/page")
+ public Result getLegalAidResources(@RequestParam(defaultValue = "1") int current,
+ @RequestParam(defaultValue = "10") int size){
+
+ return legalAidResourcesService.getLegalAidResources(current,size);
+
+ }
+
+}
diff --git a/api/src/main/java/com/mingchen/api/open/LoginController.java b/api/src/main/java/com/mingchen/api/open/LoginController.java
new file mode 100644
index 0000000..a54f55d
--- /dev/null
+++ b/api/src/main/java/com/mingchen/api/open/LoginController.java
@@ -0,0 +1,50 @@
+package com.mingchen.api.open;
+
+import com.itmingchen.common.utils.JwtTool;
+import com.mingchen.entity.User;
+import com.mingchen.model.dto.LoginInfoDTO;
+import com.mingchen.model.vo.Result;
+import com.mingchen.service.UserService;
+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;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Description: 前台登录
+ * @Date: 2024-09-02
+ */
+@RestController
+@RequestMapping("/admin/login")
+public class LoginController {
+ @Autowired
+ UserService userService;
+ @Resource
+ private JwtTool jwtTool;
+
+ /**
+ * 登录成功后,签发博主身份Token
+ *
+ * @param loginInfoDTO
+ * @return
+ */
+ @PostMapping()
+ public Result login(@RequestBody LoginInfoDTO loginInfoDTO) {
+// User user = userService.findUserByUsernameAndPassword(loginInfoDTO.getUsername(), loginInfoDTO.getPassword());
+// if (!"ROLE_admin".equals(user.getRole())) {
+// return Result.create(403, "无权限");
+// }
+ User user = userService.findUserByEmailAndPassword(loginInfoDTO);
+ user.setPassword(null);
+ String jwt = jwtTool.createToken(user.getUserId(), user.getEmail());
+ Map map = new HashMap<>();
+ map.put("user", user);
+ map.put("token", jwt);
+ return Result.ok("登录成功", map);
+ }
+}
diff --git a/api/src/main/java/com/mingchen/api/open/RegisterController.java b/api/src/main/java/com/mingchen/api/open/RegisterController.java
new file mode 100644
index 0000000..48fe2bf
--- /dev/null
+++ b/api/src/main/java/com/mingchen/api/open/RegisterController.java
@@ -0,0 +1,41 @@
+package com.mingchen.api.open;
+
+import com.mingchen.model.dto.RegisterReqDTO;
+import com.mingchen.model.vo.Result;
+import com.mingchen.service.RegisterService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @ClassName RegisterController
+ * @Description: 注册
+ * @Author: 3177583214@qq.com
+ */
+@RestController
+@RequestMapping("/register")
+public class RegisterController {
+ @Autowired
+ private RegisterService registerService;
+
+
+ /**
+ * 发送验证码
+ * @param userEmail 邮箱
+ */
+ @PostMapping("/sendEmail")
+ public void send(@RequestParam String userEmail){
+ registerService.send(userEmail);
+ }
+
+ /**
+ * 注册
+ * @param registerReqDTO 注册信息
+ */
+ @PostMapping()
+ public Result institutionRegister(@RequestBody RegisterReqDTO registerReqDTO) {
+ Result res = registerService.register(registerReqDTO);
+ return res;
+ }
+
+
+}
diff --git a/api/src/main/java/com/mingchen/api/open/UserController.java b/api/src/main/java/com/mingchen/api/open/UserController.java
new file mode 100644
index 0000000..fdba105
--- /dev/null
+++ b/api/src/main/java/com/mingchen/api/open/UserController.java
@@ -0,0 +1,21 @@
+package com.mingchen.api.open;
+
+import com.mingchen.model.vo.Result;
+import com.mingchen.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/admin")
+public class UserController {
+ @Autowired
+ UserService userService;
+
+
+ @GetMapping("/getUserInfo")
+ public Result getUserInfo(){
+ return userService.getUserInfo();
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/mingchen/api/sdk/AiService.java b/api/src/main/java/com/mingchen/api/sdk/AiService.java
new file mode 100644
index 0000000..c3f82f0
--- /dev/null
+++ b/api/src/main/java/com/mingchen/api/sdk/AiService.java
@@ -0,0 +1,20 @@
+package com.mingchen.api.sdk;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.json.JSONUtil;
+import com.mingchen.model.req.AiReq;
+import com.mingchen.model.resp.AiResp;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AiService {
+ public AiResp getChatApi(String url, String token,AiReq aiReq){
+ HttpResponse resp = HttpRequest.post(url)
+ .header("Authorization","Bearer "+token)
+ .body(JSONUtil.toJsonStr(aiReq))
+ .timeout(200000)
+ .execute();
+ return JSONUtil.toBean(resp.body(), AiResp.class);
+ }
+}
diff --git a/api/src/main/java/com/mingchen/common/config/CustomAuthenticationProvider.java b/api/src/main/java/com/mingchen/common/config/CustomAuthenticationProvider.java
new file mode 100644
index 0000000..9f37167
--- /dev/null
+++ b/api/src/main/java/com/mingchen/common/config/CustomAuthenticationProvider.java
@@ -0,0 +1,48 @@
+package com.mingchen.common.config;
+
+import com.itmingchen.common.expcetions.ErrorRequestException;
+import com.itmingchen.common.utils.StringUtils;
+import com.mingchen.service.impl.UserServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CustomAuthenticationProvider implements AuthenticationProvider {
+
+ @Autowired
+ private UserServiceImpl userService; // UserDetailsService 的实现
+ @Autowired
+ private PasswordEncoder passwordEncoder; // 密码编码器
+
+ @Override
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+ String email = authentication.getName(); // 提取用户名(电子邮件)
+ String password = authentication.getCredentials().toString(); // 提取密码
+
+ // 校验邮箱是否存在
+ if(StringUtils.isEmpty(email)) throw new ErrorRequestException("请输入邮箱");
+ // 校验密码是否存在
+ if(StringUtils.isEmpty(password)) throw new ErrorRequestException("请输入密码");
+ // 加载用户信息
+ UserDetails userDetails = userService.loadUserByUsername(email);
+
+ // 验证密码
+ if (!passwordEncoder.matches(password, userDetails.getPassword())) {
+ throw new BadCredentialsException("密码错误,请重新输入");
+ }
+ // 如果密码匹配,返回一个认证对象
+ return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
+ }
+
+ @Override
+ public boolean supports(Class> authentication) {
+ return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
+ }
+}
diff --git a/api/src/main/java/com/mingchen/common/config/JwtFilter.java b/api/src/main/java/com/mingchen/common/config/JwtFilter.java
new file mode 100644
index 0000000..c2439b6
--- /dev/null
+++ b/api/src/main/java/com/mingchen/common/config/JwtFilter.java
@@ -0,0 +1,70 @@
+package com.mingchen.common.config;
+
+import com.itmingchen.common.utils.JacksonUtils;
+import com.itmingchen.common.utils.JwtTool;
+import com.mingchen.model.vo.Result;
+import io.jsonwebtoken.Claims;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @Description: JWT请求过滤器
+ * @Date: 2024-07-21
+ */
+public class JwtFilter extends GenericFilterBean {
+
+ // 定义放行的路径和对应方法
+ private static final Set PERMIT_PATHS = Set.of(
+ "/register", // POST
+ "register/sendEmail" // POST
+ );
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+ //后台管理路径外的请求直接跳过
+ String path = request.getServletPath();
+ HttpMethod method = HttpMethod.resolve(request.getMethod());
+
+ // 统一判断路径和方法是否放行
+ if (PERMIT_PATHS.contains(path) && HttpMethod.POST == method) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+ String jwt = request.getHeader("Authorization");
+ if (JwtTool.judgeTokenIsExist(jwt)) {
+ try {
+ Claims claims = JwtTool.getTokenBody(jwt);
+ String email = claims.getSubject();
+ List authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("authorities"));
+ UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(email, null, authorities);
+ SecurityContextHolder.getContext().setAuthentication(token);
+ } catch (Exception e) {
+ e.printStackTrace();
+ response.setContentType("application/json;charset=utf-8");
+ Result result = Result.create(403, "凭证已失效,请重新登录!");
+ PrintWriter out = response.getWriter();
+ out.write(JacksonUtils.writeValueAsString(result));
+ out.flush();
+ out.close();
+ return;
+ }
+ }
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/mingchen/common/config/JwtLoginFilter.java b/api/src/main/java/com/mingchen/common/config/JwtLoginFilter.java
new file mode 100644
index 0000000..3a6b162
--- /dev/null
+++ b/api/src/main/java/com/mingchen/common/config/JwtLoginFilter.java
@@ -0,0 +1,102 @@
+package com.mingchen.common.config;
+
+import com.itmingchen.common.expcetions.ErrorRequestException;
+import com.itmingchen.common.utils.JacksonUtils;
+import com.itmingchen.common.utils.JwtTool;
+import com.mingchen.entity.User;
+import com.mingchen.model.vo.Result;
+import com.mingchen.service.LoginLogService;
+import org.springframework.security.authentication.*;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+
+import javax.servlet.FilterChain;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Description: JWT登录过滤器
+ * @Date: 2024-07-21
+ */
+public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {
+ LoginLogService loginLogService;
+ ThreadLocal currentUsername = new ThreadLocal<>();
+
+ // 可以在这里进行增加配置管理 如进行用户登陆信息初始化
+ protected JwtLoginFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager, LoginLogService loginLogService) {
+ super(new AntPathRequestMatcher(defaultFilterProcessesUrl));
+ setAuthenticationManager(authenticationManager);
+ this.loginLogService = loginLogService;
+ }
+
+ @Override
+ public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
+ throws AuthenticationException, IOException {
+ try {
+ if (!"POST".equals(request.getMethod())) {
+ throw new ErrorRequestException("请求方法错误");
+
+ }
+ User user = JacksonUtils.readValue(request.getInputStream(), User.class);
+ currentUsername.set(user.getEmail());
+
+ return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword()));
+ } catch (ErrorRequestException exception) {
+ response.setContentType("application/json;charset=utf-8");
+ Result result = Result.create(400, "非法请求");
+ PrintWriter out = response.getWriter();
+ out.write(JacksonUtils.writeValueAsString(result));
+ out.flush();
+ out.close();
+ }
+ return null;
+ }
+
+ @Override
+ protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
+ FilterChain chain, Authentication authResult) throws IOException {
+
+ // 更换验证方式 只在具体实现类更改逻辑 更符合编码设计
+ String jwt = JwtTool.generateToken(authResult.getName(), authResult.getAuthorities());
+ response.setContentType("application/json;charset=utf-8");
+ User user = (User) authResult.getPrincipal();
+ user.setPassword(null);
+ Map map = new HashMap<>();
+ map.put("user", user);
+ map.put("token", jwt);
+ Result result = Result.ok("登录成功", map);
+ PrintWriter out = response.getWriter();
+ out.write(JacksonUtils.writeValueAsString(result));
+ out.flush();
+ out.close();
+ }
+
+ @Override
+ protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException exception) throws IOException {
+ response.setContentType("application/json;charset=utf-8");
+ String msg = exception.getMessage();
+ //登录不成功时,会抛出对应的异常
+ if (exception instanceof LockedException) {
+ msg = "账号被锁定";
+ } else if (exception instanceof CredentialsExpiredException) {
+ msg = "密码过期";
+ } else if (exception instanceof AccountExpiredException) {
+ msg = "账号过期";
+ } else if (exception instanceof DisabledException) {
+ msg = "账号被禁用";
+ } else if (exception instanceof BadCredentialsException) {
+ msg = "用户名或密码错误";
+ }
+ PrintWriter out = response.getWriter();
+ out.write(JacksonUtils.writeValueAsString(Result.create(401, msg)));
+ out.flush();
+ out.close();
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/mingchen/common/config/MyAuthenticationEntryPoint.java b/api/src/main/java/com/mingchen/common/config/MyAuthenticationEntryPoint.java
new file mode 100644
index 0000000..e4e466f
--- /dev/null
+++ b/api/src/main/java/com/mingchen/common/config/MyAuthenticationEntryPoint.java
@@ -0,0 +1,31 @@
+package com.mingchen.common.config;
+
+import com.mingchen.model.vo.Result;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+import com.itmingchen.common.utils.JacksonUtils;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @Description: 未登录 拒绝访问
+ * @Date: 2024-07-21
+ */
+@Component
+public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
+ @Override
+ public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
+ throws IOException, ServletException {
+ response.setContentType("application/json;charset=utf-8");
+ PrintWriter out = response.getWriter();
+ Result result = Result.create(403, "请登录");
+ out.write(JacksonUtils.writeValueAsString(result));
+ out.flush();
+ out.close();
+ }
+}
diff --git a/api/src/main/java/com/mingchen/common/config/SecurityConfig.java b/api/src/main/java/com/mingchen/common/config/SecurityConfig.java
new file mode 100644
index 0000000..e7033af
--- /dev/null
+++ b/api/src/main/java/com/mingchen/common/config/SecurityConfig.java
@@ -0,0 +1,59 @@
+package com.mingchen.common.config;
+
+import com.mingchen.service.LoginLogService;
+import com.mingchen.service.impl.UserServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+/**
+ * @Description: Spring Security配置类
+ * @Date: 2024-07-19
+ */
+@Configuration
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+ @Autowired
+ UserServiceImpl userService;
+ @Autowired
+ LoginLogService loginLogService;
+ @Autowired
+ MyAuthenticationEntryPoint myAuthenticationEntryPoint;
+ @Autowired
+ private CustomAuthenticationProvider customAuthenticationProvider;
+
+
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.authenticationProvider(customAuthenticationProvider); // 使用自定义的 AuthenticationProvider
+ }
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ //禁用 csrf 防御
+ .csrf().disable()
+ //开启跨域支持
+ .cors().and()
+ //基于Token,不创建会话
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
+ .authorizeRequests()
+ //放行获取网页标题后缀的请求
+ .antMatchers("/admin/webTitleSuffix").permitAll()
+ //任何 /admin 开头的路径下的请求都需要经过JWT验证
+ .antMatchers(HttpMethod.GET, "/admin/**").hasAnyRole("admin", "visitor")
+ .antMatchers("/admin/**").hasRole("admin")
+ //其它路径全部放行
+ .anyRequest().permitAll()
+ .and()
+ //自定义JWT过滤器
+ .addFilterBefore(new JwtLoginFilter("/admin/login", authenticationManager(), loginLogService), UsernamePasswordAuthenticationFilter.class)
+ .addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class)
+ //未登录时,返回json,在前端执行重定向
+ .exceptionHandling().authenticationEntryPoint(myAuthenticationEntryPoint);
+ }
+}
diff --git a/api/src/main/java/com/mingchen/common/config/WebConfig.java b/api/src/main/java/com/mingchen/common/config/WebConfig.java
new file mode 100644
index 0000000..1116ded
--- /dev/null
+++ b/api/src/main/java/com/mingchen/common/config/WebConfig.java
@@ -0,0 +1,38 @@
+package com.mingchen.common.config;
+
+import com.mingchen.common.interceptor.AccessLimitInterceptor;
+import com.mingchen.common.interceptor.UserContextInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @Description: CORS跨域支持
+ * @Date: 2024-07-22
+ */
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+ @Autowired
+ AccessLimitInterceptor accessLimitInterceptor;
+ @Autowired
+ UserContextInterceptor userContextInterceptor;
+
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("*")
+ .allowedHeaders("*")
+ .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS")
+ .maxAge(3600);
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(accessLimitInterceptor);
+ registry.addInterceptor(userContextInterceptor);
+ }
+}
diff --git a/api/src/main/java/com/mingchen/common/config/configuration/BeanConfiguration.java b/api/src/main/java/com/mingchen/common/config/configuration/BeanConfiguration.java
new file mode 100644
index 0000000..bc2c839
--- /dev/null
+++ b/api/src/main/java/com/mingchen/common/config/configuration/BeanConfiguration.java
@@ -0,0 +1,68 @@
+package com.mingchen.common.config.configuration;
+
+import com.itmingchen.common.utils.*;
+import com.mingchen.common.properties.ApplicationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+import javax.annotation.Resource;
+
+@Configuration
+public class BeanConfiguration {
+
+ @Resource
+ private ApplicationProperties applicationProperties;
+
+
+ @Bean
+ public RedisUtils RedisUtils() {
+ return new RedisUtils();
+ }
+
+ @Bean
+ public RedisUtil RedisUtil() {
+ return new RedisUtil();
+ }
+
+ @Bean
+ public MailUtils MailUtils() {
+ return new MailUtils();
+ }
+
+
+ @Bean
+ public HashUtils HashUtils() {
+ return new HashUtils();
+ }
+
+
+
+ @Bean
+ public IpAddressUtils IpAddressUtils() {
+ return new IpAddressUtils();
+ }
+
+ @Bean
+ public JacksonUtils JacksonUtils() {
+ return new JacksonUtils();
+ }
+
+
+ @Bean
+ public JwtTool jwtTool() {
+ return new JwtTool(applicationProperties.getJwtKey());
+ }
+
+ @Bean
+ public UserAgentUtils UserAgentUtils() {
+ return new UserAgentUtils();
+ }
+
+
+ @Bean
+ public BCryptPasswordEncoder bCryptPasswordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/mingchen/common/config/configuration/MyBatisConfig.java b/api/src/main/java/com/mingchen/common/config/configuration/MyBatisConfig.java
new file mode 100644
index 0000000..0ec950d
--- /dev/null
+++ b/api/src/main/java/com/mingchen/common/config/configuration/MyBatisConfig.java
@@ -0,0 +1,22 @@
+package com.mingchen.common.config.configuration;
+
+import com.github.pagehelper.PageHelper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Properties;
+
+@Configuration
+public class MyBatisConfig {
+ // 设置相关的参数信息,下面有对参数的详细解释
+ @Bean
+ public PageHelper pageHelper() {
+ PageHelper pageHelper = new PageHelper();
+ Properties properties = new Properties();
+ properties.setProperty("dialect", "Mysql");
+ properties.setProperty("offsetAsPageNum", "true");
+ properties.setProperty("rowBoundsWithCount", "true");
+ pageHelper.setProperties(properties);
+ return pageHelper;
+ }
+}
diff --git a/api/src/main/java/com/mingchen/common/config/configuration/RedisConfig.java b/api/src/main/java/com/mingchen/common/config/configuration/RedisConfig.java
new file mode 100644
index 0000000..ca89e67
--- /dev/null
+++ b/api/src/main/java/com/mingchen/common/config/configuration/RedisConfig.java
@@ -0,0 +1,33 @@
+package com.mingchen.common.config.configuration;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+@Configuration
+public class RedisConfig {
+
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory){
+ RedisTemplate template = new RedisTemplate<>();
+ template.setConnectionFactory(connectionFactory);
+
+ // 使用 Jackson2JsonRedisSerializer 替换默认序列化
+ Jackson2JsonRedisSerializer