Получить XML в виде обычного текста

У меня есть конечная точка для 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;
    }
}

Но в консоль ничего не печатается. Есть идеи, где я ошибаюсь? Возможно этот компонент не зарегистрирован?


person Peter Penzov    schedule 23.11.2018    source источник
comment
Я думаю, ваш перехватчик работает некорректно. В любом случае, я думаю, что использовать перехватчик для регистрации - это немного излишне. Вы уверены, что это то, что вам нужно?   -  person Andrei Ciobanu    schedule 25.11.2018
comment
Вы действительно хотите, чтобы запрос был простым текстом или вы просто хотите преобразовать или иным образом преобразовать xml? Если вы хотите получать в виде обычного текста, вы не сможете парализовать XML или использовать какие-либо соглашения по сравнению с преимуществами конфигурации использования XML, не получая его в виде текста, затем конвертируя его в XML, а затем обратно в текст. Прошу просто уточнить. Вы также можете предоставить образец запроса   -  person Chris Maggiulli    schedule 25.11.2018
comment
@ChrisMaggiulli Я хочу регистрировать все. Не только XML, но и попытки запроса. Подскажите, как это реализовать?   -  person Peter Penzov    schedule 25.11.2018
comment
Вы смотрели этот старый ответ? Похоже, он отвечает примерно на тот же вопрос.   -  person DavidW    schedule 28.11.2018
comment
Вы забыли добавить перехватчик в interceptors list   -  person Shiva    schedule 02.12.2018


Ответы (5)


Разве это не должно быть легко, как показано ниже, получить его из 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);
}
person Red Boy    schedule 25.11.2018
comment
Но я получаю java.lang.IllegalStateException: UT010004: невозможно вызвать getReader (), getInputStream () уже вызван - person Peter Penzov; 25.11.2018
comment
@PeterPenzov Простите, плохо, только что тестировал, нужно убрать @RequestBody PaymentTransaction transaction из подписи. - person Red Boy; 25.11.2018
comment
Да, но я хотел бы также получить XML-объект PaymentTransaction. Здесь мне нужно получить объект XML, а также в отдельной переменной String содержимое запроса. Наверное, мне нужно использовать перехватчик? - person Peter Penzov; 25.11.2018
comment
Из XML вы также можете получить PaymentTransaction, но здесь Spring не поможет вам напрямую с аннотациями. Даже если вы хотите, я могу показать вам, как преобразовать XML в PaymentTransaction Object? - person Red Boy; 25.11.2018
comment
Можете сначала показать мне, как правильно реализовать ClientHttpRequestInterceptor? - person Peter Penzov; 25.11.2018
comment
@PeterPenzov Извините, я никогда не реализовывал это, поэтому не в курсе. На мой взгляд, для вашего использования, я не думаю, что это необходимо, но если ваш звонок, вы можете подождать, пока другие ответят. Удачного кодирования. - person Red Boy; 25.11.2018
comment
хорошо, вы можете показать мне, как преобразовать объект PaymentTransaction в XML? - person Peter Penzov; 25.11.2018
comment
Я получаю java.lang.IllegalStateException: UT010004: невозможно вызвать getReader (), getInputStream () уже вызван - person Peter Penzov; 16.01.2019
comment
Думаю, это был ваш самый первый комментарий, и он был решен в текущем фрагменте кода. - person Red Boy; 16.01.2019

У нас была такая же проблема, и мы используем это решение в продакшене. Это не зависит от фреймворка (в моей книге это всегда положительный момент) и просто.

Просто используйте его, не указывая его как 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.

person Urosh T.    schedule 26.11.2018
comment
У меня вызвано: java.io.IOException: UT010029: поток закрыт - person Peter Penzov; 16.01.2019
comment
Не могли бы вы поделиться конечной частью XML-строки? - person Urosh T.; 16.01.2019
comment
Кроме того, в этой трассировке стека должно быть что-то еще, верно? - person Urosh T.; 16.01.2019

Чтобы ваш контроллер получал тело запроса в виде простой строки 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.

person Community    schedule 29.11.2018
comment
Да, но мне также нужен проанализированный объект и XML в виде строки. Я пробовал оба, но не работает. - person Peter Penzov; 29.11.2018

Мы довольно давно используем spring-mvc-logger в производстве. Он написан как фильтр сервлета, поэтому может быть добавлен в качестве независимой оболочки к конечной точке MVC.

Наша настройка почти такая же, как описано на readme.md там, хотя мы ограничиваем <url-pattern> под <filter-mapping> только полезными конечными точками.

Даже если это не совсем то, что вам нужно, кодовая база там представляет собой довольно хороший небольшой пример. В частности, обратите внимание на упаковку запроса / ответа, которая необходима в фильтре. (Это сделано для того, чтобы избежать IllegalStateException: getReader(), getInputStream() already called, которое могло бы произойти, если бы getReader() был вызван дважды).

person df778899    schedule 01.12.2018

Вы создали 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;
    } 
 ...
}

Надеюсь, это поможет

person Shiva    schedule 02.12.2018