SpringMVC詳解

高級參數綁定

綁定數組

    jsp中獲取list集合並遍歷

複製代碼
<c:forEach items="${itemList }" var="item">
<tr>
    <td><input name="ids" value="${item.id}" type="checkbox"></td>
    <td>${item.name }</td>
    <td>${item.price }</td>
    <td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
    <td>${item.detail }</td>
    <td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
</tr>
</c:forEach>
複製代碼

  

    controller層接收參數並操作

1 @RequestMapping("/itemEdit")
2     public void itemEdit(QueryVo queryVo, String[] ids) {
3             queryVo.getItems.setName( (queryVo.getItems().getName());
4         queryVo.getItems.setPrice( (queryVo.getItems().getPrice());
5         ...
6     }

 

 

 


 

@RequestMapping

 

通過RequestMapping註解可以定義不同的處理器映射規則。

 

窄化請求映射

@RequestMapping("/item")放在類名上邊,設置請求前綴

@RequestMapping("/queryItem ")放在方法名上邊,請求url爲 /前綴/queryItem

 

請求方法限定

 

     默認請求方式爲get請求    

 

  •   限定GET方法

@RequestMapping(method = RequestMethod.GET)

 

如果通過Post訪問則報錯:HTTP Status 405 - Request method 'POST' not supported

 

例如:

@RequestMapping(value="/editItem",method=RequestMethod.GET)

 

  •   限定POST方法

@RequestMapping(method = RequestMethod.POST)

 

如果通過Post訪問則報錯:HTTP Status 405 - Request method 'GET' not supported

 

  •   GET和POST都可以

@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})

 

 


 

controller層方法返回值

 

  • 返回ModelAndView

 

    controller方法中定義ModelAndView對象並返回,對象中可添加model數據、指定view頁面。

 

  • 返回void

 

在controller方法形參上可以定義request和response,使用request或response指定響應結果:

1、使用request轉向頁面,如下:

request.getRequestDispatcher("頁面路徑").forward(request, response);

 

2、也可以通過response頁面重定向:

response.sendRedirect("url")

 

3、也可以通過response指定響應結果,例如響應json數據如下:

response.setCharacterEncoding("utf-8");

response.setContentType("application/json;charset=utf-8");

response.getWriter().write("json串");

 

  • 返回字符串

    邏輯視圖名 

      controller方法返回字符串可以指定邏輯視圖名,通過視圖解析器解析爲物理視圖地址。

//指定邏輯視圖名,經過視圖解析器解析爲jsp物理路徑:/WEB-INF/jsp/item/editItem.jsp
return "item/editItem";

 

    Redirect重定向

      Contrller方法返回結果重定向到一個url地址,如下商品修改提交後重定向到商品查詢方法,參數無法帶到商品查詢方法中。

//重定向到queryItem.action地址,request無法帶過去
return "redirect:queryItem.action";

 

redirect方式相當於“response.sendRedirect()”,轉發後瀏覽器的地址欄變爲轉發後的地址,因爲轉發即執行了一個新的request和response。

由於新發起一個request原來的參數在轉發時就不能傳遞到下一個url,如果要傳參數可以/item/queryItem.action後邊加參數,如下:

/item/queryItem?...&…..

 

 

    forward轉發

      controller方法執行後繼續執行另一個controller方法,如下商品修改提交後轉向到商品修改頁面,修改商品的id參數可以帶到商品修改方法中。

//結果轉發到editItem.action,request可以帶過去
return "forward:editItem.action";

 

forward方式相當於“request.getRequestDispatcher().forward(request,response)”,轉發後瀏覽器地址欄還是原來的地址。轉發並沒有執行新的request和response,而是和轉發前的請求共用一個request和response。所以轉發前請求的參數在轉發後仍然可以讀取到。

 

 

請求重定向與請求轉發的區別:

請求轉發forward:瀏覽器URL地址不會發生變化,在服務器端做了一個跳轉,同一個request域中

請求重定向redirect:瀏覽器地址會發生變化,服務器端向瀏覽器響應302狀態碼,瀏覽器收到302之後,重新請求服務器一個新的地址,不同的request域了

 


 

異常處理器

 

 

  異常處理思路

 

 

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

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

 

 

 

  •   自定義異常類

    爲了區別不同的異常通常根據異常類型自定義異常類,有時需要創建一個自定義系統異常,如果controller、service、dao拋出此類異常說明是系統預期處理的異常信息。

複製代碼
 1 public class CustomException extends Exception {
 2     /** serialVersionUID*/
 3     private static final long serialVersionUID = -5212079010855161498L;
 4     
 5     public CustomException(String message){
 6         super(message);
 7         this.message = message;
 8     }
 9 
10     //異常信息
11     private String message;
12 
13     public String getMessage() {
14         return message;
15     }
16 
17     public void setMessage(String message) {
18         this.message = message;
19     }
20 }
複製代碼

 

  •   自定義異常處理器實現HandlerExceptionResolver

 

複製代碼
 1 public class CustomExceptionResolver implements HandlerExceptionResolver {
 2     @Override
 3     public ModelAndView resolveException(HttpServletRequest request,
 4             HttpServletResponse response, Object handler, Exception ex) {
 5         String msg = null;
 6         if(ex instanceof CustomerException){
 7             CustomerException exception = (CustomerException) ex;
 8             msg = exception.getMessage();
 9         }else{
10             StringWriter s = new StringWriter();
11             PrintWriter printWriter = new PrintWriter(s);
12             ex.printStackTrace(printWriter);
13             msg = s.toString();
14         }
15         ModelAndView view = new ModelAndView();
16         view.setViewName("error");
17         view.addObject("message", msg);
18         return modelAndView;
19     }
20 }
複製代碼

 

  •   錯誤頁面

複製代碼
<%@ 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>
您的操作出現錯誤如下:<br/>
${message}
</body>
</html>
複製代碼

 

  •   異常處理器配置

    在springmvc.xml中添加:

   <!-- 異常處理器 -->
    <bean id="handlerExceptionResolver" class="cn.itcast.ssm.controller.exceptionResolver.CustomExceptionResolver"/>

 

  •   異常測試

    需求:修改商品信息,id輸入錯誤提示商品信息不存在。

 

    實現:修改controller方法“editItem”,調用service查詢商品信息,如果商品信息爲空則拋出異常:

1        // 調用service查詢商品信息
2         Items item = itemService.findItemById(id);
3         if(item == null){
4             throw new CustomException("商品信息不存在!");
5         }

 

 

 


 

上傳圖片

  配置tomcat代理目錄

在tomcat上配置圖片虛擬目錄,在tomcat下conf/server.xml中添加:

<Context docBase="F:\develop\upload\temp" path="/pic" reloadable="false"/>

 

訪問http://localhost:8080/pic即可訪問F:\develop\upload\temp下的圖片。

  也可以通過eclipse配置:

 

  •   依賴的jar包

複製代碼
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
複製代碼

 

  •   配置解析器

複製代碼
    <!-- 文件上傳 -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 設置上傳文件的最大尺寸爲5MB -->
        <property name="maxUploadSize" value="5242880"></property>    
   </bean>
    
複製代碼

 

  •   圖片上傳

    

    controller:

複製代碼
 1    //商品修改提交
 2     @RequestMapping("/imgSubmit")
 3     public String imgSubmit(MultipartFile pictureFile)throws Exception{        
 4         //原始文件名稱
 5         String pictureFile_name =  pictureFile.getOriginalFilename();
 6         //新文件名稱
 7         String newFileName = UUID.randomUUID().toString()+pictureFile_name.substring(pictureFile_name.lastIndexOf("."));
 8         
 9         //上傳圖片
10         File uploadPic = new java.io.File("F:/develop/upload/temp/"+newFileName);
11         
12         if(!uploadPic.exists()){
13             uploadPic.mkdirs();
14         }
15         //向磁盤寫文件
16         pictureFile.transferTo(uploadPic);
17 
18 .....
複製代碼

 

    頁面:

複製代碼
<!-- form添加enctype="multipart/form-data":-->
<form id="imgForm"
action="${pageContext.request.contextPath }/imgSubmit.action"
        method="post" enctype="multipart/form-data">
        <input type="hidden" name="pic" value="${item.pic }" />


<!-- file的name與controller形參一致:-->
<tr>
    <td>商品圖片</td>
    <td><c:if test="${item.pic !=null}">
            <img src="/pic/${item.pic}" width=100 height=100 />
            <br />
        </c:if> <input type="file" name="pictureFile" /></td>
</tr>
複製代碼

 

 


 

json數據交互

  @RequestBody

作用:

@RequestBody註解用於讀取http請求的內容(字符串),通過springmvc提供的HttpMessageConverter接口將讀到的內容轉換爲json、xml等格式的數據並綁定到controller方法的參數上。

List.action?id=1&name=zhangsan&age=12

 

 

  @ResponseBody

作用:

該註解用於將Controller的方法返回的對象,通過HttpMessageConverter接口轉換爲指定格式的數據如:json,xml等,通過Response響應給客戶端

 

  請求json,響應json實現

 

    1、依賴jar包

複製代碼
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.8.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.8.8</version>
</dependency>
複製代碼

  

   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 /> 則不用定義上邊的內容。

 

   3、controller層

 

複製代碼
1    // 商品修改提交json信息,響應json信息
2     @RequestMapping("/editItemSubmit_RequestJson")
3    @ResponseBody
4     public Items editItemSubmit_RequestJson(@RequestBody Items items) throws Exception {
5         System.out.println(items);
6         return items;
7     }
複製代碼

 

   4、頁面js方法

複製代碼
//引入 js:
<script type="text/javascript" 
src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>


    //請求json響應json
    function request_json(){
        $.ajax({
            type:"post",
            url:"${pageContext.request.contextPath }/item/editItemSubmit_RequestJson.action",
            contentType:"application/json;charset=utf-8",
            data:'{"name":"測試商品","price":99.9}',
            success:function(data){
                alert(data);
            }
        });
    }
複製代碼

 

 

 


 

RESTful支持

 

Restful就是一個資源定位及資源操作的風格。不是標準也不是協議,只是一種風格,是對http協議的詮釋

資源定位:互聯網所有的事物都是資源,要求url中沒有動詞,只有名詞。沒有參數

Url格式:http://blog.csdn.net/briblue/article/details/73824058

資源操作:使用put、delete、postget,使用不同方法對資源進行操作。分別對應添加、刪除、修改、查詢。一般使用時還是post和get。Put和Delete幾乎不使用。

 

  •   添加DispatcherServlet的rest配置

複製代碼
<servlet>
        <servlet-name>springmvc-servlet-rest</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc-servlet-rest</servlet-name>

        <!-- / :表示攔截所有請求,但是不攔截jsp
            /*  : 表示所有的請求都會攔截,包括jsp
            一般都是推薦只使用  /
         -->
        <url-pattern>/</url-pattern>    
</servlet-mapping>
複製代碼

 

  •   URL 模板模式映射

@RequestMapping(value="/ viewItems/{id}"):{×××}佔位符,請求的URL可以是“/viewItems/1”或“/viewItems/2”,通過在方法中使用@PathVariable獲取{×××}中的×××變量。

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

 

複製代碼
    @RequestMapping("/itemEdit/{id}")//id和形參名稱一致
    public String getItemEdit(Model model,@PathVariable("id")Integer id) throws CustomerException{//@PathVariable不用指定名稱。
        Items  items = itemService.getItemById(id);
        //view.addObject("item", items);
        model.addAttribute("item", items);
        return "editItem";
    }
複製代碼

 

  •   靜態資源訪問<mvc:resources>

 

如果在DispatcherServlet中設置url-pattern爲 /則必須對靜態資源進行訪問處理。

spring mvc 的<mvc:resources mapping="" location="">實現對靜態資源進行映射訪問。

  如下是對js文件訪問配置:

  <mvc:resources location="/js/" mapping="/js/**"/>

 


 

攔截器

 

Spring Web MVC 的處理器攔截器類似於Servlet 開發中的過濾器Filter,用於對處理器進行預處理和後處理。

區別: 攔截器不需要依賴servlet容器,過濾器需要依賴於javaWeb的環境

    攔截器是spring提供的一種機制,過濾器是javaWeb提供的一種支持

 

   一、定義攔截器

複製代碼
Public class HandlerInterceptor1 implements HandlerInterceptor{

    /**
     * controller執行前調用此方法
     * 返回true表示繼續執行,返回false中止執行
     * 這裏可以加入登錄校驗、權限攔截等
     */
    @Override
    Public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        // TODO Auto-generated method stub
        Return false;
    }
    /**
     * controller執行後但未返回視圖前調用此方法
     * 這裏可在返回用戶前對模型數據進行加工處理,比如這裏加入公用信息以便頁面顯示
     */
    @Override
    Public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub
        
    }
    /**
     * controller執行後且視圖返回後調用此方法
     * 這裏可得到執行controller時的異常信息
     * 這裏可記錄操作日誌,資源清理等
     */
    @Override
    Public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub
        
    }
}
複製代碼

 

 

   二、配置攔截器

      1、針對某種mapping配置攔截器

複製代碼
<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"/>
複製代碼

 

 

      2、針對所有mapping配置全局攔截器

複製代碼
<!--攔截器 -->
<mvc:interceptors>
    <!--多個攔截器,順序執行 -->
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="springmvc.filter.HandlerInterceptor1"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="springmvc.filter.HandlerInterceptor2"></bean>
    </mvc:interceptor>
</mvc:interceptors>
複製代碼

 

 

   三、正常流程測試

  定義兩個攔截器分別爲:HandlerInterceptor1和HandlerInteptor2,每個攔截器的preHandler方法都返回true。

  運行結果:

HandlerInterceptor1..preHandle..

HandlerInterceptor2..preHandle..

 

HandlerInterceptor2..postHandle..

HandlerInterceptor1..postHandle..

 

HandlerInterceptor2..afterCompletion..

HandlerInterceptor1..afterCompletion..

 

   四、中斷流程測試

  

  HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,運行流程如下:

    HandlerInterceptor1..preHandle..

  從日誌看出第一個攔截器的preHandler方法返回false後第一個攔截器只執行了preHandler方法,其它兩個方法沒有執行,第二個攔截器的所有方法不執行,且controller也不執行了。

 

 

  HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,運行流程如下:

    HandlerInterceptor1..preHandle..

    HandlerInterceptor2..preHandle..

    HandlerInterceptor1..afterCompletion..

  從日誌看出第二個攔截器的preHandler方法返回false後第一個攔截器的postHandler沒有執行,第二個攔截器的postHandler和afterCompletion沒有執行,且controller也不執行了。

 

  總結

preHandle按攔截器定義順序調用

postHandler按攔截器定義逆序調用

afterCompletion按攔截器定義逆序調用

postHandler在攔截器鏈內所有攔截器返成功調用

afterCompletion只有preHandle返回true才調用

 

 

   * 攔截器應用

 

1、有一個登錄頁面,需要寫一個controller訪問頁面

2、登錄頁面有一提交表單的動作。需要在controller中處理。

a)       判斷用戶名密碼是否正確

b)       如果正確 向session中寫入用戶信息

c)        返回登錄成功,或者跳轉到商品列表

3、攔截器。

a)       攔截用戶請求,判斷用戶是否登錄

b)       如果用戶已經登錄。放行

c)        如果用戶未登錄,跳轉到登錄頁面。

 

  用戶身份認證

複製代碼
Public class LoginInterceptor implements HandlerInterceptor{

    @Override
    Public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {

        //如果是登錄頁面則放行
        if(request.getRequestURI().indexOf("login.action")>=0){
            return true;
        }
        HttpSession session = request.getSession();
        //如果用戶已登錄也放行
        if(session.getAttribute("user")!=null){
            return true;
        }
        //用戶沒有登錄挑戰到登錄頁面
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        
        return false;
    }
}
複製代碼

  

  controller

複製代碼
   //登陸頁面
    @RequestMapping("/login")
    public String login(Model model)throws Exception{        
        return "login";
    }
    
    //登陸提交
    //userid:用戶賬號,pwd:密碼
    @RequestMapping("/loginsubmit")
    public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{        
        //向session記錄用戶身份信息
        session.setAttribute("activeUser", userid);
        
        return "redirect:item/queryItem.action";
    }
    
    //退出
    @RequestMapping("/logout")
    public String logout(HttpSession session)throws Exception{    
        //session過期
        session.invalidate();      
        return "redirect:item/queryItem.action";
    }
複製代碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章