一、实际需求
A主机上的“test.mdb”文件(Access数据库文件)通过Java程序发送到B主机某个共享文件夹内,A、B主机处于同一网段,均为Windows操作系统(A主机为Windows7以上版本,B主机Windows版本不作规定),A主机能访问B主机上的某个共享文件夹。
具体要求:
1、A主机上的Java程序每隔3分钟查询Access数据库“test.mdb”有无新增数据,有就发送到B主机上(假定B主机的IP地址为192.168.1.66,共享一文件夹,为administrator用户开放读写权限),没有就啥也不干,继续等待3分钟。
2、A主机上的Java程序必须隐蔽、开机启动、无需人工干预。如果B主机断网或关机则Java程序休息15分钟后继续工作,如果仍然断网,则继续休息15分钟,直到B主机开机联网后恢复每隔3分钟发送数据的模式。
3、只要A主机开机,本Java程序就自动隐蔽运行,永不停歇,直到A主机关机为止。要求能在A主机上查看日志,该日志记录了B主机的IP地址信息、发送数据的时间、成功与否以及每隔3分钟查询数据库的结果信息(是否新增的了数据)。
二、解决方案
编写Java控制台程序,编译成Jar包,在发布的程序目录中设置log文件夹,用于生成日志文件“info.log”,方便查看日志。
关键:Jar程序在Windows平台上开机启动、隐蔽运行。
方案:Jar程序作为Windows服务开机启动、自动运行。
难题:Jar 程序在控制台运行时能正常发送数据,记录日志;一旦作为Windows服务运行后,能记录日志,但是无法访问B主机的IP地址导致无法发送数据(B主机正常联网)。
解决:A主机上使用PSTool工具,将jar程序安装成系统服务,以system权限运行服务方可访问B主机IP地址下共享的文件夹,完成数据发送。
三、操作步骤
1、A主机上的材料准备
(1)Java程序(jar包)、JRE环境
(2)PSRools中的psexec工具
(3)instsrv.exe和srvany.exe工具
2、Windows服务部署准备
(1)编写批处理程序文件——startcopy.bat
用记事本编写bat批处理程序,代码如下:
cd /d %~dp0
ping 192.168.1.66 > %~dp0log\netinfo.txt
java -jar %~dp0sendAccessData.jar
保存名为“startcopy.bat”批处理文件,注意保存时扩展名为“.bat”,把这个批处理文件放在与jar程序文件相同的目录中。该批处理文件首先对IP地址进行了ping测试,并把测试结果用管道符令输出到项目根目录下的“log\netinfo.txt”文件中,然后使用“java -jar”命令运行当前目录下的“sendAccessData.jar”程序,“%~dp0”代表了批处理文件所在的目录(项目根目录),在任何目录下使用java命令运行jar包程序,必须安装JRE或JDK并配置了环境变量。
此时部署项目根目录(根目录名“sendAccessData”),根目录名根据实际情况拟定,本项目根目录结构如下:
(2)拷贝instsrv.exe和srvany.exe到系统目录(32位系统拷贝到“C:\Windows\System32”目录下,64位系统除了拷贝到“C:\Windows\System32”目录下之外还应拷贝到“C:\Windows\SysWOW64”目录下)
(3)拷贝PSRools中的PsExec.exe和PsExec64.exe到系统目录(32位系统拷贝到“C:\Windows\System32”目录下,64位系统除了拷贝到“C:\Windows\System32”目录下之外还应拷贝到“C:\Windows\SysWOW64”目录下)
3、A主机上的部署操作
(1)开启命令行,以管理员身份运行cmd
以Windows10 64位操作系统为例,在开始菜单右边Cortana输入框点击鼠标左键,输入“cmd”,在出现最佳匹配的结果中找到“命令提示符”,如下图:
鼠标移动到其上方后,点击鼠标右键,在弹出的快捷菜单中选择“以管理员身份运行”,在弹出的用户账户控制对话框中选择“是”,开启黑窗口如下图:
注意:黑窗口顶部标题栏一定要有“管理员”字样,否则不是管理员身份运行,后续操作将无效。
(2)在黑窗口输入以下命令:
psexec -i -s cmd.exe
稍等片刻将新开启另一个黑窗口,如下图:
(3)在新开启的黑窗口内输入以下命令:
instsrv SendAccessData C:\WINDOWS\system32\srvany.exe
回车之后,出现如下信息:
The service was successfuly added!
Make sure that you go into the Control Panel and use
the Services applet to change the Account Name and
Password that this newly installed service will use
for its Security Context.
出现了上述信息,表示“srvany.exe”作为Windows服务程序已经安装成功,服务名称为“SendAccessData”,服务程序为“srvany.exe”。
(4)将运行Java程序(Jar包)的批处理程序“startcopy.bat”封装为服务程序“srvany.exe”的具体服务
继续在新开启的黑窗口内输入如下三条命令并回车:
第一条:
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SendAccessData\Parameters\ /v AppDirectory /t REG_SZ /d "D:\数据检测系统\sendAccessData" /f
回车后出现“操作成功完成。”,这一条命令指定应用程序目录键值,向注册表指定的路径下添加键“AppDirectory”,值“D:\数据检测系统\sendAccessData”,键表示服务程序的根目录,用“AppDirectory”标志,值表示服务程序根目录的绝对路径,应根据自己项目根目录实际位置情况来填写。如果你的项目根目录为“send”,位于E盘的project目录下,则项目根目录绝对路径为“E:\project\send”,上面的命令就变更为:
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SendAccessData\Parameters\ /v AppDirectory /t REG_SZ /d "E:\project\send" /f
后面两条命令中的Application键值和AppParameters键值均根据项目实际情况填写。
第二条:
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SendAccessData\Parameters\ /v Application /t REG_SZ /d "D:\数据检测系统\sendAccessData\startcopy.bat" /f
回车后出现“操作成功完成。”,这一条命令指定应用程序键值,用于服务的应用程序为“startcopy.bat”,是我们之前编写好的批处理文件。键名为“ Application”,键值为你的项目中的可执行文件(exe或bat),必须填写完整的绝对路径,这里就是“D:\数据检测系统\sendAccessData\startcopy.bat"。
第三条:
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SendAccessData\Parameters\ /v AppParameters /t REG_SZ /f
回车后出现“操作成功完成。”,这一条命令指定应用程序参数键值,由于该服务程序没有参数,故键名为“AppParameters”,值为空,即不填写任何参数。
四、配置服务并查看运行结果
在A主机上进入Windows服务,找到服务名为“SendAccessData”的服务并选中,如图一:
图一 服务列表
注意观察该服务第四列“登录为”,是以Administrator身份登录运行服务的。因该服务需要访问局域网内B主机内的共享文件夹,该共享文件夹仅对Administrator用户开放了读写权限,A主机服务必须以管理员身份登录。设置步骤为在图一中鼠标双击该服务,在弹出的对话框中选择“登录”选项卡,如下图二:
图二 登录选项卡
在图二中点击“浏览”按钮,弹出如下对话框:
图三 选择用户
图三中点击“高级”按钮,然后再点击“立即查找”按钮,在下方的搜索结果中找到“Administrator”,然后依次点击“确定”按钮,返回到图二,在密码和确认密码两栏输入A主机上Administrator管理员用户的密码,最后点击“确定”按钮即可。
修改该服务为开机自启动,并启动服务,如图四:
图四 修改服务为自动启动
该服务启动后,可以查看“info.log”日志文件信息,根据日志文件信息判断服务程序是否成功运行,如下图:
日志文件反映了服务程序的运行情况,从日志上可以看到,A主机将“test.mdb”发送到B主机IP地址为192.168.1.66的共享文件夹“queryData”内,beginCounts、beginCounts_old标识了读线程在两次读(间隔3分钟)Access数据库的总记录数,如果两次读的总记录数有差异,说明新增了数据,执行发送数据,发送成功则通过日志中的“Copyed successful!”来标志,每一条日志最左边记录了时间。
五、不足之处
Access数据库没有触发器,因此在判断是否有新增数据的时候采用了Java多线程轮询,一个读线程读取Access数据库获得总记录数,另一个读写线程既读数据,又根据两次读的总记录数有无变化来决定是否发送数据。两个线程间隔3分钟,一定程度上影响了A主机的性能以及发送数据的时效性。
如果Access中使用了触发器,则一旦探知新增数据,Java程序就发送数据到B主机,这样既对A主机降低了负担,又增强了适时性。希望高人指点,改进不足。