From 18467fa05ba6c968796e66b67797fcf33ebf0367 Mon Sep 17 00:00:00 2001 From: zhangyulong Date: Wed, 3 Aug 2022 16:04:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=99=84=E4=BB=B6=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- smtweb-framework/bpm/pom.xml | 40 +- .../bpm/spring/config/FileConfigProperties.java | 38 + .../bpm/spring/controller/AttachController.java | 427 +++++++ .../dataCacheInit/AttachFolderEntityBuffer.java | 71 ++ .../bpm/spring/file/attach/AttachFileWork.java | 102 ++ .../bpm/spring/file/attach/AttachFtpWork.java | 222 ++++ .../bpm/spring/file/attach/AttachHelper.java | 283 +++++ .../system/bpm/spring/file/attach/AttachUtil.java | 135 +++ .../bpm/spring/file/attach/IAttachTraceIntf.java | 28 + .../bpm/spring/file/attach/IAttachWorkIntf.java | 115 ++ .../system/bpm/spring/initPlugin/RunDataInit.java | 27 + .../smtweb/system/bpm/util/UtilDownloadFile.java | 135 +++ .../java/cc/smtweb/system/bpm/util/UtilFile.java | 1178 ++++++++++++++++++++ .../java/cc/smtweb/system/bpm/util/UtilLogger.java | 66 ++ .../java/cc/smtweb/system/bpm/util/UtilMath.java | 465 ++++++++ .../java/cc/smtweb/system/bpm/util/UtilString.java | 504 +++++++++ .../cc/smtweb/system/bpm/util/ftp/FtpTask.java | 6 + .../smtweb/system/bpm/util/ftp/FtpTaskManager.java | 255 +++++ .../cc/smtweb/system/bpm/util/ftp/FtpUtil.java | 393 +++++++ .../system/bpm/util/ftp/IDownloadFileWorker.java | 6 + .../system/bpm/util/ftp/IFtpServerConfig.java | 16 + .../cc/smtweb/system/bpm/util/ftp/IFtpUtil.java | 59 + .../cc/smtweb/system/bpm/util/ftp/SFtpUtil.java | 396 +++++++ .../system/bpm/web/sys/base/attach/AttachInfo.java | 16 +- .../base/attachFolder/pojo/AttachFolderPojo.java | 16 + .../bpm/src/main/resources/config/application.yaml | 16 + .../framework/core/db/dao/AbstractEntityDao.java | 6 + smtweb-framework/pom.xml | 1 + 28 files changed, 5015 insertions(+), 7 deletions(-) create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/config/FileConfigProperties.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/controller/AttachController.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/dataCacheInit/AttachFolderEntityBuffer.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachFileWork.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachFtpWork.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachHelper.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachUtil.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/IAttachTraceIntf.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/IAttachWorkIntf.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/initPlugin/RunDataInit.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilDownloadFile.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilFile.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilLogger.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilMath.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilString.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpTask.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpTaskManager.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpUtil.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IDownloadFileWorker.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IFtpServerConfig.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IFtpUtil.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/SFtpUtil.java create mode 100644 smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/attachFolder/pojo/AttachFolderPojo.java diff --git a/smtweb-framework/bpm/pom.xml b/smtweb-framework/bpm/pom.xml index 150d9ad..85d8450 100644 --- a/smtweb-framework/bpm/pom.xml +++ b/smtweb-framework/bpm/pom.xml @@ -129,6 +129,38 @@ spring-boot-starter-test test + + + com.aliyun + aliyun-java-sdk-core + 4.0.6 + + + commons-net + commons-net + 3.6 + compile + + + com.jcraft + jsch + 0.1.53 + + + commons-fileupload + commons-fileupload + 1.4 + + + commons-io + commons-io + 2.11.0 + + + org.apache.httpcomponents + httpclient + 4.5.7 + @@ -176,22 +208,22 @@ - E:/WORKSPACE/JJKJ-GIT/CODE/smtweb/sw-ui-design-vue/dist/ + E:/jujia/source/sw-ui-design-vue/dist/ ${basedir}/target/classes/static/design/ui - E:/WORKSPACE/JJKJ-GIT/CODE/smtweb/sw-db-design-vue/dist/ + E:/jujia/source/sw-db-design-vue/dist/ ${basedir}/target/classes/static/design/db - E:/WORKSPACE/JJKJ-GIT/CODE/smtweb/sw-flow-design-vue/dist/ + E:/jujia/source/sw-flow-design-vue/dist/ ${basedir}/target/classes/static/design/flow - E:/WORKSPACE/JJKJ-GIT/CODE/smtweb/sw-framework-widget-vue/dist/ + E:/jujia/source/sw-framework-widget-vue/dist/ ${basedir}/target/classes/static/design/preview diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/config/FileConfigProperties.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/config/FileConfigProperties.java new file mode 100644 index 0000000..69e97b3 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/config/FileConfigProperties.java @@ -0,0 +1,38 @@ +package cc.smtweb.system.bpm.spring.config; + +import cc.smtweb.framework.core.util.JsonUtil; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "smtweb.file") +public class FileConfigProperties { + + /** + * 系统底层附件保存路径和访问路径 + */ + private String localPath; + private String url; + + /** + * 自建的附件上传路径和访问路径,支持ftp + */ + private String attachTempPath;//临时文件保存路径 + private String attachPath;//保存路径 + private String attachHttpPath;//文件访问地址 + private String attachType;//上传类型sftp/ftp/local + + private String attachFtpIp;//ftp IP地址 + private int attachFtpPort;//ftp 端口 + private String attachFtpUser;//ftp 用户名 + private String attachFtpPwd;//ftp 密码 + + + @Override + public String toString() { + return JsonUtil.encodeString(this); + } + +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/controller/AttachController.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/controller/AttachController.java new file mode 100644 index 0000000..be43c7c --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/controller/AttachController.java @@ -0,0 +1,427 @@ +package cc.smtweb.system.bpm.spring.controller; + +import cc.smtweb.framework.core.common.R; +import cc.smtweb.framework.core.db.DbEngine; +import cc.smtweb.framework.core.util.Consts; +import cc.smtweb.framework.core.util.DateUtil; +import cc.smtweb.framework.core.util.PubUtil; +import cc.smtweb.system.bpm.spring.config.FileConfigProperties; +import cc.smtweb.system.bpm.spring.file.attach.AttachHelper; +import cc.smtweb.system.bpm.spring.file.attach.AttachUtil; +import cc.smtweb.system.bpm.util.UtilDownloadFile; +import cc.smtweb.system.bpm.util.UtilFile; +import cc.smtweb.system.bpm.util.UtilLogger; +import cc.smtweb.system.bpm.util.UtilMath; +import cc.smtweb.system.bpm.web.sys.base.attach.AttachInfo; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; +import sun.misc.BASE64Decoder; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Created by AKmm at 11-6-14 上午10:44 + * 附件管理 + */ +@Slf4j +@RestController +@RequestMapping("/api/attach") +public class AttachController { + private static Logger logger = LoggerFactory.getLogger(AttachController.class); + @Autowired + private FileConfigProperties properties; + @Autowired + private AttachHelper attachHelper; + @Autowired + private AttachUtil attachUtil; + @Autowired + private DbEngine dbEngine; + private BASE64Decoder decoder = new BASE64Decoder(); + + /** + * + * @param request + * @param type 类型,如idcard:身份证、headImg:头像 + * @param ownerId 拥有者ID + * @param path 存储目录路径名,如:idcard + * @param attachIsTemp 是否临时文件:true/false 字符串 + * @param attachName 附件名称,如:XXXXX.jpg + * @param savePath 保存路径,指定文件保存目录,可为空 + * @return + * @throws Exception + */ + @PostMapping({"/upload"}) + public R upload(HttpServletRequest request, @RequestParam(value = "type", required = false) String type, + @RequestParam(value = "ownerId", required = false) Long ownerId, + @RequestParam(value = "path", required = false) String path, + @RequestParam(value = "attachIsTemp", required = false) String attachIsTemp, + @RequestParam(value = "attachName", required = false) String attachName, + @RequestParam(value = "savePath", required = false) String savePath) throws Exception { + CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext()); + //判断是否多文件上传 + if (!multipartResolver.isMultipart(request)) { + return R.error("文件不存在"); + } + MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; + Iterator itr = multiRequest.getFileNames(); + MultipartFile file = null; + while (itr.hasNext()) { + file = multiRequest.getFile(itr.next()); + AttachInfo attach = new AttachInfo(); + attach.setId(dbEngine.nextId()); + attach.setType(type);//附件类别 + if(null !=ownerId) { + attach.setOwnerId(ownerId);//附件拥有者id + } + attach.setPath(path);//附件路径 + attach.setPartyId(-1l); + attach.setTime(PubUtil.getLastTime()); + attach.setUserId(-1l); + attach.setIsTemp("true".equals(attachIsTemp) ? 1 : 0);//暂时没有有效拥有者标记 方便定时任务清除垃圾附件 + // 上传文件名 + final int i = file.getOriginalFilename().lastIndexOf("."); + if (i >= 0) { + attach.setSuffix(file.getOriginalFilename().substring(i)); + } + if (PubUtil.isEmptyStr(attachName)) { + attachName = file.getOriginalFilename(); + } + else { + attachName = attachName + attach.getSuffix(); + } + attach.setName(attachName); + Map ret = new HashMap<>(); + try { + // 上传文件域对象 + File upload = new File(attachHelper.getAttachTmpPath() + attach.getId() + attach.getSuffix()); + attach.setSize((long) FileCopyUtils.copy(file.getInputStream(), new BufferedOutputStream(new FileOutputStream(upload)))); + if (PubUtil.isEmpty(savePath)) { + localSaveAttach(attach, upload); + } else {//复制到指定目录 + String filePath; + if ("-".equals(savePath)) filePath = upload.getAbsolutePath(); + else { + filePath = savePath + DateUtil.nowDateTimeString() + UtilFile.FSChar + attach.getName(); + UtilFile.copy(upload, filePath, true); + } + } + } catch (Exception e) { + logger.error("上传文件失败", e); + return R.error("上传文件失败"); + } + return R.success(attach.getId()); + } + // 上传文件类型 + //String uploadContentType = file.getContentType(); + return R.error("上传文件失败"); + } + + /** + * + * @param request + * @param response + * @param base64File 文件base64编码 + * @param attachId 附件ID,可为空,如果有,则替换此附件ID对应数据 + * @param type 类型,如idcard:身份证、headImg:头像 + * @param ownerId 拥有者ID + * @param path 存储目录路径名,如:idcard + * @param attachIsTemp 是否临时文件:true/false 字符串 + * @param attachName 附件名称,如:XXXXX.jpg + * @param savePath 保存路径,指定文件保存目录,可为空 + * @param suffix 文件后缀,如.jpg + * @return + * @throws Exception + */ + @RequestMapping(value = "/uploadBase64", method = RequestMethod.POST) + public R uploadBase64(HttpServletRequest request, HttpServletResponse response, + @RequestParam(value = "base64File", required = false) String base64File, + @RequestParam(value = "attachId", required = false) Long attachId, + @RequestParam(value = "type", required = false) String type, + @RequestParam(value = "ownerId", required = false) Long ownerId, + @RequestParam(value = "path", required = false) String path, + @RequestParam(value = "attachIsTemp", required = false) String attachIsTemp, + @RequestParam(value = "attachName", required = false) String attachName, + @RequestParam(value = "savePath", required = false) String savePath, + @RequestParam(value = "suffix", required = false) String suffix + ) throws Exception { +// UtilLogger.error("上传文件接收base64", base64File); + if (null == base64File || "".equals(base64File)){ + return R.error("文件不能为空"); + } + String str[]=base64File.split(","); + if(str.length>1){ + base64File=str[1]; + } + // 上传文件类型 + //String uploadContentType = file.getContentType(); + AttachInfo attach = null; + boolean isNew = PubUtil.isEmpty(attachId+""); + if (isNew) { + attach = new AttachInfo(); + } + else { + attach = dbEngine.findDao(AttachInfo.class).queryEntity(attachId); + if (attach == null) { + attach = new AttachInfo(); + isNew = true; + } else isNew = attach.isNew(); + } + attach.setId(attachId); + if (PubUtil.isEmpty(attachId+"")) attach.setId(dbEngine.nextId()); + + attach.setType(type);//附件类别 + if(null !=ownerId) { + attach.setOwnerId(ownerId);//附件拥有者id + } + attach.setPath(path);//附件路径 + attach.setPartyId(-1l); + attach.setTime(PubUtil.getLastTime()); + attach.setUserId(-1l); + attach.setIsTemp("true".equals(attachIsTemp) ? 1 : 0);//暂时没有有效拥有者标记 方便定时任务清除垃圾附件 + attach.setTime(DateUtil.nowDateTimeLong()); + attach.setIsTemp("true".equals(attachIsTemp) ? 1 : 0);//暂时没有有效拥有者标记 方便定时任务清除垃圾附件 + // 上传文件名 + attach.setSuffix(suffix); + attach.setName(attachName); + Map ret = new HashMap<>(); + try { + //将base64转图片存到临时目录 + // 上传文件域对象 + //保存文件 + byte[] byt = decoder.decodeBuffer(base64File); + for (int i = 0, len = byt.length; i < len; ++i) { + if (byt[i] < 0) { + byt[i] += 256; + } + } + //创建保存目录,格式 类型目录/年月/日 + File upload = new File(attachHelper.getAttachTmpPath() + attach.getId() + attach.getSuffix()); + FileUtils.writeByteArrayToFile(upload, byt); + attach.setSize(upload.length()); + if (PubUtil.isEmpty(savePath)) { + localSaveAttach(attach, upload); + } else {//复制到指定目录 + String filePath; + if (Consts.NULL_STRING.equals(savePath)) filePath = upload.getAbsolutePath(); + else { + filePath = savePath + DateUtil.nowDateTimeString() + UtilFile.FSChar + attach.getName(); + UtilFile.copy(upload, filePath, true); + } + } + } catch (Exception e) { + UtilLogger.error("上传文件失败", e); + return R.error("上传文件失败"); + } + return R.success(attach.getId()); + } + @PostMapping({"/copyupload"}) + public R copyupload(HttpServletRequest request) throws Exception { + String type=request.getParameter("type"); + String attachId=request.getParameter("attachId"); + if(PubUtil.isEmpty(attachId)){ + return R.success(""); + } + AttachInfo attach = dbEngine.queryEntity(AttachInfo.class, Long.valueOf(attachId)); + if(null ==attach){ + return R.success(""); + } + String remoteName =attach.getId()+attach.getName().substring(attach.getName().lastIndexOf(".")); + String remotePath = attach.getPath(); + String filePath =attachHelper.getAttachTmpPath()+"tempFiles/"; + UtilFile.makeDir(filePath); + Map map = null; + try { + attachUtil.downloadAttach(remotePath, remoteName, filePath); + String filePaths=filePath+remoteName; + + attach.setId(dbEngine.nextId()); + attach.setType(type);//附件类别 + attach.setOwnerId(-1l);//附件拥有者id + attach.setPartyId(-1l); + attach.setTime(PubUtil.getLastTime()); + attach.setUserId(-1l); + attach.setName(attach.getId()+attach.getSuffix()); + // 上传文件域对象 + File upload = new File(filePaths); +// attach.setSize((long) FileCopyUtils.copy(file.getInputStream(), new BufferedOutputStream(new FileOutputStream(upload)))); + localSaveAttach(attach, upload); + }catch (Exception e){ + logger.error("上传文件失败", e); + return R.error("上传文件失败"); + } + return R.success(attach.getId()); + } + + + //保存处理附件 + private void localSaveAttach(final AttachInfo attach, final File upload) throws Exception { + try { + //一般附件,上传到服务器,并记录附件 + //传到ftp服务器上 + attachUtil.saveAttach(attach, upload.getPath(), false); + //写入数据库 + dbEngine.insertEntity(attach); +// String sql="insert into "+AttachInfo.ENTITY_NAME+" (attach_id,attach_name,attach_suffix,attach_owner_id,attach_path,attach_type,attach_size,attach_is_temp,attach_party_id,attach_time,attach_user_id,attach_count,attach_ref_id)" + } finally { + UtilFile.delFile(upload.getAbsolutePath()); + } + + } + + //将附件上传到ftp服务器上 + @RequestMapping(value = "/download", method = {RequestMethod.GET, RequestMethod.POST}) + public R down(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "attachId", required = false) Long attachId) throws Exception { + AttachInfo attach = dbEngine.queryEntity(AttachInfo.class,attachId); + if (null == attach) { + return R.error("附件不存在"); + } + final String remoteFileName = attach.getName(); + final String fileName = attach.getName(); + final String remotePath = attach.getPath(); + logger.info("下载附件:filePath:" + remotePath + ",fileName:" + fileName); + try { + attachUtil.downloadAttach(remotePath, remoteFileName, fileName, response); + attach.setCount(attach.getCount() + 1); + dbEngine.updateEntity(attach,"attach_count"); + } catch (Exception e) { + logger.error("附件下载失败",e); + R.error("附件下载失败"); + + } + return null; + } + + //图片附件显示路径 + @RequestMapping(value = "/showImg", method = {RequestMethod.GET, RequestMethod.POST}) + public R showImg(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "attachId", required = false) Long attachId) throws Exception { + AttachInfo attach = dbEngine.queryEntity(AttachInfo.class,attachId); + if (null == attach) { + return R.error("附件不存在"); + } + final String remoteFileName = attach.getName(); + final String fileName = attach.getName(); + final String remotePath = attach.getPath(); + try { + attachUtil.downloadAttach(remotePath, remoteFileName, fileName, response); + } catch (Exception e) { + logger.error("附件下载失败",e); + R.error("附件下载失败"); + } + return null; + } + + //图片附件显示路径 + @RequestMapping(value = "/showImgThumb", method = {RequestMethod.GET, RequestMethod.POST}) + public R showImgThumb(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "attachId", required = false) Long attachId, + @RequestParam(value = "width", required = false,defaultValue = "100") String width, + @RequestParam(value = "heigh", required = false,defaultValue = "100") String heigh) throws Exception { + AttachInfo attach = dbEngine.queryEntity(AttachInfo.class,attachId); + if (null == attach) { + return R.error("附件不存在"); + } + final String remoteFileName = attach.getName(); + final String tempPath = System.getProperty("java.io.tmpdir"); + final String remotePath = attach.getPath(); + try { + String lfo = tempPath + "/" + remoteFileName; + String lfd = tempPath + "/thumb_" + attach.getId() + attach.getSuffix(); + attachUtil.downloadAttach(remotePath, remoteFileName, tempPath); + int w=Integer.valueOf(width); + int h=Integer.valueOf(heigh); + if (w <= 0) w = 100; + if (h <= 0) h = 100; + getImgThumb(lfo, lfd, w, h); + if (UtilFile.isFileExist(lfd)) { + UtilDownloadFile.downfileEx(response, lfd, attach.getName()); + } else if (UtilFile.isFileExist(lfo)) { + UtilDownloadFile.downfileEx(response, lfo, attach.getName()); + } + } catch (Exception e) { + logger.error("附件下载失败",e); + R.error("附件下载失败"); + } + return null; + } + + private static boolean getImgThumb(String orgFile, String dstFile, int width, int height) { + BufferedImage bufferedImage; + try { + //read image file + bufferedImage = ImageIO.read(new File(orgFile)); + + // create a blank, RGB, same width and height, and a white background + int w = bufferedImage.getWidth(), h = bufferedImage.getHeight(); + double r = 1; + if (w > width) { + r = 1.0 * width / w; + } + + if (h > height) { + r = Math.min(1.0 * height / h, r); + } + if (!UtilMath.isEqualsZero(r - 1)) { + w = (int) Math.round(w * r); + h = (int) Math.round(h * r); + } + BufferedImage newBufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + + //TYPE_INT_RGB:创建一个RBG图像,24位深度,成功将32位图转化成24位 + newBufferedImage.createGraphics().drawImage(bufferedImage.getScaledInstance(w, h, Image.SCALE_SMOOTH), 0, 0, Color.WHITE, null); + // write to jpeg file + ImageIO.write(newBufferedImage, "jpg", new File(dstFile)); + return true; + } catch (IOException e) { + logger.error("转换jpg错误:" + orgFile); + return false; + } + } + + //删除附件 + @PostMapping({"/delete"}) + public R del(HttpServletRequest request, @RequestParam(value = "attachId", required = false) Long attachId) throws Exception { + try { + AttachInfo attach = dbEngine.queryEntity(AttachInfo.class,attachId); + if (null == attach) { + return R.error("附件不存在"); + } + attachHelper.deleteOneAttach(attach); + return R.success("附件删除成功"); + } catch (Exception e) { + logger.error("删除附件失败", e); + return R.error("删除附件失败"); + } + } + + //按拥有者删除附件 + @PostMapping({"/deleteByOwnerId"}) + public R delByOwnerId(HttpServletRequest request, @RequestParam(value = "ownerId", required = false) String ownerId) throws Exception { + try { + attachHelper.deleteAttachByOwnerId(ownerId); + return R.success("附件删除成功"); + } catch (Exception e) { + logger.error("删除附件失败", e); + return R.error("删除附件失败"); + } + } + + +} \ No newline at end of file diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/dataCacheInit/AttachFolderEntityBuffer.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/dataCacheInit/AttachFolderEntityBuffer.java new file mode 100644 index 0000000..684bec9 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/dataCacheInit/AttachFolderEntityBuffer.java @@ -0,0 +1,71 @@ +package cc.smtweb.system.bpm.spring.dataCacheInit; + +import cc.smtweb.framework.core.cache.redis.RedisManager; +import cc.smtweb.framework.core.db.DbEngine; +import cc.smtweb.system.bpm.web.sys.base.attachFolder.AttachFolder; +import cc.smtweb.system.bpm.web.sys.base.attachFolder.pojo.AttachFolderPojo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + + +/** + * 实体【[附件目录表](TB_SYS_ATTACH_FOLDER)】的缓存Buffer类 + */ +@Component +public final class AttachFolderEntityBuffer { + @Autowired + private RedisManager redisManager; + @Autowired + private DbEngine dbEngine; + + public static final String cacheKey="attach_folder_"; + + + //根据附件路径和期间获取对象 + public AttachFolderPojo getByPath(String attachPath, String period) { + + return redisManager.get(cacheKey+attachPath + "_" + period, AttachFolderPojo.class); + + } + + //根据附件路径和期间获取当前最大序号 + public int getMaxSeq(String attachPath, String period) { + AttachFolderPojo bean = getByPath(attachPath, period); + if (bean == null) return 0; + return bean.getFolderMaxSeq(); + } + + //根据附件路径和期间获取当前文件数 + public int getFileCount(String attachPath, String period) { + AttachFolderPojo bean = getByPath(attachPath, period); + if (bean == null) return 0; + return bean.getFolderFileCount().intValue(); + } + + //初始化数据 + public void initData(){ + //查询所有数据 + String sql="select folder_id,folder_path,folder_period,folder_max_seq,folder_file_count from "+ AttachFolder.ENTITY_NAME; + List returnList = dbEngine.query(sql,AttachFolder.class); + if(null !=returnList && returnList.size()>0){ + for(AttachFolder pojo:returnList){ + AttachFolderPojo p=new AttachFolderPojo(); + p.setFolderId(pojo.getId()); + p.setFolderAttachPath(pojo.getPath()); + p.setFolderFileCount(pojo.getFileCount()); + p.setFolderPeriod(pojo.getPeriod()); + p.setFolderMaxSeq(pojo.getMaxSeq()); + redisManager.set(cacheKey+pojo.getPath()+"_"+pojo.getPeriod(),p,0); + } + } + } + + //写入一个数据 + public void putOneData(AttachFolderPojo pojo){ + //查询所有数据 + redisManager.set(cacheKey+pojo.getFolderAttachPath()+"_"+pojo.getFolderPeriod(),pojo,0); + } + +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachFileWork.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachFileWork.java new file mode 100644 index 0000000..5b92dd6 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachFileWork.java @@ -0,0 +1,102 @@ +package cc.smtweb.system.bpm.spring.file.attach; + +import cc.smtweb.framework.core.util.PubUtil; +import cc.smtweb.system.bpm.spring.config.FileConfigProperties; +import cc.smtweb.system.bpm.util.UtilDownloadFile; +import cc.smtweb.system.bpm.util.UtilFile; +import cc.smtweb.system.bpm.web.sys.base.attach.AttachInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +@Component +public final class AttachFileWork implements IAttachWorkIntf { + @Autowired + private FileConfigProperties properties; + private String getPath(String remoteFolderPath) { + String path =properties.getAttachPath(); + if (PubUtil.isNotEmpty(remoteFolderPath) && !path.endsWith("/") && !remoteFolderPath.startsWith("/")) + path = path + "/" + remoteFolderPath; + else path = path + remoteFolderPath; + path = path.replaceAll("-",""); + UtilFile.makeDir(path); + if (!path.endsWith("/")) path = path + "/"; + return path; + } + + private String getFileName(String remoteFolderPath, String fileName) { + return getPath(remoteFolderPath) + fileName; + } + + public void saveAttach(String remoteAttachName, String remoteFolderPath, String localAttach, boolean isDelLocal) throws Exception { + String dstFile = getFileName(remoteFolderPath, remoteAttachName); + if (isDelLocal) UtilFile.renameTo(localAttach, dstFile); + else UtilFile.copy(localAttach,dstFile); + } + + @Override + public void copyAttach(String srcFileName, String desFileName, String remoteFolderPath, boolean isDelSrc) throws Exception { + String srcFile = getFileName(remoteFolderPath, srcFileName); + String dstFile = getFileName(remoteFolderPath, desFileName); + if (isDelSrc) UtilFile.renameTo(srcFile, dstFile); + else UtilFile.copy(srcFile, dstFile); + } + + + public void deletePath(final String remotePath) throws Exception { + UtilFile.delFile(getPath(remotePath)); + } + + public void deleteAttach(final String remotePath, final String remoteName) throws Exception { + UtilFile.delFile(getFileName(remotePath, remoteName)); + } + + public void downloadAttach(final String remotePath, final String remoteName, final String fileName, final HttpServletResponse response) throws Exception { + UtilDownloadFile.downfileEx(response, getFileName(remotePath, remoteName), fileName); + } + + public void downloadAttach(final String remotePath, final String remoteName, final String localPath) throws Exception { + UtilFile.copy(getFileName(remotePath, remoteName), localPath + "/" + remoteName); + } + + @Override + public void downloadAttach(String remotePath, String remoteName, String localPath, String localName) throws Exception { + UtilFile.copy(getFileName(remotePath, remoteName), localPath + "/" + localName); + } + + public void showAttachImg(final String remotePath, final String remoteName, final HttpServletResponse response) throws Exception { + UtilDownloadFile.sendImgFile(response, remoteName); + } + + public List getAttachListFromFtp(final List attachlist, final String ownerType, final String localRoot) throws Exception { + final List files = new ArrayList<>(); + String localPath = localRoot + "/" + ownerType + "/"; + UtilFile.makeDir(localPath); + String fileName; + File file; + for (AttachInfo attach : attachlist) { + fileName = localPath + attach.getName(); + file = new File(fileName); + if (!file.exists()) + UtilFile.copy(getFileName(attach.getPath(), attach.getName()), fileName); + files.add(fileName); + } + return files; + } + + public void makeRemoteDir(String path) throws Exception { + UtilFile.makeDir(getPath(path)); + } + + @Override + public Path getAttachPath(String remotePath, String remoteName) { + String path = getFileName(remotePath, remoteName); + return Paths.get(path); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachFtpWork.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachFtpWork.java new file mode 100644 index 0000000..abc71cd --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachFtpWork.java @@ -0,0 +1,222 @@ +package cc.smtweb.system.bpm.spring.file.attach; + +import cc.smtweb.framework.core.util.PubUtil; +import cc.smtweb.system.bpm.spring.config.FileConfigProperties; +import cc.smtweb.system.bpm.util.UtilDownloadFile; +import cc.smtweb.system.bpm.util.UtilFile; +import cc.smtweb.system.bpm.util.ftp.FtpTask; +import cc.smtweb.system.bpm.util.ftp.FtpTaskManager; +import cc.smtweb.system.bpm.util.ftp.IFtpServerConfig; +import cc.smtweb.system.bpm.util.ftp.IFtpUtil; +import cc.smtweb.system.bpm.web.sys.base.attach.AttachInfo; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.InputStream; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by AKmm at 2011-2-23 16:35:49 + * ftp工作服务 + */ +@Component +public final class AttachFtpWork implements IAttachWorkIntf { + Logger logger = LoggerFactory.getLogger(AttachFtpWork.class); + @Autowired + private FileConfigProperties properties; + private String getPath(String remoteFolderPath) { + String path = properties.getAttachPath(); + if (PubUtil.isNotEmpty(remoteFolderPath) && !path.endsWith("/") && !remoteFolderPath.startsWith("/")) + path = path + "/" + remoteFolderPath; + else path = path + remoteFolderPath; + path = path.replaceAll("-", ""); + UtilFile.makeDir(path); + if (!path.endsWith("/")) path = path + "/"; + logger.info("远程附件路径:" + path); + return path; + } + + public FtpTaskManager getFtpManager() { + return FtpTaskManager.getInstance("ATTACH_FTP", new IFtpServerConfig() { + @Override + public boolean isSFTP() { + return "sftp".equalsIgnoreCase(properties.getAttachType()); + } + + @Override + public String getServerIp() { + return properties.getAttachFtpIp(); + } + + @Override + public Integer getPort() { + return properties.getAttachFtpPort(); + } + + @Override + public String getUserName() { + return properties.getAttachFtpUser(); + } + + @Override + public String getPassword() { + return properties.getAttachFtpPwd(); + } + }); + } + + public void saveAttach(String remoteAttachName, String remoteFolderPath, String localAttach, boolean isDelLocal) throws Exception { + getFtpManager().uploadToFtp(remoteAttachName, getPath(remoteFolderPath), localAttach, isDelLocal); + } + + @Override + public void copyAttach(String srcFileName, String desFileName, String remoteFolderPath, boolean isDelSrc) throws Exception { + getFtpManager().execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + if (!ftp.existsFile(srcFileName, getPath(remoteFolderPath))) return null; + ftp.setRemoteDir("/"); + ftp.mkdir(remoteFolderPath); + ftp.rename(remoteFolderPath, srcFileName, desFileName); + return null; + } + }); + } + + + public void deletePath(final String remotePath) throws Exception { + getFtpManager().execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + ftp.deleteFolder(remotePath); + return null; + } + }); + } + + public void deleteAttach(final String remotePath, final String remoteName) throws Exception { + getFtpManager().execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + ftp.deleteFile(getPath(remotePath), remoteName); + return null; + } + }); + } + + public void downloadAttach(final String remotePath, final String remoteName, final String fileName, final HttpServletResponse response) throws Exception { + getFtpManager().execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + InputStream in; + in = ftp.downloadFile(getPath(remotePath), remoteName); + + if (in == null) return null; + try { + UtilDownloadFile.downfileStream(response, fileName, 0, in); + } finally { + IOUtils.closeQuietly(in); + ftp.completePendingCommand(); + } + + return null; + } + }); + } + + @Override + public void showAttachImg(final String remotePath, final String remoteName, final HttpServletResponse response) throws Exception { + getFtpManager().execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + InputStream in = null; + try { + in = ftp.downloadFile(getPath(remotePath), remoteName); + } catch (Exception e) { + e.printStackTrace(); + } + if (in == null) return null; + try { + UtilDownloadFile.sendImgStream(response, in); + } finally { + IOUtils.closeQuietly(in); + ftp.completePendingCommand(); + } + + return null; + } + }); + } + + + public void downloadAttach(final String remotePath, final String remoteName, final String localPath) throws Exception { + getFtpManager().execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + try { + ftp.downloadFile(getPath(remotePath), remoteName, localPath); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + }); + } + + @Override + public void downloadAttach(String remotePath, String remoteName, String localPath, String localName) throws Exception { + getFtpManager().execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + try { + ftp.downloadFileEx(getPath(remotePath), remoteName,localPath + File.separator + localName ); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + }); + } + + public List getAttachListFromFtp(final List attachlist, final String ownerType, final String localRoot) throws Exception { + final List files = new ArrayList(); + getFtpManager().execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + String localPath = localRoot + UtilFile.FSChar + ownerType + UtilFile.FSChar; + File file = new File(localPath); + if (!file.exists()) { + file.mkdirs(); + } + String fileName; + for (AttachInfo attach : attachlist) { + fileName = localPath + attach.getName(); + file = new File(fileName); + if (!file.exists()) + try { + ftp.downloadFileEx(getPath(attach.getPath()), attach.getName(), fileName); + } catch (Exception e) { + e.printStackTrace(); + } + files.add(fileName); + } + + return null; + } + }); + return files; + } + + public void makeRemoteDir(final String path) throws Exception { + getFtpManager().execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + ftp.setRemoteDir(path); + return null; + } + }); + } + + @Override + public Path getAttachPath(String remotePath, String remoteName) { + throw new UnsupportedOperationException("FTP的还没用到,没开发,暂不支持"); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachHelper.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachHelper.java new file mode 100644 index 0000000..926c8ce --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachHelper.java @@ -0,0 +1,283 @@ +package cc.smtweb.system.bpm.spring.file.attach; + +import cc.smtweb.framework.core.db.DbEngine; +import cc.smtweb.framework.core.util.PubUtil; +import cc.smtweb.system.bpm.spring.config.FileConfigProperties; +import cc.smtweb.system.bpm.util.UtilFile; +import cc.smtweb.system.bpm.util.UtilMath; +import cc.smtweb.system.bpm.web.sys.base.attach.AttachInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Created by AKmm at 11-6-15 下午3:32 + * 附件管理 + */ +@Component +public final class AttachHelper { + Logger logger = LoggerFactory.getLogger(AttachHelper.class); + @Autowired + private FileConfigProperties properties; + @Autowired + private DbEngine dbEngine; + @Autowired + private AttachUtil attachUtil; + //得到附件临时目录 + public String getAttachTmpPath() { + String tmp_attach = properties.getAttachTempPath(); + if (!tmp_attach.endsWith("/")) tmp_attach += "/"; + File file = new File(tmp_attach); + if (!file.exists()) { + file.mkdirs(); + } + return tmp_attach; + } + + //删除ftp服务器的文件 + public boolean deleteOneAttach(String attachId) throws Exception { + if (PubUtil.isEmpty(attachId)) return true; + AttachInfo attachInfo = dbEngine.queryEntity(AttachInfo.class, Long.valueOf(attachId)); + if(null == attachInfo){ + return true; + } + boolean deleteSuccess = deleteAttachInFtpServer(attachInfo.getPath(), attachInfo.getName()); + if (deleteSuccess) { + dbEngine.deleteEntity(attachInfo); + } + return deleteSuccess; + } + + //删除ftp服务器的文件 + public boolean deleteOneAttach(AttachInfo bean) throws Exception { + boolean deleteSuccess = deleteAttachInFtpServer(bean.getPath(), bean.getName()); + if (deleteSuccess) { + dbEngine.deleteEntity(bean); + } + return deleteSuccess; + } + + //删除ftp服务器的文件夹 + public void deleteFolder(final String remotePath) throws Exception { + attachUtil.deletePath(remotePath); + } + + public List getAttachListByOwnerId(String ownerId) throws Exception { + return dbEngine.query("select * from "+AttachInfo.ENTITY_NAME+" where attach_owner_id=? ",AttachInfo.class,ownerId); + } + + public List listAttachListByOwnerIdAndType(String ownerId, String attach_type) throws Exception { + return dbEngine.query("select * from "+AttachInfo.ENTITY_NAME+" where attach_owner_id=? and attach_type=? ",AttachInfo.class,ownerId,attach_type); + } + + public int getAttachCountByOwnerId(String ownerId) throws Exception { + return dbEngine.queryInt("select count(0) from "+AttachInfo.ENTITY_NAME+" where attach_owner_id=? ",ownerId); + } + + //根据附件拥有者和附件类型删除 + public boolean deleteAttachByOwnerIdAndType(String ownerId, String attachType) throws Exception { + final List list = listAttachListByOwnerIdAndType(ownerId, attachType); + return deleteAttachListEx(list); + } + + public boolean deleteAttachByOwnerId(String ownerId) throws Exception { + final List list = getAttachListByOwnerId(ownerId); + return deleteAttachListEx(list); + } + + //批量删除 + public boolean deleteAttachList(List attachIdList) throws Exception { + if (PubUtil.isEmpty(attachIdList)) return false; + dbEngine.update("delete from "+AttachInfo.ENTITY_NAME+" where attach_id in(" + PubUtil.getSqlInIds(attachIdList) + ")"); + return true; + } + + public boolean deleteAttachListEx(List list) throws Exception { + boolean result = true; + for (AttachInfo bean : list) { + if (!deleteAttachInFtpServer(bean.getPath(), bean.getName())) { + result = false; + break; + } + } + if (result) { + for (AttachInfo bean : list) { + dbEngine.deleteEntity(bean); + } + } + return result; + } + + //删除在ftp服务器上的附件 + public boolean deleteAttachInFtpServer(String remotePath, String remoteName) { + try { + attachUtil.deleteAttach(remotePath, remoteName); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * 下载附件 + * + * @param attachId 附件id + * @param localPath 要下载到的本地路径 + * @return 返回文件名 + * @throws Exception + */ + public String getAttachFromFtp(final String attachId, final String localPath) throws Exception { + AttachInfo attach = dbEngine.queryEntity(AttachInfo.class, Long.valueOf(attachId)); + if (null == attach) throw new Exception("附件不存在!"); + + final String remoteFileName = attach.getName(); + final String remotePath = attach.getPath(); + + attachUtil.downloadAttach(remotePath, remoteFileName, localPath); + return remoteFileName; + + } + + /** + * 下载附件 + * + * @param attachId 附件id + * @param localPath 要下载到的本地路径 + * @return 返回文件名 + * @throws Exception + */ + public String getAttachFromFtp(final String attachId, final String localPath, String localName) throws Exception { + AttachInfo attach = dbEngine.queryEntity(AttachInfo.class, Long.valueOf(attachId)); + if (null == attach) throw new Exception("附件不存在!"); + final String remoteFileName = attach.getName(); + final String remotePath = attach.getPath(); + + attachUtil.downloadAttach(remotePath, remoteFileName, localPath, localName); + return remoteFileName; + + } + + /** + * 下载附件 + * + * @param attachlist 附件列表 + * @param ownerType 附件类别 + * @return 返回文件名列表,本地有此文件将不再下载 + * @throws Exception + */ + private List getAttachListFromFtp(final List attachlist, final String ownerType) throws Exception { + return attachUtil.getAttachListFromFtp(attachlist, ownerType, getAttachTmpPath()); + } + + /** + * 下载附件 + * + * @param ownerId 附件拥有者id + * @param ownerType 附件类别 + * @return 返回文件名列表,本地有此文件将不再下载 + * @throws Exception + */ + public List getAttachsFromFtp(final String ownerId, final String ownerType) throws Exception { + final List attachlist = getAttachListByOwnerId(ownerId); + + return getAttachListFromFtp(attachlist, ownerType); + + } + + /** + * 下载附件 + * + * @param attachIds 附件id + * @param ownerType 附件类别 + * @return 返回文件名列表,本地有此文件将不再下载 + * @throws Exception + */ + public List getAttachsFromFtp(final List attachIds, final String ownerType) throws Exception { + List paras = new ArrayList(); + if (PubUtil.isNotEmpty(attachIds)) { + StringBuilder sb = new StringBuilder(128); + for(int i=0;i attachlist =dbEngine.queryWhere(AttachInfo.class,sb.toString(),paras.toArray()); + if (null == attachlist || attachlist.size()<1) throw new Exception("附件不存在!"); + return getAttachListFromFtp(attachlist, ownerType); + } + return new ArrayList<>(); + } + + /** + * 得到文件大小 + * + * @return + */ + public String getSizeStr(long fileSize) { + if (fileSize < 1024) return fileSize + "B"; + double n = fileSize * 1.0 / 1024; + if (UtilMath.compare(n, 1024) < 0) return UtilMath.toStdNumberString(n, 0) + "KB"; + n = n / 1024; + return UtilMath.toStdNumberString(n) + "MB"; + } + + /** + * 清除临时标志 + * + * @param attach_owner_id 拥有者 + * @throws Exception + */ + public void removeTempTag(String attach_owner_id) throws Exception { + dbEngine.update("update "+AttachInfo.ENTITY_NAME+" set attach_is_temp=0 WHERE attach_owner_id=? AND attach_is_temp=1 ",attach_owner_id); + } + + public String copyupload(String type,Long attachId) { + AttachInfo attach = dbEngine.queryEntity(AttachInfo.class, attachId); + if(attach==null){ + return ""; + } + String remoteName =attach.getId()+attach.getName().substring(attach.getName().lastIndexOf(".")); + String remotePath = attach.getPath(); + String filePath =getAttachTmpPath()+"tempFiles/"; + UtilFile.makeDir(filePath); + Map map = null; + try { + attachUtil.downloadAttach(remotePath, remoteName, filePath); + String filePaths=filePath+remoteName; + + attach.setId(dbEngine.nextId()); + attach.setType(type);//附件类别 + attach.setOwnerId(-1l);//附件拥有者id + attach.setPartyId(-1l); + attach.setTime(PubUtil.getLastTime()); + attach.setUserId(-1l); + attach.setName(attach.getId()+attach.getSuffix()); + // 上传文件域对象 + File upload = new File(filePaths); +// attach.setAttachSize((long) FileCopyUtils.copy(file.getInputStream(), new BufferedOutputStream(new FileOutputStream(upload)))); + try { + //一般附件,上传到服务器,并记录附件 + //传到ftp服务器上 + attachUtil.saveAttach(attach, upload.getPath(), false); + //写入数据库 + dbEngine.insertEntity(attach); + } finally { + UtilFile.delFile(upload.getAbsolutePath()); + } + }catch (Exception e){ + logger.error("复制文件失败", e); + return ""; + } + return attach.getId()+""; + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachUtil.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachUtil.java new file mode 100644 index 0000000..b722dd0 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/AttachUtil.java @@ -0,0 +1,135 @@ +package cc.smtweb.system.bpm.spring.file.attach; + + +import cc.smtweb.framework.core.db.DbEngine; +import cc.smtweb.framework.core.util.DateUtil; +import cc.smtweb.framework.core.util.PubUtil; +import cc.smtweb.system.bpm.spring.config.FileConfigProperties; +import cc.smtweb.system.bpm.spring.dataCacheInit.AttachFolderEntityBuffer; +import cc.smtweb.system.bpm.web.sys.base.attach.AttachInfo; +import cc.smtweb.system.bpm.web.sys.base.attachFolder.AttachFolder; +import cc.smtweb.system.bpm.web.sys.base.attachFolder.pojo.AttachFolderPojo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletResponse; +import java.nio.file.Path; +import java.util.List; + +/** + * Created by AKmm at 2011-2-23 15:06:56 + * 附件存储工具,按存储方式决定保存在 + */ +@Component +public final class AttachUtil { + //一个文件夹下最多允许多少文件 + private final static int MAX_FILE_COUNT = 1000; + private static IAttachWorkIntf worker; + @Autowired + private FileConfigProperties properties; + @Autowired + private AttachFolderEntityBuffer attachFolderEntityBuffer; + @Autowired + private DbEngine dbEngine; + @Autowired + private AttachFtpWork attachFtpWork; + @Autowired + private AttachFileWork attachFileWork; + static { +// init(); + } + + public void init() { + final String at = PubUtil.checkNull(properties.getAttachType()).toLowerCase(); + if ("ftp".equals(at) || "sftp".equals(at)) + worker = attachFtpWork; + else worker = attachFileWork; + } + + private void checkAttachFolder(final AttachInfo attach) throws Exception { + final String period = DateUtil.getNowYm(); + AttachFolderPojo folder = attachFolderEntityBuffer.getByPath(attach.getPath(), period); + + AttachFolder entity=new AttachFolder(); + boolean isNew = false; + if (folder == null) { + isNew = true; + folder = new AttachFolderPojo(); + folder.setFolderId(dbEngine.nextId()); + folder.setFolderAttachPath(attach.getPath()); + folder.setFolderPeriod(period); + folder.setFolderMaxSeq(1); + + entity.setPath(attach.getPath()); + entity.setPeriod(period); + entity.setMaxSeq(1); + } + if (folder.getFolderFileCount() >= MAX_FILE_COUNT) { + folder.setFolderMaxSeq(folder.getFolderMaxSeq() + 1); + folder.setFolderFileCount(0l); + + entity.setMaxSeq(folder.getFolderMaxSeq() + 1); + entity.setFileCount(0); + } + folder.setFolderFileCount(folder.getFolderFileCount() + 1); + entity.setFileCount(folder.getFolderFileCount() + 1); + entity.setId(folder.getFolderId()); + //检查并确定远程目录 + if (isNew) { +// dbEngine.update("insert into "+AttachFolderEntity.ENTITY_NAME+" (folder_id,attach_path,folder_period,max_seq,file_count)values(?,?,?,?,?)",entity.getFolderId(),entity.getAttachPath(),entity.getFolderPeriod(),entity.getMaxSeq(),entity.getFileCount()); + dbEngine.insertEntity(entity, "folder_id,folder_path,folder_period,folder_max_seq,folder_file_count"); + } else { +// dbEngine.update("update "+AttachFolderEntity.ENTITY_NAME+" set max_seq=?,file_count=? where folder_id=?",new Object[]{entity.getMaxSeq(),entity.getFileCount(),entity.getFolderId()}); + dbEngine.updateEntity(entity, "folder_max_seq,folder_file_count"); + } + attach.setPath(attach.getPath() + "/" + period + "/" + folder.getFolderMaxSeq()); + attachFolderEntityBuffer.putOneData(folder); + } + + public void saveAttach(final AttachInfo attach, String localAttach, boolean isDelLocal) throws Exception { + synchronized (attach.getPath()) { + checkAttachFolder(attach); + saveAttach(attach.getName(), attach.getPath(), localAttach, false); + } + } + + public void saveAttach(String remoteAttachName, String remoteFolderPath, String localAttach, boolean isDelLocal) throws Exception { + worker.saveAttach(remoteAttachName, remoteFolderPath, localAttach, isDelLocal); + } + + public void copyAttach(String srcFileName, String desFileName, String remoteFolderPath, boolean isDelSrc) throws Exception { + worker.copyAttach(srcFileName, desFileName, remoteFolderPath, isDelSrc); + } + + public void deletePath(String remotePath) throws Exception { + worker.deletePath(remotePath); + } + + public void deleteAttach(String remotePath, String remoteName) throws Exception { + worker.deleteAttach(remotePath, remoteName); + } + + public void downloadAttach(String remotePath, String remoteName, String fileName, HttpServletResponse response) throws Exception { + worker.downloadAttach(remotePath, remoteName, fileName, response); + } + + public void downloadAttach(String remotePath, String remoteName, String localPath) throws Exception { + worker.downloadAttach(remotePath, remoteName, localPath); + } + + public void downloadAttach(String remotePath, String remoteName, String localPath, String localName) throws Exception { + worker.downloadAttach(remotePath, remoteName, localPath, localName); + } + + public List getAttachListFromFtp(final List attachlist, final String ownerType, final String localRoot) throws Exception { + return worker.getAttachListFromFtp(attachlist, ownerType, localRoot); + } + + public void makeRemoteDir(String path) throws Exception { + worker.makeRemoteDir(path); + } + + public Path getAttachPath(String remotePath, String remoteName) throws Exception { + return worker.getAttachPath(remotePath, remoteName); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/IAttachTraceIntf.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/IAttachTraceIntf.java new file mode 100644 index 0000000..b255c92 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/IAttachTraceIntf.java @@ -0,0 +1,28 @@ +package cc.smtweb.system.bpm.spring.file.attach; + + +import cc.smtweb.system.bpm.web.sys.base.attach.AttachInfo; + +/** + * Created by Akmm at 13-5-4 下午3:02 + * 附件处理跟踪 + */ +public interface IAttachTraceIntf { + /** + * 附件上传后 + * + * @param filePath + * @param attach + * @throws Exception + */ + void afterUpload(String filePath, AttachInfo attach) throws Exception; + + /** + * 附件删除后 + * + * @param attach + * @throws Exception + */ + void afterDel(AttachInfo attach) throws Exception; + +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/IAttachWorkIntf.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/IAttachWorkIntf.java new file mode 100644 index 0000000..1702aff --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/file/attach/IAttachWorkIntf.java @@ -0,0 +1,115 @@ +package cc.smtweb.system.bpm.spring.file.attach; + + + +import cc.smtweb.system.bpm.web.sys.base.attach.AttachInfo; + +import javax.servlet.http.HttpServletResponse; +import java.nio.file.Path; +import java.util.List; + +/** + * Created by AKmm at 2011-2-23 16:22:20 + * 附件存储操作接口 + */ +public interface IAttachWorkIntf { + /** + * 保存附件 + * + * @param remoteAttachName 远程附件名 + * @param remoteFolderPath 远程路径 + * @param localAttach 本地文件名 + * @param isDelLocal 保存后是否删除本地 + * @throws Exception + */ + void saveAttach(String remoteAttachName, String remoteFolderPath, String localAttach, boolean isDelLocal) throws Exception; + + + /** + * 复制附件 + * + * @param srcFileName 源文件 + * @param desFileName 新文件 + * @param remoteFolderPath 文件路径 + * @param isDelSrc 保存后是否删除源文件 + * @throws Exception + */ + void copyAttach(String srcFileName, String desFileName, String remoteFolderPath, boolean isDelSrc) throws Exception; + + + /** + * 删除路径 + * + * @param remotePath 远程路径 + * @throws Exception + */ + void deletePath(String remotePath) throws Exception; + + /** + * 删除附件 + * + * @param remotePath 远程路径 + * @param remoteName 远程文件名 + * @return + */ + void deleteAttach(String remotePath, String remoteName) throws Exception; + + /** + * 下载附件到文件流 + * + * @param remotePath + * @param remoteName + * @param response + * @throws Exception + */ + void downloadAttach(String remotePath, String remoteName, String fileName, HttpServletResponse response) throws Exception; + + /** + * 下载到本地 + * + * @param remotePath 远端路径 + * @param remoteName 远端文件 + * @param localPath 本地路径 + * @throws Exception + */ + void downloadAttach(String remotePath, String remoteName, String localPath) throws Exception; + + /** + * 下载到本地 + * + * @param remotePath 远端路径 + * @param remoteName 远端文件 + * @param localPath 本地路径 + * @throws Exception + */ + void downloadAttach(String remotePath, String remoteName, String localPath, String localName) throws Exception; + + /** + * img显示 + * + * @param remotePath 远端路径 + * @param remoteName 远端文件 + * @param response + * @throws Exception + */ + void showAttachImg(final String remotePath, final String remoteName, final HttpServletResponse response) throws Exception; + + /** + * 批量下载文件到本地 + * + * @param attachlist + * @param ownerType + * @param localRoot + * @return + * @throws Exception + */ + List getAttachListFromFtp(List attachlist, String ownerType, String localRoot) throws Exception; + + void makeRemoteDir(String path) throws Exception; + + /** + * 获取文件路径 + * + */ + Path getAttachPath(String remotePath, String remoteName); +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/initPlugin/RunDataInit.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/initPlugin/RunDataInit.java new file mode 100644 index 0000000..83a1484 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/spring/initPlugin/RunDataInit.java @@ -0,0 +1,27 @@ +package cc.smtweb.system.bpm.spring.initPlugin; + +import cc.smtweb.system.bpm.spring.dataCacheInit.AttachFolderEntityBuffer; +import cc.smtweb.system.bpm.spring.file.attach.AttachUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +/** + * @Author: zhangyulong + * @Date: 2021/9/17 15:31 + */ + +@Component +public class RunDataInit implements ApplicationRunner { + @Autowired + private AttachFolderEntityBuffer attachFolderEntityBuffer; + @Autowired + private AttachUtil attachUtil; + @Override + public void run(ApplicationArguments args) throws Exception { + attachFolderEntityBuffer.initData();//附件目录缓存 + attachUtil.init();//附件上传方式初始化 + + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilDownloadFile.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilDownloadFile.java new file mode 100644 index 0000000..5161084 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilDownloadFile.java @@ -0,0 +1,135 @@ +package cc.smtweb.system.bpm.util; + +import org.apache.commons.io.IOUtils; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; + +public abstract class UtilDownloadFile { + public static void writePdf(HttpServletResponse response, InputStream inputStream) throws IOException { + InputStream bufIn = new BufferedInputStream(inputStream, 8192); + try { + OutputStream output = response.getOutputStream(); + response.setContentType("application/pdf"); + byte[] bs = new byte[8192]; + while (true) { + int nLen = bufIn.read(bs); + if (nLen <= 0) break; + output.write(bs, 0, nLen); + } + output.flush(); + } finally { + IOUtils.closeQuietly(bufIn); + } + } + + /** + * Akmm 2008.8.29 增加,原方法在大文件时,必须先读完整个文件才开始下载, + * 新加方法边读边写response.getOutputStream,让客户端及时看到进度条 + * + * @param response r + * @param fileSrc 源文件名 + * @param fileOrigName 显示在reponse中的文件名称. + */ + public static void downfileEx(HttpServletResponse response, String fileSrc, String fileOrigName) { + InputStream in = null; + try { + in = new BufferedInputStream(new FileInputStream(fileSrc), 8192); + downfileStream(response, fileOrigName, in.available(), in); + } catch (Exception e) { + // ignore + } finally { + IOUtils.closeQuietly(in); + } + } + + /** + * Akmm 2008.8.29 增加,原方法在大文件时,必须先读完整个文件才开始下载, + * 新加方法边读边写response.getOutputStream,让客户端及时看到进度条 + */ + public static void downfileStream(HttpServletResponse response, String fileName, int totalSize, InputStream in) { + OutputStream out = null; + try { + writeResponseHeader(response, fileName, totalSize); + + out = response.getOutputStream(); + byte[] bs = new byte[8192]; + while (true) { + int nLen = in.read(bs); + if (nLen <= 0) break; + out.write(bs, 0, nLen); + } + out.flush(); + } catch (IOException e) { + UtilLogger.error("客户端下载过程取消或中断!", e); + } finally { + IOUtils.closeQuietly(out); + } + } + + public static void sendImgFile(HttpServletResponse response, String fileSrc) { + InputStream in = null; + try { + in = new BufferedInputStream(new FileInputStream(fileSrc), 8192); + sendImgStream(response, in); + } catch (Exception e) { + // ignore + } finally { + IOUtils.closeQuietly(in); + } + } + + /** + * Akmm 图片显示, + */ + public static void sendImgStream(HttpServletResponse response, InputStream in) { + OutputStream out = null; + try { + out = response.getOutputStream(); + byte[] bs = new byte[8192]; + while (true) { + int nLen = in.read(bs); + if (nLen <= 0) break; + out.write(bs, 0, nLen); + } + out.flush(); + } catch (IOException e) { + UtilLogger.error("图片显示", e); + } finally { + IOUtils.closeQuietly(out); + } + } + + public static void writeResponseHeader(HttpServletResponse response, String fileName, int totalSize) { + try { + /*解决中文文件名乱码的问题*/ + fileName = java.net.URLEncoder.encode(fileName, "UTF-8"); + } catch (Exception ex) { + // ignore + } + /* + 例1.内嵌显示一个文件 + Content-disposition: inline; filename=foobar.pdf + 例2.往response里附加一个文件 + Content-disposition: attachment; filename=foobar.pdf + */ + //返回文件下载 + response.setContentType("APPLICATION/OCTET-STREAM"); + response.setCharacterEncoding("UTF-8"); + response.setHeader("GATM-Attch-Name", fileName); + response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); + if (totalSize > 0) response.setContentLength(totalSize); + } + + /** + * 写空长度的内容到输出流. + */ + public static void writeZeroLengthResponse(HttpServletResponse response, String fileName) { + try { + writeResponseHeader(response, fileName, 0); + response.flushBuffer(); + } catch (IOException e) { + // ignore e; + } + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilFile.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilFile.java new file mode 100644 index 0000000..208d16f --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilFile.java @@ -0,0 +1,1178 @@ +package cc.smtweb.system.bpm.util; + +import cc.smtweb.framework.core.util.PubUtil; +import com.aliyuncs.utils.IOUtils; +import org.springframework.util.FileCopyUtils; +import sun.misc.BASE64Decoder; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +/** + * Created by AKmm at 2011-6-10 10:13:05 + * 文件操作方法 + */ +@SuppressWarnings({"UnusedDeclaration", "ResultOfMethodCallIgnored"}) +public class UtilFile { + //使用了"/",暂未使用File.separator,因为在Windows下获取的"\",以及通过Url.getPath获取的路径中的"/",拼接路径会导致错误发生。暂时全部使用"/"; + public static final String FSChar = "/"; + // public static final String FSChar = File.separator; + + /** + * create new file + * modify by huchb in 2012.08.14 + * + * @param fileName 文件名,带路径 + * @return true is success + */ + public static boolean CreateFile(String fileName) { + File f = new File(fileName); + f.getParentFile().mkdirs(); + try { + return f.createNewFile(); + } catch (IOException e) { + UtilLogger.error("创建文件出错", e); + return false; + } + } + + /** + * UTF-8编码写入 + * + * @param text 文件内容 + * @param fileName 文件名称 + */ + public static void appendTextToFileEncode(String text, String fileName, boolean append) { + try { + OutputStreamWriter oStreamWriter = new OutputStreamWriter(new FileOutputStream(fileName, append), StandardCharsets.UTF_8); + oStreamWriter.append(text); + oStreamWriter.flush(); + oStreamWriter.close(); + } catch (IOException e) { + UtilLogger.error(e.getMessage(), e); + } + } + + /** + * 删除文件 + * modify by huchb in 2012.08.14 + * + * @param dirName 源文件或目录 + * @param isRecurse 如果是目录,是否删除其下的子目录 (是否迭代) + * @return true-成功,false-失败 + */ + public static boolean deleteFile(String dirName, boolean isRecurse) { + File f = new File(dirName); + if (f.isFile()) { + return f.delete(); + } + boolean blret = true; + try { + //取出目录下的文件数量; + File[] childsf = f.listFiles(); + if (childsf != null) { + int filenumber = childsf.length; + for (File cf : childsf) { + if (cf.isFile()) { + blret = cf.delete(); + } else if (isRecurse) { + blret = deleteFile(cf.getAbsolutePath(), true); + } + if (!blret) { + break; + } //没删除成功,跳出内循环,并退出函数,返回删除不成功; + } + //删除空目录 + blret = new File(dirName).delete(); + } + } catch (Exception e) { + UtilLogger.error(e.getMessage(), e); + blret = false; + } + return blret; + } + + //删除文件或目录 + public static boolean delFile(String path) { + File f = new File(path); + return !f.exists() || delFile(f); + } + + public static boolean delFile(File f) { + if (f.isFile()) + return f.delete(); + return delDir(f); + } + + /** + * 将data写到fn中 fn为绝对路径 + * + * @param fn 保存文件名 + * @param data 数据 + * @return int + * @roseuid 3C297D4D0102 + */ + public static int saveFile(String fn, byte[] data) { + try { + FileOutputStream fos = new FileOutputStream(fn); + fos.write(data, 0, data.length); + fos.flush(); + fos.close(); + return 0; + } catch (IOException e) { + UtilLogger.error(e.getMessage(), e); + return 100; + } + } + + /** + * @param text 文件内容 + * @param fileName 文件名称 + * @param append 是否追加的文件的尾部 + * 如果append=true 则将内容追加的文件的尾部 + * 否则,从头开始 + */ + public static void writeTextToFile(String text, String fileName, boolean append) { + try { + Writer write = new FileWriter(fileName, append); + write.write(text); + write.flush(); + write.close(); + } catch (IOException e) { + UtilLogger.error(e.getMessage( ), e); + } + } + + /** + * 本方法主要用于将一个文件拷贝到另一个文件件 + * + * @param from 源文件 + * @param to 目的文件 + * @return 返回字节数,-1:读文件错误,-2:文件未找到,-3: IO错误 + */ + public static int copyFile(String from, String to) { + int n = 0; + try { + // copy 会自动关闭input,output. + FileCopyUtils.copy(new File(from), new File(to)); //调用org.springframework.cf;中的类方法 + /*System.out.println("now copy file from " + from + " to " + to); + is = new FileInputStream(from); + byte[] bts = new byte[is.available()]; + int len = bts.length; + System.out.println("now open file"); + os = new FileOutputStream(to); + System.out.println("now open file success"); + int len1 = is.read(bts, 0, bts.length); + System.out.println("now start write file"); + os.write(bts, 0, bts.length); + bts = null; + n = len == len1 ? len : -1;*/ + } catch (FileNotFoundException fe) { + UtilLogger.error(fe.getMessage(), fe); + n = -2; + } catch (IOException ie) { + UtilLogger.error(ie.getMessage(), ie); + n = -3; + } catch (Exception e) { + UtilLogger.error("", e); + n = -1; + } + return n; + } + + /** + * 复制文件 + * + * @param oldPath 源文件 + * @param newPath 目标文件名 + * @return 成功/失败 + */ + public static boolean copy(String oldPath, String newPath) { + return copy(new File(oldPath), newPath, false); + } + + /** + * 复制/移动文件(夹) + * + * @param oldPath 旧文件 + * @param newPath 新文件 + * @param isDelOld 是否删除旧文件,删除相当于移动; + * @return 是否删除成功 + */ + public static boolean copy(String oldPath, String newPath, boolean isDelOld) { + File f = new File(oldPath); + return copy(f, newPath, isDelOld); + } + + /** + * 复制/移动文件(夹) + * + * @param oldfile 源文件 + * @param newPath 新文件名 + * @param isDelOld 是否删除旧文件名(移动方式) + * @return 成功/成败 + */ + public static boolean copy(File oldfile, String newPath, boolean isDelOld) { + try { + if (!oldfile.exists()) return true; + if (oldfile.isFile()) return copyFile(oldfile, newPath, isDelOld); + + return copyDir(oldfile, newPath, isDelOld); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public static boolean copyFile(File oldfile, String newPath, boolean isDelOld) { + if (!oldfile.exists()) return true; + int byteread; + try { + File f = new File(newPath); + f.getParentFile().mkdirs(); + try (FileOutputStream fs = new FileOutputStream(newPath); InputStream inStream = new FileInputStream(oldfile)) { + byte[] buffer = new byte[1444]; + while ((byteread = inStream.read(buffer)) != -1) { + fs.write(buffer, 0, byteread); + } + } + if (isDelOld) oldfile.delete(); + return true; + } catch (Exception e) { + UtilLogger.error("复制文件失败。", e); + return false; + } + } + + public static void copyFileToIcDir(String srcFileDir, String destFileDir) { + String[] srcFiles = getFileNames(srcFileDir); + try { + if (srcFiles != null && srcFiles.length > 0) { + for (String srcFile : srcFiles) { + if (!srcFile.endsWith(".zip")) { + copyFile(srcFileDir + "\\" + srcFile, destFileDir + "\\" + srcFile); + } //if + } //for + } + } catch (Exception e) { + e.printStackTrace(); + UtilLogger.error("拷贝文件出错!", e); + } + } + + public static boolean copyDir(File file, String newPath, boolean isDelOld) { + if (newPath.endsWith(FSChar)) newPath += FSChar; + makeDir(newPath); + File[] files = file.listFiles(); + if (files != null && files.length > 0) { + for (File temp : files) { + if (temp.isFile()) { + if (!copyFile(temp, newPath + FSChar + getFullName(temp.getPath()), isDelOld)) return false; + } else if (!copyDir(temp, newPath + FSChar + getFullName(temp.getPath()), isDelOld)) return false; + } + } + return !isDelOld || delFile(file); + } + + + /** + * 将输入流拷贝到输出流 + * + * @param in 输入流 + * @param out 输出流 + * @throws IOException + */ + public static int copyStream(InputStream in, OutputStream out) throws IOException { + // 改为一次读取4096个字节. + byte[] buf = new byte[4096]; + int byteCount = 0; + int bytesRead; + while ((bytesRead = in.read(buf, 0, buf.length)) != -1) { + out.write(buf, 0, bytesRead); + byteCount += bytesRead; + } + out.flush(); + return byteCount; + } + + /** + * 查找压缩文件 + * + * @param bFlag 搜索位置标志 true:从左到右 false:从右到左 + * @param sSearchStr 要搜索的字符串 + * return 文件名 + */ + public static String searchFile(String sSearchStr, boolean bFlag, String sFilePath) { + try { + String sFileName = ""; + String[] fls = getFileNames(sFilePath); + if (fls != null && fls.length > 0) { + for (String fl : fls) { + if (bFlag) { + if (fl.toLowerCase().contains(sSearchStr.toLowerCase())) { + sFileName = fl; + break; + } + } else { + if (fl.toLowerCase().lastIndexOf(sSearchStr.toLowerCase()) >= 0) { + sFileName = fl; + break; + } + } + } + } + return sFileName; + } catch (Exception e) { + return ""; + } + } + + + /** + * 查找所有的文件 * + * + * @param sSearchStr 要搜索的字符串 + * return 文件名list + */ + public static List searchFiles(String sSearchStr, String sFilePath) { + List list = new ArrayList<>(); + try { + String sFileName = ""; + String[] fls = getFileNames(sFilePath); + if (fls != null && fls.length > 0) { + for (String fl : fls) { + if (fl.toLowerCase().contains(sSearchStr.toLowerCase())) { + sFileName = fl; + list.add(sFileName); + } + } + } + return list; + } catch (Exception e) { + return null; + } + } + + + /** + * 创建文件路径 + * + * @param baseDir 该目录所在的父目录 + * @param dirName 目录名 + * @return true-成功;False-不成功 + */ + public static boolean mkDir(String baseDir, String dirName) { + return mkDir(baseDir + FSChar + dirName); + } + + /** + * 创建文件路径 + * + * @param destDir 目录名 + * @return true-成功;False-不成功 + */ + public static boolean mkDir(String destDir) { + boolean blRet = false; + int idx = destDir.lastIndexOf(FSChar); + if (idx == -1) + throw new IllegalArgumentException("输入参数不是一个合法的路径"); + return new File(destDir).mkdirs(); + } + + //创建目录 + public static boolean makeDir(String path) { + File f = new File(path); + return f.exists() || f.mkdirs(); + } + + /** + * 删除目录 + * + * @param file 文件对象; + */ + public static boolean delDir(File file) { + File[] files = file.listFiles(); + if (files != null) { + for (File temp : files) { + if (temp.isFile()) { + if (!temp.delete()) return false; + } else if (!delDir(temp)) return false; + } + return file.delete(); + } + return true; + } + + public static boolean delAllFile(String path) { + File file = new File(path); + File[] files = file.listFiles(); + if (files != null) { + for (File temp : files) { + if (temp.isFile()) { + if (!temp.delete()) return false; + } else if (!delDir(temp)) return false; + } + } + return true; + } + + public static String refineFilePath(String fn) { + String s = fn.replace('\\', File.separatorChar); + s = s.replace('/', File.separatorChar); + int i = s.indexOf("//"); + if (i > 0) s = s.substring(0, i) + s.substring(i + 1); + i = s.indexOf("\\\\"); + if (i > 0) s = s.substring(0, i) + s.substring(i + 1); + return s; + + } + + /** + * 从fn中读取所有内容 + * + * @param fn 源文件名 + * @return byte[] + * @roseuid 3C297D710384 + */ + public static byte[] loadFromFile(String fn) { + try { + FileInputStream fis = new FileInputStream(fn); + byte[] data = new byte[fis.available()]; + fis.read(data, 0, data.length); + fis.close(); + return data; + } catch (IOException e) { + UtilLogger.error(e.getMessage(), e); + return null; + } + } + + /** + * 从fn中读取所有内容 + * + * @param fn 源文件名 + * @return byte[] + * @roseuid 3C297D710384 + */ + public static byte[] loadFromFile(String fn, int size) { + try { + FileInputStream fis = new FileInputStream(fn); + int avail = fis.available(); + byte[] data; + if (avail > size) { + data = new byte[size]; + } else { + data = new byte[avail]; + } + fis.read(data, 0, data.length); + fis.close(); + return data; + } catch (IOException e) { + UtilLogger.error(e.getMessage(), e); + return null; + } + } + + /** + * 从fn中读取所有内容 + * + * @param fn 源文件名 + * @return byte[] + * @roseuid 3C297D710384 + */ + public static byte[] loadFromFile(File fn) { + try { + FileInputStream fis = new FileInputStream(fn); + byte[] data = new byte[fis.available()]; + fis.read(data, 0, data.length); + fis.close(); + return data; + } catch (IOException e) { + UtilLogger.error(e.getMessage(), e); + return null; + } + } + + /** + * 根据文件路径取得该文件路径下的所有文件(含子目录): + * + * @param fp filePath + * @return 存放文件的数组 + */ + public static File[] getFiles(String fp) { + if (fp == null || fp.length() <= 2) { + UtilLogger.debug("文件路径错误"); + return null; + } + File f = new File(fp); + if (f.isFile()) { + UtilLogger.debug("文件路径非文件夹"); + return new File[]{}; + } + return f.listFiles(); + } + + /** + * 根据文件路径取得该文件路径下的所有文件名称: + * + * @param filePath 路径 + * @return 存放文件名称的数组 + */ + public static String[] getFileNames(String filePath) { + if (filePath == null || filePath.length() <= 2) { + return null; + } + File f = new File(filePath); + if (f.isFile()) { + return null; + } + return f.list(); + } + + /** + * 根据文件路径取得该文件路径下的所有文件名称: + * + * @param filePath 目录名 + * @param filters 过滤文件 + * @return list + */ + public static List getFileNames(String filePath, String filters) { + List list = new ArrayList<>(); + String[] files = getFileNames(filePath); + if (files == null) { + return list; + } + for (String file : files) { + if (file.toLowerCase().endsWith(filters) || file.toUpperCase().endsWith(filters)) + list.add(file); + } + return list; + } + + /** + * filePath路径下是否存在文件fn + * + * @param fp 文件路径 + * @param fn 文件名称 + * @return 存放文件名称的数组 + */ + public static boolean isFileExist(String fp, String fn) { + if (fp == null || fn == null) return false; + String absPath; + if (fp.endsWith("/") || fp.endsWith("\\")) { + absPath = fp + fn; + } else { + absPath = fp + FSChar + fn; + } + return (new File(absPath)).exists(); + } + + /** + * 文件fn是否存在 + * + * @param fn fileName + * @return boolean + */ + public static boolean isFileExist(String fn) { + return !(fn == null || fn.length() < 1) && (new File(fn)).exists(); + } + + /** + * 获取父目录 + * + * @param fan 全路径文件名 + * @return 父目录 + */ + public static String getParentPath(String fan) { + try { + String pp = fan; + while (pp.lastIndexOf(FSChar) == (pp.length() - 1) || pp.lastIndexOf(File.separator) == (pp.length() - 1)) { + pp = pp.substring(0, pp.length() - 2); + } + int idx = pp.lastIndexOf(FSChar); + pp = pp.substring(0, idx); + return pp; + } catch (Exception e) { + UtilLogger.error(e.getMessage(), e); + return null; + } + + } + + /** + * 从输入流中所有内容到数组中 + * + * @param is Description of Parameter + * @return Description of the Returned Value + */ + public static byte[] readToBytes(InputStream is) { + byte[] buffer; + int SIZE = 1024 * 1024; + ByteArrayOutputStream bao = null; + try { + bao = new ByteArrayOutputStream(); + + buffer = new byte[SIZE]; + BufferedInputStream in = new BufferedInputStream(is, 1024 * 1024); + int iBytes = 0; + while (iBytes != -1) { + iBytes = in.read(buffer, 0, SIZE); + if (iBytes != -1) { + bao.write(buffer, 0, iBytes); + } + } + return bao.toByteArray(); + } catch (IOException ex) { + UtilLogger.error(ex.getMessage(), ex); + return null; + } finally { + try { + if (bao != null) bao.close(); + } catch (Exception ignored) { + } + } + } + + /** + * 读配置文件 + * searchstr="stic"; + * srcPath=".ini" + */ + public static String ReadINI(String searchstr, String srcPath) { + String str; + String temp = null; + BufferedReader br = null; + searchstr = searchstr.toLowerCase(); + try { + br = new BufferedReader(new InputStreamReader(new FileInputStream(srcPath))); + str = br.readLine(); + while (str != null) { + str = str.trim(); + if (str.length() > 0 && !str.startsWith("#")) { + if (str.toLowerCase().contains(searchstr)) { + temp = str.substring(str.indexOf("=") + 1); + temp = temp.replace('\\', '/'); + break; + } + } + str = br.readLine(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (br != null) br.close(); + } catch (Exception ignored) { + } + } + return temp; + } + + /** + * 检查文件名是否满足Windows风格的通配符

+ * 如*表示任意多个字符,?表示任意一个字符

+ * + * @param fileName:原文件名 + * @param filters: 通配符(*.*,a?.exe,*.zip) + * @return true false; + */ + public static boolean checkFileNames(String fileName, String filters) { + fileName = getRelativeFileName(fileName); + if (fileName == null || filters == null) + return false; + String[] arr_filters = filters.split(","); + //没有通配符,表示任意字符 + if (arr_filters == null || arr_filters.length == 0) return true; + int len = arr_filters.length; + String filter; + for (String arr_filter : arr_filters) { + filter = arr_filter; + filter = filter.trim(); + //java中,"."表示任意字符 + filter = filter.replaceAll("\\.", "\\\\."); + filter = filter.replaceAll("\\*", "\\.\\*"); + filter = filter.replace('?', '.'); + if (fileName.matches(filter)) { + return true; + } + } + + return false; + } + + /** + * 获取文件名(绝对路径)的相对文件名 + * + * @param fileAbsoluteName 绝对路径 + * @return string + */ + public static String getRelativeFileName(String fileAbsoluteName) { + if (fileAbsoluteName == null) + return null; + int pos1 = fileAbsoluteName.lastIndexOf("\\"); + int pos2 = fileAbsoluteName.lastIndexOf("/"); + int pos = Math.max(pos1, pos2); + if (pos == -1) + return fileAbsoluteName; + return fileAbsoluteName.substring(pos + 1); + } + + /** + * 拷贝下文件(非深层次拷贝) + * + * @param srcFileDir 源 + * @param destFileDir 目标 + * @return 有效的拷贝结果; + */ + public static boolean copyDirFileToDir(String srcFileDir, String destFileDir) { + String[] srcFiles = getFileNames(srcFileDir); + try { + if (srcFiles != null && srcFiles.length > 0) { + for (String srcFile : srcFiles) { + copyFile(srcFileDir + "\\" + srcFile, destFileDir + "\\" + srcFile); + } + return true; + } + } catch (Exception e) { + UtilLogger.error("拷贝文件出错!", e); + } + return false; + } + + /** + * 重命名,通过复制的方式 + */ + public static boolean renameTo(String srcFile, String destFile) { + return copy(new File(srcFile), destFile, true); + } + + /** + * 重命名,直接rename,警告,如果想跨盘move,此方法在linux下可能会失败 + * + * @param srcFile 原名 + * @param destFile 目标名字 + * @return + */ + public static boolean renameToEx(String srcFile, String destFile) { + File f = new File(srcFile); + if (!f.exists()) return false; + File df = new File(destFile); + return f.renameTo(df); + } + + /** + * 从文件全路径串中分离出有效的目录名称; + * + * @param filepath + * @return 路径,以分隔符结束; + */ + public static String getFullPath(String filepath) { + int index = filepath.lastIndexOf(FSChar); + if (index != -1) { + return filepath.substring(0, index + 1); + } else { + return ""; + } + } + + /** + * 获取文件全名 + * + * @param fileName 文件路 + * @return fullPathAndFullName + */ + public static String getFullName(String fileName) { + File f = new File(fileName); + return f.getName(); + } + + /** + * 获取文件名 + * + * @param fullPathAndFullName 全路径文件名; + * @return 文件名 + */ + public static String getName(String fullPathAndFullName) { + String fullName = getFullName(fullPathAndFullName); + int index = fullName.lastIndexOf("."); + if (index != -1) { + return fullName.substring(0, index); + } else { + return fullName; + } + } + + /** + * 获取文件扩展名 + * + * @param filepath + * @return string + */ + public static String getExtName(String filepath) { + String fullName = getFullName(filepath); + int index = fullName.lastIndexOf("."); + if (index != -1) { + return fullName.substring(index + 1); + } else { + return ""; + } + } + + /** + * 文件是否存在 + * + * @param fileName + * @return + */ + public static boolean isFileExists(String fileName) { + File f = new File(fileName); + return f.exists(); + } + + //取得文件大小 + public static long getFileSize(File f) { + if (f.exists()) { + try { + try (FileInputStream fis = new FileInputStream(f)) { + return fis.available(); + } + } catch (IOException e) { + return 0L; + } + } + return 0; + } + + public static long getFileSize(String path) { + return getFileSize(new File(path)); + } + + public static void main(String[] args) throws IOException { + // copy("f:/temp/33/worklog_new1", "f:/temp/worklog_new", true); + renameToEx("f:/temp/worklog_new1", "f:/temp/33/worklog_new1"); + } + + /** + * 获取文件列表; + * + * @param dir 文件路径 + * @param suffix 后缀名 + * @param max_level 遍历目录深度,0表示至只获取当前目录,1 标识下级目录, -1标识所有子目录 + * @return List + */ + public static List getDirFileList(String dir, String suffix, int max_level) { + File file = new File(dir); + List fileList = new ArrayList<>(); + getDirFileList(fileList, file, suffix, 0, max_level); + return fileList; + } + + /** + * 获取文件列表; + * + * @param dir 目录对象; + * @param suffix 后缀名 + * @param level 深度; + * @param max_level 最大深度; + * @return + */ + public static void getDirFileList(List fileList, File dir, String suffix, int level, int max_level) { + if (max_level >= 0 && level > max_level) return; + + File[] childs = dir.listFiles(); + if (childs == null) return; + + for (File child : childs) { + if (child.isDirectory()) { + getDirFileList(fileList, child, suffix, level + 1, max_level); + } else { + //String filePath = child.getAbsolutePath(); + String filePath = child.getName(); + if (PubUtil.isEmpty(suffix)) { + //后缀名为null则为所有文件 + fileList.add(filePath); + } else { + int begIndex = filePath.lastIndexOf(".");//最后一个.(即后缀名前面的.)的索引 + String tempsuffix = ""; + //防止是文件但却没有后缀名结束的文件 + if (begIndex != -1) { + tempsuffix = filePath.substring(begIndex + 1); + } + if (tempsuffix.equals(suffix)) { + fileList.add(filePath); + } + } + } + } + } + + /** + * 获取文件列表; + * + * @param dir 文件路径 + * @param suffix 后缀名 + * @param max_level 遍历目录深度,0表示至只获取当前目录,1 标识下级目录, -1标识所有子目录 + * @return List + */ + public static List getFiles(String dir, String suffix, int max_level) { + File file = new File(dir); + List fileList = new ArrayList<>(); + getFiles(fileList, file, suffix, 0, max_level); + return fileList; + } + + /** + * 获取文件列表; + * + * @param dir 目录对象; + * @param suffix 后缀名 + * @param level 深度; + * @param max_level 最大深度; + * @return 文件组合 + */ + public static void getFiles(List fileList, File dir, String suffix, int level, int max_level) { + if (max_level >= 0 && level > max_level) return; + + File[] childs = dir.listFiles(); + if (childs == null) return; + + for (File child : childs) { + if (child.isDirectory()) { + getFiles(fileList, child, suffix, level + 1, max_level); + } else { + String filePath = child.getName(); + if (PubUtil.isEmpty(suffix)) { + //后缀名为null则为所有文件 + fileList.add(child); + } else { + int begIndex = filePath.lastIndexOf(".");//最后一个.(即后缀名前面的.)的索引 + String tempsuffix = ""; + //防止是文件但却没有后缀名结束的文件 + if (begIndex != -1) { + tempsuffix = filePath.substring(begIndex + 1); + } + if (tempsuffix.equals(suffix)) { + fileList.add(child); + } + } + } + } + } + + + public static void zipFile(String zipFileName, File inputFile) throws Exception { + System.out.println("压缩中..."); + ZipOutputStream out = new ZipOutputStream(new FileOutputStream( + zipFileName)); + BufferedOutputStream bo = new BufferedOutputStream(out); + try { + zipFile(out, inputFile, inputFile.getName(), bo); + } finally { + IOUtils.closeQuietly(bo); + IOUtils.closeQuietly(out); + } + + System.out.println("压缩完成"); + } + + private static void zipFile(ZipOutputStream out, File f, String base, BufferedOutputStream bo) throws Exception { // 方法重载 + if (f.isDirectory()) { + File[] fl = f.listFiles(); + if (fl.length == 0) { + out.putNextEntry(new ZipEntry(base + "/")); // 创建zip压缩进入点base +// System.out.println(base + "/"); + } + for (int i = 0; i < fl.length; i++) { + zipFile(out, fl[i], base + "/" + fl[i].getName(), bo); // 递归遍历子文件夹 + } + } else { + out.putNextEntry(new ZipEntry(base)); // 创建zip压缩进入点base +// System.out.println(base); + FileInputStream in = new FileInputStream(f); + BufferedInputStream bi = new BufferedInputStream(in); + try { + int b = bi.available(); + byte[] data = new byte[b]; + while ((bi.read(data, 0, b)) != -1) { + bo.write(data, 0, b); // 将字节流写入当前zip目录 + bo.flush(); + } + } finally { + IOUtils.closeQuietly(bi); + IOUtils.closeQuietly(in); + } + + } + } + + + //解压缩返回解压之后的文件夹路径 + public static String unZipFile(File zipFile, String outpath) { + String fileout = ""; + long startTime = System.currentTimeMillis(); + try { + ZipInputStream zin = new ZipInputStream(new FileInputStream(zipFile));//输入源zip路径 + BufferedInputStream bin = new BufferedInputStream(zin); + String Parent = outpath; //输出路径(文件夹目录) + File Fout = null; + ZipEntry entry; + try { + UtilLogger.debug("开始解压文件:" + zipFile.getName()); + while ((entry = zin.getNextEntry()) != null) { + String name = entry.getName(); + Fout = new File(Parent, name); + if (name.split("\\/").length > 1) fileout = name.split("\\/")[0]; + if (!Fout.exists()) { + (new File(Fout.getParent())).mkdirs(); + } + if (entry.isDirectory()) continue; + UtilLogger.debug(" 解压:" + name); + + FileOutputStream out = new FileOutputStream(Fout); + BufferedOutputStream Bout = new BufferedOutputStream(out); + try { + int b; + while ((b = bin.read()) != -1) { + Bout.write(b); + } + } finally { + IOUtils.closeQuietly(Bout); + IOUtils.closeQuietly(out); + } +// System.out.println(Fout+"解压成功"); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + IOUtils.closeQuietly(bin); + IOUtils.closeQuietly(zin); + } + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + long endTime = System.currentTimeMillis(); + UtilLogger.debug("解压完成!耗费时间: " + (endTime - startTime) + " ms"); + return outpath + "\\" + fileout; + } + + /** + * 读取txt文件类型 + * @param fileName + * @return + */ + public static String readFileContent(String fileName) { + File file = new File(fileName); + BufferedReader reader = null; + StringBuffer sbf = new StringBuffer(); + try { + reader = new BufferedReader(new FileReader(file)); + String tempStr; + while ((tempStr = reader.readLine()) != null) { + sbf.append(tempStr); + } + reader.close(); + return sbf.toString(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + return sbf.toString(); + } + /** + * 解压文件到指定目录 + * + * @param zipFile + * @param descDir + * @author isea533 + */ + public static void unZipFiles(File zipFile, String descDir) throws IOException { + if (!descDir.endsWith("\\") && !descDir.endsWith("/")) descDir = descDir + "/"; + File pathFile = new File(descDir); + if (!pathFile.exists()) { + pathFile.mkdirs(); + } + Charset gbk = Charset.forName("GBK"); + ZipFile zip = new ZipFile(zipFile, gbk); + UtilLogger.debug("开始解压文件:" + zipFile.getName()); + try { + for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { + ZipEntry entry = (ZipEntry) entries.nextElement(); + String zipEntryName = entry.getName(); + InputStream in = zip.getInputStream(entry); + try { + String outPath = (descDir + zipEntryName).replaceAll("\\*", "/"); + + //判断路径是否存在,不存在则创建文件路径 + File file = new File(outPath.substring(0, outPath.lastIndexOf('/'))); + if (!file.exists()) { + file.mkdirs(); + } + //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压 + if (new File(outPath).isDirectory()) { + continue; + } + UtilLogger.debug(" 解压:" + zipEntryName); + //输出文件路径信息 + // System.out.println(outPath); + + OutputStream out = new FileOutputStream(outPath); + try { + byte[] buf1 = new byte[1024]; + int len; + while ((len = in.read(buf1)) > 0) { + out.write(buf1, 0, len); + } + } finally { + IOUtils.closeQuietly(out); + } + } finally { + IOUtils.closeQuietly(in); + } + } + UtilLogger.debug("解压完成! "); + } finally { + zip.close(); + } + + + } + + /** + * 判断是否是图片 + * + * @param base64Str + * @return + */ + public static boolean isImageFromBase64(String base64Str) { + boolean flag = false; + try { + BufferedImage bufImg = ImageIO.read(new ByteArrayInputStream(new BASE64Decoder().decodeBuffer(base64Str))); + if (null == bufImg) { + return flag; + } + flag = true; + } catch (Exception e) { + return flag; + } + return flag; + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilLogger.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilLogger.java new file mode 100644 index 0000000..ce379cf --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilLogger.java @@ -0,0 +1,66 @@ +package cc.smtweb.system.bpm.util; + +import cc.smtweb.framework.core.util.PubUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; + +@SuppressWarnings("UnusedDeclaration") +public class UtilLogger { + private static final Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + + private static String getOrigMsg(String message, Throwable e) { + if (message != null) return message; + return PubUtil.getOrigMsg(e); + } + + public static void debug(String message) { + logger.debug(message); + } + + public static void debug(String message, String module) { + logger.debug(MessageFormat.format("[{0}]{1}", module, message)); + } + + public static void debug(String message, Throwable e) { + logger.debug(getOrigMsg(message, e), e); + } + + public static void info(String message) { + logger.info(message); + } + + public static void info(String message, String module) { + logger.info(MessageFormat.format("[{0}]{1}", module, message)); + } + + public static void info(String message, Throwable e) { + logger.info(getOrigMsg(message, e), e); + } + + public static void warn(String message) { + logger.warn(message); + } + + public static void warn(String message, String module) { + logger.warn(MessageFormat.format("[{0}]{1}", module, message)); + } + + public static void warn(String message, Throwable e) { + logger.warn(getOrigMsg(message, e), e); + } + + public static void error(String message) { + logger.error(message); + } + + public static void error(String message, String module) { + logger.error(MessageFormat.format("[{0}]{1}", module, message)); + } + + public static void error(String message, Throwable e) { + if (e instanceof Exception) logger.info(message + PubUtil.getOrigMsg(e)); + else logger.error(getOrigMsg(message, e), e); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilMath.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilMath.java new file mode 100644 index 0000000..99f5613 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilMath.java @@ -0,0 +1,465 @@ +package cc.smtweb.system.bpm.util; + +import cc.smtweb.framework.core.util.PubUtil; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; + +/** + * Created with IntelliJ IDEA. + * User: AKhh + * Date: 12-12-25 下午1:02 + * To change this template use File | Settings | File Templates. + */ +public class UtilMath { + //整数 + private static DecimalFormat dfLng = new DecimalFormat("##############0"); + private static DecimalFormat dfLong = new DecimalFormat("###,###,###,###,##0"); + //一位小数 + private static DecimalFormat df1 = new DecimalFormat("##############0.0"); + private static DecimalFormat df1Format = new DecimalFormat("###,###,###,###,##0.0"); + //两位小数 + private static DecimalFormat df2 = new DecimalFormat("##############0.00"); + private static DecimalFormat df2Format = new DecimalFormat("###,###,###,###,##0.00"); + //四位小数 + private static DecimalFormat df4 = new DecimalFormat("###,###,###,###,##0.0000"); + //六位小数 + private static DecimalFormat df6Number = new DecimalFormat("#######################0.000000"); + private static DecimalFormat df6NumberF = new DecimalFormat("#,###,###,###,###,###,##0.000000"); + + public final static DecimalFormat stdAmountFormat = new DecimalFormat("###,###,###,###,##0.00"); + public final static DecimalFormat stdNumberFormat = new DecimalFormat("#0.00"); + public final static String DEF_NUM_TEN_THOUSAND = "10000";//万 + public static final double MAX_VALUE = 9999999999999.99D; + public static final double MIN_VALUE = -9999999999999.99D; + + private final static BigDecimal ONE_BIG = new BigDecimal(1.00D); + private static final String UNIT = "万仟佰拾亿仟佰拾万仟佰拾元角分"; + private static final String DIGIT = "零壹贰叁肆伍陆柒捌玖"; + + /** + * 4舍5入double,2位小数 + */ + public static double roundDouble(double src) { + return roundDouble(src, 2); + } + + /** + * 4舍5入double,N 位小数 + * @param src + * @param scale 小数位数 + * @return + */ + public static double roundDouble(Object src, int scale) { + if (src == null) return 0.0; + String v = src.toString(); + if (PubUtil.isEmpty(v)) return 0.0; + if (scale < 0) scale = 2; + + BigDecimal src_b = new BigDecimal(v); + BigDecimal src_v = src_b.divide(ONE_BIG, scale + 2, BigDecimal.ROUND_HALF_UP);// 4舍5入 + src_v = src_v.divide(ONE_BIG, scale, BigDecimal.ROUND_HALF_UP);// 4舍5入 + return src_v.doubleValue(); + } + + /** + * 舍位处理,原生floor有坑,部分浮点数记录为.99999999999形式,导致floor结果错误 + * @param d + * @return + */ + public static double floor(double d) { + return Math.floor(UtilMath.roundDouble(d, 2)); + } + + /** + * 比较两Double是否相等,将会吧他们专程BigDecimal进行比较; + * + * @param src double1 + * @param tag double2 + * @return src > tag 返回1, src < tag 返回-1, 否则返回0 + */ + public static int compare(double src, double tag) { + BigDecimal src_b = new BigDecimal(src); + BigDecimal src_v = src_b.divide(ONE_BIG, 2, BigDecimal.ROUND_HALF_UP);// 4舍5入 + + BigDecimal tag_b = new BigDecimal(tag); + BigDecimal tag_v = tag_b.divide(ONE_BIG, 2, BigDecimal.ROUND_HALF_UP);// 4舍5入 + + return src_v.compareTo(tag_v); + } + + /** + * 自动过滤金额中的逗号转换为double,如果出错,则返回0 + * + * @param s 源串,可能为带逗号的金额串; + * @return double + */ + public static Double toDouble(String s) { + return todouble(s); + } + + /** + * 自动过滤金额中的逗号转换为double,如果出错,则返回0 + * + * @param s 源串,可能为带逗号的金额串; + * @return double + */ + public static double todouble(String s) { + try { + return Double.parseDouble(s.replaceAll(",", "")); + } catch (Exception e) { + return 0.00; + } + } + + /** + * 获取double,主要过滤d为null的情况; + * + * @param d Double对象; + * @return double + */ + public static double todouble(Double d) { + if (d == null) return 0.0d; + return d.doubleValue(); + } + + /** + * 自动过滤金额中的逗号转换为float,如果出错,则返回0 + * + * @param s 源串,可能为带逗号的金额串; + * @return Float + */ + public static Float toFloat(String s) { + return tofloat(s); + } + + /** + * 自动过滤金额中的逗号转换为float,如果出错,则返回0 + * + * @param s 源串,可能为带逗号的金额串; + * @return Float + */ + public static float tofloat(String s) { + try { + return Float.parseFloat(s.replaceAll(",", "")); + } catch (Exception e) { + return 0.0f; + } + } + + public static long tolong(String src, long defaultvalue) { + try { + return Long.parseLong(src); + } catch (Exception e) { + return defaultvalue; + } + } + + public static int toint(String src, int defaultvalue) { + try { + return Integer.parseInt(src); + } catch (Exception e) { + return defaultvalue; + } + } + + /** + * 考虑使用中的精度,判断一个Value是否>0,实际是>0.00001 + * + * @param value double类型 + * @return boolean + */ + public static boolean isBigThanZero(double value) { + return (value > 0.00001); + } + + /** + * 考虑使用中的精度,判断一个Value是否>0,实际是>0.00001 + * + * @param value String类型 + * @return boolean + */ + public static boolean isBigThanZero(String value) { + return !PubUtil.isEmpty(value) && isBigThanZero(toDouble(value)); + } + + /** + * 考虑使用中的精度,判断一个Value是否=0,实际是给出一个值范围。 + * + * @param value double类型 + * @return boolean + */ + public static boolean isEqualsZero(double value) { + return (-0.00001 < value && value < 0.00001); + } + + /** + * 考虑使用中的精度,判断一个Value是否=0,实际是给出一个值范围。 + * + * @param value String类型 + * @return boolean + */ + public static boolean isEqualsZero(String value) { + return PubUtil.isEmpty(value) || isEqualsZero(toDouble(value)); + } + + /** + * 是否是负数 + * + * @param db_val 要判断的double + * @return 负数则返回true; + */ + public static boolean isNegative(double db_val) { + return (compare(db_val, 0.00D) == -1); + } + + /** + * 是否是正数 + * + * @param db_val 要判断的double + * @return 正数则返回true; + */ + public static boolean isPlus(double db_val) { + return (compare(db_val, 0.00D) == 1); + } + + /** + * 得到金额字符串,保持小数点2位 + * + * @param db 将double转换为金额字符串; + * @return 金额字符串#0.00; + */ + public static String toStdNumberString(double db) { + try { + return stdNumberFormat.format(db); + } catch (Exception e) { + return "0.00"; + } + } + + public static String toStdNumberStringEx(double db) { + try { + if (compare(db, -1d) == 0) return "-"; + return stdNumberFormat.format(db); + } catch (Exception e) { + return "0.00"; + } + } + + /** + * 将金额格式字符串,如23,333,093.01 去掉逗号 + * + * @param s 金额串 + * @return String 去掉逗号后的串,如果amount为空,则返回0.00 + */ + public static String toStdNumberString(String s) { + if (PubUtil.isEmpty(s)) + return "0.00"; + return stdNumberFormat.format(UtilMath.todouble(s)); + } + + /** + * 将数据转换为两位小数的数字格式; + * + * @param d 数据 + * @param isZeroToEmpty 如果未0,是否返回“”; + * @return 两位小数的字符串; + */ + public static String toStdNumberString(double d, boolean isZeroToEmpty) { + if (isEqualsZero(d)) { + return isZeroToEmpty ? "": "0.00"; + } + return stdNumberFormat.format(d); + } + + public static String toStdNumberString(String s, boolean isZeroToEmpty) { + return toStdNumberString(UtilMath.todouble(s), isZeroToEmpty); + } + + public static String toStdNumberString(double d, int scale) { + DecimalFormat dfn = null; + if (scale == 1) dfn = df1Format; + if (scale == 2) dfn = df2Format; + else if (scale == 4) dfn = df4; + else if (scale == 6) dfn = df6NumberF; + else if (scale <= 0) dfn = dfLong; + else { + StringBuilder sb = new StringBuilder("###,###,###,###,##0."); + for (int i = 0; i < scale; i++) sb.append("0"); + dfn = new DecimalFormat(sb.toString()); + } + return dfn.format(d); + } + + /** + * 将数字乘100,保留小数点后两位, 然后后面添加% + * + * @param d 值 + * @param isZeroToEmpty,如果值为0,是否返回空; + * @return 字符串; + */ + public static String toStdPercentNumberStr(double d, boolean isZeroToEmpty) { + if (d > -0.00000000001 && d < 0.00000000001) { + return isZeroToEmpty ? "": "0.00%"; + } + return toStdNumberString(d * 100) + "%"; + } + + + public static String toStdAmountString(double d) { + return toStdAmountString(d, false); + } + + /** + * 将数据转换为两位小数的金额格式,带逗号; + * + * @param d 数据 + * @param isZeroToEmpty 如果未0,是否返回“”; + * @return 金额格式的字符串; + */ + public static String toStdAmountString(double d, boolean isZeroToEmpty) { + if (isEqualsZero(d)) { + return isZeroToEmpty ? "": "0.00"; + } + return stdAmountFormat.format(d); + } + + public static String toStdAmountString(String s) { + return toStdAmountString(UtilMath.todouble(s), false); + } + + public static String toStdAmountString(String s, boolean isZeroToEmpty) { + return toStdAmountString(UtilMath.todouble(s), isZeroToEmpty); + } + + + /** + * 将小写金额转换为人民币大写金额 + * + * @param s 金额格式的串 + * @return String 转换结果 + */ + public static String toCapsAmountString(String s) { + if (PubUtil.isEmpty(s)) return ""; + return toCapsAmountString(todouble(s)); + } + + /** + * 将小写金额转换为人民币大写金额 + * + * @param v double + * @return String 转换结果 + */ + public static String toCapsAmountString(double v) { + if (v < MIN_VALUE || v > MAX_VALUE) return "参数非法!"; + + boolean negative = isNegative(v); + + if (negative) v = Math.abs(v); + long l = Math.round(v * 100); + if (l == 0) return "零元整"; + + String strValue = String.valueOf(l); + // i用来控制数 + int i = 0; + // j用来控制单位 + int j = UNIT.length() - strValue.length(); + StringBuilder rs = new StringBuilder(32); + boolean isZero = false; + for (; i < strValue.length(); i++, j++) { + char ch = strValue.charAt(i); + if (ch == '0') { + isZero = true; + if (UNIT.charAt(j) == '亿' || UNIT.charAt(j) == '万' || UNIT.charAt(j) == '元') { + rs.append(UNIT.charAt(j)); + isZero = false; + } + } else { + if (isZero) { + rs.append('零'); + isZero = false; + } + rs.append(DIGIT.charAt(ch - '0')).append(UNIT.charAt(j)); + } + } + if (rs.charAt(rs.length() - 1) != '分') + rs.append('整'); + + i = rs.indexOf("亿万"); + if (i > 0) rs.delete(i + 1, i + 2); // i+1 ->万 + + if (negative) + return rs.insert(0, '负').toString(); + else + return rs.toString(); + } + + /** + * 返回0 到 maxvalue的随机数 + * + * @param maxvalue 随机数的最大值 + * @return int + */ + public static int rnd(int maxvalue) { + return (int) (Math.random() * (maxvalue + 1)); + } + + + public static double chkDbNull(Double v) { + return v == null ? 0: v; + } + + public static double max(double d1, double d2) { + return compare(d1, d2) < 0 ? d2 : d1; + } + + public static double min(double d1, double d2) { + return compare(d1, d2) < 0 ? d1 : d2; + } + + + public static void main(String[] args) { + double aa=123456789.345678900005; + System.out.println("args0 = " + upDouble(aa,0)); + System.out.println("args1 = " + upDouble(aa,1)); + System.out.println("args2 = " + upDouble(aa,2)); + System.out.println("args3 = " + upDouble(aa,3)); + System.out.println("args4 = " + upDouble(aa,4)); + System.out.println("args5 = " + upDouble(aa,5)); + System.out.println("args5 = " + upDouble(aa,6)); + System.out.println("args5 = " + upDouble(aa,7)); + System.out.println("args5 = " + upDouble(aa,8)); + + } + + /** + * double 去尾法 + * @param src 待处理数据 + * @param scale 保留小数位数 + * @return + */ + public static double cutDouble(double src, int scale){ + String v = toStdNumberString(src, 6);//先到6位小数,再去计算,否则容易出错,如8.3成8.29999999999,舍位就成了8.29了 + DecimalFormat formater = new DecimalFormat(); + formater.setMaximumFractionDigits(scale); + formater.setGroupingSize(0); + formater.setRoundingMode(RoundingMode.FLOOR); + return new BigDecimal(formater.format(toDouble(v))).doubleValue(); + } + + /** + * double 进位法 + * @param src 待处理数据 + * @param scale 保留小数位数 + * @return + */ + public static double upDouble(double src, int scale){ + String v = toStdNumberString(src, 6);//先到6位小数,再去计算 + DecimalFormat formater = new DecimalFormat(); + formater.setMaximumFractionDigits(scale); + formater.setGroupingSize(0); + formater.setRoundingMode(RoundingMode.UP); + return new BigDecimal(formater.format(toDouble(v))).doubleValue(); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilString.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilString.java new file mode 100644 index 0000000..1eda782 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/UtilString.java @@ -0,0 +1,504 @@ +package cc.smtweb.system.bpm.util; + + +import cc.smtweb.framework.core.util.PubUtil; + +import java.text.Collator; +import java.util.*; + +/** + * Created with IntelliJ IDEA. + * User: AKhh + * Date: 12-12-24 下午5:09 + * To change this template use File | Settings | File Templates. + */ +@SuppressWarnings("UnusedDeclaration") +public class UtilString { + private static Collator chineseCollator = Collator.getInstance(Locale.CHINA); + + /** + * strSrc中寻找第一个strSe并且返回以其分隔的Left部分,汉字长度也为1 + * + * @param strSrc 源字符串 + * @param strSe 分割字符 + * @return String 返回 + */ + public static String getLeft(String strSrc, String strSe) { + if (PubUtil.isEmpty(strSrc)) + return ""; + if (PubUtil.isEmpty(strSe)) + strSe = " "; + + String result = ""; + int pos = strSrc.indexOf(strSe); + if (pos >= 0) + result = strSrc.substring(0, pos); + return result; + } + + /** + * 返回字符串的左边部分,汉字长度也为1 + * + * @param strSrc 源串,如果为空,则返回“”; + * @param count 要获取的右边字符串长度,负数将返回“”,如果count>字符串长度,则返回整个字符串; + * @return String return + */ + public static String getLeft(String strSrc, int count) { + if (PubUtil.isEmpty(strSrc) || count <= 0) { + return ""; + } + if (strSrc.length() < count) { + return strSrc; + } else { + return strSrc.substring(0, count); + } + } + + /** + * strSrc中寻找第一个strSe并且返回以其分隔的Right部分,汉字长度也为1 + * + * @param strSrc 源串 + * @param strSe 分隔符,一个字符 + * @return String right部分 + */ + public static String getRight(String strSrc, String strSe) { + if (PubUtil.isEmpty(strSrc)) + return ""; + if (PubUtil.isEmpty(strSe)) + strSe = " "; + + String result = strSrc; + int pos = strSrc.indexOf(strSe); + if (pos >= 0) + result = strSrc.substring(pos + strSe.length()); + return result; + } + + /** + * 返回字符串的右边部分,汉字长度也为1 + * + * @param strSrc 源串 + * @param count 要获取的右边字符串长度,负数将返回“”,如果count>字符串长度,则返回整个字符串; + * @return String return + */ + public static String getRight(String strSrc, int count) { + if (PubUtil.isEmpty(strSrc) || count <= 0) { + return ""; + } + int l = strSrc.length(); + if (l <= count) { + return strSrc; + } + return strSrc.substring(l - count); + } + + /** + * 左边补齐字符 + * + * @param src 源串 + * @param pad 补齐字符 + * @param length 最终长度 + * @return 补齐后的字符串 + */ + public static String padLeft(String src, String pad, int length) { + StringBuilder sb = new StringBuilder(repeatString(pad, length)); + sb.append(src); + return sb.substring(sb.length() - length); + } + + public static String padLeft(long src, String pad, int length) { + StringBuilder sb = new StringBuilder(repeatString(pad, length)); + sb.append(src); + return sb.substring(sb.length() - length); + } + + public static String padRight(String src, String pad, int length) { + StringBuilder sb = new StringBuilder(length * pad.length() + src.length()); + sb.append(src).append(repeatString(pad, length)); + return sb.substring(0, length); + } + + public static String padRight(long src, String pad, int length) { + StringBuilder sb = new StringBuilder(length * pad.length()); + sb.append(src).append(repeatString(pad, length)); + return sb.substring(0, length); + } + + /** + * 由于jdk1.3提供的replace函数不能满足替换要求,自己写一个 + * + * @param src 源串 + * @param oldS 将... + * @param newS 替换成... + * @return 替换后的字符串 + */ + public static String replaceString(String src, String oldS, String newS) { + StringBuilder ret = new StringBuilder(64); + int pos = src.indexOf(oldS); + while (pos >= 0) { + ret.append(src, 0, pos).append(newS); + src = src.substring(pos + oldS.length()); + pos = src.indexOf(oldS); + } + ret.append(src); + return ret.toString(); + } + + /** + * 取得指定字符串左边的有效数字,首先去掉两边空格 + * + * @param s 源串 + * @return 串左边的有效数字 + */ + public static String getStringLeftNumber(String s) { + String ret = ""; + int dotCount = 0; + s = s.trim(); + char[] carr = s.toCharArray(); + for (char aCarr : carr) { + if (Character.isDigit(aCarr)) { + ret += aCarr; + } else if (aCarr == '.' && dotCount == 0) { + ret += aCarr; + dotCount++; + } else { + break; + } + } + if (ret.endsWith(".")) { + ret = ret.substring(0, ret.length() - 1); + } + return ret; + } + + /** + * 取得重复字串 + * + * @param repeatString 重复字串 + * @param count 重复次数 + * @return String + */ + public static String repeatString(String repeatString, int count) { + if (count <= 0) return ""; + StringBuilder ret = new StringBuilder(repeatString.length() * count); + for (int i = 1; i <= count; i++) { + ret.append(repeatString); + } + return ret.toString(); + } + + /** + * 去除字符串左边的指定字符串 + * + * @param src 源字符串 + * @param cut 要去掉的字符串; + * @return 处理结果 + */ + public static String cutStringLeft(String src, String cut) { + if (PubUtil.isEmpty(src) || PubUtil.isEmpty(cut)) { + return ""; + } + if (src.startsWith(cut)) { + return cutStringLeft(src.substring(cut.length()), cut); + } else { + return src; + } + } + + public static String cutStringRight(String src, String cut) { + if (PubUtil.isEmpty(src) || PubUtil.isEmpty(cut)) { + return ""; + } + while (src.endsWith(cut)) + src = src.substring(0, src.length() - cut.length()); + + return src; + } + + /** + * Removes all spaces from a string + * 可以替换大部分空白字符, 不限于空格,\s 可以匹配空格、制表符、换页符等空白字符的其中任意一个 + */ + public static String removeSpaces(String str) { + return str.replaceAll("\\s*", ""); + } + + /** + * Creates a single string from a List of strings seperated by a delimiter. + * + * @param list a list of strings to join + * @param delim the delimiter character(s) to use. (null value will join with no delimiter) + * @return a String of all values in the list seperated by the delimiter + */ + public static String join(List list, String delim) { + if (list == null || list.size() < 1) + return null; + StringBuffer buf = new StringBuffer(); + Iterator i = list.iterator(); + + while (i.hasNext()) { + buf.append((String) i.next()); + if (i.hasNext()) + buf.append(delim); + } + return buf.toString(); + } + + /** + * Splits a String on a delimiter into a List of Strings. + * + * @param str the String to split + * @param delim the delimiter character(s) to join on (null will split on whitespace) + * @return a list of Strings + */ + public static List split(String str, String delim) { + List splitList = new ArrayList<>(); + StringTokenizer st; + if (str == null) + return splitList; + + if (delim != null) + st = new StringTokenizer(str, delim); + else + st = new StringTokenizer(str); + + while (st.hasMoreTokens()) { + splitList.add(st.nextToken()); + } + return splitList; + } + + //是否为true,(1,y,true,yes) + public static boolean toBoolean(String v) { + return "1".equals(v) || "y".equalsIgnoreCase(v) || "true".equalsIgnoreCase(v) || "yes".equalsIgnoreCase(v); + } + + public static int chineseCompare(String s1, String s2) { + return chineseCollator.compare(s1, s2); + } + + /** + * 按照编码级次,得到类型的真实编码,主要用于like 'parentCode%' + * getSplitTypeCode('GF82000',2, 2, 1) == GF82 + * getSplitTypeCode('GF82100',3, 2, 1) == GF821 + * getSplitTypeCode('82100' ,3, 0, 1) == 821 + * + * @param curLevel 当前编码的所在层次 + * @param startIndex 数字编码的开始选项 + * @param perSize 每层的数字编码长度 + */ + public static String getRealCode(String code, int curLevel, int startIndex, int perSize) { + StringBuilder sb = new StringBuilder(code.length()); + if (startIndex > 0) sb.append(code, 0, startIndex); + for (int i = startIndex, l = 0; i < code.length(); i += perSize) { + if (l < curLevel) { + sb.append(code, i, i + perSize); + ++l; + } else { + break; + } + } + return sb.toString(); + } + + //函数功能: 正整数 + public static boolean isPureNumber(String inputString) { + return inputString.matches("^[1-9]\\d*$"); + } + + //函数功能: 整数 + public static boolean isNumber(String inputString) { + return inputString.matches("^[-+][0-9]\\d*$"); + } + + //函数功能: 浮点数 + public static boolean isAmount(String inputString) { + return inputString.matches("^[-+]?[\\d,]+(\\.\\d+)?$"); + } + + //函数功能: 带千分号的整数 + public static boolean isFormatNumber(String inputString) { + return inputString.matches("^[-+]?[\\d,]+(\\d+)?$"); + } + + + //首字母大写 + public static String upFirst(String s) { + return s.substring(0, 1).toUpperCase() + s.substring(1); + } + + public static String padRightBytes(String src, String pad, int length) { + length -= src.replaceAll("[^\\x00-\\xff]", "**").length(); + return src + repeatString(pad, length); + } + + //按字节数取子串,begin不是按字节的 + public static String substrByte(String src, int begin, int len) { + StringBuilder sb = new StringBuilder(32); + char c; + int tl = src.length(); + for (int i = begin; i < len + begin && i < tl; i++) { + + c = src.charAt(i); + sb.append(c); + if (String.valueOf(c).replaceAll("[^\\x00-\\xff]", "**").length() > 1) { + // 遇到中文汉字,截取字节总数减1 + --len; + } + } + return sb.toString(); + } + + /** + * 通配符算法。 可以匹配"*"和"?" + * 如a*b?d可以匹配aAAAbcd + * + * @param pattern 匹配表达式 + * @param str 匹配的字符串 + * @return + */ + public static boolean match(String pattern, String str) { + if (pattern == null || str == null) + return false; + + boolean result = false; + char c; // 当前要匹配的字符串 + boolean beforeStar = false; // 是否遇到通配符* + int back_i = 0;// 回溯,当遇到通配符时,匹配不成功则回溯 + int back_j = 0; + int i, j; + for (i = 0, j = 0; i < str.length(); ) { + if (pattern.length() <= j) { + if (back_i != 0) {// 有通配符,但是匹配未成功,回溯 + beforeStar = true; + i = back_i; + j = back_j; + back_i = 0; + back_j = 0; + continue; + } + break; + } + + if ((c = pattern.charAt(j)) == '*') { + if (j == pattern.length() - 1) {// 通配符已经在末尾,返回true + result = true; + break; + } + beforeStar = true; + j++; + continue; + } + + if (beforeStar) { + if (str.charAt(i) == c) { + beforeStar = false; + back_i = i + 1; + back_j = j; + j++; + } + } else { + if (c != '?' && c != str.charAt(i)) { + result = false; + if (back_i != 0) {// 有通配符,但是匹配未成功,回溯 + beforeStar = true; + i = back_i; + j = back_j; + back_i = 0; + back_j = 0; + continue; + } + break; + } + j++; + } + i++; + } + + if (i == str.length() && j == pattern.length())// 全部遍历完毕 + result = true; + return result; + } + + //填充变量 + public static String myReplaceStrEx(String express, String b, String e, IStrHanlder hanlder) { + if (null == express) return express; + int keyBegin = 0, keyEnd = 0; + int lb = b.length(), le = e.length(); + String fn; + while (true) { + keyBegin = express.indexOf(b, keyBegin); + if (keyBegin < 0) break; + keyEnd = express.indexOf(e, keyBegin); + if (keyEnd <= keyBegin) break; + keyBegin++; + fn = express.substring(keyBegin + lb - 1, keyEnd); + fn = hanlder.work(fn); + if (fn != null) { + express = express.substring(0, keyBegin - 1) + fn + express.substring(keyEnd + le); + } + } + return express; + } + + //填充变量 + public static String myReplaceStrEx(String express, String b, String e, final Map mapVals) { + return myReplaceStrEx(express, b, e, new IStrHanlder() { + @Override + public String work(String src) { + return PubUtil.checkNull(mapVals.get(src)); + } + }); + } + + /*Blob转String*/ +// public static String blob2Str(Blob blob) { +// if (blob == null) return ""; +// ByteArrayOutputStream outStream = null; +// try { +// long len = blob.length(); +// if (len == 0L) return ""; +// byte[] bytes; +// long i = 1L; +// outStream = new ByteArrayOutputStream(); +// while (i < len) { +// bytes = blob.getBytes(i, 1024); +// i += 1024L; +// outStream.write(bytes); +// } +// +// return UtilEncode.base64EncodeB(outStream.toByteArray()); +// } catch (Exception e) { +// e.printStackTrace(); +// return ""; +// } finally { +// IOUtils.closeQuietly(outStream); +// } +// } + + + public interface IStrHanlder { + String work(String src); + } + + public static int[] splitStr(String src, String ch) { + String[] ss = src.split(ch); + int[] ret = new int[ss.length]; + for (int i = 0, len = ss.length; i < len; i++) { + ret[i] = PubUtil.getIntIgnoreErr(ss[i]); + } + return ret; + } + + public static void main(String[] args) { + String s = "a[#[#123#]bcde[aaa]bcd"; + s = UtilString.myReplaceStrEx(s, "[#", "#]", new UtilString.IStrHanlder() { + @Override + public String work(String src) { + if (src.equals("123")) return "1"; + return null; + } + }); + System.out.println(s); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpTask.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpTask.java new file mode 100644 index 0000000..b80e141 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpTask.java @@ -0,0 +1,6 @@ +package cc.smtweb.system.bpm.util.ftp; + +//FTP执行接口 +public interface FtpTask { + Object execute(IFtpUtil ftp) throws Exception; +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpTaskManager.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpTaskManager.java new file mode 100644 index 0000000..706fb62 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpTaskManager.java @@ -0,0 +1,255 @@ +package cc.smtweb.system.bpm.util.ftp; + + + +import cc.smtweb.framework.core.util.DateUtil; +import cc.smtweb.framework.core.util.PubUtil; +import cc.smtweb.system.bpm.util.UtilLogger; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +//ftp管理类 +public class FtpTaskManager { + private static Map mapInstance = null; + + static { + mapInstance = new HashMap<>(); + } + + //多线程 + private Map mapThreadFtp = new HashMap<>(); + + public static FtpTaskManager getInstance(String key, IFtpServerConfig ftpConfig) { + key = key + "_" + (ftpConfig.isSFTP() ? 1 : 0) + ftpConfig.getServerIp() + "_" + ftpConfig.getPort() + "_" + ftpConfig.getUserName(); + FtpTaskManager instance = mapInstance.get(key); + if (instance == null) { + synchronized (FtpTaskManager.class) { + instance = mapInstance.get(key); + if (instance == null) { + FtpTaskManager inst = new FtpTaskManager(); + inst.init(ftpConfig); + instance = inst; + mapInstance.put(key, instance); + } + } + } + return instance; + } + + private IFtpServerConfig ftpConfig = null; + + public FtpTaskManager() { + } + + //初始化配置信息 + public void init(IFtpServerConfig ftpConfig) { + this.ftpConfig = ftpConfig; + } + + //获取一个ftp客户端 + public IFtpUtil getFtpUtil() { + IFtpUtil ftp = mapThreadFtp.get(Thread.currentThread()); + if (ftp != null) return ftp; + + ftp = ftpConfig.isSFTP() ? new SFtpUtil() : new FtpUtil(); + boolean isConnect = ftp.login(ftpConfig); + if (isConnect) { + UtilLogger.info("FTP连接成功!"); + } else { + UtilLogger.info("FTP连接失败!" + ftpConfig.getServerIp() + " " + ftpConfig.getPort() + " " + ftpConfig.getUserName() + " " + ftpConfig.getPassword()); + } + return ftp; + } + + //获取并加到线程中备用 + public IFtpUtil getThreadFtpUtil() { + IFtpUtil ftp = getFtpUtil(); + ftp.setAutoFree(false); + mapThreadFtp.put(Thread.currentThread(), ftp); + return ftp; + } + + //释放,和getThreadFtpUtil配对 + public void dispose() { + IFtpUtil ftp = mapThreadFtp.remove(Thread.currentThread()); + if (ftp == null) return; + ftp.setAutoFree(true); + ftp.disconnect(); + } + + /** + * 直接执行一个Ftp任务 + */ + public Object execute(FtpTask ftpTask) throws Exception { + IFtpUtil ftp = getFtpUtil(); + if (!ftp.isConnected()) + throw new Exception("FTP连接失败(" + ftpConfig.getServerIp() + "/" + ftpConfig.getUserName() + "/" + (ftpConfig.isSFTP() ? "sftp" : "ftp") + ")。"); + try { + return ftpTask.execute(ftp); + } finally { + ftp.disconnect(); + } + } + + //上传文件到Ftp服务器。传完后,根据设置删除本地文件 + public void uploadToFtp(final String remoteAttachName, + final String remoteFolderPath, final String localAttach, + final boolean isDelLocal) throws Exception { + uploadToFtp(remoteAttachName, remoteFolderPath, new File(localAttach), isDelLocal); + } + + public void uploadToFtp(final String remoteAttachName, + final String remoteFolderPath, final File localFile, + final boolean isDelLocal) throws Exception { + this.execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + if (ftp.uploadFile(remoteFolderPath, remoteAttachName, localFile)) { + if (isDelLocal) {//删除本地服务器的相应附件 + localFile.delete(); + } + } + return null; + } + }); + } + + private String getBakPath(String path) { + path = PubUtil.isEmpty(path) ? DateUtil.getNowYm() : path; + return "bak/" + path + "/"; + } + + //上传文件到Ftp服务器。传完后,根据设置删除本地文件 + public void downloadFile(final String remoteAttachName, + final String remoteFolderPath, final String localFile, final boolean isDelLocal) throws Exception { + this.execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + if (!ftp.existsFile(remoteFolderPath, remoteAttachName)) { + throw new Exception("服务器文件【" + remoteFolderPath + "/" + remoteAttachName + "】不存在!"); + } + ftp.downloadFileEx(remoteFolderPath, remoteAttachName, localFile); + if (isDelLocal) { + ftp.setRemoteDir("/"); + final String bakPath = getBakPath(null); + ftp.mkdir(remoteFolderPath + "/" + bakPath); + ftp.rename(remoteFolderPath, remoteAttachName, bakPath + remoteAttachName); + } + return null; + } + }); + } + + public void delAndBakFile(String remoteFolderPath, String remoteAttachName) throws Exception { + delAndBakFile(remoteFolderPath, remoteAttachName, null); + + } + + public void delAndBakFile(String remoteFolderPath, String remoteAttachName, String bakPath) throws Exception { + this.execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + if (!ftp.existsFile(remoteFolderPath, remoteAttachName)) return null; + + String path = getBakPath(bakPath); + ftp.setRemoteDir("/"); + ftp.mkdir(remoteFolderPath + "/" + path); + ftp.rename(remoteFolderPath, remoteAttachName, path + remoteAttachName); + + return null; + } + }); + } + public void delFile(String delPath, String fileName) throws Exception { + this.execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + if (!ftp.existsFile(delPath, fileName)) return null; + ftp.deleteFile(delPath,fileName ); + return null; + } + }); + } + //从服务器下载文件到本地。传完后,根据设置删除远程目录文件 + public String[] listFileNames(final String remotePath) throws Exception { + IFtpUtil ftp = getFtpUtil(); + if (!ftp.isConnected()) return new String[0]; + String[] fileNames; + try { + fileNames = ftp.listFileNames(remotePath); + } finally { + ftp.disconnect(); + } + return fileNames; + } + + public String[] downFolder(final String remotePath, final String localPath, final boolean isDelLocal, final IDownloadFileWorker worker, final String fileNamePrefix) throws Exception { + final String[] files = listFileNames(remotePath); + List list = new ArrayList<>(); + this.execute(new FtpTask() { + public Object execute(IFtpUtil ftp) throws Exception { + for (String file : files) { + if (worker != null && !worker.isDownload(file, fileNamePrefix)) continue; + if (PubUtil.isNotEmptyId(fileNamePrefix) && !file.startsWith(fileNamePrefix)) continue; + ftp.downloadFileEx(remotePath, file, localPath + "/" + file); + if (isDelLocal) { + ftp.setRemoteDir("/"); + final String bakPath = getBakPath(null); + ftp.mkdir(remotePath + "/" + bakPath); + ftp.rename(remotePath, file, bakPath + file); + } + list.add(file); + } + return null; + } + }); + return list.toArray(new String[list.size()]); + } + + public static void main(String[] args) throws Exception { + FtpTaskManager ftp = FtpTaskManager.getInstance("test", new IFtpServerConfig() { + @Override + public boolean isSFTP() { + return false; + } + + @Override + public String getServerIp() { + return "127.0.0.1"; + } + + @Override + public Integer getPort() { + return 21; + } + + @Override + public String getUserName() { + return "demo"; + } + + @Override + public String getPassword() { + return "1"; + } + }); + ftp.uploadToFtp("S_2.jpg", "/", "f:\\temp\\tmp\\S_2.jpg", false); +// ftp.uploadToFtp("民族5.png", "/", "f:\\temp\\temp\\民族5.png", false); +// ftp.getThreadFtpUtil(); +// ftp.uploadToFtp("民族1.png", "/", "f:\\temp\\temp\\民族1.png", false); + +// ftp.uploadToFtp("民族2.png", "/", "f:\\temp\\temp\\民族2.png", false); +// ftp.uploadToFtp("民族3.png", "/", "f:\\temp\\temp\\民族3.png", false); +// ftp.downloadFile("民族2.png", "/", "f:/temp/民族2.png", true); + /*String[] ss = ftp.downFolder("/", "f:/temp/test", true); + for (String s: ss) { + System.out.println(s); + }*/ + + ftp.downloadFile("S_1.jpg", "/", "f:/temp/S_21.jpg", true); +// ftp.downloadFile("freesshd.log", "/", "f:/temp/freesshd.log", false); + //ftp.downFolder("data/11", "f:/temp/11", true, ""); + + ftp.dispose(); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpUtil.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpUtil.java new file mode 100644 index 0000000..edeee96 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/FtpUtil.java @@ -0,0 +1,393 @@ +package cc.smtweb.system.bpm.util.ftp; + +import cc.smtweb.framework.core.util.PubUtil; +import cc.smtweb.system.bpm.util.UtilFile; +import cc.smtweb.system.bpm.util.UtilLogger; +import org.apache.commons.net.ftp.FTPClient; +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPReply; + +import java.io.*; +import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * 一个ftp的封装类 + */ +@SuppressWarnings("UnusedDeclaration") +public class FtpUtil implements IFtpUtil { + private static final int LOGIN_REPEAT_TIMES = 1; + private FTPClient ftpClient; + private boolean autoFree = true; + private IFtpServerConfig ftpConf; + + public FtpUtil() { + this.ftpClient = new FTPClient(); + } + + @Override + public boolean isAutoFree() { + return autoFree; + } + + @Override + public void setAutoFree(boolean autoFree) { + this.autoFree = autoFree; + } + + //登录ftp + @Override + public boolean login(IFtpServerConfig ftpConf) { + try { + this.ftpConf = ftpConf; + return login(ftpConf.getServerIp(), ftpConf.getPort(), ftpConf.getUserName(), ftpConf.getPassword()); + } catch (Exception e) { + logError("ftp登录失败", e); + return false; + } + } + + //退出ftp + @Override + public void logout() { + try { + if (ftpClient.isConnected()) { + ftpClient.logout(); + } + } catch (IOException e) { + logError("ftp退出登录失败", e); + } + } + + //是否连接正常 + @Override + public boolean isConnected() { + if (!ftpClient.isConnected()) + return false; + try { + return ftpClient.sendNoOp(); + } catch (IOException e) { + logError("ftp测试连接失败", e); + return false; + } + } + + //设置远程目录 + @Override + public boolean setRemoteDir(String path) { + try { + String d = gbktoiso8859(path); + ftpClient.changeWorkingDirectory("/"); + if (!ftpClient.changeWorkingDirectory(d)) { + String[] paths = d.split("/"); + for (String pa : paths) { + if (!ftpClient.changeWorkingDirectory(pa)) { + ftpClient.mkd(pa); + ftpClient.changeWorkingDirectory(pa); + } + } + } + return true; + } catch (IOException e) { + logError("ftp设置远程目录失败", e); + return false; + } + } + + /** + * 创建指定文件夹 + * + * @param dirName dirName + */ + public void mkdir(String dirName) { + setRemoteDir("/"); + dirName = gbktoiso8859(dirName); + + try { + ftpClient.makeDirectory(dirName); + } catch (Exception e) { + logError("ftp创建远程目录错误", e); + } + } + + //删除远程路径 + @Override + public void deleteFolder(String path) { + try { + String d = gbktoiso8859(path); + ftpClient.removeDirectory(d); + } catch (IOException e) { + logError("ftp删除远程目录失败", e); + } + } + + /** + * 从ftp下载文件到本地 + * + * @param remotePath 远程路径 + * @param fileName 文件名 + * @param localPath 本地路径(不带文件名) + */ + @Override + public void downloadFile(String remotePath, String fileName, String localPath) throws Exception { + downloadFileEx(remotePath, fileName, localPath + File.separator + fileName); + } + + public void setPassiveNatWorkaroundStrategy() { + ftpClient.setPassiveNatWorkaroundStrategy(new FTPClient.HostnameResolver() { + @Override + public String resolve(String hostname) throws UnknownHostException { + return ftpConf.getServerIp(); + } + }); + } + + /** + * 下载文件到本地 + * + * @param remotePath 远程路径 + * @param fileName 远程文件名 + * @param localFileName 本地完全文件名(路径+文件名) + */ + @Override + public void downloadFileEx(String remotePath, String fileName, String localFileName) throws Exception { + setPassiveNatWorkaroundStrategy(); + ftpClient.enterLocalPassiveMode(); + setRemoteDir(remotePath);//转移到FTP服务器目录 + UtilLogger.info("跳转到FTP服务目录:" + remotePath); + File localFile = new File(localFileName); + if (!localFile.exists()) UtilFile.CreateFile(localFileName); + FileOutputStream is = null; + try { + is = new FileOutputStream(localFile); + ftpClient.retrieveFile(gbktoiso8859(fileName), is); + } catch (IOException e) { + localFile.deleteOnExit(); + } finally { + is.close(); + } + } + + /** + * 下载文件成流,使用此方法需要注意,关闭流之后要调用completePendingCommand方法 + * + * @param remotePath 远程路径 + * @param fileName 远程文件名 + * @return 文件流 + */ + @Override + public InputStream downloadFile(String remotePath, String fileName) throws Exception { + try { + setPassiveNatWorkaroundStrategy(); + ftpClient.enterLocalPassiveMode(); + setRemoteDir(remotePath);//转移到FTP服务器目录 + return ftpClient.retrieveFileStream(gbktoiso8859(fileName)); + } catch (IOException e) { + logError("ftp下载文件失败", e); + return null; + } + } + + /** + * 上传文件到ftp + * + * @param path 远程路径 + * @param filename 远程文件名 + * @param localFileName 本地文件(含路径) + * @return + */ + @Override + public boolean uploadFile(String path, String filename, String localFileName) throws Exception { + return uploadFile(path, filename, new File(localFileName)); + } + + @Override + public boolean uploadFile(String path, String filename, File localFile) throws Exception { + FileInputStream in = null; + try { + setPassiveNatWorkaroundStrategy(); + ftpClient.enterLocalPassiveMode(); + in = new FileInputStream(localFile); + setRemoteDir(path); + boolean b = ftpClient.storeFile(gbktoiso8859(filename), in); + if (!b) throw new Exception("FTP上传失败,请检查服务器配置!"); + return b; + } finally { + if (in != null) in.close(); + } + } + + /** + * 删除远程文件 + * + * @param path 远程路径 + * @param filename 远程文件名 + */ + @Override + public void deleteFile(String path, String filename) { + try { + setPassiveNatWorkaroundStrategy(); + setRemoteDir(path); + ftpClient.dele(gbktoiso8859(filename)); + } catch (IOException e) { + logError("删除文件失败", e); + } + } + + @Override + public boolean existsFile(String path, String filename) { + try { + setPassiveNatWorkaroundStrategy(); + ftpClient.enterLocalPassiveMode();//设置被动模式 + setRemoteDir(path); + String[] files = ftpClient.listNames(gbktoiso8859(filename)); + return PubUtil.isNotEmpty(files); + } catch (IOException e) { + logError("判断文件是否存在失败", e); + return false; + } + } + + @Override + public boolean rename(String path, String from, String to) { + try { + setPassiveNatWorkaroundStrategy(); + setRemoteDir(path); + return ftpClient.rename(gbktoiso8859(from), gbktoiso8859(to)); + } catch (IOException e) { + logError("重命名文件失败", e); + return false; + } + } + + //调用返回流的方法,在处理完流后,要调用此方法。 + @Override + public boolean completePendingCommand() { + try { + setPassiveNatWorkaroundStrategy(); + return ftpClient.completePendingCommand(); + } catch (IOException e) { + UtilLogger.error("ftp关闭流出错", e); + return false; + } + } + + //断开连接 + public FTPFile[] listFiles(String remotePath) throws IOException { + setPassiveNatWorkaroundStrategy(); + return ftpClient.listFiles(remotePath); + } + + //断开连接 + @Override + public String[] listFileNames(String remotePath) throws Exception { + setPassiveNatWorkaroundStrategy(); + setRemoteDir("/"); + setRemoteDir(remotePath); + ftpClient.enterLocalPassiveMode();//设置被动模式 + String[] files = ftpClient.listNames(""); + List list = new ArrayList<>(); + for (String s : files) { + if (!ftpClient.changeWorkingDirectory(s)) { + s = new String(s.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); + list.add(s); + } else { + ftpClient.changeToParentDirectory(); + } + } + return list.toArray(new String[list.size()]); + } + + //断开连接 + @Override + public String[] listAllFileNames(String remotePath) throws Exception { + setPassiveNatWorkaroundStrategy(); + setRemoteDir("/"); + setRemoteDir(remotePath); + ftpClient.enterLocalPassiveMode();//设置被动模式 + String[] files = ftpClient.listNames(""); + List list = new ArrayList<>(); + for (String s : files) { + s = new String(s.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); + list.add(s); + } + return list.toArray(new String[list.size()]); + } + + + //断开连接 + @Override + public void disconnect() { + if (isAutoFree() && ftpClient.isConnected()) { + try { + setPassiveNatWorkaroundStrategy(); + ftpClient.disconnect(); + } catch (IOException ignored) { + } + } + } + + //登录 + protected boolean login(String server, int port, String user, String password) throws Exception { + for (int i = 0; i < LOGIN_REPEAT_TIMES; i++) { + ftpClient.setConnectTimeout(10000); + //if (!ftpClient.isConnected()) { + connect(server, port); + if (!ftpClient.isConnected()) continue; + //} + if (ftpClient.login(user, password)) { + ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); + ftpClient.setDataTimeout(120000); + return true; + } + ftpClient.logout(); + Thread.sleep(100L); + } + disconnect(); + return false; + } + + //连接 + private void connect(String server, int port) throws Exception { + disconnect(); + ftpClient.setDefaultPort(port); + ftpClient.connect(server); + int reply = ftpClient.getReplyCode(); + if (!FTPReply.isPositiveCompletion(reply)) { + ftpClient.disconnect(); + throw new Exception("服务器拒绝连接。"); + } + } + + private void logError(String msg, Exception e) { + UtilLogger.debug(msg + " " + e.getMessage()); + } + + //编码转换 + private static String gbktoiso8859(String gbk) { + try { + if (gbk == null) + return ""; + else //iso-8859-1 + return new String(gbk.getBytes("GBK"), StandardCharsets.ISO_8859_1); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + //编码转换 + private static String iso8859toutf8(String gbk) { + try { + if (gbk == null) + return ""; + else //iso-8859-1 + return new String(gbk.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IDownloadFileWorker.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IDownloadFileWorker.java new file mode 100644 index 0000000..5a86260 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IDownloadFileWorker.java @@ -0,0 +1,6 @@ +package cc.smtweb.system.bpm.util.ftp; + +public interface IDownloadFileWorker { + + boolean isDownload(String file, String fileNamePrefix); +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IFtpServerConfig.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IFtpServerConfig.java new file mode 100644 index 0000000..28a2ec8 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IFtpServerConfig.java @@ -0,0 +1,16 @@ +package cc.smtweb.system.bpm.util.ftp; + +/** + * Created by AKmm at 2009-5-21 16:41:25 + * ftp服务器参数配置接口 + */ +public interface IFtpServerConfig { + boolean isSFTP(); + String getServerIp(); + + Integer getPort(); + + String getUserName(); + + String getPassword(); +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IFtpUtil.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IFtpUtil.java new file mode 100644 index 0000000..cfd4459 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/IFtpUtil.java @@ -0,0 +1,59 @@ +package cc.smtweb.system.bpm.util.ftp; + +import java.io.File; +import java.io.InputStream; + +/** + * Created by Akmm at 2015-12-08 14:33 + */ +public interface IFtpUtil { + //是否自动删除 + boolean isAutoFree(); + //设置自动删除 + void setAutoFree(boolean autoFree); + //登录ftp + boolean login(IFtpServerConfig ftpConf); + //退出ftp + void logout(); + + //是否连接正常 + boolean isConnected(); + + //设置远程目录 + boolean setRemoteDir(String path); + void mkdir(String dirName); + + //删除远程路径 + void deleteFolder(String path); + + void downloadFile(String remotePath, String fileName, String localPath) throws Exception; + + void downloadFileEx(String remotePath, String fileName, String localFileName) throws Exception; + + InputStream downloadFile(String remotePath, String fileName) throws Exception; + + boolean uploadFile(String path, String filename, String localFileName) throws Exception; + + boolean uploadFile(String path, String filename, File localFile) throws Exception; + + void deleteFile(String path, String filename); + //判断文件是否存在 + boolean existsFile(String path, String filename); + + //调用返回流的方法,在处理完流后,要调用此方法。 + boolean completePendingCommand(); + + //断开连接 +// FTPFile[] listFiles(String remotePath) throws IOException; + + //枚举文件名 + String[] listFileNames(String remotePath) throws Exception; + + //枚举文件名,包含文件夹 + String[] listAllFileNames(String remotePath) throws Exception; + + //断开连接 + void disconnect(); + + boolean rename(String remotePath, String from, String to) throws Exception; +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/SFtpUtil.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/SFtpUtil.java new file mode 100644 index 0000000..cc1873f --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/util/ftp/SFtpUtil.java @@ -0,0 +1,396 @@ +package cc.smtweb.system.bpm.util.ftp; + +import cc.smtweb.framework.core.util.PubUtil; +import cc.smtweb.system.bpm.util.UtilFile; +import cc.smtweb.system.bpm.util.UtilLogger; +import com.jcraft.jsch.*; +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * 一个sftp的封装类 + */ +@SuppressWarnings("UnusedDeclaration") +public class SFtpUtil implements IFtpUtil { + private static final int LOGIN_REPEAT_TIMES = 1; + private ChannelSftp sftp; + private boolean autoFree = true; + + public SFtpUtil() { + this.sftp = null; + } + + @Override + public boolean isAutoFree() { + return autoFree; + } + + @Override + public void setAutoFree(boolean autoFree) { + this.autoFree = autoFree; + } + + //登录ftp + @Override + public boolean login(IFtpServerConfig ftpConf) { + try { + int count = 0; + while (count < 3) { + // 设置超时时间为 5s + count++; + try { + JSch jsch = new JSch(); + jsch.getSession(ftpConf.getUserName(), ftpConf.getServerIp(), ftpConf.getPort()); + Session sshSession = jsch.getSession(ftpConf.getUserName(), ftpConf.getServerIp(), ftpConf.getPort()); + System.out.println("Session created."); + sshSession.setPassword(ftpConf.getPassword()); + Properties sshConfig = new Properties(); + sshConfig.put("StrictHostKeyChecking", "no"); + sshSession.setConfig(sshConfig); + sshSession.setTimeout(10 * 1000); + sshSession.connect(); + UtilLogger.debug("Session connected[" + count + "/3]."); + UtilLogger.debug("Opening Channel[" + count + "/3]."); + Channel channel = sshSession.openChannel("sftp"); + channel.connect(); + sftp = (ChannelSftp) channel; + UtilLogger.debug("已连接到 " + ftpConf.getServerIp() + ";"); + return true; + } catch (Exception e) { + UtilLogger.debug("connect fail[" + count + "/3]:" + PubUtil.getOrigMsg(e)); + } + } + UtilLogger.debug("sftp登录失败:3次连接超时..."); + return false; + } catch (Exception e) { + logError("sftp登录失败", e); + return false; + } + } + + //退出ftp + @Override + public void logout() { + disconnect(); + } + + //是否连接正常 + @Override + public boolean isConnected() { + return sftp != null && sftp.isConnected(); + /*try { + return sftpClient.sendSignal(); + } catch (IOException e) { + logError("ftp测试连接失败", e); + return false; + }*/ + } + + //设置远程目录 + @Override + public boolean setRemoteDir(String path) { + String d = path; + try { + sftp.cd("/"); + sftp.cd(d); + return true; + } catch (Exception e) { + logError("sftp进远程目录失败[" + d + "],准备创建", e); + } + + mkdir(d); + try { + sftp.cd(d); + return true; + } catch (Exception e) { + logError("sftp设置远程目录失败[" + d + "]", e); + return false; + } + } + + + private boolean openRemoteDir(String path) { + String d = path; + try { + sftp.cd(d); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * 创建指定文件夹 + * + * @param dirName dirName + */ + public void mkdir(String dirName) { + String[] dirs = dirName.split("/"); + try { + String now = sftp.pwd(); + for (int i = 0; i < dirs.length; i++) { + if (PubUtil.isEmpty(dirs[i])) continue; + boolean dirExists = openRemoteDir(dirs[i]); + if (!dirExists) { + sftp.mkdir(dirs[i]); + sftp.cd(dirs[i]); + } + } + sftp.cd(now); + } catch (SftpException e) { + logError("sftp创建远程目录错误", e); + } + } + + //删除远程路径 + @Override + public void deleteFolder(String path) { + try { + String d = path; + sftp.rmdir(d); + } catch (Exception e) { + logError("sftp删除远程目录失败", e); + } + } + + /** + * 从ftp下载文件到本地 + * + * @param remotePath 远程路径 + * @param fileName 文件名 + * @param localPath 本地路径(不带文件名) + */ + @Override + public void downloadFile(String remotePath, String fileName, String localPath) throws Exception { + downloadFileEx(remotePath, fileName, localPath + File.separator + fileName); + } + + public boolean isFileExists(String filePath, String fileName) throws Exception { + Vector vector = sftp.ls(filePath); + Iterator sftpFileNames = vector.iterator(); + while (sftpFileNames.hasNext()) { + String name = sftpFileNames.next().getFilename(); + if (name.equals(fileName)) { + return true; + } + } + return false; + } + + /** + * 下载文件到本地 + * + * @param remotePath 远程路径 + * @param fileName 远程文件名 + * @param localFileName 本地完全文件名(路径+文件名) + */ + @Override + public void downloadFileEx(String remotePath, String fileName, String localFileName) throws Exception { + if (!isFileExists(remotePath, fileName)) { + throw new Exception(); + } + File file = null; + file = new File(localFileName); + if (!file.exists()) UtilFile.CreateFile(localFileName); + FileOutputStream output = null; + + try { + String now = sftp.pwd(); + sftp.cd(remotePath); + UtilLogger.info("跳转到SFTP服务目录:" + remotePath); + + output = new FileOutputStream(file); + sftp.get(fileName, output); + sftp.cd(now); + } catch (Exception e) { + file.deleteOnExit(); + throw e; + } finally { + IOUtils.closeQuietly(output); + } + } + + /** + * 下载文件成流,使用此方法需要注意,关闭流之后要调用completePendingCommand方法 + * + * @param remotePath 远程路径 + * @param fileName 远程文件名 + * @return 文件流 + */ + @Override + public InputStream downloadFile(String remotePath, String fileName) throws Exception { + String now = sftp.pwd(); + sftp.cd(remotePath); + //setRemoteDir(remotePath);//转移到FTP服务器目录 暂时注释 拷贝错误 + InputStream is = sftp.get(fileName); + sftp.cd(now); + return is; + + } + + /** + * 上传文件到ftp + * + * @param path 远程路径 + * @param filename 远程文件名 + * @param localFileName 本地文件(含路径) + * @return + */ + @Override + public boolean uploadFile(String path, String filename, String localFileName) throws Exception { + return uploadFile(path, filename, new File(localFileName)); + } + + @Override + public boolean uploadFile(String path, String filename, File localFile) throws Exception { + FileInputStream is = null; + try { + String now = sftp.pwd(); + setRemoteDir(path); + is = new FileInputStream(localFile); + try { + sftp.put(is, filename); + } finally { + IOUtils.closeQuietly(is); + } + sftp.cd(now); + if (!existsFile(path, filename)) { + throw new Exception("SFTP上传失败,请检查服务器配置!"); + } + return true; + } finally { + if (is != null) is.close(); + } + } + + /** + * 删除远程文件 + * + * @param path 远程路径 + * @param filename 远程文件名 + */ + @Override + public void deleteFile(String path, String filename) { + try { + String now = sftp.pwd(); + setRemoteDir(path); + sftp.rm(filename); + sftp.cd(now); + } catch (Exception e) { + logError("删除文件失败", e); + } + } + + @Override + public boolean rename(String path, String from, String to) throws Exception { + try { + String now = sftp.pwd(); + setRemoteDir(path); + sftp.rename(from, to); + sftp.cd(now); + return true; + } catch (Exception e) { + logError("重命名文件失败", e); + return false; + } + } + + //调用返回流的方法,在处理完流后,要调用此方法。 + @Override + public boolean completePendingCommand() { + return true; + } + + //断开连接 + @Override + public String[] listFileNames(String remotePath) throws Exception { + List list = new ArrayList<>(); + Vector sftpFile = sftp.ls(remotePath); + ChannelSftp.LsEntry isEntity = null; + String fileName = null; + Iterator sftpFileNames = sftpFile.iterator(); + while (sftpFileNames.hasNext()) { + isEntity = sftpFileNames.next(); + if (!isEntity.getAttrs().isDir()) { + fileName = isEntity.getFilename(); + + list.add(fileName); + } + } + return list.toArray(new String[list.size()]); + } + + //断开连接 + @Override + public String[] listAllFileNames(String remotePath) throws Exception { + List list = new ArrayList<>(); + Vector sftpFile = sftp.ls(remotePath); + ChannelSftp.LsEntry isEntity = null; + String fileName = null; + Iterator sftpFileNames = sftpFile.iterator(); + while (sftpFileNames.hasNext()) { + isEntity = sftpFileNames.next(); + fileName = isEntity.getFilename(); + list.add(fileName); + } + return list.toArray(new String[list.size()]); + } + + + //断开连接 + @Override + public void disconnect() { + if (sftp != null && isAutoFree() && sftp.isConnected()) { + try { + if (sftp.getSession() != null) { + UtilLogger.debug("关闭连接 " + sftp.getSession().getHost() + ";"); + sftp.getSession().disconnect(); + UtilLogger.debug("Session disconnect."); + } + } catch (JSchException e) { + logError("关闭失败!", e); + } + sftp.quit(); + sftp.disconnect(); + UtilLogger.debug("Channel closed."); + sftp = null; + } + } + + private void logError(String msg, Exception e) { + UtilLogger.debug(msg + ":" + e.getMessage()); + } + + //编码转换 + private static String gbktoiso8859(String gbk) { + try { + if (gbk == null) + return ""; + else //iso-8859-1 + return new String(gbk.getBytes("GBK"), StandardCharsets.ISO_8859_1); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + @Override + public boolean existsFile(String path, String filename) { + try { + String now = sftp.pwd(); + setRemoteDir(path); + Vector files = sftp.ls(filename); + sftp.cd(now); + return PubUtil.isNotEmpty(files); + } catch (SftpException e) { + logError("判断文件是否存在失败", e); + return false; + } + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/attach/AttachInfo.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/attach/AttachInfo.java index 83c79ec..421d27a 100644 --- a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/attach/AttachInfo.java +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/attach/AttachInfo.java @@ -62,12 +62,12 @@ public class AttachInfo extends DefaultEntity { put("attach_path", attach_path); } /** 附件类别 */ - public int getType() { - return getInt("attach_type"); + public String getType() { + return getStr("attach_type"); } /** 附件类别 */ - public void setType(int attach_type) { + public void setType(String attach_type) { put("attach_type", attach_type); } /** 附件大小 */ @@ -115,4 +115,14 @@ public class AttachInfo extends DefaultEntity { public void setUserId(long attach_user_id) { put("attach_user_id", attach_user_id); } + + /** 下载次数 */ + public int getCount() { + return getInt("attach_count"); + } + + /** 下载次数 */ + public void setCount(int attach_count) { + put("attach_count", attach_count); + } } diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/attachFolder/pojo/AttachFolderPojo.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/attachFolder/pojo/AttachFolderPojo.java new file mode 100644 index 0000000..a0b9187 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/attachFolder/pojo/AttachFolderPojo.java @@ -0,0 +1,16 @@ +package cc.smtweb.system.bpm.web.sys.base.attachFolder.pojo; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class AttachFolderPojo implements Serializable { + private static final long serialVersionUID = 1L; + private Long folderId;// + private String folderAttachPath;// + private String folderPeriod;// + private int folderMaxSeq;// + private Long folderFileCount;// +} + diff --git a/smtweb-framework/bpm/src/main/resources/config/application.yaml b/smtweb-framework/bpm/src/main/resources/config/application.yaml index be65cfd..5c15030 100644 --- a/smtweb-framework/bpm/src/main/resources/config/application.yaml +++ b/smtweb-framework/bpm/src/main/resources/config/application.yaml @@ -3,6 +3,22 @@ smtweb: file: local-path: /data/sw/files/ url: http://127.0.0.1:8888/sw/files/ + #访问路径,需/结尾 + attach-http-path: 'http://bjjt.jujiatech.cn/files/' + #此配置原则上可以和local-path一致,可本机路径可ftp附件路径,需/结尾 + attach-path: /jjkj/attach/ + #临时文件路径,需/结尾 + attach-temp-path: /jujia/tomcat_api/webapps/files/tempFile/ + #附件上传方式 sftp/ftp/local + attach-type: sftp + #ftp IP地址 + attach-ftp-ip: 172.26.60.191 + #ftp 端口 + attach-ftp-port: 22 + #ftp 用户名 + attach-ftp-user: gzhfile + #ftp 密码 + attach-ftp-pwd: Bjjt@2021 bpm: debug: true # 有.idea或pom.xml文件的目录 diff --git a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/db/dao/AbstractEntityDao.java b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/db/dao/AbstractEntityDao.java index 6980fb4..79f15cb 100644 --- a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/db/dao/AbstractEntityDao.java +++ b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/db/dao/AbstractEntityDao.java @@ -14,6 +14,8 @@ import cc.smtweb.framework.core.exception.DbException; import cc.smtweb.framework.core.util.DateUtil; import cc.smtweb.framework.core.util.SpringUtil; import cc.smtweb.framework.core.util.VariableUtil; +import com.esotericsoftware.minlog.Log; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ClassUtils; @@ -31,6 +33,7 @@ import java.util.Map; * * @param 数据库值对象类型 */ +@Slf4j public abstract class AbstractEntityDao { protected ModelTable modelTable; protected String tableName; @@ -62,6 +65,9 @@ public abstract class AbstractEntityDao { tableName = table.value(); modelTable = ModelTableCache.getInstance().getByName(tableName); + if(null == modelTable){ + log.error("未找到缓存表结构:"+tableName); + } if (DefaultEntity.class.isAssignableFrom(type)) { for (ModelField field : modelTable.getFields()) { add(field, null, null); diff --git a/smtweb-framework/pom.xml b/smtweb-framework/pom.xml index 38a69dc..99edd0c 100644 --- a/smtweb-framework/pom.xml +++ b/smtweb-framework/pom.xml @@ -27,5 +27,6 @@ core bpm + unit