Hibernate Component keys

本文探讨了在数据库中如何以嵌入式组件的方式存储夫妻关系,通过使用Husband和Wife类来实现夫妻关系的单一表存储,并详细解释了XML映射配置。


Wife is a component of Husband class and thus they are stored in one table in DB.

1.Annotation

Husband: put @Embedded before component Wife.

Only need one <mapping class="xxxx.xxx.xxx.Husband"> since wife is part of husband's table

 

@Entity
public class Husband {
        private int id;
        private String name;
        private Wife wife;
        
        @Id
        @GeneratedValue
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        
        @Embedded
        public Wife getWife() {
            return wife;
        }
        public void setWife(Wife wife) {
            this.wife = wife;
        }
        
        
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
}

public class Wife {
    private String wifeName;
    private int age;

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public String getWifeName() {
        return wifeName;
    }
    public void setWifeName(String name) {
        wifeName = name;
    }
}

 

2.XML

Only Husband needs xml.  

<Component name="xx of getXX()"> and list <property name="">

<hibernate-mapping package="com.hibernate.model">
<class name="Husband">
   <id name="id"></id>
    <property name="name"></property>
    <component name="wife" >
       <property name ="wifeName"></property>
       <property name ="age"></property>
   </component>
</class>

 

 

 

  

转载于:https://www.cnblogs.com/fifi043/p/4906113.html

C:\jdk-21.0.7\bin\java.exe -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-Dmanagement.endpoints.jmx.exposure.include=*" "-javaagent:D:\IntelliJ IDEA 2024.3.5\lib\idea_rt.jar=62854" -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath C:\Users\86133\IdeaProjects\tools\target\classes;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter-web\3.3.4\spring-boot-starter-web-3.3.4.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter\3.3.4\spring-boot-starter-3.3.4.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot\3.3.4\spring-boot-3.3.4.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\3.3.4\spring-boot-autoconfigure-3.3.4.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter-logging\3.3.4\spring-boot-starter-logging-3.3.4.jar;C:\Users\86133\.m2\repository\ch\qos\logback\logback-classic\1.5.8\logback-classic-1.5.8.jar;C:\Users\86133\.m2\repository\ch\qos\logback\logback-core\1.5.8\logback-core-1.5.8.jar;C:\Users\86133\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.23.1\log4j-to-slf4j-2.23.1.jar;C:\Users\86133\.m2\repository\org\apache\logging\log4j\log4j-api\2.23.1\log4j-api-2.23.1.jar;C:\Users\86133\.m2\repository\org\slf4j\jul-to-slf4j\2.0.16\jul-to-slf4j-2.0.16.jar;C:\Users\86133\.m2\repository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;C:\Users\86133\.m2\repository\org\yaml\snakeyaml\2.2\snakeyaml-2.2.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter-json\3.3.4\spring-boot-starter-json-3.3.4.jar;C:\Users\86133\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.17.2\jackson-datatype-jdk8-2.17.2.jar;C:\Users\86133\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.17.2\jackson-datatype-jsr310-2.17.2.jar;C:\Users\86133\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.17.2\jackson-module-parameter-names-2.17.2.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\3.3.4\spring-boot-starter-tomcat-3.3.4.jar;C:\Users\86133\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\10.1.30\tomcat-embed-core-10.1.30.jar;C:\Users\86133\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.30\tomcat-embed-websocket-10.1.30.jar;C:\Users\86133\.m2\repository\org\springframework\spring-web\6.1.13\spring-web-6.1.13.jar;C:\Users\86133\.m2\repository\org\springframework\spring-beans\6.1.13\spring-beans-6.1.13.jar;C:\Users\86133\.m2\repository\io\micrometer\micrometer-observation\1.13.4\micrometer-observation-1.13.4.jar;C:\Users\86133\.m2\repository\io\micrometer\micrometer-commons\1.13.4\micrometer-commons-1.13.4.jar;C:\Users\86133\.m2\repository\org\springframework\spring-webmvc\6.1.13\spring-webmvc-6.1.13.jar;C:\Users\86133\.m2\repository\org\springframework\spring-context\6.1.13\spring-context-6.1.13.jar;C:\Users\86133\.m2\repository\org\springframework\spring-expression\6.1.13\spring-expression-6.1.13.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter-data-jpa\3.3.4\spring-boot-starter-data-jpa-3.3.4.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter-aop\3.3.4\spring-boot-starter-aop-3.3.4.jar;C:\Users\86133\.m2\repository\org\aspectj\aspectjweaver\1.9.22.1\aspectjweaver-1.9.22.1.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\3.3.4\spring-boot-starter-jdbc-3.3.4.jar;C:\Users\86133\.m2\repository\com\zaxxer\HikariCP\5.1.0\HikariCP-5.1.0.jar;C:\Users\86133\.m2\repository\org\springframework\spring-jdbc\6.1.13\spring-jdbc-6.1.13.jar;C:\Users\86133\.m2\repository\org\hibernate\orm\hibernate-core\6.5.3.Final\hibernate-core-6.5.3.Final.jar;C:\Users\86133\.m2\repository\jakarta\persistence\jakarta.persistence-api\3.1.0\jakarta.persistence-api-3.1.0.jar;C:\Users\86133\.m2\repository\jakarta\transaction\jakarta.transaction-api\2.0.1\jakarta.transaction-api-2.0.1.jar;C:\Users\86133\.m2\repository\org\jboss\logging\jboss-logging\3.5.3.Final\jboss-logging-3.5.3.Final.jar;C:\Users\86133\.m2\repository\org\hibernate\common\hibernate-commons-annotations\6.0.6.Final\hibernate-commons-annotations-6.0.6.Final.jar;C:\Users\86133\.m2\repository\io\smallrye\jandex\3.1.2\jandex-3.1.2.jar;C:\Users\86133\.m2\repository\com\fasterxml\classmate\1.7.0\classmate-1.7.0.jar;C:\Users\86133\.m2\repository\net\bytebuddy\byte-buddy\1.14.19\byte-buddy-1.14.19.jar;C:\Users\86133\.m2\repository\org\glassfish\jaxb\jaxb-runtime\4.0.5\jaxb-runtime-4.0.5.jar;C:\Users\86133\.m2\repository\org\glassfish\jaxb\jaxb-core\4.0.5\jaxb-core-4.0.5.jar;C:\Users\86133\.m2\repository\org\eclipse\angus\angus-activation\2.0.2\angus-activation-2.0.2.jar;C:\Users\86133\.m2\repository\org\glassfish\jaxb\txw2\4.0.5\txw2-4.0.5.jar;C:\Users\86133\.m2\repository\com\sun\istack\istack-commons-runtime\4.1.2\istack-commons-runtime-4.1.2.jar;C:\Users\86133\.m2\repository\jakarta\inject\jakarta.inject-api\2.0.1\jakarta.inject-api-2.0.1.jar;C:\Users\86133\.m2\repository\org\antlr\antlr4-runtime\4.13.0\antlr4-runtime-4.13.0.jar;C:\Users\86133\.m2\repository\org\springframework\data\spring-data-jpa\3.3.4\spring-data-jpa-3.3.4.jar;C:\Users\86133\.m2\repository\org\springframework\data\spring-data-commons\3.3.4\spring-data-commons-3.3.4.jar;C:\Users\86133\.m2\repository\org\springframework\spring-orm\6.1.13\spring-orm-6.1.13.jar;C:\Users\86133\.m2\repository\org\springframework\spring-tx\6.1.13\spring-tx-6.1.13.jar;C:\Users\86133\.m2\repository\org\slf4j\slf4j-api\2.0.16\slf4j-api-2.0.16.jar;C:\Users\86133\.m2\repository\org\springframework\spring-aspects\6.1.13\spring-aspects-6.1.13.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter-security\3.3.4\spring-boot-starter-security-3.3.4.jar;C:\Users\86133\.m2\repository\org\springframework\spring-aop\6.1.13\spring-aop-6.1.13.jar;C:\Users\86133\.m2\repository\org\springframework\security\spring-security-config\6.3.3\spring-security-config-6.3.3.jar;C:\Users\86133\.m2\repository\org\springframework\security\spring-security-core\6.3.3\spring-security-core-6.3.3.jar;C:\Users\86133\.m2\repository\org\springframework\security\spring-security-crypto\6.3.3\spring-security-crypto-6.3.3.jar;C:\Users\86133\.m2\repository\org\springframework\security\spring-security-web\6.3.3\spring-security-web-6.3.3.jar;C:\Users\86133\.m2\repository\org\springframework\boot\spring-boot-starter-validation\3.3.4\spring-boot-starter-validation-3.3.4.jar;C:\Users\86133\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\10.1.30\tomcat-embed-el-10.1.30.jar;C:\Users\86133\.m2\repository\org\hibernate\validator\hibernate-validator\8.0.1.Final\hibernate-validator-8.0.1.Final.jar;C:\Users\86133\.m2\repository\jakarta\validation\jakarta.validation-api\3.0.2\jakarta.validation-api-3.0.2.jar;C:\Users\86133\.m2\repository\org\mybatis\spring\boot\mybatis-spring-boot-starter\3.0.3\mybatis-spring-boot-starter-3.0.3.jar;C:\Users\86133\.m2\repository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\3.0.3\mybatis-spring-boot-autoconfigure-3.0.3.jar;C:\Users\86133\.m2\repository\org\mybatis\mybatis\3.5.14\mybatis-3.5.14.jar;C:\Users\86133\.m2\repository\org\mybatis\mybatis-spring\3.0.3\mybatis-spring-3.0.3.jar;C:\Users\86133\.m2\repository\com\mysql\mysql-connector-j\8.3.0\mysql-connector-j-8.3.0.jar;C:\Users\86133\.m2\repository\org\projectlombok\lombok\1.18.34\lombok-1.18.34.jar;C:\Users\86133\.m2\repository\com\auth0\java-jwt\4.4.0\java-jwt-4.4.0.jar;C:\Users\86133\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.17.2\jackson-databind-2.17.2.jar;C:\Users\86133\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.17.2\jackson-annotations-2.17.2.jar;C:\Users\86133\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.17.2\jackson-core-2.17.2.jar;C:\Users\86133\.m2\repository\io\jsonwebtoken\jjwt-api\0.11.5\jjwt-api-0.11.5.jar;C:\Users\86133\.m2\repository\io\jsonwebtoken\jjwt-impl\0.11.5\jjwt-impl-0.11.5.jar;C:\Users\86133\.m2\repository\io\jsonwebtoken\jjwt-jackson\0.11.5\jjwt-jackson-0.11.5.jar;C:\Users\86133\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\4.0.2\jakarta.xml.bind-api-4.0.2.jar;C:\Users\86133\.m2\repository\jakarta\activation\jakarta.activation-api\2.1.3\jakarta.activation-api-2.1.3.jar;C:\Users\86133\.m2\repository\org\springframework\spring-core\6.1.13\spring-core-6.1.13.jar;C:\Users\86133\.m2\repository\org\springframework\spring-jcl\6.1.13\spring-jcl-6.1.13.jar com.org.example.tools.ToolsApplication . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.3.4) 2025-08-02T13:53:30.651+08:00 INFO 17212 --- [tools] [ main] com.org.example.tools.ToolsApplication : Starting ToolsApplication using Java 21.0.7 with PID 17212 (C:\Users\86133\IdeaProjects\tools\target\classes started by 86133 in C:\Users\86133\IdeaProjects\tools) 2025-08-02T13:53:30.653+08:00 INFO 17212 --- [tools] [ main] com.org.example.tools.ToolsApplication : No active profile set, falling back to 1 default profile: "default" 2025-08-02T13:53:32.143+08:00 INFO 17212 --- [tools] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2025-08-02T13:53:32.213+08:00 INFO 17212 --- [tools] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 60 ms. Found 2 JPA repository interfaces. 2025-08-02T13:53:32.296+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Identified candidate component class: file [C:\Users\86133\IdeaProjects\tools\target\classes\com\org\example\tools\mapper\BorrowRecordMapper.class] 2025-08-02T13:53:32.296+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Identified candidate component class: file [C:\Users\86133\IdeaProjects\tools\target\classes\com\org\example\tools\mapper\FeedbackMapper.class] 2025-08-02T13:53:32.296+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Identified candidate component class: file [C:\Users\86133\IdeaProjects\tools\target\classes\com\org\example\tools\mapper\RequestMapper.class] 2025-08-02T13:53:32.296+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Identified candidate component class: file [C:\Users\86133\IdeaProjects\tools\target\classes\com\org\example\tools\mapper\SysUserMapper.class] 2025-08-02T13:53:32.296+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Identified candidate component class: file [C:\Users\86133\IdeaProjects\tools\target\classes\com\org\example\tools\mapper\ToolMapper.class] 2025-08-02T13:53:32.296+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Identified candidate component class: file [C:\Users\86133\IdeaProjects\tools\target\classes\com\org\example\tools\mapper\ToolOperationLogMapper.class] 2025-08-02T13:53:32.296+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Identified candidate component class: file [C:\Users\86133\IdeaProjects\tools\target\classes\com\org\example\tools\mapper\UserMapper.class] 2025-08-02T13:53:32.296+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Identified candidate component class: file [C:\Users\86133\IdeaProjects\tools\target\classes\com\org\example\tools\mapper\UserRequestMapper.class] 2025-08-02T13:53:32.297+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Creating MapperFactoryBean with name 'borrowRecordMapper' and 'com.org.example.tools.mapper.BorrowRecordMapper' mapperInterface 2025-08-02T13:53:32.299+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Enabling autowire by type for MapperFactoryBean with name 'borrowRecordMapper'. 2025-08-02T13:53:32.299+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Creating MapperFactoryBean with name 'feedbackMapper' and 'com.org.example.tools.mapper.FeedbackMapper' mapperInterface 2025-08-02T13:53:32.300+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Enabling autowire by type for MapperFactoryBean with name 'feedbackMapper'. 2025-08-02T13:53:32.300+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Creating MapperFactoryBean with name 'requestMapper' and 'com.org.example.tools.mapper.RequestMapper' mapperInterface 2025-08-02T13:53:32.301+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Enabling autowire by type for MapperFactoryBean with name 'requestMapper'. 2025-08-02T13:53:32.301+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Creating MapperFactoryBean with name 'sysUserMapper' and 'com.org.example.tools.mapper.SysUserMapper' mapperInterface 2025-08-02T13:53:32.301+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Enabling autowire by type for MapperFactoryBean with name 'sysUserMapper'. 2025-08-02T13:53:32.301+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Creating MapperFactoryBean with name 'toolMapper' and 'com.org.example.tools.mapper.ToolMapper' mapperInterface 2025-08-02T13:53:32.301+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Enabling autowire by type for MapperFactoryBean with name 'toolMapper'. 2025-08-02T13:53:32.301+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Creating MapperFactoryBean with name 'toolOperationLogMapper' and 'com.org.example.tools.mapper.ToolOperationLogMapper' mapperInterface 2025-08-02T13:53:32.303+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Enabling autowire by type for MapperFactoryBean with name 'toolOperationLogMapper'. 2025-08-02T13:53:32.303+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Creating MapperFactoryBean with name 'userMapper' and 'com.org.example.tools.mapper.UserMapper' mapperInterface 2025-08-02T13:53:32.303+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Enabling autowire by type for MapperFactoryBean with name 'userMapper'. 2025-08-02T13:53:32.303+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Creating MapperFactoryBean with name 'userRequestMapper' and 'com.org.example.tools.mapper.UserRequestMapper' mapperInterface 2025-08-02T13:53:32.304+08:00 DEBUG 17212 --- [tools] [ main] o.m.s.mapper.ClassPathMapperScanner : Enabling autowire by type for MapperFactoryBean with name 'userRequestMapper'. 2025-08-02T13:53:32.801+08:00 INFO 17212 --- [tools] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8089 (http) 2025-08-02T13:53:32.814+08:00 INFO 17212 --- [tools] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2025-08-02T13:53:32.814+08:00 INFO 17212 --- [tools] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.30] 2025-08-02T13:53:32.868+08:00 INFO 17212 --- [tools] [ main] o.a.c.c.C.[Tomcat].[localhost].[/api] : Initializing Spring embedded WebApplicationContext 2025-08-02T13:53:32.869+08:00 INFO 17212 --- [tools] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2168 ms 2025-08-02T13:53:33.005+08:00 INFO 17212 --- [tools] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2025-08-02T13:53:33.514+08:00 INFO 17212 --- [tools] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@51ff3c4b 2025-08-02T13:53:33.516+08:00 INFO 17212 --- [tools] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2025-08-02T13:53:33.552+08:00 INFO 17212 --- [tools] [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2025-08-02T13:53:33.616+08:00 INFO 17212 --- [tools] [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.5.3.Final 2025-08-02T13:53:33.661+08:00 INFO 17212 --- [tools] [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled 2025-08-02T13:53:34.007+08:00 INFO 17212 --- [tools] [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer 2025-08-02T13:53:34.421+08:00 INFO 17212 --- [tools] [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) 2025-08-02T13:53:34.427+08:00 INFO 17212 --- [tools] [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2025-08-02T13:53:34.446+08:00 WARN 17212 --- [tools] [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig' defined in file [C:\Users\86133\IdeaProjects\tools\target\classes\com\org\example\tools\config\SecurityConfig.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.org.example.tools.security.JwtAuthenticationFilter' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} 2025-08-02T13:53:34.447+08:00 INFO 17212 --- [tools] [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2025-08-02T13:53:34.449+08:00 INFO 17212 --- [tools] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2025-08-02T13:53:34.457+08:00 INFO 17212 --- [tools] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. 2025-08-02T13:53:34.458+08:00 INFO 17212 --- [tools] [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat] 2025-08-02T13:53:34.467+08:00 INFO 17212 --- [tools] [ main] .s.b.a.l.ConditionEvaluationReportLogger : Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2025-08-02T13:53:34.498+08:00 ERROR 17212 --- [tools] [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLICATION FAILED TO START *************************** Description: Parameter 0 of constructor in com.org.example.tools.config.SecurityConfig required a bean of type 'com.org.example.tools.security.JwtAuthenticationFilter' that could not be found. Action: Consider defining a bean of type 'com.org.example.tools.security.JwtAuthenticationFilter' in your configuration.
08-03
<think>我们遇到了一个启动错误:`Parameter 0 of constructor in com.org.example.tools.config.SecurityConfig required a bean of type 'com.org.example.tools.security.JwtAuthenticationFilter' that could not be found.` 这个错误表明在`SecurityConfig`类的构造函数中需要注入一个`JwtAuthenticationFilter`的bean,但是Spring容器中没有找到这个bean。 解决方案: 1. 确保`JwtAuthenticationFilter`类已经被Spring管理(例如,使用`@Component`注解标记)。 2. 如果`JwtAuthenticationFilter`需要一些依赖项(比如`UserDetailsService`等),确保这些依赖项也已经配置为bean。 3. 如果`JwtAuthenticationFilter`是通过`new`关键字创建的,那么我们需要将其声明为一个bean。 通常,自定义的Filter可以通过以下方式之一注册: - 在配置类中声明为`@Bean` - 使用`@Component`注解 但是,由于Filter是由Servlet容器管理的,而不是Spring,所以通常我们会在Spring Security配置中通过`addFilter`方法添加,并且将其声明为Spring bean(以便注入依赖)。 因此,我们可以在`JwtAuthenticationFilter`类上添加`@Component`注解,或者在配置类中定义一个`@Bean`方法。 然而,注意:如果这个Filter需要依赖其他bean(比如`UserDetailsService`),那么我们必须将其声明为bean,以便Spring能够注入其依赖。 让我们假设`JwtAuthenticationFilter`的代码如下: ```java public class JwtAuthenticationFilter extends OncePerRequestFilter { // 可能依赖了其他服务,比如UserDetailsService private final UserDetailsService userDetailsService; // 如果使用构造器注入,那么必须通过@Autowired(或者通过构造器隐式注入)来注入UserDetailsService public JwtAuthenticationFilter(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } // ... 其他代码 } ``` 那么,我们需要在Spring配置中将其声明为bean。有两种方式: 方式1:在`JwtAuthenticationFilter`类上使用`@Component`,并确保其构造器参数只有一个且类型为`UserDetailsService`(并且Spring容器中有该类型的bean)。 方式2:在配置类中显式定义bean: ```java @Configuration public class SecurityBeanConfig { @Bean public JwtAuthenticationFilter jwtAuthenticationFilter(UserDetailsService userDetailsService) { return new JwtAuthenticationFilter(userDetailsService); } } ``` 然后在`SecurityConfig`中,我们可以通过自动注入的方式获取这个bean: ```java @Configuration @EnableWebSecurity public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) { this.jwtAuthenticationFilter = jwtAuthenticationFilter; } // 在配置中添加这个filter @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // ... 其他配置 .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } } ``` 这样,Spring就会在创建`SecurityConfig`时注入已经创建好的`JwtAuthenticationFilter` bean。 但是,如果我们在`SecurityConfig`中已经定义了`UserDetailsService`,那么我们可以确保`UserDetailsService`的bean存在,从而可以创建`JwtAuthenticationFilter`。 所以,我们需要检查: - `JwtAuthenticationFilter`类是否被正确声明为bean(通过`@Component`或在配置类中通过`@Bean`方法)。 - 如果`JwtAuthenticationFilter`有依赖,这些依赖在Spring容器中是否可用。 如果问题仍然存在,请检查`JwtAuthenticationFilter`的包是否在Spring的组件扫描路径下(即`com.org.example.tools`及其子包)。 如果以上都正确,那么可能是循环依赖的问题,但根据错误信息,是找不到bean,所以先确保bean的创建。 由于错误信息中已经明确指出了缺少`JwtAuthenticationFilter`的bean,因此我们按照上述方式添加即可。 下面,我将提供一个示例配置: 假设`JwtAuthenticationFilter`类如下: ```java package com.org.example.tools.security; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class JwtAuthenticationFilter extends OncePerRequestFilter { private final UserDetailsService userDetailsService; public JwtAuthenticationFilter(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 从请求中获取token,验证token,然后设置认证信息 // ... 这里省略具体实现 filterChain.doFilter(request, response); } } ``` 为了将其注册为bean,我们可以在配置类中: ```java @Configuration public class JwtSecurityConfig { @Bean public JwtAuthenticationFilter jwtAuthenticationFilter(UserDetailsService userDetailsService) { return new JwtAuthenticationFilter(userDetailsService); } } ``` 或者,在`JwtAuthenticationFilter`类上添加`@Component`,并确保其构造器只有一个(这样Spring会自动注入`UserDetailsService`): ```java @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { private final UserDetailsService userDetailsService; public JwtAuthenticationFilter(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } // ... 其他代码 } ``` 注意:如果使用`@Component`,那么`UserDetailsService`必须已经存在一个bean(通常我们在`SecurityConfig`中会定义)。 如果`SecurityConfig`中已经通过`@Bean`定义了`UserDetailsService`,那么就没有问题。 因此,请根据你的项目结构选择一种方式将`JwtAuthenticationFilter`声明为bean。 如果问题解决,应用将正常启动。 如果仍然遇到问题,请检查`SecurityConfig`类,确保构造函数参数是`JwtAuthenticationFilter`类型,并且没有其他配置错误。 另外,注意在`SecurityConfig`的`securityFilterChain`方法中,将`JwtAuthenticationFilter`添加到过滤器链中: ```java http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); ``` 这样,请求就会先经过JWT过滤器进行认证。 最后,重新启动应用,看是否解决。</think>### 解决 Spring Boot 启动错误:`JwtAuthenticationFilter` Bean 缺失问题 错误信息表明 Spring 无法找到 `JwtAuthenticationFilter` 的 Bean 实例,导致应用启动失败。以下是完整的解决方案: #### 1. 创建 `JwtAuthenticationFilter` Bean 在安全配置类中显式定义 `JwtAuthenticationFilter` Bean: ```java // src/main/java/com/org/example/tools/config/SecurityConfig.java package com.org.example.tools.config; import com.org.example.tools.security.JwtAuthenticationFilter; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; 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.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; // 显式创建 JwtAuthenticationFilter Bean @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/**").permitAll() .requestMatchers("/api/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public AuthenticationManager authenticationManager( AuthenticationConfiguration config) throws Exception { return config.getAuthenticationManager(); } } ``` #### 2. 实现 `JwtAuthenticationFilter` 类 创建 JWT 认证过滤器: ```java // src/main/java/com/org/example/tools/security/JwtAuthenticationFilter.java package com.org.example.tools.security; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.stream.Collectors; @Component @RequiredArgsConstructor public class JwtAuthenticationFilter extends OncePerRequestFilter { @Value("${jwt.secret}") private String jwtSecret; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String header = request.getHeader("Authorization"); if (header == null || !header.startsWith("Bearer ")) { filterChain.doFilter(request, response); return; } String token = header.replace("Bearer ", ""); try { Claims claims = Jwts.parser() .verifyWith(Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8))) .build() .parseSignedClaims(token) .getPayload(); String username = claims.getSubject(); List<String> roles = claims.get("roles", List.class); List<SimpleGrantedAuthority> authorities = roles.stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); Authentication authentication = new UsernamePasswordAuthenticationToken( username, null, authorities ); SecurityContextHolder.getContext().setAuthentication(authentication); } catch (Exception e) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return; } filterChain.doFilter(request, response); } } ``` #### 3. 添加 JWT 密钥配置 在 `application.properties` 中添加 JWT 密钥: ```properties # src/main/resources/application.properties jwt.secret=mySecretKeyForJWTTokenGenerationThatIsAtLeast64CharactersLong123456789012345678901234 ``` ### 关键问题解决说明 #### 问题原因分析 1. **Bean 未定义**: - `SecurityConfig` 的构造函数需要 `JwtAuthenticationFilter` Bean - Spring 容器中找不到该 Bean 的实例 2. **Bean 创建方式错误**: - 过滤器未使用 `@Component` 注解标记 - 未在配置类中显式定义 `@Bean` 方法 3. **依赖注入问题**: - 过滤器可能需要依赖项(如 JWT 密钥) - Spring 无法自动注入这些依赖项 #### 解决方案要点 1. **显式 Bean 定义**: ```java @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); } ``` 2. **组件扫描**: - 确保 `@Component` 注解在过滤器类上 - 确认包路径在 Spring 扫描范围内 3. **依赖注入**: ```java @Value("${jwt.secret}") private String jwtSecret; ``` 4. **过滤器链集成**: ```java .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) ``` ### 完整的安全配置最佳实践 #### 1. JWT 工具类 ```java // src/main/java/com/org/example/tools/security/JwtUtils.java package com.org.example.tools.security; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @Component public class JwtUtils { @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); claims.put("roles", userDetails.getAuthorities()); return createToken(claims, userDetails.getUsername()); } private String createToken(Map<String, Object> claims, String subject) { SecretKey key = Keys.hmacShaKeyFor(secret.getBytes()); return Jwts.builder() .setClaims(claims) .setSubject(subject) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + expiration)) .signWith(key, SignatureAlgorithm.HS256) .compact(); } public Boolean validateToken(String token, UserDetails userDetails) { final String username = extractUsername(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } public String extractUsername(String token) { return extractClaim(token, Claims::getSubject); } public Date extractExpiration(String token) { return extractClaim(token, Claims::getExpiration); } private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) { final Claims claims = extractAllClaims(token); return claimsResolver.apply(claims); } private Claims extractAllClaims(String token) { SecretKey key = Keys.hmacShaKeyFor(secret.getBytes()); return Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) .getBody(); } private Boolean isTokenExpired(String token) { return extractExpiration(token).before(new Date()); } } ``` #### 2. 认证控制器 ```java // src/main/java/com/org/example/tools/controller/AuthController.java package com.org.example.tools.controller; import com.org.example.tools.dto.request.LoginRequest; import com.org.example.tools.dto.response.ApiResponse; import com.org.example.tools.dto.response.JwtResponse; import com.org.example.tools.security.JwtUtils; import com.org.example.tools.security.UserDetailsImpl; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/auth") @RequiredArgsConstructor public class AuthController { private final AuthenticationManager authenticationManager; private final JwtUtils jwtUtils; @PostMapping("/login") public ApiResponse<JwtResponse> authenticateUser(@RequestBody LoginRequest loginRequest) { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken( loginRequest.getUsername(), loginRequest.getPassword() ) ); SecurityContextHolder.getContext().setAuthentication(authentication); UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); String jwt = jwtUtils.generateToken(userDetails); return ApiResponse.success(new JwtResponse( jwt, userDetails.getId(), userDetails.getUsername(), userDetails.getEmail(), userDetails.getAuthorities() )); } } ``` #### 3. 配置属性 ```properties # src/main/resources/application.properties jwt.secret=mySuperSecretKeyThatIsLongEnoughForHS512Algorithm1234567890 jwt.expiration=86400000 # 24小时 ``` ### 常见问题排查 1. **Bean 仍然缺失**: - 检查 `JwtAuthenticationFilter` 是否在组件扫描路径中 - 确认没有多个 `SecurityConfig` 类冲突 2. **JWT 解析错误**: ```java // 使用正确的密钥长度 @Value("${jwt.secret}") private String jwtSecret; // 至少 64 字符 ``` 3. **过滤器顺序问题**: ```java // 确保在 UsernamePasswordAuthenticationFilter 之前 .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) ``` 4. **依赖冲突**: ```xml <!-- 检查 pom.xml 中的依赖 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值