尚硅谷实战项目-谷粒学院-part two

本文介绍了一个课程管理系统的实现过程,包括前后端开发、课程信息管理、视频处理及第三方服务集成等内容。涉及的技术要点涵盖课程信息增删改查、视频上传与播放、微服务架构设计与实现等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

添加课程基本信息

添加课程信息后端

1、使用代码生成器生成课程相关的代码

在这里插入图片描述

2、

细节问题:

  1. 创建vo实体类用于表单数据封装

  2. 把表单提交过来的数据添加数据库

    向两张表添加数据:课程表和课程描述表

  3. 把讲师和分类使用下列列表显示

    课程分类 做成二级联动效果

@Service
public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {

    @Autowired
    private EduCourseDescriptionService courseDescriptionService;


    //添加课程基本信息的方法
    @Override
    public void saveCourseInfo(CourseInfoVo courseInfoVo) {
        // 向课程表添加课程基本信息
        //CourseInfoVo对象转换eduCourse对象
        EduCourse eduCourse = new EduCourse();
        BeanUtils.copyProperties(courseInfoVo, eduCourse);
        int insert = baseMapper.insert(eduCourse);

        if (insert == 0){
            //添加失败
            throw new GuliException(20001,"添加课程信息失败");
        }

        //获取添加之后课程id
        String cid = eduCourse.getId();

        // 向课程简介表添加课程简介
        EduCourseDescription courseDescription = new EduCourseDescription();
        courseDescription.setDescription(courseInfoVo.getDescription());
        //设置描述id就是课程id
        courseDescription.setId(cid);
        courseDescriptionService.save(courseDescription);
    }
}

更改描述里面的策略:

在这里插入图片描述

添加课程信息前端

1、对菜单栏的内容进行增加

在这里插入图片描述

2、新建对应的页面并完善其内容

在这里插入图片描述

3、连接后端

在这里插入图片描述

细节问题:

添加之后,返回课程id

在这里插入图片描述

在这里插入图片描述

整合文本编辑器

1、复制文本编辑器组件,相关组件进行复制到项目里面

2、配置html变量

在这里插入图片描述

3、在index.html引入Js脚本

在这里插入图片描述

4、在页面使用文本编辑器

课程大纲列表

1、创建两个实体类:章节和小节,在章节实体类使用list表示小节

类似于上一节

修改课程信息

前端内容:

在这里插入图片描述

后端:

  //修改课程信息
    @Override
    public void updateCourseInfo(CourseInfoVo courseInfoVo) {
        //修改课程表
        EduCourse eduCourse = new EduCourse();
        BeanUtils.copyProperties(courseInfoVo,eduCourse);
        int update = baseMapper.updateById(eduCourse);
        if (update == 0){
            throw new GuliException(20001,"修改课程信息失败");
        }

        //修改描述表
        EduCourseDescription description = new EduCourseDescription();
        description.setId(courseInfoVo.getId());
        description.setDescription(courseInfoVo.getDescription());
        courseDescriptionService.updateById(description);

    }
删除课程信息

按钮已经有,后端也实现了,等项目做完需要将连上前端

阿里云视频

API:阿里云提供固定的地址,只需要调用这个固定的地址,向地址传递参数,实现功能

SDK:sdk对api方式进行封装,更方便使用。之前使用EasyExcel调用阿里云提供类或者接口里面的方法实现视频功能

阿里云视频点播SDK

1、获取视频播放地址

因为上传视频可以进行加密,加密之后,使用加密之后地址不能进行视频播放,在数据库存储不存地址,而是存储

根据视频id获取视频播放地址:

public class TestVod {
    public static void main(String[] args) throws Exception{
        //1 根据视频的ID获取视频播放地址
        // 创建初始化对象
        DefaultAcsClient client = InitObject.initVodClient("LTAI5tR617LEVVNgxTPz8dDk","AEcqAHfCr3ergCtyRCumbGso42pnJ3");

        // 创建获取视频地址request和response
        GetPlayInfoRequest request = new GetPlayInfoRequest();
        GetPlayInfoResponse response = new GetPlayInfoResponse();

        // 向request对象里面设置视频id
        request.setVideoId("fb75ed5eb8d440899bb551d15dc03d8e");

        // 使用初始化对象里面的方法,传递request,获取数据
        response = client.getAcsResponse(request);

        List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();
        //播放地址
        for (GetPlayInfoResponse.PlayInfo playInfo : playInfoList) {
            System.out.print("PlayInfo.PlayURL = " + playInfo.getPlayURL() + "\n");
        }
        //Base信息
        System.out.print("VideoBase.Title = " + response.getVideoBase().getTitle() + "\n");
    }
}

2、获取视频播放凭证

public static void getPlayAuth()  throws Exception{
    //根据视频Id获取视频播放凭证
    //创建初始化对象
    DefaultAcsClient client = InitObject.initVodClient("LTAI5tR617LEVVNgxTPz8dDk","AEcqAHfCr3ergCtyRCumbGso42pnJ3");
    //创建获取视频凭证request和response
    GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();
    GetVideoPlayAuthResponse response = new GetVideoPlayAuthResponse();

    //向request中设置视频id
    request.setVideoId("fb75ed5eb8d440899bb551d15dc03d8e");

    //调用初始化对象的方法得到凭证
    response = client.getAcsResponse(request);
    System.out.println("playauth:" +response.getPlayAuth());
}

3、上传视频到阿里云视频点播服务

在之前引入jar包时,aliyun-java-vod-upload-1.4.11.jar的导入出错,所以我用了1.4.14版本的,原因是这个包不是开源的,不能通过maven仓库下载。。

但是使用1.4.14版本官网说明如下,还需要更改oss包的版本,不然不兼容

在这里插入图片描述

下载了1.4.11的版本,但是还是报错

把官网中的需要的xml依赖复制过来,就可以运行了。。

测试成功

整合前端 视频上传

上传视频时,数据库里的video_source_id为空

删除视频

后端接口:

 //根据视频id删除阿里云视频
    @DeleteMapping("removeAlyVideo/{id}")
    public R removeAlyVideo(@PathVariable String id){
        try{
            //初始化对象
            DefaultAcsClient client = InitVodClient.initVodClient(
                    ConstantVodUtils.ACCESS_KEY_ID,
                    ConstantVodUtils.ACCESS_KEY_SECRET);
            //创建删除视频的request对象
            DeleteVideoRequest request = new DeleteVideoRequest();
            //向request设置视频id
            request.setVideoIds(id);
            //调用初始化对象的方法实现删除
            client.getAcsResponse(request);
            return R.ok();
        }catch (Exception e){
            e.printStackTrace();
            throw new GuliException(20001,"删除视频失败");
        }
    }

nacos配置

1、安装并启动nacos

使用docker安装nacos

docker run --env MODE=standalone --name mynacos -d -p 8848:8848 docker.io/nacos/nacos-server:1.3.1

2、在需要配置服务的配置文件中

# nacos服务地址
spring.cloud.nacos.discovery.server-addr=192.168.1.118:8848

3、在其主启动类上加上注解

@EnableDiscoveryClient

4、在nacos中查看是否注册成功

删除小节和删除视频

把互相调用的服务(service-edu和service-vod)在nacos中进行注册

1、引入依赖在service模块

  <!--服务调用-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2、在调用端service-edu服务启动类添加注解

@EnableFeignClients

3、在调用端 创建interface,使用注解指定调用服务名称,定义调用的方法路径

SpringCloud调用接口流程

在这里插入图片描述

熔断机制的使用

1、添加熔断器依赖

   <!--hystrix依赖,主要是用 @HystrixCommand -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

2、在调用端配置文件中开启熔断器

#开启熔断机制
feign.hystrix.enabled=true
# 设置hystrix超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000

3、在创建Interface之后,还需要创建interface对应实现类,在实现类实现方法,出错了输出内容

@Component
public class VodFileDegradeFeignClient implements VodClient {

    //出错之后会执行
    @Override
    public R removeAlyVideo(String id) {
        return R.error().message("删除视频出错了");
    }

    @Override
    public R deleteBatch(List<String> videoList) {
        return R.error().message("删除多个视频出错了");
    }
}

4、在Interface上面添加注释和属性

@Component
@FeignClient(name = "service-vod",fallback = VodFileDegradeFeignClient.class) //调用的服务名称
public interface VodClient {
...
}

搭建项目前台环境

服务端渲染

服务端渲染又称SSR (Server Side Render)是在服务端完成页面的内容,而不是在客户端通过AJAX获取数据。

服务器端渲染(SSR)的优势主要在于:更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。

如果你的应用程序初始展示 loading 菊花图,然后通过 Ajax 获取内容,抓取工具并不会等待异步完成后再进行页面内容的抓取。也就是说,如果 SEO 对你的站点至关重要,而你的页面又是异步获取内容,则你可能需要服务器端渲染(SSR)解决此问题。

另外,使用服务器端渲染,我们可以获得更快的内容到达时间(time-to-content),无需等待所有的JavaScript 都完成下载并执行,产生更好的用户体验,对于那些「内容到达时间(time-to-content)与转化率直接相关」的应用程序而言,服务器端渲染(SSR)至关重要。

什么是NUXT

Nuxt.js 是一个基于 Vue.js 的轻量级应用框架,可用来创建服务端渲染 (SSR) 应用,也可充当静态站点引擎生成静态站点应用,具有优雅的代码结构分层和热加载等特性。

NUXT目录结构

在这里插入图片描述

在这里插入图片描述

整合项目首页面

固定路由:路径是固定的

动态路由:

创建方式:

如果我们需要根据id查询一条记录,就需要使用动态路由,NUXT的动态路由是以下划线开头的vue文件,参数名为下划线后边的文件名

首页数据banner接口
@Service
public class CrmBannerServiceImpl extends ServiceImpl<CrmBannerMapper, CrmBanner> implements CrmBannerService {

    //查询所有的banner
    @Override
    public List<CrmBanner> selectAllBanner() {
        //根据id进行降序排列,只显示前2条记录
        QueryWrapper<CrmBanner> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");

        //last方法,拼接sql语句
        wrapper.last("limit 2");

        List<CrmBanner> list = baseMapper.selectList(null);
        return list;
    }
}

整合Redis

Redis特点:

1、基于key-value进行存储的

2、支持多种数据结构:string、list、hash、set、zset

3、支持持久化,通过内存进行存储的,也可以存到硬盘里面

4、支持过期时间,支持事务

一般来说,把经常进行查询,不经常修改的,不是特别重要的数据放到redis作为缓存

整合步骤:

1、引入相关依赖

<!-- redis -->
<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring2.X集成redis所需common-pool2-->
<dependency> 
    <groupId>org.apache.commons</groupId> 
    <artifactId>commons-pool2</artifactId> 
    <version>2.6.0</version>
</dependency>

2、配置类

@Configuration //配置类
@EnableCaching //开启缓存
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory
                                                               factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new
                Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setConnectionFactory(factory);
//key序列化方式
        template.setKeySerializer(redisSerializer);
//value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new
                Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config =
                RedisCacheConfiguration.defaultCacheConfig()
                        .entryTtl(Duration.ofSeconds(600))

                        .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))

                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                        .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

3、在查询所有Banner的方法上面添加缓存注释 @Cacheable

第一次查询:首先查询数据库,把数据库查询的数据返回,并且返回数据放到缓存中

第二次查询:查询缓存,发现缓存有数据,直接返回

在这里插入图片描述

4、启动redis服务

使用docker安装的redis,配置文件容器里没有,需要添加映射

  1. 创建docker统一的外部配置文件
mkdir -p docker/redis/{conf,data}
  1. 在conf目录创建redis.conf的配置文件
touch /docker/redis/conf/redis.conf
  1. 更改配置文件redis.conf,将其中的内容更改
#bind
#127.0.0.1
deemonize no #daemonize no 默认情况下,redis不是在后台运行的,如果需要在后台运行,把该项的值更改为yes
  1. 创建启动容器,加载配置文件并持久化数据
docker run -d --privileged=true -p 6379:6379 -v /docker/redis/conf/redis.conf:/etc/redis/redis.conf -v /docker/redis/data:/data --name redis-test redis redis-server /etc/redis/redis.conf --appendonly yes
  1. 使用redis-cli命令启动
  2. 启动前端,使用相关命令可以得到

在这里插入图片描述

登录实现

单点登录

单点登录三种常见方式:

1、session广播机制实现 session复制到每个模块中

2、使用cookie + redis实现

  1. 在项目中任何一个模块进行登录,登录之后,把数据放到两个地方

    1. redis:在key中生成唯一随机值(ip,用户id等) 在value生成用户数据

    2. cookie:把redis里面生成key值放到cookie里面

  2. 访问项目中其他模块,发送请求带着cookie进行发送、获取cookie值,拿着cookie做事情,把cookie获取值,到redis进行查询,根据key进行查询,如果可以获取到数据就是登录。

3、使用token实现

token是按照一定规则生成的字符串,字符串可以包含用户信息

  1. 在项目某个模块进行登录,登录之后,按照规则生成字符串,把登录之后用户包含到生成字符串里面,把字符串返回
    1. 可以把字符串通过cookie返回
    2. 把字符串通过地址栏返回
  2. 再去访问项目其他模块,每次返回在地址栏带着生成字符串,在访问模块里面获取地址栏字符串,根据字符串获取用户信息。如果可以获取到就是登录

JWT:

JWT就是给我们规定好了规则,使用jwt规则可以生成字符串,包含用户信息

JWT生成字符串包含三部分:

第一部分:jwt头信息

第二部分:有效载荷 包含主题信息(用户信息)

第三部分:签名哈希 防伪标志

邮箱验证

因为现在阿里云的短信服务不能使用,所以改为邮箱验证

在这里插入图片描述

所需要的依赖:

 <dependencies>
        <dependency>
            <groupId >com.sun.mail</groupId >
            <artifactId >javax.mail</artifactId >
            <version >1.5.4</version >
        </dependency>
        <dependency >
            <groupId >javax.mail</groupId >
            <artifactId >mail</artifactId >
            <version >1.4.5</version >
        </dependency>
    </dependencies>

待完工。


Oauth2

分布式登录:

1、登录成功后,按照一定的规则生成字符串,字符串包含用户信息

2、把生成字符串通过路径传递,或者cookie

3、后面再发送请求时长,每次带着字符串进行发送,获取字符串,从字符串获取用户信息登录

Oauth2解决方案:

令牌机制,按照一定规则生成字符串,字符串包含用户信息

本资源为网传资源,为一套比较全的电商项目,系统架构采用SOA dubbo+EasyI实现,资源过大上传乃是下载链接,如有侵权请联系/留言,不多说下面上目录: 1.01 电商系统介绍2 f% Z/ C0 z% {1 l" q+ R 2.02 电商类型介绍6 r6 J' |. a2 F, t6 y; _. v# p2 J# ` 3.03 电商系统演示介绍! D$ C$ a1 K( q, c 4.04 电商数据结构介绍 5.05 电商数据结构设计器8 q9 r1 t3 Q( A# T" ?# P0 w+ n 6.06 电商数据准备 7.07 后台管理框架搭建 8.08 spu管理跳转 9.09 分类下拉列表的加载 10.10 商品发布的业务逻辑 11.1.建表 12.2.导数据 13.3.统一环境 14.4.生成js文件0 ~* z9 y2 K/ u; k+ N8 S# l* H: V! Y 15.01 商品spu参数提交- Q( T& z* U- B, ^: q) _ 16.02 商品spu图片上传服务介绍' ], M1 {0 w- x; Z' L. y 17.03 文件上传 工具 18.04 spu信息发布功能) G' E R g0 B( \* X + N& D7 p 19.05 spu动态图片追加% N0 H) M. o8 ~+ A 20.06 spu动态图片追加 21.07 属性功能管理介绍 22.08 属性功能管理介绍 23.09 属性保存功能跳转 24.10 属性双重集合参数3 Z4 [5 |4 D, k, M- G 25.11 属性保存功能业务层代码3 E: v6 D1 y: N* t5 X& Q, | 26.12 属性能业异步内嵌页8 t- |* |7 r# @ 27.13 属性集合查询) q& ~/ W) _9 c* r+ d: D5 Z% Y 28.01 属性的双重集合查询语句 29.02 sku功能介绍! m- K+ b0 K7 U* B! o* g3 S 30.03 sku功能跳转 31.04 客户端js函数中的el表达式 32.05 异步加载spu列表数据# M& R, \7 \3 y z- w+ a% }( g" ^ 33.06 用复选框操作属性列表显示 D+ k( T; J. J" `2 u 34.07 属性参数的提交) O0 o, s0 X \! P! @0 b& H 35.08 sku的数据结构说明8 m! S+ i9 k) W4 F# ?7 U 36.09 sku添加的业务实现1 |' b G% [! w/ J* C n; N 37.10 easyui的介绍 38.11 easyui的layout初始化介绍- v- C+ z# J) e- O* I! G 39.12 easyui手风琴控件介绍1 X/ X# \' k% x2 N 40.13 tree控件 41.14 tab控件: U, |: a! S7 ?: A$ t1 ?, G 42.1.properties% C2 @ d! }9 Z& ^2 c 43.2.主键9 D3 f9 W4 J* C" B4 M 44.3. 锚点. F( v2 C8 q- I# F+ G 45.01 数据表格的用法: e: S' z. T0 @8 T( `6 L 46.02 combobox的用法; _6 }2 p3 v: O7 l* } 47.03 嵌套布局的用法% L! U! L0 ]% B 48.04 easyui同步提交后跳转问题 49.05 乱码问题! {6 |( X* i) u; w! Y' B 50.06 首页初始化 51.07 用户登录方法 k, `) e/ R( F& m5 X 52.08 通过cookie取得用户的个性化信息, J7 ?0 ]' A) \6 E7 n5 K 53.09 通过客户端cookie取得用户的个性化信息0 i7 ], O/ }# H: t6 @: j) I+ i 54.10 用户个性化信息9 b% h5 O% p; I" P7 z 55.11 任务总结 56.01 商品检索介绍 57.02 商品分类检索介绍7 J% Q6 L& r: T6 N. H8 a- E6 Y% f" d" S4 I 58.03 商品分类检索sql: Z- N/ w: k; }2 b9 E( w8 I 59.04 商品分类检索列表 60.05 商品属性检索介绍 61.06 ajax字符串数组传参 62.07 ajax字符串json传参& i' g9 \7 ^! e7 _ 63.08 表单序列化传参 64.09 动态sql的设计方法" o# D. ?# R% _1 X 65.10 动态sql的实现 66.11 任务 67.1.项目演示 68.2.resu
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qtayu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值