You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

问题排查与修复方案

  1. 修正组件扫描范围
    Application类所在包com.project.phone.phonebook与控制器、服务等组件的包com.project.phone不在同一层级,@SpringBootApplication默认仅扫描当前包及其子包,导致控制器未被注册。
  • 方案一:将Application类的包修改为com.project.phone。
  • 方案二:在@SpringBootApplication注解中添加扫描路径:
@SpringBootApplication(scanBasePackages = "com.project.phone")
  1. 修复控制器返回类型错误
    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);
}
  1. 配置外部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);
    }
}
  1. 修正接口访问路径
    部署到Tomcat后,接口路径需包含项目上下文路径(即war包名称,如demo.phonebook-0.0.1-SNAPSHOT),完整示例路径:
    http://localhost:8080/demo.phonebook-0.0.1-SNAPSHOT/phone/api/phone/start

  2. 清理Repository冗余方法
    JpaRepository已内置findAll()和save()方法,无需自行声明。删除PhoneRepo中的getAll()和save()方法,修改PhoneService:

public List<PhoneRecord> getAllRecords(){
    return phoneRepo.findAll();            
}
  1. 规范Service注解
    将PhoneService的@Component替换为@Service,符合Spring分层架构规范:
@Service
public class PhoneService {
    // ... 原有代码
}

内容的提问来源于stack exchange,提问作者Ankit Rege

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:04:59