项目重构的一些思考与经验总结

项目重构的一些思考与经验总结(待续)

  • 项目重构的一些思考与经验总结
    • 那年那月那样的我
    • 悟性决定成长
    • 哪里让我感到蹩脚
    • 总结的处理方式
      • AOP统一处理异常并打印日志
      • AOP日志辅助
      • 统一ResultBean
      • 直接上代码

项目重构的一些思考与经验总结

要么爬过坑走过弯路,要么用脑子思考。看你如何选择?

那年那月那样的我

还依稀记得刚出道不久的自己照葫芦画瓢的写着代码,不知道为什么要这么写,更无从说这样写的好处与坏处了,从网上复制粘贴,实现了功能就不管了,这也是大部分码农干的话吧。那段时间虽然在经验上积累了一些,但是在技术上没有从心底的去领悟一些东西,没有思考,更没有尝试着去创新。吃了亏才知道改,走了弯路知道接下来的每一步都要谨慎,都要用心。

悟性决定成长

你能悟多少,你才能成长多少。跑偏了,回归正题。今年来,到这家公司没有什么新颖的技术,技术体系基本上是 ant + spring + mybaits + mysql + bootStrap + html + js。也由于我负责的这几个项目进度要求不是很紧急,所以有时间去研究项目的架构,代码优化,重构等,抛弃以前蹩脚的编程方式。

哪里让我感到蹩脚

1、每每遇到异常时,不知道是抛出还是处理,要怎么处理,没有一个很理性的认识,处理异常总是凭感觉看心情。
2、日志的打印问题,打多了不好,打少了也不好,甚至出现打了很多日志,但是出错时发现没有打印相关信息。时常看到有代码基本上有一半的篇幅是日志,很不雅观。
3、Controller层接口返回五花八门问题,这我也是醉了,负责重构的这个项目返回值有Map,List,Void还有封装的resultBean 两三种。这样前端处理对应着也就五花八门了。
4、大小写不统一问题,这个是重构最头疼的一个问题。举个栗子,在使用Mybaits时候,有时候查询结果直接封装的对象里,有时候省懒直接用Map封装,问题来了,对象封装返回字段名转变成了驼峰法,Map直接是查询的字段名,这样混着来,查问题很费解。
5、Ajax没有进行统一封装问题。一般不会有太大问题,但是,因为Ajax是局部刷新,所以不能进行页面跳转的操作,在Session过期跳转登录页面上如果不对Ajax统一封装,那就尴尬了。

总结的处理方式

AOP统一处理异常并打印日志

AOP日志辅助

统一ResultBean

直接上代码

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.f2f.voi.common.CommonContainer;

@Component
public class BaseInterceptor {
	
	@Autowired
	protected CommonContainer commonContainer;
	
	protected static final Logger logger = LoggerFactory.getLogger(BaseInterceptor.class);

	protected boolean isContainAnnotationName(JoinPoint pjp, String name) {
		Signature signature = pjp.getSignature();    
		MethodSignature methodSignature = (MethodSignature)signature;    
		Method targetMethod = methodSignature.getMethod();
		Annotation[] annotations = targetMethod.getAnnotations();
		for(int i = 0; i < annotations.length; i++){   
			Annotation annotation = annotations[i];
			if(annotation.annotationType().getName().contains(name))
				return true;
	    }
		return false;
	}
}


import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;


/**
 * @describe 日志打印控制
 * @author YoungSmith
 * @date 2018年6月14日 下午2:14:06
 */
@Aspect
@Component
public class LogInterceptor extends BaseInterceptor {
	
	private static final Boolean isLogPretty = false;
	
	@Pointcut("execution(public * com.f2f.voi.*.controller.*.*(..))")
	public void myMethod() {
	};

	/**
	 * 前置通知:在某连接点之前执行的通知,但这个通知不能阻止连接点前的执行
	 * 
	 * @param jp
	 *            连接点:程序执行过程中的某一行为
	 */
	@Before("myMethod()")
	public void before(JoinPoint jp) {
		String method = jp.getTarget().getClass().getName() + "." + jp.getSignature().getName();
		StringBuilder message = new StringBuilder(method + "() started.");
		logger.info(message.toString());
		
		if(methodHasNonAopLogAnnotation(jp)){ // 方法上有不打印日志注解
			return;
		}
		
		List list = getNonAopLogParamsIndexs(jp);
		 
		Object[] args = jp.getArgs();
		StringBuilder logStr = new StringBuilder(method + "'s param is [");
		for (int i = 0; i < args.length; i++) {
			try {
				if(list.contains(i))
					continue;
				logStr.append(JSONObject.toJSONString(args[i], isLogPretty) + ",");
			} catch (Exception e) {
				// do nothing
			}
		}
		logStr.deleteCharAt(logStr.length() - 1);
		logStr.append("]");
		logger.info(logStr.toString());
	}

	/**
	 * 获取方法中没有NonAopLog注解的参数的下标列表
	 * @param jp
	 * @return
	 */
	private List getNonAopLogParamsIndexs(JoinPoint jp) {
		MethodSignature signature = (MethodSignature) jp.getSignature();
		Method methodObj = signature.getMethod();
		Annotation[][] parameterAnnotations = methodObj.getParameterAnnotations();
		List list = new ArrayList<>();
		outer: for(int i = 0; i < parameterAnnotations.length; i++){
					Annotation[] annotations = parameterAnnotations[i];
					for(int j = 0; j < annotations.length; j++){
						Annotation annotation = annotations[j];
						if(annotation.annotationType() == NonAopLog.class){
							list.add(i);
							continue outer;
						}
					}
				}
		return list;
	}

	@After("myMethod()")
	public void after(JoinPoint jp) {
		String logStr = jp.getTarget().getClass().getName() + "." + jp.getSignature().getName() + " finished.";
		logger.info(logStr);
	}

	/**
	 * 环绕通知:包围一个连接点的通知,可以在方法的调用前后完成自定义的行为,也可以选择不执行。
	 * 类似web中Servlet规范中Filter的doFilter方法。
	 * 
	 * @param pjp
	 *            当前进程中的连接点
	 * @return
	 */
	@Around("myMethod()")
	public Object doAround(ProceedingJoinPoint pjp) {
		long time = System.currentTimeMillis();
		Object result = null;
		String logStr = pjp.getTarget().getClass() + "." + pjp.getSignature().getName();
		try {
			result = pjp.proceed();
		} catch (BusinessException e) {
			logger.info(logStr + " has BusinessException. {}", e.toString());
			return ResultUtil.fail(e.getErrorCode(), e.getErrorMessage(), e.getErrorData());
		} catch (BaseException e) {
			logger.error(logStr + " has BaseException. The Error Message is:", e);
			return ResultUtil.fail(Constants.SYSTEM_ERROR, commonContainer.getMessage(Constants.SYSTEM_ERROR));
		}  catch (Exception e) {
			logger.error(logStr + " has Exception. The Error Message is:", e);
			return ResultUtil.fail(Constants.SYSTEM_ERROR, commonContainer.getMessage(Constants.SYSTEM_ERROR));
		} catch (Throwable e) {
			logger.error(logStr + " has Throwable. The Error Message is:", e);
			return ResultUtil.fail(Constants.SYSTEM_ERROR, commonContainer.getMessage(Constants.SYSTEM_ERROR));
		}
		logger.info(logStr + " Execution Time is:" + (System.currentTimeMillis() - time)/1000.00d + "s");
		return result;
	}
	
	private boolean methodHasNonAopLogAnnotation(JoinPoint pjp) {
		return isContainAnnotationName(pjp, "NonAopLog");
	}
}

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * @describe 不通过AOP打印日志,需要自己手动打印
 * @author YoungSmith
 * @date 2018年6月26日 下午3:03:57
 */
@Target(value={METHOD, PARAMETER})
@Retention(RUNTIME)
@Documented
public @interface NonAopLog {
	String value() default "";
}


你可能感兴趣的:(开发札记,Java)