springMVC 1

Scroll Down

SpringMVC 入门

spring MVC 是一个基于servlet api并且被整合进spring框架的一个web框架。

快速入门

在这一段配置中,可以不用关注这些配置是怎么来的,但是必须要按照这些配置进行配置

maven配置

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.2</version>
</dependency>

配置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">

   <!--1.注册DispatcherServlet-->
   <servlet>
       <servlet-name>springmvc</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:springmvc-servlet.xml</param-value>
       </init-param>
       <!--启动级别-1-->
       <load-on-startup>1</load-on-startup>
   </servlet>

   <!--/ 匹配所有的请求;(不包括.jsp)-->
   <!--/* 匹配所有的请求;(包括.jsp)-->
   <servlet-mapping>
       <servlet-name>springmvc</servlet-name>
       <url-pattern>/</url-pattern>
   </servlet-mapping>

</web-app>

编写Spring-mvc的配置文件

这里的spring-mvc配置文件有一个命名规范

springmvc-servlet.xml : [servletname]-servlet.xml

这个文件是在classpath下的,即一般在:resourse路径下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

添加 处理映射器

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

添加 处理器适配器

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

添加 视图解析器

<!--视图解析器:DispatcherServlet给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
   <!--前缀-->
   <property name="prefix" value="/WEB-INF/jsp/"/>
   <!--后缀-->
   <property name="suffix" value=".jsp"/>
</bean>

编写控制器类(Controller)

public class TestController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        
        //新建视图和模型
        ModelAndView modelAndView = new ModelAndView();
        
        //模拟处理业务
        String msg = "Hello Spring MVC";
        
        //添加结果 
        modelAndView.addObject("msg",msg);
        
        //添加视图名称
        modelAndView.setViewName("hello");
        
        return modelAndView;
    }
}

注意这个类实现的接口,是org.springframework.web.servlet.mvc.Controller下的,要不然会报错

配置映射

<bean id="/hello" class="team.controller.TestController"/>

实现视图层

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>hello</title>
</head>
<body>
    ${msg}
</body>
</html>

检查包依赖

  1. project structure中检查项目中有没有把依赖的包都添加进去了
  2. 如果没有添加,进行添加,然后重启tomcat

从请求到响应

1.png

第一站 DispatcherServlet

从http请求,然后发送给服务器,服务器交给我们注册的DispatcherServlet来进行处理,这个地方常常被叫做前端控制器,进行一个简单的处理。

正如我们在web.xml所配置的那样

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
    <!--启动级别-1-->
    <load-on-startup>1</load-on-startup>
</servlet>

这里有个注意点,在配置ServletMapping的时候会出现一个问题

<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

url-pattern配置的是/而不是/*

  1. / 匹配所有的请求(不包括.jsp)

  2. /* 匹配所有的请求(包括.jsp)

如果是/*在后面会出现无法拼接视图名称的问题

在这个类中,真正执行Dispatch分发的是doDispatch(HttpServletRequest request, HttpServletResponse response)方法

* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.

这个方法做如下几件事

  1. 根据HandlerMapping获取handler
  2. 根据注册的HandlerAdapter获取HandlerAdapter
  3. 找到第一个支持handler的类
  4. 用Handler处理请求
  5. 做出回应

第二站 UrlHandlerMapping

maps from URLs to beans with names that start with a slash ("/")

通过包含/nameurl向映射Bean映射

@Nullable
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    // Direct match?
    Object handler = this.handlerMap.get(urlPath);
    // 下面是通过通配符匹配
    ...
}

这一步的目的是对url中的内容进行解析,解析出控制器的名字,并且在已经注册的控制器中进行寻找,交给下一站进行使用

DispatcherServlet 源码

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);

第三站 ControllerHandlerAdapter

The accesses all installed handlers through
 * this interface, meaning that it does not contain code specific to any handler type

DispatcherServlet 通过这个处理器去调用Handler

这一步是把刚刚HandlerMapping找到的控制器名称进行适配,Adapter为适配器,会找到相对应的控制器给DispatcherServlet进行操作,这个Adapter就是执行控制器本身方法的一层封装

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

第四站 Controller

控制器里编写的是我们的业务逻辑,可以在控制器里通过Dao层访问数据库等等。控制器返回一个ModelAndView类,给DispatcherServlet

第五站 视图解析器 ViewResolver

通过返回的ModelAndView对象,DispatcherServlet交给注册过的ViewResolver进行视图的解析

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
    <!--前缀-->
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <!--后缀-->
    <property name="suffix" value=".jsp"/>
</bean>

通过配置前缀和后缀,对返回的视图名进行拼接,从而返回相对应的视图

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

使用注解开发

配置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">

   <!--1.注册DispatcherServlet-->
   <servlet>
       <servlet-name>springmvc</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:springmvc-servlet.xml</param-value>
       </init-param>
       <!--启动级别-1-->
       <load-on-startup>1</load-on-startup>
   </servlet>

   <!--/ 匹配所有的请求;(不包括.jsp)-->
   <!--/* 匹配所有的请求;(包括.jsp)-->
   <servlet-mapping>
       <servlet-name>springmvc</servlet-name>
       <url-pattern>/</url-pattern>
   </servlet-mapping>
</web-app>

在spring-mvc配置文件中配置

配置自动扫描包

<context:component-scan base-package="team.controller"/>

配置让springMVC不再处理静态资源

<mvc:default-servlet-handler/>

此处解释,引用他人博客

https://www.cnblogs.com/dflmg/p/6393416.html

由于早期的Spring MVC不能很好地处理静态资源,所以在web.xml中配置DispatcherServlet的请求映射,往往使用 *.do 、 *.xhtml等方式。这就决定了请求URL必须是一个带后缀的URL,而无法采用真正的REST风格的URL。

如果将DispatcherServlet请求映射配置为"/",则Spring MVC将捕获Web容器所有的请求,包括静态资源的请求,Spring MVC会将它们当成一个普通请求处理,因此找不到对应处理器将导致错误。

在springMVC-servlet.xml中配置<mvc:default-servlet-handler />后,会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。

就是把静态资源转交给DefaultServletHttpRequestHandler进行处理

配置映射器和适配器

<mvc:annotation-driven/>

配置视图解析器

<!--视图解析器:DispatcherServlet给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
    <!--前缀-->
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <!--后缀-->
    <property name="suffix" value=".jsp"/>
</bean>

编写controller层的代码

@Controller
public class TestController{

    @RequestMapping("/hello")
    public String hello(Model model)
    {
        model.addAttribute("msg","helloSpringMVC");
        return "hello";
    }

}
  1. 使用@Controller注解标明这是一个Bean组件,我们的<context:component-scan base-package="team.controller"/>可以扫描到这个组件,此处还可以写@RestController会直接返回一个字符串,不会被视图解析器解析
  2. 使用@RequestMapping标注资源的访问路径
  3. 参数Model model是一个模型,存放数据
  4. 返回值String类型,是视图名称,会被视图解析器解析

创建视图层

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>hello</title>
</head>
<body>
    ${msg}
</body>
</html>

创建的目录在WEB_INF/jsp目录下,目的是为了让浏览器不能直接访问资源