Spring Boot启动报错:上下文无ServletWebServerFactory Bean
Web应用启动失败:上下文未定义
org.springframework.boot.web.servlet.server.ServletWebServerFactory Bean 在为Web应用集成安全功能(添加Utilisateur实体、Role实体及对应仓库,配置Spring Security组件包括AuthEntryPoint、AuthTokenFilter、JwtUtils)后,应用无法启动,报错提示上下文未定义org.springframework.boot.web.servlet.server.ServletWebServerFactory Bean。我已在Stack Overflow搜索类似问题,但所有解决方案均无效,现专注排查该特定问题原因,恳请协助。
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.IsoShift</groupId> <artifactId>Backend</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Backend</name> <description>Backend</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> </dependency> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> </dependency> <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> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.16.0</version> </dependency> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc11</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>21</source> <target>21</target> <compilerArgs>--enable-preview</compilerArgs> </configuration> </plugin> </plugins> </build> </project>
主类文件BackendApplication.java
package com.isoshift.backend; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @SpringBootApplication public class BackendApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(BackendApplication.class, args); } }
WebSecurityConfig.java
package com.isoshift.backend.security; import com.isoshift.backend.security.jwt.AuthEntryPointJwt; import com.isoshift.backend.security.jwt.AuthTokenFilter; import com.isoshift.backend.security.service.UserDetailsServiceImpl; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 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 @EnableMethodSecurity // Spring Boot 3 public class WebSecurityConfig { @Autowired UserDetailsServiceImpl userDetailsService; @Autowired private AuthEntryPointJwt unauthorizedHandler; @Bean public AuthTokenFilter authenticationJwtTokenFilter() { return new AuthTokenFilter(); } @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); authProvider.setUserDetailsService(userDetailsService); authProvider.setPasswordEncoder(passwordEncoder()); return authProvider; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth.requestMatchers("/api/v1/auth/**").permitAll() .requestMatchers("/api/test/**").permitAll() .anyRequest().authenticated() ); http.authenticationProvider(authenticationProvider()); http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } }
AuthController.java
package com.isoshift.backend.Controleur; import com.isoshift.backend.payload.request.LoginRequest; import com.isoshift.backend.payload.request.SignupRequest; import com.isoshift.backend.payload.response.JwtResponse; import com.isoshift.backend.payload.response.MessageResponse; import com.isoshift.backend.Entity.Role; import com.isoshift.backend.Entity.Utilisateur; import com.isoshift.backend.Service.Constant.ERole; import com.isoshift.backend.repository.RoleRepo; import com.isoshift.backend.repository.UtilisateurRepo; import com.isoshift.backend.security.jwt.JwtUtils; import com.isoshift.backend.security.service.UserDetailsImpl; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; 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.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @CrossOrigin(origins = "*", maxAge = 3600) @RestController @RequestMapping("/api/v1/auth") public class AuthController { @Autowired AuthenticationManager authenticationManager; @Autowired UtilisateurRepo userRepository; @Autowired RoleRepo roleRepository; @Autowired PasswordEncoder encoder; @Autowired JwtUtils jwtUtils; @PostMapping("/signin") public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())); SecurityContextHolder.getContext().setAuthentication(authentication); String jwt = jwtUtils.generateJwtToken(authentication); UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); List<String> roles = userDetails.getAuthorities().stream() .map(item -> item.getAuthority()) .collect(Collectors.toList()); return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getUsername(), roles)); } @PostMapping("/signup") public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signUpRequest) { int matEmpInt = 0; try { matEmpInt = Integer.parseInt(signUpRequest.getMATEMP()); } catch (NumberFormatException e) { e.printStackTrace(); } if (userRepository.existsByMATEMP(matEmpInt)) { return ResponseEntity .badRequest() .body(new MessageResponse("Error: Username is already taken!")); } // Create new user's account Utilisateur user = new Utilisateur(matEmpInt, encoder.encode((signUpRequest.getNOMEMP() + signUpRequest.getPRNEMP()))); Set<String> strRoles = signUpRequest.getRole(); Set<Role> roles = new HashSet<>(); if (strRoles == null) { Role userRole = roleRepository.findByName(ERole.Role_utilisateur) .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); roles.add(userRole); } else { strRoles.forEach(role -> { if (role.equals("admin")) { Role adminRole = roleRepository.findByName(ERole.Role_admin) .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); roles.add(adminRole); } else { Role userRole = roleRepository.findByName(ERole.Role_utilisateur) .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); roles.add(userRole); } }); } user.setRoles(roles); userRepository.save(user); return ResponseEntity.ok(new MessageResponse("User registered successfully!")); } }
问题排查与解决方案
添加Web核心依赖
pom.xml中缺失spring-boot-starter-web依赖,这是Spring Boot Web应用的核心依赖,包含ServletWebServerFactory的自动配置逻辑。添加以下依赖到<dependencies>块:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>统一Java版本配置
pom.xml中<java.version>设为17,但maven-compiler-plugin的source/target设为21,版本不匹配会导致类加载异常。修改插件配置统一版本:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>${java.version}</source> <target>${java.version}</target> <!-- 移除--enable-preview,除非明确需要预览特性 --> </configuration> </plugin>移除重复Servlet依赖
单独引入的jakarta.servlet-api会与spring-boot-starter-web自带的适配版本冲突,建议删除该依赖。简化主类配置
若以JAR包方式运行,无需继承SpringBootServletInitializer(仅WAR部署到外部容器时需要),可简化主类:@SpringBootApplication public class BackendApplication { public static void main(String[] args) { SpringApplication.run(BackendApplication.class, args); } }
内容的提问来源于stack exchange,提问作者Firas Chebbi
相关产品推荐
相关产品推荐

