1. 程式人生 > >springboot(3)——整合freemarker模板、AOP統一處理、全域性異常處理

springboot(3)——整合freemarker模板、AOP統一處理、全域性異常處理

《三》、整合freemarker模板、AOP統一處理、全域性異常處理

一、整合freemarker模板引擎

  • 1、引入freemarker依賴
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
  • 2、常用配置
##################
########################################## # # freemarker 靜態資源配置 # ############################################################ # 設定ftl檔案路徑 spring.freemarker.template-loader-path=classpath:/templates # 關閉快取, 即時重新整理, 上線生產環境時需要修改了true spring.freemarker.cache=false spring.freemarker.charset=UTF-8 spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html spring.freemarker.expose-request-attributes=true spring.freemarker.expose-session-attributes=true spring.freemarker.request-context-attribute=request spring.freemarker.suffix=.ftl
  • 3、templates目錄下新建xxx.ftl字尾的模板html檔案

  • 4、註解@Controller開啟模板網頁

@RequestMapping
("/ftl") public String showFtl(ModelMap map) { return "xxx"; // 對應templates目錄下的xxx.ftl模板 }

二、AOP統一處理

AOP指面向切面程式設計, 比如在很多個請求中加某一點"面"中驗證是否登入的切入口(PointCut)
  • 1、引入aop依賴
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • 2、新建一個類HttpAspect.java切面類
@Aspect // 切面註解
@Component
public class HttpAspect {
    // 攔截TestController控制器的aspectTest方法
    @Before("execution(public * com.xxx.yyy.controller.TestController.aspectTest(..))")
    public void logBefore() {
        // 每次訪問“..../aspect”請求前會列印如下
        System.out.println("logBefore");
    }
    // 攔截TestController控制器中所有方法
    // @Before("execution(public * com.xxx.yyy.controller.TestController.*(..))")
    @After("execution(public * com.xxx.yyy.controller.TestController.aspectTest(..))")
    public void logAfter() {
        // 每次訪問“..../aspect”請求後會列印如下
        System.out.println("logAfter");
    }


    // 上面的@Before和@After重複, 可以抽出公用的PointCut切面
    // 上面的程式碼可替換為如下
    @Pointcut("execution(public * com.xxx.yyy.TestController.aspectTest(..))")
    public void log() {
    }
    @Before("log()")
    public void logBefore() {
        System.out.println("logBefore");
    }
    @After("log()")
    public void logAfter() {
        System.out.println("logAfter");
    }
}
  • 3、TestController控制器中
@GetMapping("/aspect")
@ResponseBody
public String aspectTest() {
    return "aspect test";
}
  • 4、獲取http請求頭的內容
@Before("log()")
public void doBefore(JoinPoint joinPoint) { //JoinPoint提供對連線點上可用狀態和靜態資訊的反射訪問
    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("clsss_method={}",joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
    //引數
    logger.info("args={}",joinPoint.getArgs());
}
  • 5、AOP中獲取方法返回Response內容
@AfterReturning(returning = "obj", pointcut="log()")
public void doAfterReturn(Object obj){
    logger.info("response={}", obj.toString())
}

三、全域性異常處理

  • 1、列舉用於統一管理異常的code和message
@Getter
public enum ResultEnum {
    LOGIN_FAIL(-1, "登入失敗, 登入資訊不正確"),
    LOGOUT_SUCCESS(-2, "登出成功"),
    ;
    private Integer code;
    private String message;

    ResultEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
  • 2、定義自己的繼承RuntimeException的異常類
@Getter
public class B2CException extends RuntimeException {
    private Integer code;
    public B2CException(ResultEnum resultEnum) {
        super(resultEnum.getMessage());
        this.code = resultEnum.getCode();
    }
    public B2CException(Integer code, String message) {
        super(message);
        this.code = code;
    }
}
  • 3、兩種請求的捕獲異常類:
    • 頁面跳轉形式
@ControllerAdvice
public class B2CExceptionHandler {
    public static final String IMOOC_ERROR_VIEW = "error";
    // 全域性捕獲Exception.class異常, 跳轉到error.ftl模板
    @ExceptionHandler(value = Exception.class)
    public Object errorHandler(HttpServletRequest reqest,
                               HttpServletResponse response, Exception e) throws Exception {
        e.printStackTrace(); // 列印錯誤
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", e);
        mav.addObject("url", reqest.getRequestURL());
        mav.setViewName(IMOOC_ERROR_VIEW);
        return mav;
    }
}
  • ajax形式(捕獲自定義B2CException異常)

// 全域性捕獲B2CExceptionn.class自定義的異常, json資料返回時
@ExceptionHandler(value = B2CException.class)
@ResponseBody
public ResultVO handlerB2CException(B2CException e) {
    return ResultVOUtil.error(e.getCode(), e.getMessage());
}
  • 統一返回異常的形式

    根據請求頭判斷是否是ajax請求來返回頁面還是json資料

    @ControllerAdvice
    public class B2CExceptionHandler {
        public static final String IMOOC_ERROR_VIEW = "error";
    
        @ExceptionHandler(value = Exception.class)
        public Object errorHandler(HttpServletRequest reqest,
                                   HttpServletResponse response, Exception e) throws Exception {
            e.printStackTrace();
            if (isAjax(reqest)) {
                return ResultVOUtil.error(555, e.getMessage());
            } else {
                ModelAndView mav = new ModelAndView();
                mav.addObject("exception", e);
                mav.addObject("url", reqest.getRequestURL());
                mav.setViewName(IMOOC_ERROR_VIEW);
                return mav;
            }
        }
    
        // 判斷是否是ajax請求
        private static boolean isAjax(HttpServletRequest httpRequest){
            return  (httpRequest.getHeader("X-Requested-With") != null
                    && "XMLHttpRequest"
                    .equals( httpRequest.getHeader("X-Requested-With").toString()) );
        }
    }
  • 4、使用測試
@GetMapping("/exception")
@ResponseBody
public String exceptionTest() throws Exception {
    throw new B2CException(ResultEnum.LOGIN_FAIL);
//  return "aspect test";
}

可以看到瀏覽器返回{"code":-1,"msg":"登入失敗, 登入資訊不正確"}