Spring Boot中@RestController除主类外调用返回404错误问题求助
问题描述
我的项目结构如下:
我通过Postman调用ApartmentController中定义的Get接口时,返回404错误,接口定义代码如下:
@RestController @RequestMapping("/api/apartment") class ApartmentController(private val apartmentService: ApartmentService) { @GetMapping fun getAllApartments(apartment: Apartment): List<Apartment> { return apartmentService.getAllApartments() } @PostMapping fun createApartment(apartment: Apartment): Apartment { return apartmentService.createApartment(apartment) } }
但我将相同逻辑的接口写在启动类LeaderRealEstateApiApplication所在文件中时,调用返回200正常响应,代码如下:
@SpringBootApplication() class LeaderRealEstateApiApplication fun main(args: Array<String>) { runApplication<LeaderRealEstateApiApplication>(*args) } @RestController @RequestMapping("/api/apartments") class TestResource(private val apartmentService: ApartmentService) { @GetMapping fun test(): List<Apartment> { return apartmentService.getAllApartments() } }
我已经尝试在@SpringBootApplication注解中添加scanBasePackages配置:@SpringBootApplication(scanBasePackages = ["com.leaderrealestate"]) ,但问题依然存在,请问是什么原因导致的?该如何解决?
问题原因及解决方案
核心原因
404报错说明ApartmentController没有被Spring容器成功注册为Bean,对应的接口路径没有被系统映射,本质是类扫描/Bean注册失败导致,常见原因如下:
- Kotlin类默认final导致代理失败
如果项目中没有引入kotlin-spring(spring-all-open)插件,Kotlin定义的类默认是final类型,Spring无法为@RestController这类注解的类生成代理对象,就会导致Bean注册失败。和启动类写在同一个文件的TestResource能正常工作,是因为Spring Boot对启动类同文件的类有特殊的扫描和处理逻辑。 - 包扫描路径配置不匹配
即使配置了scanBasePackages = ["com.leaderrealestate"],如果ApartmentController没有放在com.leaderrealestate包或者它的子包下,依然无法被扫描到,比如把Controller放在com.other这类和配置路径无关的包下就会失效。 - 注解导包错误
@RestController、@RequestMapping等注解导错了包,比如导入了Jersey或者其他框架的同名注解,Spring无法识别。 - 接口路径拼写错误
ApartmentController的映射路径是/api/apartment(单数),而测试用的TestResource路径是/api/apartments(复数),如果调用时误把带s的路径用在前者上也会返回404。
解决步骤
- 优先检查
kotlin-spring插件配置:
如果你用Gradle,在build.gradle.kts中添加以下配置:
如果你用Maven,在pom.xml中添加:plugins { id("org.springframework.boot") version "你的Spring Boot版本" id("io.spring.dependency-management") version "对应依赖管理版本" kotlin("jvm") version "你的Kotlin版本" kotlin("plugin.spring") version "你的Kotlin版本" // 核心是添加这个插件 }
不想加插件的话也可以手动给<build> <plugins> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <version>${kotlin.version}</version> <executions> <execution> <id>compile</id> <goals> <goal>compile</goal> </goals> <configuration> <args> <arg>-Xjsr305=strict</arg> </args> <compilerPlugins> <plugin>spring</plugin> <!-- 开启spring插件 --> </compilerPlugins> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-allopen</artifactId> <version>${kotlin.version}</version> </dependency> </dependencies> </plugin> </plugins> </build>ApartmentController类和方法加open关键字:@RestController @RequestMapping("/api/apartment") open class ApartmentController(private val apartmentService: ApartmentService) { @GetMapping open fun getAllApartments(apartment: Apartment): List<Apartment> { return apartmentService.getAllApartments() } } - 检查
ApartmentController的包路径,确认它确实在com.leaderrealestate包及其子包下,正确路径示例:com.leaderrealestate.controller.ApartmentController。 - 核对注解的导包,确保所有Spring Web注解都来自
org.springframework.web.bind.annotation包。 - 调用时确认路径是
GET /api/apartment(不带s),和ApartmentController配置的路径一致。
内容的提问来源于stack exchange,提问作者Aldin Muratovic
相关产品推荐
相关产品推荐

