使用Ajax模仿Google suggest的搜尋提示(Java+JSP+JS實現)
阿新 • • 發佈:2019-01-04
最近專案需要作一個類似google suggest的搜尋提示功能,在網上找了一些資料,自己弄弄就出來了。專案的關鍵是JS。
實際執行效果:即使在輸入的時候前面有空格,也可以正確判斷。
工程結構:
Keywords.java
package com.bird.bean; public class Keywords { private String content; public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Keywords(String content) { this.content = content; } public Keywords() { } }
DBManager.java
GetKeywordsResults.javapackage com.bird.common; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class DBManager { public DBManager() { } public static Connection getConnection() { // String driver = "oracle.jdbc.driver.OracleDriver"; String driver = "com.mysql.jdbc.Driver"; // String url = "jdbc:oracle:thin:@133.0.129.6:1521:oracle"; String url = "jdbc:mysql://127.0.0.1:3306/itbird"; // String username = "nrmdb"; // String passwd = "nrmoptr"; String username = "root"; String passwd = "root"; Connection connection = null; try { Class.forName(driver); connection = DriverManager.getConnection(url, username, passwd); } catch (Exception ex) { ex.printStackTrace(); } return connection; } public static void closeAll(Connection con, PreparedStatement pstmt, ResultSet rs) { try { if (rs != null) { rs.close(); } if (pstmt != null) { pstmt.close(); } if (con != null) { con.close(); } } catch (SQLException ex) { ex.printStackTrace(); } } }
GetKeywordServlet.javapackage com.bird.DAO; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import com.bird.bean.Keywords; import com.bird.common.DBManager; public class GetKeywordsResults { @SuppressWarnings("null") public ArrayList<Keywords> getKeywordsResults(String keyword) { ArrayList<Keywords> list = new ArrayList<Keywords>(); Keywords key = null; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; String sql = "select content from keywords where content like '%" + keyword + "%'"; try { conn = DBManager.getConnection(); pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while (rs.next()) { key = new Keywords(); System.out.println("類似關鍵詞:" + rs.getString(1)); key.setContent(rs.getString(1)); list.add(key); } } catch (Exception e) { e.printStackTrace(); } finally { DBManager.closeAll(conn, pstmt, rs); } return list; } }
package com.bird.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.bird.DAO.GetKeywordsResults;
import com.bird.bean.Keywords;
public class GetKeywordServlet extends HttpServlet {
/**
* 2014-12-18
*
* @author GHYZ
*/
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("123");
resp.setContentType("text/xml;charset=UTF-8");
resp.setHeader("Cache-Control", "no-cache");
// save keyword
String param = null;
String rawQueryStr = req.getQueryString();
String queryStr = java.net.URLDecoder.decode(rawQueryStr, "utf-8");
String[] result = queryStr.split("=");
// keyword
try {
param = result[1];
String pattern = "([\'\"-+*/^()\\]\\[])";
param = param.replaceAll(pattern, "");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("error input!");
return ;
}
param = param.trim();
System.out.println("--->" + param);
ArrayList<Keywords> list = null;
try {
System.out.println("in list Size");
list = new ArrayList<Keywords>();
list = (new GetKeywordsResults().getKeywordsResults(param));
System.out.println(list.size() + "listSize");
} catch (Exception e) {
System.out.println("input error!");
}
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
xml += "<message>";
Iterator<Keywords> iter = list.iterator();
String content;
while (iter.hasNext()) {
Keywords key = iter.next();
content = key.getContent();
xml += "<info>" + content + "</info>";
}
xml += "</message>";
resp.getWriter().write(xml);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doGet(req, resp);
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>getKeywordServlet</servlet-name>
<servlet-class>com.bird.servlet.GetKeywordServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getKeywordServlet</servlet-name>
<url-pattern>/getKeywordServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
build.js
/*
* 判斷按鍵的JavaScript程式碼
*/
var arrOptions = new Array(); //定義一個儲存伺服器返回的陣列
var strLastValue = ""; //定義儲存每次向伺服器傳送請求的引數
var theTextBox; //定義表示文字輸入變數
var currentValueSelect = -1; //定義下拉提示框中預設的選項
window.onload = function() {
var elemSpan = document.createElement("span");
elemSpan.id = "spanOutput";
elemSpan.className = "spanTextDropdown";
document.body.appendChild(elemSpan);
document.Form1.txtUserInput.onkeyup = GiveOptions;
};
function GiveOptions() { //按下鍵的呼叫方法
var intKey = -1;
if (window.event) {
intKey = event.keyCode;
theTextBox = event.srcElement;
}
if (theTextBox.value.length == 0) { //文字框內容為空
HideTheBox();
strLastValue = "";
return false;
}
if (intKey == 13) {
//按下Enter鍵
GrabHighlighted();
theTextBox.blur();
return false;
} else if (intKey == 38) {
//按下 up 鍵
MoveHightlighted(-1);
return false;
} else if (intKey == 40) {
//按下 down 鍵
MoveHightlighted(1);
return false;
}
//進行內容比較
if (theTextBox.value.indexOf(strLastValue) != 0 || arrOptions.length == 0
|| (strLastValue.length == 0 && theTextBox.value.length > 0)
|| (theTextBox.value.length <= strLastValue.length) ) {
strLastValue = theTextBox.value;
strLastValue = strLastValue.replace(/^\s*\'|\s*$/g,"");
TypeAhead(theTextBox.value);
} else {
BuildList(theTextBox.value);
}
};
function removeAllSpace(str) {
return str.replace(/\s+/g, "");
};
function TypeAhead(xStrText) { //傳送請求方法
xStrText = removeAllSpace(xStrText);
if (xStrText == "") return; //判斷如果輸入框內容為空
var url = "getKeywordServlet?param=" + xStrText; //建立傳送地址變數
if ( window.XMLHttpRequest ) { //判斷瀏覽器
req = new XMLHttpRequest();
} else if (window.ActiveXObject()) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
if (req) {
req.open("GET" , url, true); //開啟連線
//設定回撥函式
req.onreadystatechange = function() {
if (req.readyState==4 && req.status==200) {
parseMessage();
}
};
req.send(null); //實現傳送
}
};
function parseMessage() { //分析伺服器返回資料
var xmlDoc = req.responseXML.documentElement; //獲取返回的XML檔案物件
var nodeInfo = xmlDoc.getElementsByTagName("info"); //獲取標記<info>
arrOptions = new Array(); //建立一個數組物件
for (var i = 0; i < nodeInfo.length; i ++) {
arrOptions[i] = nodeInfo[i].firstChild.nodeValue; //儲存<info>到陣列物件中
}
BuildList(theTextBox.value);
strLastValue = theTextBox.value;
};
function BuildList(theText) { //建立下拉提示框方法
//alert("buidList");
theText = removeAllSpace(theText);
SetElementPosition();
var inner = "";
var theMatches = MakeMatches(theText); //獲取索要匹配的物件
for (var i = 0; i < theMatches.length; i++) {
inner += theMatches[i];
}
if (theMatches.length > 0) {
document.getElementById("spanOutput").innerHTML = inner;
document.getElementById("OptionsList_0").className = "spanHighElement";
currentValueSelect = 0;
} else {
HideTheBox();
}
};
function SetElementPosition() {
var selectedPosX = 0;
var selectedPosY = 0;
//建立關於提示框的長度和寬度的變數
var theElement = document.Form1.txtUserInput;
//var theTextBoxInt = document.Form1.txtUserInput;
if (!theElement) {
alert("not found");
return;
}
//為提示框的長度和寬度賦值
var theElemHeight = theElement.offsetHeight;
var theElemWidth = theElement.offsetWidth;
//設定提示框的位置
while ( theElement != null ) {
selectedPosX += theElement.offsetLeft;
selectedPosY += theElement.offsetTop;
theElement = theElement.offsetParent;
}
xPosElement = document.getElementById("spanOutput");
xPosElement.style.left = selectedPosX;
xPosElement.style.width = theElemWidth;
xPosElement.style.top = selectedPosY + theElemHeight;
xPosElement.style.display = "block";
};
var countForId = 0;
function MakeMatches(xCompareStr) {
countForId = 0;
var matchArray = new Array();
for ( var i = 0; i < arrOptions.length; i++) {
//遍歷arrOptions物件
var regExp = new RegExp(xCompareStr , "ig");
if ((arrOptions[i].search(regExp)) >= 0 ) {
//當有匹配的項,呼叫CreatUnderline()方法返回字串
matchArray[matchArray.length] = CreateUnderline(arrOptions[i],
xCompareStr, i);
} else {
continue;
}
}
return matchArray;
};
function MoveHightlighted(xDir) {
if (currentValueSelect >= 0) {
//獲取按鍵的值
newValue = parseInt(currentValueSelect) + parseInt(xDir);
if (newValue > -1 && newValue < countForId) {
currentValueSelect = newValue;
SetHighColor(null);
}
}
};
function ReDraw() {
BuildList(document.Form1.txtUserInput.value);
};
function GrabHighlighted() {
if (currentValueSelect >= 0) {
xVal = document.getElementById("OptionsList_" + currentValueSelect).getAttribute("theArrayNumber");
SetText(xVal);
HideTheBox();
}
};
function HideTheBox() {
document.getElementById("spanOutput").style.display = "none";
currentValueSelect = -1;
};
var undeStart = "<span class='spanMatchText'>";
var undeEnd = "</span>";
var selectSpanStart = "<span style='width:100%;display:block;' " +
" class='spanNormalElement' onmouseover='SetHighColor(this)'";
var selectSpanEnd = "</span>";
function CreateUnderline(xStr, xTextMatch, xVal) {
selectSpanMid = "onclick='SetText(" + xVal + ")'" + " id='OptionsList_" + countForId + "' theArrayNumber='" + xVal + "'>";
countForId++;
var regExp = new RegExp(xTextMatch , "ig");
var start = xStr.search(regExp);
var matchedText = xStr.substring(start, start + xTextMatch.length);
var Replacestr = xStr.replace(regExp, undeStart + matchedText + undeEnd);
return selectSpanStart + selectSpanMid + Replacestr + selectSpanEnd;
};
function SetHighColor(theTextBox) {
if (theTextBox) {
currentValueSelect = theTextBox.id.slice(
theTextBox.id.indexOf("_") + 1 , theTextBox.id.length
);
}
for (var i = 0; i< countForId; i++) {
document.getElementById('OptionsList_' + i).className = 'spanNormalElement';
}
document.getElementById('OptionsList_' + currentValueSelect).className = 'spanHighElement';
};
function SetText(xVal) {
theTextBox = document.Form1.txtUserInput;
theTextBox.value = arrOptions[xVal];
document.getElementById("spanOutput").style.display = "none";
currentValueSelect = -1;
};
index.jsp<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>Google Suggest</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<script type="text/javascript" src="build.js"></script>
<style type="text/css">
.spanTextDropdown {
left: 88px;
width: 171px;
top: 29px;
display: none;
margin-left: 80px;
border: 1px solid gray;
margin-top: -18px;
}
.spanHighElement {
background:navajowhite;
}
</style>
</head>
<body onResize="ReDraw()">
<div>
<form name="Form1" autocomplete="off" id="Form1">
Text Box:
<input type="text" name="txtUserInput" style="width: 182px;"/>
<!-- hidden zone -->
<input type="hidden" name="txtUserValue" id="hidden1"/>
<!-- help text input -->
<input type="text" name="txtIgnore" style="display: none;"/>
</form>
</div>
</body>
</html>