support add media thumb attachment
This commit is contained in:
@ -0,0 +1,39 @@
|
|||||||
|
package com.imyeyu.api.modules.common.bean;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-10-20 15:04
|
||||||
|
*/
|
||||||
|
public class MediaAttach {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-28 02:01
|
||||||
|
*/
|
||||||
|
public enum Type {
|
||||||
|
|
||||||
|
SOURCE,
|
||||||
|
|
||||||
|
THUMB
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-10-20 15:04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class ExtData {
|
||||||
|
|
||||||
|
private Long sourceId;
|
||||||
|
|
||||||
|
private String sourceMongoId;
|
||||||
|
|
||||||
|
private boolean isImage;
|
||||||
|
|
||||||
|
private boolean isVideo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.api.modules.common.entity;
|
package com.imyeyu.api.modules.common.entity;
|
||||||
|
|
||||||
import com.imyeyu.java.ref.Ref;
|
|
||||||
import com.imyeyu.api.bean.MultilingualHandler;
|
import com.imyeyu.api.bean.MultilingualHandler;
|
||||||
|
import com.imyeyu.java.ref.Ref;
|
||||||
import com.imyeyu.spring.entity.Entity;
|
import com.imyeyu.spring.entity.Entity;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -44,24 +44,36 @@ public class Attachment extends Entity implements MultilingualHandler {
|
|||||||
/** 镜像 */
|
/** 镜像 */
|
||||||
MIRROR,
|
MIRROR,
|
||||||
|
|
||||||
|
JOURNAL,
|
||||||
|
|
||||||
|
JOURNAL_TRAVEL,
|
||||||
|
|
||||||
|
JOURNAL_MOMENT,
|
||||||
|
|
||||||
/** 系统 */
|
/** 系统 */
|
||||||
SYSTEM
|
SYSTEM
|
||||||
}
|
}
|
||||||
|
|
||||||
private BizType bizType;
|
protected BizType bizType;
|
||||||
|
|
||||||
private Long bizId;
|
protected Long bizId;
|
||||||
|
|
||||||
private String attachType;
|
protected String attachType;
|
||||||
|
|
||||||
private String mongoId;
|
protected String mongoId;
|
||||||
|
|
||||||
@MultilingualField
|
@MultilingualField
|
||||||
private String title;
|
protected String title;
|
||||||
|
|
||||||
private String name;
|
protected String name;
|
||||||
|
|
||||||
private Long size;
|
protected Long size;
|
||||||
|
|
||||||
|
protected String md5;
|
||||||
|
|
||||||
|
protected String ext;
|
||||||
|
|
||||||
|
protected Long destroyAt;
|
||||||
|
|
||||||
public void setAttachTypeValue(Enum<?> attachType) {
|
public void setAttachTypeValue(Enum<?> attachType) {
|
||||||
this.attachType = attachType.toString();
|
this.attachType = attachType.toString();
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.api.modules.common.mapper;
|
package com.imyeyu.api.modules.common.mapper;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
@ -24,8 +25,9 @@ public interface AttachmentMapper extends BaseMapper<Attachment, Long> {
|
|||||||
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} AND attach_type = #{attachType} " + VALID + LIMIT_1)
|
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} AND attach_type = #{attachType} " + VALID + LIMIT_1)
|
||||||
Attachment selectByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
Attachment selectByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
||||||
|
|
||||||
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} AND " + VALID + PAGE)
|
List<Attachment> listByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes, Page page);
|
||||||
List<Attachment> listByBizId(Attachment.BizType bizType, long bizId, long offset, int limit);
|
|
||||||
|
|
||||||
List<Attachment> listByAttachType(Attachment.BizType bizType, long bizId, Enum<?> ...attachTypes);
|
long countByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes);
|
||||||
|
|
||||||
|
List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes, List<String> md5s);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
package com.imyeyu.api.modules.common.service;
|
package com.imyeyu.api.modules.common.service;
|
||||||
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
import com.imyeyu.spring.service.DeletableService;
|
import com.imyeyu.spring.service.DeletableService;
|
||||||
import com.imyeyu.spring.service.DestroyableService;
|
import com.imyeyu.spring.service.DestroyableService;
|
||||||
import com.imyeyu.spring.service.GettableService;
|
import com.imyeyu.spring.service.GettableService;
|
||||||
|
import com.imyeyu.spring.service.PageableService;
|
||||||
|
import com.imyeyu.spring.service.UpdatableService;
|
||||||
import com.mongodb.client.gridfs.model.GridFSFile;
|
import com.mongodb.client.gridfs.model.GridFSFile;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -20,7 +24,7 @@ import java.util.List;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2023-08-15 10:21
|
* @since 2023-08-15 10:21
|
||||||
*/
|
*/
|
||||||
public interface AttachmentService extends GettableService<Attachment, Long>, DeletableService<Long>, DestroyableService<Long> {
|
public interface AttachmentService extends GettableService<Attachment, Long>, PageableService<Attachment>, UpdatableService<Attachment>, DeletableService<Long>, DestroyableService<Long> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -29,6 +33,16 @@ public interface AttachmentService extends GettableService<Attachment, Long>, De
|
|||||||
*/
|
*/
|
||||||
void create(AttachmentRequest request);
|
void create(AttachmentRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建媒体附件,同步创建缩略图
|
||||||
|
*
|
||||||
|
* @param request 附件请求
|
||||||
|
* @return 缩略图附件
|
||||||
|
*/
|
||||||
|
Attachment createMedia(AttachmentRequest request) throws TimiException;
|
||||||
|
|
||||||
|
void deleteMedia(Long thumbId) throws TimiException;
|
||||||
|
|
||||||
Attachment getByBizId(Attachment.BizType bizType, long bizId);
|
Attachment getByBizId(Attachment.BizType bizType, long bizId);
|
||||||
|
|
||||||
Attachment getByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
Attachment getByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
||||||
@ -46,11 +60,26 @@ public interface AttachmentService extends GettableService<Attachment, Long>, De
|
|||||||
/**
|
/**
|
||||||
* 根据业务获取所有附件
|
* 根据业务获取所有附件
|
||||||
*
|
*
|
||||||
* @param bizType 业务类型
|
* @param bizType 业务类型
|
||||||
* @param bizId 业务 ID
|
* @param bizId 业务 ID,可为 null
|
||||||
* @param attachTypes
|
* @param attachTypes 附件类型,可为 null
|
||||||
* @return 所有附件
|
* @return 所有附件
|
||||||
* @throws TimiException 服务异常
|
* @throws TimiException 服务异常
|
||||||
*/
|
*/
|
||||||
List<Attachment> listByBizId(Attachment.BizType bizType, long bizId, Enum<?> ...attachTypes);
|
List<Attachment> listByBizId(Attachment.BizType bizType, Long bizId, Enum<?> ...attachTypes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据业务获取所有附件
|
||||||
|
*
|
||||||
|
* @param bizType 业务类型
|
||||||
|
* @param bizId 业务 ID,可为 null
|
||||||
|
* @param attachTypes 附件类型,可为 null
|
||||||
|
* @return 附件数量
|
||||||
|
* @throws TimiException 服务异常
|
||||||
|
*/
|
||||||
|
long countByBizId(Attachment.BizType bizType, Long bizId, Enum<?> ...attachTypes);
|
||||||
|
|
||||||
|
List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, List<String> md5s) throws TimiException;
|
||||||
|
|
||||||
|
PageResult<Attachment> pageByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, Page page) throws TimiException;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,22 @@
|
|||||||
package com.imyeyu.api.modules.common.service.implement;
|
package com.imyeyu.api.modules.common.service.implement;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
|
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.common.mapper.AttachmentMapper;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
||||||
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
||||||
|
import com.imyeyu.api.util.JavaCV;
|
||||||
import com.imyeyu.io.IO;
|
import com.imyeyu.io.IO;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.network.Network;
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.api.modules.common.mapper.AttachmentMapper;
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
import com.imyeyu.utils.Time;
|
import com.imyeyu.utils.Time;
|
||||||
@ -17,6 +24,8 @@ import com.mongodb.client.gridfs.GridFSBucket;
|
|||||||
import com.mongodb.client.gridfs.model.GridFSFile;
|
import com.mongodb.client.gridfs.model.GridFSFile;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
|
import org.apache.tika.Tika;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
@ -24,9 +33,14 @@ import org.springframework.data.mongodb.gridfs.GridFsTemplate;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
@ -37,8 +51,11 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class AttachmentServiceImplement extends AbstractEntityService<Attachment, Long> implements AttachmentService {
|
public class AttachmentServiceImplement extends AbstractEntityService<Attachment, Long> implements AttachmentService {
|
||||||
|
|
||||||
|
private final SettingService settingService;
|
||||||
|
|
||||||
private final AttachmentMapper mapper;
|
private final AttachmentMapper mapper;
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
private final GridFSBucket gridFSBucket;
|
private final GridFSBucket gridFSBucket;
|
||||||
private final GridFsTemplate gridFsTemplate;
|
private final GridFsTemplate gridFsTemplate;
|
||||||
|
|
||||||
@ -52,11 +69,11 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
public void destroy(Long id) {
|
public void destroy(Long id) {
|
||||||
try {
|
try {
|
||||||
Attachment attachment = get(id);
|
Attachment attachment = get(id);
|
||||||
if (!attachment.isDeleted()) {
|
|
||||||
delete(id);
|
|
||||||
}
|
|
||||||
mapper.destroy(attachment.getId());
|
|
||||||
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(attachment.getMongoId())));
|
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(attachment.getMongoId())));
|
||||||
|
|
||||||
|
attachment.setDeletedAt(Time.now());
|
||||||
|
attachment.setDestroyAt(Time.now());
|
||||||
|
mapper.update(attachment);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("delete mongo file error", e);
|
log.error("delete mongo file error", e);
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("TODO delete mongo file error");
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO delete mongo file error");
|
||||||
@ -81,12 +98,12 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
}
|
}
|
||||||
mongoName.append(request.getName());
|
mongoName.append(request.getName());
|
||||||
|
|
||||||
mongoId = gridFsTemplate.store(is, mongoName.toString()).toString();
|
mongoId = gridFsTemplate.store(request.getInputStream(), mongoName.toString()).toString();
|
||||||
Attachment attachment = new Attachment();
|
GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(mongoId)));
|
||||||
BeanUtils.copyProperties(request, attachment);
|
request.setMongoId(mongoId);
|
||||||
attachment.setMongoId(mongoId);
|
request.setSize(gridFSFile.getLength());
|
||||||
attachment.setCreatedAt(Time.now());
|
request.setMd5(IO.md5(gridFSBucket.openDownloadStream(gridFSFile.getObjectId())));
|
||||||
mapper.insert(attachment);
|
mapper.insert(request);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (mongoId != null) {
|
if (mongoId != null) {
|
||||||
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(mongoId)));
|
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(mongoId)));
|
||||||
@ -96,6 +113,74 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public Attachment createMedia(AttachmentRequest request) throws TimiException {
|
||||||
|
TimiException.required(request.getName(), "not found name");
|
||||||
|
TimiException.required(request.getBizType(), "not found bizType");
|
||||||
|
TimiException.required(request.getInputStream(), "not found inputStream");
|
||||||
|
try {
|
||||||
|
// 储存源文件
|
||||||
|
request.setAttachTypeValue(MediaAttach.Type.SOURCE);
|
||||||
|
create(request);
|
||||||
|
|
||||||
|
// 生成缩略图
|
||||||
|
InputStream mimeStream = getInputStreamByMongoId(request.getMongoId());
|
||||||
|
String mimeType = new Tika().detect(mimeStream);
|
||||||
|
boolean isImage = false;
|
||||||
|
|
||||||
|
InputStream sourceStream = getInputStreamByMongoId(request.getMongoId());
|
||||||
|
ByteArrayOutputStream thumbStream = new ByteArrayOutputStream();
|
||||||
|
switch (mimeType) {
|
||||||
|
case "image/png", "image/bmp", "image/jpeg" -> {
|
||||||
|
isImage = true;
|
||||||
|
Thumbnails.of(sourceStream).width(256).keepAspectRatio(true).toOutputStream(thumbStream);
|
||||||
|
}
|
||||||
|
case "video/mp4", "video/quicktime" -> {
|
||||||
|
log.info("capturing thumbnail: {}", request.getName());
|
||||||
|
long start = Time.now();
|
||||||
|
File tempFile = IO.file("temp/%s_%s".formatted(UUID.randomUUID().toString(), request.getName()));
|
||||||
|
try {
|
||||||
|
IO.toFile(tempFile, sourceStream);
|
||||||
|
ByteArrayOutputStream baos = JavaCV.captureThumbnail(IO.getInputStream(tempFile), 2);
|
||||||
|
Thumbnails.of(IO.toInputStream(baos)).width(256).keepAspectRatio(true).toOutputStream(thumbStream);
|
||||||
|
log.info("captured thumbnail: {} at {} ms", request.getName(), Time.now() - start);
|
||||||
|
} finally {
|
||||||
|
IO.destroy(tempFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MediaAttach.ExtData extData = new MediaAttach.ExtData();
|
||||||
|
extData.setImage(isImage);
|
||||||
|
extData.setVideo(!isImage);
|
||||||
|
extData.setSourceId(request.getId());
|
||||||
|
extData.setSourceMongoId(request.getMongoId());
|
||||||
|
|
||||||
|
AttachmentRequest thumbAttach = new AttachmentRequest();
|
||||||
|
thumbAttach.setName(Network.simpleURIFileName(request.getName()) + ".png");
|
||||||
|
thumbAttach.setBizType(request.getBizType());
|
||||||
|
thumbAttach.setBizId(request.getBizId());
|
||||||
|
thumbAttach.setAttachTypeValue(MediaAttach.Type.THUMB);
|
||||||
|
thumbAttach.setExt(gson.toJson(extData));
|
||||||
|
thumbAttach.setInputStream(new ByteArrayInputStream(thumbStream.toByteArray()));
|
||||||
|
create(thumbAttach);
|
||||||
|
|
||||||
|
return get(thumbAttach.getId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("create media attachment error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO create media attachment error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void deleteMedia(Long thumbId) throws TimiException {
|
||||||
|
Attachment attachment = get(thumbId);
|
||||||
|
delete(attachment.getId());
|
||||||
|
MediaAttach.ExtData data = gson.fromJson(attachment.getExt(), MediaAttach.ExtData.class);
|
||||||
|
delete(data.getSourceId());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Attachment getByBizId(Attachment.BizType bizType, long bizId) {
|
public Attachment getByBizId(Attachment.BizType bizType, long bizId) {
|
||||||
return mapper.selectByBizId(bizType, bizId);
|
return mapper.selectByBizId(bizType, bizId);
|
||||||
@ -144,7 +229,25 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Attachment> listByBizId(Attachment.BizType bizType, long bizId, Enum<?>... attachTypes) {
|
public List<Attachment> listByBizId(Attachment.BizType bizType, Long bizId, Enum<?>... attachTypes) {
|
||||||
return mapper.listByAttachType(bizType, bizId, attachTypes);
|
return mapper.listByBizId(bizType, bizId, Arrays.asList(attachTypes), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countByBizId(Attachment.BizType bizType, Long bizId, Enum<?>... attachTypes) {
|
||||||
|
return mapper.countByBizId(bizType, bizId, Arrays.asList(attachTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, List<String> md5s) throws TimiException {
|
||||||
|
return mapper.listByMd5s(bizType, bizId, attachTypeList, md5s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<Attachment> pageByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, Page page) throws TimiException {
|
||||||
|
PageResult<Attachment> result = new PageResult<>();
|
||||||
|
result.setList(mapper.listByBizId(bizType, bizId, attachTypeList, page));
|
||||||
|
result.setTotal(mapper.countByBizId(bizType, bizId, attachTypeList));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
42
src/main/java/com/imyeyu/api/util/JavaCV.java
Normal file
42
src/main/java/com/imyeyu/api/util/JavaCV.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package com.imyeyu.api.util;
|
||||||
|
|
||||||
|
import org.bytedeco.javacv.FFmpegFrameGrabber;
|
||||||
|
import org.bytedeco.javacv.Frame;
|
||||||
|
import org.bytedeco.javacv.Java2DFrameConverter;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-10-23 17:05
|
||||||
|
*/
|
||||||
|
public class JavaCV {
|
||||||
|
|
||||||
|
public static ByteArrayOutputStream captureThumbnail(InputStream stream, double targetSeconds) throws Exception {
|
||||||
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||||
|
try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(stream)) {
|
||||||
|
grabber.start();
|
||||||
|
long targetMillis = (long) (targetSeconds * 1000);
|
||||||
|
grabber.setTimestamp(targetMillis);
|
||||||
|
Frame frame;
|
||||||
|
while ((frame = grabber.grabImage()) != null) {
|
||||||
|
if (grabber.getTimestamp() >= targetMillis) {
|
||||||
|
Java2DFrameConverter converter = new Java2DFrameConverter();
|
||||||
|
try (converter) {
|
||||||
|
BufferedImage bi = converter.getBufferedImage(frame);
|
||||||
|
if (bi != null) {
|
||||||
|
ImageIO.write(bi, "png", outStream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,15 +2,47 @@
|
|||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
<mapper namespace="com.imyeyu.api.modules.common.mapper.AttachmentMapper">
|
<mapper namespace="com.imyeyu.api.modules.common.mapper.AttachmentMapper">
|
||||||
<sql id="table">attachment</sql>
|
<sql id="table">attachment</sql>
|
||||||
<select id="listByAttachType" resultType="com.imyeyu.api.modules.common.entity.Attachment">
|
<select id="listByBizId" resultType="com.imyeyu.api.modules.common.entity.Attachment">
|
||||||
SELECT
|
SELECT
|
||||||
*
|
*
|
||||||
FROM
|
FROM
|
||||||
<include refid="table" />
|
attachment
|
||||||
WHERE
|
WHERE
|
||||||
biz_type = #{bizType}
|
biz_type = #{bizType}
|
||||||
AND biz_id = #{bizId}
|
<if test="bizId != null">
|
||||||
<if test="attachTypes != null and 0 < attachTypes.length">
|
AND biz_id = #{bizId}
|
||||||
|
</if>
|
||||||
|
<if test="attachTypes != null and 0 < attachTypes.size()">
|
||||||
|
AND attach_type IN
|
||||||
|
<foreach collection="attachTypes" item="item" open="(" separator="," close=")">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
AND destroy_at IS NULL
|
||||||
|
<if test="page != null">
|
||||||
|
<if test="page.orderMap != null and !page.orderMap.isEmpty()">
|
||||||
|
ORDER BY
|
||||||
|
<foreach collection="page.orderMap" index="key" item="value" separator=",">
|
||||||
|
${key} ${value}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
LIMIT
|
||||||
|
#{page.offset},
|
||||||
|
#{page.limit}
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
<select id="countByBizId" resultType="long">
|
||||||
|
SELECT
|
||||||
|
COUNT(1)
|
||||||
|
FROM
|
||||||
|
attachment
|
||||||
|
WHERE
|
||||||
|
biz_type = #{bizType}
|
||||||
|
<if test="bizId != null">
|
||||||
|
AND biz_id = #{bizId}
|
||||||
|
</if>
|
||||||
|
<if test="attachTypes != null and 0 < attachTypes.size()">
|
||||||
AND attach_type IN
|
AND attach_type IN
|
||||||
<foreach collection="attachTypes" item="item" open="(" separator="," close=")">
|
<foreach collection="attachTypes" item="item" open="(" separator="," close=")">
|
||||||
#{item}
|
#{item}
|
||||||
@ -19,4 +51,23 @@
|
|||||||
AND deleted_at IS NULL
|
AND deleted_at IS NULL
|
||||||
AND destroy_at IS NULL
|
AND destroy_at IS NULL
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
<select id="listByMd5s" resultType="com.imyeyu.api.modules.common.entity.Attachment">
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
attachment
|
||||||
|
WHERE
|
||||||
|
biz_type = #{bizType}
|
||||||
|
<if test="bizId != null">
|
||||||
|
AND biz_id = #{bizId}
|
||||||
|
</if>
|
||||||
|
<if test="attachTypes != null and 0 < attachTypes.size()">
|
||||||
|
AND attach_type IN
|
||||||
|
<foreach collection="attachTypes" item="item" open="(" separator="," close=")">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
AND destroy_at IS NULL
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
|
|||||||
Reference in New Issue
Block a user