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


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

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

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

    public class DBConnecter {
    
        private static DBConnecter instance = null;
        private static Connection conn = null;
    
        private DBConnecter() {
        }
    
        public synchronized static DBConnecter getInstance() {
            if (instance == null) {
                instance = new DBConnecter();
            }
            return instance;
        }
        //连接数据库
        public Connection getConnection(String driver, String url) {
            try {
                Class.forName(driver);
                conn = DriverManager.getConnection(url);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
            return conn;
        }
    
        //Close关闭数据库连接 
        public void Close() {
            try {
                conn.close();
            } catch (Exception e) {
            }
        }
    
    }

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

     public class DataWriter {
    
    
        public void writeData(DBConnecter dbcon, List<Map<String, Object>> 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 (Map<String, Object> map : 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<String, Object> map, long datatime) {
            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<String, Object> map, long datatime) {
            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, Map<String, Object> map, 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 static Date dateFormat(String str, String format_str) {
            DateFormat format = new SimpleDateFormat(format_str);
            try {
                return format.parse(str);
            } catch (ParseException ex) {
                Logger.getLogger(DataWriter.class.getName()).log(Level.SEVERE, null, ex);
            }
            return null;
        }
    }

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

    public final class ConfigerReader {
    
    
        private static ConfigerReader instance = null;
        private static Map<String, Object> configerMap = null;
    
        private ConfigerReader() {
        }
    
        public synchronized static ConfigerReader getInstance() {
            if (instance == null) {
                instance = new ConfigerReader();
            }
            return instance;
        }
    
        public Map<String, Object> getConfigerReader(String configerPath) {
            if (configerMap != null) {
                return configerMap;
            }
            InputStream inputStream = null;
            Properties p = new Properties();
            configerMap = new HashMap<String, Object>();
            try {
                inputStream = new FileInputStream(configerPath);
                p.load(inputStream);
                configerMap = new HashMap<String, Object>();
                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);
                }
            }
            return configerMap;
        }
    }


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

    public class DataReader {
    
    
        /**
         * 以行为单位读取文件,常用于读面向行的格式化文件
         */
        public List<Map<String, Object>> readFileByLines(String readFilePath, String backFilePath, int wfid, int stationId) {
            File file = new File(readFilePath);
            File[] flist = file.listFiles();
            BufferedReader reader = null;
            List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
            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(new FileReader(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<String, Object> map = new HashMap<String, Object>();
                        //判断是否含有[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(new File(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());
            return data;
        }
    
    
        //复制文件
        public void copyFile(File sourceFile, File targetFile) {
            System.out.println("复制文件[" + sourceFile.getName() + "]到[" + targetFile.getPath() + "]开始!");
            BufferedInputStream inBuff = null;
            BufferedOutputStream outBuff = null;
            try {
                // 新建文件输入流并对它进行缓冲
                inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
                // 新建文件输出流并对它进行缓冲
                outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));
                // 缓冲数组
                byte[] b = new byte[1024 * 5];
                int len;
                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 void deleteFile(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 extends TimerTask {
    
        @Override
        public void run() {
            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 = new DataWriter();
            DataReader reader = new DataReader();
    
            List<Map<String, Object>> dataMaps = reader.readFileByLines(localDir, backDir,
                    Integer.parseInt(wfId), Integer.parseInt(stationId));
            writer.writeData(dbcon, dataMaps, driver, url);
        }
    
    }

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

    public class WPDAnalysis {
    
        /**
         * @param args the command line arguments
         */
        public static void main(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 = new Timer();
            //设置执行时间
            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(new ReaderTimerTask(), 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(new ReaderTimerTask(), date, Parameter.READERRATE);
            }
        }
    }

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

    public final class Parameter {
    
    
        //主配置文件
        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下面。

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

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

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

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

    #Java的位置
    wrapper.java.command=D:Javajdk1.6.0_31injava
    #如果你系统已经配置了%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序做成服务的主要步骤。


    作者:EliteQing
    出处:http://www.cnblogs.com/liinux/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

    欢迎加入网络爬虫QQ群:322937592 ;数据分析&网络爬虫
    网络爬虫模拟登录开源项目ghost-login:ghost-login
    微信订阅号:网络爬虫AI数据分析【WebCrawlerAIDA】

     
  • 相关阅读:
    Javascript事件模型
    关于node.js(一)
    JavaScript表单编程总结
    使用Dom操纵样式表
    文档对象模型Dom
    浏览器对象模型BOM总结
    在javascript中正则表达式的概念与应用
    CSS块级元素、内联元素概念
    HTTP协议
    [学习记录]BFS思路详解
  • 原文地址:https://www.cnblogs.com/liinux/p/5481815.html
Copyright © 2020-2023  润新知