我要传的是一个每天9-11点生成的500M的文件夹,WebService服务是以接口形式传输数据,无法直接传递文件,我将其压缩为zip格式,然后转换为字符串,以对象形式传递,在客户端解析解压整合成原来的文件,从而实现文件夹的传输。
文件结构如下
1.准备工作
pom
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.0.3.RELEASE
com.gwhn
webservice
0.0.1-SNAPSHOT
webservice
war
Demo project for Spring Boot
1.8
UTF-8
UTF-8
org.springframework.boot
spring-boot-starter-web-services
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-tomcat
javax.servlet
javax.servlet-api
4.0.1
provided
org.apache.cxf
cxf-rt-frontend-jaxws
3.2.6
org.apache.cxf
cxf-rt-transports-http
3.2.6
junit
junit
4.12
commons-io
commons-io
2.5
org.junit.jupiter
junit-jupiter-api
5.1.0-M2
test
org.apache.axis2
axis2
1.7.9
pom
net.iharder
base64
2.3.9
org.springframework.boot
spring-boot-maven-plugin
//建立对象
public class MicapsData implements Serializable{
private static final long serialVersionUID = -2506579878568411053L;
private String fileName;//micaps文件名
private String encodedFileString;//每次传输的字符串
}
//日期工具
public class DateUtil {
/**
* 获取当前时间数字
*/
public String getDate() {
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd HH:mm:ss");//20190822 12:50:02
String day = simpleDateFormat.format(date);
return day.toString();
}
/**
* 获取前推,后推日期日期yyyyMMdd
* */
public String getDate(int num){
Date date = new Date();//获取当前时间
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
calendar.add(Calendar.DATE,num);//日期往前推一天
date = calendar.getTime();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyMMdd");
return simpleDateFormat.format(date).toString();
}
}
//路径配置文件
pathconfig.txt
每日micaps文件夹路径:D:\\zhpfile\\ideaworkspace
临时文件夹路径:D:\\zhpfile\\ideaworkspace\\gz
日志存放路径:D:\\zhpfile\\ideaworkspace\\gwhnWebServiceLog
其他新增配置请联系xxxx
路径配置文件在resources文件夹下,我写了一个类专门读取这些路径
public class ReadConfig {
/**
* 读取配置文件所有字符
* */
public String readConfig() throws IOException,Exception{
BufferedReader bufferedReader = null;
URL url = ReadConfig.class.getClassLoader().getResource("pathconfig.txt");//文件路径
File file = new File(url.getFile());
FileReader fileReader = new FileReader(url.getFile());//得到配置文件
bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file.getPath()), "utf-8")); ;//用字符流读取
String word = "";
String str="";
while((str=bufferedReader.readLine())!=null) { //●判断最后一行不存在,为空
word = word + str;
}
bufferedReader.close();//关闭字符流
fileReader.close();
return word;
}
/**
* 从pathconfig中提取每日micaps文件夹上一级路径
* */
public String getMicapPath() throws Exception{
String configPath = readConfig().substring(readConfig().indexOf("每日micaps文件夹路径:")+14,readConfig().indexOf("临时文件夹路径:"));
DateUtil dateUtil = new DateUtil();
return configPath+"\\"+dateUtil.getDate(-1);//业务化运行使用的路径
// return "D:\\zhpfile\\ideaworkspace\\19102820";
}
/**
* 从pathconfig中提取每日临时文件夹路径
* */
public String getTempPath() throws Exception{
return readConfig().substring(readConfig().indexOf("临时文件夹路径:")+8,readConfig().indexOf("日志存放路径:"));//业务化运行使用的路径
// return "D:\\zhpfile\\ideaworkspace\\gz";
}
public String getLogPath() throws Exception{
return readConfig().substring(readConfig().indexOf("日志存放路径:")+7,readConfig().indexOf("其他新增配置"));//业务化运行使用的路径
}
}
2.文件处理
public interface ZipFileService {
public void FileToZip(String srcDir, OutputStream out, boolean KeepDirStructure) throws RuntimeException;
public void ZipToFile(File srcFile, String destDirPath);
public void compress(File sourceFile, ZipOutputStream zos, String name,
boolean KeepDirStructure) throws Exception;
public void copyFile(File fromFile,File toFile) throws Exception;
public String[] getFileList(File file) ;
public void deleteDirectory(File file);
}
public class ZipFileServiceImpl implements ZipFileService {
private static final int BUFFER_SIZE = 2 * 1024;
/**
* 原始压缩成ZIP 方法
* 由于文件太大无法传输,所以我修改成先压为为几个包,而后分开传输,到客户端解压到同一文件夹下
* @param srcDir 压缩文件夹路径
* @param out 压缩文件输出流
* @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
public void FileToZip(String srcDir, OutputStream out, boolean KeepDirStructure) throws RuntimeException {
long start = System.currentTimeMillis();
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(out);
File sourceFile = new File(srcDir);
compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
long end = System.currentTimeMillis();
System.out.println(srcDir+"压缩完成,耗时:" + (end - start) + " ms");
} catch (Exception e) {
throw new RuntimeException("zip error from ZipUtils", e);
} finally {
if (zos != null) {
try {
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* zip解压
* @param srcFile zip源文件
* @param destDirPath 解压后的目标文件夹
* @throws RuntimeException 解压失败会抛出运行时异常
*/
@Override
public void ZipToFile(File srcFile, String destDirPath) {
long start = System.currentTimeMillis();
if (!srcFile.exists()) { // 判断源文件是否存在
throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
}
// 开始解压
ZipFile zipFile = null;
try {
zipFile = new ZipFile(srcFile);
Enumeration> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry) entries.nextElement();
System.out.println("解压" + entry.getName());
if (entry.isDirectory()) { // 如果是文件夹,就创建个文件夹
String dirPath = destDirPath + "/" + entry.getName();
File dir = new File(dirPath);
dir.mkdirs();
} else {
File targetFile = new File(destDirPath + "/" + entry.getName());// 如果是文件,就先创建一个文件,然后用io流把内容copy过去
if(!targetFile.getParentFile().exists()){ // 保证这个文件的父文件夹必须要存在
targetFile.getParentFile().mkdirs();
}
targetFile.createNewFile();
// 将压缩文件内容写入到这个文件中
InputStream is = zipFile.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(targetFile);
int len;
byte[] buf = new byte[BUFFER_SIZE];
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.close();// 关流顺序,先打开的后关闭
is.close();
}
}
long end = System.currentTimeMillis();
System.out.println("解压完成,耗时:" + (end - start) +" ms");
} catch (Exception e) {
throw new RuntimeException("unzip error from ZipUtils", e);
} finally {
if(zipFile != null){
try {
zipFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 递归压缩方法
* @param sourceFile 源文件
* @param zos zip输出流
* @param name 压缩后的名称
* @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
* @throws Exception
*/
public void compress(File sourceFile, ZipOutputStream zos, String name,
boolean KeepDirStructure) throws Exception {
byte[] buf = new byte[BUFFER_SIZE];
if (sourceFile.isFile()) {
// 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
zos.putNextEntry(new ZipEntry(name));
// copy文件到zip输出流中
int len;
FileInputStream in = new FileInputStream(sourceFile);
while ((len = in.read(buf)) != -1) {
zos.write(buf, 0, len);
}
// Complete the entry
zos.closeEntry();
in.close();
} else {
File[] listFiles = sourceFile.listFiles();
if (listFiles == null || listFiles.length == 0) {
// 需要保留原来的文件结构时,需要对空文件夹进行处理
if (KeepDirStructure) {
// 空文件夹的处理
zos.putNextEntry(new ZipEntry(name + "/"));
// 没有文件,不需要文件的copy
zos.closeEntry();
}
} else {
for (File file : listFiles) {
// 判断是否需要保留原来的文件结构
if (KeepDirStructure) {
// 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
// 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
compress(file, zos, name + "/" + file.getName(), KeepDirStructure);
} else {
compress(file, zos, file.getName(), KeepDirStructure);
}
}
}
}
}
/**
* 复制文件
* @param fromFile
* @param toFile
*
* 2016年12月19日 下午3:31:50
* @throws IOException
*/
@Override
public void copyFile(File fromFile, File toFile) throws Exception {
FileInputStream ins = new FileInputStream(fromFile);
FileOutputStream out = new FileOutputStream(toFile);
byte[] b = new byte[1024];
int n=0;
while((n=ins.read(b))!=-1){
out.write(b, 0, n);
}
ins.close();
out.close();
}
/**
* 获取一个文件夹下所有文件名
* */
@Override
public String[] getFileList(File file) {
return new String[0];
}
// 删除文件夹
@Override
public void deleteDirectory(File file) {
if (file.isFile()) {// 表示该文件不是文件夹
file.delete();
} else {
String[] childFilePaths = file.list();// 首先得到当前的路径
for (String childFilePath : childFilePaths) {
File childFile = new File(file.getAbsolutePath() + "/" + childFilePath);
deleteDirectory(childFile);
}
file.delete();
}
}
}
3.要暴露服务的接口,重点来了
注意文件转字符串的类在net.iharder下,
接口路径如下
@WebService(targetNamespace = “http://service.gwhn.com/”, endpointInterface = “com.gwhn.service.FileService”)
前面是服务空间,倒序到服务为止,后面是正序接口类,写到要使用的接口
@WebService
public interface FileService {
@WebMethod
public MicapsData getZipMicapsdata(String name,String date) throws Exception;
@WebMethod
public int deleteTempFiles(int sendOver)throws Exception;
}
import com.gwhn.dao.FileDao;
import com.gwhn.dao.impl.FileDaoImpl;
import com.gwhn.entity.MicapsData;
import com.gwhn.service.FileService;
import com.gwhn.service.ZipFileService;
import com.gwhn.util.DateUtil;
import com.gwhn.util.LogUtil;
import com.gwhn.util.ReadConfig;
import net.iharder.*;
import net.iharder.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.jws.WebService;
import java.io.*;
import java.util.*;
/**
* Created by DLuser on 2019/10/30.
*/
@WebService(targetNamespace = "http://service.gwhn.com/", endpointInterface = "com.gwhn.service.FileService")
@Component
public class FileServiceImpl implements FileService {
ReadConfig readConfig = new ReadConfig();
private Map micapsDataMap = new HashMap();
String filename = "";
public FileServiceImpl() throws Exception {
}
/**
* 根据文件名获取当天预测文件形成的字符串
*/
@Override
public MicapsData getZipMicapsdata(String name, String date) throws Exception {
ZipFileService zipFileService = new ZipFileServiceImpl();
DateUtil dateUtil = new DateUtil();
try{
if (name.equals("1") && date.equals("1")) {
zipFileService.deleteDirectory(new File(readConfig.getTempPath()));
LogUtil logUtil = new LogUtil();
System.out.println("本次传输完毕");
logUtil.writeLog(dateUtil.getDate()+name+"传输成功");
return null;//传来传输完毕信号,处理缓存
} else {
String tempPath = readConfig.getTempPath();//获取临时文件夹路径D:\zhpfile\ideaworkspace\gz
System.out.println("临时文件夹路径:" + tempPath);
String micapsPath = readConfig.getMicapPath();//获取micaps文件夹路径D:\zhpfile\ideaworkspace\19102820
System.out.println("micaps文件夹路径:" + micapsPath);
String dateString = dateUtil.getDate(-1);//19082220
File file = new File(tempPath);
if (!file.exists()) {
file.mkdirs();
}
// File file1 = new File(tempPath + "\\" + date + "log.txt");
System.out.println("对方传递的当天日期字符串:" + date);
if (date.equals(dateString)) {
file.mkdirs();
if (name.equals(dateString + "10FG6.zip")) {
System.out.println("开始复制"+micapsPath+"中零散数据到"+tempPath);
copyFiles(micapsPath, tempPath, dateString);//复制四中数据到指定目录下
zipFiles(micapsPath, tempPath, dateString); /**分别压缩四个文件*/
}
/**将当天的各项micaps数据存入映射*/
List filesList = getFilNameStringList();
for (int i = 0; i < filesList.size(); i++) {
file = new File(tempPath + "\\" + dateString + filesList.get(i) + ".zip");
MicapsData micapsData = new MicapsData();
micapsData.setFileName(file.getName());
FileDao fileDao = new FileDaoImpl();
String fileString = fileDao.getFileByteString(file);
micapsData.setEncodedFileString(fileDao.getFileByteString(file));
micapsDataMap.put(file.getName(), micapsData);
}
}
filename = name;
System.out.println("对方请求的的文件名:" + filename);
MicapsData micapsData = micapsDataMap.get(filename);
return micapsData;
}
}catch (Exception e){
DateUtil dateUtil1 = new DateUtil();
LogUtil logUtil = new LogUtil();
logUtil.writeLog(dateUtil.getDate()+"传输失败");
System.out.println("传输失败");
}
return null;
}
/**
* 接收到对方传来的传输完毕信息,删除缓存文件夹
*/
@Override
public int deleteTempFiles(int sendOver) throws Exception {
if (sendOver == 1) {
ZipFileService zipFileService = new ZipFileServiceImpl();
File file = new File(readConfig.getTempPath());
zipFileService.deleteDirectory(file);
}
return 1;
}
/**
* 复制当天对应的文件
*/
public void copyFiles(String micapsPath, String tempPath, String dateString) throws Exception {
ZipFileService zipFileService = new ZipFileServiceImpl();
File file = new File(micapsPath);
List micapsFileList = new ArrayList();
File[] fileList = file.listFiles();
for (int i = 0; i < fileList.length; i++) {
if (!fileList[i].isDirectory()) {
File srcfile = new File(fileList[i].getPath());
// File gzFile = new File("D:\\zhpfile\\ideaworkspace\\gz19102820\\");
File gzFile = new File(tempPath + "\\" + dateString + "gz");
if (!gzFile.exists()) {
gzFile.mkdirs();
}
File tofile = new File(gzFile.getPath() + "\\" + srcfile.getName());
zipFileService.copyFile(srcfile, tofile);
}
}
FileOutputStream out = new FileOutputStream(new File(tempPath + "\\" + dateString + "gz.zip"));
zipFileService.FileToZip(tempPath + "\\" + dateString + "gz", out, true);
}
/**
* 生成文件夹字符集合
*/
public List getFilNameStringList() {
List pathList = new ArrayList();
pathList.add("10FG6");
pathList.add("WIND_10M");
pathList.add("WIND10M");
pathList.add("gz");
return pathList;
}
/**
* 压缩四个文件夹到指定目录下
*/
public void zipFiles(String micapsPath, String tempPath, String dateString) throws Exception {
ZipFileService zipFileService = new ZipFileServiceImpl();
OutputStream outputStream = new FileOutputStream(tempPath + "\\" + dateString + "10FG6.zip");
zipFileService.FileToZip(micapsPath + "\\10FG6", outputStream, true);
outputStream = new FileOutputStream(tempPath + "\\" + dateString + "WIND_10M.zip");
zipFileService.FileToZip(micapsPath + "\\WIND_10M", outputStream, true);
outputStream = new FileOutputStream(tempPath + "\\" + dateString + "WIND10M.zip");
zipFileService.FileToZip(micapsPath + "\\WIND10M", outputStream, true);
}
}
将文件转换为字符串!!!
@Component
public class FileDaoImpl implements FileDao {
/**
* 将文件转换为字符串
*/
@Override
public String getFileByteString(File file) throws Exception {
String encodedFileString = "";
InputStream inputStream = new FileInputStream(file);
long length = file.length();// 取得文件大小
byte[] bytes = new byte[(int) length];// 根据大小创建字节数组,每次大约20M
int offset = 0;// 读取文件内容到字节数组
int numRead = 0;
while (offset < bytes.length
&& (numRead = inputStream.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
if (offset < bytes.length) {// 读取完毕的校验
throw new IOException("不能完全讀取文件:" + file.getName());
}
inputStream.close();
encodedFileString = Base64.encodeBytes(bytes);
return encodedFileString;
}
}
5,webservice服务配置,这是关键
import com.gwhn.service.FileService;
import com.gwhn.service.impl.FileServiceImpl;
import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.xml.ws.Endpoint;
/**
* Created by DLuser on 2019/10/28.
*/
@Configuration
public class WebServiceConfig {
@Bean
public ServletRegistrationBean dispatcherServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/service/*");//发布服务名称
}
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
@Bean
public FileService fileService() throws Exception{
return new FileServiceImpl();
}
@Bean
public Endpoint endpoint() throws Exception{
EndpointImpl endpoint = new EndpointImpl(springBus(), fileService());//绑定要发布的服务
endpoint.publish("/micapsdata"); //显示要发布的名称
return endpoint;
}
}
然后是日志书写,这个需求是有时间和是否成功,我写的很简单
public class LogUtil {
/**
* 获取日志文件
*/
public File getLogFile() throws Exception {
ReadConfig readConfig = new ReadConfig();
File file = new File(readConfig.getLogPath()+".txt");
if (!file.exists()) {
file.createNewFile();
}
return file;
}
/**
* 获取日志文件所有字符,本方法建议不要和readConfig中的合并
*/
public String getLogString() throws Exception {
File file = getLogFile();
BufferedReader bufferedReader = null;
FileReader fileReader = new FileReader(file);//得到配置文件
bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file.getPath()), "utf-8"));
;//用字符流读取
String word = "";
String str = "";
while ((str = bufferedReader.readLine()) != null) { //●判断最后一行不存在,为空
word = word + str;
}
bufferedReader.close();//关闭字符流
fileReader.close();
return word;
}
/**
* 获取日志文件'所有字符
*/
public void writeLog(String content) throws Exception {
FileOutputStream fileOutputStream = null;
ReadConfig readConfig = new ReadConfig();
File file = getLogFile();
String oldContent = getLogString();
fileOutputStream = new FileOutputStream(file);
fileOutputStream.write((oldContent+"\t\t"+content).getBytes());
fileOutputStream.flush();
fileOutputStream.close();
}
}
最后是启动类,是已经可以打包扔到tomcat的那种
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class WebserviceApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(WebserviceApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
// 这里sources的类就是启动类
return builder.sources(WebserviceApplication.class);
}
}
接下来写客户端
需求是定时检查固定目录是否有当天文件,没有的话发送请求到服务端请求文件