框架笔记 -SpringMVC

SpringMVC

是一个表现层的框架,用于处理与前端的请求和响应

  • @ResponseBody: 可以自动将实体类转换为JSON

REST风格

表现形式状态转换

优点

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
  • 书写简化

在这里插入图片描述

异常处理

常见异常

  • 框架内部抛出的异常: 因使用不合规导致
  • 数据层抛出的异常: 因外部服务器故障导致(例如: 服务器访问超时)
  • 业务层抛出的异常: 因业务逻辑书写错误导致(例如: 遍历业务书写操作,导致索引异常等)
  • 表现层抛出的异常: 因数据收集、校验等规则导致(例如: 不匹配的数据类型间导致异常)
    等规则导致(例如: 不匹配的数据类型间导致异常)
  • 工具类抛出的异常: 因工具类书写不严谨不够健壮导致(例如: 必要释放的连接长期未释放)

解决策略

  • 所有的异常均抛出到表现层进行处理

异常处理器

集中的、统一的处理项目中出现的异常

// 可以根据处理的异常不同,制作多个方法分别处理对应的异常
@RestControllerAdvice	// 设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行
public class ProjectExceptionAdvice {
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex) {
        return new Result(403, null, "捕获到一个异常");	// code, msg
    }
}

项目异常分类

  • 业务异常
    • 规范的用户行为产生的异常
    • 不规范的用户行为操作产生的异常
  • 系统异常
    • 项目运行过程中可预计且无法避免的异常
  • 其他异常
    • 编程人员未预期到的异常
处理方案
  • 业务异常
    • 发送对应消息传递给用户,提醒规范操作
  • 系统异常
    • 发送固定信息传递给用户
    • 发送特定信息给运维人员
    • 记录日志
  • 其他异常
    • 发送固定信息传递给用户
    • 发送特定信息给编程人员(见识到新的异常,记录下来)
    • 记录日志

编写一个自定义的异常类:

public class SystemException extends RuntimeException {
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public SystemException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    public SystemException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }
}

捕获异常

// 抛出异常代码
// throw new SystemException(code, "");	
// code可以使用自己的异常代码类

// 可以根据处理的异常不同,制作多个方法分别处理对应的异常
@RestControllerAdvice	// 设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行
public class ProjectExceptionAdvice {
    @ExceptionHandler(SystemException.class)
    public Result doSystemException(Exception ex) {
        // 记录日志
        // 发送信息给运维
        // 发送消息给开发人员
        return new Rusult(ex.getCode(), null, ex.getMessage());
    }
    
    // 。。。
}

拦截器

Interceptor是一种动态拦截方法调用的机制

作用:

  • 在指定的方法调用前后执行预先设定好的代码
  • 阻止原始方法的执行

拦截器与过滤器的区别

  • 归属不同: Filter属于Servlet技术,Interceptor属于SpringMVC技术
  • 拦截内容不同: Filter对所有访问进行拦截,Interceptor只针对SpringMVC的访问进行增强

使用步骤

  1. 制作拦截器功能类
@Component
public class ProjectInterceptor implements HandlerInterceptor {
    // 表示在原始的拦截之前执行该段代码
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        return true;    // 放行
    }

    // 表示在原始的拦截之后执行该段代码
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }

    // 比原始的拦截之后的代码更后
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}
  1. 制作拦截器的执行位置
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/path");   // 拦截路径可以设置多个
    }
}
  1. 简化开发
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
    // 可以配置多个拦截器,形成拦截器链,运行顺序参照拦截器的添加顺序
    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Autowired
    private ProjectInterceptor2 projectInterceptor2;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置多拦截器
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");
    }
}

过滤器

一个例子,出现的Jwt相关工具类见博文 工具类:

@Component
@Slf4j
public class AuthorizeFilter implements Ordered, GlobalFilter {

    @Override
    public int getOrder() {
        // 值越小 优先级越高
        return 0;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. 通过ServerWebExchange获取request和response
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        // 2. 校验请求url是否包含login 判断是否是登录请求
        // 2.1 如果是登录请求 放行
        if (request.getURI().getPath().contains("/login")) {
            return chain.filter(exchange);
        }

        // 3. 从请求头获取token令牌
        String token = request.getHeaders().getFirst("token");

        // 4. 校验令牌,是否为空 是否正确
        // 4.1 判断令牌是否为空
        if (StringUtils.isBlank(token)) {
            // 返回无权限
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            // 表示请求不再向后端微服务路由
            return response.setComplete();
        }

        // 4.2 判断令牌是否正确
        try {
            Claims claimsBody = AppJwtUtil.getClaimsBody(token);
            int i = AppJwtUtil.verifyToken(claimsBody);
            if (i == 1 || i == 2) {
                // 说明令牌过期 返回401
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }
        } catch (Exception e) {
            // 令牌有错,可能会抛出异常,所以手动捕获
            e.printStackTrace();;
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        // 5. 放行
        return chain.filter(exchange);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值