為了賬號安全,請及時綁定郵箱和手機立即綁定

SpringMVC從入門到精通之第二章

2016.01.15 01:01 10807瀏覽

這一章原本我是想寫一個入門程序的,但是后來仔細想了一下,先從下面的圖中的組件用代碼來介紹,可能更效果會更加好一點。
第一節:開發準備
介紹之前先說下我的開發調試環境:
JDK 1.7的64位 、Eclipse Kepler(J2EE) 64位的、Tomcat 7.0.42 mysql 5.1、SQLyog(這是我的標配)
springmvc 版本 3.2(這個大家可以到網上自行下載最好要有源碼)
第二節:開發與配置
架構圖
第一步發送request請求,這個一步我就不說了,之前有看到慕課有很多朋友分享了http協議的介紹傳送
開發環境介紹過了,下面來創建一個工程:如下圖 整個工程結構
工程結構
在hanson.springmvc.pojo中新建一個Items類包含屬性如下圖:
實體類
用戶發送請求到前端控制器。前端控制器需要在web.xml中配置:

<!-- 配置前端控制器 -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--加載前端控制器配置文件 上下文配置位置-->
    <init-param>
        <!-- 備注:
            contextConfigLocation:指定springmvc配置的加載位置,如果不指定則默認加
            載WEB-INF/[DispatcherServlet的Servlet 名字]-servlet.xml(例如springmvc-servlet.xml)。
         -->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext-servlet.xml</param-value>
    </init-param>
    <!-- 表示隨WEB服務器啟動 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!-- 備注:可以攔截三種請求 
        第一種:攔截固定后綴的url,比如設置為 *.do、*.action, 例如:/user/add.action 此方法最簡單,不會導致靜態資源(jpg,js,css)被攔截.
        第二種:攔截所有,設置為/,例如:/user/add  /user/add.action此方法可以實現REST風格的url,
                很多互聯網類型的應用使用這種方式.但是此方法會導致靜態文件(jpg,js,css)被攔截后不能正常顯示.需要特殊處理.
        第三種:攔截所有,設置為/*,此設置方法錯誤,因為請求到Action,當action轉到jsp時再次被攔截,提示不能根據jsp路徑mapping成功.
     -->
    <url-pattern>*.action</url-pattern>
  </servlet-mapping>

工程結構圖:
工程結構圖2
到這里前端配置器就算配置完了,目前這個配置足夠我們學習springmvc了。
你需要知道的是:前端控制器的作用,如何配置,以及攔截什么樣的請求。對于restful風格的請求我會在后面講到。
第三節 Handler的開發
開發之前先說一說處理器適配器。說之前就得說一說適配器模式我們就拿生活中的例子來解釋一下適配器模式,現在只有一個三相的插座,但是現在卻有一個三相插頭的洗衣機和一個二相插頭的電視機,那么洗衣機當然沒有問題,可以插到三相插座上,但是電視機卻沒辦法插了,于是人們想出了一個適配器,這個適配器一頭插在這個三相插座上,另外一端放出一個二相插座,然后電視就插在了這個適配器的二相插座上了,最后洗衣機,電視機都可以使用了。總結起來就是一句:將一個類的接口適配成用戶所期待的。
加上之前說的,想要看清3D電影,就必須帶上3D眼鏡。
springmvc中也是這樣要求處理器實現多種接口才能被處理器適配器執行。
下面來介紹幾個處理器適配器,以及他們能夠執行的處理器。
第一個:
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter簡單的處理器適配器,此適配器能夠執行實現org.springframework.web.servlet.mvc.Controller接口的處理器,來看下源碼:

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

    public boolean supports(Object handler) {
        //該類支持Controller類型的處理器
        return (handler instanceof Controller);
    }

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return ((Controller) handler).handleRequest(request, response);
    }

    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }
}

既然要求這個適配器支持的類型是Controller類型的,那我們就實現這個接口
代碼如下:

package hanson.springmvc.web.controller;

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

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
/**
 * 
 * @ClassName: ItemsController1   
 * @Description: TODO(簡單的處理器適配器支持執行實現Controller接口的處理器)   
 * @author: Hanson
 * @date: 2016年1月14日 下午11:59:06   
 *
 */
public class ItemsController1 implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        return null;
    }

}

第四節
ModelAndView對象封裝了模型數據和視圖對象,有一個組件叫視圖解析器,就是用來解析這個對象的,它可以把這個對象解析成兩部分一個為Model另一個為View然后將model渲染到View上面(簡單點就是將model里面的數據放到頁面),最終返回給用戶。
我用靜態數據模擬一下這個實現。

@Override
    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        // 商品列表
        List<Items> itemsList = new ArrayList<Items>();
        Items items_2 = new Items();
        items_2.setName("蘋果手機");
        items_2.setPrice(6088f);
        items_2.setDetail("iphone6s蘋果手機!");
        itemsList.add(items_2);
        // 創建modelAndView:填充數據、設置視圖
        ModelAndView modelAndView = new ModelAndView();
        // 填充數據
        modelAndView.addObject("itemsList", itemsList);// 類似request.setAttribute("","")
        // 視圖:邏輯名稱
        modelAndView.setViewName("jsp/itemsList");// request.getRequestDispatcher("url").forward(request, response);
        return modelAndView;
    }

jsp中代碼:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>查詢商品列表</title>
</head>
<body>
    商品列表:
    <table width="100%" border=1>
        <tr>
            <td>商品名稱</td>
            <td>商品價格</td>
            <td>商品描述</td>
        </tr>
        <c:forEach items="${itemsList }" var="item">
            <tr>
                <td>${item.name }</td>
                <td>${item.price }</td>
                <td>${item.detail }</td>
            </tr>
        </c:forEach>

    </table>
</body>
</html>

再看下工程結構:
工程結構三
第五節
下面我們來看看之前提到的視圖解析器org.springframework.web.servlet.view.InternalResourceViewResolver類是用來解析jsp的它要求類路徑下面有jstl的jar。源碼如下:

/*
 * Copyright 2002-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.servlet.view;

import org.springframework.util.ClassUtils;

/**
 * Convenient subclass of {@link UrlBasedViewResolver} that supports
 * {@link InternalResourceView} (i.e. Servlets and JSPs) and subclasses
 * such as {@link JstlView}.
 *
 * <p>The view class for all views generated by this resolver can be specified
 * via {@link #setViewClass}. See {@link UrlBasedViewResolver}'s javadoc for details.
 * The default is {@link InternalResourceView}, or {@link JstlView} if the
 * JSTL API is present.
 *
 * <p>BTW, it's good practice to put JSP files that just serve as views under
 * WEB-INF, to hide them from direct access (e.g. via a manually entered URL).
 * Only controllers will be able to access them then.
 *
 * <p><b>Note:</b> When chaining ViewResolvers, an InternalResourceViewResolver
 * always needs to be last, as it will attempt to resolve any view name,
 * no matter whether the underlying resource actually exists.
 *
 * @author Juergen Hoeller
 * @since 17.02.2003
 * @see #setViewClass
 * @see #setPrefix
 * @see #setSuffix
 * @see #setRequestContextAttribute
 * @see InternalResourceView
 * @see JstlView
 */
public class InternalResourceViewResolver extends UrlBasedViewResolver {

    private static final boolean jstlPresent = ClassUtils.isPresent(
            "javax.servlet.jsp.jstl.core.Config", InternalResourceViewResolver.class.getClassLoader());

    private Boolean alwaysInclude;

    private Boolean exposeContextBeansAsAttributes;

    private String[] exposedContextBeanNames;

    /**
     * Sets the default {@link #setViewClass view class} to {@link #requiredViewClass}:
     * by default {@link InternalResourceView}, or {@link JstlView} if the JSTL API
     * is present.
     */
    public InternalResourceViewResolver() {
        Class viewClass = requiredViewClass();
        if (viewClass.equals(InternalResourceView.class) && jstlPresent) {
            viewClass = JstlView.class;
        }
        setViewClass(viewClass);
    }

    /**
     * This resolver requires {@link InternalResourceView}.
     */
    @Override
    protected Class requiredViewClass() {
        return InternalResourceView.class;
    }

    /**
     * Specify whether to always include the view rather than forward to it.
     * <p>Default is "false". Switch this flag on to enforce the use of a
     * Servlet include, even if a forward would be possible.
     * @see InternalResourceView#setAlwaysInclude
     */
    public void setAlwaysInclude(boolean alwaysInclude) {
        this.alwaysInclude = Boolean.valueOf(alwaysInclude);
    }

    /**
     * Set whether to make all Spring beans in the application context accessible
     * as request attributes, through lazy checking once an attribute gets accessed.
     * <p>This will make all such beans accessible in plain <code>${...}</code>
     * expressions in a JSP 2.0 page, as well as in JSTL's <code>c:out</code>
     * value expressions.
     * <p>Default is "false".
     * @see InternalResourceView#setExposeContextBeansAsAttributes
     */
    public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) {
        this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes;
    }

    /**
     * Specify the names of beans in the context which are supposed to be exposed.
     * If this is non-null, only the specified beans are eligible for exposure as
     * attributes.
     * @see InternalResourceView#setExposedContextBeanNames
     */
    public void setExposedContextBeanNames(String[] exposedContextBeanNames) {
        this.exposedContextBeanNames = exposedContextBeanNames;
    }

    @Override
    protected AbstractUrlBasedView buildView(String viewName) throws Exception {
        InternalResourceView view = (InternalResourceView) super.buildView(viewName);
        if (this.alwaysInclude != null) {
            view.setAlwaysInclude(this.alwaysInclude);
        }
        if (this.exposeContextBeansAsAttributes != null) {
            view.setExposeContextBeansAsAttributes(this.exposeContextBeansAsAttributes);
        }
        if (this.exposedContextBeanNames != null) {
            view.setExposedContextBeanNames(this.exposedContextBeanNames);
        }
        view.setPreventDispatchLoop(true);
        return view;
    }

}

它需要在applicationContext-servlet.xml中配置:

<!-- 配置視圖解析器 -->
    <!-- InternalResourceViewResolver:支持JSP視圖解析 -->
    <!-- viewClass:JstlView表示JSP模板頁面需要使用JSTL標簽庫,所以classpath中必須包含jstl的相關jar包; -->
    <!-- prefix 和suffix:查找視圖頁面的前綴和后綴,最終視圖的址為: -->
    <!-- 前綴+邏輯視圖名+后綴,邏輯視圖名需要在controller中返回ModelAndView指定,比如邏輯視圖名為hello,-->
    <!-- 則最終返回的jsp視圖地址 "WEB-INF/jsp/hello.jsp" -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

重點:到這里你應該知道處理器適配器(簡單的處理器適配器、處理器適配器執行處理器,處理器應該具備那些要求才能被執行,視圖解析器、以及ModelAndView對象)
第六節
疑問?前端控制器要怎么才能根據URL找到處理器呢?
本節知識點:處理器映射器
前端控制器會去調用處理器映射器找到處理器。
現在來介紹一下處理器映射器:
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping:
表示將定義的Bean名字作為請求的url,需要將編寫的controller在spring容器中進行配置, 且指定bean的name為請求的url,且必須以.action結尾(web.xml配置)。

<!-- 配置BeanNameUrl處理器映射器 -->
    <!-- BeanNameUrlHandlerMapping:表示將定義的Bean名字作為請求的url,需要將編寫的controller在spring容器中進行配置, -->
    <!-- 且指定bean的name為請求的url,且必須以.action結尾。 -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<!-- controller配置 -->
    <!-- name="/items1.action":前邊配置的處理器映射器為BeanNameUrlHandlerMapping, -->
    <!-- 如果請求的URL 為“上下文/items1.action”將會成功映射到ItemList1控制器。 -->
    <bean name="/items1.action" id="itemList1" class="hanson.springmvc.web.controller.ItemsController1"/>   

結束語:這一章要求對上一章理解比較透徹。
有疑問的歡迎留言。


本文為慕課網作者原創,轉載請標明【原文作者及本文鏈接地址】。侵權必究,謝謝合作!

點擊查看更多內容
59人點贊

若覺得本文不錯,就分享一下吧!

評論

相關文章推薦

正在加載中
意見反饋 幫助中心 APP下載
官方微信

舉報

0/150
提交
取消
lpl竞猜