From 885290e4d0d0c7fad3f538d901c616e49c3d6985 Mon Sep 17 00:00:00 2001 From: 胡仁荣 <897853850@qq.com> Date: 星期二, 18 七月 2023 18:15:58 +0800 Subject: [PATCH] oss分块上传 --- src/main/java/com/qxueyou/scc/teach/live/utils/RedisCache.java | 270 +++++++++++++++++++ src/main/java/com/qxueyou/scc/controller/HweiYunOBSController.java | 79 ++++- src/main/java/com/qxueyou/scc/teach/res/service/impl/FileService.java | 28 ++ pom.xml | 6 src/main/java/com/qxueyou/scc/teach/res/service/HweiYunOBSService.java | 22 + src/main/resources/application.properties | 14 src/main/java/com/qxueyou/scc/teach/res/model/Res.java | 2 src/main/java/com/qxueyou/scc/base/service/ICacheService.java | 3 src/main/java/com/qxueyou/scc/base/model/Result.java | 14 src/main/java/com/qxueyou/scc/base/service/impl/RedisCacheBean.java | 6 src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java | 226 +++++++++++++++ src/main/java/com/qxueyou/scc/teach/res/service/impl/ResService.java | 20 + src/main/java/com/qxueyou/scc/teach/live/model/AccessLog.java | 50 +++ src/main/java/com/qxueyou/scc/stucontroller/StuLiveController.java | 51 +++ src/main/java/com/qxueyou/scc/teach/res/service/IFileService.java | 5 15 files changed, 760 insertions(+), 36 deletions(-) diff --git a/pom.xml b/pom.xml index 2732c81..ac828c5 100644 --- a/pom.xml +++ b/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> diff --git a/src/main/java/com/qxueyou/scc/base/model/Result.java b/src/main/java/com/qxueyou/scc/base/model/Result.java index d29db52..d1188a2 100644 --- a/src/main/java/com/qxueyou/scc/base/model/Result.java +++ b/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; diff --git a/src/main/java/com/qxueyou/scc/base/service/ICacheService.java b/src/main/java/com/qxueyou/scc/base/service/ICacheService.java index 88b279a..c943ace 100644 --- a/src/main/java/com/qxueyou/scc/base/service/ICacheService.java +++ b/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(); } diff --git a/src/main/java/com/qxueyou/scc/base/service/impl/RedisCacheBean.java b/src/main/java/com/qxueyou/scc/base/service/impl/RedisCacheBean.java index 9669bbe..5472539 100644 --- a/src/main/java/com/qxueyou/scc/base/service/impl/RedisCacheBean.java +++ b/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; + } } diff --git a/src/main/java/com/qxueyou/scc/controller/HweiYunOBSController.java b/src/main/java/com/qxueyou/scc/controller/HweiYunOBSController.java index 02cd660..9c8516a 100644 --- a/src/main/java/com/qxueyou/scc/controller/HweiYunOBSController.java +++ b/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浠h〃鎴愬姛锛�500浠h〃涓婁紶澶辫触锛�205浠h〃闇�閲嶆柊灏濊瘯 + * + * @param identifier 鍞竴id锛岄渶瀹㈡埛绔繚璇佸敮涓�鎬э紝鐩稿悓鏂囦欢淇濊瘉鍞竴鍗冲彲锛岄潪MD5 + * @return + * @TODO : 鐩墠缂哄皯瀵� 鍚勬ā鍧楁枃浠朵釜鏁般�佹枃浠舵牸寮忋�佹枃浠跺ぇ灏忕殑涓婁紶鎺у埗,缁熶竴澧炲姞鍦╟onfigFileModule琛ㄩ噷闈㈠嵆鍙疄鐜� 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("涓婁紶妯″潡瑙f瀽鍑洪敊锛�" + 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) { diff --git a/src/main/java/com/qxueyou/scc/stucontroller/StuLiveController.java b/src/main/java/com/qxueyou/scc/stucontroller/StuLiveController.java index 481c30d..b465015 100644 --- a/src/main/java/com/qxueyou/scc/stucontroller/StuLiveController.java +++ b/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); } diff --git a/src/main/java/com/qxueyou/scc/teach/live/model/AccessLog.java b/src/main/java/com/qxueyou/scc/teach/live/model/AccessLog.java new file mode 100644 index 0000000..eb8c195 --- /dev/null +++ b/src/main/java/com/qxueyou/scc/teach/live/model/AccessLog.java @@ -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 = "鐩存挱闂磇d") + private String courseId; + @ApiModelProperty(value = "璁块棶ip") + private String ip; + @ApiModelProperty(value = "杩涘叆鐩存挱寮�濮嬫椂闂�") + private Date enterTime; + @ApiModelProperty(value = "绂诲紑鐩存挱鏃堕棿") + private Date leaveTime; + @ApiModelProperty(value = "濡傛灉鏄痷serId鍦ㄥ钩鍙版煡璇笉鍒板垯鏄父瀹�") + private String userId; + @ApiModelProperty(value = "ip褰掑睘鍦颁俊鎭�") + private String ipAttribution; + @ApiModelProperty(value = "roadShow:璺紨锛宑onference:浼氳") + private String type; + @ApiModelProperty(value = "鍒涘缓鏃堕棿") + private Date createTime; + @ApiModelProperty(value = "淇敼鏃堕棿") + private Date updateTime; + //鏄惁鍒犻櫎锛�0鏈垹闄� 1鍒犻櫎 + @ApiModelProperty(value = "鍒犻櫎鏍囪瘑") + private Integer deleteFlag; + +} diff --git a/src/main/java/com/qxueyou/scc/teach/live/utils/RedisCache.java b/src/main/java/com/qxueyou/scc/teach/live/utils/RedisCache.java new file mode 100644 index 0000000..13552d2 --- /dev/null +++ b/src/main/java/com/qxueyou/scc/teach/live/utils/RedisCache.java @@ -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銆丼tring銆佸疄浣撶被绛� + * + * @param key 缂撳瓨鐨勯敭鍊� + * @param value 缂撳瓨鐨勫�� + */ + public <T> void setCacheObject(final String key, final T value) + { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 缂撳瓨鍩烘湰鐨勫璞★紝Integer銆丼tring銆佸疄浣撶被绛� + * + * @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=璁剧疆鎴愬姛锛沠alse=璁剧疆澶辫触 + */ + public boolean expire(final String key, final long timeout) + { + return expire(key, timeout, TimeUnit.SECONDS); + } + + /** + * 璁剧疆鏈夋晥鏃堕棿 + * + * @param key Redis閿� + * @param timeout 瓒呮椂鏃堕棿 + * @param unit 鏃堕棿鍗曚綅 + * @return true=璁剧疆鎴愬姛锛沠alse=璁剧疆澶辫触 + */ + 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; + } + + /** + * 鑾峰緱缂撳瓨鐨刲ist瀵硅薄 + * + * @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; + } + + /** + * 鑾峰緱缂撳瓨鐨剆et + * + * @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); + } + } + + /** + * 鑾峰緱缂撳瓨鐨凪ap + * + * @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); + } +} diff --git a/src/main/java/com/qxueyou/scc/teach/res/model/Res.java b/src/main/java/com/qxueyou/scc/teach/res/model/Res.java index d191896..5415f36 100644 --- a/src/main/java/com/qxueyou/scc/teach/res/model/Res.java +++ b/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; diff --git a/src/main/java/com/qxueyou/scc/teach/res/service/HweiYunOBSService.java b/src/main/java/com/qxueyou/scc/teach/res/service/HweiYunOBSService.java index 3b2a896..15a6eff 100644 --- a/src/main/java/com/qxueyou/scc/teach/res/service/HweiYunOBSService.java +++ b/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); } diff --git a/src/main/java/com/qxueyou/scc/teach/res/service/IFileService.java b/src/main/java/com/qxueyou/scc/teach/res/service/IFileService.java index 6249440..5afe654 100644 --- a/src/main/java/com/qxueyou/scc/teach/res/service/IFileService.java +++ b/src/main/java/com/qxueyou/scc/teach/res/service/IFileService.java @@ -35,5 +35,6 @@ * @return */ InputStream readStreamById(String id); - -} \ No newline at end of file + + Result checkMd5(String md5, String fileName); +} diff --git a/src/main/java/com/qxueyou/scc/teach/res/service/impl/FileService.java b/src/main/java/com/qxueyou/scc/teach/res/service/impl/FileService.java index 6f14ba5..e67a090 100644 --- a/src/main/java/com/qxueyou/scc/teach/res/service/impl/FileService.java +++ b/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; + } } diff --git a/src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java b/src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java index 3413b40..8964cf2 100644 --- a/src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java +++ b/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(闃块噷浜慜SS鍒濆鍖栧垎鐗囦笂浼犱换鍔¤繑鍥�,鍜寀niqueId鍙妅ey涓�涓�瀵瑰簲),鑻ヨ幏鍙栦笉鍒帮紝鍒�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(闃块噷浜慜SS鍒濆鍖栧垎鐗囦笂浼犱换鍔¤繑鍥�,鍜寀niqueId鍙妅ey涓�涓�瀵瑰簲),鑻ヨ幏鍙栦笉鍒帮紝鍒�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; + } } diff --git a/src/main/java/com/qxueyou/scc/teach/res/service/impl/ResService.java b/src/main/java/com/qxueyou/scc/teach/res/service/impl/ResService.java index 26db190..f15eb2d 100644 --- a/src/main/java/com/qxueyou/scc/teach/res/service/impl/ResService.java +++ b/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()); + //杩欓噷鐩稿綋浜庤缃綘涓婁紶鍒皁bs鐨勬枃浠惰矾 + 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)); // } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2d6ba1d..a5a0e27 100644 --- a/src/main/resources/application.properties +++ b/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 -- Gitblit v1.8.0