有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java Paypal集成SOAP JAXWS SSL握手异常

这个问题与使用SOAP请求/响应模型将PayPal API与Java集成有关

以下方法包括建立请求参数并返回响应字符串,在本例中是令牌。我看了几个关于如何进行请求调用的示例,但是这些方法是为较少的版本创建的(这个版本是“109.0”,我看到的其他示例是80、60甚至40)

不管怎样,我下载了。来自PayPal的wsdl文件,创建了具有SOAPUI和JAX-WS web服务风格的客户端java类,保存了项目,并使用MyEclipse打开。我也在我的Java TomCat服务器上导入了PayPal证书,在Java的cacerts文件上使用keytool导入

假设以下方法是返回字符串值的请求方法:

public String setExpressCheckout(String returnURL, String cancelURL) throws ErrorGeneral {

    PayPalAPIInterfaceService pp = new PayPalAPIInterfaceService();
    UserIdPasswordType login = new UserIdPasswordType();
    login.setUsername("carlos.martinez_api1.netijam.com");
    login.setPassword("1389974315");
    login.setSignature("AFcWxV21C7fd0v3bYYYRCpSSRl31AI-ujedgZR8zf1CorgeJpph2tssY");
    String token = "";
    String ackString;   
    // following class is generated by wsdl2java utility Service class

    final PayPalAPIAAInterface expressCheckoutPort = pp.getPayPalAPIAA();
    final Binding binding = ((BindingProvider) expressCheckoutPort).getBinding();
    List<Handler> handlersList = new ArrayList<Handler>();

    // now, adding instance of Handler to handlersList which should do our job:
    // creating header instance
    CustomSecurityHeaderType headerObj = new CustomSecurityHeaderType();
    UserIdPasswordType credentials = new UserIdPasswordType();
    credentials.setUsername("carlos.martinez_api1.netijam.com");
    credentials.setPassword("1389974315");
    credentials.setSignature("AFcWxV21C7fd0v3bYYYRCpSSRl31AI-ujedgZR8zf1CorgeJpph2tssY");
    headerObj.setCredentials(credentials);


    ObjectFactory objectFactory = new ObjectFactory();
    // creating JAXBElement from headerObj
    final JAXBElement<CustomSecurityHeaderType> requesterCredentials = objectFactory.createRequesterCredentials(headerObj);

    handlersList.add(new SOAPHandler<SOAPMessageContext>() {
        @Override
        public boolean handleMessage(final SOAPMessageContext context) {        
            try {
                // checking whether handled message is outbound one as per Martin Strauss answer
                final Boolean outbound = (Boolean) context.get("javax.xml.ws.handler.message.outbound");
                if (outbound != null && outbound) {
                    // obtaining marshaller which should marshal instance to xml
                    final Marshaller marshaller = JAXBContext.newInstance(CustomSecurityHeaderType.class).createMarshaller();
                    // adding header because otherwise it's null
                    final SOAPHeader soapHeader = context.getMessage().getSOAPPart().getEnvelope().addHeader();
                    // marshalling instance (appending) to SOAP header's xml node
                    marshaller.marshal(requesterCredentials, soapHeader);
                }
            } catch (final Exception e) {
                throw new RuntimeException(e);
            }
            return true;
        }

        @Override
        public boolean handleFault(SOAPMessageContext context) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void close(MessageContext context) {
            // TODO Auto-generated method stub

        }

        @Override
        public Set<QName> getHeaders() {
            // TODO Auto-generated method stub
            return null;
        }

        // ... default implementations of other methods go here

    });
    // as per Jean-Bernard Pellerin's comment setting handlerChain list here, after all handlers were added to list

    binding.setHandlerChain(handlersList);


    try {

        SetExpressCheckoutReq sECR = new SetExpressCheckoutReq();
        SetExpressCheckoutRequestType sECRDT = new SetExpressCheckoutRequestType();
        sECRDT.setVersion("109.0");
        SetExpressCheckoutRequestDetailsType details = new SetExpressCheckoutRequestDetailsType();
        PaymentDetailsType paymentDetails = new PaymentDetailsType();
        paymentDetails.setOrderDescription("Integrating Stuff Test Order");
        paymentDetails.setInvoiceID("INVOICE-" + Math.random());
        BasicAmountType orderTotal = new BasicAmountType();
        orderTotal.setCurrencyID(CurrencyCodeType.EUR);
        orderTotal.setValue("120.00");
        paymentDetails.setOrderTotal(orderTotal);
        paymentDetails.setPaymentAction(PaymentActionCodeType.SALE);
        List<PaymentDetailsType> listaDetallesPago = new ArrayList<PaymentDetailsType>();
        listaDetallesPago.add(paymentDetails);
        details.setPaymentDetails(listaDetallesPago);
        details.setReturnURL(returnURL);
        details.setCancelURL(cancelURL);

        sECRDT.setSetExpressCheckoutRequestDetails(details);


        sECR.setSetExpressCheckoutRequest(sECRDT);


        SetExpressCheckoutResponseType response = expressCheckoutPort.setExpressCheckout(sECR);

        ackString = response.getAck().value();
        System.out.println(ackString);
        token = response.getToken();

        for (ErrorType msg : response.getErrors()) {
            System.out.println(msg.getLongMessage());
        }
    } catch (Exception ex) {
        System.out.println(ex.getMessage());
    }

    // get the token from the response
    return token;
}

这就是我收到的错误:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1091)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at com.sun.xml.ws.transport.http.client.HttpClientTransport.getOutput(HttpClientTransport.java:92)
at com.sun.xml.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:110)
at com.sun.xml.ws.protocol.soap.ClientMUPipe.process(ClientMUPipe.java:72)
at com.sun.xml.ws.handler.HandlerPipe.process(HandlerPipe.java:134)
at com.sun.xml.ws.handler.HandlerPipe.process(HandlerPipe.java:134)
at com.sun.xml.ws.client.Stub.process(Stub.java:125)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:127)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:238)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:212)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:110)
at com.sun.proxy.$Proxy39.setExpressCheckout(Unknown Source)
at capsula.SetExpressCheckoutService.setExpressCheckout(SetExpressCheckoutService.java:168)
at capsula.SetExpressCheckoutService.main(SetExpressCheckoutService.java:56)

我试图搜索网络的每一个部分,以找到解决方案,但我做不到。我从PayPal上读了很多例子,但它并没有告诉我任何关于新版本的信息,因为在旧版本中,有一种简单的方法可以发出请求,包括请求上的凭据,而不是执行以下糟糕的部分:

ObjectFactory objectFactory = new ObjectFactory();
// creating JAXBElement from headerObj
final JAXBElement<CustomSecurityHeaderType> requesterCredentials = objectFactory.createRequesterCredentials(headerObj);

handlersList.add(new SOAPHandler<SOAPMessageContext>() {
    @Override
    public boolean handleMessage(final SOAPMessageContext context) {        
        try {
            // checking whether handled message is outbound one as per Martin Strauss answer
            final Boolean outbound = (Boolean) context.get("javax.xml.ws.handler.message.outbound");
            if (outbound != null && outbound) {
                // obtaining marshaller which should marshal instance to xml
                final Marshaller marshaller = JAXBContext.newInstance(CustomSecurityHeaderType.class).createMarshaller();
                // adding header because otherwise it's null
                final SOAPHeader soapHeader = context.getMessage().getSOAPPart().getEnvelope().addHeader();
                // marshalling instance (appending) to SOAP header's xml node
                marshaller.marshal(requesterCredentials, soapHeader);
            }
        } catch (final Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void close(MessageContext context) {
        // TODO Auto-generated method stub

    }

    @Override
    public Set<QName> getHeaders() {
        // TODO Auto-generated method stub
        return null;
    }

    // ... default implementations of other methods go here

});
// as per Jean-Bernard Pellerin's commententer code here setting handlerChain list here, after all handlers were added to list

binding.setHandlerChain(handlersList);

因为我不确定这是否正确

一切帮助都将不胜感激。谢谢!=)


共 (1) 个答案

  1. # 1 楼答案

    问题是在我自己生成的类中,当我试图调用webservice时,我无法传递CustomSecurityHeader,这是因为类APIService没有正确生成。对于这个案子,经过调查,我知道发生了什么

    起初,我使用soapUI程序自动生成发送消息的类。Paypal提供给开发人员的wsdl文件。但是,我没有做的重要一点是建立一个自定义参数,这是执行正确生成的代码所必需的:

    -XadditionalHeaders-Xnocompile

    这是为另一个使用“wsimport”命令(用于Jax WS库生成的代码)的教程提取的,使用该命令的人也添加了这些参数。完整的线路是。我可以使用这样的终端控制台命令:

    wsimport-keep-xaadditionalheaders-Xnocompile-p贝宝。测试桌面/PayPalSvc。wsdl/

    生成正确的类并传递CustomSecurityHeader

    我目前的正确请求代码是:

    String usuario = "carlos.martinez_api1.netijam.com";
    String password = "XEDdsafXSCE4";
    String firma = "A6aFJz-KhDsdf7f-668iCsdfweFplAcbDlof-vWP5wsdfsdEAy9T-d.";
    //Make encapsulated object of my own class cabeceraPeticiones
    CabeceraPeticiones cabeceraPeticiones = CabeceraPeticiones.getInstanceCabecera(usuario, password, firma);
    //Call the method that takes the header in the format that webservice needs
    Holder<CustomSecurityHeaderType> cabeceraSeguridad = cabeceraPeticiones.getCabecera();      
    
    //Set the connection params to work properly and the webservice method that I want to execute
    PayPalAPIInterfaceService pp = new PayPalAPIInterfaceService();
    GetExpressCheckoutDetailsReq gECR = new GetExpressCheckoutDetailsReq();
    GetExpressCheckoutDetailsRequestType gECDRT = new GetExpressCheckoutDetailsRequestType();
    PayPalAPIAAInterface expressCheckoutPort = pp.getPayPalAPIAA(); 
    ((BindingProvider) expressCheckoutPort).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,  "https://api-aa-3t.sandbox.paypal.com/2.0/");
    
    //I take the response from the webservice operation that I execute, passing the header and the webservice request param
    GetExpressCheckoutDetailsResponseType response = expressCheckoutPort.getExpressCheckoutDetails(gECR, cabeceraSeguridad);