Разбор текста / html в application / json с помощью RestTemplate в java

#java #spring-boot #rest #spring-mvc

#java #spring-boot #rest #spring-mvc

Вопрос:

Вот мой код:

         HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
        map.add("xx","xx");
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
        ResponseEntity<String> response = new RestTemplate().postForEntity( url, request ,String.class);
  

Вот мой ответ:

  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <body onLoad="xx">
 <form action='xxx' method="post" name="aspForm" >
 <input type="hidden" name="responseMessage" value='Successfully Registered'/>
 <input type="hidden" name="url" value='xxxx'/>
 <input type="hidden" name="status" value='SUCCESS'/>
</form>
</body>
</html>
  

Как преобразовать эти пары имен и значений из html-ответа в JSON?

Комментарии:

1. Почему бы вам не внести изменения в службу, чтобы возвращать json вместо html

2. Это немного «облегченное» объяснение, чтобы полностью понять цель здесь. Если вы пытаетесь отправить JSON String со .html страницы обратно на сервер, к которому вы подключаетесь, существуют сотни ответов SO об отправке JSON от клиента на сервер. Извините, надеюсь, я не кажусь грубым, это не мое намерение… Я не могу точно сказать, какую часть (и где) необходимо преобразовать в ваши данные.

3. Дорогой иностранец, когда я захожу в сторонний API с указанным выше form_url_encoded, я получаю указанный выше HTML-ответ. Мне нужно получить ответ и выполнить некоторые бизнес-операции. Надеюсь, теперь вы поняли.

4. Уважаемый @Y2020-09, приведенное ниже решение — это то, которое я ищу.

Ответ №1:

Этого можно достичь с помощью Jsoup и Jackson object mapper:

 import com.fasterxml.jackson.databind.ObjectMapper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

Document doc = Jsoup.parse(html);
    
    String responseMessage = doc.body()
            .getElementsByAttributeValue("name", "responseMessage")
            .first()
            .attributes()
            .get("value");
    
    String status = doc.body()
            .getElementsByAttributeValue("name", "status")
            .first()
            .attributes()
            .get("value");
    
    String url = doc.body()
            .getElementsByAttributeValue("name", "url")
            .first()
            .attributes()
            .get("value");
    
    Response response = new Response();
    response.setResponseMessage(responseMessage);
    response.setStatus(status);
    response.setUrl(url);
    
    ObjectMapper mapper = new ObjectMapper();
    
    String json = mapper.writeValueAsString(response);
    
    System.out.println(json);
  

Вывод:

 {"responseMessage":"Successfully Registered","status":"SUCCESS","url":"xxxx"}
  

Обновить:

Если необходимо преобразовать строку HTML без ручного вебскрейпинга, это также возможно (но, я полагаю, будет работать только для XHTML, потому что синтаксический анализатор сломается при разметке, не совместимой с XML).

Зависимость от POM:

 <dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.moxy</artifactId>
    <version>2.5.2</version>
    <type>jar</type>
 </dependency>
  

Определение компонента (пропущен getter / setter):

 @XmlRootElement(name = "html")
@XmlAccessorType(XmlAccessType.FIELD)
public class Response {

    @XmlPath("body/form/input[@name='url']/@value")
    private String url;

    @XmlPath("body/form/input[@name='status']/@value")
    private String status;

    @XmlPath("body/form/input[@name='responseMessage']/@value")
    private String responseMessage;

}
  

Создать конвертер сообщений:

 private static HttpMessageConverter<Object> createXmlHttpMessageConverter() throws JAXBException {
    MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
   // I added lot of mediatypes, leave necessary ones
    xmlConverter.setSupportedMediaTypes(Arrays.asList(
            MediaType.APPLICATION_XML, MediaType.TEXT_HTML, MediaType.TEXT_PLAIN, MediaType.TEXT_XML
    ));
    Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
    jaxb2Marshaller.setClassesToBeBound(Response.class);
    // without this jaxb will complain about doctype in the beginning
    jaxb2Marshaller.setSupportDtd(true);
    xmlConverter.setMarshaller(jaxb2Marshaller);
    xmlConverter.setUnmarshaller(jaxb2Marshaller);
    return xmlConverter;
}
  

Инициализация шаблона REST:

 RestTemplate rest = new RestTemplate();
rest.getMessageConverters().add(0, createXmlHttpMessageConverter());
  

Также вам нужно будет установить MOXy в качестве поставщика JAXB. Я использовал для этого кода

 System.setProperty(JAXBContext.JAXB_CONTEXT_FACTORY, "org.eclipse.persistence.jaxb.JAXBContextFactory");
  

но это можно сделать и другими способами.

Все это позволит вам выполнить вызов:

 Response response = rest.postForEntity(url, request, Response.class);
  

И из экземпляра ответа должно быть тривиально получить JSON с помощью Jackson.

Комментарии:

1. Да, Александра, я согласен с вашим ответом. Мы можем сделать то же самое, также используя объект HtmlPage в HtmlUnit framework. Предоставленный вами код — это не что иное, как «Webscraping». Есть ли какой-либо другой способ, которым мы можем перехватить HTML-ответ от API к JSON? Спасибо 🙂

2. Обновленный ответ с другим решением

3. ваши усилия высоко ценятся.. спасибо, мой друг .. 🙂