mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 07:11:52 +08:00
mp:增加上传临时素材的接口
This commit is contained in:
parent
541ee81300
commit
ec872c702c
@ -4,9 +4,6 @@ import lombok.*;
|
||||
import io.swagger.annotations.*;
|
||||
import javax.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* @author fengdan
|
||||
*/
|
||||
@ApiModel("管理后台 - 公众号账号更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
|
@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.mp.controller.admin.material;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadRespVO;
|
||||
import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadTemporaryReqVO;
|
||||
import cn.iocoder.yudao.module.mp.convert.material.MpMaterialConvert;
|
||||
import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO;
|
||||
import cn.iocoder.yudao.module.mp.service.material.MpMaterialService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.io.IOException;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Api(tags = "管理后台 - 公众号素材")
|
||||
@RestController
|
||||
@RequestMapping("/mp/material")
|
||||
@Validated
|
||||
public class MpMaterialController {
|
||||
|
||||
@Resource
|
||||
private MpMaterialService mpMaterialService;
|
||||
|
||||
@ApiOperation("上传临时素材")
|
||||
@PostMapping("/upload-temporary")
|
||||
public CommonResult<MpMaterialUploadRespVO> uploadTemporaryMaterial(
|
||||
@Valid MpMaterialUploadTemporaryReqVO reqVO) throws IOException {
|
||||
MpMaterialDO material = mpMaterialService.uploadTemporaryMaterial(reqVO);
|
||||
return success(MpMaterialConvert.INSTANCE.convert(material));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package cn.iocoder.yudao.module.mp.controller.admin.material.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@ApiModel("管理后台 - 公众号素材上传结果 Response VO")
|
||||
@Data
|
||||
public class MpMaterialUploadRespVO {
|
||||
|
||||
@ApiModelProperty(value = "素材的 media_id", required = true, example = "123")
|
||||
private String mediaId;
|
||||
|
||||
@ApiModelProperty(value = "素材的 URL", required = true, example = "https://www.iocoder.cn/1.png")
|
||||
private String url;
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.mp.controller.admin.material.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@ApiModel("管理后台 - 公众号素材上传临时 Request VO")
|
||||
@Data
|
||||
public class MpMaterialUploadTemporaryReqVO {
|
||||
|
||||
@ApiModelProperty(value = "公众号账号的编号", required = true, example = "2048")
|
||||
@NotNull(message = "公众号账号的编号不能为空")
|
||||
private Long accountId;
|
||||
|
||||
@ApiModelProperty(value = "文件类型", required = true, example = "image", notes = "参见 WxConsts.MediaFileType 枚举")
|
||||
@NotEmpty(message = "文件类型不能为空")
|
||||
private String type;
|
||||
|
||||
@ApiModelProperty(value = "文件附件", required = true)
|
||||
@NotNull(message = "文件不能为空")
|
||||
@JsonIgnore // 避免被操作日志,进行序列化,导致报错
|
||||
private MultipartFile file;
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.mp.convert.material;
|
||||
|
||||
import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadRespVO;
|
||||
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
|
||||
import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface MpMaterialConvert {
|
||||
|
||||
MpMaterialConvert INSTANCE = Mappers.getMapper(MpMaterialConvert.class);
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "id", ignore = true),
|
||||
@Mapping(source = "account.id", target = "accountId"),
|
||||
@Mapping(source = "account.appId", target = "appId"),
|
||||
})
|
||||
MpMaterialDO convert(String mediaId, String type, String url, MpAccountDO account);
|
||||
|
||||
MpMaterialUploadRespVO convert(MpMaterialDO bean);
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package cn.iocoder.yudao.module.mp.dal.dataobject.material;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
|
||||
/**
|
||||
* 公众号素材 DO
|
||||
*
|
||||
* 1. <a href="https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.html">临时素材</a>
|
||||
* 2. <a href="https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Adding_Permanent_Assets.html">永久素材</a>
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("mp_material")
|
||||
@KeySequence("mp_material_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MpMaterialDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 微信公众号 ID
|
||||
*
|
||||
* 关联 {@link MpAccountDO#getId()}
|
||||
*/
|
||||
private Long accountId;
|
||||
/**
|
||||
* 微信公众号 appid
|
||||
*
|
||||
* 冗余 {@link MpAccountDO#getAppId()}
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 公众号素材 id
|
||||
*/
|
||||
private String mediaId;
|
||||
/**
|
||||
* 文件类型
|
||||
*
|
||||
* 枚举 {@link WxConsts.MediaFileType}
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 是否永久
|
||||
*
|
||||
* true - 永久素材
|
||||
* false - 临时素材
|
||||
*/
|
||||
private Boolean permanent;
|
||||
/**
|
||||
* 文件服务器的 URL
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 名字
|
||||
*
|
||||
* 只有【永久素材】使用
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 公众号文件 URL
|
||||
*
|
||||
* 只有【永久素材】使用
|
||||
*/
|
||||
private String mpUrl;
|
||||
|
||||
/**
|
||||
* 视频素材的标题
|
||||
*
|
||||
* 只有【永久素材】使用
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 视频素材的描述
|
||||
*
|
||||
* 只有【永久素材】使用
|
||||
*/
|
||||
private String introduction;
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cn.iocoder.yudao.module.mp.dal.mysql.material;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface MpMaterialMapper extends BaseMapperX<MpMaterialDO> {
|
||||
|
||||
default MpMaterialDO selectByAccountIdAndMediaId(Long accountId, String mediaId) {
|
||||
return selectOne(MpMaterialDO::getAccountId, accountId,
|
||||
MpMaterialDO::getMediaId, mediaId);
|
||||
}
|
||||
|
||||
}
|
@ -80,4 +80,25 @@ public class MpUtils {
|
||||
ValidationUtils.validate(validator, message, group);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据消息类型,获得对应的媒体文件类型
|
||||
*
|
||||
* 注意,不会返回 WxConsts.MediaFileType.THUMB,因为该类型会有明确标注
|
||||
*
|
||||
* @param messageType 消息类型 {@link WxConsts.XmlMsgType}
|
||||
* @return 媒体文件类型 {@link WxConsts.MediaFileType}
|
||||
*/
|
||||
public static String getMediaFileType(String messageType) {
|
||||
switch (messageType) {
|
||||
case WxConsts.XmlMsgType.IMAGE:
|
||||
return WxConsts.MediaFileType.IMAGE;
|
||||
case WxConsts.XmlMsgType.VOICE:
|
||||
return WxConsts.MediaFileType.VOICE;
|
||||
case WxConsts.XmlMsgType.VIDEO:
|
||||
return WxConsts.MediaFileType.VIDEO;
|
||||
default:
|
||||
return WxConsts.MediaFileType.FILE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package cn.iocoder.yudao.module.mp.service.material;
|
||||
|
||||
import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadTemporaryReqVO;
|
||||
import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 公众号素材 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface MpMaterialService {
|
||||
|
||||
/**
|
||||
* 获得素材的 URL
|
||||
*
|
||||
* 该 URL 来自我们自己的文件服务器存储的 URL,不是公众号存储的 URL
|
||||
*
|
||||
* @param accountId 公众号账号编号
|
||||
* @param mediaId 公众号素材 id
|
||||
* @param type 文件类型 {@link WxConsts.MediaFileType}
|
||||
* @return 素材的 URL
|
||||
*/
|
||||
String downloadMaterialUrl(Long accountId, String mediaId, String type);
|
||||
|
||||
MpMaterialDO uploadTemporaryMaterial(@Valid MpMaterialUploadTemporaryReqVO reqVO) throws IOException;
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package cn.iocoder.yudao.module.mp.service.material;
|
||||
|
||||
import cn.hutool.core.io.FileTypeUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||
import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadTemporaryReqVO;
|
||||
import cn.iocoder.yudao.module.mp.convert.material.MpMaterialConvert;
|
||||
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
|
||||
import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO;
|
||||
import cn.iocoder.yudao.module.mp.dal.mysql.material.MpMaterialMapper;
|
||||
import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
|
||||
import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 公众号素材 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class MpMaterialServiceImpl implements MpMaterialService {
|
||||
|
||||
@Resource
|
||||
private MpMaterialMapper mpMaterialMapper;
|
||||
|
||||
@Resource
|
||||
private FileApi fileApi;
|
||||
|
||||
@Resource
|
||||
@Lazy // 延迟加载,解决循环依赖的问题
|
||||
private MpAccountService mpAccountService;
|
||||
|
||||
@Resource
|
||||
@Lazy // 延迟加载,解决循环依赖的问题
|
||||
private MpServiceFactory mpServiceFactory;
|
||||
|
||||
@Override
|
||||
public String downloadMaterialUrl(Long accountId, String mediaId, String type) {
|
||||
// 第一步,直接从数据库查询。如果已经下载,直接返回
|
||||
MpMaterialDO material = mpMaterialMapper.selectByAccountIdAndMediaId(accountId, mediaId);
|
||||
if (material != null) {
|
||||
return material.getUrl();
|
||||
}
|
||||
|
||||
// 第二步,尝试从临时素材中下载
|
||||
String url = downloadMedia(accountId, mediaId);
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
MpAccountDO account = mpAccountService.getRequiredAccount(accountId);
|
||||
material = MpMaterialConvert.INSTANCE.convert(mediaId, type, url, account)
|
||||
.setPermanent(false);
|
||||
mpMaterialMapper.insert(material);
|
||||
|
||||
// 不考虑下载永久素材,因为上传的时候已经保存
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MpMaterialDO uploadTemporaryMaterial(MpMaterialUploadTemporaryReqVO reqVO) throws IOException {
|
||||
WxMpService mpService = mpServiceFactory.getRequiredMpService(reqVO.getAccountId());
|
||||
// 第一步,上传到公众号
|
||||
File file = null;
|
||||
WxMediaUploadResult result;
|
||||
String mediaId;
|
||||
String url;
|
||||
try {
|
||||
// 写入到临时文件
|
||||
file = FileUtil.newFile(FileUtil.getTmpDirPath() + reqVO.getFile().getOriginalFilename());
|
||||
reqVO.getFile().transferTo(file);
|
||||
// 上传到公众号
|
||||
result = mpService.getMaterialService().mediaUpload(reqVO.getType(), file);
|
||||
// 上传到文件服务
|
||||
mediaId = ObjUtil.defaultIfNull(result.getMediaId(), result.getThumbMediaId());
|
||||
url = uploadFile(mediaId, file);
|
||||
} catch (WxErrorException e) {
|
||||
// TODO yunai:待完善
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
FileUtil.del(file);
|
||||
}
|
||||
|
||||
// 第二步,存储到数据库
|
||||
MpAccountDO account = mpAccountService.getRequiredAccount(reqVO.getAccountId());
|
||||
MpMaterialDO material = MpMaterialConvert.INSTANCE.convert(mediaId, reqVO.getType(), url, account)
|
||||
.setPermanent(false);
|
||||
mpMaterialMapper.insert(material);
|
||||
return material;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载微信媒体文件的内容,并上传到文件服务
|
||||
*
|
||||
* 为什么要下载?媒体文件在微信后台保存时间为 3 天,即 3 天后 media_id 失效。
|
||||
*
|
||||
* @param accountId 公众号账号的编号
|
||||
* @param mediaId 媒体文件编号
|
||||
* @return 上传后的 URL
|
||||
*/
|
||||
public String downloadMedia(Long accountId, String mediaId) {
|
||||
WxMpService mpService = mpServiceFactory.getMpService(accountId);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
try {
|
||||
// 第一步,从公众号下载媒体文件
|
||||
File file = mpService.getMaterialService().mediaDownload(mediaId);
|
||||
// 第二步,上传到文件服务
|
||||
return uploadFile(mediaId, file);
|
||||
} catch (WxErrorException e) {
|
||||
log.error("[mediaDownload][media({}) 第 ({}) 次下载失败]", mediaId, i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String uploadFile(String mediaId, File file) {
|
||||
String path = mediaId + "." + FileTypeUtil.getType(file);
|
||||
return fileApi.createFile(path, FileUtil.readBytes(file));
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +1,8 @@
|
||||
package cn.iocoder.yudao.module.mp.service.message;
|
||||
|
||||
import cn.hutool.core.io.FileTypeUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||
import cn.iocoder.yudao.module.mp.controller.admin.message.vo.MpMessagePageReqVO;
|
||||
import cn.iocoder.yudao.module.mp.controller.admin.message.vo.MpMessageSendReqVO;
|
||||
import cn.iocoder.yudao.module.mp.convert.message.MpMessageConvert;
|
||||
@ -17,9 +14,11 @@ import cn.iocoder.yudao.module.mp.enums.message.MpMessageSendFromEnum;
|
||||
import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
|
||||
import cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils;
|
||||
import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
|
||||
import cn.iocoder.yudao.module.mp.service.material.MpMaterialService;
|
||||
import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO;
|
||||
import cn.iocoder.yudao.module.mp.service.user.MpUserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
|
||||
@ -31,7 +30,6 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Validator;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 粉丝消息表 Service 实现类
|
||||
@ -48,6 +46,8 @@ public class MpMessageServiceImpl implements MpMessageService {
|
||||
private MpAccountService mpAccountService;
|
||||
@Resource
|
||||
private MpUserService mpUserService;
|
||||
@Resource
|
||||
private MpMaterialService mpMaterialService;
|
||||
|
||||
@Resource
|
||||
private MpMessageMapper mpMessageMapper;
|
||||
@ -56,9 +56,6 @@ public class MpMessageServiceImpl implements MpMessageService {
|
||||
@Lazy // 延迟加载,解决循环依赖的问题
|
||||
private MpServiceFactory mpServiceFactory;
|
||||
|
||||
@Resource
|
||||
private FileApi fileApi;
|
||||
|
||||
@Resource
|
||||
private Validator validator;
|
||||
|
||||
@ -69,7 +66,6 @@ public class MpMessageServiceImpl implements MpMessageService {
|
||||
|
||||
@Override
|
||||
public void receiveMessage(String appId, WxMpXmlMessage wxMessage) {
|
||||
WxMpService mpService = mpServiceFactory.getRequiredMpService(appId);
|
||||
// 获得关联信息
|
||||
MpAccountDO account = mpAccountService.getAccountFromCache(appId);
|
||||
Assert.notNull(account, "公众号账号({}) 不存在", appId);
|
||||
@ -79,7 +75,7 @@ public class MpMessageServiceImpl implements MpMessageService {
|
||||
// 记录消息
|
||||
MpMessageDO message = MpMessageConvert.INSTANCE.convert(wxMessage, account, user);
|
||||
message.setSendFrom(MpMessageSendFromEnum.USER_TO_MP.getFrom());
|
||||
downloadMessageMedia(mpService, message);
|
||||
downloadMessageMedia(message);
|
||||
mpMessageMapper.insert(message);
|
||||
}
|
||||
|
||||
@ -97,6 +93,7 @@ public class MpMessageServiceImpl implements MpMessageService {
|
||||
// 记录消息
|
||||
MpMessageDO message = MpMessageConvert.INSTANCE.convert(sendReqBO, account, user);
|
||||
message.setSendFrom(MpMessageSendFromEnum.MP_TO_USER.getFrom());
|
||||
// TODO 芋艿:downloadMessageMedia
|
||||
mpMessageMapper.insert(message);
|
||||
|
||||
// 转换返回 WxMpXmlOutMessage 对象
|
||||
@ -124,7 +121,7 @@ public class MpMessageServiceImpl implements MpMessageService {
|
||||
// 记录消息
|
||||
MpMessageDO message = MpMessageConvert.INSTANCE.convert(wxMessage, account, user);
|
||||
message.setSendFrom(MpMessageSendFromEnum.MP_TO_USER.getFrom());
|
||||
downloadMessageMedia(mpService, message);
|
||||
downloadMessageMedia(message);
|
||||
mpMessageMapper.insert(message);
|
||||
return message;
|
||||
}
|
||||
@ -132,38 +129,17 @@ public class MpMessageServiceImpl implements MpMessageService {
|
||||
/**
|
||||
* 下载消息使用到的媒体文件,并上传到文件服务
|
||||
*
|
||||
* @param mpService 公众号 Service
|
||||
* @param message 消息
|
||||
*/
|
||||
private void downloadMessageMedia(WxMpService mpService, MpMessageDO message) {
|
||||
private void downloadMessageMedia(MpMessageDO message) {
|
||||
if (StrUtil.isNotEmpty(message.getMediaId())) {
|
||||
message.setMediaUrl(downloadMedia(mpService, message.getMediaId()));
|
||||
message.setMediaUrl(mpMaterialService.downloadMaterialUrl(message.getAccountId(),
|
||||
message.getMediaId(), MpUtils.getMediaFileType(message.getType())));
|
||||
}
|
||||
if (StrUtil.isNotEmpty(message.getThumbMediaId())) {
|
||||
message.setThumbMediaUrl(downloadMedia(mpService, message.getThumbMediaId()));
|
||||
message.setThumbMediaUrl(mpMaterialService.downloadMaterialUrl(message.getAccountId(),
|
||||
message.getThumbMediaId(), WxConsts.MediaFileType.THUMB));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载微信媒体文件的内容,并上传到文件服务
|
||||
*
|
||||
* 为什么要下载?媒体文件在微信后台保存时间为 3 天,即 3 天后 media_id 失效。
|
||||
*
|
||||
* @param mpService 微信公众号 Service
|
||||
* @param mediaId 媒体文件编号
|
||||
* @return 上传后的 URL
|
||||
*/
|
||||
private String downloadMedia(WxMpService mpService, String mediaId) {
|
||||
try {
|
||||
// 第一步,从公众号下载媒体文件
|
||||
File file = mpService.getMaterialService().mediaDownload(mediaId);
|
||||
// 第二步,上传到文件服务
|
||||
String path = mediaId + "." + FileTypeUtil.getType(file);
|
||||
return fileApi.createFile(path, FileUtil.readBytes(file));
|
||||
} catch (WxErrorException e) {
|
||||
log.error("[mediaDownload][media({}) 下载失败]", mediaId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ import {getMessagePage, sendMessage} from '@/api/mp/message'
|
||||
}, {
|
||||
...this.objData,
|
||||
type: this.objData.repType,
|
||||
content: this.objData.repContent,
|
||||
// content: this.objData.repContent,
|
||||
// TODO 芋艿:临时适配,保证可用
|
||||
})).then(response => {
|
||||
this.sendLoading = false
|
||||
|
@ -4,15 +4,12 @@
|
||||
-->
|
||||
<template>
|
||||
<el-tabs type="border-card" v-model="objData.repType" @tab-click="handleClick">
|
||||
<!-- 类型 1:文本 -->
|
||||
<el-tab-pane name="text">
|
||||
<span slot="label"><i class="el-icon-document"></i> 文本</span>
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
placeholder="请输入内容"
|
||||
v-model="objData.repContent">
|
||||
</el-input>
|
||||
<el-input type="textarea" :rows="5" placeholder="请输入内容" v-model="objData.content" />
|
||||
</el-tab-pane>
|
||||
<!-- 类型 2:图片 -->
|
||||
<el-tab-pane name="image">
|
||||
<span slot="label"><i class="el-icon-picture"></i> 图片</span>
|
||||
<el-row>
|
||||
@ -29,19 +26,10 @@
|
||||
<el-button type="success" @click="openMaterial">素材库选择<i class="el-icon-circle-check el-icon--right"></i></el-button>
|
||||
</el-col>
|
||||
<el-col :span="12" class="col-add">
|
||||
<el-upload
|
||||
:action="actionUrl"
|
||||
:headers="headers"
|
||||
multiple
|
||||
:limit="1"
|
||||
:on-success="handleUploadSuccess"
|
||||
:file-list="fileList"
|
||||
:before-upload="beforeImageUpload"
|
||||
:data="uploadData">
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
|
||||
:before-upload="beforeImageUpload" :on-success="handleUploadSuccess">
|
||||
<el-button type="primary">上传图片</el-button>
|
||||
<div slot="tip" class="el-upload__tip">
|
||||
支持bmp/png/jpeg/jpg/gif格式,大小不超过2M
|
||||
</div>
|
||||
<div slot="tip" class="el-upload__tip">支持 bmp/png/jpeg/jpg/gif 格式,大小不超过 2M</div>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -69,12 +57,7 @@
|
||||
<el-button type="success" @click="openMaterial">素材库选择<i class="el-icon-circle-check el-icon--right"></i></el-button>
|
||||
</el-col>
|
||||
<el-col :span="12" class="col-add">
|
||||
<el-upload
|
||||
:action="actionUrl"
|
||||
:headers="headers"
|
||||
multiple
|
||||
:limit="1"
|
||||
:on-success="handleUploadSuccess"
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :on-success="handleUploadSuccess"
|
||||
:file-list="fileList"
|
||||
:before-upload="beforeVoiceUpload"
|
||||
:data="uploadData">
|
||||
@ -188,9 +171,9 @@
|
||||
},
|
||||
props: {
|
||||
objData:{
|
||||
type:Object
|
||||
type: Object
|
||||
},
|
||||
//图文类型:1、已发布图文;2、草稿箱图文
|
||||
// 图文类型:1、已发布图文;2、草稿箱图文
|
||||
newsType:{
|
||||
type: String,
|
||||
default: "1"
|
||||
|
Loading…
Reference in New Issue
Block a user