久久久久久亚洲Av无码精品专口,久久综合久久综合亚洲,亚洲综合色婷婷七月丁香http://www.tkk7.com/Victor/category/1602.html享受喧囂 安于平靜zh-cnTue, 27 Feb 2007 10:22:48 GMTTue, 27 Feb 2007 10:22:48 GMT60Java初學者容易混淆的幾個問題http://www.tkk7.com/Victor/articles/23755.htmlVictorVictorWed, 14 Dec 2005 00:59:00 GMThttp://www.tkk7.com/Victor/articles/23755.htmlhttp://www.tkk7.com/Victor/comments/23755.htmlhttp://www.tkk7.com/Victor/articles/23755.html#Feedback0http://www.tkk7.com/Victor/comments/commentRss/23755.htmlhttp://www.tkk7.com/Victor/services/trackbacks/23755.html1.String類和StringBuffer類

  它們都是處理字符串的類,但是它們有一個最大的區別,那就是。

  eg1:





......
//omit some code
String s1="You are hired!";
System.out.println(s1.replace(′h′,′f′));//用f把字串中的h替換了
System.out.println(s1);
......
//omit some code

  運行結果:

   You are fired!
   You are hired!

  結果分析:

  從結果,明顯可知,s1的值并沒有被改變,而第一行結果只是屏幕內容的替換.

  eg2:





......
//omit some code
StringBuffer s2=new StringBuffer("Hello from Java!");
s2.replace(6,10,"to");
System.out.println(s2);
......
//omit some code

  運行結果:

  Hello to Java!

  結果分析:

  顯然,s2的值已改變.
 
  2.位邏輯與條件邏輯

  首先聲明, 為了與位邏輯更好區分開來,我把通常所說的邏輯取了個別名叫做條件邏輯.

  它們都有各自的操作符,位邏輯操作符有:&(與運算),^(異或運算),|(或運算);條件邏輯操作符有:&&(并
且),||(或者)。

  位邏輯運算通常是針對兩個數而言,實行位操作;而條件邏輯運算是針對兩個條件表達式而言,實行條件操作.其實,位邏輯操作符一樣可以實現條件操作,但是此時有一個重要的區別:用位操作符時,不管操作符兩邊的條件表達式成不成立,它都要通通進行運算判斷,而條件邏輯操作符不一樣了,如果通過左側的操作數就可以進行它們需要的判斷,那么它就不會再計算右側的操作數了,這種情況叫短路.廢話少說!且看下例.

  eg1:





......
//omit some code
double value=0;
if(value!=0 && 1/value<1000){
System.out.println("The value is not too small.");
}
else{
System.out.println("The value is too small.");
}
......
//omit some code

  運行結果:

  The value is too small.

  結果分析:

  照理說應會出現除數為0的錯誤,但是我剛才說了,由于條件邏輯操作符是短路操作符,顯然,value!=0不成立,立即就可作出判斷應執行else后的語句,所以它就不再會運算判斷1/value<1000了.如果不懂請再看一
例:

   eg2:





......
//omit some code
double int1=0,int2=1,int3=1;
if(int1!=0 & (int2=2)==1){}
System.out.println("int2="+int2);
if(int1!=0 && (int3=2)==1){}
System.out.println("int3="+int3);
......
//omit some code

  運行結果:

   int2=2.0
   int3=1.0

  結果分析:

  我想不用我分析了,你應該懂了吧.

  3.實例變量與類變量

  可以通過兩種方法在類中存儲數據───作為實例變量和類變量.實例變量是特定于對象的,如果你有兩個對象(即一個類的兩個實例),每一個對象中的實例變量獨立于另一個對象中的實例變量的;另一方面,兩個對象的類變量均指向相同的數據,并因此面保存相同的值,換句話說,類變量被類中的所有對象共享.差點忘了,它們在形式上的區別,類變量在聲明時比實例變量多一個static.

  eg:





class data
{
public int intdata=0;//顯然,intdata在這兒是實例變量
}
public class exam
{
public static void main(String[] args)
{
data a,b;
a=new data();
b=new data();
a.intdata=1;
System.out.println("b.indata="+b.intdata);
}
}

  運行結果:

  b.intdata=0

  結果分析:

  可以看出,a.intdata的值雖然變了,但并沒有影響b.intdata.但是如果在data類中聲明intdata時,在其前面加上static就變成類變量了(即:public static int intdata=0;),則此時運行結果會變為:

  b.intdata=1

  這次a.intdata值的改變可把b.intdata影響了,事實上,對象a和b的類變量均指向相同的數據,所有值一樣,這就是類變量的作用。

4.實例方法,類方法,構造器方法

  我們通常所說的方法系指實例方法,就像c語言中的函數一樣,其具體方法我就不用說了,在這里我主要是用它來區分類方法和構造器方法.類方法與實例方法最大的區別是:在形式上類方法多一個static,在用法上,
不必創建對象就可直接調用類方法(而實例方法卻一定要先創建對象,再通過對象調用)。

  eg:





class add
{
static int addem(int op1,int op2)
{
return op1+op2;
}
}
public class xxf
{
public static void main(String[] args)
{
System.out.println("addem(2,2)="+add.addem(2,2));
} //直接用類名作為對象調用類方法
}

  注: 也可按通常的方法,即先創建對象,再調用方法,不過,這時static就無任何意義了。

  再說說構造器方法,它是用來初始化對象中的數據的一種方法,創建很容易,只需在類中加上一個與這個類同名的方法,不需要在前面加任何訪問說明符或者返回類型,另外,構造器也一樣可以向方法一樣傳遞參數.

  eg:





class data
{
private String data1;//事先聲明

data(String s)
{
data1=s; /*通過接收數據來初始化變量.(注:不能在構造器內
聲明變量,事先在外就要聲明.)*/
}

public String getdata()
{
return data1;
}
}

public class xxf
{
public static void main(String[] args)
{
System.out.println((new data("I love you")).getdata());/*通過傳遞參數調用構造器新建一
個對象,再通過對象調用方法得到數據*/
}
}

  5.接口與類

  類是對一類特定對象的規格說明,我們可以類定義創建對象,通過創建對象來組合所有屬于該類的組件,而接口不能這樣做.而接口實質上就是一個常量和抽象方法的集合,要使用一個接口,就需要在類中實現這個接口,然后作為類定義的一部分,編寫接口中聲明的每一個方法,接口中的方法永遠是public,abstract,接口中的常量永遠是public static和final,因此不需要為它們說明屬性。

  因為在Java中不支持多重繼承,但是,可以用接口來實現類似的功能,這是接口的重要作用之一。

  eg:





interface anyone //定義一個接口
{
final double PI=3.1416;
void setNumber(int number);
int getNumber();
}
interface anyother //定義另一個接口
{
void setString(String str);
String getString();
}

class xxf implement anyone,anyother //定義一個類,并使用兩個接口
{
int number;
String str;
public xxf(){}
void setNumber(int number)
{
this.number=number;
}
void setString(String str)
{
this.str=str;
}
void int getNumber(){}//可以為一個空實現.
void String getString(){}
}
//在類中必須實現接口中聲明的所有方法.(當然也可不必,但是要用到適配器類或用抽象類)


Victor 2005-12-14 08:59 發表評論
]]>
Java讀取XML文件的工具類http://www.tkk7.com/Victor/articles/23104.htmlVictorVictorFri, 09 Dec 2005 03:11:00 GMThttp://www.tkk7.com/Victor/articles/23104.htmlhttp://www.tkk7.com/Victor/comments/23104.htmlhttp://www.tkk7.com/Victor/articles/23104.html#Feedback0http://www.tkk7.com/Victor/comments/commentRss/23104.htmlhttp://www.tkk7.com/Victor/services/trackbacks/23104.html
managers table
 +  service implementation
net.csdn.blog.xport.IDBConnectionManager net.csdn.blog.xport.impl.DBConnectionManagerCommonImpl
net.csdn.blog.xport.IDomainIdentify net.csdn.blog.xport.impl.DomainIdentifyImpl

所以,在程序中,可以用類似Table Query的方式來讀取XML節點(Node)上面的屬性值!

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE managers SYSTEM "manager-config.dtd">
<managers>
<manager name="DBConnectionManager" >
<service>net.csdn.blog.xport.IDBConnectionManager</service>
<implementation>net.csdn.blog.xport.impl.DBConnectionManagerCommonImpl</implementation>
</manager>
<manager name="NTAccountIdendify" >
<service>net.csdn.blog.xport.IDomainIdentify</service>
<implementation>net.csdn.blog.xport.impl.DomainIdentifyImpl</implementation>
</manager>
</managers>

按照下面的代碼讀取:

// 查找以manager作為tag標記,屬性中存在name且屬性值為"DBConnectionManager"的
// XML節點, 并返回此節點的DOM Element對象!
// 類似name字段為PK值,且name="DBConnectionManager"
managerElement
= XMLFileUtil.findElement(xmlDomContent.getRootElement(),
"manager",
"name",
"DBConnectionManager");
if (managerElement != null) {
//取得Element中的implementation屬性對象...
serviceImplElement = managerElement.element("implementation");
if (serviceImplElement != null) {
//取這個屬性的值...
serviceImplClassString = serviceImplElement.getText();
}
}

Source of XML Utility Class:

/*

* @(#)XMLFileUtil.java 1.0 2004/12/20
*
* Copyright 2004 Shark Wang, All rights reserved.

*/

package net.csdn.blog.xport;

import java.net.URL;
import java.util.Iterator;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
* The <code>XmlUtil</code> class supported your code to read/write xml
* data from the file. all methods in this class depend on <code>dom4j</code>.
*
*
@author Shark Wang
*
@version 1.0, 2004/12/20
*
@since Tutorial 1.0
*/

public class XMLFileUtil {

private static Logger logger = LogManager.getLogger(XMLFileUtil.class);

/**
* read xml content from some file, and load xml data into the
* Document object.
*
*
@param filePath String
*
@return Document
*/

public static Document LoadXmlFile(String filePath) {

/* marked by Shark Wang
*****************************************************************
//get resolver to ignore the DTD validation
EntityResolver resolver = new EntityResolver() {
public InputSource resolveEntity(String publicId,
String systemId) {
return new InputSource(new StringBufferInputStream(""));
}
};
//create reader
SAXReader reader = new SAXReader();
//set reader attribute to ignore DTD validation
reader.setEntityResolver(resolver);
reader.setValidation(false);
reader.setIncludeExternalDTDDeclarations(false);
reader.setIncludeInternalDTDDeclarations(false);
*******************************************************************
*/

SAXReader reader =
new SAXReader();
//try to load xml data into Document object
Document doc = null;
try {
String urlString =
null;
if (filePath.startsWith("/")) {
urlString = "file://" + filePath;
}
else {
urlString = "file:///" + filePath;
}
logger.debug("XML File's URL :" + urlString);
doc = reader.read(
new URL(urlString));
}
catch (Exception ex) {
logger.info("Can not load " + filePath);
logger.debug(ex.getMessage(), ex);
}
//return Document object
return doc;
}

/**
* Get attribute value by name for some xml element.
*
*
@param element Element
*
@param attributeName String
*
@return String
*/

public static String getAttributeValue(Element element,
String attributeName) {
String attributeValue =
null;
for (Iterator i = element.attributeIterator(); i.hasNext(); ) {
Attribute attribute = (Attribute) i.next();
if (attribute.getName().equals(attributeName)) {
attributeValue = (String) attribute.getData();
break;
}
}
return attributeValue;
}

public static Element findElement(Element searchedElement,
String targetNodePrefix,
String targetNodeAttributeName,
String targetNodeAttributeValue) {
Element elementTarget =
null;
for (Iterator i = searchedElement.elementIterator(targetNodePrefix);
i.hasNext(); ) {
Element element = (Element) i.next();
String strManagerName =
XMLFileUtil.getAttributeValue(element,
targetNodeAttributeName);
if (strManagerName.equals(targetNodeAttributeValue)) {
elementTarget = element;
break;
}
}
return elementTarget;
}

private XMLFileUtil() {
}
}


Victor 2005-12-09 11:11 發表評論
]]>
JSP中早就有了類似.Net DataSet那樣的離線數據訪問了,拋棄ResultSet,擁抱Result吧! http://www.tkk7.com/Victor/articles/23102.htmlVictorVictorFri, 09 Dec 2005 03:08:00 GMThttp://www.tkk7.com/Victor/articles/23102.htmlhttp://www.tkk7.com/Victor/comments/23102.htmlhttp://www.tkk7.com/Victor/articles/23102.html#Feedback0http://www.tkk7.com/Victor/comments/commentRss/23102.htmlhttp://www.tkk7.com/Victor/services/trackbacks/23102.html微軟的.NET平臺上面的數據訪問有一個特點,就是數據查詢的結果,可以放在內存中,以XML格式進行描述,不需要一直與數據庫保持在線連接,用DataSet + Data Adapter來實現!

而在JDBC中,我們通常使用javax.sql.ResultSet類來存放放回的數據,它的流程和生命周期如下:

使用ResultSet來返回數據庫查詢結果
Client --> Connection --> Statement --> JDBC Driver --+
  Database
Client <-- Parsing <-- ResultSet <-- JDBC Driver --+
               
  Connection lifecycle
   
   
 
  ResultSet lifecycle  
 

我們可以看到,這樣會長期占用數據庫連接的資源,是一個有點不爽的問題...

其實,在JSTL中提供了另外一種機制,讓我們在返回查詢結果到表示層的時候,可以做到離線使用!它就是javax.servlet.jsp.jstl.sql.Result類!

 1 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
2 <%@page contentType="text/html; charset=UTF-8"%>
3 <%@page import="java.sql.Connection"%>
4 <%@page import="java.sql.DriverManager"%>
5 <%@page import="java.sql.ResultSet"%>
6 <%@page import="java.sql.SQLException"%>
7 <%@page import="java.sql.Statement"%>
8 <%@page import="javax.servlet.jsp.jstl.sql.Result"%>
9 <%@page import="javax.servlet.jsp.jstl.sql.ResultSupport"%>
10 <%
11 // 暫且把這個下面的內容看作多層架構中的DAO好了,我偷懶了!
12 Connection conn = null;
13 Statement stmt = null;
14 ResultSet rs = null;
15 String strDbUrl
16 = "jdbc:mysql://localhost/tutorial?user=tutorial&password=tutpwd";
17 try {
18 //開始與數據庫作查詢
19 Class.forName("com.mysql.jdbc.Driver").newInstance();
20 conn = DriverManager.getConnection(strDbUrl);
21 stmt = conn.createStatement();
22 String strSql = "SELECT * FROM R_TUT_USERS";
23 rs = stmt.executeQuery(strSql);
24 //把ResultSet轉化成Result
25 Result userData = ResultSupport.toResult(rs);
26 //當我們把結果放到某個Model bean后,就可以關閉數據庫連接了.
27 //為了簡化,我們暫且把pageContext看作Model Bean好了!
28 pageContext.setAttribute("userData", userData);
29 }
30 catch (Exception ex) {
31 // handle any errors
32 System.out.println("SQLException: " + ex.getMessage());
33 }
34 finally {
35 try {
36 if (rs != null) {
37 rs.close();
38 }
39 if (stmt != null) {
40 stmt.close();
41 }
42 if (conn != null) {
43 conn.close();
44 }
45 }
46 catch (SQLException ex) {
47 System.out.println("SQL Exception: " + ex.getMessage());
48 }
49 }
50 //DAO的邏輯結束
51 %>
52 <html>
53 <head>
54 <title>test</title>
55 </head>
56 <body>
57 <!--// 下面當作是表示層吧 //-->
58 <c:forEach items="${userData.rows}" var="user">
59 <c:out value='${user.name}'/>
60 </c:forEach>
61 </body>
62 </html>


Victor 2005-12-09 11:08 發表評論
]]>
java中文問題詳解(轉)http://www.tkk7.com/Victor/articles/22876.htmlVictorVictorWed, 07 Dec 2005 07:38:00 GMThttp://www.tkk7.com/Victor/articles/22876.htmlhttp://www.tkk7.com/Victor/comments/22876.htmlhttp://www.tkk7.com/Victor/articles/22876.html#Feedback0http://www.tkk7.com/Victor/comments/commentRss/22876.htmlhttp://www.tkk7.com/Victor/services/trackbacks/22876.html預備知識:
 1.字節和unicode
  java內核是unicode的,就連class文件也是,但是很多媒體,包括文件/流的保存方式
  是使用字節流的。 因此java要對這些字節流經行轉化。char是unicode的,而byte是字節.
  java中byte/char互轉的函數在sun.io的包中間有。其中bytetocharconverter類是中調度,
  可以用來告訴你,你用的convertor。其中兩個很常用的靜態函數是
   public static bytetocharconverter getdefault() ;
   public static bytetocharconverter getconverter(string encoding);
  如果你不指定converter,則系統會自動使用當前的encoding,gb平臺上用gbk,en平臺上用
  8859_1
  
  我們來就一個簡單的例子:
     "你"的gb碼是:0xc4e3 ,unicode是0x4f60
     你用:
     --encoding="gb2312";
     --byte b[]={(byte)'\u00c4',(byte)'\u00e3'};
     --convertor=bytetocharconverter.getconverter(encoding);
     --char [] c=converter.convertall(b);
     --for(int i=0;i     --{
     -- system.out.println(integer.tohexstring(c[i]));
     --}
     --打印出來是0x4f60
     --但是如果使用8859_1的編碼,打印出來是
     --0x00c4,0x00e3
     ----例1
     反過來:
     --encoding="gb2312";
        char c[]={'\u4f60'};
        convertor=bytetocharconverter.getconverter(encoding);
     --byte [] b=converter.convertall(c);
     --for(int i=0;i     --{
     -- system.out.println(integer.tohexstring(b[i]));
     --}
      --打印出來是:0xc4,0xe3
      ----例2
      --如果用8859_1就是0x3f,?號,表示無法轉化      --
      很多中文問題就是從這兩個最簡單的類派生出來的。而卻有很多類  
  不直接支持把encoding輸入,這給我們帶來諸多不便。很多程序難得用encoding
  了,直接用default的encoding,這就給我們移植帶來了很多困難
  --
  2.utf-8
  --utf-8是和unicode一一對應的,其實現很簡單
  --
   -- 7位的unicode: 0 _ _ _ _ _ _ _
  --11位的unicode: 1 1 0 _ _ _ _ _ 1 0 _ _ _ _ _ _
  --16位的unicode: 1 1 1 0 _ _ _ _ 1 0 _ _ _ _ _ _ 1 0 _ _ _ _ _ _
  --21位的unicode: 1 1 1 1 0 _ _ _ 1 0 _ _ _ _ _ _ 1 0 _ _ _ _ _ _ 1 0 _ _ _ _ _ _
  --大多數情況是只使用到16位以下的unicode:
  --"你"的gb碼是:0xc4e3 ,unicode是0x4f60
  --我們還是用上面的例子
  --  --例1:0xc4e3的二進制:
  --  --    1 1 0 0 0 1 0 0 1 1 1 0 0 0 1 1
  --  --    由于只有兩位我們按照兩位的編碼來排,但是我們發現這行不通,
  --  --    因為第7位不是0因此,返回"?"
  --  --   
  --  --例2:0x4f60的二進制:
  --  --    0 1 0 0 1 1 1 1 0 1 1 0 0 0 0 0
  --  --    我們用utf-8補齊,變成:
  --  --    11100100 10111101 10100000
  --  --    e4--bd-- a0
  --  --    于是返回0xe4,0xbd,0xa0
  --  --
  3.string和byte[]
  --string其實核心是char[],然而要把byte轉化成string,必須經過編碼。
  --string.length()其實就是char數組的長度,如果使用不同的編碼,很可
  --能會錯分,造成散字和亂碼。
  --例:
  ----byte [] b={(byte)'\u00c4',(byte)'\u00e3'};
  ----string str=new string(b,encoding);  ----
  ----如果encoding=8859_1,會有兩個字,但是encoding=gb2312只有一個字  ----
  --這個問題在處理分頁是經常發生
  4.reader,writer/inputstream,outputstream
  --reader和writer核心是char,inputstream和outputstream核心是byte。
  --但是reader和writer的主要目的是要把char讀/寫inputstream/outputstream
--一個reader的例子:
--文件test.txt只有一個"你"字,0xc4,0xe3--
--string encoding=;
--inputstreamreader reader=new inputstreamreader(
----new fileinputstream("text.txt"),encoding);
--char []c=new char[10];
--int length=reader.read(c);
--for(int i=0;i----system.out.println(c[i]);
  --如果encoding是gb2312,則只有一個字符,如果encoding=8859_1,則有兩個字符
  --------
--
--
  
   ----
 2.我們要對java的編譯器有所了解:
 --javac -encoding
  我們常常沒有用到encoding這個參數。其實encoding這個參數對于跨平臺的操作是很重要的。
  如果沒有指定encoding,則按照系統的默認encoding,gb平臺上是gb2312,英文平臺上是iso8859_1。 
 --java的編譯器實際上是調用sun.tools.javac.main的類,對文件進行編譯,這個類 --
 有compile函數中間有一個encoding的變量,-encoding的參數其實直接傳給encoding變量。
 編譯器就是根據這個變量來讀取java文件的,然后把用utf-8形式編譯成class文件。
 一個例子:
 --public void test()
 --{
 ----string str="你";
 ----filewriter write=new filewriter("test.txt");
 ----write.write(str);
 ----write.close();
 --}
 ----例3
--如果用gb2312編譯,你會找到e4 bd a0的字段
--
--如果用8859_1編譯,
--00c4 00e3的二進制:
--00000000 11000100 00000000 11100011--
--因為每個字符都大于7位,因此用11位編碼:
--11000001 10000100 11000011 10100011
--c1-- 84-- c3--  a3
--你會找到c1 84 c3 a3 --
    
  但是我們往往忽略掉這個參數,因此這樣往往會有跨平臺的問題:
  --  例3在中文平臺上編譯,生成zhclass
  --  例3在英文平臺上編譯,輸出enclass
  --1.  zhclass在中文平臺上執行ok,但是在英文平臺上不行
  --2.  enclass在英文平臺上執行ok,但是在中文平臺上不行
  原因:
 --1.在中文平臺上編譯后,其實str在運行態的char[]是0x4f60, ----
 --在中文平臺上運行,filewriter的缺省編碼是gb2312,因此
 --chartobyteconverter會自動用調用gb2312的converter,把str轉化
 --成byte輸入到fileoutputstream中,于是0xc4,0xe3放進了文件。
 --但是如果是在英文平臺下,chartobyteconverter的缺省值是8859_1,
 --filewriter會自動調用8859_1去轉化str,但是他無法解釋,因此他會
 --輸出"?" ----
 --2. 在英文平臺上編譯后,其實str在運行態的char[]是0x00c4 0x00e3, ----
 --在中文平臺上運行,中文無法識別,因此會出現??
 --  在英文平臺上,0x00c4-->0xc4,0x00e3->0xe3,因此0xc4,0xe3被放進了
 --文件
----
1.對于jsp正文的解釋:
--tomcat首先看一下你的葉面中有沒有"


http://localhost/test/test.jsp?value=你

結果:你好你

但這種方法局限性較大,比如對上傳的文章分段,這樣的做法是死定的,最好的
解決方案是用這種方案:


你好



必讀好文,但解決方案不敢恭維
發言者:小熊
時 間:2000/10/17 17:21:31 來 自:www.javaunion.org


--------------------------------------------------------------------------------

1.網頁傳參數不提倡用get方法,而且用戶可以調整是否用utf-8發送
2.建議jsp中最好不要用,實際上加不加這句都有實現中文正常顯示的方案,我認為不加方便些,至少不用寫這些代碼,如下的配置我認為可以使中文正常顯示:
a.所有的javabean用iso8859-1編譯
b.jsp文件中不要寫以上charset=gb2312的語句(寫了反而錯)

在tomcat情況下注意以上2點就行---了,等等,對于其他有可能不行的jsp服務器,加上以下
c.服務器上的操作系統語言設為英文(像沒有裝類似bluepoint中文系統的linux一般本來就是英文)
就行---了

誰要是還不對,請報告....


re:必讀好文,但解決方案不敢恭維
發言者:congling
時 間:2000/10/17 21:06:23 來 自:www.javaunion.org


--------------------------------------------------------------------------------

tomcat的參數問題無論是get或是post方式都是用8859_1編碼的。這個可以看tomcat servlet實現的源代碼:
a) 對于post方法
 javax.servlet.http.httputils的parsepostdata方法: (對于post的form數據)
 string postedbody = new string(postedbytes, 0, len, "8859_1");)這里是沒有問題的因為中文都會用%來說明。但是parsename這個函數,卻沒有把是中文的東西整合起來,他只是簡單的拼湊,因此可以認定他是使用8859_1的編碼規則
  sb.append((char) integer.parseint(s.substring(i+1, i+3), 16));
----  i += 2;
--
b) 對于get方法
 org.apache.tomcat.service.http.httprequestadapter
   -- line=new string(buf, 0, count,
       constants.characterencoding.default);
----constants.characterencoding.default=8859_1
 這段代碼不好跟蹤,千萬不要被一些假象迷惑住。httprequestadapter是從requestimpl中派生的。但是,實際上用8080端口的server并沒有直接用到requestimpl,而是用了httprequestadapter來獲得querystring

對于加不加encoding,我保留我的意見,因為如果要解決上傳文件分頁問題,必須要用他來編碼。而且編碼能保證在一些beans當中的傳遞性。

看來我要在這里說明一下了
發言者:小熊
時 間:1970/01/01 07:59:59 來 自:www.javaunion.org


--------------------------------------------------------------------------------

tomcat僅僅是一個對jsp1.1,servlet2.2的一個標準的實現,我們不應該要求這個免費軟件在細致末節上和性能上都面面俱到,它主要考慮的英文用戶,這也是為什么不作特殊轉換我們的漢字用url方法傳遞有問題的原因,我們大部分瀏覽器ie其高級設置中始終以utf-8發送url的選項缺省是選上的,如果說這是tomcat的bug也是可以的,另外tomcat不管當前的操作系統是什么語言,好像都按iso8859去編譯jsp,我覺得也有點欠妥,但是不管怎么說,新標準的實現和熱門的軟件在語言的支持方面永遠都是先考慮英文

我的方案什么說要好一些呢
1.還是那句話,英文國家的軟件永遠都是先考慮英文,java虛擬機的規范中要求虛擬機內部必須實現iso8859,unicode,utf-8三種,其他的不作要求,我們用的jdk中的虛擬機就是這樣,嵌入式的就更不用說了,也就是說其他的encode都很可能不是java虛擬機內部直接支持的,我們的中文自然也不在其列,需要外部的包支持轉換,sun jdk應該在i18n.jar中,用iso8859速度最快,不需要其它調用和交換什么的,更沒有讀包的io操作
2.至少少寫了代碼,沒有額外操作,簡潔的風格誰不喜歡
3.所寫的jsp頁面國際性化好,我才寫了一個jsp+javabeans的聊天室軟件(沒有用到servlet,jsp真的確實很好),同樣的程序美國人用他們的瀏覽器進入就是英文界面,中文進入就是中文界面,如果加上charset=gb2312至少很麻煩
4.限定了gb2312,如果用戶要用gbk,怎么辦,不加更好,不管什么的字符集,只要我當前瀏覽器設定的是,我就能顯示出來

總結:無論從速度上,開發效率上,和可擴展性上考慮,我的方案都比你的好,另外,我找不到你的方案比我的好的地方

中華技術網整理發布 http://www.asfocus.com


Victor 2005-12-07 15:38 發表評論
]]>
最安全的加密算法 (摘自溫少的blog)http://www.tkk7.com/Victor/articles/21922.htmlVictorVictorWed, 30 Nov 2005 02:50:00 GMThttp://www.tkk7.com/Victor/articles/21922.htmlhttp://www.tkk7.com/Victor/comments/21922.htmlhttp://www.tkk7.com/Victor/articles/21922.html#Feedback0http://www.tkk7.com/Victor/comments/commentRss/21922.htmlhttp://www.tkk7.com/Victor/services/trackbacks/21922.html
one-time pad的算法有以下要求:
1、密鑰必須隨機產生
2、密鑰不能重復使用
3、密鑰和密文的長度是一樣的。

one-time pad是最安全的加密算法,雙方一旦安全交換了密鑰,之后交換信息的過程就是絕對安全的啦。這種算法一直在一些要求高度機密的場合使用,據說美國和前蘇聯之間的熱線電話、前蘇聯的間諜都是使用One-time pad的方式加密的。不管超級計算機工作多久,也不管多少人,用什么方法和技術,具有多大的計算能力,都不可能破解。

一次一密的一種實現方式,如下:
public class OneTimePadUtil {
    
public static byte[] xor(byte[] bytes, byte[] keyBytes) {
        
if (keyBytes.length != bytes.length) {
            
throw new IllegalArgumentException();
        }


        
byte[] resultBytes = new byte[bytes.length];

        
for (int i = 0; i < resultBytes.length; ++i) {
            resultBytes[i] 
= (byte) (keyBytes[i] ^ bytes[i]);
        }


        
return resultBytes;
    }

}

使用例子:
String plainText = "溫少";
String keyText 
= "密碼";

byte[] plainBytes = plainText.getBytes();
byte[] keyBytes = keyText.getBytes();

assert plainBytes.length 
== keyBytes.length;

//加密
byte[] cipherBytes = OneTimePadUtil.xor(plainBytes, keyBytes);

//解密
byte[] cipherPlainBytes = OneTimePadUtil.xor(cipherBytes, keyBytes);


這是最簡單的加密算法,但也是最安全的機密算法。前天和朋友討論到了這個問題,所以寫了這篇文章。



Victor 2005-11-30 10:50 發表評論
]]>
JSP編程進度條設計實例(轉)http://www.tkk7.com/Victor/articles/6293.htmlVictorVictorFri, 17 Jun 2005 07:44:00 GMThttp://www.tkk7.com/Victor/articles/6293.htmlhttp://www.tkk7.com/Victor/comments/6293.htmlhttp://www.tkk7.com/Victor/articles/6293.html#Feedback0http://www.tkk7.com/Victor/comments/commentRss/6293.htmlhttp://www.tkk7.com/Victor/services/trackbacks/6293.htmlXML處理等,雖然這些任務主要由數據庫系統或中間件完成,但任務執行的結果仍舊要借助JSP才能發送給用戶。本文介紹了一種通過改進前端表現層來改善用戶感覺、減輕服務器負載的辦法。

  當JSP調用一個必須長時間運行的操作,且該操作的結果不能(在服務器端)緩沖,用戶每次請求該頁面時都必須長時間等待。很多時候,用戶會失去耐心,接著嘗試點擊瀏覽器的刷新按鈕,最終失望地離開。

  本文介紹的技術是把繁重的計算任務分離開來,由一個獨立的線程運行,從而解決上述問題。當用戶調用JSP頁面時,JSP頁面會立即返回,并提示用戶任務已經啟動且正在執行JSP頁面自動刷新自己,報告在獨立線程中運行的繁重計算任務的當前進度,直至任務完成。

一、模擬任務

  首先我們設計一個TaskBean類,它實現java.lang.Runnable接口,其run()方法在一個由JSP頁面(start.jsp)啟動的獨立線程中運行。終止run()方法執行由另一個JSP頁面stop.jsp負責。TaskBean類還實現了java.io.Serializable接口,這樣JSP頁面就可以將它作為JavaBean調用:
package test.barBean;
import java.io.Serializable;


public class TaskBean implements Runnable, Serializable {
private int counter;
private int sum;
private boolean started;
private boolean running;
private int sleep;


public TaskBean() {
counter = 0;
sum = 0;
started = false;
running = false;
sleep = 100;
}
}


  TaskBean包含的“繁重任務”是計算1+2+3…+100的值,不過它不通過100*(100+1)/2=5050公式計算,而是由run()方法調用work()方法100次完成計算。work()方法的代碼如下所示,其中調用Thread.sleep()是為了確保任務總耗時約10秒。


protected void work() {
try {
Thread.sleep(sleep);
counter++;
sum += counter;
} catch (InterruptedException e) {
setRunning(false);
}
}

  status.jsp頁面通過調用下面的getPercent()方法獲得任務的完成狀況:


public synchronized int getPercent() {
return counter;
}

如果任務已經啟動,isStarted()方法將返回true:

public synchronized boolean isStarted() {
return started;
}


  如果任務已經完成,isCompleted()方法將返回true:


public synchronized boolean isCompleted() {
return counter == 100;
}


  如果任務正在運行,isRunning()方法將返回true:


public synchronized boolean isRunning() {
return running;
}



  SetRunning()方法由start.jsp或stop.jsp調用,當running參數是true時。SetRunning()方法還要將任務標記為“已經啟動”。調用setRunning(false)表示要求run()方法停止執行。


public synchronized void setRunning(boolean running) {
this.running = running;
if (running)
started = true;
}

  任務執行完畢后,調用getResult()方法返回計算結果如果任務尚未執行完畢,它返回null:


public synchronized Object getResult() {
if (isCompleted())
return new Integer(sum);
else
return null;
}

  當running標記為true、completed標記為false時,run()方法調用work()。在實際應用中,run()方法也許要執行復雜的SQL查詢、解析大型XML文檔,或者調用消耗大量CPU時間的EJB方法。注意“繁重的任務”可能要在遠程服務器上執行。報告結果的JSP頁面有兩種選擇:或者等待任務結束,或者使用一個進度條。


public void run() {
try {
setRunning(true);
while (isRunning() && !isCompleted())
work();
} finally {
setRunning(false);
}
}

二、啟動任務


  start.jsp是web.xml部署描述符中聲明的歡迎頁面,web.xml的內容是:


<?xml version="1.0" encoding="GB2312"?>


<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">


<web-app>
<welcome-file-list>
<welcome-file>start.jsp</welcome-file>
</welcome-file-list>
</web-app>


  start.jsp啟動一個專用的線程來運行“繁重的任務”,然后把HTTP請求傳遞給status.jsp。


  start.jsp頁面利用<jsp:useBean>標記創建一個TaskBean的實例,將scope屬性定義為session使得對于來自同一瀏覽器的HTTP請求,其他頁面也能提取到同一個Bean對象。start.jsp通過調用session.removeAttribute("task")確保<jsp:useBean>創建了一個新的Bean對象,而不是提取一個舊對象(例如,同一個用戶會話中更早的JSP頁面所創建的Bean對象)。


  下面是start.jsp頁面的代碼清單:


<% session.removeAttribute("task"); %>


<jsp:useBean id="task" scope="session"
class="test.barBean.TaskBean"/>


<% task.setRunning(true); %>
<% new Thread(task).start(); %>
<jsp:forward page="status.jsp"/>

  start.jsp創建并設置好TaskBean對象之后,接著創建一個Thread,并將Bean對象作為一個Runnable實例傳入。調用start()方法時新創建的線程將執行TaskBean對象的run()方法。


  現在有兩個線程在并發執行:執行JSP頁面的線程(稱之為“JSP線程”),由JSP頁面創建的線程(稱之為“任務線程”)。接下來,start.jsp利用調用status.jsp,status.jsp顯示出進度條以及任務的執行情況。注意status.jsp和start.jsp在同一個JSP線程中運行。


  start.jsp在創建線程之前就把TaskBean的running標記設置成了true,這樣,即使當JSP線程已開始執行status.jsp而任務線程的run()方法尚未啟動,也能夠確保用戶會得到“任務已開始運行”的狀態報告。


  將running標記設置成true、啟動任務線程這兩行代碼可以移入TaskBean構成一個新的方法,然后由JSP頁面調用這個新方法。一般而言,JSP頁面應當盡量少用Java代碼,即我們應當盡可能地把Java代碼放入Java類。不過本例中我們不遵從這一規則,把new Thread(task).start()直接放入start.jsp突出表明JSP線程創建并啟動了任務線程。


  在JSP頁面中操作多線程必須謹慎,注意JSP線程和其他線程實際上是并發執行的,就象在桌面應用程序中,我們用一個線程來處理GUI事件,另外再用一個或多個線程來處理后臺任務。不過在JSP環境中,考慮到多個用戶同時請求某一個頁面的情況,同一個JSP頁面可能會在多個線程中同時運行另外,有時同一個用戶可能會向同一個頁面發出多個請求,雖然這些請求來自同一個用戶,它們也會導致服務器同時運行一個JSP頁面的多個線程。

三、任務進度

  status.jsp頁面利用一個HTML進度條向用戶顯示任務的執行情況。首先,status.jsp利用<jsp:useBean>標記獲得start.jsp頁面創建的Bean對象:


<jsp:useBean id="task" scope="session"
class="test.barBean.TaskBean"/>


  為了及時反映任務執行進度,status.jsp會自動刷新。JavaScript代碼setTimeout("location='status.jsp'", 1000)將每隔1000毫秒刷新頁面,重新請求status.jsp,不需要用戶干預。


<HTML>


<HEAD>
<TITLE>JSP進度條</TITLE>
<% if (task.isRunning()) { %>
<SCRIPT LANGUAGE="JavaScript">
setTimeout("location='status.jsp'", 1000);
</SCRIPT>
<% } %>
</HEAD>


<ODY>


  進度條實際上是一個HTML表格,包含10個單元——即每個單元代表任務總體的10%進度。


<H1 ALIGN="CENTER">JSP進度條</H1>


<H2 ALIGN="CENTER">
結果: <%= task.getResult() %><BR>
<% int percent = task.getPercent(); %>
<%= percent %>%
</H2>


<TABLE WIDTH="60%" ALIGN="CENTER"
BORDER=1 CELLPADDING=0 CELLSPACING=2>
<TR>
<% for (int i = 10; i <= percent; i += 10) { %>
<TD WIDTH="10%" BGCOLOR="#000080">&nbsp;</TD>
<% } %>
<% for (int i = 100; i > percent; i -= 10) { %>
<TD WIDTH="10%">&nbsp;</TD>
<% } %>
</TR>
</TABLE>

  任務執行情況分下面幾種狀態:正在執行,已完成,尚未開始,已停止:


<TABLE WIDTH="100%" BORDER=0 CELLPADDING=0 CELLSPACING=0>
<TR>
<TD ALIGN="CENTER">
<% if (task.isRunning()) { %>
正在執行
<% } else { %>
<% if (task.isCompleted()) { %>
完成
<% } else if (!task.isStarted()) { %>
尚未開始
<% } else { %>
已停止
<% } %>
<% } %>
</TD>
</TR>

頁面底部提供了一個按鈕,用戶可以用它來停止或重新啟動任務:


<TR>
<TD ALIGN="CENTER">
<BR>
<% if (task.isRunning()) { %>
<FORM METHOD="GET" ACTION="stop.jsp">
<INPUT TYPE="SUBMIT" VALUE="停止">
</FORM>
<% } else { %>
<FORM METHOD="GET" ACTION="start.jsp">
<INPUT TYPE="SUBMIT" VALUE="開始">
</FORM>
<% } %>
</TD>
</TR>
</TABLE>
</BODY></HTML>


  只要不停止任務,約10秒后瀏覽器將顯示出計算結果5050:


  四、停止任務


  stop.jsp頁面把running標記設置成false,從而停止當前的計算任務:


<jsp:useBean id="task" scope="session"
class="test.barBean.TaskBean"/>


<% task.setRunning(false); %>
<jsp:forward page="status.jsp"/>

  注意最早的Java版本提供了Thread.stop方法,但JDK從1.2版開始已經不贊成使用Thread.stop方法,所以我們不能直接調用Thread.stop()。


  第一次運行本文程序的時候,你會看到任務的啟動有點延遲同樣地,第一次點擊“停止”按鈕時也可以看到任務并沒有立即停止運行(特別是如果機器配置較低的話,延遲的感覺更加明顯),這些延遲都是由于編譯JSP頁面導致的。編譯好JSP頁面之后,應答速度就要快多了。


  五、實際應用


  進度條不僅使得用戶界面更加友好,而且對服務器的性能也有好處,因為進度條會不斷地告訴用戶當前的執行進度,用戶不會再頻繁地停止并重新啟動(刷新)當前的任務。另一方面,創建單獨的線程來執行后臺任務也會消耗不少資源,必要時可考慮通過一個線程池來實現Thread對象的重用。另外,頻繁地刷新進度頁面也增加了網絡通信開銷,所以務必保持進度頁面簡潔短小。


  在實際應用中,后臺執行的繁重任務可能不允許停止,或者它不能提供詳細的執行進度數據。例如,查找或更新關系數據庫時,SQL命令執行期間不允許中途停止——不過如果用戶表示他想要停止或中止任務,程序可以在SQL命令執行完畢后回退事務。


  解析XML文檔的時候,我們沒有辦法獲知已解析內容精確的百分比。如果用DOM解析XML文檔,直到解析完成后才得到整個文檔樹如果用SAX,雖然可以知道當前解析的內容,但通常不能確定還有多少內容需要解析。在這些場合,任務的執行進度只能靠估計得到。


  估計一個任務需要多少執行時間通常是很困難的,因為它涉及到許多因素,即使用實際測試的辦法也無法得到可靠的結論,因為服務器的負載隨時都在變化之中。一種簡單的辦法是測量任務每次執行所需時間,然后根據最后幾次執行的平均時間估算。如果要提高估計時間的精確度,應當考慮實現一種針對應用特點的算法,綜合考慮多種因素,例如要執行的SQL語句類型、要解析的XML模式的復雜程度,等等。


  結束語:本文例子顯示出用JSPJavaHTMLJavaScript構造進度條是相當容易的,真正困難的是如何將它用到實際應用之中,特別是獲得后臺任務的進度信息,但這個問題沒有通用的答案,每一種后臺執行的任務都有它自己的特點,必須按照具體情況具體分析。




Victor 2005-06-17 15:44 發表評論
]]>
Java 編程技術中漢字問題的分析及解決(轉)http://www.tkk7.com/Victor/articles/5553.htmlVictorVictorSat, 04 Jun 2005 03:44:00 GMThttp://www.tkk7.com/Victor/articles/5553.htmlhttp://www.tkk7.com/Victor/comments/5553.htmlhttp://www.tkk7.com/Victor/articles/5553.html#Feedback0http://www.tkk7.com/Victor/comments/commentRss/5553.htmlhttp://www.tkk7.com/Victor/services/trackbacks/5553.html

段明輝
自由撰稿人
2000 年 11月 8日


在基于 Java 語言的編程中,我們經常碰到漢字的處理及顯示的問題。一大堆看不懂的亂碼肯定不是我們愿意看到的顯示效果,怎樣才能夠讓那些漢字正確顯示呢?Java 語言默認的編碼方式是UNICODE ,而我們中國人通常使用的文件和數據庫都是基于 GB2312 或者 BIG5 等方式編碼的,怎樣才能夠恰當地選擇漢字編碼方式并正確地處理漢字的編碼呢?本文將從漢字編碼的常識入手,結合 Java 編程實例,分析以上兩個問題并提出解決它們的方案。



現在 Java 編程語言已經廣泛應用于互聯網世界,早在 Sun 公司開發 Java 語言的時候,就已經考慮到對非英文字符的支持了。Sun 公司公布的 Java 運行環境(JRE)本身就分英文版和國際版,但只有國際版才支持非英文字符。不過在 Java 編程語言的應用中,對中文字符的支持并非如同 Java Soft 的標準規范中所宣稱的那樣完美,因為中文字符集不只一個,而且不同的操作系統對中文字符的支持也不盡相同,所以會有許多和漢字編碼處理有關的問題在我們進行應用開發中困擾著我們。有很多關于這些問題的解答,但都比較瑣碎,并不能夠滿足大家迫切解決問題的愿望,關于 Java 中文問題的系統研究并不多,本文從漢字編碼常識出發,分析 Java 中文問題,希望對大家解決這個問題有所幫助。

漢字編碼的常識

我們知道,英文字符一般是以一個字節來表示的,最常用的編碼方法是 ASCII 。但一個字節最多只能區分256個字符,而漢字成千上萬,所以現在都以雙字節來表示漢字,為了能夠與英文字符分開,每個字節的最高位一定為1,這樣雙字節最多可以表示64K格字符。我們經常碰到的編碼方式有 GB2312、BIG5、UNICODE 等。關于具體編碼方式的詳細資料,有興趣的讀者可以查閱相關資料。我膚淺談一下和我們關系密切的 GB2312 和 UNICODE。GB2312 碼,中華人民共和國國家標準漢字信息交換用編碼,是一個由中華人民共和國國家標準總局發布的關于簡化漢字的編碼,通行于中國大陸地區及新加坡,簡稱國標碼。兩個字節中,第一個字節(高字節)的值為區號值加32(20H),第二個字節(低字節)的值為位號值加32(20H),用這兩個值來表示一個漢字的編碼。UNICODE 碼是微軟提出的解決多國字符問題的多字節等長編碼,它對英文字符采取前面加“0”字節的策略實現等長兼容。如 “A” 的 ASCII 碼為0x41,UNICODE 就為0x00,0x41。利用特殊的工具各種編碼之間可以互相轉換。

Java 中文問題的初步認識

我們基于 Java 編程語言進行應用開發時,不可避免地要處理中文。Java 編程語言默認的編碼方式是 UNICODE,而我們通常使用的數據庫及文件都是基于 GB2312 編碼的,我們經常碰到這樣的情況:瀏覽基于 JSP 技術的網站看到的是亂碼,文件打開后看到的也是亂碼,被 Java 修改過的數據庫的內容在別的場合應用時無法繼續正確地提供信息。

String sEnglish = “apple”;

String sChinese = “蘋果”;

String s = “蘋果 apple ”;

sEnglish 的長度是5,sChinese的長度是4,而 s 默認的長度是14。對于 sEnglish來說, Java 中的各個類都支持得非常好,肯定能夠正確顯示。但對于 sChinese 和 s 來說,雖然 Java Soft 聲明 Java 的基本類已經考慮到對多國字符的支持(默認 UNICODE 編碼),但是如果操作系統的默認編碼不是 UNICODE ,而是國標碼等。從 Java 源代碼到得到正確的結果,要經過 “Java 源代碼-> Java 字節碼-> ;虛擬機->操作系統->顯示設備”的過程。在上述過程中的每一步驟,我們都必須正確地處理漢字的編碼,才能夠使最終的顯示結果正確。

“ Java 源代碼-> Java 字節碼”,標準的 Java 編譯器 javac 使用的字符集是系統默認的字符集,比如在中文 Windows 操作系統上就是 GBK ,而在 Linux 操作系統上就是ISO-8859-1,所以大家會發現在 Linux 操作系統上編譯的類中源文件中的中文字符都出了問題,解決的辦法就是在編譯的時候添加 encoding 參數,這樣才能夠與平臺無關。用法是

javac –encoding GBK。

“ Java 字節碼->虛擬機->操作系統”, Java 運行環境 (JRE) 分英文版和國際版,但只有國際版才支持非英文字符。 Java 開發工具包 (JDK) 肯定支持多國字符,但并非所有的計算機用戶都安裝了 JDK 。很多操作系統及應用軟件為了能夠更好的支持 Java ,都內嵌了 JRE 的國際版本,為自己支持多國字符提供了方便。

“操作系統->顯示設備”,對于漢字來說,操作系統必須支持并能夠顯示它。英文操作系統如果不搭配特殊的應用軟件的話,是肯定不能夠顯示中文的。

還有一個問題,就是在 Java 編程過程中,對中文字符進行正確的編碼轉換。例如,向網頁輸出中文字符串的時候,不論你是用

out.println(string);還是用

<%=string%>,都必須作 UNICODE 到 GBK 的轉換,或者手動,或者自動。在 JSP 1.0中,可以定義輸出字符集,從而實現內碼的自動轉換。用法是

<%@page contentType=”text/html;charset=gb2312” %>

但是在一些 JSP 版本中并沒有提供對輸出字符集的支持,(例如 JSP 0.92),這就需要手動編碼輸出了,方法非常多。最常用的方法是

String s1 = request.getParameter(“keyword”);

String s2 = new String(s1.getBytes(“ISO-8859-1”),”GBK”);

getBytes 方法用于將中文字符以“ISO-8859-1”編碼方式轉化成字節數組,而“GBK” 是目標編碼方式。我們從以ISO-8859-1方式編碼的數據庫中讀出中文字符串 s1 ,經過上述轉換過程,在支持 GBK 字符集的操作系統和應用軟件中就能夠正確顯示中文字符串 s2 。

Java 中文問題的表層分析及處理

背景

開發環境

JDK1.15

Vcafe2.0

JPadPro

服務器端

NT IIS

Sybase System

Jconnect(JDBC)

客戶端

IE5.0

Pwin98

?span >

.CLASS 文件存放在服務器端,由客戶端的瀏覽器運行 APPLET , APPLET 只起調入 FRAME 類等主程序的作用。界面包括 Textfield ,TextArea,List,Choice 等。

I.用 JDBC 執行 SELECT 語句從服務器端讀取數據(中文)后,將數據用 APPEND 方法加到 TextArea(TA) ,不能正確顯示。但加到 List 中時,大部分漢字卻可正確顯示。

將數據按“ISO-8859-1” 編碼方式轉化為字節數組,再按系統缺省編碼方式 (Default Character Encoding) 轉化為 STRING ,即可在 TA 和 List 中正確顯示。

程序段如下:

dbstr2 = results.getString(1);

//After reading the result from DB server,converting it to string.

dbbyte1 = dbstr2.getBytes(“iso-8859-1”);

dbstr1 = new String(dbbyte1);

在轉換字符串時不采用系統默認編碼方式,而直接采用“ GBK” 或者 “GB2312” ,在 A 和 B 兩種情況下,從數據庫取數據都沒有問題。

II.處理方式與“取中文”相逆,先將 SQL 語句按系統缺省編碼方式轉化為字節數組,再按“ISO-8859-1”編碼方式轉化為 STRING ,最后送去執行,則中文信息可正確寫入數據庫。

程序段如下:

sqlstmt = tf_input.getText();

//Before sending statement to DB server,converting it to sql statement.

dbbyte1 = sqlstmt.getBytes();

sqlstmt = newString(dbbyte1,”iso-8859-1”);

_stmt = _con.createStatement();

_stmt.executeUpdate(sqlstmt);

……

問題:如果客戶機上存在 CLASSPATH 指向 JDK 的 CLASSES.ZIP 時(稱為 A 情況),上述程序代碼可正確執行。但是如果客戶機只有瀏覽器,而沒有 JDK 和 CLASSPATH 時(稱為 B 情況),則漢字無法正確轉換。

我們的分析:

1.經過測試,在 A 情況下,程序運行時系統的缺省編碼方式為 GBK 或者 GB2312 。在 B 情況下,程序啟動時瀏覽器的 JAVA 控制臺中出現如下錯誤信息:

Can't find resource for sun.awt.windows.awtLocalization_zh_CN

然后系統的缺省編碼方式為“8859-1”。

2.如果在轉換字符串時不采用系統缺省編碼方式,而是直接采用 “GBK” 或“GB2312”,則在 A 情況下程序仍然可正常運行,在 B 情況下,系統出現錯誤:

UnsupportedEncodingException。

3.在客戶機上,把 JDK 的 CLASSES.ZIP 解壓后,放在另一個目錄中, CLASSPATH 只包含該目錄。然后一邊逐步刪除該目錄中的 .CLASS 文件,另一邊運行測試程序,最后發現在一千多個 CLASS 文件中,只有一個是必不可少的,該文件是:

sun.io.CharToByteDoubleByte.class。

將該文件拷到服務器端和其它的類放在一起,并在程序的開頭 IMPORT 它,在 B 情況下程序仍然無法正常運行。

4.在 A 情況下,如果在 CLASSPTH 中去掉 sun.io.CharToByteDoubleByte.class ,則程序運行時測得默認編碼方式為“8859-1”,否則為 “GBK” 或 “GB2312” 。

如果 JDK 的版本為1.2以上的話,在 B 情況下遇到的問題得到了很好的解決,測試的步驟同上,有興趣的讀者可以嘗試一下。

Java 中文問題的根源分析及解決

在簡體中文 MS Windows 98 + JDK 1.3 下,可以用 System.getProperties() 得到 Java 運行環境的一些基本屬性,類 PoorChinese 可以幫助我們得到這些屬性。

類 PoorChinese 的源代碼:

public class PoorChinese {

}

執行 java PoorChinese 后,我們會得到:

系統變量 file.encoding 的值為 GBK ,user.language 的值為 zh , user.region 的值為 CN ,這些系統變量的值決定了系統默認的編碼方式是 GBK 。

在上述系統中,下面的代碼將 GB2312 文件轉換成 Big5 文件,它們能夠幫助我們理解 Java 中漢字編碼的轉化:

?

import java.io.*;

import java.util.*;

?

public class gb2big5 {

?

static int iCharNum=0;

?

public static void main(String[] args) {

System.out.println("Input GB2312 file, output Big5 file.");

if (args.length!=2) {

System.err.println("Usage: jview gb2big5 gbfile big5file");

System.exit(1);

String inputString = readInput(args[0]);

writeOutput(inputString,args[1]);

System.out.println("Number of Characters in file: "+iCharNum+".");

}

?

static void writeOutput(String str, String strOutFile) {

try {

FileOutputStream fos = new FileOutputStream(strOutFile);

Writer out = new OutputStreamWriter(fos, "Big5");

out.write(str);

out.close();

}

catch (IOException e) {

e.printStackTrace();

e.printStackTrace();

}

}

?

static String readInput(String strInFile) {

StringBuffer buffer = new StringBuffer();

try {

FileInputStream fis = new FileInputStream(strInFile);

InputStreamReader isr = new InputStreamReader(fis, "GB2312");

Reader in = new BufferedReader(isr);

int ch;

while ((ch = in.read()) > -1) {

iCharNum += 1;

buffer.append((char)ch);

}

in.close();

return buffer.toString();

}

catch (IOException e) {

e.printStackTrace();

return null;

}

}

}

?

編碼轉化的過程如下:

GB2312------------------>Unicode------------->Big5

執行 java gb2big5 gb.txt big5.txt ,如果 gb.txt 的內容是“今天星期三”,則得到的文件 big5.txt 中的字符能夠正確顯示;而如果 gb.txt 的內容是“情人節快樂”,則得到的文件 big5.txt 中對應于“節”和“樂”的字符都是符號“?”(0x3F),可見 sun.io.ByteToCharGB2312 和 sun.io.CharToByteBig5 這兩個基本類并沒有編好。

正如上例一樣, Java 的基本類也可能存在問題。由于國際化的工作并不是在國內完成的,所以在這些基本類發布之前,沒有經過嚴格的測試,所以對中文字符的支持并不像 Java Soft 所聲稱的那樣完美。前不久,我的一位技術上的朋友發信給我說,他終于找到了 Java Servlet 中文問題的根源。兩周以來,他一直為 Java Servlet 的中文問題所困擾,因為每面對一個含有中文字符的字符串都必須進行強制轉換才能夠得到正確的結果(這好象是大家公認的唯一的解決辦法)。后來,他確實不想如此繼續安分下去了,因為這樣的事情確實不應該是高級程序員所要做的工作,他就找出 Servlet 解碼的源代碼進行分析,因為他懷疑問題就出在解碼這部分。經過四個小時的奮斗,他終于找到了問題的根源所在。原來他的懷疑是正確的, Servlet 的解碼部分完全沒有考慮雙字節,直接把 %XX 當作一個字符。(原來 Java Soft 也會犯這幺低級的錯誤!)

如果你對這個問題有興趣或者遇到了同樣的煩惱的話,你可以按照他的步驟Servlet.jar 進行修改

找到源代碼 HttpUtils 中的 static private String parseName ,在返回前將 sb(StringBuffer) 復制成 byte bs[] ,然后 return new String(bs,”GB2312”)。作上述修改后就需要自己解碼了:

HashTable form=HttpUtils .parseQueryString(request.getQueryString())或者

form=HttpUtils.parsePostData(……)

千萬別忘了編譯后放到 Servlet.jar 里面。

五、 關于 Java 中文問題的總結

Java 編程語言成長于網絡世界,這就要求 Java 對多國字符有很好的支持。 Java 編程語言適應了計算的網絡化的需求,為它能夠在網絡世界迅速成長奠定了堅實的基礎。 Java 的締造者 (Java Soft) 已經考慮到 Java 編程語言對多國字符的支持,只是現在的解決方案有很多缺陷在里面,需要我們付諸一些補償性的措施。而世界標準化組織也在努力把人類所有的文字統一在一種編碼之中,其中一種方案是 ISO10646 ,它用四個字節來表示一個字符。當然,在這種方案未被采用之前,還是希望 Java Soft 能夠嚴格地測試它的產品,為用戶帶來更多的方便。



Victor 2005-06-04 11:44 發表評論
]]>
主站蜘蛛池模板: 国产极品粉嫩泬免费观看| 亚洲精品免费视频| 免费萌白酱国产一区二区| 亚洲伊人久久大香线蕉结合| 免费看美女裸露无档网站| 亚洲免费福利在线视频| 毛片A级毛片免费播放| 亚洲爆乳成av人在线视菜奈实| 亚洲精品动漫免费二区| 亚洲人成人网站18禁| 四虎免费永久在线播放| 视频免费1区二区三区| 亚洲色精品vr一区二区三区| 美女视频黄的免费视频网页 | 亚洲av日韩专区在线观看| 国产精品无码一二区免费| 免费国产在线精品一区| 亚洲乱码一区二区三区在线观看 | a级毛片高清免费视频就| 亚洲国产精品VA在线看黑人| 最近免费中文字幕高清大全| 亚洲一区中文字幕| 又黄又爽无遮挡免费视频| a级成人毛片免费视频高清| 亚洲一卡2卡4卡5卡6卡残暴在线| 全免费a级毛片免费**视频| 五月天国产成人AV免费观看| 亚洲av无码不卡| 成年女人免费视频播放体验区 | 久久综合九色综合97免费下载| 亚洲国产精品yw在线观看| 国产黄色片在线免费观看| 国产猛男猛女超爽免费视频| 激情综合亚洲色婷婷五月APP| 国产又黄又爽又刺激的免费网址| 免费看成人AA片无码视频吃奶| 亚洲国产精品久久久久秋霞影院 | 国产91色综合久久免费| 国产成人亚洲精品电影| 亚洲日本中文字幕| 亚洲高清无码在线观看|