WebService开发记录
自打去年被BMC的Web Service整的非常凄惨之后,我就对Java平台下的Web Service开发敬而远之,实在受不了各种莫名其妙的问题,还有开发的配置调试过程。但是今年的这个时间,我又不得不硬着头皮把Web Service嵌入一个老的项目里面,于是各种麻烦铺面而来。
先是想使用Axis2来开发,网络上的一篇篇文章说实话简直是没什么营养,我怀疑这帮人是不是只成功过一次,还是说有前置条件但是却没写出来,总之如果按照这些千篇一律的文章是不可能顺顺当当就配置成功的。通过反复的试探大概了解了其配置,总体上感觉太复杂,对于一般的中小型、老旧项目不太适用,如果使用Axis2来开发,耗费的开发、调试时间得不偿失,所以干脆直接放弃,同时也摆脱了那些味同嚼蜡的水文。
接着就寻求比较简单的框架,一般来说易于自己理解的就是简单的框架,看上CXF一眼就对其一见钟情,不过对于从未接触此框架的人来说,如果只是按照网络上的文章去做还是有些困难,这里不说如何配置,只是说不能完全按照那些文章去做,因为或多或少都有些瑕疵,需要反复调试。
开发环境为:eclipse,JDK1.7,tomcat8,SpringMVC4.1,cxf3.1。
声明一个接口,使用WebService进行注解:
- package com.xnck.ws.server;
- import javax.jws.WebService;
- @WebService
- public interface ITestWebService {
- public boolean test(String userId);
- }
实现这个接口:
- package com.xnck.ws.server.impl;
- import javax.jws.WebService;
- import org.apache.log4j.Logger;
- import com.xnck.ws.server.ITestWebService;
- @WebService(endpointInterface = "com.xnck.ws.server.ITestWebService")
- public class TestWebService implements ITestWebService{
- private static final Logger log = Logger.getLogger(TestWebService.class);
- public boolean test(String userId) {
- return false;
- }
- }
WEB-INF/classes内添加cxf.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:jaxws="http://cxf.apache.org/jaxws"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://cxf.apache.org/jaxws
- http://cxf.apache.org/schemas/jaxws.xsd">
- <import resource="classpath:META-INF/cxf/cxf.xml" />
- <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
- <bean id="test" class="com.xnck.ws.server.impl.TestWebService" />
- <jaxws:endpoint id="testWebService" implementor="#test" address="/test">
- </jaxws:endpoint>
- </beans>
WEB.xml中的部分配置内容为:
- <!-- contextconfig -->
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:spring-common.xml,classpath:cxf.xml
- </param-value>
- </context-param>
- <listener>
- <listener-class>
- org.springframework.web.context.ContextLoaderListener
- </listener-class>
- </listener>
- <!-- spring servlet -->
- <servlet>
- <servlet-name>Spring-Servlet</servlet-name>
- <servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:spring-servlet.xml
- </param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>Spring-Servlet</servlet-name>
- <url-pattern>*.do</url-pattern>
- </servlet-mapping>
- <servlet-mapping>
- <servlet-name>Spring-Servlet</servlet-name>
- <url-pattern>*.shtml</url-pattern>
- </servlet-mapping>
- <!-- cxf servlet -->
- <servlet>
- <servlet-name>CXFServlet</servlet-name>
- <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
- <load-on-startup>2</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>CXFServlet</servlet-name>
- <url-pattern>/webservice/*</url-pattern>
- </servlet-mapping>
然后启动tomcat,访问http://localhost:8080/yourwebstie/webservice,就可以看到正常的WSDL输出信息了,到这里没有什么问题,即使有点问题也是小问题。
但是,使用SoapUI来对上文开发的TestWebService测试时,就出错了,具体的错误为:Cannot create a secure XMLInputFactory。去互联网上搜索,千篇一律的解决办法又出现了,各种搞定后来其实是搞不定。一般在互联网上通过5分钟的搜索无法解决问题时,那这个问题就十分棘手了,有可能卡主很长时间。不停的打开这些前篇一律的帖子,终于发现有几篇有营养的,首先:
http://blog.csdn.net/wuxuguang123/article/details/43676265这个帖子从cxf的源代码进行分析,给出了令人眼前一亮的解决办法,通过设定常量“ALLOW_INSECURE_PARSER”的值来解决办法,但是并没有非常明确的说明该如何解决,只是比较模糊的给出了方向。
再继续搜索发现了两个帖子,分别是http://codego.net/584909/和http://shangliang57.iteye.com/blog/2048380,第一个帖子想通过Spring声明Bean来改变这个常量的值,我在尝试的时候失败了,应该是某些配置或者框架版本不一样,第二个帖子是通过cxf的拦截器来设置这个常量的值,尝试后成功了。关于cxf拦截器的说明介绍,可以看这里http://lavasoft.blog.51cto.com/62575/167288/。
造的拦截器代码如下:
- package com.xnck.authorize.interceptor;
- import org.apache.cxf.interceptor.Fault;
- import org.apache.cxf.message.Message;
- import org.apache.cxf.phase.AbstractPhaseInterceptor;
- import org.apache.cxf.phase.Phase;
- public class CxfWssJSystemEnvIntercepter extends AbstractPhaseInterceptor<Message>{
- public CxfWssJSystemEnvIntercepter(String phase) {
- super(phase);
- }
- public CxfWssJSystemEnvIntercepter(){
- super(Phase.RECEIVE);
- }
- @Override
- public void handleMessage(Message message) throws Fault {
- if(null==System.getProperty("org.apache.cxf.binding.soap.messageFactoryClassName")
- ||"".equals(System.getProperty("org.apache.cxf.binding.soap.messageFactoryClassName"))
- ){
- System.setProperty("org.apache.cxf.stax.allowInsecureParser","1");
- }
- }
- }
这样在符合条件的时候,访问任何一个cxf的web service都会触发这个拦截器,从而更改常量“ALLOW_INSECURE_PARSER”的值。在cxf.xml里面发布web service时的配置就变成:
- <bean id="task" class="com.ceservice.ws.server.impl.TaskWebService" />
- <jaxws:endpoint id="taskWebService" implementor="#task" address="/task">
- <jaxws:inInterceptors>
- <bean class="com.ceservice.authorize.interceptor.CxfWssJSystemEnvIntercepter"></bean>
- </jaxws:inInterceptors>
- </jaxws:endpoint>
再运行进行测试,我这里是没有再报错了。