Update: cache module, security modules and build

This commit is contained in:
likingcode
2026-03-18 15:18:41 +08:00
parent 4a0737ddeb
commit d257e3595d
48 changed files with 2076 additions and 822 deletions

71
pom.xml
View File

@@ -66,12 +66,83 @@
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- ==================== 可插拔组件 ==================== -->
<!-- Spring Security + JWT -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
<!-- Sa-Token 鉴权 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>1.37.0</version>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- 缓存抽象 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- PostgreSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

View File

@@ -7,697 +7,113 @@
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.2.3)
2026-03-07T08:57:24.832Z INFO 1395465 --- [springboot-scaffold] [ main] c.e.s.SpringbootScaffoldApplication : Starting SpringbootScaffoldApplication v1.0.0 using Java 21.0.10 with PID 1395465 (/home/llm/Projects/springboot-scaffold/target/springboot-scaffold-1.0.0.jar started by llm in /home/llm/Projects/springboot-scaffold)
2026-03-07T08:57:24.840Z DEBUG 1395465 --- [springboot-scaffold] [ main] c.e.s.SpringbootScaffoldApplication : Running with Spring Boot v3.2.3, Spring v6.1.4
2026-03-07T08:57:24.843Z INFO 1395465 --- [springboot-scaffold] [ main] c.e.s.SpringbootScaffoldApplication : No active profile set, falling back to 1 default profile: "default"
2026-03-07T08:57:32.385Z INFO 1395465 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2026-03-07T08:57:32.453Z INFO 1395465 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 30 ms. Found 0 JPA repository interfaces.
2026-03-07T08:57:39.150Z INFO 1395465 --- [springboot-scaffold] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8082 (http)
2026-03-07T08:57:39.218Z INFO 1395465 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2026-03-07T08:57:39.222Z INFO 1395465 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.19]
2026-03-07T08:57:39.853Z INFO 1395465 --- [springboot-scaffold] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2026-03-07T08:57:39.862Z INFO 1395465 --- [springboot-scaffold] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 14718 ms
2026-03-07T08:57:41.622Z INFO 1395465 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2026-03-07T08:57:43.594Z INFO 1395465 --- [springboot-scaffold] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA
2026-03-07T08:57:43.610Z INFO 1395465 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2026-03-07T08:57:43.680Z INFO 1395465 --- [springboot-scaffold] [ main] o.s.b.a.h2.H2ConsoleAutoConfiguration : H2 console available at '/h2-console'. Database available at 'jdbc:h2:file:~/h2/springboot_scaffold'
2026-03-07T08:57:47.458Z INFO 1395465 --- [springboot-scaffold] [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2026-03-07T08:57:47.796Z INFO 1395465 --- [springboot-scaffold] [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.4.4.Final
2026-03-07T08:57:48.002Z INFO 1395465 --- [springboot-scaffold] [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled
2026-03-07T08:57:49.405Z INFO 1395465 --- [springboot-scaffold] [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
2026-03-07T08:57:56.408Z INFO 1395465 --- [springboot-scaffold] [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
2026-03-07T08:57:56.727Z INFO 1395465 --- [springboot-scaffold] [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
2026-03-07T08:58:00.775Z WARN 1395465 --- [springboot-scaffold] [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2026-03-07T08:58:01.509Z INFO 1395465 --- [springboot-scaffold] [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html]
2026-03-07T08:58:10.592Z INFO 1395465 --- [springboot-scaffold] [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator'
2026-03-07T08:58:11.582Z INFO 1395465 --- [springboot-scaffold] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8082 (http) with context path ''
2026-03-07T08:58:11.689Z INFO 1395465 --- [springboot-scaffold] [ main] c.e.s.SpringbootScaffoldApplication : Started SpringbootScaffoldApplication in 49.545 seconds (process running for 52.6)
2026-03-07T08:58:55.808Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-03-07T08:58:55.810Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2026-03-07T08:58:55.824Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 8 ms
2026-03-07T08:58:56.276Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: RootController.index() 参数: []
2026-03-07T08:58:56.277Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: RootController.index() 耗时: 1ms
2026-03-07T09:04:54.453Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: RootController.index() 参数: []
2026-03-07T09:04:54.454Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: RootController.index() 耗时: 1ms
2026-03-07T09:04:54.926Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
2026-03-07T09:04:54.927Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:04:54.927Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
2026-03-07T09:04:54.932Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:04:54.936Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
Creating a new SqlSession
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7edf21ef] was not registered for synchronization because synchronization is not active
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e00c432] was not registered for synchronization because synchronization is not active
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@40942315] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.0
JDBC Connection [HikariProxyConnection@1678050146 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
JDBC Connection [HikariProxyConnection@990931398 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
JDBC Connection [HikariProxyConnection@130499610 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Preparing: SELECT COUNT(*) FROM users
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
==> Parameters:
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e00c432]
<== Columns: COUNT(*)
<== Row: 0
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7edf21ef]
2026-03-07T09:04:55.109Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 183ms
2026-03-07T09:04:55.106Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:04:55.110Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:04:55.110Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 183ms
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@40942315]
2026-03-07T09:04:55.136Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:04:55.136Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:04:55.136Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 204ms
2026-03-07T09:05:06.090Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7377beec] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@978555190 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
2026-03-07T09:05:06.093Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:05:06.093Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@90950fc] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@428815786 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
2026-03-07T09:05:06.089Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:05:06.094Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@440b2f50] was not registered for synchronization because synchronization is not active
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7377beec]
2026-03-07T09:05:06.096Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 6ms
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@90950fc]
2026-03-07T09:05:06.100Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:05:06.100Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:05:06.100Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 7ms
As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@440b2f50]
2026-03-07T09:05:06.117Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:05:06.118Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:05:06.118Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 29ms
2026-03-07T09:05:36.083Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:05:36.083Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@34150731] was not registered for synchronization because synchronization is not active
2026-03-07T09:05:36.084Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@50a60d1e] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@770987400 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
JDBC Connection [HikariProxyConnection@1647938239 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@34150731]
2026-03-07T09:05:36.086Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:05:36.082Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@50a60d1e]
2026-03-07T09:05:36.087Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 3ms
2026-03-07T09:05:36.087Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@736d353] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.6666666666666666
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@736d353]
2026-03-07T09:05:36.093Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:05:36.093Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:05:36.093Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 11ms
2026-03-07T09:05:36.086Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:05:36.094Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 11ms
2026-03-07T09:06:06.078Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:06:06.078Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
2026-03-07T09:06:06.080Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@43ee2751] was not registered for synchronization because synchronization is not active
2026-03-07T09:06:06.077Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:06:06.081Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@40db3c0a] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1204923380 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@43ee2751]
2026-03-07T09:06:06.082Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 2ms
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@17dc9322] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@565369255 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@17dc9322]
2026-03-07T09:06:06.084Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:06:06.084Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.75
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@40db3c0a]
2026-03-07T09:06:06.086Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:06:06.087Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:06:06.087Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 10ms
2026-03-07T09:06:06.084Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 6ms
2026-03-07T09:06:36.080Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@17588e60] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1674264023 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@17588e60]
2026-03-07T09:06:36.082Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:06:36.085Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cd52d5e] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1429246749 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cd52d5e]
2026-03-07T09:06:36.086Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:06:36.077Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:06:36.086Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@79bd0b9e] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@79bd0b9e]
2026-03-07T09:06:36.085Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 5ms
2026-03-07T09:06:36.087Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:06:36.093Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:06:36.093Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 16ms
2026-03-07T09:06:36.086Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:06:36.095Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 17ms
2026-03-07T09:06:41.293Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:06:41.293Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1a0b0f13] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@462297636 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1a0b0f13]
2026-03-07T09:06:41.296Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2d32d6a] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@25026644 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2d32d6a]
2026-03-07T09:06:41.301Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 5ms
2026-03-07T09:06:41.294Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:06:41.301Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6b43759c] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8333333333333334
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6b43759c]
2026-03-07T09:06:41.302Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:06:41.302Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:06:41.299Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:06:41.306Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:06:41.306Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 13ms
2026-03-07T09:06:41.309Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 15ms
2026-03-07T09:08:41.365Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:08:41.365Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5f9384ac] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@250235960 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
2026-03-07T09:08:41.369Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:08:41.365Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35e2cef0] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8571428571428571
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35e2cef0]
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5f9384ac]
2026-03-07T09:08:41.371Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 6ms
2026-03-07T09:08:41.369Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2412cfb] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@945724641 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2412cfb]
2026-03-07T09:08:41.371Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:08:41.378Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:08:41.378Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 13ms
2026-03-07T09:08:41.382Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:08:41.383Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:08:41.383Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 14ms
2026-03-07T09:09:11.381Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:09:11.389Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@339b8b85] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@2044663817 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
2026-03-07T09:09:11.385Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:09:11.393Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@e836b18] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.875
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@e836b18]
2026-03-07T09:09:11.378Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@25bb0795] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1706570017 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@339b8b85]
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@25bb0795]
2026-03-07T09:09:11.401Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 23ms
2026-03-07T09:09:11.398Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:09:11.403Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:09:11.404Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 23ms
2026-03-07T09:09:11.407Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:09:11.407Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:09:11.407Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 22ms
2026-03-07T09:09:57.591Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:09:57.591Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@76aff600] was not registered for synchronization because synchronization is not active
2026-03-07T09:09:57.592Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:09:57.592Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@62fcd225] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@216920430 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
2026-03-07T09:09:57.593Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b9672e8] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@103531179 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8888888888888888
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@76aff600]
2026-03-07T09:09:57.599Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:09:57.599Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:09:57.599Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 8ms
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@62fcd225]
2026-03-07T09:09:57.600Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:09:57.600Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:09:57.600Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 8ms
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b9672e8]
2026-03-07T09:09:57.603Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 10ms
2026-03-07T09:10:15.699Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:10:15.699Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
2026-03-07T09:10:15.700Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4ee6ebd7] was not registered for synchronization because synchronization is not active
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6f7c93a3] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.9
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6f7c93a3]
2026-03-07T09:10:15.702Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:10:15.702Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:10:15.702Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 3ms
JDBC Connection [HikariProxyConnection@995189036 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4ee6ebd7]
2026-03-07T09:10:15.704Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 4ms
2026-03-07T09:10:15.720Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:10:15.724Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@619fee3f] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1251411904 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@619fee3f]
2026-03-07T09:10:15.734Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:10:15.738Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:10:15.738Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 18ms
2026-03-07T09:10:45.697Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@41732ca4] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1767511888 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@41732ca4]
2026-03-07T09:10:45.698Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 7ms
2026-03-07T09:10:45.694Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:10:45.699Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16edaf1a] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.9090909090909091
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16edaf1a]
2026-03-07T09:10:45.700Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:10:45.700Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:10:45.695Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:10:45.702Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@634584d5] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1658574820 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@634584d5]
2026-03-07T09:10:45.705Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 6ms
2026-03-07T09:10:45.703Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:10:45.709Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:10:45.710Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 15ms
2026-03-07T09:11:15.696Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:11:15.698Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@78a4240e] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@611531950 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
2026-03-07T09:11:15.694Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:11:15.699Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2709c912] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.9166666666666666
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2709c912]
2026-03-07T09:11:15.700Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:11:15.700Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:11:15.700Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 6ms
2026-03-07T09:11:15.700Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4900755b] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@985053914 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4900755b]
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@78a4240e]
2026-03-07T09:11:15.704Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 6ms
2026-03-07T09:11:15.708Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:11:15.708Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:11:15.708Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 12ms
2026-03-07T09:11:20.259Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.list() 参数: []
2026-03-07T09:11:20.260Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.findAll()
2026-03-07T09:11:20.260Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.e.s.service.impl.UserServiceImpl : 📊 [UserService] 查询所有用户
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75988cd9] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8461538461538461
JDBC Connection [HikariProxyConnection@1859934865 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM users ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75988cd9]
2026-03-07T09:11:20.265Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.findAll() => ArrayList
2026-03-07T09:11:20.265Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.findAll()
2026-03-07T09:11:20.265Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.list() 耗时: 6ms
2026-03-07T09:13:39.723Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:13:39.723Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@66b24c60] was not registered for synchronization because synchronization is not active
2026-03-07T09:13:39.720Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@abcee10] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1337876771 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@abcee10]
2026-03-07T09:13:39.726Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:13:39.726Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@dfe33ca] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@101992541 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8571428571428571
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@66b24c60]
2026-03-07T09:13:39.728Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:13:39.728Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:13:39.728Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 6ms
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@dfe33ca]
2026-03-07T09:13:39.728Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:13:39.728Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:13:39.728Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 6ms
2026-03-07T09:13:39.724Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 4ms
2026-03-07T09:13:46.169Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.list() 参数: []
2026-03-07T09:13:46.169Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.findAll()
2026-03-07T09:13:46.169Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.e.s.service.impl.UserServiceImpl : 📊 [UserService] 查询所有用户
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5d32c3a4] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8666666666666667
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5d32c3a4]
2026-03-07T09:13:46.171Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.findAll() => ArrayList
2026-03-07T09:13:46.171Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.findAll()
2026-03-07T09:13:46.171Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.list() 耗时: 2ms
2026-03-07T09:13:50.492Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:13:50.506Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:13:50.506Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@53c286a4] was not registered for synchronization because synchronization is not active
2026-03-07T09:13:50.510Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@47d7de43] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@927509680 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@47d7de43]
2026-03-07T09:13:50.512Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:13:50.513Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@31bcbe4a] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@201598228 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.875
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@53c286a4]
2026-03-07T09:13:50.517Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:13:50.520Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:13:50.521Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 29ms
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@31bcbe4a]
2026-03-07T09:13:50.524Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 11ms
2026-03-07T09:13:50.517Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:13:50.532Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-8] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 26ms
2026-03-07T09:13:58.593Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6b758231] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@2126245868 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6b758231]
2026-03-07T09:13:58.595Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:13:58.600Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@31c79940] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8823529411764706
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@31c79940]
2026-03-07T09:13:58.601Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:13:58.601Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:13:58.593Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:13:58.602Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cf45f69] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1134251079 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
2026-03-07T09:13:58.600Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 7ms
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cf45f69]
2026-03-07T09:13:58.608Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 13ms
2026-03-07T09:13:58.606Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:13:58.611Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:13:58.611Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 18ms
2026-03-07T09:14:28.582Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:14:28.582Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
2026-03-07T09:14:28.582Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@54ca2e3c] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1838371682 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@54ca2e3c]
2026-03-07T09:14:28.583Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:14:28.584Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3de435fb] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8888888888888888
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3de435fb]
2026-03-07T09:14:28.584Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2770fa1] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@859350386 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2770fa1]
2026-03-07T09:14:28.583Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 1ms
2026-03-07T09:14:28.589Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:14:28.590Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 7ms
2026-03-07T09:14:28.587Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:14:28.591Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:14:28.591Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 9ms
2026-03-07T09:14:58.931Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:14:58.932Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
2026-03-07T09:14:58.936Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:14:58.936Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4ff48ae6] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@908619933 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
2026-03-07T09:14:58.938Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3989ee74] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.8947368421052632
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3989ee74]
2026-03-07T09:14:58.940Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:14:58.940Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:14:58.940Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 9ms
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4ff48ae6]
2026-03-07T09:14:58.944Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:14:58.944Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:14:58.944Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 8ms
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3fbc7956] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@721325685 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3fbc7956]
2026-03-07T09:14:58.948Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 10ms
2026-03-07T09:15:28.926Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:15:28.926Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5021275e] was not registered for synchronization because synchronization is not active
2026-03-07T09:15:28.928Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:15:28.929Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3f87579d] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@469087888 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
2026-03-07T09:15:28.929Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5e8dc242] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.9
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5e8dc242]
2026-03-07T09:15:28.930Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:15:28.930Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:15:28.930Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 8ms
JDBC Connection [HikariProxyConnection@1372181421 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5021275e]
2026-03-07T09:15:28.934Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:15:28.934Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:15:28.934Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 8ms
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3f87579d]
2026-03-07T09:15:28.938Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 9ms
2026-03-07T09:15:58.931Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:15:58.936Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10ce968c] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1714135762 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
2026-03-07T09:15:58.932Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@42485dce] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@2065854273 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
2026-03-07T09:15:58.934Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:15:58.939Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@447777c4] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.9047619047619048
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@447777c4]
2026-03-07T09:15:58.940Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:15:58.940Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10ce968c]
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@42485dce]
2026-03-07T09:15:58.944Z INFO 1395465 --- [springboot-scaffold] [io-8082-exec-10] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 10ms
2026-03-07T09:15:58.944Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:15:58.945Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:15:58.944Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 12ms
2026-03-07T09:15:58.947Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 16ms
2026-03-07T09:16:28.924Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2ed3de82] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@349902318 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2ed3de82]
2026-03-07T09:16:28.928Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 4ms
2026-03-07T09:16:28.926Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:16:28.930Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@89ed8c5] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@736052548 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@89ed8c5]
2026-03-07T09:16:28.927Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
2026-03-07T09:16:28.932Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@66047844] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.9090909090909091
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@66047844]
2026-03-07T09:16:28.933Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:16:28.933Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:16:28.933Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-2] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 6ms
2026-03-07T09:16:28.931Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:16:28.937Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:16:28.937Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-9] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 11ms
2026-03-07T09:16:58.931Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
2026-03-07T09:16:58.931Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@79f75a00] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@692524477 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
2026-03-07T09:16:58.932Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@79f75a00]
2026-03-07T09:16:58.933Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
2026-03-07T09:16:58.934Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
2026-03-07T09:16:58.937Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
2026-03-07T09:16:58.937Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 6ms
Creating a new SqlSession
2026-03-07T09:16:58.938Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@140850d4] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.9130434782608695
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@140850d4]
2026-03-07T09:16:58.939Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
2026-03-07T09:16:58.939Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
2026-03-07T09:16:58.939Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 7ms
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75cdad47] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@411658786 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
==> Parameters:
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75cdad47]
2026-03-07T09:16:58.940Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 6ms
2026-03-07T09:46:43.594Z INFO 1411782 --- [springboot-scaffold] [ main] c.e.s.SpringbootScaffoldApplication : Starting SpringbootScaffoldApplication v1.0.0 using Java 21.0.10 with PID 1411782 (/home/llm/Projects/springboot-scaffold/target/springboot-scaffold-1.0.0.jar started by llm in /home/llm/Projects/springboot-scaffold)
2026-03-07T09:46:43.612Z DEBUG 1411782 --- [springboot-scaffold] [ main] c.e.s.SpringbootScaffoldApplication : Running with Spring Boot v3.2.3, Spring v6.1.4
2026-03-07T09:46:43.616Z INFO 1411782 --- [springboot-scaffold] [ main] c.e.s.SpringbootScaffoldApplication : No active profile set, falling back to 1 default profile: "default"
2026-03-07T09:46:51.883Z INFO 1411782 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2026-03-07T09:46:51.893Z INFO 1411782 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2026-03-07T09:46:51.970Z INFO 1411782 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 44 ms. Found 0 JPA repository interfaces.
2026-03-07T09:46:52.055Z INFO 1411782 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2026-03-07T09:46:52.058Z INFO 1411782 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2026-03-07T09:46:52.120Z INFO 1411782 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 20 ms. Found 0 Redis repository interfaces.
2026-03-07T09:47:00.903Z INFO 1411782 --- [springboot-scaffold] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8082 (http)
2026-03-07T09:47:00.979Z INFO 1411782 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2026-03-07T09:47:00.986Z INFO 1411782 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.19]
2026-03-07T09:47:01.536Z INFO 1411782 --- [springboot-scaffold] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2026-03-07T09:47:01.543Z INFO 1411782 --- [springboot-scaffold] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 17641 ms
2026-03-07T09:47:03.138Z INFO 1411782 --- [springboot-scaffold] [ main] c.e.s.config.database.DatabaseConfig : 🚀 使用 H2 内存数据库
2026-03-07T09:47:03.393Z INFO 1411782 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2026-03-07T09:47:05.499Z INFO 1411782 --- [springboot-scaffold] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA
2026-03-07T09:47:05.513Z INFO 1411782 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2026-03-07T09:47:05.595Z INFO 1411782 --- [springboot-scaffold] [ main] o.s.b.a.h2.H2ConsoleAutoConfiguration : H2 console available at '/h2-console'. Database available at 'jdbc:h2:file:~/h2/springboot_scaffold'
2026-03-07T09:47:06.561Z WARN 1411782 --- [springboot-scaffold] [ main] o.s.aop.framework.CglibAopProxy : Unable to proxy interface-implementing method [public final void org.springframework.web.filter.OncePerRequestFilter.doFilter(jakarta.servlet.ServletRequest,jakarta.servlet.ServletResponse,jakarta.servlet.FilterChain) throws jakarta.servlet.ServletException,java.io.IOException] because it is marked as final, consider using interface-based JDK proxies instead.
2026-03-07T09:47:06.561Z WARN 1411782 --- [springboot-scaffold] [ main] o.s.aop.framework.CglibAopProxy : Unable to proxy interface-implementing method [public final void org.springframework.web.filter.GenericFilterBean.init(jakarta.servlet.FilterConfig) throws jakarta.servlet.ServletException] because it is marked as final, consider using interface-based JDK proxies instead.
2026-03-07T09:47:08.518Z ERROR 1411782 --- [springboot-scaffold] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Exception starting filter [jwtAuthenticationFilter]
java.lang.NullPointerException: Cannot invoke "org.apache.commons.logging.Log.isDebugEnabled()" because "this.logger" is null
at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:239) ~[spring-web-6.1.4.jar!/:6.1.4]
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:263) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:102) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4287) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4902) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1332) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1322) ~[tomcat-embed-core-10.1.19.jar!/:na]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-10.1.19.jar!/:na]
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) ~[na:na]
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:845) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1332) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1322) ~[tomcat-embed-core-10.1.19.jar!/:na]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-10.1.19.jar!/:na]
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) ~[na:na]
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:240) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:433) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:921) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.apache.catalina.startup.Tomcat.start(Tomcat.java:437) ~[tomcat-embed-core-10.1.19.jar!/:na]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:126) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:105) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:499) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:218) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:188) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:162) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:618) ~[spring-context-6.1.4.jar!/:6.1.4]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-3.2.3.jar!/:3.2.3]
at com.example.scaffold.SpringbootScaffoldApplication.main(SpringbootScaffoldApplication.java:9) ~[!/:1.0.0]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91) ~[springboot-scaffold-1.0.0.jar:1.0.0]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53) ~[springboot-scaffold-1.0.0.jar:1.0.0]
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58) ~[springboot-scaffold-1.0.0.jar:1.0.0]
2026-03-07T09:47:08.551Z ERROR 1411782 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardContext : One or more Filters failed to start. Full details will be found in the appropriate container log file
2026-03-07T09:47:08.555Z ERROR 1411782 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardContext : Context [] startup failed due to previous errors
2026-03-07T09:47:08.698Z INFO 1411782 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2026-03-07T09:47:08.716Z WARN 1411782 --- [springboot-scaffold] [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server
2026-03-07T09:47:08.720Z INFO 1411782 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2026-03-07T09:47:08.971Z INFO 1411782 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
2026-03-07T09:47:09.105Z INFO 1411782 --- [springboot-scaffold] [ main] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2026-03-07T09:47:09.207Z ERROR 1411782 --- [springboot-scaffold] [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:165) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:618) ~[spring-context-6.1.4.jar!/:6.1.4]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-3.2.3.jar!/:3.2.3]
at com.example.scaffold.SpringbootScaffoldApplication.main(SpringbootScaffoldApplication.java:9) ~[!/:1.0.0]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91) ~[springboot-scaffold-1.0.0.jar:1.0.0]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53) ~[springboot-scaffold-1.0.0.jar:1.0.0]
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58) ~[springboot-scaffold-1.0.0.jar:1.0.0]
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:145) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:105) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:499) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:218) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:188) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:162) ~[spring-boot-3.2.3.jar!/:3.2.3]
... 13 common frames omitted
Caused by: java.lang.IllegalStateException: StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[] failed to start
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.rethrowDeferredStartupExceptions(TomcatWebServer.java:207) ~[spring-boot-3.2.3.jar!/:3.2.3]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:129) ~[spring-boot-3.2.3.jar!/:3.2.3]
... 18 common frames omitted

View File

@@ -0,0 +1,100 @@
package com.example.scaffold.cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
/**
* 缓存配置 - 支持 Caffeine(本地) 和 Redis(分布式)
*
* 学习要点:
* 1. @EnableCaching - 启用 Spring Cache
* 2. @Cacheable - 缓存方法结果
* 3. @CacheEvict - 清除缓存
* 4. @CachePut - 更新缓存
*/
@Slf4j
@Configuration
@EnableCaching
public class CacheConfig {
/**
* Caffeine 本地缓存 - 默认
*/
@Bean
@Primary
@ConditionalOnProperty(name = "cache.type", havingValue = "caffeine", matchIfMissing = true)
public CacheManager caffeineCacheManager() {
log.info("🚀 启用 Caffeine 本地缓存");
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
// 初始容量
.initialCapacity(100)
// 最大容量
.maximumSize(1000)
// 写入后过期时间
.expireAfterWrite(10, TimeUnit.MINUTES)
// 记录命中率
.recordStats()
);
return cacheManager;
}
/**
* Redis 分布式缓存
*/
@Bean
@ConditionalOnProperty(name = "cache.type", havingValue = "redis")
public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
log.info("🚀 启用 Redis 分布式缓存");
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
// 键序列化
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
// 值序列化
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()))
// 过期时间
.entryTtl(Duration.ofMinutes(10))
// 不缓存 null
.disableCachingNullValues();
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
/**
* 自定义缓存 Key 生成器
*/
@Bean
public KeyGenerator customKeyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getSimpleName()).append(":");
sb.append(method.getName()).append(":");
for (Object param : params) {
sb.append(param).append("-");
}
return sb.toString();
};
}
}

View File

@@ -0,0 +1,143 @@
package com.example.scaffold.cache;
import com.example.scaffold.entity.User;
import com.example.scaffold.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* 缓存服务 - 演示 Spring Cache 和 Redis 操作
*
* 学习要点:
* 1. @Cacheable - 方法结果缓存
* 2. @CachePut - 更新缓存
* 3. @CacheEvict - 清除缓存
* 4. RedisTemplate - 直接操作 Redis
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class CacheService {
private final UserMapper userMapper;
private final StringRedisTemplate redisTemplate;
/**
* 根据ID查询用户 - 使用缓存
*
* @Cacheable 注解说明:
* - value: 缓存名称
* - key: 缓存键(支持 SpEL 表达式)
* - unless: 条件,为 true 时不缓存
*/
@Cacheable(value = "users", key = "#id", unless = "#result == null")
public User getUserById(Long id) {
log.info("🔍 [Cache] 从数据库查询用户: id={}", id);
return userMapper.findById(id);
}
/**
* 更新用户 - 更新缓存
*
* @CachePut 注解说明:
* - 方法一定会执行
* - 执行后更新缓存
*/
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
log.info("💾 [Cache] 更新用户并刷新缓存: id={}", user.getId());
userMapper.update(user);
return user;
}
/**
* 删除用户 - 清除缓存
*
* @CacheEvict 注解说明:
* - 清除指定缓存
* - allEntries = true: 清除所有条目
* - beforeInvocation = true: 方法执行前清除
*/
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
log.info("🗑️ [Cache] 删除用户并清除缓存: id={}", id);
userMapper.deleteById(id);
}
/**
* 清除所有用户缓存
*/
@CacheEvict(value = "users", allEntries = true)
public void clearUserCache() {
log.info("🧹 [Cache] 清除所有用户缓存");
}
// ==================== Redis 直接操作 ====================
/**
* Redis String 操作
*/
public void setString(String key, String value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
log.info("📝 [Redis] SET {} = {} (TTL: {} {})", key, value, timeout, unit);
}
public String getString(String key) {
String value = redisTemplate.opsForValue().get(key);
log.info("📝 [Redis] GET {} = {}", key, value);
return value;
}
/**
* Redis Hash 操作
*/
public void setHash(String key, String field, String value) {
redisTemplate.opsForHash().put(key, field, value);
log.info("📝 [Redis] HSET {} {} = {}", key, field, value);
}
public String getHash(String key, String field) {
Object value = redisTemplate.opsForHash().get(key, field);
log.info("📝 [Redis] HGET {} {} = {}", key, field, value);
return value != null ? value.toString() : null;
}
/**
* Redis List 操作
*/
public void pushToList(String key, String value) {
redisTemplate.opsForList().rightPush(key, value);
log.info("📝 [Redis] RPUSH {} {}", key, value);
}
/**
* Redis Set 操作
*/
public void addToSet(String key, String value) {
redisTemplate.opsForSet().add(key, value);
log.info("📝 [Redis] SADD {} {}", key, value);
}
/**
* Redis 分布式锁
*/
public boolean tryLock(String key, String value, long timeout, TimeUnit unit) {
Boolean success = redisTemplate.opsForValue()
.setIfAbsent(key, value, timeout, unit);
log.info("🔒 [Redis] TRY_LOCK {} = {}", key, success);
return Boolean.TRUE.equals(success);
}
public void unlock(String key) {
redisTemplate.delete(key);
log.info("🔓 [Redis] UNLOCK {}", key);
}
}

View File

@@ -0,0 +1,206 @@
package com.example.scaffold.learning;
import com.example.scaffold.cache.CacheService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 高级功能学习控制器
*
* 学习内容:
* 1. Redis 数据类型操作
* 2. 缓存策略
* 3. 分布式锁
* 4. 认证方案对比
*/
@Slf4j
@RestController
@RequestMapping("/api/learning/advanced")
@RequiredArgsConstructor
public class AdvancedLearningController {
private final StringRedisTemplate redisTemplate;
private final CacheService cacheService;
@Value("${auth.type:none}")
private String authType;
@Value("${cache.type:caffeine}")
private String cacheType;
@Value("${spring.datasource.driver-class-name}")
private String dbDriver;
/**
* 系统配置概览
*/
@GetMapping("/config")
public Map<String, Object> getConfig() {
String dbType = dbDriver.contains("h2") ? "H2" :
dbDriver.contains("mysql") ? "MySQL" :
dbDriver.contains("postgresql") ? "PostgreSQL" : "Unknown";
return Map.of(
"认证方案", Map.of(
"当前", authType,
"可选", "none | jwt | satoken",
"说明", Map.of(
"none", "无认证,开发测试用",
"jwt", "Spring Security + JWT标准方案",
"satoken", "Sa-Token轻量级方案"
)
),
"缓存方案", Map.of(
"当前", cacheType,
"可选", "caffeine | redis",
"说明", Map.of(
"caffeine", "本地缓存,单机高性能",
"redis", "分布式缓存,支持集群"
)
),
"数据库", Map.of(
"当前", dbType,
"可选", "H2 | MySQL | PostgreSQL",
"驱动", dbDriver
)
);
}
/**
* Redis 数据类型演示
*/
@GetMapping("/redis/types")
public Map<String, Object> redisTypes() {
return Map.of(
"String", "字符串,最基本的数据类型",
"Hash", "哈希,适合存储对象",
"List", "列表,支持队列/栈操作",
"Set", "集合,去重、交并差运算",
"SortedSet", "有序集合,支持排名",
"Bitmap", "位图,海量布尔值存储",
"HyperLogLog", "基数统计UV统计",
"Geo", "地理位置,附近的人",
"Stream", "流,消息队列"
);
}
/**
* Redis String 操作演示
*/
@PostMapping("/redis/string")
public Map<String, Object> redisString(@RequestParam String key,
@RequestParam String value,
@RequestParam(defaultValue = "60") long ttl) {
cacheService.setString(key, value, ttl, TimeUnit.SECONDS);
return Map.of(
"操作", "SET",
"key", key,
"value", value,
"ttl", ttl + ""
);
}
@GetMapping("/redis/string")
public Map<String, Object> getRedisString(@RequestParam String key) {
String value = cacheService.getString(key);
return Map.of(
"操作", "GET",
"key", key,
"value", value,
"存在", value != null
);
}
/**
* 缓存穿透/击穿/雪崩解决方案
*/
@GetMapping("/cache/problems")
public Map<String, Object> cacheProblems() {
return Map.of(
"缓存穿透", Map.of(
"问题", "查询不存在的数据,每次都打到数据库",
"解决", "布隆过滤器 | 缓存空值",
"代码", "@Cacheable(unless=\"#result == null\")"
),
"缓存击穿", Map.of(
"问题", "热点key过期大量请求打到数据库",
"解决", "互斥锁 | 逻辑过期",
"代码", "synchronized 或 Redis 分布式锁"
),
"缓存雪崩", Map.of(
"问题", "大量key同时过期数据库压力激增",
"解决", "随机过期时间 | 多级缓存",
"代码", "expire + random(60)"
)
);
}
/**
* 分布式锁演示
*/
@PostMapping("/redis/lock")
public Map<String, Object> distributedLock(@RequestParam String resource,
@RequestParam(defaultValue = "10") long ttl) {
String lockKey = "lock:" + resource;
String lockValue = Thread.currentThread().getName();
boolean locked = cacheService.tryLock(lockKey, lockValue, ttl, TimeUnit.SECONDS);
if (locked) {
try {
// 模拟业务操作
Thread.sleep(1000);
return Map.of(
"success", true,
"message", "获取锁成功,执行业务操作",
"resource", resource,
"lockKey", lockKey
);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return Map.of("success", false, "error", "业务中断");
} finally {
cacheService.unlock(lockKey);
}
} else {
return Map.of(
"success", false,
"message", "获取锁失败,资源被占用",
"resource", resource
);
}
}
/**
* JWT vs Sa-Token 对比
*/
@GetMapping("/auth/compare")
public Map<String, Object> authCompare() {
return Map.of(
"Spring Security + JWT", Map.of(
"优点", "标准方案、生态完善、社区活跃",
"缺点", "配置复杂、学习曲线陡、代码量大",
"适用", "大型项目、企业级应用",
"复杂度", "⭐⭐⭐⭐⭐"
),
"Sa-Token", Map.of(
"优点", "轻量级、API简洁、功能丰富、文档友好",
"缺点", "相对较新、生态不如Spring Security",
"适用", "中小型项目、快速开发",
"复杂度", "⭐⭐"
),
"选择建议", Map.of(
"快速开发", "Sa-Token",
"企业级", "Spring Security",
"学习成本", "Sa-Token 更低",
"扩展性", "Spring Security 更强"
)
);
}
}

View File

@@ -0,0 +1,97 @@
package com.example.scaffold.security.jwt;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* JWT 认证过滤器
*
* 学习要点:
* 1. OncePerRequestFilter - 确保每个请求只过滤一次
* 2. SecurityContextHolder - Spring Security 上下文
* 3. 认证流程:提取 Token → 验证 → 设置上下文
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
// 1. 从请求中提取 JWT Token
String jwt = getJwtFromRequest(request);
// 2. 验证 Token
if (StringUtils.hasText(jwt) && jwtUtil.validateToken(jwt)) {
// 3. 从 Token 中获取用户信息
String username = jwtUtil.getUsernameFromToken(jwt);
Long userId = jwtUtil.getUserIdFromToken(jwt);
// 4. 获取角色这里简化处理实际应从数据库或Token中解析
List<SimpleGrantedAuthority> authorities = Arrays.asList(
new SimpleGrantedAuthority("ROLE_USER")
);
// 5. 创建认证对象
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
new JwtUserDetails(userId, username),
null,
authorities
);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// 6. 设置 Security 上下文
SecurityContextHolder.getContext().setAuthentication(authentication);
log.debug("JWT 认证成功: userId={}, username={}", userId, username);
}
} catch (Exception e) {
log.error("JWT 认证失败: {}", e.getMessage());
SecurityContextHolder.clearContext();
}
// 继续过滤器链
filterChain.doFilter(request, response);
}
/**
* 从请求头中提取 JWT Token
*
* 支持格式:
* Authorization: Bearer <token>
*/
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
/**
* JWT 用户信息
*/
public record JwtUserDetails(Long userId, String username) {}
}

View File

@@ -0,0 +1,103 @@
package com.example.scaffold.security.jwt;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* JWT Security 配置
*
* 学习要点:
* 1. @ConditionalOnProperty - 条件化配置
* 2. SecurityFilterChain - 安全过滤器链
* 3. 无状态会话Stateless Session
*/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@ConditionalOnProperty(name = "auth.type", havingValue = "jwt")
public class JwtSecurityConfig {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 禁用 CSRFJWT 不需要)
.csrf(AbstractHttpConfigurer::disable)
// 配置无状态会话
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
// 配置请求授权
.authorizeHttpRequests(auth -> auth
// 公开端点
.requestMatchers("/", "/index.html", "/ioc.html", "/aop.html",
"/mybatis.html", "/transaction.html",
"/css/**", "/js/**", "/favicon.ico").permitAll()
.requestMatchers("/api/auth/**", "/h2-console/**").permitAll()
.requestMatchers("/api/learning/**").permitAll()
// 其他需要认证
.anyRequest().authenticated()
)
// 添加 JWT 过滤器
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
// H2 Console 配置
.headers(headers -> headers.frameOptions(frame -> frame.sameOrigin()));
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 内存用户(演示用,实际应从数据库加载)
*/
@Bean
public UserDetailsService userDetailsService() {
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin123"))
.roles("ADMIN", "USER")
.build();
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("user123"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(admin, user);
}
@Bean
public AuthenticationManager authenticationManager() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService());
provider.setPasswordEncoder(passwordEncoder());
return new ProviderManager(provider);
}
}

View File

@@ -0,0 +1,140 @@
package com.example.scaffold.security.jwt;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* JWT 工具类
*
* 学习要点:
* 1. JWT 结构Header.Payload.Signature
* 2. 签名算法HS256、HS512
* 3. Token 过期机制
* 4. 刷新 Token 策略
*/
@Slf4j
@Component
public class JwtUtil {
@Value("${auth.jwt.secret:your-secret-key-here-must-be-at-least-256-bits}")
private String secret;
@Value("${auth.jwt.expiration:86400000}")
private Long expiration;
private SecretKey getSigningKey() {
return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
}
/**
* 生成 JWT Token
*
* @param userId 用户ID
* @param username 用户名
* @param roles 角色列表
* @return JWT Token
*/
public String generateToken(Long userId, String username, String... roles) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + expiration);
Map<String, Object> claims = new HashMap<>();
claims.put("userId", userId);
claims.put("username", username);
claims.put("roles", roles);
return Jwts.builder()
.claims(claims)
.subject(username)
.issuedAt(now)
.expiration(expiryDate)
.signWith(getSigningKey(), Jwts.SIG.HS256)
.compact();
}
/**
* 从 Token 中获取用户名
*/
public String getUsernameFromToken(String token) {
Claims claims = parseToken(token);
return claims != null ? claims.getSubject() : null;
}
/**
* 从 Token 中获取用户ID
*/
public Long getUserIdFromToken(String token) {
Claims claims = parseToken(token);
return claims != null ? claims.get("userId", Long.class) : null;
}
/**
* 验证 Token 是否有效
*/
public boolean validateToken(String token) {
try {
parseToken(token);
return true;
} catch (ExpiredJwtException e) {
log.warn("JWT Token 已过期: {}", e.getMessage());
} catch (UnsupportedJwtException e) {
log.warn("不支持的 JWT Token: {}", e.getMessage());
} catch (MalformedJwtException e) {
log.warn("无效的 JWT Token: {}", e.getMessage());
} catch (SecurityException e) {
log.warn("JWT 签名验证失败: {}", e.getMessage());
} catch (IllegalArgumentException e) {
log.warn("JWT Token 为空或非法: {}", e.getMessage());
}
return false;
}
/**
* 解析 Token
*/
private Claims parseToken(String token) {
return Jwts.parser()
.verifyWith(getSigningKey())
.build()
.parseSignedClaims(token)
.getPayload();
}
/**
* 检查 Token 是否即将过期(用于刷新)
*
* @param token JWT Token
* @param threshold 阈值(毫秒)
* @return 是否即将过期
*/
public boolean isTokenExpiredSoon(String token, long threshold) {
try {
Claims claims = parseToken(token);
Date expiration = claims.getExpiration();
return expiration.getTime() - System.currentTimeMillis() < threshold;
} catch (Exception e) {
return true;
}
}
/**
* 刷新 Token
*/
public String refreshToken(String token) {
Claims claims = parseToken(token);
Long userId = claims.get("userId", Long.class);
String username = claims.getSubject();
String roles = claims.get("roles", String.class);
return generateToken(userId, username, roles);
}
}

View File

@@ -0,0 +1,71 @@
package com.example.scaffold.security.satoken;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Sa-Token 配置
*
* 学习要点:
* 1. Sa-Token 相比 Spring Security 更轻量
* 2. 支持分布式 Session
* 3. 支持登录设备控制
* 4. 支持权限认证、角色认证
*/
@Slf4j
@Configuration
@ConditionalOnProperty(name = "auth.type", havingValue = "satoken")
public class SaTokenConfig implements WebMvcConfigurer {
/**
* 注册 Sa-Token 拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor(handle -> {
// 登录校验
StpUtil.checkLogin();
}))
.addPathPatterns("/api/**")
.excludePathPatterns(
"/api/auth/**",
"/api/learning/**",
"/api/users/count"
);
}
/**
* Sa-Token 全局过滤器
*/
@Bean
public SaServletFilter saServletFilter() {
return new SaServletFilter()
// 拦截路径
.addInclude("/**")
// 排除路径
.addExclude("/", "/index.html", "/ioc.html", "/aop.html",
"/mybatis.html", "/transaction.html", "/users.html", "/api.html",
"/css/**", "/js/**", "/favicon.ico",
"/h2-console/**")
// 认证函数
.setAuth(obj -> {
SaRouter.match("/api/**")
.notMatch("/api/auth/**", "/api/learning/**")
.check(r -> StpUtil.checkLogin());
})
// 异常处理
.setError(e -> {
log.error("Sa-Token 认证失败: {}", e.getMessage());
return "{\"code\": 401, \"message\": \"未登录\"}";
});
}
}

View File

@@ -242,6 +242,22 @@
<button class="btn btn-primary" onclick="testApi('GET', '/api/learning/transaction/propagation', null, 'learnResult4')">测试</button>
<div id="learnResult4" class="result"></div>
</div>
<div class="api-item get">
<span class="method get">GET</span>
<strong>反射 - 类信息</strong>
<div class="url">/api/learning/reflection/class-info</div>
<button class="btn btn-primary" onclick="testApi('GET', '/api/learning/reflection/class-info', null, 'learnResult5')">测试</button>
<div id="learnResult5" class="result"></div>
</div>
<div class="api-item get">
<span class="method get">GET</span>
<strong>高级 - 性能统计</strong>
<div class="url">/api/learning/advanced/performance</div>
<button class="btn btn-primary" onclick="testApi('GET', '/api/learning/advanced/performance', null, 'learnResult6')">测试</button>
<div id="learnResult6" class="result"></div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,46 @@
# 高级配置 - 可插拔组件
spring:
config:
activate:
on-profile: advanced
# 数据库选择: h2 / mysql / postgresql
datasource:
driver-class-name: ${DB_DRIVER:org.h2.Driver}
url: ${DB_URL:jdbc:h2:file:~/h2/springboot_scaffold}
username: ${DB_USER:sa}
password: ${DB_PASS:}
# Redis 缓存
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASS:}
database: ${REDIS_DB:0}
timeout: 3000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
# 鉴权方案选择: none / jwt / satoken
auth:
type: ${AUTH_TYPE:jwt} # none | jwt | satoken
jwt:
secret: ${JWT_SECRET:your-secret-key}
expiration: ${JWT_EXPIRATION:86400000} # 24小时
satoken:
timeout: ${SA_TIMEOUT:86400} # 24小时
activity-timeout: ${SA_ACTIVITY_TIMEOUT:1800} # 30分钟
# 缓存配置
cache:
type: ${CACHE_TYPE:caffeine} # caffeine | redis
redis:
time-to-live: 600000 # 10分钟
# MyBatis 多数据库适配
mybatis:
configuration:
database-id: ${DB_TYPE:h2} # h2 | mysql | postgresql

View File

@@ -0,0 +1,29 @@
# Learn profile: keep dependencies and runtime simple for first-round learning
spring:
config:
activate:
on-profile: learn
datasource:
url: jdbc:h2:mem:springboot_scaffold_learn;MODE=MYSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driver-class-name: org.h2.Driver
username: sa
password:
h2:
console:
enabled: true
app:
profile: learn
enabled-modules:
- ioc
- aop
- mybatis
- transaction
- users
auth:
type: none
learning-note: "learn 模式默认不开启鉴权,专注 Spring 核心学习"
cache:
type: caffeine

View File

@@ -1,7 +1,10 @@
spring.application.name=springboot-scaffold
server.port=8082
server.port=8083
server.forward-headers-strategy=framework
# H2 Database
spring.profiles.active=${APP_PROFILE:learn}
# H2 Database (default baseline; learn profile overrides to in-memory)
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:file:~/h2/springboot_scaffold
spring.datasource.driverClassName=org.h2.Driver

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,260 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>高级功能学习 - Spring Boot</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; }
.container { max-width: 1400px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 30px 20px; text-align: center; margin-bottom: 20px; border-radius: 10px; }
.header h1 { font-size: 2em; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; justify-content: center; }
.nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; }
.nav a:hover, .nav a.active { background: #f5576c; color: white; }
.card { background: white; border-radius: 10px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.08); }
.card h3 { color: #f5576c; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
.config-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; }
.config-item { background: #f8f9fa; padding: 15px; border-radius: 8px; border-left: 4px solid #f5576c; }
.config-item h4 { margin-bottom: 10px; }
.config-item .current { color: #28a745; font-weight: bold; }
.btn { padding: 10px 20px; background: #f5576c; color: white; border: none; border-radius: 5px; cursor: pointer; margin: 5px; }
.btn:hover { background: #e0465b; }
.btn-secondary { background: #6c757d; }
.result { background: #1e1e1e; color: #d4d4d4; padding: 15px; border-radius: 5px; margin-top: 10px; font-family: monospace; font-size: 0.9em; overflow-x: auto; max-height: 400px; overflow-y: auto; }
.compare-table { width: 100%; border-collapse: collapse; margin: 15px 0; }
.compare-table th, .compare-table td { padding: 12px; text-align: left; border-bottom: 1px solid #eee; }
.compare-table th { background: #f8f9fa; }
.compare-table tr:hover { background: #f8f9fa; }
.problem-box { background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin: 10px 0; border-radius: 5px; }
.problem-box h4 { color: #856404; margin-bottom: 8px; }
.redis-types { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; }
.redis-type { background: #e3f2fd; padding: 15px; border-radius: 8px; }
.redis-type h4 { color: #1976d2; margin-bottom: 5px; }
.tipbox { background:#fff7e6;border-left:4px solid #fa8c16;padding:15px;border-radius:8px;margin-bottom:20px; }
.tipbox h4 { color:#ad6800;margin-bottom:8px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🚀 高级功能学习</h1>
<p>Redis 缓存 | 分布式锁 | 多数据库 | 认证方案</p>
</div>
<div class="nav">
<a href="index.html">🏠 首页</a>
<a href="ioc.html">📦 IoC</a>
<a href="aop.html">🔪 AOP</a>
<a href="mybatis.html">💾 MyBatis</a>
<a href="transaction.html">🔄 事务</a>
<a href="users.html">👥 用户</a>
<a href="advanced.html" class="active">🚀 高级</a>
<a href="auth-lab.html">🔐 鉴权实验室</a>
<a href="api.html">🔌 API</a>
</div>
<div class="tipbox">
<h4>🧪 实验任务卡(高级模块)</h4>
<label style="display:block;margin-bottom:8px;"><input id="advancedTaskDone" type="checkbox" onchange="toggleAdvancedTaskDone(this)"> 本任务我已经完成</label>
<ul style="padding-left:20px;line-height:1.8;">
<li>目标:比较 learn/advanced profile 下可用能力差异</li>
<li>步骤1先查看“系统配置”和“认证方案对比”</li>
<li>步骤2执行 Redis SET/GET + 分布式锁接口</li>
<li>预期advanced 模式下功能更完整,返回字段更丰富</li>
<li>常见坑:本机无 Redis 导致接口失败(属于环境问题)</li>
</ul>
</div>
<div class="card">
<h3>⚙️ 系统配置</h3>
<button class="btn" onclick="loadConfig()">查看当前配置</button>
<div id="configResult" class="result"></div>
</div>
<div class="card">
<h3>🔐 认证方案对比</h3>
<button class="btn" onclick="loadAuthCompare()">JWT vs Sa-Token</button>
<a class="btn btn-secondary" href="auth-lab.html">进入鉴权实验室</a>
<div id="authResult" class="result"></div>
</div>
<div class="card">
<h3>💾 Redis 数据类型</h3>
<div class="redis-types">
<div class="redis-type"><h4>String</h4><p>字符串,最基本类型</p></div>
<div class="redis-type"><h4>Hash</h4><p>哈希,存储对象</p></div>
<div class="redis-type"><h4>List</h4><p>列表,队列/栈</p></div>
<div class="redis-type"><h4>Set</h4><p>集合,去重运算</p></div>
<div class="redis-type"><h4>SortedSet</h4><p>有序集合,排名</p></div>
</div>
<button class="btn" onclick="loadRedisTypes()">查看详细说明</button>
</div>
<div class="card">
<h3>🧪 Redis 操作测试</h3>
<div style="display:flex;gap:10px;margin-bottom:15px;">
<input type="text" id="redisKey" placeholder="Key" style="flex:1;padding:10px;border:1px solid #ddd;border-radius:5px;">
<input type="text" id="redisValue" placeholder="Value" style="flex:1;padding:10px;border:1px solid #ddd;border-radius:5px;">
<input type="number" id="redisTtl" placeholder="TTL(秒)" value="60" style="width:100px;padding:10px;border:1px solid #ddd;border-radius:5px;">
</div>
<button class="btn" onclick="setRedisString()">SET</button>
<button class="btn btn-secondary" onclick="getRedisString()">GET</button>
<div id="redisResult" class="result"></div>
</div>
<div class="card">
<h3>🔒 分布式锁演示</h3>
<p>模拟多个请求竞争同一资源</p>
<input type="text" id="lockResource" placeholder="资源名称" value="order:1001" style="padding:10px;border:1px solid #ddd;border-radius:5px;margin-right:10px;">
<button class="btn" onclick="testDistributedLock()">获取分布式锁</button>
<div id="lockResult" class="result"></div>
</div>
<div class="card">
<h3>⚠️ 缓存三大问题</h3>
<div class="problem-box">
<h4>缓存穿透</h4>
<p><strong>问题:</strong>查询不存在的数据,每次都打到数据库</p>
<p><strong>解决:</strong>布隆过滤器 | 缓存空值</p>
</div>
<div class="problem-box">
<h4>缓存击穿</h4>
<p><strong>问题:</strong>热点key过期大量请求打到数据库</p>
<p><strong>解决:</strong>互斥锁 | 逻辑过期</p>
</div>
<div class="problem-box">
<h4>缓存雪崩</h4>
<p><strong>问题:</strong>大量key同时过期数据库压力激增</p>
<p><strong>解决:</strong>随机过期时间 | 多级缓存</p>
</div>
<button class="btn" onclick="loadCacheProblems()">查看详细方案</button>
<div id="cacheResult" class="result"></div>
</div>
</div>
<script>
const ADV_TASK_KEY = 'task.advanced.done';
function toggleAdvancedTaskDone(el) {
localStorage.setItem(ADV_TASK_KEY, el.checked ? '1' : '0');
}
function initAdvancedTaskState() {
const done = localStorage.getItem(ADV_TASK_KEY) === '1';
const checkbox = document.getElementById('advancedTaskDone');
if (checkbox) checkbox.checked = done;
}
async function loadConfig() {
const result = document.getElementById('configResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/advanced/config');
const data = await res.json();
result.innerHTML = `<strong>系统配置</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadAuthCompare() {
const result = document.getElementById('authResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/advanced/auth/compare');
const data = await res.json();
result.innerHTML = `<strong>认证方案对比</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadRedisTypes() {
const result = document.getElementById('redisResult');
try {
const res = await fetch('/api/learning/advanced/redis/types');
const data = await res.json();
result.innerHTML = `<strong>Redis 数据类型</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function setRedisString() {
const key = document.getElementById('redisKey').value;
const value = document.getElementById('redisValue').value;
const ttl = document.getElementById('redisTtl').value;
if (!key || !value) {
alert('请输入 Key 和 Value');
return;
}
const result = document.getElementById('redisResult');
try {
const res = await fetch(`/api/learning/advanced/redis/string?key=${encodeURIComponent(key)}&value=${encodeURIComponent(value)}&ttl=${ttl}`, { method: 'POST' });
const data = await res.json();
result.innerHTML = `<strong>SET 结果</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '操作失败: ' + e.message;
}
}
async function getRedisString() {
const key = document.getElementById('redisKey').value;
if (!key) {
alert('请输入 Key');
return;
}
const result = document.getElementById('redisResult');
try {
const res = await fetch(`/api/learning/advanced/redis/string?key=${encodeURIComponent(key)}`);
const data = await res.json();
result.innerHTML = `<strong>GET 结果</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '操作失败: ' + e.message;
}
}
async function testDistributedLock() {
const resource = document.getElementById('lockResource').value;
const result = document.getElementById('lockResult');
result.textContent = '获取锁中...';
try {
const res = await fetch(`/api/learning/advanced/redis/lock?resource=${encodeURIComponent(resource)}`, { method: 'POST' });
const data = await res.json();
result.innerHTML = `<strong>分布式锁结果</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '操作失败: ' + e.message;
}
}
async function loadCacheProblems() {
const result = document.getElementById('cacheResult');
try {
const res = await fetch('/api/learning/advanced/cache/problems');
const data = await res.json();
result.innerHTML = `<strong>缓存问题解决方案</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
loadConfig();
initAdvancedTaskState();
</script>
</body>
</html>

View File

@@ -49,6 +49,8 @@
.tab-content.active { display: block; }
.json-input { width: 100%; min-height: 100px; padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-family: monospace; font-size: 0.9em; }
.profile-banner { background:#fff7e6;border-left:4px solid #fa8c16;padding:12px 14px;border-radius:8px;margin-bottom:18px; color:#874d00; }
.tools { margin: 10px 0 16px; }
</style>
</head>
<body>
@@ -68,6 +70,12 @@
<a href="api.html" class="active">🔌 API</a>
</div>
<div id="profileBanner" class="profile-banner">正在读取 profile...</div>
<div class="tools">
<button class="btn btn-primary" onclick="copyCurl()">复制当前示例 cURLGET /api/users</button>
<a class="btn btn-primary" href="verify-lab.html">进入修复验证实验室</a>
</div>
<div class="tabs">
<div class="tab active" onclick="switchTab('user')">👥 用户 API</div>
<div class="tab" onclick="switchTab('product')">📦 产品 API</div>
@@ -248,6 +256,27 @@
document.getElementById(tab + 'Tab').classList.add('active');
}
async function loadProfileBanner() {
try {
const res = await fetch('/api/profile');
const data = await res.json();
const enabled = (data.enabledModules || []).join(', ');
document.getElementById('profileBanner').textContent = `当前 profile: ${data.profile} | 鉴权模式: ${data.authType || 'none'} | 已启用模块: ${enabled}`;
} catch (e) {
document.getElementById('profileBanner').textContent = '当前 profile 读取失败,请检查 /api/profile';
}
}
async function copyCurl() {
const curl = `curl -X GET "${window.location.origin}/api/users"`;
try {
await navigator.clipboard.writeText(curl);
alert('已复制: ' + curl);
} catch (e) {
alert('复制失败,请手动复制: ' + curl);
}
}
async function testApi(method, url, body, resultId) {
const resultDiv = document.getElementById(resultId);
resultDiv.classList.add('show');
@@ -275,6 +304,8 @@
resultDiv.innerHTML = `<strong style="color:#ff6b6b;">Error</strong>\n\n${e.message}`;
}
}
loadProfileBanner();
</script>
</body>
</html>

View File

@@ -0,0 +1,142 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>鉴权实验室 - Spring Boot</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; background:#f5f5f5; }
.container { max-width: 1100px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg,#4facfe,#00f2fe); color:#fff; padding:28px 20px; border-radius:12px; margin-bottom:20px; text-align:center; }
.nav { display:flex; gap:10px; flex-wrap:wrap; justify-content:center; margin-bottom:20px; }
.nav a { padding:10px 18px; background:#fff; border-radius:20px; text-decoration:none; color:#333; }
.nav a.active { background:#4facfe; color:#fff; }
.card { background:#fff; border-radius:12px; padding:20px; margin-bottom:20px; box-shadow:0 2px 10px rgba(0,0,0,.08); }
.card h3 { color:#1890ff; margin-bottom:12px; }
.lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin-bottom:20px; }
.row { display:flex; gap:10px; flex-wrap:wrap; margin:10px 0; }
input, select { padding:10px; border:1px solid #ddd; border-radius:6px; min-width:200px; }
button { padding:10px 16px; background:#1890ff; color:#fff; border:none; border-radius:6px; cursor:pointer; }
button.secondary { background:#6c757d; }
.result { background:#111827; color:#d1d5db; padding:14px; border-radius:8px; min-height:120px; white-space:pre-wrap; font-family:monospace; }
.hint { color:#666; margin-top:8px; line-height:1.7; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔐 Spring 鉴权实验室</h1>
<p>登录 → 取 Token → 访问受保护接口 → 对比 learn/advanced 模式</p>
</div>
<div class="nav">
<a href="index.html">🏠 首页</a>
<a href="advanced.html">🚀 高级功能</a>
<a href="verify-lab.html">🩺 修复验证实验室</a>
<a href="api.html">🔌 API 测试</a>
<a href="auth-lab.html" class="active">🔐 鉴权实验室</a>
</div>
<div class="lab">
<strong>实验任务卡</strong>
<ul style="padding-left:20px; line-height:1.8; margin-top:8px;">
<li>步骤1点击“读取当前模式”确认现在是 learn / advanced</li>
<li>步骤2用 admin/admin123 登录,拿到 token</li>
<li>步骤3带上 token 调用当前实验接口,观察是否放行或返回 503/401</li>
<li>步骤4切换 auth.type 后对比 none/jwt/satoken 行为差异</li>
</ul>
</div>
<div class="card">
<h3>当前模式</h3>
<div class="row">
<button onclick="loadProfile()">读取当前模式</button>
</div>
<div id="profileResult" class="result">点击按钮读取...</div>
</div>
<div class="card">
<h3>登录拿 Token</h3>
<div class="row">
<input id="username" value="admin" placeholder="用户名">
<input id="password" value="admin123" placeholder="密码" type="password">
<button onclick="login()">登录</button>
</div>
<div class="hint">演示账号admin/admin123 或 user/user123</div>
<div id="loginResult" class="result">点击登录后显示响应...</div>
</div>
<div class="card">
<h3>接口访问实验</h3>
<div class="row">
<button onclick="callSecureApi()">访问 /api/auth/info</button>
<button class="secondary" onclick="clearToken()">清空本地 Token</button>
</div>
<div class="hint">当前页面会优先从 localStorage 读取 token 并自动加到 Authorization 头里。learn 模式下接口通常直接放行advanced+jwt 下更适合观察真实鉴权链路。</div>
<div id="secureResult" class="result">点击按钮后显示接口结果...</div>
</div>
</div>
<script>
let cachedToken = localStorage.getItem('spring.scaffold.token') || '';
async function loadProfile() {
const el = document.getElementById('profileResult');
el.textContent = '读取中...';
try {
const res = await fetch('/api/profile');
const data = await res.json();
el.textContent = JSON.stringify(data, null, 2);
} catch (e) {
el.textContent = '读取失败: ' + e.message;
}
}
async function login() {
const el = document.getElementById('loginResult');
el.textContent = '登录中...';
try {
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: document.getElementById('username').value,
password: document.getElementById('password').value,
})
});
const data = await res.json();
const token = data.token || data.data?.token || '';
if (token) {
cachedToken = token;
localStorage.setItem('spring.scaffold.token', token);
}
el.textContent = JSON.stringify(data, null, 2);
} catch (e) {
el.textContent = '登录失败: ' + e.message;
}
}
async function callSecureApi() {
const el = document.getElementById('secureResult');
el.textContent = '请求中...';
try {
const headers = {};
if (cachedToken) headers['Authorization'] = 'Bearer ' + cachedToken;
const res = await fetch('/api/auth/info', { headers });
const text = await res.text();
el.textContent = `HTTP ${res.status}\n\n${text}`;
} catch (e) {
el.textContent = '请求失败: ' + e.message;
}
}
function clearToken() {
cachedToken = '';
localStorage.removeItem('spring.scaffold.token');
document.getElementById('secureResult').textContent = '本地 token 已清空';
}
loadProfile();
</script>
</body>
</html>

View File

@@ -41,6 +41,9 @@
.status-item { background: white; padding: 20px 30px; border-radius: 10px; text-align: center; }
.status-item .value { font-size: 2em; font-weight: bold; color: #667eea; }
.status-item .label { color: #666; margin-top: 5px; }
.lab { background:#fff7e6; border:1px solid #ffe58f; border-radius:10px; padding:16px; margin-bottom:20px; }
.lab h4 { margin-bottom:8px; color:#ad6800; }
.lab ul { margin-left:18px; color:#444; line-height:1.7; }
footer { text-align: center; padding: 30px; color: #666; margin-top: 40px; }
</style>
@@ -69,6 +72,22 @@
<div class="value" id="orderCount">-</div>
<div class="label">订单数量</div>
</div>
<div class="status-item">
<div class="value" id="activeProfile">-</div>
<div class="label">当前 Profile</div>
</div>
</div>
<div class="lab">
<h4>🧪 实验任务卡(事务模块)</h4>
<p style="margin-bottom:8px;color:#8c8c8c;">鉴权学习建议learn=none先学核心advanced=jwt/satoken再学安全链路</p>
<ul>
<li>目标:理解事务回滚与 REQUIRES_NEW 差异</li>
<li>步骤1到 transaction.html 创建普通订单rollback=false</li>
<li>步骤2再创建模拟失败订单rollback=true</li>
<li>预期:主事务回滚,但独立事务可保留日志/部分数据(取决于实现)</li>
<li>观察点查看控制台事务日志TransactionInterceptor TRACE</li>
</ul>
</div>
<div class="nav">
@@ -78,6 +97,10 @@
<a href="mybatis.html">💾 MyBatis</a>
<a href="transaction.html">🔄 事务管理</a>
<a href="users.html">👥 用户管理</a>
<a href="advanced.html">🚀 高级功能</a>
<a href="reflection.html">🪞 反射实验室</a>
<a href="auth-lab.html">🔐 鉴权实验室</a>
<a href="verify-lab.html">🩺 修复验证实验室</a>
<a href="api.html">🔌 API 测试</a>
</div>
@@ -142,6 +165,55 @@
<a href="users.html" class="btn">开始学习 →</a>
</div>
<div class="card">
<h3>🚀 高级功能</h3>
<p>Redis 缓存、分布式锁、多数据库、认证方案对比,从小白到高手的进阶之路。</p>
<ul class="feature-list">
<li><span class="icon"></span>Redis 数据类型操作</li>
<li><span class="icon"></span>缓存穿透/击穿/雪崩</li>
<li><span class="icon"></span>分布式锁实现</li>
<li><span class="icon"></span>JWT vs Sa-Token</li>
<li><span class="icon"></span>多数据库切换</li>
</ul>
<a href="advanced.html" class="btn">进阶学习 →</a>
</div>
<div class="card">
<h3>🪞 反射实验室</h3>
<p>动态查看类结构、通过构造器创建对象、修改私有字段、调用私有方法,理解 Spring 等框架底层为什么依赖反射。</p>
<ul class="feature-list">
<li><span class="icon"></span>类/字段/方法元信息</li>
<li><span class="icon"></span>反射构造对象</li>
<li><span class="icon"></span>私有字段修改</li>
<li><span class="icon"></span>公开/私有/静态方法调用</li>
</ul>
<a href="reflection.html" class="btn">开始实验 →</a>
</div>
<div class="card">
<h3>🔐 鉴权实验室</h3>
<p>一步步体验登录、带 Token 请求、鉴权放行/拦截,对比 learn / advanced 模式差异。</p>
<ul class="feature-list">
<li><span class="icon"></span>登录拿 Token</li>
<li><span class="icon"></span>自动携带 Authorization</li>
<li><span class="icon"></span>当前模式读取</li>
<li><span class="icon"></span>交互式错误观察</li>
</ul>
<a href="auth-lab.html" class="btn">开始实验 →</a>
</div>
<div class="card">
<h3>🩺 修复验证实验室</h3>
<p>自己点检查,不靠口头确认。直接验证 profile、H2、用户服务、MyBatis 和鉴权模式。</p>
<ul class="feature-list">
<li><span class="icon"></span>一键总览检查</li>
<li><span class="icon"></span>数据库链路验证</li>
<li><span class="icon"></span>用户服务验证</li>
<li><span class="icon"></span>MyBatis 查询验证</li>
</ul>
<a href="verify-lab.html" class="btn">开始验证 →</a>
</div>
<div class="card">
<h3>🔌 API 测试面板</h3>
<p>在线测试所有 API 接口,查看请求响应,理解 RESTful API 工作原理。</p>
@@ -172,7 +244,7 @@
</div>
<footer>
<p>🍃 Spring Boot 学习脚手架 | <a href="/h2-console" target="_blank">H2 控制台</a> (JDBC: jdbc:h2:file:~/h2/springboot_scaffold, 用户: sa)</p>
<p>🍃 Spring Boot 学习脚手架 | <a href="/h2-console" target="_blank">H2 控制台</a> (learn 模式 JDBC: jdbc:h2:mem:springboot_scaffold_learn, 用户: sa)</p>
</footer>
</div>
@@ -180,17 +252,19 @@
// 加载状态数据
async function loadStatus() {
try {
const [beans, users, products, orders] = await Promise.all([
const [beans, users, products, orders, profile] = await Promise.all([
fetch('/api/learning/ioc/beans').then(r => r.json()),
fetch('/api/users/count').then(r => r.json()),
fetch('/api/products').then(r => r.json()),
fetch('/api/orders').then(r => r.json())
fetch('/api/orders').then(r => r.json()),
fetch('/api/profile').then(r => r.json())
]);
document.getElementById('beanCount').textContent = beans.total || '-';
document.getElementById('userCount').textContent = users.count || 0;
document.getElementById('productCount').textContent = products.length || 0;
document.getElementById('orderCount').textContent = orders.length || 0;
document.getElementById('activeProfile').textContent = profile.profile || '-';
} catch (e) {
console.error('加载状态失败:', e);
}

View File

@@ -3,173 +3,200 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IoC 容器学习 - Spring Boot</title>
<title>IoC 生命周期可视化实验室 - Spring Boot</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; }
.container { max-width: 1400px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px 20px; text-align: center; margin-bottom: 20px; border-radius: 10px; }
.header h1 { font-size: 2em; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; justify-content: center; }
.nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; }
.nav a:hover, .nav a.active { background: #667eea; color: white; }
.card { background: white; border-radius: 10px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.08); }
.card h3 { color: #667eea; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
.grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); gap:16px; }
.concept-box { background: #f8f9fa; border-left: 4px solid #667eea; padding: 15px; margin: 10px 0; border-radius: 5px; }
.concept-box h4 { color: #333; margin-bottom: 10px; }
.lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin-bottom:20px; }
.btn { padding: 10px 20px; background: #667eea; color: white; border: none; border-radius: 5px; cursor: pointer; margin: 5px; }
.btn:hover { background: #5a6fd6; }
.btn-secondary { background: #6c757d; }
.result { background: #1e1e1e; color: #d4d4d4; padding: 15px; border-radius: 5px; margin-top: 10px; font-family: monospace; font-size: 0.9em; overflow-x: auto; max-height: 400px; overflow-y: auto; }
.btn-purple { background:#8e44ad; }
.result { background: #1e1e1e; color: #d4d4d4; padding: 15px; border-radius: 5px; margin-top: 10px; font-family: monospace; font-size: 0.9em; overflow-x: auto; max-height: 420px; overflow-y: auto; white-space: pre-wrap; }
table { width: 100%; border-collapse: collapse; margin: 10px 0; }
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #eee; }
th { background: #f8f9fa; font-weight: 600; }
tr:hover { background: #f8f9fa; }
.badge { padding: 4px 8px; border-radius: 4px; font-size: 0.8em; }
.badge-primary { background: #667eea; color: white; }
.badge-success { background: #28a745; color: white; }
.badge-warning { background: #ffc107; color: #333; }
.timeline { background:#0f172a; color:#e2e8f0; padding:14px; border-radius:8px; max-height:420px; overflow:auto; }
.timeline-item { padding:10px; border-left:3px solid #60a5fa; margin:10px 0; background:rgba(255,255,255,0.04); }
.small { color:#666; font-size:0.9em; line-height:1.7; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>📦 IoC 容器学习</h1>
<p>控制反转 (Inversion of Control) 与依赖注入 (Dependency Injection)</p>
<h1>📦 IoC 生命周期可视化实验室</h1>
<p>把“类加载”“Bean 创建”“单例/多例/懒加载”拆开看,自己动手触发、自己观察结果。</p>
</div>
<div class="nav">
<a href="index.html">🏠 首页</a>
<a href="ioc.html" class="active">📦 IoC</a>
<a href="verify-lab.html">🩺 修复验证</a>
<a href="aop.html">🔪 AOP</a>
<a href="mybatis.html">💾 MyBatis</a>
<a href="transaction.html">🔄 事务</a>
<a href="users.html">👥 用户</a>
<a href="api.html">🔌 API</a>
</div>
<div class="card">
<h3>📚 核心概念</h3>
<div class="concept-box">
<h4>什么是 IoC</h4>
<p><strong>控制反转 (Inversion of Control)</strong>:将对象的创建和管理交给 Spring 容器,而不是由开发者手动创建。</p>
<p><strong>依赖注入 (Dependency Injection)</strong>IoC 的一种实现方式通过构造器、Setter 或字段将依赖注入到对象中。</p>
<div class="lab">
<strong>🧪 实验任务卡</strong>
<ul style="padding-left:20px; line-height:1.8; margin-top:8px;">
<li>先点“加载总览”,搞清楚 JVM 类加载 和 Spring Bean 生命周期不是一回事</li>
<li>再点“比较三种作用域”,对比 singleton / prototype / lazy singleton 的实例 ID 和 hashCode</li>
<li>然后分别连续点击“获取单例 / 获取多例 / 获取懒加载单例”,观察时间线变化</li>
<li>最后重置时间线,再重新做一遍,看看第一次触发和第二次触发的区别</li>
</ul>
</div>
<div class="grid">
<div class="card">
<h3>📚 核心概念总览</h3>
<button class="btn" onclick="loadOverview()">加载总览</button>
<div id="overviewResult" class="result">点击按钮查看“类加载 vs Bean 生命周期”...</div>
</div>
<div class="concept-box">
<h4>为什么用 IoC</h4>
<ul>
<li><strong>解耦</strong>:对象之间不直接依赖,通过接口交互</li>
<li><strong>可测试</strong>:方便使用 Mock 对象进行单元测试</li>
<li><strong>可维护</strong>:集中管理对象生命周期</li>
<li><strong>AOP 支持</strong>:便于实现切面编程</li>
</ul>
<div class="card">
<h3>🆚 作用域对比实验</h3>
<button class="btn" onclick="compareScopes()">比较三种作用域</button>
<button class="btn btn-secondary" onclick="resetTimeline()">重置时间线</button>
<div class="small">观察重点singleton 两次获取是否同一实例prototype 为什么每次都变lazy singleton 第一次获取前是否就已经创建?</div>
<div id="compareResult" class="result"></div>
</div>
</div>
<div class="card">
<h3>🎯 单点触发实验</h3>
<button class="btn" onclick="inspect('singleton')">获取单例 Bean</button>
<button class="btn btn-purple" onclick="inspect('prototype')">获取多例 Bean</button>
<button class="btn btn-secondary" onclick="inspect('lazy')">获取懒加载单例</button>
<div id="inspectResult" class="result">点击上面的按钮,观察实例 ID / hashCode / 访问次数如何变化...</div>
</div>
<div class="grid">
<div class="card">
<h3>🕰️ 生命周期时间线</h3>
<button class="btn" onclick="loadTimeline()">刷新时间线</button>
<div id="timelineResult" class="timeline">时间线加载中...</div>
</div>
<div class="card">
<h3>📊 Bean 作用域解释</h3>
<table>
<tr><th>作用域</th><th>创建时机</th><th>实例特点</th></tr>
<tr><td><span class="badge badge-primary">singleton</span></td><td>通常容器启动时</td><td>全局一个实例,反复获取同一个对象</td></tr>
<tr><td><span class="badge badge-success">prototype</span></td><td>每次 getBean 时</td><td>每次都是新实例,不进单例池</td></tr>
<tr><td><span class="badge badge-warning">lazy singleton</span></td><td>第一次真正使用时</td><td>启动不创建,首次获取才创建,之后复用</td></tr>
</table>
<div class="concept-box">
<h4>记住这句话</h4>
<p><strong>类加载 ≠ Bean 创建Bean 创建 ≠ 每次请求都 new。</strong></p>
</div>
</div>
</div>
<div class="card">
<h3>🔍 查看所有 Bean</h3>
<p>Spring 容器中管理的所有 Bean 对象</p>
<button class="btn" onclick="loadBeans()">刷新 Bean 列表</button>
<button class="btn btn-secondary" onclick="document.getElementById('beansResult').innerHTML=''">清空</button>
<div id="beansResult" class="result"></div>
</div>
<div class="card">
<h3>📊 Bean 作用域</h3>
<table>
<tr><th>作用域</th><th>说明</th><th>使用场景</th></tr>
<tr><td><span class="badge badge-primary">singleton</span></td><td>默认,整个应用只有一个实例</td><td>无状态的服务、配置类</td></tr>
<tr><td><span class="badge badge-success">prototype</span></td><td>每次请求都创建新实例</td><td>有状态的对象</td></tr>
<tr><td><span class="badge badge-warning">request</span></td><td>每个 HTTP 请求一个实例</td><td>Web 应用</td></tr>
<tr><td><span class="badge badge-warning">session</span></td><td>每个 HTTP 会话一个实例</td><td>用户会话数据</td></tr>
</table>
<button class="btn" onclick="testScopes()">测试作用域</button>
<div id="scopesResult" class="result"></div>
</div>
<div class="card">
<h3>⚡ 性能统计</h3>
<p>实时监控方法执行时间和调用次数</p>
<button class="btn" onclick="loadPerformance()">刷新统计</button>
<button class="btn btn-secondary" onclick="resetPerformance()">重置统计</button>
<div id="performanceResult" class="result"></div>
</div>
<div class="card">
<h3>💉 依赖注入方式对比</h3>
<table>
<tr><th>方式</th><th>优点</th><th>缺点</th><th>推荐度</th></tr>
<tr><td>构造器注入</td><td>明确依赖、不可变、易测试</td><td>参数多时代码长</td><td>⭐⭐⭐⭐⭐</td></tr>
<tr><td>Setter 注入</td><td>可选依赖、灵活</td><td>可能为 null</td><td>⭐⭐⭐</td></tr>
<tr><td>字段注入</td><td>代码简洁</td><td>隐藏依赖、难测试</td><td></td></tr>
</table>
</div>
</div>
<script>
async function loadOverview() {
const result = document.getElementById('overviewResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/ioc/lifecycle/overview');
const data = await res.json();
result.textContent = JSON.stringify(data, null, 2);
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function inspect(scope) {
const result = document.getElementById('inspectResult');
result.textContent = '触发中...';
try {
const res = await fetch(`/api/learning/ioc/lifecycle/inspect/${scope}?trigger=ui-click`);
const data = await res.json();
result.textContent = JSON.stringify(data, null, 2);
loadTimeline();
} catch (e) {
result.textContent = '触发失败: ' + e.message;
}
}
async function compareScopes() {
const result = document.getElementById('compareResult');
result.textContent = '对比中...';
try {
const res = await fetch('/api/learning/ioc/lifecycle/compare');
const data = await res.json();
result.textContent = JSON.stringify(data, null, 2);
loadTimeline();
} catch (e) {
result.textContent = '对比失败: ' + e.message;
}
}
async function loadTimeline() {
const result = document.getElementById('timelineResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/ioc/lifecycle/timeline');
const data = await res.json();
if (!data.length) {
result.textContent = '暂无时间线事件,先点上面的实验按钮。';
return;
}
result.innerHTML = data.map(item => `
<div class="timeline-item">
<div><strong>#${item.seq}</strong> [${item.scope}] ${item.beanName}</div>
<div>${item.phase}</div>
<div style="color:#94a3b8; margin-top:6px;">${item.detail}</div>
</div>
`).join('');
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function resetTimeline() {
await fetch('/api/learning/ioc/lifecycle/reset', { method: 'POST' });
loadTimeline();
}
async function loadBeans() {
const result = document.getElementById('beansResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/ioc/beans');
const data = await res.json();
result.innerHTML = `<strong>总 Bean 数: ${data.total}</strong>\n\n用户相关 Bean:\n${data.userBeans.map(b => ' - ' + b).join('\n')}`;
result.innerHTML = `<strong>总 Bean 数: ${data.total}</strong>\n\nIoC 学习相关 Bean:\n${data.userBeans.map(b => ' - ' + b).join('\n')}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function testScopes() {
const result = document.getElementById('scopesResult');
try {
const res = await fetch('/api/learning/ioc/scopes');
const data = await res.json();
result.innerHTML = JSON.stringify(data, null, 2);
} catch (e) {
result.textContent = '测试失败: ' + e.message;
}
}
async function loadPerformance() {
const result = document.getElementById('performanceResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/ioc/performance');
const data = await res.json();
if (Object.keys(data).length === 0) {
result.textContent = '暂无性能数据,请先调用一些 API';
return;
}
let html = '<table><tr><th>方法</th><th>调用次数</th><th>错误数</th><th>平均耗时(ms)</th><th>最大耗时(ms)</th></tr>';
for (const [key, val] of Object.entries(data)) {
html += `<tr><td>${key}</td><td>${val.count}</td><td>${val.errors}</td><td>${val.avgMs}</td><td>${val.maxMs}</td></tr>`;
}
html += '</table>';
result.innerHTML = html;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function resetPerformance() {
try {
await fetch('/api/learning/ioc/performance/reset', { method: 'POST' });
loadPerformance();
} catch (e) {
alert('重置失败: ' + e.message);
}
}
loadBeans();
loadPerformance();
loadOverview();
loadTimeline();
</script>
</body>
</html>
</html>

View File

@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>反射可视化实验室 - Spring Boot</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; background:#f5f5f5; }
.container { max-width:1200px; margin:0 auto; padding:20px; }
.header { background:linear-gradient(135deg,#0f766e,#14b8a6); color:#fff; padding:28px 20px; border-radius:12px; text-align:center; margin-bottom:20px; }
.nav { display:flex; gap:10px; flex-wrap:wrap; justify-content:center; margin-bottom:20px; }
.nav a { padding:10px 18px; background:#fff; border-radius:20px; text-decoration:none; color:#333; }
.nav a.active { background:#0f766e; color:#fff; }
.lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin-bottom:20px; }
.grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); gap:16px; }
.card { background:#fff; border-radius:12px; padding:18px; box-shadow:0 2px 10px rgba(0,0,0,.08); }
.card h3 { color:#0f766e; margin-bottom:10px; }
.result { background:#111827; color:#d1d5db; padding:12px; border-radius:8px; min-height:180px; white-space:pre-wrap; font-family:monospace; margin-top:10px; overflow:auto; }
button { padding:10px 14px; background:#0f766e; color:#fff; border:none; border-radius:6px; cursor:pointer; margin-right:8px; margin-bottom:8px; }
input { padding:10px; border:1px solid #ddd; border-radius:6px; margin-right:8px; margin-bottom:8px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🪞 反射可视化实验室</h1>
<p>不只说“反射很重要”,而是让你自己查看类信息、动态构造对象、读写字段、调用私有方法。</p>
</div>
<div class="nav">
<a href="index.html">🏠 首页</a>
<a href="ioc.html">📦 IoC</a>
<a href="reflection.html" class="active">🪞 反射</a>
<a href="verify-lab.html">🩺 修复验证</a>
</div>
<div class="lab">
<strong>实验任务卡</strong>
<ul style="padding-left:20px; line-height:1.8; margin-top:8px;">
<li>先看类信息,理解反射能拿到哪些元数据</li>
<li>再用构造器动态创建对象,观察实例内容</li>
<li>再读写私有字段,理解为什么框架可以“跳过表面上的访问限制”</li>
<li>最后调用私有方法和静态方法,感受反射为什么是框架底层利器</li>
</ul>
</div>
<div class="grid">
<div class="card">
<h3>概念总览</h3>
<button onclick="callApi('/api/learning/reflection/overview','overview')">加载总览</button>
<div id="overview" class="result"></div>
</div>
<div class="card">
<h3>类元信息</h3>
<button onclick="callApi('/api/learning/reflection/class-info','classInfo')">查看类信息</button>
<div id="classInfo" class="result"></div>
</div>
</div>
<div class="grid">
<div class="card">
<h3>动态构造对象</h3>
<input id="ctorName" value="ref-user" placeholder="name">
<input id="ctorCount" value="5" placeholder="count">
<button onclick="instantiate()">反射创建对象</button>
<div id="ctorResult" class="result"></div>
</div>
<div class="card">
<h3>私有字段读写</h3>
<input id="fieldValue" value="changed-by-reflection" placeholder="new field value">
<button onclick="fieldAccess()">修改私有字段</button>
<div id="fieldResult" class="result"></div>
</div>
</div>
<div class="grid">
<div class="card">
<h3>方法调用实验</h3>
<input id="prefix" value="你好" placeholder="prefix">
<button onclick="methodCall()">调用公开/私有/静态方法</button>
<div id="methodResult" class="result"></div>
</div>
<div class="card">
<h3>框架为什么依赖反射</h3>
<button onclick="callApi('/api/learning/reflection/why-frameworks-use-it','frameworkResult')">查看框架视角</button>
<div id="frameworkResult" class="result"></div>
</div>
</div>
</div>
<script>
async function callApi(url, id) {
const el = document.getElementById(id);
el.textContent = '加载中...';
try {
const res = await fetch(url);
const data = await res.json();
el.textContent = JSON.stringify(data, null, 2);
} catch (e) {
el.textContent = '失败: ' + e.message;
}
}
async function instantiate() {
const name = encodeURIComponent(document.getElementById('ctorName').value);
const count = encodeURIComponent(document.getElementById('ctorCount').value);
callApi(`/api/learning/reflection/instantiate?name=${name}&count=${count}`, 'ctorResult');
}
async function fieldAccess() {
const value = encodeURIComponent(document.getElementById('fieldValue').value);
callApi(`/api/learning/reflection/field-access?value=${value}`, 'fieldResult');
}
async function methodCall() {
const prefix = encodeURIComponent(document.getElementById('prefix').value);
callApi(`/api/learning/reflection/method-call?prefix=${prefix}`, 'methodResult');
}
callApi('/api/learning/reflection/overview','overview');
</script>
</body>
</html>

View File

@@ -0,0 +1,120 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>修复验证实验室 - Spring Boot</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; background:#f5f5f5; }
.container { max-width:1200px; margin:0 auto; padding:20px; }
.header { background:linear-gradient(135deg,#667eea,#764ba2); color:#fff; padding:28px 20px; border-radius:12px; text-align:center; margin-bottom:20px; }
.nav { display:flex; gap:10px; flex-wrap:wrap; justify-content:center; margin-bottom:20px; }
.nav a { padding:10px 18px; background:#fff; border-radius:20px; text-decoration:none; color:#333; }
.nav a.active { background:#667eea; color:#fff; }
.lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:16px; border-radius:8px; margin-bottom:20px; }
.grid { display:grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap:16px; }
.card { background:#fff; border-radius:12px; padding:18px; box-shadow:0 2px 10px rgba(0,0,0,.08); }
.card h3 { margin-bottom:12px; color:#333; }
.result { background:#111827; color:#d1d5db; padding:12px; border-radius:8px; min-height:160px; white-space:pre-wrap; font-family:monospace; margin-top:10px; }
button { padding:10px 14px; background:#667eea; color:#fff; border:none; border-radius:6px; cursor:pointer; margin-right:8px; margin-bottom:8px; }
.status-pass { color:#16a34a; font-weight:700; }
.status-fail { color:#dc2626; font-weight:700; }
.hint { color:#666; line-height:1.7; margin-top:8px; }
.summary { background:#fff; border-radius:12px; padding:18px; margin-bottom:20px; box-shadow:0 2px 10px rgba(0,0,0,.08); }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🩺 修复验证实验室</h1>
<p>不是“我说修好了”,而是你自己点检查,看到哪里坏、为什么坏、修没修好。</p>
</div>
<div class="nav">
<a href="index.html">🏠 首页</a>
<a href="auth-lab.html">🔐 鉴权实验室</a>
<a href="api.html">🔌 API 测试</a>
<a href="verify-lab.html" class="active">🩺 修复验证实验室</a>
</div>
<div class="lab">
<strong>参与式验证任务卡</strong>
<ul style="padding-left:20px;line-height:1.8;margin-top:8px;">
<li>先点“一键跑总览”,确认当前 profile / auth / datasource 状态</li>
<li>再分别点数据库、用户服务、MyBatis 产品查询,感受“哪个环节坏了就在哪一步暴露”</li>
<li>最后打开 H2 Console验证修复后跳转是不是仍保持 https</li>
<li>如果某一步失败,不要只看失败,要看返回里的 hint —— 那是排查方向</li>
</ul>
</div>
<div class="summary">
<button onclick="runOverview()">一键跑总览</button>
<button onclick="openH2()">打开 H2 Console</button>
<div id="summaryResult" class="result">点击按钮开始验证...</div>
</div>
<div class="grid">
<div class="card">
<h3>数据库链路</h3>
<button onclick="runCheck('database','dbResult')">检查数据库</button>
<div class="hint">验证 DataSource / JDBC / H2 是否可用。</div>
<div id="dbResult" class="result"></div>
</div>
<div class="card">
<h3>用户服务链路</h3>
<button onclick="runCheck('users','userResult')">检查用户服务</button>
<div class="hint">验证 JPA / Service / 用户数据查询是否正常。</div>
<div id="userResult" class="result"></div>
</div>
<div class="card">
<h3>MyBatis 链路</h3>
<button onclick="runCheck('products','productResult')">检查产品查询</button>
<div class="hint">验证 MyBatis Mapper / SQL / 数据库查询是否正常。</div>
<div id="productResult" class="result"></div>
</div>
<div class="card">
<h3>鉴权模式</h3>
<button onclick="runCheck('auth','authResult')">检查鉴权模式</button>
<div class="hint">对照当前 profile理解 why learn=none / advanced=jwt。</div>
<div id="authResult" class="result"></div>
</div>
</div>
</div>
<script>
async function runOverview() {
const el = document.getElementById('summaryResult');
el.textContent = '检查中...';
try {
const res = await fetch('/api/verify/overview');
const data = await res.json();
el.textContent = JSON.stringify(data, null, 2);
} catch (e) {
el.textContent = '总览检查失败: ' + e.message;
}
}
async function runCheck(name, resultId) {
const el = document.getElementById(resultId);
el.textContent = '检查中...';
try {
const res = await fetch('/api/verify/' + name);
const data = await res.json();
const badge = data.ok ? '✅ PASS' : '❌ FAIL';
el.textContent = badge + '\n\n' + JSON.stringify(data, null, 2);
} catch (e) {
el.textContent = '检查失败: ' + e.message;
}
}
function openH2() {
window.open('/h2-console', '_blank');
}
runOverview();
</script>
</body>
</html>

View File

@@ -1,26 +1,47 @@
com/example/scaffold/dto/OrderCreateRequest.class
com/example/scaffold/learning/MyBatisLearningController.class
com/example/scaffold/learning/reflection/ReflectionLabTarget.class
com/example/scaffold/config/database/DatabaseConfig.class
com/example/scaffold/SpringbootScaffoldApplication.class
com/example/scaffold/learning/lifecycle/IocLifecycleTracker.class
com/example/scaffold/controller/AuthController.class
com/example/scaffold/security/LearningPermitAllSecurityConfig.class
com/example/scaffold/learning/IocLearningController.class
com/example/scaffold/learning/lifecycle/PrototypeLifecycleBean.class
com/example/scaffold/learning/lifecycle/LifecycleDemoBean.class
com/example/scaffold/controller/VerificationController.class
com/example/scaffold/dto/ProductCreateRequest.class
com/example/scaffold/learning/lifecycle/SingletonLifecycleBean.class
com/example/scaffold/learning/IocLearningController$LearningBean.class
com/example/scaffold/controller/RootController.class
com/example/scaffold/learning/AopLearningController.class
com/example/scaffold/security/jwt/JwtUtil.class
com/example/scaffold/cache/CacheConfig.class
com/example/scaffold/config/LearningProfileInfo.class
com/example/scaffold/controller/HelloController.class
com/example/scaffold/service/UserService.class
com/example/scaffold/SpringbootScaffoldApplication.class
com/example/scaffold/service/impl/UserServiceImpl.class
com/example/scaffold/controller/UserController.class
com/example/scaffold/learning/IocLearningController.class
com/example/scaffold/learning/ReflectionLearningController.class
com/example/scaffold/security/jwt/JwtSecurityConfig.class
com/example/scaffold/aop/LearningAspect.class
com/example/scaffold/service/impl/OrderService.class
com/example/scaffold/controller/ProductOrderController.class
com/example/scaffold/mapper/ProductMapper.class
com/example/scaffold/security/jwt/JwtAuthenticationFilter$JwtUserDetails.class
com/example/scaffold/cache/CacheService.class
com/example/scaffold/mapper/OrderMapper.class
com/example/scaffold/security/jwt/JwtAuthenticationFilter.class
com/example/scaffold/aop/PerformanceAspect.class
com/example/scaffold/entity/User.class
com/example/scaffold/dto/UserCreateRequest.class
com/example/scaffold/dto/ProductCreateRequest.class
com/example/scaffold/learning/lifecycle/LazySingletonLifecycleBean.class
com/example/scaffold/learning/AdvancedLearningController.class
com/example/scaffold/security/satoken/SaTokenConfig.class
com/example/scaffold/entity/Order.class
com/example/scaffold/mapper/UserMapper.class
com/example/scaffold/learning/TransactionLearningController.class
com/example/scaffold/learning/IocLearningController$LearningBean.class
com/example/scaffold/controller/RootController.class
com/example/scaffold/learning/AopLearningController.class
com/example/scaffold/aop/PerformanceAspect$MethodStats.class
com/example/scaffold/config/AppConfig.class
com/example/scaffold/controller/AuthController$LoginRequest.class
com/example/scaffold/entity/Product.class

View File

@@ -1,24 +1,43 @@
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/mapper/ProductMapper.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/controller/UserController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/AopLearningController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/entity/Product.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/entity/Order.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/mapper/UserMapper.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/dto/ProductCreateRequest.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/security/jwt/JwtAuthenticationFilter.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/security/jwt/JwtUtil.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/cache/CacheConfig.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/lifecycle/SingletonLifecycleBean.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/controller/HelloController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/service/impl/UserServiceImpl.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/dto/OrderCreateRequest.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/TransactionLearningController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/security/satoken/SaTokenConfig.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/aop/PerformanceAspect.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/ReflectionLearningController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/entity/User.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/IocLearningController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/controller/ProductOrderController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/mapper/OrderMapper.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/config/AppConfig.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/lifecycle/LifecycleDemoBean.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/security/LearningPermitAllSecurityConfig.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/controller/RootController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/service/UserService.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/cache/CacheService.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/config/database/DatabaseConfig.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/SpringbootScaffoldApplication.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/controller/VerificationController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/dto/UserCreateRequest.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/mapper/ProductMapper.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/config/LearningProfileInfo.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/controller/UserController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/entity/Product.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/AdvancedLearningController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/mapper/UserMapper.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/lifecycle/IocLifecycleTracker.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/reflection/ReflectionLabTarget.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/TransactionLearningController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/lifecycle/PrototypeLifecycleBean.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/lifecycle/LazySingletonLifecycleBean.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/controller/AuthController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/security/jwt/JwtSecurityConfig.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/learning/MyBatisLearningController.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/service/impl/OrderService.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/SpringbootScaffoldApplication.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/dto/UserCreateRequest.java
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/aop/LearningAspect.java

Binary file not shown.