Просмотр исходного кода

im消息添加文件上传下载功能

fancy 5 лет назад
Родитель
Сommit
92151a2cf2
13 измененных файлов с 633 добавлено и 2 удалено
  1. 1 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/entity/StorageType.java
  2. 1 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_message_assemble_communicate.java
  3. 83 0
      o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ActionFileDownload.java
  4. 111 0
      o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ActionImageDownloadWidthHeight.java
  5. 76 0
      o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ActionUploadFile.java
  6. 12 0
      o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionAllocateStorageMaaping.java
  7. 13 0
      o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionAttachmentNone.java
  8. 17 0
      o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionEmptyExtension.java
  9. 15 0
      o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionFileNotExist.java
  10. 12 0
      o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionStorageNotExist.java
  11. 61 0
      o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ImAction.java
  12. 228 0
      o2server/x_message_core_entity/src/main/java/com/x/message/core/entity/IMMsgFile.java
  13. 3 0
      o2server/x_message_core_entity/src/main/java/com/x/message/core/entity/PersistenceProperties.java

+ 1 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/entity/StorageType.java

@@ -1,6 +1,6 @@
 package com.x.base.core.entity;
 package com.x.base.core.entity;
 
 
 public enum StorageType {
 public enum StorageType {
-	file, processPlatform, mind, meeting, calendar, okr, cms, bbs, report, strategyDeploy, teamwork, structure;
+	file, processPlatform, mind, meeting, calendar, okr, cms, bbs, report, strategyDeploy, teamwork, structure, im;
 	public static final int length = JpaObject.length_32B;
 	public static final int length = JpaObject.length_32B;
 }
 }

+ 1 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_message_assemble_communicate.java

@@ -8,7 +8,7 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.message.core.entity.Instant", "com.x.message.core.entity.Message",
 		"com.x.message.core.entity.Instant", "com.x.message.core.entity.Message",
 		"com.x.message.core.entity.Mass", "com.x.message.core.entity.Org",
 		"com.x.message.core.entity.Mass", "com.x.message.core.entity.Org",
 		"com.x.message.core.entity.IMMsg", "com.x.message.core.entity.IMConversation",
 		"com.x.message.core.entity.IMMsg", "com.x.message.core.entity.IMConversation",
-		"com.x.message.core.entity.IMConversationExt" }, storeJars = { "x_message_core_entity", "x_meeting_core_entity",
+		"com.x.message.core.entity.IMConversationExt", "com.x.message.core.entity.IMMsgFile" }, storeJars = { "x_message_core_entity", "x_meeting_core_entity",
 				"x_processplatform_core_entity", "x_organization_core_express" })
 				"x_processplatform_core_entity", "x_organization_core_express" })
 public class x_message_assemble_communicate extends Deployable {
 public class x_message_assemble_communicate extends Deployable {
 }
 }

+ 83 - 0
o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ActionFileDownload.java

@@ -0,0 +1,83 @@
+package com.x.message.assemble.communicate.jaxrs.im;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.project.cache.ApplicationCache;
+import com.x.base.core.project.config.StorageMapping;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WoFile;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.message.assemble.communicate.ThisApplication;
+import com.x.message.core.entity.IMMsgFile;
+import net.sf.ehcache.Ehcache;
+import net.sf.ehcache.Element;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Created by fancyLou on 2020-06-15.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+public class ActionFileDownload extends BaseAction  {
+
+    private static Logger logger = LoggerFactory.getLogger( ActionFileDownload.class );
+
+    private Ehcache cache = ApplicationCache.instance().getCache(ActionFileDownload.class);
+
+    ActionResult<Wo> execute(EffectivePerson effectivePerson, String id) throws Exception {
+        try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+            ActionResult<Wo> result = new ActionResult<>();
+            Wo wo = null;
+            /** 确定是否要用application/octet-stream输出 */
+            IMMsgFile file = emc.find(id, IMMsgFile.class);
+            if (null == file) {
+                throw new ExceptionFileNotExist(id);
+            }
+
+
+            String cacheKey = ApplicationCache.concreteCacheKey(this.getClass(), id);
+            Element element = cache.get(cacheKey);
+            if ((null != element) && (null != element.getObjectValue())) {
+                wo = (Wo) element.getObjectValue();
+            } else {
+                StorageMapping mapping = ThisApplication.context().storageMappings().get(IMMsgFile.class, file.getStorage());
+                if (null == mapping) {
+                    throw new ExceptionStorageNotExist(file.getStorage());
+                }
+                try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+                    file.readContent(mapping, os);
+                    byte[] bs = os.toByteArray();
+                    wo = new Wo(bs, this.contentType(false, file.getName()),
+                            this.contentDisposition(false, file.getName()));
+                    /**
+                     * 对10M以下的文件进行缓存
+                     */
+                    if (bs.length < (1024 * 1024 * 10)) {
+                        cache.put(new Element(cacheKey, wo));
+                    }
+                }catch (Exception e){
+                    if(e.getMessage().indexOf("existed") > -1){
+                        logger.warn("原始附件{}-{}不存在,删除记录!", file.getId(), file.getName());
+                        emc.beginTransaction(IMMsgFile.class);
+                        emc.delete(IMMsgFile.class, file.getId());
+                        emc.commit();
+                    }
+                    throw e;
+                }
+            }
+            result.setData(wo);
+            return result;
+        }
+    }
+
+
+    public static class Wo extends WoFile {
+
+        public Wo(byte[] bytes, String contentType, String contentDisposition) {
+            super(bytes, contentType, contentDisposition);
+        }
+
+    }
+}

+ 111 - 0
o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ActionImageDownloadWidthHeight.java

@@ -0,0 +1,111 @@
+package com.x.message.assemble.communicate.jaxrs.im;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.project.cache.ApplicationCache;
+import com.x.base.core.project.config.StorageMapping;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WoFile;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.message.assemble.communicate.ThisApplication;
+import com.x.message.core.entity.IMMsgFile;
+import net.sf.ehcache.Ehcache;
+import net.sf.ehcache.Element;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.imgscalr.Scalr;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Created by fancyLou on 2020-06-15.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+public class ActionImageDownloadWidthHeight extends BaseAction  {
+
+    private static Logger logger = LoggerFactory.getLogger( ActionImageDownloadWidthHeight.class );
+
+    private Ehcache cache = ApplicationCache.instance().getCache(ActionImageDownloadWidthHeight.class);
+
+    ActionResult<Wo> execute(EffectivePerson effectivePerson, String id, Integer width, Integer height) throws Exception {
+        try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+            ActionResult<Wo> result = new ActionResult<>();
+            Wo wo = null;
+            /** 确定是否要用application/octet-stream输出 */
+            IMMsgFile file = emc.find(id, IMMsgFile.class);
+            if (null == file) {
+                throw new ExceptionFileNotExist(id);
+            }
+            if (!ArrayUtils.contains(IMAGE_EXTENSIONS, file.getExtension())) {
+                throw new Exception("file is not image file.");
+            }
+            if (width < 0 || width > 5000) {
+                throw new Exception("invalid width:" + width + ".");
+            }
+            if (height < 0 || height > 5000) {
+                throw new Exception("invalid height:" + height + ".");
+            }
+
+
+            String cacheKey = ApplicationCache.concreteCacheKey(this.getClass(), id+width+height);
+            Element element = cache.get(cacheKey);
+
+            if ((null != element) && (null != element.getObjectValue())) {
+                wo = (Wo) element.getObjectValue();
+                result.setData(wo);
+            } else {
+                StorageMapping mapping = ThisApplication.context().storageMappings().get(IMMsgFile.class, file.getStorage());
+                if (null == mapping) {
+                    throw new ExceptionStorageNotExist(file.getStorage());
+                }
+                try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+                    file.readContent(mapping, os);
+                    try (ByteArrayInputStream input = new ByteArrayInputStream(os.toByteArray())) {
+                        BufferedImage src = ImageIO.read(input);
+                        int scalrWidth = (width == 0) ? src.getWidth() : width;
+                        int scalrHeight = (height == 0) ? src.getHeight() : height;
+                        Scalr.Mode mode = Scalr.Mode.FIT_TO_WIDTH;
+                        if(src.getWidth()>src.getHeight()){
+                            mode = Scalr.Mode.FIT_TO_HEIGHT;
+                        }
+                        BufferedImage scalrImage = Scalr.resize(src,Scalr.Method.SPEED, mode, NumberUtils.min(scalrWidth, src.getWidth()),
+                                NumberUtils.min(scalrHeight, src.getHeight()));
+                        try (org.apache.commons.io.output.ByteArrayOutputStream baos = new org.apache.commons.io.output.ByteArrayOutputStream()) {
+                            ImageIO.write(scalrImage, "png", baos);
+                            byte[] bs = baos.toByteArray();
+
+                            wo = new Wo(bs, this.contentType(false, file.getName()),
+                                    this.contentDisposition(false, file.getName()));
+
+                            cache.put(new Element(cacheKey, wo));
+                            result.setData(wo);
+                        }
+                    }
+                }catch (Exception e){
+                    if(e.getMessage().indexOf("existed") > -1){
+                        logger.warn("原始附件{}-{}不存在,删除记录!", file.getId(), file.getName());
+                        emc.beginTransaction(IMMsgFile.class);
+                        emc.delete(IMMsgFile.class, file.getId());
+                        emc.commit();
+                    }
+                    throw e;
+                }
+            }
+            return result;
+        }
+    }
+
+
+    public static class Wo extends WoFile {
+
+        public Wo(byte[] bytes, String contentType, String contentDisposition) {
+            super(bytes, contentType, contentDisposition);
+        }
+
+    }
+}

+ 76 - 0
o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ActionUploadFile.java

@@ -0,0 +1,76 @@
+package com.x.message.assemble.communicate.jaxrs.im;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.entity.annotation.CheckPersistType;
+import com.x.base.core.project.config.StorageMapping;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WoId;
+import com.x.base.core.project.tools.DefaultCharset;
+import com.x.message.assemble.communicate.ThisApplication;
+import com.x.message.core.entity.IMMsgFile;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+
+import java.util.Date;
+
+/**
+ * Created by fancyLou on 2020-06-15.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+public class ActionUploadFile extends BaseAction {
+
+    public ActionResult<Wo> execute(EffectivePerson effectivePerson, String conversationId, String type, byte[] bytes,
+                                    FormDataContentDisposition disposition) throws Exception {
+        try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+            ActionResult<Wo> result = new ActionResult<>();
+            StorageMapping mapping = ThisApplication.context().storageMappings().random(IMMsgFile.class);
+            if (null == mapping) {
+                throw new ExceptionAllocateStorageMaaping();
+            }
+
+            String fileName = "";
+            /** 文件名编码转换 */
+            if (StringUtils.isEmpty(fileName)) {
+                fileName = new String(disposition.getFileName().getBytes(DefaultCharset.charset_iso_8859_1),
+                        DefaultCharset.charset);
+            }
+            fileName = FilenameUtils.getName(fileName);
+            /** 禁止不带扩展名的文件上传 */
+            if (StringUtils.isEmpty(FilenameUtils.getExtension(fileName))) {
+                throw new ExceptionEmptyExtension(fileName);
+            }
+            if(bytes==null){
+                throw new ExceptionAttachmentNone(fileName);
+            }
+            IMMsgFile file = new IMMsgFile();
+            file.setName(fileName);
+            file.setStorage(mapping.getName());
+            file.setPerson(effectivePerson.getDistinguishedName());
+            Date now = new Date();
+            file.setCreateTime(now);
+            file.setLastUpdateTime(now);
+            file.setExtension(StringUtils.lowerCase(FilenameUtils.getExtension(fileName)));
+            file.setConversationId(conversationId);
+            file.setType(type);
+
+            emc.check(file, CheckPersistType.all);
+            file.saveContent(mapping, bytes, fileName);
+            emc.beginTransaction(IMMsgFile.class);
+            emc.persist(file);
+            emc.commit();
+            Wo wo = new Wo();
+            wo.setId(file.getId());
+            result.setData(wo);
+            return result;
+        }
+    }
+
+
+
+
+    public static class Wo extends WoId {
+    }
+}

+ 12 - 0
o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionAllocateStorageMaaping.java

@@ -0,0 +1,12 @@
+package com.x.message.assemble.communicate.jaxrs.im;
+
+import com.x.base.core.project.exception.PromptException;
+
+class ExceptionAllocateStorageMaaping extends PromptException {
+
+	private static final long serialVersionUID = 4132300948670472899L;
+
+	ExceptionAllocateStorageMaaping() {
+		super("无法分派存储器.");
+	}
+}

+ 13 - 0
o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionAttachmentNone.java

@@ -0,0 +1,13 @@
+package com.x.message.assemble.communicate.jaxrs.im;
+
+
+import com.x.base.core.project.exception.PromptException;
+
+class ExceptionAttachmentNone extends PromptException {
+
+	private static final long serialVersionUID = 4132300948670472899L;
+
+	ExceptionAttachmentNone(String name) {
+		super("未上传附件: {}.", name);
+	}
+}

+ 17 - 0
o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionEmptyExtension.java

@@ -0,0 +1,17 @@
+package com.x.message.assemble.communicate.jaxrs.im;
+
+import com.x.base.core.project.exception.PromptException;
+
+class ExceptionEmptyExtension extends PromptException {
+
+	private static final long serialVersionUID = 4132300948670472899L;
+
+	ExceptionEmptyExtension(String name) {
+		super("不能上传文件扩展名为空的文件: {}.", name);
+	}
+
+	ExceptionEmptyExtension(String message, String name) {
+		super(message, name);
+	}
+
+}

+ 15 - 0
o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionFileNotExist.java

@@ -0,0 +1,15 @@
+package com.x.message.assemble.communicate.jaxrs.im;
+
+import com.x.base.core.project.exception.PromptException;
+
+class ExceptionFileNotExist extends PromptException {
+
+	private static final long serialVersionUID = 7750207007061165350L;
+
+	ExceptionFileNotExist(String id) {
+		super("指定的文件: {} 不存在.", id);
+	}
+	ExceptionFileNotExist(String id, String fileId) {
+		super("指定的文件: {} 的附件{}不存在.", id, fileId);
+	}
+}

+ 12 - 0
o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ExceptionStorageNotExist.java

@@ -0,0 +1,12 @@
+package com.x.message.assemble.communicate.jaxrs.im;
+
+import com.x.base.core.project.exception.PromptException;
+
+class ExceptionStorageNotExist extends PromptException {
+
+	private static final long serialVersionUID = 4132300948670472899L;
+
+	ExceptionStorageNotExist(String name) {
+		super("无法找到存储器: {}.", name);
+	}
+}

+ 61 - 0
o2server/x_message_assemble_communicate/src/main/java/com/x/message/assemble/communicate/jaxrs/im/ImAction.java

@@ -12,6 +12,8 @@ import com.x.base.core.project.jaxrs.StandardJaxrsAction;
 import com.x.base.core.project.jaxrs.WoId;
 import com.x.base.core.project.jaxrs.WoId;
 import com.x.base.core.project.logger.Logger;
 import com.x.base.core.project.logger.Logger;
 import com.x.base.core.project.logger.LoggerFactory;
 import com.x.base.core.project.logger.LoggerFactory;
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
 
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.*;
 import javax.ws.rs.*;
@@ -189,4 +191,63 @@ public class ImAction extends StandardJaxrsAction {
     }
     }
 
 
 
 
+    @JaxrsMethodDescribe(value = "上传文件.", action = ActionUploadFile.class)
+    @POST
+    @Path("msg/upload/{conversationId}/type/{type}")
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    @Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+    public void uploadFile(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
+                           @JaxrsParameterDescribe("会话id") @PathParam("conversationId") String conversationId,
+                           @JaxrsParameterDescribe("文件类型") @PathParam("type") String type,
+                           @JaxrsParameterDescribe("附件标识") @FormDataParam(FILE_FIELD) final byte[] bytes,
+                           @JaxrsParameterDescribe("上传文件") @FormDataParam(FILE_FIELD) final FormDataContentDisposition disposition){
+        ActionResult<ActionUploadFile.Wo> result = new ActionResult<>();
+        EffectivePerson effectivePerson = this.effectivePerson(request);
+        try {
+            result = new ActionUploadFile().execute(effectivePerson, conversationId, type, bytes, disposition);
+        } catch (Exception e) {
+            logger.error(e, effectivePerson, request, null);
+            result.error(e);
+        }
+        asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+    }
+
+    @JaxrsMethodDescribe(value = "获取文件内容,输出头信息", action = ActionFileDownload.class)
+    @GET
+    @Path("msg/download/{id}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void download(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
+                         @JaxrsParameterDescribe("附件标识") @PathParam("id") String id) {
+        ActionResult<ActionFileDownload.Wo> result = new ActionResult<>();
+        EffectivePerson effectivePerson = this.effectivePerson(request);
+        try {
+            result = new ActionFileDownload().execute(effectivePerson, id);
+        } catch (Exception e) {
+            logger.error(e, effectivePerson, request, null);
+            result.error(e);
+        }
+        asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+    }
+
+
+    @JaxrsMethodDescribe(value = "下载图片设定宽高后的(png格式).width(0-5000)像素,0代表不限制,height(0-5000)像素,0代表不限制.", action = ActionImageDownloadWidthHeight.class)
+    @GET
+    @Path("msg/download/{id}/image/width/{width}/height/{height}")
+    @Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void downloadImageWidthHeight(@Suspended final AsyncResponse asyncResponse,
+                                         @Context HttpServletRequest request, @JaxrsParameterDescribe("附件标识") @PathParam("id") String id,
+                                         @JaxrsParameterDescribe("宽度") @PathParam("width") Integer width,
+                                         @JaxrsParameterDescribe("高度") @PathParam("height") Integer height) {
+        ActionResult<ActionImageDownloadWidthHeight.Wo> result = new ActionResult<>();
+        EffectivePerson effectivePerson = this.effectivePerson(request);
+        try {
+            result = new ActionImageDownloadWidthHeight().execute(effectivePerson, id, width, height);
+        } catch (Exception e) {
+            logger.error(e, effectivePerson, request, null);
+            result.error(e);
+        }
+        asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+    }
+
 }
 }

+ 228 - 0
o2server/x_message_core_entity/src/main/java/com/x/message/core/entity/IMMsgFile.java

@@ -0,0 +1,228 @@
+package com.x.message.core.entity;
+
+import com.x.base.core.entity.JpaObject;
+import com.x.base.core.entity.Storage;
+import com.x.base.core.entity.StorageObject;
+import com.x.base.core.entity.StorageType;
+import com.x.base.core.entity.annotation.CheckPersist;
+import com.x.base.core.entity.annotation.ContainerEntity;
+import com.x.base.core.project.annotation.FieldDescribe;
+import com.x.base.core.project.tools.DateTools;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.openjpa.persistence.jdbc.Index;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * Created by fancyLou on 2020-06-15.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+
+@ContainerEntity(dumpSize = 1000, type = ContainerEntity.Type.content, reference = ContainerEntity.Reference.strong)
+@Entity
+@Table(name = PersistenceProperties.IMMsgFile.table, uniqueConstraints = {
+        @UniqueConstraint(name = PersistenceProperties.IMMsgFile.table + JpaObject.IndexNameMiddle
+                + JpaObject.DefaultUniqueConstraintSuffix, columnNames = { JpaObject.IDCOLUMN,
+                JpaObject.CREATETIMECOLUMN, JpaObject.UPDATETIMECOLUMN, JpaObject.SEQUENCECOLUMN }) })
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+@Storage(type = StorageType.im)
+public class IMMsgFile extends StorageObject {
+
+
+    private static final long serialVersionUID = 492931147504877023L;
+    private static final String TABLE = PersistenceProperties.IMMsgFile.table;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @FieldDescribe("数据库主键,自动生成.")
+    @Id
+    @Column(length = length_id, name = ColumnNamePrefix + id_FIELDNAME)
+    private String id = createId();
+
+    /* 以上为 JpaObject 默认字段 */
+
+    public void onPersist() throws Exception {
+
+    }
+
+    public static final String person_FIELDNAME = "person";
+    @FieldDescribe("上传用户.")
+    @Column(length = length_255B, name = ColumnNamePrefix + person_FIELDNAME)
+    @Index(name = TABLE + IndexNameMiddle + person_FIELDNAME)
+    @CheckPersist(allowEmpty = true)
+    private String person;
+
+    public static final String name_FIELDNAME = "name";
+    @FieldDescribe("文件名称.")
+    @Column(length = length_255B, name = ColumnNamePrefix + name_FIELDNAME)
+    @Index(name = TABLE + IndexNameMiddle + name_FIELDNAME)
+    @CheckPersist(allowEmpty = false, fileNameString = true)
+    private String name;
+
+    public static final String storage_FIELDNAME = "storage";
+    @FieldDescribe("存储器的名称,也就是多个存放节点的名字.")
+    @Column(length = JpaObject.length_64B, name = ColumnNamePrefix + storage_FIELDNAME)
+    @CheckPersist(allowEmpty = false, simplyString = true)
+    @Index(name = TABLE + IndexNameMiddle + storage_FIELDNAME)
+    private String storage;
+
+    public static final String extension_FIELDNAME = "extension";
+    @FieldDescribe("扩展名,必须要有扩展名的文件才允许上传.")
+    @Column(length = JpaObject.length_64B, name = ColumnNamePrefix + extension_FIELDNAME)
+    @CheckPersist(allowEmpty = false, fileNameString = true)
+    private String extension;
+
+    public static final String lastUpdateTime_FIELDNAME = "lastUpdateTime";
+    @FieldDescribe("最后更新时间")
+    @Column(name = ColumnNamePrefix + lastUpdateTime_FIELDNAME)
+    @Index(name = TABLE + IndexNameMiddle + lastUpdateTime_FIELDNAME)
+    @CheckPersist(allowEmpty = false)
+    private Date lastUpdateTime;
+
+
+
+    public static final String deepPath_FIELDNAME = "deepPath";
+    @FieldDescribe("是否使用更深的路径.")
+    @CheckPersist(allowEmpty = true)
+    @Column(name = ColumnNamePrefix + deepPath_FIELDNAME)
+    @Index(name = TABLE + IndexNameMiddle + deepPath_FIELDNAME)
+    private Boolean deepPath;
+
+
+    public static final String length_FIELDNAME = "length";
+    @FieldDescribe("文件大小.")
+    @Column(name = ColumnNamePrefix + length_FIELDNAME)
+    @CheckPersist(allowEmpty = true)
+    private Long length;
+
+
+    @Override
+    public String path() throws Exception {
+        if (null == this.conversationId) {
+            throw new Exception("conversationId can not be null.");
+        }
+        if (StringUtils.isEmpty(type)) {
+            throw new Exception("type can not be empty.");
+        }
+        String str = this.conversationId;
+        str += PATHSEPARATOR;
+        str += DateTools.format(this.getCreateTime(), DateTools.formatCompact_yyyyMMdd);
+        str += PATHSEPARATOR;
+        str += this.type;
+        str += PATHSEPARATOR;
+        str += this.id;
+        str += StringUtils.isEmpty(this.extension) ? "" : ("." + this.extension);
+        return str;
+    }
+
+    public static final String conversationId_FIELDNAME = "conversationId";
+    @FieldDescribe("会话id, 关联的会话.")
+    @Column(length = length_64B, name = ColumnNamePrefix + conversationId_FIELDNAME)
+    @CheckPersist(allowEmpty = false)
+    private String conversationId;
+
+
+    public static final String type_FIELDNAME = "type";
+    @FieldDescribe("文件分类,对应消息类型.")
+    @Column(length = JpaObject.length_64B, name = ColumnNamePrefix + type_FIELDNAME)
+    @CheckPersist(allowEmpty = false)
+    private String type;
+
+
+
+
+    public String getPerson() {
+        return person;
+    }
+
+    public void setPerson(String person) {
+        this.person = person;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getStorage() {
+        return storage;
+    }
+
+    @Override
+    public void setStorage(String storage) {
+        this.storage = storage;
+    }
+
+    @Override
+    public String getExtension() {
+        return extension;
+    }
+
+    @Override
+    public void setExtension(String extension) {
+        this.extension = extension;
+    }
+
+    @Override
+    public Date getLastUpdateTime() {
+        return lastUpdateTime;
+    }
+
+    @Override
+    public void setLastUpdateTime(Date lastUpdateTime) {
+        this.lastUpdateTime = lastUpdateTime;
+    }
+
+    @Override
+    public Boolean getDeepPath() {
+        return deepPath;
+    }
+
+    @Override
+    public void setDeepPath(Boolean deepPath) {
+        this.deepPath = deepPath;
+    }
+
+
+    public String getConversationId() {
+        return conversationId;
+    }
+
+    public void setConversationId(String conversationId) {
+        this.conversationId = conversationId;
+    }
+
+    @Override
+    public Long getLength() {
+        return length;
+    }
+
+    @Override
+    public void setLength(Long length) {
+        this.length = length;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+
+}

+ 3 - 0
o2server/x_message_core_entity/src/main/java/com/x/message/core/entity/PersistenceProperties.java

@@ -32,4 +32,7 @@ public final class PersistenceProperties extends AbstractPersistenceProperties {
 	public static class IMMsg {
 	public static class IMMsg {
 		public static final String table = "MSG_IM_MESSAGE";
 		public static final String table = "MSG_IM_MESSAGE";
 	}
 	}
+	public static class IMMsgFile {
+		public static final String table = "MSG_IM_MESSAGE_FILE";
+	}
 }
 }