SpringMVC全面复习

Javaweb

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

SpringMVC

Spring MVC是Spring框架的一个模块,专门用于构建Web应用程序的模型-视图-控制器(MVC)架构。它通过清晰的分离关注点,简化了Web应用各部分的开发。Spring MVC提供了强大的绑定机制,能够将请求参数绑定到控制器方法的参数上,支持灵活的验证和数据转换。它还内置了对RESTful API的支持,使得开发者可以轻松构建REST风格的Web服务。Spring MVC的分发器DispatcherServlet负责将请求路由到相应的控制器,而视图解析器则负责渲染响应的视图。此外,Spring MVC与Spring的其他模块如Spring Security和Spring Data无缝集成,提供了全面的安全、数据访问和事务管理功能,使得构建健壮、可维护的Web应用程序变得更加容易。

在这里插入图片描述
在这里插入图片描述
导入Spring整合SpringMVC的坐标

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.3.7</version>
</dependency>

创建Spring的配置文件applicationContext.xml,配置Spring包扫描

<context:component-scan base-package="com.mem.service"/>

在web.xml中配置SpringMVC的前端控制器ServletDispatcher

<!-- 创建Servlet WebApplicationContext容器的配置 -->
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <!--加载Spring MVC的配置文件-->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <!--
    可以设置该servlet在加载时的优先级以及是否在容器中加载该servlet
    Tomcat依次执行的是DispatcherServlet中的静态代码块,构造方法,init()方法
    -->
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

这里的/表示这是一个根路径模式,意味着DispatcherServlet将映射到应用的根路径,并且可以处理进入应用的所有HTTP请求。
编写一个控制器Controller,配置映射信息,并交给SpringMVC容器管理

@Controller//交给spring容器进行管理
public class QuickController {
    @RequestMapping("/show")//配置映射路径
    public void show(){
        System.out.println("show ...");
    }
}

在这里插入图片描述
控制台正常打印show …
报错原因:show()方法应该返回视图名字
改进: 将controller层中的show()方法返回值改为String,并添加上相应的页面

@Controller
public class QuickController {
    @RequestMapping("/show")
    public String show(){
        System.out.println("show ...");
        return "/show.jsp";
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title></title>
</head>
<body>
    <h1>show</h1>
</body>
</html>

Controller中访问容器中的Bean
创建service层

public interface QuickService {
}

@Service
public class QuickServiceImpl implements QuickService {
}

创建Spring的配置文件applicationContext.xml,配置Spring包扫描

<!--组件扫描-->
<context:component-scan base-package="com.mem.service"/>

在web.xml中配置ContextLoadListener及初始参数

<!-- 创建Root WebApplicationContext容器的配置 -->
<!--加载Spring的配置文件-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--配置ContextLoaderListener(官方提供的)-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

在Controller层注入QuickService对象

@Controller
public class QuickController {

    @Autowired
    private QuickService quickService;

    @RequestMapping("/show")
    public String show(){
        System.out.println("show ...");
        System.out.println("quickService:"+quickService);
        return "/show.jsp";
    }
}

测试:控制台打印出quickService的地址quickService:com.mem.service.impl.QuickServiceImpl@5f87226c
Spring笔记(四)(黑马)(web层解决方案-SpringMVC)
在这里插入图片描述
SpringMVC关键组件浅析
在这里插入图片描述
在这里插入图片描述
SpringMVC的默认组件,SpringMVC 在前端控制器 DispatcherServlet加载时,就会进行初始化操作,在进行初始化时,就会加载SpringMVC默认指定的一些组件,这些默认组件配置在 DispatcherServlet.properties 文件中,该文件存在与spring-webmvc-5.3.7.jar包下的 org\springframework\web\servlet\DispatcherServlet.properties
在这里插入图片描述
这些默认的组件是在DispatcherServlet中进行初始化加载的,在DispatcherServlet中存在集合存储着这些组件, SpringMVC的默认组件会在 DispatcherServlet 中进行维护,但是并没有存储在与SpringMVC的容器中

public class DispatcherServlet extends FrameworkServlet {
    //存储处理器映射器
    private List<HandlerMapping> handlerMappings;
    //存储处理器适配器
    private List<HandlerAdapter> handlerAdapters;
    //存储视图解析器
    private List<ViewResolver> viewResolvers;
    // ... 省略其他代码 ...

    protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context); // 以这个为例
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }
    private void initHandlerMappings(ApplicationContext context) {
    	// 获取DispatcherServlet.properties文件中的三个类
        this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
    }
}

配置组件代替默认组件,如果不想使用默认组件,可以将替代方案使用Spring Bean的方式进行配置,例如,在 spring-mvc.xml中配置RequestMappingHandlerMapping

<!--使用自定义的HandlerMapping,替代默认的HandlerMapping-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

当我们在Spring容器中配置了HandlerMapping,则就不会在加载默认的HandlerMapping策略了,原理比较简单, DispatcherServlet 在进行HandlerMapping初始化时,先从SpringMVC容器中找是否存在HandlerMapping,如果 存在直接取出容器中的HandlerMapping,在存储到 DispatcherServlet 中的handlerMappings集合中去。

Spring MVC 的请求处理
在这里插入图片描述
@RequestMapping注解,主要使用在控制器的方法上,用于标识客户端访问资源路径,常用的属性有value、path 、method、headers、params等。当@RequestMapping只有一个访问路径需要指定时,使用value属性、path属 性或省略value和path,当有多个属性时,value和path不能省略

@RequestMapping(value = "/show")//使用value属性指定一个访问路径
public String show(){}
@RequestMapping(value = {"/show","/haohao","/abc"})//使用value属性指定多个访问路径
public String show(){}
@RequestMapping(path = "/show")//使用path属性指定一个访问路径
public String show(){}
@RequestMapping(path = {"/show","/haohao","/abc"})//使用path属性指定多个访问路径
public String show(){}
@RequestMapping("/show")//如果只设置访问路径时,value和path可以省略
public String show(){}
@RequestMapping({"/show","/haohao","/abc"})
public String show(){}

当@RequestMapping 需要限定访问方式时,可以通过method属性设置

//请求地址是/show,且请求方式必须是POST才能匹配成功
@RequestMapping(value = "/show",method = RequestMethod.POST)
public String show(){}

@GetMapping
当请求方式是GET时,我们可以使用@GetMapping替代@RequestMapping
@PostMapping
当请求方式是POST时,我们可以使用@PostMapping替代@RequestMapping
@RequestMapping 在类上使用,@RequestMapping 、@GetMapping、@PostMapping还可以使用在 Controller类上,使用在类上后,该类所有方法都公用该@RequestMapping设置的属性,访问路径则为类上的映射 地址+方法上的映射地址,例如:

@Controller
@RequestMapping("/xxx")
public class UserController implements ApplicationContextAware, ServletContextAware {
    @GetMapping("/aaa")
    public ModelAndView aaa(HttpServletResponse response) throws IOException, ModelAndViewDefiningException {
        return null;
    }
}

请求数据的接收
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
客户端传递多个同名参数时,也可以使用单列集合接收,但是需要使用@RequestParam告知框架传递的参数是要同名设置的,不是对象属性设置的
在这里插入图片描述
在这里插入图片描述
收实体JavaBean属性数据
接收实体JavaBean属性数据,单个JavaBean数据:提交的参数名称只要与Java的属性名一致,就可以进行自动封装

public class User {
    private String username;
    private Integer age;
    private String[] hobbies;
    private Date birthday;
    private Address address;
    //... 省略get和set方法 ... 
}
public class Address {
    private String city;
    private String area;
}

@GetMapping("/show")
public String show(User user){
	System.out.println(user);
    return "/index.jsp";
}

接收Json数据格式数据
接收Json数据格式数据,Json数据都是以请求体的方式提交的,且不是原始的键值对格式的,所以我们要使用 @RequestBody注解整体接收该数据。

@PostMapping("/show")
public String show((@RequestBody String body){
    System.out.println(body);
    return "/index.jsp";
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
使用Rest风格:
接收Restful风格数据,Restful请求数据一般会在URL地址上携带,可以使用注解 @PathVariable(占位符参数名称)
http://localhost:8080/user/100

@PostMapping("/user/{id}")
public String findUserById(@PathVariable("id") Integer id){
    System.out.println(id);
    return "/index.jsp";
}

请求URL资源地址包含多个参数情况:http://localhost:8080/user/haohao/18

@PostMapping("/user/{username}/{age}")
public String findUserByUsernameAndAge(@PathVariable("username") String username,
                                       @PathVariable("age") Integer age){
    System.out.println(username+"=="+age);
    return "/index.jsp";
}

在这里插入图片描述
服务器端,由于映射器适配器需要文件上传解析器,而该解析器默认未被注册,所以手动注册

<!--配置文件上传解析器,注意:id的名字是固定写法-->
<bean id="multipartResolver" 
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  <property name="defaultEncoding" value="UTF-8"/><!--文件的编码格式 默认是ISO8859-1-->
  <property name="maxUploadSizePerFile" value="1048576"/><!--上传的每个文件限制的大小 单位字节-->
  <property name="maxUploadSize" value="3145728"/><!--上传文件的总大小-->
  <property name="maxInMemorySize" value="1048576"/><!--上传文件的缓存大小-->
</bean>

而CommonsMultipartResolver底层使用的Apache的是Common-fileuplad等工具API进行的文件上传

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.4</version>
</dependency>

使用MultipartFile类型接收上传文件

@PostMapping("/fileUpload")
public String fileUpload(@RequestBody MultipartFile myFile) throws IOException {
    System.out.println(myFile);
    //获得上传的文件的流对象
    InputStream inputStream = myFile.getInputStream();
    //使用commons-io存储到C:\haohao\abc.txt位置
    FileOutputStream outputStream = new FileOutputStream("C:\\Users\\haohao\\"+myFile.getOriginalFilename());
    IOUtils.copy(inputStream,outputStream);
    //关闭资源
    inputStream.close();
    outputStream.close();
return "/index.jsp";
}

若接收多个文件,变为数组即可

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
Javaweb常用对象的获取
获得Javaweb常见原生对象,有时在我们的Controller方法中需要用到Javaweb的原生对象,例如:Request、 Response等,我们只需要将需要的对象以形参的形式写在方法上,SpringMVC框架在调用Controller方法时,会自动传递实参:

@GetMapping("/javawebObject")
public String javawebObject(HttpServletRequest request, HttpServletResponse response, 
HttpSession session){
    System.out.println(request);
    System.out.println(response);
    System.out.println(session);
    return "/index.jsp";
}

请求静态资源
静态资源请求失效的原因,当DispatcherServlet的映射路径配置为 / 的时候,那么就覆盖的Tomcat容器默认的缺省 Servlet在Tomcat的config目录下有一个web.xml 是对所有的web项目的全局配置,其中有如下配置
在这里插入图片描述

url-pattern配置为 / 的Servlet我们称其为缺省的Servlet,作用是:当其他Servlet都匹配不成功时,就找缺省的Servlet ,静态资源由于没有匹配成功的Servlet,所以会找缺省的DefaultServlet,该DefaultServlet具备二次去匹配静态资源的功能。但是我们配置DispatcherServlet后就将其覆盖掉了,而DispatcherServlet会将请求的静态资源的名称当成Controller的映射路径去匹配,即静态资源访问不成功了!
第一种方案:
在web.xml中,可以再次激活Tomcat的DefaultServlet,Servlet的url-pattern的匹配优先级是:精确匹配>目录匹配> 扩展名匹配>缺省匹配,所以可以指定某个目录下或某个扩展名的资源使用DefaultServlet进行解析:
在这里插入图片描述
在这里插入图片描述
注解驱动mvc:annotation-driven标签
静态资源配置的第二第三种方式我们可以正常访问静态资源了,但是Controller又无法访问了,报错404,即找不到对应的资源
在这里插入图片描述
又结合组件浅析知识点,一旦SpringMVC容器中存在 HandlerMapping 类型的组件时,前端控制器 DispatcherServlet在进行初始化时,就会从容器中获得HandlerMapping ,不在加载 dispatcherServlet.properties 中默认处理器映射器策略,那也就意味着RequestMappingHandlerMapping不会被加载到了。

RequestMappingHandlerMapping的作用是:解析@RequestMapping(“”)注解的,最后容器中没有RequestMappingHandlerMapping的bean 也就没办法识别里面的内容了

解决方法:
手动将RequestMappingHandlerMapping也注册到SpringMVC容器中就可以了,这样DispatcherServlet在进行初始化时,就会从容器中同时获得RequestMappingHandlerMapping存储到DispatcherServlet中名为 handlerMappings的List集合中,对@RequestMapping 注解进行解析。

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

根据上面的讲解,可以总结一下,要想使用@RequestMapping正常映射到资源方法,同时静态资源还能正常访问, 还可以将请求json格式字符串和JavaBean之间自由转换,我们就需要在spring-mvc.xml中进行如下配置:

<!--使用RequestMappingHandlerAdapter,内部添加messageConverters: 实现遇到json格式自动转换为对象格式-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        </list>
    </property>
</bean>

在这里插入图片描述

PS: mvc:annotation-driven/ 标签在不同的版本中,帮我们注册的组件不同。
Spring 3.0.X 版本注册是 DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter,由于框架的发展,从Spring 3.1.X 开始注册组件变为 RequestMappingHandlerMapping和RequestMappingHandlerAdapter

Spring MVC 的响应处理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
响应模型数据,响应模型数据本质也是转发,在转发时可以准备模型数据

@RequestMapping("/resp3")
public ModelAndView resp3(ModelAndView modelAndView){
    // ModelAndView封装模型数据和视图名
    // 设置模型数据
    User user = new User();
    user.setUsername("haohao");
    user.setAge(18);
    modelAndView.addObject("user",user);
    // 设置试图名,在页面中展示模型数据
    modelAndView.setViewName("/show.jsp");
    return modelAndView;
}

直接回写数据,直接通过方法的返回值返回给客户端的字符串,但是SpringMVC默认的方法返回值是视图,可以通过 @ResponseBody 注解显示的告知此处的返回值不要进行视图处理,是要以响应体的方式处理的

@RequestMapping("/resp4")
@ResponseBody
public String resp4(){
    return "hello world!";
}

前后端分类异步业务数据响应
在这里插入图片描述
回写Json格式的字符串,即将直接拼接Json格式的字符串或使用工具将JavaBean转换成Json格式的字符串回写

@GetMapping("/ajax/resp1")
@ResponseBody
public String resp1(){
    return "{\"username\":\"haohao\",\"age\":18}";
}

@GetMapping("/ajax/resp2")
@ResponseBody
public String resp2() throws JsonProcessingException {
    //创建JavaBean
    User user = new User();
    user.setUsername("haohao");
    user.setAge(19);
    //使用Jackson转换成json格式的字符串
    String json = new ObjectMapper().writeValueAsString(user);
    return json;
}

在讲解SringMVC接收请求数据时,客户端提交的Json格式的字符串,也是使用Jackson进行的手动转换成JavaBean ,可以当我们使用了@RequestBody时,直接用JavaBean就接收了Json格式的数据,原理其实就是SpringMVC底层 帮我们做了转换,此处@ResponseBody也可以将JavaBean自动给我们转换成Json格式字符串回响应

@GetMapping("/ajax/resp3")
@ResponseBody
public User resp3() throws JsonProcessingException {
    //创建JavaBean
    User user = new User();
    user.setUsername("haohao");
    user.setAge(20);
    //直接返回User对象
    return user;
}

进一步优化,可以使用@RestController替代@Controller和@ResponseBody,@RestController内部具备的这两个 注解的功能

@RestController
public class ResponseController2 {


    @GetMapping("/ajax/resp1")
    //    @ResponseBody
    public String resp1(){
        return "{\"username\":\"haohao\",\"age\":18}";
    }

    @GetMapping("/ajax/resp2")
    //    @ResponseBody
    public String resp2() throws JsonProcessingException {
        //创建JavaBean
        User user = new User();
        user.setUsername("haohao");
        user.setAge(19);
        //使用Jackson转换成json格式的字符串
        String json = new ObjectMapper().writeValueAsString(user);
        return json;
    }
}

Spring MVC 的拦截器
在这里插入图片描述
在这里插入图片描述
实现了HandlerInterceptor接口,且被Spring管理的Bean都是拦截器,接口定义如下:

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 {
    }
}

在这里插入图片描述
拦截器快速入门

public class MyInterceptor1 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Controller方法执行之前...");
        return true; // 放行
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Controller方法执行之后...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("渲染视图结束,整个流程完毕...");
    }
}

在spring-mvc.xml中, 配置Interceptor

<!--配置拦截器-->
<mvc:interceptors>
  <mvc:interceptor>
    <!--配置对哪些资源进行拦截操作-->
    <mvc:mapping path="/**"/>
    <bean class="com.mem.interceptor.MyInterceptor1"></bean>
  </mvc:interceptor>
</mvc:interceptors>

controller层,业务代码

// 测试拦截器
@RequestMapping("/interceptor_req")
public String interceptor_req(){
    System.out.println("interceptor_req ...");
    return "/show.jsp";
}
Controller方法执行之前...
interceptor_req ...
Controller方法执行之后...
渲染视图结束,整个流程完毕...

拦截器执行顺序
在这里插入图片描述
在这里插入图片描述
Spring MVC 的全注解开发
跟之前全注解开发思路一致, xml配置文件使用核心配置类替代,xml中的标签使用对应的注解替代

<!--1. 组件扫描 -->
<!--组件扫描web层-->
<context:component-scan base-package="com.mem.controller"/>

<!--2. 非自定义的Bean -->
<!--配置文件上传解析器,注意:id的名字是固定写法-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  <property name="defaultEncoding" value="UTF-8"/><!--文件的编码格式 默认是ISO8859-1-->
  <property name="maxUploadSizePerFile" value="1048576"/><!--上传的每个文件限制的大小 单位字节-->
  <property name="maxUploadSize" value="3145728"/><!--上传文件的总大小-->
  <property name="maxInMemorySize" value="1048576"/><!--上传文件的缓存大小-->
</bean>

<!--3.Bean的配置 -->
<!--访问静态资源的方式3:底层注册一个DefaultServletHttpRequestHandler 来处理静态资源-->
<mvc:default-servlet-handler/>
<!--mvc的注解驱动-->
<mvc:annotation-driven/>
<!--配置拦截器-->
<mvc:interceptors>
  <mvc:interceptor>
    <!--配置对哪些资源进行拦截操作-->
    <mvc:mapping path="/**"/>
    <bean class="com.mem.interceptor.MyInterceptor1"></bean>
  </mvc:interceptor>
</mvc:interceptors>

第一步,第二步,可以利用之前所学的spring的配置类来搞定
组件扫描,可以通过@ComponentScan注解完成;
文件上传解析器multipartResolver可以通过非自定义Bean的注解配置方式,即@Bean注解完成

@Configuration
// <context:component-scan base-package="com.mem.controller"/>
@ComponentScan("com.mem.controller")
public class SpringMVCConfig {
    /**
     * <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
     *     <property name="defaultEncoding" value="UTF-8"/><!--文件的编码格式 默认是ISO8859-1-->
     *     <property name="maxUploadSizePerFile" value="1048576"/><!--上传的每个文件限制的大小 单位字节-->
     *     <property name="maxUploadSize" value="3145728"/><!--上传文件的总大小-->
     *     <property name="maxInMemorySize" value="1048576"/><!--上传文件的缓存大小-->
     * </bean>
     */
    @Bean
    public CommonsMultipartResolver multipartResolver(){
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setDefaultEncoding("UTF-8");
        multipartResolver.setMaxUploadSizePerFile(1048576);
        multipartResolver.setMaxUploadSize(3145728);
        multipartResolver.setMaxInMemorySize(1048576);
        return multipartResolver;
    }
}

第三步,非Bean的配置(mvc:default-servlet-handler/、mvc:annotation-driven/、mvc:interceptors) 该怎么办呢?
SpringMVC 提供了一个注解@EnableWebMvc,我们看一下源码,内部通过@Import导入了DelegatingWebMvcConfiguration类

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
	// 从容器中注入 WebMvcConfigurer 类型的Bean
    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }
}

首先先看下父类WebMvcConfigurationSupport:

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
	// 将 RequestMappingHandlerMapping 放入容器
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
        @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, 
        @Qualifier("mvcConversionService") FormattingConversionService conversionService, 
        @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        RequestMappingHandlerMapping mapping = this.createRequestMappingHandlerMapping();
        // 中间省略
        return mapping;
    }

    // 将 RequestMappingHandlerAdapter 放入容器
    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
        @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, 
        @Qualifier("mvcConversionService") FormattingConversionService conversionService, 
        @Qualifier("mvcValidator") Validator validator) {
        RequestMappingHandlerAdapter adapter = this.createRequestMappingHandlerAdapter();
        return adapter;
    }
}

这一步的效果等同于mvc:annotation-driven/注解驱动
实现:
创建MyWebMvcConfigurer实现WebMvcConfigurer接口,实现addInterceptors 和 configureDefaultServletHandling方法

@Component
public class MyWebMvcConfigurer implements WebMvcConfigurer {
    // 替代 <mvc:interceptors>
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 创建拦截器对象,进行注册
        // Interceptor 的执行顺序也取决于添加顺序
        registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**");
    }

    // 替代 <mvc:default-servlet-handler/>
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        // 开启DefaultServlet,就可以处理静态资源了
        configurer.enable();
    }
}

最后,在SpringMVC核心配置类上添加@EnableWebMvc注解

@Configuration
// <context:component-scan base-package="com.mem.controller"/>
@ComponentScan("com.mem.controller")
@EnableWebMvc
public class SpringMVCConfig {
    /**
     * <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
     *     <property name="defaultEncoding" value="UTF-8"/><!--文件的编码格式 默认是ISO8859-1-->
     *     <property name="maxUploadSizePerFile" value="1048576"/><!--上传的每个文件限制的大小 单位字节-->
     *     <property name="maxUploadSize" value="3145728"/><!--上传文件的总大小-->
     *     <property name="maxInMemorySize" value="1048576"/><!--上传文件的缓存大小-->
     * </bean>
     */
    @Bean
    public CommonsMultipartResolver multipartResolver(){
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setDefaultEncoding("UTF-8");
        multipartResolver.setMaxUploadSizePerFile(1048576);
        multipartResolver.setMaxUploadSize(3145728);
        multipartResolver.setMaxInMemorySize(1048576);
        return multipartResolver;
    }
}

DispatcherServlet 加载核心配置类
现在是使用SpringMVCConfig核心配置类替代了spring-mvc.xml,怎么加载呢?

<!-- 创建Servlet WebApplicationContext容器的配置 -->
<servlet>
  <servlet-name>DispatcherServlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <!--加载Spring MVC的核心配置文件-->
  <!--        <init-param>-->
  <!--            <param-name>contextConfigLocation</param-name>-->
  <!--            <param-value>classpath:spring-mvc.xml</param-value>-->
  <!--        </init-param>-->
  <!--加载Spring MVC的核心配置类-->
  <init-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </init-param>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.mem.config.SpringMVCConfig</param-value>
  </init-param>
  <!--
  可以设置该servlet在加载时的优先级以及是否在容器中加载该servlet
  Tomcat依次执行的是DispatcherServlet中的静态代码块,构造方法,init()方法
  -->
  <load-on-startup>2</load-on-startup>
</servlet>

方法2: 参照Spring的 ContextLoaderListener加载核心配置类的做法,定义了一个AnnotationConfigWebApplicationContext,通过 代码注册核心配置类
在这里插入图片描述
Spring MVC 的组件原理刨析
前端控制初始化
在这里插入图片描述
在这里插入图片描述
结论:SpringMVC 的ApplicationContext容器创建时机,Servlet 规范的 init(ServletConfig config) 方法经过子类重写 ,最终会调用 FrameworkServlet 抽象类的initWebApplicationContext() 方法,该方法中最终获得 一个根 Spring容器(Spring产生的),一个子Spring容器(SpringMVC产生的)。
Spring MVC 的异常处理机制
在这里插入图片描述
在这里插入图片描述
SpringMVC的异常处理方式
在这里插入图片描述
初始化:
新建一个异常测试Controller:

@RestController
public class ExceptionController {
    /**
     * 模拟运行时异常
     * @return
     */
    @RequestMapping("/exception1")
    public String exceptionMethod1(){
        int i = 1/0;
        return "Hello Exception";
    }
    /**
     * 模拟编译异常
     * @return
     */
    @RequestMapping("/exception2")
    public String exceptionMethod2() throws FileNotFoundException {
        FileInputStream inputStream = new FileInputStream("C:/xx/xx/xx.xx");
        return "Hello Exception";
    }
}

改善1:加上简单异常处理器(SimpleMappingExceptionResolver),对不同的异常进行不同的跳转友好页面,操作如下
在配置类上加一个SimpleMappingExceptionResolver类型的Bean

@Configuration
@ComponentScan("com.mem.controller")
@EnableWebMvc
public class SpringMVCConfig {
    // 配置简单的异常处理器类
    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        // 不管是什么异常,统一的响应一个友好页面
        //        simpleMappingExcepti
        onResolver.setDefaultErrorView("/error1.html");
        // 区分异常类型,根据不同的异常类型,跳转不同的视图
        Properties properties = new Properties();// 键值对,key:异常的全限定名,value:跳转的视图名
        properties.setProperty("java.lang.RuntimeException","/error1.html");
        properties.setProperty("java.io.FileNotFoundException","/error2.html");
        simpleMappingExceptionResolver.setExceptionMappings(properties);
        return simpleMappingExceptionResolver;
    }
}

添加错误页面
在这里插入图片描述

改善2:自定义异常处理器,实现HandlerExceptionResolver接口,操作如下:
添加自定义异常处理器类

@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    /**
     *
     * @param request 请求
     * @param response 响应
     * @param handler Controller层的方法的封装
     * @param e 异常,可以用于判断
     * @return
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
        System.out.println("request:"+request);
        System.out.println("response:"+response);
        System.out.println("handler:"+handler);
        System.out.println("e:"+e);

        // 1. 可以简单的响应一个友好的提示页面
        ModelAndView modelAndView = new ModelAndView();
        if(e instanceof RuntimeException ){
            modelAndView.setViewName("/error1.html");
        }else{
            modelAndView.setViewName("/error2.html");
        }
        return modelAndView;
    }
}

自定义异常处理器还可以以json形式返回:
修改MyHandlerExceptionResolver的resolveException方法:

@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    /**
     *
     * @param request 请求
     * @param response 响应
     * @param handler Controller层的方法的封装
     * @param e 异常,可以用于判断
     * @return
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
        System.out.println("request:"+request);
        System.out.println("response:"+response);
        System.out.println("handler:"+handler);
        System.out.println("e:"+e);

        // 1. 可以简单的响应一个友好的提示页面
        //        ModelAndView modelAndView = new ModelAndView();
        //        if(e instanceof RuntimeException ){
        //            modelAndView.setViewName("/error1.html");
        //        }else{
        //            modelAndView.setViewName("/error2.html");
        //        }

        // 2. 前后端分离开发,响应json格式的字符串 {"code": 200,"message":"","data":{"username":"haohao","age":18}}
        String resultJson = "{\"code\": 500,\"message\":\"异常\",\"data\":{\"username\":\"haohao\",\"age\":18}}";
        try {
            response.getWriter().write(resultJson);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return null;
    }
}

改善3:使用注解的方式,更加灵活(常用)
新建类(ExceptionByAnno):

@ControllerAdvice
public class ExceptionByAnno {

    @ExceptionHandler(RuntimeException.class)
    public ModelAndView RuntimeExceptionResolverMethod(Exception exception){
        System.out.println("exception:"+exception); // exception:java.lang.ArithmeticException: / by zero
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/error1.html");
        return modelAndView;
    }

    @ExceptionHandler(IOException.class)
    @ResponseBody
    public Result IOExceptionResolverMethod(Exception exception){
        System.out.println("exception:"+exception); // exception:java.io.FileNotFoundException: C:\xx\xx\xx.xx (系统找不到指定的路径。)
        Result result = new Result(500,"","");
        return result;
    }

    @ExceptionHandler(FileNotFoundException.class)
    public ModelAndView FileNotFoundExceptionResolverMethod(Exception exception){
        System.out.println("exception:"+exception); // exception:java.io.FileNotFoundException: C:\xx\xx\xx.xx (系统找不到指定的路径。)
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/error2.html");
        return modelAndView;
    }
}

SpringMVC 常用的异常解析器
在这里插入图片描述
HandlerExceptionResolverComposite 是一个组合体,内部包含了ExceptionHandlerExceptionResolver + DefaultHandlerExceptionResolver + ResponseStatusExceptionResolver三个解析器
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【再谈设计模式】抽象工厂模式~对象创建的统筹者

一、引言 在软件开发的世界里&#xff0c;高效、灵活且易于维护的代码结构是每个开发者追求的目标。设计模式就像是建筑蓝图中的经典方案&#xff0c;为我们提供了应对各种常见问题的有效策略。其中&#xff0c;抽象工厂模式在对象创建方面扮演着重要的角色&#xff0c;它如同一…

【Linux】ELF可执行程序和动态库加载

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…

SpringBootCloud 服务注册中心Nacos对服务进行管理

介绍 Nacos&#xff08;Naming and Configuration Service&#xff09;是一个开源的、动态的服务发现、配置管理和服务管理平台&#xff0c;特别适用于云原生应用和微服务架构。它可以作为服务注册中心&#xff0c;用于微服务的注册、发现、配置管理等。在微服务架构中&#x…

八款局域网监控软件优选|2024最新排行榜(企业老板收藏篇)

在当今数字化办公的时代&#xff0c;企业和组织对于局域网电脑监控的需求日益增长。无论是为了保障信息安全、提高员工工作效率&#xff0c;还是为了规范网络行为&#xff0c;一款优秀的局域网电脑监控软件都能发挥重要作用。市面上的监控软件种类繁多&#xff0c;功能各异&…

限价订单簿中的高频交易

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

丹摩征文活动|CogVideoX-2b:从0到1,轻松完成安装与部署!

丹摩征文活动 | CogVideoX-2b&#xff1a;从0到1&#xff0c;轻松完成安装与部署&#xff01; CogVideoX 介绍 CogVideoX的问世&#xff0c;标志着视频制作技术迈入了一个全新的时代。它不仅打破了传统视频制作在效率与质量之间的平衡难题&#xff0c;还通过其先进的3D变分自…

Creo 9.0 中文版软件下载安装教程

[软件名称]&#xff1a;Creo 9.0 [软件语言]&#xff1a;简体中文 [软件大小]&#xff1a;5.2G [安装环境]&#xff1a;Win11/Win10/ [硬件要求]&#xff1a;内存8G及以上 下载方法&#xff1a;电脑打开浏览器&#xff0c;复制下载链接&#xff0c;粘贴至浏览器网址栏&…

RT-DETR融合CVPR[2024]无膨胀多尺度卷积PKI模块及相关改进思路

RT-DETR使用教程&#xff1a; RT-DETR使用教程 RT-DETR改进汇总贴&#xff1a;RT-DETR更新汇总贴 《Poly Kernel Inception Network for Remote Sensing Detection》 一、 模块介绍 论文链接&#xff1a;https://arxiv.org/abs/2403.06258 代码链接&#xff1a;https://github…

ubuntu-desktop-24.04上手指南(更新阿里源、安装ssh、安装chrome、设置固定IP、安装搜狗输入法)

ubuntu-desktop-24.04上手指南(更新阿里源、安装ssh、安装chrome、设置固定IP、安装搜狗输入法) 一、更新并安装基础软件 #切换root用户 sudo su -#更新 apt update #升级 apt upgrade#install vim apt install vim#install net-tools apt install net-tools二、安装ssh并设置…

[CKS] K8S ServiceAccount Set Up

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于Rolebinding的题目。 ​ 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS] K8S Netwo…

介绍和安装及数据类型

1、介绍和安装 1.1、简介 ClickHouse是俄罗斯的Yandex于2016年开源的列式存储数据库&#xff08;DBMS&#xff09;&#xff0c;使用C语言编写&#xff0c;主要用于在线分析处理查询&#xff08;OLAP&#xff09;&#xff0c;能够使用SQL查询实时生成分析数据报告。 OLAP&…

算法魅力-二分查找实战

目录 前言 算法定义 朴素二分模版 二分查找 二分的边界查找 在排序数组中查找元素的第一个和最后一个位置&#xff08;medium&#xff09; 暴力算法 二分查找 边界查找分析 山峰数组的峰顶 暴力枚举 二分查找 搜索旋转排序数组中的最小值&#xff08;medium&#xf…

Linux第四讲:Git gdb

Linux第四讲&#xff1a;Git && gdb 1.版本控制器Git1.1理解版本控制1.2理解协作开发1.3Git的历史1.4Git的操作1.4.1仓库创建解释、仓库克隆操作1.4.2本地文件操作三板斧1.4.3文件推送详细问题 2.调试器 -- gdb/cgdb使用2.1调试的本质是什么2.2watch命令2.3set var命令…

海底捞点单

单点锅底推荐&#xff1a; 番茄锅底通31 牛油麻辣通44 清汤麻辣备44 菌汤锅底通31 小吃&主食&#xff1a; 捞派捞面一黄金小馒头一茴香小油条 红糖枇杷一小酥肉 DIY锅底推荐&#xff1a; 1.寿喜锅&#xff1a;海鲜味酱4勺陈醋1勺蚝油2勺盐适量白糖7勺 芹菜1勺 2.麻辣锅底…

PNG图片批量压缩exe工具+功能纯净+不改变原始尺寸

小编最近有一篇png图片要批量压缩&#xff0c;大小都在5MB之上&#xff0c;在网上找了半天要么就是有广告&#xff0c;要么就是有毒&#xff0c;要么就是功能复杂&#xff0c;整的我心烦意乱。 于是我自己用python写了一个纯净工具&#xff0c;只能压缩png图片&#xff0c;没任…

达梦8数据库适配ORACLE的8个参数

目录 1、概述 1.1 概述 1.2 实验环境 2、参数简介 3、实验部分 3.1 参数BLANK_PAD_MODE 3.2 参数COMPATIBLE_MODE 3.3 参数ORDER_BY_NULLS_FLAG 3.4 参数DATETIME_FMT_MODE 3.5 参数PL_SQLCODE_COMPATIBLE 3.6 参数CALC_AS_DECIMAL 3.7 参数ENABLE_PL_SYNONYM 3.8…

如何低成本、零代码开发、5分钟内打造一个企业AI智能客服?

传统客服因员工效率低、时段需求波动大、数据管理费时费力等管理难题&#xff0c;导致难以满足用户需求&#xff0c;无法深入挖掘客服数据价值&#xff0c;造成客源流失。而智能体搭建的“智能客服”能借助大模型和知识库知识&#xff0c;助力实现数字化运营&#xff0c;破解企…

CC1链学习记录

&#x1f338; 前言 上篇文章学习记录了URLDNS链&#xff0c;接下来学习一下Common-Colections利用链。 &#x1f338; 相关介绍 Common-Colections是Apache软件基金会的项目&#xff0c;对Java标准的Collections API提供了很好的补充&#xff0c;在其基础上对常用的数据结构…

【启明智显分享】5G CPE为什么适合应用在连锁店中?

连锁门店需要5G CPE来满足其日益增长的网络需求&#xff0c;提升整体运营效率和竞争力。那么为什么5G CPE适合连锁店应用呢&#xff0c;小编为此做了整理&#xff0c;主要是基于以下几个方面的原因&#xff1a; 一、高效稳定的网络连接 1、高速数据传输&#xff1a; 5G CPE能…

怎么禁止文件外发?企业如何禁止文件外发,教你6种方法,综合运用效果加倍

在当今数字化的商业环境中&#xff0c;企业内部文件承载着大量关键信息&#xff0c;犹如企业的命脉。这些文件可能包含着核心技术机密、客户资料、未公开的战略规划以及敏感的财务数据等&#xff0c;它们是企业在激烈市场竞争中立足的重要资产。然而&#xff0c;随着信息传播途…