自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

猴子程序员

猴子学python

  • 博客(162)
  • 资源 (77)
  • 收藏
  • 关注

原创 【2021-12-31】将 [4, -4] 映射到为 [0, 1000]的空间

/*** 将 [4, -4] 映射到为 [0, 1000]的空间* 2021-12-31/HHF* 如输入 -4 ,输出 1000* 输入 4, 输出 0* 输入 5.6 , 输出 1000* 输入 -5.6, 输出 0* 输入 0, 输出 500* 输入 1, 输出 375* 输入 -1, 输出 625*/function mapping(v) {var minValue = -4, maxValue = 4;function range(minVa..

2021-12-31 10:55:23 225

原创 [2021-12-16][HHF]数据库连接查询(join),左连查询(left join),右连查询(right)

数据库中,有两个T1, T2T1表id name 1 A 2 B 3 C T2表 id name 2 B 3 C 4 D 当只用JOIN 时,只显示两个的并集select * from t1 join t2 on t1.id = t2.id当只用 LEFT JOIN 时,显示A表的全部 + B表并集select * from t1 left join t2 on t1...

2021-12-16 16:02:24 565

原创 [2021-11-17][HHF][CSDN][Maven国内中央仓库]

<?xml version="1.0" encoding="UTF-8"?><settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.

2021-11-17 14:17:39 117

原创 [2020-06-01][HHF][安装python开发环境]

摘要   在开发之需要搭建好,比较简单的就是安装anacodda , 他是一个all in one 的安装包,或者自己动手搭建一个开发环境,以下就是自己动手搭建一个开发环境。安装环境 系统安装在 windows7下下载https://www.python.org/downloads/windows/将安装的变量设入到系统环境验证是否安装成功参考Python-Anaconda环境配置-https://blog.csdn.net/robin...

2020-06-01 17:24:57 182

原创 [猴子学python] 2020-06-01 如保下载m3m(java版转python版)

摘要 python没什么难的,只要多练,三个月就是专家了,先搞定基础100题.参考快速入门(完整):Python实例100个(基于最新Python3.7版本) - https://blog.csdn.net/weixin_41084236/article/details/81564963...

2020-06-01 15:46:56 119

原创 [猴子学python] 2020-06-01 如保下载m3m(java版转python版)

手头上有一个m3u8下载视频的java源码,但想转为python语言用来学习。我先看原java版的m3u8源码先撸了一遍,然后开发将他转了python版。

2020-06-01 14:25:09 279

原创 [猴子学python]2020-06-01 撸知识点

逐个基础知识来抓导言知识点参考导言学习python基础很重要,每个知识点都需要知道才能灵活运用,逐个基础知识来抓知识点python入门不难,只要百度+时间+认真+有一定的基础的话,应该很快撸代码,不懂的在后面具体项目中再重温一下就好了。1.基础语法、输入、输出,变量、注释,缩进、PEP8规范  这个的概念基本没难度,刚开始PEP8规范有一些默认,看一下就明白了。  2.布尔、数字、字符串、列表、元组、字典、集合- 布尔、数字、字符串、列表这个好理解- 这个主要是元组,有点陌生,看一下下面

2020-06-01 13:53:21 208

原创 [猴子学python]2020-06-01 引序

[猴子学python]导言我是猴子,在混了十几年java程序员之后,发现python才是王道,一把年纪为了不失业,于是开始撸起袖子开始学起了python,但python的涉及的很多领域,如简单的语法,爬虫,web应用,高一点的数据分析,数据量化,再高一点的数据决策,图像分析,再高一点的人工人智能等,想来想去,于是我选择从自己比较感兴趣,又比较简单,或我能理解的地方开始。如果发现网上已经有多的文章编写的话,我就不自己写了直接引用,如果发现网上写得还够完善我用我的理解再补充一下,但难免有不足的地方,请强力指

2020-06-01 11:50:45 216

原创 [2018-11-19][HHF][Nginx 目录浏览]

#user nobody;worker_processes 1;#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#pid logs/nginx.pid;events { worker_connections ...

2018-11-25 10:47:07 320 1

原创 [2018-10-19][HHF][一键生成项目管理文档目录]

创建一个 create_project.cmd 的批下理输入@echo offchcp 936mkdir .\00管理mkdir .\00管理\项目计划mkdir .\00管理\会议纪要mkdir .\00管理\项目周报mkdir .\01需求mkdir .\01需求\资料收集mkdir .\01需求\调研报告mkdir .\01需求\需求变更mkdir ....

2018-11-19 10:01:38 1113 1

原创 基于Mario(超级马里奥)的AI程序分析

@参考耶鲁编程马拉松:用神经网络学习超级马里奥游戏(论文下载)(中文)NEATEvolve.lua-- MarI/O by SethBling-- Feel free to use this code, but please do not redistribute it.-- Intended for use with the BizHawk emulator and

2018-01-10 11:26:07 2284

原创 利用jacob实现access数据访问

利用jacob实现access数据访问

2016-05-20 09:48:00 562

原创 Linux下管理Tomcat

启动Tomcatcd /tomcat/bin./catalina.sh  start查看日志:cd /tomcat/logstail -f catalina.out查看Java运行情况ps -ef |grep jav关掉tomcat:kill -9   48497

2015-10-21 11:53:16 492

转载 nodejs 简单连接msql

nodejs 简单连接msqlvar mysql = require('mysql');var conn = mysql.createConnection({ host: 'localhost', user: 'nodejs', password: 'nodejs', database:'nodejs', port: 3306});

2015-09-25 14:20:08 791

转载 node js 读取文件内容

node js 读取文件内容function readLines(input, func) { var remaining = ''; input.on('data', function(data) { remaining += data; var index = remaining.indexOf('\n');

2015-09-25 13:44:59 590

转载 nodejs 服务器重新启动

在我们开发node 应用的时候,一但你的应用已经启动了,这个时候如果你修改了服务端的文件,那么要是这个修改起作用,你必须手动停止服务然后再重新启动,这在开发过程中无疑是很烦人的一件事,最好是有一个能够监控所有变动文件的脚本,一单发现文件有变动则立即重启服务,重新加载刚刚修改过的文件。这里推荐一个:nodemon。 首先为了是这个命令全局可用,最好我们进行全局安装: npm instal

2015-09-25 13:40:22 9733

转载 修改svn提交后的日志

VisualSVN SERVER - 项目 -> MBY-CA-SERVER - 属性 ->  Pre-revision property change hook 添加/修改SET REPOS="%1"SET REV="%2"SET USER="%3"SET PROPNAME="%4"SET ACTION="%5"IF %ACTION% == "M" (IF %PR

2015-09-21 11:06:35 803

转载 VisualSVN设置提交时必须输入log信息

http://www.cnblogs.com/lancidie/p/3142001.html

2015-09-21 11:02:46 601

原创 js懒人工具包

js懒人工具包

2015-09-11 13:44:38 2385

转载 用Windows引导器启动Grub

一般Linux、Windows双系统用户习惯用Linux的启动管理器Grub引导Windows,但由于以下原因,有时还需要用Windows的引导器引导Grub:需要保留电脑的一键恢复功能。将Grub写至MBR一般会损坏这一功能。重新安装Windows系统后,MBR中的Grub被Windows覆盖。此时要想启动Linux而又没有Linux修复盘,可采用此文的方法。现主要有两种方案

2014-08-07 17:47:46 1733

转载 WINPE DIY

http://ahtcjxf.blog.163.com/blog/static/468760742009111175742571/引用教父 的WINPE DIY 简介以天琴星座(lyra)·Build 20090226 为例,同时借鉴论坛其他高手制作的 PE 及教程简单介绍关于 WINPE DIY 的一些内容,其中比较复杂(其实是我不懂)的部分一笔带过,需要的自己搜

2014-07-22 21:59:17 2607

转载 爬虫

http://www.oschina.net/p/webmagic

2014-06-10 11:35:47 693

转载 將本地windows 变成 git server服务器

將本地windows 变成 git server服务器   http://freshbrewedcode.com/derekgreer/2012/02/19/hosting-a-git-repository-in-windows/

2014-06-10 11:27:40 598

转载 统计

http://commons.apache.org/proper/commons-math/userguide/stat.htmlhttps://code.google.com/p/java-statistical-analysis-tool/wiki/Examples

2014-05-31 23:00:57 773

原创 java代码统计工具

java代码统计工具http://download.csdn.net/detail/china8848/557296

2014-05-31 22:49:58 3643

转载 把java程序注册成windows服务

http://fruitking.iteye.com/blog/466054先去下载一个JavaService-2.0.10.zip 然后解压 有很多文件 这里只需要JavaService.exe这个文件即可 让我们开始吧 自己先写个java程序测试一下 package com.fruitking.test; import java.io.Fil

2014-05-31 22:42:50 660

转载 SVN服务器配置说明

http://www.cnblogs.com/ricksun/articles/1564905.html

2014-05-31 22:38:14 792

转载 推荐一些socket工具,TCP、UDP调试、抓包工具

还记得我在很久很久以前和大家推荐的Fiddler和Charles debugger么?他们都是HTTP的神器级调试工具,非常非常的好用。好工具能让你事半功倍,基本上,我是属于彻头彻尾的工具控。  假如有一天,你写“传统”的PHP有些累了,想玩玩socket了,搞搞python、NodeJS、GO之类的新兴语言或框架(当然我不是说这些语言不能写web),或者干脆就用PHP吧,事实上PHP5.

2014-05-21 16:22:50 61706 1

原创 Gradle笔记

6.1每个构建包含一个或多个 "Project"每个project包含一个或多个 "Task",每个 task 都是一个原子操作,或是编译一些文件,或是打jar包 ,或是生成javadoc6.2你可以用gradle命令来调用当前目录下的build.gradle文件,build.gradle通常称之为构建脚本;构建脚本中定义了一个项目和包含的任务hel

2014-05-20 13:53:50 16047 1

转载 The Hibernate build.gradle source code

apply plugin: 'eclipse'apply plugin: 'idea'allprojects { repositories { mavenCentral() mavenLocal() mavenRepo name: 'jboss-nexus', urls: "https://repository.jboss.org/ne

2014-05-20 13:20:20 1963

转载 栈的应用 --- 迷宫解题(超详细版!)

https://software.intel.com/zh-cn/blogs/2014/03/03/?utm_campaign=CSDN&utm_source=intel.csdn.net&utm_medium=Link&utm_content=%20others-%20suanfa注:为了不离开本节讨论的重点--栈,迷宫的自动生成以后重新写。这里用简单的二维数组代替,

2014-05-20 10:24:33 732

转载 Hiren’s BootCD 15.2下载 – 史上最强大的WinPE U盘启动工具详细介绍

说起Hiren's BootCD,国人可能不太了解,它在国外可是非常流行的。在国内用得最多的无非就是老毛桃、深度PE、深山红叶等WinPE系统,但是更新都好慢。对老的机器还行,对新的电脑就不一定了。上个星期有一位同事要把她的 Thinkpad X220 由原来的 Windows 7 家庭版装成XP系统,又是找我弄。当时我用晨枫u盘维护工具3.0进入,直接给你来了个蓝屏。我以为是SATA接口问题

2014-05-20 10:21:43 7325 1

转载 Java自带的性能监测工具用法简介——jstack、jconsole、jinfo、jmap、jdb、jsta、jvisualvm

在开始介绍之前,先介绍几篇写的比较详细的博客,咱们不求最精,一定最全,最省事。 http://blog.csdn.net/fenglibing/article/details/6411924 一、jstatd 启动jvm监控服务。它是一个基于rmi的应用,向远程机器提供本机jvm应用程序的信息。默认端口1099。 实例:jstatd -J-Djava.security.policy

2014-05-13 09:59:54 1290

转载 visualSVN server绿化策略 摆脱两个apache的尴尬

SVN就不多说了,非常好用的版本控制!安装也非常简单。我的开发环境是WINDOWS,方案是VisualSVN Server和TortoiseSVN,这个安装起来简直超方便!不过有一点非常严重的问题就是官方的VisualSVNServer的安装包里面自带apache服务器,安装的时候不能与本机原有apache(或IIS)端口冲突,这样我的最初的情况就变成机器里有两个apache,4个httpd.ex

2014-05-09 17:41:48 2125

转载 Maven的搭建

用maven将组件发布到本地nexus 服务器http://niyanshi.iteye.com/blog/1250632http://www.cnblogs.com/cbf4life/archive/2010/01/29/1659502.htmlhttp://niyanshi.iteye.com/blog/1250632利用Nexus搭建Maven的本地仓库服务器http:/

2014-05-06 07:50:59 492

转载 GoF著作中未提到的设计模式(5):Object Pool

Object Pool,即对象池,对象被预先创建并初始化后放入对象池中,对象提供者就能利用已有的对象来处理请求,减少对象频繁创建所占用的内存空间和初始化时间,例如数据库连接对象基本上都是创建后就被放入连接池中,后续的查询请求使用的是连接池中的对象,从而加快了查询速度。类似被放入对象池中的对象还包括Socket对象、线程对象和绘图对象(GDI对象)等。  在Object Pool设计模式中,主要

2014-04-30 17:51:50 445

转载 GoF著作中未提到的设计模式(6):Specification

在一个较为复杂的业务流程中,某些条件的满足与否决定了业务逻辑的走向,我们可以把这些条件抽离出来,使得任意个条件以某种关系进行组合,从而灵活地对业务逻辑进行定制。另外,在查询、过滤等应用场合中,我们也可以预定义多个条件,使用这些条件的组合来处理查询逻辑,而不是使用逻辑判断语句来处理,那样只会让代码变得复杂,让脑袋变大。  在Specification设计模式中,一个条件就是一个specifi

2014-04-30 17:42:54 497

转载 GoF著作中未提到的设计模式(7):Publish-Subscribe

很多项目中都有消息分发或者事件通知机制,尤其是模块化程度高的项目。例如在办公自动化系统中,有些子系统对于新建用户这一事件很感兴趣,权限模块希望为这个新用户设置默认的权限,报表模块希望重新生成当月的报表,诸如此类的代码都写到新建用户的业务逻辑后面,会加大耦合度,可维护性降低,并且对于每个模块都是一个独立工程的情况,这种方式更是不可取。对于简单的情形,观察者模式就适用了,如果系统中有很多地方都需要收发

2014-04-30 17:40:21 358

转载 GoF著作中未提到的设计模式(3):Null Object

Null Object模式的目的包括:1. 当对象提供者无法提供指定类型的对象时, 返回一个什么都不做的对象, 这对调用者是透明的,并且调用者不用判断获得的对象是否为null了,当然,对象提供者必须告知调用者(通过约定等).2. 有时候需要传递一个什么都不做的某个类型的对象给合作方. 例如某个函数需要实现特定接口的对象(通过参数传入)进行某些操作, 该函数的调用者在某些情况下希望不

2014-04-30 17:38:07 522

转载 GoF著作中未提到的设计模式(1): Archetype

GoF著作中未提到的设计模式(1):Archetype  半天也没能给这个设计模式想出一个中文名称,算了,有时候还是原版的更容易理解。  简单地说,Archetype设计模式的目的是将业务处理逻辑和具体实现分离,所以至少需要两个参与者:Decorator和Delegate,它们都实现同一个接口,Decorator负责处理业务逻辑,而Delegate负责具体的实现,在Decorato

2014-04-30 17:36:17 534

基于Javascript的可视化流程设计器

基于Javascript的可视化流程设计器

2013-11-04

基于Extjs的可视化流程设计开发

基于Extjs的可视化流程设计开发,只要放于web容器下,即可运行,主要使用了extjs的框架,使系统可以可视化设计

2013-11-04

完整的ERP流程图大全

图23.1 企业销售管理业务的第一层数据流图 3 图23.2 销售基础数据管理业务数据流图(第二层数据流) 4 图23.3 销售计划管理业务数据流图(第二层数据流) 4 图23.4 销售订单管理业务数据流图(第二层数据流) 5 图23.5 销售收发货管理业务数据流图(第二层数据流) 5 图23.6 销售服务管理业务数据流图(第二层数据流) 6 图23.7 企业销售管理E—R关系图 6 图23.8 销售管理系统的功能模块图 7 图24.1 企业采购管理数据流程图 8 图24.2 采购基础数据管理数据流程图(第二层数据流) 9 图24.3 采购计划管理数据流程图(第二层数据流) 9 图24.4 采购订单处理数据流程图(第二层数据流) 10 图24.5 采购收货管理数据流程图(第二层数据流) 10 图24.6 采购系统实体关系图 11 图24.7 采购系统模块图 12 图25.1 企业库存管理第一层数据流图 13 图25.2 库存基础数据管理数据流图(第二层数据流) 14 图25.3 库存处理数据流图(第二层数据流) 14 图25.4 入库处理展开数据流图(第三层数据流) 15 图25.5 出库处理展开数据流图(第三层数据流) 15 图25.6 企业库存管理E—R关系图 16 图25.7 库存管理系统功能模块图 17 图26.1 制造标准管理业务数据流图 18 图26.2 制造标准管理实体关系图 18 图26.3 制造标准管理功能模块图 19 图27.1 计划管理业务数据流图 20 图27.2 主生产计划管理业务数据流图(第二层数据流程图) 20 图27.3 物料需求计划管理业务数据流图第二层数据流程图) 21 图27.4 能力需求计划管理业务数据流图第二层数据流程图) 21 图27.5 计划管理实体关系 22 图27.6 计划管理功能模块图 23 图28.1 企业车间管理第一层数据流图 24 图28.2 车间任务管理系统数据流程图 24 图28.3 生产工票管理数据流程图 25 图28.4 车间物料管理数据流程图 25 图28.5 车间完工管理数据流程图 25 图28.6 企业生产管理E—R关系图 26 图28.7 车间管理系统功能模块图 27 图29.1 JIT生产管理数据流程图 28 图29.2 JIT计划管理数据流程图(第二层数据流程图) 28 图29.3 JIT系统维护数据流程图(第二层数据流程图) 29 图29.4 JIT生产管理数据流程图(第二层数据流程图) 29 图29.5 JIT系统实体关系图 30 图29.6 JIT功能模块图 30 30.1 质量管理数据流程图(简化) 31 图30.2 质量管理基本数据维护数据流程图(第二层) 31 图30.3 质量管理质量标准数据流程图(第二层) 32 图30.4 质量管理质量检验数据流程图(第二层) 32 图30.5 质量管理系统的实体关系 32 图30.6 质量管理功能模块图 33 图31.1 企业财务管理业务数据流图(简化) 34 图31.2 财务管理系统的功能模块图 35 图32.1 人力资源管理数据流程图 36 图32.2 人事管理数据流程图(第二层) 36 图32.3 人力资源计划管理数据流程图(第二层) 37 图32.4 招聘管理数据流程图(第二层) 37 图32.5 培训管理数据流程图(第二层) 37 图32.6 人力资源测评数据流程图(第二层) 38 图32.7 人力资源管理的实体关系 38 图32.8 人力资源管理功能模块图 39 图33.1设备与仪器管理业务数据流程图 40 图33.2设备与仪器基本资料管理数据流程图(第二层, 可继续展开) 40 图33.3设备与仪器业务管理数据流程图(第二层数据流) 41 图33.4 设备管理实体关系图 41 图33.5 设备管理功能模块图 42

2013-08-13

axis web service的教程,入门到精通

axis web service的教程,入门到精通

2013-07-24

web service 客户端java例子

java web service, web service 客户端java例子,

2013-07-24

axis专用开发包

axis专用开发包 AXIS学习笔记 关键词: AXIS AXIS学习笔记(一) ronghao100 原创 前天头告诉我用SOAP WEB服务开发一个客户程序,用来与企业内部的ERP进行交互。晚上赶快找相关的资料猛看,总算对SOAP有了一定的认识。干程序员这行真不容易,好象得不停地学习新东西,一不小心就被淘汰:(不过学习也是个很有意思的事情。好了,废话少说,让我们开始吧。 一、软件环境 1、axis-1_2 (从apache网站下载最新axis-bin-1_2.zip解压即可) 2、Tomcat5.0 3、JDK5.0 二、相关配置 1、在你的%TOMCAT_HOME%\common\lib下需要加入三个包 activation.jar、mail.jar、tools.jar 2、环境变量设置 AXIS_HOME 即axis-bin-1_2.zip解压的目录(我的是在F:\soap\axis-1_2) AXIS_LIB 即 %AXIS_HOME%\lib AXISCLASSPATH 即 %AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;也就是把%AXIS_LIB%下所用JAR文件都导入 三、实验一下 在%AXIS_HOME%\webapps下找到axis文件夹,将其整个拷贝到%TOMCAT_HOME%\webapps下,启动 Tomcat,打开浏览器访问http://localhost:8080/axis/,出现以下页面说明你配置成功了。很简单吧:) 四、发布我们的第一个程序 第一个程序简单的返回HELLO WORLD! HelloWorld.java public class HelloWorld { public String sayHello() { return "HELLO WORLD!"; } } 我们的第一种发布方式: 将HelloWorld.java拷贝到%TOMCAT_HOME%\webapps\axis下,然后将其改名为HelloWorld.jws,这样AXIS就自然将其发布了。现在写个客户端程序访问一下: TestClient.java import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.rpc.ParameterMode; public class TestClient { public static void main(String [] args) throws Exception { String endpoint = "http://localhost:" +"8080"+ "/axis/HelloWorld.jws";//指明服务所在位置 Service service = new Service(); //创建一个Service实例,注意是必须的! Call call = (Call) service.createCall();//创建Call实例,也是必须的! call.setTargetEndpointAddress( new java.net.URL(endpoint) );//为Call设置服务的位置 call.setOperationName( "sayHello" );//注意方法名与HelloWorld.java中一样!! String res = (String) call.invoke( new Object[] {} );//返回String,没有传入参数 System.out.println( res ); } } 我的测试是在jbuilder2005中,注意项目中要导入其自带的AXIS包(当然应该把其中JAR文件替换一下),可以看到程序返回了 "HELLO WORLD!" 可以看到在AXIS里发布服务其实是一件很容易的事,这是因为这个服务很简单的原因:)下面我们介绍第二种发布方式,这是常用的。 我们的第二种发布方式: 1、将HelloWorld.java编译成HelloWorld.class,放到%TOMCAT_HOME%\webapps\axis\WEB-INF\classes 下 2、在%TOMCAT_HOME%\webapps\axis\WEB-INF下新建deploy.wsdd文件,即SOAP服务发布描述文件 deploy.wsdd <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="" target="_blank">http://xml.apache.org/axis/wsdd/providers/java"> <service name="HelloWorld" provider="java:RPC"> <parameter name="className" value="HelloWorld"/> <parameter name="allowedMethods" value="sayHello"/> </service> </deployment> 在DOS下转换目录到%TOMCAT_HOME%\webapps\axis\WEB-INF,命令: java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.wsdd 你会发现目录下多了一个server-config.wsdd文件,这就是AXIS的配置文件,以后所有的服务发布描述都会在里面找到。(当然,你可以直接修改它,不用再写deploy.wsdd)然后打开浏览器http://localhost:8080/axis/servlet/AxisServlet,你就会看到你的服务已发布 同样用客户端程序访问一下:(注意和上边的差别!!) HelloClient.java import org.apache.axis.client.Call; import org.apache.axis.client.Service; public class HelloClient { public static void main(String [] args) throws Exception { String endpoint = "http://localhost:" +"8080"+ "/axis/services/HelloWorld";//注意!差别仅仅在这里!! Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName("sayHello" ); String res = (String) call.invoke( new Object[] {} ); System.out.println( res ); } } 好了,相信你对AXIS已有了大致的了解。接下来将会涉及到传参数、JAVABEAN对象,及AXIS的安全问题,下次再说吧:)也欢迎和我,一个快乐的JAVA程序员,联系:)[email protected] ++++++++++++++++++++++++++++++++++++++ AXIS学习笔记(二)使用Handler来增强Web服务的功能 Handler的基本概念 J2EE Web 服务中的Handler技术特点非常像Servlet技术中的Filter。我们知道,在Servlet中,当一个HTTP到达服务端时,往往要经过多个Filter对请求进行过滤,然后才到达提供服务的Servlet,这些Filter的功能往往是对请求进行统一编码,对用户进行认证,把用户的访问写入系统日志等。相应的,Web服务中的Handler通常也提供一下的功能: 对客户端进行认证、授权; 把用户的访问写入系统日志; 对请求的SOAP消息进行加密,解密; 为Web Services对象做缓存。 SOAP消息Handler能够访问代表RPC请求或者响应的SOAP消息。在JAX-RPC技术中,SOAP消息Handler可以部署在服务端,也可以在客户端使用。 下面我们来看一个典型的SOAP消息Handler处理顺序: 某个在线支付服务需要防止非授权的用户访问或者撰改服务端和客户端传输的信息,从而使用消息摘要(Message Digest)的方法对请求和响应的SOAP消息进行加密。当客户端发送SOAP消⑹保?突Ф说?andler把请求消息中的某些敏感的信息(如信用卡密码)进行加密,然后把加密后的SOAP消息传输到服务端;服务端的SOAP消息Handler截取客户端的请求,把请求的SOAP 消息进行解密,然后把解密后的SOAP消息派发到目标的Web服务端点。 Apache axis是我们当前开发Web服务的较好的选择,使用axisWeb服务开发工具,可以使用Handler来对服务端的请求和响应进行处理。典型的情况下,请求传递如图1所示。 图1 SOAP消息的传递顺序 在图中,轴心点(pivot point)是Apache与提供程序功能相当的部分,通过它来和目标的Web服务进行交互,它通常称为Provider。axis中常用的Provider有Java:RPC,java:MSG,java:EJB。一个Web服务可以部署一个或者多个Handler。 Apache axis中的Handler体系结构和JAX-RPC 1.0(JSR101)中的体系结构稍有不同,需要声明的是,本文的代码在axis中开发,故需要在axis环境下运行。 在axis环境下,SOAP消息Handler必须实现org.apache.axis.Handler接口(在JAX-RPC 1.0规范中,SOAP消息Handler必须实现javax.xml.rpc.handler.Handler接口),org.apache.axis.Handler接口的部分代码如下: 例程1 org.apache.axis.Handle的部分代码 public interface Handler extends Serializable { public void init(); public void cleanup(); public void invoke(MessageContext msgContext) throws AxisFault ; public void onFault(MessageContext msgContext); public void setOption(String name, Object value); public Object getOption(String name); public void setName(String name); public String getName(); public Element getDeploymentData(Document doc); public void generateWSDL(MessageContext msgContext) throws AxisFault; … } 为了提供开发的方便,在编写Handler时,只要继承org.apache.axis.handlers. BasicHandler即可,BasicHandler是Handler的一个模板,我们看它的部分代码: 例程2 BasicHandler的部分代码 public abstract class BasicHandler implements Handler { protected static Log log = LogFactory.getLog(BasicHandler.class.getName()); protected Hashtable options; protected String name; //这个方法必须在Handler中实现。 public abstract void invoke(MessageContext msgContext) throws AxisFault; public void setOption(String name, Object value) { if ( options == null ) initHashtable(); options.put( name, value ); } … } BasicHandler中的(MessageContext msgContext)方法是Handler实现类必须实现的方法,它通过MessageContext来获得请求或者响应的SOAPMessage对象,然后对SOAPMessage进行处理。 在介绍Handler的开发之前,我们先来看一下目标Web服务的端点实现类的代码,如例程3所示。 例程3 目标Web服务的端点实现类 package com.hellking.webservice; public class HandleredService { //一个简单的Web服务 public String publicMethod(String name) { return "Hello!"+name; } } //另一个Web服务端点: package com.hellking.webservice; public class OrderService { //web服务方法:获得客户端的订单信息,并且对订单信息进行对应的处理, 通常情况是把订单的信息写入数据库,然后可客户端返回确认信息。 public String orderProduct(String name,String address,String item,int quantity,Card card) { String cardId=card.getCardId(); String cardType=card.getCardType(); String password=card.getPassword(); String rderInfo="name="+name+",address="+address+",item="+item+",quantity="+quantity+" ,cardId="+cardId+",cardType="+cardType+",password="+password; System.out.println("这里是客户端发送来的信息:"); System.out.println(orderInfo); return orderInfo; } } 下面我们分不同情况讨论Handler的使用实例。 使用Handler为系统做日志 Handler为系统做日志是一种比较常见而且简单的使用方式。和Servlet中的Filter一样,我们可以使用Handler来把用户的访问写入系统日志。下面我们来看日志Handler的具体代码,如例程4所示。 例程4 LogHandler的代码 package com.hellking.webservice; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.Date; import org.apache.axis.AxisFault; import org.apache.axis.Handler; import org.apache.axis.MessageContext; import org.apache.axis.handlers.BasicHandler; public class LogHandler extends BasicHandler { /**invoke,每一个handler都必须实现的方法。 */ public void invoke(MessageContext msgContext) throws AxisFault { //每当web服务被调用,都记录到log中。 try { Handler handler = msgContext.getService(); String filename = (String)getOption("filename"); if ((filename == null) || (filename.equals(""))) throw new AxisFault("Server.NoLogFile", "No log file configured for the LogHandler!", null, null); FileOutputStream fos = new FileOutputStream(filename, true); PrintWriter writer = new PrintWriter(fos); Integer counter = (Integer)handler.getOption("accesses"); if (counter == null) counter = new Integer(0); counter = new Integer(counter.intValue() + 1); Date date = new Date(); msgContext.getMessage().writeTo(System.out); String result = "在"+date + ": Web 服务 " + msgContext.getTargetService() + " 被调用,现在已经共调用了 " + counter + " 次."; handler.setOption("accesses", counter); writer.println(result); writer.close(); } catch (Exception e) { throw AxisFault.makeFault(e); } } } 前面我们说过,Handler实现类必须实现invoke方法,invoke方法是Handler处理其业务的入口点。LogHandler的主要功能是把客户端访问的Web服务的名称和访问时间、访问的次数记录到一个日志文件中。 下面部署这个前面开发的Web服务对像,然后为Web服务指定Handler。编辑Axis_Home/WEB-INF/ server-config.wsdd文件,在其中加入以下的内容: <service name="HandleredService" provider="java:RPC"> <parameter name="allowedMethods" value="*"/> <parameter name="className" value="com.hellking.webservice.HandleredService"/> <parameter name="allowedRoles" value="chen"/> <beanMapping languageSpecificType="java:com.hellking.webservice.Card" qname="card:card" xmlns:card="card"/> <requestFlow> <handler name="logging" type="java:com.hellking.webservice.LogHandler"> <parameter name="filename" value="c:\\MyService.log"/> </handler> </requestFlow> </service> … </globalConfiguration> … <handler name="logging" type="java:com.hellking.webservice.LogHandler"> <parameter name="filename" value="c:\\MyService.log"/> </handler> … <service name="HandleredService" provider="java:RPC"> … <requestFlow> <handler type="logging"/> …<!--在这里可以指定多个Handler--> </requestFlow> </service> http://127.0.0.1:8080/handler/services/HandleredService?wsdl&method=publicMethod&name=chen 注意:这个URL需要根据具体情况改变。 在Sun Jul 06 22:42:03 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 1 次. 在Sun Jul 06 22:42:06 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 2 次. 在Sun Jul 06 22:42:13 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 3 次. 使用Handler对用户的访问认证 使用Handler为用户访问认证也是它的典型使用,通过它,可以减少在Web服务端代码中认证的麻烦,同时可以在部署描述符中灵活改变用户的访问权限。 对用户认证的Handler代码如下: 例程5 认证的Handler package com.hellking.webservice; import…. //此handler的目的是对用户认证,只有认证的用户才能访问目标服务。 public class AuthenticationHandler extends BasicHandler { /**invoke,每一个handler都必须实现的方法。 */ public void invoke(MessageContext msgContext)throws AxisFault { SecurityProvider provider = (SecurityProvider)msgContext.getProperty("securityProvider"); if(provider==null) { provider= new SimpleSecurityProvider(); msgContext.setProperty("securityProvider", provider); } if(provider!=null) { String userId=msgContext.getUsername(); String password=msgContext.getPassword(); //对用户进行认证,如果authUser==null,表示没有通过认证, 抛出Server.Unauthenticated异常。 org.apache.axis.security.AuthenticatedUser authUser = provider.authenticate(msgContext); if(authUser==null) throw new AxisFault("Server.Unauthenticated", Messages.getMessage("cantAuth01", userId), null,null); //用户通过认证,把用户的设置成认证了的用户。 msgContext.setProperty("authenticatedUser", authUser); } } } 在AuthenticationHandler代码里,它从MessageContext中获得用户信息,然后进行认证,如果认证成功,那么就使用msgContext.setProperty("authenticatedUser", authUser)方法把用户设置成认证了的用户,如果认证不成功,那么就抛出Server.Unauthenticated异常。 部署这个Handler,同样,在server-config里加入以下的内容: <handler name="authen" type="java:com.hellking.webservice.AuthenticationHandler"/> … <service name="HandleredService" provider="java:RPC"> <parameter name="allowedRoles" value="chen"/> … </service> WEB-INF/users.lst文件中加入以下用户: hellking hellking chen chen http://127.0.0.1:8080/handler/services/HandleredService?wsdl&method=publicMethod&name=chen 将会提示输入用户名和密码,如图2所示。 图2 访问web服务时的验证 如果客户端是应用程序,那么可以这样在客户端设置用户名和密码: 例程6 在客户端设置用户名和密码 http://127.0.0.1:808 String endpointURL = "http://127.0.0.1:8080/handler/services/HandleredService?wsdl"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpointURL) ); call.setOperationName( new QName("HandleredService", "orderProduct") );//设置操作的名称。 //由于需要认证,故需要设置调用的用户名和密码。 call.getMessageContext().setUsername("chen"); call.getMessageContext().setPassword("chen"); 使用Handler对用户的访问授权 对于已经认证了的用户,有时在他们操作某个特定的服务时,还需要进行授权,只有授权的用户才能继续进行操作。我们看对用户进行授权的Handler的代码。 例程7 对用户进行授权的代码 package com.hellking.webservice; import… //此handler的目的是对认证的用户授权,只有授权的用户才能访问目标服务。 public class AuthorizationHandler extends BasicHandler { /**invoke,每一个handler都必须实现的方法。 */ public void invoke(MessageContext msgContext) throws AxisFault { AuthenticatedUser user = (AuthenticatedUser)msgContext.getProperty("authenticatedUser"); if(user == null) throw new AxisFault("Server.NoUser", Messages.getMessage("needUser00"), null, null); String userId = user.getName(); Handler serviceHandler = msgContext.getService(); if(serviceHandler == null) throw new AxisFault(Messages.getMessage("needService00")); String serviceName = serviceHandler.getName(); String allowedRoles = (String)serviceHandler.getOption("allowedRoles"); if(allowedRoles == null) { return; } SecurityProvider provider = (SecurityProvider)msgContext.getProperty("securityProvider"); if(provider == null) throw new AxisFault(Messages.getMessage("noSecurity00")); for(StringTokenizer st = new StringTokenizer(allowedRoles, ","); st.hasMoreTokens();) { String thisRole = st.nextToken(); if(provider.userMatches(user, thisRole)) { return;//访问授权通过。 } } //没有通过授权,不能访问目标服务,抛出Server.Unauthorized异常。 throw new AxisFault("Server.Unauthorized", Messages.getMessage("cantAuth02", userId, serviceName), null, null); } } 在service-config.wsdd文件中,我们为Web服务指定了以下的用户: <parameter name="allowedRoles" value="chen,hellking"/> provider.userMatches(user, thisRole)将匹配允许访问Web服务的用户,如果匹配成功,那么授权通过,如果没有授权成功,那么抛出Server.Unauthorized异常。 使用Handler对SOAP消息进行加密、解密 由于SOAP消息在HTTP协议中传输,而HTTP协议的安全度是比较低的,怎么保证信息安全到达对方而不泄漏或中途被撰改,将是Web服务必须解决的问题。围绕Web服务的安全,有很多相关的技术,比如WS-Security,WS-Trace等,另外,还有以下相关技术: XML Digital Signature(XML数字签名) XML Encryption (XML加密) XKMS (XML Key Management Specification) XACML (eXtensible Access Control Markup Language) SAML (Secure Assertion Markup Language) ebXML Message Service Security Identity Management & Liberty Project 不管使用什么技术,要使信息安全到达对方,必须把它进行加密,然后在对方收到信息后解密。为了提供开发的方便,可以使用Handler技术,在客户端发送信息前,使用客户端的Handler对SOAP消息中的关键信息进行加密;在服务端接收到消息后,有相应的Handler把消息进行解密,然后才把SOAP消息派发到目标服务。 下面我们来看一个具体的例子。加入使用SOAP消息发送订单的信息,订单的信息如下: 例程8 要发送的订单SOAP消息 <soap-env:Envelope xmlns:soap-env="" target="_blank">http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Header/> <soapenv:Body> <ns1:orderProduct soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encod ing/" xmlns:ns1="HandleredService"> <arg0 xsi:type="xsd:string">hellking</arg0> <arg1 xsi:type="xsd:string">beijing</arg1> <arg2 xsi:type="xsd:string">music-100</arg2> <arg3 xsi:type="xsd:int">10</arg3> <arg4 href="#id0"/> </ns1:orderProduct> <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmls oap.org/soap/encoding/" xsi:type="ns2:card" xmlns:soapenc="http://schemas.xmlsoa p.org/soap/encoding/" xmlns:ns2="card"> <cardId xsi:type="xsd:string">234230572</cardId> <cardType xsi:type="xsd:string">visa</cardType> <password xsi:type="xsd:string">234kdsjf</password> </multiRef> </soapenv:Body> </soap-env:Envelope> 上面的黑体字是传输的敏感信息,故需要加密。我们可以使用Message Digest之类的方法进行加密。加密之后的信息结构如下: 例程9 把SOAP消息某些部分加密 <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope … <soapenv:Body> <ns1:orderProduct …> … <arg4 href="#id0"/> </ns1:orderProduct> <multiRef …> <ns3:EncryptedData xmlns:ns3="" target="_blank">http://www.w3.org/2000/11/temp-xmlenc"> <ns3:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ns3:DigestValue>rO0ABXQAkyA8Y2FyZ……. </ns3:DigestValue> </ns3:EncryptedData> </multiRef> </soapenv:Body> </soapenv:Envelope> 图3是使用Handler对SOAP消息进行加密、解密后,SOAP消息在传递过程中结构的改变。 图3 SOAP消息的加密和解密 从上图可以看出,通过使用加密、解密的Handler,可以确保消息的安全传递。进一步说,如果把这种Handler做成通用的组件,那么就可以灵活地部署到不同的服务端和客户端。 客户端的Handler的功能是把SOAP消息使用一定的规则加密,假如使用Message Digest加密方式,那么可以这样对敏感的信息加密: 例程10 对SOAP消息的敏感部分加密 SOAPElement ele= soapBodyElement.addChildElement(envelope.createName ("EncryptedData","","http://www.w3.org/2000/11/temp-xmlenc")); ele.addChildElement("DigestMethod").addAttribute(envelope.createName ("Algorithm"),"http://www.w3.org/2000/09/xmldsig#sha1"); byte[] digest=new byte[100]; ByteArrayOutputStream out=new ByteArrayOutputStream (100); MessageDigest md = MessageDigest.getInstance("SHA"); ObjectOutputStream oos = new ObjectOutputStream(out); //要加密的信息 String data = " <cardId xsi:type='xsd:string'>234230572 </cardId><cardType xsi:type='xsd:string'>visa</cardType> <password xsi:type='xsd:string'>234kdsjf</password>"; byte buf[] = data.getBytes(); md.update(buf); oos.writeObject(data); oos.writeObject(md.digest()); digest=out.toByteArray(); out.close(); ele.addChildElement("DigestValue").addTextNode(new sun.misc.BASE64Encoder().encode(digest));//对加密的信息编码 在客户端发送出SOAP消息时,客户端的Handler拦截发送的SOAP消息,然后对它们进行加密,最后把加密的信息传送到服务端。 服务端接收到加密的信息后,解密的Handler会把对应的加密信息解密。服务端Handler代码如例程11所示。 例程11 服务端解密Handler package com.hellking.webservice; import… //此handler的目的是把加密的SOAP消息解密成目标服务可以使用的SOAP消息。 public class MessageDigestHandler extends BasicHandler { /**invoke,每一个handler都必须实现的方法。 */ public void invoke(MessageContext msgContext)throws AxisFault { try { //从messageContext例取得SOAPMessage对象。 SOAPMessage msg=msgContext.getMessage(); SOAPEnvelope env=msg.getSOAPPart().getEnvelope(); Iterator it=env.getBody().getChildElements(); SOAPElement multi=null; while(it.hasNext()) { multi=(SOAPElement)it.next();//multi是soapbody的最后一个child。 } String value="";//value表示加密后的值。 SOAPElement digestValue=null; Iterator it2=multi.getChildElements(); while(it2.hasNext()) { SOAPElement temp=(SOAPElement)it2.next(); Iterator it3=temp.getChildElements(env.createName("DigestValue", "ns3","http://www.w3.org/2000/11/temp-xmlenc")); if(it3.hasNext()) value=((SOAPElement)it3.next()).getValue();//获得加密的值 } //把加密的SOAPMessage解密成目标服务可以调用的SOAP消息。 SOAPMessage msg2=convertMessage(msg,this.decrypte(value)); msgContext.setMessage(msg2); } catch(Exception e) { e.printStackTrace(); } } //这个方法是把加密的数据进行解密,返回明文。 public String decrypte(String value) { String data=null; try { ByteArrayInputStream fis = new ByteArrayInputStream(new sun.misc.BASE64Decoder().decodeBuffer(value)); ObjectInputStream ois = new ObjectInputStream(fis); Object o = ois.readObject(); if (!(o instanceof String)) { System.out.println("Unexpected data in string"); System.exit(-1); } data = (String) o; System.out.println("解密后的值:" + data); o = ois.readObject(); if (!(o instanceof byte[])) { System.out.println("Unexpected data in string"); System.exit(-1); } byte origDigest[] = (byte []) o; MessageDigest md = MessageDigest.getInstance("SHA"); md.update(data.getBytes()); } … return data; } //把解密后的信息重新组装成服务端能够使用的SOAP消息。 public SOAPMessage convertMessage(SOAPMessage msg,String data) { …. } } 可以看出,服务端解密的Handler和客户端加密的Handler的操作是相反的过程。 总结 通过以上的讨论,相信大家已经掌握了Handler的基本使用技巧。可以看出,通过使用Handler,可以给Web服务提供一些额外的功能。在实际的开发中,我们可以开发出一些通用的Handler,然后通过不同的搭配方式把它们部署到不同的Web服务中。 +++++++++++++++++++++++++++++++++++++++ AXIS学习笔记(三)(建立安全的AXIS服务上) ronghao100 原创 在前面的文章中,我们实现了最简单的AXIS服务。现在我们一起来讨论一下Web服务的安全问题。 根据应用的对安全要求的级别不同,可以采用不同的方式来实现安全性,以下是目前最常用的一些实现方式(从低到高排列): 1、J2EE Web应用默认的访问控制(数据是明文的); 2、使用axis的Handler进行访问控制(数据是明文的); 3、使用Servlet过滤器(Filter)进行访问控制(数据是明文的); 4、使用SSL/HTTPS协议来传输(加密的数据传输协议); 5、使用WS-Security规范对信息进行加密与身份认证(数据被加密传输)。 我们仅讨论第2、4、5种实现方式。在此之前我们先来了解一下AXIS自带的一个工具SOAPMonitor。 一、SOAPMonitor的使用 打开http://localhost:8080/axis/进入AXIS的主页面,你会看见: SOAPMonitor-[disabled by default for security reasons] ,默认状态下其是不可用的,现在我们就来激活它。 1、到目录%TOMCAT_HOME%\webapps\axis下,你会找到SOAPMonitorApplet.java,在命令行中编译它: javac -classpath %AXIS_HOME%\lib\axis.jar SOAPMonitorApplet.java 编译完之后你会看见目录下多了很多CLASS文件,它们的名字是SOAPMonitorApplet*.class 2、在目录%TOMCAT_HOME%\webapps\axis\WEB-INF下打开server-config.wsdd文件,将下面的两部分代码直 接加入其中相应的位置 第一部分: <handler name="soapmonitor" type="java:org.apache.axis.handlers.SOAPMonitorHandler"> <parameter name="wsdlURL" value="/axis/SOAPMonitorService-impl.wsdl"/> <parameter name="namespace" value="" target="_blank">http://tempuri.org/wsdl/2001/12/SOAPMonitorService-impl.wsdl"/> <parameter name="serviceName" value="SOAPMonitorService"/> <parameter name="portName" value="Demo"/> </handler> 第二部分: <service name="SOAPMonitorService" provider="java:RPC"> <parameter name="allowedMethods" value="publishMessage"/> <parameter name="className" value="org.apache.axis.monitor.SOAPMonitorService"/> <parameter name="scope" value="Application"/> </service> 3、选择你要监控的服务 以上次的HelloWorld服务为例,在server-config.wsdd中你会找到这段代码 <service name="HelloWorld" provider="java:RPC"> <parameter name="allowedMethods" value="sayHello"/> <parameter name="className" value="HelloWorld"/> </service> 在这段代码中加入以下的代码: <requestFlow> <handler type="soapmonitor"/> </requestFlow> <responseFlow> <handler type="soapmonitor"/> </responseFlow> 最后的样子是: <service name="HelloWorld" provider="java:RPC"> <requestFlow> <handler type="soapmonitor"/> </requestFlow> <responseFlow> <handler type="soapmonitor"/> </responseFlow> <parameter name="allowedMethods" value="sayHello"/> <parameter name="className" value="HelloWorld"/> </service> 这样HelloWorld服务就被监控了 4、启动Tomcat,打开http://localhost:8080/axis/SOAPMonitor,你就会看到Applet界面,在 jbuilder2005中运行我们上次写的客户端程序 TestClient.java。OK!你会在Applet界面看 见客户端与服务器端互发的XML内容,注意这里是明文! 二、使用axis的Handler进行访问控制(对安全要求不高时推荐) axis为Web服务的访问控制提供了相关的配置描述符,并且提供了一个访问控制的简单 Handler。默认情况下,你只要在配置描述符中添加用户,然后在Web服务器的部署描述符中自动允许的角色即可。 1、在axis的配置文件users.lst(位于WEB-INF目录下)中添加一个用户,如"ronghao1111",表示 用户名为ronghao,密码为1111。 2、把例HelloWorld的Web服务重新部署(新加的部分已标出) <service name="HelloWorld" provider="java:RPC"> <requestFlow> <handler type="soapmonitor"/> <handler type="Authenticate"/> //新加的AXIS自带的Handler </requestFlow> <responseFlow> <handler type="soapmonitor"/> </responseFlow> <parameter name="allowedMethods" value="sayHello"/> <parameter name="allowedRoles" value="ronghao"/> //注意,这里是新加的部分! <parameter name="className" value="HelloWorld"/> </service> 在这个部署描述符中,指定HelloWorld服务只能被ronghao访问 3、修改客户端程序 TestClient.java,增加访问用户名、密码(新加的部分已标出) TestClient.java import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.rpc.ParameterMode; public class TestClient { public static void main(String [] args) throws Exception { String endpoint = "http://localhost:" +"8080"+ "/axis/HelloWorld"; Service service = new Service(); Call call = (Call) service.createCall(); call.getMessageContext().setUsername("ronghao");// 用户名。 call.getMessageContext().setPassword("1111");// 密码 call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName( "sayHello" ); String res = (String) call.invoke( new Object[] {} ); System.out.println( res ); } } 执行TestClient,能够顺利访问Web服务;如果修改用户名或者密码,那么就不能访问 。同样, 你在http://localhost:8080/axis/SOAPMonitor中看到的请求和响应的XML是明文! 三、使用SSL/HTTPS协议来传输 Web服务也可以使用SSL作为传输协议。虽然JAX-RPC并没有强制规定是否使用SSL协议,但在tomcat 下使用HTTPS协议。 1、使用JDK自带的工具创建密匙库和信任库。 1)通过使用以下的命令来创建服务器端的密匙库: keytool -genkey -alias Server -keystore server.keystore -keyalg RSA 输入keystore密码: changeit 您的名字与姓氏是什么? [Unknown]: Server 您的组织单位名称是什么? [Unknown]: ec 您的组织名称是什么? [Unknown]: ec 您所在的城市或区域名称是什么? [Unknown]: beijing 您所在的州或省份名称是什么? [Unknown]: beijing 该单位的两字母国家代码是什么 [Unknown]: CN CN=Server, OU=ec, O=ec, L=beijing, ST=beijing, C=CN 正确吗? [否]: y 输入<Server>的主密码 (如果和 keystore 密码相同,按回车): 以上命令执行完成后,将获得一个名为server.keystore的密匙库。 2)生成客户端的信任库。首先输出RSA证书: keytool -export -alias Server -file test_axis.cer -storepass changeit -keystore server.keystore 然后把RSA证书输入到一个新的信任库文件中。这个信任库被客户端使用,被用来验证服务器端的身份。 keytool -import -file test_axis.cer -storepass changeit -keystore client.truststore -alias serverkey -noprompt 以上命令执行完成后,将获得一个名为client.truststore的信任库。 3)同理生成客户端的密匙库client.keystore和服务器端的信任库server.truststore.方便起见给出.bat文件 gen-cer-store.bat内容如下: set SERVER_DN="CN=Server, OU=ec, O=ec, L=BEIJINGC, S=BEIJING, C=CN" set CLIENT_DN="CN=Client, OU=ec, O=ec, L=BEIJING, S=BEIJING, C=CN" set KS_PASS=-storepass changeit set KEYINFO=-keyalg RSA keytool -genkey -alias Server -dname %SERVER_DN% %KS_PASS% -keystore server.keystore %KEYINFO% -keypass changeit keytool -export -alias Server -file test_axis.cer %KS_PASS% -keystore server.keystore keytool -import -file test_axis.cer %KS_PASS% -keystore client.truststore -alias serverkey -noprompt keytool -genkey -alias Client -dname %CLIENT_DN% %KS_PASS% -keystore client.keystore %KEYINFO% -keypass changeit keytool -export -alias Client -file test_axis.cer %KS_PASS% -keystore client.keystore keytool -import -file test_axis.cer %KS_PASS% -keystore server.truststore -alias clientkey -noprompt 好的,现在我们就有了四个文件:server.keystore,server.truststore,client.keystore,client.truststore 2、更改Tomcat的配置文件(server.xml),增加以下部署描述符:(其实里面有,只是被注释掉了) <Connector port="8440" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" clientAuth="true" keystoreFile="f:\server.keystore" keystorePass="changeit" truststoreFile="f:\server.truststore" truststorePass="changeit" sslProtocol="TLS" /> 3、把HelloWorld重新部署一次,在server-config.wsdd中修改如下部署代码。(还原了而已) <service name="HelloWorld" provider="java:RPC"> <requestFlow> <handler type="soapmonitor"/> </requestFlow> <responseFlow> <handler type="soapmonitor"/> </responseFlow> <parameter name="allowedMethods" value="sayHello"/> <parameter name="className" value="HelloWorld"/> </service> 4、修改客户端程序 TestClient.java(修改的部分已标出) public class TestClient { public static void main(String [] args) throws Exception { String endpoint = "https://localhost:" +"8440"+ "/axis/HelloWorld";//注意区别在这里!https! Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName( "sayHello" ); String res = (String) call.invoke( new Object[] {} ); System.out.println( res ); } } 5、最后使用命令来执行客户端程序 java -cp %AXISCLASSPATH% -Djavax.net.ssl.keyStore=client.keystore -Djavax.net.ssl.keyStorePassword=changeit -Djavax.net.ssl.trustStore=client.truststore TestClient +++++++++++++++++++++++++++++++++++++++ AXIS学习笔记(四)(建立安全的AXIS服务下) ronghao100 原创 四、使用WS-Security规范对信息进行加密与身份认证 我们打算用Handler结合WSSecurity实现Web服务安全(Handler的有关内容请参阅AXIS学习笔记(二)) 设想流程:用WSClientRequestHandler.java位于客户端对客户端发出的XML文档进行加密 WSServerRequestHandler.java位于服务器端对客户端发出的加密后的XML文档进行解密 WSServerResponseHandler.java位于服务器端对服务器端返回的XML文档进行加密 WSClientResponseHandler.java位于客户端对服务器端返回的XML文档进行解密 1、使用ISNetworks安全提供者,ISNetworks实现了RSA加密、解密算法。 当然,你也可以使用其它的安全提供者,并且可以使用不同的加密算法。 ISNetworks相关包ISNetworksProvider.jar。拷贝到%TOMCAT_HOME% \webapps\axis\WEB-INF\lib 2、Trust Services Integration Kit提供了一个WS-Security实现。你可以从http://www.xmltrustcenter.org获得相关库文件,分别是ws-security.jar和tsik.jar。ws-security.jar中包含一个WSSecurity类,我们使用它来对XML进行数字签名和验证,加密与解密。同样拷贝到%TOMCAT_HOME%\webapps\axis\WEB-INF\lib 3、创建密匙库和信任库。(见上文,一模一样!) 4、框架结构 WSClientHandler.java //基类,包含了一些公用方法 WSClientRequestHandler.java //继承于WSClientHandler.java,调用WSHelper.java对客户端发出的XML文档进行加密 WSClientResponseHandler.java //继承于WSClientHandler.java,调用WSHelper.java对服务器端返回的XML文档进行解密 WSServerHandler.java //基类,包含了一些公用方法 WSServerRequestHandler.java //继承于WSServerHandler.java,调用WSHelper.java对客户端发出的加密后的XML文档进行解密 WSServerResponseHandler.java//继承于WSServerHandler.java,调用WSHelper.java对服务器端返回的XML文档进行加密 WSHelper.java //核心类,对SOAP消息签名、加密、解密、身份验证 MessageConverter.java //帮助类,Document、SOAP消息互相转换 5、具体分析(在此强烈建议看一下tsik.jar的API) WSHelper.java public class WSHelper { static String PROVIDER="ISNetworks";//JSSE安全提供者。 //添加JSSE安全提供者,你也可以使用其它安全提供者。只要支持DESede算法。这是程序里动态加载还可以在JDK中静态加载 static { java.security.Security.addProvider(new com.isnetworks.provider.jce.ISNetworksProvider()); } /** *对XML文档进行数字签名。 */ public static void sign(Document doc, String keystore, String storetype, String storepass, String alias, String keypass) throws Exception { FileInputStream fileInputStream = new FileInputStream(keystore); java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype); keyStore.load(fileInputStream, storepass.toCharArray()); PrivateKey key = (PrivateKey)keyStore.getKey(alias, keypass.toCharArray()); X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias); SigningKey sk = SigningKeyFactory.makeSigningKey(key); KeyInfo ki = new KeyInfo(); ki.setCertificate(cert); WSSecurity wSSecurity = new WSSecurity();//ws-security.jar中包含的WSSecurity类 wSSecurity.sign(doc, sk, ki);//签名。 } /** *对XML文档进行身份验证。 */ public static boolean verify(Document doc, String keystore, String storetype, String storepass) throws Exception { FileInputStream fileInputStream = new FileInputStream(keystore); java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype); keyStore.load(fileInputStream, storepass.toCharArray()); TrustVerifier verifier = new X509TrustVerifier(keyStore); WSSecurity wSSecurity = new WSSecurity(); MessageValidity[] resa = wSSecurity.verify(doc, verifier, null,null); if (resa.length > 0) return resa[0].isValid(); return false; } /** *对XML文档进行加密。必须有JSSE提供者才能加密。 */ public static void encrypt(Document doc, String keystore, String storetype, String storepass, String alias) throws Exception { try { FileInputStream fileInputStream = new FileInputStream(keystore); java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype); keyStore.load(fileInputStream, storepass.toCharArray()); X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias); PublicKey pubk = cert.getPublicKey(); KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede",PROVIDER); keyGenerator.init(168, new SecureRandom()); SecretKey key = keyGenerator.generateKey(); KeyInfo ki = new KeyInfo(); ki.setCertificate(cert); WSSecurity wSSecurity = new WSSecurity(); //加密。 wSSecurity.encrypt(doc, key, AlgorithmType.TRIPLEDES, pubk, AlgorithmType.RSA1_5, ki); } catch(Exception e) { e.printStackTrace(); } } /** *对文档进行解密。 */ public static void decrypt(Document doc, String keystore, String storetype, String storepass, String alias, String keypass) throws Exception { FileInputStream fileInputStream = new FileInputStream(keystore); java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype); keyStore.load(fileInputStream, storepass.toCharArray()); PrivateKey prvk2 = (PrivateKey)keyStore.getKey(alias, keypass.toCharArray()); WSSecurity wSSecurity = new WSSecurity(); //解密。 wSSecurity.decrypt(doc, prvk2, null); WsUtils.removeEncryptedKey(doc);//从 WS-Security Header中删除 EncryptedKey 元素 } public static void removeWSSElements(Document doc) throws Exception { WsUtils.removeWSSElements(doc);// 删除WSS相关的元素。 } } WSClientHandler.java //继承自org.apache.axis.handlers.BasicHandler即AXIS内在的 public class WSClientHandler extends BasicHandler{ protected String keyStoreFile ; protected String keyStoreType ="JKS";//默认 protected String keyStorePassword ; protected String keyAlias ; protected String keyEntryPassword ; protected String trustStoreFile ; protected String trustStoreType = "JKS";//默认 protected String trustStorePassword ; protected String certAlias ; public void setInitialization(String keyStoreFile,String keyStoreType,String keyStorePassword, String keyAlias,String keyEntryPassword,String trustStoreFile, String trustStoreType,String trustStorePassword,String certAlias){ this.keyStoreFile=keyStoreFile; this.keyStoreType=keyStoreType; this.keyStorePassword=keyStorePassword; this.keyAlias=keyAlias; this.keyEntryPassword=keyEntryPassword; this.trustStoreFile=trustStoreFile; this.trustStoreType=trustStoreType; this.trustStorePassword=trustStorePassword; this.certAlias=certAlias; } public void setInitialization(String keyStoreFile,String keyStorePassword, String keyAlias,String keyEntryPassword,String trustStoreFile, String trustStorePassword,String certAlias){ this.keyStoreFile=keyStoreFile; this.keyStorePassword=keyStorePassword; this.keyAlias=keyAlias; this.keyEntryPassword=keyEntryPassword; this.trustStoreFile=trustStoreFile; this.trustStorePassword=trustStorePassword; this.certAlias=certAlias; } public void invoke(MessageContext messageContext) throws AxisFault {//在这个方法里对XML文档进行处理 //do nothing now! } public void onFault(MessageContext msgContext) { System.out.println("处理错误,这里忽略!"); } } WSClientRequestHandler.java public class WSClientRequestHandler extends WSClientHandler{ public void invoke(MessageContext messageContext) throws AxisFault { try { SOAPMessage soapMessage = messageContext.getMessage(); Document doc = MessageConverter.convertSoapMessageToDocument(soapMessage); //soapMessage转换为Document WSHelper.sign(doc, keyStoreFile, keyStoreType,keyStorePassword, keyAlias, keyEntryPassword); //数字签名 WSHelper.encrypt(doc, trustStoreFile, trustStoreType, trustStorePassword, certAlias); //加密 soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc); //处理后的Document再转换回soapMessage messageContext.setMessage(soapMessage); } catch (Exception e){ System.err.println("在处理响应时发生以下错误: " + e); e.printStackTrace(); } } } WSClientResponseHandler.java public class WSClientResponseHandler extends WSClientHandler{ public void invoke(MessageContext messageContext) throws AxisFault { try { SOAPMessage soapMessage = messageContext.getCurrentMessage(); Document doc = MessageConverter.convertSoapMessageToDocument(soapMessage); WSHelper.decrypt(doc, keyStoreFile, keyStoreType, keyStorePassword, keyAlias, keyEntryPassword);//解密 WSHelper.verify(doc, trustStoreFile, trustStoreType, trustStorePassword);//验证 WSHelper.removeWSSElements(doc); soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc); messageContext.setMessage(soapMessage); } catch (Exception e){ e.printStackTrace(); System.err.println("在处理响应时发生以下错误: " + e); } } } WSServerHandler.java public class WSServerHandler extends BasicHandler{ protected String keyStoreFile ; protected String keyStoreType ="JKS";//默认 protected String keyStorePassword ; protected String keyAlias ; protected String keyEntryPassword ; protected String trustStoreFile ; protected String trustStoreType = "JKS";//默认 protected String trustStorePassword ; protected String certAlias ; public void invoke(MessageContext messageContext) throws AxisFault { //do nothing now! } public void onFault(MessageContext msgContext) { System.out.println("处理错误,这里忽略!"); } public void init() { //初始化,从配置文件server-config.wsdd中读取属性 keyStoreFile = (String)getOption("keyStoreFile"); if(( keyStoreFile== null) ) System.err.println("Please keyStoreFile configured for the Handler!"); trustStoreFile = (String)getOption("trustStoreFile"); if(( trustStoreFile== null) ) System.err.println("Please trustStoreFile configured for the Handler!"); keyStorePassword = (String)getOption("keyStorePassword"); if(( keyStorePassword== null) ) System.err.println("Please keyStorePassword configured for the Handler!"); keyAlias = (String)getOption("keyAlias"); if(( keyAlias== null) ) System.err.println("Please keyAlias configured for the Handler!"); keyEntryPassword = (String)getOption("keyEntryPassword"); if(( keyEntryPassword== null) ) System.err.println("Please keyEntryPassword configured for the Handler!"); trustStorePassword = (String)getOption("trustStorePassword"); if(( trustStorePassword== null) ) System.err.println("Please trustStorePassword configured for the Handler!"); certAlias = (String)getOption("certAlias"); if ((certAlias==null)) System.err.println("Please certAlias configured for the Handler!"); if ((getOption("keyStoreType")) != null) keyStoreType = (String)getOption("keyStoreType"); if ((getOption("trustStoreType")) != null) trustStoreType = (String)getOption("trustStoreType"); } } WSServerRequestHandler.java public class WSServerRequestHandler extends WSServerHandler{ public void invoke(MessageContext messageContext) throws AxisFault { try { SOAPMessage msg = messageContext.getCurrentMessage(); Document doc = MessageConverter.convertSoapMessageToDocument(msg); System.out.println("接收的原始消息:"); msg.writeTo(System.out); WSHelper.decrypt(doc, keyStoreFile, keyStoreType, keyStorePassword, keyAlias, keyEntryPassword);//解密 WSHelper.verify(doc, trustStoreFile, trustStoreType, trustStorePassword);//验证 WSHelper.removeWSSElements(doc); msg = MessageConverter.convertDocumentToSOAPMessage(doc); System.out.println("怀原后的原始消息:"); msg.writeTo(System.out); messageContext.setMessage(msg); } catch (Exception e){ e.printStackTrace(); System.err.println("在处理响应时发生以下错误: " + e); } } } WSServerResponseHandler.java public class WSServerResponseHandler extends WSServerHandler{ public void invoke(MessageContext messageContext) throws AxisFault { try { SOAPMessage soapMessage = messageContext.getMessage(); System.out.println("返回的原始消息:"); soapMessage.writeTo(System.out); Document doc = MessageConverter.convertSoapMessageToDocument(soapMessage); WSHelper.sign(doc, keyStoreFile, keyStoreType, keyStorePassword, keyAlias, keyEntryPassword);//数字签名 WSHelper.encrypt(doc, trustStoreFile, trustStoreType,//加密 trustStorePassword, certAlias); soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc); System.out.println("返回的加密后的消息:"); soapMessage.writeTo(System.out); messageContext.setMessage(soapMessage); } catch (Exception e){ System.err.println("在处理响应时发生以下错误: " + e); e.printStackTrace(); } } } 6、应用 为方便使用,把上述文件打包为ws-axis.jar,放入%TOMCAT_HOME%\webapps\axis\WEB-INF\lib 1)把HelloWorld重新部署一次,在server-config.wsdd中修改如下部署代码。 <service name="HelloWorld" provider="java:RPC"> <parameter name="allowedMethods" value="*"/> <parameter name="className" value="HelloWorld"/> <requestFlow> <handler type="soapmonitor"/> <handler type="java:com.ronghao.WSAxis.WSServerRequestHandler"> <parameter name="keyStoreFile" value="f:\server.keystore"/> <parameter name="trustStoreFile" value="f:\server.truststore"/> <parameter name="keyStorePassword" value="changeit"/> <parameter name="keyAlias" value="Server"/> <parameter name="keyEntryPassword" value="changeit"/> <parameter name="trustStorePassword" value="changeit"/> <parameter name="certAlias" value="clientkey"/> </handler> </requestFlow> <responseFlow> <handler type="soapmonitor"/> <handler type="java:com.ronghao.WSAxis.WSServerResponseHandler"> <parameter name="keyStoreFile" value="f:\server.keystore"/> <parameter name="trustStoreFile" value="f:\server.truststore"/> <parameter name="keyStorePassword" value="changeit"/> <parameter name="keyAlias" value="Server"/> <parameter name="keyEntryPassword" value="changeit"/> <parameter name="trustStorePassword" value="changeit"/> <parameter name="certAlias" value="clientkey"/> </handler> </responseFlow> </service> 2)修改客户端程序 TestClient.java(修改的部分已标出,记着导入ws-axis.jar) import javax.xml.namespace.QName; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import com.ronghao.WSAxis.*; public class WSSClient1 { public static void main(String [] args) { try { //服务端的url,需要根据情况更改。 String endpointURL = "http://localhost:8080/axis/services/HelloWorld"; Service svc = new Service(); WSClientHandler handler=new WSClientRequestHandler(); //注意新加的HANDLER handler.setInitialization("f:/client.keystore","changeit","Client","changeit", "f:/client.truststore","changeit","serverkey");//初始化 WSClientHandler handlee=new WSClientResponseHandler(); //注意新加的HANDLER handlee.setInitialization("f:/client.keystore","changeit","Client","changeit", "f:/client.truststore","changeit","serverkey");//初始化 Call call =(Call)svc.createCall(); call.setClientHandlers(handler,handlee);//添加Handler call.setTargetEndpointAddress(new java.net.URL(endpointURL)); call.setOperationName(new QName("sayHello")); String result = (String) call.invoke( new Object [] {}); System.out.println("the result"+result); } catch (Exception e) { e.printStackTrace(); } } } 运行的时候http://localhost:8080/axis/SOAPMonitor中看到的请求的XML就已加密! 总结 这里对代码的解释是不够的,很多概念没有提到。建议你最好看tsik.jar和AXIS的API深入了解。另外对ws-axis.jar的加解密实现打算运用apache的wss4j,相关网址http://ws.apache.org/ws-fx/wss4j/。不过这个东西也应该够用了暂时。所有的源文件在附件中附件:soapTest.zip(279K) ++++++++++++++++++++++++++++++++++++++ AXIS学习笔记(五)( 在AXIS服务间传递JavaBean及其安全解决) ronghao100 原创 在AXIS服务间传递JavaBean及其安全解决 这是AXIS学习笔记的最后一篇。在前面我们讨论了最简单的HelloWorld服务,客户端并没有向服务器端 传递参数,现在我们来传传JavaBean。当然,也可以传递你自己定义的JAVA类,但那样你必须自己创建 专门的XML序列化器和反序列化器;而对JavaBean,AXIS提供了现成的序列化器。(有人说:懒惰是程序员最大的美德,我喜欢,所以我就传传JavaBean) 一、服务器端 1、CLASS类两个Order.class,OrderTest.class,位于%TOMCAT_HOME%\webapps\axis\WEB-INF\classes下 这两个类都直接给出源码,不再说明 Order.java public class Order { private String id; private String name; public void setId(String id){ this.id=id; } public String getId(){ return id; } public void setName(String name){ this.name=name; } public String getName(){ return name; } } OrderTest.java public class OrderTest { public Order returnOrder(Order order){ Order newOrder=new Order(); if(order.getId().equals("1")) newOrder.setName("ronghao"); else newOrder.setName("haorong"); return newOrder; } } 2、修改服务器端配置文件server-config.wsdd 在server-config.wsdd中相应位置添加以下代码 <service name="Order" provider="java:RPC"> <parameter name="allowedMethods" value="returnOrder"/> <parameter name="className" value="OrderTest"/> <beanMapping languageSpecificType="java:Order" qname="ns1:Order" xmlns:ns1="urn:BeanService"/> </service> 可以看到和前面的发布服务代码相比仅多了一行代码 <beanMapping languageSpecificType="java:Order" qname="ns1:Order" xmlns:ns1="urn:BeanService"/> languageSpecificType属性指定JavaBean类文件位置,例如: languageSpecificType="java:com.ronghao.axis.Order" qname属性指定JavaBean类的名字 其他是固定的。 二、客户端 客户端类文件一个OrderClient.class,代码如下(变化的部分加注释): public class OrderClient { public static void main(String args[]) throws Exception { String endpoint = "http://localhost:8080/axis/services/Order"; //服务所在位置 Order order=new Order(); //JavaBean order.setId("1"); Service service = new Service(); Call call = (Call)service.createCall(); //注册JavaBean,注意和server-config.wsdd中的配置代码比较 QName qn = new QName("urn:BeanService", "Order"); call.registerTypeMapping(Order.class, qn, new BeanSerializerFactory(Order.class, qn), new BeanDeserializerFactory(Order.class, qn)); String name="no!"; try { call.setTargetEndpointAddress(new URL(endpoint)); //调用的服务器端方法 call.setOperationName(new QName("Order", "returnOrder")); //设定传入的参数,这里qn即Order.class call.addParameter("arg1", qn, ParameterMode.IN); //设定返回的参数是Order.class call.setReturnType(qn, Order.class); Order result = (Order)call.invoke(new Object[] { order }); if(result != null) name = result.getName(); } catch(Exception e) { System.err.println(e); } System.out.println(name); } } OK!运行一下,就可以看到返回了"ronghao"。 和上一篇文章一样,我们不容许在网络中传递XML是明文,于是需要加密和验证。这里我们继续采用上次所讲的框架。(已打包成ws-axis.jar) 一、修改服务器端配置文件server-config.wsdd(和上一文章一模一样!不再罗嗦) 在server-config.wsdd中相应位置添加以下代码 <requestFlow> <handler type="soapmonitor"/> <handler type="java:com.ronghao.WSAxis.WSServerRequestHandler"> <parameter name="keyStoreFile" value="f:\server.keystore"/> <parameter name="trustStoreFile" value="f:\server.truststore"/> <parameter name="keyStorePassword" value="changeit"/> <parameter name="keyAlias" value="Server"/> <parameter name="keyEntryPassword" value="changeit"/> <parameter name="trustStorePassword" value="changeit"/> <parameter name="certAlias" value="clientkey"/> </handler> </requestFlow> <responseFlow> <handler type="soapmonitor"/> <handler type="java:com.ronghao.WSAxis.WSServerResponseHandler"> <parameter name="keyStoreFile" value="f:\server.keystore"/> <parameter name="trustStoreFile" value="f:\server.truststore"/> <parameter name="keyStorePassword" value="changeit"/> <parameter name="keyAlias" value="Server"/> <parameter name="keyEntryPassword" value="changeit"/> <parameter name="trustStorePassword" value="changeit"/> <parameter name="certAlias" value="clientkey"/> </handler> </responseFlow> 二、客户端(区别就在这里,注意!!) 首先在这里要说一下,客户端代码编写困扰了我很长一段时间(整整一天),因为它并不象我想象的那么简单,当然解决起来还是挺简单的:)问题的解决经历了三个阶段 第一阶段: 在这个阶段我想当然的在OrderClient.class中加入了如下代码: WSClientHandler handler=new WSClientRequestHandler();//注意新加的HANDLER handler.setInitialization("f:/client.keystore","changeit","Client","changeit", "f:/client.truststore","changeit","serverkey");//初始化 WSClientHandler handlee=new WSClientResponseHandler();//注意新加的HANDLER handlee.setInitialization("f:/client.keystore","changeit","Client","changeit", "f:/client.truststore","changeit","serverkey");//初始化 call.setClientHandlers(handler,handlee);//添加Handler 这个方法也是我在上一文章里介绍的,结果抛出以下异常: faultString: org.xml.sax.SAXException: Deserializing parameter &apos;newProfileReturn&apos;: could not find deserializer for type {urn:BeanService Order}SerializableProfile 也就是说不能正常解析XML文件,于是理所当然的郁闷了,觉得代码中肯定漏设了CALL的一个属性,于是查看AXIS的源代码,没有结果!转机出现在下面一行代码,在不断的抛出异常中我修改了代码 将call.setClientHandlers(handler,handlee);改为 call.setClientHandlers(null,null); 结果程序还是抛出同样的异常,于是意识到这可能是AXIS的一个BUG,为证明这一点,我将下面的Handler初始化代码删除 WSClientHandler handler=new WSClientRequestHandler();//注意新加的HANDLER handler.setInitialization("f:/client.keystore","changeit","Client","changeit", "f:/client.truststore","changeit","serverkey");//初始化 WSClientHandler handlee=new WSClientResponseHandler();//注意新加的HANDLER handlee.setInitialization("f:/client.keystore","changeit","Client","changeit", "f:/client.truststore","changeit","serverkey");//初始化 结果还是抛出同样的异常,果然是BUG!得到这个结论后去了apache AXIS主页,在问题列表中见到了完全一样问题的提交,但没有解答(晕!) 最后得到了结论:call的setClientHandlers()方法只有当call处理简单的数据类型,如String,int等等才能正常使用! (当然,如果你对这个问题有不同的见解,欢迎和我联系。或许我错了,但程序不运行是真的:)) 第二阶段: 开始在google上找问题的解决方法,这也是我的习惯:)。找了一个类似问题的讨论,地址如下: http://marc.theaimsgroup.com/?l=axis-user&m=111259980822735&w=2 他们的解决方法是Handler继承于javax.xml.rpc.handler.Handler,然后在程序里动态注册而在我的ws-axis.jar里Handler继承于org.apache.axis.handlers.BasicHandler。当然, javax.xml.rpc.handler.Handler是org.apache.axis.handlers.BasicHandler的老爸,但在程序里老爸和儿子之间却不能很好的兼容,这也许就是所谓的代沟??无奈中重新写了Handler,但在运行中却抛出异常,提示message在被invoke的时候已被更改。我靠,Handler的作用就是来更改message的啊!这是什么世道! 我知道很多程序采用的就是这种方法,但我好象怎么修改都抛出上述异常。 第三阶段 既然在程序里动态注册Handler行不通,于是决定写个单独的配置文件来注册Handler。如果这种方法不幸失败就返回第二阶段。好马为什么不吃回头草?? 1、ws-axis.jar中修改WSClientHandler.class,修改后如下,我想你一看就明白为何修改 public class WSClientHandler extends BasicHandler{ protected String keyStoreFile ; protected String keyStoreType ="JKS"; protected String keyStorePassword ; protected String keyAlias ; protected String keyEntryPassword ; protected String trustStoreFile ; protected String trustStoreType = "JKS"; protected String trustStorePassword ; protected String certAlias ; public void init() { keyStoreFile = (String)getOption("keyStoreFile"); if(( keyStoreFile== null) ) System.err.println("Please keyStoreFile configured for the Handler!"); trustStoreFile = (String)getOption("trustStoreFile"); if(( trustStoreFile== null) ) System.err.println("Please trustStoreFile configured for the Handler!"); keyStorePassword = (String)getOption("keyStorePassword"); if(( keyStorePassword== null) ) System.err.println("Please keyStorePassword configured for the Handler!"); keyAlias = (String)getOption("keyAlias"); if(( keyAlias== null) ) System.err.println("Please keyAlias configured for the Handler!"); keyEntryPassword = (String)getOption("keyEntryPassword"); if(( keyEntryPassword== null) ) System.err.println("Please keyEntryPassword configured for the Handler!"); trustStorePassword = (String)getOption("trustStorePassword"); if(( trustStorePassword== null) ) System.err.println("Please trustStorePassword configured for the Handler!"); certAlias = (String)getOption("certAlias"); if ((certAlias==null)) System.err.println("Please certAlias configured for the Handler!"); if ((getOption("keyStoreType")) != null) keyStoreType = (String)getOption("keyStoreType"); if ((getOption("trustStoreType")) != null) trustStoreType = (String)getOption("trustStoreType"); } public void invoke(MessageContext messageContext) throws AxisFault { //do nothing now! } public void onFault(MessageContext msgContext) { System.out.println("处理错误,这里忽略!"); } } 2、写客户端的配置代码client-config.wsdd,如下: <?xml version="1.0" encoding="UTF-8"?> <deployment name="defaultClientConfig" xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="" target="_blank">http://xml.apache.org/axis/wsdd/providers/java"> <transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"/> <transport name="local" pivot="java:org.apache.axis.transport.local.LocalSender"/> <transport name="java" pivot="java:org.apache.axis.transport.java.JavaSender"/> <globalConfiguration> <requestFlow> <handler type="java:com.ronghao.WSAxis.WSClientRequestHandler"> <parameter name="keyStoreFile" value="D:\Tomcat5.5\webapps\axis\WEB-INF\client.keystore"/> <parameter name="keyEntryPassword" value="changeit"/> <parameter name="certAlias" valu

2013-07-24

GWT使用大全

GWT使用大全, GWT配置, GWT使用方法,GWT手册,GWT使用手册

2013-07-16

Java读取TIFF文件

java读取tiff文件,并获得长,高。

2013-06-26

Sencha Architect 2.x无限次使用教程

Sencha Architect 2.x无限次使用教程 Sencha Architect 2是ExtJS和Sencha Touch的官方可视化IDE工具。最新版本是2.2,说是破解,其实是修改License来实现无限试用而已

2013-06-12

java PIO 对execl的操作详解

java PIO 对execl的操作详解 package com.hxtony.office.excel; import org.apache.poi.hssf.usermodel.HSSFRichTextString; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.Region; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.File; import java.sql.PreparedStatement; import java.sql.ResultSetMetaData; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Connection; import java.sql.ResultSet; import java.io.UnsupportedEncodingException; public class OperatorExcel2007 { private String fileSeparator = System.getProperty("file.separator"); public OperatorExcel2007() { } public static void main(String agvs[]) { OperatorExcel2007 e = new OperatorExcel2007(); // sql语句的要求:将数据表写在第一位如:select * from 数据表, 其他表…… where 数据表.id in (select id from 任意表) String[] sql = new String[]{"select * from table_a where a='a'", "select * from table_b where b='b'", ""}; try {

2013-05-17

maven入门到精通

maven入门到精通 用 Maven 做项目管理 在 Java世界中我们很多的开发人员选择用 Ant来构建项目,一个 build.xml能够完成编译、测试、打包、部署等很多任务,但我们也碰到了很多的问题,如 jar文件管理混乱,各个项目结构和 build.xml相差很大等等。而 Maven的出现,给项目提供了更多的支持。 1 简介 Maven 作为 Apache 的一个开源项目,旨在给项目管理提供更多的支持,主页地址为 http://maven.apache.org 。它最早的意图只是为了给 apache 组织的几个项目提供统一的开发、测试、打包和部署,能让开发者在多个项目中方便的切换。很多伟大的事业,出发点都很简单, ebay 就是很好的例证。而 maven 的成功又一次验证了这一点,越来越多的项目开始使用 maven 。 基本原理 Maven 的基本原理很简单,采用远程仓库和本地仓库以及一个类似 build.xml 的 pom.xml ,将 pom.xml 中定义的 jar 文件从远程仓库下载到本地仓库,各个应用使用同一个本地仓库的 jar ,同一个版本的 jar 只需下载一次,而且避免每个应用都去拷贝 jar 。如图 1 。同时它采用了现在流行的插件体系架构,只保留最小的核心,其余功能都通过插件的形式提供,所以 maven 下载很小( 1.1M ),在执行 maven 任务时,才会自动下载需要的插件。 这个基本原理与 Pear ――PHP扩展与应用库( the PHP Extension and Application Repository )的原理非常相似,都有一个官方的仓库,都是微内核,通过网络将需要的文件下载到本地,通过官方仓库将相应的类库进行统一管理。 Pear 已经成为 PHP 开发事实上的标准,而 Maven 在 Java 世界的地位也逐渐加强,成为标准指日可待。

2013-04-15

Maven完全手册

Maven完全手册 maven2 起步 相信maven1 大家都已经很熟悉了,具体maven能做什么,就不详细说了。个人觉得maven在开源项目中用的还是比较多的,公司内部,就不太清楚了。我以前的公司用过一段时间,不过后来就没有下文了。 与maven1 相比,maven2可算是几乎重写了,不过从速度来说应该更快。 主要的几个新特性包括:(详细参考http://www.ibm.com/developerworks/cn/opensource/os-maven2/index.html) 1. 更快、更简单 速度方面可以比上ant了 2. 更少的配置文件 现在的配置文件只剩下了settings.xml和pom.xml了。 3. Plugin语言更换 语言开始支持java,BeanShell和ant 4. 提供了预定义的模版 这点是最有帮助的,用户可以自己定义自己的项目模版了,就像用appfuse一样生成项目结构 5. 生命周期的引入 在Maven2中有了明确的生命周期概念,而且都提供与之对应的命令,使得项目构建更加清晰明了。 6. 新增Dependency Scope 这点也比较重要,有些用于test范围的包,可以不用加入依赖了 7. 传递依赖,简化依赖管理 这是最为方便的,可以省了很多配置。如a 依赖 b,b 依赖c 默认 a也会依赖 c。但是也会带来隐患,如版本冲突。不过maven 也已经考虑到了,可以使用exclusions来排除相应的重复依赖

2013-04-15

Maven2 的新特性.7z

Maven2 的新特性.7z 文档选项 打印本页 将此页作为电子邮件发送 级别: 初级 键 胡 ([email protected]), 西安交通大学硕士 伟红 胡 ([email protected]), 工程师,IBM 区域合作伙伴支持中心, IBM 2006 年 2 月 23 日 本文主要阐述 Maven2 的新特性,这些新特性可以大大地缩短了开发管理中的工作量,使得开发人员将精力集中在实际的业务问题上。 Maven 出现到现在也有很长时间了,初识它的感觉至今仍清晰的印在脑海中。现在想来,当时从 Ant 移情 Maven 的想法其实很朴素,就是因为 Maven 可以以网站的形式展现与项目相关的信息,如开发人员列表、各种 Report。这种方式为项目的构建带来了极大的方便,尤其是 Report 的。试想对于产生的 Junit-Report、JavaDoc、CheckStyle、PMD 等报告,如果没有一个统一的入口,每次切换目录是多么令人厌烦的事情! Maven 无疑是相当成功的,这一点从越来越多的开源项目开始使用 Maven 就可以看出。Maven 取得成功的原因很简单:在简化构建脚本的同时,功能并没有缩水,反而有所增强;提供汇集项目信息的工具,并以相当友好的方式呈现;丰富的插件简化了工作。如此有力的工具出现,自然是争相使用。 新特性 如今 Maven2 已经推出,Maven 的官方网站称,Maven2 相对于 Maven1 是一个相当大的转变,甚至不惜牺牲兼容性来达到这一目的。(为了 Maven1 的用户着想,Maven1 仍在继续他的使命。)如此大的变动到底换来了什么样的结果? 1. 更快、更简单 比起 Maven1 那不急不慢的运行速度,Maven2在速度上有了质的飞跃,甚至与Ant相比也毫不逊色(当然,下载不算)。除此之外,"简化工作,使用业界公认的最佳实践"也是是 Maven2 的另一大主题,其他的新特性无处不在体现 Maven2 为简化工作而做出的努力。 2. 更少的配置文件 Maven1 和 Maven2 主要配置文件的对比: • Maven1:project.xml、maven.xml、project.properties和build.properties。 • Maven2:pom.xml和settings.xml。 POM是Maven的核心对象模型,在Maven2中POM已由project.xml转移到pom.xml中使用,版本也由3升级为4。对于项目,一般只需要pom.xml就行了。 在Maven2中不需要也不提倡使用maven.xml,原因如下: • plugin的易用性的增强。 • 散布于maven.xml中的内容难以在不同项目间共享,也不利于维护。在Maven2中建议使用自定义的plugin来封装这些内容。 如果仍期望能够使用类似maven.xml的功能,如<preGoal>,请参考Inserting non-standard build steps using preGoals and postGoals。 在Maven2中,配置使用settings.xml,它取代了原有的project.properties和build.properties。配置在Maven2中存在两种级别: • 用户级,针对操作系统登录用户而言。一般在$home/.m2/,对于windows用户,就是目录:C:\Documents and Settings\用户名\.m2\settings.xml。 • 全局级:一般在%M2_HOME%/conf/settings.xml,M2_HOME是Maven2的根目录环境变量名。 在settings.xml中可以配置,如本地Repository、proxy等等,关于settings.xml的结构可以从Maven的官方网站上获取。 3. Plugin语言更换 在Maven2中,编写plugin的语言由jelly变更为Java和BeanShell。Java在速度上更有优势,而且开发人员的熟悉程度更高。对于其他的流行脚本,如groovy,Maven的官方网站的意见是,等待其更成熟时再考虑 。 4. 提供预定义的目录模板 好的目录结构可以使开发人员更容易理解项目,为以后的维护工作也打下良好的基础。Maven2根据业界公认的最佳目录结构,为开发者提供了缺省的标准目录模板。Maven2的标准目录结构如下: 使用目录模板,可以使pom.xml更简洁。因为Maven2已经根据缺省目录,预定义了相关的动作,而无需人工的干预。以resources目录为例: • src/main/resources,负责管理项目主体的资源。在使用Maven2执行compile之后,这个目录中的所有文件及子目录,会复制到target/classes目录中,为以后的打包提供了方便。 • src/test/resources,负责管理项目测试的资源。在使用Maven2执行test-compile之后,这个目录中的所有文件及子目录,会复制到target/test-classes目录中,为后续的测试做好了准备。 这些动作在 Maven1 中,是需要在 maven.xml 中使用<preGoal>或<postGoal>来完成的。如今,完全不需要在pom.xml中指定就能够自动完成。在src和test都使用resources,方便构建和测试,这种方式本就已是前人的经验。通过使用Maven2,使这个经验在开发团队中得到普及。 创建标准目录模板,可以通过如下命令: mvn archetype:create -DgroupId=com.codeline.commons -DartifactId=codelineCommons groupId和artifactId的含义与Maven1中的含义一样,参数artifactId的值会作为项目根目录的名字。除了建立相应的目录之外,Maven2还会创建缺省的pom.xml。 Maven2也考虑到:不同类型的项目需要拥有不同的目录结构。如创建web项目,可以使用命令: mvn archetype:create -DgroupId=com.mycompany.app -DartifactId=my-webapp -DarchetypeArtifactId=maven-archetype-webapp 5. 生命周期的引入 在Maven2中有了明确的生命周期概念,而且都提供与之对应的命令,使得项目构建更加清晰明了。主要的生命周期阶段: • validate,验证工程是否正确,所有需要的资源是否可用。 • compile,编译项目的源代码。 • test-compile,编译项目测试代码。 • test,使用已编译的测试代码,测试已编译的源代码。 • package,已发布的格式,如jar,将已编译的源代码打包。 • integration-test,在集成测试可以运行的环境中处理和发布包。 • verify,运行任何检查,验证包是否有效且达到质量标准。 • install,把包安装在本地的repository中,可以被其他工程作为依赖来使用 • deploy,在整合或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其他的开发者或者工程可以共享。 • generate-sources,产生应用需要的任何额外的源代码,如xdoclet。 如果要执行项目编译,那么直接输入:mvn compile即可,对于其他的阶段可以类推。阶段之间是存在依赖关系(dependency)的,如test依赖test-compile。在执行mvn test时,会先运行mvn test-compile,然后才是mvn test。 6. 新增Dependency Scope 在POM 4中,<dependency>中还引入了<scope>,它主要管理依赖的部署。目前<scope>可以使用5个值: • compile,缺省值,适用于所有阶段,会随着项目一起发布。 • provided,类似compile,期望JDK、容器或使用者会提供这个依赖。如servlet.jar。 • runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。 • test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。 • system,类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。 <scope>的使用举例: <dependency> <groupId>hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.0.3</version> <scope>test</scope> </dependency> 7. 传递依赖,简化依赖管理 在Maven1中,需要把依赖所需要的包也一并列出。这对于使用类似如Hibernate的用户来说所操的心太多了,而且也不方便。在Maven2中实现了传递依赖,如此对于Hibernate所依赖的包,Maven2会自动下载,开发人员只需关心Hibernate即可。 注意:只有得到Maven支持的依赖,通常是plugin形式出现,才能获得这个特性。而且对于一些老的plugin,可能由于时间的关系不支持传递依赖。如至少在Maven 2.0.1中,对于Hibernate 2.1.2,仍然需要显式列出Hibernate 2.1.2所依赖的包。 回页首 使用简介 安装Maven2的步骤非常简单:首先从Maven官方网站下载相应的软件包,目前是Maven 2.0.1;然后解压,并设置环境变量M2_HOME= Maven2的解压安装目录;最后将%M2_HOME%/bin添加到path中,方便Maven在任何目录下运行。 Maven2的运行命令是mvn,使用mvn -h可以获得相关的帮助信息。常用情形: • 创建Maven项目:mvn archetype:create • 编译源代码:mvn compile • 编译测试代码:mvn test-compile • 运行测试:mvn test • 产生site:mvn site • 打包:mvn package • 在本地Repository中安装jar:mvn install • 清除产生的项目:mvn clean 或许是由于刚刚推出的缘故,Maven2目前还是有一些不尽如人意的地方。尤其是Report部分的plugin,有的是因为目前还没有,如junit-report。有的则是一些莫名其妙的问题,如checktyle和pmd,在本地locale下都无法正常工作。以pmd举例,在产生PMD报告时会抛出如下异常: java.util.MissingResourceException: Can't find bundle for base name pmd-report, locale zh_CN at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle .java:839) at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:808) at java.util.ResourceBundle.getBundle(ResourceBundle.java:702) …… 幸运的是,Maven2一出现就备受关注,要不了多长时间,诸如此类的问题应该就会很快解决。 回页首 结论 Maven2在Maven1的优势基础之上,又向前迈进了一大步。它提供的这些新特性大大地缩短了开发管理中的工作量,使得开发人员将精力集中在实际的业务问题上。而且这些新特性对于简化使用,普及最佳实践,也起到了积极的作用。 参考资料 • Inserting non-standard build steps using preGoals and postGoals http://docs.codehaus.org/display/MAVEN/Maven2+Goal+Decoration • Maven官方网站 http://maven.apache.org/ • Maven支持的依赖列表 http://www.ibiblio.org/maven2 • 在 Eclipse 中利用 Maven • 项目管理: Maven 让事情变得简单 作者简介 胡键,西安交通大学硕士,2000年毕业后一直从事软件开发。2002年开始使用Java,在平时的项目开发中经常采用OpenSource的工具,如Ant、Maven、Hibernate、Struts等,目前正在研究信息集成方面的规范和技术。可以通过[email protected]与他取得联系,或访问个人blog:http://blog.donews.com/foxgem/。 胡伟红,西安交通大学硕士,目前就职于IBM 区域合作伙伴支持中心。主要负责Websphere产品的支持。对开源的项目有很大的兴趣。可通过 [email protected] 与她联系。

2013-04-15

javascript/js超强计算器

javascript/js超强计算器, js计算器,js开源计算器,js公式计算器

2013-04-15

editplus js/xml/html格式化

让Editplus自动格式化js、css、html。。。 本人一般用editplus写一些小的测试代码或者来研究学习别人的代码,但经常会遇到这些问题:下载过来的HTML/CSS代码混乱,JS代码被压缩,或者是我们想把我们的代码做一下压缩混淆以供发布时使用。当然,对于代码的格式化和代码压缩等,我们都可以使用专有的工具,或者使用一些在线的工作来做,既然EditPlus可以扩展插件,那我们何不利用这一功能来把这些工具集成到EP中呢? 其实很早我都有这些想法,一直没有深究其做法,EP的用户工具组,我一般也是挂些帮助手册之类的供开发时参考。今天在BlueIdea看到有人发了一篇名为“让Editplus自动格式化css和js”的文章,看完后觉得写的很好,我也突然来了灵感,为什么不把前端开发常用工具都集成进去呢? 说做就做,我在网上找了一些相关的工具代码,按照作者的方式开始改造(作者是使用“本地cScript调用JS+EP的文本过滤器”的方式来实现的)。 下面来说下集成的方法(以下以EditPlus3中文版本为例): 1、下载工具包:edtools.rar ,解压后放到磁盘的一个目录,如D:\edTools。 2、打开ED,打开“工具”-“用户工具组”,在弹出的对象框中,在“组和工具项目”下拉框中选择一个工具组,点击“组名称”,为该组工具设定一个名称,如“前端开发工具”,如下图所示: 3、下面开始加入工具,这里主要以JSFormat为例讲解,其它类似。 点击“添加”--“应用程序”,在新建的项中,菜单文本写上名称,如"jsFormat",在命令里面输入: Java代码 1.cscript /nologo "D:\edTools\jsFormatter.js" 后面引号中的内容要修改你磁盘上对应的文件的路径。 在下面的几个选项中,选择“运行为文本过滤”。如下图所示: 4、其它几个的安装方式与jsFormat的安装类似,这里不再重复。点击ED ,工具你会发现:jsFormat Ctrl+1,打开一个js点击后你会发现奥秘。 http://www.cnblogs.com/jikey/archive/2011/03/20/1989367.html

2013-04-09

178个经典c语言源代码

178个经典c语言源代码,c++算法 #define N 199 #define NN 7000 #include <stdio.h> int main(void) { static int a[NN]={0},b[NN]={0}; int i,j,k,m,n,x; n=N;i=0; while (n!=0) { a[i]=b[i]=n; i++; n=(n-n)/10; } for(k=1;k<N;k++) { for(i=0;i<NN;i++) b[i]=a[NN-i-1]; i=0; while (b[i]==0)i++; for(m=0;m<NN;m++) b[m]=a[m]; for (m=1;m<N;m++) { /* printf("k=%d,m=%d\n",k,m);*/ x=0; for(j=0;j<NN;j++) { if (b[j]==0&&x==0&&j>NN-i) break; a[j]=a[j]+b[j]+x; if (a[j]>9) { a[j]=a[j]; x=1; } else x=0; } } } for (k=0;k<(NN-1)/2;k++) { x=a[k];a[k]=a[NN-k-1];a[NN-k-1]=x; } m=0; while (a[m]==0)m++; printf("%d^%d=",N,N); for (k=m;k<NN;k++) printf("%d",a[k]); printf("\n"); return 0; }

2013-03-30

扑克智能算法,能正常编译

扑克智能算法,能正常编译, porker AI.

2013-03-27

懒人的win系统管理教程

懒人的win系统管理教程

2013-03-21

tcp/IP调试工具

tcp调试工具 , 双向调试。比较简单的tcp/ip协议分析工具

2013-03-07

极限编程(XP)篇

极限编程(XP)篇 极端编程(eXtreme Programming)是一种开发纪律,以简单性、交流、反馈和勇气为基本宗旨。它的做法是以有效的实践规则将整个团队紧密联系起来,通过充分的反馈使团队能随时知道自己目前的状况和恰当的调节规则以适应自己的特殊情况。 在极端编程中,每一个项目贡献者都是“团队”完整的一部分。这个队伍是围绕着一个每天和队伍坐在一起共同工作的商业代表——“客户”建立起来的。 核心实践:整体团队 极端编程的队伍采用一种简单的方式来进行规划和跟踪,以决定下一步要做什么和预知项目什么时候会完成。聚焦于商业价值,团队通过一系列的通过了客户定义的测试和完全集成的小的发布来创作软件系统。 核心实践:规划策略,小发行版,客户测试 极端编程者通过成对和小组的方式共同工作,通过简单设计和强制测试的代码,不断的提升设计以保证设计总是适合当前的需求。 核心实践:简单设计,成对编程,测试优先开发,设计改进 极端编程队伍会总是保持系统能够集成并且在所有的时间运行。程序员以成对的方式编写所有的产品代码,并且在所有时间内都共同工作。他们以相似的形式编码以保证所有成员都可以按需要理解和改进所有的代码。 核心实践:持续集成,集体代码所有权,编码标准 极端编程队伍分享一个公共并且简单的系统蓝图。所有成员可以按照一种不时保持同步的节奏进行工作。 核心实践:系统比喻,可接受的步伐 核心实践 团队整体 一个XP项目的所有参与者都作为一个团队的成员坐在一起。这个团队必须包括一个业务的代表——“客户”,他提供需求,设置优先度,并掌管整个项目的方向。最好这个客户或者他的助手是一个最终用户,了解该领域,知道什么是所需要的。团队当然还要有程序员。团队可能会包含测试员,他帮助客户定义客户验收测试。分析员可以作为客户的助手,帮助客户定义需求。通常还会有一个指导,他帮助整个团队跟踪、推动开发进程。也可能会有一个管理者,他提供资源、处理对外交流和分工协作。这些职责中没有任何一个是必须某个个人独有的:每一个XP团队的成员都以任何他们所能做到的方式参与,最好的团队没有专家,只有一些有着特殊的技能的一般的参与者。 规划策略 XP的计划解决软件开发中的两个关键问题:预知在责任期内哪些东西将被完成,并且确定下一步需要做什么。重点是把握项目的正确轨道——这是相当简单明了的——更胜于希望精确预知哪些东西将会需要以及可能花费多少时间——这是相当困难的。在XP这里有两个关键的规划步骤,用来解决这两个问题: 发布计划是一个实践让客户向程序员们演示所希望获得的特性,然后程序员们评估它们的难度。当手中有了代价的评估和这些特性的重要程序的认知之后,客户安排一个项目计划。最初的发布计划需要留有足够的余地:优先级以及评估都不是真实可靠的,并且知道团队开始工作以前,我们都无法确切地了解队伍的开发进度。甚至最初的发布计划也不是足够精确能进行决断,所以XP队伍通常会不时地校正发布计划。 迭代计划是一个实践籍此可以为团队提供每几个开发周的导向。XP队伍通过两周的“迭代”来建立软件系统,在每一个迭代结束时提供可以运行的有实际用途的软件系统。在进行迭代计划时,客户演示下两周内希望完成的特性。程序员们将它们分割成若干个任务,并且评估它们的成本(比发布计划要细致一些)。基于在之前的迭代中完成的工作,团队签定当前迭代中将要承担的工作。 这些计划十分的简单,然而他们为客户提供了非常好的信息和极好的操纵控制。每隔几周,多少进展都可以一目了然。在XP中没有“百分之九十完成”:一个特性故事要么完成了,要么没有完成。关注可视结果方法在于一个很好的小的对立论点:一方面来说,非常直观地,如果进度不能令人满意,客户可以在某一个位置取消项目。从另一方面说,进度是显而易见地,并且判断哪些东西将会完成的能力是很完善的,因此XP项目往往可以在较少的压力下完成更多的需要的东西。 客户测试 作为每一个所要求特性的演示的一部分,XP客户定义一个或者多个自动进行的接受测试来表明特性已经能够实现。团队实现这些测试并且用它们来向自己和客户证明特性已经被正确的实现了。由于时间的压力,自动化是很重要的,手工测试将被跳过。这就像当黑夜来临的时候,就可以关掉你的灯一样。 最好的XP团队会将他们的客户测试当作程序员的测试一样对待:一旦测试运行了,从此之后团队会保持它能够一直正确运行。这意味着系统只能够被改进,总是向前的,从不会倒退。 小发行版本 XP团队通过两个重要的方式实践小发行版本: 第一,团队在每一个迭代发布可以运行的,测试过的软件系统,提供客户选择的商业价值。客户可以为任何目的使用这个软件系统,无论是评估还是发布给最终用户(强烈推荐)。最重要的方式是在每一个迭代结束的时候软件系统是可见的,并且提交给了客户。这保证了任何事情都是公开和真实的。 第二,XP团队尽可能频繁地发布给他们的最终用户。XP网站项目每天都进行发布,居家项目则每月或者更频繁地发布。甚至可以简包装的产品可以每季度地发运。 这么频繁地创建好的版本也许显得不太可能,但是XP团队每时每刻都在进行着发布。更多信息可以参看持续集成,并请注意这些频繁的发布通过XP中随处可见的测试(如同客户测试和测试优先开发中所描述的)变得现实了。 简单设计 XP团队建构软件系统为一个简单的设计。他们从简单开始,并且在整个程序员测试和设计改进过程中,他们保持着简单的设计。一个XP团队保持着设计总是刚好适合系统当前的功能要求。这里没有多余的投入,并且软件系统总是为将来做好了准备。 在XP中设计并不是一次性完成的事情,也不是一件从上到下的事情,它是自始至终的事情。在发布计划和迭代计划中都有设计的步骤,在快速设计过程中集合了团队的能力并且在整个项目过程地构中改进设计。在类似于极端编程这样的递增和迭代过程中,良好的设计是本质。这是在整个开发过程中必须更多的关注设计的原因。 成对编程 在XP所有的产品软件都是由两个程序员并排坐在一起,在同一台机器上共同完成的。这个实践保证了所有的产品代码都至少有一个其它的程序员进行了审视,而结果是更好的设计,更好的测试和更好的代码。 让两个程序员去做“一个程序员的工作”看起来有些效率低下,但是实际上刚好相反。研究表明成对编程在让程序员们单独工作相同的时间内会得到更好的代码。这证明了:两个头脑加在一起比一个好得多! 很多程序员在还没有尝试过的情况下就反对成对编程。这确实需要一些实践来做好它,而且你需要认真地实践数周以上的时间来看到结果。百分之九十的学习过成对编程的程序员都会喜欢这样,因此我们向所有的团队强烈推荐它。 除开提供更好的代码和测试之外,成队也提供了知识在团队中间传递。当成对地程序员交换伙伴时,每个人都会从其它的某个人那里学到新的知识。程序员们在学习,他们的技术在提高,他们对团队和公司来讲变得更有价值。成对,即使它本身在XP过程之外实施,也是每个人的巨大成功。 测试优先开发 极端编程围绕着反馈,而在软件开发中,好的反馈需要好的测试。最优秀的XP团队实践“测试优先开发”,在一个很小的循环中增加一个测试,然后让它能够工作。几乎是轻而易举的,团队提供的代码接近100%都有测试程序覆盖着,在绝大多数情况下这是很重要的进步。(如果你的程序员已经提供了更多的现有测试程序,你会拥有更多的力量。将它们保存下来,他们只会提供帮助的!) 仅仅写了测试程序还是不够的:你必须要运行它们。这里,极端编程也是极端的。这些“程序员测试”,或者说“单元测试”是一个完整的集合,每当程序员们发布任何代码到代码库的时候(成对的程序员通常每天发布两次或者更多次),每一个程序员测试必须能够正确的运行。每时每刻都是百分之百运行!这意味着程序员们可以立刻得到有关他们做得究竟如何的反馈。进一步说,这些测试提供了软件设计改进时无价的支持。 设计改进 极端编程在每一个迭代都关注于提供商业价值。为了在整个项目过程中完成这个目标,软件系统必须有良好的设计。可选择性可能会降低并且最终停滞。因此XP采用一种持续改进设计的过程,称为“重构”,来自于Martin Fowler 的书名,“重构:改进现有代码的设计”。 重构的过程关注在去掉重复(一个低劣设计的明确标志),以及提高代码的“内聚”,还有减少“耦合”。高内聚和低耦合在最近三十年以来被公认为是良好设计的特点。结果就是XP团队从一个好的简单的设计出发,并且总是让软件系统有一个好的简单的设计。这让他们能保持他们的开发速度,并且通常在实际上提高了项目开发速度。 重构自然是通过全面的测试来提供有力的支持的,这些测试用来确认当设计改变的时候不会破坏系统中的任何东西。因此客户测试和程序员测试都是有效的评价因素。XP的实践是相互支持的:他们会比各自独立时更为强壮。 持续集成 极端编程队伍总是保持的系统完全地集成在一起。我们说每日建构版本是为弱者提供的:XP团队每天都要构建系统很多次。(一个40人的XP团队每天至少集成八到十次!) 这个实践的好处可以通过回想你可能听说过的(或者是亲身参与过的)项目来了解:当系统构建是每周或以更低的频率进行时,通常会陷入“集成的地狱”,在那里所有东西都不能运行而且没有人知道为什么。 极少进行集成会给软件项目带来一系列的问题。第一个,尽管集成是发行好的工作代码的条件, 但是团队并不去实践它,而且通常它被委派给那些对整个系统并不十分了解的人。第二,极少集成的代码通常是——我宁愿说总是——错漏百出。 集体代码所有权 在一个极端编程项目中,每一对程序员都可以在任何时候改进任何一处的代码。这意味着所有的代码在很多人的关注下获得更多的收益,这样就提升了代码质量并且减少了缺陷。这里还有另外一个重要的好处:当代码仅由单个人负责的时候,要求的特性往往会放到了错误的位置,因为一个程序员发现他需要一个特性但是那段代码却不归他管理。代码的所有者太忙乐而不能去增加这个特性,所以这个程序员只好把这个特性加进了这个特性本不应该存在的他自己的代码中。这导致了难看的,难于维护到代码,充斥着重复和低(差)的内聚。 如果有人在他们所不理解的代码上进行盲目的修改时,集体代码所有权可能带来问题。XP通过两种关键技术来避免这类的问题:通过程序员测试来捕获错误,成对编程则表明在不熟悉的代码上工作的时候最佳途径是找一个这方面的专家作为伙伴。为了确保在需要是进行好的修改,这种实践将知识延伸到了整个团队。 编码标准 XP团队遵循一个公共的编码标准,因此系统中所有的代码看上去都像出自单独一个——非常有能力的——人之手。这个标准的规定并不重要:重要的是要让所有的代码看上去很相似,用来支持集体代码所有权。 系统比喻 极端编程团队对于程序如何运作形成一个共识,我们称之为“系统比喻”。在最佳状态时,系统比喻是关于程序如何运作的一个简单的灵魂描述,例如用“这个程序工作时就像一箱子蜜蜂,外出寻找花粉并带回蜂箱”作为一个基于代理的信息查询系统的描述。 有些时候一个十分诗意的想象可能不会出现。在任何情况下,无论有没有生动的比喻,XP团队都会选用一个公共的命名系统来确保每个人都能理解系统是如何工作的,以及到哪里去找到你所需要的功能,或者找到你要增加功能的正确位置。 可接受的步伐 极端编程团队都会在这里很长的一段时间。他们努力的工作,并且在一个能够不断维持的步伐下。这意味着在有效的时候他们会加班工作,而且他们经常这样工作来保证每周都有最大的生产力。这恰当的解释了死亡竞赛式的项目既不会有生产力也不会创造有质量的软件系统。XP团队在这里是要胜利而不是要死亡。 小结 极端编程是一种以简单性、交流、反馈和勇气为基本宗旨的开发纪律。它的做法是以有效的实践规则将整个团队紧密联系起来,通过充分的反馈使团队能随时知道自己目前的状况和恰当地调节实践规则以适应自己的特殊情况。

2013-03-07

tomcat下验证集群是否成功app

将该应用放到webapps目录下,就可以验证该tomcat是否集群是否成功。

2021-05-31

TongWeb6.0用户使用手册

TongWeb6.0用户使用手册

2020-12-29

sigar-lib.zip

libsigar-aarch64-linux.so libsigar-amd64-freebsd-6.so libsigar-amd64-linux.so libsigar-amd64-solaris.so libsigar-ia64-hpux-11.sl libsigar-ia64-linux.so libsigar-pa-hpux-11.sl libsigar-ppc-aix-5.so libsigar-ppc-linux.so libsigar-ppc64-aix-5.so libsigar-ppc64-linux.so libsigar-s390x-linux.so

2020-09-27

java 抓包工具/网络嗅探源码,亲测可运行

java 抓包工具/网络嗅探源码,亲测可运行,包念64位jpcap.jar及对应jpcap.dll,感觉网上64位的Jpcap.dll比较难找,就打了个包上来。 里面放了2种版本的Jpcap(jpcap.jar+Jpcap.dll),都可以使用

2020-09-21

doc2pdf_src.zip

docx转pdf java源码 import com.spire.doc.*; /* * @version V1.0 */ public class ToPDF { public static void main(String[] args) { long start = System.currentTimeMillis(); String inputFile="D:\\home\\da_data\\Sample.docx"; String outputFile="D:\\home\\da_data\\toPDF.pdf"

2020-09-03

java读取dwg的预览图

java读取dwg的预览图, 使java将autocad 的dwg文件读出预览图

2018-06-15

多屏控制台

在开发一个项目时,通常需要打开多个的控制台来完成项目开发,,如用maven打包、启动mysql数据库,启动tomcat起一个应用,再起tomcat进行集群等等,之后打开了N多个窗口,最终自己也可能搞不清这个打开的控制台是哪个服务,为此,引发了开发一个控制台管理器的想法,打开一个应用,就自动开了N个控制台,然后这些控制台,自动的在屏幕排好版,形成有序的管理,方面管控。

2018-05-13

无法安装64位版本的Office的终极解决办法

无法安装64位版本的Office,因为在您的PC上找到了以下32位程序,请卸载所有32位Office程序,然后重试安装64位Office。如果要安装32位Office,请运行32位安装程序。不管是office2013还是office2010以及office2007,都会出现这个问题,下面小编给大家提供一款“一键解决工具”吧!

2017-12-29

openssl生成认证证书的工具

最简单的方法,直接用java里的keytool工具生成一个keystore文件,然后直接用这个文件启用https就可以了。 方法如下: 命令行执行%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA 执行过程中会询问你一些信息,比如国家代码,省市等,其中需要填写两个密码,一次在开头,一次在最后,请保持两个密码相同。比如,我将密码都设成s3cret。 如果不同,启动会报错,大概是下面这样的 java.io.IOException: Cannot recover key 执行完成后会生成一个.keystore文件,将它复制到tomcat的bin目录下(并不一定,放哪里都可以) 打开conf目录下的server.xml文件,找到以下这一段 它被注释掉了,将注释去掉,并将这一段改成以下 maxThreads="150" scheme="https" secure="true" keystoreFile="bin/.keystore" keystorePass=" s3cret" clientAuth="false" sslProtocol="TLS" /> 之后启动tomcat就可以了,通过https方式访问8443端口,就能看到效果。如果用http访问之前的端口,那么还是普通的未加密连接。 到这里问题来了,我的目的是启用https,但现在http还能访问,那么就可以绕开https。https也就起不了什么作用了。因此要强制访问https。 打开你的web应用的web.xml文件,在最后加上这样一段 Protected Context /* CONFIDENTIAL 重启tomcat,现在你放问原来的地址,假设是http://localhost:8080/mywebapp/,可以看到,连接被重定向到了https的连接 https://localhost:8443/mywebapp/。这样,我们的目的达到了。 但似乎还有点小问题,keystorePass="s3cret",这个密码直接被明码方式卸载server.xml里。总觉得有还是有点不爽。 那么还有一种稍微复杂点的方式,我们使用openssl。 首先,需要下载openssl,为了方便,可以下载一个绿色版, 加压后除了openssl.exe以外,还有一个bat文件,这个可以帮助我们快速创建证书申请文件。 运行autocsr.bat,按照提示输入信息,之后按任意键确认。你会得到两个文件,一个server.key,这是私钥文件,还有一个名为certreq.csr的证书请求文件。 如果你要向证书颁发机构申请正式的安全证书,那么就把这个certreq.csr文件发给他们就行了。他们会给你发来两个cer文件,一个是服务器证书,一个是根证书 如果你只是要使用https,那么证书自己签署就可以了。 在命令行下进入刚才解压的目录,找到openssl.exe所在的目录,执行以下命令 openssl x509 -req -in certreq.csr -out cert.cer -signkey server.key -days 3650 现在你将得到一个名为cert.cer的证书文件。 修改server.xml将 maxThreads="150" scheme="https" secure="true" keystoreFile="bin/.keystore" keystorePass=" s3cret" clientAuth="false" sslProtocol="TLS" /> 修改为以下内容(假设cert.cer和server.key文件都放在tomcat的conf目录下) maxThreads="150" scheme="https" secure="true" SSLCertificateFile="conf/cert.cer" SSLCertificateKeyFile="conf/server.key" sslProtocol="TLS" /> PS.如果真的向证书颁发机构申请到了正式的安全证书,那么配置还有点不同,如下 maxThreads="150" scheme="https" secure="true" SSLCertificateFile="conf/server.cer" SSLCertificateKeyFile="conf/server.key" SSLCertificateChainFile="conf/intermediate.cer" sslProtocol="TLS" /> 因为证书颁发机构会给两个整数,一个是签署后的服务器证书,还有一个中级CA证书,所以要多一行配置。 可能证书颁发机构只会给你服务器证书也就是server.cer, 中级的CA证书即 intermediate.cer 需要到 证书颁发机构提供的网站中去下载,具体的操作会为证书颁发机构给发的邮箱中会有相关的提示 好了,到这里都配置完了,重启tomcat,就可以看到效果。不过,看到的通常会是一个exception,大概是说APR not available 如果遇到这个异常,说明你的tomcat没有安装apr支持 apr安装详见:http://www.blogjava.net/yongboy/archive/2009/08/31/293343.html 之后启动tomcat,问题应该解决了,看起来效果和第一种方式没什么不同。

2016-10-21

instantclient-basic-windows.x64-12.1.0.2.0.zip

不安装Oracle客户端,使用plsql连接Oracle服务器 32位官网工具,无论32位还是64位系统 PLSQL 都需要32的 instantclient-basic-windows.x64-12.1.0.2.0.zip,非常好用,亲自测试成功,本人windows8.1 64位 完全好用!

2016-06-29

lzma.exe使用教程

lzma在绝大多数Linux和Unix系统中默认安装,即安装了Linux和Unix系统就集成了lzma.exe等执行文件。 lzma几个主要参数: -d --decompress --uncompress 指定解压缩,比如 lzma -d test.lzma,该命令相当于 unlzma test.lzma -f --force 强制解压/压缩,忽略一切问题,比如:目标文件已经存在,直接覆盖等。 -h --help 显示帮助 -k --keep 不删除原始文件, -t --test 测试,不解压 -v --verbose 显示进度等信息, -z --compress 强制压缩 用法示例: 压缩文件: lzma test.tar 压缩后生成:lzma.tar.lzma 并且原文件 test.tar会被删除,要想保留,添加 -k 选项 lzma -k test.tar 解压: lzma -d test.tar.lzma 或 unlzma test.tar.lzma 解压后 test.tar.lzma默认被删除,如果想保留,添加-k选项, 如果目标文件已经存在,lzma不会覆盖,而报错退出执行, 添加 -f忽略: lzma -kf test.tar 覆盖已经存在的 lzma.tar.lzma 同时保留原文件 test.tar 解压: lzma -dkf test.tar.lzma 覆盖已经存在的 test.tar 同时保留 test.tar.lzma 上述参数可按照需要作为命令行自行添加(命令参数),目前发现,lzma解压与压缩可应用于其乐达系列DVD,中九阿里、华亚、澜起等机型的数据处理上。

2014-11-21

Screen2Exe V3.4绿色汉化版(免费屏幕录像工具)

Screen2EXE是一款具有独到压缩算法的屏幕录制软件,它可以记录用户在屏幕上的每一步操作,包括鼠标轨迹,点击动作给予花环提示,然后保存为不需播放器即可观看的exe可执行文件。 在生成录制文件的大小与质量之间有四个档次,慢速:每秒一帧;正常:美妙两帧;快速:每秒四帧;最快,尽可能快,至于到底有多快取决于你的电脑性能,以上四个档次中用户还可以选择是否记录麦克风语音。当然,如果你生成的文件质量越高,包含内容越多,那么相应的文件体积也会变大。 软件使用独创的压缩算法,可以获得最小的文件体积,方便传输和保存,生成的演示影片拥有接近无损的画质,同样也可选择较低质量和灰度图像以获取更小的文件体积,生成的目标文件可以使用压缩软件进一步压缩从而大大减小文件体积,是一个不可多得的屏幕记录免费软件。 开始记录会有5秒倒计时,结束录制按F9。

2014-11-13

Wallpaper Calendar 3.0.2 build 87

欢迎使用周捷制作的中文汉化软件 E-mail: [email protected] ===============================================================   软件名称:Wallpaper Calendar 3.0.2 build 87   软件公司:zepsoft   公司网址:www.zepsoft.com   操作系统:Win9x/Win2K/WinXP   软件性质:共享软件   软件简介:十分漂亮的日历显示软件,它可以自动定新时更桌面背景,将桌面上图        标文字的背景颜色设置为透明,并将日历透明的合成于桌面上,而且您        还可以在日历上写上文字,比如约会、日程安排等信息,方便您的工作        和学习。   使用方法:将压缩包解压到一个文件夹,然后运行 WallCal3.exe 即可。        如果你从前安装过这个程序的英文版,请先卸载原程序,        然后删除注册表(regedit)键值“HK_CU\Software\zepsoft”,        98 用户删除 %windir%\Application Data\Zepsoft 文件夹,        2K/XP 用户删除 %userprofile%\Application Data\Zepsoft 文件夹,        然后再运行本程序。    注册码:pgpZgdRMlC ============================================================================ 该汉化补丁只是我业余时间的作品,如发现有翻译错误的地方,请您即时指正,您可以 转载我的软件,但转载时请不要删改软件包中的所有文件,我在这里先谢了。

2014-11-13

visual css version 1.3

visual css version 1.3,css制作利器,完全的可视化工具

2014-02-07

winpe制作利器——grub4dos使用方法和工具

winpe制作利器——grub4dos使用方法和工具

2014-02-07

grub4dos初级教程图文版

1.1 grub简介 GRUB 是一个遵从Multiboot(多重启动)规范的启动管理程序。现在接触到的有3种,即GNU Grub Legacy , GNU Grub2 和 Grub for dos(grub4dos)。 GNU GRUB Legacy其实就是原来的 GNU GRUB 0.xx ,最新版是2005年发布的GNU GRUB 0.97。 目前已停止开发,并改名为 GNU GRUB Legacy。 GNU GRUB2是第二代GRUB,它将取代原来的GNU GRUB(例如0.9x版),但目前还处于开发阶段,尚未发布正式版。 GNU GRUB Legacy和GNU GRUB2都是 GNU 组织的项目。 GRUB for DOS(GRUB4DOS)是一个以 GNU GRUB 为基础的功能强大的引导器。它可以在 DOS 和 LINUX下运行,也可以通过其他引导器来运行,还可以作为MBR运行。GRUB4DOS内置了功能完善的 BIOS 级磁盘仿真。 下面以比较广泛使用的GRUB4DOS为基础进行说明。GNU GRUB与GRUB4DOS的不同之处,可参看相关说明文件。

2014-02-07

汉字液晶的字模生成

汉字液晶的字模生成

2013-12-26

powerbuilder102个绝对实用技巧

DataWindow中动态变更DropDownDW值.doc Datawindow中每页打印固定行.doc PB 修 改 数 据 库 表 结 构 的 技 巧.doc PB 中 窗 口 自 动 居 中.doc PB6.5中有关OLE控件功能的三个缺点.doc PB的环境参数设置.doc PB与Excel通讯.doc PB中客户机从服务器获取系统时间.doc

2013-11-21

powerbuilder

PrintDefineFont() 功能定义打印作业使用的字体,对每个打印作业PowerBuilder支持八种字体。 语法PrintDefineFont(printjobnumber,fontnumber,facename,height,weight,fontpitch,fontfamily, italic,underline) 参数printjobnumber:用PrintOpen()函数打开的打印作业号fontnumber:指定赋给当前定义字体的编号,有效值在1到8之间 facename:string类型,指定字体名称,该字体应该是你的打印机支持的字体,比如“宋体”height:Integer类型,使用正值指定字体的高度,以千分之一英寸为单位;使用负值指定字体点数,比如,-18代表18点。一般来说,使用点数更精确些weight:指定字体的磅数,正常字体为400磅,粗体为700磅fontpitch:FontPitch枚举类型,指定字体标准。有效取值为:Default! - 缺省值;Fixed! - 固定形式;Variable! - 可变形式fontfamily:FontFamily枚举类型,指定字体系列。有效取值为:AnyFont!、Decorative!、Modern!、Roman!、Script!、Swiss!italic:boolean类型,指定是否使用斜体样式。有效取值为:TRUE - 使用斜体样式;FALSE - 不使用斜体样式。缺省值为FALSEunderline:boolean类型,指定是否加下划线。有效取值为:TRUE - 加下划线;FALSE - 不加下划线。缺省值为FALSE返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintDefineFont()函数返回NULL。用法在一个打印作业中,应用程序能够最多同时定义8种字体。当应用程序需要使用更多的字体时,可以在使用了某个字体号输出内容后使用PrintDefineFont()函数将该字体号对应的字体更换为其它字体。 -------------------------------------------------------------------------------- PrintLine() 功能在当前打印页上绘出指定厚度的一条线。 语法PrintLine ( printjobnumber, x1, y1, x2, y2, thickness ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号x1:integer类型,指定直线起点的x坐标,以千分之一英寸为单位y1:integer类型,指定直线起点的y坐标,以千分之一英寸为单位x2:integer类型,指定直线终点的x坐标,以千分之一英寸为单位y2:integer类型,指定直线终点的y坐标,以千分之一英寸为单位thickness:integer类型,指定直线的厚度,以千分之一英寸为单位返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintLine()函数返回NULL。用法应用程序执行了PrintLine()函数后,该函数并不改变打印光标的位置。 -------------------------------------------------------------------------------- PrintOpen() 功能启动打印作业并返回作业号。 语法PrintOpen ( { jobname } ) 参数jobname:string类型,可选项,指定要打开打印作业的名称,该名称将显示在打印管理器窗口中返回值Long。函数执行成功时返回打印作业号,发生错误时返回-1。如果任何参数的值为NULL,PrintOpen()函数返回NULL。用法应用程序执行PrintOpen()函数后,启动新的打印作业并走纸到下一页,同时将打印机缺省字体设置为该打印作业的字体。打印光标的位置位于打印区的左上角。其它同组的打印函数使用PrintOpen()函数返回的作业号来标识作业。需要注意的是,使用PrintOpen()函数打开打印作业、使用同组的其它函数完成打印任务后,必须使用PrintClose()关闭打印作业,或根据需要使用PrintCancel()函数取消打印作业。 -------------------------------------------------------------------------------- PrintOval() 功能在指定位置以指定线宽绘制椭圆或圆。 语法PrintOval ( printjobnumber, x, y, width, height, thickness ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号x:integer类型,指定椭圆或圆外形框左上角的x坐标,以千分之一英寸为单位y:integer类型,指定椭圆或圆外形框左上角的y坐标,以千分之一英寸为单位width:integer类型,指定椭圆或圆外形框的宽度,以千分之一英寸为单位height:integer类型,指定椭圆或圆外形框的高度,以千分之一英寸为单位thickness:integer类型,指定椭圆或圆外边线的厚度,以千分之一英寸为单位返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintOval()函数返回NULL。用法应用程序执行了PrintOval()函数后,该函数并不改变打印光标的位置。PrintOval()函数绘出的椭圆或圆是实心的,也就是说,执行该函数后,椭圆或圆下面的文字或图像将完全被覆盖。如果想在椭圆或圆中输出文字或图形,那么应用程序应该首先绘制椭圆或圆,然后使用其它函数在椭圆或圆中输出文字或图形。 -------------------------------------------------------------------------------- PrintPage() 功能将当前页发送给打印机或打印池并在当前打印作业中启动一个新的打印页。 语法PrintPage ( printjobnumber ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintPage()函数返回NULL。 -------------------------------------------------------------------------------- PrintRect() 功能在指定位置以指定线宽打印矩形。 语法PrintRect ( printjobnumber, x, y, width, height, thickness ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号x:integer类型,指定矩形左上角的x坐标,以千分之一英寸为单位y:integer类型,指定矩形左上角的y坐标,以千分之一英寸为单位width:integer类型,指定矩形的宽度,以千分之一英寸为单位height:integer类型,指定矩形的高度,以千分之一英寸为单位thickness:integer类型,指定矩形边线的厚度,以千分之一英寸为单位返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintRect()函数返回NULL。用法应用程序执行了PrintRect()函数后,该函数并不改变打印光标的位置。PrintRect()函数绘出实心的矩形,也就是说,执行该函数后,矩形下面的文字或图像将完全被覆盖。如果想在矩形中输出文字或图形,那么应用程序应该首先绘制矩形,然后使用其它函数在矩形中输出文字或图形。 -------------------------------------------------------------------------------- PrintRoundRect() 功能在指定位置以指定线宽打印圆角矩形。 语法PrintRoundRect(printjobnumber,x,y,width,height,xradius,yradius,thickness) 参数printjobnumber:用PrintOpen()函数打开的打印作业号x:integer类型,指定圆角矩形左上角的x坐标,以千分之一英寸为单位y:integer类型,指定圆角矩形左上角的y坐标,以千分之一英寸为单位width:integer类型,指定圆角矩形的宽度,以千分之一英寸为单位height:integer类型,指定圆角矩形的高度,以千分之一英寸为单位xradius:integer类型,指定圆角矩形圆角部分的x半径,以千分之一英寸为单位yradius:integer类型,指定圆角矩形圆角部分的y半径,以千分之一英寸为单位thickness:integer类型,指定圆角矩形边线的厚度,以千分之一英寸为单位返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintRoundRect()函数返回NULL。用法应用程序执行了PrintRoundRect()函数后,该函数并不改变打印光标的位置。PrintRoundRect()函数绘出实心的圆角矩形,也就是说,执行该函数后,圆角矩形下面的文字或图像将完全被覆盖。如果想在圆角矩形中输出文字或图形,那么应用程序应该首先绘制圆角矩形,然后使用其它函数在圆角矩形中输出文字或图形。 -------------------------------------------------------------------------------- PrintScreen() 功能在打印作业中打印屏幕图像。 语法PrintScreen ( printjobnumber, x, y {, width, height } ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号x:integer类型,指定要打印屏幕图像左上角在打印页上的x坐标,以千分之一英寸为单位y:integer类型,指定要打印屏幕图像左上角在打印页上的y坐标,以千分之一英寸为单位width:integer类型,可选项,指定屏幕图像的打印宽度,以千分之一英寸为单位。如果省略了该参数,那么PowerBuilder按屏幕的原始宽度打印屏幕图像。如果指定了该参数,必须同时指定height参数height:integer类型,可选项,指定屏幕图像的打印高度,以千分之一英寸为单位。如果省略了该参数,那么PowerBuilder按屏幕的原始高度打印屏幕图像返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintScreen()函数返回NULL。 -------------------------------------------------------------------------------- PrintSend() 功能直接向打印机发送任意字符串,通常用于发送打印机的控制代码。 语法PrintSend ( printjobnumber, string {, zerochar } ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号string:string类型,指定发送到打印机的字符串。在该字符串中,使用非打印字符的ASCII码值表示非打印字符zerochar:integer类型,可选项,指定在string参数中用于表示数值0的ASCII码值。有效取值在1到255之间返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintSend()函数返回NULL。用法应用程序使用PrintSend()函数可以直接向打印机发送控制序列(换码序列),比如,设置打印文字的浓淡、打印页的四周空白等。不同类型的打印机使用不同的控制序列,你需要翻一翻你的打印机手册。由于PowerBuilder使用数值0(即ASCII码为0的字符)结束每个字符串,因此,如果打印控制序列中包含了数值0,应用程序需要使用其它字符在参数string中替代数值0,并用zerochar参数指明这个替代字符。一般来说,应该选择一个打印机控制序列中不使用的字符作为0值字符的替代字符。通常情况下,按下述次序组织打印作业:1. 使用PrintOpen()函数打开打印作业2. 使用PrintSend()函数设置打印机特性,比如打印方向、四周空白等3. 使用PrintDefineFont()和PrintSetFont()函数设置该打印作业使用的字体4. 使用该组的其它函数打印输出文字或图形5. 执行PrintClose()函数关闭打印作业 -------------------------------------------------------------------------------- PrintSetFont() 功能设置当前打印作业使用的字体。 语法PrintSetFont ( printjobnumber, fontnumber ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号fontnumber:指定该打印作业使用字体的字体编号,该编号与PrintDefineFont()函数中定义的编号应该对应,字体编号的有效取值在1到8之间,0表示使用打印机的缺省字体返回值Integer。函数执行成功时返回当前字体的高度,发生错误时返回-1。如果任何参数的值为NULL,PrintSetFont()函数返回NULL。 -------------------------------------------------------------------------------- PrintSetSpacing() 功能设置行间距因子,打印函数将使用该因子来决定行间距。 语法PrintSetSpacing ( printjobnumber, spacingfactor ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号spacingfactor:指定行间距因子,用字符高度的倍数表示,缺省值为1.2返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintSetSpacing()函数返回NULL。用法在PowerBuilder应用程序中,行间距与字符的高度成正比,缺省值为字符高度的1.2倍。当Print组函数生成新行时,系统自动把打印光标的x坐标位置设置为0,y坐标位置在原有基础上增加当前行距值。使用PrintSetSpacing()函数可以改变当前打印作业的行距。 -------------------------------------------------------------------------------- PrintSetup() 功能打开打印机设置对话框。 语法PrintSetup ( ) 返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,PrintSetup()函数返回NULL。用法当系统中安装了多种打印机时,在Windows 95中PrintSetup()函数打开如图2-1所示的对话框,单击“Setup”按钮设置打印机各种特性。如果系统中只有一个打印机,则直接打开该打印机的打印设置对话框。需要注意的是,在Windows95和Windows NT 3.51以后的版本中,使用PrintSetup()函数设置的打印机设置只对当前应用起作用,并不影响其它应用的打印机设置。对Windows 3.1来说,使用PrintSetup()函数设置的打印机设置影响系统中的所有应用。 -------------------------------------------------------------------------------- PrintText() 功能在指定位置打印一行文本。 语法PrintText ( printjobnumber, string, x, y {, fontnumber } ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号string:string类型,指定要打印的文本x:integer类型,指定文本开始打印位置的x坐标,以千分之一英寸为单位y:integer类型,指定文本开始打印位置的y坐标,以千分之一英寸为单位fontnumber:可选参数,指定打印文本使用的字体号,该编号由PrintDefineFont()函数确定。省略该参数时,以打印作业的当前字体打印文本返回值Integer。函数执行成功时返回文本打印后打印光标的x位置,即参数x的值加上打印文本的宽度。发生错误时返回-1。如果任何参数的值为NULL,PrintText()函数返回NULL。 -------------------------------------------------------------------------------- PrintWidth() 功能确定一个字符串在指定打印作业中按当前字体所占的宽度,以千分之一英寸为单位。 语法PrintWidth ( printjobnumber, string ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号string:string类型,指定要决定其打印宽度的字符串返回值Integer。函数执行成功时返回按当前字体计算的字符串打印宽度,以千分之一英寸为单位,发生错误时返回-1。如果任何参数的值为NULL,PrintWidth()函数返回NULL。 -------------------------------------------------------------------------------- PrintX() 功能返回打印光标的x坐标位置。 语法PrintX ( printjobnumber ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号返回值Integer。函数执行成功时返回打印光标的x坐标位置,以千分之一英寸为单位,发生错误时返回-1。如果任何参数的值为NULL,PrintX()函数返回NULL。 -------------------------------------------------------------------------------- PrintY() 功能返回打印光标的y坐标位置。 语法PrintY ( printjobnumber ) 参数printjobnumber:用PrintOpen()函数打开的打印作业号返回值Integer。函数执行成功时返回打印光标的y坐标位置,以千分之一英寸为单位,发生错误时返回-1。如果任何参数的值为NULL,PrintY()函数返回NULL。  LibraryCreate() 功能创建一个空的PowerBuilder应用库,并可根据需要在创建应用库的同时添加库注解。 语法LibraryCreate ( libraryname{, comments } ) 参数libraryname:string类型,指定要创建应用库的名称,可以带上路径,不带路径时在当前目录下创建应用库comments:string类型,可选项,指定要创建的应用库的注解返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,LibraryCreate()函数返回NULL。用法LibraryCreate()函数在指定路径下创建一个空的PowerBuilder应用库(PBL)。如果在指定应用库名称时没有指定文件的扩展名,那么该函数自动加上扩展名.PBL。 -------------------------------------------------------------------------------- LibraryDelete() 功能删除应用库库文件或应用库中的数据窗口对象。 语法LibraryDelete ( libraryname{, objectname, objecttype } ) 参数libraryname:string类型,指定库名,可以带上路径,不带路径时在系统搜索路径下查找应用库objectname:string类型,可选项,指定要从库中删除的数据窗口对象的名称objecttype:LibImportType类型,可选项,指定要删除对象的类型,目前仅支持ImportDataWindow!返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,LibraryDelete()函数返回NULL。 用法执行LibraryDelete()函数时,如果未指定后两个参数,那么该函数删除指定的应用库;如果指定了后两个参数,那么该函数删除指定应用库中指定的数据窗口对象。LibraryDelete()函数只能删除应用库中的数据窗口对象,如果想删除其它对象,那么只能在PowerBuilder开发环境中使用库管理画笔(Library Painter)来实现了。 -------------------------------------------------------------------------------- LibraryDirectory() 功能 得到应用库中指定对象的信息列表,内容包括对象名称、最近修改日期和时间、以及对象的注释。 语法LibraryDirectory ( libraryname, objecttype ) 参数libraryname:string类型,指定PowerBuilder应用库的名称,如果名称中未指定路径,那么该函数根据操作系统标准的文件搜索路径查找指定文件objecttype:LibDirType枚举类型,指定希望函数列出的对象类型,有效取值请参看用法。返回值String。函数执行成功时返回一个字符串,每个对象占用一行,行中各信息之间使用Tab字符(~t)分隔。行中信息格式为:对象名~t修改日期/时间~t注释~n发生错误时函数返回空字符串("")。如果任何参数的值为NULL,LibraryDirectory()函数返回NULL。 用法LibraryDirectory()函数的objecttype参数是个LibDirType枚举类型的量,其有效取值为:DirAll!得到所有对象的信息DirApplication!得到应用对象的信息DirDataWindow!得到所有数据窗口对象的信息DirFunction!得到所有函数对象的信息DirMenu!得到所有菜单对象的信息DirPipeline!得到所有数据管道对象的信息DirProject!得到工程对象的信息DirQuery!得到所有查询对象的信息DirStructure!得到所有结构对象的信息DirUserObject!得到所有用户对象的信息DirWindow!得到所有窗口对象的信息使用LibraryDirectory()函数得到指定对象的名称、修改日期/时间以及可能的注释后,应用程序既可以使用Pos()函数进行定位和字符串分割,也可以使用数据窗口的ImportString()函数将结果显示在数据窗口中。 -------------------------------------------------------------------------------- LibraryExport() 功能从指定应用库中以对象的语法定义格式卸出对象。 语法LibraryExport ( libraryname, objectname, objecttype ) 参数libraryname:string类型,指定要移出对象的应用库的名称,如果名称中未指定路径,那么该函数根据操作系统标准的文件搜索路径查找指定文件objectname:string类型,指定要移出对象的名称objecttype :LibExportType枚举类型,指定要移出对象的类型,具体取值请参看用法返回值String。函数执行成功时返回指定对象的语法,该语法与使用库管理画笔(Library Painter)移出对象时的语法相同,区别在于LibraryExport()函数省略了移出语法的头部。如果发生错误,则函数返回空字符串("")。如果任何参数的值为NULL,LibraryExport()函数返回NULL。 用法LibraryExport()的objecttype参数的可能取值为: ExportApplication!应用对象ExportDataWindow!数据窗口对象ExportFunction!函数对象ExportMenu!菜单对象ExportPipeline!数据管道对象ExportProject!工程对象ExportQuery!查询对象ExportStructure!结构对象ExportUserObject!用户对象ExportWindow!窗口对象 -------------------------------------------------------------------------------- LibraryImport() 功能将以语法格式表示的数据窗口对象装入指定的应用库中。 语法LibraryImport(libraryname,objectname,objecttype,syntax,errors{,comments } ) 参数libraryname:string类型,指定要移入对象的应用库的名称,如果名称中未指定路径,那么该函数根据操作系统标准的文件搜索路径查找指定文件objectname:string类型,指定要移入的数据窗口对象的名称 objecttype:LibImportType枚举类型,指定要移入对象的类型,目前该函数只支持ImportDataWindow!,表示只能向应用库中移入数据窗口对象syntax:string类型,指定要移入数据窗口对象的语法errors:string类型变量,用于在发生错误时保存出错信息comments:string类型,可选项,用于指定移入对象的注解返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,LibraryImport()函数返回NULL。 用法当应用程序在运行过程中动态创建数据窗口对象后,可以使用LibraryImport()函数把动态数据窗口对象的定义保存到应用库中,以后就可以直接使用该对象了。 FileClose() 功能关闭先前用FileOpen()函数打开的文件。 语法FileClose ( fileno ) 参数fileno:integer,指定要关闭文件的文件句柄,该句柄使用FileOpen()函数打开文件时得到返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果fileno参数的值为NULL,那么FileClose()函数返回NULL。 -------------------------------------------------------------------------------- FileDelete() 功能删除指定的文件。 语法FileDelete ( filename ) 参数filename:string类型,指定要删除文件的文件名,其中可以包含路径返回值Boolean。函数执行成功时返回TRUE,发生错误时返回FALSE。如果filename参数的值为NULL,那么FileDelete()函数返回NULL。 -------------------------------------------------------------------------------- FileExists() 功能检查指定的文件是否存在。 语法FileExists ( filename ) 参数filename:string类型,指定要检查存在性的文件的文件名,其中可以包含路径返回值Boolean。如果指定文件存在时返回TRUE,不存在时返回FALSE。如果filename参数的值为NULL,那么FileExists()函数返回NULL。用法如果filename参数指定的文件被另一个应用加锁锁住,那么FileExists()函数也将返回FALSE。 -------------------------------------------------------------------------------- FileLength() 功能得到指定文件的长度(以字节为单位)。 语法FileLength ( filename ) 参数filename:string类型,指定要得到其长度的文件的文件名,其中可以包含路径返回值Long。函数执行成功时返回指定文件的长度(以字节为单位)。如果指定的文件不存在,函数返回-1。如果filename参数的值为NULL,那么FileLength()函数返回NULL。 -------------------------------------------------------------------------------- FileOpen() 功能以指定的读写方式打开指定的文件,同时返回该文件的句柄。 语法FileOpen(filename{,filemode{,fileaccess{,filelock{,writemode,{creator,filetype}}}}}) 参数filename:string类型,指定要打开文件的名称,其中可以包含路径 filemode:FileMode枚举类型,可选项,指定文件打开方式。有效取值为:?LineMode! - 缺省值,行模式;?StreamMode! - 流模式fileaccess:FileAccess枚举类型,可选项,指定文件访问方式。有效取值为:?Read! - 缺省值,只读方式,这样打开的文件只能进行读操作;?Write! - 只写方式,这样打开的文件只能进行写操作?filelock:FileLock枚举类型,可选项,指定文件加锁方式。有效取值为:n LockReadWrite! - 缺省值,只有打开该文件的用户能够访问该文件,其它用 户对该文件的访问均被拒绝;n LockRead! - 只有打开该文件的用户能够读该文件,但其它任何用户均可写该文件;n LockWrite! - 只有打开该文件的用户能够写该文件,但其它任何用户均可读该文件;n Shared! - 所有用户均可读写该文件writemode:WriteMode枚举类型,可选项,当fileaccess参数指定为Write!时,该参数指定在指定文件已经存在时数据的添加方式。有效取值为:?Append! - 缺省值,将数据添加到原文件尾部;?Replace! - 覆盖原有数据creator:可选项,用于Macintosh机,使用四个字符的字符串指定文件的创建者。指定该参数后,必须同时指定filetype参数filetype:可选项,用于Macintosh机,使用四个字符的字符串指定文件类型返回值Integer。函数执行成功时返回打开文件的句柄,随后的文件操作函数利用该句柄完成对文件的操作。发生错误时函数返回-1。如果任何参数的值为NULL,那么FileOpen()函数返回NULL。用法当文件以行模式打开时,每执行一次FileRead()函数读取一行数据;每执行一次FileWrite()函数,该函数自动在写出的字符串末尾增加一个回车(CR)换行(LF)符(这是应用程序在Windows 系统中运行时的情况,在UNIX下只加一个换行字符)。当文件以流模式打开时,执行一次FileRead()函数读取32,765个字节的数据,如果余下数据没有这么多,那么FileRead()函数就读取所有余下的数据;执行一次FileWrite()函数时,最多可写入32,765个字节的数据,并且不添加回车换行字符。当文件以写方式使用FileOpen()函数打开时,如果指定的文件不存在,那么FileOpen()函数创建该文件。 -------------------------------------------------------------------------------- FileRead() 功能从指定文件中读取数据。 语法FileRead ( fileno, variable ) 参数fileno:integer类型,指定文件句柄(由FileOpen()函数得到)variable:string或blob类型的变量,用于保存读取的数据返回值Integer。函数执行成功时返回读取的字符数或字节数;如果在读取任何字符前读到了文件结束符(EOF),则FileRead()函数返回-100;当指定文件以行模式打开时,如果在读取任何字符之前遇到了回车(CR)或换行(LF)字符,则FileRead()函数返回0。如果发生其它错误,FileRead()函数返回-1。如果任何参数的值为NULL,那么FileRead()函数返回NULL。用法当指定文件以行模式(Line Mode)打开时,FileRead()函数一次读取一行数据,并把它保存到参数variable中,然后跳过行结束符(回车换行符,操作系统不同,使用的字符也不同),把文件指针移动到下一行的起始位置。当文件以流模式(Stream Mode)打开时,FileRead()函数或一直读取到文件结尾,或读取32,765字节的数据,决定于两者哪个数据长度更短些。 -------------------------------------------------------------------------------- FileSeek() 功能将文件指针移动到指定位置。读写文件时相应函数会自动移动文件指针。 语法FileSeek ( fileno, position, origin ) 参数fileno: integer类型,指定文件句柄(由FileOpen()函数得到) position:long类型,指定相对于origin参数指定位置的新位置偏移量,以字节为单位 origin:SeekType枚举类型,指定从哪里开始移动文件指针,即指针移动的基准。有效取值为:?FromBeginning! - 缺省值,从文件开头移动指针;?FromCurrent! - 从当前位置移动文件指针;?FromEnd! - 从文件结尾处移动文件指针返回值Long。函数执行成功时返回指针移动后的指针位置。如果任何参数的值为NULL,那么FileSeek()函数返回NULL。 -------------------------------------------------------------------------------- FileWrite() 功能向指定文件中写数据。 语法FileWrite (fileno , variable ) 参数fileno:integer类型,指定文件句柄(由FileOpen()函数得到)variable:string或blob类型,其值将写入fileno参数指定的文件返回值Integer。函数执行成功时返回写入文件的字符或字节数,发生错误时返回-1。如果任何参数的值为NULL,那么FileWrite()函数返回NULL。用法FileWrite()函数从当前文件指针开始写入指定数据,写入之后,将文件指针调整到刚刚写入数据的下一个字节位置。当文件以writemode参数设置为Replace!方式打开时,文件指针最初位于文件的开头位置;当文件以writemode参数设置为Append!方式打开时,文件指针最初位于文件的结尾位置。当文件以行模式打开时,执行FileWrite()函数时,该函数自动在每次写入数据的后面加上回车换行符,并把文件指针移动到回车换行符后面。当文件以流模式打开时,FileWrite()函数一次最多写入32,765个字节。如果variable参数中数据的长度超过了32,765个字节,那么FileWrite()函数只向文件中写入前32,765个字符并返回32,765。 -------------------------------------------------------------------------------- GetFileOpenName() 功能显示打开文件对话框,让用户选择要打开的文件。 语法GetFileOpenName(title,pathname,filename{,extension{,filter}}) 参数title:string类型,指定对话框的标题pathname:string类型变量,用于保存该对话框返回的文件路径及文件名filename:string类型变量,用于保存该对话框返回的文件名extension:string类型,可选项,使用1到3个字符指定缺省的扩展文件名 filter:string类型,可选项,其值为文件名掩码,指定显示在该对话框的列表框中供用户选择的文件名满足的条件(比如*.*,*.TXT,*.EXE等)返回值Integer。函数执行成功时返回1;当用户单击了对话框上的“Cancel”按钮时函数返回0;发生错误时返回-1。如果任何参数的值为NULL,那么GetFileOpenName()函数返回NULL。 用法filter参数的格式为:description,*. ext缺省值为:"All Files (*.*),*.*"其中,description说明扩展名的意义,比如“所有文件”、“文本文件”等。你可以根据需要指定在打开文件对话框中显示的文件名类型。当需要指定多种文件类型时,各类型之间使用逗号分隔,例如:"PIF 文件, *.PIF, 批处理文件, *.BAT"需要注意的是,该函数只是得到一个文件名,而并没有打开文件,需要打开文件时,依然需要使用FileOpen()函数。 -------------------------------------------------------------------------------- GetFileSaveName() 功能显示保存文件对话框,让用户选择要保存到的文件。 语法GetFileSaveName(title,pathname,filename{,extension{,filter}}) 参数title:string类型,指定对话框的标题pathname:string类型变量,用于保存该对话框返回的文件路径及文件名filename:string类型变量,用于保存该对话框返回的文件名extension:string类型,可选项,使用1到3个字符指定缺省的扩展文件名filter:string类型,可选项,其值为文件名掩码,指定显示在该对话框的列表框中供用户选择的文件名满足的条件(比如*.*,*.TXT,*.EXE等)返回值Integer。函数执行成功时返回1;当用户单击了对话框上的“Cancel”按钮时函数返回0;发生错误时返回-1。如果任何参数的值为NULL,那么GetFileSaveName()函数返回NULL。 用法filter参数的格式为:description,*. ext缺省值为:"All Files (*.*),*.*"其中,description说明扩展名的意义,比如“所有文件”、“文本文件”等。你可以根据需要指定在打开文件对话框中显示的文件名类型。当需要指定多种文件类型时,各类型之间使用逗号分隔,例如:"PIF 文件, *.PIF, 批处理文件, *.BAT"需要注意的是,该函数只是得到一个文件名,而并没有打开文件,需要打开文件时,依然需要使用FileOpen()函数。 GetCommandDDE() 功能得到DDE客户应用发送的命令。 语法GetCommandDDE ( string ) 参数string:string类型的变量,用于保存DDE客户应用发送的命令返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果string参数的值为NULL, GetCommandDDE()函数返回NULL。用法当DDE客户应用向DDE服务器应用发送一条命令时,这个动作将触发DDE服务器应用活动窗口的RemoteExec事件,在这个事件的事件处理程序中,可以使用GetCommandDDE()函数得到DDE客户应用发送的命令。 -------------------------------------------------------------------------------- GetCommandDDEOrigin() 功能确定哪一个DDE客户应用向服务器发送了命令。 语法GetCommandDDEOrigin ( applstring ) 参数applstring:string变量,用于保存发送命令的DDE客户应用的名称返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果applstring参数的值为 NULL,GetCommandDDEOrigin()函数返回NULL。 -------------------------------------------------------------------------------- GetDataDDE() 功能得到DDE客户应用发送的数据。 语法GetDataDDE ( string ) 参数string:string类型变量,用于保存接收到的数据返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL, GetDataDDE()函数返回NULL。 -------------------------------------------------------------------------------- GetDataDDEOrigin()功能确定哪个DDE客户应用发送了数据。 语法GetDataDDEOrigin ( applstring, topicstring, itemstring ) 参数applstring:string类型变量,用于保存客户应用的名称topicstring:string类型变量,用于保存主题(比如,在Excel中,主题可以是REGION.XLS)itemstring:string类型变量,用于保存数据项标识(比如,在Excel中,数据项标识可能是R1C2)返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,GetDataDDEOrigin()函数返回NULL。 -------------------------------------------------------------------------------- RespondRemote() 功能向客户端应用指明最近的命令或数据是否已经接收。 语法RespondRemote ( boolean ) 参数boolean:其值为boolean量的逻辑表达式,TRUE表示接收先前收到的命令或数据,FALSE表示不接收先前收到的命令或数据返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果boolean参数的值为NULL,RespondRemote()函数返回NULL。 -------------------------------------------------------------------------------- SetDataDDE() 功能向DDE客户应用发送数据。 语法SetDataDDE ( string {, applname, topic, item } ) 参数string:指定要发送到DDE客户应用的数据applname:string类型,可选项,指定接收数据的客户应用的DDE名称topic:string类型,可选项,指定基础数据组item:string类型,可选项,指定基础数据组中的数据项返回值Integer。函数执行成功时返回1,发生错误时返回下述值之一:-1函数调用的环境不对-2数据未被接收如果任何参数的值为NULL,SetDataDDE()函数返回NULL。 -------------------------------------------------------------------------------- StartServerDDE() 功能将当前应用设置为DDE服务器。 语法StartServerDDE ( { windowname, } applname, topic {, item } ) 参数windowname:可选项,指定服务器窗口名,缺省值为当前窗口applname:当前应用的DDE名称topic:string类型,指定DDE客户应用能够引用的基本数据组item:由逗号(,)分隔的一个或多个字符串,指定服务器应用支持的数据项返回值Integer。函数执行成功时返回1,发生错误时返回-1,表示当前应用已经设置为DDE服务器。如果任何参数的值为NULL,StartServerDDE()函数返回NULL。 -------------------------------------------------------------------------------- StopServerDDE() 功能停止当前应用的DDE服务器功能。执行该函数后,发给该应用的任何DDE客户应用请求都将失败。 语法StopServerDDE ( { windowname, } applname, topic ) 参数windowname:可选项,指定要关闭服务器功能的服务器窗口名,缺省值为当前窗口,如果当前应用有多个服务器窗口,那么必须指定该参数applname:当前应用的DDE名称topic:string类型,应该与StartServerDDE()中对应参数相同返回值Integer。函数执行成功时返回1,发生错误时返回-1,表示当前应用未曾作为DDE服务器启动。如果任何参数的值为NULL,StopServerDDE()函数返回NULL。 CPU() 功能得到自当前应用程序启动后开始CPU所消耗的时间,以毫秒为单位。 语法CPU() 返回值Long。返回自当前应用程序启动后开始CPU所消耗的时间,以毫秒为单位。 -------------------------------------------------------------------------------- Idle() 功能该函数在用户每次活动(例如,按键盘、移动鼠标等)后重置定时器,n秒后触发应用对象的Idle事件。 语法Idle ( n ) 参数n:指定空闲时间间隔,以秒为单位。该参数的值设置为0时,停止空闲检测,不再触发应用对象的Idle事件返回值Integer。函数执行成功时返回1,此时启动定时器。如果不能启动定时器或定时器未启动而n的值指定为0时,函数返回-1。如果任何参数的值为NULL,Idle()函数返回NULL。用法利用Idle()函数,应用程序可以构造自己的屏幕保护程序,避免安全数据的泄露。当使用Idle()函数已经启动了定时器后,如果再次以非0参数调用Idle()函数,那么该函数重设时间间隔,但并不启动新的定时器。Idle()函数启动定时器后,如果在指定的时间间隔(从用户最近一次操作算起)内没有操作应用程序,那么就触发应用对象的Idle事件,在这个事件中可以编写关闭窗口、退出数据库登录等一系列代码,然后使用Restart()函数重新启动应用程序,起到保密的目的。发生下述任何情况时,系统自动重置定时器(即重新开始计时):n 用户在该应用程序的任何窗口内移动鼠标或单击鼠标(双击鼠标时首先触发单击事件)n 在该应用程序的某个窗口是当前窗口时用户按下了任意一个或多个键n 在该应用程序的窗口最小化时,用户在该应用的图标上单击鼠标或移动鼠标n 在该应用程序的窗口最小化并且该应用程序是当前应用程序(应用名称被加亮显示)时,用户按了任何按键n 可视数据窗口检索数据时引起的编辑控件(指漂浮在数据窗口当前行/列上的编辑控件)重绘操作 -------------------------------------------------------------------------------- Timer() 功能 在指定的时间间隔内反复触发指定窗口的定时器事件。 语法Timer ( interval {, windowname } ) 参数interval:指定两次触发Timer事件之间的时间间隔,有效值在0到65之间。如果该参数的值指定为0,那么关闭定时器,不再触发指定窗口的Timer事件windowname:窗口名,指定时间间隔到时要触发哪个窗口的Timer事件。省略该参数时,触发当前窗口的Timer事件返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,Timer()函数返回NULL。用法使用Timer()函数可以周期性地触发指定窗口的Timer事件,这样,每当时间间隔过去时,应用程序都可以完成一些周期性的工作,比如绘制简单动画等。将Timer()的interval参数设置为非0值时启动定时器并开始计时;将该函数的interval参数设置为0时关闭定时器,终止计时任务。需要注意的是,在Microsoft Windows系统中,该函数能够计时的最小时间间隔为0.055秒(约1/18秒),如果把interval参数的值设置小于0.055,那么该定时器将每隔0.055秒触发一次窗口的Timer事件。Microsoft Windows 3.x最多只支持系统中同时启动16个定时器。 RegistryDelete() 功能删除Windows系统注册库中的一个键或键的某个值。 语法RegistryDelete ( key, valuename ) 参数key:string类型,指定键名,将删除该键或删除该键的某个值valuename:string类型,指定要删除的值的名称。如果想删除键、键的值、以及其下的所有子键,那么将该参数指定为空字符串返回值Integer。函数执行成功时返回1,发生错误时返回-1。用法为了唯一地标识某个键,在key参数中,可以从根键开始依次指定各级父键,各键之间使用反斜杠(\)分隔。 -------------------------------------------------------------------------------- RegistryGet() 功能从系统注册库中得到指定键的值。 语法RegistryGet ( key, valuename, valuetype, valuevariable ) 参数key:string类型,指定键名valuename:string类型,指定要访问值的名称。每个键可以有一个未命名的值和多个命名的值。要访问未命名的值,把该参数指定为空字符串("")valuetype:RegistryValueType枚举类型,指定值的数据类型。有效取值请参看用法valuevariable:用于保存键值的变量,其数据类型应该与valuetype参数指定的类型相匹配返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果valuevariable的数据类型与valuetype参数指定的类型不匹配,将引发运行错误。 用法valuetype的可能取值为:RegString!以空字符结束的字符串RegExpandString!以空字符结束的字符串,其中包括了对环境变量的非扩展应用RegBinary!二进制数据ReguLong!32位数据ReguLongBigEndian!32位大数据RegLink!Unicode符号链RegMultiString!动态字符串数组为了唯一地标识某个键,在key参数中,可以从根键开始依次指定各级父键,各键之间使用反斜杠(\)分隔。 -------------------------------------------------------------------------------- RegistryKeys() 功能从系统注册库中得到指定键的有效子键。 语法RegistryKeys ( key, subkeys ) 参数key:string类型,指定键名subkeys:字符串数组变量,用于保存各子键返回值Integer。函数执行成功时返回1,发生错误时返回-1。用法在subkeys参数中可以使用定长数组,也可以使用动态数组。使用动态数组时,数组的上界反映了能够得到的子键个数。当使用定长数组时,其数组元素个数必须足够多,保证能够容纳所有子键,但是,在具体得到子键之前,没有办法能够预先知道实际子键个数。为了唯一地标识某个键,在key参数中,可以从根键开始依次指定各级父键,各键之间使用反斜杠(\)分隔。 -------------------------------------------------------------------------------- RegistrySet() 功能在系统注册库中设置或创建指定键。 语法RegistrySet ( key, valuename, valuetype, value ) 参数key:string类型,指定键名valuename:string类型,指定要访问值的名称。每个键可以有一个未命名的值和多个命名的值。要访问未命名的值,把该参数指定为空字符串("")。如果注册库中不存在指定值名,该函数将创建新的值名valuetype:RegistryValueType枚举类型,指定值的数据类型。有效取值请参看用法value:要设置的值,其数据类型应该与valuetype参数指定的类型相匹配返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果valuevariable的数据类型与valuetype参数指定的类型不匹配,将引发运行错误。用法valuetype的可能取值为:RegString!以空字符结束的字符串RegExpandString!以空字符结束的字符串,其中包括了对环境变量的非扩展应用RegBinary!二进制数据ReguLong!32位数据ReguLongBigEndian!32位大数据RegLink!Unicode符号链RegMultiString!动态字符串数组为了唯一地标识某个键,在key参数中,可以从根键开始依次指定各级父键,各键之间使用反斜杠(\)分隔。 -------------------------------------------------------------------------------- RegistryValues() 功能得到与指定键相关的一组值名。该函数在Windows 3.1中无效。 语法RegistryValues ( key, valuename ) 参数key:string类型,指定键名valuename:字符串数组变量,用于保存值名返回值Integer。函数执行成功时返回1,发生错误时返回-1。用法在valuename 参数中可以使用定长数组,也可以使用动态数组。使用动态数组时,数组的上界反映了能够得到的值名个数。当使用定长数组时,其数组元素个数必须足够多,保证能够容纳所有值名,但是,在具体得到值名之前,没有办法能够预先知道实际值名个数。为了唯一地标识某个键,在key参数中,可以从根键开始依次指定各级父键,各键之间使用反斜杠(\)分隔。  Clipboard() 功能提取或替换Windows系统剪贴板的文本内容。 语法Clipboard ( { string } ) 参数string:string类型,可选项,指定要复制到系统剪贴板上的文本。如果剪贴板上已有内容的话,该文本将取代剪贴板的当前内容返回值String。函数执行成功时,如果剪贴板上包含文本数据,那么函数返回剪贴板的当前内容;如果剪贴板上包含非文本数据(比如位图)或不包含任何数据,那么函数返回空字符串("")。如果string参数的值为NULL,Clipboard()函数返回NULL。用法无论是否指定string参数,Clipboard()都将返回剪贴板的当前内容。当指定string参数时,剪贴板的原有内容被string参数的值取代;省略string参数时,仅仅得到剪贴板的内容。 -------------------------------------------------------------------------------- CommandParm() 功能得到应用程序运行时指定的命令参数。 语法CommandParm ( ) 返回值String。函数执行成功时返回应用程序运行时的命令行参数,函数执行错误或没有命令行参数时函数返回空字符串("")。用法命令行参数是应用程序启动时跟在应用程序名称后面的任何参数,比如,在运行窗口中输入了下述命令:MyAppl C:\EMPLOYEE\EMPLIST.TXT那么MyAppl应用程序中使用CommandParm()函数得到的命令行参数为:C:\EMPLOYEE\EMPLIST.TXT当应用程序的命令行中包含几个参数时,CommandParm()函数作为一个字符串返回所有参数。利用字符串操作函数可以分离各参数。在应用对象的Open事件中没有必要执行CommandParm()函数。此时,Open事件的argument参数中包含了命令行参数。 -------------------------------------------------------------------------------- DoScript() 功能执行AppleScript程序段,该函数只在Macintosh平台上有效。 语法DoScript ( script, result ) 参数script:string类型,指定要运行的程序段(script)result:string类型,由AppleScript程序段返回的结果信息或出错信息返回值Integer。返回由AppleScript返回的结果代码。如果任何参数的值为NULL,DoScript()函数返回NULL。 -------------------------------------------------------------------------------- GetApplication() 功能得到当前应用对象的句柄,这样你可以查询或设置应用对象的属性(通常用于编写通用代码)。 语法GetApplication ( ) 返回值Application。返回当前应用对象的句柄。 -------------------------------------------------------------------------------- GetEnvironment() 功能得到操作系统、处理器、屏幕显示等与系统相关的信息。 语法GetEnvironment ( environmentinfo ) 参数environmentinfo:Environment对象名,用于保存系统环境信息返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果参数environmentinfo的值为NULL,GetEnvironment()函数返回NULL。用法当开发交叉平台项目时,利用GetEnvironment()函数,应用程序能够得到当前运行的操作系统、使用的CPU类型、操作系统的版本、屏幕的大小以及颜色数等信息,这些信息的具体表示请参阅本书环境对象(Environment Object)的介绍。 -------------------------------------------------------------------------------- GetFocus() 功能确定当前焦点位于哪个控件上。 语法GetFocus ( ) 返回值GraphicObject。函数执行成功时返回当前得到焦点控件的引用,发生错误时返回无效引用。用法应用程序利用IsValid()函数可以检测GetFocus()是否返回有效的控件引用。同时,使用TypeOf()函数可以确定控件的类型。 -------------------------------------------------------------------------------- Post() 功能将指定消息加入到某个窗口的消息队列中,这个窗口既可以是PowerBuilder应用的窗口,也可以是其它应用的窗口。 语法Post( handle, messageno, word, long ) 参数handle:long类型,指定窗口的系统句柄,将向该窗口邮寄消息messageno:UnsignedInteger类型,指定要邮寄的消息号 word:long类型,指定与消息一起邮寄的word类参数值。如果messageno参数指定的消息不使用该参数,那么将这个参数的值设置为0long:long类型或string,指定与消息一起邮寄的long型参数值或字符串返回值Boolean。如果任何参数的值为NULL,Post()函数返回NULL。 用法Post()函数用于向窗口发送非PowerBuilder预定义事件的消息,这个窗口可以是PowerBuilder应用的窗口,也可以是其它应用的窗口。Post()函数把发送的消息放置在指定窗口消息队列的尾部,然后返回到应用程序中,它并不等待相应事件事件处理程序的执行。这一点与Send()函数不同,Send()函数直接触发指定窗口相应的事件,执行事件处理程序后返回到调用应用中。因此,我们说Post()函数采用的是异步方式,Send()函数采用的是同步方式。Post()函数的参数handle指定接收消息的窗口句柄,对PowerBuilder窗口来说,使用Handle()函数可以得到该句柄。对其它应用程序的窗口来说,可以调用系统API函数查找窗口并得到相应窗口的句柄。如果应用程序要邮寄PowerBuilder定义事件(包括预定义事件和用户定义事件),那么使用PostEvent()函数既简单有方便。当应用程序在long参数位置指定一个字符串时,Post()函数复制一个该字符串的副本,然后将副本的地址传送给指定窗口。 -------------------------------------------------------------------------------- ProfileInt() 功能从初始化文件(.ini)中读取整型设置值。 语法ProfileInt ( filename, section, key, default ) 参数filename:string类型,指定初始化文件的名称,可以包括路径,省略路径时,该函数按操作系统的标准路径搜索指定文件section:string类型,指定要得到的值所在的节(Section)key:string类型,指定要得到的值的名称,不用区分大小写default:integer类型,当指定的文件、节名、项目名不存在或不能转换为整数时,函数返回该参数指定的值返回值Integer。函数执行成功时,在指定的文件、节名、项目名不存在任何错误的情况下,函数返回相应项的值;如果指定的文件、节名、项目名不存在或不能转换为整数时,函数返回default参数指定的缺省值。如果发生错误,函数返回-1。如果任何参数的值为NULL,ProfileInt()函数返回NULL。 -------------------------------------------------------------------------------- ProfileString() 功能从初始化文件(.ini)中读取字符串型设置值。 语法ProfileString ( filename, section, key, default ) 参数filename:string类型,指定初始化文件的名称,可以包括路径,省略路径时,该函数按操作系统的标准路径搜索指定文件section:string类型,指定要得到的值所在的节(Section)key:string类型,指定要得到的值的名称,不用区分大小写default:string类型,当指定的文件、节名、项目名不存在时,函数返回该参数指定的值返回值String。函数执行成功时,在指定的文件、节名、项目名不存在任何错误的情况下,函数返回相应项的值;如果指定的文件、节名、项目名不存在,函数返回default参数指定的缺省值。如果发生错误,函数返回空字符串。如果任何参数的值为NULL,ProfileString()函数返回NULL。 -------------------------------------------------------------------------------- Restart() 功能停止所有程序段的执行、关闭所有窗口、提交事务、断开与数据库的连接,然后重新启动应用程序。 语法Restart() 返回值Integer。函数执行成功时返回1,发生错误时返回-1。 -------------------------------------------------------------------------------- Run() 功能运行指定的应用程序。 语法Run ( string {, windowstate } ) 参数string:string类型,指定要运行的应用程序的名称,其中可以包括路径以及相应的参数,就像在命令行中键入的那样windowstate:WindowState枚举类型,可选项,指定程序运行时的窗口状态。有效取值为:Maximized! - 最大化窗口;Minimized! - 最小化窗口;Normal! - 缺省值,正常窗口返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,Run()函数返回NULL。 用法使用Run()函数,应用程序能够启动操作系统中的任何程序。当在Run()参数中指定了要启动应用程序的参数时,参数的意义、格式、个数等由具体的应用程序确定。如果在Run()函数的string参数中指定了文件名但没有给出扩展名时,PowerBuilder认为该文件的扩展名为.EXE。要运行扩展名不是.EXE的应用程序(比如.BAT, .COM, 或.PIF),必须在Run()函数的参数中指定文件的扩展名。 -------------------------------------------------------------------------------- Send() 功能向窗口发送指定的消息并立即执行相应的事件处理程序。 语法Send( handle, messageno, word, long ) 参数handle:long类型,指定窗口的系统句柄,将向该窗口发送消息messageno:UnsignedInteger类型,指定要发送的消息号word:long类型,指定与消息一起发送的word类参数值。如果messageno参数指定的消息不使用该参数,那么将这个参数的值设置为0long:long类型或string,指定与消息一起发送的long型参数值或字符串返回值Long。函数执行成功时返回Windows系统调用SendMessage()的返回值,发生错误时返回-1。如果任何参数的值为NULL,Send()函数返回NULL。 用法Send()函数用于向窗口发送非PowerBuilder预定义事件的消息,这个窗口可以是PowerBuilder应用的窗口,也可以是其它应用的窗口。Send()函数直接触发指定窗口相应的事件,执行事件处理程序后返回到调用应用中,这一点与Post()函数不同,Post()函数把发送的消息放置在指定窗口消息队列的尾部,然后返回到应用程序中,它并不等待相应事件事件处理程序的执行。因此,我们说Post()函数采用的是异步方式,Send()函数采用的是同步方式。Send()函数的参数handle指定接收消息的窗口句柄,对PowerBuilder窗口来说,使用Handle()函数可以得到该句柄。对其它应用程序的窗口来说,可以调用系统API函数查找窗口并得到相应窗口的句柄。实际上,Send()函数把它的各个参数直接传送给Windows的系统调用SendMessage()。在各种C++开发工具的WINDOWS.H文件中可以查到各消息编号。如果应用程序要发送PowerBuilder定义事件(包括预定义事件和用户定义事件),那么使用TriggerEvent()函数既简单有方便。当应用程序在long参数位置指定一个字符串时,Send()函数复制一个该字符串的副本,然后将副本的地址传送给指定窗口。 -------------------------------------------------------------------------------- SetProfileString() 功能设置初始化文件中指定项的值。 语法SetProfileString ( filename, section, key, value ) 参数filename:string类型,指定初始化文件的名称,可以包括路径,省略路径时,该函数按操作系统的标准路径搜索指定文件section:string类型,指定要设置的值所在的节(Section)key:string类型,指定要设置的值的名称,不用区分大小写default:string类型,指定要设置项的值返回值Integer。函数执行成功时返回1,指定的文件未找到或指定的文件不能访问时函数返回-1。如果任何参数的值为NULL,SetProfileString()函数返回NULL。 -------------------------------------------------------------------------------- ShowHelp() 功能显示应用程序帮助,该帮助使用Microsoft Windows帮助系统进行操作。 语法ShowHelp ( helpfile, helpcommand {, typeid } ) 参数helpfile:string类型,指定帮助文件的名称helpcommand:HelpCommand枚举类型,指定显示帮助的格式。有效取值为:Index! - 显示目录主题,使用该值时不要指定typeid参数;Keyword! - 转移到由指定关键字确定的主题;Topic! - 显示指定主题的帮助typeid:可选项,指定帮助主题返回值Integer。函数执行成功时返回1,发生错误时返回-1。如果任何参数的值为NULL,ShowHelp()函数返回NULL。 -------------------------------------------------------------------------------- SignalError() 功能触发应用对象的SystemError事件,通常用于代码调试。 语法SignalError ( { number }, { text } ) 参数number:integer类型,可选项,其值将保存到Error对象的number属性中text:string类型,可选项,其值将保存到Error对象的text属性中返回值Integer。函数执行成功时返回1,发生错误时返回-1。 -------------------------------------------------------------------------------- Yield() 功能将控制权转移给其它图形对象,包括非PowerBuilder对象。该函数检测消息队列,如果有消息,就把消息取出。利用该函数可以在执行耗时较长的操作时把控制权转让给其它应用。 语法Yield() 返回值Boolean。如果在消息队列中提取到了消息,那么函数返回TRUE,否则返回FALSE。用法正常情况下,PowerBuilder应用程序在执行一段代码(比如函数或事件处理程序)的过程中不响应用户的操作。对耗时短暂的代码段来说,这种处理方式没有什么不妥的地方,但是,如果某个代码段的执行耗时较长,应用程序又希望为用户提供更多的控制权,那么需要在这段代码中插入Yield()函数,让用户能够进行其它操作,特别在循环执行的代码中更应该如此。应用程序执行Fill() 功能建立一个由指定字符串填充的指定长度的字符串。 语法Fill ( chars, n ) 参数chars:string类型,指定用于重复填充的字符串n:long类型,指定由该函数返回的字符串的长度返回值String。函数执行成功时返回n个字符的字符串,该字符串以参数chars中的字符串重复填充而成。如果参数chars中的字符个数多于n个,那么使用chars字符串的前n个字符填充函数返回的字符串;如果参数chars中的字符个数少于n个,那么使用chars字符串反复填充,直到返回的字符串长度达到n为止。如果任何参数的值为NULL,Fill()函数返回NULL。 -------------------------------------------------------------------------------- Left() 功能得到字符串左部指定个数的字符。 语法Left ( string, n ) 参数string:string类型,指定要提取子串的字符串n:long类型,指定子串长度返回值String。函数执行成功时返回string字符串左边n个字符,发生错误时返回空字符串("")。如果任何参数的值为NULL,Left()函数返回NULL。如果n的值大于string字符串的长度,那么Left()函数返回整个string字符串,但并不增加其它字符。 -------------------------------------------------------------------------------- LeftTrim() 功能返回指定字符串删除了左部空格后的字符串。 语法LeftTrim ( string ) 参数string:string类型,指定要删除左部空格的字符串返回值String。函数执行成功时返回删除了string字符串左部空格的字符串,发生错误时返回空字符串("")。如果任何参数的值为NULL,LeftTrim()函数返回NULL。 -------------------------------------------------------------------------------- Len() 功能得到字符串的长度。 语法Len (string) 参数string:string类型变量返回值Long。函数执行成功时返回字符串的长度,发生错误时返回-1。如果任何参数的值为NULL,则Len()函数返回NULL。 -------------------------------------------------------------------------------- Lower() 功能将字符串中的大写字母转换为小写字母。 语法Lower ( string ) 参数string:要将其中的大写字母转换为小写字母的字符串返回值String。函数执行成功时返回将大写字母转换为小写字母后的字符串,发生错误时返回空字符串("")。如果string参数的值为NULL,Lower()函数返回NULL。 -------------------------------------------------------------------------------- Match() 功能确定字符串中是否包含指定模式的字符。 语法Match ( string, textpattern ) 参数string:string类型,指定要检查是否匹配指定模式的字符串textpattern:string类型,指定文本匹配模式返回值Boolean:如果字符串string与模式textpattern相匹配,则函数返回TRUE,否则返回FALSE。如果指定的匹配模式无效或上述两个参数中的任何一个未曾赋值,那么Match()函数返回FALSE。如果任何参数的值为NULL,Match()函数返回NULL。 用法textpattern参数的写法与正则表达式十分相似,它由元字符和普通字符组成。每个元字符都有不同的匹配含义,普通字符则与其自身相匹配。下面是匹配模式中使用的元字符及其意义: ^指示字符串的开始,例如,^asd表示以asd开头的字符串,字符串asdfgh与模式^asd匹配,而字符串basdfg与模式^asd不匹配。 $指示字符串的结束,例如,red$表示所有以red结束的字符串均与该模式匹配,而redo与模式red$不匹配。 .匹配任意单个字符,例如,^&&$匹配任何六个字符组成的字符串。 []匹配括号中列出的字符,例如,^[ABC]$匹配由一个字符组成的字符串,其值只能是A或B或C。 -与方括号一起,指定匹配字符的范围,例如,^[A-Z]$只匹配那些由一个大写字母组成的字符串。方括号里还可以使用^字符,表示匹配不在指定范围内的任何字符,例如,[^0-9]匹配除数字外的任何字符。 *,+,?这些符号跟在一个字符后面表示该字符可以出现的次数。星号(*)表示可以出现0次或任意次;加号(+)表示可以出现多次,但至少出现一次;问号(?)表示出现0次或一次。例如,A*匹配0个或多个A(没有A、A、AA、AAA、AAAA、**);A+匹配1个或多个A(A、AA、AAA、AAAA、**);A?匹配空串或1个A。 \斜杠(\)是转义字符,它去掉特殊字符的特殊含义,比如,模式\$匹配字符$,模式\\匹配字符\。 -------------------------------------------------------------------------------- Mid() 功能取字符串的子串。 语法Mid ( string, start {, length } ) 参数string:string类型,指定要从中提取子串的字符串start:long类型,指定子串第一个字符在string字符串中的位置,第一个位置为1length:long类型,可选项,指定子串的长度返回值String。函数执行成功时返回string字符串中从start位置开始、长度为length的子串。如果start参数的值大于string中字符个数,那么Mid()函数返回空字符串。如果省略了length参数或length参数的值大于从start开始、string字符串中余下字符的长度,那

2013-11-21

poweruiler入门到精通

第01章 认识PowerBuilder 9.0 第05章 创建应用程序 第06章 创建窗体 第07章 创建菜单和工具栏 第10章 应用程序的调试和发布 第11章 典型小型实例赏析 第12章 图书管理系统实例 第13章 学生选课系统实例 数据库文件 readme.txt 附录A 源代码的使用方法.doc

2013-11-21

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除