SpringMVC进阶-异常拦截器文件上传和Restful风格(1)

简介: SpringMVC进阶-异常拦截器文件上传和Restful风格(1)

案例需要的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>springmvc021</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>
  <dependencies>
    <!--jackson-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>
    <!-- servlet3.1规范的坐标 -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!--jsp坐标-->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>
    <!--spring的坐标-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.6.RELEASE</version>
    </dependency>
    <!--spring web的坐标-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.6.RELEASE</version>
    </dependency>
    <!--springmvc的坐标-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.6.RELEASE</version>
    </dependency>
    <!--Lombok-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.6</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <!--jdk编译插件-->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>utf-8</encoding>
        </configuration>
      </plugin>
      <!--tomcat插件-->
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <!-- tomcat7的插件, 不同tomcat版本这个也不一样 -->
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.1</version>
        <configuration>
          <!-- 通过maven tomcat7:run运行项目时,访问项目的端口号 -->
          <port>80</port>
          <!-- 项目虚拟路径  如果配置的aa, 则访问路径为localhost:8080/aa-->
          <path>/</path>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

1 异步调用

20201209195343601.png

1.1 发送异步请求

前端index.jsp代码

两个注意事项

1.前端需要通过contentType告诉后端是JSON数据,并且数据在请求体中

2.前端需要把数据转换成字符串再发送

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <button id="btn1">点击发送请求</button>
    <script>
        $(function () {
            $("#btn1").on('click',function () {
                var users = [
                    {
                        name:"jack",
                        age:34
                    },
                    {
                        name:"tom",
                        age:32
                    },{
                        name:"张三",
                        age:3
                    }
                ];
                $.ajax({
                    type:"post",
                    url:"/user/ajax",
                    data:JSON.stringify(users),//把对象转字符串
                    contentType:"application/json",//用json,text后端封装复杂数据会失败报415,自行测试
                    success:function (data) {
                        console.log(data)
                    }
                });
            });
        });
    </script>
</body>
</html>

java代码

package cn.oldlu.controller;
import cn.oldlu.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/ajax")
    @ResponseBody
    public Map<Object, Object> ajax(@RequestBody List<User> users){
        System.out.println(users);
        //不要直接返回字符串,返回对象,测试前端success接收到的是字符串还是对象
        HashMap<Object, Object> map = new HashMap<>();
        map.put("status","success");
        return map;
    }
}

20201209100712394.png

20201209233452559.png

2 异步请求-跨域访问

2.1 跨域访问介绍

  • 当通过域名A下的操作访问域名B下的资源时,称为跨域访问
  • 跨域访问时,会出现无法访问的现象

3b1d74e68d5acd02aeeb8d8c3b293c2f.png

2.2 跨域环境搭建

当前电脑启动两台服务器会比较麻烦。

可以为当前电脑设置两个host域名,访问页面用A域名,页面访问后台用B域名

修改C:\Windows\System32\drivers\etc 目录下的 host文件,将该文件拷贝到其他盘,修改后替换原文件即可

添加如下内容

127.0.0.1       a.com
127.0.0.1       b.com

前端index.jsp代码 修改访问的服务的地址

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <button id="btn1">点击发送请求</button>
    <script>
        $(function () {
            $("#btn1").on('click',function () {
                var users = [
                    {
                        name:"jack",
                        age:34
                    },
                    {
                        name:"tom",
                        age:32
                    },{
                        name:"张三",
                        age:3
                    }
                ];
                $.ajax({
                    type:"post",
                    url:"http://b.com/user/ajax",//修改此处!!!!!!
                    data:JSON.stringify(users),//把对象转字符串
                    contentType:"application/json",//用json,text后端封装复杂数据会失败报415,自行测试
                    success:function (data) {
                        console.log(data)
                    }
                });
            });
        });
    </script>
</body>
</html>

在浏览器中访问a.com ,因为要发请求给http://b.com服务器,所以会报跨域错误

6d7f9eed72d0d52e8e09612200774f17.png

2.3 跨域访问支持

在接口所在的方法或者类上加@CrossOrigin注解

//使用@CrossOrigin开启跨域访问
//标注在处理器方法上方表示该方法支持跨域访问
//标注在处理器类上方表示该处理器类中的所有处理器方法均支持跨域访问
package cn.oldlu.controller;
import cn.oldlu.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/user")
@CrossOrigin
public class UserController {
    @RequestMapping("/ajax")
    @ResponseBody
    public Map<Object, Object> ajax(@RequestBody List<User> users){
        System.out.println(users);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("status","success");
        return map;
    }
}

20201209195226766.png

3 拦截器

3.1 拦截器Interceptor

请求处理过程解析

6469f34f10e5f98a8a929c73489c2bdc.png

概念和作用

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

作用

1.在指定的方法调用前后执行预先设定后的的代码

2.阻止原始方法的执行

核心原理:AOP思想

拦截器链:多个拦截器按照一定的顺序,对原始被调用功能进行增强

拦截器VS过滤器

归属不同: Filter属于Servlet技术, Interceptor属于SpringMVC技术

拦截内容不同: Filter对所有访问进行增强, Interceptor仅针对SpringMVC的访问进行增强

3b0f7331aa0c08c84a9a547b93dbbdfc.png

3.2 自定义拦截器开发过程

第一步:实现HandlerInterceptor接口

//自定义拦截器需要实现HandleInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
    //处理器运行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("前置运行----a1");
        //返回值为false将拦截原始处理器的运行
        //如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行
        return true;
    }
    //处理器运行之后执行
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("后置运行----b1");
    }
    //所有拦截器的后置执行全部结束后,执行该操作
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        System.out.println("完成运行----c1");
    }
    //三个方法的运行顺序为    preHandle -> postHandle -> afterCompletion
    //如果preHandle返回值为false,三个方法仅运行preHandle
}

第二步:配置拦截器

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/showPage"/>
        <bean class="com.itheima.interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

注意:配置顺序为先配置执行位置,后配置执行类

3.3 拦截器执行流程

a6c1569947392efac699448f2a46481a.png

3.4 拦截器配置与方法参数

3.4.1 前置处理方法

原始方法之前运行

public boolean preHandle(HttpServletRequest request,
                         HttpServletResponse response,
                         Object handler) throws Exception {
    System.out.println("preHandle");
    return true;
}

参数

request:请求对象

response:响应对象

  • handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装
  • 返回值
    返回值为false,被拦截的处理器将不执行

3.4.2 后置处理方法

原始方法运行后运行,如果原始方法被拦截,则不执行

public void postHandle(HttpServletRequest request,
                       HttpServletResponse response,
                       Object handler,
                       ModelAndView modelAndView) throws Exception {
    System.out.println("postHandle");
}

参数

modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整

3.4.3 完成处理方法

拦截器最后执行的方法,无论原始方法是否执行

public void afterCompletion(HttpServletRequest request,
                            HttpServletResponse response,
                            Object handler,
                            Exception ex) throws Exception {
    System.out.println("afterCompletion");
}

参数

ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

3.5 拦截器配置项

<mvc:interceptors>
    <!--开启具体的拦截器的使用,可以配置多个-->
    <mvc:interceptor>
        <!--设置拦截器的拦截路径,支持*通配-->
        <!--/**         表示拦截所有映射-->
        <!--/*          表示拦截所有/开头的映射-->
        <!--/user/*     表示拦截所有/user/开头的映射-->
        <!--/user/add*  表示拦截所有/user/开头,且具体映射名称以add开头的映射-->
        <!--/user/*All  表示拦截所有/user/开头,且具体映射名称以All结尾的映射-->
        <mvc:mapping path="/*"/>
        <mvc:mapping path="/**"/>
        <mvc:mapping path="/handleRun*"/>
        <!--设置拦截排除的路径,配置/**或/*,达到快速配置的目的-->
        <mvc:exclude-mapping path="/b*"/>
        <!--指定具体的拦截器类-->
        <bean class="MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

f59be1dac074b49ee536e87000bf9eae.png

责任链模式

责任链模式是一种行为模式

特征:着一条预先设定的任务链顺序执行,每个节点具有独立的工作任务

优势:

独立性:只关注当前节点的任务,对其他任务直接放行到下一节点

隔离性:具备链式传递特征,无需知晓整体链路结构,只需等待请求到达后进行处理即可

灵活性:可以任意修改链路结构动态新增或删减整体链路责任

解耦:将动态任务与原始任务解耦

弊端:

链路过长时,处理效率低下

可能存在节点上的循环引用现象,造成死循环,导致系统崩溃

4 异常处理

20201209195532472.png

系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理,如下图:

ac11b5bb2301718d83118456d357a351.png

4.0 异常处理的方式

方式1(了解)

e1648d2dc51eeb134bc2396e21791098.png

方式2(XML了解)

第一步 创建异常处理器类实现HandlerExceptionResolver

efd8c80162b97daffa9037017b80bb30.png

第二步 编写异常页面error.jsp

48f2b811498506b9f8bd87054b9de5bd.png

第三步:把自定义异常处理类注册到springmvc框架中

97b16d035bd851a8ca233a4ca028af06.png

第四步:控制器中编写会发生异常的代码

fe02d5eb1a06caeb5bfb7182e9471e91.png

测试异常跳转

ef0293e623294e90275225d2e4446716.png

方式3(注解)掌握

package cn.oldlu.exception;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ControllerAdvice
public class ExceptionAdvice {
    //该注解中设置要捕获的异常的类型,当前方法中编写异常的处理方式
    @ExceptionHandler(RuntimeException.class)
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/error.jsp");
        modelAndView.addObject("msg","系统出错");
        return modelAndView;
    }

f351b34f72d590bd2b106d95e9e25de7.png

4.2 自定义异常

c62040669eb1e825288b9a2ae4ec0b5d.png

//自定义异常继承RuntimeException,覆盖父类所有的构造方法
public class BusinessException extends RuntimeException {
    public BusinessException() {
    }
    public BusinessException(String message) {
        super(message);
    }
    public BusinessException(String message, Throwable cause) {
        super(message, cause);
    }
    public BusinessException(Throwable cause) {
        super(cause);
    }
    public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

异常触发方式

if(user.getName().trim().length()<4) {
    throw new BusinessException("用户名长度必须在2-4位之间,请重新输入! ");
}
  • 通过自定义异常将所有的异常现象进行分类管理,以统一的格式对外呈现异常消息


相关实践学习
基于函数计算快速搭建Hexo博客系统
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
目录
相关文章
|
3月前
|
前端开发 JavaScript
[SpringMVC]restful风格
[SpringMVC]restful风格
38 1
[SpringMVC]restful风格
|
4月前
|
前端开发 Java Apache
JAVAEE框架技术之6-springMVC拦截器和文件上传功能
JAVAEE框架技术之6-springMVC拦截器和文件上传功能
71 0
JAVAEE框架技术之6-springMVC拦截器和文件上传功能
|
6天前
|
XML JSON 数据库
SpringMVC RESTful
SpringMVC RESTful
13 0
|
3月前
|
XML JSON Java
基于springMVC的RESTful服务实现
  RESTful(RESTful Web Services)一种架构风格,表述性状态转移,它不是一个软件,也不是一个标准,而是一种思想,不依赖于任何通信协议,但是开发时要成功映射到某协议时也需要遵循其标准,但不包含对通信协议的更改
24 1
|
4月前
|
前端开发 Java 应用服务中间件
SpringMvc拦截器和手写模拟SpringMvc工作流程源码详解
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分。 M: Model,模型层,指工程中的JavaBean,作用是处理数据。 JavaBean分为两类: 1.实体类Bean:专门存储业务数据的,如Student User等 2.业务处理Bean:指Service或Dao对象,专门用于处理业务逻辑和数据访问。
|
4月前
|
XML JSON 前端开发
SpringMVC之视图和RESTful
【1月更文挑战第19天】 一、SpringMVC的视图 1、ThymeleafView 2、转发视图 3、重定向视图 4、视图控制器view-controller 二、RESTful 1、RESTful简介 a>资源 b>资源的表述 c>状态转移 2、RESTful的实现 3、HiddenHttpMethodFilter
60 0
|
4月前
|
XML JSON 数据库
SpringMVC之RESTful(含实际代码操作)
SpringMVC之RESTful(含实际代码操作)
|
5月前
|
前端开发 Java 数据库连接
【1024程序员节】RestFul,mvc拦截器,SSM基本整合-学习笔记
【1024程序员节】RestFul,mvc拦截器,SSM基本整合-学习笔记
52 1
|
5月前
|
前端开发 JavaScript Java
Spring Boot中Spring MVC的基本配置讲解与实战(包括静态资源配置,拦截器配置,文件上传配置及实战 附源码)
Spring Boot中Spring MVC的基本配置讲解与实战(包括静态资源配置,拦截器配置,文件上传配置及实战 附源码)
53 1
|
5月前
|
XML JSON Java
SpringMVC原理分析 | Controller配置、RestFul风格
SpringMVC原理分析 | Controller配置、RestFul风格
31 0