【外卖项目实战开发二】

news/2024/5/4 18:46:37/文章来源:https://blog.csdn.net/m0_52896752/article/details/127877608

文章目录

  • 1、完善登录功能
    • 问题分析
    • 代码实现
  • 2、新增员工
    • 需求分析
    • 数据模型
    • 代码开发
  • 3、员工信息分页查询
    • 需求分析
    • 代码开发
  • 4、启用/禁用员工账号
    • 需求分析
    • 代码开发
    • 代码修复
  • 5、编辑员工信息
    • 需求分析
    • 代码开发


1、完善登录功能

问题分析

前面我们已经完成了后台系统的员工登录功能开发,但是还存在一个问题:用户如果不登录,直接访问系统首页面,照样可以正常访问。

这种设计并不合理,我们希望看到的效果应该是,只有登录成功后才可以访问系统中的页面,如果没有登录则跳转到登录页面。

那么,具体应该怎么实现呢?

答案就是使用过滤器或者拦截器,在过滤器或者拦截器中判断用户是否已经完成登录,如果没有登录则跳转到登录页面

代码实现

实现步骤:

  • 创建自定义过滤器LoginCheckFilter
@WebFilter(filterName = "LoginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request=(HttpServletRequest) servletRequest;HttpServletResponse response=(HttpServletResponse) servletResponse;log.info("拦截到请求:{}",request.getRequestURI());filterChain.doFilter(request,response);}
}
  • 在启动类上加入注解@ServletComponentScan
@Slf4j
@SpringBootApplication
@ServletComponentScan
public class ReggieApplication {public static void main(String[] args) {SpringApplication.run(ReggieApplication.class,args);log.info("项目启动成功!!!");}
}
  • 完善过滤器的处理逻辑
    过滤器具体的处理逻辑如下:
    1、获取本次请求的URI
    2、判断本次请求是否需要处理
    3、如果不需要处理,则直接放行
    4、判断登录状态,如果已登录,则直接放行
    5、如果未登录则返回未登录结果
    **image**
/*** @ClassName: LoginCheckFilter* @Description: 检查用户是否已经完成登录*/
@WebFilter(filterName = "LoginCheckFilter",urlPatterns = "/*")
@Slf4j
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("拦截到请求:{}",requestURI);//        定义不需要处理的请求路径String[] urls=new String[]{"/employee/login","/employee/logout","/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;}log.info("用户未登录");
//        5、如果未登录则返回未登录结果,通过输出流向客户端页面响应数据response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));return;}//路径匹配,检查本次请求是否需要放行public boolean check(String[] urls,String requestURI){for (String url : urls) {boolean match = PATH_MATCHER.match(url, requestURI);if(match==true){return true;}}return  false;}
}

2、新增员工

需求分析

后台系统中可以管理员工信息,通过新增员工来添加后台系统用户。点击 添加员工 按钮跳转到新增页面,如下:
image

数据模型

新增员工,其实就是将我们新增页面录入的员工数据插入到employee表。需要注意,employee表中对username字段加入了唯一约束,因为username是员工的登录账号,必须是唯一的

代码开发

在开发代码之前,需要梳理一下整个程序的执行过程:

  • 页面发送ajax请求,将新增员工页面中输入的数据以json的形式提交到服务端
  • 服务端Controller接收页面提交的数据并调用Service将数据进行保存
  • Service调用Mapper操作数据库,保存数据
    image
    //新增员工@PostMappingpublic R<String> save(HttpServletRequest request, @RequestBody Employee employee){log.info("新增员工,员工信息:{}",employee.toString());//设置初始密码,需要进行md5加密处理employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));employee.setCreateTime(LocalDateTime.now());employee.setUpdateTime(LocalDateTime.now());Long empId = (Long) request.getSession().getAttribute("employee");employee.setCreateUser(empId);employee.setUpdateUser(empId);employeeService.save(employee);return R.success("新增员工成功");}

前面的程序还存在一个问题,就是当我们在新增员工时输入的账号已经存在,由于employee表中对该字段加入了唯一约束,此时程序会抛出异常:
java.sql.SQLIntegrityConstraintViolationException: Duplicate entry ‘heniang’ for key ‘idx_username’

此时需要我们的程序进行异常捕获,通常有两种处理方式:

1、在Controller方法中加入try.catch进行异常捕获

2、使用异常处理器进行全局异常捕获

@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {//进行异常处理方法@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){log.error(ex.getMessage());if(ex.getMessage().contains("Duplicate entry")){String[] split = ex.getMessage().split(" ");String msg=split[2]+"已存在";return R.error(msg);}return R.error("未知错误");}
}

总结

1、根据产品原型明确业务需求

2、重点分析数据的流转过程和数据格式

3、通过debug断点调试跟踪程序执行过程

3、员工信息分页查询

需求分析

系统中的员工很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。

image

代码开发

在开发代码之前,需要梳理一下整个程序的执行过程:

  • 页面发送ajax请求,将分页查询参数(page.pageSize、name)提交到服务端
  • 服务端Controller接收页面提交的数据并调用Service查询数据
  • Service调用Mapper操作数据库,查询分页数据
  • Controller将查询到的分页数据响应给页面
  • 页面接收到分页数据并通过ElementUI的Table组件展示到页面上

配置MP分页插件

@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return  mybatisPlusInterceptor;}
}

员工信息分页查询

@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> queryWrapper=new LambdaQueryWrapper();//添加过滤条件queryWrapper.like(!StringUtils.isEmpty(name),Employee::getName,name);//添加排序条件queryWrapper.orderByDesc(Employee::getUpdateTime);//执行查询employeeService.page(pageInfo,queryWrapper);return R.success(pageInfo);
}

功能测试
image

4、启用/禁用员工账号

需求分析

在员工管理列表页面,可以对某个员工账号进行启用或者禁用操作。账号禁用的员工不能登录系统,启用后的员工可以正常登录。

需要注意,只有管理员(admin用户)可以对其他普通用户进行启用、禁用操作,所以普通用户登录系统后启用、禁用按钮不显示。

代码开发

页面中是怎么做到只有管理员admin能够看到启用、禁用按钮的?

image

在开发代码之前,需要梳理一下整个程序的执行过程:

1、页面发送ajax请求,将参数(id、 status)提交到服务端

2、服务端Controller接收页面提交的数据并调用Service更新数据

3、Service调用Mapper操作数据库

image

页面中的ajax请求是如何发送的?
image

根据id修改员工信息

@PutMapping
public R<String> update(HttpServletRequest request,@RequestBody Employee employee){log.info(employee.toString());Long empId = (Long) request.getSession().getAttribute("employee");employee.setUpdateTime(LocalDateTime.now());employee.setUpdateUser(empId);employeeService.updateById(employee);return R.success("员工信息修改成功");
}

测试过程中没有报错,但是功能并没有实现,查看数据库中的数据也没有变化。观察控制台输出的SQL:
image

SQL执行的结果是更新的数据行数为0,仔细观察id的值,和数据库中对应记录的id值并不相同
image

代码修复

通过观察控制台输出的SQL发现页面传递过来的员工id的值和数据库中的id值不一致,这是怎么回事呢?

分页查询时服务端响应给页面的数据中id的值为19位数字,类型为long

页面中js处理long型数字只能精确到前16位,所以最终通过ajax请求提交给服务端的时候id就改变了

前面我们已经发现了问题的原因,即js对long型数据进行处理时丢失精度,导致提交的id和数据库中的id不一致。

如何解决这个问题?

我们可以在服务端给页面响应json数据时进行处理,将long型数据统一转为String字符串。

具体实现步骤:

1) 提供对象转换器JacksonobjectMapper,基于Jackson进行Java对象到json数据的转换

/*** 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]*/
public class JacksonObjectMapper extends ObjectMapper {public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";public JacksonObjectMapper() {super();//收到未知属性时不报异常this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);//反序列化时,属性不存在的兼容处理this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);SimpleModule simpleModule = new SimpleModule().addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))).addSerializer(BigInteger.class, ToStringSerializer.instance).addSerializer(Long.class, ToStringSerializer.instance).addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));//注册功能模块 例如,可以添加自定义序列化器和反序列化器this.registerModule(simpleModule);}
}

2) 在WebMvcConfig配置类中扩展Spring mvc的消息转换器,在此消息转换器中使用提供的对象转换器进行Java对象到json数据的转换

@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {//创建消息转换器MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();//设置对象转换器,底层使用Jackson将Java转换为jsonmessageConverter.setObjectMapper(new JacksonObjectMapper());//将上面的消息转换器对象追加到mvc框架的转换器集合中converters.add(0,messageConverter);super.extendMessageConverters(converters);
}

5、编辑员工信息

需求分析

在员工管理列表页面点击编辑按钮,跳转到编辑页面,在编辑页面回显员工信息并进行修改,最后点击保存按钮完成编辑操作

image

代码开发

在开发代码之前需要梳理一下操作过程和对应的程序的执行流程:

1、点击编辑按钮时,页面跳转到add.html,并在url中携带参数[员工id]

2、在add.html页面获取url中的参数[员工id]

3、发送ajax请求,请求服务端,同时提交员工id参数

4、服务端接收请求,根据员工id查询员工信息,将员工信息以json形式响应给页面

//根据id查询员工信息
@GetMapping("/{id}")
public R<Employee> getById(@PathVariable String id){log.info("根据id查对象");Employee emp = employeeService.getById(id);if(emp!=null){return R.success(emp);}return R.error("没有查询到该用户信息");
}

5、页面接收服务端响应的json数据,通过VUE的数据绑定进行员工信息回显

6、点击保存按钮,发送ajax请求,将页面中的员工信息以json方式提交给服务端

7、服务端接收员工信息,并进行处理,完成后给页面响应

8、页面接收到服务端响应信息后进行相应处理

注意:add.html页面为公共页面,新增员工和编辑员工都是在此页面操作,所以该代码部分与之前添加员工代码对应,不需要重写。

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

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

相关文章

基于JavaWeb的婚恋交友网站设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

大数据:HDFS的Shell常用命令操作

文章目录一 HDFS的Shell介绍二 HDFS常用命令操作01 创建目录&#xff08;1&#xff09;创建单层目录&#xff08;3&#xff09;创建多层目录02 查看目录03 上传本地文件到HDFS04 查看文件内容05 下载HDFS文件到本地06 删除HDFS文件07 删除HDFS目录08 移动目录或文件09 文件合并…

第九章 堆排序与TOPK问题

第九章&#xff1a;堆排序与TOPK问题一、堆排序&#xff1a;1、思路分析&#xff1a;&#xff08;1&#xff09;建堆&#xff08;2&#xff09;排序2、堆排序模板二、TOPK问题&#xff1a;1、什么是TOPK问题&#xff1f;2、解决方法一、堆排序&#xff1a; 假设我们实现一个小…

26k Star, 理解Git太轻松了。。。

程序员宝藏库&#xff1a;gitee.com/sharetech_lee/CS-Books-Store Git是目前使用比较广泛一款版本控制工具&#xff0c;从事开发工作&#xff0c;很难绕开Git。 因此&#xff0c;关于如何快速学习Git使用一直都是一个经久不衰的话题。 前不久我在另外一篇文章中曾提到Git对初…

树莓派上搭建SVN服务器

目录 一、服务端安装步骤 1.安装svn 2.创建目录 3.创建版本仓库 4.修改配置&#xff08;authz,passwd,svnserve.conf&#xff09; 5.启动服务 二、tortoisSVN客户端安装 三、结束 一、服务端安装步骤 1.安装svn sudo apt-get install subversion 2.创建目录 sudo m…

用Python蹭别人家图片接口,做一个【免费图床】吧

打开本文&#xff0c;相信你确实需要一个免费且稳定的图床&#xff0c;这篇博客就让你实现。 文章目录⛳️ 谁家的图床⛳️ 实战编码⛳️ 第一轮编码⛳️ 第二轮编码⛳️ 第三轮编码⛳️ 第四轮编码⛳️ 谁家的图床 这次咱们用新浪微博来实现【免费图床应用】&#xff0c;通过…

基于keras 卷积神经外网络搭建的手写数字识别 完整代码+数据可直接运行

项目介绍: 适合新手入门学习代码数据很简洁 上结果: 主要的卷积神经网络: 卷积是指在滑动中提取特征的过程,可以形象地理解为用放大镜把每步都放大并且拍下来,再把拍下来的图片拼接成一个新的大图片的过程。 2D卷积是一个相当简单的操作: 我们先从一个小小的权重矩阵…

十个值得珍藏的正则表达式

正则表达式常学常忘&#xff0c;记规则不如记例子&#xff0c;记多不如记精&#xff0c;记例子就记最经典的。下面是本人珍藏的十个有用的正则表达式&#xff0c;不吝分享&#xff0c;以飨读者。 正则表达式要点 小括号&#xff1a;代表分组 中括号&#xff1a;代表集合 大括号…

外卖项目08---Linux

目录 一、 Linux简介 119 二、Linux安装 120 三、常用命令 122 3.1Linux命令初体验 3.1.1 command [-options] [parameter] 3.2Linux常用命令---文件目录操作命令-ls&-cd&-cat 124 3.2.1list 3.2.2 cd 3.2.3 cat 3.3 Linux常用命令---文件目录操作命令…

机器学习模型与backtrader框架整合

原创文章第116篇&#xff0c;专注“个人成长与财富自由、世界运作的逻辑&#xff0c; AI量化投资”。 北京疫情似乎还没有到拐点&#xff0c;但这三天结束后应该会到来。 今天重点说说&#xff0c;机器学习模型整合到我们的回测框架中&#xff0c;并与backtrader连接起来回测…

傻白入门芯片设计,先进封装技术(五)

集成电路芯片与封装之间是不可分割的整体。没有一个芯片可以不用封装就能正常工作&#xff0c;封装对芯片来说是必不可少的&#xff0c;随着IC生产技术的进步&#xff0c;封装技术也不断更新换代&#xff0c;每一代IC都与新一代的IC封装技术紧密相连。 目录 一、什么是封装&am…

详解设计模式:抽象工厂模式

工厂方法模式&#xff0c;又称工厂模式、多态工厂模式和虚拟构造器模式&#xff0c;通过工厂父类定义负责创建产品的公共接口&#xff0c;子类负责生产具体对象。可以理解为简单工程模式的升级&#xff0c;解决简单工厂模式的弊端。 &#xff5e; 本篇内容包括&#xff1a;关于…

java基本语法 下

目录 运算符 运算符&#xff1a;算术运算符 运算符&#xff1a;赋值运算符 运算符&#xff1a;比较运算符 运算符&#xff1a;逻辑运算符 运算符&#xff1a;三元运算符 运算符的优先级 程序流程控制 概念 顺序结构 if-else结构 switch-case结构 循环结构 循环结构…

你不能错过的【Python爬虫】测试3(爬取所有内容 + 完整源代码 + 架构 + 结果)

目录 一、主要工具包 以及 版本二、架构展示三、各部分code3.1 yjs.py (重要)3.2 items.py3.3 middlewares.py3.4 pipelines.py3.5 settings.py3.6 start.py四、结果展示一、主要工具包 以及 版本 scrapy:2.7.1版本(这里主要用到的工具包) 二、架构展示 三、各部分code 3…

8、MyBatis核心配置文件之typeAliases(mybatis-config.xml)

MyBatis核心配置文件之typeAliases&#xff08;mybatis-config.xml&#xff09; 1、&#xff01;&#xff01;&#xff01;&#xff01;注意 2、 设置类型别名&#xff08;比如有的全类名&#xff08;resultType&#xff09;太长了不好使用&#xff09; typeAlias :设置某个类…

AOP实现方式-P20,21,22

项目的包&#xff1a; pom依赖导入有关aop的包&#xff1a; <dependencies><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactI…

mysql-6-主从复制搭建

1 总结 1&#xff1a;主从复制最大缺陷就是延迟。 2 搭建前的准备 2.1复制的基本原则 每个slave只有一个master每个slave只能有一个唯一的服务器ID每个master可以有多个slavemysql版本尽量一致&#xff0c;防止出问题。两台服务能ping通MySQL主从是基于binlog的&#xff0c;主上…

【路径规划】(1) Dijkstra 算法求解最短路,附python完整代码

好久不见&#xff0c;我又回来了&#xff0c;这段时间把路径规划的一系列算法整理一下&#xff0c;感兴趣的点个关注。今天介绍一下机器人路径规划算法中最基础的 Dijkstra 算法&#xff0c;文末有 python 完整代码&#xff0c;那我们开始吧。 1. 算法介绍 1959 年&#xff0c…

FAIRNESS IN MACHINE LEARNING: A SURVEY 阅读笔记

论文链接 刚读完一篇关于机器学习领域研究公平性的综述&#xff0c;这篇综述想必与其有许多共通之处&#xff0c;重合部分不再整理笔记&#xff0c;可详见上一篇论文的笔记&#xff1a; A Survey on Bias and Fairness in Machine Learning 阅读笔记_Catherine_he_ye的博客 S…

scrapy的入门使用

目录 一、 安装scrapy 1.windonws/Mac安装命令&#xff1a; 2. 安装依赖包&#xff1a;pip install pypiwin32 二、 scrapy项目开发流程 1.创建项目:    2.生成一个爬虫: 3.提取数据: 4.保存数据: 三、 创建项目 四、创建爬虫 五、完善爬虫 5.2 定位元素以及提取…