用 JAX-WS(jdk自带的实现)方式,这次要在服务中使用一个复杂类型Customer,并实现附件传输的功能,这里使用MTOM的附件传输方式。MTOM(SOAP Message Transmission Optimization Mechanism)是SOAP 消息传输优化机制,MTOM可以在SOAP 消息中发送二进制数据。 先来看Customer类:
package org.duke.jaxws.server;
import java.util.Date;
import javax.activation.DataHandler; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlMimeType; import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Customer") @XmlAccessorType(XmlAccessType.FIELD) public class Customer { private long id; private String name; private Date birthday; @XmlMimeType("application/octet-stream") private DataHandler imageData;
public long getId() { return id; }
public void setId(long 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; }
public DataHandler getImageData() { return imageData; }
public void setImageData(DataHandler imageData) { this.imageData = imageData; }
} MTOM 方式中要传输的附件必须使用javax.activation.DataHandler 类,还要注意必须在类上使用@XmlAccessorType(FIELD)注解,标注JAXB 在进行JAVA 对象与XML 之间进行转换时只关注字段,而不关注属性(getXXX()方法),否则发布Web 服务时会报出现了两个imageData 属性的错误,原因未知,可能是BUG。 然后使用@XmlMimeType 注解标注这是一个附件类型的数据,这里我们标注imageData 是一个二进制文件,当然你也可以使用具体的MIME类型,譬如:image/jpg、image/gif 等,但要考虑到客户端是否支持。 接口类:
package org.duke.jaxws.server;
import javax.jws.WebParam; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.ws.soap.MTOM;
@WebService(name = "Hello") @SOAPBinding(style = SOAPBinding.Style.RPC) @MTOM public interface Hello { public void printContext();
public Customer selectCustomerByName( @WebParam(name = "customer") Customer customer);
public Customer selectMaxAgeCustomer(Customer c1, Customer c2); } @MTOM注解用于开启MTOM功能。 @WebService注解中的name属性标注在接口类上,可以指定wsdl中接口名称,也就是生成的客户端代码中接口类的名字。 @SOAPBinding(style = SOAPBinding.Style.RPC)指定SOAP消息样式,有两个枚举值:SOAPBinding.Style.DOCUMENT(默认)和 SOAPBinding.Style.RPC,可以对比这两种方式生成的wsdl会有所不同,而且生成的客户端代码也会有所不同。 实现类:
package org.duke.jaxws.server;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Set; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.annotation.Resource; import javax.jws.WebService; import javax.xml.ws.WebServiceContext; import javax.xml.ws.handler.MessageContext;
@WebService(serviceName = "Hello", portName = "HelloPort", targetNamespace = "http://server.jaxws.duke.org/", endpointInterface = "org.duke.jaxws.server.Hello") public class HelloImpl implements Hello {
@Resource private WebServiceContext context;
@Override public void printContext() { MessageContext ctx = context.getMessageContext(); Set<String> set = ctx.keySet(); for (String key : set) { System.out.println("{" + key + "," + ctx.get(key) + "}"); try { System.out.println("key.scope=" + ctx.getScope(key)); } catch (Exception e) { System.out.println(key + " is not exits"); } } }
@Override public Customer selectCustomerByName(Customer customer) { if ("duke".equals(customer.getName())) { customer.setId(1); try { customer.setBirthday(new SimpleDateFormat("yyyy-MM-dd") .parse("1985-03-14")); } catch (ParseException e) { e.printStackTrace(); } customer.setImageData(new DataHandler(new FileDataSource(new File( "c:" + File.separator + "duke.jpg")))); } else { customer.setId(2); customer.setBirthday(new Date()); customer.setImageData(new DataHandler(new FileDataSource(new File( "c:" + File.separator + "origin.jpg")))); } return customer; }
@Override public Customer selectMaxAgeCustomer(Customer c1, Customer c2) { try { // 输出接收到的附件 System.out.println("c1.getImageData().getContentType()=" + c1.getImageData().getContentType()); InputStream is = c2.getImageData().getInputStream(); OutputStream os = new FileOutputStream("c:\\temp1.jpg"); byte[] bytes = new byte[1024]; int c; while ((c = is.read(bytes)) != -1) { os.write(bytes, 0, c); } os.close();
System.out.println("c2.getImageData().getContentType()=" + c2.getImageData().getContentType()); is = c2.getImageData().getInputStream(); os = new FileOutputStream("c:\\temp2.jpg"); bytes = new byte[1024]; while ((c = is.read(bytes)) != -1) { os.write(bytes, 0, c); } os.close(); } catch (IOException e) { e.printStackTrace(); }
if (c1.getBirthday().getTime() > c2.getBirthday().getTime()) { return c2; } else { return c1; } } } @WebService注解的serviceName属性指定wsdl中service节点的name属性值。portName属性指定wsdl中 service节点下port节点name属性值。targetNamespace属性指定wsdl根节点definitions的 targetNamespace属性值。endpointInterface属性指定要发布的WebService接口的全路径名,当实现类实现了多个接 口时,需要通过此属性标注哪个类是WebService的服务端点接口(SEI)。 在这个类中,通过@Resource注解注入了一个WebServiceContext对象,这个对象即是WebService的上下文环境。 发布这个服务:
package org.duke.jaxws.server;
import javax.xml.ws.Endpoint;
public class SoapServer { public static void main(String[] args) { Endpoint.publish("http://localhost:8080/Service/Hello", new HelloImpl()); } } 在命令行键入“wsimport -s src -p org.duke.jaxws.client -keep http://localhost:8080/Service/Hello?wsdl”生成客户端代码,拷贝到工程相应文件夹里,这时,就可以调用这个服务了:
package org.duke.jaxws.test;
import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.GregorianCalendar;
import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.namespace.QName;
import org.duke.jaxws.client.Customer; import org.duke.jaxws.client.Hello; import org.duke.jaxws.client.Hello_Service;
public class SoapClient { public static void main(String[] args) throws ParseException, MalformedURLException { QName qName = new QName("http://server.jaxws.duke.org/", "Hello"); Hello_Service helloService = new Hello_Service(new URL( "http://localhost:8080/Service/Hello?wsdl"), qName); Hello hello = (Hello) helloService.getPort(Hello.class);
hello.printContext();
System.out.println("########################################");
Customer customer = new Customer(); customer.setName("duke"); DataSource ds = hello.selectCustomerByName(customer).getImageData() .getDataSource(); String attachmentMimeType = ds.getContentType(); System.out.println(attachmentMimeType); try { InputStream is = ds.getInputStream(); OutputStream os = new FileOutputStream( "c:\\Shawn\\duke-real_temp.jpg"); byte[] bytes = new byte[1024]; int c; while ((c = is.read(bytes)) != -1) { os.write(bytes, 0, c); } } catch (IOException e) { e.printStackTrace(); }
System.out.println("########################################");
Customer c1 = new Customer(); c1.setId(1); c1.setName("duke"); GregorianCalendar calendar = (GregorianCalendar) GregorianCalendar .getInstance(); calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1985-03-14")); try { c1.setBirthday(DatatypeFactory.newInstance() .newXMLGregorianCalendar(calendar)); } catch (DatatypeConfigurationException e) { e.printStackTrace(); } c1.setImageData(new DataHandler(new FileDataSource( "c:\\Shawn\\duke1.jpg")));
Customer c2 = new Customer(); c2.setId(2); c2.setName("abc"); calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1986-03-14")); try { c2.setBirthday(DatatypeFactory.newInstance() .newXMLGregorianCalendar(calendar)); } catch (DatatypeConfigurationException e) { e.printStackTrace(); } c2.setImageData(new DataHandler(new FileDataSource( "c:\\Shawn\\duke-real_temp.jpg")));
Customer c = hello.selectMaxAgeCustomer(c1, c2); System.out.println(c.getName());
} }
|