1. 程式人生 > >Spring MVC使用篇(十二)—— 異常處理

Spring MVC使用篇(十二)—— 異常處理

1、綜述

  在Web專案正式上線或者執行時,往往會出現一些不可預料的異常資訊。對於邏輯性或設計性問題,開發人員或者維護人員需要通過日誌,檢視異常資訊並排除異常;而對於使用者,則需要為其呈現出其可以理解的異常提示頁面,讓使用者有一個良好的使用體驗。所以異常的處理對於一個Web專案來說是非常重要的。Spring MVC提供了強大的異常處理機制。

2、全域性異常處理器

  系統中的異常一般分為兩大類:預期異常和執行時異常。對於前者一般通過捕獲異常來獲取異常資訊,而後者主要通過規範程式碼的開發、測試,通過一些技術手段來減少執行時異常的發生。

  在Spring MVC中,提供了一個全域性異常處理器,用於對系統中出現的異常進行統一處理。在一般的系統中,DAO、Service及Controller層出現的異常都以“throws Exception”的形式向上層丟擲,最後都會由Spring MVC的前端控制器(DispatcherServlet)統一交由全域性異常處理器進行異常處理。

  當系統遇到異常時,不同層的異常會拋向上一級,並最終拋向Spring MVC的全域性異常處理器。該全域性處理器要實現的主要功能是:第一,解析出異常資訊,判斷異常屬於哪種異常類;第二,如果該異常型別是系統自定義的異常,直接取出異常資訊,並在錯誤頁面展示。如果該異常型別不是系統自定義的異常,構造一個自定義的異常型別,資訊為“未知錯誤”;第三,構建異常資訊展示檢視資訊,將異常資訊繫結到異常介面的Model域中,然後跳轉到相關的異常資訊顯示頁面。

2.1 SimpleMappingExceptionResolver異常處理器

  SimpleMappingExceptionResolver異常處理器是系統定義好的異常處理器。該方式只需要在Spring MVC的核心配置檔案springmvc.xml中註冊該異常處理器Bean即可。該Bean比較特殊,沒有id屬性,無需顯示呼叫或被注入給其它Bean,當異常發生時會自動執行該類。

  現在利用SimpleMappingExceptionResolver異常處理器處理系統預設異常的情況。

  首先,在“com.ccff.controller”下建立名為“ExceptionController”的控制器,具體程式碼如下:

package com.ccff.controller;

import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/ExceptionTest") public class ExceptionController { @RequestMapping("/login") public String login(){ return "exception/login"; } @RequestMapping("/doLogin") public String doLogin(User user){ if ("".equals(user.getUsername()) || "".equals(user.getPassword())){ throw new NullPointerException("空指標異常"); } return "exception/success"; } }

  由上面的程式碼可以看出,login方法用於顯示登入頁面,而使用者輸入資訊後將表單提交到doLogin方法處理。而在doLogin方法中,如果使用者輸入的使用者名稱或者密碼為空時,將會直接丟擲NullPointerException(空指標異常)。注意:這裡僅僅是 為了演示對於系統自帶的異常的處理,並不完全符合業務邏輯。

  接著,在springmvc.xml配置檔案中配置異常處理器,將如下程式碼加入到配置檔案中即可:

<!--配置異常處理器-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.NullPointerException">exception/nullError</prop>
        </props>
    </property>
    <property name="defaultErrorView" value="exception/error" />
    <property name="exceptionAttribute" value="ex" />
</bean>

  由上面的程式碼可以看出,在springmvc.xml配置檔案中配置了SimpleMappingExceptionResolver異常處理器Bean,同時為其配置了以下三個屬性:

  exceptionMappings:properties型別屬性,用於指定具體的不同型別的異常所對應的異常響應頁面。key為異常類的全限定性類名,value則為響應頁面路徑。(注意:由於之前配置過了InternalResourceViewResolver檢視解析器,同時配置了字首和字尾,這裡仍然是直接使用拼接形成最後路徑的方式)

  defaultErrorView:指定預設的異常響應頁面。若發生的異常不是exceptionMappings中指定的異常,則使用預設異常響應頁面。

  exceptionAttribute:捕獲到的異常物件。一般異常響應頁面中使用。

  然後,在WEB-INF/jsp路徑下建立名為“exception”的資料夾用來存放和異常處理相關的JSP檔案。

  登入頁面login.jsp程式碼如下所示:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   
<!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>
        <h3>使用者登入</h3>
        <form action="doLogin.action" method="post">
            <table width="300px;" border=1>
                <tr>
                    <td>使用者編號:</td>
                    <td><input type="text" name="userId" id="userId" /></td>
                </tr>
                <tr>
                    <td>使用者名稱:</td>
                    <td><input type="text" name="username" id="username" /></td>
                </tr>
                <tr>
                    <td>密 碼:</td>
                    <td><input type="password" name="password" id="password" /></td>
                </tr>
            </table>
            <br/>
            <input type="submit" id="login_button" value="使用者登入" />
        </form>
    </body>
</html> 

  空資訊異常頁面nullError.jsp程式碼如下所示:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>NULL ERROR</title>
  </head>
  
  <body>
    Null Error page<br>
    <hr>
    ${ex.message }<br>
  </body>
</html>

  預設異常資訊頁面error.jsp程式碼如下所示:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>ERROR</title>
  </head>
  
  <body>
    Error page<br>
    <hr>
    ${ex.message }<br>
  </body>
</html>

  登入成功頁面success.jsp程式碼如下所示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>登入成功</title>
</head>
<body>
  <h2>登入成功!</br></br>歡迎您${user.username}!</h2>

  <hr/>

  <h3>使用user引數顯示使用者註冊資訊</h3>
  <table width="300px;" border=1>
    <tr>
      <td>使用者編號:</td>
      <td>${user.userId}</td>
    </tr>
    <tr>
      <td>使用者名稱:</td>
      <td>${user.username}</td>
    </tr>
    <tr>
      <td>密 碼:</td>
      <td>${user.password}</td>
    </tr>
  </table>
</body>
</html>

  最後,將專案部署到Tomcat上後,在瀏覽器內輸入請求URL:http://localhost:8080/demo/ExceptionTest/login.action 後向使用者顯示登入頁面,如下所示:
在這裡插入圖片描述
  根據前面在Controller中的doLogin方法的登入處理邏輯,當用戶名或者密碼為空時,將會出現空指標異常,並根據在配置檔案中配置的異常頁面,將顯示nullError.jsp頁面的內容。

  因此在登入頁面中僅輸入使用者編號後提交表單,則向用戶顯示結果如下:
在這裡插入圖片描述

2.2 自定義異常處理器

  使用Spring MVC定義好的SimpleMappingExceptionResolver異常處理器,可以實現發生指定異常後的跳轉。但若要實現在捕獲到指定異常時,執行一些操作的目的,它是完成不了的。此時,就需要自定義異常處理器。

  第一,在“com.ccff.exception”下建立名為“PasswordLengthException”的自定義異常,具體程式碼如下:

package com.ccff.exception;

public class PasswordLengthException extends Exception {
    //異常資訊
    private String message;

    public PasswordLengthException(String message) {
        super(message);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

  自定義異常類繼承了Exception父類。Exception類為java.lang.Throwable的子類,用於描述程式能夠捕獲的異常。在PasswordLengthException中設定了一個成員變數message,專門用來存放異常資訊。當需要丟擲PasswordLengthException型別的異常時,通過其構造方法就可以設定其異常資訊,後期在全域性異常處理器中,可以通過PasswordLengthException類的getMessage方法來獲取相關的異常資訊。

  第二,自定義全域性異常處理器,即該核心異常處理器專門用於處理系統中所有關於PasswordLengthException的異常。在“com.ccff.exception”下建立名為“PasswordLengthExceptionResolver”的異常處理器。具體程式碼如下:

package com.ccff.exception;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

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

public class PasswordLengthExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        //1、解析出異常型別
        PasswordLengthException passwordLengthException = null;
        if (e instanceof PasswordLengthException){
            //2、如果該異常型別是自定義的PasswordLengthException異常,直接取出異常資訊,在錯誤頁面顯示
            passwordLengthException = (PasswordLengthException) e;
        }else {
            //3、如果該異常型別不是自定義的PasswordLengthException異常,構造一個自定義的異常型別(資訊為“未知錯誤”)
            passwordLengthException = new PasswordLengthException("未知錯誤");
        }
        //錯誤資訊
        String message = passwordLengthException.getMessage();
        ModelAndView modelAndView = new ModelAndView();
        //將錯誤資訊傳到頁面
        modelAndView.addObject("message",message);
        //指向到錯誤頁面
        modelAndView.setViewName("/exception/passwordLengthError");
        return modelAndView;
    }
}

  這裡需要注意的是:全域性異常處理器要實現Spring MVC提供的HandlerExceptionResolver介面。 從上面的程式碼中可以看到,HandlerExceptionResolver介面中定義了一個名為resolveException的方法,該方法主要用於處理Controller中的異常。引數“Exception e”即為Controller或其下層丟擲的異常。引數“Object o”就是處理器介面卡要執行的Handler物件。resolveException方法的返回值型別是ModelAndView,也就是說,可以通過這個返回值類設定發出異常時顯示的頁面。

  第三,需要在WEB-INF/jsp/exception下建立一個名為“passwordLengthError.jsp”的頁面來顯示當密碼長度不符合要求時的需要顯示異常的頁面,具體程式碼如下:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>PASSWORD LENGTH ERROR</title>
  </head>
  
  <body>
    Password Length Error page<br>
    <hr>
    ${message }<br>
  </body>
</html>

  第四,修改控制器中的doLogin方法,具體程式碼如下:

package com.ccff.controller;

import com.ccff.exception.PasswordLengthException;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/ExceptionTest")
public class ExceptionController {
    @RequestMapping("/login")
    public String login(){
        return "exception/login";
    }

    @RequestMapping("/doLogin")
    public String doLogin(User user) throws PasswordLengthException {
        if ("".equals(user.getUsername()) || "".equals(user.getPassword())){
            throw new NullPointerException("空指標異常");
        }else if (user.getPassword().length()<6 || user.getPassword().length()>12){
            throw new PasswordLengthException("密碼長度異常");
        }
        return "exception/success";
    }
}

  第五,在Spring MVC的核心配置檔案springmvc.xml中將自定義的全域性異常處理器配置進去,具體配置如下:

<!--配置自定義異常處理器-->
<bean class="com.ccff.exception.PasswordLengthExceptionResolver" />

  這裡雖然只添加了一個bean的載入配置,但是隻要該Bean對應的類實現了HandlerExceptionResolver介面,這個類就會被Spring MVC作為一個全域性異常處理器。

  最後將專案部署到Tomcat上後,在瀏覽器內輸入請求URL:http://localhost:8080/demo/ExceptionTest/login.action 後,為了測試自定義的密碼長度異常,在登入表單中輸入3位的密碼,如下所示:
在這裡插入圖片描述
  當表單提交後,在控制器的doLogin方法中會捕獲到密碼長度異常,並最終交由全域性異常處理器處理該異常,顯示結果如下:
在這裡插入圖片描述

2.3 異常處理註解

  使用註解@ExceptionHandler可以將一個方法指定為異常處理方法。該註解只有一個可選屬性value,為一個class<?>陣列,用於指定該註解的方法所要處理的異常類,即所要匹配的異常。

&emsp 而被註解的方法,其返回值可以是ModelAndView、String或void,方法名隨意,方法引數可以是Exception及其子類物件、HttpServletRequest、HttpServletResponse等。系統會自動為這些方法引數賦值。

  對於異常處理註解的用法,也可以直接將異常處理方法註解於Controller之中。不過一般不這樣使用,而是將異常處理方法專門定義在一個Controller中,讓其他Controller繼承該Controller即可。但是,這種用法的弊端也很明顯:Java是“單繼承多實現”的,這個Controller的繼承將這唯一的一個繼承機會使用了,使得若再有其他類需要繼承,將無法直接實現。

  在這一節的演示專案中,我們使用異常處理註解的方法對使用者編號的驗證進行異常處理。驗證使用者登入時輸入的使用者編號是否大於0。

  第一步,在“com.ccff.exception”下建立名為“UserIdBigZeroException”的自定義異常,具體程式碼如下:

package com.ccff.exception;

public class UserIdBigZeroException extends Exception {
    //異常資訊
    private String message;

    public UserIdBigZeroException(String message) {
        super(message);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

  第二步,在“com.ccff.exception”下建立名為“MyExceptionResolverController”的控制器,即定義異常處理的的Controller,具體程式碼如下:

package com.ccff.controller;

import com.ccff.exception.UserIdBigZeroException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MyExceptionResolverController {
    //用於處理使用者編號異常的方法
    @ExceptionHandler(UserIdBigZeroException.class)
    public ModelAndView handleUserIdBigZeroException(Exception ex){
        ModelAndView modelAndView = new ModelAndView();
        String message = ((UserIdBigZeroException)ex).getMessage();
        modelAndView.addObject("message",message);
        modelAndView.setViewName("/exception/userIdBigZeroError");
        return modelAndView;
    }
}

  第三步,修改ExceptionController,讓其繼承自異常處理Controller,同時在ExceptionController中的doLogin方法中捕獲使用者編號大於0異常資訊,具體程式碼如下:

package com.ccff.controller;

import com.ccff.exception.PasswordLengthException;
import com.ccff.exception.UserIdBigZeroException;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/ExceptionTest")
public class ExceptionController extends MyExceptionResolverController {
    @RequestMapping("/login")
    public String login(){
        return "exception/login";
    }

    @RequestMapping("/doLogin")
    public String doLogin(User user) throws PasswordLengthException, UserIdBigZeroException {
        if ((Integer)user.getUserId() instanceof Integer && user.getUserId()<=0){
            throw new UserIdBigZeroException("使用者編號必須大於0");
        }
        if ("".equals(user.getUsername()) || "".equals(user.getPassword())){
            
            
           

相關推薦

Spring MVC使用—— 異常處理

1、綜述   在Web專案正式上線或者執行時,往往會出現一些不可預料的異常資訊。對於邏輯性或設計性問題,開發人員或者維護人員需要通過日誌,檢視異常資訊並排除異常;而對於使用者,則需要為其呈現出其可以理解的異常提示頁面,讓使用者有一個良好的使用體驗。所以異常的處

Python入門異常處理

Python 異常處理 python提供了兩個非常重要的功能來處理python程式在執行中出現的異常和錯誤。你可以使用該功能來除錯python程式。 異常處理: 本站Python教程會具體介紹。 斷言(Assertions):本站Python教程會具體介紹。

python的學習----異常處理(3)

異常處理(3) 一、異常基礎 try/except:捕捉由程式碼中的異常並恢復,匹配except裡面的錯誤,並自行except中定義的程式碼,後繼續執行程式(發生異常後,由except捕捉到異常後,不會中斷程式,繼續執行try語句後面的程式) try/finally: 無論異常是否發生,都執行清理行為 (發

Spring Boot教程整合elk1

分享圖片 operation you 運行 hot href iba for 分享 elk 簡介 Elasticsearch是個開源分布式搜索引擎,它的特點有:分布式,零配置,自動發現,索引自動分片,索引副本機制,restful風格接口,多數據源,自動搜索負載等。

Spring原始碼解析——AOP原理——@EnableAspectJAutoProxy

一、@EnableAspectJAutoProxy 第一步:註冊AnnotationAwareAspectJAutoProxyCreator 把AnnotationAwareAspectJAutoProxyCreator建立為RootBeanDefinition,加入

linux基礎:Redhat7系統中rpm的相關操作與第三方軟體庫的搭建與共享

RPM RPM是Red-Hat Package Manager(RPM軟體包管理器)的縮寫,這一檔案格式名稱雖然打上了RedHat的標誌,但是其原始設計理念是開放式的,現在包括OpenLinux、S.u.S.E.以及Turbo Linux等Linux的分發版本都

Linux 網路協議棧開發基礎—— 使用wireshark分析TCP/IP協議中TCP包頭的格式

摘要: 本文簡單介紹了TCP面向連線理論知識,詳細講述了TCP報文各個欄位含義,並從Wireshark俘獲分組中選取TCP連線建立相關報文段進行分析。 一、概述 TCP是面向連線的可靠傳輸協議,兩個程序互發資料之前需要建立連線,這裡的連線只不過是端系統中分配的一些快

Spring Boot:Spring Boot使用單元測試

前言這次來介紹下Spring Boot中對單元測試的整合使用,本篇會通過以下4點來介紹,基本滿足日常需求Service層單元測試Controller層單元測試新斷言assertThat使用單元測試的回滾正文Spring Boot中引入單元測試很簡單,依賴如下:1 2 3 4

Spring Boot 入門:報表匯出,對比poi、jxl和esayExcel的效率

本片部落格是緊接著Spring Boot 入門(十一):整合 WebSocket, 實時顯示系統日誌寫的 關於poi、jxl和esayExcel的介紹自行百度。 jxl最多支援03版excel,所以單個sheet頁面最多隻能匯出65536條資料。 我直接將excel匯入到瀏覽器並開啟,以下統計匯出時長指將資

spring-boot-route整合redis做為快取

## redis簡介 redis作為一種非關係型資料庫,讀寫非常快,應用十分廣泛,它採用key-value的形式儲存資料,value常用的五大資料型別有string(字串),list(連結串列),set(集合),zset(有序集合)和hash(雜湊表)。 redis的特性決定了它的功能,它可以用來做以下這

python學習筆記異常處理

關鍵字 .exe strip support 異常 解析器 輸入 rod () python解析器去執行程序,檢測到了一個錯誤時,觸發異常,異常觸發後且沒被處理的情況下,程序就在當前異常處終止,後面的代碼不會運行,所以你必須提供一種異常處理機制來增強你程序的健壯性與容錯性

C++語言學習——異常處理

right data ges cal 修飾符 當前 ins 最終 cati C++語言學習(十八)——異常處理 一、C語言異常處理 異常是指程序在運行過程中產生可預料的執行分支。如除0操作,數組訪問越界、要打開的文件不存在。Bug是指程序中的錯誤,是不被預期的運行方式。如野

分享知識-快樂自己:Spring中的三種異常處理機制

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSch

springMvc 處理圖片,視訊等檔案的上傳

導包 需要匯入如下的包 commons-fileupload-1.3.3.jar commons-io-2.6.jar 修改表單型別 想要上傳圖片、文字、電影、音樂等資源的時候,需要將 form 的

EMV規範學習與研究——指令碼處理

指令碼處理目的是髮卡行可以提供命令指令碼讓終端傳送給IC卡,這些命令執行的功能對當前交易沒有影響,但是對確保IC卡中後續的正常執行非常重要。在一個授權應答中又可能包括多個指令碼,每個指令碼包括多個髮卡行指令碼命令。 終端可能不能理解某個髮卡行指令碼命令,但是終端需要把每個指

Spring.NET教程整合NHibernate和ASP.NET MVC(基礎)

contains sar occurs false port company param soft stat 今天帶給大家的就是期待以久的ASP.net MVC與Spring.NET和NHibernate的組合,視圖打造.NET版的SSH(Spring-Struts-Hib

spring cloud微服務快速教程之 分散式ID解決方案mybatis-plus

0-前言   分散式系統中,分散式ID是個必須解決的問題點;   雪花演算法是個好方式,不過不能直接使用,因為如果直接使用的話,需要配置每個例項workerId和datacenterId,在微服務中,例項一般動態配置,直接指定具體例項的這兩個引數是不現實的;   所以,一般採用雪花演算法的變種,主要是將這兩個

學習MVC之租房網站-緩存和靜態頁面

.html 控制臺 ron 在線教育 適合 取代 system caching 租房網站 在上一篇<學習MVC之租房網站(十一)-定時任務和雲存儲>學習了Quartz的使用、發郵件,並將通過UEditor上傳的圖片保存到雲存儲。在項目的最後,再學習優化網站性能的

CoreThink開發更改默認出錯異常頁防止暴露敏感數據

highlight true pos pub light brush 關閉 sql exception 默認的異常頁會打印文件位置,而且是絕對路徑,會打印SQL語句,真實上線一定不要用這個默認的,而且關閉trace關閉調試模式也不行。 針對CoreThink1.2 Th

SpringMVC自定義異常處理器 HandlerExceptionResolver接口

pin org ota admin pack property framework ase exception 自定義異常處理器和系統異常處理器的提升版可以實現相同的功能,但是使用的方法不同,自定義異常處理器可以不用在配置文件中配置name多東西,只需要一個異常處理器就可以