前言

Java的跨平台功能听起来很诱人可口,号称“Write Once,Run Everywhere”,实际上是“Run Once,Debug Everywh”... 在实际开发过程中还是会遇到各种各样的坑的,刚刚解决了一系列问题,特地写个文章总结一下。

使用Gradle构建Jar包

感谢万能的Gradle,极大提高了Java开发的生产力~

在Gradle中生成jar包可以使用官方的插件:application 来简单生成Jar包,同时还有多种不同的配置可以自定义,了解详情请参照Gradle官方文档。

我这里使用的是一个叫做 shadow 的Gradle插件,把构建jar包的配置都安排得明明白白了,非常的方便!

官方文档:https://imperceptiblethoughts.com/shadow/configuration/#configuring-output-name

下面是 build.gradle 配置参考:

plugins {
id 'com.github.johnrengelman.shadow' version '4.0.3' // Apply the java plugin to add support for Java
id 'java' // Apply the application plugin to add support for building an application
id 'application'
} dependencies {
implementation 'com.github.jengelman.gradle.plugins:shadow:4.0.3'
} // Output to build/libs/name.jar
shadowJar {
baseName = 'name'
classifier = null
version = null
} apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'java'

具体的配置要依照项目的实际需要来配置~

设置完 shadow 插件之后,执行 gradle build 就可以在 build/libs/ 文件夹下面生成你的可执行jar包了,超级方便。

需要更多功能可以查看shadow官网文档,写的很清楚。

访问jar包中的资源

虽然jar包中有各种目录结构,但是jar包本质仍然是一个文件,所以不可以用传统的方法去访问,像 File 类,Class 对象的 getResouce 方法都不行的。

应该使用 ClassLoadergetResourceStream 方法直接获取资源文件的输入流。

例如:

InputStream is=this.getClass().getResourceAsStream("/resource/res.txt");
InputStream is=this.getClass().getClassLoader().getResourceStream("/resource/res.txt");

注意:Class对象和ClassLoader对象的getResourceStream方法也是有不同的,具体的不同可以查看这个笔记:正确获取Java项目资源

访问Jar包中的文件夹

当jar包中的资源文件很多的时候,不可能一个个输入名字去获取,这也太hack了吧,肯定要用自动化的方式来提高生产力。

事实上,访问jar包中的文件夹是挺麻烦的,不过还是找到了取巧的方法,试了一下还是挺好用的。

(不过最好做一下缓存)

代码如下:

String path = getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
JarFile localJarFile = new JarFile(new File(path)); Enumeration<JarEntry> entries = localJarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
String innerPath = jarEntry.getName();
System.out.println(innerPath);
}

使用getClass().getProtectionDomain().getCodeSource().getLocation().getPath(); 来获取当前jar包的路径,如果代码不在jar包中运行的话,获取到的就是当前class文件所在路径。所以在使用之前最好做一下判断,看看程序是否在jar包中运行。

关于JavaFX的Media资源问题

JavaFX可以播放音乐,但是和其他Image、Font资源不同的是,Media对象的构造函数只能接受一个String参数(即文件URL),所以没办法使用getResourceStream方法把文件输入流传入对象。

我查了一下官网,找到了解决办法,把文件URL换成JarURL就可以了,文档:https://docs.oracle.com/javase/6/docs/api/java/net/JarURLConnection.html。

简单示例:

String path = String.format("jar:file:%s!/%s", jarPath, relativePath);
Media media = new Media(path);

注意:relativePath的形式是 media/hello.wav 这样的。

深入Jar包:Gradle构建可执行jar包与访问jar包中文件夹与文件的更多相关文章

  1. Linux 系统下文件夹与文件的读写可执行权限问题

    linux是一个多用户操作系统,linux对文件系统内的所有文件,实行了严格的权限划分管理.防止没有权限的用户访问某个文件.linux文件或目录的权限分为 读.写.可执行三种权限.文件访问的用户类别分 ...

  2. Gradle构建SpringBoot并打包可运行的jar配置

    使用Gradle构建项目,继承了Ant的灵活和Maven的生命周期管理,不再使用XML作为配置文件格式,采用了DSL格式,使得脚本更加简洁. 构建环境: jdk1.6以上,此处使用1.8 Gradle ...

  3. spring boot 打包jar后访问classes文件夹的文件提示地址不存在

    报错内容:class path resource [client.p12] cannot be resolved to absolute file path because it does not r ...

  4. 使用python ftplib包递归下载文件夹及文件

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-06-11 09:35:49 # @Author : Yaheng Wang ...

  5. 修改jar包配置文件的正确操作,jar包解压出来的文件夹重新打成jar,不依靠开发工具!!!!

    修改jar包配置文件的正确操作,有的时候通过一些解压工具可以对内部的文件进行修改,但是有时候会无效.这就很烦了 一.背景:       有一个springboot项目,事先我已经用编译好打成jar包以 ...

  6. 使用 Gradle 构建 Java 项目

    使用 Gradle 构建 Java 项目 这个手册将通过一个简单的 Java 项目向大家介绍如何使用 Gradle 构建 Java 项目. 我们将要做什么? 我们将在这篇文档航中创建一个简单的 Jav ...

  7. gradle构建android项目

    工具: Android Studio2.0 gradle-2.10 一.Android常识 在做Android开发的时候我们首先必须要有一个SDK.一般SDK的主要作用就是将硬件和软件进行分离,做软件 ...

  8. AS Gradle构建工具与Android plugin插件【大全】

    Android plugin version 与 gradle version 的关系 Gradle是一种构建工具,它通过编写一个名为build.gradle的脚本文件对项目进行设置,再根据这个脚本对 ...

  9. 在Editplus中配置java的(带包)编译(javac)和执行(java)的方法

    配置的前提是电脑安装了JDK而且配置好了相关的环境变量(JAVA_HOME,path和classpath). 配置好后在命令行中输入javac和java验证是否配置成功: 假设出现上面的情况则说明配置 ...

随机推荐

  1. Flink SQL 核心概念剖析与编程案例实战

    本次,我们从 0 开始逐步剖析 Flink SQL 的来龙去脉以及核心概念,并附带完整的示例程序,希望对大家有帮助! 本文大纲 一.快速体验 Flink SQL 为了快速搭建环境体验 Flink SQ ...

  2. 风炫安全web安全学习第二十八节课 CSRF攻击原理

    风炫安全web安全学习第二十八节课 CSRF攻击原理 CSRF 简介 跨站请求伪造 (Cross-Site Request Forgery, CSRF),也被称为 One Click Attack 或 ...

  3. node.js常用内置模块一

    在使用内模块的时候需要先将所需的内置模块进行引入. OS模块 在nodejs中OS模块提供了与操作系统相关的属性和方法 // 导入OS内置模块,必须先进行导入,否则无法使用 const os = re ...

  4. 【C++】《C++ Primer 》第九章

    第九章 顺序容器 一.顺序容器概述 顺序容器(sequential container):为程序员提供了控制元素存储和访问顺序的能力.这种顺序不依赖于元素的值,而是与元素加入容器时的位置相对应. 不同 ...

  5. python学习笔记 | macOS Big Sur动态壁纸食用指南

    目录 前言 爬虫篇 壁纸使用篇 后记 前言 北京时间23日凌晨1点,苹果WWDC2020大会开幕.在发布会上,苹果正式发布了新版macOS,并将其命名为"Big Sur". 相比于 ...

  6. MySQL常用字符串函数和日期函数

    数据函数 SELECT ABS(-8); /*绝对值*/ SELECT CEILING(9.4); /*向上取整*/ SELECT FLOOR(9.4); /*向下取整*/ SELECT RAND() ...

  7. docker 安装linux centos 环境

    如何在centos7中使用docker创建一个支持ssh连接的容器 以下内容已有现成的,这里借用下这哥们的帖子https://www.cnblogs.com/caidingyu/p/10642158. ...

  8. MySQL查询截取分析

    一.查询优化 1,mysql的调优大纲 慢查询的开启并捕获 explain+慢SQL分析 show profile查询SQL在Mysql服务器里面的执行细节和生命周期情况 SQL数据库服务器的参数调优 ...

  9. C语言字符串结束符“\0”

    介绍 '\0'就是8位的00000000,因为字符类型中并没有对应的这个字符,所以这么写.'\0'就是 字符串结束标志. '\0'是转译字符,意思是告诉编译器,这不是字符0,而是空字符.空字符\0对应 ...

  10. mysql—if函数

    在mysql中if()函数的具体语法如下:IF(expr1,expr2,expr3),如果expr1的值为true,则返回expr2的值,如果expr1的值为false,则返回expr3的值. 开始实 ...