Spring Boot 进阶之 Web 进阶笔记
一、表单验证
改造 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
您的鼓励是我前行最大的动力,欢迎点赞,欢迎送小星星✨ ~