SpringMVC

目录

一、SpringMVC学习资料

二、SpringMVC一些面试题

[2.1.1 Spring MVC 原理](#2.1.1 Spring MVC 原理)

[2.1.2 什么是MVC](#2.1.2 什么是MVC)

[2.1.3 什么是SpringMVC](#2.1.3 什么是SpringMVC)

[2.1.3 SpringMVC的特点](#2.1.3 SpringMVC的特点)

[2.2 SpringMVC具体的执行流程是什么?★★★★](#2.2 SpringMVC具体的执行流程是什么?★★★★)

[2.3 SpringMVC常用注解](#2.3 SpringMVC常用注解)

[2.4 SpringMVC中的`@Controller`注解有何作用?](#2.4 SpringMVC中的@Controller注解有何作用?)

[2.5 `@RequestParam`、`@PathVariable`和`@RequestBody`分别用于什么场景?](#2.5 @RequestParam@PathVariable@RequestBody分别用于什么场景?)

[2.6 怎样在Spring MVC中处理文件上传和下载?](#2.6 怎样在Spring MVC中处理文件上传和下载?)

[2.7 什么是Spring MVC的拦截器(Interceptor)?如何配置和使用?](#2.7 什么是Spring MVC的拦截器(Interceptor)?如何配置和使用?)

[2.8 Spring MVC拦截器和Servlet Filter有什么区别?](#2.8 Spring MVC拦截器和Servlet Filter有什么区别?)

[2.9 指出Spring Security如何与Spring MVC拦截器协同工作](#2.9 指出Spring Security如何与Spring MVC拦截器协同工作)

[2.10.1 ResponseEntity★★★★](#2.10.1 ResponseEntity★★★★)

[2.10.2 ResponseEntity中包含了哪些重要属性?](#2.10.2 ResponseEntity中包含了哪些重要属性?)

[2.11 RequestEntity](#2.11 RequestEntity)

[2.12.1 自定义拦截器有哪些方式?★★★★](#2.12.1 自定义拦截器有哪些方式?★★★★)

[2.12.2 自定义拦截器中的`preHandle()`、`postHandle()`和`afterCompletion()`分别在什么阶段执行?](#2.12.2 自定义拦截器中的preHandle()postHandle()afterCompletion()分别在什么阶段执行?)

[2.12.3 拦截器的应用场景](#2.12.3 拦截器的应用场景)


一、SpringMVC学习资料

地址:

目录:

二、SpringMVC一些面试题

2.1.1 Spring MVC 原理

  • Spring MVC 是 Spring 框架的一个模块,用于构建Web应用程序。它遵循模型-视图-控制器(Model-View-Controller)架构模式。以下是 Spring MVC 工作原理的基本步骤:略。
  • Spring 的模型-视图-控制器(MVC)框架是围绕一个 DispatcherServlet 来设计的,这个 Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。

2.1.2什么是MVC

MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分

M:Model,模型层,指工程中的JavaBean,作用是处理数据

JavaBean分为两类:

  • 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等

  • 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器。

2.1.3 什么是SpringMVC

  • SpringMVC是Spring的一个后续产品,是Spring的一个子项目
  • SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案
  • 注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet

2.1.3 SpringMVC的特点

  • Spring 家族原生产品,与 IOC 容器等基础设施无缝对接

  • 基于原生的Servlet ,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理

  • 表述层各细分领域需要解决的问题全方位覆盖 ,提供全面解决方案

  • 代码清新简洁,大幅度提升开发效率

  • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可

  • 性能卓著,尤其适合现代大型、超大型互联网项目要求

2.2 SpringMVC具体的执行流程是什么?★★★★

SpringMVC的执行流程如下:

  1. 用户发起HTTP请求到达DispatcherServlet(前端控制器)。
  2. DispatcherServlet通过HandlerMapping(处理器映射器)找到对应的Controller(控制器)方法。
  3. HandlerAdapter(处理器适配器)调用Controller方法处理业务逻辑。
  4. Controller方法执行完毕,返回一个ModelAndView对象,包含了视图名和模型数据。
  5. ViewResolver(视图解析器)根据ModelAndView中的视图名解析出实际的视图对象。
  6. 视图对象负责渲染视图,如JSP页面或其他模板引擎。
  7. 渲染完成后,响应内容返回给客户端。

2.3 SpringMVC常用注解

在Spring MVC中,一些常用的注解包括:

  • @Controller: 标识一个类作为Spring MVC控制器,该类会处理HTTP请求。
  • @RequestMapping: 用于映射HTTP请求。可以放在类级别表示控制器的基本路径,也可以放在方法级别表示具体的操作路径。
  • @GetMapping / @PostMapping / @PutMapping / @DeleteMapping : 这些是@RequestMapping的特殊形式,分别对应HTTP的GET, POST, PUT, DELETE操作。
  • @PathVariable: 从URL模板中获取值并注入到方法参数中。
  • @RequestParam: 从请求参数中获取值,通常用于GET请求或POST请求的表单数据。
  • @RequestBody: 用来读取请求主体内容,通常用于接收JSON或XML数据。
  • @ResponseBody: 将方法返回的对象序列化成JSON或其他格式并直接写入HTTP响应体。
  • @ExceptionHandler: 注解在方法上,用于捕获并处理特定的异常。
  • @Autowired: 自动装配Spring容器中的bean,可以用于字段、构造器、setter方法等。
  • @ModelAttribute: 用于将方法返回的对象添加到模型中,常用于表单回显或者初始值设置。

2.4 SpringMVC中的`@Controller`注解有何作用?

@Controller注解在SpringMVC中用于标记一个类作为控制器,它扮演着接收HTTP请求并调用业务逻辑进行处理的角色。当Spring容器启动时,会扫描标记了此注解的类,并将它们注册为bean,以便后续的请求能够与这些控制器关联。使用示例:

java 复制代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloWorldController {

    @GetMapping("/hello")
    public String sayHello() {
        return "hello";  // 返回的字符串会被视图解析器解析为视图名称
    }
}

在这个例子中,@Controller注解定义了一个名为HelloWorldController的控制器,@GetMapping("/hello")则标识了sayHello()方法可以处理/hello的HTTP GET请求。

2.5 `@RequestParam`、`@PathVariable`和`@RequestBody`分别用于什么场景?

@RequestParam@PathVariable@RequestBody是Spring MVC中用于处理HTTP请求参数的三种不同方式:

@RequestParam : 用于从URL查询参数或请求头中获取值。它通常与GET或POST请求一起使用。例如,如果你有一个URL http://example.com/user?id=123,你可以这样做:

java 复制代码
public User getUser(@RequestParam("id") int userId) {
    // ...
}

这里的@RequestParam("id")会获取URL中的'id'参数值。

@PathVariable : 用于获取RESTful URL模板中的占位符值。常用于处理基于资源的URI。比如,/users/{userId},你可以这样获取路径变量:

java 复制代码
public User getUser(@PathVariable("userId") int userId) {
    // ...
}

这里的@PathVariable("userId")会获取URL路径中的userId部分。

@RequestBody: 用于读取请求正文的内容,并将其绑定到一个Java对象上。这在接收到JSON或XML等数据格式的POST请求时特别有用:

java 复制代码
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
    // ...
}

在这个例子中,@RequestBody会将请求体中的JSON转换为User对象。

2.6 怎样在Spring MVC中处理文件上传和下载?

在Spring MVC中处理文件上传和下载涉及以下几个步骤:

文件上传:

1)首先,在HTML表单中使用<form>标签,并设置enctype="multipart/form-data"来支持文件上传。

html 复制代码
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/>
    <input type="submit" value="Upload"/>
</form>

2)在@Controller类中,使用@RequestParam("file") MultipartFile file来接收上传的文件。

java 复制代码
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
    // 验证文件非空
    if (!file.isEmpty()) {
        try {
            byte[] bytes = file.getBytes();
            // 保存文件到服务器
            File(dirPath, fileName).writeBytes(bytes);
            return "You successfully uploaded " + file.getOriginalFilename() + "!";
        } catch (IOException e) {
            return "You failed to upload " + file.getName() + " => " + e.getMessage();
        }
    } else {
        return "You failed to upload because the file was empty.";
    }
}

2.7 什么是Spring MVC的拦截器(Interceptor)?如何配置和使用?

Spring MVC的拦截器类似于Java Servlet中的Filter,但它们的作用范围更小,只针对DispatcherServlet处理的请求进行拦截。拦截器允许你在请求被控制器处理之前或之后执行一些额外的操作,比如权限检查、日志记录、性能监控等。

配置和使用Spring MVC的拦截器分为几个步骤:

(1)创建拦截器实现HandlerInterceptor接口 创建一个新的类并实现org.springframework.web.servlet.HandlerInterceptor接口。通常需要重写三个方法:preHandle()postHandle()afterCompletion()

java 复制代码
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("Pre-handle: Before processing request");
        return true; // 返回true表示继续处理,返回false则中断后续处理
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("Post-handle: After controller is executed but before view rendering");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("After completion: After rendering view");
    }
}

(2)配置拦截器 在Spring MVC的配置文件(如WebMvcConfigurerAdapterWebMvcConfigurationSupport的子类)中注册拦截器。

java 复制代码
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor());
        // 添加更多拦截器...
    }
}

或者使用Java配置(自定义的WebMvcConfigurer接口实现类):

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor());
        // ...
    }
}

(3)可选:拦截器链 可以将多个拦截器添加到链中,并通过registry.order(int)方法指定其优先级。优先级越高,拦截器越先执行。

(4)可选:排除特定路径 使用addPathPatternsexcludePathPatterns方法可以指定哪些URL路径应该被拦截,哪些应该被排除。

java 复制代码
registry.addInterceptor(new MyInterceptor())
    .addPathPatterns("/api/**") // 匹配/api/下的所有路径
    .excludePathPatterns("/api/login"); // 排除/api/login路径

2.8 Spring MVC拦截器和Servlet Filter有什么区别?

Spring MVC拦截器(HandlerInterceptor)和Servlet Filter都是用来增强请求处理的功能,但在作用范围、执行流程以及具体功能上有所不同:

作用范围

  • Spring MVC拦截器仅作用于Spring MVC框架内部,只对由Spring DispatcherServlet处理的请求生效。
  • Servlet Filter是对整个Servlet容器内的请求生效,不仅限于Spring MVC,包括其他基于Servlet的应用也可以拦截。

执行流程

  • Spring MVC拦截器在DispatcherServlet调用处理器之前和之后执行,以及视图渲染完成后执行,这些操作都位于Spring MVC的控制流中。
  • Servlet Filter是在ServletRequest对象被传递给下一个过滤器或目标servlet之前和之后执行。在Servlet容器层面,filter链是线性的,不像Spring MVC的拦截器有明确的前后关系。

功能与上下文

  • 拦截器可以访问Spring MVC的一些高级特性,如模型AndView对象、Spring Security的SecurityContextHolder等。
  • Filter则相对底层,它主要处理ServletRequest和ServletResponse对象,但可以实现任何HTTP级别的修改,比如改变字符编码、压缩响应内容、登录验证等。

2.9 指出Spring Security如何与Spring MVC拦截器协同工作

Spring Security可以通过多种方式与Spring MVC的拦截器协同工作,以提供安全相关的控制。以下是它们协作的基本过程:

(1)配置Filter Security Interceptor (FSI) : 在Spring Security配置类中,通常会定义一个FilterSecurityInterceptor bean。这个filter负责根据预设的安全规则(如访问决策管理器和权限表达式)检查HTTP请求。

java 复制代码
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and()
            .formLogin() // 添加其他安全设置...
    }
}

(2)Spring Security默认拦截所有请求 : FilterSecurityInterceptor 默认会被添加到Servlet容器的Filter链中,并在请求到达控制器之前运行。

(3)自定义拦截器与Spring Security集成: 可以创建自定义的Spring MVC拦截器来执行额外的操作,例如记录日志或者进行特定的安全检查。要确保自定义拦截器正常工作,需要注意其执行顺序。通常,安全相关的拦截器应排在前面。

(4)使用DelegatingFilterProxy与Spring MVC集成 : 为了将Spring Security Filter作为Spring MVC的一部分,你可以使用DelegatingFilterProxy注册Spring Security filter。这允许你在Spring应用上下文中管理Spring Security filter,而不是直接在web.xml中配置。

XML 复制代码
<bean id="springSecurityFilterChain" class="org.springframework.web.filter.DelegatingFilterProxy">
    <property name="targetBeanName" value="filterSecurityInterceptor"/>
</bean>

(5)调整拦截器顺序 : 使用Ordered接口或@Order注解来自定义拦截器的执行顺序。较低的数字表示较高的优先级,例如,@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)通常用于确保Spring Security过滤器先于其他自定义拦截器运行。

2.10.1 ResponseEntity**★★★★**

ResponseEntity 是 Spring MVC 中的一个类,用于构建 HTTP 响应。它允许你精确地控制响应的状态码、头部和主体。下面是一个简单的用法示例:

java 复制代码
@GetMapping("/example")
public ResponseEntity<String> handleExample() {
    String body = "This is a sample response";
    HttpHeaders headers = new HttpHeaders();
    headers.add("Custom-Header", "Value");

    return new ResponseEntity<>(body, headers, HttpStatus.OK);
}

在这个例子中:

  1. 创建了一个字符串 "This is a sample response" 作为响应体。
  2. 创建了 HttpHeaders 实例,并添加了一个自定义头部 "Custom-Header"
  3. 使用 HttpStatus.OK 设置响应状态码为 200。
  4. 将上述三个组件组合成一个 ResponseEntity 对象并返回。

2.10.2 ResponseEntity中包含了哪些重要属性?

ResponseEntity 是 Spring MVC 提供的一个类,它代表了一个完整的 HTTP 响应。以下是 ResponseEntity 的主要组成部分:

  1. Body: 这是响应的主体内容,可以是任何类型的数据,比如字符串、自定义对象、文件等。通常由泛型参数指定,如 ResponseEntity<String>ResponseEntity<MyClass>

  2. Status: 它表示响应的状态码,可以是 HttpStatus 类中的枚举值,或者直接传递一个整数,例如 HttpStatus.CREATED(201) 表示资源已成功创建。

  3. Headers: 包含了响应头部信息,可以通过 HttpHeaders 对象来设置。可以添加自定义的头信息,如 Content-Type、Location 等。

示例:

java 复制代码
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/example")
    public ResponseEntity<String> getExample() {
        String body = "Hello, this is a response!";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.TEXT_PLAIN);
        
        return ResponseEntity.status(HttpStatus.OK)
                .headers(headers)
                .body(body);
    }
}

2.11 RequestEntity

RequestEntity 类是 Spring WebFlux 和 Spring MVC 中的一部分,主要用于构建请求对象。它可以用来封装 HTTP 请求的所有关键部分,包括方法(GET, POST 等)、URL、头信息以及请求体。这是一个基本的使用示例:

java 复制代码
@PostMapping("/example")
public ResponseEntity<String> handlePost(@RequestBody RequestEntity<String> requestEntity) {
    String requestBody = requestEntity.getBody();
    HttpMethod method = requestEntity.getMethod();
    URI requestedUri = requestEntity.getUri();

    // 处理请求...
    
    return new ResponseEntity<>("Processed successfully", HttpStatus.OK);
}

在这个例子中:

  1. @PostMapping 注解定义了处理 POST 请求的方法。
  2. @RequestBody RequestEntity<String> 参数允许我们从请求中获取 RequestEntity 对象,其中 String 表示我们将接收请求体的内容。
  3. requestEntity.getBody() 获取请求体内容。
  4. requestEntity.getMethod() 返回请求的 HTTP 方法。
  5. requestEntity.getUri() 提供了请求的目标 URI。

2.12.1 自定义拦截器有哪些方式?★★★★

自定义拦截器通常有以下两种方式:

  1. 实现HandlerInterceptor接口:(推荐)

    java 复制代码
    public class CustomInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 方法执行前的操作,如身份验证、日志记录等
            return true; // 返回true表示继续处理请求,返回false则中断请求处理
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            // 方法执行后的操作,但此时视图还未渲染
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            // 请求完全处理后执行,包括视图渲染完成
        }
    }
  2. 继承AbstractHandlerInterceptorAdapter类(Spring框架的一种简化版拦截器实现):

    java 复制代码
    public class SimplifiedCustomInterceptor extends AbstractHandlerInterceptorAdapter {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 类似于上面的preHandle方法,但是代码结构更为简单
            return true;
        }
    
        // 不需要实现postHandle和afterCompletion方法,除非你需要使用它们
    }

注册拦截器可以通过以下两种方式:

  1. 实现WebMvcConfigurer接口:

    java 复制代码
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Autowired
        private CustomInterceptor customInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(customInterceptor)
                .addPathPatterns("/path/to/match")
                .excludePathPatterns("/path/to/exclude");
        }
    }
  2. 使用@Bean注解声明拦截器并在WebMvcConfigurationSupport子类中注册:

    java 复制代码
    @Configuration
    public class WebConfig extends WebMvcConfigurationSupport {
        @Autowired
        private CustomInterceptor customInterceptor;
    
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(customInterceptor)
                .addPathPatterns("/path/to/match")
                .excludePathPatterns("/path/to/exclude");
        }
    
        @Bean
        public CustomInterceptor customInterceptor() {
            return new CustomInterceptor();
        }
    }

2.12.2 自定义拦截器中的`preHandle()`、`postHandle()`和`afterCompletion()`分别在什么阶段执行?

自定义拦截器中的preHandle()postHandle()afterCompletion()这三个方法分别在以下阶段执行:

  1. preHandle():此方法在DispatcherServlet调用目标处理器之前执行,主要用于进行权限校验、日志记录或者数据预处理等工作。如果这个方法返回false,那么请求处理将被终止;如果返回true,则将继续执行后续的拦截器以及目标处理器。

  2. postHandle():此方法在DispatcherServlet调用目标处理器之后,但在视图渲染之前执行。可以在这个方法里对ModelAndView对象进行修改,或者做一些其他的数据处理工作。

  3. afterCompletion():此方法在整个请求处理完成后执行,即视图渲染完毕后。它主要用来进行资源清理或者一些善后工作,例如关闭数据库连接、释放缓存等。

preHandle

该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。

postHandle

该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。

afterCompletion

当preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据等。

2.12.3 ​​​​​​​拦截器的应用场景

  • 日志记录:记录请求信息的日志
  • 权限检查,如登录检查
  • 性能检测:检测方法的执行时间
相关推荐
2402_8575893627 分钟前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
吾爱星辰1 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
哎呦没2 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
编程、小哥哥2 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
IT学长编程3 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
杨哥带你写代码3 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
郭二哈4 小时前
C++——模板进阶、继承
java·服务器·c++
A尘埃4 小时前
SpringBoot的数据访问
java·spring boot·后端
yang-23074 小时前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端