问题
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