Get XML in plain text

喜你入骨 提交于 2019-12-14 03:43:44

问题


I have this endpoint for 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 model.

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

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

How I can get the XML request in plain XML text?

I also tried with Spring interceptor: I tried this code:

@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 for logging:

@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;
    }
}

But nothing is printed into the console. Any idea where I'm wrong? Probably this component is not registered?


回答1:


Shouldn't it be easy like below to get it from HttpServletRequest, unless I'm missing something. I don't think there is need to use interceptor etc.

@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);
}



回答2:


We had the same issue and use this solution in production. Which is not framework dependent (always an upside in my book) and simple.

Just consume it without specifying it as an XML. Then read the request lines and join them by \n if you want to have new lines in your xml. If not, join them by "" or whatever you please. This presumes you are using the javax.servlet.http.HttpServletRequest

Example:

@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

}

And you have an plain xml string.




回答3:


For your controller to receive the request body as a plain xml string, you need only change the @RequestBody parameter type to 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 {
    ...

With the above mapping, if the client has submitted xml, you'll see the raw XML. Otherwise, if the client has submitted json, you'll see the raw JSON. Make sure you check the request's "Content-Type" header to know which type you're dealing with.

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




回答4:


We've been using the spring-mvc-logger in production for quite a while. It's written as a servlet filter, so can be added as an independent wrapper to the MVC endpoint.

Our set up is almost exactly like described on the readme.md there, though we restrict the <url-pattern> under the <filter-mapping> to just the useful endpoints.

Even if it's not exactly what you're after, the codebase there makes quite a nice small example. In particular note the request/response wrapping that is needed in the filter. (This is to avoid the IllegalStateException: getReader(), getInputStream() already called that would otherwise happen if getReader() were called twice).




回答5:


You have created List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(); but did not add the RestTemplateHeaderModifierInterceptor object to it.

You can autowire in the same in Application like below:

@Autowired 
ClientHttpRequestInterceptor clientHttpRequestInterceptor;

and

interceptors.add(clientHttpRequestInterceptor);

The code looks like below:

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;
    } 
 ...
}

Hope it helps



来源:https://stackoverflow.com/questions/53450695/get-xml-in-plain-text

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!