项目中需要用到CXF做WS处理,花点时间对其有个简单认识,主要是在安全认证以及日志记录和异常处理这块有要求控制。
安全认证采用的是WSS4J,日志记录和异常处理采用拦截器控制,
资源下载:客户端和服务端都点这
服务端
整体架构.
至于webservice的配置可以参考其他文档,
服务接口
- package?com.cxfdemo.ws.service;??
- ??
- import?java.util.List;??
- import?javax.jws.WebParam;??
- import?javax.jws.WebResult;??
- import?javax.jws.WebService;??
- import?com.cxfdemo.ws.service.model.Resume;??
- import?com.cxfdemo.ws.service.model.User;??
- ??
- @WebService??
- public?interface?HelloWorld?{??
- ????@WebResult(name?=?"String")??
- ????public?String?sayHi(@WebParam(name="text")String?text);??
- ??????
- ????@WebResult(name?=?"user")??
- ????public?User?getUser(@WebParam(name="id")String?id);??
- ??????
- public?List<User>?getAllUsers();??
- void?saveUser(@WebParam(name="id")String?id,???
- ????????????@WebParam(name="name")String?name,???
- ????????????@WebParam(name="sex")int?sex);??
- ?????
- ?
- ?
- ?????*?如客户端中需要用到new?User("id","name",1)构造User对象时?
- ?????*??
- ?????*?需要在ObjectFactory中加入?
- ?????*??public?User?createUser(String?id,String?name,int?sex)?{?
- ?????*??????return?new?User(id,name,sex);?
- ?????*??}?
- ?????*?</p>?
- ?????*?@param?user?
- ?????*/??
- void?saveUsers(@WebParam(name="user")User?user);??
- public?String?saveResumes(@WebParam(name="resume")Resume?resume);???
- }??
服务实现
其中关于文件传输采用二进制方式.
有2点是必须配置的。
1.传输对象中含有DataHandler 属性
@XmlMimeType("application/octet-stream")
private DataHandler dataHandler;
2.服务发布时协议规定
<!-- 文件传送必须协议 -->
<jaxws:properties>
? ? ? ??<entry key="mtom-enabled" value="true"/> ?
</jaxws:properties>
spring配置
<import?resource="classpath:META-INF/cxf/cxf.xml"?/>??
- ????import?resource="classpath:META-INF/cxf/cxf-extension-soap.xml"?/>??
- ????import?resource="classpath:META-INF/cxf/cxf-servlet.xml"? ??????
- ??????
- bean?id="serverPasswordCallback"?class="com.cxfdemo.ws.service.ServerPasswordCallback"></bean>??
- ??????
- ??????
- bean?id="wss4jInInterceptor"?class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">??
- ????????constructor-arg ????????????map ??????????????????
- ????????????????entry?key="action"?value="UsernameToken"? ????????????????entry?key="passwordType"?value="PasswordText"?/>??
- entry?key="passwordCallbackRef"?value-ref="serverPasswordCallback"? ???????????? ???????? ??
- <!--?发布服务?-->??
- jaxws:endpoint?id="helloWorld"?address="/helloWorld"??
- ????????implementor="com.cxfdemo.ws.service.HelloWorldService" ??????????
- jaxws:propertiesentry?key="mtom-enabled"?value="true"/>????
- <!--?输入拦截器?-->??
- jaxws:inInterceptorsref?bean="wss4jInInterceptor"? ??????????????
- bean?class="org.apache.cxf.interceptor.LoggingInInterceptor"?<!--?正常输出拦截器?-->??
- jaxws:outInterceptorsbean?class="com.cxfdemo.ws.service.interceptor.ErrorHandlerInterceptor"<!--?错误输出拦截器?-->??
- jaxws:outFaultInterceptorsjaxws:endpointjaxws:endpoint?id="updateFile"?address="/updateFile"??
- ????????implementor="com.cxfdemo.ws.service.UpdateFileService">????
- entry?key="mtom-enabled"?value="true"?/>????
- >???
- <!--?全局配置?-->??
- ????<!--?cxf:buscxf:featurescxf:logging?>?-->??
采用的是jaxws:endpoint发布服务,至于其他方式,这里就不描述了,关于WSS4J的文章,网上也有很多。
服务端CallbackHandler配置
其实密码验证的工作是交给了WSS4JInInterceptor来处理的。
下面是一次错误密码的异常信息。
从异常堆栈中看出密码校验在UsernameTokenValidator中处理。源码如下。
日志记录拦截器
可根据是否含有错误原因或错误信息分辨出当前此次服务请求成功与否。
一次密码错误的日志信息
请求信息为:
?<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"><wsse:UsernameToken wsu:Id="UsernameToken-CF676781B956C77EB214127352680991"><wsse:Username>client</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">clientpass1</wsse:Password></wsse:UsernameToken></wsse:Security></SOAP-ENV:Header><soap:Body><ns2:saveUsers xmlns:ns2="http://service.ws.cxfdemo.com/"><user><collections>11dfdfd</collections><collections>22dfdfd</collections><collections>33dfdfd</collections><id>id</id><map><entry><key>44</key><value>333</value></entry><entry><key>55</key><value>333</value></entry><entry><key>22</key><value>333</value></entry><entry><key>33</key><value>333</value></entry><entry><key>11</key><value>333</value></entry></map><name>name</name><sex>2</sex></user></ns2:saveUsers></soap:Body></soap:Envelope>
soapUI配置
Eclipse的插件地址:http://www.soapui.org/eclipse/update
客服端
采用wsdl2java?生成的客户端。
密码也是用WSS4JOutInterceptor拦截设置的。
copy
?
bean?id="clientPasswordCallback"?class="com.cxfdemo.ws.client.ClientPasswordCallback"bean?id="wss4jOutInterceptor"?class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"entry?key="action"?value="UsernameToken"entry?key="user"?value="client"entry?key="passwordType"?value="PasswordText"entry?key="passwordCallbackRef"?value-ref="clientPasswordCallback"/>???
jaxws:client?id="client"?address="http://localhost:8888/CXFDemo/webservice/helloWorld"??
????????serviceClass="com.cxfdemo.ws.service.HelloWorld"bean?class="org.apache.cxf.interceptor.LoggingOutInterceptor"?ref?bean="wss4jOutInterceptor"jaxws:clientjaxws:client?id="updateFile"?address="http://localhost:8888/CXFDemo/webservice/updateFile"??
????????serviceClass="com.cxfdemo.ws.service.HelloWorld"<!--?对所有的服务配置超时机制???只对服务名为{http://service.ws.cxfdemo.com/}HelloWorldService的服务生效.???-->??
http-conf:conduit?name="*.http-conduit">?????????
??????????
http-conf:client?ConnectionTimeout="15000"?ReceiveTimeout="30000"http-conf:conduit>??