01-index

目标:完整了解做项目的思路,接触一些企业级的开发技术,让大家之后都能轻松做出管理系统!

1. 企业做项目流程

  1. 需求分析
  2. 设计(概要设计、详细设计)
  3. 技术选型
  4. 初始化 / 引入需要的技术
  5. 写 Demo
  6. 写代码(实现业务逻辑)
  7. 测试(单元测试、系统测试)
  8. 代码提交 / 代码评审
  9. 部署
  10. 发布上线

2. 需求分析

  1. 登录 / 注册
  2. 用户管理(仅管理员可见)对用户的查询、修改
  3. 用户校验(仅用户可见)

3. 技术选型

前端:三件套 + React + 组件库 Ant Design + Umi + Ant Design Pro(现成的管理系统)

后端:

  • Java
  • Spring(依赖注入框架,帮助管理 Java 对象,集成一些其他的内容)
  • SpringMVC(web 框架,提供接口访问、restful 接口等能力)
  • Mybatis(Java 操作数据库的框架,持久层框架,对 jdbc 的封装)
  • Mybatis-Plus(对 mybatis 的增强,不用写 sql 也能实现增删改查)
  • SpringBoot(快速启动 / 快速集成项目。不用手动管理 spring 配置,不用整合各种框架)
  • Junit 单元测试库
  • Mysql 数据库

部署:服务器 / 容器(平台)

4. 3种初始化java项目

  1. GitHub 现成的代码
  2. SpringBoot 官方的模板生成open in new window
  3. 直接在 IDEA 开发工具中生成

如果要引入 jar 包,去 maven 中心仓库open in new window

5. 数据库设计

1. 用户表设计

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `username` varchar(256) DEFAULT NULL COMMENT '用户昵称',
  `userAccount` varchar(256) DEFAULT NULL COMMENT '账号',
  `avatarUrl` varchar(1024) DEFAULT NULL COMMENT '用户头像',
  `gender` tinyint(4) DEFAULT NULL COMMENT '性别',
  `userPassword` varchar(512) NOT NULL COMMENT '密码',
  `phone` varchar(128) DEFAULT NULL COMMENT '电话',
  `email` varchar(512) DEFAULT NULL COMMENT '邮箱',
  `userStatus` int(11) NOT NULL DEFAULT '0' COMMENT '状态 0 - 正常',
  `createTime` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updateTime` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `isDelete` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否删除',
  `userRole` int(11) NOT NULL DEFAULT '0' COMMENT '用户角色 0 - 普通用户 1 - 管理员',
  `planetCode` varchar(512) DEFAULT NULL COMMENT '星球编号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户';

2. 自动生成器的使用

MyBatisX 插件,自动根据数据库生成:

  • domain:实体对象
  • mapper:操作数据库的对象
  • mapper.xml:定义了 mapper 对象和数据库的关联,可以在里面自定义 SQL
  • service:包含常用的增、删、改、查
  • serviceImpl:具体实现 service

6. 注册逻辑设计

  1. 用户在前端输入账户和密码、以及校验码
  2. 校验用户的账户、密码、校验密码,是否符合要求
    1. 非空
    2. 账户长度 >= 4 位
    3. 密码 >= 8 位
    4. 账户不能重复
    5. 账户不包含特殊字符
    6. 密码和校验密码相同
  3. 对密码进行加密(DB 不能存明文密码)
  4. 向数据库插入用户数据
if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword, planetCode)) {
    throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
}

7. 登录功能

1. 接口设计

  • 接受参数:用户账户、密码
  • 请求类型:POST
  • 请求体:JSON 格式的数据
  • 返回值:用户信息(脱敏

请求参数很长时不建议用 get

2. 登录逻辑

  1. 校验用户账户和密码是否合法
  2. 非空
  3. 账户长度不小于 4 位
  4. 密码就不小于 8 位
  5. 账户不包含特殊字符
  6. 校验密码是否输入正确,要和数据库中的密文密码去对比
  7. 用户信息脱敏,隐藏敏感信息,防止数据库中的字段泄露
  8. 记录用户的登录态(session),将其存到服务器上(用后端 SpringBoot 框架封装的服务器 tomcat 去记录)
  9. 返回脱敏后的用户信息 cookie

3. 实现

application.yml 指定接口全局路径前缀

servlet:
  context-path: /api

校验写在哪里?

  • controller:倾向于对请求参数本身的校验,不涉及业务逻辑本身(越少越好)
  • service:对业务逻辑的校验(有可能被 controller 之外的类调用)

4. 如何知道是哪个用户登录

  1. 连接服务器端后,得到一个 session 状态(匿名会话),返回给前端
  2. 登录成功后,得到了登录成功的 session,并且给该 session 设置一些值(用户信息),返回给前端一个设置 cookie 的 ”命令“ session => cookie
  3. 前端接收到后端的命令,设置 cookie,保存到浏览器内
  4. 前端再次请求后端的时候(相同的域名),在请求头中带上 cookie
  5. 后端拿到前端传来的 cookie,找到对应的 session
  6. 后端从 session 中可以取出基于该 session 存储的变量(用户的登录信息、登录名)

Auto filling Java call 插件

8. 用户管理

接口设计关键:必须鉴权!!!

  1. 查询用户(允许根据用户名查询)
  2. 删除用户
cUVuYTVyNUVVYTlJcUVINGFzV1FpNEJCMmt1VWZEazNPWDgwcnRKc0lBPT0=

9. 前后端交互

前端使用 ajax 来请求后端

1. 前端请求及封装关系

  • axios 封装了 ajax
  • request 是 ant design 项目又封装了一次

追踪 request 源码:用到了 umi 的插件、requestConfig 配置文件

10. 代理

正向代理:替客户端向服务器发送请求,可以解决跨域问题

  • Node.js 服务器

反向代理:替服务器统一接收请求

  • Nginx 服务器

  • 原本请求:http://localhost:8000/api/user/login
  • 代理请求:http://localhost:8080/api/user/login
dDFrNUxmYTNlQVU4cGJXTXdiT3BudWZjZEo4dFJ6ZGxjSkFiNmdjPQ==

11. 前端框架介绍

1. Ant Design Pro 初始化

框架由他人开发,经常变动,所以请勿必阅读 官方文档open in new window

# 使用 npm
npm i @ant-design/pro-cli -g
pro create myapp

接下来选择框架版本,一定要选 v3!!!

ZHA4QlBvWTNMaHB5aHU4NHZkRTdjdWZjZEo4dFJ6ZGxjSkFiNmdmelJnPT0=
# 安装依赖 package.json
yarn

# 打开开发模式下页面右下角的小气泡,方便添加区块和模版等pro资产
tyarn add @umijs/preset-ui -D
npm install --save-dev @umijs/preset-ui
WFZGYUppN2dWdGdPcWZnWFNDc1p5R0J6OGU3SlJBYzBHL1NLdjlZQm1nPT0=
enRXaUs5M216M1AvT3lIeWVwZWZ5MkJ6OGU3SlJBYzBHL1NLdjlZQm1nPT0=

2. Umi 框架权限管理

  • app.tsx:项目全局入口文件,定义了整个项目中使用的公共数据(eg:用户信息)
  • access.ts:控制用户的访问权限

获取初始状态流程:首次访问页面(刷新页面),进入 app.tsx,执行 getInitialState(),该方法的返回值就是全局可用的状态值

3. ProComponents高级表单

  1. 通过 columns 定义表格有哪些列
  2. columns 属性
    • dataIndex:对应返回数据对象的属性
    • title:表格列名
    • copyable:是否允许复制
    • ellipsis:是否允许缩略
    • valueType:用于声明这一列的类型(dateTime、select)

4. 框架关系

  • 《Ant Design》组件库 => 基于 React 实现
  • 《Ant Design Procomponents》 => 基于《Ant Design》实现
  • 《Ant Design Pro》后台管理系统 => 基于《Ant Design》+《React》+《Ant Design Procomponents》+ 其他的库实现

5. 其他知识

MFSU:前端编译优化

12. 后端优化

1. 通用返回对象

目的:给对象补充一些信息,告诉前端这个请求在业务层面上是成功还是失败

  • 200、404、500、502、503
  • 自定义错误码,返回类支持返回正常和错误
{
    "name": "yupi"
}
// 成功
{
    "code": 0 // 业务状态码
    "data": {
        "name": "yupi"
    },
	"message": "ok"
}
// 错误
{
    "code": 50001 // 业务状态码
    "data": null
	"message": "用户操作异常、xxx"
}

2. 封装全局异常处理器

1. 实现

  1. 定义业务异常类
  2. 相对于 java 的异常类,支持更多字段
  3. 自定义构造函数,更灵活 / 快捷的设置字段
  4. 编写全局异常处理器(利用 Spring AOP,在调用方法前后进行额外的处理)

2. 作用

  1. 捕获代码中所有的异常,内部消化,让前端得到更详细的业务报错 / 信息
  2. 同时屏蔽掉项目框架本身的异常(不暴露服务器内部状态)
  3. 集中处理。eg:记录日志

13. 前端优化

1. 全局响应处理

对接口的 通用响应 进行统一处理

  • 从 response 中取出 data
  • 根据 code 去集中处理错误。比如用户未登录、没权限...

参考请求封装工具的官方文档

14. 用户校验

  • 先让用户自己填:2 - 5 位编号,全凭自觉
  • 后台补充对编号的校验:长度校验、唯一性校验
  • 前端补充输入框,适配后端

后期拉取星球数据,定期清理违规用户

15. 多环境

多环境:指同一套项目代码在不同的阶段需要根据实际情况来调整配置,并且部署到不同的机器上

  1. 本地环境:localhost(127.0.0.1)
  2. 开发环境(远程开发):大家连同一台机器,为了大家开发方便
  3. 测试环境(测试)开发 / 测试 / 产品,单元测试 / 性能测试 / 功能测试 / 系统集成测试,独立的数据库、独立的服务器
  4. 预发布环境(体验服):和正式环境一致,正式数据库,更严谨,查出更多问题
  5. 正式环境(线上,公开对外访问的项目):尽量不要改动,保证上线前的代码是 “完美” 运行
  6. 沙箱环境(实验环境):为了做实验

  1. 每个环境互不影响
  2. 区分不同的阶段:开发 / 测试 / 生产
  3. 对项目进行优化
    1. 本地日志级别
    2. 精简依赖,节省项目体积
    3. 项目的环境 / 参数可以调整,比如 JVM 参数

1. 前端多环境实战

startFront(env) {
    if(env === 'prod') {
        // 不输出注释
        // 项目优化
        // 修改请求地址
    } else {
        // 保持本地开发逻辑
    }
}

用了 umi 框架,build 时会自动传入 NODE_ENV == production 参数,start NODE_ENV 参数为 development

  • 启动方式
    • 开发环境:npm run start(本地启动,监听端口、自动更新)
    • 线上环境:npm run build(项目构建打包),可以使用 serve 工具启动 npm i -g serve
  • 项目的配置。不同的项目(框架)都有不同的配置文件,umi 的配置文件是 config,对应的环境名称后缀来区分开发环境和生产环境
    • 开发环境:config.dev.ts
    • 生产环境:config.prod.ts
    • 公共配置:config.ts 不带后缀

2. 后端多环境实战

SpringBoot 项目,通过 application.yml 添加不同的后缀来区分配置文件

java -jar .\user-center-backend-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
  • 依赖的环境地址
    • 数据库地址
    • 缓存地址
    • 消息队列地址
    • 项目端口号
  • 服务器配置

16. 项目部署

需要 Linux 服务器(建议大家用 CentOS 8+ / 7.6 以上)

1. 原始部署

1. 前端

web 服务器: nginx 、apache、tomcat

安装 nginx 服务器

  1. 用系统自带的软件包管理器快速安装,比如 centos 的 yum
  2. 自己到官网安装(参考文章)
curl -o nginx-1.21.6.tar.gz http://nginx.org/download/nginx-1.21.6.tar.gz

tar -zxvf nginx-1.21.6.tar.gz

cd nginx-1.21.6

yum install pcre pcre-devel -y

yum install openssl openssl-devel -y

./configure --with-http_ssl_module --with-http_v2_module --with-stream

make
make install
ls /usr/local/nginx/sbin/nginx

vim /etc/profile
# 在最后一行添加
export PATH=$PATH:/usr/local/nginx/sbin

nginx

# 查看启动情况
netstat -ntlp

2. 后端

jdk、maven 安装

yum install -y java-1.8.0-openjdk*

curl -o apache-maven-3.8.5-bin.tar.gz https://dlcdn.apache.org/maven/maven-3/3.8.5/binaries/apache-maven-3.8.5-bin.tar.gz

# 下载代码
git clone xxx

# 打包构建,跳过测试
mvn package -DskipTests

java -jar ./user-center-backend-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

2. 宝塔Linux部署

Linux 运维open in new window

3. 前端托管

前端腾讯云 web 应用托管(比容器化更傻瓜式,不需要写构建应用的命令,就能启动前端项目)

  • 小缺点:需要将代码放到代码托管平台上
  • 优势:不用写命令、代码更新时自动构建

4. Docker部署

docker 是容器,可以将项目的环境(java、nginx)和项目的代码一起打包成镜像,更容易分发和移植。再启动项目时,不需要敲一大堆命令,而是直接下载镜像、启动镜像就可以了

虚拟化

  1. 端口映射:把本机的资源(实际访问地址)和容器内部的资源(应用启动端口)进行关联
  2. 目录映射:把本机的端口和容器应用的端口进行关联
# 前端
docker run -p 80:80 -d user-center-frontend:v0.0.1

# 后端
docker run -p 8080:8080 user-center-backend:v0.0.1

# 进入容器
docker exec -i -t  fee2bbb7c9ee /bin/bash

# 查看进程
docker ps

# 查看日志
docker logs -f [container-id]

# 杀死容器
docker kill

# 强制删除镜像
docker rmi -f

1. Dockerfile

  • FROM:依赖的基础镜像
  • WORKDIR:工作目录
  • COPY:从本机复制文件
  • RUN:执行命令
  • CMD / ENTRYPOINT:(附加额外参数)指定运行容器时默认执行的命令
# 后端,构建镜像
docker build -t user-center-backend:v0.0.1 .

# 前端,构建镜像
docker build -t user-center-front:v0.0.1 .

Docker 构建优化:减少尺寸、减少构建时间(eg:多阶段构建,可以丢弃之前阶段不需要的内容)

5. Docker平台部署

  1. 云服务商的容器平台(腾讯云、阿里云)
  2. 面向某个领域的容器平台(前端 / 后端微信云托管) 要花钱!

容器平台的好处:

  1. 不用输命令来操作,更方便省事
  2. 不用在控制台操作,更傻瓜式、更简单
  3. 大厂运维,比自己运维更省心
  4. 额外的能力:监控、告警、其他(存储、负载均衡、自动扩缩容、流水线)

17. 绑定域名

前端项目访问流程:

  1. 用户输入网址
  2. 域名解析服务器(把网址解析为 ip 地址 / 交给其他的域名解析服务)
  3. 服务器(防火墙)
  4. nginx 接收请求,找到对应的文件,返回文件给前端
  5. 前端加载文件到浏览器中(js、css)=> 渲染页面

后端项目访问流程:

  1. 用户输入网址
  2. 域名解析服务器
  3. 服务器
  4. nginx反向代理,替服务器接收请求,转发请求
  5. 后端项目(8080端口)

18. 跨域问题解决

浏览器为了用户的安全,仅允许向 同域名、同端口 的服务器发送请求

1. 添加跨域头

让服务器告诉浏览器:允许跨域(返回 cross-origin-allow 响应头)

1. 网关支持(Nginx)

# 跨域配置
location ^~ /api/ {
    proxy_pass http://127.0.0.1:8080/api/;
    add_header 'Access-Control-Allow-Origin' $http_origin;
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers '*';
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Origin' $http_origin;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
    }
}

2. 修改后端服务

SpringBoot设置Cors跨域的四种方式open in new window

  1. 配置 @CrossOrigin 注解
  2. 添加 web 全局请求拦截器
@Configuration
public class WebMvcConfg implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //设置允许跨域的路径
        registry.addMapping("/**")
                //设置允许跨域请求的域名
                //当 **Credentials为true时,** Origin不能为星号,需为具体的ip地址【如果接口不带cookie,ip无需设成具体ip】
                .allowedOrigins("http://localhost:9527", "http://127.0.0.1:9527", "http://127.0.0.1:8082", "http://127.0.0.1:8083")
                //是否允许证书 不再默认开启
                .allowCredentials(true)
                //设置允许的方法
                .allowedMethods("*")
                //跨域允许时间
                .maxAge(3600);
    }
}
  1. 定义新的 CorsFilter

19. 项目优化点

  1. 功能扩充
    1. 管理员创建用户、修改用户信息、删除用户
    2. 上传头像
    3. 按照更多的条件去查询用户
    4. 更改权限
  2. 修改 Bug
  3. 项目登录改为分布式 session(单点登录 - redis)
  4. 通用性
    1. set-cookie domain 域名更通用。eg:改为 *.xxx.com
    2. 把用户管理系统 => 用户中心(之后所有的服务都请求这个后端)
  5. 后台添加全局请求拦截器(统一去判断用户权限、统一记录请求日志)