Update: cache module, security modules and build
This commit is contained in:
71
pom.xml
71
pom.xml
@@ -66,12 +66,83 @@
|
|||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
</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 -->
|
<!-- Test -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|||||||
804
springboot.log
804
springboot.log
@@ -7,697 +7,113 @@
|
|||||||
=========|_|==============|___/=/_/_/_/
|
=========|_|==============|___/=/_/_/_/
|
||||||
:: Spring Boot :: (v3.2.3)
|
:: 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-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-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-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-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-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-07T08:57:32.385Z INFO 1395465 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
|
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-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-07T09:46:51.893Z INFO 1411782 --- [springboot-scaffold] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
|
||||||
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-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-07T08:57:39.218Z INFO 1395465 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
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-07T08:57:39.222Z INFO 1395465 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.19]
|
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-07T08:57:39.853Z INFO 1395465 --- [springboot-scaffold] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
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-07T08:57:39.862Z INFO 1395465 --- [springboot-scaffold] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 14718 ms
|
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-07T08:57:41.622Z INFO 1395465 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
|
2026-03-07T09:47:00.979Z INFO 1411782 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||||
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-07T09:47:00.986Z INFO 1411782 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.19]
|
||||||
2026-03-07T08:57:43.610Z INFO 1395465 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
|
2026-03-07T09:47:01.536Z INFO 1411782 --- [springboot-scaffold] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||||
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-07T09:47:01.543Z INFO 1411782 --- [springboot-scaffold] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 17641 ms
|
||||||
2026-03-07T08:57:47.458Z INFO 1395465 --- [springboot-scaffold] [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
|
2026-03-07T09:47:03.138Z INFO 1411782 --- [springboot-scaffold] [ main] c.e.s.config.database.DatabaseConfig : 🚀 使用 H2 内存数据库
|
||||||
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-07T09:47:03.393Z INFO 1411782 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
|
||||||
2026-03-07T08:57:48.002Z INFO 1395465 --- [springboot-scaffold] [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled
|
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-07T08:57:49.405Z INFO 1395465 --- [springboot-scaffold] [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
|
2026-03-07T09:47:05.513Z INFO 1411782 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
|
||||||
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-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-07T08:57:56.727Z INFO 1395465 --- [springboot-scaffold] [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
|
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.
|
||||||
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
|
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-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-07T09:47:08.518Z ERROR 1411782 --- [springboot-scaffold] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Exception starting filter [jwtAuthenticationFilter]
|
||||||
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'
|
java.lang.NullPointerException: Cannot invoke "org.apache.commons.logging.Log.isDebugEnabled()" because "this.logger" is null
|
||||||
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 ''
|
at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:239) ~[spring-web-6.1.4.jar!/:6.1.4]
|
||||||
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)
|
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:263) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
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'
|
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:102) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
2026-03-07T08:58:55.810Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
|
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4287) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
2026-03-07T08:58:55.824Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 8 ms
|
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4902) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
2026-03-07T08:58:56.276Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: RootController.index() 参数: []
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
2026-03-07T08:58:56.277Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-1] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: RootController.index() 耗时: 1ms
|
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1332) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
2026-03-07T09:04:54.453Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: RootController.index() 参数: []
|
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1322) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
2026-03-07T09:04:54.454Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: RootController.index() 耗时: 1ms
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
|
||||||
2026-03-07T09:04:54.926Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
|
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
2026-03-07T09:04:54.927Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
|
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) ~[na:na]
|
||||||
2026-03-07T09:04:54.927Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
|
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
2026-03-07T09:04:54.932Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: UserController.count() 参数: []
|
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:845) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
2026-03-07T09:04:54.936Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: UserServiceImpl.count()
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
Creating a new SqlSession
|
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1332) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
Creating a new SqlSession
|
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1322) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
Creating a new SqlSession
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
|
||||||
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7edf21ef] was not registered for synchronization because synchronization is not active
|
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e00c432] was not registered for synchronization because synchronization is not active
|
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) ~[na:na]
|
||||||
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@40942315] was not registered for synchronization because synchronization is not active
|
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.0
|
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:240) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
JDBC Connection [HikariProxyConnection@1678050146 wrapping conn1: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
JDBC Connection [HikariProxyConnection@990931398 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
|
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:433) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
JDBC Connection [HikariProxyConnection@130499610 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
==> Preparing: SELECT * FROM orders ORDER BY created_at DESC
|
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:921) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
==> Preparing: SELECT COUNT(*) FROM users
|
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
|
at org.apache.catalina.startup.Tomcat.start(Tomcat.java:437) ~[tomcat-embed-core-10.1.19.jar!/:na]
|
||||||
==> Parameters:
|
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:126) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
==> Parameters:
|
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:105) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
==> Parameters:
|
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:499) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
<== Total: 0
|
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:218) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e00c432]
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:188) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
<== Columns: COUNT(*)
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:162) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
<== Row: 0
|
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:618) ~[spring-context-6.1.4.jar!/:6.1.4]
|
||||||
<== Total: 0
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7edf21ef]
|
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:04:55.109Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 183ms
|
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:04:55.106Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:04:55.110Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:04:55.110Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 183ms
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
<== Total: 1
|
at com.example.scaffold.SpringbootScaffoldApplication.main(SpringbootScaffoldApplication.java:9) ~[!/:1.0.0]
|
||||||
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@40942315]
|
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
|
||||||
2026-03-07T09:04:55.136Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
|
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
|
||||||
2026-03-07T09:04:55.136Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
|
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91) ~[springboot-scaffold-1.0.0.jar:1.0.0]
|
||||||
2026-03-07T09:04:55.136Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 204ms
|
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53) ~[springboot-scaffold-1.0.0.jar:1.0.0]
|
||||||
2026-03-07T09:05:06.090Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
|
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58) ~[springboot-scaffold-1.0.0.jar:1.0.0]
|
||||||
Creating a new SqlSession
|
|
||||||
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7377beec] was not registered for synchronization because synchronization is not active
|
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
|
||||||
JDBC Connection [HikariProxyConnection@978555190 wrapping conn0: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
|
2026-03-07T09:47:08.555Z ERROR 1411782 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardContext : Context [] startup failed due to previous errors
|
||||||
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
|
2026-03-07T09:47:08.698Z INFO 1411782 --- [springboot-scaffold] [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||||
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: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:05:06.093Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
|
2026-03-07T09:47:08.720Z INFO 1411782 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
|
||||||
Creating a new SqlSession
|
2026-03-07T09:47:08.971Z INFO 1411782 --- [springboot-scaffold] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
|
||||||
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@90950fc] was not registered for synchronization because synchronization is not active
|
2026-03-07T09:47:09.105Z INFO 1411782 --- [springboot-scaffold] [ main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||||
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
|
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||||
==> Parameters:
|
2026-03-07T09:47:09.207Z ERROR 1411782 --- [springboot-scaffold] [ main] o.s.boot.SpringApplication : Application run failed
|
||||||
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()
|
org.springframework.context.ApplicationContextException: Unable to start web server
|
||||||
Creating a new SqlSession
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:165) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@440b2f50] was not registered for synchronization because synchronization is not active
|
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:618) ~[spring-context-6.1.4.jar!/:6.1.4]
|
||||||
==> Parameters:
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
<== Total: 0
|
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7377beec]
|
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:05:06.096Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-3] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listProducts() 耗时: 6ms
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
<== Total: 0
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@90950fc]
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:05:06.100Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: OrderService.findAll() => ArrayList
|
at com.example.scaffold.SpringbootScaffoldApplication.main(SpringbootScaffoldApplication.java:9) ~[!/:1.0.0]
|
||||||
2026-03-07T09:05:06.100Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: OrderService.findAll()
|
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
|
||||||
2026-03-07T09:05:06.100Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-4] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: ProductOrderController.listOrders() 耗时: 7ms
|
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
|
||||||
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
|
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91) ~[springboot-scaffold-1.0.0.jar:1.0.0]
|
||||||
Cache Hit Ratio [com.example.scaffold.mapper.UserMapper]: 0.5
|
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53) ~[springboot-scaffold-1.0.0.jar:1.0.0]
|
||||||
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@440b2f50]
|
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58) ~[springboot-scaffold-1.0.0.jar:1.0.0]
|
||||||
2026-03-07T09:05:06.117Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : ✅ [AOP @AfterReturning] 方法返回: UserServiceImpl.count() => Long
|
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
|
||||||
2026-03-07T09:05:06.118Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔸 [AOP @After] 执行完成: UserServiceImpl.count()
|
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:145) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:05:06.118Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-6] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 完成: UserController.count() 耗时: 29ms
|
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:105) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:05:36.083Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listOrders() 参数: []
|
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:499) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:05:36.083Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-5] c.example.scaffold.aop.LearningAspect : 🔹 [AOP @Before] 即将执行: OrderService.findAll()
|
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:218) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
Creating a new SqlSession
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:188) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@34150731] was not registered for synchronization because synchronization is not active
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:162) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
2026-03-07T09:05:36.084Z INFO 1395465 --- [springboot-scaffold] [nio-8082-exec-7] c.example.scaffold.aop.LearningAspect : 🔄 [AOP @Around] 开始: ProductOrderController.listProducts() 参数: []
|
... 13 common frames omitted
|
||||||
Creating a new SqlSession
|
Caused by: java.lang.IllegalStateException: StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[] failed to start
|
||||||
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@50a60d1e] was not registered for synchronization because synchronization is not active
|
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.rethrowDeferredStartupExceptions(TomcatWebServer.java:207) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
JDBC Connection [HikariProxyConnection@770987400 wrapping conn2: url=jdbc:h2:file:~/h2/springboot_scaffold user=SA] will not be managed by Spring
|
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:129) ~[spring-boot-3.2.3.jar!/:3.2.3]
|
||||||
==> Preparing: SELECT * FROM products ORDER BY created_at DESC
|
... 18 common frames omitted
|
||||||
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
|
|
||||||
|
|||||||
100
src/main/java/com/example/scaffold/cache/CacheConfig.java
vendored
Normal file
100
src/main/java/com/example/scaffold/cache/CacheConfig.java
vendored
Normal 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();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
143
src/main/java/com/example/scaffold/cache/CacheService.java
vendored
Normal file
143
src/main/java/com/example/scaffold/cache/CacheService.java
vendored
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 更强"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) {}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
// 禁用 CSRF(JWT 不需要)
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
140
src/main/java/com/example/scaffold/security/jwt/JwtUtil.java
Normal file
140
src/main/java/com/example/scaffold/security/jwt/JwtUtil.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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\": \"未登录\"}";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -242,6 +242,22 @@
|
|||||||
<button class="btn btn-primary" onclick="testApi('GET', '/api/learning/transaction/propagation', null, 'learnResult4')">测试</button>
|
<button class="btn btn-primary" onclick="testApi('GET', '/api/learning/transaction/propagation', null, 'learnResult4')">测试</button>
|
||||||
<div id="learnResult4" class="result"></div>
|
<div id="learnResult4" class="result"></div>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
46
target/classes/application-advanced.yml
Normal file
46
target/classes/application-advanced.yml
Normal 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
|
||||||
29
target/classes/application-learn.yml
Normal file
29
target/classes/application-learn.yml
Normal 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
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
spring.application.name=springboot-scaffold
|
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.h2.console.enabled=true
|
||||||
spring.datasource.url=jdbc:h2:file:~/h2/springboot_scaffold
|
spring.datasource.url=jdbc:h2:file:~/h2/springboot_scaffold
|
||||||
spring.datasource.driverClassName=org.h2.Driver
|
spring.datasource.driverClassName=org.h2.Driver
|
||||||
|
|||||||
Binary file not shown.
BIN
target/classes/com/example/scaffold/cache/CacheConfig.class
vendored
Normal file
BIN
target/classes/com/example/scaffold/cache/CacheConfig.class
vendored
Normal file
Binary file not shown.
BIN
target/classes/com/example/scaffold/cache/CacheService.class
vendored
Normal file
BIN
target/classes/com/example/scaffold/cache/CacheService.class
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
target/classes/com/example/scaffold/security/jwt/JwtUtil.class
Normal file
BIN
target/classes/com/example/scaffold/security/jwt/JwtUtil.class
Normal file
Binary file not shown.
Binary file not shown.
260
target/classes/static/advanced.html
Normal file
260
target/classes/static/advanced.html
Normal 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>
|
||||||
@@ -49,6 +49,8 @@
|
|||||||
.tab-content.active { display: block; }
|
.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; }
|
.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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -68,6 +70,12 @@
|
|||||||
<a href="api.html" class="active">🔌 API</a>
|
<a href="api.html" class="active">🔌 API</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="profileBanner" class="profile-banner">正在读取 profile...</div>
|
||||||
|
<div class="tools">
|
||||||
|
<button class="btn btn-primary" onclick="copyCurl()">复制当前示例 cURL(GET /api/users)</button>
|
||||||
|
<a class="btn btn-primary" href="verify-lab.html">进入修复验证实验室</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<div class="tab active" onclick="switchTab('user')">👥 用户 API</div>
|
<div class="tab active" onclick="switchTab('user')">👥 用户 API</div>
|
||||||
<div class="tab" onclick="switchTab('product')">📦 产品 API</div>
|
<div class="tab" onclick="switchTab('product')">📦 产品 API</div>
|
||||||
@@ -248,6 +256,27 @@
|
|||||||
document.getElementById(tab + 'Tab').classList.add('active');
|
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) {
|
async function testApi(method, url, body, resultId) {
|
||||||
const resultDiv = document.getElementById(resultId);
|
const resultDiv = document.getElementById(resultId);
|
||||||
resultDiv.classList.add('show');
|
resultDiv.classList.add('show');
|
||||||
@@ -275,6 +304,8 @@
|
|||||||
resultDiv.innerHTML = `<strong style="color:#ff6b6b;">Error</strong>\n\n${e.message}`;
|
resultDiv.innerHTML = `<strong style="color:#ff6b6b;">Error</strong>\n\n${e.message}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadProfileBanner();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
142
target/classes/static/auth-lab.html
Normal file
142
target/classes/static/auth-lab.html
Normal 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>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
.status-item { background: white; padding: 20px 30px; border-radius: 10px; text-align: center; }
|
.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 .value { font-size: 2em; font-weight: bold; color: #667eea; }
|
||||||
.status-item .label { color: #666; margin-top: 5px; }
|
.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; }
|
footer { text-align: center; padding: 30px; color: #666; margin-top: 40px; }
|
||||||
</style>
|
</style>
|
||||||
@@ -69,6 +72,22 @@
|
|||||||
<div class="value" id="orderCount">-</div>
|
<div class="value" id="orderCount">-</div>
|
||||||
<div class="label">订单数量</div>
|
<div class="label">订单数量</div>
|
||||||
</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>
|
||||||
|
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
@@ -78,6 +97,10 @@
|
|||||||
<a href="mybatis.html">💾 MyBatis</a>
|
<a href="mybatis.html">💾 MyBatis</a>
|
||||||
<a href="transaction.html">🔄 事务管理</a>
|
<a href="transaction.html">🔄 事务管理</a>
|
||||||
<a href="users.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>
|
<a href="api.html">🔌 API 测试</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -142,6 +165,55 @@
|
|||||||
<a href="users.html" class="btn">开始学习 →</a>
|
<a href="users.html" class="btn">开始学习 →</a>
|
||||||
</div>
|
</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">
|
<div class="card">
|
||||||
<h3>🔌 API 测试面板</h3>
|
<h3>🔌 API 测试面板</h3>
|
||||||
<p>在线测试所有 API 接口,查看请求响应,理解 RESTful API 工作原理。</p>
|
<p>在线测试所有 API 接口,查看请求响应,理解 RESTful API 工作原理。</p>
|
||||||
@@ -172,7 +244,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer>
|
<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>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -180,17 +252,19 @@
|
|||||||
// 加载状态数据
|
// 加载状态数据
|
||||||
async function loadStatus() {
|
async function loadStatus() {
|
||||||
try {
|
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/learning/ioc/beans').then(r => r.json()),
|
||||||
fetch('/api/users/count').then(r => r.json()),
|
fetch('/api/users/count').then(r => r.json()),
|
||||||
fetch('/api/products').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('beanCount').textContent = beans.total || '-';
|
||||||
document.getElementById('userCount').textContent = users.count || 0;
|
document.getElementById('userCount').textContent = users.count || 0;
|
||||||
document.getElementById('productCount').textContent = products.length || 0;
|
document.getElementById('productCount').textContent = products.length || 0;
|
||||||
document.getElementById('orderCount').textContent = orders.length || 0;
|
document.getElementById('orderCount').textContent = orders.length || 0;
|
||||||
|
document.getElementById('activeProfile').textContent = profile.profile || '-';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('加载状态失败:', e);
|
console.error('加载状态失败:', e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,173 +3,200 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>IoC 容器学习 - Spring Boot</title>
|
<title>IoC 生命周期可视化实验室 - Spring Boot</title>
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; }
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; }
|
||||||
.container { max-width: 1400px; margin: 0 auto; padding: 20px; }
|
.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 { 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; }
|
.header h1 { font-size: 2em; }
|
||||||
|
|
||||||
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; justify-content: center; }
|
.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 { 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; }
|
.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 { 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; }
|
.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 { 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 { padding: 10px 20px; background: #667eea; color: white; border: none; border-radius: 5px; cursor: pointer; margin: 5px; }
|
||||||
.btn:hover { background: #5a6fd6; }
|
.btn:hover { background: #5a6fd6; }
|
||||||
.btn-secondary { background: #6c757d; }
|
.btn-secondary { background: #6c757d; }
|
||||||
|
.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: 400px; overflow-y: auto; }
|
.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; }
|
table { width: 100%; border-collapse: collapse; margin: 10px 0; }
|
||||||
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #eee; }
|
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #eee; }
|
||||||
th { background: #f8f9fa; font-weight: 600; }
|
th { background: #f8f9fa; font-weight: 600; }
|
||||||
tr:hover { background: #f8f9fa; }
|
tr:hover { background: #f8f9fa; }
|
||||||
|
|
||||||
.badge { padding: 4px 8px; border-radius: 4px; font-size: 0.8em; }
|
.badge { padding: 4px 8px; border-radius: 4px; font-size: 0.8em; }
|
||||||
.badge-primary { background: #667eea; color: white; }
|
.badge-primary { background: #667eea; color: white; }
|
||||||
.badge-success { background: #28a745; color: white; }
|
.badge-success { background: #28a745; color: white; }
|
||||||
.badge-warning { background: #ffc107; color: #333; }
|
.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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1>📦 IoC 容器学习</h1>
|
<h1>📦 IoC 生命周期可视化实验室</h1>
|
||||||
<p>控制反转 (Inversion of Control) 与依赖注入 (Dependency Injection)</p>
|
<p>把“类加载”“Bean 创建”“单例/多例/懒加载”拆开看,自己动手触发、自己观察结果。</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<a href="index.html">🏠 首页</a>
|
<a href="index.html">🏠 首页</a>
|
||||||
<a href="ioc.html" class="active">📦 IoC</a>
|
<a href="ioc.html" class="active">📦 IoC</a>
|
||||||
|
<a href="verify-lab.html">🩺 修复验证</a>
|
||||||
<a href="aop.html">🔪 AOP</a>
|
<a href="aop.html">🔪 AOP</a>
|
||||||
<a href="mybatis.html">💾 MyBatis</a>
|
<a href="mybatis.html">💾 MyBatis</a>
|
||||||
<a href="transaction.html">🔄 事务</a>
|
<a href="transaction.html">🔄 事务</a>
|
||||||
<a href="users.html">👥 用户</a>
|
|
||||||
<a href="api.html">🔌 API</a>
|
<a href="api.html">🔌 API</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="lab">
|
||||||
<h3>📚 核心概念</h3>
|
<strong>🧪 实验任务卡</strong>
|
||||||
<div class="concept-box">
|
<ul style="padding-left:20px; line-height:1.8; margin-top:8px;">
|
||||||
<h4>什么是 IoC?</h4>
|
<li>先点“加载总览”,搞清楚 JVM 类加载 和 Spring Bean 生命周期不是一回事</li>
|
||||||
<p><strong>控制反转 (Inversion of Control)</strong>:将对象的创建和管理交给 Spring 容器,而不是由开发者手动创建。</p>
|
<li>再点“比较三种作用域”,对比 singleton / prototype / lazy singleton 的实例 ID 和 hashCode</li>
|
||||||
<p><strong>依赖注入 (Dependency Injection)</strong>:IoC 的一种实现方式,通过构造器、Setter 或字段将依赖注入到对象中。</p>
|
<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>
|
||||||
<div class="concept-box">
|
|
||||||
<h4>为什么用 IoC?</h4>
|
<div class="card">
|
||||||
<ul>
|
<h3>🆚 作用域对比实验</h3>
|
||||||
<li>✅ <strong>解耦</strong>:对象之间不直接依赖,通过接口交互</li>
|
<button class="btn" onclick="compareScopes()">比较三种作用域</button>
|
||||||
<li>✅ <strong>可测试</strong>:方便使用 Mock 对象进行单元测试</li>
|
<button class="btn btn-secondary" onclick="resetTimeline()">重置时间线</button>
|
||||||
<li>✅ <strong>可维护</strong>:集中管理对象生命周期</li>
|
<div class="small">观察重点:singleton 两次获取是否同一实例?prototype 为什么每次都变?lazy singleton 第一次获取前是否就已经创建?</div>
|
||||||
<li>✅ <strong>AOP 支持</strong>:便于实现切面编程</li>
|
<div id="compareResult" class="result"></div>
|
||||||
</ul>
|
|
||||||
</div>
|
</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">
|
<div class="card">
|
||||||
<h3>🔍 查看所有 Bean</h3>
|
<h3>🔍 查看所有 Bean</h3>
|
||||||
<p>Spring 容器中管理的所有 Bean 对象</p>
|
|
||||||
<button class="btn" onclick="loadBeans()">刷新 Bean 列表</button>
|
<button class="btn" onclick="loadBeans()">刷新 Bean 列表</button>
|
||||||
<button class="btn btn-secondary" onclick="document.getElementById('beansResult').innerHTML=''">清空</button>
|
<button class="btn btn-secondary" onclick="document.getElementById('beansResult').innerHTML=''">清空</button>
|
||||||
<div id="beansResult" class="result"></div>
|
<div id="beansResult" class="result"></div>
|
||||||
</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>
|
</div>
|
||||||
|
|
||||||
<script>
|
<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() {
|
async function loadBeans() {
|
||||||
const result = document.getElementById('beansResult');
|
const result = document.getElementById('beansResult');
|
||||||
result.textContent = '加载中...';
|
result.textContent = '加载中...';
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/learning/ioc/beans');
|
const res = await fetch('/api/learning/ioc/beans');
|
||||||
const data = await res.json();
|
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) {
|
} catch (e) {
|
||||||
result.textContent = '加载失败: ' + e.message;
|
result.textContent = '加载失败: ' + e.message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function testScopes() {
|
loadOverview();
|
||||||
const result = document.getElementById('scopesResult');
|
loadTimeline();
|
||||||
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();
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
119
target/classes/static/reflection.html
Normal file
119
target/classes/static/reflection.html
Normal 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>
|
||||||
120
target/classes/static/verify-lab.html
Normal file
120
target/classes/static/verify-lab.html
Normal 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>
|
||||||
@@ -1,26 +1,47 @@
|
|||||||
com/example/scaffold/dto/OrderCreateRequest.class
|
com/example/scaffold/dto/OrderCreateRequest.class
|
||||||
com/example/scaffold/learning/MyBatisLearningController.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/controller/HelloController.class
|
||||||
com/example/scaffold/service/UserService.class
|
com/example/scaffold/service/UserService.class
|
||||||
com/example/scaffold/SpringbootScaffoldApplication.class
|
|
||||||
com/example/scaffold/service/impl/UserServiceImpl.class
|
com/example/scaffold/service/impl/UserServiceImpl.class
|
||||||
com/example/scaffold/controller/UserController.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/aop/LearningAspect.class
|
||||||
com/example/scaffold/service/impl/OrderService.class
|
com/example/scaffold/service/impl/OrderService.class
|
||||||
com/example/scaffold/controller/ProductOrderController.class
|
com/example/scaffold/controller/ProductOrderController.class
|
||||||
com/example/scaffold/mapper/ProductMapper.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/mapper/OrderMapper.class
|
||||||
|
com/example/scaffold/security/jwt/JwtAuthenticationFilter.class
|
||||||
com/example/scaffold/aop/PerformanceAspect.class
|
com/example/scaffold/aop/PerformanceAspect.class
|
||||||
com/example/scaffold/entity/User.class
|
com/example/scaffold/entity/User.class
|
||||||
com/example/scaffold/dto/UserCreateRequest.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/entity/Order.class
|
||||||
com/example/scaffold/mapper/UserMapper.class
|
com/example/scaffold/mapper/UserMapper.class
|
||||||
com/example/scaffold/learning/TransactionLearningController.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/aop/PerformanceAspect$MethodStats.class
|
||||||
com/example/scaffold/config/AppConfig.class
|
com/example/scaffold/config/AppConfig.class
|
||||||
|
com/example/scaffold/controller/AuthController$LoginRequest.class
|
||||||
com/example/scaffold/entity/Product.class
|
com/example/scaffold/entity/Product.class
|
||||||
|
|||||||
@@ -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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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
|
/home/llm/Projects/springboot-scaffold/src/main/java/com/example/scaffold/aop/LearningAspect.java
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user