I'm Shendi
最近在写控制台软件,客户端软件,于是就需要增加更新模块,在这里记录一下
目录
思路
首先是服务端和客户端进行通信,一般通过校验版本来判断是否需要更新
如果需要更新则获取需要更新的文件
更新分为几种类型,通过服务端发来的消息来判断,
- 可选更新
- 强制更新(自动更新)
在代码方面,一般都是直接打包成jar,于是直接下载替换就行
其余的配置文件方面的也是如此,通过相对路径
在更新完毕后重新启动.
如果不想重新启动则可以使用自定义类加载器来实现热更新.
实现
这里直接使用控制台
从服务端获取的操作直接省略了(这里需要自己根据自己的需求来对应处理)
代码如下(旧)
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) throws Exception {
// 模拟,需要更新则执行
if (true) {
// 获取到要更新的文件,这里替换成从服务器获取要更新的文件
FileInputStream input = new FileInputStream("../Test.class");
byte[] data = new byte[input.available()];
input.read(data);
input.close();
// 替换
FileOutputStream output = new FileOutputStream("Test.class");
output.write(data);
output.close();
// 重新启动
Runtime.getRuntime().exec("cmd /c start java Test");
System.exit(0);
}
System.out.println("测试,更新前");
// 方便显示,不然窗口弹出就会消失
while (true) {}
}
}
新版
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) throws Exception {
// 模拟,需要更新则执行
if (false) {
// 获取到要更新的文件,这里替换成从服务器获取要更新的文件
FileInputStream input = new FileInputStream("../Test.class");
byte[] data = new byte[input.available()];
input.read(data);
input.close();
// 替换
FileOutputStream output = new FileOutputStream("Test.class");
output.write(data);
output.close();
// 重新启动
Runtime.getRuntime().exec("cmd /c start java Test");
System.exit(0);
}
System.out.println("测试,更新后");
// 方便显示
while (true) {}
}
}
目录结构如下
然后我们编译
到client目录下运行,于是可以看到如下
这时 更新就完成了.
最后,推荐一下我写的工具包(更新时替换文件操作可以使用此工具包的FileUtil类)
https://github.com/1711680493/ShendiKit
解压实现更新(补充附加代码)
上面提供的是思路,下面提供的是一种实用性的更新方式
首先看效果
此种方式使用解压缩包的方式进行更新(JDK 支持zip,不需要第三方jar包)
思路:有一个jar专门用于更新,当需要更新则从服务器下载压缩包(zip,压缩包内容为需要更新的文件),且将压缩包解压到对应目录,覆盖旧的文件,再启动更新后的jar包以达到更新效果
解压缩代码如下
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* 更新工具,用于检测/进行更新.
* <br>
* 创建时间 2021年8月21日 下午6:57:37
* @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
* @version 1.0
*/
public class Update {
public static void main(String[] args) throws IOException {
// TODO 从服务器下载要更新的文件压缩包(zip),下载完后保存到指定目录
// 解压目录,这里取项目根目录
String unzipPath = System.getProperty("user.dir");
// 解压文件到当前文件夹,替换对应文件
ZipFile zip = new ZipFile(unzipPath.concat("/update.zip"));
System.out.println(zip.size());
Enumeration<? extends ZipEntry> e = zip.entries();
while (e.hasMoreElements()) {
ZipEntry ele = e.nextElement();
// 文件路径
String path = unzipPath.concat(File.separatorChar + ele.getName());
if (ele.isDirectory()) {
// 目录则判断是否存在, 不存在则创建
File f = new File(path);
if (!f.exists()) f.mkdirs();
} else {
// 文件则直接解压到指定目录,有对应文件直接替换
System.out.println("文件被替换了:" + path);
FileOutputStream fo = new FileOutputStream(path);
InputStream input = zip.getInputStream(ele);
byte[] data = new byte[input.available()];
input.read(data, 0, data.length);
fo.write(data);
fo.close();
}
}
zip.close();
// 解压完成=更新完成,运行启动类的jar后退出
Runtime.getRuntime().exec("cmd /c start java -jar test.jar");
System.exit(0);
}
}