2011年9月27日
Java遍历Map
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
Java遍历Set
对 set 的遍历
1.迭代遍历:
Set<String> set = new HashSet<String>();
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
2.for循环遍历:
for (String str : set) {
System.out.println(str);
}
优点还体现在泛型 假如 set中存放的是Object
Set<Object> set = new HashSet<Object>();
for循环遍历:
for (Object obj: set) {
if(obj instanceof Integer){
int aa= (Integer)obj;
}else if(obj instanceof String){
String aa = (String)obj
}
........
}
当一个人找不到出路的时候,最好的办法就是将当前能做好的事情做到极致,做到无人能及。
今天在研究了一下关于ORACLE的导入导出的功能,周五快要下班的时候给同事新建一个表空间,将同一个数据库中的某个用户下的表导入新的表空间上,建好表空间和用户后,直接用 exp ,imp 来导入数据到新的表空间,查是发现后来导入的数据还在原来的表空间上,(周五那天的我是用工具编辑DMP文件,修改里的表空间名后导入的),后来想起来了eygle的书上写了关于这个的问题,于是今天就来试验了一下。
第一种:修改用户的一些权限。
首先使用sytem帐户登陆
--创建新表空间的用户
SQL> create user pangzi identified by pangzi default tablespace pangzi temporary tablespace temp;
用户已创建。
--授给新用户一般的权限
SQL> grant export full database to pangzi;
授权成功。
SQL> grant import full database to pangzi;
授权成功。
SQL> grant connect,resource to pangzi;
授权成功。
SQL> grant create procedure to pangzi;
授权成功。
SQL> grant create job to pangzi;
授权成功。
SQL> grant create view to pangzi;
授权成功。
SQL> grant create synonym to pangzi;
授权成功。
--从这里开始将是增加的,为了使导入的数据,不放在原来的表空间上
SQL> grant dba to pangzi;
--收回用户的umlimited tablespace权限
SQL> revoke unlimited tablespace from pangzi;
--设置新创建的用户可使用syb表空间的大小0(原数据所在的表空间为syb)
SQL> alter user pangzi quota 0 on syb;
--设置新创建的用户可使用pangzi表空间的大小不限制
SQL> alter user pangzi quota unlimited on pangzi;
--收回DBA权限
SQL> revoke dba from pangzi;
执行导入数据
C:\Users\dyspangzi>imp pangzi/pangzi@testdev file=syb.dmp full=y
Import: Release 10.2.0.3.0 - Production on 星期六 4月 21 17:48:54 2012
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
经由常规路径由 EXPORT:V10.02.01 创建的导出文件
警告: 这些对象由 SYB 导出, 而不是当前用户
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入
. 正在将 SYB 的对象导入到 PANGZI
. . 正在导入表 "ALL_SALES"导入了 360 行
. . 正在导入表 "COUPONS"导入了 6 行
. . 正在导入表 "CUSTOMERS"导入了 5 行
. .中间部分内容省略,都是导入的信息
. . 正在导入表 "REG_EXPS"导入了 1 行
. . 正在导入表 "SALARY_GRADES"导入了 4 行
即将启用约束条件...
成功终止导入, 没有出现警告。
导入成功,我们看导的表已经在新的表空间中了
SQL> show user
USER 为 "PANGZI"
SQL> select table_name,tablespace_name from user_tables;
TABLE_NAME TABLESPACE_NAME
------------------------------ ------------------------------
DYSPANGZI PANGZI
CUSTOMERS PANGZI
PRODUCT_TYPES PANGZI
PRODUCTS PANGZI
PURCHASES PANGZI
EMPLOYEES PANGZI
SALARY_GRADES PANGZI
PURCHASES_WITH_TIMESTAMP PANGZI
PURCHASES_TIMESTAMP_WITH_TZ PANGZI
PURCHASES_WITH_LOCAL_TZ PANGZI
COUPONS PANGZI
TABLE_NAME TABLESPACE_NAME
------------------------------ ------------------------------
PROMOTIONS PANGZI
ORDER_STATUS PANGZI
PRODUCT_CHANGES PANGZI
MORE_PRODUCTS PANGZI
MORE_EMPLOYEES PANGZI
DIVISIONS PANGZI
JOBS PANGZI
EMPLOYEES2 PANGZI
ALL_SALES PANGZI
PRODUCT_PRICE_AUDIT PANGZI
REG_EXPS PANGZI
已选择22行。
第二种:使用EXPDP和IMPDP来导入和导出
使用expdp来导出,首先要为一个参数来指定一个路径——directory,expdp是在服务器端工作,导出的文件需要放在本地目录,这个参数就是保存导出文件的位置。这个可以自己创建,也可以是默认的,我自己创建了一个,名字是expdir
SQL> CREATE OR REPLACE DIRECTORY expdir AS '/var/backup';
目录已创建。
SQL> select * from dba_directories;
OWNER DIRECTORY_NAME DIRECTORY_PATH
------------------- ------------------------------- -----------------------------------------
SYS ADMIN_DIR /ade/aime_10.2_lnx_push/oracle/md/admin
SYS DATA_PUMP_DIR /usr/app/oracle/product/10.2.0/db_1/rdbms/log/
SYS WORK_DIR /ade/aime_10.2_lnx_push/oracle/work
SYS EXPDIR /var/backup
--给用户授予读写权限
SQL> grant read,write on directory expdir to syb;
开始导出数据
[oracle@dyspangzi ~]$ expdp dumpfile=syb.dmp directory=expdir;
Export: Release 10.2.0.1.0 - Production on Saturday, 21 April, 2012 18:06:46
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Starting "SYB"."SYS_EXPORT_SCHEMA_01": dumpfile=syb.dmp directory=expdir
Estimate in progress using BLOCKS method...
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 1.375 MB
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/COMMENT
Processing object type SCHEMA_EXPORT/PACKAGE/PACKAGE_SPEC
Processing object type SCHEMA_EXPORT/FUNCTION/FUNCTION
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PACKAGE/COMPILE_PACKAGE/PACKAGE_SPEC/ALTER_PACKAGE_SPEC
Processing object type SCHEMA_EXPORT/FUNCTION/ALTER_FUNCTION
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
Processing object type SCHEMA_EXPORT/PACKAGE/PACKAGE_BODY
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/REF_CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/TRIGGER
. . exported "SYB"."DYSPANGZI" 48.50 KB 659 rows
. . exported "SYB"."ALL_SALES" 13.68 KB 360 rows
中间导出信息省略
. . exported "SYB"."REG_EXPS" 5.437 KB 1 rows
. . exported "SYB"."SALARY_GRADES" 5.710 KB 4 rows
. . exported "SYB"."PRODUCT_PRICE_AUDIT" 0 KB 0 rows
Master table "SYB"."SYS_EXPORT_SCHEMA_01" successfully loaded/unloaded
******************************************************************************
Dump file set for SYB.SYS_EXPORT_SCHEMA_01 is:
/var/backup/syb.dmp
Job "SYB"."SYS_EXPORT_SCHEMA_01" successfully completed at 18:07:11
导出成功后查看一下刚才创建目录里边的内容
[root@dyspangzi var]# cd backup
[root@dyspangzi backup]# ls -l
总计 720
-rw-r--r-- 1 oracle oinstall 3472 04-21 18:07 export.log
-rw-r----- 1 oracle oinstall 729088 04-21 18:07 syb.dmp
多了两个文件,一个是日志文件一个是导出的数据文件,在导入的时候需要这两个文件。下面开始导入。
===================================================================================
出现了第一个错误
[oracle@dyspangzi ~]$ impdp pangzi/pangzi dumpfile=syb.dmp directory=expdir remap_tablespace=syb:pangzi
Import: Release 10.2.0.1.0 - Production on Saturday, 21 April, 2012 18:45:35
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-39087: directory name EXPDIR is invalid
出现了错误,后来发现这个是因为新用户pangzi没有对目录的读写权限造成的,于是加上权限
SQL> grant read,write on directory expdir to pangzi;
授权成功。
==================================================================================
出现了第二个错误
[oracle@dyspangzi ~]$ impdp pangzi/pangzi dumpfile=syb.dmp directory=expdir remap_tablespace=syb:pangzi
Import: Release 10.2.0.1.0 - Production on Saturday, 21 April, 2012 18:47:38
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
ORA-31655: no data or metadata objects selected for job
ORA-39154: Objects from foreign schemas have been removed from import
Master table "PANGZI"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "PANGZI"."SYS_IMPORT_FULL_01": pangzi/******** dumpfile=syb.dmp directory=expdir remap_tablespace=syb:pangzi
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Job "PANGZI"."SYS_IMPORT_FULL_01" successfully completed at 18:47:41
这个是由于原来的用户和现在的不一样了,加上这个参数就好了 remap_schema=syb:pangzi
=====================================================================================================
下面是没有任何错误的导入了
[oracle@dyspangzi ~]$ impdp pangzi/pangzi dumpfile=syb.dmp directory=expdir remap_schema=syb:pangzi remap_tablespace=syb:pangzi
Import: Release 10.2.0.1.0 - Production on Saturday, 21 April, 2012 18:49:24
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Master table "PANGZI"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "PANGZI"."SYS_IMPORT_FULL_01": pangzi/******** dumpfile=syb.dmp directory=expdir remap_schema=syb:pangzi remap_tablespace=syb:pangzi
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
. . imported "PANGZI"."DYSPANGZI" 48.50 KB 659 rows
. . imported "PANGZI"."ALL_SALES" 13.68 KB 360 rows
中间部分导入信息省略
. . imported "PANGZI"."PURCHASES_WITH_TIMESTAMP" 5.609 KB 1 rows
. . imported "PANGZI"."REG_EXPS" 5.437 KB 1 rows
. . imported "PANGZI"."SALARY_GRADES" 5.710 KB 4 rows
. . imported "PANGZI"."PRODUCT_PRICE_AUDIT" 0 KB 0 rows
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/PACKAGE/PACKAGE_SPEC
Processing object type SCHEMA_EXPORT/FUNCTION/FUNCTION
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PACKAGE/COMPILE_PACKAGE/PACKAGE_SPEC/ALTER_PACKAGE_SPEC
Processing object type SCHEMA_EXPORT/FUNCTION/ALTER_FUNCTION
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
Processing object type SCHEMA_EXPORT/PACKAGE/PACKAGE_BODY
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/REF_CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/TRIGGER
Job "PANGZI"."SYS_IMPORT_FULL_01" successfully completed at 18:49:37
成功导入!!!!
查看默认的表空间
SQL> select table_name,tablespace_name from user_tables;
TABLE_NAME TABLESPACE_NAME
------------------------------ ------------------------------
DYSPANGZI PANGZI
CUSTOMERS PANGZI
PRODUCT_TYPES PANGZI
PRODUCTS PANGZI
PURCHASES PANGZI
EMPLOYEES PANGZI
SALARY_GRADES PANGZI
PURCHASES_WITH_TIMESTAMP PANGZI
PURCHASES_TIMESTAMP_WITH_TZ PANGZI
PURCHASES_WITH_LOCAL_TZ PANGZI
COUPONS PANGZI
TABLE_NAME TABLESPACE_NAME
------------------------------ ------------------------------
PROMOTIONS PANGZI
ORDER_STATUS PANGZI
PRODUCT_CHANGES PANGZI
MORE_PRODUCTS PANGZI
MORE_EMPLOYEES PANGZI
DIVISIONS PANGZI
JOBS PANGZI
EMPLOYEES2 PANGZI
ALL_SALES PANGZI
PRODUCT_PRICE_AUDIT PANGZI
REG_EXPS PANGZI
已选择22行。
此表空间中没有索引,所以第一种方法也没有报错,如果出现有索引的第一种方法还得增加几步,等我明天找到周五那个数据再来再着做试验。
-----------------------------------------------------------
今天特意去公司找来了那天导的数据库,回来做实验。采用第一种方法不可行,虽然说可以使用IMP 加indexs参数来导出一些索引,但是导入的时候总有莫名其妙的错误,估计还是我没弄好,所以为了省事还是直接用第二种吧,方便,无错。
1.在Oracle中可以用下面两种:
01:
create table newtable as select * from oldtable;//用于复制前未创建新表newtable不存在的情况
02:
insert into newtable select * from oldtable;//已经创建了新表newtable 的情况
注意:第一种方式只是复制了表结构,但是主键什么的并没有复制进去,所以用的时候要小心在意。
2.如果想简单快速的复制表结构,而不需要oldtable里面的数据,可以用下面的语句:
create table newtable as select * from oldtable where 1=2;(把数据过滤掉)
3.如过newtable 和oldtable的表结构不同,可以使用下面的方式:
create table newtable as select s.c1,s.c2 from oldtable s;
4.如果想重新命名newtable的列名:
在oracle中:
create table newtable(id,name1) as select s.c1,s.c2 from oldtable s;
或者
create table newtable as select s.c1 ,s.c2 from oldtable s;
在mysql中恐怕只能用第二种方式了。
5.如果是只需要把一部分的oldtable中的数据添加到newtable中。可以这样:
create table newtable as (select * from oldtable where ...);//加where过滤条件
6.最常见的情况是id列新表中要用,并且和旧表中的不同,使用下面的语句就可以了(我们可以重新建一个sequence)
create table yang(id,name) as select hibernate_sequence.nextval,t.ename from emp t;
7.要注意,导出表的时候不能用select...into语句。
方法1:在shell中执行LANG=en 将语言设为英语就可以了.SSH下很多中文都不支持.
方法2:
在使用ssh远程控制redhat服务器时,中文显示为乱码。这个问题困扰了好久,后来发现修改i18n这个文件能够修正乱码。
方法如下:修改/etc/sysconfig/i18n文件,将其改成以下内容:
LANG="zh_CN.GB18030"
LANGUAGE="zh_CN.GB18030:zh_CN.GB2312:zh_CN"
SUPPORTED="zh_CN.UTF-8:zh_CN:zh:en_US.UTF-8:en_US:en"
SYSFONT="lat0-sun16"
重启机器,问题应该解决了。
方法3:
如果你用的是putty ,你只要在字符编码里选择utf-8就正常了
补充:这样做的后果是,在linux启动时,那些提示文字中文都变成了“?”符号。如果不习惯的话将ssh显示端改成英文吧。如下:
LANG=en_US
一、java实现DES加密算法为了实现一对密钥对整个项目所有加密解密文件都适用的方法,采用先生成一对密钥.保存到xml文件中,以后获得私匙和公钥只需要从xml文件中取得就可以了./*** 把成生的一对密钥保存到DesKey.xml文件中*/public static void saveDesKey(){ try { SecureRandom sr = new SecureRandom(); //为我们选择的DES算法生成一个KeyGenerator对象 KeyGenerator kg = KeyGenerator.getInstance ("DES" ); kg.init (sr); FileOutputStream fos = new FileOutputStream("C:/DesKey.xml"); ObjectOutputStream oos = new ObjectOutputStream(fos); //生成密钥 Key key = kg.generateKey(); oos.writeObject(key); oos.close(); } catch (Exception e) { e.printStackTrace(); }}获取密钥方法如下:
/*** 获得DES加密的密钥。在交易处理的过程中应该定时更* 换密钥。需要JCE的支持,如果jdk版本低于1.4,则需要* 安装jce-1_2_2才能正常使用。* @return Key 返回对称密钥*/ public static Key getKey() { Key kp = null; try { String fileName = "conf/DesKey.xml"; InputStream is = DesUtil.class.getClassLoader() .getResourceAsStream(fileName); ObjectInputStream oos = new ObjectInputStream(is); kp = (Key) oos.readObject(); oos.close(); } catch (Exception e) { e.printStackTrace(); } return kp; }文件采用DES算法加密文件
/**
* 文件file进行加密并保存目标文件destFile中
* @param file
* 要加密的文件 如c:/test/srcFile.txt
* @param destFile
* 加密后存放的文件名 如c:/加密后文件.txt
*/
public static void encrypt(String file, String destFile) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, getKey());
InputStream is = new FileInputStream(file);
OutputStream out = new FileOutputStream(dest);
CipherInputStream cis = new CipherInputStream(is, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = cis.read(buffer)) > 0) {
out.write(buffer, 0, r);
}
cis.close();
is.close();
out.close();
}文件采用DES算法解密文件
/**
* 文件file进行加密并保存目标文件destFile中
* @param file
* 已加密的文件 如c:/加密后文件.txt
* @param destFile
* 解密后存放的文件名 如c:/ test/解密后文件.txt
*/
public static void decrypt(String file, String dest) throws Exception { Cipher cipher = Cipher.getInstance("DES"); cipher.init(Cipher.DECRYPT_MODE, getKey()); InputStream is = new FileInputStream(file); OutputStream out = new FileOutputStream(dest); CipherOutputStream cos = new CipherOutputStream(out, cipher); byte[] buffer = new byte[1024]; int r; while ((r = is.read(buffer)) >= 0) { cos.write(buffer, 0, r); } cos.close(); out.close(); is.close(); }
1、查看操作系统版本和内核版本#uname –a
#more /etc/redhat-release
2、创建相关目录/usr/src/redhat/SOURCES //存放源代码,补丁,图标等文件。
/usr/src/redhat/SPECS //存放用于管理rpm制作进程的spec文件。
/usr/src/redhat/BUILD //解压后的文件存放在这里。
/usr/src/redhat/RPMS //存放由rpmbuild制作好的二进制包。
/usr/src/redhat/SRPMS //存放由rpmbuild制作好的源码包。
#mkdir -p /usr/src/redhat/
#cd /usr/src/redhat/
#mkdir SOURCES SPECS BUILD RPMS SRPMS
3、下载Nginx源码包下载源码包到SOURCES目录,不需要解压
#wget http://nginx.org/download/nginx-1.3.9.tar.gz
4、手工创建SPEC文件由于spec文件是由spec语言编写的,请注意spec语言的语法。
#cd /usr/src/redhat/SPECS/
#cat < nginx.spec > EOC
Summary: High Performance Web Server Name: nginx Version: 1.3.9 Release: el5 License: GPL Group: Applications/Server Source: http://nginx.org/download/nginx-1.3.9.tar.gz URL: http://nginx.org/ Distribution: Linux Packager: JingSheng <jingsheng1@staff.sina.com.cn> %description nginx [engine x] is a HTTP and reverse proxy server %prep useradd nginx -s /sbin/nologin rm -rf $RPM_BUILD_DIR/nginx-1.3.9 zcat $RPM_SOURCE_DIR/nginx-1.3.9.tar.gz | tar -xvf - %build cd $RPM_BUILD_DIR/nginx-1.3.9 ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx/ --with-http_stub_status_module --with-http_ssl_module make %install cd $RPM_BUILD_DIR/nginx-1.3.9 make install %preun if [ -z "`ps aux | grep nginx | grep -v grep`" ];then killall nginx >/dev/null exit 0 fi %files /usr/local/nginx |
#:以#开头是注释,rpm会忽略它。
Summary:简单描述软件。
Name :定义rpm的名称。
Version: 定义软件版本
Release: 发行版本
License: 定义许可证
Group: 软件分类
Source: 源码下载地址
URL: 源码相关网站
Distribution: 发行版系列
Packager: 打包人的信息
scription:软件详细描述,可多行
%prep :软件编译之前的处理,如解压。
%build :开始编译软件,如make
%install :开始安装软件,如make install
%files :指定哪些文件需要被打包,如/usr/local/nginx
%preun :定义卸载之前的动作,如杀掉进程。
5、开始RPM制作在制作RPM包之前,需要安装必要的编译工具
#yum install -y gcc rpm-build pcre-devel
开始编译生成rpm包
# rpmbuild-bb nginx.spec
注意:如果安装生成报错,请将安装过的东东全部去除,再重新打包
# rpm –qpl *.rpm 查看rpm包含哪些
最近一直在折腾linux,centos、redhat装了又装,到最后还是装了redhat。
以前多少接触过linux,但是都不深入(这次虽然也是皮毛,但是稍微知道了一些东东,现在就卖了),这次从零开始自己折腾linux,确实是被linux折腾了。linux跟windows确实有很多不同,有机会再继续介绍,这次先说一下使用Xmanager远程连接Redhat的经历。
Xmanager不多说了,是一款非常不错的管理工具。但是,如果要让Xmanager远程连接redhat,其实远程连接,主要还是想要做成跟windows的远程桌面一样的东西,图形界面方便啦!
只是这次配置Xmanager相当痛苦,按照网上各种资料对redhat进行配置,然后不停的reboot,但是,xmanager总是连不上。
这其中,修改的文件包括:
/usr/share/gdm/defaults.conf这个gdm的配置文件,主要是以下内容:
Enable=true
DisplaysPerHost=10
Port=177
还有/etc/inittab文件,主要是首先默认级别为5,这个文件貌似在安装的时候就已经默认为5了。id:5:initdefault:
然后最后一行的“x:5:respawn:/etc/X11/prefdm -nodaemon”调整为:
x:5:respawn:/usr/sbin/gdm
当然,还得改!
依然是/usr/share/gdm/defaults.conf,在[security]中调整以下的值:
AllowRoot=true
AllowRemoteRoot=true
AllowRemoteAutoLogin=true
如果开着防火墙,那还是要放开177端口,我暂时把防火墙关了。
reboot!reboot总是很重要的!
如果上述调整完成之后,依然无法连接,我就是这样的情况,连接不上啊!!!!
又随便找了几篇文章,也许跟hosts文件有关系哦!
打开/etc/hosts文件一看,空的!!!
在其中加上127.0.0.1 localhost,reboot,我总是喜欢reboot,这样比较干净!比较彻底!
在Xstart中配置好相应的参数,一定要在Commond中选择“GNOME”,这样再Run,Xbrowser将久违的redhat桌面打开了!
今天开发的同事,和我说
SecureCRT连接到IDC服务器,老超时断开,影响工作了
研究了下。
因为客户端与服务器之间存在路由器,防火墙以及为了本身的安全性,在超过特定的时间后就会把空闲连接断开。或者是服务器端设置了断开空闲连接。
解决方法:
既然会断开超时的空闲连接,那么我们就应该让客户端与服务器之间的连接“忙”起来,方法有两个:
从服务器方面入手:
修改/etc/ssh/sshd_config配置文件 ClientAliveInterval 300(默认为0)
这个参数的是意思是每5分钟,服务器向客户端发一个消息,用于保持连接
service sshd reload 生效
从客户端入手:
上面是配置需要服务器权限,如果没有服务器权限则可以使用这个方法,其思想是:客户端向服务器发一个消息,用于保持连接
secureCRT在选项 终端 反空闲 中设置每隔多少秒发送一个字符串,或者是NO-OP协议包
putty:putty -> Connection -> Seconds between keepalives ( 0 to turn off ), 默认为0, 改为300
CentOS 5远程SSH连接超时设定
操作系统:CentOS 5.6 SSH版本:OpenSSH_4.3p2
网上很多文章都说,远程SSH连接的超时设定是在/etc/ssh/sshd_config里,使用ClientAliveInterval和ClientAliveCountMax选项,我原来也这么认为的,不过一直没配置过超时。
今天配置了一下,发现这个是不对的,正确的配置是在/etc/profile里,使用TMOUT选项进行控制,如TMOUT=300,设定超时间隔为300秒。
远程桌面服务使局域网 (LAN) 上的计算机可以连接到服务器(也称为远程计算机)并运行位于服务器上的程序。这可以只需要在1台机器上安装应用程序,其他机器共享使用。远程桌面连接使用远程桌面服务技术,使一台计算机可远程控制另一台计算机。
windows 远程终端服务是单用户的,也就是说通过远程登录到服务器时,服务器本地将黑屏。如何做到不管用本地登录还是远程登录,同一时刻容许多个用户操作服务器计算机。
首先:
要安装工具包,需要从微软下载(远程服务器管理工具 http://www.microsoft.com/downloads/zh-cn/details.aspx?displaylang=zh-cn&FamilyID=7d2f6ad7-656b-4313-a005-4e344e43997d ),安装升级包后,在控制面板--程序和功能--打开或关闭WINDOWS功能---远程服务器管理工具--角色管理工具--远程桌面服务工具,选中前面的选择框。
在开始--命令框输入cmd,在弹出的Dos界面输入netstat -na ,如果出现 3389 端口,就说明远程终端已经启动了。
然后:
1, 下载 补丁UniversalTermsrvPatch,功能就是去除单用户登陆的限制,允许多人多用户同时并行访问登录。
2, 根据你的系统运行对应的程序:
32位系统请运行 UniversalTermsrvPatch-x86.exe;
64位系统请运行 UniversalTermsrvPatch-x64.exe。
3, 需要管理员权限。右键点程序,选择以管理员身份运行。
4, 破解后需要重启生效。
5, 备份文件: \windows\system32\termsrv.dll.backup.(如果想还原设置 请将备份文件改名为termsrv.dll替换破解的文件即可)
远程桌面的其它可能的设置:
运行gpedit.msc打开组策略,计算机配置-管理模板-Windows组件-远程桌面服务-远程桌面会话主机-连接-“限制连接数量”,如果将状态设置为“禁用”或“未配置”,则在“组策略”级别上不强制限制连接的数量。
在Windows 2003系统上的远程桌面实际上就是终端服务,虽然远程桌面最初在Windows XP上就已经存在,但由于Windows XP的远程桌面功能,只能提供一个用户使用计算机,因此使用率并不高。而Windows 2003提供的远程桌面功能则可供多用户同时使用,在其上可以运行程序、保存文件和使用网络资源,在很多方面可以像使用终端一样,并且在管理及配置方面比原来的终端服务更方便。要更好地发挥远程桌面的作用就要对远程桌面进行相应的配置。 www.2cto.com
组策略编译器(gpedit.msc)配置
使用组策略编译器配置用户远程连接数以及用户会话数,
1,“开始”—>“运行”输入gpedit.msc回车打开组策略编译器->“计算机配置”->“管理模板”->“
windows组件”->“终端服务”,右侧鼠标右键选择“限制连接数”打开属性,选择“设置”—>选择“已启用”, “TS 允许的最大连接数”填写你所需要的数量,例如:20。确定完成最大连接数限制设置。双击“会话”->选择“为断开的会话设置时间限制”右键选择属性-》“设置”->xuanze选择“已启用”-》“结束断开连接会话”填写合适的时间,五分钟为好。
终端服务配置(Tscc.msc)的使用
使用终端服务配置可以更改本地计算机上该连接的属性、添加新连接或设置服务器。打开“控制面板”—〉“管理工具”,单击“终端服务器配置”启动终端服务配置窗口。
1 单击左边窗口的“连接”项,右边窗口即出现可选的RDP-TCP连接,右击“RDP-TCP”,选“属性”出现RDP-Tcp属性对话框,主要配置有:
(1)连接数设置:可在“网卡”选项中更改。设置更多地连接数可使更多的用户同时登录服务器。默认最多同时两个用户连接,如果想要使3个以上的用户同时使用远程桌面功能,则必须安装终端服务,安装后就可以任意设定用户数制。 www.2cto.com
安装终端服务可通过Windows的“添加/删除程序”—〉“添加/删除Windows组件”中,选中“终端服务器”来添加,根据需要完成相应配置,完成终端服务安装,重启机器生效。
由于每个用户连接远程桌面后最小占用12MB左右的内存,因此可根据服务器内存大小来设定用户数,一般用户数不要太多,以免影响性能。如256MB内存可设定用户数8个左右,512MB内存可设定20~30个。
(2)调整颜色分辨率(颜色深度):在“客户端设置”项中。限制颜色深度可以增强连接性能,尤其是对于慢速链接,并且还可以减轻服务器负载。“远程桌面”连接的当前默认最大颜色深度设置为 16 位。
选中“颜色深度最大值”,可修改限定的最大颜色深度为8、15、16或24位。若不选中,则使用登录的客户端颜色设置。
(3)让客户自动登录:在“登录设置”选项卡上。这对普通应用非常方便,可加快登录速度,提高服务效率。
要使用自动登录,需选中“总是使用下列登录信息”,在“用户名”中,键入允许自动登录到服务器的用户的名称,在“密码”和“确认密码”中,键入该用户的密码。 这样客户端连接时将不用再输入用户名和密码,而自动进入Windows 2003桌面(注意:若此后再有用户登录,那么原来的连接将被断开)。若输入不完整,则登录时还会要求输入用户名或密码。
如要想更安全的使用服务器,则应选中“总是提示密码”以指定该用户在登录到服务器之前始终要被提示输入密码,从而限制客户端的自动登录。
(4)对连接自动限制管理:单击“会话”项来设定。主要用来设定超时的限制,以便释放会话所占用的资源,“结束已断开的会话”和“空闲会话限制”的时间,一般应用设为5分钟较好。对安全性要求高的也可设定“活动会话限制”的时间。“达到会话限制或者连接被中断时”下的选项,最好选“结束会话”,这样连接所占的资源就会被释放。
(5)设置加密级别:单击“常规”项,可指定在终端服务会话期间,对于客户端与远程计算机之间发送的所有数据是否强制加密级别。分四个级别:符合 FIPS(最高级别的加密)、高(加密数据经过强 128 位加密。)、客户端兼容(加密数据经过客户端支持的最大密钥强度加密)和低(从服务器发送到客户端的数据将不会被加密)。
(6)启用终端客户音频:在“客户端设置”项下边,默认为禁用,以节约服务器资源。当用户少时 ,单击“音频映射”去掉被禁用的选项,使终端客户能使用多媒体设备。当然,客户端计算机也必须装有声卡。 www.2cto.com
如果有多个用户连接到相同的服务器,则会以同一个用户名登录。
(7)启用驱动器映射;此项可方便终端与服务器磁盘间文件的相互传送。启用后本地驱动器将作为网络驱动器显示在终端中。
同样还有打印机、剪贴板、com端口等也可设置映射。但每设置一个都要占用一定的系统资源;所以,一般用户最好禁用。
(8)服务器的安全设置:在“权限”项,可选择组或用户,限制其对终端的配置权限。另外,由于只有Administrators 和 Remote Desktop Users 组的成员可以使用终端服务连接与远程计算机连接,所以可对不同用户分组管理,对于要求安全性高的,可利用NTFS分区设置不同用户的权限。
“服务器设置”—》“限制每个用户使用一个会话”右键选择属性,去除“限制每个用户使用一个会话”的勾选,确认完成设置。
整个多用户的远程连接设置到此结束。
在远程管理方面,Windows Server 2003系统一个最明显的进步就是增加了“远程桌面”功能。这样一来,从Windows 2000保留下来的终端服务似乎就显得有点多余了。然而情况并不是这样,因为在不安装“终端服务器”的前提下,“远程桌面”功能的可管理性比较有限。搭建终端服务器以后,对Windows 2000 Server和Windows Server 2003系统的远程管理操作将更加灵活。
在Windows Server 2003(SP1)中默认没有安装终端服务器组件,用户需要手动添加该组件。安装终端服务组件的步骤如下所述:
步骤/方法
第1步,在开始菜单中依次单击“控制面板”→“添加或删除程序”菜单项,打开“添加或删除程序”窗口。然后单击“添加/删除Windows组件”按钮,打开“Windows组件向导”对话框。在“组件”列表中选中“终端服务器”复选框,如图2008112107所示。
图2008112107 选中“终端服务器”复选框
第2步,打开“配置警告”对话框,提示用户关于IE安全配置方面的信息。因为配置终端服务器的目的主要是为了远程管理Windows Server 2003服务器,对于浏览Internet方面的要求并不高,因此直接单击“是”按钮。返回“Windows组件”对话框,选中“终端服务器授权”复选框,并单击“下一步”→“下一步”按钮即可,如图2008112108所示。
图2008112108 “配置警告”对话框
第3步,在打开的为应用程序兼容性选择默认权限对话框中列出两种安装模式,即“完整安全模式”和“宽松安全模式”。选择不同的模式会应用到Windows Server 2003系统的不同安全级别。选中“完整安全模式”单选框,并单击“下一步”按钮,如图2008112109所示。
图2008112109 选中“完整安全模式”单选框
第4步,打开指定终端服务器许可证服务器对话框,提示用户该终端服务器必须在120天内与Windows Server 2003终端服务器许可证服务器连接才能保证正常使用。由于在“Windows组件”对话框中选中了“终端服务器授权”复选框,则意味着这台Windows Server 2003终端服务器将同时作为许可证服务器。因此选中“使用下列许可证服务器”单选框,并在编辑框中输入这台服务器的名称或IP地址。设置完毕单击“下一步”按钮,如图2008112110所示。
图2008112110 输入许可证服务器IP地址
第5步,在打开的终端服务器授权模式对话框中,要求用户指定这台终端服务器使用的授权模式。选中“每设备授权模式”单选框,并单击“下一步”按钮,如图2008112111所示。
图200811211 选中“每设备授权模式”单选框
第6步,打开“终端服务器授权安装程序”对话框,要求用户选择安装许可证服务器数据库的路径。一般可以保持默认路径,并单击“下一步”按钮,如图2008112112所示。
图2008112112 选择许可证服务器数据库路径
第7步,Windows组件向导开始安装终端服务器和终端服务器授权组件,在安装过程中要求提供Windows Server 2003(SP1)系统的安装光盘或指定安装程序路径。完成安装后单击“完成”按钮关闭Windows组件向导,并按照提示重新启动计算机。
package com;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAX解析XML,事件驱动
* 只有两种节点
* Element Node元素节点
* Text Node文本节点
*/
public class SaxResolveXML {
public static void main(String[] args){
try {
SaxResolveXML saxResolveXML = new SaxResolveXML();
InputStream inStream = new FileInputStream("D:\\xml.xml");
List<Person> list = saxResolveXML.getList(inStream);
for(Person person : list){
System.out.println(person.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public List<Person> getList(InputStream inStream) throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parse = factory.newSAXParser();
SaxResolve saxResolve = new SaxResolve();
parse.parse(inStream, saxResolve);
inStream.close();
return saxResolve.getPerson();
}
private final class SaxResolve extends DefaultHandler {
private List<Person> list = null;
private Person person = null;
private String tag = null;
public List<Person> getPerson(){
return list;
}
//开始文档事件
public void startDocument() throws SAXException {
//初始化
list = new ArrayList<Person>();
}
//开始元素语法事件 参数说明:命名空间、不带命名空间的标签名、含有命名空间前缀的标签名、属性
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
if("person".equals(qName)){
person = new Person();
person.setId(Integer.parseInt(atts.getValue(0)));
}
tag = qName;
}
//触发文本节点事件 参数说明:整个xml内容的字符串、当前读到文本类型的开始位置、当前读到文本的数据长度
public void characters(char[] ch, int start, int length)
throws SAXException {
if(tag != null){
String data = new String(ch, start, length);
if(tag.equals("name")){
person.setName(data);
}else if(tag.equals("age")){
person.setAge(Integer.parseInt(data));
}
}
}
//结束元素语法事件 参数说明:命名空间、不带命名空间的标签名、含有命名空间前缀的标签名
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("person".equals(qName)){
list.add(person);
person = null;
//对象设为空
}
tag = null;
}
}
/*//开始文档事件
public void startDocument() throws SAXException {
}
//开始元素语法事件 参数说明:命名空间、不带命名空间的标签名、含有命名空间前缀的标签名、属性
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
}
//触发文本节点事件 参数说明:整个xml内容的字符串、当前读到文本类型的开始位置、当前读到文本的数据长度
public void characters(char[] ch, int start, int length)
throws SAXException {
}
//结束元素语法事件 参数说明:命名空间、不带命名空间的标签名、含有命名空间前缀的标签名
public void endElement(String uri, String localName, String qName)
throws SAXException {
}
public void endDocument() throws SAXException {
}
public void endPrefixMapping(String prefix) throws SAXException {
}
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
}
public void processingInstruction(String target, String data)
throws SAXException {
}
public void setDocumentLocator(Locator locator) {
}
public void skippedEntity(String name) throws SAXException {
}
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
}*/
}
xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id="1">
<name>liming</name>
<age>23</age>
</person>
<person id="2">
<name>lixiangmei</name>
<age>24</age>
</person>
</persons>
export LD_LIBRARY_PATH=/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/runtime/glnx86:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/os/glnx86:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/java/jre/glnx86/jre/lib/i386/native_threads:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/java/jre/glnx86/jre/lib/i386/server:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/java/jre/glnx86/jre/lib/i386
export XAPPLRESDIR=/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/X11/app-defaults
把以上两行加入系统的环境变量里面:具体操作如下:
vi /etc/profile
按 i 就可以编辑这个文件,开始复制
把上面两行拷贝到这个文件的最下面然后保存就可以了!
保存退出时先按一下“ESC”,然后再按“:wq”就可以保存退出了!
/**
* 从数据库中查询IRI和KLO模型的数据,并下载到本地
* @param dataTime 时次
* @param outIRIFilePath IRI文件下载到本地的路径
* @param outKLOFilePath KLO文件下载到本地的路径
* @param outAnaFilePath 插值文件下载到本地的路径
*/
@SuppressWarnings("static-access")
public static void selectBlogInfo(String dataTime, String outIRIFilePath, String outKLOFilePath, String outAnaFilePath) {
try {
Connection con = DBConnectionManager.getInstance().getConnection();
Statement st = con.createStatement();
String sql = "select * from MODELTEC where DATATIME=to_date('"+dataTime+"', 'YYYY-mm-dd HH24')";
ResultSet rs = st.executeQuery(sql);
if (rs.next()) {
Blob blod = rs.getBlob("IRIDATA");
InputStream reader = blod.getBinaryStream();
dataTime = dataTime.replaceAll("-", "");
dataTime = dataTime.replaceAll(" ", "");
String iriFilePath = outIRIFilePath+"\\"+dataTime+"0000.iri.grd";
File file = new File(iriFilePath);
OutputStream writer;
writer = new BufferedOutputStream(new FileOutputStream(file));
byte buf[] = new byte[1024];
for (int i = 0; (i = reader.read(buf)) > 0;) {
writer.write(buf, 0, i);
}
writer.close();
reader.close();
blod = rs.getBlob("IRIDATA");
reader = blod.getBinaryStream();
String kloFilePath = outKLOFilePath+"\\"+dataTime+"0000.klo.grd";
file = new File(kloFilePath);
writer = new BufferedOutputStream(new FileOutputStream(file));
buf = new byte[1024];
for (int i = 0; (i = reader.read(buf)) > 0;) {
writer.write(buf, 0, i);
}
writer.close();
reader.close();
blod = rs.getBlob("ANADATA");
reader = blod.getBinaryStream();
String anaFilePath = outAnaFilePath+"\\"+dataTime+"0000.grd";
file = new File(anaFilePath);
writer = new BufferedOutputStream(new FileOutputStream(file));
buf = new byte[1024];
for (int i = 0; (i = reader.read(buf)) > 0;) {
writer.write(buf, 0, i);
}
writer.close();
reader.close();
}
DBConnectionManager.closeConnection();
if(con!=null){con.close();}
if(st!=null){st.close();}
if(rs!=null){rs.close();}
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 把IRI和KLO模型的文件上传到数据库中
* @param dataTime 时次
* @param iriFilePath 要上传IRI文件的绝对路径
* @param kloFilePath 要上传KLO文件的据对路径
* @param ANAFilePath 要上传插值文件的据对路径
*/
@SuppressWarnings("static-access")
public static void insertBlogInfo(String dataTime, String IRIFilePath, String KLOFilePath, String ANAFilePath) {
try {
Connection con = DBConnectionManager.getInstance().getConnection();
// 处理事务
boolean defaultCommit;
defaultCommit = con.getAutoCommit();
con.setAutoCommit(false);
Statement st = con.createStatement();
String sql = "select * from MODELTEC where DATATIME=to_date('"+dataTime+"', 'YYYY-mm-dd HH24')";
ResultSet rs = st.executeQuery(sql);
if(rs.next()){
System.out.println(dataTime+"时次已经入库!");
return ;
}
// 插入一个空对象
sql = "insert into MODELTEC(ID, DATATIME, IRIDATA, KLODATA, ANADATA) values(" +
"SEQU_MODEL_ID.nextval, " +
"to_date('"+dataTime+"','YYYY-mm-dd HH24'), " +
"empty_blob(), " +
"empty_blob(), " +
"empty_blob())";
st.executeUpdate(sql);
// 用for update方式锁定数据行
sql = "select IRIDATA,KLODATA,ANADATA from MODELTEC where DATATIME=to_date('"+dataTime+"', 'YYYY-mm-dd HH24') for update";
rs = st.executeQuery(sql);
if (rs.next()) {
// 得到java.sql.Blob对象,然后Cast为oracle.sql.BLOB
BLOB blob = (BLOB) rs.getBlob("IRIDATA");
// 到数据库的输出流
OutputStream outStream = blob.getBinaryOutputStream();
// 这里用一个文件模拟输入流
InputStream fin = new FileInputStream(new File(IRIFilePath));
// 将输入流写到输出流
byte[] b = new byte[blob.getBufferSize()];
int len = 0;
while ((len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
}
// 依次关闭(注意顺序)
fin.close();
outStream.flush();
outStream.close();
// 得到java.sql.Blob对象,然后Cast为oracle.sql.BLOB
blob = (BLOB) rs.getBlob("KLODATA");
// 到数据库的输出流
outStream = blob.getBinaryOutputStream();
// 这里用一个文件模拟输入流
fin = new FileInputStream(new File(IRIFilePath));
// 将输入流写到输出流
b = new byte[blob.getBufferSize()];
len = 0;
while ((len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
}
// 依次关闭(注意顺序)
fin.close();
outStream.flush();
outStream.close();
// 得到java.sql.Blob对象,然后Cast为oracle.sql.BLOB
blob = (BLOB) rs.getBlob("ANADATA");
// 到数据库的输出流
outStream = blob.getBinaryOutputStream();
// 这里用一个文件模拟输入流
fin = new FileInputStream(new File(ANAFilePath));
// 将输入流写到输出流
b = new byte[blob.getBufferSize()];
len = 0;
while ((len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
}
// 依次关闭(注意顺序)
fin.close();
outStream.flush();
outStream.close();
con.commit();
/* 恢复原提交状态 */
con.setAutoCommit(defaultCommit);
DBConnectionManager.closeConnection();
if(con!=null){con.close();}
if(st!=null){st.close();}
if(rs!=null){rs.close();}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
// date类型转换为String类型
// formatType格式为yyyy-MM-dd HH:mm:ss//yyyy年MM月dd日 HH时mm分ss秒
// data Date类型的时间
public static String dateToString(Date data, String formatType) {
return new SimpleDateFormat(formatType).format(data);
}
// long类型转换为String类型
// currentTime要转换的long类型的时间
// formatType要转换的string类型的时间格式
public static String longToString(long currentTime, String formatType)
throws ParseException {
Date date = longToDate(currentTime, formatType); // long类型转成Date类型
String strTime = dateToString(date, formatType); // date类型转成String
return strTime;
}
// string类型转换为date类型
// strTime要转换的string类型的时间,formatType要转换的格式yyyy-MM-dd HH:mm:ss//yyyy年MM月dd日
// HH时mm分ss秒,
// strTime的时间格式必须要与formatType的时间格式相同
public static Date stringToDate(String strTime, String formatType)
throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat(formatType);
Date date = null;
date = formatter.parse(strTime);
return date;
}
// long转换为Date类型
// currentTime要转换的long类型的时间
// formatType要转换的时间格式yyyy-MM-dd HH:mm:ss//yyyy年MM月dd日 HH时mm分ss秒
public static Date longToDate(long currentTime, String formatType)
throws ParseException {
Date dateOld = new Date(currentTime); // 根据long类型的毫秒数生命一个date类型的时间
String sDateTime = dateToString(dateOld, formatType); // 把date类型的时间转换为string
Date date = stringToDate(sDateTime, formatType); // 把String类型转换为Date类型
return date;
}
// string类型转换为long类型
// strTime要转换的String类型的时间
// formatType时间格式
// strTime的时间格式和formatType的时间格式必须相同
public static long stringToLong(String strTime, String formatType)
throws ParseException {
Date date = stringToDate(strTime, formatType); // String类型转成date类型
if (date == null) {
return 0;
} else {
long currentTime = dateToLong(date); // date类型转成long类型
return currentTime;
}
}
// date类型转换为long类型
// date要转换的date类型的时间
public static long dateToLong(Date date) {
return date.getTime();
}
1、新建用户
useradd 用户名(gpsin) -g 当前登录用户(root) -d 根目录(/home/weiss) -s /sbin/nologin(不是用于登录)
passwd 用户名(为该用户创建密码)
2、删除用户
userdel 用户名(gpsin)
3、修改用户根目录
usermod -d 新目录(/home/wei) 用户名(gpsin)
window:需要两个文件
一个要执行的bat文件 test.bat
文件内容:ftp -n -s:C:\\config.txt 127.0.0.1
另一个操作ftp的命令文件 config.txt
文件内容:
user user
pass
ls
put ......
get ......
bye
linux:只需要一个文件即可也就是sh文件
test.sh
文件内容:ftp -i -n 127.0.0.1
user user pass
bin
ls
put ......
get ......
bye
ftp -nv 127.0.0.1 <<EOF
user user pass
bin
prompt
lcd /home
put ......
get ......
quit
package db;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DBPool {
private ComboPooledDataSource dataSource;
public static Connection con;
public DBPool() {
try {
dataSource = new ComboPooledDataSource();
dataSource.setUser("test");
dataSource.setPassword("test");
dataSource.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:orcl");
dataSource.setDriverClass("oracle.jdbc.driver.OracleDriver");
dataSource.setInitialPoolSize(2);
dataSource.setMinPoolSize(1);
dataSource.setMaxPoolSize(10);
dataSource.setMaxStatements(50);
dataSource.setMaxIdleTime(60);
dataSource.setAcquireRetryAttempts(3);
} catch (PropertyVetoException e) {
}
}
public final static DBPool getInstance() {
return new DBPool();
}
public final Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
return null;
}
}
//测试方法
public static void main(String[] args) throws SQLException {
con = DBPool.getInstance().getConnection();
System.out.println(con);
try {
if (con != null){con.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
} //初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 initialPoolSize
cpds.setInitialPoolSize(initialPoolSize);
//连接池中保留的最大连接数。Default: 15 maxPoolSize
cpds.setMaxPoolSize(maxPoolSize);
//连接池中保留的最小连接数。
cpds.setMinPoolSize(minPoolSize);
//获得连接的最大等待毫秒数。Default: 1000 acquireRetryDelay
cpds.setAcquireRetryDelay(acquireRetryDelay);
//最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 maxIdleTime
cpds.setMaxIdleTime(maxIdleTime);
//当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 acquireIncrement
//cpds.setAcquireIncrement(3);
//每60秒检查所有连接池中的空闲连接。Default: 0 idleConnectionTestPeriod
//cpds.setIdleConnectionTestPeriod(60);
//连接关闭时默认将所有未提交的操作回滚。Default: false autoCommitOnClose
//cpds.setAutoCommitOnClose(true);
//JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0
//cpds.setMaxStatements(1);
//maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数
//cpds.setMaxStatementsPerConnection(100);
//定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:测试的表必须在初始数据源的时候就存在。Default: null preferredTestQuery
//cpds.setPreferredTestQuery("select sysdate from dual");
// 因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
// 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
// 等方法来提升连接测试的性能。Default: false testConnectionOnCheckout
//cpds.setTestConnectionOnCheckout(true);
//如果设为true那么在取得连接的同时将校验连接的有效性。Default: false testConnectionOnCheckin
//cpds.setTestConnectionOnCheckin(true);
//定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 acquireRetryAttempts
//cpds.setAcquireRetryAttempts(30);
//获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
//保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
//获取连接失败后该数据源将申明已断开并永久关闭。Default: false breakAfterAcquireFailure
//cpds.setBreakAfterAcquireFailure(false);
//两次连接中间隔时间,单位毫秒。Default: 1000 acquireRetryDelay
cpds.setAcquireRetryDelay(60000);
java.lang.AbstractMethodError: oracle.jdbc.driver.OracleResultSetImpl.getClob(异常解决办法
最近遇到了一个头痛的问题,可能大家也遇到过。经过多番的询问与查找,终于知道问题原因的所在:异常内容如下:
java.lang.AbstractMethodError: oracle.jdbc.driver.OracleResultSetImpl.getClob(Ljava/lang/String;)Ljava/sql/Clob;
问题原因:Oracle驱动版本不对
解决办法:在Oracle服务器上找到这个驱动,然后cp到Apache的lib目录下,并同是修改环境变量classpath,保证这个lib/classes12.jar在最前面;修改完后,重新启动服务,问题就可以解决。
(ojdbc14.jar在classes12.jar前面)
useradd gpsin -g root -d /inraw -s /sbin/nologin #该用户仅用来支持FTP服务,因此不必让他登录系统
gpsin是ftp登录的用户名,root指定哪个用户可以使用该ftp用户,-d /inraw 指定ftp的根目录,-s /sbin/nologin不用于登录
passwd gpsin 给gpsin用户设置密码
1.下载
rarlinux-3.7.1.tar.zip
#unzip rarlinux-3.7.1.tar.zip
#cd rar
#make
#make install
运行 rar --help 可以看到帮助信息,如果出现下列信息:
#rar: /lib/tls/libc.so.6: version `GLIBC_2.4' not found (required by rar)
#rar: /lib/tls/libc.so.6: version `GLIBC_2.7' not found (required by rar)
则执行:
#cp -f rar_static /usr/local/bin/rar
这样就可以使用rar 命令了。
一、卸载jdk1.4
由于Redhat Enterprise Linux 5.6 中自带安装了jdk1.4.2的,所以在安装jdk1.6前我把jdk1.4.2的卸了,步骤如下:
1、打开终端输入 yum remove java
终端显示 Is this ok [y/N]:
输入y ,按回车。
终端显示 Complete! 此时jdk1.4已被卸了。
二、安装jdk1.6
1.下载:jdk-1_5_0_06-linux-i586-rpm.bin
地址:http://java.sun.com/j2se/1.5.0/download.jsp
2.给文件加上可执行权限
[root@esprit java]# chmod +x jdk-1_5_0_06-linux-i586-rpm.bin
chmod +x jdk-6u31-linux-i586-rpm.bin
3.执行jdk-1_5_0_06-linux-i586-rpm.bin
[root@esprit java]# ./jdk-1_5_0_06-linux-i586-rpm.bin
./jdk-6u31-linux-i586-rpm.bin
执行后生成jdk-6u31-linux-i586.rpm
4.安装jdk-6u31-linux-i586.rpm
rpm -ivh jdk-6u31-linux-i586.rpm
########################################### [100%]
package jdk-1.6.0_31-fcs is already installed
这里我jdk安装在/usr/java目录下
三、配置java环境变量
环境变量配置有三种方法(分别是:修改/etc/profile文件,修改用户目录下的.bashrc文件,直接在shell下修改)
这里我只讲我用到的修改/etc/profile文件
[root@esprit java]# vi /etc/profile
打开文件后,按 I 键,在文件后添加:
JAVA_HOME =/ usr / java / jdk1.6.0_31
PATH = $JAVA_HOME / bin:$PATH
CLASSPATH = .:$JAVA_HOME / lib / tools.jar:$JAVA_HOME / lib / dt.jar:$JAVA_HOME/lib
export JAVA_HOME PATH CLASSPATH
按esc 键
输入:wq 保存退出。
重新登入
四、检查jdk是否装好
在命令行输入: java -version
如果显示版本信息,表示已经安装配置成功
五、卸载jdk1.6
输入 rpm -qa|grep jdk
显示 jdk-1.6.0_24-fcs
卸载 rpm -e –nodeps jdk-1.6.0_24-fcs
package com.ky.ui.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import javax.imageio.ImageIO;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
/**
Email:
上午11:18:19
*/
public final class ImgRead{
// public final static String getPressImgPath(){
// return ApplicationContext.getRealPath("/template/data/util/shuiyin.gif");
// }
/** *//**
* 把图片印刷到图片上
* @param pressImg -- 水印文件
* @param targetImg -- 目标文件
* @param x
* @param y
*/
public final static void pressImage(String pressImg, String targetImg, int x, int y){
try {
File _file = new File(targetImg);
Image src = ImageIO.read(_file);
int wideth = src.getWidth(null);
int height = src.getHeight(null);
BufferedImage image = new BufferedImage(wideth, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
g.drawImage(src, 0, 0, wideth, height, null);
// 水印文件
File _filebiao = new File(pressImg);
Image src_biao = ImageIO.read(_filebiao);
int wideth_biao = src_biao.getWidth(null);
int height_biao = src_biao.getHeight(null);
g.drawImage(src_biao, wideth - wideth_biao - x, height - height_biao -y, wideth_biao,
height_biao, null);
// /
g.dispose();
FileOutputStream out = new FileOutputStream(targetImg);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
out.close();
} catch (Exception e){
e.printStackTrace();
}
}
/** *//**
* 打印文字水印图片
* @param pressText --文字
* @param targetImg -- 目标图片
* @param fontName -- 字体名
* @param fontStyle -- 字体样式
* @param color -- 字体颜色
* @param fontSize -- 字体大小
* @param x -- 偏移量
* @param y
*/
public static void pressText(String pressText, String targetImg, String fontName,int fontStyle, int color, int fontSize, int x, int y){
try{
File _file = new File(targetImg);
Image src = ImageIO.read(_file);
int wideth = src.getWidth(null);
int height = src.getHeight(null);
BufferedImage image = new BufferedImage(wideth, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
g.drawImage(src, 0, 0, wideth, height, null);
// String s="www.qhd.com.cn";
g.setColor(Color.RED);
g.setFont(new Font(fontName, fontStyle, fontSize));
g.drawString(pressText, wideth - fontSize - x, height - fontSize/2 - y);
g.dispose();
FileOutputStream out = new FileOutputStream(targetImg);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
out.close();
} catch (Exception e){
System.out.println(e);
}
}
public static void main(String[] args){
pressImage("C:/foot_05.gif", "c:/Chart.jpg", 20 ,20);
}
}
// 获取屏幕的边界
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(frame.getGraphicsConfiguration());
// 获取底部任务栏高度
int taskBarHeight = screenInsets.bottom;
1、 下载vsftpd
# wget ftp://vsftpd.beasts.org/users/cevans/vsftpd-2.3.2.tar.gz
2、 解压、安装vsftpd
# tar xvfz vsftpd-2.3.2.tar.gz
# cd vsftpd-2.3.2
# make
make命令成功执行后,您将看到vsftpd文件获得当前目录中创建。
# ls -l vsftpd
3、 安装 vsftpd d到 Linux
# make install
在make install,确保vsftpd文件复制到/ usr / local / sbin目录。
# ls -l /usr/local/sbin/vsftpd
4、 复制vsftpd手册页到/usr/share/man/man8,man5
# cp vsftpd.8 /usr/share/man/man8/
# cp vsftpd.conf.5 /usr/share/man/man5/
5、 拷贝vsftpd.cond配置文件
# cp vsftpd.conf /etc
6、 设置Anonymouse FTP访问vsftpd
# mkdir /var/ftp/
# chown root.root /var/ftp
# chmod og-w /var/ftp
ftp localhost
Connected to dotcom.
220 (vsFTPd 2.3.2)
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (localhost:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
在这个阶段,如果你试图登录与任何其他账户(除了匿名,和ftp),它就会失败,如下所示
# ftp localhost
Connected to dotcom.
220 (vsFTPd 2.3.2)
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (localhost:root): ramesh
530 This FTP server is anonymous only.
Login failed.
ftp>
7、 允许LINIX登录使用vsftp
# cp RedHat/vsftpd.pam /etc/pam.d/ftp
#local_enable=YES
# ftp localhost
Connected to dotcom.
220 (vsFTPd 2.3.2)
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (localhost:root): ramesh
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
切记再每次修改完vsftpd.conf文件之后要重启一下vsftpd
# ps -ef | grep vsftpd
# kill -9 {vsftpd-pid}
# /usr/local/sbin/vsftpd &
如果还不能登录成功,那么要关闭系统其他的ftp服务和防火墙
Service xinetd stop
Service iptables stop
摘要: 各种排序算法:冒择路(入)兮(稀)快归堆,桶式排序,基数排序 冒泡排序,选择排序,插入排序,稀尔排序,快速排序,归并排序,堆排序,桶式排序,基数排序 一、冒泡排序(BubbleSort) 1. 基本思想: 两两比较待排序数据元素的大小,发现两个数据元素的次序相反时即进行交换,直到没有反序的数据元素为止。 2. 排序过程: 设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气...
阅读全文
摘要: Java反射机制是Java语言被视为准动态语言的关键性质。Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息,动态地生成此类,并调用其方法或修改其域(甚至是本身声明为private的域或方法)。
也许你使用Java已经很长时间了,可是几乎不会用到Java反射机制。你会嗤之以鼻地告诉我,Java反射机制没啥用...
阅读全文
1.使用mysqladmin修改mysql密码
C:\>mysqladmin -udbuser -p password newpassEnter password: oldpass当然用此命令的前提是你把mysql加入了环境变量,如果没有加入环境变量的话那只能在命令行下cd到mysqladmin所在的目录下与此那个次命令了!
-----------------------------------------
2.重置root密码
方法一:
在my.ini的[mysqld]字段加入:
skip-grant-tables
重启mysql服务,这时的mysql不需要密码即可登录数据库
然后进入mysql
mysql>use mysql;mysql>update user set password=password('新密码') WHERE User='root'; mysql>flush privileges;运行之后最后去掉my.ini中的skip-grant-tables,重启mysqld即可。
修改mysql密码方法二:
不使用修改my.ini重启服务的方法,通过非服务方式加skip-grant-tables运行mysql来修改mysql密码
停止mysql服务
打开命令行窗口,在bin目录下使用mysqld-nt.exe启动,即在命令行窗口执行: mysqld-nt --skip-grant-tables
然后另外打开一个命令行窗口,登录mysql,此时无需输入mysql密码即可进入。
按以上方法修改好密码后,关闭命令行运行mysql的那个窗口,此时即关闭了mysql,如果发现mysql仍在运行的话可以结束掉对应进程来关闭。
启动mysql服务
-----------------------------------------
记住此方法,走遍天下无mysql密码
先假设一个ftp地址 用户名 密码
FTP Server: home4u.at.china.com
User: yepanghuang
Password: abc123
打开windows的开始菜单,执行“运行”命令,在对话框中输入ftp,按下“确定”按钮将会切换至DOS窗口,出现命令提示符
ftp>键入命令连接FTP服务器
:
ftp> open home4u.at.china.com (回车)
稍等片刻,屏幕提示连接成功:
ftp> connected to home4u.china.com
接下来服务器询问用户名和口令,分别输入yepanghuang和abc123,待认证通过即可。
windows下ftp上传文件:
比如要把 D:\index.html上传至服务器的根目录中,可以键入:
ftp> put D:\index.html (回车)
当屏幕提示你已经传输完毕,可以键入相关命令查看:
ftp> dir (回车)
windows下ftp上传下载:
假设要把服务器\images目录中的所有.jpg文件下载至本机中,可以输入指令:
ftp> cd images(回车) [注:进入\images目录]
ftp> mget *.jpg
windows下ftp上传与下载工作完毕,键入bye中断连接。
ftp> bye(回车)
下面是一些常用的FTP命令:
1. open:与服务器相连接;
2. send(put):上传文件;
3. get:下载文件;
4. mget:下载多个文件;
5. cd:切换目录;
6. dir:查看当前目录下的文件;
7. del:删除文件;
8. bye:中断与服务器的连接。
如果想了解更多,可以键入
ftp> help (回车)
查看命令集:
ascii: 设定以ASCII方式传送文件(缺省值)
bell: 每完成一次文件传送,报警提示
binary: 设定以二进制方式传送文件
bye: 终止主机FTP进程,并退出FTP管理方式
case: 当为ON时,用MGET命令拷贝的文件名到本地机器中,全部转换为小写字母
cd: 同UNIX的CD命令
cdup: 返回上一级目录
chmod: 改变远端主机的文件权限
close: 终止远端的FTP进程,返回到FTP命令状态,所有的宏定义都被删除
delete: 删除远端主机中的文件
dir [remote-directory] [local-file]: 列出当前远端主机目录中的文件.如果有本地文件,就将结果写至本地文件
get [remote-file] [local-file]: 从远端主机中传送至本地主机中
help [command]: 输出命令的解释
lcd: 改变当前本地主机的工作目录,如果缺省,就转到当前用户的HOME目录
ls [remote-directory] [local-file]: 同DIR
其实在网上也看到过一些文章,介绍如何让java程序以window服务的方式启动。
今天有空,就想用c写一个window服务,在服务启动时来启动一个java程序。
因为在c方面,我十足菜鸟,先到网上搜索了一下关于如何用c写出windows服务,找到一篇介绍的相当详细,参照介绍写了一个window服务。
测试的过程中遇到一个问题,由于我的java程序启动时会在系统托盘显示一个小图标,但通过c写的window服务启运这个java程序后,系统托盘里没有显示小图标。
再搜索,原来:
windows服务程序默认是工作于WinLogon桌面的,服务启动时不会显示GUI界面.可以打开控制面板->服务,查看服务的属性->[登录]-[允许服务与桌面交互],打上钩后,系统托盘就能显示在任务栏。
用C写一个windows服务:
来源:http://www.vckbase.com/document/viewdoc/?id=1474
摘要
Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务。为了学习这种控制台应用程序的基础知识,C(不是C++)是最佳选择。本文将建立并实现一个简单的服务程序,其功能是查询系统中可用物理内存数量,然后将结果写入一个文本文件。最后,你可以用所学知识编写自己的 Windows 服务。
当初我写第一个 NT 服务时,我到 MSDN 上找例子。在那里我找到了一篇 Nigel Thompson 写的文章:“Creating a Simple Win32 Service in C++”,这篇文章附带一个 C++ 例子。虽然这篇文章很好地解释了服务的开发过程,但是,我仍然感觉缺少我需要的重要信息。我想理解通过什么框架,调用什么函数,以及何时调用,但 C++ 在这方面没有让我轻松多少。面向对象的方法固然方便,但由于用类对底层 Win32 函数调用进行了封装,它不利于学习服务程序的基本知识。这就是为什么我觉得 C 更加适合于编写初级服务程序或者实现简单后台任务的服务。在你对服务程序有了充分透彻的理解之后,用 C++ 编写才能游刃有余。当我离开原来的工作岗位,不得不向另一个人转移我的知识的时候,利用我用 C 所写的例子就非常容易解释 NT 服务之所以然。
服务是一个运行在后台并实现勿需用户交互的任务的控制台程序。Windows NT/2000/XP 操作系统提供为服务程序提供专门的支持。人们可以用服务控制面板来配置安装好的服务程序,也就是 Windows 2000/XP 控制面板|管理工具中的“服务”(或在“开始”|“运行”对话框中输入 services.msc /s——译者注)。可以将服务配置成操作系统启动时自动启动,这样你就不必每次再重启系统后还要手动启动服务。
本文将首先解释如何创建一个定期查询可用物理内存并将结果写入某个文本文件的服务。然后指导你完成生成,安装和实现服务的整个过程。
第一步:主函数和全局定义
首先,包含所需的头文件。例子要调用 Win32 函数(windows.h)和磁盘文件写入(stdio.h):
#include <windows.h>
#include <stdio.h>
接着,定义两个常量:
#define SLEEP_TIME 5000
#define LOGFILE "C:\\MyServices\\memstatus.txt"
SLEEP_TIME 指定两次连续查询可用内存之间的毫秒间隔。在第二步中编写服务工作循环的时候要使用该常量。
LOGFILE 定义日志文件的路径,你将会用 WriteToLog 函数将内存查询的结果输出到该文件,WriteToLog 函数定义如下:
int WriteToLog(char* str)
{
FILE* log;
log = fopen(LOGFILE, "a+");
if (log == NULL)
return -1;
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
声明几个全局变量,以便在程序的多个函数之间共享它们值。此外,做一个函数的前向定义:
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();
现在,准备工作已经就绪,你可以开始编码了。服务程序控制台程序的一个子集。因此,开始你可以定义一个 main 函数,它是程序的入口点。对于服务程序来说,main 的代码令人惊讶地简短,因为它只创建分派表并启动控制分派机。
void main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// 启动服务的控制分派机线程
StartServiceCtrlDispatcher(ServiceTable);
}
一个程序可能包含若干个服务。每一个服务都必须列于专门的分派表中(为此该程序定义了一个 ServiceTable 结构数组)。这个表中的每一项都要在 SERVICE_TABLE_ENTRY 结构之中。它有两个域:
- lpServiceName: 指向表示服务名称字符串的指针;当定义了多个服务时,那么这个域必须指定;
- lpServiceProc: 指向服务主函数的指针(服务入口点);
分派表的最后一项必须是服务名和服务主函数域的 NULL 指针,文本例子程序中只宿主一个服务,所以服务名的定义是可选的。
服务控制管理器(SCM:Services Control Manager)是一个管理系统所有服务的进程。当 SCM 启动某个服务时,它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数。将分派表传递给 StartServiceCtrlDispatcher。这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程,该线程运行分派表中每个服务的 ServiceMain 函数(本文例子中只有一个服务)分派器还监视程序中所有服务的执行情况。然后分派器将控制请求从 SCM 传给服务。
注意:如果 StartServiceCtrlDispatcher 函数30秒没有被调用,便会报错,为了避免这种情况,我们必须在 ServiceMain 函数中(参见本文例子)或在非主函数的单独线程中初始化服务分派表。本文所描述的服务不需要防范这样的情况。
分派表中所有的服务执行完之后(例如,用户通过“服务”控制面板程序停止它们),或者发生错误时。StartServiceCtrlDispatcher 调用返回。然后主进程终止。
第二步:ServiceMain 函数
Listing 1 展示了 ServiceMain 的代码。该函数是服务的入口点。它运行在一个单独的线程当中,这个线程是由控制分派器创建的。ServiceMain 应该尽可能早早为服务注册控制处理器。这要通过调用 RegisterServiceCtrlHadler 函数来实现。你要将两个参数传递给此函数:服务名和指向 ControlHandlerfunction 的指针。
它指示控制分派器调用 ControlHandler 函数处理 SCM 控制请求。注册完控制处理器之后,获得状态句柄(hStatus)。通过调用 SetServiceStatus 函数,用 hStatus 向 SCM 报告服务的状态。
Listing 1 展示了如何指定服务特征和其当前状态来初始化 ServiceStatus 结构,ServiceStatus 结构的每个域都有其用途:
- dwServiceType:指示服务类型,创建 Win32 服务。赋值 SERVICE_WIN32;
- dwCurrentState:指定服务的当前状态。因为服务的初始化在这里没有完成,所以这里的状态为 SERVICE_START_PENDING;
- dwControlsAccepted:这个域通知 SCM 服务接受哪个域。本文例子是允许 STOP 和 SHUTDOWN 请求。处理控制请求将在第三步讨论;
- dwWin32ExitCode 和 dwServiceSpecificExitCode:这两个域在你终止服务并报告退出细节时很有用。初始化服务时并不退出,因此,它们的值为 0;
- dwCheckPoint 和 dwWaitHint:这两个域表示初始化某个服务进程时要30秒以上。本文例子服务的初始化过程很短,所以这两个域的值都为 0。
调用 SetServiceStatus 函数向 SCM 报告服务的状态时。要提供 hStatus 句柄和 ServiceStatus 结构。注意 ServiceStatus 一个全局变量,所以你可以跨多个函数使用它。ServiceMain 函数中,你给结构的几个域赋值,它们在服务运行的整个过程中都保持不变,比如:dwServiceType。
在报告了服务状态之后,你可以调用 InitService 函数来完成初始化。这个函数只是添加一个说明性字符串到日志文件。如下面代码所示:
// 服务初始化
int InitService()
{
int result;
result = WriteToLog("Monitoring started.");
return(result);
}
在 ServiceMain 中,检查 InitService 函数的返回值。如果初始化有错(因为有可能写日志文件失败),则将服务状态置为终止并退出 ServiceMain:
error = InitService();
if (error)
{
// 初始化失败,终止服务
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
// 退出 ServiceMain
return;
}
如果初始化成功,则向 SCM 报告状态:
// 向 SCM 报告运行状态
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);
接着,启动工作循环。每五秒钟查询一个可用物理内存并将结果写入日志文件。
如 Listing 1 所示,循环一直到服务的状态为 SERVICE_RUNNING 或日志文件写入出错为止。状态可能在 ControlHandler 函数响应 SCM 控制请求时修改。
第三步:处理控制请求
在第二步中,你用 ServiceMain 函数注册了控制处理器函数。控制处理器与处理各种 Windows 消息的窗口回调函数非常类似。它检查 SCM 发送了什么请求并采取相应行动。
每次你调用 SetServiceStatus 函数的时候,必须指定服务接收 STOP 和 SHUTDOWN 请求。Listing 2 示范了如何在 ControlHandler 函数中处理它们。
STOP 请求是 SCM 终止服务的时候发送的。例如,如果用户在“服务”控制面板中手动终止服务。SHUTDOWN 请求是关闭机器时,由 SCM 发送给所有运行中服务的请求。两种情况的处理方式相同:
- 写日志文件,监视停止;
- 向 SCM 报告 SERVICE_STOPPED 状态;
由于 ServiceStatus 结构对于整个程序而言为全局量,ServiceStatus 中的工作循环在当前状态改变或服务终止后停止。其它的控制请求如:PAUSE 和 CONTINUE 在本文的例子没有处理。
控制处理器函数必须报告服务状态,即便 SCM 每次发送控制请求的时候状态保持相同。因此,不管响应什么请求,都要调用 SetServiceStatus。
图一 显示 MemoryStatus 服务的服务控制面板
第四步:安装和配置服务
程序编好了,将之编译成 exe 文件。本文例子创建的文件叫 MemoryStatus.exe,将它拷贝到 C:\MyServices 文件夹。为了在机器上安装这个服务,需要用 SC.EXE 可执行文件,它是 Win32 Platform SDK 中附带的一个工具。(译者注:Visaul Studio .NET 2003 IDE 环境中也有这个工具,具体存放位置在:C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\Bin\winnt)。使用这个实用工具可以安装和移除服务。其它控制操作将通过服务控制面板来完成。以下是用命令行安装 MemoryStatus 服务的方法:
sc create MemoryStatus binpath= c:\MyServices\MemoryStatus.exe
发出此创建命令。指定服务名和二进制文件的路径(注意 binpath= 和路径之间的那个空格)。安装成功后,便可以用服务控制面板来控制这个服务(参见图一)。用控制面板的工具栏启动和终止这个服务。
图二 MemoryStatus 服务的属性窗口
MemoryStatus 的启动类型是手动,也就是说根据需要来启动这个服务。右键单击该服务,然后选择上下文菜单中的“属性”菜单项,此时显示该服务的属性窗口。在这里可以修改启动类型以及其它设置。你还可以从“常规”标签中启动/停止服务。以下是从系统中移除服务的方法:
sc delete MemoryStatus
指定 “delete” 选项和服务名。此服务将被标记为删除,下次西通重启后,该服务将被完全移除。
第五步:测试服务
从服务控制面板启动 MemoryStatus 服务。如果初始化不出错,表示启动成功。过一会儿将服务停止。检查一下 C:\MyServices 文件夹中 memstatus.txt 文件的服务输出。在我的机器上输出是这样的:
Monitoring started.
273469440
273379328
273133568
273084416
Monitoring stopped.
为了测试 MemoryStatus 服务在出错情况下的行为,可以将 memstatus.txt 文件设置成只读。这样一来,服务应该无法启动。
去掉只读属性,启动服务,在将文件设成只读。服务将停止执行,因为此时日志文件写入失败。如果你更新服务控制面板的内容,会发现服务状态是已经停止。
开发更大更好的服务程序
理解 Win32 服务的基本概念,使你能更好地用 C++ 来设计包装类。包装类隐藏了对底层 Win32 函数的调用并提供了一种舒适的通用接口。修改 MemoryStatus 程序代码,创建满足自己需要的服务!为了实现比本文例子所示范的更复杂的任务,你可以创建多线程的服务,将作业划分成几个工作者线程并从 ServiceMain 函数中监视它们的执行。
最近的机器内存又爆满了,除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于随意化,这些不好的习惯或对程序语言的不了解是应该好好打压打压了。
下面是参考网络资源总结的一些在Java编程中尽可能要做到的一些地方。
1. 尽量在合适的场合使用单例
使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面:
第一,控制资源的使用,通过线程同步来控制资源的并发访问;
第二,控制实例的产生,以达到节约资源的目的;
第三,控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。
2. 尽量避免随意使用静态变量
要知道,当某个对象被定义为stataic变量所引用,那么gc通常是不会回收这个对象所占有的内存,如
- public class A{
- static B b = new B();
- }
public class A{ static B b = new B(); }
此时静态变量b的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。
3. 尽量避免过多过常的创建Java对象
尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理,在我们可以控制的范围内,最大限度的重用对象,最好能用基本的数据类型或数组来替代对象。
4. 尽量使用final修饰符
带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。
5. 尽量使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。
6. 尽量处理好包装类型和基本类型两者的使用场所
虽然包装类型和基本类型在使用过程中是可以相互转换,但它们两者所产生的内存区域是完全不同的,基本类型数据产生和处理都在栈中处理,包装类型是对象,是在堆中产生实例。
在集合类对象,有对象方面需要的处理适用包装类型,其他的处理提倡使用基本类型。
7. 慎用synchronized,尽量减小synchronize的方法
都知道,实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。synchronize方法被调用时,直接会把当前对象锁 了,在方法执行完之前其他线程无法调用当前对象的其他方法。所以synchronize的方法尽量小,并且应尽量使用方法同步代替代码块同步。
8. 尽量使用StringBuilder和StringBuffer进行字符串连接
这个就不多讲了。
9. 尽量不要使用finalize方法
实际上,将资源清理放在finalize方法中完成是非常不好的选择,由于GC的工作量很大,尤其是回收Young代内存时,大都会引起应用程序暂停,所以再选择使用finalize方法进行资源清理,会导致GC负担更大,程序运行效率更差。
10. 尽量使用基本数据类型代替对象
String str = "hello";
上面这种方式会创建一个“hello”字符串,而且JVM的字符缓存池还会缓存这个字符串;
String str = new String("hello");
此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o
11. 单线程应尽量使用HashMap、ArrayList
HashTable、Vector等使用了同步机制,降低了性能。
12. 尽量合理的创建HashMap
当你要创建一个比较大的hashMap时,充分利用另一个构造函数
public HashMap(int initialCapacity, float loadFactor)
避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事,在默认中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能准确的估计你所需要的最佳大小,同样的Hashtable,Vectors也是一样的道理。
13. 尽量减少对变量的重复计算
如
for(int i=0;i<list.size();i++)
应该改为
for(int i=0,len=list.size();i<len;i++)
并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。
14. 尽量避免不必要的创建
如
A a = new A();
if(i==1){list.add(a);}
应该改为
if(i==1){
A a = new A();
15. 尽量在finally块中释放资源
程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。
16. 尽量使用移位来代替'a/b'的操作
"/"是一个代价很高的操作,使用移位的操作将会更快和更有效
如
int num = a / 4;
int num = a / 8;
应该改为
int num = a >> 2;
int num = a >> 3;
但注意的是使用移位应添加注释,因为移位操作不直观,比较难理解
17.尽量使用移位来代替'a*b'的操作
同样的,对于'*'操作,使用移位的操作将会更快和更有效
如
int num = a * 4;
int num = a * 8;
应该改为
int num = a << 2;
18. 尽量确定StringBuffer的容量
StringBuffer 的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再 丢弃旧的数组。在大多数情况下,你可以在创建 StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。
如:StringBuffer buffer = new StringBuffer(1000);
19. 尽量早释放无用对象的引用
大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。
例如:
- Public void test(){
- Object obj = new Object();
- ……
- Obj=null;
- }
Public void test(){ Object obj = new Object(); …… Obj=null; }
上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:
- Public void test(){
- Object obj = new Object();
- ……
- Obj=null;
- //执行耗时,耗内存操作;或调用耗时,耗内存的方法
- ……
- }
Public void test(){ Object obj = new Object(); …… Obj=null; //执行耗时,耗内存操作;或调用耗时,耗内存的方法 …… }
这时候就有必要将obj赋值为null,可以尽早的释放对Object对象的引用。
20. 尽量避免使用二维数组
二维数据占用的内存空间比一维数组多得多,大概10倍以上。
21. 尽量避免使用split
除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需 要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。
22. ArrayList & LinkedList
一 个是线性表,一个是链表,一句话,随机查询尽量使用ArrayList,ArrayList优于LinkedList,LinkedList还要移动指 针,添加删除的操作LinkedList优于ArrayList,ArrayList还要移动数据,不过这是理论性分析,事实未必如此,重要的是理解好2 者得数据结构,对症下药。
23. 尽量使用System.arraycopy ()代替通过来循环复制数组
System.arraycopy() 要比通过循环来复制数组快的多
24. 尽量缓存经常使用的对象
尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache进行缓存,他们基本都实现了FIFO/FLU等缓存算法。
25. 尽量避免非常大的内存分配
有时候问题不是由当时的堆状态造成的,而是因为分配失败造成的。分配的内存块都必须是连续的,而随着堆越来越满,找到较大的连续块越来越困难。
26. 慎用异常
当创建一个异常时,需要收集一个栈跟踪(stack track),这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大。当需要创建一个 Exception 时,JVM 不得不说:先别动,我想就您现在的样子存一份快照,所以暂时停止入栈和出栈操作。栈跟踪不只包含运行时栈中的一两个元素,而是包含这个栈中的每一个元素。
如 果您创建一个 Exception ,就得付出代价。好在捕获异常开销不大,因此可以使用 try-catch 将核心内容包起来。从技术上讲,您甚至可以随意地抛出异常,而不用花费很大的代价。招致性能损失的并不是 throw 操作——尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就 抛出异常。异常是为异常的情况而设计的,使用时也应该牢记这一原则。
相关回复:
xuanyuan 写道
7.慎用synchronized,尽量减小synchronize的方法
re:同意,不过文中有个地方说错了,使用synchronized关键字并不一定都是锁定当前对象的,要看具体的锁是什么。如果是在方法上加的synchronized,则是以对象本身为锁的,如果是静态方法则锁的粒度是类。
---------------
9.尽量不要使用finalize方法
re:同意,其实不推荐用finalize方法的根本原因在于,JVM的规范并不保证何时执行该方法,所以用这个方法来释放资源很不合适,有可能造成长时间资源得不到释放。
---------------
16.尽量使用移位来代替'a/b'的操作;17.尽量使用移位来代替'a*b'的操作
re:个人不太同意这两条。这样做确实有更好的性能,但是却牺牲了可读性。这两个操作符对很多程序员来说并不直观。我认为在如今硬件价格不那么昂贵的情况下,略微牺牲一些性能,换来更好的可读性和可维护性是好的选择。
wuzhengju 写道
19.尽量早释放无用对象的引用
大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。
例如:
Public void test(){
Object obj = new Object();
……
Obj=null;
}
上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:
Public void test(){
Object obj = new Object();
……
Obj=null;
//执行耗时,耗内存操作;或调用耗时,耗内存的方法
……
}
如果Object obj = new Object(); 如果这对象并不是大对象,这有必要吗?Obj=null;只是告诉jvm这个对象已经成为垃圾,至于什么时候回收,还不能确定! 这可读性也不好!
下面的代码片段是由经过验证的程序修改而来。观察这些代码片段你会发现,跟以前的版本相比,在Java7里,文件相关的操作变得简单的多了。通过使用新的Files类里提供的各种方法,你可以只用一行代码就能完成下列的文件操作:
这篇文件是以你对Java7里提供的新的Path类很熟悉为前提,如果你不熟悉这个类,这里就简单说一句,Path是文件系统里对位置的一个逻辑概念,例如c:\ 和../foobar.txt都是Path。
创建和删除文件
下面的代码片段向你展示的是用 Files.createFile (Path target) 方法创建文件的基本用法。
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Path file = Files.createFile (target);
很多时候,出于安全的原因,你可能希望在创建的文件上设置一下属性,例如:是否可读/可写/写执行。这些属性依赖于文件系统的种类,你需要使用跟文件系统相应的权限辅助类来完成这种操作。例如,PosixFilePermission和PosixFilePermissions为POSIX文件系统设计的。下面的是在POSIX文件系统上的文件设置读写权限的用法。
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Set<PosixFilePermission> perms = PosixFilePermissions.fromString ("rw-rw-rw-");
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute (perms);
Files.createFile (target, attr);
这个java.nio.file.attribute包里提供了很多关于FilePermission的类。
警告当创建一个带有权限属性的文件时,请注意包含这个文件的文件夹是否有权限的强制约束。例如,你会发现,由于这些限制,尽管你给创建的文件指定了rw-rw-rw权限,实际创建的结果却是rw-r–r–。
删除文件更简单,使用Files.delete (Path)这个方法。
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Files.delete (target);
拷贝和移动文件
下面的代码向你展示的是使用Files.copy (Path source, Path target)方法做文件拷贝的基本用法。
- Path source = Paths.get ("C:\\My Documents\\Stuff.txt");
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Files.copy (source, target);
经常的,在拷贝文件的过程中你可能希望指定一些操作设置。在Java7里,你可以通过使用StandardCopyOption enum来设置这些属性。下面看一个例子。
- import static java.nio.file.StandardCopyOption.*;
- Path source = Paths.get ("C:\\My Documents\\Stuff.txt");
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
- Files.copy (source, target, REPLACE_EXISTING);
拷贝操作时可以使用的属性还包括COPY_ATTRIBUTES (保留文件属性) 和ATOMIC_MOVE (确保移动事务操作的成功,否则进行回滚)。
移动文件的操作跟拷贝很相似,使用Files.move (Path source, Path target)方法。
同样,你也可以指定移动操作的属性,使用Files.move (Path source, Path target, CopyOptions...) 方法里的参数来设置。
- import static java.nio.file.StandardCopyOption.*;
- Path source = Paths.get ("C:\\My Documents\\Stuff.txt");
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Files.move (source, target, REPLACE_EXISTING,COPY_ATTRIBUTES);
可以看出,新的用于文件操作的NIO.2 API 非常便于使用。
众所周知,随机数是任何一种编程语言最基本的特征之一。而生成随机数的基本方式也是相同的:产生一个0到1之间的随机数。看似简单,但有时我们也会忽略了一些有趣的功能。
我们从书本上学到什么?
最明显的,也是直观的方式,在Java中生成随机数只要简单的调用:
- java.lang.Math.random()
在所有其他语言中,生成随机数就像是使用Math工具类,如abs, pow, floor, sqrt和其他数学函数。大多数人通过书籍、教程和课程来了解这个类。一个简单的例子:从0.0到1.0之间可以生成一个双精度浮点数。那么通过上面的信息,开发人员要产生0.0和10.0之间的双精度浮点数会这样来写:
- Math.random() * 10
而产生0和10之间的整数,则会写成:
- Math.round(Math.random() * 10)
进阶
通过阅读Math.random()的源码,或者干脆利用IDE的自动完成功能,开发人员可以很容易发现,java.lang.Math.random()使用一个内部的随机生成对象 - 一个很强大的对象可以灵活的随机产生:布尔值、所有数字类型,甚至是高斯分布。例如:
- new java.util.Random().nextInt(10)
它有一个缺点,就是它是一个对象。它的方法必须是通过一个实例来调用,这意味着必须先调用它的构造函数。如果在内存充足的情况下,像上面的表达式是可以接受的;但内存不足时,就会带来问题。
一个简单的解决方案,可以避免每次需要生成一个随机数时创建一个新实例,那就是使用一个静态类。猜你可能想到了java.lang.Math,很好,我们就是改良java.lang.Math的初始化。虽然这个工程量低,但你也要做一些简单的单元测试来确保其不会出错。
假设程序需要生成一个随机数来存储,问题就又来了。比如有时需要操作或保护种子(seed),一个内部数用来存储状态和计算下一个随机数。在这些特殊情况下,共用随机生成对象是不合适的。
并发
在Java EE多线程应用程序的环境中,随机生成实例对象仍然可以被存储在类或其他实现类,作为一个静态属性。幸运的是,java.util.Random是线程安全的,所以不存在多个线程调用会破坏种子(seed)的风险。
另一个值得考虑的是多线程java.lang.ThreadLocal的实例。偷懒的做法是通过Java本身API实现单一实例,当然你也可以确保每一个线程都有自己的一个实例对象。
虽然Java没有提供一个很好的方法来管理java.util.Random的单一实例。但是,期待已久的Java 7提供了一种新的方式来产生随机数:
- java.util.concurrent.ThreadLocalRandom.current().nextInt(10)
这个新的API综合了其他两种方法的优点:单一实例/静态访问,就像Math.random()一样灵活。ThreadLocalRandom也比其他任何处理高并发的方法要更快。
经验
Chris Marasti-Georg 指出:
- Math.round(Math.random() * 10)
使分布不平衡,例如:0.0 - 0.499999将四舍五入为0,而0.5至1.499999将四舍五入为1。那么如何使用旧式语法来实现正确的均衡分布,如下:
- Math.floor(Math.random() * 11)
幸运的是,如果我们使用java.util.Random或java.util.concurrent.ThreadLocalRandom就不用担心上述问题了。
Java实战项目里面介绍了一些不正确使用java.util.Random API的危害。这个教训告诉我们不要使用:
- Math.abs(rnd.nextInt())%n
而使用:
- rnd.nextInt(n)
package com.wss;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
public class GPS_GNSS_XML_Color {
//删除节点时传入的参数
private static String deleteNumber;
//修改节点时传入的参数
private static String updateNumber;
//读取传入的路径,返回一个document对象
public static Document loadInit(String filePath){
Document document = null;
try{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(new File(filePath));
document.normalize();
return document;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}
}
/**
* 删除制定的xml
* @param filePath
* @return
*/
public static boolean deleteXML(String filePath){
deleteNumber = "421f481e-790c-41be-91e3-27d215b73ce2";
Document document = loadInit(filePath);
try{
NodeList nodeList = document.getElementsByTagName("color");
for(int i=0; i<nodeList.getLength(); i++){
String number_ = document.getElementsByTagName("number").item(i).getFirstChild().getNodeValue();
//删除节点时传入的参数
if(number_.equals(deleteNumber)){
Node node = nodeList.item(i);
node.getParentNode().removeChild(node);
saveXML(document, filePath);
}
}
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 修改制定的xml
* @param filePath
* @return
*/
public static boolean updateXML(String filePath){
updateNumber = "421f481e-790c-41be-91e3-27d215b73ce2";
//读取传入的路径,返回一个document对象
Document document = loadInit(filePath);
try{
//获取叶节点
NodeList nodeList = document.getElementsByTagName("color");
//遍历叶节点
for(int i=0; i<nodeList.getLength(); i++){
String number = document.getElementsByTagName("number").item(i).getFirstChild().getNodeValue();
String colorValue = document.getElementsByTagName("colorValue").item(i).getFirstChild().getNodeValue();
Double minValue = Double.parseDouble(document.getElementsByTagName("minValue").item(i).getFirstChild().getNodeValue());
Double maxValue = Double.parseDouble(document.getElementsByTagName("maxValue").item(i).getFirstChild().getNodeValue());
//修改节点时传入的参数
if(number.equals(updateNumber)){
document.getElementsByTagName("colorValue").item(i).getFirstChild().setNodeValue("black");
document.getElementsByTagName("minValue").item(i).getFirstChild().setNodeValue("2222");
document.getElementsByTagName("maxValue").item(i).getFirstChild().setNodeValue("22222");
System.out.println();
}
}
saveXML(document, filePath);
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 添加节点
* @param filePath
* @return
*/
public static boolean addXML(String filePath){
try{
//读取传入的路径,返回一个document对象
Document document = loadInit(filePath);
//创建叶节点
Element eltColor = document.createElement("color");
Element eltNumber = document.createElement("number");//创建叶节点的第一个元素
Element eltColorValue = document.createElement("colorValue");//创建叶节点的第二个元素
Element eltMinValue = document.createElement("minValue");//创建叶节点的第三个元素
Element eltMaxValue = document.createElement("maxValue");//创建叶节点的第四个元素
Text number_ = document.createTextNode(UUID.randomUUID().toString());//创建叶节点的第一个元素下的文本节点
eltNumber.appendChild(number_);//把该文本节点加入到叶节点的第一个元素里面
Text colorValue_ = document.createTextNode("colorValue");//创建叶节点的第二个元素下的文本节点
eltColorValue.appendChild(colorValue_);//把该文本节点加入到叶节点的第二个元素里面
Text minValue_ = document.createTextNode("100");//创建叶节点的第三个元素下的文本节点
eltMinValue.appendChild(minValue_);//把该文本节点加入到叶节点的第三个元素里面
Text maxValue_ = document.createTextNode("200");//创建叶节点的第四个元素下的文本节点
eltMaxValue.appendChild(maxValue_);//把该文本节点加入到叶节点的第四个元素里面
//把叶节点下的元素加入到叶节点下
eltColor.appendChild(eltNumber);
eltColor.appendChild(eltColorValue);
eltColor.appendChild(eltMinValue);
eltColor.appendChild(eltMaxValue);
//获取根节点
Element eltRoot = document.getDocumentElement();
//把叶节点加入到根节点下
eltRoot.appendChild(eltColor);
//更新修改后的源文件
saveXML(document, filePath);
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 把修改后的document写进源文件(更新源文件)
* @param document
* @param filePath
* @return
*/
public static boolean saveXML(Document document, String filePath){
try{
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(new File(filePath));
transformer.transform(source, result);
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 获取xml文件的所有记录
* @param filePath
* @return
*/
public static List<ColorValue> selectXML(String filePath){
List<ColorValue> colorValueList = new ArrayList<ColorValue>();
try{
//读取传入的路径,返回一个document对象
Document document = loadInit(filePath);
//获取叶节点
NodeList nodeList = document.getElementsByTagName("color");
//遍历叶节点
for(int i=0; i<nodeList.getLength(); i++){
ColorValue colorValue = new ColorValue();
String number_ = document.getElementsByTagName("number").item(i).getFirstChild().getNodeValue();
String colorValue_ = document.getElementsByTagName("colorValue").item(i).getFirstChild().getNodeValue();
Double minValue_ = Double.parseDouble(document.getElementsByTagName("minValue").item(i).getFirstChild().getNodeValue());
Double maxValue_ = Double.parseDouble(document.getElementsByTagName("maxValue").item(i).getFirstChild().getNodeValue());
colorValue.setNumber(number_);
colorValue.setColorValue(colorValue_);
colorValue.setMinValue(minValue_);
colorValue.setMaxValue(maxValue_);
colorValueList.add(colorValue);
}
return colorValueList;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}
}
}
package com.wss;
public class ColorValue {
private String number;
private String colorValue;
private Double minValue;
private Double maxValue;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getColorValue() {
return colorValue;
}
public void setColorValue(String colorValue) {
this.colorValue = colorValue;
}
public Double getMinValue() {
return minValue;
}
public void setMinValue(Double minValue) {
this.minValue = minValue;
}
public Double getMaxValue() {
return maxValue;
}
public void setMaxValue(Double maxValue) {
this.maxValue = maxValue;
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Colors>
<color>
<number>7007b384-fab3-4779-9171-229d0664b6b5</number>
<colorValue>black</colorValue>
<minValue>2222</minValue>
<maxValue>22222</maxValue>
</color>
<color>
<number>421f481e-790c-41be-91e3-27d215b73ce2</number>
<colorValue>colorValue</colorValue>
<minValue>100</minValue>
<maxValue>200</maxValue>
</color>
</Colors>
// 写文件UTF-8格式 写一行
public static void writerTxtFile(String filePath, String text) {
OutputStreamWriter fs;
try {
fs = new OutputStreamWriter(new FileOutputStream(filePath, true), "UTF-8");
fs.write(text + "\n");
fs.flush();
fs.close();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 写文件UTF-8格式 写一行
public static void writerStringBuffer(String filePath, StringBuffer text) {
OutputStreamWriter fs;
try {
fs = new OutputStreamWriter(new FileOutputStream(filePath, true), "UTF-8");
fs.write(text + "\n");
fs.flush();
fs.close();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 写文件
public static void writerTxtFile(String filePath, List<String> list) {
OutputStreamWriter fs;
try {
fs = new OutputStreamWriter(new FileOutputStream(filePath, true), "UTF-8");
for(int i=0; i<list.size(); i++){
fs.write(list.get(i) + "\n");
}
fs.flush();
fs.close();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
package dateapp;
import java.util.Date;
import java.util.Calendar;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
//import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.JSpinner.NumberEditor;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import javax.swing.border.LineBorder;
public class DateChooseJButton extends JButton {
private DateChooser dateChooser = null;
private String preLabel = "";
public DateChooseJButton() {
this(getNowDate());
}
public DateChooseJButton(SimpleDateFormat df, String dateString) {
this();
setText(df, dateString);
}
public DateChooseJButton(Date date) {
this("", date);
}
public DateChooseJButton(String preLabel, Date date) {
if (preLabel != null)
this.preLabel = preLabel;
setDate(date);
setBorder(null);
setCursor(new Cursor(Cursor.HAND_CURSOR));
super.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (dateChooser == null)
dateChooser = new DateChooser();
Point p = getLocationOnScreen();
p.y = p.y + 30;
dateChooser.showDateChooser(p);
}
});
}
private static Date getNowDate() {
return Calendar.getInstance().getTime();
}
private static SimpleDateFormat getDefaultDateFormat() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
// 覆盖父类的方法
public void setText(String s) {
Date date;
try {
date = getDefaultDateFormat().parse(s);
} catch (ParseException e) {
date = getNowDate();
}
setDate(date);
}
public void setText(SimpleDateFormat df, String s) {
Date date;
try {
date = df.parse(s);
} catch (ParseException e) {
date = getNowDate();
}
setDate(date);
}
public void setDate(Date date) {
super.setText(preLabel + getDefaultDateFormat().format(date));
}
public Date getDate() {
String dateString = getText().substring(preLabel.length());
try {
return getDefaultDateFormat().parse(dateString);
} catch (ParseException e) {
return getNowDate();
}
}
// 覆盖父类的方法使之无效
public void addActionListener(ActionListener listener) {
}
private class DateChooser extends JPanel implements ActionListener,
ChangeListener {
int startYear = 1980; // 默认【最小】显示年份
int lastYear = 2050; // 默认【最大】显示年份
int width = 400; // 界面宽度
int height = 200; // 界面高度
Color backGroundColor = Color.gray; // 底色
// 月历表格配色----------------//
Color palletTableColor = Color.white; // 日历表底色
Color todayBackColor = Color.orange; // 今天背景色
Color weekFontColor = Color.blue; // 星期文字色
Color dateFontColor = Color.black; // 日期文字色
Color weekendFontColor = Color.red; // 周末文字色
// 控制条配色------------------//
Color controlLineColor = Color.pink; // 控制条底色
Color controlTextColor = Color.white; // 控制条标签文字色
Color rbFontColor = Color.white; // RoundBox文字色
Color rbBorderColor = Color.red; // RoundBox边框色
Color rbButtonColor = Color.pink; // RoundBox按钮色
Color rbBtFontColor = Color.red; // RoundBox按钮文字色
JDialog dialog;
JSpinner yearSpin;
JSpinner monthSpin;
JSpinner hourSpin;
JComboBox minSpin;
JComboBox secondBox;
JButton[][] daysButton = new JButton[6][7];
DateChooser() {
setLayout(new BorderLayout());
setBorder(new LineBorder(backGroundColor, 2));
setBackground(backGroundColor);
JPanel topYearAndMonth = createYearAndMonthPanal();
add(topYearAndMonth, BorderLayout.NORTH);
JPanel centerWeekAndDay = createWeekAndDayPanal();
add(centerWeekAndDay, BorderLayout.CENTER);
}
private JPanel createYearAndMonthPanal() {
Calendar c = getCalendar();
int currentYear = c.get(Calendar.YEAR);
int currentMonth = c.get(Calendar.MONTH) + 1;
int currentHour = c.get(Calendar.HOUR_OF_DAY);
int currentMin = c.get(Calendar.MINUTE);
int currentSecond = c.get(Calendar.SECOND);
JPanel result = new JPanel();
result.setLayout(new FlowLayout());
result.setBackground(controlLineColor);
yearSpin = new JSpinner(new SpinnerNumberModel(currentYear,
startYear, lastYear, 1));
yearSpin.setPreferredSize(new Dimension(48, 20));
yearSpin.setName("Year");
yearSpin.setEditor(new JSpinner.NumberEditor(yearSpin, "####"));
yearSpin.addChangeListener(this);
result.add(yearSpin);
JLabel yearLabel = new JLabel("年");
yearLabel.setForeground(controlTextColor);
result.add(yearLabel);
monthSpin = new JSpinner(new SpinnerNumberModel(currentMonth, 1,
12, 1));
monthSpin.setPreferredSize(new Dimension(35, 20));
monthSpin.setName("Month");
monthSpin.addChangeListener(this);
result.add(monthSpin);
JLabel monthLabel = new JLabel("月");
monthLabel.setForeground(controlTextColor);
result.add(monthLabel);
hourSpin = new JSpinner(new SpinnerNumberModel(currentHour, 0, 23,
1));
hourSpin.setPreferredSize(new Dimension(35, 20));
hourSpin.setName("Hour");
hourSpin.addChangeListener(this);
result.add(hourSpin);
JLabel hourLabel = new JLabel("时");
hourLabel.setForeground(controlTextColor);
result.add(hourLabel);
minSpin = new JComboBox();
;
addComboBoxItem(minSpin);
minSpin.setPreferredSize(new Dimension(45, 20));
minSpin.setName("Min");
minSpin.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent e) {
JComboBox source = (JComboBox) e.getSource();
Calendar c = getCalendar();
if (source.getName().equals("Min")) {
c.set(Calendar.MINUTE, getSelectedMin());
setDate(c.getTime());
return;
}
}
});
result.add(minSpin);
JLabel minLabel = new JLabel("分");
hourLabel.setForeground(controlTextColor);
result.add(minLabel);
secondBox = new JComboBox();
addComboBoxItem(secondBox);
secondBox.setPreferredSize(new Dimension(45, 20));
secondBox.setName("Second");
// secondBox.addActionListener(this) ;
secondBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent e) {
JComboBox source = (JComboBox) e.getSource();
Calendar c = getCalendar();
if (source.getName().equals("Second")) {
c.set(Calendar.SECOND, getSelectedSecond());
setDate(c.getTime());
return;
}
}
});
result.add(secondBox);
JLabel secondLabel = new JLabel("秒");
hourLabel.setForeground(controlTextColor);
result.add(secondLabel);
return result;
}
private void addComboBoxItem(JComboBox comboBox) {
for (int i = 0; i < 60; i++) {
comboBox.addItem(i);
}
}
private JPanel createWeekAndDayPanal() {
String colname[] = { "日", "一", "二", "三", "四", "五", "六" };
JPanel result = new JPanel();
// 设置固定字体,以免调用环境改变影响界面美观
result.setFont(new Font("宋体", Font.PLAIN, 12));
result.setLayout(new GridLayout(7, 7));
result.setBackground(Color.white);
JLabel cell;
for (int i = 0; i < 7; i++) {
cell = new JLabel(colname[i]);
cell.setHorizontalAlignment(JLabel.RIGHT);
if (i == 0 || i == 6)
cell.setForeground(weekendFontColor);
else
cell.setForeground(weekFontColor);
result.add(cell);
}
int actionCommandId = 0;
for (int i = 0; i < 6; i++)
for (int j = 0; j < 7; j++) {
JButton numberButton = new JButton();
numberButton.setBorder(null);
numberButton.setHorizontalAlignment(SwingConstants.RIGHT);
numberButton.setActionCommand(String
.valueOf(actionCommandId));
numberButton.addActionListener(this);
numberButton.setBackground(palletTableColor);
numberButton.setForeground(dateFontColor);
if (j == 0 || j == 6)
numberButton.setForeground(weekendFontColor);
else
numberButton.setForeground(dateFontColor);
daysButton[i][j] = numberButton;
result.add(numberButton);
actionCommandId++;
}
return result;
}
private JDialog createDialog(Frame owner) {
JDialog result = new JDialog(owner, "日期时间选择", true);
result.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
result.getContentPane().add(this, BorderLayout.CENTER);
result.pack();
result.setSize(width, height);
return result;
}
void showDateChooser(Point position) {
Frame owner = (Frame) SwingUtilities
.getWindowAncestor(DateChooseJButton.this);
if (dialog == null || dialog.getOwner() != owner)
dialog = createDialog(owner);
dialog.setLocation(getAppropriateLocation(owner, position));
flushWeekAndDay();
dialog.show();
}
Point getAppropriateLocation(Frame owner, Point position) {
Point result = new Point(position);
Point p = owner.getLocation();
int offsetX = (position.x + width) - (p.x + owner.getWidth());
int offsetY = (position.y + height) - (p.y + owner.getHeight());
if (offsetX > 0) {
result.x -= offsetX;
}
if (offsetY > 0) {
result.y -= offsetY;
}
return result;
}
private Calendar getCalendar() {
Calendar result = Calendar.getInstance();
result.setTime(getDate());
return result;
}
private int getSelectedYear() {
return ((Integer) yearSpin.getValue()).intValue();
}
private int getSelectedMonth() {
return ((Integer) monthSpin.getValue()).intValue();
}
private int getSelectedHour() {
return ((Integer) hourSpin.getValue()).intValue();
}
private int getSelectedMin() {
return (Integer) this.minSpin.getSelectedItem();
}
private int getSelectedSecond() {
return (Integer) this.secondBox.getSelectedItem();
}
private void dayColorUpdate(boolean isOldDay) {
Calendar c = getCalendar();
int day = c.get(Calendar.DAY_OF_MONTH);
c.set(Calendar.DAY_OF_MONTH, 1);
int actionCommandId = day - 2 + c.get(Calendar.DAY_OF_WEEK);
int i = actionCommandId / 7;
int j = actionCommandId % 7;
if (isOldDay)
daysButton[i][j].setForeground(dateFontColor);
else
daysButton[i][j].setForeground(todayBackColor);
}
private void flushWeekAndDay() {
Calendar c = getCalendar();
c.set(Calendar.DAY_OF_MONTH, 1);
int maxDayNo = c.getActualMaximum(Calendar.DAY_OF_MONTH);
int dayNo = 2 - c.get(Calendar.DAY_OF_WEEK);
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 7; j++) {
String s = "";
if (dayNo >= 1 && dayNo <= maxDayNo)
s = String.valueOf(dayNo);
daysButton[i][j].setText(s);
dayNo++;
}
}
dayColorUpdate(false);
}
public void stateChanged(ChangeEvent e) {
JSpinner source = (JSpinner) e.getSource();
Calendar c = getCalendar();
if (source.getName().equals("Hour")) {
c.set(Calendar.HOUR_OF_DAY, getSelectedHour());
setDate(c.getTime());
return;
}
dayColorUpdate(true);
if (source.getName().equals("Year"))
c.set(Calendar.YEAR, getSelectedYear());
else
// (source.getName().equals("Month"))
c.set(Calendar.MONTH, getSelectedMonth() - 1);
setDate(c.getTime());
flushWeekAndDay();
}
public void actionPerformed(ActionEvent e) {
JButton source = (JButton) e.getSource();
if (source.getText().length() == 0)
return;
dayColorUpdate(true);
source.setForeground(todayBackColor);
int newDay = Integer.parseInt(source.getText());
Calendar c = getCalendar();
c.set(Calendar.DAY_OF_MONTH, newDay);
setDate(c.getTime());
}
}
public static void main(String[] args){
new JButton();
}
}
上述日期控件继承JButton,使用时只要构造出来JButton对象就行了。
package com.wss;
import java.awt.BorderLayout;
public class SearchTest extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTextField latitude;
private JTextField longitude;
private JTextField max;
private JTextField min;
private JTextField center;
private JComboBox begin;
private JComboBox end;
private JTable table;
private DefaultTableModel dm;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SearchTest frame = new SearchTest();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public SearchTest() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getToolkit();
setSize(Toolkit.getDefaultToolkit().getScreenSize());
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.NORTH);
JLabel label = new JLabel("纬度:");
panel.add(label);
latitude = new JTextField();
panel.add(latitude);
latitude.setColumns(10);
JLabel label_1 = new JLabel("经度:");
panel.add(label_1);
longitude = new JTextField();
panel.add(longitude);
longitude.setColumns(10);
JLabel label_2 = new JLabel("时间:");
panel.add(label_2);
//获取数据库里的时间正序输出
List<GPSBean> list_ = BusinessSelect.selectTime("select distinct to_char(obvdatetime,'YYYY-mm-dd HH24:MI:SS') t from gps order by t asc");
String[] time = new String[list_.size()];
for(int a=0; a<list_.size(); a++){
time[a] = list_.get(a).getTime();
}
begin = new JComboBox(time);
panel.add(begin);
JLabel label_3 = new JLabel("至");
panel.add(label_3);
end = new JComboBox(time);
panel.add(end);
JButton close = new DateChooseJButton();
panel.add(close);
//点击事件
search.addActionListener(new SearchTest_search_actionAdapter(this));
JPanel panel_1 = new JPanel();
contentPane.add(panel_1, BorderLayout.CENTER);
String name[] = {"ID","时间","纬度","经度","值"};
String sql = "select * from gps order by id desc";
List<GPSBean> list = BusinessSelect.selectGPS(sql);
Object gpsValue[][] = new Object[list.size()][5];
for(int i=0; i<list.size(); i++){
GPSBean gpsBean = list.get(i);
Object value[] =
{
gpsBean.getId(),
gpsBean.getObvdateTime(),
gpsBean.getLongitude(),
gpsBean.getLatitude(),
gpsBean.getTecvalue()
};
for(int j=0; j<value.length; j++){
gpsValue[i][j] = value[j];
}
}
dm = new DefaultTableModel(gpsValue, name);
table = new JTable(dm);
table.setPreferredScrollableViewportSize(new Dimension(800,600));
JScrollPane scrollPane = new JScrollPane(table);
panel_1.add(scrollPane);
JPanel panel_s = new JPanel();
contentPane.add(panel_s, BorderLayout.SOUTH);
JLabel max_ = new JLabel("最大值:");
panel_s.add(max_);
max = new JTextField();
panel_s.add(max);
max.setColumns(10);
JLabel min_ = new JLabel("最小值:");
panel_s.add(min_);
min = new JTextField();
panel_s.add(min);
min.setColumns(10);
JLabel center_ = new JLabel("中值:");
panel_s.add(center_);
center = new JTextField();
panel_s.add(center);
center.setColumns(10);
}
public void search_actionPerformed(ActionEvent e){
dm.setRowCount(0);
String latitude_value = latitude.getText();
String longitude_value = longitude.getText();
String begin_value = begin.getSelectedItem().toString();
String end_value = end.getSelectedItem().toString();
String sql = "";
if(latitude_value.equals("") && longitude_value.equals("")){
sql = "select * from (select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS') as d, latitude, longitude, tecvalue, abs(latitude-0) a, abs(longitude-0) b " +
"from gps where obvdateTime>=TO_DATE('"+begin_value
+"','YYYY-mm-dd HH24:MI:SS') and obvdateTime<=TO_DATE('"+end_value
+"','YYYY-mm-dd HH24:MI:SS') order by a asc, b asc) where a<3 and b<5 order by d asc, a asc,b asc";
}else{
sql = "select * from (select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS') as d, latitude, longitude, tecvalue, abs(latitude-"
+Double.parseDouble(latitude_value)
+") a, abs(longitude-"+Double.parseDouble(longitude_value)
+") b from gps where obvdateTime>=TO_DATE('"+begin_value
+"','YYYY-mm-dd HH24:MI:SS') and obvdateTime<=TO_DATE('"+end_value
+"','YYYY-mm-dd HH24:MI:SS') order by a asc, b asc) where a<3 and b<5 order by d asc, a asc,b asc";
}
ResultSet rs = CommontDAO.selectFile(sql);
Vector<Object> v;
String time = "2011-02-28 00:00:00";
List<GPSBean> gpsBeanList = new ArrayList<GPSBean>();
try{
while(rs.next()){
if(time.equals(rs.getString(2)) || time == rs.getString(2)){
}else{
GPSBean gpsBean = new GPSBean();
gpsBean.setId(Integer.parseInt(rs.getString(1)));
gpsBean.setObvdateTime(rs.getString(2));
gpsBean.setLatitude(Double.parseDouble(rs.getString(3)));
gpsBean.setLongitude(Double.parseDouble(rs.getString(4)));
gpsBean.setTecvalue(Double.parseDouble(rs.getString(5)));
gpsBeanList.add(gpsBean);
time = rs.getString(2);
v = new Vector<Object>();
v.add(rs.getString(1));
v.add(rs.getString(2));
v.add(rs.getString(3));
v.add(rs.getString(4));
v.add(rs.getString(5));
dm.addRow(v);
}
}
}catch(Exception ex){
ex.printStackTrace();
System.out.println(ex.getMessage());
}finally{
CommontDAO.cloes(rs);
Double tecValue[] = new Double[gpsBeanList.size()];
for(int i=0; i<gpsBeanList.size(); i++){
tecValue[i] = gpsBeanList.get(i).getTecvalue();
}
Double center_value = Sort.center(tecValue);
Double max_value = Sort.max(tecValue);
Double min_value = Sort.min(tecValue);
max.setText(max_value+"");
min.setText(min_value+"");
center.setText(center_value+"");
}
}
}
class SearchTest_search_actionAdapter implements ActionListener {
private SearchTest adaptee;
SearchTest_search_actionAdapter(SearchTest adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.search_actionPerformed(e);
}
}
package com.wss;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.sql.*;
import java.util.*;
public class BusinessSelect {
//根据sql查询记录
public static List<GPSBean> selectGPS(String sql){
ResultSet rs = null;
List<GPSBean> list = new ArrayList<GPSBean>();
try{
rs = CommontDAO.selectFile(sql);
while(rs.next()){
GPSBean gpsBean = new GPSBean();
gpsBean.setId(Integer.parseInt(rs.getString(1)));
gpsBean.setObvdateTime(rs.getString(2));
gpsBean.setLongitude(Double.parseDouble(rs.getString(3)));
gpsBean.setLatitude(Double.parseDouble(rs.getString(4)));
gpsBean.setTecvalue(Double.parseDouble(rs.getString(5)));
list.add(gpsBean);
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5));
}
return list;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}finally{
CommontDAO.cloes(rs);
}
}
//搜索(根据经度和纬度查询最近一点的记录)
public static List<GPSBean> selectGPS(Double latitude_, Double longitude_){
ResultSet rs = null;
List<GPSBean> list = new ArrayList<GPSBean>();
try{
//获取比指定点大的最近的1个值
String sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(latitude-"+latitude_+") a from gps order by a desc";
rs = CommontDAO.selectFile(sql);
while(rs.next()){
System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6));
}
System.out.println("---------------------------------------------------------------------------");
sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(longitude-"+longitude_+") b from gps order by b desc";
rs = CommontDAO.selectFile(sql);
while(rs.next()){
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5));
System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6));
}
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(latitude-"+latitude_+") a, abs(longitude-"+longitude_+") b from gps order by a asc, b asc";
//重要
// sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(latitude-"+latitude_+") a, abs(longitude-"+longitude_+") b from gps where obvdateTime>=TO_DATE('2011-03-01 00:00:00','YYYY-mm-dd HH24:MI:SS') and obvdateTime<=TO_DATE('2011-03-01 02:00:00','YYYY-mm-dd HH24:MI:SS') order by a asc, b asc";
while(rs.next()){
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5));
System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6)+","+rs.getString(7));
}
return list;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}finally{
CommontDAO.cloes(rs);
}
}
//搜索(根据经度和纬度查询最近一点的记录)
public static List<GPSBean> selectGPS(Double latitude_, Double longitude_, String begin, String end){
ResultSet rs = null;
List<GPSBean> list = new ArrayList<GPSBean>();
String sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(latitude-"+latitude_+") a, abs(longitude-"+longitude_+") b from gps where obvdateTime>=TO_DATE('"+begin+"','YYYY-mm-dd HH24:MI:SS') and obvdateTime<=TO_DATE('"+end+"','YYYY-mm-dd HH24:MI:SS') order by a asc, b asc";
rs = CommontDAO.selectFile(sql);
String test = "";
try{
while(rs.next()){
GPSBean gpsBean = new GPSBean();
gpsBean.setId(Integer.parseInt(rs.getString(1)));
gpsBean.setObvdateTime(rs.getString(2));
gpsBean.setLatitude(Double.parseDouble(rs.getString(3)));
gpsBean.setLongitude(Double.parseDouble(rs.getString(4)));
gpsBean.setTecvalue(Double.parseDouble(rs.getString(5)));
list.add(gpsBean);
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6)+","+rs.getString(7));
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5));
// test += rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6)+","+rs.getString(7)+"\r\n";
}
// File f = new File("D:/test.txt");
// OutputStream out = new FileOutputStream(f,true);
// out.write(test.getBytes());
return list;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}finally{
CommontDAO.cloes(rs);
}
}
//获取时间
public static List<GPSBean> selectTime(String sql){
ResultSet rs = null;
List<GPSBean> list = new ArrayList<GPSBean>();
try{
rs = CommontDAO.selectFile(sql);
while(rs.next()){
GPSBean gpsBean = new GPSBean();
gpsBean.setTime(rs.getString(1));
list.add(gpsBean);
}
return list;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}finally{
CommontDAO.cloes(rs);
}
}
}
package com.wss;
public class GPSBean {
private int id;
private String obvdateTime;
private double longitude;
private double latitude;
private double tecvalue;
private String time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getObvdateTime() {
return obvdateTime;
}
public void setObvdateTime(String obvdateTime) {
this.obvdateTime = obvdateTime;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getTecvalue() {
return tecvalue;
}
public void setTecvalue(double tecvalue) {
this.tecvalue = tecvalue;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
package com.wss;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import com.db.DBConnectionManager;
public class CommontDAO {
private static DBConnectionManager dbcm = DBConnectionManager.getInstance();
//insert语句(支持多条sql)
public static boolean insertFile(String sql){
Connection con = null;
Statement st = null;
try{
con = dbcm.getConnection();
st = con.createStatement();
sql = sql.substring(0, sql.length()-1);
String[] num = sql.split(";");
for(int i=0; i<num.length; i++){
st.addBatch(num[i]);
}
st.executeBatch();
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}finally{
close(con, st);
}
}
//select语句(返回一个ResultSet)
public static ResultSet selectFile(String sql){
Connection con = null;
Statement st = null;
ResultSet rs = null;
try{
con = dbcm.getConnection();
st = con.createStatement();
rs = st.executeQuery(sql);
return rs;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return rs;
}
}
public static void close(Connection con){
try{
if(con != null){
con.close();
}
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
}
}
public static void close(Connection con, Statement st){
try{
if(st != null){
st.close();
}
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
}
close(con);
}
public static void close(Connection con, Statement st, ResultSet rs){
try{
if(rs != null){
rs.close();
}
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
}
close(con, st);
}
public static void cloes(ResultSet rs){
try{
if(rs != null){
rs.close();
}
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
package com.wss;
public class Sort {
//求最大值
public static Double max(Double[] value){
//把数组第一个值最为一个标志
Double num1 = value[0];
//中间变量
Double temp = 0.0;
for(int i=1; i<value.length; i++){
if(num1 < value[i]){
temp = num1;
num1 = value[i];
value[i] = temp;
}
}
return num1;
}
//求最小值
public static Double min(Double[] value){
//把数组第一个值最为一个标志
Double num1 = value[0];
//中间变量
Double temp = 0.0;
for(int i=0; i<value.length; i++){
if(num1 > value[i]){
temp = num1;
num1 = value[i];
value[i] = temp;
}
}
return num1;
}
//求中值
public static Double center(Double[] value){
Double temp = 0.0;
//排序
for(int i=0; i<value.length; i++){
for(int j=i+1; j<value.length; j++){
if(value[i] > value[j]){
temp = value[j];
value[j] = value[i];
value[i] = temp;
}
}
}
//求中值所在的下标位置
int num = value.length/2;
return value[num];
}
public static void main(String[] args){
Double value[] = {4.0, 1.0, 2.0, 3.0};
System.out.println(Sort.center(value));
}
}
DWR(Direct Web Remoting)是一个WEB远程调用框架.利用这个框架可以让AJAX开发变得很简单.利用DWR可以在客户端利用JavaScript直接调用服务端的Java方法并返回值给JavaScript就好像直接本地客户端调用一样(DWR根据Java类来动态生成JavaScrip代码).它的最新版本DWR0.6添加许多特性如:支持Dom Trees的自动配置,支持Spring(JavaScript远程调用spring bean),更好浏览器支持,还支持一个可选的commons-logging日记操作.
以上摘自open-open,它通过反射,将java翻译成javascript,然后利用回调机制,轻松实现了javascript调用Java代码。
其大概开发过程如下:
1.编写业务代码,该代码是和dwr无关的。
2.确认业务代码中哪些类、哪些方法是要由javascript直接访问的。
3.编写dwr组件,对步骤2的方法进行封装。
4.配置dwr组件到dwr.xml文件中,如果有必要,配置convert,进行java和javascript类型互转。
5.通过反射机制,dwr将步骤4的类转换成javascript代码,提供给前台页面调用。
5.编写网页,调用步骤5的javascript中的相关方法(间接调用服务器端的相关类的方法),执行业务逻辑,将执行结果利用回调函数返回。
6.在回调函数中,得到执行结果后,可以继续编写业务逻辑的相关javascript代码。
下面以用户注册的例子,来说明其使用。(注意,本次例子只是用于演示,说明DWR的使用,类设计并不是最优的)。
1.先介绍下相关的Java类
User: 用户类,
public class User {
//登陆ID,主键唯一
private String id;
//姓名
private String name;
//口令
private String password;
//电子邮件
private String email;
//以下包含getXXX和setXXX方法
.......
}
UserDAO:实现User的数据库访问,这里作为一个演示,编写测试代码
public class UserDAO {
//存放保存的数据
private static Map dataMap = new HashMap();
//持久用户
public boolean save(User user) {
if (dataMap.containsKey(user.getId()))
return false;
System.out.println("下面开始保存用户");
System.out.println("id:"+user.getId());
System.out.println("password:"+user.getPassword());
System.out.println("name:"+user.getName());
System.out.println("email:"+user.getEmail());
dataMap.put(user.getId(), user);
System.out.println("用户保存结束");
return true;
}
//查找用户
public User find(String id) {
return (User)dataMap.get(id);
}
}
DWRUserAccess:DWR组件,提供给javascript访问的。
public class DWRUserAccess {
UserDAO userDAO = new UserDAO();
public boolean save(User user) {
return userDAO.save(user);
}
public User find(String id) {
return userDAO.find(id);
}
}
下面说明下程序执行的流程
1.用户在页面上输入相关注册信息,id、name、password、email,点击“提交”按钮
2.javascript代码开始执行,根据用户填写相关信息,通过dwr提供的DWRUserAccess.js里save的方法,调用服务器端的DWRUserAccess类save方法,将注册信息保存。
3.通过DWRUserAccess.jsp里的find方法,调用服务器端DWRUserAccess类里的find方法,执行用户信息查找。
注意,在以上的执行过程中,DWRUserAccess是供DWR调用的,是DWR组件,因此需要将DWRUserAccess类配置到dwr中。
接下来讲解本次dwr测试环境的配置。
1.新建一个webapp,命名为testApp
2.将dwr.jar拷贝到testApp的WEB-INF的lib目录下
3.编译上面的User,UserDAO,DWRUserAccess类,放到classes目录下
4.在web.xml中配置servlet,适配路径到dwr目录下,如下所示
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<description>Direct Web Remoter Servlet</description>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>scriptCompressed</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
以上的配置可以拦截testApp下所有指向dwr的请求,关于这个拦截器,我们会在后面介绍。
5.WEB-INF下新建一个dwr.xml文件,内容如下:
< xml version="1.0" encoding="UTF-8" >
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<allow>
<create creator="new" javascript="DWRUserAccess">
<param name="class" value="test.DWRUserAccess"/>
</create>
<convert converter="bean" match="test.User"/>
</allow>
</dwr>
这里我们把DWRUserAccess配置到了dwr中,create元素中,creater="new"表示每调用一次DWRUserAccess时,需要new一个这样的类;javascript="DWRUserAccess",表示提供给前台页面调用的javascirpt文件是DWRUserAccess.js。
convert元素用于数据类型转换,即java类和javascript之间相互转换,因为和前台交换的是User对象,因此需要对此使用bean转换,我们将在后面介绍这个类。
4.编写测试的HTML页面 test.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>DWR测试</TITLE>
<meta http-equiv=Content-Type content="text/html; charset=gb2312">
<script src="/oblog312/dwr/engine.js"></script>
<script src="/oblog312/dwr/util.js"></script>
<script src="/oblog312/dwr/interface/DWRUserAccess.js"></script>
</HEAD>
<BODY>
<B>用户注册</B><br>
------------------------------------------------
<Br>
<form name="regForm">
登陆ID:<input type="text" name="id"><br>
口 令:<input type="password" name="password"><br>
姓 名:<input type="text" name="name"><br>
电子邮件:<input type="text" name="email"><br>
<input type="button" name="submitBtn" value="提交" onclick="OnSave()"><br>
</form>
<br>
<br><B>用户查询</B><br>
------------------------------------------------
<Br>
<form name="queryForm">
登陆ID:<input type="text" name="id"><br>
<input type="button" name="submitBtn" value="提交" onclick="OnFind()"><br>
</form>
<br>
</BODY>
</HTML>
<SCRIPT LANGUAGE="JavaScript">
<!--
function saveFun(data) {
if (data) {
alert("注册成功!");
} else {
alert("登陆ID已经存在!");
}
}
function OnSave() {
var userMap = {};
userMap.id = regForm.id.value;
userMap.password = regForm.password.value;
userMap.name = regForm.name.value;
userMap.email = regForm.email.value;
DWRUserAccess.save(userMap, saveFun);
}
function findFun(data) {
if (data == null) {
alert("无法找到用户:"+queryForm.id.value);
return;
}
alert("找到用户,nid:"+data.id+",npassword:"+data.password+",nname:"+data.name+",nemail:"+data.email);
}
function OnFind() {
DWRUserAccess.find(queryForm.id.value, findFun);
}
//-->
</SCRIPT>
以下对页面的javascript进行解释
<script src="/oblog312/dwr/engine.js"></script>
<script src="/oblog312/dwr/util.js"></script>
这两个是dwr提供的,用户可以不必关心,只需要导入即可
<script src="/oblog312/dwr/interface/DWRUserAccess.js"></script>
是我们编写的DWRUserAccess类,经dwr反射后,生成的javascript代码,它和DWRUserAccess.java是对应的,供用户调用,实际上我们就是通过这个js文件去调用服务器端的DWRUserAccess类的。
<SCRIPT LANGUAGE="JavaScript">
<!--
function saveFun(data) {
if (data) {
alert("注册成功!");
} else {
alert("用户名已经存在!");
}
}
function OnSave() {
var userMap = {};
userMap.id = regForm.id.value;
userMap.password = regForm.password.value;
userMap.name = regForm.name.value;
userMap.email = regForm.email.value;
DWRUserAccess.save(userMap, saveFun);
}
function findFun(data) {
if (data == null) {
alert("无法找到用户:"+queryForm.id.value);
return;
}
alert("找到用户,nid:"+data.id+",npassword:"+data.password+",nname:"+data.name+",nemail:"+data.email);
}
function OnFind() {
DWRUserAccess.find(queryForm.id.value, findFun);
}
//-->
</SCRIPT>
这段javascirpt代码,我们来看下OnSave函数,首先它构造一个map,将表单数据都设置到map中,然后调用DWRUserAccess.save(userMap, saveFun),执行save操作。大家可以注意到,服务器端的DWRUserAccess中的save方法是这样的:boolean save(User user),其参数是一个User对象,返回一个boolean值;而客户端的方法是这样的:save(userMap,saveFun),第一个参数userMap是javascirpt中的map对象,在这里相当于服务器端的User对象(在服务器端执行时,会通过convert转换成User对象),前面我们提到dwr是利用回调函数来返回执行结果的,第二个参数saveFun即是一个回调函数。在函数function saveFun(data)中,data是执行结果,这里是一个bool值,非常简单的,我们通过判断data是否为真,可以知道用户名是否重复,用户是否注册成功。
看一下OnFind查找函数,执行结果在回调函数findFun(data)中,因为服务器端返回的是一个User对象,通过convert,将会转换成javascript的一个map对象,
于是在findFun中,通过data.id、data.name、data.password、data.email我们可以轻松的访问到这个User对象。
好了配置完毕,启动服务器,在目录中打入localhost/testApp/test.html。
1.在“用户注册”表单中,id框中输入admin,password中输入123456,name中输入chenbug,email中输入chenbug@zj.com,点击提交按钮,弹出对话框:“注册成功”,在服务器后台可以看到信息如下:
下面开始保存用户
id:admin
password:123456
name:chenbug
email:chenbug@zj.com
用户保存结束
再次点击提交按钮,弹出对话框“登陆ID已经存在”。
2.在“用户查询”对话框中,输入登陆ID为admin,点击提交按钮,提示找到用户,并显示相关信息,输入admin123,点击提交按钮,提示无法找到用户。
至此,测试结束。
后续:
1。拦截器 uk.ltd.getahead.dwr.DWRServlet
该类拦截所有指向dwr目录下的请求,并调用Processor的handler方法进行处理,在uk.ltd.getahead.dwr.impl.DefaultProcessor下,我们可以看到详细的处理过程。
if (pathInfo.length() == 0 ||
pathInfo.equals(HtmlConstants.PATH_ROOT) ||
pathInfo.equals(req.getContextPath()))
{
resp.sendRedirect(req.getContextPath() + servletPath + HtmlConstants.FILE_INDEX);
}
else if (pathInfo.startsWith(HtmlConstants.FILE_INDEX))
{
index.handle(req, resp);
}
else if (pathInfo.startsWith(HtmlConstants.PATH_TEST))
{
test.handle(req, resp);
}
else if (pathInfo.startsWith(HtmlConstants.PATH_INTERFACE))
{
iface.handle(req, resp);
}
else if (pathInfo.startsWith(HtmlConstants.PATH_EXEC))
{
exec.handle(req, resp);
}
else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_ENGINE))
{
file.doFile(req, resp, HtmlConstants.FILE_ENGINE, HtmlConstants.MIME_JS);
}
else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_UTIL))
{
file.doFile(req, resp, HtmlConstants.FILE_UTIL, HtmlConstants.MIME_JS);
}
else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_DEPRECATED))
{
file.doFile(req, resp, HtmlConstants.FILE_DEPRECATED, HtmlConstants.MIME_JS);
}
else
{
log.warn("Page not found (" + pathInfo + "). In debug/test mode try viewing /[WEB-APP]/dwr/"); //$NON-NLS-1$ //$NON-NLS-2$
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
}
通过判断request请求的servlet路径,进行处理,大家可以自己去参看,这里不详细讨论。
2.bean转换器,<convert converter="bean" match="test.User"/>
将dwr.jar解压缩,在路径ukltdgetaheaddwr下可以看到dwr.xml,这里配置了系统默认的一些转换器,
<converter id="bean" class="uk.ltd.getahead.dwr.convert.BeanConverter"/>即是刚才用到User类的转换器,进入代码我们来看看它是如何在javascript和java间进行转换的。
打开BeanConverter代码,定位到函数
public Object convertInbound(Class paramType, InboundVariable iv, InboundContext inctx) throws ConversionException
即是将javascript对象转换成java对象的,其中
paramType即Class类型,在上面的例子中是test.User,
InboundVariable iv,是传入的值,通过iv.getValue可以得到传入的javascript值串
InboundContext inctx,是入口参数上下文,用于保存转换的后java对象。
因为前台传入的是一个javascript的map类型,而map肯定是以{开始和以}结束的,于是在这个函数一开始进行了判断
if (!value.startsWith(ConversionConstants.INBOUND_MAP_START))
{
throw new IllegalArgumentException(Messages.getString("BeanConverter.MissingOpener", ConversionConstants.INBOUND_MAP_START)); //$NON-NLS-1$
}
if (!value.endsWith(ConversionConstants.INBOUND_MAP_END))
{
throw new IllegalArgumentException(Messages.getString("BeanConverter.MissingCloser", ConversionConstants.INBOUND_MAP_START)); //$NON-NLS-1$
}
javascript中,map里各个项是用逗号连接的,如var userMap = {id:'admin',password:'123456',name:'chenbug',email:'chenbug@zj.com'};而每个项的键值对是用冒号连接的,
在convertInbound函数的接下来的处理中,即是通过分析map字串,通过paramType构造java实例(即User类),然后通过反射,将这些键值对设置到java实例中,并返回。
这样就完成了javascript到java的转换。
另一个函数
public String convertOutbound(Object data, String varname, OutboundContext outctx) throws ConversionException
即是将java对象转换为javascript对象(其实是声明和赋值语句)。
Object data ,是待转换的java对象
String varname,是javascript中的该对象的变量名
OutboundContext outctx,传出参数上下文,用于保存转换后的javascript值
StringBuffer buffer = new StringBuffer();
buffer.append("var "); //$NON-NLS-1$
buffer.append(varname);
buffer.append("={};"); //$NON-NLS-1$
这里声明了map类型的变量。
即下来来的代码即是通过反射进行变量赋值,如下
buffer.append(varname);
buffer.append('.');
buffer.append(name);
buffer.append('=');
buffer.append(nested.getAssignCode());
buffer.append(';');
大家可以自己去参看更多的代码。
3.dwr本身提供了一个测试环境,大家在配置完后,可以在IE中输入地址http://localhost/testApp/dwr/index.html,看到配置的各DWR组件,并进行相关测试。
先准备好软件:
Apache官方下载地址:apache_2.0.55-win32-x86-no_ssl.msi,更多版本在这里;
php官方下载地址:php-5.0.5-Win32.zip,更多镜像下载地址,更多版本下载;
mysql官方下载地址:mysql-4.1.14-win32.zip,更多镜像下载地址,更多版本下载。
一、安装Apache,配置成功一个普通网站服务器
运行下载好的“apache_2.0.55-win32-x86-no_ssl.msi”,出现如下界面:
出现Apache HTTP Server 2.0.55的安装向导界面,点“Next”继续
确认同意软件安装使用许可条例,选择“I accept the terms in the license agreement”,点“Next”继续
将Apache安装到Windows上的使用须知,请阅读完毕后,按“Next”继续
设置系统信息,在Network Domain下填入您的域名(比如:goodwaiter.com),在Server Name下填入您的服务器名称(比如:www.goodwaiter.com,也就是主机名加上域名),在Administrator's Email Address下填入系统管理员的联系电子邮件地址(比如:yinpeng@xinhuanet.com),上述三条信息仅供参考,其中联系电子邮件地址会在当系统故障时提供给访问者,三条信息均可任意填写,无效的也行。下面有两个选择,图片上选择的是为系统所有用户安装,使用默认的80端口,并作为系统服务自动启动;另外一个是仅为当前用户安装,使用端口8080,手动启动。一般选择如图所示。按“Next”继续。]
选择安装类型,Typical为默认安装,Custom为用户自定义安装,我们这里选择Custom,有更多可选项。按“Next”继续
出现选择安装选项界面,如图所示,左键点选“Apache HTTP Server 2.0.55”,选择“This feature, and all subfeatures, will be installed on local hard drive.”,即“此部分,及下属子部分内容,全部安装在本地硬盘上”。点选“Change...”,手动指定安装目录。
我这里选择安装在“D:\”,各位自行选取了,一般建议不要安装在操作系统所在盘,免得操作系统坏了之后,还原操作把Apache配置文件也清除了。选“OK”继续。
返回刚才的界面,选“Next”继续。
确认安装选项无误,如果您认为要再检查一遍,可以点“Back”一步步返回检查。点“Install”开始按前面设定的安装选项安装。
正在安装界面,请耐心等待,直到出现下面的画面。
安装向导成功完成,这时右下角状态栏应该出现了下面的这个绿色图标,表示Apache服务已经开始运行,按“Finish”结束Apache的软件安装
我们来熟悉一下这个图标,很方便的,在图标上左键单击,出现如下界面,有“Start(启动)”、“Stop(停止)”、“Restart(重启动)”三个选项,可以很方便的对安装的Apache服务器进行上述操作。
好了现在我们来测试一下按默认配置运行的网站界面,在IE地址栏打“http://127.0.0.1”,点“转到”,就可以看到如下页面,表示Apache服务器已安装成功。
现在开始配置Apache服务器,使它更好的替我们服务,事实上,如果不配置,你的安装目录下的Apache2\htdocs文件夹就是网站的默认根目录,在里面放入文件就可以了。这里我们还是要配置一下,有什么问题或修改,配置始终是要会的,如图所示,“开始”、“所有程序”、“Apache HTTP Server 2.0.55”、“Configure Apache Server”、“Edit the Apache httpd conf Configuration file”,点击打开。
XP的记事本有了些小变化,很实用的一个功能就是可以看到文件内容的行、列位置,按下图所示,点“查看”,勾选“状态栏”,界面右下角就多了个标记,“Ln 78, Col 10”就表示“行 78,列 10”,这样可以迅速的在文件中定位,方便解说。当然,你也可以通过“编辑”,“查找”输入关键字来快速定位。每次配置文件的改变,保存后,必须在 Apache服务器重启动后生效,可以用前面讲的小图标方便的控制服务器随时“重启动”。
现在正式开始配置Apache服务器,“Ln 228”,或者查找关键字“DocumentRoot”(也就是网站根目录),找到如下图所示地方,然后将""内的地址改成你的网站根目录,地址格式请照图上的写,主要是一般文件地址的“\”在Apache里要改成“/”。
“Ln 253”,同样,你也可以通过查找“
“Ln321”,DirectoryIndex(目录索引,也就是在仅指定目录的情况下,默认显示的文件名),可以添加很多,系统会根据从左至右的顺序来优先显示,以单个半角空格隔开,比如有些网站的首页是index.htm,就在光标那里加上“index.htm ”文件名是任意的,不一定非得“index.html”,比如“test.php”等,都可以。
这里有一个选择配置选项,以前可能要配置,现在好像修正过来了,不用配置了,就是强制所有输出文件的语言编码,html文件里有语言标记(,这个就是设定文档语言为gb2312)的也会强制转换。如果打开的网页出现乱码,请先检查网页内有没有上述 html语言标记,如果没有,添加上去就能正常显示了。把“# DefaultLanguage nl”前面的“# ”去掉,把“nl”改成你要强制输出的语言,中文是“zh-cn”,保存,关闭。
好了,简单的Apache配置就到此结束了,现在利用先前的小图标重启动,所有的配置就生效了,你的网站就成了一个网站服务器,如果你加载了防火墙,请打开80或8080端口,或者允许Apache程序访问网络,否则别人不能访问。如果你有公网IP(一般ADSL或电话拨号上网的都是),就可以邀请所有能上网的朋友访问使用http://你的IP地址(IP地址查询可访问http://www.goodwaiter.com,查询内容内即是)你的网站了;如果你没有公网IP,也可以把内网IP地址告诉局域网内的其它用户,让他们通过http://你的内网IP地址,访问你的网站。
二、php的安装、以module方式,将php与apache结合使你的网站服务器支持php服务器脚本程序
将下载的php安装文件php-5.0.5-Win32.zip右键解压缩。
指定解压缩的位置,我的设定在“D:\php”
查看解压缩后的文件夹内容,找到“php.ini-dist”文件,将其重命名为“php.ini”,打开编辑,找到下面图中的地方, Ln385,有一个“register_globals = Off”值,这个值是用来打开全局变量的,比如表单送过来的值,如果这个值设为“Off”,就只能用“$_POST['变量名']、$_GET['变量名 ']”等来取得送过来的值,如果设为“On”,就可以直接使用“$变量名”来获取送过来的值,当然,设为“Off”就比较安全,不会让人轻易将网页间传送的数据截取。这个值是否改成“On”就看自己感觉了,是安全重要还是方便重要?
这里还有一个地方要编辑,功能就是使php能够直接调用其它模块,比如访问mysql,如下图所示,Ln563,选择要加载的模块,去掉前面的 “;”,就表示要加载此模块了,加载的越多,占用的资源也就多一点,不过也多不到哪去,比如我要用mysql,就要把“;extension= php_mysql.dll”前的“;”去掉。所有的模块文件都放在php解压缩目录的“ext”之下,我这里的截图是把所有能加载的模块都加载上去了,前面的“;”没去掉的,是因为“ext”目录下默认没有此模块,加载会提示找不到文件而出错。这里只是参考,一般不需要加载这么多,需要的加载上就可以了,编辑好后保存,关闭。
如果上一步加载了其它模块,就要指明模块的位置,否则重启Apache的时候会提示“找不到指定模块”的错误,这里介绍一种最简单的方法,直接将php安装路径、里面的ext路径指定到windows系统路径中——在“我的电脑”上右键,“属性”,选择“高级”标签,点选“环境变量”,在“系统变量”下找到“Path”变量,选择,双击或点击“编辑”,将“;D:\php;D:\php\ext”加到原有值的后面,当然,其中的“D:\php” 是我的安装目录,你要将它改为自己的php安装目录,如下图所示,全部确定。系统路径添加好后要重启电脑才能生效,可以现在重启,也可以在所有软件安装或配置好后重启。
现在开始将php以module方式与Apache相结合,使php融入Apache,照先前的方法打开Apache的配置文件,Ln 173,找到这里,添加进如图所示选中的两行,第一行“LoadModule php5_module D:/php/php5apache2.dll”是指以module方式加载php,第二行“PHPIniDir "D:/php"”是指明php的配置文件php.ini的位置,是当然,其中的“D:/php”要改成你先前选择的php解压缩的目录。
还是Apache的配置文件,Ln 757,加入“AddType application/x-httpd-php .php”、“AddType application/x-httpd-php .html”两行,你也可以加入更多,实质就是添加可以执行php的文件类型,比如你再加上一行“AddType application/x-httpd-php .htm”,则.htm文件也可以执行php程序了,你甚至还可以添加上一行“AddType application/x-httpd-php .txt”,让普通的文本文件格式也能运行php程序。
前面所说的目录默认索引文件也可以改一下,因为现在加了php,有些文件就直接存为.php了,我们也可以把“index.php”设为默认索引文件,优先顺序就自己排了,我的是放在第一位。编辑完成,保存,关闭。
现在,php的安装,与Apache的结合已经全部完成,用屏幕右下角的小图标重启Apache,你的Apache服务器就支持了php。
三、mysql的安装,与php、Apache相结合
打开下载的mysql安装文件mysql-4.1.14-win32.zip,双击解压缩,运行“setup.exe”,出现如下界面
mysql安装向导启动,按“Next”继续
选择安装类型,有“Typical(默认)”、“Complete(完全)”、“Custom(用户自定义)”三个选项,我们选择“Custom”,有更多的选项,也方便熟悉安装过程
在“Developer Components(开发者部分)”上左键单击,选择“This feature, and all subfeatures, will be installed on local hard drive.”,即“此部分,及下属子部分内容,全部安装在本地硬盘上”。在上面的“MySQL Server(mysql服务器)”、“Client Programs(mysql客户端程序)”、“Documentation(文档)”也如此操作,以保证安装所有文件。点选“Change...”,手动指定安装目录。
填上安装目录,我的是“D:\mysql”,也建议不要放在与操作系统同一分区,这样可以防止系统备份还原的时候,数据被清空。按“OK”继续。
返回刚才的界面,按“Next”继续。
确认一下先前的设置,如果有误,按“Back”返回重做。按“Install”开始安装。
正在安装中,请稍候,直到出现下面的界面
这里是询问你是否要注册一个mysql.com的账号,或是使用已有的账号登陆mysql.com,一般不需要了,点选“Skip Sign-Up”,按“Next”略过此步骤。
现在软件安装完成了,出现上面的界面,这里有一个很好的功能,mysql配置向导,不用向以前一样,自己手动乱七八糟的配置my.ini了,将 “Configure the Mysql Server now”前面的勾打上,点“Finish”结束软件的安装并启动mysql配置向导。
mysql配置向导启动界面,按“Next”继续。
选择配置方式,“Detailed Configuration(手动精确配置)”、“Standard Configuration(标准配置)”,我们选择“Detailed Configuration”,方便熟悉配置过程。
选择服务器类型,“Developer Machine(开发测试类,mysql占用很少资源)”、“Server Machine(服务器类型,mysql占用较多资源)”、“Dedicated MySQL Server Machine(专门的数据库服务器,mysql占用所有可用资源)”,大家根据自己的类型选择了,一般选“Server Machine”,不会太少,也不会占满。
选择mysql数据库的大致用途,“Multifunctional Database(通用多功能型,好)”、“Transactional Database Only(服务器类型,专注于事务处理,一般)”、“Non-Transactional Database Only(非事务处理型,较简单,主要做一些监控、记数用,对MyISAM数据类型的支持仅限于non-transactional),随自己的用途而选择了,我这里选择“Transactional Database Only”,按“Next”继续。
对InnoDB Tablespace进行配置,就是为InnoDB 数据库文件选择一个存储空间,如果修改了,要记住位置,重装的时候要选择一样的地方,否则可能会造成数据库损坏,当然,对数据库做个备份就没问题了,这里不详述。我这里没有修改,使用用默认位置,直接按“Next”继续
选择您的网站的一般mysql访问量,同时连接的数目,“Decision Support(DSS)/OLAP(20个左右)”、“Online Transaction Processing(OLTP)(500个左右)”、“Manual Setting(手动设置,自己输一个数)”,我这里选“Online Transaction Processing(OLTP)”,自己的服务器,应该够用了,按“Next”继续
是否启用TCP/IP连接,设定端口,如果不启用,就只能在自己的机器上访问mysql数据库了,我这里启用,把前面的勾打上,Port Number:3306,按“Next”继续
这个比较重要,就是对mysql默认数据库语言编码进行设置,第一个是西文编码,第二个是多字节的通用utf8编码,都不是我们通用的编码,这里选择第三个,然后在Character Set那里选择或填入“gbk”,当然也可以用“gb2312”,区别就是gbk的字库容量大,包括了gb2312的所有汉字,并且加上了繁体字、和其它乱七八糟的字——使用mysql的时候,在执行数据操作命令之前运行一次“SET NAMES GBK;”(运行一次就行了,GBK可以替换为其它值,视这里的设置而定),就可以正常的使用汉字(或其它文字)了,否则不能正常显示汉字。按 “Next”继续。
选择是否将mysql安装为windows服务,还可以指定Service Name(服务标识名称),是否将mysql的bin目录加入到Windows PATH(加入后,就可以直接使用bin下的文件,而不用指出目录名,比如连接,“mysql.exe -uusername -ppassword;”就可以了,不用指出mysql.exe的完整地址,很方便),我这里全部打上了勾,Service Name不变。按“Next”继续。
这一步询问是否要修改默认root用户(超级管理)的密码(默认为空),“New root password”如果要修改,就在此填入新密码(如果是重装,并且之前已经设置了密码,在这里更改密码可能会出错,请留空,并将“Modify Security Settings”前面的勾去掉,安装配置完成后另行修改密码),“Confirm(再输一遍)”内再填一次,防止输错。“Enable root access from remote machines(是否允许root用户在其它的机器上登陆,如果要安全,就不要勾上,如果要方便,就勾上它)”。最后“Create An Anonymous Account(新建一个匿名用户,匿名用户可以连接数据库,不能操作数据,包括查询)”,一般就不用勾了,设置完毕,按“Next”继续。
确认设置无误,如果有误,按“Back”返回检查。按“Execute”使设置生效。
设置完毕,按“Finish”结束mysql的安装与配置——这里有一个比较常见的错误,就是不能“Start service”,一般出现在以前有安装mysql的服务器上,解决的办法,先保证以前安装的mysql服务器彻底卸载掉了;不行的话,检查是否按上面一步所说,之前的密码是否有修改,照上面的操作;如果依然不行,将mysql安装目录下的data文件夹备份,然后删除,在安装完成后,将安装生成的 data文件夹删除,备份的data文件夹移回来,再重启mysql服务就可以了,这种情况下,可能需要将数据库检查一下,然后修复一次,防止数据出错。
与Apache及php相结合,前面已提过,这里再说一下,在php安装目录下,找到先前重命名并编辑过的 php.ini,如下图所示,Ln563,把“;extension=php_mysql.dll”前的“;”去掉,加载mysql模块。保存,关闭后,重启apache就可以了。这里也可以选择其它要加载的模块,去掉前面的“;”,就表示要加载此模块了,加载的越多,占用的资源也就多一点,不过也多不到哪去。所有的模块文件都放在php解压缩目录的“ext”之下,我这里的截图是把所有能加载的模块都加载上去了,前面的“;”没去掉的,是因为“ext” 目录下默认没有此模块,加载会提示找不到文件而出错。这里只是参考,一般不需要加载这么多,需要的加载上就可以了,编辑好后保存,关闭。
同样,加载了模块后,就要指明模块的位置,否则重启Apache的时候会提示“找不到指定模块”的错误,这里介绍一种最简单的方法,直接将 php安装路径、里面的ext路径指定到windows系统路径中——在“我的电脑”上右键,“属性”,选择“高级”标签,点选“环境变量”,在“系统变量”下找到“Path”变量,选择,双击或点击“编辑”,将“;D:\php;D:\php\ext”加到原有值的后面,当然,其中的“D:\php”是我的安装目录,你要将它改为自己的php安装目录,如下图所示,全部确定。系统路径添加好后要重启电脑才能生效,可以现在重启,也可以在所有软件安装或配置好后重启。