现在新的项目对于升级打包都方便,但是公司还有一些老项目还是采用每次升级替换静态文件和编译后的.class文件这种方式来升级。
小修小改还没啥,遇到几个大需求要一起打包,改动的多了就比较费时间了。挨个新建目录也很烦鸭…
于是就打算写一个自动打包的程序,根据版本控制软件的提交记录(相对路径)来进行自动打包并压缩。
打包后如下:
自动复制文件到指定目录并压缩打包代码
package faker.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @program: 装维系统
* @description: PackageUtil 智能打包工具类 复制方法依赖jdk1.7
* 根据svn提交记录的相对路径拷贝出打包文件
* @author: 淡梦如烟
* @create: 2019-09-11 11:31
*/
public class PackageUtil {
/**
* 启动的main方法
* 直接启动
* @param args 参数
*/
public static void main(String[] args){
test();
//通过输入参数打包
// inputStart();
}
/**
* 输出文件列表
*/
public static List<String> outPutFileList = new ArrayList<>();
/**
* 自动打包的系统代码支持
* 需在项目里启动
* @param request 请求
* @param response 响应
* @return 返回结果
*/
// public Map<String,Object> autoPackageService(HttpServletRequest request, HttpServletResponse response) {
// Map<String,Object> result = new HashMap<>();
// //项目根路径
// String projectRoot = request.getParameter("ProjectRoot");
// //打包文件列表字符串 从svn提交记录里复制出来的
// String filesListstr = request.getParameter("filesListstr");
// //导出路径
// String outputPath = request.getParameter("outputPath");
// result = startPackage(projectRoot,filesListstr,outputPath);
// return result;
// }
/**
* 开始打包的静态方法
* @param projectRoot 项目根路径
* @param filesListstr 打包文件列表字符串 从svn提交记录里复制出来的
* @param outputPath 输出路径
* @return
*/
private static Map<String,Object> startPackage(String projectRoot, String filesListstr,String outputPath) {
Map<String,Object> result = new HashMap<>();
projectRoot = changePath(projectRoot);
//将从svn提交记录里复制出来的打包文件列表字符串转化为文件地址列表
List<String> filesList = getFilesStrToList(filesListstr);
//将java文件处理为class源文件地址
List<String> classFilesList = changeToRealClassPath(filesList,projectRoot);
Map<String,Object> copy = startDoCopy(classFilesList,projectRoot,outputPath);
result.put("copyInfo",copy);
result.put("inputFile",filesList);
// result.put("outputFile",classFilesList);
return result;
}
/**
* 变更路径写法
* @param projectRoot 路径
* @return
*/
private static String changePath(String projectRoot){
//项目根路径处理 补全路径
if(projectRoot.contains("\\")){
if(!"\\".equals(projectRoot.substring(projectRoot.length()-2,projectRoot.length()))){
projectRoot = projectRoot.replaceAll("\\\\","/");
}
}
//替换路径符号
if(projectRoot.contains("/")) {
if (!"/".equals(projectRoot.substring(projectRoot.length() - 2, projectRoot.length()))) {
projectRoot = projectRoot + "/";
}
}
return projectRoot;
}
/**
* 开始复制文件
* @param classFilesList 待复制的文件列表
* @param projectRoot 项目路径
* @param outputPath 输出路径
* @return
*/
private static Map<String,Object> startDoCopy(List<String> classFilesList,String projectRoot,String outputPath) {
Map<String,Object> result = new HashMap<>();
List<String> errorList = new ArrayList<>();
outputPath = changePath(outputPath);
File file = new File(outputPath);
//没有目录就创建根目录
if (!file.exists()) {
file.mkdirs();
}
//循环复制文件
for(String files:classFilesList){
if(".class".equals(files.substring(files.length()-6,files.length()))){
//class文件存在内部类,有可能编译出多个文件,故单独处理
List<String> errorList2 = copyClass(files,projectRoot,outputPath);
errorList.addAll(errorList2);
}else{
//其他文件直接复制
File staticFile = new File(projectRoot+files);
if (staticFile.exists()) {
File output = new File(outputPath+files);
if (!output.exists()) {
output.getParentFile().mkdirs();
}else {
output.delete();
}
String error = copyFileUsingJava7Files(staticFile,output);
if(null!=error){
errorList.add(error);
}
}
//加入输出文件列表豪华套餐
outPutFileList.add(files);
}
}
StringBuffer text = new StringBuffer();
for(String str:outPutFileList){
text.append(str).append(System.lineSeparator());
}
//System.out.println(text.toString());
//输出文件明细
File outputListText = new File(outputPath+"/更新文件明细.txt");
if(!outputListText.exists()){
outputListText.getParentFile().mkdirs();
}
try {
outputListText.createNewFile();
FileWriter fw = new FileWriter(outputListText, true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(text.toString());
bw.flush();
bw.close();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
//生成压缩包
File file2 = new File(outputPath);
try {
System.out.println("正在压缩文件.....");
ZipFolderMethod(new File(outputPath),new File(file2.getParentFile().getPath()+"/新疆移动"+file2.getName()+".zip"));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("压缩完毕");
result.put("errorList",errorList);
return result;
}
/**
* 复制class源文件
* 主要是判断有无内部类文件
* @param files class源文件路径
* @param projectRoot 项目路径
* @param outputPath 输出路径
* @return
*/
private static List<String> copyClass(String files, String projectRoot, String outputPath) {
List<String> errorList = new ArrayList<>();
List<String> classList = new ArrayList<>();
//原文件
File staticFile = new File(projectRoot+files);
classList.add(staticFile.getPath());
File parentDir = staticFile.getParentFile();
//原文件目录下的所有文件
File[] parentFiles = parentDir.listFiles();
int filesSize = parentFiles.length;
StringBuffer stringBuffer = new StringBuffer();
/*
查找该目录下是否有class文件的内部类编译文件
InstallBaseService$1.class 这种
其中内部类编号不会大于本目录下文件个数,故都遍历一遍比较
*/
for(int i=1;i<filesSize;i++){
//清理buffer
stringBuffer.setLength(0);
//得到文件名
String fileName = staticFile.getName();
fileName = fileName.substring(0,fileName.length()-6);
//试探文件名
stringBuffer.append(fileName).append("$").append(i).append(".class");
//如果有内部类就加入列表
for(File pfile:parentFiles){
if(pfile.getName().equals(stringBuffer.toString())){
classList.add(pfile.getPath());
}
}
}
//获取输出路径的目录路径
File outputFile1 = new File(outputPath+files);
String outputFilePath = outputFile1.getParentFile().getPath();
//写入class文件及其内部类
for(String classPath:classList){
//原class路径
File classFile = new File(classPath);
//输出路径
File output2 = new File(outputFilePath+"/"+classFile.getName());
if (!output2.exists()) {
output2.getParentFile().mkdirs();
}else {
output2.delete();
}
String error = copyFileUsingJava7Files(classFile,output2);
if(null!=error){
errorList.add(error);
}
String out = files.substring(0,files.lastIndexOf("/"))+"/"+classFile.getName();
//加入输出文件列表豪华套餐
outPutFileList.add(out);
}
return errorList;
}
/**
* Java7的文件复制方法
* @param source 源文件
* @param dest 目标文件
*/
private static String copyFileUsingJava7Files(File source, File dest){
String err = null;
try {
Files.copy(source.toPath(), dest.toPath());
System.out.println("复制文件"+source.getPath()+"\n到:"+dest.getPath()+"完毕!\n");
} catch (IOException e) {
e.printStackTrace();
err = "\n"+e.toString();
}
return err;
}
/**
* 将java文件处理为class源文件地址
* @param filesList java文件地址列表
* @param projectRoot 项目根路径
* @return class源文件地址列表
*/
private static List<String> changeToRealClassPath(List<String> filesList,String projectRoot) {
List<String> list = new ArrayList<>(filesList.size());
for(String path:filesList){
if("src/".equals(path.substring(0,4))){
String classPath = path.substring(4,path.length());
//java变class源文件
if(path.contains(".")){
String[] pathSplit= path.split("\\.");
String lastSuff = pathSplit[pathSplit.length-1];
if("java".equals(lastSuff.toLowerCase().trim())){
classPath = "WebRoot/WEB-INF/classes/" + classPath.substring(0,classPath.length()-4)+"class";
}else if("xml".equals(lastSuff.toLowerCase().trim())){
classPath = "WebRoot/WEB-INF/classes/" + classPath;
}
}
list.add(classPath);
}else{
list.add(path);
}
}
return list;
}
/**
* 将从svn提交记录里复制出来的打包文件列表字符串转化为文件地址列表
* @param filesListstr 打包文件列表字符串
* @return 文件地址列表
*/
private static List<String> getFilesStrToList(String filesListstr) {
filesListstr = filesListstr.replaceAll("\t\n","\n");
String[] filesArr = filesListstr.split("\n");
List<String> list = new ArrayList<>();
for(String file:filesArr){
if(file!=null&&!"".equals(file.trim())){
list.add(file);
}
}
return list;
}
/**
* 加载测试数据
*/
private static String[] getData(){
String projectRoot = "F:\\AllWorkSpace\\新疆移动";
String copyPath = "I:\\temp\\新疆移动\\新疆移动自动打包";
final String filesListstr = "" +
"src/wlcs/auto/dao/ScanOrderWaitingCreateDao.java\t\n" +
"src/wlcs/auto/dao/ibatis/ScanOrderWaitingCreate.xml\t\n" +
"src/wlcs/ws/install/services/impl/EomsConstructionGd2DwGdservice.java\t\n" +
"src/wlcs/ws/install/services/impl/FuKaiServiceProviderImpl.java\t\n" +
"src/wlcs/ws/install/services/impl/PackXmlUtilNew.java\t\n" +
"src/wlcs/ws/obstacle/services/impl/ObstacleServiceProviderImpl.java\t\n" +
"src/wlcs/ws/obstacle/services/model/ObstacleXmlInfo.java\t\n" +
"";
return new String[]{projectRoot,filesListstr,copyPath};
}
/**
* 测试
*/
public static void test(){
//项目根路径
String projectRoot = null;
//打包文件列表字符串 从svn提交记录里复制出来的
String filesListstr = null;
projectRoot = getData()[0];
filesListstr = getData()[1];
String copyPath = getData()[2];
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
//导出加上时间防止重复
copyPath = copyPath+"\\"+simpleDateFormat.format(new Date());
Map<String,Object> result = startPackage(projectRoot,filesListstr,copyPath);
System.out.println(result);
}
/**
* 输入数据进行复制
*/
public static void inputStart(){
//项目根路径
String projectRoot = null;
//打包文件列表字符串 从svn提交记录里复制出来的
String filesListstr = null;
//导出路径
String copyPath = null;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
System.out.println("请输入待复制的项目根路径(例 F:\\AllWorkSpace\\新疆移动 ):");
Scanner scanner = new Scanner(System.in);
projectRoot = scanner.nextLine();
System.out.println("请输入待导出的根路径(例 F:\\package\\新疆移动 ):");
//导出加上时间防止重复
copyPath = scanner.nextLine()+"\\"+simpleDateFormat.format(new Date());
System.out.println("请粘贴从svn上复制的提交文件相对路径列表(输入exit+回车键结束):");
projectRoot = "";
//每一行
String buffer;
while(!"exit".equals(buffer=scanner.nextLine())){
//这里写你读到每行后应该做的事情
if(!"exit".equals(buffer)){
filesListstr += (buffer+"\t\n");
}
}
scanner.close();
//计时
Long time1 = System.currentTimeMillis();
System.out.println("正在复制中,请稍后...");
Map<String,Object> result = startPackage(projectRoot,filesListstr,copyPath);
System.out.println("复制完成,耗时"+(System.currentTimeMillis()-time1)+"毫秒~");
}
/**
* 按目录压缩文件
* @param sFoder 输入目录
* @param zipFolder 输出目录
* @throws IOException 异常
*/
public static void ZipFolderMethod(File sFoder, File zipFolder) throws IOException {
// TODO Auto-generated method stub
ZipOutputStream zipoutFolder = new ZipOutputStream(new FileOutputStream(zipFolder));
InputStream in = null;
// zipoutFolder.setEncoding("GBK"); //为解决注释乱码
zipoutFolder.setComment("文件夹的压缩");
// 列出所有文件的路径,保存到集合中,在ListAllDirectory(sFoder)方法中用到递归
TreeSet<String> pathTreeSet = ListAllDirectory(sFoder);
String[] pathStr = pathTreeSet.toString().substring(1, pathTreeSet.toString().length() - 1).split(",");
for (int i = 0; i < pathStr.length; i++) {
String filePath = pathStr[i].trim();
StringBuffer pathURL = new StringBuffer();
String[] tempStr = filePath.split("\\\\"); // 这个地方需要注意,在Java中需要“\\\\”表示“\”字符串。
// 这里的变量j是从第几层开始打压缩包
Boolean start = false;
for (int j = 0; j < tempStr.length - 1; j++) {
if("WebRoot".equals(tempStr[j])){
start = true;
}
if(start){
pathURL.append(tempStr[j] + File.separator);
}
}
String path = pathURL.append(tempStr[tempStr.length - 1]).toString();
in = new FileInputStream(new File(filePath));
zipoutFolder.putNextEntry(new ZipEntry(path));
int temp = 0;
while ((temp = in.read()) != -1) {
zipoutFolder.write(temp);
}
in.close();
}
zipoutFolder.close();
}
/**
* 获取目录下的所有文件
* @param sFolder 目录路径
* @return
*/
public static TreeSet<String> ListAllDirectory(File sFolder) {
TreeSet<String> ts = new TreeSet<String>();
if (sFolder != null) {
if (sFolder.isDirectory()) {
File f[] = sFolder.listFiles();
if (f != null) {
for (int i = 0; i < f.length; i++) {
ts.addAll(ListAllDirectory(f[i]));
}
}
} else {
ts.add(sFolder.toString());
}
}
return ts;
}
}
可以直接执行main方法在test()里改数据或者使用inputStart()方法来输入参数