SpringBoot + CXF快速實現SOAP WebService(支持Basic Auth)

嘮叨兩句java

講真,SOAP跟如今流行的RESTful WebService比起來顯得很難用。冗餘的XML文本信息太多,可讀性差,它的請求信息有時很難手動構造,不太好調試。不過說歸說,對某些企業用戶來講SOAP的使用率仍然是很高的。

 

需求背景spring

接手維護的一個項目,最近客戶想開放項目中的功能給第三方調用,並且接入方指定必須是SOAP接口。這項目原來的代碼我看着頭疼,也不想再改了,除非推倒重寫。客戶的需求雖然不難但要的很急,爲了儘快交付就使用SpringBoot快速搭一個微服務。

 

開始動手apache

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>

 

編寫服務代碼(示例代碼)app

@WebService(targetNamespace="http://demo.example.com/")
public interface IUserService {

    @WebMethod
    User getUserById(@WebParam(name = "id") int id);

    @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 implements IUserService {

    private Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private IUserDAO userDAO;

    @Override
    public User getUserById(int id) {
        return userDAO.getUserById(id);
    }

    @Override
    public int addUser(User user) {
        logger.info("save user [" + user.getId() + "]");
        userDAO.addUser(user);
        return 0;
    }
}

 

鑑權攔截器maven

public class AuthInterceptor extends AbstractSoapInterceptor {

    private static final String BASIC_PREFIX = "Basic ";
    private static final String USERNAME = "lichmama";
    private static final String PASSWORD = "123456";

    public AuthInterceptor() {
        super(Phase.PRE_INVOKE);
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        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 new Fault(exception);
        }
        if (!auth.startsWith(BASIC_PREFIX)) {
            SOAPException exception = new SOAPException("auth failed, header [Authorization] is illegal");
            throw new Fault(exception);
        }
        String plaintext = new String(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 new Fault(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 new Fault(exception);
        }
    }
}

 

編寫配置類ide

@Configuration
public class SoapConfig {

    @Autowired
    private IUserService userService;

    @Autowired
    @Qualifier(Bus.DEFAULT_BUS_ID)
    private SpringBus bus;

    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(bus, userService);
        endpoint.publish("/userService");
        return endpoint;
    }
}

 

修改CXF默認發佈路徑(application.properties)spring-boot

server.port=8000
cxf.path=/soap

 

啓動項目後訪問http://localhost:8000/soap/userService?wsdl微服務

 

使用SoapUI測試一下,看上去沒什麼問題測試

 

客戶端增長對Basic Auth的支持:ui

/*
  使用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:

public class GeneralSoapClient {

    private String WSDL;

    private String namespaceURI;

    private String localPart;

    public GeneralSoapClient() {

    }

    public GeneralSoapClient(String WSDL, String namespaceURI, String localPart) {
        this.WSDL = WSDL;
        this.namespaceURI = namespaceURI;
        this.localPart = localPart;
    }

    public String getWSDL() {
        return WSDL;
    }

    public void setWSDL(String WSDL) {
        this.WSDL = WSDL;
    }

    public String getNamespaceURI() {
        return namespaceURI;
    }

    public void setNamespaceURI(String namespaceURI) {
        this.namespaceURI = namespaceURI;
    }

    public String getLocalPart() {
        return localPart;
    }

    public void setLocalPart(String localPart) {
        this.localPart = localPart;
    }

    private boolean requireAuth = false;

    private String username;

    private String password;

    public boolean isRequireAuth() {
        return requireAuth;
    }

    public void setRequireAuth(boolean requireAuth) {
        this.requireAuth = requireAuth;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * 建立Soap Service實例
     * @param serviceInterface
     * @return
     * @throws Exception
     */
    public <T> T create(Class<T> serviceInterface) throws Exception {
        URL url = new URL(WSDL);
        QName qname = new QName(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);
        }
        return port;
    }
}
View Code
public class TestSoap {

    public static void main(String[] args) throws Exception {
        String wsdl = "http://localhost:8080/soap/userService?wsdl";
        String namespaceURI = "http://demo.example.com/";
        String localPart = "UserService";
        GeneralSoapClient soapClient = new GeneralSoapClient(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

 

收工下班了。

相關文章
相關標籤/搜索