找实习、找实习、找实习 求内推 有没有大佬们愿意给我一次机会。求求啦!
前语
本文章循序渐进 从而完成一个企业级别 的用户办理体系
写在前面 咱们知道 登录功用 作为 咱们开发的项目必备的一个功用,也是最基本的初始化功用!
但是 怎么完成、功用全不全 这个里边学问就很大了
比方 倘若咱们仅仅是一张表的crud 这固然简略
但 实在的登录或许注册功用 考虑的肯定会更多 比方 怎么防止被恶意调用接口、仅有ID确保事务性、有没有集成三方登录、用户名的灵敏词汇的检索 等等
那么就跟随作者一起去看看吧~
前置技能栈: 首要 您需求 会 创立 springBoot 项目 以及具有 mysql (操作数据库)的根底!
作者水平有限、请多多包容~
初学者
以 注册、和登录 举比方就好了
- 首要 咱们先结构一个SpringBoot项目
- 接下来 咱们先引进 slf4j (测验文档)的依靠 便利测验
<!-- https://doc.xiaominfo.com/knife4j/documentation/get_start.html-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
- yaml 中装备一下 swagger
# 支撑 swagger3
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
- 咱们就能够再项目中 去编写 完成功用啦
先搞一个用户表
create table user
(
username varchar(256) null comment '用户昵称',
id bigint auto_increment comment 'id'
primary key,
userAccount varchar(256) null comment '账号',
avatarUrl varchar(1024) null comment '用户头像',
gender tinyint null comment '性别',
userPassword varchar(512) not null comment '暗码',
phone varchar(128) null comment '电话',
email varchar(512) null comment '邮箱',
userStatus int default 0 not null comment '状况 0 - 正常',
createTime datetime default CURRENT_TIMESTAMP null comment '创立时间',
updateTime datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP,
isDelete tinyint default 0 not null comment '是否删去',
userRole int default 0 not null comment '用户人物 0 - 普通用户 1 - 办理员',
planetCode varchar(512) null comment '编号'
)
comment '用户';
- 编写实体类 (这儿咱们能够运用MybatisX 插件 来进行一键生成)
package com.lizhi.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* 用户
* @TableName user
*/
@TableName(value ="user") //告知MP 这是用户表
// 下面三个是Lombok的注解 作用是不需求 写 get set 了
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 用户昵称
*/
private String username;
/**
* 账号
*/
private String userAccount;
/**
* 用户头像
*/
private String avatarUrl;
/**
* 性别
*/
private Integer gender;
/**
* 暗码
*/
private String userPassword;
/**
* 电话
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 状况 0 - 正常
*/
private Integer userStatus;
/**
* 创立时间
*/
private Date createTime;
/**
*
*/
private Date updateTime;
/**
* 是否删去
*/
@TableLogic
private Integer isDelete;
/**
* 用户人物 0 - 普通用户 1 - 办理员
*/
private Integer userRole;
/**
* 编号
*/
private String planetCode;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
- 所以看到 上面 其实咱们还需求 引进 mysql 连接池 依靠 spring mybatis 依靠 mybatis-plus 依靠 以及 lombok 依靠
<!-- 这个依靠是快速构建 启动项目 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- 数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
mapper 层 我就不搞了 (MP帮你封装好了)
- controller 操控层
package com.lizhi.controller;
import com.lizhi.entity.User;
import com.lizhi.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* @author <a href="https://github.com/lizhe-0423">荔枝</a>
*/
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@PostMapping("/register")
public String userRegister(@RequestBody User userRegisterRequest) {
String userAccount = userRegisterRequest.getUserAccount();
String userPassword = userRegisterRequest.getUserPassword();
String planetCode = userRegisterRequest.getPlanetCode();
long result = userService.userRegister(userAccount, userPassword, planetCode);
return "注册成功";
}
@PostMapping("/login")
public String userLogin(@RequestBody User userLoginRequest, HttpServletRequest request) {
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
User user = userService.userLogin(userAccount, userPassword, request);
return "登录成功";
}
}
能够看到 操控层 更多的是进行一个交互 咱们把具体的逻辑封装在 service层 (处理事务)
- service层
接口
package com.lizhi.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lizhi.entity.User;
import javax.servlet.http.HttpServletRequest;
/**
* 用户服务
*
* @author 荔枝
*/
public interface UserService extends IService<User> {
/**
* 用户注册
*
* @param userAccount 用户账户
* @param userPassword 用户暗码
* @param planetCode 编号
* @return 新用户 id
*/
long userRegister(String userAccount, String userPassword, String planetCode);
/**
* 用户登录
*
* @param userAccount 用户账户
* @param userPassword 用户暗码
* @param request
* @return 用户信息
*/
User userLogin(String userAccount, String userPassword, HttpServletRequest request);
}
- 完成
package com.lizhi.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lizhi.entity.User;
import com.lizhi.mapper.UserMapper;
import com.lizhi.service.UserService;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 用户服务完成类
*
* @author 荔枝
*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService {
@Resource
private UserMapper userMapper;
@Override
public long userRegister(String userAccount, String userPassword, String planetCode) {
// 3. 刺进数据
User user = new User();
user.setUserAccount(userAccount);
user.setUserPassword(userPassword);
user.setPlanetCode(planetCode);
boolean saveResult = this.save(user);
if (!saveResult) {
return -1;
}
return user.getId();
}
@Override
public User userLogin(String userAccount, String userPassword, HttpServletRequest request) {
val user = new User();
user.setUserAccount(userAccount);
user.setUserPassword(userPassword);
// 4. 记载用户的登录态
request.getSession().setAttribute("user", user);
return user;
}
}
访问下面这个地址
http://127.0.0.1:2318/api/doc.html
测验:
收成
上面 仅仅一个简略的 demo 但demo 便是 demo 在实在开发中 先不说安全问题的危险 就说这些代码格式 想必各位应该就受不了吧!
记得 我 还在上大二的时分 那个时分 身边有一个常常带着我做项目的”好哥哥” 其时便是他教给我代码的书写标准
其实 这个东西 你说他重要吧 如同很重要 不重要 也不重要 由于这个东西 更多的便是”潜规“则一样 以后早晚会懂得!!!
那么 让咱们来说说上面有什么问题吧
首要从代码自身的视点来看:
拿注册来看 @requestBody 咱们知道 获取的json 数据 主动 转换成对应的实体类 也便是说这个当地是用来接收前端用户传来的 数据的 那么这个当地就有问题了 咱们最好不要直接用一个User实体类来承受数据
由于 一个完好实体类 少了 还好 太多了话 前端 就不知道他要给你传什么了
- 所以在Java中 咱们专门有一种说法叫 DTO 也便是恳求 表明前端 向 后端 传递的数据 理解成request
/**
* 用户注册恳求体
*
* @author 荔枝
*/
@Data
public class UserRegisterRequest implements Serializable {
private static final long serialVersionUID = 3191241716373120793L;
private String userAccount;
private String userPassword;
private String checkPassword;
private String planetCode;
}
- 咱们仅仅把用到的数据 封装成一个实体类 已然有了前端向后端 传递的数据了 那么是不是有后端向前端传递的数据呢? 没错 咱们管这种叫 VO
比方 前端 展示的用户信息 (在User 实体类中包括了ID、创立时间、更新时间等等 这些是不给前端用户看的 所以关于其他的数据 咱们再封装成VO进行回来)
- 不要呈现魔法值
比方 我session 那里 存储的数据 要用常量
package com.yupi.usercenter.contant;
/**
* 用户常量
*
* @author 荔枝
*/
public interface UserConstant {
/**
* 用户登录态键
*/
String USER_LOGIN_STATE = "userLoginState";
// ------- 权限 --------
/**
* 默认权限
*/
int DEFAULT_ROLE = 0;
/**
* 办理员权限
*/
int ADMIN_ROLE = 1;
}
- 不要回来前端 字符串 自界说通用回来类进行回来
安全性/功用性:
- 首要 传递过来的数据 咱们应该先进行校验(前端也需求进行校验)
- 一个完好的用户流程或许还包括 删去用户、刊出登录 等常见功用
进阶者
当你能考虑上述 的东西的话 那么在我的印象中 你的实力应该有大二的实在水平啦
然后就让咱们来完成它吧!
接下来我只 举例 一些重要的功用 完好的代码我会附上GitHub地址
用户操控层
package com.lizhi.usercenter.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lizhi.usercenter.common.BaseResponse;
import com.lizhi.usercenter.common.ErrorCode;
import com.lizhi.usercenter.common.ResultUtils;
import com.lizhi.usercenter.exception.BusinessException;
import com.lizhi.usercenter.model.domain.User;
import com.lizhi.usercenter.model.domain.request.UserLoginRequest;
import com.lizhi.usercenter.model.domain.request.UserRegisterRequest;
import com.lizhi.usercenter.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;
import static com.lizhi.usercenter.contant.UserConstant.ADMIN_ROLE;
import static com.lizhi.usercenter.contant.UserConstant.USER_LOGIN_STATE;
/**
* 用户接口
*
* @author 荔枝
*/
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Resource
private UserService userService;
@PostMapping("/register")
public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
if (userRegisterRequest == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
String userAccount = userRegisterRequest.getUserAccount();
String userPassword = userRegisterRequest.getUserPassword();
String checkPassword = userRegisterRequest.getCheckPassword();
String planetCode = userRegisterRequest.getPlanetCode();
if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword, planetCode)) {
return null;
}
long result = userService.userRegister(userAccount, userPassword, checkPassword, planetCode);
return ResultUtils.success(result);
}
@PostMapping("/login")
public BaseResponse<User> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
if (userLoginRequest == null) {
return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
if (StringUtils.isAnyBlank(userAccount, userPassword)) {
return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
User user = userService.userLogin(userAccount, userPassword, request);
return ResultUtils.success(user);
}
@PostMapping("/logout")
public BaseResponse<Integer> userLogout(HttpServletRequest request) {
if (request == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
int result = userService.userLogout(request);
return ResultUtils.success(result);
}
@GetMapping("/current")
public BaseResponse<User> getCurrentUser(HttpServletRequest request) {
Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
User currentUser = (User) userObj;
if (currentUser == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN);
}
long userId = currentUser.getId();
// TODO 校验用户是否合法
User user = userService.getById(userId);
User safetyUser = userService.getSafetyUser(user);
return ResultUtils.success(safetyUser);
}
@GetMapping("/search")
public BaseResponse<List<User>> searchUsers(String username, HttpServletRequest request) {
if (!isAdmin(request)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(username)) {
queryWrapper.like("username", username);
}
List<User> userList = userService.list(queryWrapper);
List<User> list = userList.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());
return ResultUtils.success(list);
}
@PostMapping("/delete")
public BaseResponse<Boolean> deleteUser(@RequestBody long id, HttpServletRequest request) {
if (!isAdmin(request)) {
throw new BusinessException(ErrorCode.NO_AUTH);
}
if (id <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
boolean b = userService.removeById(id);
return ResultUtils.success(b);
}
/**
* 是否为办理员
*
* @param request
* @return
*/
private boolean isAdmin(HttpServletRequest request) {
// 仅办理员可查询
Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
User user = (User) userObj;
return user != null && user.getUserRole() == ADMIN_ROLE;
}
}
不知道童鞋们看到 这儿有没有蒙 不过不要慌 就像 我说的 那些多出来的代码只不过是一些规则校验
当然了 假如是正式 或许 担任的规则校验 咱们应该抽取成一个 代码片段
比方在 service层中接口 verfy接口 (校验接口)
自界说的回来类
package com.lizhi.usercenter.common;
import lombok.Data;
import java.io.Serializable;
/**
* 通用回来类
*
* @param <T>
* @author 荔枝
*/
@Data
public class BaseResponse<T> implements Serializable {
private int code;
private T data;
private String message;
private String description;
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, String message) {
this(code, data, message, "");
}
public BaseResponse(int code, T data) {
this(code, data, "", "");
}
public BaseResponse(ErrorCode errorCode) {
this(errorCode.getCode(), null, errorCode.getMessage(), errorCode.getDescription());
}
}
自界说回来信息
package com.lizhi.usercenter.common;
/**
* 回来东西类
*
* @author 荔枝
*/
public class ResultUtils {
/**
* 成功
*
* @param data
* @param <T>
* @return
*/
public static <T> BaseResponse<T> 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 message
* @param description
* @return
*/
public static BaseResponse error(int code, String message, String description) {
return new BaseResponse(code, null, message, description);
}
/**
* 失利
*
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode, String message, String description) {
return new BaseResponse(errorCode.getCode(), null, message, description);
}
/**
* 失利
*
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode, String description) {
return new BaseResponse(errorCode.getCode(), errorCode.getMessage(), description);
}
}
此时 咱们再来看到 操控层
类型 便是咱们自己界说的通用回来类型
咱们回来数据的时分 便是自己界说的回来东西类
自界说过错代码
package com.lizhi.usercenter.common;
/**
* 过错码
*
* @author 荔枝
*/
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;
}
}
这儿的用法便是 再 进行 权限校验的 时分 假如报错 自界说回来的过错
下面 注册 为例
- 参数校验 假如不符合 主动抛出咱们自界说的过错
- 账号校验有没有特别字符
- 账号有无与数据库重复
- 进行暗码的加密
- 回来用户id 假如注册失利 回来-1
/**
* 盐值,混淆暗码
*/
private static final String SALT = "lizhi";
@Override
public long userRegister(String userAccount, String userPassword, String checkPassword, String planetCode) {
// 1. 校验
if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword, planetCode)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
}
if (userAccount.length() < 4) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
}
if (userPassword.length() < 8 || checkPassword.length() < 8) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户暗码过短");
}
if (planetCode.length() > 5) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "星球编号过长");
}
// 账户不能包括特别字符
String validPattern = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
Matcher matcher = Pattern.compile(validPattern).matcher(userAccount);
if (matcher.find()) {
return -1;
}
// 暗码和校验暗码相同
if (!userPassword.equals(checkPassword)) {
return -1;
}
// 账户不能重复
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("userAccount", userAccount);
long count = userMapper.selectCount(queryWrapper);
if (count > 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
}
// 星球编号不能重复
queryWrapper = new QueryWrapper<>();
queryWrapper.eq("planetCode", planetCode);
count = userMapper.selectCount(queryWrapper);
if (count > 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "编号重复");
}
// 2. 加密
String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
// 3. 刺进数据
User user = new User();
user.setUserAccount(userAccount);
user.setUserPassword(encryptPassword);
user.setPlanetCode(planetCode);
boolean saveResult = this.save(user);
if (!saveResult) {
return -1;
}
return user.getId();
}
收成
当你看到此时下来 我想你应该对 一个项目 尤其是登录项目 应该做什么 有了一个明晰的认知
首要
-
你知道了 VO 和 DTO
-
实在的项目 自界说 通用回来 与 过错代码
咱们此时 再来考虑一些东西 以及 上述的代码 是不是 能够再进行简化
问题如下
- 灵敏词汇的检索 比方用户 账号 有无灵敏词汇(谩骂、种族歧视 等等)
- 同一时间 两个用户一起登陆 是否会一起登录 假如此时进行 签到、打卡 (会不会产生双倍积分?)
- 怎么防止被爬虫 然后进行接口的调用
- 有没有完成找回暗码、记住暗码的功用?
以及 更丰厚的功用 或许更 高档的技能
……
感悟者
针对上述 罗列的问题
1 .灵敏词汇的检索 比方用户 账号 有无灵敏词汇(谩骂、种族歧视 等等)
解决方法:
数据库建立这么一张词汇表 然后注册账号的时分 用户名 去匹配 假如匹配到 就 回来用户名非法信息,不然注册成功
- 同一时间 的确 有或许 会登录成功
解决方法: 锁操作(这仅仅单机锁 单机锁的意思 假如处于分布式环境就会失效)
synchronized (unionId.intern()) {
// 查询用户是否已存在
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("unionId", unionId);
User user = this.getOne(queryWrapper);
// 被封号,禁止登录
if (user != null && UserRoleEnum.BAN.getValue().equals(user.getUserRole())) {
throw new BusinessException(ErrorCode.FORBIDDEN_ERROR, "该用户已被封,禁止登录");
}
// 用户不存在则创立
if (user == null) {
user = new User();
user.setUnionId(unionId);
user.setMpOpenId(mpOpenId);
user.setUserAvatar(wxOAuth2UserInfo.getHeadImgUrl());
user.setUserName(wxOAuth2UserInfo.getNickname());
boolean result = this.save(user);
if (!result) {
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "登录失利");
}
}
// 记载用户的登录态
request.getSession().setAttribute(USER_LOGIN_STATE, user);
return getLoginUserVO(user);
- 运用 验证码 每次 登录 或许 注册 的时分 让用户 进行 验证码 验证
解决方法: 运用hutool 引进 hutool东西库的验证码功用:
package com.lizhi.stpspringbootinit.util;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import lombok.val;
/**
* @author <a href="https://github.com/lizhe-0423">荔枝</a>
* 图片验证码
*/
public class Captcha {
/**
* 生成 扭曲干扰验证码
* @param str 传入 暗码进行验证
* @return true 验证码正确 false 验证码过错
*/
public boolean shearCaptcha(String str){
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 100, 4, 4);
//图形验证码写出,能够写出到文件,也能够写出到流
// captcha.write("d:/shear.png");
boolean verify = captcha.verify(str);
return verify;
}
}
- 找回暗码 通过密保找回 (数据表操作) 而 记住暗码 其实 便是 登录 用户 的时分 将用户信息 存入 session 上面演示的功用中 主动完成了此功用
- jwt 和 session+redis 具体百度吧 简略来说是两种不同的登录手法 jwt 愈加简略 但 扩展性差 session+redis的方法 扩展性强
前面 咱们知道 用户将信息 存入session 完成 记住用户的功用
但这样有坏处 咱们知道session表明一次会话 所以关闭浏览器 或许 重启使用 session就会消失
而所谓的session+redis 不过便是 将session信息存储到redis中罢了 这样就能够进行长久的保存了!
而jwt 其实 便是将用户信息 携带在jwt(字符串)中(前后端传递jwt)
6.引进 Sa-Token
能够看我的另一篇笔记 玩转Sa-Token 2023年,不会还有人用SpringSecurity登录鉴权吧 – ()
收成
假如你看到这儿 假如你读到这儿 那这便是真爱 你难以抗拒~~~
好了 此时 你现已会自己考虑了 你的实力现已不仅仅限制在代码自身 我承认 你的实力有大三的水平了(大三强者、恐怖如斯 )
漫笔
过度考虑
所谓过度考虑 在码农身上便是指过度优化 关于你我新手来说 便是 只懂了解的技能选型 假如叫你完成什么功用 你有必要依靠它的前置 代码 而不能自身 具有编写代码的能力
我把 新手 分为两个阶段
第一个阶段 萌新
学习便是看视频 你是一个真实在正的代码 小白 你获取信息 学习的方法 便是看视频 假如遇到没有视频的新技能 就会捉襟见肘 一起 在编程中 假如遇到的过错 的当地 ,也是 百度 假如百度不到 也和前面一样!
你敲代码 仅仅本能的仿照
第二个阶段 初窥门径
你尝试 开端阅读源码
你学习的方法 开端变得厌烦看视频 由于你觉得这样获取信息的速度太慢了
你能够尝试着写点功用 而且有自己直接 比方这篇文章 用户办理功用
第三个阶段 高档新手
你现已 会看源码 而且 看得懂 大部分源码
你获取信息的途径 也不是 纸质书籍教程 而是阅读官方文档
你觉得自己什么都会 又如同仅仅什么都会一点
你 年轻气盛 你 迈入了编程的第一步
所以 道阻且长 咱们都应该尽力✊
关于成为怎样的人?
其实 作者 我 没考上高中 读的也是职高 我费力尽力 上的也不过是个三本
我厌烦这个大学 我认为这是一个没有学术气氛 而且官僚横行的校园 我与朋友参与竞赛看其他校园导师带着一起答辩 我也很羡慕
我高中 常常想 上了 大学就好了
我上了 大学 还真的是这样 大一我课余时间打篮球 报吉他社
我常常看到 网上有人说 假如大一就开端学习编程就好了 假如大一就看到这篇文章就好了
我也在想 假如我大一学习 就好了
但细心一想 我真的懊悔码?
不管怎样 这便是芳华 不是吗? 大学就应该干点大学的事不是吗? 恋爱、散步、live house 、聚餐、运动 ……
****等等等等 记得一句话 咱们不应该站在现在的高度去批评其时的自己 假如站在其时的视点 或许又是一次重蹈覆辙 但这一切真的仅仅重蹈覆辙吗?
结束
找实习找实习找实习、求内推~~~~
项目地址:
github.com/lizhe-0423/…
hutool(三方东西库):
www.hutool.cn/
MybatisPlus(数据库):
baomidou.com/
Sa-Token(登录框架)
sa-token.cc/