黔南州住房和城乡建设局网站,设计公司注册需要什么条件,商丘网站制作电话,番禺区建设局网站统一处理异常
SpringBoot设计#xff0c;如果出现错误404或500#xff0c;自动调用特定路径下的html页面(路径和名字都特定)。/templates/error/404.html、/templates/error/500.html。程序中有错误自动就调用该页面。 但是错误有异步请求错误#xff0c;也想同时记录日志。…统一处理异常
SpringBoot设计如果出现错误404或500自动调用特定路径下的html页面(路径和名字都特定)。/templates/error/404.html、/templates/error/500.html。程序中有错误自动就调用该页面。 但是错误有异步请求错误也想同时记录日志。则使用统一处理的方式即全局配置。
ControllerAdvice 是 Spring MVC 中的一个注解用于定义全局控制器的通知advice。它允许您在整个应用程序范围内定义对控制器的异常处理、绑定属性以及其他全局控制器通知的方法。 具体来说ControllerAdvice 通常与 ExceptionHandler、InitBinder 和 ModelAttribute 注解一起使用
ExceptionHandler: 用于定义在控制器中抛出指定类型异常时的处理方法。InitBinder: 用于定义在控制器中自定义数据绑定规则的方法。ModelAttribute: 用于定义在所有请求处理方法之前执行的方法通常用于在模型中添加公共属性。
通过将 ControllerAdvice 注解添加到类上您可以在该类中定义这些通知方法并在整个应用程序中共享它们以便统一处理异常、数据绑定和模型属性。这样可以提高代码的重用性和可维护性并使全局控制器的配置更加简洁和清晰。 //手动重定向错误页面RequestMapping(path /error, method RequestMethod.GET)public String getErrorPage() {return /error/500;}// 是Controller全局配置类不用对任何Controller再做配置可以统一做Controller的全局配置。ControllerAdvice用来修饰类。
// 异常处理方案ExceptionHandler、绑定数据方案ModelAttribute、绑定参数方案DataBinder. 他们都用来修饰方法。
// 这里只演示统一处理异常ExceptionHandler
ControllerAdvice(annotations Controller.class) // 限定注解Controller,否则组件扫描所有的bean
public class ExceptionAdvice {private static final Logger logger LoggerFactory.getLogger(ExceptionAdvice.class);ExceptionHandler({Exception.class})// 处理哪些异常Exception是所有异常的父类,所有异常都处理// 有异常controller会传过来Exceptionpublic void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {// 记录日志logger.error(服务器发生异常 e.getMessage());//异常的概括for (StackTraceElement element : e.getStackTrace()) {//把异常所有栈的信息都记录下来logger.error(element.toString());}// 给浏览器响应// 要看是什么请求想要服务器返回网页html/异步请求JSON(xml).从请求的消息头获取。String xRequestedWith request.getHeader(x-requested-with);if (XMLHttpRequest.equals(xRequestedWith)) {// 异步请求response.setContentType(application/plain;charsetutf-8);PrintWriter writer response.getWriter();// 输出流writer.write(CommunityUtil.getJSONString(1,服务器异常!));// 输出JSON字符串}else{// 请求html重定向到错误页面response.sendRedirect(request.getContextPath() /error);}}
}
统一记录日志
记录日志不一定有异常。拦截器也是针对控制器的。没有对业务组件、数据访问层统一处理。
想对业务层统一记录日志而统一记录日志是系统功能不要和业务功能混在一起实现。否则在想对记录日志的位置进行改变时将会非常麻烦因为业务bean有很多个需要修改的时候得一个个改。
由此引入了AOP的方式即面向切面编程切面是一个一个组件。业务Bean是一个一个target。我们要先声明切点的位置再通知要做什么事。只需要对切面组件编程即可不需要再进到业务Bean中去改提升了编程效率。 Aspect切面
注解Component Aspect声明切点的位置Pointcut(切点的位置返回值 包.类.方法.参数) pointcut()通知具体逻辑5个注解Before After AfterReturning AfterThrowing Around Target: 是业务Bean AOP实现有两种 AspectJ 和 Spring AOP。一般用后者即可。它是运行时织入通过代理的方式只在方法处有连接点。Spring AOP面向切面编程通常通过代理的方式来实现主要有以下几个原因无侵入性 通过代理方式实现 AOP 可以避免对现有代码的侵入性。即使目标类没有实现任何接口也可以通过 Spring AOP实现切面功能。动态性 代理方式允许在运行时动态地应用切面。这意味着可以在运行时决定是否应用切面以及如何应用切面而无需在编译时硬编码切面逻辑。单一职责原则 通过代理方式实现 AOP可以使目标类专注于自身的业务逻辑而将横切关注点如日志记录、事务管理等从目标类中解耦出来符合单一职责原则。多个切面组合代理方式允许将多个切面组合应用于目标类而无需修改目标类的代码。这种灵活性使得可以根据需求组合不同的切面实现更加复杂的功能。易于管理 通过代理方式实现的切面可以集中管理例如在配置文件中声明切面和通知的关系而无需在每个目标类中显式地声明切面逻辑。
统一记录日志示例
Component
Aspect
public class ServiceLogAspect {private static final Logger logger LoggerFactory.getLogger(ServiceLogAspect.class);Pointcut(execution(* com.nowcoder.community.service.*.*(..)))public void pointcut() {}Before(pointcut())public void before(JoinPoint joinPoint) {// 参数连接点// 用户[1.2.3.4],在[xxx],访问了[com.nowcoder.community.service.xxx()].ServletRequestAttributes attributes (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request attributes.getRequest();String ip request.getRemoteHost();String now new SimpleDateFormat(yyyy-MM-dd HH:mm:ss).format(new Date());String target joinPoint.getSignature().getDeclaringTypeName() . joinPoint.getSignature().getName();// 得到该连接点的类名和方法名logger.info(String.format(用户[%s],在[%s],访问了[%s]., ip, now, target));}After(pointcut())public void after() {System.out.println(after);}AfterReturning(pointcut())public void afterRetuning() {System.out.println(afterRetuning);}AfterThrowing(pointcut())public void afterThrowing() {System.out.println(afterThrowing);}Around(pointcut())public Object around(ProceedingJoinPoint joinPoint) throws Throwable {// 参数连接点System.out.println(around before);Object obj joinPoint.proceed();// 连接点调用目标组件的方法返回目标组件的返回值System.out.println(around after);return obj;}
}