Унифицированная обработка springboot

При обработке сетевых запросов некоторые функции необходимо извлекать и обрабатывать единообразно, отдельно от бизнеса.

проверка входа

Вы можете использовать перехватчик Interceptor из Spring MVC для реализации интерфейса HandlerInterceptor. После реализации этого интерфейса он будет перехватывать запрос перед его отправкой контроллеру.
Реализация перехватчика делится на следующие два шага:

  • Создайте собственный перехватчик и реализуйте метод preHandle (предварительная обработка перед выполнением определенных методов) интерфейса HandlerInterceptor.
  • Добавьте пользовательский перехватчик в метод addInterceptors WebMvcConfigurer.

Мы используем сеанс как пример проверки входа, и реализация выглядит следующим образом:

package com.demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 登录拦截器
 */
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    
    

    /**
     * 为 false 则不能继续往下执行;为 true 则可以。
     */ 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        // 判断session的信息是否合法
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute("userinfo") != null) {
    
    
            return true;
        }
        log.error("当前用户没有访问权限");
        response.setStatus(401);
        return false;
    }
}

Зарегистрируйте написанный пользовательский перехватчик в контейнере через WebMvcConfigurer, чтобы перехватчик вступил в силу. Конкретный код реализации выглядит следующим образом:

package com.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyConfig implements WebMvcConfigurer {
    
    

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**") // 拦截所有请求
                .excludePathPatterns("/user/login"); // 排除不拦截的 url
    }
}

Если объект не внедряется, параметр addInterceptor() также может напрямую создать новый объект:

@Configuration // 一定不要忘记
public class MyConfig implements WebMvcConfigurer {
    
    

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") // 拦截所有请求
                .excludePathPatterns("/user/login"); // 排除不拦截的 url
    }
}

принцип

Все выполнение контроллера будет реализовано через диспетчер DispatcherServlet Spring MVC, и все методы будут выполнять метод планирования doDispatch в DispatcherServlet, Исходный код doDispatch выглядит следующим образом:

protected void doDispatch(HttpServletRequest request, HttpServletResponse
        response) throws Exception {
    
    
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
    
    
        try {
    
    
            ModelAndView mv = null;
            Object dispatchException = null;
            try {
    
    
                // ...  忽略不重要的代码
                // 调⽤预处理
                if (!mappedHandler.applyPreHandle(processedRequest, respon
                        se)) {
    
    
                    return;
                }
                // 执⾏ Controller 中的业务
                mv = ha.handle(processedRequest, response, mappedHandler.g
                        etHandler());
               // ...  忽略不重要的代码
            } catch (Exception var20) {
    
    
                dispatchException = var20;
            } catch (Throwable var21) {
    
    
                dispatchException = new NestedServletException("Handler di
                        spatch failed", var21);
            }
            this.processDispatchResult(processedRequest, response, mappedH
                    andler, mv, (Exception)dispatchException);
        } catch (Exception var22) {
    
    
            this.triggerAfterCompletion(processedRequest, response, mapped
                    Handler, var22);
        } catch (Throwable var23) {
    
    
            this.triggerAfterCompletion(processedRequest, response, mapped
                    Handler, new NestedServletException("Handler processing failed", var23));
        }
    } finally {
    
    
        if (asyncManager.isConcurrentHandlingStarted()) {
    
    
            if (mappedHandler != null) {
    
    
                mappedHandler.applyAfterConcurrentHandlingStarted(processe
                        dRequest, response);
            }
        } else if (multipartRequestParsed) {
    
    
            this.cleanupMultipart(processedRequest);
        }
    }
}

Из приведенного выше исходного кода видно, что перед началом выполнения Контроллера сначала будет вызван метод препроцессинга applyPreHandle, а исходный код реализации метода applyPreHandle выглядит следующим образом:

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    
    for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex
            = i++) {
    
    
        // 获取项⽬中使⽤的拦截器 HandlerInterceptor
        HandlerInterceptor interceptor = (HandlerInterceptor)this.intercep
        torList.get(i);
        if (!interceptor.preHandle(request, response, this.handler)) {
    
    
            this.triggerAfterCompletion(request, response, (Exception)null
            );
            return false;
        }
    }
    return true;
}

Обработка исключений

Обработка исключений во время запроса также является относительно распространенным объектом унифицированной обработки.

Унифицированная обработка исключений реализована с помощью @ControllerAdvice + @ExceptionHandler. @ControllerAdvice представляет класс уведомлений контроллера, а @ExceptionHandler — обработчик исключений.Выполнение события метода, конкретный код реализации выглядит следующим образом:

package com.demo;

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

import java.util.HashMap;

/**
 * 统一处理异常
 * 一般都需要自定义一个异常对象,这里为了简单说明只用一个map对象来说明
 */
@ControllerAdvice
public class ErrorAdive {
    
    

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public HashMap<String, Object> exceptionAdvie(Exception e) {
    
    
        HashMap<String, Object> result = new HashMap<>();
        result.put("code", "-1");
        result.put("msg", e.getMessage());
        return result;
    }

    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody
    public HashMap<String, Object> arithmeticAdvie(ArithmeticException e) {
    
    
        HashMap<String, Object> result = new HashMap<>();
        result.put("code", "-2");
        result.put("msg", e.getMessage());
        return result;
    }

}

Если в это время произойдет исключение, об ошибке не будет сообщено, и код будет продолжать выполняться, но пользовательская информация об исключении будет возвращена во внешний интерфейс!

принцип

@ControllerAdvice — это aop Spring, который отсекает все атрибуты контроллера, включая точку входа и логику, которая должна быть вплетена в аспект, и взаимодействует с @ExceptionHandler для захвата указанного типа исключения, созданного в контроллере, чтобы достичь цель различения различных типов исключений.

возвращаемая структура данных

Унифицированная структура возвращаемых данных может быть реализована с помощью интерфейса @ControllerAdvice + ResponseBodyAdvice. Конкретный код реализации выглядит следующим образом:

package com.demo;

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyA
dvice;

import java.util.HashMap;

/**
 * 统一返回数据的处理
 */
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    
    
    /**
     * 内容是否需要重写(通过此⽅法可以选择性部分控制器和⽅法进⾏重写)
     * 返回 true 表示重写
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterTyp
e) {
    
    
        return true;
    }
    /**
     * ⽅法返回之前调⽤此⽅法
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpR
                                          equest request,
                                  ServerHttpResponse response) {
    
    
        // 构造统⼀返回对象
        HashMap<String, Object> result = new HashMap<>();
        result.put("state", 1);
        result.put("msg", "");
        result.put("data", body);
        return result;
    }
}

おすすめ

転載: blog.csdn.net/h295928126/article/details/129655114