| | |
| | | <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> |
| | |
| | | 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; |
| | |
| | | |
| | | /** 结果数据 */ |
| | | private Object data; |
| | | |
| | | |
| | | public static final String MSG_SUCCESS = "success"; |
| | | |
| | | public static final String MSG_FAIL = "fail"; |
| | | /** |
| | | * 非法请求状态码 |
| | | */ |
| | |
| | | public static final Result SUCCESS = new Result(true); |
| | | |
| | | public static final Result FAIL = new Result(false); |
| | | |
| | | |
| | | public Result() { |
| | | super(); |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | */ |
| | | boolean setIfAbsent(String key, Object obj); |
| | | |
| | | <K,V> RedisTemplate<K,V> template(); |
| | | |
| | | } |
| | |
| | | redisTemplate.opsForHash().put(key, hashKey, value); |
| | | |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | @Override |
| | | public <K, V> RedisTemplate<K, V> template() { |
| | | return redisTemplate; |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | @RestController |
| | | @RequestMapping("/file")// @RequestMapping("/file") |
| | | public class HweiYunOBSController { |
| | | private final Logger log = LogManager.getLogger("FileController"); |
| | | |
| | | @Resource |
| | | private HweiYunOBSService hweiYunOBSService; |
| | |
| | | if (ObjectUtils.isEmpty(file) || file.getSize() <= 0) { |
| | | return null; |
| | | } |
| | | |
| | | // if (FileUtil.isEmpty(file)) { |
| | | // return new Result(false,"文件为空"); |
| | | // } |
| | |
| | | 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) { |
| | |
| | | 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; |
| | |
| | | import io.swagger.annotations.ApiImplicitParams; |
| | | import io.swagger.annotations.ApiOperation; |
| | | |
| | | @Slf4j |
| | | @Api(tags="直播接口-学员端") |
| | | @RestController |
| | | @CrossOrigin |
| | |
| | | |
| | | @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, |
| | |
| | | * @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); |
| | | } |
| | | |
New file |
| | |
| | | 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; |
| | | |
| | | } |
New file |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | private String creator; |
| | | private String createId; |
| | | private String updator; |
| | | private String updateId; |
| | | private String updateId; |
| | | private boolean deleteFlag; |
| | | private String coverPageUrl; |
| | | private String status; |
| | |
| | | |
| | | 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; |
| | |
| | | * @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); |
| | | } |
| | |
| | | * @return |
| | | */ |
| | | InputStream readStreamById(String id); |
| | | |
| | | } |
| | | |
| | | Result checkMd5(String md5, String fileName); |
| | | } |
| | |
| | | } |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | | |
| | |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class HweiYunOBSServiceImpl implements HweiYunOBSService { |
| | | public class HweiYunOBSServiceImpl extends CommonAppService implements HweiYunOBSService { |
| | | |
| | | private final Logger log = LogManager.getLogger(HweiYunOBSServiceImpl.class); |
| | | @Autowired |
| | |
| | | |
| | | @Autowired |
| | | FileService fileService; |
| | | |
| | | /** |
| | | * redis 模板 |
| | | */ |
| | | @Autowired |
| | | ICacheService cache; |
| | | |
| | | |
| | | public final static String FILE_TYPE_VIDEO = "video"; |
| | | |
| | |
| | | } |
| | | 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; |
| | | } |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | |
| | | @Autowired |
| | | private ApplicationContext appContext; |
| | | |
| | | @Autowired |
| | | private HweiOBSConfig hweiOBSConfig; |
| | | |
| | | @Autowired |
| | | private IClassLectureService classLectureService; |
| | |
| | | // 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)); |
| | | // } |
| | | |
| | | } |
| | |
| | | |
| | | #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############# |
| | |
| | | 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 |