派生自 projectDept/qhighschool

胡仁荣
2023-07-18 885290e4d0d0c7fad3f538d901c616e49c3d6985
oss分块上传
13个文件已修改
2个文件已添加
796 ■■■■■ 已修改文件
pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/base/model/Result.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/base/service/ICacheService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/base/service/impl/RedisCacheBean.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/controller/HweiYunOBSController.java 79 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/stucontroller/StuLiveController.java 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/teach/live/model/AccessLog.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/teach/live/utils/RedisCache.java 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/teach/res/model/Res.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/teach/res/service/HweiYunOBSService.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/teach/res/service/IFileService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/teach/res/service/impl/FileService.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java 226 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/qxueyou/scc/teach/res/service/impl/ResService.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.properties 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -435,6 +435,12 @@
            <classifier>jdk15</classifier><!-- 指定jdk版本 -->
        </dependency>
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>2.8.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
src/main/java/com/qxueyou/scc/base/model/Result.java
@@ -1,5 +1,7 @@
package com.qxueyou.scc.base.model;
import com.qxueyou.scc.base.util.CollectionUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@@ -31,7 +33,10 @@
    
    /** 结果数据  */
    private Object data;
    public static final String MSG_SUCCESS = "success";
    public static final String MSG_FAIL = "fail";
    /**
     * 非法请求状态码
     */
@@ -40,7 +45,7 @@
    public static final Result SUCCESS = new Result(true);
    
    public static final Result FAIL = new Result(false);
    public Result() {
        super();
    }
@@ -70,6 +75,11 @@
        this.msg=msg;
        this.data=data;
    }
    public Result(boolean success, Object... objs) {
        this.success = success;
        this.msg = success ? MSG_SUCCESS : MSG_FAIL;
        this.data = CollectionUtils.newObjectMap(objs);
    }
    
    public boolean isSuccess() {
        return success;
src/main/java/com/qxueyou/scc/base/service/ICacheService.java
@@ -1,5 +1,7 @@
package com.qxueyou.scc.base.service;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -179,5 +181,6 @@
     */
    boolean setIfAbsent(String key, Object obj);
    <K,V> RedisTemplate<K,V> template();
}
src/main/java/com/qxueyou/scc/base/service/impl/RedisCacheBean.java
@@ -209,5 +209,9 @@
        redisTemplate.opsForHash().put(key, hashKey, value);
    }
    @SuppressWarnings("unchecked")
    @Override
    public <K, V> RedisTemplate<K, V> template() {
        return redisTemplate;
    }
}
src/main/java/com/qxueyou/scc/controller/HweiYunOBSController.java
@@ -6,11 +6,16 @@
import cn.hutool.core.util.StrUtil;
//import cn.hutool.core.io.FileUtil;
import com.aliyun.oss.OSSException;
import com.obs.services.exception.ObsException;
import com.obs.services.model.PutObjectResult;
import com.qxueyou.scc.base.model.FileMeta;
import com.qxueyou.scc.base.model.Result;
import com.qxueyou.scc.base.util.ClientUtils;
import com.qxueyou.scc.teach.res.service.HweiYunOBSService;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@@ -35,6 +40,7 @@
@RestController
@RequestMapping("/file")// @RequestMapping("/file")
public class HweiYunOBSController {
    private final Logger log = LogManager.getLogger("FileController");
    @Resource
    private HweiYunOBSService hweiYunOBSService;
@@ -45,7 +51,6 @@
        if (ObjectUtils.isEmpty(file) || file.getSize() <= 0) {
            return null;
        }
//        if (FileUtil.isEmpty(file)) {
//            return new Result(false,"文件为空");
//        }
@@ -54,21 +59,63 @@
        return test;
    }
//    @RequestMapping(value = "fenpian", method = RequestMethod.POST)
//    public  Map<String, Object>  fpsave(@RequestParam(value = "file", required = false) MultipartFile file) throws IOException {
//
//        if (ObjectUtils.isEmpty(file) || file.getSize() <= 0) {
//            return null;
//        }
//
////        if (FileUtil.isEmpty(file)) {
////            return new Result(false,"文件为空");
////        }
////        final List<FileMeta> test = hweiYunOBSService.fileUpload(file, file.getOriginalFilename());
//        Map<String, Object> fnepian = hweiYunOBSService.fnepian(file, file.getOriginalFilename());
////        return ResponseVO.ok("执行成功",test);
//        return fnepian;
//    }
    /**
     * 文件上传接口:为客户端提供多线程分片上传接口
     * 返回状态值:200代表成功,500代表上传失败,205代表需重新尝试
     *
     * @param identifier 唯一id,需客户端保证唯一性,相同文件保证唯一即可,非MD5
     * @return
     * @TODO : 目前缺少对 各模块文件个数、文件格式、文件大小的上传控制,统一增加在configFileModule表里面即可实现 1 图片; 2 文档 3 视频 4 音频
     */
    @RequestMapping(value = "/uploadChunk", headers = "content-type=multipart/*", method = RequestMethod.POST)
    public @ResponseBody FileMeta doUploadPublic(MultipartFile file, HttpServletResponse response,
                            Integer chunkNumber, Integer totalChunks, long chunkSize, long totalSize, String identifier, String filename, Integer currentChunkSize) {
        FileMeta fileMeta = new FileMeta();
        try {
            Result uploadResult = null;
            uploadResult = hweiYunOBSService.uploadChunk(file.getInputStream(), identifier.concat(ClientUtils.getUserId()), chunkNumber, currentChunkSize, totalChunks, filename);
            fileMeta.setFileId(uploadResult.getDataT("fileId"));
            fileMeta.setPath(uploadResult.getDataT("path"));
            if (!uploadResult.isSuccess()) {
                response.setStatus(205);
            }
        } catch (OSSException e) {
            response.setStatus(500);
            log.error(e, e);
        } catch (Exception e) {
            log.error("上传模块解析出错:" + e.getMessage(), e);
            response.setStatus(500);
        }
        fileMeta.setFileName(filename);
        fileMeta.setFileSize(String.valueOf(totalSize));
        fileMeta.setFileType(null);
        return fileMeta;
    }
    /**
     * 初始化分片上传任务
     *
     * @return
     */
    @RequestMapping(value = "/uploadChunk/init", method = RequestMethod.POST)
    public @ResponseBody
    Result initUploadChunk(String identifier, String fileName,String md5) {
        //如果MD5的对应文件存在则直接返回
//        Result result = fileService.checkMd5(md5,fileName);
        return hweiYunOBSService.initUploadChunk(identifier.concat(ClientUtils.getUserId()), fileName,md5);
    }
    @RequestMapping(value = "delete", method = RequestMethod.POST)
    public Result delete(@RequestParam(value = "fileName", required = false)  String fileName) {
src/main/java/com/qxueyou/scc/stucontroller/StuLiveController.java
@@ -1,10 +1,15 @@
package com.qxueyou.scc.stucontroller;
import java.util.*;
import java.util.concurrent.TimeUnit;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qxueyou.scc.base.dao.CommonDAO;
import com.qxueyou.scc.sdk.MTCloud;
import com.qxueyou.scc.teach.live.model.AccessLog;
import com.qxueyou.scc.teach.live.utils.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
@@ -27,6 +32,7 @@
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
@Slf4j
@Api(tags="直播接口-学员端")
@RestController
@CrossOrigin
@@ -41,6 +47,12 @@
    
    @Autowired
    MediaLiveDAO dao;
    @Autowired
    RedisCache redisCache;
    @Autowired
    CommonDAO commonDAO;
    
    private final static short[] PUBLIC_LIVE_STATUS = new short[] {
            MediaVideoLive.STATUS_LIVE_LIVE,MediaVideoLive.STATUS_LIVE_PAUSE,
@@ -120,28 +132,51 @@
     * @return
     */
    @GetMapping(value = "view")
    public Result view(String couresId,String userId,String userName) throws Exception {
    public Result view(String couresId,String userId,String userName,String logId) throws Exception {
        AccessLog log=new AccessLog();
        if(StringUtils.isEmpty(logId)){
//            String ip = IpUtils.getIpAddr(request);
//            String cityInfo = null;
//            try {
//                cityInfo = IpUtils.getCityInfo(ip);
//            } catch (Exception e) {
//                log.error("获取ip归属地信息失败!");
//            }
            log.setCourseId(couresId);
            log.setEnterTime(new Date());
            log.setType("guangxi");
            log.setName(userName);
//            log.setIp(ip);
//            log.setIpAttribution(cityInfo);
            commonDAO.save(log);
        }else {
            String liveUrl = redisCache.getCacheObject("LIVE_URL" + userId);
            return new Result(true, "success",liveUrl);
        }
        MTCloud client = new MTCloud();
        String userRole = null;
        HashMap<Object,Object> options = new HashMap<Object, Object>();
        if(userId.equals("")){
            userId= randomId();
        }
        if(userName.equals("") || userName==null){
            userName= "游客";
        }
            userRole=MTCloud.ROLE_GUEST;
        }else {
            userRole=MTCloud.ROLE_USER;
        }
        String res = client.courseAccess(couresId,userId,userName,userRole, 10000, options);
        String res = client.courseAccess(couresId,userId,userName, MTCloud.ROLE_USER, 10000, options);
        JSONObject jsonObject = JSON.parseObject(res);
        if(jsonObject.getString("code").equals("0")){
            JSONObject data = jsonObject.getJSONObject("data");
            String liveUrl = (String) data.get("liveUrl");
            StringBuffer redisLiveUrl = new StringBuffer("LIVE_URL");
            redisLiveUrl=redisLiveUrl.append(userId);
            redisCache.setCacheObject(redisLiveUrl.toString(),liveUrl,5, TimeUnit.MINUTES);
            return new Result(true, "success",liveUrl);
        }
src/main/java/com/qxueyou/scc/teach/live/model/AccessLog.java
New file
@@ -0,0 +1,50 @@
package com.qxueyou.scc.teach.live.model;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.Date;
/**
 * 访问日志
 */
@Data
@NoArgsConstructor//无参构造方法
@AllArgsConstructor//全参构造方法
//@EqualsAndHashCode(callSuper = true)
@Table(name="sa_access_log")
public class AccessLog implements Serializable {
    private static final long serialVersionUID = -1979488824632702882L;
    @ApiModelProperty(value = "编号")
    private  String logId;
    @ApiModelProperty(value = "姓名")
    private  String name;
    @ApiModelProperty(value = "直播间id")
    private String courseId;
    @ApiModelProperty(value = "访问ip")
    private String ip;
    @ApiModelProperty(value = "进入直播开始时间")
    private Date enterTime;
    @ApiModelProperty(value = "离开直播时间")
    private Date leaveTime;
    @ApiModelProperty(value = "如果是userId在平台查询不到则是游客")
    private String userId;
    @ApiModelProperty(value = "ip归属地信息")
    private String ipAttribution;
    @ApiModelProperty(value = "roadShow:路演,conference:会议")
    private String type;
    @ApiModelProperty(value = "创建时间")
    private Date createTime;
    @ApiModelProperty(value = "修改时间")
    private Date updateTime;
    //是否删除:0未删除 1删除
    @ApiModelProperty(value = "删除标识")
    private Integer deleteFlag;
}
src/main/java/com/qxueyou/scc/teach/live/utils/RedisCache.java
New file
@@ -0,0 +1,270 @@
package com.qxueyou.scc.teach.live.utils;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache
{
    @Resource
    public RedisTemplate redisTemplate;
    public Long getIncrValue(String key) {
        return redisTemplate.opsForValue().increment(key, 0l);
    }
    public Long incr(String key) {
        return redisTemplate.opsForValue().increment(key, 1l);
    }
    public void expire(String key, Long timeout, TimeUnit unit) {
        redisTemplate.expire(key, timeout, unit);
    }
    public void delete(String key) {
        redisTemplate.delete(key);
    }
    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final String key, final T value)
    {
        redisTemplate.opsForValue().set(key, value);
    }
    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     * @param timeout 时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
    {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }
    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout)
    {
        return expire(key, timeout, TimeUnit.SECONDS);
    }
    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @param unit 时间单位
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit)
    {
        return redisTemplate.expire(key, timeout, unit);
    }
    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key)
    {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }
    /**
     * 删除单个对象
     *
     * @param key
     */
    public void deleteObject(final String key)
    {
         redisTemplate.delete(key);
    }
    /**
     * 删除集合对象
     *
     * @param collection 多个对象
     * @return
     */
    public void deleteObject(final Collection collection)
    {
         redisTemplate.delete(collection);
    }
    /**
     * 缓存List数据
     *
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> long setCacheList(final String key, final List<T> dataList)
    {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }
    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public <T> List<T> getCacheList(final String key)
    {
        return redisTemplate.opsForList().range(key, 0, -1);
    }
    /**
     * 缓存Set
     *
     * @param key 缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
    {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext())
        {
            setOperation.add(it.next());
        }
        return setOperation;
    }
    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final String key)
    {
        return redisTemplate.opsForSet().members(key);
    }
    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
    {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }
    /**
     *  缓存Map,并设置有效期
     * @param key 键
     * @param dataMap 键值对
     * @param timeout 时间
     * @param unit  时间单位
     * @param <T>
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap,long timeout, final TimeUnit unit)
    {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
            redisTemplate.opsForHash().getOperations().expire(key,timeout,unit);
        }
    }
    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key)
    {
        return redisTemplate.opsForHash().entries(key);
    }
    /**
     * 往Hash中存入数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
    {
        redisTemplate.opsForHash().put(key, hKey, value);
    }
    /**
     * 获取Hash中的数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public <T> T getCacheMapValue(final String key, final String hKey)
    {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }
    /**
     * 删除Hash中的数据
     *
     * @param key
     * @param hkey
     */
    public void delCacheMapValue(final String key, final String hkey)
    {
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.delete(key, hkey);
    }
    /**
     * 获取多个Hash中的数据
     *
     * @param key Redis键
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
    {
        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }
    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(final String pattern)
    {
        return redisTemplate.keys(pattern);
    }
}
src/main/java/com/qxueyou/scc/teach/res/model/Res.java
@@ -33,7 +33,7 @@
    private String creator;
    private String createId;
    private String updator;
    private String updateId;
        private String updateId;
    private boolean deleteFlag;
    private String coverPageUrl;
    private String status;
src/main/java/com/qxueyou/scc/teach/res/service/HweiYunOBSService.java
@@ -2,6 +2,7 @@
import com.obs.services.model.PutObjectResult;
import com.qxueyou.scc.base.model.FileMeta;
import com.qxueyou.scc.base.model.Result;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@@ -53,4 +54,25 @@
     * @return: java.io.InputStream
     */
    InputStream fileDownload(String objectKey);
    /**
     * oss 分片上传
     *
     * @param input
     * @param uniqueId
     * @param chunkNumber
     * @param totalChunk
     * @return
     */
    Result uploadChunk(InputStream input, String uniqueId, int chunkNumber, long chunkSize, int totalChunk, String fileName);
    /**
     * 初始化
     *
     * @param uniqueId
     * @param fileName
     * @param md5
     * @return
     */
    Result initUploadChunk(String uniqueId, String fileName, String md5);
}
src/main/java/com/qxueyou/scc/teach/res/service/IFileService.java
@@ -35,5 +35,6 @@
     * @return
     */
    InputStream readStreamById(String id);
}
    Result checkMd5(String md5, String fileName);
}
src/main/java/com/qxueyou/scc/teach/res/service/impl/FileService.java
@@ -239,4 +239,32 @@
        }
        return null;
    }
    @Override
    public Result checkMd5(String md5, String fileName) {
//        if(StringUtils.isBlank(md5)){
//            return Result.FAIL;
//        }
//
//
//            Boolean objectExist;
//            objectExist = authOssService.doseObjectExist(resFile.getPath());
//
//            if (objectExist) {
//
//                ResFileDO resFileToDB = new ResFileDO();
//                BeanUtils.copyProperties(resFile, resFileToDB);
//                resFileToDB.setId(null);
//                TraceUtils.setCreateTrace(resFileToDB);
//                ResFileDO resFileDB = save(resFileToDB);
//
//                Result result = new Result(true, "fileId", resFileDB.getId(), "path", resFileDB.getPath(),"fileName",fileName,
//                        "fileSize",resFileToDB.getSize(),"fileType",resFileToDB.getFileType(),"hit",true);
//                result.setResultCode(201);
//                return result;
//
//        }
        return Result.FAIL;
    }
}
src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java
@@ -7,10 +7,12 @@
import com.obs.services.model.*;
import com.qxueyou.scc.base.model.FileMeta;
import com.qxueyou.scc.base.model.Result;
import com.qxueyou.scc.base.util.CollectionUtils;
import com.qxueyou.scc.base.util.QFileUtils;
import com.qxueyou.scc.base.util.UUIDUtils;
import com.qxueyou.scc.base.service.ICacheService;
import com.qxueyou.scc.base.service.impl.CommonAppService;
import com.qxueyou.scc.base.util.*;
import com.qxueyou.scc.config.HweiOBSConfig;
import com.qxueyou.scc.teach.res.model.Res;
import com.qxueyou.scc.teach.res.model.ResDir;
import com.qxueyou.scc.teach.res.model.ResFile;
import com.qxueyou.scc.teach.res.service.HweiYunOBSService;
import com.qxueyou.scc.teach.res.service.IFileService;
@@ -21,6 +23,7 @@
import org.apache.logging.log4j.Logger;
import org.aspectj.util.FileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@@ -42,7 +45,7 @@
 */
@Slf4j
@Service
public class HweiYunOBSServiceImpl implements HweiYunOBSService {
public class HweiYunOBSServiceImpl extends CommonAppService implements HweiYunOBSService {
    private final Logger log = LogManager.getLogger(HweiYunOBSServiceImpl.class);
    @Autowired
@@ -50,6 +53,13 @@
    @Autowired
    FileService fileService;
    /**
     * redis 模板
     */
    @Autowired
    ICacheService cache;
    public final static String FILE_TYPE_VIDEO = "video";
@@ -315,4 +325,212 @@
        }
        return null;
    }
    /**
     * 文件分片上传实现逻辑,各分片是多线程上传
     *
     * @param input       输入流
     * @param uniqueId    资源唯一id(前端传入)
     * @param chunkNumber 分片编号
     * @param chunkSize   分片大小
     * @param totalChunk  分片总数
     * @param fileName    文件名
     * @return
     */
    public Result uploadChunk(InputStream input, String uniqueId, int chunkNumber, long chunkSize, int totalChunk,
                              String fileName) {
        HashOperations<Object, Object, Object> _cacheMap = cache.template().opsForHash();
        ObsClient obsClient = new ObsClient(hweiOBSConfig.getAccessKey(),hweiOBSConfig.getSecurityKey(),hweiOBSConfig.getEndPoint());
        //给初始化预留1.2秒钟的时间
        try {
            if (chunkNumber < 4) {
                Thread.sleep(1200l);
            }
        } catch (InterruptedException e) {
            log.error(e.getMessage(), e);
        }
        //获取分片上传id(阿里云OSS初始化分片上传任务返回,和uniqueId及key一一对应),若获取不到,则10秒内循环十次直至获取到,否则返回错误
        String uploadId = getUploadId(uniqueId);
        if (uploadId == null) {
            return new Result(false);
        }
        String key = (String) _cacheMap.get(uniqueId + ClientUtils.getUserId(), "key");
        boolean exists = true;
        //上传片段
        if (!_cacheMap.hasKey(uploadId, String.valueOf(chunkNumber))) {
            //开始上传
            UploadPartRequest uploadPartRequest = new UploadPartRequest(hweiOBSConfig.getBucketName(), key);
            uploadPartRequest.setUploadId(uploadId);
            // 设置分段号,范围是1~10000
            uploadPartRequest.setPartNumber(chunkNumber);
            // 设置分段大小
            uploadPartRequest.setPartSize(chunkSize);
            uploadPartRequest.setInput(input);
            UploadPartResult partResult = obsClient.uploadPart(uploadPartRequest);
            exists = false;
            _cacheMap.put(uploadId, String.valueOf(chunkNumber), partResult.getEtag());
        }
        //全部片段上传完成,调用client complete方法完成分片上传任务,并插入数据库
        if (_cacheMap.size(uploadId) != null
                && _cacheMap.size(uploadId) >= totalChunk
                && !_cacheMap.hasKey(uniqueId + ClientUtils.getUserId(), "finish")) {
            List<PartEtag> tags = new ArrayList<>(5);
            _cacheMap.entries(uploadId).forEach((k, v) -> {
                tags.add(new PartEtag((String) v, Integer.parseInt((String) k)));
            });
            CompleteMultipartUploadResult completeMultipartUploadResult = obsClient.completeMultipartUpload(new CompleteMultipartUploadRequest(hweiOBSConfig.getBucketName(), key, uploadId,
                    tags));
            System.out.println(completeMultipartUploadResult.getObjectUrl());
            ObjectMetadata metadata = obsClient.getObjectMetadata(hweiOBSConfig.getBucketName(), key);
//            obsClient.setObjectAcl(hweiOBSConfig.getBucketName(), key, AccessControlList.REST_CANNED_PUBLIC_READ);
            //标记完成
            _cacheMap.put(uniqueId + ClientUtils.getUserId(), "finish", "true");
//            //更新数据库信息
            updateFile((String) _cacheMap.get(uniqueId + ClientUtils.getUserId(), "fileId"), metadata.getContentLength(), metadata.getContentMd5(), key, fileName);
            //销毁缓存
            cache.template().expire(uniqueId + ClientUtils.getUserId(), 1, TimeUnit.MINUTES);
        }
        return new Result(true, "hit", exists, "fileId", _cacheMap.get(uniqueId + ClientUtils.getUserId(), "fileId"), "path", _cacheMap.get(uniqueId + ClientUtils.getUserId(), "path"));
    }
    @Override
    public Result initUploadChunk(String uniqueId, String fileName, String md5) {
        String path = getDestPath(fileName);
        String key = chopPath(path);
        //清缓存
        cache.template().delete(uniqueId + ClientUtils.getUserId());
        InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(hweiOBSConfig.getBucketName(), key);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setObjectStorageClass(StorageClassEnum.STANDARD);
        initiateMultipartUploadRequest.setMetadata(new ObjectMetadata());
        //调用OSS SDK 接口返回uploadId
        ObsClient obsClient = new ObsClient(hweiOBSConfig.getAccessKey(),hweiOBSConfig.getSecurityKey(),hweiOBSConfig.getEndPoint());
        String uploadId = obsClient.initiateMultipartUpload(initiateMultipartUploadRequest).getUploadId();
        //为配合分片上传,后台先新建文件记录
        ResFile file = newFileToDB(fileName, path, getFileType(fileName), 0l, md5);
        //添加到缓存
        cache.template().opsForHash().put(uniqueId + ClientUtils.getUserId(), "uploadId", uploadId);
        cache.template().opsForHash().put(uniqueId + ClientUtils.getUserId(), "key", key);
        cache.template().opsForHash().put(uniqueId + ClientUtils.getUserId(), "path", path);
        cache.template().opsForHash().put(uniqueId + ClientUtils.getUserId(), "fileId", file.getFileId());
        //防止产生过多缓存垃圾
        cache.template().expire(uniqueId + ClientUtils.getUserId(), 1, TimeUnit.DAYS);
        ResFile file1 = new ResFile();
        file1.setUpdateId(uploadId);
        file1.setFileId(file.getFileId());
        file1.setPath(file.getPath());
        return new Result(true,"cs",file1);
    }
    /**
     * 更新文件信息到数据库
     *
     * @param fileId
     * @param fileLength
     * @param md5
     * @param path
     * @param fileName
     * @return
     */
    private ResFile updateFile(String fileId, long fileLength, String md5, String path, String fileName) {
        ResFile file = new ResFile();
        file.setFileId(fileId);
        file.setSize(fileLength);
        file.setMd5Hash(md5);
        file.setPath(path);
        file.setFileName(fileName);
        cache.template().opsForList().rightPush("BaseOssServiceUpdate", file);
        return file;
    }
    /**
     * 插入文件信息到数据库
     *
     * @param name
     * @param relativePath 相对路径
     * @param type         文件类型,非文件格式
     * @return
     */
    private ResFile newFileToDB(String name, String relativePath, String type, Long fileSize, String md5) {
        ResFile file = new ResFile();
        TraceUtils.setCreateTrace(file);
        file.setFileName(name);
        file.setFileFormat(QFileUtils.getFileFormat(name));
        file.setFileType(type);
        file.setMd5Hash(md5);
        file.setPath(relativePath);
        file.setSize(fileSize == null ? 0 : fileSize);
        file.setDeleteFlag(false);
        save(file);
        return file;
    }
    /**
     * 如果路径以 / 或 \ 开头,需要截取
     *
     * @param destPath
     * @return
     */
    public String chopPath(String destPath) {
        if (destPath.startsWith("/") || destPath.startsWith("\\")) {
            return destPath.substring(1);
        }
        return destPath;
    }
    /**
     * 获取分片上传id(阿里云OSS初始化分片上传任务返回,和uniqueId及key一一对应),若获取不到,则10秒内循环十次直至获取到,否则返回错误
     *
     * @param uniqueId
     * @return
     */
    private String getUploadId(String uniqueId) {
        HashOperations<Object, Object, Object> _cacheMap = cache.template().opsForHash();
        String uploadId = (String) _cacheMap.get(uniqueId + ClientUtils.getUserId(), "uploadId");
        int tryCount = 0;
        while (uploadId == null && tryCount < 10) {
            try {
                Thread.sleep(1000l);
                uploadId = (String) _cacheMap.get(uniqueId + ClientUtils.getUserId(), "uploadId");
                tryCount++;
            } catch (InterruptedException e) {
                log.error(e, e);
            }
        }
        return uploadId;
    }
}
src/main/java/com/qxueyou/scc/teach/res/service/impl/ResService.java
@@ -6,6 +6,11 @@
import javax.annotation.PostConstruct;
import com.obs.services.ObsClient;
import com.obs.services.model.HttpMethodEnum;
import com.obs.services.model.TemporarySignatureRequest;
import com.obs.services.model.TemporarySignatureResponse;
import com.qxueyou.scc.config.HweiOBSConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Scheduled;
@@ -46,6 +51,9 @@
    @Autowired
    private ApplicationContext appContext;
    @Autowired
    private HweiOBSConfig hweiOBSConfig;
    @Autowired
    private IClassLectureService classLectureService;
@@ -313,8 +321,18 @@
//                     CollectionUtils.newObjectMap("path", path, "name", res.getName(), "coverPageUrl", res.getCoverPageUrl(), "size",
//                             this.classLectureService.readDocPageCount(res.getItemDestId())));//文件的页数
//        }else {
        // URL有效期,3600秒
        long expireSeconds = 3600L;
        TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireSeconds);
        //设置桶名,一般都是写在配置里,这里直接赋值即可
        request.setBucketName(hweiOBSConfig.getBucketName());
        //这里相当于设置你上传到obs的文件路
        request.setObjectKey((String) path);
        ObsClient obsClient = new ObsClient(hweiOBSConfig.getAccessKey(),hweiOBSConfig.getSecurityKey(),hweiOBSConfig.getEndPoint());
        TemporarySignatureResponse temporarySignatureResponse=obsClient.createTemporarySignature(request);
             return new Result(true, "success",
                     CollectionUtils.newObjectMap("path", path, "name", res.getName(), "coverPageUrl", res.getCoverPageUrl(), "size", 0));
                     CollectionUtils.newObjectMap("path", temporarySignatureResponse.getSignedUrl(), "name", res.getName(), "coverPageUrl", res.getCoverPageUrl(), "size", 0));
//        }
    }
src/main/resources/application.properties
@@ -20,7 +20,7 @@
#mysqldb.datasource.url=jdbc:mysql://rds88t2of1fi184y4s5wo.mysql.rds.aliyuncs.com:3306/scc?useUnicode=true&characterEncoding=GBK&characterSetResults=GBK&zeroDateTimeBehavior=convertToNull
#mysqldb.datasource.url=jdbc:mysql://10.1.80.52:3306/rsdb?useUnicode=true&characterEncoding=GBK&characterSetResults=GBK&zeroDateTimeBehavior=convertToNull
mysqldb.datasource.url=jdbc:mysql://110.41.147.200:3306/scc?useUnicode=true&characterEncoding=GBK&characterSetResults=GBK&zeroDateTimeBehavior=convertToNull
mysqldb.datasource.url=jdbc:mysql://localhost:3306/scc?useUnicode=true&characterEncoding=GBK&characterSetResults=GBK&zeroDateTimeBehavior=convertToNull
mysqldb.datasource.username=root
#mysqldb.datasource.username=rs
#######\uFFFD\uFFFD\uFFFD\uFFFD\u03AA\uFFFD\uFFFD\u05F0\uFFFD\uFFFD\u03F5\u0373\uFFFD\uFFFD\u012C\uFFFD\uFFFD\uFFFD\u00FB\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u02FF\uFFFD#############
@@ -102,3 +102,15 @@
wx.app.secret=95c5470a52a2c4e037741f82246f4d86
logging.config=classpath:log4j2.xml
#oss.public
oss.public.access-key-id=MPTI87UMKZLBSWK2DG4V
oss.public.bucket-name=qxueyou
oss.public.end-point=obs.cn-north-4.myhuaweicloud.com
oss.public.secret-access-key=ziNypQwspMYQeIlM2mSHwlr9hS4Xw9VlH316Ur3C
#oss.auth
oss.auth.access-key-id=MPTI87UMKZLBSWK2DG4V
oss.auth.bucket-name=qxueyou-video
oss.auth.end-point=obs.cn-north-4.myhuaweicloud.com
oss.auth.secret-access-key=ziNypQwspMYQeIlM2mSHwlr9hS4Xw9VlH316Ur3C