WUJUNWEI'S BLOG
WuJunwei
Jul 5, 2020
It takes 34 minutes to read this article.

SpringMVC介绍;架构;推荐使用的注解配置;springMvc的hello world

SpringMVC介绍

MVC回顾

1、 模型(Model):负责封装应用的状态,并实现应用的功能。通常分为数据模型和业务逻辑模型,数据模型用来存放业务数据,比如订单信息、用户信息等;而业务逻辑模型包含应用的业务操作,比如订单的添加或者修改等。通常由java开发人员编写程序完成,代码量最多

2、 视图(View):视图通过控制器从模型获得要展示的数据,然后用自己的方式展现给用户,相当于提供界面来与用户进行人机交互。通常有前端和java开发人员完成,代码量较多。

3、 控制器(Controller):用来控制应用程序的流程和处理用户所发出的请求。当控制器接收到用户的请求后,会将用户的数据和模型的更新相映射,也就是调用模型来实现用户请求的功能;然后控制器会选择用于响应的视图,把模型更新后的数据展示给用户。起到总调度的作用,Controller通常由框架实现,使用时基本不需要编写代码

SpringMVC介绍

大部分java应用都是web应用,展现层是web应用最为重要的部分。Spring为展现层提供了一个优秀的web层框架——SpringMVC。和众多其他web框架一样,它基于MVC的设计理念,此外,它采用了松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性。

SpringMVC通过一套MVC注解,让POJO成为处理请求的控制器,无需实现任何接口,同时,SpringMVC还支持REST风格的URL请求。 此外,SpringMVC在数据绑定、视图解析、本地化处理以及静态资源处理上都有许多不俗的表现。

它在框架设计、扩展性、灵活性等方面全面超越了Struts、WebWork等MVC框架,从原来的追赶者一跃成为MVC的领跑者。

SpringMVC框架围绕DispatcherServlet这个核心展开,DispatcherServlet是SpringMVC框架的总导演、总策划,它负责截获请求并将其分派给相应的处理器处理。

SpringMVC架构

hello world

创建web项目(war)

若创建结束提示错误,则右击项目——>Java EE Tools——>Generate Deployment Descriptor Stub.然后系统会在src/main/webapp/WEB_INF文件加下创建web.xml文件。错误解决!

引入jar包及源码包

Spring-web:web开发相关的基础功能包

Spring-webmvc:SpringMVC框架核心包

pom.xml:

<dependencies>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>5.1.16.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.1.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.1.16.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-expression</artifactId>
  <version>5.1.16.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aop</artifactId>
	<version>5.1.16.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-web</artifactId>
	<version>5.1.16.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>5.1.16.RELEASE</version>
</dependency>
 	<dependency>
 		<groupId>commons-logging</groupId>
 		<artifactId>commons-logging</artifactId>
 		<version>1.2</version>
 	</dependency>
 	<dependency>
 		<groupId>log4j</groupId>
 		<artifactId>log4j</artifactId>
 		<version>1.2.12</version>
 	</dependency>
</dependencies>

配置web.xml

  <servlet>
  	<servlet-name>springmvc</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<!-- 
  		/*:拦截所有请求,包括jsp
  		/ :拦截所有请求,不包含jsp
  		*.do,*.action
  	 -->
  	<url-pattern>*.do</url-pattern>
  </servlet-mapping>

springmvc的配置文件

{servlet-name}-servlet.xml

用户发送请求到web容器,并被DispatchServlet拦截之后进入springmvc容器,springmvc该怎么处理那,这就需要springmvc的配置文件。

那么springmvc的配置文件该放在什么位置,又该怎么命名呢?

找到DispatchServlet这个类:

由此知道,springmvc默认读取/WEB-INF/{servlet-name}-servlet.xml这个配置文件,因为我们在web.xml中的servlet-name配置的是springmvc,所以在WEB-INF目录下创建springmvc-servlet.xml文件:

springmvc配置文件的头信息和spring一样。

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

</beans>

HandlerMapping映射器

<!-- 配置HandlerMapping -->
	<!-- 把bean的name属性作为Url -->
	<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> #### HandlerAdapter适配器

<!-- 配置HandlerAdapter -->
	<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

ViewResolver试图解析器

由此可见,视图解析器的规则是:prefix+viewName+suffix

完整的配置

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

	<!-- 配置映射器,把bean的name属性作为一个url -->
	<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
	
	<!-- 配置适配器 -->
	<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
	
	<bean name="/hello.do" class="com.atguigu.springmvc.controller.HelloController" />
	
	<!-- 配置视图解析器 -->
	<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"  -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>

HelloController

HelloController内容:

/**
 * 在整体架构中,通常称为Handler
 * 在具体实现中,通常称为Controller
 * @author joedy
 *
 */

public class HelloController implements Controller {

@Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
    throws Exception {
    ModelAndView mv = new ModelAndView();
    mv.setViewName("hello"); // 试图名称
    mv.addObject("msg", "这是我的第一个SpringMVC程序!!"); // 数据模型
    return mv;
    }
   	 
}

添加jsp页面(hello.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div style="color:red; font-size:30px">${msg }</div>
</body>
</html>

运行测试

通过浏览器访问:http://localhost:8080/springmvc/hello.do

添加log日志

Log4j.properties内容:

log4j.rootLogger=DEBUG,A1
log4j.logger.org.mybatis=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

日志打印信息

流程分析

优化helloworld程序

入门程序虽然完成了,但是还有可以改进的空间。结合Spring入门流程,我们一步步的优化入门程序。

web.xml

load-on-startup

结合启动日志,发现入门程序在tomcat的运行完成后并没有加载servlet,而是在用户第一次访问之后才加载。生产环境会影响网站的相应速度

解决方案:让tomcat启动时就去加载DispatcherServlet并初始化Spring容器。

指定SpringMVC的配置文件

通常情况下SpringMVC的命名规则是{servlet-name}-servlet.xml,一个配置文件名而已,问题不大。

但是,SpringMVC的配置文件的存放路径,如果采用默认配置路径(WEB-INF下),这在项目开发时不利于统一维护管理。能不能把SpringMVC的配置文件和其他Spring配置文件放在一起,方便统一管理呢?

通过dispatcherServlet的初始化参数告诉SpringMVC它的配置文件在哪里。

这时就需要在web.xml中去指定springMVC的存放路径,配置方式:

  <servlet>
  	<servlet-name>springmvc</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	<!-- 指定springMVC的配置文件,多个可以用逗号和空格隔开 -->
  	<init-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>classpath:springmvc-servlet.xml</param-value>
  	</init-param>
  	<!-- 值为非负的情况下,tomcat启动时,就加载该servlet。值越小加载的优先级就越高 -->
  	<load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<!-- 
  		/*:拦截所有请求,包括jsp
  		/ :拦截所有请求,不包含jsp
  		*.do,*.action
  	 -->
  	<url-pattern>*.do</url-pattern>
  </servlet-mapping>

原理:参见DispatcherServlet父类的注释

DispatchServlet.class源码中:

找到DispatchServlet.properties文件:

在这个默认的配置文件中,已经配置了映射器和适配器。

所以在springmvc-servlet.xml文件中可以省略之前配置的映射器和适配器

再次测试:

helloword的缺点

1)每个类需要都实现Controller接口

2)每个类(Controller)只能完成一个用户请求(或者只能处理一个业务逻辑)

3)每个类(Controller)都要在配置文件里,进行配置 解决方案:

注解程序

注解

默认注解配置

在DispatchServlet.properties文件中,已经提供了默认的注解映射器和适配器,所以咱们可以直接书写注解的代码

创建hello2Controller

内容:

@Controller
public class Hello2Controller {

@RequestMapping("show1")
public ModelAndView test1(){
ModelAndView mv = new ModelAndView();
mv.setViewName("hello");
mv.addObject("msg", "这是SpringMVC的第一个注解程序!");
return mv;
}

}

配置扫描器

在springmvc-servlet.xml中,开启注解扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 配置映射器,把bean的name属性作为一个url -->
	<!-- <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> -->
	
	<!-- 配置适配器 -->
	<!-- <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> -->
	
	<!-- <bean name="/hello.do" class="com.atguigu.springmvc.controller.HelloController" /> -->
	
	<!-- 配置注解扫描,和Spring的配置方式一样 -->
	<context:component-scan base-package="com.atguigu.springmvc" />
	
	<!-- 配置视图解析器 -->
	<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"  -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>

测试

缺点

找到默认的注解映射器和适配器,发现他们都已过时。

既然默认配置的映射器和适配器都已经过期,并且springmvc也推荐了相应的支持注解的映射器和适配器

推荐使用的注解配置

springmvc-servlet.xml

<!-- 推荐使用的注解映射器 -->
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
	
<!-- 推荐使用的注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

最佳方案(注解驱动)

注解驱动的配置

在springmvc-servlet.xml中配置注解驱动

<!-- 注解驱动,替代推荐使用的注解映射器和适配器,并提供了对json的支持 -->
<mvc:annotation-driven />

注解驱动的原理

AnnotationDrivenBeanDefinitionParser的注释

注解配置最终方案

使用注解驱动后springmvc-servlet.xml这个配置文件:

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

	<!-- 注解驱动,替代推荐使用的注解映射器和适配器,并提供了对json的支持 -->
	<mvc:annotation-driven />
	
	<!-- 配置注解扫描,和Spring的配置方式一样 -->
	<context:component-scan base-package="com.atguigu.springmvc" />
	
	<!-- 配置视图解析器 -->
	<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"  -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>

目前这些配置已经能够完成springmvc的基本使用,后续还会添加一些高级用法的配置,例如:拦截器、自定义试图、文件上传等