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 ​​​​​​​拦截器的应用场景

  • 日志记录:记录请求信息的日志
  • 权限检查,如登录检查
  • 性能检测:检测方法的执行时间
相关推荐
考虑考虑38 分钟前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干1 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
hqxstudying1 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·1 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
Bug退退退1232 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠2 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
Zz_waiting.3 小时前
Javaweb - 10.4 ServletConfig 和 ServletContext
java·开发语言·前端·servlet·servletconfig·servletcontext·域对象
全栈凯哥3 小时前
02.SpringBoot常用Utils工具类详解
java·spring boot·后端
兮动人3 小时前
获取终端外网IP地址
java·网络·网络协议·tcp/ip·获取终端外网ip地址
呆呆的小鳄鱼3 小时前
cin,cin.get()等异同点[面试题系列]
java·算法·面试