1.4W字!让我带你读懂springmvc的世界!

这篇具有很好参考价值的文章主要介绍了1.4W字!让我带你读懂springmvc的世界!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一.前提了解

1.tomcat和servlet的关系?

2.springmvc想要实现web开发必须满足的条件是什么?

二.什么是SpringMVC

三.基于SpringMVC创建web项目

①创建项目并选择依赖

 ②设置热部署(部分代码改动不需要手动重新run即可生效)

四.理解前后端分离的开发过程

五.SpringMVC实现web开发

1.详解用户端返回的响应

@Controller

@ResponseBody

重定向和转发

转发

重定向

转发和重定向的区别:(M)

自定义返回类型

@RestController

@RequestMapping

 2.详解服务端接收用户端的请求

2.1关于请求路径和请求头中的参数

@Pathvirable

使用postman对测试结果进行分析:

@RequestHeader

@CookieValue

@SessionAttribute

2.2关于请求参数

无注解的请求参数

@RequestParam

@RequestPart

@RequestBody

通过配置类设置编程式的配置方案

设置后端路径的统一前缀

设置拦截器

统一异常处理

统一的结果处理:

关于responseBodyAdvice的作用


一.前提了解

在我们真正的去讲述springmvc之前,我们先明确以下两个问题:

1.tomcat和servlet的关系?

我们都知道,servlet是实现动态页面的技术,servlet是进行web开发的规范,而tomcat是servlet容器,它在符合servlet规范的基础上对外提供了web服务器和端口号,实现对servlet的统一管理;同时可以接收用用户的请求,将请求发送给servlet,并在servlet给出响应之后将响应发送给客户端

2.springmvc想要实现web开发必须满足的条件是什么?

通过上面的论述,我们能清晰理解的是,tomcat满足了servlet规范,并在此基础上进行了web开发,springmvc如果想要实现web开发,也必须满足servlet规范。

二.什么是SpringMVC

SpringMVC是进行web开发的框架,它同样依托于springboot框架(springboot内包含了springmvc),受益于springboot框架中约定大于配置的原则,springboot内部默认配置了springmvc的文件路径,并对springmvc进行了很多默认的配置(不需要用户自己手动配置),springmvc内置了满足servlet规范的web服务器(相当于定制化的服务器)(对servlet进行了进一步的封装),而如果我们想要使用springmvc进行web开发,只需要满足springmvc的使用规范即可。

使用springmvc进行web开发的目的也很明了:使web开发更方便,提高web开发的效率

三.基于SpringMVC创建web项目

①创建项目并选择依赖

1.4W字!让我带你读懂springmvc的世界!

1.4W字!让我带你读懂springmvc的世界!

1.4W字!让我带你读懂springmvc的世界!

 ②设置热部署(部分代码改动不需要手动重新run即可生效)

1.4W字!让我带你读懂springmvc的世界!

 1.4W字!让我带你读懂springmvc的世界!

③禁用JMX:因为如果不对其进行排除会导致在项目启动时报错,虽然这个报错不影响我们项目的实现,但是规范化起见,我们还是加上

1.4W字!让我带你读懂springmvc的世界!

 ④禁用tomcat,取而代之undertow(非必须选项,换是因为undertow的效率略高于tomcat)

1.4W字!让我带你读懂springmvc的世界!

⑤修改编码集

1.4W字!让我带你读懂springmvc的世界!

1.4W字!让我带你读懂springmvc的世界!

四.理解前后端分离的开发过程

springMVC 的MVC 是由以下三部分组成:①Model (模型)②View(视图) ③ Controller(控制器) 

我们结合web请求和响应的过程来理解开发过程和springmc的三个组成部分:

1.4W字!让我带你读懂springmvc的世界!

用户发送http请求,通过controller层结合model层分析请求信息并给出响应响应,将响应的数据返回给view层,最后通过view层给出http响应 。

结合具体的放方法对此进行分析:

1.4W字!让我带你读懂springmvc的世界!

1.4W字!让我带你读懂springmvc的世界!

事实上专业的逻辑应该是这样的:
 

处理流程
DispatcherServlet 的处理流程可以分为以下几个步骤:

接收客户端请求
        当客户端发送请求时,DispatcherServlet 会接收并处理该请求。接收请求的方式取决于 DispatcherServlet 的配置,通常情况下,它会将请求映射到一个 URL,然后监听该 URL 的请求。

创建请求对象
        DispatcherServlet 会根据客户端请求创建一个请求对象,该对象中包含了客户端请求的所有信息,例如请求方法、请求头、请求参数等。

处理请求映射
DispatcherServlet 会将请求映射到相应的控制器进行处理。请求映射是通过 HandlerMapping 进行的,HandlerMapping 负责将请求映射到一个或多个控制器,以便选择最合适的控制器进行处理。

调用控制器
        DispatcherServlet 会调用相应的控制器进行处理,控制器会根据请求参数和业务逻辑进行相应的处理,并返回一个 ModelAndView 对象。

渲染视图
        DispatcherServlet 会将 ModelAndView 对象传递给视图解析器(ViewResolver),视图解析器会根据 ModelAndView 中的视图名称来解析相应的视图对象。然后,DispatcherServlet 将模型数据传递给视图对象,以便渲染视图。最终,视图对象会生成相应的响应结果并返回给客户端。

 

五.SpringMVC实现web开发

1.详解用户端返回的响应

@Controller

@controller表示被这个注解修饰的类是一个bean(一般只能用来修饰类),并且这个bean负责处理web请求和响应

@ResponseBody

@ResponseBody表示响应正文,即规定返回值的类型(既可以修饰类,又可以修饰方法,修饰类代表所有的方法都设置返回值类型,修饰方法代表只有这个方法规定好返回值的类型),@ResponseBody规定被其修饰的方法的返回值以特定的数据格式进行返回,默认的返回形式是json

重定向和转发

如果没有使用@ResponseBody来规定好返回值类型的格式,的默认的返回值类型是String,并且代表一个路径:这个路径一般分为两种应用场景:转发和重定向

转发

语法格式:forward:/+路径

1.4W字!让我带你读懂springmvc的世界!

抓包查看特征:

①只有一次请求和响应 响应的资源是一个html页面

1.4W字!让我带你读懂springmvc的世界!

1.4W字!让我带你读懂springmvc的世界!

 1.4W字!让我带你读懂springmvc的世界!

重定向

语法格式:"redirect:/+路径”

抓包查看特征:

1.4W字!让我带你读懂springmvc的世界!

第一次请求: 

1.4W字!让我带你读懂springmvc的世界! 第一次响应:

1.4W字!让我带你读懂springmvc的世界!

第二次请求:

1.4W字!让我带你读懂springmvc的世界!

第二次响应:

1.4W字!让我带你读懂springmvc的世界!

转发和重定向的区别:(M)

1.重定向访问服务器两次,转发只访问服务器一次。

2.转发页面的URL不会改变,而重定向地址会改变

3.转发只能转发到自己的web应用内,重定向可以重定义到任意资源路径。

4.转发相当于服务器跳转,相当于方法调用,在执行当前文件的过程中转向执行目标文件,两个文件(当前文件和目标文件)属于同一次请求,前后页 共用一个request,可以通过此来传递一些数据或者session信息,request.setAttribute()和 request.getAttribute()。而重定向会产生一个新的request,不能共享request域信息与请求参数

5.由于转发相当于服务器内部方法调用,所以转发后面的代码仍然会执行(转发之后记得return);重定向代码执行之后是方法执行完成之后进行重定向操作,也就是访问第二个请求,如果是方法的最后一行进行重定向那就会马上进行重定向(重定向也需要return)。
 

自定义返回类型

除了使用@ResponseBody设置返回值类型和进行转发和重定向之外,还能实现自定义的返回值类型,操作如下:

我们举一个例子来进行说明:我们传输给客户端一个.doc对象(网络资源下载)

1.创建文件路径对象

2.读取路径中的字节数组

3.设置自定义的返回对象

@Controller
public class SelfController {
    @GetMapping("/object1")
    public ResponseEntity test() throws IOException {
        //创建返回值
        //传输字节码文件
        Path p=new File("D:\\大物实验报告\\42109211014_20221018142451.doc").toPath();
        byte[]bytes= Files.readAllBytes(p);
      return   ResponseEntity.ok().header("content-type", "application/msword").body(bytes);
    }
}

我们使用路径进行访问

1.4W字!让我带你读懂springmvc的世界!

@RestController

我们暂且可以将其作用简单理解为:@Controller和@Responsebody的组合注解

使用方法:加载类前面

1.4W字!让我带你读懂springmvc的世界!

@RequestMapping

@RequestMapping代表请求路径,该注解既可以加到类上,也能加到方法上如果类上和方法上同时加了这个注解,则请求路径表示为:类路径+方法路径

使用方法:

1.4W字!让我带你读懂springmvc的世界!

部分属性:

●value:定义request请求的映射地址

●method:定义地request址请求的方式,包括【GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.】默认接受get请求,如果请求方式和定义的方式不一样则请求无法成功。

●params:定义request请求中必须包含的参数值。

 2.详解服务端接收用户端的请求

2.1关于请求路径和请求头中的参数

@Pathvirable

使用方式:用于修饰形参

@Pathvirable 作用:标识请求路径中的动态参数(从使用@RequestMapping中请求路径中读取被@Pathvirable 修饰的方法形参变量名一致的变量,将其读取至方法中相同变量名的形参变量中。)

代码演示:

@RestController
public class PathTest {
    @RequestMapping("/test/{id}")
    public Object test(@PathVariable Long id){
        //创建容器
        HashMap<String, Long> stringLongHashMap = new HashMap<>();
        stringLongHashMap.put("id", id);
        return  stringLongHashMap;
    }

使用postman对测试结果进行分析:

1.4W字!让我带你读懂springmvc的世界!

 @pathvirable修饰的变量类型可以对请求路径传来的变量进行校验,如果请求路径中的参数和参数的类型不符,会报400错误

1.4W字!让我带你读懂springmvc的世界!

@RequestHeader

作用:通过绑定请求头中的字段名,获取请求头的字段信息

使用示例:

   @RequestMapping("/header")
    public Object getHeader(@RequestHeader("user-agent") String headers){
        HashMap<String, String> stringLongHashMap = new HashMap<>();
        stringLongHashMap.put("user-agent", headers);
        return  stringLongHashMap;
    }

1.4W字!让我带你读懂springmvc的世界!

@CookieValue

作用:通过绑定cookie中的键名,获取cookie中的信息

使用方式:

    @RequestMapping("/cookie")
    public Object getCookie(@CookieValue("JSESSIONID") String cookie){
        HashMap<String, String> stringLongHashMap = new HashMap<>();
        stringLongHashMap.put("my-cookie", cookie);
        return  stringLongHashMap;

1.4W字!让我带你读懂springmvc的世界!

1.4W字!让我带你读懂springmvc的世界!

@SessionAttribute

在讲解这个之前,我们先简要说一下cookie和session之间的关系:session保存在服务端,服务端用它来保存用户信息,我们可以将session理解为键值对,键为随机生成的sessionId,值为当前用户的session对象;cookie保存到客户端,也是用来保存用户信息,再校验用户信息时根据sessionId在服务端匹配对应的sessoin对象,进行身份校验

@SessionAttribute用来处获取请求参数中的session信息(根据sessionId在服务端获取session对象,之后进行校验用户信息)

使用实例:
 

 @RequestMapping("/login")
    public Object info(HttpServletRequest request){
        //通过session存储session信息
        HttpSession session = request.getSession(true);
        //存储session信息
        session.setAttribute("user", "zhangsan");
        //创建容器并返回
        HashMap<String, String> map = new HashMap<>();
        map.put("user", "zhangsan");
        return map;
    }
    @RequestMapping("/check")
    public Object checkLogin(@SessionAttribute("user") String name){
        HashMap<String, String> map = new HashMap<>();
        map.put("user", name);
        return map;
    }

一般在进行登录校验时的大体流程如下:

首次登录时检查session对象是否存在(不存在则新创建一个session对象),之后根据前端传来的用户信息对其进行存储,返回响应,之后如果再进行其他操作(需要在用户登录的基础上)则需要根据sessionId从服务器中获取session对象进行校验

结果分析:
1.4W字!让我带你读懂springmvc的世界!

1.4W字!让我带你读懂springmvc的世界!

2.2关于请求参数

无注解的请求参数

 前端的请求参数通常分为四种数据格式进行传输:query-string ,表单类型的数据、json格式的数据和form-data类型的数据,而我们后端接收请求的java对象,我们将其分为简单数据类型(基本数据类型+包装类+String)和复杂数据类型(集合框架和自定义的类型),以下我们将从这两种数据类型进行分析;
我们先给出结论:无论是简单数据类型还是复杂数据类型,在没有注解的情况下后端能进行数据解析的只有query-string ,表单类型的数据、json格的数据,json类型的数据需要使用注解(@RequestBody),我们根据这个画一个表格对此进行说明:

1.4W字!让我带你读懂springmvc的世界!

我们分别对这几种前端数据类型进行分析:
 

@RequestParam

@RequestParam(能修饰除json之外的其他类型,还可以修饰map 、list等集合)

参数:vlaue/name:用来标识请求参数的名称(请求路径中请求参数的名称),这个参数也可以不传,只要保证方法中的参数和请求路径参数完全一致即可

required:这个参数在请求参数中是否必须提供:FALSE代表不是必须提供,TRUE代表必须提供

参数类型类型不匹配或者要求必须提供的参数没有提供会报400错误

作用:将请求参数转化为控制器方法的形参

使用实例:
 

@RequestMapping("/requestB")
    public Object res(@RequestParam String name ,@RequestParam() Integer id){
        HashMap<String, String> map = new HashMap<>();
        map.put("name", name);
        map.put("id", id+"");
        return map;
    }

1.4W字!让我带你读懂springmvc的世界!

@RequestPart

@RequestPart一般用于用于将multipart/form-data类型数据映射到控制器处理方法的参数中

注解解析

  ① value:

    绑定的参数名称,参数值为String类型。

  ② name:

    绑定的参数名称,参数值为String类型。name和value可以同时使用,但两者的值需一致,否则会出现错误。(400)
  ③ required:

    请求头中是否必须包含指定的值,默认值为true。

    required为true时,如果请求头中缺少指定的值,则会抛出异常。

    required为false时,如果请求头中缺少指定的值,则会返回null。

使用用例:

1.4W字!让我带你读懂springmvc的世界!

    @RequestMapping("/upload")
    //上传文件
    public Object upload(@RequestPart MultipartFile head, User user) throws IOException {
       head.transferTo(new File("D:/上传的"+head.getOriginalFilename()));
        HashMap<String, Object> map = new HashMap<>();
        map.put("file", head);
        return map;

    }

文件上传可能出现的错误:系统找不到指定文件
java.io.FileNotFoundException: C:\Users\86131\AppData\Local\Temp\tomcat.8080.6906634590984434583\work\Tomcat\localhost\ROOT\upload_135c4883_3414_49af_b54e_39dbe063b0de_00000002.tmp (系统找不到指定的文件。)

我们去系统指定的目录中查看文件是否上传成功:

发现虽然报了错误,但是文件上传成功了:
1.4W字!让我带你读懂springmvc的世界!

在分析错误原因前我们先对文件上传的逻辑进行分析:客户端向服务端传输文件,文件首先报错到系统网卡然后部分文件信息保存到服务端内存,而有关文件内容将会在本地的一个临时目录中进行保存,如果我们调用transferTo(),会将默认保存的系统文件移动到我们指定的文件目录中,这种情况下原来临时目录的文件就没有了,所以当我们后面再调用有关文件信息的方法,首先在服务端的内存中进行查找,如果服务端内存没有这个信息,则需要到临时目录中进行查找,如果临时目录中没有这个文件,则会报以上的错误。

如何解决这个问题呢?

解决思路也比较清晰:在调用文件相关信息的时候,在transferTo()方法执行之前进行调用即可。

@RequestBody

我们前面有说到的是无论是无注解的请求参数还是使用@RequestParam注解,都不支持对json数据的解析,而@RequestBody能够实现对json数据的解析,不支持对其他数据类型的解析。

使用实例:

  @RequestMapping("/json")

    public Object jsonSend( @RequestBody User user){
        HashMap<String, String> map = new HashMap<>();
        map.put("name", user.getName());
        map.put("id", user.getId()+"");
        return map;
    }

1.4W字!让我带你读懂springmvc的世界!

通过配置类设置编程式的配置方案

我们知道可以通过设置配置文件的格式对springboot项目进行设置,但是通过配置文件设置比较麻烦或者设置通过配置文件无法实现的我们可以通过编程(设置配置类)来设置配置。通过@Configuration来实现这个功能:被@Configuration修饰的类会在springboot项目启动时进行加载配置,我们通过使用以下两个实例进行加载说明:

设置后端路径的统一前缀

功能:为所有的后端控制器添加统一的前缀(名为:api)

应用场景:在访问后端的请求路径时需要对其的部分路径的处理逻辑加一些统一的校验,为了区分前端路径和后端路径,我们统一为所有的控制器都加一个前缀.

我们给出代码实例:

因为我们进行的是有关web开发的配置,所以我们进行的配置要继承WebMvcConfigurer的接口

@Configuration
public class AppConfig implements WebMvcConfigurer {
    //调用路径匹配的api,为所有的后端逻辑添加前缀
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
      configurer.addPathPrefix("api", c->{
          //通过循环遍历所有的后端controller判断是否要加前缀(暂时设置所有的路径都为前缀)
          //如果需要在此处使某些控制器不加前缀,在此处应该加一些别的逻辑经即可
         return true;
      });
    }

1.4W字!让我带你读懂springmvc的世界!

我们在实际的路径中并没有api请求路径, 但是我们进行访问时必须通过“api”路径进行访问,否则直接报404

1.4W字!让我带你读懂springmvc的世界!

 1.4W字!让我带你读懂springmvc的世界!

设置拦截器

我们首先了解一下web开发的三大组件:servlet(连接器)、listener(监听器)和filter(过滤器),我们需要明确的是:spring官方并没有提供拦截器,拦截器是springmvc提供的,但是其实现原理是和过滤器类似。

拦截器的处理逻辑如下:

1.4W字!让我带你读懂springmvc的世界!

 在客户端返送请求之前会通过拦截器preHander相关方法进行处理,preHander返回一个Boolean值,TRUE则继续向下执行,FALSE则直接返回;在controller层返回响应后同样也会通过拦截器,这时回调用postHander()方法,最后将响应返回给客户端,我们自定义的拦截器通常会重写以下三个方法:

1、preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) 方法在请求处理之前被调用。该方法在 Interceptor 类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理,也可以进行一些判断来决定请求是否要继续进行下去。该方法的返回至是 Boolean 类型,当它返回 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当它返回为 true 时会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法。

2、postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 方法在当前请求处理完成之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。

3、afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法需要在当前对应的 Interceptor 类的 preHandle 方法返回值为 true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。此方法主要用来进行资源清理。

我们设置拦截器的过程可以从以下三个方面进行设计分析:①自定义拦截器②设置拦截路径③设置拦截器的处理逻辑

我们给出一个拦截器中以下的三种代码:
①路径处理:

配置拦截路径支持模糊匹配:而进行配置的方式,一般是通过添加拦截路径和排除一些不拦截的路径来处理

/**:添加任意路径

/api/**:添加api下的任意路径

/api/*:添加api下的一层目录

设置排除路径:

/api/login:排除api下的login的目录

/api/register:排除api下的register目录

②自定义拦截器:

自定义拦截器并引用HandlerInterceptor接口,然后重写接口中的方法

③实现方法逻辑

在重写的方法中实现方法逻辑

完整代码:

@Configuration
public class AppConfig implements WebMvcConfigurer {
    //调用路径匹配的api,为所有的后端逻辑添加前缀
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
      configurer.addPathPrefix("api", c->{
          //通过循环遍历所有的后端controller判断是否要加前缀(暂时设置所有的路径都为前缀)
         return true;
      });
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       //使用注册器进行注册过滤器
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/login")
                        .excludePathPatterns("/api/register");
    }
}
public class LoginInterceptor implements HandlerInterceptor {
    //设置请求逻辑:在请求前进行处理
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       //获取session
        HttpSession session = request.getSession(false);
        if(session!=null){
            String user = (String)session.getAttribute("user");
            if(user!=null){
                //判断是否是用户
                if(user.equals("admin")){
                    return true;
                }
            }
        }
        response.setStatus(401);

        return false;
    }
}

Interceptor 作用
日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等;
权限检查:如登录检测,进入处理器检测用户是否登录;
性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如 Apache 也可以自动记录)
通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现。

统一异常处理

如果我们通过浏览器进行请求时出现错误,极有可能把后端的报错信息全部显示到浏览器上,一方面这样存在极大的安全隐患(其他程序员根据报错可能会对我们后端的实现有一定的了解,从而进行破坏性操作),另一方面对用户的体验也并不是很友好。

1.4W字!让我带你读懂springmvc的世界!

因此我们需要进行统一的异常处理,将后端报错进行统一起来,我们进行如下操作:使用@ControllerAdvice注解进行控制器增强,使用@ExceptionHandle(异常类)进行统一的异常处理,@ExceptionHandle(异常类)的处理逻辑如下:根据括号中的异常类信息,当发生括号内的异常类中的报错信息之后,使用其下的方法进行报错的处理(起到的作用是异常处理的catch)

@ControllerAdvice
public class ExceptionHandle {
    //默认以json形式返回数据
    @ResponseBody
    //统一捕获异常类
    @ExceptionHandler(Exception.class)
    public Object handle(Exception e){
        HashMap<String, Object> map = new HashMap<>();
        map.put("code",500);
        map.put("message",e.getMessage());
        return map;
    }

1.4W字!让我带你读懂springmvc的世界!

需要注意的是:@ExceptionHandle(异常类)只能捕获其括号内的异常,一旦出了其括号内异常类的范围,还是会直接将错误信息直接返回给客户端:修改之后的错误信息如下:

@ControllerAdvice
public class ExceptionHandle {
    //默认以json形式返回数据
//    @ResponseBody
//    //统一捕获异常类
//    @ExceptionHandler(Exception.class)
//    public Object handle(Exception e){
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("code",500);
//        map.put("message",e.getMessage());
//        return map;
//    }
    @ResponseBody
    //统一捕获异常类
    @ExceptionHandler(IOException.class)
    public Object handleIo(Exception e){
        HashMap<String, Object> map = new HashMap<>();
        map.put("code",500);
        map.put("message",e.getMessage());
        return map;
    }

1.4W字!让我带你读懂springmvc的世界!

统一的结果处理:

①自定义结果类

@Data
public class Result {
    private Boolean ok;
    private Object data;
    private String error;
}

②使用@ControllerAdvice统一处理结果:设置ok data(data在返回的body中直接处理) 和error

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        //进行赋值处理
        Result result = new Result();
        result.setOk(true);
        result.setData(body);
        result.setError(null);
        return result;
    }
}

我们使用这个结果类访问以下代码:

import java.util.HashMap;

/**
 * @author tongchen
 * @create 2023-04-28 10:34
 */
@RestController
public class UserController {
    @RequestMapping("/user/{id}/{name}")
    public Object user(@PathVariable String name,@PathVariable Integer id ){
        HashMap<String, Object> map = new HashMap<>();
        map.put("user", name);
        return map;
    }
}

结果如下:

1.4W字!让我带你读懂springmvc的世界!

但是我们发现一个问题,在这个代码中,我们将返回信息除了data外直接写死了 ,我们思考一个问题:在真正的业务场景中,我们应该如何统一处理返回结果呢?(异常结果处理和统一结果处理)

A:修改返回类,取消统一设置返回方法,在具体的业务场景中具体返回结果,异常类单独返回结果

具体code及结果如下:

@Data
public class Result<T> {
    private Integer ok;//1代表成功 0代表失败
    private T data;
    private String msg;//正确或异常的信息
    public static <T>Result<T> success(T data){
        Result<T> result = new Result<>();
        result.setData(data);
        result.setOk(1);
        return result;
    }
    public static  <T>Result<T>error(String msg){
        Result<T> result = new Result<>();
        result.setOk(0);
       result.setMsg(msg);
        return result;
    }
}

 正常的结果类:

@RestController
public class UserController {
    @RequestMapping("/user/{id}/{name}")
    public Object user(@PathVariable String name,@PathVariable Integer id ){
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", id);
        map.put("name",name);
        return Result.success(map);
    }
}

异常的结果类:

public class MyException extends Exception{
    public MyException(String message) {
        super(message);
    }
}
@RestController
public class ExceptionController {
    @RequestMapping("/test")
    public void test() throws MyException {
        throw new MyException("HAHAHH");
    }
}

异常的结果类处理:
 

@ControllerAdvice
public class ExceptionHandle {
    //默认以json形式返回数据
//    @ResponseBody
//    //统一捕获异常类
//    @ExceptionHandler(Exception.class)
//    public Object handle(Exception e){
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("code",500);
//        map.put("message",e.getMessage());
//        return map;
//    }
    @ResponseBody
    //统一捕获异常类
    @ExceptionHandler(MyException.class)
    public Object handleIo(Exception e){
        HashMap<String, Object> map = new HashMap<>();
      return Result.error("服务器错误");
    }


}

正常结果:

1.4W字!让我带你读懂springmvc的世界!

 异常结果:

1.4W字!让我带你读懂springmvc的世界!

关于responseBodyAdvice的作用

 

 ResponseBodyAdvice 接口是在 Controller 执行 return 之后,在 response 返回给客户端之前,执行的对 response 的一些处理,可以实现对 response 数据的一些统一封装或者加密等操作。

  该接口一共有两个方法:

(1)supports  —— 判断是否要执行beforeBodyWrite方法,true为执行,false不执行  ——  通过supports方法,我们可以选择哪些类或哪些方法要对response进行处理,其余的则不处理。

(2)beforeBodyWrite  ——  对 response 处理的具体执行方法。文章来源地址https://www.toymoban.com/news/detail-456066.html

到了这里,关于1.4W字!让我带你读懂springmvc的世界!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux - 一篇带你读懂 Curl Proxy 代理模式

    curl 是一个很有名的处理网络请求的 类Unix 工具。出于某种原因,我们进行网络请求,需要设置代理。本文讲全面介绍如何为 curl 设置代理 设置代理参数 基本用法 设置 HTTP 代理 下面两种设置代理的方式是可以的 由于代理地址的默认协议为  HTTP, 所以可以省略,按照下面的

    2024年02月05日
    浏览(54)
  • 一文带你读懂设计模式之责任链模式

    emm,翻了一下之前刚入职时候的学习笔记,发现之前在熟悉业务代码的时候曾经专门学习并整理过过设计模式中的 责任链模式 ,之前只是对其简单了解过常用的设计模式有哪些,并未结合实例和源码深入对其探究,利用熟悉代码契机进行系统学习并整理文档如下。 俗话说没

    2024年02月12日
    浏览(33)
  • CTF是什么?一文带你读懂网络安全大赛

    💻随着大数据、人工智能的发展,人们步入了新的时代,逐渐走上科技的巅峰。 ⚔科技是一把双刃剑,网络安全不容忽视,人们的 隐私 在大数据面前暴露无遗,账户被盗、资金损失、网络诈骗、隐私泄露,种种迹象表明,随着互联网的发展, 网络安全 需要引起人们的重视

    2024年02月07日
    浏览(47)
  • MATLAB :【11】一文带你读懂serialport串口收发原理与实现

    碎碎念: 这周的主要工作还是集中于FOC中,因为羡慕稚晖君做出的漂亮Qt面板,因此在利用MATLAB复刻过程中,学习了一下serialport的使用。FOC的GUI部分就在加班加点写作中啦,同时最近打算开一个新坑,大家可以期待一下哈哈哈。 欢迎大佬们点赞+收藏+关注~ o(* ̄▽ ̄*)ブ 目录

    2023年04月18日
    浏览(39)
  • 3D智能相机:带你读懂3D机器视觉如何实时扫描构建物体的3D模型

    作者:御剑飞行  3D智能相机是一种能够捕捉三维空间中物体形状和位置信息的相机。它可以在一个瞬间同时捕捉到物体的深度和颜色信息,并用这些数据创建一个三维模型。 3D智能相机工作方式示意图,图源@御剑飞行 3D智能相机能够捕获物体的更详细信息,包括其尺寸、形

    2024年04月09日
    浏览(40)
  • 抖音小店无货源处罚全解,一文带你读懂官方规则,合理规避风险

    大家好,我是电商年年 根据官方解释, “无货源店铺” ,指店铺经营者没有现货,在网上找产品找货源,在未取得货源方授权的情况下,把货源信息“搬运”到自己的店铺中,等有消费者下单,店铺经营者再去 货源方店铺下 单,由货源方向消费者派单发货。   那官方对于

    2024年02月03日
    浏览(51)
  • 【无标题】chatGPT--白话文教你读懂chatGPT

    ChatGPT是Chat(聊天) Generative(生成) Pre-trained(预先训练过的) Transformer(改革者)的一个简写(或称缩写),也有人说Transformer是转换者的意思,但是大致意思基本一样,我们也不用太执着到底是什么意思。本次ChatGPT是美国OpenAI (OpenAI,在美国成立的人工智能研究公司,核心宗旨在于“实

    2023年04月24日
    浏览(44)
  • 一篇文章让你读懂-曼彻斯特编码

    目录 写在前面的话 1 what?什么是曼彻斯特编码  2 how?怎么使用曼彻斯特编码 2.1 曼彻斯特的编码: 2.2 曼彻斯特的译码: 3 why?为什么推荐曼彻斯特编码?这种编码方式的优缺点         数据传输之前为什么将数据进行编码?         这是个好问题!!         一

    2023年04月15日
    浏览(36)
  • 图论:一文教你读懂常见的图遍历算法

    深度优先搜索(DFS): 从一个起始节点开始,访问该节点并将其标记为已访问。 递归地访问所有与当前节点直接相连且未被访问过的节点。 重复上述步骤,直到所有节点都被访问过或没有未访问的节点。 广度优先搜索(BFS): 从一个起始节点开始,将其放入队列中,并标

    2024年04月25日
    浏览(26)
  • ES高频面试问题:一张图带你读懂 Elasticsearch 中“正排索引(正向索引)”和“倒排索引(反向索引)”区别

    从广义来说,doc values 本质上是一个序列化的 列式存储 。列式存储 适用于聚合、排序、脚本等操作,所有的数字、地理坐标、日期、IP 和不分词( not_analyzed )字符类型都会默认开启, 不支持 text 和 annotated_text 类型 倒排 :即 词项 = 包含当前词项的doc_id的列表 的映射。倒排

    2024年02月02日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包