# user-center-front **Repository Path**: itholmes/user-center-front ## Basic Information - **Project Name**: user-center-front - **Description**: 用户中心系统,实现用户登录、注册、管理用户信息等功能。 - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2022-09-02 - **Last Updated**: 2023-11-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: React ## README # 前端环境搭建 ## Ant Design Pro 环境搭建 **ant design pro 使用的是 5.2.0 版本,去 github 的 tag 上面找一下就行。其他版本试了试坑很多。。** 修改 yarn 的镜像源: ```shell # 安装yarn npm install --global yarn # 修改镜像源 yarn config set registry https://registry.npm.taobao.org -g yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g ``` 解决卷标语法不正确:(通过修改 yarn 全局目录) ```shell # 安装依赖 yarn # 查看yarn的目录 yarn global bin # 查看yarn全局目录 yarn global dir # 因为我电脑的yarn目录和安装的模块不在相同的硬盘分区里导致的 ; 于是去修改 yarn的全局安装位置和缓存位置: yarn config set global-folder "D:\nodejs\yarn\global" yarn config set cache-folder "D:\nodejs\yarn\cache" ``` **有时候权限不够,可以去修改 nodejs 文件夹,将其设置为完全控制。** 开启 Umi UI: ```shell yarn add @umijs/preset-ui -D # 或 npm install --save-dev @umijs/preset-ui # 其实Umi UI的原理就是通过git克隆或者pull下来。。 # 这样就会有一个米饭小图标,点击对应模块添加就可以了。 # .umi3文件,我们可以去c盘查看到一个.umi3的一个文件。 # 如果遇到git仓库的问题可以去看看.umi3文件,删除也没事。就是你使用uim ui创建也页面的一些数据存到这个文件夹下面。 ``` 删除安装好的模块: ``` 直接对应pages的目录删除,并且删除router文件对应的路径。 ``` 国际化英文单词:internationalization 的首末字符 i 和 n,18 为中间的字符数。 ant design pro 移除国际化: ```json "i18n-remove": "pro i18n-remove --locale=zh-CN --write", ``` ## Ant Design Pro 目录介绍 > config 目录: > > 存储一些配置文件。 > dist 目录: > > 项目打包后存储的目录。 > mock 目录:(假数据) > > 模拟数据的目录。 > public 目录: > > 存放一些静态资源,像图标,视频音频等。 > src 目录:写代码的目录。 > > - components 目录:存放组件。 > - pages 目录:存放页面。 页面与组件的区别,页面一般是唯一的,一个页面包含许多组件。可以理解为包含被包含的关系把。 > - locales 目录:国际化的文件,可以 i18n-remove 移除对应的国际化效果。 > - e2e 目录:里面定义了一些列的测试流程,一般是可以删除的额。 > tests 目录: > > 测试目录。可以删除。 app.tsx 文件:是整个项目的入口。 glocal.less 文件:是一个全局样式文件,所有文件都引用了该样式文件。 glocal.tsx 文件:全局的脚本文件。 .editorconfig 文件:编辑器配置。 .eslint:检查 js 代码语法。 .prettierrc.js 文件:是一个美化代码的一个工具。 jest.config.js 文件:也是一个测试工具,可以删除。 .stylelintrc.js 文件:检查 css 语法。 playwright.config.ts 文件:也是一个测试工具。可以删除。 # 后端环境搭建 **SpringBoot 构建的三种方式:** - 可以去 github 官方搜索,springboot-template,找一些其他人写的模板(不建议使用)。 - SpringBoot 官方的模板生成器。 - 直接在 IDEA 中生成。 **Mybatis-plus:就是对 mybatis 的增强,不用写 sql 也能实现增删改查。** ```java //通过继承BaseMapper实现,外加上一个实体类。 extends BaseMapper ``` > **@runWith 注解作用:** > > @RunWith 就是一个运行器 > > @RunWith(JUnit4.class)就是指用 JUnit4 来运行 > > @RunWith(SpringJUnit4ClassRunner.class),让测试运行于 Spring 测试环境 > > @RunWith(SpringRunner.class) springboot > > **有些时候,也能没有 runwith 也能跑起来,是和@Test 注解有关!!!** > > ```java > import org.junit.jupiter.api.Test; //就不需要引入runwith指定启动器。 > @Test > ``` > **为什么性别不适合建索引?** > > 如果你是从 100 万行数据中取 50 万行数据,就比如性别字段,那你相对需要访问 50 万次索引,再访问 50 万次表,加起来的开销并不会比直接对表进行一次完整扫描小。 ```sql -- 插入的时候,下面的语句null就是可以为null,on update就是数据字段有变更时,会更新为当前时间。 updateTime datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP ``` ## 后端代码 > **MyBatisX 插件,自动根据数据库生成 model/domain/pojo/bean 实体对象,mapper(操作数据库对象),mapper.xml(定义 mapper 对象和数据库关联,可以自己写 SQL),service 和 serviceImpl 逻辑层的增删改查。** > **自动生成 pojo 类的 插件:** > > - **安装一个 idea 插件,叫做 GenerateAllSetter。可以自动生成假数据。** > **mybatis-plus 如果是插入操作,会给原来的对应 pojo 对象赋予插入的主键 ID。** ### 注册逻辑 注意事项: 1. 校验用户的账户,密码,校验密码,是否符合要求。 - 账户不小于 4 位。 - 密码不小于 8 位。 - 账户不能重复。 - 账户不包含特殊字符。 - 密码和校验密码相同。 - 校验是否为 null 或者空字符串等。 2. 对密码加密(密码千万不要直接存储到数据库中) > **Apache Commons Lang 包的作用:对于一些判断是否位空的一些数据** > > ```java > //1. 没有commons Lang包的校验 > if (userAccount == null || userPassword == null || checkPassword == null || userAccount.length() > 0 ... ){ //要校验很多。 > > } > > //有了commons Lang包的校验 > //1. 校验 通过commons lang下面的StringUtils直接校验了三个参数的相关信息。 > if (StringUtils.isAllBlank(userAccount,userPassword,checkPassword)){ > > } > ``` > **hutool 糊涂工具类很好用!!!** > **平时的一些逻辑校验,我们最好按照最优的顺序进行一个顺序判断,避免多余的情况发生。** > **多了解一些加密:** > > ```java > @Test > void junitTest01() throws Exception{ > //MessageDigest的加密。 > MessageDigest md5 = MessageDigest.getInstance("MD5"); > //多了解一些加密的东西,DigestUtils,加入一个salt盐 + 用户密码进而加密。 > String s = DigestUtils.md5DigestAsHex(("salt" + "mypassword").getBytes()); > System.out.println(s); > } > ``` > **注意:long 和 Long 不同!很容易混淆!!** ### 登录逻辑 请求参数:账户 + 密码。 方法:post 返回值:用户信息(记得脱敏,脱敏就是隐藏敏感信息,不返回密码) 注意事项: - 校验用户账户和密码是否合法。 - 非空 - 账户长度不小于 4 - 密码不小于 8 - 账户不包含特殊字符 - 校验密码是否正确 - 要记录用户的登录态(session),存在服务器上(cookie) - 返回用户信息(脱敏) > **mybatis-plus 的逻辑删除:(不懂可以取官方搜一下)** > > ```yaml > mybatis-plus: > global-config: > db-config: > logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) > logic-delete-value: 1 # 逻辑已删除值(默认为 1) > logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) > ``` > **插件 Auto filling Java call arguments:自动填充参数的插件。** > **为什么 controller 层进行了校验,service 层还要进行一次校验呢?** > > **controller 层倾向于对请求参数本身的校验,不涉及业务逻辑本身(越少越好)。** > > **service 层是对业务逻辑的校验(有可能被 controller 之外的类调用)。** > **测试使用 idea 自带的 http client 就可以,**可以直接接口右边的小图标是可以的! > **mybatis-plus 的逻辑删除:如果开启了 mybatis-plus 的逻辑删除,此时就会将删除 改为 更新。** > **注意必须,鉴权!!!** > > **判断是否有权限调用这个接口。** > **经典 NPE,空指针异常。** > **SpringBoot 设计失效时间:** > > ```yaml > # session失效时间,86400就是一天的时间 > spring: > session: > timeout: 86400 > ``` > **Java8 版本的 steam 流!!!** > **要求访问该 springboot 的请求路径必须有前缀/api:** > > ```yaml > server: > servlet: > context-path: /api > ``` > **对于泛型基本数据类型不能使用,必须使用对应的包装类型才可以!!** > > 例如: > > ```java > BaseResponse 和 BaseResponse 就很容易忽略。 > ``` > 枚举值不支持 set 方法!!! > > ```java > package com.itholmes.usercenter.common; > > /** > * @projectName: user-center > * @package: com.itholmes.usercenter.common > * @className: ErrorCode > * @author: xuyanbo > * @description: 全局错误码 > * @date: 2022/7/25 21:14 > * @version: 1.0 > */ > public enum ErrorCode { > > /** > * 封装一些统一状态码 > */ > SUCCESS(0,"ok",""), > PARAMS_ERROR(40000,"请求参数错误",""), > NULL_ERROR(40001,"请求为空",""), > NOT_LOGIN(40100,"未登录",""), > NO_AUTH(40101,"无权限",""); > > private final int code; > private final String message; > private final String description; > > ErrorCode(int code, String message, String description) { > this.code = code; > this.message = message; > this.description = description; > } > > public int getCode() { > return code; > } > > public String getMessage() { > return message; > } > > public String getDescription() { > return description; > } > } > ``` ### 封装全局异常处理 1. 定义业务异常类(继承 Exception 等等,一般自定义异常类在 exception 包下面) 自定义异常类: ```java package com.itholmes.usercenter.exception; import com.itholmes.usercenter.common.ErrorCode; /** * @author: xuyanbo * @description: 自定义异常类 * @date: 2022/7/30 12:55 */ public class BusinessException extends RuntimeException{ private final int code; private String description; public BusinessException(String message,int code,String description){ super(message); this.code = code; this.description = description; } public BusinessException(ErrorCode errorCode){ super(errorCode.getMessage()); this.code = errorCode.getCode(); this.description = errorCode.getDescription(); } //ErrorCode是一个自定义的枚举类 public BusinessException(ErrorCode errorCode,String description){ super(errorCode.getMessage()); this.code = errorCode.getCode(); this.description = description; } public int getCode() { return code; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } } ``` 自定义枚举类: ```java package com.itholmes.usercenter.common; /** * @author: xuyanbo * @description: 全局错误码 * @date: 2022/7/25 21:14 */ public enum ErrorCode { /** * 封装一些统一状态码 */ SUCCESS(0,"ok",""), PARAMS_ERROR(40000,"请求参数错误",""), NULL_ERROR(40001,"请求为空",""), NOT_LOGIN(40100,"未登录",""), NO_AUTH(40101,"无权限",""), SYSTEM_ERROR(50000,"系统内部异常",""); private final int code; private final String message; private final String description; ErrorCode(int code, String message, String description) { this.code = code; this.message = message; this.description = description; } public int getCode() { return code; } public String getMessage() { return message; } public String getDescription() { return description; } } ``` result 类: ```java package com.itholmes.usercenter.common; import lombok.Data; import java.io.Serializable; /** * @projectName: user-center * @package: com.itholmes.usercenter.common * @className: BaseResponse * @author: xuyanbo * @description: 通用返回类 * @date: 2022/7/25 20:38 */ @Data public class BaseResponse implements Serializable { private int code; private T data; private String message; private String description; public BaseResponse(int code, T data,String message) { this(code,data,message,""); } public BaseResponse(int code, T data,String message,String description) { this.code = code; this.data = data; this.message = message; this.description = description; } public BaseResponse(int code, T data) { this(code,data,"",""); } public BaseResponse(ErrorCode errorCode){ this(errorCode.getCode(),null,errorCode.getMessage()); } } ``` result 封装类: ```java package com.itholmes.usercenter.common; /** * @projectName: user-center * @package: com.itholmes.usercenter.common * @className: ResultUtils * @author: xuyanbo * @description: 返回工具类 * @date: 2022/7/25 20:52 */ public class ResultUtils { /** * 通用返回 成功 * @param data * @param * @return */ public static BaseResponse success(T data){ return new BaseResponse<>(0,data,"ok"); } /** * 通用返回 失败 * @param errorCode * @return */ public static BaseResponse error(ErrorCode errorCode){ return new BaseResponse(errorCode); } /** * 失败 * @param code * @param messsage * @param description * @return */ public static BaseResponse error(int code,String messsage,String description){ return new BaseResponse(code,null,messsage,description); } /** * 失败 * @param errorCode * @param messsage * @param description * @return */ public static BaseResponse error(ErrorCode errorCode,String messsage,String description){ return new BaseResponse(errorCode.getCode(),null,messsage,description); } /** * 失败 * @param errorCode * @param description * @return */ public static BaseResponse error(ErrorCode errorCode,String description){ return new BaseResponse(errorCode.getCode(),errorCode.getMessage(),description); } } ``` 自定义统一异常处理类: ```java package com.itholmes.usercenter.exception; import com.itholmes.usercenter.common.BaseResponse; import com.itholmes.usercenter.common.ErrorCode; import com.itholmes.usercenter.common.ResultUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * @author: xuyanbo * @description: 全局异常处理器 * @date: 2022/7/30 13:15 */ //原理是SpringAOP的作用 @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { //捕获自定义异常 @ExceptionHandler(BusinessException.class) public BaseResponse businessExceptionHandler(BusinessException e){ log.error("businessException: " + e.getMessage() , e); return ResultUtils.error(e.getCode(),e.getMessage(),e.getDescription()); } @ExceptionHandler public BaseResponse runtimeExceptionHandler(RuntimeException e){ log.error("runtimeException",e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR,e.getMessage(),""); } } ``` 2. 编写全局异常处理器。 - 就是统一异常处理,捕获全局的异常,达到内部消化、集中处理的效果。返回给前端更加详细的信息。 - 屏蔽掉项目框架本身的异常,不暴露服务器内部状态,有一定的安全效果。 - 集中记录日志,封装日志。 ## 前端修改 ### ant design pro 常见细节 > ```tsx > // @ts-ignore 这里忽略当前错误 > ``` > **import 引入的时候能够看到 @ 符号,表示的是根目录 src。** > ```html > 统一管理所有用户信息等情况 > ``` > > **target 选择跳转页面方式。rel="noreferrer"是用来隐藏我们的跳转来源。** > **搞清楚下面三个东西的关系:** > > - **ant design 组件库 = 封装了 React** > > - **Ant Design Pro procomponents =》 封装了 Ant Design**。**https://procomponents.ant.design/** > > - **Ant Design Pro 后台管理系统 =》 由 Ant Design,React,Ant Design Procomponents 组合而成的。** > **解释一下以下代码:** > > - **?号代表这个属性有没有都可以,这叫做类型约束。** > - **string 代表的是这个属性的类型。** > > ```tsx > type RegisterParams = { > userAccount?: string; > userPassword?: string; > checkPassword?: string; > type?: string; > }; > > //ts想要运行,需要先编译为js。 > ``` ### webstrom 的快捷键 > **webstorm:ctrl + alt + o(optimize:优化) , 去掉所有没有用到的标签。** > **shift + f6 选中某个变量或者常量,进行重构。** > > **shift + f6 能够重构这个字段,一改全都改。** > **如何查找源码:** > > ![1658411764160](.\image\1658411764160.jpg) ### ant design pro 项目一直处于 loading 问题解决 > **ant design pro 项目,启动后在 src 下面会有一个.umi 文件,项目一直处于 loading 的时候就可以考虑删除一下.umi 文件,相当于清除缓存,然后项目就跑通了。** ### --save 和 --save-dev 有啥区别 > 1. **npm install moduleName --save** 简写 -s,将模块安装到项目 node_modules 目录下,也会将模块依赖写入 dependencies 节点,同时运行 npm install 初始化项目时会将模块下载到项目目录下。 > 2. **npm install moduleName --save-dev** 简写 -d,将模块安装到项目 node_modules 目录下,也会将模块依赖写入 devDependencies 节点,同时运行 npm install 初始化项目时,会将模块下载到项目目录下。 > > **dependencies 节点是项目运行时的依赖,当程序上线后仍然需要的依赖,比如 express 这些,这时需要 --save 参数** > **而 devDependencies 节点是开发依赖,当我们在开发时会用到这些依赖,当项目部署了就不需要了,如 webpack、gulp、babel 这些, 这时需要 --save-dev 参数** > > npm install eslint --save-dev ,其中 --save-dev 表示会把 eslint 安装到 package.json 文件中的 devDependencies 属性中,意思是只是开发阶段用到这个包,上线时就不需要这个包了 ### idea 自定义快捷创建 > **settings - 》 Live Templates -》 新建一个分组 customJava(随便) -》 设置好 Template text(想要快捷生成的代码) 和 Abbreviation (快捷代码块) ,Description 描述。** **可以使用$END$生成代码后,定义鼠标的位置。** ### 统一处理后端返回来的数据 在 typings.d.ts 文件中,定义通用返回类型: ```ts /** * 通用返回类 */ type BaseResponse = { code: number; data: T; message: string; description: string; }; ``` 再通过使用 responseInterceptor 全局拦截处理。 # 多环境设计 **概念:[https://blog.csdn.net/weixin_41701290/article/details/120173283](https://blog.csdn.net/weixin_41701290/article/details/120173283)** 多环境设计最好的办法设计思想: 最理想的效果应该是:无论项目要切换到哪个环境,整个项目都完全不用修改。 因此,我们可以将 指定环境 这件事放到最后,在通过命令去打包或者启动项目时,将环境参数写进去。 举个例子,我们在启动 java 项目时,给 env 系统变量传递不同参数: ```shell # 测试环境 java -jar -Denv=test dist.jar # 生产环境 java -jar -Dend=prod dist.jar ``` 然后在程序中读取该参数,加载对应的配置即可: ```java // 读取 env 参数 String env = System.getProperty("env"); new DBConfig("db-" + env + ".properties"); ``` 线上环境:npm run build(项目构建打包) , **可以使用 serve 工具启动。** **serve 安装:npm install -g serve ,之后去打包好的 dist 目录下面执行 serve 就可以运行了!** **静态化概念:就是给每一个路由都生成一个 html 页面更加方便!** **后端,一般配置 prod 生产环境启动:** - **起名 application-prod.yml 文件,一般配置生产环境的一些中间件数据库等等。** ```shell D:\environments\git\project2\用户中心系统\user-center-system\user-center\target>java -jar user-center-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.7.0) 2022-08-20 16:21:35.066 INFO 11296 --- [ main] c.i.usercenter.UserCenterApplication : Starting UserCenterApplication v0.0.1-SNAPSHOT using Java 1. 8.0_211 on ITHolmes with PID 11296 (D:\environments\git\project2\用户中心系统\user-center-system\user-center\target\user-center-0.0.1-SNAPSHOT.jar started by IT_ holmes in D:\environments\git\project2\用户中心系统\user-center-system\user-center\target) 2022-08-20 16:21:35.068 INFO 11296 --- [ main] c.i.usercenter.UserCenterApplication : The following 1 profile is active: "prod" 2022-08-20 16:21:36.266 INFO 11296 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-08-20 16:21:36.276 INFO 11296 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] ```