SpringMVC[6]--异常处理

Web项目上线或运行时往往会出现一些不可预料的异常信息,对于开发人员可以通过日志来查看逻辑性或设计性的问题,而对于用户,需要呈现出可以理解的异常提示界面。

全局异常处理器

异常的分类:

  • 预期异常:通过捕获异常来获取异常信息。
  • 运行时异常:主要通过规范代码的开发、测试,通过一些技术手段来减少运行时异常的发生。

以下代码示例,内容接上篇文章:SpringMVC[5]--Validation校验

1. 自定义异常类UserException

以User类的异常为例,定义一个专门处理User相关操作跑步的异常的自定义异常类。

package cn.com.mvc.exception;

public class UserException extends Exception {
    //异常信息
    private String message;
    public UserException(String message){
        super();
        this.message = message;
    }
    @Override
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

上面通过UserException的构造方法设置异常信息,通过其getMessage()获取其异常信息。

2. 定义全局异常处理器UserExceptionResolver

其实现的主要功能:

  1. 解析异常类型,判断异常属于哪种异常类。
  2. 如果是系统自定义的异常,则直接取出异常信息,并在错误页面展示。如果不是系统自定义的异常,构造一个自定义的异常类型,信息为“未知错误”。
  3. 构建异常信息展示信息,将异常信息绑定到异常界面的Model域中,然后跳转到相关的异常信息显示页面。

创建全局异常处理器UserExceptionResolver,即该核心异常处理器专门用于处理系统中所有有关User的异常,去实现HandlerExceptionResolver接口。

package cn.com.mvc.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 UserExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) {
        //1.解析出异常类型
        UserException userException = null;
        if(ex instanceof UserException){
            //2. 如果该异常类型是系统自定义的类型,直接取出异常信息,在错误页面展示
            userException = (UserException)ex;
        } else {
            //3. 如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为"未知错误")
            userException = new UserException("未知错误!");
        }
        //错误信息
        String message = userException.getMessage();
        ModelAndView modelAndView = new ModelAndView();
        //将错误信息传到页面
        modelAndView.addObject("message",message);
        //只指向错误页面
        modelAndView.setViewName("/errorPage/userError");
        return modelAndView;
    }
}
3. 编写前端异常界面userError.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>提示</title>
</head>
<body>
    <h1>抱歉,访问异常,错误信息如下:</h1>
    <h2><font color="red">${message}</font></h2>
</body>
</html>
4. 在Controller类中进行判定和抛出
package cn.com.mvc.controller;

import cn.com.mvc.exception.UserException;
import cn.com.mvc.model.User;
import cn.com.mvc.validator.UserValidator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.validation.Valid;
import java.util.List;

@Controller
@RequestMapping("user")
public class UserControllerTest {
    @InitBinder
    public void initBinder(DataBinder binder){
        binder.setValidator(new UserValidator());
    }
    @RequestMapping("toLogin")
    public String toLoginPage(){
        //跳转至登录页面
        return "/user/login";
    }
    @RequestMapping("login")
    public String login(Model model, @Valid User user, BindingResult result) throws UserException{
        //登录检测
        List<ObjectError> allErrors = null;
        if(result.hasErrors()){
            allErrors = result.getAllErrors();
            for (ObjectError objectError : allErrors){
                //输出错误信息
                System.out.println("code="+objectError.getCode()+" DefaultMessage="+objectError.getDefaultMessage());
                //将错误信息传到页面
                model.addAttribute("allErrors",allErrors);
            }
            return "/user/login";
        } else {
            //其他的业务逻辑
        }
        //异常判断代码
        //查询用户是否为黑用户
        boolean isBlackUser = checkBlackList(user);
        //如果用户在黑名单中,则抛出异常,结束程序
        if(isBlackUser){
            throw new UserException("无权访问!");
        }
        return "/user/loginSuccess";
    }
    private boolean checkBlackList(User user){
        String blackArray[] = {"jack", "tom", "jean"};
        for (int i = 0; i < blackArray.length; i++){
            if (user.getUsername().equals(blackArray[i])){
                return true;
            }
        }
        return false;
    }
}
5. 检测结果

当输入如 jack用户登录时出现以下界面。


异常结果.png
6. 配置properties来防止出现硬编码
  • 新建exceptionMapping.properties
user.not.have.power=无访问权限!
  • 编写读取properties文件的辅助类
package cn.com.mvcUtil;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ExceptionPropertyUtil {
    private Properties prop;//属性集合对象
    private InputStream fis;//属性文件输入流

    private void init() throws IOException{
        prop = new Properties();
        fis = this.getClass().getResourceAsStream("/exceptionMapping.properties");
        prop.load(fis);//将属性文件流装载到Properties对象中
        fis.close();//关闭流
    }
    public String getExceptionMsg(String ExceptionCode) throws IOException{
        init();
        String msg = prop.getProperty(ExceptionCode);
        if (msg != null){
            return msg;
        }else {
            return "未定义异常!";
        }
    }
}
  • 在UserException中的getMessage方法中,在捕获异常时,使用ExceptionPropertyUtil通过约定好的代码获取相应的中文异常信息:
public String getMessage(){ 
    try{
        return new ExceptionPropertyUtil().getExceptionMsg(message);
    } catch (IOException e){
        e.printStackTrace();
    }
    return message;
}
  • 在Controller相关方法中,需要传入异常代号:
//查询用户是否为黑户名单用户
boolean isBlackUser = checkBlackList(user);
//如果在黑户名单中,抛出异常,结束程序
if(isBlackUser){
    throw new UserException("user.not.have.power");
}

这样方便以后的统一管理与编辑。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,360评论 6 343
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 写作是记日记的另一种方式,记日记是写作的开始。 写作是喜欢的结果,不是沽名钓誉的手段。 写作是情感的表现,不是为了...
    白浅墨阅读 138评论 0 1
  • 有一种美丽,叫淡到极致 于人生中,是有你如花, 于生命里,是一树花开, 此时或安静或热烈,彼刻或寂寞或璀...
    别具一格格阅读 648评论 2 3