`

在java中"模拟" XMLHttpRequest

阅读更多
这里所说的"模拟" 是指 : 在java中,使用类似 XMLHttpRequest 的方式来实现"同步/异步的HttpRequest"功能.


  用 java 实现一个HTTPRequest 并不难. 通过 java.net 包内提供的东东 可以很容易的实现.
  而且我们还有 apache 的 HttpClient 一类的组件可供我们使用 .
  实现 异步的HTTPRequest 当然同样简单 , 再使用一个 Thread就ok了.
  但是 使用上面的 方法 , 实现的往往只是一个 "异步的HTTPRequest"的功能而已,
  使用方式上 还是 很 java的.
 
我在这里所要介绍的 则是使用很"ajax"的方式来实现"异步的HTTPRequest"的功能.
这个 AjaxHttpRequest 类  模仿了 XMLHttpRequest 的实现,
从属性 方法 使用方式上 都尽量的和 XMLHttpRequest 接近.

利用 AjaxHttpRequest 类 可以更自然的实现 ajax请求的服务端代理 等工作.

=============================

当然 本文的技术研究的价值 也许远远大于 实用的价值. :P .


我先来举一个例子 ,  AjaxHttpRequest 类的代码&注释 在后面附上 附件中也会提供该java文件.

大家注意看代码注释 ,我要说的东西更多的都在注释里呢.

一个 用 java 来调用 google 翻译服务的例子 (利用了后面附上的 AjaxHttpRequest 类) :

	/**
	 * 利用这个AjaxHttpReuqest类来实现 对google translate服务的访问 .
	 * 只演示了 "英-->汉"的翻译.
	 * 返回的是JSON字符串,需要使用Json工具类进行转换,这个不难 就不详细举例了.
	 */
	public static void testGoogleTranslate(String words,boolean async) throws IOException {
		Map params=new HashMap();
		params.put("q",words);
		params.put("v","1.0");
		params.put("langpair","en|zh-CN");
		String url="http://ajax.googleapis.com/ajax/services/language/translate";
		
		// 以上为 调用google翻译服务所需要的参数.
		// 下面 是用java 来调用这个 翻译服务.
		// 在 AjaxHttpRequest 类的 帮助下 我们可以使用 类似操作浏览器XHR对象的方式来 实现该功能.
	
		
		// 创建 AjaxHttpRequest对象 相当于 创建 XHR对象.
		// 这里的final 主要是为了"使监听器内部能够调用ajax对象"而加的.
		final AjaxHttpRequest ajax=new AjaxHttpRequest();
		
		// 设置状态监听器,类似 XHR对象的 onreadystatechange 属性.
		// 由于js 和java的本质区别 导致这里可能和 xhr有点不一样,但是应该不难理解.
		ajax.setReadyStateChangeListener(
				// 监听器, 根据需求 实现onReadyStateChange方法即可.
				new AjaxHttpRequest.ReadyStateChangeListener(){
						public void onReadyStateChange() {
							int readyState = ajax.getReadyState();
							//判断状态 然后做出相应处理.
							if (readyState==AjaxHttpRequest.STATE_COMPLETE){
								System.out.println( ajax.getResponseText() );
							}
						}			
				}
		);
		
		// 这里就和 xhr 几乎完全一样了
		ajax.open("POST", url, true);
		
		//这里这个send方法接受的参数是一个map ,当然AjaxHttpRequest类也提供了string的方法
		ajax.send(params);

	}


有了上面的功能 当页面中要使用google的翻译服务时 就不用在引入google的那些js了.
也不用担心 客户端无法访问google的情况了.



下面附上 AjaxHttpRequest类 的完整代码 ( 附件中有下载 )

package com.fins.gt.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;

		
/**
 * AjaxHttpRequest ,用java 模拟 浏览器的 XMLHttpRequest 对象.
 * 目的是 用 操作浏览器中的XHR对象的 方式来处理java端的 http请求.
 * 
 * @author fins
 * 
 * 本类的实现借鉴了 cobra 组件的 org.lobobrowser.html.test.SimpleHttpRequest 类.
 * 可以看作是对 SimpleHttpRequest 类的一个完善和补充.
 * 
 * cobra 组件是一个 Java HTML Renderer & Parser,
 * 官方网站 : http://lobobrowser.org/cobra.jsp
 */

public class AjaxHttpRequest {

	// 对应 XMLHttpRequest 的5种状态.
	public static final int STATE_UNINITIALIZED = 0;
	public static final int STATE_LOADING = 1;
	public static final int STATE_LOADED = 2;
	public static final int STATE_INTERACTIVE = 3;
	public static final int STATE_COMPLETE = 4;

	// 默认的 userAgent 
	public static final String DEFAULT_USERAGENT = "Mozilla/4.0 (compatible; MSIE 6.0;) JavaAjax/1.0";

	// 默认的 编码 
	public static final String DEFAULT_AJAX_CHARSET = "UTF-8";
	public static final String DEFAULT_HTTP_CHARSET = "ISO-8859-1";
	
	// 默认的 HTTP method
	public static final String DEFAULT_REQUEST_METHOD = "POST";

	private int readyState;
	private int status;
	private String statusText;
	private String responseHeaders;
	private byte[] responseBytes;
	private Map responseHeadersMap;
	private Map requestHeadersMap;
	private ReadyStateChangeListener readyStateChangeListener;

	private boolean async;
	private boolean sent;
	private URLConnection connection;
	private String userAgent = DEFAULT_USERAGENT;
	private String postCharset = DEFAULT_AJAX_CHARSET;
	private Proxy proxy;
	
	private URL requestURL;
	protected String requestMethod;
	protected String requestUserName;
	protected String requestPassword;

/////////////////////////////////
/////////////////////////////////

	
	/**
	 * 构造方法. 自动添加 XMLHttpRequest 的一些缺省头信息.
	 * 如果不需要这些头信息,可在创建 AjaxHttpRequest 实例后,
	 * 通过 setRequestHeader/removeRequestHeader/removeAllRequestHeaders 方法
	 * 进行修改或移除. 
	 */
	public AjaxHttpRequest() {
		requestHeadersMap = new LinkedHashMap();
		setRequestHeader("X-Requested-With", "XMLHttpRequest");
		setRequestHeader("Accept",
				"text/javascript, text/html, application/xml, application/json, text/xml, */*");
	}

	/**
	 * 类似 XMLHttpRequest 中的 readyState 属性.
	 */
	public synchronized int getReadyState() {
		return this.readyState;
	}

	/**
	 * 类似 XMLHttpRequest 中的 status 属性.
	 */
	public synchronized int getStatus() {
		return this.status;
	}

	/**
	 * 类似 XMLHttpRequest 中的 statusText 属性.
	 */
	public synchronized String getStatusText() {
		return this.statusText;
	}
	
	/**
	 * 类似 XMLHttpRequest 中的 setRequestHeader 方法.
	 */
	public void setRequestHeader(String key, String value) {
		this.requestHeadersMap.put(key, value);
	}
	
	/**
	 * 类似 XMLHttpRequest 中的 open 方法.
	 */
	public void open(String method, String url, boolean async, String userName, String password)
			throws IOException {
		URL urlObj = createURL(null, url);
		open(method, urlObj, async, userName, password);
	}

	
	/**
	 * 类似 XMLHttpRequest 中的 open 方法.
	 */
	public void open(final String method, final URL url, boolean async, final String userName,
			final String password) throws IOException {
		this.abort();
		Proxy proxy = this.proxy;
		URLConnection c = proxy == null || proxy == Proxy.NO_PROXY ? url.openConnection() : url
				.openConnection(proxy);
		synchronized (this) {
			this.connection = c;
			this.async = async;
			this.requestMethod = method;
			this.requestURL = url;
			this.requestUserName = userName;
			this.requestPassword = password;
		}
		this.changeState(AjaxHttpRequest.STATE_LOADING, 0, null, null);
	}


	/**
	 * 类似 XMLHttpRequest 中的 open 方法.
	 * 省略部分参数的形式.
	 */
	public void open(String url, boolean async) throws IOException {
		open(DEFAULT_REQUEST_METHOD, url, async, null, null);
	}
	
	/**
	 * 类似 XMLHttpRequest 中的 open 方法.
	 * 省略部分参数的形式.
	 */
	public void open(String method, String url, boolean async) throws IOException {
		open(method, url, async, null, null);
	}
	

	/**
	 * 类似 XMLHttpRequest 中的 send 方法.
	 * 支持发送 key-value 形式的数据集合(Map).
	 * 传入map参数, 自动转换成string形式 并调用 send(String) 方法发送.
	 */	
	public void send(Map parameters) throws IOException {
		Iterator keyItr=parameters.keySet().iterator();
		StringBuffer strb=new StringBuffer();
		while (keyItr.hasNext()){
			Object key = keyItr.next();
			String keyStr = encode(key);
			String valueStr = encode(parameters.get(key));
			strb.append(keyStr).append("=").append(valueStr);
			strb.append("&");
		}
		send(strb.toString());
	}
	
	/**
	 * 类似 XMLHttpRequest 中的 send 方法.
	 */
	public void send(final String content) throws IOException {
		final URL url = this.requestURL;
		if (url == null) {
			throw new IOException("No URL has been provided.");
		}
		if (this.isAsync()) {
			new Thread("AjaxHttpRequest-" + url.getHost()) {
				public void run() {
					try {
						sendSync(content);
					} catch (Throwable thrown) {
						log(Level.WARNING, "send(): Error in asynchronous request on " + url, thrown);
					}
				}
			}.start();
		} else {
			sendSync(content);
		}
	}
	
	/**
	 * 类似 XMLHttpRequest 中的 getResponseHeader 方法.
	 */
	public synchronized String getResponseHeader(String headerName) {
		return this.responseHeadersMap == null ? null : (String) this.responseHeadersMap.get(headerName);
	}
	
	/**
	 * 类似 XMLHttpRequest 中的 getAllResponseHeaders 方法.
	 */
	public synchronized String getAllResponseHeaders() {
		return this.responseHeaders;
	}
	
	
	/**
	 * 类似 XMLHttpRequest 中的 responseText 属性.
	 */
	public synchronized String getResponseText() {
		byte[] bytes = this.responseBytes;
		String encoding = getCharset(this.connection);
		if (encoding==null){
			encoding=getPostCharset();
		}
		if (encoding == null) {
			encoding = DEFAULT_HTTP_CHARSET;
		}
		try {
			return bytes == null ? null : new String(bytes, encoding);
		} catch (UnsupportedEncodingException uee) {
			log(Level.WARNING, "getResponseText(): Charset '" + encoding + "' did not work. Retrying with "
					+ DEFAULT_HTTP_CHARSET + ".", uee);
			try {
				return new String(bytes, DEFAULT_HTTP_CHARSET);
			} catch (UnsupportedEncodingException uee2) {
				// Ignore this time
				return null;
			}
		}
	}

	/**
	 * 类似 XMLHttpRequest 中的 responseXML 属性.
	 * TODO : 此方法在java中 并不常使用, 而且需要两个额外的包,两个包不是所有的java环境都有的.
	 *   所以我(fins)把此方法注释条了. 
	 *   如果确实需要此方法 请自行取消该方法的注释,并引入下面列出的类/接口.
	 *     javax.xml.parsers.DocumentBuilderFactory;
	 *     org.w3c.dom.Document;
	 */
//		  public synchronized Document getResponseXML() { 
//			  byte[] bytes =  this.responseBytes; 
//			  if (bytes == null) { 
//				  return null; 
//			  } 
//			  InputStream in =  new ByteArrayInputStream(bytes); 
//			  try { 
//				  return DocumentBuilderFactory.newInstance().newDocumentBuilder() .parse(in); 
//			  }catch (Exception err) { 
//				  log(Level.WARNING,  "Unable to parse response as XML.", err); return null;
//			  }
//		 }
	
	
	/**
	 * 类似 XMLHttpRequest 中的 responseBody 属性.
	 * @deprecated 这个方法命名源自XMLHttpRequest中的responseBody属性.
	 * 不过这个名字并不是好名字.建议使用 getResponseBytes 方法代替之.
	 */
	public synchronized byte[] getResponseBody() {
		return this.getResponseBytes();
	}
	
	/**
	 * 类似 XMLHttpRequest 中的 responseBody 属性.
	 * 建议使用此方法代替 getResponseBody 方法.
	 */
	public synchronized byte[] getResponseBytes() {
		return this.responseBytes;
	}	
	
	/**
	 * 与 XMLHttpRequest 中的 responseStream 属性对应的方法 暂不提供.
	 * 因为1 不常用 2 通常可用 getResponseBytes 方法代替 
	 */
	
	
	/**
	 * 类似 XMLHttpRequest 中的 onreadystatechange 属性.
	 * 设置一个监听器,用来跟踪HttpRequest状态变化.
	 * 参数是一个 ReadyStateChangeListener 对象.
	 * ReadyStateChangeListener 是一个抽象类. 只需 实现 onReadyStateChange方法即可.
	 */
	
	public void setReadyStateChangeListener(ReadyStateChangeListener listener) {
		this.readyStateChangeListener = listener;
	}
	
	/**
	 * 中断 Request 请求. 类似 XMLHttpRequest 中的 abort.
	 */
	public void abort() {
		URLConnection c = null;
		synchronized (this) {
			c = this.getConnection();
		}
		if (c instanceof HttpURLConnection) {
			((HttpURLConnection) c).disconnect();
		} else if (c != null) {
			try {
				c.getInputStream().close();
			} catch (IOException ioe) {
				ioe.printStackTrace();
			}
		}
	}
	
///////////////////////////////////////////////
//// 以上 为 模拟 XMLHttpRequest 对象 相关的方法 ////
///////////////////////////////////////////////
///////////////////////////////////////////////
	
	
	/**
	 * 返回 此次HttpRequest是否是"异步"的.
	 */
	public boolean isAsync() {
		return async;
	}
	
	/**
	 * 返回 此次HttpRequest是否已经发送.
	 * 已经发送 且还没有完全处理完此次发送的返回信息时,是不能再次发送的.
	 * 如果需要联系发送请求, 请再另行创建一个 AjaxHttpRequest对象.
	 */
	public boolean hasSent() {
		return sent;
	}
	protected void setSent(boolean sent) {
		this.sent=sent;
	}
	
	/**
	 * 设置/取得 伪造的  userAgent 信息.通常不用理会.
	 * 很少有http服务会对此做严格的判断.
	 */
	public void setUserAgent(String userAgent) {
		this.userAgent = userAgent;
	}
	public String getUserAgent() {
		return this.userAgent;
	}

	/**
	 * 取得/设置 默认的 AJAX编码.AJAX请求都是UTF-8编码 此属性通常无需改变.
	 */
	public String getPostCharset() {
		return this.postCharset;
	}
	public void setPostCharset(String postCharset) {
		this.postCharset = postCharset;
	}
	
	
	/**
	 * 实现发送数据功能的方法,是整个类的核心. 
	 * 我(fins)借鉴了 cobra 组件的 org.lobobrowser.html.test.SimpleHttpRequest 类中的同名方法.
	 * 略作改动.
	 */
	protected void sendSync(String content) throws IOException {
		if (hasSent()){
			log(Level.WARNING, "This AjaxHttpRequest Object has sent", null);
			return ;
		}
		try {
			URLConnection c;
			synchronized (this) {
				c = this.connection;
			}
			if (c==null){
				log(Level.WARNING, "Please open AjaxHttpRequest first.", null);
				return ;
			}
			setSent(true);
			initConnectionRequestHeader(c);
			int istatus;
			String istatusText;
			InputStream err;
			if (c instanceof HttpURLConnection) {
				HttpURLConnection hc = (HttpURLConnection) c;
				String method = this.requestMethod==null?DEFAULT_REQUEST_METHOD:this.requestMethod;
	
				method = method.toUpperCase();
				hc.setRequestMethod(method);
				if ("POST".equals(method) && content != null) {
					hc.setDoOutput(true);
					byte[] contentBytes = content.getBytes(this.getPostCharset());
					hc.setFixedLengthStreamingMode(contentBytes.length);
					OutputStream out = hc.getOutputStream();
					try {
						out.write(contentBytes);
					} finally {
						out.flush();
					}
				}
				istatus = hc.getResponseCode();
				istatusText = hc.getResponseMessage();
				err = hc.getErrorStream();
			} else {
				istatus = 0;
				istatusText = "";
				err = null;
			}
			synchronized (this) {
				this.responseHeaders = getConnectionResponseHeaders(c);
				this.responseHeadersMap = c.getHeaderFields();
			}
			this.changeState(AjaxHttpRequest.STATE_LOADED, istatus, istatusText, null);
			InputStream in = err == null ? c.getInputStream() : err;
			int contentLength = c.getContentLength();

			this.changeState(AjaxHttpRequest.STATE_INTERACTIVE, istatus, istatusText, null);
			byte[] bytes = loadStream(in, contentLength == -1 ? 4096 : contentLength);
			this.changeState(AjaxHttpRequest.STATE_COMPLETE, istatus, istatusText, bytes);
		} finally {
			synchronized (this) {
				this.connection = null;
				setSent(false);
			}
		}
	}

	
	/**
	 * 当状态变化时 重新设置各种状态值,并触发状态变化监听器.
	 */
	protected void changeState(int readyState, int status, String statusMessage, byte[] bytes) {
		synchronized (this) {
			this.readyState = readyState;
			this.status = status;
			this.statusText = statusMessage;
			this.responseBytes = bytes;
		}
		if (this.readyStateChangeListener!=null){
			this.readyStateChangeListener.onReadyStateChange();
		}
	}

	/**
	 * 对字符串进行 URLEncoder 编码.
	 */
	protected String encode(Object str){
		try {
			return URLEncoder.encode(String.valueOf(str), getPostCharset());
		} catch (UnsupportedEncodingException e) {
			return String.valueOf(str);
		}
	}
	
	/**
	 * 将设置的 RequestHeader 真正的设置到链接请求中.
	 */
	protected void initConnectionRequestHeader(URLConnection c) {
		c.setRequestProperty("User-Agent", this.getUserAgent());
		Iterator keyItor = this.requestHeadersMap.keySet().iterator();
		while (keyItor.hasNext()) {
			String key = (String) keyItor.next();
			String value = (String) this.requestHeadersMap.get(key);
			c.setRequestProperty(key, value);
		}
	}


	/**
	 * 以下 4个 方法 负责处理 requestHeader信息. 
	 */
	public String getRequestHeader(String key) {
		return (String) this.requestHeadersMap.get(key);
	}
	public String removeRequestHeader(String key) {
		return (String)this.requestHeadersMap.remove(key);
	}
	public void removeAllRequestHeaders() {
		this.requestHeadersMap.clear();
	}
	public Map getAllRequestHeaders() {
		return this.requestHeadersMap;
	}
	
	
	
	public URLConnection getConnection() {
		return connection;
	}

	public void setConnection(URLConnection connection) {
		this.connection = connection;
	}
	public Proxy getProxy() {
		return proxy;
	}
	public void setProxy(Proxy proxy) {
		this.proxy = proxy;
	}

	
	
	/////////////////////////////////////////////////////////////////////
	// 以下是 Static Method //////////////////////////////////////////////
	// 这些静态方法其实可以(应该)单独提取出去的, ///////////////////////////////
	// 不过为了让这个程序结构简单些 , 我(fins)就全部 all in one 了.///////////////////
	// 这些方法也不都是我(fins)自己写的 很多是copy 借鉴来的 功能都挺简单的 就不详细说明了 //
	/////////////////////////////////////////////////////////////////////
	
	public static void log(Level level, String msg, Throwable thrown) {
		System.out.println(level.getName() + " : " + thrown.getMessage() + " ----- " + msg);
	}
	public static String getConnectionResponseHeaders(URLConnection c) {
		int idx = 0;
		String value;
		StringBuffer buf = new StringBuffer();
		while ((value = c.getHeaderField(idx)) != null) {
			String key = c.getHeaderFieldKey(idx);
			buf.append(key);
			buf.append(": ");
			buf.append(value);
			idx++;
		}
		return buf.toString();
	}
	public static String getCharset(URLConnection connection) {
		String contentType = connection==null?null:connection.getContentType();
		if (contentType != null) {
			StringTokenizer tok = new StringTokenizer(contentType, ";");
			if (tok.hasMoreTokens()) {
				tok.nextToken();
				while (tok.hasMoreTokens()) {
					String assignment = tok.nextToken().trim();
					int eqIdx = assignment.indexOf('=');
					if (eqIdx != -1) {
						String varName = assignment.substring(0, eqIdx).trim();
						if ("charset".equalsIgnoreCase(varName)) {
							String varValue = assignment.substring(eqIdx + 1);
							return unquote(varValue.trim());
						}
					}
				}
			}
		}
		return null;
	}
	public static String unquote(String text) {
		if (text.startsWith("\"") && text.endsWith("\"")) {
			return text.substring(1, text.length() - 2);
		}
		return text;
	}
	protected static URL createURL(URL baseUrl, String relativeUrl) throws MalformedURLException {
		return new URL(baseUrl, relativeUrl);
	}
	protected static byte[] loadStream(InputStream in, int initialBufferSize) throws IOException {
		if (initialBufferSize == 0) {
			initialBufferSize = 1;
		}
		byte[] buffer = new byte[initialBufferSize];
		int offset = 0;
		for (;;) {
			int remain = buffer.length - offset;
			if (remain <= 0) {
				int newSize = buffer.length * 2;
				byte[] newBuffer = new byte[newSize];
				System.arraycopy(buffer, 0, newBuffer, 0, offset);
				buffer = newBuffer;
				remain = buffer.length - offset;
			}
			int numRead = in.read(buffer, offset, remain);
			if (numRead == -1) {
				break;
			}
			offset += numRead;
		}
		if (offset < buffer.length) {
			byte[] newBuffer = new byte[offset];
			System.arraycopy(buffer, 0, newBuffer, 0, offset);
			buffer = newBuffer;
		}
		return buffer;
	}


	///////////////////////////////////////////////////////////	
	// Listener Class /////////////////////////////////////////
	///////////////////////////////////////////////////////////
	
	/**
	 * 一个用来监听 HttpRequest状态 的监听器. 是一个内部静态抽象类.
	 * 可以根据实际情况来自行重构(如 增加方法、变为独立的外部类等).
	 */
	public static abstract class ReadyStateChangeListener {
		public abstract void onReadyStateChange();
	}
	


	///////////////////////////////////////////////////////////	
	// Test Method ////////////////////////////////////////////
	///////////////////////////////////////////////////////////
	
	/**
	 * 利用这个AjaxHttpReuqest类来实现 对google translate服务的访问 .
	 * 只演示了 "英-->汉"的翻译.
	 * 返回的是JSON字符串,需要使用Json工具类进行转换,这个不难 就不详细举例了.
	 */
	public static void testGoogleTranslate(String words,boolean async) throws IOException {
		Map params=new HashMap();
		params.put("q",words);
		params.put("v","1.0");
		params.put("langpair","en|zh-CN");
		String url="http://ajax.googleapis.com/ajax/services/language/translate";
		
		// 以上为 调用google翻译服务所需要的参数.
		// 下面 是用java 来调用这个 翻译服务.
		// 在 AjaxHttpRequest 类的 帮助下 我们可以使用 类似操作浏览器XHR对象的方式来 实现该功能.
	
		
		// 创建 AjaxHttpRequest对象 相当于 创建 XHR对象.
		// 这里的final 主要是为了"使监听器内部能够调用ajax对象"而加的.
		final AjaxHttpRequest ajax=new AjaxHttpRequest();
		
		// 设置状态监听器,类似 XHR对象的 onreadystatechange 属性.
		// 由于js 和java的本质区别 导致这里可能和 xhr有点不一样,但是应该不难理解.
		ajax.setReadyStateChangeListener(
				// 监听器, 根据需求 实现onReadyStateChange方法即可.
				new AjaxHttpRequest.ReadyStateChangeListener(){
						public void onReadyStateChange() {
							int readyState = ajax.getReadyState();
							//判断状态 然后做出相应处理.
							if (readyState==AjaxHttpRequest.STATE_COMPLETE){
								System.out.println( ajax.getResponseText() );
							}
						}			
				}
		);
		
		// 这里就和 xhr 几乎完全一样了
		ajax.open("POST", url, true);
		
		//这里这个send方法接受的参数是一个map ,当然AjaxHttpRequest类也提供了string的方法
		ajax.send(params);

	}
	
	public static void main(String[] args) throws IOException {
			
		testGoogleTranslate("Hello world!",false);
		
	}
	

}

43
11
分享到:
评论
23 楼 lgbzc 2008-11-19  
看了 感觉不错,但是没运行出来
22 楼 jhaij 2008-11-17  
关注ing...
21 楼 zhentaoliu 2008-11-08  
swantt 写道

HTMLUNIT,目前我用这个.

呵呵
20 楼 liushouzhao 2008-11-08  
您老够猛啊
19 楼 lcfred 2008-11-07  
模拟的非常好,领教了
18 楼 fins 2008-11-06  
xman 写道

你还真能把简单的事情复杂化


这个确实简单  如果用HttpClient来做 几行代码就搞定

我只是想自己动手 模拟一下 ,这样对xmlhttprequest才会有深入的认识

这东西本来也是以技术研究为主的啦 嘿嘿

不算重复造轮子 因为这个根本就不是轮子 ---- 啥也不是 就是一个游戏 
17 楼 showcup 2008-11-06  
htmlunit什么东西
16 楼 xman 2008-11-06  
你还真能把简单的事情复杂化
15 楼 fins 2008-11-06  
不是

我做的就是
用java实现了一个
使用起来和 xmlhttprequest 使用习惯比较接近的
"同步/异步httprequest"
14 楼 harrison2010 2008-11-06  
==我想问的是你这样是不是等于吧ajax的httprequest自己实现了一边啊。请指导
13 楼 fins 2008-11-06  
1.5
其实 那个proxy 可有可无

你把那个属性去掉 然后对代码略做调整就行
12 楼 penghao122 2008-11-06  
用的jdk版本是多少 Proxy找不到呢
11 楼 renyanwei 2008-11-05  
恩 博主很有发现的能力 O(∩_∩)O哈哈~
10 楼 liushilang 2008-11-05  
fins真行,主要代码认真看过了.收录起来,以备后用
9 楼 fins 2008-11-05  
我觉得还是 cobra  好一些, 建议使用

(HtmlUtil没有仔细研究 看看说明 体积, 以及maven就头大了 呵呵)
8 楼 lkjust08 2008-11-05  
LZ很棒,学习了。
7 楼 playfish 2008-11-05  
swantt 写道

HTMLUNIT,目前我用这个.

不知道为什么,用htmlunit在处理结构很复杂的页面时会出现一个很大的问题,就是它要解析非常的久,有时候可能十几kb大小的页面都要处理30秒,不知道swantt是否碰到过这样的问题
6 楼 java.lang.Object 2008-11-04  
不错,很少看到用系统类库实现这么强的功能的代码了
5 楼 wonderful_wenqin 2008-11-04  
howesen 写道

学习了,非常棒!

谢谢啊 !
4 楼 hudong0178 2008-11-04  
不错啊。。顶!!

相关推荐

    在java中\"模拟\" XMLHttpRequest

    通过阅读和分析这个类的源码,我们可以深入了解如何在Java中模拟XMLHttpRequest的工作原理,并将其应用到实际项目中。 总之,`AjaxHttpRequest`类在Java环境中提供了与JavaScript中的XMLHttpRequest相似的功能,...

    全面剖析XMLHttpRequest对象

    XMLHttpRequest对象是Web开发中的关键组件,尤其对于实现AJAX(异步JavaScript和XML)技术至关重要。它允许在不刷新整个页面的情况下与服务器进行通信,极大地提升了用户体验。这个对象在所有现代浏览器中都得到了...

    用法 XMLHttpRequest的用法 ajax同步和异步的区别

    在提供的Java Servlet代码中,定义了处理GET请求的方法`doGet`,该方法模拟长时间运行的任务: ```java @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ...

    JAVA海康威视isup方式demo包,与人脸考勤机打通。适用于人脸考勤机没有固定IP情况.zip

    在实际开发过程中,开发者需要深入理解ISUP协议的工作原理,并将其融合到Java应用程序中。例如,ISUP协议可能会定义一系列的信号流程,用于建立和断开连接、传送控制信息、以及错误处理机制等。开发者需要在Java代码...

    java+js交互Demo

    对于需要在Java后端执行JavaScript的场景,可以使用Apache HttpClient模拟浏览器行为,或者使用Jsoup库解析和操作HTML文档。这样,Java可以发起HTTP请求,获取网页内容,然后通过JavaScript处理。 总之,Java和...

    模拟百度输入提示功能

    在模拟百度输入提示功能中,JavaScript用于捕捉用户在搜索框中的输入事件,当用户输入时,它会触发一个Ajax请求发送到服务器。 **Ajax(Asynchronous JavaScript and XML)** 是一种创建动态网页的技术,允许在不...

    ajax,java即时通讯web qq

    【Ajax与Java即时通讯在Web QQ中的应用】 Ajax(Asynchronous JavaScript and XML)是一种在无需刷新整个网页的情况下,能够更新部分网页的技术。它通过在后台与服务器进行少量数据交换,使得网页实现异步更新,...

    用Ajax构建动态Java程序

    通过以上内容,我们可以了解到Ajax在Java Web开发中的重要作用及其与Java的结合方式。掌握这些技术,将有助于构建出更加高效、用户体验优良的Web应用程序。实际操作时,还需要根据具体项目需求选择合适的技术栈和...

    java ajax简单应用

    在该事件处理器中,检查XMLHttpRequest对象的readyState和status属性,确保请求已完成且成功。接着,使用responseText或responseXML属性获取服务器返回的数据,更新HTML页面的部分内容。 5. **测试与调试**:运行...

    JAVA_基于Java+JSP的人才招聘管理系统(毕业设计作品)毕业设计实现+源码.zip

    在这个系统中,Java主要负责业务逻辑处理,如用户认证、数据验证、业务规则等。 2. **JSP(JavaServer Pages)**:JSP是Java EE中的一个重要组成部分,用于动态网页开发。在系统中,JSP页面用来展示用户界面,接收...

    模拟ie发送http消息

    在JavaScript中,我们可以使用fetch API或XMLHttpRequest,例如: ```javascript fetch('http://example.com', { method: 'GET', headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Trident/7.0; rv:...

    Java相关技术.pdf

    4. 异步数据查询(XMLHttpRequest):允许在不刷新整个页面的情况下获取数据。 5. 绑定机制(JavaScript):将上述技术整合,实现前后端交互。 Android是由Google推出的开源手机操作系统,基于Linux内核。Android...

    HTTP 通信测试或者JAVAServlet测试

    在IT行业中,HTTP通信测试和Java Servlet测试是Web应用程序开发中的关键环节,它们确保了客户端与服务器之间的数据传输准确无误。在这个场景中,我们关注的是如何通过HTTP协议进行通信,以及如何使用Java Servlet来...

    servlet+ajax模拟百度搜索(含jar包)

    在本项目中,我们通过Ajax异步请求与Servlet后台交互,模拟百度搜索时用户输入关键词后实时展示建议结果的效果。下面将详细介绍这两个关键技术和实现过程。 1. Servlet:Servlet是Java Web开发中的一个核心组件,它...

    Java Web典型模块与项目实战大全源代码26

    在Java Web开发中,"典型模块与项目实战大全"是一个重要的学习资源,旨在帮助开发者深入理解和掌握实际项目中的关键技术和架构。本章是常建功编著的《Java Web典型模块与项目实战大全》的第26章,尽管具体章节内容未...

    java web ajax 入门Demo 百度 Google 搜索 提示 ajax 模糊查询

    在这个Demo中,我们将使用Java Web技术和JSP(JavaServer Pages)来处理服务器端逻辑。以下是实现过程的步骤: 1. **创建HTML界面**: 创建一个简单的HTML页面,包含一个输入框和一个按钮。当用户在输入框中输入...

    ajax使用,实现百度搜索范例

    在Java环境中,我们可以使用Servlet或Spring MVC等框架处理Ajax请求。这里以Servlet为例,创建一个处理GET请求的Servlet,解析请求参数,生成模拟的搜索结果,并以JSON格式返回。 ```java @WebServlet("/search") ...

    ajax+jackson 模拟购物车

    在Web开发中,购物车功能是电商网站的核心部分之一,它涉及到用户交互、数据处理和实时更新等多个环节。本项目利用Ajax和Jackson技术来模拟实现购物车的功能,这既体现了前端与后端的异步通信,又展示了JSON数据的...

    基于jsp+servlet+Ajax异步登陆模拟web项目

    【基于jsp+servlet+Ajax异步登陆模拟web项目】是一个典型的Web开发实例,它整合了三种核心技术:JavaServer Pages(JSP)、Servlet以及Asynchronous JavaScript and XML(Ajax)。这个项目的核心目的是实现用户登录...

    java 进度条

    本文将深入探讨如何在Java项目中利用Ajax实现进度条,以提升用户体验,具体通过以下两个步骤: #### 步骤一:创建基本的Ajax进度条 ##### 客户端与服务器交互原理 进度条的实现基于Ajax技术,它允许网页在不重新...

Global site tag (gtag.js) - Google Analytics