B071-项目实战-用户模块--手机注册 管理员登录

目录

      • 完成注册功能
        • 后端开发完成
          • UserController
          • UserServiceImpl
          • LogininfoMapper
        • 前端页面完成
          • 绑定数据
          • 绑定事件
          • 准备登录页
      • 管理员登录1
        • 需求分析
        • 登录设计
          • 页面设计
          • 表设计
          • 流程设计
          • 所需技术
      • 员工新增级联操作登录信息
        • EmployeeServiceImpl
        • ShopServiceImpl
      • 管理员登录2
        • 前端页面
        • 后端接口
          • LoginController
          • LoginServiceImpl
          • logininfoMapper
        • 前端登录完成
        • 后端拦截
          • PetHomeWebMvcConfigurer
          • LoginInterceptor
        • 前端拦截
        • 路由拦截
        • 其他

分别启动后端,后台,前台和redis
ph-admin:npm run dev,ph-web:live-server --port=80
redis:redis-server.exe redis.windows.conf

完成注册功能

在这里插入图片描述

后端开发完成

UserController
    /***  用户注册接口* @param userDto 自定义Dto接收前端参数* @return*/@PostMapping("/register/code")public AjaxResult redisterCode(@RequestBody UserDto userDto){try {userService.redisterCode(userDto);return AjaxResult.me();} catch (BusinessException e) {return AjaxResult.me().setMessage(e.getMessage());}catch (Exception e) {e.printStackTrace();return AjaxResult.me().setMessage("系统繁忙,稍后重试!!");}}
UserServiceImpl
	@Overridepublic void redisterCode(UserDto userDto) {//1.校验//  1.1空校验if(StringUtils.isEmpty(userDto.getPhone()) ||StringUtils.isEmpty(userDto.getVerifycode()) ||StringUtils.isEmpty(userDto.getPassword()) ||StringUtils.isEmpty(userDto.getConfirmPwd()) ){throw new BusinessException("请输入完整信息在进行注册!");}//  1.2两次密码是否一致if(!userDto.getPassword().equals(userDto.getConfirmPwd())){throw new BusinessException("密码不一致,请重新输入!");}//  1.3是否被注册Logininfo obj = logininfoMapper.loadByDto(userDto);if(obj != null){throw new BusinessException("用户已经存在!");}//2.验证码是否存在Object codeObj = redisTemplate.opsForValue().get(UserConstant.USER_VERFIY_CODE+":"+userDto.getPhone());//  2.1 验证码是否过期if(codeObj == null){throw new BusinessException("验证码已经过期,请重新发送验证码!");}String code = ((String)codeObj).split(":")[0];//  2.2 验证码是否正确if(!userDto.getVerifycode().equalsIgnoreCase(code)){throw new BusinessException("请输入正确的验证码!");}//3.登录成功// 3.1登录信息表User user = userDto2User(userDto);Logininfo logininfo = user2LoginInfo(user);logininfoMapper.save(logininfo);//返回自增id// 3.2用户表user.setInfo(logininfo);//引用属性传值userMapper.save(user);}/*** 将dto转换成实体对象* @param userDto* @return*/private User userDto2User(UserDto userDto) {//1.定义需要返回的对象User user = new User();//2.封装数据user.setUsername(userDto.getPhone());user.setPhone(userDto.getPhone());/*private String salt;private String password;*/String salt = StrUtils.getComplexRandomString(32);String md5Pwd = MD5Utils.encrypByMd5(userDto.getPassword() + salt);user.setSalt(salt);//存储加密使用的盐值user.setPassword(md5Pwd);//存储使用盐值加密之后的密码//3.返回return user;}/*** 通过user拷贝LoginInfo* @param user* @return*/private Logininfo user2LoginInfo(User user) {Logininfo info = new Logininfo();//直接使用工具类拷贝  同名原则拷贝属性值BeanUtils.copyProperties(user, info);info.setType(1);//设置前端用户默认值return info;}
LogininfoMapper
    <!--Logininfo loadByDto(UserDto userDto);--><select id="loadByDto" parameterType="cn.itsource.user.dto.UserDto" resultType="Logininfo">SELECT * FROM t_logininfo WHERE phone =  #{phone} and type = #{type}</select>

前端页面完成

绑定数据
		data:{phoneUserForm:{phone:"",verifycode:"",password:"1",confirmPwd:"1",type:1}},
<form method="post"><div class="user-phone"><label for="phone"><i class="am-icon-mobile-phone am-icon-md"></i></label><input type="tel" v-model="phoneUserForm.phone" name="" id="phone" placeholder="请输入手机号"></div><div class="verification"><label for="code"><i class="am-icon-code-fork"></i></label><input type="tel" name="" v-model="phoneUserForm.verifycode" id="code" placeholder="请输入验证码"><!--<a class="btn" href="javascript:void(0);" οnclick="sendMobileCode();" id="sendMobileCode"><span id="dyMobileButton">获取</span></a>--><button type="button" @click="sendMobileCode">获取</button></div><div class="user-pass"><label for="password"><i class="am-icon-lock"></i></label><input type="password" name="" v-model="phoneUserForm.password" id="password" placeholder="设置密码"></div><div class="user-pass"><label for="passwordRepeat"><i class="am-icon-lock"></i></label><input type="password" name="" v-model="phoneUserForm.confirmPwd" id="passwordRepeat" placeholder="确认密码"></div>
</form>
绑定事件
<div class="am-cf"><input type="submit" name="" @click="register" value="注册" class="am-btn am-btn-primary am-btn-sm am-fl">
</div>
            register(){this.$http.post("/user/register/code",this.phoneUserForm).then(result=>{result = result.data;if(result.success){//成功之后? 提示成功alert("注册成功!");//跳转到登录页location.href="login.html";}else{alert("注册失败:"+result.message);}}).catch(result=>{alert("系统异常!");})},
准备登录页

拷贝login.html到根目录并修改路径

管理员登录1

需求分析,页面,表设计,流程设计,

需求分析

见文档

登录设计

页面设计

见文档

表设计

见文档

流程设计

见文档

所需技术

见文档

员工新增级联操作登录信息

店铺入驻保存shop表和employee表的时候要同步存入logininfo表
员工新增保存employee表的时候也要保存logininfo表

做法:分别在EmployeeServiceImpl和UserServiceImpl重写add,update,del方法,方法内加入同步操作logininfo表的代码

EmployeeServiceImpl

	/*** 针对于loginInfo的级联操作:员工和用户都应该有* 这里我们只写 员工的*/@Override@Transactionalpublic void add(Employee employee) {initEmployee(employee);Logininfo logininfo = employee2LoginInfo(employee);logininfoMapper.save(logininfo);employee.setLogininfo(logininfo);employeeMapper.save(employee);}@Overridepublic void update(Employee employee) {//1.修改loginInfoLogininfo logininfo = logininfoMapper.loadById(employee.getLogininfo_id());if(logininfo != null){BeanUtils.copyProperties(employee, logininfo);logininfoMapper.update(logininfo);employeeMapper.update(employee);}}@Overridepublic void delete(Long id) {Employee employee = employeeMapper.loadById(id);if(employee != null){logininfoMapper.remove(employee.getLogininfo_id());employeeMapper.remove(id);}}private void initEmployee(Employee employee) {//设置盐值String salt = StrUtils.getComplexRandomString(32);String md5Pwd = MD5Utils.encrypByMd5(employee.getPassword()+salt);employee.setSalt(salt);employee.setPassword(md5Pwd);}private Logininfo employee2LoginInfo(Employee employee) {Logininfo logininfo = new Logininfo();BeanUtils.copyProperties(employee, logininfo);logininfo.setType(0);return logininfo;}

ShopServiceImpl

        //2.先保存员工数据 保存之后返回自增id
//        employeeMapper.save(admin);employeeService.add(admin);

管理员登录2

前端页面

ph-admin - login.vue
标签元素 - data - 按钮 - methods

<template><el-form :model="ruleForm2" :rules="rules2" ref="ruleForm2" label-position="left" label-width="0px" class="demo-ruleForm login-container"><h3 class="title">系统登录</h3><el-form-item prop="account"><el-input type="text" v-model="ruleForm2.username" auto-complete="off" placeholder="账号"></el-input></el-form-item><el-form-item prop="checkPass"><el-input type="password" v-model="ruleForm2.password" auto-complete="off" placeholder="密码"></el-input></el-form-item><el-checkbox v-model="checked" checked class="remember">记住密码</el-checkbox><el-form-item style="width:100%;"><el-button type="primary" style="width:47%;" @click.native.prevent="login" :loading="logining">登录</el-button><el-button type="success" style="width:47%;" @click.native.prevent="goRegister">店铺入驻</el-button></el-form-item></el-form>
</template><script>import { requestLogin } from '../api/api';//import NProgress from 'nprogress'export default {data() {return {logining: false,ruleForm2: {username: '3',password: '3',type:0//表名是后端员工登录},rules2: {account: [{ required: true, message: '请输入账号', trigger: 'blur' },//{ validator: validaePass }],checkPass: [{ required: true, message: '请输入密码', trigger: 'blur' },//{ validator: validaePass2 }]},checked: true};},methods: {goRegister(){//这里是拷贝的登录成功只有跳转主页this.$router.push({ path: '/shopRegister' });/*店铺入驻*/},handleReset2() {this.$refs.ruleForm2.resetFields();},login(ev) {this.$refs.ruleForm2.validate((valid) => {  //点击登录按钮的时候,触发表单校验if (valid) {this.logining = true; //开启忙等框this.$http.post("/login/account",this.ruleForm2).then(result=>{this.logining = false;//关闭忙等框result = result.data;if(result.success){//提示登录成功this.$message({message: "登录成功!",type: 'success'});//跳转到主页this.$router.push({ path: '/echarts' });}else{this.$message({message: result.message,type: 'error'});}}).catch(result=>{this.logining = false;//关闭忙等框this.$message({message: "系统异常",type: 'error'});})} else {console.log('error submit!!');return false;}});}}}
</script>

后端接口

LoginController
/*** 统一登录接口*/
@RestController
@RequestMapping("/login")
public class LoginController {@AutowiredILoginService loginService;/*** 账号登录,支持前后端账号登录*/@PostMapping("/account")public AjaxResult account(@RequestBody LoginDto loginDto){try {return loginService.account(loginDto);} catch (Exception e) {e.printStackTrace();return AjaxResult.me().setMessage("系统繁忙,稍后重试!");}}
}
LoginServiceImpl

在这里插入图片描述

/*** 统一登录业务层*/
@Service
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class LoginServiceImpl implements ILoginService {@Autowiredprivate LogininfoMapper logininfoMapper;@Autowiredprivate RedisTemplate redisTemplate;/*** 账号登录* loginDto 中表明了是哪一个端登录 type = 0*/@Overridepublic AjaxResult account(LoginDto loginDto) {//1.校验// 1.1 空校验  loginDto所有字段都要校验if(StringUtils.isEmpty(loginDto.getUsername()) ||StringUtils.isEmpty(loginDto.getPassword()) ||StringUtils.isEmpty(loginDto.getType()) ){return AjaxResult.me().setMessage("用户或密码不能为空!");}// 1.2 判断用户是否存在  查询loginInfo表Logininfo logininfo = logininfoMapper.loadByLoginDto(loginDto);if (logininfo == null) {return AjaxResult.me().setMessage("用户不存在!");}// 1.3 账号是否被禁用if(logininfo.getDisable() != 1){return AjaxResult.me().setMessage("账号被禁用,请联系管理员!");}// 2.判断密码是否正确String salt = logininfo.getSalt();String md5pwd = logininfo.getPassword();String md5PwdTmp = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);if(!md5pwd.equals(md5PwdTmp)){// 2.2 密码不等  抛错return AjaxResult.me().setMessage("用户名或密码错误!");}// 2.1 如果密码相等  登录成功  存redis,封装返回值/*** 这里的redis  key就是前端需要存储的token*/String token = UUID.randomUUID().toString();redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);Map<String,Object> map = new HashMap<>();map.put("token", token);map.put("logininfo",logininfo);return AjaxResult.me().setResultObj(map);}
}
logininfoMapper
    <select id="loadByLoginDto" parameterType="cn.ming.basic.dto.LoginDto" resultType="Logininfo">SELECT * FROM t_logininfoWHERE (username =  #{username} or phone = #{username} or email = #{username})and type = #{type}</select>

前端登录完成

保存信息到localstorage

	login(ev) {this.$refs.ruleForm2.validate((valid) => {  //点击登录按钮的时候,触发表单校验if (valid) {this.logining = true; //开启忙等框this.$http.post("/login/account",this.ruleForm2).then(result=>{this.logining = false;//关闭忙等框result = result.data;if(result.success){//保存信息到localstoragevar resultObj =  result.resultObj;localStorage.setItem("token",resultObj.token);localStorage.setItem("logininfo",JSON.stringify(resultObj.logininfo));//提示登录成功this.$message({message: "登录成功!",type: 'success'});//跳转到主页this.$router.push({ path: '/echarts' });}else{this.$message({message: result.message,type: 'error'});}}).catch(result=>{this.logining = false;//关闭忙等框this.$message({message: "系统异常",type: 'error'});})} else {console.log('error submit!!');return false;}});}

前端右上角展示登录人信息

		mounted() {var user = localStorage.getItem('logininfo');if (user) {user = JSON.parse(user);this.sysUserName = user.username || user.email || user.phone || '';this.sysUserAvatar = user.avatar || '';}}

后端拦截

除了登录和注册相关的其他所有ajax请求都应该拦截
如:注册,发送验证码,店铺入驻,图片上传,

PetHomeWebMvcConfigurer
@Configuration
public class PetHomeWebMvcConfigurer implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/login/**").excludePathPatterns("/user/register/**").excludePathPatterns("/verifycode/**").excludePathPatterns("/fastDfs").excludePathPatterns("/shop/settlement");}
}
LoginInterceptor
@Component
public class LoginInterceptor implements HandlerInterceptor {@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {//判断是否登录?  前端需要给我们传递 tokenString token = request.getHeader("token");// fde6185f-36ac-4df0-9c0e-9d4c4ebb617cif(!StringUtils.isEmpty(token)){Object obj = redisTemplate.opsForValue().get(token);if(obj !=null){//已经登录过//刷新redis的token存储时间redisTemplate.opsForValue().set(token, obj, 30, TimeUnit.MINUTES);//放行return true;}}//如果已经登录过期response.setContentType("application/json;charset=UTF-8");PrintWriter writer = response.getWriter();writer.write("{\"success\":false,\"message\":\"noLogin\"}");writer.flush();writer.close();//@TODO 权限校验return false;}
}

前端拦截

axios前置拦截:发送axios请求前给请求加上token

axios后置拦截:接收到后端拦截器的nologin信息后跳到登录页

写在main.js,vue下面

/**axios前置拦截器*作用:每次发送axios请求,需要携带token给后端*/
axios.interceptors.request.use(config=>{//携带tokenlet uToken =  localStorage.getItem("token");if(uToken){config.headers['token']=uToken;}return config;//一定要返回配置
},error => {Promise.reject(error);
})/*** axios后置拦截:       作用:接收后端拦截器报错,在这里处理*/
axios.interceptors.response.use(result=>{console.log(result.data+"jjjjjjj");let data = result.data;if(!data.success && data.message==="noLogin"){localStorage.removeItem('token');localStorage.removeItem('logininfo');router.push({ path: '/login' });}return result;
},error => {Promise.reject(error);
})

路由拦截

http://localhost:8081/#/
根首页并没有触发axios请求,是直接访问直接打开的,也需要拦截
登录和注册页面要放行

router.beforeEach((to, from, next) => {if (to.path == '/login' || to.path == '/shopRegister') {localStorage.removeItem('token');localStorage.removeItem('logininfo');next()//需要放行}else{let user = JSON.parse(localStorage.getItem('logininfo'));if (!user) {//如果没有值,定位到登录页next({ path: '/login' })} else {//如果有值,正常访问页面next()}}
})

其他

管理员登录前提:login.vue中集成axios和vue
整体思路  先不要考虑登录拦截,先把登录做好
1)后台登录接口
2)前台登录实现并且保存loginInfo和token到localStorage,登录成功跳转首页,并展示用户名
3)前台通过axios的前置拦截器携带token到后台
4)后台做token的登录拦截器,如果没有回报错给前台
5)前台通过axios后置拦截器对后台登录拦截错误进行跳转到登录页面
6)前台也要做拦截-有的地址是不需要访问后台后端接口
LoginDto 	
LoginController	/login/acount	loginAccount
LoginInfoServiceImpl 	loginAcount
xml后台登录
Login.vue	/login/accountaxios携带token到后台 main.js
为了后端校验是否已经登录,只要用axios的请求都要携带token后端登录拦截
写拦截器	配置拦截器
前台对后台拦截结果跳转登录页面 main.js			后台拦截器实现后端已经退出登录的跳转登录页面
前端拦截器-页面没有和后台进行数据交互		 	  登录和注册在没有登录情况下也能访问

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/28569.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MacOS使用USB接口与IPhone进行Socket通信

演示效果如下: 开源地址: GitHub - rsms/peertalk: iOS and Mac Cocoa library for communicating over USB 克隆源码: git clone https://github.com/rsms/peertalk.git 克隆后打开peertalk然后启动xcode工程 先启动MacOS服务端工程,再启动iOS客户端工程 客户端 服务端

php代码逻辑题

<?php error_reporting(0); show_source(__FILE__); $guess $_POST[guess]; $data (array)json_decode($_GET[data]); if(substr(md5($guess),0,27)797ed5077436dc8abaec64750e2)if ($data[aaa] !666 && intval($data[aaa],0) 666 &‮⁦!!⁩⁦& "h…

AtcoderABC249场

A - JoggingA - Jogging 题目大意 高桥和青木一起慢跑&#xff0c;高桥每隔 ACAC 秒钟走 BB 米&#xff0c;然后休息 CC 秒钟&#xff0c;青木每隔 DFDF 秒钟走 EE 米&#xff0c;然后休息 FF 秒钟。现在已经过去了 XX 秒钟&#xff0c;问谁跑得更远。 思路分析 模拟来解决这…

mysql 1 -- 数据库介绍、mysql 安装及设置

Linux 安装 mysql 1、数据库&#xff08;mysql&#xff09; 数据文件 - 数据库过了系统 2、c/s mysql 服务器 mysql 客户端 ip port : 3306 3、关系型 于 非关系型数据库&#xff08;nosql&#xff09; nosql可以解决一些关系型数据库所无法实现的场景引用。 一、数据库介绍 …

VScode 右键菜单加入使用用VSCode打开文件和文件夹【Windows】

VScode 右键菜单加入使用用VSCode打开文件和文件夹【Windows】 介绍修改注册表添加右键打开文件属性修改注册表添加右键打开文件夹属性修改注册表添加右键空白区域属性 介绍 鼠标右击文件或者文件夹&#xff0c;可直接用VSCode打开&#xff0c;非常方便。但如果我们在安装VSCo…

「网络编程」传输层协议_ UDP协议学习_及原理深入理解

「前言」文章内容大致是传输层协议&#xff0c;UDP协议讲解。 「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、传输层二、UDP协议2.1 再谈端口号2.2.1 端口号范围划分2.2.2 认识知名端口号2.2.3 端口号注意问题2.2.4 netstat命令和pidof命令 2.2 UD…

设计模式之享元模式

写在前面 本文看下一种结构型设计模式&#xff0c;享元模式。 1&#xff1a;介绍 1.1&#xff1a;什么时候使用享元模式 当程序需要大量的重复对象&#xff0c;并且这些大量的重复对象只有部分属性不相同&#xff0c;其他都是相同的时候&#xff0c;就可以考虑使用享元设计…

STM32之按键驱动的使用和自定义(MultiButton)

原始Github地址 Github地址 修改后 调整内容 将宏定义转换成配置结构体 头文件 #ifndef _MULTI_BUTTON_H_ #define _MULTI_BUTTON_H_#include "stdint.h" #include "string.h"//According to your need to modify the constants. //#define TICKS_IN…

Redis实战案例19-Redis解决主从一致性问题

主节点&#xff08;Master&#xff09;“写操作”&#xff1a; 接收并响应客户端的读写请求。持久化数据到磁盘&#xff08;根据配置可以选择使用RDB快照或者AOF日志&#xff09;。将自己的写操作同步给所有的从节点。处理发布/订阅&#xff08;Pub/Sub&#xff09;模式中的发…

AUTOSAR CP标准的RTE和BSW各模块的设计及开发工作

AUTOSAR&#xff08;Automotive Open System Architecture&#xff09;是一种开放的汽车电子系统架构标准&#xff0c;旨在提供一种统一的软件架构&#xff0c;以实现汽车电子系统的模块化和可重用性。 AUTOSAR标准中的两个重要模块是RTE&#xff08;Runtime Environment&…

微服务Day2——Nacos注册中心入门

Nacos注册中心 1、Nacos简介 国内公司一般都推崇阿里巴巴的技术&#xff0c;比如注册中心&#xff0c;SpringCloudAlibaba也推出了一个名为Nacos的注册中心。 2、Mac安装 进入Nacos官网下载安装包 http://nacos.io/zh-cn/ Github仓库地址 下载解压后进入nacos/bin目录下 …

Docker——认识Docker 常用命令 Linux中安装docker 常见问题及其解决

目录 引出Docker是啥&#xff1f;Docker是啥&#xff1f;Docker VS 虚拟机1.特性优势2.资源优势 Docker的架构Docker常用命令&#xff08;0&#xff09;docker run&#xff08;1&#xff09;docker ps&#xff08;2&#xff09;docker stop 容器名称&#xff08;3&#xff09;…