Web Service项目
目录
文章目录
内容
这里我使用的开发工具IDEA,要测试多对服务端与客户端,这里就简单的搭建个父子工程,只是为了方便。
1、web service入门
1.1、基础理论知识
理论知识部分这里不再详述,可自行查阅相关文档或者参考文章末尾提到的前辈们的博客。
1.2、入门项目
- 注解:WebService
- 类:Endpoint 用于发布服务
这里我们做个简单的天气查询。
- 实现功能:输入城市名称,获取城市对于的天气描述。
入门项目我们用jdk原生的类库实现。
1.2.1、服务端
-
工程目录结构如图:
-
相关源代码如下:
-
接口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()); } }
-
点击左侧绿色三角或者右键运行服务(发布服务),如图:
至此,服务端运行
1.2.2、简单测试
浏览器输入:http://127.0.0.1:9000/weather?wsdl,查看服务端自动生成的wsdl文档,如图:
1.2.2、客户端测试
客户端测试有几种实现方式:普通浏览器调用方式,Ajax调用,原生jdk,QName方式,URLConnection方式等等。
这里只接受常用的原生jdk及推荐的QName方式。
其中QName方式在下面的测试通过公共服务获取电话号码信息中介绍。
-
命令:
wsimport 是jdk自带的生成WebService客户端的命令 -s 路径 在指定路径下面生成带源码的客户端
步骤:
-
创建客户端项目,就是最简单的maven项目
-
进入java包所在的文件夹,如图:
-
SHIFT+右键或者地址栏输入powershell(没有就输入cmd) ,选择进入powershell(没有就用cmd),如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gnASExV0-1601046420372)(./images/2020-09-24_ws-introduction-client-right-powershell-before.png)] -
输入命令:
wsimport -s . http://127.0.0.1:9000/weather?wsdl
-
java包下自动生成客户端代码,.class文件不需要,删除即可,如图:
-
下面编写客户端测试代码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); } }
点击运行,结果出来了,但是出了点小状况,如图:
解决方案:
-
点击图示Edit Configuratins:
-
如图修改编码:
-
重新运行,乱码问题解决,如图:
1.3、调用公网的手机归属地查询服务
1.3.1、普通方式客户端实现
公网服务地址 (里面提供了很多免费调用的服务):http://www.webxml.com.cn/zh_cn/index.aspx
步骤:
-
创建maven普通工程
-
切换到java包下,执行生成客户端代码命令:
wsimport -s . http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
-
编写客户端测试类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); } }
-
运行客户端,结果如图:
1.3.2、QName方式客户端
生成客户端方式同上
步骤:
-
创建普通Maven项目
-
切换到java包所在的目录,生成客户端代码,命令同上,改下地址
-
编写客户端测试类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、服务端
步骤同上
-
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>
-
项目目录结构,如图:
-
源码代码如下
-
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); }
-
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; } }
-
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("====服务开启==="); } }
-
-
启动服务端
解析:
- pom.xml配置文件中的依赖版本根据需要自己选择
- 关于WebService注解相关知识自行查阅相关文档
- 注解不会继承所以我们在接口及其实现类上都加了相同的注解
2.2.1.1、客户端
这里cxf提供了生成客户端的工具,apache-cxf-3.1.18,具体版本,根据需要自己去apache官网下载
步骤:
-
创建普通Maven工程,引入依赖同上
-
切换到java包对于的目录,进入命令行,执行客户端生成命令
wsdl2java -d . http://127.0.0.1:9001/weather?wsdl -d 路径 生成到指定的目录下
-
编写客户端测试类代码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); } }
-
启动客户端查看测试结果
2.2.2、cxf整合spring web
相关介绍:
- 这里我们整合spring web,mybatis,cxf,数据库使用mysql,日志用logback
- 实现根据用户id查询数据库中用户表中用户信息的功能
2.2.2.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实现分页功能的等等,这里只是示范案例,不会用到这些功能。
-
数据库中用户表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');
-
项目结构如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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>
-
-
配置tomcat服务器
- 主要是修改项目路径为 / ,tomcat详细配置自行查阅想文档,如图:
-
启动tomcat,至此server端完成
-
简单测试,浏览器中输入:http://127.0.0.1:8080/user?wsdl ,显示wsdl说明启动成功,如图:
2.2.2.2、客户端
步骤:
-
搭建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>
-
切换到java包下,执行命令生成客户端代码,命令如下:
wsdl2java -d . http://127.0.0.1:9090/user?wsdl
-
创建客户端测试代码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); } }
-
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>
-
项目目录结构如图:
-
第二中测试就是使用@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); } }
-
启动测试, 结果:
2.2.3、cxf整合spring boot
项目功能同sprng web相同,根据用户id查询表中用户信息。这里我们不在整合mybaits,只做测试,在service实现类中直接新建一个User对象,返回。
因为是spring boot项目,我们搭建的时候,搭建一个新的工程。
2.2.3.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>
-
项目目录结构,如图:![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eqlpk4Ko-1601046420382)(./images/2020-09-24_ws-xcf-spring-boot-server-struction.png)]
- 红线没影响](https://img-blog.csdnimg.cn/20200925231536447.png#pic_center)
-
代码
-
User.java同上
-
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); }
-
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; } }
- 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; // } }
- application.yml
cxf: path: /ws
-
-
运行CxfApplication启动类即可
解析:
-
CxfApplication中注释的@Bean 和application.yml中的配置功能相同,使用任一即可
-
使用了2种发布方式
- Endpoint 原生JDK方式,/user
- cxf的类库, /user2
-
关于webservice拦截器部分自行查阅相关文档,本人换没有详细研究,不做分析
-
客户端测试部分,方式同上,不在赘述
至此WebService相关的项目告一段落。
后记 :
感谢前辈们,参考博客地址:
- https://blog.csdn.net/c99463904/article/details/76018436
- https://blog.csdn.net/Cs_hnu_scw/article/details/80181762
欢迎交流,本人QQ:806797785
项目源代码地址:https://gitee.com/gaogzhen