1 参考文档
从第397天开始 对应链接
这个里边更加亲民,有他遇到的一些bug,和一些注意事项
另一个版本的谷粒商城笔记
2 在vscode中的一些调试
一些npm常用命令:
//清依赖残留,否则安装不上
npm rebuild node-sass
npm uninstall node-sass
//指定node-sass版本,这句等价于修改package.json文件了。
// 注意不要指定4.9.2了
npm install node-sass@4.14 //这个是谷粒商城对应的版本
//安装其他依赖:
npm install
npm install --legacy-peer-deps //暴力安装依赖针对npm install 失败的情况
// 启动项目(这个要根据实际情况来):
npm run dev
3 spring cloud
Spring Cloud 是分布式微服务架构的一站式解决方案,它提供了一套简单易用的编程模型,使我们能在 Spring Boot 的基础上轻松地实现微服务系统的构建。
1. 微服务的诞生
微服务是基于分而治之的思想演化出来的。
传统大型又全面的系统,随着会联网的发展很难满足市场需求。
从分布式架构-SOA架构-微服务架构
微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。
每个服务运行在其独立的进程中,服务和服务间采用轻量级的通信机制互相沟通(通常是基于 HTTP 的 RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。
2. 微服务架构与SOA架构的区别
微服务是真正的分布式的、去中心化的。把所有的“思考”逻辑包括路由、消息解析等放在服务内部,去掉一个大一统的 ESB,服务间轻通信,是比 SOA 更彻底的拆分。
3. 微服务架构引发的问题
随着整个业务数据被分散在各个子服务之后,也带来了两个最明显的问题。
业务管理系统对数据完整性查询,比如分页查询、多条件查询等,数据被割裂后如何来整合?
数据分析挖掘,这些需求可能需要分析全量的数据,并且在分析时不能影响到当前业务
从技术方案来讲,我们一般有两种选择来处理这些问题,第一种是在线处理数据,第二种是离线处理数据。
在线处理数据的方案:通过微服务提供的接口来获取数据,然后进行数据整合,不过这种方式有着明显的弊端,就是调用者需要编写大量的代码进行数据处理。其次在对各个微服务进行调取数据时会影响微服务的正常业务处理性能
离线处理数据方案:将业务数据准实时的同步到另外一个数据库中,在同步的过程中进行数据整合处理,以满足业务方对数据的需求,数据同步过来后,再提供另外一个服务接口专业负责对外输出数据信息,这种方案有两个特点:①数据同步方案是关键,技术选型有很多,如何选择切合公司业务的技术方案;②离线数据处理对微服务正常业务处理没有影响。
4.nacos(注册中心与配置中心)
注册中心:nacos
配置中心:nacos
网关:gateway
远程调用:netflix把feign闭源了,spring cloud开了个openFeign
5.Feign(远程调用)与注册中心
声明式远程调用
feign是一个声明式的HTTP客户端,他的目的就是让远程调用更加简单。给远程服务发的是HTTP请求。
会员服务想要远程调用优惠券服务,只需要给会员服务里引入openfeign依赖,他就有了远程调用其他服务的能力。
6 前端笔记参考
前端基础笔记
插值表达式:{{}}
注意:在网速慢的时候会出现差值闪烁
例如:{{msg}} {{1+1}} {{hello()}} 前面的内容如果网速慢的话会先显示括号,然后才替换成数据。
v-html 和v-text能解决这个问题
花括号只能写在标签体内(<div 标签内> 标签体 ),不能用在标签内 可以再标签体内
谷粒学院
参考文档
谷粒学院-阿昌喜欢吃黄桃版本
4 201天项目起步
商业模式
商业模式:
B2C模式:管理员和普通用户
管理员:添加 修改 删除
用户: 查询
B2B2C模式(很多电商平台):商家到商家再到用户
京东:有普通用户 可以买自营 可以买普通商家
项目用到的技术
前端 :vue element-ui node.js axios
后端: springboot+springcloud+spring security+Mybatis-plus
创建项目步骤
1.创建数据库
2.创建初始化springboot工程(报红就重启项目)
3.引入相关依赖
4.安装lombok插件
5.创建application.properties类型配置文件(先用application.properties,之后再用yml类型文件,驱动、时区、数据库、用户名、密码要是自己的)
6.编写代码
实体类
mapper
启动类上要加mapperscan、启动类位置
7.单元测试
(1)查询user表种的所有数据
Autowired注入
项目技术点
主键生成策略:
1.自动增长
1.uuid: 每次生成随机的唯一的值(排序不方便)
3.mybatis-p:提供的snowflake雪花算法(实现方式就是在主键上写@TableId)
4.redis实现
自动填充
1、表添加两个字段
createTime updateTime
2、添加实体属性 命名特点
3、在实体类里面进行自动填充属性添加注解
4、创建类,实现接口MetaObjectHandler 实现接口里面的方法
乐观锁
解决某些问题
主要解决丢失更新
丢失更新解决方案:
悲观锁:串行
乐观锁: 比较当前版本和数据库中的是否相同,若不相同,不能更改,若相同可以更改,并且版本号加一
1、表添加字段,version来表示版本号
2、对应实体类 (添加自动填充注解)
4、进行测试
mybatis_plus简单操作
1.根据id查询
User user=userMapper.selectById(1231115382920916994L);
2.多个id批量查询
selectBatchIds(Collection<? extends Serializable> collection)
@Test
public void testSelectDemo1(){
List user=userMapper.selectBatchids(Arrays.asList(1L,2L,3L));
System.out.println(user);
}
3.分页查询
(1)配置分类插件
(2)编写分页代码
创建page对象 (两个参数,当前页,和每页记录数)
调用mybatis_plus中的方法
4.删除
物理删除:直接在数据库中删除
逻辑删除:可易理解为用一个标志位,0表示未删除,1表示已经删除
第一步、在表中添加逻辑删除字段,对应实体类添加属性,属性添加注解
第二步、配置逻辑删除插件
执行删除删除代码,最终效果deleted值变成1
5.条件构造器
创建新对象
设置条件
eq 等值查询
like模糊查询
nq不等值查询
5 202天
前后端分离开发
前端:html、css、js、jq
主要作用:数据显示
ajax操作
后端:controller service mapper
主要作用:返回数据或者操作数据
开发接口,不是interface,开发controller service mapper的过程
用的maven是 f盘贵阳住建里边的3.6.1
代码生成器导入的时候代码报红:
1:依赖问题
2:对爆红的代码重新new一个
讲师管理模块(后端)
查询删除模块
使用代码生成器之前把数据库信息改好,
1、三层结构 mapper service controller
service中注入mapper
controller中注入service
2、在controller中写好查询表中所有数据
mybatis-plus版本太老引起的问题
3.逻辑删除功能
(1)配置逻辑删除插件
(2)逻辑删除主键上添加注解TableLogic
(3)controlelr 中写方法
因为delete提交 所以测试方式用swager或者postman
Swagger测试模块
整合swagger进行接口测试:
1、生成在线文档
2、方便接口测试
具体做法:
1、创建公共模块,整合swagger,为了所有模块都能进行使用,guli_xueyuan创建子模块common,在common创建子模块service_base
2、创建swager配置类
具体使用:
在service_edu引入service_base依赖
最后在配置类上加一个扫描注解
统一返回结果对象json格式
json数据格式
項目中我们会将响应式封装成json返回,一般我们会将所有接口的数据格式统一,是前端对数据的操作更一致、轻松。
一般没有具体的形式只要能描述清楚返回的数据状态以及要返回的具体数据就可以了,但是一般会包含状态码、返回消息、数据这几部分内容
分页功能
1.插件
2. 在controller中实现
3. 路径传值的方式
多条件组合查询带分项
**实现方式:**把条件值传递到接口里面
条件之封装到对象,用对象进行传递
@RequestBody 把数据封装成json形式
@ResponseBody 一般把数据以json形式返回
异常处理没有做完
报红可能是依赖没有导入 或者导错
6 203天
散碎点
统一日志处理、
前端开发和前端开发工具、
ES6入门、Vue、Axios、ElementUI、Nodejs、NPM包管理器、Babel、模块化、Webpack -谷粒学院
反引号 里边不仅可以写字符串,还可以写变量
深克隆:
把要复制的对象以及它所引用地对象都复制一遍
浅克隆:
没有把要复制对象所引用的对象复制
Vue
Axios
ElementUI
7 204天
跨域问题
插槽
首先要理解2个知识点:
1.插槽
2.作用于插槽
插槽,也就是slot,是组件的一块HTML模板,这块模板显示不显示、以及怎样显示由父组件来决定。 实际上,一个slot最核心的两个概念这里就点出来了,是显示不显示和怎样显示
作用域插槽实际上是带有数据的插槽,可以获取到父组件
传递的参数,将这些参数使用到子组件
插槽里
<w-table-column prop="je" label="总价" width="100">
<template slot-scope="scope">
<span>{{Number(scope.row.je).toFixed('2')}}</span>
</template>
</w-table-column>
watch监听器
将原本created()里面的发按法封装到init()中,在created()中调用,并通过监听器监听路由变化就执行init()判断路径是否有id值,有就获取id值,没有就清空数据;
$route(to, from)固定写法,意思为监听路由变化
...
init() {
//判断路径中是否有id值
if (this.$route.params && this.$route.params.id) {
//从路径中获取id值
const id = this.$route.params.id;
//调用根据id查询的方法
this.getInfoById(id);
}else{
this.teacher = {};
}
},
},
created() {
//在页面渲染之前
this.init()
},
watch: {
$route(to, from) {
//路由变化方式,当路由发送变化,方法就执行
console.log("watch $route");
this.init()
},
}
8 205天.阿里云OSS、讲师管理前后端【上传头像功能】、课程分类管理【环境搭建、Excel文件读取添加数据库】 -谷粒学院
一、新建云存储微服务
二、实现文件上传
nginx回顾
配置nginx反向代理
1、修改配置文件
2、修改默认端口
3、在配置文件http内,配置转发规则
5、修改前端访问端口,修改为nginx监听端口
9 Day206.课程分类【导入功能】前端实现、 课程分类列表【显示功能】、课程管理【模块需求、添加课程功能】 -谷粒学院
10 Day207&208.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布 -谷粒学院
11 Day209.SpringCloud【微服务、Springcloud】、服务发现【Nacos】、服务调用【Feign】、删除课程业务完善、熔断器【Hystrix】 谷粒学院
Nacos主要提供以下四大功能:
服务发现和服务健康监测
动态配置服务
动态DNS服务
服务及其元数据管理
把服务注册到nacos上:
(1)引入依赖
(2)配置文件
(3)启动类加注解(@EnableDiscoveryClient)
12 Day210.服务端渲染技术NUXT、整合前台主页面、名师、课程静态页面、首页整合banner数据后端部分【创建banner微服务、接口、banner后台前端实现】 -谷粒学院
服务端渲染技术NUXT
服务端渲染又称SSR (Server Side Render)是在服务端完成页面的内容,而不是在客户端通过AJAX获取数据。
服务器端渲染(SSR)的优势主要在于:更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
seo就是可以提升搜索排名
ajax不利于seo
13 Day210.首页显示课程名称数据整合、首页数据整合【Redis缓存】使用 -谷粒学院
14 Day211&212.登录页面模式、整合JWT、整合阿里云短信服务、用户登录注册接口【后端】、用户登录注册【前端】 -谷粒学院
单一服务器:早期单一服务器,用户认证。通过对session域的设置
单点登录:(只要是属于一个项目的,登陆了其中一个模块,访问其他模块的时候就不用在登陆了)例如登录百度网盘,再使用百度文库的时候就不用登录了
jwt(json web token)
使用Requestbody时候需要post提交,如果get提交出现下面错误
原因一:
原因二:
可能因为模块太多没有编译,点Build—》rebuild project
15 Day212.OAuth2、微信二维码登入注册功能、用户登录信息前后端供、讲师列表前后端 -谷粒学院
一、什么是OAuth2
记住:
OAuth2是一种授权框架,按照一定规则生成字符串,字符串包含用户信息,但是,他不提供具体的生成规则,他是一种解决方案,主要解决:1、开放系统间授权 ,2、分布式访问问题
固定路由:一般写成 index 路径是固定的
动态路由:以下划线开头,一般写成 _id 这种 每个页面可能因为id的不同而显示不同的内容
16 Day213.讲师详细页、课程列表页面、课程详细页、阿里云视频播放测试、阿里云云视频播放器 -谷粒学院
讲师详细页,
阿里云视频播放器没有做
Day214.课程评论功能、微信支付实现课程支付模块前后端 -谷粒学院
注解报错
将以下代码加到一个配置类中:
// 设置@Value注解取值不到忽略(不报错)
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer c = new PropertySourcesPlaceholderConfigurer();
c.setIgnoreUnresolvablePlaceholders(true);
return c;
}
17 Day215.课程详细页面功能完善、Echarts统计分析模块[生成统计数据+生成图表]前后端整合 -谷粒学院
fallback:容错处理,因为Fallback是通过Hystrix实现的, 所以需要开启Hystrix,spring boot application.properties文件配置feign.hystrix.enabled=true,这样就开启了Fallback 就是熔断机制,部分程序出错还可以继续运行
Day216.Canal数据同步工具、GATEWAY网关、权限管理需求分析、开发权限管理接口 -谷粒学院
canal数据同步工具
1.在虚拟机安装好canal 然后做一些配置(虚拟机mysql端口、用户名、密码)
2.在idea中新增一个模块,pom文件,properties文件,最重要的两个是canalclient监听类和主启动类
18 Day217.SpringSecurity整合、查询用户类前后端对接、Nacos配置中心、代码提交远程Git仓库、Jenkins项目部署 -谷粒学院
谷粒学院项目总结
一、项目后台管理系统功能
1.登录功能(SpringSecurity框架)
2.权限管理
(1)菜单管理:列表、添加、修改、删除
(2)角色管理
列表、添加、修改、删除、批量删除
为角色分配菜单
(3)用户管理
列表、添加、修改、删除、批量删除
为用户分配角色
(4)权限管理表和关系
3.讲师管理模块
(1)条件查询分页列表、添加、修改、删除
4.课程分类模块
(1)添加课程分类
*读取exel表里面课程分类数据,添加到数据库中
(2)课程分类列表
*使用树形结构显示课程分类
5.课程管理模块
(1)课程列表
(2)添加课程
*课程发布流程:第一步填写课程基本信息,第二步添加课程大纲(章节和小节),第三步课程信息确认,最总课程发布
*课程如何判断是否已经被发布?使用status字段
*课程添加过程中,中途把课程停止添加,重新去添加新的课程,如何找到之前没有发布完成课程,继续进行发布?
到课程列表中根据课程状态查询出未发布的课程,点击课程右边超链接把课程继续发布完成
(3)添加小节时上传视频
6.统计分析模块
(1)生成统计数据
(2)统计数据图标显示
echarts
项目前台用户系统功能
1.首页数据显示
(1)显示幻灯片功能
(2)显示热门课程
(3)显示名师
2.注册功能
(1)获取手机验证码
3.登录功能
(1)普通登录
sso单点登录
*使用jwt生成token字符串
jwt有三部分组成:
第一部分 jwt头信息
第二部分 有效载荷 包含主体信息(用户信息)
第三部分 前名哈希 防伪标志
登录实现流程:
调用登陆的接口会返回一个token的字符串,把返回的token字符串放到cookie里面,创建前端拦截器进行判断,如果cookie里面包含token字符串,把token字符串放到header里面。调用接口根据token获取用户信息,把用户信息放到cookie里面,进行显示。
(2)微信二维码登录
*Auth2:是针对特定问题解决方案
1.开放系统授权
2.分布式访问
*如何获取扫描人信息过程
扫描之后微信接口返回一个code(临时票据),那这这个票据请求微信固定地址,得到两个值access_token(访问凭证)、openid(微信唯一标识),拿着这两个值再去请求微信固定地址,得到微信扫描人信息(昵称,头像等)。
4.名师功能
5.名师详情功能
6.课程列表
(1)条件查询分页列表功能
7.课程详情页
(1)课程信息显示(包含课程基本信息)
(2)判断课程是否需要购买
8.课程视频功能(微信支付)
(1)生成课程订单
(2)生成微信支付二维码
(3)微信最终支付
*微信支付实现流程:
*如果课程是收费课程,点击立即购买
19 总结在线教育项目技术点
1.在线教育项目采用前后端分离开发
2.项目使用前端技术
(1)vue
(2)element-ui
(3)nodejs
JavaScript的运行环境,不需要浏览器直接运行js代码,模拟服务器效果
(4)NPM
*包管理工具,类似于Maven
npm命令:npm init
npm install 依赖名称
(5)Babel
*转码器,可以吧ES6代码转换成ES5代码
(6)前端模块化
通过一个页面或者一个js文件,调用另外一个js文件里面的方法
问题:ES6的模块化无法在Node.js中执行,需要用Babel编辑成ES5后再执行
(8)Echarts
*图表显示工具
20 总结在线教育项目技术点(后端一)
1.项目采用微服务架构
2.SpringBoot
3.SpringCloud
(1)是很多框架的总称,使用这些框架实现微服务架构,基于SpringBoot实现
(2)SpringCloud有哪些框架
(4)
*nacos作为注册中心
*使用nacos作为配置中心
(5)Feign
*服务调用,一个微服务调用另外一个微服务,实现远程调用
(6)熔断器
(7)Gateway网关
SpringCloud之前zuul网关,目前Gateway网关
(8)SpringCloud版本
2开头版本
4.MyBatisPlus
5.EasyExcel
21 总结在线教育项目技术点(后端二)
1.springsecurity
(4)springSecurity代码执行过程
2.Redis
3.Nginx
4.OAuth2+JWT
(1)OAuth2针对特定问题解决方案
(2)JWT包含三部分
5.HttpClient
6.Cookie
微信支付
阿里云oss
阿里云视频点播
阿里云短信服务
注册的时候,发送手机验证码
22 总结在线教育项目问题
1.前端问题-路由切换问题
(1)多次路由跳转到同一个页面,页面中created方法只会执行一次
解决方案:使用vue监听
2.前端问题-ES6模块运行问题
(1)nodejs不能直接运行ES6模块化代码,使用Babel把ES6代码转换ES5代码执行
3.mp生成19位id
(1)mp生成id值是19位,javascript处理数字类型值时候,只会处理到16位
解决方案:把实体类中的id类型改为string类型
4.跨域问题
5.413问题
6.maven加载问题
(1)maven加载项目的时候,默认不会加载src-java文件夹里面xml类型文件的
(2)解决方案:
*直接复制xml文件到target目录
*通过配置实现
23 介绍项目模块
项目涉及技术
这是一个产品还是项目
测试要求
企业终端的项目(产品)开发流程
系统中都有那些角色?数据库是怎么设计的?
视频点播是怎么实现的(流媒体你们是怎么实现的)
前后端联调经常遇到的问题
分布式系统的CAP原理
架构图
24 Day400&401&402&403&404&405&406.商品服务 -谷粒商城
用例
1.
2.
3.
条件分页查询
一、条件分页
1.分页插件
@Configuration
@EnableTransactionManagement
@MapperScan("com.atguigu.gulimall.product.dao")
public class MybatisConfig {
//分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
2.controller
/**
* 规格参数列表
* @param params
* @param catelogId
* @return
*/
@GetMapping("/base/list/{catelogId}")
public R baseAttrList(@RequestParam Map<String, Object> params,@PathVariable("catelogId")Integer catelogId){
PageUtils page = attrService.queryBaseAttrPage(params,catelogId);
return R.ok().put("page", page);
}
3.service serviceimpl实现层层
PageUtils queryBaseAttrPage(Map<String, Object> params, Integer catelogId);
@Override
public PageUtils queryBaseAttrPage(Map<String, Object> params, Integer catelogId) {
// 构造条件
QueryWrapper<AttrEntity> wrapper = new QueryWrapper<>();
if (catelogId !=0){
wrapper.eq("catelog_id",catelogId);
}
// 当参数不为空的时候
String key = (String) params.get("key");
if (!StringUtils.isEmpty(key)){
wrapper.eq("catelog_id",key).or().like("attr_name",key);
}
// 分页
IPage<AttrEntity> page = this.page(
new Query<AttrEntity>().getPage(params),
wrapper
);
PageUtils pageUtils = new PageUtils(page);
List<AttrEntity> list = page.getRecords();
// 流的形式
List<AttrRespVo> resultList = list.stream().map(item -> {
AttrRespVo attrRespVo = new AttrRespVo();
BeanUtils.copyProperties(item, attrRespVo);
AttrAttrgroupRelationEntity attrId = attrAttrgroupRelationService.
getOne(new QueryWrapper<AttrAttrgroupRelationEntity>().
eq("attr_id", item.getAttrId()));
if (attrId != null) {
AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrId);
attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName());
}
CategoryEntity categoryEntity = categoryService.getById(item.getCatelogId());
if (categoryEntity != null) {
attrRespVo.setCatelogName(categoryEntity.getName());
}
return attrRespVo;
}).collect(Collectors.toList());
pageUtils.setList(resultList);
return pageUtils;
}
二、增、删除、修改
1.controller层
/**
* 保存
*/
@RequestMapping("/save")
public R save(@RequestBody AttrVo vo){
attrService.saveAttr(vo);
return R.ok();
}
/**
* 修改
*/
@RequestMapping("/update")
public R update(@RequestBody AttrVo attr){
attrService.updateAttr(attr);
return R.ok();
}
/**
* 删除
*/
@RequestMapping("/delete")
public R delete(@RequestBody Long[] attrIds){
attrService.removeByIds(Arrays.asList(attrIds));
return R.ok();
}
2.service层(因为删除用的是mybatis自带的方法,就没有写service层)
void saveAttr(AttrVo vo);
void updateAttr(AttrVo attr);
3.serviceImpl 实现类
//保存
@Override
public void saveAttr(AttrVo vo) {
AttrEntity attrEntity = new AttrEntity();
BeanUtils.copyProperties(vo,attrEntity);
this.save(attrEntity);
AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
attrAttrgroupRelationEntity.setAttrGroupId(vo.getAttrGroupId());
attrAttrgroupRelationEntity.setAttrId(attrEntity.getAttrId());
attrAttrgroupRelationService.save(attrAttrgroupRelationEntity);
}
//修改
@Override
public void updateAttr(AttrVo attr) {
// 修改基本数据
AttrEntity attrEntity = new AttrEntity();
BeanUtils.copyProperties(attr,attrEntity);
this.updateById(attrEntity);
// 修改关联数据
AttrAttrgroupRelationEntity attrgroupRelation = new AttrAttrgroupRelationEntity();
attrgroupRelation.setAttrGroupId(attr.getAttrGroupId());
attrgroupRelation.setAttrId(attr.getAttrId());
Integer count=relationDao.selectCount(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id",attr.getAttrId()));
if (count>0){
relationDao.update(attrgroupRelation,new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id",attr.getAttrId()));
}else {
relationDao.insert(attrgroupRelation);
}
}