WebService简单理解就是用http发送接收xml数据,但这个xml得遵守系统的规范。这个规范就是WSDL(Web服务描述语言,Web Services Description Language)。
在WebService中传输的xml有一个正式的名称叫Soap(简单对象访问协议 Simple Object Access Protocol)。
WebService分为客户端和服务端。这两个都可以做数据源提供数据,比如说客户端发送大量数据给服务端,服务端接收大量数据。也可以是客户端发起请求获取服务端提供的大量数据。所有谁生产谁消费这事对Webservice不必纠结。
SpringBoot项目中还是推荐使用注解的方式实现WebService,这样比较优雅。
1.首先要引入大量的依赖。目前部分jar可能有漏斗,如果项目对安全有较高的要求请引入没有漏洞版本的jar
- <!-- webService依赖-->
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-core</artifactId>
- <version>${cxf-core.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-frontend-jaxws</artifactId>
- <version>${cxf-core.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-transports-http-jetty</artifactId>
- <version>${cxf-core.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-transports-http</artifactId>
- <version>${cxf-core.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web-services</artifactId>
- <version>2.7.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
- <version>${cxf-core.version}</version>
- </dependency>
- <dependency>
- <groupId>com.sun.xml.ws</groupId>
- <artifactId>jaxws-ri</artifactId>
- <version>2.3.5</version>
- <type>pom</type>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.apache.cxf.services/cxf-services -->
- <dependency>
- <groupId>org.apache.cxf.services</groupId>
- <artifactId>cxf-services</artifactId>
- <version>3.4.3</version>
- <type>pom</type>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-bindings-soap -->
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-bindings-soap</artifactId>
- <version>${cxf-core.version}</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-api -->
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-api</artifactId>
- <version>2.7.18</version>
- </dependency>
接着实现服务器端的代码
服务器端的代码有两部分一部分是WebService接口,一部分是发布WebService的配置类
接口定义(规范WSDL)
- import javax.jws.WebMethod;
- import javax.jws.WebParam;
- import javax.jws.WebService;
-
- /**
- * Webservice 发送数据
- * @author dhh
- */
- @WebService(serviceName = "WebServiceSender",
- targetNamespace="http://service.rebate.modules.jeecg.org/",
- endpointInterface = "org.jeecg.modules.rebate.service.WebServiceServer")
- public interface WebServiceServer {
-
-
- @WebMethod(operationName = "Invoke")
- void invoke(@WebParam(name="from",targetNamespace = "http://service.rebate.modules.jeecg.org/")String from,
- @WebParam(name="token",targetNamespace = "http://service.rebate.modules.jeecg.org/")String token,
- @WebParam(name="funcName",targetNamespace = "http://service.rebate.modules.jeecg.org/")String funcName,
- @WebParam(name="parameters",targetNamespace = "http://service.rebate.modules.jeecg.org/")String parameters) throws Exception;
- }
实现类(接收到请求后服务器端做处理)
- import lombok.extern.slf4j.Slf4j;
- import org.jeecg.modules.rebate.service.WebServiceServer;
- import org.springframework.stereotype.Service;
-
- /**
- * @author dhh
- */
- @Slf4j
- @Service
- public class WebServiceSenderServiceImpl implements WebServiceServer {
-
- @Override
- public void invoke(String from, String token, String funcName, String parameters) throws Exception {
- if("数据来源".equals(from)){
- switch (funcName) {
- }
- }else{
- log.info("未知来源的数据{},禁止写入!",from);
- throw new Exception("未知来源的数据,禁止写入");
- }
- }
- }
配置类(发布服务)
- import org.apache.cxf.jaxws.EndpointImpl;
- import org.apache.cxf.Bus;
- import org.apache.cxf.bus.spring.SpringBus;
- import org.apache.cxf.phase.Phase;
- import org.apache.cxf.transport.servlet.CXFServlet;
- import org.jeecg.modules.rebate.service.WebServiceServer;
- import org.jeecg.modules.rebate.service.impl.WebServiceSenderServiceImpl;
- import org.springframework.boot.web.servlet.ServletRegistrationBean;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import javax.xml.ws.Endpoint;
-
-
- /**
- * @author dhh
- */
- @Configuration
- public class WebServiceConfig {
-
- @Bean(name = "cxfServlet") // 注入servlet bean name不能dispatchlet ,否则会覆盖dispatcherServlet
- public ServletRegistrationBean<CXFServlet> cxfServlet() {
- return new ServletRegistrationBean<CXFServlet>(new CXFServlet(), "/webservice/*");
- }
- @Bean
- public WebServiceServer webServiceSender() {
- return new WebServiceSenderServiceImpl();
- }
-
- @Bean(name = Bus.DEFAULT_BUS_ID)
- public SpringBus springBus() {
- return new SpringBus();
- }
- @Bean
- public Endpoint endpoint() {
- // 参数二,是SEI实现类对象
- EndpointImpl endpoint = new EndpointImpl(this.springBus(),this.webServiceSender());
- // 发布服务
- endpoint.publish("/server");
- return endpoint;
- }
-
- }
接下来启动项目访问/webservice/server?wsdl 就可以看看WSDL的内容了。
然后搭建客户端
客户端搭建很简单,就是用http发送一个xml,困难在xml数据的格式要遵守服务端定义的wsdl要求。比如命名空间要和服务端的一致(http://service.rebate.modules.jeecg.org/),参数数量和名称也要和服务端定义的一致方可
- import lombok.extern.slf4j.Slf4j;
- import org.dom4j.Document;
- import org.dom4j.DocumentException;
- import org.dom4j.DocumentHelper;
- import org.dom4j.Element;
- import org.jeecg.modules.rebate.bean.WebServiceRequest;
- import org.jeecg.modules.rebate.entity.AttachmentInfo;
- import org.jeecg.modules.rebate.entity.ProjectInfo;
- import org.jeecg.modules.rebate.entity.ProjectScope;
- import org.jeecg.modules.rebate.service.WebServiceClientService;
- import org.springframework.stereotype.Service;
-
- import java.io.*;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.nio.charset.StandardCharsets;
- import java.util.List;
- import java.util.Map;
-
- /**
- * @author dhh
- */
- @Slf4j
- @Service
- public class WebServiceClientServiceImpl implements WebServiceClientService {
- /**
- * 发送请求,发送请求时,将数据封装起来
- */
- @Override
- public String send(WebServiceRequest request, String xmlEntry) {
- try {
- URL url = new URL(request.getRequestUrl());
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setRequestMethod("POST");
- connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
- connection.setDoOutput(true);
- connection.setDoInput(true);
- String xml = this.requestXmlBuilder(request.getEsbCode(), request.getComp(),request.getFrom(),request.getToken(), request.getFuncName(), xmlEntry);
- connection.setRequestProperty("Content-Length",String.valueOf(xml.length()));
- OutputStream out = connection.getOutputStream();
- out.write(xml.getBytes(StandardCharsets.UTF_8));
- int responseCode = connection.getResponseCode();
- if(responseCode==200){
- InputStream in = connection.getInputStream();
- String result = getResult(in);
- log.info(result);
- return result;
- }
- } catch (IOException e) {
- log.error(e.getMessage());
- }
- return "ERROR";
- }
这里我将构建xml单独写了一个方法,可以根据服务端WSDL规范自行定义
- private String requestXmlBuilder(String esbCode,String COMP,String from ,String token,String funcName,String xml){
- StringBuffer buffer= new StringBuffer();
- buffer.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:boi=\"http://service.rebate.modules.jeecg.org/\">");
- buffer.append("<soapenv:Header>");
- buffer.append("<extraParams>");
- buffer.append("<esbCode>");
- // esbCode:数据
- buffer.append(esbCode);
- buffer.append("</esbCode>");
-
- buffer.append("<COMP>");
- // COMP:数据
- buffer.append(COMP);
- buffer.append("</COMP>");
- buffer.append("</extraParams>");
- buffer.append("</soapenv:Header>");
- buffer.append("<soapenv:Body>");
- buffer.append("<boi:Invoke>");
- buffer.append("<boi:from>");
- buffer.append(from);
- buffer.append("</boi:from>");
- buffer.append("<boi:token>");
- buffer.append(token);
- buffer.append("</boi:token>");
- buffer.append("<boi:funcName>");
- // funcName:数据
- buffer.append(funcName);
- buffer.append("</boi:funcName>");
- buffer.append("<boi:parameters><![CDATA[");
- // XML:数据
- buffer.append(xml);
- buffer.append("]]></boi:parameters>");
- buffer.append("</boi:Invoke>");
- buffer.append("</soapenv:Body>");
- buffer.append("</soapenv:Envelope>");
- return buffer.toString();
-
- }
后面直接调用客户端方法请求本地服务端就可以测试客户端了,以上结束。
Apache CXF -- Developing a Service
后面还有拦截器的用法,感兴趣的可以了解一下!