Spring MVC 教程
在本 Spring MVC 教程中,我们将学习如何使用 Spring Tool Suite 开发 Spring MVC Web 应用程序。Spring MVC框架广泛用于Java Web 应用程序。
Spring MVC
与Struts 框架一样,Spring MVC 也基于 Java EE Servlet 和 JSP 技术并实现模型-视图-控制器设计模式。
Spring MVC 教程
我们之前已经了解了Spring 依赖注入的工作原理,在本教程中,我们将学习如何使用 Spring MVC 框架创建一个简单的 Web 应用程序。我们可以使用 Eclipse 或 IntelliJ IDE 进行 Spring 项目开发,但 SpringSource 提供了Spring Tool Suite (STS),这是一个基于 Eclipse 的 IDE,并带有内置的VMware vFabric tc Server,该服务器建立在 Apache Tomcat 容器之上并针对基于 Spring 的应用程序进行了优化。我将在Spring MVC 教程和其他未来的教程中使用 STS,因为它通过提供以下功能使开发人员的工作更轻松:
- 支持创建骨架 Spring 应用程序(MVC、Rest、Batch 等),非常适合从头开始创建项目。我们很快就会在本 Spring MVC 教程中看到创建 Spring MVC 项目是多么容易。
- 提供有用的功能,例如创建 Spring 配置文件、解析配置文件和类以提供有关它们的有用信息。
- Spring 应用程序的自动验证
- 重构支持轻松进行项目更改,更改也会反映在配置文件中。
- 代码辅助不仅适用于类,也适用于配置文件,我非常喜欢这个功能,因为大多数时候我们需要知道我们可以使用什么及其细节。
- 通过集成 AspectJ 为面向方面编程 (AOP) 提供最佳支持。
Looking at all the features STS provide, I was sold for this and decided to use it for Spring application and till now I am very happy with it. Just Download the STS from STS Official Download Page and install it. I am using STS 3.4.0.RELEASE that is based on Eclipse 4.3.1 release. If you don’t want to use STS and want to get its facilities in existing Eclipse, then you need to install its plugin from Eclipse Marketplace. Use below image as a reference and make sure to chose the correct STS version for installation. Below plugin is good for Eclipse Kepler. If you don’t want to use SpringSource server, you can deploy the application in any other Java EE container such as Tomcat, JBoss etc. For this tutorial, I will use the server that ships with STS but I have tested the application by exporting it as WAR file into separate tomcat server and it’s working fine. Now that our server environment and IDE is ready, let’s proceed to create our first Spring MVC project. Below steps are valid for STS as well as Eclipse with STS plugins.
Creating Spring MVC Application in STS or Eclipse
Step 1: Create New Spring Project from the menu. Step 2: In the new project window, give the name as “SpringMVCExample” and chose template as “Spring MVC Project”. If you are using this template for the first time, STS will download it from SpringSource website. If you want, you can add the project to any working set. Step 3: When the template is downloaded, in the next screen you need to provide the top-level package name. This package will be used as the base-package for Spring components. Step 4: Once the project is created by Spring MVC template, it will look like below image. Don’t worry if you don’t see User.java class, login.jsp and user.jsp files, they have been added by me later on. If your project is not compiled and you see some errors, run Maven/Update Project. Make sure to check the “Force update of Snapshots/Releases” options, refer below image. Overall project looks just like any other maven based web application with some Spring configuration files. Now it’s time to analyze the different part of the projects and extend it a little.
Spring MVC Dependencies
Our generated pom.xml file looks like below.
<?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.journaldev</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 will be the servlet-context for the web application, so you can change it if you want something else. There are few properties defined for Spring Framework, AspectJ and SLF4j versions, I found that they were not reflecting the latest versions, so I have changed them to the latest stable version as of today. The project dependencies that I am interested in are;
- spring-context: Spring Core dependency. Notice the exclusion of commons logging in favor of SLF4J.
- spring-webmvc: Spring artifact for MVC support
- aspectjrt: AspectJ API reference
- SLF4J and Log4j: For logging purposes, Spring is very easy to configure for log4j or Java Logging API because of SLF4J integration.
- javax.inject - JSR330 API for dependency injection
There are some other dependencies added, such as Servlet, JSP, JSTL and JUnit API but for starter application, we can overlook them.
Spring MVC Tutorial - Log4j Configuration
The generated log4j.xml file looks like below.
<?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.journaldev.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>
Notice that it’s printing everything to console, we can easily add appenders to redirect logging to files.
Spring MVC Tutorial - Deployment Descriptor Configuration
Let’s see our web.xml and analyze it.
<?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
ties the ApplicationContext
lifecycle to ServletContext
lifecycle and automate the creation of ApplicationContext
. ApplicationContext
is the place for Spring beans and we can provide it’s configuration through contextConfigLocation context parameter. root-context.xml file provides the configuration details for WebApplicationContext. DispatcherServlet
is the controller class for Spring MVC application and all the client requests are getting handled by this servlet. The configuration is being loaded from the servlet-context.xml file.
Spring MVC Tutorial - Configuration Files
root-context.xml file:
<?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>
We can define shared beans here, as of now there is nothing in it. servlet-context.xml code:
<?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.journaldev.spring" />
</beans:beans>
This is how the standard Spring configuration file looks like, just imagine writing all this on your own and you will start liking STS tool. annotation-driven element is used to let Controller servlet know that annotations will be used for bean configurations. resources element defines the location where we can put static files such as images, HTML pages etc that we don’t want to get through Spring framework. InternalResourceViewResolver
is the view resolver, we can provide view pages location through prefix and suffix properties. So all our JSP pages should be in /WEB-INF/views/ directory. context:component-scan element is used to provide the base-package location for scanning Controller classes. Remember the value of the top-level package given at the time of project creation, it’s the same value getting used here.
Spring MVC Controller Class
HomeController is created automatically with the home() method, although I have extended it a little bit by adding loginPage() and login() methods.
package com.journaldev.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注释用于表明它是一个 Web 控制器类。@RequestMapping与类和方法一起使用,将客户端请求重定向到特定的处理程序方法。请注意,处理程序方法返回的是字符串,这应该是要用作响应的视图页面的名称。如您所见,我们有三个方法返回不同的字符串,因此我们需要创建具有相同名称的 JSP 页面。请注意,login() 方法将使用 HTTP 方法作为 POST 调用,因此我们在这里需要一些表单数据。因此,我们有 User 模型类,并使用@Validated注释将其标记为要进行验证。每个方法都包含 Model 作为参数,我们可以设置稍后在 JSP 响应页面中使用的属性。
Spring MVC 模型类
模型类用于保存表单变量,我们的用户模型 bean 如下所示。
package com.journaldev.spring;
public class User {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
一个具有变量名及其 getter 和 setter 方法的简单 java bean。
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 页面,供用户提供用户名作为输入。请注意,表单变量名与 User 类变量名相同。此外,表单操作为“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>
为用户提供显示用户名的简单主页,请注意我们在登录方法中设置此属性。
Spring MVC 示例应用程序测试
我们的应用程序已准备好执行,只需在 VMware tc Server 或您选择的任何其他 servlet 容器上运行它,您将获得以下页面作为响应。这就是 Spring MVC 教程,您可以看到使用 STS 插件创建 Spring MVC 应用程序是多么容易。代码大小非常小,大多数配置由 Spring MVC 处理,因此我们可以专注于业务逻辑。从以下链接下载示例 spring MVC 项目并试用它。
下载 Spring MVC 项目