package com.gpdi.softevaluate.action;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ProjectSetAction extends DispatchAction
{
/**
* <p>模板驗證</p>
* @param mapping
* @param form
* @param request
* @param response
* @return
* @throws Exception
*/
public ActionForward check(ActionMapping mapping, ActionForm
form,HttpServletRequest request, HttpServletResponse response)throws
Exception
{
String rest="";
String lotId="";
String retn="";
String flag="";
CommDaoFactory mgObj = new CommDaoFactory();
try
{
rest=request.getParameter("rest");
lotId=request.getParameter("lotId");
}
catch(Exception e)
{
}
if(!rest.equals("0")||!rest.equals("")||rest!=null)
{
flag="no";
}
else
{
flag="ok";
}
PrintWriter out=response.getWriter();
//服務器返回信息
out.write(flag);
out.close();
//讀取本Action所有的請求參數,將path重新構造,加上請求參數
//ActionForward forward= new ActionForward("project/projectSet.do?do=add&lotId=6");
//forward.setRedirect(true);
//傳參數后返回
//return forward;
return mapping.findForward(null);
}
public
ActionForward creattable(ActionMapping mapping, ActionForm
form,HttpServletRequest request, HttpServletResponse response)throws
Exception
{
//實現功能代碼
return mapping.findForward("create");
}
}
3.struts.config.xml
<action attribute="projectSetForm" name="projectSetForm"
parameter="do" path="/project/projectSet" scope="request"
type="com.gpdi.softevaluate.action.ProjectSetAction" validate="false">
<forward name="list" path="/project/viewProject.jsp" />
<forward name="add" path="/project/addProject.jsp" />
<forward name="create" path="/project/createTable.jsp" />
</action>
function verifyDate(tmpDateValue){
var tmpLength = tmpDateValue.length;
if (tmpLength == 0||tmpLength==null)
{
return true;
}
for (var i = 0; i < tmpLength;i++){
aChar = tmpDateValue.substring(i,i+1);
if(aChar != "-" && (aChar < "0" || aChar > "9")) {
return false;
}
}
if ((tmpLength < 8 || tmpLength > 10) && tmpLength != 0) {
return false;
}
for (var j= 0; j < 4;j++){
aChar = tmpDateValue.substring(j,j+1);
if(aChar < "0" || aChar > "9") {
return false;
}
}
if (tmpDateValue.substring(4,5) != "-" || tmpDateValue.substring(5,6) == "-"){
return false;
}
if (tmpLength == 8){
if (tmpDateValue.substring(6,7) != "-" || tmpDateValue.substring(7,8) == "-" ){
return false;
}
}
if (tmpLength == 9){
if (tmpDateValue.substring(8,9) == "-" ){
return false;
}
}
if (tmpLength == 10){
if (tmpDateValue.substring(7,8) != "-" || tmpDateValue.substring(6,7) == "-" || tmpDateValue.substring(8,9) == "-" || tmpDateValue.substring(9,10) == "-" ){
return false;
}
}
var count=0;
for (var k = 0; k < tmpLength;k++){
aChar = tmpDateValue.substring(k,k+1);
if(aChar == "-") {
count++;
}
}
if (count!=2){
return false;
}
return true;
}
<%@ 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>My JSP 'ManageMenu.jsp' starting page</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">
<link rel="STYLESHEET" type="text/css" href="css/dhtmlXTree.css">
<script src="js/dhtmlXCommon.js"></script>
<script src="js/dhtmlXTree.js"></script>
<script type="text/javascript" src="<%=request.getContextPath()%>/dwr/engine.js"></script>
<script type="text/javascript" src="<%=request.getContextPath()%>/dwr/util.js"></script>
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/interface/service.js'> </script>
<style type="text/css">
.input
{
width:300px;
height:20px;
border:solid 0px;
}
.input1
{
width:70px;
height:20px;
border:solid 0px;
}
.input2
{
width:300px;
height:20px;
border:solid 1px;
}
</style>
<script type="text/javascript">
var oPopup = window.createPopup();
var array_info;
function showmenu(height)
{
var lefter2 = event.clientY+12;
var topper2 = event.clientX+10;
var height2=file_menu.clientHeight;
oPopup.document.body.innerHTML = oContextHTML.innerHTML+"<input type='hidden' id='file_id' value='"+event.srcElement.id+"' name='file_id'>";
oPopup.show(topper2, lefter2, 150,height,this_win);
}
function viewRight()
{
var id=tree.getSelectedItemId();//被選中的節點
//tree.insertNewNext(id,'1',"FFTT",viewRight,"tombs_mag.gif","magazines_open.gif","magazines_close.gif","回家","SELECT");
if(id!="0_0_-1")//當不是根菜單時
{
//alert(":::"+array_info[0]);
var chs = new Array();
chs = id.split("_");
var id=chs[0];
var ids=chs[1];
var v=array_info[0];
var height=0;
var adds=document.getElementById("add");
var edits=document.getElementById("edit");
var deletes=document.getElementById("delete");
var st_add="";
var st_edit="";
var st_delete="";
var dis_add="";
var dis_edit="";
var dis_delete="";
if(ids==-1)//一級目錄
{
height=75;
st_add="<SPAN ONCLICK=\"parent.add('"+chs[2]+"')\">新增節點(<u>A</u>dd)</SPAN> ";
st_edit="<SPAN ONCLICK=\"parent.edit('"+v[0]+"','"+v[1]+"','"+v[2]+"','"+v[3]+"','"+v[4]+"','"+v[5]+"')\">修改節點(<u>E</u>dit)</SPAN> ";
st_delete=" <SPAN ONCLICK=\"parent.deletes('"+id+"')\">刪除節點(<u>D</u>elete)</SPAN> ";
dis_add="";//將設為顯示
dis_edit="";//將設為顯示
dis_delete="";//將設為顯示
}
else
{
height=50;
st_add="";
st_edit="<SPAN ONCLICK=\"parent.edit('"+v[0]+"','"+v[1]+"','"+v[2]+"','"+v[3]+"','"+v[4]+"','"+v[5]+"')\">修改節點(<u>E</u>dit)</SPAN> ";
st_delete=" <SPAN ONCLICK=\"parent.deletes('"+id+"')\">刪除節點(<u>D</u>elete)</SPAN> ";
dis_add="none";//將設為顯示
dis_edit="";//將設為顯示
dis_delete="";//將設為顯示
}
adds.innerHTML=st_add;
edits.innerHTML=st_edit;
deletes.innerHTML=st_delete;
adds.style.display=dis_add;//將設為顯示
edits.style.display=dis_edit;//將設為顯示
deletes.style.display=dis_delete;//將設為顯示
showmenu(height);
}
else//根目錄
{
var adds=document.getElementById("add");
var edits=document.getElementById("edit");
var deletes=document.getElementById("delete");
adds.innerHTML="<SPAN ONCLICK=\"parent.add('root')\">新增節點(<u>A</u>dd)</SPAN> ";
edits.innerHTML="";
deletes.innerHTML="";
adds.style.display="";//將設為顯示
edits.style.display="none";//將設為顯示
deletes.style.display="none";//將設為顯示
var height=25;
showmenu(height);
}
}
function tonclick()
{
var id=tree.getSelectedItemId();//被選中的節點
if(id!="0_0_-1")//當不是根菜單時
{
var chs = new Array();
chs = id.split("_");
service.getMenuInfo(chs[0],menuclick);
var table=document.getElementById("table");//顯示節點信息的表
var tdshow=document.getElementById("tdshow");//顯示節點信息的表
var add_show=document.getElementById("add_show");
tdshow.style.display="";//將表格設為顯示
add_show.style.display="none";//將表格設為顯示
table.style.display="";//將表格設為顯示
//alert(table_style);
//tree.insertNewNext(id,'1',"FFTT",viewRight,"tombs_mag.gif","magazines_open.gif","magazines_close.gif","回家","SELECT");
}
}
function hander()
{
// var id=tree.getSelectedItemId();//被選中的節點
// alert(id);
tonclick();
viewRight();
}
function menuclick(data)
{
array_info=data;
var array=data[0];
var cms_name=document.getElementById("name");//顯示節點的名稱
var cms_link=document.getElementById("link");//顯示節點的鏈接
var cms_orders=document.getElementById("orders");//顯示節點的排序號
var cms_is_show=document.getElementById("is_show");//節點是否顯示
var cms_is_quick=document.getElementById("is_quick");//節點是否作為快速通道
var legend=document.getElementById("legend");//
legend.innerHTML=array[0];
cms_name.value=array[0];
cms_link.value=array[1];
cms_orders.value=array[2];
if(array[3]==0)
{
cms_is_show.value="顯示";
}
else
{
cms_is_show.value="不顯示";
}
if(array[4]==0)
{
cms_is_quick.value="是";
}
else
{
cms_is_quick.value="否";
}
}
</script>
<script type="text/javascript">
function add(id)
{
//菜單響應添加時調用
var add_show=document.getElementById("add_show");
var tdshow=document.getElementById("tdshow");
var click=document.getElementById("click");
var add_legend=document.getElementById("add_legend");
var add_cms_name=document.getElementById("add_name");//顯示節點的名稱
var add_cms_link=document.getElementById("add_link");//顯示節點的鏈接
var add_cms_orders=document.getElementById("add_orders");//顯示節點的排序號
var add_cms_is_show=document.getElementById("add_is_show");//節點是否顯示
var add_cms_is_quick=document.getElementById("add_is_quick");//節點是否作為快速通道
add_show.style.display="";
tdshow.style.display="none";
//bt.style.display="";
//bt.value="添加節點";
add_legend.innerHTML="添加節點";
click.innerHTML="<input type=\"button\" name=\"bt\" value=\"添加節點\" onclick=\"adds('"+id+"')\" id=\"bt\">";
add_cms_name.value="";
add_cms_link.value="";
add_cms_orders.value="";
add_cms_is_show.value="0";
add_cms_is_quick.value="1";
}
</script>
<script type="text/javascript">
function edit(name,link,orders,is_show,is_quick,id)
{
//菜單響應修改時調用
var add_show=document.getElementById("add_show");
var tdshow=document.getElementById("tdshow");
var click=document.getElementById("click");
var add_legend=document.getElementById("add_legend");
var add_cms_name=document.getElementById("add_name");//顯示節點的名稱
var add_cms_link=document.getElementById("add_link");//顯示節點的鏈接
var add_cms_orders=document.getElementById("add_orders");//顯示節點的排序號
var add_cms_is_show=document.getElementById("add_is_show");//節點是否顯示
var add_cms_is_quick=document.getElementById("add_is_quick");//節點是否作為快速通道
add_show.style.display="";
tdshow.style.display="none";
//bt.style.display="";
//bt.value="修改節點";
add_legend.innerHTML="修改"+name;
click.innerHTML="<input type=\"button\" name=\"bt\" value=\"修改節點\" onclick=\"edits('"+id+"')\" id=\"bt\">";
add_cms_name.value=name;
add_cms_link.value=link;
add_cms_orders.value=orders;
add_cms_is_show.value=is_show;
add_cms_is_quick.value=is_quick;
}
</script>
<script type="text/javascript">
var stname;
function adds(id)
{
//alert("添加按鈕--"+id);
//數據庫添加時調用
var form =document.form1;
var name=form.add_name.value;
var link=form.add_link.value;
var orders=form.add_orders.value;
var is_show=form.add_is_show.value;
var is_quick=form.add_is_quick.value;
if(name==""||name==null)
{
alert("節點名稱不能為空!");
return false;
}
if(link==""||link==null)
{
link="#";
}
if(orders==""||orders==null)
{
orders="1";
}
if(is_show==""||is_show==null)
{
is_show="0";
}
if(is_quick==""||is_quick==null)
{
is_quick="1";
}
stname=name;
//alert(id);
service.Add(id,name,link,orders,is_show,is_quick,clickAdd);
}
function clickAdd(info)
{
var returninfo=new Array();
returninfo = info.split(";");
if(returninfo[0]=="true")
{
alert("新增【"+stname+"】節點成功!");
var id=tree.getSelectedItemId();//被選中的節點
var insertid=returninfo[1]+"_"+returninfo[2]+"_"+returninfo[3];
//alert("::::"+insertid);
tree.insertNewChild(id,insertid,stname,hander,"book_titel.gif","books_open.gif","book.gif","","") ;
//var form2=document.form2;
//form2.action="cms/manageMenu.jsp";
//form2.submit();
}
else
{
alert("新增【"+stname+"】節點失敗!");
}
}
</script>
<script type="text/javascript">
function deletes(id)
{
//菜單,數據庫刪除時調用
var bln = window.confirm("您確定要刪除此界面嗎?");
if(bln==true)
{
service.deleteAll(id,clickDelete);
tree.deleteItem(tree.getSelectedItemId(),true);
}
else
{
return false;
}
}
function clickDelete(info)
{
alert(info);
}
</script>
<script type="text/javascript">
function edits(id)
{
//數據庫修改時調用
var form =document.form1;
var name=form.add_name.value;
var link=form.add_link.value;
var orders=form.add_orders.value;
var is_show=form.add_is_show.value;
var is_quick=form.add_is_quick.value;
service.modify(id,name,link,orders,is_show,is_quick,clickModify);
}
function clickModify(info)
{
alert(info);
}
</script>
</head>
<body id="this_win">
<table>
<tr>
<td valign="top">
<form name="form2" method="post" action="">
<div id="treeboxbox_tree" style="width:250; height:600;background-color:#f5f5f5;border :1px solid Silver;; overflow:auto;"></div>
<script>
tree=new dhtmlXTreeObject("treeboxbox_tree","100%","100%",0);
tree.setImagePath("images/imgs/");
tree.setXMLAutoLoading("cms/cmsmenu.jsp?op=open");
tree.loadXML("cms/cmsmenu.jsp?op=init");
//tree.enableItemEditor(true);
tree.setOnClickHandler(tonclick);//單擊事件調用方法
tree.setOnRightClickHandler(viewRight);//設置右鍵調用方法
// tree.insertNewChild('root',5,"新節點",viewRight,"0","0","0","0","SELECT") ;
//tree.insertNewItem('0',100,"New Node 1",0,0,0,0,"SELECT");
</script>
</form>
</td>
<td rowspan="2" style="padding-left:25" valign="top" >
<form name="form1" method="post" action="">
<fieldset style="DISPLAY:none " id="tdshow">
<legend id="legend"></legend>
<table width="554" border="0" id="table" style="DISPLAY: none">
<tr>
<td width="102" height="24" scope="col">
<div align="left"><font size="2">名字:</font></div>
</td>
<td width="168" scope="col">
<div align="left" >
<input name="name" type="text" value="name" id="name" readonly class='input' >
</div>
</td>
</tr>
<tr>
<td width="98" scope="col">
<div align="left"><font size="2">鏈接:</font> </div>
</td>
<td width="168" scope="col">
<div align="left" >
<input name="link" type="text" value="link" id="link" readonly class='input'>
</div></td>
</tr>
<tr>
<td height="21"><font size="2">序號: </font></td>
<td height="21">
<div align="left" >
<input name="orders" type="text" value="orders" id="orders" readonly class='input'>
</div>
</td>
</tr>
<tr>
<td>
<div align="left"><font size="2">是否顯示:</font> </div></td>
<td>
<div align="left" >
<input name="is_show" type="text" value="is_show" id="is_show" readonly class='input'>
</div>
</td>
</tr>
<tr>
<td height="21"><font size="2">是否快速通道:</font></td>
<td height="21">
<div align="left" >
<input name="is_quick" type="text" value="is_quick" id="is_quick" readonly class='input'>
</div>
</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td height="21"></td>
<td height="21">
</td>
<td></td>
<td> </td>
</tr>
</table>
</fieldset>
<fieldset style="DISPLAY:none " id="add_show">
<legend id="add_legend"></legend>
<table width="554" border="0" id="add_table">
<tr>
<td width="102" height="24" scope="col">
<div align="left"><font size="2">名字:</font></div>
</td>
<td width="168" scope="col">
<div align="left" >
<input name="add_name" type="text" value="name" id="add_name" class='input2' >
</div>
</td>
</tr>
<tr>
<td width="98" scope="col">
<div align="left"><font size="2">鏈接:</font> </div>
</td>
<td width="168" scope="col">
<div align="left" >
<input name="add_link" type="text" value="link" id="add_link" class='input2'>
</div></td>
</tr>
<tr>
<td height="21"><font size="2">序號: </font></td>
<td height="21">
<div align="left" >
<input name="add_orders" type="text" value="orders" id="add_orders" class='input2'>
</div>
</td>
</tr>
<tr>
<td>
<div align="left"><font size="2">是否顯示:</font> </div></td>
<td>
<div align="left" >
<select name="add_is_show" id="add_is_show">
<option value="0" selected>顯示
<option value="1">不顯示
</select>
</div>
</td>
</tr>
<tr>
<td height="21"><font size="2">是否快速通道:</font></td>
<td height="21">
<div align="left" >
<select name="add_is_quick" id="add_is_quick">
<option value="0" selected>是
<option value="1">否
</select>
</div>
</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td height="21"> </td>
<td height="21">
</td>
<td id="click"></td>
<td> </td>
</tr>
</table>
</fieldset>
</form>
</td>
</tr>
<tr>
<td>
</td>
</tr>
</table>
<DIV ID="oContextHTML" STYLE="display:none;">
<div id="file_menu">
<DIV onmouseover="this.style.filter='progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#99ccff, EndColorStr=#FFFFFF)';"
onmouseout="this.style.filter='';"
STYLE="font-family:verdana; font-size:70%; height:25px; background:#e4e4e4; border:1px solid black; padding:3px; padding-left:20px; cursor:hand;DISPLAY: none" id="add">
</DIV>
<DIV onmouseover="this.style.filter='progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=yellowgreen,EndColorStr=#FFFFFF)';"
onmouseout="this.style.filter='';"
STYLE="font-family:verdana; font-size:70%; height:25px; background:#e4e4e4; border:1px solid black; padding:3px; padding-left:20px; cursor:hand; border-top:0px solid black;DISPLAY: none" id="edit">
</DIV>
<DIV onmouseover="this.style.filter='progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=gold, EndColorStr=#FFFFFF)';"
onmouseout="this.style.filter='';"
STYLE="font-family:verdana; font-size:70%; height:25px; background:#e4e4e4; border:1px solid black; padding:3px; padding-left:20px; cursor:hand;DISPLAY: none" id="delete">
</DIV>
</div>
</DIV>
</body>
</html>
最近和朋友們一起做了一個搜索提示的功能 使用了ajax+mysql數據庫進行的操作,代碼貼出來給大家參考一下:
suggest.html:
<html>
<head>
<style type="text/css" media="screen">
body {
font: 11px arial;
}
.suggest_link {
background-color: #FFFFFF;
padding: 2px 6px 2px 6px;
}
.suggest_link_over {
background-color: #E8F2FE;
padding: 2px 6px 2px 6px;
}
#search_suggest {
position: absolute;
background-color: #FFFFFF;
text-align: left;
border: 1px solid #000000;
}
</style>
<script language="JavaScript" type="text/javascript" src="ajax_search.js"></script>
</head>
<body>
<h3>Simple AJAX Search Suggest</h3>
<div style="width: 500px;">
<form id="frmSearch" action="">
<input type="text" id="txtSearch" name="txtSearch" alt="Search Criteria" onkeyup="searchSuggest();" autocomplete="off" />
<input type="submit" id="cmdSearch" name="cmdSearch" value="Search" alt="Run Search" /><br />
<div id="search_suggest">
</div>
</form>
</div>
</body>
</html>
ajax_search.js文件:
//Gets the browser specific XmlHttpRequest Object
function getXmlHttpRequestObject() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else if(window.ActiveXObject) {
return new ActiveXObject("Microsoft.XMLHTTP");
} else {
alert("Your Browser Sucks!\nIt's about time to upgrade don't you think?");
}
}
function createAjaxObj(){
var httprequest=false
if (window.XMLHttpRequest)
{ // if Mozilla, Safari etc
httprequest=new XMLHttpRequest()
if (httprequest.overrideMimeType)
httprequest.overrideMimeType('text/xml')
}
else if (window.ActiveXObject)
{ // if IE
try {
httprequest=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e){
try{
httprequest=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e){}
}
}
return httprequest
}
//Our XmlHttpRequest object to get the auto suggest
var searchReq = createAjaxObj();
//Called from keyup on the search textbox.
//Starts the AJAX request.
function searchSuggest() {
if (searchReq.readyState == 4 || searchReq.readyState == 0) {
var str = escape(document.getElementById('txtSearch').value);
searchReq.open("GET", 'search?search=' + str, true);
searchReq.onreadystatechange = handleSearchSuggest;
searchReq.send(null);
}
}
//Called when the AJAX response is returned.
function handleSearchSuggest() {
if (searchReq.readyState == 4) {
var ss = document.getElementById('search_suggest')
ss.innerHTML = '';
var str = searchReq.responseText.split("\n");
for(i=0; i < str.length - 1; i++) {
//Build our element string. This is cleaner using the DOM, but
//IE doesn't support dynamically added attributes.
var suggest = '<div onmouseover="javascript:suggestOver(this);" ';
suggest += 'onmouseout="javascript:suggestOut(this);" ';
suggest += 'onclick="javascript:setSearch(this.innerHTML);" ';
suggest += 'class="suggest_link">' + str[i] + '</div>';
ss.innerHTML += suggest;
}
}
}
//Mouse over function
function suggestOver(div_value) {
div_value.className = 'suggest_link_over';
}
//Mouse out function
function suggestOut(div_value) {
div_value.className = 'suggest_link';
}
//Click function
function setSearch(value) {
document.getElementById('txtSearch').value = value;
document.getElementById('search_suggest').innerHTML = '';
}
數據庫的代碼:
CREATE DATABASE /*!32312 IF NOT EXISTS*/ search;
USE search;
DROP TABLE IF EXISTS SUGGEST;
CREATE TABLE SUGGEST (
SUGGEST_ID int(11) NOT NULL auto_increment,
TITLE varchar(255) default NULL,
PRIMARY KEY (SUGGEST_ID)
)TYPE=MyISAM ;
LOCK TABLES SUGGEST WRITE;
INSERT INTO SUGGEST VALUES (1,'Home'),(2,'TECHNOLOGIES'),(3,'SOLUTIONS AND SOFTWARE'),(4,'Websites'),(5,'Web Apps'),(6,'Applications'),(7,'E-COMMERCE SOLUTIONS'),(8,'osCommerce'),(9,'CMS / Portals'),(10,'Microsoft .NET'),(11,'J2EE'),(12,'LAMP'),(13,'PHP'),(14,'MySQL'),(15,'Apache'),(16,'ASP.NET'),(17,'Windows Applications'),(18,'JSP'),(19,'SWING'),(20,'Web Technologies'),(21,'XHTML'),(22,'RSS / ATOM'),(23,'XML'),(24,'XSL'),(25,'XAML'),(26,'AJAX'),(27,'About DynamicAJAX'),(28,'CSS'),(29,'The Basics'),(30,'SAJAX'),(31,'About The Site Images'),(32,'About Me'),(33,'JavaScript'),(34,'RSS 2.0'),(35,'ATOM 1.0'),(36,'Search Engine Optimization'),(37,'Flash'),(38,'Open Source'),(39,'HTTP Server'),(40,'Full Text Search'),(41,'Best Practices'),(42,'XML Schema Definitons'),(43,'Web Content Accessibility Guidelines'),(44,'Printable Pages'),(45,'Search Engine'),(46,'Navigation'),(47,'Direct Web Remoting'),(48,'Mars Exploration Rovers'),(49,'Cassini'),(50,'Fun with Queries'),(51,'SEO Tricks and Tactics'),(52,'osCommerce Contributions'),(53,'PHP & IIS'),(54,'Regular Expressions'),(55,'Rants'),(56,'URL Rewrite'),(57,'Fun with CSS'),(58,'ActionScript'),(59,'Visual Studio 2005'),(60,'SQL Server'),(61,'Search Engine Commands'),(62,'Web Site Layout'),(63,'AJAX'),(64,'AJAX Basics'),(65,'ATLAS'),(66,'SAJAX'),(67,'Tutorials'),(68,'Novice'),(69,'Frameworks'),(70,'Ajax.NET'),(71,'Framework Tutorials'),(72,'SAJAX'),(73,'Ajax.NET'),(74,'Direct Web Remoting'),(75,'Intermediate'),(76,'AJAX Example Sites'),(77,'My Tutorials'),(78,'AJAX Web Chat Part 1'),(79,'The JavaScript'),(80,'Sending The Request'),(81,'Color Schemes'),(82,'AJAX Resources'),(83,'The Backend'),(84,'Usability Additions'),(85,'AJAX Instant Messenger Part 1'),(86,'Ruby on Rails'),(87,'Crazy Queries'),(88,'XmlHttpRequest Methods'),(89,'XmlHttpRequest Properties'),(90,'AjaxTags'),(91,'Direct Web Remoting'),(92,'My URL Rewriting'),(93,'Great Quotes'),(94,'IXSSO Queries'),(95,'AFLAX'),(96,'Other Technologies'),(97,'Microsoft Indexing Server'),(98,'.NET & CISSO');
UNLOCK TABLES;
SearchSuggest.java:
package book.suggest;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SearchSuggest extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
String search = request.getParameter("search");//獲得請求中cate的值
//定義查詢數據庫的SQL語句
String sql = "select title from suggest where title like '"+search+"%' order by title";
Connection conn = null;//聲明Connection對象
Statement stmt = null;//聲明Statement對象
ResultSet rs = null;//聲明ResultSet對象
Vector vData = new Vector();
//response.setContentType("text/xml");//設置返回數據類型為xml格式
java.io.PrintWriter out = response.getWriter();
try {
// 加載數據庫驅動類
Class.forName("com.mysql.jdbc.Driver");
// 訪問數據庫的地址
String url = "jdbc:mysql://localhost/search";
//創建Connection對象
conn = DriverManager.getConnection(url, "root", "");
// 創建Statement對象
stmt = conn.createStatement();
// 執行SQL語句,返回記錄集
rs = stmt.executeQuery(sql);
//定義AblumEO實體對象
while (rs.next())
{
vData.add(rs.getString("TITLE"));
}
StringBuffer buf = new StringBuffer();
for (int i=0;i<vData.size();i++)
{
String keyword = (String)vData.get(i);
buf.append(keyword+"\n");
}
out.print(buf.toString());
// out.print(parasToXML(vData));//調用parasToXML()方法
} catch (Exception e) {
e.printStackTrace();
} finally {//最后關必記錄集,Connection對象
try {
// this will close any associated ResultSets
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
} catch (SQLException sqle) {
}
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
doPost(request, response);
}
/*
public String parasToXML(Vector v) {// 該方法將數據轉化成XML格式輸出
StringBuffer buf = new StringBuffer();
buf.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
buf.append("<pictures>");
for (int i = 0; i < v.size(); i++) {
AlbumEO album = (AlbumEO) v.get(i);
buf.append("<item>");
buf.append("<name>" + album.getAlbumName() + "</name>");
buf.append("<url>" + album.getAlbumURL() + "</url>");
buf.append("<description>" + album.getAlbumDescription()
+ "</description>");
buf.append("</item>");
}
buf.append("</pictures>");
return buf.toString();
}
*/
}
本示例共有 四部分,請大家復制到自己的文件中進行 運行,最后的結果如圖:
2008-03-05 10:45:16 / 個人分類:js
function open(form)
{
var apply_id=form.flag.value;
var srcFile = "/uniframework/configuration.action?actName=applyToDistribut&flag="+apply_id;
var winFeatures = "dialogWidth=850px;dialogHeight=550px;status=no;help=no;";
var seleItemValue='';
var checkbox = form.checkbox;
if(checkbox){
if(checkbox.length)
{
for(var i=0;i<checkbox.length;i++)
{
if(i==0)seleItemValue = form.checkbox[i].value;
else
seleItemValue+=","+form.checkbox[i].value;
}
}else
{
seleItemValue = form.checkbox.value;
}
}
var obj = form1;
var ret = window.showModalDialog(srcFile, seleItemValue, winFeatures);
if(ret!=undefined){
addCTItemToTable(ret);
}
}
function addCTItemToTable(data)
{
var tableobj = document.getElementById("CTTable");
var appli_id="";
if (tableobj != null)
{
for(var k=0;k<data.length;k++)
{
var st=data[k];
appli_id=st[7];
var newRow = tableobj.insertRow(tableobj.rows.length);
c1 = newRow.insertCell(0);
c1.innerHTML = " <input type=checkbox name=checkbox checked class=checkbox1 value='"+st[0]+"'> ";
c2 = newRow.insertCell(1);
c2.innerHTML = '<div align=\"center\">' + st[1] + '</div>';
c3 = newRow.insertCell(2);
c3.innerHTML = '<div align=\"center\">'+st[2]+'</div>';
c4 = newRow.insertCell(3);
c4.innerHTML = '<div align=\"center\">'+st[3]+'</div>';
c5 = newRow.insertCell(4);
c5.innerHTML = '<div align=\"center\">'+st[4]+'</div>';
c6 = newRow.insertCell(5);
c6.innerHTML = '<div align=\"center\">'+st[5]+'</div>';
c7 = newRow.insertCell(6);
c7.innerHTML = '<div align=\"center\">'+st[6]+'</div>'
}
}
}
這幾天又花時間做了一個,使用起來效果更好,因為沒有時間寫更多的幫助,大家慢慢研究代碼吧!
最近項目中要用到下拉多選樹,有人從網上找了一個,用了一段時間后發現有一些問題,一個頁面中只能有一個下拉樹,我就研究其中的代碼,自己重新寫了一個下拉頁面的腳本,能夠在一個頁面中使用多個下拉樹。
其原理其實就是用DIV的隱藏的顯示來實現下拉頁面,頁面放在了DIV里的一個FRAME里,用JS來控制這些顯示與隱藏,廢話不多說了,把源碼給大家公布一下。代碼中如有不足之處敬請大家指出。
給大家說一下它的用法,首先在頁面里加上JS文件:
在需要下拉樹的地方寫一個DIV:
JS里用到了兩個圖片,你可以把這兩個圖片放到主頁面同一層的路徑下,或者直接修改JS源文件,把它指向你自己的路徑。
目標頁面需要加一些東西,寫一個函數:
function getUserData(tag){
var ids = tree1.getAllChecked();
if(ids.length==0)return "";
if(tag=="id")
return tree1.getAllChecked();
else if(tag=="name"){
var idArray = ids.split(",");
var names=tree1.getItemText(idArray[0]);
for(i=1;i names += "," + tree1.getItemText(idArray[i]);
return names;
}
}
其中的返回值可以根據你的頁面要實現的功能改動。
var currSeleTabId='returning';
var selectTab="";
function oninit(tabbarId)
{
var tabbar = window[tabbarId];
selectTab=tabbar;
tabbar.setOnSelectHandler(seleTable_func);
}
function seleTable_func(idn,ido)
{
currSeleTabId = idn;
//alert(idn);
var form=document.form1;
var number=form.NUMBER.value;
var name=form.APPLYER.value;
var address=form.APPLYER_DEPT_NAME.value;
var url="/uniframework/configuration.action?actName=showReturnQuery&info="+idn;
var url1="&model.configApply.number="+number+"&model.configApply.APPLYER="+name+"&model.configApply.APPLYER_DEPT_NAME="+address;
selectTab.setContentHref(idn,encodeURI(url+url1))
return true;
}
</script>
</head>
<body onLoad="form1.NUMBER.focus();">
<form name="form1" method="post" action="" target="_self">
<table width="98%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td width="100%" height="22" valign="top">
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="100%" height="22" class=table_title_bg070><span class="text_l14"><img src="/uniframework/images/a01.gif" width="19" height="18"><a class="ameth" href="/uniframework/jsp/provider/moduleHomepage.jsp">資產借用申請</a> ></span></td>
<td width="*" valign="top" background="/uniframework/images/table_title_bg070.gif"> </td>
</tr>
</table>
</td>
</tr>
</table><br>
<table width="97%" height="40" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<fieldset class="fieldset" >
<legend class="legend"><img src="/uniframework/images/dot12.gif"> 查詢條件</legend>
<table class="fieldsettable" height="30" >
<tr height="30">
<td class="text17">編號:</td>
<td class="text18"><input type="text" class="Input12" id="NUMBER" name="model.configApply.NUMBER" value="<ww:property value = "model.configApply.NUMBER"/>" title="請輸入要查詢的編號"></td>
<td class="text19">部門:</td>
<td class="text20">
<input name="model.configApply.APPLYER_DEPT_NAME" type="text" class="Input12" id="APPLYER_DEPT_NAME" value="<ww:property value = "model.configApply.APPLYER_DEPT_NAME"/>">
</tr>
<tr height="30">
<td class="text17">歸還人:</td>
<td class="text18" colspan="2">
<input name="model.configApply.APPLYER" type="text" class="Input12" id="APPLYER" value="<ww:property value = "model.configApply.APPLYER"/>">
</td>
</tr>
</table>
</fieldset><br>
<table width="94%" border="0" cellpadding="0" cellspacing="0">
<tr height="70%">
<td width="65%" align="right">
<button class="btn3_mouseout btn0" onclick="queryReturn(form1,document.frames[0])">查 詢</button>
</td>
<td width="2%"></td>
<td width="5%" align="right">
<button class="btn3_mouseout btn0" onclick="clean(form1)">重 置</button>
</td>
<td width="2%"></td>
<td width="5%">
<button class="btn3_mouseout btn0" onclick="self.location='/uniframework/configuration.action?actName=toAddAssetsReturn'">新 增</button>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<div hrefmode="iframe" id="a_tabbar" class="dhtmlxTabBar" imgpath="/uniframework/images/dhTabbarImg/" style="width:98%; height:410px;" skinColors="#FCFBFC,#F4F3EE" oninit="oninit('a_tabbar');">
<div id="returning" width="100" name="歸還中" href="/uniframework/configuration.action?actName=showReturnQuery&info=initreturn" ></div>
<div id="returned" width="100" name="已歸還" href="/uniframework/configuration.action?actName=showReturnQuery&info=returned"></div>
<div id="no" width="100" name="審批未通過" href="/uniframework/configuration.action?actName=showReturnQuery&info=no"></div>
<div id="all" width="100" name="所有" href="/uniframework/configuration.action?actName=showReturnQuery&info=all" ></div>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</body>
</html>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<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>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
dwr.xml中加入struts的設定,其中formBean的參數的value值,會對應到struts-config.xml中<form-beans>的設定
<dwr><allow><create creator="struts" javascript="testFrm"><param name="formBean" value="testActionForm"/></create></allow></dwr>
struts-config.xml<struts-config><form-beans><form-bean name="testActionForm" type="test.struts.testActionForm" /></form-beans><action-mappings><action name="testActionForm" path="/testAction" scope="session" type="test.struts.testAction" validate="false"><forward name="display" path="/display.jsp" /></action></action-mappings><message-resources parameter="ApplicationResources" /></struts-config>
testActionForm.java,getDate()會透過dwr,取得現在最新的日期package test.struts;import org.apache.struts.action.*;import java.util.*;public class testActionForm extends ActionForm {private String strDate;public void setStrDate(String strDate) {this.strDate = strDate;}public String getStrDate() {return strDate;}//dwr public String getDate() {Date date = new Date();return date.toString();}}
testAction.java
package test.struts;import org.apache.struts.action.ActionMapping;import org.apache.struts.action.ActionForm;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.struts.action.ActionForward;import org.apache.struts.action.Action;import org.apache.struts.action.*;public class testAction extends Action {public ActionForward execute(ActionMapping mapping, ActionForm form,HttpServletRequest request,HttpServletResponse response) {testActionForm actionForm = (testActionForm) form;System.out.println(actionForm.getStrDate());return mapping.findForward("display");}}
date.jsp,在form的部分,請用struts 的 tag library,我把<html:text property="strDate" size="30" >改成<input type="text" name="strDate">後,無法正常的接受到值.
<%@ page contentType="text/html; charset=Big5" %><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %><%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %><%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %><html><head><title>title</title><script type='text/javascript' src='dwr/interface/testFrm.js'></script><script type='text/javascript' src='dwr/engine.js'></script><script type='text/javascript' src='dwr/util.js'></script></head><SCRIPT LANGUAGE="JavaScript" type="">function refreshDate() {testFrm.getDate(populateDate);}function populateDate(data){DWRUtil.setValue('strDate', data);}</script><body><html:form action="testAction.do">date:<html:text property="strDate" size="30" ></html:text><input type="button" onclick="refreshDate();" value="更新日期"/><br/><html:submit>送出 </html:submit></html:form></body></html>
display.jsp
<%@ page contentType="text/html; charset=Big5" %><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>%@page import="test.struts.*"%<html><head><title>test</title></head><body bgcolor="#ffffff"><h1>您送出的日期:<br><bean:write name="testActionForm" property="strDate"/></h1></body></html>
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1621900
前期的系統創建、struts、hibernate、spring的集成工作就不用說了,一路下來…………
主要看DWR的應用,它用于表單驗證:
1、先看它的配置:
(1)在web.xml里加上:
(2)再建一個類,用于獲取驗證輸出信息的屬性文件,這個文件是參考了良葛格 的DWR 入門與應用(一)
里的Book代碼
java 代碼
(3)編寫屬性文件dwrPro_zh_CN.propertie(中文)和dwr_en.properties(英文)
(4)配置dwr.xml,里面用了spring的bean 和java類
spring beanName 的value =“userManager”從applicationContext.xml里取得
這里應該大家都懂,就不羅嗦了
(5)配好了這些,就可以在頁面里用了
讀取dwr.xml的userManager,然后讀取applicationContext.xml里userManager bean ,進而實行findUserIsExist方法。
![]() |
|
級 別: 初級
張
濤 (zzhangt@cn.ibm.com),
軟件工程師, IBM
王
秉坤 (wangbk@cn.ibm.com),
軟件工程師, IBM
2008 年 4 月 10 日
單點登錄(Single Sign On , 簡稱 SSO )是目前比較流行的服務于企業業務整合的解決方案之一, SSO 使得在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統。CAS(Central Authentication Service)是一款不錯的針對 Web 應用的單點登錄框架,本文介紹了 CAS 的原理、協議、在 Tomcat 中的配置和使用,對于采用 CAS 實現輕量級單點登錄解決方案的入門讀者具有一定指導作用。
CAS 是 Yale 大學發起的一個開源項目,旨在為 Web 應用系統提供一種可靠的單點登錄方法,CAS 在 2004 年 12 月正式成為 JA-SIG 的一個項目。CAS 具有以下特點:
從結構上看,CAS 包含兩個部分: CAS Server 和 CAS Client。CAS Server 需要獨立部署,主要負責對用戶的認證工作;CAS Client 負責處理對客戶端受保護資源的訪問請求,需要登錄時,重定向到 CAS Server。圖1 是 CAS 最基本的協議過程:
CAS Client 與受保護的客戶端應用部署在一起,以 Filter 方式保護受保護的資源。對于訪問受保護資源的每個 Web 請求,CAS Client 會分析該請求的 Http 請求中是否包含 Service Ticket,如果沒有,則說明當前用戶尚未登錄,于是將請求重定向到指定好的 CAS Server 登錄地址,并傳遞 Service (也就是要訪問的目的資源地址),以便登錄成功過后轉回該地址。用戶在第 3 步中輸入認證信息,如果登錄成功,CAS Server 隨機產生一個相當長度、唯一、不可偽造的 Service Ticket,并緩存以待將來驗證,之后系統自動重定向到 Service 所在地址,并為客戶端瀏覽器設置一個 Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新產生的 Ticket 過后,在第 5,6 步中與 CAS Server 進行身份合適,以確保 Service Ticket 的合法性。
在該協議中,所有與 CAS 的交互均采用 SSL 協議,確保,ST 和 TGC 的安全性。協議工作過程中會有 2 次重定向的過程,但是 CAS Client 與 CAS Server 之間進行 Ticket 驗證的過程對于用戶是透明的。
另外,CAS 協議中還提供了 Proxy (代理)模式,以適應更加高級、復雜的應用場景,具體介紹可以參考 CAS 官方網站上的相關文檔。
本文中的例子以 tomcat5.5 為例進行講解,下載地址:
http://tomcat.apache.org/download-55.cgi
到 CAS 官方網站下載 CAS Server 和 Client,地址分別為:
http://www.ja-sig.org/downloads/cas/cas-server-3.1.1-release.zip
http://www.ja-sig.org/downloads/cas-clients/cas-client-java-2.1.1.zip
![]() ![]() |
![]()
|
CAS Server 是一套基于 Java 實現的服務,該服務以一個 Java Web Application 單獨部署在與 servlet2.3 兼容的 Web 服務器上,另外,由于 Client 與 CAS Server 之間的交互采用 Https 協議,因此部署 CAS Server 的服務器還需要支持 SSL 協議。當 SSL 配置成功過后,像普通 Web 應用一樣將 CAS Server 部署在服務器上就能正常運行了,不過,在真正使用之前,還需要擴展驗證用戶的接口。
在 Tomcat 上部署一個完整的 CAS Server 主要按照以下幾個步驟:
如果希望 Tomcat 支持 Https,主要的工作是配置 SSL 協議,其配置過程和配置方法可以參考 Tomcat 的相關文檔。不過在生成證書的過程中,會有需要用到主機名的地方,CAS 建議不要使用 IP 地址,而要使用機器名或域名。
CAS Server 是一個 Web 應用包,將前面下載的 cas-server-3.1.1-release.zip 解開,把其中的 cas-server-webapp-3.1.1.war 拷貝到 tomcat的 webapps 目錄,并更名為 cas.war。由于前面已配置好 tomcat 的 https 協議,可以重新啟動 tomcat,然后訪問:https://localhost:8443/cas ,如果能出現正常的 CAS 登錄頁面,則說明 CAS Server 已經部署成功。
雖然 CAS Server 已經部署成功,但這只是一個缺省的實現,在實際使用的時候,還需要根據實際概況做擴展和定制,最主要的是擴展認證 (Authentication) 接口和 CAS Server 的界面。
CAS Server 負責完成對用戶的認證工作,它會處理登錄時的用戶憑證 (Credentials) 信息,用戶名/密碼對是最常見的憑證信息。CAS Server 可能需要到數據庫檢索一條用戶帳號信息,也可能在 XML 文件中檢索用戶名/密碼,還可能通過 LDAP Server 獲取等,在這種情況下,CAS 提供了一種靈活但統一的接口和實現分離的方式,實際使用中 CAS 采用哪種方式認證是與 CAS 的基本協議分離開的,用戶可以根據認證的接口去定制和擴展。
擴展 AuthenticationHandler
CAS 提供擴展認證的核心是 AuthenticationHandler 接口,該接口定義如清單 1 下:
|
該接口定義了 2 個需要實現的方法,supports ()方法用于檢查所給的包含認證信息的Credentials 是否受當前 AuthenticationHandler 支持;而 authenticate() 方法則擔當驗證認證信息的任務,這也是需要擴展的主要方法,根據情況與存儲合法認證信息的介質進行交互,返回 boolean 類型的值,true 表示驗證通過,false 表示驗證失敗。
CAS3中還提供了對AuthenticationHandler 接口的一些抽象實現,比如,可能需要在執行authenticate() 方法前后執行某些其他操作,那么可以讓自己的認證類擴展自清單 2 中的抽象類:
|
AbstractPreAndPostProcessingAuthenticationHandler 類新定義了 preAuthenticate() 方法和 postAuthenticate() 方法,而實際的認證工作交由 doAuthentication() 方法來執行。因此,如果需要在認證前后執行一些額外的操作,可以分別擴展 preAuthenticate()和 ppstAuthenticate() 方法,而 doAuthentication() 取代 authenticate() 成為了子類必須要實現的方法。
由于實際運用中,最常用的是用戶名和密碼方式的認證,CAS3 提供了針對該方式的實現,如清單 3 所示:
|
基于用戶名密碼的認證方式可直接擴展自 AbstractUsernamePasswordAuthenticationHandler,驗證用戶名密碼的具體操作通過實現 authenticateUsernamePasswordInternal() 方法達到,另外,通常情況下密碼會是加密過的,setPasswordEncoder() 方法就是用于指定適當的加密器。
從以上清單中可以看到,doAuthentication() 方法的參數是 Credentials 類型,這是包含用戶認證信息的一個接口,對于用戶名密碼類型的認證信息,可以直接使用 UsernamePasswordCredentials,如果需要擴展其他類型的認證信息,需要實現Credentials接口,并且實現相應的 CredentialsToPrincipalResolver 接口,其具體方法可以借鑒 UsernamePasswordCredentials 和 UsernamePasswordCredentialsToPrincipalResolver。
JDBC 認證方法
用戶的認證信息通常保存在數據庫中,因此本文就選用這種情況來介紹。將前面下載的 cas-server-3.1.1-release.zip 包解開后,在 modules 目錄下可以找到包 cas-server-support-jdbc-3.1.1.jar,其提供了通過 JDBC 連接數據庫進行驗證的缺省實現,基于該包的支持,我們只需要做一些配置工作即可實現 JDBC 認證。
JDBC 認證方法支持多種數據庫,DB2, Oracle, MySql, Microsoft SQL Server 等均可,這里以 DB2 作為例子介紹。并且假設DB2數據庫名: CASTest,數據庫登錄用戶名: db2user,數據庫登錄密碼: db2password,用戶信息表為: userTable,該表包含用戶名和密碼的兩個數據項分別為 userName 和 password。
1. 配置 DataStore
打開文件 %CATALINA_HOME%/webapps/cas/WEB-INF/deployerConfigContext.xml,添加一個新的 bean 標簽,對于 DB2,內容如清單 4 所示:
|
其中 id 屬性為該 DataStore 的標識,在后面配置 AuthenticationHandler 會被引用,另外,需要提供 DataStore 所必需的數據庫驅動程序、連接地址、數據庫登錄用戶名以及登錄密碼。
2. 配置 AuthenticationHandler
在 cas-server-support-jdbc-3.1.1.jar 包中,提供了 3 個基于 JDBC 的 AuthenticationHandler,分別為 BindModeSearchDatabaseAuthenticationHandler, QueryDatabaseAuthenticationHandler, SearchModeSearchDatabaseAuthenticationHandler。其中 BindModeSearchDatabaseAuthenticationHandler 是用所給的用戶名和密碼去建立數據庫連接,根據連接建立是否成功來判斷驗證成功與 否;QueryDatabaseAuthenticationHandler 通過配置一個 SQL 語句查出密碼,與所給密碼匹配;SearchModeSearchDatabaseAuthenticationHandler 通過配置存放用戶驗證信息的表、用戶名字段和密碼字段,構造查詢語句來驗證。
使用哪個 AuthenticationHandler,需要在 deployerConfigContext.xml
中設置,默認情況下,CAS 使用一個簡單的 username=password 的
AuthenticationHandler,在文件中可以找到如下一行:<bean
class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePassword
AuthenticationHandler"
/>,我們可以將其注釋掉,換成我們希望的一個
AuthenticationHandler,比如,使用QueryDatabaseAuthenticationHandler 或
SearchModeSearchDatabaseAuthenticationHandler 可以分別選取清單 5 或清單 6 的配置。
|
|
另外,由于存放在數據庫中的密碼通常是加密過的,所以 AuthenticationHandler 在匹配時需要知道使用的加密方法,在 deployerConfigContext.xml 文件中我們可以為具體的 AuthenticationHandler 類配置一個 property,指定加密器類,比如對于 QueryDatabaseAuthenticationHandler,可以修改如清單7所示:
|
其中 myPasswordEncoder 是對清單 8 中設置的實際加密器類的引用:
|
這里 MyPasswordEncoder 是根據實際情況自己定義的加密器,實現 PasswordEncoder 接口及其 encode() 方法。
3. 部署依賴包
在以上配置完成以后,需要拷貝幾個依賴的包到 cas 應用下,包括:
CAS 提供了 2 套默認的頁面,分別為“ default ”和“ simple ”,分別在目錄“ cas/WEB-INF/view/jsp/default ”和“ cas/WEB-INF/view/jsp/simple ”下。其中 default 是一個稍微復雜一些的頁面,使用 CSS,而 simple 則是能讓 CAS 正常工作的最簡化的頁面。
在部署 CAS 之前,我們可能需要定制一套新的 CAS Server 頁面,添加一些個性化的內容。最簡單的方法就是拷貝一份 default 或 simple 文件到“ cas/WEB-INF/view/jsp ”目錄下,比如命名為 newUI,接下來是實現和修改必要的頁面,有 4 個頁面是必須的:
CAS 的頁面采用 Spring 框架編寫,對于不熟悉 Spring 的使用者,在修改之前需要熟悉該框架。
頁面定制完過后,還需要做一些配置從而讓 CAS 找到新的頁面,拷貝“ cas/WEB-INF/classes/default_views.properties ”,重命名為“ cas/WEB-INF/classes/ newUI_views.properties ”,并修改其中所有的值到相應新頁面。最后是更新“ cas/WEB-INF/cas-servlet.xml ”文件中的 viewResolver,將其修改為如清單 9 中的內容。
|
![]() ![]() |
![]()
|
單點登錄的目的是為了讓多個相關聯的應用使用相同的登錄過程,本文在講解過程中構造 2個簡單的應用,分別以 casTest1 和 casTest2 來作為示例,它們均只有一個頁面,顯示歡迎信息和當前登錄用戶名。這 2 個應用使用同一套登錄信息,并且只有登錄過的用戶才能訪問,通過本文的配置,實現單點登錄,即只需登錄一次就可以訪問這兩個應用。
假設 CAS Server 單獨部署在一臺機器 A,而客戶端應用部署在機器 B 上,由于客戶端應用與 CAS Server 的通信采用 SSL,因此,需要在 A 與 B 的 JRE 之間建立信任關系。
首先與 A 機器一樣,要生成 B 機器上的證書,配置 Tomcat 的 SSL 協議。其次,下載http://blogs.sun.com/andreas/entry/no_more_unable_to_find 的 InstallCert.java,運行“ java InstallCert compA:8443 ”命令,并且在接下來出現的詢問中輸入 1。這樣,就將 A 添加到了 B 的 trust store 中。如果多個客戶端應用分別部署在不同機器上,那么每個機器都需要與 CAS Server 所在機器建立信任關系。
準備好應用 casTest1 和 casTest2 過后,分別部署在 B 和 C 機器上,由于 casTest1 和casTest2,B 和 C 完全等同,我們以 casTest1 在 B 機器上的配置做介紹,假設 A 和 B 的域名分別為 domainA 和 domainB。
將 cas-client-java-2.1.1.zip 改名為 cas-client-java-2.1.1.jar 并拷貝到 casTest1/WEB-INF/lib目錄下,修改 web.xml 文件,添加 CAS Filter,如清單 10 所示:
|
對于所有訪問滿足 casTest1/protected-pattern/ 路徑的資源時,都要求到 CAS Server 登錄,如果需要整個 casTest1 均受保護,可以將 url-pattern 指定為“/*”。
從清單 10 可以看到,我們可以為 CASFilter 指定一些參數,并且有些是必須的,表 格 1 和表 格 2 中分別是必需和可選的參數:
參數名 | 作用 |
edu.yale.its.tp.cas.client.filter.loginUrl | 指定 CAS 提供登錄頁面的 URL |
edu.yale.its.tp.cas.client.filter.validateUrl | 指定 CAS 提供 service ticket 或 proxy ticket 驗證服務的 URL |
edu.yale.its.tp.cas.client.filter.serverName | 指定客戶端的域名和端口,是指客戶端應用所在機器而不是 CAS Server 所在機器,該參數或 serviceUrl 至少有一個必須指定 |
edu.yale.its.tp.cas.client.filter.serviceUrl | 該參數指定過后將覆蓋 serverName 參數,成為登錄成功過后重定向的目的地址 |
參數名 | 作用 |
edu.yale.its.tp.cas.client.filter.proxyCallbackUrl | 用于當前應用需要作為其他服務的代理(proxy)時獲取 Proxy Granting Ticket 的地址 |
edu.yale.its.tp.cas.client.filter.authorizedProxy | 用于允許當前應用從代理處獲取 proxy tickets,該參數接受以空格分隔開的多個 proxy URLs,但實際使用只需要一個成功即可。當指定該參數過后,需要修改 validateUrl 到 proxyValidate,而不再是 serviceValidate |
edu.yale.its.tp.cas.client.filter.renew | 如果指定為 true,那么受保護的資源每次被訪問時均要求用戶重新進行驗證,而不管之前是否已經通過 |
edu.yale.its.tp.cas.client.filter.wrapRequest | 如果指定為 true,那么 CASFilter 將重新包裝 HttpRequest,并且使 getRemoteUser() 方法返回當前登錄用戶的用戶名 |
edu.yale.its.tp.cas.client.filter.gateway | 指定 gateway 屬性 |
CAS 在登錄成功過后,會給瀏覽器回傳 Cookie,設置新的到的 Service Ticket。但客戶端應用擁有各自的 Session,我們要怎么在各個應用中獲取當前登錄用戶的用戶名呢?CAS Client 的 Filter 已經做好了處理,在登錄成功后,就可以直接從 Session 的屬性中獲取,如清單 11 所示:
|
在 JSTL 中獲取用戶名的方法如清單 12 所示:
|
另外,CAS 提供了一個 CASFilterRequestWrapper 類,該類繼承自HttpServletRequestWrapper,主要是重寫了 getRemoteUser() 方法,只要在前面配置 CASFilter 的時候為其設置“ edu.yale.its.tp.cas.client.filter.wrapRequest ”參數為 true,就可以通過 getRemoteUser() 方法來獲取登錄用戶名,具體方法如清單 13 所示:
|
![]() ![]() |
![]()
|
在 casTest1 和 casTest2 中,都有一個簡單 Servlet 作為歡迎頁面 WelcomPage,且該頁面必須登錄過后才能訪問,頁面代碼如清單 14 所示:
|
在上面所有配置結束過后,分別在 A, B, C上啟動 cas, casTest1 和 casTest2,按照下面步驟來訪問 casTest1 和 casTest2:
可以看到圖 中地址欄里的地址多出了一個 ticket 參數,這就是 CAS 分配給當前應用的 ST(Service Ticket)。
![]() ![]() |
![]()
|
本文介紹了 CAS 單點登錄解決方案的原理,并結合實例講解了在 Tomcat 中使用 CAS 的配置、部署方法以及效果。CAS 是作為開源單點登錄解決方案的一個不錯選擇,更多的使用細節可以參考 CAS 官方網站。
![]() |
||
![]() |
張濤,IBM 中國軟件開發實驗室工程師,目前主要致力于基于 Rational 平臺解決方案的開發。 |
![]() |
||
![]() |
王秉坤,IBM 中國軟件開發實驗室工程師,目前主要致力于基于 Rational 平臺解決方案的開發。 |
DWR是一個Open Source的 java項目。DWR可以讓JavaScript調用運行在Web服務器里面的JAVA程序。簡單一點或者專業一點就是Easy AJAX for JAVA.
下面將一步一步的介紹怎么完成一個簡單DEMO
1,從官方網站下載DWR https://dwr.dev.java.net/files/documents/2427/32252/dwr.war 把他直接放到TOMCAT_HOME/webapps 下面
2,編寫一個Java類如下:
DWRTest.java
package com.test.ajax;
/**
*
* @author 方見華
*
*/
public class DWRTest {
public DWRTest(){
}
public String getMyName(){
return "James Fang";
}
}
3, 把DRWTest類配置在dwr.xml中,dwr.xml是DWR的配置文件,所有需要在JavaScript中調用的java的類都必須在這個文件中描述 。這個文件的位于TOMCAT_HOME/webapps/dwr/WEB-INF/dwr.xml. 在<allow>標簽中添加以下內容
<create creator="new" javascript="MyTest" scope="application">
<param name="class" value="com.test.ajax.DWRTest"/>
</create>
4, 編寫調用DWRTest類 getMyName的方法的HTML文件,test.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
<html>
<head>
<title>DWR - My First AJAX</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<script type='text/javascript' src='/dwr/dwr/interface/MyTest.js'></script>
<script type='text/javascript' src='/dwr/dwr/engine.js'></script>
<script type='text/javascript' src='/dwr/dwr/util.js'></script>
<script language="javascript">
var mycall=function callBack(data){
DWRUtil.setValue("demo1",data);
}
function showMyName(){
MyTest.getMyName(mycall);
}
function clearName(){
demo1.value="";
}
</script>
</head>
<body>
<h1>Ajax Test Page</h1>
<input type="button" value="setMyName" onclick="javascript:showMyName()"><input type="button" value="Clear" onclick="javascript:clearName()"><br>
<input type="text" id="demo1"></select><br>
</body></html>
5, 運行,在瀏覽器中輸入 http://localhost:8080/dwr/test.html
如果將 form 提交到服務器端 ASP 程序,ASP 程序要獲得用戶選擇的那個 Radio 的 value 是非常方便的,用 request.Form("RadioName"),不必理會有幾個 Radio。
但在 JS(JavaScript) 中就要復雜多了,我們不能像對其它元素(如:文本框)一樣,使用 formid.objName.value 來取值,我們應該循環這個組的 Radio,判斷其 checked 屬性,再取值。
為了方便使用javascript獲取radio的值,我寫了一個通用的函數來實現:
function GetRadioValue(RadioName){
var obj;
obj=document.getElementsByName(RadioName);
if(obj!=null){
var i;
for(i=0;i<obj.length;i++){
if(obj[i].checked){
return obj[i].value;
}
}
}
return null;
}
比如,我們有一個name屬性為:“myradio”的單選控件組,要得到選中的值,只需這樣調用就可以了:
var RValue;
RValue=GetRadioValue("myradio");
如果沒有給出的radioname控件,則直接返回null,或者這一組控件沒有被選擇的項,則也返回null。
// 獲取編輯器中HTML內容
function getEditorHTMLContents(EditorName) {
var oEditor = FCKeditorAPI.GetInstance(EditorName);
return(oEditor.GetXHTML(true));
}
// 獲取編輯器中文字內容
function getEditorTextContents(EditorName) {
var oEditor = FCKeditorAPI.GetInstance(EditorName);
return(oEditor.EditorDocument.body.innerText);
}
// 設置編輯器中內容
function SetEditorContents(EditorName, ContentStr) {
var oEditor = FCKeditorAPI.GetInstance(EditorName) ;
oEditor.SetHTML(ContentStr) ;
}
FCKeditorAPI是FCKeditor加載后注冊的一個全局對象,利用它我們就可以完成對編輯器的各種操作。
在當前頁獲得 FCK 編輯器實例:
var Editor = FCKeditorAPI.GetInstance('InstanceName');
從 FCK 編輯器的彈出窗口中獲得 FCK 編輯器實例:
var Editor = window.parent.InnerDialogLoaded().FCK;
從框架頁面的子框架中獲得其它子框架的 FCK 編輯器實例:
var Editor = window.FrameName.FCKeditorAPI.GetInstance('InstanceName');
從頁面彈出窗口中獲得父窗口的 FCK 編輯器實例:
var Editor = opener.FCKeditorAPI.GetInstance('InstanceName');
獲得 FCK 編輯器的內容:
oEditor.GetXHTML(formatted); // formatted 為:true|false,表示是否按HTML格式取出
也可用:
oEditor.GetXHTML();
設置 FCK 編輯器的內容:
oEditor.SetHTML("content", false); // 第二個參數為:true|false,是否以所見即所得方式設置其內容。此方法常用于"設置初始值"或"表單重置"哦作。
插入內容到 FCK 編輯器:
oEditor.InsertHtml("html"); // "html"為HTML文本
檢查 FCK 編輯器內容是否發生變化:
oEditor.IsDirty();
在 FCK 編輯器之外調用 FCK 編輯器工具條命令:
命令列表如下:
DocProps, Templates, Link, Unlink, Anchor, BulletedList, NumberedList, About, Find, Replace, Image, Flash, SpecialChar, Smiley, Table, TableProp, TableCellProp, UniversalKey, Style, FontName, FontSize, FontFormat, Source, Preview, Save, NewPage, PageBreak, TextColor, BGColor, PasteText, PasteWord, TableInsertRow, TableDeleteRows, TableInsertColumn, TableDeleteColumns, TableInsertCell, TableDeleteCells, TableMergeCells, TableSplitCell, TableDelete, Form, Checkbox, Radio, TextField, Textarea, HiddenField, Button, Select, ImageButton, SpellCheck, FitWindow, Undo, Redo
使用方法如下:
oEditor.Commands.GetCommand('FitWindow').Execute();
package com.gpdi.softevaluate.action;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ProjectSetAction extends DispatchAction
{
/**
* <p>模板驗證</p>
* @param mapping
* @param form
* @param request
* @param response
* @return
* @throws Exception
*/
public ActionForward check(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response)throws Exception
{
String rest="";
String lotId="";
String retn="";
String flag="";
CommDaoFactory mgObj = new CommDaoFactory();
try
{
rest=request.getParameter("rest");
lotId=request.getParameter("lotId");
}
catch(Exception e)
{
}
if(!rest.equals("0")||!rest.equals("")||rest!=null)
{
flag="no";
}
else
{
flag="ok";
}
PrintWriter out=response.getWriter();
//服務器返回信息
out.write(flag);
out.close();
//讀取本Action所有的請求參數,將path重新構造,加上請求參數
//ActionForward forward= new ActionForward("project/projectSet.do?do=add&lotId=6");
//forward.setRedirect(true);
//傳參數后返回
//return forward;
return mapping.findForward(null);
}
public ActionForward creattable(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response)throws Exception
{
//實現功能代碼
return mapping.findForward("create");
}
}
3.struts.config.xml
<action attribute="projectSetForm" name="projectSetForm"
parameter="do" path="/project/projectSet" scope="request"
type="com.gpdi.softevaluate.action.ProjectSetAction" validate="false">
<forward name="list" path="/project/viewProject.jsp" />
<forward name="add" path="/project/addProject.jsp" />
<forward name="create" path="/project/createTable.jsp" />
</action>