Spring入门17 - 第一个Spring MVC Web程序

时间:2021-05-16 21:57:47

入门 17 - 第一个Spring MVC Web程序

 在进行这个程序之前,请您先完成入门 04 - 第一个Spring程序
 我们的第一个Spring MVC Web程序将使用Tomcat 5.0.28来示范,我们在webapps目录下建立一个springapp目录,这次为了方便,我们直接使用spring.jar,以及其相依的 commons-logging.jar,请将这两个jar放到 springapp/WEB-INF/lib下。
 Spring MVC框架的中心是dispatcher:org.springframework.web.servlet.DispatcherServlet。 DispatcherServlet负责将Web请求分派(dispatch)给handler,Spring为handler定义了预设接口: org.springframework.web.servlet.mvc.Controller:

Controller.java

public interface Controller {

    public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse res) throws Exception;

}


 DispatcherServlet分派请求的根据是委托给实作 org.springframework.web.servlet.HandlerMapping接口的对象来处理,例如 org.springframework.web.servlet.handler.SimpleUrlHandlerMapping,请求与 handler之间的映射是撰写在Bean定义档中。
 DispatcherServlet本身是一个Servlet,我们要先在web.xml中定义:

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>

                                                                               

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"

    version="2.4">

                                                                               

    <description>

        Spring App Examples.

    </description>

    <display-name>Spring App Examples</display-name>

   

    <servlet>

        <servlet-name>hello</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    </servlet>

    <servlet-mapping>

        <servlet-name>hello</servlet-name>

        <url-pattern>*.do</url-pattern>

    </servlet-mapping>

                                                                               

</web-app>


 在web.xml中,我们定义了一个DispatcherServlet的实例hello,所有*.do结尾的请求都会由它来处理, DispatcherServlet预设会使用Servlet的名称为前置,读取name-servlet.xml作为其Bean定义档,以上面的设定即 读取hello-servlet.xml。依这个机制,如果您要多个模块,可以定义不同的名称来使用多个DispatcherServlet的实例,并分别读取不同的Bean定义档。
 您也可以自行定义Bean定义档的名称,像是:

<servlet>

    <servlet-name>hello</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>/WEB-INF/hello1-servlet.xml, /WEB-INF/hello2-servlet.xml</param-value>

    </init-param>     

</servlet>


 我们这边使用预设的hello-servlet.xml作为Bean定义档的名称,其内容如下:

hello-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

        <property name="mappings">

            <props>

                <prop key="/hellouser.do">helloUserAction</prop>

            </props>

        </property>

    </bean>

   

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <property name="viewClass">

            <value>org.springframework.web.servlet.view.InternalResourceView</value>

        </property>

    </bean>

   

    <bean id="helloUserAction" class="onlyfun.caterpillar.HelloUserAction">

        <property name="helloWord">

            <value>Hello!</value>

        </property>

        <property name="viewPage">

            <value>/WEB-INF/jsp/hellouser.jsp</value>

        </property>

    </bean>

</beans>


 DispatcherServlet将请求与handler的映射交给HandlerMapping的实作 org.springframework.web.servlet.view.InternalResourceViewResolver,在上面的设定中,我们将/hellouser.do的请求交给名称为helloUserAction的handler,它是个实作Controller接口的类别,我 们待会再来看看它。
 先来关心一下viewResolver,Spring可以让您使用不同的表示层技术,透过viewResolver的转换,您的表示层可以使用纯綷的 JSP/Servlet、JSTL、Velocity、Tiles等等,在这边我们使用JSP/Servlet,您只要简单的设定viewClass属性 为org.springframework.web.servlet.view.InternalResourceView。如果您的表示层使用 JSTL,则可以设定org.springframework.web.servlet.view.JstlView,同样的,对于Spring支持的其 它表示层技术,Spring都提供有一个viewClass可以设定。
 来看看helloUserAction,它实作了Controller界面:

HelloUserAction.java

package onlyfun.caterpillar;

 

import java.io.IOException;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

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

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.bind.RequestUtils;

 

public class HelloUserAction implements Controller {

   private String helloWord;

    private String viewPage;

   

   public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse res)

        throws ServletException, IOException {

      String user = RequestUtils.getRequiredStringParameter(req, "user");

      Map model = new HashMap();

      model.put("helloWord", getHelloWord());

      model.put("user", user);

   

       return new ModelAndView(getViewPage(), model);

    }

   

    public void setViewPage(String viewPage) {

       this.viewPage = viewPage;

    }

   

    public String getViewPage() {

       return viewPage;

    }

 

    public void setHelloWord(String helloWord) {

       this.helloWord = helloWord;

    }

   

    public String getHelloWord() {

       return helloWord;

    }

}


 handlerRequest()在MVC/Model2中扮演的作用,在于处理请求内容、呼叫商务对象、准备Model,它必须返回一个ModelAndView的实例,表示最后要显示给使用者观看的表示层资源。
 在上面的例子中,我们只是将请求中的user参数取出,填入Model中,ModelAndView接受一个Map对象作为请求,之后viewResolver会根据所设定的viewClass将之转换为View层可以抽取出来的数据源。
 在上面的例子中,我们使用了依赖注入的方式设定helloWord,以及View的地址,利用依赖注入的方式,我们可以避免将View的资源地址写死在 程序中,而请您回顾一下viewPage属性,我们设定其为/WEB-INF/jsp/hellouser.jsp,将资源设定在WEB-INF中,可以避免使用者直接存取资源,以获得较高的安全性与资源访问控制
 hellouser.jsp的内容如下,我们使用了JSP 2.0的Expression Language将Model取出以显示在页面上:

hellouser.jsp

<html>

<head><title>HelloPage</title></head>

<body>

    <H1> ${helloWord}, ${user}!!</H2>

</body>

</html>


现在可以启动您的Servlet容器了,在网址列输入本地测试地址:

http://localhost:8080/springapp/hellouser.do?user=Justin


我们给了一个请求参数user=Justin,程序执行的结果如下:

<html>

<head><title>HelloPage</title></head>

<body>

    <H1> Hello!, Justin!!</H2>

</body>

</html>