2008年5月31日
<!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>2列右側固定左側自適應寬度,未知高度且底部平齊+頭部+導航+尾部——<a >標準之路www.aa25.cn</a></title>
<link href="layout.css" rel="stylesheet" type="text/css" />
<meta name="Keywords" content="標準之路,www.aa25.cn,網頁標準布局,DIV+CSS" />
<meta name="" content="標準之路,www.aa25.cn,網頁標準布局,DIV+CSS" />
<meta name="author" content"×××,有問題請到www.68css.cn網站留言" />
<meta name="Description" content="本套網頁標準布局模板是由標準之路(www.aa25.cn)制作完成,如果您要轉載,請保留版權" />
</head>
<body>
<div id="container">
<div id="header">This is the Header</div>
<br class="clearfloat" />
<div id="menu">This is the Menu</div>
<br class="clearfloat" />
<div id="mainContent">
<div id="sidebar">This is the sidebar<br />
</div>
<div id="content">2列右側固定左側自適應寬度,未知高度且底部平齊+頭部+導航+尾部——<a >標準之路www.aa25.cn</a><br />
<br />
本例和例21差不多,一個是固定寬度,一個是自適應,同樣是未知高度。<br />
<br />
此例中需要說明一點的是:當content設定高度后,3像素會跑到content外側,反之,在content內部。這樣,我們用!important修正在ie下向左多浮動2像素,加上3像素的bug正好是5像素,所以在火狐和IE下顯示是一樣的,這是大家必須注意的一點。而當content設定高度后,如100px,那么在IE6下,當高度超過100px時,它會自動把conent撐高,而火狐去不會。所以用!important修正在IE下設定高度值使它的3像素跑到外側,火狐下因不存在3像素問題,所以高度自動。<br />
<br />
<br />
總之,實現的方法是多種多樣的,這只是本人在學習過程中總結的一點經驗,權當拋磚引玉,希望能對您有所幫助,當然您有更好的辦法和布局,歡迎一塊來學習,交流,讓web標準在中國得到更好的發展。同時希望您繼續關注標準之路(www.aa25.cn)<br />
<br />
如果您要實現未知高度底部平齊,請參考23例<br />
</div>
</div>
<br class="clearfloat" />
<div id="footer">This is the footer<span style="display:none"><script language="javascript" type="text/javascript" src="http://js.users.51.la/1967272.js"></script></span></div>
</div>
</body>
</html>
?
css
body { font-family:Verdana; font-size:14px; margin:0;}
#container {margin:0 auto; width:100%;}
#header { height:100px; background:#9c6; margin-bottom:5px;}
#menu { height:30px; background:#693; margin-bottom:5px;}
#mainContent { background:url(bg.gif) right 0 repeat-y; overflow:auto;zoom:1; margin-bottom:5px;}
#sidebar { float:right; width:200px;background:#cf9;}
#content { margin-right:205px !important; margin-right:202px; height:auto !important; height:100px; background:#ffa;}
#footer { height:60px; background:#9c6;}
.clearfloat { clear:both; height:0; font-size: 1px; line-height: 0px;}
?
已有 0 人發表留言,猛擊->>這里<<-參與討論
ITeye推薦
winver-檢查Windows版本
?
wmimgmt.msc打開windows管理體系結構(WMI)
?
wupdmgrwindows更新程序
?
wscriptwindows腳本宿主設置
?
write寫字板
?
winmsd-系統信息
?
wiaacmgr-掃描儀和照相機向導
?
winchatXP自帶局域網聊天
?
mem.exe顯示內存使用情況
?
Msconfig.exe-系統配置實用程序
?
mplayer2-簡易widnows media player
?
mspaint畫圖板
?
mstsc遠程桌面連接
?
mplayer2-媒體播放機
?
magnify放大鏡實用程序
?
mmc打開控制臺
?
mobsync同步命令
?
dxdiag-檢查DirectX信息
?
drwtsn32 系統醫生
?
devmgmt.msc- 設備管理器
?
dfrg.msc-磁盤碎片整理程序
?
diskmgmt.msc-磁盤管理實用程序
?
dcomcnfg-打開系統組件服務
?
ddeshare-打開DDE共享設置
?
dvdplayDVD播放器
?
net stop messenger-停止信使服務
?
net start messenger開始信使服務
?
notepad打開記事本
?
nslookup-網絡管理的工具向導
?
ntbackup-系統備份和還原
?
narrator-屏幕“講述人”
?
ntmsmgr.msc移動存儲管理器
?
ntmsoprq.msc-移動存儲管理員操作請求
?
netstat -an(TC)命令檢查接口
?
syncapp創建一個公文包
?
sysedit系統配置編輯器
?
sigverif-文件簽名驗證程序
?
sndrec32-錄音機
?
shrpubw創建共享文件夾
?
secpol.msc-本地安全策略
?
syskey-系統加密,一旦加密就不能解開,保護windows xp系統的雙重密碼
?
services.msc-本地服務設置
?
Sndvol32-音量控制程序
?
sfc.exe系統文件檢查器
?
sfc /scannow-windows文件保護
?
tsshutdn-60秒倒計時關機命令
?
tourstartxp簡介(安裝完成后出現的漫游xp程序)
?
taskmgr任務管理器
?
eventvwr-事件查看器
?
eudcedit-造字程序
?
explorer-打開資源管理器
?
packager-對象包裝程序
?
perfmon.msc計算機性能監測程序
?
progman程序管理器
?
regedit.exe注冊表
?
rsop.msc-組策略結果集
?
regedt32-注冊表編輯器
?
rononce -p 15秒關機
?
regsvr32 /u *.dll停止dll文件運行
?
regsvr32 /u zipfldr.dll取消ZIP支持
?
cmd.exeCMD命令提示符
?
chkdsk.exe-Chkdsk磁盤檢查
?
certmgr.msc證書管理實用程序
?
calc-啟動計算器
?
charmap啟動字符映射表
?
cliconfg-SQL SERVER 客戶端網絡實用程序
?
Clipbrd剪貼板查看器
?
conf-啟動netmeeting
?
compmgmt.msc-計算機管理
?
cleanmgr-垃圾整理
?
ciadv.msc索引服務程序
?
osk打開屏幕鍵盤
?
odbcad32-ODBC數據源管理器
?
oobe/msoobe /a檢查XP是否激活
?
lusrmgr.msc本機用戶和組
?
logoff-注銷命令
?
iexpress-木馬捆綁工具,系統自帶
?
Nslookup-IP地址偵測器
?
fsmgmt.msc-共享文件夾管理器
?
utilman輔助工具管理器
?
gpedit.msc-組策略
?
已有 0 人發表留言,猛擊->>這里<<-參與討論
ITeye推薦
package com.shine;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
import javax.swing.Timer;
public class Tetris extends JFrame {
public Tetris() {
Tetrisblok a = new Tetrisblok();
addKeyListener(a);
add(a);
}
public static void main(String[] args) {
Tetris frame = new Tetris();
JMenuBar menu = new JMenuBar();
frame.setJMenuBar(menu);
JMenu game = new JMenu("游戲");
JMenuItem newgame = game.add("新游戲");
JMenuItem pause = game.add("暫停");
JMenuItem goon = game.add("繼續");
JMenuItem exit = game.add("退出");
JMenu help = new JMenu("幫助");
JMenuItem about = help.add("關于");
menu.add(game);
menu.add(help);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(220, 275);
frame.setTitle("Tetris內測版");
// frame.setUndecorated(true);
frame.setVisible(true);
frame.setResizable(false);
}
}
// 創建一個俄羅斯方塊類
class Tetrisblok extends JPanel implements KeyListener {
// blockType 代表方塊類型
// turnState代表方塊狀態
private int blockType;
private int score = 0;
private int turnState;
private int x;
private int y;
private int i = 0;
int j = 0;
int flag = 0;
// 定義已經放下的方塊x=0-11,y=0-21;
int[][] map = new int[13][23];
// 方塊的形狀 第一組代表方塊類型有S、Z、L、J、I、O、T 7種 第二組 代表旋轉幾次 第三四組為 方塊矩陣
private final int shapes[][][] = new int[][][] {
// i
{ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 } },
// s
{ { 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } },
// z
{ { 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } },
// j
{ { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
// o
{ { 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
// l
{ { 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
// t
{ { 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } };
// 生成新方塊的方法
public void newblock() {
blockType = (int) (Math.random() * 1000) % 7;
turnState = (int) (Math.random() * 1000) % 4;
x = 4;
y = 0;
if (gameover(x, y) == 1) {
newmap();
drawwall();
score = 0;
JOptionPane.showMessageDialog(null, "GAME OVER");
}
}
// 畫圍墻
public void drawwall() {
for (i = 0; i < 12; i++) {
map[i][21] = 2;
}
for (j = 0; j < 22; j++) {
map[11][j] = 2;
map[0][j] = 2;
}
}
// 初始化地圖
public void newmap() {
for (i = 0; i < 12; i++) {
for (j = 0; j < 22; j++) {
map[i][j] = 0;
}
}
}
// 初始化構造方法
Tetrisblok() {
newblock();
newmap();
drawwall();
Timer timer = new Timer(1000, new TimerListener());
timer.start();
}
// 旋轉的方法
public void turn() {
int tempturnState = turnState;
turnState = (turnState + 1) % 4;
if (blow(x, y, blockType, turnState) == 1) {
}
if (blow(x, y, blockType, turnState) == 0) {
turnState = tempturnState;
}
repaint();
}
// 左移的方法
public void left() {
if (blow(x - 1, y, blockType, turnState) == 1) {
x = x - 1;
}
;
repaint();
}
// 右移的方法
public void right() {
if (blow(x + 1, y, blockType, turnState) == 1) {
x = x + 1;
}
;
repaint();
}
// 下落的方法
public void down() {
if (blow(x, y + 1, blockType, turnState) == 1) {
y = y + 1;
delline();
}
;
if (blow(x, y + 1, blockType, turnState) == 0) {
add(x, y, blockType, turnState);
newblock();
delline();
}
;
repaint();
}
// 是否合法的方法
public int blow(int x, int y, int blockType, int turnState) {
for (int a = 0; a < 4; a++) {
for (int b = 0; b < 4; b++) {
if (((shapes[blockType][turnState][a * 4 + b] == 1) && (map[x
+ b + 1][y + a] == 1))
|| ((shapes[blockType][turnState][a * 4 + b] == 1) && (map[x
+ b + 1][y + a] == 2))) {
return 0;
}
}
}
return 1;
}
// 消行的方法
public void delline() {
int c = 0;
for (int b = 0; b < 22; b++) {
for (int a = 0; a < 12; a++) {
if (map[a][b] == 1) {
c = c + 1;
if (c == 10) {
score += 10;
for (int d = b; d > 0; d--) {
for (int e = 0; e < 11; e++) {
map[e][d] = map[e][d - 1];
}
}
}
}
}
c = 0;
}
}
// 判斷你掛的方法
public int gameover(int x, int y) {
if (blow(x, y, blockType, turnState) == 0) {
return 1;
}
return 0;
}
// 把當前添加map
public void add(int x, int y, int blockType, int turnState) {
int j = 0;
for (int a = 0; a < 4; a++) {
for (int b = 0; b < 4; b++) {
if (map[x + b + 1][y + a] == 0) {
map[x + b + 1][y + a] = shapes[blockType][turnState][j];
}
;
j++;
}
}
}
// 畫方塊的的方法
public void paintComponent(Graphics g) {
super.paintComponent(g);
// 畫當前方塊
for (j = 0; j < 16; j++) {
if (shapes[blockType][turnState][j] == 1) {
g.fillRect((j % 4 + x + 1) * 10, (j / 4 + y) * 10, 10, 10);
}
}
// 畫已經固定的方塊
for (j = 0; j < 22; j++) {
for (i = 0; i < 12; i++) {
if (map[i][j] == 1) {
g.fillRect(i * 10, j * 10, 10, 10);
}
if (map[i][j] == 2) {
g.drawRect(i * 10, j * 10, 10, 10);
}
}
}
g.drawString("score=" + score, 125, 10);
g.drawString("抵制不良游戲,", 125, 50);
g.drawString("拒絕盜版游戲。", 125, 70);
g.drawString("注意自我保護,", 125, 90);
g.drawString("謹防受騙上當。", 125, 110);
g.drawString("適度游戲益腦,", 125, 130);
g.drawString("沉迷游戲傷身。", 125, 150);
g.drawString("合理安排時間,", 125, 170);
g.drawString("享受健康生活。", 125, 190);
}
// 鍵盤監聽
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_DOWN:
down();
break;
case KeyEvent.VK_UP:
turn();
break;
case KeyEvent.VK_RIGHT:
right();
break;
case KeyEvent.VK_LEFT:
left();
break;
}
}
// 無用
public void keyReleased(KeyEvent e) {
}
// 無用
public void keyTyped(KeyEvent e) {
}
// 定時器監聽
class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
repaint();
if (blow(x, y + 1, blockType, turnState) == 1) {
y = y + 1;
delline();
}
;
if (blow(x, y + 1, blockType, turnState) == 0) {
if (flag == 1) {
add(x, y, blockType, turnState);
delline();
newblock();
flag = 0;
}
flag = 1;
}
;
}
}
}
?轉自CSDN
已有 0 人發表留言,猛擊->>這里<<-參與討論
ITeye推薦
function htmlToubb(h,u){
str = pattern(document.getElementById(h).value);
document.getElementById(u).value=str;
}
function ubbTohtml(u,h){
str = up(document.getElementById(u).value);
document.getElementById(h).value=str;
}
function pattern(str){
str = str.replace(/<br[^>]*>/ig,'\n');
str = str.replace(/<p[^>\/]*\/>/ig,'\n');
str = str.replace(/\son[\w]{3,16}\s?=\s*([\'\"]).+?\1/ig,'');
str = str.replace(/<hr[^>]*>/ig,'[hr]');
str = str.replace(/<(sub|sup|u|strike|b|i|pre)>/ig,'[$1]');
str = str.replace(/<\/(sub|sup|u|strike|b|i|pre)>/ig,'[/$1]');
str = str.replace(/<(\/)?strong>/ig,'[$1b]');
str = str.replace(/<(\/)?em>/ig,'[$1i]');
str = str.replace(/<(\/)?blockquote([^>]*)>/ig,'[$1blockquote]');
str = str.replace(/<img[^>]*smile=\"(\d+)\"[^>]*>/ig,'[s:$1]');
str = str.replace(/<img[^>]*src=[\'\"\s]*([^\s\'\"]+)[^>]*>/ig,'[img]'+'$1'+'[/img]');
str = str.replace(/<a[^>]*href=[\'\"\s]*([^\s\'\"]*)[^>]*>(.+?)<\/a>/ig,'[url=$1]'+'$2'+'[/url]');
str = str.replace(/<[^>]*?>/ig, '');
str = str.replace(/&/ig, '&');
str = str.replace(/</ig, '<');
str = str.replace(/>/ig, '>');
return str;
}
function up(str){
str = str.replace(/</ig,'<');
str = str.replace(/>/ig,'>');
str = str.replace(/\n/ig,'<br />');
str = str.replace(/\[code\](.+?)\[\/code\]/ig, function($1, $2) {return phpcode($2);});
str = str.replace(/\[hr\]/ig,'<hr />');
str = str.replace(/\[\/(size|color|font|backcolor)\]/ig,'</font>');
str = str.replace(/\[(sub|sup|u|i|strike|b|blockquote|li)\]/ig,'<$1>');
str = str.replace(/\[\/(sub|sup|u|i|strike|b|blockquote|li)\]/ig,'</$1>');
str = str.replace(/\[\/align\]/ig,'</p>');
str = str.replace(/\[(\/)?h([1-6])\]/ig,'<$1h$2>');
str = str.replace(/\[align=(left|center|right|justify)\]/ig,'<p align="$1">');
str = str.replace(/\[size=(\d+?)\]/ig,'<font size="$1">');
str = str.replace(/\[color=([^\[\<]+?)\]/ig, '<font color="$1">');
str = str.replace(/\[backcolor=([^\[\<]+?)\]/ig, '<font style="background-color:$1">');
str = str.replace(/\[font=([^\[\<]+?)\]/ig, '<font face="$1">');
str = str.replace(/\[list=(a|A|1)\](.+?)\[\/list\]/ig,'<ol type="$1">$2</ol>');
str = str.replace(/\[(\/)?list\]/ig,'<$1ul>');
str = str.replace(/\[s:(\d+)\]/ig,function($1,$2){ return smilepath($2);});
str = str.replace(/\[img\]([^\[]*)\[\/img\]/ig,'<img src="$1" border="0" />');
str = str.replace(/\[url=([^\]]+)\]([^\[]+)\[\/url\]/ig, '<a href="$1">'+'$2'+'</a>');
str = str.replace(/\[url\]([^\[]+)\[\/url\]/ig, '<a href="$1">'+'$1'+'</a>');
return str;
}
?
已有 0 人發表留言,猛擊->>這里<<-參與討論
ITeye推薦
PL/SQL 或UE中進行設置時發現,找不到Courier New
字體。重裝也沒作用。
根本原因是沒有將?Courier New 設置為“顯示”

已有 0 人發表留言,猛擊->>這里<<-參與討論
ITeye推薦
Windows Registry Editor Version 5.00
?
[HKEY_CLASSES_ROOT\*\shell]
[HKEY_CLASSES_ROOT\*\shell\UltraEdit]
@="UltraEdit-32"
[HKEY_CLASSES_ROOT\*\shell\UltraEdit\Command]
@="C:\\Program Files (x86)\\IDM Computer Solutions\\UltraEdit\\Uedit32.exe %1"
C:\\Program Files (x86)\\IDM Computer Solutions\\UltraEdit\\Uedit32.exe這個改為實際路徑
已有 0 人發表留言,猛擊->>這里<<-參與討論
ITeye推薦
每次一按回車,序號后面跟著一個箭頭,雖然打印的時候不會顯示出來,但這種排版效果不好。
好像是樣式的問題,不知道怎么處理?

解決辦法如圖:

已有 0 人發表留言,猛擊->>這里<<-參與討論
ITeye推薦
1,當選擇了一段文本后 (如一個變量名)在整個類中用到該文本的地方都高亮顯示
Eclipse工具欄上有個類似鋼筆的圖標,按下去就可以了。
2,當想要修改一個變量在類中所有用到的地方時 如 A a = new A(); 還有很多其它位置用到a 現在想要把a 改為a1
可以選正a后在菜單上選Refactor->Rename 就可以。類中有a 的地方都會改為a1
作者:caoyinghui1986 發表于2009-9-4 21:41:00
原文鏈接
//原文地址:http://hi.baidu.com/xublog/blog/item/06a9261120fd9b78cb80c435.html
5.6 其他功能
在這一節中,我們將介紹幾個非常有用的Eclipse功能。這些功能有助于您提高CVS和Eclipse的使用效率。
5.6.1 編輯器中的快速差別功能對CVS的支持
在本書第2章“Eclipse入門”中,您知道編輯
器所支持的快速差別功能可對文件的添加和修改操作加上注釋。如果您在Workbench | Editor | Quick
Diff首選項頁面中啟用了Latest CVS
Revision選項,那么快速差別功能所添加的文件注釋是在參考CVS中該文件最新版本的基礎之上添加的。在將更改提交到CVS或用CVS中該文件的某
一版本來替換該文件時,快速差別功能所添加的注釋會被刪除。
5.6.2 補丁程序:快速而又簡單地共享更改
補丁程序(patch)是一個包含了某一資源的資源庫實例和該資源的工作空間實例之間差別的文件。補丁程序可表示出一個單獨文件(或完整項目)中的差別。補丁程序允許您共享尚未提交到CVS的更改。有很多原因使得補丁程序非常有用。
● 由于您沒有向CVS提交資源的權限,所以您需要將該補丁程序發送給具有資源提交權限的人,然后再由他向CVS提交資源。
● 您需要為所遇到的問題準備一個應急修改或臨時工作空間。
● 在將重要的更改提交到CVS之前,您可能想讓別人對您的更改進行校驗。在這種情況下,您可以將補丁程序發送給校驗人以讓他們進行測試。
通過使用快捷菜單Team | Create
Patch…,我們就可以創建補丁文件。該操作會調用Create
Patch向導來指導您完成補丁文件的創建。若要應用某補丁程序,則使用快捷菜單Team | Apply Patch…。該操作會調用Apply
Patch向導。Eclipse聯機文檔Workbench User Guide的Working with patches
一節中有關上述兩個操作的描述非常精彩。
5.6.3 項目集:加快新工作空間
小組支持為工作空間中的項目(一個或多個)提供了版
本控制信息的封裝功能。該封裝功能被稱為項目集。項目集的目的是從執行任務所需的資源庫中把需要的全部項目都預先準備到一個工作空間中。在應用程序構建過
程中可能要用到存在相互依賴關系的多個項目。下述操作可能是單調乏味而又容易產生錯誤的:決定所需項目,然后再將這些所需的正確項目從資源庫中手動添加到
工作空間中。項目集是Eclipse的一個功能單元。資源庫提供程序可對是否支持該功能進行選擇(很多資源庫提供程序都會選擇是)。CVS對項目集提供了
支持。一個項目集所封裝的項目可能是由不同資源庫管理的。
項目集信息包含在一個文件中。若要創建該項目集信息
文件,則在菜單欄上選擇File | Export | Team Project Set選項。若要使用該項目集信息文件,則在菜單欄上選擇File
| Import | Team Project
Set選項。通過使用Export向導,我們可以對項目集中所包含的項目進行定義。出于通用的考慮,最終的項目集信息文件可被發送給別人以在CVS中進行
導入或維護。對于所開發的應用程序來說,您可以為其開發生命周期關鍵節點處的快照維護多個項目集文件。
在導入過程中,項目集文件中定義的所有項目都被從
CVS中自動檢出到您的工作空間中。在導入過程中,一種可能比較穩健的做法是禁用自動構建首選項設置(Workbench首選項頁面中的Build
Automatically設置)。通過禁用Build
Automatically設置,我們就可以在導入過程中避免編譯和構建操作,進而加快資源的導入。但在導入操作完成后,請記住要重新啟用該首選項。
5.6.4 斷開項目與CVS的連接或為項目重分派一個CVS資源庫
通過使用Team |
Disconnect…操作,您可以斷開項目與CVS的連接。在選擇了快捷菜單Team |
Disconnect…后會出現一個對話框。該對話框會對您進行詢問,以讓您對是否保存該項目的CVS元數據作出決定。如果選擇了保留該項目的CVS元數
據,那么通過使用Team | Share
Project…操作,我們就可以將該項目與同一CVS資源庫進行重新連接。如果您刪除了該CVS元數據,那么可以將該項目共享給其他資源庫。
作為選擇,如想將項目重新分派給另外一個CVS資源庫,那么您可以先為該項目打開CVS資源庫頁面,然后再選擇Change Sharing…按鈕。該操作與使用Disconnect…以及Share Project…操作在邏輯上等價。
作者:caoyinghui1986 發表于2009-8-28 21:58:00
原文鏈接
//原文地址:http://hi.baidu.com/xublog/blog/item/8265f309c5d35bc93ac76334.html
5.5 特殊情況及其處理
這里將給出一些您每天或在軟件開發周期中可能會碰到的常見情況,以及如何使用Eclipse來處理這些情況的建議。某些情況的解決可能需要使用CVS,但通常只使用Eclipse就可以處理它們。
5.5.1 對項目資源進行重命名、移動和刪除
●
避免重命名CVS控制之下的項目。如果您這樣做了,那么所做的命名修改只在該項目所處的工作空間中有效。保留在CVS中的仍是該項目的初始名。如果必須修
改項目的名稱,那么您最好先使用Team |
Disconnect…操作來解除該項目與CVS的關聯關系,然后再對該項目重命名。事實上,重命名后的項目會被看作是新項目。在將重命名后的項目重新連
接到CVS時,您必須像定義任何新項目一樣將該重命名后的項目定義到CVS中。
● 對文件夾的重命名操作會導致CVS中出現一個新文件夾。幸運的是,原文件夾中的內容會被移動到新文件夾中。如果您啟用了CVS首選項Prune empty directories,那么在從CVS檢出資源后,該舊文件夾將不會出現在您的工作空間中。
●
如果您將工作空間中的某資源刪除了,那么在向CVS提交了更改后,保存在CVS中的該資源也會被刪除。要記住的是文件夾決不會在CVS中刪除。CVS首選
項Prune empty directories使得這些文件夾隱藏在視圖中。默認情況下,CVS首選項Prune empty
directories是被啟用的。
● 因為修改可能會涉及多個項目,所以在進行全局修改前,您需要確保工作空間中的所有項目是資源庫中的最新版本。Java類的重構是一個可能導致工作空間被廣泛修改的操作。項目間的資源移動也可能產生這種影響。
● 在CVS透視圖中,項目之間資源移動的結果是:所要移動的資源添加到目標項目中,而源項目中的該資源會被刪除。移動到目標項目中的資源必須被添加到版本控制中。而資源重命名的效果與此相同。
●
在文件被修改后,如果您要執行諸如同步等CVS操作,那么我們建議您在項目層次上進行同步(即使您的更改可能僅涉及一個單獨文件)。例如,如果您對一個文
件進行了重命名這一CVS的刪除和添加操作,那么在文件層次上的同步將只會檢測添加操作而不檢測刪除操作。而項目層次上的同步則會對添加和刪除操作都進行
檢測。
● 在所進行的修改涉及整個應用程序的情況下,您應該將這次修改通知給自己所在的小組,以避免不必要的沖突。此時,一旦條件滿足,您就應該提交修改。沖突的解決可能是冗長乏味而又難以解決的。
5.5.2 取消修改:使用替換和比較操作
有時,我們都希望事情能夠重新開始。在人的一生中,
這可能不容易。但是對于Eclipse和CVS來說,這要簡單得多。根據您的需要,您有多種選擇。在先前的幾章中,您看到了如何使用快捷菜單操作
Replace With和Compare
With用工作空間中的本地歷史記錄來替換和比較資源。通過使用CVS,您對資源的替換和比較操作就有了額外的選擇。如果您尚未最終完成某個修改,而且之
后一段時間里根本就沒有繼續這次修改。這種情況下,Compare
With操作可能會非常有用,它會使您記起上次停止修改的地方。在使用上述Replace With和Compare
With操作時,您是用來自HEAD流(或者其他分支/版本、某一個具體版本)的最新資源來替換或比較當前資源的。
5.5.3 通過建立分支來進行版本維護和新版本開發
在小組已經交付了您的應用程序并準備開始下一個版本的開發工作時,您可能喜歡所有的后續開發能在下一版本所指派的特定分支處開始,同時還要允許先前版本的服務。這里所給出的就是在Eclipse中可用的一種方法。
●
在包含了最近已完成版本的分支(或HEAD)中,請選擇所有的項目。然后在所選項目上使用Branch…快捷菜單,并輸入該新版本的新分支名。這樣,所選
擇的全部項目以及這些項目的內容將用下一個版本分支名來標記。在CVS
Repositories視圖中,這些項目會被列在那個分支名之下。在從那個分支處將這些項目檢出到您的工作空間之后,接下來的操作是基于該新版本分支
的。
● 您可重復上述過程以創建一個單獨的維護分支。該維護分支獨立于上面所創建的新版本分支。
●
為了能以維護分支為基礎,在工作空間中對新版本分支進行合適的前向修改,您可以通過使用Compare With | Another Branch
or Version…操作來確定這兩個分支之間的差別。在Compare視圖中,您可以手動合并從維護分支到新版本分支的更改。
作者:caoyinghui1986 發表于2009-8-28 21:56:00
原文鏈接
//原文地址:http://hi.baidu.com/xublog/blog/item/8eab160264428f094afb512b.html
5.4.9 處理同一文件的并發更新
首先,我們討論一下一個被建議用來進行修改操作的協
議。當在工作空間中使用資源時,您的操作是獨立于CVS資源庫的。因為發生在資源庫中的更改可能是在您不知道的情況下發生的,所以非常重要的一點是,如果
還未檢查資源庫中是否有更新取代了您的更改,那么您一定不要提交任何更改。Team |
Update…操作會用資源庫中那些取代了您的更改的任何更改來更新項目的本地副本。對于文本文件(包括Java類)來說,Team |
Update…操作會自動對任何更改進行合并(從資源庫到工作空間),即使這些更改可能造成沖突。在遇到沖突時,合并操作會用特定的CVS標記文本來標識
文件中的沖突,以幫助您識別出沖突行。標記文本并不是與任何類型的文件都兼容,例如它可能導致編譯錯誤。
Update…
操作是一個非常強大的操作,我們在練習時一定要小心。在下面這個例子中,Pat和Lynn更新了一個簡單的文本文件。無需知道它,它們都對以“B”和
“C”開始的行進行了更新。標記文本會對沖突的那些行以及引入了沖突的版本號(1.2)進行了標識。對于一個帶有眾多沖突的復雜Java文件來說,您可能
很難解決其中的沖突。
A is for apple
<<<<<<< sample.txt
B is for bird (updated by pat
)
C is for crow (updated by pat
)
=======
B is for bobcat (updated by lynn
)
C is for cow (updated by lynn
)
>>>>>>> 1.2
D is for dog
E is for excellent
F is for farm
G is for goat...
Team | Synchronize with
Repository…操作也支持更新,但是該操作不會自動進行更新。在執行該操作后會顯示Synchronize視圖,并會列出工作空間副本和資源庫最
新資源之間那些不一致的資源。在Synchronize視圖中,您可以對這些差別進行檢查,并決定所要采取的操作。由于Team |
Synchronize with Repository…操作可使您擁有更多的控制權,所以我們建議您使用該操作來代替Update…操作。
下面總結一下文件并發更新的基本規則:在對工作空間
中的文件進行修改之前,您必須用資源庫中的所有更改來更新工作空間中的資源。為了安全起見,此時請使用Team | Synchronize with
Repository…操作。在Synchronize視圖中,您可執行更新操作,還可提交更改,并可協調沖突。
5.4.10 使用CVS的Watch/Edit支持以避免對同一文件的并行更新
CVS
的Watch/Edit支持是Eclipse本身就提供的。如果您同意使用CVS的Watch/Edit支持,那么在提交資源時,您和小組其他成員之間就
可以避免沖突。在啟用了CVS的Watch/Edit支持之后,您的項目小組可以更好地理解在所有具體項目中,當前誰正更新文件。相反,前面所討論的
CVS Annotate視圖為您所顯示的是先前的更改以及誰做的更改。CVS的Watch/Edit支持是在項目層次上被啟用的。如果在Team |
CVS >Watch/Edit的首選項設置頁面中選中了Configure projects to use Watch/Edit on
checkout復選框,那么在項目被檢出時,Watch/Edit支持將被自動激活。您也可以通過設置項目的CVS屬性在受CVS管理的現有項目上啟用
Watch/Edit支持。在CVS的Watch/Edit支持被啟用時,該項目中的文件處于只讀狀態。此時,如果您在編輯器中打開了某文件后又試圖對該
文件進行修改,那么CVS服務器會被詢問。在編輯文件時,如果其他人也正在編輯該文件,那么就會出現一個對話框以通知您小組中其他成員也正在編輯該文件
(見圖5-9)。這時,您可以繼續對該文件進行編輯,但是在您提交該文件時需要進行沖突管理。在文件被修改時,檢查標記修飾符
會被添加到該文件上。
圖5-9 顯示其他人正在編輯同一文件的對話框
在項目、文件夾以及文件上執行Team |
Show Editors操作后會打開CVS Editors視圖。CVS
Editors視圖中列出的是所有正在被其他人更新的資源(見圖5-10)。無論是否處于Watch/Edit的控制之下,您在任何項目及項目資源上都可
以使用Team | Show Editors操作。但是Team | Show
Editors操作只會對啟用了Watch/Edit支持的項目資源進行標識。
圖5-10 列出了哪個用戶正在更新文件夾中文件的CVS Editors視圖
您可以使用Team |
Edit操作來顯式地通知CVS服務器,讓CVS服務器知道您想對文件進行更新。您還可以使用Team |
Unedit操作來通知CVS服務器,讓CVS服務器知道您不想再編輯該文件。這樣,您所做的任何更改都會被從CVS資源庫中檢出。表5-3給出了有關這
些操作的信息。在向CVS提交了更改之后,Watch/Edit列表中的資源會被隱式刪除掉。
Watch/Edit是一個非常有用的工具。但是該
工具的使用需要遵循一些規則,并要注意一些考慮事項。首先,如果要使Watch/Edit功能高效,那么小組中的每個成員都必須在存在潛在沖突的項目中啟
動Watch/Edit功能。其次,您必須連接到CVS服務器上。如果您沒有和CVS服務器相連,并且想更新一個文件,那么您將不得不顯式地將該文件的只
讀狀態(從該文件的屬性頁面中可獲得該屬性)取消掉。當然,該支持現在是折中的。這是因為,沒有任何人知道該更新,而且在提交過程中存在潛在的沖突。如果
您刪除了一個項目并且該項目資源的Watch/Edit首選項設置沒有被啟用,那么CVS服務器將不會被通知,并且CVS服務器會繼續向外報告您正在對這
些資源進行編輯。如果您的小組計劃使用Watch/Edit支持,那么明智的做法是小組中所有人都啟用被標注為Configure projects
to use Watch/Edit on checkout的CVS Watch/Edit首選項設置。
5.4.11 恢復被刪除的文件
有時候,在文件被刪除并且更改被提交給CVS后,您
可能需要恢復所刪除的文件。幸運的是,CVS不會將所刪除的文件從該文件所在的資源庫中移除。您可以使用Team | Restore from
Repository操作來恢復所刪除的文件。如果被刪除的文件在資源庫中存在,那么您將看到一個對話框。在該對話框中,您可以選擇所要恢復的文件的具體
修訂版(見圖5-11)。而文件的最新修訂版則是一個對所刪除文件的引用。這是因為文件刪除是一個CVS修訂操作。
圖5-11 顯示可恢復的被刪除文件的Restore from Repository對話框
當一個文件被恢復到工作空間中的時候,該文件被看作是一個新文件。在提交該文件之前或提交該文件時,必須將該新文件添加到版本控制中。
5.4.12 其他CVS用戶界面元素
1. Checkout向導
在New wizard對話框中獲得的是CVS向導中的檢出項目。通常,您會使用CVS Repositories視圖來檢出項目。但是,有些CVS資源庫是不允許被瀏覽的。在這種情況下,檢出向導可能就比較有用。但是在這種情況下,您必須預先知道該項目的名稱。
2. CVS備忘單
若要打開Cheat Sheet Selection對話框,則選擇Help | Cheat Sheets…命令。對于CVS任務來說,備忘單用來為分支和合并操作提供幫助。
作者:caoyinghui1986 發表于2009-8-28 21:53:00
原文鏈接
//原文地址:http://hi.baidu.com/xublog/blog/item/6d090c22ffe227f5d6cae22b.html
5.4.3 CVS Annotate視圖
CVS
Annotate視圖與CVS Repository Exploring透視圖中的CVS
Repositories視圖使用的是同一界面空間。CVS Annotate視圖用來標識各版本文件中所添加的新行以及被更改過的行。CVS
Annotate視圖還會指出做出這次修改的是誰。現在您知道是誰做出了這些難以解釋的更新,或者是誰應該對這些難以解釋的更新負責。對于所選擇的任何版
本來說,文件中所添加的新行會在編輯器中突出顯示(見圖5-4)。若要打開CVS Annotate視圖,則從CVS
Repositories視圖、CVS Resource History視圖的快捷菜單Team中選擇Show
Annotation操作。打開CVS Annotate視圖的一種比較方便的方法是從Navigator透視圖或Package
Explorer視圖中所顯示的某一個文件上選擇Team | Show Annotation操作。在打開CVS Repository
Exploring透視圖時會打開CVS Annotate視圖,CVS Resource
History視圖,并且在編輯器中所打開的文件的版本是最新的。CVS
Annotate視圖中的選擇操作會將編輯器復位到被更新的代碼行,并且相應的版本會在CVS Resource
History視圖中突出顯示出來。相反,如果在編輯器中選擇了一行代碼,那么在CVS Repository
Exploring透視圖的那些視圖中就會適當地對所更改的對象進行突出顯示。現在您就可以非常容易地對任何文本文件的、詳細的更改歷史信息進行檢查。
圖5-4 CVS Repository Exploring透視圖中的CVS Annotate視圖
5.4.4 CVS Resource History視圖
CVS Resource
History視圖可顯示某一具體文件的所有版本的詳細信息(見圖5-5)。CVS Resource History視圖是CVS
Repository Exploring透視圖的一部分。在CVS
Repositories視圖中先選擇一個文件,然后再在單擊右鍵所出現的快捷菜單中選擇Show in Resource
History命令,這樣您就可以看到該文件的歷史版本信息。在受CVS控制的項目上單擊鼠標右鍵后所出現的Team快捷菜單項中也有Show in
Resource History命令。作為一種查看文件歷史的快速方法,您可以將受CVS控制的工作空間中的某一文件拖放到CVS Resource
History視圖以直接查看該文件的歷史信息。
圖5-5 CVS Resource History視圖
對于任何被選擇的修訂版本來說,與該修訂版本相關的
分支和版本標記,連同該版本的文件被提交到資源庫時所提供的注釋,都會一起顯示在CVS Resource
History視圖的底部(見圖5-5)。通過在CVS Resource
History視圖的下拉菜單中進行相應選擇,我們可以隱藏該視圖中的“Tags”項和“Comment”項。
文件的歷史記錄可能比較長,這時,您可以使用CVS Resource History視圖工具欄上的Filter History
按鈕來過濾CVS Resource History視圖。也可以根據作者、注釋值、日期變化等來對CVS Resource History視圖中的顯示內容進行過濾。CVS Resource History視圖工具欄上的Link with Editor操作
會使CVS Resource History視圖與當前活動編輯器(僅對CVS控制之下的文件)保持同步。
對于在CVS Resource History視圖中被選擇的那些版本來說,您對它們可以執行的操作是依賴于資源是否已被復制到工作空間而發生變化的。這些操作被列在表5-2中。
表5-2 CVS Resource History視圖中的操作
操 作
|
描 述
|
Compare
|
該操作會對所選的兩個版本進行相互比較
|
Get Contents
|
該操作會用所選版本的內容來替換該資源的本地工作副本中的內容
|
Get Sticky Revision
|
該
操作會將資源的本地工作副本還原為一個先前版本。本地副本會作為資源庫修訂版,并會保留相同的版本標記。需要指出的是,只有在對CVS非常熟悉的情況下,
您才可以使用該操作。該操作的后果之一是,除非“sticky
revision”標記被移走(直接使用CVS命令),否則您不能提交任何進一步的修改。當然,您可使用Replace With | Latest
from Repository操作返回到原版本。通常,除非您是一個熟練的CVS用戶,否則您可能不會對“sticky revision”標記感興趣
|
Open
|
該操作會在編輯器中打開所選的修訂版文件。這時,您是不能對該版本文件作出任何更改的
|
(續表)
操 作
|
描 述
|
Refresh View
|
該操作會用CVS資源庫中的內容來更新CVS Resource History視圖
|
Show Annotation
|
該操作會使Eclipe切換到CVS Repository Exploring透視圖,并使得CVS Annotate視圖變為當前焦點以顯示出所選文件的注釋
|
Tag with Existing…
|
該操作會將已有的資源庫版本或分支標記應用到所選的資源上。該操作是一個特殊的操作。請查看聯機幫助中的Moving Version Tags專題以獲得何時使用該操作的詳細信息
|
5.4.5 查看CVS命令
Eclipse
Console視圖可顯示出CVS與Eclipse之間的所有的命令和響應;在您碰到問題的時候,該視圖是非常有用的。在Eclipse
Console視圖中還顯示了所發布的供用戶使用的任何Eclipse CVS操作的所有CVS命令。在Team | CVS |
Console首選項頁面中,您可以對該控制臺的外觀和行為進行配置。
5.4.6 CVS是如何管理工作空間中項目的
圖5-6顯示了Package
Explorer視圖中一個處在CVS控制之下的項目。通過觀察圖標上的標記修飾符以及附加的文字信息,您可以很明顯地看出這一點。只有在啟用了
Workbench | Label Decorations首選項設置后,Eclipse才會在Package
Explorer視圖中顯示附加文字信息。對于那些受版本控制所有資源來說,在它們的資源圖標上都有一個很小的磁盤標志修飾符
。對于那些CVS所不知道的、被添加到項目中的文件來說,在這些文件的圖標中也有一個很小的標志修飾符
。
在如圖5-6所示的Package
Explorer視圖中,緊接著項目名后面的是該項目所屬CVS資源庫服務器的名稱(位于方括號中)。如果該項目是被作為一個分支部分來使用的,那么該分
支的名稱也會被包含在方括號中。文本修飾符>表明本地資源是一個傳出更改(outgoing
change),這就意味著該本地資源已經在本地修改過,并與CVS中相應內容不一致。Package
Explorer視圖中受CVS控制的文件夾(直至項目文件夾)也具有這個特征。資源名后面的圓括號中所顯示的文本表示的是該資源的文件格式(ASCII
格式或二進制格式)。我們知道,對于ASCII文件來說,在CVS文件實例和本地文件實例之間的并行修改可被合并。而二進制文件只能被替換。
圖5-6 Label Decorations首選項被啟用時受CVS控制的項目
在Team | CVS | Label Decorations首選項頁面中,您可以對CVS標簽修飾的表示和規則進行修改。
5.4.7 在Team快捷菜單中可獲得的CVS操作
Team菜單可從任何工作空間資源的快捷菜單中獲
得。有幾個CVS操作是與Team菜單相關的。我們將對使用CVS進行工作維護中最常用的操作進行總結。Team菜單下的具體子菜單隨著所選擇的是否是一
個項目而發生變化。只有在項目沒有被CVS或任何其他資源庫管理時,所選擇的項目才會有一個Share
Project…操作。表5-3所提供的是一個所有CVS小組操作的參考列表。其中有些操作可能是您不熟悉的。我們將在本章后面對這些操作進行討論。通常
情況下,您最常用的操作是Share Project…、Synchronize with
Repository…、Update…以及Commit…。Share
Project操作是一個允許您將項目加到CVS中的綜合性向導。從定義CVS資源庫連接到提交項目資源之間的每一個步驟都包括在該向導中。
表5-3 Team菜單中的CVS操作
操 作
|
描 述
|
Add to .cvsignore…
|
該
操作會將所選的項目文件排除在CVS管理之外。這些被排除的文件不會出現在Synchronize視圖之中,也不會被提交給CVS資源庫。CVS在您的項
目中維護了一個名為.cvsignore的文件。在該文件中會標識出那些被排除的文件實例。一開始,.cvsignore文件是不存在的;在該操作第一次
執行時,才會創建.cvsignore文件。您必須將.cvsignore文件添加到版本控制中,并在CVS中維護該文件
|
Add to Version Control
|
該操作會將所選文件置于CVS控制之下。典型情況下,在項目中創建新文件時會使用該操作。如果您沒有將資源顯式地添加到版本控制中,那么在執行提交操作時,Eclipse會對您作出提示
|
Apply Patch…
|
該操作將使用由Create Patch操作所創建的補丁文件來修補程序
|
Branch…
|
該操作會創建一個分支。這樣,項目(或所選資源)可獨立于其他開發過程而被修改
|
Change ASCII/Binary
Property…
|
執行該操作后會顯示Set Keyword Substitution向導。該向導允許您為所選文件選擇期望的CVS關鍵字替換模式。它對CVS如何解釋ASCII或二進制文件進行了定義
|
Commit…
|
如
果沒有沖突發生,該操作會使用您的本地更改來更新CVS資源庫,并會提示您給出一個注釋。如果執行該操作時所選擇的操作對象是一個項目或文件夾,那么項目
或文件夾中的所有被修改資源都將提交到CVS中。如果CVS中的相應文件取代了所要提交的文件,那么Commit…操作將失敗
|
Create Patch…
|
該操作會基于本地資源和CVS之間的不同而創建一個補丁文件。其他人可共享該補丁文件。這就允許在資源庫之外共享您的工作
|
Disconnect…
|
該操作會在所選工作空間項目中刪除所有CVS連接信息
|
(續表)
操 作
|
描 述
|
Edit
|
該
操作只可用于那些啟用了Watch/Edit(可在項目的CVS屬性頁面或CVS首選項設置中啟用該功能)的項目。該操作會通知CVS服務器,讓它知道您
正在更新該文件。如果有其他人(一個或多個)正在編輯該文件,那么您將被提示,以就是否繼續該操作作出決定。此時,您可忽略該提示并對文件進行修改。但
是,在您試圖對修改進行提交時可能會碰到沖突。如果您只是想先打開所要編輯的文件,那么該文件會被打開。但是在試圖對該文件進行修改時,您會得到相同的提
示。如果要使用外部編輯器,那么您首先必須要做的是取消該文件的只讀狀態,然后再使用外部編輯器打開該文件。在后面,我們會對該操作繼續進行討論
|
Merge…
|
該操作會將某一具體分支中的修改合并回該分支之前的代碼庫中
|
Restore from
Repository…
|
對于那些被刪除的項目文件來說,如果它們仍存在于項目中,并允許您將它們恢復回原工作空間,則執行該操作后會列出這些被刪除的文件。在本章后面,我們將會對該操作進行詳細討論
|
Share Project…
|
只有項目才能使用該操作。而且,只有在那些不受資源庫管理的項目上才可以看到該操作。執行該操作后會顯示向導。在該向導中,您可以完成的任務有:將項目與一個可以使用的資源庫相關聯,以及提交項目資源。其他資源庫提供程序也可能會使用該操作
|
Show Annotation
|
執行該操作后將切換到CVS Repository Exploring透視圖,并會將焦點集中到CVS Annotate視圖以顯示出所選文件的注釋
|
Show Editors
|
該
操作適用于那些啟用了Watch/Edit(可在項目的CVS屬性頁面或CVS首選項設置中啟用該功能)的項目中的文件夾和文件。在執行該操作后會打開
CVS編輯器視圖。在該視圖中會標識出其他正在編輯該文件或該文件夾中內容的用戶。只有那些啟用了Watch/Edit的項目才可能顯示在CVS編輯器視
圖中
|
Show in Repository
History
|
該操作為所選資源顯示CVS Repository History視圖
|
Synchronize with
Repository…
|
該
操作會將所選擇的文件與CVS資源庫中的對應文件進行比較,并切換到Team
Synchronizing透視圖。比較后所發現的任何差異都會顯示在Synchronize視圖中。對于項目或文件夾來說,在執行該操作時,它們里面所
包含的全部資源都將與CVS中的對應資源進行比較。而那些與CVS中對應資源相比發生了變化的資源會被顯示在Synchronize視圖中。在您檢查所有
更改、與資源庫實例進行比較,以及解決沖突時,這是一種最安全的CVS使用方法
|
Tag as Version…
|
該操作會為所選項目、文件夾(或文件)以及所有的子文件資源的所有CVS實例添加版本標志。您也可以在CVS Repositories視圖中進行版本標識
|
(續表)
操 作
|
描 述
|
Unedit
|
該
操作只可用于那些啟用了Watch/Edit(可在項目的CVS屬性頁面或CVS首選項設置中啟用該功能)的項目文件。該操作會將您從當前正在編輯某一文
件的那個用戶列表中刪除掉。執行該操作后,您會從當前活動用戶列表中被刪除,并且所做的任何更改都會被取消,而所編輯的文件會恢復到執行任何更新之前的內
容。在向CVS提交文件時,如果工作空間副本與服務器副本完全相同,那么Unedit操作會被隱式調用。在本章后面部分,我們還將對該操作進行討論
|
Update…
|
該
操作會使用CVS中所有最新版本來更新本地資源。CVS中的更新將與本地資源(二進制文件除外)進行合并。建議您在使用Commit…操作前執行
Update…操作。如果其他人在您的最近一次更新后又進行了提交操作,那么您的提交操作將會失敗。建議您用Synchronize with
Repository…操作來代替Update…操作
|
5.4.8 Team Synchronizing透視圖和Synchronize向導
Team
Synchronizing透視圖是您對工作空間與CVS(其他資源庫提供程序可被集成到Team
Synchronizing透視圖中)進行同步的大本營。在選擇了Team | Synchronize with
Repository…操作后,您會被提示并切換到Team Synchronizing透視圖。在Team
Synchronizing透視圖中含有Synchronize視圖和一個編輯器區域。所有被打開的編輯器都會顯示在該編輯器區域中。圖5-7所顯示的就
是一個Team
Synchronizing透視圖的例子。在Synchronize視圖中,您可以對本地項目和該項目的CVS副本之間的差別進行觀察和操作。其他想使用
該透視圖的資源庫提供程序也可使用該視圖。在打開一個文件的同時,Eclipse也會打開一個適當的比較編輯器(文本、Java、XML或圖像)。在比較
編輯器中會顯示出工作空間文件和CVS中該文件的最新版本之間的差別。這樣,您就可以在將文件提交到CVS之前瀏覽和最終確定該文件的內容。
在Synchronize視圖的工具欄上有如下一組按鈕:Incoming Mode
(從CVS中更新)、Outgoing Mode
(提交到CVS)、Incoming and Outgoing Mode
以及Conflicts Mode
。
通過使用上述按鈕,您可以對同步信息進行過濾。在使用了Incoming
Mode按鈕后,您會看到有哪些操作正在進行。如果小組中只有您一個人,那么可能只有Outgoing
Mode按鈕才是您感興趣的。若要接受所有的傳入更改,則使用Synchronize視圖工具欄上的Update All Incoming
Changes…按鈕
。若要提交您的所有更改,則使用Synchronize視圖工具欄上的Commit All Outgoing Changes…按鈕
。工具欄操作Pin Current Synchronization
允
許您對先前同步中所使用的一組資源進行引用。Synchronize視圖的工具欄上的這些按鈕允許您通過工作集來過濾內容。您可對比較標準進行調整,并可
使用Layout菜單在樹、壓縮文件夾以及提交集(Commit
Set)之間進行視圖切換。提交集允許您查看資源庫更改。這些更改會按照提交者、注釋和提交日期來分類顯示。在確定傳入更改集的更詳細信息時,這種分類非
常有用。Synchronize視圖擁有自己的Preferences對話框。在Synchronize視圖的菜單中,您可以打開該
Preferences對話框。在Synchronize視圖的菜單中,您還可以執行Schedule…操作。該操作允許您按照所選擇的某一重復進度來自
動執行資源庫的同步操作。
圖5-7 顯示傳入更改和傳出沖突文件三方比較的Team Synchronizing透視圖
1. Synchronize向導
從工作臺工具欄(或Synchronize視圖菜單欄)的下拉菜單中選擇Synchronize…操作
后
會出現Synchronize向導。在Synchronize向導中,您可以對要與CVS(以及其他那些被允許使用Eclipse小組同步支持的資源庫提
供程序)進行同步的項目進行選擇。如圖5-8所示,您可對工作空間、所選資源或者一個工作集進行同步。在Synchronize向導結束后,您會返回到
Team Synchronizing透視圖。
作者:caoyinghui1986 發表于2009-8-28 21:50:00
原文鏈接
//原文地址:http://hi.baidu.com/xublog/blog/item/b66d38afeb3688ca7dd92a2a.html
Eclipse中的CVS用戶界面
現在,您已經對CVS有了一個基本的理解。接下來,
我們將討論Eclipse是如何為CVS使用者提供幫助的。在對其進行討論之前,先略為詳細地看一下Eclipse的CVS用戶界面。在開始之
前,Eclipse的CVS用戶界面是毫無價值的。這是因為,與Eclipse中的很多操作相似,大多數的CVS資源庫訪問操作都在后臺運行,這些操作不
會對其他操作造成妨礙。諸如檢出、提交、同步等可能需要長時間運行的操作并不會對您所要完成的其他任務造成妨礙。在下面所給出的這個簡短列表中,列出了在
Eclipse用戶界面中使用CVS時會碰到的最常見任務。在練習5中,您會實踐所有這些任務。
● 定義到CVS資源庫的連接。
● 瀏覽CVS資源庫。
● 將新的工作空間項目定義到CVS中。
● 從CVS中檢出已有項目。
● 將工作空間中的更改提交給CVS。
● 使用CVS中的最新版本來更新自己的工作空間項目。
● 在合適的里程碑處進行版本設置。
● 用資源庫中的資源來比較或替換工作空間中的資源。
5.4.1 CVS Repository Exploring透視圖:資源庫主頁
如圖5-1所示的CVS Repository
Exploring透視圖是在Eclipse中使用CVS的大本營。在該透視圖中含有CVS Repositories視圖、CVS Resource
History視圖以及編輯器區域。在CVS Repositories視圖中會顯示出您的工作空間所知道的CVS資源庫。而在CVS
Resource History視圖中所顯示的則是受CVS控制的任何已知文件的修改歷史記錄。在CVS Repository
Exploring透視圖中,您可以建立與CVS服務器的連接。
5.4.2 CVS Repositories視圖
CVS
Repositories視圖扮演著資源庫瀏覽器的角色。在CVS
Repositories視圖中,您可以對資源庫中存在的項目進行選擇,并可將這些項目檢出到工作空間中。如圖5-1所示,CVS
Repositories視圖位于CVS Repository Exploring透視圖的左邊窗格中。通過使用快捷菜單New |
Repository Location...或選擇Add CVS Repository
命
令,您可以在自己的工作空間中定義CVS資源庫的位置。Eclipse支持各種類型的CVS連接(見圖5-2)。在CVS
Repositories視圖中,您可以定義多個CVS資源庫。在瀏覽資源庫時,您可以看到資源庫中的內容。如圖5-1所示,這些內容包括HEAD、
Branches、versions目錄中的項目以及Dates條目。您可展開目錄樹或使用工具欄中的Go Into
和Back
操作來往下一直看到具體文件。在工具欄上有一個Refresh View
操作,由于CVS Repositories視圖不會與資源庫中的內容更改自動保持一致,所以在做任何重要操作之前,您可能要使用Refresh View
按鈕來刷新CVS Repositories視圖。
出于方便的考慮,如果您從Resource透視圖中打開了CVS Repositories視圖,那么該視圖將作為一個選項卡式視圖顯示在Navigator透視圖的旁邊。
在CVS Repositories視圖中,一個最常見的任務是從資源庫中將項目檢出到您的工作空間中。要完成上述任務,請先在Branches、HEAD或Versions下選擇一個項目,然后再在單擊鼠標右鍵后所出現的快捷菜單中選擇Check Out命令。
圖5-1 CVS Repository Exploring透視圖
圖5-2 在工作空間中定義新的CVS資源庫位置
在第一次展開CVS
Repositories視圖中的Branches目錄時,您會看到該目錄中沒有任何內容。在使用了快捷菜單操作Refresh
Branches…后會出現Refresh Branches對話框(見圖5-3)。在Refresh
Branches對話框中,您可以為一個或多個資源庫項目執行CVS中的分支標記檢索請求。CVS資源庫中可以包含大量分支。而您可能僅對其中的部分分支
感興趣。在Refresh Branches對話框中,您可以對要進行分支標記信息檢索的項目進行選擇。在表5-1所示的參考列表中,列出了CVS
Repositories視圖中的所有可用的快捷菜單操作。其中有些操作依賴于您在圖5-3的第3個欄目中的選擇。一開始,您可能需要使用以下這些操
作:New | Repository Location…、Check Out…、Compare with…以及Show in Resource
History。現在,您不必理解這些操作,它們僅為您提供一個參考。
圖5-3 Refresh Branches對話框
表5-1 在CVS Repositories視圖中可使用的上下文操作
操 作
|
描 述
|
從快捷菜單中可獲得該命令
|
Add to Branch
List…
|
將一個項目(但不包括該項目的內容)添加至一個新的或已經存在的分支上。該操作可代替Team | Branch操作。對于那些將在一個分支中單獨開發的新項目來說,該操作是比較有用的
|
被選擇的項目
|
Check Out
|
把從資源庫中所選擇的內容復制到自己的工作空間中。而且文件夾可被檢出,同時該文件夾與項目的一致性會得到維護。對于含有獨立部分的大型項目來說,該操作非常有用
|
被選擇的項目,以及在Branches、HEAD或Versions下所選擇的項目文件夾
|
Check Out As…
|
把從資源庫中所選擇的內容復制到自己的工作空間中,并以另外一個名稱來命名。在對所做的更改進行提交時,該項目保持它在CVS中的初始一致性。當需要在工作空間中同時擁有某一項目的多個實例時,該操作非常有用
|
被選擇的項目,以及在Branches、HEAD或Versions下所選擇的項目文件夾
|
(續表)
操 作
|
描 述
|
從快捷菜單中可獲得該命令
|
Compare
|
在選擇了兩個資源庫文件后,執行該操作會顯示出Compare視圖
|
兩個被選擇的資源庫
|
Compare With…
|
該操作會打開Compare with Branch or Verson對話框,并允許您將所選資源與Branches、HEAD或Versions中的資源進行比較
|
被選擇的資源
|
Configure Branches and
Versions…
|
執行該操作后將顯示出一個對話框。在所顯示的對話框中會顯示出資源中的分支或版本標記。而對話框中所顯示的那些標記會顯示在CVS Repositories視圖中
|
各種對象
|
Copy to Clipboard
|
將連接字符串復制到寫字板上。例如:pserver: anonymous@dev.eclipse.org:/home/eclipse
|
被選擇的資源庫
|
Discard location
|
從CVS Repositories視圖中刪除所選資源庫的位置定義
|
被選擇的資源庫
|
New | Date Tag…
|
執行該操作后會顯示出一個對話框以創建新的日期標記
|
被選擇的資源庫,在CVS Repositories視圖中所選擇的Dates條目
|
New | Repository Location…
|
執行該操作后將顯示出一個對話框以定義新的CVS資源庫位置。另外還可獲得一個工具欄圖標
|
任何對象
|
Open
|
執行該操作后會在編輯器中打開所選文件的最新版本
|
被選擇的文件
|
Properties
|
顯示所選資源庫的屬性及其連接信息
|
被選擇的資源庫
|
Refresh Branches…
|
執行該操作后將顯示出一個對話框以允許您發現一個或多個項目的分支
|
在CVS Repositories視圖中所選擇的Branches條目,被選擇(或沒有被選擇)的資源庫位置
|
Refresh View
|
使用資源庫的當前信息來刷新CVS Repositories視圖
|
各種對象
|
Remove
|
將所選的日期標記從CVS Repositories視圖刪除掉
|
被選擇的日期標記
|
Show Annotation
|
該操作會為所選文件顯示CVS Annotate視圖
|
被選擇的文件
|
Show In Resource History
|
該操作會在CVS Resource History視圖中顯示所選文件的版本歷史信息
|
被選擇的文件
|
Tag As Version…
|
將一個版本標記應用到所選的資源及其子資源上
|
被選擇的資源
|
Tag With
Existing…
|
該操作會將一已有的資源庫版本或分支標記應用到所選的資源上。這是一個比較特殊的操作。有關何時使用該操作的更多信息請參見聯機幫助中的Moving Version Tags專題
|
被選擇的資源
|
作者:caoyinghui1986 發表于2009-8-28 21:47:00
原文鏈接
原文地址:http://hi.baidu.com/xublog/blog/item/6579e60e8364fdcc7bcbe19e.html
版本控制在團隊開發中是必不可少的。CVS是優秀的開源版本控制軟件,Eclipse本身就內置了對CVS的支持,只需簡單配置,即可使用CVS。
首先我們要正確安裝并配置好CVS服務器,通常Linux Server都自帶CVS服務,不過命令行操作比較繁瑣。Windows下也有簡單易用的CVS服務器,這里我們推薦CVSNT,可以下載CVSNT 2.0.51a,安裝并啟動CVSNT:
然后切換到Repositories面板,添加一個Repository,命名為/cvs-java,CVSNT會提示是否初始化這個Repository,選擇是:
然后在Advanced面板上選中“Pretend to be a Unix CVS version”:
然后,在Windows賬戶中為每一個開發人員添加用戶名和口令。
現在,CVSNT的安裝配置已經完成,下一步,啟動Eclipse,我們可以使用原有的Hello工程,或者新建一個Project,然后選擇菜單
Window->Show View->Other,打開CVS->CVS Repositories:
然后點擊按鈕
,添加一個Repository:
注意用戶名和口令直接填Windows的用戶名和口令,然后選中“Validate Connection on Finish”,點擊Finish完成:
首先,我們要將一個現有的工程放到CVS服務器中,切換到Package Explorer,選中Hello工程,右鍵點擊,選擇Team->Share Project…:
使用剛才我們添加的Repository,繼續,并將所有文件都添加到CVS中,最后Eclipse提示Commit:
填入一個簡單的注釋,確定,然后Eclipse會把整個工程提交到CVS服務器,可以在Package
Explorer中看到圖標發生了變化,Hello.java文件后面會有版本號1.1。在CVS
Repositories面板中刷新,可以看到剛添加進來的工程:
在團隊開發中,當創建了一個基本的工程并提交到CVS后,別的開發人員首先要Check
Out這個工程到各自的本地計算機上,這里為了演示,首先我們在Package Explorer中刪除Hello工程,然后打開CVS
Repositories(如果沒有看到Repository就按照上面的方法添加Repository),選擇Hello工程,右鍵點擊,選擇
Check Out As…:
作為一個Project簽出,就可以在Package Explorer中看到簽出的工程。
當對某些源文件作了修改后,需要提交更改到CVS服務器。選中更改的文件或工程,右鍵點擊,選擇Team->Commit…:
然后填入簡單的注釋,就可以提交到CVS服務器上了,可以看到源文件的版本號變成了1.2。
以上簡單介紹了如何搭建CVS服務器以及在Eclipse中如何使用CVS,可以參考CVS手冊以便了解Branch、Merge等更多功能的使用。
作者:caoyinghui1986 發表于2009-8-28 21:40:00
原文鏈接
曾因項目的迫切需要計劃開發一打包軟件,最終卻夭折。現在回想多有遺撼。不得不令我反思當中的教訓。
我認為要想開發一個成功的軟件兩個大的環境是必不可少的,一個是外部環境,包括公司的支持,領導的鼓勵和擁有一個穩定的,成熟的項目團隊,相對穩定的用戶群體。還有一個是對軟件本身的規劃,包括對需求的明確,系統的架構,工作量的評估,明確的項目計劃和有序的計劃執行。
打包工具的失敗就是一個印證。
打包工具的構想是源于項目中,繁鎖的,重復的人工打包操作,包括從配置庫一下代碼,編譯,打包,上傳FTP等操作,由于打包后進行問題驗證時又時常出問題,所以該過程不得反復多次執行。執行過程中又難免出現放錯文件,漏打文件等不必要的錯誤從而嚴重影響項目進度。
打包工具就是為解決打包過程中的繁鎖操作,提供可視化界面,為打包提供一鍵式操作。一開始構想時好的。但是一開始也是錯的,因為打包工具一開始就缺乏一個可供運作的外部環境。公司不知道有這個項目的存在,或許還稱不上是一個項目,因為它只是我個人提出的一個優化項目流程的簡單方案。但是也由于這個問題,為項目的失敗埋下了一個定時炸彈。
開始對項目進行簡單的規劃后,包括簡單的需求分析,系統的架構。沒有正式的文檔,也沒有對文檔進行評審和風險評估。就開始著手開發了。開發過程中不斷的變更架構(因為一開始就沒有一個好的架構),不斷的變更需求(雖然需求是自己做的),沒改一個地方,對代碼都是翻天覆地的變化,當中的辛酸或許只有我自己才能體會。先拋開架構不說,為什么自己做的需求,自己開發,需求都還會變呢?那是因為在開發過程中,你站在用戶的角度一想,發現那樣做確實不當,得改。這就告訴我們問題越早發現,就越容易被解決。想想如果該需求是在需求文檔中詳細體現出來,在需求評審的時候被發現,那改改文檔也就了事了,等到了開發時才發現這個問題,想想那個時候去改那又會有多大的改動。這也告訴我們好的文檔不僅能有效的指導開發,提高質量。也能更及時的發現問題,避免不必要的改動。更是后期維護升級的一個依據。
當然這些變化還不足以讓一個項目夭折。打包工具一開始規劃其中一部份包含了對開發人員的代碼進行檢視等功能,但由于公司推出了一個工具已經具備這一功能,使得打包工具的這一需求已不在具備這一用戶群體。所以穩定的用戶群體在一個軟件開發過程中也是一個不可忽視的環節。
在項目開發到中期,我被分配到一個實際項目中,由于沒有多余的時間來做這個不被重視的工具,打包工具開始慢慢夭折。從這個事分析,我個人其實也算是這個項目的一個穩定項目團隊。我被分配到其它項目中就算是為這個穩定的團隊帶來了不穩定因素。結果導致項目夭折。可見一個穩定的,成熟的項目團隊在項目中的重要性。
這個項目雖然失敗了,但我從中吸取了很多教訓。如果再給我一次機會來做這個項目,有幾個事情我必須得做。
1,向公司審請,將該項目作為公司內部項目正式立項。確保有一個穩定的外部環境。
2,向廣大用戶(開發人員)收集需求,整理形成軟件的基本規格。
3,明確制定項目計劃,有組織,有目地的進行研發。
4,根據基本規格編寫需求文檔,明確功能點,進行大眾評審,及時發現問題。
5,制定詳細的架構規劃。進行評審。
6,協調有扎實功底的開發人員,確保技術難題被攻破
7,協調有豐富經驗的測試人沒,保證版本質量
作者:caoyinghui1986 發表于2009-8-28 21:27:00
原文鏈接
Create DataBase SHOPPING;
go
use SHOPPING;
go
/*==============================================================*/
/* Table: CATEGORIES */
/*==============================================================*/
create table CATEGORIES (
CATEGORY_ID bigint identity,
CATEGORY_NAME varchar(100) not null,
CATEGORY_DESCN varchar(500) null,
constraint PK_CATEGORIES primary key (CATEGORY_ID)
)
go
/*==============================================================*/
/* Table: PRODUCTS */
/*==============================================================*/
create table PRODUCTS (
PRODUCT_NO varchar(10) not null,
CATEGORY_ID bigint not null,
PRODUCT_NAME varchar(300) not null,
PRODUCT_PRICE float not null,
PHOTO_PATH varchar(100) null,
PRODUCT_DESCN varchar(2000) null,
constraint PK_PRODUCTS primary key (PRODUCT_NO)
)
go
/*==============================================================*/
/* Table: PRODUCT_SUPPLY */
/*==============================================================*/
create table PRODUCT_SUPPLY (
SUPPLY_NO varchar(10) null,
PRODUCT_NO varchar(10) null
)
go
/*==============================================================*/
/* Table: SUPPLIERS */
/*==============================================================*/
create table SUPPLIERS (
SUPPLY_NO varchar(10) not null,
SUPPLY_NAME varchar(200) not null,
SUPPLY_DESCN varchar(400) null,
constraint PK_SUPPLIERS primary key (SUPPLY_NO)
)
go
/*==============================================================*/
/* Create Relation */
/*==============================================================*/
alter table PRODUCTS
add constraint FK_PRODUCTS_REFERENCE_CATEGORI foreign key (CATEGORY_ID)
references CATEGORIES (CATEGORY_ID)
go
alter table PRODUCT_SUPPLY
add constraint FK_PRODUCT__REFERENCE_PRODUCTS foreign key (PRODUCT_NO)
references PRODUCTS (PRODUCT_NO)
go
alter table PRODUCT_SUPPLY
add constraint FK_PRODUCT__REFERENCE_SUPPLIER foreign key (SUPPLY_NO)
references SUPPLIERS (SUPPLY_NO)
go
創建數據庫腳本的
PRODUCTS(產品表) 和 CATEGORIES(類別表)一對多 PRODUCT_SUPPLY 為中間表 SUPPLIERS(供貨商表) 和 PRODUCTS 為多對多的關系。
products 表 hbm.xml
<many-to-one name="category" class="Category" cascade="save-update">
<column name="CATEGORY_ID" />
</many-to-one>
<!--多對多的關系中table指向的是中間表-->
<set name="supplys" table="PRODUCT_SUPPLY" cascade="save-update">
<!--key指向的是外鍵-->
<key column="PRODUCT_NO"></key>
<!--column對應中間表中的外鍵-->
<many-to-many class="Supply" column="SUPPLY_NO"></many-to-many>
</set>
category 表 hbm.xml
<set name="productes" table="productes" cascade="save-update" inverse="true">
<!--key指向的是外鍵-->
<key column="CATEGORY_ID"></key>
<one-to-many class="Product"/>
</set>
supply 表 hbm.xml
<set name="products" table="PRODUCT_SUPPLY" inverse="true" cascade="save-update">
<key column="SUPPLY_NO"></key>
<many-to-many class="Product" column="PRODUCT_NO"></many-to-many>
</set>
1, 添加一個的新商品名稱為”Compaq 2620” 該商品屬于“筆記本”類別 由當前所有的提供商提供貨源
List list = session.createQuery("from Supply").list(); Category c = (Category) session.get(Category.class, new Long(1)); product.setCategory(c); product.setSupplys(new HashSet(list)); session.save(product);
2, 查詢編號為” S0001”的提供商提供的所有商品 //通過隱式內連接導航 List list = session.createQuery("from Product p where p.supplys.supply_no='S0001'").list(); 隱式內連接導航 要注意的一個問題是 從many端到 one 端 可以無限導航 但從one到many端只能導航一級
3,查詢編號為”S0002”的提供商提供的所有商品所涉及的類別 session.createQuery("from Category c where c.productes.product_no in (select p.product_no from Product p where p.supplys.supply_no='S0002' ) ").list(); 用到子查詢
4,查詢名稱為”TCL SHE8533”的商品的每個提供商的編號、名稱(部分屬性查詢) session.createQuery("select s.supply_no,s.supply_name from Supply s where s.products.product_name='TCL SHE8533'").list(); //投影查詢。如果想將查詢出來的 結果封裝成對象 用 select new package.Temp(s.a,s.b...) from .... Temp提供相應的構造方法包含可選的字段注意帶包名。
5, 查詢多于3種商品的類別信息(使用size函數處理) session.createQuery("from Category s where s.productes.size>3").list(); 注意其中的 size 表示的是 商品類別中產品數量多于3的類別。size用來處理集合中的大小
6,查詢至少有一個商品的類別信息(使用exists處理) session.createQuery("from Category c where exists( from c.productes) ").list();
7,查詢可以提供某種商品的供應商信息(使用elements處理) session.createQuery("from Supply s where :product in elements(s.products) ")..setParameter("product", product).list(); product為 一個 對象 。 product in elements(s.products) 表示這個對象是否在這個集合中
8,使用本地SQL,顯示所有商品的商品名、價格以及類別信息,并降序排列。 session.createSQLQuery("select p.PRODUCT_NAME,p.PRODUCT_PRICE ,c.* from PRODUCTS p ,CATEGORIES c where p.CATEGORY_ID = c.CATEGORY_ID order by p.PRODUCT_PRICE desc") 的到的 集合中是個 Object[]; 如果想返回對象 可以用 命名sql并在配置文件中指定返回的對象類型。
9 分頁查詢 :將商品按價格升序排列后,取第三頁的記錄,(每頁顯示2條記錄) Query query = session.createQuery("from Product p order by p.product_price ") .setFirstResult(2*(3-1)) .setMaxResults(2);
10,查詢所有類別的名字,及該類別包含的商品數量 (使用group by ,count函數) session.createQuery("select max(c.category_name), count(p) from Category c inner join c.productes p group by c.category_id ") 還有一種簡單的方式就是 "select c.category_name, c.products.size from Category c "
11,批處理: 將某個類別下的商品修改為現有的另一個類別。 int count = session.createQuery("update Product p set p.category=:category where p.category.category_id='1'") .setParameter("category",c ).executeUpdate(); c為加載的一個新的類別
12,往數據庫中初始化3個名稱相同的商品(其他字段自行設置)。 要求:查詢所有商品,如果多個商品的名稱相同,則取其中任意一個完整的商品信息
hql = "from Prodcut pp where pp.product_no in (select max(p.category_id) from Product p group by p.product_name") ; 注意后面的一個 小技巧。 由于group by 后只能包含 group by字段和聚合函數 所以如果我想區別的字段似乎不可能 。但我們不妨將你要取的那個字段也加個聚合函數min 或 max 這樣就可以取出你要的 任意字段了。適應sql sql2000中不妨 在pubs 下運行 select max(title_id) as 編號 ,count(type) as 數量, type from titles group by type 看看結果就知道了 雖然只 group by 了 type但 還是可以得到title_id
作者:caoyinghui1986 發表于2008-6-15 12:39:00
原文鏈接
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <script> //供DEMO02_01頁面的關閉按鈕調用 function myFunction(v){ //alert("這里是父窗口中的函數"+v); document.getElementById("parentText").value=v; }
//打開新窗口 function openNewWindow(){ window.open("DEMO02_01.html","","height=300;width=300;location=0;status =0;toolbar=0");
}
</script> </head>
<body>
<button onclick="openNewWindow();">打開新窗口</button> <hr> 此文本框的值要從子窗口中取得 <input type="text" id="parentText"> </body> </html>
DEMO02_01.html
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <script> function funClose(){ //:調用父窗體(DEMO02.html)中的myFunction 函數 //window.opener獲得父窗口的window對象的引用 并調用 myFunction () 函數在js中作為window的屬性 window.opener.myFunction(document.getElementById("childText").value);
window.close(); } </script>
</head>
<body> <button onclick="funClose();">關閉本窗口</button> <hr> 此文本框的值將要傳遞到父窗口 <input type="text" id="childText" value="子窗口的值:1"> </body> </html>
作者:caoyinghui1986 發表于2008-6-15 12:31:00
原文鏈接
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<script>
//補充完成下邊的函數,打開新的一個模式窗口
function openShowModalDialog(){
var obj = window;
var params = new Array("aaaa",obj);
var returnValue = window.showModalDialog("DEMO04_01.html",params);
document.getElementById("showContentDiv").innerHTML=returnValue;
}
</script>
</head>
<body>
<h1>模式窗口的使用:</h1>
<h3>補充完成openShowModalDialog函數,打開新的一個模式窗口</h3>
<button onclick="openShowModalDialog();">打開新的模式窗口</button>
<br>
<hr>
<div id="showContentDiv">
</div>
</body>
</html>
DEM004-01.html
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<script>
//補充完成函數,將文本框returnValue的值設置為父窗口返回值,并關閉本窗口
function closeShowModalDialog(){
//獲得模式窗體的參數。
var p = window.dialogArguments;
window.returnValue=document.getElementById("returnValue").value;
//設置父窗體的返回值 p[1] 事實上是拿到了父窗體的引用
p[1].returnValue=document.getElementById("returnValue").value;
window.close();
}
</script>
</head>
<body>
<h1>模式窗口的使用:</h1>
<h3>補充完成closeShowModalDialog函數,將文本框returnValue的值設置為父窗口返回值,并關閉本窗口</h3>
<button onclick="closeShowModalDialog();">設置返回值,并關閉窗口</button>
<hr>
窗口的返回值
<input type="text" id="returnValue" value="在這里設置返回值">
</body>
</html>
作者:caoyinghui1986 發表于2008-6-15 12:27:00
原文鏈接
DEM003.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<frameset rows="70,*" cols="*" framespacing="0" frameborder="yes" style="border:0px">
<frame src="DEMO03_bar.html" name="bar" scrolling="No" noresize="noresize" id="bar"arginwidth="0" marginheight="0" />
<frameset cols="150,*" frameborder="yes" border="1" framespacing="0">
<frame src="DEMO03_menu.html" name="menu" scrolling="No" noresize="noresize" id="menu" marginwidth="0" marginheight="0" />
<frame src="DEMO03_main.html" name="mainFrame" id="main" marginwidth="0" marginheight="0" />
</frameset>
</frameset>
<noframes><body>
</body>
</noframes></html>
DEM003_bar.html
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<script>
//補充完成此函數,用于刷新Menu窗體的頁面
function flushMenuFrame(){
//top表示頂級窗口 的 window對象
window.top.menu.location.href="DEMO03_menu.html";
}
//補充完成此函數,將barText文本框的值寫入到Main窗口的mainText中去。
function writeValueToMainFrame(){
//parent表示 但前窗口的 上級窗口的 window對象
window.parent.mainFrame.document.getElementById("mainText").value=document.getElementById("barText").value;
}
</script>
</head>
<body>
<center>BAR頁面</center>
<button onclick="flushMenuFrame();">刷新框架Menu窗口的頁面</button>
Bar頁面的文本框:<input type="text" id="barText" value="Bar頁面的值1"><button onclick="writeValueToMainFrame();">向Main窗口寫值</button>
</body>
</html>
DEMO003_main.html
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
</head>
<body>
<center>Main窗體</center>
<br><br>
Main窗體中的文本框
<input type="text" id="mainText" value="Main頁面的值2">
</body>
</html>
作者:caoyinghui1986 發表于2008-6-15 12:24:00
原文鏈接
實現功能是 用戶本地瀏覽一個圖片后(本來要用上傳 為簡單起見就制作本地測試) 功過Hibernate中向數據庫插入圖片 并在另一個頁面把這個圖片顯示出來
index.jsp
<body>
<form name="frm" action="imgServlet" method="post">
<input type="file" name="path"/>
<input type="submit" value="提交">
</form>
</body>
一個簡單的表單用于瀏覽圖片
Img.java
public class Img implements java.io.Serializable {
// Fields
private Integer id;
private byte[] img;
......
}
Img.hbm.xml
<hibernate-mapping>
<class name="hib.Img" table="img" schema="dbo" >
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<property name="img" type="binary">
<column name="img" not-null="true" />
</property>
</class>
</hibernate-mapping>
servlet中的處理方式 (web.xml 中 <url-pattern>/imgServlet</url-pattern> 對這個servlet的配置)
public void doPostt(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
//PrintWriter out2 = response.getWriter();
//servlet 中 out 對象只可取一次.
//如果要用與輸出二進制數據 . 就必須用 OutputStream 對象.
OutputStream out = response.getOutputStream();
request.setCharacterEncoding("UTF-8");
String path = request.getParameter("path");
java.io.File file = new File(path);
InputStream inputStream = new FileInputStream(file);
byte[] buff= new byte[(int) file.length()];
inputStream.read(buff, 0, (int) file.length());
Img img = new Img();
img.setImg(buff);
Session session = HibernateSessionFactory.getSession();
session.save(img);
session.beginTransaction().commit();
String realPath = request.getSession().getServletContext().getRealPath("/");
System.out.println("realPath"+realPath);
System.out.println("path:"+path);
System.out.println("插入成功!!!");
try {
//將圖片寫入到輸出流中
out.write(img.getImg());
} catch (Exception e) {
e.printStackTrace();
}
//request.getRequestDispatcher("show.jsp").forward(request, response);
response.sendRedirect("show.jsp");
out.flush();
out.close();
}
show.jsp
<body>
<img src="imgServlet"/>
</body>
通過提交就可以在 show.jsp看到用戶提交的圖片并且改圖片保存到了數據庫
作者:caoyinghui1986 發表于2008-6-6 14:52:00
原文鏈接
每次在CSDN回貼的時候都會遇到好多關于連接池的貼。自己在測試的時候也發現這個東西,有時候確實比較麻煩。干脆就花了一點時間把他們總結了
一下.
我機器的環境是 Eclipse3.2 + tomcate5.5+ JDK1.5 +sqlserver2000
測試前 首先要確保 sql2000 打了spk3,spk4補丁包。
struts中c3p0 連接池的配置。
<data-sources >
<data-source key="ds" type="com.mchange.v2.c3p0.ComboPooledDataSource">
<set-property property="driverClassName" value="com.microsoft.jdbc.sqlserver.SQLServerDriver" />
<set-property property="url" value="jdbc:microsoft:sqlserver://localhost:1433;databasename=pubs" />
<set-property property="maxCount" value="10"/>
<set-property property="minCount" value="1"/>
<set-property property="username" value="sa" />
<set-property property="password" value="" />
</data-source>
Action中獲得這個連接的方式。
DataSource ds = this.getDataSource(request,"ds");
struts中dbcp 連接池的配置
<data-source key="dsDBCP" type="org.apache.commons.dbcp.BasicDataSource">
<set-property property="driverClassName" value="com.microsoft.jdbc.sqlserver.SQLServerDriver" />
<set-property property="url" value="jdbc:microsoft:sqlserver://localhost:1433;databasename=pubs" />
<set-property property="maxCount" value="10"/>
<set-property property="minCount" value="1"/>
<set-property property="username" value="sa" />
<set-property property="password" value="" />
</data-source>
使用 dbcp 連接池 時除了要注意 導入必要的 3個連接池驅動包外 還要引入sql的三個驅動包。
-------------------------------------------------------------------------------------------------------------------------------
Spring中dbcp 連接池的配置
jdbc.properties
jdbc.driverClassName=com.microsoft.jdbc.sqlserver.SQLServerDriver
jdbc.url=jdbc:microsoft:sqlserver://localhost:1433;databasename=pubs
jdbc.username=sa
jdbc.password=
jdbc.properties 文件來定義連接信息。
在 dbcpPoolBean.xml文件中的bean配置。
<bean id="aa" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- 對與單個文件 這里可以直接用 location屬性 然后給一個 value單值 原因是因為在其 父類的實現中
PropertiesLoaderSupport 有個 setLocation方法.
public void setLocation(Resource location) {
this.locations = new Resource[] {location};
}
public void setLocations(Resource[] locations) {
this.locations = locations;
}
所以單個文件可以簡單的用 location對應一個 值(value)
-->
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="password" value="${jdbc.password}"/>
<property name="username" value="${jdbc.username}"/>
</bean>
客戶段可以通過
ApplicationContext ctx = new ClassPathXmlApplicationContext("dbcpPoolBean.xml");
DataSource ds = (org.apache.commons.dbcp.BasicDataSource )ctx.getBean("dataSource");
來獲得數據源。當然在web開發中可以通過容器自動注入。
----------------------------------------------------------------------------------------------------------------------------
Tocmate5.5中配置數據源:
自己在配置這個東西的時候搞了好久 ,最后還是求助 CSDN解決的
貼子http://topic.csdn.net/u/20080605/20/7fdd0eee-9c43-428a-8b82-5db9a1968151.html
總結下幾個需要注意的地方:
1,首先在 tomcate 的server.xml文件中正確配置
2,要將相關的驅動包(sql的和連接池的)copy到 C:/Tomcat 5.5/common/lib(我的tomcate在c盤)
server.xml中的配置信息:
<Context path="/testPool"
docBase="F:/Exercise/Newer/tomcatePool/WebRoot"
debug="5"
reloadable="true"
crossContext="true">
<Resource name="jdbc/userDB"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.commons.dbcp.BasicDataSourceFactory"
username="sa"
password=""
driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs"
maxActive="100"
maxIdle="1000"
maxWait="5000"/>
</Context>
讀取連接池的方法:
try{
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/userDB");
//可以獲得 ds
System.out.println(ds);
Connection con = ds.getConnection();
System.out.println("我的到了連接拉:"+con);
//out.println( ds.getConnection());
}catch(Exception ex){
ex.printStackTrace();
}
通過這兩步配置后你就可以用 http://localhost:8080/testPool/來訪問 你的資源 testPool 是你在 <Context path="/testPool"/> 中path的值匹配
如果你吧你的項目部署到tomcate還是不能獲得連接。 這是你要在 C:/Tomcat 5.5/conf/Catalina/localhost 下新建一個xml 文件 (tomcatePool.xml)
tomcatePool 是你的當前項目的名字。
這樣就可以通過 http://localhost:8080/tomcatePool/ 來訪問你的資源了。這時 server.xml文件中就可以不配置。
tomcatePool.xml
<Context path=""
docBase=""
debug="5"
reloadable="true"
crossContext="true">
<Resource name="jdbc/userDB"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.commons.dbcp.BasicDataSourceFactory"
username="sa"
password=""
driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs"
maxActive="100"
maxIdle="1000"
maxWait="5000"/>
</Context>
注意path和docBase 因為是通過項目名來訪問的所以這兩個值沒有意義。
------------------------------------------------------------------------------------------------------------------------------
hibernate 中獲得容器(tomcate)中的數據源。
只要加 一個配置。
hibernate.cfg.xml文件
<property name="connection.datasource">java:comp/env/jdbc/userDB</property>
有了這個后
<!-- <property name="connection.username">sa</property>-->
<!-- <property name="connection.url">-->
<!-- jdbc:microsoft:sqlserver://127.0.0.1:1433;databasename=temp-->
<!-- </property>-->
<!-- <property name="myeclipse.connection.profile">sql2000</property>-->
<!-- <property name="connection.driver_class">-->
<!-- com.microsoft.jdbc.sqlserver.SQLServerDriver -->
<!-- </property>-->
這些就可以注釋掉呢。
另外測試中發現 .hbm.xml 文件中的 catalog="temp" 屬性可以覆蓋 數據源中
url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs" 這里配置的數據庫名稱。
****************************************************************************************************
目前就只做了這么多 以后遇到了新的再來補充.
作者:caoyinghui1986 發表于2008-6-6 14:28:00
原文鏈接
Hibernate映射類型對照表
java類型 |
Hibernate映射類型 |
SQL類型 |
java.math.BigDecimal |
big_decimal |
numeric |
byte[] |
binary |
varbinary(blob) |
boolean(java.lang.Boolean) |
boolean |
bit |
byte(java.lang.Byte) |
byte |
tinyint |
java.util.Calendar |
calendar |
timestamp |
java.sql.Clob |
clob |
clob |
java.util.Date 或java.sql.Date |
date |
date |
double(java.lang.Double) |
double |
double |
float(java.lang.Float) |
float |
float |
int (java.lang.Integer) |
integer |
integer |
java.util.Local |
local |
varchar |
long(java.lang.Long) |
long |
bigint |
java.io.Serializable的某個實例 |
serializable |
varbinary(或blob) |
java.lang.String |
string |
varchar |
java.lang.String |
text |
clob |
java.util.Date 或 java.sql.Timestamp |
time |
timestamp |
從書上把這個表抄下來方便以后查閱.
考慮到 操作 blob 的字段太復雜 一個變換的技巧是 . 實體類用 byte[] 類型 , hibernate 類型用 binary ,數據庫還是用 blob .這樣 可以簡化一些操作.
作者:caoyinghui1986 發表于2008-6-4 20:56:00
原文鏈接
Spring 和 struts 整合的三種方式。
1,使用Spring 的 ActionSupport
2, 使用Spring 的 DelegatingRequestProcessor 類。
3,全權委托。
無論用那種方法來整合第一步就是要為struts來裝載spring的應用環境。 就是在 struts 中加入一個插件。
struts-config.xml中
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
</plug-in>
spring 的配置文件被作為參數配置進來。這樣可以省略對web.xml 文件中的配置。確保你的applicationContext.xml 在WEB-INF目錄下面
1,使用Spring的ActionSupport .
Spring 的ActionSupport 繼承至 org.apache.struts.action.Action
ActionSupport的子類可以或得 WebApplicationContext類型的全局變量。通過getWebApplicationContext()可以獲得這個變量。
這是一個 servlet 的代碼:
public class LoginAction extends org.springframework.web.struts.ActionSupport {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
LoginForm loginForm = (LoginForm) form;// TODO Auto-generated method stub
//獲得 WebApplicationContext 對象
WebApplicationContext ctx = this.getWebApplicationContext();
LoginDao dao = (LoginDao) ctx.getBean("loginDao");
User u = new User();
u.setName(loginForm.getName());
u.setPwd(loginForm.getPwd());
if(dao.checkLogin(u)){
return mapping.findForward("success");
}else{
return mapping.findForward("error");
}
}
}
applicationContext.xml 中的配置
<beans>
<bean id="loginDao" class="com.cao.dao.LoginDao"/>
</beans>
這中配置方式同直接在web.xml文件配置差別不大。注意:Action繼承自 org.springframework.web.struts.ActionSupport 使得struts和spring耦合在一起。
但實現了表示層和業務邏輯層的解耦(LoginDao dao = (LoginDao) ctx.getBean("loginDao"))。
2,使用Spring 的 DelegatingRequestProcessor 類
DelegatingRequestProcessor 繼承自 org.apache.struts.action.RequestProcessor 并覆蓋了里面的方法。
sturts-config.xml 中 <controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor"/> 通過 <controller >來替代
org.apache.struts.action.RequestProcessor 的請求處理。
public class LoginAction extends Action {
//利用spring來注入這個對象。
private LoginDao dao ;
public void setDao(LoginDao dao) {
System.out.println("執行注入");
this.dao = dao;
}
public LoginDao getDao() {
return dao;
}
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
LoginForm loginForm = (LoginForm) form;// TODO Auto-generated method stub
//這樣一改這行代碼似乎沒有必要了。
//WebApplicationContext ctx = this.getWebApplicationContext();
//LoginDao dao = (LoginDao) ctx.getBean("loginDao");
User u = new User();
u.setName(loginForm.getName());
u.setPwd(loginForm.getPwd());
//直接用dao來調用spring會將這個對象實例化。
if(dao.checkLogin(u)){
return mapping.findForward("success");
}else{
return mapping.findForward("error");
}
}
}
這里的。
LoginAction extends Action 說明 struts 每有和spring 耦合。
看一下
applicationContext.xml 中的配置。
<beans>
<bean id="loginDao" class="com.cao.dao.LoginDao"/>
<bean name="/login" class="com.cao.struts.action.LoginAction">
<property name="dao">
<ref local="loginDao"/>
</property>
</bean>
</beans>
這里 name="/login" 與struts 中的path匹配
class="com.cao.struts.action.LoginAction" 與struts 中的type匹配
還要為 LoginAction 提供必要的setXXX方法。 獲得ApplicationCotext和依賴注入的工作都在DelegatingRequestProcessor中完成。
3,全權委托:
Action 的創建和對象的依賴注入全部由IOC容器來完成。 使用Spring的DelegatingAcionProxy來幫助實現代理的工作
org.springframework.web.struts.DelegatingActiongProxy繼承于org.apache.struts.action.Action .
全權委托的配置方式同 方式 2 類似 (applcationContext.xml文件的配置和 Action類的實現方式相同)。
<struts-config>
<data-sources />
<form-beans >
<form-bean name="loginForm" type="com.cao.struts.form.LoginForm" />
</form-beans>
<global-exceptions />
<global-forwards />
<action-mappings >
<!-- type指向的是spring 的代理類 -->
<action
attribute="loginForm"
input="login.jsp"
name="loginForm"
path="/login"
scope="request"
type="org.springframework.web.struts.DelegatingActionProxy" >
<forward name="success" path="/ok.jsp" />
<forward name="error" path="/error.jsp" />
</action>
</action-mappings>
<message-resources parameter="com.cao.struts.ApplicationResources" />
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
</plug-in>
</struts-config>
不同之處
1, <action>中 type指向的是spring 的代理類
2, 去掉struts-config.xml中 <controller >
三種整和方式中我們優先選用 全權委托的方式。
理由:
1,第一種使得過多的耦合了Spring和Action .
2,RequestProcessor類已經被代理 如果要再實現自己的實現方式(如:編碼處理)怕有點麻煩。
總結一下:
整合工作中的步驟:
1,修改struts-config.xml
2, 配置applicationContext.xml
3, 為Action添加get/set方法 來獲得依賴注入的功能。
作者:caoyinghui1986 發表于2008-6-2 6:16:00
原文鏈接
1,通過Listener加載ApplicationContext
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
-----------------------------------------------------------------------------------------------------------------------------------------
通過Servlet加載ApplicationContext
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>SpringContextServlet</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
-------------------------------------------------------------------------------------------------------------------------------------------
兩種加載方式中要特別注意 路徑問題。
<param-value>/WEB-INF/applicationContext.xml</param-value>
其中要確保你的 WEB-INF 下 有 applicationContext.xml 這個文件
測試發現WEB-INF區分大小寫。 空格好象沒有發現問題。
Listener 接口 是在 servelt2.3 版本被引入的 我機器的配置是Eclipse3.2 +Tomcate5.0+JDK1.5
使用這個沒有問題。
還有一個 applicationContext.xml 如果放在 WEB-INF目錄外似乎在這里
哪怕是改成相應的路徑好象也訪問不到。
servlet中可以通過
ApplicationContext context = org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
得到 context 對象。
作者:caoyinghui1986 發表于2008-6-1 15:52:00
原文鏈接
calendar.js
--------------------------------------------------------------------------------
<!--
document.write("<div id=meizzCalendarLayer style='position: absolute; z-index: 9999; width: 144; height: 193; display: none'>");
document.write("<iframe name=meizzCalendarIframe scrolling=no frameborder=0 width=100% height=100%></iframe></div>");
function writeIframe()
{
var strIframe = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=gb2312'><style>"+
"*{font-size: 12px; font-family: 宋體}"+
".bg{ color: "+ WebCalendar.lightColor +"; cursor: default; background-color: "+ WebCalendar.darkColor +";}"+
"table#tableMain{ width: 142; height: 180;}"+
"table#tableWeek td{ color: "+ WebCalendar.lightColor +";}"+
"table#tableDay td{ font-weight: bold;}"+
"td#meizzYearHead, td#meizzYearMonth{color: "+ WebCalendar.wordColor +"}"+
".out { text-align: center; border-top: 1px solid "+ WebCalendar.DarkBorder +"; border-left: 1px solid "+ WebCalendar.DarkBorder +";"+
"border-right: 1px solid "+ WebCalendar.lightColor +"; border-bottom: 1px solid "+ WebCalendar.lightColor +";}"+
".over{ text-align: center; border-top: 1px solid #FFFFFF; border-left: 1px solid #FFFFFF;"+
"border-bottom: 1px solid "+ WebCalendar.DarkBorder +"; border-right: 1px solid "+ WebCalendar.DarkBorder +"}"+
"input{ border: 1px solid "+ WebCalendar.darkColor +"; padding-top: 1px; height: 18; cursor: hand;"+
" color:"+ WebCalendar.wordColor +"; background-color: "+ WebCalendar.btnBgColor +"}"+
"</style></head><body onselectstart='return false' style='margin: 0px' oncontextmenu='return false'><form name=meizz>";
if (WebCalendar.drag){ strIframe += "<scr"+"ipt language=javascript>"+
"var drag=false, cx=0, cy=0, o = parent.WebCalendar.calendar; function document.onmousemove(){"+
"if(parent.WebCalendar.drag && drag){if(o.style.left=='')o.style.left=0; if(o.style.top=='')o.style.top=0;"+
"o.style.left = parseInt(o.style.left) + window.event.clientX-cx;"+
"o.style.top = parseInt(o.style.top) + window.event.clientY-cy;}}"+
"function document.onkeydown(){ switch(window.event.keyCode){ case 27 : parent.hiddenCalendar(); break;"+
"case 37 : parent.prevM(); break; case 38 : parent.prevY(); break; case 39 : parent.nextM(); break; case 40 : parent.nextY(); break;"+
"case 84 : document.forms[0].today.click(); break;} window.event.keyCode = 0; window.event.returnValue= false;}"+
"function dragStart(){cx=window.event.clientX; cy=window.event.clientY; drag=true;}</scr"+"ipt>"}
strIframe += "<select name=tmpYearSelect onblur='parent.hiddenSelect(this)' style='z-index:1;position:absolute;top:3;left:18;display:none'"+
" onchange='parent.WebCalendar.thisYear =this.value; parent.hiddenSelect(this); parent.writeCalendar();'></select>"+
"<select name=tmpMonthSelect onblur='parent.hiddenSelect(this)' style='z-index:1; position:absolute;top:3;left:74;display:none'"+
" onchange='parent.WebCalendar.thisMonth=this.value; parent.hiddenSelect(this); parent.writeCalendar();'></select>"+
"<table id=tableMain class=bg border=0 cellspacing=2 cellpadding=0>"+
"<tr><td width=140 height=19 bgcolor='"+ WebCalendar.lightColor +"'>"+
" <table width=140 id=tableHead border=0 cellspacing=1 cellpadding=0><tr align=center>"+
" <td width=15 height=19 class=bg title='向前翻 1 月 快捷鍵:←' style='cursor: hand' onclick='parent.prevM()'><b><</b></td>"+
" <td width=60 id=meizzYearHead title='點擊此處選擇年份' onclick='parent.funYearSelect(parseInt(this.innerText, 10))'"+
" onmouseover='this.bgColor=parent.WebCalendar.darkColor; this.style.color=parent.WebCalendar.lightColor'"+
" onmouseout='this.bgColor=parent.WebCalendar.lightColor; this.style.color=parent.WebCalendar.wordColor'></td>"+
" <td width=50 id=meizzYearMonth title='點擊此處選擇月份' onclick='parent.funMonthSelect(parseInt(this.innerText, 10))'"+
" onmouseover='this.bgColor=parent.WebCalendar.darkColor; this.style.color=parent.WebCalendar.lightColor'"+
" onmouseout='this.bgColor=parent.WebCalendar.lightColor; this.style.color=parent.WebCalendar.wordColor'></td>"+
" <td width=15 class=bg title='向后翻 1 月 快捷鍵:→' onclick='parent.nextM()' style='cursor: hand'><b>></b></td></tr></table>"+
"</td></tr><tr><td height=20><table id=tableWeek border=1 width=140 cellpadding=0 cellspacing=0 ";
if(WebCalendar.drag){strIframe += "onmousedown='dragStart()' onmouseup='drag=false' onmouseout='drag=false'";}
strIframe += " borderColorLight='"+ WebCalendar.darkColor +"' borderColorDark='"+ WebCalendar.lightColor +"'>"+
" <tr align=center><td height=20>日</td><td>一</td><td>二</td><td>三</td><td>四</td><td>五</td><td>六</td></tr></table>"+
"</td></tr><tr><td valign=top width=140 bgcolor='"+ WebCalendar.lightColor +"'>"+
" <table id=tableDay height=120 width=140 border=0 cellspacing=1 cellpadding=0>";
for(var x=0; x<5; x++){ strIframe += "<tr>";
for(var y=0; y<7; y++) strIframe += "<td class=out id='meizzDay"+ (x*7+y) +"'></td>"; strIframe += "</tr>";}
strIframe += "<tr>";
for(var x=35; x<39; x++) strIframe += "<td class=out id='meizzDay"+ x +"'></td>";
strIframe +="<td colspan=3 class=out title='"+ WebCalendar.regInfo +"'><input style=' background-color: "+
WebCalendar.btnBgColor +";cursor: hand; padding-top: 4px; width: 100%; height: 100%; border: 0' onfocus='this.blur()'"+
" type=button value=' 關閉' onclick='parent.hiddenCalendar()'></td></tr></table>"+
"</td></tr><tr><td height=20 width=140 bgcolor='"+ WebCalendar.lightColor +"'>"+
" <table border=0 cellpadding=1 cellspacing=0 width=140>"+
" <tr><td><input name=prevYear title='向前翻 1 年 快捷鍵:↑' onclick='parent.prevY()' type=button value='<<'"+
" onfocus='this.blur()' style='meizz:expression(this.disabled=parent.WebCalendar.thisYear==1000)'><input"+
" onfocus='this.blur()' name=prevMonth title='向前翻 1 月 快捷鍵:←' onclick='parent.prevM()' type=button value='< '>"+
" </td><td align=center><input name=today type=button value='Today' onfocus='this.blur()' style='width: 50' title='當前日期 快捷鍵:T'"+
" onclick=/"parent.returnDate(new Date().getDate() +'/'+ (new Date().getMonth() +1) +'/'+ new Date().getFullYear())/">"+
" </td><td align=right><input title='向后翻 1 月 快捷鍵:→' name=nextMonth onclick='parent.nextM()' type=button value=' >'"+
" onfocus='this.blur()'><input name=nextYear title='向后翻 1 年 快捷鍵:↓' onclick='parent.nextY()' type=button value='>>'"+
" onfocus='this.blur()' style='meizz:expression(this.disabled=parent.WebCalendar.thisYear==9999)'></td></tr></table>"+
"</td></tr><table></form></body></html>";
with(WebCalendar.iframe)
{
document.writeln(strIframe); document.close();
for(var i=0; i<39; i++)
{
WebCalendar.dayObj[i] = eval("meizzDay"+ i);
WebCalendar.dayObj[i].onmouseover = dayMouseOver;
WebCalendar.dayObj[i].onmouseout = dayMouseOut;
WebCalendar.dayObj[i].onclick = returnDate;
}
}
}
function WebCalendar() //初始化日歷的設置
{
this.regInfo = "WEB Calendar ver 3.0 作者:meizz(梅花雪疏影橫斜) 網站:http://www.meizz.com/ 關閉的快捷鍵:[Esc]";
this.regInfo += " Ver 2.0:walkingpoison(水晶龍) Ver 1.0:meizz(梅花雪疏影橫斜)";
this.daysMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
this.day = new Array(39); //定義日歷展示用的數組
this.dayObj = new Array(39); //定義日期展示控件數組
this.dateStyle = null; //保存格式化后日期數組
this.objExport = null; //日歷回傳的顯示控件
this.eventSrc = null; //日歷顯示的觸發控件
this.inputDate = null; //轉化外的輸入的日期(d/m/yyyy)
this.thisYear = new Date().getFullYear(); //定義年的變量的初始值
this.thisMonth = new Date().getMonth()+ 1; //定義月的變量的初始值
this.thisDay = new Date().getDate(); //定義日的變量的初始值
this.today = this.thisDay +"/"+ this.thisMonth +"/"+ this.thisYear; //今天(d/m/yyyy)
this.iframe = window.frames("meizzCalendarIframe"); //日歷的 iframe 載體
this.calendar = getObjectById("meizzCalendarLayer"); //日歷的層
this.dateReg = ""; //日歷格式驗證的正則式
this.yearFall = 50; //定義年下拉框的年差值
this.format = "yyyy-mm-dd"; //回傳日期的格式
this.timeShow = false; //是否返回時間
this.drag = true; //是否允許拖動
this.darkColor = "#FF6347"; //控件的暗色
this.lightColor = "#FFFFFF"; //控件的亮色
this.btnBgColor = "#FFF5A0"; //控件的按鈕背景色
this.wordColor = "#000040"; //控件的文字顏色
this.wordDark = "#DCDCDC"; //控件的暗文字顏色
this.dayBgColor = "#FFFACD"; //日期數字背景色
this.todayColor = "#FF9933"; //今天在日歷上的標示背景色
this.DarkBorder = "#FFE4C4"; //日期顯示的立體表達色
} var WebCalendar = new WebCalendar();
function calendar() //主調函數
{
var e = window.event.srcElement; writeIframe();
var o = WebCalendar.calendar.style; WebCalendar.eventSrc = e;
if (arguments.length == 0) WebCalendar.objExport = e;
else WebCalendar.objExport = eval(arguments[0]);
WebCalendar.iframe.tableWeek.style.cursor = WebCalendar.drag ? "move" : "default";
var t = e.offsetTop, h = e.clientHeight, l = e.offsetLeft, p = e.type;
while (e = e.offsetParent){t += e.offsetTop; l += e.offsetLeft;}
o.display = ""; WebCalendar.iframe.document.body.focus();
var cw = WebCalendar.calendar.clientWidth, ch = WebCalendar.calendar.clientHeight;
var dw = document.body.clientWidth, dl = document.body.scrollLeft, dt = document.body.scrollTop;
if (document.body.clientHeight + dt - t - h >= ch) o.top = (p=="image")? t + h : t + h + 6;
else o.top = (t - dt < ch) ? ((p=="image")? t + h : t + h + 6) : t - ch;
if (dw + dl - l >= cw) o.left = l; else o.left = (dw >= cw) ? dw - cw + dl : dl;
if (!WebCalendar.timeShow) WebCalendar.dateReg = /^(/d{1,4})(-|//|.)(/d{1,2})/2(/d{1,2})$/;
else WebCalendar.dateReg = /^(/d{1,4})(-|//|.)(/d{1,2})/2(/d{1,2}) (/d{1,2}):(/d{1,2}):(/d{1,2})$/;
try{
if (WebCalendar.objExport.value.trim() != ""){
WebCalendar.dateStyle = WebCalendar.objExport.value.trim().match(WebCalendar.dateReg);
if (WebCalendar.dateStyle == null)
{
WebCalendar.thisYear = new Date().getFullYear();
WebCalendar.thisMonth = new Date().getMonth()+ 1;
WebCalendar.thisDay = new Date().getDate();
alert("原文本框里的日期有錯誤!/n可能與你定義的顯示時分秒有沖突!");
writeCalendar(); return false;
}
else
{
WebCalendar.thisYear = parseInt(WebCalendar.dateStyle[1], 10);
WebCalendar.thisMonth = parseInt(WebCalendar.dateStyle[3], 10);
WebCalendar.thisDay = parseInt(WebCalendar.dateStyle[4], 10);
WebCalendar.inputDate = parseInt(WebCalendar.thisDay, 10) +"/"+ parseInt(WebCalendar.thisMonth, 10) +"/"+
parseInt(WebCalendar.thisYear, 10); writeCalendar();
}
} else writeCalendar();
} catch(e){writeCalendar();}
}
function funMonthSelect() //月份的下拉框
{
var m = isNaN(parseInt(WebCalendar.thisMonth, 10)) ? new Date().getMonth() + 1 : parseInt(WebCalendar.thisMonth);
var e = WebCalendar.iframe.document.forms[0].tmpMonthSelect;
for (var i=1; i<13; i++) e.options.add(new Option(i +"月", i));
e.style.display = ""; e.value = m; e.focus(); window.status = e.style.top;
}
function funYearSelect() //年份的下拉框
{
var n = WebCalendar.yearFall;
var e = WebCalendar.iframe.document.forms[0].tmpYearSelect;
var y = isNaN(parseInt(WebCalendar.thisYear, 10)) ? new Date().getFullYear() : parseInt(WebCalendar.thisYear);
y = (y <= 1000)? 1000 : ((y >= 9999)? 9999 : y);
var min = (y - n >= 1000) ? y - n : 1000;
var max = (y + n <= 9999) ? y + n : 9999;
min = (max == 9999) ? max-n*2 : min;
max = (min == 1000) ? min+n*2 : max;
for (var i=min; i<=max; i++) e.options.add(new Option(i +"年", i));
e.style.display = ""; e.value = y; e.focus();
}
function prevM() //往前翻月份
{
WebCalendar.thisDay = 1;
if (WebCalendar.thisMonth==1)
{
WebCalendar.thisYear--;
WebCalendar.thisMonth=13;
}
WebCalendar.thisMonth--; writeCalendar();
}
function nextM() //往后翻月份
{
WebCalendar.thisDay = 1;
if (WebCalendar.thisMonth==12)
{
WebCalendar.thisYear++;
WebCalendar.thisMonth=0;
}
WebCalendar.thisMonth++; writeCalendar();
}
function prevY(){WebCalendar.thisDay = 1; WebCalendar.thisYear--; writeCalendar();}//往前翻 Year
function nextY(){WebCalendar.thisDay = 1; WebCalendar.thisYear++; writeCalendar();}//往后翻 Year
function hiddenSelect(e){for(var i=e.options.length; i>-1; i--)e.options.remove(i); e.style.display="none";}
function getObjectById(id){ if(document.all) return(eval("document.all."+ id)); return(eval(id)); }
function hiddenCalendar(){getObjectById("meizzCalendarLayer").style.display = "none";};
function appendZero(n){return(("00"+ n).substr(("00"+ n).length-2));}//日期自動補零程序
function String.prototype.trim(){return this.replace(/(^/s*)|(/s*$)/g,"");}
function dayMouseOver()
{
this.className = "over";
this.style.backgroundColor = WebCalendar.darkColor;
if(WebCalendar.day[this.id.substr(8)].split("/")[1] == WebCalendar.thisMonth)
this.style.color = WebCalendar.lightColor;
}
function dayMouseOut()
{
this.className = "out"; var d = WebCalendar.day[this.id.substr(8)], a = d.split("/");
this.style.removeAttribute('backgroundColor');
if(a[1] == WebCalendar.thisMonth && d != WebCalendar.today)
{
if(WebCalendar.dateStyle && a[0] == parseInt(WebCalendar.dateStyle[4], 10))
this.style.color = WebCalendar.lightColor;
this.style.color = WebCalendar.wordColor;
}
}
function writeCalendar() //對日歷顯示的數據的處理程序
{
var y = WebCalendar.thisYear;
var m = WebCalendar.thisMonth;
var d = WebCalendar.thisDay;
WebCalendar.daysMonth[1] = (0==y%4 && (y%100!=0 || y%400==0)) ? 29 : 28;
if (!(y<=9999 && y >= 1000 && parseInt(m, 10)>0 && parseInt(m, 10)<13 && parseInt(d, 10)>0)){
alert("對不起,你輸入了錯誤的日期!");
WebCalendar.thisYear = new Date().getFullYear();
WebCalendar.thisMonth = new Date().getMonth()+ 1;
WebCalendar.thisDay = new Date().getDate(); }
y = WebCalendar.thisYear;
m = WebCalendar.thisMonth;
d = WebCalendar.thisDay;
WebCalendar.iframe.meizzYearHead.innerText = y +" 年";
WebCalendar.iframe.meizzYearMonth.innerText = parseInt(m, 10) +" 月";
WebCalendar.daysMonth[1] = (0==y%4 && (y%100!=0 || y%400==0)) ? 29 : 28; //閏年二月為29天
var w = new Date(y, m-1, 1).getDay();
var prevDays = m==1 ? WebCalendar.daysMonth[11] : WebCalendar.daysMonth[m-2];
for(var i=(w-1); i>=0; i--) //這三個 for 循環為日歷賦數據源(數組 WebCalendar.day)格式是 d/m/yyyy
{
WebCalendar.day[i] = prevDays +"/"+ (parseInt(m, 10)-1) +"/"+ y;
if(m==1) WebCalendar.day[i] = prevDays +"/"+ 12 +"/"+ (parseInt(y, 10)-1);
prevDays--;
}
for(var i=1; i<=WebCalendar.daysMonth[m-1]; i++) WebCalendar.day[i+w-1] = i +"/"+ m +"/"+ y;
for(var i=1; i<39-w-WebCalendar.daysMonth[m-1]+1; i++)
{
WebCalendar.day[WebCalendar.daysMonth[m-1]+w-1+i] = i +"/"+ (parseInt(m, 10)+1) +"/"+ y;
if(m==12) WebCalendar.day[WebCalendar.daysMonth[m-1]+w-1+i] = i +"/"+ 1 +"/"+ (parseInt(y, 10)+1);
}
for(var i=0; i<39; i++) //這個循環是根據源數組寫到日歷里顯示
{
var a = WebCalendar.day[i].split("/");
WebCalendar.dayObj[i].innerText = a[0];
WebCalendar.dayObj[i].title = a[2] +"-"+ appendZero(a[1]) +"-"+ appendZero(a[0]);
WebCalendar.dayObj[i].bgColor = WebCalendar.dayBgColor;
WebCalendar.dayObj[i].style.color = WebCalendar.wordColor;
if ((i<10 && parseInt(WebCalendar.day[i], 10)>20) || (i>27 && parseInt(WebCalendar.day[i], 10)<12))
WebCalendar.dayObj[i].style.color = WebCalendar.wordDark;
if (WebCalendar.inputDate==WebCalendar.day[i]) //設置輸入框里的日期在日歷上的顏色
{WebCalendar.dayObj[i].bgColor = WebCalendar.darkColor; WebCalendar.dayObj[i].style.color = WebCalendar.lightColor;}
if (WebCalendar.day[i] == WebCalendar.today) //設置今天在日歷上反應出來的顏色
{WebCalendar.dayObj[i].bgColor = WebCalendar.todayColor; WebCalendar.dayObj[i].style.color = WebCalendar.lightColor;}
}
}
function returnDate() //根據日期格式等返回用戶選定的日期
{
if(WebCalendar.objExport)
{
var returnValue;
var a = (arguments.length==0) ? WebCalendar.day[this.id.substr(8)].split("/") : arguments[0].split("/");
var d = WebCalendar.format.match(/^(/w{4})(-|//|.|)(/w{1,2})/2(/w{1,2})$/);
if(d==null){alert("你設定的日期輸出格式不對!/r/n/r/n請重新定義 WebCalendar.format !"); return false;}
var flag = d[3].length==2 || d[4].length==2; //判斷返回的日期格式是否要補零
returnValue = flag ? a[2] +d[2]+ appendZero(a[1]) +d[2]+ appendZero(a[0]) : a[2] +d[2]+ a[1] +d[2]+ a[0];
if(WebCalendar.timeShow)
{
var h = new Date().getHours(), m = new Date().getMinutes(), s = new Date().getSeconds();
returnValue += flag ? " "+ appendZero(h) +":"+ appendZero(m) +":"+ appendZero(s) : " "+ h +":"+ m +":"+ s;
}
WebCalendar.objExport.value = returnValue;
hiddenCalendar();
}
}
function document.onclick()
{
if(WebCalendar.eventSrc != window.event.srcElement) hiddenCalendar();
}
//-->
----------------------------------------------------------------------------------------------------------------------------------------------
<SCRIPT LANGUAGE="JavaScript" src="calendar.js"></SCRIPT>
在你的頁面中引入 這個 js 文件
通過onfocus來調用并顯示日歷
<input type="text" onfocus="calendar()" name="xxx">
當把一個帶中文的js文件考到Eclipse工程時候會報編碼錯誤這是 需要點右鍵 屬性 更改編碼。然后粘貼就可以
了
如果粘貼出現亂碼 http://d.download.csdn.net/down/476931/caoyinghui1986
有完整的JS文件 js文件中出錯的地方可以用 <!-- --> 注釋. (JBuilder2005不報錯 ,Eclipse好象有這個問題)
注釋 后就沒有事情了。
作者:caoyinghui1986 發表于2008-5-31 17:56:00
原文鏈接
public class Test {
public static void main(String[] args) {
String str = new String(
"1,2,3,4,5,6,7,8,9,11,13,14,1000,1001,1002,1003");
String[] s = str.split(",");
int[] num = new int[s.length];
String result = "";
for (int i = 0; i < s.length; i++) {
num[i] = Integer.parseInt(s[i]);
}
for (int i = 0; i < num.length; i++) {
if (i == 0) {
result = "" + num[i];
} else if (i == num.length - 1) {
if (num[i] - num[i - 1] == 1) {
result = result + "-" + num[i];
} else {
result = result + "," + num[i];
}
} else {
if ((num[i] - num[i - 1] == 1) && (num[i + 1] - num[i] == 1)) {
continue;
}
if ((num[i] - num[i - 1] == 1) && (num[i + 1] - num[i] != 1)) {
result = result + "-" + num[i];
}
if ((num[i] - num[i - 1] != 1)) {
result = result + "," + num[i];
}
}
}
System.out.println(result);
}
}
作者:caoyinghui1986 發表于2008-5-31 14:11:00
原文鏈接