springMVC3

複習:html

 

springmvc框架:前端

         DispatcherServlet前端控制器:接收request,進行responsejava

         HandlerMapping處理器映射器:根據url查找Handler。(能夠經過xml配置方式,註解方式)jquery

         HandlerAdapter處理器適配器:根據特定規則去執行Handler,編寫Handler時須要按照HandlerAdapter的要求去編寫。程序員

         Handler處理器(後端控制器):須要程序員去編寫,經常使用註解開發方式。web

                   Handler處理器執行後結果 是ModelAndView,具體開發時Handler返回方法值類型包括 :ModelAndView、String(邏輯視圖名)、void(經過在Handler形參中添加request和response,相似原始 servlet開發方式,注意:能夠經過指定response響應的結果類型實現json數據輸出)ajax

         View resolver視圖解析器:根據邏輯視圖名生成真正的視圖(在springmvc中使用View對象表示)spring

         View視圖:jsp頁面,僅是數據展現,沒有業務邏輯。json

 

註解開發:後端

         使用註解方式的處理器映射器和適配器:

         <!--註解映射器 -->

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

<!--註解適配器 -->

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

 

在實際開發,使用<mvc:annotation-driven>代替上邊處理器映射器和適配器配置。

 

@controller註解必需要加,做用標識類是一個Handler處理器。

@requestMapping註解必需要加,做用:

         一、對url和Handler的方法進行映射。

         二、能夠窄化請求映射,設置Handler的根路徑,url就是根路徑+子路徑請求方式

         三、能夠限制http請求的方法

映射成功後,springmvc框架生成一個Handler對象,對象中只包括 一個映射成功的method。

 

註解開發中參數綁定:

         將request請求過來的key/value的數據(理解一個串),經過轉換(參數綁定的一部分),將key/value串轉成形參,將轉換後的結果傳給形參(整個參數綁定過程)。

         springmvc所支持參數綁定:

                   一、默認支持不少類型,HttpServletRequest、response、session、

                            model/modelMap(將模型數據填充到request域)

                   二、支持簡單數據類型,整型、字符串、日期。。

                            只要保證request請求的參數名和形參名稱一致,自動綁定成功

                            若是request請求的參數名和形參名稱不一致,可使用@RequestParam(指定request請求的參數名),@RequestParam加在形參的前邊。

                   三、支持pojo類型

                            只要保證request請求的參數名稱和pojo中的屬性名一致,自動將request請求的參數設置到pojo的屬性中。

                  注意:形參中即有pojo類型又有簡單類型,參數綁定互不影響。

                   自定義參數綁定:

                            日期類型綁定自定義:

                                     定義的Converter<源類型,目標類型>接口實現類,好比:

                                     Converter<String,Date>表示:將請求的日期數據串轉成java中的日期類型。

                                     注意:要轉換的目標類型必定和接收的pojo中的屬性類型一致。

                                     將定義的Converter實現類注入處處理器適配器中。

<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<!-- conversionService -->
    <bean id="conversionService"
        class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!-- 轉換器 -->
        <property name="converters">
            <list>
                <bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
            </list>
        </property>
    </bean>

 

springmvc和struts2區別:

springmvc面向方法開發的(更接近service接口的開發方式),struts2面向類開發。

springmvc能夠單例開發,struts2只能是多例開發。

 

1       包裝類型pojo參數綁定

 

1.1      需求

         商品查詢controller方法中實現商品查詢條件傳入。

 

1.2      實現方法

第一種方法:在形參中 添加HttpServletRequest request參數,經過request接收查詢條件參數。

第二種方法:在形參中讓包裝類型的pojo接收查詢條件參數。

         分析:

         頁面傳參數的特色:複雜,多樣性。條件包括 :用戶帳號、商品編號、訂單信息。。。

         若是將用戶帳號、商品編號、訂單信息等放在簡單pojo(屬性是簡單類型)中,pojo類屬性比較多,比較亂。

         建議使用包裝類型的pojo,pojo中屬性是pojo。

        

1.3      頁面參數和controller方法形參定義

 

頁面參數:

 

         商品名稱:<input name="itemsCustom.name" />

         注意:itemsCustom和包裝pojo中的屬性一致便可。

 

controller方法形參:

   

      public ModelAndView queryItems(HttpServletRequest request,ItemsQueryVo itemsQueryVo) throws Exception

 

2       集合類型綁定

 

2.1      數組綁定

 

2.1.1     需求

商品批量刪除,用戶在頁面選擇多個商品,批量刪除。

 

2.1.2     表現層實現

關鍵:將頁面選擇(多選)的商品id,傳到controller方法的形參,方法形參使用數組接收頁面請求的多個商品id。

 

controller方法定義:

 

 

 

3.1      list綁定

3.1.1     需求

一般在須要批量提交數據時,將提交的數據綁定到list<pojo>中,好比:成績錄入(錄入多門課成績,批量提交),

本例子需求:批量商品修改,在頁面輸入多個商品信息,將多個商品信息提交到controller方法中。

 

3.1.2     表現層實現

controller方法定義:

         一、進入批量商品修改頁面(頁面樣式參考商品列表實現)

         二、批量修改商品提交

         使用List接收頁面提交的批量數據,經過包裝pojo接收,在包裝pojo中定義list<pojo>屬性

 

 

頁面定義:

 

3.3      map綁定

也經過在包裝pojo中定義map類型屬性。

 

在包裝類中定義Map對象,並添加get/set方法,action使用包裝對象接收。

包裝類中定義Map對象以下:

 

Public class QueryVo {
private Map<String, Object> itemInfo = new HashMap<String, Object>();
  //get/set方法..
}

 

 

頁面定義以下:

 

<tr>
<td>學生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年齡:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>

 

Contrller方法定義以下:

 

public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getStudentinfo());
}

 

 

1       springmvc校驗

 

1.1      校驗理解

 

項目中,一般使用較可能是前端的校驗,好比頁面中js校驗。對於安全要求較高點建議在服務端進行校驗。

 

服務端校驗:

         控制層conroller:校驗頁面請求的參數的合法性。在服務端控制層conroller校驗,不區分客戶端類型(瀏覽器、手機客戶端、遠程調用)

         業務層service(使用較多):主要校驗關鍵業務參數,僅限於service接口中使用的參數。

         持久層dao:通常是不校驗的。

 

1.2      springmvc校驗需求

 

springmvc使用hibernate的校驗框架validation(和hibernate沒有任何關係)。

 

校驗思路:

         頁面提交請求的參數,請求到controller方法中,使用validation進行校驗。若是校驗出錯,將錯誤信息展現到頁面。

具體需求:

         商品修改,添加校驗(校驗商品名稱長度,生產日期的非空校驗),若是校驗出錯,在商品修改頁面顯示錯誤信息。

 

1.3      環境準備

hibernate的校驗框架validation所須要jar包:

 

1.4     配置校驗器

1.5      校驗器注入處處理器適配器中

 

 

 

 

1.6      在pojo中添加校驗規則

在ItemsCustom.java中添加校驗規則:

 

1.7      CustomValidationMessages.properties

 

在CustomValidationMessages.properties配置校驗錯誤信息:

 

 

 

1.8     捕獲校驗錯誤信息

 

在須要校驗的pojo前邊添加@Validated,在須要校驗的pojo後邊添加BindingResult bindingResult接收校驗出錯信息

注意:@ValidatedBindingResult bindingResult是配對出現,而且形參順序是固定的(一前一後)。

 

1.9     在頁面顯示校驗錯誤信息

 

在controller中將錯誤信息傳到頁面便可。

 

 

 

 

1.1      分組校驗

1.1.1     需求

在pojo中定義校驗規則,而pojo是被多個 controller所共用,當不一樣的controller方法對同一個pojo進行校驗,可是每一個controller方法須要不一樣的校驗。

 

解決方法:

定義多個校驗分組(實際上是一個java接口),分組中定義有哪些規則

每一個controller方法使用不一樣的校驗分組

 

 

1.1.2     校驗分組 

 

1.1.1     在校驗規則中添加分組

 

 

1.1.1     在controller方法使用指定分組的校驗

 

 

 

1       數據回顯

1.1      什麼數據回顯

提交後,若是出現錯誤,將剛纔提交的數據回顯到剛纔的提交頁面。

 

1.2      pojo數據回顯方法

 

一、springmvc默認對pojo數據進行回顯。

pojo數據傳入controller方法後,springmvc自動將pojo數據放到request域,key等於pojo類型(首字母小寫)

 

使用@ModelAttribute指定pojo回顯到頁面在request中的key

 

二、@ModelAttribute還能夠將方法的返回值傳到頁面

 

在商品查詢列表頁面,經過商品類型查詢商品信息。

在controller中定義商品類型查詢方法,最終將商品類型傳到頁面。

 

頁面上能夠獲得itemTypes數據

 

三、使用最簡單方法使用model,能夠不用@ModelAttribute

 

1.3      簡單類型數據回顯

 

使用最簡單方法使用model。

 

model.addAttribute("id", id);

 

 

1       異常處理

1.1      異常處理思路

 

系統中異常包括兩類:預期異常和運行時異常RuntimeException,前者經過捕獲異常從而獲取異常信息,後者主要經過規範代碼開發、測試經過手段減小運行時異常的發生。

         系統的dao、service、controller出現都經過throws Exception向上拋出,最後由springmvc前端控制器交由異常處理器進行異常處理,以下圖:

 

springmvc提供全局異常處理器(一個系統只有一個異常處理器)進行統一異常處理。

 

1.2      自定義異常類

 

對不一樣的異常類型定義異常類,繼承Exception。

 

1.3      全局異常處理器

 

思路:

         系統遇到異常,在程序中手動拋出,dao拋給service、service給controller、controller拋給前端控制器,前端控制器調用全局異常處理器。

         全局異常處理器處理思路:

                  解析出異常類型

                  若是該 異常類型是系統 自定義的異常,直接取出異常信息,在錯誤頁面展現

                  若是該 異常類型不是系統 自定義的異常,構造一個自定義的異常類型(信息爲「未知錯誤」)

 

springmvc提供一個HandlerExceptionResolver接口

 

@Override
    public ModelAndView resolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex) {
        //handler就是處理器適配器要執行Handler對象(只有method)
        
//        解析出異常類型
//        若是該 異常類型是系統 自定義的異常,直接取出異常信息,在錯誤頁面展現
//        String message = null;
//        if(ex instanceof CustomException){
//            message = ((CustomException)ex).getMessage();
//        }else{
////            若是該 異常類型不是系統 自定義的異常,構造一個自定義的異常類型(信息爲「未知錯誤」)
//            message="未知錯誤";
//        }
        
        //上邊代碼變爲
        CustomException customException = null;
        if(ex instanceof CustomException){
            customException = (CustomException)ex;
        }else{
            customException = new CustomException("未知錯誤");
        }
        
        //錯誤信息
        String message = customException.getMessage();
        
        
        ModelAndView modelAndView = new ModelAndView();
        
        //將錯誤信息傳到頁面
        modelAndView.addObject("message", message);
        
        //指向錯誤頁面
        modelAndView.setViewName("error");

        
        return modelAndView;
    }

1.4      錯誤頁面

 

1.5      在springmvc.xml配置全局異常處理器

 

1.6      異常測試

 

在controller、service、dao中任意一處須要手動拋出異常。

若是是程序中手動拋出的異常,在錯誤頁面中顯示自定義的異常信息,若是不是手動拋出異常說明是一個運行時異常,在錯誤頁面只顯示「未知錯誤」。

 

在商品修改的controller方法中拋出異常 .

 

在service接口中拋出異常:

 

 

若是與業務功能相關的異常,建議在service中拋出異常。

與業務功能沒有關係的異常,建議在controller中拋出。

 

上邊的功能,建議在service中拋出異常。

 

1       上傳圖片

 

1.1      需求

在修改商品頁面,添加上傳商品圖片功能。

 

1.2      springmvc中對多部件類型解析

 

在 頁面form中提交enctype="multipart/form-data"的數據時,須要springmvc對multipart類型的數據進行解析。

 

在springmvc.xml中配置multipart類型解析器。

 

 

 

 

1.3      加入上傳圖片的jar

上邊的解析內部使用下邊的jar進行圖片上傳。

 

 

 

1.4      建立圖片虛擬 目錄 存儲圖片

經過圖形界面配置:

 

 

 

也能夠直接修改tomcat的配置:

 

在conf/server.xml文件,添加虛擬 目錄 :

 

 

 

 

注意:在圖片虛擬目錄 中,必定將圖片目錄分級建立(提升i/o性能),通常咱們採用按日期(年、月、日)進行分級建立。

 

1.5      上傳圖片代碼

1.5.1     頁面

 

 

 

 

1.5.2     controller方法

修改:商品修改controller方法:

 

 

 

1       json數據交互

 

1.1      爲何要進行json數據交互

 

json數據格式在接口調用中、html頁面中較經常使用,json格式比較簡單,解析還比較方便。

好比:webservice接口,傳輸json數據.

 

1.2      springmvc進行json交互

 

 

 

一、請求json、輸出json,要求請求的是json串,因此在前端頁面中須要將請求的內容轉成json,不太方便。

 

二、請求key/value、輸出json。此方法比較經常使用。

 

1.3      環境準備

 

1.3.1     加載json轉的jar包

springmvc中使用jackson的包進行json轉換(@requestBody和@responseBody使用下邊的包進行json轉),以下:

 

 

 

1.3.2     配置json轉換器

 

在註解適配器中加入messageConverters

 

<!--註解適配器 -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
        <list>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
        </list>
        </property>
    </bean>

注意:若是使用<mvc:annotation-driven /> 則不用定義上邊的內容。

1.4      json交互測試

 

1.4.1     輸入json串,輸出是json串

1.4.1.1              jsp頁面

使用jquery的ajax提交json串,對輸出的json結果進行解析。

 

1.4.1.2              controller

 

1.4.1.3              測試結果

 

 

1.4.2     輸入key/value,輸出是json串

 

1.4.2.1              jsp頁面

使用jquery的ajax提交key/value串,對輸出的json結果進行解析。

 

 

1.4.2.2              controller

 

 

1.4.2.3              測試

 

 

 

1       RESTful支持

 

1.1      什麼是RESTful

RESTful架構,就是目前最流行的一種互聯網軟件架構。它結構清晰、符合標準、易於理解、擴展方便,因此正獲得愈來愈多網站的採用。

 

RESTful(即Representational State Transfer的縮寫)實際上是一個開發理念,是對http的很好的詮釋。

 

 

一、對url進行規範,寫RESTful格式的url

 

非REST的url:http://...../queryItems.action?id=001&type=T01

REST的url風格:http://..../items/001

         特色:url簡潔,將參數經過url傳到服務端

二、http的方法規範

不論是刪除、添加、更新。。使用url是一致的,若是進行刪除,須要設置http的方法爲delete,同理添加。。。

 

後臺controller方法:判斷http方法,若是是delete執行刪除,若是是post執行添加。

 

三、對http的contentType規範

請求時指定contentType,要json數據,設置成json格式的type。。

 

1.2      REST的例子

1.2.1     需求

查詢商品信息,返回json數據。

 

1.2.2     controller

定義方法,進行url映射使用REST風格的url,將查詢商品信息的id傳入controller .

 

輸出json使用@ResponseBody將java對象輸出json。

 

@RequestMapping(value="/ itemsView/{id}"):{×××}佔位符,請求的URL能夠是「/viewItems/1」或「/viewItems/2」,經過在方法中使用@PathVariable獲取{×××}中的×××變量。

@PathVariable用於將請求URL中的模板變量映射到功能處理方法的參數上。

若是RequestMapping中表示爲"/ itemsView /{id}",id和形參名稱一致,@PathVariable不用指定名稱。

 

1.2.3     REST方法的前端控制器配置

 

在web.xml配置:

 

 

 

1.3      對靜態資源的解析

 

配置前端控制器的url-parttern中指定/,對靜態資源的解析出現問題:

 

 

 

在springmvc.xml中添加靜態資源解析方法。

 

 

1       攔截器

1.1      攔截定義

 

定義攔截器,實現HandlerInterceptor接口。接口中提供三個方法。

 

public class HandlerInterceptor1 implements HandlerInterceptor {

    
    //進入 Handler方法以前執行
    //用於身份認證、身份受權
    //好比身份認證,若是認證經過表示當前用戶沒有登錄,須要此方法攔截再也不向下執行
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        
        //return false表示攔截,不向下執行
        //return true表示放行
        return false;
    }

    //進入Handler方法以後,返回modelAndView以前執行
    //應用場景從modelAndView出發:將公用的模型數據(好比菜單導航)在這裏傳到視圖,也能夠在這裏統一指定視圖
    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        
        
    }

    //執行Handler完成執行此方法
    //應用場景:統一異常處理,統一日誌處理
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        
        
    }

}

 

1.2      攔截器配置

 

 

1.2.1     針對HandlerMapping配置

springmvc攔截器針對HandlerMapping進行攔截設置,若是在某個HandlerMapping中配置攔截,通過該 HandlerMapping映射成功的handler最終使用該 攔截器。

<bean
    class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
    <property name="interceptors">
        <list>
            <ref bean="handlerInterceptor1"/>
            <ref bean="handlerInterceptor2"/>
        </list>
    </property>
</bean>
    <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
    <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>

 

通常不推薦使用。

 

1.2.2     相似全局的攔截器

springmvc配置相似全局的攔截器,springmvc框架將配置的相似全局的攔截器注入到每一個HandlerMapping中。

 

 

1.3      攔截測試

1.3.1     測試需求

測試多個攔截器各各方法執行時機。

 

 

1.3.2     編寫兩個攔截

 

1.3.3     兩個攔截器都放行

HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle

HandlerInterceptor2...postHandle
HandlerInterceptor1...postHandle

HandlerInterceptor2...afterCompletion
HandlerInterceptor1...afterCompletion

 

 

總結:

preHandle方法按順序執行,

postHandleafterCompletion按攔截器配置的逆向順序執行。

 

1.3.4     攔截器1放行,攔截器2不放行

HandlerInterceptor1...preHandle

HandlerInterceptor2...preHandle

HandlerInterceptor1...afterCompletion

 

 

總結:

攔截器1放行,攔截器2 preHandle纔會執行。

攔截器2 preHandle不放行,攔截器2 postHandle和afterCompletion不會執行。

只要有一個攔截器不放行,postHandle不會執行。

 

1.3.1      攔截器1不放行,攔截器2不放行

HandlerInterceptor1...preHandle

 

攔截器1 preHandle不放行,postHandle和afterCompletion不會執行。

攔截器1 preHandle不放行,攔截器2不執行。

 

 

1.3.2     小結

 

根據測試結果,對攔截器應用。

 

好比:統一日誌處理攔截器,須要該 攔截器preHandle必定要放行,且將它放在攔截器連接中第一個位置。

 

好比:登錄認證攔截器,放在攔截器連接中第一個位置。權限校驗攔截器,放在登錄認證攔截器以後。(由於登錄經過後才校驗權限)

 

1.4      攔截器應用(實現登錄認證)

 

1.4.1     需求

 

一、用戶請求url

二、攔截器進行攔截校驗

         若是請求的url是公開地址(無需登錄便可訪問的url),讓放行

         若是用戶session 不存在跳轉到登錄頁面

         若是用戶session存在放行,繼續操做。

 

1.4.2     登錄controller方法

 

@Controller
public class LoginController {

    // 登錄
    @RequestMapping("/login")
    public String login(HttpSession session, String username, String password)
            throws Exception {

        // 調用service進行用戶身份驗證
        // ...

        // 在session中保存用戶身份信息
        session.setAttribute("username", username);
        // 重定向到商品列表頁面
        return "redirect:/items/queryItems.action";
    }

    // 退出
    @RequestMapping("/logout")
    public String logout(HttpSession session) throws Exception {

        // 清除session
        session.invalidate();

        // 重定向到商品列表頁面
        return "redirect:/items/queryItems.action";
    }

}

 

1.4.3     登錄認證攔截實現

 

1.4.3.1              代碼實現

 

public class LoginInterceptor implements HandlerInterceptor {

    
    //進入 Handler方法以前執行
    //用於身份認證、身份受權
    //好比身份認證,若是認證經過表示當前用戶沒有登錄,須要此方法攔截再也不向下執行
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        
        //獲取請求的url
        String url = request.getRequestURI();
        //判斷url是不是公開 地址(實際使用時將公開 地址配置配置文件中)
        //這裏公開地址是登錄提交的地址
        if(url.indexOf("login.action")>=0){
            //若是進行登錄提交,放行
            return true;
        }
        
        //判斷session
        HttpSession session  = request.getSession();
        //從session中取出用戶身份信息
        String username = (String) session.getAttribute("username");
        
        if(username != null){
            //身份存在,放行
            return true;
        }
        
        //執行這裏表示用戶身份須要認證,跳轉登錄頁面
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        
        //return false表示攔截,不向下執行
        //return true表示放行
        return false;
    }

 

1.4.3.2              攔截器配置

 

相關文章
相關標籤/搜索