一、首先了解两个概念,JAX-WS与JAX-RS的区别

JAX-WS:java TM API forXML_Based web Service
JAX-RS:java TM API forRestFul web Service

两者是不同风格的

SOA(Service Oriented Architecture)架构:面向服务的架构,它是一种设计思想,服务之间通过相互依赖最终提供系一系列的功能。
-----微服务架构大部分思想都是由SOA而来,只是微服务架构更具组件化,还有一些架构建模

JAX-RS:JAVA EE6 引进的新技术,支持rest架构风格创建web服务
JAX-WS:基于xml web service的java Api 允一个远程调用可以转换为一个基于XML的协议例如SOAP,在使用JAX-WS过程中,开发者不需要编写任何生成和处理SOAP消息的代码。JAX-WS的运行时实现会将这些API的调用转换成为对应的SOAP消息。

二、目前比较主流的web服务实现方法

Apache Axis1、Apache Axis2、Codehaus XFire、Apache CXF、Apache Wink、Jboss RESTEasy、sun JAX-WS(最简单、方便)、阿里巴巴 Dubbo等

Rest:简单易用,效率高
Soap:成熟度高,安全性高

(个人观点-----无理由)
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC实现服务的输入输出,可以和Spring框架无缝衔接。

正文

需要引入的jar包

可能会出现springboot版本会和cxf版本出现不兼容的情况,需要注意,不匹配会出现找不到cxf下的类

<version>2.5.1</version> 
<cxf.version>3.4.0</cxf.version>
<!-- CXF webservice -->
		<dependency>
			<groupId>org.scala-lang</groupId>
			<artifactId>scala-library</artifactId>
			<version>2.11.0</version>
		</dependency>
		<!-- 提供JacksonJsonProvider,非必需,可以使用其他json转化替换-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jersey</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.7</version>
		</dependency>
		<!--soup 是一款Java 的HTML解析器,
		可直接解析某个URL地址、HTML文本内容。
		它提供了一套非常省力的API,
		可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。-->
		<dependency>
			<groupId>org.jsoup</groupId>
			<artifactId>jsoup</artifactId>
			<version>1.9.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxws</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http-jetty</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-rs-extension-providers</artifactId>
			<version>${cxf.version}</version>
		</dependency>

创建实体类,

import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;

@XmlRootElement(name = "emplyee")
public class EmployeeXML implements Serializable {
    private Integer empid;
    private String deptno;
    private String empjob;
    private String empname;
    private String EntryDate;
    private Integer empstatus;
}

基于soap的整合

cxf配置类:

import com.example.wxwsofto.service.webService.cxf.ProspectService;
import com.example.wxwsofto.service.webService.cxf.impl.ProspectServiceImpl;
import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import javax.xml.ws.Endpoint;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJsonProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * http://localhost:8081/cxf/prosService?wsdl  访问链接必须加上wsdl否则会抛出异常
 */
@Configuration
public class cxfConfig {
    @Bean
    public ProspectService myService() {
        return new ProspectServiceImpl();
    }
	//CXFServlet()用来拦截cxf,拦截路径/cxf/*
    @Bean
    public ServletRegistrationBean createServletRegistrationBean(){
        return new ServletRegistrationBean(new CXFServlet(),"/cxf/*");
    }
	
    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus(){
        return new SpringBus();
    }

    @Bean
    @Qualifier("prosService")
    public Endpoint endpoint(){
        EndpointImpl endpoint = new EndpointImpl(springBus(),myService());
        endpoint.getInInterceptors().add(new AuthInterceptorJAWS());//添加校验拦截器
        endpoint.publish("/prosService"); //暴露的api
        return endpoint;
    }
    @Bean("jsonProvider") // 构造一个json转化bean,因为后面需要用这个bean配置json转化,所以给他取个名
    public JacksonJsonProvider getJacksonJsonProvider() {
        return new JacksonJsonProvider();
    }
}

webservice 接口:

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
 * webservice的接口类与服务实现类的namespace保持一致 否则会找不到
 */
@WebService(targetNamespace = "http://prospect.service.com",
            name = "prosService")
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML}) //返回类型
@Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML}) //请求类型
public interface ProspectService {
    @WebMethod
    @WebResult(name = "String",targetNamespace = "")
    String sendMessage(@WebParam(name = "message") String message);
}
import cn.hutool.core.lang.UUID;
import com.example.wxwsofto.service.webService.cxf.ProspectService;
import org.springframework.stereotype.Component;

import javax.jws.WebService;

@Component
@WebService(
        targetNamespace = "http://prospect.service.com", // 与接口中的命名空间一致,一般是接口的包名倒
        endpointInterface = "com.example.wxwsofto.service.webService.cxf.ProspectService",
        serviceName ="prosService" ) //暴露的接口名字
public class ProspectServiceImpl implements ProspectService {
    @Override
    public String sendMessage(String message) {
        return UUID.fastUUID().toString();
    }
}

服务的调用:

import com.example.wxwsofto.service.webService.config.LoginInterceptorJAWS;
import com.example.wxwsofto.service.webService.cxf.ProspectService;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * webservice的接口类与服务实现类的namespace保持一致 否则会找不到
 */
@RestController
public class WebServiceInvoke {
    @ResponseBody
    @RequestMapping("/webServiceInvoke")
    public String invoke(){
        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        Client client = dcf.createClient("http://localhost:8081/cxf/prosService?wsdl");
        // 需要密码的情况需要加上用户名和密码
        client.getOutInterceptors().add(new LoginInterceptorJAWS("root","root"));
        Object[] objects = new Object[0];
        try {
            // invoke("方法名",参数1,参数2,参数3....);
            objects = client.invoke("sendMessage", "wxw");
            System.out.println("返回数据:" + objects[0]);
        } catch (java.lang.Exception e) {
            e.printStackTrace();
        }
        return objects[0].toString();
    }

    /**
     * \用代理类工厂,需要拿到对方的接口
     * @return
     */
    @ResponseBody
    @RequestMapping("/webServiceInvokeProxy")
    public String invokeProxy(){
        JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
        jaxWsProxyFactoryBean.setAddress("http://localhost:8081/cxf/prosService?wsdl");
        jaxWsProxyFactoryBean.getOutInterceptors().add(new LoginInterceptorJAWS("root","root"));
        jaxWsProxyFactoryBean.setServiceClass(ProspectService.class);
        ProspectService prospectService = (ProspectService) jaxWsProxyFactoryBean.create();
        String nihao = prospectService.sendMessage("nihao");
        return nihao;
    }
}

上边服务的调用,引入了用户名密码的校验,使用的cxf的拦截器 AbstractPhaseInterceptor,分为两个方向请求进入和请求响应进行拦截

限流加身份校验

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.util.concurrent.RateLimiter;
import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import javax.servlet.http.HttpServletRequest;
import javax.xml.soap.SOAPException;
import java.util.List;
import java.util.Map;

public class AuthInterceptorJAWS extends AbstractPhaseInterceptor<SoapMessage> {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private static final String USERNAME = "root";
    private static final String PASSWORD = "root";
    private Map<String, RateLimiter> rateLimiterMap = MapUtil.newConcurrentHashMap();
    private RateLimiter rateLimiter =null;
    public AuthInterceptorJAWS() {
        /*定义在那个阶段拦截*/
        super(Phase.PRE_PROTOCOL);
    }

    @Override
    public void handleMessage(SoapMessage soapMessage) throws Fault {
        List<Header> headers = null;
        String username = null;
        String password = null;
        try {
            headers=soapMessage.getHeaders();
        } catch (Exception e) {
            logger.error("获取请求头信息失败,失败信息:{}",e.getMessage());
        }
        if (headers==null){
            throw new Fault(new IllegalArgumentException("找不到用户信息,无法验证用户信息"));
        }
        for (Header header: headers
             ) {
            SoapHeader soapHeader =(SoapHeader)header;
            /*
            WebServiceContext webServiceContext =new WebServiceContextImpl();
            MessageContext messageContext = webServiceContext.getMessageContext();
            HttpServletRequest request =(HttpServletRequest)messageContext.get(MessageContext.SERVLET_REQUEST);
            String pathInfo = request.getPathInfo();
            System.out.println("pathInfo:"+pathInfo);*/
            Message currentMessage = PhaseInterceptorChain.getCurrentMessage();
            //获取request
            HttpServletRequest request = (HttpServletRequest) currentMessage.get(AbstractHTTPDestination.HTTP_REQUEST);
            System.out.println("getHttpServletMapping:"+request.getHttpServletMapping().getServletName());
            System.out.println("getMethos:"+request.getMethod());
            System.out.println("getPathInfo:"+request.getPathInfo());
            Element element = (Element) soapHeader.getObject();
            String textContent = element.getTextContent();
            System.out.println("textContent:"+textContent);
            String baseURI = element.getBaseURI();
            System.out.println("baseURI:"+baseURI);
            NamedNodeMap attributes = element.getAttributes();
            for (int i=0;i<attributes.getLength();i++){
                System.out.println("attributes的属性"+i+attributes.item(i));
            }
            Currentlimit(baseURI);
            boolean limit = rateLimiter.tryAcquire();
            if (!limit){
                throw new Fault(new IllegalArgumentException("访问过快,请稍在尝试"));
            }
            NodeList usernameNode = element.getElementsByTagName("username");
            NodeList passwordNode = element.getElementsByTagName("password");
            username = usernameNode.item(0).getTextContent();
            password = passwordNode.item(0).getTextContent();
            System.out.println(username+password);
            if (StrUtil.isBlank(username)||StrUtil.isBlank(password)){
                throw new Fault(new IllegalArgumentException("用户信息为空"));
            }
            if (!(username.equals(USERNAME)&&password.equals(PASSWORD))){
                SOAPException soapException = new SOAPException("认证失败");
                logger.error("用户认证失败");
                throw new Fault(soapException);
            }
        }
    }

    /**
     * 限流
     */
    public void Currentlimit(String uri){
        if (rateLimiter==null){
            rateLimiter = RateLimiter.create(1);
            rateLimiterMap.put(uri,rateLimiter);
        }
    }
}

在请求的前身份信息封装到请求头里面,

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.namespace.QName;
import java.util.List;

public class LoginInterceptorJAWS extends AbstractPhaseInterceptor<SoapMessage> {
    private String username="root";
    private String password="root";
    public LoginInterceptorJAWS(String username, String password) {
        //设置在发送请求前阶段进行拦截
        super(Phase.PREPARE_SEND);
        this.username=username;
        this.password=password;
    }

    @Override
    public void handleMessage(SoapMessage soapMessage) throws Fault {
        List<Header> headers = soapMessage.getHeaders();
        Document doc = DOMUtils.createDocument();
        Element auth = doc.createElementNS("http://prospect.service.com","SecurityHeader");
        Element UserName = doc.createElement("username");
        Element UserPass = doc.createElement("password");

        UserName.setTextContent(username);
        UserPass.setTextContent(password);

        auth.appendChild(UserName);
        auth.appendChild(UserPass);
        System.out.println(auth.toString());
        System.out.println(doc.toString());

        headers.add(0, new Header(new QName("SecurityHeader"),auth));
    }
}

至此

整合Restful api

编写rest一个接口

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

@Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public interface ProspectInterface {
    @GET
    @Produces({MediaType.APPLICATION_XML})
    @Path("/getMessage1/{message}")
    public Employee getMessage1(@PathParam("message") String message);

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    @Path("/getMessage2/{message:[0-9]{0,10}}")
    public String getMessage2(@PathParam("message") Integer message);
}
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

@Component
@Path("/")
public class ProspectInterfaceImpl implements ProspectInterface {
    @GET
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_XML})
    @Path("/getMessage1/{message}")
    @Override
    public Employee getMessage1(@PathParam("message") String message) {
        JSONObject obj = JSONUtil.createObj();
        //obj.putOnce(String.valueOf(message),UUID.fastUUID().toString());
        Employee employee =new Employee();
        employee.setEmpjob("java");
        employee.setDeptno("zhogdain");
        employee.setEmpname(message);
        return employee;
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    @Path("/getMessage2/{message:[0-9]{0,10}}")
    @Override
    public String getMessage2(@PathParam("message") Integer message) {
        JSONObject obj = JSONUtil.createObj();
        obj.putOnce(String.valueOf(message),UUID.fastUUID().toString());
        System.out.println(obj.toString());
        return obj.toString();
    }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 将Bean托管给Spring -->
    <bean id="prosService" class="com.example.wxwsofto.service.webService.cxf.impl.ProspectInterfaceImpl">
    </bean>
    <!-- 配置需要暴露的Rest ful Service -->
    <jaxrs:server id="restContainer" address="/prosAdders"> <!-- 暴露restful api 类似于前文提到的webService【暴露soap】 即访问的时候要加上这个address -->
        <jaxrs:serviceBeans>
            <!-- 相当于打包发布服务 -->
            <ref bean="prosService" />
        </jaxrs:serviceBeans>
        <!-- 提供一个json转化,没有这个不能自动返回json jsonProvider就是前面@Bean生成的在CxfConfig -->
        <jaxrs:providers>
            <ref bean="jsonProvider" />
        </jaxrs:providers>
    </jaxrs:server>
</beans>

以上仅供参考,如有帮助到你,可以点个star