Java框架 —— SpringMVC

news/2025/2/28 23:58:33/文章来源:https://www.cnblogs.com/codyxz/p/18608025

MVC 分层

MVC:Model View Controller(模型-视图-控制器)

  • 模型(Model):处理数据逻辑的部分;在web应用中,他通常包含与数据库交互的代码,负责数据的存储、检索和更新

  • 视图(View):将数据渲染为用户界面,视图只展示页面,不包含业务逻辑

  • 控制器(Controller):模型和视图之间的协调者,它接收用户的输入,调用视图和模型完成用户的请求


核心组件

  • 前端控制器(DisPatcherServlet):负责接收请求、分发,给予客户端响应

  • 处理器映射器(HandlerMapping):根据URL匹配查找能处理的Handler,并会将请求涉及到的拦截器和Handler一起封装

  • 处理器适配器(HandlerAdapter):根据HandlerMapping找到的Handler,适配执行对应的Handler

  • 请求处理器(Handler):处理实际请求的处理器(可理解为方法)

  • 视图解析器(ViewResolver):根据Handler返回的逻辑视图,解析并渲染成实际视图,并传递给DisPatcherServlet响应给客户端

DisPatcherServlet

SpringMVC围绕前端控制器模式设计,DisPatcherServlet需要Java配置或者XML配置根据Servlet规范进行声明和映射(一般使用XML配置)

  • Java配置注册并初始化DisPatcherServlet
    public class MyWebApplicationInitializer implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext servletContext) {// Load Spring web application configurationAnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();context.register(AppConfig.class);// Create and register the DispatcherServletDispatcherServlet servlet = new DispatcherServlet(context);ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);registration.setLoadOnStartup(1);registration.addMapping("/app/*");}
    }
    
  • web.xml配置注册并初始化DisPatcherServlet
    <web-app><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/app-context.xml</param-value></context-param><servlet><servlet-name>app</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value></param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>app</servlet-name><url-pattern>/app/*</url-pattern></servlet-mapping>
    </web-app>
    

运行原理

 客户端发送请求到前端控制器DisPatcherServlet,前端控制器调用处理器映射器HandlerMapping查找请求对应的处理方法Handler,并将涉及到的拦截器和Handler一起封装返回给前端控制器,前端控制器再调用处理器适配器HandlerAdapter执行Handler,并将数据放入Model中或直接返回ModelAndView对象给前端控制器,前端控制器再调用视图解析器ViewResolver将逻辑视图解析为实际视图,并将模型数据传递给视图View,视图将其渲染成HTML,返回给前端控制器,前端控制器再将渲染好的视图返回给客户端


常用注解

  • 控制器相关

    • @Controller:类级别的注解,用于标记一个类为Controller的注解,负责接收用户请求,进行处理后,最终返回客户,一般结合@RequestMapping进行使用

    • @RestController:是@Controller@ResponseBody的结合,它标记的类中,每个方法的返回值都会以 JSON 或 XML 的形式直接写入 HTTP 响应体中,相当于在每个方法上都添加了 @ResponseBody 注解

  • 请求映射相关

    • @RequestMapping:用于将请求映射到相应的处理方法上,可以作用于类或者方法级别

    • @GetMapping@PostMapping@PutMapping@DeleteMapping

      Restful 风格

      浏览器表单中只支持GET和POST请求,所以为了让浏览器实现PUT和DELETE,Spring提供了一个过滤器,将GET、POST请求转换成PUT、DELETE形式

  • 参数绑定相关

    • @RequestParam:将HTTP请求的参数绑定到控制器方法的参数上

    • @PathVariable:用于获取路径中的动态参数

    • @RequestBody:将请求体中的JSON或XML数据绑定到方法的参数对象上

  • 响应相关

    • @ResponseBody:将方法的返回值作为HTTP响应体的内容,常用于返回JSON或XML数据

    • @ResponseStatus:用于设置HTTP对应的状态码

自定义类型转换器

 页面传递的参数是String类型的,而在控制器中接收的参数是不固定的,对于基本数据类型,SpringMVC提供了类型转换器,对于不支持的目标类型,如:日期、自定义类型,则需要自定义类型转换器

顶层接口:Converter ——— 将类型 S 转换成 T

@FunctionalInterface
public interface Converter<S, T> {/*** Convert the source object of type {@code S} to target type {@code T}.* @param source the source object to convert, which must be an instance of {@code S} (never {@code null})* @return the converted object, which must be an instance of {@code T} (potentially {@code null})* @throws IllegalArgumentException if the source cannot be converted to the desired target type*/@NullableT convert(S source);
}

实现

通过实现 Converter 接口

  1. 自定义类型转换器 —— 实现Converter接口
    实体类
public class Goods {private String name;private double price;private int num;public Goods() {}public Goods(String name, double price, int num) {this.name = name;this.price = price;this.num = num;}@Overridepublic String toString() {return "Goods{" +"name='" + name + '\'' +", price=" + price +", num=" + num +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}
}

Controller层

@Controller
@RequestMapping("/goods")
public class GoodsController {@RequestMapping("/show")public String add(@RequestParam("goods") Goods goods, Model model){model.addAttribute("goods",goods);return "showGoods";}
}

自定义类型转换 GoodsConverter

public class GoodsConverter implements Converter<String, Goods> {public GoodsConverter(){System.out.println("GoodsConverter...");}@Overridepublic Goods convert(String source) {Goods goods = new Goods();if (source != null) {String[] split = source.split(",");if (split.length == 3) {goods.setName(split[0]);goods.setPrice(Double.parseDouble(split[1]));goods.setNum(Integer.parseInt(split[2]));return goods;} else {throw new IllegalArgumentException(String.format("类型转换失败, 需要格式'apple, 10.58,200 ',但格式是[% s ] ", source));}}else {throw new IllegalArgumentException("source不能为空");}}
}

spring-mvc.xml配置文件

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><list><bean class="com.ry.GoodsConverter"/></list></property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"/>

通过@InitBinder注解(推荐)

用于@Controller标注的类的方法上,表示为当前控制器注册一个属性编辑器,只对当前Controller有效,在其他方法执行前执行,做到预处理数据; @InitBinder标注的方法必须有WebDataBinder参数,用于表单到方法的绑定(属性编辑器可以理解为帮我们完成参数绑定的)

@Controller
public class UserController {@InitBinderpublic void initBinder(WebDataBinder binder){binder.registerCustomEditor(LocalDate.class,new PropertyEditorSupport(){@Overridepublic void setAsText(String text) throws IllegalArgumentException {//将请求参数转换为LocalDate类型setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")));}});}
}

拦截器

拦截指定的用户请求,并进行相应的预处理和后处理,类似于Servlet中的过滤器,只不过比过滤器的功能更强大

应用场景

  • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计等

  • 权限控制:如登录检测,进入处理器检测是否登录,没有登录返回登录页面

  • 性能监测:记录拦截器进入处理器和离开处理器的时间

配置及使用

  • 通过实现HandlerInterceptor接口来实现拦截器,接口中有三个方法preHandle()postHandle()afterCompletion()

    • preHandle():处理器执行前执行,如果返回false,则跳过处理器、拦截器postHandle()、视图渲染等,直接执行拦截器afterCompletion()

    • postHandle():处理器执行后,视图渲染前执行,如果抛出异常,则跳过该方法直接执行afterCompletion()

    • afterCompletion():视图渲染后执行,不管是否抛出异常

    /*** 定义一个拦截器*/
    public class HandlerInterceptor1 implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("拦截器1的preHandle方法执行了...");//返回值true表示放行,false表示不放行return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("拦截器1的postHandle方法执 行了");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("拦截器1的afterCompletion方法执行了");}
    }
    
  • 在SpringMVC配置文件中进行配置

    • <mvc:interceptors>使用<mvc:interceptor>标签对拦截器进行作用范围的设置。

    • 使用<mvc:mapping path=""/>设置处理的请求,可以使用通配符,可以设置多个

    • 使用<mvc:exclude-mapping path="" />设置不需要拦截的请求,可以使用通配符,可以配置多个。但是使用的前提是需要先配置需要处理的请求范围,即需要先配置了<mvc:mapping path="" />才行,否则会有错误。

    <!-- 配置拦截器,拦截器可以有0或多个 -->
    <mvc:interceptors><!-- 配置一个拦截器 --><mvc:interceptor><!-- mvc:mapping用于指定当前所注册的拦截器可以拦截的请求路径,path路径/**表示拦截所有请求,两个*表示匹配多级目录URL地址,例如/aaa/bbb/ccc --><mvc:mapping path="/**"/><bean id="handlerInterceptor1" class="com.thr.interceptor.HandlerInterceptor1"/></mvc:interceptor>
    </mvc:interceptors>
    

多个拦截器的执行顺序

 当我们在项目中配置了多个拦截器,他们的执行顺序由我们定义时的顺序决定,但是拦截器中的方法执行顺序不同

先顺序执行拦截器1、2、3的preHandle(),再逆序执行postHandle(),最后逆序执行afterCompletion()方法

拦截器和过滤器的区别

  • 拦截器不依赖于 Servlet 容器,过滤器依赖于 Servlet 容器

  • 拦截器是基于Java反射的,过滤器是基于函数回调

  • 拦截器只对action请求起作用,过滤器对几乎所以请求都有效

  • 拦截器可以访问action上下文、值栈中的对象,过滤器不能访问







参考文章:

  • SpringMVC入门学习(十二)----SpringMVC的拦截器

  • Spring MVC 系列之拦截器 Interceptor 最全总结

  • SpringMVC--Converter(类型转换器)详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/854994.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024-12-18 17 55 记录 Cambly trip`s summary and wher 1607b517085581159d14fe7750337be7

2024-12-18 17:55 记录 Cambly trip`s summary and where is the next ?https://tingwu.aliyun.com/doc/transcripts/g2y8qevxaayxnbeo?sl=1# 《2024-12-18 17:55 记录 Cambly trip`s summary and where is the next ?》1. 全文摘要 对话讲述了一个人通过使用美好的旅行来…

实验六 模板类、文件I/O和异常处理

1、实验任务一 Complex.hpp#pragma once#include <iostream> #include <stdexcept>// 声明 //////////////////////////////////////////////////// // 复数模板类声明 template<typename T> class Complex { public:Complex(T r = 0, T i = 0);Complex(cons…

免费设计Logo的新神器Slea.ai

使用Slea.ai,你可以在几分钟内设计出专业、高质量的Logo,支持多种场景应用,免费下载,实现自定义设计。品牌打造从未如此轻松!作为一名注重品牌形象的创作者或企业主,你是否苦于设计一款专业又独特的Logo?今天我要向大家推荐一个超级实用的网站——Slea.ai,它是一款免费的…

MOS管的寄生电容

我们经常看到,在电源电路中,功率MOS管的G极经常会串联一个小电阻,几欧姆到几十欧姆不等,那么这个电阻用什么作用呢? 这个电阻的作用有2个作用:限制G极电流,抑制振荡。 限制G极电流MOS管是由电压驱动的,是以G级电流很小,但是因为寄生电容的存在,在MOS管打开或关闭的时…

配置CentOS 7阿里yum源

备份yum源配置文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo_bakvi /etc/yum.repos.d/CentOS-Base.repo# CentOS-Base.repo # # The mirror system uses the connecting IP address of the client and the # update status of each mirror to …

源码信息收集

引子:上一篇主要介绍了与Web架构相关的信息收集,而在Web架构中有一至关重要的一环,那就是源码。Web应用中美观的ui、特色的功能全靠源码来实现,但同样的,几乎绝大多数与Web相关的漏洞都也都与其源码有关。而本篇则介绍几种常见的源码信息收集方式。附:完整笔记目录~ ps:…

标定和定位的关系

手眼标定手眼标定可以利用某真值位置和传感器观测位置对比得到外参。 关联本质上是外参不同引起的看同一外接参照物,认为自身运动轨迹的不同。位置如上观测同一建筑(三角形,上顶点是北方),真实轨迹(左图):是向北直行是在向正前方走世界坐标系->偏置传感器轨迹(中间图…

12.13

实验2 熟悉常用的HDFS操作1.实验目的 (1)理解HDFS在Hadoop体系结构中的角色; (2)熟练使用HDFS操作常用的Shell命令; (3)熟悉HDFS操作常用的Java API。 2. 实验平台 (1)操作系统:Linux(建议Ubuntu16.04或Ubuntu18.04); (2)Hadoop版本:3.1.3; (3)JDK版本:1.…

12.10

实验八:随机森林算法实现与测试一、实验目的 深入理解随机森林的算法原理,进而理解集成学习的意义,能够使用 Python 语言实现随机森林算法的训练与测试,并且使用五折交叉验证算法进行模型训练与评估。 二、实验内容 (1)从 scikit-learn 库中加载 iris 数据集,使用留出法…

Tengine:Nginx二次开发-高性能进化

前言:在当今的互联网时代,Web 服务器的性能和稳定性对于网站的成功至关重要。Nginx 以其高性能和可扩展性而闻名,但有时候,我们需要更多的特性来满足特定的业务需求。Tengine,作为一个由淘宝网发起的 Nginx 二次开发版本,不仅继承了 Nginx 的所有特性,还添加了许多高级功…