SpringBoot异常处理器的使用与添加员工功能实现流程介绍
作者:懒羊羊.java 发布时间:2021-10-21 19:24:23
承接上文 传送门
一.完善登录功能
按照常理,只有登陆过后才能进入首页,若没有登陆则应当直接跳转到登陆页面,这样的场景不就完美契合过滤器的功效吗
下面,针对此功能来设计一个过滤器
@Slf4j
@WebFilter(filterName = "loginFilterCheck", urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
@Override
public 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);
}
}
通过它可以拦截到来自页面的请求
对于拦截的请求,我们要做如下的处理:
1、获取本次请求的URI,并定义不需要放行的资源路径
//获取本次请求的uri
String requestURI = request.getRequestURI();
//定义不需要处理的资源路径
String[] urls=new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
为了解决通配符的引入而造成的路径比较问题,我们可以通过路径匹配器AntPathMatcher()来解决(由Spring为我们提供的工具)
2、判断本次请求是否需要处理
当我们拿到工具对象之后,就可以通过遍历字符串数组的方式,将请求中的uri与事先设定中不需要拦截资源路径进行对比,然后封装成一个check方法,就像这样:
public boolean check(String[] urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if (match){
return true;
}
}
return false;
}
3.如果是不需要处理的资源路径则直接放行
//判断是否需要处理
boolean check = check(urls, requestURI);
//如果不需要处理就直接放行
if (check){
filterChain.doFilter(request,response);
return;
}
4、判断登录状态,如果已登录,则直接放行,如果未登录则返回未登录结果(通过从Session里获得对象,查看是否为空来进行评判)
//查看登陆状态 如果已登录 则直接放行
if (!(request.getSession().getAttribute("employee") == null)) {
filterChain.doFilter(request, response);
return;
}
//如果未登录,则通过输出流的方式向客户端页面响应数据
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
二.添加员工功能
前端页面已将写好,,当用户录入信息,就伴随着一次请求,而后端要做的就是将在请求中将表单里的数据保存到数据库中
新增员工,其实就是将我们添加页面录入的员工数据插入到employee表。需要注意,employee表中对username字段加入了唯一约束,因为username是员工的登录账号,必须是唯一的
我们该如何实现?
1、当页面发送ajax请求,表单中输入的数据以json的形式提交到服务器端
2、服务端Controller层接收页面提交的数据并调用Service层将数据进行保存
3、Service调用Mapper操作数据库,保存数据
Controller层如何设计呢?
1.毋庸置疑的是,首先要封装一个用于保存的方法save()
2.其次HttpServletRequest里已经封装了表单的数据,当一次请求发生其中的数据就被当作形参传入了方法内,随即就是设置表单中没有的属性,比如:setCreateTime,setUpdateTime,setCreateUser,setUpdateUser
总而言之,方法里涵盖了表单里提交的数据和请求发生后动态变更的数据,而我们写好了save()方法之后,就得去用Service层(employeeService)来执行这个方法将数据保存到数据库中,就像这样:
@PostMapping //前端的请求路径为employee,而上述@RequestMapping("/employee")已写好
public R<String> save(HttpServletRequest request, @RequestBody Employee employee) {
log.info("新增员工:{}", employee.toString());
//设置初始默认密码
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
//设置更新时间
employee.setCreateTime(LocalDateTime.now());//创建时间
employee.setUpdateTime(LocalDateTime.now());//更新时间
//获取当前登录用户的id
Long empID = (Long) request.getSession().getAttribute("employee");
employee.setCreateUser(empID);
employee.setUpdateUser(empID);
return R.success("添加员工成功!");
}
当我们在前端表单中填好了新增员工的信息后,点击保存,后台就执行如下的SQL:
三.异常处理的运用
写好了添加的方法,我激动得添加了好几个员工,但是当我添加了一个同名员工之后,程序运行的戛然而止,后台竟然抛出了异常:java.sql.SQLIntegrityConstraintViolationException
前端也报出了接口错误500,结合之前的表设计,不难想到我的username索引设置的是unique呀!唯一约束!
很显然
我们需要处理这个异常,很多人第一时间想到的可能是:这则错误是service层调用save()方法所导致的,那我把save()方法try-catch不就行了吗?
这样想确实没毛病是我的话我也这样,可是以后业务一旦复杂起来,需要这样处理的方法多了怎么办呢?我要去一个一个try-catch吗?多麻烦啊!
这不就是所谓的硬编码问题嘛!处理这种问题咱们在一个地方统一配置一下不久统统解决啊,跟MyBatis解决JDBC硬编码问题是一个道理!
所以,我们使用异常 * 进行全局异常捕获,这样设置就轻松化解:
/**
* 全局异常处理
*/
@ControllerAdvice(annotations = {RestController.class, Controller.class}) //拦截有指定注解类的Controller
@Slf4j
@ResponseBody
public class GlobalExceptionHandler {
/**
* 异常处理方法,一旦Controller发生此异常就会被拦截到
* @return
*/
@ExceptionHandler({SQLIntegrityConstraintViolationException.class})
public R<String> excpHandler(SQLIntegrityConstraintViolationException exception) {//捕获到的异常被传到方法的形参里
log.info("异常信息:"+exception.getMessage());
//细化添加失败后的返回信息
if (exception.getMessage().contains("Duplicate entry")){
String[] s = exception.getMessage().split(" ");
String msg=s[2]+"已存在!";
return R.error(msg);
}
return R.error("发生异常!添加失败!");
}
}
一旦Controller层发生此异常就会被拦截到!
通过Debug,当程序出现因为重复添加而引起的异常时我们的msg就被细化了出来
来源:https://iyu77.blog.csdn.net/article/details/127130230


猜你喜欢
- 背景SpringBoot的应用监控方案比较多,SpringBoot+Prometheus+Grafana是目前比较常用的方案之一。它们三者之
- 以前公司的产品已经上线20多年了,主要是维护,也就是改bug。每周我们Team会从Jira上拿我们可以改的bug,因为每个团队负责的业务范围
- 在Maven工程里运行Java main方法mvn compilemvn exec:java -Dexec.mainClass="
- 在网上有非常多通过射线方式实现的人物行走控制脚本,可是假设仅仅是想通过键盘按键来控制的话。比方进行第三人称视角控制,事实上仅仅须要进行简单的
- 不论是使用传统路由的配置方式还是服务路由的配置方式,我们都需要为每个路由规则定义匹配表达式,也就是上面所说的 path 参数。在Zuul中,
- 一、项目简述(+需求文档+PPT)功能:卡管理,卡消费,卡充值,图书借阅,消费,记录,注销等等功能。二、项目运行环境配置:Jdk1.8 +
- 服务降级服务压力剧增的时候,根据当前的业务情况及流量对一些服务和页面有策略的降级,以此缓解服务器的压力,以保证核心任务的进行。同时保证部分甚
- 本文实例为大家分享了C语言实现顺序表的顺序查找和折半查找的具体代码,供大家参考,具体内容如下顺序查找:#include <iostre
- 1:@Qualifier@Qualifier 注释指定注入 Bean 的名称,这样歧义就消除了。所以@Auto
- 本文实例完成人机猜拳互动游戏的开发,供大家参考,具体内容如下阶段一:实验——分析业务,创建用户类1.分析业务,抽象出类、类的特征和行为2.创
- AtomicInteger 类底层存储一个int值,并提供方法对该int值进行原子操作。AtomicInteger 作为java.util.
- 在 Windows 有一些字符是不能作为文件名,尝试重命名一个文件,输入/ 就可以看到windows 提示的不能作为文件名的字符那么具体是包
- c#里面封装了几乎所有我们可以想到的和我们没有想到的类,流是读取文件的一般手段,那么你真的会用它读取文件中的数据了么?真的能读完全么?通常我
- 背景在Spring boot项目开发中经常遇到需要使用枚举的场景,比如描述状态、性别、类型等相关字段。通常这些字段在数据库会以tinyint
- 前言上文讲的MyBatis部署运行且根据官网运行了一个demo:一步到位部署运行MyBatis3源码<保姆级>jdbc再贴一个J
- 本文实例为大家分享了Android九宫格图片展示的具体代码,供大家参考,具体内容如下推荐视频:尚硅谷Spring Data JPA视频教程,
- Spring Data JPA 映射VO/DTO对象在项目开发中,时常需要根据业务需求来映射VO/DTO对象(这两个概念理解感觉很模糊- 。
- 一、常用的单位:相对单位主要有:px、sp、dp绝对单位主要有:pt、in、mm二、单位应用总结:一般用相对单位,而不是绝对单位1、字体的大
- BitArray的基础可以看菜鸟编程BitArray 类管理一个紧凑型的位值数组,它使用布尔值来表示,其中 true 表示位是开启的(1),
- 本文实例讲解了通知Notification使用方法,此知识点就是用作通知的显示,包括振动、灯光、声音等效果,分享给大家供大家参考,具体内容如