Spring Boot 进阶之 Web 进阶笔记

2018-11-17  本文已影响0人  solocoder

一、表单验证

改造 Girl 对象,给 age 字段加校验最小值为18,并给出错误提示。

@Entity
public class Girl {

    @Id
    @GeneratedValue
    private Integer id;

    private String cupSize;

    @Min(value = 18, message = "未成年少女禁止入内")
    private Integer age;

    public Girl() {
    }
    
    //getter、setter 方法省略
}

相应的 Controller 方法,用 Girl 对象接收传递过来的参数,并加上 @Validated 注解。BindingResult 用来接收错误信息

@PostMapping(value = "/girl/add")
public Girl add(@Validated Girl girl, BindingResult bindingResult) {
    if(bindingResult.hasErrors()){
        System.out.println(bindingResult.getFieldError().getDefaultMessage());
        return null;
    }
    return repository.save(girl);
}

如果传递的 age 小于 18,则会报错。

注意:@NotNull 和 @NotEmpty 和@NotBlank 区别

@NotEmpty 用在集合类上面
@NotBlank 用在String上面
@NotNull 用在基本类型上

二、使用 AOP 处理请求

先在 pom.xml 文件中添加 AOP 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

新建 HttpAspect.java

package com.solo.test01.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class HttpAspect {

    private static final Logger logger = LoggerFactory.getLogger(HttpAspect.class);

    //指定切点
    @Pointcut("execution(public * com.solo.test01.controller.GirlController.*(..))")
    public void log() {

    }

    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {
        logger.info("doBefore-----");
        
        //获取 http 请求的内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //url
        logger.info("url: {}", request.getRequestURL());
        //method
        logger.info("method: {}", request.getMethod());
        // ip
        logger.info("ip: {}", request.getRemoteAddr());
        //方法
        logger.info("class_method: {}", joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName());
        //参数
        logger.info("params: {}", joinPoint.getArgs());
    }

    @After("log()")
    public void doAfter() {
        logger.info("doAfter-----");
    }
    
    @AfterReturning(returning = "object", pointcut = "log()")
    public void doAfterReturning(Object object){
        logger.info("response: {}", object.toString());
    }
}

@Pointcut 指定切点,在 @Before 中获取 http 请求的内容,@AfterReturning 获取返回的内容。

三、指定统一返回格式

创建 Result 对象为统一返回数据格式

public class Result<T> {
    private Integer code;
    private String msg;
    private T data;
    
    // get, set方法省略
}

封装工具类 ResultUtils


/**
 * 返回结果的工具类封装
 */
public class ResultUtils {

    public static Result success(Object obj) {
        Result result = new Result();
        result.setCode(0);
        result.setMsg("成功");
        result.setData(obj);
        return result;
    }

    public static Result success() {
        return success(null);
    }

    public static Result error(Integer code, String msg) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
}

不同状态返回相同格式的结果

@PostMapping(value = "/girl/add")
public Result<Girl> add(@Validated Girl girl, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return ResultUtils.error(1, bindingResult.getFieldError().getDefaultMessage());
    }
    return ResultUtils.success(repository.save(girl));
}

四、全局捕获异常处理

假如在 Service 中抛出了异常

@Component
public class GirlService {

    @Autowired
    GirlRepository repository;

    public void getAge(Integer id){
        Girl girl = repository.findById(id).get();
        Integer age = girl.getAge();
        if(age <= 10){
            // 还在上小学吧
            throw new GirlException(ResultEnum.PRIMARY_SCHOOL);
        }else if(age > 10 && age < 16){
            // 还在上中学吧
            throw new GirlException(ResultEnum.MIDDLE_SCHOOL);
        }
    }
}

定义一个 ExceptionHandle 来全局捕获 GirlException 异常


@ControllerAdvice
public class ExceptionHandle {

    @ExceptionHandler(value = GirlException.class)
    @ResponseBody
    public Result handle(Exception e){
        if(e instanceof GirlException){
            GirlException girlException = (GirlException) e;
            return ResultUtils.error(girlException.getCode(), e.getMessage());
        }
        return ResultUtils.error(-1, "未知错误");
    }
}

这样当出现指定异常时就会被全局捕获到。

GirlException 是自定义异常,代码如下:

public class GirlException extends RuntimeException {

    private Integer code;

    public GirlException() {
    }

    public GirlException(ResultEnum resultEnum) {
        super(resultEnum.getMsg());
        this.code = resultEnum.getCode();
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}

要继承 RuntimeException ,不要继承 Exception ,否则事务不会回滚。

将所有错误码和错误信息都封装到枚举类里,便于统一管理。

public enum ResultEnum {
    UNKNOWN(-1, "未知错误"),
    SUCCESS(0, "成功"),
    PRIMARY_SCHOOL(100, "还是小学生吧"),
    MIDDLE_SCHOOL(101, "是中学生吧")
    ;

    private Integer code;
    private String msg;

    ResultEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

作者正在写一个有趣的开源项目 coderiver,致力于打造全平台型全栈精品开源项目。

coderiver 中文名 河码,是一个为程序员和设计师提供项目协作的平台。无论你是前端、后端、移动端开发人员,或是设计师、产品经理,都可以在平台上发布项目,与志同道合的小伙伴一起协作完成项目。

coderiver 河码 类似程序员客栈,但主要目的是方便各细分领域人才之间技术交流,共同成长,多人协作完成项目。暂不涉及金钱交易。

计划做成包含 pc端(Vue、React)、移动H5(Vue、React)、ReactNative混合开发、Android原生、微信小程序、java后端的全平台型全栈项目,欢迎关注。

项目地址:https://github.com/cachecats/coderiver

您的鼓励是我前行最大的动力,欢迎点赞,欢迎送小星星✨ ~

上一篇下一篇

猜你喜欢

热点阅读