标题:编写轻量级WebService服务器
作者:Lee353086(kagula)
日期:2007-12-15
目的:通过示例代码和其它样例文件,你将了解[1]如何解析和生成soap信息[2]简单的http server端编程
阅读对象:
java程序员
环境:
[1]IBM JAVA JDK(From WebSphere6.1安装包)
[2]MyEclipse5.1.x
内容:
java源代码(含大量注解)和xml样例文件。
注意:
NHttpServer.java文件,根据
http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-nio/src/examples/org/apache/http/examples/nio/NHttpServer.java
文件修改而来。
必须信赖包:
[1]saaj.jar(可以使用Axis1.4发行包中的saaj.jar)
[2]httpcore-4.0-alpha6.jar、httpcore-nio-4.0-alpha6.jar等包来自http://jakarta.apache.org/httpcomponents/
正文:
第一部份:NHttpServer.java源文件清单
---------------------------------------------------------------------------------------------------------------------------
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.util.Iterator;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.MethodNotSupportedException;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.nio.DefaultServerIOEventDispatch;
import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
import org.apache.http.nio.NHttpConnection;
import org.apache.http.nio.protocol.BufferingHttpServiceHandler;
import org.apache.http.nio.protocol.EventListener;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.ListeningIOReactor;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.protocol.HttpRequestHandlerRegistry;
import org.apache.http.protocol.ResponseConnControl;
import org.apache.http.protocol.ResponseContent;
import org.apache.http.protocol.ResponseDate;
import org.apache.http.protocol.ResponseServer;
import org.apache.http.util.EntityUtils;
public class NHttpServer {
public static void main(String[] args) throws Exception {
Log log=LogFactory.getLog("NHttpServer");
//设置Http服务器根目录.begin
args=new String[1];
args[0]="WebRoot";
// 设置Http服务器根目录.end
if (args.length < 1) {
log.error("Please specify document root directory");
System.exit(1);
}
/**
* 设置Http Server参数
*/
HttpParams params = new BasicHttpParams(null);
params
.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 30*60*1000)
.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "Jakarta-HttpComponents-NIO/1.1");
/**
* Httpproc拦截器
*/
BasicHttpProcessor httpproc = new BasicHttpProcessor();
httpproc.addInterceptor(new ResponseDate());
httpproc.addInterceptor(new ResponseServer());
httpproc.addInterceptor(new ResponseContent());
httpproc.addInterceptor(new ResponseConnControl());
BufferingHttpServiceHandler handler = new BufferingHttpServiceHandler(
httpproc,
new DefaultHttpResponseFactory(),
new DefaultConnectionReuseStrategy(),
params);
// Set up request handlers
HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
reqistry.register("*", new HttpFileHandler(args[0]));
handler.setHandlerResolver(reqistry);
// Provide an event logger
handler.setEventListener(new EventLogger());
IOEventDispatch ioEventDispatch = new DefaultServerIOEventDispatch(handler, params);
ListeningIOReactor ioReactor = new DefaultListeningIOReactor(2, params);
try {
ioReactor.listen(new InetSocketAddress(8080));
ioReactor.execute(ioEventDispatch);
} catch (InterruptedIOException ex) {
log.error("Interrupted");
} catch (IOException e) {
log.error("I/O error: " + e.getMessage());
}
log.debug("Shutdown");
}
static class HttpFileHandler implements HttpRequestHandler {
private final String docRoot;
private final Log log=LogFactory.getLog("HttpFileHandler");
public HttpFileHandler(final String docRoot) {
super();
this.docRoot = docRoot;
}
public void handle(
final HttpRequest request,
final HttpResponse response,
final HttpContext context) throws HttpException, IOException {
String method = request.getRequestLine().getMethod().toUpperCase();
log.debug("request.getRequestLine().getMethod().toUpperCase() => "+method);
if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) {
throw new MethodNotSupportedException(method + " method not supported");
}
//测试SOAP原始上传内容.begin
/*
if (request instanceof HttpEntityEnclosingRequest) {
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
byte[] entityContent = EntityUtils.toByteArray(entity);
log.debug("Incoming entity content (bytes): " + entityContent.length);
log.debug("Incoming entity content (String):"+new String(entityContent,"utf-8"));
}
*/
//测试SOAP原始上传内容.end
//检查上传url(不包括本地服务器地址).begin
String target = request.getRequestLine().getUri();
log.debug("request.getRequestLine().getUri() => "+target);
// 检查上传url(不包括本地服务器地址).end
String strWS="/ws";
if(target.equalsIgnoreCase(strWS))
{
log.debug("处理WebService服务请求");
wsProcessing(request,response);
}else {
//默认,http请求,处理函数
final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8"));
defaultProcessing(response,file);
}
}
/**
* WebService请求,处理函数
*
*/
public void wsProcessing(final HttpRequest request,final HttpResponse response)
{
if (request instanceof HttpEntityEnclosingRequest) {
try {
//取从Axis1.4发过来的请求
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
byte[] entityContent = EntityUtils.toByteArray(entity);
// create the actual message
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
//Create objects for the message parts
SOAPPart soapPart = message.getSOAPPart();
//construct from ByteArrayInputStream
StreamSource preppedMsgSrc = new StreamSource(new ByteArrayInputStream(entityContent));
/*
String MsgSrc=new String("<soapenv:Envelope xmlns:soapenv=/"http://schemas.xmlsoap.org/soap/envelope//" xmlns:xsd=/"http://www.w3.org/2001/XMLSchema/" xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/"><soapenv:Body><JWSendLog soapenv:encodingStyle=/"http://schemas.xmlsoap.org/soap/encoding//"><arg0 xsi:type=/"soapenc:string/" xmlns:soapenc=/"http://schemas.xmlsoap.org/soap/encoding//">cd8f0a5a585940aa8420fb439311656d</arg0><arg1 xsi:type=/"soapenc:string/" xmlns:soapenc=/"http://schemas.xmlsoap.org/soap/encoding//">0</arg1><arg2 xsi:type=/"soapenc:string/" xmlns:soapenc=/"http://schemas.xmlsoap.org/soap/encoding//">kagula uid</arg2></JWSendLog></soapenv:Body></soapenv:Envelope>");
StreamSource preppedMsgSrc = new StreamSource(new ByteArrayInputStream(MsgSrc.getBytes()));
*/
soapPart.setContent(preppedMsgSrc);
//Save the message
// message.saveChanges();
//iterator body content.begin
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body=envelope.getBody();
Iterator iter=body.getChildElements();
while(iter.hasNext())
{
//may be could be for getting call method name
//among these important is getNodeName(),getValue()
//SOAPElement content.begin
SOAPElement element=(SOAPElement)iter.next();
log.debug("SOAPElement.getNodeName="+element.getNodeName()+",getNodeType="+element.getNodeType()+",getNodeValue="+element.getNodeValue());
log.debug("SOAPElement.getPrefix="+element.getPrefix()+",getTagName="+element.getTagName()+",getValue="+element.getValue());
//SOAPElement content.end
Iterator eiter=element.getChildElements();
while(eiter.hasNext())
{
//may be could read for getting call method 's parameters
//SOAPElement content.begin
SOAPElement subelement=(SOAPElement)eiter.next();
log.debug("SOAPElement.getNodeName="+subelement.getNodeName()+",getNodeType="+subelement.getNodeType()+",getNodeValue="+subelement.getNodeValue());
log.debug("SOAPElement.getPrefix="+subelement.getPrefix()+",getTagName="+subelement.getTagName()+",getValue="+subelement.getValue());
//SOAPElement content.end
}
}
//iterator body content.end
//Check the input
/*
System.out.println("/nREQUEST:/n");
message.writeTo(System.out);
System.out.println();
*/
}catch(Exception e)
{
log.error("soap error:"+e.toString());
}
}//end if (request instanceof HttpEntityEnclosingRequest)
//返回SOAP格式,信息
returnSOAP(response,new String("你好!这是我的反馈信息。(Hello!It's my response msg.)"));
}
/**
* 返回WebService服务请求的响应
* @param response
* @param strMsg
*/
public void returnSOAP(final HttpResponse response,final String strMsg)
{
try {
MessageFactory fac = MessageFactory.newInstance();
SOAPMessage msg=fac.createMessage();
SOAPPart part=msg.getSOAPPart();
SOAPEnvelope envelope=part.getEnvelope();
SOAPBody body=envelope.getBody();
Name bodyName=envelope.createName("Response", "", "http://tempuri.org/");
SOAPBodyElement list =body.addBodyElement(bodyName);
Name resultN = envelope.createName("result");
SOAPElement result = list.addChildElement(resultN);
result.addTextNode(strMsg);
msg.saveChanges();
msg.writeTo(System.out);
log.debug("SOAPEnvelope.toString()"+envelope.toString());
//response
response.setStatusCode(HttpStatus.SC_OK);
StringEntity entity=new StringEntity(envelope.toString());
response.setEntity(entity);
} catch (Exception ex) {
log.error("returnSOPA()=>"+ex.toString());
}
}
/**
* http请求,缺省处理函数
* @param response
* @param file
*/
public void defaultProcessing(final HttpResponse response,final File file)
{
if (!file.exists()) {
response.setStatusCode(HttpStatus.SC_NOT_FOUND);
EntityTemplate body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<html><body><h1>");
writer.write("File ");
writer.write(file.getPath());
writer.write(" not found");
writer.write("</h1></body></html>");
writer.flush();
}
});
body.setContentType("text/html; charset=UTF-8");
response.setEntity(body);
log.error("File " + file.getPath() + " not found");
} else if (!file.canRead() || file.isDirectory()) {
response.setStatusCode(HttpStatus.SC_FORBIDDEN);
EntityTemplate body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<html><body><h1>");
writer.write("Access denied");
writer.write("</h1></body></html>");
writer.flush();
}
});
body.setContentType("text/html; charset=UTF-8");
response.setEntity(body);
log.error("Cannot read file " + file.getPath());
} else {
response.setStatusCode(HttpStatus.SC_OK);
FileEntity body = new FileEntity(file, "text/html");
response.setEntity(body);
log.debug("Serving file " + file.getPath());
}
}
}
static class EventLogger implements EventListener {
private final Log log=LogFactory.getLog("EventLogger");
public void connectionOpen(final NHttpConnection conn) {
log.debug("Connection open: " + conn);
}
public void connectionTimeout(final NHttpConnection conn) {
log.debug("Connection timed out: " + conn);
}
public void connectionClosed(final NHttpConnection conn) {
log.debug("Connection closed: " + conn);
}
public void fatalIOException(final IOException ex, final NHttpConnection conn) {
log.debug("I/O error: " + ex.getMessage());
}
public void fatalProtocolException(final HttpException ex, final NHttpConnection conn) {
log.debug("HTTP error: " + ex.getMessage());
}
}
}
---------------------------------------------------------------------------------------------------------------------------
第二部份:客户端代码片段(使用了Axis1.4)
---------------------------------------------------------------------------------------------------------------------------
...by omit...
try
{
String endpoint = "http://localhost:8080/ws";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName("JWSendLog");
ret = (String) call.invoke(new Object[]{"cd8f0a5a585940aa8420fb439311656d","0","kagula uid","0"});
}catch(AxisFault af)
{
System.out.println("Reason:"+af.getFaultReason());
}catch (ServiceException se)
{
se.printStackTrace();
}catch(Exception e)
{
e.printStackTrace();
}
System.out.println("testSMSWebService_JWSendLog(...) ret="+ret);
...by omit...
---------------------------------------------------------------------------------------------------------------------------
第三部份:请求SOAP样例
---------------------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<JWSendLog soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<arg0 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
cd8f0a5a585940aa8420fb439311656d
</arg0>
<arg1 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">0</arg1>
<arg2 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">kagula uid</arg2>
<arg3 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">中文参数测试</arg3>
</JWSendLog>
</soapenv:Body>
</soapenv:Envelope>
---------------------------------------------------------------------------------------------------------------------------
第四部份:返回SOAP样例
---------------------------------------------------------------------------------------------------------------------------
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<Response xmlns="http://tempuri.org/">
<result xmlns="">你好!这是我的反馈信息。(Hello!It's my response msg.)
</result>
</Response>
</soapenv:Body>
</soapenv:Envelope>
---------------------------------------------------------------------------------------------------------------------------
第五部份:使用简介
启动程序后,在地址栏中打入http://localhost:8080/ws也会返回xml形式的内容。
在地址栏中打入http://localhost:8080/index.html,WEB浏览器会去access你项目当前运行目录下的WebRoot目录下的index.html文件。
如果没有找到文件,返回,文件不存在的提示。
参考网站:
[1]axis官方网站
http://ws.apache.org/axis/
[2]httpcomponents项目官方网站
http://jakarta.apache.org/httpcomponents/
备注:
[1]代码经过修改,可以不依赖于Axis1.4提供的jar包
[2]本文中的代码,只有通过必要修改,才能作为WebService服务器使用。