0


(从零写到生成exe文件)Java 将Git作为文件云盘?我的世界MOD同步器?全代码从新建项目开始写

使用场景:跟朋友玩我的世界联机的时候朋友是个啥子不会装Mod,故闲着没事做的时候写了这个项目,只需配置好Git文件下载地址及保存文件路径就可以一键同步了
软件体验下载及使用教程地址:https://blog.csdn.net/u012930947/article/details/139595128
开发软件:idea、jdk11、exe4j
tips:之前写了一版使用JGit去clone或者pull去同步github的文件,但是经常会因为网络问题获取不到而失效,故变成下载zip
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

一、创建GIt项目并拿到下载zip文件路径和zip文件内目录名,记录及保存

这个看我这篇文章,翻到下面有教程
https://blog.csdn.net/u012930947/article/details/139595128

1、打开https://github.com/,注册账号或登录成功后面进入此界面,点击New

在这里插入图片描述

2、创建Git项目

请添加图片描述

3、点击uploading an existing 跳转到上传Mod文件界面后点击 choose your files 上传Mod文件

请添加图片描述
在这里插入图片描述

4、获取Git压缩包文件地址,先点击左上角你的Git仓库名称,回到主页后再点击你创建的Git项目

在这里插入图片描述

5、先点右上角Code打开下拉,点Download Zip

请添加图片描述

6、出现这样的界面,复制zip文件下载链接,保存下来

请添加图片描述

7、下载下来后,打开压缩包,将压缩包内目录名保存下来

在这里插入图片描述

注:重要配置参数

二、创建Java项目及iml配置

1、打开Idea,点击左上角的File->New->Project->New Proect
命名随便

在这里插入图片描述

2、在src下创建java、resources文件

在这里插入图片描述

3、打开Project Structure 更新及设置iml文件

在这里插入图片描述
在这里插入图片描述

4、设置完成后data_pull_exe.iml文件里应该是这样

在这里插入图片描述

5、添加jar包 commons-io-2.13.0 (这个jar就做了个强制删除,视情况可以不加)在resources下增加libs

6、再次打开Project Structure->Libraries,点+号选择Java,选中resources下的libs

在这里插入图片描述

7、选择确认后.iml文件内应该是这样的

在这里插入图片描述

三、项目结构介绍

在这里插入图片描述

四、项目开发

1、新建常量类、异常处理类及字符处理类

新建com.common.constant包,创建SyncConstant类
新建com.common.exception包,创建ServiceException类
新建com.common.utils包,创建StringUtils类

SyncContent 类

LOCAL_TEMP :缓存文件地址,下载的zip文件保存及解压地址,窗口关闭时会删除这个文件
DOWNLOAD_PATH、IN_PACK_FILE_NAME、MOVE_LOCAL_PATH: 用于初始化.config文件配置参数的默认赋值
CONFIG_LOCAL_PATH:.config文件夹生成到的路径,默认当前文件夹 CONFIG_NAME :.config文件夹的文件名

packagecom.common.constant;publicclassSyncContent{/** 下载缓存文件地址 */publicstaticStringLOCAL_TEMP=".temp\\";/** 远程Zip地址下载地址 */publicstaticStringDOWNLOAD_PATH="";// 用于替换初始化.config配置文件里的配置publicstaticStringCOL_DOWNLOAD_PATH="download_path";/** 远程下载的压缩包内文件名 */publicstaticStringIN_PACK_FILE_NAME="";// 用于替换初始化.config配置文件里的配置publicstaticStringCOL_IN_PACK_FILE_NAME="in_pack_file_name";/** 默认解压的文件地址 */publicstaticStringMOVE_LOCAL_PATH="";// 用于替换初始化.config配置文件里的配置publicstaticStringCOL_MOVE_LOCAL_PATH="move_local_path";/** 配置文件保存地址 - 当前文件夹 */publicstaticfinalStringCONFIG_LOCAL_PATH="./";/** 配置名称 */publicstaticfinalStringCONFIG_NAME=".config";}
ServiceException类
packagecom.common.exception;publicclassServiceExceptionextendsRuntimeException{privateString message;publicServiceException(){}publicServiceException(String message){this.message = message;}publicServiceException(Exception exception){if(exception instanceofServiceException){this.message =((ServiceException) exception).getMessage();}else{this.message ="系统异常";}}@OverridepublicStringgetMessage(){return message;}}
StringUtils类
packagecom.common.utils;publicclassStringUtils{/** 空字符串 */privatestaticfinalStringNULLSTR="";publicstaticbooleanisEmpty(String str){return str ==null||NULLSTR.equals(str.trim());}}

2、创建config.template模板文件

a、在resources下先创建一个txt文件

在这里插入图片描述

b、将模板格式复制进去

# 远程zip文件下载地址
download_path={download_path}
# zip文件内的目录名
in_pack_file_name={in_pack_file_name}
# 将zip目录in_pack_file_name下的文件转移到的本地路径
move_local_path={move_local_path}

在这里插入图片描述

c、再点击 文件->另存为->config.template

改成ANSI编码使用用exe软件生成.config文件时中文才不会乱码

在这里插入图片描述

3、读取.config配置文件,新建配置类,在com.properties下创建ConfigProperties

packagecom.properties;importcom.common.constant.SyncContent;importcom.global.SyncGlobal;importjava.io.FileInputStream;importjava.io.IOException;importjava.io.StringReader;importjava.nio.charset.Charset;importjava.util.Properties;publicclassConfigProperties{// 远程zip文件下载地址privateString download_path;// zip文件内的目录名privateString in_pack_file_name;// 将zip目录in_pack_file_name下的文件转移到的本地路径privateString move_local_path;publicConfigProperties(){Properties properties =newProperties();try{if(SyncGlobal.configFile.exists()){FileInputStream fileInputStream =newFileInputStream(SyncContent.CONFIG_NAME);// 替换单斜杠 - 为什么需要替换:在弹窗中选择文件路径时获取到的文件地址是单斜杠,会被自动转意导致路径不正确String content =newString(fileInputStream.readAllBytes(),Charset.forName("GBK")).replace("\\","\\\\");
                properties.load(newStringReader(content));
                fileInputStream.close();
                download_path = properties.getProperty(SyncContent.COL_DOWNLOAD_PATH);
                in_pack_file_name = properties.getProperty(SyncContent.COL_IN_PACK_FILE_NAME);
                move_local_path = properties.getProperty(SyncContent.COL_MOVE_LOCAL_PATH);}}catch(IOException e){
            e.printStackTrace();}}publicStringgetDownload_path(){return download_path;}publicvoidsetDownload_path(String download_path){this.download_path = download_path;}publicStringgetIn_pack_file_name(){return in_pack_file_name;}publicvoidsetIn_pack_file_name(String in_pack_file_name){this.in_pack_file_name = in_pack_file_name;}publicStringgetMove_local_path(){return move_local_path;}publicvoidsetMove_local_path(String move_local_path){this.move_local_path = move_local_path;}}

4、新建全局变量类,在com.global下新建SyncGlobal类

packagecom.global;importcom.common.constant.SyncContent;importcom.properties.ConfigProperties;importcom.window.SyncWindows;importorg.apache.commons.io.FileUtils;importjavax.net.ssl.HttpsURLConnection;importjava.awt.*;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.util.zip.ZipFile;/**
 * 全局变量
 */publicclassSyncGlobal{/** 主窗口 */publicstaticSyncWindows jFrame;/** 下载输入流 **/publicstaticInputStream dowInputStream =null;/** 下载输出流 **/publicstaticFileOutputStream dowOutputStream =null;/** zip文件类 **/publicstaticZipFile zipFile =null;/** 解压输入流 **/publicstaticInputStream zipInputStream =null;/** 解压输出流 **/publicstaticFileOutputStream zipOutputStream =null;/** https网络连接 **/publicstaticHttpsURLConnection connection =null;/** 配置文件 **/publicstaticConfigProperties configProperties;/** 配置文件路径 */publicstaticFile configFile =newFile(SyncContent.CONFIG_LOCAL_PATH+SyncContent.CONFIG_NAME);// 图标publicstaticImage imageIcon =null;/**
     * 全局关闭时-清空缓存文件.temp
     * @throws IOException
     */publicstaticvoid clearTemp ()throwsIOException{if(dowInputStream !=null){
            dowInputStream.close();}if(dowOutputStream !=null){
            dowOutputStream.close();}if(zipInputStream !=null){
            zipInputStream.close();}if(zipOutputStream !=null){
            zipOutputStream.close();}if(zipFile !=null){
            zipFile.close();}if(connection !=null){
            connection.disconnect();}// 强制删除File tempFile =newFile(SyncContent.LOCAL_TEMP);if(tempFile.isDirectory()){FileUtils.forceDelete(tempFile);}}}

5、初始化配置文件.config,在com.properties下新建ConfigReader

可用于根据config.template初始化.config文件,设置全局配置变量

packagecom.properties;importcom.Main;importcom.common.constant.SyncContent;importcom.common.exception.ServiceException;importcom.common.utils.StringUtils;importcom.global.SyncGlobal;importjava.io.BufferedReader;importjava.io.FileWriter;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.lang.reflect.Field;importjava.nio.charset.Charset;publicclassConfigReader{/**
     * 初始化
     */publicstaticvoid init (){// 初始化配置文件SyncGlobal.configProperties =newConfigProperties();// 配置文件不存在即初始化if(!SyncGlobal.configFile.exists()){rebuildConfig();}// 配置文件重要配置为空抛异常if(StringUtils.isEmpty(SyncGlobal.configProperties.getDownload_path())){thrownewServiceException("远程zip文件下载地址未配置");}elseif(StringUtils.isEmpty(SyncGlobal.configProperties.getIn_pack_file_name())){thrownewServiceException("zip文件内目录名未配置");}}/**
     * 重建配置
     */publicstaticvoid rebuildConfig (){// 获取配置模板,读取Resource下配置模板文件流try(InputStream inputStream =Main.class.getClassLoader().getResourceAsStream("config.template");BufferedReader reader =newBufferedReader(newInputStreamReader(inputStream))){String template;String configContent ="";while((template = reader.readLine())!=null){
                configContent += template +"\r\n";}// 通过反射设置初始化配置默认值for(Field field :SyncGlobal.configProperties.getClass().getDeclaredFields()){
                field.setAccessible(true);String key = field.getName();String value =(String) field.get(SyncGlobal.configProperties);// 设置默认值if(value ==null||"".equals(value.trim())){if(key.equals(SyncContent.COL_DOWNLOAD_PATH)){
                        value =SyncContent.DOWNLOAD_PATH;}if(key.equals(SyncContent.COL_IN_PACK_FILE_NAME)){
                        value =SyncContent.IN_PACK_FILE_NAME;}if(key.equals(SyncContent.COL_MOVE_LOCAL_PATH)){
                        value =SyncContent.MOVE_LOCAL_PATH;}}
                field.set(SyncGlobal.configProperties, value);
                configContent = configContent.replace("{"+ key +"}", value);}// 输出.confg文件 - GBK编码加上模板文件格式为ANSI编码才能使软件生成配置文件时中文不会乱码//(直接idea运行可能会中文乱码)FileWriter writer =newFileWriter(SyncGlobal.configFile,Charset.forName("GBK"));
            writer.write(configContent);
            writer.close();}catch(Exception e){
            e.printStackTrace();thrownewServiceException(e);}}}

6、创建主弹窗,在com.window下新建SyncWindows类

icon.png是弹窗打开的图标,可随便找一张放在resource下

packagecom.window;importcom.global.SyncGlobal;importjavax.swing.*;importjava.awt.*;importjava.awt.event.WindowAdapter;importjava.net.URL;publicclassSyncWindowsextendsJFrame{JLabel label;Container container;JProgressBar progressBar;JFrame jFrame =this;JScrollPane scrollPane;publicInteger width =300;publicInteger height =100;/**
     * 初始化窗口
     */publicSyncWindows(){// 从文件路径加载图标URL imageUrl =SyncWindows.class.getClassLoader().getResource("icon.png");SyncGlobal.imageIcon =Toolkit.getDefaultToolkit().getImage(imageUrl);
        jFrame.setIconImage(SyncGlobal.imageIcon);// 设置窗口大小
        jFrame.setSize(width, height);// 窗口名称
        jFrame.setTitle("Mincraft Mod 同步");// 屏幕居中显示
        jFrame.setLocationRelativeTo(null);// 禁止用户调整窗口的大小
        jFrame.setResizable(false);// 面板
        container = jFrame.getContentPane();// 文字显示
        label =newJLabel();// 文字默认显示
        label.setText("...");//使标签上的文字居中
        label.setHorizontalAlignment(SwingConstants.CENTER);// 进度条
        progressBar =newJProgressBar(JProgressBar.HORIZONTAL,0,100);
        progressBar.setStringPainted(true);// 设置初始进度值(下载或解压进度条)
        progressBar.setValue(0);
        scrollPane =newJScrollPane(label);// 将文字添加到JFrame
        container.add(scrollPane);// 将进度条添加到JFrame
        container.add(progressBar,BorderLayout.SOUTH);// 监听窗口关闭
        jFrame.addWindowListener(windowsClose());// 显示窗口this.setVisible(true);}/**
     * 设置窗口大小
     * @param width
     * @param height
     */publicvoid updateSize (int width,int height){SwingUtilities.invokeLater(()->{this.setSize(width, height);});}/**
     * 设置主要文字信息
     * @param text
     */publicvoid setLabel (String text){SwingUtilities.invokeLater(()->{
            label.setText(text);});}/**
     * 设置进度条
     * @param progress
     */publicvoid setProgress (int progress){SwingUtilities.invokeLater(()->{
            progressBar.setValue(progress);});}/**
     * 窗口关闭
     */publicWindowAdapter windowsClose (){returnnewWindowAdapter(){//窗口被关闭时的监听publicvoidwindowClosed(java.awt.event.WindowEvent e){
                systemClose ();}//点击窗口关闭按钮监听publicvoidwindowClosing(java.awt.event.WindowEvent e){
                jFrame.dispose();}};}/**
     * 系统关闭
     */publicstaticvoid systemClose (){try{SyncGlobal.clearTemp ();}catch(Exception e){
            e.printStackTrace();}finally{System.exit(0);}}publicContainergetContainer(){return container;}publicJProgressBargetProgressBar(){return progressBar;}publicvoidsetProgressBar(JProgressBar progressBar){this.progressBar = progressBar;}}

7、文件选择弹窗(包含覆盖.config配置文件参数),在com.window下创建SelectFileJDialog类

packagecom.window;importcom.common.exception.ServiceException;importcom.global.SyncGlobal;importcom.properties.ConfigReader;importjavax.swing.*;importjava.awt.*;importjava.awt.event.WindowAdapter;importjava.awt.event.WindowEvent;importjava.io.File;publicclassSelectFileJDialogextendsJDialog{JDialog jDialog =this;privateInteger width =300;privateInteger height =120;publicfinalstaticSelectFileJDialog init (){returnnewSelectFileJDialog();}publicSelectFileJDialog(){// 从文件路径加载图标
        jDialog.setIconImage(SyncGlobal.imageIcon);// 文本框finalJTextField fileTextField =newJTextField(20);
        fileTextField.setText(SyncGlobal.configProperties.getMove_local_path());// 选择按钮JButton select =newJButton("选择文件");
        select.addActionListener(e ->{// 选择文件夹JFileChooser fileChooser =newJFileChooser(newFile(SyncGlobal.configProperties.getMove_local_path()).isDirectory()?SyncGlobal.configProperties.getMove_local_path():"./");
            fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);int result = fileChooser.showOpenDialog(jDialog);if(result ==JFileChooser.APPROVE_OPTION){File selectedFile = fileChooser.getSelectedFile();
                fileTextField.setText(selectedFile.getAbsolutePath());}});// 为对话框添加窗口关闭事件监听器
        jDialog.addWindowListener(newWindowAdapter(){@OverridepublicvoidwindowClosing(WindowEvent e){// 窗口关闭关闭整个程序
                jDialog.dispose();SyncGlobal.jFrame.systemClose();}});// 选择按钮JButton confirm =newJButton("确认");
        confirm.addActionListener(e ->{boolean isStart =false;File selectFile =newFile(fileTextField.getText());if(!selectFile.isDirectory()){if(JOptionPane.showConfirmDialog(null,"文件目录不存在,是否创建?","提示",JOptionPane.YES_NO_OPTION)==0){
                    isStart =true;
                    selectFile.mkdirs();}}elseif(JOptionPane.showConfirmDialog(null,"程序将会清空选择文件夹中所有文件,确认?","提示",JOptionPane.YES_NO_OPTION,JOptionPane.WARNING_MESSAGE)==0){
                isStart =true;}if(isStart){try{// 设置全局变量 - 文件同步地址SyncGlobal.configProperties.setMove_local_path(fileTextField.getText());// 重写.config文件ConfigReader.rebuildConfig();}catch(Exception ex){
                    ex.printStackTrace();thrownewServiceException(ex);}
                jDialog.dispose();}});// 设置对话框的布局和内容
        jDialog.setLayout(newFlowLayout());
        jDialog.add(fileTextField);
        jDialog.add(select);
        jDialog.add(confirm);// 设置标题
        jDialog.setTitle("确认路径");// 禁止用户调整窗口的大小
        jDialog.setResizable(false);// 设置对话框的大小和可见性
        jDialog.setSize(width, height);// 这个配置等于弹窗等待,这个弹窗开启时后面的代码不会执行
        jDialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);// 使对话框居中于主窗口
        jDialog.setLocationRelativeTo(SyncGlobal.jFrame);
        jDialog.setVisible(true);}}

8、编写文件下载、zip解压、文件迁移类FileUtils(包含下载解压进度条调整),在com.common.utils下新建FileUtils类

packagecom.common.utils;importcom.common.exception.ServiceException;importcom.global.SyncGlobal;importjavax.net.ssl.HttpsURLConnection;importjavax.net.ssl.SSLContext;importjavax.net.ssl.TrustManager;importjavax.net.ssl.X509TrustManager;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.math.BigDecimal;importjava.net.HttpURLConnection;importjava.net.URL;importjava.nio.charset.Charset;importjava.nio.file.Files;importjava.nio.file.Path;importjava.nio.file.attribute.DosFileAttributeView;importjava.text.SimpleDateFormat;importjava.util.Date;importjava.util.Enumeration;importjava.util.zip.ZipEntry;importjava.util.zip.ZipFile;publicclassFileUtils{/**
     * 远程下载zip
     * @param downloadPath 远程文件地址
     * @param downLocalPath 本地保存地址
     * @return
     * @throws Exception
     */publicstaticStringremoteDownloadZip(String downloadPath,String downLocalPath)throwsException{// 更改文字显示SyncGlobal.jFrame.setLabel("正在下载..");File downLocalFile =newFile(downLocalPath);if(!downLocalFile.isDirectory()){
            downLocalFile.mkdirs();}// 隐藏文件isHidden(downLocalPath);
        downLocalFile.setExecutable(true);URL url =newURL(downloadPath);SyncGlobal.connection =(HttpsURLConnection) url.openConnection();// 创建信任所有服务器的TrustManagerTrustManager[] trustAllCerts =newTrustManager[]{newX509TrustManager(){publicjava.security.cert.X509Certificate[]getAcceptedIssuers(){returnnull;}publicvoidcheckClientTrusted(java.security.cert.X509Certificate[] certs,String authType){}publicvoidcheckServerTrusted(java.security.cert.X509Certificate[] certs,String authType){}}};// 生成的exe使https请求不报错System.setProperty("javax.net.debug","all");// 初始化SSLContext并设置TrustManagerSSLContext sc =SSLContext.getInstance("TLSv1.2");
        sc.init(null, trustAllCerts,newjava.security.SecureRandom());// 设置允许输入流输入数据到本地SyncGlobal.connection.setDoInput(true);// 设置允许输出流输出到服务器SyncGlobal.connection.setDoOutput(true);// 从SSLContext获取SSLSocketFactory并设置到HttpsURLConnection中SyncGlobal.connection.setSSLSocketFactory(sc.getSocketFactory());// 设置通用的请求属性SyncGlobal.connection.setRequestProperty("Accept-Encoding","identity");// 建立实际的连接SyncGlobal.connection.connect();int responseCode =SyncGlobal.connection.getResponseCode();if(responseCode !=HttpURLConnection.HTTP_OK){thrownewServiceException("下载失败!");}// 引用形式的描述信息:打开远程文件的输入流SyncGlobal.dowInputStream =SyncGlobal.connection.getInputStream();// 创建本地文件输出流String downFilePath = downLocalPath +newSimpleDateFormat("yyyyMMddHHmmss").format(newDate())+".zip";SyncGlobal.dowOutputStream =newFileOutputStream(downFilePath);// 按字节读取写入文件byte[] buffer =newbyte[1024];int length;// 文件大小BigDecimal totalSize =newBigDecimal(SyncGlobal.connection.getContentLength());BigDecimal downloadedSize =BigDecimal.ZERO;// 计数int num =0;while((length =SyncGlobal.dowInputStream.read(buffer))!=-1){SyncGlobal.dowOutputStream.write(buffer,0, length);
            downloadedSize = downloadedSize.add(newBigDecimal(length));// 请求下载时文件大小可能会返回-1,即做个假进度条if(SyncGlobal.connection.getContentLength()>0){BigDecimal progress =(downloadedSize.multiply(newBigDecimal(100))).divide(totalSize,BigDecimal.ROUND_HALF_DOWN);SyncGlobal.jFrame.setProgress(progress.intValue());}else{// 假进度条
                num++;SyncGlobal.jFrame.setProgress(num >100000?80:50);}}// 关闭流SyncGlobal.dowInputStream.close();SyncGlobal.dowOutputStream.close();SyncGlobal.connection.disconnect();if(!newFile(downFilePath).exists()){thrownewServiceException("同步失败,文件下载失败");}return downFilePath;}/**
     * 解压zip
     * @param zipPath
     * @param toPath
     * @return
     */publicstaticvoid decZipFile (String zipPath,String toPath)throwsException{// 更改文字显示SyncGlobal.jFrame.setLabel("正在解压...");// 获取Zip文件 - 编码设置gbk,在生成exe文件后启动后解压的文件名显示才正常SyncGlobal.zipFile =newZipFile(zipPath,Charset.forName("gbk"));// 遍历压缩文件中的所有条目Enumeration<?extendsZipEntry> entries =SyncGlobal.zipFile.entries();int totalEntries =SyncGlobal.zipFile.size();int currentEntry =0;while(entries.hasMoreElements()){ZipEntry entry = entries.nextElement();// 解压缩条目到目标文件夹String entryName = entry.getName();
            entryName =newString(entryName.getBytes(Charset.forName("gbk")));File entryFile =newFile(toPath, entryName);if(entry.isDirectory()){
                entryFile.mkdirs();}else{
                entryFile.getParentFile().mkdirs();SyncGlobal.zipInputStream =SyncGlobal.zipFile.getInputStream(entry);SyncGlobal.zipOutputStream =newFileOutputStream(entryFile);byte[] buffer =newbyte[1024];int length;while((length =SyncGlobal.zipInputStream.read(buffer))>0){SyncGlobal.zipOutputStream.write(buffer,0, length);}SyncGlobal.zipOutputStream.close();SyncGlobal.zipInputStream.close();}// 进度条赋值
            currentEntry++;int progress =(int)((currentEntry /(double) totalEntries)*100);SyncGlobal.jFrame.setProgress(progress);}// 关闭压缩文件SyncGlobal.zipFile.close();}/**
     * 移动zip文件
     * @param zipDecFilePath
     * @param moveLocalPath
     * @throws Exception
     */publicstaticvoid moveZipFile (String zipDecFilePath,String moveLocalPath)throwsException{// 删除目标目录所有文件
        deleteFiles (moveLocalPath);SyncGlobal.jFrame.setLabel("正在移动文件..");File sourceFolder =newFile(zipDecFilePath);File destinationFolder =newFile(moveLocalPath);if(!sourceFolder.exists()){thrownewServiceException("同步失败,解压文件不存在!");}if(!destinationFolder.isDirectory()){
            destinationFolder.mkdirs();}File[] files = sourceFolder.listFiles();if(files !=null&& files.length >0){StringBuilder fileMsgs =newStringBuilder();for(File file : files){try{Files.move(file.toPath(),newFile(destinationFolder.getAbsolutePath()+File.separator + file.getName()).toPath());
                    fileMsgs.append("文件"+ file.getName()+"同步完成<br/>");}catch(IOException e){
                    fileMsgs.append("文件"+ file.getName()+"同步失败<br/>");
                    e.printStackTrace();}SyncGlobal.jFrame.setLabel("<html><body>"+ fileMsgs +"</body></html>");}SyncGlobal.jFrame.updateSize(500,300);// 屏幕居中显示SyncGlobal.jFrame.setLocationRelativeTo(null);}else{thrownewServiceException("文件不存在!");}}/**
     * 删除指定文件夹下的文件
     * @param path
     */publicstaticvoiddeleteFiles(String path){File file =newFile(path);if(file.exists()){if(file.isDirectory()){File[] files = file.listFiles();for(File f : files){if(f.isFile()){
                        f.delete();}elseif(f.isDirectory()){deleteFiles(f.getAbsolutePath());}}
                file.delete();}else{
                file.delete();}}}/**
     * 隐藏文件
     * @param filePath
     * @return
     * @throws IOException
     */publicstaticboolean isHidden (String filePath)throwsIOException{Path path =Path.of(filePath);DosFileAttributeView view =Files.getFileAttributeView(path,DosFileAttributeView.class);
        view.setHidden(true);return view.readAttributes().isHidden();}}

9、同步开始方法,用于调用下载、解压、迁移文件方法,在com.service下新建SyncService类

packagecom.service;importcom.common.constant.SyncContent;importcom.global.SyncGlobal;importcom.common.utils.FileUtils;importjavax.swing.*;publicclassSyncService{/**
     * 开始同步
     * @throws Exception
     */publicstaticvoid start ()throwsException{// 隐藏文件 - 会使config禁止访问// FileUtils.isHidden(SyncGlobal.configFile.getAbsolutePath());// 远程下载String zipPath =FileUtils.remoteDownloadZip(SyncGlobal.configProperties.getDownload_path(),SyncContent.LOCAL_TEMP);// 解压压缩包文件FileUtils.decZipFile(zipPath,SyncContent.LOCAL_TEMP);// 移动文件FileUtils.moveZipFile(SyncContent.LOCAL_TEMP+SyncGlobal.configProperties.getIn_pack_file_name(),SyncGlobal.configProperties.getMove_local_path());// 同步完成JOptionPane.showMessageDialog(SyncGlobal.jFrame,"同步完成");}}

10、启动类,在com包下新建Main.java

用于调用窗口启动、初始化配置、文件选择弹窗、开始同步文件及异常窗口处理

packagecom;importcom.common.exception.ServiceException;importcom.global.SyncGlobal;importcom.properties.ConfigReader;importcom.service.SyncService;importcom.window.SelectFileJDialog;importcom.window.SyncWindows;importjavax.swing.*;publicclassMain{publicstaticvoidmain(String[] args)throwsInterruptedException{// 开启窗口SyncGlobal.jFrame =newSyncWindows();try{// 初始化配置ConfigReader.init();// 文件选择SelectFileJDialog.init();// 开始同步文件SyncService.start();}catch(Exception e){
            e.printStackTrace();if(e instanceofServiceException){JOptionPane.showMessageDialog(SyncGlobal.jFrame, e.getMessage(),"确认",0);SyncGlobal.jFrame.systemClose();}else{JOptionPane.showMessageDialog(SyncGlobal.jFrame,"同步失败","确认",0);SyncGlobal.jFrame.setLabel(e.getMessage());SyncGlobal.jFrame.setProgressBar(null);}}finally{// 停30秒Thread.sleep(30000);SyncGlobal.jFrame.systemClose();}}}

五、项目打成jar包

1、打开Project Structure

在这里插入图片描述

2、选择Artifacts,点击+号,按图片点击

在这里插入图片描述

3、选择你的Main方法,然后点OK

在这里插入图片描述
在这里插入图片描述

4、再次点击OK,之后应该会在项目中生成一个META-INF文件

在这里插入图片描述

5、打包成jar包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

六、生成exe文件

1、先将我们的jar包复制到桌面

2、打开exe4j,百度搜索有下载

3、激活exe4j,不然打开软件会有exe4j带的弹窗

通用激活码:L-g782dn2d-1f1yqxx1rv1sqd 名称和公司名称随意
在这里插入图片描述

在这里插入图片描述

4、点击下一步,选择JAR IN EXE

在这里插入图片描述

5、下一步

在这里插入图片描述

6、下一步,设置应用图标

随便找张图片就行
百度搜在线ico转换器
例:https://www.xunjietupian.com/image-to-icon/

在这里插入图片描述

7、下一步,选择Jar包及设置启动类

在这里插入图片描述
在这里插入图片描述

8、下一步、配置jre(重要)

a.填写完最小最大java版本后,点击Search sequence

在这里插入图片描述

b、将这三个删除

在这里插入图片描述
c、然后点击+,按图片步骤完成后确定
在这里插入图片描述

9、往后直接下一步到完成,exe文件就生成了

10、生成jre文件,这个必须和生成的exe文件放在同目录

a、找到jdk安装目录,例如我的:C:\Program Files\Java\jdk-11.0.6

b、用管理员身份打开cmd,输入cd C:\Program Files\Java\jdk-11.0.6到jdk目录地址,假如在D盘那就先输入 D: 回车再输入,cd D:\Program Files\Java\jdk-11.0.6定位到jdk目录地址

在这里插入图片描述

c、将 bin\jlink.exe --module-path jmods --add-modules java.desktop --output jre 复制到cmd里执行,将在jdk目录生成jre文件

在这里插入图片描述
d、将jre文件复制到我们生成的exe文件目录
在这里插入图片描述

七、软件使用及下载地址

https://blog.csdn.net/u012930947/article/details/139595128

八、其他:使用JGit同步

简单写的一个弹窗应用,使用exe执行大概不可用
需要引用的包org.eclipse.jgit.jar及sl4fj(jgit需要引)

packagecom.mcworld;importorg.eclipse.jgit.api.*;importorg.eclipse.jgit.api.errors.GitAPIException;importorg.eclipse.jgit.lib.Repository;importorg.eclipse.jgit.storage.file.FileRepositoryBuilder;importjavax.swing.*;importjava.awt.*;importjava.awt.event.WindowAdapter;importjava.awt.event.WindowEvent;importjava.io.File;importjava.io.IOException;publicclassMain{publicstaticvoidmain(String[] args)throwsException{// 创建一个简单的弹窗JDialog dialog =newJDialog();
        dialog.setTitle("同步Mod");
        dialog.setSize(300,100);
        dialog.setLocationRelativeTo(null);
        dialog.setLayout(newFlowLayout());
        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);// 添加窗口监听器来处理关闭事件
        dialog.addWindowListener(newWindowAdapter(){@OverridepublicvoidwindowClosing(WindowEvent e){// 这里编写你关闭窗口时想要执行的代码System.out.println("进程结束");// 确保窗口关闭
                dialog.dispose();System.exit(0);}});// 本地仓库路径:你的我的世界mods文件路径String localRepoPath ="";File filePath =newFile(localRepoPath);if(!filePath.exists()){
            filePath.mkdirs();}JLabel label =null;String gitignorePath = localRepoPath +".git";try{if(!newFile(gitignorePath).isDirectory()){
                label =newJLabel("首次执行稍长..请耐心等待");
                dialog.add(label);deleteFiles(localRepoPath);// 设置弹窗可见
                dialog.setVisible(true);// git仓库地址String repoUrl ="https://github.com/xxx/MyMincraft.git";// 使用克隆命令CloneCommand cloneCommand =Git.cloneRepository();// 设置仓库的URL
                cloneCommand.setURI(repoUrl);// 设置克隆到的目录
                cloneCommand.setDirectory(newFile(localRepoPath));// 执行克隆操作Git git = cloneCommand.call();
                git.close();}else{
                label =newJLabel("正在更新");
                dialog.add(label);// 设置弹窗可见
                dialog.setVisible(true);}// 打开本地仓库Repository localRepo =newFileRepositoryBuilder().setGitDir(newFile(localRepoPath +"/.git")).build();// 创建Git对象Git git =newGit(localRepo);// 创建Pull命令
            git.reset().setMode(ResetCommand.ResetType.HARD).call();PullCommand pullCommand = git.pull();// 执行Pull操作
            pullCommand.call();}catch(IOException|GitAPIException e){
            e.printStackTrace();
            label.setText(e.getMessage());Thread.sleep(5000);}finally{
            dialog.setVisible(false);// 设置弹窗不可见System.exit(0);}}/**
     * 删除指定文件夹下的文件
     * @param path
     */publicstaticvoiddeleteFiles(String path){File file =newFile(path);if(file.exists()){if(file.isDirectory()){File[] files = file.listFiles();for(File f : files){if(f.isFile()){
                        f.delete();}elseif(f.isDirectory()){deleteFiles(f.getAbsolutePath());}}
                file.delete();}else{
                file.delete();}}}}
标签: java git 开发语言

本文转载自: https://blog.csdn.net/u012930947/article/details/139590049
版权归原作者 sqd233 所有, 如有侵权,请联系我们删除。

“(从零写到生成exe文件)Java 将Git作为文件云盘?我的世界MOD同步器?全代码从新建项目开始写”的评论:

还没有评论