上周末听了在用友工作的两个学长的一个小讲座,虽然时间不长,但还是有些收获的,其中一个开发部的经理就提到了一些小的技术点,其中就包括dwr,回家后上网查了查相关资料,了解到dwr是一个java开源框架,它的诞生就是为了降低开发ajax的难度,原理类似于在javascript中调用java类,于是就使用dwr技术模拟Google首页做了个练习。由于正直全国哀悼日,页面效果与各大网站相同,采用灰色样式,在这里祝愿遭受灾难的亲人们早日重建家园。
后台数据库为Oracle:
--创建查询信息表 create table searchInfo ( id number not null primary key,--编号 content varchar2(100) not null,--查询内容 count number not null--查询次数 ) --创建序列 create sequence seq_searchInfo; --创建插入数据的存储过程 create or replace procedure proc_add(vContent varchar2,vResult out varchar2) as vCount number; begin select count(*) into vCount from searchInfo where content = vContent; if vCount = 0 then insert into searchInfo values(seq_searchInfo.Nextval,vContent,1); else update searchInfo set count = count + 1 where content = vContent; end if; vResult := 'success'; exception when others then vResult := 'fail'; end;
首先需要把dwr.jar导入到WEB-INF/lib目录下,然后在web.xml文件中配置DWRServlet
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet> <description> This is the description of my J2EE component </description> <display-name> This is the display name of my J2EE component </display-name> <servlet-name>ServletX</servlet-name> <servlet-class>control.ServletX</servlet-class> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ServletX</servlet-name> <url-pattern>/ServletX</url-pattern> </servlet-mapping> </web-app>
接着需要在WEB-INF/lib目录下创建dwr.xml文件,并对javascript要调用的类进行声明并公开方法,当然默认公开全部方法,需要提到的是,若类方法的参数或返回值为Bean,则还需要使用convert标签
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr/dwr20.dtd"> <dwr> <allow> <create creator="new" javascript="history"> <param name="class" value="operation.OperSearchInfo" /> <include method="getHistory" /> </create> <convert converter="bean" match="entity.SearchInfo"> <param name="include" value="content,count" /> </convert> </allow> </dwr>
两个xml文件配置好后,可以在地址栏中输入http://localhost:9527/工程名/dwr进行测试,若测试成功,将显示可用的类及其方法
创建控制器ServletX.java,本例中只是判断用户的搜索操作是否成功,并以控制台的形式输出
package control; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import operation.*; public class ServletX extends HttpServlet { private static final long serialVersionUID = 1L; public ServletX() { super(); } public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String model = request.getParameter("model"); if(model.equals("search")){ String content = Translation.transCode(request.getParameter("content")); OperSearchInfo obj = new OperSearchInfo(); if(obj.search(content)){ System.out.println("success"); }else{ System.out.println("fail"); } } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } public void init() throws ServletException { // Put your code here } }
创建与数据库表对应的实体Bean,SearchInfo.java文件
package entity; /** *//** * 搜索信息表实体 * @author 非凡DZ * */ public class SearchInfo { private int id;//编号 private String content;//查询内容 private int count;//查询次数 public String getContent() { return content; } public void setContent(String content) { this.content = content; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
创建对数据库表searchInfo进行操作的类OperSearchInfo.java及方法
package operation; import java.sql.*; import java.util.*; import db.DataBase; import entity.SearchInfo; /** *//** * 该类包含对searchInfo表所有操作 * @author 非凡DZ * */ public class OperSearchInfo { /** *//** * 用户点击搜索按钮后执行 * @param content * @return */ public boolean search(String content){ boolean flag = false; DataBase db = new DataBase(); Connection con = db.getConnection(); CallableStatement cs = null; try{ cs = con.prepareCall("{call proc_add(?,?)}"); cs.setString(1, content); cs.registerOutParameter(2, java.sql.Types.CHAR); cs.execute(); if(cs.getString(2).equals("success")){ flag = true; } }catch(Exception e){ System.out.println("proc异常"+e.getMessage()); e.printStackTrace(); }finally{ try{ con.close(); }catch(Exception ex){ System.out.println("关闭连接异常"+ex.getMessage()); ex.printStackTrace(); } } return flag; } /** *//** * 获得与界面文本框中信息相似的前10条信息 * @param content 界面文本框中的数据 * @return 相似信息 */ public ArrayList getHistory(String content){ DataBase db = new DataBase(); Connection con = db.getConnection(); ResultSet rs = null; ArrayList<SearchInfo> aryResult = new ArrayList<SearchInfo>(); String sql = "select content,count from searchInfo where content" +" like ? and rownum <= 10 order by count desc"; try{ if(!content.equals("")){ PreparedStatement pstn = con.prepareStatement(sql); pstn.setString(1, content+"%"); rs = pstn.executeQuery(); while(rs.next()){ SearchInfo info = new SearchInfo(); info.setContent(rs.getString(1)); info.setCount(rs.getInt(2)); aryResult.add(info); } } }catch(Exception e){ System.out.println("获得历史查询信息异常"+e.getMessage()); e.printStackTrace(); }finally{ try{ con.close(); }catch(Exception ex){ System.out.println("关闭连接异常"+ex.getMessage()); ex.printStackTrace(); } } return aryResult; } }
Translation类用于处理数据传输的编码问题
package operation; import java.io.*; /** *//** * 该类用于解决编码问题 * @author 非凡DZ * */ public class Translation { public Translation() { } public static String transCode(String str){ String temp = null; if(str == null){ temp = ""; } try { temp = new String(str.getBytes("iso8859-1"), "utf-8"); } catch (UnsupportedEncodingException ex) { } return temp; } }
DataBase用于获得数据库连接
package db; import java.sql.*; /** *//** * 该类用于获取数据库连接 * @author 非凡DZ * */ public class DataBase { private Connection con; private String driver = "oracle.jdbc.driver.OracleDriver"; private String url = "jdbc:oracle:thin:@localhost:1521:daizhenghenry"; private String uid = "daizheng"; private String pwd = "daizheng"; public Connection getConnection(){ try{ Class.forName(driver); con = DriverManager.getConnection(url, uid, pwd); }catch(Exception e){ System.out.println("连接异常"+e.getMessage()); e.printStackTrace(); } return con; } }
最后是jsp页面
<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>模拟搜索引擎</title> <mce:style type="text/css"><!-- html {}{ filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); } --></mce:style><style type="text/css" mce_bogus="1"> html {}{ filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); } </style> <mce:script type='text/javascript' src="/ajaxTest/dwr/interface/history.js" mce_src="ajaxTest/dwr/interface/history.js"></mce:script> <mce:script type='text/javascript' src="/ajaxTest/dwr/engine.js" mce_src="ajaxTest/dwr/engine.js"></mce:script> <mce:script type='text/javascript' src="/ajaxTest/dwr/util.js" mce_src="ajaxTest/dwr/util.js"></mce:script> <mce:script language="javascript"><!-- /**//*处理用户相关搜索*/ function change(data){ //得到表格中的行数 var count = document.getElementById('tab').rows.length; //如果表中存在行,将所有行删除 if(count >0){ for(var i=count-1;i>=0;i--){ document.getElementById('tab').deleteRow(i); } } //如果存在相关搜索记录 if(data.length > 0){ document.getElementById('Related').style.display = ''; document.getElementById('x').style.display = ''; for(var i=0;i<data.length;i++){ var objTr = document.getElementById('tab').insertRow(); var objTd1 = objTr.insertCell(0); objTd1.innerHTML = "<input readonly type='text' " +"size='35' name='txtHistory' style="border:none;background:#FFFFFF" mce_style="border:none;background:#FFFFFF"" +" value='"+data[i].content+"' onmouseover='overChangeColor(this)'" +" onmouseleave='leaveChangeColor(this)' " +"onclick='clickHistory(this)'>"; var objTd2 = objTr.insertCell(1); objTd2.innerHTML = "<input type='text' name='result' readonly" +" size='15' style="border:none;background:#FFFFFF;text-align:right" mce_style="border:none;background:#FFFFFF;text-align:right"" +" value='"+data[i].count+"结果"+"' align='right'/>"; objTd2.align = 'right'; } }else{ document.getElementById('Related').style.display = 'none'; } } /**//*关闭历史查询记录*/ function myClose(){ document.getElementById('Related').style.display = 'none'; } /**//*鼠标在相关搜索内容上方时执行*/ function overChangeColor(object){ var histories = document.getElementsByName('txtHistory'); for(var i=0;i<histories.length;i++){ //如果当前鼠标停留在某一行上 if(histories[i].style.background == '#ccffcc'){ histories[i].style.background = '#FFFFFF'; var tdObj1 = histories[i].parentElement;//td var trObj1 = tdObj1.parentElement;//tr var childObj1 = trObj1.childNodes(1); var x1 = childObj1.childNodes(0); x1.style.background = '#FFFFFF'; break; } } object.style.background = '#CCFFCC'; var tdObj = object.parentElement;//td var trObj = tdObj.parentElement;//tr var childObj = trObj.childNodes(1); var x = childObj.childNodes(0); x.style.background = '#CCFFCC'; } /**//*鼠标离开相关搜索内容上方时执行*/ function leaveChangeColor(object){ object.style.background = '#FFFFFF'; var tdObj = object.parentElement;//td var trObj = tdObj.parentElement;//tr var childObj = trObj.childNodes(1);//td var x = childObj.childNodes(0);//input x.style.background = '#FFFFFF'; } /**//*鼠标点击相关搜索内容时执行*/ function clickHistory(object){ document.frm.content.value = object.value; document.getElementById('Related').style.display = 'none'; frm.submit(); } /**//*用户在搜索框中按键事件处理*/ function keySelectHistory(){ var nKeyCode = window.event.keyCode; if(nKeyCode == 38 || nKeyCode == 40){ var count = document.getElementById('tab').rows.length; var tempRowId;//记录鼠标悬浮所在行 var flag = false;//标识是否有已经变色的行 if(count > 0 && (nKeyCode == 38 || nKeyCode == 40)){//如果存在相关搜索信息 var histories = document.getElementsByName('txtHistory'); for(var i=0;i<histories.length;i++){ //如果当前鼠标停留在某一行上 if(histories[i].style.background == '#ccffcc'){ tempRowId = i; flag = true; break; } } if(!flag){ tempRowId = 0; } if(nKeyCode == 38){//向上键 if(tempRowId > 0){ leaveChangeColor(histories[tempRowId]); overChangeColor(histories[tempRowId - 1]); document.frm.content.value = (histories[tempRowId - 1]).value; }else{ leaveChangeColor(histories[0]); overChangeColor(histories[count - 1]); document.frm.content.value = (histories[count - 1]).value; } }else if(nKeyCode == 40){//向下键 if(tempRowId == 0 && histories[0].style.background != '#ccffcc'){ overChangeColor(histories[0]); document.frm.content.value = histories[0].value; }else if(tempRowId < count -1){ leaveChangeColor(histories[tempRowId]); overChangeColor(histories[tempRowId + 1]); document.frm.content.value = (histories[tempRowId + 1]).value; }else{ leaveChangeColor(histories[tempRowId]); overChangeColor(histories[0]); document.frm.content.value = histories[0].value; } } } }else{//搜索框内容发生改变时(手动使其变化,而非通过上下键) var str = document.frm.content.value; history.getHistory(str,change); } } // --></mce:script> </head> <body> <b>模拟搜索引擎</b> <br /> <form action="ServletX" name="frm" method="post"> <img alt="逝者安息,生者坚强" src="images/daonian.gif" mce_src="images/daonian.gif" /> <br /> <br /> <input type="hidden" name="model" value="search" /> <input type="text" size="55" name="content" onkeyup="keySelectHistory()" /> <input type="submit" value="搜索" /> <div id="Related" style="border:1px solid #f990033;display:'none';width:335;"> <table id="tab" cellpadding="0" border="0" cellspacing="0"> </table> <a id="x" href="javascript:;" mce_href="javascript:;" onclick='myClose()' style="display:none" mce_style="display:none">关闭</a> </div> </form> </body> </html>