#
計算機生于美國,英語是他的母語,而英語以外的其它語言對他來說都是外語。他跟我們一樣,不管外語掌握到什么程度,也不會像母語那樣使用得那么好,時常也會出一些“拼寫錯誤”問題。
亂碼的出現根本原因在于編碼和解碼使用了不同的編碼方案。比如用GBK編碼的文件,用UTF-8去解碼結果肯定都是火星文。所以要解決這個問題,中心思想就在于使用統一的編碼方案。
jsp頁面間的參數傳遞有以下幾種方式:1、表單(form)的提交。2、直接使用URL后接參數的形式(超級鏈接)。3、如果兩個jsp頁面在兩個不同的窗口中,并且這兩個窗口是父子的關系,子窗口中的jsp也可以使用javascript和DOM(window.opener.XXX.value)來取得父窗口中的jsp的輸入元素的值。下面就前兩種方式中出現的亂碼問題做一下剖析。
1、表單(form)的提交實現參數頁面間的傳遞
在介紹表單傳遞參數的內容之前,先來了解一些預備知識。表單的提交方式和請求報文中對漢字的處理。
表單的提交方式:
通常使用的表單的提交方式主要是:post和get兩種。兩者的區別在于:post方式是把數據內容放在請求的數據正文部分,沒有長度的限制;get方式則是把數據內容直接跟在請求的頭部的URL后面,有長度的限制。下面是同一個頁面兩種方式的請求報許文。
Requesttest.jsp代碼
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%-- post方式提交表單 --%>
<form action="http://localhost:8888/EncodingTest/requestresult.jsp" method="post">
UserName:<input type="text" name="username"/>
Password:<input type="password" name="password"/>
<input type="submit" value="Submit">
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <%-- post方式提交表單 --%> <form action="http://localhost:8888/EncodingTestb/requestresult.jsp" method="post"> UserName:<input type="text" name="username"/> Password:<input type="password" name="password"/> <input type="submit" value="Submit"> </form> </body> </html>
在上面的請求頁面的username輸入框里輸入的是“世界杯”三個漢字,password輸入框中輸入"123"后按下Submit按鈕提交請求。截獲到的請求報文如下:
Post方式的請求報文代碼
POST /EncodingTest/requestresult.jsp HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://localhost:8080/TomcatJndiTest/requesttest.jsp
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; aff-kingsoft-ciba; .NET CLR 2.0.50727)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8888
Content-Length: 49
Connection: Keep-Alive
Cache-Control: no-cache
username=%E4%B8%96%E7%95%8C%E6%9D%AF&password=123
POST /EncodingTest/requestresult.jsp HTTP/1.1 Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Referer: http://localhost:8080/TomcatJndiTest/requesttest.jsp Accept-Language: zh-cn User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; aff-kingsoft-ciba; .NET CLR 2.0.50727) Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Host: localhost:8888 Content-Length: 49 Connection: Keep-Alive Cache-Control: no-cache username=%E4%B8%96%E7%95%8C%E6%9D%AF&password=123
以上報文內容,可以看出post方式的請求報文是有專門的數據部的。,
下面的同一請求頁面的get提交方式的請求報文:
Get方式的請求報文代碼
GET /EncodingTest/requestresult.jsp?username=%E4%B8%96%E7%95%8C%E6%9D%AF&password=123 HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://localhost:8080/TomcatJndiTest/requesttest.jsp
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; aff-kingsoft-ciba; .NET CLR 2.0.50727)
Accept-Encoding: gzip, deflate
Host: localhost:8888
Connection: Keep-Alive
GET /EncodingTest/requestresult.jsp?username=%E4%B8%96%E7%95%8C%E6%9D%AF&password=123 HTTP/1.1 Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Referer: http://localhost:8080/TomcatJndiTest/requesttest.jsp Accept-Language: zh-cn User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; aff-kingsoft-ciba; .NET CLR 2.0.50727) Accept-Encoding: gzip, deflate Host: localhost:8888 Connection: Keep-Alive
以上報文內容,可以看出get方式的請求報文沒有專門的數據部,數據是直接跟在url的后面。
請求報文中對漢字的處理:
從上面兩種報文可以看出頁面上輸入的“世界杯”三個漢字被替換成了"%E4%B8%96%E7%95%8C%E6%9D%AF”這樣一個字符串,然后發給服務器的。看到這,可能會有兩個問題:問題一、這個字符串是什么?問題二、為什么要做這樣的替換?
這個字符串是“世界杯”這三個漢字對應的"UTF-8”編碼"E4B896E7958CE69DAF"在每個字節前追加一個"%"后形成的。至于為什么要做這樣的轉化,我的理解是:因為請求報文會以"ISO-8859-1"的編碼方式編碼后,通過網絡流的方式傳送到服務器端。"ISO-8859-1"僅支持數字、英文字母和一些特殊字符,所以像漢字等這樣的字符"ISO-8859-1"是不認識的。所以就必須先給這些"ISO-8859-1"不支持的字符做個“整形”手術。這樣才能正確的將頁面上的信息傳送到服務器端。
這時可能又會有另外一個問題:上面的例子中為什么會選用"UTF-8"編碼,其它的編碼方案可以嗎?答案是可以的。在jsp頁面代碼的頭部有這樣一段代碼"<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>"其中charset的值就是瀏覽器在提交請求報文前,對請求報文做“整形”手術時用的字符集,同是也是瀏覽器解釋服務器的響應頁面時的字符集。
在了解了以上內容后,開始剖析表單方式傳遞參數的亂碼問題。
以上例為例,點擊"Submit"按鈕后,瀏覽器將做完“整形”手術后的請求報文發送給WEB服務器上的Servlet容器,容器在收到這個請求報文后,會解析這個請求報文并用這個報文的信息生成一個HttpServletRequest對象,然后將這個HttpServletRequest對象傳給這個頁面所要請求的jsp或Servlet(上例中為"requestresult.jsp")。在這個被請求的jsp或Servlet(上例中為"requestresult.jsp")中,使用HttpServletRequest對象的getParameter("")方法來取得上一頁面傳來的參數。默認情況下,這一方法使用的是"ISO-8859-1"來解碼,所以對于英文或數字的參數值自然能正確取得,但對于漢字這樣的字符是解不出來的,因為那幾個漢字曾經做過“整形”手術,已經認不出來了。要想再把它們認出來,那就得要把手術的主刀醫生找到,然后再做一次“還原”手術。下面提供的幾個方案,可用于不同的情況。
方案一代碼
<%String str = new String(request.getParameter("username").getBytes("ISO-8859-1"),"utf-8"); %>
Username:<%=str %>
<%String str = new String(request.getParameter("username").getBytes("ISO-8859-1"),"utf-8"); %> Username:<%=str %>
既然request.getParameter("username")默認情況下返回的字符串是用"ISO-8859-1"解出來的,那就先把這個不可辨認的字符串再用"ISO-8859-1"來打散,也就是:request.getParameter("username").getBytes("ISO-8859-1")。最后再用跟你的頁面的charset一致的字符集來重組這個字符串:new String(request.getParameter("username").getBytes("ISO-8859-1"),"utf-8")。這樣就能見到它的廬山真面目了。
方案一是一種比較萬能的方法,不管是post還是get都適用,但可以看出它的缺點是:對于每個可能出現漢字的參數都要顯示的做這么一段處理。一個兩個還行,要是很多的話,那就應該考慮一下是不是可以選用下一種方案。
方案二代碼
<%request.setCharacterEncoding("UTF-8"); %>
<%request.setCharacterEncoding("UTF-8"); %>
方案二是在頁面的最開始或者是在該頁面中使用的第一個request.getParameter("")方法之前加上上述一段代碼,它的作用是用作為參數傳入的編碼集去覆蓋request對象中的默認的"ISO-8859-1"編碼集。這樣request.getParameter("")方法就會用新的編碼集去解碼,因為"UTF-8"支持中文,所以作為參數傳過來的“世界杯”三個漢字就能正確的接收到了。但關于request.setCharacterEncoding("")方法,API文檔中有如下的說明:
Overrides the name of the character encoding used in the body of this request. This method must be called prior to reading request parameters or reading input using getReader(). Otherwise, it has no effectb.
所以方案二只對post方式提交的請求有效,因為參數都在request的body區。而對get方式提交的請求則是無效的,這時你會發現同樣的做法但顯示的還是亂碼。所以你的請求要是是以get方式提交的話,那你還是乖乖的選用方案一吧!
從上面的敘述可以知道,方案二需要在每個頁面的前頭加上<%request.setCharacterEncoding("UTF-8"); %>這段代碼,這樣做是不是也挺累的,所以我們想到了使用過濾器來幫助我們做這件事兒,那就清爽、簡單多了。
Encodingfilter代碼
public class EncodingFilter implements Filter {
private String charset;
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//用init方法取得的charset覆蓋被攔截下來的request對象的charset
request.setCharacterEncoding(this.charset);
//將請求移交給下一下過濾器,如果還有的情況下。
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig config) throws ServletException {
//從web.xml中的filter的配制信息中取得字符集
this.charset = config.getInitParameter("charset");
}
}
public class EncodingFilter implements Filter { private String charset; @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //用init方法取得的charset覆蓋被攔截下來的request對象的charset request.setCharacterEncoding(this.charset); //將請求移交給下一下過濾器,如果還有的情況下。 chain.doFilter(request, response); } @Override public void init(FilterConfig config) throws ServletException { //從web.xml中的filter的配制信息中取得字符集 this.charset = config.getInitParameter("charset"); } }
要想這個過濾器生效,還得到web.xml里加入下面的配制信息。
Web.xml代碼
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>cn.eric.encodingtest.filter.EncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter> <filter-name>EncodingFilter</filter-name> <filter-class>cn.eric.encodingtest.filter.EncodingFilter</filter-class> <init-param> <param-name>charset</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2、直接使用URL后接參數的形式(超級鏈接)。
有些時候可能會遇到通過一個超級鏈接來把參數傳到下一個頁面,而剛好這個參數的值有可能會出現中文的情況。就像下面這樣:
<a href="./jstlresult.jsp?content=世界杯">Go South Africa
跟form提交有些不同的是:當你點擊這個超級鏈接后在瀏覽器的地址欄里看到的是http://localhost:8080/TomcatJndiTest/jstlresult.jsp?content=世界杯,而不是http://localhost:8080/TomcatJndiTest/jstlresult.jsp?content=%E4%B8%96%E7%95%8C%E6%9D%AF
這里瀏覽器并沒有幫我們把這個轉化工作搞定,所以這里要自己動手,豐衣足食了。做法如下:
<a href="./jstlresult.jsp?content=<%=java.net.URLEncoder.encode("世界杯","utf-8") %>">Go South Africa
這樣的話在第二個頁面就能使用<%String str = new String(request.getParameter("content").getBytes("ISO-8859-1"),"utf-8"); %>的方法來正確的得到這個參數值了。
總結一下:
1、post提交的方式:使用過濾器,將到達頁面前的request對象中的字符編碼設定成跟你頁面統一的編碼。
2、get提交的方式:<%String str = new String(request.getParameter("content").getBytes("ISO-8859-1"),"utf-8"); %>這樣的字符串重組的方法。
3、超級鏈接方式:先將鏈接url中的漢字用java.net.URLEncoder.encode("paramValue","charset")方法處理一下,下面的做法參照2。
有個IT老公真傷不起,不知道什么時候就在你的電腦里動點手腳,把你整的云里霧里。
老公為了對付老婆看電視連戲劇,什么都想出來了。。。。
老公,是被老婆逼急了。老婆,被老公整慘了。
以下是原文,源代碼都公布了,被逼急了的老公是否試一下。
寫幾個代碼化解家庭糾紛
因老婆迷戀《重案6組》第三部(其實其它電視劇只要迷上也是這德性),這幾天晚上都要看到12點多甚至1點才睡覺,讓她睡嘛又有意見,強行關機是不可能的,這就是犟脾氣。第二天我們都要上班,為了家庭和諧,決定從技術上想辦法。
通過手機連接無線路由控制,進行查看dhcp客戶端列表,根據計算機名獲得老婆計算機的ip,然后再通過路由設置進行寬帶限速,限制在10-12kbtb,這帶寬看視頻是不可能了。誰知道優酷一下緩沖了一集的,一集時間太長,所以這個失敗了。
昨晚00:05趁老婆沖涼的功夫,偷偷在她計算機上添加計劃任務,配置了00:30執行shutdown,參數啥都配置好了,然后我臉朝一側偷笑,想著,等你進屋吹完頭發剛坐下沒看兩分鐘,就關機,這樣就可以休息了。結果樂了好一會,但居然沒關系,看來是shutdown參數或計劃任務有問題。
于是呼想做個東西放她電腦上,但可憐的是她也是做it的,所以程序要適當高級一點。這就是需求。
程序要做得方便合理,即她不知道有程序在運行,我控制也要人性化,什么時候想關機就關機,或者重啟(因為有時周末我也玩得晚)。所以最后結論:1、用戶不知道這個程序的存在;2、程序運行不影響用戶正常操作;3、能遠程控制。 這就是需求分析。
設計思路:后臺開啟http服務,晚上要她老看電視劇不休息,我就手機瀏覽器連接這個http服務,點1下就控制了。
最終思路:
1、因我是做java的,老婆機器上也有jdk,于是就用jdk1.6寫一httpserver,運行后可以通過瀏覽器訪問,并能接收關機類型、延遲時間這兩個參數。
2、寫一個批處理命令,用來悄悄執行這個java程序,運行過程無毒無煙無污染,以免起疑。
3、通過操作系統計劃任務或者開機啟動功能來運行這個批處理。
MySQL:
String Driver="com.mysql.jdbc.Driver"; //驅動程序
String URL="jdbc:mysql://localhost:3306/db_name"; //連接的URL,db_name為數據庫名
String Username="username"; //用戶名
String Password="password"; //密碼
Class.forName(Driver).new Instance();
Connection con=DriverManager.getConnection(URL,Username,Password);
Microsoft SQL Server:
1)
String Driver="com.microsoft.jdbc.sqlserver.SQLServerDriver"; //連接SQL數據庫的方法
String URL="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=db_name"; //db_name為數據庫名
String Username="username"; //用戶名
String Password="password"; //密碼
Class.forName(Driver).new Instance(); //加載數據可驅動
Connection con=DriverManager.getConnection(URL,UserName,Password); //
2)
String Driver="com.microsoft.sqlserver.jdbc.SQLServerDriver"; //連接SQL數據庫的方法
String URL="jdbc:sqlserver://localhost:1433;DatabaseName=db_name"; //db_name為數據庫名
String Username="username"; //用戶名
String Password="password"; //密碼
Class.forName(Driver).new Instance(); //加載數據可驅動
Connection con=DriverManager.getConnection(URL,UserName,Password);
Sysbase:
String Driver="com.sybase.jdbc.SybDriver"; //驅動程序
String URL="jdbc:Sysbase://localhost:5007/db_name"; //db_name為
tb數據可名
String Username="username"; //用戶名
String Password="password"; //密碼
Class.forName(Driver).newInstance();
Connection con=DriverManager.getConnection(URL,Username,Password);
Oracle(用thin模式):
String Driver="oracle.jdbc.driver.OracleDriver"; //連接數據庫的方法
String URL="jdbc:oracle:thin:@loaclhost:1521:orcl"; //orcl為數據庫的SID
String Username="username"; //用戶名
String Password="password"; //密碼
Class.forName(Driver).newInstance(); //加載數據庫驅動
Connection con=DriverManager.getConnection(URL,Username,Password);
PostgreSQL:
String Driver="org.postgresql.Driver"; //連接數據庫的方法
String URL="jdbc:postgresql://localhost/db_name"; //db_name為數據可名
String Username="username"; //用戶名
String Password="password"; //密碼
Class.forName(Driver).newInstance();
Connection con=DriverManager.getConnection(URL,Username,Password);
String Driver="org.postgresql.Driver"; //連接數據庫的方法
DB2:
String Driver="com.ibm.db2.jdbc.app.DB2.Driver"; //連接具有DB2客戶端的Provider實例
//String Driver="com.ibm.db2.jdbc.net.DB2.Driver"; //連接不具有DB2客戶端的Provider實例
String URL="jdbc:db2://localhost:50000/db_name"; //db_name為數據可名
String Username="username"; //用戶名
String Password="password"; //密碼
Class.forName(Driver).newInstance();
Connection con=DriverManager.getConnection(URL,Username,Password);
Informix:
String Driver="com.informix.jdbc.IfxDriver";
String URL="jdbc:Informix-sqli://localhost:1533/db_name:INFORMIXSER=myserver"; //db_name為數據可名
String Username="username"; //用戶名
String Password="password"; //密碼
Class.forName(Driver).newInstance();
Connection con=DriverManager.getConnection(URL,Username,Password);
JDBC-ODBC:
String Driver="sun.jdbc.odbc.JdbcOdbcDriver";
String URL="jdbc:odbc:dbsource"; //dbsource為數據源名
String Username="username"; //用戶名
String Password="password"; //密碼
Class.forName(Driver).newInstance();
Connection con=DriverManager.getConnection(URL,Username,Password);
假設任你選擇一種職業,你打算干什么?美國人的回答充分顯示了干一行厭一行。一位軍界要人說:“去鄉間開一個雜貨店。”一位女部長說:“到哥斯達黎加的濱海游覽區開一家旅館。”一位市長說:“改行當攝影記者。”而一位勞工部部長說:“出任一家冰激凌公司的總經理。”
假設有來世,你打算作何選擇?日本有一百多位商人接受測試,回答可說是五花八門,盡其想象。其中,表示繼續從商的很少,大部分人愿意當藝術家或學者,有男士說想投胎為女子,有人說甘愿退出人的世界化為植物,甚至有人說愿意變為一只狗。
我覺得這試驗很有噱頭,于是作東施效顰。一日,拜訪作家諶容,趁便問:“假設時光倒流,您會不會重新選擇?”諶女士其時正在戒煙,她一邊嗑瓜子,一邊說:“我想這沒什么好選擇,我就是喜歡寫作。”
又一日,看望學者金克木。當著金老的面,我什么也沒提,只是漫無邊際地閑聊。回家后,給金老撥了個電話。金老在電話那頭笑了。他說:“花非花,霧非霧,美國人、日本人怎么說,我不管,反正永遠當不了真。你要我說嗎?一定要?我的答復只能是—哈哈哈哈!”
隨后,我或用電話直接征詢,或借助朋友的幫忙,在周圍廣為撒網。測驗的結果是—
劇作家吳祖光、畫家吳冠中與法國文學專家羅大岡全都笑而不答。
北大中文系著名教授袁行霈則說:“來世,肯定地說,我還想教書。”
中國市長協會負責人陶斯亮輕盈地一笑:“要有來世,我就學音樂。”
小提琴演奏家盛中國對今生的選擇十分自負:“音樂是一種深入靈魂超越國界的語言,我不想改弦易轍。”
清華大學電子工程系教授鄭君里搖了搖頭:“知識分子還是要當的,但不想再搞工程方面的研究,可以搞文學、社會科學。為什么?
tb工程方面涉及的人太多,難以出成果。”
作家袁鷹:“繼續當編輯,我覺得這差事很美……”
作家藍翎:“這個問題我如此回答你:我最初的愿望是學英語,我的后輩都是工程技術人員。”
詩人牛漢:“這輩子由于種種原因,沒寫出大名堂,壯志未酬,遺憾哪遺憾!因此,下一輩子還是要寫詩,下兩輩子下三輩子也還是要寫詩!”
雕塑家鄭于鶴:“我是搞造型藝術的,我覺得幾十年時間根本不夠,若有可能,我想二百年三百年地連續搞,也許能做出點成績。”
書法家徐楚德:“我嘛,來生還是寫字,既可躲進小樓成一統,避免外界干擾,又有成就感。”
經濟學家管益忻:“那我就要考慮怎樣在陸地和地球之外重建人類的家園了。”
作家蔣子龍:“下輩子我想做一只鳥。天空多干凈,鳥兒多自由,它既可以高飛,也可以享受地面,可以走、跑、停,還可以演唱。”
作家石英:“若有可能,下輩子當個隱士,怎樣?”
最后,我又撥通了學者季羨林的電話。不久前曾經登門求教,季老贈了我五本書,我講了一些讀后感,末了小心翼翼地探問:“假設有來世,先生……”季老答:“你別問,我不相信有來世。”我連忙申明:“這僅僅是假設,假設……”季老沒吱聲,也許是沒弄明白我的意思,也許是覺著不值得回答。
燈下翻閱季老贈我的散文集《賦得永久的悔》,在《一個老知識分子的心聲》一文篇尾,不期覓得現成的答案。季老在講了過去七八十年中的酸甜苦辣后,筆鋒一轉說:“我從來不相信什么輪回轉生。現在,如果讓我相信一回的話,我就恭肅虔誠禱祝造化小兒,下一輩子無論如何也別再撥弄我,千萬別再把我撥弄成知識分子。”
摘要: GetFocus()功能確定當前焦點位于哪個控件上。語法GetFocus ( )返回值GraphicObject。函數執行成功時返回當前得到焦點控件的引用,發生錯誤時返回無效引用。用法應用程序利用IsValid()函數可以檢測GetFocus()是否返回有效的控件引用。同時,使用TypeOf()函數可以確定控件的類型。 Post()功能將指定消息加入到某個窗口的消息隊列中,這個窗口既可以是Powe...
閱讀全文
一、連接數據庫
連接數據庫也就是指定事務對象。PowerBuilder提供了兩個函數:SetTrans()和SetTransObject()。
語法格式:
dw_control.SetTrans(TransactionObject)
dw_control.SetTransObject(TransactionObject)
其中,dw_control是所使用的數據窗口控件,transactionObject是所要指定的事務對象。
這兩個函數有一個重要的區別就是在使用SetTrans()函數時,用戶不需做任何數據初始化或事務對象初始化工作。用戶只需要在這里填充一個事務對象,PB就會自動完成對該事物對象的初始化以及和數據庫連接的工作。而使用SetTransObject()函數時,用戶必須首先把所用的事務對象連接到數據庫上。
但是,這并不意味著SetTrans()函數比SetTransObject()函數更好,使用SetTrans()函數時,每調用一次函數必須連接一次數據庫,因為這個函數在每個事務處理的末端都會執行Disconnect語句。與此相反,使用SetTransObject()函數可以為數據庫維持一個開放性的連接。因此在一般情況下,為了提高效率,總是采用SetTransObject()函數。
這兩個函數都是成功時返回1,發生錯誤時返回-1。
二、檢索數據
用于檢索數據的函數只有一個,就是Retrieve()函數。
語法格式:
dw_control.Retrieve()
如果數據窗口控件上的數據窗口對象是有檢索參數的,就要在這個函數調用時加上檢索參數。而且檢索參數必須和數據窗口對象中定義順序一致。
此函數返回一個長整型的數據,代表檢索出來的數據行數。如果發生錯誤,將返回-1。
三、更新數據
當用戶對數據窗口對象內的數據修改后,想把這些修改反映到數據庫中去時,必須使用Update()函數。
語法格式:
dw_control.Update()
這個更新可能成功,也可能失敗。一般在這個函數被調用之后,總是要做一個檢查。請看下面的例子:
Int li_return
li_return = dw_1.Update()
IF li_return = 1 THEN
COMMIT USING SQLCA;
ELSE
ROLLBACK USING SQLCA;
END IF
在這段代碼中,首先對數據窗口控件進行更新操作。但是更新只是把數據寫入到客戶機的內存,并沒有提交到數據庫中。如果更新成功,就把它提交到數據庫中,如果更新失敗,就回滾到當前的事務。
行操作
行操作的函數主要是對數據庫中的數據進行插入、刪除或選擇操作TB。
一、插入行
在DataWindow中插入一行,可以使用InsertRow()函數。
語法格式:
dw_control.InsertRow(rownumber)
dw_control是數據窗口控件名,rownumber是要插入行的的行號。如果這個參數為0,代表在當前DataWindow的最后一行插入一空行。
InsertRow()函數返回一個長整型值,以此來代表插入的行號。如果插入失敗,則返回-1。
二、刪除行
要刪除DataWindow內的一行數據,則要使用DeleteRow()函數。
語法格式:
dw_control.DeleteRow(rownumber)
其中rownumber是要刪除的行號。如果該值為0,表示刪除當前行。如果刪除成功,返回1,失敗則返回-1。
三、設置當前行
如果要設置DataWindow中的某行為當前行,可以使用SetRow()函數。
語法格式:
dw_control.SetRow(rownumber)
其中rownumber是要設置為當前行的行號。如果函數返回1表示成功,返回-1代表失敗。
四、獲取當前行
如果想要獲取DataWindow中的某行為當前行,可以使用GetRow()函數。
語法格式:
dw_control.GetRow()
該函數沒有參數,它返回一個長整型,代表當前行號。如果返回-1代表失敗。如果返回0代表沒有選中任何行。
五、選擇行
如果想要在DataWindow中加亮顯示某一行或取消加亮顯示某一行,可以使用SelectRow()函數。
語法格式:
dw_control.SelectRow(rownumber,select)
其中,rownumber表示要加亮或者取消加這顯示的行號,0表示所有行。select是一個布爾類型的值,TRUE表示加亮,FALSE表示取消加亮顯示。該函數返回1時表示成功,返回-1時表示失敗。
如果想要直接設置某一行為加亮,需要首先取消其它行的加亮顯示狀態,采用如下的兩行代碼:
dw_1.SelectRow(0,FALSE)
dw_1.SelectRow(rownumber,TRUE)
六、TB獲取選擇行
如果想要獲取當前DataWindow中加亮顯示的行,可以使用GetSelectRow()函數。
語法格式:
dw_control.GetSelectRow(rownumber)
其中,rownumber為開始查找的行的行號,0表示從頭開始查找。該函數返回一個長整數,表示從rownumber開始查找第一個加亮顯示的行的行號。如果失敗返回0。
七、滾動行
如果在DataWindow的末尾插入一行數據,而當前行是在DataWindow的中央,那么這種插入可能不會被用戶覺察。為了改變這種情況,可以滾動行到DataWindow的末尾,這樣用戶就能發現新的改變。要滾動行,可以使用ScrollToRow()函數。
語法格式:
dw_control.ScrollToRow(rownumber)
該函數返回1時表示成功,返回-1時表示失敗。
與ScrollToRow()函數據功能相關的還有如下幾個函數:
ScrollPriorRow():向上滾動一行
ScrollNextRow():向下滾動一行
列操作
列操作類的函數主要是選擇指定的列和獲取列的信息。
一、獲取列
如果要獲取當前的列號,可以使用GetColumn()函數,如果要獲取當前的列名,可以使用GetColumnName()函數。
語法格式:
dw_control.GetColumn()
dw_control.GetColumnName()
這兩個函數都沒有參數,GetColumn()函數返回一個長整型值,代表當前的列號,GetColumnName()函數返回當前列的列名。如果返回0,表示當前沒有任何列被選擇返回-1表示失敗。
二、設置列
要設置某一列為DataWindow中的當前列,可以使用SetColumn()函數。
語法格式:
dw_control.SetColumn(column)
其中column既可以是列號,也可以是列名。當該函數返回1時表示成功,返回-1時表示失敗。
數據操作
數據操作類的函數主要是對DataWindow中的數據進行獲取、設置。
一、獲取數據
如果要從DataWindow的指定行和列中獲取數據,就要使用GetItem系列的函數。
這個系列的函數共有五個,分別是對字符串、數字、日期、日期時間和小數。
語法格式:
dw_control.GetItemString(rownumber,column)
dw_control.GetItemNumber(rownumber,column)
dw_control.GetItemDate(rownumber,column)
dw_control.GetItemDateTime(rownumber,column)
dw_control.GetItemDecimal(rownumber,column)
其中,rownumber參數表示行號,column可以是列號或列名。
二、設置數據
與獲取數據所用的函數不同,設置DataWindow內指定行列處的數據只要使用一個SetItem()函數就可以了。
語法格式:
dw_control.SetItem(rownumber, column, value)
其中rownumber表示行號,column可以是列號,也可以是列名,value表示要設置的值。但是該必須與DataWindow中指定的行列處的數據類型一致,不然PowerBuilder會報錯。
SetItem()函數返回1時表示成功,返回-1時表示失敗。
三、數據排序
如果希望對DataWindow內的數據進行重新排序,而又不想重新從數據庫中檢索數據,可以使用SetSort()和Sort()函數。這兩個函數一起完成對DataWindow進行排序的功能。其中SetSort()函數用于設置如何排序,Sort()函數用于對DataWindow實際進行排序。
語法格式:
dw_control.SetSort(expression)
dw_control.Sort()
其中expression是一個字符串,表示排序的表達式,它的具體值是一個列名后面加一個空格,然后是"A",表示升序,或"D",表示降序。如果有多個列要同時進行排序,它們之間用逗號隔開。
例:dw_1.SetSort("name A,xh D")
這兩個函數都是返回1表示成功,返回-1表示失敗。
四、數據過濾
如果希望對DataWindow內的數據進行過濾而不重新從數據庫中檢索數據,可以使用SetFilter()和Filter()函數。它們一起完成對數據的過濾功能。其中
SetFilter()函數用來設置過濾條件,Filter()函數用于對DataWindow進行過濾。
語法格式:
dw_control.SetFiter(expression)
dw_control.Fiter()
其中expression是一個字符串,表示過濾的條件,它實際是一個邏輯表達式。
例:
dw_1.SetFilter("id>\'003\' AND name like\'王%\'")
dw_1.Filter()
這兩個函數都是返回1表示成功,返回-1表示失敗。
五、數據檢查
PowerBuilder提供了兩個函數用于數據的檢查,它們是DeleteCount()和ModifiedCount(),其作用分別是檢查DataWindow中的數據自上一次更新到現在,被刪除的行數和被修改的行數。它們一般在窗口的CloseQuery事件中使用,用來檢查該窗口的DataWindow中的數據是否有尚未保存的修改。
語法格式:
dw_control.DeleteCount()
dw.control.ModifiedCount()
它們分別返回從上一次更新到現在,DataWindow中被刪除和被修改的行數。如果沒有行被刪除或被修改,那么它們返回0。如果出現錯誤則返回-1。
一般情況下,如果窗口中含有可供修改的數據窗口對象,那么在窗口的CloseQuery事件中通常使用如下代碼檢查數據窗口對象中是否有尚未保存的數據:
Int li_return
IF dw_1.ModifiedCount() > 0 OR dw_1.DeletedCount() >0 THEN
li_return = MessageBox("提示","數據尚未保存,是否保存?",Question!,YesNoCancel!,3)
CHOOSE CASE li_return
CASE 1
TriggerEvent(\'ue_save\')
RETURN 0
CASE 2
RETURN 0
CASE 3
RETURN 1
END CHOOSE
END IF
1. 怎么判斷數據窗口中指定字段的數據類型?
Dw_1.describe(“colname.coltype”)
返回類型為:string
在實際中有時候可能會有不讓用戶刷新頁面,或者在頁面點右鍵等需求,這里簡單貼一段我在tb項目中用到的js
function document.oncontextmenu(){event.returnValue=false;}//屏蔽鼠標右鍵
function window.onhelp(){return false} //屏蔽F1幫助
function document.onkeydown()
{
if ((window.event.altKey)&&
((window.event.keyCode==37)|| //屏蔽 Alt+ 方向鍵 ←
(window.event.keyCode==39))) //屏蔽 Alt+ 方向鍵 →
{
event.returnValue=false;
}
if ((event.keyCode==116)|| //屏蔽 F5 刷新鍵
(event.ctrlKey && event.keyCode==82)){ //Ctrl + R
event.keyCode=0;
event.returnValue=false;
}
if (event.keyCode==122){event.keyCode=0;event.returnValue=false;} //屏蔽F11
if (event.ctrlKey && event.keyCode==78) event.returnValue=false; //屏蔽 Ctrl+n
if (event.shiftKey && event.keyCode==121)event.returnValue=false; //屏蔽 shift+F10
if (window.event.srcElement.tagName == "A" && window.event.shiftKey)
window.event.returnValue = false; //屏蔽 shift 加鼠標左鍵新開一網頁
}
這里退格鍵沒做屏蔽,因為會用到退格鍵的刪除,如果有需求可以自己加
一個表可以有兩個主鍵的作用:
primary key for table xs ' is not unique :主鍵沖突
首先,那兩個字段都變成了主鍵,這話是不確切的.嚴格的說因為是 你選擇的那兩個字段共同構成了主鍵,也就是 "學生編號+課程編號 "的組合是一個主鍵,這個組合不能夠重復,不能夠同時為空, 而不是 "學生編號 " "課程編號 " 各為一個主鍵,不信你可以查看tb系統表.
表中已有主鍵新增一個主鍵:語句
例如:
alter table AC04_blbc DROP PRIMARY KEY;
alter table AC04_blbc modify sbxz VARCHAR(8) NOT NULL,add constraint PK_AC04_blbc primary key (AAE002, AAC001, AAE041,sbxz);
一年半的時間里,曾小亮兩上八寶山。
送走的第一位好友,是某著名互聯網公司女性頻道的主編,突發腦溢血,去世時年僅37歲。新近送走的是《健康與美容》雜志的主編孟玲和,48歲,開會時突發腦溢血,去世前幾天曾小亮還曾與其徹夜長聊。
從八寶山回來的路上,曾小亮一個人沿著長安街走了好久。這位酒尚出版人助理、情感職場專欄作家、總是為別人調制“心靈雞湯”的人,在那一刻,竟然抑制不住心生強烈的幻滅感。
他忽然間覺得,金錢、地位、名利都不再那么重要,生命、健康與愛,這些我們人生中更具有本源意義,但是長久被忽視的東西,慢慢清晰地浮現出來。
這是“壓力山大”的一代人。嚴重透支身體,恨不能每周7*24小時地工作,在躋身上層、功成名就的路上狂奔。他們的不安全感、焦慮感從某種程度上遠遠超過了父輩。
他們幾乎完整地經歷了中國社會經濟快速發展的三十年,從物質財富的極度匱乏到迅速富裕;同時也見證了恢復高考、計劃生育、打破大鍋飯、企業改制、取消福利分房、中國加入WTO等種種既有秩序的被打破。
當秩序被打破時,總會有人為此付出代價。這一代人身上深深烙上了中國社會經濟發展代際變遷的印記。
35歲老了?
提前來臨的焦慮、無措、迷茫
科銳國際人力資源公司業務總監劉峰前一陣子剛剛接觸了一家叫“豆瓣”的互聯網公司。讓他這個做了十幾年人力資源工作的老“獵頭”有些意外的是,豆瓣公司員工的平均年齡非常小,大概在25歲左右。
大約三年前,劉峰和騰訊的HR有次聊天,讓他印象深刻的是騰訊的“特色”之一“很年輕”。
近十年里,國內一些新晉大公司的出現,像百度、騰訊、阿里巴巴等互聯網巨頭的崛起,帶動了一個大產業,使很多年輕人年紀輕輕就獲得了意想不到的成功。
而且,互聯網等新產業的勃興,正加速著社會對人才的需求和優勝劣汰,也正拉低著職場人群的平均年齡。
互聯網領域里“年輕化”的公司正日益多起來。比如中國第一家女性團購網站“聚美優品”,三個聯合創始人都是80后,一些中層管理者甚至是1989年生人,今年29歲的CEO陳歐一直有個想法,在自己30歲以前把聚美優品做上市。他甚至坦言,在事業快速發展的這幾年,他暫時不會因為結婚這類“家事”把自己限制住。
35歲在某種程度上就意味著職場“生死線”,對許多IT人來說,35歲甚至意味著技術生涯的結束。
現在,對越來越多在職場和事業上打拼的80后來說,29歲就已經臨近“過期”:青春的有效期29歲截止,一到30歲,就會被打上“Timeout”(過期)的印記。
對于那些最早一批進入外資企業“吃螃蟹”的人來說,現在已近人到中年,更是處境尷尬。
一方面由于年齡的原因,不少外企白領在公司的發展遭遇瓶頸,“在我這個年齡和職位,繼續待在外企的話后面的路已經很清楚,升職上遭遇玻璃天花板,年齡上經不起高強度的工作”。
另一方面,不少人由于產業大環境的變化,“金飯碗”的含金量正在加速褪去。
科銳國際早期的客戶源100%都是外資企業;公司成立五六年時,2000年左右,科銳國際開始與包括華為、李寧等在內的本土企業有初步接觸;到2004年、2005年時,公司明確將發展內資企業客戶作為重點,彼時內資企業所占科銳國際客戶源的比例還很低;從2008年、2009年以后,內資企業的業務能占到科銳國際總業務的百分之二三十。“在高科技、互聯網這些行業,外資客戶與內資客戶的比重甚至是四六開。”
劉峰認識很多外資企業的高層或者中層以上的經理,在90年代末或者2000年左右,他們的職業很讓人艷羨,而tb現在職業的“含金量”已經大不如以前。“那時候的外企中高層,買兩套房子很正常,但是你今天進到外企,即使給你八千、一萬塊錢月薪,你什么時候才能買個房子呢?同樣是薪水,含義已經發生了深刻的變化。”
社會經濟的快速發展也讓職場危機提前而至,在發達國家,焦慮、無措、迷茫等中年職場危機的表現通常發生在45~55歲,但是在中國卻提前了近10年。
這是“壓力山大”的一代人。嚴重透支身體,恨不能每周7x24小時地工作,在躋身上層、功成名就的路上狂奔。他們的不安全感、焦慮感從某種程度上遠遠超過了父輩。
退休或重返職場?
參數未知的將來
“退休”,對當下這個人群來說,幾乎是一種奢望。
李強是一家私企的老板,早年做生意賺了幾百萬后覺得足夠將來生活了,便結束了生意,開始安享生活。可是不到十年,他發現生活的發展完全脫離了他預設的軌道。“十年前幾百萬足夠一個人安安穩穩過完一輩子,可是我沒有想到這幾年房價、物價會漲成這樣,現在幾百萬還算個啥。”“安享”計劃泡湯的李強不得不重整旗鼓,再次創業。
劉峰身邊也有朋友有過和李強類似“提前退休”的經歷。這位朋友為了移民加拿大,在事業發展最順風順水的時候,提前結束在中國國內的工作,在加拿大當地隨便找了個工作。待到移民必須的居住時間期滿后,這位朋友想再回中國來發展,卻發現已經錯失了事業發展的最好機會。
對于至少還有些“家底兒”的李強等人來說未來雖然艱難,但還不至于毫無保障,對于更多的中年職場工作者而言未來生活的參數一概未知,這種不確定性和不安全感更加重了這一群體的焦慮。到底有多少資產未來才可以安枕無憂?沒人可以給出一個確切的答案。
20多年前,大學每年的學費只有200元,現在有些專業已經沖上萬元,增長了約50倍。中國青年報社會調查中心曾有一項7625人參與的調查統計稱,盡管78.8%的人認為和十年前相比收入增加了,但是85.3%的人感覺自己的生活負擔比十年前更重了。有人估算了近四十年來中國人結婚的成本:70年代末是600元,80年代是3000元,90年代是3.3萬,21世紀達56.6萬,越來越貴的中國式婚姻。顯而易見的是,中國社會經濟獲得了前所未有的快速發展,但人們的收入增長速度卻遠沒有跑過物價上漲的速度。
“在過去幾十年的發展過程中,一個不可回避的問題就是國家對中層人群,其實沒有好的政策來扶植他們。”劉峰感慨,中層的賦稅很高,高到很嚇人的程度,而另一方面,國家給予這一階層的福利幾乎是零。“比如說我每月交那么多錢的稅,突然有一天失業了,卻發現我什么都沒有,真的是什么都沒有。”
對于這一現狀,資深產業經濟學家白益民認為,日本企業的員工對于未來的焦慮感要比中國低得多,“日本有約定俗成的終身雇傭制以及與其相配合的年功序列制、企業工會。這是日本的三大神器。”白益民介紹,在日本的企業中,企業不會輕易裁員,年功序列制是指工資待遇按員工的資歷慢慢增長,所以一旦進入一個企業,你就可以知道自己未來在這家公司大概享有的工資待遇水準。
長期以來,對于中國是否應該采用終身雇傭制的爭論一直存在,白益民的看法是一些特定的企業可以嘗試這種制度,這對于企業人才的積累、技術的傳承以及員工對生活的安全感都將會有很大的幫助。
異化的人性
“被高速”的一代
曾小亮認為,整個社會在追求經濟高速發展的時候,同時導致了人性的異化。因為人不可能變成一個經濟動物,人有內在的自尊、自我,有對幸福感的追逐,經濟并不能滿足人們更深的快樂。“很多人在有了基本的物質保證之后,就會發現自己開始尋找新的幸福之道。”
“你會發現人們這種心理狀態的變化和經濟發展有一脈相承的地方,特別是在經濟高速發展的時候。”曾小亮注意到,中年階層的這種集體性焦慮和迷茫,曾經出現在美國的上世紀七八十年代,中國臺灣的九十年代。
在中國,一方面是高速發展的經濟環境讓管理人才的職業晉升速度超過了心智成熟度的提升,另一方面是中國長期以來的應試教育過分注重分數,而忽視了心靈的成長,此外對經濟發展的過度追求,也讓這一群體缺乏對生活的整體觀。
“升遷官能癥”在中層人群中就相當普遍。“或是沒有做好準備,或者是能力不夠、提拔太快,被提拔上去以后,會發現很多事情自己沒有能力駕馭了。”曾小亮認為,因為心智的成熟速度趕不上社會角色的提升速度,很多中層人群在職場角色擢升后就會出現各種問題。“跟同事的關系、家庭的問題,突然就會覺得自己扛不住了。我曾經在專欄中提到過,在這個狀態下要學會用一些方法去調試,這就涉及到很多大的課題了。我覺得這跟人才的儲備也有關系,經濟發展太快,人才儲備不夠。”
這種對周遭事物掌控能力的欠缺也極大地加劇了這一人群的焦慮感。
一直以來,中國都推崇GDP增長的神話,認為面臨的首要問題是盡快地發展生產力,提高經濟水平,解除貧困狀態,增強綜合國力。在這種背景下,“GDP崇拜”成為一種普遍情結,唯效率主義或獨尊經濟指數的發展成為主要甚至惟一的取向。片面追求經濟增長也導致了諸多不良的后果,國民教育、就業保障、社會福利、醫療衛生、文化建設等與人民生活質量密切相關的社會領域的發展就被不同程度的犧牲掉了,當置身經濟發展大潮的主流階層人士行至中年才發現自己忽略了身體,忽視了家庭,卻并沒有從過快發展的經濟中獲得多少幸福感,甚至于找不到自己的未來。
近年來,美國、英國等發達國家越來越重視“幸福指數”這一軟指標,美國聯邦政府和英國內閣甚至撥巨資成立專門的研究機構,聘請諾貝爾經濟學獎得主丹尼爾·卡內曼等專家坐鎮,設立衡量人們幸福感的指標,使它與GDP一樣成為衡量一個國家發展水平的標準。
“幸福經濟”越來越成為人們熱議的話題。曾有人發問,如果GDP的增長不能讓人們更幸福,政府為什么還要致力于GDP的增長呢?當下“茫一代”既是推動中國社會經濟高速發展的螞蟻雄兵,也是被經濟高速發展“副作用”所中傷的一代,他們是否幸福、如何才能幸福,是中國社會經濟代際變遷的注腳。
初級測試工程師 :年薪約在2-4萬左右。他們的工作通常是按照測試方案和流程對產品進行功能測試,檢查產品是否有缺陷。 具有一些手工測試經驗,開發測試腳本并開始熟悉測試生存周期和測試技術;
中級測試工程師 :年薪在5-6萬左右。他們要能夠編寫測試文案,測試文檔,與項目組一起制定測試階段的工作計劃。能夠在項目中合理利用測試工具來完成測試任務。能夠獨立編寫自動測試腳本程序并擔任測試編程初期的領導工作,進一步拓展編程語言、操作系統、網絡與數據庫方面的技能;
高級測試工程師 :年薪8-10萬左右。他們不但需要掌握測試與開發技術,而且對所測試軟件對口的行業非常了解,能夠對測試方案可能出現的問題進行分析和評估。幫助開發或維護測試或編程標準與過程,負責同級的評審,并能夠指導初級的測試工程師;
Team Leader(測試主管) :年薪8-15w,一般至少具有5年的工作經驗,負責管理一個小團隊。負責進度安排、工作規模/成本估算、按進度表和預算目標交付產品,負責開發項目的技術方法,能夠為用戶提供支持和演示;
測試經理 :年薪在12-20w,能夠擔當測試領域內的整個開發生存周期業務,能夠為用戶提供交互和大量演示,負責項目成本、進度安排、計劃和人員分工;
計劃經理(或者說測試總監) :年薪20-30w,具有多年純熟的開發與支持(測試/質量保證)活動方面的經驗,管理從事若干項目的人員以及整個開發生存周期,負責把握項目方向和盈虧責任。
----------------------------------------------------------------------------------
0級:
不了解測試方法;
沒有測試計劃和測試樣例,漫無目的測試,靠運氣找BUG;
tb提交BUG的時候描述非常不清楚;
1級:
了解一些測試方法;
有一定的邏輯思考能力;
知道測試重點,了解測試覆蓋率,會設計測試樣例;
提交BUG的時候描述非常清楚,有詳細的BUG重現步驟;
2級:
知道常用測試方法和測試技巧;
有較強邏輯思考能力;
會使用一些自動化測試工具;
有明確的測試計劃和測試重點,設計的測試樣例覆蓋率較高。
提交BUG的時候描述非常清楚,有詳細的重現步驟,規律性以及解決的建議。
3級:
熟悉常用測試方法和測試技巧;
不定期學習新的測試方法和測試技巧;
有很強邏輯思考能力;
會使用一些自動化測試工具;
經常上一些測試論壇和同行交流;
會一種編程語言(特別是shell,python等腳本語言);
有明確的測試計劃和測試重點,設計的測試樣例覆蓋率非常高。
提交BUG的時候描述非常清楚,有詳細的重現步驟,規律性以及解決的建議。