一、springMVC全局异常有点
若有很多异常没有被包装,那么我们项目的类,包名,sql语句,数据库ip等关键信息都会暴露。
二、spring以及springMVC包扫描进行隔离。
1.springMVC应该扫描controller,spring扫描其他bean
2.coding:
spring配置文件:排除controller注解 springMVC配置文件:关闭默认扫描,只扫描controller注解 |
三、使用@Component注解
1.默认控制层用@controller,服务层用@service,Dao层用@Repository,其他一律使用@Component。
四、ModelAndView
不在作用于服务器转发就是跳转页面,使之返回Json对象,对异常进行重写包装。
五、SpringMVC全局异常流程图
包装的异常即ModelAndView对象。
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.json.MappingJackson2JsonView; @Component public class ExceptionResolver implements HandlerExceptionResolver{ private static final Logger log = LoggerFactory.getLogger(ExceptionResolver.class); public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { //使用日志打印出异常 log.error("{} Exception",httpServletRequest.getRequestURI(),e); //使用jackson封装异常 ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView()); //使用jackson2.x的时候使用MappingJackson2JsonView,目前使用的是1.9。 modelAndView.addObject("status",ResponseCode.ERROR.getCode()); modelAndView.addObject("msg","接口异常,详情请查看服务端日志的异常信息"); modelAndView.addObject("data",e.toString()); return modelAndView; } } |
六、springMVC拦截器流程图
1.拦截器配置
/**表示所有路径及其子路径
/* 表示当前路径,但不包括子路径
/web项目的根目录请求
|
2.拦截器执行流程
3.重置HttpServletResponse
4.解决拦截登陆循环问题
七、HandlerInterceptor(preHandler(),postHandler(),afterHandler())
PreHandler返回false那么不进入Controller,直接返回。返回true,跳到postHandler,最后调到afterHandler。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("preHandle"); //请求中Controller中的方法名 HandlerMethod handlerMethod = (HandlerMethod)handler; //解析HandlerMethod String methodName = handlerMethod.getMethod().getName(); String className = handlerMethod.getBean().getClass().getSimpleName(); //解析参数,具体的参数key以及value是什么,我们打印日志 StringBuffer requestParamBuffer = new StringBuffer(); Map paramMap = request.getParameterMap(); Iterator it = paramMap.entrySet().iterator(); while (it.hasNext()){ Map.Entry entry = (Map.Entry)it.next(); String mapKey = (String)entry.getKey(); String mapValue = StringUtils.EMPTY; //request这个参数的map,里面的value返回的是一个String[] Object obj = entry.getValue(); if(obj instanceof String[]){ String[] strs = (String[])obj; mapValue = Arrays.toString(strs); } requestParamBuffer.append(mapKey).append("=").append(mapValue); }
if(StringUtils.equals(className,"UserManageController") && StringUtils.equals(methodName,"login")){ log.info("权限拦截器拦截到请求,className:{},methodName:{}",className,methodName); //如果是拦截到登录请求,不打印参数,因为参数里面有密码,全部会打印到日志中,防止日志泄露 return true; } log.info("权限拦截器拦截到请求,className:{},methodName:{},param:{}",className,methodName,requestParamBuffer.toString()); User user = null; String loginToken = CookieUtil.readLoginToken(request); if(StringUtils.isNotEmpty(loginToken)){ String userJsonStr = RedisShardedPoolUtil.get(loginToken); user = JsonUtil.string2Obj(userJsonStr,User.class); } if(user == null || (user.getRole().intValue() != Const.Role.ROLE_ADMIN)){ //返回false.即不会调用controller里的方法 response.reset();//这里要添加reset,否则报异常 getWriter() has already been called for this response. response.setCharacterEncoding("UTF-8");//geelynote 这里要设置编码,否则会乱码 response.setContentType("application/json;charset=UTF-8");//geelynote 这里要设置返回值的类型,因为全部是json接口。 PrintWriter out = response.getWriter(); out.print(JsonUtil.obj2String(ServerResponse.createByErrorMessage("拦截器拦截,用户无权限操作"))); out.flush(); out.close();//geelynote 这里要关闭 return false; } return true; } |