start from 2021年12月23日11:53:20 to
1.项目介绍
- P2-19:42,项目整体开发流程。P2-1:20:05,后台管理系统admin-dist/前台管理系统api-dist,启动方法:对应文件夹cmd,npm install -g(表示全局安装) anywhere。1:27:31,启动后端界面连接网关进行请求交互,去后端打包之后进入admin-dist/js/app.js处修改网关接口。
1-1.后台系统开发
- 后端功能:1.类别增删改查、2.用户列表(用户查询/模糊查询)、3.视频列表(视频列表/模糊查询)、4.后台管理员登录,退出。
- 技术选型: SpringBoot + SpringCloud + Vue + Docker(nacos/mysql........)
- 后台项目结构:
- yingxue-admin =====> 维护后端系统全局父项目
- yingxue-commons =====> 用来存放后端系统公共代码工具类....
- yingxue-users =====> 用来完成用户列表
- yingxue-category =====> 用来完成类别接口
- yingxue-videos =====> 用来完成视频接口
- yingxue-admin =====> 用来完成后端管理员操作
- yingxue-gateway =====> 后端系统网关服务,路由转发+跨域处理:localhost:8888/9999
- 后端管理系统页面:用vue+elementui完成
- 环境搭建:1)库表入库、2)构建项目结构、3)每个微服务构建一个独立springboot应用、4)启动nacos 将每个应用作为微服务注册到nacos、5)创建服务网关 配置对应路由规则 + 跨域、6)根据接口文档开发接口,连接对应数据:json,postman、6)启动后端界面连接网关进行请求交互,去后端打包之后admin-dist/js/app.js修改网关接口。
1-2.虚拟机上安装相应的镜像
- 删除不需要的镜像,比如:
docker rmi -f centos:7
- 安装镜像:
docker pull nacos/nacos-server:2.0.2
- 创建双网卡的步骤P3-8:09:
- 进入虚拟机,找到网络配置:
cd /etc/sysconfig/network-scripts/
,ls本来会看到有两块网卡,一个叫ens33,ens37。但没有ens37配置文件,所以要拷贝:cp ifcfg-ens33 ifcfg-ens37
,接下来编辑ens37配置文件:vi ifcfg-ens37
,修改DEVICE=ens37
,NAME=ens37
,删除UUID
,修改:BOOTPROTO=static
,在最下面添加:IPADDR=10.15.0.2
,不能和上面第二张图中的IP地址(10.15.0.2)一样。保存退出并重启network:systemctl restart network
、
1-3.新建父项目
- 小技巧:安装JetBrainsToolbox自动下载更新IDEA。
- 新建一个yingxue-admin父项目:Save-Actions插件:选择General-》Activate save actions on save …… ②Formatting-Actions -》Reformat file。删除父项目的src文件夹。维护:①维护springboot父项目、②维护springcloud和springcloud-alibaba版本
父项目配置文件pom.xml
<groupId>com.jun</groupId>
<artifactId>yingxue-admin</artifactId>
<version>1.0</version>
<!--properties属性可以自定义n多个属性-->
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR6</spring-cloud.version>
<spring.cloud.alibaba.version>2.2.1.RELEASE</spring.cloud.alibaba.version>
<mybatis.spring.boot.starter.version>2.1.3</mybatis.spring.boot.starter.version>
<mysql.connector.java.version>5.1.38</mysql.connector.java.version>
<druid.vcerion>1.2.1</druid.vcerion>
<commons.fileupload.version>1.4</commons.fileupload.version>
<javacpp.version>1.4.1</javacpp.version>
<javacv.version>1.4.1</javacv.version>
<opencv.platform.version>3.4.1-1.4.1</opencv.platform.version>
<ffmpeg.platform.version>3.4.2-1.4.1</ffmpeg.platform.version>
<aliyun.java.sdk.core.version>4.5.3</aliyun.java.sdk.core.version>
<commons.lang.version>2.6</commons.lang.version>
<fastjson.version>1.2.74</fastjson.version>
<spring.data.redis.version>2.3.0.RELEASE</spring.data.redis.version>
<aliyun.sdk.oss.version>3.10.2</aliyun.sdk.oss.version>
</properties>
<!--继承SpringBoot父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<!--维护SpringCloud和SpringCloud-alibaba-->
<dependencyManagement> <!--父项目中只维护依赖-->
<dependencies>
<!--引入SpringCloud-alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--引入SpringCloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--mysql,mybatis,druid-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.java.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.starter.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.vcerion}</version>
</dependency>
</dependencies>
</dependencyManagement>
1-4.新建子模块
- 除了commons以外,每个模块都是系统中的一个微服务,每个服务都是一个独立的应用(SpringBoot应用)。新建的微服务都会向服务注册中心nacos进行注册:P3-40:54,IDEA连接远程Linux。然后创建一个yingxue文件夹,将
docker-compose.yml
文件放到该文件夹里。启动:[root@192 yingxue]# docker-compose up -d
,启动起来后可以查看日志:docker logs -f 容器id
,然后在浏览器中输入:192.168.200.130:8848/nacos
。
①yingxue-commons
- 主要用来放一些公共的工具类和一些公共的代码,公共的依赖。
pom.xml
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos-client-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
②yingxue-administrators
启动mysql并初始化数据
- 启动数据库并初始化数据:P4-3:06,原来是用docker启动mysql,然后创建数据库,执行SQL脚本。现在启动docker-mysql的时候,让其自动创建数据库yingxue,自动执行sql脚本。P4-6:19。
docker run --rm(创建一个临时的mysql,容器关闭它就自动删除了) -d -e MYSQL_ROOT_PASSWORD=root mysql:5.6
,然后进入mysql容器:docker exec -it 容器id bash
,切换目录:cd docker-entrypoint-initdb.d
,日后只需要这个目录里面有sql文件就行了。所以完整的通过docker启动mysql的语句是:docker run --name mysql01 -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=yingxue -v data:/var/lib/mysql -v ./yingxue.sql:/docker-entrypoint-initdb.d/yingxue.sql mysql:5.6
,但项目中还是用docker-compose up -d
启动的较多:
volumes:
data:
services:
# P4-10:50 将yingxue.sql上传到Linux的/root/yingxue目录下,并更新该文件夹下的docker-compose.yml
# 随后执行:[root@192 yingxue]# docker-compose up -d,连接mysql查看表以及数据库是否创建成功。
mysql:
image:
mysql:5.6
ports:
- "3306:3306"
networks:
- yingxue_network
volumes:
- data:/var/lib/mysql
- ./yingxue.sql:/docker-entrypoint-initdb.d/yingxue.sql
environment:
- "MYSQL_ROOT_PASSWORD=hrj"
- "MYSQL_DATABASE=yingxue"
登录的接口
- 用PostMan测试:
已登录-用户信息的接口
//2.已登录用户信息的接口,P6-5:00
@GetMapping("/admin-user")
public Admin admin(String token) {
log.info("当前的token信息:{}", token);
redisTemplate.setKeySerializer(new StringRedisSerializer());
return (Admin) redisTemplate.opsForValue().get(token);
}
- 从上图中可以看到null属性,null属性不再建议向前端打印,因为JSON数据越小,网络传输速度越快。所以返回数据可以不为Admin,可以定义其他对象,比如定义一个Map。但在前后端分离的开发中,大多是重新定义一个dto
//com.jun.dto.AdminDTO.java
public class AdminDTO {
//@JsonFormat //用来修改转换日期的时间格式的。
@JsonProperty("name")
//代表转换到JSON中的属性名是谁?如果不写,默认就是定义的成员变量名
private String username;
private String avatar;……}
//-----com.jun.controller.AdminController.java-------
//2.已登录用户信息的接口,P6-5:00。//vo=view object(业务返回的结果和页面想要的数据结果不一致,
//所以要把业务的结果转变成一个页面所需要的对象),在前后端分离的开发中,叫做:dto=data transfer object
@GetMapping("/admin-user")
public AdminDTO admin(String token) {
log.info("当前的token信息:{}", token);
redisTemplate.setKeySerializer(new StringRedisSerializer());
Admin admin = (Admin) redisTemplate.opsForValue().get(token);
AdminDTO adminDTO = new AdminDTO();
//1.属性复制:P6-15:42
BeanUtils.copyProperties(admin, adminDTO); //将两个对象中重复的属性拷贝
//adminDTO.setName(admin.getUsername()); //如果在AdminDTO中,name属性改为username,并且加了@JsonProperty就可以省略。
return adminDTO;
}
登出的接口
//3.登出的接口
@DeleteMapping("/tokens/{token}")
public void logout(@PathVariable("token") String token) {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.delete(token);
}
网关中的配置
gateway:
routes: # 用来配置路由规则:id、uri、path P3-56:39
- id: admins_router
uri: lb://API-ADMINS # http://localhost:8980 # 日后可能是集群,所以不能写死58:38
predicates:
- Path=/admins/demos,/admins/tokens,/admins/admin-user,/admins/tokens/**
filters: #P3-1:05:01
- StripPrefix=1 #去掉请求前缀的filter,后边需要写一个int类型的数字,1代表一级,2代表去掉两级
③yingxue-category
类别列表的接口
P8-14:42
<resultMap type="com.jun.entity.Category" id="CategoriesMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<!--封装children,p8-16:20-->
<collection property="children" javaType="list" ofType="com.jun.entity.Category">
<id property="id" column="cid" jdbcType="INTEGER"/>
<result property="name" column="cname" jdbcType="VARCHAR"/>
<result property="parentId" column="cparentId"/>
</collection>
</resultMap>
<!--查询类别,一级类别父ID没值。P8-14:42-->
<select id="queryByFirstLevel" resultMap="CategoriesMap">
select c.id, c.name, c1.id cid, c1.name cname, c1.parent_id cparentId
from yingxue.category c
left join yingxue.category c1
on c.id = c1.parent_id
where c.parent_id is null;
</select>
//1.类别列表
@GetMapping
public List<Category> categories() {
return categoryService.queryByFirstLevel();
}
类别更新的接口
//com.jun.controller.CategoryController.java
//2.修改列表接口
@PatchMapping("/{id}")
public Category update(@PathVariable("id") Integer id, @RequestBody Category category) {
log.info("更新类别的id:{}", id);
log.info("更新类别的信息:{}", JSONUtils.writeJSON(category));
//更新:P9-7:13
category.setId(id);
return categoryService.update(category);
}
类别添加的接口
//3.添加类别的接口 com.jun.controller.CategoryController.java
@PostMapping
public Category save(@RequestBody Category category) {
log.info("添加类别的信息:{}", JSONUtils.writeJSON(category));
return categoryService.insert(category);
}
//com.jun.service.impl.CategoryServiceImpl.java
@Override
public Category insert(Category category) {
Date date = new Date();
category.setCreatedAt(date);
category.setUpdatedAt(date);
this.categoryDao.insert(category);
return category;//返回的Category是否存在id?
}
<!--新增所有列,useGeneratedKeys针对于mysql数据库可用,使用数据自动递增id;
keyProperty将数据库本次生成的id赋值给参数对象的哪个属性。-->
<insert id="insert" parameterType="com.jun.entity.Category" keyProperty="id" useGeneratedKeys="true">
insert into category(name, parent_id, created_at, updated_at, deleted_at)
values (#{name}, #{parentId}, #{createdAt}, #{updatedAt}, #{deletedAt})
</insert>
后端系统的结合接口测试
- 上传admin-dist文件夹到项目的根目录,Ctrl+f搜localhost,
baseURL:"http://localhost:9999/admin"
而此时我们的网关地址为:
网关的配置
server:
port: 9999
spring:
application:
name: API-GATEWAY
cloud:
nacos:
server-addr: 192.168.200.130:8848
gateway:
routes: # 用来配置路由规则:id、uri、path P3-56:39
- id: admins_router
uri: lb://API-ADMINS # http://localhost:8980 # 日后可能是集群,所以不能写死58:38
predicates:
- Path=/admins/demos,/admins/tokens,/admins/admin-user,/admins/tokens/**
filters: #P3-1:05:01
- StripPrefix=1 #去掉请求前缀的filter,后边需要写一个int类型的数字,1代表一级,2代表去掉两级
# category router
- id: category_router
uri: lb://API-CATEGORY
predicates: # P8-9:31
- Path=/category/demos,/category/categories,/category/categories/**
filters:
- StripPrefix=1
# videos router
- id: videos_router
uri: lb://API-VIDEOS
predicates:
- Path=/videos/demos
filters:
- StripPrefix=1
# users router
- id: users_router
uri: lb://API-USERS
predicates:
- Path=/users/demos
filters:
- StripPrefix=1
globalcors: #跨域配置处理 P3-1:10:28
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"
- 启动admin-dist,先切换到目录下:
cd admin-dist
,然后启动(P1-1:21:13):anywhere -p 9091(端口随便写)
,P12-3:00
。推荐好用的图床:路过图床。 - 全局安装:
D:\笔记\青橙小店\SpringCloud&Alibaba微服务综合实战项目\资料\admin-dist>npm install -g anywhere
④yingxue-users
⑤yingxue-videos
⑥yingxue-gateway
- 网关底层默认集成的是ribbon,ribbon是负载均衡的客户端。P3-1:03:26,介绍网关。Gateway=router路由+filter过滤