项目管理与SSM框架 SpringMVC(五)

简介: 项目管理与SSM框架 SpringMVC(五)

六、SpringMVC异常处理

6.1 单个控制器异常处理

在系统当中, Dao、Service、Controller层代码出现都可能抛出异常。如果哪里产生异常就在哪里处理,则会降低开发效率。所以一般情况下我们会让异常向上抛出,最终到达DispatcherServlet中,此时SpringMVC提供了异常处理器进行异常处理,这样可以提高开发效率。

1、处理异常的控制器

//异常处理方法,添加@ExceptionHandler注解表示该方法是处理异常的方法,属性为处理的异常类。
    //Exception:异常对象。Model:数据模型
    @ExceptionHandler(java.lang.NullPointerException.class)
    public String exceptionHandler(Exception exception,Model model){
        //模型中添加异常对象
        model.addAttribute("msg",exception);
        //跳转到异常页面
        return "error";
    }

2、前端异常页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>异常</title>
</head>
<body>
出错了!${requestScope.msg}
</body>
</html>


6.2 全局异常处理

在控制器中定义异常处理方法只能处理该控制器类的异常,要想处理所有控制器的异常,需要定义全局异常处理类。

package com.zj.controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
//全局异常处理器处理所有控制器的异常,需要添加@ControllerAdvice注解
@ControllerAdvice
public class GlobalExceptionHandler {
    //异常处理方法,添加@ExceptionHandler注解表示该方法是处理异常的方法,属性为处理的异常类。
    //Exception:异常对象。Model:数据模型
    @ExceptionHandler(java.lang.NullPointerException.class)
    public String exceptionHandler(Exception exception, Model model){
        //模型中添加异常对象
        model.addAttribute("msg",exception);
        //跳转到异常页面
        return "error";
    }
}

6.3 自定义异常

以上方式都是使用的SpringMVC自带的异常处理器进行异常处理,我们还可以自定义异常处理器处理异常:

package com.zj.controller;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 自定义异常处理器实现HandlerExceptionResolver接口,并放入Spring容器中
@Component
public class MyExceptionHandler implements HandlerExceptionResolver {
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        if (e instanceof NullPointerException) {
            modelAndView.setViewName("error");
        } else {
            modelAndView.setViewName("error2");
        }
        modelAndView.addObject("msg", e);
        return modelAndView;
    }
}

七、SpringMVC拦截器

7.1 拦截器简介

SpringMVC的拦截器(Interceptor)也是AOP思想的一种实现方式。它与Servlet的过滤器(Filter)功能类似,主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。

拦截器和过滤器的区别

  • 拦截器是SpringMVC组件,而过滤器是Servlet组件。
  • 拦截器不依赖Web容器,过滤器依赖Web容器。
  • 拦截器只能对控制器请求起作用(不拦截静态资源),而过滤器则可以对所有的请求起作用。
  • 拦截器可以直接获取IOC容器中的对象,而过滤器就不太方便获取。

7.2 拦截器使用

1、创建控制器方法

@RequestMapping("/m1")
    public String m1(){
        System.out.println("控制器方法");
        return "result";
    }

2、创建拦截器类,该类实现HandlerInterceptor接口,需要重写三个方法:

  • preHandle:请求到达Controller前执行的方法,返回值为true通过拦截器,返回值为false被拦截器拦截。
  • postHandle:跳转到JSP前执行的方法
  • afterCompletion:跳转到JSP后执行的方法
package com.zj.controller;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
    // 请求到达Controller前执行,此时可以向request域添加数据。
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("请求到达Controller之前");
        // 如果return false则无法到达Controller
        return true;
    }
    // 跳转到JSP前执行,此时可以向Request域添加数据
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        request.setAttribute("name","张三");
        System.out.println("请求跳转到JSP前");
    }
    // 跳转到JSP后执行,此时已经不能向Request域添加数据
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("请求跳转到JSP后");
    }
}

3、在SpringMVC核心配置文件中配置拦截器

<!--拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--配置拦截器的作用对象-->
        <mvc:mapping path="/**"/>
        <!--配置拦截器对象-->
       <bean class="com.zj.controller.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

4、JSP页面

<html>
<body>
<h2>Hello, ${requestScope.name}</h2>
</body>
</html>


7.3 全局拦截器

全局拦截器可以拦截所有控制器处理的URL,作用等于/**,配置方式如下:

<!-- 配置拦截器 -->
<mvc:interceptors>  
  <!-- 全局拦截器 -->  
  <bean class="com.zj.interceptor.MyInterceptor">
  </bean>
</mvc:interceptors>

7.4 拦截器链与执行顺序

如果一个URL能够被多个拦截器所拦截,全局拦截器最先执行,其他拦截器根据配置文件中配置的从上到下执行,接下来我们再配置一个拦截器:

<!--拦截器-->
<mvc:interceptors>
    <!--拦截器1-->
    <mvc:interceptor>
        <!--配置拦截器的作用对象-->
        <mvc:mapping path="/**"/>
        <!--配置拦截器对象-->
        <bean class="com.zj.Interceptor.MyInterceptor"/>
    </mvc:interceptor>
    <!--拦截器2-->
    <mvc:interceptor>
        <!--配置拦截器的作用对象-->
        <mvc:mapping path="/**"/>
        <!--配置拦截器对象-->
        <bean class="com.zj.Interceptor.MyInterceptor2"/>
    </mvc:interceptor>
</mvc:interceptors>

结论:

  1. preHandle()顺序执行,postHandle()、afterComletion()逆序执行。
  2. 只要有一个preHandle()拦截,后面的preHandle(),postHandle()都不会执行。
  3. 只要相应的preHandle()放行,afterComletion()就会执行。

7.5 拦截器过滤敏感词案例

在系统中,我们需要将所有响应中的一些敏感词替换为***,此时可以使用拦截器达到要求:

1、写控制器方法

@RequestMapping("/m2")
public String m2(Model model){
  model.addAttribute("name","大笨蛋");
  return "index";
}

2、编写敏感词拦截器

package com.zj.Interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.Set;
// 敏感词拦截器
public class SensitiveWordInterceptor implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws UnsupportedEncodingException {
    request.setCharacterEncoding("UTF-8");
    response.setContentType("text/plain;charset=UTF-8");
      return true;
   }
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    // 敏感词列表
    String[] sensitiveWords = {"坏人","暴力","笨蛋"};
    // 获取model中所有数据
    Map<String, Object> model = modelAndView.getModel();
    Set<Map.Entry<String, Object>> entries = model.entrySet();
    // 遍历model
    for (Map.Entry<String, Object> entry : entries) {
      String key = entry.getKey();
      String value = entry.getValue().toString();
      // 将model值和敏感词列表遍历比对
      for (String sensitiveWord : sensitiveWords) {
        // 如果model值包含敏感词,则替换
        if(value.contains(sensitiveWord)){
          String newStr = value.replaceAll(sensitiveWord, "**");
          model.put(key, newStr);
         }
       }
     }
   }
}

3、配置拦截器

<!-- 配置拦截器-->
<mvc:interceptors>
  <!-- 敏感词拦截器 -->
  <mvc:interceptor>
    <mvc:mapping path="/**"/>
    <bean class="com.zj.interceptor.SensitiveWordInterceptor"></bean>
  </mvc:interceptor>
</mvc:interceptors>

4、访问


八、SpringMVC跨域请求

8.1 同源策略

同源策略是浏览器的一个安全功能。同源,指的是两个URL的协议,域名,端口相同。浏览器出于安全方面的考虑,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。

哪些不受同源策略限制:

  1. 页面中的<a>跳转、表单提交不会受到同源策略限制的。
  2. 静态资源引入也不会受到同源策略限制。如嵌入到页面中的<script src=""><img src=""><link href="">等。

最容易收到同源策略影响的就是Ajax请求。

8.2 跨域请求

当请求URL的协议、域名、端口三者中任意一个与当前页面URL不同时即为跨域。浏览器执行JavaScript脚本时,会检查当前请求是否同源,如果不是同源资源,就不会被执行。

当前页面URL 被请求页面URL 是否跨域 原因
http://www.baidu.com/ http://www.baidu.com/index.html
http://www.baidu.com/ https://www.baidu.com/index.html 跨域 协议不同
http://www.baidu.com/ http://www.jd.com/ 跨域 主域名不同
http://www.baidu.com/ http://jd.jd.com/ 跨域 子域名不同
http://www.baidu.com:8080/ http://www.baidu.com:7001/ 跨域 端口号不同

8.3 控制器接收跨域请求

SpringMVC提供了注解@CrossOrigin解决跨域问题。用法如下:

@RequestMapping("/m3")
@ResponseBody
// 如果请求从http://localhost:8080发出,则允许跨域访问
@CrossOrigin("http://localhost:8080")
public String m3(){
  System.out.println("测试跨域请求");
  return "success";
}


相关文章
|
5月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
12月前
|
前端开发 Java 测试技术
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestParam
本文介绍了 `@RequestParam` 注解的使用方法及其与 `@PathVariable` 的区别。`@RequestParam` 用于从请求中获取参数值(如 GET 请求的 URL 参数或 POST 请求的表单数据),而 `@PathVariable` 用于从 URL 模板中提取参数。文章通过示例代码详细说明了 `@RequestParam` 的常用属性,如 `required` 和 `defaultValue`,并展示了如何用实体类封装大量表单参数以简化处理流程。最后,结合 Postman 测试工具验证了接口的功能。
678 0
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestParam
|
12月前
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestBody
`@RequestBody` 是 Spring 框架中的注解,用于将 HTTP 请求体中的 JSON 数据自动映射为 Java 对象。例如,前端通过 POST 请求发送包含 `username` 和 `password` 的 JSON 数据,后端可通过带有 `@RequestBody` 注解的方法参数接收并处理。此注解适用于传递复杂对象的场景,简化了数据解析过程。与表单提交不同,它主要用于接收 JSON 格式的实体数据。
1288 0
|
12月前
|
前端开发 Java 微服务
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@PathVariable
`@PathVariable` 是 Spring Boot 中用于从 URL 中提取参数的注解,支持 RESTful 风格接口开发。例如,通过 `@GetMapping(&quot;/user/{id}&quot;)` 可以将 URL 中的 `{id}` 参数自动映射到方法参数中。若参数名不一致,可通过 `@PathVariable(&quot;自定义名&quot;)` 指定绑定关系。此外,还支持多参数占位符,如 `/user/{id}/{name}`,分别映射到方法中的多个参数。运行项目后,访问指定 URL 即可验证参数是否正确接收。
759 0
|
12月前
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestMapping
@RequestMapping 是 Spring MVC 中用于请求地址映射的注解,可作用于类或方法上。类级别定义控制器父路径,方法级别进一步指定处理逻辑。常用属性包括 value(请求地址)、method(请求类型,如 GET/POST 等,默认 GET)和 produces(返回内容类型)。例如:`@RequestMapping(value = &quot;/test&quot;, produces = &quot;application/json; charset=UTF-8&quot;)`。此外,针对不同请求方式还有简化注解,如 @GetMapping、@PostMapping 等。
679 0
|
12月前
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RestController
本文主要介绍 Spring Boot 中 MVC 开发常用的几个注解及其使用方式,包括 `@RestController`、`@RequestMapping`、`@PathVariable`、`@RequestParam` 和 `@RequestBody`。其中重点讲解了 `@RestController` 注解的构成与特点:它是 `@Controller` 和 `@ResponseBody` 的结合体,适用于返回 JSON 数据的场景。文章还指出,在需要模板渲染(如 Thymeleaf)而非前后端分离的情况下,应使用 `@Controller` 而非 `@RestController`
479 0
|
8月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
571 0
|
8月前
|
SQL Java 数据库连接
2-SSM框架篇
Spring框架核心知识点总结,涵盖IOC、DI、Bean作用域、事务管理、AOP、Spring MVC流程及MyBatis相关问题。内容包括控制反转与依赖注入原理、Bean生命周期与线程安全、事务传播机制、JDK与CGLIB代理区别、MyBatis动态SQL与缓存机制等高频面试题。
149 0
|
8月前
|
SQL Java 数据库连接
Spring、SpringMVC 与 MyBatis 核心知识点解析
我梳理的这些内容,涵盖了 Spring、SpringMVC 和 MyBatis 的核心知识点。 在 Spring 中,我了解到 IOC 是控制反转,把对象控制权交容器;DI 是依赖注入,有三种实现方式。Bean 有五种作用域,单例 bean 的线程安全问题及自动装配方式也清晰了。事务基于数据库和 AOP,有失效场景和七种传播行为。AOP 是面向切面编程,动态代理有 JDK 和 CGLIB 两种。 SpringMVC 的 11 步执行流程我烂熟于心,还有那些常用注解的用法。 MyBatis 里,#{} 和 ${} 的区别很关键,获取主键、处理字段与属性名不匹配的方法也掌握了。多表查询、动态
234 0
|
8月前
|
JSON 前端开发 Java
第05课:Spring Boot中的MVC支持
第05课:Spring Boot中的MVC支持
347 0