SpringMVC学习:控制层(Controller)基于注解详解

文章目录

在SpringMVC中, 基于注解的控制层(Controller),客户端发送来的请求Request中的URL就映射到Controller层的一个方法,因此,在Controller层中,大多数注解都是基于这个方法的。下面就从应用于方法的各种注解进行学习。

一、URL映射Controller的方法返回值

方法的返回值,主要有四种类型

  • ModelAndView 表示返回的为数据模型和视图
  • String 表示返回的是视图
    返回值是String类型的,有三种写法,每种写法所解析的意思都是不一样的
  1. 普通字符串——>表示视图名称

  2. “forward:”+url——>转发 (这种写法:使用的是当前的Request对象,而处理此对象的JSP页面是URL 指定的页面。

  3. “redirect:”+url——>重定向(重定向,新的Request和JSP页面对象)

  • void 将请求的url作为视图名称,很少使用
  • Object 表示返回的是数据模型(一般返回的是json数据)
    在这里插入图片描述

二、SpringMVC各类注解详解

注解 解释
@Controller 将类映射为Controller层,添加到IoC容器中
@RequestMapping 配置请求映射路径,即URL
@RequestParam 表示参数来源于请求参数
@PathVariable 表示参数来源于URL
@RequestHeader 表示参数来源于请求头
@CookieValue 表示参数来源于Cookie
@RequestBody 表示参数来源于请求体
@ModelAttribute 将请求数据转换为对象
@Valid 后台校验
@InitBinder 类型转换,注册属性编辑器
@ControllerAdvice 统一异常处理,处理全局异常
@ExceptionHander 异常处理器,处理特定异常的方法
@ResponseBody 结合返回值为Object的方法使用,用来返回JSON数据
@RestController 将类映射为Controller层,默认为所有方法添加@ResponseBody注解

(一) @Controller

控制层注解,放在定义的控制层类的上面,表示的意思是此类为Controller层,可以在核心配置文件中扫描得到一个控制层Bean,里面的每个方法都是Request中URL的一个映射。
在这里插入图片描述

// TODO: 2021/7/1 基于注解的控制层,一个类中可以有许多个URL映射
@Controller
public class UserActionInation {
    // TODO: 2021/7/1 这是基于注解的映射 ,下面的注解接收的是客户端请求的URL
    @RequestMapping("/hello")
    public ModelAndView sayHello(String name){
        ModelAndView modelAndView = new ModelAndView();
        System.out.println("hello java");
        modelAndView.setViewName("hello");
        return modelAndView;
    }
}

(二) @RequestMapping

配置请求映射路径,即URL

1.基本用法

该注解可以定义在方法上,也可以定义在类上,表示层级关系
例:当想要访问controller层UserActionInation中的sayHello()方法时,他的层级关系就是contextpath/one/hello

@Controller
@RequestMapping("/one")
public class UserActionInation {
    // TODO: 2021/7/1 这是基于注解的映射 ,下面的注解接收的是客户端请求的URL
    @RequestMapping("/hello")
    public ModelAndView sayHello(String name){
        ModelAndView modelAndView = new ModelAndView();
        System.out.println("hello java");
        modelAndView.setViewName("hello");
        return modelAndView;
    }
}
<form action="${pageContext.servletContext.contextPath}/one/hello" method="post">

配置URL时以/开头和不以/开头的区别:

  • 添加时表示从项目根路径开始查找
  • 不添加时表示从当前方法所在层级开始查找
    在这里插入图片描述

2. path属性或value属性:URL的多种写法

请求映射路径有三种写法:

2.1 Ant风格(较少使用)

在这里插入图片描述

  1. 单层目录 (一个 * 表示)在这里插入图片描述
  2. 单层或多层目录(两个**号表示)
    在这里插入图片描述
  3. 表示单个字符,必须有一个字符(用 ?表示)
    在这里插入图片描述

2.2 Rest风格

  1. {变量}表示URL中的占位符,可以结合@PathVariable获取值
    在这里插入图片描述
    // TODO: 2021/7/2 Rest风格的url路径,可以从路径中得到相应的值 
    @RequestMapping(value = "/hello/{username}/{password}")
    public String showhello(@PathVariable String username, @PathVariable(value = "password") String userpassword) {
        System.out.println(username + ";" + userpassword);
        return "hello";
    }
  1. {变量:正则}表示使用正则表达式来限定值的格式
    在这里插入图片描述

    // TODO: 2021/7/2 用正则表达式限定占位符内值的格式,用{变量:正则表达式} 来确定义
    @RequestMapping(value = "/hello/{id:\\d+}/{password}")
    public String showhello(@PathVariable int id, @PathVariable(value = "password") String userpassword) {
        System.out.println(id + ";" + userpassword);
        return "hello";
    }

2.3 固定格式

有时候,我们希望通过多个URL来访问Conroller中的方法,这时个,可以用valule 或 path来确定。value和path互为别名,值为数组,可以指定多个值。
在这里插入图片描述

    @RequestMapping(path = {"/test3","/test4"})
    public String test3(){
        return "hello";
    }

3. method属性:根据请求方式访问

  • 限定请求方式:GET、POST、PUT、DELETE等。主要意思是,通过URL访问controller层方法时,一般都有POST,GET方式,如果想限定这个方法只能是POST 或 都 GET 请求的一种才能访问,这个时候,就需要限请求方式。
  • 限定请求方式也是在@RequestMapping()的参数里面,属性类型为method;
  • 如果@RequestMapping()里有多个必性,那么必须显示的调用属性;
    在这里插入图片描述
    @RequestMapping(path = "/test5",method = RequestMethod.GET)
    @GetMapping(value = "/test5")
    public String test5(){
        return "hello";
    }

    @RequestMapping(path = "/test6",method = RequestMethod.POST)
    @PostMapping(path = "/test6")
    public String test6(){
        return "hello";
    }

4. @RequestMapping的其他属性(URL的限定属性)

主要是两个属性,这两个属性可以描述为限定属性,意思是只有在URL,或者URL的请求中,只有符合条件的情况下,才能访问controller层中的方法。

  • params 限定请求参数,必须符合指定条件;
    表达的意思是,有URL路径中,URL必须包容参数,参数的限定条件就是在params属性中定义的。
    在这里插入图片描述
    @RequestMapping(path = "/test7",params = {"id","username=admin","password!=123"})
    public String test7(){
        return "hello";
    }
  • headers 限定请求的头部,必须符合指定条件
    在这里插入图片描述
    在这里插入图片描述
    @RequestMapping(path = "/test8",headers = {"Cookie","Accept-Language=zh-CN,zh;q=0.9"})
    public String test8(){
        return "hello";
    }

(三) @SessionAttributes

@SessionAttributes,
从表单提交的数据,传递给控制层方法参数对象,在没有添加@SessionAttributes注解的情况下,每提交一次页面都会产生一个新的自定义方法参数对象,如果想将一个对象贯穿整个会话的始终。那么就得使用@SessionAttributes注解,在注解上添加在方法参数上的对象名。具体用法如下:

  • 作用:将模型中指定名称的数据存储到session中

@Controller
@RequestMapping(value = "/web1")
@SessionAttributes("studentSecond")
public class ActionController {

    @RequestMapping(value = "/step2")
    public String step2(StudentSecond studentSecond, Errors errors) {
        System.out.println(studentSecond);
        return "step2";
    }

    @RequestMapping(value = "/step3")
    public String step3(StudentSecond studentSecond, Errors errors) {
        System.out.println(studentSecond.toString());
        return "step3";
    }

    @RequestMapping(value = "/step4")
    public String step4(StudentSecond studentSecond, Errors errors) {
        System.out.println(studentSecond.toString());
        return "step4";
    }

    @RequestMapping(value = "/steptel")
    public String steptel(StudentSecond studentSecond, Errors errors) {
        System.out.println(studentSecond.toString());
        return "steptel";
    }
    @RequestMapping(value = "/step5")
    public String step5(StudentSecond studentSecond, Errors errors) {
        System.out.println(studentSecond.toString());
        return "step5";
    }
}

在这里插入图片描述

三、控制层(Cotroller)方法上的注解

(一) 方法参数

控制层是一个加了@Controller注解的类,在这个类中方法的参数可以传入JavaEE组件,也有适用于方法及方法参数上的各种注解!控制层类方法参数主要有以下几种:

1. JAVAEE组件

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
   @RequestMapping("/hello")
    public void hellogood(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
    }

2. IO流

  • InputStream/OutputStream
  • Reader/Writer
  • Reader
  • Writer
    在这里插入图片描述
   @RequestMapping("/hello")
    public void hellogood(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
        // TODO: 2021/7/3 其实输入流和输出流是从request和response中获得的
        ServletInputStream inputStream = request.getInputStream();
        ServletOutputStream outputStream = response.getOutputStream();

        BufferedReader reader = request.getReader();
        PrintWriter writer = response.getWriter();
    }

    @RequestMapping("/test2")
    public void methondinputstream(InputStream is, OutputStream out) {
        // TODO: 2021/7/3 其实输入流和输出流是从request和response中获得的
    }

3.向界面传递数据

  • Model
  • Map
  • ModelMap (ModeMap包含Model的方法也包含Map的方法)
    这三者都是将数据存储到Request作用域中
    在这里插入图片描述
   @RequestMapping(value = "/good1")
    public String modleMap(Model model, Map map, ModelMap modelMap){
        model.addAttribute("name","javahello");
        map.put("salary",new Integer(2000));
        modelMap.addAttribute("age",20);
        modelMap.put("tel",201021);
        return "showinfo";
    }

4.方法参数为String类型及其他基本数据类型的注解应用

控制层用于方法上的注解,最主要的还是用在方法参数上,主要有以下几个注解:

@RequestParam

(1)方法参数没有添加注解@RequestParam及 @RequestParam中属性name的情况
  1. 表示参数来源于请求参数,默认所有参数都添加该注解,参数值来源于同名的请求 参数。在 一般情况下,控制层的方法参数中,默认都带此注解,方法参数开始都会从Request中寻找同名的参数,并将值传递给方法参数。如果添中了些注解,而参数名与请求参数名不相同时,可以在此注解中添加属性name,将Request中参数为name的值传递给方法参数。
    在这里插入图片描述

  2. 同时需要注意的时,方法参数中显式的加了@RequestParam,表名此方法参数必须从Request参数中得到值,否则就会出现错误!
    在这里插入图片描述

  @RequestMapping("/test/{id:\\d+}/*/**")
    public String showparam(@RequestParam String usrname, @PathVariable(value = "id") int age, int salary) {
        System.out.println(usrname + ";" + age + ";" + salary);
        return "hello";
    }

    @RequestMapping(value = "/test6")
    public String showother(@RequestParam(name = "username") String mygood){
        return "hello";
    }
(2)@RequestParam注解中属性requried
  1. 正在情况下,此属性一般为true,表示如果方法参数中添加了@RequestParam注解,那么方法参数就必须从Request中得到值,如果没得到的话,就会报错!
  2. 如果将requried设置为false时,表示方法参数不是必须从Request中得到值,如果Request没有值的话,值就为null,有的话,就将Request的参数传传递给方法参数。在Request得到参数值,两种方法:一是看Request是否有与方法名同名参数,有的话直接传递;二是看@RequestParam是否增加了属性namer指定的参数,有的话,就将指定参数名对应的参数值传递给方法参数。
    在这里插入图片描述
    @RequestMapping(value = "/test7")
    public String test7(@RequestParam(name = "name",required = false,defaultValue = "admin") String username){
       return "hello";
    }
(3)@RequestParam注解中属性defaultValue属性

此属性的意思是:如果在Request中没有找到参数对应的值,那么就使用该属性定义的值传递给方法参数。

@PathVariable

该注解的主要意思是从URL路径中,获得占位符{id}指定的值,占位符的讲解,在前面的章节中已经详细说过,在这里主要讲注解@PathVariable如何从URL请求路径中获得值。
在这里插入图片描述

@RequestHeader

此注解表示:将从Request中头中获取指定头名的值传递给方法参数。
在这里插入图片描述

    @RequestMapping(value = "/test9")
    public String test9(@RequestHeader(name = "User-Agent") String user, @RequestHeader(name = "Cookie") String cookie) {
        System.out.println(user + ";" + cookie + ";");
        return "hello";
    }

@CookieValue

表示参数来源于Cookie
在这里插入图片描述

    @RequestMapping(value = "/test10")
    public String test10(@CookieValue(name = "JSESSIONID") String sessionid) {
        System.out.println(sessionid);
        return "hello";
    }

@RequestBody

只有post才有请求体。
在这里插入图片描述

    @RequestMapping(value = "/test11")
    public String test11(@RequestBody String bodystr){
        System.out.println("打印请求体中的内容!!");
        System.out.println(bodystr);
        return "hello";
    }

4.方法参数为自定义类型时数据的传递

@ModelAttribute

将请求数据转换为对象。对像是根据需求自定义的类,在定义的时候,一定要注意的是:自定义类中的属性名必须和传递给他值的Request中的参数名是相同的,且都为字符串类型。

  • 自定义对象做为方法参数,如果有前面不添加@ModelAttribute,默认是添加的(隐式添加)
  • @ModelAttribute有两种用法,一种是添加在自定义方法参数前;另一种是添加在方法前,两者的含义是不同的。
  1. 添加在方法参数为自定义类前的时候,是将Request中的数据封装到自定义类对象中(参数名必须和对象的属性名相同)
  2. 添加在方法上面的时候,所执行的操作是:调用Controller层任何方法时候,都会执行添加了@ModelAttribute注解的方法,并且将方法的返回值,存储到request作用域中!

在这里插入图片描述

5.方法参数为错误参数类型

说明:Controller层方法中的错误参数的主要用途是,当方法自定义参数发生数据注入装配错误的时候,在方法中添加错误参数,可以使方法继续往下执行!

  • Errors
  • BindingResult

主用用途:

  1. 用来接受错误信息,实现服务端的数据校验。
  2. 实际开发中,既要做客户端表单校验,又要做服务端数据校验。

示例:如果表单注入到自定义到对象的数据类型不符合要求,重新跳传到注册页面!
在这里插入图片描述

 @RequestMapping(value = "/registor")
    public String loginregi(@ModelAttribute StudentImpl student, Errors errors){
        if (errors.hasErrors()) {
            System.out.println("数据装配绑定存在问题,将重返注册页面!");
            return "login";
        }
        return "hello";
    }

手动添加错误:我不们仅要判断注入的数据类型是否与自定义类中的属性数据类型一样,还要分析注入的数据的合理性,因此,在得到数据后,进行相关的判断分析,如果符合要求,就继续进行下一步操作,如果不符合要求,就向Errors中添加错误内容!
在这里插入图片描述

四、服务端数据校验

(一)简介

1.JSR303校验

  • JSR303是一个数据验证的标准规范,用于对Java Bean中的属性进行校验,称为Bean Validation
  • 提供了常用的校验注解

2.Hibernate Validator(开放源代码的对象验证器)

  • 是JSR303的一个参考实现, 并提供了扩展注解

(二)用法

1.添加JAR包

  • hibernate-validator-annotation-processor
  • hibernate-validator

注意:这个地点添加jar包时,一定要注意版本,过高的版本缺少ELManager,会报错!

        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.1.Final</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator-annotation-processor -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator-annotation-processor</artifactId>
            <version>6.0.2.Final</version>
        </dependency>

2.为参数对象添加注解

在这里插入图片描述

    @RequestMapping(value = "/test13")
    public String login2(@Valid StudentImpl student, Errors errors){
        return "hello";
    }

3.为参数对象里面的属性添加注解

(1)@Range

在对象属性中添加此校验器的话,指的是该属性的取值范围:

@Range(min = 1,max = 120,message = "年龄必须在1-120之间")
private int age;

(2)@NotEmpty

在一个对象属性中添加此校验器,指的时该对象属性不能为空
在这里插入图片描述

(3)@Pattern

正则表达式注解,指明从Request传入到方法对象属性的值必须符合正则表达式要求,否则就会报错

    @NotEmpty(message = "输入的密码不能为空") //不能为空注解,指明属性不能为空
    @Pattern(regexp = "\\w{6,10}")//正则表达式注解,表明
    private String username;

(4) @Length

指的是注入到对象属性中的数据长度必须满足对象属性上@Length()注解设定的min(最小值)和 max(最大值)

 @Length(min = 4,max = 10,message = "输入的数据不符合要求 ")

(5) @Email

从Request取得的数据注入方法自定义参数对象时,必须满足注入的数据格式是邮箱格式,如果不正确,就将错误传递给Errors。

  @Email(message = "输入的格式不正确")

在这里插入图片描述

(三)基本校验规则

1.空检查

@Null 验证对象是否为null

@NotNull 验证对象是否不为null, 无法查检长度为0的字符串

@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.

@NotEmpty 检查约束元素是否为NULL或者是EMPTY.

2.Booelan检查

@AssertTrue 验证 Boolean 对象是否为 true

@AssertFalse 验证 Boolean 对象是否为 false

3.长度检查

@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内

@Length(min=, max=) Validates that the annotated string is between min and max included.

4.日期检查

@Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期

@Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期

@Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。

5.数值检查

建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为”“,Integer为null

@Min 验证 Number 和 String 对象是否大等于指定的值

@Max 验证 Number 和 String 对象是否小等于指定的值

@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度

@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度

@Digits 验证 Number 和 String 的构成是否合法

@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。

@Range(min=, max=) 被指定的元素必须在合适的范围内

@Range(min=10000,max=50000,message=”range.bean.wage”)

@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)

@CreditCardNumber信用卡验证

@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。

@ScriptAssert(lang= ,script=, alias=)

@URL(protocol=,host=, port=,regexp=, flags=)

(四)自定义注解

有些时候jsr303为我们提供的注解并不能解决我们的需求,比如我们需要验证一个11位长度的手机号时,我们会使用这样的方式

@NotBlank
@Pattern(regexp = "^[0-9]{11}$")
private String phone;

每次我们都要为这个字段加上两个注解,还要写正则表达式,十分累赘,写一个时无所谓,当实体类过多时,而且都有这个字段时,就会十分麻烦。这时我们可以自己为这个验证写个注解,可以复用。

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {CellPhoneValid.class })// 注意点一
public @interface CellPhone {

	//下面三条属性不能乱改,可能会报错

    // 错误时信息
    String message() default "格式不正确,应该是11位";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };
}

// 继承ConstraintValidator<T,String>接口,注意点二
class CellPhoneValid implements ConstraintValidator<CellPhone,String>{
    @Override
    public void initialize(CellPhone constraintAnnotation) { //注意点三
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
		// 直接在这里面写上我们的验证逻辑即可
        return value!=null && Pattern.matches("^[0-9]{11}", value);
    }
}

五、类型转换

(一)简介

如果在一个表彰中,输入的数据是一个字符串,而在控制层的方法参数中,接收数据的是自定义对象的一个对象属性,此时,就要进行数据类型的转换!数据转换再注入的基本流程如图所示:
在这里插入图片描述
数据类型转换,就需要数据类型转换器,自定义转换器,可以从以下两个接口中来实现

  • 使用PropertyEditor
  • 使用Converter(推荐)

(二)使用PropertyEditor

从接口PropertyEditor中实现转换器类,其主要步骤如下:

1. 定义属性编辑器

从PropertyEditor实现转换器,最重要的是重定两个抽象方法

public class StringToAddressConverter extends PropertyEditorSupport {
  public StringToAddressConverter(){}

    @Override
    public String getAsText() {
      StudentAddress studentvalue = (StudentAddress) getValue();
      String country = studentvalue.getCountry();
      String city = studentvalue.getCity();
      String studentinfo = "[" + country + "-" + city + "]";
      return studentinfo;
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
      Pattern compile = Pattern.compile("\\[(.*)-(.*)\\]");
      Matcher matcher = compile.matcher(text);
      if (matcher.matches()) {
        String country = matcher.group(1);
        String city = matcher.group(2);
        StudentAddress studentAddress = new StudentAddress();
        studentAddress.setCountry(country);
        studentAddress.setCity(city);
        setValue(studentAddress);
      }
    }
}

需要注意的地主是,从表单中得到的中文数据,需要进行编码,也就是需要自定义一个字符编码过滤器,或使用自带的字符编码,具体示例代码如下:

  1. 自定义过滤器
public class FilterServletClass implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}
  1. 自带的过滤器
<filter>
        <filter-name>servletfilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>servletfilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2.注册属性编辑器

使用@InitBinder来注册属性编辑器,也就是将这个@InitBinder注解加在控制层自定义的一个方法上,这个方法必须实现参数DataBinder的实便,具体代代码如下:

 @InitBinder
    public void registorBinder(DataBinder binder){
        binder.registerCustomEditor(StudentAddress.class,new StringToAddressConverter());
    }

(三)使用Converter接口自定义转换器

1. 定义转换器,实现Converter接口

public class StringToAddressController implements Converter<String, StudentAddress> {
    @Override
    public StudentAddress convert(String s) {
        Pattern compile = Pattern.compile("\\[(.*)-(.*)\\]");
        Matcher matcher = compile.matcher(s);
        if (matcher.matches()) {
            String country = matcher.group(1);
            String city = matcher.group(2);
            StudentAddress studentAddress = new StudentAddress();
            studentAddress.setCity(country);
            studentAddress.setCountry(country);
            return studentAddress;
        }else {
            throw new RuntimeException("转换发生失败!");
        }
    }
}

2. 管理自定义转换器

实现Converter接口的自定义转换器,注册这个转换器是在核心配置文件xml 中进行部署的。

    <bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="web1.converter.StringToAddressController"/>
            </set>
        </property>
    </bean>

3. 加载应用自定义管理器

<mvc:annotation-driven conversion-service="conversionService"/>

mvc:annotation-driver 这个代码:一是会加载映射处理器Bean,适配处理器Bean,和一些自带的属性转换器,同时也可以加载自定义的转换器。

六、统一异常处理

(一)简介

对异常进行统一处理,在WEB技术中,有两种统一异常处理技术:

  • 使用web技术提供的统一异常处理
  • 使用SpringMVC提供的统一异常处理

(二)使用web技术提供的统一异常处理

  1. 在web.xml配置文件中配置错误页面信息,具体代码示例如下:
  <error-page>
        <error-code>404</error-code>
        <location>/error/404.jsp</location>
    </error-page>
  1. 定义一个错误页面的jsp,这个jsp页面命名路径必须与web.xml中部署的名字和路径一致,当出现错误页面代码信息的时候,tomcat服务器就会调用相应错误代码对应的jsp页面。

(三)使用SpringMVC提供的统一异常处理

统一异常处理,是自定义一个异常处理类,以@ControllerAdvice标此类,并在Spring容器中(个人理解为:核心控制器容器)通过扫描包的方式,将此异常处理类生产一个Bean,存放在容器中,自定义的异常处理类中,可自定义方法,并在方法上添加@ExceptionHandler注解,依据注解上定义的异常结构,来接收不同的异常处理,并可以通过return返回一个jsp面,进行视图解析。个人理解:自定义异常处理类中的异常处理方法被调用的原理应该和@ModelAttribute注解一样。只要在容器中存在异常,就会调用与此异常相关的异常处理方法。具体实现步骤如下:

  1. 定义一个异常处理类(通知),添加@ControllerAdvice

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class ExceptionAdvice {

    @ExceptionHandler(Exception.class)
    public String allException(Exception e){
        System.out.println(e.getMessage());
        return "error/exception";
    }

    @ExceptionHandler(ArithmeticException.class)
    public String AuthException(Exception e){
        System.out.println(e.getMessage());
        return "error/arithmetic";
    }

    @ExceptionHandler(NullPointerException.class)
    public String nullException(Exception e){
        System.out.println("发生了空指针异常!");
        System.out.println(e.getMessage());
        return "error/nullpage";
    }
}

  1. 定义异常处理方法,添加@ExceptionHandler
 @ExceptionHandler(Exception.class)
    public String allException(Exception e){
        System.out.println(e.getMessage());
        return "error/exception";
    }

具体代码分析图片如下:
在这里插入图片描述


版权声明:本文为weixin_51098159原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。