2008年5月30日
<!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 href="http://www.aa25.cn">标准之路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 href="http://www.aa25.cn">标准之路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
原文链接
Spring通过PropertyEdit(属性编辑器) 可以将字符串转换为真实类型。通过CustomEditorConfigurer ,ApplicationContext 可以很方便的支持自定义
PropertyEdit。
MyType.java
package com.cao.spring.applicationContext;
public class MyType {
private String text;
public MyType(String text){
this.text = text;
}
public String getText(){
return this.text;
}
}
DependsOnType.java
package com.cao.spring.applicationContext;
public class DependsOnType {
private MyType type;
public MyType getType() {
return type;
}
public void setType(MyType type) {
this.type = type;
}
}
//自定义的属性编辑器MyTypeEdit.java
package com.cao.spring.applicationContext;
public class MyTypeEdit extends java.beans.PropertyEditorSupport{
//提供一种对字符串的转换策略
private String format;
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
//覆盖父类(PropertyEditorSupport)的setAsText方法。
public void setAsText(String text) {
if(format!=null && format.equals("upperCase")){
System.out.println("修改前的样子:"+text);
text=text.toUpperCase();
}
//获得编辑前的类型
System.out.println("获得编辑前的类型 "+text.getClass().getSimpleName());
//包装成真实类型
MyType type = new MyType(text);
//注入包装后的类型
setValue(type);
}
}
配置bean propertyEdit.xml
<beans>
<bean id="myBean" class="com.cao.spring.applicationContext.DependsOnType">
<!-- type的真实类型是 MyType 但这里指定的是一个普通的String -->
<property name="type">
<value>abc</value>
</property>
</bean>
</beans>
将属性编辑器配置进来 plugin.xml
<bean id="aaa" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map> <!-- key指定了转换后的类型 -->
<entry key="com.cao.spring.applicationContext.MyType">
<!-- 内部bean 配置了自定义的属性编辑器 -->
<bean class="com.cao.spring.applicationContext.MyTypeEdit">
<!-- 配置字符串的转换策略 -->
<property name="format" value="upperCase"/>
</bean>
</entry>
</map>
</property>
</bean>
测试类:
public class MyEditorTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"application/plugin.xml","application/propertyEdit.xml"});
DependsOnType type= (DependsOnType) ctx.getBean("myBean");
System.out.println(type.getType().getClass().getSimpleName());
System.out.println(type.getType().getText());
}
}
//输出结果:
修改前的样子:abc获得编辑前的类型 StringMyTypeABC
作者:caoyinghui1986 发表于2008-5-30 20:44:00
原文链接