VIP免费

一文深入了解springmvc入门使用

精品 springmvc拦截器 原创
43
DEMO程序园
程序猿 2020-07-15
积分:0

简介:

本文主要从日常中对springmvc高频使用点做了简单的介绍,包括springmvc的工作原理,核心组件,以及日常编码中常用注解及使用方式,如何传参,拦截器等应用,更多使用技巧还需要大家在日常工作中去磨炼,共同进步。

1. 何为MVC?

MVC 是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

  • 视图(View) 在 JavaEE 应用程序中,视图(View)可以由 JSP(Java Server Page)担任。在现在前后端分离的模式下,View 已经由前端所取代。

  • 控制器(Controller) JavaEE 应用中,Controller 可能是一个 Servlet 。在 Spring MVC 中担任控制器角色的是 DispatcherServlet。

  • 模型(Model) Model 则是由一个实体 Bean 来实现,主要对应数据层。

2. springmvc工作原理

Spring MVC 最核心的思想在于 DispatcherServlet 。在现在的开发模式中,我们主要使用的也是 Spring MVC 的这一核心功能。

Spring MVC 工作原理图如下:

5e9ac00c0001278911570606.jpg


浏览器发起一个请求(如:http://localhost:8080/hello), 会经历如下步骤:

  1. DispatcherServlet 接收到请求

  2. 通过 HandlerMapping 找到对应的 handler

  3. 然后通过 HandlerAdapter 调用 Controller 进行后续业务逻辑处理(3-4)

  4. 处理完业务逻辑后,Controller 将视图名返回给 HandlerAdapter

  5. DispatcherServlet 选择合适的 ViewResolver 生成 View 对象

  6. 最后 View 渲染并返回响应数据

3. 核心组件

springmvc核心组件分为3个,他们分别是Handler、HandlerMapping、HanderAdapter

3.1 Handler

Handler 是用来做具体事情的,对应的是 Controller 里面的方法,所有有 @RequestMapping 标注的方法都可以看做为一个 Handler。

3.2 HandlerMapping

HandlerMapping 是用来找到 Handler 的,是请求路径与 Handler 的映射关系。

3.3 HanderAdapter

HandlerAdapter 从名字看,可以知道它是一个适配器。它是用来跟具体的 Handler 配合使用的。可以简单理解为各种电子产品与电源适配器(充电器)的关系。

DispatcherServlet 最核心的方法就是 doDispatch ,doDispatch 主要做了四件事:

  1. 根据 request 找到 Handler

  2. 根据 Handler 找到对应的 HanderAdapter

  3. 用 HanderAdapter 处理 Handler

  4. 处理经过以上步骤的结果

4. springmvc常用注解

注解作用域说明
@ControllerController标识
@RequestMapping类/方法URL映射
@ResponseBody类/方法以Json方式返回
@RequestParam参数按名字接收参数
@RequestBody参数接收Json参数
@PathVariable参数接收URL中的参数
@RestController组合注解:@Controller + @ResponseBody
@GetMapping方法组合注解:@RequestMapping(method = RequestMethod.GET)
@PostMapping方法组合注解:@RequestMapping(method = RequestMethod.POST)
@PutMapping方法组合注解:@RequestMapping(method = RequestMethod.PUT)
@PatchMapping方法组合注解:@RequestMapping(method = RequestMethod.PATCH)
@DeleteMapping方法组合注解:@RequestMapping(method = RequestMethod.DELETE)

从上表我们可以发现组合注解就是具有多个功能的注解,由多个注解或者一个注解 + 一个特定的属性值组成的注解,相当于对注解的一种封装。

例如@RestController 不仅可以标识一个 Controller ,还能让被标识的 Controller 中的所有方法都返回 JSON 格式的数据;@GetMapping 不仅可以映射一个请求路径,还让该路径只响应 GET 请求,对于其他的请求方式不响应。

5 如何优雅传递参数

Spring MVC 的主要工作就是接收外部的请求,然后根据请求去调用相应的服务,最后将处理结果返回。外部发来的请求会以各种形式带着各式各样的参数,以达到不同的目的。Spring MVC共 有四种接收参数的方式:

  • 无注解方式

  • @RequestParam 方式

  • @PathVariable 方式

  • @RequestBody 方式

接下来,我们分别给出示例:

首先,我们需要准备一个接收入参的实体类:

public class User {
   private String name;
   private int age;
   
   // 此处省略set get方法
   // ......
}

5.1 无注解形式

@RestController
public class ParamController {
   
   @GetMapping("/noannotation")
   public User noAnnotation( User user) {
       return user;
   }
 
}

请求示例:

http://localhost:8080/noannotation?name=无注解方式&age=18

5.2 @RequestParam方式

@RequestParam 注解有四个属性:

属性类型说明
nameString参数名称
valueStringname 属性的别名
requiredboolean指定是否为必传参数(为 true 时不传会报错)
defaultValueString参数默认值
@GetMapping("/requestparam")
public User RequestParam(@RequestParam String name, @RequestParam int age) {
 User user = new User();
 user.setName(name);
 user.setAge(age);
 return user;
}

请求示例:

http://localhost:8080/requestparam?name=@RequestParam方式&age=4

5.3 @PathVariable方式

@PathVariable 注解有三个属性:

属性类型说明
nameString参数名称
valueStringname 属性的别名
requiredboolean指定是否为必传参数(为 true 时不传会报错)
@GetMapping("/pathvariable/{name}/{age}")
public User PathVariable(@PathVariable String name,@PathVariable int age) {
 User user = new User();
 user.setName(name);
 user.setAge(age);
 return user;
}

请求示例:

http://localhost:8080/pathvariable/@PathVariable方式/2

5.4 @RequestBody方式

@RequestBody 只有一个属性:

属性类型说明
requiredboolean指定是否为必传参数(为 true 时不传会报错)
@PostMapping("/requestbody")
public User RequestBody(@RequestBody User user) {
   return user;
}

请求示例(请自行使用接口调试工具测试,如postMan):

url: http://localhost:8080/requestbody
method: post
body: {"name":"@RequestBody方式","age":12}

6. 拦截器


6.1 简介

书接上回,在这一趴我们一起来学习一下 Spring MVC 中的拦截器。拦截器在我们日常开发当中有着很重要的地位,很多重要的功能需要借助拦截器帮我们完成。我们通常会使用拦截器帮我们完成以下功能:

  • 登录认证

  • 权限验证

  • 记录日志

  • 性能监控


6.2 自定义拦截器

接下来我们学习如何写一个拦截器。Spring MVC 中所有的拦截器都实现/继承自 HandlerInterceptor 接口。我们想要写一个自定义拦截器的话,需要实现/继承 HandlerInterceptor 或其子接口/实现类。下图是 Spring MVC 中拦截器的类图(还有几个类是 HandlerInterceptorAdapter的子类,这里没有列出):

5e9abed20001b27620800520.jpg


HandlerInterceptor 接口的源码如下:

public interface HandlerInterceptor {

  // 处理器执行前被调用
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
  throws Exception {

 return true;
}

  // 处理器执行后,视图渲染前被调用
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
  @Nullable ModelAndView modelAndView) throws Exception {
}

  // 视图渲染完成后背调用
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
  @Nullable Exception ex) throws Exception {
}

}

下面我们自定义一个最简单、纯净的拦截器,也就是直接实现 HandlerInterceptor 接口。

新建一个类 LogInterceptor 并实现 HandlerInterceptor 接口:

并在三个方法中分别添加一条日志打印的代码

@Slf4j
@Component
public class LogInterceptor implements HandlerInterceptor {
   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       log.info("preHandle");
       return true;
   }

   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
       log.info("postHandle");
   }

   @Override
   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
       log.info("afterCompletion");
   }
}

新建一个类 WebConfigurer 并实现 WebMvcConfigurer 接口,用于注册我们自定义的拦截器:

@Configuration
public class WebConfigurer implements WebMvcConfigurer {

   @Autowired
   private LogInterceptor logInterceptor;

   @Override
   public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(logInterceptor);
   }
}

HelloControllerhello 方法中添加一条日志打印代码:

@Slf4j
@RestController
public class HelloController {
   @GetMapping("/hello")
   public String hello(@RequestParam(required = false) @ApiParam("名字") String name) {
       if (name == null || "".equals(name)) {
           name = "Spring Boot";
       }
       log.info("hello");
       return "Hello "+name;
   }
}

OK,接下来启动工程,并访问以下hello 方法,控制台会看到如下的输出:

com.imooc.springboot.LogInterceptor      : preHandle
com.imooc.springboot.HelloController     : hello
com.imooc.springboot.LogInterceptor      : postHandle
com.imooc.springboot.LogInterceptor      : afterCompletion

如果一切正常,将出现如上结果,这代表我们的自定义拦截器成功了!

3.3 拦截器执行流程

从控制台的日志输出,我们可以大概看出拦截器的执行流程。下面我们来更加深入的学习一下拦截器的整个执行流程:

5e9abea90001c57d07710426.jpg

  1. 执行 preHandle 方法,该方法会返回一个布尔值。如果为 false ,则结束本次请求:如果为 true 则继续。

  2. 执行处理器逻辑,也就是我们的 Controller 。

  3. 执行 postHandle 方法。

  4. 执行视图解析和视图渲染 (我们直接返回了 JSON 对象,所以没有视图处理)。

  5. 执行 afterCompletion 方法。

我们可以在 DispatcherServletdoDispatch 方法的源码中进一步验证这个执行逻辑:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
 try {
 
  // 返回 HandlerExecutionChain  其中包含了拦截器队列
  mappedHandler = getHandler(processedRequest);

  //调用拦截器 PreHandle 方法,若返回 false 将直接 return
  if (!mappedHandler.applyPreHandle(processedRequest, response)) {
   return;
  }

  // 处理 Controller
  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

  // 调用拦截器的 PostHandle 方法
  mappedHandler.applyPostHandle(processedRequest, response, mv);
 }

 // 调用拦截器的 afterCompletion 方法
 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}

7 总结

本文主要从日常中对springmvc高频使用点做了简单的介绍,包括springmvc的工作原理,核心组件,以及日常编码中常用注解及使用方式,如何传参,拦截器等应用,更多使用技巧还需要大家在日常工作中去磨炼,共同进步。


评论
最新发布
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-18
layui

微信扫码关注DEMO程序园公众号

本周热门
1989
1631
1389
1337
1280
1062
1042
996
869
516
热门下载
27
20
19
14
14
12
12
12
12
11