@ControllerAdvice

注解介绍

以下是@ControllerAdvice的源码

package org.springframework.web.bind.annotation;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
	
    //指定一个或多个包的基本路径。@ControllerAdvice将应用于这些基本路径下的所有控制器类。	
    //另外注意参数名为basePackages,因为别名注解@AliasFor。
	@AliasFor("basePackages")
	String[] value() default {};
	
	//指定一个或多个包的基本路径。@ControllerAdvice将应用于这些基本路径下的所有控制器类。
    //另外注意参数名为value,因为别名注解@AliasFor。
	@AliasFor("value")
	String[] basePackages() default {};
    
    //value与basePackages作用一致,都是指定包,以下几种写法作用一致,都是指定处理com.example.controller包下的控制器
		//@ControllerAdvice(value = {"com.example.controller"}) //可以指定多个包
		//@ControllerAdvice(value = "com.example.controller")
		//@ControllerAdvice("com.example.controller")
		//@ControllerAdvice(basePackages = {"com.example.controller"}) //可以指定多个包
    
    
    /******************************************************************************************/
    

	//指定一个或多个类,参数是*.class。 @ControllerAdvice将应用于这些类所在的包的所有控制器。
    //比如  @ControllerAdvice(basePackageClasses = DemoController.class)
	Class<?>[] basePackageClasses() default {};

	//指定一个或多个控制器接口或父类,参数是*.class。 @ControllerAdvice将应用于这些接口或父类的所有实现类或子类。
	Class<?>[] assignableTypes() default {};

	//指定一个或多个注解类,参数是*.class。 @ControllerAdvice将应用于带有这些注解的控制器类。
	Class<? extends Annotation>[] annotations() default {};

}

全局异常处理

Controller

Controller中抛一个异常,异常亦可以是在Controller调用的Service或其他地方抛出,只要被Controller调用即可,但是不能被内部捕获处理,否则ControllerAdvice就不会处理了

import com.example.exception.CustomException;
import org.springframework.web.bind.annotation.*;

@RestController//如果没有@ResponseBody,方法返回值会被视图解析器解析,无法解析就会404
@RequestMapping("/two")
public class DemoController {
    
    @RequestMapping("/d")
    public String test3(@RequestParam String d) throws CustomException {
        //这里如果是try-catch,ControllerAdvice就不会生效了
        if("0".equals(d)){
            throw new CustomException("自定义异常");
        }
        System.out.println(d);
        return d;
    }

}

自定义异常

public class CustomException extends Exception {

    public CustomException(String message) {
        super(message);
    }
}

ControllerAdvice

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(CustomException.class)
    @ResponseBody//不加此注解返回值会被视图解析器解析,无法正常返回字符串
    public String toCustomException(CustomException e) {
		//如果出现异常,就会被此类处理,然后将下面的返回值响应出去
        return "Controller报错,异常信息为: "+e.getMessage();
    }
}

image-20231028090819573

全局模型属性

用于向Model添加属性,Model的属性可以通过视图获取并展示到前端

ControllerAdvice

import com.example.controller.DemoController;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;

@ControllerAdvice(basePackageClasses = DemoController.class)
public class GlobalExceptionHandler {

    /**
     * Model参数是用于在控制器方法中添加模型属性并将它们传递给视图的对象。
     * Model参数不是从HTTP请求中获取的,而是在控制器方法被调用时由Spring MVC框架自动创建和传递的。
     * Model设置的参数,可以在视图中通过${***}获取,然后展示在thymeleaf上
     * */
    @ModelAttribute
    public void addGlobalAttributes(Model model) {
        // 定义全局的数据预处理规则
        model.addAttribute("myModel","自定义模型属性值");
        
        //下面是对应一个key多个value
        /*
        Map<String, String> map = new HashMap<String, String>();
        map.put("key1", "value1");
        map.put("key2", "value2");
        map.put("key3", "value3");
        model.addAttribute("myModel",map);
        */
        
    }
    
    /**
    	对应上面一个key多个value的另一种写法
    */
//     @ModelAttribute()//model的属性key为map,就是下面方法里的map名
//    //@ModelAttribute("myMap")  //model的属性key为自定义的myMap
//    public Map<String, String> presetParam(){
//        Map<String, String> map = new HashMap<String, String>();
//        map.put("key1", "value1");
//        map.put("key2", "value2");
//        map.put("key3", "value3");
//        return map;
//    }

}

Controller

@Controller
@RequestMapping("/two")
public class DemoController {

    @RequestMapping("/view")
    public ModelAndView test4(@RequestParam String d){
        System.out.println(d);
        
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("resultOne");
        return modelAndView;
    }
    
    //可以通过以下方式获取自定义模型属性值
    /*
    @RequestMapping("/view")
    public ModelAndView test4(@RequestParam String d,Model model){
        String e = model.getAttribute("myModel").toString();
        System.out.println("输出自定义模型属性值:"+e);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("resultOne");
        return modelAndView;
    }
    */
}

视图

记得添加thymeleaf依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
	<version>2.7.2</version> <!-- 与springboot保持一致即可 -->
</dependency>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>我的视图</title>
</head>
<body>
<h1>Hello,View</h1>
<p th:text="自定义模型属性值为+${myModel}"></p>
</body>
</html>

效果

访问

http://localhost:8081/two/view?d=123

image-20231028103814746

属性值为map时

image-20231028111116976

全局数据绑定与预处理

在请求参数进入controller前做处理,也可以用自定义参数解析器实现,这里主要是用到了WebDataBinder

org.springframework.web.bind.WebDataBinder是Spring MVC框架中的一个类,用于绑定请求参数到Java对象上。

在Web开发中,当客户端发送一个HTTP请求时,请求中通常会包含一些参数。这些参数需要绑定到Java对象中,以便在控制器方法中进行处理。

WebDataBinder的作用就是将请求参数绑定到Java对象上。它提供了一系列方法,用于配置和自定义数据绑定的规则。

下面是一些WebDataBinder的常用方法:

  • registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor):注册一个自定义的属性编辑器,用于将请求参数的字符串值转换为Java对象的属性类型。
  • registerCustomEditor(Class<?> requiredType, String field, PropertyEditor propertyEditor):注册一个自定义的属性编辑器,用于将请求参数的字符串值转换为Java对象的指定字段的属性类型。
  • setValidator(Validator validator):设置一个验证器,用于验证绑定到Java对象上的数据。
  • initBeanPropertyAccess():初始化绑定的Java对象,以便在后续的数据绑定过程中使用。

下面展示,实现将请求参数 ip:port/test?d=1 换成 ip:port/test?d=一(如果是请求体传json转对象的需求,就用自定义参数解析器吧。。。)

Controller

@Controller
@RequestMapping("/two")
public class DemoController {

    @RequestMapping("/s")
    @ResponseBody
    public String test4(@RequestParam String d){
        System.out.println(d);

        return d;
    }

}

配置

import com.example.view.DemoPropertyEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;


@ControllerAdvice
public class GlobalExceptionHandler {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        //添加一个将请求参数数字转中文的编辑器
        //比如把 ip:port/test?d=1 换成 ip:port/test?d=一
        binder.registerCustomEditor(String.class, new DemoPropertyEditor());
    }

}

自定义编辑器

import java.beans.PropertyEditorSupport;

public class DemoPropertyEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        int value = Integer.parseInt(text);
        String chineseValue = convertToChinese(value);
        setValue(chineseValue);
    }

    private String convertToChinese(int value) {
        switch (value) {
            case 1:
                return "一";
            case 2:
                return "二";
            case 3:
                return "三";
            case 4:
                return "四";
            default:
                throw new IllegalArgumentException("Invalid value: " + value);
        }
    }

}

验证

访问

http://localhost:8081/two/s?d=1

效果

image-20231028114957349

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值