后端项目分层一般如下:
控制层:controller
业务层:service
数据访问层:dao
下面演示在实际项目中,移除统一处理流程:
这篇文章的处理原则:controller负责异常统一处理,业务层负责把异常抛至控制层
dao层:
该层直接与数据库交互,而dao层由service调用,因此该层异常在service中处理即可
service层
业务层数据牵扯到业务处理流程,所有很容易出现异常,在方法后统一抛出一个Exception的方式。(对于某些代码明确其异常(或需自定义异常)时,可以使用try...catch来处理)
controller层
控制层来接收业务层处理的结果,当业务层出现异常且通过抛出异常的方式,那么异常会交由控制层处理,在控制层中,一旦出现异常,需要在该层处理,不能再往外抛,否则能影响服务器性能。
案例:
模拟一个service----controller流程,来处理异常,如下:
接口层:模拟一个testException方法,并在接口后抛出统一的异常Exception
package com.shuizhu.service;import java.util.Map;/*** @author 睡竹* @date 2023/3/20*/
public interface TestService {Map testException() throws Exception;
}
接口实现层:
package com.shuizhu.service.impl;import com.shuizhu.service.TestService;
import org.springframework.stereotype.Service;import java.util.LinkedHashMap;
import java.util.Map;/*** @author 睡竹* @date 2023/3/20*/
@Service
public class TestExceptionImpl implements TestService {@Overridepublic Map testException() throws Exception{//1/0 会出现异常,当出现异常时,会抛至controller层进行统一处理int i = 1/0;Map map = new LinkedHashMap();map.put("result",i);return map;}
}
package com.shuizhu.utils;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.util.HashMap;
import java.util.Map;/*** 返回数据** @author 睡竹*/
public class R extends HashMap {private static final long serialVersionUID = 1L;private static final Integer METHOD_INDEX = 1;private static final Logger logger= LogManager.getLogger();public R() {put("code", 0);put("msg", "success");}//测试获取的codepublic Integer getCode() {return (Integer) this.get("code");}public static R error() {return error(500, "未知异常,请联系管理员");}public static R error(String msg) {return error(500, msg);}public static R error(int code, String msg) {R r = new R();r.put("code", code);r.put("msg", msg);return r;}public static R errorApi(Exception e) {/** 通过getStackTrace获取controller中的方法名称 */StackTraceElement[] stackTrace = new Throwable().getStackTrace();String method = "";if (stackTrace.length > 0) {/** 获取方法名称 */method = stackTrace[METHOD_INDEX].getMethodName();}/** 把错误日志打印至控制台,按文本形式可以提高系统性能 */logger.error(method + "接口异常->",e);/*** 日志输出格式:"方法名称 接口异常-> 异常重要的信息"* 前提:接口名称需要与controller方法名称一致*/return error(method + "接口异常->" + e.getMessage());}public static R ok(String msg) {R r = new R();r.put("msg", msg);return r;}public static R ok(Map map) {R r = new R();r.putAll(map);return r;}public static R ok() {return new R();}@Overridepublic R put(String key, Object value) {super.put(key, value);return this;}
}
package com.shuizhu.controller;import com.shuizhu.service.TestService;
import com.shuizhu.utils.R;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.util.Map;/*** @author 睡竹* @date 2023/3/20*/
@RestController
public class TestController {@ResourceTestService testService;@RequestMapping("/testException")public R testException(){try {Map map = testService.testException();return R.ok(map);} catch (Exception e) {return R.errorApi(e);}}
}
接口为:http://127.0.0.1:8080/testException
接口返回了异常中的getMessage()信息,再来看控制台打印日志:
上述日志是通过logger进行日志打印输出的
下面改下代码,直接打印堆栈信息至控制台(这种方式不能出现在生产环境中):
try {Map map = testService.testException();return R.ok(map);} catch (Exception e) {e.printStackTrace();//直接打印堆栈信息,会影响性能return R.error(e.getMessage());}
可以再控制台中看到明显的区别: