内容关键词:结构,部署,配置,应用,解析
知识来源: 720科技(张森鹏)
一、知识笔记
1.采用SpringMVC的好处:
(1)根据 URI 调用相应的 action。
(2)实例化正确的控制器类。
(3)根据请求参数值来构造表单 bean。
(4)调用控制器对象的相应方法。
(5)转向到一个视图(JSP 页面 )。
Spring MVC 是一个包含了 Dispatcher servlet 的 MVC 框架。它调用控制器方法并转发到视图。使用 Spring MVC 的第一个好处是,不需要编写 Dispatcher servlet。以下是 Spring MVC具有的能加速开发的功能的列表。
Spring MVC 提供了一个 Dispatcher Servlet,无需额外开发。
Spring MVC 使用基于 XML 的配置文件,可以编辑,而无需重新编译应用程序。
Spring MVC 实例化控制器,并根据用户输入来构造 bean。
Spring MVC 可以自动绑定用户输入,并正确地转换数据类型。例如, Spring MVC 能自动解析字符串,并设置 float 或 decimal 类型的属性。
Spring MVC 可以校验用户输入,若校验不通过,则重定向回输入表单。输入校验是可选的,支持编程方式以及声明方式。关于这一点, Spring MVC 内置了常见的校验器。
Spring MVC 是 Spring 框架的一部分,可以利用 Spring 提供的其他能力。 Spring MVC 支持国际化和本地化,支持根据用户区域显示多国语言。
Spring MVC 支持多种视图技术。最常见的 JSP 技术以及其他技术包括 Velocity 和FreeMarker。
2.controller接口
在 Spring 2.5 前,开发一个控制器的唯一方法是实现 org.springframework.web.servlet.mvc.Controller 接口。 这个接口公开了一个 handleRequest 方法。下面是该方法的签名:
ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response)
其实现类可以访问对应请求的 HttpServletRequest 和 HttpServletResponse,还必须返回一个 ModelAndView 对象,它包含视图路径或视图路径和模。
Controller 接口的实现类只能处理一个单一动作(action), 而一个基于注解的控制器可以同时支持多个请求处理动作,并且无须实现任何接口。
二、重要知识
1.SpringMVC应用
本章的示例应用程序 springmvc-intro1 展示了基本的 Spring MVC 应用。该应用程序同第2 章学习的 appdesign1 应用非常相似,专用于展示 Spring MVC 是如何工作的。Sringmvc-intro1应用也有两个控制器类似于 appdesign1 的控制器类。
(1) 目录结构
图 3.1 展示了 springmvc-intro1 的目录结构。注意, WEB-INF/lib 目录包含了 Spring MVC所需要的所有的 jar 文件。特别需要注意的是 spring-webmvc-x.y.z.jar 文件,其中包含了DispatcherServlet 的类。还要注意 Spring MVC 依赖于 Apache Commons Logging 组件,没有它,Spring MVC 应用程序将无法正常工作。可以从以下网址下载这个组件:
http://commons.apache.org/proper/commons-loggins/download_logging.cgi
图 3.1 springmvc-intro1 的目录结构
该示例应用的所有 JSP 页面都存放在/WEB-INF/jsp 目录下,确保无法被直接访问。
(2)部署描述符文件和 Spring MVC 配置文件
清单 3.1 部署描述符(web.xml)文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"
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_3_1.xsd">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- map all requests to the DispatcherServlet -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
这里告诉了 Servlet/ JSP 容器,我们将使用 Spring MVC 的 Dispatcher Servlet,并通过url-pattern 元素值配置为“/”,将所有的 URL 映射到该 servlet。由于 servlet 元素下没有 init-param元素,所以 Spring MVC 的配置文件在/WEB-INF 文件夹下,并按照通常的命名约定。
清单 3.2 Spring MVC 配置文件
<?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">
<bean name="/input-produrt"
class="controller.InputProductController"/>
<bean name="/save-product"
class="controller.SaveProductController"/>
</beans>
这里声明了 InputProductController 和 SaveProductController 两个控制器类,并分别映射到/product_input 和/product_save。
(3)Controller 类
springmvc-intro1应用程序有 InputProductController和 SaveProductController这两个“传统”风格的控制器,分别实现了 Controller 接口。代码分别见清单 3.3 和清单 3.4。
清单 3.3 InputProductController 类
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class InputProductController implements Controller {
private static final Log logger = LogFactory
.getLog(InputProductController.class);
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
logger.info("InputProductController called");
return new ModelAndView("/WEB-INF/jsp/ProductForm.jsp");
}
}
InputProductController 类的 handleRequest 方法只是返回一个 ModelAndView,包含一个视图,且没有模型。因此,该请求将被转发到/WEB-INF/jsp/ProductForm.jsp 页面。
清单 3.4 SaveProductController 类
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import domain.Product;
import form.ProductForm;
public class SaveProductController implements Controller {
private static final Log logger = LogFactory
.getLog(SaveProductController.class);
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
logger.info("SaveProductController called");
ProductForm productForm = new ProductForm();
// populate action properties
productForm.setName(request.getParameter("name"));
productForm.setDescription(request.getParameter(
"description"));
productForm.setPrice(request.getParameter("price"));
// create model
Product product = new Product();
product.setName(productForm.getName());
product.setDescription(productForm.getDescription());
try {
product.setPrice(
Float.parseFloat(productForm.getPrice()));
} catch (NumberFormatException e) {
}
// insert code to save Product
return new ModelAndView("/WEB-INF/jsp/ProductDetails.jsp",
"product", product);
}
}
SaveProductController 类的 handleRequest 方法中,首先用请求参数创建一个 ProductForm对象;然后,它根据 ProductForm 对象创建 Product 对象。由于 ProductForm 的 price 属性是一个字符串,而其在 Product 类对应的是一个 float,此处类型转换是必要的。在第 4 章中,我们将学习在 Spring MVC 中如何省去 ProductForm 对象,使事情变得更省力。
SaveProductController 的 handleRequest 方法最后返回的 ModelAndView 模型包含了视图
的路径、模型名称以及模型(的路径、模型名称以及模型(product 对象)。该模型将提供给目标视图,用于界面显示。
springmvc-intro1 应用程序中包含两个 JSP 页面: ProductForm.jsp 页面(代码见清单 3.5)和 ProductDetails.jsp 页面(见清单 3.6)。
清单 3.5 ProductForm.jsp 页面
<!DOCTYPE HTML>
<html>
<head>
<title>Add Product Form</title>
<style type="text/css">@import url(css/main.css);</style>
</head>
<body>
<div id="global">
<form action="save- Product" method="post">
<fieldset>
<legend>Add a product</legend>
<label for="name">Product Name: </label>
<input type="text" id="name" name="name" value=""
tabindex="1">
<label for="description">Description: </label>
<input type="text" id="description" name="description"
tabindex="2">
<label for="price">Price: </label>
<input type="text" id="price" name="price" tabindex="3">
<div id="buttons">
<label for="dummy"> </label>
<input id="reset" type="reset" tabindex="4">
<input id="submit" type="submit" tabindex="5"
value="Add Product">
</div>
</fieldset>
</form>
</div>
</body>
</html>
此处不适合讨论 HTML 和 CSS,但需要强调的是清单 3.5 中的 HTML 是经过适当设计的,并且没有使用<table>来布局输入字段。
清单 3.6 ProductDetails.jsp 页面
<!DOCTYPE HTML>
<html>
<head>
<title>Save Product</title>
<style type="text/css">@import url(css/main.css);</style>
</head>
<body>
<div id="global">
<h4>The product has been saved.</h4>
<p>
<h5>Details:</h5>
Product Name: ${product.name}<br/>
Description: ${product.description}<br/>
Price: $${product.price}
</p>
</div>
</body>
</html>
ProductDetails.jsp 页面通过模型属性名“product”来访问由 SaveProductController 传入的 Product对象。这里用 JSP 表达式语言来显示 Product 对象的各种属性。
(5) 测试应用
现在,在浏览器中输入如下 URL 来测试应用:
http://localhost:8080/springmvc-introl/input-product
会看到类似图 3.2 的产品表单页面,在空字段中输入相应的值后单击“Add Product(添加产品)”按钮,会在下一页中看到产品属性。
图 3.2 springmvc-intro1 的产品表单
2.视图解析器
Spring MVC 中的视图解析器负责解析视图。可以通过在配置文件中定义一个 ViewResolver(如下)来配置视图解析器。
<bean id="viewResolver" class="org.springframework.web.servlet.
view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
视图解析器配置有前缀和后缀两个属性。这样一来, view路径将缩短。例如,仅需提供“myPage”,而不必再将视图路径设置为/WEB-INF/jsp/myPage.jsp,视图解析器将会自动增加前缀和后缀。
以 springmvc-intro2 应用为例,该例子同 springmvc-intro1应用类似,但调整了配置文件的名称和路径。此外,它还配置了默认的视图解析器,为所有视图路径添加前缀和后缀,如图3.3 所示。
图 3.3 springmvc-intro2 文件结构
清单 3.7 springmvc-intro2 应用的部署描述符
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"
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_3_1.xsd">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/springmvc-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
需要特别注意的是 web.xml 文件中的 init-param 元素。要使用非默认配置文件的命名和路径,需要使用名为 contextConfigLocation 的 init-param,其值应为配置文件在应用中的相对路径(见清单 3.8)。
清单 3.8 springmvc-intro2 的配置文件
<?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">
<bean name="/input-product"
class="controller.InputProductController"/>
<bean name="/save-product"
class="controller.SaveProductController"/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.
InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
在浏览器中输入如下 URL,测试 app03b 应用:
http://localhost:8080/springmvc-intro2/input-product
即可看到如图 3.2 所示的表单页面。
三、学习指导
SpringMVC学习指南