【Java EE 学习 83 上】【SpringMVC】【基本使用方法】

1、SpringMVC框架概述

  什么是SpringMVC?SpringMVC是一个和Struts2差很少的东西,他们的做用和性质几乎是相同的,甚至开发效率上也差很少,可是在运行效率上SpringMVC要高于Struts2;注意这里的SpringMVC很明确的指明了使用了MVC框架,Struts2也使用了MVC框架。html

  1.环境准备

    和以前使用的spring环境几乎是差很少的,可是须要增长两个核心包:前端

org.springframework.web.servlet-3.0.0.RELEASE.jarjava

org.springframework.web-3.0.0.RELEASE.jargit

    这是在Spring3.0的环境下,Spring3.2有了重大的升级,再也不使用org.springframework.web.servlet-3.0.0.RELEASE.jar,而是取而代之的使用了下面的jar包:github

spring-webmvc-3.2.0.RELEASE.jarweb

  固然,仍是推荐使用Spring3.2的版本,根据spring官方文档中的声明,自3.0版本以后一直到3.2版本的全部版本都存在已知的并且很明显的bug;在spring3.2中则解决了至关数量的bug。spring

  2.须要的完整jar包列表

    因为我使用的是Eclipse,因此相关jar包IDE并无提供支持,因此只能手动添加jstl.jar以及standard.jar了:express

aopalliance.jar
commons-logging.jar
jstl.jar
spring-aop-3.2.0.RELEASE.jar
spring-aspects-3.2.0.RELEASE.jar
spring-beans-3.2.0.RELEASE.jar
spring-context-3.2.0.RELEASE.jar
spring-context-support-3.2.0.RELEASE.jar
spring-core-3.2.0.RELEASE.jar
spring-expression-3.2.0.RELEASE.jar
spring-web-3.2.0.RELEASE.jar
spring-webmvc-3.2.0.RELEASE.jar
standard.jar编程

  很明显了,使用SpringMVC的另一个最大的好处就是不用像在Struts2中那样再引入一大批的jar包了。浏览器

2、第一个SpringMVC程序

  1.首先在web.xml配置文件中配置一个Servlet

<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.action</url-pattern>
</servlet-mapping>

  2.配置spring配置文件

  默认的Servlet将会读取WEB-INF文件夹下的相应配置文件;固然该配置文件的命名还须要知足规则才行:$servletName-servlet.xml,不然Servlet也找不到相应的配置文件;根据上述的配置中的servlet-name标签的值,咱们将配置文件的名字命名为:action-servlet.xml,这个配置文件实际上就是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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    <!-- 内部资源视图解析器 -->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsps/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
<beans>

  内部视图资源解析器肯定了一种规则,那就是将Controller返回的ModelAndView对象进行解析,并将viewName提取出来和"prefix"以及"suffix"进行拼接,获得须要跳转的资源位置,并执行跳转,具体是重定向仍是转发,须要根据ModelAndView的内容进行肯定。

  这里则是假设全部jsp页面都保存到了/jsps目录下,而且都是以.jsp结尾。

  3.新建控制器

  全部控制器的超类都是AbstractController,这里直接继承该类,并重写该类的核心方法:handleRequestInternal,该方法返回值是ModelAndView对象,该对象必须赋予一个字符串表明资源的位置。

package com.kdyzm.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class HomeController extends AbstractController {
    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        System.out.println("你好,这是第一个SpringMVC程序!");
        return new ModelAndView("index");
    }
}

  这里的index通过"内部视图资源解析器"解析以后,就转变成了真正的地址:/jsps/index.jsp,在浏览器上就须要使用http://localhost:8080/项目名称/jsps/index.jsp来访问了。

  新建控制器以后须要将控制器注入到spring容器管理。

<bean name="/home.action" class="com.kdyzm.controller.HomeController"></bean>

  4.在/jsp/文件夹下新建jsp页面index.jsp

 1 <%@ page language="java" pageEncoding="utf-8"%>
 2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 3 <html>
 4 <head>
 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 6 <title>Insert title here</title>
 7 </head>
 8 <body>
 9     你好,这是第一个SpringMVC程序!
10 </body>
11 </html>

  5.在浏览器上输入http://localhost:8080/springmvc/home.action进行测试

  

  测试成功。

3、三种不一样的URL处理器映射

  所谓的处理器映射就是一种Map对象,它储存着请求的url到控制器的映射,它可以将咱们的请求转交给某一个指定的控制器处理。

  1.Bean名url处理器映射

    这是默认的url处理器映射,也是最常使用的url处理器映射;所谓默认,就是不配置也会自动加载,这里显式声明一下意思意思:

<bean
    class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
    <property name="order" value="3"></property>
</bean>

    它有一个serOrder方法,该方法可以肯定该url处理器的优先级,若是配置了多个url处理器映射,那么该值越大的越有限匹配;以前的例子因为没有明确的配置url处理器映射,因此使用的是默认的url处理器映射。

  2.简单url处理器映射

    这种url处理器映射基本上没有人使用,由于使用这种方式须要将key和值一一列举出来,这种工做量即便在一个中型项目中也是难以承受的。

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="order" value="2"></property>
    <property name="mappings">
        <map>
            <entry key="/abc.action" value-ref="homeAction"></entry>
            <entry key="/xiaozhang.action" value-ref="homeAction"></entry>
        </map>
    </property>
</bean>

  使用这种形式的访问方式就是使用key值部分,好比上述的例子中定义了两个能够都指向了同一个资源:homeAction,那么使用这两种方式都可以访问到同一个页面:

  http://localhost:8080/springmvc1/abc.action或者http://localhost:8080/springmvc1/xiaozhang.action

  

  

  3.控制器类名处理器映射

    顾名思义,使用这种方式可以直接经过控制器的类名访问控制器,使用这种方式虽然简单可是使用这种凡有着很明显的弊端,那就是若是不一样的包中若是定义了相同类名的控制器,那么使用这种方式确定会出错。因此也不推荐使用这种方式。

<bean
    class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
    <property name="order" value="1"></property>
</bean>

    使用控制器类名直接访问控制器,可是注意须要将类名首字母编程小写:

  

  4.综上所述,这三种控制器映射中,只有第一种配置起来最简单,并且最灵活,是强烈推荐的使用方式。

4、三种不一样的控制器

  SpringMVC中控制器的概念和Struts2中的Action的概念几乎是差很少的,尝试着将控制器看作Action会发现理解起来就会简单的多。

  1.最基本的控制器

    直接继承AbstractController,该抽象类是全部控制器的超类,直接继承该抽象类也可以实现简单的数据处理功能。

 1 package com.kdyzm.controller;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 
 6 import org.springframework.web.servlet.ModelAndView;
 7 import org.springframework.web.servlet.mvc.AbstractController;
 8 
 9 public class HomeController extends AbstractController {
10     @Override
11     protected ModelAndView handleRequestInternal(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
12         System.out.println("这是第二个SpringMVC程序!");
13         return new ModelAndView("index");
14     }
15 }

  在XML文件中的配置:

<bean id="homeAction" name="/home.action" class="com.kdyzm.controller.HomeController"></bean>

  在讲解接下来的几个控制器以前首先须要建立一个JavaBean:

 1 package com.kdyzm.domain;
 2 
 3 import java.io.Serializable;
 4 
 5 public class Person implements Serializable {
 6     private static final long serialVersionUID = 1298989747316274828L;
 7     private int id;
 8     private String name;
 9     private String address;
10     private int age;
11 
12     /****************** 华丽的分割线 **************************/
13     public int getId() {
14         return id;
15     }
16 
17     public void setId(int id) {
18         this.id = id;
19     }
20 
21     public String getName() {
22         return name;
23     }
24 
25     public void setName(String name) {
26         this.name = name;
27     }
28 
29     public String getAddress() {
30         return address;
31     }
32 
33     public void setAddress(String address) {
34         this.address = address;
35     }
36 
37     public int getAge() {
38         return age;
39     }
40 
41     public void setAge(int age) {
42         this.age = age;
43     }
44 
45     @Override
46     public String toString() {
47         return "Person [id=" + id + ", name=" + name + ", address=" + address + ", age=" + age + "]";
48     }
49 }
com.kdyzm.domain.Person

  2.命令控制器

  使用这种控制器可以实现简单的数据的收发,而且可以实现自动封装成Bean对象;可是须要经过构造方法注册命令类和命令名称。

 1 package com.kdyzm.controller;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 
 6 import org.springframework.validation.BindException;
 7 import org.springframework.web.servlet.ModelAndView;
 8 import org.springframework.web.servlet.mvc.AbstractCommandController;
 9 
10 import com.kdyzm.domain.Person;
11 
12 /**
13  * 命令控制器
14  * 
15  * @author kdyzm
16  *         访问形式:http://localhost:8080/springmvc1/commandController.action?id=1&
17  *         name=xiaozhang&age=12&address=shandong
18  */
19 @SuppressWarnings("deprecation")
20 public class MyCommandController extends AbstractCommandController {
21     /**
22      * 须要经过构造方法注册命令类和命令名称
23      */
24     public MyCommandController() {
25         this.setCommandClass(Person.class);
26         this.setCommandName("person");
27     }
28 
29     @Override
30     protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command,
31             BindException errors) throws Exception {
32         System.out.println("使用了CommandController控制器!" + command);
33         return new ModelAndView("index");
34     }
35 
36 }

  须要注意的是使用这种方式必须继承AbstractCommandController抽象类,可是这种方式已通过时了,也就是不推荐使用了,查看javadoc:

  

  在上面画圈的部分能够看出,在spring3.0以后这种方式就已通过时了,推荐使用注解控制器的方式;注解控制器的方式以后再说。

  先看XML文件中的配置,XML文件中的配置也十分简单,只须要注入到Spring容器中便可:

<bean id="commandController" name="/commandController.action"
        class="com.kdyzm.controller.MyCommandController"></bean>  

  3.表单控制器

  表单控制器的特色是:

    (1)可以自动将获取的参数封装成Bean对象

    (2)能够自动识别请求的方式,并根据请求方式的不一样使用不一样方式进行处理

      若是是GET方式的请求,则会自动转发到显示表单的页面;若是是POST请求,就会对数据进行封装并跳转到程序中定义好的页面。

 1 package com.kdyzm.controller;
 2 
 3 import org.springframework.web.servlet.mvc.SimpleFormController;
 4 
 5 import com.kdyzm.domain.Person;
 6 /**
 7  * 简单表单控制器
 8  * 访问方法:http://localhost:8080/springmvc1/formController.action
 9  * 表单页面显示方法和访问的表单提交的对象都是相同的url地址
10  * @author kdyzm
11  *
12  */
13 @SuppressWarnings("deprecation")
14 public class MyFormController extends SimpleFormController {
15     /**
16      * 在构造方法中实现注册命令类和命令名称
17      */
18     public MyFormController() {
19         this.setCommandClass(Person.class);
20         this.setCommandName("person");
21         System.out.println("执行了formController的构造方法!");
22     }
23     /**
24      * 执行set、get方法的时候会出问题!
25      * 表单内容必须填写正确,不然不能正确提交!最后执行不了该方法!
26      */
27     @Override
28     protected void doSubmitAction(Object command) throws Exception {
29         System.out.println("MyFormController:"+command);
30         super.doSubmitAction(command);
31     }
32 }

    注意上面的方法的返回值是void,该方法的返回值为何不是ModelAndView对象呢?由于成功以后须要跳转的页面是由配置文件决定的。

    XML文件中的配置和以前相比有些不一样:

<bean id="formController" name="/formController.action"
    class="com.kdyzm.controller.MyFormController">
    <property name="formView" value="formView"></property>
    <property name="successView" value="index"></property>
</bean>

    注意上面红色背景部分的内容,formView部分配置的是若是接收到了GET方式的请求,就会重定向到formView.jsp页面上,若是接收到了POST请求,那么就会执行上面的doSubmitAction方法,若是执行该方法的过程当中并无出现异常,执行该方法以后就会跳转到配置的成功页面上去。

  注意,在执行该doSubmitAction方法以前就已经将javaBean封装好了,若是封装的过程当中出现异常,Spring并不会报错提醒,只是将页面跳转到显示form表单的页面上去而已,这会让人百思不得其解到底发生了什么事情,实际上就是封装javaBean失败而已;最多见的错误信息就是"类型不匹配",好比javaBean中定义的类型是int类型,可是在前端页面上传递过来的数据不能转换成整型类型,这种状况下就会发生转换失败的状况,这样就不能跳转到成功页面上去了。

  这种方式也已通过时了,过期的缘由和以前相同,在spring3.0以后就推荐使用注解控制器实现了。

  4.向导表单控制器

  这种控制器的特色:

    (1)可以跨页面实现表单提交,好比调查问卷,一页显示不完,须要多个页面才能显示完成,可是提交的时候就须要提交全部的信息

    (2)可以自动封装提交的数据,固然这种功能以前的表单控制器也可以实现

    (3)使用这种方式须要特别注意数据回显的问题

  

 1 package com.kdyzm.controller;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 
 6 import org.springframework.validation.BindException;
 7 import org.springframework.web.servlet.ModelAndView;
 8 import org.springframework.web.servlet.mvc.AbstractWizardFormController;
 9 
10 import com.kdyzm.domain.Person;
11 /**
12  * 向导表单控制器
13  * @author kdyzm
14  *
15  */
16 @SuppressWarnings("deprecation")
17 public class MyWizardController extends AbstractWizardFormController{
18     /**
19      * 仍是须要经过构造方法注册命令类和命令方法
20      */
21     public MyWizardController() {
22         this.setCommandClass(Person.class);
23         this.setCommandName("person");
24     }
25     /**
26      * 当最终提交了表单以后将会访问该方法
27      */
28     @Override
29     protected ModelAndView processFinish(HttpServletRequest request, HttpServletResponse response, Object command,
30             BindException errors) throws Exception {
31         System.out.println("访问了WizardController类:"+command);
32         return new ModelAndView("index");
33     }
34     @Override
35     protected ModelAndView processCancel(HttpServletRequest request, HttpServletResponse response, Object command,
36             BindException errors) throws Exception {
37         System.out.println("访问了processCancel方法!"+command);
38         return new ModelAndView("index");
39     }
40 }

  固然,使用这种方式也得经过构造方法实现注册命令类和命令方法;关键是得重写上面红色背景部分的方法,这两个方法分别对应着提交的方法和取消的方法,并且返回值都是ModelAndView,这就意味着不须要咱们经过配置文件的方式实现页面的跳转了,这时候就使用ModelAndView的方式实现页面的跳转。

  配置文件和以前的配置文件也有比较大的区别:

<bean id="wizardFormController" name="/wizard.action"
    class="com.kdyzm.controller.MyWizardController">
    <property name="pages">
        <list>
            <value>wizard/1</value>
            <value>wizard/2</value>
            <value>wizard/3</value>
        </list>
    </property>
</bean>

  这里的pages属性指的就是全部的分页;wizard/1实际上就是/jsps/wizard/1.jsp,也就是说我在/jsps/wizard文件夹中新建了三个jsp文件,这三个jsp文件组成了"提交"表单这一事件。

  在每一个jsp页面中,须要视状况给它们分配几个"提交"按钮,好比上一页、下一页、退出、提交,可是每一个提交按钮都须要给它们分配一个预先定义好的名字;这个名字不是根据咱们的规则定义的,而是根据AbstractWizardFormController类的规则定义的。

 org.springframework.web.servlet.mvc.AbstractWizardFormController

Deprecated. as of Spring 3.0, in favor of annotated controllers

Form controller for typical wizard-style workflows.

In contrast to classic forms, wizards have more than one form view page. Therefore, there are various actions instead of one single submit action:

  • finish: trying to leave the wizard successfully, that is, perform its final action, and thus requiring a valid state;
  • cancel: leaving the wizard without performing its final action, and thus without regard to the validity of its current state;
  • page change: showing another wizard page, e.g. the next or previous one, with regard to "dirty back" and "dirty forward".

Finish and cancel actions can be triggered by request parameters, named PARAM_FINISH ("_finish") and PARAM_CANCEL ("_cancel"), ignoring parameter values to allow for HTML buttons. The target page for page changes can be specified by PARAM_TARGET, appending the page number to the parameter name (e.g. "_target1"). The action parameters are recognized when triggered by image buttons too (via "_finish.x", "_abort.x", or "_target1.x").

The current page number will be stored in the session. It can also be specified as request parameter PARAM_PAGE ("_page") in order to properly handle usage of the back button in a browser: In this case, a submission will always contain the correct page number, even if the user submitted from an old view.

The page can only be changed if it validates correctly, except if a "dirty back" or "dirty forward" is allowed. At finish, all pages get validated again to guarantee a consistent state.

Note that a validator's default validate method is not executed when using this class! Rather, the validatePage implementation should call special validateXXX methods that the validator needs to provide, validating certain pieces of the object. These can be combined to validate the elements of individual pages.

Note: Page numbering starts with 0, to be able to pass an array consisting of the corresponding view names to the "pages" bean property.

   上述文档说明了规则:

    (1)若是是"提交"按钮,名字必须是"_finish"

    (2)若是是"退出"按钮,名字必须是"_cancle"

    (3)若是是"上一页"或者"下一页"按钮,名字的前缀必须是"_target",后面跟着目标页的页码,规律是若是是第一页,那么页码就是0;若是是第二页,页码就是1,以此类推。

  另外以前配置文件中的

    <value>wizard/1</value>
    <value>wizard/2</value>
    <value>wizard/3</value>

   并无什么特别的含义,并不是写了1就是第一页,其实任何名字也无所谓,实际上摆放的位置决定了它真实的页序。

  注意:全部过程当中访问的url地址都是:http://localhost:8080/springmvc1/wizard.action,至于向导表单控制器是如何进行逻辑处理的,这种事情就不须要咱们操心了。

5、项目练习源代码地址

https://github.com/kdyzm/springmvc1

相关文章
相关标签/搜索