SpringBoot + CXF快速实现SOAP WebService(支持Basic Auth)

摘要:
唠叨两句讲真,SOAP跟现在流行的RESTfulWebService比起来显得很难用。不过说归说,对某些企业用户来说SOAP的使用率仍然是很高的。需求背景接手维护的一个项目,最近客户想开放项目中的功能给第三方调用,而且接入方指定必须是SOAP接口。客户的需求虽然不难但要的很急,为了尽快交付就使用SpringBoot快速搭一个微服务。开始动手1.新建一个SpringStarterProject2.加入cxf的maven配置org.apache.cxfcxf-spring-boot-starter-jaxws3.1.15编写服务代码@WebServicepublicinterfaceIUserService{@WebMethodUsergetUserById;@WebMethodintaddUser;}@InInterceptors@WebService@ComponentpublicclassUserServiceImplimplementsIUserService{privateLoggerlogger=LoggerFactory.getLogger;@AutowiredprivateIUserDAOuserDAO;@OverridepublicUsergetUserById{returnuserDAO.getUserById;}@OverridepublicintaddUser{logger.info;userDAO.addUser;return0;}}鉴权拦截器publicclassAuthInterceptorextendsAbstractSoapInterceptor{privatestaticfinalStringBASIC_PREFIX="Basic";privatestaticfinalStringUSERNAME="lichmama";privatestaticfinalStringPASSWORD="123456";publicAuthInterceptor(){super;}@OverridepublicvoidhandleMessagethrowsFault{HttpServletRequestrequest=message.get;Stringauth=request.getHeader;if{SOAPExceptionexception=newSOAPException;thrownewFault;}if(!

唠叨两句

讲真,SOAP跟现在流行的RESTful WebService比起来显得很难用。冗余的XML文本信息太多,可读性差,它的请求信息有时很难手动构造,不太好调试。不过说归说,对某些企业用户来说SOAP的使用率仍然是很高的。

需求背景

接手维护的一个项目,最近客户想开放项目中的功能给第三方调用,而且接入方指定必须是SOAP接口。这项目原来的代码我看着头疼,也不想再改了,除非推倒重写。客户的需求虽然不难但要的很急,为了尽快交付就使用SpringBoot快速搭一个微服务。

开始动手

1.新建一个Spring Starter Project
2.加入cxf的maven配置
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
        <version>3.1.15</version>
    </dependency>

编写服务代码(示例代码)

@WebService(targetNamespace="http://demo.example.com/")
public interfaceIUserService {
    @WebMethod
    User getUserById(@WebParam(name = "id") intid);
    @WebMethod
    int addUser(@WebParam(name = "user") User user);
}
@InInterceptors(interceptors={"com.example.demo.auth.AuthInterceptor"})
@WebService(serviceName = "UserService", targetNamespace = "http://demo.example.com/", endpointInterface = "com.example.demo.soap.IUserService")
@Component
public class UserServiceImpl implementsIUserService {
    private Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    privateIUserDAO userDAO;
    @Override
    public User getUserById(intid) {
        returnuserDAO.getUserById(id);
    }
    @Override
    public intaddUser(User user) {
        logger.info("save user [" + user.getId() + "]");
        userDAO.addUser(user);
        return 0;
    }
}

鉴权拦截器

public class AuthInterceptor extendsAbstractSoapInterceptor {
    private static final String BASIC_PREFIX = "Basic ";
    private static final String USERNAME = "lichmama";
    private static final String PASSWORD = "123456";
    publicAuthInterceptor() {
        super(Phase.PRE_INVOKE);
    }
    @Override
    public void handleMessage(SoapMessage message) throwsFault {
        HttpServletRequest request =(HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
        String auth = request.getHeader("Authorization");
        if (auth == null) {
            SOAPException exception = new SOAPException("auth failed, header [Authorization] not exists");
            throw newFault(exception);
        }
        if (!auth.startsWith(BASIC_PREFIX)) {
            SOAPException exception = new SOAPException("auth failed, header [Authorization] is illegal");
            throw newFault(exception);
        }
        String plaintext = newString(Base64.getDecoder().decode(auth.substring(BASIC_PREFIX.length())));
        if (StringUtils.isEmpty(plaintext) || !plaintext.contains(":")) {
            SOAPException exception = new SOAPException("auth failed, header [Authorization] is illegal");
            throw newFault(exception);
        }
        String[] userAndPass = plaintext.split(":");
        String username = userAndPass[0];
        String password = userAndPass[1];
        if (!USERNAME.equals(username) || !PASSWORD.equals(password)) {
            SOAPException exception = new SOAPException("auth failed, username or password is incorrect");
            throw newFault(exception);
        }
    }
}

编写配置类

@Configuration
public classSoapConfig {
    @Autowired
    privateIUserService userService;
    @Autowired
    @Qualifier(Bus.DEFAULT_BUS_ID)
    privateSpringBus bus;
    @Bean
    publicEndpoint endpoint() {
        EndpointImpl endpoint = newEndpointImpl(bus, userService);
        endpoint.publish("/userService");
        returnendpoint;
    }
}

修改CXF默认发布路径(application.properties)

server.port=8000
cxf.path=/soap

启动项目后访问http://localhost:8000/soap/userService?wsdl

SpringBoot + CXF快速实现SOAP WebService(支持Basic Auth)第1张

使用SoapUI测试一下,看上去没什么问题

SpringBoot + CXF快速实现SOAP WebService(支持Basic Auth)第2张

客户端增加对Basic Auth的支持:

/*
  使用Eclipse自动生成Web Service Client,在SoapBingdingStub的createCall()方法中加入一下代码:
*/
//basic auth
_call.setProperty("javax.xml.rpc.security.auth.username", "lichmama");
_call.setProperty("javax.xml.rpc.security.auth.password", "123456");

然后正常调用即可,这里提供一下自己写的SoapClient:

SpringBoot + CXF快速实现SOAP WebService(支持Basic Auth)第3张SpringBoot + CXF快速实现SOAP WebService(支持Basic Auth)第4张
public classGeneralSoapClient {
    privateString WSDL;
    privateString namespaceURI;
    privateString localPart;
    publicGeneralSoapClient() {
    }
    publicGeneralSoapClient(String WSDL, String namespaceURI, String localPart) {
        this.WSDL =WSDL;
        this.namespaceURI =namespaceURI;
        this.localPart =localPart;
    }
    publicString getWSDL() {
        returnWSDL;
    }
    public voidsetWSDL(String WSDL) {
        this.WSDL =WSDL;
    }
    publicString getNamespaceURI() {
        returnnamespaceURI;
    }
    public voidsetNamespaceURI(String namespaceURI) {
        this.namespaceURI =namespaceURI;
    }
    publicString getLocalPart() {
        returnlocalPart;
    }
    public voidsetLocalPart(String localPart) {
        this.localPart =localPart;
    }
    private boolean requireAuth = false;
    privateString username;
    privateString password;
    public booleanisRequireAuth() {
        returnrequireAuth;
    }
    public void setRequireAuth(booleanrequireAuth) {
        this.requireAuth =requireAuth;
    }
    publicString getUsername() {
        returnusername;
    }
    public voidsetUsername(String username) {
        this.username =username;
    }
    publicString getPassword() {
        returnpassword;
    }
    public voidsetPassword(String password) {
        this.password =password;
    }
    /**
     * 创建Soap Service实例
     * @paramserviceInterface
     * @return
     * @throwsException
     */
    public <T> T create(Class<T> serviceInterface) throwsException {
        URL url = newURL(WSDL);
        QName qname = newQName(namespaceURI, localPart);
        Service service =Service.create(url, qname);
        T port =service.getPort(serviceInterface);
        if(requireAuth) {
            BindingProvider prov =(BindingProvider) port;
            prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
            prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);
        }
        returnport;
    }
}
View Code
public classTestSoap {
    public static void main(String[] args) throwsException {
        String wsdl = "http://localhost:8080/soap/userService?wsdl";
        String namespaceURI = "http://demo.example.com/";
        String localPart = "UserService";
        GeneralSoapClient soapClient = newGeneralSoapClient(wsdl, namespaceURI, localPart);
        soapClient.setRequireAuth(true);
        soapClient.setUsername("lichmama");
        soapClient.setPassword("123456");
        IUserService service = soapClient.create(IUserService.class);
        User user = service.getUserById(101);
    }
}

最后交代一下开发环境

STS 3.7.3 + SpringBoot 2.0.1 + JDK1.8

收工下班了。

免责声明:文章转载自《SpringBoot + CXF快速实现SOAP WebService(支持Basic Auth)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇iOS 三方库fmdb 的使用ECharts问题--散点图中对散点添加点击事件下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Delphi XE4 TStringHelper用法详解

原文地址:DelphiXE4TStringHelper用法详解作者:天下为公 Delphi XE4的TStringHelper,对操作字符串进一步带来更多的方法,估计XE5还能继续用到。System.SysUtils.TStringHelper大小写转换:-------------------------------------------------...

c# 常用 Common

/// <summary> /// md5加密字符串 /// </summary> /// <param name="message"></param> /// <returns></returns>...

建行互联网银企被扫支付

背景 最近在对接建行的支付,我们做的是被扫支付,就是B扫C,一开始对方发了一个压缩包给我,看起来挺齐全的,文档、demo啥的都有,以为很简单,跟微信支付宝类似,调一下接口,验证一下就OK了。然而,事实证明我还是太年轻了。而且网络上你能够搜到的基本上都用不了,所以记一下博客,或许可以帮助其他人。 先说一下建行支付比较特殊的地方吧 1、官方提供的demo里面,...

Jakarta Java Mail属性参数配置

前言 Jakarta Mail网址:https://eclipse-ee4j.github.io/mail SMTP协议可匹配的属性:https://eclipse-ee4j.github.io/mail/docs/api/com/sun/mail/smtp/package-summary.html 翻译(Package com.sun.mail.smtp...

CORS跨域实现思路及相关解决方案

本篇包括以下内容: CORS 定义 CORS 对比 JSONP CORS,BROWSER支持情况 主要用途 Ajax请求跨域资源的异常 CORS 实现思路 安全说明 CORS 几种解决方案 自定义CORSFilter Nginx 配置支持Ajax跨域 支持多域名配置的CORS Filter keyword:cors,跨域,ajax,403,fi...

多线程使用注意

命名 来源:https://www.cnblogs.com/guozp/p/10344446.html 我们在创建线程池的时候,一定要给线程池名字,如下这种写法,线程是默认直接生成的: public static void main(String[] args) { ExecutorService executorService = E...