使用JAXB读取XML文件时出现Servlet实例化HTTP 500错误求助
问题描述
使用JAXB创建XML文件后,在Servlet中读取该文件时报HTTP 500错误,错误提示为Error instantiating servlet class(Servlet类实例化错误),调试后无法定位问题,需要排查XML读取逻辑及相关配置问题。
报错截图


1. Servlet代码
import java.io.*; import java.util.List; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.xml.sax.SAXParseException; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; @WebServlet public class HelloServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException { try { PrintWriter out = response.getWriter(); if(request.getParameter("name").equals("lol")){ out.println("servlet working"); } File file = new File("mvs.xml"); JAXBContext jaxbContext = JAXBContext.newInstance(Movie.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); Movie m= (Movie) jaxbUnmarshaller.unmarshal(file); System.out.println(m.getFilm()); out.println("Movies : "); List<movieINFO> list=m.getFilm(); for(movieINFO mINFO:list) out.println(mINFO.getId()+" "+mINFO.getMovieName()+" " +mINFO.getDirector()+" "+mINFO.getReleaseDate() +" "+mINFO.getTrailer()); } catch (JAXBException e) { e.printStackTrace(); } } }
2. web.xml配置
<?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"> <servlet> <servlet-name>getMovie</servlet-name> <servlet-class>com.example.q1.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>getMovie</servlet-name> <url-pattern>/movieName</url-pattern> </servlet-mapping> </web-app>
3. index.jsp代码
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <title>Movie List</title> </head> <body> <form action="movieName" method="post"> <h1>Movie List</h1> <input placeholder="movie name" type="text" name="name"> <input type="submit" value="Submit"> </form> </body> </html>
4. 待读取XML文件内容
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <movie> <film id="10"> <director>Matthias Schweighöfer</director> <genre>Comedy/Action</genre> <movieName>Army of Thieves</movieName> <releaseDate>29/10/2021</releaseDate> <trailer>https://www.youtube.com/watch?v=Ith2WetKXlg</trailer> </film> <film id="11"> <director> Denis Villeneuve</director> <genre>Sci-Fi/Adventure</genre> <movieName>Dune</movieName> <releaseDate>16/09/2021</releaseDate> <trailer>https://www.youtube.com/watch?v=n9xhJrPXop4</trailer> </film>
问题排查与修复方案
1. 修复Servlet实例化失败问题
- 你同时使用了
@WebServlet注解和web.xml配置Servlet,二者冲突是实例化失败的核心原因,二选一即可:要么删除类上的@WebServlet注解,保留web.xml配置;要么删除web.xml里的servlet和servlet-mapping配置,给@WebServlet加上urlPatterns属性:@WebServlet("/movieName") - 核对HelloServlet的包路径是否和web.xml里配置的
com.example.q1.HelloServlet完全一致,包名拼写错误也会导致类找不到,实例化失败。 - 检查依赖兼容性:你用的是Jakarta EE 9+的Servlet包(jakarta.servlet开头),如果使用低版本JAXB(javax.xml.bind开头)会出现类加载冲突,替换为Jakarta兼容的JAXB实现即可,Maven项目参考依赖如下:
<dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>3.0.1</version> <scope>runtime</scope> </dependency>
2. 修复XML读取逻辑问题
- 原代码用相对路径
new File("mvs.xml")读取文件,Servlet运行时的工作目录是应用服务器的启动目录,不是项目资源目录,必然找不到文件。正确做法是把mvs.xml放到项目的WEB-INF/classes目录下,用ServletContext读取资源:
// 替换原File文件读取逻辑 InputStream is = getServletContext().getResourceAsStream("/mvs.xml"); Movie m= (Movie) jaxbUnmarshaller.unmarshal(is);
- 补全XML文件的根节点闭合标签
</movie>,否则XML格式错误会直接导致反序列化失败。 - 检查
Movie、movieINFO实体类的JAXB注解配置:Movie类要加@XmlRootElement(name = "movie"),存储film集合的字段要加@XmlElement(name = "film"),实体属性名要和XML节点名对应,否则反序列化会报错。 - 对请求参数做空判断,避免用户未输入内容直接提交触发空指针异常:
String name = request.getParameter("name"); if("lol".equals(name)){ out.println("servlet working"); }
内容的提问来源于stack exchange,提问作者Alex Alecco
相关产品推荐
相关产品推荐

