Web Service项目

Web Service项目

目录




内容

这里我使用的开发工具IDEA,要测试多对服务端与客户端,这里就简单的搭建个父子工程,只是为了方便。

1、web service入门

1.1、基础理论知识

理论知识部分这里不再详述,可自行查阅相关文档或者参考文章末尾提到的前辈们的博客。

1.2、入门项目

  • 注解:WebService
  • 类:Endpoint 用于发布服务

这里我们做个简单的天气查询。

  • 实现功能:输入城市名称,获取城市对于的天气描述。

入门项目我们用jdk原生的类库实现。

1.2.1、服务端

  • 工程目录结构如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QZ2bNf7x-1601046420364)(./images/2020-09-24_ws-introduction-server.png)]

  • 相关源代码如下:

    • 接口WeatherService.java

        package com.gaogzhen.service;
      
        import javax.jws.WebService;
      
        @WebService
        public interface WeatherService {
        	String queryWeather(String cityName);
        }
      
    • 接口实现类:WeatherServiceImpl.java

        package com.gaogzhen.service.impl;
      
        import com.gaogzhen.service.WeatherService;
      
        import javax.jws.WebService;
      
        @WebService
        public class WeatherServiceImpl implements WeatherService {
        	@Override
        	public String queryWeather(String cityName) {
        		String weather = null;
        		switch (cityName) {
        			case "济南":
        				weather = "秋高气爽";
        				break;
        			case "泰安":
        				weather = "风和日丽";
        			default:
        				weather = "七月流火";
        		}
        		return weather;
        	}
        }
      
    • 服务端(发布类):WeatherServer.java

        package com.gaogzhen;
      
        import com.gaogzhen.service.impl.WeatherServiceImpl;
      
        import javax.xml.ws.Endpoint;
      
        public class WeatherServer {
        	public static void main(String[] args) {
        		Endpoint.publish("http://127.0.0.1:9000/weather", new WeatherServiceImpl());
        	}
        }
      

点击左侧绿色三角或者右键运行服务(发布服务),如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j7ZwKAe6-1601046420366)(./images/2020-09-24_ws-introduction-server-run_1.png)]

至此,服务端运行

1.2.2、简单测试

浏览器输入:http://127.0.0.1:9000/weather?wsdl,查看服务端自动生成的wsdl文档,如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cK3iP4zg-1601046420367)(./images/2020-09-24_ws-introduction-server-wsdl.png)]

1.2.2、客户端测试

客户端测试有几种实现方式:普通浏览器调用方式,Ajax调用,原生jdk,QName方式,URLConnection方式等等。

这里只接受常用的原生jdk及推荐的QName方式。

其中QName方式在下面的测试通过公共服务获取电话号码信息中介绍。

  • 命令:

      wsimport 是jdk自带的生成WebService客户端的命令
      -s 路径 在指定路径下面生成带源码的客户端
    

步骤:

  1. 创建客户端项目,就是最简单的maven项目

  2. 进入java包所在的文件夹,如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KhIhzWRo-1601046420369)(./images/2020-09-24_ws-introduction-client-show-in-explore.png)]

  3. SHIFT+右键或者地址栏输入powershell(没有就输入cmd) ,选择进入powershell(没有就用cmd),如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GrCAU0GZ-1601046420370)(./images/2020-09-24_ws-introduction-client-powershell-before.png)]
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gnASExV0-1601046420372)(./images/2020-09-24_ws-introduction-client-right-powershell-before.png)]

  4. 输入命令:wsimport -s . http://127.0.0.1:9000/weather?wsdl

  5. java包下自动生成客户端代码,.class文件不需要,删除即可,如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j83M1Xa5-1601046420372)(./images/2020-09-24_ws-introduction-client-struction.png)]

  6. 下面编写客户端测试代码WeatherClient.java,如下:

     package com.gaogzhen;
    
     import com.gaogzhen.service.impl.WeatherServiceImpl;
     import com.gaogzhen.service.impl.WeatherServiceImplService;
    
     public class WeatherClient {
     	public static void main(String[] args) {
     		WeatherServiceImplService service = new WeatherServiceImplService();
     		WeatherServiceImpl implPort = service.getWeatherServiceImplPort();
     		String weather = implPort.queryWeather("济南");
     		System.out.println(weather);
     	}
     }
    

点击运行,结果出来了,但是出了点小状况,如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lbimaeM0-1601046420373)(./images/2020-09-24_ws-introduction-client-result-code.png)]

解决方案:

  1. 点击图示Edit Configuratins:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SRhE1HBb-1601046420374)(./images/2020-09-24_ws-introduction-client-edit-configurations.png)]

  2. 如图修改编码:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-35HrdQhV-1601046420375)(./images/2020-09-24_ws-introduction-client-encoding_1.png)]

  3. 重新运行,乱码问题解决,如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7RltLSuz-1601046420375)(./images/2020-09-24_ws-introduction-client-normal.png)]

1.3、调用公网的手机归属地查询服务

1.3.1、普通方式客户端实现

公网服务地址 (里面提供了很多免费调用的服务):http://www.webxml.com.cn/zh_cn/index.aspx

步骤:

  1. 创建maven普通工程

  2. 切换到java包下,执行生成客户端代码命令:

     wsimport  -s . http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
    
  3. 编写客户端测试类MobileClient.java,代码如下:

     package com.gaogzhen;
    
     import cn.com.webxml.MobileCodeWS;
     import cn.com.webxml.MobileCodeWSSoap;
    
     public class MobileClient {
     	public static void main(String[] args) {
     		MobileCodeWS mobileCodeWS = new MobileCodeWS();
     		MobileCodeWSSoap soap = mobileCodeWS.getPort(MobileCodeWSSoap.class);
     		String info = soap.getMobileCodeInfo("188xxxxxxxx", null); // 电话号码自己输入
     		System.out.println(info);
     	}
     }
    
  4. 运行客户端,结果如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m3ZuOaUR-1601046420376)(./images/2020-09-24_ws-mobile-client-result.png)]

1.3.2、QName方式客户端

生成客户端方式同上
步骤:

  1. 创建普通Maven项目

  2. 切换到java包所在的目录,生成客户端代码,命令同上,改下地址

  3. 编写客户端测试类MobileClient.java,代码如下:

     package gaogzhen;
    
     import webxml.MobileCodeWSSoap;
    
     import javax.xml.namespace.QName;
     import javax.xml.ws.Service;
     import java.net.MalformedURLException;
     import java.net.URL;
    
     public class MobileClient {
     	public static void main(String[] args) throws MalformedURLException {
     		URL wsdl = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl");
     		QName serviceName = new QName("http://WebXml.com.cn/", "MobileCodeWS");
     		Service service = Service.create(wsdl, serviceName);
     		MobileCodeWSSoap soap = service.getPort(MobileCodeWSSoap.class);
     		String info = soap.getMobileCodeInfo("188xxxxxxxxx", null);
     		System.out.println(info);
     	}
     }
    

结果同上

2、CXF框架

2.1、理论知识

理论知识部分这里不再详述,可自行查阅相关文档或者参考文章末尾提到的前辈们的博客。

2.2、项目实践

2.2.1、cxf 类库

2.2.1.1、服务端

步骤同上

  1. pom.xml配置文件依赖如下:

     <dependencies>
     		<dependency>
     			<groupId>org.apache.cxf</groupId>
     			<artifactId>cxf-rt-frontend-jaxws</artifactId>
     			<version>3.3.5</version>
     		</dependency>
     		<dependency>
     			<groupId>org.apache.cxf</groupId>
     			<artifactId>cxf-rt-transports-http</artifactId>
     			<version>3.3.5</version>
     		</dependency>
     		<dependency>
     			<groupId>org.apache.cxf</groupId>
     			<artifactId>cxf-rt-transports-http-jetty</artifactId>
     			<version>3.3.5</version>
     		</dependency>
     	</dependencies>
    
  2. 项目目录结构,如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XhPKsebi-1601046420377)(./images/2020-09-24_ws-cxf-struction.png)]

  3. 源码代码如下

    1. WeatherService.java

      package com.gaogzhen.service;
      
      import javax.jws.WebParam;
      import javax.jws.WebResult;
      import javax.jws.WebService;
      
      @WebService(
      		targetNamespace = "http://service.gaogzhen.com",
      		portName = "WeatherWSImpl",
      		serviceName = "WeatherWS",
      		name = "WeatherSOAP"
      )
      public interface WeatherService {
      	public @WebResult(name = "result") String queryWeather(@WebParam(name = "cityName") String cityName);
      }
      
    2. WeatherServiceImpl.java

      package com.gaogzhen.service.impl;
      
      import com.gaogzhen.service.WeatherService;
      
      import javax.jws.WebParam;
      import javax.jws.WebResult;
      import javax.jws.WebService;
      
      @WebService(
      		targetNamespace = "http://service.gaogzhen.com",
      		portName = "WeatherWSImpl",
      		serviceName = "WeatherWS",
      		name = "WeatherSOAP"
      )
      public class WeatherServiceImpl implements WeatherService {
      	@Override
      	public @WebResult(name = "result") String queryWeather(@WebParam(name = "cityName") String cityName) {
      		String weather = null;
      		switch (cityName) {
      			case "济南":
      				weather = "秋高气爽";
      				break;
      			case "泰安":
      				weather = "风和日丽";
      			default:
      				weather = "七月流火";
      		}
      		return weather;
      	}
      }
      
    3. WeatherServer.java

      package com.gaogzhen;
      
      import com.gaogzhen.service.WeatherService;
      import com.gaogzhen.service.impl.WeatherServiceImpl;
      import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
      
      public class WeatherServer {
      	public static void main(String[] args) {
      		JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
      		factoryBean.setServiceClass(WeatherService.class);
      		factoryBean.setServiceBean(new WeatherServiceImpl());
      		factoryBean.setAddress("http://127.0.0.1:9001/weather");
      		factoryBean.create();
      		System.out.println("====服务开启===");
      	}
      }
      
  4. 启动服务端

解析:

  1. pom.xml配置文件中的依赖版本根据需要自己选择
  2. 关于WebService注解相关知识自行查阅相关文档
  3. 注解不会继承所以我们在接口及其实现类上都加了相同的注解
2.2.1.1、客户端

这里cxf提供了生成客户端的工具,apache-cxf-3.1.18,具体版本,根据需要自己去apache官网下载

步骤:

  1. 创建普通Maven工程,引入依赖同上

  2. 切换到java包对于的目录,进入命令行,执行客户端生成命令

     wsdl2java  -d . http://127.0.0.1:9001/weather?wsdl 
     -d 路径 生成到指定的目录下
    
  3. 编写客户端测试类代码WeatherClient.java,代码如下:

    import com.gaogzhen.service.WeatherSOAP;
    import com.gaogzhen.service.WeatherWS;
    import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
    
    public class WeatherCxfClient {
    	public static void main(String[] args) {
    		JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
    		factory.setServiceClass(WeatherSOAP.class);
    		factory.setAddress("http://127.0.0.1:9001/weather");
    		WeatherSOAP service = (WeatherSOAP)factory.create();
    		String weather = service.queryWeather("济南");
    		System.out.println(weather);
    	}
    }
    
  4. 启动客户端查看测试结果

2.2.2、cxf整合spring web

相关介绍:

  1. 这里我们整合spring web,mybatis,cxf,数据库使用mysql,日志用logback
  2. 实现根据用户id查询数据库中用户表中用户信息的功能
2.2.2.1、服务端

步骤:

  1. 创建Maven web工程,引入相关依赖,其中父工程,项目名为自己的(不要照抄)pom.xml如下:

     <?xml version="1.0" encoding="UTF-8"?>
    
     <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
       <parent>
     	<artifactId>webservice</artifactId>
     	<groupId>com.gaogzhen</groupId>
     	<version>1.0-SNAPSHOT</version>
       </parent>
       <modelVersion>4.0.0</modelVersion>
    
       <artifactId>ws-cxf-spring-web</artifactId>
    
       <properties>
     	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     	<maven.compiler.source>1.8</maven.compiler.source>
     	<maven.compiler.target>1.8</maven.compiler.target>
       </properties>
    
       <dependencies>
     	<dependency>
     	  <groupId>javax.servlet</groupId>
     	  <artifactId>javax.servlet-api</artifactId>
     	  <version>3.1.0</version>
     	  <scope>provided</scope>
     	</dependency>
     	<!-- spring-web -->
     	<dependency>
     	  <groupId>org.springframework</groupId>
     	  <artifactId>spring-web</artifactId>
     	  <version>5.2.6.RELEASE</version>
     	</dependency>
     	<dependency>
     	  <groupId>org.springframework</groupId>
     	  <artifactId>spring-context</artifactId>
     	  <version>5.2.6.RELEASE</version>
     	</dependency>
    
     	<dependency>
     	  <groupId>org.apache.cxf</groupId>
     	  <artifactId>cxf-rt-frontend-jaxws</artifactId>
     	  <version>3.1.18</version>
     	</dependency>
     	<dependency>
     	  <groupId>org.apache.cxf</groupId>
     	  <artifactId>cxf-rt-transports-http</artifactId>
     	  <version>3.1.18</version>
     	</dependency>
    
     	<dependency>
     	  <groupId>org.springframework</groupId>
     	  <artifactId>spring-jdbc</artifactId>
     	  <version>5.2.6.RELEASE</version>
     	</dependency>
     	<dependency>
     	  <groupId>mysql</groupId>
     	  <artifactId>mysql-connector-java</artifactId>
     	  <version>8.0.20</version>
     	</dependency>
     	<dependency>
     	  <groupId>org.mybatis</groupId>
     	  <artifactId>mybatis</artifactId>
     	  <version>3.5.3</version>
     	</dependency>
     	<dependency>
     	  <groupId>org.mybatis</groupId>
     	  <artifactId>mybatis-spring</artifactId>
     	  <version>2.0.1</version>
     	</dependency>
     	<dependency>
     	  <groupId>com.alibaba</groupId>
     	  <artifactId>druid</artifactId>
     	  <version>1.1.10</version>
     	</dependency>
     	<dependency>
     	  <groupId>com.github.pagehelper</groupId>
     	  <artifactId>pagehelper</artifactId>
     	  <version>5.1.10</version>
     	</dependency>
    
     	<dependency>
     	  <groupId>org.projectlombok</groupId>
     	  <artifactId>lombok</artifactId>
     	  <version>1.18.10</version>
     	  <scope>provided</scope>
     	</dependency>
     	<dependency>
     	  <groupId>ch.qos.logback</groupId>
     	  <artifactId>logback-classic</artifactId>
     	  <version>1.2.3</version>
     	</dependency>
    
     	<dependency>
     	  <groupId>commons-codec</groupId>
     	  <artifactId>commons-codec</artifactId>
     	  <version>1.10</version>
     	</dependency>
       </dependencies>
    
       <build>
     	<finalName>ws-cxf-spring-web</finalName>
       </build>
     </project>
    
    • 其中有些依赖现在用不到,将来完成的项目可能用到,比如pagehelper实现分页功能的等等,这里只是示范案例,不会用到这些功能。
  2. 数据库中用户表sys_user.sql,数据库导出的,可直接导入某个数据库下面使用,或者自己简单创建个用户表,如下:

     DROP TABLE IF EXISTS `sys_user`;
     CREATE TABLE `sys_user`  (
       `id` int(11) NOT NULL AUTO_INCREMENT,
       `balance` int(11) NULL DEFAULT NULL,
       `username` varchar(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '用户名',
       `password` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '密码',
       `age` int(11) NULL DEFAULT NULL COMMENT '年龄',
       `email` varchar(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '邮箱',
       `user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '用户id',
       `status` int(11) NOT NULL DEFAULT 0 COMMENT '用户状态,0未激活,1:已激活',
       `create_time` datetime(0) NULL DEFAULT NULL,
       PRIMARY KEY (`id`) USING BTREE,
       UNIQUE INDEX `idx_name`(`username`) USING BTREE
     ) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
    
     -- ----------------------------
     -- Records of sys_user
     -- ----------------------------
     INSERT INTO `sys_user` VALUES (1, 1000, 'etoak', 'e10adc3949ba59abbe56e057f20f883e', 20, 'asd', '123', 0, '2020-08-14 15:31:50');
     INSERT INTO `sys_user` VALUES (2, 1000, 'zs', 'e10adc3949ba59abbe56e057f20f883e', 22, '123123', '1231', 0, '2020-08-24 15:32:06');
     INSERT INTO `sys_user` VALUES (3, 1000, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 12, 'sss', '123', 0, '2020-08-14 17:52:50');
     INSERT INTO `sys_user` VALUES (4, 1000, 'ww', 'e10adc3949ba59abbe56e057f20f883e', 22, '431103832@qq.com', '6f8c38f9f92e4a3a9f898ae26561454a', 0, '2020-08-25 17:11:40');
     INSERT INTO `sys_user` VALUES (6, 1000, '张三', 'e10adc3949ba59abbe56e057f20f883e', 19, '431103832@qq.com', '1e43bb4da55347e48124fff97bf4a3f2', 0, '2020-08-25 17:16:32');
     INSERT INTO `sys_user` VALUES (7, 1000, '2002', 'e10adc3949ba59abbe56e057f20f883e', 20, '431103832@qq.com', '7969c4d821d84741868b5674f9fe8260', 0, '2020-08-26 09:55:14');
     INSERT INTO `sys_user` VALUES (8, NULL, '111', '123456', 20, '1111@126.com', '1f7649773a194f6d81aca46f91f2b49f', 0, '2020-09-18 17:02:10');
     INSERT INTO `sys_user` VALUES (9, NULL, 'gaogzhen', '123456', 33, 'g2zh@163.com', '7f1fb8a1d3f743cda8e6828c2f30c386', 0, '2020-09-19 10:56:08');
    
  3. 项目结构如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zpsUy0wx-1601046420378)(./images/2020-09-24_ws-cxf-springweb-stuction.png)]

    • User.java代码

        package com.etoak.bean;
      
        import lombok.AllArgsConstructor;
        import lombok.Data;
        import lombok.NoArgsConstructor;
      
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        public class User {
        	private Integer id;
        	private String username;
        	private Integer age;
        	private String email;
        }
      
    • UserMapper.java

        package com.etoak.mapper;
      
        import com.etoak.bean.User;
      
        public interface UserMapper {
        	User queryById(int id);
        }
      
    • UserService

        package com.etoak.service;
      
        import com.etoak.bean.User;
      
        import javax.jws.WebParam;
        import javax.jws.WebService;
      
        @WebService(
        		serviceName = "UserServiceWs",
        		portName = "UserServicePort"
        )
        public interface UserService {
        	User queryById(@WebParam(name = "id") int id);
        }
      
    • UserServiceImpl

        package com.etoak.service.impl;
      
        import com.etoak.bean.User;
        import com.etoak.mapper.UserMapper;
        import com.etoak.service.UserService;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Service;
      
        import javax.jws.WebParam;
        import javax.jws.WebService;
      
        @WebService(
        		serviceName = "UserServiceWs",
        		portName = "UserServicePort"
        )
        @Service
        public class UserServiceImpl implements UserService {
      
        	@Autowired
        	UserMapper userMapper;
      
        	@Override
        	public User queryById(@WebParam(name = "id") int id) {
        		return userMapper.queryById(id);
        	}
        }
      
    • UserMapper,.xml

        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE mapper
        		PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        		"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
        <mapper namespace="com.etoak.mapper.UserMapper">
        	<select id="queryById" resultType="user">
        		select  id,
        				username,
        				age,
        				email
        		from sys_user
        		where id = #{value}
        	</select>
        </mapper>
      
    • jdbc.properties

        jdbc.driver=com.mysql.cj.jdbc.Driver
        jdbc.url=jdbc:mysql://127.0.0.1:3306/et2003
        jdbc.username=root
        jdbc.password=root
      
    • logback.xml

        <?xml version="1.0" encoding="UTF-8"?>
        <!--
         scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 
         scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。 当scan为true时,此属性生效。默认的时间间隔为1分钟(60 seconds)。 
         debug: 当此属性设置为true时,将打印出logback内部日志信息, 默认值为false。 -->
        <configuration scan="true" scanPeriod="120 seconds" debug="false">
      
        	<!-- 定义日志文件所在目录 -->
        	<property name="LOG_HOME" value="D:/logs/" />
      
        	<!--控制台输出 -->
        	<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        		<encoder>
        			<!--解决乱码问题 -->
        			<charset>UTF-8</charset>
        			<!--格式化输出:PatternLayout
        				%d表示日期,
        				%thread表示线程名,
        				%-5level:级别从左显示5个字符宽度
        				%logger输出日志的logger名 
        				%msg:日志消息
        				%n是换行符
        			 -->
        			<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger{36}: %msg%n</pattern>
        		</encoder>
        	</appender>
      
        	<!--滚动文件 -->
        	<appender name="infoLogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        		<!-- 过滤掉ERROR日志 -->
        		<filter class="ch.qos.logback.classic.filter.LevelFilter">
        			<level>ERROR</level>
        			<onMatch>DENY</onMatch>
        			<onMismatch>ACCEPT</onMismatch>
        		</filter>
      
        		<encoder>
        			<charset>UTF-8</charset>
        			<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger{36}: %msg%n</pattern>
        		</encoder>
        		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        			<fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}.log</fileNamePattern>
        			<maxHistory>30</maxHistory><!--保存最近30天的日志 -->
        		</rollingPolicy>
        	</appender>
      
        	<!--滚动文件 -->
        	<appender name="errorLogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        		<!-- ThresholdFilter:临界值过滤器,只输出级别等于或高于给定的临界值(日志级别)-->
        		<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        			<level>ERROR</level>
        		</filter>
        		<encoder>
        			<charset>UTF-8</charset>
        			<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger{36}: %msg%n</pattern>
        		</encoder>
        		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        			<fileNamePattern>${LOG_HOME}/error_%d{yyyy-MM-dd}.log</fileNamePattern>
        			<!--保存最近30天的日志 -->
        			<maxHistory>30</maxHistory>
        		</rollingPolicy>
        	</appender>
      
        	<!--这里如果是info,spring、mybatis等框架则不会输出:TRACE < DEBUG < INFO < WARN < ERROR -->
        	<!--root是所有logger的祖先,均继承root,如果某一个自定义的logger没有指定level,就会寻找 父logger看有没有指定级别,直到找到root。 -->
        	<root level="info">
        		<appender-ref ref="stdout" />
        		<appender-ref ref="infoLogFile" />
        		<appender-ref ref="errorLogFile" />
        	</root>
      
        	<!--为某个包单独配置logger 比如定时任务,写代码的包名为:com.seentao.task 步骤如下: 1、定义一个appender,取名为task(随意,只要下面logger引用就行了) appender的配置按照需要即可 2、定义一个logger: 
        		<logger name="com.seentao.task" level="DEBUG" additivity="false"> <appender-ref ref="task" /> </logger> 注意:additivity必须设置为false,这样只会交给task这个appender,否则其他appender也会打印com.seentao.task里的log信息。 
        		3、这样,在com.seentao.task的logger就会是上面定义的logger了。 private static Logger logger = LoggerFactory.getLogger(Class1.class); -->
        	<appender name="mybatisSQL" 
        		class="ch.qos.logback.core.ConsoleAppender">
        		<encoder>
        			<charset>UTF-8</charset>
        			<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger{36}: %msg%n</pattern>
        		</encoder>
        	</appender>
      
        	<logger name="com.etoak.mapper" level="DEBUG" additivity="false">
        		<appender-ref ref="mybatisSQL" />
        	</logger>
      
        </configuration>
      
    • spring-cxf.xml

        <?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:p="http://www.springframework.org/schema/p"
        	   xmlns:context="http://www.springframework.org/schema/context"
        	   xmlns:jaxws="http://cxf.apache.org/jaxws"
        	   xmlns:core="http://cxf.apache.org/core"
        	   xsi:schemaLocation="http://www.springframework.org/schema/beans
        		http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        		http://cxf.apache.org/jaxws
        		http://cxf.apache.org/schemas/jaxws.xsd
        		http://cxf.apache.org/core
        		http://cxf.apache.org/schemas/core.xsd
        		http://www.springframework.org/schema/context
        		http://www.springframework.org/schema/context/spring-context-4.2.xsd">
      
        	<context:component-scan base-package="com.etoak" />
      
        	<!--
        		JaxWsServerFactoryBean
        		setAddress
        		setServiceClass
        		setServiceBean
        		create()
        	-->
        	<!-- http://ip:port/context/ws/user?wsdl -->
        	<jaxws:server address="/user"
        				  serviceClass="com.etoak.service.UserService">
        		<jaxws:serviceBean>
        			<ref bean="userServiceImpl" />
        		</jaxws:serviceBean>
        	</jaxws:server>
      
        	<context:property-placeholder location="classpath:jdbc.properties" />
        	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        		<property name="driverClassName" value="${jdbc.driver}" />
        		<property name="url" value="${jdbc.url}" />
        		<property name="username" value="${jdbc.username}" />
        		<property name="password" value="${jdbc.password}" />
        	</bean>
        	<bean class="org.mybatis.spring.SqlSessionFactoryBean">
        		<!-- 数据源、typeAliasesPackage、mapperLocations、plugins -->
        		<property name="dataSource" ref="dataSource" />
        		<property name="mapperLocations" value="classpath:mappers/*.xml" />
        		<property name="typeAliasesPackage" value="com.etoak.bean" />
        		<property name="plugins">
        			<list>
        				<bean class="com.github.pagehelper.PageInterceptor">
        					<property name="properties">
        						<props>
        							<prop key="reasonable">true</prop>
        						</props>
        					</property>
        				</bean>
        			</list>
        		</property>
        	</bean>
        	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        		<property name="basePackage" value="com.etoak.mapper" />
        	</bean>
      
        </beans>
      
    • web.xml

        <?xml version="1.0" encoding="UTF-8"?>
        <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        		 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
        		 version="4.0">
      
        	<context-param>
        		<param-name>contextConfigLocation</param-name>
        		<param-value>classpath:spring-cxf.xml</param-value>
        	</context-param>
      
        	<listener>
        		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        	</listener>
        	<servlet>
        		<servlet-name>cxfServlet</servlet-name>
        		<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        		<load-on-startup>1</load-on-startup>
        	</servlet>
        	<servlet-mapping>
        		<servlet-name>cxfServlet</servlet-name>
        		<url-pattern>/ws/*</url-pattern>
        	</servlet-mapping>
        </web-app>
      
  4. 配置tomcat服务器

    1. 主要是修改项目路径为 / ,tomcat详细配置自行查阅想文档,如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9JMXSF94-1601046420379)(./images/2020-09-24_ws-xcf-spring-web-server-tomcat.png)]
  5. 启动tomcat,至此server端完成

  6. 简单测试,浏览器中输入:http://127.0.0.1:8080/user?wsdl ,显示wsdl说明启动成功,如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-45fumaUN-1601046420380)(./images/2020-09-24_ws-xcf-spring-web-server-user-wsdl.png)]

2.2.2.2、客户端

步骤:

  1. 搭建Maven普通项目,pom.xml如下:

     <?xml version="1.0" encoding="UTF-8"?>
     <project xmlns="http://maven.apache.org/POM/4.0.0"
     		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     	<parent>
     		<artifactId>webservice</artifactId>
     		<groupId>com.gaogzhen</groupId>
     		<version>1.0-SNAPSHOT</version>
     	</parent>
     	<modelVersion>4.0.0</modelVersion>
    
     	<artifactId>ws-cxf-spring-client</artifactId>
    
     	<dependencies>
     		<dependency>
     			<groupId>org.springframework</groupId>
     			<artifactId>spring-context</artifactId>
     			<version>5.2.6.RELEASE</version>
     		</dependency>
    
     		<dependency>
     			<groupId>org.apache.cxf</groupId>
     			<artifactId>cxf-rt-frontend-jaxws</artifactId>
     			<version>3.1.18</version>
     		</dependency>
     		<dependency>
     			<groupId>org.apache.cxf</groupId>
     			<artifactId>cxf-rt-transports-http</artifactId>
     			<version>3.1.18</version>
     		</dependency>
     		<dependency>
     			<groupId>org.apache.cxf</groupId>
     			<artifactId>cxf-rt-transports-http-jetty</artifactId>
     			<version>3.1.18</version>
     		</dependency>
     		<dependency>
     			<groupId>junit</groupId>
     			<artifactId>junit</artifactId>
     			<version>4.12</version>
     			<scope>test</scope>
     		</dependency>
     	</dependencies>
    
     </project>
    
  2. 切换到java包下,执行命令生成客户端代码,命令如下:

     wsdl2java -d . http://127.0.0.1:9090/user?wsdl
    
  3. 创建客户端测试代码CxfSpringClient.java

     package com.etoak;
    
     import com.etoak.service.User;
     import com.etoak.service.UserService;
     import org.springframework.context.ApplicationContext;
     import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    
     public class CxfSpringClient {
     	public static void main(String[] args) {
     		ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring-cxf.xml");
     		UserService userService = ac.getBean(UserService.class);
    
     		User user = userService.queryById(1);
     		System.out.println(user);
     	}
     }
    
  4. resources包下创建spring.cxf.xml配置文件,内容如下:

     <?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:p="http://www.springframework.org/schema/p"
     	   xmlns:context="http://www.springframework.org/schema/context"
     	   xmlns:jaxws="http://cxf.apache.org/jaxws"
     	   xmlns:core="http://cxf.apache.org/core"
     	   xsi:schemaLocation="http://www.springframework.org/schema/beans
     		http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
     		http://cxf.apache.org/jaxws
     		http://cxf.apache.org/schemas/jaxws.xsd
     		http://cxf.apache.org/core
     		http://cxf.apache.org/schemas/core.xsd
     		http://www.springframework.org/schema/context
     		http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    
     	<jaxws:client id="userService"
     				  address="http://localhost:8080/ws/user"
     				  serviceClass="com.etoak.service.UserService">
     	</jaxws:client>
    
    
     </beans>
    
  5. 项目目录结构如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8GjwXbPr-1601046420381)(./images/2020-09-24_ws-xcf-spring-web-client-struction.png)]

  6. 第二中测试就是使用@Test注解,在上图中test包下创建com.etoak.testClient.java,代码如下:

     package com.etoak;
    
     import com.etoak.service.User;
     import com.etoak.service.UserService;
     import org.junit.Test;
     import org.springframework.context.ApplicationContext;
     import org.springframework.context.support.ClassPathXmlApplicationContext;
    
     public class TestClient {
    
     	@Test
     	public void testClient() {
     		ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring-cxf.xml");
     		UserService userService = ac.getBean(UserService.class);
    
     		User user = userService.queryById(1);
     		System.out.println(user);
     	}
     }
    
  7. 启动测试, 结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xwnYZmm8-1601046420381)(./images/2020-09-24_ws-xcf-spring-web-client-ret.png)]

2.2.3、cxf整合spring boot

项目功能同sprng web相同,根据用户id查询表中用户信息。这里我们不在整合mybaits,只做测试,在service实现类中直接新建一个User对象,返回。

因为是spring boot项目,我们搭建的时候,搭建一个新的工程。

2.2.3.1、服务端

步骤:

  1. 搭建maven普通工程,pom.xml如下:

     <?xml version="1.0" encoding="UTF-8"?>
     <project xmlns="http://maven.apache.org/POM/4.0.0"
     		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     	<parent>
     		<artifactId>spring-boot-starter-parent</artifactId>
     		<groupId>org.springframework.boot</groupId>
     		<version>2.3.0.RELEASE</version>
     	</parent>
     	<modelVersion>4.0.0</modelVersion>
    
     	<groupId>com.etoak.et2003.ws</groupId>
     	<artifactId>ws-cxf-boot</artifactId>
     	<version>1.0-SNAPSHOT</version>
    
     	<dependencies>
     		<dependency>
     			<groupId>org.springframework.boot</groupId>
     			<artifactId>spring-boot-starter-web</artifactId>
     		</dependency>
     		<dependency>
     			<groupId>org.apache.cxf</groupId>
     			<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
     			<version>3.3.5</version>
     			<exclusions>
     				<exclusion>
     					<groupId>javax.validation</groupId>
     					<artifactId>validation-api</artifactId>
     				</exclusion>
     			</exclusions>
     		</dependency>
     		<dependency>
     			<groupId>org.projectlombok</groupId>
     			<artifactId>lombok</artifactId>
     		</dependency>
     	</dependencies>
    
     </project>
    
  2. 项目目录结构,如图:![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eqlpk4Ko-1601046420382)(./images/2020-09-24_ws-xcf-spring-boot-server-struction.png)]

    1. 红线没影响](https://img-blog.csdnimg.cn/20200925231536447.png#pic_center)
  3. 代码

    1. User.java同上

    2. UserService.java

       package com.etoak.service;
      
       import com.etoak.bean.User;
      
       import javax.jws.WebParam;
       import javax.jws.WebService;
      
       @WebService
       public interface UserService{
       	User queryById(@WebParam(name = "id") int id);
       }
      
    3. UserServiceImpl

     package com.etoak.service.impl;
    
     import com.etoak.bean.User;
     import com.etoak.service.UserService;
     import org.springframework.stereotype.Service;
    
     import javax.jws.WebParam;
     import javax.jws.WebService;
    
    
     @Service
     @WebService
     public class  UserServiceImpl implements UserService {
    
     	@Override
     	public User queryById(@WebParam(name = "id") int id) {
     		User user  = new User();
     		user.setId(id);
     		user.setUsername("zs");
     		user.setAge(20);
     		user.setEmail("zs@163.com");
     		return  user;
     	}
     }
    
    1. CxfApplicaiton.java
     package com.etoak;
    
     import com.etoak.service.UserService;
     import org.apache.cxf.Bus;
     import org.apache.cxf.endpoint.EndpointException;
     import org.apache.cxf.endpoint.Server;
     import org.apache.cxf.jaxws.EndpointImpl;
     import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
     import org.springframework.beans.factory.annotation.Autowired;
     import org.springframework.boot.SpringApplication;
     import org.springframework.boot.autoconfigure.SpringBootApplication;
     import org.springframework.context.annotation.Bean;
    
     @SpringBootApplication
     public class CxfApplication {
     	public static void main(String[] args) {
     		SpringApplication.run(CxfApplication.class, args);
     	}
    
     	@Autowired
     	Bus bus;
    
     	@Autowired
     	UserService userService;
    
     	@Bean
     	public EndpointImpl userServiceEndpoint() {
     		// 给所有服务添加拦截器
     //        bus.getInInterceptors().add(new LoggingInInterceptor());
     //        QName qName = new QName("http://localhost:9001/user", "UserService");
     		EndpointImpl endpoint = new EndpointImpl(bus, userService);
     		endpoint.publish("/user");
     		return endpoint;
     	}
    
     	@Bean
     	public JaxWsServerFactoryBean userServiceFactoryBean() {
     		JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
     		factory.setAddress("/user2");
     		factory.setServiceClass(UserService.class);
     		factory.setServiceBean(userService);
     		Server server = factory.create();
     		server.start();
     		return factory;
     	}
    
     //    @Bean
     //    public ServletRegistrationBean<CXFServlet> cxfServlet() {
     //        ServletRegistrationBean<CXFServlet> registration = new ServletRegistrationBean<>();
     //        registration.setServlet(new CXFServlet());
     //        registration.addUrlMappings("/ws/*");
     //        return registration;
     //    }
     }
    
    1. application.yml
     cxf:
       path: /ws
    
  4. 运行CxfApplication启动类即可

解析:

  1. CxfApplication中注释的@Bean 和application.yml中的配置功能相同,使用任一即可

  2. 使用了2种发布方式

    1. Endpoint 原生JDK方式,/user
    2. cxf的类库, /user2
  3. 关于webservice拦截器部分自行查阅相关文档,本人换没有详细研究,不做分析

  4. 客户端测试部分,方式同上,不在赘述

至此WebService相关的项目告一段落。

后记

感谢前辈们,参考博客地址:

  1. https://blog.csdn.net/c99463904/article/details/76018436
  2. https://blog.csdn.net/Cs_hnu_scw/article/details/80181762

欢迎交流,本人QQ:806797785

项目源代码地址:https://gitee.com/gaogzhen
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gaog2zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值