SpringBoot调用Dynamics NAV 2015 SOAP服务时遇Unknown JAXB异常
我尝试用Java SpringBoot调用Dynamics NAV 2015的SOAP WebService,该服务需要用户名、密码、域名形式的凭证。编写了SoapClientService类添加SOAP头认证信息,调用服务端TestConnection方法,同时配置RestController提供/api/test-connection接口。请求该接口时返回错误:处理请求时出错:Unknown JAXB exception。无法区分该异常是来自marshalSendAndReceive方法的序列化问题,还是目标URL认证失败导致。
已完成的准备工作:
- 从
resources/wsdl目录下的ControlePreparation.wsdl文件生成Java类 - 引入
jaxb-api依赖 - 配置
maven-jaxb2-plugin插件 - 编写
WebServiceConfig配置类初始化Jaxb2Marshaller和SoapClientService实例
核心代码
SoapClientService类
@Service public class SoapClientService extends WebServiceGatewaySupport { @Value("${soap.service.url}") private String serviceUrl; @Value("${nav.user}") private String navUser; @Value("${nav.password}") private String navPassword; @Value("${nav.domain}") private String navDomain; public String testConnection() { // Create request object TestConnection request = new TestConnection(); // Add SOAP headers for authentication getWebServiceTemplate().setInterceptors(new ClientInterceptor[] { new ClientInterceptor() { @Override public boolean handleRequest(MessageContext messageContext) { TransportContext context = TransportContextHolder.getTransportContext(); WebServiceMessage message = messageContext.getRequest(); SoapHeader header = ((SoapMessage) message).getSoapHeader(); QName navUserHeader = new QName("urn:microsoft-dynamics-schemas/codeunit/ControlePreparation", "NavUser"); QName navPassHeader = new QName("urn:microsoft-dynamics-schemas/codeunit/ControlePreparation", "NavPass"); QName navDomainHeader = new QName("urn:microsoft-dynamics-schemas/codeunit/ControlePreparation", "NavDomain"); header.addHeaderElement(navUserHeader).setText(navUser); header.addHeaderElement(navPassHeader).setText(navPassword); header.addHeaderElement(navDomainHeader).setText(navDomain); return true; } @Override public boolean handleResponse(MessageContext messageContext) { // Handle response if needed return true; } @Override public boolean handleFault(MessageContext messageContext) { // Handle fault if needed return true; } @Override public void afterCompletion(MessageContext messageContext, Exception ex) { // Clean up resources if needed } } }); // Make SOAP call and receive response TestConnectionResult response = (TestConnectionResult) getWebServiceTemplate().marshalSendAndReceive(serviceUrl, request, new SoapActionCallback( "urn:microsoft-dynamics-schemas/codeunit/ControlePreparation:TestConnection" )); // Process response if (response != null) { return response.getReturnValue(); } else { return null; // Or handle null response as needed } } }
RestController类
@RestController @RequestMapping("/api") public class SoapController { @Autowired private SoapClientService soapClientService; @GetMapping("/test-connection") public ResponseEntity<String> testConnection() { try { String response = soapClientService.testConnection(); if (response != null) { return ResponseEntity.ok(response); } else { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("Failed to retrieve test connection response."); } } catch (HttpClientErrorException e) { return ResponseEntity.status(e.getStatusCode()).body("HTTP error occurred: " + e.getMessage()); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("An error occurred while processing the request: " + e.getMessage()); } } }
依赖配置(pom.xml)
<dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.1</version> <!-- Version peut être différente --> </dependency>
Maven插件配置(pom.xml)
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifactId> <version>0.15.3</version> <executions> <execution> <goals> <goal>generate</goal> </goals> </execution> </executions> <configuration> <generatePackage>com.ticop.demo.soapApi</generatePackage> <generateDirectory>${project.basedir}/src/main/java</generateDirectory> <schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory> <schemaIncludes> <include>*.wsdl</include> </schemaIncludes> <args> <arg>-wsdl</arg> </args> </configuration> </plugin>
生成的TestConnection类
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "") @XmlRootElement(name = "TestConnection") public class TestConnection { }
生成的TestConnectionResult类
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "returnValue" }) @XmlRootElement(name = "TestConnection_Result") public class TestConnectionResult { @XmlElement(name = "return_value", required = true) protected String returnValue; /** * Gets the value of the returnValue property. * * @return * possible object is * {@link String } * */ public String getReturnValue() { return returnValue; } /** * Sets the value of the returnValue property. * * @param value * allowed object is * {@link String } * */ public void setReturnValue(String value) { this.returnValue = value; } }
WebServiceConfig配置类
@Configuration public class WebServiceConfig { @Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); // this package must match the package in the <generatePackage> specified in // pom.xml marshaller.setContextPath("com.ticop.demo.soapApi"); return marshaller; } @Bean public SoapClientService soapClientService(Jaxb2Marshaller marshaller) { SoapClientService client = new SoapClientService(); client.setDefaultUri("http://172.16.8.191:7047/DynamicsNAV80/WS/FAD2014/Codeunit/ControlePreparation"); client.setMarshaller(marshaller); client.setUnmarshaller(marshaller); return client; } }
内容的提问来源于stack exchange,提问作者majd ddine oueslati
相关产品推荐
相关产品推荐

