0%

从CDN(或图床)上给JAVA应用加载必要图片资源

找到问题

在公共课《基础与案例分析》中,当我们做出一个Java小游戏并打包成jar后发现,我们的小游戏依赖的图片无法打包进jar文件运行,并且这些图片只能存放在与jar相同的目录下,这使得我们的小游戏在整体上看不太美观,并且不利于分享或网络传输我们的小游戏。

问题分析

找到办法

我们目前遇到的问题是如何将img图片文件夹在传输过程中去除,并让其不用和jar在同一目录。或者将img图片文件夹与jar打包,并且在用户首次打开的时候能自动整合。

上述两点,经过通过一些搜索引擎搜索发现,实现将img图片文件夹与jar打包的代码太过复杂或者通过把图片存放的文件夹,写到src的路径下,把普通文件夹,改成package包。然后使用如下代码进行图片的获取

1
类.class.getResource("图片路径")

写到src的路径下

并且使用软件将其打包进jar

软件将其打包进jar

不过,这样只是单纯的将img置入jar并不利于后续的更改操作

又因为我的eclipse在jdk/jre方面有些许问题,并不能完美执行上述操作,所以我使用第一种的方法,即img图片文件夹在传输过程中去除,让其不用和jar在同一目录。

问题实现

img图片文件夹在传输过程中去除

这个问题的实现,我们可以让其在通过互联网下载jar小游戏后,运行期间将img文件夹中的图片通过网络下载到本地的目标文件夹,然后通过小游戏代码对目标文件夹中的图片资源进行引用

实现过程

首先,我们创建名为Init的类用来初始化资源并且初始化完毕后转到游戏的入口new GameFrame();

我们希望从网络上下载10个不同命名的图片到本地指定文件夹,并且进行游戏时对其进行引用,目前我们已经在游戏中引用了C:\\ProgramData\\Dreamy Pig\\img中的图片

引用了指定目录下的文件

初始化

Init.java中我们创建函数public static void Init() {}作为初始化的开始。这个函数我们需要在其中做出三件事,即图片的下载及提示、下载完成后的检测、进入游戏

下载图片

我们新建一个类以及函数并且在Init引用:InitTip.Initip();//初始化资源

窗口提示

在这个类中,我们先进行初始化的提示,使用以下代码进行窗口绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class InitTip {
public static void Initip() {
JFrame frame = new InitipFrame();
//事件分派线程
EventQueue.invokeLater(new Runnable() {
public void run() {
//显示窗口
frame.setLocationRelativeTo(null);//窗体居中显示
frame.setTitle("初始化");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);

}
}
);
}
}

class InitipFrame extends JFrame{

//使创建的窗口中有一个带有文本信息的组件
public InitipFrame() {
add(new InitipComponent());//加入组件
pack();//根据组件的大小,自动调整窗口的大小
}

}

class InitipComponent extends JComponent{
// (小原则):尽量不直接设置大小,而是通过常量的方式在实例域中设置
public static final int MESSAGE_X = 75;
public static final int MESSAGE_Y = 100;

private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 200;

//重写paintComponent方法
public void paintComponent(Graphics g) {
g.drawString("正在检测本地资源", MESSAGE_X, MESSAGE_Y);
}

//重写,返回组件的首选大小
public Dimension getPreferredSize() {
return new Dimension(DEFAULT_WIDTH,DEFAULT_HEIGHT);
}

}

检测与创建文件夹

做好窗口绘制后,我们需要进行在线下载资源的整体步骤,一开始,我们需要创建存放图片的文件夹用来存放下载的图片

InitTip函数中、EventQueue.invokeLater后进行以下操作

先判断主文件夹Dreamy Pig是否存在,若不存在则创建文件夹,否则在控制台输出“主文件夹已存在”(使用println自己测试的时候看得到)

然后在主文件夹中判断图片文件夹Img是否存在,若不存在则创建文件夹,否则在控制台输出“图片文件夹已存在”供调试测试时观察。

具体代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
File MainFolder = new File("C:\\ProgramData\\Dreamy Pig");
if (!MainFolder.exists() && !MainFolder.isDirectory()) {
MainFolder.mkdirs();
System.out.println("创建主文件夹");
} else {
System.out.println("主文件夹已存在");
}
File ImgFolder = new File("C:\\ProgramData\\Dreamy Pig\\Img");
if (!ImgFolder.exists() && !ImgFolder.isDirectory()) {
ImgFolder.mkdirs();
System.out.println("创建图片文件夹");
} else {
System.out.println("图片文件夹已存在");
}
检测更新

运用java.net.URL;的特性,从https://i-nmb.cn/pig/update.png下载update.png到本地,然后进行判断是否存在update.png【原理:如果需要更新就上传一张任意照片到服务器使得程序能从目标网址下载图片到本地,若无需更新则在服务器中删除这一图片,使得程序无法下载图片。之后的步骤中只需使用?.exists()函数判断update.png是否存在来代替软件是否存在更新】

代码如下:

1
2
3
4
5
6
7
8
BufferedImage png1 = null;
try {
URL url = new URL("https://i-nmb.cn/pig/update.png");
png1 = ImageIO.read(url);
ImageIO.write(png1, "png", new File("C:\\ProgramData\\Dreamy Pig\\update.png"));
} catch (IOException e) {
e.printStackTrace();
}
检测是否需要初始化或者资源缺失

除了更新要下载资源外,我们的应用第一次启动的初始化以及资源缺失的时候需要下载资源。

首先我们需要将下载的资源名字存在一个作为map的数组里面存入图片的名字

其次,我们用for循环遍历所有资源图片判断是否存在更新或初始化、资源丢失的情况

1
2
3
4
5
6
7
8
9
10
11
12
//检测图片是否都存在
String [] img_name = new String [10];
img_name = new String[]{"barrier.png",
"Barrier_down.png",
"barrier_up.png",
"cloud0.png",
"cloud1.png",
"pig_bk.png",
"pig_down.png",
"pig_normal.png",
"pig_up.png",
};
开始进行更新、初始化

我们首先进行判断是否有更新或者需要初始化及资源缺失。

其次,如果存在更新,我们先使用for循环对旧资源遍历并进行删除。

接着,从我们的图床或主机、CDN上下载图片到本地即可。

最后,关闭初始化窗口并释放资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
        File upd = new File("C:\\ProgramData\\Dreamy Pig\\update.png");
for (int i = 0; i < 9; i++) {
File img = new File("C:\\ProgramData\\Dreamy Pig\\img\\"+img_name[i]);
if(!img.exists()||upd.exists()){

System.out.println("C:\\ProgramData\\Dreamy Pig\\img\\"+img_name[i]+"不存在或存在更新");
//判断是否是更新,如果存在更新就删除原资源
if (upd.exists()) {

new showMessageFrame("正在更新");
for (int k = 0; k < 9; k++) {//批量删除旧资源

File old = new File("C:\\ProgramData\\Dreamy Pig\\img\\" + img_name[k]);
System.out.println("拟删除" + old);

Boolean dpBoolean = old.delete();
System.out.println("删除"+dpBoolean);
if (!dpBoolean&&old.exists()) {
System.out.println( old + " " + "存在" + old.exists());
//打开.bat给予管理员权限
creatBat();//创建bat
new showMessageFrame("正在请求管理员权限");
OpenBat.BatOpen();
System.exit(1);

}
}


File bat = new File("C:\\ProgramData\\Dreamy Pig\\admin.bat");
bat.delete();
boolean deleted = upd.delete();
System.out.println(deleted);//删除更新检测文件
}
//更新需要管理员权限 提示

//进行图片更新
for (int j = 0; j < 9; j++){
new showMessageFrame(img_name[j]+"正在下载");
BufferedImage image0 = null;
try {
URL url = new URL("https://img1.i-nmb.cn/pig/"+img_name[j]);
image0 = ImageIO.read(url);

ImageIO.write(image0, "png", new File("C:\\ProgramData\\Dreamy Pig\\img\\"+img_name[j]));
} catch (IOException e) {
e.printStackTrace();
}

}
if(!img.exists()){
new showMessageFrame(img_name[i]+"加载失败");
}


}else if(img.exists()){
new showMessageFrame("C:\\ProgramData\\Dreamy Pig\\img\\"+img_name[i]+"加载成功");

}
}
frame.dispose();//关闭当前窗口
frame.setVisible(false); //释放资源

若大家和我们一样放入在c盘中,那么可能会遇到管理员权限问题。给予自己管理员权限的操作,之后我会在写一篇文章详细介绍。

弹窗提示

在上述代码中,我们可以见到showMessageFrame这个函数,这个是我们的一个弹窗提示,他会在水平居中、垂直底端对齐的位置弹出加载成功或者其他的一系列提示

演示

我们需要新建一个类及对应函数来实现这个操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class showMessageFrame extends javax.swing.JFrame {
private JLabel text;
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension screensize = tk.getScreenSize();
int height = screensize.height;
int width = screensize.width;
private String str = null;

public showMessageFrame(String str) {
this.str = str;
new Thread(new Runnable() {
@Override
public void run() {
initGUI();
}
}).start();
}

private void initGUI() {
try {
setUndecorated(true);
setLocationRelativeTo(null);
setVisible(true);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
{
text = new JLabel("<html>" + str + "</html>", JLabel.CENTER);
getContentPane().add(text, BorderLayout.CENTER);
text.setBackground(new java.awt.Color(255, 251, 240));
}
pack();
setBounds(width / 2 - 180, height - 150, 360, 100);
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
dispose();
} catch (Exception e) {
e.printStackTrace();
}
}

}

之后我们在Initip()函数中直接引用即可

检测

引用的InitTip函数中下载图片以及提示之后我们还需要在Init函数方法中进行遍历检测,检测下载的图片是否都存在。若不存在则提示资源不存在并且结束for循环,若存在则提示更新完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int jc=1;

//检测是否更新完成
String [] img_name = new String [10];
img_name = new String[]{"barrier.png",
"Barrier_down.png",
"barrier_up.png",
"cloud0.png",
"cloud1.png",
"pig_bk.png",
"pig_down.png",
"pig_normal.png",
"pig_up.png",
};

File upd = new File("C:\\ProgramData\\Dreamy Pig\\update.png");
for (int i = 0; i < 9; i++) {
File img = new File("C:\\ProgramData\\Dreamy Pig\\img\\" + img_name[i]);
if (!img.exists() ) {
boolean deleted = upd.delete();
UpdateFailed.UpdateFailed();
jc=0;
break;
}
}
if (jc==1){DownloadFinish.Finish();}//更新完成

进入游戏

将进入游戏的入口new GameFrame();放置在尾端即可,将程序主入口GameApp.java中的原入口替换为Init.Init();

1
2
3
4
5
public class GameApp {
public static void main(String[] args) {
Init.Init();
}
}
技术分享,如果您觉得内容不错的话不妨进行打赏,您的支持将鼓励我继续创作!
  • 本文作者: i囡漫笔
  • 本文链接: https://i-nmb.cn/net-img.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道