一文深入了解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 工作原理图如下:
在这里插入图片描述

浏览器发起一个请求(如: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的子类,这里没有列出):

在这里插入图片描述

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 拦截器执行流程

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

  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的工作原理,核心组件,以及日常编码中常用注解及使用方式,如何传参,拦截器等应用,更多使用技巧还需要大家在日常工作中去磨炼,共同进步。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值