一、整合freemarker模板引擎
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-freemarkerartifactId>
dependency>
############################################################
#
# 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)
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
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");
}
}
@GetMapping("/aspect")
@ResponseBody
public String aspectTest() {
return "aspect test";
}
@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());
}
@AfterReturning(returning = "obj", pointcut="log()")
public void doAfterReturn(Object obj){
logger.info("response={}", obj.toString())
}
三、全局异常处理
@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;
}
}
@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;
}
}
@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;
}
}
// 全局捕获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()) );
}
}
@GetMapping("/exception")
@ResponseBody
public String exceptionTest() throws Exception {
throw new B2CException(ResultEnum.LOGIN_FAIL);
// return "aspect test";
}
可以看到浏览器返回{"code":-1,"msg":"登录失败, 登录信息不正确"}