转载于:http://blog.csdn.net/kongxx/article/details/7525476
Apache的CXF现在几乎成了Java领域构建Web Service的首选类库,并且它也确实简单易用,下面就通过几篇系列文章做一下简单介绍。
当然首先想到的当然还是那个Hello World示例。这个系列文章中用到的例子都是基于Maven构建的工程,下面是我的pom.xml文件内容
- <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/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.googlecode.garbagecan.cxfstudy</groupId>
- <artifactId>cxfstudy</artifactId>
- <packaging>war</packaging>
- <version>1.0-SNAPSHOT</version>
- <name>cxfstudy Maven Webapp</name>
- <url>http://maven.apache.org</url>
- <properties>
- <cxf.version>2.2.7</cxf.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-frontend-jaxws</artifactId>
- <version>${cxf.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-transports-http</artifactId>
- <version>${cxf.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-transports-http-jetty</artifactId>
- <version>${cxf.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-ws-security</artifactId>
- <version>${cxf.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-ws-policy</artifactId>
- <version>${cxf.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-bundle-jaxrs</artifactId>
- <version>${cxf.version}</version>
- </dependency>
- <dependency>
- <groupId>javax.ws.rs</groupId>
- <artifactId>jsr311-api</artifactId>
- <version>1.1.1</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.5.8</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-jdk14</artifactId>
- <version>1.5.8</version>
- </dependency>
- <dependency>
- <groupId>commons-httpclient</groupId>
- <artifactId>commons-httpclient</artifactId>
- <version>3.0</version>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.3</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.8.1</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <build>
- <finalName>cxfstudy</finalName>
- <resources>
- <resource>
- <directory>src/main/resources</directory>
- </resource>
- <resource>
- <directory>src/main/java</directory>
- <includes>
- <include>**</include>
- </includes>
- <excludes>
- <exclude>**/*.java</exclude>
- </excludes>
- </resource>
- </resources>
- <plugins>
- <plugin>
- <groupId>org.mortbay.jetty</groupId>
- <artifactId>maven-jetty-plugin</artifactId>
- <configuration>
- <contextPath>/</contextPath>
- <connectors>
- <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
- <port>9000</port>
- </connector>
- </connectors>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </project>
1.创建HelloWorld 接口类
- package com.googlecode.garbagecan.cxfstudy.helloworld;
- import javax.jws.WebMethod;
- import javax.jws.WebParam;
- import javax.jws.WebResult;
- import javax.jws.WebService;
- @WebService
- public interface HelloWorld {
- @WebMethod
- @WebResult String sayHi(@WebParam String text);
- }
- package com.googlecode.garbagecan.cxfstudy.helloworld;
- public class HelloWorldImpl implements HelloWorld {
- public String sayHi(String name) {
- String msg = "Hello " + name + "!";
- return msg;
- }
- }
- package com.googlecode.garbagecan.cxfstudy.helloworld;
- import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
- // http://localhost:9000/HelloWorld?wsdl
- public class Server {
- public static void main(String[] args) throws Exception {
- JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
- factory.setServiceClass(HelloWorldImpl.class);
- factory.setAddress("http://localhost:9000/ws/HelloWorld");
- factory.create();
- System.out.println("Server start...");
- Thread.sleep(60 * 1000);
- System.out.println("Server exit...");
- System.exit(0);
- }
- }
- package com.googlecode.garbagecan.cxfstudy.helloworld;
- import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
- public class Client {
- public static void main(String[] args) {
- JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
- factory.setServiceClass(HelloWorld.class);
- factory.setAddress("http://localhost:9000/ws/HelloWorld");
- HelloWorld helloworld = (HelloWorld) factory.create();
- System.out.println(helloworld.sayHi("kongxx"));
- System.exit(0);
- }
- }
首先运行Server类来启动Web Service服务,然后访问http://localhost:9000/ws/HelloWorld?wsdl地址来确定web service启动正确。
运行Client测试类,会在命令行输出Hello kongxx!的message。
=====================
Apache CXF实战之一 Hello World Web Service
书接上文,下面看看CXF怎样和spring集成。
1.创建HelloWorld 接口类
- package com.googlecode.garbagecan.cxfstudy.helloworld;
- import javax.jws.WebMethod;
- import javax.jws.WebParam;
- import javax.jws.WebResult;
- import javax.jws.WebService;
- @WebService
- public interface HelloWorld {
- @WebMethod
- @WebResult String sayHi(@WebParam String text);
- }
2.创建HelloWorld实现类
- package com.googlecode.garbagecan.cxfstudy.helloworld;
- public class HelloWorldImpl implements HelloWorld {
- public String sayHi(String name) {
- String msg = "Hello " + name + "!";
- return msg;
- }
- }
3.修改web.xml文件
- <!DOCTYPE web-app PUBLIC
- "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd" >
- <web-app>
- <display-name>cxfstudy</display-name>
- <servlet>
- <servlet-name>cxf</servlet-name>
- <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>cxf</servlet-name>
- <url-pattern>/ws/*</url-pattern>
- </servlet-mapping>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath*:**/spring.xml</param-value>
- </context-param>
- </web-app>
4.创建spring配置文件并放在classpath路径下
- <?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:jaxws="http://cxf.apache.org/jaxws"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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-extension-soap.xml" />
- <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
- <jaxws:endpoint id="helloworld" implementor="com.googlecode.garbagecan.cxfstudy.helloworld.HelloWorldImpl" address="/HelloWorld" />
- <!-- For client test -->
- <jaxws:client id="helloworldClient" address="http://localhost:9000/ws/HelloWorld" serviceClass="com.googlecode.garbagecan.cxfstudy.helloworld.HelloWorld" />
- </beans>
5.创建测试类
- package com.googlecode.garbagecan.cxfstudy.helloworld;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class SpringClient {
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
- HelloWorld helloworld = (HelloWorld)context.getBean("helloworldClient");
- System.out.println(helloworld.sayHi("kongxx"));
- }
- }
6.测试
6.1 首先启动tomcat或者使用maven的jetty,并访问http://localhost:9000/ws/HelloWorld?wsdl来验证web service已经启动并且生效;
6.2 然后运行测试类来验证web service。
===================
前面两篇文章介绍了怎样通过CXF来构建最基本的Web Service,并且其中暴露的接口参数和返回值都是字符串,下面来看看一个稍微复杂一点的例子。
1. 首先是一个普通的pojo对象,用来表示一个实体类
- package com.googlecode.garbagecan.cxfstudy.jaxws;
- import java.util.Date;
- public class Customer {
- private String id;
- private String name;
- private Date birthday;
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Date getBirthday() {
- return birthday;
- }
- public void setBirthday(Date birthday) {
- this.birthday = birthday;
- }
- @Override
- public String toString() {
- return org.apache.commons.lang.builder.ToStringBuilder.reflectionToString(this);
- }
- }
2. 创建Web Service接口类
- package com.googlecode.garbagecan.cxfstudy.jaxws;
- import javax.jws.WebMethod;
- import javax.jws.WebParam;
- import javax.jws.WebResult;
- import javax.jws.WebService;
- @WebService
- public interface CustomerService {
- @WebMethod
- @WebResult Customer findCustomer(@WebParam String id);
- }
3. 创建Web Service接口的实现类
- package com.googlecode.garbagecan.cxfstudy.jaxws;
- import java.util.Calendar;
- public class CustomerServiceImpl implements CustomerService {
- public Customer findCustomer(String id) {
- Customer customer = new Customer();
- customer.setId("customer_" + id);
- customer.setName("customer_name");
- customer.setBirthday(Calendar.getInstance().getTime());
- return customer;
- }
- }
4. 下面是Server端的代码
- package com.googlecode.garbagecan.cxfstudy.jaxws;
- import javax.xml.ws.Endpoint;
- import org.apache.cxf.interceptor.LoggingInInterceptor;
- import org.apache.cxf.interceptor.LoggingOutInterceptor;
- import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
- public class MyServer {
- private static final String address = "http://localhost:9000/ws/jaxws/customerService";
- public static void main(String[] args) throws Exception {
- // http://localhost:9000/ws/jaxws/customerService?wsdl
- JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
- factoryBean.getInInterceptors().add(new LoggingInInterceptor());
- factoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
- factoryBean.setServiceClass(CustomerServiceImpl.class);
- factoryBean.setAddress(address);
- factoryBean.create();
- }
- }
5. 下面是Client端的代码
- package com.googlecode.garbagecan.cxfstudy.jaxws;
- import java.net.SocketTimeoutException;
- import javax.xml.ws.WebServiceException;
- import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
- public class MyClient {
- public static void main(String[] args) throws Exception {
- JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
- factoryBean.setAddress("http://localhost:9000/ws/jaxws/customerService");
- factoryBean.setServiceClass(CustomerService.class);
- Object obj = factoryBean.create();
- CustomerService customerService = (CustomerService) obj;
- try {
- Customer customer = customerService.findCustomer("123");
- System.out.println("Customer: " + customer);
- } catch(Exception e) {
- if (e instanceof WebServiceException
- && e.getCause() instanceof SocketTimeoutException) {
- System.err.println("This is timeout exception.");
- } else {
- e.printStackTrace();
- }
- }
- }
- }
6.测试
首先运行MyServer类,然后运行MyClient类来验证Web Service。
==============
这篇文章介绍一下怎么通过CXF来发布RESTful的Web Service.
1. 首先是实体类,注意其中的@XmlRootElement注解
- package com.googlecode.garbagecan.cxfstudy.jaxrs;
- import java.util.Date;
- import javax.xml.bind.annotation.XmlRootElement;
- @XmlRootElement(name="Customer")
- public class Customer {
- private String id;
- private String name;
- private Date birthday;
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Date getBirthday() {
- return birthday;
- }
- public void setBirthday(Date birthday) {
- this.birthday = birthday;
- }
- @Override
- public String toString() {
- return org.apache.commons.lang.builder.ToStringBuilder.reflectionToString(this);
- }
- }
2. RESTful Web Service接口类,可以通过修改@Produces注解来声明暴露接口返回的json还是xml数据格式
- package com.googlecode.garbagecan.cxfstudy.jaxrs;
- import javax.ws.rs.GET;
- import javax.ws.rs.Path;
- import javax.ws.rs.PathParam;
- import javax.ws.rs.Produces;
- import javax.ws.rs.QueryParam;
- @Path(value = "/customer")
- @Produces("*/*")
- //@Produces("application/xml")
- //@Produces("application/json")
- public interface CustomerService {
- @GET
- @Path(value = "/{id}/info")
- Customer findCustomerById(@PathParam("id")String id);
- @GET
- @Path(value = "/search")
- Customer findCustomerByName(@QueryParam("name")String name);
- }
3. RESTful Web Service接口实现类
- package com.googlecode.garbagecan.cxfstudy.jaxrs;
- import java.util.Calendar;
- public class CustomerServiceImpl implements CustomerService {
- public Customer findCustomerById(String id) {
- Customer customer = new Customer();
- customer.setId(id);
- customer.setName(id);
- customer.setBirthday(Calendar.getInstance().getTime());
- return customer;
- }
- public Customer findCustomerByName(String name) {
- Customer customer = new Customer();
- customer.setId(name);
- customer.setName(name);
- customer.setBirthday(Calendar.getInstance().getTime());
- return customer;
- }
- }
4. Server端代码
- package com.googlecode.garbagecan.cxfstudy.jaxrs;
- import org.apache.cxf.interceptor.LoggingInInterceptor;
- import org.apache.cxf.interceptor.LoggingOutInterceptor;
- import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
- public class MyServer {
- public static void main(String[] args) throws Exception {
- JAXRSServerFactoryBean factoryBean = new JAXRSServerFactoryBean();
- factoryBean.getInInterceptors().add(new LoggingInInterceptor());
- factoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
- factoryBean.setResourceClasses(CustomerServiceImpl.class);
- factoryBean.setAddress("http://localhost:9000/ws/jaxrs");
- factoryBean.create();
- }
- }
5. Client端代码
- package com.googlecode.garbagecan.cxfstudy.jaxrs;
- import org.apache.commons.httpclient.HttpClient;
- import org.apache.commons.httpclient.HttpStatus;
- import org.apache.commons.httpclient.methods.GetMethod;
- public class MyClient {
- public static void main(String[] args) throws Exception {
- go("http://localhost:9000/ws/jaxrs/customer/1/info");
- go("http://localhost:9000/ws/jaxrs/customer/search?name=abc");
- }
- private static void go(String url) throws Exception {
- HttpClient client = new HttpClient();
- GetMethod method = new GetMethod(url);
- int statusCode = client.executeMethod(method);
- if (statusCode != HttpStatus.SC_OK) {
- System.err.println("Method failed: " + method.getStatusLine());
- }
- byte[] responseBody = method.getResponseBody();
- System.out.println(new String(responseBody));
- }
- }
6.测试
首先运行MyServer类,然后运行MyClient类来验证Web Service。
================
在现实应用中有些时候会有比较大的数据对象需要传输,或者在一个比较慢的网络环境下发布调用web service,此时可以通过压缩数据流的方式来减小数据包的大小,从而提高web service的性能。下面来看看怎样来做到这一点。
1. 首先模拟一个可以存放大数据的pojo对象,这个对象可以通过构造参数给定的size来模拟一个size大小的字符串。
- package com.googlecode.garbagecan.cxfstudy.compress;
- public class BigData {
- private String name;
- private String data;
- public BigData() {
- }
- public BigData(String name, int size) {
- this.name = name;
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < size; i++) {
- sb.append("0");
- }
- this.data = sb.toString();
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getData() {
- return data;
- }
- public void setData(String data) {
- this.data = data;
- }
- }
2. Web Service接口类,和普通的接口定义没有什么区别。
- package com.googlecode.garbagecan.cxfstudy.compress;
- import javax.jws.WebMethod;
- import javax.jws.WebParam;
- import javax.jws.WebResult;
- import javax.jws.WebService;
- @WebService
- public interface BigDataService {
- @WebMethod
- @WebResult BigData getBigData(@WebParam String name, @WebParam int size);
- }
3. Web Service实现类
- package com.googlecode.garbagecan.cxfstudy.compress;
- public class BigDataServiceImpl implements BigDataService {
- public BigData getBigData(String name, int size) {
- BigData bigData = new BigData(name, size);
- return bigData;
- }
- }
4. 测试类,这片文章使用了JUnit测试类来做测试。setUpBeforeClass方法用来启动Service, testGetBigData方法用来测试web service。
注意setUpBeforeClass方法中的
factoryBean.getInInterceptors().add(new GZIPInInterceptor());
factoryBean.getOutInterceptors().add(new GZIPOutInterceptor());
和testGetBigData方法中的
endpoint.getInInterceptors().add(new GZIPInInterceptor());
endpoint.getOutInterceptors().add(new GZIPOutInterceptor());
上面两段代码就是告诉CXF使用压缩Interceptor来压缩和解压缩数据包。
- package com.googlecode.garbagecan.cxfstudy.compress;
- import org.apache.cxf.endpoint.Client;
- import org.apache.cxf.endpoint.Endpoint;
- import org.apache.cxf.frontend.ClientProxy;
- import org.apache.cxf.interceptor.LoggingInInterceptor;
- import org.apache.cxf.interceptor.LoggingOutInterceptor;
- import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
- import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
- import org.apache.cxf.transport.http.gzip.GZIPInInterceptor;
- import org.apache.cxf.transport.http.gzip.GZIPOutInterceptor;
- import org.junit.Assert;
- import org.junit.BeforeClass;
- import org.junit.Test;
- public class BigDataServiceTest {
- private static final String address = "http://localhost:9000/ws/compress/bigDataService";
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
- factoryBean.getInInterceptors().add(new LoggingInInterceptor());
- factoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
- factoryBean.getInInterceptors().add(new GZIPInInterceptor());
- factoryBean.getOutInterceptors().add(new GZIPOutInterceptor());
- factoryBean.setServiceClass(BigDataServiceImpl.class);
- factoryBean.setAddress(address);
- factoryBean.create();
- }
- @Test
- public void testGetBigData() {
- JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
- factoryBean.setAddress(address);
- factoryBean.setServiceClass(BigDataService.class);
- Object obj = factoryBean.create();
- Client client = ClientProxy.getClient(obj);
- Endpoint endpoint = client.getEndpoint();
- endpoint.getInInterceptors().add(new GZIPInInterceptor());
- endpoint.getOutInterceptors().add(new GZIPOutInterceptor());
- BigDataService service = (BigDataService) obj;
- Assert.assertNotNull(service);
- String name = "my big data";
- int size = 1024 * 1024 * 10;
- long start = System.currentTimeMillis();
- BigData bigData = service.getBigData(name, size);
- long stop = System.currentTimeMillis();
- System.out.println("Time: " + (stop - start));
- Assert.assertNotNull(bigData);
- Assert.assertEquals(name, bigData.getName());
- Assert.assertEquals(size, bigData.getData().length());
- }
- }
5. 运行此unit test,可以在日志中看到数据包前后大小和内容。
================
我们在使用Web Service的过程中,很多情况是需要对web service请求做认证的,对于运行在web容器里的应用程序来说,可能会比较简单一些,通常可以通过filter来做一些处理,但是其实CXF本身也提供了对web service认证的方式。下面来看一下如何实现
1. 首先是一个简单pojo
- package com.googlecode.garbagecan.cxfstudy.security;
- public class User {
- private String id;
- private String name;
- private String password;
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- }
2. Web Service接口
- package com.googlecode.garbagecan.cxfstudy.security;
- import java.util.List;
- import javax.jws.WebMethod;
- import javax.jws.WebResult;
- import javax.jws.WebService;
- @WebService
- public interface UserService {
- @WebMethod
- @WebResult List<User> list();
- }
3. Web Service实现类
- package com.googlecode.garbagecan.cxfstudy.security;
- import java.util.ArrayList;
- import java.util.List;
- public class UserServiceImpl implements UserService {
- public List<User> list() {
- List<User> users = new ArrayList<User>();
- for (int i = 0; i < 10; i++) {
- User user = new User();
- user.setId("" + i);
- user.setName("user_" + i);
- user.setPassword("password_" + i);
- users.add(user);
- }
- return users;
- }
- }
4. Server端Handler,其中使用了一个Map来存放用户信息,真是应用中可以使用数据库或者其它方式获取用户和密码
- package com.googlecode.garbagecan.cxfstudy.security;
- import java.io.IOException;
- import java.util.HashMap;
- import java.util.Map;
- 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 ServerUsernamePasswordHandler implements CallbackHandler {
- // key is username, value is password
- private Map<String, String> users;
- public ServerUsernamePasswordHandler() {
- users = new HashMap<String, String>();
- users.put("admin", "admin");
- }
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- WSPasswordCallback callback = (WSPasswordCallback) callbacks[0];
- String id = callback.getIdentifier();
- if (users.containsKey(id)) {
- if (!callback.getPassword().equals(users.get(id))) {
- throw new SecurityException("Incorrect password.");
- }
- } else {
- throw new SecurityException("Invalid user.");
- }
- }
- }
5. Client端Handler,用来设置用户密码,在真实应用中可以根据此类和下面的测试类来修改逻辑设置用户名和密码。
- package com.googlecode.garbagecan.cxfstudy.security;
- 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 ClientUsernamePasswordHandler implements CallbackHandler {
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- WSPasswordCallback callback = (WSPasswordCallback) callbacks[0];
- int usage = callback.getUsage();
- System.out.println("identifier: " + callback.getIdentifier());
- System.out.println("usage: " + callback.getUsage());
- if (usage == WSPasswordCallback.USERNAME_TOKEN) {
- callback.setPassword("admin");
- }
- }
- }
6. 单元测试类,注意在Server端添加了WSS4JInInterceptor到Interceptor列表中,在Client添加了WSS4JOutInterceptor到Interceptor列表中。
- package com.googlecode.garbagecan.cxfstudy.security;
- import java.net.SocketTimeoutException;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import javax.xml.ws.WebServiceException;
- import junit.framework.Assert;
- import org.apache.cxf.endpoint.Client;
- import org.apache.cxf.endpoint.Endpoint;
- import org.apache.cxf.frontend.ClientProxy;
- import org.apache.cxf.interceptor.LoggingInInterceptor;
- import org.apache.cxf.interceptor.LoggingOutInterceptor;
- import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
- import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
- import org.apache.cxf.transport.http.HTTPConduit;
- import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
- import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
- import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
- import org.apache.ws.security.WSConstants;
- import org.apache.ws.security.handler.WSHandlerConstants;
- import org.junit.BeforeClass;
- import org.junit.Test;
- public class UserServiceTest {
- private static final String address = "http://localhost:9000/ws/security/userService";
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
- factoryBean.getInInterceptors().add(new LoggingInInterceptor());
- factoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
- Map<String, Object> props = new HashMap<String, Object>();
- props.put("action", "UsernameToken");
- props.put("passwordType", "PasswordText");
- props.put("passwordCallbackClass", ServerUsernamePasswordHandler.class.getName());
- WSS4JInInterceptor wss4JInInterceptor = new WSS4JInInterceptor(props);
- factoryBean.getInInterceptors().add(wss4JInInterceptor);
- factoryBean.setServiceClass(UserServiceImpl.class);
- factoryBean.setAddress(address);
- factoryBean.create();
- }
- @Test
- public void testList() {
- JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
- factoryBean.setAddress(address);
- factoryBean.setServiceClass(UserService.class);
- Object obj = factoryBean.create();
- Client client = ClientProxy.getClient(obj);
- Endpoint endpoint = client.getEndpoint();
- Map<String,Object> props = new HashMap<String,Object>();
- props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
- props.put(WSHandlerConstants.USER, "admin");
- props.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
- props.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientUsernamePasswordHandler.class.getName());
- WSS4JOutInterceptor wss4JOutInterceptor = new WSS4JOutInterceptor(props);
- endpoint.getOutInterceptors().add(wss4JOutInterceptor);
- HTTPConduit conduit = (HTTPConduit) client.getConduit();
- HTTPClientPolicy policy = new HTTPClientPolicy();
- policy.setConnectionTimeout(5 * 1000);
- policy.setReceiveTimeout(5 * 1000);
- conduit.setClient(policy);
- UserService service = (UserService) obj;
- try {
- List<User> users = service.list();
- Assert.assertNotNull(users);
- Assert.assertEquals(10, users.size());
- } catch(Exception e) {
- if (e instanceof WebServiceException
- && e.getCause() instanceof SocketTimeoutException) {
- System.err.println("This is timeout exception.");
- } else {
- e.printStackTrace();
- }
- }
- }
- }
最后运行上面的测试类来测试结果,也可以修改测试方法中的密码,看看错误结果,这里就不在写错误密码的测试用例了,因为我是一懒人。
===============
首先声明我知道有个协议叫ftp,也知道有种编程叫sock编程,但我就是碰到了server对外只开放80端口,并且还需要提供文件上传和下载功能的应用,那好吧,开始干活。
1. 首先是一个封装了服务器端文件路径,客户端文件路径和要传输的字节数组的MyFile类。
- package com.googlecode.garbagecan.cxfstudy.filetransfer;
- public class MyFile {
- private String clientFile;
- private String serverFile;
- private long position;
- private byte[] bytes;
- public String getClientFile() {
- return clientFile;
- }
- public void setClientFile(String clientFile) {
- this.clientFile = clientFile;
- }
- public String getServerFile() {
- return serverFile;
- }
- public void setServerFile(String serverFile) {
- this.serverFile = serverFile;
- }
- public long getPosition() {
- return position;
- }
- public void setPosition(long position) {
- this.position = position;
- }
- public byte[] getBytes() {
- return bytes;
- }
- public void setBytes(byte[] bytes) {
- this.bytes = bytes;
- }
- }
2. 文件传输的Web Service接口
- package com.googlecode.garbagecan.cxfstudy.filetransfer;
- import javax.jws.WebMethod;
- import javax.jws.WebService;
- @WebService
- public interface FileTransferService {
- @WebMethod
- void uploadFile(MyFile myFile) throws FileTransferException;
- @WebMethod
- MyFile downloadFile(MyFile myFile) throws FileTransferException;
- }
3. 文件传输的Web Service接口实现类,主要是一些流的操作
- package com.googlecode.garbagecan.cxfstudy.filetransfer;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.util.Arrays;
- import org.apache.commons.io.FileUtils;
- import org.apache.commons.io.IOUtils;
- public class FileTransferServiceImpl implements FileTransferService {
- public void uploadFile(MyFile myFile) throws FileTransferException {
- OutputStream os = null;
- try {
- if (myFile.getPosition() != 0) {
- os = FileUtils.openOutputStream(new File(myFile.getServerFile()), true);
- } else {
- os = FileUtils.openOutputStream(new File(myFile.getServerFile()), false);
- }
- os.write(myFile.getBytes());
- } catch(IOException e) {
- throw new FileTransferException(e.getMessage(), e);
- } finally {
- IOUtils.closeQuietly(os);
- }
- }
- public MyFile downloadFile(MyFile myFile) throws FileTransferException {
- InputStream is = null;
- try {
- is = new FileInputStream(myFile.getServerFile());
- is.skip(myFile.getPosition());
- byte[] bytes = new byte[1024 * 1024];
- int size = is.read(bytes);
- if (size > 0) {
- byte[] fixedBytes = Arrays.copyOfRange(bytes, 0, size);
- myFile.setBytes(fixedBytes);
- } else {
- myFile.setBytes(new byte[0]);
- }
- } catch(IOException e) {
- throw new FileTransferException(e.getMessage(), e);
- } finally {
- IOUtils.closeQuietly(is);
- }
- return myFile;
- }
- }
4. 一个简单的文件传输异常类
- package com.googlecode.garbagecan.cxfstudy.filetransfer;
- public class FileTransferException extends Exception {
- private static final long serialVersionUID = 1L;
- public FileTransferException() {
- super();
- }
- public FileTransferException(String message, Throwable cause) {
- super(message, cause);
- }
- public FileTransferException(String message) {
- super(message);
- }
- public FileTransferException(Throwable cause) {
- super(cause);
- }
- }
5. 下面是Server类用来发布web service
- package com.googlecode.garbagecan.cxfstudy.filetransfer;
- import javax.xml.ws.Endpoint;
- public class FileTransferServer {
- public static void main(String[] args) throws Exception {
- Endpoint.publish("http://localhost:9000/ws/jaxws/fileTransferService", new FileTransferServiceImpl());
- }
- }
6. 最后是Client类,用来发送文件上传和下载请求。
- package com.googlecode.garbagecan.cxfstudy.filetransfer;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.util.Arrays;
- import org.apache.commons.io.FileUtils;
- import org.apache.commons.io.IOUtils;
- import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
- public class FileTransferClient {
- private static final String address = "http://localhost:9000/ws/jaxws/fileTransferService";
- private static final String clientFile = "/home/fkong/temp/client/test.zip";
- private static final String serverFile = "/home/fkong/temp/server/test.zip";
- public static void main(String[] args) throws Exception {
- long start = System.currentTimeMillis();
- // uploadFile();
- // downloadFile();
- long stop = System.currentTimeMillis();
- System.out.println("Time: " + (stop - start));
- }
- private static void uploadFile() throws FileTransferException {
- InputStream is = null;
- try {
- MyFile myFile = new MyFile();
- is = new FileInputStream(clientFile);
- byte[] bytes = new byte[1024 * 1024];
- while (true) {
- int size = is.read(bytes);
- if (size <= 0) {
- break;
- }
- byte[] fixedBytes = Arrays.copyOfRange(bytes, 0, size);
- myFile.setClientFile(clientFile);
- myFile.setServerFile(serverFile);
- myFile.setBytes(fixedBytes);
- uploadFile(myFile);
- myFile.setPosition(myFile.getPosition() + fixedBytes.length);
- }
- } catch(IOException e) {
- throw new FileTransferException(e.getMessage(), e);
- } finally {
- IOUtils.closeQuietly(is);
- }
- }
- private static void uploadFile(MyFile myFile) throws FileTransferException {
- JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
- factoryBean.setAddress(address);
- factoryBean.setServiceClass(FileTransferService.class);
- Object obj = factoryBean.create();
- FileTransferService service = (FileTransferService) obj;
- service.uploadFile(myFile);
- }
- private static void downloadFile() throws FileTransferException {
- MyFile myFile = new MyFile();
- myFile.setServerFile(serverFile);
- long position = 0;
- while (true) {
- myFile.setPosition(position);
- myFile = downloadFile(myFile);
- if (myFile.getBytes().length <= 0) {
- break;
- }
- OutputStream os = null;
- try {
- if (position != 0) {
- os = FileUtils.openOutputStream(new File(clientFile), true);
- } else {
- os = FileUtils.openOutputStream(new File(clientFile), false);
- }
- os.write(myFile.getBytes());
- } catch(IOException e) {
- throw new FileTransferException(e.getMessage(), e);
- } finally {
- IOUtils.closeQuietly(os);
- }
- position += myFile.getBytes().length;
- }
- }
- private static MyFile downloadFile(MyFile myFile) throws FileTransferException {
- JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
- factoryBean.setAddress(address);
- factoryBean.setServiceClass(FileTransferService.class);
- Object obj = factoryBean.create();
- FileTransferService service = (FileTransferService) obj;
- return service.downloadFile(myFile);
- }
- }
首先需要准备一个大一点的文件,然后修改代码中的clientFile和serverFile路径,然后分别打开uploadFile和downloadFile注释,运行程序,检查目标文件查看结果。
这个程序还是比较简单的,但基本生完成了文件上传下载功能,如果需要,也可以对这个程序再做点修改使其支持断点续传。