一個帳號同一時間只能一人登錄
對于一個帳號在同一時間只能一個人登錄,可以通過下面的方法實現:
1 .在用戶登錄時,把用戶添加到一個 ArrayList 中
2 .再次登錄時查看 ArrayList 中有沒有該用戶,如果 ArrayList 中已經存在該用戶,則阻止其登錄
3 .當用戶退出時,需要從該 ArrayList 中刪除該用戶,這又分為三種情況
① 使用注銷按鈕正常退出
② 點擊瀏覽器關閉按鈕或者用 Alt+F4 退出,可以用 javascript 捕捉該頁面關閉事件,
執行一段 java 方法刪除 ArrayList 中的用戶
③ 非正常退出,比如客戶端系統崩潰或突然死機,可以采用隔一段時間 session 沒活動就刪除該 session 所對應的用戶來解決,這樣用戶需要等待一段時間之后就可以正常登錄。
?
在 LoginAction 中定義:
// 用來在服務器端存儲登錄的所有帳號
public static List logonAccounts;
?
login() 登錄方法中:
// 設置 session 不活動時間為 30 分
request.getSession().setMaxInactiveInterval(60*30);
if(logonAccounts==null){
??? logonAccounts = new ArrayList();
}
// 查看 ArrayList 中有沒有該用戶
if(!logonAccounts.contains(account.getAccountId())){
??? // 在用戶登錄時,把用戶添加到一個 ArrayList 中
??? logonAccounts.add(account.getAccountId());
??? return "login";
}else{
??? return "denied";
}
?
① 使用注銷按鈕正常退出
logout() 退出方法中:
if(logonAccounts==null){
??? logonAccounts = new ArrayList();
}
if(logonAccounts.contains(account.getAccountId())){
??? logonAccounts.remove(account.getAccountId());
}
?
② 點擊瀏覽器關閉按鈕或者用 Alt+F4 退出:
在后臺彈出一個窗口,在彈出窗口中刪除 ArrayList 中的用戶
function window.onbeforeunload(){
??? window.open('accountUnbound.jsp','',
??????????? 'height=0,width=0,top=10000,left=10000')
}
?
accountUnbound.jsp : 彈出窗口中刪除 ArrayList 中的用戶
<%
??? Account account = (Account) request.getSession().getAttribute("account");
??? if(account != null){
??????? if(LoginAction.logonAccounts==null){
??????????? LoginAction.logonAccounts = new ArrayList();
??????? }
??????? if(LoginAction.logonAccounts.contains(account.getAccountId())){
??????????? LoginAction.logonAccounts.remove(account.getAccountId());
??????? }
??? }
%>
為了保證上面代碼可以執行完畢, 3 秒后關閉此彈出窗口
<script>
setTimeout("closeWindow();",3000);
function closeWindow(){
??? window.close();
}
</script>
?
③ 使 implements HttpSessionListener ,并實現 sessionCreated/sessionDestroyed 方法
在 sessionDestroyed 中刪除 ArrayList 中的用戶(用戶超過 30 分鐘不活動則執行此方法)
??? Account account = (Account) request.getSession().getAttribute("account");
??? if(account != null){
??????? if(LoginAction.logonAccounts==null){
??????????? LoginAction.logonAccounts = new ArrayList();
??????? }
??????? if(LoginAction.logonAccounts.contains(account.getAccountId())){
??????????? LoginAction.logonAccounts.remove(account.getAccountId());
??????? }
??? }
?
注:
對于上面的,由于彈出窗口很容易被防火墻或者安全軟件阻攔,造成無法彈出窗口,從而短時間不能登錄,這種情況可以用 AJAX 來代替彈出窗口,同樣在后臺執行刪除用戶的那段代碼,卻不會受到防火墻限制:
<script>
??? // <![CDATA[
??? var http_request = false;
??? function makeRequest (url) {
??????? http_request = false;
??????? if (window.XMLHttpRequest) { // Mozilla, Safari,...
??????????? http_request = new XMLHttpRequest();
??????????? if (http_request.overrideMimeType) {
??????????????? http_request.overrideMimeType('text/xml');
??????????? }
??????? } else if (window.ActiveXObject) { // IE
??????????? try {
??????????????? http_request = new ActiveXObject("Msxml2.XMLHTTP");
??????????? } catch (e) {
??????????????? try {
??????????????????? http_request = new ActiveXObject("Microsoft.XMLHTTP");
??????????????? } catch (e) {
??????????????? }
??????????? }
??????? }
??????? if (!http_request) {
??????????? alert('Giving up :( Cannot create an XMLHTTP instance');
??????????? return false;
??????? }
??????? http_request.onreadystatechange = alertContents;
??????? http_request.open('GET', url, true);
??????? http_request.send(null);
?
??? }
??? function alertContents() {
??????? if (http_request.readyState == 4) {
??????????? if (http_request.status == 200) {
??????????????? window.close();
??????????? } else {
??????????????? alert('There was a problem with the request.');
??????????? }
??????? }
?
??? }
??? function window. onbeforeunload() {
??????? makeRequest ('accountUnbound.jsp');
??? }
??? //]]>
</script>
?
對于上面的這段 ajax 代碼,在網上有很多詳細的解釋,把它加到 onbeforeunload() 瀏覽器關閉事件中,在后臺執行代碼的效果很好, 不必擔心彈出窗口有時候會無效的問題 。
?
使用這段代碼后,上面 ② 中 accountUnbound.jsp 中的那段關閉彈出窗口 window.close(); 的 js 代碼就不需要了。
樹形菜單一
????根據dtree的要求,我們來建一個數據庫表來存儲樹的節點信息,表名為functions,其結構如下:
id字段:varchar 10 主鍵--節點標識碼 pid字段:varchar 10 not null--父節點標識碼 name字段:varchar 20 not null url字段:varchar 50 not null--這個字段存儲的是點擊該節點時,要定位的資源(比如一個頁面的url), 為了不使本文的篇幅過長,暫時不給出相應的頁面, 您可以隨便輸入一個字母比如:a,以使本例能夠正常運行。 title字段:varchar 20 target字段:varchar 10 icon字段:varchar 20 iconopen字段:varchar 20 opened字段:char 1 |
????在表中輸入如下一些記錄以供后面的實驗用:
0、-1、我的權限、javascript: void(0); 00、0、用戶管理、javascript: void(0); 0001、00、創建新用戶; 0002、00、刪除用戶; 01、0、 文章管理、javascript: void(0); 0101、01、添加新文章; 0102、01、修改文章; 0103、01、刪除文章; |
????到此,數據庫方面的準備工作就告一段落。
????接下來的工作我們仍然在先前介紹的mystruts項目中進行。先編寫一個名為:FunctionsForm的ActionForm,其代碼如下:
package entity; import org.apache.struts.action.*; import javax.servlet.http.*; public class FunctionsForm extends ActionForm { private String icon; private String iconOpen; private String id; private String name; private String opened; private String pid; private String target; private String title; private String url; public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public String getIconOpen() { return iconOpen; } public void setIconOpen(String iconOpen) { this.iconOpen = iconOpen; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getOpened() { return opened; } public void setOpened(String opened) { this.opened = opened; } public String getPid() { return pid; } public void setPid(String pid) { this.pid = pid; } public String getTarget() { return target; } public void setTarget(String target) { this.target = target; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } |
????因為我們的樹型節點的數據都存儲在數據庫表中,接下來,要做一個數據訪問對象類,名稱為:FunctionsDao.java,其代碼如下:
package db; import java.sql.*; import java.util.*; import entity.FunctionsForm; public class FunctionsDao { private static Connection con = null; public FunctionsDao(Connection con) { this.con=con; } public static Collection findTree() { PreparedStatement ps=null; ResultSet rs = null; ArrayList list=new ArrayList(); String sql="select * from functions"; try{ if(con.isClosed()){ throw new IllegalStateException("error.unexpected"); } ps=con.prepareStatement(sql); rs=ps.executeQuery(); while(rs.next()){ FunctionsForm functionsForm=new FunctionsForm(); functionsForm.setId(rs.getString("id")); functionsForm.setPid(rs.getString("pid")); functionsForm.setName(rs.getString("name")); functionsForm.setUrl(rs.getString("url")); functionsForm.setTitle(rs.getString("title")); functionsForm.setTarget(rs.getString("target")); functionsForm.setIcon(rs.getString("icon")); functionsForm.setIconOpen(rs.getString("iconOpen")); functionsForm.setOpened(rs.getString("opened")); list.add(functionsForm); } return list; } catch(SQLException e){ e.printStackTrace(); throw new RuntimeException("error.unexpected"); } finally{ try{ if(ps!=null) ps.close(); if(rs!=null) rs.close(); }catch(SQLException e){ e.printStackTrace(); throw new RuntimeException("error.unexpected"); } } } } |
????這里值得注意的是:在以往我們見到的一些顯示樹型菜單的程序,如:一些asp程序中往往簡單地采用遞歸調用的方法來查找到樹的各個節點。這對那些樹的深度不確定的場合還是有些用處,但這種處理方法也有一個致命的弱點,那就是反復地進行數據庫查詢,對一些節點較多的應用,對應用程序性能的影響是非常大的,有時會慢得讓人難以接受;而在實際的應用中大多數情況下樹的深度往往是有限的,如:用于會計科目的樹一般最多也在六層以下。又如:用作網頁功能菜單的情況,網頁設計的原則就有一條是:達到最終目的地,鼠標點擊次數最好不要多于三次。因此,在實際設計存儲樹型結構的表時要考慮查詢的效率。對能確定樹的最大深度的情況下,要設法盡量優化查詢語句,減少查詢次數,以提高應用程序的性能同時減少數據庫的負荷。
????本例對應的Action的名稱為FunctionsAction,其代碼如下:
package action; import entity.*; import org.apache.struts.action.*; import javax.servlet.http.*; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.Collection; import db.FunctionsDao; public class FunctionsAction extends Action { public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) { DataSource dataSource; Connection cnn=null; ActionErrors errors=new ActionErrors(); try{ dataSource = getDataSource(httpServletRequest,"A"); cnn = dataSource.getConnection(); FunctionsDao functionsDao=new FunctionsDao(cnn); Collection col=functionsDao.findTree(); httpServletRequest.setAttribute("treeList",col); return actionMapping.findForward("success"); } catch(Throwable e){ e.printStackTrace(); //throw new RuntimeException("未能與數據庫連接"); ActionError error=new ActionError(e.getMessage()); errors.add(ActionErrors.GLOBAL_ERROR,error); } finally{ try{ if(cnn!=null) cnn.close(); } catch(SQLException e){ throw new RuntimeException(e.getMessage()); } } saveErrors(httpServletRequest,errors); return actionMapping.findForward("fail"); } } |
????在struts-config.xml文件中加入如下內容:
<form-beans> <form-bean name="functionsForm" type="entity.FunctionsForm" /> </form-beans> <action-mappings> <action name="functionsForm" path="/functionsAction" scope="request" type="action.FunctionsAction" validate="false" > <forward name="success" path="/testDTree.jsp" /> <forward name="fail" path="/genericError.jsp" /> </action> </action-mappings> |
????為了對應配置中的,我們還要提供一個顯示錯誤信息的jsp頁面,其代碼如下:
<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html> <head> <title> genericError </title> <link href="css/mycss.css" rel="stylesheet" type="text/css"> </head> <body bgcolor="#ffffff"> <html:errors/> </body> </html> |
????下面,我們來看一下我們顯示樹型菜單的頁面代碼,從配置中可以看出,頁面的名稱為testDTree.jsp,代碼如下:
<%@ page contentType="text/html; charset=UTF-8" %> <%@ 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> testDTree </title> <link rel="StyleSheet" href="css/dtree.css" type="text/css" /> </head> <body bgcolor="#eeeeee"> <body leftmargin="0" topmargin="0"><table width="180"> <tr><td height="300" valign="top" nowrap> <script type="text/javascript" src="js/dtree.js"></script> <script type='text/javascript'> tree = new dTree('tree'); tree.config.folderLinks=false; tree.config.useCookies=false; <logic:iterate id="functionsForm" name="treeList" scope="request" type="entity.FunctionsForm"> tree.add("<bean:write name="functionsForm" property="id"/>","<bean:write name="functionsForm" property="pid"/>","<bean:write name="functionsForm" property="name"/>","<bean:write name="functionsForm" property="url"/>","<bean:write name="functionsForm" property="title"/>","<bean:write name="functionsForm" property="target"/>","<bean:write name="functionsForm" property="icon"/>"); </logic:iterate> document.write(tree); </script> </td> </tr> </table> </body> </html> |
????從 可以看出,我們要在mystruts目錄下,建一個名為js的目錄,并將下載的dtree文件dtree.js放在該目錄中。
????再在mystruts目錄下分別建一個名為img和名為css的目錄,將dtree中用到的圖標和層疊樣式表單文件分別放在相應的目錄中。
????有關dtree的使用方法,詳見其說明文檔,如:api.html。筆者在此要感謝dtree的作者為我們提供了一個結構如此清晰的javascript程序!
????現在,可以編譯執行這個例子程序了,編譯后在瀏覽器中輸入:http://127.0.0.1:8080/mystruts/functionsAction.do就可以看到運行效果。效果圖為:
????注:dtree的下載地址為: http://www.destroydrop.com/javascripts/tree/
使用hashtable對字符串操作
1.在一些字符串數組中,常會有重復的記錄,比如手機號碼,我們可以通過Hashtable來對其進行過濾


















示例:
??? ??? String[] mobile={"13811071500","13811071500","13811071501","13811071503","13811071501"};
??? ??? mobile=checkArray(mobile);
??? ??? for(int i=0;i<mobile.length;i++)
??? ??? ??? System.out.println(mobile[i]);
??? ?? 輸出結果為:
??? ??? 13811071503
??? ??? 13811071501
??? ??? 13811071500
2.A,B均為字符串數組,找出在A中存在,而在B中不存在的字符串
??? public String[] compareArray(String[] A,String[] B){
??? ??? Hashtable<String, String> hash=new Hashtable<String, String>();
??? ??? Hashtable<String, String> hash_new=new Hashtable<String, String>();
??? ??? for(int i=0;i<B.length;i++)
??? ??? ??? hash.put(B[i], B[i]);
??? ??? for(int i=0;i<A.length;i++){
??? ??? ??? if(!hash.containsKey(A[i]))
??? ??? ??? ??? hash_new.put(A[i], A[i]);
??? ??? }
??? ??? String[] C=new String[hash_new.size()];
??? ??? int i=0;
??? ??? Enumeration enumeration=hash_new.keys();
??? ??? while(enumeration.hasMoreElements()){
??? ??? ??? C[i]=enumeration.nextElement().toString();
??? ??? ??? i++;
??? ??? }
??? ??? return C;
??? }
示例:
??? ??? String[] mobile1={"13811071500","13811071501","13811071502","13811071503","13811071504"};
??? ??? String[] mobile2={"13811071500","13811071505","13811071502","13811071506","13811071504"};
??? ??? String[] mobile3=compareArray(mobile1,mobile2);
??? ??? for(int i=0;i<mobile3.length;i++)
??? ??? ??? System.out.println(mobile[i]);
輸出結果:
??? 13811071503
??? 13811071501
存在的問題:
每次都是倒序,可以再對程序稍加改動,變成正序。
?
3.將一個字符串數組中某一個特定的字符串過濾掉
























java隨機數
??????? 隨機數發生器(Random)對象產生以后,通過調用不同的method:nextInt()、nextLong()、nextFloat()、nextDouble()等獲得不同類型隨機數。
?????? 1>生成隨機數
?? ??????? Random random = new Random();
?????????? Random random = new Random(100);//指定種子數100
?????????? random調用不同的方法,獲得隨機數。
?????????? 如果2個Random對象使用相同的種子(比如都是100),并且以相同的順序調用相同的函數,那它們返回值完全相同。如下面代碼中兩個Random對象的輸出完全相同
????????? import java.util.*;
????????? class TestRandom {
??????????????? public static void main(String[] args) {
???????????????????? Random random1 = new Random(100);
???????????????????? System.out.println(random1.nextInt());
???????????????????? System.out.println(random1.nextFloat());
?????????????????????System.out.println(random1.nextBoolean());
???????????????????? Random random2 = new Random(100);
???????????????????? System.out.println(random2.nextInt());
???????????????????? System.out.println(random2.nextFloat());
???????????????????? System.out.println(random2.nextBoolean());
??????????????? }
??????????? }
????????2>指定范圍內的隨機數
???????????? 隨機數控制在某個范圍內,使用模數運算符%
??????????? import java.util.*;
???????????????? class TestRandom {
????????????????????? public static void main(String[] args) {
?????????????????????????? Random random = new Random();
?????????????????????????? for(int i = 0; i < 10;i++) {
?????????????????????????????? System.out.println(Math.abs(random.nextInt())%10);
?????????????????????????? }
????????????????????? }
???????????????? }
???????????? 獲得的隨機數有正有負的,用Math.abs使獲取數據范圍為非負數
???????3>獲取指定范圍內的不重復隨機數
?????????? ?import java.util.*;
????????????class TestRandom {
????????????????? public static void main(String[] args) {
???????????????????????int[] intRet = new int[6];?
?????????????????????? int intRd = 0; //存放隨機數
?????????????????????? int count = 0; //記錄生成的隨機數個數
?????????????????????? int flag = 0; //是否已經生成過標志
?????????????????????? while(count<6){
??????????????????????????? Random rdm = new Random(System.currentTimeMillis());
??????????????????????????? intRd = Math.abs(rdm.nextInt())%32+1;
?????????????????????????? ?for(int i=0;i<count;i++){
?????????????????????????????? ?if(intRet[i]==intRd){
??????????????????????????????????? flag = 1;
??????????????????????????????????? break;
????????????????????????????????}else{
??????????????????????????????????? flag = 0;
????????????????????????????????}
??????????????????????????? }
??????????????????????????? if(flag==0){
??????????????????????????????? intRet[count] = intRd;
??????????????????????????????? count++;
????????????????????????????}
?????????????????? }
????????????????? for(int t=0;t<6;t++){
????????????????????? System.out.println(t+"->"+intRet[t]);
??????????????????}
?????????????? }
??????????? }
Java中的隨機數是否可以重復?Java中產生的隨機數能否可以用來產生數據庫主鍵?帶著這個問題,我們做了一系列測試。
1.測試一: 使用不帶參數的Random()構造函數
public class RandomTest? {
? public static void main(Str
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
