如何编写可同时接收解析XML与JSON请求的Servlet程序?
Servlet同时支持JSON/XML请求及分支判断问题修复
一、Content-Type分支无法进入的问题修复
两个分支无法匹配的核心原因有两个:
- 字符串比较逻辑错误:Java中字符串内容比较必须使用
equals()方法,==对比的是字符串对象的内存地址,请求头返回的字符串和常量字符串内存地址不同,永远返回false - Content-Type存在附加参数:实际请求的Content-Type通常会携带编码等后缀,例如
application/json;charset=utf-8,直接全等匹配会失败,推荐使用contains()方法模糊匹配,或者直接调用Servlet原生的getContentType()方法简化获取
修复后的判断逻辑参考:
// 先获取content-type,统一转小写避免大小写问题 String contentType = request.getContentType() == null ? "" : request.getContentType().toLowerCase(); ObjectMapper objectMapper = new ObjectMapper(); if (contentType.contains("application/json")) { System.out.println("json "); Symbol symbolContainerFromJson = objectMapper.readValue(request.getReader(), Symbol.class); System.out.println(symbolContainerFromJson.getSymbol()); } else if (contentType.contains("application/xml")) { System.out.println("xml"); Symbol symbolContainerFromXml = new XmlMapper().readValue(request.getReader(), Symbol.class); System.out.println(symbolContainerFromXml.getSymbol()); } else { // 不支持的媒体类型返回415状态码 response.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); return; }
二、完整的JSON/XML请求兼容实现
前置依赖
如果使用Jackson做序列化/反序列化,需要引入XML支持包(Maven示例):
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.15.2</version> <!-- 和你使用的jackson-databind版本保持一致即可 --> </dependency>
定义参数接收实体类
import jakarta.xml.bind.annotation.XmlRootElement; import lombok.Data; @Data // Lombok注解,自动生成get/set方法,也可以手动编写 @XmlRootElement // XML序列化必须的根节点注解 public class Symbol { private List<String> Symbol; // 手动编写get/set示例 // public List<String> getSymbol() { return Symbol; } // public void setSymbol(List<String> symbol) { Symbol = symbol; } }
对应XML请求格式示例:
<Symbol> <Symbol>OLM</Symbol> <Symbol>ASC</Symbol> </Symbol>
完整doPost实现
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); // 先把请求体缓存为字符串,避免输入流只能读取一次的问题 BufferedReader reader = request.getReader(); StringBuilder bodySb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { bodySb.append(line); } String requestBody = bodySb.toString(); String contentType = request.getContentType() == null ? "" : request.getContentType().toLowerCase(); ObjectMapper jsonMapper = new ObjectMapper(); XmlMapper xmlMapper = new XmlMapper(); Symbol symbolContainer = null; try { if (contentType.contains("application/json")) { symbolContainer = jsonMapper.readValue(requestBody, Symbol.class); } else if (contentType.contains("application/xml")) { symbolContainer = xmlMapper.readValue(requestBody, Symbol.class); } else { response.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); response.getWriter().write("仅支持application/json和application/xml格式的请求"); return; } } catch (Exception e) { e.printStackTrace(); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.getWriter().write("请求体格式解析失败,请检查格式是否正确"); return; } // 后续业务逻辑,直接从symbolContainer获取Symbol列表即可 List<String> symbolList = symbolContainer.getSymbol(); // 其他业务处理... }
注意事项
- 实体类的属性名要和请求里的键名完全一致,比如JSON里的键是
Symbol,实体类的属性名也要是Symbol,如果要自定义名称可以加@JsonProperty(JSON场景)和@JacksonXmlProperty(XML场景)注解 - 如果不想用实体类映射,也可以用DOM4J等原生XML解析工具,直接从请求体字符串中提取Symbol标签的内容
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

