使用原生Java代码生成可执行Jar包
最近想做一个功能,就是把我们编译后的字节码及其资源文件打包成一个可执行的jar包,在装有jre的机器上双击就能运行。
首先是我们需要选择哪些字节码和文件需要打包到文件中,这个我们用JFileChooser来做,让用户选择,我做了一个窗体来让用户选择。
效果如下:

我们让浏览文件系统,并选择需要打包的文件夹,然后计算出可以作为启动类的文件,通过下方的下拉让用户选择。
生成文件路径在确认按钮点击后弹出文件保存框让用户选择就好(也可以弹出输入框)。
代码如下:
Main
package org.coderecord.commons.ejarmaker; import java.awt.EventQueue; import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException; public class Main { public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() { @Override
public void run() {
new FrmMain().setVisible(true);
}
});
} }
Main
FrmMain(只是界面代码,业务代码最后贴出)
package org.coderecord.commons.ejarmaker; import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List; import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.filechooser.FileFilter; public class FrmMain extends JFrame implements ActionListener { private static final long serialVersionUID = 2016913328739206536L;
// 选择的文件(用户在文件选择器中选择的)
private List<File> userSelectedFiles = new ArrayList<>();
// 我们经过分析得到的最终会被打包的文件
private List<File> finalFiles = new ArrayList<>(); public FrmMain() {
setSize(480, 320);
setResizable(false);
setLocationRelativeTo(null);
setTitle("通用可执行Jar包生成工具");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
// 在运行时获取资源文件的方式,一定是使用Class.getResource方式
// 在jar包中这种方式也行得通
// ‘/’代表根路径
setIconImage(Toolkit.getDefaultToolkit().getImage(FrmMain.class.getResource("/resources/icon.png")));
initComponents();
} // 初始化组件
private void initComponents() {
// 提示
lblTip = new JLabel("选择需要打包的文件并设置启动类");
lblTip.setLocation(20, 10);
lblTip.setSize(350, 20);
add(lblTip); // 浏览按钮
btnBrowser = new JButton("浏 览");
btnBrowser.setLocation(380, 10);
btnBrowser.setSize(80, 24);
btnBrowser.addActionListener(this);
add(btnBrowser); // 展示已选择文件
JScrollPane jspFiles = new JScrollPane();
txtFiles = new JTextArea();
txtFiles.setEditable(false);
jspFiles.setSize(440, 160);
jspFiles.setLocation(20, 40);
txtFiles.setSize(440, 201600);
txtFiles.setLocation(20, 40);
txtFiles.setFocusable(false);
jspFiles.setViewportView(txtFiles);
add(jspFiles); // 选择启动类
cobMainClass = new JComboBox<>();
cobMainClass.setSize(440, 30);
cobMainClass.setLocation(20, 210);
add(cobMainClass); // 清除已选
btnCls = new JButton("重 选");
btnCls.setLocation(20, 250);
btnCls.setSize(80, 24);
btnCls.addActionListener(this);
add(btnCls); // 确认按钮
btnConfirm = new JButton("确认");
btnConfirm.setSize(80, 24);
btnConfirm.setLocation(380, 250);
btnConfirm.addActionListener(this);
add(btnConfirm); // 文件选择器
jfcSelect = new JFileChooser();
// 可以选择文件和文件夹
jfcSelect.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
// 可以多选
jfcSelect.setMultiSelectionEnabled(true); // 文件保存
jfcSave = new JFileChooser();
// 设置只接受以“.jar”结尾的文件
jfcSave.setAcceptAllFileFilterUsed(false);
jfcSave.setFileFilter(new FileFilter() { @Override
public String getDescription() {
return "可执行Jar";
} @Override
public boolean accept(File f) {
return f.getName().endsWith(".jar");
}
});
} @Override
public void actionPerformed(ActionEvent e) { } private JLabel lblTip;
private JButton btnBrowser;
private JFileChooser jfcSelect;
private JTextArea txtFiles;
private JComboBox<String> cobMainClass;
private JButton btnCls;
private JButton btnConfirm;
private JFileChooser jfcSave;
}
FrmMain_UI
然后开始业务部分,首先是选择文件,我们允许用户选择多个文件和文件夹(甚至可以通过多次选择来选择不同盘符、路径下的文件和文件夹),在选择后可能有重复的地方或两次选择后有包含的项目,我们要去除。
我们为“浏览”按钮事件添加处理,让用户选择文件并处理选中文件:
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btnBrowser) {
// 浏览
int result = jfcSelect.showOpenDialog(this); // 选择了文件
if(result == JFileChooser.APPROVE_OPTION) {
for(File file : jfcSelect.getSelectedFiles())
userSelectedFiles.add(file); // 整理选择的文件,去除重复项
removeDuplicateItems(userSelectedFiles); // 重新计算选中文件
finalFiles.clear();
for(File file : userSelectedFiles)
addFileToList(file, finalFiles); // 计算文件展示打包路径及展示路径
// 计算可启动类路径
// 展示到文本框中
cobMainClass.removeAllItems();
txtFiles.setText("");
File file,direc;
String filePath,direcPath;
Iterator<File> itd,itf;
for(itd = userSelectedFiles.iterator(); itd.hasNext();) {
direc = itd.next();
direcPath = direc.getAbsolutePath();
for(itf = finalFiles.iterator(); itf.hasNext();) {
file = itf.next();
filePath = file.getAbsolutePath();
if(filePath.equalsIgnoreCase(direcPath)) {
txtFiles.append(file.getName() + "\n");
filePaths.put(file.getName(), file);
//fileNames.put(file.getName(), file.getName().endsWith(".class")?file.getName().substring(0, file.getName().lastIndexOf('.')):file.getName());
if(file.getName().endsWith(".class"))
cobMainClass.addItem(file.getName().endsWith(".class")?file.getName().substring(0, file.getName().lastIndexOf('.')):file.getName());
itf.remove();
} else if(filePath.startsWith(direcPath)) {
String nameTmp = filePath.substring(direcPath.lastIndexOf(File.separator) + 1).replace(File.separatorChar, '/');
filePaths.put(nameTmp, file);
txtFiles.append(nameTmp + "\n");
//fileNames.put(nameTmp, nameTmp.endsWith(".class")?nameTmp.substring(0, nameTmp.lastIndexOf('.')).replace('/', '.'):nameTmp);
if(nameTmp.endsWith(".class") && nameTmp.indexOf('$') == -1)
cobMainClass.addItem(nameTmp.substring(0, nameTmp.lastIndexOf('.')).replace('/', '.'));
itf.remove();
}
}
}
}
}
} // 添加文件(非文件夹)到集合
private void addFileToList(File file, List<File> fileArr) {
if(file.isDirectory())
for(File child : file.listFiles())
addFileToList(child, fileArr);
else
fileArr.add(file);
} // 去除重复项
private void removeDuplicateItems(List<File> fileArr) {
// 去重复项
Set<String> directories = new HashSet<>();
Set<String> files = new HashSet<>();
for(File file : fileArr)
if(file.isDirectory())
directories.add(file.getAbsolutePath());
else
files.add(file.getAbsolutePath());
//去包含项(先去文件夹再去文件应该更好)
String fpath,dpath;
for(Iterator<String> itf = files.iterator(); itf.hasNext();) {
fpath = itf.next();
for(Iterator<String> itd = directories.iterator(); itd.hasNext();) {
dpath = itd.next();
if(fpath.startsWith(dpath))
itf.remove();
}
}
String dpath1,dpath2;
Set<String> directories1 = new HashSet<>(directories);
for(Iterator<String> itd1 = directories.iterator(); itd1.hasNext();) {
dpath1 = itd1.next();
for(Iterator<String> itd2 = directories1.iterator(); itd2.hasNext();) {
dpath2 = itd2.next();
if(dpath1.equals(dpath2))
continue;
else if(dpath2.startsWith(dpath1))
itd2.remove();
else if(dpath1.startsWith(dpath2))
itd1.remove();
}
}
directories.addAll(directories1); fileArr.clear();
for(String file : files)
fileArr.add(new File(file));
for(String directory : directories)
fileArr.add(new File(directory));
}
btnBrowser_event_handler
“重选”按钮点击后清除已选项,逻辑就先不详细介绍了。
然后是“确定”按钮,我们弹出文件保存框让用户选择保存位置,然后生成可执行的jar包:
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btnBrowser) {
} else if(e.getSource() == btnCls) {
if(userSelectedFiles.size() == 0) return;
else if(JOptionPane.showConfirmDialog(this, "确定重选吗?将清除所有已选项!") == JOptionPane.OK_OPTION) {
userSelectedFiles.clear();
finalFiles.clear();
filePaths.clear();
cobMainClass.removeAllItems();
}
} else if(e.getSource() == btnConfirm) {
if(filePaths.size() == 0) {
JOptionPane.showMessageDialog(this, "未选择文件", "错误", JOptionPane.ERROR_MESSAGE);
return;
} else if(cobMainClass.getSelectedItem() == null) {
JOptionPane.showMessageDialog(this, "未选择启动类", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
// 打包
int result = jfcSave.showSaveDialog(this);
if(result == JFileChooser.APPROVE_OPTION) {
try {
// 清单文件
Manifest man = new Manifest();
// 版本和启动类路径必要
man.getMainAttributes().putValue(Name.MANIFEST_VERSION.toString(), "1.0");
man.getMainAttributes().putValue(Name.MAIN_CLASS.toString(), cobMainClass.getSelectedItem().toString());
// Class-Path一定不要,除非能保证将引用类(即import的类)都联合打包了
JarOutputStream jos = new JarOutputStream(new FileOutputStream(jfcSave.getSelectedFile()), man);
jos.setLevel(Deflater.BEST_COMPRESSION);
BufferedInputStream bis = null;
byte[] cache = new byte[1024];
StringBuffer config = new StringBuffer();
for(String name : filePaths.keySet()) {
bis = new BufferedInputStream(new FileInputStream(filePaths.get(name)), 1024);
config.append(name).append('=').append(bis.available()).append('\n');
jos.putNextEntry(new JarEntry(name));
int count;
while((count = bis.read(cache, 0, 1024)) != -1)
jos.write(cache, 0, count);
jos.closeEntry();
bis.close();
}
jos.flush();
jos.close();
JOptionPane.showMessageDialog(this, "导出成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
} catch(Exception ex) {
JOptionPane.showMessageDialog(this, ex.getMessage(), "异常", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
}
} }
btnConfirm_event_handler
当然,这里还有一个小问题:选择文件(自己写的文件名就算不加后缀也能保存成功-_-)。
先展示一下结果:

在文件系统中选择:

导出到桌面:


运行一下:

我最后再将完整的源码贴出一份:
package org.coderecord.commons.ejarmaker; import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.jar.Attributes.Name;
import java.util.zip.Deflater; import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.filechooser.FileFilter; public class FrmMain extends JFrame implements ActionListener { private static final long serialVersionUID = 2016913328739206536L;
// 选择的文件(用户在文件选择器中选择的)
private List<File> userSelectedFiles = new ArrayList<>();
// 我们经过分析得到的最终会被打包的文件
private List<File> finalFiles = new ArrayList<>();
// 文件打包路径及物理文件
private Map<String, File> filePaths = new Hashtable<>(); public FrmMain() {
setSize(480, 320);
setResizable(false);
setLocationRelativeTo(null);
setTitle("通用可执行Jar包生成工具");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
// 在运行时获取资源文件的方式,一定是使用Class.getResource方式
// 在jar包中这种方式也行得通
// ‘/’代表根路径
setIconImage(Toolkit.getDefaultToolkit().getImage(FrmMain.class.getResource("/resources/icon.png")));
initComponents();
} // 初始化组件
private void initComponents() {
// 提示
lblTip = new JLabel("选择需要打包的文件并设置启动类");
lblTip.setLocation(20, 10);
lblTip.setSize(350, 20);
add(lblTip); // 浏览按钮
btnBrowser = new JButton("浏 览");
btnBrowser.setLocation(380, 10);
btnBrowser.setSize(80, 24);
btnBrowser.addActionListener(this);
add(btnBrowser); // 展示已选择文件
JScrollPane jspFiles = new JScrollPane();
txtFiles = new JTextArea();
txtFiles.setEditable(false);
jspFiles.setSize(440, 160);
jspFiles.setLocation(20, 40);
txtFiles.setSize(440, 201600);
txtFiles.setLocation(20, 40);
txtFiles.setFocusable(false);
jspFiles.setViewportView(txtFiles);
add(jspFiles); // 选择启动类
cobMainClass = new JComboBox<>();
cobMainClass.setSize(440, 30);
cobMainClass.setLocation(20, 210);
add(cobMainClass); // 清除已选
btnCls = new JButton("重 选");
btnCls.setLocation(20, 250);
btnCls.setSize(80, 24);
btnCls.addActionListener(this);
add(btnCls); // 确认按钮
btnConfirm = new JButton("确认");
btnConfirm.setSize(80, 24);
btnConfirm.setLocation(380, 250);
btnConfirm.addActionListener(this);
add(btnConfirm); // 文件选择器
jfcSelect = new JFileChooser();
// 可以选择文件和文件夹
jfcSelect.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
// 可以多选
jfcSelect.setMultiSelectionEnabled(true); // 文件保存
jfcSave = new JFileChooser();
// 设置只接受以“.jar”结尾的文件
jfcSave.setAcceptAllFileFilterUsed(false);
jfcSave.setFileFilter(new FileFilter() { @Override
public String getDescription() {
return "可执行Jar";
} @Override
public boolean accept(File f) {
return f.getName().endsWith(".jar");
}
});
} @Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btnBrowser) {
// 浏览
int result = jfcSelect.showOpenDialog(this); // 选择了文件
if(result == JFileChooser.APPROVE_OPTION) {
for(File file : jfcSelect.getSelectedFiles())
userSelectedFiles.add(file); // 整理选择的文件,去除重复项
removeDuplicateItems(userSelectedFiles); // 重新计算选中文件
finalFiles.clear();
for(File file : userSelectedFiles)
addFileToList(file, finalFiles); // 计算文件展示打包路径及展示路径
// 计算可启动类路径
// 展示到文本框中
cobMainClass.removeAllItems();
txtFiles.setText("");
File file,direc;
String filePath,direcPath;
Iterator<File> itd,itf;
for(itd = userSelectedFiles.iterator(); itd.hasNext();) {
direc = itd.next();
direcPath = direc.getAbsolutePath();
for(itf = finalFiles.iterator(); itf.hasNext();) {
file = itf.next();
filePath = file.getAbsolutePath();
if(filePath.equalsIgnoreCase(direcPath)) {
txtFiles.append(file.getName() + "\n");
filePaths.put(file.getName(), file);
if(file.getName().endsWith(".class"))
cobMainClass.addItem(file.getName().endsWith(".class")?file.getName().substring(0, file.getName().lastIndexOf('.')):file.getName());
itf.remove();
} else if(filePath.startsWith(direcPath)) {
String nameTmp = filePath.substring(direcPath.lastIndexOf(File.separator) + 1).replace(File.separatorChar, '/');
filePaths.put(nameTmp, file);
txtFiles.append(nameTmp + "\n");
if(nameTmp.endsWith(".class") && nameTmp.indexOf('$') == -1)
cobMainClass.addItem(nameTmp.substring(0, nameTmp.lastIndexOf('.')).replace('/', '.'));
itf.remove();
}
}
}
}
} else if(e.getSource() == btnCls) {
if(userSelectedFiles.size() == 0) return;
else if(JOptionPane.showConfirmDialog(this, "确定重选吗?将清除所有已选项!") == JOptionPane.OK_OPTION) {
userSelectedFiles.clear();
finalFiles.clear();
filePaths.clear();
cobMainClass.removeAllItems();
}
} else if(e.getSource() == btnConfirm) {
if(filePaths.size() == 0) {
JOptionPane.showMessageDialog(this, "未选择文件", "错误", JOptionPane.ERROR_MESSAGE);
return;
} else if(cobMainClass.getSelectedItem() == null) {
JOptionPane.showMessageDialog(this, "未选择启动类", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
// 打包
int result = jfcSave.showSaveDialog(this);
if(result == JFileChooser.APPROVE_OPTION) {
try {
// 清单文件
Manifest man = new Manifest();
// 版本和启动类路径必要
man.getMainAttributes().putValue(Name.MANIFEST_VERSION.toString(), "1.0");
man.getMainAttributes().putValue(Name.MAIN_CLASS.toString(), cobMainClass.getSelectedItem().toString());
// Class-Path一定不要,除非能保证将引用类(即import的类)都联合打包了
JarOutputStream jos = new JarOutputStream(new FileOutputStream(jfcSave.getSelectedFile()), man);
jos.setLevel(Deflater.BEST_COMPRESSION);
BufferedInputStream bis = null;
byte[] cache = new byte[1024];
StringBuffer config = new StringBuffer();
for(String name : filePaths.keySet()) {
bis = new BufferedInputStream(new FileInputStream(filePaths.get(name)), 1024);
config.append(name).append('=').append(bis.available()).append('\n');
jos.putNextEntry(new JarEntry(name));
int count;
while((count = bis.read(cache, 0, 1024)) != -1)
jos.write(cache, 0, count);
jos.closeEntry();
bis.close();
}
jos.flush();
jos.close();
JOptionPane.showMessageDialog(this, "导出成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
} catch(Exception ex) {
JOptionPane.showMessageDialog(this, ex.getMessage(), "异常", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
}
} } // 添加文件(非文件夹)到集合
private void addFileToList(File file, List<File> fileArr) {
if(file.isDirectory())
for(File child : file.listFiles())
addFileToList(child, fileArr);
else
fileArr.add(file);
} // 去除重复项
private void removeDuplicateItems(List<File> fileArr) {
// 去重复项
Set<String> directories = new HashSet<>();
Set<String> files = new HashSet<>();
for(File file : fileArr)
if(file.isDirectory())
directories.add(file.getAbsolutePath());
else
files.add(file.getAbsolutePath());
//去包含项(先去文件夹再去文件应该更好)
String fpath,dpath;
for(Iterator<String> itf = files.iterator(); itf.hasNext();) {
fpath = itf.next();
for(Iterator<String> itd = directories.iterator(); itd.hasNext();) {
dpath = itd.next();
if(fpath.startsWith(dpath))
itf.remove();
}
}
String dpath1,dpath2;
Set<String> directories1 = new HashSet<>(directories);
for(Iterator<String> itd1 = directories.iterator(); itd1.hasNext();) {
dpath1 = itd1.next();
for(Iterator<String> itd2 = directories1.iterator(); itd2.hasNext();) {
dpath2 = itd2.next();
if(dpath1.equals(dpath2))
continue;
else if(dpath2.startsWith(dpath1))
itd2.remove();
else if(dpath1.startsWith(dpath2))
itd1.remove();
}
}
directories.addAll(directories1); fileArr.clear();
for(String file : files)
fileArr.add(new File(file));
for(String directory : directories)
fileArr.add(new File(directory));
} private JLabel lblTip;
private JButton btnBrowser;
private JFileChooser jfcSelect;
private JTextArea txtFiles;
private JComboBox<String> cobMainClass;
private JButton btnCls;
private JButton btnConfirm;
private JFileChooser jfcSave;
}
FrmMain
这里有我导出的文件(这个是eclipse导出的,它在manifest中加入了classPath没有错误,我有时候加入后有问题)。
欢迎您移步我们的交流群,无聊的时候大家一起打发时间:
或者通过QQ与我联系:
(最后编辑时间2014-03-02 16:12:50)
使用原生Java代码生成可执行Jar包的更多相关文章
- 使用eclipse创建java程序可执行jar包
一.eclipse中,在要打成jar包的项目名上右击,出现如下弹出框,选择“export”: 二.在接下来出现的界面中点击“jar file”,然后next: 三.在接下来出现的界面中,如图所示勾选上 ...
- JAVA生成(可执行)Jar包的全面详解说明 [打包][SpringBoot][Eclipse][IDEA][Maven][Gradle][分离][可执行]
辛苦所得,转载还请注明: https://www.cnblogs.com/applerosa/p/9739007.html 得空整理了关于java 开发中,所有打包方式的 一个操作方法, 有基于ID ...
- Java打包可执行jar包 包含外部文件
外部文件在程序中设置成相对当前工程路径,执行jar包时,将外部文件放在和jar包平级的目录. public class Main { 3 public static void main(String[ ...
- java 生成可执行jar包
jar -cvfm my.jar [配置主函数入口文件] [包] Main-Class: 包名.类名 注意“:”后边有一个空格,类名后边要有回车换行
- java 执行 jar 包中的 main 方法
java 执行 jar 包中的 main 方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar执行后总是运行指定的主方法,如果 jar 中有多 ...
- IntelliJ IDEA导出Java 可执行Jar包
原文:IntelliJ IDEA导出Java 可执行Jar包 保证自己的Java代码是没有问题的,在IDEA里面是可以正常运行的,然后,按下面步骤: 打开File -> Project Stru ...
- eclipse生成【带有外部jar包】的java可执行jar包
之前有写过一篇使用eclipse生成java可执行jar包,但是最近的一次使用中无论如何都不成功,当双击执行打成的jar时,弹出如下错误: could not find the main class: ...
- java -jar 执行jar包出现 java.lang.NoClassDefFoundError
我用idea工具将自己开发java程序打成一个可执行的jar包,当然用eclipse或者直接用jar命令行都无所谓,本质都是将程序归档到一个压缩包,并附带一个说明清单文件. 打jar的操作其实很简单, ...
- java执行jar包出错:Unable to access jarfile
java执行jar包出错:Unable to access jarfile 错误的原因有多种: 1.一般都是路径不正确.在Windows中,正确的路径类似于: java -jar "D:\W ...
随机推荐
- C++中extern “C”含义及extern、static关键字浅析
https://blog.csdn.net/bzhxuexi/article/details/31782445 1.引言 C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C ...
- Java LinkedList工作原理及实现
1. 概述 以双向链表实现.链表无容量限制,但双向链表本身使用了更多空间,也需要额外的链表指针操作. 按下标访问元素—get(i)/set(i,e) 要悲剧的遍历链表将指针移动到位(如果i>数组 ...
- 字节码 反编译 APKTool 重新打jar包 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Linux下RocketMQ环境的配置
RocketMQ是一款分布式消息系统,最初是由阿里巴巴消息中间件团队研发并大规模应用于生产系统,满足线上海量堆积的需求,在去年捐赠给Apache开源基金会,并列为孵化项目,今年成功的正式成为了apac ...
- Morris图表使用小记
挺好用的,碰到几个问题,有的是瞎试解决了的: 1.我想折线图能够响应单击事件,即点击某个节点后,就能加载进一步的信息,帮助没找到,参照另外一个地方的写法,居然支持事件 Morris.Line({ el ...
- Python 隔离沙箱 virtualenv
我认为Python一个很大的优势就是官方网站给出的众多的软件包,几乎能帮助你实现你想要的任何功能,避免了重复开发的劳动,但是零零碎碎的包,以及每个包的各种各样的版本管理就成为了一个比较棘手的问题,因此 ...
- JVM源码分析之Object.wait/notify实现(转载)
最简单的东西,往往包含了最复杂的实现,因为需要为上层的存在提供一个稳定的基础,Object作为java中所有对象的基类,其存在的价值不言而喻,其中wait和notify方法的实现多线程协作提供了保证. ...
- SNF快速开发平台MVC-EasyUI3.9之-DataGrid表格控件如何增加右键菜单
如题,我们在项目开发当中会遇到需要,表格控件增加右键菜单的使用. 下面我们就以SNF框架增加右键菜单步骤如下: 1.在加载页面当中增加如下菜单定义 <div id="mm" ...
- 第三部分:Android 应用程序接口指南---第二节:UI---第十章 拖放
第10章 拖放 使用Android的拖放框架,允许用户通过一个图形化的拖放动作,把数据从当前布局中的一个视图上转移到另一个视图上.这个框架包含了一个拖动事件类,拖动监听器和一些辅助的方法和类. 虽然这 ...
- MUI中等待框的H5实现
MUI没有内置的那个弹出转圈圈的那个等待框,那个nativeui.showwaiting是只能用于app中的,不能用在H5网页中的,网上找了下,找到个别人已经写好的,自己 测试了下没问题,先记下来 @ ...