本项目的存储图片和音频文件都存储在腾讯云的服务器中,本章先介绍存储图片的方式。
存储桶文件创建:
存储桶项目存储内容:
APPID和密钥管理:
APPID和密钥是整个云存储最为重要的验证依据,在配置文件中应用。
现在简要介绍整个云存储的配置过程(只能指定路径上传存储,密钥隐藏):
package com.lxl;
import com.alibaba.fastjson.JSON;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
import java.io.File;
public class TestCos {
public static void main(String[] args) {
// 1 初始化用户身份信息(secretId, secretKey)。
String secretId = "AKIDQjskRxPgs1HPNl0LSM3c2GF3jGbkiXCh";
String secretKey = "###############################";
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
Region region = new Region("ap-beijing");
ClientConfig clientConfig = new ClientConfig(region);
// 这里建议设置使用 https 协议
clientConfig.setHttpProtocol(HttpProtocol.https);
// 3 生成 cos 客户端。
COSClient cosClient = new COSClient(cred, clientConfig);
// 指定要上传的文件
File localFile = new File("/Users/xiaolianglu/01.png");
// 指定文件将要存放的存储桶
String bucketName = "ggkt-1312247070";
// 指定文件上传到 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示将文件 picture.jpg 上传到 folder 路径下
String key = "/2022/07/01.png";
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile);
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
System.out.println(JSON.toJSONString(putObjectResult));
}
}
配置application.properties方便后续服务器数据调用(密钥隐藏):
spring.servlet.multipart.max-file-size=1024MB
spring.servlet.multipart.max-request-size=1024MB
tencent.cos.file.region=ap-beijing
tencent.cos.file.secretid=AKIDQjskRxPgs1HPNl0LSM3c2GF3jGbkiXCh
tencent.cos.file.secretkey=############################
tencent.cos.file.bucketname=ggkt-1312247070
创建工具类(将个人数据库数据做转换,作为接口传输数据):
package com.lxl.ggkt.vod.utils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
@Component
public class ConstantPropertiesUtil implements InitializingBean {
@Value("${tencent.cos.file.region}")
private String region;
@Value("${tencent.cos.file.secretid}")
private String secretId;
@Value("${tencent.cos.file.secretkey}")
private String secretKey;
@Value("${tencent.cos.file.bucketname}")
private String bucketName;
public static String END_POINT;
public static String ACCESS_KEY_ID;
public static String ACCESS_KEY_SECRET;
public static String BUCKET_NAME;
@Override
public void afterPropertiesSet() throws Exception {
END_POINT = region;
ACCESS_KEY_ID = secretId;
ACCESS_KEY_SECRET = secretKey;
BUCKET_NAME = bucketName;
}
}
确定上传流之后,查看对应文档提供的事例,修改默认的KEY_ID和KEY_SECRECT,存储桶APP_ID,修改上传文件路径:
package com.lxl.ggkt.vod.service.impl;
import com.lxl.ggkt.vod.service.FileService;
import com.lxl.ggkt.vod.utils.ConstantPropertiesUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.UUID;
@Service
public class FileServiceImpl implements FileService {
//文件上传
@Override
public String upload(MultipartFile file) {
// 1 初始化用户身份信息(secretId, secretKey)。
String secretId = ConstantPropertiesUtil.ACCESS_KEY_ID;
String secretKey = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
Region region = new Region(ConstantPropertiesUtil.END_POINT);
ClientConfig clientConfig = new ClientConfig(region);
// 这里建议设置使用 https 协议
clientConfig.setHttpProtocol(HttpProtocol.https);
// 3 生成 cos 客户端。
COSClient cosClient = new COSClient(cred, clientConfig);
// 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
// 对象键(Key)是对象在存储桶中的唯一标识。 998u-09iu-09i-333
//在文件名称前面添加uuid值
String key = UUID.randomUUID().toString().replaceAll("-","")
+file.getOriginalFilename();
//对上传文件分组,根据当前日期 /2022/11/11
String dateTime = new DateTime().toString("yyyy/MM/dd");
key = dateTime+"/"+key;
try {
//获取上传文件输入流
InputStream inputStream = file.getInputStream();
ObjectMetadata objectMetadata = new ObjectMetadata();
PutObjectRequest putObjectRequest = new PutObjectRequest(
bucketName,
key,
inputStream,
objectMetadata);
// 高级接口会返回一个异步结果Upload
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
//返回上传文件路径
//https://ggkt-atguigu-1310644373.cos.ap-beijing.myqcloud.com/01.jpg
String url = "https://"+bucketName+"."+"cos"+"."+ConstantPropertiesUtil.END_POINT+".myqcloud.com"+"/"+key;
return url;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
完成对应的FileUploadController.java(上传接口):
package com.lxl.ggkt.vod.controller;
import com.lxl.ggkt.result.Result;
import com.lxl.ggkt.vod.service.FileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@Api(tags = "文件上传接口")
@RestController
@RequestMapping("/admin/vod/file")
//@CrossOrigin
public class FileUploadController {
@Autowired
private FileService fileService;
@ApiOperation("文件上传")
@PostMapping("upload")
public Result uploadFile(
@ApiParam(name = "file", value = "文件", required = true)
@RequestParam("file") MultipartFile file){
String url = fileService.upload(file);
return Result.ok(url).message("上传文件成功");
}
}
课程后端相关设计(列表展示,数据导入,数据导出):
package com.lxl.ggkt.vod.controller;
import com.lxl.ggkt.model.vod.Subject;
import com.lxl.ggkt.result.Result;
import com.lxl.ggkt.vod.service.SubjectService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* <p>
* 课程科目 前端控制器
* </p>
*
* @author lxl
* @since 2022-07-19
*/
@RestController
@RequestMapping("/admin/vod/subject")
//@CrossOrigin
public class SubjectController {
@Autowired
private SubjectService subjectService;
@ApiOperation("课程分类列表")
@GetMapping("getChildSubject/{id}")
public Result getChildSubject(@PathVariable Long id){
List<Subject> list = subjectService.selectSubjectList(id);
return Result.ok(list);
}
//课程分类导出
@ApiOperation("课程分类导出")
@GetMapping("exportData")
public void exportData(HttpServletResponse response){
subjectService.exportData(response);
}
//课程分类导入
@ApiOperation("课程分类导入")
@PostMapping("importData")
public Result importData(MultipartFile file){
subjectService.importData(file);
return Result.ok(null);
}
}
数据文档的导入和导出使用EasyExcel进行操作:
首先为了清楚展示导入和导出的数据,本项目封装了SubjectEeVo类:
package com.lxl.ggkt.vo.vod;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* <p>
* Dict
* </p>
*
* @author lxl
*/
@Data
public class SubjectEeVo {
@ExcelProperty(value = "id" ,index = 0)
private Long id;
@ExcelProperty(value = "课程分类名称" ,index = 1)
private String title;
@ExcelProperty(value = "上级id" ,index = 2)
private Long parentId;
@ExcelProperty(value = "排序" ,index = 3)
private Integer sort;
}
编写service实现类(显示课程列表,导入数据,导出数据,判断是否为父子节点):
package com.lxl.ggkt.vod.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lxl.ggkt.exception.GgktException;
import com.lxl.ggkt.model.vod.Subject;
import com.lxl.ggkt.vo.vod.SubjectEeVo;
import com.lxl.ggkt.vod.listener.SubjectListener;
import com.lxl.ggkt.vod.mapper.SubjectMapper;
import com.lxl.ggkt.vod.service.SubjectService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.excel.EasyExcel;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* 课程科目 服务实现类
* </p>
*
* @author atguigu
* @since 2022-07-19
*/
@Service
public class SubjectServiceImpl extends ServiceImpl<SubjectMapper, Subject> implements SubjectService {
@Autowired
private SubjectListener subjectListener;
@Override
public List<Subject> selectSubjectList(Long id) {
QueryWrapper<Subject> wrapper = new QueryWrapper<>();
wrapper.eq("parent_id",id);
List<Subject> subjectList = baseMapper.selectList(wrapper);
for (Subject subject:subjectList){
Long subjectId = subject.getId();
boolean isChild = this.isChildren(subjectId);
subject.setHasChildren(isChild);
}
return subjectList;
}
@Override
public void exportData(HttpServletResponse response) {
try{
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("课程分类", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
List<Subject> subjectList = baseMapper.selectList(null);
List<SubjectEeVo> subjectEeVoList = new ArrayList<>();
for(Subject subject : subjectList) {
SubjectEeVo subjectEeVo = new SubjectEeVo();
// subjectEeVo.setId(subject.getId());
// subjectEeVo.setParentId(subject.getParentId());
BeanUtils.copyProperties(subject,subjectEeVo);
subjectEeVoList.add(subjectEeVo);
}
EasyExcel.write(response.getOutputStream(), SubjectEeVo.class)
.sheet("课程分类").doWrite(subjectEeVoList);
}catch (Exception e){
throw new GgktException(20001,"导出失败");
}
}
@Override
public void importData(MultipartFile file) {
try {
EasyExcel.read(file.getInputStream(),SubjectEeVo.class,
subjectListener).sheet().doRead();
} catch (IOException e) {
throw new GgktException(20001,"导入失败");
}
}
private boolean isChildren(Long subjectId) {
QueryWrapper<Subject> wrapper = new QueryWrapper<>();
wrapper.eq("parent_id",subjectId);
Integer count = baseMapper.selectCount(wrapper);
return count > 0;
}
}
上述代码涉及到了读取监听器,它主要的作用是一行一行读取数据,调用方法插入数据,同时添加数据到数据库中:
package com.lxl.excel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.Map;
@Component
public class SubjectListener extends AnalysisEventListener<SubjectEeVo> {
@Autowired
private SubjectMapper dictMapper;
//一行一行读取
@Override
public void invoke(SubjectEeVo subjectEeVo, AnalysisContext analysisContext) {
//调用方法添加数据库
Subject subject = new Subject();
BeanUtils.copyProperties(subjectEeVo,subject);
dictMapper.insert(subject);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
最后查看对应的controller接口,导入,导出controller直接调用SubjectServiceImp接口即可。
package com.lxl.ggkt.vod.controller;
import com.lxl.ggkt.model.vod.Subject;
import com.lxl.ggkt.result.Result;
import com.lxl.ggkt.vod.service.SubjectService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* <p>
* 课程科目 前端控制器
* </p>
*
* @author lxl
* @since 2022-07-19
*/
@RestController
@RequestMapping("/admin/vod/subject")
//@CrossOrigin
public class SubjectController {
@Autowired
private SubjectService subjectService;
@ApiOperation("课程分类列表")
@GetMapping("getChildSubject/{id}")
public Result getChildSubject(@PathVariable Long id){
List<Subject> list = subjectService.selectSubjectList(id);
return Result.ok(list);
}
//课程分类导出
@ApiOperation("课程分类导出")
@GetMapping("exportData")
public void exportData(HttpServletResponse response){
subjectService.exportData(response);
}
//课程分类导入
@ApiOperation("课程分类导入")
@PostMapping("importData")
public Result importData(MultipartFile file){
subjectService.importData(file);
return Result.ok(null);
}
}