可以用wsimport –keep http://localhost:9000/cxf?wsdl 生成客户端
也可以用CXF的wsdl2java命令生成客户端代码
使用Cxf必须创建一个服务接口(客户端使用)、这个接口的实现类(服务端处理客户端请求的相关业务)、服务端启动类(发布服务)和客户端启动类(访问服务)。
注:Exception in thread “main” java.lang.NoClassDefFoundError:
Com/sun/mail/util/LineInputStream
原因:JavaEE版本和JavaMail的版本不一致。
解决方法:windowàpreferencesàjava,把版本改成一致就可以了。
首先导入cxf的所有包。
以HelloWorld为例,服务接口:
package com.test;
import javax.jws.WebService;
@WebService//必须注解WebService,让cxf知道这个接口是发布的WebService
public interface HelloWorld
{
public String sayHi(String name);
}
服务实现类:
package com.test;
import javax.jws.WebService;
@WebService
public class HelloWorldImpl implements HelloWorld
{
public String sayHi(String name)
{
System.out.println("Hello " + name);
return "Hello " + name;
}
}
服务端启动类:
package com.server;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import com.test.HelloWorldImpl;
public class ServerStart
{
protected ServerStart() throws Exception
{
HelloWorldImpl helloWorld = new HelloWorldImpl();
String address = "http://localhost:9000/cxf";
/**
* 也可以使用注释的方式发布
*/
//Endpoint.publish(address, helloWorld);
//发布服务
JaxWsServerFactoryBean server = new JaxWsServerFactoryBean();
server.setServiceClass(helloWorld.getClass());
server.setAddress(address);
server.create();
}
public static void main(String[] args) throws Exception
{
new ServerStart();
}
}
客户端启动类:
package com.client;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.test.HelloWorld;
public class ClientStart
{
public static void main(String args[]) throws Exception
{
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setAddress("http://localhost:9000/cxf");
HelloWorld client = factory.create(HelloWorld.class);
//调用客户端方法并打印在控制台
System.out.println(client.sayHi("cxf"));
}
}
2、CXF复杂对象的传递
复杂对象的传递,首先需要创建一个实体类,用于存放List、Map等,
提供其getter、setter方法。然后在接口中提供实体类List的getter、setter方法,以供客户端调用和赋值。相关业务在接口的实现类中处理。
例子如下:
实体类:
package com.server;
import java.util.List;
import java.util.Map;
public class Demo
{
private String name;
private int age;
private List<Integer> list;
private Map<Integer, String> map;
private int array[];
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<Integer> getList() {
return list;
}
public void setList(List<Integer> list) {
this.list = list;
}
public Map<Integer, String> getMap() {
return map;
}
public void setMap(Map<Integer, String> map) {
this.map = map;
}
public int[] getArray() {
return array;
}
public void setArray(int[] array) {
this.array = array;
}
}
接口:
package com.client;
import java.util.List;
@WebService
public interface ClientSimple {
public List<Demo> getDemoList();
public List<Demo> setDemoList(List<Demo> list);
}
接口实现类:
package com.server;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.jws.WebService;
@WebService
public class ServerSimple implements ClientSimple {
private int requestCount = 0;
public List getDemoList(){
requestCount++;//统计客户端访问次数
System.out.println("requestCount= " + requestCount);
List<Demo> demoList = new ArrayList<Demo>();
Demo demo = new Demo();
demo.setAge(22);
demo.setName("xx");
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
demo.setList(list);
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
demo.setMap(map);
int[] array = {1,2,3};
demo.setArray(array);
demoList.add(demo);
return demoList;
}
public List<Demo> setDemoList(List<Demo> list){
requestCount++;
System.out.println("requestCount= " + requestCount);
return list;
}
}
服务启动类:
package com.server;
import javax.xml.ws.Endpoint;
public class ServerStart {
protected ServerStart() throws Exception{
System.out.println("Starting Server...");
ServerSimple server = new ServerSimple();
String address = "http://localhost:9001/Demo";//设置访问路径
Endpoint.publish(address, server); //发布服务
}
public static void main(String[] args) throws Exception{
new ServerStart();
System.out.println("Server ready...");
Thread.sleep(5*60*1000);//5分钟后服务端退出
System.out.println("Server exiting");
System.exit(0);
}
}
客户端启动类:
package com.client;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class ClientStart {
public static void getServerList(){
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
//利用拦截器打印输入输出日志
factory.getOutInterceptors().add(new LoggingInInterceptor());
factory.getInInterceptors().add(new LoggingOutInterceptor());
factory.setServiceClass(ClientSimple.class);
factory.setAddress("http://localhost:9001/Demo");
ClientSimple client = (ClientSimple)factory.create();
List<Demo> demoList = new ArrayList<Demo>();
System.out.println("getServerList begin....");
System.out.println("List Size: " + demoList.size());
for(Iterator<Demo> iter = demoList.iterator(); iter.hasNext();){
Demo demo = iter.next();
System.out.println(demo.toString());
}
System.out.println("getServerList end....");
}
public static void setServiceList(){
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getOutInterceptors().add(new LoggingInInterceptor());
factory.getInInterceptors().add(new LoggingOutInterceptor());
factory.setServiceClass(ClientSimple.class);
factory.setAddress("http://localhost:9001/Demo");
ClientSimple client = (ClientSimple)factory.create();
List<Demo> demoList = new ArrayList<Demo>();
System.out.println("setServerList begin....");
Demo demo = new Demo();
//为demo赋值
demo.setAge(22);
demo.setName("xx");
List<Integer> list1 = new ArrayList<Integer>();
list1.add(3);
list1.add(2);
list1.add(1);
demo.setList(list1);
Map<Integer, String> map1 = new HashMap<Integer, String>();
map1.put(1, "A");
map1.put(2, "b");
demo.setMap(map1);
int[] array = {1,2,3};
demo.setArray(array);
//将Demo放入demoList
demoList.add(demo);
demo = new Demo();
demo.setAge(23);
demo.setName("x-x");
List<Integer> list2 = new ArrayList<Integer>();
list2.add(3);
list2.add(6);
list2.add(9);
demo.setList(list2);
Map<Integer, String> map2 = new HashMap<Integer, String>();
map2.put(1, "a");
map2.put(2, "B");
demo.setMap(map2);
int[] array1 = {3,6,3};
demo.setArray(array1);
//放入第二个Demo
demoList.add(demo);
System.out.println("demoList Size: " + demoList.size());
for(Iterator<Demo> iter = demoList.iterator(); iter.hasNext();){
demo = iter.next();
System.out.println(demo.toString());
}
System.out.println("getServerList end....");
}
public static void main(String[] args){
getServerList();
setServiceList();
}
}
3、CXF图片上传(MTOM)
附件上传需要借助MTOM,也需要一个实体类,用来处理上传的附件。
实体类:
public class Resume {
private String candidateName;//附件名
private String resumeFileType;//附件类型
private DataHandler resume;//附件
public String getCandidateName() {
return candidateName;
}
public void setCandidateName(String candidateName) {
this.candidateName = candidateName;
}
public String getResumeFileType() {
return resumeFileType;
}
public void setResumeFileType(String resumeFileType) {
this.resumeFileType = resumeFileType;
}
public DataHandler getResume() {
return resume;
}
public void setResume(DataHandler resume) {
this.resume = resume;
}
}
服务接口:
@WebService
public interface ResumeUploadService {
void uploadResume(@WebParam(name="resume") Resume resume);
}
接口实现类:
@WebService(endpointInterface = "com.webservice.ResumeUploadService",
serviceName = "ResumeService")
public class ResumeUploadServiceImpl implements ResumeUploadService {
public void uploadResume(Resume resume) {
DataHandler handler = resume.getResume();
try{
InputStream is = handler.getInputStream();
OutputStream os = new FileOutputStream(
new File("d:\\" + resume.getCandidateName() + "."
+ resume.getResumeFileType()));
byte[] b = new byte[5*1000*1024];//设置附件最大限制
int bytesRead = 0;
while((bytesRead = is.read(b)) != -1){
os.write(b, 0, bytesRead);
}
os.flush();
os.close();
is.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
服务启动类:
public class ServerStart {
public static void main(String[] args) throws Exception{
new ServerStart();
System.out.println("Server ready...");
Thread.sleep(5*60*1000);//5分钟后服务端退出
System.out.println("Server exiting");
System.exit(0);
}
protected ServerStart() {
System.out.println("Starting Server...");
ResumeUploadServiceImpl rus = new ResumeUploadServiceImpl();
String address = "http://localhost:9000/mtom0.2/upload";
Endpoint ep = Endpoint.publish(address, rus);
Binding binding = ep.getBinding();
((SOAPBinding)binding).setMTOMEnabled(true);
}
}
客户端启动类:
public class ClientStart {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ResumeUploadService.class);
factory.setAddress("http://localhost:9000/mtom0.2/upload");
ResumeUploadService client = (ResumeUploadService)factory.create();
Resume resume = new Resume();
int i = new Random().nextInt();
System.out.println("生成的随机数为:" + i);
resume.setCandidateName("cxf" + i);//设置附件名
resume.setResumeFileType("png");//设置附件类型
DataSource source = new FileDataSource(new File("e:\\upload.png"));
resume.setResume(new DataHandler(source));
//测试文件大小
InputStream is = resume.getResume().getInputStream();
System.out.println("文件大小为:" + is.available());
client.uploadResume(resume);//开始上传附件
System.out.println("上传成功!");
System.exit(0);
}
}
4、CXF之MTOM
(原文地址:http://blog.csdn.net/fhd001/archive/2010/08/05/5789311.aspx)
MTOM(消息传输优化机制Message Transmission and Optimization Mechanism)是一个标准的服务,让你的服务传输二进制数据更方便,更有效率。很多框架都支持MTOM---Axis2,JAX-WS RI, JBoss WS , XFire , Microsoft WCF ,等更多.如果二进制是xml文档的一部分,它需要base64编码。当MTOM在一个服务上启用时,它可能需要二进制数据且通常是xml文档的一部分, 并为它创建一个附件。
启用MTOM是一个相当简单的过程。首先,你必须注解POJO类型或schema类型.........下面告诉你怎样为JAXB激活MTOM. MTOM也支持Aegis.
1、 注解
a. 为MTOM修改你的schema
假如我们有这样一个Picture的schema类型,如:
<schema targetNamespace="http://pictures.com"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<element name="Picture">
<complexType>
<sequence>
<element name="Title" type="xsd:string"/>
<element name="ImageData" type="xsd:base64Binary"/>
</sequence>
</complexType>
</element>
</schema>
在这种情况下,ImageData元素是我们想作为附件传送。我们只需要添加一个xmime : expectedContentTypes 注解:
<schema targetNamespace="http://pictures.com"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xmime="http://www.w3.org/2005/05/xmlmime">
<element name="Picture">
<complexType>
<sequence>
<element name="Title" type="xsd:string"/>
<element name="ImageData" type="xsd:base64Binary"
xmime:expectedContentTypes="application/octet-stream"/>
</sequence>
</complexType>
</element>
</schema>
这告诉JAXB(其中WSDL2Java用来为你的服务生成POJO),这个字段可以是任何内容类型。 而不是为base64Binary创建一个byte[]数组. 它将创建一个DataHandler ,而不是用于流数据。
b. 注解你的JAXB bean来启用MTOM
@XmlType
public class Picture {
private String title;
@XmlMimeType("application/octet-stream")
private DataHandler imageData;
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public DataHandler getImageData() { return imageData; }
public void setImageData(DataHandler imageData) { this.imageData = imageData; }
}
2、 在你的服务上启用MTOM
如果你使用JAX-WS API发布你的服务,你可以像这样启用MTOM,如:
import javax.xml.ws.Endpoint;
import javax.xml.ws.soap.SOAPBinding;
Endpoint ep = Endpoint.publish("http://localhost/myService", new MyService());
SOAPBinding binding = (SOAPBinding) ep.getBinding();
binding.setMTOMEnabled(true);
或者,你用xml来发布你的服务:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">
<jaxws:endpoint
id="helloWorld"
implementor="demo.spring.HelloWorldImpl"
address="http://localhost/HelloWorld">
<jaxws:properties>
<entry key="mtom-enabled" value="true"/>
</jaxws:properties>
</jaxws:endpoint>
</beans>
如果你使用simple frontend,你可以在ServerFactoryBean或ClientProxyFactoryBean设置mtom-enabled属性.
Map<String,Object> props = new HashMap<String, Object>();
props.put("mtom-enabled", Boolean.TRUE); // Boolean.TRUE or "true" will work as the property value here
ClientProxyFactoryBean pf = new ClientProxyFactoryBean();
pf.setPropertyies(props);
....
YourClient client = (YourClient) pf.create();
ServerFactoryBean sf = new ServerFactoryBean();
sf.setPropertyies(props);
...
sf.create();
你也可以用xml来配置(simple frontend):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:simple="http://cxf.apache.org/simple"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/simple http://cxf.apache.org/schema/simple.xsd">
<simple:server
id="helloWorld"
serviceClass="demo.spring.HelloWorldImpl"
address="http://localhost/HelloWorld">
<simple:properties>
<entry key="mtom-enabled" value="true"/>
</simple:properties>
</simple:server>
<simple:client
id="helloWorldClient"
serviceClass="demo.spring.HelloWorldImpl"
address="http://localhost/HelloWorld">
<simple:properties>
<entry key="mtom-enabled" value="true"/>
</simple:properties>
</simple:client>
</beans>
3、 使用DataHandlers
Picture picture = ...;
DataHandler handler = picture.getImageData();
InputStream is = handler.getInputStream();
DataSource source = new ByteArrayDataSource(new byte[] {...}, "content/type");
DataSource source = new FileDataSource(new File("my/file"));
Picture picture = new Picture();
picture.setImageData(new DataHandler(source));
4、 大文件上传
上传需要一个实体类(类上需注解XmlAccessorType(XmlAccessType.FIElD)),实例类里有三个参数(candidateName附件名、resumeFileType附件类型、DataHandler resume附件)DataHandler上需注解@XmlMineType(“application/octet-stream”),还需要在服务接口注解@SOAPBinding(style=”SOAPBinding.Style.RPC”)和@MTOM来开启MTOM。
@SOAPBinding(style = SOAPBinding.Style.RPC)指定SOAP消息样式,有两个枚举值:SOAPBinding.Style.DOCUMENT(默认)和 SOAPBinding.Style.RPC,可以对比这两种方式生成的wsdl会有所不同,而且生成的客户端代码也会有所不同。
附件实体类:
package com.pojo;
import javax.activation.DataHandler;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlMimeType;
@XmlAccessorType(XmlAccessType.FIELD)
public class Resume {
private String candidateName;//附件名
private String resumeFileType;//附件类型
@XmlMimeType("application/octet-stream")
private DataHandler resume;//附件
public String getCandidateName() {
return candidateName;
}
public void setCandidateName(String candidateName) {
this.candidateName = candidateName;
}
public String getResumeFileType() {
return resumeFileType;
}
public void setResumeFileType(String resumeFileType) {
this.resumeFileType = resumeFileType;
}
public DataHandler getResume() {
return resume;
}
public void setResume(DataHandler resume) {
this.resume = resume;
}
}
接口类:
package com.webservice;
import java.io.IOException;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.ws.soap.MTOM;
import com.pojo.Resume;
@WebService
@SOAPBinding(style=SOAPBinding.Style.RPC)
@MTOM
public interface ResumeUploadService {
void uploadResume(@WebParam(name="resume") Resume resume) throws IOException;
}
接口实现类:
package com.webservice;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.activation.DataHandler;
import javax.jws.WebService;
import com.pojo.Resume;
@WebService(endpointInterface = "com.webservice.ResumeUploadService",
serviceName = "ResumeService")
//@BindingType(SOAPBinding.SOAP11HTTP_MTOM_BINDING)
public class ResumeUploadServiceImpl implements ResumeUploadService {
public void uploadResume(Resume resume) throws IOException{
DataHandler handler = resume.getResume();
final int BUFFER_SIZE = 50*1024*1024;// 缓冲区大小为3M
long fileLength = 0;
int read = 0;
InputStream is = null;
OutputStream os = null;
try{
//1.
is = handler.getInputStream();
os = new FileOutputStream(
new File("d:\\" + resume.getCandidateName() + "."
+ resume.getResumeFileType()));
// is = new BufferedInputStream(handler.getInputStream());
// os = new BufferedOutputStream(new FileOutputStream("d:\\" + resume.getCandidateName() + "."
// + resume.getResumeFileType()));
fileLength = is.available();
System.out.println("服务端测试文件大小:" + fileLength);
byte[] b = new byte[BUFFER_SIZE];
while((read = is.read(b)) != -1){
os.write(b, 0, read);
}
//2.目前测试6M文件可以上传,10M内存溢出
//
// byte[] dst = new byte[BUFFER_SIZE];//每次读出3M
// for(int offset=0; offset<fileLength; offset+=BUFFER_SIZE){
// if(fileLength - offset >= BUFFER_SIZE){
// read = is.read(dst);
// os.write(dst, 0, read);
//System.out.println("test if run " + offset);
// }else{
// read = is.read(dst);
// os.write(dst, 0, read);
//System.out.println("test else run");
// }
// read=0;
// os.flush();
// }
}catch(IOException e){
e.printStackTrace();
}finally{
if(is != null)is.close();
if(os != null){
os.flush();
os.close();
}
}
}
}
服务端启动类:
package com.server;
import javax.xml.ws.Endpoint;
public class ServerStart {
/**
* @param args
* 上传附件的时候应注意把MyException自带的Java EE 5 Libraries删掉,
* 否则会出现Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream
* 原因:JavaEE版本和JavaMail的版本不一致。
*/
public static void main(String[] args) throws Exception{
new ServerStart();
System.out.println("Server ready...");
Thread.sleep(5*60*1000);//5分钟后服务端退出
System.out.println("Server exiting");
System.exit(0);
}
protected ServerStart() {
System.out.println("Starting Server...");
ResumeUploadServiceImpl rus = new ResumeUploadServiceImpl();
String address = "http://localhost:9000/mtom0.2/upload";
Endpoint.publish(address, rus);
// Endpoint ep = Endpoint.publish(address, rus);
// Binding binding = ep.getBinding();
// System.out.println(binding.getBindingID());
// ((SOAPBinding)binding).setMTOMEnabled(true);
}
}
客户端启动类:
package com.client;
import java.io.File;
import java.io.InputStream;
import java.util.Random;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.pojo.Resume;
import com.webservice.ResumeUploadService;
public class ClientStart {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ResumeUploadService.class);
factory.setAddress("http://localhost:9000/mtom0.2/upload");
ResumeUploadService client = (ResumeUploadService)factory.create();
Resume resume = new Resume();
//启动MTOM(有问题)
// QName qname = new QName("http://webservice.com/", "ResumeService");
// Service svc = Service.create(qname);
// ResumeUploadService proxy = svc.getPort(ResumeUploadService.class);
// BindingProvider bp = (BindingProvider) proxy;
// SOAPBinding binding = (SOAPBinding) bp.getBinding();
// binding.setMTOMEnabled(true);
int i = new Random().nextInt();
System.out.println("生成的随机数为:" + i);
resume.setCandidateName("cxf" + i);//设置附件名
DataSource source = new FileDataSource(new File("e:\\myTools\\jdk-1_5_0-windows-i586.exe"));
DataHandler handler = new DataHandler(source);
resume.setResume(handler);//设置附件
//得到附件类型
String fileType = source.getName().substring(source.getName().lastIndexOf(".")+1);
System.out.println("文件类型为:" + fileType);
resume.setResumeFileType(fileType);//设置附件类型
//测试文件大小
InputStream is = resume.getResume().getInputStream();
System.out.println("文件大小为:" + is.available() + "个字节");
client.uploadResume(resume);//开始上传附件
System.out.println("上传成功!");
System.exit(0);
}
}
5、 CXF之WS-Security安全机制
一个WebService挂在互联网上,如果知道地址,那么任何人都可以访问,所以应该考虑 WebService的安全问题。应该只让指定的客户端访问。下面利用Jax-WS的拦截器来做用户验证。
和上面例子一样,首先需要一个服务接口和服务实现类,这里省略。
其次需要2个身份验证的CallbackHandler:
服务端CallbackHandler
package com.mms.webservice.test;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
public class ServerPasswordCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pwcb = (WSPasswordCallback) callbacks[0];
String id = pwcb.getIdentifier();
switch (pwcb.getUsage()) {
case WSPasswordCallback.USERNAME_TOKEN_UNKNOWN:
// 密码方式 plaintext
if (!"cxf".equals(id)) {
throw new UnsupportedCallbackException(pwcb,
"username is invalid.");
}
if (!"mima".equals(pwcb.getPassword())) {
throw new UnsupportedCallbackException(pwcb,
"password is invalid.");
}
break;
case WSPasswordCallback.DECRYPT:
case WSPasswordCallback.SIGNATURE:
// used to retrieve password for private key
if ("serverkey".equals(id)) {
pwcb.setPassword("serverpass");
}
break;
}
}
}
客户端CallbackHandler:
package com.mms.webservice.test;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
public class ClientPasswordCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
//服务器标识
System.out.println("Server ID:"+pc.getIdentifier());
// 设置返回给客户的服务器密码信息
pc.setPassword("mima");
pc.setIdentifier("cxf");
}
}
然后还需要服务端启动类和和客户端启动类:
服务端启动类:
package com.server;
import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.handler.WSHandlerConstants;
import com.mms.webservice.HelloWorldImpl;
import com.mms.webservice.test.ServerPasswordCallback;
public class Server {
/**
* @param args
*/
public static void main(String[] args) {
Server server = new Server();
//server.test();//没有安全验证WS
server.testUsernameToken();//有安全验证WS
}
private void test() {
JaxWsServerFactoryBean server = new JaxWsServerFactoryBean();
// server.getInInterceptors().add(new LoggingInInterceptor());
// server.getOutInterceptors().add(new LoggingOutInterceptor());
server.setServiceClass(HelloWorldImpl.class);
server.setAddress("http://localhost:9000/security");
server.create();
}
private WSS4JInInterceptor getInInterceptor() {
Map<String, Object> inProps = new HashMap<String, Object>();
inProps.put(WSHandlerConstants.ACTION,
WSHandlerConstants.USERNAME_TOKEN);
// 密码类型 : plain text
inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
// 客户信息校验类设置
inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
ServerPasswordCallback.class.getName());
return new WSS4JInInterceptor(inProps);
}
private void testUsernameToken() {
JaxWsServerFactoryBean server = new JaxWsServerFactoryBean();
//将回调拦截器加入server拦截器
server.getInInterceptors().add(getInInterceptor());
//server.getOutInterceptors().add(getOutInterceptor());
server.setServiceClass(HelloWorldImpl.class);
server.setAddress("http://localhost:9000/security");
server.create();
}
}
客户端启动类:
package com.client;
import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.handler.WSHandlerConstants;
import com.mms.webservice.HelloWorld;
import com.mms.webservice.test.ClientPasswordCallback;
public class client {
/**
* @param args
*/
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
//打印日志
factory.getOutInterceptors().add(new LoggingInInterceptor());
factory.getInInterceptors().add(new LoggingOutInterceptor());
factory.getOutInterceptors().add(getOutInterceptor());
factory.setAddress("http://localhost:9000/security");
factory.setServiceClass(HelloWorld.class);
HelloWorld client = (HelloWorld)factory.create();
System.out.println(client.sayHi("cxf"));
}
private static WSS4JOutInterceptor getOutInterceptor() {
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put(WSHandlerConstants.ACTION,
WSHandlerConstants.USERNAME_TOKEN);
// 服务器用户标识
outProps.put(WSHandlerConstants.USER, "IamServer");
// 密码类型 : plain text
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
// 返回给客户端的密码信息
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
ClientPasswordCallback.class.getName());
return new WSS4JOutInterceptor(outProps);
}
}
原理:利用CXF自身的拦截器
参考文章:http://hi.baidu.com/leezuu/blog/item/e502c3ae3de7da044a36d675.html
6、 CXF之JSON应用
下面例子展示如何在ServerFactoryBeans应用JSON,首先创建一个HashMap属性来设置StAX的XMLInputFactory和XMLOutputFactory:
Map<String,Object> properties = new HashMap<String,Object>();
// Create a mapping between the XML namespaces and the JSON prefixes.
// The JSON prefix can be "" to specify that you don't want any prefix.
HashMap<String, String> nstojns = new HashMap<String,String>();
nstojns.put("http://customer.acme.com", "acme");
MappedXMLInputFactory xif = new MappedXMLInputFactory(nstojns);
properties.put(XMLInputFactory.class.getName(), xif);
MappedXMLOutputFactory xof = new MappedXMLOutputFactory(nstojns);
properties.put(XMLOutputFactory.class.getName(), xof);
设置Context-Type属性:
// Tell CXF to use a different Content-Type for the JSON endpoint
// This should probably be application/json, but text/plain allows
// us to view easily in a web browser.
properties.put("Content-Type", "text/plain");
最后创建服务:
// Build up the server factory bean
JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
sf.setServiceClass(CustomerService.class);
// Use the HTTP Binding which understands the Java Rest Annotations
sf.setBindingId(HttpBindingFactory.HTTP_BINDING_ID);
sf.setAddress("http://localhost:8080/json");
sf.setServiceBean(new CustomerServiceImpl());
sf.setProperties(properties);
sf.create();
原文来自Apache官网:http://cxf.apache.org/docs/json-support.html
7、 CXF之嵌入Jetty
这次只介绍服务端,嵌入Jetty不需要导入Jetty的jar包,只需要导入CXF的包即可(CXF已把Jetty整合)。
首先的创建服务接口和服务实现类,这里不再重复,参照前面例子。
其次创建一个Jetty启动类,用来启动Jetty并且发布Web服务。
package com.server;
import javax.xml.ws.Endpoint;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import com.service.HelloWorldImpl;
public class JettyServer {
public static void main(String[] args){
new JettyServer();
}
private JettyServer(){
System.out.println(System.getProperty("user.dir"));
String app = System.getProperty("user.dir");//得到项目路径
org.eclipse.jetty.server.Server server
= new org.eclipse.jetty.server.Server();//新建一个Jetty服务器
Connector conn = new SelectChannelConnector();//新建Connector组件
conn.setHost("127.0.0.1");
conn.setPort(9000);
server.setConnectors(new Connector[]{conn});//插入服务器主件中
org.eclipse.jetty.server.handler.ContextHandler context
= new org.eclipse.jetty.server.handler.ContextHandler();//新建Handler组件
context.setContextPath("/");//Web应用的上下文跟路径
context.setResourceBase(app);
server.setHandler(context);//插入服务器主件中
org.eclipse.jetty.util.thread.QueuedThreadPool pool
= new org.eclipse.jetty.util.thread.QueuedThreadPool();//创建线程池组件
pool.setMaxThreads(100);//设置最大线程数
pool.setMinThreads(10);//设置最小线程数
server.setThreadPool(pool);
//发布Web服务
//Endpoint.publish("http://127.0.0.1:9000/WS-CXF-Jetty", new HelloWorldImpl());
JaxWsServerFactoryBean wsServer = new JaxWsServerFactoryBean();
wsServer.setAddress("http://127.0.0.1:9000/WS-CXF-Jetty");
wsServer.setServiceBean(new HelloWorldImpl());
wsServer.create();
try {
server.start();
//System.out.println(server.isStarted());
} catch (Exception e) {
e.printStackTrace();
}
}
}
参考文档:http://liuskysun.blog.163.com/blog/static/9981297820101023139723/
8、 关于wsdl2java自动生成客户端
利用wsdl2java生成的客户端,有个继承javax.xml.ws.Service的类,此方法的3个构造函数会报错(The constructor Service(URL, QName, WebServiceFeature[]) is undefined),原因是:jdk中有个javax.xml.ws.Service(低版本),而CXF的geronimo-jaxws_2.2_spec-1.0.jar中也有个javax.xml.ws.Service(高版本),而类里默认调用的是jdk(低版本)的Service,故报错!