上周末听了在用友工作的两个学长的一个小讲座,虽然时间不长,但还是有些收获的,其中一个开发部的经理就提到了一些小的技术点,其中就包括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>