JAVA EXCEL API 簡介
Java Excel 是一開放源碼項目,通過它 Java 開發人員可以讀取 Excel 文件的內容、創建新的 Excel 文件、更新已經存在的 Excel 文件。使用該 API 非 Windows 操作系統也可以通過純 Java 應用來處理 Excel 數據表。因為是使用 Java 編寫的,所以我們在 Web 應用中可以通過 JSP、Servlet 來調用 API 實現對 Excel 數據表的訪問。
現在發布的穩定版本是 V2.0,提供以下功能:
- 從 Excel 95、97、2000 等格式的文件中讀取數據;
- 讀取 Excel 公式(可以讀取 Excel 97 以后的公式);
- 生成 Excel 數據表(格式為 Excel 97);
- 支持字體、數字、日期的格式化;
- 支持單元格的陰影操作,以及顏色操作;
- 修改已經存在的數據表;
現在還不支持以下功能,但不久就會提供了:
- 不能夠讀取圖表信息;
- 可以讀,但是不能生成公式,任何類型公式最后的計算值都可以讀出;
回頁首
應用示例
1 從 Excel 文件讀取數據表
Java Excel API 既可以從本地文件系統的一個文件 (.xls),也可以從輸入流中讀取 Excel 數據表。讀取 Excel 數據表的第一步是創建 Workbook( 術語:工作薄 ),下面的代碼片段舉例說明了應該如何操作:( 完整代碼見 ExcelReading.java)
import java.io.*; import jxl.*; … … … … try { // 構建 Workbook 對象 , 只讀 Workbook 對象 // 直接從本地文件創建 Workbook // 從輸入流創建 Workbook InputStream is = new FileInputStream(sourcefile); jxl.Workbook rwb = Workbook.getWorkbook(is); } catch (Exception e) { e.printStackTrace(); }
|
一旦創建了 Workbook,我們就可以通過它來訪問 Excel Sheet( 術語:工作表 )。參考下面的代碼片段:
// 獲取第一張 Sheet 表 Sheet rs = rwb.getSheet(0);
|
我們既可能通過 Sheet 的名稱來訪問它,也可以通過下標來訪問它。如果通過下標來訪問的話,要注意的一點是下標從 0 開始,就像數組一樣。
一旦得到了 Sheet,我們就可以通過它來訪問 Excel Cell( 術語:單元格 )。參考下面的代碼片段:
// 獲取第一行,第一列的值 Cell c00 = rs.getCell(0, 0); String strc00 = c00.getContents(); // 獲取第一行,第二列的值 Cell c10 = rs.getCell(1, 0); String strc10 = c10.getContents(); // 獲取第二行,第二列的值 Cell c11 = rs.getCell(1, 1); String strc11 = c11.getContents(); System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType()); System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType()); System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType());
|
如果僅僅是取得 Cell 的值,我們可以方便地通過 getContents() 方法,它可以將任何類型的 Cell 值都作為一個字符串返回。示例代碼中 Cell(0, 0) 是文本型,Cell(1, 0) 是數字型,Cell(1,1) 是日期型,通過 getContents(),三種類型的返回值都是字符型。
如果有需要知道 Cell 內容的確切類型,API 也提供了一系列的方法。參考下面的代碼片段:
String strc00 = null; double strc10 = 0.00; Date strc11 = null; Cell c00 = rs.getCell(0, 0); Cell c10 = rs.getCell(1, 0); Cell c11 = rs.getCell(1, 1); if(c00.getType() == CellType.LABEL) { LabelCell labelc00 = (LabelCell)c00; strc00 = labelc00.getString(); } if(c10.getType() == CellType.NUMBER) { NmberCell numc10 = (NumberCell)c10; strc10 = numc10.getValue(); } if(c11.getType() == CellType.DATE) { DateCell datec11 = (DateCell)c11; strc11 = datec11.getDate(); } System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType()); System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType()); System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType());
|
在得到 Cell 對象后,通過 getType() 方法可以獲得該單元格的類型,然后與 API 提供的基本類型相匹配,強制轉換成相應的類型,最后調用相應的取值方法 getXXX(),就可以得到確定類型的值。API 提供了以下基本類型,與 Excel 的數據格式相對應,如下圖所示:
每種類型的具體意義,請參見 Java Excel API Document。
當你完成對 Excel 電子表格數據的處理后,一定要使用 close() 方法來關閉先前創建的對象,以釋放讀取數據表的過程中所占用的內存空間,在讀取大量數據時顯得尤為重要。參考如下代碼片段:
// 操作完成時,關閉對象,釋放占用的內存空間 rwb.close();
|
Java Excel API 提供了許多訪問 Excel 數據表的方法,在這里我只簡要地介紹幾個常用的方法,其它的方法請參考附錄中的 Java Excel API Document。
Workbook 類提供的方法
1. int getNumberOfSheets()
獲得工作薄(Workbook)中工作表(Sheet)的個數,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); int sheets = rwb.getNumberOfSheets();
|
2. Sheet[] getSheets()
返回工作薄(Workbook)中工作表(Sheet)對象數組,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); Sheet[] sheets = rwb.getSheets();
|
3. String getVersion()
返回正在使用的 API 的版本號,好像是沒什么太大的作用。
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); String apiVersion = rwb.getVersion();
|
Sheet 接口提供的方法
1) String getName()
獲取 Sheet 的名稱,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); String sheetName = rs.getName();
|
2) int getColumns()
獲取 Sheet 表中所包含的總列數,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); int rsColumns = rs.getColumns();
|
3) Cell[] getColumn(int column)
獲取某一列的所有單元格,返回的是單元格對象數組,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell[] cell = rs.getColumn(0);
|
4) int getRows()
獲取 Sheet 表中所包含的總行數,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); int rsRows = rs.getRows();
|
5) Cell[] getRow(int row)
獲取某一行的所有單元格,返回的是單元格對象數組,示例子:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell[] cell = rs.getRow(0);
|
6) Cell getCell(int column, int row)
獲取指定單元格的對象引用,需要注意的是它的兩個參數,第一個是列數,第二個是行數,這與通常的行、列組合有些不同。
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell cell = rs.getCell(0, 0);
|
2 生成新的 Excel 工作薄
下面的代碼主要是向大家介紹如何生成簡單的 Excel 工作表,在這里單元格的內容是不帶任何修飾的 ( 如:字體,顏色等等 ),所有的內容都作為字符串寫入。( 完整代碼見 ExcelWriting.java)
與讀取 Excel 工作表相似,首先要使用 Workbook 類的工廠方法創建一個可寫入的工作薄 (Workbook) 對象,這里要注意的是,只能通過 API 提供的工廠方法來創建 Workbook,而不能使用 WritableWorkbook 的構造函數,因為類 WritableWorkbook 的構造函數為 protected 類型。示例代碼片段如下:
import java.io.*; import jxl.*; import jxl.write.*; … … … … try { // 構建 Workbook 對象 , 只讀 Workbook 對象 //Method 1:創建可寫入的 Excel 工作薄 jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile)); //Method 2:將 WritableWorkbook 直接寫入到輸出流 /* OutputStream os = new FileOutputStream(targetfile); jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(os); */ } catch (Exception e) { e.printStackTrace(); }
|
API 提供了兩種方式來處理可寫入的輸出流,一種是直接生成本地文件,如果文件名不帶全路徑的話,缺省的文件會定位在當前目錄,如果文件名帶有全路徑的話,則生成的 Excel 文件則會定位在相應的目錄;另外一種是將 Excel 對象直接寫入到輸出流,例如:用戶通過瀏覽器來訪問 Web 服務器,如果 HTTP 頭設置正確的話,瀏覽器自動調用客戶端的 Excel 應用程序,來顯示動態生成的 Excel 電子表格。
接下來就是要創建工作表,創建工作表的方法與創建工作薄的方法幾乎一樣,同樣是通過工廠模式方法獲得相應的對象,該方法需要兩個參數,一個是工作表的名稱,另一個是工作表在工作薄中的位置,參考下面的代碼片段:
// 創建 Excel 工作表 jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0);
|
"這鍋也支好了,材料也準備齊全了,可以開始下鍋了!",現在要做的只是實例化 API 所提供的 Excel 基本數據類型,并將它們添加到工作表中就可以了,參考下面的代碼片段:
//1. 添加 Label 對象 jxl.write.Label labelC = new jxl.write.Label(0, 0, "This is a Label cell"); ws.addCell(labelC); // 添加帶有字型 Formatting 的對象 jxl.write.WritableFont wf = new jxl.write.WritableFont(WritableFont.TIMES, 18, WritableFont.BOLD, true); jxl.write.WritableCellFormat wcfF = new jxl.write.WritableCellFormat(wf); jxl.write.Label labelCF = new jxl.write.Label(1, 0, "This is a Label Cell", wcfF); ws.addCell(labelCF); // 添加帶有字體顏色 Formatting 的對象 jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.RED); jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc); jxl.write.Label labelCFC = new jxl.write.Label(1, 0, "This is a Label Cell", wcfFC); ws.addCell(labelCF); //2. 添加 Number 對象 jxl.write.Number labelN = new jxl.write.Number(0, 1, 3.1415926); ws.addCell(labelN); // 添加帶有 formatting 的 Number 對象 jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##"); jxl.write.WritableCellFormat wcfN = new jxl.write.WritableCellFormat(nf); jxl.write.Number labelNF = new jxl.write.Number(1, 1, 3.1415926, wcfN); ws.addCell(labelNF); //3. 添加 Boolean 對象 jxl.write.Boolean labelB = new jxl.write.Boolean(0, 2, false); ws.addCell(labelB); //4. 添加 DateTime 對象 jxl.write.DateTime labelDT = new jxl.write.DateTime(0, 3, new java.util.Date()); ws.addCell(labelDT); // 添加帶有 formatting 的 DateFormat 對象 jxl.write.DateFormat df = new jxl.write.DateFormat("dd MM yyyy hh:mm:ss"); jxl.write.WritableCellFormat wcfDF = new jxl.write.WritableCellFormat(df); jxl.write.DateTime labelDTF = new jxl.write.DateTime(1, 3, new java.util.Date(), wcfDF); ws.addCell(labelDTF);
|
這里有兩點大家要引起大家的注意。第一點,在構造單元格時,單元格在工作表中的位置就已經確定了。一旦創建后,單元格的位置是不能夠變更的,盡管單元格的內容是可以改變的。第二點,單元格的定位是按照下面這樣的規律 (column, row),而且下標都是從 0 開始,例如,A1 被存儲在 (0, 0),B1 被存儲在 (1, 0)。
最后,不要忘記關閉打開的 Excel 工作薄對象,以釋放占用的內存,參見下面的代碼片段:
// 寫入 Exel 工作表 wwb.write(); // 關閉 Excel 工作薄對象 wwb.close();
|
這可能與讀取 Excel 文件的操作有少少不同,在關閉 Excel 對象之前,你必須要先調用 write() 方法,因為先前的操作都是存儲在緩存中的,所以要通過該方法將操作的內容保存在文件中。如果你先關閉了 Excel 對象,那么只能得到一張空的工作薄了。
3 拷貝、更新 Excel 工作薄
接下來簡要介紹一下如何更新一個已經存在的工作薄,主要是下面二步操作,第一步是構造只讀的 Excel 工作薄,第二步是利用已經創建的 Excel 工作薄創建新的可寫入的 Excel 工作薄,參考下面的代碼片段:( 完整代碼見 ExcelModifying.java)
// 創建只讀的 Excel 工作薄的對象 jxl.Workbook rw = jxl.Workbook.getWorkbook(new File(sourcefile)); // 創建可寫入的 Excel 工作薄對象 jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile), rw); // 讀取第一張工作表 jxl.write.WritableSheet ws = wwb.getSheet(0); // 獲得第一個單元格對象 jxl.write.WritableCell wc = ws.getWritableCell(0, 0); // 判斷單元格的類型 , 做出相應的轉化 if(wc.getType() == CellType.LABEL) { Label l = (Label)wc; l.setString("The value has been modified."); } // 寫入 Excel 對象 wwb.write(); // 關閉可寫入的 Excel 對象 wwb.close(); // 關閉只讀的 Excel 對象 rw.close();
|
之所以使用這種方式構建 Excel 對象,完全是因為效率的原因,因為上面的示例才是 API 的主要應用。為了提高性能,在讀取工作表時,與數據相關的一些輸出信息,所有的格式信息,如:字體、顏色等等,是不被處理的,因為我們的目的是獲得行數據的值,既使沒有了修飾,也不會對行數據的值產生什么影響。唯一的不利之處就是,在內存中會同時保存兩個同樣的工作表,這樣當工作表體積比較大時,會占用相當大的內存,但現在好像內存的大小并不是什么關鍵因素了。
一旦獲得了可寫入的工作表對象,我們就可以對單元格對象進行更新的操作了,在這里我們不必調用 API 提供的 add() 方法,因為單元格已經于工作表當中,所以我們只需要調用相應的 setXXX() 方法,就可以完成更新的操作了。
盡單元格原有的格式化修飾是不能去掉的,我們還是可以將新的單元格修飾加上去,以使單元格的內容以不同的形式表現。
新生成的工作表對象是可寫入的,我們除了更新原有的單元格外,還可以添加新的單元格到工作表中,這與示例 2 的操作是完全一樣的。
最后,不要忘記調用 write() 方法,將更新的內容寫入到文件中,然后關閉工作薄對象,這里有兩個工作薄對象要關閉,一個是只讀的,另外一個是可寫入的。
回頁首
小結
本文只是對 Java Excel API 中常用的方法作了介紹,要想更詳盡地了解 API,請大家參考 API 文檔,或源代碼。Java Excel API 是一個開放源碼項目,請大家關注它的最新進展,有興趣的朋友也可以申請加入這個項目,或者是提出寶貴的意見。
使用Junit4.4測試
在類上的配置Annotation
@RunWith(SpringJUnit4ClassRunner.class) 用于配置spring中測試的環境
@ContextConfiguration(Locations="../applicationContext.xml") 用于指定配置文件所在的位置
@Test標注在方法前,表示其是一個測試的方法 無需在其配置文件中額外設置屬性.
多個配置文件時{"/applic","/asas"} 可以導入多個配置文件
測試中的事務配置 ,
AbstractTransactionalJUnit38SpringContextTests、 AbstractTransactionalJUnit4SpringContextTests
AbstractTransactionalTestNGSpringContextTests
已經在類級別預先配置了好了事物支持
在普通spring的junit環境中配置事務
在類之前加入注解
@TransactionConfiguration(transactionManagert="txMgr",defaultRollback=false)
@Transactional
在方法中主要使用的Annotation包括
@TestExecutionListeners({})---用于禁用默認的監聽器 否著需要通過@contextconfiguration配置一個ApplicationContext;
@BeforeTransaction
@Before
@Rollback(true)
@AfterTransaction
@NotTransactional
Junit4.4下支持類,方便基于junit4.4的測試
AbstractJUnit4SpringContextTests:
AbstractTransactionalJUnit4SpringContextTests:
需要在applicationContext中定義一個datasource
2009年3月9日
目前Spring2.5只支持4.4的Junit進行測試
下面是一個簡單的測試Demo
1 package com.gameplus.service.webService;
2
3 import javax.annotation.Resource;
4
5 import org.junit.Test;
6 import org.junit.runner.RunWith;
7 import org.springframework.test.context.ContextConfiguration;
8 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
9
10 @RunWith(SpringJUnit4ClassRunner.class)
11 @ContextConfiguration(locations={"../../../../applicationContext.xml","../../../../applicationDatasource.xml"})
12 public class UserServiceTest {
13 @Resource
14 private IUserService userService;
15
16 @Test
17 public void testAddOpinion1() {
18 userService.downloadCount(1);
19 System.out.println(1);
20 }
21 @Test
22 public void testAddOpinion2() {
23 userService.downloadCount(2);
24 System.out.println(2);
25 }
26 }
27
注意需要新的Jar包如下
javassist-3.4.GA.jar
hibernate3.jar
hibernate-annotations.jar
尤其注意用新版的,舊版會出現類未找到的異常
版權聲明:轉載時請以超鏈接形式標明文章原始出處和作者信息及本聲明
http://ralf0131.blogbus.com/logs/55701639.html
參考:http://www.javaeye.com/topic/14631
關于JUnit4: http://www.ibm.com/developerworks/cn/java/j-junit4.html
背景:
如果在Hibernate層采用lazy=true的話,有的時候會拋出LazyInitializationException,這時一種解決辦法是用OpenSessionInViewFilter,但是如果通過main方法來運行一些測試程序,那么上述方法就沒有用武之地了。這里提供了一種方法,來達到實現和OpenSessionInViewFilter相同作用的目的。這里的應用場景是采用JUnit4來編寫測試用例。
JUnit4的好處是:采用annotation來代替反射機制,不必寫死方法名.
首先添加一個abstract class(AbstractBaseTestCase.class), 做一些準備性的工作:
(可以看到@Before和@After兩個annotation的作用相當于setUp()和tearDown()方法,但是,顯然更靈活)
package testcase;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/***
* An abstract base class for TestCases.
* All test cases should extend this class.
*/
public class AbstractBaseTestCase {
private SessionFactory sessionFactory;
private Session session;
protected FileSystemXmlApplicationContext dsContext;
private String []configStr = {"/WebRoot/WEB-INF/applicationContext.xml"};
@Before
public void openSession() throws Exception {
dsContext = new FileSystemXmlApplicationContext(configStr);
sessionFactory = (SessionFactory) dsContext.getBean("sessionFactory");
session = SessionFactoryUtils.getSession(sessionFactory, true);
session.setFlushMode(FlushMode.MANUAL);
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
}
@After
public void closeSession() throws Exception {
TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.releaseSession(session, sessionFactory);
}
}
接下來繼承上述基類,實現測試邏輯:
(注意import static用于引用某個類的靜態方法)
(@Test注解表明該方法是一個測試方法)
package testcase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Before;
import org.junit.Test;
public class testCase1 extends AbstractBaseTestCase {
private YourManager manager;
@Before
public void prepare(){
manager = (YourManager)dsContext.getBean("YourManager");
}
@Test
public void test1(){
try {
String result = manager.do_sth();
System.out.println(result);
assertEquals(result, EXPECTED_RESULT);
} catch (Exception e) {
e.printStackTrace();
fail("Exception thrown.");
}
}
}
document.getElementById(obj).style.backgroundPosition="10px 0px";
window.onload =function() {
(function(b)
{
var a=document.createElement("script");
a.setAttribute("charset","utf-8");
a.setAttribute("type","text/javascript");
a.setAttribute("src",b);
document.getElementsByTagName("head")[0].appendChild(a)
}
)("1.js");
}
String[] userData = "1######".split("#");
System.out.println(userData.length);
輸出:userData.length = 1
該方法的作用就像是使用給定的表達式和限制參數 0 來調用兩參數 split 方法。因此,結果數組中不包括結尾空字符串。
- // Construct result
- int resultSize = matchList.size();
- if (limit == 0)
- while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
- resultSize--;
- String[] result = new String[resultSize];
- return matchList.subList(0, resultSize).toArray(result);
split方法是調用Pattern的split實現的,看上面代碼中的
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
可見。字符串末尾的空字符串將從匹配結果中去除
idCard.js部分*******************************************************
//****************************************************************************
// 構造函數,變量為15位或者18位的身份證號碼
function clsIDCard(CardNo) {
this.Valid=false;
this.ID15='';
this.ID18='';
this.Local='';
if(CardNo!=null)this.SetCardNo(CardNo);
}
// 設置身份證號碼,15位或者18位
clsIDCard.prototype.SetCardNo = function(CardNo) {
this.ID15='';
this.ID18='';
this.Local='';
CardNo=CardNo.replace(" ","");
var strCardNo;
if(CardNo.length==18) {
pattern= /^\d{17}(\d|x|X)$/;
if (pattern.exec(CardNo)==null)return;
strCardNo=CardNo.toUpperCase();
} else {
pattern= /^\d{15}$/;
if (pattern.exec(CardNo)==null)return;
strCardNo=CardNo.substr(0,6)+'19'+CardNo.substr(6,9)
strCardNo+=this.GetVCode(strCardNo);
}
this.Valid=this.CheckValid(strCardNo);
}
// 校驗身份證有效性
clsIDCard.prototype.IsValid = function() {
return this.Valid;
}
// 返回生日字符串,格式如下,1981-10-10
clsIDCard.prototype.GetBirthDate = function() {
var BirthDate='';
if(this.Valid)BirthDate=this.GetBirthYear()+'-'+this.GetBirthMonth()+'-'+this.GetBirthDay();
return BirthDate;
}
// 返回生日中的年,格式如下,1981
clsIDCard.prototype.GetBirthYear = function() {
var BirthYear='';
if(this.Valid)BirthYear=this.ID18.substr(6,4);
return BirthYear;
}
// 返回生日中的月,格式如下,10
clsIDCard.prototype.GetBirthMonth = function() {
var BirthMonth='';
if(this.Valid)BirthMonth=this.ID18.substr(10,2);
if(BirthMonth.charAt(0)=='0')BirthMonth=BirthMonth.charAt(1);
return BirthMonth;
}
// 返回生日中的日,格式如下,10
clsIDCard.prototype.GetBirthDay = function() {
var BirthDay='';
if(this.Valid)BirthDay=this.ID18.substr(12,2);
return BirthDay;
}
// 返回性別,1:男,0:女
clsIDCard.prototype.GetSex = function() {
var Sex='';
if(this.Valid)Sex=this.ID18.charAt(16)%2;
return Sex;
}
// 返回15位身份證號碼
clsIDCard.prototype.Get15 = function() {
var ID15='';
if(this.Valid)ID15=this.ID15;
return ID15;
}
// 返回18位身份證號碼
clsIDCard.prototype.Get18 = function() {
var ID18='';
if(this.Valid)ID18=this.ID18;
return ID18;
}
// 返回所在省,例如:上海市、浙江省
clsIDCard.prototype.GetLocal = function() {
var Local='';
if(this.Valid)Local=this.Local;
return Local;
}
clsIDCard.prototype.GetVCode = function(CardNo17) {
var Wi = new Array(7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2,1);
var Ai = new Array('1','0','X','9','8','7','6','5','4','3','2');
var cardNoSum = 0;
for (var i=0; i<CardNo17.length; i++)cardNoSum+=CardNo17.charAt(i)*Wi[i];
var seq = cardNoSum%11;
return Ai[seq];
}
clsIDCard.prototype.CheckValid = function(CardNo18) {
if(this.GetVCode(CardNo18.substr(0,17))!=CardNo18.charAt(17))return false;
if(!this.IsDate(CardNo18.substr(6,8)))return false;
var aCity={11:"北京",12:"天津",13:"河北",14:"山西",15:"內蒙古",21:"遼寧",22:"吉林",23:"黑龍江 ",31:"上海",32:"江蘇",33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山東",41:"河南",42:"湖北 ",43:"湖南",44:"廣東",45:"廣西",46:"海南",50:"重慶",51:"四川",52:"貴州",53:"云南",54:"西藏 ",61:"陜西",62:"甘肅",63:"青海",64:"寧夏",65:"新疆",71:"臺灣",81:"香港",82:"澳門",91:"國外"};
if(aCity[parseInt(CardNo18.substr(0,2))]==null)return false;
this.ID18=CardNo18;
this.ID15=CardNo18.substr(0,6)+CardNo18.substr(8,9);
this.Local=aCity[parseInt(CardNo18.substr(0,2))];
return true;
}
clsIDCard.prototype.IsDate = function(strDate) {
var r = strDate.match(/^(\d{1,4})(\d{1,2})(\d{1,2})$/);
if(r==null)return false;
var d= new Date(r[1], r[2]-1, r[3]);
return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[2]&&d.getDate()==r[3]);
}
頁面部分**************************************************************
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>身份證驗證</title>
<script src="idCard.js"></script>
</head>
<body>
<script>
function valiIdCard(idCard){
var checkFlag = new clsIDCard(idCard);
if (!checkFlag.IsValid()) {
alert("輸入的身份證號無效,請輸入真實的身份證號!");
document.getElementByIdx("idCard").focus();
return false;
}else{
alert("正確!");
}
}
</script>
<input id="idCard" type="text" onblur="valiIdCard(this.value)"/>
</body>
該騙子詐騙短信內容:“溫馨提示,現已從您帳上支出1300元,,工行客服:021—60512737。
第一步:加入log4j-1.2.8.jar到lib下。
第二步:在CLASSPATH下建立log4j.properties。內容如下:
1 log4j.rootCategory=INFO, stdout , R
2
3 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
4 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
5 log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n
6
7 log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
8 log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log
9 log4j.appender.R.layout=org.apache.log4j.PatternLayout
10 log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
11
12 log4j.logger.com.neusoft=DEBUG
13 log4j.logger.com.opensymphony.oscache=ERROR
14 log4j.logger.net.sf.navigator=ERROR
15 log4j.logger.org.apache.commons=ERROR
16 log4j.logger.org.apache.struts=WARN
17 log4j.logger.org.displaytag=ERROR
18 log4j.logger.org.springframework=DEBUG
19 log4j.logger.com.ibatis.db=WARN
20 log4j.logger.org.apache.velocity=FATAL
21
22 log4j.logger.com.canoo.webtest=WARN
23
24 log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
25 log4j.logger.org.hibernate=DEBUG
26 log4j.logger.org.logicalcobwebs=WARN
第三步:相應的修改其中屬性,修改之前就必須知道這些都是干什么的,在第二部分講解。
第四步:在要輸出日志的類中加入相關語句:
定義屬性:protected final Log log = LogFactory.getLog(getClass());
在相應的方法中:
if (log.isDebugEnabled())
{
log.debug(“System …..”);
}
二、Log4j說明
1 log4j.rootCategory=INFO, stdout , R
此句為將等級為INFO的日志信息輸出到stdout和R這兩個目的地,stdout和R的定義在下面的代碼,可以任意起名。等級可分為OFF、 FATAL、ERROR、WARN、INFO、DEBUG、ALL,如果配置OFF則不打出任何信息,如果配置為INFO這樣只顯示INFO, WARN, ERROR的log信息,而DEBUG信息不會被顯示,具體講解可參照第三部分定義配置文件中的logger。
3 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
此句為定義名為stdout的輸出端是哪種類型,可以是
org.apache.log4j.ConsoleAppender(控制臺),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天產生一個日志文件),
org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件)
org.apache.log4j.WriterAppender(將日志信息以流格式發送到任意指定的地方)
具體講解可參照第三部分定義配置文件中的Appender。
4 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
此句為定義名為stdout的輸出端的layout是哪種類型,可以是
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串),
org.apache.log4j.TTCCLayout(包含日志產生的時間、線程、類別等等信息)
具體講解可參照第三部分定義配置文件中的Layout。
5 log4j.appender.stdout.layout.ConversionPattern= [QC] %p [%t] %C.%M(%L) | %m%n
如果使用pattern布局就要指定的打印信息的具體格式ConversionPattern,打印參數如下:
%m 輸出代碼中指定的消息
%p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL
%r 輸出自應用啟動到輸出該log信息耗費的毫秒數
%c 輸出所屬的類目,通常就是所在類的全名
%t 輸出產生該日志事件的線程名
%n 輸出一個回車換行符,Windows平臺為“rn”,Unix平臺為“n”
%d 輸出日志時間點的日期或時間,默認格式為ISO8601,也可以在其后指定格式,比如:%d{yyyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
%l 輸出日志事件的發生位置,包括類目名、發生的線程,以及在代碼中的行數。
[QC]是log信息的開頭,可以為任意字符,一般為項目簡稱。
輸出的信息
[TS] DEBUG [main] AbstractBeanFactory.getBean(189) | Returning cached instance of singleton bean 'MyAutoProxy'
具體講解可參照第三部分定義配置文件中的格式化日志信息。
7 log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
此句與第3行一樣。定義名為R的輸出端的類型為每天產生一個日志文件。
8 log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log
此句為定義名為R的輸出端的文件名為D:\Tomcat 5.5\logs\qc.log
可以自行修改。
9 log4j.appender.R.layout=org.apache.log4j.PatternLayout
與第4行相同。
10 log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
與第5行相同。
12 log4j.logger.com. neusoft =DEBUG
指定com.neusoft包下的所有類的等級為DEBUG。
可以把com.neusoft改為自己項目所用的包名。
13 log4j.logger.com.opensymphony.oscache=ERROR
14 log4j.logger.net.sf.navigator=ERROR
這兩句是把這兩個包下出現的錯誤的等級設為ERROR,如果項目中沒有配置EHCache,則不需要這兩句。
15 log4j.logger.org.apache.commons=ERROR
16 log4j.logger.org.apache.struts=WARN
這兩句是struts的包。
17 log4j.logger.org.displaytag=ERROR
這句是displaytag的包。(QC問題列表頁面所用)
18 log4j.logger.org.springframework=DEBUG
此句為Spring的包。
24 log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
25 log4j.logger.org.hibernate=DEBUG
此兩句是hibernate的包。
以上這些包的設置可根據項目的實際情況而自行定制。
三、log4j詳解
1、定義配置文件
Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件log4j.properties(鍵=值)。下面將介紹使用log4j.properties文件作為配置文件的方法:
①、配置根Logger
Logger 負責處理日志記錄的大部分操作。
其語法為:
log4j.rootLogger = [ level ] , appenderName, appenderName, …
其中,level 是日志記錄的優先級,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定義的級別。Log4j建議只使用四個級別,優 先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應用程序中相應級別的日志信息的開關。比如在這里定 義了INFO級別,只有等于及高于這個級別的才進行處理,則應用程序中所有DEBUG級別的日志信息將不被打印出來。ALL:打印所有的日志,OFF:關 閉所有的日志輸出。 appenderName就是指定日志信息輸出到哪個地方。可同時指定多個輸出目的地。
②、配置日志信息輸出目的地 Appender
Appender 負責控制日志記錄操作的輸出。
其語法為:
log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1
…
log4j.appender.appenderName.optionN = valueN
這里的appenderName為在①里定義的,可任意起名。
其中,Log4j提供的appender有以下幾種:
org.apache.log4j.ConsoleAppender(控制臺),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天產生一個日志文件),
org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件),可通過 log4j.appender.R.MaxFileSize=100KB設置文件大小,還可通過 log4j.appender.R.MaxBackupIndex=1設置為保存一個備份文件。
org.apache.log4j.WriterAppender(將日志信息以流格式發送到任意指定的地方)
例如:log4j.appender.stdout=org.apache.log4j.ConsoleAppender
定義一個名為stdout的輸出目的地,ConsoleAppender為控制臺。
③、配置日志信息的格式(布局)Layout
Layout 負責格式化Appender的輸出。
其語法為:
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
…
log4j.appender.appenderName.layout.optionN = valueN
其中,Log4j提供的layout有以下幾種:
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串),
org.apache.log4j.TTCCLayout(包含日志產生的時間、線程、類別等等信息)
2、格式化日志信息
Log4J采用類似C語言中的printf函數的打印格式格式化日志信息,打印參數如下:
%m 輸出代碼中指定的消息
%p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL
%r 輸出自應用啟動到輸出該log信息耗費的毫秒數
%c 輸出所屬的類目,通常就是所在類的全名
%t 輸出產生該日志事件的線程名
%n 輸出一個回車換行符,Windows平臺為“rn”,Unix平臺為“n”
%d 輸出日志時間點的日期或時間,默認格式為ISO8601,也可以在其后指定格式,比如:%d{yyyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
%l 輸出日志事件的發生位置,包括類目名、發生的線程,以及在代碼中的行數。
3、在代碼中使用Log4j
我們在需要輸出日志信息的類中做如下的三個工作:
1、導入所有需的commongs-logging類:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
2、在自己的類中定義一個org.apache.commons.logging.Log類的私有靜態類成員:
private final Log log = LogFactory.getLog(getClass());
LogFactory.getLog()方法的參數使用的是當前類的class。
3、使用org.apache.commons.logging.Log類的成員方法輸出日志信息:
if (log.isDebugEnabled())
{
log.debug("111");
}
if (log.isInfoEnabled())
{
log.info("222");
}
if (log.isWarnEnabled())
{
log.warn("333");
}
if (log.isErrorEnabled())
{
log.error("444");
}
if (log.isFatalEnabled())
{
log.fatal("555")
}
log4j中關閉memcached日志
log4j.logger.com.danga.MemCached.MemCachedClient=ERROR
一、連接池概述
數據庫連接池概述:
數據庫連接是一種關鍵的有限的昂貴的資源,這一點在多用戶的網頁應用程序中體現得尤為突出。對數據庫連接的管理能顯著影響到整個
應用程序的伸縮性和健壯性,影響到程序的性能指標。數據庫連接池正是針對這個問題提出來的。
數據庫連接池負責分配、管理和釋放數據庫連接,它允許應用程序重復使用一個現有的數據庫連接,而再不是重新建立一個;釋放空閑時
間超過最大空閑時間的數據庫連接來避免因為沒有釋放數據庫連接而引起的數據庫連接遺漏。這項技術能明顯提高對數據庫操作的性能。
數據庫連接池在初始化時將創建一定數量的數據庫連接放到連接池中,這些數據庫連接的數量是由最小數據庫連接數來設定的。無論這些
數據庫連接是否被使用,連接池都將一直保證至少擁有這么多的連接數量。連接池的最大數據庫連接數量限定了這個連接池能占有的最大連接
數,當應用程序向連接池請求的連接數超過最大連接數量時,這些請求將被加入到等待隊列中。數據庫連接池的最小連接數和最大連接數的設
置要考慮到下列幾個因素:
1) 最小連接數是連接池一直保持的數據庫連接,所以如果應用程序對數據庫連接的使用量不大,將會有大量的數據庫連接資源被浪費;
2) 最大連接數是連接池能申請的最大連接數,如果數據庫連接請求超過此數,后面的數據庫連接請求將被加入到等待隊列中,這會影響之
后的數據庫操作。
3) 如果最小連接數與最大連接數相差太大,那么最先的連接請求將會獲利,之后超過最小連接數量的連接請求等價于建立一個新的數據庫
連接。不過,這些大于最小連接數的數據庫連接在使用完不會馬上被釋放,它將被放到連接池中等待重復使用或是空閑超時后被釋放。
目前常用的連接池有:C3P0、DBCP、Proxool
網上的評價是:
C3P0比較耗費資源,效率方面可能要低一點。
DBCP在實踐中存在BUG,在某些種情會產生很多空連接不能釋放,Hibernate3.0已經放棄了對其的支持。
Proxool的負面評價較少,現在比較推薦它,而且它還提供即時監控連接池狀態的功能,便于發現連接泄漏的情況。
配置如下:
1、在spring配置文件中,一般在applicationContext.xml中
<bean id="proxoolDataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource">
<property name="driver" value="${jdbc.connection.driverClassName}"/>
<property name="driverUrl" value="${jdbc.connection.url}"/>
<property name="user" value="${jdbc.connection.username}"/>
<property name="password" value="${jdbc.connection.password}"/>
<!-- 測試的SQL執行語句 -->
<property name="houseKeepingTestSql" value="${proxool.houseKeepingTestSql}"/>
<!-- 最少保持的空閑連接數 (默認2個) -->
<property name="prototypeCount" value="${proxool.prototypeCount}"/>
<!-- proxool自動偵察各個連接狀態的時間間隔(毫秒),偵察到空閑的連接就馬上回收,超時的銷毀 默認30秒) -->
<property name="houseKeepingSleepTime" value="${proxool.hourseKeepingSleepTime}"/>
<!-- 最大活動時間(超過此時間線程將被kill,默認為5分鐘) -->
<property name="maximumActiveTime" value="${proxool.maximumActiveTime}"/>
<!-- 連接最長時間(默認為4個小時) -->
<property name="maximumConnectionLifetime" value="${proxool.maximumConnectionLifetime}"/>
<!-- 最小連接數 (默認2個) -->
<property name="minimumConnectionCount" value="${proxool.minimumConnectionCount}"/>
<!-- 最大連接數 (默認5個) -->
<property name="maximumConnectionCount" value="${proxool.maximumConnectionCount}"/>
<!-- -->
<property name="statistics" value="${proxool.statistics}"/>
<!-- 別名 -->
<property name="alias" value="${proxool.alias}"/>
<!-- -->
<property name="simultaneousBuildThrottle" value="${proxool.simultaneous-build-throttle}"/>
</bean>
然后注入到sessionFactory中
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="proxoolDataSource"/>
</bean>
Porxool 配置文件
--==--==--==--==--==<proxool.xml>==--==--==--==--==--==--==
<?xml version="1.0" encoding="UTF-8"?>
<proxool>
<alias>WMS</alias>
<driver-url>jdbc:postgresql://192.168.210.184:5432/wms</driver-url>
<driver-class>org.postgresql.Driver</driver-class>
<driver-properties>
<property name="user" value="wms_user" />
<property name="password" value="wms" />
</driver-properties>
<minimum-connection-count>2</minimum-connection-count>
<maximum-connection-count>40</maximum-connection-count>
<simultaneous-build-throttle>20</simultaneous-build-throttle>
<prototype-count>2</prototype-count>
<house-keeping-test-sql>select CURRENT_DATE</house-keeping-test-sql>
</proxool>
--==--==--==--==--==<proxool.xml>==--==--==--==--==--==--==
配置說明:
alias -〉數據庫連接別名(程序中需要使用的名稱)
driver-url -〉數據庫驅動
driver-class -〉驅動程序類
driver-properties -〉聯機數據庫的用戶和密碼
minimum-connection-count -〉最小連接數量,建議設置0以上,保證第一次連接時間
maximum-connection-count -〉最大連接數量,如果超過最大連接數量則會拋出異常。連接數設置過多,服務器CPU和內存性能消耗很
大。
simultaneous-build-throttle -〉同時最大連接數
prototype-count -〉一次產生連接的數量。
例:如果現在prototype-count設置為4個,但是現在已經有2個可以獲得的連接,那么
將會試圖再創建2個連接。
但不能超過最大連接數。
maximum-active-time -〉連接最大時間活動 默認5分鐘
maximum-connection-lifetime -〉連接最大生命時間 默認4小時