java程序做成服务_利用JAVA Service Wrapper把JAVA程序做成windows服务

今天做了一个读取数据入库的程序。由于读取的数据每天都更新,于是就想把程序做成一个服务,每天定时执行。研究了一下,发现有几种方式可以做。下面我主要记录一下JAVA Service Wrapper方式。

一、下面是整个程序的功能部分:

1.连接数据库的功能。我写了一个DBConnecter类,是一个单例。

public classDBConnecter {private static DBConnecter instance = null;private static Connection conn = null;privateDBConnecter() {

}public synchronized staticDBConnecter getInstance() {if (instance == null) {

instance= newDBConnecter();

}returninstance;

}//连接数据库

publicConnection getConnection(String driver, String url) {try{

Class.forName(driver);

conn=DriverManager.getConnection(url);

}catch(Exception e) {

System.out.println(e.getMessage());

}returnconn;

}//Close关闭数据库连接

public voidClose() {try{

conn.close();

}catch(Exception e) {

}

}

}

2.然后是针对数据库的一个操作类DataWriter。

public classDataWriter {public void writeData(DBConnecter dbcon, List>maps, String driver, String url) {if (maps == null ||maps.isEmpty()) {

System.out.println("当前没有可写入数据,请等待...");return;

}

Connection con=dbcon.getConnection(driver, url);if (con != null) {try{long datatime = new Date().getTime() / 1000;

System.out.println("写数据开始,当前时间为[" + datatime + "]!");

PreparedStatement pst_insert=con.prepareStatement(Parameter.sql_insert);

PreparedStatement pst_minsert=con.prepareStatement(Parameter.sql_minsert);

PreparedStatement pst_update=con.prepareStatement(Parameter.sql_update);for (Mapmap : maps) {//for (String name : Parameter.pName) {//System.out.println(name + ":" + map.get(name));//}

if(ifHaveRecord(con, map, driver, url)) {

updateData(pst_update, map, datatime);

insertData(pst_minsert, map, datatime);

}else{

insertData(pst_insert, map, datatime);

}

}

pst_insert.executeBatch();

pst_minsert.executeBatch();

pst_update.executeBatch();

con.commit();

dbcon.Close();long time = new Date().getTime() / 1000;

System.out.println("写数据结束,耗时[" + (time - datatime) + "秒]!");

}catch(SQLException ex) {try{

con.rollback();

}catch(SQLException ex1) {

Logger.getLogger(DataWriter.class.getName()).log(Level.SEVERE, null, ex1);

}

}finally{

dbcon.Close();

}

}

}public void insertData(PreparedStatement pst_insert, Map map, longdatatime) {try{

pst_insert.setLong(1, Long.parseLong(map.get(Parameter.pName[0]).toString()));

pst_insert.setLong(2, datatime);

pst_insert.setLong(3, dateFormat(map.get(Parameter.pName[1]).toString(), Parameter.FORMAT_STR).getTime() / 1000);

pst_insert.setObject(4, map.get(Parameter.pName[2]));

pst_insert.setObject(5, map.get(Parameter.pName[3]));

pst_insert.setObject(6, map.get(Parameter.pName[4]));

pst_insert.setObject(7, map.get(Parameter.pName[5]));

pst_insert.setObject(8, map.get(Parameter.pName[6]));

pst_insert.setObject(9, map.get(Parameter.pName[7]));

pst_insert.executeUpdate();//System.out.println(pst_insert.toString() + "_insert");

} catch(SQLException ex) {

Logger.getLogger(DataWriter.class.getName()).log(Level.SEVERE, null, ex);

}

}public void updateData(PreparedStatement pst_update, Map map, longdatatime) {try{

pst_update.setLong(7, Long.parseLong(map.get(Parameter.pName[0]).toString()));

pst_update.setLong(8, dateFormat(map.get(Parameter.pName[1]).toString(), Parameter.FORMAT_STR).getTime() / 1000);

pst_update.setObject(9, map.get(Parameter.pName[2]));

pst_update.setLong(1, datatime);

pst_update.setObject(2, map.get(Parameter.pName[3]));

pst_update.setObject(3, map.get(Parameter.pName[4]));

pst_update.setObject(4, map.get(Parameter.pName[5]));

pst_update.setObject(5, map.get(Parameter.pName[6]));

pst_update.setObject(6, map.get(Parameter.pName[7]));

pst_update.executeUpdate();//System.out.println(pst_update.toString() + "_update");

} catch(SQLException ex) {

Logger.getLogger(DataWriter.class.getName()).log(Level.SEVERE, null, ex);

}

}public boolean ifHaveRecord(Connection con, Mapmap, String driver, String url) {if (con != null) {try{

PreparedStatement pst=(PreparedStatement) con.prepareStatement(Parameter.sql_select);

pst.setLong(1, Long.parseLong(map.get(Parameter.pName[0]).toString()));

pst.setLong(2, dateFormat(map.get(Parameter.pName[1]).toString(), Parameter.FORMAT_STR).getTime() / 1000);

pst.setObject(3, map.get(Parameter.pName[2]));

ResultSet rs=pst.executeQuery();if (rs != null) {return true;

}

}catch(SQLException e) {

Logger.getLogger(DataWriter.class.getName()).log(Level.SEVERE, null, e);

}

}return false;

}public staticDate dateFormat(String str, String format_str) {

DateFormat format= newSimpleDateFormat(format_str);try{returnformat.parse(str);

}catch(ParseException ex) {

Logger.getLogger(DataWriter.class.getName()).log(Level.SEVERE, null, ex);

}return null;

}

}

3.由于我所有的属性值都是通过配置文件得到的,下面是配置文件的读入类ConfigerReader,这也是一个单例。

public final classConfigerReader {private static ConfigerReader instance = null;private static Map configerMap = null;privateConfigerReader() {

}public synchronized staticConfigerReader getInstance() {if (instance == null) {

instance= newConfigerReader();

}returninstance;

}public MapgetConfigerReader(String configerPath) {if (configerMap != null) {returnconfigerMap;

}

InputStream inputStream= null;

Properties p= newProperties();

configerMap= new HashMap();try{

inputStream= newFileInputStream(configerPath);

p.load(inputStream);

configerMap= new HashMap();

configerMap.put(Parameter.WFID, p.getProperty(Parameter.WFID));

configerMap.put(Parameter.STATIONID, p.getProperty(Parameter.STATIONID));

configerMap.put(Parameter.WFNAME, p.getProperty(Parameter.WFNAME));

configerMap.put(Parameter.WFTIME1, p.getProperty(Parameter.WFTIME1));

configerMap.put(Parameter.WFTIME2, p.getProperty(Parameter.WFTIME2));

configerMap.put(Parameter.DRIVER, p.getProperty(Parameter.DRIVER));

configerMap.put(Parameter.URL, p.getProperty(Parameter.URL));

configerMap.put(Parameter.USER, p.getProperty(Parameter.USER));

configerMap.put(Parameter.PWD, p.getProperty(Parameter.PWD));

configerMap.put(Parameter.DB, p.getProperty(Parameter.DB));

configerMap.put(Parameter.LOCALDIR, p.getProperty(Parameter.LOCALDIR));

configerMap.put(Parameter.BACKDIR, p.getProperty(Parameter.BACKDIR));

}catch(IOException ex) {

Logger.getLogger(ConfigerReader.class.getName()).log(Level.SEVERE, null, ex);

}finally{try{

inputStream.close();

}catch(IOException ex) {

Logger.getLogger(ConfigerReader.class.getName()).log(Level.SEVERE, null, ex);

}

}returnconfigerMap;

}

}

4.下面是我的WPD文件读写类DataReader。

public classDataReader {/*** 以行为单位读取文件,常用于读面向行的格式化文件*/

public List> readFileByLines(String readFilePath, String backFilePath, int wfid, intstationId) {

File file= newFile(readFilePath);

File[] flist=file.listFiles();

BufferedReader reader= null;

List> data = new ArrayList>();try{//System.out.println("以行为单位读取文件内容,一次读一整行:");

if (flist == null || flist.length == 0) {

System.out.println("当前没有数据文件!");return null;

}else{

System.out.println("发现" + flist.length + "个文件!");

}for (int i = 0; i < flist.length; i++) {

String name=flist[i].getName();

String currentfile= readFilePath + File.separator +name;//int namelength = name.length();//String fileDate = name.substring(namelength - 12, namelength - 4);//System.out.println("文件的时间为:" + fileDate);

System.out.println("读取第" + (i + 1) + "个文件,文件名为[" + name + "]");

reader= new BufferedReader(newFileReader(currentfile));//一次读入一行,直到读入null为文件结束

int daytype = 1;int stempid = 0;//String time = fileDate.substring(0, 4) + "-" + fileDate.substring(4, 6) + "-" + fileDate.substring(6);

String time = "";

String tempString;//按行来读取文件内容

while ((tempString = reader.readLine()) != null) {

Map map = new HashMap();//判断是否含有[000#]类型的内容

Pattern stapattern = Pattern.compile("[0-9]{3}\\#");

Matcher stamatcher=stapattern.matcher(tempString);if (stamatcher.find()) {//如果包含取出#号前面的数字,若找到说明为新的station数据,重置daytype和time

stempid = Integer.parseInt(stamatcher.group().split("#")[0]);//System.out.println("stempid " + ": " + stempid);

daytype = 1;

time= "";

}if (stempid != stationId && stationId != 0) {//若当前的sId与stationid不符,说明当前的station数据不符合要求,跳出循环

continue;

}//判断是否含有[0000-00-00 00:00:00]时间类型的内容

Pattern timepattern = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}");

Matcher timematcher=timepattern.matcher(tempString);//如果能查询到时间内容

if(timematcher.find()) {//获取时间的日期属性[0000-00-00]

String date = timematcher.group().substring(0, 10);//如果daytype>1的话,就添加daytype到map中

if (daytype > 1) {//用正则表达式获取小数值

Pattern numpattern = Pattern.compile("-?[0-9]+\\.[0-9]{2}");

Matcher nummatcher=numpattern.matcher(tempString);//从pName第三个开始向map中存入值

int pKey = 3;while(nummatcher.find()) {

map.put(Parameter.pName[pKey], nummatcher.group());

pKey++;

}//如果不能找到

if (pKey > 3) {//添加wid到map中

map.put(Parameter.pName[0], wfid);//把nwpdatetime添加到map中

map.put(Parameter.pName[1], timematcher.group());//添加daytype到map中

map.put(Parameter.pName[2], daytype);

data.add(map);

}

}//如果当前日期与上一次日期不一致,daytype加1,并给time赋值

if (!time.equals(date)) {

time=date;

daytype++;

}

}

}

File backFileDir= new File(backFilePath + File.separator +name);if (!backFileDir.exists()) {

file.mkdir();

}

copyFile(newFile(currentfile), backFileDir);

reader.close();

deleteFile(currentfile);

}

}catch(IOException e) {

Logger.getLogger(DataReader.class.getName()).log(Level.SEVERE, null, e);

}finally{if (reader != null) {try{

reader.close();

}catch(IOException ex) {

Logger.getLogger(DataReader.class.getName()).log(Level.SEVERE, null, ex);

}

}

}//System.out.println("数据长度:" + data.size());

returndata;

}//复制文件

public voidcopyFile(File sourceFile, File targetFile) {

System.out.println("复制文件[" + sourceFile.getName() + "]到[" + targetFile.getPath() + "]开始!");

BufferedInputStream inBuff= null;

BufferedOutputStream outBuff= null;try{//新建文件输入流并对它进行缓冲

inBuff = new BufferedInputStream(newFileInputStream(sourceFile));//新建文件输出流并对它进行缓冲

outBuff = new BufferedOutputStream(newFileOutputStream(targetFile));//缓冲数组

byte[] b = new byte[1024 * 5];intlen;while ((len = inBuff.read(b)) != -1) {

outBuff.write(b,0, len);

}//刷新此缓冲的输出流

outBuff.flush();

}catch(IOException ex) {

Logger.getLogger(DataReader.class.getName()).log(Level.SEVERE, null, ex);

}finally{try{if (inBuff != null) {

inBuff.close();//关闭流

}if (outBuff != null) {

outBuff.close();//关闭流

}

}catch(IOException ex) {

Logger.getLogger(DataReader.class.getName()).log(Level.SEVERE, null, ex);

}

}

}//删除文件

public voiddeleteFile(String filepath) {

File file= new File(filepath);//定义文件路径//路径为文件且不为空则进行删除

if (file.isFile() &&file.exists()) {

System.out.println(file.isFile());if(file.delete()) {

System.out.println("删除文件[" + filepath + "]成功!");

}else{

System.out.println("删除文件[" + filepath + "]失败!");

}

}

}

}

我需要根据配置文件的要求获取相应station下面的数据,而且获取的数据入库要求是从00:15:00开始,到下一天00:00:00算一个天。所以在判断的时候,是先放入缓存MAP中,后比较时间标识。

除此,在删除数据文件的时候,一定要先关掉流,再执行删除操作,负责会失败。

5,接下来是定时执行程序ReaderTimerTask,他继承了TimerTask类,在这个类中,获取了配置参数,然后调用了DataReader解析WPD数据,调用DataWriter写入数据库。

public class ReaderTimerTask extendsTimerTask {

@Overridepublic voidrun() {

Map map=ConfigerReader.getInstance().getConfigerReader(Parameter.configer);

String wfId=map.get(Parameter.WFID).toString().trim();if (!"".equals(wfId.toString())) {

System.out.println("获取电场ID成功!");

}else{

System.out.println("获取电场ID失败!");return;

}

String stationId=map.get(Parameter.STATIONID).toString().trim();if (!"".equals(stationId.toString())) {

System.out.println("获取气象站ID成功!");

}else{

System.out.println("获取气象站ID失败!");return;

}

String localDir=map.get(Parameter.LOCALDIR).toString().trim();if (!"".equals(localDir)) {

System.out.println("获取本地文件目录成功!");

}else{

System.out.println("获取本地文件目录失败!");return;

}

String backDir=map.get(Parameter.BACKDIR).toString().trim();if (!"".equals(backDir)) {

System.out.println("获取文件备份目录成功!");

}else{

System.out.println("获取文件备份目录失败!");return;

}

String driver=map.get(Parameter.DRIVER).toString().trim();if (!"".equals(driver)) {

System.out.println("获取数据库驱动成功!");

}else{

System.out.println("获取数据库驱动失败!");return;

}

String url=map.get(Parameter.URL).toString().trim();if (!"".equals(localDir)) {

System.out.println("获取数据库URL成功!");

}else{

System.out.println("获取数据库URL失败!");return;

}

DBConnecter dbcon=DBConnecter.getInstance();if (dbcon != null) {

System.out.println("数据库连接成功!");

}else{

System.out.println("数据库连接失败!");return;

}

DataWriter writer= newDataWriter();

DataReader reader= newDataReader();

List> dataMaps =reader.readFileByLines(localDir, backDir,

Integer.parseInt(wfId), Integer.parseInt(stationId));

writer.writeData(dbcon, dataMaps, driver, url);

}

}

6,最后就是主函数类WPDAnalysis。这个类也获取了读取参数类。并根据读取的参数设置执行时间。

public classWPDAnalysis {/***@paramargs the command line arguments*/

public static voidmain(String[] args) {

Map map=ConfigerReader.getInstance().getConfigerReader(Parameter.configer);

String wftime1=map.get(Parameter.WFTIME1).toString();

String wftime2=map.get(Parameter.WFTIME2).toString();

Timer timer= newTimer();//设置执行时间

Calendar calendar =Calendar.getInstance();int year =calendar.get(Calendar.YEAR);int month =calendar.get(Calendar.MONTH);int day = calendar.get(Calendar.DAY_OF_MONTH);//每天

int hour = 9;int minute = 00;int second = 00;//定制每天的09:00:00执行,

if (!"".equals(wftime1.trim())) {int time =Integer.parseInt(wftime1);

hour= time / 3600;

minute= time % 3600 / 60;

second= time % 3600 % 60;

}

calendar.set(year, month, day, hour, minute, second);

Date date=calendar.getTime();

System.out.println("服务第一次执行开始,当前时间为" +date.toString());

timer.schedule(newReaderTimerTask(), date, Parameter.READERRATE);if (!"".equals(wftime2.trim())) {int time =Integer.parseInt(wftime2);

hour= time / 3600;

minute= time % 3600 / 60;

second= time % 3600 % 60;

calendar.set(year, month, day, hour, minute, second);

System.out.println("服务第二次执行开始,当前时间为" +date.toString());

date=calendar.getTime();

timer.schedule(newReaderTimerTask(), date, Parameter.READERRATE);

}

}

}

除了这些主要功能类,还有一个参数配置类Parameter。程序中所有的参数都能在这个类中找到。

public final classParameter {//主配置文件

public final static String configer = "D:\\Analysis\\configer.properties";//数据库属性

public final static String WFID = "WFID";public final static String STATIONID = "STATIONID";public final static String WFNAME = "WFNAME";public final static String WFTIME1 = "WFTIME1";public final static String WFTIME2 = "WFTIME2";public final static String DRIVER = "DRIVER";public final static String URL = "URL";public final static String USER = "USER";public final static String PWD = "PWD";public final static String DB = "DB";//文件操作属性

public final static String LOCALDIR = "LOCALDIR";public final static String BACKDIR = "BACKDIR";public final static int READERRATE = 10 * 1000;//文本属性

public final static String[] pName = {"wfid", "nwpdate", "daytype", "uavg", "vavg", "temperature", "pressure", "humidity", "vspeed"};public final static String FORMAT_STR = "yyyy-MM-dd HH:mm:ss";//SQL插入语句

public final static String sql_insert = "insert into nwpdata(wfid,datatime,nwptime,daytype,temperature,pressure,humidity) "

+ "values (?,?,?,?,?,?,?)";//SQL备份插入语句

public final static String sql_minsert = "insert into nwpdatam(wfid,datatime,nwptime,daytype,temperature,pressure,humidity) "

+ "values (?,?,?,?,?,?,?)";public final static String sql_update = "update nwpdata set datatime = ?,uavg4 = ?, vavg4 = ?,"

+ "temperature = ?,pressure = ?,humidity = ? "

+ "where wfid = ? and nwptime = ? and daytype = ?";public final static String sql_select = "select * from nwpdata where wfid = ? and nwptime = ? and daytype = ?";

}

程序的配置文件类如下:

[SERVICE]

WFTIME1=28800

WFTIME2=

WFID=1

STATIONID=54

[DATABASE]

TYPE=sql_server

DRIVER=com.microsoft.sqlserver.jdbc.SQLServerDriver

URL=jdbc:sqlserver://192.168.10.104;user=sa;password=cast1234;database=DB

USER=sa

PWD=cast1234

DB=DB

[NRFMNWP]

LOCALDIR=D:\\Analysis\\Output

BACKDIR=D:\\Analysis\\Back

二、整个项目需要打包生成WPDAnalysis.jar,然后我们就可以做我们的window服务了。

第一步在http://wrapper.tanukisoftware.com/doc/english/download.jsp下载我们的java service wrapper工具,下载后解压。工具分32位跟64位,看自己所需。

第二步构建你的程序工作目录,比如我构建D:\WPDAnalysis_64。然后在目录下建造lib,logs,bin,conf等文件夹。其实目录名字也可以自己随便定义,只要最后配置正确即可。同时把你的WPDAnalysis.jar也放在D:\WPDAnalysis_64下面。

第三步把解压后的文件夹中src\bin中的文件复制到新建的bin文件夹下面。并把所有文件的in后缀去掉。同时把解压后文件夹中bin下的wrapper.exe也放到新建的bin下。

第四步把解压后的文件夹中src\conf中的文件复制到新建的conf文件夹中。把in后缀去掉。

第五步把解压后的文件夹中lib中的wrapper.jar与wrapper.dll放大新建的lib下面。同时把WPDAnalysis程序所需要的第三方jar包夜放在这里。我这里使用sqljdbc4.jar。

第六步配置wrapper.conf文件,主要配置选项如下:

#Java的位置

wrapper.java.command=D:\Java\jdk1.6.0_31\bin\java

#如果你系统已经配置了%JAVA_HOME%的环境变量,上面的就可以不配置了。如下:

#wrapper.java.command=%JAVA_HOME%/bin/java

#classpath:

wrapper.java.classpath.1=../WPDAnalysis.jar

wrapper.java.classpath.2=../lib/wrapper.jar

wrapper.java.classpath.3=../lib/sqljdbc4.jar

# Java Library Path (取决于Wrapper.DLL 或者libwrapper.so)

wrapper.java.library.path.1=../lib

#MAIN CLASS 此处决定了使用Java Service Wrapper的方式

wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp

#你的Java应用类,我这里是这样子

wrapper.app.parameter.1=wpdanalysis.WPDAnalysis

#服务名称

wrapper.name=WPDAnalysis_64

#服务部署名称,会显示到window服务中的名称栏

wrapper.displayname=Analysis WPD Data Into DataBase For X64

#服务的描述

wrapper.description=Analysis WPD Data Into DataBase For X64

配置以后,点击bin文件夹下面的App.bat进行测试,如果能够在console中出现正常结果的话就表明配置正确。然后点击InstallApp-NT.bat安装服务,也可以点击UninstallApp-NT.bat卸载服务。成功安装服务后可以在window服务管理中看到哦。

以上就是java序做成服务的主要步骤。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值