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

Payara部署Jakarta EE项目POST访问REST API返回404问题

404错误根本原因

所有REST接口未被JAX-RS容器正确注册、路径映射存在多层冲突,核心问题按影响优先级排序:

  • 资源类未加载:ApplicationConfig重写了getClasses()方法,但负责添加资源类的addRestResourceClasses()是空实现,ApiResource未被加入JAX-RS资源集合,所有端点不会被初始化。
  • web.xml中JAX-RS配置完全错误:
    1. 错将静态资源默认Servlet org.apache.catalina.servlets.DefaultServlet 配置为JAX-RS调度Servlet,该Servlet仅处理静态文件,不会识别JAX-RS注解和请求。
    2. 路径规则冲突:同时通过@ApplicationPath("rest")定义应用根路径、web.xml配置/rest/api/*映射、ApiResource定义@Path("api"),三层路径叠加后规则混乱,无法匹配到正确端点。
    3. 命名空间不兼容:初始化参数使用旧Java EE时代的javax.ws.rs.Application,新版Payara基于Jakarta EE,正确参数名为jakarta.ws.rs.Application,即使Servlet配置正确也无法识别应用类。

修复步骤

1. 修正JAX-RS基础配置(二选一即可,推荐纯注解配置)

方案A:纯注解配置(无多余配置,兼容性最好)

  • 删除web.xml中整个<servlet>和<servlet-mapping>节点,仅保留<session-config>部分即可,JAX-RS会自动扫描@ApplicationPath注解完成启动。
  • 修改ApplicationConfig类,删除重写的getClasses()和空实现的addRestResourceClasses()方法,容器会自动扫描所有带@Path注解的资源类完成注册:
@ApplicationPath("rest")
public class ApplicationConfig extends Application {
    // 不需要重写任何方法
}

方案B:保留web.xml配置

  • 删除ApplicationConfig类上的@ApplicationPath("rest")注解。
  • 替换web.xml中错误的Servlet配置,使用JAX-RS官方Servlet、修正参数名和映射路径:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
    <servlet>
        <servlet-name>jakarta.ws.rs.core.Application</servlet-name>
        <init-param>
            <param-name>jakarta.ws.rs.Application</param-name>
            <param-value>com.apps.io.webservice.ApplicationConfig</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jakarta.ws.rs.core.Application</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>
  • 同样删除ApplicationConfig中重写的getClasses()方法,让容器自动扫描资源类。

2. 确认正确访问路径

配置修正后,接口完整路径结构为:http://<Payara地址>:<端口>/<应用上下文根>/rest/api/<方法路径>
例如创建用户的POST请求地址为:http://localhost:8080/io_user_management_war_1.0-SNAPSHOT/rest/api/createUser

应用上下文根默认和war包文件名一致,可在Payara管理控制台手动修改。

3. 清理无效代码

删除ApiResource类中@POST注解后多余的乱码`enter code here`,避免编译异常。

非404类前置修复(接口通了也会报错,必须改)

这些问题不会导致404,但会让接口在调用时抛出运行时异常,一并修复:

  1. JPA配置兼容问题
    现有persistence.xml使用JPA 1.0版本规范,和Jakarta EE不兼容,替换根节点为Jakarta JPA 3.0配置,同时将事务类型改为容器支持的JTA(适配@Transactional注解):
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="3.0" xmlns="https://jakarta.ee/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
      <persistence-unit name="com.apps.io_user_management_war_1.0-SNAPSHOTPU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
          <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver" />
          <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:target/h2-2" />
          <property name="jakarta.persistence.jdbc.user" value="sa" />
          <property name="jakarta.persistence.jdbc.password" value="" />
          <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
          <property name="eclipselink.ddl-generation.output-mode" value="database" />
        </properties>
      </persistence-unit>
    </persistence>
    
    同时修改UserService类,不要手动创建线程不安全的EntityManagerFactory和EntityManager,改用容器注入:
    @ApplicationScoped
    @Transactional
    public class UserService {
        @PersistenceContext
        private EntityManager entityManager;
        // 删除手动初始化emf、entityManager的代码
    
        public List<User> getAllUsers() {
            return entityManager.createQuery("SELECT c FROM User c", User.class).getResultList();
        }
    
        public User createUser(User user) {
            entityManager.persist(user);
            return user;
        }
    
        public User getUser(String email) {
            TypedQuery<User> query = entityManager.createQuery("SELECT e FROM User e WHERE e.email = :email", User.class);
            query.setParameter("email", email);
            return query.getSingleResult();
        }
    
        public User updateUser(User user) {
            entityManager.merge(user);
            return user;
        }
    }
    
  2. JPQL语法错误
    现有JPQL中写的FROM user是错误的:JPQL使用实体类名(首字母大写User)而非数据库表名,同时user是H2数据库保留关键字,所有JPQL中表名位置替换为User即可。
  3. 实体表名冲突
    User实体类配置的表名user是H2保留关键字,修改为非保留字:
    @Entity
    @Table(name = "app_user")
    public class User {
        // 其余代码不变
    }
    

内容的提问来源于stack exchange,提问作者Uchenna Ugwu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 01:12:26