专用图片表的设计与七牛云的使用

专用图片表的设计与七牛云的使用

业务开发的过程中,各模块会有图片上传的功能,最初会在各个业务表中维护各自的图片字段,如此一来,图片字段会比较分散,
分散的图片字段有如下的缺点:
1. 统计系统中有多少图片时,得去各个表中查找,如果图片字段命名还千奇百怪,这种是一种比较耗时的工作。
2. 业务表中的记录进行删除(从后台或者直接从数据库进行)时,图片记录也随之消息了,导致图片本身和数据库之间就失去了联系。
集中的图片图片有如下的好处:
1. 图片的集中管理,在图片所在的主表被删除后,此图片记录还存在,可以根据图片记录来清除图片,达到节省磁盘空间的目的。
我设计的图片表:
专用图片表的设计与七牛云的使用_第1张图片
对应的bean ImageAndFile 如下:

package com.soccer.model;

import com.soccer.util.QiNiuKit;

import javax.persistence.*;
import java.util.Date;

import static javax.persistence.GenerationType.IDENTITY;

/**
 *@Author 丰建立
 *@Date 2017/11/2 15:43
 */
@Entity
@Table(name="image_and_file")
public class ImageAndFile  implements java.io.Serializable{
    private Long id;
    private String fileKey;//七牛文件key ,可能是多个, 以","分隔
    private String tableName;//文件所在 表名
    private String fieldName;//文件所在字段名
    private Long recId;//文件所在记录id
    private String fileExt;//文件类型
    private Date opTime;//

    public ImageAndFile() {
    }

    public ImageAndFile(String fileKey, String tableName, String fieldName, Long recId, String fileExt) {
        this.fileKey = fileKey;
        this.tableName = tableName;
        this.fieldName = fieldName;
        this.recId = recId;
        this.fileExt = fileExt;
        this.opTime = new Date();
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    @Column(name = "fileKey")
    public String getFileKey() {
        return fileKey;
    }

    public void setFileKey(String fileKey) {
        this.fileKey = fileKey;
    }

    @Column(name = "tableName")
    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }
    @Column(name = "fieldName")
    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }
    @Column(name = "recId")
    public Long getRecId() {
        return recId;
    }

    public void setRecId(Long recId) {
        this.recId = recId;
    }
    @Column(name = "fileExt")
    public String getFileExt() {
        return fileExt;
    }

    public void setFileExt(String fileExt) {
        this.fileExt = fileExt;
    }
    @Column(name = "opTime")
    public Date getOpTime() {
        return opTime;
    }

    public void setOpTime(Date opTime) {
        this.opTime = opTime;
    }

    @Transient
    public String getUrl() {
        return QiNiuKit.DOMAIN+"/"+this.fileKey+"?v="+(this.getOpTime()==null?(new Date().getTime()):this.getOpTime().getTime());
    }
}

图片需要由本地上传至七牛云,而图片的 key 由 tableName/fileldName/recId.jpg组成。这样同一张图片反复上传时,会对之前的图片进行覆盖,达到节省空间的目的。 每次上传图片时,会更新图片表的时间戳,访问此图片时也会带上此时间戳,如此就可以解决 相同图片名,在客户端被缓存的问题。(如果每次访问同一张图片使用随机的时间戳,又会有流量浪费的毛病)。
下面为保存图片时代码片段:

@Transactional
    public void saveOrUpdate(Logo one) throws Exception {
        super.saveOrUpdate(one);
        qiniuApiService.uploadImageToYun(one.getUrl(),"logo","url",one.getId());
    }

需要先获表主表的id, 然后再调用图片上传方法。 因此先需要保存主表。
将本地图片上传七牛云时,有三点注意:

  • 如果图片url为空,表明用户删除了图片,需要将之前存的七牛云图片删除,再删除iamge_and_file记录。
  • 如果之前图片记录为空,上传图片至七牛云,并保存图片记录
  • 如果之前图片记录非空,上传图片至七牛云,并更新图片记录的时间戳。
 public void uploadImageToYun(String localImagePath, String tableName, String fieldName, Long recId, boolean zipImg) throws Exception{
        if(StringUtils.isEmpty(tableName)){
            throw new Exception("tableName is empty");
        }
        if(StringUtils.isEmpty(fieldName)){
            throw new Exception("fieldName is empty");
        }
        if(StringUtils.isEmpty(recId)){
            throw new Exception("recId is empty");
        }
        if(StringUtils.isEmpty(localImagePath)){
            ImageAndFile image = imageAndFileDao.getImage(tableName,fieldName,recId);
            if(image!=null){
                imageAndFileDao.delete(image);
                QiNiuKit.delete(image.getFileKey());
            }
            return;
        }
        String path = localImagePath;
        String fileExt = "jpg";

        if(localImagePath.startsWith("{")){
            try {
            JSONObject json = JSONObject.parseObject(localImagePath);
            path = json.getString("3");
            } catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }

        if(!StringUtils.isEmpty(path)&& !path.startsWith(QiNiuKit.DOMAIN)){
            String absImgPath = InitServlet.APPLICATION_URL + "/" + path;
            File img = new File(absImgPath);
            if(img.exists() && img.isFile()){
                if(zipImg){
                    //   ImageUtil.zipImage(absImgPath, CommonServiceImpl.LARGE_DIMENS[0], CommonServiceImpl.LARGE_DIMENS[1]);
                }
                fileExt = path.substring(path.lastIndexOf(".")+1);
                String key = QiNiuKit.upload(img, tableName+"/"+fieldName+"/"+recId+"."+fileExt);
                if(key!=null){
                    ImageAndFile image = imageAndFileDao.getImage(tableName,fieldName,recId);
                    if(image == null){
                        imageAndFileDao.saveOrUpdate(key,tableName,fieldName,recId,fileExt);
                    }else{
                        //刷新缓存
                        imageAndFileDao.excuteSqlUpdate("update image_and_file u set u.opTime = now() where u.id= ?",image.getId());
                        QiNiuKit.refresh(image.getUrl());
                    }
                }
            }
        }

    }

我使用的持久层技术为hibernate .使用 小技巧使 ImageAndFile这个实体对客户端透明:
JoinColumnsOrFormulas 是 hibernate 的标签,用得好也是蛮强大,像是为我的功能量身定做一样。
如此一来,将图片集中管理起来了,而且不用对前端代码作过多修改,即可兼容。

@Column(name = "url", length = 200)
    public String getUrl() {
        if(this.getIcon()!=null){
            return this.getIcon().getUrl();
        }
        return this.url;
    }
    private ImageAndFile icon;
    @OneToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
    @JoinColumnsOrFormulas({
            @JoinColumnOrFormula(column=@JoinColumn(name ="id", referencedColumnName ="recId", nullable = true, insertable =false, updatable = false)),
            @JoinColumnOrFormula(formula=@JoinFormula(value="'logo'", referencedColumnName = "tableName")),
            @JoinColumnOrFormula(formula=@JoinFormula(value="'url'", referencedColumnName = "fieldName"))
    })
    private ImageAndFile getIcon() {
        return icon;
    }

    public void setIcon(ImageAndFile icon) {
        this.icon = icon;
    }

你可能感兴趣的:(专用图片表的设计与七牛云的使用)