1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > springBoot+mybatis-plus+MySQL实现前后端登录注册案例(跟着做完直接成为老师眼中的好学生^_^)

springBoot+mybatis-plus+MySQL实现前后端登录注册案例(跟着做完直接成为老师眼中的好学生^_^)

时间:2020-11-14 22:22:40

相关推荐

springBoot+mybatis-plus+MySQL实现前后端登录注册案例(跟着做完直接成为老师眼中的好学生^_^)

postman测试结果(示例):

注册失败返回值:

后端可以判断账号是否被注,并返回出结果

登录错误返回值:

登录错误会返回用户名错误还是其他问题导致用户登录不上去,用于精准的提示用户注册

用户登录账号,密码正确但是跨游览器导致token缺失会返回验证码(让用户选择或者填:前端的事情),用于精准的帮助用户找回token从而登录

用户登录账号,密码正确但是跨游览器导致token缺失会返回验证码用户输入验证码后,后端可以判断验证码是否正确。正确则返回token,前端收到toke保存本地即可:

登录成功返回值:

登录成功会返回一系列的值给予前端一系列的操作。

开发工具:

idel.vsCode,postman,mysql(navicat)

用到的包:

Lombok,BCrypt.druid,jwt,jbcrypt,

基于此后端登录注册业务逻辑:

1.注册流程

前端注册时不携带token,后端springboot接收数据对用户名进行加jwt加密返回token操作,密码则进行加密操作存储到数据库(使用BCrypt.hashpw进行加密),

2.登录流程

前端登录发送用户名,密码等数据到后端,使用mp查询数据库中加密的密码和用户名,判断用户名是否一致,后端接收数据然后把前端发来的密码和数据库中的密码用BCrypt.checkpw解密后,判断密码是否一致,确认一致后然后返回token到前端,前端把token存储在本地。基于以上的业务逻辑,主要介绍注册和登录时密码和用户名的前后端校验。

3.注意

1.前端收到token需要把token存储在游览器本地(localstorage),下次请求时,携带token:才能请求成功。

2.前端用户登录和注册校验数据时,用户名不能超过12位,密码不能超过20位,网名不能超过8位最好!否则会引起后端程序崩溃!!!!!!!!!!!!!!

3.

当用户注册过后又换了游览器登录,就会导致token在新的游览器上丢失,这时只要用户输入的账号密码正确,后端会使用mp查询数据库,判断token是否正确,错误返回验证码("由于设备更改:返回验证数字"+loginRandon):前端收到数据,让用户选择哪个数字或者让用户填数字,填完后请求即可。然后端判断验证码是否正确,正确则返回数据库中的token和字符串做拼接来传递给前端。(拼接示例:"检测令牌为空:返回令牌"+tokenOne),前端收到数据,把字符串拆掉存储在本地即可(前端需要做非空验证)。不正确则会返回("数字令牌错误!"

4.前端请求不成功解决方案:

确认环境是否是vue?
是vue:代理才行能请求成功(安全)

原生js:创建控制层类下的可跨域配置类修改成另一种类型(下面会发)不做代理也可以请求成功

开始编码:

创建mysql数据库和表字符集utf-8

文件目录:

1.创建spting-boot工程,

勾选MybatisDriver,spring-boot(3以下版本),lombok

2.配置坐标(pom.xml):

​<dependency><groupId>org.mindrot</groupId><artifactId>jbcrypt</artifactId><version>0.4</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>​

3.配置数据库驱动

server:port: 81spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/shopping_mall_db?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:id-type: assign_idtable-prefix: tab_logic-delete-field: deletelogic-delete-value: 1logic-not-delete-value: 0

4.创建实体类entity(User)

package com.sms.entity;import com.baomidou.mybatisplus.annotation.TableField;import lombok.Data;import lombok.EqualsAndHashCode;@Data@EqualsAndHashCode(callSuper = false)public class User {private Long id;private String username;private String password;@TableField(value = "screen_name")private String screenName;private String token;@TableField(exist = false)private Integer loginRandom;}

5.创建Entity接口继承BaseMapper类

package com.sms.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.sms.domain.User;import org.apache.ibatis.annotations.Mapper;@Mapperpublic interface UserDao extends BaseMapper<User> {}

5.创建service层接口SysUserservice,QueryTokenService:

SysUserservice类:

public interface SysUserService extends IService<User> {/*** 用户注册* enroll* @return*/String enroll(User user);/*** 用户登录* @param* user* @return*/// String login(String userName, String password,String token);String login(User user);}

QueryTokenService类:

package com.sms.server;import com.baomidou.mybatisplus.extension.service.IService;import com.sms.domain.User;public interface QueryTokenService extends IService<User> {Boolean returnQueryToken(String token);}

6.创建service层接口实现类SysUserserviceImpl,QueryTokenServiceImpl:

SysUserserviceImpl 类:

@Service@Transactionalpublic class SysUserserviceImpl extends ServiceImpl<UserDao, User> implements SysUserService {@Autowiredprivate UserDao userDao;//写sql语句的类//注册的类,注解可以校验是不是父接口的子类Integer returnLoginRandom=null;@Overridepublic String enroll(User user) {String username = user.getUsername();String password = user.getPassword();String screenName = user.getScreenName();try {if (username == null || password == null) {return "账号密码中不能为空";}QueryWrapper<User> qw = new QueryWrapper<>();qw.eq("userName", username);User userEnrollEnroll1 = userDao.selectOne(qw);if (userEnrollEnroll1 != null) {return "已有账号";}} catch (NullPointerException e) {throw new ComFoundException();}//使用jwt加密用户名来生成随机tokenLoginToken loginToken = new LoginToken();String userUserNameJwt = loginToken.returnLogin(username);//使用BCrypt对密码进行加密String BCryptPassword = BCrypt.hashpw(password, BCrypt.gensalt());//开始存储数据User userEnrollEnrollSave = new User();userEnrollEnrollSave.setUsername(username);userEnrollEnrollSave.setScreenName(screenName);userEnrollEnrollSave.setPassword(BCryptPassword);userEnrollEnrollSave.setToken(userUserNameJwt);int insert = userDao.insert(userEnrollEnrollSave);if (insert != 1) {return "插入失败";}return userUserNameJwt;}//登录的类,注解可以校验是不是父接口的子类@Overridepublic String login(User user) {//获取前端的数据String username = user.getUsername();String password = user.getPassword();String token = user.getToken();Integer loginRandom=user.getLoginRandom();if (username == null || password == null) {return "账号不为空";}//前端无数字验证值走这些代码(默认无值)if (loginRandom==null) {//判断数据是否无误LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();lqw.eq(User::getUsername,username);lqw.select(User::getId, User::getPassword,User::getToken);List<User> userList = userDao.selectList(lqw);if (userList == null || userList.size() == 0) {return "用户名或密码错误";}//对密码进行解密String passwordBCryptCheckpw = null;for (User userPassword : userList) {passwordBCryptCheckpw = userPassword.getPassword();}//使用BCrypt.checkpw(password,passwordBCryptCheckpw)来确认数据是否正确Boolean flag = BCrypt.checkpw(password, passwordBCryptCheckpw);if (flag != true) {return "用户名或密码错误";}//用户跨游览器导致token缺失解决String tokenOne=null;for (User userToken:userList){tokenOne= userToken.getToken();}if (tokenOne==null||!tokenOne.equals(token)) {if (loginRandom==null){RandomNumber randomNumber=new RandomNumber();returnLoginRandom = randomNumber.returnLoginRandom();//如果数据库中查不到token则证明这个用户要么是黑户,要么是工作人员的失误return "由于您的设备更改:返回验证数字"+ returnLoginRandom;}}//使用jwt加密用户名来生成随机tokenLoginToken loginToken = new LoginToken();String ReturnUserNameToken = loginToken.returnLogin(password);//查询登录的是哪一个人的id;String idStr = null;for (User userId : userList) {idStr = String.valueOf(userId.getId()) + "L";}long id = Long.parseLong(idStr.replace("L", ""));//更新tokenUser userPutToken = userDao.selectById(id);userPutToken.setToken(ReturnUserNameToken);int flags = userDao.updateById(userPutToken);if (flags != 1) {return "添加失败";}return ReturnUserNameToken;}//前端传值loginRandom走这些代码(默认无值)if(loginRandom!=null) {//判断数据是否无误LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();lqw.eq(User::getUsername,username);lqw.select(User::getId, User::getPassword,User::getToken);List<User> userList = userDao.selectList(lqw);if (userList == null || userList.size() == 0) {return "用户名或密码错误";}//对密码进行解密String passwordBCryptCheckpw = null;for (User userPassword : userList) {passwordBCryptCheckpw = userPassword.getPassword();}//使用BCrypt.checkpw(password,passwordBCryptCheckpw)来确认数据是否正确Boolean flag = BCrypt.checkpw(password, passwordBCryptCheckpw);if (flag != true) {return "用户名或密码错误";}//用户跨游览器导致token缺失解决// 前端拿到token在进行登录,则能登录成功String tokenOne=null;for (User userToken:userList){tokenOne= userToken.getToken();}if (tokenOne==null||!tokenOne.equals(token)) {if (loginRandom.equals(returnLoginRandom)){returnLoginRandom=null;return "检测令牌为空:返回令牌"+tokenOne;}if (!loginRandom.equals(returnLoginRandom)){return "数字令牌错误!";}}//使用jwt加密用户名来生成随机tokenLoginToken loginToken = new LoginToken();String ReturnUserNameToken = loginToken.returnLogin(password);//查询登录的是哪一个人的id;String idStr = null;for (User userId : userList) {idStr = String.valueOf(userId.getId()) + "L";}long id = Long.parseLong(idStr.replace("L", ""));//更新tokenUser userPutToken = userDao.selectById(id);userPutToken.setToken(ReturnUserNameToken);int flags = userDao.updateById(userPutToken);if (flags != 1) {return "添加失败";}return ReturnUserNameToken;}return "错误";}

QueryTokenServiceImpl类:

@Service@Transactionalpublic class QueryTokenServiceImpl extends ServiceImpl<UserDao,User> implements QueryTokenService {@Autowiredprivate UserDao userDao;@Overridepublic Boolean returnQueryToken(String token) {QueryWrapper<User> qw=new QueryWrapper<>();qw.eq("token",token);List<User> userList=userDao.selectList(qw);try{if (userList==null||userList.size()==0){return false;}}catch (NullPointerException e){throw new ComFoundException();}return true;}}

7.创建统一错误处理类ComFoundException:

package com.sms.server.ex;public class ComFoundException extends RuntimeException{public ComFoundException() {super();}public ComFoundException(String message) {super(message);}public ComFoundException(String message, Throwable cause) {super(message, cause);}public ComFoundException(Throwable cause) {super(cause);}public ComFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}}

8.创建工具类来实现返回数据给前端的类和校验类:

RandomNumber:(生成验证码)

public class RandomNumber {public int returnLoginRandom(){Random random=new Random();int loginRandom = random.nextInt(9000) + 1000;//生成四位随机数return loginRandom;}}

LoginToken:

package com.sms.util.jwttoken;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;import java.util.HashMap;import java.util.Map;public class LoginToken {//登录会用到的工具public String returnLogin(String password){Date now=new Date();//HashMap可以存储键值对Map<String,Object> claims=new HashMap<>();claims.put("password",password);//使用jwt生成器生成TokenString token= Jwts.builder().setClaims(claims).setIssuedAt(now).signWith(SignatureAlgorithm.HS256,"secret").compact();return token;}}

Result:

@Datapublic class Result {private Integer code;private boolean success;private String message;private Object data;private Date date;public static Result loginBody(Integer code,Boolean success,String message,Object data,Date date){Result result = new Result();result.setCode(code);result.setSuccess(success);result.setData(data);result.setMessage(message);result.setDate(date);return result;}public static Result enroll(Integer code,Boolean success,String message,String data,Date date){Result result = new Result();result.setCode(code);result.setSuccess(success);result.setData(data);result.setMessage(message);result.setDate(date);return result;}}

ResultCode

package com.sms.util.ResultLoginCode;public class ResultCode{public static final Integer POST_OK=20011;public static final Integer POST_ERR=20010;public static final Integer DELETE_OK=20021;public static final Integer DELETE_ERR=20020;public static final Integer UPDATE_OK=1;public static final Integer UPDATE_ERR=0;public static final Integer GET_OK=1;public static final Integer GET_ERR=20010;}

9.创建控制层类

1.可跨域配置类(上面提到的请求不成功解决方案!二选一!)

使用:vue做代理的(安全):

@Configurationpublic class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/shop/**").allowedOrigins("http://localhost:8080").allowedMethods("GET","POST","PUT","DELETE").allowedHeaders("Content-Type").allowCredentials(true).maxAge(3600);}}

原生js的,不需要做代理的:

@Configurationpublic class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOriginPatterns("*").allowedMethods("GET","POST","PUT","DELETE").allowedHeaders("*").allowCredentials(true).maxAge(3600);}}

2.接口类:

@RestController@RequestMapping("/shop")public class Controller {@Autowiredprivate SysUserService sysUserservice;@Autowiredprivate QueryTokenService queryTokenService;@PostMapping("/login")public Result getPersonInfo(@RequestBody User user){String data = sysUserservice.login(user);String newData=null;Boolean flag= queryTokenService.returnQueryToken(data);Integer code=flag!=true?ResultCode.POST_ERR:ResultCode.POST_OK;//解决用户跨游览器导致token缺失;String message = null;message=flag!=true?data:"恭喜你,登录成功!请稍等,正在进入页面。";Boolean flagMessage=data.contains("检测令牌为空:返回令牌");Boolean flagMessageNumber=data.contains("由于您的设备更改:返回验证数字");if (flagMessageNumber==true){message=data;code=ResultCode.POST_OK;data=null;flag=true;}if (flagMessage==true){message=data;code=ResultCode.POST_OK;data=null;flag=true;}Date date=new Date();Result result = Result.loginBody(code, flag, message,data,date);return result;}//@RequestBody把前端的值转化为json类型@PostMapping("/enroll")public Result postPersonInfo(@RequestBody User user){Integer code;String message=null;//返回的是tokenString data = sysUserservice.enroll(user);code=data!=null? ResultCode.POST_OK:ResultCode.POST_ERR;message=code!=ResultCode.POST_OK?data=null:"注册成功!";if (data=="已有账号"){message="注册失败:已有账号!";code=ResultCode.POST_ERR;data=null;}Boolean success=code!=ResultCode.POST_ERR?true:false;Date date=new Date();Result result = Result.enroll(code,success,message,data,date);return result;}}

恭喜你!!!已成功学完。

最难不过坚持!!!

后续前端会出,敬请关注!^_^

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。