1. 程式人生 > >可單例開發、典型的教科書式的mvc構架----springmvc----day01

可單例開發、典型的教科書式的mvc構架----springmvc----day01

springmvc-day01
    springmvc的基礎知識

    1.springmvc框架
        1.1什麼是springmvc
            springmvc是spring框架的一個模組,springmvc和spring無需通過中間整合層進行整合。
            springmvc是一個基於mvc的web框架。

        1.2mvc在B/S系統下的應用
            mvc是一個設計模式,mvc在B/S系統下的應用:

        1.3springmvc框架
            第一步:發起請求到前端控制器(DispatcherServlet)
            
            第二步:前端控制器請求HandlerMapping查詢Handler
                可以根據xml配置、註解進行查詢
            
            第三步:處理器對映器HandlerMapping向前端控制器返回Handler

            第四步:前端控制器呼叫處理器介面卡去執行Handler

            第五步:處理器介面卡去執行Handler

            第六步:Handler執行完成給介面卡返回ModelAndView

            第七步:處理器介面卡向前端控制器返回ModelAndView
                ModelAndView是springmvc框架的一個底層物件,包括Model和view

            第八步:前端控制器請求檢視解析器去進行檢視解析
                根據邏輯檢視名解析成真正的檢視(jsp)

            第九步:檢視解析器向前端控制器返回view

            第十步:前端控制器進行檢視渲染
                檢視渲染將模型資料(在ModelAndView物件中)填充到request域。

            第十一步:前端控制器向用戶響應結果。

            元件:
                1.前端控制器DispatcherServlet(不需要程式設計師開發)
                作用接收請求,響應結果,相當於轉發器,中央處理器。
                有了DispatcherServlet減少了其他元件之間的耦合度。

                2.處理器對映器HandlerMapping(不需要程式設計師開發)
                作用:根據請求的url查詢Handler

                3.處理器介面卡HandlerAdapter 
                作用:按照特定規則(HandlerAdapter要求的規則)去執行Handler

                4.處理器Handler(需要程式設計師開發)
                注意:編寫Handler時按照HandlerAdapter的要求去做,這樣介面卡才可以去正確執行Handler

                5.檢視解析器View resolver(不需要程式設計師開發)
                作用:進行檢視解析,根據邏輯檢視名解析成真正的檢視(view)

                6.檢視View(需要程式設計師開發jsp)
                View是一個介面,實現類支援不同的View型別(jsp、freemarker、pdf...)

    2.入門程式
        2.1需求
            以案例作為驅動
            springmvc和mybatis使用一個案例(商品訂單管理)。
            功能需求:商品列表查詢

        2.2環境準備
            資料庫環境:mysql
            java環境:
                jdk
                eclipse indigo

            springmvc版本:spring3.2

            需要spring3.2所有jar(一定要包括spring-webmvc-x.x.x.RELEASE.jar)

        2.3配置前端控制器
            在web.xml中配置前端控制器。
            <!-- springmvc前端控制器 -->
            <servlet>
                <servlet-name>springmvc</servlet-name>
                <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                
                <!-- contextConfigLocation配置springmvc載入的配置檔案(配置處理器、對映器、介面卡等等)
                    如果不配置contextConfigLocation,預設載入的是/WEB-INF/servlet名稱-servlet.xml(springmvc-servlet.xml)
                 -->
                <init-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>classpath:springmvc.xml</param-value>
                </init-param>
            </servlet>
            
            <servlet-mapping>
                <servlet-name>springmvc</servlet-name>
                <!-- 
                    第一種:*.action,訪問以.action結尾由DispatcherServlet進行解析
                    第二種:/,所有訪問的地址都由DispatcherServlet進行解析,對於靜態檔案的解析需要配置不讓DispatcherServlet解析
                        使用此種方法可以實現RESTful風格的url
                    第三種:/*,這樣配置不對,使用這種配置,最終需要發到一個jsp頁面時,
                        仍然會有DispatcherServlet解析jsp地址值,不能提供jsp頁面找到handler,會報錯
                -->
                <url-pattern>*.action</url-pattern>
            </servlet-mapping>

        2.4配置處理器介面卡
            在classpath下的springmvc.xml中配置處理器介面卡
            <!-- 處理器介面卡 -->
            <!-- 所有處理器介面卡都實現HandlerAdapter介面 -->
            <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

            通過檢視原始碼:
                public class SimpleControllerHandlerAdapter implements HandlerAdapter {

                    @Override
                    public boolean supports(Object handler) {
                        return (handler instanceof Controller);
                    }

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

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

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

                }

            此介面卡能執行實現Controller介面的Handler
                public interface Controller {

                    /**
                     * Process the request and return a ModelAndView object which the DispatcherServlet
                     * will render. A {@code null} return value is not an error: it indicates that
                     * this object completed request processing itself and that there is therefore no
                     * ModelAndView to render.
                     * @param request current HTTP request
                     * @param response current HTTP response
                     * @return a ModelAndView to render, or {@code null} if handled directly
                     * @throws Exception in case of errors
                     */
                    ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;

                }

        2.5開發Handler
            需要實現controller介面,才能由org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter介面卡執行。
            public class ItemsController1 implements Controller {

                @Override
                public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
                    // 呼叫service查詢資料庫,查詢商品列表,這裡使用靜態資料模擬
                    List<Items> itemsList = new ArrayList<Items>();

                    // 向list中填充靜態資料
                    Items items_1 = new Items();
                    items_1.setName("聯想筆記本");
                    items_1.setPrice(6000f);
                    items_1.setDetail("ThinkPad T430 聯想膝上型電腦!");

                    Items items_2 = new Items();
                    items_2.setName("蘋果手機");
                    items_2.setPrice(5000f);
                    items_2.setDetail("iphone6蘋果手機!");

                    itemsList.add(items_1);
                    itemsList.add(items_2);

                    // 返回ModelAndView
                    ModelAndView modelAndView = new ModelAndView();
                    // 相當於resquest的setAttribute,在jsp頁面中通過itemsList取資料
                    modelAndView.addObject("itemsList", itemsList);
                    
                    //指定檢視
                    modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
                    

                    return modelAndView;
                }

            }

        2.6檢視編寫

        2.7配置Handler
            將編寫Handler在spring容器中載入。
                <!-- 配置Handler -->
                <bean id="itemsController1" name="/queryItems.action" class="com.changemax.ssm.controller.ItemsController1"></bean>

        2.8配置處理器對映器
            在classpath下的springmvc.xml中配置處理器對映器

                <!-- 處理器對映器 -->
                <!-- 將bean的name作為url進行查詢,需要在配置Handler時指定beanname(就是url) beanname的所有對映器都實現了HTTPResultHandler -->
                <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

        2.9配置檢視解析器
            需要配置解析器jsp的檢視解析器
                <!-- 檢視解析器 -->
                <!-- 解析jsp檢視,預設使用jstl標籤,classpath下得有jstl的jar包 -->
                <bean
                    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <!-- 配置jsp路徑的字首 -->
                    <property name="prefix" value="/WEB-INF/jsp/" />
                    <!-- 配置jsp路徑的字尾 -->
                    <property name="suffix" value=".jsp" />
                </bean>

        2.10部署除錯
            訪問地址:http://localhost:8080/springmvc-day01/queryItems.action

    3.非註解的處理器對映器的介面卡
        3.1非註解的處理器對映器
            處理器對映器:
                org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping

            另一個對映器:
                org.springframework.web.servlet.handler.SimpleUrlHandlerMapping


            <!-- 處理器對映器 -->
            <!-- 將bean的name作為url進行查詢,需要在配置Handler時指定beanname(就是url) beanname的所有對映器都實現了HTTPResultHandler -->
            <bean
                class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />


            <!-- 簡單url對映 -->
            <bean
                class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
                <property name="mappings">
                    <props>
                        對Itesmcontroller進行url地址對映,url就是queryItems.action
                        <prop key="/queryItems1.action">itemsController1</prop>
                        <prop key="/queryItems2.action">itemsController1</prop>
                        <prop key="/queryItems3.action">itemsController2</prop>
                    </props>
                </property>
            </bean>

            多個對映器可以並存,前端控制器判斷url能讓哪些對映器對映,就讓正確的對映器處理。

        3.2非註解的處理器介面卡
            org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
            要求編寫的Handler實現Controller介面。
                public class ItemsController1 implements Controller {

                    @Override
                    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
                        // 呼叫service查詢資料庫,查詢商品列表,這裡使用靜態資料模擬
                        List<Items> itemsList = new ArrayList<Items>();


            org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
            要求編寫的Handler實現HttpRequestHandler介面
                public class ItemsController2 implements HttpRequestHandler {

                    @Override
                    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
                            throws ServletException, IOException {
                        // 呼叫service查詢資料庫,查詢商品列表,這裡使用靜態資料模擬
                        List<Items> itemsList = new ArrayList<Items>();

            
            <!-- 處理器介面卡 -->
            <!-- 所有處理器介面卡都實現HandlerAdapter介面 -->
            <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

            <!-- 另一個非註解的介面卡 -->
            <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />

    4.DispatcherServlet.properties
        前端控制器從上邊的檔案中載入處理器對映器、介面卡、檢視解析器等元件,如果不在springmvc.xml中配置,使用預設載入的配置。


    5.註解的處理器對映器和介面卡
        對映器:
            在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping(過時)
            在spring3.1之後使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

        介面卡:
            在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter(過時)
            在spring3.1之後使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter


        5.1配置註解對映器和介面卡
            <!-- 註解的對映器 -->
            <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

            <!-- 註解的介面卡 -->
            <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
        
        
            <!-- mvc:annotation-driven代替上邊註解對映器和註解介面卡的配置 
                mvc:annotation-driven預設載入很多的引數繫結方法,比如json轉換解析器就預設載入了,
                如果使用mvc:annotation-driven不用配置上邊的RequestMappingHandlerMapping和RequsetMappingHandleAdaper
                實際開發中使用:mvc:annotation-driven
            -->

        5.2開發註解Handler
            使用註解的對映器和註解的介面卡。(註解的對映器和註解的介面卡必須配對使用)
                //使用@Controller註解標識這個是個控制器
                @Controller
                public class ItemsController3 {
                    // 商品查詢列表
                    //@RequestMapping實現了對方法和url進行對映,一個方法對應一個url
                    //一般建議url和方法名一樣,便於維護
                    @RequestMapping("/queryItems")
                    public ModelAndView queryItems() throws Exception {
                        // 呼叫service查詢資料庫,查詢商品列表,這裡使用靜態資料模擬
                        List<Items> itemsList = new ArrayList<Items>();

                        // 向list中填充靜態資料
                        Items items_1 = new Items();
                        items_1.setName("聯想筆記本");
                        items_1.setPrice(6000f);
                        items_1.setDetail("ThinkPad T430 聯想膝上型電腦!");

                        Items items_2 = new Items();
                        items_2.setName("蘋果手機");
                        items_2.setPrice(5000f);
                        items_2.setDetail("iphone6蘋果手機!");

                        itemsList.add(items_1);
                        itemsList.add(items_2);

                        ModelAndView modelAndView = new ModelAndView();

                        // 相當於resquest的setAttribute,在jsp頁面中通過itemsList取資料
                        modelAndView.addObject("itemsList", itemsList);

                        // 指定檢視
                        //通過springmvc配置檔案,可以省掉jsp路徑的字首和字尾
                        modelAndView.setViewName("items/itemsList");
                        
                        return modelAndView;
                    }
                    
                }

        5.3在spring容器中載入Handler
            <!-- 對於註解的handler配置可以單個配置
                在實際開發中,建議使用元件掃描
             -->
            <bean id="itemsController3"
                class="com.changemax.ssm.controller.ItemsController3"></bean>
                <!-- 可以使用掃描controller、service、...
                    這裡讓掃描controller,指定controller的包路徑
                -->
                <context:component-scan base-package="com.changemax.ssm.controller"></context:component-scan>

        5.4部署除錯
            訪問:http://localhost:8080/springmvc-day01/queryItems.action


    6原始碼分析(瞭解)
        通過前端控制器原始碼分析springmvc的執行過程。
        第一步:前端控制器接收請求
            呼叫doDiapatch

        第二步:前端控制器呼叫處理器對映器查詢Handler

        第三步:呼叫處理器介面卡執行Handler,得到執行結果ModelAndView

        第四步:檢視渲染,將model資料填充到request域。
            檢視解析,得到view。
            呼叫view的渲染方法,將model資料填充到request域

    7.入門程式小結
        通過入門程式理解springmvc前端控制器、處理器對映器、處理器介面卡、檢視解析器用法。
            前端控制器配置:
                第一種:*.action,訪問以.action結尾    由DispatcherServlet進行解析

                第二種:/,所以訪問的地址都由DispatcherServlet進行解析,對於靜態檔案的解析需要配置不讓DispatcherServlet進行解析
                    使用此種方式可以實現RESTful風格的url

            處理器對映器:
                非註解處理器對映器(瞭解)
                註解的處理器對映器(掌握)
                    對標記@Controller類中標識有@RequestMapping的方法進行對映。在@RequestMapping裡邊定義對映的url。
                    使用註解的對映器不用再xml中配置url和Handler的對映關係。

            處理器介面卡:
                非註解的處理器介面卡(瞭解)
                註解的處理器介面卡(掌握)
                    註解處理器介面卡的註解的處理器對映器是配對使用。理解為不能使用非註解對映器進行對映。

                    <mvc:annotation-driven></mvc:annotation-driven>可以替代下邊的配置:
                        <!--註解對映器 -->
                        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
                        <!--註解介面卡 -->
                        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

                    實際開發使用:mvc:annotation-driven

            檢視解析器配置字首和字尾:
                <!-- 檢視解析器 -->
                <!-- 解析jsp檢視,預設使用jstl標籤,classpath下得有jstl的jar包 -->
                <bean
                    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <!-- 配置jsp路徑的字首 -->
                    <property name="prefix" value="/WEB-INF/jsp/" />
                    <!-- 配置jsp路徑的字尾 -->
                    <property name="suffix" value=".jsp" />
                </bean>

                如此配置之後,就可以在程式中不用指定字首和字尾


    8.springmvc和mybatis整合
        
        8.1需求
            使用springmvc和mybatis完成商品列表查詢。

        8.2整合思路
            spring將各層進行整合
            通過spring管理持久層的mapper(相當於dao介面)
            通過spring管理業務層service,service中可以呼叫mapper介面。
            spring進行事物控制。

            通過spirng管理表現層Handler,Handler中可以呼叫service介面。

            mapper、service、Handler都是javabean。

            第一步:整合dao層:
                mybatis和spring整合,通過spring管理mapper介面。
                使用mapper的掃描器自動掃描mapper介面在spring中進行註冊。

            第二步:整合service層
                通過spring管理service介面。
                使用配置方式將service介面配置在spring配置檔案中。
                實現事務控制。

            第三步:整合springmvc
                由於springmvc是spring的模組,不需要整合。

        8.3準備環境
            資料庫環境:mysql
            Java環境:
                jdk1.8
                eclipse indigo
                springmvc4.3

            所需要jar包;
                資料庫驅動包:mysql
                mybatis的jar包
                mybatis和spring的整合包
                log4j包
                dbcp資料庫連線池包
                spring3.2所有jar包
                jstl包


        8.4整合dao
            mybatis和spring進行整合

            8.4.1sqlMapConfig.xml
                mybatis自己的配置檔案:
                    <?xml version="1.0" encoding="UTF-8" ?>
                    <!DOCTYPE configuration
                    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
                    "http://mybatis.org/dtd/mybatis-3-config.dtd">
                    <configuration>
                        <!-- 全域性的setting配置,根據需要新增 -->

                        <!-- 別名定義 -->
                        <typeAliases>
                            <package name="com.changemax.ssm.po" />
                        </typeAliases>


                        <!-- 載入 對映檔案 由於使用spring和mybatis的整合包進行mapper掃描,這裡不需要配置了 -->
                        <mappers>
                            <!-- <mapper resource="sqlmap/User.xml" /> -->
                            <!-- 批量載入mapper 指定mapper介面的包名,mybatis自動掃描包下邊所有mapper介面進行載入 遵循一些規範: 需要將mapper介面類名和mapper.xml對映檔名稱保持一致,且在一個目錄 
                                中 上邊規範的前提是:使用的是mapper代理方法 和spring整合後,使用mapper掃描器,這裡不需要配置了 -->
                            <!-- <package name="com.changemax.ssm.mapper" /> -->
                        </mappers>
                    </configuration>

            8.4.2applicationContext-jdbc.xml
                配置:
                    資料來源
                    SqlSessionFactory
                    mapper掃描器

                    <?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.2.xsd 
                            http://www.springframework.org/schema/mvc 
                            http://www.springframework.org/schema/mvc/spring-mvc-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 
                            http://www.springframework.org/schema/tx 
                            http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">

                        <!-- 和jdbc配置相關的 -->

                        <!-- 載入db.properties檔案中的內容,db.properties檔案中的key命名要具有一定的特殊規則 -->
                        <context:property-placeholder
                            location="classpath:db.properties" />

                        <!-- 配置資料來源,c3p0連線池 -->
                        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
                            destroy-method="close">
                            <property name="driverClassName" value="${jdbc.driver}" />
                            <property name="url" value="${jdbc.url}" />
                            <property name="username" value="${jdbc.username}" />
                            <property name="password" value="${jdbc.password}" />
                            <property name="maxActive" value="30" />
                            <property name="maxIdle" value="5" />
                        </bean>

                        <!-- 配置sqlSessionFactory -->
                        <bean id="sqlSessionFactory"
                            class="org.mybatis.spring.SqlSessionFactoryBean">
                            <!-- 資料庫連線池 -->
                            <property name="dataSource" ref="dataSource" />
                            <!-- 載入mybatis的全域性配置檔案 -->
                            <property name="configLocation"
                                value="classpath:mybatis/sqlMapConfig.xml" />
                        </bean>

                        <!-- mapper掃描器 -->
                        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                            <!-- 掃描包路徑,如果需要掃描多個包,中間使用半形逗號隔開 -->
                            <property name="basePackage" value="com.changemax.ssm.mapper"></property>
                            <property name="sqlSessionFactoryBeanName"
                                value="sqlSessionFactory" />
                        </bean>

                    </beans>

            8.4.3applicationContext-transaction.xml
                
            

            8.4.4逆向工程生成po類及mapper(單表增刪改查)
                將生成的檔案拷貝至工程中。

            8.4.5手動定義商品查詢mapper
                針對綜合查詢mapper,一般情況會有關聯查詢,建議自定義mapper

                8.4.5.1ItemsMapperCustom.xml
                    <?xml version="1.0" encoding="UTF-8" ?>
                    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
                    <mapper namespace="com.changemax.ssm.mapper.ItemsMapperCustom" >

                       <!-- 定義商品查詢的sql片段,就是商品查詢條件 -->
                       <sql id="query_items_where">
                           <!-- 使用動態sql,通過if判斷,滿足條件進行sql拼接 -->
                           <!-- 商品查詢條件通過ItemsQueryVo包裝物件 中itemsCustom屬性傳遞 -->
                               <if test="itemsCustom!=null">
                                   <if test="itemsCustom.name!=null and itemsCustom.name!=''">
                                       items.name LIKE '%${itemsCustom.name}%'
                                   </if>
                               </if>
                        
                       </sql>
                          
                          <!-- 商品列表查詢 -->
                          <!-- parameterType傳入包裝物件(包裝了查詢條件)
                              resultType建議使用擴充套件物件
                           -->
                          <select id="findItemsList" parameterType="com.changemax.ssm.po.ItemsQueryVo"
                               resultType="com.changemax.ssm.po.ItemsCustom">
                              SELECT items.* FROM items  
                              <where>
                                  <include refid="query_items_where"></include>
                              </where>
                          </select>
                          
                    </mapper>

                8.4.5.2ItemsMapperCustom.java
                    package com.changemax.ssm.mapper;

                    import java.util.List;

                    import com.changemax.ssm.po.ItemsCustom;
                    import com.changemax.ssm.po.ItemsQueryVo;

                    public interface ItemsMapperCustom {
                        //商品查詢列表
                        public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo)throws Exception;
                    }


        8.5整合service
            讓spring關聯service介面。

            8.5.1定義service介面
                public interface ItemsService {
                    /**
                     * 商品查詢列表
                     * <p>
   &n