上一篇写了个最简单的小例子,只是为了说明JAVA6开发Web Service很方便,这一篇稍微深入一点,写个稍微有点代表性的小例子。
依然使用 JAX-WS(jdk自带的实现)方式,这次要在服务中使用一个复杂类型Customer,并实现附件传输的功能,这里使用MTOM的附件传输方式。MTOM(SOAP Message Transmission Optimization Mechanism)是SOAP 消息传输优化机制,MTOM可以在SOAP 消息中发送二进制数据。
先来看Customer类:
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 等,但要考虑到客户端是否支持。
接口类:
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会有所不同,而且生成的客户端代码也会有所不同。
实现类:
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的上下文环境。
发布这个服务:
import javax.xml.ws.Endpoint;
public class SoapServer {
public static void main(String[] args) {
Endpoint.publish( " http://localhost:8080/Service/Hello " , new HelloImpl());
}
}
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());
}
}