Spring MVC
SpringMVC 是一个包含了 Dispatcher servlet 的 MVC 框架,它调用控制器方法并转发到视图,
SpringMVC 能够加速开发的功能列表:
1. SpringMVC 中提供了一个开箱即用 Dispatcher servlet,无需额外开发。
2. SpringMVC 中使用基于 XML 的配置文件,可以编辑,而无需重新编译应用程序。
3. SpringMVC 实例化控制器,并根据用户输入来构造 bean
4. SpringMVC 可以自动绑定用户输入,并正确地转换数据类型。例如,SpringMVC 能够自动解析字符串,并设置 float 或 decimal 类型的属性
5. SpringMVC 内置了常见的校验器,可以校验用户输入,若校验不通过,则重定向会输入表单。输入校验是可选的,支持编程以及声明方式
6. SpringMVC 是 Spring 框架的一部分,可以利用 Spring 提供的其他能力
7. SpringMVC 支持国际化和本地化,支持根据用户区域显示多国语言
8. SpringMVC 支持多种视图技术,如 JSP、Velocity、FreeMarker
Spring MVC的配置可以分为基于 XML 的配置文件和注解(Spring 2.5之后)来管理应用中所用的 bean。
Spring MVC 的 DispatcherServlet
org.spring.framework.web.servlet.DispatcherServlet
要使用这个 Servlet,需要将其配置到部署描述符(web.xml)中,使用 <servlet> 元素和 <servlet-mapping> 元素,如下
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <!-- 可选项,存在表名将在应用程序启动时装载Servlet并调用其init()方法;若不存在则在该servlet的第一次请求时加载 --> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> <!-- 该 Servlet 处理所有的请求 --> </servlet-mapping>
Spring MVC 的配置文件
Dispatcher Servlet 会在应用中寻找一个 Spring MVC 的配置文件,该配置文件的默认命名和默认位置为:
/WEB-INF/servletName-servlet.xml // servletName是部署描述符中 <servlet-name> 元素的值
也可以通过部署描述符的 <init-param> 元素修改 Spring MVC 配置文件的名称和位置,可以放置在应用程序目录中的任何地方。
<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> <!-- Spring MVC 配置文件的位置和名称 --> </init-param> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
Spring MVC 的 Controller 接口
在 Spring 2.5 以前,开发一个控制器的唯一方法是实现 org.springframework.web.servlet.mvc.Controller 接口,该接口公开了一个方法
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws java.lang.Exception //
Controller 接口的实现类可以访问对应请求的 httpServletRequest 和 HttpServletResponse,还必须返回一个包含视图路径或视图路径和模型的 ModelAndView 对象。
Controller 接口的实现类只能处理一个单一动作(action),而一个基于注解的控制器可以同时支持多个请求处理动作,并且无需实现任何接口。
Spring MVC 中的视图解析器
org.springframework.web.servlet.view.InternalResourceViewResolver
视图解析器负责解析视图,可以通过在 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>
采用视图解析器后,在控制器类中只需要提供视图名称即可,视图解析器会自动加前缀和后缀。
例如,视图名为 ProductDetails,经过视图解析器处理后变为 /WEB-INF/jsp/ProductDetails.jsp
一个 Spring MVC 的简单应用(未使用视图解析器)
目录结构
部署描述符(web.xml)
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <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> <url-pattern>/</url-pattern> <!-- 该 Servlet 处理所有的请求 --> </servlet-mapping> </web-app>
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="/product_input.action" class="app17a.controller.InputProductController" /> <bean name="/product_save.action" class="app17a.controller.SaveProductController" /> </beans>
app17a.controller.InputProductController类
package app17a.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"); } }
app17a.controller.SaveProductController类
package app17a.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 app17a.domain.Product; import app17a.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(); productForm.setName(request.getParameter("name")); productForm.setDescription(request.getParameter("description")); productForm.setPrice(request.getParameter("price")); Product product = new Product(); product.setName(productForm.getName()); product.setDescription(productForm.getDescription()); try { product.setPrice(Float.parseFloat(productForm.getPrice())); } catch (NumberFormatException e) { e.printStackTrace(); } return new ModelAndView("/WEB-INF/jsp/ProductDetails.jsp", "product", product); } }
app17a.domain.Product类
package app17a.domain; import java.io.Serializable; public class Product implements Serializable { // 一个JavaBean 实现该接口,其实例可以安全的将数据保存到 HttpSession 中。 private static final long serialVersionUID = 1L; private String name; private String description; private float price; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } }
app17a.form.ProductForm类
package app17a.form; // 表单类与 HTML表单相映射,是HTML表单在服务端的代表 public class ProductForm { // 表单类不需要实现 Serializable 接口,因为表单对象很少保存在 HttpSession 中。 private String name; private String description; private String price; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } }
ProductForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Add Product Form</title> <link type="text/css" rel="stylesheet" href="css/main.css" /> </head> <body> <div id="global"> <form action="product_save.action" method="post"> <fieldset> <legend>Add a product</legend> <p> <label for="name">Product Name: </label> <input type="text" id="name" name="name" value="" tabindex="1" /> </p> <p> <label for="description">Description: </label> <input type="text" id="description" name="description" tabindex="2" /> </p> <p> <label for="price">Price: </label> <input type="text" id="price" name="price" tabindex="3" /> </p> <div id="buttons"> <label for="dummy"> </label> <input type="reset" id="reset" tabindex="4" /> <input type="submit" id="submiy" tabindex="5" /> </div> </fieldset> </form> </div> </body> </html>
ProductDetails.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Save Product</title> <link type="text/css" rel="stylesheet" href="css/main.css" /> </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>
测试结果
使用视图解析器的 Spring MVC 应用
目录结构
部署描述符(web.xml)
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <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> <!-- Spring MVC 配置文件的位置和名称 --> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping>
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="/product_input.action" class="app17b.controller.InputProductController" /> <bean name="/product_save.action" class="app17b.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>
其他文件内容不变,测试效果一样。