• Spring MVC 为控制器添加通知与处理异常


      与Spring AOP一样,Spring MVC也能够给控制器加入通知,它主要涉及4个注解:
      •@ControllerAdvice,主要作用于类,用以标识全局性的控制器的拦截器,它将应用于对应的控制器。
      •@InitBinder,是一个允许构建POJO参数的方法,允许在构造控制器参数的时候,加入一定的自定义控制。
      •@ExceptionHandler,通过它可以注册一个控制器异常,使用当控制器发生注册异常时,就会跳转到该方法上。
      •@ModelAttribute,是一种针对于数据模型的注解,它先于控制器方法运行,当标注方法返回对象时,它会保存到数据模型中。

      代码清单16-19:控制器通知

    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:测试控制器通知

    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:测试@ModelAttribute

    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";
        }
    }


  • 相关阅读:
    mysql 慢查询分析工具
    php+redis实现消息队列
    Mysql数据库千万级数据查询优化方案.....
    windows下安装docker详细步骤
    Git基础使用教程
    redis实现消息队列&发布/订阅模式使用
    macos上改变输入法顺序
    ssh动态转发小记
    ubuntu上runsv/runit小记
    使用libcurl下载https地址的文件
  • 原文地址:https://www.cnblogs.com/ooo0/p/11141768.html
Copyright © 2020-2023  润新知