上次说SpringMVC主要是解决Controller层的相关问题,这节就用配置文件+注解的方式完成一个SpringMVC程序的开发。

一、第一个SpringMVC程序的开发
1、开发版本
1. JDK1.8+
2. Maven3.6.3
3. IDEA2020.3.2
4. SpringFramework 5.1.4 
5. Tomcat8.5.42
6. MySQL5.7.26
2、相关依赖

在之前整合Spring+Struts2+Mybatis开发的基础上,去掉struts2依赖,加一个springmvc的依赖即可,参考Spring(8)

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

既然是用配置文件+注解的方式开发,那么其实是和Struts2时的配置差不多的,也需要在web.xml中指定配置文件,并实现工厂创建,配置文件可以随便命名,这里叫dispatcher.xml,创建Spring配置文件如下,bean标签中缺少引用需要自己补充。

6.png

web.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!--创建工厂-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--指定SpringMVC配置文件的路径-->
<!--        <init-param>-->
<!--            <param-name>contextConfigLocation</param-name>-->
<!--            <param-value>classpath:dispatcher.xml</param-value>-->
<!--        </init-param>-->
        <!--本Servlet会在tomcat启动的时候就会被创建-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

DispathcerServlet,创建工厂:

1. DispatcherServlet称为前端控制器(中央控制器)
2. DispatcherServlet的核心作用:
	1. 用于创建Spring的工厂(容器)。
	     ApplicationContext ctx = new ClassPathXmlApplicationContext("dispatcher.xml");
	     因为DispatcherServlet封装的Spring工厂(容器)只能读取xml,所以无法迁移到纯注解编程
	2. 控制SpringMVC内部的运行流程。

dispatcher.xml,添加springmvc核心功能标签和包扫描标签:

    <!--设置注解扫描的路径-->
    <context:component-scan base-package="com.jin" />

    <!--引入SpringMVC的核心功能-->
    <mvc:annotation-driven />

mvc:annotation-driven的作用:

# <mvc:annotation-driven/> 这段配置的主要作用:引入SpringMVC的核心功能。 
# 主要引入了2个核心类型
# 1.RequestMappingHandlerMapping
# 2.RequestMappingHandlerAdapter

1. RequestMappingHandlerMapping实现了HandlerMapping接口【了解】
		它会处理@RequestMapping注解,并将其注册到请求映射表中。
2. RequestMappingHandlerAdapter实现了 HandlerAdapter接口【了解】
		它是处理请求的适配器,确定调用某个符合要求的控制器类中具体服务的方法。

简单来说这两个接口实现的作用就是,从哪里来,到哪里去。

context:component-scan的作用:

1. 进行注解扫描
2. DispatcherServlet所创建的工厂需要读取XML的配置文件,不能使用纯注解的开发。所以目前使用Spring配置文件+基础注解的形式,进行开发。
	基础注解:@Component,@Service,@Repository,@Controller,@Scope,@Transactional等
	高级注解:@Configuration,@Bean,@ComponentScan等
	后续SpringMVC高级版的课程,会使用纯注解版开发,与SpringBoot的使用方式高度一致。

一些基础配置,本质还是创建工厂,并将配置文件中的对象交由工厂管理。

3、程序编码
#  基本流程
1. 开发一个类在上面加入@Controller注解 (生成bean对象交由工厂管理)
2. 提供一个控制器方法:参数是HttpServletRequest,HttpServletResponse,返回值是String的,同时加入@RequestMapping注解定义请求路径(从哪里来)
3. 在控制方法中,完成核心开发功能,把对应JSP页面的路径,作为方法的返回值返回。(到哪里去)
package com.jin;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author jinyunlong
 * @date 2022/1/7 16:21
 * @profession ICBC锅炉房保安
 */
@Controller
//@Scope("singleton")
//@Scope("prototype")
public class FirstController {

    public FirstController(){
        System.out.println("FirstController.FirstController");
    }

//    @RequestMapping("/first")
//    @RequestMapping("first")
    @RequestMapping(value={"/first","/third"})
    public String first(HttpServletRequest request, HttpServletResponse response){
        System.out.println("request = " + request);
        return "/result.jsp";
    }

    @RequestMapping(value="/second") //在注解使用时,如果只有一个value属性的话,value属性名,可以省略。
    public String second(HttpServletRequest request, HttpServletResponse response) {
        //第二个控制器功能
        System.out.println("request = " + request);
        return "/result.jsp";
    }
}

如上代码,和Servlet一个类只能提供一个服务方法不同,SpringMVC作为控制器,一个类可以提供多个服务方法。

注意:SpringMVC我们开发的Controller,也称之为Handler(SpringMVC内部的叫法)

二、第一个SpringMVC程序的细节分析
1、关于类对象的创建次数
1. 回顾:Servlet控制器被创建的次数
		一种类型的Servlet,只会被Tomcat创建一次,所以Servlet是单实例的。

2. Servlet是单实例并不是单例设计模式

3. SpringMVC的控制器被Spring创建的次数
		可以只创建一次,也可以创建多次,默认是只创建一次。
		控制器创建的次数,是由@Scope注解决定的。

4. 默认情况下SpringMVC的控制器只会被创建一次,会存在线程安全的问题。

单实例和单例设计模式的区分:简单理解,单例设计模式就是结扎,结果不可逆,单实例是使用了安全措施,可自己控制,在Spring及SpringMVC中均使用@Scope注解控制。

2、@RequestMapping注解

核心作用:为控制器方法提供外部访问的url路径。相当于Servlet中的urlpartten,使用@RequestMapping注解更加灵活多变。特点:

(1)开头的路径分割符 / 可以省略 (2)在一个控制器方法上映射多个路径 ,可看如上代码↑

(3)Controller类上加入@RequestMapping注解,比如

package com.jin;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author jinyunlong
 * @date 2022/1/20 14:02
 * @profession ICBC锅炉房保安
 */
@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/addUser")
    public String addUser(){
        return "/result.jsp";
    }

    @RequestMapping("/deleteUser")
    public String deleteUser(){
        return "/index.jsp";
    }
}

好处是可以更好的按照功能,进行不同模块的区分,有利于项目的管理。

(4)@RequestMapping限定用户的请求方式 比如:

在注解后加入参数:method = RequestMethod.POST 那么请求方就只能以POST方式发起请求,使用其他方式直接会报405

7.PNG

(5)Http协议中其他的请求方式,比如put、delete等,这些在restful架构风格中使用较多,日常了解就完了,用到再看。

3、控制器方法参数

SpringMVC在控制器方法参数设计的过程中,非常灵活,可以支持多种参数的设置方式,非常强大,它也把这种设计,叫做数据绑定。说白了就是传参。以前Servlet时一般就是接request返response,SpringMVC中也差不多,比如:

package com.jin;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;

/**
 * @author jinyunlong
 * @date 2022/1/20 16:55
 * @profession ICBC锅炉房保安
 */
@Controller
@RequestMapping("/methonParam")
public class MethodParamController {
    @RequestMapping("/m1")
    public String m1(HttpSession session){
        System.out.println("session = " + session);
        return "/result.jsp";
    }

    @RequestMapping("/m2")
    public String m2(){
        System.out.println("MethodParamController.m2");
        return "/result.jsp";
    }
}

两个例子,但都不好,一种和ServletAPI有耦合,另一种直接没有参数,以后还会详细记录传参这块。

4、视图解析器(页面跳转)

上述代码的返回值String都是"/result.jsp",很明显存在耦合,假如我不把result.jsp放在默认路径下了,加了一层jsp目录,这样返回页面自然就找不到了,这个时候就需要视图解析器ViewResolver来控制:

8.png

只需要加入一个封装好的bean对象即可,然后对文件类型后缀和路径前缀的值进行注入即可:

<!--    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">-->
<!--        <property name="prefix" value="/"></property>-->
<!--        <property name="suffix" value=".jsp"></property>-->
<!--    </bean>-->

加入如上配置后,在Controller返回String值后他会自己做一个前后缀的拼接,所以只需要返回要返回页面对应的文件名即可。

使用注解开发的话只需要放到@Bean中自定义即可。

package com.jin;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

/**
 * @author jinyunlong
 * @date 2022/1/20 21:37
 * @profession ICBC锅炉房保安
 */
@Configuration
public class AppConfig {

    @Bean
    public InternalResourceViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

注意:

  1. AppConfig配置Bean应该放置到context:component-scan/ 扫描的路径下。
  2. 结合前面所讲,目前因为DispatcherServlet封装的Spring工厂(容器)只能读取xml,所以无法进行纯注解替换。
5、SpringMVC配置文件的默认设置

如果在web.xml中没有设置SpringMVC配置文件的的路径,系统会查找默认配置文件,如下servlet-name命名为dispatcherServlet,如果没设置配置文件路径,系统就会去找默认路径下是否有dispatcherServlet-servlet.xml这个文件,找不到的就会报错提示找不到这个文件。

    <!--创建工厂-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--指定SpringMVC配置文件的路径-->
<!--        <init-param>-->
<!--            <param-name>contextConfigLocation</param-name>-->
<!--            <param-value>classpath:dispatcher.xml</param-value>-->
<!--        </init-param>-->
        <!--本Servlet会在tomcat启动的时候就会被创建-->
        <load-on-startup>1</load-on-startup>
    </servlet>

所以 SpringMVC默认配置文件的名字,放置位置是 /WEB-INF/[servlet-name]-servlet.xml


标题:SpringMVC(1)
作者:jyl
地址:http://jinyunlong.xyz/articles/2022/01/21/1642743551562.html