2007年8月2日
在 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 格式的信息
|
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
29 | 30 | 31 | 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 | 5 | 6 | 7 | 8 |
|
公告
导航
统计
- 随笔: 63
- 文章: 0
- 评论: 27
- 引用: 0
常用链接
留言簿(2)
随笔分类
随笔档案
搜索
最新评论
阅读排行榜
评论排行榜
|
|