springboot(十)集成CXF发布webservice以及客户端调用

x33g5p2x  于2021-12-17 转载在 其他  
字(6.8k)|赞(0)|评价(0)|浏览(571)

概述:

    Web service是一个pin独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。

    更多理论知识请自行百度一下。 

sprinboot集成cxf:

新建项目:springboot-webservice,pom.xml:

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-test</artifactId>
  5. <scope>test</scope>
  6. </dependency>
  7. <!--cxf依赖-->
  8. <dependency>
  9. <groupId>org.apache.cxf</groupId>
  10. <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
  11. <version>3.3.1</version>
  12. </dependency>
  13. </dependencies>

新建接口DemoService

  1. @javax.jws.WebService(name="DemoService",targetNamespace = "http://service.springbootwebservice.example.com")
  2. public interface DemoService {
  3. @WebMethod
  4. String say(@WebParam(name = "name") String name);
  5. }

   @WebService :该注解用于对接口,类进行注解,表示要发布的web服务

              name :暴露服务名称

              targetNamespace : 命名空间,一般为接口的包名的倒序

   @WebMethod:该注解用于用@WebService注解的类或接口的方法上,表示要发布的方法:

   @WebParam:该注解表示方法的参数

实现类DemoServiceImpl.java:

  1. @javax.jws.WebService( serviceName = "DemoService"
  2. ,targetNamespace = "http://service.springbootwebservice.example.com"
  3. ,endpointInterface = "com.example.springbootwebservice.service.DemoService")
  4. @Component
  5. public class DemoServiceImpl implements DemoService {
  6. @Override
  7. public String say(String name) {
  8. return "我是:" + name;
  9. }
  10. }

**     @WebService** :该注解用于对接口,类进行注解,表示要发布的web服务

               serviceName :服务名 与接口中指定的name一致

               targetNamespace:接口包名倒叙,并且和接口定义保持一致

               endpointInterface:接口地址

  编写拦截器AuthInterceptor.java:用于访问用户验证       

  1. import java.util.List;
  2. import javax.xml.soap.SOAPException;
  3. import org.apache.cxf.binding.soap.SoapHeader;
  4. import org.apache.cxf.binding.soap.SoapMessage;
  5. import org.apache.cxf.headers.Header;
  6. import org.apache.cxf.interceptor.Fault;
  7. import org.apache.cxf.phase.AbstractPhaseInterceptor;
  8. import org.apache.cxf.phase.Phase;
  9. import org.springframework.util.StringUtils;
  10. import org.w3c.dom.Element;
  11. import org.w3c.dom.NodeList;
  12. public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
  13. //默认登陆用户
  14. private String USERNAME="admin";
  15. //默认登陆用户密码
  16. private String PASSWORD="123456";
  17. public AuthInterceptor() {
  18. // 定义在什么阶段进行拦截
  19. super(Phase.PRE_PROTOCOL);
  20. }
  21. @Override
  22. public void handleMessage(SoapMessage soapMessage) throws Fault {
  23. String username = null;
  24. String password = null;
  25. List<Header> headers = soapMessage.getHeaders();
  26. if(headers == null) {
  27. throw new Fault(new IllegalArgumentException("headers未取到,无法验证用户信息"));
  28. }
  29. // 获取客户端传递的用户名和密码
  30. for (Header header : headers) {
  31. SoapHeader soapHeader = (SoapHeader) header;
  32. Element e = (Element) soapHeader.getObject();
  33. NodeList usernameNode = e.getElementsByTagName("username");
  34. NodeList passwordNode = e.getElementsByTagName("password");
  35. username = usernameNode.item(0).getTextContent();
  36. password = passwordNode.item(0).getTextContent();
  37. if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
  38. throw new Fault(new IllegalArgumentException("用户信息为空!"));
  39. }
  40. }
  41. // 校验客户端用户名密码是否和服务端一致
  42. if(!(username.equals(USERNAME) && password.equals(PASSWORD))) {
  43. throw new Fault(new SOAPException("用户信息认证失败!"));
  44. }
  45. }
  46. }

配置类CxfConfig.java:

  1. @Configuration
  2. public class CxfConfig {
  3. /**
  4. * 此方法作用是改变项目中服务名的前缀名
  5. * wsdl的默认访问地址为http://127.0.0.1:8080/services/* 也就是/service/*
  6. * 我们可以自己配置:wsdl访问地址为:http://127.0.0.1:8080/webservice/*
  7. * 这里我们自定义服务名为/webservice/*
  8. * 当然还可以直接在application.properties文件中加上cxf.path=/webservice
  9. * @return
  10. */
  11. @Bean
  12. public ServletRegistrationBean servletRegistrationBean() {
  13. ServletRegistrationBean bean = new ServletRegistrationBean(
  14. new CXFServlet(), "/webservice/*");
  15. bean.setLoadOnStartup(0);
  16. bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
  17. return bean;
  18. }
  19. @Bean(name = Bus.DEFAULT_BUS_ID)
  20. public SpringBus springBus() {
  21. return new SpringBus();
  22. }
  23. //把实现类交给spring管理
  24. @Bean
  25. public DemoService webService() {
  26. return new DemoServiceImpl();
  27. }
  28. //终端路径
  29. @Bean
  30. public Endpoint endpoint() {
  31. //绑定要发布的服务
  32. EndpointImpl endpoint = new EndpointImpl(springBus(), webService());
  33. // 服务端添加自定义拦截器 不需要验证可以省略此方法
  34. endpoint.getInInterceptors().add(new AuthInterceptor());
  35. //绑定要发布的服务名称
  36. endpoint.publish("/ws");
  37. return endpoint;
  38. }
  39. }

编写拦截器ClientInterceptor.java:用于在请求头添加用户信息用于验证

  1. import java.util.List;
  2. import javax.xml.namespace.QName;
  3. import org.apache.cxf.binding.soap.SoapMessage;
  4. import org.apache.cxf.headers.Header;
  5. import org.apache.cxf.helpers.DOMUtils;
  6. import org.apache.cxf.interceptor.Fault;
  7. import org.apache.cxf.phase.AbstractPhaseInterceptor;
  8. import org.apache.cxf.phase.Phase;
  9. import org.w3c.dom.Document;
  10. import org.w3c.dom.Element;
  11. public class ClientInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
  12. //登陆用户
  13. private String username;
  14. //登陆密码
  15. private String password;
  16. public ClientInterceptor(String username, String password) {
  17. // 发送请求之前进行拦截
  18. super(Phase.PREPARE_SEND);
  19. this.username = username;
  20. this.password = password;
  21. }
  22. @Override
  23. public void handleMessage(SoapMessage soapMessage) throws Fault {
  24. List<Header> headers = soapMessage.getHeaders();
  25. Document doc = DOMUtils.createDocument();
  26. Element auth = doc.createElement("authrity");
  27. Element username = doc.createElement("username");
  28. Element password = doc.createElement("password");
  29. username.setTextContent(this.username);
  30. password.setTextContent(this.password);
  31. auth.appendChild(username);
  32. auth.appendChild(password);
  33. headers.add(0, new Header(new QName("tiamaes"), auth));
  34. }
  35. }

编写客户端CxfClient.java

  1. public class Cxfclient {
  2. // 服务端接口地址
  3. private static String address = "http://localhost:8080/webservice/ws?wsdl";
  4. public static void main(String[] args) {
  5. method1();
  6. method2();
  7. }
  8. /**
  9. * 方式1.代理类工厂方式,需要拿到对方的接口
  10. */
  11. public static void method1() {
  12. try {
  13. // 代理工厂
  14. JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
  15. // 设置代理地址
  16. jaxWsProxyFactoryBean.setAddress(address);
  17. // 添加用户信息验证
  18. jaxWsProxyFactoryBean.getOutInterceptors().add(new ClientInterceptor("admin", "123456"));
  19. // 设置接口类型
  20. jaxWsProxyFactoryBean.setServiceClass(DemoService.class);
  21. // 创建一个代理接口实现
  22. DemoService ws = (DemoService) jaxWsProxyFactoryBean.create();
  23. // 调用代理接口的方法调用并返回结果
  24. String result = ws.say("lisi");
  25. System.out.println("代理类工厂方式返回结果:" + result);
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. /**
  31. * 动态调用方式
  32. */
  33. public static void method2() {
  34. // 创建动态客户端
  35. JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
  36. Client client = dcf.createClient(address);
  37. // 添加用户信息验证
  38. client.getOutInterceptors().add(new ClientInterceptor("admin", "123456"));
  39. Object[] objects = new Object[0];
  40. try {
  41. // invoke("方法名",参数1,参数2,参数3....);
  42. objects = client.invoke("say", "zhangsan");
  43. System.out.println("动态调用方式结果:" + objects[0]);
  44. } catch (java.lang.Exception e) {
  45. e.printStackTrace();
  46. }
  47. }
  48. }

    注:如果不想要登陆验证请注释以下代码:

           1.CxfConfig.java类中endpoint()方法中:endpoint.getInInterceptors().add(new AuthInterceptor());

           2.Cxfclient.java类中动态调用方法中:client.getOutInterceptors().add(new ClientInterceptor("admin", "123456"));

           3.Cxfclient.java类中工厂调用方法中:jaxWsProxyFactoryBean.getOutInterceptors().add(new ClientInterceptor("admin", "123456"));

          其实注释1就可以啦,2、3不注释也没啥影响的。个人习惯!

源码地址https://gitee.com/xu0123/springboot2

相关文章