1. 程式人生 > 實用技巧 >SpringBoot基於切面來攔截@PathVariable引數及丟擲異常全域性處理方法

SpringBoot基於切面來攔截@PathVariable引數及丟擲異常全域性處理方法

SpringBoot基於切面來攔截@PathVariable引數及丟擲異常全域性處理方法

微信小程式的介面驗證防止非法請求,登入的時候獲取openId生成一個七天有效期token存入redis中。

後續每次請求都需要把token作為引數傳給後臺介面進行驗證,為了方便使用@PathVariable 直接將引數做為路徑傳過來 不用每一次都新增param引數也方便前端介面的請求。

例如:

@ApiOperation(value = "小程式登入")
@PostMapping("/login")
public AntdResponse login(@RequestParam String username, @RequestParam String password, @RequestParam String openId) throws Exception {
    String st = wxTokenService.passport(username, password);
    //省略。。。。。
    String wxToken = IdUtil.simpleUUID();
    data.put("wxToken", wxToken);
    wxTokenService.saveWxTokenToRedis(wxToken, openId);
    return new AntdResponse().success("登入成功,登入有效期七天").data(data);
}

@ApiOperation(value = "預約訂單")
@PostMapping("/{wxToken}/addOrder")
public AntdResponse addOrder(@PathVariable String wxToken, @RequestBody ProductOrderDto productOrderDto){
    String openId = wxTokenService.getOpenIdByWxToken(wxToken);
    orderService.addOrder(openId, productOrderDto);
    return new AntdResponse().success("預約訂單成功");
}

為了方便統一驗證,基於切面來實現資料的驗證。

package cn.pconline.antd.smallshop.interceptor;

import cn.pconline.antd.common.exception.WxTokenException;
import cn.pconline.antd.smallshop.service.IWxTokenService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * @Description 微信小程式登入攔截
 * @Author jie.zhao
 * @Date 2020/10/26 18:08
 */
@Component
@Aspect
public class WxMiniInterceptor {

    @Autowired
    private IWxTokenService wxTokenService;
    
    //這裡需要把登入的請求控制器排除出去
    @Pointcut("within (cn.pconline.antd.smallshop.wxmini..*) && !within(cn.pconline.antd.smallshop.wxmini.WxMiniLoginController)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object trackInfo(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
        String wxToken = (String) pathVariables.get("wxToken");
        if (wxToken == null) {
            throw new WxTokenException("微信小程式令牌引數缺失!");
        }
        String openId = wxTokenService.getOpenIdByWxToken(wxToken);
        if (openId == null || "".equals(openId)) {
            throw new WxTokenException("登入失效,請重新登入!");
        }
        return joinPoint.proceed();
    }
}

全域性異常處理

@RestControllerAdvice
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionHandler {
    @ExceptionHandler(value = WxTokenException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public AntdResponse handleWxTokenException(WxTokenException e) {
        log.error("微信Token攔截異常資訊:", e);
        return new AntdResponse().message(e.getMessage()).code(Code.C500.getCode().toString()).status(ResponseStat.ERROR.getText());
    }
}
package cn.pconline.antd.common.exception;

/**
 * 微信授權token異常
 */
public class WxTokenException extends RuntimeException  {

    private static final long serialVersionUID = -3608667856397125671L;

    public WxTokenException(String message) {
        super(message);
    }
}

這裡需要注意的是 WxTokenException 要繼承RuntimeException而不是Exception,否則的話會報UndeclaredThrowableException。

java.lang.reflect.UndeclaredThrowableException
    at com.insigmaunited.lightai.controller.UserController$$EnhancerBySpringCGLIB$$e4eb8ece.profile(<generated>)

異常原因:
我們的異常處理類,實際是 動態代理的一個實現。
如果一個異常是檢查型異常並且沒有在動態代理的介面處宣告,那麼它將會被包裝成UndeclaredThrowableException.
而我們定義的自定義異常,被定義成了檢查型異常,導致被包裝成了UndeclaredThrowableException
java.lang.reflect.UndeclaredThrowableException的解決