springboot项目学习-瑞吉外卖(2)

今天主要完善以下功能:

  • 拦截页面(页面拦截功能,在这里用的是过滤器实现的)
  • 添加员工功能

项目结构

1.页面拦截功能

filter——LoginCheckFilter类

@Slf4j
@WebFilter(filterName = "LoginCheckFilter",urlPatterns = "/*")
public class LoginCheckFilter implements Filter {//路径匹配器,支持通配符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();log.info("拦截到URI------> {}",requestURI);//定义不需要处理的请求路径String[] urls = new String[]{"/employee/login","/employee/logout",//静态资源可以放行,我们过滤的是这些页面上的动态数据"/backend/**","/front/**"};//如果我们请求的路径是/backend/index.html这类的,他和上面放行的路径/backend/**不匹配//这时就要用到路径匹配器//2.判断本次请求是否需要处理boolean check = check(requestURI, urls);//3.如果不需要处理,则直接放行if (check){log.info("------本次请求{}不需要处理------",requestURI);filterChain.doFilter(request,response);return;}//4.判断登陆状态,如果已登录,则直接放行if (request.getSession().getAttribute("selectEmployee") != null){log.info("用户已登录,id为------>{}",request.getSession().getAttribute("selectEmployee"));filterChain.doFilter(request,response);return;}//5.如果没有登陆,则返回未登录结果//这里的页面跳转,前端已经做了(响应拦截器),后端只需要给前端响应数据,前端就能自己做判断,并执行页面跳转(request.js)//注意这里,为什么之前controller层中直接return数据,而这里要用流的方式输出?因为这个方法的返回值为voidlog.info("用户未登陆");response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));}/*** 路径匹配* @param requestURI* @param urls* @return*/public boolean check(String requestURI,String[] urls){for (String url : urls) {boolean match = PATH_MATCHER.match(url, requestURI);if (match){return true;}}return false;}
}

介绍下这个类中的重点:

  • @WebFilter(filterName = "LoginCheckFilter",urlPatterns = "/*") 表明这个类是个filter,并且设置filter的名称过滤路径
  • 有了上面的注解之后,我们还需要在springboot的启动类上添上如下注解:
    @ServletComponentScan 有了这个注解之后,在filter,servlet,listener上使用@WebFilter这个注解之后,可以自动完成注册
  • 在这个类中有一个叫check的方法,用来进行路径匹配,就是用从前端获取的URI和自己设置的放行的路径进行比较,若成功匹配,就返回true,否则返回false

单独讲解下,用户没有登录的情况的程序,这个要结合前端代码来看,如下:

在前后端分离的项目里,后端只管数据Model,前端来管控制视图跳转View,上面的代码可以看出,要想进行试图跳转,必须满足两个条件,一个是code===0,这个在我们通用类R中封装的有这种情况,若返回R.error,里面的code默认是0,另一个是msg==='NOTLOGIN',这个需要后端自己传值,但要注意的是,doFilter这个方法的返回值是void,因此我们要用getWrite()来给前端传值 

2.添加员工功能

前端分析

在前后端分离的项目中,后端一定要学会看前端的代码,请求,返回值等等,然后照着前端的接口来写程序,下面以添加员工为例来说明

 进入添加员工的页面,我们输入了员工数据之后,network会显示相关的请求,从这里我们就能获取到该功能的请求url和method,有了这两个东西,我们才能规范的编写controller层的代码

看了请求携带的参数之后,我们才能规范的编写SQL语句(知道了前端参数和数据库字段的对应关系) 

看了js代码,我们得知了,当添加员工成功时,要给前端返回code===1,所有controller层的返回值要用通用类中的R.success(这个方法中设置了code为1)

controller——EmployeeController类

//添加员工功能@PostMappingpublic R<String> addEmployee(@RequestBody Employee employee){System.out.println("准备执行");//设置初始密码123456,需要进行md5加密employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));//设置用户创建和修改的时间employee.setCreateTime(LocalDateTime.now());employee.setUpdateTime(LocalDateTime.now());//设置创建和修改人(因为视频里的这两个属性是用的mybatis-plus,这里我自己做了修改)employee.setCreateUser(1L);employee.setUpdateUser(1L);//设置idRandom random = new Random();Long i = (long) random.nextInt(1000);employee.setId(i);employeeService.addEmployee(employee);log.info("员工信息:{}",employee.toString());return R.success("添加成功");}

 common——GlobalExceptionHandler类

数据库里的username字段设置的是唯一unique,当我们在添加员工的时候,如果出现用户名重复的情况,数据库就会抛出异常SQLIntegrityConstraintViolationException(其实id也设置了唯一,在视频里采用的是mybatis-plus,人家在设置id时用了雪花算法,而我用的是mybatis,所以上面的代码,采用的是随机数,而不是给它写死的),所以我们要来处理这个数据库抛出来的异常 

在common包下添加一个处理异常的通用类 

着重介绍下面的程序

  • @ControllerAdvice 用来拦截Controller的注解,它默认不写参数,表示拦截所有的controller,我们也可以给他添加某个包名,让其扫描指定包下的所有controller,也可以像下面的程序这样,给他指定扫描controller(下面的代码意思是,让它扫描所有的controller和所有的RestController)
  • @ResponseBody 用来返回Json格式的数据
  • @ExceptionHandler 处理指定的异常 
@ControllerAdvice(annotations = {RestController.class,Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public R<String> exceptionHandler(SQLIntegrityConstraintViolationException exception){log.info(exception.getMessage());//抛出的异常为Duplicate entry 'zhangsan' for key 'employee.idx_username'//如果抛的异常里有"Duplicate entry"就进入ifif (exception.getMessage().contains("Duplicate entry")){//将我们获取的异常按空格为分隔符封装成数组//比如这个数组的0号下标对应的字符串是Duplicate,1号下标对应的是entryString[] split = exception.getMessage().split(" ");String msg = split[2] + "已存在";return R.error(msg);}return R.error("未知错误");}
}

除了上面的注解和方法要学习之外,我们也要学习这样的处理方法,如果不这样除了,我可能会将输入的用户名和遍历数据库后得到的username做对比,如果一样再返回给前端对应的信息,这样的方式和上面的处理方式一对比后,就显得很烂了

3.分页查询功能(Mybatis)

  • 原本一直在用mybatis进行项目开发,但是在这个功能完成的时候,因为controller层的返回数据的类型是人家mybatisplus封装好的,这下不得不用mybatisplus去开发了,但是基于mybatis的代码我还是放下面了,可以参考参考>_<

前端代码分析

当我进入到员工列表页面时,前端就会发送给一个请求,里面携带了两个路径参数page和pageSize,并且告知了后端请求的url,还有请求方式为GET

 当我在搜索框里输入员工姓名并点击查询时,前端又会传来一个叫做name的路径参数

后端就需要根据这些来完善相关代码,如下:

mapper——EmployeeMapper接口

  //查询所有员工List<Employee> selectAllEmployee(int page,int pageSize,String name);

mapper——EmployeeMapper.xml映射文件

可以看看这里的SQL怎么来写的,由于刚才的前端分析可知name这个参数前端传了才有,没传就没有,所以SQL编写的时候就要加一个if判断,来动态添加name属性

<select id="selectAllEmployee" resultType="employee">select * from employee<if test="name != null">where name like concat('%',#{name},'%')</if>limit #{page},#{pageSize}</select>

这里Service层就省略吧,有点懒了说实话,啊哈哈哈哈>_<

controller——EmployeeController类

//分页查询功能@GetMapping("/page")public R<Employee> page(int page,int pageSize,String name){log.info("page = {},pageSize = {},name = {}",page,pageSize,name);page = (page - 1) * pageSize;List<Employee> employees = employeeService.selectAllEmployee(page, pageSize,name);for (Employee employee : employees) {System.out.println(employee);}return null;}

有以下几点需要学习:

  • 通过GET请求的方式,后端可以直接获得路径参数(注意:如果是restful风格的GET请求,则要在参数前加上@PathVariable注解),具体可以看看这个作者写的文章:
  • https://blog.csdn.net/CJPSR/article/details/131094717
  • 这里我们把前端传的路径参数里的三个值取出来了,并且做了分页查询的逻辑处理,再让其作为参数传到分页查询的方法里

4.分页查询功能(MybatisPlus)

前端代码已经分析过了,接下来只是用mybatisplus来实现这个功能

准备工作:

  • 导入依赖
        <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency>
  • mapper层接口继承BaseMapper<>
@Mapper
@Repository
public interface EmployeePlusMapper extends BaseMapper<Employee> {
}
  • service层接口继承IService<>,实现类继承ServiceImpl<>

public interface EmployeePlusService extends IService<Employee> {
}
@Service
public class EmployeePlusServiceImpl extends ServiceImpl<EmployeePlusMapper, Employee> implements EmployeePlusService {
}

PS:之前用的是mybatis,现在换成了mybatisplus之后,配置文件里的格式要改一改

#mybatis.configuration.map-underscore-to-camel-case=true
#
#mybatis.type-aliases-package=com.itheima.entity
#
#mybatis.mapper-locations=classpath:mybatis/mapper/*.xmlmybatis-plus.configuration.map-underscore-to-camel-case=truemybatis-plus.type-aliases-package=com.itheima.entitymybatis-plus.mapper-locations=classpath:mybatis/mapper/*.xml

controller——EmployeeController类

  @GetMapping("/page")public R<Page> page(int page,int pageSize,String name){log.info("page = {}, pageSize = {}, name = {}",page,pageSize,name);//构造分页构造器Page pageInfo = new Page<>(page,pageSize);//构造条件构造器LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();if (name != null){wrapper.like(Employee::getName,name);}//添加排序条件wrapper.orderByDesc(Employee::getUpdateTime);//执行查询employeePlusService.page(pageInfo,wrapper);return R.success(pageInfo);}

config——MybatisPlusConfig类

这个类的作用是导入mybatisplus分页查询的插件

/*** 导入MybatisPlus分页查询的插件*/
@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return mybatisPlusInterceptor;}
}

5.启用和禁用员工账号

首先,只有admin管理员才能有启用和禁用员工的按钮,普通员工没有这个功能按钮,这是怎么实现的呢?

在list.html文件里有这样的程序:

如果user为admin,那么就展现下面的禁用和启用的按钮,否则就不展现,那么这个user是哪来的呢?

同样的,在list.html中有create的钩子函数:

将key值为userInfo的键值对中的username转换成Json格式并且给user,这个userInfo就是我们在实现登录功能时,如果登陆成功,就将这个用户信息存在userInfo这个键中,并将这个键值对存放在localStorage中,如下:

了解一点前端代码,总没有坏处>_<

下面来正式开发启用和禁用功能

 mapper——EmployeeMapper接口

    //修改员工的statusint updateEmployeeStatus(int status, Long id, LocalDateTime updateTime);

mapper——EmployeeMapper.xml映射文件

 <update id="updateEmployeeStatus">update employee set status = #{status},update_time = #{updateTime} where id = #{id}</update>

service层略

controller——EmployeeController类

//禁用和启用功能@PutMappingpublic R<String> updateEmployeeStatus(@RequestBody Employee employee){//获取前端传来的json格式的参数Integer status = employee.getStatus();Long id = employee.getId();//修改时间employee.setUpdateTime(LocalDateTime.now());log.info("id = {},status = {}",id,status);//执行SQL语句employeeService.updateEmployeeStatus(status,id,employee.getUpdateTime());return R.success("执行成功");}

6.编辑员工功能

6.1.回显用户数据

老规矩,先分析前端代码,当点击编辑按钮时,前端就会发送如下请求

进入add.html来分析分析前端代码 ,从这里可以看出添加员工和修改员工的页面是同一个,当从前端的url中获取id,那么就编辑页面,并且执行init方法

init方法的具体内容是,当后端传来的code为1,则就在编辑页面回显员工的信息。 

mapper——EmployeeMapper接口 

//编辑用户——回显用户数据
Employee selectEmployeeById(long id);

EmployeeMapper.xml映射文件

<select id="selectEmployeeById" resultType="employee">select * from employee where id = #{id}
</select>

controller——EmployeeController类

   //编辑用户——回显用户数据@GetMapping("/{id}")public R<Employee> selectEmployeeById(@PathVariable Long id){//根据id查询用户Employee employee = employeeService.selectEmployeeById(id);return R.success(employee);}

 获取restful风格的路径参数,需要添加@PathVariable注解

 6.2.编辑用户

  • 分析了前端请求可知,这个功能的请求路径和请求方式和之前禁用和启用员工功能的是一样的,所以我们只需要在之前编写好的基础上做一点修改即可。
  • 回顾下之前的禁用和启用功能,无非就是修改一下员工的status属性,这个编辑功能的本质也是修改,所以只需要在xml映射文件里添一个if判断即可,当传的员工信息的参数不为空,那么就把那些属性添加到SQL语句中

 EmployeeMapper.xml映射文件

 <update id="updateEmployee" parameterType="employee">update employee set username = #{username} ,name = #{name} ,phone = #{phone} ,sex = #{sex} ,id_number = #{idNumber} ,update_time = #{updateTime}where id = #{id}</update>

还有一个小修改是,将对应的方法的参数修改成Employee类型

  • 别学着学懵了,SQL语句里#{}中的属性,是我们entity里编写的属性,当controller层获取到前端传来的用户信息的参数之后,就会把其封装到Employee类型的参数中(因为前端是这样写好的,通过把用户数据封装到Employee对象中,再用Json格式传给后端)如此,这个employee的对象中的属性就会随之改变,不需要让方法的参数具体到某一个字段

 前后修改对比

    //修改员工的status//int updateEmployeeStatus(int status, Long id, LocalDateTime updateTime);int updateEmployeeStatus(Employee employee);

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

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

相关文章

Qt打开已有工程方法

在Qt中&#xff0c;对于一个已有工程如何进行打开&#xff1f; 1、首先打开Qt Creator 2、点击文件->打开文件或项目&#xff0c;找到对应文件夹下的.pro文件并打开 3、点击配置工程 这样就打开对应的Qt项目了&#xff0c;点击运行即可看到对应的效果 Qt开发涉及界面修饰…

01-DBA自学课-安装部署MySQL

一、安装包下载 1&#xff0c;登录官网 MySQL :: MySQL Downloads 2&#xff0c;点击社区版下载 3&#xff0c;找到社区服务版 4&#xff0c;点击“档案”Archives 就是找到历史版本&#xff1b; 5&#xff0c;选择版本进行下载 本次学习&#xff0c;我们使用MySQL-8.0.26版本…

IAB欧洲发布首张泛欧洲数字零售媒体能力矩阵图

2024年1月18日&#xff0c;互动广告署-欧洲办事处&#xff08;IAB Europe)发布了首张泛欧洲数字零售媒体能力矩阵图。为媒体买家提供的新资源概述了在欧洲运营的零售商提供的现场、场外和数字店内零售媒体广告机会。 2024年1月18日&#xff0c;比利时布鲁塞尔&#xff0c;欧洲领…

实用工具推荐:适用于 TypeScript 网络爬取的常用爬虫框架与库

随着互联网的迅猛发展&#xff0c;网络爬虫在信息收集、数据分析等领域扮演着重要角色。而在当前的技术环境下&#xff0c;使用TypeScript编写网络爬虫程序成为越来越流行的选择。TypeScript作为JavaScript的超集&#xff0c;通过类型检查和面向对象的特性&#xff0c;提高了代…

NFT交易市场-后端开发

首先我们需要配置好我们的ipfs&#xff0c;参考官方文档 1.https://docs.ipfs.tech/install/command-line/#system-requirementshttps://docs.ipfs.tech/how-to/command-line-quick-start/#initialize-the-repository 首先新建一个文件夹 然后在终端输入npm init -y命令进行初…

【AI】发现一款运行成本较低的SelfHosting语言模型

【背景】 作为一个想构建局域网AI服务的屌丝,一直苦恼的自然是有限的资源下有没有对Spec要求低一点的SelfHosting的AI服务框架了。今天给大家介绍这款听起来有点希望,但是我也还没试验过,感兴趣的可以去尝试看看。 【介绍】 大模型生成式AI与别的技术不同,由于资源要求高…

分布式之网关介绍

一、网关简介 1、网关背景 由于微服务“各自为政的特性”使微服务的使用非常麻烦。通常公司会有一个“前台小姐姐”作为统一入口&#xff0c;这就是网关 2、网关作用 统一入口&#xff1a;为服务提供一个唯一的入口&#xff0c;网关起到外部和内部隔离的作用&#xff0c; 保…

演讲嘉宾公布 | 智能家居与会议系统专题论坛将于3月28日举办

一、智能家居与会议系统专题论坛 智能家居通过集成先进的技术和设备&#xff0c;为人们提供了更安全、舒适、高效、便捷且多彩的生活体验。智能会议系统它通过先进的技术手段&#xff0c;提高了会议效率&#xff0c;降低了沟通成本&#xff0c;提升了参会者的会议体验。对于现代…

iOS模拟器 Unable to boot the Simulator —— Ficow笔记

本文首发于 Ficow Shen’s Blog&#xff0c;原文地址&#xff1a; iOS模拟器 Unable to boot the Simulator —— Ficow笔记。 内容概览 前言终结模拟器进程命令行改权限清除模拟器缓存总结 前言 iOS模拟器和Xcode一样不靠谱&#xff0c;问题也不少。&#x1f602; 那就有病治…

设计数据库之外部模式:数据库的应用

Chapter5&#xff1a;设计数据库之外部模式&#xff1a;数据库的应用 笔记来源&#xff1a;《漫画数据库》—科学出版社 设计数据库的步骤&#xff1a; 概念模式 概念模式(conceptual schema)是指将现实世界模型化的阶段进而&#xff0c;是确定数据库理论结构的阶段。 概念模…

分布式搜索引擎-DSL查询文档

分布式搜索引擎-DSL查询文档 文章目录 分布式搜索引擎-DSL查询文档1、DSL Query的分类1.1、全文检索查询1.2、精确查询1.3、地理查询1.4、复合查询1.5、Function Score Query1.6、复合查询Boolean Query 2、搜索结果处理2.1、排序2.2、分页2.3、深度分页2.4、高亮 1、DSL Query…

优化选址问题 | 基于鹈鹕算法求解基站选址问题含Matlab源码

目录 问题代码问题 鹈鹕算法(Pelican Optimization Algorithm, POA)是一种相对较新的启发式优化算法,模拟了鹈鹕鸟觅食的行为。这种算法通常用于解决复杂的优化问题,如函数优化、路径规划、调度问题等。基站选址问题通常是一个复杂的优化问题,需要考虑覆盖范围、干扰、成…

java设计模式(2)---六大原则

设计模式之六大原则 这篇博客非常有意义&#xff0c;希望自己能够理解的基础上&#xff0c;在实际开发中融入这些思想&#xff0c;运用里面的精髓。 先列出六大原则&#xff1a;单一职责原则、里氏替换原则、接口隔离原则、依赖倒置原则、迪米特原则、开闭原则。 一、单一职…

STM32 使用gcc编译介绍

文章目录 前言1. keil5下的默认编译工具链用的是哪个2. Arm编译工具链和GCC编译工具链有什么区别吗&#xff1f;3. Gcc交叉编译工具链的命名规范4. 怎么下载gcc-arm编译工具链参考资料 前言 我们在STM32上进行开发时&#xff0c;一般都是基于Keil5进行编译下载&#xff0c;Kei…

docker 数据卷 (二)

1&#xff0c;为什么使用数据卷 卷是在一个或多个容器内被选定的目录&#xff0c;为docker提供持久化数据或共享数据&#xff0c;是docker存储容器生成和使用的数据的首选机制。对卷的修改会直接生效&#xff0c;当提交或创建镜像时&#xff0c;卷不被包括在镜像中。 总结为两…

FileZilla 链接服务器提示 20 秒连接超时

FileZilla 有个默认设置是如果 20 秒没有数据的话会自动中断链接。 Command: Pass: **************** Error: Connection timed out after 20 seconds of inactivity Error: Could not connect to server修改配置 这个配置是可以修改的&#xff0c;修改的步骤为&#xff1a; …

PostgreSQL中控制文件的解析与恢复

最近遇到有人问起PG中控制文件的一些使用问题,总结了一下。 1、PG控制文件简介 1.1、存储的位置 它的路径位于: 相关信息,可以用命令pg_controldata得到: [10:41:27-postgres@centos2:/var/lib/pgsql/14/data/global]$ pg_controldata -D $PGDATA pg_control version …

【LabVIEW FPGA入门】FPGA寄存器(Register)

当您需要从多个时钟域或设计的不同部分访问数据&#xff0c;并且需要编写可重复使用的代码时&#xff0c;可使用寄存器项来存储数据。与 FIFO 相比&#xff0c;寄存器项消耗的 FPGA 逻辑资源更少&#xff0c;而且不消耗块存储器&#xff0c;而块存储器是最有限的 FPGA 资源类型…

java数据结构与算法基础-----字符串------正则表达式---持续补充中

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 目前校招的面试&#xff0c;经常会遇到各种各样的有关字符串处理的算法。掌…

综合知识篇20-基于中间件的开发新技术考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…