将XML转换为纯文本

5

我有一个Spring Rest API的端点:

@PostMapping(value = "/v1/", consumes = { MediaType.APPLICATION_XML_VALUE,
            MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_XML_VALUE,
                    MediaType.APPLICATION_JSON_VALUE })
    public PaymentResponse handleMessage(@RequestBody PaymentTransaction transaction, HttpServletRequest request) throws Exception {

    // get here plain XML  

}

XML模型。
@XmlRootElement(name = "payment_transaction")
@XmlAccessorType(XmlAccessType.FIELD)
public class PaymentTransaction {
    public enum Response {
        failed_response, successful_response
    }

    @XmlElement(name = "transaction_type")
    public String transactionType;
    .........
}

如何以普通XML文本格式获取XML请求?

我还尝试使用Spring拦截器: 我尝试了以下代码:

@SpringBootApplication
@EntityScan("org.plugin.entity")
public class Application extends SpringBootServletInitializer implements WebMvcConfigurer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    ........

    @Bean
    public RestTemplate rsestTemplate() {
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
        RestTemplate restTemplate = new RestTemplate(
                new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
        restTemplate.setInterceptors(interceptors);
        return restTemplate;
    } 
}

日志记录组件:

@Component
public class RestTemplateHeaderModifierInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {

        StringBuilder sb = new StringBuilder();
        sb.append("[ ");
        for (byte b : body) {
            sb.append(String.format("0x%02X ", b));
        }
        sb.append("]");

        System.out.println("!!!!!!!!!!!!!!!");
        System.out.println(sb.toString());      

        ClientHttpResponse response = execution.execute(request, body);

        InputStream inputStream = response.getBody();

        String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

        System.out.println("!!!!!!!!!!!!!!!");
        System.out.println(result);

        return response;
    }
}

但是没有任何内容打印到控制台。我错在哪里了?或许这个组件没有被注册?

我认为你的拦截器没有正常工作。不管怎样,我认为使用拦截器记录日志有点过头了。你确定这是你想要的吗? - Andrei Ciobanu
您实际上想要请求为纯文本,还是只是想转换XML?如果您想以纯文本形式接收,则无法解析XML或使用任何基于约定而非配置的XML优势,除非将其作为文本接收,然后将其转换为XML,再转换回文本。我只是想澄清一下。另外,您能提供一个请求示例吗? - Chris Maggiulli
@ChrisMaggiulli 我想记录所有的东西。不仅仅是XML,还有请求尝试。你能给一些实现的建议吗? - Peter Penzov
你看过这个旧回答吗?它似乎回答了几乎相同的问题。 - DavidW
你忘记将拦截器添加到interceptors列表中了。 - Shiva
5个回答

3
除非我漏掉了什么,否则从HttpServletRequest中获取它应该很容易,就像下面这样。我认为没有必要使用拦截器等。
@PostMapping(value = "/v1/", consumes = { MediaType.APPLICATION_XML_VALUE,
            MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_XML_VALUE,
                    MediaType.APPLICATION_JSON_VALUE })
    public PaymentResponse handleMessage(HttpServletRequest request) throws Exception {

    String str, wholeXML = "";
    try {
        BufferedReader br = request.getReader();
        while ((str = br.readLine()) != null) {
            wholeXML += str;
        }
    System.out.println(wholeXML);
    //Here goes comment question, to convert it into PaymentTransaction
   JAXBContext jaxbContext = JAXBContext.newInstance(PaymentTransaction.class);
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

    StringReader reader = new StringReader(wholeXML);
    PaymentTransaction paymentTransaction = (PaymentTransaction) unmarshaller.unmarshal(reader);
}

但我得到了java.lang.IllegalStateException异常:UT010004:无法调用getReader(),因为已经调用getInputStream()。 - Peter Penzov
1
是的,但我想要获取XML对象PaymentTransaction。在这里,我需要获取XML对象,并且还需要将请求内容放入单独的字符串变量中。可能需要使用拦截器? - Peter Penzov
@PeterPenzov 对不起,我从未实现过这个功能,所以不清楚。就你的使用情况而言,我认为它并不是必需的,但这取决于你自己,你可以等待其他人的回答。祝编码愉快。 - Red Boy
1
好的,你能展示一下如何将PaymentTransaction对象转换成XML吗? - Peter Penzov
我收到了java.lang.IllegalStateException: UT010004: 无法调用getReader(),因为已经调用了getInputStream()。 - Peter Penzov
显示剩余4条评论

0

我们已经在生产环境中使用spring-mvc-logger相当长的时间了。它是作为一个servlet过滤器编写的,因此可以作为独立的包装器添加到MVC端点。

我们的设置几乎与readme.md中描述的完全相同,尽管我们将<filter-mapping>下的<url-pattern>限制为仅有用的端点。

即使它不完全符合您的要求,那里的代码库也是一个很好的小例子。特别要注意在过滤器中需要的请求/响应包装。(这是为了避免IllegalStateException: getReader(), getInputStream() already called,否则如果调用getReader()两次就会发生这种情况)。


0

我们曾经遇到过同样的问题,并在生产中使用了这个解决方案。它不依赖于框架(在我看来总是有好处的),而且非常简单。

只需将其作为非 XML 格式进行消费。然后读取请求行并通过 \n 连接它们,如果您想在 XML 中换行。如果不需要,在连接时可以使用 "" 或其他任何您喜欢的字符。这假定您正在使用 javax.servlet.http.HttpServletRequest

示例:

@PostMapping(value = "/v1")
    public PaymentResponse handleMessage(HttpServletRequest request) throws Exception {

    final InputStream xml = request.getInputStream();
    final String xmlString = new BufferedReader(new InputStreamReader(xml))
          .lines()
          .collect(Collectors.joining("\n"));
   // do whatever you please with it

}

而且你有一个普通的XML字符串。


我遇到了 Caused by: java.io.IOException: UT010029: Stream is closed。 - Peter Penzov
你可以分享一下 XML 字符串的结尾部分吗? - Urosh T.
另外,那个堆栈跟踪肯定还有更多信息,对吗? - Urosh T.

0

如果您希望控制器以纯xml字符串形式接收请求正文,您只需要将 @RequestBody 参数类型更改为 String:

@PostMapping(value = "/v1/", consumes = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE })
public PaymentResponse handleMessage(@RequestBody String xmlOrJson, HttpServletRequest request) throws Exception {
    ...

通过上述映射,如果客户端提交了XML,则您将看到原始的XML。否则,如果客户端提交了JSON,则您将看到原始的JSON。确保检查请求的“Content-Type”标头以了解您正在处理的类型。

请参见https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestbody


是的,但我还需要解析后的对象和XML字符串。我尝试了两种方法,但都不起作用。 - Peter Penzov

0

您已经创建了 List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(); 但是没有将 RestTemplateHeaderModifierInterceptor 对象添加到其中。

您可以像下面这样在 Application 中自动装配它:

@Autowired 
ClientHttpRequestInterceptor clientHttpRequestInterceptor;

interceptors.add(clientHttpRequestInterceptor);

代码如下:

class Application {
...
@Autowired 
ClientHttpRequestInterceptor clientHttpRequestInterceptor;
@Bean
    public RestTemplate rsestTemplate() {
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
        RestTemplate restTemplate = new RestTemplate(
                new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
interceptors.add(clientHttpRequestInterceptor);
        restTemplate.setInterceptors(interceptors);
        return restTemplate;
    } 
 ...
}

希望能有所帮助

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接