【SpringBoot】使用扫盲

438 阅读2分钟
这篇文章会记录一些SpringBoot中常用的知识/技巧。

这些知识或技巧并不高深,但如果没有接触过,工作进度常常会受阻,明明一个很简单的问题,却花了许久才解决。

本文不定期更新。

自定义拦截器(拦截HTTP请求)

使用场景:拦截http请求,在请求前后自定义处理内容。

核心类:HandlerInterceptor,WebMvcConfigurer

HandlerInterceptor,包含三个方法:

  • preHandle 目标方法执行前执行
  • postHandle 目标方法执行后执行
  • afterCompletion 请求完成时执行

核心步骤: 第一步, 自定义拦截处理逻辑:实现HandlerInterceptor接口。

public class MyHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 自定义逻辑
        return true;
    }
}

第二步,注册拦截器,使其能够作用于controller方法

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        HandlerInterceptor handlerInterceptor = new MyHandlerInterceptor();
        // 注册拦截器
        InterceptorRegistration simLoginRegistration = registry.addInterceptor(handlerInterceptor);
        // 设置优先级
        simLoginRegistration.order(10);
    }
}

自此,在请求接口时spring mvc通过该拦截器,能够自动拦截该接口。

获取Spring容器对象

使用场景:从Spring容器中获取Bean

获取Bean对象方式:

  • BeanFactoryAware接口
  • ApplicationContextAware接口

BeanFactoryAware

@Service
public class BeanUtils implements BeanFactoryAware {
    private static BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public static <T> T getBean(String name) {
        return (T) BeanUtils.beanFactory.getBean(name);
    }
}

ApplicationContextAware

@Service
public class SpringUtils implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    public static <T> T getBean(String name) {
        return (T) SpringUtils.applicationContext.getBean(name);
    }
}

自定义接口参数类型转换

使用场景:接口中接收参数的实体对象中,有个字段的类型是Date,但是实际传参的是字符串类型:2021-01-03 10:20:15

核心 : 自定义注解 + HandlerMethodArgumentResolver + WebMvcConfigurer

第一步,自定义注解

import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DateParam {
    public String name() default "";
}

第二步,实现**HandlerMethodArgumentResolver接口**


import com.pinduoduo.teochew.common.anno.DateParam;
import com.pinpinxiaozhan.service.base.utils.DateTimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.util.Date;

@Slf4j
public class MyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(DateParam.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        DateParam dateParam = parameter.getParameterAnnotation(DateParam.class);
        String name = dateParam.name();
        if ("".equals(name)) {
            name = parameter.getParameter().getName();
        }
        String tmp = webRequest.getParameter(name);
        Date res = DateTimeUtils.parse(tmp, DateTimeUtils.SHORT_DISPLAY_PATTERN);
        log.info("resolveArgument tmp {} res {}", tmp, DateTimeUtils.format(res, DateTimeUtils.SHORT_DISPLAY_PATTERN));
        return res;
    }
}

第三步,注册自定义的解析器

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new MyHandlerMethodArgumentResolver());
    }
}

第四步,通过注解使用自定义解析器

@GetMapping(value = "/test")
    @ApiOperation("测试")
    public BaseResponse<Boolean> test(@DateParam(name = "date") Date request) {
        String userName = UserBasicInfoContext.getUserBasicInfo().getUserName();
        log.info("PushController bindUserAndClient request is {} userName is {}", JsonUtils.toJson(request), userName);
        return BaseResponse.ofSuccess(true);
    }

自定义异常处理

使用场景:自定义controller全局异常处理,用于优化返回给前端的错误信息。

核心:@RestControllerAdvice + @ExceptionHandler

@RestController
@Slf4j
@Order(0)
public class MyControllerAdvice {
    @Autowired(required = false)
    private HttpServletRequest req;

    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public BaseResponse<Object> handleBusinessException(BusinessException exception) {
        req.setAttribute(CatConstants.CAT_STATE, exception.getClass().getName());
        log.error("Handling business exception", exception);
        return BaseResponse
                .fail()
                .errorCode(exception.getCode())
                .errorMsg(exception.getMessage())
                .build();
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public BaseResponse<Object> handleValidException(Exception e, @Autowired HttpServletRequest request) {
        ConstraintViolationException mae = (ConstraintViolationException) e;
        request.setAttribute(CatConstants.CAT_STATE, mae.getClass().getName());
        String errorMsg = mae.getConstraintViolations().isEmpty() ?
                "invalid params" : Lists.newArrayList(mae.getConstraintViolations()).get(0).getMessage();
        log.warn("handleValidException request not valid {}", errorMsg);
        return BaseResponse.ofFail(ErrorCode.BAD_PARAMS.getCode(), errorMsg);
    }

}