SpringMVC 扩展

SpringMVC 扩展

1. RESTFul 风格

RESTFul是一种基于 HTTP 和标准化设计原则的软件架构风格,用于设计和实现可靠、可扩展和易于集成的 Web 服务和应用程序。

要求:

  • 每一个URI 代表一种资源,是名词,也就是 url中不要带动作

  • 客户端使用 GET、POST、PUT、DELETE 表示操作方式的动词对服务端资源进行操作,GET获取资源,进行查询操作。POST进行插入操作,PUT进行更新操作,DELETE 进行删除操作。

使用 RESTFul 风格,url可能是相同的,但是通过 请求方式的不同可以区别不同的请求

操作 传统风格 REST风格
保存 /crud/saveEmp url:/crud/emp 请求方式:POST
删除 /crud/deleteEmp?id=1 url:/crud/emp/1 请求方式:DELETE
更新 /crud/updateEmp url:/crud/emp 请求方式:PUT
查询 /crud/selectEmp?id=1 url:/crud/emp/1 请求方式:GET

 

RESTFul 并不是只能用 路径传参。在某些情况下也可以使用 param传参

当查询的是一个单一的资源,传入的是一个id值,这时候可以用 路径传参,比如根据id 查询一个用户

当查询的是一个集合资源,传入的是一个范围值,这时可以用 param传参,比如分页查询或多条件模糊查询等

而POST 和 PUT 用 请求体传参即可,即json数据

 

2. 全局异常处理

当出现异常时,有两种解决方案:

  • 编程式异常处理:在业务逻辑代码中显示地进行异常处理,用try catch

  • 声明式异常处理:将业务逻辑代码与异常处理分离,通过配置进行统一的管理,互不干扰

 

步骤:

  1. 声明异常处理控制器类

    定义一个类,在类上使用 @ControllerAdvice 或 @RestControllerAdvice 注解,捕捉全局异常

  2. 在这个类中,声明异常处理handler方法,通过 @ExceptionHandler 注解指定相应的异常

当出现异常时,就会走对应的handler方法

@ControllerAdvice 和 @RestControllerAdvice 的区别是:前者可以返回视图,可以重定向和转发。后者返回字符串

@RestController
@RequestMapping("exception")
public class ExceptionController {
    @GetMapping("data")
    public String data(){
        String name = null;
        name.toString();
        return name;
    }
}

上面会出现空指针异常

@RestControllerAdvice
public class GlobalExceptionHandler {
​
    @ExceptionHandler(NullPointerException.class)
    public Object NullPointerException(NullPointerException e){
        return e.getMessage();
    }
}

定义了一个全局异常处理类,里面通过 @ExceptionHandler 指定了 如果出现 NullPointerException异常就会走下面的方法,在该方法中处理异常即可。

注意:需要保证 @RestControllerAdvice 被扫描到

 

3. 拦截器

拦截器可以在执行handler 之前和之后或者在DispatcherServlet返回时执行一些代码,加上一些功能,如登录校验等。和Filter功能类似。

拦截器和过滤器的区别:

相似点:

  • 拦截:必须把请求拦住,才能执行后续操作

  • 过滤:拦截器或过滤器存在的意义就是对请求进行统一处理

  • 放行:对请求执行了必要操作后,放请求过去,让它访问原本想要访问的资源

不同点:

  • 工作平台不同

    • 过滤器工作在Servlet容器中

    • 拦截器工作在SpringMVC 的基础上

  • 拦截的范围

    • 过滤器能够拦截到的最大范围是整个web应用

    • 拦截器能够拦截到的最大范围是整个SpringMVC 负责的请求

  • IOC 容器支持

    • 想得到过滤器ioc容器需要调用专门的工具方法,spring并没有支持

    • 拦截器就放在ioc容器中,可以直接从ioc容器中装配组件,可以直接得到ioc容器的支持

使用

  1. 创建一个类,实现 HandlerInterceptor 接口,重写三个方法

    • preHandler 在处理请求的目标Handler方法之前执行,返回true就是放行,返回false拦截

    • postHandler 在目标handler方法之后执行,如果handler报错则不执行

    • afterCompletion 渲染视图后执行(在最后)一定执行

  2. 将拦截器加入到 ioc容器中

    在配置类里重写 addInterceptor 方法,调用 参数 InterceptorRegistry的 registry方法,传入的参数是 new

    拦截器类

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }
​
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
​
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

参数:request 请求对象、response 响应对象、handler 调用的对象方法、modelAndView 返回的视图和共享域对象、Exception 异常对象

 

@Configuration
@ComponentScan({"com.ztone.controller","com.ztone.error"})
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
​
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor());
    }
}

必须继承 WebMvcConfigurer

上面这种方式是拦截了所有的请求,如果想要拦截指定请求可以追加调用 addPathPatterns

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/data");
}

也可以排除拦截某些请求,调用 excludePathPatterns

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new MyInterceptor())
            .addPathPatterns("/user/**").excludePathPatterns("/user/data");
}

 

如果有多个拦截器,那么先声明的拦截器优先级高,优先级高的在外层,也就是 优先级高的拦截器先执行 preHandler,后执行 postHandler 和 afterCompletion

 

4.参数校验注解

jsr303 是Java为Bean数据合法性校验提供的标准框架

注解 规则
@Null 标注值必须为null
@NotNull 标注值不可null
@AssertTrue 标注值必须为true
@AssertFalse 标注值必须为false
@Max(value) 标注值必须小于等于value
@Min(value) 标注值必须大于等于value
@DecimalMin(value) 标注值必须大于等于value
@DecimalMax(value) 标注值必须小于等于value
@Size(max,min) 标注值必须在max和min范围内
@Digits(integer,fratction) 标注值必须是数字,并且在可接受的范围内
@Past 标注值只能用于日期型,且必须是过去的日期
@Future 标注值只能用于日期型,且必须是未来的日期
@Pattern(value) 标注值必须符合指定的正则表达式
@Email 标注值必须是格式正确的Email
@Length 标注值字符串大小必须在指定的范围内
@NotEmpty 标注集合长度不为空
@Range 标注值必须在指定的范围内
@NotBlank 标注值字符串不为null,且不是空字符串

 

使用:

  1. 需要导入依赖

    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>8.0.0.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>8.0.0.Final</version>
    </dependency>
  2. 在实体类的属性上使用注解

    @Data
    public class User {
    ​
        @NotBlank
        private String name;
    ​
        @Length(min = 6, max = 12)
        private String password;
    ​
        @Min(0)
        private int age;
    }
  3. 在接收参数的地方使用 @Validated

    @Controller
    public class UserController {
    
        @GetMapping("data")
        public String data(@Validated @RequestBody User user){
            return null;
        }
    }

当传来的参数没有通过校验,那么就会直接向前端报异常

如果想要自定义向前端的输出,可以在参数的后面紧挨着一个 参数 BindingResult

在handler中调用 该对象的 hasErrors方法,一旦报错就会返回 true

@Controller
public class UserController {

    @GetMapping("data")
    public String data(@Validated @RequestBody User user, BindingResult bindingResult){
        if (bindingResult.hasErrors()) {
            //处理向前端的返回数据
        }
        return null;
    }
}
posted @ 2024-08-17 16:32  GrowthRoad  阅读(13)  评论(0编辑  收藏  举报