如何定期向当前网页添加新的搜索匹配

时间:2011-11-15 09:23:27

标签: ajax jsp servlets queue

我有一个自制的框架/ API,它会进行一些可能需要很长时间的数据库搜索。长时间意味着几秒到几分钟,具体取决于输入。搜索将结果放入java.util.concurrent.BlockingQueue中。因此,第一个搜索结果是immediatley可用。

我现在想要创建一个搜索页面,在提交搜索后,结果页面立即加载这些首次点击,然后定期添加后续点击直到搜索完成。我怎么能这样做?

1 个答案:

答案 0 :(得分:0)

行。我想出了一个解决方案。

大警告: 未经测试用于生产用途!

使用的javascript依赖项:JQuery,jquery datatables插件(http://datatables.net)和用于数据表的fnStandingRedraw插件。

Java依赖:googles Gson库

我有一个提交给servlet的搜索页面。

servlet启动搜索并将搜索线程和BlockingQueue放入会话中,然后重定向到结果页面:

final LinkedBlockingQueue<Integer> hits =
    new LinkedBlockingQueue<Integer>();
Thread searcher = new Thread() {

@Override
public void run() {

    query.search(hits);
}
};
searcher.start();
session.setAttribute("searchQueue", hits);            
session.setAttribute("searchThread", searcher);
response.sendRedirect("SearchResult.jsp");

请注意,Queue中填充了数据库中的主键,因此为整数。

结果页面需要以下参考:

<link href="css/datatables/demo_table.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="js/jquery-1.6.2.js"></script>
<script type="text/javascript" src="js/jquery.dataTables.min.js"></script>               
<script type="text/javascript" src="js/datatables.fnStandingRedraw.js"></script>  

并按照javascript代码初始化表并添加行:

<script type="text/javascript">    
    var resultsTable;
    var myTimer;

    $(document).ready(function() {
        resultsTable = $('#result').dataTable( {
            "bDeferRender": true,
            "bProcessing": true,
            "sPaginationType": "full_numbers",
            "iDisplayLength": 4,            
            "aLengthMenu": [[4, -1], [4, "All"]],
            "sScrollY": "580", 
            "aaSorting": [],
            "aoColumns": [
            /* column1 */   {"bSearchable": true, 
                    "bSortable": true,
                    "sWidth": "50px"},
                /* column2*/{"bSearchable": false, 
                    "bSortable": false,
                    "sWidth": "510px"}
            ]
        } );            
        getAndAddRows();
        startTimer();
    } ); 

    function startTimer() {
        myTimer = window.setInterval( function() {
            getAndAddRows();
        }, 500);
    };

    function stopTimer(){
        window.clearInterval(myTimer);
    }


    function getAndAddRows(){
    $.get(
        'getSearchHits',
        function(data){
            if(data[0] == 'searchCompleted'){
                    stopTimer();
                    $('#hitsFound').text('Hits Found: ' 
                        + resultsTable.fnSettings().fnRecordsTotal()
                        + ' Search Completed');  
                    return;
            }
            $('#result').dataTable().fnAddData(data, false);            
            resultsTable.fnStandingRedraw();
            $('#hitsFound').text('Hits Found: ' 
                + resultsTable.fnSettings().fnRecordsTotal()
                + ' Searching...');  
        }, 
        "json"
        );    
    } 
</script>

<h1 id="hitsFound">Hits Found:</h1>

<table id="result">
    <thead>
        <tr>
            <th>column1</th>
            <th>column2</th>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>

请参阅数据表主页,了解如何设置此类表格。 基于计时器定期调用JQuery get-function。它调用另一个从队列中读取的servlet并返回格式为JSON的新命中:

int limit = 50; //amount of records ro return
int counter = 0;
BlockingQueue<Integer> hits = (BlockingQueue<Integer>) session.getAttribute("searchQueue");
Thread searcher = (Thread) session.getAttribute("searchThread");
Gson gson = new Gson();
ArrayList<ArrayList> rows = new ArrayList<ArrayList>();

while (hits.size() > 0 && limit > counter) {
    ArrayList row = new ArrayList();
    Integer key = hits.take();
    // get desired data and add it to current row example:
    String myData = dataccessObject.getMyData(key); 

    row.add(key);
    row.add(myData);

    rows.add(row);      
    counter++;
}

if (rows.size() < 1 && !searcher.isAlive()) {
    out.print("[\"searchCompleted\"]");
} else {
    String json = gson.toJson(rows); //==> json is [[1,"myData1"],[2,"myData2"]]        
    out.print(json);
}

可能需要根据您的目的调整限制和计时器。有限制,以便实际定期添加新结果。 (如果获取数据的速度低于找到新命中的速度,则在搜索完成之前不会返回任何内容并显示。)

请注意,字符串myData可以是HTML,并以HTML格式呈现。在我的情况下,我返回图像标签。这些图像标签有另一个servlet作为动态创建图像的源。请注意,datatables选项“bDeferRender”:true仅在第一次可见时才会呈现相应的行(在我的情况下为图像)。例如。如果用户只查看前3页,则4-100页实际上从未实现过渲染。如果用户点击最后一页,则只有最后一页被渲染,而不是全部。

如有任何问题或改进/可能的错误,请发表评论。