You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot调用Dynamics NAV 2015 SOAP服务时遇Unknown JAXB异常

SpringBoot调用Dynamics NAV 2015 SOAP WebService遇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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 13:06:05