网页平台功能开发

4、网页平台功能开发

4.1 总体功能概览

在这里插入图片描述

4.2 重点接口功能实现

(1)统一异常返回与统一结果返回

定义统一返回结果对象

项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更一致、轻松。

一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容。

例如,我们的系统要求返回的基本数据格式如下:

列表:

{
  "code": 200,
  "message": "成功",
  "data": [
    {
      "id": 2,
      "name": "欧阳老师",
      "intro": "高级讲师"
    }
  ],
  "ok": true
}

没有返回数据:

{
  "code": 200,
  "message": "成功",
  "data": null,
  "ok": true
}

失败:

{
  "code": 201,
  "message": "失败",
  "data": null,
  "ok": false
}

我们可以在service_utils模块创建结果类Result,使得项目中返回的结果统一。

	//成功
	public static<T> Result<T> ok(T data){
		Result<T> result = new Result<>();
		if(data != null) result.setData(data);
		result.setCode(20000);
		result.setMessage("成功");
		return result;
	}
	//失败
	public static<T> Result<T> fail(T data){
		Result<T> result = new Result<>();
		if(data != null) result.setData(data);
		result.setCode(20001);
		result.setMessage("失败");
		return result;
	}

定义统一异常
同样,我们可以在service_utils模块创建结果类Result、统一异常处理类GlobalExceptionHandler.java、自定义异常处理类GlktException.java

@ControllerAdvice
public class GlobalExceptionHandler {

	//全局异常处理
	@ExceptionHandler(Exception.class)
	@ResponseBody
	public Result error(Exception e){
		e.printStackTrace();
		return Result.fail(null).message("执行全局异常处理");
	}

	//特定异常处理
	@ExceptionHandler(ArithmeticException.class)
	@ResponseBody
	public Result error(ArithmeticException e){
		e.printStackTrace();
		return Result.fail(null).message("执行ArithmeticException异常处理");
	}

	//自定义异常处理
	@ExceptionHandler(GlktException.class)
	@ResponseBody
	public Result error(GlktException e){
		e.printStackTrace();
		return Result.fail(null).code(e.getCode()).message(e.getMsg());
	}
}
(2)数据的CURD功能
1)列表功能(条件分页查询)

条件分页查询依赖于分页插件,首先创建配置类。

@Configuration
@MapperScan("com.work.glkt.vod.mapper")
public class VodConfig {
	/**
	 * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
	 */
	@Bean
	public MybatisPlusInterceptor mybatisPlusInterceptor() {
		MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
		interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
		return interceptor;
	}
}

在Controller里实现分页查询接口。TeacherQueryVo类封装了网页端所需的属性等信息,通过它可以获取需要的条件值,并利用StringUtils工具类进行非空判断,并封装相应的条件值。将Page对象与条件值封传入IService封装的分页查询方法中。

	//条件查询分页
	@ApiOperation("条件查询分页")
	@GetMapping("findQueryPage/{current}/{limit}")
	public Result findPage(@PathVariable long current,
						   @PathVariable long limit,
						   @RequestBody(required = false) TeacherQueryVo teacherQueryVo) {
		//创建page对象
		Page<Teacher> pageParam = new Page<>(current,limit);
		//判断teacherQueryVo对象是否为空
		if(teacherQueryVo == null) {//查询全部
			IPage<Teacher> pageModel =
					teacherService.page(pageParam,null);
			return Result.ok(pageModel);
		} else {
			//获取条件值
			String name = teacherQueryVo.getName();
			Integer level = teacherQueryVo.getLevel();
			String joinDateBegin = teacherQueryVo.getJoinDateBegin();
			String joinDateEnd = teacherQueryVo.getJoinDateEnd();
			//进行非空判断,条件封装
			QueryWrapper<Teacher> wrapper = new QueryWrapper<>();
			if(!StringUtils.isEmpty(name)) {
				wrapper.like("name",name);
			}
			if(!StringUtils.isEmpty(level)) {
				wrapper.eq("level",level);
			}
			if(!StringUtils.isEmpty(joinDateBegin)) {
				wrapper.ge("join_date",joinDateBegin);
			}
			if(!StringUtils.isEmpty(joinDateEnd)) {
				wrapper.le("join_date",joinDateEnd);
			}
			//调用方法分页查询
			IPage<Teacher> pageModel = teacherService.page(pageParam, wrapper);
			//返回
			return Result.ok(pageModel);
		}
	}
2)删除

删除指逻辑删除,本质上是更新操作。将is_deleted字段值由0改为1,数据并未真正删除。
在这里插入图片描述

3)添加功能
4)修改

修改功能,本质上可以分为两步,先根据id查询信息,回显后实现更改功能。

	//修改-根据id查询
	@ApiOperation("根据id查询")
	@GetMapping("getTeacher/{id}")
	public Result getTeacher(@PathVariable Long id) {
		Teacher teacher = teacherService.getById(id);
		return Result.ok(teacher);
	}

	// 修改-最终实现
	@ApiOperation("修改最终实现")
	@PostMapping("updateTeacher")
	public Result updateTeacher(@RequestBody Teacher teacher) {
		boolean isSuccess = teacherService.updateById(teacher);
		if(isSuccess) {
			return Result.ok(null);
		} else {
			return Result.fail(null);
		}
	}
(3)数据的树形显示

如下图所示,在某些列表功能中,数据的树形显示可以方便展示数据的层级关系。与普通列表功能相比,这一部分功能主要涉及三个方面:

  • 1.前端:利用Element-UI的懒加载
  • 2.数据库:如何实现数据的层级关系
  • 3.后端接口:数据的封装

在这里插入图片描述
1.前端:利用Element-UI的懒加载
参考: Element-UI说明文档

<script>
  export default {
    data() {
      return {
        data: [{
          label: '一级 1',
          children: [{
            label: '二级 1-1',
            children: [{
              label: '三级 1-1-1'
            }]
          }]
        },......
        defaultProps: {
          children: 'children',
          label: 'label'
        }
      };
    },
    methods: {
      handleNodeClick(data) {
        console.log(data);
      }
    }
  };
</script>

2.数据库:如何实现数据的层级关系
在数据库中创建多个id字段,表示层级关系,如在课程列表中,设置idparent_id,其中两者的对应关系如下图所示,id=0表示为一级父标题,对于子标题,parent_id为所对应的父标题的id。即后端开发对应的id为1,而Java属于后端开发,则其parent_id为后端开发的id=1。
在这里插入图片描述

在这里插入图片描述
3.后端接口:数据的封装
首先将parent_id值为0的数据封装到subjectList中;接下来遍历subjectList,判断有无下一层数据,判断依据是有无数据的parent_id等于subjectListid的值。若存在,则封装到对象中。

	public List<Subject> selectSubjectList(Long id) {
		//select * from subject where parent_id = 0;
		QueryWrapper<Subject> wrapper = new QueryWrapper<>();
		wrapper.eq("parent_id", id);
		List<Subject> subjectList = baseMapper.selectList(wrapper);
		//遍历subjectList,判断有无下一层数据,如果有,hasChildren=true
		for(Subject s : subjectList){
			Long subjectId = s.getId();
			//查询
			boolean isChild = this.isChildren(subjectId);
			//封装到对象
			s.setHasChildren(isChild);
		}
		return subjectList;
	}
	//判断下一层是否有数据
	private boolean isChildren(Long subjectId) {
		QueryWrapper<Subject> wrapper = new QueryWrapper<>();
		wrapper.eq("parent_id",subjectId );
		Integer count = Math.toIntExact(baseMapper.selectCount(wrapper));
		return count > 0;
	}
(4)EasyExcel的使用

这一部分见:在线教育平台开发(硅谷课堂)

(5)腾讯云存储

项目中主要涉及腾讯云对象存储腾讯云点播
腾讯云对象存储
对象存储(Cloud Object Storage,COS)是腾讯云提供的一种存储海量文件的分布式存储服务,用户可通过网络随时存储和查看数据。腾讯云 COS 使所有用户都能使用具备高扩展性、低成本、可靠和安全的数据存储服务。

COS 通过控制台、API、SDK 和工具等多样化方式简单、快速地接入,实现了海量数据存储和管理。通过 COS 可以进行任意格式文件的上传、下载和管理。

项目中涉及头像的上传、课程数据的上传与下载等功能都可以通过腾讯云存储对象实现。

具体配置与使用过程

  • 首先进行存储桶的创建。
    在这里插入图片描述
  • 在其中可以看到文件存储情况,可以进行文件上传测试。
    在这里插入图片描述
  • 创建API秘钥,进入API秘钥管理
    在这里插入图片描述

整合腾讯云对象存储
根据参考文档:存储桶操作进行功能实现。

  1. 在service_vod模块引入依赖
<dependencies>
    <!-- 腾讯云COS依赖 -->
    <dependency>
        <groupId>com.qcloud</groupId>
        <artifactId>cos_api</artifactId>
        <version>5.6.54</version>
    </dependency>
    <!-- 日期工具栏依赖 -->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
    </dependency>
</dependencies>
  1. 配置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=你的id
tencent.cos.file.secretkey=你的key
#bucket可以在控制台创建,也可以使用java代码创建
tencent.cos.file.bucketname=你的bucketName
  1. 创建工具类
/**
 * 常量类,读取配置文件application.properties中的配置
 */
@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;
    }
}
  1. 创建:FileService.java
public interface FileService {
    //文件上传
    String upload(MultipartFile file);
}
  1. FileServiceImpl.java实现相关功能
@Service
public class FileServiceImpl implements FileService {
    @Override
    public String upload(MultipartFile file) {
        // Endpoint以杭州为例,其它Region请按实际情况填写。
        String endpoint = ConstantPropertiesUtil.END_POINT;

        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
        // 1 初始化用户身份信息(secretId, secretKey)。
        String secretId = ConstantPropertiesUtil.ACCESS_KEY_ID;
        String secretKey = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);

        // 2 设置 bucket 的地域
        // clientConfig 中包含了设置 region, https(默认 http),超时, 代理等 set 方法
        Region region = new Region(ConstantPropertiesUtil.END_POINT);
        ClientConfig clientConfig = new ClientConfig(region);
        // 这里建议设置使用 https 协议
        // 从 5.6.54 版本开始,默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);

        try{
            // 指定要上传的文件
            InputStream inputStream = file.getInputStream();
            // 指定文件将要存放的存储桶
            // 指定文件上传到 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示将文件 picture.jpg 上传到 folder 路径下
            String key = UUID.randomUUID().toString().replaceAll("-","")+
                    file.getOriginalFilename();
            String dateUrl = new DateTime().toString("yyyy/MM/dd");
            key = dateUrl+"/"+key;

            ObjectMetadata objectMetadata = new ObjectMetadata();
            PutObjectRequest putObjectRequest =
                    new PutObjectRequest(bucketName, key, inputStream,objectMetadata);
            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            System.out.println(JSON.toJSONString(putObjectResult));
            //https://ggkt-atguigu-1310644373.cos.ap-beijing.myqcloud.com/01.jpg
            String url = "https://"+bucketName+"."+"cos"+"."+endpoint+".myqcloud.com"+"/"+key;
            return url;
        } catch (Exception clientException) {
            clientException.printStackTrace();
            return null;
        }
    }
}

6.创建Controller

FileUploadController.java

@Api(tags = "文件上传接口")
@RestController
@RequestMapping("/admin/vod/file")
public class FileUploadController {
    @Autowired
    private FileService fileService;
    /**
     * 文件上传
     */
    @ApiOperation(value = "文件上传")
    @PostMapping("upload")
    public Result upload(
            @ApiParam(name = "file", value = "文件", required = true)
            @RequestParam("file") MultipartFile file) {
        String uploadUrl = fileService.upload(file);
        return Result.ok(uploadUrl).message("文件上传成功");
    }
}
  1. 在前端实现

腾讯云点播
腾讯云点播(Video on Demand,VOD)基于腾讯多年技术积累与基础设施建设,为有音视频应用相关需求的客户提供包括音视频存储管理、音视频转码处理、音视频加速播放和音视频通信服务的一站式解决方案。
在项目开发中,视频点播模块需要完成视频的上传与删除功能,可以通过腾讯云点播服务进行。
根据参考文档:文档中心进行功能实现。

  1. 开通"云点播"服务

  2. 管理控制台

  3. 上传视频
    上传视频可将视频上传到云点播的存储中,以进行后续的处理和分发等。

  • 单击左侧菜单栏【媒资管理 > 视频管理】,默认展示【已上传】标签页;
  • 点击【上传视频】按钮;
  • 单击【选择视频】,选择本地视频文件;
  • 单击【开始上传】;
  • 页面将自动跳转至【正在上传】标签页, 本地文件所在行【状态】栏为“上传成功”时,单击【已上传】标签页,可见完成上传的视频;
  1. 前端集成
  2. 编写视频点播接口
    ① 创建相关类
    ② 引入相关依赖
<dependency>
    <groupId>com.qcloud</groupId>
    <artifactId>vod_api</artifactId>
    <version>2.1.4</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

③ 编写Controller

@Api(tags = "腾讯云点播")
@RestController
@RequestMapping("/admin/vod")
@CrossOrigin
public class VodController {

    @Autowired
    private VodService vodService;
	
    //上传视频
    @PostMapping("upload")
    public Result uploadVideo(
            @ApiParam(name = "file", value = "文件", required = true)
            @RequestParam("file") MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        String originalFilename = file.getOriginalFilename();
        String videoId = vodService.uploadVideo(inputStream, originalFilename);
        return Result.ok(videoId);
    }
    
    //删除视频
    @DeleteMapping("remove/{videoSourceId}")
    public Result removeVideo( @PathVariable String videoSourceId) {
        vodService.removeVideo(videoSourceId);
        return Result.ok();
    }
}

④ 编写Service

(1)VodService定义方法

public interface VodService {
    //上传视频
    String uploadVideo(InputStream inputStream, String originalFilename);
    //删除视频
    void removeVideo(String videoSourceId);
}

(2)VodServiceImpl实现方法

@Service
public class VodServiceImpl implements VodService {
    
    //上传视频
    @Override
    public String uploadVideo(InputStream inputStream, String originalFilename) {
        try {
            VodUploadClient client =
                    new VodUploadClient(ConstantPropertiesUtil.ACCESS_KEY_ID,
                                        ConstantPropertiesUtil.ACCESS_KEY_SECRET);
            VodUploadRequest request = new VodUploadRequest();
            //视频本地地址
            request.setMediaFilePath("D:\\001.mp4");
            //指定任务流
            request.setProcedure("LongVideoPreset");
            //调用上传方法,传入接入点地域及上传请求。
            VodUploadResponse response = client.upload("ap-guangzhou", request);
            //返回文件id保存到业务表,用于控制视频播放
            String fileId = response.getFileId();
            System.out.println("Upload FileId = {}"+response.getFileId());
            return fileId;
        } catch (Exception e) {
            System.out.println(e.toString());
        }
        return null;
    }
    
    //删除视频
    @Override
    public void removeVideo(String videoSourceId) {
       try{
            // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
            Credential cred = 
                    new Credential(ConstantPropertiesUtil.ACCESS_KEY_ID, 
                            ConstantPropertiesUtil.ACCESS_KEY_SECRET);
            // 实例化要请求产品的client对象,clientProfile是可选的
            VodClient client = new VodClient(cred, "");
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DeleteMediaRequest req = new DeleteMediaRequest();
            req.setFileId(videoSourceId);
            // 返回的resp是一个DeleteMediaResponse的实例,与请求对象对应
            DeleteMediaResponse resp = client.DeleteMedia(req);
            // 输出json格式的字符串回包
            System.out.println(DeleteMediaResponse.toJsonString(resp));
        } catch (TencentCloudSDKException e) {
            System.out.println(e.toString());
        }
    }
}

客户端上传视频
上述上传视频方法存在的问题是需要在代码中指明上传视频的本地地址,因此,为了方便后续使用,采用客户端上传视频的方式,具体实现参考链接:link

操作步骤:

  1. 申请上传签名(创建Signature类,在Controller中编写相关接口)
  2. 使用 SDK 上传视频
  3. 事件通知
(6)SpringCloud组件

这一部分见:在线教育平台开发(硅谷课堂)

(7)欢拓云直播配置

这一部分见:微信公众号开发(硅谷课堂)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值