Ajax - 基础教程第八章例子学习五

来源:互联网 发布:c#多线程编程实例 pdf 编辑:程序博客网 时间:2024/06/07 02:18

新闻搜索版块 

 老规矩,先贴下web service的地址:http://local.yahooapis.com/LocalSearchService/V3/localSearch?appid=thunderboltsoft&zip=94306&results=10&query=ajax

 这个版块不像前面的自动填充那个,这个是通过你输入的关键字,然后帮你查找新闻,在把这些新闻填充到下面的DIV中。

一。 主界面search.jsp

代码清单8-18 search.jsp

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 

<div id="searchRoot" style="left:500px; top:450px;">
    
<div id="searchHandle">
        
<table width="100%" border="0" class="textbox">
            
<tr>
                
<td align="left" class="controls">
                    Search Powered by Yahoo!
                
</td>
            
</tr>
        
</table>
    
</div>
        
    
<div id="searchContent" class="searchContent">  
        Search term: 
<input class="normalText" type="text" name="searchTerm" id="searchTerm" onfocus="onFocusFunction('searchTerm');"/>
        
<br/>
    
</div>
    
</div>

下面的搜索填充框是在ajaxDashboard.jsp中

<div id="popup" style="position:absolute;overflow:auto;display:none;background-color:white" >
    
</div>

 二。 ajaxDashboard.js在页面加载是运行函数initDomDrag("searchHandle", "searchRoot");这是鼠标拖动方法,但可惜的是新闻填充的DIV是在searchRoot的外面,所以拖动的话是会跟填充框脱离的,感觉这个版块的作者跟前面的版块的作者很大区别,特别是写的js,又长有难读懂。

 加载页面时,ajaxDashboard.js运行了方法

AutocompleteManager.registerHandler(new AutocompleteHandler("searchTerm", "Search", 275, 3));

这个方法的定义是在autocomplete.js中,

var AutocompleteManager = new AutocompleteManagerImpl();
AutocompleteManager是函数AutocompleteManagerImpl()的一个对象。


function AutocompleteManagerImpl() {
    this.textboxes = new Object();
    
    ............................................

    this.registerHandler = function(handler) {
        this.textboxes[handler.id] = handler;
    }
}

这个AutocompleteManager对象的初始化是通过一个Object对象textboxes保存一个AutocompleteHandler(id, url, interval, minLength) 对象,调用这个textboxes很简单,就是知道id就行了,在这个例子中,AutocompleteManager.textboxes[ searchTerm ]就能得到这个对象了,反正id是固定的,所以这个不用想太多了。

function AutocompleteHandler(id, url, interval, minLength) {
    this.id = id;                          //标识对象的id标志
    this.url = url;                       //用到的Servlet
    this.interval = interval;      //循环定时器的设定时间
    this.minLength = minLength;      //查询字符串最少的字节
    this.lastSearchString = "";
    this.timeoutID;                   //循环定时器开关
    this.state = "stopped";      //状态
}

启动Ajax的是<input class="normalText" type="text" name="searchTerm" id="searchTerm" onfocus="onFocusFunction('searchTerm');"/>中的onfocus="onFocusFunction('searchTerm');"

我不明白作者为什么用onfocus,其实用onchange跟onkeyup这些应该也可以的,这些先不管啦,看看

function onFocusFunction(id) {
    AutocompleteManager.startTheInterval(id);
}

 this.startTheInterval = function(id) {
       
        var handler = this.textboxes[id];       //取得AutocompleteHandler对象,主要是要它里面的属性状态

        if(handler.state == "running") {        //如果在上一次启动AJAX没完成,handler.state是running的,防止多次启动AJAX服务
            return;
        }
       
        var functionString = "handleInterval('" + id + "');" ;

        handler.timeoutID = window.setInterval(functionString, handler.interval);  //其实这个是用一次就行了,可以用一次定时器setTimeout,而不是用循环定时器setInterval,虽然用了searchString == handler.lastSearchString的判断使Ajax服务不会重复执行,但用一次定时器setTimeout就不用加多这些东西了,也不用加多定时器开关了
        handler.state = "running";

    }

这个方法中,主要是启动了函数function handleInterval(id) ,

function handleInterval(id) {
    var searchString = document.getElementById(id).value;    //取得输入框的值
    var handler = AutocompleteManager.getHandlerFor(id);   //取得AutocompleteHandler对象

 if(searchString.length < handler.minLength || searchString.length == 0) {//输入值长度为0或小于规定最小长度
        clearPopup();                        //清除popupDIV
        hideAutoComplete();           //隐藏popupDIV,这两个函数很简单,就不列出了
        return;                     
    }

    if(searchString == handler.lastSearchString) {//跟上次输入字符串比较,防止重复启动AJAX服务
        return;
    }

    //Made it this far so make the request一切ok,启动AJAX服务
    doRequest(id, handler.url);
   
    //Remember the last search string保存这次输入字符串
    handler.lastSearchString = document.getElementById(id).value;
}

doRequest方法

function doRequest(textboxID, url) {
    setOffsets(textboxID);      //这个主要是设置popupDIV的偏移量跟输入框能一致,代码是一样的,所以不贴出来
    var textbox = document.getElementById(textboxID);
    if(textbox.value.length > 1) { //taconite框架,没什么好讲的啦
        var ajaxRequest = new AjaxRequest(url);
        ajaxRequest.addNamedFormElements(textboxID);
        ajaxRequest.setPostRequest(showPopup);
        ajaxRequest.sendRequest();
    }
    else if(textbox.value.length == 0) {
        clearPopup();           //清除popupDIV的内容,并设置为隐藏
    }
}

function showPopup(ajaxRequest) {         //设置popupDIV为显示状态
    document.getElementById("popup").style.display = "";
}

js方面的主要过程就是这样啦

如果你想让popupDIV能一起随着鼠标拖动,那要注意我这里给出的修改方法了

首先把ajaxDashboard.jsp中的

<div id="popup" style="position:absolute;overflow:auto;display:none;background-color:white" >
    </div>

放到search.jsp中的searchContentDIV下面,像这样

<div id="searchContent" class="searchContent"> 
        Search term: <input class="normalText" type="text" name="searchTerm" id="searchTerm" onfocus="onFocusFunction('searchTerm');"/>
        <br/>
    </div>
    <div id="popup" style="position:absolute;overflow:auto;display:none;background-color:white" >
    </div>

然后在autocomplete.js中的函数function setOffsets(textboxID)中的

    popup.style.left = 76 + "px";
    popup.style.top = 47 + "px";

设置数字是经过本人的反复试验出来的,使popupDIV能跟输入框的偏移量一致,因为popuoDIV放在searchRootDIV中,所以也能跟着随鼠标拖动

三。 SearchServlet.java,在AJAX服务中用到的servlet

在web.xml中添加

<servlet>
        
<servlet-name>SearchServlet</servlet-name>
        
<servlet-class>ajaxdashboard.servlet.SearchServlet</servlet-class>
    
</servlet>
    
<servlet-mapping>
        
<servlet-name>SearchServlet</servlet-name>
        
<url-pattern>/Search</url-pattern>
    
</servlet-mapping>

代码清单8-19 SearchServlet.java

package ajaxdashboard.servlet;

import ajaxdashboard.service.SearchService;
import java.io.*;
import java.util.Collection;
import javax.servlet.*;
import javax.servlet.http.*;

public class SearchServlet extends HttpServlet {
    
/**
     * 
     
*/
    
private static final long serialVersionUID = 3137159287689087514L;
    
private static final String AJAX_JSP = "/search/searchAutocomplete.jsp";
    
    
protected void processRequest(HttpServletRequest request
                                            , HttpServletResponse response)
                                            
throws ServletException, IOException {
        String searchTerm 
= request.getParameter("searchTerm");
        System.out.println(
" ==========Searching: " + searchTerm);
        SearchService searchService 
= new SearchService();
        Collection results 
= searchService.search(searchTerm);
        
//        for(Iterator it = results.iterator(); it.hasNext();) {
//            System.out.println(((SearchResult)it.next()).toString());
//        }
        
        request.setAttribute(
"results", results);
        request.getRequestDispatcher(AJAX_JSP).forward(request, response);
    }
    
    
protected void doGet(HttpServletRequest request, HttpServletResponse response)
    
throws ServletException, IOException {
        processRequest(request, response);
    }
    
    
protected void doPost(HttpServletRequest request, HttpServletResponse response)
    
throws ServletException, IOException {
        processRequest(request, response);
    }
    
}

跟前面几个版块一样,SearchServlet中的数据的取得主要是用到了SearchService.java,Collection results = searchService.search(searchTerm);再把results放到request变量中,传递到taconite框架页面上

代码清单8-20 SearchService.java


package ajaxdashboard.service;
import ajaxdashboard.domain.SearchResult;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;

/**
 *
 * 
@author Owner
 
*/
public class SearchService {
    
private static final String YAHOO_SEARCH_URL = 
        
"http://local.yahooapis.com/LocalSearchService/V3/localSearch" 
            
+ "?appid=thunderboltsoftware"
            
+ "&zip=94306"
            
+ "&results=10"
            
+ "&query=";

    
private InputStream getResultsInputStream(String searchTerm) throws Exception {
        String url 
= YAHOO_SEARCH_URL + searchTerm;
        System.out.println(
"url: " + url);
     
        HttpURLConnection con 
= (HttpURLConnection)new URL(url).openConnection();
        con.setDoInput(
true);
        con.setDoOutput(
true);
        
        con.setRequestMethod(
"GET");
        
        
return con.getInputStream();
    }
    
    
public Collection search(String searchTerm) {
        Document resultsXML 
= getSearchResultsXML(searchTerm);
        
return parseResults(resultsXML);
    }
    
    
private Document getSearchResultsXML(String searchTerm) {
        SAXBuilder builder 
= new SAXBuilder();
        Document news 
= null;
        
        
try {
            InputStream searchResultsInputStream 
= getResultsInputStream(searchTerm);
            news 
= builder.build(searchResultsInputStream);
        } 
        
catch (JDOMException ex) {
            System.out.println(
"Error: " + ex.toString());
        } 
        
catch (IOException ex) {
            System.out.println(
"Error: " + ex.toString());
        }
        
catch(Exception ex) {
            System.out.println(
"Exception: " + ex.toString());
        }
        
        
return news;
        
    }
    
    
private Collection parseResults(Document results) {
        Collection searchResults 
= new ArrayList();
        Namespace ns 
= Namespace.getNamespace("urn:yahoo:lcl");
        
        Element root 
= results.getRootElement();
        
        List items 
= root.getChildren("Result", ns);
        System.out.println(
"res size: " + items.size());
        Element item 
= null;
        SearchResult result 
= null;
        
for(Iterator it = items.iterator(); it.hasNext();) {
            item 
= (Element)it.next();
            result 
= new SearchResult();

            result.setTitle(item.getChildText(
"Title", ns));
            result.setAddress(item.getChildText(
"Address", ns));
            result.setUrl(item.getChildText(
"Url", ns));
            searchResults.add(result);
        }
        
        
return searchResults;
    }
    
}
 

其实理清整个过程,理解起来很简单的,这个跟新闻标题版块一样是通过链接获取服务的,所以先确定URL,下面的步骤基本都是一样的啦

        HttpURLConnection con = (HttpURLConnection)new URL(url).openConnection(); //打开连接
        con.setDoInput(
true);        //设置连接输入功能
        con.setDoOutput(
true);     //设置连接输出功能
        con.setRequestMethod(
"GET"); //设置请求方式,get或post或其他的

        InputStream searchResultsInputStream = con.getInputStream(); //确定连接输入数据

        SAXBuilder builder = new SAXBuilder();
        Document news = null;

        news = builder.build(searchResultsInputStream); //用SAXBuilder对象把输入的数据转换成一定格式的文档,这里我的理解是xml文档

        //可能是用org.jdom.input.SAXBuilder转换的,所以有命名空间的话,命名空间要设置

        Namespace ns = Namespace.getNamespace("urn:yahoo:lcl"); //注意这里,这个是修改过的了,源代码中用到的是错误的
        Element root = results.getRootElement();         //这个是固定的,取得xml文档的root元素
        List items = root.getChildren("Result", ns);       //取得标记名为<Result>的子元素的数组items

        for(Iterator it = items.iterator(); it.hasNext();) {   //取得子元素数组items中的元素
            item = (Element)it.next();             //items中的元素
            item.getAttribute("id", ns)            //取得该元素的某个属性值                                                                                       

            item.getChildText("Title",ns)      //取得该元素的子元素的值(前提是该子元素已经没子元素了)
        }

这里用到的jdom.jar

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;

//然后你可以把这些数据放到实体类的集合中,再把这个集合保存到request变量中

//像新闻标题版块那个web service是没命名空间的,所以直接用List items = root.getChildren("Result");把ns去掉就行了

四。 searchAutocomplete.jsp

代码清单8-21 searchAutocomplete.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 
<%@ taglib uri="http://taconite.sf.net/tags" prefix="tac" %>

<tac:taconiteRoot>
    
    
<tac:replaceChildren contextNodeID="popup" parseOnServer="true">
        
        
<c:forEach var="result" items="${results}">
            
<div onmouseover="hilite(this);" onmouseout="unhilite(this);">
                
<href="${result.url}" class="autocomplete" target="_blank">
                    ${result.title}
                
</a>
            
</div>
        
</c:forEach>
                       
    
</tac:replaceChildren>
    
</tac:taconiteRoot>

taconite框架,没什么好说的,建议大家去看看taconite框架中的例子,可以学到很多taconite框架的用法,这些都很实用的。

到这里,ajax基础教程第八章的例子,在经过查找错误,改正,对一些地方改良以后,终于完成了,运行你的例子看看吧

原创粉丝点击