Spring Boot应用启动正常但Postman请求返回404求助
Spring Boot通讯录应用部署Tomcat后接口404问题
我开发了一款Spring Boot通讯录管理应用,部署到Tomcat服务器后,用Postman请求接口返回404错误。以下是项目代码:
Application类
package com.project.phone.phonebook; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Phone控制器
package com.project.phone.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.project.phone.Entity.PhoneRecord; import com.project.phone.Service.PhoneService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @RestController // 等同于@Controller + @ResponseBody @RequestMapping("phone/api/phone") public class PhoneController { @Autowired PhoneService phoneService; @GetMapping("/start") public String getMethodName() { return "start"; } @GetMapping(value ="/getAll", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<PhoneRecord>> getAllRecords(){ List<PhoneRecord> listOfRecords= phoneService.getAllRecords(); return (ResponseEntity<List<PhoneRecord>>) listOfRecords; } @PostMapping(value = "/save", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<PhoneRecord> saveRecord(@RequestBody PhoneRecord phone){ PhoneRecord newPhone= phoneService.saveNewRecord(phone); return new ResponseEntity<>(newPhone, HttpStatus.CREATED); } }
PhoneService服务类
package com.project.phone.Service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.project.phone.Entity.PhoneRecord; import com.project.phone.Repository.PhoneRepo; @Component public class PhoneService { @Autowired PhoneRepo phoneRepo; public List<PhoneRecord> getAllRecords(){ List<PhoneRecord> phoneRecords = phoneRepo.getAll(); return phoneRecords; } public PhoneRecord saveNewRecord(PhoneRecord phone) { PhoneRecord pRecord = phoneRepo.save(phone); return pRecord; } }
PhoneRepo仓库类
package com.project.phone.Repository; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import com.project.phone.Entity.PhoneRecord; @Repository public interface PhoneRepo extends JpaRepository<PhoneRecord, Integer> { public List<PhoneRecord> getAll(); @SuppressWarnings("unchecked") public PhoneRecord save(PhoneRecord phone); }
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.3.3</version> <relativePath/> <!-- 从仓库查找父依赖 --> </parent> <groupId>com.project.phoneBook</groupId> <artifactId>demo.phonebook</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo.phonebook</name> <description>phone book project for spring</description> <url/> <licenses> <license/> </licenses> <developers> <developer/> </developers> <scm> <connection/> <developerConnection/> <tag/> <url/> </scm> <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-web</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
问题排查与修复方案
- 修正组件扫描范围
Application类所在包com.project.phone.phonebook与控制器、服务等组件的包com.project.phone不在同一层级,@SpringBootApplication默认仅扫描当前包及其子包,导致控制器未被注册。
- 方案一:将Application类的包修改为
com.project.phone。 - 方案二:在
@SpringBootApplication注解中添加扫描路径:
@SpringBootApplication(scanBasePackages = "com.project.phone")
- 修复控制器返回类型错误
getAllRecords方法中直接将List强转为ResponseEntity会抛出类型转换异常,正确写法:
@GetMapping(value ="/getAll", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<PhoneRecord>> getAllRecords(){ List<PhoneRecord> listOfRecords= phoneService.getAllRecords(); return ResponseEntity.ok(listOfRecords); }
- 配置外部Tomcat部署的war包格式
Spring Boot默认生成jar包,部署到外部Tomcat需改为war包:
- 在pom.xml中添加
<packaging>war</packaging>(在<version>标签后)。 - 添加Tomcat依赖为provided:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency>
- 修改Application类继承
SpringBootServletInitializer:
public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
修正接口访问路径
部署到Tomcat后,接口路径需包含项目上下文路径(即war包名称,如demo.phonebook-0.0.1-SNAPSHOT),完整示例路径:http://localhost:8080/demo.phonebook-0.0.1-SNAPSHOT/phone/api/phone/start清理Repository冗余方法
JpaRepository已内置findAll()和save()方法,无需自行声明。删除PhoneRepo中的getAll()和save()方法,修改PhoneService:
public List<PhoneRecord> getAllRecords(){ return phoneRepo.findAll(); }
- 规范Service注解
将PhoneService的@Component替换为@Service,符合Spring分层架构规范:
@Service public class PhoneService { // ... 原有代码 }
内容的提问来源于stack exchange,提问作者Ankit Rege
相关产品推荐
相关产品推荐

