1. 程式人生 > >SpringMVC基礎知識

SpringMVC基礎知識

order getname tle hashcode 字符串轉日期 ole xtend 之前 org

一、Spring MVC簡介

1.1Spring MVC工作流程

映射器:主要是根據瀏覽器上輸入的url來映射所有滿足要求的Handle(控制器類)

適配器:主要是決定調用哪個Handler來實現具體的業務邏輯

技術分享圖片

1.2Spring MVC VS Struts2

1)springmvc的入口是一個servlet,即前端控制器;

struts2入口是一個filter過慮器,即前端過濾器,

2)springmvc是基於方法開發(控制器類是單例的,不可能維護實體變量),傳遞參數是通過方法形參,可以設計為單例;

struts2是基於類開發(維護一個實體變量),傳遞參數是通過類的屬性,只能設計為多例

3)springmvc通過參數解析器是將request對象內容進行解析成方法形參,將響應數據和頁面封裝成ModelAndView對象,最後又將模型數據通過request對象傳輸到頁面;

struts采用值棧存儲請求和響應的數據,通過OGNL存取數據

4)springmvc開發運行速度快於struts2

二、Spring MVC工程搭建(xml)

2.1導入springioc,springweb , springmvc相關的jar包

2.2在/WEB-INF/ web.xml文件配置SpringMVC的前端控制器DispatcherServlet(前端控制器)

<!-- 註冊springmvc核心控制器 -->
    <servlet>
    <!-- servlet-name名字隨便寫 -->
       <servlet-name>DispatcherServlet</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <!-- 通知DispatcherServlet去指定的目錄下加載springmvc.xml配置文件
           classpath:是在工程的src路徑下尋找
        如果不配置init-param的話,控制器會自動尋找/WEB-INF/<servlet-name>-servlet.xml文件-->
       <init-param>
       <!-- 值是固定的,相當於鍵值對 -->
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:springmvc.xml</param-value>
       </init-param>
    </servlet>
    <servlet-mapping>
       <servlet-name>DispatcherServlet</servlet-name>
       <url-pattern>*.action</url-pattern>//攔截請求
    </servlet-mapping>

註:在默認情況下:springmvc框架的配置文件必須叫<servlet-name>-servlet.xml

且必須放在/WEB-INF/目錄下,我們可以在web.xml文件中,為DispatcherServlet配置一個初始化參數,

讓它去我們指定的目錄下加載springmvc.xml配置文件

2.3配置springmvc.xml

註:該配置文件的命名規則遵循web.xml文件中核心控制器配置

<!-- 控制器(程序員) -->
    <bean name="/hello.action" class="cn.itcast.javaee.springmvc.base.HelloAction"></bean> 
   
   
    <!-- 映射器(框架) 如果不寫,默認是將bean標簽的name屬性當做URL--> 
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> 
     
    <!-- 適配器(框架),如果不寫,默認是用於尋找實現了Controller接口的類 --> 
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> 
 
    <!-- 視圖解析器(框架),默認是通過ModelAndView對象中封裝的視圖名稱(真實路徑)找到真正的頁面--> 
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean> 
     
</beans>

  

三、springmcv組件講解(在springmvc中配置)

3.1概念講解

1)DispatcherServlet:前端控制器

用戶請求到達前端控制器,它就相當於mvc模式中的c,dispatcherServlet是整個流程控制的中心,由它調用其它組件處理用戶的請求,dispatcherServlet的存在降低了組件之間的耦合性。

2)HandlerMapping:處理器映射器

HandlerMapping負責根據用戶請求url找到Handler即處理器,springmvc提供了不同的映射器實現不同的映射方式,例如:配置文件方式,實現接口(controller)方式,註解方式等。

3)HandlAdapter:處理器適配器

通過HandlerAdapter對處理器進行執行,這是適配器模式的應用,通過擴展適配器可以對更多類型的處理器進行執行。

4)Handler:處理器

Handler 是繼DispatcherServlet前端控制器的後端控制器,在DispatcherServlet的控制下Handler對具體的用戶請求進行處理。

由於Handler涉及到具體的用戶業務請求,所以一般情況需要程序員根據業務需求開發Handler。

5)ViewResolver:視圖解析器

View Resolver負責將處理結果生成View視圖,View Resolver首先根據邏輯視圖名解析成物理視圖名即具體的頁面地址,再生成View視圖對象,最後對View進行渲染將處理結果通過頁面展示給用戶。

6)View:視圖

springmvc框架提供了很多的View視圖類型的支持,包括:jstlView、freemarkerView、pdfView等。我們最常用的視圖就是jsp。

一般情況下需要通過頁面標簽或頁面模版技術將模型數據通過頁面展示給用戶,需要由程序員根據業務需求開發具體的頁面。

說明:

在springmvc的各個組件中,處理器映射器、處理器適配器、視圖解析器稱為springmvc的三大組件。

需要用戶開發的組件有handler(控制器)、view(視圖)

3.2組件用法註意事項

1)視圖解析器InternalResourceViewResolver【解析視圖邏輯名對應的真實路徑】

ModelAndView對象中即可以封裝真實視圖路徑名,也可以封裝視圖路徑的邏輯名。在springmvc中,如果是真實名稱,可以不配置,如果不是,要配置前綴和後綴。邏輯視圖名需要在controller中返回ModelAndView指定,比如邏輯視圖名為success,則最終返回的jsp視圖地址為::

“/jsp/itemList.jsp”

最終jsp物理地址:前綴+邏輯視圖名+後綴

代碼如下:

 <!-- 視圖解析器(框架) --> 
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

Action類代碼如下:

modelAndView.setViewName("success");

2)映射器BeanNameUrlHandlerMapping

該映射器適合一個請求訪問一個控制器

將程序員定義的Action所對應的<bean>標簽的name屬性作為請求路徑

 <!-- 註冊控制器(程序員) -->
      <bean name="/add.action" class="cn.itcast.javaee.springmvc.mapping.UserAction"></bean>
 
      <!-- 註冊映射器(handler包)(框架) -->
      <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

http://localhost:8080/springmvc-day01/add.action,訪問到UserAction類

3)映射器SimpleUrlHandlerMapping

多個路徑對應同一個Action

/delete.action和/update.action和/find.action請求路徑都交由<bean>標簽為id的Action,

技術分享圖片
 <!-- 註冊控制器(程序員) -->
      <bean id="userActionID" class="cn.itcast.javaee.springmvc.mapping.UserAction"></bean>
      
      <!-- 註冊映射器(handler包)(框架) -->
      <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
           <property name="mappings">
               <props>
                  <prop key="/delete.action">userActionID</prop>
                  <prop key="/update.action">userActionID</prop>
                  <prop key="/find.action">userActionID</prop>
               </props>
           </property>
      </bean>
技術分享圖片

http://localhost:8080/springmvc-day01/delete.action,

http://localhost:8080/springmvc-day01/update.action,

http://localhost:8080/springmvc-day01/find.action,三個地址都訪問到UserAction類

4)適配器SimpleControllerHandlerAdapter

適配器 :幫你找到實現controler接口的類-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

5)控制器ParameterizableViewController

直接將請求跳轉到jsp頁面,不經過程序員寫的控制器

<!-- /index.action請求,直接轉發到WEB-INF/index.jsp頁面 -->
      <bean name="/index.action" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
           <property name="viewName" value="/index.jsp"/>
      </bean>

3.3自定義日期轉換器和編碼過濾器

1)在默認情況下,springmvc不能將String類型轉成Date類型,必須自定義類型轉換器

public class AdminAction extends Controller{
    @Override
    protected void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
       binder.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
    }

2)spring提供的,專用於解決POST提交中文亂碼問題,需要在web.xml文件中配置

技術分享圖片
 <!-- 編碼過濾器 -->
    <filter>
       <filter-name>CharacterEncodingFilter</filter-name>
       <filter-class>
    org.springframework.web.filter.CharacterEncodingFilter
       </filter-class>
       <init-param>
           <param-name>encoding</param-name>
           <param-value>UTF-8</param-value>
       </init-param>
    </filter>
    <filter-mapping>
       <filter-name>CharacterEncodingFilter</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>
技術分享圖片

四、Spring MVC工程搭建(註解)

4.1創建工程導入jar包

導入springioc,springweb和springmvc相關的jar包

4.2在/WEB-INF/下創建web.xml文件

技術分享圖片
<servlet>
       <servlet-name>DispatcherServlet</servlet-name>  <前端控制器>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:spring.xml</param-value>  <配置路徑名稱>
       </init-param>
    </servlet>
    <servlet-mapping>
       <servlet-name>DispatcherServlet</servlet-name>
       <url-pattern>*.action</url-pattern>   <!--攔截.action請求-->
    </servlet-mapping>
技術分享圖片

4.3配置springmvc.xml

SpringMVC本身就是Spring的子項目,對Spring兼容性很好,不需要做很多配置。配置一個Controller掃描就可以了,讓Spring對頁面控制層Controller進行管理。

1)組件掃描器

省去在spring容器配置每個Controller類的繁瑣。使用<context:component-scan>自動掃描標記@Controller的控制器類,

2)註解式映射器

對類中標記了@ResquestMapping的方法進行映射。根據@ResquestMapping定義的url匹配@ResquestMapping標記的方法,匹配成功返回HandlerMethod對象給前端控制器。

HandlerMethod(處理器方法)對象中封裝url對應的方法Method。 從spring3.1版本開始,廢除了DefaultAnnotationHandlerMapping的使用,推薦使用RequestMappingHandlerMapping完成註解式處理器映射。

3)註解式適配器

對標記@ResquestMapping的方法進行適配。從spring3.1版本開始,廢除了AnnotationMethodHandlerAdapter的使用,推薦使用RequestMappingHandlerAdapter完成註解式處理器適配。

4)註解驅動

為了省事,直接受用註解驅動因為直接配置處理器映射器和處理器適配器比較麻煩。 SpringMVC使用<mvc:annotation-driven>自動加載 RequestMappingHandlerMapping和RequestMappingHandlerAdapter

可以在springmvc.xml配置文件中使用<mvc:annotation-driven>替代註解處理器和適配器的配置。

<!-- 註解驅動 -->
<mvc:annotation-driven />

springmvc配置如下:

技術分享圖片
<!-- Action控制器 -->
      <context:component-scan base-package="cn.itcast.javaee.springmvc.helloannotation"/> //controller類所在的包
     
      <!-- 基於註解的映射器(可選) -->
      <bean class=" org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping "/>
     
      <!-- 基於註解的適配器(可選) -->
      <bean class=" org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter "/>
     
     <!-- 視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       <property name="prefix" value="/jsp/"/>
       <property name="suffix" value=".jsp"/>
    </bean>       
</beans>
技術分享圖片

4.4創建HelloAction.java控制器類

1)HelloAction是一個普通的java類,不需要實現任何接口。

2)需要在類上添加@Controller註解,把Controller交由Spring管理

3)在方法上面添加@RequestMapping註解,裏面指定請求的url。其中“.action”可以加也可以不加。

技術分享圖片
/**
 * 單例
 * 控制器(程序員)
*/
//加上這個@Controller,相當於是控制器類
@Controller
public class HelloAction{
    public HelloAction(){//單例,第一次訪問創建
       System.out.println("HelloAction()::" + this.hashCode());
    }
   
    /**
     * 業務方法
     * 只要是/hello.action的請求,都交由HelloAction對象中的hello()方法去處理
     * 之前是在xml中配置bean的。
     */
    //value值是可以寫多個的。
    @RequestMapping(value="/hello.action")  
    //hello帶參數用Model類,這個類是
    public String hello(Model model) throws Exception{
       System.out.println("HelloAction::hello()");
       model.addAttribute("message","你好");
       return "success";
    }
   
    /**
     * 業務方法
     * 只要是/bye.action的請求,都交由HelloAction對象中的bye()方法去處理
     */
    @RequestMapping(value="/bye.action")  
    public String bye(Model model) throws Exception{
       System.out.println("HelloAction::hello()");
       model.addAttribute("message","再見");
       return "success";
    }
}
技術分享圖片

4.5在/WebRoot/下創建success.jsp

技術分享圖片
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>這是我的第二個springmvc應用程序</title>
  </head>
  <body>
    success.jsp<br/>
    ${message}
  </body>
</html>
技術分享圖片

部署到tomcat中,http://127.0.0.1:8080/springmvc-day02/hello.action

五、springmvc項目開發小功能

5.1參數綁定

1)默認支持的形參類型

HttpServletRequest:通過request對象獲取請求信息,一般get方式提交的可以用request對象獲取。

HttpServletResponse:通過response處理響應信息

HttpSession:通過session對象得到session中存放的對象

Model/ModelMap:用於向頁面傳遞數據。ModelMap是Model接口的實現類,也可以通過ModelMap向頁面傳遞數據。如果使用Model/ModelMap則在方法中可以不使用ModelAndView對象,Model對象可以向頁面傳遞數據,View對象則可以使用String返回值替代。

2)簡單基本類型

當請求的參數名稱和處理器形參名稱一致時會將請求參數與形參進行綁定。這樣,從Request取參數的方法就可以進一步簡化。參數類型推薦使用包裝數據類型,因為基礎數據類型不可以為null

整型:Integer、int

字符串:String

單精度:Float、float

雙精度:Double、double

布爾型:Boolean、boolean

說明:對於布爾類型的參數,請求的參數值為true或false。或者1或0

請求url:

http://localhost:8080/xxx.action?id=2&status=false

處理器方法:

public String editItem(Model model,Integer id,Boolean status)

使用@RequestParam對簡單參數的約定

常用於處理簡單類型的綁定。

value:參數名字,即入參的請求參數名字,如value=“itemId”表示請求的參數 區中的名字為itemId的參數的值將傳入

required:是否必須,默認是true,表示請求中一定要有相應的參數,否則將報錯

HTTP Status 400 - Required Integer parameter ‘XXXX‘ is not present

defaultValue:默認值,表示如果請求中沒有同名參數時的默認值

@RequestMapping("/itemEdit"),頁面中參數名itemId的參數(默認為1,必須要傳)傳過來給形參id。
public String queryItemById(@RequestParam(value = "itemId", required = true, defaultValue = "1") Integer id,
                   ModelMap modelMap) {}

3)pojo對象類型數據

pojo: 普通的Java對象,對於屬性一般實現了JavaBean的標準,另外還可以包含一些簡單的業務邏輯(方法)

如果提交的參數很多,或者提交的表單中的內容很多的時候,可以使用簡單類型接受數據,也可以使用pojo類接收數據。

要求:pojo對象中的屬性名和表單中input的name屬性一致

public String updateItem(Item item) {
         // 返回邏輯視圖
         return "success";
}

技術分享圖片

技術分享圖片

4)自定義參數

比如:由於日期數據有很多種格式,springmvc沒辦法把字符串轉換成日期類型。所以需要自定義參數綁定。

前端控制器接收到請求後,找到註解形式的處理器適配器,對RequestMapping標記的方法進行適配,並對方法中的形參進行參數綁定。可以在springmvc處理器適配器上自定義轉換器Converter進行參數綁定。

技術分享圖片
//Converter<S, T>
//S:source,需要轉換的源的類型
//T:target,需要轉換的目標類型
public class DateConverter implements Converter<String, Date> {
 
         @Override
         public Date convert(String source) {
                   try {
                            // 把字符串轉換為日期類型
                            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
                            Date date = simpleDateFormat.parse(source);
 
                            return date;
                   } catch (ParseException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                   }
                   // 如果轉換異常則返回空
                   return null;
         }
}
技術分享圖片 技術分享圖片
在springmvc中:
<!-- 轉換器配置 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
         <property name="converters">
                   <set>
                            <bean class="cn.itcast.springmvc.converter.DateConverter" />//自定義類名
                   </set>
         </property>
</bean>
技術分享圖片

5)數組參數

針對需求:在商品列表頁面選中多個商品,然後刪除。

註意:數組名要和表單中的name名稱一樣。

方法:

技術分享圖片
 //數組的名字要和頁面03_emp中name的屬性值保持一樣
    public String deleteAll(Model model,int[] ids) throws Exception{
       System.out.println("需要刪除的員工編號分別是:");
       for(int id : ids){
           System.out.print(id+" ");
       }
       model.addAttribute("message","批量刪除員工成功");
       return "/jsp/ok.jsp";
    }
技術分享圖片

jsp頁面:

技術分享圖片
 <th>編號</th>
           <th>姓名</th>
        </tr>
        <tr>
           <td><input type="checkbox" name="ids" value="1"/></td>
           <td>哈哈</td>
        </tr>
        <tr>
           <td><input type="checkbox" name="ids" value="2"/></td>
           <td>呵呵</td>
          省略
        </tr>
技術分享圖片

技術分享圖片

6)將表單的數據綁定到List

需求:表單中的每一條記錄對應一個user類,

註意:list類名要和jspname屬性名一樣。

批量註冊用戶

UserAction.java

技術分享圖片
@Controller
@RequestMapping(value="/user")
public class UserAction {
    @RequestMapping(value="/addAll")
    public String addAll(Bean bean,Model model) throws Exception{
       for(User user : bean.getUserList()){
           System.out.println(user.getName()+":"+user.getGender());
       }
       model.addAttribute("message","批量增加用戶成功");
       return "/success.jsp";
    }
}
技術分享圖片

Bean.java

技術分享圖片
public class Bean {
//list類名要和jsp中name屬性名一樣。
    private List<User> userList = new ArrayList<User>();
    public Bean(){}
    public List<User> getUserList() {
       return userList;
    }
    public void setUserList(List<User> userList) {
       this.userList = userList;
    }
}
技術分享圖片

registerAll.jsp

技術分享圖片
 <form action="${pageContext.request.contextPath}/user/addAll.action" method="POST">
        
       姓名:<input type="text" name="userList[0].name" value="哈哈"/>
       性別:<input type="text" name="userList[0].gender" value="男"/>
       <hr/>
      
       姓名:<input type="text" name="userList[1].name" value="呵呵"/>
       性別:<input type="text" name="userList[1].gender" value="男"/>
       <hr/>
 
       姓名:<input type="text" name="userList[2].name" value="嘻嘻"/>
       性別:<input type="text" name="userList[2].gender" value="女"/>
       <hr/>
      
       <input type="submit" value="批量註冊"/>
      
    </form>
技術分享圖片

5.2解決項目中的編碼問題

解決post亂碼問題

提交發現,保存成功,但是保存的是亂碼

在web.xml中加入:

技術分享圖片
 <!-- 解決post亂碼問題 -->
         <filter>
                   <filter-name>encoding</filter-name>
                   <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
                   <!-- 設置編碼參是UTF8 -->
                   <init-param>
                            <param-name>encoding</param-name>
                            <param-value>UTF-8</param-value>
                   </init-param>
         </filter>
         <filter-mapping>
                   <filter-name>encoding</filter-name>
                   <url-pattern>/*</url-pattern>
         </filter-mapping>
技術分享圖片

以上可以解決post請求亂碼問題。

對於get請求中文參數出現亂碼解決方法有兩個:

修改tomcat配置文件添加編碼與工程編碼一致,如下:

<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

另外一種方法對參數進行重新編碼:

String userName =new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")

ISO8859-1是tomcat默認編碼,需要將tomcat編碼後的內容按utf-8編碼

5.3@RequestMapping註解使用

1)url路徑的映射

@RequestMapping(value="item")或@RequestMapping("/item"),value的值是數組,可以將多個url映射到同一個方法

@RequestMapping(value = { "itemList", "itemListAll" })
public ModelAndView queryItemList() {

2)可以添加到類上

在class上添加@RequestMapping(url)指定通用請求前綴, 限制此類下的所有方法請求url必須以請求前綴開頭

3)請求方法限定

技術分享圖片
//限定GET方法
@RequestMapping(method = RequestMethod.GET)
//如果通過POST訪問則報錯:
//HTTP Status 405 - Request method ‘POST‘ not supported
//限定POST方法
@RequestMapping(method = RequestMethod.POST)
//如果通過GET訪問則報錯:
//HTTP Status 405 - Request method ‘GET‘ not supported
//GET和POST都可以(默認)
@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})
技術分享圖片

5.4controller控制器方法的返回值

1)返回ModelAndView

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

控制器方法:

技術分享圖片
public ModelAndView handleRequest(HttpServletRequest requqest,HttpServletResponse response) throws Exception {
       // ModelAndView現在不用了
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.addObject("message","這是我的第一個springmvc應用程序");
       modelAndView.setViewName("/jsp/success.jsp");
       return modelAndView;
    }
技術分享圖片

2)返回void,利用request和response指定響應結果

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

①使用request轉發頁面,如下:

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

②可以通過response頁面重定向:

response.sendRedirect("url")

response.sendRedirect("/springmvc-web2/itemEdit.action");

3)返回字符串(項目中一般都用這種)

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

public String hello(Model model) throws Exception{
       System.out.println("HelloAction::hello()");
       model.addAttribute("message","你好");
       return "success";
    }

②轉發和重定向

在轉發情況下,共享request域對象,會將參數從第一個業務控制方法傳入第二個業務控制方法,

反之,重定向則不行

技術分享圖片
public String findEmpById(int id,Model model) throws Exception{
       System.out.println("查詢"+id+"號員工信息");
       //轉發到EmpAction的另一個方法中去,即再次發送請求
       return "forward:/emp/update.action";
       //重定向到EmpAction的另一個方法中去,即再次發送請求,也可以吧id放到session中,也可以吧id直接寫在末尾。
       //return "redirect:/emp/update.action?id=" + id;
 
    }
技術分享圖片

5.5@InitBinder來解決字符串轉日期類型

技術分享圖片
/**
     * 自定義類型轉換器,springmvc在轉換參數時候,
     * 如果轉不成功,會去自定義類型轉換器中用
     */
    @InitBinder
    public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
       binder.registerCustomEditor(
              Date.class,
              new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),true));
    }
技術分享圖片

六、異常處理器

springmvc在處理請求過程中出現異常信息交由異常處理器進行處理,自定義異常處理器可以實現一個系統的異常處理邏輯。

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

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

技術分享圖片

6.1自定義異常處理器

技術分享圖片
public class CustomHandleException implements HandlerExceptionResolver {
                        
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
           Exception exception) {
       // 定義異常信息
       String msg;
 
       // 判斷異常類型
       if (exception instanceof MyException) {
           // 如果是自定義異常,讀取異常信息
           msg = exception.getMessage();
       } else {
           // 如果是運行時異常,則取錯誤堆棧,從堆棧中獲取異常信息
           Writer out = new StringWriter();
           PrintWriter s = new PrintWriter(out);
           exception.printStackTrace(s);
           msg = out.toString();
 
       }
 
       // 把錯誤信息發給相關人員,郵件,短信等方式
       // TODO
 
       // 返回錯誤頁面,給用戶友好頁面顯示錯誤信息
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.addObject("msg", msg);
       modelAndView.setViewName("error");
 
       return modelAndView;
    }
}
技術分享圖片

在springmvc中配置

<!-- 配置全局異常處理器 -->
<bean
id="customHandleException"     class="cn.itcast.ssm.exception.CustomHandleException"/>

6.2自定義異常類

技術分享圖片
public class MyException extends Exception {
    private String message; // 異常信息
    public MyException() {
       super();
    }
    public MyException(String message) {
       super();
       this.message = message;
    }
    public String getMessage() {
       return message;
    }
    public void setMessage(String message) {
       this.message = message;
    }
}
技術分享圖片

七、springmvc中的攔截器

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

實現HandlerInterceptor接口

如下:

技術分享圖片
public class HandlerInterceptor1 implements HandlerInterceptor {
 
    // Controller執行前調用此方法
    // 返回true表示繼續執行,返回false中止執行
    // 這裏可以加入登錄校驗、權限攔截等
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
       System.out.println("HandlerInterceptor1....preHandle");
        // 設置為true,測試使用
       return true;
    }
 
    // controller執行後且視圖返回後調用此方法
    // 這裏可得到執行controller時的異常信息
    // 這裏可記錄操作日誌
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
           throws Exception {
       System.out.println("HandlerInterceptor1....afterCompletion");
    }
 
    // controller執行後但未返回視圖前調用此方法
    // 這裏可在返回用戶前對模型數據進行加工處理,比如這裏加入公用信息以便頁面顯示
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
           throws Exception {
       System.out.println("HandlerInterceptor1....postHandle");
    }
}
技術分享圖片

攔截器配置

上面定義的攔截器再復制一份HandlerInterceptor2,註意新的攔截器修改代碼:

System.out.println("HandlerInterceptor2....preHandle");

在springmvc.xml中配置攔截器

技術分享圖片
<!-- 配置攔截器 -->

<mvc:interceptors>

 

    <mvc:interceptor>

       <!-- 所有的請求都進入攔截器 -->

       <mvc:mapping path="/**" />

       <!-- 配置具體的攔截器 -->

       <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1" />

    </mvc:interceptor>

    <mvc:interceptor>

       <!-- 所有的請求都進入攔截器 -->

       <mvc:mapping path="/**" />

       <!-- 配置具體的攔截器 -->

       <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor2" />

    </mvc:interceptor>

</mvc:interceptors>
技術分享圖片

正常流程測試

瀏覽器訪問地址

http://127.0.0.1:8080/springmvc-web2/itemList.action

運行流程

控制臺打印:

HandlerInterceptor1..preHandle..

HandlerInterceptor2..preHandle..

HandlerInterceptor2..postHandle..

HandlerInterceptor1..postHandle..

HandlerInterceptor2..afterCompletion..

HandlerInterceptor1..afterCompletion..

中斷流程測試

瀏覽器訪問地址

http://127.0.0.1:8080/springmvc-web2/itemList.action

運行流程

HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,

運行流程如下:

HandlerInterceptor1..preHandle..

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

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

HandlerInterceptor1..preHandle..

HandlerInterceptor2..preHandle..

HandlerInterceptor1..afterCompletion..

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

總結:

preHandle按攔截器定義順序調用

postHandler按攔截器定義逆序調用

afterCompletion按攔截器定義逆序調用

postHandler在攔截器鏈內所有攔截器返回true調用

afterCompletion只有preHandle返回true才調用

八、使用json數據交互

8.1@RequestBody註解

用於讀取http請求的內容(字符串),通過springmvc提供的HttpMessageConverter接口將讀到的內容(json數據)轉換為java對象並綁定到Controller方法的參數上。

8.2請求json和響應json的實現

1)導入jar包

2)配置json轉換器

如果不使用註解驅動<mvc:annotation-driven />,就需要給處理器適配器配置json轉換器,參考之前學習的自定義參數綁定。

在springmvc.xml配置文件中,給處理器適配器加入json轉換器:

技術分享圖片
<!--處理器適配器 -->

<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>
技術分享圖片

3)寫javabean

Item.java

技術分享圖片
public class Item {

    private Integer id;

    private String name;

    private Double sal;

    public User(){}

    public Integer getId() {

       return id;

    }

    public void setId(Integer id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

    public Double getSal() {

       return sal;

    }

    public void setSal(Double sal) {

       this.sal = sal;

    }

}
技術分享圖片

4)jsp編寫

技術分享圖片
<form>

       編號:<input type="text" name="id" value="1"/><br/>

       姓名:<input type="text" name="name" value="哈哈"/><br/>

       薪水:<input type="text" name="sal" value="5000"/><br/>

       <input type="button" value="異步提交註冊"/>

    </form>

   

    <script type="text/javascript">

       $(":button").click(function(){

           var url = "${pageContext.request.contextPath}/ testJson ";

           var sendData = {

              "id":1,

              "name":"哈哈",

              "sal":5000

           };

           $.post(url,sendData,function(backData,textStatus,ajax){

              alert(ajax.responseText);

           });

       });

    </script>
技術分享圖片

5)控制器編寫

技術分享圖片
/**

 * 測試json的交互

 * @param item

 * @return

 */

@RequestMapping("testJson")

// @ResponseBody

public @ResponseBody Item testJson(@RequestBody Item item) {

System.out.println(item.getId()+":"+item.getName()+":"+item.getSal());

    return item;

}
技術分享圖片

SpringMVC基礎知識