@@ -129,6 +129,38 @@ | |||
<artifactId>spring-boot-starter-test</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.aliyun</groupId> | |||
<artifactId>aliyun-java-sdk-core</artifactId> | |||
<version>4.0.6</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>commons-net</groupId> | |||
<artifactId>commons-net</artifactId> | |||
<version>3.6</version> | |||
<scope>compile</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jcraft</groupId> | |||
<artifactId>jsch</artifactId> | |||
<version>0.1.53</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>commons-fileupload</groupId> | |||
<artifactId>commons-fileupload</artifactId> | |||
<version>1.4</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>commons-io</groupId> | |||
<artifactId>commons-io</artifactId> | |||
<version>2.11.0</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.apache.httpcomponents</groupId> | |||
<artifactId>httpclient</artifactId> | |||
<version>4.5.7</version> | |||
</dependency> | |||
</dependencies> | |||
<build> | |||
@@ -176,22 +208,22 @@ | |||
<resources> | |||
<!-- 界面设计器 --> | |||
<resource> | |||
<directory>E:/WORKSPACE/JJKJ-GIT/CODE/smtweb/sw-ui-design-vue/dist/</directory> | |||
<directory>E:/jujia/source/sw-ui-design-vue/dist/</directory> | |||
<targetPath>${basedir}/target/classes/static/design/ui</targetPath> | |||
</resource> | |||
<!-- DB设计器 --> | |||
<resource> | |||
<directory>E:/WORKSPACE/JJKJ-GIT/CODE/smtweb/sw-db-design-vue/dist/</directory> | |||
<directory>E:/jujia/source/sw-db-design-vue/dist/</directory> | |||
<targetPath>${basedir}/target/classes/static/design/db</targetPath> | |||
</resource> | |||
<!-- 流程设计器 --> | |||
<resource> | |||
<directory>E:/WORKSPACE/JJKJ-GIT/CODE/smtweb/sw-flow-design-vue/dist/</directory> | |||
<directory>E:/jujia/source/sw-flow-design-vue/dist/</directory> | |||
<targetPath>${basedir}/target/classes/static/design/flow</targetPath> | |||
</resource> | |||
<!-- 预览脚手架 --> | |||
<resource> | |||
<directory>E:/WORKSPACE/JJKJ-GIT/CODE/smtweb/sw-framework-widget-vue/dist/</directory> | |||
<directory>E:/jujia/source/sw-framework-widget-vue/dist/</directory> | |||
<targetPath>${basedir}/target/classes/static/design/preview</targetPath> | |||
</resource> | |||
<!-- 设定主资源目录,入口跳转页等 --> | |||
@@ -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); | |||
} | |||
} |
@@ -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<String> 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<String, Object> 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<String, Object> 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<String, String> 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("删除附件失败"); | |||
} | |||
} | |||
} |
@@ -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<AttachFolder> 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); | |||
} | |||
} |
@@ -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<String> getAttachListFromFtp(final List<AttachInfo> attachlist, final String ownerType, final String localRoot) throws Exception { | |||
final List<String> 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); | |||
} | |||
} |
@@ -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<String> getAttachListFromFtp(final List<AttachInfo> attachlist, final String ownerType, final String localRoot) throws Exception { | |||
final List<String> files = new ArrayList<String>(); | |||
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的还没用到,没开发,暂不支持"); | |||
} | |||
} |
@@ -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<AttachInfo> getAttachListByOwnerId(String ownerId) throws Exception { | |||
return dbEngine.query("select * from "+AttachInfo.ENTITY_NAME+" where attach_owner_id=? ",AttachInfo.class,ownerId); | |||
} | |||
public List<AttachInfo> 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<AttachInfo> list = listAttachListByOwnerIdAndType(ownerId, attachType); | |||
return deleteAttachListEx(list); | |||
} | |||
public boolean deleteAttachByOwnerId(String ownerId) throws Exception { | |||
final List<AttachInfo> list = getAttachListByOwnerId(ownerId); | |||
return deleteAttachListEx(list); | |||
} | |||
//批量删除 | |||
public boolean deleteAttachList(List<String> 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<AttachInfo> 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<String> getAttachListFromFtp(final List<AttachInfo> attachlist, final String ownerType) throws Exception { | |||
return attachUtil.getAttachListFromFtp(attachlist, ownerType, getAttachTmpPath()); | |||
} | |||
/** | |||
* 下载附件 | |||
* | |||
* @param ownerId 附件拥有者id | |||
* @param ownerType 附件类别 | |||
* @return 返回文件名列表,本地有此文件将不再下载 | |||
* @throws Exception | |||
*/ | |||
public List<String> getAttachsFromFtp(final String ownerId, final String ownerType) throws Exception { | |||
final List<AttachInfo> attachlist = getAttachListByOwnerId(ownerId); | |||
return getAttachListFromFtp(attachlist, ownerType); | |||
} | |||
/** | |||
* 下载附件 | |||
* | |||
* @param attachIds 附件id | |||
* @param ownerType 附件类别 | |||
* @return 返回文件名列表,本地有此文件将不再下载 | |||
* @throws Exception | |||
*/ | |||
public List<String> getAttachsFromFtp(final List<String> attachIds, final String ownerType) throws Exception { | |||
List<Object> paras = new ArrayList<Object>(); | |||
if (PubUtil.isNotEmpty(attachIds)) { | |||
StringBuilder sb = new StringBuilder(128); | |||
for(int i=0;i<attachIds.size();i++){ | |||
if(i==0){ | |||
sb.append(" attach_id=? "); | |||
}else{ | |||
sb.append(" or attach_id=? "); | |||
} | |||
paras.add(attachIds.get(i)); | |||
} | |||
final List<AttachInfo> 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<String, String> 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()+""; | |||
} | |||
} |
@@ -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<String> getAttachListFromFtp(final List<AttachInfo> 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); | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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<String> getAttachListFromFtp(List<AttachInfo> attachlist, String ownerType, String localRoot) throws Exception; | |||
void makeRemoteDir(String path) throws Exception; | |||
/** | |||
* 获取文件路径 | |||
* | |||
*/ | |||
Path getAttachPath(String remotePath, String remoteName); | |||
} |
@@ -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();//附件上传方式初始化 | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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<String> 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<String> split(String str, String delim) { | |||
List<String> 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<String, String> 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); | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
package cc.smtweb.system.bpm.util.ftp; | |||
//FTP执行接口 | |||
public interface FtpTask { | |||
Object execute(IFtpUtil ftp) throws Exception; | |||
} |
@@ -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<String, FtpTaskManager> mapInstance = null; | |||
static { | |||
mapInstance = new HashMap<>(); | |||
} | |||
//多线程 | |||
private Map<Thread, IFtpUtil> 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<String> 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(); | |||
} | |||
} |
@@ -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<String> 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<String> 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 ""; | |||
} | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
package cc.smtweb.system.bpm.util.ftp; | |||
public interface IDownloadFileWorker { | |||
boolean isDownload(String file, String fileNamePrefix); | |||
} |
@@ -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(); | |||
} |
@@ -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; | |||
} |
@@ -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<ChannelSftp.LsEntry> vector = sftp.ls(filePath); | |||
Iterator<ChannelSftp.LsEntry> 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<String> list = new ArrayList<>(); | |||
Vector<ChannelSftp.LsEntry> sftpFile = sftp.ls(remotePath); | |||
ChannelSftp.LsEntry isEntity = null; | |||
String fileName = null; | |||
Iterator<ChannelSftp.LsEntry> 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<String> list = new ArrayList<>(); | |||
Vector<ChannelSftp.LsEntry> sftpFile = sftp.ls(remotePath); | |||
ChannelSftp.LsEntry isEntity = null; | |||
String fileName = null; | |||
Iterator<ChannelSftp.LsEntry> 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<ChannelSftp.LsEntry> files = sftp.ls(filename); | |||
sftp.cd(now); | |||
return PubUtil.isNotEmpty(files); | |||
} catch (SftpException e) { | |||
logError("判断文件是否存在失败", e); | |||
return false; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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;// | |||
} | |||
@@ -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文件的目录 | |||
@@ -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 <T> 数据库值对象类型 | |||
*/ | |||
@Slf4j | |||
public abstract class AbstractEntityDao<T> { | |||
protected ModelTable modelTable; | |||
protected String tableName; | |||
@@ -62,6 +65,9 @@ public abstract class AbstractEntityDao<T> { | |||
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); | |||
@@ -27,5 +27,6 @@ | |||
<modules> | |||
<module>core</module> | |||
<module>bpm</module> | |||
<module>unit</module> | |||
</modules> | |||
</project> |