package com.leanwo.management.service; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; import java.security.MessageDigest; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.log4j.Logger; import org.springframework.stereotype.Service; import com.leanwo.management.model.ApplicationSetting; /** * 自动更新服务. * * @author YangZhiJie */ public class AutoUpdateService { private static Logger logger = Logger.getLogger(AutoUpdateService.class); /** * 更新的网站. */ private String updateSite; /** * Gets the 更新的网站. * * @return the 更新的网站 */ public String getUpdateSite() { return updateSite; } /** * Sets the 更新的网站. * * @param updateSite the new 更新的网站 */ public void setUpdateSite(String updateSite) { this.updateSite = updateSite; } /** * 检查服务器上是否有可更新的程序 * @return */ public boolean canUpdate(ApplicationSetting setting) { List autoUpdateFileNames = setting.getAutoUpdateFileNames(); if (autoUpdateFileNames == null || autoUpdateFileNames.size() < 1) { return false; } return true; } /** * 从输入流中获取字节数组 * @param inputStream * @return * @throws IOException */ public static byte[] readInputStream(InputStream inputStream) { byte[] buffer = new byte[1024]; int len = 0; ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { while((len = inputStream.read(buffer)) != -1) { bos.write(buffer, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { if(bos != null){ try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } return bos.toByteArray(); } /** * 判断文件是否存在 * @param httpPath * @return */ private static Boolean existHttpPath(String httpPath){ URL httpurl = null; try { httpurl = new URL(new URI(httpPath).toASCIIString()); URLConnection urlConnection = httpurl.openConnection(); // urlConnection.getInputStream(); Long TotalSize=Long.parseLong(urlConnection.getHeaderField("Content-Length")); if (TotalSize <= 0){ return false; } return true; } catch (Exception e) { logger.debug(httpurl + "文件不存在"); return false; } } /** * 确定执行更新. */ public void autoUpdate(ApplicationSetting setting) { //需要更新的文件 List autoUpdateFileNames = setting.getAutoUpdateFileNames(); String savePath = setting.getInstallPath(); //用于保存下载文件的目录 File saveDir = new File(savePath); File tempDir = new File(savePath + "/" + "temp"); String fileName = savePath.substring(savePath.lastIndexOf("\\")+1); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String dateStr = sdf.format(new Date()); URL url; InputStream inputStream = null; FileOutputStream fos = null; try { for (String s : autoUpdateFileNames) { //url请求路径 String requestPath = updateSite + "/" + fileName + "/" + s; //判断需要下载的文件是否存在 if (!existHttpPath(requestPath)) { throw new RuntimeException("需要更新的文件"+ requestPath + "不存在"); } //判断需要下载的文件对应的MD5文件是否存在 String sd = s.substring(0 ,s.lastIndexOf(".")+1)+"md5"; String md5Path = updateSite + "/" + fileName + "/" + sd; //判断需要下载的文件对应的MD5文件是否存在 if (!existHttpPath(md5Path)) { throw new RuntimeException("需要更新的文件"+ requestPath + "的MD5文件不存在"); } //读取远程md5文件中值 url = new URL(md5Path); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); //设置超时间为5秒 conn.setConnectTimeout(5*1000); //防止屏蔽程序抓取而返回403错误 conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //得到输入流 inputStream = conn.getInputStream(); //获取自己的输入流数组 byte[] getData = readInputStream(inputStream); String md5Value = new String(getData); //判断要保存的目录是否存在,不存在就创建 if(!saveDir.exists()){ saveDir.mkdir(); } File file = new File(saveDir + "/" + s); if (file.exists()){ String fileMD5 = getFileMD5(file); if (fileMD5.equals(md5Value)){ throw new RuntimeException("需要更新的文件"+ requestPath + "已经是最新的,暂时要不需要更新"); } //如果元文件存在,且MD5值与远程不一样,移动原文件到old+time文件夹 boolean move1 = moveFileToDir(file, savePath + "/old" + dateStr); if (!move1){ throw new RuntimeException("移动文件"+ file.getAbsolutePath() + "到old时出错"); } //copyFile(file, saveDir + "/old" + dateStr); } if(!tempDir.exists()){ tempDir.mkdir(); } //要更新的文件存在,并且改文件的MD5值与远程不一样 //或者要更新文件在本地不存在,执行更新操作 url = new URL(requestPath); conn = (HttpURLConnection)url.openConnection(); //设置超时间为5秒 conn.setConnectTimeout(5*1000); //防止屏蔽程序抓取而返回403错误 conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //得到输入流 inputStream = conn.getInputStream(); //获取自己的输入流数组 getData = readInputStream(inputStream); fos = new FileOutputStream(new File(tempDir + "/" + s)); fos.write(getData); inputStream.close(); fos.close(); String downloadFileMD5 = getFileMD5(new File(tempDir + "/" + s)); if (!downloadFileMD5.equals(md5Value)){ throw new RuntimeException("更新的文件"+ requestPath + "未下载完整,请重新更新"); } //将temp中的新文件复制到指定目录并解压 boolean move2 = moveFileToDir(new File(tempDir + "/" + s), savePath); if (!move2) { throw new RuntimeException("从temp移动文件"+ requestPath + "到指定目录出错"); } //copyFile(new File(tempDir + "/" + s), savePath); if (s.substring(s.lastIndexOf(".")+1).equals("zip")) { //将更新后的文件解压 unZipFiles(new File(saveDir + "//" + s), savePath+"\\"); } } //unzipFromLoc(savePath); } catch (MalformedURLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if(inputStream!=null){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 解压文件到指定目录 * 解压后的文件名,和之前一致 * @param zipFile 待解压的zip文件 * @param descDir 指定目录 */ public static void unZipFiles(File zipFile, String descDir) { ZipFile zip = null; InputStream in = null; FileOutputStream out = null; try { zip = new ZipFile(zipFile, Charset.forName("gbk")); String name = zip.getName().substring(zip.getName().lastIndexOf('\\')+1, zip.getName().lastIndexOf('.')); File pathFile = new File(descDir+name); //判断解压到的目录是否存在,存在则清空并删除 if (pathFile.exists() && pathFile.isDirectory()) { deleteAllFile(pathFile); } //不存在就创建后解压 pathFile.mkdirs(); for (Enumeration entries = zip.entries(); entries.hasMoreElements();) { ZipEntry entry = (ZipEntry) entries.nextElement(); String zipEntryName = entry.getName(); in = zip.getInputStream(entry); String outPath = (descDir + name +"/"+ zipEntryName).replaceAll("\\*", "/"); // 判断路径是否存在,不存在则创建文件路径 File file = new File(outPath.substring(0, outPath.lastIndexOf('/'))); if (!file.exists()) { file.mkdirs(); } // 判断文件全路径是否为文件夹,如果是,不需要解压 if (new File(outPath).isDirectory()) { continue; } out = new FileOutputStream(outPath); byte[] buf1 = new byte[1024]; int len; while ((len = in.read(buf1)) > 0) { out.write(buf1, 0, len); } } logger.debug("解压完毕"); } catch (IOException e) { e.printStackTrace(); }finally { if (in != null){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (out != null){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 清空并删除指定目录 * @param filePath */ public static void deleteAllFile(File file){ File[] listFiles = file.listFiles(); if (listFiles.length == 0){ file.delete(); }else{ for (File f : listFiles) { if(f.isDirectory()){ deleteAllFile(f); }else{ f.delete(); } } file.delete(); } } /** * 读取指定文件的MD5值 * @param file * @return */ public static String getFileMD5(File file) { if (!file.isFile()) { return null; } MessageDigest digest = null; FileInputStream in = null; byte buffer[] = new byte[2014]; int len; try { digest =MessageDigest.getInstance("MD5"); in = new FileInputStream(file); while ((len = in.read(buffer)) != -1) { digest.update(buffer, 0, len); } BigInteger bigInt = new BigInteger(1, digest.digest()); return bigInt.toString(16); } catch (Exception e) { e.printStackTrace(); return null; } finally { if (in != null){ try { in.close(); } catch (Exception e) { e.printStackTrace(); } } } } /** * 复制文件到指定文件夹下 * @param oldPath * @param newPath * @throws IOException */ public static void copyFile(File file, String newPath) { File newDir = new File(newPath); if (!newDir.exists()){ newDir.mkdirs(); } File newFile = new File(newPath + "/" + file.getName()); FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream(file); out = new FileOutputStream(newFile);; byte[] buffer=new byte[2097152]; while((in.read(buffer)) != -1){ out.write(buffer); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if (in != null){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (out != null){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 移动指定文件到指定目录下 */ public static boolean moveFileToDir(File file, String dirPath){ boolean flag; File saveDir = new File(dirPath); if (!saveDir.exists()){ saveDir.mkdirs(); } flag = file.renameTo(new File(saveDir+"/"+file.getName())); return flag; } }