Web登录认证

Web登录认证-课堂笔记

1. 接收表单参数的时候,如果是日期字符串,服务端接收时需要加注解:@DateTimeFormat(pattern="日期格式")
2. 接收路径变量参数的时候,Controller的方法形参上要加:@PathVariable("")
3. 文件上传:
	客户端三要素:
		表单提交方式要使用POST
		表单form标签上![在这里插入图片描述](https://img-blog.csdnimg.cn/9100f08b5ded409095287e11104f87ff.png#pic_center)
enctype属性值必须是multipart/form-data
		表单form标签里边应该有文件选择框,并且必须有name <input type="file" name="表单参数名"/>
	服务端要接收文件参数:
		要使用MultipartFile类型接收文件数据
	文件的存储:
		可以存储到服务器本地磁盘上
			1. 先重命名文件:
				获取原始文件名:multipartFile.getOriginalFilename()
				截取得到后缀名
				拼接一个随机字符串:UUID.randomUUID().toString() + 文件后缀名
			2. 再把文件保存到磁盘上
				multipartFile.transferTo(new File("文件路径"));
		可以存储到云服务器上,比如阿里云的OSS
			去云平台上注册帐号、开通OSS服务
			在OSS控制台上:创建Bucket
			要把文件上传到OSS:从官方文档里找到上传文件的代码,拷贝改一下就能使用了
4. SpringBoot工程的配置文件
	支持:
		properties文件:语法更简单,但是不方便表示配置参数的层级
		yml或yaml文件:可以表示参数的层级,但是容易出错
    yaml文件语法:
    	每个配置参数也是键值对格式,键值对之间使用 :空格 分隔
    	参数的层级,是通过键值对前边的空格数量。相同数量的空格,表示这些参数属于同一层级
    	参数值:
    		纯量:简单值。
    		数组: - 元素值
    		Map: 子级的键值对
    获取配置文件里某些参数值:
    	@Value("${配置参数名}"),把参数值注入给一个成员变量
    	@ConfigurationProperties(prefix="前缀"),把一批参数封装成一个JavaBean对象
    		1. 创建一个类,类上加@ConfigurationProperties(prefix="前缀"),和@Component
    		2. 类里要有成员变量,并提供get和set方法。要求 前缀+成员变量名 要和 配置参数名 相同

一、登录功能-基本功能实现

需求

用户需要在登录页面上,输入自己的帐号密码后点击“登录”按钮。

如果服务端校验帐号和密码都正确,才允许进入tlias系统页面

如果服务端校验帐号或密码不正确,需要给出错误提示,并不允许跳转到tlias系统功能页面

在这里插入图片描述

分析

在这里插入图片描述

实现

LoginController

package com.itheima.controller;

import com.itheima.pojo.Emp;
import com.itheima.pojo.Result;
import com.itheima.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author liuyp
 * @since 2023/08/23
 */
@RestController
public class LoginController {

    @Autowired
    private EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {
        Emp e = empService.login(emp);
        return e == null ? Result.error("帐号或密码错误") : Result.success();
    }
}

EmpService

Emp login(Emp emp);

EmpServiceImpl

@Override
public Emp login(Emp emp) {
    return empMapper.login(emp);
}

EmpMapper

@Select("select * from emp where username = #{username} and password = #{password}")
Emp login(Emp emp);

二、登录校验-用户身份令牌

1. 功能介绍

虽然我们已经完成了登录功能,但是当用户在登录后对其它功能的访问中,服务端并不知道当是哪个用户帐号在做本次操作,这是不利于系统的权限控制的。

如果想要服务端能够识别每次请求的用户身份,就需要在登录成功后的每次请求中,共享当前用户的身份数据

能够在多次请求中识别用户身份的常用技术有:

  • 传统的会话技术:Cookie和Session。在会话中共同数据的技术,当然可以共享登录的用户帐号
  • 目前流行的技术:JWT令牌。目前比较流行的技术,广泛用于系统中作为身份识别的令牌

2. 会话技术【了解】

会话技术介绍

什么是会话:会话的双方指的是客户端和服务端

  • 当客户端和服务端建立TCP连接开始,一次会话就开始了
  • 在会话过程中,客户端和服务端之间可以有多次请求和响应
  • 当客户端和服务端之间的连接断开,会话就结束了

什么是会话技术:

  • 是在一次会话过程(包含多次请求请求)中,共享数据的一种技术

有哪些会话技术:

  • Cookie技术:客户端的会话技术,数据数据存储到客户端的技术,在一次会话中可以进行共享
  • session技术:服务端的会话技术,数据存储到服务端session对象里,在一次会话中可以进行共享。session依赖于Cookie

会话技术的问题:

  • Cookie的问题:

    • 某些客户端技术默认不支持Cookie,比如APP
    • 客户端,用户可能会禁用Cookie
    • 不能跨域

    在这里插入图片描述

  • session的问题:

    • 服务端集群环境下不能直接使用session技术。如果真要用,还需要解决服务器集群之间的 session同步问题

    在这里插入图片描述

Cookie技术

开启会话:

  • 客户端发请求------------------------------------>服务端:创建Cookie对象,把数据放到Cookie里
  • 客户端得到Cookie<------------------------------服务端:把Cookie对象响应给客户端
  • 客户端后续每次请求,都会携带Cookie---------->服务端:接收Cookie里的数据
  • 客户端后续每次请求,都会携带Cookie---------->服务端:接收Cookie里的数据
  • 客户端浏览器关闭:所有Cookie清空

会话结束

缺点:

  • 客户端每次请求都要携带一些数据,造成一些网络宽带的压力
  • Cookie只有共享字符串类型的数据,不能其它其它数据(比如JavaBean对象)

在这里插入图片描述

Session技术

开启会话:

  • 客户端第一次请求----------------------------------->服务端:创建session对象,把数据存储到session里
  • 客户端得到Cookie(session的id)<--------------------服务端:把session的id放到Cookie里,响应给客户端
  • 客户端后续每次请求携带cookie(session的id)------->服务端:根据session的id找到对应session对象,从中取出数据
  • 客户端后续每次请求携带cookie(session的id)------->服务端:根据session的id找到对应session对象,从中取出数据
  • 关闭浏览器

会话结束:Cookie被清空了

session技术:

  • 可以存储、共享任意类型的数据:字符串、JavaBean对象,任意Java对象都可以
  • 网络负荷减小了:客户端服务端之间只需要传输session的id,不需要传输那么多Cookie对象了
  • 会话之间共享的数据也可以更多:服务端session对象里可以存储任意多个数据,只要JVM内存空间足够

在这里插入图片描述

3. JWT技术【重点】

JWT介绍

JWT:

  • JSON Web Token,json格式的web令牌技术,属于令牌技术的一种。用于解决web开发中的身份识别问题

  • 定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式传输信息。由于数字签名的存在,这些信息是可靠的。

JWT的特性:

  • 可以防篡改。一旦被篡改,服务端可以校验出来的
  • 不能防泄露。任何人得到jwt令牌,都可以从中得到 令牌承载的用户信息

JWT的注意:

  • 生成token时,一定不要往token里放敏感信息。比如用户的密码、手机号等等

在这里插入图片描述

JWT结构

由三部分组成 :

  • Header头:里边放的是令牌的类型、签名算法等等元数据信息。使用Base64Url编码得到的
  • Body载荷:里边放的是用户的身份信息。使用Base64Url编码得到的
  • Signature签名:Header + Body + 密钥字符串,通过签名算法生成签名,用于做防篡改校验

在这里插入图片描述

JWT示例

添加依赖
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
JWT的生成与解析
package com.itheima;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author liuyp
 * @since 2023/08/23
 */
public class DemoJwt {
    public static void main(String[] args) throws InterruptedException {
        //1. 生成JWT令牌
        //1.1 准备载荷信息,即用户的身份信息
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", 1);
        claims.put("username", "tom");
        //1.2 生成JWT令牌
        String token = Jwts.builder()
                //把载荷内容设置到JWT令牌里
                .setClaims(claims)
                //设置令牌的过期时间。这里设置有效期为:截止到当前时间+1000毫秒,即有效期只有1秒(可以根据实际情况自定义有效期)
                .setExpiration(new Date(System.currentTimeMillis() + 1000))
                //设置令牌的密钥。在将来解析令牌时,根据密钥校验令牌的签名,防止令牌被篡改
                .signWith(SignatureAlgorithm.HS256, "itheima")
                //生成令牌
                .compact();

        //token = eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjkyODc4MDE1LCJ1c2VybmFtZSI6InRvbSJ9.VhKA_ghuwKnIcxevdeb6AS0ZMw78WT3zqVQpQOFSvUk
        System.out.println("token = " + token);

        // Thread.sleep(1000);

        //2. 校验与解析令牌:如果令牌过期,会抛出异常;如果令牌被篡改,会抛出异常;如果一切正常,会得到令牌里的载荷内容
        Claims claimsRes = Jwts.parser()
                //设置密钥。用于稍后的令牌签名校验,判断令牌是否被篡改了。如果令牌被篡改,会抛出异常
                .setSigningKey("itheima")
                //校验并解析令牌。如果令牌被篡改或已过期,会抛出异常
                .parseClaimsJws(token)
                //获取令牌载荷内容
                .getBody();
        System.out.println(claimsRes);
    }
}

4. 完善登录功能-生成JWT令牌

只要修改LoginController里的登录方法login即可

package com.itheima.controller;

import com.itheima.pojo.Emp;
import com.itheima.pojo.Result;
import com.itheima.service.EmpService;
import com.itheima.util.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author liuyp
 * @since 2023/08/23
 */
@RestController
public class LoginController {

    @Autowired
    private EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {
        Emp e = empService.login(emp);
        if (e != null) {
            Map<String, Object> claims = new HashMap<>();
            claims.put("id", e.getId());
            claims.put("username", e.getUsername());
            String token = JwtUtils.generateJwt(claims);
            return Result.success(token);
        }
        return Result.error("帐号或密码错误");
    }
}

三、登录校验-登录状态校验

1. 功能介绍

到目前为止,我们已经解决了帐号密码校验、用户身份识别的问题,但是登录功能还缺一部分没有完成:如果没有登录,则不允许对服务端的功能访问,即不允许使用员工管理、部门管理等等功能

这就需要我们能够对客户端的请求进行拦截,然后根据是否登录的状态,再决定是否放行

这样的技术常见的有:

  • JavaEE基础技术提供的-Filter过滤器。一些传统的项目可能使用Filter
  • SpringMVC框架提供的-Interceptor拦截器。如果相对较新的项目,项目里使用了Spring框架,通常都会用Interceptor

常见的使用场景:

  • 过滤敏感词
  • 黑名单过滤
  • 权限控制:没有登录不允许访问

在这里插入图片描述

2. 过滤器Filter

2.1 使用入门

使用步骤
  1. 创建Java类,实现javax.servlet.Filter接口
    • 重写接口的doFilter方法:在方法里编写过滤逻辑,并决定是否要放行
    • 在类上添加注解@WebFilter:标记一下,这个类是过滤器类。如果不加这个注解,过滤器就不生效
  2. 在引导类上添加注解@ServletComponentScan,用于扫描Servlet相关的注解,包括@WebFilter
使用示例
过滤器类Demo01Filter
package com.itheima.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @author liuyp
 * @since 2023/08/23
 */
@WebFilter
public class Demo01Filter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //目标方法执行之前的预处理,根据需求自定义。。。
        System.out.println("拦截器Demo01Filter.doFilter执行了,目标方法执行前...");
        //放行不拦截。如果没有这行代码,就不放行。只有放行了,客户端的请求才能够访问到目标资源
        filterChain.doFilter(servletRequest, servletResponse);
        //目标方法执行之后的后处理,根据需求自定义。。。
        System.out.println("拦截器Demo01Filter.doFilter执行了,目标方法执行后...");
    }
}
引导类

引导类上添加@ServletComponentScan注解

package com.itheima;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
public class TliasWebManagementApplication {
    public static void main(String[] args) {
        SpringApplication.run(TliasWebManagementApplication.class, args);
    }
}
测试效果

打开Postman,访问tlias系统里的任意一个功能,发请求时,查看idea控制台,发现拦截器都执行了

2.2 过滤器详解

执行原理(执行过程)

如果一次请求有多个过滤器可以进行过滤,任意一个过滤器不放行,整个请求就不可能到达目标资源

在这里插入图片描述

拦截范围

在过滤器上使用注解@WebFilter时,可以使用注解的urlPatternsvalue属性,配置过滤器的拦截范围。

  • @WebFilter(urlPatterns = "拦截范围")
  • @WebFilter(value = "拦截范围")
  • @WebFilter("拦截范围")

拦截范围的写法,常用的有:

拦截范围语法示例作用
精确拦截/emps只拦截客户端对/emps的请求
范围拦截/emps/*(必须以/开头以*结尾)拦截客户端对/emps下的资源请求,比如/emps,/emps/1, /emps/xx/yy等等

示例:

package com.itheima.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @author liuyp
 * @since 2023/08/24
 */
@WebFilter(urlPatterns = "/emps/*")
public class Demo01Filter implements Filter {
    /**
     * 这个方法就是过滤器的过滤方法。客户端的每次请求,只要在此过滤器的过滤范围内,这个方法就必定执行
     * @param request  请求对象。它封装了本次http请求的所有数据
     * @param response 响应对象。我们向这个对象里设置数据,这些数据最终会被转换成HTTP响应,返回给客户端
     * @param chain    过滤器链对象。用于放行请求的
     *
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //在目标方法执行之前的预处理
        System.out.println("A");
        //可以放行。只有过滤器放行了,本次请求才可能到达目标资源(Controller里的方法)
        chain.doFilter(request, response);
        //在目标方法执行之后的后处理
        System.out.println("B");
    }
}
多过滤器的过滤顺序(过滤器链)

按照过滤器的全限定类名进行排序。

哪个过滤器排序靠前,哪个过滤器就先执行

2.3 完善登录功能-使用Filter校验登录状态

分析

需要使用过滤器Filter进行拦截。在过滤器里:

  1. 获取本次请求的uri路径。如果是登录:直接放行
  2. 获取本次请求的携带的token。如果获取不到:不放行,给客户端直接返回响应
  3. 校验本次请求的token。如果token非法或过期:不放行,给客户端直接返回响应
  4. 否则:token一切正常,直接放行
添加fastjson依赖

因为稍后我们需要使用到json转换工具:FastJson,所以先把FastJson的依赖坐标添加到pom.xml里

<!--fastJSON-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.76</version>
</dependency>
登录校验校验Filter
package com.itheima.filter;

import com.alibaba.fastjson.JSON;
import com.itheima.pojo.Result;
import com.itheima.util.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author liuyp
 * @since 2023/08/23
 */
@Slf4j
@WebFilter("/*")
public class LoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setContentType("application/json;charset=utf-8");

        //1. 获取本次请求的目标资源路径。如果是登录,就直接放行不拦截
        String uri = request.getRequestURI();
        if ("/login".equals(uri)) {
            log.info("本次请求是登录,直接放行");
            filterChain.doFilter(request, response);
            return;
        }
        //2. 获取本次请求携带的token,并校验
        String token = request.getHeader("token");
        //   2.1 如果token为空:直接返回响应“未登录”
        if (token == null || "".equals(token)) {
            log.warn("本次请求{},没有携带token,不允许访问", uri);
            response.setStatus(401);
            response.getWriter().println(JSON.toJSONString(Result.error("未登录")));
            return;
        }
        //   2.2 如果token非法或过期:直接返回响应“未登录”
        try {
            JwtUtils.parseJWT(token);
        } catch (Exception e) {
            log.warn("本次请求{},携带的token过期或非法,不允许访问", uri);
            response.setStatus(401);
            response.getWriter().println(JSON.toJSONString(Result.error("请重新登录")));
            return;
        }

        //3. 放行
        filterChain.doFilter(request, response);
    }
}
功能测试
  • 请求时不携带token,请求被拦截

在这里插入图片描述

  • 请求时携带了token,没有被拦截,功能正常

在这里插入图片描述

3. 拦截器Interceptor【重点】

是由SpringMVC框架提供的技术

3.1 使用入门

使用步骤
  1. 创建拦截器类:创建Java类,实现HandlerInterceptor接口,重写接口的方法(需要用哪个,就重写哪个):

    • preHandle方法:在目标方法执行前的预处理方法
    • postHandle方法:在目标方法执行成功后的后处理方法
    • afterCompletion方法:在服务端给客户端返回响应之前执行的最终方法
  2. 配置拦截器:

    • 创建Java类,作为Spring的配置类

      添加注解@Configuration,把类标记为Spring的配置类

      实现接口WebMvcConfigurer,作为Web层框架SpringMVC的配置类,必须实现此接口

    • 重写接口的addInterceptors方法

      在方法里配置拦截器

使用示例
拦截器类Demo01Interceptor
package com.itheima.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author liuyp
 * @since 2023/08/23
 */
public class Demo01Interceptor implements HandlerInterceptor {
    /**
     * 预处理方法:在目标方法执行之前先执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Demo01Interceptor.preHandle.....");
        //如果方法返回true,表示放行;如果返回false,表示不放行
        return true;
    }
    
    /**
     * 后处理方法:在目标方法执行之后再执行(目标方法执行成功以后,才会执行)
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Demo01Interceptor.postHandle.....");
    }

    /**
     * 最终处理方法:在给客户端返回响应之前,最终执行(无论目标方法有没有异常,都必定会执行)
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("Demo01Interceptor.afterCompletion.....");
    }
}
配置类WebConfig
package com.itheima.config;

import com.itheima.interceptor.Demo01Interceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author liuyp
 * @since 2023/08/23
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册拦截器,并设置拦截范围为/**,表示拦截所有请求
        registry.addInterceptor(new Demo01Interceptor()).addPathPatterns("/**");
    }
}

3.2 拦截器详解

拦截范围
写法示例作用
拦截一级匹配路径/emp/*只拦截一级目录。拦截/emp/1, /emp/2;不拦截/emp/xx/yy
拦截任意级匹配路径/emp/**拦截任意级目录。拦截/emp,/emp/1, /emp/2/emp/xx/yy/emp/xx/yy/zz
多过滤器的拦截顺序
  1. 先执行所有拦截器的preHandle方法。

    如果任何一个拦截器的preHandle方法返回false,就拦截不放行了

  2. 再执行目标方法

  3. 再执行所有拦截器的postHandle方法。

    只有在目标方法执行后,没有异常时才会执行的

    执行的顺序,和preHandle的顺序是倒着的

  4. 再执行所有拦截器的afterCompletion方法

    无论目标方法有没有异常,都必定会执行的

    执行的顺序,和preHandle的顺序是倒着的

在这里插入图片描述

3.3 完善登录功能-使用Interceptor校验登录状态

拦截器LoginInterceptor
package com.itheima.interceptor;

import com.alibaba.fastjson.JSON;
import com.itheima.pojo.Result;
import com.itheima.util.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author liuyp
 * @since 2023/08/23
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1. 如果本次请求是登录,就直接放行
        String uri = request.getRequestURI();
        if ("/login".equals(uri)) {
            log.info("本次请求是登录,直接放行");
            return true;
        }
        //2. 获取本次请求携带的token
        String token = request.getHeader("token");
        //   如果没有token:直接返回响应结果
        if (!StringUtils.hasText(token)) {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(401);
            response.getWriter().println(JSON.toJSONString(Result.error("未登录")));
            return false;
        }
        //   如果token过期或非法:直接返回响应结果
        try {
            JwtUtils.parseJWT(token);
        } catch (Exception e) {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(401);
            response.getWriter().println(JSON.toJSONString(Result.error("请重新登录")));
            return false;
        }
        //3. 放行
        return true;
    }
}
WebConfig里配置拦截器
package com.itheima.config;

import com.itheima.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author liuyp
 * @since 2023/08/23
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
    }
}
功能测试

四、异常处理

1. 项目中的异常处理方案

项目里遇到异常,通常做一件事:抛

所有异常抛,最终统一由异常处理器进行处理

在这里插入图片描述

2. SpringMVC异常处理器

使用步骤

  1. 创建一个Java类,类上添加注解@RestControllerAdvice。表示这个类是对Controller进行功能增强的
  2. 类里创建一个方法用于处理异常
    • 方法上加注解@ExceptionHandler(异常类名.class)
    • 方法里要加形参:注解里要抓取什么类型的异常,方法就要有什么类型的形参。
    • 方法里要处理异常:
      • 打印异常信息
      • 给客户端返回友好提示

使用示例

package com.itheima.exception;

import com.itheima.pojo.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 类上加的注解@RestControllerAdvice:表示当前类是用于对 Controller类进行功能增强的
 * @author liuyp
 * @since 2023/08/24
 */
@RestControllerAdvice
public class TliasExceptionHandler {

    /**
     * 方法上加@ExceptionHandler(异常类型):表示告诉SpringMVC,这个方法用于抓取什么样的异常进行处理
     * 注解里写的什么类型的异常,方法里就要加什么类型的形参:是抓取到的异常对象
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e){
        //在实际开发中,一旦抓到异常,一定要打印出来。不能把异常吃掉
        e.printStackTrace();
        //给客户端返回一个更友好的结果
        return Result.error("系统正在维护……");
    }
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值