springMVC学习(hello world)

前面几篇文章学习了spring的基础,包括了springIOC和springAOP,spring操作jdbc,以及S2SH整合,今天开始我们的核心内容,今天带大家利用spring的MVC写一个hello world程序,先来看看springMVC的流程。

客户端发过来一个request,spring通过DispatcherServlet分发给HandlerMapping,然后由HandlerMapping决定具体跳转到那个Controller来处理,Controller处理了以后,会返回一个ModelAndView,最后ViewResolver解析ModelAndView来决定具体跳转到那个页面用来呈现给用户。
springMVC流程

新建web工程拷贝jar文件

我们新建一个web工程叫做springmvc,然后将spring需要的jar文件拷贝到web-info下的lib目录当中,需要如下jar文件:
com.springsource.javax.servlet.jsp.jstl-1.1.2.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.taglibs.standard-1.1.2.jar
org.springframework.aop-3.0.0.RELEASE.jar
org.springframework.asm-3.0.0.RELEASE.jar
org.springframework.beans-3.0.0.RELEASE.jar
org.springframework.context-3.0.0.RELEASE.jar
org.springframework.context.support-3.0.0.RELEASE.jar
org.springframework.core-3.0.0.RELEASE.jar
org.springframework.expression-3.0.0.RELEASE.jar
org.springframework.web-3.0.0.RELEASE.jar
org.springframework.web.servlet-3.0.0.RELEASE.jar
可以看到前面一些以com开头的jar文件时spring依赖的jar,而后面一些以org开头的文件时spring的核心jar包。

配置DispatcherServlet

在web.xml中配置DispatcherServlet,注意这里的DispatcherServlet类似于structs2当中的filter。

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

这里的servlet-name的名称随便给一个,但是需要注意的是两个必须相同,因为servlet会根据servlet-mapping中配置的servlet-name来查找相同名称的servlet,进而找到处理的类,这里我们的处理类就是org.springframework.web.servlet.DispatcherServlet,”.action”表示只要url中是以”.action”这种形式的,都会被DispatcherServlet来处理。

创建Controller和springAction-servlet.xml

这里的controller和structs中的action的作用是一样的。springAction-servlet.xml(这里是因为我在web.xml中配置的DispatcherServlet的名称叫做springAction,所以这里需要命名为springAction-servlet.xml)相当于structs中的structs.xml,就是根据controller的返回值来判断应该跳转到那个页面来显示给用户。我们先创建一个SpringController,注意这里需要继承AbstractController

package com.test.springmvc.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 SpringController extends AbstractController {

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest arg0,
            HttpServletResponse arg1) throws Exception {
        System.out.println("SpringController runs ....");
        return new ModelAndView("success");
    }
}

可以看到这里我们的controller继承自AbstractController,然后重写了handleRequestInternal方法,该方法的两个参数就是HttpServletRequest和HttpServletResponse,并且可以看到该方法的返回值和我们前面说的是一样的,即是ModelAndView类型,这里我直接返回的是new ModelAndView(“success”);
下面看看springAction-servlet.xml应该怎么写,我们在web-info下创建一个springAction-servlet.xml:

<?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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
                        http://www.springframework.org/schema/mvc 
                        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
                        http://www.springframework.org/schema/context 
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd 
                        http://www.springframework.org/schema/aop 
                        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
                        http://www.springframework.org/schema/tx 
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsps/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

说明一下,”name=prefix”表示需要匹配的视图的前缀,”name=suffix”表示需要匹配的视图的后缀,什么意思呢??比如说刚才在controller中返回new ModelAndView(“success”); 那么此时将匹配WEB-INF/jsps/目录下的success.jsp 这样清楚了吧。。
同时还需要配置我们的controller,如下:

<bean name="/spring.action" class="com.test.springmvc.controller.SpringController">
</bean>

这里配置的controller,name中的值表示当我请求中是以spring.action结尾的那么将会交给SpringController来处理。
此时,我访问”http://localhost:8080/springmvc/spring.action“此时系统会跳转到SpringController来做处理,然后跳转到对应的界面。

下面,我们来看看另外两种处理器映射的介绍。
1.简单的url映射:
首先我需要给之前的controller的bean添加一个id,用来唯一标识该controller:

<bean id="springId" name="/spring.action"
        class="com.test.springmvc.controller.SpringController">
</bean>

然后添加我们的SimpleUrlHandlerMapping对应的bean:

    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <map>
                <entry key="/test.action" value="springId"></entry>
                <entry key="/adb.action" value="springId"></entry>
            </map>
        </property>
    </bean>

在SimpleUrlHandlerMapping类中存在一个类型是map的mappings属性,我们通过property标签给他添加值就可以了,SimpleUrlHandlerMapping会自动根据配置去查找对应的controller来处理,比如我们配置的两个entry,第一个key=”test.action” ,value=”springId”,那么当我们通过test.action这样的url请求过来的时候,此时SimpleUrlHandlerMapping回去查找id为springId的bean对应的controller来处理。
此时就可以通过http://localhost:8080/springmvc/test.action这样的url来请求了。

2.根据类名映射:
spring为我们提供了另外一种ControllerClassNameHandlerMapping来处理映射的。顾名思义就是根据类名来映射的,比如我访问springController.action这样的url,系统将会去寻找SpringController.java类,然后来做对应的处理。

<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
</bean>

问题来了,那么如果这个时候我两种url映射都写上了,到底该根据那个来处理呢??spring为我们提供了一个属性”order”,我们可以通过设置该属性的值,来判断应该首先匹配那个规则。值越大,优先级越高。比如:

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <map>
                <entry key="/test.action" value="springId"></entry>
                <entry key="/adb.action" value="springId"></entry>
            </map>
        </property>
        <property name="order" value="3"></property>
</bean>

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

这个时候如果两种映射方式都可以匹配得到的话,那么会优先选择order值较大的一个来映射,除非第一个映射不到,才会转为order值较小的映射。

几种常见的控制器

我们之前写的SpringController是继承自AbstractController的,此时如果我需要获得浏览器请求的数据,需要通过handleRequestInternal方法中的request.getParameter(“”)方法来获得,大家有没有想过,如果我这里有很多个参数需要传递,就会有很多个request.getParameter(“”)来写,这样和servlet一样,很大的降低了效率,之前在structs2中,是利用一个实体类,然后将该实体类当成属性声明到action中,并且设置了set方法,这样在客户端传递过来的时候,自动就会将参数封装到实体类当中,那么spring中也为我们提供了这样的方便。首先,我新建一个Person类,用来封装客户端传递过来的参数:

package com.test.springmvc.model;

public class Person {
    private int id;
    private String name;
    private String pass;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    @Override
    public String toString() {
        return "Person [id=" + id + ", name=" + name + ", pass=" + pass + "]";
    }
}

封装类创建好了以后,我新建一个MyCommandController继承自AbstractCommandController,此时需要重写handle(HttpServletRequest req,HttpServletResponse res, Object obj, BindException exec)方法,我的目的是绑定客户端的参数,因此可以在MyCommandController的构造方法中绑定,这里spring和structs2还是有一点不同的。

public MyConmmandController() {
        this.setCommandClass(Person.class);
        this.setCommandName("person");
}

可以看到通过设置setCommandClass就可以指定需要封装的类了。然后再handle方法中这样进行类型转换就可以拿到浏览器传递的数据了。

protected ModelAndView handle(HttpServletRequest req,
            HttpServletResponse res, Object obj, BindException exec) throws Exception {
        Person p = (Person) obj;
        System.out.println(p);
        return new ModelAndView("showPerson");
}

注意不要忘记配置controller,此时需要在springAction-servlet.xml中配置我的controller:

<bean name="/myCommand.action" class="com.test.springmvc.commandcontroller.MyConmmandController">
</bean>

此时就可以通过”http://localhost:8080/springmvc/myCommand.action?id=121&name=uu&pass=yyy“该条url来访问了。并且可以成功的获取数据。这就是AbstractCommandController的用法。

下面看看另外一种controller,叫做SimpleFormController,这个controller是用来封装表单数据的。我新建一个类MyFormController继承自SimpleFormController。

package com.test.springmvc.commandcontroller;

import org.springframework.web.servlet.mvc.SimpleFormController;

import com.test.springmvc.model.Person;

@SuppressWarnings("deprecation")
public class MyFormController extends SimpleFormController {

    public MyFormController() {
        this.setCommandClass(Person.class);
        this.setCommandName("person");
    }

    @Override
    protected void doSubmitAction(Object command) throws Exception {
        Person p = (Person) command;
        System.out.println("dosubmit runs ...person is :"+p);
        super.doSubmitAction(command);
    }
}

可以看到这里绑定数据的方式和AbstractCommandController是相同的。可是我继承SimpleFormController之后,重写的doSubmitAction方法竟然没有返回值,之前我们是一直返回的是ModelAndView类型的,根据该类型和ViewResolver来解析跳转到对应的界面,注意:SimpleFormController需要我们自己配置,他为我们提供了两个属性:
1.formView:表示当我访问该controller对应的action时候,会跳转到该formView属性对应的值的界面
2.successView:表示当处理表单成功以后跳转到的页面。
什么意思呢?看看我的MyFormController的配置:

<bean name="/myform.action" class="com.test.springmvc.commandcontroller.MyFormController">
        <property name="formView" value="myform"></property>
        <property name="successView" value="success"></property>
    </bean>

<bean  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsps/"></property>
        <property name="suffix" value=".jsp"></property>
</bean>

我的formView的值是”myform”,那么此时当我访问”http://localhsot:8080/springmvc/myform.action“的时候,spring会跳转到”WEB-INF/jsps/myform.jsp”,现在是不是很好理解呢。再来看看我们的myform.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
  </head>

  <body>
     <form action="<%=basePath%>/myform.action" method="post">
       姓名:<input type="text" name="name">
       密码 :<input type="text" name="pass">
       <input type="submit" value="tijiao"> 
     </form>
  </body>
</html>

在myform.jsp中的form表单跳转到了myform.action里面,然后处理成功以后,会根据MyFromController中的和ViewResovler的配置,跳转到”WEB-INF/jsps/success.jsp”页面,是不是很简单呢??这就是SimpleFormController的使用。

下面介绍最后一种controller的用法,大家有没有遇到过这样一种现象,就是我提交的表单可能是有好几个页面组成的,而不是同一个页面中的表单,如果表单的数据太多的话,一页显示不下,那么可以利用多个页面来提交同一个表单,而AbstractWizardFormController正有这样的优势,它可以将多个页面的表单集合成一个表单。说了这么多,我动手试一下,新建一个MyWizardController继承自AbstractWizardFormController,然后为该controller绑定需要封装从浏览器传递过来的数据,以及重写processFinish方法:

public MyWizardController() {
        setCommandClass(Person.class);
        setCommandName("person");
    }

@Override
protected ModelAndView processFinish(HttpServletRequest arg0,
            HttpServletResponse arg1, Object arg2, BindException arg3)
            throws Exception {
        Person person = (Person) arg2;
        System.out.println("processFinish runs.....person is :"+person);
        return null;
    }

然后配置该controller,在springAction-servlet.xml下进行配置。

    <bean name="/mywizard.action" class="com.test.springmvc.commandcontroller.MyWizardController">
        <property name="pages">
            <list>
                <value>wizard/first</value>
                <value>wizard/second</value>
                <value>wizard/third</value>
            </list>
        </property>
    </bean>

<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsps/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

注意这里我为MyWizardController绑定了三个页面,这里有一个属性,是”pages”从AbstractWizardFormController中继承过来的。这三个页面的配置是有顺序的,如果我访问”http://localhost:8080/springmvc/mywizard.action“此时系统会自动跳转到”WEB-INF/jsps/wizard/first.jsp”页面。下面看看我们的这三个页面的写法:
first.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<html>
  <head>
    <base href="<%=basePath%>">
    <title>this is first</title>
  </head>

  <body>
    <form action="<%=basePath%>/mywizard.action" method="post">
        id:<input type="text" name="id">
        <input type="submit" name="_cancel" value="取消">
        <input type="submit" name="_target1" value="下一步">
    </form>
  </body>
</html>

second.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <title>this is first</title>
  </head>

  <body>
    <form action="<%=basePath%>/mywizard.action" method="post">
        name:<input type="text" name="name">
        <input type="submit" name="_target0" value="上一步">
        <input type="submit" name="_cancel" value="取消">
        <input type="submit" name="_target2" value="下一步">
    </form>
  </body>
</html>

third.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <title>this is first</title>
  </head>

  <body>
    <form action="<%=basePath%>/mywizard.action" method="post">
        pass:<input type="text" name="pass">
        <input type="submit" name="_cancel" value="取消">
        <input type="submit" name="_target1" value="上一步">
        <input type="submit" name="_finish" value="提交">
    </form>
  </body>
</html>

好了,到现在位置三个jsp就写完了,需要注意:这里的”取消”,”下一步”,”上一步”,”提交”这些按钮的name都是spring约定好的,也就是我们必须要这么写,这里的”下一步”,就会跳转到我们在pages中配置的第二个页面,再次”下一步”就会跳转到配置的第三个页面,所以说这些页面的配置是有顺序的。现在我们通过url:”http://localhost:8080/springmvc/mywizard.action“来访问,首先会跳转到first.jsp,点击下一步会跳转到second.jsp,当我点击完成的时候,才会执行MyWizardController中的processFinish方法,可以看到在该方法中,我将浏览器传递过来的数据转换成封装的对象类,然后打印出来了。

到目前为止,一切看似那么美好,可是,发现当我点击”取消”按钮的时候,会出现错误,这是因为我们没有重写processCancel方法,在MyWizardController中重写该方法:

@Override
protected ModelAndView processCancel(HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {
        // TODO Auto-generated method stub
        return new ModelAndView("cancel");
    }

这里我返回的是一个ModelAndView(“cancel)对象,就是当我点击取消的时候,spring会根据该返回值结合ViewResolver跳转到”WEB-INF/jsps/cancel.jsp”页面。

到现在为止我们的springMVC基础教程就学习完了,补充一点吧,大家发现我的”springAction-servlet.xml”默认是写在了”WEB-INF”下面,如果我想将他写到src下是否可行呢???是可以的。

首先将springAction-servlet.xml移到src下,然后只需要在web.xml中配置DispatcherServlet时候进行相应的配置初始参数”contextConfigLocation”的值即可。注意必须是这个参数,这是spring规定好的,如下:

<servlet>
    <servlet-name>springAction</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springAction-servlet.xml</param-value>
        </init-param>
</servlet>

好了,今天springMVC就学习到这里了,下一篇会带给大家基于注解的springMVC实现,希望大家喜欢。

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值