Spring MVC 爲控制器添加通知與處理異常

  與Spring AOP同樣,Spring MVC也可以給控制器加入通知,它主要涉及4個註解:
  •@ControllerAdvice,主要做用於類,用以標識全局性的控制器的攔截器,它將應用於對應的控制器。
  •@InitBinder,是一個容許構建POJO參數的方法,容許在構造控制器參數的時候,加入必定的自定義控制。
  •@ExceptionHandler,經過它能夠註冊一個控制器異常,使用當控制器發生註冊異常時,就會跳轉到該方法上。
  •@ModelAttribute,是一種針對於數據模型的註解,它先於控制器方法運行,當標註方法返回對象時,它會保存到數據模型中。java

  代碼清單16-19:控制器通知web

package com.ssm.chapter15.controller.advice;

//標識控制器通知,而且指定對應的包

import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;

import java.text.SimpleDateFormat;
import java.util.Date;

@ControllerAdvice(basePackages = {"com.ssm.chapter15.controller.advice"})
public class CommonControllerAdvice {

    //定義HTTP對應參數處理規則
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        //針對日期類型的格式化,其中CustomDateEditor是客戶自定義編輯器
        // 它的boolean參數表示是否容許爲空
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), false));
    }

    //處理數據模型,若是返回對象,則該對象會保存在
    @ModelAttribute
    public void populateModel(Model model) {
        model.addAttribute("projectName", "chapter15");
    }

    //異常處理,使得被攔截的控制器方法發生異常時,都能用相同的視圖響應
    @ExceptionHandler(Exception.class)
    public String exception() {
        return "exception";
    }
}

 


  代碼清單16-20:測試控制器通知spring

package com.ssm.chapter15.controller.advice;

import org.apache.http.client.utils.DateUtils;
import org.springframework.format.annotation.NumberFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/advice")
public class MyAdviceController {

    /**
     * http://localhost:8081/advice/test.do?date=2017-06-23%2018:12:00&amount=123,456.78
     * @param date  日期,在@initBinder 綁定的方法有註冊格式
     * @param model 數據模型,@ModelAttribute方法會先於請求方法運行
     * @return map
     */
    @RequestMapping("/test")
    @ResponseBody
    public Map<String, Object> testAdvice(Date date, @NumberFormat(pattern = "##,###.00") BigDecimal amount, Model model) {
        Map<String, Object> map = new HashMap<String, Object>();
        //因爲@ModelAttribute註解的通知會在控制器方法前運行,因此這樣也會取到數據
        map.put("project_name", model.asMap().get("projectName"));
        // map.put("date", DateUtils.format(date, "yyyy-MM-dd"));
        map.put("date", DateUtils.formatDate(date, "yyyy-MM-dd"));
        map.put("amount", amount);
        return map;
    }

    /**
     * 測試異常.
     */
    @RequestMapping("/exception")
    public void exception() {
        throw new RuntimeException("測試異常跳轉");
    }
}

 

  控制器(註解@Controller)也可使用@Init-Binder、@ExceptionHandler、@ModelAttribute。注意,它只對於當前控制器有效數據庫

  代碼清單16-21:測試@ModelAttributeapache

package com.ssm.chapter15.controller;

import com.ssm.chapter15.pojo.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(value = "/role2")
public class Role2Controller {

    // @Autowired
    // private RoleService roleService = null;

    /**
     * 在進入控制器方法前運行,先從數據庫中查詢角色,而後以鍵role保存角色對象到數據模型
     *
     * @param id 角色編號
     * @return 角色
     */
    @ModelAttribute("role")
    public Role initRole(@RequestParam(value = "id", required = false) Long id) {
        //判斷id是否爲空
        if (id == null || id < 1) {
            return null;
        }
        // Role role = roleService.getRole(id);
        Role role = new Role(id, "射手", "遠程物理輸出");
        return role;
    }

    /**
     * http://localhost:8081/role2/getRoleFromModelAttribute.do?id=1
     *
     * @param role 從數據模型中取出的角色對象
     * @return 角色對象
     * @ModelAttribute 註解從數據模型中取出數據
     */
    @RequestMapping(value = "getRoleFromModelAttribute")
    @ResponseBody
    public Role getRoleFromModelAttribute(@ModelAttribute("role") Role role) {
        return role;
    }
}

 



  表16-2中只列舉了一些異常映射碼,而實際上會更多,關於它的定義能夠看源碼的枚舉類org.springframework.http.HttpStatus

  代碼清單16-22:自定義異常
package com.ssm.chapter15.exception;

//新增Spring MVC的異常映射,code表明異常映射碼,而reason則表明異常緣由

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "找不到角色信息異常!!")
public class RoleException extends RuntimeException {

    private static final long serialVersionUID = 5040949196309781680L;
    
}

 


  經過註解@ResponseStatus的配置code能夠映射SpringMVC的異常碼,而經過配置reason能夠了解配置產生異常的緣由。既然定義了異常,那麼咱們可能就須要使用異常。在大部分狀況下,可使用Java所提供的try...catch...finally語句處理異常。Spring MVC也提供了處理異常的方式。
  代碼清單16-23:使用RoleException異常
package com.ssm.chapter15.controller;

import com.ssm.chapter15.exception.RoleException;
import com.ssm.chapter15.pojo.Role;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping(value = "/roleE")
public class RoleExceptionController {

    /**
     * http://localhost:8081/roleE/notFound.do?id=1
     *
     * @param id
     * @return
     */
    @RequestMapping("notFound")
    @ResponseBody
    public Role notFound(Long id) {
        // Role role = roleService.getRole(id);
        Role role = new Role(id, "射手", "遠程物理輸出");
        role = null;
        //找不到角色信息拋出RoleException
        if (role == null) {
            throw new RoleException();
        }
        return role;
    }

    //當前控制器發生RoleException異常時,進入該方法
    @ExceptionHandler(RoleException.class)
    public String HandleRoleException(RoleException e) {
        //返回指定的頁面,避免不友好
        return "exception";
    }
}
相關文章
相關標籤/搜索