2007年7月26日
在 Win XP 中工作和Windows中工作时一样,利用快捷键代替鼠标。可以利用键盘快捷键打开、关闭和导航“开始”菜单、桌面、菜单、对话框以及网页。键盘还可以让您更简单地与计算机交互。 单击一个标题或按 TAB 键可以突出显示这个标题,然后按 ENTER 键。 一、常规键盘快捷键
按键 |
目的 |
Ctrl + C |
复制。 |
Ctrl + X |
剪切。 |
Ctrl + V |
粘贴。 |
Ctrl + Z |
撤消。 |
DELETE |
删除。 |
Shift + Delete |
永久删除所选项,而不将它放到“回收站”中。 |
拖动某一项时按 CTRL |
复制所选项。 |
拖动某一项时按 CTRL + SHIFT |
创建所选项目的快捷键。 |
F2 |
重新命名所选项目。 |
CTRL + 向右键 |
将插入点移动到下一个单词的起始处。 |
CTRL + 向左键 |
将插入点移动到前一个单词的起始处。 |
CTRL + 向下键 |
将插入点移动到下一段落的起始处。 |
CTRL + 向上键 |
将插入点移动到前一段落的起始处。 |
CTRL + SHIFT + 任何箭头键 |
突出显示一块文本。 |
SHIFT + 任何箭头键 |
在窗口或桌面上选择多项,或者选中文档中的文本。 |
Ctrl + A |
选中全部内容。 |
F3 |
搜索文件或文件夹。 |
Alt + Enter |
查看所选项目的属性。 |
Alt + F4 |
关闭当前项目或者退出当前程序。 |
ALT + Enter |
显示所选对象的属性。 |
Alt + 空格键 |
为当前窗口打开快捷菜单。 |
Ctrl + F4 |
在允许同时打开多个文档的程序中关闭当前文档。 |
Alt + Tab |
在打开的项目之间切换。 |
Alt + Esc |
以项目打开的顺序循环切换。 |
F6 |
在窗口或桌面上循环切换屏幕元素。 |
F4 |
显示“我的电脑”和“Windows 资源管理器”中的“地址”栏列表。 |
Shift + F10 |
显示所选项的快捷菜单。 |
Alt + 空格键 |
显示当前窗口的“系统”菜单。 |
Ctrl + Esc |
显示“开始”菜单。 |
ALT + 菜单名中带下划线的字母 |
显示相应的菜单。 |
在打开的菜单上显示的命令名称中带有下划线的字母 |
执行相应的命令。 |
F10 |
激活当前程序中的菜单条。 |
右箭头键 |
打开右边的下一菜单或者打开子菜单。 |
左箭头键 |
打开左边的下一菜单或者关闭子菜单。 |
F5 |
刷新当前窗口。 |
BackSpace |
在“我的电脑”或“Windows 资源管理器”中查看上一层文件夹。 |
Esc |
取消当前任务。 |
将光盘插入到 CD-ROM 驱动器时按 SHIFT 键 |
阻止光盘自动播放。 |
二、对话框快捷键
按键 |
目的 |
Ctrl + Tab |
在选项卡之间向前移动。 |
Ctrl + Shift +Tab |
在选项卡之间向后移动。 |
Tab |
在选项之间向前移动。 |
Shift + Tab |
在选项之间向后移动。 |
ALT + 带下划线的字母 |
执行相应的命令或选中相应的选项。 |
Enter |
执行活选项动或按钮所对应的命令。 |
空格键 |
如果活选项动是复选框,则选中或清除该复选框。 |
箭头键 |
活选项动是一组选项按钮时,请选中某个按钮。 |
F1 |
显示帮助。 |
F4 |
显示当前列表中的项目。 |
BackSpace |
如果在“另存为”或“打开”对话框中选中了某个文件夹,则打开上一级文件夹。 |
三、自然键盘快捷键 在“Microsoft 自然键盘”或包含 Windows 徽标键(简称WIN) 和“应用程序”键(简称KEY) 的其他兼容键盘中,您可以使用以下快捷键。
按键 |
目的 |
WIN |
显示或隐藏"开始"菜单。 |
WIN+ BREAK |
显示"系统属性"对话框。 |
WIN+ D |
显示桌面。 |
WIN+ M |
最小化所有窗口。 |
WIN+ Shift + M |
还原最小化的窗口。 |
WIN+ E |
打开"我的电脑"。 |
WIN+ F |
搜索文件或文件夹。 |
CTRL+WIN+ F |
搜索计算机。 |
WIN+ F1 |
显示 Windows 帮助。 |
WIN+ L |
如果连接到网络域,则锁定您的计算机,或者如果没有连接到网络域,则切换用户。 |
WIN+ R |
打开"运行"对话框。 |
KEY |
显示所选项的快捷菜单。 |
WIN+ U |
打开"工具管理器"。 |
四、辅助键盘快捷键
按键 |
目的 |
右侧 SHIFT 键八秒钟 |
切换“筛选键”的开和关。 |
左边的 ALT + 左边的 SHIFT + PRINT SCREEN |
切换“高对比度”的开和关。 |
左边的 ALT + 左边的 SHIFT + NUM LOCK |
切换“鼠标键”的开和关。 |
Shift 键五次 |
切换“粘滞键”的开和关。 |
Num Lock 键五秒钟 |
切换“切换键”的开和关。 |
WIN+ U |
打开“工具管理器”。 |
“Windows 资源管理器”键盘快捷键
按键 |
目的 |
END |
显示当前窗口的底端。 |
主页 |
显示当前窗口的顶端。 |
NUM LOCK + 数字键盘的星号 (*) |
显示所选文件夹的所有子文件夹。 |
NUM LOCK + 数字键盘的加号 (+) |
显示所选文件夹的内容。 |
NUM LOCK + 数字键盘的减号 (-) |
折叠所选的文件夹。 |
左箭头键 |
当前所选项处于展开状态时折叠该项,或选定其父文件夹。 |
右箭头键 |
当前所选项处于折叠状态时展开该项,或选定第一个子文件夹。 |
一、排版: 1.关键词和操作符之间加适当的空格。 2.相对独立的程序块与块之间加空行 3.较长的语句、表达式等要分成多行书写。 4.划分出的新行要进行适应的缩进,使排版整齐,语句可读。 5.长表达式要在低优先级操作符处划分新行,操作符放在新行之首。 6.循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分。 7.若函数或过程中的参数较长,则要进行适当的划分。 8.不允许把多个短语句写在一行中,即一行只写一条语句。 9.函数或过程的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格。 10.C/C++语言是用大括号‘{’和‘}’界定一段程序块的,编写程序块时‘{’和 ‘}’应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体 的开始、类的定义、结构的定义、枚举的定义以及if、for、do、while、 switch、case语句中的程序都要采用如上的缩进方式。
二、注释 1.注释要简单明了。 2.边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。 3.在必要的地方注释,注释量要适中。注释的内容要清楚、明了,含义准确,防止 注释二义性。保持注释与其描述的代码相邻,即注释的就近原则。 4.对代码的注释应放在其上方相邻位置,不可放在下面。 5.对数据结构的注释应放在其上方相邻位置,不可放在下面;对结构中的每个域 的注释应放在此域的右方;同一结构中不同域的注释要对齐。 6.变量、常量的注释应放在其上方相邻位置或右方。 7.全局变量要有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它 以及存取时注意事项等的说明。 8.在每个源文件的头部要有必要的注释信息,包括:文件名;版本号;作者;生成 日期;模块功能描述(如功能、主要算法、内部各部分之间的关系、该文件与其 它文件关系等);主要函数或过程清单及本文件历史修改记录等。 9.在每个函数或过程的前面要有必要的注释信息,包括:函数或过程名称;功能描 述;输入、输出及返回值说明;调用关系及被调用关系说明等。
三、命名 1.较短的单词可通过去掉“元音”形成缩写; 2.较长的单词可取单词的头几发符的优先级,并用括号明确表达式的操作顺序,避 免使用默认优先级。 3.使用匈牙利表示法
四、可读性 1.避免使用不易理解的数字,用有意义的标识来替代。 2.不要使用难懂的技巧性很高的语句。 3.源程序中关系较为紧密的代码应尽可能相邻。
五、变量 1.去掉没必要的公共变量。 2.构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问的公共 变量,防止多个不同模块或函数都可以修改、创建同一公共变量的现象。 3.仔细定义并明确公共变量的含义、作用、取值范围及公共变量间的关系。 4.明确公共变量与操作此公共变量的函数或过程的关系,如访问、修改及创建等。 5.当向公共变量传递数据时,要十分小心,防止赋与不合理的值或越界等现象发生。 6.防止局部变量与公共变量同名。 7.仔细设计结构中元素的布局与排列顺序,使结构容易理解、节省占用空间,并减 少引起误用现象。 8.结构的设计要尽量考虑向前兼容和以后的版本升级,并为某些未来可能的应用保 留余地(如预留一些空间等)。 9.留心具体语言及编译器处理不同数据类型的原则及有关细节。 10.严禁使用未经初始化的变量。声明变量的同时对变量进行初始化。 11.编程时,要注意数据类型的强制转换。
六、函数、过程 1.函数的规模尽量限制在200行以内。 2.一个函数最好仅完成一件功能。 3.为简单功能编写函数。 4.函数的功能应该是可以预测的,也就是只要输入数据相同就应产生同样的输出。 5.尽量不要编写依赖于其他函数内部实现的函数。 6.避免设计多参数函数,不使用的参数从接口中去掉。 7.用注释详细说明每个参数的作用、取值范围及参数间的关系。 8.检查函数所有参数输入的有效性。 9.检查函数所有非参数输入的有效性,如数据文件、公共变量等。 10.函数名应准确描述函数的功能。 11.避免使用无意义或含义不清的动词为函数命名 12.函数的返回值要清楚、明了,让使用者不容易忽视错误情况。 13/明确函数功能,精确(而不是近似)地实现函数设计。 14.减少函数本身或函数间的递归调用。 15.编写可重入函数时,若使用全局变量,则应通过关中断、信号量(即P、V操作) 等手段对其加以保护。
七、可测性 1.在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调 测开关及相应测试代码如打印函数等。 2.在进行集成测试/系统联调之前,要构造好测试环境、测试项目及测试用例,同时 仔细分析并优化测试用例,以提高测试效率。
八、程序效率 1.编程时要经常注意代码的效率。 2.在保证软件系统的正确性、稳定性、可读性及可测性的前提下,提高代码效率。 3.不能一味地追求代码效率,而对软件的正确性、稳定性、可读性及可测性造成影 响。 4.编程时,要随时留心代码效率;优化代码时,要考虑周全。 5.要仔细地构造或直接用汇编编写调用频繁或性能要求极高的函数。 6.通过对系统数据结构划分与组织的改进,以及对程序算法的优化来提高空间效率。 7.在多重循环中,应将最忙的循环放在最内层。 8.尽量减少循环嵌套层次。 9.避免循环体内含判断语句,应将循环语句置于判断语句的代码块之中。 10.尽量用乘法或其它方法代替除法,特别是浮点运算中的除法。
九、质量保证 1.在软件设计过程中构筑软件质量。 代码质量保证优先原则 (1)正确性,指程序要实现设计要求的功能。 (2)稳定性、安全性,指程序稳定、可靠、安全。 (3)可测试性,指程序要具有良好的可测试性。 (4)规范/可读性,指程序书写风格、命名规则等要符合规范。 (5)全局效率,指软件系统的整体效率。 (6)局部效率,指某个模块/子模块/函数的本身效率。 (7)个人表达方式/个人方便性,指个人编程习惯。 2.只引用属于自己的存贮空间。 3.防止引用已经释放的内存空间。 4.过程/函数中分配的内存,在过程/函数退出之前要释放。 5.过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出前要关闭。 6.防止内存操作越界。 7.时刻注意表达式是否会上溢、下溢。 8.认真处理程序所能遇到的各种出错情况。 9.系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用。 10.系统运行之初,要对加载到系统中的数据进行一致性检查。 11.严禁随意更改其它模块或系统的有关设置和配置。 12.不能随意改变与其它模块的接口。 13.充分了解系统的接口之后,再使用系统提供的功能。 14.要时刻注意易混淆的操作符。当编完程序后,应从头至尾检查一遍这些操作符。 15.不使用与硬件或操作系统关系很大的语句,而使用建议的标准语句。 16.建议:使用第三方提供的软件开发工具包或控件时,要注意以下几点: (1)充分了解应用接口、使用环境及使用时注意事项。 (2)不能过分相信其正确性。 (3)除非必要,不要使用不熟悉的第三方工具包与控件。
十、代码编译 1.编写代码时要注意随时保存,并定期备份,防止由于断电、硬盘损坏等原因造成 代码丢失。 2.同一项目组内,最好使用相同的编辑器,并使用相同的设置选项。 3.合理地设计软件系统目录,方便开发人员使用。 4.打开编译器的所有告警开关对程序进行编译。 5.在同一项目组或产品组中,要统一编译开关选项。 6.使用工具软件(如Visual SourceSafe)对代码版本进行维护。
十一、代码测试、维护 1.单元测试要求至少达到语句覆盖。 2.单元测试开始要跟踪每一条语句,并观察数据流及变量的变化。 3.清理、整理或优化后的代码要经过审查及测试。 4.代码版本升级要经过严格测试。
linux目录架构 / 根目录 /bin 常用的命令 binary file 的目錄 /boot 存放系统启动时必须读取的档案,包括核心 (kernel) 在内 /boot/grub/menu.lst GRUB设置 /boot/vmlinuz 内核 /boot/initrd 核心解壓縮所需 RAM Disk /dev 系统周边设备 /etc 系统相关设定文件 /etc/DIR_COLORS 设定颜色 /etc/HOSTNAME 设定用户的节点名 /etc/NETWORKING 只有YES标明网络存在 /etc/host.conf 文件说明用户的系统如何查询节点名 /etc/hosts 设定用户自已的IP与名字的对应表 /etc/hosts.allow 设置允许使用inetd的机器使用 /etc/hosts.deny 设置不允许使用inetd的机器使用 /etc/hosts.equiv 设置远端机不用密码 /etc/inetd.conf 设定系统网络守护进程inetd的配置 /etc/gateways 设定路由器 /etc/protocols 设定系统支持的协议 /etc/named.boot 设定本机为名字服务器的配置文件 /etc/sysconfig/network-scripts/ifcfg-eth0 设置IP /etc/resolv.conf 设置DNS /etc/X11 X Window的配置文件,xorg.conf 或 XF86Config 這兩個 X Server 的設定檔 /etc/fstab 记录开机要mount的文件系统 /etc/inittab 设定系统启动时init进程将把系统设置成什么样的runlevel /etc/issue 记录用户登录前显示的信息 /etc/group 设定用户的组名与相关信息 /etc/passwd 帐号信息 /etc/shadow 密码信息 /etc/sudoers 可以sudo命令的配置文件 /etc/securetty 设定哪些终端可以让root登录 /etc/login.defs 所有用户登录时的缺省配置 /etc/exports 设定NFS系统用的 /etc/init.d/ 所有服務的預設啟動 script 都是放在這裡的,例如要啟動或者關閉 /etc/xinetd.d/ 這就是所謂的 super daemon 管理的各項服務的設定檔目錄 /etc/modprobe.conf 内核模块额外参数设定 /etc/syslog.conf 日志设置文件 /home 使用者家目录 /lib 系统会使用到的函数库 /lib/modules kernel 的相关模块 /var/lib/rpm rpm套件安装处 /lost+found 系統不正常產生錯誤時,會將一些遺失的片段放置於此目錄下 /mnt 外设的挂载点 /media 与/mnt类似 /opt 主机额外安装的软件 /proc 虚拟目录,是内存的映射 /proc/version 内核版本 /proc/sys/kernel 系统内核功能 /root 系统管理员的家目录 /sbin 系统管理员才能执行的指令 /srv 一些服務啟動之後,這些服務所需要取用的資料目錄 /tmp 一般使用者或者是正在執行的程序暫時放置檔案的地方 /usr 最大的目录,存许应用程序和文件 /usr/X11R6: X-Window目录 /usr/src: Linux源代码 /usr/include:系统头文件 /usr/openwin 存放SUN的OpenWin /usr/man 在线使用手册 /usr/bin 使用者可執行的 binary file 的目錄 /usr/local/bin 使用者可執行的 binary file 的目錄 /usr/lib 系统会使用到的函数库 /usr/local/lib 系统会使用到的函数库 /usr/sbin 系统管理员才能执行的指令 /usr/local/sbin 系统管理员才能执行的指令 /var 日志文件 /var/log/secure 記錄登入系統存取資料的檔案,例如 pop3, ssh, telnet, ftp 等都會記錄在此檔案中 /var/log/wtmp 記錄登入者的訊息資料, last /var/log/messages 幾乎系統發生的錯誤訊息 /var/log/boot.log 記錄開機或者是一些服務啟動的時候,所顯示的啟動或關閉訊息 /var/log/maillog 紀錄郵件存取或往來( sendmail 與 pop3 )的使用者記錄 /var/log/cron 記錄 crontab 這個例行性服務的內容 /var/log/httpd, /var/log/news, /var/log/mysqld.log, /var/log/samba, /var/log/procmail.log: 分別是幾個不同的網路服務的記錄檔 一些常用的基本命令: uname -a 查看内核版本 ls -al 显示所有文件的属性 pwd 显示当前路径 cd - 返回上一次目录 cd ~ 返回主目录 date s 设置时间、日期 cal 显示日历 cal 2006 bc 计算器具 man & info 帮助手册 locale 显示当前字体 locale -a 所有可用字体 /etc/sysconfig/i18n设置文件 LANG=en 使用英文字体 sync 将数据同步写入硬盘 shutdonw -h now & half & poweroff 关机 reboot 重启 startx & init 5 进入图形介面 /work & ?work 向上、下查找文档内容 chgrp 改变档案群组 chgrp testing install.log chown 改变所属人 chown root:root install.log chmod 改变属性 chmod 777 install.log read=4 write=2 execute=1 cp 复制 cp filename rm 删除文件 rm -rf filename 强制删除文件 rmdir 删除文件夹 mv 移动 mv 123.txt 222.txt 重命名 mkdir 创建文件夹 touch 创建文件 更新当前时间 cat 由第一行开始显示 cat |more 分页 nl 在内容前加行号 more & less 一面一面翻动 head -n filename 显示第N行内容 tail -n filename 显示后N行内容 od 显示非纯文档 df -h 显示分区空间 du 显示目录或文件的大小 fdisk 分区设置 fdisk -l /dev/hda 显示硬盘分区状态 mkfs 建立各种文件系统 mkfs -t ext3 /dev/ram15 fsck 检查和修复LINUX档案 ln 硬链接 ln -s 软件链接 whereis 查找命令 locate 查找 find 查找 find / -name "***.***" which 查看工具 whoami 显示当前用户 gcc -v 查看GCC版本 chattr +i filename 禁止删除 chattr -i filename 取消禁止 lsattr 显示隐藏档属性 updatedb 更新资料库 mke2fs 格式化 mkfs -t ext3 dd if=/etc/passwd of=/tmp/passwd.bak 备份 mount 列出系统所有的分区 mount -t iso9660 /dev/cdrom /mnt/cdrom 挂载光盘 mount -t vfat /dev/fd0 /mnt/floppy 挂载软盘 mount -t vfat -o iocharset=utf8,umask=000 /dev/hda2 /mnt/hda2 挂载fat32分区 mount -t ntfs -o nls=utf8,umask=000 /dev/hda3 /mnt/hda3 挂载ntfs分区 Linux-NTFS Project: http://linux-ntfs.sourceforge.net/ umount /mnt/hda3 缷载 ifconfig 显示或设置网络设备 service network restart 重启网卡 ifdown eth0 关闭网卡 ifup eth0 开启网卡 clear 清屏 history 历史记录 !55 执行第55个指令 stty 设置终端 stty -a fdisk /mbr 删除GRUB at 僅進行一次的工作排程 crontab 循環執行的例行性命令 [e]编辑,[l]显示,[r]删除任务 & 后台运行程序 tar -zxvf 123.tar.gz & --------->后台运行 jobs 观看后台暂停的程序 jobs -l fg 将后台程序调到前台 fg n ------>n是数字,可以指定进行那个程序 bg 让工作在后台运行 kill 结束进程 kill -9 PID [9]强制结束,[15]正常结束,[l]列出可用的kill信号 ps aux 查看后台程序 top 查看后台程序 top -d 2 每两秒更新一次 top -d 2 -p10604 观看某个PID top -b -n 2 > /tmp/top.txt ----->將 top 的資訊進行 2 次,然後將結果輸出到 /tmp/top.txt pstree 以树状图显示程序 [A]以 ASCII 來連接, [u]列出PID, [p]列出帐号 killall 要刪除某個服務 killall -9 httpd free 显示内存状态 free -m -------->以M为单位显示 uptime 显示目前系统开机时间 netstat 显示网络状态 netstat -tulnp------>找出目前系統上已在監聽的網路連線及其 PID dmesg 显示开机信息 demsg | more nice 设置优先权 nice -n -5 vi & ----->用 root 給一個 nice 植為 -5 ,用於執行 vi renice 调整已存在优先权 runlevel 显示目前的runlevel depmod 分析可载入模块的相依性 lsmod 显示已载入系统的模块 modinfo 显示kernel模块的信息 insmod 载入模块 modprobe 自动处理可载入模块 rmmod 删除模块 chkconfig 检查,设置系统的各种服务 chkconfig --list ----->列出各项服务状态 ntsysv 设置系统的各种服务 cpio 备份文件
压缩命令: *.Z compress 程式壓縮的檔案; *.bz2 bzip2 程式壓縮的檔案; *.gz gzip 程式壓縮的檔案; *.tar tar 程式打包的資料,並沒有壓縮過; *.tar.gz tar 程式打包的檔案,其中並且經過 gzip 的壓縮 compress filename 压缩文件 加[-d]解压 uncompress gzip filename 压缩 加[-d]解压 zcat 123.gz 查看压缩文件内容 bzip2 -z filename 压缩 加[-d]解压 bzcat filename.bz2 查看压缩文件内容 tar -cvf /home/123.tar /etc 打包,不压缩 tar -xvf 123.tar 解开包 tar -zxvf /home/123.tar.gz 以gzip解压 tar -jxvf /home/123.tar.bz2 以bzip2解压 tar -ztvf /tmp/etc.tar.gz 查看tar内容 cpio -covB > [file|device] 份份 cpio -icduv < [file|device] 还原 vi一般用法 一般模式 编辑模式 指令模式 h 左 a,i,r,o,A,I,R,O :w 保存 j 下 进入编辑模式 :w! 强制保存 k 上 dd 删除光标当前行 :q! 不保存离开 l 右 ndd 删除n行 :wq! 保存后离开 0 移动到行首 yy 复制当前行 :e! 还原原始档 $ 移动到行尾 nyy 复制n行 :w filename 另存为 H 屏幕最上 p,P 粘贴 :set nu 设置行号 M 屏幕中央 u 撤消 :set nonu 取消行号 L 屏幕最下 [Ctrl]+r 重做上一个动作 ZZ 保存离开 G 档案最后一行 [ctrl]+z 暂停退出 :set nohlsearch 永久地关闭高亮显示 /work 向下搜索 :sp 同时打开两个文档 ?work 向上搜索 [Ctrl]+w 两个文档设换 gg 移动到档案第一行 :nohlsearch 暂时关闭高亮显示 认识SHELL alias 显示当前所有的命令别名 alias lm="ls -al" 命令别名 unalias lm 取消命令别名 type 类似which exprot 设置或显示环境变量 exprot PATH="$PATH":/sbin 添加/sbin入PATH路径 echo $PATH 显示PATH路径 bash 进入子程序 name=yang 设定变量 unset name 取消变量 echo $name 显示变量的内容 myname="$name its me" & myname='$name its me' 单引号时$name失去变量内容 ciw=/etc/sysconfig/network-scripts/ 设置路径 env 列出所有环境变量 echo $RANDOM 显示随意产生的数 set 设置SHELL PS1='[\u@\h \w \A #\#]\$ ' 提示字元的設定 [root@linux ~]# read [-pt] variable -----------读取键盘输入的变量 參數: -p :後面可以接提示字元! -t :後面可以接等待的『秒數!』 declare 声明 shell 变量 ulimit -a 显示所有限制资料 ls /tmp/yang && echo "exist" || echo "not exist" 意思是說,當 ls /tmp/yang 執行後,若正確,就執行echo "exist" ,若有問題,就執行echo "not exist" echo $PATH | cut -d ':' -f 5 以:为分隔符,读取第5段内容 export | cut -c 10-20 读取第10到20个字节的内容 last | grep 'root' 搜索有root的一行,加[-v]反向搜索 cat /etc/passwd | sort 排序显示 cat /etc/passwd | wc 显示『行、字数、字节数』 正规表示法 [root@test root]# grep [-acinv] '搜尋字串' filename 參數說明: -a :將 binary 檔案以 text 檔案的方式搜尋資料 -c :計算找到 '搜尋字串' 的次數 -i :忽略大小寫的不同,所以大小寫視為相同 -n :順便輸出行號 -v :反向選擇,亦即顯示出沒有 '搜尋字串' 內容的那一行! grep -n 'the' 123.txt 搜索the字符 -----------搜尋特定字串 grep -n 't[ea]st' 123.txt 搜索test或taste两个字符---------利用 [] 來搜尋集合字元 grep -n '[^g]oo' 123.txt 搜索前面不为g的oo-----------向選擇 [^] grep -n '[0-9]' 123.txt 搜索有0-9的数字 grep -n '^the' 123.txt 搜索以the为行首-----------行首搜索^ grep -n '^[^a-zA-Z]' 123.txt 搜索不以英文字母开头 grep -n '[a-z]$' 123.txt 搜索以a-z结尾的行---------- 行尾搜索$ grep -n 'g..d' 123.txt 搜索开头g结尾d字符----------任意一個字元 . grep -n 'ooo*' 123.txt 搜索至少有两个oo的字符---------重複字元 * sed 文本流编辑器 利用脚本命令来处理文本文件 awd 模式扫描和处理语言 nl 123.txt | sed '2,5d' 删除第二到第五行的内容 diff 比较文件的差异 cmp 比较两个文件是否有差异 patch 修补文件 pr 要打印的文件格式化
帐号管理 /etc/passwd 系统帐号信息 /etc/shadow 帐号密码信息 经MD5 32位加密 在密码栏前面加『 * 』『 ! 』禁止使用某帐号 /etc/group 系统群组信息 /etc/gshadow newgrp 改变登陆组 useradd & adduser 建立新用户 ---------> useradd -m test 自动建立用户的登入目录 useradd -m -g pgroup test --------->指定所属级 /etc/default/useradd 相关设定 /etc/login.defs UID/GID 有關的設定 passwd 更改密码 -----------> passwd test usermod 修改用户帐号 userdel 删除帐号 ----------->userdel -r test chsh 更换登陆系统时使用的SHELL [-l]显示可用的SHELL;[-s]修改自己的SHELL chfn 改变finger指令显示的信息 finger 查找并显示用户信息 id 显示用户的ID -----------> id test groupadd 添加组 groupmod 与usermod类似 groupdel 删除组 su test 更改用户 su - 进入root,且使用root的环境变量 sudo 以其他身份来执行指令 visudo 编辑/etc/sudoers 加入一行『 test ALL=(ALL) ALL 』 %wheel ALL = (ALL) ALL 系统里所有wheel群组的用户都可用sudo %wheel ALL = (ALL) NOPASSWD: ALL wheel群组所有用户都不用密码NOPASSWD User_Alias ADMPW = vbird, dmtsai, vbird1, vbird3 加入ADMPW组 ADMPW ALL = NOPASSWD: !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, \ !/usr/bin/passwd root 可以更改使用者密码,但不能更改root密码 (在指令前面加入 ! 代表不可) PAM (Pluggable Authentication Modules, 嵌入式模組) who & w 看谁在线 last 最近登陆主机的信息 lastlog 最近登入的時間 读取 /var/log/lastlog talk 与其他用户交谈 write 发送信息 write test [ctrl]+d 发送 mesg 设置终端机的写入权限 mesg n 禁止接收 mesg y wall 向所有用户发送信息 wall this is q test mail 写mail /etc/default/useradd 家目录默认设置 quota 显示磁盘已使用的空间与限制 quota -guvs ----->秀出目前 root 自己的 quota 限制值 quota -vu 查询 quotacheck 检查磁盘的使用空间与限制 quotacheck -avug ----->將所有的在 /etc/mtab 內,含有 quota 支援的 partition 進行掃瞄 [-m] 强制扫描 quota一定要是独立的分区,要有quota.user和quota.group两件文件,在/etc/fstab添加一句: /dev/hda3 /home ext3 defaults,usrquota,grpquota 1 2 chmod 600 quota* 设置完成,重启生效 edquota 编辑用户或群组的quota [u]用户,[g]群组,[p]复制,[t]设置宽限期限 edquota -a yang edquota -p yang -u young ----->复制 quotaon 开启磁盘空间限制 quotaon -auvg -------->啟動所有的具有 quota 的 filesystem quotaoff 关闭磁盘空间限制 quotaoff -a -------->關閉了 quota 的限制 repquota -av 查閱系統內所有的具有 quota 的 filesystem 的限值狀態 Quota 從開始準備 filesystem 的支援到整個設定結束的主要的步驟大概是: 1、設定 partition 的 filesystem 支援 quota 參數: 由於 quota 必須要讓 partition 上面的 filesystem 支援才行,一般來說, 支援度最好的是 ext2/ext3 , 其他的 filesystem 類型鳥哥我是沒有試過啦! 啟動 filesystem 支援 quota 最簡單就是編輯 /etc/fstab , 使得準備要開放的 quota 磁碟可以支援 quota 囉; 2、建立 quota 記錄檔: 剛剛前面講過,整個 quota 進行磁碟限制值記錄的檔案是 aquota.user/aquota.group, 要建立這兩個檔案就必須要先利用 quotacheck 掃瞄才行喔! 3、編輯 quota 限制值資料: 再來就是使用 edquota 來編輯每個使用者或群組的可使用空間囉; 4、重新掃瞄與啟動 quota : 設定好 quota 之後,建議可以再進行一次 quotacheck ,然後再以 quotaon 來啟動吧!
开机流程简介 1、載入 BIOS 的硬體資訊,並取得第一個開機裝置的代號; 2、讀取第一個開機裝置的 MBR 的 boot Loader (亦即是 lilo, grub, spfdisk 等等) 的開機資訊; 3、載入 Kernel 作業系統核心資訊, Kernel 開始解壓縮,並且嘗試驅動所有硬體裝置; 4、Kernel 執行 init 程式並取得 run-level 資訊; 5、init 執行 /etc/rc.d/rc.sysinit 檔案; 6、啟動核心的外掛模組 (/etc/modprobe.conf); 7、init 執行 run-level 的各個批次檔( Scripts ); 8、init 執行 /etc/rc.d/rc.local 檔案; 9、執行 /bin/login 程式,並等待使用者登入; 10、登入之後開始以 Shell 控管主機。 在/etc/rc.d/rc3.d內,以S开头的为开机启动,以K开头的为关闭,接着的数字代表执行顺序 GRUB vga设定 彩度\解析度 640x480 800x600 1024x768 1280x1024 bit 256 769 771 773 775 8 bit 32768 784 787 790 793 15 bit 65536 785 788 791 794 16 bit 16.8M 786 789 792 795 32 bit
./configure 检查系统信息 ./configure --help | more 帮助信息 make clean 清除之前留下的文件 make 编译 make install 安装 rpm -q ----->查询是否安装 rpm -ql ------>查询该套件所有的目录 rpm -qi ----->查询套件的说明资料 rpm -qc[d] ----->设定档与说明档 rpm -ivh ---->安装 rpm -V -------->查看套件有否更动过 rpm -e ------>删除 rpm -Uvh ------->升级安装 --nodeps ----->强行安装 --test ----->测试安装
JavaScript,是世界上最流行的编程语言之一。事实上世界上的每一台个人电脑都安装并在频繁使用至少一个JavaScript解释器。JavaScript的流行完全是由于他在WWW脚本语言领域中的地位决定的。
Despite its popularity, few know that JavaScript is a very nice dynamic object-oriented general-purpose programming language. How can this be a secret? Why is this language so misunderstood?
尽管它很流行,但是很少有人知道JavaScript是一个非常棒的动态面向对象通用编程语言。这居然能成为一个秘密!这门语言为什么被误解如此之深?
The Name
名字
The Java- prefix suggests that JavaScript is somehow related to Java, that it is a subset or less capable version of Java. It seems that the name was intentionally selected to create confusion, and from confusion comes misunderstanding. JavaScript is not interpreted Java. Java is interpreted Java. JavaScript is a different language.
Java- 前缀很容易使人联想到Java,并认为它是Java的子集或简化版的Java。看起来最初给它选这个名字是别有用心的,是故意混淆概念、故意制造"误解"的。JavaScript不是解释执行的Java。Java是解释执行的Java。JavaScript是另外一种语言。
JavaScript has a syntactic similarity to Java, much as Java has to C. But it is no more a subset of Java than Java is a subset of C. It is better than Java in the applications that Java (fka Oak) was originally intended for.
JavaScript的语法和Java有相似之处,这就像Java的语法和C很相像一样。但是它不是Java的子集,就像Java不是C的子集一样。它在Java(Oak)最初打算进军的领域中比Java更好。
JavaScript was not developed at Sun Microsystems, the home of Java. JavaScript was developed at Netscape. It was originally called LiveScript, but that name wasn't confusing enough.
JavaScript不是Sun Microsystems的产品,Sun是Java的家。JavaScript是在Netscape被开发出来的。它最初叫LiveScript,嗯……还是这个名字好。
The -Script suffix suggests that it is not a real programming language, that a scripting language is less than a programming language. But it is really a matter of specialization. Compared to C, JavaScript trades performance for expressive power and dynamism.
-Script后缀让人认为他不是一门真正的编程语言,和一门"编程语言"还有相当的差距。但是这只是应用领域的问题。和C相比,JavaScript是牺牲了性能但换来了丰富的表现力和灵活的形态。
Lisp in C's Clothing
披着C皮的Lisp
JavaScript's C-like syntax, including curly braces and the clunky for statement, makes it appear to be an ordinary procedural language. This is misleading because JavaScript has more in common with functional languages like Lisp or Scheme than with C or Java. It has arrays instead of lists and objects instead of property lists. Functions are first class. It has closures. You get lambdas without having to balance all those parens.
JavaScript的类C语法,包括大括号和语句的形式 ,让它看起来像普通的面向过程编程语言。这是一种误解 ,因为JavaScript和函数式语言,比如 Lisp 或 Scheme,有更多的相似之处,而不是和C或Java。它使用数组而不是列表 ,使用对象而不是属性列表。函数是第一位的,它有闭包 (closures),另外你还可以使用lambda表达式。
Typecasting
类型转换
JavaScript was designed to run in Netscape Navigator. Its success there led to it becoming standard equipment in virtually all web browsers. This has resulted in typecasting. JavaScript is the George Reeves of programming languages. JavaScript is well suited to a large class of non-Web-related applications
JavaScript最初被设计成在Netscape Navigator中运行,它在Navigator中的成功引领它成为事实上所有web浏览器的标准装备。这就造就了"类型转换"。JavaScript是编程语言中的 George Reeves(超人),是大量非web程序的称职之选。
Moving Target
移动靶
The first versions of JavaScript were quite weak. They lacked exception handling, inner functions, and inheritance. In its present form, it is now a complete object-oriented programming language. But many opinions of the language are based on its immature forms.
JavaScript的最初几版非常弱,没有异常处理,没有内部函数和继承。现如今,它已经成为完全面向对象的编程语言。但是这门语言的许多思想是基于它不成熟的形式的。
The ECMA committee that has stewardship over the language is developing extensions which, while well intentioned, will aggravate one of the language's biggest problems: There are already too many versions. This creates confusion.
ECMA委员会,这门语言的管家,正在对它进行扩展,也在蓄意恶化它最大的问题:有太多的版本。这是混乱的根源。
Design Errors
设计上的错误
No programming language is perfect. JavaScript has its share of design errors, such as the overloading of + to mean both addition and concatenation with type coercion, and the error-prone with statement should be avoided. The reserved word policies are much too strict. Semicolon insertion was a huge mistake, as was the notation for literal regular expressions. These mistakes have led to programming errors, and called the design of the language as a whole into question. Fortunately, many of these problems can be mitigated with a good lint program.
没有什么编程语言是完美的。JavaScript也有它设计上的错误,比如重载的+号随着类型的不同既表示"相加"又表示"连接",和本该避免的有错误倾向的 with 语句。它的保留字策略过于严格。分号的插入是一个巨大的错误,比如作为字面正则表达式的符号时。这些失误已直接导致编程中的错误,也使这门语言的整体设计遭人质疑。还好,这些问题中有许多都可以在良好的 lint 程序中得以缓解。
The design of the language on the whole is quite sound. Surprisingly, the ECMAScript committee does not appear to be interested in correcting these problems. Perhaps they are more interested in making new ones.
这门语言的整体设计(上的问题)是相当明显的。奇怪的是ECMAScript委员会并没有对修正其中存在的问题表现出太大的兴趣,也许他们更热衷于制造新的问题。
Lousy Implementations
糟糕的实现
Some of the earlier implementations of JavaScript were quite buggy. This reflected badly on the language. Compounding that, those implementations were embedded in horribly buggy web browsers.
JavaScript的一些早期实现有许多bug,这反过来对语言本身产生了很坏的影响。更糟糕的是这些满是bug的实现是嵌入在满是bug的web浏览器中的。
Bad Books
糟糕的书
Nearly all of the books about JavaScript are quite awful. They contain errors, poor examples, and promote bad practices. Important features of the language are often explained poorly, or left out entirely. I have reviewed dozens of JavaScript books, and I can only recommend one: JavaScript: The Definitive Guide (4th Edition) by David Flanagan. (Attention authors: If you have written a good one, please send me a review copy.)
几乎所有的JavaScript书都是相当可怕的。它们包含错误,包含不好的例子,并鼓励不好的做法。JavaScript语言的一些重要特性它们要么没有解释清楚,要么根本就没有提及。我看过很多JavaScript的书,但我只能推荐一本:David Flanagan著的 JavaScript: The Definitive Guide (4th Edition) (《JavaScript权威指南 第四版》)。(作者们请注意:如果你们写出了好书请发给我一份副本,我给你们校对。)
Substandard Standard
“准标准”的标准
The official specification for the language is published by ECMA. The specification is of extremely poor quality. It is difficult to read and very difficult to understand. This has been a contributor to the Bad Book problem because authors have been unable to use the standard document to improve their own understanding of the language. ECMA and the TC39 committee should be deeply embarrassed.
ECMA公布的官方语言规范的质量极其的差。不仅难读而且极其难懂。它可为那些"糟糕的书"做出了不小的贡献,因为那些作者无法通过这个标准文档来更深地理解这门语言。ECMA和TC39应该为此感到非常尴尬。
Amateurs
业余者
Most of the people writing in JavaScript are not programmers. They lack the training and discipline to write good programs. JavaScript has so much expressive power that they are able to do useful things in it, anyway. This has given JavaScript a reputation of being strictly for the amateurs, that it is not suitable for professional programming. This is simply not the case.
使用JavaScript的人大多不是程序员,他们缺少写良好程序的培训和训练。JavaScript有非常强大的表现力,不管怎样他们也能使用它做有用的事情。这给了JavaScript一个”全然适合业余爱好者而不适合专业程序员“的名声。这很明显是一个错误。
Object-Oriented
面向对象
Is JavaScript object-oriented? It has objects which can contain data and methods that act upon that data. Objects can contain other objects. It does not have classes, but it does have constructors which do what classes do, including acting as containers for class variables and methods. It does not have class-oriented inheritance, but it does have prototype-oriented inheritance.
JavaScript是面向对象的吗?它有对象,它的对象可以包含数据以及对数据进行操作的方法,对象也可以包含其他的对象。它没有类,但是它有构造函数来做类的事情,包括声明类的变量和方法。它没有面向类的继承,但是他有面向原型的继承。
The two main ways of building up object systems are by inheritance (is-a) and by aggregation (has-a). JavaScript does both, but its dynamic nature allows it to excel at aggregation.
构建对象系统的两大主要方法是继承(is-a)和聚合(has-a)。这两者JavaScript都有,但是它的动态天性允许有比聚合更好的实现方式。
Some argue that JavaScript is not truly object oriented because it does not provide information hiding. That is, objects cannot have private variables and private methods: All members are public.
一些关于JavaScript不是真的面向对象的争论其理由是它没有提供信息隐藏。也就是说JavaScript的对象没有私有变量和私有方法:它的所有成员都是公开的。
But it turns out that JavaScript objects can have private variables and private methods. (Click here now to find out how.) Of course, few understand this because JavaScript is the world's most misunderstood programming language.
但是事实是JavaScript 的对象可以有私有变量和私有方法(点击这里来看如何实现)。当然,之所以很少有人知道这个是因为JavaScript是世界上误解最深的语言嘛。
Some argue that JavaScript is not truly object oriented because it does not provide inheritance. But it turns out that JavaScript supports not only classical inheritance, but other code reuse patterns as well.
另一些关于JavaScript不是真的面向对象的争论其理由是它没有提供继承。但是事实是JavaScript不但支持经典的继承,而且支持其他一些代码重用的模式。
觉得这篇文章很不错,转载过来与大家一起分享.
1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 <table border oncontextmenu=return(false)><td>no</table> 可用于Table
2. <body onselectstart="return false"> 取消选取、防止复制
3. onpaste="return false" 不准粘贴
4. oncopy="return false;" oncut="return false;" 防止复制
5. <link rel="Shortcut Icon" href="favicon.ico"> IE地址栏前换成自己的图标
6. <link rel="Bookmark" href="favicon.ico"> 可以在收藏夹中显示出你的图标
7. <input style="ime-mode:disabled"> 关闭输入法
8. 永远都会带着框架 <script language="JavaScript"><!-- if (window == top)top.location.href = "frames.htm"; //frames.htm为框架网页 // --></script>
9. 防止被人frame <SCRIPT LANGUAGE=JAVASCRIPT><!-- if (top.location != self.location)top.location=self.location; // --></SCRIPT>
10. 网页将不能被另存为 <noscript><*** src="/*.html>";</***></noscript>
11. <input type=button value="/查看网页源代码 onclick="window.location = "view-source:"+ "http://www.pconline.com.cn""> 12.删除时确认 <a href=""javascript :if(confirm("确实要删除吗?"))location="boos.asp?&areyou=删除&page=1"">删除</a>
13. 取得控件的绝对位置 //Javascript <script language="Javascript"> function getIE(e){ var t=e.offsetTop; var l=e.offsetLeft; while(e=e.offsetParent){ t+=e.offsetTop; l+=e.offsetLeft; } alert("top="+t+"/nleft="+l); } </script> //VBScript <script language="VBScript"><!-- function getIE() dim t,l,a,b set a=document.all.img1 t=document.all.img1.offsetTop l=document.all.img1.offsetLeft while a.tagName<>"BODY" set a = a.offsetParent t=t+a.offsetTop l=l+a.offsetLeft wend msgbox "top="&t&chr(13)&"left="&l,64,"得到控件的位置" end function --></script>
14. 光标是停在文本框文字的最后 <script language="javascript"> function cc() { var e = event.srcElement; var r =e.createTextRange(); r.moveStart("character",e.value.length); r.collapse(true); r.select(); } </script> <input type=text name=text1 value="123" onfocus="cc()">
15. 判断上一页的来源 javascript : document.referrer
16. 最小化、最大化、关闭窗口 <object id=hh1 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11"> <param name="Command" value="Minimize"></object> <object id=hh2 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11"> <param name="Command" value="Maximize"></object> <OBJECT id=hh3 classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"> <PARAM NAME="Command" value="/Close"></OBJECT> <input type=button value="/最小化 onclick=hh1.Click()> <input type=button value="/blog/最大化 onclick=hh2.Click()> <input type=button value=关闭 onclick=hh3.Click()> 本例适用于IE
17.屏蔽功能键Shift,Alt,Ctrl <script> function look(){ if(event.shiftKey) alert("禁止按Shift键!"); //可以换成ALT CTRL } document.onkeydown=look; </script>
18. 网页不会被缓存 <META HTTP-EQUIV="pragma" CONTENT="no-cache"> <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"> <META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT"> 或者<META HTTP-EQUIV="expires" CONTENT="0">
19.怎样让表单没有凹凸感? <input type=text style="""border:1 solid #000000"> 或 <input type=text style="border-left:none; border-right:none; border-top:none; border-bottom: 1 solid #000000"></textarea>
20.<div><span>&<layer>的区别? <div>(division)用来定义大段的页面元素,会产生转行 <span>用来定义同一行内的元素,跟<div>的唯一区别是不产生转行 <layer>是ns的标记,ie不支持,相当于<div>
21.让弹出窗口总是在最上面: <body onblur="this.focus();">
22.不要滚动条? 让竖条没有: <body style="overflow:scroll;overflow-y:hidden"> </body> 让横条没有: <body style="overflow:scroll;overflow-x:hidden"> </body> 两个都去掉?更简单了 <body scroll="no"> </body>
23.怎样去掉图片链接点击后,图片周围的虚线? <a href="#" onFocus="this.blur()"><img src="/logo.jpg" border=0></a>
24.电子邮件处理提交表单 <form name="form1" method="post" action=mailto:****@***.com enctype="text/plain"> <input type=submit> </form>
25.在打开的子窗口刷新父窗口的代码里如何写? window.opener.location.reload()
26.如何设定打开页面的大小 <body onload="top.resizeTo(300,200);"> 打开页面的位置<body onload="top.moveBy(300,200);">
27.在页面中如何加入不是满铺的背景图片,拉动页面时背景图不动 <STYLE> body {background-image:url(/logo.gif); background-repeat:no-repeat; background-position:center;background-attachment: fixed} </STYLE>
28. 检查一段字符串是否全由数字组成 <script language="Javascript"><!-- function checkNum(str){return str.match(//D/)==null} alert(checkNum("1232142141")) alert(checkNum("123214214a1")) // --></script>
29. 获得一个窗口的大小 document.body.clientWidth; document.body.clientHeight
30. 怎么判断是否是字符 if (/[^/x00-/xff]/g.test(s)) alert("含有汉字"); else alert("全是字符");
31.TEXTAREA自适应文字行数的多少 <textarea rows=1 name=s1 cols=27 onpropertychange ="this.style.posHeight=this.scrollHeight"> </textarea>
32. 日期减去天数等于第二个日期 <script language=Javascript> function cc(dd,dadd) { //可以加上错误处理 var a = new Date(dd) a = a.valueOf() a = a - dadd * 24 * 60 * 60 * 1000 a = new Date(a) alert(a.getFullYear() + "年" + (a.getMonth() + 1) + "月" + a.getDate() + "日") } cc("12/23/2002",2) </script>
33. 选择了哪一个Radio <HTML><script language="vbscript"> function checkme() for each ob in radio1 if ob.checked then window.alert ob.value next end function </script><BODY> <INPUT name="radio1" type="radio" value="/style" checked>Style <INPUT name="radio1" type="radio" value="/blog/barcode">Barcode <INPUT type="button" value="check" onclick="checkme()"> </BODY></HTML>
34.脚本永不出错 <SCRIPT LANGUAGE="JavaScript"> <!-- Hide function killErrors() { return true; } window.onerror = killErrors; // --> </SCRIPT>
35.ENTER键可以让光标移到下一个输入框 <input onkeydown="if(event.keyCode==13)event.keyCode=9">
36. 检测某个网站的链接速度: 把如下代码加入<body>区域中: <script language=Javascript> tim=1 setInterval("tim++",100) b=1 var autourl=new Array() autourl[1]=1000){this.resized=true;this.style.width=1000;}" align=absMiddle border=0>www.njcatv.net" autourl[2]="javacool.3322.net" autourl[3]=1000){this.resized=true;this.style.width=1000;}" align=absMiddle border=0>www.sina.com.cn" autourl[4]="www.nuaa.edu.cn" autourl[5]=1000){this.resized=true;this.style.width=1000;}" align=absMiddle border=0>www.cctv.com" function butt(){ ***("<form name=autof>") for(var i=1;i<autourl.length;i++) ***("<input type=text name=txt"+i+" size=10 value="/测试中……> =》<input type=text name=url"+i+" size=40> =》<input type=button value="/blog/GO onclick=window.open(this.form.url"+i+".value)><br>") ***("<input type=submit value=刷新></form>") } butt() function auto(url){ document.forms[0]["url"+b].value=url if(tim>200) {document.forms[0]["txt"+b].value="/链接超时"} else {document.forms[0]["txt"+b].value="/blog/时间"+tim/10+"秒"} b++ } function run(){for(var i=1;i<autourl.length;i++)***("<img src=http://"+autourl+"/"+Math.random()+" width=1 height=1 onerror=auto("http://"+autourl+"")>")} run()</script>
37. 各种样式的光标 auto :标准光标 default :标准箭头 hand :手形光标 wait :等待光标 text :I形光标 vertical-text :水平I形光标 no-drop :不可拖动光标 not-allowed :无效光标 help :?帮助光标 all-scroll :三角方向标 move :移动标 crosshair :十字标 e-resize n-resize nw-resize w-resize s-resize se-resize sw-resize
38.页面进入和退出的特效 进入页面<meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)"> 推出页面<meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)"> 这个是页面被载入和调出时的一些特效。duration表示特效的持续时间,以秒为单位。transition表示使用哪种特效,取值为1-23: 0 矩形缩小 1 矩形扩大 2 圆形缩小 3 圆形扩大 4 下到上刷新 5 上到下刷新 6 左到右刷新 7 右到左刷新 8 竖百叶窗 9 横百叶窗 10 错位横百叶窗 11 错位竖百叶窗 12 点扩散 13 左右到中间刷新 14 中间到左右刷新 15 中间到上下 16 上下到中间 17 右下到左上 18 右上到左下 19 左上到右下 20 左下到右上 21 横条 22 竖条 23 以上22种随机选择一种
39.在规定时间内跳转 <META http-equiv=V="REFRESH" content="5;URL=http://www.51js.com">
40.网页是否被检索 <meta name="ROBOTS" content="属性值"> 其中属性值有以下一些: 属性值为"all": 文件将被检索,且页上链接可被查询; 属性值为"none": 文件不被检索,而且不查询页上的链接; 属性值为"index": 文件将被检索; 属性值为"follow": 查询页上的链接; 属性值为"noindex": 文件不检索,但可被查询链接; 属性值为"nofollow": 文件不被检索,但可查询页上的链接。
41、email地址的分割 把如下代码加入<body>区域中 <a href="mailto:webmaster@sina.com">webmaster@sina.com</a>
42、流动边框效果的表格 把如下代码加入<body>区域中 <SCRIPT> l=Array(6,7,8,9,'a','b','b','c','d','e','f') Nx=5;Ny=35 t="<table border=0 cellspacing=0 cellpadding=0 height="+((Nx+2)*16)+"><tr>" for(x=Nx;x<Nx+Ny;x++) t+="<td width=16 id=a_mo"+x+"> </td>" t+="</tr><tr><td width=10 id=a_mo"+(Nx-1)+"> </td><td colspan="+(Ny-2)+" rowspan="+(Nx)+"> </td><td width=16 id=a_mo"+(Nx+Ny)+"></td></tr>" for(x=2;x<=Nx;x++) t+="<tr><td width=16 id=a_mo"+(Nx-x)+"> </td><td width=16 id=a_mo"+(Ny+Nx+x-1)+"> </td></tr>" t+="<tr>" for(x=Ny;x>0;x--) t+="<td width=16 id=a_mo"+(x+Nx*2+Ny-1)+"> </td>" ***(t+"</tr></table>") var N=Nx*2+Ny*2 function f1(y){ for(i=0;i<N;i++){ c=(i+y)%20;if(c>10)c=20-c document.all["a_mo"+(i)].bgColor=""""#0000"+l[c]+l[c]+"'"} y++ setTimeout('f1('+y+')','1')} f1(1) </SCRIPT>
43、JavaScript主页弹出窗口技巧 窗口中间弹出 <script> window.open("http://www.cctv.com","","width=400,height=240,top="+(screen.availHeight-240)/2+",left="+(screen.availWidth-400)/2); </script> ============ <html> <head> <script language="LiveScript"> function WinOpen() { msg=open("","DisplayWindow","toolbar=no,directories=no,menubar=no"); msg.***("<HEAD><TITLE>哈 罗!</TITLE></HEAD>"); msg.***("<CENTER><H1>酷 毙 了!</H1><h2>这 是<B>JavaScript</B>所 开 的 视 窗!</h2></CENTER>"); } </script> </head> <body> <form> <input type="button" name="Button1" value="Push me" onclick="WinOpen()"> </form> </body> </html> ============== 一、在下面的代码中,你只要单击打开一个窗口,即可链接到赛迪网。而当你想关闭时,只要单击一下即可关闭刚才打开的窗口。 代码如下: <SCRIPT language="JavaScript"> <!-- function openclk() { another=open('1000){this.resized=true;this.style.width=1000;}" align=absMiddle border=0>http://www.ccidnet.com','NewWindow'); } function closeclk() { another.close(); } //--> </SCRIPT> <FORM> <INPUT TYPE="BUTTON" NAME="open" value="/打开一个窗口" onClick="openclk()"> <BR> <INPUT TYPE="BUTTON" NAME="close" value="/blog/关闭这个窗口" onClick="closeclk()"> </FORM> 二、上面的代码也太静了,为何不来点动感呢?如果能给页面来个降落效果那该多好啊! 代码如下: <script> function drop(n) { if(self.moveBy){ self.moveBy (0,-900); for(i = n; i > 0; i--){ self.moveBy(0,3); } for(j = 8; j > 0; j--){ self.moveBy(0,j); self.moveBy(j,0); self.moveBy(0,-j); self.moveBy(-j,0); } } } </script> <body onLoad="drop(300)"> 三、讨厌很多网站总是按照默认窗口打开,如果你能随心所欲控制打开的窗口那该多好。 代码如下: <SCRIPT LANGUAGE="JavaScript"> <!-- Begin function popupPage(l, t, w, h) { var windowprops = "location=no,scrollbars=no,menubars=no,toolbars=no,resizable=yes" + ",left=" + l + ",top=" + t + ",width=" + w + ",height=" + h; var URL = "http://www.80cn.com"; popup = window.open(URL,"MenuPopup",windowprops); } // End --> </script> <table> <tr> <td> <form name=popupform> <pre> 打开页面的参数<br> 离开左边的距离: <input type=text name=left size=2 maxlength=4> pixels 离开右边的距离: <input type=text name=top size=2 maxlength=4> pixels 窗口的宽度: <input type=text name=width size=2 maxlength=4> pixels 窗口的高度: <input type=text name=height size=2 maxlength=4> pixels </pre> <center> <input type=button value="打开这个窗口!" onClick="popupPage(this.form.left.value, this.form.top.value, this.form.width.value, this.form.height.value)"> </center> </form> </td> </tr> </table>你只要在相对应的对话框中输入一个数值即可,将要打开的页面的窗口控制得很好。
44、页面的打开移动 把如下代码加入<body>区域中 <SCRIPT LANGUAGE="JavaScript"> <!-- Begin for (t = 2; t > 0; t--) { for (x = 20; x > 0; x--) { for (y = 10; y > 0; y--) { parent.moveBy(0,-x); } } for (x = 20; x > 0; x--) { for (y = 10; y > 0; y--) { parent.moveBy(0,x); } } for (x = 20; x > 0; x--) { for (y = 10; y > 0; y--) { parent.moveBy(x,0); } } for (x = 20; x > 0; x--) { for (y = 10; y > 0; y--) { parent.moveBy(-x,0); } } } //--> // End --> </script>
45、显示个人客户端机器的日期和时间 <script language="LiveScript"> <!-- Hiding today = new Date() ***("现 在 时 间 是: ",today.getHours(),":",today.getMinutes()) ***("<br>今 天 日 期 为: ", today.getMonth()+1,"/",today.getDate(),"/",today.getYear()); // end hiding contents --> </script>
46、自动的为你每次产生最後修改的日期了: <html> <body> This is a simple HTML- page. <br> Last changes: <script language="LiveScript"> <!-- hide script from old browsers ***(document.lastModified) // end hiding contents --> </script> </body> </html>
47、不能为空和邮件地址的约束: <html> <head> <script language="JavaScript"> <!-- Hide function test1(form) { if (form.text1.value == "") alert("您 没 写 上 任 何 东 西, 请 再 输 入 一 次 !") else { alert("嗨 "+form.text1.value+"! 您 已 输 入 完 成 !"); } } function test2(form) { if (form.text2.value == "" || form.text2.value.indexOf('@', 0) == -1) alert("这 不 是 正 确 的 e-mail address! 请 再 输 入 一 次 !"); else alert("您 已 输 入 完 成 !"); } // --> </script> </head> <body> <form name="first"> Enter your name:<br> <input type="text" name="text1"> <input type="button" name="button1" value="输 入 测 试" onClick="test1(this.form)"> <P> Enter your e-mail address:<br> <input type="text" name="text2"> <input type="button" name="button2" value="输 入 测 试" onClick="test2(this.form)"> </body>
48、跑马灯 <html> <head> <script language="JavaScript"> <!-- Hide var scrtxt="怎麽样 ! 很酷吧 ! 您也可以试试."+"Here goes your message the visitors to your page will "+"look at for hours in pure fascination..."; var lentxt=scrtxt.length; var width=100; var pos=1-width; function scroll() { pos++; var scroller=""; if (pos==lentxt) { pos=1-width; } if (pos<0) { for (var i=1; i<=Math.abs(pos); i++) { scroller=scroller+" ";} scroller=scroller+scrtxt.substring(0,width-i+1); } else { scroller=scroller+scrtxt.substring(pos,width+pos); } window.status = scroller; setTimeout("scroll()",150); } //--> </script> </head> <body onLoad="scroll();return true;"> 这里可显示您的网页 ! </body> </html>
49、在网页中用按钮来控制前页,后页和主页的显示。 <html> <body> <FORM NAME="buttonbar"> <INPUT TYPE="button" VALUE="Back" onClick="history.back()"> <INPUT TYPE="button" VALUE="JS- Home" onClick="location='script.html'"> <INPUT TYPE="button" VALUE="Next" onCLick="history.forward()"> </FORM> </body> </html> 50、查看某网址的源代码 把如下代码加入<body>区域中 <SCRIPT> function add() { var ress=document.forms[0].luxiaoqing.value window.location="view-source:"+ress; } </SCRIPT> 输入要查看源代码的URL地址: <FORM><input type="text" name="luxiaoqing" size=40 value="http://"></FORM> <FORM><br> <INPUT type="button" value="查看源代码" onClick=add()> </FORM>
51、title显示日期 把如下代码加入<body>区域中: <script language="JavaScript1.2"> <!--hide var isnMonth = new Array("1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"); var isnDay = new Array("星期日","星期一","星期二","星期三","星期四","星期五","星期六","星期日"); today = new Date () ; Year=today.getYear(); Date=today.getDate(); if (document.all) document.title="今天是: "+Year+"年"+isnMonth[today.getMonth()]+Date+"日"+isnDay[today.getDay()] //--hide--> </script>
52、显示所有链接 把如下代码加入<body>区域中 <script language="JavaScript1.2"> <!-- function extractlinks(){ var links=document.all.tags("A") var total=links.length var win2=window.open("","","menubar,scrollbars,toolbar") win2.***("<font size='2'>一共有"+total+"个连接</font><br>") for (i=0;i<total;i++){ win2.***("<font size='2'>"+links[i].outerHTML+"</font><br>") } } //--> </script> <input type="button" onClick="extractlinks()" value="显示所有的连接">
53、回车键换行 把如下代码加入<body>区域中 <script type="text/javascript"> function handleEnter (field, event) { var keyCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode; if (keyCode == 13) { var i; for (i = 0; i < field.form.elements.length; i++) if (field == field.form.elements[i]) break; i = (i + 1) % field.form.elements.length; field.form.elements[i].focus(); return false; } else return true; } </script> <form> <input type="text" onkeypress="return handleEnter(this, event)"><br> <input type="text" onkeypress="return handleEnter(this, event)"><br> <textarea>回车换行
54、确认后提交 把如下代码加入<body>区域中 <SCRIPT LANGUAGE="JavaScript"> <!-- function msg(){ if (confirm("你确认要提交嘛!")) document.lnman.submit() } //--> </SCRIPT> <form name="lnman" method="post" action=""> <p> <input type="text" name="textfield" value="确认后提交"> </p> <p> <input type="button" name="Submit" value="提交" onclick="msg();"> </p> </form>
55、改变表格的内容 把如下代码加入<body>区域中 <script> var arr=new Array() arr[0]="一一一一一"; arr[1]="二二二二二"; arr[2]="三三三三三"; </script> <select onchange="zz.cells[this.selectedIndex].innerHTML=arr[this.selectedIndex]"> <option value=a>改变第一格</option> <option value=a>改变第二格</option> <option value=a>改变第三格</option> </select> <table id=zz border=1> <tr height=20> <td width=150>第一格</td> <td width=150>第二格</td> <td width=150>第三格</td> </tr> </table>
webservice的工作原理
实际上,WebService的主要目标是跨平台的可互操作性。为了达到这一目标,WebService完全基于XML(可扩展标记语言)、XSD(XMLSchema)等独立于平台、独立于软件供应商的标准,是创建可互操作的、分布式应用程序的新平台。由此可以看出,在以下四种情况下,使用WebService会带来极大的好处。
优势一:跨防火墙的通信
如果应用程序有成千上万的用户,而且分布在世界各地,那么客户端和服务器之间的通信将是一个棘手的问题。因为客户端和服务器之间通常会有防火墙或者代理服务器。在这种情况下,使用DCOM就不是那么简单,通常也不便于把客户端程序发布到数量如此庞大的每一个用户手中。传统的做法是,选择用浏览器作为客户端,写下一大堆ASP页面,把应用程序的中间层暴露给最终用户。这样做的结果是开发难度大,程序很难维护。
举个例子,在应用程序里加入一个新页面,必须先建立好用户界面(Web页面),并在这个页面后面,包含相应商业逻辑的中间层组件,还要再建立至少一个ASP页面,用来接受用户输入的信息,调用中间层组件,把结果格式化为HTML形式,最后还要把“结果页”送回浏览器。要是客户端代码不再如此依赖于HTML表单,客户端的编程就简单多了。
如果中间层组件换成WebService的话,就可以从用户界面直接调用中间层组件,从而省掉建立ASP页面的那一步。要调用WebService,可以直接使用MicrosoftSOAPToolkit或.NET这样的SOAP客户端,也可以使用自己开发的SOAP客户端,然后把它和应用程序连接起来。不仅缩短了开发周期,还减少了代码复杂度,并能够增强应用程序的可维护性。同时,应用程序也不再需要在每次调用中间层组件时,都跳转到相应的“结果页”。
从经验来看,在一个用户界面和中间层有较多交互的应用程序中,使用WebService这种结构,可以节省花在用户界面编程上20%的开发时间。另外,这样一个由WebService组成的中间层,完全可以在应用程序集成或其它场合下重用。最后,通过WebService把应用程序的逻辑和数据“暴露”出来,还可以让其它平台上的客户重用这些应用程序。
优势二:应用程序集成
允许在不同平台上、以不同语言编写的各种程序以基于标准的方式相互通信。企业级的应用程序开发者都知道,企业里经常都要把用不同语言写成的、在不同平台上运行的各种程序集成起来,而这种集成将花费很大的开发力量。应用程序经常需要从运行在IBM主机上的程序中获取数据;或者把数据发送到主机或UNIX应用程序中去。即使在同一个平台上,不同软件厂商生产的各种软件也常常需要集成起来。通过WebService,应用程序可以用标准的方法把功能和数据“暴露”出来,供其它应用程序使用。
例如,有一个订单记录程序,用于从客户获得新订单,包括客户信息、发货地址、数量、价格和付款方式等内容;还有一个订单执行程序,用于实际货物发送的管理。这两个程序来自不同软件厂商。一份新订单进来之后,订单记录程序需要通知订单执行程序发送货物。通过在订单执行程序上面增加一层WebService,订单执行程序可以把“AddOrder”函数“暴露”出来。这样,每当有新订单到来时,订单登录程序就可以调用这个函数来发送货物了。
优势三:B2B的集成
用WebService集成应用程序,可以使公司内部的商务处理更加自动化。但当交易跨越供应商和客户、突破公司的界限时会怎么样呢?跨公司的商务交易集成通常叫做B2B集成。
WebService是B2B集成成功的关键。通过WebService,公司可以把关键的商务应用“暴露”给指定的供应商和客户。例如,把电子下单系统和电子发票系统“暴露”出来,客户就可以以电子的方式发送订单,供应商则可以以电子的方式发送原料采购发票。当然,这并不是一个新的概念,EDI(电子文档交换)早就是这样了。但是,WebService的实现要比EDI简单得多,而且WebService运行在Internet上,在世界任何地方都可轻易实现,其运行成本就相对较低。不过,WebService并不像EDI那样,是文档交换或B2B集成的完整解决方案。WebService只是B2B集成的一个关键部分,还需要许多其它的部分才能实现集成。
用WebService来实现B2B集成的最大好处在于可以轻易实现互操作性。只要把商务逻辑“暴露”出来,成为WebService,就可以让任何指定的合作伙伴调用这些商务逻辑,而不管他们的系统在什么平台上运行,使用什么开发语言。这样就大大减少了花在B2B集成上的时间和成本,让许多原本无法承受EDI的中小企业也能实现B2B集成。
优势四:软件和数据重用
软件重用是一个很大的主题,重用的形式很多,重用的程度有大有小。最基本的形式是源代码模块或者类一级的重用,另一种形式是二进制形式的组件重用。
用WebService集成各种应用中的功能,为用户提供一个统一的界面
当前,像表格控件或用户界面控件这样的可重用软件组件,在市场上都占有很大的份额。但这类软件的重用有一个很大的限制,就是重用仅限于代码,数据不能重用。原因在于,发布组件甚至源代码都比较容易,但要发布数据就没那么容易,除非是不会经常变化的静态数据。
WebService在允许重用代码的同时,可以重用代码背后的数据。使用WebService,再也不必像以前那样,要先从第三方购买、安装软件组件,再从应用程序中调用这些组件;只需要直接调用远端的WebService就可以了。举个例子,要在应用程序中确认用户输入的地址,只需把这个地址直接发送给相应的WebService,这个WebService就会帮你查阅街道地址、城市、省区和邮政编码等信息,确认这个地址是否在相应的邮政编码区域。WebService的提供商可以按时间或使用次数来对这项服务进行收费。这样的服务要通过组件重用来实现是不可能的,那样的话你必须下载并安装好包含街道地址、城市、省区和邮政编码等信息的数据库,而且这个数据库还是不能实时更新的。
另一种软件重用的情况是,把好几个应用程序的功能集成起来。例如,要建立一个局域网上的门户站点应用,让用户既可以查询联邦快递包裹,查看股市行情,又可以管理自己的日程安排,还可以在线购买电影票。现在Web上有很多应用程序供应商,都在其应用中实现了这些功能。一旦他们把这些功能都通过WebService“暴露”出来,就可以非常容易地把所有这些功能都集成到你的门户站点中,为用户提供一个统一的、友好的界面。
将来,许多应用程序都会利用WebService,把当前基于组件的应用程序结构扩展为组件/WebService的混合结构,可以在应用程序中使用第三方的WebService提供的功能,也可以把自己的应用程序功能通过WebService提供给别人。两种情况下,都可以重用代码和代码背后的数据。
从以上论述可以看出,WebService在通过Web进行互操作或远程调用的时候是最有用的。不过,也有一些情况,WebService根本不能带来任何好处。
短处一:单机应用程序
目前,企业和个人还使用着很多桌面应用程序。其中一些只需要与本机上的其它程序通信。在这种情况下,最好就不要用WebService,只要用本地的API就可以了。COM非常适合于在这种情况下工作,因为它既小又快。运行在同一台服务器上的服务器软件也是这样。最好直接用COM或其它本地的API来进行应用程序间的调用。当然WebService也能用在这些场合,但那样不仅消耗太大,而且不会带来任何好处。
短处二:局域网的同构应用程序
在许多应用中,所有的程序都是用VB或VC开发的,都在Windows平台下使用COM,都运行在同一个局域网上。例如,有两个服务器应用程序需要相互通信,或者有一个Win32或WinForm的客户程序要连接局域网上另一个服务器的程序。在这些程序里,使用DCOM会比SOAP/HTTP有效得多。与此相类似,如果一个.NET程序要连接到局域网上的另一个.NET程序,应该使用.NETremoting。有趣的是,在.NETremoting中,也可以指定使用SOAP/HTTP来进行WebService调用。不过最好还是直接通过TCP进行RPC调用,那样会有效得多。
总之,只要从应用程序结构的角度看,有别的方法比WebService更有效、更可行,那就不要用WebService。
将Web Service定义为:通过 SOAP 在 Web上提供的软件服务,使用 WSDL 文件进行说明,并通过 UDDI 进行注册。
Web Service架构:Web Service是独立的、模块化的应用,能够通过因特网来描述、发布、定位以及调用。在Web Service的体系架构中包括三个角色:服务提供者(Service Provider)、服务请求者(Service Requestor)、服务注册器(Service Registry)。角色间主要有三个操作:发布(Publish)、查找(Find)、绑定(Bind)。
下图清楚的描述了三种角色,以及角色之间的作用关系。
Web Service协议标准
1、简单对象访问协议(SOAP)
SOAP是Simple Object Access Protocol的缩写,是一种基于XML的不依赖传输协议的表示层协议,用来在分散或分布式的应用程序之间方便地以对象的形式交换数据。在SOAP的下层,可以是HTTP,也可以是SMTP/POP3,还可以是为一些应用而专门设计的特殊的通信协议。
SOAP包括三个主要部分:
SOAP封装结构:定义了一个整体框架,以表示消息中包含什么内容,谁来处理这些内容以及这些内容是可选的或是必需的。
SOAP编码规则:定义了用以交换应用程序定义的数据类型的实例的一系列机制。
SOAP RPC表示:定义了一个用来表示远程过程调用和应答的协定。
2、Web Service描述语言(WSDL)
WSDL是Web Service Description Language的缩写,该语言将网络服务定义成一个能交换消息的通信端点集,为分布式系统提供了帮助文档,同时也可作为自动实现应用间通信的解决方案。
3、统一描述、发现和集成协议(UDDI)
UDDI是一套基于Web的、分布式的、为Web Service提供的、信息注册中心的实现标准规范,同时也包含一组使企业能将自身提供的Web Service注册,以使别的企业能够发现的访问协议的实现标准。
通过xfire实现了webservice。下面详细介绍一下xfire。
XFire是一个免费的,开源的SOAP框架. 它不仅允许你轻松简易地实现这么一个环境.而且还提供了很多先进的特性.如果你的Web应用有一个Java类, 现在你希望这个类变成Web服务,用XFire完成这一工作你不必写一句代码.仅需操作一下部署描述器,你就会得到一个Web服务.
一、建立接口文件com.resoft.recis.ws.ReCISService
public interface ReCISService {
//请求系统设置信息
public AppInfo getAppInfo();
}
public class ReCISServiceImp implements ReCISService {
public com.resoft.recis.ws.AppInfo getAppInfo() {
// TODO Auto-generated method stub
return com.resoft.recis.ws.AppInfo.getAppInfo();
}
}
二、已存在类com.resoft.recis.ws. AppInfo
public class AppInfo {
double cardLeft;
/** default constructor */
public AppInfo() {
}
public double getCardLeft() {
return cardLeft;
}
public void setCardLeft(double cardLeft) {
this.cardLeft = cardLeft;
}
public static AppInfo getAppInfo() {
Session session = HibernateUtil.getSession();
com.resoft.recis.biz.AppInfo dbappinfo = (com.resoft.recis.biz.AppInfo) Util
.getHQLResult(session, "from AppInfo");
if (dbappinfo == null) {
return null;
}
com.resoft.recis.ws.AppInfo appinfo = new com.resoft.recis.ws.AppInfo();
appinfo.setOperid("");
appinfo.setOrgcode("");
appinfo.setCardHeight(dbappinfo.getCardHeight());
appinfo.setCardLeft(dbappinfo.getCardLeft());
appinfo.setCardTop(dbappinfo.getCardTop());
appinfo.setCardWidth(dbappinfo.getCardWidth());
HibernateUtil.closeSession();
return appinfo;
}
}
三、Web.xml应用的部署描述
<!— xfire的servlet配置文件 -->
<servlet>
<servlet-name>XFireServlet</servlet-name>
<display-name>XFire Servlet</display-name>
<servlet-class>
org.codehaus.xfire.transport.http.XFireConfigurableServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
四、创建services.xml文件
XFire本身就是基于Servlet的应用,xfire使用services.xml文件来完成Web服务配置。这个文件位于src/META-INF/xfire目录下,
src\META-INF\xfire
下面是基本的配置条目,这个配置文件中配置了xfire的接口,实现与验印控件的交互。
<beans xmlns="http://xfire.codehaus.org/config/1.0">
<service>
<name>ReCISService</name>
<namespace>http://resoft</namespace>
<serviceClass>com.resoft.recis.ws.ReCISService</serviceClass> <implementationClass>com.resoft.recis.ws.ReCISServiceImp</implementat ionClass>
</service>
</beans>
services.xml文件中的具体内容如下:
<service>元素:
对Web服务的定义包含在<service>元素内。<service>元素下还有若干子元素。
<name>子元素:
可以提供任何有效的xml名字,这个名字会被客户端程序和服务器上的其他组件使用.例如,当服务器起来以后,你可以在浏览器上使用这个名称来查看WSDL.
<namespace>子元素:
任何有效地xml名称都可以, <namespace>将作为你服务器的唯一标识变量使用.
<serviceClass>子元素:
包含Java类名用来指明方法的签名.在这个例子中是ReCISService接口.如果Java类没有实现任何接口,那就填入类名.只需要这一个入口来将他们转换成Web服务.
<implementationClass>子元素:
记录实现接口的Java类名.这是一个可选元素.如果前一个元素<serviceClass>填入的是接口,那么此处就要填入相应的实现类名.
五、XFire和所有必要的库文件
访问XFire官方网站http://xfire.codehaus.org/ 下载xfire-distribution-1.2.5.zip并解压到本地文件夹中.参考xfire-distribution-1.2.5\xfire-1.2.5\manual\Dependency Guide.html中介绍拷贝相关jar包到WEB-INF\lib,xfire-distribution-1.2.5需要的jar包如下:
xfire-all-1.2.5.jar
activation-1.1.jar
commons-codec-1.3.jar
commons-httpclient-3.0.jar
commons-logging-1.0.4.jar
mail-1.4.jar
jaxen-1.1-beta-9.jar
jdom-1.0.jar
junit-3.8.1.jar
servlet-api-2.3.jar
spring-1.2.6.jar
stax-api-1.0.1.jar
wsdl4j-1.6.1.jar
wstx-asl-3.2.0.jar
xbean-2.2.0.jar
xbean-spring-2.8.jar
XmlSchema-1.1.jar
xfire-jsr181-api-1.0-M1.jar
六、通过URL验证Web服务有效性
首先,我们先来看看WSDL是否有效。在浏览器中输入URL地址为http://127.0.0.1/test/services/ReCISService?wsdl 注意URL中IP地址和端口号是否需要修改。如果输入了有效的URL,将会看到以<wsdl:definitions>为根结点的xml文件。这个文件叫做web服务的WSDL.如果你看到了这个文件,那么初步验证你的Web服务有效。
但是这个验证还不够。有时候情况会复杂一些,你可以看到WSDL,但是客户端却无法访问Web服务。因此要真正检验Web服务是否真的好使,就要用客户端程序对Web服务作一次真正的调用。
七、客户端验证Web服务有效性
建立下面测试类测试Web服务器的有效性。
public class TestWebservice
{
public static void main(String args[])
{
String serviceURL ="http://127.0.0.1/test/services/ReCISService";
Service serviceModel = new ObjectServiceFactory().create(ReCISService.class,null,"http://resoft",null);
XFireProxyFactory serviceFactory = new XFireProxyFactory();
try
{
ReCISService service = (ReCISService) serviceFactory.create(serviceModel, serviceURL);
Client client = Client.getInstance(service);
System.out.println("begin");
com.resoft.recis.ws.AppInfo ai=service.getAppInfo();
System.out.println(ai.getCardHeight());
System.out.println("end");
}
catch (MalformedURLException e)
{
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Web service到底是什么;在什么情况下你应该使用Web service。
分布式应用程序和浏览器
研究一下当前的应用程序开发,你会发现一个绝对的倾向:人们开始偏爱基于浏览器的瘦客户应用程序。这当然不是因为瘦客户能够提供更好的用户界面,而是因为它能够避免花在桌面应用程序发布上的高成本。发布桌面应用程序成本很高,一半是因为应用程序安装和配置的问题,另一半是因为客户和服务器之间通信的问题。
传统的Windows富客户应用程序使用DCOM来与服务器进行通信和调用远程对象。配置好DCOM使其在一个大型的网络中正常工作将是一个极富挑战性的工作,同时也是许多IT工程师的噩梦。事实上,许多IT工程师宁愿忍受浏览器所带来的功能限制,也不愿在局域网上去运行一个DCOM。在我看来,结果就是一个发布容易,但开发难度大而且用户界面极其受限的应用程序。极端的说,就是你花了更多的资金和时间,却开发出从用户看来功能更弱的应用程序。不信?问问你的会计师对新的基于浏览器的会计软件有什么想法:绝大多数商用程序用户希望使用更加友好的Windows用户界面。
关于客户端与服务器的通信问题,一个完美的解决方法是使用HTTP协议来通信。这是因为任何运行Web浏览器的机器都在使用HTTP协议。同时,当前许多防火墙也配置为只允许HTTP连接。
许多商用程序还面临另一个问题,那就是与其他程序的互操作性。如果所有的应用程序都是使用COM或.NET语言写的,并且都运行在Windows平台上,那就天下太平了。然而,事实上大多数商业数据仍然在大型主机上以非关系文件(VSAM)的形式存放,并由COBOL语言编写的大型机程序访问。而且,目前还有很多商用程序继续在使用C++、Java、Visual Basic和其他各种各样的语言编写。现在,除了最简单的程序之外,所有的应用程序都需要与运行在其他异构平台上的应用程序集成并进行数据交换。这样的任务通常都是由特殊的方法,如文件传输和分析,消息队列,还有仅适用于某些情况的的API,如IBM的"高级程序到程序交流(APPC)"等来完成的。在以前,没有一个应用程序通信标准,是独立于平台、组建模型和编程语言的。只有通过Web Service,客户端和服务器才能够自由的用HTTP进行通信,不论两个程序的平台和编程语言是什么。
什么是Web Service
对这个问题,我们至少有两种答案。从表面上看,Web service 就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。这就是说,你能够用编程的方法通过Web来调用这个应用程序。我们把调用这个Web service 的应用程序叫做客户。例如,你想创建一个Web service ,它的作用是返回当前的天气情况。那么你可已建立一个ASP页面,它接受邮政编码作为查询字符串,然后返回一个由逗号隔开的字符串,包含了当前的气温和天气。要调用这个ASP页面,客户端需要发送下面的这个HTTP GET请求:
http://host.company.com/weather.asp?zipcode=20171
返回的数据就应该是这样:
21,晴
这个ASP页面就应该可以算作是Web service 了。因为它基于HTTP GET请求,暴露出了一个可以通过Web调用的API。当然,Web service 还有更多的东西。
下面是对Web service 更精确的解释: Web services是建立可互操作的分布式应用程序的新平台。作为一个Windows程序员,你可能已经用COM或DCOM建立过基于组件的分布式应用程序。COM是一个非常好的组件技术,但是我们也很容易举出COM并不能满足要求的情况。
Web service平台是一套标准,它定义了应用程序如何在Web上实现互操作性。你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过Web service标准对这些服务进行查询和访问。
新平台
Web service平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性,Web service平台必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。在传统的分布式系统中,基于界面(interface)的平台提供了一些方法来描述界面、方法和参数(译注:如COM和COBAR中的IDL语言)。同样的,Web service平台也必须提供一种标准来描述Web service,让客户可以得到足够的信息来调用这个Web service。最后,我们还必须有一种方法来对这个Web service进行远程调用。这种方法实际是一种远程过程调用协议(RPC)。为了达到互操作性,这种RPC协议还必须与平台和编程语言无关。下面几个小节就简要介绍了组成Web service平台的这三个技术。
XML和XSD
可扩展的标记语言(XML)是Web service平台中表示数据的基本格式。除了易于建立和易于分析外,XML主要的优点在于它既是平台无关的,又是厂商无关的。无关性是比技术优越性更重要的:软件厂商是不会选择一个由竞争对手所发明的技术的。
XML解决了数据表示的问题,但它没有定义一套标准的数据类型,更没有说怎么去扩展这套数据类型。例如,整形数到底代表什么?16位,32位,还是64位?这些细节对实现互操作性都是很重要的。W3C制定的XML Schema(XSD)就是专门解决这个问题的一套标准。它定义了一套标准的数据类型,并给出了一种语言来扩展这套数据类型。Web service平台就是用XSD来作为其数据类型系统的。当你用某种语言(如VB.NET或C#)来构造一个Web service时,为了符合Web service标准,所有你使用的数据类型都必须被转换为XSD类型。你用的工具可能已经自动帮你完成了这个转换,但你很可能会根据你的需要修改一下转换过程。在第二章中,我们将深入XSD,学习怎样转换自定义的数据类型(例如类)到XSD的类型。
SOAP
Web service建好以后,你或者其他人就会去调用它。简单对象访问协议(SOAP)提供了标准的RPC方法来调用Web service。实际上,SOAP在这里有点用词不当:它意味着下面的Web service是以对象的方式表示的,但事实并不一定如此:你完全可以把你的Web service写成一系列的C函数,并仍然使用SOAP进行调用。SOAP规范定义了SOAP消息的格式,以及怎样通过HTTP协议来使用SOAP。SOAP也是基于XML和XSD的,XML是SOAP的数据编码方式。第三章我们会讨论SOAP,并结识SOAP消息的各种元素。
WSDL
你会怎样向别人介绍你的Web service有什么功能,以及每个函数调用时的参数呢?你可能会自己写一套文档,你甚至可能会口头上告诉需要使用你的Web service的人。这些非正式的方法至少都有一个严重的问题:当程序员坐到电脑前,想要使用你的Web service的时候,他们的工具(如Visual Studio)无法给他们提供任何帮助,因为这些工具根本就不了解你的Web
service。解决方法是:用机器能阅读的方式提供一个正式的描述文档。Web service描述语言(WSDL)就是这样一个基于XML的语言,用于描述Web service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的Web service生成WSDL文档,又能导入WSDL文档,生成调用相应Web service的代码。
对运营商来说,所谓电信数据业务一般是指承载于GSM、GRPS、WirelessLAN等通信网络,接入到基于IP(InternetProtocol)网络技术的各类数据设备与服务器,以Internet为资源基础提供内容与应用服务的各类新型业务的总称,例如:短消息(SMS)、无线应用协议(WAP)、多媒体消息(MMS)、电子邮件(E-mail)、空中接口(下载)服务器(OTAServer)等。从商业模式的角度来看,电信运营商利用自己成熟的通信网络和丰富的后端服务与计费系统,组成服务提供平台(Service Delivery Platform),为新闻、游戏、邮件、商务等各种Internet服务提供用户接入、管理、计费等基础设施支持,扩展了对自身终端用户的商业服务范围;与Internet内容与应用服务商实行收入分成,开启了新的营收渠道。长期以来,电信运营商掌握着三个技术制高点:通信渠道、用户数据库和营帐系统。围绕着这些制高点,运营商进行了长期的投入与建设,并且在语音等传统业务领域已经达到了很高的技术成熟度。然而,电信数据业务的开展为运营商的技术储备带来了新的需求和挑战,新的业务系统与管理平台大量涌现,彼此之间以及与旧有系统的整合迫在眉睫。独特的商业合作模式创造了独特的供应链管理(Supply-Chain Management)的需求,即合作服务提供商关系管理。据估计,电信行业传统业务中运营商需要管理的设备元素与终端用户数目的比例平均为1:10000,即一个设备元素平均被用于服务10000个用户。随着新业务的开展和数据网络设备及服务器的增加,该比例已经缩减至1:500,即一个设备元素平均被用于服务500个用户。很多数据业务灵活跨越多个通信渠道、用户和合作服务提供商,进一步增加了设备整合的复杂性。
基于上述原因,目前国内外成熟运营商的基础设施建设重点已经从个别关键设备转移到了端到端的设备整合,这种整合常常跨越大量合作伙伴的边界。面临这样的变化,传统的系统整合技术,如点对点的私有接口适配器、适用于企业内部使用的传统分布式对象构件中间件和消息中间件等,已经显得力不从心。电信互连互通和增值服务链的建设需要安全、灵活,有能力跨越合作伙伴IT管理域边界的新技术。
Web技术在广域网应用中的极大成功,XML(eXtendedMark-upLanguage)在电子商务和企业数据交换与整合中的普遍应用以及分布式对象和消息中间件架构在企业内部应用整合中的推广,从多方面启发了业界的智慧,于2001年推出了整合三者优势的WebService技术与面向服务架构(Service-Oriented Architecture,SOA),用以满足包括电信行业在内的各商务领域对新型整合技术与框架的需求。结合电信行业数据业务的背景,本文介绍了该技术的基本概念及其在系统整合中的应用。
一、基本概念
WebService的国际标准由因制定Web和XML技术标准而名满天下的W3C组织(WorldWideWeb Consortium)制定。目前,由 Web Services 架构组达成一致意见的Web Service的暂行定义为:Web Service是由URI(统一资源标识符)标识的软件应用程序,其接口和绑定可以通过XML构件进行定义、描述和发现,Web Service支持通过基于因特网的协议使用基于XML的消息与其它软件应用程序直接交互。
仔细阅读这个定义,我们可以看出WebService的用于软件应用程序之间交互的技术,具有以下基本特征:
通信层面上的Web特征:使用URI进行标识,并使用各种因特网协议进行通信。
表示层面上的XML特征:使用XML描述服务接口和绑定信息,通信消息格式使用XML。
架构层面上的分布式计算特征:服务可以被使用它的应用程序在网络上查找和发现。
从上个世纪90年代末开始,许多厂商已经自发的开始使用Web通信协议(HTTP)加XML消息的方法解决各种因特网上的服务整合的问题了。例如:基于位置服务中的LIF(LocationInteroperabilityForum)标准和爱立信、诺基亚、摩托罗拉等公司的实现都使用了HTTP承载XML消息的方式。各类电子商务标准普遍基于XML,并且在实现中使用HTTP协议进行传输。一个只有几页纸的因特网上远程过程调用标准XML-RPC则是这类技术的典范,该标准规范了基于XML的调用描述与数据表示,至今仍然在被一些公司应用。
业界早期零散的努力在W3C组织最终汇聚成为今天WebService标准的基础。而标准中的服务发现机制则具有些OMG(ObjectManagementGroup)组织制定的CORBA(Common Object Request Broker Architecture)的基于命名服务(Naming Service)和IDL(Interface Definition Language)描述的服务查找的影子。然而,目前Web Service技术和以CORBA为代表的传统分布式构件对象技术的一个显著不同在于:Web Service传递的是XML数据,而不是对象或对象引用。事实上,在广域网上不同的商家之间传递二进制对象和对象引用会导致服务与被服务方实现技术的紧耦合,是不合适、不现实的。因此,有人提出:Web Service也许更适合使用异步消息进行系统间对话,而不是现在流行的远程过程调用(Remote Procedure Call,RPC)模式。基于消息的Web Service被称为Message Web Service,基于RPC机制的Web Service为RPC Web Service。尽管Message Web Service从理论上说会更为灵活、高效,其编程模型却比较复杂,需要应用开发者具有较高的IT架构设计与程序编制的能力。因此,目前各个IT厂商支持的主流仍然是编程模型较为简单的RPC Web Service。此外,两类技术变种有着共同的技术基础,都采用面向服务架构,符合上述定义。
二、面向服务的应用架构
W3CWebService架构组建议了一个的面向服务的WebService架构,如图1所示。在这个架构中,核心是服务这个概念。服务被定义为执行某类商业任务(比如零件采购或书籍查询)的一组操作。在Web Service上下文中,可以使用标准的XML技术和Internet协议发布、查找和绑定服务。Web Service 架构定义了3个主要实体。
图1面向服务的WebService架构
服务提供者:负责使用WSDL描述和定义WebService的功能,在UDDI注册库(位于服务代理)中发布这些服务的信息,使得它们可以被服务请求者访问和调用。
服务代理:负责宣传服务提供者发布的WebService和允许服务请求者查找发布的WebService 定义。它的作用和电话本的黄页相同。
服务请求者:负责通过服务代理查找所需要的WebService后,下载描述WebService的WSDL文档,根据服务描述来绑定和调用服务提供者提供的Web Service。
WebService架构的这种三角形设计模式被称为面向服务的体系结构。它包括了下面3个标准操作。
发布:由服务提供者执行来宣传和注册一个服务的存在和功能,是服务提供者和服务代理之间的操作。
查找:由服务请求者执行来查找符合特定需求或技术特征的服务,是服务请求者和服务代理之间的操作。
绑定:由服务请求者执行来调用服务提供者提供的服务,是服务请求者和服务提供者之间的操作。
WebService是面向服务的架构(ServiceOrientedArchitecture, SOA)的一种实现。SOA是分布式计算领域中采用的一种主要体系结构。和CORBA和DCOM这样的分布式计算技术不同,Web Service是基于标准和松耦合的。首先,广泛接受的Internet标准(如XML、SOAP、HTTP等)提供了在各不同厂商解决方案之间的交互性。开发者就可以开发出平台独立、编程语言独立的Web Services,从而能够充分利用现有的软硬件资源和人力资源。其次,松耦合将分布计算中的参与者隔离开来,交互两边某一方的改动并不会影响到另一方。这两者的结合意味着公司可以实现某些Web services而不用对使用这些Web Services的客户端的知识有任何了解。
SOA的强大和灵活性将给电子商务带来巨大的好处。如果某企业将其IT基础设施抽象出来,将其业务功能以某种粒度的服务形式表示并发布出来,每种服务都清晰地表示其业务价值,那么,这些服务的顾客(可能在公司内部,也可能是公司的某个业务伙伴)就可以通过已发布的业务接口来使用这些服务,而不用考虑服务实现的具体技术。
三、WebService发展阶段
按照目前IT界较为公认的划分方法,WebService技术从产生到成熟可以分成三个阶段:
基础服务架构的完善;
安全与可靠性支持的完善;
跨域协同(Coordination)和快速服务链整合技术(Composition)的完善。
在第一阶段,WebService的发展重点在于服务通信、描述以及发现机制的标准化。在面向服务的架构下,具体的标准规范通信消息的SOAP(SimpleObjectAccess Protocol)协议,规范服务描述的WSDL语言,和用于服务注册与发现的UDDI(Universal Description, Discovery, and Integration)服务和ebXML(e-Business XML)标准。该阶段的主要工作目前已经完成。
目前,WebService的发展已经到了第二阶段,即消息级的WebService安全机制和WebService消息传输的可靠性机制的标准化。Web Service作为一种端到端的分布式技术,不同于以往的点对点的技术,传递的消息可能穿越各类信息服务中介,如:内容分类过滤的防火墙、商业导购中间商、专业计费服务提供商等。最终的服务,被服务方以及中介之间存在有限的商业信任,这意味着中介既需要看懂并处理部分消息内容,又无权看到与己无关的部分而传统的因特网点对点安全技术不能满足这样的需求。所谓消息级安全是对点对点安全技术的加强与扩充,目的在于满足端到端的通信安全需要。尽管实现效率还有待提高,目前在电子商务最具权威性的机构,OASIS(Organization for the Advancement of Structured Information Standards)组织中制定了 Web Service Security的发展框架,其核心的WS-Security标准也已经完成了第一版的工作。此外,大多数商业服务需要可靠的信息传输,它们共同的需求被抽取出来,就构成了对Web Service可靠性的需求。一些厂商试图给出这些需求在系统一级的解决方案,提出了一系列的标准化方案,整个工作正在迅速的进行之中。
此外,2002年7月IBM、微软和BEA共同提出了WebService跨域协同、事务和服务链整合技术的三个标准草案(WebServiceCoordination、Web Service Transaction、Business Process Execution Language for Web Service)标志着Web Service第三阶段研究与标准化工作也已经提上了日程。
四、WebService在电信增值业务平台的应用示例
尽管WebService的商业模式目前还处于发展过程中,但其中一些模式已经通过大量的实践得到了业界的承认,例如,企业之间的信息交换,信息门户和商业流程的整合。这些模式结合电信领域的特点,产生了一些特有的基于电信的WebService的商业模式。此处以WebService在电信增值业务平台的应用为示例,说明其在电信行业数据业务中的应用。
电信增值业务平台是增值业务价值链的技术支撑平台,管理运营商和ServiceProvider(SP)之间业务集成的商业关系。对于运营商而言,平台封装了底层的通信网络,向SP提供一个开放的安全的访问网络能力的标准接口集合。这个集合包括了网络功能实体、认证、基于内容的计费以及服务定购关系等。SP可以利用这个平台便捷地在这个平台上实现新的电信增值业务。ParlayGroup、3GPP和ETSI联合制定的Parlay/OSA[5]就是这样一个面向电信增值业务平台的电信规范。WebService在Parlay/OSA中得到了广泛的应用。如图1所示,采纳Parlay Web Service的电信增值业务平台体系结构。增值业务平台由电信运营商管理和维护,分为两个逻辑部分:框架和网络资源能力服务器。框架向SP提供两种类型的接口支持。其一是面向企业法人的电信服务定购关系的接口支持,如图2中②所示,包括了SP企业账户的管理、应用程序的管理、电信资源使用合同的管理。其二是向SP的电信增值业务的应用程序提供安全接入认证,电信资源查找、签署服务等级合约、获得电信服务实例入口和服务质量监控的接口支持,如图2中③所示。SP应用程序使用的电信资源是由网络资源能力服务器提供的,如图2中④所示。这里的电信资源包括话音、短信、位置、用户状态和计费等,它们可以通过各种不同的私有协议映射到运营商现有的网络设备和内部系统中。这些资源通过图2中①所示的接口注册到框架。从上可以看出,这种电信增值业务平台是一个典型的B2B模式(SP和运营商)中采用Web Service进行业务集成的应用示例。
此外,在OpenMobileAlliance(OMA)组织中的MobileWeb Service(MWS)工作组也在探讨如何采用标准的Web Service的技术在移动运营商的网络中部署并构建新的电信数据业务平台。目前的工作还处于草案阶段。鉴于Parlay在相同的领域中已经有了很多的标准和技术的积累,OMA MWS已经和Parlay签署了一个合作协议,用于协调双方的标准制定工作。
图2采纳ParlayWeb Service的电信增值业务平台体系结构
现在我将列举三种情况,在这三种情况下,你将会发现使用Web service会带来极大的好处。此后,我还会举出不应该使用Web service的一些情况。
跨越防火墙的通信
如果你的应用程序有成千上万的用户,而且他们都分布在世界各地,那么客户端和服务器之间的通信将是一个棘手的问题。那是因为客户端和服务器之间通常都会有防火墙或者代理服务器。在这种情况下,你想使用DCOM就不是那么简单了,而且,通常你也不愿意把你的客户端程序发布到如此庞大数量的每一个用户手中。于是,你最终选择了用浏览器作为客户端,写下一堆ASP页面,把应用程序的中间层暴露给最终用户。结果呢?运气好的话,只是开发难度大了一些,运气不好的话,就会得到一个根本无法维护的应用程序。
想象一下你应该怎么在你的应用程序里面加入一个新的页面:你必须先建立好用户界面(Web页面),以及在这个页面后面,包含相应商业逻辑的中间层组件。这还不够,你还要再建立至少一个ASP页面,用来接受用户输入的信息,调用中间层组件,把结果格式化为HTML形式,最后还要把"结果页"送回浏览器。要是客户端代码不再如此依赖于HTML表单,客户端的编程不就简单多了吗?还有,建立ASP页面的那一步可以省略掉吗?
当然。如果你的中间层组件是Web service的话,你完全可以从用户界面直接调用中间层组件,从而省掉建立ASP页面的那一步。要调用Web service,你可以直接使用Microsoft SOAP Toolkit或.NET这样的SOAP客户端,也可以使用你自己开发的SOAP客户端,然后把它和你的应用程序连接起来。这样做,不仅可以缩短开发周期,还可以减少代码的复杂度,并增强整个应用程序的可维护性。同时,你的应用程序也不再需要在每次调用中间层组件时,都跳转到相应的"结果页"了。
以我的经验来看,在一个用户界面和中间层有较多交互的应用程序中,使用Web service这种结构,可以轻松的节省花在用户界面编程上的20%的开发时间。这样做还有另一个好处,就是你将得到一个由Web service组成的中间层,这一层是完全可以在应用程序集成或其他场合下被重用的。最后,通过Web service把你的应用程序的逻辑和数据暴露出来,还可以让其它平台上的客户重用你的应用程序。
应用程序集成
企业级的应用程序开发者都知道,企业里经常都要把用不同语言写成的在不同平台上运行的各种程序集成起来,而这种集成将花费很大的开发的力量。你的应用程序经常都需要从运行在古老的IBM主机上的程序中获取数据;或者再把数据发送到主机或UNIX应用程序中去。即使是在同一个平台上,不同的软件厂商生产的各种软件也常常需要集成起来。通过Web service,应用程序可以用标准的方法把功能和数据暴露出来,供其它的应用程序使用。
例如,你有一个订单登录程序,用于登录从客户来的新订单,包括客户信息、发货地址、数量、价格和付款方式等信息。同时,你还有一个订单执行程序,用于实际货物发送的管理。这两个程序是来自不同软件厂商的。一份新订单进来之后,订单登录程序需要通知订单执行程序发送货物。通过在订单执行程序上面增加一层Web service,订单执行程序可以把"AddOrder"函数暴露出来。这样,每当有新订单到来时,订单登录程序就可以调用这个函数来发送货物了。进而通过Web service集成应用程序
B2B的集成
用Web service集成应用程序,可以使你公司内部的商务处理更加自动化。但当交易跨越了你的供应商和客户,突破了公司的界线时又会怎么样呢?跨公司的商务交易集成通常叫做B2B集成。
Web service是B2B集成成功的关键。通过Web service,你的公司可以把关键的商务应用暴露给指定的供应商和客户。例如,把你的电子下单系统和电子发票系统暴露出来,你的客户就可以以电子的方式向你发送购货订单,而你的供应商则可以以电子的方式把原料采购的发票发送给你。当然,这并不是一个新的概念:电子文档交换(EDI)早就是这样了。Web service和EDI之间的主要区别在于,Web service的实现要比EDI简单得多,而且Web service是运行在Internet上的,在世界任何地方都可轻易实现,这样其运行成本就相对较低。不过,Web service并不像EDI那样,是文档交换或B2B集成的一套完整的解决方案。Web service只是B2B集成的一个关键部分,还需要许多其它的部分才能完成这个集成。
用Web service来实现B2B集成的最大好处在于可以轻易实现互操作性。只要把你的商务逻辑暴露出来,成为Web service,你就可以让任何指定的合作伙伴轻松的调用你的商务逻辑,而不管他们的系统在什么平台上运行,使用的是什么开发语言。这样就大大减少了花在B2B集成的上的时间和成本。这样的低成本让许多原本无法承受EDI的投资成本的中小企业也能实现B2B集成。
软件重用
软件重用是一个很大的主题,它有很多的形式和程度。最基本的形式是源代码模块或者类一级的重用。另一种形式是二进制形式的组件重用。当前,像表格控件或用户界面控件这样的可重用软件组件在市场上都占有很大的份额。但这类软件的重用都有一个很严重的限制:重用仅限于代码,而数据不能被重用。原因在于你可以很轻易的发布组件甚至源代码,但要发布数据就没那么容易了,除非那些数据都是不会经常变化的静态数据。
而Web service允许你在重用代码的同时,重用代码后面的数据。使用Web service,你不再像以前那样,要先从第三方购买、安装软件组件,再从你的应用程序中调用这些组件。你只需要直接调用远端的Web service就可以了。举个例子,你想在你的应用程序中确认用户输入的邮件地址,那么,你只需把这个地址直接发送给相应的Web service,这个Web service 就会帮你查阅街道地址、城市、省区和邮政编码等信息,确认这个地址的确在相应的邮政编码区域。Web service 的提供商可以按时间或使用次数来对这项服务进行收费。这样的服务要通过组件重用来实现是不现实的,因为那样的话你必须下载并安装好包含街道地址、城市、省区和邮政编码等信息的数据库,而且这个数据库还是不能实时更新的。
另一种软件重用的情况是把好几个应用程序的功能集成起来。例如,你想要建立一个局域网上的门户站点应用,让用户既可以查询他们的联邦快递包裹,察看股市行情,又可以管理他们的日程安排,还可以在线购买电影票。现在Web上有很多应用程序供应商,都在其应用中实现了上面的这些功能。一旦他们把这些功能都通过Web service 暴露出来,你就可以非常轻易地把所有这些功能都集成到你的门户站点中,为用户提供一个统一的、友好的界面。
用Web service来集成各种应用中的功能,为用户提供一个统一的界面
许多应用程序都会利用Web service,把当前基于组件的应用程序结构扩展为组件和Web service 的混合结构。你也可以在应用程序中使用第三方的Web service 提供的功能。你还可以把你自己的应用程序的功能通过Web service 提供给别人。所有这些情况下,你都可以重用代码和代码后面的数据。总之,Web service 将是软件重用的一种非常有力的形式。
什么时候不应该使用Web Service
一个对Web service的完整介绍还应该包括什么时候不该用Web service。经过前面的介绍,我们知道了Web service 在通过Web进行互操作或远程调用的时候是最有用的。不过,还有许多情况,Web service根本不能给你带来任何好处。
单机应用程序
目前,我们还有很多桌面应用程序是供商用和个人使用的。其中一些只需要与运行在本机上的其他程序通信。在这种情况下,我们最好就不要再用Web service ,只要用本地的API就可以了。COM非常适合于在这种情况下工作,因为它既小又快。运行在一台服务器上的服务器软件也是这样:最好直接用COM或其他本地的API来进行应用程序间的调用。当然Web service 也能用在这些情况下,但那样不仅消耗太大,而且不会给你带来任何好处。
局域网上的同构应用程序
在许多应用中,你所有的程序都是用VB或VC开发的,都在Windows平台下使用COM,都运行在同一个局域网上。例如,你有两个服务器应用程序需要相互通信,或者你有一个Win32或WinForm的客户程序要连接到局域网上的另一个服务器程序。在这些程序里使用DCOM会比SOAP/HTTP有效的多。类似的,如果你的一个.NET程序要连接到LAN上的另一个.NET程序,那么你应该使用.NET remoting。有趣的是,在.NET remoting中,你也可以指定使用SOAP/HTTP来进行Web service 调用。不过最好还是直接通过TCP进行RPC调用,那样会有效得多。总之,只要你从应用程序结构的角度看来,有别的方法比Web service 更有效,更可行,那就不要再用Web service。
总结
Web service是创建可互操作的分布式应用程序的新平台。Web service 的主要目标是跨平台的可互操作性。为了达到这一目标,Web service 是完全基于XML、XSD等独立于平台、独立于软件供应商的标准的。
Web service在应用程序跨平台和跨网络进行通信的时候是非常有用的。Web service适用于应用程序集成、B2B集成、代码和数据重用,以及通过Web进行客户端和服务器的通信的场合。
当然,Web service也不是万能的,你不能到处滥用Web service。在有些情况下,Web service 会降低应用程序的性能,而不会带来任何好处。例如,一台机器或一个局域网里面运行的同构应用程序就不应该用Web service 进行通信。
今天是感恩节,差点又要在公司加班了。好在Web Service程序并不是特别难搞,下午终于在eclipse下调通过了,正确产生了服务器端和客户端的Java代码,apache的东西的确很不错。
说道Web Service的程序开发八个月前我加班调试公司和中国电信的商务领航系统的接口的时候,用的就是Web Service,Web Service有很多优点,使用Web Service可以在不同编程语言间实现数据交换,而我那时对Web Service也不熟,就由同事帮我生成了一大堆Web Service的框架代码,我则只单独开发业务代码。
这次的另外一个项目也要用Web Service了,不过人手也少了,没有人帮做Web Service了,只好自己动手。
好在开发前,有个同事先给我们不熟悉Web Service的程序员进行了一些培训,我才知道原来以前的Web Service都是可以自动生成代码的,而且也不难,试了一个下午客户端和服务器端的Web Service代码就都调试通过了,真不错。
为了更多喜爱开发的程序员也能迅速了解Web Service的开发,我这里整理了一些通过Axis开发Web Service的一些要点,希望能让不熟悉Web Service的开发人员能够迅速掌握Web Service。
一、Axis环境的安装
1、安装环境 J2SE SDK 1.4,Tomcat 5.0,eclipse 3.2。
2、到 http://xml.apache.org 网站下载Axis安装包。
3、将Axis相关包文件放在WEB-INF\lib目录下。
4、Axis可选的包:activation.jar; mail.jar; xmlsec-1.4.Beta1.jar拷贝到WEB-INF目录下,生成客户端时候需要使用。
Axis支持三种web service的部署和开发,分别为:
1、Dynamic Invocation Interface (DII)
2、Dynamic Proxy方式
3、Stubs方式
前两种方式我就不介绍了,同事告诉我他们自己都不使用前两种方式,他们建议我们使用Stubs方式,因此我就主要就介绍一下第三种方式。注意,我自己的Java源代码是放在D:\workspace\test\目录下,Axis相关包文件放在D:\workspace\test\WEB-INF目录下。
二、编写wsdd发布web服务,编写stub client访问web服务
1、编写服务端程序server,SayHello.java,编译server.SayHello.java
package server; public class SayHello { public String getName(String name) { return "hello "+name; } }
2、编写wsdd文件
deploy.wsdd文件内容如下:
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="SayHello" provider="java:RPC"> <parameter name="className" value="server.SayHello.getName"/> <parameter name="allowedMethods" value="*"/> </service> </deployment>
3、发布服务:
编辑一个deploy.bat,Axis_Lib为axis.jar路径。内容如下:
set Axis_Lib=D:\workspace\test\WEB-INF\lib set Java_Cmd=java -Djava.ext.dirs=%Axis_Lib% set Axis_Servlet=http://localhost:8080/test/servlet/AxisServlet %Java_Cmd% org.apache.axis.client.AdminClient -l%Axis_Servlet% deploy.wsdd
执行这个批处理文件,这时候,如果提示成功的话,访问http://localhost:8080/test/services 就会显示服务列表。
4、生成客户端client stub文件
在浏览器上访问服务器端的服务,可以下载到WSDL文件,通过Axis的相关工具,可以自动从WSDL文件中生成Web Service的客户端代码。
编写一个WSDL2Java.bat文件,其内容如下:
set Axis_Lib=D:\workspace\test\WEB-INF\lib set Java_Cmd=java -Djava.ext.dirs=%Axis_Lib% set Output_Path=D:\workspace\test\src set Package=server.SayHello %Java_Cmd% org.apache.axis.wsdl.WSDL2Java -o%Output_Path% -p%Package% SayHello.wsdl
执行这个批处理文件就可以生成client stub.
生成的stub client文件列表为:SayHello.java,SayHelloService.java,SayHelloServiceLocator.java,SayHelloSoapBindingStub.java .
5、编写客户端程序,编译并执行
下面是一段junit测试客户端代码。
import java.net.URL; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite;
public class TestWSClient extends TestCase {
public TestWSClient(String string) { super(string); }
public void SayHelloClient() throws Exception {
SayHelloService service = new SayHelloServiceLocator(); SayHello_PortType client = service.getSayHello() ; String retValue = client.getName("clientname"); System.out.println(retValue);
}
public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(new TestWSClient("SayHelloClient")); return suite; } }
至此,整个服务器端和客户端的Web Service框架代码就完成了,剩下的就是在里面加入你的业务代码了,怎么样,Web Service并不难开发吧。
虽然人们通过跳槽来寻求职位和收入的快速提升,但也不是每个人都可以通过跳槽达到这些目的。据调查,以下这几个因素决定了人们的收入差别:
一、学历
收入的差别是随着学历的增长而增高,据调查,每多接受一年的教育,平均年薪就会增加8.3%(MBA除外),拥有较高的教育程度,良好的实际工作能力的人通常会获得比较优厚薪酬的工作。
二、经验
随着年龄和工作经验的增长,薪资水平也会递增。工作6年以上者年薪均值达到了4.5万元以上,是工作1年以下者的2倍。也就是说,薪酬与经验成正比,经验多、工作时间长者自然获薪酬也多。《财经》杂志进行过一项调查,其中销售人员的调查结果是:有2年经验的销售部主管年总薪金平均是3.27万元,而有13年经验的平均达到7.18万元。
三、年龄
国家统计局城市社会经济调查总队在北京、上海、浙江等10个省市对9956户城市高收入家庭进行了问卷调查。在我国,目前25-35岁年轻人的收入高于其他各年龄组,占城市高收入群体的37%.说明随着社会的变化发展,英语、电脑已越来越成为基本工具而不是技能,从业者(尤其是高级管理人员)掌握了较多新知识,具备较强的知识更新能力,就能在人才竞争中占据有利地位。因此,30-40岁的人在中高收入人群中的比重将迅速扩大。
四、行业
一项对京、沪、穗、深四城市白领年薪的调查显示,北京地区收入最高的是计算机行业,白领平均年薪为5万元;上海、广州均是“律师、会计师”行业高居榜首,平均年薪分别为5.42万元和5万元;在深圳,薪水最高的是“教育、文化、科研、医疗”行业,平均年薪高达7.02万元。
五、英语
虽然社会上对英语等级考试还有些质疑,但职场中,英语无疑是添薪加码的一大“法宝”。调查显示,外语能力越高,其薪资的竞争力也就越强。外语能力“熟练”者平均年薪比“中等”者年薪多出近16000元。即使与去年下半年相比,外语能力熟练者的平均薪资也有了近2000元的升幅,而外语能力一般者薪资升幅仅为300元。
六、个人整体素质
一项针对高收入外企白领的调查显示:高学历并不完全等同于高收入,优秀个人素质才是获得高薪的关键因素。目前高薪收入者大多具有良好的人际关系处理能力,敬业精神和不断学习的能力等基本素质。
七、成功跳槽
具备了以上素质,无论是在原单位还是成功跳到另一家新单位,都会拥有高于一般水平的薪资,而成功地跳槽则会加速薪酬的提升速度。
了解了以上信息,你就会理解为什么有的人不但跳得不理想,而且越跳越低的原因了。反过来,具备综上所述各种优势的人才也是企业们想方设法要留下的骨干力量,面对越来越激烈的人才竞争,企业也在挖空心思地维护着自己的人才领地,用各种方法留住人才。
讲理法:“老板,我干活,你领功拿赏。功我不要了,钱总得分我一些吧。” 对比法:“老板,再给我一万,我开的还是小丰田,那能和您的凯迪拉克比。” 拍马屁法:“老板,你的马屁好大噢。能不能让我拍一下。” 同情法:“老板,我上有老,下有小,中间还有个好吃懒做爱花钱的老公/老婆。” 输球法:常陪老板打高尔夫。每场必输。(此法源出于国内的输棋、输牌法)
Blackmail法:“老板,秘书xx小姐取笑我。说我一年挣的还不够你俩假装开会用公款到欧洲浪漫一星期的开销。 分红法:“老板,你长我二万元,我分你一万。” 入股法:“老板,我在研制永动机。快做成了,只是还差十万元。你先捐给我,以后你做股东” 暗示法:在老板面前大声念关于员工枪杀上司的报导。然后叹道:“可怜的人,薪水长得不够,才干出这种事来”
拂袖法:“不长钱,我走人”(此为上计)
如果你觉得自己的能力、业绩足以超过别人……总之你有把握让老板知道你值得加薪,那么你就不妨大胆地把你的要求提出来。
对自己作正确的评估
老板给员工加薪,意味着他自己要因此承担部分损失。当你打定主意准备向老板提出加薪要求的时候,一定得先给自己作一番正确的评估,即你在公司的资历怎样,你在老板心中的分量重不重,你最近出色地完成了哪些项目,这些项目为公司带来了多大的利润,你认为你未来还会为公司作出哪些贡献,你的离去是否会为公司带来某种损失……总之对自己有一个正确的评估,你就能知彼知己,有的放矢,既不会让老板为难,也能让大家知道你是否真正“薪有所值”。
选择适当的时机
当老板沉浸在成功的喜悦中,或是他的家人有什么喜事而使他轻松愉快的时候,你向他提出适当的要求他就比较容易接受。
从你自身来说,由于你的努力,公司近期业绩增长,或者你刚刚完成了某个大项目为公司增了光,这个时候,你向老板提出加薪要求,他也会慎重考虑一番。再者就是你看到同行业的许多员工都不同程度地加了薪,老板心里也有数,正在等待观望中,你适时地捅破这层纸,他也会欣然接受,顺水推舟。
善开“金”口几招式
向老板提加薪要求其实是一招险棋,弄不好就会因此而被“扫地出门”,或者即使没赶你出去,今后也会对你“另眼相看”。所以,善开“金”口是既不让老板对你反感又能让你腰包鼓鼓的前提。托人传话
作为一般员工,你也许不会经常直接和老板打交道,但部门经理会对你了解得更多一些,而部门经理则是老板经常要召集开会的人之一。除此之外,老板身边也有比较亲近的人,通过他们转达你的加薪要求有时比你直接开口效果更好。当然这里你得把握好一个“度”,即能替你传话的人一定是了解你、理解你、同情你的人,这样他在传话的过程中就能把话说得婉转些、圆满些,即使遭到拒绝,面子上也不至于太尴尬,因为你毕竟没和老板“正面交锋”。
适时“提醒”
记得五年前,我在南方一家公司打工,由于初来乍到,不懂规矩,每到发工资时总爱向别人打听:“哎,这个月你拿了多少?”谁知他们一个个都讳莫如深,三缄其口。后来我才明白个中奥妙,因为每个员工的工资是不一样的。但在一个偶然的机会里,我还是发现我的工资连续好几个月比与我做同一样事的同事少了好几百块钱。于是我趁向老板送材料的机会向他作了一番“提醒”:“老板,实在是不好意思,有一件事我一直没弄清楚,我发现这几个月我的工资比我的同事少了好几百块钱,是不是我的试用期已过而正式聘用的相关手续还没有办妥(其实我知道人事部门已经给我办好了手续)”当时老板并没有什么特别的反应,而是很认真地答应替我过问一下。第二天,他正式通知我说,真是不好意思,其实你的工资早几个月就应该加上去了,只是财务上一时没办好手续,以后有什么事如果我忘了可以提醒我一下,不要有什么顾虑,按劳分配嘛。
假意辞职
公司真的离不开你吗?你这一走马上就有单位愿意接收你吗?新的公司薪水就一定比现在多吗?这些问题在你假意辞职前一定得吃准了,否则“偷鸡不成反蚀一把米”,那可是你自找的。
小王是公司里的业务骨干,同他一块出来打拼的一个同学在另一家公司干得有声有色,而且月薪比他多了近千元。他力邀小王加盟他们公司,并说他们老板已经给他留好了位置,承诺月薪一定比原单位多一千元。小王考虑到自己老板平时对他不薄,工作也干得很顺心,只要老板给他加个五六百元,他就不想离开原公司。但薪水毕竟是个诱惑,不提出来也不行。于是他找了机会把同学的意思向老板说了,并说如果老板有接替他的合适人选,他才会考虑离开,如果暂时还没有合适人选,他宁愿不要那份薪水继续留在公司干。老板感动之余自然明白了小王的心思。过了一个月,小王的工资袋里就多了800元钱。
直言不讳
一个人因为暗恋另外一个人却不敢当面对他说,结果人家最终投入了别人的怀抱。这种叫人后悔不已的事在职场上也时有发生。如果你觉得自己的付出与得到的回报不相符,如果你认为你的潜力足以压过你身边的平庸之辈,那么你就不妨把你的加薪要求直接向老板提出来。你不愿提或不敢提,知情人反而会觉得你这人缺乏激情,不思进取。要知道,精明的老板有时宁愿给一个敢为天下先的“激进分子”加一千块钱,也不愿给10个按部就班的平庸之辈人均加一百块钱。第一个吃螃蟹的人往往是创造财富最多的人。
尴尬一:辛辛苦苦小学六年勤勤恳恳初中三年废寝忘食高中三年,眼看要走进考场却赶上国家扩招,任他猫猫狗狗也都能混个大学文凭,现在大学文凭算什么葱啊!(正好混了个) 尴尬二:稀里糊涂大学混了四年,使尽浑身解数拿到英语四级、计算机三级证,毕业证、学位证二证在手却怎么也找不到如意的工作,有的连工作都找不到??刚毕业就失业。 (混了四年拿了几个证,现在的工作的感觉就是被骗了,谁叫我们都是“第一次”啊,现在的大学生值几个钱啊) 尴尬三:千辛万苦进了外商独资企业当白领,还是世界五百强,才发现原来中国现在遍地是外企,五百强有499家都在中国有分号。干白领的活承受巨大压力天天加班挣得比民工又多不了多少,稍微发点牢骚就有老外拍桌子:你他妈什么玩意儿,上午把你fire下午我就能找一个!(幸运没进掉外企) 尴尬四:福利分房早已成为昨日黄花,住房公积金少得可怜,又赶上无耻之徒畜牲一样遍地炒房,辛辛苦苦工作了一年,才发现如果不吃不喝睡大街衣麻袋一年攒的钱才能买四五平米住房,贷款住进新房一点都开心不起来??要换贰拾年的贷款啊!(没敢想买房,只想把房租交上) 尴尬五:小时候教育要做个诚实的孩子,中学大学又普及诚信教育,工作后却不得不抽假烟、喝假酒、说假话,上了拿假文凭人的当,在假发票上签了字,最糟心的是??花钱叫了个小姐,一摸身上全是假的。(虽然假话到是不说,但假酒喝了不少,抽烟那叫人在江湖身不由己;倒是没叫过小姐,听到这两个字都起鸡皮疙瘩) 尴尬六:他们说计划经济的教育已经跟不上时代,他们说要普及素质教育,结果我们什么都得学,什么都刚摸到皮毛却连皮毛都不知道。一旦参加工作发现原来在学校里什么都没有学到,得花大把大把的钱去上这个班去考那个证。班上完了,证也考到了,发现自己还是一个二百五;(越来越觉得自己真是一个二百五) 尴尬七:电子信息产业高速发展,网上信息如潮如涌,不论是垃圾还是精华都让人疲惫不堪,没手机没电脑人家会觉得你生于陆拾年代,有人天天打游戏有人天天上网也有人天天在网上钓鱼??美人鱼出现的几率小于万分之一。(出现美人鱼,是人家的) 尴尬八:从小学完雷锋学赖宁,接着在学李素丽、孔繁森,之后还有济南交警还有抗洪英雄还有在异国他乡被炸死的记者还有……现在要学杨利伟??说一套做一套,表面文章做足了接着自私自利。(看透了政府,就是蒙着老百姓玩,大死也不做公务员) 尴尬九:闯荡社会若干年发现一事无成一钱未赚一权未某,必不得已重新拾起书本泡在这个考前冲刺那个精华笔记那个制胜宝典那个某某密题中,希望能够再去学校混个更高一点的文凭出来好混日子;(回想起来在学校的日子叫爽啊,可惜没有珍惜,多希望上天再给一次机会,目前有考研的打算) 尴尬十:美好的生活属于谁呢?二十年前,“属于我,属于你,属于八十年代的新一辈“,十五年前“太阳是我们的,太阳是我们的,月亮……”,十年前“让我们期待明 天会更好!”,八年前“不经历风雨,则么能见彩虹,没有人能随随便便成功”,现在“我闭上眼睛就成天黑”。1990S初生牛犊不怕虎,谁都没把八十年出生的人放在眼里。
中新网8月7日电 美国《财富》(Fortune)杂志6日证实,墨西哥电信巨子卡洛斯·斯利姆·埃卢以590亿美元资产,取代微软创始人比尔·盖茨成为新的世界首富。但埃卢对此反应平静,称“并不在乎世界首富的头衔“。
追踪世界顶尖公司业绩的《财富》表示,根据埃卢旗下公司在股票交易所的市场价值,他的资产净值在今年增加120亿美元。《财富》杂志在67岁的埃卢简介中称,依照他7月底公开持有的股票价值,他的资产已达590亿美元。
该杂志称,之前长期占据世界首富宝座的微软创始人盖茨资产净值估计有580亿美元。埃卢此前在接受媒体采访时说,“无论我的财富排名第2位,第20位,或是2000位,这都不重要。”
在全球富豪中,身为黎巴嫩移民之子的埃卢创造了一个神话,曾经创下最近10年全球个人资产增值速度最快的纪录。美国《福布斯》杂志曾于今年4月11日公布的最新一期全球个人财富排行榜显示,那时排名第三的埃卢身家超过美国伯克希尔·哈撒韦公司董事长沃伦·巴菲特,跃至财富榜第二位。
这是一张椅子的图片,但是,回复后,把它保存到某个目录下,如果你的系统是xp的话, 查看方式选择缩略图或者幻灯片方式,看到的小图 却变成一个机器女人坐着的图案,据说这是清华学子发现的xp漏洞, 真是百思不得其解,到底是怎么一回事啊!!!!!
本人是试过了·····真的·····
要轻松流畅上网你是否注意到你的电脑系统磁盘的可用空间正在一天天在减少呢?是不是像老去的猴王一样动作一天比一天迟缓呢?
没错!在Windows在安装和使用过程中都会产生相当多的垃圾文件,包括临时文件(如:*.tmp、*._mp)日志文件(*.log)、临时帮助文件(*.gid)、磁盘检查文件(*.chk)、临时备份文件(如:*.old、*.bak)以及其他临时文件。特别是如果一段时间不清理IE的临时文件夹“Temporary Internet Files”,其中的缓存文件有时会占用上百MB的磁盘空间。这些LJ文件不仅仅浪费了宝贵的磁盘空间,严重时还会使系统运行慢如蜗牛。这点相信你肯定忍受不了吧!所以应及时清理系统的LJ文件的淤塞,保持系统的“苗条”身材,轻松流畅上网!朋友来吧,现在就让我们一起来快速清除系统垃圾吧!!下面是步骤很简单就两步!
在电脑屏幕的左下角按“开始→程序→附件→记事本”,把下面的文字复制进去(黑色部分),点“另存为”,路径选“桌面”,保存类型为“所有文件”,文件名为“清除系统LJ.bat”,就完成了。记住后缀名一定要是.bat,ok!你的垃圾清除器就这样制作成功了! 双击它就能很快地清理垃圾文件,大约一分钟不到。
======就是下面的文字(这行不用复制)=============================
@echo off echo 正在清除系统垃圾文件,请稍等...... del /f /s /q %systemdrive%\*.tmp del /f /s /q %systemdrive%\*._mp del /f /s /q %systemdrive%\*.log del /f /s /q %systemdrive%\*.gid del /f /s /q %systemdrive%\*.chk del /f /s /q %systemdrive%\*.old del /f /s /q %systemdrive%\recycled\*.* del /f /s /q %windir%\*.bak del /f /s /q %windir%\prefetch\*.* rd /s /q %windir%\temp & md %windir%\temp del /f /q %userprofile%\cookies\*.* del /f /q %userprofile%\recent\*.* del /f /s /q "%userprofile%\Local Settings\Temporary Internet Files\*.*" del /f /s /q "%userprofile%\Local Settings\Temp\*.*" del /f /s /q "%userprofile%\recent\*.*" echo 清除系统LJ完成! echo. & pause
=====到这里为止(这行不用复制)============================================== 以后只要双击运行该文件,当屏幕提示“清除系统LJ完成!就还你一个“苗条”的系统了!!到时候再看看你的电脑,是不是急速如飞呢?可别忘了回帖喔!
注:LJ就是垃圾的意思!这招比那些所谓的优化大师好用!最重要的是无论在公司默认的系统环境还是在自己家中的电脑都不会破坏系统文件
安装
Add jcaptcha-all.jar (provided in bin-distribution) and ehcache.jar (not provided see ehcache site) to your application class path, ie in you WEB-INF/lib folder. 实例一个jcaptcha服务,注意,必须是单例模式的
import com.octo.captcha.service.image.ImageCaptchaService; import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
public class CaptchaServiceSingleton { private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService(); public static ImageCaptchaService getInstance(){ return instance; } }
注:以上是默认的一个实现,下面是其他更多的实现
- SimpleListSoundCaptchaEngine //还可以用声音,真爽哦
- SpellerSoundCaptchaEngine
- SpellerSoundCaptchaEngine
- DefaultGimpyEngineCaptcha
- BaffleListGimpyEngineCaptcha
- BasicListGimpyEngineCaptcha
- DeformedBaffleListGimpyEngineCaptcha
- DoubleRandomListGimpyEngineCaptcha
- SimpleListImageCaptchaEngineCaptcha
- SimpleFishEyeEngineCaptcha
具体请参考 官方说明编写一个产生图片的servlet
import com.octo.captcha.service.CaptchaServiceException; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder;
import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException;
public class ImageCaptchaServlet extends HttpServlet {
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
}
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { byte[] captchaChallengeAsJpeg = null; // the output stream to render the captcha image as jpeg into ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream(); try { // get the session id that will identify the generated captcha. //the same id must be used to validate the response, the session id is a good candidate! String captchaId = httpServletRequest.getSession().getId(); // call the ImageCaptchaService getChallenge method BufferedImage challenge = CaptchaServiceSingleton.getInstance().getImageChallengeForID(captchaId, httpServletRequest.getLocale()); // a jpeg encoder JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream); jpegEncoder.encode(challenge); } catch (IllegalArgumentException e) { httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); return; } catch (CaptchaServiceException e) { httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; }
captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
// flush it in the response httpServletResponse.setHeader("Cache-Control", "no-store"); httpServletResponse.setHeader("Pragma", "no-cache"); httpServletResponse.setDateHeader("Expires", 0); httpServletResponse.setContentType("image/jpeg"); ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream(); responseOutputStream.write(captchaChallengeAsJpeg); responseOutputStream.flush(); responseOutputStream.close(); } }
为servlet修改web.xml配置文件
<servlet> <servlet-name>jcaptcha</servlet-name> <servlet-class>ImageCaptchaServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>jcaptcha</servlet-name> <url-pattern>/jcaptcha</url-pattern> </servlet-mapping>
编写你的客户端的展示
<img src="jcaptcha"> <input type='text' name='j_captcha_response' value=''>
上面的src="jcaptcha" 就是调用了上面的servlet,text里是用户填写的确认验证码 后台逻辑验证
Boolean isResponseCorrect =Boolean.FALSE; //remenber that we need an id to validate! String captchaId = httpServletRequest.getSession().getId(); //retrieve the response String response = httpServletRequest.getParameter("j_captcha_response"); // Call the Service method try { isResponseCorrect = CaptchaServiceSingleton.getInstance().validateResponseForID(captchaId, response); } catch (CaptchaServiceException e) { //should not happen, may be thrown if the id is not valid }
OK,大功告成了.
在java中使用awt在服务器上处理图片的时候发现有错: 第一遍执行 500 Servlet Exception java.lang.InternalError: Can't connect to X11 window server using ':0.0' as the value of the DISPLAY variable. at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method) at sun.awt.X11GraphicsEnvironment.<clinit>(X11GraphicsEnvironment.java:134) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:141) at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:62) at java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1041) at com.lodesoft.ipniii.club.tool.AlbumTool.createSmallThumb(AlbumTool.java:793) at com.lodesoft.ipniii.club.test.action.UpdateAllPhotoAction.perform(UpdateAllPhotoAction.java:82) at org.apache.struts.action.Action.execute(Action.java:420) at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484) at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274) at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482) at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507) at javax.servlet.http.HttpServlet.service(HttpServlet.java:126) at javax.servlet.http.HttpServlet.service(HttpServlet.java:103) at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:113) at com.caucho.server.cache.CacheFilterChain.doFilter(CacheFilterChain.java:211) at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:177) at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:221) at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:262) at com.caucho.server.port.TcpConnection.run(TcpConnection.java:315) at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:353) at com.caucho.util.ThreadPool.run(ThreadPool.java:302) at java.lang.Thread.run(Thread.java:534)
-------------------------------------------------------------------------------- Resin-3.0.6 (built Tue, 20 Jan 2004 09:46:57 PST) 然后刷新这个页面 500 Servlet Exception java.lang.NoClassDefFoundError at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:141) at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:62) at java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1041) at com.lodesoft.ipniii.club.tool.AlbumTool.createSmallThumb(AlbumTool.java:793) at com.lodesoft.ipniii.club.test.action.UpdateAllPhotoAction.perform(UpdateAllPhotoAction.java:82) at org.apache.struts.action.Action.execute(Action.java:420) at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484) at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274) at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482) at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507) at javax.servlet.http.HttpServlet.service(HttpServlet.java:126) at javax.servlet.http.HttpServlet.service(HttpServlet.java:103) at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:113) at com.caucho.server.cache.CacheFilterChain.doFilter(CacheFilterChain.java:211) at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:177) at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:221) at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:262) at com.caucho.server.port.TcpConnection.run(TcpConnection.java:315) at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:353) at com.caucho.util.ThreadPool.run(ThreadPool.java:302) at java.lang.Thread.run(Thread.java:534)
-------------------------------------------------------------------------------- Resin-3.0.6 (built Tue, 20 Jan 2004 09:46:57 PST) 我们的服务器上没有安装xwindows,但是安装了XFree86的相关包。web server用的是 Resin 306 ,现在找到了解决方法。 1:安装XFree86-Xvfb-4.3.0-2.i386.rpm。如果什么XFree86的相关包都没有,那就要弄来装一装了。起码的libs是要有的。 2:使用两个命令: ------------------------------------ Xvfb :0 -screen 0 800x600x16 & 启动Xwindows的虚拟设备 export DISPLAY=localhost:0.0 配置本地环境 ------------------------------------ 运行顺序先后没有太大的关系。 注意的是 Xvfb :0 -screen 0 中的两个0的参数和后面 DISPLAY=localhost:0.0 中的两个0是对应的。Xvfb实现的应该是后台虚拟拟图形界面环境。 3:可以把这两个命令做成启动就运行的脚本,也可以在启动Resin的时候调用起来,我用的后者 修改resin ./bin 目录下的httpd.sh 在JAVA_HOME 配置项前加入 Xvfb :0 -screen 0 800x600x16 & export DISPLAY=localhost:0.0 4:其实没有什么第四,因为这样就可以啦。 200408220127 :今天来增加一条,如果安装liunx的时候没有选择安装任何xwindows的组件,那么从linux安装盘上去取Xvfb的包安装是不会成功的,因为还需要一大堆依赖的包,而我就因为找不到这些包,不能加快进度而加班到昨天早上4点多。庆幸的是我找到了一个好办法去解决(不然可能要拖到5,6点才能结束),我在XFree86的官方站点上 http://XFree86.org 找到了一个Xvfb的tag下载,下来后解压出来就可以用了,哈哈哈哈。要注意的是要去找版本对应的tag包,比如RedHat 9对应的是XFree86 4.3.0 的版本,就去它的FTP下载相应版本的包,取下来后解压出bin目录,运行其中Xvfb就可以,记得加参数哦!
碰到文件乱码,google了一下,发现这篇文章还不赖
摘录如下: 之前,写过一个Download.jsp文件,可以解决下载文件乱码问题(诸如:DOC,XSL文件等等). 后来发现,遇到中文名的文件的时候,文件下载将会报错~~~~ 今天,通过改写原Download.jsp文件已经彻底解决了这个问题~ 现在,把一整套的文件上传下载的方法给贴出来~~~以便大家借鉴!~!~!~!~! 作者:古埃及法老 download.jsp文件---------------------------------------------------------
<% java.io.BufferedInputStream bis=null; java.io.BufferedOutputStream bos=null; try{ String filename=request.getParameter("filename"); filename=new String(filename.getBytes("iso8859-1"),"gb2312"); response.setContentType("application/x-msdownload"); response.setHeader("Content-disposition","attachment; filename="+new String(filename.getBytes("gb2312"),"iso8859-1")); bis =new java.io.BufferedInputStream(new java.io.FileInputStream(config.getServletContext().getRealPath("files/" + filename))); bos=new java.io.BufferedOutputStream(response.getOutputStream()); byte[] buff = new byte[2048]; int bytesRead; while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) { bos.write(buff,0,bytesRead); } } catch(Exception e){ e.printStackTrace(); } finally { if (bis != null)bis.close(); if (bos != null)bos.close(); } %>
注意,关键就是 setHeader里的filename需要重新编码,格式是ISO-8859-1就OK了
以下是我自己项目中用到的代码片断,供参考:
list.jsp: 显示附件名称的页面
<tr> <td height="25" class="tdcor">附 件 </td> <td colspan="3" height=50> <% if (null != publish.getAttatchFilename() && publish.getAttatchFilename().length() > 0) { %> <a href="publish_do.jsp?method=download&fileName= <%=URLEncoder.encode(publish.getAttatchFilename(),"GBK")%>"> <%=URLDecoder.decode(publish.getAttatchFilename(),"GBK")%></a> <% } %> </td> </tr>
download.jsp:下载页面
else if (null != method && method.equals("download")) {//下载附件
String fileName = request.getParameter("fileName"); File file = new File(Constants.PUBLISH_FILE_PATH + "/" + URLDecoder.decode(fileName,"GBK")); response.reset(); response.setContentType("application/octet-stream; charset=GBK"); response.addHeader("Content-Disposition", "attachment; filename=" + CourseDetailBusiness.transfer(URLDecoder.decode(fileName,"GBK"),"GBK","ISO-8859-1")); response.setContentLength((int) file.length());
byte[] buffer = new byte[4096]; BufferedOutputStream output = null; BufferedInputStream input = null;
// 写缓冲区: try { output = new BufferedOutputStream(response.getOutputStream()); input = new BufferedInputStream(new FileInputStream(file));
int n = (-1); while ((n = input.read(buffer, 0, 4096)) > -1) { output.write(buffer, 0, n); } response.flushBuffer(); } catch (Exception e) { } // maybe user cancelled download finally { if (input != null) input.close(); if (output != null) output.close(); }
说明: 1。文件名在数据库中保存的编码为URLEncode 2.在list.jsp显示的时候多了一次encode,不知为什么,不encode一次还不行,实际上是第二次编码了
我现在的编程方法,不再是以前的整块应用,和C/S应用的两层架构,现在流行的编程方式是三层架构,就是表示层,商业逻辑,还有数据库都相互独立。 远程方法调用正是基于三层架构设计的中间层。远程方法调用的原理是桩和骨架结构。主要有三层,分别是桩/骨架层,远程引用层,还有传输层。 要完成一个简单的RMI应用要分为以下几个简单的步骤: 1。定义远程接口 2。定义和实现RMI服务器类 3。定义和实现客户端类 4。编译以上的源码 5。生成桩/骨架 6。创建安全策略 7。启动RMI注册表 8。启动服务器 9。启动客户端 我们来做一个例子,在服务器上有一个连接数据库,插入值的方法,我们在客户端要使用这个方法,来真正的插入一个值! 第一步:先编写一个接口AccountServer.java,这个接口要继承Remote接口,并且提供一个远程方法insertDetails(),这个方法要抛出RemoteException异常,代码如下:
import java.rmi.Remote; import java.rmi.RemoteException;
public interface AccountServer extends Remote { public String insertDetails(String firstName, String lastName, String phone, String income, String accountType) throws RemoteException; }
第二步:实现远程对象类,就是RMI服务器,AccountServerImpl.java,这个类要继承UnicastRemoteObject类,并且要实现自己写的远程接口类AccountServer,首先要定义远程对象构造器,然后就是要实现远程接口中的方法,这个方法来连接mysql数据库,并且插入值.然后我们main方法中,设置安全管理程序,然后创建远程对象,接着注册远程对象.代码如下:
import java.rmi.Naming; import java.rmi.RMISecurityManager; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement;
public class AccountServerImpl extends UnicastRemoteObject implements AccountServer { private Connection con;
public AccountServerImpl() throws RemoteException { super(); }
public String insertDetails(String firstName, String lastName, String phone, String income, String accountType) throws RemoteException { int rowsAffected = 0; String sReturn = "fail"; try { Class.forName("com.mysql.jdbc.Driver"); con = DriverManager .getConnection( "jdbc:mysql://127.0.0.1/jsptest?useUnicode=true&characterEncoding=GBK", "root", ""); PreparedStatement ps = con .prepareStatement("insert into User_info values(?,?,?,?,?)"); ps.setString(1, "firstName"); ps.setString(2, "lastName"); ps.setString(3, "phone"); ps.setString(4, "income"); ps.setString(5, "accountType");
rowsAffected = ps.executeUpdate();
if (rowsAffected > 0) { sReturn = "success"; }
} catch (Exception e) { e.printStackTrace(); } return sReturn; }
public static void main(String[] args) { //设置安全管理程序 System.setSecurityManager(new RMISecurityManager());
try { //创建远程对象 AccountServerImpl as = new AccountServerImpl(); //注册远程对象 Naming.rebind("AccountServer", as); System.out.println("RMI服务器启动成功"); } catch (RemoteException e) { e.printStackTrace(); } catch (Exception e1) { e1.printStackTrace(); } }
} 第三步:编写客户端代码,Client.java 这个代码中有两个重要的任务,就是得到远程对象的应用,然后调用远程对象,其余的都是界面部分,就不再讲解,代码如下:
import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.rmi.Naming;
import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField;
public class Client { public static void main(String[] args) { ClientFrame frame = new ClientFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); } }
class ClientFrame extends JFrame { public ClientFrame() { setTitle("客户端"); setSize(200, 220);
Container con = getContentPane(); ClientPanel panel = new ClientPanel(); con.add(panel); } }
class ClientPanel extends JPanel { private JLabel lfirst, llast, lphone, lincome, ltype;
private JTextField ffirst, flast, fphone, fincome, ftype;
private JButton submit;
public ClientPanel() { lfirst = new JLabel(" 姓:"); llast = new JLabel(" 名:"); lphone = new JLabel("电话:"); lincome = new JLabel("来自:"); ltype = new JLabel("类型:");
ffirst = new JTextField(10); flast = new JTextField(10); fphone = new JTextField(10); fincome = new JTextField(10); ftype = new JTextField(10);
submit = new JButton(" 提 交 "); submit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { //得到远程对象 AccountServer as = (AccountServer) Naming .lookup("rmi://localhost/AccountServer"); String firstName = ffirst.getText(); String lastName = flast.getText(); String phone = fphone.getText(); String income = fincome.getText(); String accountType = ftype.getText(); //调用远程方法 String str = as.insertDetails(firstName, lastName, phone, income, accountType); if ("fail".equals(str)) { JOptionPane.showMessageDialog(null, "插入失败"); } else { JOptionPane.showMessageDialog(null, "插入成功"); }
} catch (Exception e2) { e2.printStackTrace(); } } });
add(lfirst); add(ffirst); add(llast); add(flast); add(lphone); add(fphone); add(lincome); add(fincome); add(ltype); add(ftype); add(submit); } }
第四步:在Dos下,进入代码所在目录,使用javac *.java 来编译所有代码 第五步:在class文件所在目录使用 rmic AccountServerImpl来生成桩和骨架(AccountServerImpl_Skel.class和AccountServerImpl.Stub.class) 第六步:用policytool工具来创建安全策略文件,放开所有的权限,保存.java.policy文件在C:\Documents and Settings\Administrator文件夹下 第七步:使用start rmiregistry命令来启动注册表,默认使用1099端口,我们不需要改变 第八步:java -Djava.rmi.server.codebase=file:/e:/aa/ -classpath .;%CLASSPATH% AccountServerImpl来启动服务器,注意由于服务器中要使用Mysql数据库,所有我们引入使用数据库的jar包,将mysql的jar包添加的CLASSPATH,就OK呢 第九步:使用java Client来启动客户端,和得到图形界面的客户端,填入数据,点击提交,数据就会添加进入数据库
附: 数据库名称:jsptest 表名:user_info 表结构: CREATE TABLE user_info ( firstName varchar(50) NOT NULL default '', lastName varchar(50) NOT NULL default '', phone varchar(20) NOT NULL default '', income varchar(30) NOT NULL default '', accountType varchar(50) NOT NULL default '', PRIMARY KEY (firstName) )
一 .RMI概述
RMI(Remote Method Invocation) RMI是分布式对象软件包,它简化了在多台计算机上的JAVA应用之间的通信。必须在jdk1.1以上
RMI用到的类 java.rmi.Remote 所有可以被远程调用的对象都必须实现该接口 java.rmi.server.UnicastRemoteObject 所有可以被远程调用的对象都必须扩展该类
什么是RMI 远程方法调用是一种计算机之间对象互相调用对方函数,启动对方进程的一种机制, 使用这种机制,某一台计算机上的对象在调用另外一台计算机上的方法时,使用的程 序语法规则和在本地机上对象间的方法调用的语法规则一样。
优点 这种机制给分布计算的系统设计、编程都带来了极大的方便。 只要按照RMI规则设计程序,可以不必再过问在RMI之下的网络细节了,如:TCP和Socket等等。 任意两台计算机之间的通讯完全由RMI负责。调用远程计算机上的对象就像本地对象一样方便。
1、面向对象: RMI可将完整的对象作为参数和返回值进行传递,而不仅仅是预定义的数据类型。 也就是说,可以将类似Java哈西表这样的复杂类型作为一个参数进行传递。
2、可移动属性: RMI可将属性从客户机移动到服务器,或者从服务器移动到客户机。
3、设计方式: 对象传递功能使您可以在分布式计算中充分利用面向对象技术的强大功能,如二层和三层结构系统。 如果用户能够传递属性,那么就可以在自己的解决方案中使用面向对象的设计方式。 所有面向对象的设计方式无不依靠不同的属性来发挥功能,如果不能传递完整的对象——包括实现和类型 ——就会失去设计方式上所提供的优点。
4、安全性: RMI使用Java内置的安全机制保证下载执行程序时用户系统的安全。 RMI使用专门为保护系统免遭恶意小程序侵害而设计的安全管理程序。 5、便于编写和使用 RMI使得Java远程服务程序和访问这些服务程序的Java客户程序的编写工作变得轻松、简单。 远程接口实际上就是Java接口。 为了实现RMI的功能必须创建远程对象任何可以被远程调用的对象必须实现远程接口。但远程 接口本身并不包含任何方法。因而需要创建一个新的接口来扩展远程接口。 新接口将包含所有可以远程调用的方法。远程对象必须实现这个新接口,由于新的接口扩展了 远程接口,实现了新接口,就满足了远程对象对实现远程接口的要求,所实现的每个对象都将 作为远程对象引用。
个人总结: RMI说白了,就是提供了一种远程的方法调用。这种调用简单方便,可以传递复杂java对象。现在流行的j2ee中的EJB的底层实现技术就是RMI,EJB的调用就是经过封装的,更高级的RMI调用。
下面我们就来写一个RMI的程序:
一.创建RMI程序的6个步骤: 1、定义一个远程接口的接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常。 2、定义一个实现该接口的类。 3、使用RMIC程序生成远程实现所需的残根和框架。 4、创建一个服务器,用于发布2中写好的类。 5. 创建一个客户程序进行RMI调用。 6、启动rmiRegistry并运行自己的远程服务器和客户程序。
二. 程序详细说明
1.定义一个远程接口的接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常。
import java.rmi.Remote; import java.rmi.RemoteException; public interface I_Hello extends java.rmi.Remote //需要从Remote继承 { public String SayHello() throws RemoteException; //需要抛出remote异常 }
上面例子我们定义一个返回字符串的远程方法 SayHello(),这个远程接口 I_Hello必须是public的,它必须从java.rmi.Remote继承而来,接口中的每一个方法都必须抛出远程异常java.rmi.RemoteException。
抛出这个异常的原因 由于任何远程方法调用实际上要进行许多低级网络操作,因此网络错误可能在调用过程中随时发生。 因此,所有的RMI操作都应放到try-catch块中。 2、定义一个实现该接口的类。
import java.io.PrintStream; import java.rmi.*; import java.rmi.server.UnicastRemoteObject;
public class Hello extends UnicastRemoteObject //必须从UnicastRemoteObject 继承 implements I_Hello { public Hello() throws RemoteException //需要一个抛出Remote异常的默认初始化方法 { }
public String SayHello() //这个是实现I_Hello接口的方法 { return "Hello world !!"; } }
实现接口的类必须继承UnicastRemoteObject类。 扩展java.rmi.server.UnicastRemoteObject UnicastRemoteObject顾名思义,是让客户机与服务器对象实例建立一对一的连接。
3、使用RMIC程序生成远程实现所需的残根Stub 和 框架。 2中的Hello 编译好以后,我们就可以用RMIC命令来生成残根Stub 在Dos窗口里,到Hello.class 所在目录,运行以下命令: rmic Hello 命令执行完以后,将会在当前目录生成一个 Hello_Stub.class 这个就是我们远程调用时需要的类
参考: 在RMI中,客户机上生成的调动调用参数和反调动返回值的代码称为残根。有的书上称这部分代码为“主干”。 服务器上生成的反调动调用参数和进行实际方法调用调动返回值的代码称为框架。 生成残根和框架的工具 Rmic命令行工具(RMI Compiler) 格式: Rmic classname
4、创建一个服务器,用于发布2中写好的类。
import java.rmi.*; public class RMI_Server { public static void main(String[] args) { try { Hello hello = new Hello(); //实例化要发布的类 Naming.rebind("RMI_Hello", hello); //绑定RMI名称 进行发布 System.out.println("=== Hello server Ready === "); } catch(Exception exception) { exception.printStackTrace(); } } }
5. 创建一个客户程序进行RMI调用。
import java.rmi.*; public class RMI_Client { public static void main(String[] args) { try { I_Hello hello = (I_Hello) Naming.lookup("RMI_Hello"); //通过RMI名称查找远程对象 System.out.println(hello.SayHello()); //调用远程对象的方法 } catch (Exception e) { e.printStackTrace(); } }
}
Naming.lookup("RMI_Hello") 其中的参数“RMI_Hello”只是针对本机的RMI查找,如果是异地的RMI调用请参照 rmi://127.0.0.1:1099/RMI_Hello 端口1099是默认的RMI端口,如果你启动 rmiregistry 的时候(见第6点)没有指定特殊的端口号,默认就是1099
到此我们所有的代码编写都完成了,不过不要急着去运行,请跟随第6点去运行,因为rmi 调用还会遇到一些特别的情况,偶花了牛劲,才找到原因的,许多刚用RMI的人,常常被这些问题搞得吐血
6、启动rmiRegistry并运行自己的远程服务器和客户程序。 1)服务器的运行 先在DOS下运行 rmiregistry 这个命令是开启RMI的注册服务,开启以后我们的server程序才能调用rebing方法发布我们的类
然后,运行我们的server程序 RMI_Server 这里是最容易出错的,参见下面注意事项。 注意: 如果提示找不到Stub类,这个需要用下面的命令来运行 java.exe -Djava.rmi.server.codebase=file:/E:\MIS_Interface\momo\TestEasy\classes/ RMI_Server
蓝字部分指定了stub类的路径。
有人会问,我已经把stub 通过-classpath 加到类路径里面了,为什么还没有提示这个错误呢?原因是这样的:这里提示的找不到stub类,不是由你写的RMI_Server这个程序引起的,是由rmi注册服务器报告的异常,也就是我们前面启动的 rmiregistry ,因为你写的RMI_Server 要求RMI注册服务器注册一个新的类,自然RMI服务器必须知道你的类放在哪里,所以我们通过 -Djava.rmi.server.codebase 这个运行参数来指定 你也可以通过修改操作系统的classpath 环境变量来指定stub的位置,只不过太麻烦
2) 客户端的运行 直接运行RMI_Client 即可 注意 把 Stub 和 接口 I_Hello 加到类路径里 通常第一次运行客户端都会报一个错误: Access XXXX 不记得具体的了,反正就是“访问权限限制”,这是因为RMI的服务需要授权,外部程序才能访问,所以我们要改动 jre的安全配置文件,来开放权限, 具体如下:
打开你的jdk目录下的这个文件 C:\Program Files\Java\jdk1.5.0_04\jre\lib\security\java.policy 在文件最后加入下面代码: grant { permission java.net.SocketPermission "*:1024-65535", "connect,accept"; permission java.net.SocketPermission "*:80","connect"; }; 此代码,开放了端口的connect访问权限
注意 你应该修改服务器那台机子的安全配置文件,也就是你运行 rmiregistry 和 RMI_Server的机子 另外,很多人修改完以后,仍然报这个错误,多数情况是由于你没有修改到正确的jdk 下的文件,而是修改到其他jdk的文件, 我们安装oracle , Weblogic等等软件的时候都会自带一个 jdk,他们会自动在操作系统的环境变量里面加入jdk的路径,所以,你先要确定你运行服务器端程序是用哪个jdk,再修改这个jdk下的配置文件,确定当前jdk的路径很简单 开始 -》运行-》rmiregistry 看看这个DOS窗口标题的路径,就是你当前系统默认jdk的路径了
客户端正常运行以后,就会出现以下结果: Hello world !!
这些字符是通过RMI调用远程服务器的类返回的结果
摘要 Java Servlet 编程可以很方便地将 HTML 文件发送到客户端 Web 浏览器。然而许多站点还允许访问非 HTML 格式的文档,包括 Adobe PDF、Microsoft Word 和 Micorsoft Excel 等。事实上这些非 HTML 格式只要能用 MIME 类型表示,就可以利用 servlet 来发送。本文将以 PDF 和 Microsoft Word 文件为例,向你介绍如何使用 servlet 传送非 HTML 格式文件,以及与防火墙交互的方法。 你只要将文件写到 servlet 的输出流中,就可以利用 servlet 在浏览器中打开一个文件。尽管这看起来非常简单,在打开非 HTML 格式文档(比如二进制数据或多媒体文件)的时候,仍要注意一些要点。 首先从获得 servlet 的输出流开始: ServletOutputStream out = res.getOutputStream(); 互联网上使用 MIME (multipurpos Internet mail extension 多目的互联网邮件扩展协议)来传送混合格式、多媒体和二进制数据文件。如果要在 servlet 的 response 对象中打开某个文档,就必须设置该文档的 MIME 类型。下面这个例子中我们将打开 PDF 文档。 MIME 类型 Web 浏览器使用 MIME 类型来识别非 HTML 文档,并决定如何显示该文档内的数据。将插件 (plug-in) 与 MIME 类型结合使用,则当 Web 浏览器下载 MIME 类型指示的文档时,就能够启动相应插件处理此文档。某些 MIME 类型还可以与外部程序结合使用,浏览器下载文档后会启动相应的外部程序。 MIME 类型非常有用。它们允许 Web 浏览器处理不同格式的文档,却不需要事先嵌入相关知识。Java Servlets 可以使用 MIME 类型来向浏览器传送非 HTML 文件,比如 Adobe PDF 和 Micorsoft Word。使用正确的 MIME 类型能够保证这些非 HTML 文件被正确的插件或外部程序显示。本文末的资料部分提供了一些网址,指向一些已定义 MIME 类型列表和关于 MIME 类型的文章。 PDF 文件的 MIME 类型是 "application/pdf"。要用 servlet 来打开一个 PDF 文档,需要将 response 对象中 header 的 content 类型设置成 "application/pdf": // MIME type for pdf doc res.setContentType( "application/pdf" ); 若要打开一个 Microsoft Word 文档,你就要将 response 对象的 content 类型设置成 "application/msword": // MIME type for MSWord doc res.setContentType( "application/msword" ); 如果是一个 Excel 文档,则使用 MIME 类型 "application/vnd.ms-excel"。其中 vnd 表示该应用程序的制造者,必须将它包含在 MIME 类型里才能够打开该类型文档。 有时候浏览器不能识别文档的 MIME 类型。通常这是由于没有安装这些文档需要的插件而导致的。这种情况下,浏览器会弹出一个对话框,询问用户是否需要打开该文件或是将它保存到本地磁盘上。 Content disposition 一种叫做 content-disposition 的 HTTP response header 允许 servlet 指定文档表示的信息。使用这种 header ,你就可以将文档指定成单独打开(而不是在浏览器中打开),还可以根据用户的操作来显示。如果用户要保存文档,你还可以为该文档建议一个文件名。这个建议名称会出现在 Save As 对话框的“文件名”栏中。如果没有指定,则对话框中就会出现 servlet 的名字。更多关于 content-disposition header 的信息,可以参阅资料。 在 servlet 中,你需要将 header 设置成下面这样: res.setHeader("Content-disposition", "attachment; filename=" + "Example.pdf" ); // attachment - since we don´t want to open // it in the browser, but // with Adobe Acrobat, and set the // default file name to use. 如果你要打开的是 Microsoft Word 文件,你可以设成: res.setHeader("Content-disposition", "attachment; filename" + "Example.doc" ); 封装非 HTML 文档 完成上述工作后,剩下的就非常简单了。你需要根据待传送文件的名字,创建一个 java.net.URL 对象。交给 URL 构造器的字符串必须是指向该文件的一个有效 URL 地址。在这个例子中,我要打开 Adobe employment 格式的文档: String fileURL = "http://www.adobe.com/aboutadobe/careeropp/pdfs/adobeapp.pdf;" 你的 URL 字符串也可以类似于 http://www.gr.com/pub/somefile.doc 或 http://www.gr.com/pub/somefile.xls。但必须确保待传送文件类型与先前在 HTTP response 对象中设置的 MIME 类型一致。 URL url = new URL ( fileURL ); 防火墙 如果需要通过防火墙,最后一件要考虑的事情就是你的 URL 链接。首先应当搜集所用代理服务器的相关信息,例如主机名称和端口号等。更多关于如何通过防火墙建立链接的信息,可以参看下面的资料部分。 如果使用的是 Java 2,你应该从 URL 对象类中创建一个 URLConnection 对象,并设置下列系统属性: URLConnection conn = url.openConnection(); // Use the username and password you use to // connect to the outside world // if your proxy server requires authentication. String authentication = "Basic " + new sun.misc.BASE64Encoder().encode("username:password".getBytes()); System.getProperties().put("proxySet", "true"); System.getProperties().put("proxyHost", PROXY_HOST); // your proxy host System.getProperties().put("proxyPort", PROXY_PORT); // your proxy port conn.setRequestProperty("Proxy-Authorization", authentication); 如果你使用的是 JDK 1.1,则不能设置这些系统属性。这种情况下,你可以根据所用代理服务器的信息创建 java.net.URL 对象: url = new URL("http", PROXY_HOST, Integer.parseInt(PROXY_PORT), fileURL ); // assumes authentication is not required 深入工作 开始阅读你传送的文档之前,首先要从 URLConnection (或 URL) 对象中获得输入流 InputStream。在这个例子中,用 BufferedInputStream 将 InputStream 封装起来。 如果你采用 URLConnection,可以尝试如下代码: BufferedInputStream bis = new BufferedInputStream(conn.getInputStream()); 如果你使用 URL,则可用下列代码: BufferedInputStream bis = new BufferedInputStream(url.openStream()); 一旦你完成上述操作,就只要简单地将 InputStream 中的字节,写入到 servlet 的输出流 OutputStream 中: BufferedOutputStream bos = new BufferedOutputStream(out); byte[] buff = new byte[2048]; int bytesRead; // Simple read/write loop. while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) { bos.write(buff, 0, bytesRead); } 在最后的代码块中,关闭这些流。 这个例子是利用 doPost 来实现的(doPost 是 HttpServlet 子类的一个方法): public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { ServletOutputStream out = res.getOutputStream (); //--------------------------------------------------------------- // Set the output data´s mime type //--------------------------------------------------------------- res.setContentType( "application/pdf" ); // MIME type for pdf doc //--------------------------------------------------------------- // create an input stream from fileURL //--------------------------------------------------------------- String fileURL = "http://www.adobe.com/aboutadobe/careeropp/pdfs/adobeapp.pdf"; //------------------------------------------------------------ // Content-disposition header - don´t open in browser and // set the "Save As..." filename. // *There is reportedly a bug in IE4.0 which ignores this... //------------------------------------------------------------ res.setHeader("Content-disposition", "attachment; filename=" += "Example.pdf" ); //----------------------------------------------------------------- // PROXY_HOST and PROXY_PORT should be your proxy host and port // that will let you go through the firewall without authentication. // Otherwise set the system properties and use URLConnection.getInputStream(). //----------------------------------------------------------------- BufferedInputStream bis = null; BufferedOutputStream bos = null; try { URL url = new URL( "http", PROXY_HOST, Integer.parseInt(PROXY_PORT), fileURL ); // Use Buffered Stream for reading/writing. bis = new BufferedInputStream(url.openStream()); bos = new BufferedOutputStream(out); byte[] buff = new byte[2048]; int bytesRead; // Simple read/write loop. while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) { bos.write(buff, 0, bytesRead); } } catch(final MalformedURLException e) { System.out.println ( "MalformedURLException." ); throw e; } catch(final IOException e) { System.out.println ( "IOException." ); throw e; } finally { if (bis != null) bis.close(); if (bos != null) bos.close(); } } 结论 正如你所读到的,用 servlet 来打开非 html 文档相当简单。即使是要通过防火墙也是如此。只要设置了正确的 MIME 类型,就可以使用同样的代码来打开图片或其他多媒体文件。当今的互联网上包含了大量信息,其中许多数据被存储为非 HTML 格式。使用 servlet 能够克服 HTML 的限制,简单方便地向用户传送这些非 HTML 格式的信息
下面是DLOG4J生成随即验证码的代码:
package dlog4j;
import java.io.IOException;
import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
import dlog4j.util.image.RandomImageGenerator;
/** * 用于产生注册用户时的随即图片以防止非法攻击 * @author Liudong */ public class RandomImageServlet extends HttpServlet {
public final static String RANDOM_LOGIN_KEY = "RANDOM_LOGIN_KEY";
public void init() throws ServletException { System.setProperty("java.awt.headless","true"); } public static String getRandomLoginKey(HttpServletRequest req) { return (String)req.getSession().getAttribute(RANDOM_LOGIN_KEY); } protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { HttpSession ssn = req.getSession(); if(ssn!=null) { String randomString = RandomImageGenerator.random(); ssn.setAttribute(RANDOM_LOGIN_KEY,randomString); res.setContentType("image/jpeg"); RandomImageGenerator.render(randomString,res.getOutputStream()); } } }
这段代码在Linux下工作是没问题的,但是生成图片的时候会抛出类没定义的异常,除非JDK是1.5版本。如果JDK为1.4的话,那只能给应用服务器的启动加上参数-Djava.awt.headless=true,具体每个应用服务器如何加此参数请参照不同服务器的文档。Tomcat可以通过修改startup.sh来添加这个参数。
在网上看过很多对该问题的描述,都没有什么有效的解决办法。
在这将着重介绍一下Windows系统的Svchost.exe和Explorer.exe两种进程,作为Windows系统中两种重要的进程,下面我们就来看看他们的特点以及在各个操作系统中的应用。
Explorer
在Windows系列的操作系统中,运行时都会启动一个名为Explorer.exe的进程。这个进程主要负责显示系统桌面上的图标以及任务栏,它在不同的系统中有不同的妙用。
Explorer在Windows 9x中的应用
在Windows 9x中,这个进程是运行系统时所必需的。如果用“结束任务”的方法来结束Explorer.exe进程,系统就会刷新桌面,并更新注册表。所以,我们也可以利用此方法来快速更新注册表。方法如下:
按下Ctrl+Alt+Del组合键,出现“结束任务”对话框。在该对话框中选择“Explorer”选项,然后单击“结束任务”按钮,将出现“关闭Windows”对话框。单击“否”按钮,系统过一会儿将出现另一个对话框,告诉你该程序没有响应,询问是否结束任务。单击“结束任务”按钮,则更新注册表并返回Windows 9x系统环境中。这比起烦琐的重新启动过程要方便多了?
Explorer在Windows 2000/XP中的应用
在Windows 2000/XP和其他Windows NT内核的系统中,Explorer.exe进程并不是系统运行时所必需的,所以可以用任务管理器来结束它,并不影响系统的正常工作。打开你需要运行的程序,如记事本。然后右击任务栏,选择“任务管理器”,选中“进程”选项卡,在窗口中选择
Explorer.exe进程,单击“结束进程”按钮,,接下来桌面上除了壁纸(活动桌面Active Desktop的壁纸除外),所有图标和任务栏都消失了。此时你仍可以像平常一样操作一切软件。
如果你想运行其他软件,但此时桌面上空无一物,怎么办?别着急,下面有两种可以巧妙地打开其他软件:
第一种方法:按下Ctrl+Alt+Del组合键,出现“Windows安全”对话框,单击“任务管理器”按钮(或是直接按下Ctrl+Shift+Esc组合键),在任务管理器窗口中选中“应用程序”选项卡,单击“新任务”,在弹出的“创建新任务”的对话框中,输入你想要打开的软件的路径和名称即可。
你还可以在正在运行的软件上,选择“文件→打开”,在“打开”对话框中,点击“文件类型”下拉列表,选择“所有文件”,再浏览到你想打开的软件,右击它,在快捷菜单中选择“打开”命令,就可以启动你需要的软件了。注意,此时不能够通过单击“打开”按钮来打开软件,此种方法适用于大多数软件,Office系列除外。
通过结束Explorer.exe进程,还可以减少4520KB左右的系统已使用内存,无疑会加快系统的运行速度,为资源紧张的用户腾出了宝贵的空间。
Svchost.exe
Svchost.exe是NT核心系统的非常重要的进程,对于2000、XP来说,不可或缺。很多病毒、木马也会调用它。所以,深入了解这个程序,是玩电脑的必修课之一。
大家对Windows操作系统一定不陌生,但你是否注意到系统中“Svchost.exe”这个文件呢?细心的朋友会发现Windows中存在多个 “Svchost”进程(通过“ctrl+alt+del”键打开任务管理器,这里的“进程”标签中就可看到了),为什么会这样呢?下面就来揭开它神秘的面纱。
在基于NT内核的Windows操作系统家族中,不同版本的Windows系统,存在不同数量的“Svchost”进程,用户使用“任务管理器”可查看其进程数目。一般来说,Win 2000有两个Svchost进程,Win XP中则有四个或四个以上的Svchost进程(以后看到系统中有多个这种进程,千万别立即判定系统有病毒了哟),而Win 2003 server中则更多。这些Svchost进程提供很多系统服务,如:rpcss服务(remote procedure call)、dmserver服务(logical disk manager)、dhcp服务(dhcp clieNT)等
如果要了解每个Svchost进程到底提供了多少系统服务,可以在Win 2000的命令提示符窗口中输入“tlist -s”命令来查看,该命令是Win 2000 support tools提供的。在Win XP则使用“tasklist /svc”命令。
Svchost中可以包含多个服务
Windows系统进程分为独立进程和共享进程两种,“Svchost.exe”文件存在于“%systemroot% system32”目录下,它属于共享进程。随着Windows系统服务不断增多,为了节省系统资源,微软把很多服务做成共享方式,交由 Svchost.exe进程来启动。
但Svchost进程只作为服务宿主,并不能实现任何服务功能,即它只能提供条件让其他服务在这里被启动,而它自己却不能给用户提供任何服务。那这些服务是如何实现的呢?
原来这些系统服务是以动态链接库(dll)形式实现的,它们把可执行程序指向 Svchost,由Svchost调用相应服务的动态链接库来启动服务。那Svchost又怎么知道某个系统服务该调用哪个动态链接库呢?这是通过系统服务在注册表中设置的参数来实现。
从启动参数中可见服务是靠Svchost来启动的。
因为Svchost进程启动各种服务,所以病毒、木马也想尽办法来利用它,企图利用它的特性来迷惑用户,达到感染、入侵、破坏的目的(如冲击波变种病毒“w32.welchia.worm”)。但Windows系统存在多个Svchost进程是很正常的,在受感染的机器中到底哪个是病毒进程呢?这里仅举一例来说明。
假设Windows XP系统被“w32.welchia.worm”感染了。正常的Svchost文件存在于“c:\Windows\system32”目录下,如果发现该文件出现在其他目录下就要小心了。“w32.welchia.worm”病毒存在于“c:\Windows\system32Win s”目录中,因此使用进程管理器查看Svchost进程的执行文件路径就很容易发现系统是否感染了病毒。
Windows系统自带的任务管理器不能够查看进程的路径,可以使用第三方进程管理软件,如“Windows优化大师”进程管理器,通过这些工具就可很容易地查看到所有的Svchost进程的执行文件路径,一旦发现其执行路径为不平常的位置就应该马上进行检测和处理。
印度软件巨头印孚瑟斯技术公司(Infosys)董事长纳拉亚纳·穆尔蒂日前表示,他认为印度软件业领先中国20年。
印度报业托拉斯援引穆尔蒂的话说,中国的制造业享誉世界,但软件业落后于印度。但他同时强调,印度软件公司不能低估中国同行的发展潜力。
在分析印度软件业迅速发展的原因时,穆尔蒂认为,印度软件人才工作勤奋,软件公司更加了解顾客的需求,同时在运营方面更加优秀。
穆尔蒂指出,印度软件业发展了先进的销售体系、销售流程和销售方法,并且高度重视产品质量。与此同时,他认为印度应该在软件业方面进一步加强其优势。
印度目前已经成为全球软件研发基地之一和IT服务外包主要目的地。据统计,目前印度公司参与的IT服务合同约占全球IT服务合同总金额的7%。这其中,塔塔咨询公司、印孚瑟斯技术有限公司和维普罗公司等大型企业扮演了重要角色。
网站中有哪些关键技巧?有哪些陷阱?在这里,世界上一流的网站设计专家,让你共享他们的秘密,告诉你:使网站赋予情趣的诀窍、应该避免做什么、应使用什么工具软件以及他们喜爱和厌恶的网站。
01明确内容
如果你想成为一个网站设计者,并正想建一个网站的话,首先应该考虑网站的内容,包括网站功能和你的用户需要什么。你的整个设计都应该围绕这些方面来进行。
02抓住用户
如果用户不能够迅速地进入你的网站,或操作不便捷,网站设计就是失败的。不要让用户失望而转向你的对手的网站。Ailiss.com
03优化内容
内容是核心。大约在两年以前,企业网站就像一本广告册子,更槽糕的是,网站使用了大量的图片,似乎要几个世纪才能下载完。Chanels网站(www.channels.co.uk)在设计的某些方面是成功的,但是内容太贪乏,并且要花很长时间才能找到所要的东西,因此不能算是一个成功的网站。
04快速下载
没有什么比要花很长时间下载页面更槽糕的了。作为一条经验,一个标准的网页应不大于60K,通过56K调制解调器加载花30秒的时间。有的设计者说网页加载应在15秒内。
05网站升级
时刻注意网站的运行状况。性能很好的主机随着访问人数的增加,可能会运行缓慢。但是,如果你不想失去访问者的话,一定要仔细计划好你的升级计划。Ailiss.com
06坚持基本原则
即使你不懂HTML语言,你只需购买一个有版权的所见即所得的网页设计工具,如AdobePageMill或MicrosoftFrontPageExpress,就可以创建一个看起来很合理的网站。但是,在设计时,这些软件包虽然不需要HTML,却使网站速度下降。为了成功地设计网站,你必须理解HTML是如何工作的。大多数的网站设计者建议网络新手应从有关HTML的书中去寻找答案,用Notepad制作网页。
07学习HTML
用HTML设计网站,可以控制设计的整个过程。但是,如果你仅仅是网站设计的新手,你应该寻找一个允许修改HTML的软件包。HomeSite4是一个很好的Web设计工具。在设计过程中,HomeSite4能帮助你学习HTML。它还允许你切换到所见即所得的模式,以便你在把网站发送到Web之前,预览你的网站。
08用笔画一个网站的框架
圣人云:笔比剑更强大。在用计算机之前,用笔画一个网站的框架,显示出所有网页的相互关系。计划好你的用户如何以最少的时间浏览你的网站。
09“在计算机上永远也找不到好的方案”。——专家忠告
10网站地图
许多设计者把他们的网站地图放在网站上,这种做法,却是弊大于利。绝大部分的访问者上网是寻找一些特别的信息,他们对于你的网站是如何工作的,并没有兴趣。如果你觉得你的网站需要地图,那很可能是需要改进你的导航和工具条
11“睁大你的眼睛,留意所有的事情。对最不相关的东西的观察可以得到最好的灵感。观察一个站点的结构和设计。理解站点结构的关键元素,确保你的设计是围绕站点浏览进行的。”——专家忠告
12点击规则
听说过3次点击规则吗?对于小型网站,在你的主页上,没有任何一条信息,需要点击次数超过3次的。对于大型网站,使用导航和工具条来改善操作。
13特殊字体的应用
虽然你可以在你的HTML中使用特殊的字体,但是,你不可能预测你的访问者在他们的计算机上将看到什么。在你的计算机里看起来相当好的页面,在另一个不同的平台上看起来可能非常糟糕。一些网站设计员喜欢使用来定义特性,这虽然允许你使用特殊的字体,但是仍需要一些变通的方法,以免你所选择的字体在访问者的计算机上不能显示。级联风格表CSS有助于解决这些问题,但是只有最新版的浏览器才支持CSS。
14“使用切合实际的简便的命名规则。”——专家忠告
15检查错别字
好的拼写是人们一生中重要的技能。但是遗憾的是,许多设计者都缺少这种技能。确保你拼写正确,并且格外注意平常容易误写的错别字。Ailiss.com
16避免长文本页面
在一个站点上有许多只有文本的页面,是令人乏味的,且也浪费Web的潜力。如果你有大量的基于文本的文档,应当以AdobeAcrobat格式的文件形式来放置,以便你的访问者能离线阅读。
17不要使用卷滚条人们厌恶在网上使用卷滚条。Trouble网站(www.Trouble.co.uk)是一个典型的设计很差的网站。它基于一个浮动的架构,为了阅读所有的文本,浏览者不得不使用卷滚条。
18专家最喜爱的Web设计工具
1.AdobePhotoshop
2.MacromediaFlash
3.AdobeIllustrator
4.AdobeImageRead
5.Dreamweaver
6.MacromediaFireworks
7.AllaireHomesites
8.MicrosoftNotepad
9.MacromediaDirector
10.lightwave
11.MacromediaFreehand
12.其它:AdobeAcrobatExchange,AllaireColdFusion,BBEdit,HTMLValidator等。
19网站介绍
你应当有一个很清晰的网站介绍,告诉访问者你的网站能够提供些什么,以便访问者能找到想要的东西。但是,许多设计者都没有这样做。有效的导航条和搜索工具使人们很容易找到有用的信息,这对访问者很重要。告诉访问者你所提供的正是他们想要的信息。
20“网站一旦发布,网站设计的优点和缺陷全都公布于世。没有什么方法使你能够比从自己的错误、倾听其他人的建议和用户反馈意见中学到更多的东西。”——专家忠告
21闪烁让人头痛
通过使用标识可以吸引访问者对你的主页特殊部分的注意,但这也让你的访问者头痛。如果你想使访问者再次光顾你的网站,就少用此方法。
22背景颜色
背景颜色也会产生一些问题,可能会使网页难于阅读。你应当坚持使用白色的背景和黑色的文本,另外还应当坚持使用通用字体。Ailiss.com
23向前和向后按钮
应当避免强迫用户使用向前和向后按钮。你的设计应当使用户能够很快地找到他们所要的东西。绝大多数好的站点在每一页同样的位置上都有相同的导航条,使浏览者能够从每一页上访问网站的任何部分。
24“坚持你的信念。严格遵守各种规则。避免想当然。绝不停止学习。”——专家忠告
25点击记数器
不要轻易考虑在你的网站上放置一个醒目的点击记数器。你设计网站是为了给访问者提供服务,而不是推销你自己认为重要的东西。大多数浏览者认为计数器毫无意义,它们很容易被做假,浏览者也不想看广告。如果你显示你的网站是多么受欢迎,你最好提供一个链接,显示访问日志。
26不要用框架
与记数器一样,框架在网页上越来越流行。在大多数网站上,在屏幕的左边有一个框架。但是设计者立刻就发现,在使用框架时产生了许多的问题。使用框架时如果没有17英寸的显示屏几乎不可能显示整个网站。框架也使得网站内个人主页不能够成为书签。也许更重要的是,搜索引擎常常被框架混淆,从而不能列出你的网站。
27去掉图像
在浏览器中即使去掉了图像功能,也要保证访问者能够在你的网站上获得满意的效果。对于那些使用ISDN连接并且关掉了图像功能的访问者,还能获得好的网页加载性能。可以通过在网页底部提供另外的链接和使用替代文字,而不是图像来满足访问者的需要。
28重复使用图像
一些网站由于使用大量不重复的图像而错过了使用更好的技巧的机会。在创建商标时,在网页上多次使用同样的图像是一个好的方法,并且一旦它们被装入,以后重新载入就会很快。
29避免使用过大的图像
不要使用横跨整个屏幕的图像。避免访问者向右滚动屏幕。占75%的屏幕宽度是一个好的建议。Ailiss.com
30“避免使用炫耀的技巧。”——专家忠告
31选择使用Flash动画
许多使用比较慢的计算机的访问者发现动画图标很容易耗尽系统资源,使网站的操作变得很困难,因此,应该给用户一个跳过使用Flash动画的选择。
32尽量少使用Flash插件
虽然许多Web设计者认为Flash功能很强大,并且Netscape5.0将支持Flash,在使用时不必再下载任何插件。但是,最好还是取消使用Flash做各接口的想法。
33让用户先预览小图像
如果不得不放置大的图像在网站上,就最好使用Thumbnails软件,把图像的缩小版本的预览效果显示出来,这样用户就不必浪费金钱和时间去下载他们根本不想看的大图像。
34动画与内容应有机结合
确保动画和内容有关联。它们应和网页浑然一体,而不是干巴巴的。动画并不只是MacromediaDirector等制作的东西的简单堆积。Ailiss.com
35慎用声音
声音的运用也应得到警惕。内联声音是网页设计者的另一个禁地。因为过多地使用声音会使下载速度很慢,同时并没有带给浏览者多少好处。首次听到鼠标发出声音可能会很有趣,但是多次以后肯定会很烦人。使用声音前,应该仔细考虑声音将会给你带来什么。
36少用Java和AxtiveX
在网页上应尽量少使用Java和AxtiveX。因为并不是每一种浏览器都需要使用它,只有那些Netscape和Explorer的早期版本的使用者才需要它。另外Mac在处理Java时也存在问题,过分地使用Java,会使Mac崩溃。
37设计成功的网站
www.bmw.co.uk——内容和关联性很好 Ailiss.com
www.yugop.com——图形下载很快
www.comicrelief.org.uk——设计简单明了
www.dreamcast-europe.comwww.newsunlimited.co.ukwww.newbeetle.comwww.swoon.comwww.viaduct.co.uk
38慎用插件
在Web设计中,如果依赖于一些特别的插件,会减少网站的吸引力。如果访问者没有所要求的插件,将不得不到其它站点去下载,这样访问者有可能就不会返回了。
39使用著名的插件
如果网站上有声音或视频,要保证使用者通过使用某个知名的插件,能够听到或看到。许多站点使用QuickTime、RealPlay和Shockwave插件。因为,许多访问者并不愿意浪费很多时间和金钱去下载可能仅使用一次的插件。
40使用先进技术
跟上新的技术。Web技术的进步绝不会停止,所以应花一些时间来研究新产品和开发技术。
41自己创建图像和声音
使用你自己创建的或从某个商业网站上下载的图像和声音。在制作商业网站时,应该花足够的资金来创建图形,以增强公司的宣传。Ailiss.com
42“无论是游戏、图像、动画还是电影,想想你喜欢的设计是怎样的,这将激发你的创作灵感,使你创作出新的和更好的网站。”——专家忠告
43平台的兼容性
要为用户着想,必须最少在一台PC和一台Mac机上测试你的网站,看看兼容性如何。
44用软件分析工具找错
使用软件分析工具检查HTML。软件分析工具DoctorHTML能够帮助检查HTML中的任何问题。如果你有许多网页需要检查,可选用软件分析工具。在网址www.weblint.org/validation.html中,你能够找到更多有效的HTML工具。
45避免错误链接
网站中可能与其它一些有用的站点作了链接。但是,如果在你的网页上有链接,一定要经常检查它们,保证链接有效。链接的网站可能很多,但不要链接到与你的内容无关的网站上。
46给观众成熟的东西
如果网站没有完成,就不要发送到Web上。所有好的网站都是在幕后完成之后再发布的。
47在搜索引擎上登记网站
任何一个人发现你的网站的机会都很少,除非你把你的网站在主要的搜索引擎上进行登记。Ailiss.com
48设计一个留言板
浏览者愿意把时间花在好的网站上,所以最好有一个留言本,这能激励访问者再次回到你的网站,还有助于扩充网站内容。
49测试网站
在你的网站正式发布之前,必须进行有用的测试。在设计网站时要使用最新的软件,但是不要忘了人们并不会使用最新的浏览器,所以要照顾到以前的浏览器。在上载网站时还要测试所有的链接和导航工具条。
50“尽你所能反复测试所设计的网站,直到你不能发现新的东西为止。”——专家忠告
51演示即将发布的网站
在网站正式运行之前,让人演示它。演示中人们会告诉你所设计的网站是否容易使用。Ailiss.com
52动画点缀
网页上的动画最多只用一个
53“倾斜的按钮看起来不会太好,最好不要使用。”——专家忠告
54内容组织
在开始创建新的网页前,仔细考虑网站内容的组织。决定好想让访问者浏览的内容,然后设计导航系统。
55“空白万岁”
注意留空白。不要用图像、文本和不必要的动画GIFs来充斥网页,即使有足够的空间,在设计时也应该避免使用。
56“利用空白去吸引注意力。为了吸引眼球,Web设计者使用各种方法,比如:闪烁、旋转等,但是利用空白会吸引更多的注意力。”——专家忠告
57图像压缩
为了保持小的图像,可以使用类似GIF向导的程序,它能自动对图像进行压缩。先声明图像的大小,在图像显示之前最好能详细说明图像大小属性,可以在IMG标签中保存这个属性。这可以使网页显得很流畅,因为浏览器可以在图像被下载之前在屏幕上显示整个网页。
58设计失败的网站
www.boo.com——在它上面找一件T恤衫要花一个小时www.miniheroes.co.uk——不吸引人,主页太雷赘 Ailiss.com
www.saturn.com.——设计太差
www.e13.com.——没有新意
www.song.com.——导航不知所云
59图像大小属性,可以在IMG标签中保存这个属性。这可以使网页显得很流畅,因为浏览器可以在图像被下载之前在屏幕上显示整个网页。Ailiss.com
60用户注册
如果能知道谁浏览了网站以及是怎样浏览网站的,那么就能得到大量有用的信息。但是,要求访问者在浏览网站之前进行注册,这样做是要冒风险的,因为这将赶走一批不愿意注册的人。获得信息的另一种方法是进行有奖竞猜或金钱奖励,让用户能主动填一些信息反馈表。
61使网站具有交互功能
在网站上提供一些回答问题的工具,使得访问者能从网站上获得交互的信息。Ailiss.com
62图片更新
尽可能经常更换网站上的图片,人们更愿意点击的是图片而不是文本。
63在网站上提供游戏
游戏是很好的交互工具,它是使访问者能再次光顾网站的好方法。
64挑选工具软件
仔细选择Web设计工具。保证使用自己最想要的、自我感觉最好的软件。
65使用最新版本的软件
尽量使用Web设计软件的最新版本,还应当能被授权进行免费或便宜的升级。
现在中国所有招聘网站都是以人事经理为中心,因为他们是给钱的一方,较少从求职者角度考虑,如果我们从求职者立场或者中立立场来看中国招聘网站的生意模式及运作流程,将这个求职者并不知晓的事情公布出来,你就会更好清醒认识招聘网站,也更好的实际的利用人才网站求职: 1、 人才网站与企业人事经理的生意模式对求职者影响: 人才网站的行规是企业人事经理支付600元,可以在一个月内发布一定的职位让求职者投递简历,可以搜索查看人才网站简历库的简历,还可以下载一定数量的简历主动与求职者联系。而大企业及知名公司一般都是购买1年的招聘服务。问题就出来了:如果这个职位1到2周企业招到人了,但他购买的是1个月的服务,所以企业的职位还是挂在网上,而且人才网站竞争激烈,一般都会赠送1个月服务。所以一般职位至少1个月挂在人才网站是无效的,是浪费求职者查看与投递简历时间的。 大公司最不可靠,他们用网络、报纸、现场,1年的大大banner永远挂在人才网站上,他们并不需要人,只是为了广告宣传。 所以人才网站50%以上的职位都是过期的、无效的、不招人或招满人的,所有求职者抱怨我投了那么多简历为什么反馈率那么低,反馈率低是非常正常的。 另外51job网站的反馈率是最低的,这也是行业秘密:因为51Job的资源80%是以报纸招聘为主,报纸招聘效率高,但网站上的职位都是在报纸上刊登过后作为免费与补充服务,所以很多HR只会看报纸上来的简历,网站来的简历基本不看,在加上51job简历投递量实在太大,那些懒惰的HR才懒得一封一封的看,只会用搜索关键字来看,如本科+3年工作经验+主管等,其他不符合条件的看都不看一眼。所以你知道为什么一直没有公司找你面试,不是你不行,而是HR都不看你发的简历。下面第二部分告诉你如何被他们搜索到。 现在你知道网络招聘的反馈率为什么那么低了吧。不信你用自动回复邮件形式发送中国3大招聘网站职位HR的邮箱,看看有多少HR看了你的简历,一个工作论坛的网友说,他试着发了100个HR邮箱简历,可以通过自动回复的反馈率统计,可以看到50%HR不看简历就直接删除,30%根本就不打开邮件,只有20%打开邮箱,还有10%可能已经找到人的。他的分析说即使是中国前3名招聘网站以严格标准来看也只有10%职位是真正要急迫招人的。 二、既然知道一些潜规则,那我们也迎合一些这些规则,告诉你一些网络求职的小秘密 (1)采用行业招聘网站求职。因为行业招聘网站是按行业发布职位信息的,所以专业和工作经历比较对口。比如你要找物业管理类的工作,你到万行工作网 www.114job.com.cn的物业管理招聘频道上去注册简历就比较好,因为那里全部都是物业管理类的企业在招聘;如果你要找外贸的工作,你就可以万行工作网的外贸招聘频道去找,肯定有大量的外贸工作机会。其它的就不在列举。在目前的情况下,几乎每个行业的人才在万行工作网上都能找到自己的频道。 (2)简历要与大公司沾边 当人事经理搜索招聘网站简历库简历时,一般会以关键字“知名企业名称+职位名称”,比如消费品行业可能喜欢可口可乐及宝洁的人,人事经理会这样搜索,例如:“可口可乐+销售经理”,系统会搜索到简历中出现以上关键字的求职者,如果你的简历里出现知名企业名称的字样,就可以被搜索到,例如:“我在xx矿泉水公司工作,成功地令竞争对手——可口可乐旗下的天与地矿泉水在当地的市场份额减少……”:“我在可口可乐的广州白云区经销商工作”等。又提高了人事经理浏览简历的机会! (3) 经常刷新简历 当人事经理搜索简历库的简历时,符合条件的简历是按刷新的时间顺序排列,而一般只会看前面一两页。很多求职者其实并不知道刷新简历可以获得更多求职机会。因此每次登陆,最好都刷新简历,刷新以后,就能排在前面,更容易被人事经理找到! (4) 不要只应聘最近三天的职位 一般求职者认为刚刚发布的最新的招聘信息肯定是成功率最大的,其实不然。因为很多企业人事经理没有及时的登陆刷新刊登的职位,所以求职者在搜索职位时刚刷新的职位会排在前面,这些职位应聘的人多,竞争大,相反,一些职位已经是半个月甚至两个月的,应聘的人少,成功率反而高。 (5) 让你的邮件永远在最前面 你要知道每天人事经理看求职者邮箱,他们其实是很懒的,100多页简历邮件他们最多只看前5页!你现在应该知道为什么你的求职简历永远没有回应! 所以发邮件到企业指定的邮箱时,怎样才能让你的邮件永远排在最前面,让人事经理每次打开邮箱都首先看到你的邮件?只要在发邮件前,把电脑系统的日期改为一个将来的日期,如2008年,因为大多邮箱都是默认把邮件按日期排序,所以你的邮件起码要到2008年以后才会被排在后面! (如果你求职成功,要向我请客耶!) (6) 新颖的邮件标题 人事经理每天收到大量的求职电子邮件,求职者一般会按企业要求把邮件题目写成:应聘xx职位,怎样才能吸引人事经理的眼球,让他先打开自己的邮件?可以在邮件题目上做文章。一天人事经理收到几百封邮件,只有标题新颖的才有机会被打开。 例子:我的一个女性朋友发了100多封邮件求职都没有任何反应,因为应聘做文员的太多了,而我这个朋友做过空姐,我将她的邮件标题改为“空姐来广州找工作”,引起绝大部分男人事经理想入非非,结果三天之内有30多个男人事经理通知面试,3个月找不到工作的她而变成3天找到上十份工作。你现在知道邮件标题的重要性了吧。 (7) 简历最好放靓照 对于人事经理来说,每天需要浏览大量简历,如果同等的条件,一般会先通知有照片的求职者来面试,因为通过照片,人事经理对应聘者又多了几分了解。如果是美女,被通知的可能性就更大。我作为人事经理,曾经招聘一个人事主管,收到300多封简历,我找出前30份有相片的前5份,通知了最漂亮相片的2个女孩,就定下了其中的一个。对于一般职位如文职人员之类,中国人的传统还是以貌取人,你即使不漂亮,也照一个艺术照,就增多了面试机会(与其等死,还不如放手一搏),毕竟很现实的是,简历的目的就是有面试的机会,其他就要靠实力与运气了。 (8)求职信“骂”对方公司往往会带来意想不到的效果 一般人认为在求职信中称赞对方公司会引起好感,其实不然。如果先指出这家公司的缺点,往往会引起关注,语不惊人死不休呢,我作为人事经理,我只会对指出我们缺点的求职者有好感,对恭维我们公司的求职者一般会放在一边。即使你不知道对方公司缺点,你随便写一些永远不会错的:“我认为贵司创新不够,市场表现过于常规化;我以消费者心态观察贵司,发现贵司客户服务还有许多待改进的地方;我发现贵司品牌形象还有可能做的更好……”如闻其详,可面谈。可勾引相关公司面试。只要有面试机会,其他再说。(简历有机会面试目的是一切,手段是无所谓的)。 (9)自己要学会让简历与职位匹配 2个观念都是有效的:一是不要太在乎对方职位要求的描述,很多职位描述只是写写,连经理都不知道要招什么样的人,如果你看到对方职位要求本科,你是专科就不敢投递简历,那就失去机会了。如果你看到对方要求有5年经验,你只有3年经验,你也不敢投,那完全没有必要。因为人事经理们对职位的描述只是例行公事随便谢谢而已,你千万不要当真! 另外一个匹配观念就是他的职位如何描述,你就改变你的简历换一个说法匹配,如他说要求领导能力强,你的简历也说具有领导才能,他要沟通能力一流,你的简历也说我最擅长沟通。你的简历表面匹配度最高,也可以多增加机会。你可将简历改成为他职位描述完全量身定做的简历。 其实求职者有更多的面试机会,不但可以增加成功求职机会,还可以增加自己的信心,工资越叫越高还可以积累面试经验。很多优秀的求职者网上发了很多简历没有回应,以为自己不行没有竞争力,只好自动降价,实为可惜! 特别是中国最大的招聘网站51job的简历投递反馈率是同行业最低的,因为它主要资源80%投入报纸,报纸招聘完甚至录取完毕后将职位入库,只是将职位作为一个摆设放到网站。 要知道现在网络求职的成功率一般2个月是发1000份简历,有8份面试,2份成功,一个是你不想去的,可能一个是你相对满意的。所以网络求职的朋友千万不要对自己失去信心。
Q: Can you sell yourself in two minutes? Go for it. (你能在两分钟內自我推荐吗?大胆试试吧!) A: With my qualifications and experience, I feel I am hardworking,responsible and diligent in any project I undertake. Your organization could benefit from my analytical and interpersonal skills.(依我的资格和经验,我觉得我对所从事的每一个项目都很努力、负责、勤勉。我的分析能力和与人相处的技巧,对贵单位必有价值。)
Q:Give me a summary of your current job description. (对你目前的工作,能否做个概括的说明。) A:I have been working as a computer programmer for five years. To be specific, I do system analysis, trouble shooting and provide software support. (我干了五年的电脑程序员。具体地说,我做系统分析,解决问题以及软件供应方面的支持。)
Q:Why did you leave your last job?(你为什么离职呢?) A: Well, I am hoping to get an offer of a better position. If opportunity knocks, I will take it.(我希望能获得一份更好的工作,如果机会来临,我会抓 住。) A:I feel I have reached the "glass ceiling" in my current job. / I feel there is no opportunity for advancement. (我觉得目前的工作,已经达到顶峰,即沒有升迁机会。)
Q:How do you rate yourself as a professional?(你如何评估自己是位专业人员呢?) A: With my strong academic background, I am capable and competent. (凭借我良好的学术背景,我可以胜任自己的工作,而且我认为自己很有竞争力。) A:With my teaching experience, I am confident that I can relate to students very well. (依我的教学经验,我相信能与学生相处的很好。)
Q: What contribution did you make to your current (previous) organization?(你对目前/从前的工作单位有何贡献?) A: I have finished three new projects, and I am sure I can apply my experience to this position. (我已经完成三个新项目,我相信我能将我的经验用在这份工作上。)
Q:What do you think you are worth to us?(你怎么认为你对我们有价值呢?) A:I feel I can make some positive contributions to your company in the future. (我觉得我对贵公司能做些积极性的贡献。)
Q:What make you think you would be a success in this position? (你如何知道你能胜任这份工作?) A:My graduate school training combined with my internship should qualify me for this particular job. I am sure I will be successful. (我在研究所的训练,加上实习工作,使我适合这份工作。我相信我能成功。)
Q:Are you a multi-tasked individual?(你是一位可以同时承担数项工作的人吗?)or Do you work well under stress or pressure?(你能承受工作上的压力吗?) A:Yes, I think so. A:The trait is needed in my current(or previous) position and I know I can handle it well. (这种特点就是我目前(先前)工作所需要的,我知道我能应付自如。)
Q:What is your strongest trait(s)?(你个性上最大的特点是什么?) A:Helpfulness and caring.(乐于助人和关心他人。) A:Adaptability and sense of humor.(适应能力和幽默感。) A:Cheerfulness and friendliness.(乐观和友爱。)
Q: How would your friends or colleagues describe you?(你的朋友或同事怎样形容你?) A: (pause a few seconds) (稍等几秒钟再答,表示慎重考虑。) They say Mr. Chen is an honest, hardworking and responsible man who deeply cares for his family and friends. (他们说陈先生是位诚实、工作努力,负责任的人,他对家庭和朋友都很关心。) A:They say Mr. Chen is a friendly, sensitive, caring and determined person.(他们说陈先生是位很友好、敏感、关心他人和有决心的人。)
Q:What personality traits do you admire?(你欣赏哪种性格的人?) A: (I admire a person who is)honest, flexible and easy-going. (诚实、不死板而且容易相处的人。) A: (I like) people who possess the "can do" spirit. (有"实际行动"的人。)
Q:What leadership qualities did you develop as an administrative personnel?(作为行政人员,你有什么样的领导才能?) A:I feel that learning how to motivate people and to work together as a team will be the major goal of my leadership. (我觉得学习如何把人们的积极性调动起来,以及如何配合协同的团队精神,是我行政工作的主要目标。) A:I have refined my management style by using an open-door policy. (我以开放式的政策,改进我的行政管理方式。)
Q:How do you normally handle criticism?(你通常如何处理別人的批评?) A:Silence is golden. Just don’t say anything; otherwise the situation could become worse. I do, however, accept constructive criticism. (沈默是金。不必说什么,否则情况更糟,不过我会接受建设性的批评。) A:When we cool off, we will discuss it later. (我会等大家冷靜下来再讨论 。)
Q: What do you find frustrating in a work situation?(在工作中,什么事令你不高兴?) A: Sometimes, the narrow-minded people make me frustrated. (胸襟狭窄的人,有时使我泄气。) A:Minds that are not receptive to new ideas. (不能接受新思想的那些取。)
Q:How do you handle your conflict with your colleagues in your work? (你如何处理与同事在工作中的意见不和?) A:I will try to present my ideas in a more clear and civilized manner in order to get my points across. (我要以更清楚文明的方式,提出我的看法,使对方了解我的观点。)
Q:How do you handle your failure?(你怎样对待自己的失敗?) A: None of us was born "perfect". I am sure I will be given a second chance to correct my mistake. (我们大家生来都不是十全十美的,我相信我有第二个机会改正我的错误。)
Q:What provide you with a sense of accomplishment. (什么会让你有成就感?) A:Doing my best job for your company. (为贵公司竭力效劳。) A:Finishing a project to the best of my ability. (尽我所能,完成一个项目。)
Q:If you had a lot of money to donate, where would you donate it to?Why?(假如你有很多钱可以捐赠,你会捐给什么单位?为什么?) A:I would donate it to the medical research because I want to do something to help others. (我会捐给医药研究,因为我要为他人做点事。) A:I prefer to donate it to educational institutions. (我乐意捐给教育机构。)
Q:What is most important in your life right now?(眼下你生活中最重要的是什么?) A:To get a job in my field is most important to me. (对我来说,能在这个领域找到工作是最重要的。) A:To secure employment hopefully with your company. (希望能在贵公司任职对我说最重要。)
Q:What current issues concern you the most?(目前什么事是你最关心的?) A:The general state of our economy and the impact of China’ entry to WTO onour industry. (目前中国经济的总体情況以及中国入世对我们行业的影响。)
Q: How long would you like to stay with this company?(你会在本公司服务多久呢?) A: I will stay as long as I can continue to learn and to grow in my field.(只要我能在我的行业力继续学习和长进,我就会留在这里。)
Q:Could you project what you would like to be doing five years from now?(你能预料五年后你会做什么吗?) A:As I have some administrative experience in my last job, I may use my organizational and planning skills in the future. (我在上一个工作中积累了一些行政经验,我将来也许要运用我组织和计划上的经验 和技巧。) A:I hope to demonstrate my ability and talents in my field adequately.(我希望能充分展示我在这个行业的能力和智慧。) A:Perhaps, an opportunity at a management position would be exciting.(也许有机会,我将会从事管理工作。) 如果不愿正面回答,也可以说:It would be premature for me to predict this. (现在对此问题的预测,尚嫌过早。) 甚至还可以打趣的说:Hypothetically speaking, I might be able to do your current job as adirector.(或 CEO 或 president)((说不定,我也能做你现在主任的工作呢!)
Q: What range of pay-scale are you interested in?(你喜欢那一种薪水层次标准?) A: Money is important, but the responsibility that goes along with this job is what interests me the most. (薪水固然重要,但这工作伴随而来的责任更吸引我。) A: 假如你有家眷,可以说: To be frank and open with you, I like this job, but I have a family to support. (坦白地说,我喜欢这份工作,不过我必须要负担我的家庭。)
Other Tips (其它建议) Know something about the organization you are applying to. (了解一些你申请工作单位的情况) Dress properly. Don’t shake hand with the interviewer until he/she extendshis/her hand. (穿着要得体,人家伸手时才握手。) Don’t sit down until invited to do so by the interviewer. (人家未请,先別坐下。) Make eye-contact with the interviewer during the interview. (面试时,眼睛要看着对方。)Listen actively and stay calm. (注意听,保持冷静。) If invited to a meal, be especially careful about your table manners. (被邀吃饭时,要特別注意餐桌礼节。) Don’t talk with your mouth full. (嘴里有食物,不可开口说话) Don’t make much noise while you eat. (吃东西不要出声音) Don’t blow your nose or use the toothpick at table. (不要拧鼻涕或用牙签剔牙) Don’t appear to be pushy or overly anxious to get a job.(不必过分表现急着要工作) Be honest but not too modest.(要诚实,但不必太谦虚) Don’t put yourself down or cut yourself up. (不可妄自菲薄或自贬) Try to avoid discussing politics or religion with your interviewer. (避免 与面试人谈政治或宗教)
献个自己的清明节哀悼书 文/微尘
不管你从事什么行业的工作,千万别从事计算机软件行业的开发工作。我发誓,今生我入错行,来世我做猪做狗,不做程序员!
软件开发行业的的特点决定的开发人员痛苦的一生,有如下原因:
1、我即将设计的东西用户无法看到或者想象到 比如建筑行业吧,你要盖房子,没问题开放单位会请人设计效果图,或者画出标准图纸,包括用的钢筋、水泥、瓷砖等等所有材料都可以标上要求。 再说抽象点的广告设计,广告设计基本上可以做出过样板或者效果图,即使错了修正起来也是容易。最主要是美术东西是可以描述的。
不管从事哪个行业,你能做的东西别人大概都有个粗略的概念,但软件就没有,你做出来的东西可*作性如何,你做出来的东西美感效果如何,这都关系到双方的责任界定问题。
2、我即将设计的东西是否是客户所描述的东西 软件东西涉及到从外观表现到内在的逻辑,外观表现还好,客户说不好看,我就改一改,可要命的是有些开发工具无法实现,那就只能跳楼,比如说人家说要IE那种性感美,可你设计出来的传统美,更糟糕的是你的开发平台无法实现那种骨美,这个时候你就抱着你的软件哭吧。
逻辑的东西更不提,很多时候客户要什么都描述不清楚,或者就是描述错误。好了你的需求分析做出来,他们也签字了。可最后东西出来,经过运行测试,人家说你理解错啦!怎么办,跟他争吗?有意义吗?欲哭无泪,欲死不能!到了这个程度只能自己骂自己笨,不清楚中国话是可以进行多种理解的吗?也只能怪自己没有具备神通看出客户的内心。
以上所说的,还是正常错误,不是故意整你,如果你碰到故意整你的客户,那么不上吊都要自杀的了。
3、特别是制度化的软件犹如地狱 如果是开发什么杀毒软件啊,应用、工具软件等好办。无法就是象WINDOWS那么傻瓜式,后面的版本升级也不用花太多的精力,请几个美工或者找个论坛征求下意见,就可以:我变我变,七十二变不够可以八十一变。 可如果你是帮客户进行制度化软件的实施,特别是用产品包软件去帮客户进行制度化实施。不掉层皮也要抽点筋还不知道能否顺利结束。一般销售人员可以天花乱坠地吹或者跟客户做演示,这也是每办法的办法,谁让他们是业务员,业务人员的目标就是业绩、提成,业绩提成。而开发人员往往也是最讨厌业务人员了。因为牛是你吹的,可责任是我付的!这就好比中国教育部有句话:书记领导下校长负责制。书记可以领导,错了,该杯黑锅的时候由校长抗着!这是怎么样的天理啊!话说多了,业务人员错了有钱拿,错得越多签单越快,开发人员就死得越早。
制度化的东西是最不好弄,没有理由,没有建设性,人家就是如此的制度,你不能提建议要求该制度,完全一种强奸的感觉。就是你当孙子去!为了那几文钱!
4、人家是越老越值钱,我们是越老越贬值 除了卖色、唱、身等行业有这个特点外,看来也就开发行业有这个特点。
你年轻,你有本钱,没问题,三天不睡觉,白天睡觉晚上干活,你牛!到了你30岁,你就知道死字是如何写的了。
还有就是不知道是哪些傻瓜,天天弄出什么新技术,关键技术,你跟不跟?不跟,那么不如提前退休回家种番薯还好了。跟吧,你能跟多久,到你结婚的时候看着老婆在睡觉你却在愁眉苦脸啃那烂书;等你孩子出生了,你孩子要换尿片的时候,你能说等等我在看书呢?
5、人家要钱有钱,要面子有面子,我却灰头灰脸 各个行业都有爆发户,惟独开发人员无法爆发!为什么呢,你就靠那么点小工资能做什么?人家企业部门经理月薪都是几十K算,我们的计量单位还是元,更别说那些总经理了,看着他们的收入,我数都不会数,一个字,晕;二个字,真晕。
当你的孩子在同学中说,我爸爸是程序员,意味着怎么呢?A、那么老了还做程序员啊 B、就是编编程序的 C、顶多是个工匠(就是修理修理的那种) 。
综合上所述: A、我下定决心,排除万难,不管做什么,不做程序员! B、我请求上天,如果要让我当程序员,那么就让我去做畜生好了! C、为了我的孩子,我要发奋图强,我要翻身!
想使用Linux已经很长时间了,由于没有硬性任务一直也没有系统学习,近日由于工作需要必须使用Linux下的MySQL。本以为有Windows下使用SQL Server的经验,觉得在Linux下安装MySql应该是易如反掌的事,可在真正安装和使用MySQL时走了很多弯路,遇见很多问题,毕竟Linux 和Windows本身就有很大区别。为了让和我一样的初学者在学习的过程中少走弯路,尽快入门,写了此文,希望对您有所帮助。 二、安装Mysql 1、下载MySQL的安装文件 安装MySQL需要下面两个文件: MySQL-server-5.0.9-0.i386.rpm MySQL-client-5.0.9-0.i386.rpm 下载地址为: http://dev.mysql.com/downloads/mysql/5.0.html,打开此网页,下拉网页找到“Linux x86 RPM downloads”项,找到“Server”和“Client programs”项,下载需要的上述两个rpm文件。 2、安装MySQL rpm文件是Red Hat公司开发的软件安装包,rpm可让Linux在安装软件包时免除许多复杂的手续。该命令在安装时常用的参数是 –ivh ,其中i表示将安装指定的rmp软件包,V表示安装时的详细信息,h表示在安装期间出现“#”符号来显示目前的安装过程。这个符号将持续到安装完成后才停止。 1)安装服务器端 在有两个rmp文件的目录下运行如下命令: [root@test1 local]# rpm -ivh MySQL-server-5.0.9-0.i386.rpm 显示如下信息。 warning: MySQL-server-5.0.9-0.i386.rpm: V3 DSA signature: NOKEY, key ID 5072e1f5 Preparing... ########################################### [100%] 1:MySQL-server ########################################### [100%] 。。。。。。(省略显示) /usr/bin/mysqladmin -u root password 'new-password' /usr/bin/mysqladmin -u root -h test1 password 'new-password' 。。。。。。(省略显示) Starting mysqld daemon with databases from /var/lib/mysql 如出现如上信息,服务端安装完毕。测试是否成功可运行netstat看Mysql端口是否打开,如打开表示服务已经启动,安装成功。Mysql默认的端口是3306。 [root@test1 local]# netstat -nat Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 上面显示可以看出MySQL服务已经启动。 2)安装客户端 运行如下命令: [root@test1 local]# rpm -ivh MySQL-client-5.0.9-0.i386.rpm warning: MySQL-client-5.0.9-0.i386.rpm: V3 DSA signature: NOKEY, key ID 5072e1f5 Preparing... ########################################### [100%] 1:MySQL-client ########################################### [100%] 显示安装完毕。 用下面的命令连接mysql,测试是否成功。 三、登录MySQL 登录MySQL的命令是mysql, mysql 的使用语法如下: mysql [-u username] [-h host] [-p[password]] [dbname] username 与 password 分别是 MySQL 的用户名与密码,mysql的初始管理帐号是root,没有密码,注意:这个root用户不是Linux的系统用户。MySQL默认用户是root,由于初始没有密码,第一次进时只需键入mysql即可。 [root@test1 local]# mysql Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 to server version: 4.0.16-standard Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> 出现了“mysql>”提示符,恭喜你,安装成功! 增加了密码后的登录格式如下: mysql -u root -p Enter password: (输入密码) 其中-u后跟的是用户名,-p要求输入密码,回车后在输入密码处输入密码。 注意:这个mysql文件在/usr/bin目录下,与后面讲的启动文件/etc/init.d/mysql不是一个文件。 四、MySQL的几个重要目录 MySQL安装完成后不象SQL Server默认安装在一个目录,它的数据库文件、配置文件和命令文件分别在不同的目录,了解这些目录非常重要,尤其对于Linux的初学者,因为 Linux本身的目录结构就比较复杂,如果搞不清楚MySQL的安装目录那就无从谈起深入学习。 下面就介绍一下这几个目录。 1、数据库目录 /var/lib/mysql/ 2、配置文件 /usr/share/mysql(mysql.server命令及配置文件) 3、相关命令 /usr/bin(mysqladmin mysqldump等命令) 4、启动脚本 /etc/rc.d/init.d/(启动脚本文件mysql的目录) 五、修改登录密码 MySQL默认没有密码,安装完毕增加密码的重要性是不言而喻的。 1、命令 usr/bin/mysqladmin -u root password 'new-password' 格式:mysqladmin -u用户名 -p旧密码 password 新密码 2、例子 例1:给root加个密码123456。 键入以下命令 : [root@test1 local]# /usr/bin/mysqladmin -u root password 123456 注:因为开始时root没有密码,所以-p旧密码一项就可以省略了。 3、测试是否修改成功 1)不用密码登录 [root@test1 local]# mysql ERROR 1045: Access denied for user: 'root@localhost' (Using password: NO) 显示错误,说明密码已经修改。 2)用修改后的密码登录 [root@test1 local]# mysql -u root -p Enter password: (输入修改后的密码123456) Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 to server version: 4.0.16-standard Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> 成功! 这是通过mysqladmin命令修改口令,也可通过修改库来更改口令。 六、启动与停止 1、启动 MySQL安装完成后启动文件mysql在/etc/init.d目录下,在需要启动时运行下面命令即可。 [root@test1 init.d]# /etc/init.d/mysql start 2、停止 /usr/bin/mysqladmin -u root -p shutdown 3、自动启动 1)察看mysql是否在自动启动列表中 [root@test1 local]# /sbin/chkconfig –list 2)把MySQL添加到你系统的启动服务组里面去 [root@test1 local]# /sbin/chkconfig – add mysql 3)把MySQL从启动服务组里面删除。 [root@test1 local]# /sbin/chkconfig – del mysql 七、更改MySQL目录 MySQL默认的数据文件存储目录为/var/lib/mysql。假如要把目录移到/home/data下需要进行下面几步: 1、home目录下建立data目录 cd /home mkdir data 2、把MySQL服务进程停掉: mysqladmin -u root -p shutdown 3、把/var/lib/mysql整个目录移到/home/data mv /var/lib/mysql /home/data/ 这样就把MySQL的数据文件移动到了/home/data/mysql下 4、找到my.cnf配置文件 如果/etc/目录下没有my.cnf配置文件,请到/usr/share/mysql/下找到*.cnf文件,拷贝其中一个到/etc/并改名为my.cnf)中。命令如下: [root@test1 mysql]# cp /usr/share/mysql/my-medium.cnf /etc/my.cnf 5、编辑MySQL的配置文件/etc/my.cnf 为保证MySQL能够正常工作,需要指明mysql.sock文件的产生位置。 修改socket=/var/lib/mysql/mysql.sock一行中等号右边的值为:/home/mysql/mysql.sock 。操作如下: vi my.cnf (用vi工具编辑my.cnf文件,找到下列数据修改之) # The MySQL server [mysqld] port = 3306 #socket = /var/lib/mysql/mysql.sock(原内容,为了更稳妥用“#”注释此行) socket = /home/data/mysql/mysql.sock (加上此行) 6、修改MySQL启动脚本/etc/rc.d/init.d/mysql 最后,需要修改MySQL启动脚本/etc/rc.d/init.d/mysql,把其中datadir=/var/lib/mysql一行中,等号右边的路径改成你现在的实际存放路径:home/data/mysql。 [root@test1 etc]# vi /etc/rc.d/init.d/mysql #datadir=/var/lib/mysql (注释此行) datadir=/home/data/mysql (加上此行) 7、重新启动MySQL服务 /etc/rc.d/init.d/mysql start 或用reboot命令重启Linux 如果工作正常移动就成功了,否则对照前面的7步再检查一下。 八、MySQL的常用操作 注意:MySQL中每个命令后都要以分号;结尾。 1、显示数据库 mysql> show databases; +----------+ | Database | +----------+ | mysql | | test | +----------+ 2 rows in set (0.04 sec) Mysql刚安装完有两个数据库:mysql和test。mysql库非常重要,它里面有MySQL的系统信息,我们改密码和新增用户,实际上就是用这个库中的相关表进行操作。 2、显示数据库中的表 mysql> use mysql; (打开库,对每个库进行操作就要打开此库,类似于foxpro ) Database changed mysql> show tables; +-----------------+ | Tables_in_mysql | +-----------------+ | columns_priv | | db | | func | | host | | tables_priv | | user | +-----------------+ 6 rows in set (0.01 sec) 3、显示数据表的结构: describe 表名; 4、显示表中的记录: select * from 表名; 例如:显示mysql库中user表中的纪录。所有能对MySQL用户操作的用户都在此表中。 Select * from user; 5、建库: create database 库名; 例如:创建一个名字位aaa的库 mysql> create databases aaa; 6、建表: use 库名; create table 表名 (字段设定列表); 例如:在刚创建的aaa库中建立表name,表中有id(序号,自动增长),xm(姓名),xb(性别),csny(出身年月)四个字段 use aaa; mysql> create table name (id int(3) auto_increment not null primary key, xm char(8),xb char(2),csny date); 可以用describe命令察看刚建立的表结构。 mysql> describe name; +-------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+----------------+ | id | int(3) | | PRI | NULL | auto_increment | | xm | char(8) | YES | | NULL | | | xb | char(2) | YES | | NULL | | | csny | date | YES | | NULL | | +-------+---------+------+-----+---------+----------------+ 7、增加记录 例如:增加几条相关纪录。 mysql> insert into name values('','张三','男','1971-10-01'); mysql> insert into name values('','白云','女','1972-05-20'); 可用select命令来验证结果。 mysql> select * from name; +----+------+------+------------+ | id | xm | xb | csny | +----+------+------+------------+ | 1 | 张三 | 男 | 1971-10-01 | | 2 | 白云 | 女 | 1972-05-20 | +----+------+------+------------+ 8、修改纪录 例如:将张三的出生年月改为1971-01-10 mysql> update name set csny='1971-01-10' where xm='张三'; 9、删除纪录 例如:删除张三的纪录。 mysql> delete from name where xm='张三'; 10、删库和删表 drop database 库名; drop table 表名; 九、增加MySQL用户 格式:grant select on 数据库.* to 用户名@登录主机 identified by "密码" 例1、增加一个用户user_1密码为123,让他可以在任何主机上登录,并对所有数据库有查询、插入、修改、删除的权限。首先用以root用户连入MySQL,然后键入以下命令: mysql> grant select,insert,update,delete on *.* to user_1@"%" Identified by "123"; 例1增加的用户是十分危险的,如果知道了user_1的密码,那么他就可以在网上的任何一台电脑上登录你的MySQL数据库并对你的数据为所欲为了,解决办法见例2。 例2、增加一个用户user_2密码为123,让此用户只可以在localhost上登录,并可以对数据库aaa进行查询、插入、修改、删除的操作(localhost指本地主机,即MySQL数据库所在的那台主机),这样用户即使用知道user_2的密码,他也无法从网上直接访问数据库,只能通过 MYSQL主机来操作aaa库。 mysql>grant select,insert,update,delete on aaa.* to user_2@localhost identified by "123"; 用新增的用户如果登录不了MySQL,在登录时用如下命令: mysql -u user_1 -p -h 192.168.113.50 (-h后跟的是要登录主机的ip地址) 十、备份与恢复 1、备份 例如:将上例创建的aaa库备份到文件back_aaa中 [root@test1 root]# cd /home/data/mysql (进入到库目录,本例库已由val/lib/mysql转到/home/data/mysql,见上述第七部分内容) [root@test1 mysql]# mysqldump -u root -p --opt aaa > back_aaa 2、恢复 [root@test mysql]# mysql -u root -p ccc < back_aaa
1)首先查找以前是否安装MySQL 3.23.54?
命令:rpm -qa | grep mysql
可以看到两个MySQL包:mysql-server、mysql-devel-3.23.54a-11。
2)删除命令:
rpm -e --nodeps 包名
3)然后删除mysql老版本的开发头文件和库
rm -fr /usr/lib/mysql
rm -fr /usr/include/mysql
之后可以正常安装了。
如果 MySQL 正在运行,首先杀之: killall -TERM mysqld。 启动 MySQL :/usr/bin/safe_mysqld --skip-grant-tables & 就可以不需要密码就进入 MySQL 了。
然后就是 >use mysql >update user set password=password("new_pass") where user="root"; >flush privileges; 重新杀 MySQL ,用正常方法启动 MySQL 。
对于所有 Web 应用程序来说,安全是非常重要的。一个安全问题是当变量超出会话范围时您可能需要考虑限制用户访问 Web 应用程序的特殊页面。出现这个问题时,您可能想要求用户再次登录,然后才能继续。
|
本技巧适用于以下技术和资源
NetBeans IDE 6.0、5.5.1 和 5.5
|
|
JavaServer Faces Components/ Java EE Platform
|
1.2 with Java EE 5* 1.1 with J2EE 1.4
|
Travel Database
|
不需要
|
BluePrints AJAX Component Library
|
不需要
|
* 到发布本文时止,Sun Java System Application Server 只支持 Java EE 5。
现在,本文中的技巧已适用于 Sun Java Application Server PE 9.0 Update Release 1 和 Tomcat 5.5.17。如果您使用其他服务器,请查看发行说明和 FAQ 了解已知问题和解决办法。有关所支持服务器和 Java EE 平台的详细信息,请参阅发行说明。
概述
本技巧介绍当会话超时或达到空值时您如何将该用户重定向到另一个页面。在这种情况下,您希望在加载页面时执行重定向。但是使用超级链接不起作用,按钮动作处理器方法的标准代码也不起作用。
处理该情况的最可靠方法是使用 Servlet Filter。而且使用 Servlet Filter 还非常高效,因为一旦设置了此过滤器,您便可以在项目中的任何页面或组件中使用。同时您还可以为按钮动作处理器方法编写自定义代码,后一种方法不如前面的方法可靠,原因是该方法取决于 web.xml 文件中的设置。修改后的动作处理器代码还必须包含于您要测试会话是否超时的所有页面上。尽管本技巧介绍如何修改按钮动作处理器,但建议您尽可能使用 Servlet Filter 方法。
无论您选择哪种方法,要使代码正常工作,您还需要在 web.xml 文件中设置一个会话超时值;例如,将会话超时值设置为 1 分钟:
<session-config>
<session-timeout>1</session-timeout>
</session-config>
创建一个具有两页的项目
您可以自己轻松创建此示例。在您的可视 Web 应用程序中设置两个页面:页面1 具有一个按钮和一个显示会话超时消息的 ErrorPage。如果用户在达到 web.xml 文件中设置的超时值之前,单击页面 1 上的按钮,则不会发生任何事情(因为会话尚未超时)。但是,如果已经达到了超时值,即表示该会话已经超时,则该按钮会将用户带到 ErrorPage。
请记住,当会话超时时查看重定向是否正常工作,您必须等待超过您在 web.xml 文件中设置的超时值之后才能单击该按钮。
使用 Servlet Filter
当会话超时时重定向用户的最佳方法是使用 Servlet Filter。使用该方法,您不需要对按钮动作处理器的代码进行任何修改。
常规步骤如下:
l 使用 GUI 创建一个 Filter 类并将它的过滤器映射设置为 Servlet 和 Faces Servlet。
l 将 Servlet Filter 类中的代码替换为自定义代码。
l 部署项目。
下面是完成此操作的方法。
1. 首先,创建 Filter 类。在 NetBeans 6.0 中,右键单击该项目,然后单击 New -> Other 打开 File Type 对话框。(在 NetBeans 5.5 或 5.5.1 中,右键单击该项目,然后单击 New->File/Folder 可打开该对话框。)然后在该对话框屏幕的 Categories 列(如果它尚未高亮显示)中选择 Web,在 Files Type 列中选择 Filter。单击 Next。
2. 将显示 New Filter 对话框。在 Class Name 中输入 SessionCheckFilter,然后单击 Next。(您可以为此过滤器使用任何名称。)
3. 在 Configure Filter Deployment 对话框中,在 Filter Mappings 框(如果尚未高亮显示)中选择 SessionCheckFilter,然后单击 Edit。
|
图 1. Configure Filter Deployment 对话框 (单击可放大图像)
|
4. 在 Filter Mapping 对话框中,选中 Servlet 并确保它设置为 Faces Servlet。然后单击 Finish。
5. 现在,在源编辑器中打开 SessionCheckFilter 类,然后用以下代码替换整个类。
代码示例 1:用于重定向的 SessionCheckFilter 代码
|
public class SessionCheckFilter implements Filter {
private static int firstRequest = 0;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest hreq = (HttpServletRequest)request;
HttpServletResponse hres = (HttpServletResponse)response; HttpSession session = hreq.getSession();
if (session.isNew()) {
if(firstRequest == 0){
firstRequest++;
} else {
hres.sendRedirect("faces/ErrorPage.jsp");
return;
}
}
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {} public void destroy() {}
}
|
Servlet Filter 采用 doFilter 方法进行它的所有处理。它获得对会话的参考并测试会话是否是新的会话或者用户是否仍然在上一个会话中。如果是新的会话,则代码会增加变量 firstRequest ,它表示这不再是新的会话。但是,如果用户仍然位于相同的会话中并且该会话已经超时,则 Servlet Filter 会将该用户重定向到一个设置为处理超时问题的页面。在本例中,为 faces/ErrorPage.jsp 。
现在,您可以部署和运行该项目了。当您等待超过超时值(在本例中,为 1 分钟)之后单击主页面上的按钮时,过滤器会将您重定向到错误页面。无论您以前单击该按钮多少次,都会发生该重定向。还请注意,Servlet Filter 适用于任何页面和任何组件。您不需要为页面上的组件编写任何特殊的代码。
修改按钮动作处理器方法
您也可以为按钮动作处理器方法编写一些自定义的代码以在会话到期时将用户重定向到另一个页面。
除了设置超时值之外,要使该方法正常工作,还要确保将 web.xml 文件中的 javax.faces.STATE_SAVING_METHOD 参数设置为 client 。如果设置为 server ,则按钮动作方法将永远也不会被调用,无论超时值的设置如何都是如此。要验证和更改此参数的设置,请展开 web.xml 文件的 Context Parameters 部分。如果 javax.faces.STATE_SAVING_METHOD 的值设置为 server ,请使用 Edit 按钮将属性值更改为 client 。
|
图 3:设置 javax.faces.STATE_SAVING_METHOD 参数
|
所有关键代码都位于按钮动作处理器方法中。在 Java 源编辑器中打开 Page1 按钮动作处理器方法,并向该方法中添加以下代码。输入该代码之后,请使用 Fix Imports 函数导入该代码使用的类。
代码示例 2:用于会话超时重定向的按钮动作处理器
|
public String button1_action() {
ExternalContext externalContext = getFacesContext().getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
HttpSession session = request.getSession();
if (session.isNew()) {
try {
String errorPageURL = externalContext.getRequestContextPath() +
"/faces/ErrorPage.jsp";
externalContext.redirect(errorPageURL);
} catch(IOException ioe) {
System.out.println("==============");
ioe.printStackTrace(System.out);
System.out.println(ioe.toString());
System.out.println("==============");
}
} else {
System.out.println("==============");
System.out.println("*** Session is not New ***");
System.out.println("==============");
}
return null;
}
|
该动作处理器方法的关键部分位于开始部分。前三个方法为:
ExternalContext externalContext = getFacesContext().getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
HttpSession session = request.getSession();
为您提供一个该会话本身的处理器。
接下来,您检查该会话是否是新会话,或者是否用户仍然处于相同(上一个)会话中。如果是新会话,则执行 try 块中的代码;否则,用户仍然处于相同会话中,并且动作处理器方法返回。try 块中的重定向代码如下:
if (session.isNew()) {
try {
String errorPageURL = externalContext.getRequestContextPath() +
"/faces/ErrorPage.jsp";
externalContext.redirect(errorPageURL);
上面的代码建立了到您要重定向到的页面的路径,在本例中为错误页面 ErrorPage.jsp 。路径为 Web 应用程序上下文和重定向到的页面名称的组合。代码使用 ExternalContext.getRequestContextPath 方法返回请求 URI 的一部分,该部分标识请求的 Web 应用程序上下文,并且还向此上下文中附加重定向页面的名称 (/faces/ErrorPage.jsp )。
然后,调用 ExternalContext .redirect 方法,将它的绝对 URL 路径传递给重定向页面。redirect 方法将客户端请求重定向到指定的 URL。它还在当前请求的 FacesContext 实例上调用 responseComplete 方法。
小结
尽管两种方法都可以正常工作,但很容易看出使用 Servlet Filter 是处理会话超时时重定向问题的最简单方法。您不仅可以使用 IDE 对话框创建 Servlet Filter,使所需要添加的代码非常简单。而且使用 Servlet Filter 还不需要在要检查会话是否超时的每个页面上(或者包括在多个组件动作处理器中)重定向逻辑。
本教程介绍如何在 10 分钟之内创建一个博客。本教程运行支持 Ruby 的 NetBeans IDE 6.0 (M10)。
内容
教程要求
本教程需要以下软件:
l Java Standard Development Kit (JDK) version 6.0
l 支持 Ruby 的 NetBeans IDE 6.0 (M10)
设置
l 将 derbyclient.jar (jdk1.6.0_home/db/lib/derbyclient.jar ) 复制到您的 jruby lib 目录 (NetBeans_install_dir/ruby1/jruby-1.0/lib )。
创建 Ruby on Rails 项目
1. 在 NetBeans IDE 中,选择 File > New Project。
2. 在 Categories 字段中选择 Ruby,在 Projects 字段中选择 Ruby on Rails Application,然后单击 Next。
3. 在 Project Name 字段中键入 RubyWebLog ,然后单击 Finish。
4. 浏览 Projects 窗口。如下图所示,Projects 窗口按类别对项目进行分组。展开每个节点可查看每个类别中的类型。
配置数据库
1. 在 Projects 窗口中,展开 Configuration 节点。
2. 打开 database.yml 。
3. 在 database.yml 中,删除 development: 下的默认数据库配置并替换为以下配置:
代码示例 1:在 database.yml 中开发数据库配置
|
adapter: jdbc
driver: org.apache.derby.jdbc.ClientDriver
url: jdbc:derby://localhost:1527/sample
username: app
password: app
|
4. 确保您使用代码示例 1 中所示的正确格式。如果使用制表符,则可能会在迁移数据库时遇到错误。
5.打开 environment.rb 并在内容为 Rails::Initializer.run do |config| 的行上面插入以下代码:
代码示例 2:Ruby 代码
|
if RUBY_PLATFORM =~ /java/
require 'rubygems'
RAILS_CONNECTION_ADAPTERS = %w(jdbc)
end
|
6.打开 Services 窗口,展开 Databases 节点,并检查示例 {app on APP} 数据库是否已连接。
如果示例数据库标记的 jdbc 节点已中断,则 IDE 未连接到数据库。要连接到示例数据库,请右键单击示例数据库的 jdbc 节点,然后从弹出菜单中选择 Connect。如果出现 Connect 对话框,则对 Password 输入 app ,选择 Remember Password During This Session,然后单击 OK。
创建模型
在本部分中,您使用 Rails 生成器创建一个迁移。迁移是一种使用版本跟踪数据库更改的方式。
1. 切换回 Projects 窗口,右键单击 Model 节点,然后选择 Generate。
2. 在 Rails Generator 对话框中,在 Arguments 字段中键入 Post ,然后单击 OK。
作为模型生成的一部分,为您创建了一个迁移 001_create_posts.rb :
3. 展开 Database Migrations > migrate 节点并打开 001_create_posts.rb 。
4. 如下图所示,向 up 方法中添加标题列(以粗体显示) :
代码示例 3:001_create_posts.rb 的代码
|
class CreatePosts < ActiveRecord::Migration
def self.up
create_table :posts do |t|
t.column "title", :string
end
end
def self.down
drop_table :posts
end
end
|
5.当运行数据库迁移时执行 self.up 方法。当停止数据库时运行 self.down 方法。self.down 方法将数据库回滚到以前的版本。
6.在 Projects 窗口中,右键单击 RubyWebLog 节点,然后选择 Migrate Database > To Current Version。
该操作运行数据库迁移。输出窗口表示迁移 CreatePosts 的时间。下面是某些常见错误的纠正方法:
o org.jvyamlb.ScannerException: ScannerException null, mapping values are not allowed here . 表示 database.yml 文件的格式有问题。请检查是否使用了制表符进行缩进。
o The driver encountered an error: cannot load Java class org.apache.derby.jdbc.ClientDriver . 请验证是否如设置中所述复制了 derbyclient.jar 文件。
7.切换到 Services 窗口,展开 jdbc > Tables 节点查看生成的 posts 表以及关联的 schema_info 表。
如果没有看到新的条目,请右键单击 Tables 节点,然后选择 Refresh。
使用 Scaffold
在本部分中,使用 Ruby on Rails scaffold 功能。Scaffold 提供创建、编辑、查看和破坏博客中条目的基本界面。
1. 切换回 Projects 窗口,右键单击 Controllers 节点,然后选择 Generate。
2. 在 Rails Generator 对话框中,在 Name 字段中键入 Blog 。将 Views 字段保留为空。单击 OK。
3. 向 blog_controller.rb 中添加以下代码,该代码提供围绕该模型的一个简单的 CRUD 应用程序:
代码示例 4:blog_controller.rb 的代码
|
class BlogController < ApplicationController
scaffold :post
end
|
4. 在 Configuration 节点下,打开 routes.rb 并在最后一个 end 语句之前添加以下代码:
map.connect '', :controller => "blog"
5. 展开 Public 节点并删除 index.html 。
现在,当运行该应用程序时便会自动加载该博客。
6. 单击工具栏中的 Run Main Project 按钮启动 WEBrick 服务器并启动浏览器。
下面是该应用程序的第一个页面。
7. 单击 New post。
8. 输入一个标题,然后单击 Create。
下面是博客列表的示例。
迁移 Forward
在这里,您通过添加其他迁移(向编辑页面中添加正文)来更改数据模型。
1. 右键单击 Database Migrations 节点,然后选择 Generate。在 Rails Generator 对话框中,在 Arguments 字段中键入 AddBody ,然后单击 OK。
Ruby 便创建了一个名为 002_add_body.rb 的版本迁移脚本。
2. 按照如下方式修改 002_add_body.rb :
代码示例 5:002_add_body.rb 的代码
|
class AddBody < ActiveRecord::Migration
def self.up
add_column 'posts', 'body', :text
end
def self.down
remove_column 'posts', :body
end
end
|
3. 右键单击 RubyWebLog 节点,然后选择 Migrate Database > To Current Version。
4. 返回到浏览器并单击 Edit 链接查看 Ruby 如何识别新的正文字段。
5. 单击 Back 返回到 Listing Posts 页面,并创建更多博客条目。例如:
使列表看起来更像博客
到目前位置,scaffold 已经创建了一个基本的 CRUD 应用程序,使用该应用程序可以轻松测试该模式。这里您生成 scaffold,将其作为修改用户界面的基础。
1. 在 Projects 窗口中,右键单击 Views 节点,然后选择 Generate。
2. 在 Rails Generator 对话框中,从 Generate 下拉列表中选择 scaffold。
3. 在 Model Name 字段中键入 Post ,在 Controller Name 字段中键入 Blog 。保留 Actions 字段为空。单击 OK。
4. 展开 Views > blog 并打开 list.rhtml 。删除 <h1> 和 <table> 标记并将其替换为以下代码:
代码示例 6:list.rhtml 的代码
|
<h1>The Ruby Blog</h1>
<% @posts.each do |post| %>
<h2><%= post.title %></h2>
<p><%= post.body %></p>
<small> <%= link_to 'Permalink', :action => 'show', :id => post %></small>
<hr>
<% end %>
|
5. 保存 list.rhtml 并刷新您的浏览器。
6. 要首先用最新的条目显示博客,请通过向 @posts in list.rhtml 的结尾添加 .reverse 颠倒排序顺序:
<% @posts.reverse.each do |post| %>
当保存该文件并刷新您的浏览器时,该博客显示如下:
1. Map的遍历
有人看了这个标题可能发笑,因为这实在太简单,难道我在凑字数?可是根据我自己的经验来说,人的岁数长的时候记忆力却不跟着长,倒有不进反退的现象。我就是虽然写过很多遍但仍然用到的时候就忘个干净,在这里写一下强化记忆J
SortedMap pDataMap = new TreeMap();
Iterator itor = pDataMap.entrySet().iterator();
while(itor.hasNext()){
Map.Entry vEntry = (Entry) itor.next();
vEntry.getKey();
vEntry.getValue();
//做一些其他的事……
}
2. 文件操作
本文主要关注简单的对象序列化的相关操作,对于更为详细的操作过程,请参照《Java编程思想 2e》。
2.1.文件过滤器
文件过滤器主要用在FileChooser或者File.listFiles()方法中,用于过滤掉一些与本程序无关的类型文件。本例给出一个察看给定文件后缀名的文件过滤器,对于给定的文件察看其文件名,如果和给定的后缀名一致则返回true,否则返回false。
publicclass RecorderFileFilter implements FilenameFilter
{
/**后缀名 **/
String postfixStr;
public RecorderFileFilter(String postfix){
this.postfixStr = postfix;
}
publicboolean accept(File dir, String name) {
/**只判断后文件的缀名是否正确即可 **/
if( name.endsWith(postfixStr) )
returntrue;
else
returnfalse;
}
}
2.2.对象的保存与读取
首先介绍一下我的程序的存储结构:我的数据保存在两种类型的文件中,即“时间字符串.data”和“时间字符串.plan”两种类型。其中.data文件是一个HashMap<String,String>类的序列化文件,而.plan文件是一个SortedMap<String,String>类的序列化文件。他们都保存在“user.dir/data”目录下。下面的这些方法的功能是读取/保存这个目录下数据文件,如果你想保存你自定义的文件到指定目录,下面的代码至需要稍微修改一下即可使用:
/**用以标识读入数据的类型,也是文件后缀名**/
publicstaticfinal String DATA_TYPE = ".data";
publicstaticfinal String PLAN_TYPE = ".plan";
/**以程序运行目录作为基目录**/
publicstatic File appDir = new File(System.getProperty("user.dir"));
publicstatic File imgDir = new File(appDir,"img");
publicstatic File dataDir = new File(appDir,"data");
publicstatic File reportDir = new File(appDir,"report");
publicstatic FileInputStream fIn;
publicstatic FileOutputStream fOut;
publicstatic ObjectInputStream objIn;
publicstatic ObjectOutputStream objOut;
/**---------------功能函数部分----------------------**/
/**
*查找并读入"user.home/data/"目录下所有的记录文件,将其放到一个Map中
*HashMap的Key为文件名,也是欠款人帐户的ID号。
*关于获得的文件的具体信息请参照技术说明书。
*如果pType=DATA_TYPE,则dataMap的格式为<String,HashMap>
* pType=PLAN_TYPE,则dataMap的格式为<String,SortedMap>
*@returnSortedMap
*/
publicstatic HashMap loadAll(String pType){
/** 数据文件名(简历账号的时间)即为ID **/
HashMap vDataMap = new HashMap();
/**后缀名为data的即为数据文件**/
File[] dataFiles = dataDir.listFiles(new RecorderFileFilter(pType));
for(int i = 0; i < dataFiles.length; i++){
try{
if( pType.equals(FileUtil.DATA_TYPE) ){
HashMap<String,String> hMap = (HashMap<String,String>)loadObjectFromFile(dataFiles[i]);
/**去掉文件名的后缀名即或得key,也就是欠款帐户ID**/
vDataMap.put(hMap.get("id"),hMap);
}elseif( pType.equals(FileUtil.PLAN_TYPE) ){
SortedMap<String,SortedMap> hMap = (SortedMap<String,SortedMap>)loadObjectFromFile(dataFiles[i]);
/**去掉文件名的后缀名即或得key,也就是欠款帐户ID**/
vDataMap.put(StringUtil.clearFileName(dataFiles[i]) ,hMap);
}else
thrownew Exception("读取了错误的文件类型");
}
catch(Exception ex) {
MessageUtil.showErrMsg("读取数据时出现错误,数据有可能丢失!"+
"\n 文件名为:"+dataFiles[i].getName());
}
}
return vDataMap;
}
/**
*将给定内容存入文件中.
*@parampContentMapMap其所装内容为<id(String), HashMap或SortedMap>
*/
publicstaticvoid saveAll(HashMap<String,String> pDataMap,SortedMap<String,String> pPlanMap){
Iterator itor = pDataMap.entrySet().iterator();
while(itor.hasNext()){
Map.Entry vEntry = (Entry) itor.next();
String id = (String) vEntry.getKey();
saveToFile(id,pDataMap,pPlanMap);
}
}
/**
*将制定欠款账户的信息存入文件中
*@paramidString 这个信息在保存欠款协议时不可或缺
*@parampDataMapSortedMap
*@parampPlanMapSortedMap
*/
publicstaticvoid saveToFile(String id, HashMap<String,String> pDataMap,
SortedMap<String,String> pPlanMap){
try{
if( pDataMap != null )
saveObjectToFile(new File(dataDir,id+DATA_TYPE), pDataMap);
if( pPlanMap != null )
saveObjectToFile(new File(dataDir,id+PLAN_TYPE), pPlanMap);
}
catch(Exception ex) {
MessageUtil.showErrMsg("保存数据时出现错误,数据没有被正确保存!");
}
}
/**
*将文件中的序列化对象读出来
*@parampFileFile
*@returnObject
*@throwsException
*/
publicstatic Object loadObjectFromFile(File pFile) throws Exception {
fIn = new FileInputStream(pFile);
objIn = new ObjectInputStream(fIn);
Object obj = objIn.readObject();
fIn.close();
objIn.close();
return obj;
}
/**
*将对象序列化到相应的文件中去--保存数据时候专用,因为该函数将数据保存在appDir/data目录下
*@parampFileNameString
*@paramobjObject
*@throwsException
*/
publicstaticvoid saveObjectToFile(File pFile,Object pObj) throws Exception
{
fOut = new FileOutputStream(pFile);
objOut = new ObjectOutputStream(fOut);
objOut.writeObject(pObj);
fOut.close();
objOut.close();
}
2.3.其他
由于每个程序都有图标文件,所以从制定目录读入图标应该是每个程序都会用到的。其次,删除指定目录下的指定类型文件似乎也很常用J
/**从img文件夹中获取图标**/
publicstatic ImageIcon getImageIcon(String pImageFileName){
File imgFile = new File(imgDir,pImageFileName);
ImageIcon imageIcon = new ImageIcon(imgFile.getAbsolutePath());
return imageIcon;
}
/**清除reportDir目录下所有html文件**/
publicstaticvoid clearReportFiles(){
File vReportDir = new File(reportDir.getAbsolutePath());
File[] vReportFiles = vReportDir.listFiles(new FilenameFilter(){
publicboolean accept(File dir, String name){
if( name.endsWith("html"))
returntrue;
returnfalse;
}
});
for(int i = 0; i < vReportFiles.length; i++)
vReportFiles[i].delete();
}
7月26日,网游运营商完美时空(Nasdaq:PWRD)在纳斯达克市场挂牌交易,上市首日便大涨27.5%。
此时风光无限的完美时空,却在一个多月前遭遇了一场令人哭笑不得的推销。
完美时空当时发表的声明称,“中国网络史上最大规模的黑客DDOS攻击在6月11日凌晨上演”,并称公司因此遭受了数百万元的经济损失。
完美时空随即向北京市海淀区警方报案,后经调查,该起黑客攻击的目的竟然是为了推销某公司生产的防火墙产品。
先黑网站再卖设备
7月25日,海淀区警方宣布,破获了一起以DDOS手段实施的黑客攻击案,这次攻击给联众、完美时空等几家网络游戏公司造成了近千万元的经济损失。而有关人员发起攻击的目的很简单,就是为了推销上海遐迩网络科技(发展)有限公司(下称遐迩网络)生产的抗DDOS防火墙。
时间回溯到6月10日,完美时空公司技术部工作人员突然发现大量攻击数据从网上涌来,开始攻击公司网站。到6月11日下午,攻击流量总计超过了100G,这已经大大超过了完美时空租赁的带宽。
随后,由于数据包过于庞大,完美时空公司网站和旗下4款大型网络游戏全部数据完全被阻断,网络充值系统也被迫关闭。
接到完美时空公司报案的海淀警方在一个多月前已经接到过类似的报警。据了解,自4月23日开始,联众在北京等地的服务器遭遇猛烈攻击,众多玩家无法进入游戏,在联众公司采取补救措施的时候,攻击却越来越猛。但是几天后,攻击便自行停止了。
颇为蹊跷的是,在攻击结束后的数日内,联众技术部的人员就接到了推销电话,自称来自遐迩网络公司的销售人员称,如果采用该公司的设备,就可以很好地抵御这种DDOS攻击。
抱着试试看的心态,联众租用了该公司的相关设备。在采用该公司的防火墙产品后,果然针对联众的攻击随之大幅度下降。由于遐迩网络公司的一套防火墙需要近百万元,燃眉之急稍解的联众决定停用该公司的防火墙产品。但是让联众没有想到的是,第二天,网络攻击又再次大规模爆发,联众在上海、北京等地的数个服务器先后被攻击瘫痪。
“没想到一停用就再次遭受大规模攻击。”联众总裁伍国樑相当气愤地告诉记者,在这种情况下,联众无奈向海淀区警方报案。
6月14日,海淀警方抓获了上海遐迩网络公司的4名工作人员,目前,这4人因涉嫌破坏计算机信息系统,已被海淀区检察院批准逮捕。
海淀警方公布的消息显示,这4名工作人员交代了自己利用黑客手段向多家网络游戏公司发动网络攻击,以便通过攻击来销售自己公司防火墙设备的事实。
海淀警方还称,除了联众和完美时空之外,上述人员此前还攻击过2家网络游戏公司,并成功的销售了自己的防火墙设备。
商业黑客泛滥
公开资料显示,遐迩网络公司成立于2004年5月,是一家致力于网络安全产品研发的专业机构,公司研发的抗拒绝服务系统已经通过多个机构的认证,并已申请国家专利,在业内颇有名气。
7月27日,记者来到遐迩网络公司所在的上海浦东新区张杨路上一个不太起眼的小区里。门口并没有醒目的公司标记,办公室看起来也不显眼。“这已经是6月份的事情了,我们不想再谈。”遐迩网络公司有关人士拒绝了记者的采访要求。
上述遐迩网络公司4名销售人员的这种“先攻击、再销售”的黑客式销售模式,在外界看来确实匪夷所思。但据记者了解,在IT行业,类似的事件并不鲜见。
自2007年1月24日起,杭州天畅科技的游戏网站和《大唐风云》、《大唐》等游戏的服务器,均出现较为严重的不稳定状况,导致网站和游戏服务器无法登陆。
杭州天畅科技的调查显示,大量不明来历的数据包每天对网站和游戏服务器发起攻击,堵塞了网络,造成断网现象。
“我们也经常遭遇到各种黑客的DDOS攻击,很难查。”征途网络董事长史玉柱也向记者抱怨。在这种情况下,征途网络不得不采用各种防火墙设备来防止类似的攻击。
据记者了解,DDOS攻击也被称为拒绝服务攻击,该攻击可以利用网络通讯协议本身固有的缺陷,通过伪造超过服务器处理能力的请求数据,造成服务器响应阻塞,从而使正常的用户请求得不到应答,以实现其攻击目的。
正是基于这种攻击的隐蔽性及其所带来的巨大危害,DDOS攻击很多时候都被利用来攻击对手。“市场上有很多高手专门给一些公司做这种攻击行为。”上海一家网络安全设备公司的负责人告诉记者,“整个网络上这种攻击是很泛滥的,一些是发自网络安全公司;一些发自竞争对手。”
而很多中小企业由于没有专业的防范力量,在遭受攻击时一般都会采用“及时”推销上门的防火墙设备。
“一般来说,生产这种防火墙的公司都会先试着攻击对方的网站,找出技术漏洞,然后提醒客户购买产品,但是并不会损害客户的网站,这在行业里面已经不是什么秘密。”上述网络安全设备公司负责人告诉记者。不过,他坦承,像完美时空、联众等这种遭到明显敲诈的行为,在业内还不算多。
DDOS攻击罪责悬念
国家计算机网络应急技术处理协调中心的一份研究报告也显示,黑客攻击目前已经形成了一条隐蔽的产业链,目前在我国网络安全黑色产业链产值已超过2.38亿元,造成的损失则超过76亿元,已经形成了不可忽视的地下经济力量。
“还是必须加大处罚力度。”一直从事数据安全业务的GDS万国数据公司总裁黄伟认为。据了解,目前中国的互联网立法情况要落后现实许多,《计算机信息网络国际联网安全保护管理办法》中规定制造和传播病毒是违法的,但是对于木马、黑客程序、DDOS攻击等并没有清晰的界定。
有业内人士认为,这种DDOS网络攻击犯罪有两个明显不同于传统犯罪的特色:其一是犯罪现场的不确定性,带来了电子证据的法律效力及有关损失的评估难题;其二是立法执法跟不上形势,很难了解犯罪行为造成的破坏价值。
实际上,这种攻击行为不只是影响到像完美时空这样的企业,如果这种攻击被用于攻击基础网络时,带来的损失就更加不可估量了。
有关人士认为,目前,国内的相关信息安全立法还比较滞后,而且缺乏完整性、严密性和足够的震慑力。
“必须用法律和技术相结合的手段来应对网络黑客的攻击,在增强行业自律和用户自我保护意识的同时,必须增强网络安全产业的服务链。”黄伟强调。
摘要: 1. 日期部分
对于像日期、时间和钱这样的对象来说,不同的国家、地区都有不同的显示格式。即便是同一地区,也可能存在差异。但是在不考虑国家化,时间格式相对固定的情形下,对于时间的处理还是相对比较简单的。在我最近所作的一个小程序里面,遇到了一些与日期有关的且不考虑国际化和复杂格式的问题。例如如何求两个日期所差的天数,所差的月数;将日期类转化为规定格式的字符串,将规定格式的日期... 阅读全文
NEC周三(7/25)表示完成一项既可保有与现存JPEG压缩规格相同压缩率,又能大幅加速JPEG图文件压缩速度的无损压缩(lossless compression)技术。
一般的JPEG格式仅对应8bit色阶,因此在医疗、卫星航空、科学研究等领域常因此丧失图像精准度,对于这些特殊领域来说,若要使用现有不失真的图像压缩技术,则装置所需的演算处理能力势必要提高,结果将导致庞大的图像数量往往需要以天为单位进行转文件,而且也无法应用在例如数字相机等低电力的轻便装置中。
新技术的压缩图片与现有的JPEG-LS、JPEG2000压缩率相当,最大支持色阶却有16bit,压缩速率是JPEG-LS的10倍以上、JPEG2000的30倍以上;同时对应从图像中低分辨率的部份依序进行压缩/解压缩的图像显示方式,让使用者能和使用JPEG档案一样,在图像档案尚未全部接收完成前即可看见概略图像。
NEC已在7/23于西班牙巴塞隆纳举行的IGARSS 2007会议中发表此技术,而研究成果已经被日本宇宙航空研究机构(JAXA)预定采用于2010年后的金星探测计划
前言
本文前言部分为我的一些感想,如果你只对本文介绍的Java实用技巧感兴趣,可以跳过前言直接看正文的内容。
本文的写作动机来源于最近接给人家帮忙写的一个小程序,主要用于管理分期付款的货款的一系列管理,包括过期款的纪录,过期款利息的计算,为提前付款的用户提供一些返款奖励等等,这些与本文无关自不必细说。为了尽快完成任务,我自然选择了我用得最多的Java来实现。经过2周的劳动,顺利完成了任务,明天就可以去交差,但是这一刻我却忽然有些其他的想法。诚然这样的活原本属于体力劳动,类似的活我也做过不止一次,对于很多高人来说,没什么值得一提的,以前我也只是交差收钱了事,但这一次我却多了一些想法,使我不吐不快。
在程序的实现过程中,我遇到了个小问题,就是计算两个日期的差。由于以前常用的Date类的大多数方法都被标记为“deprecate”,所以我决定用Calender作为计算日期的主力。但是大多数参考书上都是由关于Calender的日期格式,Locale的设置,常量的含义等方面的讲解,却怎么也找不到这样一个简单却常用的任务怎么实现(注:这也不能怪我懒惰,作为这样一个程序来说,如果有正确且成熟的方法,谁还会去花大量时间仔细研究API呢?反正这个类可能在今后的几个月甚至几年都用不上,现在记住到时候也都忘了L)。于是在我google了好一阵之后,终于在某人的Blog上找到了用Calender计算日期差的方法。在那一刻我真有久旱逢甘雨之感。博主可能是一时兴起,也有可能是兴趣所在,但无论是什么原因,他的工作都为我提供了很大的方便。有了他的代码示例,我可以不再去逐个查找Java-Doc里面的API,然后挑出几个来尝试解决问题,最后再写个demo验证这一繁复的过程了。
再回想一下我完成这个程序的过程,由于以前做过一些类似的程序,我可以将里面的很多部分以直接应用到这个程序中,节省了大量的时间,让我可以更专注于核心业务的实现当中。然而或许是出于懒惰,或许是没有时间,又或许原来的是Blog没有多少人关注,我都没有将这些大多数人都可能会用得上的东西放到网上。
再联想一下国外开源工作者对中国程序员的评价—“只获取,不贡献”,就觉得人家说得十分对。自己就用着免费的J2SDK语言,免费的Eclipse,免费的JFreeChart,免费的JasperReport……,却从来没能够给人家贡献哪怕一行代码。这样也就算了,但是类似于一些力所能及的东西,例如可能每个Java程序员都会碰到的一些小问题,小技巧,常常出现的错误,为什么我就不能把他们贴出来供人分享呢?说不定就会帮到某位哥们解决大问题,更有可能你的几句话就能节省别人几分钟甚至几小时的时间。如果每个人都能在业余时间把自己的一些心得体会贴出来,相信更多的人将因此受益。当你遇到问题的时候,才能心安理得的去Google或Baidu。相信这也是技术论坛和技术Blog的初衷吧,毕竟这个世界并不是只有钱才是最重要的原动力。
1 改变Swing应用程序的默认字体/字号
经常使用Swing作为程序UI的人可能会注意到,Swing组件默认显示文字的字号为11。这对于英文显示毫无问题,但是如果用这个字号显示中文的话,这么小的字号就会使程序变得很难看。我当年在用IReport0.56的时候就发现他的菜单栏和弹出的Dialog里的字很难看,但是将字号调大之后就好多了。虽然在最近版本的JDK里似乎修正了这个字体问题,但是如果你的程序必须使用以前版本的JDK的话,这个问题就需要处理一下,下面就是一个不错的解决方案:
Font vFont = new Font("Dialog", Font.PLAIN, 13);
UIManager.put("ToolTip.font", vFont);
UIManager.put("Table.font", vFont);
UIManager.put("TableHeader.font", vFont);
UIManager.put("TextField.font", vFont);
UIManager.put("ComboBox.font", vFont);
UIManager.put("TextField.font", vFont);
UIManager.put("PasswordField.font", vFont);
UIManager.put("TextArea.font", vFont);
UIManager.put("TextPane.font", vFont);
UIManager.put("EditorPane.font", vFont);
UIManager.put("FormattedTextField.font", vFont);
UIManager.put("Button.font", vFont);
UIManager.put("CheckBox.font", vFont);
UIManager.put("RadioButton.font", vFont);
UIManager.put("ToggleButton.font", vFont);
UIManager.put("ProgressBar.font", vFont);
UIManager.put("DesktopIcon.font", vFont);
UIManager.put("TitledBorder.font", vFont);
UIManager.put("Label.font", vFont);
UIManager.put("List.font", vFont);
UIManager.put("TabbedPane.font", vFont);
UIManager.put("MenuBar.font", vFont);
UIManager.put("Menu.font", vFont);
UIManager.put("MenuItem.font", vFont);
UIManager.put("PopupMenu.font", vFont);
UIManager.put("CheckBoxMenuItem.font", vFont);
UIManager.put("RadioButtonMenuItem.font", vFont);
UIManager.put("Spinner.font", vFont);
UIManager.put("Tree.font", vFont);
UIManager.put("ToolBar.font", vFont);
UIManager.put("OptionPane.messageFont", vFont);
UIManager.put("OptionPane.buttonFont", vFont);
这段代码用在程序的开始部分,可以有效地将Swing组件的显示字体设置为我们在vFont所设定的内容。
1.1 让窗口更好地居中显示
无论是顶层组件JFrame还是对话框JDialog,让他们的窗口居中显示是一个很常见的问题,因为他们默认总是从左上角弹出来,这也太不爽了!对于这个问题,JBuilder应用程序生成向导给出了解决方案:
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height)
frameSize.height = screenSize.height;
if (frameSize.width > screenSize.width)
frameSize.width = screenSize.width;
frame.setLocation((screenSize.width-frameSize.width)/2,screenSize.height-frameSize.height) / 2);
这个方法对于大多数窗口组件来说都足够了,但是还有其他问题存在,比如说分辨率和显示器的尺寸都会导致应用程序窗口“变形”,明明在17寸显示器1024*768分辨率下显示好好的窗口到了19寸的1280*800的宽屏下就会被“拉”得很“长”。于是,虽然有布局管理器帮我们管理拉伸后组件的放置,但仍然解决不了拉长后带来的美观问题。我的经验是,对于某些窗口,由于它被“拉长”之后由于其内部组件之间的间隙变大,会显得很难看。所以应该为他们设定一个最合适的显示大小。在居中显示的时候只调整位置而不改变大小,这样就不会影响窗口的美观。所以我们只需要对上面的代码小改一下即可,以JFrame为例:
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
screenSize = Toolkit.getDefaultToolkit().getScreenSize();
frame.setPreferredSize(new Dimension(512,450));
int frameWidth = this.getPreferredSize().width;
int frameHeight = this.getPreferredSize().height;
frame.setSize(frameWidth, frameHeight);
frame.setLocation((screenSize.width - frameWidth) / 2,(screenSize.height - frameHeight) / 2);
2 自定义JFrame的关闭事件
有的时候,当用户关闭应用程序窗口的时候,我们可能希望程序在结束之前保存一些必要的数据。对于这种需求,我们有两种备选方案:
2.1 获取程序关闭的“钩子”
Runtime.getRuntime().addShutdownHook(shutdownHook);
protected Thread shutdownHook = new PlatformShutdownHook();
protected class PlatformShutdownHook extends Thread {
public void run()
{
//一些清理工作在这里进行……
}
}
通过这种方法,我们就可以在程序结束时获得通知,以便进行一些保存或清理的工作。然而这种方法的缺点是,在程序收到结束通知的时候,所有的UI组件已经被销毁了,用户此时看到的是程序已经结束。而事实上如果程序保存需要花很长的时间的话,用户是不能获取任何信息的,这是一个很糟糕的用户体验。因为如果这时用户关机的话,程序就有可能丢失尚未保存的信息,而对于这一切,用户并不知情。
2.2 处理JFrame关闭事件
为了在UI被销毁之前收到程序结束的消息,我们需要自行处理窗口关闭的事件。注意在这里我们没有采用addActionListener(……)方法,因为这样做只能让我们在窗口关闭之后收到通知,这样就与上面的方法没什么区别了。
我们需要在JFrame的构造函数中设置:
//设定标志,让MainFrame自己接收窗口事件
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
然后再实现下面的函数:
protected void processWindowEvent(final WindowEvent pEvent) {
if (pEvent.getID() == WindowEvent.WINDOW_CLOSING) {
/** 防止用户多次点击“关闭”按钮造成重复保存 **/
if( !isClosing ) isClosing = true;
else return;
//处理JFrame关闭事件……
}else{
//忽略其他事件,交给JFrame处理
super.processWindowEvent(pEvent);
}
}
如此一来,我们就可以在窗口被关闭之前通知用户程序正在保存数据的信息,例如后面提到的InfiniteProgressPanel可以显示的内容。
3 日期选择组件与JDialog的冲突问题
由于很多应用程序都需要用户输入日期,却又怕用户输入的日期格式错误,所以日期选择组件便应运而生。虽然我们很需要它,但是网上绝大多数的组件都是需要给钱的。在找到SwingX之前,我找到的唯一能够免费使用的日历组件就是一个名为DateChooser的JDialog:
看样子很不错,它支持中文,对于今天高亮显示,可以调整年分和月份……一切都非常符合要求。但是这么好的组件却不能用在我的程序里,原因是在我的程序中,调用这个组件的组件也是一个JDialog,并且设置了setAlwaysOnTop(true)—即总在最前端显示。由于DateChooser也设定了在最前端显示,这就导致了它和其父组件的显示冲突,最终结果是DateChooser不能正常显示。对于这个问题,我最终使用SwingX的组件DatePicker来代替DateChooser完成选择日期的使命,惯于DatePicker的使用我将来会在“SwingX使用详解”中提到,这里就不再细说。但是这个问题仍然值得我们注意,即如果一个窗口组件是设置了总在最前端显示的JDialog,那么就不要以这个JDialog为父组件来弹出其他JDialog,以避免冲突的发生。
4 JTable的实用技巧
无论对于什么样的一个应用程序来说,用表格的形式来显示数据是再平常不过的事情了。于是JTable就成为我们在所有Swing组件中最不可或缺的朋友。对于JTable的操作,大多数情况下我们都可以不假外求,因为JDK自带的例子SwingSet2给我们展示了足够多的功能。
在这个例子里,我们可以改变单元格的间距,行高,选择类型(Selection Style),是否显示水平线,甚至可以将表格内容打印出来。其中,表格除了文字之外还可以包含其他组件和内容,如SwingSet2种就加入了可以选择颜色的JComboBox和喜爱的食物所代表的图片。
但有些时候,我们还会有一些其他的需求。例如说为了保护我们的眼睛,我们希望表格的内容是带有间隔色的,如奇数行显示蓝色,而偶数行显示白色。又或者我们希望表格中某些列的内容是可编辑的,而且他列的内容是不可编辑的。又或者让表格中的列带有排序的功能,能让我们点一下表头它就自己按照从低到高或从高到低的顺序自行排列。最后我们希望表格的表头和单元格力的内容能够居中显示。让我们一个一个来实现这些功能!
4.1 间隔色表格及单元格/表头居中显示
JTable的API并没有为我们提供更改表格行或列的颜色的能力。但是我们知道,表格的表头和内容的呈现形式都是由相应的Renderer来控制的,所以我们只需要继承单元格默认的Renderer并作相应的修改就可以达到目的:
由于实现了接口TableCellRenderer,我们只需要实现唯一的函数getTableCellRendererComponent(…)。在上例中我们看到,在函数中我们判断当前行是奇数还是偶数,如果是奇数,就设置其背景色为淡蓝色,否则就设其背景色为白色。在每次更新表格内容的时候,我们只需要调用下面的函数,就可以保证表格在内容被更改之后依然正确显示间隔色。
/** 为所有表格设置间隔色 **/
private void setRenderColor(){
for( int i = 0; i < table.getColumnModel().getColumnCount(); i++ ) table.getColumn( colname[i] ).setCellRenderer(colorRender );
}
另外,如果我们想要让单元格中的内容居中显示的话,请注意到在设置间隔色部分下面的函数,通过setHorizontalAlignment(SwingConstants.CENTER)我们就可以让单元格内容居中显示。
虽然JTable表格的表头在默认情况下应该是居中显示的,但不知道为什么,在我的应用程序中表格的表头总是左对齐显示,这让我恼火不已。由于和单元格一样,表头的各项显示指标也是由其Renderer控制的,所以只需要设置一下表头的Renderer就能达到目的:
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(renderer.CENTER);
利用这种方法,如果我们需要让他右对齐似乎也不是什么难事,对吗?
4.2 让某些单元格不可编辑
有些时候,我们希望有些行/列可以被编辑,而有些行/列不能被编辑。如下就是一例,我的程序希望第一列(编号列)的内容可以被用户通过双击进行编辑,而其他列则不能被用户编辑。单元格能否被编辑取决于JTable的isCellEditable(int row,int column)。如果该函数返回true则(row,column)所代表的单元格可以被编辑,否则该单元格不能被编辑。于是我建立了一个名为SingleUnitEditableTable的类,他继承自JTable,并Overwrite了isCellEditable(int row,int column)方法:
//设置单元格不可编辑,为缺省实现
public boolean isCellEditable(int row, int column) {
if( editableColumn != -1){
if( column == editableColumn )
return true;
return false;
}
return false;
}
其中的editableColumn是一个内部属性,用来指定哪个列可以被编辑。通过这个例子,我相信,如果你想实现奇数行/列可编辑而偶数行/列不可被编辑或者满足特定条件的单元格不可被编辑这样的JTable易如反掌了吧?下面就是我的应用程序的结果:
第一列可编辑
其他列均不可编辑
4.3 JTable自排序
这个问题已经由JDK6.0帮我们解决了,在这个版本,JDK为我们提供了一个名为TableRowSorter的类,在程序中我们只需要写2行代码即可实现表格内容的排序:
TableRowSorter sorter = new TableRowSorter(tableModel);
accAllTable.setRowSorter(sorter);
看到“编号”列旁边的箭头了吗?如果我们用鼠标点击表头,JTable就会自动为我们由小到大排序,再点一下,表格就会从大到小排序,真是十分方便。而对于JDK6.0之前的应用程序就没有这么好的运气了,我们需要自己实现一个TableRowSorter,并且自己生成一个表头的Renderer来实现排序小箭头,真是繁琐啊!我这里倒是有一个不错的实现,如果有人需要的话可以给我留言。不过自己实现Renderer采用的是JLabel,会改变表头的模样,不如默认的表头好看,所以可能的话还是升级吧J
5 用JEditorPane显示HTML描述的文本
从JDK1.4开始,Swing的很多组件(如JLabel)都可以显示HTML语言写的文本。这是一个巨大的进步,因为我们可以将所要显示的文字的配置信息如字体,字号,颜色,换行等信息直接以HTML写入到组件的setText()方法当中,不但免去了事后对这些信息进行繁杂配置的烦恼,而且还丰富和简化了所要显示文本的形式。而JEditorPane则有所不同,它天生就是用来分析并显示格式化文本的,由一些Java写的开源Web浏览器甚至都采用改进后的JEditorPane作为Web页的显示器。下图就是SwingSet2中的JEditorPane相关的例子。我们可以看到JEditorPane可以显示大多数的HTML元素,包括图片,格式化文字,URL链接等。
然而通过JEditorPane显示HTML描述的文本有两种方式:
第一种是直接使用JEditorPane.setPage(String htmlTxt);来显示用html语言写成的文本。但是这种方法的缺点是无法显示HTML文本中所描述的对外部资源(如图片,CSS等)的引用。所以如果要显示更为丰富的信息,仅仅用第一种方法是不够的。
所以第二种方法就呼之欲出:将用HTML语言描述的动态文本信息写到文件中,使之成为真正的HTML文件,再用JEditorPane.setPage(URL)或JEditorPane.setPage(String htmlFilePath),JEditorPane方法读入这个动态生成的内容文件就可以让JEditorPane自动为我们显示丰富的信息了。
String vNewReportFileName = "file:///c:/temp.html";
JEditorPane reportPane = new JEditorPane();
File f = new File(FileUtil.reportDir,vNewReportFileName);
FileWriter fw = new FileWriter(f, false);
fw.write("<html>");
fw.write("<head>");
…………
fw.write("</body></html>");
//清理操作
fw.flush();
fw.close();
f = null;
reportPane.setPage(vNewReportFileName);
下图就是我的程序所显示的结果,从图中我们可以清楚地看到由CSS文件定义的表格的Title,这个Title是由一个蓝色的图片作为背景的。
让人遗憾的是用JEditorPane显示的表格的边框都很粗,虽然我已经将了表格的border设置为1,可是JEditorPane依然我行我素。但是在IE下,表格的边框的表现就要好的多:
网上有人说这是一个Bug,但是没有人给过解决这个问题的方法,如果有人又解决方法的话请留言,我将不胜感激!
6 用InfiniteProgressPanel实现GlassPane
俗话说重要人物都最后出场,作为Swing篇的完结部分,我为大家隆重推荐一个GlassPane的实现—InfiniteProgressPanel,它的效果如图所示:
怎么样,很酷吧?这是在程序进行更新的时候能够给用户以提示,可以屏蔽用户操作而且十分美观的特殊进度条。它源于一个超级Java大牛的手笔,此君的《Swing Hacker》在去年如带给我的震撼到现在还挥之不去。从那以后,谁再敢说Java不能做出好看的用户界面之前都需要自己好好掂量一下自己是否有这么说的资格。这本书让我真正认识到,只有想不到没有做不到。都是一样用Swing,为啥人家就能玩出花样呢?差距!
其实现原理很简单,说白了就是用Java2D画圈!至于源码各位可以到网上自己搜。他的使用十分简单:
InfiniteProgressPanel glassPane = new InfiniteProgressPanel();
frame.setGlassPane(glassPane)
在需要它显示的时候,就这样做:
Thread myThread = new Thread(new Runnable(){
public void run() {
InfiniteProgressPanel gl = thisRef.glassPane;
gl.start();
gl.setText("正在保存数据请稍候....");
try {
//这里放要做的事情……
gl.setText("保存完毕,欢迎使用!");
Thread.sleep(1000);
}catch(InterruptedException ex) {
}finally{
gl.stop();
}
}
});
myThread.start();
这里有几个问题需要注意:
1. 必须要将InfiniteProgressPanel的显示放到一个线程里,相信大家都知道原因,我不用多说。
2. 在InfiniteProgressPanel结束之前的Thread.sleep(1000);是必要的,如果时间设得太短或不设将会导致InfiniteProgressPanel死掉。至于原因我没有时间深究,各位有兴趣可以自行察看其源码,如果你能找到原因高诉我,我会非常感激。
3. 在有些时候会出现圆圈“四处乱窜”的现象,不过不太常见。
JavaScript包含的Ajax是Web2.0应用的一个重要组成部分。该部分的进化发展使网络变成了超级平台。该转变同时也催生了新品种的病毒和蠕虫,比如Yamanner,Samy 以及Spaceflash等等。Google,Netflix,Yahoo 以及MySpace等门户网站在过去的几个月里都因为新的漏洞而蒙受一定损失。黑客们可以利用这些漏洞进行钓鱼,跨站点脚本(XSS)以及跨站点伪造(XSRF)请求等攻击。
Ajax中没有固有的安全漏洞,但是对该技术向量的适配显著地改变了网络应用的开发途径以及方法论。以前,DCOM和CORBA组成核心中间件层的时候,将数据和对象序列化非常困难。Ajax使用简单的GET,POST或者SOAP调用,来转换XML,HTML,JS Array,JSON,JS Objects以及其他定制的对象;全部这些操作都不需要调用中间件层。Ajax的这种综合能力使应用服务器与浏览器之间的数据交换非常流畅。从服务器端传来的信息动态地被注入到当前的DOM相关环境,然后浏览器的DOM状态重置。在讲安全漏洞之前,我们先来看看促成Web2.0漏洞的关键因素。
多重分散的终端点以及隐藏调用——Web2.0应用与Web1.0的主要区别就是信息访问机制的区别。比起它的前身Web1.0, Web2.0应用有数个Ajax终点。潜在的Ajax调用分散于整个浏览器页面,并且能够被各个事件分别调用。开发者恨难应付Ajax调用的这种分散性,并且由于这些调用是隐藏的,不那么明显,它还可能导致代码不规范。
认证混乱——输入和输出内容认证是应用的重要因素之一。Web2.0应用使用桥,mashups,还有反馈等等。很多情况下,它假定“另一方”(读取服务器端或者客户端代码)已经实现了认证,这种混乱就导致了双方都没有实现适当的认证控制。
不受信任的信息来源——Web2.0应用从很多不受信任的来源比如反馈,博客,搜索结果中获得信息。这些内容在提供给终端浏览器之前从来没有被认证,这就有可能引发跨站点攻击。黑客还有可能在浏览器中加载JavaScript,以便迫使浏览器发出跨域的调用并打开安全漏洞。那样的话,这些致命的漏洞就能被病毒和蠕虫利用。
数据序列化——浏览器可以调用Ajax来实施数据序列化。它可以获取JS array,Objects,Feeds,XML文件,HTML 块以及JSON。如果这些序列块中的某一个被解析并修改了,黑客们就可以强迫浏览器执行恶意脚本。不受信任信息与数据序列化的结合,对终端用户的安全是致命的。
动态脚本构成和执行——Ajax会建立一个后端通道,从服务器获取数据,然后将它传送给DOM。实现这一点的必要条件就是动态地执行JavaScripts,以便随时更新DOM或者浏览器页面缓存的状态。Ajax通过调用定制的功能或者eval()功能。未经认证的内容或者使用不安全的调用,轻则导致会话内容泄露,重则迫使浏览器执行恶意内容等各种后果。
Web2.0应用可能因为上面提到的1个或多个失误而变得易受攻击。如果开发者不够审慎,没有花心思在安全管理上的话,那么服务器和浏览器端都会出现安全问题。以下是10个可能的安全漏洞的简要说明。
(1)畸形的JS对象序列
JavaScript支持面向对象编程(OOP)技术。它有很多不同的内置对象,也允许用户自己创建对象。使用者可以用new object() 或者自己编辑如下代码来创建新的对象。
message = {
from : "john@example.com",
to : "jerry@victim.com",
subject : "I am fine",
body : "Long message here",
showsubject : function(){document.write(this.subject)}
};
这是一个简单的消息对象,其中有2个字段需要电子邮件地址。我们可以使用Ajax来将该对象序列化并用JavaScript代码编译。程序员可以将它赋值到变量或者eval()。如果攻击者发送嵌入了脚本的恶意“主题”,那么读者就将成为跨站点脚本攻击的受害者。JS对象既包含数据也包含方法。对JS对象序列的不当使用将产生可以被诡计多端的注入代码利用的安全漏洞。
(2)JSON对注入
JavaScript对象符号(JSON)是一个简单而有效的少量数据交换格式,它包含对象,数组,Hash表,向量以及列表数据结构。JavaScript, Python, C, C++, C# 和Perl languages都支持JSON。JSON序列在Web2.0应用中是个非常有效的交换机制。开发者频繁使用Ajax和JSON,获取并传送必要的信息给DOM。下面是个简单的带有不同的name值对的JSON对象:“bookmarks”对象。
{"bookmarks":[{"Link":"www.example.com","Desc":"Interesting link"}]}
黑客们可以在Link或者Desc中注入恶意脚本。如果DOM和可执行程序被注入了,XSS目录也会被注入。这是使终端用户感染恶意内容的另一种方法。
(3)JS数组中毒
JS数组是另一个比较普遍的序列化对象。人们可以很容易地跨平台移植它,并且它在使用不同语言的结构中也很有效。感染一个JS数组可以扰乱整个DOM环境。黑客们可以在浏览器中使用简单的跨站点脚本攻击JS数组。下面是一个JS数组的例子:
new Array(“Laptop”, “Thinkpad”, “T60”, “Used”, “900$”, “It is great and I have used it for 2 years”)
该数组是从一个拍卖二手笔记本的网站传出来的。如果这个数组对象在服务器端没有被仔细处理,黑客就可以在最后字段中注入脚本。这种注入将危及浏览器安全并被攻击者利用。
(4)被修改的XML数据流
Ajax调用接受来自多个地址的XML。这些XML块来自运行在SOAP,REST或者XML-RPC的网络服务。这些网络服务是由从第三方的代理桥那里接收过来的。如果这些第三方XML数据流被攻击者修改过,那么攻击者就可能向其中注入恶意内容。
浏览器从它自带的XML解析器接收该数据流。该解析器容易受不同的XML炸弹的攻击。人们也可以在该数据流中注入脚本,这样就可以导致跨站点脚本攻击(XSS)。浏览器接收未经认证的XML数据流的话,这就会危及终端客户端的安全。
(5)DOM中脚本注入
前四个漏洞都是由于序列化问题引起的。一旦浏览器收到序列化的对象数据流,开发者会发出某种调用来访问DOM。这种调用的目的是将新内容“重写”或者“重填”入DOM中,可以调用eval()这个定制功能,也可以使用document.write()。如果这些调用是在不受信任信息流上进行的,浏览器就有可能由于DOM的操作漏洞而受攻击。攻击者可以用很多document.*()调用来向DOM环境中注入XSS。
例如,这段JavaScript代码:Document.write(product-review)。
在这里,“Product-review”是从第三方blog上获得的变量。如果它含有JavaScript会怎样?答案很明显。这个JavaScript就会被浏览器运行。
(6)跨域访问和回调
Ajax不能从浏览器跨域访问。所有比较流行的浏览器都有个安全特性,那就是拦截跨域访问。一些网站服务为对象序列提供回调功能。开发者可以使用这个功能来把网站服务整合到浏览器本身。人们可以把该功能名传回,这样浏览器一找到回调对象数据流,它就会被浏览器中早已有的特殊功能名执行。
这个回调对使用浏览器内认证的开发者来说是个额外负担。如果输入的对象数据流未经浏览器认证那么终端客户端就会成为跨域攻击的目标。不管是有意还是无意的,跨域服务可以向浏览器中注入恶意内容。该跨域调用在当前DOM环境中运行,于是导致当前对话也易受攻击。在实现应用之前,人们需要仔细检查整个跨域功能。
(7)RSS和Atom注入
联合的反馈,RSS以及Atom,是最普遍的一种将站点更新信息传到网络上的方法。许多新闻,博客,门户站点等等,都在网络上共享多个反馈。反馈是标准的XML文档,并且可以被任何程序接收。Web2.0应用使用窗口小部件或者浏览器内部元件整合了联合反馈。这些组件调用Ajax来访问反馈。
这些反馈可以被终端用户方便地选择。一旦用户选择了它们,这些反馈就会被解析并注入到DOM中。那么如果这个反馈在注入之前没有被适当地认证过,就会出现一些安全问题。人们可以往浏览器中注入恶意链接或者JavaScript代码。注入之后,就大事不妙了,最终结果是XSS和对话被黑客拦截。
(8)单击炸弹
Web2.0应用可能不会很简单地就被黑客攻下,但他们可以对它进行基于事件的注入。人们可以将带有"onclick"字样的恶意链接用JavaScript注入。这样,浏览器就带着个随时等待终端用户右键点击来触发的炸弹。一旦用户点击了链接或按钮,能够启动炸弹的那个事件被启动了,那么攻击就成功了。此类攻击会导致对话被恶意代码拦截。
这也是由于人们从那些没有经过正确验证的不受信任源处获得的信息,所导致的安全漏洞。为了利用该安全漏洞,它需要终端客户端触发一个事件。这个事件也许是诸如点击按钮或者链接的这种无害事件,但是点击后就使会用户损失惨重。它可能引起某个恶意事件,将当前对话信息发送给目标,又或者在当前浏览器环境中执行一系列脚本攻击。
(9) 基于Flash的跨域访问
黑客们可以使用Flash插件的Ajax接口,从而用浏览器中的JavaScritps发出GET和POST请求。这个接口使黑客们能进行跨域调用。为了避免安全问题,该Flash插件实现了根据策略访问其他域的功能。该策略可以通过在域的根部放置crossdomain.xml文件来配置。如果放置的文件配置不当——很普遍的现象——它就可能允许跨域访问。下面是一个配置不当的XML文档:
现在可以从浏览器自身发出跨域调用了。这个结构还有一些其他安全问题。基于Flash的丰富网络应用(RIA)如果配置错误的话,很容易由于Ajax的跨域访问Bug而被攻击。
(10) XSRF
跨域伪造请求(XSRF)是个老牌的攻击向量了,它迫使浏览器向不同的域发出HTTP GET或者POST请求;这些请求可以跨域在运行的应用逻辑中启动某种事件。它可能请求修改密码或者电子邮件地址等。浏览器调用它后,它重放cookie并获得身份认证。这就是该请求的关键部分。如果某个应用只根据cookie来判识身份,那么该攻击就会成功。
Web2.0中Ajax是就XML-RPC,SOAP或者REST与后端网络服务进行对话的,通过GET和POST可以进行这些调用。换句话说,人们可以对这些网络服务进行跨站点调用,从而危及受害者与网络服务接口的身份信息。XSRF这个攻击向量很有趣,它在这个新界定的端点情况中创造了新的层次。这些终点可能是为Ajax或者网络服务而准备的,但它们也有可能被跨域请求所激活。
对安全漏洞的攻击以及相应对策
Web2.0应用有多个终端点;每个点都是威胁的侵入点。为了保证安全,我们应当保护好所有这些点。在将第三方信息发送给客户端之前要对其进行彻底处理。
为了处理Ajax序列,必须在它们到达DOM之前对输入数据流进行验证。XML解析以及跨域安全问题也需要额外重视,并实施更好的安全管理措施。我们应当遵循那个最简单最笨拙的原则:不让未经认证的跨域信息进入浏览器。有趣的是,到目前为止,安全专家们都不主张使用客户端脚本来进行输入验证,因为这很容易被规避掉。
Web2.0促成了很多浏览器安全相关的新的漏洞。利用这些安全漏洞很难但不是不可能。安全问题以及促成因素结合起来将严重影响那些大的网络团体,比如能被攻击者蠕虫和病毒利用的那些组织。最终将导致身份信息的泄漏。
结论
本文简单地讲了一些可能出现的关于Ajax漏洞。还有很多其他潜在的漏洞,比如利用跨域代理来在浏览器中建立单项通道或者存储变量。
Web2.0中很多逻辑都转到了客户端。这会将整个应用暴露给一些严重的威胁。对整合来自多方的、不受信源的数据的迫切要求也将全面增加风险向量:XSS,XSRF,跨域问题以及客户端上的序列,还有不安全的网站服务,服务器端的XML-RPC和REST访问。相反地,Ajax可被用来构造优美的无缝数据整合。但是,任一不安全的调用或者信息流都会使其产事与愿违的效果,从而促成可被利用的安全漏洞。
这些新技术向量很有前景,令很多人兴奋不已,但是攻击者,病毒和蠕虫作者对它更感兴趣。为了保障安全,开发者应当在这些细节方面格外小心。
如何新增一个mysql用户
增加一个用户test1密码为abc,让他可以在任何主机上登录,并对所有数据库有查询、插入、修改、删除的权限。首先用以root用户连入MYSQL,然后键入以下命令:mysql>grant select,insert,update,delete on *.* to test1@"%" Identified by "abc"; 增加的用户是十分危险的,你想如某个人知道test1的密码,那么他就可以在internet上的任何一台电脑上登录你的mysql数据库并对你的数据可以为所欲为了 增加一个用户test2密码为abc,让他只可以在localhost上登录,并可以对数据库mydb进行查询、插入、修改、删除的操作 (localhost指本地主机,即MYSQL数据库所在的那台主机),这样用户即使用知道test2的密码,他也无法从internet上直接访问数据 库,只能通过MYSQL主机上的web页来访问了。 mysql>grant select,insert,update,delete on mydb.* to test2@localhost identified by "abc"; 或 mysql>grant all privileges on mydb.* to test2@localhost identified by "abc"; 如果你不想test2有密码,可以再打一个命令将密码消掉。 mysql>grant select,insert,update,delete on mydb.* to test2@localhost identified by ""; 另外,也可以通过直接往user表中插入新纪录的方式来实现。
如何修改mysql用户密码
如果要修改的用户不是root用户 方法1 先进入root用户的mysql数据库中 mysql>mysql -u root -p mysql mysql>update user set password=password('new_password') where user='user'; mysql>flush privileges; 如果修改的用户是root 首先停止MySQL的运行,然后重新启动 : PATH_TO_MYSQL/bin/mysqld --skip-grant-tables & 就可以不需要密码就进入 MySQL 了。 然后就是 mysql>use mysql mysql>update user set password=password("new_pass") where user="root"; mysql>flush privileges; 重新杀 MySQL ,用正常方法启动 MySQL 一定注意:很多新手没有用password=password("..."),而是直接password="..."所以改掉密码不好使
另一种方法是使用mysqladmin命令 比如原来的用户user的密码是123现更新密码为123456 MySQL\bin\mysqladmin -u user -p password 123456 Enter password:123
如何删除用户和撤销权限
要完全删除一个用户,你必须用一条DELETE语句明确从user表中删除用户记录: >mysql -u root -p mysql >password:****** mysql->DELETE FROM user ->WHERE user=‘user_name’ and Host=‘host_name’; mysql>FLUSH PRIVILEGES;
收回资料库使用权限的方法如下(以 MySQL root 进入): mysql> revoke delete on addbook.* from maa@localhost; Query OK, 0 rows affected (0.00 sec)
收回全部的权限 mysql> revoke all privileges on addbook.* from maa@localhost; Query OK, 0 rows affected (0.00 sec)
增加和删除数据库
使用mysqladmin命令(增加) MySQL\bin\mysqladmin -u root -p create dbtest Enter password:******** Database "dbtest" created
使用mysqladmin命令(删除) MySQL\bin\mysqladmin -u root -p drop dbtest Enter password:******** Dropping the database is potentially a very bad thing to do. Any data stored in the database will be destroyed. Do you really want to drop the 'dbtest' database [y/N] y Database "dbtest" dropped
由于gd2才开始支持真彩图片的创建,所以,,升级服务器,因为原来的安装都是默认的系统安装,也更因为是个菜鸟,所以,安装很困难,起初根据网上一些文章在我的red hat A 3 上安装测试,不过,测试了安装php4.3.X 和php5.0.X都没有成功,最后,根据其他人的文章,自己搞了将近3天,终于安装上了,下面就我安装中出现的错误和过程写出来和大家分享,以免有像我一样的菜鸟们走弯路! (我可是两天多的时间,安装php的次数不下50次得来的经验,希望大家多多支持,有错误当然欢迎给我指正!转载请注明来自中国智慧在线(http: //article.21e.cn ,谢谢!),以下经过测试在red hat 9 和red hat A 3上通过!
如果你机器里原来装有了PHP或者APACHE的RPM或者低版本.你可以现删除,删除安装简洁一些,不过我的实际操作过程是煤油删除,而直接安装的.当然你也可以跟我一样! 首先,服务器GCC要有,不然什么都不能做.可以用gcc -v来查看是否安装了GCC,
#gcc -v Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux Thread model: posix gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-34)
有以上类似信息说明已有GCC,没有就现安装吧,至于如何安装,我就不说了,可以用光盘安装或者是下载源文件都可以,当然你的版本不一定是3.2.3!
请下载以下所有的东西:
httpd-2.0.X.tar.gz 版本最好是下载最新的啦,下载地址:http://www.apache.org MySQL-client-4.0.20-0.i386.rpm MySQL-server-4.0.20-0.i386.rpm(如果你打算升级mysql的话请下载,下载地址:http: //www.mysql.org 当然也是下载最新的版本最好了,由于我不打算安装mysql,就省略了,安装的时候的步骤也是先安装mysql!) php-5.0.X.tar.gz 下载地址:http://www.php.net ZendOptimizer-2.5.3-linux-glibc21-i386.tar.gz zend的最新版安装是好像有点问题,就下载这个版本就可以,zend用来加速php,你可以选择不安装!下载地址:http: //www.zend.com gd-2.0.28.tar.gz 这个软件的下载地址,php推荐的是:http://www.boutell.com/gd/ 但是由于某些原因,开发者不支持gif图像的创建,这有点不太方便,所以,我下载了个支持gif图像的,也就是打了gif补丁的:http: //www.rime.com.au/gd/ libxml2-2.X.X.tar.gz 下载地址: zlib-1.X.X.tar.gz 忘记了,自己找一下吧 jpegsrc.v6b.tar.gz 下载地址:ftp://ftp.uu.net/graphics/jpeg/ libpng-1.2.5.tar.gz 下载地址:http://www.libpng.org/pub/png/libpng.html freetype2-X.X.tar.gz 下载地址:http://www.fretype.org
xpm-3.4k-2.i386.rpm 忘记了,自己找一下吧
以上都是我下载的官方地址,软件的版本中的X,你自己看看你想用哪个版,不过最好是用最新稳定版本的!如果你以前安装过上述软件的其他版本,你也可以选择不安装!
安装MYSQL 服务器: #rpm -ivh MySQL-server-4.0.20-0.i386.rpm #rpm -ivh MySQL-client-4.0.20-0.i386.rpm 安装好后试试能不能用 #mysql 如果设置了密码后测试方法是(mysql -u root -proot -h localhost 注意的是-p后煤没有空格,直接跟密码) Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 27651 to server version: 4.0.20-standard Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
说明可以了! 请自己改mysql的密码,方法不说了!
安装XPM
#rpm -ivhxpm-3.4k-2.i386.rpm
安装libxml # tar -zxf libxml2-2.6.16.tar.gz # cd libxml2-2.6.16 # ./configure (xml默认安装就可以,不要指定路径了,因为安装时php可能找不到它,PHP5只支持libxml2-2.5.10以上版本) # make # make install
安装zlib # tar -zxf zlib-1.2.2.tar.gz # cd zlib-1.2 # ./configure --prefix=/usr/local/zlib2 (注意,如果您以前没有安装zlib,可以不指定路径,我是没有删除以前的低版本才指定的!以下雷同!) # make # make install
安装jpeg # tar -zxf jpegsrc.v6b.tar.gz # cd jpeg-6b/ # ./configure --prefix=/usr/local/jpeg6 # make # make install-lib 如果你选择默认安装,可能很顺利,指定路径后,请先创建以下文件夹 错误提示:...... /usr/bin/install -c -m 644 jconfig.h /usr/local/jpeg6/include/jconfig.h /usr/bin/install: 无法创建一般文件‘/usr/local/jpeg6/include/jconfig.h’: 没有那个文件或目录 make: *** [install-headers] Error 1 # mkdir /usr/local/jpeg6 # mkdir /usr/local/jpeg6/include # mkdir /usr/local/jpeg6/lib # make install-lib # make install
安装时如果错误提示: /usr/bin/install: 无法创建一般文件‘/usr/local/jpeg6/lib/libjpeg.a’: 没有那个文件或目录 make: *** [install-lib] Error 1 创建如下文件夹: # mkdir /usr/local/jpeg6/lib # make install /usr/bin/install -c cjpeg /usr/local/jpeg6/bin/cjpeg /usr/bin/install: 无法创建一般文件‘/usr/local/jpeg6/bin/cjpeg’: 没有那个文件或目录 make: *** [install] Error 1 # mkdir /usr/local/jpeg6/bin /usr/bin/install -c -m 644 ./cjpeg.1 /usr/local/jpeg6/man/man1/cjpeg.1 /usr/bin/install: 无法创建一般文件‘/usr/local/jpeg6/man/man1/cjpeg.1’: 没有那个文件或目录 make: *** [install] Error 1 # mkdir /usr/local/jpeg6/man # mkdir /usr/local/jpeg6/man/man1 # make install 好了,直到安装成功!
安装libpng: # tar -zxf libpng-1.2.7-config.tar.gz # cd libpng-1.2.7-config # ./configure --prefix=/usr/local/libpng2 # make # make install
安装freetype: # tar -zxf freetype-2.1.9.tar.gz # cd freetype-2.1.9 # ./configure --prefix=/usr/local/freetype2 # make # make install
安装gd库: # tar -zxf gd-2.0.26gif.tar.gz # cd gd-2.0.26gif # ./configure --prefix=/usr/local/gd2 --with-zlib=/usr/local/zlib2/ --with-png=/usr/local/libpng2/ --with-jpeg=/usr/local/jpeg6/ --with-freetype=/usr/local/freetype2/ (请指定及格插件的安装路径,否则安装php的时候可能出错!) # make # make install
安装apache,(php5安装环境需要apache2.0.46以上版本,下载的时候注意!) #tar zxvf httpd-2.0.50.tar.gz #cd httpd-2.0.50 #./configure --prefix=/usr/local/apache2 --enable-module=so #make #make install
安装php5: # tar -zxf php5-200411260130.tar.gz # cd php5-200411260130 # ./configure --prefix=/usr/local/php --with-apxs2=/usr/local/apache2/bin/apxs --with-jpeg-dir=/usr/local/jpeg6/ --with-png-dir=/usr/local/libpng2/ --with-gd=/usr/local/gd2/ --with-freetype-dir=/usr/local/freetype2/ --enable-trace-vars --with-zlib-dir=/usr/local/zlib2/ -with-mysql=/var/lib/mysql # make # make install # cp php.ini-dist /usr/local/php/lib/php.ini
安装libxml的时候如果指定了路径,make的时候可能出错,所以,我安装的时候没指定! 我MAKE PHP4.3.8 和5的时候都遇到: ext/gd/gd.lo(.text+0x63a): In function `zm_deactivate_gd':
/root/software/php-4.3.8/ext/gd/gd.c:385: undefined reference to `gdFreeFontCache'
collect2: ld returned 1 exit status
make: *** [sapi/cli/php]Error 1 另外还有一个错误可能是什么: libphp.lo的错误(错误当时没有纪录,忘记了,大概是!) 是因为GD库的freetype没装,或者是安装gd库的时候煤油指定插件的路径!!
复制PHP.INI文件到正确位置 在PHP目录下运行 #cp php.ini-dist /usr/local/php/lib/php.ini
编辑apache配置文件httpd.conf #vi /usr/local/apache2/conf/httpd.conf
要改的有如下几处:
一般都在 #AddType application/x-tar .tgz 下加一行 #LoadModule php5_module modules/libphp5.so AddType application/x-httpd-php .php 如果你搜索其它地方没有以下这行
LoadModule php5_module modules/libphp5.so 请把上面的#号去掉
还有找到 DirectoryIndex index.html index.html.var 在后面加 index.php 让它把index.php做为默认页
找到 # don't use Group #-1 on these systems! 把下面的用户名和组改为 User apache Group apache (原来好像是nobody)
再找 #ServerName 把#去掉,后面的IP改成你的IP.
找到 DocumentRoot "/usr/local/apache2/htdocs" 把/usr/local/apache2/htdocs改为你存放网页文件的路径
为了让中文网页没乱码 找到 AddDefaultCharset iso8859-1 把后面的iso8859-1改为gb2312 或者是干脆off 其他的选项就自己修改吧!或者到http://article.21e.cn 有一个专门的httpd.conf的说明!
保存httpd.conf文件.
启动apache # /usr/local/apache2/bin/apachectl start 如果没有出错,写一个测试页放到你网页目录下.访问就应该可以看到php的版本等信息了!
如无意外.PHP脚本已经可以连接mysql了.
用ZendOptimizer加速PHP
#tar zxvf ZendOptimizer-2.5.3-linux-glibc21-i386.tar.gz #cd ZendOptimizer-2.5.3-linux-glibc21-i386 #./install.sh 安装的时候注意输入正确的安装apache的路径等内容! 安装完毕,再看看phpinfo页面的zend选项就发现了!!
如果你以前的apache没有删除,而你又想使用 # /etc/init.d/httpd restart 这样重起apache的话,那就修改/etc/init.d/httpd这个文件,修改其中的apahce的三个路径就可以了!!
好了,终于安装完毕,你的机器已经是最新的apache+php+mysql+gd.......了,恭喜!!
艾,累死我了,整整弄了好几天!!休息了!!~(安装的时候,可能安装的时候和写不不是很一样,不过大同小异!)
同时感谢以前那几位辛苦的安装者,参照你们的文章我才得以顺利安装成功,虽然还是用了好几天!~
1.安装一个包 # rpm -ivh 2.升级一个包 # rpm -Uvh 3.移走一个包 # rpm -e 4.安装参数 --force 即使覆盖属于其它包的文件也强迫安装 --nodeps 如果该RPM包的安装依赖其它包,即使其它包没装,也强迫安装。 5.查询一个包是否被安装 # rpm -q < rpm package name> 6.得到被安装的包的信息 # rpm -qi < rpm package name> 7.列出该包中有哪些文件 # rpm -ql < rpm package name> 8.列出服务器上的一个文件属于哪一个RPM包 #rpm -qf 9.可综合好几个参数一起用 # rpm -qil < rpm package name> 10.列出所有被安装的rpm package # rpm -qa 11.列出一个未被安装进系统的RPM包文件中包含有哪些文件? # rpm -qilp < rpm package name> -------------------------------------------------------------------------------------
详细手册如下: 一、安装
命令格式:
rpm -i ( or --install) options file1.rpm ... fileN.rpm
参数:
file1.rpm ... fileN.rpm 将要安装的RPM包的文件名
详细选项:
-h (or --hash) 安装时输出hash记号 (``#'') --test 只对安装进行测试,并不实际安装。 --percent 以百分比的形式输出安装的进度。 --excludedocs 不安装软件包中的文档文件 --includedocs 安装文档 --replacepkgs 强制重新安装已经安装的软件包 --replacefiles 替换属于其它软件包的文件 --force 忽略软件包及文件的冲突 --noscripts 不运行预安装和后安装脚本 --prefix 将软件包安装到由 指定的路径下 --ignorearch 不校验软件包的结构 --ignoreos 不检查软件包运行的操作系统 --nodeps 不检查依赖性关系 --ftpproxy 用 作为 FTP代理 --ftpport 指定FTP的端口号为
通用选项
-v 显示附加信息 -vv 显示调试信息 --root 让RPM将指定的路径做为"根目录",这样预安装程序和后安 装程序都会安装到这个目录下 --rcfile 设置rpmrc文件为 --dbpath 设置RPM 资料库存所在的路径为
二、删除
命令格式:
rpm -e ( or --erase) options pkg1 ... pkgN
参数
pkg1 ... pkgN :要删除的软件包
详细选项
--test 只执行删除的测试 --noscripts 不运行预安装和后安装脚本程序 --nodeps 不检查依赖性
通用选项
-vv 显示调试信息 --root 让RPM将指定的路径做为"根目录",这样预安装程序和后安装 程序都会安装到这个目录下 --rcfile 设置rpmrc文件为 --dbpath 设置RPM 资料库存所在的路径为
三、升级
命令格式
rpm -U ( or --upgrade) options file1.rpm ... fileN.rpm
参数
file1.rpm ... fileN.rpm 软件包的名字
详细选项
-h (or --hash) 安装时输出hash记号 (``#'') --oldpackage 允许"升级"到一个老版本 --test 只进行升级测试 --excludedocs 不安装软件包中的文档文件 --includedocs 安装文档 --replacepkgs 强制重新安装已经安装的软件包 --replacefiles 替换属于其它软件包的文件 --force 忽略软件包及文件的冲突 --percent 以百分比的形式输出安装的进度。 --noscripts 不运行预安装和后安装脚本 --prefix 将软件包安装到由 指定的路径下 --ignorearch 不校验软件包的结构 --ignoreos 不检查软件包运行的操作系统 --nodeps 不检查依赖性关系 --ftpproxy 用 作为 FTP代理 --ftpport 指定FTP的端口号为
通用选项
-v 显示附加信息 -vv 显示调试信息 --root 让RPM将指定的路径做为"根目录",这样预安装程序和后安装程序都会安装到这个目录下 --rcfile 设置rpmrc文件为 --dbpath 设置RPM 资料库存所在的路径为
四、查询
命令格式:
rpm -q ( or --query) options
参数:
pkg1 ... pkgN :查询已安装的软件包
详细选项
-p (or ``-'') 查询软件包的文件 -f 查询属于哪个软件包 -a 查询所有安装的软件包 --whatprovides 查询提供了 功能的软件包 -g 查询属于 组的软件包 --whatrequires 查询所有需要 功能的软件包
信息选项
显示软件包的全部标识 -i 显示软件包的概要信息 -l 显示软件包中的文件列表 -c 显示配置文件列表 -d 显示文档文件列表 -s 显示软件包中文件列表并显示每个文件的状态 --scripts 显示安装、卸载、校验脚本 --queryformat (or --qf) 以用户指定的方式显示查询信息 --dump 显示每个文件的所有已校验信息 --provides 显示软件包提供的功能 --requires (or -R) 显示软件包所需的功能
通用选项
-v 显示附加信息 -vv 显示调试信息 --root 让RPM将指定的路径做为"根目录",这样预安装程序和后安装程序都会安装到这个目录下 --rcfile 设置rpmrc文件为 --dbpath 设置RPM 资料库存所在的路径为
五、校验已安装的软件包
命令格式:
rpm -V ( or --verify, or -y) options
参数
pkg1 ... pkgN 将要校验的软件包名
软件包选项
-p Verify against package file -f 校验所属的软件包 -a Verify 校验所有的软件包 -g 校验所有属于组 的软件包
详细选项
--noscripts 不运行校验脚本 --nodeps 不校验依赖性 --nofiles 不校验文件属性
通用选项
-v 显示附加信息 -vv 显示调试信息 --root 让RPM将指定的路径做为"根目录",这样预安装程序和后安装程序都会安装到这个目录下 --rcfile 设置rpmrc文件为 --dbpath 设置RPM 资料库存所在的路径为
六、校验软件包中的文件
语法:
rpm -K ( or --checksig) options file1.rpm ... fileN.rpm
参数:
file1.rpm ... fileN.rpm 软件包的文件名
Checksig--详细选项
--nopgp 不校验PGP签名
通用选项
-v 显示附加信息 -vv 显示调试信息 --rcfile 设置rpmrc文件为
七、其它RPM选项
--rebuilddb 重建RPM资料库 --initdb 创建一个新的RPM资料库 --quiet 尽可能的减少输出 --help 显示帮助文件 --version 显示RPM的当前版本
本文的大体思路是展示了一次业务交易如何动态地为子系统处理过程触发业务事件。本文所示的例子使用Spring框架和Spring AOP有效地解耦业务服务和子系统处理功能。现在让我们仔细看看业务需求。
业务需求
客户注册系统(CRS——customer registration system)在其完成客户在线注册后需要发送通知给它的客户,并传送他们的地址数据到发票系统(invoice system),以便为付费产生发票。
技术设计
让我们把上面提到的业务需求分解成技术设计。本例中,我们将定义一个自定义业务事件以标示客户注册过程。
一个事件可以被认为是在特定时间间隔发生的一些事情。本例中,它是客户注册过程。典型地,当事件发生时,一个单一事件可能包含了一个或多个需要发生的动作。按照业务需求,我们已经确定了如下两个动作:
- 发送邮件通知客户。
- 传送客户地址数据到发票系统。
我们现在将设计事件数据结构以持有存储在事件数据库表中的信息。以下事件属性被确定下来。
- 事件标识符:1
- 事件描述:客户注册事件
- 动作代码:MT
该事件标识符是映射到数据库中的主键。事件描述定义了关于事件的描述信息。最后一个是动作代码,当事件发生时,它代表了要发生的不同动作。该动作代码定义在动作代码对照表中。
上面提到的事件,其动作代码标识为M和T。M代表发送一个邮件通知到客户,T代表传送客户地址数据到发票系统。
Example: Event.java
/** *Event.java - The event domain object *@author - Vigil Bose */ public class Event implements Serializable {
private Integer eventId; private String eventDesc; private String eventActionCodes; private static final long serialVersionUID = 1L;
/** The cached hash code value for this instance. Settting to 0 triggers re-calculation. */ private int hashValue = 0;
/** *@return the eventActionCodes */ public String getEventActionCodes(){ return eventActionCodes; } /** * @param eventActionCodes the eventActionCodes to set */ public void setEventActionCodes(String eventActionCodes) { this.eventActionCodes = eventActionCodes; } /** * @return the eventDesc */ public String getEventDesc() { return eventDesc; } /** * @param eventDesc the eventDesc to set */ public void setEventDesc(String eventDesc) { this.eventDesc = eventDesc; } /** * Return the simple primary key value that identifies this object. * @return the eventId */ public Integer getEventId() { return eventId; } /** * Set the simple primary key value that identifies this object. * @param eventId the eventId to set */ public void setEventId(Integer eventId) { this.hashValue = 0; this.eventId = eventId; } /** *Implementation of the equals comparison on the basis of equality *of the primary key values. * @param rhs * @return boolean */ public boolean equals(Object rhs){ if (rhs == null) return false; if (! (rhs instanceof Event)) return false; Event that = (Event) rhs; if (this.getEventId() == null || that.getEventId() == null) return false; return (this.getEventId().equals(that.getEventId())); }
/** * Implementation of the hashCode method conforming to the Bloch pattern with * the exception of array properties (these are very unlikely primary key types). * @return int */ public int hashCode(){ if (this.hashValue == 0){ int result = 17; int eventIdValue = this.getEventId() == null ? 0 : this.getEventId().hashCode(); result = result * 37 + eventIdValue; this.hashValue = result; } return this.hashValue; } }
现在我们已经设计了事件领域对象以代表客户注册事件。现在我们转而设计Web层与业务服务层之间的API契约。设计的约束之一是改变领域模型不能破坏Web层与业务服务层之间的API契约。为了满足该设计约束,确定了两个数据包装类:AbstractData和UserData。AbstractData本质上定义了一些行为的抽象。UserData是AbstractData的子类,并提供了其他行为。比如,如果你有一个应用框架,抽象类可以提供诸如事件和消息处理的默认服务。
在本例中,AbstractData负责收集各种业务事件。AbstractData的子类是UserData,用来持有我们的主要领域对象(用户对象)。
用户领域对象由不同属性组成,这些属性是用来识别用户的,如userId、firstName、lastName和加过密的password。它还包含了地址领域对象,该对象有多个地址属性,如address line 1、address line 2、city、state等等。
Example: AbstractData.java
/** *AbstractData.java - A template pattern like class that implments *the event collection behavior. This class is used by all data *transfer wrapper objects between UI Layer and Server side Layer *@author - Vigil Bose */ public abstract class AbstractData{
/** *Stores all the events identified during the transaction *Processing. */ private Set eventSet = Collections.synchronizedSet(new HashSet());
/** * @return Returns the eventSet. */ public Set getEventSet() { return eventSet; }
/** *@param event - An instance of a business event resulted from a particular *business transaction */ public void addToEventSet(Event event) { this.eventSet.add(event); }
}
在AbstractData中声明一个集合(Set)的原因,是为了避免在给定时间点集合中有同一重复事件。让我们看看UserData长什么样吧。UserData包含了实际User领域对象。因此针对User领域对象的任何改变都被限制在这个包装类中,不会破坏客户端和业务服务层之间的接口契约。
Example: UserData.java
/** *UserData.java - A concrete POJO data wrapper whose responsibility is to *holds the main domain object reference and used between client and business *service layers. *@author - Vigil Bose */ public class UserData extends AbstractData{
private User user;
/** * @return The user domain object instance */ public Users getUsers(){ return this.users; } /** *@param The user instance to set. */ public void setUser(User user){ this.user = user; }
}
让我们看看业务服务接口。本例中,我们将在IRegistrationService接口中定义一个叫做doRegister()的API契约,以完成用户注册业务过程。该API本质上是事务型的,因为它要向多个数据库表插入记录。客户层和业务层通过该接口进行交互。
Example: IRegistrationService.java
/** *IRegistrationService.java - A classic example of EJB's business *methods interface pattern that exposes all the Registration *related business methods that can be implemented by both the *enterprise session bean as well as the Pojo service. Moreover *this pattern allows us to switch to POJO implementation later *if it makes sense to do so. *@author - Vigil Bose */ public interface IRegistrationService{
/** *API to complete the registration business process *@param userData - The data wrapper object */ public void doRegister(AbstractData userData);
}
为了简单起见,本例中我们只用了POJO(Plain Old Java Object)服务。业务服务实现则实现了完成客户注册过程的业务逻辑。本例中,服务实现的唯一职责是将调用委派给数据访问层(Data Access Layer),以在适当的数据库表中记录客户注册交易的状态。
Example: RegistrationServiceImpl.java
/** *The primary business method implementation of Customer Registration Service. *This is a POJO. It does not depend on any Spring APIs. It's usable outside a *Spring container, and can be instantiated using new in a JUnit test. However, *we can still apply declarative transaction management to it using Spring AOP. *@author - Vigil Bose */ public class RegistrationServiceImpl implements IRegistrationService{
private IRegistrationServiceDao registrationServiceDao;
/** * A setter method of dependency injection * @param registrationServiceDao - The registrationServiceDao to set. */ public setRegistrationServiceDao(IRegistrationServiceDao registrationServiceDao){ this.registrationServiceDao = registrationServiceDao; } /** * API to register the user * @param user - The user domain object */ public void doRegister(AbstractData userData){ this.registrationServiceDao.completeRegistration(userData.getUser()); } }
务实使用DAO模式
Data Access Object(DAO——数据访问对象)在核心J2EE设计模式一书中被编目为一个集成层设计模式。它把持久库存取和操作代码封装到了一个单独的层次。本文中所指的持久库就是RDBMS。
该模式在业务逻辑层和持久存储层之间引入了一个抽象层。业务对象通过数据访问对象访问RDBMS(数据源)。该抽象层简化了应用代码并引入了灵活性。理想地,对数据源所做的变动(比如变换数据库厂商或类型),仅仅需要改变数据访问对象,因而对业务对象影响最小。本例中,我们使用Hibernate实现数据访问策略。
DAO设计模式所提供的的灵活性主要被归因于对象设计的最佳实践:用接口编程。该原则规定了具体对象必须实现一个接口,在调用程序中使用该接口而非具体对象本身。因此,你可以容易地替换一个不同的实现,而对客户端代码冲击很小。
遵循上面所说的原则,我们将定义注册服务DAO接口——IRegistrationServiceDao.java,它有一个completeRegistraion()行为。业务组件将通过这个接口与DAO交互。
Example: IRegistrationServiceDao.java
/** *A POJO data access object interface for the CRS services business layer. *The API's defined in this interface are all transactional APIs within the *business services layer *@author - Vigil Bose */ public interface IRegistrationServiceDao{ /** * Data Access API to create the new user in the system * @param user - The composite user domain object */ public void completeRegistration(User user) throws DataAccessException; }
在定义了数据访问接口之后,我们必须提供一个IRegistrationServiceDao的具体实现——RegistrationServiceDaoImpl。
本例中该实现中使用了Hibernate。这里所使用的模式是策略模式,可以用任何对象关系映射(Object Relation Mapping)产品或JDBC来替换。该类的职责是将客户注册交易的状态记录在数据库表中。
Example: RegistrationServiceDaoImpl.java
/** *The Registration Services Data Access Strategy implementation *using Hibernate persistence mechanism that support various *registration related business transactions. *@author - Vigil Bose */ public class RegistrationServiceDaoImpl extends HibernateDaoSupport implements IRegistrationServiceDao{
/** * Data Access API to create the new user in the system * @param users - The composite users domain object */ public void completeRegistration(Users users) throws DataAccessException {
getHibernateTemplate().save(users); }
}
任何应用程序中,访问只读数据都是重要的。让我们看一个普通java接口——ILookUpServiceDao的例子,它在CRS中被用到,其暴露了finder和getter方法以访问只读数据。
Example: ILookUpServiceDao.java
/** *A POJO data access object interface that exposes the lookup API's in Customer *Registration System. *The API's defined in this interface can be used with or without any other *transactional APIs within the business services layer *@author - Vigil Bose */ public interface ILookUpServiceDao{ /** * Data Access API to find the event instance based on its primary key * @param eventId - The event tables primary key identifier */ public Event findEventById(Integer eventId) throws DataAccessException;
}
下例是Hibernate实现策略。ILookUpServiceDao接口中的API定义在具体类LookUpServiceDaoImpl中被实现。为了简单,这里只显示了一个API实现。
Example: LookUpServiceDaoImpl.java
/** *A POJO data access implementation that implements the lookup API's in Customer *Registration System. *The API's defined in this interface can be used with any other *transactional APIs within the business services layer *@author - Vigil Bose */ public classe LookUpServiceDaoImpl extends HibernateDaoSupport implements ILookUpServiceDao { /** * Data Access API to find the event instance based on its primary key * @param eventId - The event tables primary key identifier * @return an instance of Event domain object * @throws DataAccessException */ public Event findEventById(Integer eventId) throws DataAccessException{ return (Event)getHibernateTemplate().get(Event.class, eventId); }
}
Spring框架提供的HibernateDaoSupport类是一个模板模式实现,其抽象了Hibernate相关API和与Hibernate Session相关的资源管理。
有了数据访问实现,我们对业务需求的一个方面——客户注册过程——感到满意了。现在我们将考虑需求的第二个方面,它是在设计期间所确定的子系统功能。该需求是这样的:当注册完成时,系统将发送邮件通知给客户并传送客户地址数据给发票系统以产生发票。我们将通过著名的命令模式来实现子系统处理过程。
命令模式
命令模式用来提供一个公共接口以执行不同的命令。任何实现了该命令接口的类可以在其execute()方法中提供特定任务的实现。
在设计期间,我们已经确定了针对同一接口的两个不同命令实现。就业务服务层来说,子系统功能是一个单独的关注点。因此我使用AOP技术将这个单独的关注点从主要业务服务层实现(RegistrationServiceImpl)中解耦。
想更多了解AOP概念的人,请点击这里。你还可以从下面看到一些关于AOP的介绍。现在,让我们设计命令接口。
Example: ICommand.java
/** *ICommand.java - The famous command interface that exposes the execute API. *@author - Vigil Bose */ public interface ICommand{
/** *The Command design pattern encapsulates the concept of the *command into an object. The issuer holds a reference to the *command object rather than to the recipient.The issuer sends *the command to the command object by executing a specific *method on it. The command object is then responsible for *dispatching the command to a specific recipient to get the *job done. *@param data - The data transfer object */ public void execute(Object data);
}
典型的命令实现提供了打包一组计算的方法(一个接收者和一组动作)并把它作为第一级别对象向周围传递。该命令对象调用请求命令接收者(receiver)的方法以真正处理请求。通常也能发现一个命令实现自己处理特定任务,无须委派请求给receiver。在本例中,MailingCommandImpl通过调用EmailService实现了发送邮件通知的任务。为简单起见,EmailService实现没有在本例中展现。毕竟,我们的意图是展现业务事件是如何借助于AOP和Spring2.0被路由到子系统处理器的。
Example: MailingCommandImpl.java
/** *MailingCommandImpl.java - A command implementation that implements *the task of sending mail notification to the customer who completed *the registration process. *@author - Vigil Bose */ public class MailingCommandImpl implements ICommand{
private IEmailService emailService;
/** *A setter method of dependency injection *@param emailService - The emailService instance to set. */ public void setEmailService(IEmailService emailService){ this.emailService = emailService; } /** *API execute is used to execute the mailing tasks implemented *@param args - An instance of AbstractData used in business service layer */ public void execute(Object args){
//get the reference of user object User user = (User)args;
//get the reference of address object via its parent object User. Address address = user.getAddress()
//Invoke the EmailService API here to send out the notifications....
} }
现在,我将设计第二个命令实现,它将帮助我们实现关于传送客户地址数据到发票应用的业务需求。在这个特定实现中,我们可以选择任何协议(如Web服务、消息传递,或 XML over Http等等)来发送客户信息到发票应用(假设发票应用可以使用上面提到的任何协议用作应用集成)。为了简单,下面给出的是使用JMS消息传递的例子。本例并没有展示JMS消息传递的内部结构。
Example: SendCustomerInfoCommandImpl.java
/** *SendCustomerInfoCommandImpl.java - A command implementation that implements *the task of transmiting the customer's address data to the invoice system. *@author - Vigil Bose */ public class SendCustomerInfoCommandImpl implements ICommand{
private IMessagingService messagingService;
/** * A setter method of dependency injection */ public void setMessagingService(IMessagingService messagingService){ this.messagingService = messagingService; }
/** *API execute is used to execute the messaging task implemented. *@param args - An instance of AbstractData used in the business service layer */ public void execute(Object args){
User user = (User)args;
//Invoke the appropriate messagingService API //to send the customer information here.... } }
AOP的基本概念
AOP也被称为Aspect Oriented Programming(面向方面编程)试图帮助程序员分离关注点,尤其是横向切面关注点(cross-cutting concerns)。过程、包、类及方法都是帮助程序员把关注点封装到单一实体内。但是有些关注点不适合这种形式的封装。我们称之为横向切面关注点,是因为它们横跨了程序中许多模块。它可能使代码分散或缠结(scattered or tangled),使人们更难理解和维护。当一个关注点(例如本利的事件路由)蔓延到许多模块(类和方法)时,代码被分散了。这意味着修改事件分发功能可能需要修改所有受影响的模块。
代码失去了典雅和简单,因为各种新的关注点已经与基本功能(有时称为业务逻辑关注点)缠结在一起。事务、消息传递、安全以及日志都是横向切面关注点的例子。
AOP试图通过让程序员在一个单独的称之为aspect的模块中表达横向切面关注点来解决这些问题。Aspect可以包含advice(加入到程序指定点的代码)和inter-type声明(增加到其他类的结构成员)。例如,一个安全模块可以包含在访问一个银行账户前执行安全检查的advice。pointcut定义了一个银行账户能被访问的时机(加入点,join points),而在advice体内的代码定义了安全检查是如何实现的。使用这种方式,检查代码和位置点可以在一个地方维护。更进一步,好的pointcut可以预见后期程序变动,因此如果另一个开发者创建了一个新的方法来访问银行账户,在其执行时advice将应用到该新方法上。占据领导地位的AOP实现是AspectJ、AspectWorkz、Spring AOP等等。
Spring AOP用纯Java实现。不需要特殊编译处理。AspectJ需要特殊编译处理。Spring AOP不需要控制各层级类装载器,因而适合用在J2EE web容器或应用服务器中。Spring 2.0还提供了与AspectJ的紧密集成。
事件路由
为了满足我们的业务需求,我以及确定了两个AOP组件。它们是RegistrationBeforeAdvice和RegistrationAfterAdvice。请参考Spring参考文档以获得更多关于各种AOP advice和其他概念。
识别出两个AOP组件背后的基本原理是支持事件路由和在代码中最小化交叉依赖。RegistrationBeforeAdvice的职责被限制在识别和收集适当的业务事件。该before advice的Spring AOP实现可以被配置在Spring应用上下文配置文件(Spring application context file)中,以截获业务服务接口API来注入定制行为——识别并增加正确的业务事件到事件集合中。
本例中,RegistrationBeforAdvice截获业务服务接口的doRegister(AbstractData data)API。该advice访问该服务接口API的入参(AbstractData)。早期在AbstractData层实现的事件集合在这里也变得垂手可得。RegistrationBeforeAdvice识别恰当的业务事件并把它增加到event集合中。
Spring应用上下文中的eventMap配置是一个全局事件映射(global event map)。eventKey将适当的业务服务接口API名称映射到事件标识符。这让我们可以在全局事件映射配置中无缝地将一个定义在业务服务接口的新的业务API映射到一个事件id,而无需修改RegistrationBeforeAdvice AOP组件的任何代码。然而,对这种方法有一个警告。当程序员犯了错误,在全局事件映射配置中配置了错误的方法名到eventId,这种错误在编译期间并不容易发现。但是一个简单的Junit测试即可发现这种用词不当的错误。
业务API名称:doRegister Event Id: 1
映射另一个业务API名,如doUpdate(),到另一个值为2的事件id现在变得非常容易了。我们所要改变的只是在接口中定义新的API之后,在Spring应用上下文配置文件的事件映射中增加一个映射即可。下例给出了配置片断。
<!-- creates a java.util.Map instance with values loaded from the supplied 'sourceMap'.Global Event Map. The values are mapped in event table. The keys are matched with the business API name--> <util:map id="eventMap"> <entry key="doRegister"> <value type="java.lang.Integer">1</value></entry> <entry key="doUpdate"> <value type="java.lang.Integer">2</value></entry> </util:map>
在某些情况下,单个业务处理可能导致多个事件。这仍只需轻微修改RegistrationAfterAdvice(译注:疑为RegistrationBeforeAdvice )的代码及事件映射配置即可。这种情况下,我们需要说明每个业务交易的事件列表。为简单起见,本文例中只限于展示一个业务交易仅有一个事件的情况。
请参考下面的代码样例,实际看看before advice。
Example: RegistrationBeforeAdvice.java
/** *RegistrationBeforeAdvice.java - This advise acts before the doRegister() API in *the business service interface executes and sets the appropriate event in the *eventSet collection implemented in the AbstractData layer. The event is Customer *Registered Event. This advice inserts custom behavior in IRegistrationService API *doRegister() before it is executed and identifies the correct business event add *it to the event collection *@author - Vigil Bose */ public class RegistrationBeforeAdvice implements MethodBeforeAdvice{
private Map eventMap; private ILookUpServiceDao lookUpServiceDao;
/** * A setter method of dependency injection * @param Map - The eventMap instance to set. */ public void setEventMap(Map eventMap){ this.eventMap = eventMap; } /** * A setter method of dependency injection * @param lookUpServiceDao - The lookUpServiceDao instance to set. */ public void setLookUpServiceDao(ILookUpServiceDao lookUpServiceDao){ this.lookUpServiceDao = lookUpServiceDao; } /** *Before advice can insert custom behavior before the join point *executes, but cannot change the return value.If a before advice *throws an exception, this will abort further execution of the *interceptor chain. The exception will propagate back up the *interceptor chain. If it is unchecked, or on the signature of the *invoked method, it will be passed directly to the client; otherwise *it will be wrapped in an unchecked exception by the AOP proxy. *@param method - method being invoked *@param args - arguments to the method *@param target - target of the method invocation. May be null *@throws Throwable - if this object wishes to abort the call. *Any exception thrown will be returned to the caller if it's allowed *by the method signature. Otherwise the exception will be wrapped *as a runtime exception *@see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method *java.lang.Object[], java.lang.Object) */ public void before(Method method, Object[] args, Object target) throws Throwable {
AbstractData data = (AbstractData)args[0];
Set keySet = this.eventMap.keySet(); Integer eventId;
Event event = null; String eventKey = null;
//Iterate through the key set and extract event identifier and //retrieve the event from the database and add it to the event //collection.
for (Iterator iter = keySet.iterator(); iter.hasNext();) { eventKey = (String) iter.next();
//Check whether the eventKey is matched with the business //service interface API name. If it does, extract the eventId //and retrieve the event instance from the datastore and add it //to the event collection.
if (eventKey.equalsIgnoreCase(method.getName()){ eventId = (Integer)eventMap.get(eventKey);
event = this.lookupService.findEventById(Integer eventId); data.addToEventSet(event); } } } }
本例中,一个需考虑的设计限制是Before advice或After advice组件抛出的异常应该不影响在线业务交易。在线客户不应受到事件路由错误的惩罚。为简化起见,我没有在该例中展示如何处理异常。
RegistrationAfterAdvice负责迭代事件集合、动作代码以及初始化路由过程。本例中使用的动作代码是M和T。在Spring应用上下文配置文件中每一个动作代码都有命令与之映射。RegistrationAfterAdvice通过每个与事件(客户注册事件)相关联的动作代码及获得映射的命令对象实例对事件集合进行迭代。一旦命令对象引用被获得,路由自动地发生,通过传递客户数据给每个命令实现以执行适当的任务。
Example: RegistrationAfterAdvice.java
/** *RegistrationAfterAdvice.java - This advise acts after when the doRegister() *API of the business service implementation is executed. This advise will *actually delegate the event actions associated with the Customer Registered *Event to the appropriate command. This advice inserts custom behavior to *IRegistrationService interface API's after the API is executed. *@author - Vigil Bose */ public class RegistrationAfterAdvice implements AfterReturningAdvice { /** *After returning advice is invoked only on normal method return, *not if an exception is thrown. Such advice can see the return *value, but cannot change it. * *@param returnValue - the value returned by the method, if any *@param method - method being invoked *@param args - arguments to the method *@param target - target of the method invocation. May be null *@throws Throwable - if this object wishes to abort the call. *Any exception thrown will be returned to the caller if it's allowed *by the method signature. Otherwise the exception will be wrapped as a runtime *exception *@see org.springframework.aop.AfterReturningAdvice#afterReturning *(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], *java.lang.Object) */ public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
AbstractData data = (AbstractData)args[0]; User userInfo = (User)data.getUser(); Set eventSet = data.eventSet();
Set keySet = this.commandMap.keySet(); Event event = null; String actionCodes = null; String actionCode = null;
//Iterate through the event set for (Iterator iter = eventSet.iterator(); iter.hasNext();) {
event = (Event) iter.next(); actionCodes = event.getEventActionCodes();
//Loop through the action codes and extract each command mapped to //the action code in spring application context file.
for (int i=0; i < actionCodes.length();i++){ actionCode = new Character(eventActionCodes.charAt(i)).toString(); command = (ICommand)commandMap.get(actionCode); if (command != null){ command.execute(userInfo); } } } } }
在上面例子中可以看到,我本可以在RegistrationAfterAdvice本身实现事件集合和事件路由机制。但为了保持事件集合和事件路由的责任分离,我决定使用两个AOP advice组件处理子系统路由功能。
完整配置
现在,在Spring应用上下文xml文件中将所有配置都串起来。在下面的例子中,Hibernate实现被用作数据访问层的数据关系映射(OR映射)。当应对多个资源提供者(如数据库和JMS)时,推荐使用JtaTransation策略。为简单起见,下例中只展示了本地事务策略。
Example: applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd"> <bean id="registrationService" class="RegistrationServiceImpl"> <property name="registrationServiceDao" ref="registrationServiceDao"/> </beans> <bean id="registrationServiceDao" class="RegistrationServiceDaoImpl"> <property name="sessionFactory" ref="sessionFactory"/> </beans> <bean id="lookUpServiceDao" class="LookUpServiceDaoImpl"> <property name="sessionFactory" ref="sessionFactory"/> </beans> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"/> <property> name="dataSource" ref="dataSource"/> <!-- Use the following property jtaTransactionManager when dealing with CMT transactions --> <!-- <property name="jtaTransactionManager" ref="jtaTransactionManager"/>--> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> <prop key="hibernate.connection.pool_size">3</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.generate_statistics">true</prop> <prop key="hibernate.cache.use_structured_entries">true</prop> <prop key="hibernate.max_fetch_depth">3</prop> <prop key="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.region_prefix">node1</prop> </props> </property> <property name="mappingResources"> <list> <value>Users.hbm.xml</value> <value>Address.hbm.xml</value> </list> </property> </bean> <bean>id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!-- <bean id="jtaTransactionManager" class="org.springframework.jndi.JndiObjectFactoryBean"> --> <!--The JNDI name of TransactionManager published in OC4J Container in 10g--> <!-- <property name="jndiName" value="java:comp/pm/TransactionManager"/> </bean> --> <!-- Transaction manager that delegates to JTA for ultimate coordinate of transactions --> <!-- <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>--> <aop:config> <!--Format: execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)--> <!--The pointcut expression here is the execution of any public method defined by the IRegistrationService interface--> <aop:pointcut id="registrationServicePointcut" expression="execution(public * *..IRegistrationService.*(..))"/> <!-- Here: applying the advice named "registrationBeforeAdvice" to all methods on classes named RegistrationServiceImpl. --> <aop:advisor pointcut-ref="registrationServicePointcut" advice-ref="registrationBeforeAdvice" order="1"/> <!-- This definition creates auto-proxy infrastructure based on the given pointcut, expressed in AspectJ pointcut language. Here: applying the advice named "registrationServiceTransactionAdvice" to all methods on classes named RegistrationServiceImpl.--> <aop:advisor pointcut-ref="registrationServicePointcut" advice-ref="registrationServiceTransactionAdvice" order="2"/> <!-- This definition creates auto-proxy infrastructure based on the given pointcut,expressed in AspectJ pointcut language. Here: applying the advice named "registrationAfterAdvice" to all methods on classes named RegistrationServiceImpl. --> <aop:advisor pointcut-ref="registrationServicePointcut" advice-ref="registrationAfterAdvice" order="3"/> </aop:config> <!-- Transaction advice definition, based on method name patterns. Defaults to PROPAGATION_REQUIRED for all methods whose name starts with "do". By default, the transaction is rolled back for runtime exceptions including DataAccessException. --> <tx:advice id="registrationServiceTransactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="do*"/> </tx:attributes> </tx:advice> <bean id="registrationBeforeAdvice" class="RegistraionBeforeAdvice"> <property name="order" value="1"/> <property name="eventMap" ref="eventMap"/> <property name="lookUpServiceDao" ref="lookUpServiceDao"/> </bean> <bean id="registrationAfterAdvice" class="RegistrationAfterAdvice"> <property name="order" value="3"/> <property name="commandMap"> <map> <entry key="M"><ref bean="mailingCommand"/></entry> <entry key="T"><ref bean="sendCustomerInfoCommand"/> </entry> </map> </property> </beans> <bean id="mailingCommand" class="MailingCommandImpl"> <property name="emailService" ref="emailService"/> </beans> <bean id="sendCustomerInfoCommand" class="SendCustomerInfoCommandImpl"> <property name="messagingService" ref="messagingService"/> </beans> <bean id="messagingService" class="MessagingService"> <property name="jmsTemplate" ref="jmsTemplate"/> </beans> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="defaultQueueConnectionFactory" /> <property name="defaultDestination" ref="defaultQueueDestination" /> </bean> <!-- JNDI Lookup configuration for event queue connection factory used in messaging --> <jee:jndi-lookup id="defaultQueueConnectionFactory" jndi-name="EVENT_QUEUE"/> <!-- JNDI Lookup configuration for event queue destination used in messaging --> <jee:jndi-lookup id="defaultQueueDestination" jndi-name="EVENTQueue"/> <!-- JNDI Lookup configuration for DataSource in J2EE environments --> <jee:jndi-lookup id="dataSource" jndi-name="jdbc/userDS"/> <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host" value="localhost"/> </bean> <bean id="emailService" class="EmailServicesImpl"> <property name="mailSender" ref="mailSender"/> </bean> <!-- creates a java.util.Map instance with values loaded from the supplied 'sourceMap'.Global Event Map. The values are mapped in event table. The keys are matched with the business API name--> <util:map id="eventMap"> <entry key="doRegister"> <value type="java.lang.Integer">1</value></entry> </util:map> </beans>
AOP——Aspect Oriented Programming是程序设计中相对比较新的概念。该技术是对面向对象技术的补充,并带来了更多强大能力和关注点的分离,而这些正是面向对象技术的弱项。
结论
关注点分离是开发面向服务架构的关键原则。它需要被分别应用到基础架构层和实现层。本文中,我们示范了如何使用Spring框架的依赖注入原则和AOP特性分离出横向切面关注点。正如你已经在例子代码中看到的,使用这一方法能让我们把处理服务每个关注点的代码的交叉依赖减到最小。
参考
Spring参考文档: http://www.springframework.org/docs/reference/
免责
请将所提供的代码更多的视为示范使用的例子,而非被证明准备就绪的产品。如果你使用了这些代码并发现有任何问题,请通知我以便更新。
查看英文原文:Dynamic Routing Using Spring framework and AOP
7月21日消息,据国外媒体报道,微软计划在3年内推出继Windows Vista之后的新版操作系统,内部代号为“Windows 7”。
尽管Windows Vista上市还没有几个月的时间,但据知情人士透露,微软已经开始在讨论下一代操作系统。据悉,下一版操作系统的内部代号为Windows 7,预计在3年内上市。
与Vista一样,Windows 7也将分为个人版和企业版,而且也分为32位和64位两种版本。目前,关于Windows 7的其他信息还比较少,但微软计划将更多的信息提供给企业用户和合作伙伴。
Windows 7此前的开发代码被称为“维也纳(Vienna)”,微软代表已经证实,Windows 7是下一代操作系统的内部代码。
事实上,微软现在就讨论Windows 7并不足为奇。因为Windows Vista用了5年时间才上市,已经是备受业界指责。而包括CEO史蒂夫·鲍尔默在内的微软高层此前也曾表示,下一代操作系统绝对不会用5年时间。
7月11日消息,据国外媒体报道,网络安全研究人员仲尼·郎近日表示,随着搜索引擎功能的日益完善,以及越来越多的信息涌入互联网,Google已经成为黑客发送攻击的得力助手。
当仲尼需要某些信息时,他和大家一样,都选择了Goolge。但是,与一般网民搜索新闻或电影等内容不同,仲尼所要查找的是信用卡信息、保护保证号,或企业服务器上的其他私人信息。
当然,仲尼并不是要发动攻击,这只是他工作内容的一部分。他是IT服务公司“计算机科学”的安全研究员,同时也是一名黑客,并撰写过黑客技术书籍。
仲尼近日在接受《福布斯》采访时表示,利用Google搜索引擎,他可以搜索到很多私人信息,如信用卡号码、社会保障号,以及其他很多发动攻击所需要的身份信息。
仲尼称,在一些教育机构站点,他搜到了全部的Excel表格,上面有学生名称、社会保障号和学分。而且,这只是小儿科。仲尼利用Goolge还可以侵入到SQL服务器,直接获取数据库信息。
随着搜索引擎使用频率的增高,再加上Web 2.0的流行使越来越的私人信息暴露在互联网上,仲尼认为,Google对黑客的帮助作用将越来越强大。
十二年之前,Sun公司默默宣布了一种可以使网页更动感和更富有活力的编程语言及其环境。当然,目前Java语言已经成为了一种普遍使用的工具,不仅仅用于为网页添加更多的动态效果,还包括创建和生成这些网页(透过servlets和JSP技术),提供一个用于事务性过程和商业逻辑的平台(透过EJB技术,即Enterprise Java Beans),访问消息系统(透过JMS技术,即Java Message Service),访问关系型数据库(透过JDBC技术),甚至于访问不同的主机(透过Java Connector API技术)。但这个故事还远远没有终结,每天,以Java为中心的社区通过开源的努力和大量的项目变得越来越强大,甚至于官方的Java平台也不断地通过Java Community Process这样一个开放性的国际组织来进行构建、成长和对自身进行增强。
六年之前,微软大张旗鼓地宣布了一系列崭新的编程语言和应用于各种开发场景下的环境。在此之后,.NET已经出现了两个发行版本。每一个主要的发行版本都会对运行时和三款主流的语言(C#,C++和Visual Basic)产生巨大的改变,同时也会为客户层和服务层带来许多新特性,如事务的支持(System.Transactions),泛型的支持(同时支持C#和Visual Basic),目录服务支持,管理(WMI)等等。这个故事也远远没有终结,微软甚至计划将一系列新技术应用到其下一个发行版本中(NetFX 3.0, 随Vista发行)。一个急速增长的社区也依然在不断扩大,并用开源和商业的新项目以及新构想增强了.NET环境。
在这几年中,在Java和.NET环境之间产生了大量的讨论,大多数的讨论都强烈地倾向于两者中的一方,这几乎没有产生任何作用。毕竟,诸如“我的编程语言比你的编程语言要好”或者“我的平台比你的平台运行得要快”,乃至于“你们很逊”这类的话题或许在鸡尾酒会和小组会议上是一个你来我往的颇为有趣的话题,但是这些话题对于引导一个有意义的软件开发是没有任何成效可言的。在经历了立场和姿态上的对立以及互相攻击以后,当尝试使.NET和Java共同工作和对此进行有意义的讨论时,这些对话却又转向了一些诸如“Web服务”、“企业服务总线”或“面向服务的体系架构”等繁杂的词汇中,而没有任何实在的展示。当越过这些高层的讨论去关注底层的细节时,对话中经常出现的又是SOAP、WSDL和WS协议,或者通过消息交换数据,或者在CLR中实现JVM,或者在JVM中实现CLR等。
换句话说,来解释这些流行的用语即“你大步迈进并讨论这如何去解决这个问题,但是却从来没有真正得讨论为什么你要这样做” 从历史的角度看,关于Java/.NET互操作性的讨论降低到了体系结构的次要位置,仅次于“按需”主题——也就是说这种互操作的发生仅仅应该在一个企业同时使用.NET和Java系统,并且需要在它们之间进行对话时。尽管如此,在这个讨论中关于动机问题的讨论被忽视了——为什么开发人员想要同时使用Java和.NET?尽管可能不需要这样做。
从表面上看来,这是一个危险的主题。因为不是由于对某个平台“不能”做什么的暗示而招致完全的义愤,就是任何关于某个平台可能在某方面“优于”另一个平台的说法都会导致偏爱或无知的谴责。(这甚至忽略了一个基本的问题,即指出这里的“优于”的定义是什么)。与其无视或躲避这个话题,不如直接面对它。这样的谴责和批评是不应该被忽略的,事实上我们应该欢迎它们,并将其作为一个大讨论的一部分,这个大讨论将解答何时、何地以及如何做出这些决策。尽管这样,我们认为开放式的讨论,时刻检查思想,允许读者形成自己的、批判的观点依然非常重要。
本文作为关于Java/.NET互操作性主题系列文章中的一篇,也正是基于此观点进行的。
* * *
当在大脑中思索什么是Java和.NET都做的好的方面时,有好几个场景会浮现于我们的脑海并值得我们向前探索。
Office客户端,J2EE服务器
微软的Office产品,无论好坏,即使在有电脑的历史以来不是最流行(这里所说的流行是指安装在更多的电脑主机上)的软件平台,也必然是最流行的软件平台之一。目前,Office产品已经迎来了第二个十年,作为一个强大的平台,用户可以输入,维护和查看广泛的、不同来源的数据。对于那些目前依赖于J2EE后台服务器的用户来说,既然有相当数量的数据,那么将这些数据转入Office平台来实现更加简单的管理和考察将是一个很好的考量。更让人感兴趣的是来考察Office平台利用过程无关的通信工具、实现利用Spring或其他轻型Java容器中业已实现的商业逻辑的方式。
在2006年8月发行的MSDN杂志发表了数篇关于Office开发的文章(并为此强烈建议任何对于Office编程能力不熟悉的人将此作为背景材料),在以“使用Office作为一个开发平台的须知”为题的一篇文章中,用一个图表展示了Office平台的全部能力。这里我们没有卷帙浩繁地列出完全名单,而是用一块区域简单列出Office可以与Java平台进行良好互动的几点特性:
-
外部自动化。由于COM自动化技术的强大,COM自动化的后继者,Visual Studio Tools for Office (VSTO),这个主要的Office,包括Word、Excel、 Outlook 和其他应用程序等,组件可以被外部的应用程序接口所驱动,因此,各种Office文档就可以通过一些通用语言从外部创建。拿Excel的强大的图表和计算功能或者Word的强大的编辑和拼写检查功能来说,考虑在Java应用程序如何结合这些功能来实现何种新功能将十分有趣,在服务器上(如一个Web应用程序可以驱动Word来创建一个顾客邮件或者打印由J2EE服务器传入的包含特定数据元素的报告文本,就像使用Velocity引擎填充模板生成HTML的方式一样),或者是在客户端,利用Eclipse富客户端平台,一个已经实现可以作为COM自动化组件的宿主(事实上,Eclipse可以在一个安装有Office的Windows操作系统里创建Word文档)。当用户仅仅需要查看Word文档而不是创作Word文档时,这就显得尤其重要。微软提供了一个免费的Word查看程序,如果Java的Web应用程序负责创建Word文档,然后通过HTTP协议在网络上传送,这样就可以提供一个比HTML更加丰富的格式。
-
插件。Office也可以提供插件功能,一些软件组件作为插件在Office的内部运行,通常的情形是将它们自身作为一个主菜单项或者一个上下文菜单。一个.NET组件可以将其自身注册为一个Excel电子表格应用程序插件,使用一些形式的Java互联技术(Web服务,远程调用工具包或其他过程内宿主)来连接Java的商业组件用于验证、数据获取或存储。比如,很多公司使用Excel作为一个发票和/或会计解决方案,而且他们可能使用了一些Java组件作为一个简单的进出公司会计系统的方式。这个会计系统一般是庞大的、基于Java技术的一个应用程序包,运行在一个企业级的服务器上,通过EJB中的会话Bean提供的Java连接器进行访问。
-
Excel用户自定义函数。Excel在其计算引擎中已经提供调用用户自定义函数功能有非常久的时间了,从历史来看,这些函数必然是使用非托管的(原始C++)代码编写而成,这些代码为应用程序带来了危险的不稳定性。创建一个Excel中的用户自定义函数为应用程序服务器中业已存在的商业逻辑进行一个简单的包装——比如一个存货支票调用Excel表格模板来生成一个订购单——可以提供给对大多数Excel用户来说Excel不曾给过的强大的在线体验。
-
智能标记。智能标记是微软为文档中的一些小方框所起的新名称,这写文档中的小方框包含一个箭头,一般位于感兴趣的内容旁边。在文档中,智能标记经常会被配置和自定义特殊的元素,比如说在Word的自动纠错中,如果Word认为出现了一个打印错误,那么在被纠正的单词上方悬停鼠标就会出现一个智能标记,在没有出现真正的错误的情况下,允许用户选择取消这个纠正。智能标记就是插件的一种形式,因此其他帮助用户弥补客户端和企业服务之间裂痕的可视化辅助组件也可以使用此种形式。
Office同样为那些使用了纲领性元素的组件和文档提供了一些部署的支持,因此在很多情况下,在这些组件内进行功能的升级就像到一个共享下载服务器发布一些东西一样简单。显然,一个主要的考虑是使用Office将出现许可费带来的成本,但幸运的是,大多数商业环境应该都已经部署了Office环境,减少了显著增加的费用。
Spring和J2EE容器中的Windwos工作流
Windows工作流是微软在“NetFX 3.0”发行版本中的发行的一个新框架,它将随着Windows Vista操作系统被同时安装。工作流的目的是提供一个方法,这个方法使得商业过程功能——或许是一个小规模的应用,比如网站中网页的交互,或许是一个大规模的应用,比如签署一个保险协议的主要过程——可以被非开发人员创建、查看、跟踪和编辑等。工作流的开发人员(或者是传统的.NET开发人员,或者是领域专家)使用一个类似流图表工具的环境设计工作流,这些工作流由一些活动组成,这些活动表示过程当中的一个个逻辑步骤。这个环境将会随Visual Studio一起被普遍提供,但是也可以在一些其他自定义的应用程序中存在,同样也允许公司将工作流的设计者完全剥离出传统的程序员工具之外。工作流设计的结果就是一个格式化的XML文档或代码,然后使用工作流编译器将其编译成一个.NET类,这个类将由工作流运行时处理,运行于各种环境之中,包括ASP.NET,控制台应用程序或者是一个拥有图形用户接口的应用程序等。工作流可以是串行的或是由外界状态改变驱动的,甚至可以跨越很长的时间间隔。
从事实上看,工作流运行时是被设计为易用于各种应用环境和上下文之中,一个最直接的想法就是使用一些连接技术将工作流应用于Spring(或其他J2EE容器)中,比如可能是工作流运行时支撑Spring容器创建自定义的活动,以用于调用Spring中的Bean类执行商业功能,也可能是在Spring的Bean中支撑工作流运行时,来执行对Spring接受的远程调用进行响应的功能。特别是在第二种情况下,终端用户可以设计业务过程并将其执行于传统的企业服务器中。同样,工作流的狂热爱好者已经描述了工作流可以如何被应用,以来结构化ASP.NET应用程序中网页的导航,这样一种方式不同于Structs的action映射文件。在servlet容器中支撑工作流来完成同样的目标是另一种可行的办法,同样也在servlet和JSP网页之间提供了一种可见的“流”,而非目前占据此位置的晦涩的XML语法。
WPF客户端到Java服务
本节将会描述最后一个,但肯定不是最不重要的场景,而且它有可能成为将.NET和Java在一起使用时最富有挑战的场景:在Java强大和可扩展的服务提供的数据模型之上(可能是Spring,EJB,或一些组合),使用新的WPF技术来提供一个丰富而强大的用户界面。WPF所宣称的基于xaml的编程模型,标志着相较于近一个时期以来典型的UI编程模型的重大改变,而且在许多方面都让人很容易地产生复杂的用户界面,这种技术超出了Swing或SWT目前所能够实现的。另外,由于xaml是一种基于文本的格式,因此可以动态生成XAML并将其下载到客户端执行,就像现在的HTML一样。
WPF前台与Java后台之间通过WCF进行对话将可能称为一个典型的场景。WCF是微软的新的通信管道,使所有的分布式通信编程模式成为一个单一的架构。除了支持许多最新的WS-*规范,WCF还通过多种途径提供了用于通信的丰富的可扩展性模型,包括通过REST格式(有时称作普通XML,或POX),甚至可能使用其他的通信媒介,比如UDP。Sun通过其Tango项目使得这个办法更加可行,作为一种特定的设计目标,Tango项目可以与WCF无缝集成。
* * *
不言而喻,以上这份列表是很难列出Java和.NET之间进行可能的互操作的所有场景的。事实上,为了让这篇文章处于一个可控的长度,在这儿我们忽略了下面几种可能性:
-
采用Eclipse的富客户端平台作为客户端,要么部署一个通过由DCOM向.NET/COM+通信的服务组件,要么部署一个WCF服务。
-
在一台部署了Excel计算引擎的Windows Server 2003机器中采用Swing客户端和/或Java Web Start创造一种便携式、可下载、零部署客户端应用解决方案。
-
在一个SWT应用程序中利用DirectX提供本地的3D效果(包括音效)。
-
使用微软的语音服务器,以提供交互式语音识别(IVR),而“前台”使用一个Swing或J2EE应用。
等等,等等,等等。
听起来好像这一切都是牵强和不合理的煽情,就像在脑海里浮现出那帮拥有大量时间但却没有常识的营销人员所作的事。当Java拥有公式引擎时何必使用Excel?当我们拥有JAX-WS时何必使用WCF?当我们拥有Java3D时何必使用WPF?让我们坦然的面对如下事实:.NET能做的任何事,Java都可以做到,反之亦然。免得我们因为偏爱某项技术被指责。但我们也尤其须要坦白承认的一个事实是:两种平台各有特殊的兴趣领域,并且它们在各自的领域做得都很好。开发人员愿意抛开立场偏见,进行开明的讨论,并发挥各自平台的优势以导致一些更大的利益。或是宽泛地引用卡尔?马克斯的一句名言,“对每一个项目而言,应该根据自己的需要充分发挥其所需平台的能力。”( From each platform, according to its abilities, to each project, according to its needs.)
查看英文原文:Java, .NET, But Why Together?
我曾撰写的文章《从Java到Ruby:所有管理者需要知道的事情》并非是为程序开发者所写,而是写给技术选用的决策者看的。在理解Ruby难点以及使用Rails框架方面,Ruby拥护者们为刚起步的开发者做出了大量值得称赞的工作,但是对于管理者和执行人员来说,并没有足够的信息帮助他们在众多技术之间做出选择。在这个系列的上一篇文章中,我们探讨了在Java在线商店中建立向导项目的策略。在这篇文章中,我们将要探讨Java与Ruby语言迁移时风险预测方面的问题。
通常来说,“使用Ruby具有风险”是一种普遍的看法,这存在一定的原因。因为使用新的语言天生是有风险的。随着Ruby on Rails逐步进入到主流的开发领域中,这样的风险将会随时间逐渐降低,因为有逐步增长的开发者群、组件(或称作gems和plug-ins)相关的书籍、以及业务合作伙伴与你沟通交流。但同时你也可以听到主流的观点指出“使用Java是安全的”。对于这种的观点,我持有强烈的反对意见。随着语言的膨胀,这样的风险通常也会增长。为了便于理解在目前在这些观点上正发生什么变化,投入点精力去研究Java最初的应用情况是值得的。
新技术采用概况
许多分析家拥有技术应用所需的描述模型。其中最为流行的模型是定义在Ruby的Web开发框架Iowa中,用来描述农产品的应用,稍后在一本由Geoffrey A. Moore写作的名为《跨越鸿沟》(Crossing the Chasm)的书中,被用来描述技术内容。在书中,Moore分析了技术应用周期中存在着的五个截然不同的群体:
- 技术专家。这个群体倾向于采用新的技术。任何一种有前途的技术都会引起这个群体的注意。
- 先行采纳者。不管这项技术是否在主流技术中取得成功,这个群体都将会采用新的技术来提升竞争优势。
- 实用主义者。一旦新的技术进入主流应用,或是有足够陡峭的增长曲线来保证技术将得到广泛采用,那么实用主义者就会积极采用新的技术。
- 保守派。只有新技术成为必须的时候,他们才会考虑采用新的技术。
- 怀疑论者。这个群体可能很晚才会采用新的技术,或者也可能永远只使用某一特定技术。
Moore指出,技术应用的关键之处在于团队中是否存在实用主义者。因为实用主义者需要新技术大规模的应用,这个中间群体希望看到其他务实派在团队做出承诺之前就使用新的技术。这是一个类似于《第二十二条军规》书中所描述的现象,因为务实派们都会相互依赖的存在。出于这样的原因,在先行采纳者排列在技术专家之后和务实派之前,你会经常在市场接受度曲线中看到一种下降的趋势。Moore将这种下降称之为鸿沟倾向,并且这种想法应出于围绕任何新技术的风险讨论的中心。
Moore解决方法是,把重点放在跨越鸿沟的过程中。通常来说,你很难通过一个巨大的飞跃跨过鸿沟。你需要有一个目标明确的细分市场。Java技术首先通过Applet程序进入网络客户端,之后转向服务端的计算、移动终端、以及其他类似于移动计算以及企业架构的应用,最终为网络带来强大冲击。
在《超越Java》一书中,我认为存在于程序设计语言之间的鸿沟特别严重。我们大多数人都认识到在Lisp语言上投入精力将大幅提高生产率,但是同时也会导致更难找到合适的程序开发人员、教学资源、类库以及组件等。同时我们还将不得不付出更多的花费来进行一些必要的整合工作。出于这个原因,大众市场只会以大约每十年的时间周期更换主流的编程语言。在服务端编程语言方面,可以清晰看到这种趋势的存在。COBOL和Fortran语言出现于1954年到1961年之间。C语言则诞生在上世纪70年代初期,C++是出现在上世纪80年代中期,Java语言则出现在1996年。我应当把C#语言算做整合高效的Java语言克隆版本,虽然这样的说法可能会引发一些争辩。许多其他的语言在此阶段中诞生,但是上述语言仍旧没有一个能够占据统治地位。伴随的风险是阻碍新编程语言被广泛采用的最重要原因。
Java的风险概况
使用Java语言曾经需要克服很大的风险。当时,大多数服务端的编程都在使用C++语言。C++是一门高效的操作系统语言,非常适用于应用程序开发。C语言家族在这方面的表现相当出色,因为客户机/服务器端编程以及用户界面开发需要程序性能与适应性良好地结合在一起,在当时其他的编程语言都无法符合这样的要求。为了克服伴随采用新编程语言而来的风险,Java需要以下的三个条件均成立:
- C++开发者不得不经历一番辛苦的学习过程。指针的存在(由于缺少编译时的安全性)导致各种各样难以消除的缺陷。内存管理使得内存泄漏成为家常便饭。C++对于大多数程序开发者来说,显得过于复杂。这些问题增加了针对于C++语言的风险评估。
- Java需要解决一些C++语言无法处理的工作。Java语言所具有简洁、灵活的特性以及众多C++所不包括的类库支持。这些要素减少了针对于Java语言的风险评估,并可以保持开发团队小型化最终从根本上提高生产力。
- Java需要一个催化剂。随着网络爆炸,Applet应用普遍被嵌入在NetScape浏览器中,使得C语言开发者不得不转向去开始使用Java语言。C++因为和Java语法的类似,可以简单地进行过渡。Java得以迅速获得数量庞大的用户群,并且在同微软的竞争中逐步提升这样的过渡。
Java的膨胀要比我们以前所见的任何一次技术浪潮都要迅速,同时也可能比我一生所见的任何技术都要庞大,然而Java的发展蓝图却一直保持清晰。为了建立新的语言,原有的语言已不适应开发者的需求,新的语言必须要克服原有语言的缺陷,并最终以某些催化效应迅速聚集起数量庞大的用户群。
Java作为Internet应用语言在客户端迅速得到立足。借助于灵巧的Applet应用程序,由于Java提供了对于应用开发者极有帮助的特性,使得Java快速转移到服务器端开发,这些特性包含有:
- 内存管理
- 干净的继承模型
- 更好的面向对象功能
- 便携性
- Internet类库
- 安全
……以及其他许多特性。在我看来,Java一直以来都是最为成功的编程语言。随着Java不断的改进,使用Java语言变得越来越安全,并最终在Internet应用中统领着服务端开发的市场。商业投资,开发者社区,各种教育培训,开放源代码的框架,以及各种各样的信息发布都使得使用Java开发的风险降低。上述几点清晰地解释了Java取得成功的原因。
一旦新的程序开发语言跨越鸿沟,开发语言相关的风险则会随着市场占有率的提升显著减少。
Java则拥有一个令人赞叹的成功过程。但是程序设计语言没有仍旧停留在不确定的技术发展水平之上。所有成功语言都会产生技术膨胀,因为它们必须去适应使用者不断变化的需求。成功的编程语言无法像其他的语言一样快速的适应变化,他们必须保持一定程度上的向后兼容,来满足逐步增长的用户基本需求。随着技术滞后与语言膨胀的产生,另一种形式的风险预测逐步形成。为了新的风险预测,由于风险与程序开发者高效完成工作的能力相关,使得风险与市场占有率的降低有必然的联系。
到目前为止,我已经开始关注于新生技术的市场风险。在Java诞生十周年之际,另一种形式的风险评估成为必须。就像《人月神话》、《死亡之旅》和《人件》等许多有影响力的书籍中鼓吹的那些风险一样:
- 低下的生产力将导致更庞大的团队规模和更长的时间周期
- 风险随着项目的规模而增加
- 风险随着团队规模的扩张而增加
- 质量风险,以Bug的数量来衡量,随着代码行数的增加而增长
- 成本的增长导致风险的增加
- 综合成本随着复杂性的提高而增加
随着程序设计语言或者编程范例的使用有了积累,相对于技术发展水平,语言将会与生产力相关联。项目团队需要增加规模,开发者需要编写更多的代码来解决相同的问题。所有这些因素本身就会增加风险。所有的因素将会导致必然的结论。
由于市场主宰地位的终止,相对于技术发展水平来说,生产力风险与开发语言相关性将会增加。
在Java语言的范畴中,这些情况是否以及如何发生是一个将会引起激烈争论的话题。当然,Java仍然是解决整个一系列企业问题的最佳语言,比方说非常大型的项目,或是比如双相提交或核心对象关系映射等具备特定需求的问题。针对于Java的商业投资从来没有这么强过,并且Java社区一直是保持持续高涨。但是根基中的缺陷逐渐开始显现出来。
Java的企业级JavaBean框架,WS-*风格的网络服务,以及JavaEE的复杂性和宽松度已受到越来越多的批评。James Duncan Davidson,servlet的创始人之一,曾表示Java不再像从前那样方便易用。目前很难给一个普通的Java开发者,讲明白如何解决最一般的编程问题:比如有后台数据库支撑的网络应用。出现的相关证据是,已经出现了很多使用其他语言的开发框架,最为出名的就是Ruby on Rails,在处理小规模问题时具备极高的生产力。资深Java开发者James Duncan Davidson,Mike Clark,Justin Gehtland,Stuart Halloway以及其他许多开发者都证明,在关键的小型项目中使用了Rails之后,获得了非常高的生产效率:具备后台数据库支撑的绿色网络应用。当然,我的个人经验也是可以轻松地使用Ruby on Rails构造、部署并维护这样的应用。
这些报告将会引起广泛的争论,就像是早期关于Java生产力的那些报告一样。还记得,在Java开发广泛普及之前,Java首次出现在各式的小型应用中。开发人员的生产力是驱动Java早先增长期的重要标准。请谨记Moore关于新技术出现的理论。跨越鸿沟最好的方式不是通过一次大的跳跃,而是每次只前进一个小的阶段。
我坚信复杂性和松散的开发效率是使得Java目前正在经历风险的原因。
Ruby与生俱来的风险
比起其他新生的开发语言来,Ruby并没有什么特别之处。缺少商业投资,有限的开发资源,还缺少开发经验,这都为新生的程序设计语言带来了风险。下面是一些我遭遇到的较大的风险。
- 人才的缺乏。很难找到熟练的Ruby开发人员。根据Java的发展情况来看,这样的现状将会很快有所改观,但是就目前来说,如果你计划在很短的时间内组织一个人数较多的Ruby开发团队,其困难程度远比组建相同的Java团队要大得多。
- 缺少经验。许多LAMP相关的语言已经建立了记录跟踪机制。Google使用Python;许多主流的.COM公司使用Perl或C语言。目前仍没有使用Ruby打造的旗舰级应用,来展示Ruby语言强健的可拓展性,或是复杂的企业级集成。我们只是不知道Ruby是否可以解决某些特定类型的问题。
- 部署和配置策略。Ruby on Rails已经出现将近一年的时间,所以在部署和配置方面的经验还不如竞争语言那样丰富。
- 缺少类库支持。Ruby远不如Java语言拥有这么多丰富的类库支持。
- 缺少商业投资。你需要花费很大的力气才能找到Ruby的咨询、培训或承包的机会,并且这些大多数还并不存在。
还有其他许多类似的风险。然而,你可以有效地降低使用Ruby语言的风险,比如采取绩效挂钩的风险预测。虽然开发和部署大型Ruby应用的相关知识积累仍然十分有限,但是你可以在适当的着眼点不断学习新的知识。对于PHP、Perl和Python等LAMP相关语言,业界有着非常丰富的知识积累。在应用部署机制、Web服务器以及非共享可拓展策略等方面都是一致的。
在考虑参与开发的人手时,不要低估你通过对员工进行内部培训来建立高效团队的能力。对于使用Spring、Eclipse、Hibernate和WebWork进行Java开发的新手,我的训练计划常常是为Ruby on Rails开发者指定培训计划的五倍。如果你开始使用具有类似于Ruby特性的开发语言,比方说Perl,Python或Smalltalk,它们可以帮助你很好地起步。如果你打算从零开始培养一个程序员的话,培养一个使用Ruby的开发者,远比培训Java开发者使用最新的一大堆各种框架要合算的多。
想一想那些众多的函数类库,有多少是你真正需要的?如果你需要分布式处理,双相提交,那么就使用Java编程。如果您需要与Microsoft Office的宏完美地整合,那么就使用.NET。但如果你想编写操作系统整合脚本,或编写基于数据库的绿色Web应用,那么Ruby则正是你所需要的。并且你可以经常编写要用到但手边没有的任何程序。我曾协助一家公司工作,他们在两个星期内编写了自己的数据库驱动程序,但仍然比完成项目其他工作所用的时间要多。我还认识一个使用Ruby在四小时内修补现有代码,为程序拓展Oracle支持的开发者。Thoughtworks在很短的开发周期内就发布了RBatis,即Ruby版本的实体关系映射工具iBATIS。
所以当你站在全局考虑时,会感觉到使用Ruby的风险往往被夸大了,尤其是在Java并没有带给你一切所需资源的时候。自己真正去尝试使用Ruby语言,是把这些风险纳入控制范围之内的最好方法。使用Rails开发一些实际的应用,并站在实践的角度上发言。而不要盲目迷信别人的说法。
神话 vs 事实
Rails是银弹。
人们曾经在Rails项目上失败过,并且还将会有更多失败的教训。如果你在没有具备必须技能的情况下使用它,你也将可能面临失败的命运。
与之类似的说明是,如果Java语言不是导致失败的问题根源,那么Ruby将同样不会是你的答案。大多数软件开发问题的出现是与特定技术无关的。如果你正在遭受打击,Ruby on Rails的采用只能加快你遭受打击的速度。
选择Ruby颇具风险,因为你无法预测到错误。
采用任何新的语言,最主要的风险是你将预测到错误,并且错误停滞在使用的类库之中。这的确是一项相当重大的风险,但是这个问题决不仅局限于Ruby语言之中。在Java语言里,你需要就主要类库的使用做出决定,其中任何一个都可能带给你复杂臃肿的代码。你是否会为声明事物选择Spring或EJB 3等技术?Java的持久层架构是不是一个正确的选择,或者Hibernate就是最终的解决方案?关于Web MVC分层的正确选择是什么,是逐步衰落的Struts框架,还是其他更易用的框架?
在Ruby语言之中,选择Web开发框架则相对简单许多。你将很可能与Rails一起工作。语言动态的特性同样各层之间的结构更为简化,通过特定的约定来使得开发配置比Java实现更为明晰。
为Java项目招募人手总是更为容易。
Java拥有数量庞大的开发者群体,但是开发社区之间有着巨大的分歧。如果你想使用一个综合的Java工具集,你的选择是十分有限的。即使你选择了像Spring这样的流行框架,你的团队必须还要学会使用针对给定项目所需的各种类库。在这种情况下,Java的核心力量,过多的函数类库,将会给项目带来副作用。相反,大部分的Ruby开发者都知道Rails框架。此外,你通常需要更多的Java开发者去处理类似的任务。有时,招募Java的开发人员要容易得多。但有时,情况也并不是这样。
Rails无法拓展。
Ruby on Rails其实有很好的延展性。它的缓存模型非常强大,并且非共享的架构在LAMP社区中多次被证明是非常有效的。实际上,我们知道Ruby on Rails完全可以适应较大型应用的要求。我们不知道Ruby on Rails是否可以承受大规模的应用部署。没有固有的架构使我相信这是一条死胡同。对于典型的应用,总之错误的潜伏期是存在于数据库端。
Rails的整合选项十分有限。
Rails对于基于ReST的Web服务有着良好的支持。Ruby同样通过JRuby项目提供对于JVM的支持,以及提供对于微软的CLR运行时的支持。同时Ruby也提供了良好的消息传输支持。最后,为项目选择最好的工具将会帮助你始终处于良好的状态。优秀的开发团队可以在Java和Ruby项目上同时获得成功。
总结:你可以承担什么样的角色?
如果你正在考虑使用Ruby,那么在你身边将会有很多有用的信息。与其他同时在有效使用Java和Ruby的开发者交流。阅读关于开发框架的资料。查找从Java到Ruby的迁移资料。如果你并不想放弃Java,只是想寻找轻量级的开发体验,那么去了解一下那些可以为你带来更多相关体验的项目,比如说RIFE、JMatter或Wicket项目。如果你认为Ruby可能是一个好的选择,那么要留心以下的建议:
- 为项目选择合适的工具。Ruby on Rails并不是银弹,ROR是一个针对以数据库为后台的高度精简的Web应用开发环境。与新的数据库模式配合较好,或者你可以通过变更来适应Rails的各种固有优点。
- 细心计划开发团队的热身阶段。你不需要在Monster.com站点投放广告并在三日之内为项目招募齐全开发人员。但你可能需要考虑培训你部分或全部的开发者,并且招募几个顶尖的Rails开发者,或是请求某些项目咨询来帮助你把项目启动。
- 了解你使用传统方式的结合点。通常,项目中最头疼的部分是定义与外部系统的交互。你最初证明概念的工作需要与某些接触点交互,至少是要明确你在何处对项目感觉到满意。
如果你还是不确定,那么做一个先行者,或是遵从保守派的观点。缓解风险最佳的方法总是优秀的判断能力。
关于作者
Bruce Tate居住在德克萨斯州的奥斯丁,是一位山地自行车和橡皮艇爱好者,同时也是两个孩子的父亲。Bruce已经撰写了9本编程方面的书籍,其中包含两本Ruby的书籍以及五本Java相关的书籍。Bruce还是RapidRed公司的创始人,公司专注于包含Ruby和Rails在内的轻量级开发技术,并提供开发、资讯和培训等业务。Bruce是一位世界范围内广受称赞的优秀演说家、程序员、培训师以及技术顾问。
查看英文原文:From Java to Ruby: Risk
自JavaScript从ECMAScript 版本3那里获得重大更新后,JavaScript 这些年来一直在稳步前进。InfoQ.com一直在关注其官方网站对JavaScript的更新修改。
网景公司为JavaScript 2.0而出品的ECMAScript版本4在网上可以下载了。jQuery项目的创建者,John Resig在自己的博客上发表了一些观点:
我认为JavaScript语言经历了许多不同的阶段:
1 我们需要为web页面写脚本的阶段(Netscape)
2 标准化阶段(ECMAScript的出现)
3 JavaScript并不是一个摆设阶段(Ajax的出现)
4 JavaScript成为一种编程语言
JavaScript在1995由Brendan Eich(Netscape公司的一名工程师)所创建,于1996年早期和Netscape 2一起发布。JavaScript作为一种语言,在过去一直受人们所研究评论,如Douglas Crockford 这么写道:世界上最为误解的编程语言;最近Google的Steve Yegge这么描述:JavaScript是下一代重要的语言。John Resig在它的博客中继续写道:
……JavaScript将会被作为一种重要的编程语言——从web开发的概念中分离出来。
不再基于web使用
在Rails上使用JavaScript,应该承认这个项目是非常好的,但是不幸的,现在绝大多数人都在谈论下一个流行的语言如何到来,宣布对非常流行的Ruby on Rails框架的重写,没有人去关注它。事实上,JavaScript,运行于Rhino,也是我们应该去关注的。
Helma——这个web应用程序框架是在服务器端使用JavaScript开发的,很稳定。
所有这些说法让我认识到:JavaScript最为一种语言还是具有先进性的。虽然它的主要领域将会是web浏览器(新的JavaScript引擎会继续朝这个方向努力);在将来,JavaScript使用在服务器端将会使另外一个很大的领域。
引用Steve Yegge博客中的话:
……因为下一代流行语言将至(或许18-24月,或许更短,我说不准,总之是即将到来)……
许多人看到Steve Yeggie坚信下一代流行语言就是Javascript或者是ECMAScript。在Mozilla 页面,你就会明白网景公司想让JavaScript 2.0和ECMAScript版本4 作为一样的语言,只是JavaScript2.0提供少许几个额外特性。JavaScript 2.0草案规范在这里可以找到。
最近看到不少文章,作者去比较两种或者多种语言以试图证明他喜爱的语言更棒。我仔细观察过,通常而言,这些文章会侧重在其他语言(指非作者喜爱的语言)的弱点上;有时候,会举例来证明其他语言的冗长,得出结论说自己的语言代码更少、更简捷。
在我看来,虽然是针对其他语言的“弱点”,但作者写这样的文章也无可厚非,毕竟这样的文章多依事实说话,起码你可以知道一门语言的优点和另外一门语言的弱点,而且会引起其他“语言人”的关注和争论,无论怎样这对你如何选择编程语言都是有借鉴意义的。以下为编程语言的三大定理,会客观地帮助你。
编程语言基本定理
为了分析编程语言,你首先要知道它们为什么存在。由此引申出我的编程语言基本定理:编程语言的存在是为了让人们明白计算机操作。
编程语言的出现是为了克服人类认知的局限。现代计算机运行的是二进制指令,我们很难面对着“1”与“0”去写程序,我们无法号令机器,所以我们发明了编程语言,借以理解和向计算机传达我们所要的操作。
所以比较任何语言,都应当权衡它们对我们理解计算机操作所带来的方便。
第二定理
如果程序员对一段代码不解,他会弃用或者重写。
比你可以多快地写代码更重要的是,你写的代码可以让后来看到的人多快地理解。
举个例子:parm=10
既然没有声明变量,我怎么断定这行代码是对是错?编译器又没用,因为这完全可以执行,所以我只能通过后面的代码才能明白这段代码是什么意思。所以你也不难理解,为什么在查找错误代码是你会费那么大劲了,即使你知道出错的部分。
第三定理
没有任何一门语言适用于所有编程任务。这条定理很清楚,我不多做解释。
所以在选择编程语言时以下事情应当考虑:
l 常规特性:性能、兼容性、操作……
l 团队大小
l 代码多少
l 代码的寿命
l 应用领域
l 工具:选择语言考虑的最后一个问题是工具的支持。一个合适的编辑器对于你编程所起的作用不亚于语言本身的语法
按照Mozilla的规划,Firefox 3.0将做出一些革命性的改变,比如使用尚未发布的Gecko 1.9渲染引擎,引入图形显示引擎Cairo,全方位改善性能、稳定性和安全性,调整用户界面等等。
以下就是Mozilla社区在过去几周内的工作成果:
1、新的书签、标签和历史管理器“Places”
在Firefox 3.0里,“Places”全面负责管理书签、历史和其他网页信息。该功能目前还处于开发阶段,最终版将支持书签标签、全文索引、扩展元数据搜索、内置同步、多种格式导出等功能,尤其会在书签的分类整理和管理方面进行增强,可以轻松找到自己需要的网址。
2、恶意软件检测
与Firefox 2.0阻止可能会窃取私人信息的网址一样,Firefox 3.0会把试图在用户计算机上安装恶意软件的网址拒之门外。Mozilla正在就此与Google展开合作。
3、统一内容管理
现在的Firefox在处理各种不同类型的内容的时候,比如MIME、RSS、协议、下载程序,会使用不同的对话框。Firefox 3.0则会在内容处理的内部架构上实现统一化,并使用一致的内容管理用户界面,可以让用户在同一个对话框内选择对不同内容的操作方式。简单来说,就像是Windows XP的自动播放提示窗口。
4、微格式(MicroFormat)检测
Firefox 3.0可以自动检测网页上下文里的微格式内容,并使鼠标光标随之改变、与之交互。
5、隐私浏览(Private Browsing)模式
在进入隐私浏览模式后,Firefox 3.0不会存储任何与用户有关的个人信息,包括浏览记录、搜索记录、下载记录、Cookies等等,同时地址栏也会变成一个醒目的黑条。
>
她是1999年就加入Google的最早创始团队成员之一,也曾经是Google创始人拉里.佩奇的第一任女朋友,被称为Google第一美女副总裁的她,主管Google全球搜索产品和用户服务体验,这就是Google全球副总裁玛丽萨.迈尔(Marissa Mayer)。
在Google进入中国两年后的今天,她首次来到中国,虽然在2007年Google先后和中国移动、迅雷、中国网通、电信以及新浪达成合作,也在中国推出了一系列热榜、导航和生活搜索等产品,但仍然没有改变中国的搜索市场份额在百度之下的事实,“搜索产品是Google先做的,而Google来到中国,就说我们抄袭百度,这不公平”,谈到外界对于今年Google推出的很多产品是对百度的模仿,玛丽萨.这样表示。
7月20日,就Google全球产品和市场策略以及中国本土市场的差异,记者对玛丽萨.迈尔进行了独家专访。
中国和日本市场不相上下
记者:今年Google推出了很多如导航、热榜、生活搜索等产品,但大家认为这些产品都是对百度社区、娱乐等产品的模仿,并不符合Google创新产品的理念,你怎么看?
玛丽萨.迈尔:对这些产品是不是创新产品,我认为从我们总部来评价不公平,事实上网页搜索本来就是Google最先做的,百度后做的,只是因为Google来到中国,就说我们抄袭和模仿百度,这个不公平,我认为我们上述产品都是尽可能以最好、最清晰的方式呈现给用户。
当然,百度确实有值得我们学习的地方,有很多很好的产品,它是一个强大的竞争对手在挑战我们,这样的话会鞭策我们加倍努力改进自己的工作,实际上这两个大对手的竞争,也会最终改善最终用户它的搜索体验。
另外,其实百度他实际上替我们做了一个很困难工作,了解中国的市场,让消费者了解什么样的是好的服务,另外帮我们了解消费者对于搜索服务有什么样的期待,我们从里面实际上也获益了。
所以Google在中国,除了改进核心的搜索产品,营销方面也要加倍努力。
记者:说到百度,它去年就已经进入了日本市场,在积极进行国际化战略拓展,Google怎么看待百度这种发展?是否会对Google的全球市场产生竞争?另外,即使今年Google在中国推出了一系列产品,也发展了一系列本土合作伙伴,但是市场份额仍然在百度之下,Google打算如何进一步加大中国的本土化?
玛丽萨.迈尔:我个人认为百度进入日本还不能说是一个全球化的战略,当然,Google现在还没有看清楚他们的整个战略,我们要在等等看,等看清楚他们的战略结果后再做判断,所以现在还谈不上全球市场的竞争。
作为中国本土化方面,我们还要加大中国这边的研发团队,中国的网络页面内容更丰富,每一个页面上都有很多链接,我们近期已经针对中国市场在很多网页上对UI做了很多变化,网页优化有了很大变化;另外,在移动搜索方面,中国市场手机用户的数量很高,超过4亿人,所以在移动搜索方面我们会加大投入;还有社区产品,我们内部也在认真讨论和设计进入这个领域。
Google第一美女副总裁玛丽萨.迈尔(Marissa Mayer)
记者:针对整个亚太市场,中国、日本、韩国等在Google的市场战略里是一个什么位置?目前其他几个市场的发展状况是怎样的?
玛丽萨.迈尔:Google现在在日本和韩国都有了研发中心和办公室,人员规模都在10-100人之间,而中国市场规模上很丰富,我们在中国市场的研发人员今年年底要达到500多人,而且这个还不是上限,所以中国市场非常重要。
但是日本在广告、媒体方面的市场也很重要,而且Google在日本还占有不小的市份额,比如Google在日本和KDDI提供移动搜索服务,一个星期就给KDDI赚了100万美元。所以一定要比较的话,中国市场和日本市场不分上下。
Google“整合搜索”与雅虎“全能搜索”本质不同
记者:Google现在全球产品战略是怎样的?你们之前提出的“整合搜索”(Universal Search)概念和雅虎现在力推的“全能搜索”(Omni Search)有什么区别?
玛丽萨.迈尔:Google的全球产品战略是并重发展三个方面:搜索、广告技术和产品,还有工具应用,不论是针对个人用户还是企业用户的应用工具,这三个方面对全球战略来说同等重要没有先后和轻重,但在中国,目前可能搜索还是最重要排在第一位的。
我们的“整合搜索”是在一个关键词下,将目前Google主要的网页、图像、新闻、视频、本地、地图六大类产品和信息同时做搜索,按照相关性和关联度进行排序和混合在一起,给出一个最终关联性和相关度最高的搜索结果。
而雅虎的“全能搜索”,不是总是去搜索上述各个不同类别的信息,而是将所有的搜索结果放到一起,没有进行相关性的排序,所以差别是很大的。
当然,中国目前还没有整合搜索的相关产品,我们下一步将有计划的尽快把整合搜索结合到Google.cn中来。
记者:说到移动搜索,Google在去年底今年初和中国移动达成合作进行移动搜索的研发,目前双方移动搜索产品进展到什么程度?Google对移动搜索的理解是怎样的?
玛丽萨.迈尔:事实上,网页搜索还是一直是Google最重要的。我们和中国移动的合作从开始时只能在移动梦网站内搜索,现在已经可以将互联网网页转为移动网页,在中国移动的手机上覆盖率已经达到70%,而且对于一项搜索结果,用户可以通过发短信直接将结果发到手机上,现在移动搜索这块的搜索量已经从年初到现在增长了400%多。
刚才讲到中国手机用户4个多亿,我们在研究的时候就会知道在四亿多部手机里面,到底有多少具体用手机传输和处理数据,在这么多数据处理里面,又有多少人的手机是可以具有大量数据的处理能力,又有多少人会用手机数据处理功能的,根据我们的了解,中国的手机用户中最多有一亿的用户是真正用手机处理大量的数据。
另外,在中国使用短信功能的人很多,我们就要去了解大家用短信来干什么,和能干什么,这个都是我们进一步研究的对象。比如说有一种搜索方式,客户用短信把他搜索的关键词发给我们,而我们能把结果以短信的形式回复他们,但如果是地图搜索,卫星搜索就不太切合实际了。
记者:那针对Google 目前已经推出的搜索产品和服务、工具,您认为在哪些方面还需要改善和提高的?
玛丽萨.迈尔:一个是在个性化主页方式方面要进一步提高,也就是说这个用户本身能够根据自己的需要和兴趣,外加其它的模块,这样组成自己专门主页,他可以把时钟、天气、游戏、短信都加进去,他想加什么都可以,这样的话Google的用户在用Google的时候,也是一种个性化的体验。
另外,Google之所以是一个强大的产品,是基于三“S”的一个特征,第一个S叫搜索(Search),它改变了我们传统用Email的方式;第二个是空间(Space),未来我们想把Gmail的空间再进一步扩大,或者采用在将来推出用户付费方式,总之是要进一步为用户提供空间更大的服务;第三是速度(Speed),在中国电子邮件服务方面,有很多的竞争对手,但不管是雅虎的还是其他的邮箱,我们的速度至少比别人快十倍。
但即使是这样,现在基于网络的Email速度实在是太慢了,未来我们需要提高速度。
搜索未来六大趋势
记者:您作为Google主管产品和用户体验的副总裁,怎么看待未来搜索技术的趋势?
玛丽萨.迈尔:我认为未来搜索技术的趋势主要有六个方面:
一是突破语言障,可以用中文,也可以用英文,即用任何一种语言搜索都可以获取全世界各种语言的结果;
第二个是除了网络上的信息,图书馆的图书信息与出版社的出版信息都将成为我们的信息和数据来源,即达到“图书馆+合作合作伙伴+出版社”的数据信息来源,来完成一项最好的搜索结果,即我们的整合全球信息;
第三个是“视频+语音”的多媒体搜索,一定是未来的主要应用和趋势之一;
第四个即我们现在提出的整合搜索,对主要的几大类信息和产品同时做搜索,给出一个相关性和关联度最高的搜索结果;
第五个是地图和本地搜索信息的结合,如我们现在的Google Earth产品和本地信息的文字、图片等的结合;
第六个是客户软件和工具的结合和调节,像Google现在已经推出的桌面产品,我们认为搜索不但只可以在网络上搜索,在本机和本地都可以随时发起搜索。
当然,搜索核心业务当中还有有很大的潜力可挖,比如搜索用户能不能进行和搜索引擎对话,而不是输入关键字得到一个反馈的结果;还有在十多个搜索的网站结果中,怎么能实现一个互动的模等等。
记者:那么美国总部市场那边今年做了哪些创新产品?在今年所有中国市场推出的产品里,您认为哪一项是最具有创新性的?
玛丽萨.迈尔:今年春天美国那边对Google的地图产品进行了很大的提升,细化到了每条街道的图片,比如我和朋友约好去和咖啡,我通过Google搜索不但可以搜出地址,还可以搜出那家咖啡店的门是什么样子,可以让用户有最直观的感受。
还有,还推出了一个“Google Gear”产品,是一项基于浏览器运行的动态交互互联网产品,有三方面的改变,可以做到本地数据缓存,浏览读读更快,支持离线方式浏览,重新上线后自动直接数据同步。我认为这两项产品是今年美国总部那边做的比较创新的产品。
至于Google中国今年推出的各项产品里,我个人认为热榜产品很好,有新的版本和数据呈现,而且同时可以看见别人在搜索什么。
“干得比驴累,吃得比猪差,起得比鸡早,看上去比谁都好,五年后比谁都老”相信很多程序员朋友都曾这样感慨和抱怨过自己的生活状态。的确,日复一日地手按键盘、目盯显示器,在实现一个个程序和任务的同时,有时候我们的健康也慢慢流失在那一段段整齐的代码中。
前段时间CSDN做了一期“谁扼杀了程序员的健康”的专题,并对程序员的健康状况做了一次调查。调查共分为:“亚健康”、“很虚弱”、“糟透了”、“很健康”、“没感觉”五种选项,以程序员单选投票的方式进行。
调查结果显示“亚健康”高居榜首,这样的结果可能已在我们的预料之中,然而当看到具体的数字和比例的时候,我们还是不由得吃惊:截止发稿时,在总数741 的健康状况投票中,“亚健康”的票数高达473,占总比例的62.9%,也即每一百名程序员中,有约63名认为自己的身体健康处于亚健康状态!
亚健康状态是人体处于健康和疾病之间的过渡阶段,在身体上、心理上没有疾病,但主观上却有许多不适的症状表现和心理体验。软件工程师小杨告诉记者,“有几个程序员不颈椎疼、不头晕眼疼?!太正常了这。每天都感觉特别疲惫、乏力却还要继续写代码。晚上躺在床上是最舒服的时刻,脑子就像被掏空了一样。”
位于调查结果第二位的是“很虚弱”——149,比例为19.81% 。显然,很虚弱的健康指数低于亚健康,已接近生病和透支状态,他们的健康已经被亮出了黄牌。“也没有太明显的病,但就是觉得虚,很虚!”一位不愿意透漏姓名的程序员这样告诉记者,“我咖啡就不离口,有时候感觉脑子大得像要裂开。恍恍惚惚的,一段时间看见电脑屏幕就想吐。即使到了周末,出去玩还是空空的感觉,没等休过来,周一又来了。痛苦的轮回,又没别的办法。”
虽然每个人的理解不一样,但是“糟透了”这样的词如果用来形容程序员健康的话,相信大多数人都绝对认同“你已经病了”这样的理解。令我们不敢相信的是,竟然有8.24%的程序员用这个词来形容自己的健康状态!一位开发者这样描述自己的生活状况:“每天睡三四个小时,高强度的持续开发一个月,睡个觉脑子里面都是在想问题,上个厕所还得一边翻资料……”这样的生活也不难理解为什么响起刺耳的健康警铃。
调查结果中“非常健康”的票数低得可怜——40,即使算上“没感觉”,二者之和也不过9.04%,几乎跟“糟透了”持平。如果将“非常健康”和“没感觉”一起算为健康的话,处于亚健康状态的程序员是健康状态的7倍,自认为“很虚弱”的程序员数目是处于健康状态的2.2倍!
对于自己的健康状况,你是最清楚的。虽然700多份调查并不能够代表所有的程序员,但我们希望能够借此给你一个参考。也希望你能吃好、睡好、休息好、工作好、身体好.
在所有的球类运动中,足球可以说最能体现人类刚猛血性的运动了,甚至展现一个民族的精神风范,所以草根王子做为一个男人,做为一个中国人,我没有理由不深切关注我们的中国国家足球队!同样像我一样有着热血的中国人也无时无刻不关注着中国足球的命运。
冲出亚洲走向世界,是多少代中国足球人多少年梦想,可是事与愿违,中国足球连亚洲都难振翅一飞,每次都铩羽而归。
尽管屡战屡败,可是当我们第十四届亚洲杯战火重新燃起,又一场亚洲足球英雄宴到来,尽管我们这些恨铁不成钢的球迷一再发誓不看中国足球了,但如果听说绿茵场上真的有黄皮肤黑眼睛的中国男儿在奔跑时,又忍不住偷偷搬来椅子神情专注看着电视直播,内心的热血再次沸腾!
感觉这次中国队有些与众不同,首战中5-1狂胜马来西亚,次战虽然以2-2平伊朗有些差强人意,但是最后一战只要战平弱旅乌兹别克就可以出线。
如此大好形势似乎一切胜利在望了,可是聪明的人早就看出这场球背后潜在危机了:历经上二场考验的门将李雷雷因伤缺阵由稚气的杨君出任,二大核心球员郑智李玮峰也因吃黄牌缺战,上场的一些国足足球素质明显有待进步。
果不出其然,在第71分钟赵旭日犯规送给对手左翼任意球,球传禁区,中路埋伏的沙茨基赫,头球攻门,稚嫩的杨君虽然判断准确,挡出,但脱手,其它队员防守出现重大失误,还是给了沙茨基赫补射的机会。接下来,中国队心理防线崩溃,兵败如山倒,再次铩羽止步八强大门之外。当时我感觉整个天都好像塌下来了,女朋友发来视频我都不敢接,生怕脸上无际的悲伤莫名无辜地传递给善良温柔的她。可是出乎我意料的是,女朋友坦然地说:本来中国足球水平就不是很高了,输了就输了,难道他们不想赢?他们也尽力了!
我心有些许所悟所释,是啊,我似乎没有必要这样夸大自己的悲伤情绪,古人常说:胜败乃兵家常事。中国足球所在存的问题,不只一场比赛就可以轻易解决掉的,也不是一只比赛就可以轻易看透的,如果我们用一场失利就否定了中国足球命运的未来,那我们这些以泱泱大中自居为豪的球迷是不是太没有出息了!?
于是我带着很释然的心态看一些知名网站的足球评论时,让我大吃一惊的是:很多足球评论者,足球迷,对这场球的失利的反应,反常到了一种病态疯狂自虐和攻讦地步。
诸如“可耻”“耻辱”“傻B”等字眼,纷纷跳入我的眼帘,漫天袭地的对国足进行了史无前例的谩骂侮辱式的疯狂攻击,像一场声势浩大的飓风袭来!
非常知名的体育新闻网豁然出现《27年后重演小组淘汰悲剧朱家军添中国足球“新耻辱”》
甚至很有影响力的著名足球评论员李承鹏,也像一个骂街的泼妇写着:朱家军之死是行政足球最后一根脑神经坏死,朱指导请辞职吧,过去你坚决不辞职还可归为性格问题,现在再不辞职就是人格问题了。。。。。。“行政足球”,连输球都可以搞出这样悲壮的行为艺术,我呸!
再看看众多其它网友一些留言:
“你说你个鸟,我看你们就和老挝一个档次的!还他妈的德甲,英超水平!屁放大了闪到腰,我日!~!就你们这群傻B就那点出息,解散吧!改行吧!!隆个胸去题女足吧”
“无语。除了耻辱我不知道还能用什么词来形容这场比赛。”
“无耻老朱;你有两条路可以选择.一是像个男人一样辞职:二是到泰国去找人阉啦”
“我赛前就希望中国队可以输掉比赛,那样“猪头”就终于可以下课了,不用再流毒百世,遗臭万年了。”
像以上这样的谩骂不胜枚举,本来就是一场输球,本来我们一直都明白竞技精神“贵在参与”,愣是到了现在,一场输球竟然成了千千万万众多足球迷侮辱国家足球队员人格道德问题和教练人格道德问题的冠冕堂皇的攻击借口,而且还理直气壮。
一场球输了,一场口德洪水战却轰轰烈烈上演了!
尽管范志毅面呈悔意地说:我看过这场比赛后,我想对球迷说的话就是我们的队员已经尽力了,希望大家以一个平和的心态去看待中国足球的又一次失败。虽然0比3的比分有些让人难以接受,但我们还是不应该对中国足球丧失信心。 尽管邵佳一真诚地道歉:这届亚洲杯留给大家的是遗憾,没能给大家带来快乐,我只能在这说句对不起了。
尽管郑智很无奈地剖白:我一点没有为队友和自己推脱责任的意思。。。。。。我知道这个时候很多中国球迷都非常伤心,非常抱歉,让大家再次承受失利的痛苦。
可是很多球迷们并没有因为他们的真诚的道歉而放过他们,公然跑到他们的博客里留言:“我草!真幸运可以在前面骂骂你们。。踢的什么鸡8球啊?要我教你们不?********那么多钱都干嘛去了?找小姐也不用花那么多吧!多做点善事,积点德。。。散了,散了。。。。骂你们简直浪费精力。。。”
呜呼,这就是我们国人球迷的素质,胜了把你吹上天堂,败了把你打入地狱,竭尽百般病态口才语言,让你毫无尊严,毫无人格地立于世间,大有骂得你以死谢罪才一解心头之恨!
如果说中国足球体制和国足水平以及教练执教水平,导致了中国足球如此不尽人意足球现状的话,那么我想还有一个非常重要的因素就是:足球迷的功利“成则王败则寇”的足球价值观,也是祸害中国足球的致命因素之一。
当现代足球成为一种产业时,千千万万个买票看球的球迷就理所当然成为足球消费者,如果当我们足球者缺乏起码的对足球人的尊重,缺乏一种理性平和的对足球人的理解,缺乏一种起码足球价值胸襟,代之以一种非常狭隘的功利观,进行漫无边际的责骂和道德上的侮辱,试想在这种语言暴力强大环境压力下,换位思考一下,我们的足球队员怎能热情四射完成一场心态轻松的灵感百出的足球创作?
输了一场球不可怕,只要有亚洲杯,四年之后再次打响,我们还是有希望的,四点之后也许不行,八年之后,十二年之后。。。。。若干年之后总有一天中国队一定能冲出亚洲走向世界的,因为我相信中华民族是一个不服输不倔的民族。
假如我们因为输了这场球,虽然这场球赛对中国足球在此次亚洲杯上命运至关重要,如果我们连信心都输了,连对足球人起码的尊重都输了,连对足球起码的风度和胸襟都输了,这才是一场彻底而可怕的输!
球可输,可能是技不如人,可能是战术不如人,也可能是足球素养不如人,我们可以冷静地找原因来改,任何进步都是需要时间,中国现代足球产业运作本来就比很多国家启动慢,这就更需要时间了。但是我们不能口无遮拦地对球员对教练对相关的足球人进行人身攻击,更不能胡乱加什么道德侮辱性的攻击,毫不注意一个堂堂大国公民的“口德素质”。
希望我们的球迷和足球评论员真正理智地成熟起来!
7月18日下午,年仅26岁的华为员工张锐,在深圳梅林某小区的楼道内自缢身亡。
进入华为只有60多天的他,生前曾多次向亲人表示工作压力太大,并两度想要辞职,为此父亲两度来深看望劝说
。
在父亲第二次来到深圳时,张锐选择了以这种方式与亲人告别,没留下一句话,身后只有因上大学欠下的5万多
元债务。
对于父母来说,张锐是上天给他们迟来的“礼物”——张锐出生的那一年,父亲已经37岁,母亲29岁
。他离开的时候,父母都已经白发苍苍。
毕业后换了4份工作
据其父母提供的材料显示,张锐,今年26岁,2000年考上武汉大学电子科学与技术系,2004年毕业。这对这个贫
困的家庭来说是非常艰难的事情。在武汉一家工厂工作的父亲早已下岗,每月只有几百元的下岗费,而母亲没有工作。4
年大学下来,家中债务高达近5万元。
毕业后,张锐在湖北当地一家企业工作了一年多,随后来到了深圳,在两家企业工作了一段时间。
今年4月份,张锐应聘华为并被录取。5月14日,张锐与华为签订了为期一年的劳动合同。对此,他很高兴,还打
电话告诉了父母。
两度要辞职父亲两次赴深
但张锐的兴奋并没有持续多长时间,和他住在一起的表弟首先感觉到了这种变化。表弟告诉记者,几天之后张锐
就有些不高兴,晚上经常失眠。他问张锐是否工作压力比较大,张锐说表现不好就会被主管批评,还要经常加班。
1个多月后,父母接到了儿子的电话。张锐表示,因为工作压力比较大,他想不干了,并征求父母的意见。对此
母亲明确表示不同意。由于惦记着儿子,母亲催促父亲去深圳劝说孩子不要放弃这份工作。7月1日,张锐父亲买了张站
票,带了个小板凳坐车到了深圳。在父亲的劝说下,张锐逐渐恢复平静,同意继续工作。3天之后,父亲回到了武汉老家
。
但几天之后,张锐再次打电话回家表示准备辞职,老父只好第二次来到了深圳。
未留一句遗言他自缢身亡
7月17日,进入公司60多天从没请过假的张锐向主管请了一天假。晚上,他与父亲一起到小区附近散步。7月18日
,张锐又请了一天假。下午2时,他告诉父亲要出去,从此再也没有回去。
当晚上11时左右,正在武汉的张锐母亲突然听到敲门声,当地民警告诉她,下午深圳警方在梅林地区某小区的楼
道内发现了一个自缢身亡的人,其身份证显示是她的儿子张锐。
母亲一时无法相信这个事实,因为孩子父亲还正在深圳。而此时张锐父亲也正在深圳四处搜寻儿子。他去网吧找
了几次没找到,手机也关了。随后他打电话回家,才得知孩子已经出事。
对于父母,张锐没有留下一句遗言。当父亲赶到小区时,尸体已经被运走。事后他得知,这里是儿子刚来深圳时
,与同学们一起住过的地方,距离他在华为坂田基地旁边的出租屋约有4公里路程。
华为愿付1万元“安抚费”
昨日下午,张锐父母与华为公司进行了第三次协商。张锐父母提出,希望公司能做出补偿。但华为人事部副部长
张志刚表示,根据公司规定只能给予1万元的安抚费。他说,张锐是自杀而且发生在公司外,其死亡并不在公司的员工伤
亡补贴制度之内,这1万元也是公司对家属的慰问。
对于家属认为的压力过大问题,张志刚承认华为公司的员工的确都有压力,但对于张锐来说,压力实际上远没到
把他击垮的程度。他说,张锐进入华为只有60多天,没有转正,也不能独立承担项目。
而且对于新进员工,公司都会配备思想导师,从各方面给予指导。此外,张锐性格比较内向,“外人很难
进入他的内心世界”。
“张锐选择了这条路,将痛苦留给你们,也给公司造成了负面影响,这是一种不负责任的行为。”张
志刚对张锐父母说。
为了桌面Java的未来发展,许多的重大改进正在进行中,
对此做了很大的努力
就语言方面来说,出现了JavaFX script 项目。
JavaFX是很灵巧的,它提供了一个高级的脚本接口,运行在Java
2D的API上。从用户的角度来看,他们不需要编写
Java代码,不需要深入理解复杂的线程,Java 2D,
Swing类的层次结构,定时框架结构(timing framework)等等
。相反,他们只是编写脚本语言和描绘出所需要的GUI,包括活波的音响效果,图形效果,
比如说梯度或者音乐,和数据绑定等等,这些都建立在一个基础API上。
这里有许多的工具帮助你学习syntax语言,相关资源这个从这
个网站获得;JavaFX研发小组的目标就是提供syntax语言,和
一些关于JavaFX的用户体验,这些用户包括美术设计员和那些对应用程序可视界面美观感
兴趣的民众。当前,JavaFX某种程度上作为第四步产生的语言在运行,因为首先是解释器
将FX脚本创建成为Java代码,然后再调用适当的
Java 2D API。该小组长期的目标是将FX脚本直接编译成字节
码。
JavaFX添加到桌面Java是一件非
常好的事情,但是,这得取决于是否有这样的一种JRE的存在,它能运行
JavaFX生成的代码。有些人认为FX已经进军到
RIA(rich Internet application)领域,和Adobe公司的
Flex一较高下。但是,目前还是有一些难题需要解决,举个例子,如何才能让桌面
Java的安装体验和运行时间性能比得上其它的RIA框架。还好
,这种问题正在被其他的项目解决,这个项目名称就是Java kernel。
Java kernel主动承认这么一个事情,即大多数的
Java应用程序都是只有JRE的部分大小,如
Limewire(一个文件共享的桌面应用程序),它只有
JRE的三分之一大小。Kernel将会对
JRE重新打包,使得只下载应用程序所需要的部分JRE。每个
程序所需要的基本部分将会被下载,作为JRE启动所需要的最小部分,其他的部分根据需要
下载,或者根据ClassNotFound异常信息,下载缺失的类。这将是一个巨大的好消息帮助桌
面Java应用程序瘦身,同时还能使得桌面Java应用程序执行
的更为有效。除了解决如何下载的问题外,kernel还非常关注
Java程序的启动性能。
在先前的kernel几个版本,热启动时间(warm
start times)减少了很多,但是,在应用程序调用main(String[])前,冷启
动JRE仍然需要延误许多秒的时间。Java kernel正在尝试有
效的处理冷启动,将冷启动转变为热启动,通过一些相关的技术,如预加载(pre-loading)
JRE,从硬盘读入到内存,还有一个操作系统服务,这个服务的功能就是监视可分配的内存来加载
JRE,使得用户获得最佳的性能。出了这些,kernel还提供了
一个新的浏览器插件,提供给Web 开发者更多的关于桌面运行信息,可获得的
JRE水平等等。
对于桌面Java来说,Java kernel 和
Java FX两大好消息。说Kernel是一个非常好的技术,是因为
它承认了Swing已经到了一个非常成熟的阶段,并且帮助开发这如何将他们的
Java应用程序更为快速,更为有效的搬到用户桌面上。说FX
是两外一个非常好的消息,是因为它为Java开发者打开了新篇章,特别是那些愿意使用脚
本语言和做一些高级的,活波的,图形效果的开发者,他们只需要写简单几行代码就可以完成。我相信这两项技术将会
使得更多的应用程序用Java语言编写,运行在用户的机器上,同时,对于用户和开发者来
说,应用程序变得更快,更简单。
“12年前没有我,就没有今天的新浪”
理财周报记者 李冰心/文
你可能有段时间没关注过唐骏了,那个走出微软光环后,成为中国最高身价职业经理人的唐
骏。
上周,在上海的一个创业投资论坛上,身为盛大网络总裁的唐骏忽然心血来潮道出了一段
12年前的尘封往事,他对理财周报记者说,“如果没有我,
就没有今天的新浪。”
应该感谢我
否则新浪还在做Rich Win
“这是一个非常真实的故事,没有一个人知道,包括王志东在
内。”在唐骏说起这番话的时候,新浪创始人王志东刚刚走下演讲台落座,谁也没有想到
,唐骏要说的往事是跟微软和王志东息息相关。
1995年,王志东带着自己研发的中文平台
RichWin去美国与微软洽谈合作。
唐骏说,那时候他刚进微软两个月,作为一名普通软件工程师和王志东开会。
“你在会上跟我们讲述了你的RichWin是多么伟大,微软需要
RichWin,没有RichWin微软在中国很难推广,因为微软做不
到中文系统和英文系统同时进行。我很佩服,RichWin的技术上伟大得令微软人深感佩服。
”王志东的这句话深深刺激了微软工程师唐骏。
“你看不起微软,所以我就下狠心要改变这样的局面,因为那
个时候我代表的是微软。”从此以后,唐骏在微软日夜工作,提出了
Windows Linux的开发模式,使各种语言系统的开发模式变得全面统一,从此才有了今天的
Windows2000、XP和vista,中
文、英文、日文等所有的操作系统在全球统一发布。
“因为微软使用了我们当时提出的操作系统国际版本的开发模
式。你应该感谢我,当时如果我不提出这个开发模式,你还在享受着你的RichWin给你带来
的巨大利润。你应该感谢我,如果没有我唐骏,也没有今天的新浪,因为你还会做你的
RichWin。”回忆往事,唐骏情不自禁地问,
“你们没有觉得唐骏做人真的是很低调吗?”
卡拉
OK记分系统发明专利
唐骏卖了
8万美元
很难想象,一向在公众面前温文尔雅的唐骏回首往事会意兴难平。不过,仅认为是王志东的
高傲激发了唐骏的斗志,显然有失公允。因为在加盟微软之前,他已经进行了多次创业尝试。
“1992年的时候我在美国,没有王志东那样的伟大梦想,我就
是为了生存,我只是觉得做一般的普通员工给我带来的生存价值并不是很大,所以我创业。”
唐骏说,如今街头随处可见的大头贴就是他当年在美国花两天时间想出来的创意,后来转让给了一家日本
公司,连带其他交易共获利50万美元,而那间日本公司如今已是上市公司。
唐骏自豪地说,卡拉OK的记分系统也是他发明的,虽然已经过
了15年,现在别人还是做不出来——这个技术专利唐骏卖了
8万美元。“实际上那就是唐骏标准,很多人说不准,是因为
你唱得距离唐骏太远了,也有很多人分数高,因为咱们是一条线上的。”唐骏用顽童般得
意的口气调侃着自己的发明,他说,那时创业就是为了追求新鲜,追求满足感。
唐骏在美国还曾创办了一家律师事务所,虽然那时他并没有律师执照。更像一家皮包公司的
律师事务所,却取了一个响亮的名字:美国第一律师事务所。后来他还帮助国内一些演艺界明星到美国走穴。
我对创业充满激情
我喜欢改变生活
唐骏在公众眼中,被视为职业经理人的杰出代表,但他的职业生涯中也经历了草根式、外援
式、温室型三个创业阶段:“其实我很幸运,我没有像创业者一样追求什么东西,我只是
希望我的人生精彩。”
当唐骏觉得自己对创业已经失去新鲜刺激感之后,他幸运的加入了微软。三年之后,唐骏在
微软公司内部得到了一次创业机会, 创立上海徐家汇微软全球技术中心。
“微软派我一个人到上海来,无非给了我资金、政策,除了微
软的大力支持,其他的都等同创业。”1997年唐骏只身来到上海,从选址到装修都是他一
个人操作,而当他离开的时候,这个技术中心的员工已经达到500多人。
此后,唐骏说服了上海联投和微软公司各出资两百万美金,令他完成了一次外援式创业
——创办上海微创软件公司。同样是他一个人再次开创了一条成功的商业模式。
“在微软的大温室环境下,给我很多资源,让我去创建微软全球技术中心,更重要的是我
也通过资本运作的方式让我拥有了微创软件创始人、CEO的角色。所以我觉得我的创业人生
非常完美,我对创业还是充满激情,我喜欢做一些改变生活的东西。”
50万的日薪成为
中国身价最高的职业经理人
2003年底在上海的一个软件外包会议上,唐骏与盛大网络创始
人陈天桥不期而遇,陈天桥“网上迪斯尼”的构想令他再次
准备迎接新一轮挑战。
2004年,唐骏离开微软正式加盟盛大网络,以日薪高达
50万元成为中国身价最高的职业经理人。
近日,盛大宣布收购网游公司成都锦天科技,收购涉及金额超过人民币
1亿元,年仅23岁的加拿大籍青年彭海涛一夜之间成为亿万富
翁。
谈及最终促成这桩收购的原因,唐骏说,网游在当今的互联网商业模式当中被华尔街认为是
中国最成功的一种商业模式,而彭海涛纯粹靠自己打拼,能够在网游界占有一席位置实属不易。
对创业的激情令唐骏更多关注对创业者投入,他透露,盛大有一个专门的收购团队在不断寻
找合适的并购对象。唐骏的理论则是,“首先你要选对商业模式,当然你还需要核心竞争
力,最重要的是一个创业者的基本素质,这种创业的精神,这种执着。
摘要: [导读]本文通过实例,介绍在做验证码的时候为了给用户很好的体验,需要在原有验证方式基础之上增加一段js,通过xmlhttp来获取返回值,以此来验证是否有效。同时,本例还特别适合检验用户名是否有效。 1、我们在做验证码的时候往往由于要反作弊,验证有时故意加入多的干扰因素,这时验证码显示不很清楚,用户经常输入错误。这样不但要重新刷新页面,导致用户没有看清楚验证码而重填而不是修改,... 阅读全文
您想做 Google 的中国地图吗?
您是否曾震撼于 Google 地图(maps.google.com)的绚丽表现和强大技术?您是不是想让中国也拥有这样好的地图服务?你是否想开发吸引三亿眼球的手机地图?请加入我们!
我们是 Mapabc.com 的地图技术和搜索技术开发团队,负责为 Google(bendi.google.com)、新浪(bendi.iask.com)和中国移动提供地图服务和技术支持。我们需要有能力、经验和理想抱负的杰出青年加入我们的队伍,我们期待着您。
北京图盟科技有限公司(Mapabc.com),是中国领先的地图和导航服务提供商,专业从事互联网、手机地图及相关的位置服务。Mapabc 的用户遍及各个领域。在互联网行业,Mapabc为搜索引擎(Eg:Google、中国搜索...)、门户网站(Eg:新浪...)和行业网站(Eg:搜房...)等用户提供的地图技术和地理位置检索服务;在移动增值领域,Mapabc为中国移动用户提供的手机地图和位置搜索服务(LBS);在行业应用领域,Mapabc帮助政府和行业用户构建高效的无线定位、监控和办公自动化系统(Eg:城管通...)。
我们目前招聘以下方面的人才,待遇面谈:
基本要求: 计算机软件相关专业本科及以上学历,本科要求有1年以上开发经验; 具有团队合作精神和独立工作能力,具备钻研和开拓精神,责任心强,能够承受工作压力; 本科生必须全职,硕士研究生可全职或实习。
岗位: 图形算法高级工程师(3人) 高级测试经理(2人) 导航开发高级工程师(2人) GIS研发高级工程师(3人) GIS及导航产品经理(2人) 算法开发工程师(5人) 三维开发工程师(3人) 嵌入式开发工程师(2人) Kjava开发工程师(1人) Java开发工程师(3人) 三维美工(兼职)
岗位详细描述:
(1) 图形算法高级工程师(3人) 职位描述: 核心图形引擎相关算法的设计、研发 学历要求:本科及以上专业毕业; 职位要求: 1、精通算法设计/数据结构者, 熟悉操作系统原理 2、能熟练阅读英文资料 3、精通C/C++语言编程 4、三年以上二/三维图形图像底层开发经验, 有GIS行业相关工作经验者优先 5、具备较强的系统设计能力和代码开发能力,沟通能力较强,思路清晰,性格稳定,有较强合作意识
(2) 高级测试经理(2人) 职位描述: 根据开发项目、产品开发计划和测试需求,编制测试方案,制定测试计划,分配测试资源和测试任务,组织设计并搭建测试环境,组织、计划、实施测试,控制测试进度,调整测试计划。 学历要求:本科及以上专业毕业; 职位要求: 1、精通测试相关知识,熟悉CMMI相关知识 2、能熟练阅读英文资料 3、熟练使用相关工具软件 4、二年以上测试管理职位工作经验,四年以上测试工作经验 5、有较强的组织协调能力、沟通能力、分析决策能力、影响力、计划与执行能力及寻根究底的探索精神,具有驾驶经验,思路清晰,性格稳定,有较强合作意识。
(3) 导航开发高级工程师(2人) 职位描述:手机导航或车载导航软件方向的研发和产品化 学历要求:本科及以上专业毕业; 职位要求: 1、精通算法设计/数据结构者, 熟悉操作系统原理 2、能熟练阅读英文资料 3、精通C/C++语言编程 4、一年以上导航软件及相关软件的设计开发经验,熟悉整个导航流程过程 5、具备较强的系统设计能力和代码开发能力,具有驾驶经验,具有良好沟通能力,思路清晰,性格稳定,有较强合作意识。
(4) GIS研发高级工程师(3人) 职位描述: GIS引擎相关空间算法的设计、研发,GIS引擎相关模块的系统设计、研发 学历要求:本科及以上专业毕业 职位要求: 1、精通算法设计/数据结构者, 熟悉操作系统原理 2、能熟练阅读英文资料 3、精通C/C++语言编程 4、三年以上GIS算法或二/三维图形图像底层开发经验 5、具备较强的系统设计能力和代码开发能力,沟通能力较强,思路清晰,性格稳定,有较强合作意识。
(5) GIS及导航产品经理(2人) 职位描述:GIS平台产品或导航产品的负责GIS平台产品或导航产品的发展、规划和设计;撰写和整理相关文档 学历要求:本科及以上专业毕业 职位要求: 1、具有GIS或导航相关行业知识 2、能熟练阅读英文资料 3、能够使用项目管理及产品流程制定等相关软件,熟悉C++编程 4、至少三年的GIS从业经历,具有代码开发、市场运作、运营管理和项目管理经历者优先,具有GIS或导航产品评测、测试和质量控制的经验。 5、深厚的文字功底,良好的沟通能力,对GIS或导航行业发展深有研究,有独到的见解;具有良好的技术功底和专业知识 6、具有驾驶经验 7、思路清晰,性格稳定,有较强合作意识。
(6) 算法开发工程师(5人) 职位描述: 实时交通,导航以及图像处理的基础服务研发 学历要求:本科及以上专业毕业 职位要求: 1、有较深的算法基础和较广泛的算法知识,对开发相关算法程序抱有较大的热情和兴趣 2、英语4级 3、熟练使用C++或Java语言,2年以上工作经验 4、有GIS行业开发经验者优先 5、有路径规划、地图匹配、图像处理等相关经验者优先 6、责任心强、较强的语言和文字表达能力,创新、为人坦诚,积极
(7) 三维开发工程师(3人) 职位描述: 三维的GIS底层研发 学历要求:本科及以上专业毕业 职位要求: 1、精通计算机图形图像技术与算法实现 2、英语四级以上,能熟练阅读英文文献 3、精通c/c++技术, 掌握VC开发技巧,2年以上工作经验 4、精通Directx或OpenGL开发,深刻理解Directx或OpenGL渲染流程,掌握Shader相关技术 5、有三维应用或游戏开发经验者优先,GIS开发经验者优先 6、责任心强、较强的语言和文字表达能力,创新、为人坦诚,积极
(8) 嵌入式开发工程师(2人) 职位描述:客户端底层平台研发 学历要求:本科及以上专业毕业 职位要求: 1、精通算法设计/数据结构 2、能熟练阅读英文资料 3、精通C++程序开发,了解STL 4、两年以上嵌入式系统开发经验,熟悉EVC4或者Windows Mobile5.0 5、具备较强的系统设计能力和代码开发能力,思维活跃,积极上进,可以独立开展工作,为人坦诚、积极、责任心强,可承受较大工作压力
(9) Kjava开发工程师(1人) 职务描述:客户端以及服务端的地图基础服务研发 学历要求:专科及以上专业毕业; 职位要求: 1、精通java底层以及算法 2、能熟练阅读英文资料 3、具有团队合作精神和独立工作能力,具备钻研和开拓精神,责任心强,能够承受工作压力 4、精通 Java 语言、J2EE技术,熟练掌握java底层和算法 5、一年以上的kjava游戏开发经验 6、具备较强的系统设计能力和代码开发能力,具有良好的团队精神和人际沟通能力,以及工作的创新能力和稳定性,思路清晰,性格稳定,有较强合作意识
(10) Java开发工程师(3人) 职位描述: 地图服务以及新技术应用开发 学历要求: 职位要求: 1、精通java底层以及算法 2、能熟练阅读英文资料 3、至少2年java开发工作 4、具有团队合作精神和独立工作能力,具备钻研和开拓精神,责任心强,能够承受工作压力 5、精通 Java 语言、J2EE技术,熟练掌握java底层和算法 6、熟悉javascript开发经验者优先,有大型项目的开发经验经验者优先 7、熟悉 Jsp、Servlet、JavaBean、XML、Struts、Hibernate等WEB动态服务开发技术 8、有GIS相关工作经验者优先 9、具备较强的系统设计能力和代码开发能力,具有良好的团队精神和人际沟通能力,以及工作的创新能力和稳定性,思路清晰,性格稳定,有较强合作意识
(11) 三维美工(兼职) 职位描述:三维美工(兼职) 学历要求: 职位要求: 1、熟练掌握3DMAX,PHOTOSHOP 2、发简历时,请注明要应聘的职位,并提供作品 3、负责3D建模贴图,特效绘制等相关美术工作。 4、美术或相关专业、有游戏美术开发相关工作经验者优先。 5、具备一年以上相关工作经验; 6、熟练使用3dMAX等相关美工软件; 7、具有良好的团队合作精神。
有意加入我们团队的朋友,请联系我们: E_mail:basemanager@mapabc.com
请将您的简历通过E_mail发给我们,在简历里请详细描述您的工作经历和技术专长。
达·芬奇设计的第一辆汽车草图与模型图。
达·芬奇亲自解剖了几十具尸体,对人体骨骼、肌肉、关节以及内脏器官进行了精确了解和绘制。他甚至还设计了心脏复原手术。
达·芬奇设计世界上第一款直升机。
造汽车,造飞机,造机器人,杰出画家竟是百科全书式科学巨匠
蒙娜丽莎的微笑,迷人而神秘,直到今天还有人在破解其中之谜。只是破解这个谜谈何容易,要知道制造这个谜的人,曾经自己就破解了许多自然科学之谜。他就是达·芬奇。近日,达·芬奇发明的自行车来到北京,一个科学天才与他当年的设想再次让我们仰望了一下。
事实上,达·芬奇在天马行空中,一直将奇思妙想写在手稿上,直到去世也没有发表。然而,“科学家达·芬奇”的称号对达·芬奇来说是当之无愧的,有人甚至评价为世界十大科学家之首。
达·芬奇科学成就:
● 天文学
达·芬奇对传统的“地球中心说”持否定的观点。他认为地球不是太阳系的中心,更不是宇宙的中心,而只是一颗绕太阳运转的行星,太阳本身是不运动的。达·芬奇还认为月亮自身并不发光,它只是反射太阳的光辉。他的这些观点的提出早于哥白尼“太阳中心说”。甚至在当时,达·芬奇就幻想利用太阳能了。
● 物理学
达·芬奇重新发现了液体压力的概念,提出了连通器原理。他指出:在连通器内,同一液体的液面高度是相同的,不同液体的液面高度不同,液体的高度与密度成反比。他发现了惯性原理,后来为伽利略的实验所证明。他认为一个抛射体最初是沿倾斜的直线上升,在引力和冲力的混合作用下作曲线位移,最后冲力耗尽,在引力的作用下作垂直下落运动。他的这一发现使亚里士多德的落体学说产生了动摇。他发展了杠杆原理,除推导出作用力与臂长关系外,还算出了速度与臂长的关系。他指出了“永动机”作为能源的不可能性。
● 建筑
在建筑方面,达·芬奇表现出卓越的才华。他设计过桥梁、教堂、圆屋顶建筑和城市下水道。在城市街道设计中,他将车马道和人行道分开;设计城市建筑时,具体规定了房屋的高度和街道的宽度。米兰的护城河就是他设计和建造的。
● 水利工程
达·芬奇对水利学的研究比意大利的学者克斯铁列早一个世纪。为了排除泥沙,他作了疏通亚诺河的施工计划。他设计并亲自主持修建了米兰至帕维亚的运河灌溉工程。由他经手建造的一些水库、水闸、拦水坝便利了农田灌溉,推动了农业生产的发展。有些水利设施至今仍在发挥作用。
● 军事和机械
发明了飞行机械、直升机、降落伞、机关枪、手榴弹、坦克车、潜水艇、双层船、壳战舰、起重机等等。
● 地质学
达·芬奇根据高山上有海中动物化石的事实推断出地壳有过变动,指出地球上洪水的痕迹是海陆变迁的证明,这个思想与300年后赫顿在地质学方面的发现颇为近似。并且在麦哲伦环球航行之前,他就计算出地球的直径为7000余英里。
他是直升机之祖
这位文艺复兴时期的天才早在莱特兄弟之前就有可能开创人类飞行的历史。
“如果他当初发表了他的著作的话,科学一定会一下就跳到一百年以后的局面。猜测这种情况对人类的学术与社会的进步,当然是毫无用处的,但是我们可以万无一失地说,如果真有这种情况发生的话,人类的学术和社会的演变一定都会大不相同,”科学史家丹皮尔津津乐道的这位科学巨人正是达·芬奇。
事实上,达·芬奇时代的人们也与前人一样,有着飞行的梦想。在佛罗伦萨呆了一段时间后, 达·芬奇又来到米兰。1483至1486年期间,达·芬奇绘制了一幅飞行器草图。
在达·芬奇的设想中,这是一种依靠飞行员自身提供动力来驱动的飞行器。这位天才称自己的设计为“扑翼飞机”,达·芬奇让自己的飞机同时具备了推动力和提升力。
让我们姑且根据达·芬奇画的草图来还原出这架飞机。飞机的外形由木头、帆布等当时的材料制成,在飞行器两侧是一双膜状的翅膀,结构和形状酷似蝙蝠或翼龙,这双翅膀展翼可以达到11米。飞行员背负着这个巨大的飞行器,通过不停地踩动一个动力滑轮来驱动,而这个推动力又通过手摇曲轴得到放大,同时向提升装置提供动力。
设计出这款飞机时,达·芬奇心中一直有个理念:只要力量足够就可以飞行。看来,这位文艺复兴时期的天才早在莱特兄弟之前就有可能开创人类飞行的历史。事实上,这个最早的飞行器的机械设计十分完美,但是,由于人自身所提供的动力和飞行器本身的自重相比不成比例,是无法实际应用的。事实上,达·芬奇称自己的发明也是提供一个直升动力,而不是真正能工作的飞机。直到今天,人们还将达·芬奇的设计视为直升机的先祖。
他设计出初级机器人
更为奇妙的是,达·芬奇还设计了一套方法以做心脏修复手术。
达·芬奇曾自称自己没有受过书本教育,大自然才是他真正的老师。而认识自然,认识自己。这位文艺复兴时期的天才不遗余力地履行着。为了认识人类自身,达·芬奇亲自解剖了几十具尸体,对人体骨骼、肌肉、关节以及内脏器官进行了精确了解和绘制。
在多次解剖后,达·芬奇发现了血液对人体所起到的新陈代谢作用,血液把营养带到身体的各个部分,又把废物从各部分带走。在具体的解剖观察中,达·芬奇发现了心脏由4个腔组成并画出了心脏瓣膜图。
事实上,当年达·芬奇连人体循环系统工作机理的一点概念都没有。更为神奇的是,2005年,一名英国外科医生还利用达·芬奇设计的方法做心脏修复手术。不过,解剖学的研究在当时并没有给达·芬奇带来声誉,而是遭到了无数的诽谤。
不过,就是对人体的这种深入了解,达·芬奇在手稿中甚至绘制了西方文明世界的第一款人形机器人。
达·芬奇赋予了这个机器人以木头、皮革和金属的外壳。而如何让机器人动起来,才是让达·芬奇大伤脑筋的。在达·芬奇的构想中,他想到了用下部的齿轮作为驱动装置。由此通过两个机械杆的齿轮再与胸部的一个圆盘齿轮咬合,机器人的胳膊就可以挥舞,坐或者站立。更绝的是,再通过一个传动杆与头部相连,头部就可以转动甚至可以开合下颌。而一旦配备了自动鼓装置后,这个机器人甚至还可以发出声音。
原来,500多年前,就已经有了机器人的雏形。
他本可让文明提前一百年
点燃现代汽车发明灵感之火的正是这辆“达·芬奇汽车”。
最酷的事实是达·芬奇长达7000多页的手稿(现存约5000多页)至今仍在影响科学研究,他就是一位现代世界的预言家,而他的手稿页被称为一部15世纪科学技术的真正百科全书。
很早,达·芬奇就对当时的四轮马车不满。在他的科学世界中,早就有了汽车的影子。事实上,点燃现代汽车发明灵感之火的正是这辆“达·芬奇汽车”。
既然是汽车就要考虑动力问题,达·芬奇在汽车中部安装了两根弹簧以解决这个问题。人力转动车的后轮使得各个齿轮相互咬合,弹簧绷紧就产生了力,再通过杠杆作用将力传递到轮子上。
那么怎么控制车速呢?达·芬奇也想到了。他在车身上安装了一个圆盘装置,圆盘表面设置了很多方形的木块,和每个轮子连接的铁杆另一端与圆盘相接,这就是用于控制车速的装置。圆盘扇放置的木块数量越多,与铁杆之间的摩擦就会越大,阻力也越大,轮子的运转速度越慢,行驶的距离越长。
当然,达·芬奇也想到了刹车装置。位于齿轮之间有一个木块,拉动绳索将木块卡在齿轮之间,车就可以停止。不过,这辆汽车不能载人,因为仅靠弹簧的动力根本无法行驶很长的距离。
同时,达·芬奇还将弹簧巧妙地运用在了钟表设计上。后来大型钟表采用的原理,就是出自达·芬奇的设想。只是在这个设想中,弹簧的弹力被物体的重力所代替,物体向下的重力通过众多齿轮咬合作用被均匀传递,钟表便得以保持匀速运动。
此外,挖河机、潜水机、起重机、照相机、加热机、温度计……达·芬奇曾有过无数的发明设计。而这些发明足足可以让我们的世界科学文明进程提前100年。
对机械世界痴迷不已
水下呼吸装置、发条传动装置,滚珠装置、反向螺旋、纺织物扩张器……
水下呼吸装置、拉动装置,发条传动装置、滚珠装置、反向螺旋、差动螺旋、纺织物扩张器……达·芬奇将他无数的奇思妙想呈现在世人面前。故事的开头不得不说起达·芬奇初到佛罗伦萨学画的经历。事实上,这段经历开启了艺术家达·芬奇的大门,也开启了科学家达·芬奇的大门。
1460年,达·芬奇随父亲来到佛罗伦萨,开始了他的学徒生涯,同时开始学画。学画的达·芬奇参与安装佛罗伦萨圣母玛丽亚大教堂穹顶灯塔上巨型铜球,由此接触并感受到了各式各样机械系统的神奇。
佛罗伦萨圣母玛丽亚大教堂是文艺复兴建筑的开端。达·芬奇在安装穹顶灯塔上巨型铜球时,亲眼目睹了三速提升机等机械装置的效率,深感其中的神奇。由此,布鲁内莱斯基的机械系统设计理念对达·芬奇产生了很大影响。当时一批“锡耶纳工程师”对达·芬奇的科学世界也产生了重要影响。
而锡耶纳的工程师们设计的一种外形像船的河道淤泥挖掘机,用来清除浅水狂口的沙砾和淤泥,还有一种能够提高装载量又加快行驶速度的桨叶船,这些锡耶纳工程师的发明,让达·芬奇对机械的魔力产生了巨大的兴趣。
从此,达·芬奇对机械世界痴迷不已
|
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 |
|
公告
导航
统计
- 随笔: 63
- 文章: 0
- 评论: 27
- 引用: 0
常用链接
留言簿(2)
随笔分类
随笔档案
搜索
最新评论
阅读排行榜
评论排行榜
|
|