瑞吉外卖01-实现管理端登录登出功能

开发前准备

准备数据表

结合页面原型创建数据库reggie,可以使用图形化界面或者MySQL命令运行SQL文件导入表结构(使用命令时sql文件不要放在中文目录中)

在这里插入图片描述

创建工程

创建一个SpringBoot的工程(勾选Spring Web,MySQL和MyBatis),配置pom.xml文件导入druid,lombok和MyBatisPlus依赖的坐标

<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version>
</dependency>
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>

配置applicaton.yml文件

server:port: 8080
spring:
application:# web应用的名称(默认就是工程名)name: reggie_take_outdatasource:druid:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: 123456redis:host: localhostport: 6379database: 0cache:redis:time-to-live: 1800000  #ms ->30min
mybatis-plus:configuration:# 在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法开启映射(默认就是true)map-underscore-to-camel-case: true# 开启日志功能log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:id-type: ASSIGN_ID
reggie:path: D:\SpringBoot_Reggie\reggie_take_out\src\main\resources\static\front\hello\

创建主程序类并使用@SpringBootApplication注解, 告诉SpringBoot这是一个SpringBoot应用并且是所有程序的启动入口

@Slf4j
@SpringBootApplication
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);log.info("项目启动成功...");}
}

在请求控制器中创建处理请求的方法

@Slf4j
@RestController
public class HelloController {@RequestMapping("/hello")public String handle01(@RequestParam("name") String name){log.info("请求进来了....");return "Hello, Spring Boot 2!"+"你好:"+name;}
}

静态资源映射

Spring Boot工程中引入的静态资源需要放到static或者templates目录下才能访问到

  • 访问resources目录下的静态资源需要编写配置类config/WebMvcConfig配置一下资源映射放行这些资源

打开浏览器访问登录页面(暂无法登录)http://localhost:8080/backend/page/login/login.html

@Configuration
@Slf4j
public class WebMvcConfig extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("开始进行静态资源映射...");// 根据用户的请求路径映射到对应的请求资源目录registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");}
}

统一结果封装

编写一个通用结果类common/Result封装所有Controller的返回结果, 服务器响应给前端的所有数据最终都会包装成此种类型中

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {private Integer code;  // 编码:1成功,0和其他数字失败private String errMsg;  // 错误信息private T data; // 数据(如响应的实体类数据)private Map map = new HashMap();  // 动态数据public static <T> Result<T> success(T data) {Result<T> r = new Result<>();r.code = 1;  //成功状态码r.data = data;return r;}public static <T> Result<T> error(String errMsg) {Result<T> r = new Result<>();r.errMsg = errMsg; //设置错误信息r.code = 0;  //默认失败状态码,后期我们可以根据自己的需求来设置其他状态码return r;}public Result<T> add(String msg, String value) {this.map.put(msg, value);return this;}
}

登录和登出功能

前端登录登出效果

在这里插入图片描述

new Vue({methods: {async handleLogin() {// 校验用户名和密码是否为空,validate是element框架提供的校验方法this.$refs.loginForm.validate(async (valid) => {if (valid) {// 渲染登录的状态,true表示登录中this.loading = true// res是服务端响应的结果(一般是一个通用结果封装类) let res = await loginApi(this.loginForm)if (String(res.code) === '1') {// 1表示登录成功localStorage.setItem('userInfo',JSON.stringify(res.data))// data表示实体类数据window.location.href= '/backend/index.html'} else {this.$message.error(res.msg)this.loading = false}}})logout() {logoutApi().then((res)=>{if(res.code === 1){localStorage.removeItem('userInfo')window.location.href = '/backend/page/login/login.html'}})},}}
}) <div class="right-menu"><!--这里动态的显示登录的用户名--><div class="avatar-wrapper">{{ userInfo.name }}</div><!--这里就是登出的按钮--><img src="images/icons/btn_close@2x.png" class="outLogin" alt="退出" @click="logout" />
</div><div class="right-menu">// userInfo就是登录成功后后端响应的用户信息<div class="avatar-wrapper">{{ userInfo.name }}</div><img src="images/icons/btn_close@2x.png" class="outLogin" alt="退出" @click="logout" />
</div>function loginApi(data) {return $axios({'url': '/employee/login','method': 'post',data})
}function logoutApi(){return $axios({'url': '/employee/logout','method': 'post',})
}

登录和登出的业务流程

第一步: 创建对应的实体类Employee

@Data
public class Employee implements Serializable {private static final long serialVersionUID = 1L;private Long id;private String username;private String name;private String password;private String phone;private String sex;private String idNumber;private Integer status;private LocalDateTime createTime;private LocalDateTime updateTime;// 这两个先不用管,后面再说@TableField(fill = FieldFill.INSERT)private Long createUser;@TableField(fill = FieldFill.INSERT_UPDATE)private Long updateUser;
}

第二步: 创建对应的Mapper和Service

// 直接将Mapper接口动态生成的代理类交给Spring容器管理(不需要再扫描mapper接口)
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
}
public interface EmployeeService extends IService<Employee> {
}//继承ServiceImpl实现EmployeeService接口,别忘了@Service注解
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
}

第三步: 在Controller中编写登录方法

在这里插入图片描述

@RestController
@RequestMapping("/employee")
public class EmployeeController {@Autowiredprivate EmployeeService employeeService;/*** 登入功能* @param request   * @param employee* @return*/// 登录页面发送post请求提交用户名和密码@PostMapping("/login")// 将页面提交的用户名和密码封装到Employee对象中public Result<Employee> login(HttpServletRequest request, @RequestBody Employee employee) {String password = employee.getPassword();// spring内部提供的工具类可以将密码进行MD5加密处理password = DigestUtils.md5DigestAsHex(password.getBytes());// 根据页面提交的用户名查询数据库LambdaQueryWrapper<Employee> lqw = new LambdaQueryWrapper<>();lqw.eq(Employee::getUsername, employee.getUsername());Employee emp = employeeService.getOne(lqw);// 没有查询到员工则返回登录失败的结果if (emp == null) {return Result.error("登陆失败");}// 与查询到的员工密码进行比对,如果不一致则返回登录失败的结果if (!emp.getPassword().equals(password)) {return Result.error("登录失败");}// 查看查询到员工的状态,如果是已禁用状态,则返回员工已禁用结果if (emp.getStatus() == 0) {return Result.error("该用户已被禁用");}// 登录成功,将员工id存入Session并返回登录结果request.getSession().setAttribute("employee",emp.getId());return Result.success(emp);}
} 

第四步: 在Controller中编写退出方法

/**
* 登出功能
* @param request
* @return
*/
@PostMapping("/logout")
public Result<String> logout(HttpServletRequest request) {// 清理Session中保存的当前登录员工的idrequest.getSession().removeAttribute("employee");// 返回结果return Result.success("退出成功");
}

登录状态校验

我们不登录直接访问 http://localhost/backend/index.html也可以正常访问首页显然是不合理的,所以需要用到过滤器或拦截器

过滤器或拦截器中判断用户是否登录,只有登录成功才能看到首页面,未登录状态则跳转到登录页面

在这里插入图片描述

第一步: 设置过滤器,/*表示处理所有请求

@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {//Spring提供的工具类,专门用于路径匹配public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 强转HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;//1.获取本次请求的URIString requestURI = request.getRequestURI();// 将拦截到的URI输出到日志,{}是占位符将自动填充request.getRequestURI()的内容log.info("拦截到请求:{}",requestURI);// 定义不需要处理的所有请求String[] urls = new String[]{"/employee/login","/employee/logout",// 访问backend和front目录下的静态页面的请求不需要拦截,但是页面中通过Ajax请求渲染的数据需要拦截"/backend/**","/front/**"};//2.判断本次请求是否需要处理boolean check = check(urls, requestURI);//3.如果不需要处理,则直接放行if (check) {log.info("本次请求:{},不需要处理",requestURI);filterChain.doFilter(request,response);return;}//4.对于需要处理的请求,需要判断登录状态,如果已登录则直接放行if (request.getSession().getAttribute("employee") != null) {log.info("用户已登录,id为{}",request.getSession().getAttribute("employee"));filterChain.doFilter(request,response);return;}//5.如果未登录则返回一个Result对象且msg为NOTLOGINlog.info("用户未登录");// ,// 导入fastjson的坐标将Result对象转化为Json格式的字符串,然后通过输出流方式响应给客户端response.getWriter().write(JSON.toJSONString(Result.error("NOTLOGIN")));}public boolean check(String[] urls, String requestURI){for (String url : urls) {boolean match = PATH_MATCHER.match(url, requestURI);if (match) {//匹配return true;}}//不匹配return false;}
}

第二步: 前端设置响应拦截器,获取后端响应的用户信息,如果用户未登录则自动重定向到登录页面

// 响应拦截器
service.interceptors.response.use(res => {if (res.data.code === 0 && res.data.msg === 'NOTLOGIN') {// 返回登录页面console.log('---/backend/page/login/login.html---')localStorage.removeItem('userInfo')// 跳转到登录页面window.top.location.href = '/backend/page/login/login.html'} else {return res.data}
}

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

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

相关文章

JumpServer2023漏洞复现合集

本文主要复现JumpServer2023年出现的大批量漏洞&#xff0c;既是分享也是为了记录自己的成长&#xff0c;近期会持续更新。 1. JumpServer MongoDB远程代码执行漏洞&#xff08;CVE-2023-43651&#xff09; 1.1 漏洞级别 高危 1.2 漏洞描述 经过身份验证的用户可以利用Mon…

StatSVN统计svn项目中每人代码提交量

一.JDK配置 StatSVN是java语言开发的&#xff0c;要运行必须先安装jdk并配置环境变量。 1.jdk下载地址https://www.oracle.com/ 2.jdk环境变量配置&#xff0c;路径为jdk安装位置 二.下载StatSVN 1.下载地址 http://sourceforge.net/projects/statsvn/ 2.解压到本地目录&a…

通信原理——信源信息熵、码元速率、误码率计算

对信源信息熵、码元速率、误码率计算 相关知识——数字通信系统的有效性和可靠性指标 (1)例题一 4进制数字信号符号速率为240kB&#xff0c;则其信息速率为____kb/s&#xff1b;若改用8进制传输&#xff0c;则其符号速率为____kB。若改变后的信号平均每秒有一个码元发生错误&a…

Cesium 展示——绘制圆的几种方式(全面)

文章目录 需求分析1. 使用圆形几何体 椭圆(CircleGeometry):2. 使用多边形几何体 Polygon(PolygonGeometry):3. 使用自定义几何体(CustomGeometry):4. 使用线实体(polyline):其他需求 总结绘制圆的几种方式 分析 1. 使用圆形几何体 椭圆(CircleGeometry): …

终于有人把VMware虚拟机三种网络模式讲清楚了!

前段时间VMware更新了&#xff0c;你用上最新版了吗&#xff1f; 有几个网工在操作中遇到过各种各样的问题。 比如说由于公司服务器重启导致出现下面的问题&#xff1a;在Xshell里连接虚拟机映射时连接失败&#xff1b;能够连接上虚拟机的映射地址&#xff0c;但git pull时报…

【LittleXi】C程序预处理、编译、汇编、链接步骤

【LittleXi】C程序预处理、编译、汇编、链接步骤 C程序 #include<stdio.h> int main(){int x1,y1;printf("xy%d",xy); }1、预处理 将头文件引入进来、除去注释、宏定义下放 执行指令 g -E esc.c -o esc.i 2、编译 将处理好的代码编译为汇编代码.s 执行…

Go ZIP压缩文件读写操作

创建zip文件 golang提供了archive/zip包来处理zip压缩文件&#xff0c;下面通过一个简单的示例来展示golang如何创建zip压缩文件&#xff1a; func createZip(filename string) {// 缓存压缩文件内容buf : new(bytes.Buffer)// 创建zipwriter : zip.NewWriter(buf)defer writ…

Android开发中遇到的问题请求帮助分析解决

本篇文章主要寻求广大的网友&#xff0c;对我遇到的问题进行分析解答&#xff0c;希望能给出更好的&#xff0c;更优化的方法。话不多说先上遇到的问题的流程图的分析&#xff1a; 以上就是流程分析图&#xff0c;希望能够尽快解决&#xff0c;希望得到大家的支持。再次本人非常…

2023最新electron 进程间通讯的几种方法

数据传递&#xff08;旧&#xff09; 渲染进程发数据到主进程 // 按钮事件 const handleWebRootPathClick () > {ipcRenderer.send(open_dir) }// main.ts中接收 ipcMain.on(open_dir, () > {console.log(recv ok) }) 主进程发数据到渲染进程 // main.ts中发送数据 …

大数据分析师职业技能提升好考吗?含金量高不高

随着大数据时代的到来&#xff0c;大数据分析技能需求已经成为很多企业和机构的必备要求。大数据分析师证书成为当下的热门之一&#xff0c;那么大数据分析师证书需要具备哪些条件呢&#xff1f; 首先&#xff0c;报考大数据分析师证书需要具备以下方面的条件&#xff1a; …

数据恢复入门分享-启动扇区

启动扇区位于存储区的前端&#xff0c;一般显示如下 如果扇区数据丢失或者错误 存储器也就不能识别和数据存储了 关注我们&#xff0c;不定期分享互联网数字化的干货 #数据恢复##储存卡##启动扇区#

arcgis--创建多分辨率DEM

方法一&#xff1a;技术链为【栅格转点】-【创建TIN】-【TIN转栅格】。首先需要将栅格转成点数据&#xff0c;再根据点数据创建TIN&#xff0c;再将TIN转栅格。 1、打开一幅DEM影像图&#xff0c;如下&#xff1a; 在【转换工具】-【由栅格转出】 -【栅格转点】工具中&#xf…