Payara部署Jakarta EE项目POST访问REST API返回404问题
404错误根本原因
所有REST接口未被JAX-RS容器正确注册、路径映射存在多层冲突,核心问题按影响优先级排序:
- 资源类未加载:
ApplicationConfig重写了getClasses()方法,但负责添加资源类的addRestResourceClasses()是空实现,ApiResource未被加入JAX-RS资源集合,所有端点不会被初始化。 - web.xml中JAX-RS配置完全错误:
- 错将静态资源默认Servlet
org.apache.catalina.servlets.DefaultServlet配置为JAX-RS调度Servlet,该Servlet仅处理静态文件,不会识别JAX-RS注解和请求。 - 路径规则冲突:同时通过
@ApplicationPath("rest")定义应用根路径、web.xml配置/rest/api/*映射、ApiResource定义@Path("api"),三层路径叠加后规则混乱,无法匹配到正确端点。 - 命名空间不兼容:初始化参数使用旧Java EE时代的
javax.ws.rs.Application,新版Payara基于Jakarta EE,正确参数名为jakarta.ws.rs.Application,即使Servlet配置正确也无法识别应用类。
- 错将静态资源默认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,但会让接口在调用时抛出运行时异常,一并修复:
- 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; } } - JPQL语法错误
现有JPQL中写的FROM user是错误的:JPQL使用实体类名(首字母大写User)而非数据库表名,同时user是H2数据库保留关键字,所有JPQL中表名位置替换为User即可。 - 实体表名冲突
User实体类配置的表名user是H2保留关键字,修改为非保留字:@Entity @Table(name = "app_user") public class User { // 其余代码不变 }
内容的提问来源于stack exchange,提问作者Uchenna Ugwu
相关产品推荐
相关产品推荐

