1

我试图理解我遇到的这个特殊问题。在这里使用 Spring OXM 来实现一个 Soap WS Consumer。

我只是附上相关信息来解释问题。

登录Ws配置,

@Configuration
public class LoginWsConfiguration {

    @Inject
    private OnboardingProperties onboardingProperties;

    @Bean
    Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller
            .setPackagesToScan("org.openiam.ws.login.api_3_2_6");
        try {
            jaxb2Marshaller.afterPropertiesSet();
        }
        catch (Exception ex) {
            throw new BeanCreationException(ex.getMessage(), ex);
        }
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller jaxb2Marshaller) {
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(jaxb2Marshaller);
        webServiceTemplate.setUnmarshaller(jaxb2Marshaller);
        webServiceTemplate.setDefaultUri(onboardingProperties.getIAM().getEndpoint().getLogin());

        return webServiceTemplate;
    }

LoginClient 客户端实现为,

@Component
public class LoginClient {

    private static final Logger log = LoggerFactory.getLogger(IAMLoginClient.class);

    @Autowired
    private LoginMapper loginMapper;

    @Inject
    private OnboardingProperties onboardingProperties;

    private WebServiceTemplate webServiceTemplate;

    @Autowired
    public LoginClient(WebServiceTemplate webServiceTemplate) {
        this.webServiceTemplate = webServiceTemplate;
    }

    public LoginClient() {
    }

    public Optional getLoginByUserId(final String userId) {
        ObjectFactory factory = new ObjectFactory();
        GetLoginByUser req = factory.createGetLoginByUser();
        req.setUserId(userId);
        GetLoginByUserResponse resp = (GetLoginByUserResponse)webServiceTemplate.marshalSendAndReceive(req);
        if (resp != null && resp.getReturn() != null && resp.getReturn().getStatus() == org.openiam.ws.login.api_3_2_6.ResponseStatus.SUCCESS) {
            List<Login> foundLogins = resp.getReturn().getPrincipalLists();
            Login foundLogin = foundLogins.stream()
                .filter(login -> login.getManagedSysId().equals(Constants.IAM_DEFAULT_MANAGED_SYS_ID))
                .findFirst()
                .orElse(null);
            return Optional.ofNullable((foundLogin != null) ? this.loginMapper.mapIAMLogin(foundLogin) : null);
        }
        return Optional.empty();
    }

为了完整起见,GetLoginByUser,

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getLoginByUser", propOrder = {
    "userId"
})
@XmlRootElement(name = "getLoginByUser")
public class GetLoginByUser {

    protected String userId;

    /**
     * Gets the value of the userId property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getUserId() {
        return userId;
    }

    /**
     * Sets the value of the userId property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setUserId(String value) {
        this.userId = value;
    }

}

GetLoginByUserResponse,

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getLoginByUserResponse", propOrder = {
    "_return"
})
@XmlRootElement(name = "getLoginByUserResponse")
public class GetLoginByUserResponse {

    @XmlElement(name = "return")
    protected LoginListResponse _return;

    /**
     * Gets the value of the return property.
     * 
     * @return
     *     possible object is
     *     {@link LoginListResponse }
     *     
     */
    public LoginListResponse getReturn() {
        return _return;
    }

    /**
     * Sets the value of the return property.
     * 
     * @param value
     *     allowed object is
     *     {@link LoginListResponse }
     *     
     */
    public void setReturn(LoginListResponse value) {
        this._return = value;
    }

}

但是,当我尝试时,

@Autowired
private UserClient iamUserClient;

@Autowired
private LoginClient iamLoginClient;

Optional<IAMUser> userFromIAM = iamUserClient.getUserByPrincipal(lowercaseLogin);
IAMUser userIAM = userFromIAM.
        orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in IAM"));
    if (userIAM.getStatus() != IAMUserStatus.ACTIVE || userIAM.getAccountStatus() != null) {
        throw new UserNotActivatedException("User " + lowercaseLogin + " is not active");
    }
Optional<IAMLogin> loginFromIAM = iamLoginClient.getLoginByUserId(userIAM.getId());

我得到错误,

org.springframework.oxm.UncategorizedMappingException: Unknown JAXB exception; nested exception is javax.xml.bind.JAXBException: class org.openiam.ws.login.api_3_2_6.GetLoginByUser nor any of its super class is known to this context.
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.convertJaxbException(Jaxb2Marshaller.java:915)
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.marshal(Jaxb2Marshaller.java:684)
    at org.springframework.ws.support.MarshallingUtils.marshal(MarshallingUtils.java:81)
    at org.springframework.ws.client.core.WebServiceTemplate$2.doWithMessage(WebServiceTemplate.java:399)
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:590)
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:383)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:373)
    at com.orchestral.dsm.onboarding.iam.ws.login.LoginClient.getLoginByUserId(LoginClient.java:77)
    at com.orchestral.dsm.onboarding.security.IAMUserDetailsService.loadUserByUsername(IAMUserDetailsService.java:45)

从我可以看到它在编组getUserByPrincipalUserClient)时不会失败,但会在getLoginByUserId( )上失败LoginClient

4

2 回答 2

3

这是因为两者,

@Autowired
private UserClient iamUserClient;

@Autowired
private LoginClient iamLoginClient;

彼此冲突。拥有个人jaxb2Marshaller并通过它来WebServiceTemplate解决问题。

所以 LoginWsConfiguration 更新为,

@Configuration
public class LoginWsConfiguration {

    @Bean
    Jaxb2Marshaller jaxb2LoginMarshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("org.openiam.ws.login.api_3_2_6");
        return jaxb2Marshaller;
    }

    @Bean
    public LoginClient loginClient(Jaxb2Marshaller jaxb2LoginMarshaller) {
        LoginClient client = new LoginClient();
        client.setMarshaller(jaxb2LoginMarshaller);
        client.setUnmarshaller(jaxb2LoginMarshaller);
        client.setDefaultUri("uri");

        return client;
    }
}
于 2017-02-11T22:45:49.447 回答
0

这个配置在 Spring 4 上对我有用,现在在 Spring 5 中我看到 WebMvcConfigurerAdapter 已被弃用,但它仍然有效:

@Configuration
@EnableWebMvc
@ComponentScan({})
public class WebConfig extends WebMvcConfigurerAdapter {

    public MappingJackson2HttpMessageConverter jacksonMessageConverter() {
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper mapper = new ObjectMapper(); 
        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

        mapper.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, false);
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

        messageConverter.setObjectMapper(mapper);
        return messageConverter;

    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 
        converters.add(jacksonMessageConverter());
        super.configureMessageConverters(converters);
    }
}
于 2019-05-05T18:06:27.483 回答