Spring MVC教程

时间:2020-02-23 14:35:57  来源:igfitidea点击:

在本Spring MVC教程中,我们将学习如何使用Spring Tool Suite开发Spring MVC Web应用程序。
Spring MVC框架广泛用于Java Web应用程序。

SpringMVC

与Struts Framework一样,Spring MVC也基于Java EE Servlet和JSP技术,并实现了Model–View–Controller设计模式。

Spring MVC教程

我们之前已经看到了Spring Dependency Injection的工作原理,并且在本教程中,我们将学习如何使用Spring MVC框架创建一个简单的Web应用程序。

我们可以使用Eclipse或者IntelliJ IDE进行Spring项目开发,但是SpringSource提供了Spring Tool Suite(STS),它是基于Eclipse的IDE,并带有基于Apache Tomcat容器构建并经过优化的内置VMware vFabric tc Server。
用于基于Spring的应用程序。

我将STS用于Spring MVC教程和其他将来的教程,因为它通过提供以下功能,使开发人员的生活变得更轻松:

  • 支持创建骨架Spring应用程序(MVC,Rest,Batch等),非常适合从头开始项目。
    我们将在本SpringMVC教程中很快看到创建一个Spring MVC项目是多么容易。

  • 提供有用的功能,例如创建Spring Configuration文件,解析配置文件和类以提供有关它们的有用信息。

  • 自动验证Spring应用程序

  • 重构支持可轻松进行项目更改,更改也反映在配置文件中。

  • 代码不仅为类而且为配置文件提供帮助,我非常喜欢此功能,因为大多数时候我们需要知道我们可以使用什么及其细节。

  • 通过集成AspectJ,对面向方面的编程(AOP)的最佳支持。

查看STS提供的所有功能,我为此被卖了,并决定将其用于Spring应用程序,直到现在我对此都很满意。

只需从STS官方下载页面下载STS并安装。
我正在使用基于Eclipse 4.3.1发行版的STS 3.4.0.RELEASE。

如果您不想使用STS并希望在现有的Eclipse中获得其功能,则需要从Eclipse Marketplace中安装其插件。
使用下图作为参考,并确保选择正确的STS版本进行安装。
下面的插件非常适合Eclipse Kepler。

如果您不想使用SpringSource服务器,则可以将应用程序部署在任何其他Java EE容器中,例如Tomcat,JBoss等。
对于本教程,我将使用STS附带的服务器,但是我已经通过导出测试了该应用程序将它作为WAR文件放入单独的tomcat服务器中,并且工作正常。

现在我们的服务器环境和IDE已经准备就绪,让我们继续创建我们的第一个Spring MVC项目。
以下步骤对STS以及具有STS插件的Eclipse有效。

在STS或者Eclipse中创建Spring MVC应用程序

步骤1:从菜单中创建New Spring Project。

步骤2:在新项目窗口中,将名称命名为" SpringMVCExample",并选择模板作为" Spring MVC Project"。
如果您是第一次使用此模板,STS将从SpringSource下载它。
如果需要,可以将项目添加到任何工作集中。

步骤3:下载模板后,在下一个屏幕中,您需要提供顶级软件包名称。
该软件包将用作Spring组件的基本软件包。

步骤4:通过Spring MVC模板创建项目后,它将如下图所示。

如果您没有看到User.java类,login.jsp和user.jsp文件,请不用担心,它们是我稍后添加的。

如果您的项目尚未编译,并且看到一些错误,请运行Maven/Update Project。
确保选中"强制更新快照/发布"选项,请参见下图。

总体项目看起来与带有某些Spring配置文件的任何其他基于Maven的Web应用程序一样。
现在是时候分析项目的不同部分并进行一些扩展了。

Spring MVC依赖关系

我们生成的pom.xml文件如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.theitroad</groupId>
	<artifactId>SpringMVCExample</artifactId>
	<name>SpringMVCExample</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>4.0.0.RELEASE</org.springframework-version>
		<org.aspectj-version>1.7.4</org.aspectj-version>
		<org.slf4j-version>1.7.5</org.slf4j-version>
	</properties>
	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				 </exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
				
		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>	
		
		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
				
		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	
		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>        
	</dependencies>
  <build>
      <plugins>
          <plugin>
              <artifactId>maven-eclipse-plugin</artifactId>
              <version>2.9</version>
              <configuration>
                  <additionalProjectnatures>
                      <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                  </additionalProjectnatures>
                  <additionalBuildcommands>
                      <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                  </additionalBuildcommands>
                  <downloadSources>true</downloadSources>
                  <downloadJavadocs>true</downloadJavadocs>
              </configuration>
          </plugin>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>2.5.1</version>
              <configuration>
                  <source>1.6</source>
                  <target>1.6</target>
                  <compilerArgument>-Xlint:all</compilerArgument>
                  <showWarnings>true</showWarnings>
                  <showDeprecation>true</showDeprecation>
              </configuration>
          </plugin>
          <plugin>
              <groupId>org.codehaus.mojo</groupId>
              <artifactId>exec-maven-plugin</artifactId>
              <version>1.2.1</version>
              <configuration>
                  <mainClass>org.test.int1.Main</mainClass>
              </configuration>
          </plugin>
      </plugins>
  </build>
</project>

artifactId将是Web应用程序的servlet上下文,因此,如果需要其他内容,可以更改它。

对于Spring Framework,AspectJ和SLF4j版本定义的属性很少,我发现它们没有反映最新版本,因此我将它们更改为今天的最新稳定版本。

我感兴趣的项目依赖项是;

  • spring-context:Spring Core依赖项。
    注意排除了支持SLF4J的公共日志记录。

  • spring-webmvc:支持MVC的Spring工件

  • Aspectjrt:AspectJ API参考

  • SLF4J和Log4j:出于日志记录的目的,由于SLF4J集成,Spring非常容易为log4j或者Java Logging API配置。

  • javax.inject –用于依赖性注入的JSR330 API

还添加了其他一些依赖项,例如Servlet,JSP,JSTL和JUnit API,但是对于入门应用程序,我们可以忽略它们。

Spring MVC教程– Log4j配置

生成的log4j.xml文件如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="https://jakarta.apache.org/log4j/">

	<!-- Appenders -->
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" 
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%-5p: %c - %m%n" 
		</layout>
	</appender>
	
	<!-- Application Loggers -->
	<logger name="com.theitroad.spring">
		<level value="info" 
	</logger>
	
	<!-- 3rdparty Loggers -->
	<logger name="org.springframework.core">
		<level value="info" 
	</logger>
	
	<logger name="org.springframework.beans">
		<level value="info" 
	</logger>
	
	<logger name="org.springframework.context">
		<level value="info" 
	</logger>

	<logger name="org.springframework.web">
		<level value="info" 
	</logger>

	<!-- Root Logger -->
	<root>
		<priority value="warn" 
		<appender-ref ref="console" 
	</root>
	
</log4j:configuration>

请注意,它会将所有内容打印到控制台,我们可以轻松添加添加程序以将日志重定向到文件。

Spring MVC教程–部署描述符配置

让我们看看我们的web.xml并对其进行分析。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

ContextLoaderListener将ApplicationContext生命周期与ServletContext生命周期联系起来,并自动创建ApplicationContext。
" ApplicationContext"是Spring Bean的存放地,我们可以通过contextConfigLocation上下文参数提供其配置。
root-context.xml文件提供WebApplicationContext的配置详细信息。

DispatcherServlet是Spring MVC应用程序的控制器类,所有客户端请求都由该servlet处理。
该配置是从servlet-context.xml文件中加载的。

Spring MVC教程–配置文件

root-context.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
		
</beans>

我们可以在这里定义共享bean,到目前为止,其中没有任何内容。

servlet-context.xml代码:

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

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven 

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" 

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" 
		<beans:property name="suffix" value=".jsp" 
	</beans:bean>
	
	<context:component-scan base-package="com.theitroad.spring" 	
	
</beans:beans>

这就是标准Spring配置文件的样子,想象一下自己编写所有这些内容,您将开始喜欢STS工具。

注解驱动的元素用于让Controller Servlet知道注解将用于bean配置。

resources元素定义了我们可以放置我们不想通过Spring框架获取的静态文件(例如图像,HTML页面等)的位置。

InternalResourceViewResolver是视图解析器,我们可以通过前缀和后缀属性提供视图页面的位置。
因此,我们所有的JSP页面都应位于/WEB-INF/views /目录中。

context:component-scan元素用于提供扫描Controller类的基本包位置。
请记住,在创建项目时给定的顶级程序包的价值,此处使用的是相同的价值。

Spring MVC控制器类

HomeController是使用home()方法自动创建的,尽管我通过添加loginPage()和login()方法对其进行了扩展。

package com.theitroad.spring;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	/**
	 * Simply selects the home view to render by returning its name.
	 */
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		logger.info("Welcome home! The client locale is {}.", locale);
		
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
		
		String formattedDate = dateFormat.format(date);
		
		model.addAttribute("serverTime", formattedDate );
		
		return "home";
	}
	
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String loginPage(Locale locale, Model model) {
		return "login";
	}
	
	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String login(@Validated User user, Model model) {
		model.addAttribute("userName", user.getUserName());
		return "user";
	}
}

@Controller批注用于指示它是网络控制器类。

@RequestMapping与类和方法一起使用,以将客户端请求重定向到特定的处理程序方法。
请注意,处理程序方法正在返回String,这应该是用作响应的视图页面的名称。

如您所见,我们有三种返回不同字符串的方法,因此我们需要创建具有相同名称的JSP页面。

注意,login()方法将以HTTP方法作为POST调用,因此我们期望这里有一些表单数据。
因此,我们有User模型类,并使用@Validated批注将其标记为进行验证。

每个方法都包含Model作为参数,我们可以设置属性以供以后在JSP响应页面中使用。

Spring MVC模型类

模型类用于保存表单变量,我们的User模型bean如下所示。

package com.theitroad.spring;

public class User {

	private String userName;

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}
	
}

一个简单的Java Bean,具有变量名称及其getter和setter方法。

Spring MVC教程–查看页面

我们有如下三个JSP页面。

home.jsp代码:

<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
</head>
<body>
<h1>
	Hello world!  
</h1>

<P>  The time on the server is ${serverTime}. </P>
</body>
</html>

注意,使用JSP表达式语言来获取属性值。

login.jsp代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login Page</title>
</head>
<body>
<form action="home" method="post">
<input type="text" name="userName"><br>
<input type="submit" value="Login">
</form>
</body>
</html>

一个简单的JSP页面,供用户提供userName作为输入。
请注意,表单变量名与用户类变量名相同。
同样,表单动作是" home",方法是" post"。
很明显,HomeController login()方法将处理此请求。

user.jsp代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>User Home Page</title>
</head>
<body>
<h3>Hi ${userName}</h3>
</body>
</html>

显示用户名的用户的简单主页,请注意,我们在登录方法中设置了此属性。