目录

交易监控中间件_实现

目前情况

暂时还没有搞成真正的中间件,只是把相关代码写在这里,想要集成的朋友可以copy到项目中。

之后有时间,考虑下做成真正的中间件,以jar/pom的方式方便感兴趣的朋友集成!

SQL

update.sql
############################
#交易监控需求
############################
CREATE TABLE `la_trans_monitor` (
  `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `sys_date` CHAR(8) NOT NULL COMMENT '系统日期',
  `sys_time` CHAR(6) NOT NULL COMMENT '系统时间',
  `method_type` VARCHAR(10) NOT NULL COMMENT '方法类型,PO:提供对外服务方法,IN:内部服务方法,IO:调用外部方法,SQL:内部sql',
  `outer_system` VARCHAR(20) COMMENT '外部系统代码',
  `method_route` VARCHAR(500) NOT NULL COMMENT '方法路径',
  `method_name` VARCHAR(500) NOT NULL COMMENT '方法名称',
  `request` longtext COMMENT '入参',
  `response` longtext COMMENT '出参',
  `is_exception` INT(1) NOT NULL DEFAULT '0' COMMENT '是否异常发生,0:没发生异常,1:发生异常',
  `begin_time` TIMESTAMP(3) NOT NULL COMMENT '开始时间',
  `end_time` TIMESTAMP(3) NOT NULL COMMENT '结束时间',
  `used_time` BIGINT NOT NULL COMMENT '耗时(毫秒)',
  `ip` VARCHAR(100) COMMENT '机器ip',
  `resv1` VARCHAR(100) COMMENT '备注字段1',
  `resv2` VARCHAR(100) COMMENT '备注字段2',
  `resv3` VARCHAR(100) COMMENT '备注字段3',
  `is_delete` INT(1) NOT NULL DEFAULT '0' COMMENT '是否删除,0:不删除,1:删除',
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '数据创建时间',
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '数据更新时间',
  PRIMARY KEY (`id`),
  KEY `ix_sys_date` (`sys_date`) ,
  KEY `ix_method_type` (`method_type`) ,
  KEY `ix_method_route` (`method_route`) ,
  KEY `ix_is_exception` (`is_exception`) ,
  KEY `ix_created_at` (`created_at`),
  KEY `ix_updated_at` (`updated_at`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COMMENT='交易监控表';

LogMethodTime.java

LogMethodTime.java
package com.shhxzq.fin.lifeapp.model.base;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
import org.apache.commons.lang.StringUtils;
 
/** 
 * 方法打日志并计算时间注解
 * @author Gxx
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface LogMethodTime {
	/**
	 * 是否监控
	 * 前提:true才监控
	 * @return
	 */
	boolean isMonitor() default false;
 
	/**
	 * 监控方法类型枚举
	 * @return
	 */
	MonitorMethodTypeEnum monitorMethodType() default MonitorMethodTypeEnum.IN;
 
	/**
	 * 外部系统代码
	 * @return
	 */
	SystemEnum outerSystem() default SystemEnum.LIFE_APP;
 
	/**
	 * 方法名称
	 * @return
	 */
	String methodName() default StringUtils.EMPTY;
 
	/**
	 * 备注字段1
	 * @return
	 */
	String resv1() default StringUtils.EMPTY;
 
	/**
	 * 备注字段2
	 * @return
	 */
	String resv2() default StringUtils.EMPTY;
 
	/**
	 * 备注字段3
	 * @return
	 */
	String resv3() default StringUtils.EMPTY;
}

MonitorMethodTypeEnum.java

MonitorMethodTypeEnum.java
package com.shhxzq.fin.lifeapp.model.base;
 
import org.apache.commons.lang.StringUtils;
 
/**
 * 监控方法类型枚举
 * @author Gxx
 */
public enum MonitorMethodTypeEnum {
 
	PROVIDE_OUT("PO", "提供对外服务方法"),
	IN("IN", "内部服务方法"),
	INVOKE_OUT("IO", "调用外部方法"),
	SQL("SQL", "SQL"),
	;
 
	/**
	 * 类型
	 */
	private String type;
 
	/**
	 * 名称
	 */
	private String name;
 
	/**
	 * 构造函数
	 * @param type
	 * @param name
	 */
	MonitorMethodTypeEnum(String type, String name){
		this.type = type;
		this.name = name;
	}
 
	/**
	 * 根据type获取枚举,查不到返回null
	 * @param type
	 * @return
	 */
	public static MonitorMethodTypeEnum getMonitorMethodTypeEnumByType(String type){
		/**
		 * 循环便利该类中的所有枚举
		 */
		for(MonitorMethodTypeEnum temp : MonitorMethodTypeEnum.values()){
			if(StringUtils.equals(temp.getType(), type)){
				return temp;
			}
		}
		/**
		 * 查询不到,返回null
		 */
		return null;
	}
 
	public String getType() {
		return type;
	}
 
	public void setType(String type) {
		this.type = type;
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
}

SystemEnum.java

SystemEnum.java
package com.shhxzq.fin.lifeapp.model.base;
 
import org.apache.commons.lang.StringUtils;
 
/**
 * 系统枚举
 * @author Gxx
 */
public enum SystemEnum {
 
	LIFE_APP("la", "生活应用"),
	BANK_ENGINE("be", "银行引擎"),
	SUPER_GATEWAY("spw", "超网"),
	BEI_DOU("beidou", "安全中心"),
	CTS("cts", "交易"),
	;
 
	/**
	 * 类型
	 */
	private String system;
 
	/**
	 * 名称
	 */
	private String name;
 
	/**
	 * 构造函数
	 * @param system
	 * @param name
	 */
	SystemEnum(String system, String name){
		this.system = system;
		this.name = name;
	}
 
	/**
	 * 根据system获取枚举,查不到返回null
	 * @param system
	 * @return
	 */
	public static SystemEnum getSystemEnumBySystem(String system){
		/**
		 * 循环便利该类中的所有枚举
		 */
		for(SystemEnum temp : SystemEnum.values()){
			if(StringUtils.equals(temp.getSystem(), system)){
				return temp;
			}
		}
		/**
		 * 查询不到,返回null
		 */
		return null;
	}
 
	public String getSystem() {
		return system;
	}
 
	public void setSystem(String system) {
		this.system = system;
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
}

application-context.xml

application-context.xml
	<!-- 服务层AOP begin -->
	<bean id="serviceAop" class="com.shhxzq.fin.lifeapp.biz.utils.ServiceAop" />
	<aop:config>
		<aop:aspect id="serviceAspect" ref="serviceAop">
			<aop:pointcut id="target" expression="execution(* com.shhxzq.fin.lifeapp..*.*(..))" />
			<aop:around method="around" pointcut-ref="target" />
		</aop:aspect>
	</aop:config>
	<!-- 服务层AOP end -->

LaCreditServiceImpl.java

LaCreditServiceImpl.java
/**
 * 信用卡服务接口实现类
 *
 * @author Gxx
 */
@Service("laCreditService")
public class LaCreditServiceImpl implements LaCreditService {
    /**
     * 查询是否显示信用卡管理菜单
     *
     * @param request
     * @return
     */
    @LogMethodTime(isMonitor = true, monitorMethodType = MonitorMethodTypeEnum.PROVIDE_OUT, methodName = "查询是否显示信用卡管理菜单", resv1="{request[0].custNo}", resv2="{response}")
    @Override
    public boolean queryShowCreditMenu(QueryShowCreditMenuRequest request) {
        ...
    }
}

spring-mvc.xml

spring-mvc.xml
	<!-- 扫描控制器类 -->
	<context:component-scan base-package="com.shhxzq.fin.lifeapp" />
 
	<!-- 让aop可以切面到controller -->
	<aop:aspectj-autoproxy proxy-target-class="true"/>

ServiceAop.java

ServiceAop.java
package com.shhxzq.fin.lifeapp.biz.utils;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
 
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
 
import com.shhxzq.fin.lifeapp.biz.service.RabbitService;
import com.shhxzq.fin.lifeapp.model.base.BaseUuidLogger;
import com.shhxzq.fin.lifeapp.model.base.BusinessException;
import com.shhxzq.fin.lifeapp.model.base.LogMethodTime;
import com.shhxzq.fin.lifeapp.model.base.MonitorMethodTypeEnum;
import com.shhxzq.fin.lifeapp.model.base.SystemEnum;
 
/**
 * 服务层AOP
 * @author Gxx
 */
public class ServiceAop {
 
	/**
	 * 日志记录器
	 */
	Logger logger = BaseUuidLoggerUtils.getBaseUuidLogger();
 
	/**
	 * 方法前后操作
	 * @param pjp
	 * @return
	 * @throws Exception
	 */
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		/**
		 * 获取切面方法
		 */
		Signature sig = pjp.getSignature();
		MethodSignature msig = null;
		if (!(sig instanceof MethodSignature)) {
			throw new IllegalArgumentException("该注解只能用于方法");
		}
		msig = (MethodSignature) sig;
		Object target = pjp.getTarget();
		Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
 
		/**
		 * 判断是否有Logger对象,有则强制设置为BaseUuidLogger
		 */
		Field[] files = target.getClass().getDeclaredFields();
		for(Field field : files) {
			if(field.getType() == Logger.class) {
				/**
				 * 私有变量必须先设置Accessible为true
				 */
	            field.setAccessible(true);
				/**
				 * 判断是否第一次赋值
				 */
				if(!(field.get(target) instanceof BaseUuidLogger)) {
					/**
					 * 创建基础日志操作实体-同一个线程的uuid是一样的
					 */
					BaseUuidLogger uuidLogger = new BaseUuidLogger();
					/**
					 * 拷贝属性-父类向子类拷贝(两层父类)
					 */
					BeanUtils.copyPropertiesLevel2(uuidLogger, field.get(target));
					/**
					 * 覆盖设置Logger对象
					 */
		            field.set(target, uuidLogger);
				}
			}
		}
 
		/**
		 * 判断是否加注解@LogMethodTime 和 是否落地
		 */
		boolean isLogMethodTime = currentMethod.isAnnotationPresent(LogMethodTime.class);//是否加注解@LogMethodTime
		boolean isMonitor = false;//是否监控
		MonitorMethodTypeEnum monitorMethodType = null;//监控方法类型枚举
		SystemEnum outerSystem = null;//外部系统代码
		String methodName = null;//方法名称
		String resv1 = null;//备注字段1
		String resv2 = null;//备注字段2
		String resv3 = null;//备注字段3
 
		/**
		 * 判断是否加注解@LogMethodTime
		 */
		if(isLogMethodTime) {
			Annotation p = currentMethod.getAnnotation(LogMethodTime.class);
 
			Method m = p.getClass().getDeclaredMethod("isMonitor", null);
			isMonitor = (boolean) m.invoke(p, null);
 
			/**
			 * 判断是否监控
			 */
			if(isMonitor) {
				m = p.getClass().getDeclaredMethod("monitorMethodType", null);
				monitorMethodType = (MonitorMethodTypeEnum) m.invoke(p, null);
 
				m = p.getClass().getDeclaredMethod("outerSystem", null);
				outerSystem = (SystemEnum) m.invoke(p, null);
 
				m = p.getClass().getDeclaredMethod("methodName", null);
				methodName = (String) m.invoke(p, null);
 
				m = p.getClass().getDeclaredMethod("resv1", null);
				resv1 = (String) m.invoke(p, null);
 
				m = p.getClass().getDeclaredMethod("resv2", null);
				resv2 = (String) m.invoke(p, null);
 
				m = p.getClass().getDeclaredMethod("resv3", null);
				resv3 = (String) m.invoke(p, null);
			}
		}
 
		/**
		 * 类.方法 名字
		 */
		String targetName = pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName();
		String request = StringUtils.EMPTY;
		String response = StringUtils.EMPTY;
 
		/**
		 * 判断是否加注解@LogMethodTime
		 */
		if(isLogMethodTime) {
			request = BeAopUtil.getStringFromRequest(pjp.getArgs());
			String requestMsg = "log - {0} request - {1}";
			logger.info(MessageFormat.format(requestMsg, new Object[] { targetName, request }));
		}
 
		/**
		 * 开始时间 结束时间 耗时 是否异常发生
		 */
		long begin = DateUtils.getNow().getTime();
		long end = 0;
		long usedTime = 0;
		boolean isException = false;
 
		Object result = null;
		try {
			/**
			 * 执行方法
			 */
			result = pjp.proceed();
 
			/**
			 * 返回信息
			 */
			response = BeAopUtil.getStringFromResponse(result);
 
			/**
			 * 返回结果
			 */
			return result;
		} catch (BusinessException t) {
			logger.error(targetName + " exception occure!reason:" + t.getMessage());
 
			/**
			 * 异常发生,返回报文为异常信息
			 */
			isException = true;
			response = t.getMessage();
 
			throw t;
		} catch (Throwable t) {
			logger.error(targetName + " exception occure!", t);
 
			/**
			 * 异常发生,返回报文为异常信息
			 */
			isException = true;
			response = t.getMessage();
 
			throw t;
		} finally {
			try {
				/**
				 * 注解@LogMethodTime才计算计算时间
				 */
				if(isLogMethodTime) {
					end = DateUtils.getNow().getTime();
					usedTime = end - begin;
					logger.info(targetName + " use time : " + usedTime / 1000.0 + "s");
 
					/**
					 * 没有异常发生,打印返回信息
					 */
					if(!isException) {
						String responseMsg = "log - {0} response - {1}";
						logger.info(MessageFormat.format(responseMsg, new Object[] { targetName, response }));
					}
 
					/**
					 * 判断是否监控
					 */
					if(isMonitor) {
						/**
						 * 获取本地ip
						 */
						String localIP = StringUtils.EMPTY;
						try {
							InetAddress localHost = InetAddress.getLocalHost();
							localIP = localHost.getHostAddress();
						} catch (Exception e) {
							logger.error("获取本地ip异常发生", e);
						}
 
						/**
						 * 获取方法路径(包括参数类型)
						 */
						String methodRoute = TransMonitorUtils.getMethodRoute(targetName, pjp.getArgs());
 
						/**
						 * 组织map
						 */
						Map<String, Object> map = new HashMap<String, Object>();
						map.put("methodType", monitorMethodType == null ? StringUtils.EMPTY : monitorMethodType.getType());//方法类型
						map.put("outerSystem", outerSystem == null ? StringUtils.EMPTY : outerSystem.getSystem());//外部系统代码
						map.put("methodRoute", methodRoute);//方法路径
						map.put("methodName", methodName);//方法名称
						map.put("request", BaseUuidLogger.uuid.get() + request);//入参
						map.put("response", response);//出参
						map.put("isException", isException);//是否异常发生
						map.put("beginTime", begin);//开始时间
						map.put("endTime", end);//结束时间
						map.put("usedTime", usedTime);//耗时(毫秒)
						map.put("ip", localIP);//本地ip
 
						/**
						 * 从ThreadLocal中MAP获取resv1,2,3 
						 * 优先级高于
						 * 从注解中解析表达式获取对象
						 */
						String resv1InMap = TransMonitorUtils.getResv1(methodRoute);//从ThreadLocal中MAP获取备注字段1
						String resv2InMap = TransMonitorUtils.getResv2(methodRoute);//从ThreadLocal中MAP获取备注字段2
						String resv3InMap = TransMonitorUtils.getResv3(methodRoute);//从ThreadLocal中MAP获取备注字段3
						if(null != resv1InMap) {
							map.put("resv1", resv1InMap);
						} else {
							map.put("resv1", ExpressLanUtils.getObjectFromExpressexToString(resv1, pjp.getArgs(), result, isException));//从注解中解析表达式获取对象-备注字段1
						}
						if(null != resv2InMap) {
							map.put("resv2", resv2InMap);
						} else {
							map.put("resv2", ExpressLanUtils.getObjectFromExpressexToString(resv2, pjp.getArgs(), result, isException));//从注解中解析表达式获取对象-备注字段2
						}
						if(null != resv3InMap) {
							map.put("resv3", resv3InMap);
						} else {
							map.put("resv3", ExpressLanUtils.getObjectFromExpressexToString(resv3, pjp.getArgs(), result, isException));//从注解中解析表达式获取对象-备注字段3
						}
 
						/**
						 * 异步执行任务-提交任务
						 */
						AsynUtils.getInstance().submitTask(new Callable<Boolean>() {
							@Override
							public Boolean call() throws Exception {
								/**
								 * 推送la交易监控(为了异步执行)
								 */
								SpringUtils.getInstance().getBean(RabbitService.class).sendLaTransMonitor(map);
								return true;
							}
						});
					}
				}
			} catch (Exception e) {
				logger.error("切面处理异常发生!", e);
			}
		}
	}
}

BeAopUtil.java

BeAopUtil.java
package com.shhxzq.fin.lifeapp.biz.utils;
 
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
 
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
 
/**
 * Aop工具类
 * @author Gxx
 */
public class BeAopUtil {
 
	/**
	 * 根据入参获取字符串
	 * @param args
	 * @return
	 */
	public static String getStringFromRequest(Object[] args){
		String req = "";
		for(Object arg:args){
			if(arg == null){
				req = req + "null,";
				continue;
			}else if(arg instanceof List == true || arg instanceof Set == true){
				req = req + JsonTools.toJSONString(arg);
			}
			else if(arg.getClass().isArray()){
				req = req + JSONArray.fromObject(arg);
			}
			else if( arg instanceof Enum){
				req = req + JsonTools.toJSONString(arg)+",";
			}else if(!(arg instanceof String)
					&& !(arg instanceof BigDecimal)
					&& !(arg instanceof Boolean)
					&& !(arg instanceof Integer)
					&& (arg instanceof Object)){
				req = req+JSONObject.fromObject(arg).toString()+",";
			}else{
				req = req+arg.toString()+",";
			}
		}
		if(req.endsWith(",")) {
			req = req.substring(0, req.length() - 1);
		}
		return req;
	}
 
	/**
	 * 根据出参获取字符串
	 * @param arg
	 * @return
	 */
	public static String getStringFromResponse(Object arg){
		String rsp = "";
		if(arg == null){
			rsp = rsp + "null";
			return rsp;
		}else if(arg instanceof List || arg instanceof Set == true){
			rsp = rsp + JsonTools.toJSONString(arg);
			return rsp;
		}else if( arg instanceof Enum){
			rsp = rsp + JsonTools.toJSONString(arg);
			return rsp;
		}else if(!(arg instanceof String )
				&& !(arg instanceof BigDecimal)
				&& !(arg instanceof Boolean)
				&& !(arg instanceof Integer )
				&& (arg instanceof Object)){
			rsp = rsp+JSONObject.fromObject(arg).toString()+",";
		}else{
			rsp = rsp+arg.toString()+",";
		}
		if(rsp.endsWith(",")) {
			rsp = rsp.substring(0, rsp.length() - 1);
		}
		return rsp;
	}
}

TransMonitorUtils.java

TransMonitorUtils.java
package com.shhxzq.fin.lifeapp.biz.utils;
 
import java.util.HashMap;
import java.util.Map;
 
import org.apache.log4j.Logger;
 
/** 
 * 交易监控工具类
 * @author Gxx
 */
public class TransMonitorUtils {
	/**
	 * 日志记录器
	 */
	static Logger logger = BaseUuidLoggerUtils.getBaseUuidLogger();
 
	/**
	 * 通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
	 * 使得同一个线程的resvMap是一样的,存放监控方法的备注字段
	 */
	private static ThreadLocal<Map<String, String>> resvMap = new ThreadLocal<Map<String, String>>() {
		/**
		 * 初始值
		 */
		public Map<String, String> initialValue() {
			return new HashMap<>();
		}
	};
 
	/**
	 * 往ThreadLocal中MAP设置备注字段1
	 * @param className 类名
	 * @param methodName 方法名
	 * @param args 参数
	 * @param string 备注字段1
	 */
	public synchronized static void setResv1(String className, String methodName, Object[] args, String string) {
		String methodRoute = getMethodRoute(className + "." + methodName, args);
		resvMap.get().put(methodRoute + ".resv1", string);
	}
 
	/**
	 * 往ThreadLocal中MAP设置备注字段2
	 * @param className 类名
	 * @param methodName 方法名
	 * @param args 参数
	 * @param string 备注字段2
	 */
	public synchronized static void setResv2(String className, String methodName, Object[] args, String string) {
		String methodRoute = getMethodRoute(className + "." + methodName, args);
		resvMap.get().put(methodRoute + ".resv2", string);
	}
 
	/**
	 * 往ThreadLocal中MAP设置备注字段3
	 * @param className 类名
	 * @param methodName 方法名
	 * @param args 参数
	 * @param string 备注字段3
	 */
	public synchronized static void setResv3(String className, String methodName, Object[] args, String string) {
		String methodRoute = getMethodRoute(className + "." + methodName, args);
		resvMap.get().put(methodRoute + ".resv3", string);
	}
 
	/**
	 * 从ThreadLocal中MAP获取备注字段1
	 * @param string
	 */
	public synchronized static String getResv1(String methodRoute) {
		return resvMap.get().get(methodRoute + ".resv1");
	}
 
	/**
	 * 从ThreadLocal中MAP获取备注字段2
	 * @param string
	 */
	public synchronized static String getResv2(String methodRoute) {
		return resvMap.get().get(methodRoute + ".resv2");
	}
 
	/**
	 * 从ThreadLocal中MAP获取备注字段3
	 * @param string
	 */
	public synchronized static String getResv3(String methodRoute) {
		return resvMap.get().get(methodRoute + ".resv3");
	}
 
	/**
	 * 获取方法路径(包括参数类型)
	 * @param targetName 类名+方法名
	 * @param args 参数数组
	 * @return
	 */
	public static String getMethodRoute(String targetName, Object[] args) {
		String methodRoute = targetName + "(";
		if(null != args) {
			for(int i=0;i<args.length;i++) {
				if(i > 0) {
					methodRoute += ", ";
				}
				Object object = args[i];
				String type = object.getClass().getTypeName();
				methodRoute += type;
			}
		}
		methodRoute += ")";
		return methodRoute;
	}
}

ExpressLanUtils.java

ExpressLanUtils.java
package com.shhxzq.fin.lifeapp.biz.utils;
 
import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlExpression;
import org.apache.commons.jexl3.MapContext;
import org.apache.commons.jexl3.internal.Engine;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
 
/** 
 * 表达式语言工具类
 * 依赖commons-jexl3包
 * @author Gxx
 */
public class ExpressLanUtils {
	/**
	 * 日志记录器
	 */
	static Logger logger = BaseUuidLoggerUtils.getBaseUuidLogger();
	/**
	 * 请求参数前缀标示
	 */
	public static final String REQUEST_PREFIX = "{request";
	/**
	 * 请求参数后缀标示
	 */
	public static final String REQUEST_SUFFIX = "}";
	/**
	 * 请求参数前缀标示
	 */
	public static final String RESPONSE_PREFIX = "{response";
	/**
	 * 请求参数后缀标示
	 */
	public static final String RESPONSE_SUFFIX = "}";
	/**
	 * 分隔符
	 */
	public static final String SPLIT_STRING = "\\{\\|\\}";
 
	/**
	 * 判断是否是表达式
	 * @param string
	 * @return
	 */
	public static boolean isExpress(String string) {
		return isRequestExpress(string) || isResponseExpress(string);
	}
 
	/**
	 * 判断是否是[获取请求]表达式
	 * @param string
	 * @return
	 */
	public static boolean isRequestExpress(String string) {
		/**
		 * 判断非空
		 */
		if(StringUtils.isNotBlank(string)) {
			string = StringUtils.trim(string);
			if(string.startsWith(REQUEST_PREFIX) && string.endsWith(REQUEST_SUFFIX)) {
				return true;
			}
		}
		return false;
	}
 
	/**
	 * 判断是否是[获取返回]表达式
	 * @param string
	 * @return
	 */
	public static boolean isResponseExpress(String string) {
		/**
		 * 判断非空
		 */
		if(StringUtils.isNotBlank(string)) {
			string = StringUtils.trim(string);
			if(string.startsWith(RESPONSE_PREFIX) && string.endsWith(RESPONSE_SUFFIX)) {
				return true;
			}
		}
		return false;
	}
 
	/**
	 * 从表达式(按分隔符拆分后)获取对象
	 * 1.非表达式,原样返回
	 * 2.[获取请求]表达式,解析表达式,返回[请求]中的值
	 * 3.[获取返回]表达式,
	 * 3.1.没有异常发生,解析表达式,返回[返回]中的值
	 * 3.2.有异常发生,返回null
	 * @param express 表达式:[获取请求]表达式/[获取返回]表达式
	 * @param request 请求参数数组
	 * @param response 返回参数
	 * @param isException 是否发生异常
	 * @return
	 */
	public static Object getObjectFromExpress(String express, Object[] request, Object response, boolean isException) {
		try {
			/**
			 * 1.非表达式,原样返回
			 */
			boolean isRequestExpress = isRequestExpress(express);
			boolean isResponseExpress = isResponseExpress(express);
			if(!isRequestExpress && !isResponseExpress) {
				return express;
			}
			/**
			 * 2.[获取请求]表达式,解析表达式,返回[请求]中的值
			 * 比如:
			 * {request} : 取第一个request参数
			 * {request[0]} : 取第一个request参数
			 * {request[1]} : 取第二个request参数
			 * {request.custNo} : 取第一个request参数的属性
			 * {request.createdAt.time} : 取第一个request参数的属性的属性
			 * {request[0].custNo} : 取第一个request参数的属性
			 * {request[0].createdAt.time} : 取第一个request参数的属性的属性
			 * {request[1].createdAt.time} : 取第二个request参数的属性的属性
			 */
			if(isRequestExpress) {
				/**
				 * 2.0.判空
				 */
				if(null == request || request.length == 0) {
					return null;
				}
				/**
				 * 2.1.去掉开头:{request
				 */
				express = express.substring(REQUEST_PREFIX.length());
				/**
				 * 2.2.去掉结尾:}
				 */
				express = express.substring(0, express.length() - 1);
				/**
				 * 2.3.判空 {request}
				 */
				if(StringUtils.isBlank(express)) {
					return request[0];
				}
				/**
				 * 2.4.判断.开头
				 */
				Object object = null;
				if(express.startsWith(".")) {
					express = express.substring(1);
					object = request[0];
					return getObjectFromExpress(express, object);
				}
				/**
				 * 2.4.判断[开头
				 */
				if(express.startsWith("[")) {
					express = express.substring(1);
					int index = express.indexOf("]");
					int indexValue = Integer.parseInt(express.substring(0, index));
					object = request[indexValue];
					express = express.substring(index + 1);
					/**
					 * 2.4.1.判断request[*]
					 */
					if(StringUtils.isBlank(express)) {
						return object;
					}
					/**
					 * 2.4.2.判断request[*].custNo
					 */
					if(express.startsWith(".")) {
						express = express.substring(1);
						return getObjectFromExpress(express, object);
					}
				}
 
			}
			/**
			 * 3.[获取返回]表达式,解析表达式,返回[返回]中的值
			 * 比如:
			 * {response} : 取第一个request参数
			 * {response.custNo} : 取第一个request参数的属性
			 * {response.createdAt.time} : 取第一个request参数的属性的属性
			 */
			if(isResponseExpress) {
				/**
				 * 3.0.判空
				 */
				if(null == response) {
					return null;
				}
				/**
				 * 3.1.去掉开头:{response
				 */
				express = express.substring(RESPONSE_PREFIX.length());
				/**
				 * 3.2.去掉结尾:}
				 */
				express = express.substring(0, express.length() - 1);
				/**
				 * 3.3.判空 {response}
				 */
				if(StringUtils.isBlank(express)) {
					return response;
				}
				/**
				 * 3.4.判断.开头
				 */
				if(express.startsWith(".")) {
					express = express.substring(1);
					return getObjectFromExpress(express, response);
				}
			}
			return null;
		} catch (Exception e) {
			logger.error("从表达式获取对象异常发生", e);
			return null;
		}
	}
 
	/**
	 * 从表达式(jexl)获取对象
	 * @param express
	 * @param object
	 * @return
	 */
	public static Object getObjectFromExpress(String express, Object object) {
		try {
			/**
			 * 判空
			 */
			if(null == object) {
				return null;
			}
			JexlEngine JEXL = new Engine();
			JexlExpression e = JEXL.createExpression("object." + express);
	        JexlContext jc = new MapContext();
	        jc.set("object", object);
	        return e.evaluate(jc);
		} catch (Exception e) {
			logger.error("从表达式获取对象异常发生", e);
			return null;
		}
	}
 
	/**
	 * 从表达式(按分隔符拆分后)获取对象并转成string
	 * @param express
	 * @param request
	 * @param response
	 * @param isException
	 * @return
	 */
	public static String getObjectFromExpressToString(String express, Object[] request, Object response, boolean isException) {
		/**
		 * 从表达式获取对象
		 */
		Object result = getObjectFromExpress(express, request, response, isException);
		if(null == result) {
			return null;
		} else {
			return result.toString();
		}
	}
 
	/**
	 * 从表达式(按分隔符拆分前)获取对象并转成string
	 * @param express
	 * @param request
	 * @param response
	 * @param isException
	 * @return
	 */
	public static Object getObjectFromExpressexToString(String express, Object[] request, Object response, boolean isException) {
		try {
			/**
			 * 1.非表达式,原样返回
			 * NORMAL_STRING
			 * NORMAL_STRING{|}{response.*}{|}{request[*].*}
			 * {request.*}
			 * {request[*].*}
			 * {response.*}
			 * {request.*}{|}{request[*].*}
			 * {request[*].*}{|}{response.*}
			 * {response.*}{|}{response.*}{|}{request[*].*}
			 */
			if(StringUtils.isBlank(express)) {
				return express;
			}
			String result = StringUtils.EMPTY;
			String[] expressArray = express.split(SPLIT_STRING);
			for(int i=0;i<expressArray.length;i++) {
				if(i > 0) {
					result += "|";
				}
				/**
				 * 从表达式获取对象
				 */
				Object temp = getObjectFromExpressToString(expressArray[i], request, response, isException);
				/**
				 * 空则略过
				 */
				if(null != temp) {
					result += temp.toString();
				}
			}
			return result;
		} catch (Exception e) {
			logger.error("从表达式(按分隔符拆分前)获取对象并转成string异常发生!", e);
			return express;
		}
	}
}

AsynUtils.java

AsynUtils.java
package com.shhxzq.fin.lifeapp.biz.utils;
 
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
 
/**
 * 异步执行任务工具类
 * @author Gxx
 * @param <T>
 */
public final class AsynUtils {
	/**
	 * 单例模式
	 */
    private static AsynUtils instance = new AsynUtils();
 
    /**
	 * 进行异步任务列表
	 */
    private List<FutureTask> futureTasks = new ArrayList<FutureTask>();
 
	/**
	 * 线程池 暂时约定初始化5个线程 和JDBC连接池是一个意思 实现重用
	 */
    private ExecutorService executorService = Executors.newFixedThreadPool(5);
 
    public static AsynUtils getInstance() {
    	return instance;
    }
 
    /**
     * 异步执行任务-提交任务
     */
    public void submitTask(Callable callable) {
    	/**
		 * 创建一个异步任务
		 */
		FutureTask futureTask = new FutureTask(callable);
		futureTasks.add(futureTask);
		/**
		 * 提交异步任务到线程池,让线程池管理任务
		 * 由于是异步并行任务,所以这里并不会阻塞
		 * 注意:一旦提交,线程池如果有可用线程,马上分配执行!
		 */
		executorService.submit(futureTask);
    }
}

RabbitService.java

RabbitService.java
package com.shhxzq.fin.lifeapp.biz.service;
 
import java.util.Map;
 
/**
 * rabbit服务接口
 * @author Gxx
 */
public interface RabbitService {
	/**
	 * 推送la交易监控(为了异步执行)
	 * @param wechatMap
	 */
	public void sendLaTransMonitor(Map<String, Object> map);
}

RabbitServiceImpl.java

RabbitServiceImpl.java
package com.shhxzq.fin.lifeapp.biz.impl;
 
import java.util.Map;
 
import com.shhxzq.fin.lifeapp.biz.utils.HawkeyeUtil;
import com.shhxzq.fin.lifeapp.model.base.LaMonitorType;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.shhxzq.fin.lifeapp.biz.service.RabbitService;
 
/**
 * rabbit服务实现类
 * @author Gxx
 */
@Service("rabbitService")
public class RabbitServiceImpl implements RabbitService {
 
	/**
	 * 日志记录器
	 */
	Logger logger = Logger.getLogger(RabbitServiceImpl.class);
 
	/**
	 * mq执行器
	 */
	@Autowired
	private AmqpTemplate amqpTemplate;
 
	/**
	 * 推送la交易监控(为了异步执行)
	 * @param wechatMap
	 */
	public void sendLaTransMonitor(Map<String, Object> map) {
		String jsonString = StringUtils.EMPTY;
		try {
			/**
			 * 默认值为null不会转json,这里强制转
			 * {"a":1,"b":"","c":null,"d":"wuzhuti.cn"}
			 */
			jsonString  = JSON.toJSONString(map, SerializerFeature.WriteMapNullValue);
			logger.info("推送la交易监控(为了异步执行),开始!");
			amqpTemplate.convertAndSend("la_queue_la_trans_monitor_key", jsonString);
			logger.info("推送la交易监控(为了异步执行),结束!");
		} catch (Exception e) {
			/**
			 * mq异常捕获,不往外抛
			 */
			logger.error("推送la交易监控(为了异步执行)[json:" + jsonString + "]!", e);
            /**
             * 报警
             */
			HawkeyeUtil.logEvent(LaMonitorType.RABBIT_MQ.getType(), LaMonitorType.RABBIT_MQ_EXCEPTION.getType(), e.getMessage());
		}
	}
}

application-mq-rabbit.xml

application-mq-rabbit.xml
<?xml version="1.0" encoding="UTF-8"?>
 
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
	xmlns:rabbit="http://www.springframework.org/schema/rabbit"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/integration/ip
      http://www.springframework.org/schema/integration/ip/spring-integration-ip-2.0.xsd
      http://www.springframework.org/schema/integration
      http://www.springframework.org/schema/integration/spring-integration.xsd
      http://www.springframework.org/schema/task
      http://www.springframework.org/schema/task/spring-task-3.0.xsd
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/rabbit
      http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd">
 
	<!-- mq连接服务配置 -->
	<rabbit:connection-factory id="connectionFactory"
		host="${la.rabbit.host}" username="${la.rabbit.username}" password="${la.rabbit.password}"
		port="${la.rabbit.port}" />
 
	<rabbit:admin connection-factory="connectionFactory" />
 
	<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
		exchange="payment_exchange" />
 
	<!-- 推送la交易监控(为了异步执行) -->
	<rabbit:queue id="la_queue_la_trans_monitor"
		durable="true" auto-delete="false" exclusive="false"
		name="la_queue_la_trans_monitor" />
 
	<rabbit:direct-exchange name="payment_exchange"
		durable="true" auto-delete="false" id="payment_exchange">
 
		<rabbit:bindings>
			<!-- 通知la消息 -->
			<rabbit:binding queue="la_queue_la_trans_monitor"
				key="la_queue_la_trans_monitor_key" />
		</rabbit:bindings>
 
	</rabbit:direct-exchange>
 
	<!-- queue litener 观察 监听模式 当有消息到达时会通知监听在对应的队列上的监听对象 task-executor="taskExecutor" -->
	<rabbit:listener-container
		connection-factory="connectionFactory" acknowledge="auto">
 
		<!-- 接收la消息 -->
		<rabbit:listener queues="la_queue_la_trans_monitor" ref="laTransMonitorListener" />
 
	</rabbit:listener-container>
</beans>

LaTransMonitorListener.java

LaTransMonitorListener.java
package com.shhxzq.fin.lifeapp.biz.impl.mq;
 
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.shhxzq.fin.lifeapp.biz.utils.DateUtils;
import com.shhxzq.fin.lifeapp.dao.credit.LaTransMonitorMapper;
import com.shhxzq.fin.lifeapp.model.base.BaseUuidLogger;
import com.shhxzq.fin.lifeapp.model.constants.CreditConstants;
import com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitorWithBLOBs;
 
import net.sf.json.JSONObject;
 
/**
 * 接受la交易监控推送(异步执行)
 * @author Gxx
 */
@Service(value = "laTransMonitorListener")
public class LaTransMonitorListener implements MessageListener {
 
	/**
	 * 日志处理器
	 */
	private Logger logger = Logger.getLogger(LaTransMonitorListener.class);
 
	@Autowired
	private LaTransMonitorMapper laTransMonitorMapper;
 
	@Override
	public void onMessage(Message message) {
		try {
			/**
			 * 刷新uuid
			 */
			((BaseUuidLogger)logger).refreshUuid();
			logger.info("接受la交易监控推送(异步执行)对象:" + message);
			/**
			 * 接受消息
			 */
			String receiveMsg;
			try {
				receiveMsg = new String(message.getBody(), message.getMessageProperties().getContentEncoding());
			} catch (Exception e) {
				logger.error("接受la交易监控推送(异步执行),字符转换失败", e);
				return;
			}
			/**
			 * 判断消息为空
			 */
			if (StringUtils.isBlank(receiveMsg)) {
				logger.error("接受la交易监控推送(异步执行)收到消息为空");
				return;
			} else {
				/**
				 * 获取数据
				 */
				JSONObject jsonObject = JSONObject.fromObject(receiveMsg);
				String methodType = jsonObject.getString("methodType");//方法类型
				String outerSystem = jsonObject.getString("outerSystem");//外部系统代码
				String methodRoute = jsonObject.getString("methodRoute");//方法路径
				String methodName = jsonObject.getString("methodName");//方法名称
				String request = jsonObject.getString("request");//入参
				String response = jsonObject.getString("response");//出参
				Boolean isException = jsonObject.getBoolean("isException");//是否异常发生
				Long beginTime = jsonObject.getLong("beginTime");//开始时间
				Long endTime = jsonObject.getLong("endTime");//结束时间
				Long usedTime = jsonObject.getLong("usedTime");//耗时(毫秒)
				String ip = jsonObject.getString("ip");//本地ip
				String resv1 = jsonObject.getString("resv1");//备注字段1
				String resv2 = jsonObject.getString("resv2");//备注字段2
				String resv3 = jsonObject.getString("resv3");//备注字段3
 
				/**
				 * 字符串长度处理
				 */
				request = (null != request && request.length() > 1000 ? request.substring(0, 1000) + "..." : request);
				response = (null != response && response.length() > 1000 ? response.substring(0, 1000) + "..." : response);
				resv1 = (null != resv1 && resv1.length() > 100 ? resv1.substring(0, 100) : resv1);
				resv2 = (null != resv2 && resv2.length() > 100 ? resv2.substring(0, 100) : resv2);
				resv3 = (null != resv3 && resv3.length() > 100 ? resv3.substring(0, 100) : resv3);
 
				/**
				 * 交易监控落库
				 */
				LaTransMonitorWithBLOBs laTransMonitorWithBLOBs = new LaTransMonitorWithBLOBs();
				laTransMonitorWithBLOBs.setSysDate(DateUtils.getCurrentDate());
				laTransMonitorWithBLOBs.setSysTime(DateUtils.getCurrentTime());
				laTransMonitorWithBLOBs.setMethodType(methodType);
				laTransMonitorWithBLOBs.setOuterSystem(outerSystem);
				laTransMonitorWithBLOBs.setMethodRoute(methodRoute);
				laTransMonitorWithBLOBs.setMethodName(methodName);
				laTransMonitorWithBLOBs.setRequest(request);
				laTransMonitorWithBLOBs.setResponse(response);
				laTransMonitorWithBLOBs.setIsException(isException ? CreditConstants.IS_EXCEPTION_YES : CreditConstants.IS_EXCEPTION_NO);
				laTransMonitorWithBLOBs.setBeginTime(DateUtils.getDate(beginTime));
				laTransMonitorWithBLOBs.setEndTime(DateUtils.getDate(endTime));
				laTransMonitorWithBLOBs.setUsedTime(usedTime);
				laTransMonitorWithBLOBs.setIp(ip);
				laTransMonitorWithBLOBs.setResv1(resv1);
				laTransMonitorWithBLOBs.setResv2(resv2);
				laTransMonitorWithBLOBs.setResv3(resv3);
				laTransMonitorWithBLOBs.setIsDelete(CreditConstants.IS_DELETE_NO);
				laTransMonitorWithBLOBs.setCreatedAt(DateUtils.getNow());
				laTransMonitorWithBLOBs.setUpdatedAt(DateUtils.getNow());
				laTransMonitorMapper.insert(laTransMonitorWithBLOBs);
				logger.info("交易监控落库完成!");
			}
		} catch (Exception e) {
			logger.error("交易监控接受落库异常发生!", e);
		}
	}
 
}

LaTransMonitorMapper.java

LaTransMonitorMapper.java
package com.shhxzq.fin.lifeapp.dao.credit;
 
import org.springframework.stereotype.Repository;
 
import com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitor;
import com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitorWithBLOBs;
 
@Repository
public interface LaTransMonitorMapper {
    int deleteByPrimaryKey(Integer id);
 
    int insert(LaTransMonitorWithBLOBs record);
 
    int insertSelective(LaTransMonitorWithBLOBs record);
 
    LaTransMonitorWithBLOBs selectByPrimaryKey(Integer id);
 
    int updateByPrimaryKeySelective(LaTransMonitorWithBLOBs record);
 
    int updateByPrimaryKeyWithBLOBs(LaTransMonitorWithBLOBs record);
 
    int updateByPrimaryKey(LaTransMonitor record);
}

LaTransMonitorWithBLOBs.java

LaTransMonitorWithBLOBs.java
package com.shhxzq.fin.lifeapp.model.credit.vo;
 
public class LaTransMonitorWithBLOBs extends LaTransMonitor {
    private String request;
 
    private String response;
 
    public String getRequest() {
        return request;
    }
 
    public void setRequest(String request) {
        this.request = request == null ? null : request.trim();
    }
 
    public String getResponse() {
        return response;
    }
 
    public void setResponse(String response) {
        this.response = response == null ? null : response.trim();
    }
 
	@Override
	public String toString() {
		return "LaTransMonitorWithBLOBs [request=" + request + ", response=" + response + "] LaTransMonitor [" + super.toString() + "]";
	}
}

LaTransMonitor.java

LaTransMonitor.java
package com.shhxzq.fin.lifeapp.model.credit.vo;
 
import java.util.Date;
 
public class LaTransMonitor {
    private Integer id;
 
    private String sysDate;
 
    private String sysTime;
 
    private String methodType;
 
    private String outerSystem;
 
    private String methodRoute;
 
    private String methodName;
 
    private Integer isException;
 
    private Date beginTime;
 
    private Date endTime;
 
    private Long usedTime;
 
    private String ip;
 
    private String resv1;
 
    private String resv2;
 
    private String resv3;
 
    private Integer isDelete;
 
    private Date createdAt;
 
    private Date updatedAt;
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getSysDate() {
        return sysDate;
    }
 
    public void setSysDate(String sysDate) {
        this.sysDate = sysDate == null ? null : sysDate.trim();
    }
 
    public String getSysTime() {
        return sysTime;
    }
 
    public void setSysTime(String sysTime) {
        this.sysTime = sysTime == null ? null : sysTime.trim();
    }
 
    public String getMethodType() {
        return methodType;
    }
 
    public void setMethodType(String methodType) {
        this.methodType = methodType == null ? null : methodType.trim();
    }
 
    public String getOuterSystem() {
        return outerSystem;
    }
 
    public void setOuterSystem(String outerSystem) {
        this.outerSystem = outerSystem == null ? null : outerSystem.trim();
    }
 
    public String getMethodRoute() {
        return methodRoute;
    }
 
    public void setMethodRoute(String methodRoute) {
        this.methodRoute = methodRoute == null ? null : methodRoute.trim();
    }
 
    public String getMethodName() {
        return methodName;
    }
 
    public void setMethodName(String methodName) {
        this.methodName = methodName == null ? null : methodName.trim();
    }
 
    public Integer getIsException() {
        return isException;
    }
 
    public void setIsException(Integer isException) {
        this.isException = isException;
    }
 
    public Date getBeginTime() {
        return beginTime;
    }
 
    public void setBeginTime(Date beginTime) {
        this.beginTime = beginTime;
    }
 
    public Date getEndTime() {
        return endTime;
    }
 
    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }
 
    public Long getUsedTime() {
        return usedTime;
    }
 
    public void setUsedTime(Long usedTime) {
        this.usedTime = usedTime;
    }
 
    public String getIp() {
        return ip;
    }
 
    public void setIp(String ip) {
        this.ip = ip == null ? null : ip.trim();
    }
 
    public String getResv1() {
        return resv1;
    }
 
    public void setResv1(String resv1) {
        this.resv1 = resv1 == null ? null : resv1.trim();
    }
 
    public String getResv2() {
        return resv2;
    }
 
    public void setResv2(String resv2) {
        this.resv2 = resv2 == null ? null : resv2.trim();
    }
 
    public String getResv3() {
        return resv3;
    }
 
    public void setResv3(String resv3) {
        this.resv3 = resv3 == null ? null : resv3.trim();
    }
 
    public Integer getIsDelete() {
        return isDelete;
    }
 
    public void setIsDelete(Integer isDelete) {
        this.isDelete = isDelete;
    }
 
    public Date getCreatedAt() {
        return createdAt;
    }
 
    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }
 
    public Date getUpdatedAt() {
        return updatedAt;
    }
 
    public void setUpdatedAt(Date updatedAt) {
        this.updatedAt = updatedAt;
    }
}

LaTransMonitorMapper.xml

LaTransMonitorMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.shhxzq.fin.lifeapp.dao.credit.LaTransMonitorMapper" >
  <resultMap id="BaseResultMap" type="com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitor" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="sys_date" property="sysDate" jdbcType="CHAR" />
    <result column="sys_time" property="sysTime" jdbcType="CHAR" />
    <result column="method_type" property="methodType" jdbcType="VARCHAR" />
    <result column="outer_system" property="outerSystem" jdbcType="VARCHAR" />
    <result column="method_route" property="methodRoute" jdbcType="VARCHAR" />
    <result column="method_name" property="methodName" jdbcType="VARCHAR" />
    <result column="is_exception" property="isException" jdbcType="INTEGER" />
    <result column="begin_time" property="beginTime" jdbcType="TIMESTAMP" />
    <result column="end_time" property="endTime" jdbcType="TIMESTAMP" />
    <result column="used_time" property="usedTime" jdbcType="BIGINT" />
    <result column="ip" property="ip" jdbcType="VARCHAR" />
    <result column="resv1" property="resv1" jdbcType="VARCHAR" />
    <result column="resv2" property="resv2" jdbcType="VARCHAR" />
    <result column="resv3" property="resv3" jdbcType="VARCHAR" />
    <result column="is_delete" property="isDelete" jdbcType="INTEGER" />
    <result column="created_at" property="createdAt" jdbcType="TIMESTAMP" />
    <result column="updated_at" property="updatedAt" jdbcType="TIMESTAMP" />
  </resultMap>
  <resultMap id="ResultMapWithBLOBs" type="com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitorWithBLOBs" extends="BaseResultMap" >
    <result column="request" property="request" jdbcType="LONGVARCHAR" />
    <result column="response" property="response" jdbcType="LONGVARCHAR" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, sys_date, sys_time, method_type, outer_system, method_route, method_name, is_exception, 
    begin_time, end_time, used_time, ip, resv1, resv2, resv3, is_delete, created_at, 
    updated_at
  </sql>
  <sql id="Blob_Column_List" >
    request, response
  </sql>
  <select id="selectByPrimaryKey" resultMap="ResultMapWithBLOBs" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    ,
    <include refid="Blob_Column_List" />
    from la_trans_monitor
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from la_trans_monitor
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitorWithBLOBs" >
    insert into la_trans_monitor (id, sys_date, sys_time, 
      method_type, outer_system, method_route, 
      method_name, is_exception, begin_time, 
      end_time, used_time, ip, 
      resv1, resv2, resv3, 
      is_delete, created_at, updated_at, 
      request, response)
    values (#{id,jdbcType=INTEGER}, #{sysDate,jdbcType=CHAR}, #{sysTime,jdbcType=CHAR}, 
      #{methodType,jdbcType=VARCHAR}, #{outerSystem,jdbcType=VARCHAR}, #{methodRoute,jdbcType=VARCHAR}, 
      #{methodName,jdbcType=VARCHAR}, #{isException,jdbcType=INTEGER}, #{beginTime,jdbcType=TIMESTAMP}, 
      #{endTime,jdbcType=TIMESTAMP}, #{usedTime,jdbcType=BIGINT}, #{ip,jdbcType=VARCHAR}, 
      #{resv1,jdbcType=VARCHAR}, #{resv2,jdbcType=VARCHAR}, #{resv3,jdbcType=VARCHAR}, 
      #{isDelete,jdbcType=INTEGER}, #{createdAt,jdbcType=TIMESTAMP}, #{updatedAt,jdbcType=TIMESTAMP}, 
      #{request,jdbcType=LONGVARCHAR}, #{response,jdbcType=LONGVARCHAR})
  </insert>
  <insert id="insertSelective" parameterType="com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitorWithBLOBs" >
    insert into la_trans_monitor
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="sysDate != null" >
        sys_date,
      </if>
      <if test="sysTime != null" >
        sys_time,
      </if>
      <if test="methodType != null" >
        method_type,
      </if>
      <if test="outerSystem != null" >
        outer_system,
      </if>
      <if test="methodRoute != null" >
        method_route,
      </if>
      <if test="methodName != null" >
        method_name,
      </if>
      <if test="isException != null" >
        is_exception,
      </if>
      <if test="beginTime != null" >
        begin_time,
      </if>
      <if test="endTime != null" >
        end_time,
      </if>
      <if test="usedTime != null" >
        used_time,
      </if>
      <if test="ip != null" >
        ip,
      </if>
      <if test="resv1 != null" >
        resv1,
      </if>
      <if test="resv2 != null" >
        resv2,
      </if>
      <if test="resv3 != null" >
        resv3,
      </if>
      <if test="isDelete != null" >
        is_delete,
      </if>
      <if test="createdAt != null" >
        created_at,
      </if>
      <if test="updatedAt != null" >
        updated_at,
      </if>
      <if test="request != null" >
        request,
      </if>
      <if test="response != null" >
        response,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="sysDate != null" >
        #{sysDate,jdbcType=CHAR},
      </if>
      <if test="sysTime != null" >
        #{sysTime,jdbcType=CHAR},
      </if>
      <if test="methodType != null" >
        #{methodType,jdbcType=VARCHAR},
      </if>
      <if test="outerSystem != null" >
        #{outerSystem,jdbcType=VARCHAR},
      </if>
      <if test="methodRoute != null" >
        #{methodRoute,jdbcType=VARCHAR},
      </if>
      <if test="methodName != null" >
        #{methodName,jdbcType=VARCHAR},
      </if>
      <if test="isException != null" >
        #{isException,jdbcType=INTEGER},
      </if>
      <if test="beginTime != null" >
        #{beginTime,jdbcType=TIMESTAMP},
      </if>
      <if test="endTime != null" >
        #{endTime,jdbcType=TIMESTAMP},
      </if>
      <if test="usedTime != null" >
        #{usedTime,jdbcType=BIGINT},
      </if>
      <if test="ip != null" >
        #{ip,jdbcType=VARCHAR},
      </if>
      <if test="resv1 != null" >
        #{resv1,jdbcType=VARCHAR},
      </if>
      <if test="resv2 != null" >
        #{resv2,jdbcType=VARCHAR},
      </if>
      <if test="resv3 != null" >
        #{resv3,jdbcType=VARCHAR},
      </if>
      <if test="isDelete != null" >
        #{isDelete,jdbcType=INTEGER},
      </if>
      <if test="createdAt != null" >
        #{createdAt,jdbcType=TIMESTAMP},
      </if>
      <if test="updatedAt != null" >
        #{updatedAt,jdbcType=TIMESTAMP},
      </if>
      <if test="request != null" >
        #{request,jdbcType=LONGVARCHAR},
      </if>
      <if test="response != null" >
        #{response,jdbcType=LONGVARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitorWithBLOBs" >
    update la_trans_monitor
    <set >
      <if test="sysDate != null" >
        sys_date = #{sysDate,jdbcType=CHAR},
      </if>
      <if test="sysTime != null" >
        sys_time = #{sysTime,jdbcType=CHAR},
      </if>
      <if test="methodType != null" >
        method_type = #{methodType,jdbcType=VARCHAR},
      </if>
      <if test="outerSystem != null" >
        outer_system = #{outerSystem,jdbcType=VARCHAR},
      </if>
      <if test="methodRoute != null" >
        method_route = #{methodRoute,jdbcType=VARCHAR},
      </if>
      <if test="methodName != null" >
        method_name = #{methodName,jdbcType=VARCHAR},
      </if>
      <if test="isException != null" >
        is_exception = #{isException,jdbcType=INTEGER},
      </if>
      <if test="beginTime != null" >
        begin_time = #{beginTime,jdbcType=TIMESTAMP},
      </if>
      <if test="endTime != null" >
        end_time = #{endTime,jdbcType=TIMESTAMP},
      </if>
      <if test="usedTime != null" >
        used_time = #{usedTime,jdbcType=BIGINT},
      </if>
      <if test="ip != null" >
        ip = #{ip,jdbcType=VARCHAR},
      </if>
      <if test="resv1 != null" >
        resv1 = #{resv1,jdbcType=VARCHAR},
      </if>
      <if test="resv2 != null" >
        resv2 = #{resv2,jdbcType=VARCHAR},
      </if>
      <if test="resv3 != null" >
        resv3 = #{resv3,jdbcType=VARCHAR},
      </if>
      <if test="isDelete != null" >
        is_delete = #{isDelete,jdbcType=INTEGER},
      </if>
      <if test="createdAt != null" >
        created_at = #{createdAt,jdbcType=TIMESTAMP},
      </if>
      <if test="updatedAt != null" >
        updated_at = #{updatedAt,jdbcType=TIMESTAMP},
      </if>
      <if test="request != null" >
        request = #{request,jdbcType=LONGVARCHAR},
      </if>
      <if test="response != null" >
        response = #{response,jdbcType=LONGVARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKeyWithBLOBs" parameterType="com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitorWithBLOBs" >
    update la_trans_monitor
    set sys_date = #{sysDate,jdbcType=CHAR},
      sys_time = #{sysTime,jdbcType=CHAR},
      method_type = #{methodType,jdbcType=VARCHAR},
      outer_system = #{outerSystem,jdbcType=VARCHAR},
      method_route = #{methodRoute,jdbcType=VARCHAR},
      method_name = #{methodName,jdbcType=VARCHAR},
      is_exception = #{isException,jdbcType=INTEGER},
      begin_time = #{beginTime,jdbcType=TIMESTAMP},
      end_time = #{endTime,jdbcType=TIMESTAMP},
      used_time = #{usedTime,jdbcType=BIGINT},
      ip = #{ip,jdbcType=VARCHAR},
      resv1 = #{resv1,jdbcType=VARCHAR},
      resv2 = #{resv2,jdbcType=VARCHAR},
      resv3 = #{resv3,jdbcType=VARCHAR},
      is_delete = #{isDelete,jdbcType=INTEGER},
      created_at = #{createdAt,jdbcType=TIMESTAMP},
      updated_at = #{updatedAt,jdbcType=TIMESTAMP},
      request = #{request,jdbcType=LONGVARCHAR},
      response = #{response,jdbcType=LONGVARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.shhxzq.fin.lifeapp.model.credit.vo.LaTransMonitor" >
    update la_trans_monitor
    set sys_date = #{sysDate,jdbcType=CHAR},
      sys_time = #{sysTime,jdbcType=CHAR},
      method_type = #{methodType,jdbcType=VARCHAR},
      outer_system = #{outerSystem,jdbcType=VARCHAR},
      method_route = #{methodRoute,jdbcType=VARCHAR},
      method_name = #{methodName,jdbcType=VARCHAR},
      is_exception = #{isException,jdbcType=INTEGER},
      begin_time = #{beginTime,jdbcType=TIMESTAMP},
      end_time = #{endTime,jdbcType=TIMESTAMP},
      used_time = #{usedTime,jdbcType=BIGINT},
      ip = #{ip,jdbcType=VARCHAR},
      resv1 = #{resv1,jdbcType=VARCHAR},
      resv2 = #{resv2,jdbcType=VARCHAR},
      resv3 = #{resv3,jdbcType=VARCHAR},
      is_delete = #{isDelete,jdbcType=INTEGER},
      created_at = #{createdAt,jdbcType=TIMESTAMP},
      updated_at = #{updatedAt,jdbcType=TIMESTAMP}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

注意点

mysql包依赖5.1.34,如果版本太低,数据库时间相关字段timestamp(3)有可能会漏掉毫秒值,比如:2017-07-02 09:46:21.317,存到数据库中变成2017-07-02 09:46:21.000。

pom.xml
<!-- mysql -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.34</version>
</dependency>

界面相关

界面功能(查询明细,统计,实时监控)我在config_center上做了一套,后端查询record_app的实现。

所以以下代码不属于lifeapp,属于config_center+record_app

query.ftl

query.ftl
<!DOCTYPE html>
<!--
This is a starter template page. Use this page to start your new project from
scratch. This page gets rid of all links and provides the needed markup only.
-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>查看监控</title>
<!-- Tell the browser to be responsive to screen width -->
<meta
	content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
	name="viewport">
<!-- Bootstrap 3.3.6 -->
<link rel="stylesheet" href="${rc.contextPath}/bootstrap/css/bootstrap.min.css">
<!-- Font Awesome -->
<link rel="stylesheet"
	href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
<!-- Ionicons -->
<!-- <link rel="stylesheet"
	href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css"> -->
<!-- Theme style -->
<link rel="stylesheet" href="${rc.contextPath}/dist/css/AdminLTE.min.css">
<!-- AdminLTE Skins. We have chosen the skin-blue for this starter
        page. However, you can choose any other skin. Make sure you
        apply the skin class to the body tag so the changes take effect.
  -->
<link rel="stylesheet" href="${rc.contextPath}/dist/css/skins/skin-blue.min.css">
 
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
  <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  <![endif]-->
<!-- daterange picker -->
<link rel="stylesheet"
	href="${rc.contextPath}/plugins/daterangepicker/daterangepicker.css">
<!-- bootstrap datepicker -->
<link rel="stylesheet" href="${rc.contextPath}/plugins/datepicker/datepicker3.css">
<!-- bootstrap datetimepicker -->
<link rel="stylesheet" href="${rc.contextPath}/plugins/datetimepicker/bootstrap-datetimepicker.css">
 
<!--自动换行-->
<style>
td {
	word-wrap:break-word;
	word-break:break-all;
}
</style>
 
<script src="${rc.contextPath}/js/base.js"></script>
 
<script type="text/javascript">
	var contextPath = "${rc.contextPath}/";
	var monitorArray = new Array();//监控信息集合
	var pageSize = 10;//每页大小
	var activePage = 1;//当前页数
	var totalPage = 0;//总页数
	var totalCount = 0;//总数
	var isRequesting = false;//是否正在与服务器端交互
 
	//查询监控信息
	function queryMonitor(){
		if(isRequesting){
			showAttention("正在与服务器端交互,请稍等!");
			return;
		}
		isRequesting = true;
		$("#monitor_table").css("display", "none");
		$.ajax({
			type: 'POST',
			url: '${rc.contextPath}/monitor/query.htm',
			data: 'methodRoute=' + $("#method_route").val() + '&methodType=' + $("#method_type").val() + '&outerSystem=' + $("#outer_system").val() + 
			'&isException=' + $("#is_exception").val() + '&beginTime=' + $("#begin_time").val() + '&endTime=' + $("#end_time").val() + 
			'&beginUsedTime=' + $("#begin_used_time").val() + '&endUsedTime=' + $("#end_used_time").val() + '&ip=' + $("#ip").val() + '&resv1=' + $("#resv1").val() + '&resv2=' + $("#resv2").val() + 
			'&resv3=' + $("#resv3").val() + '&pageSize=' + pageSize + '&activePage=' + activePage,
			success: function(data) {
				isRequesting = false;
				var obj = data;
				monitorArray = obj.list;
				totalPage = obj.totalPage;
				totalCount = obj.totalCount;
				if(totalPage == 0){
					totalPage = 1;
					activePage = 1;
				}
				showMonitor();
				showSuccess("查询监控成功!");
			}
		});
	}
	//用户监控信息
	function showMonitor(){
		var content = "<div class='box-header with-border'> <h3 class='box-title'>查询结果</h3>"
						+"<div class='box-tools pull-right'>"
			                +"<button type='button' class='btn btn-box-tool' data-widget='collapse'>"
			                	+"<i class='fa fa-minus'></i>"
			                +"</button>"
			                +"<button type='button' class='btn btn-box-tool' data-widget='remove'><i class='fa fa-times'></i></button>"
		              	+"</div></div>"
		+"<div class='box-body table-responsive no-padding'>"
			+"<table class='table table-bordered table-hover' style='width: 2500px;'>"
				+"<tbody>"
					+"<tr>"
						+"<th class='text-center'>主键</th>"
						+"<th class='text-center'>系统日期</th>"
						+"<th class='text-center'>系统时间</th>"
						+"<th class='text-center'>方法路径</th>"
						+"<th class='text-center'>方法名称</th>"
						+"<th class='text-center'>方法类型</th>"
						+"<th class='text-center'>外部系统</th>"
						+"<th class='text-center'>入参</th>"
						+"<th class='text-center'>出参</th>"
						+"<th class='text-center'>是否异常发生</th>"
						+"<th class='text-center'>开始时间</th>"
						+"<th class='text-center'>结束时间</th>"
						+"<th class='text-center'>耗时(毫秒)</th>"
						+"<th class='text-center'>机器ip</th>"
						+"<th class='text-center'>备注字段1</th>"
						+"<th class='text-center'>备注字段2</th>"
						+"<th class='text-center'>备注字段3</th>"
					+"</tr>";
		if(monitorArray.length == 0){
			content += "<tr><td class='text-center' colspan='17'>无相关数据!</td></tr>";
		} else {
			for(var i=0;i<monitorArray.length;i++){
				var obj = monitorArray[i];
				content += "<tr id='tr_" + obj["id"] + "'>"
						+"<td class='text-center'>" + obj["id"] + "</td>"
						+"<td class='text-center'>" + obj["sysDate"] + "</td>"
						+"<td class='text-center'>" + obj["sysTime"] + "</td>"
						+"<td style='width: 300px;overflow:auto;'>" + obj["methodRoute"] + "</td>"
						+"<td class='text-center'>" + obj["methodName"] + "</td>"
						+"<td class='text-center'>" + obj["methodType"] + "</td>"
						+"<td class='text-center'>" + obj["outerSystem"] + "</td>"
						+"<td class='text-center'>" + obj["request"] + "</td>"
						+"<td class='text-center' style='width: 300px;overflow:auto;'>" + obj["response"] + "</td>"
						+"<td class='text-center'>" + obj["isException"] + "</td>"
						+"<td class='text-center'>" + obj["beginTime"] + "</td>"
						+"<td class='text-center'>" + obj["endTime"] + "</td>"
						+"<td class='text-center'>" + obj["usedTime"] + "</td>"
						+"<td class='text-center'>" + obj["ip"] + "</td>"
						+"<td class='text-center'>" + obj["resv1"] + "</td>"
						+"<td class='text-center'>" + obj["resv2"] + "</td>"
						+"<td class='text-center'>" + obj["resv3"] + "</td>"
					+"</tr>";
			}
		}
 
		content += "</tbody>"
			+"</table>"
		+"</div>";
 
		content += getTfoot();
 
		$("#monitor_table").html(content);
		$("#monitor_table").css("display", "block");
	}
	function getTfoot(){
		var content = "<div class='box-footer clearfix'>" + 
		"<ul class='pagination pagination-sm no-margin pull-right'>" + 
		"<li>" + "<a>总数:[" + totalCount + "] 总页数:[" + totalPage + "]</a>" + "</li>" +
		"<li><a href=\"javascript: jump2page(1)\" title=\"首页\">&laquo; 首页</a></li>";   
	    if(activePage > 1){
			content += "<li><a href=\"javascript: jump2page(" + (activePage-1) + ")\" title=\"上一页\">&laquo; 上一页</a></li>";
	    }
		//显示前2页,本页,后2页
		for(var i=activePage-2;i<activePage+3;i++){
			if(i >= 1 && i <= totalPage){
				content += "<li" + (i==activePage?" class='active'":"") + "><a href=\"javascript: jump2page(" + i + ")\" class=\"number" + ((i==activePage)?" current":"") + "\" title=\"" + i + "\">" + i + "</a></li>";
			}
		}
	    if(activePage < totalPage){
			content += "<li><a href=\"javascript: jump2page(" + (activePage+1) + ")\" title=\"下一页\">下一页 &raquo;</a></li>";
		}
		content += "<li><a href=\"javascript: jump2page(" + totalPage + ")\" title=\"尾页\">尾页 &raquo;</a></li>" + 
	                "</ul>" + 
	                "</div>";
	    return content;
	}
	function jump2page(index){
		activePage = index;
		queryMonitor();
	}
 
	//统计监控信息
	function countMonitor(){
		if(isRequesting){
			showAttention("正在与服务器端交互,请稍等!");
			return;
		}
		isRequesting = true;
		$("#monitor_table").css("display", "none");
		$.ajax({
			type: 'POST',
			url: '${rc.contextPath}/monitor/count.htm',
			data: 'methodRoute=' + $("#method_route").val() + '&methodType=' + $("#method_type").val() + '&outerSystem=' + $("#outer_system").val() + 
			'&isException=' + $("#is_exception").val() + '&beginTime=' + $("#begin_time").val() + '&endTime=' + $("#end_time").val() + 
			'&beginUsedTime=' + $("#begin_used_time").val() + '&endUsedTime=' + $("#end_used_time").val() + '&ip=' + $("#ip").val() + '&resv1=' + $("#resv1").val() + '&resv2=' + $("#resv2").val() + 
			'&resv3=' + $("#resv3").val() + '&pageSize=' + pageSize + '&activePage=' + activePage,
			success: function(data) {
				isRequesting = false;
				showCountMonitor(data);
				showSuccess("统计监控成功!");
			}
		});
	}
	//统计监控信息
	function showCountMonitor(obj){
		var content = "<div class='box-header with-border'> <h3 class='box-title'>统计结果</h3>"
						+"<div class='box-tools pull-right'>"
			                +"<button type='button' class='btn btn-box-tool' data-widget='collapse'>"
			                	+"<i class='fa fa-minus'></i>"
			                +"</button>"
			                +"<button type='button' class='btn btn-box-tool' data-widget='remove'><i class='fa fa-times'></i></button>"
		              	+"</div></div>"
		+"<div class='box-body table-responsive no-padding'>"
			+"<table class='table table-bordered table-hover'>"
				+"<tbody>"
					+"<tr>"
						+"<th class='text-center'>并发数</th>"
						+"<th class='text-center'>平均耗时(毫秒)</th>"
						+"<th class='text-center'>tps(事务数/秒)</th>"
					+"</tr>";
 
		content += "<tr>"
						+"<td class='text-center'>" + obj.totalCount + "</td>"
						+"<td class='text-center'>" + obj.avgUsedTime + "</td>"
						+"<td class='text-center'>" + obj.tps + "</td>"
					+"</tr>";
 
		content += "</tbody>"
			+"</table>"
		+"</div>";
 
		$("#monitor_table").html(content);
		$("#monitor_table").css("display", "block");
	}
</script>
 
<style type="text/css">
div.alert {
	padding-top: 5px;
	padding-bottom: 5px
}
</style>
 
</head>
<!--
BODY TAG OPTIONS:
=================
Apply one or more of the following classes to get the
desired effect
|---------------------------------------------------------|
| SKINS         | skin-blue                               |
|               | skin-black                              |
|               | skin-purple                             |
|               | skin-yellow                             |
|               | skin-red                                |
|               | skin-green                              |
|---------------------------------------------------------|
|LAYOUT OPTIONS | fixed                                   |
|               | layout-boxed                            |
|               | layout-top-nav                          |
|               | sidebar-collapse                        |
|               | sidebar-mini                            |
|---------------------------------------------------------|
-->
<body class="hold-transition skin-blue sidebar-mini">
	<div class="wrapper">
 
		<!-- Main Header -->
		<header class="main-header">
 
			<!-- Logo -->
			<a href="index2.html" class="logo"> <!-- mini logo for sidebar mini 50x50 pixels -->
				<span class="logo-mini"><b>RA</b></span> <!-- logo for regular state and mobile devices -->
				<span class="logo-lg"><b>Record App</b></span>
			</a>
 
			<!-- Header Navbar -->
			<nav class="navbar navbar-static-top" role="navigation">
				<!-- Sidebar toggle button-->
				<a href="#" class="sidebar-toggle" data-toggle="offcanvas"
					role="button"> <span class="sr-only">Toggle navigation</span>
				</a>
				<!-- Navbar Right Menu -->
				<div class="navbar-custom-menu">
					<ul class="nav navbar-nav">
						<!-- User Account Menu -->
						<li class="dropdown user user-menu">
							<!-- Menu Toggle Button --> <a href="#" class="dropdown-toggle"
							data-toggle="dropdown"> <!-- The user image in the navbar-->
								<img src="${rc.contextPath}/dist/img/user2-160x160.jpg" class="user-image"
								alt="User Image"> <!-- hidden-xs hides the username on small devices so only the image appears. -->
								<span class="hidden-xs">管理员</span>
						</a>
							<ul class="dropdown-menu">
								<!-- The user image in the menu -->
								<li class="user-header"><img
									src="${rc.contextPath}/dist/img/user2-160x160.jpg" class="img-circle"
									alt="User Image">
 
									<p>
										管理员 <small>您已成功登录</small>
									</p></li>
								<!-- Menu Footer-->
								<li class="user-footer">
									<div class="pull-right">
										<a href="${rc.contextPath}/logout.htm" class="btn btn-default btn-flat">退出</a>
									</div>
								</li>
							</ul>
						</li>
					</ul>
				</div>
			</nav>
		</header>
		<!-- Left side column. contains the logo and sidebar -->
		<aside class="main-sidebar">
 
			<!-- sidebar: style can be found in sidebar.less -->
			<section class="sidebar">
 
				<!-- Sidebar user panel (optional) -->
				<div class="user-panel">
					<div class="pull-left image">
						<img src="${rc.contextPath}/dist/img/user2-160x160.jpg" class="img-circle"
							alt="User Image">
					</div>
					<div class="pull-left info">
						<p>管理员</p>
						<!-- Status -->
						<a href="#"><i class="glyphicon glyphicon-record text-success"></i> 已登录</a>
					</div>
				</div>
 
				<!-- Sidebar Menu -->
				<ul class="sidebar-menu">
					<li class="header">配置</li>
					<!-- Optionally, you can add icons to the links -->
					<li>
						<a href="${rc.contextPath}/index.htm">
							<i class="glyphicon glyphicon-search"></i>
							<span>查询配置</span>
						</a>
					</li>
					<li>
						<a href="${rc.contextPath}/config/add.htm">
							<i class="glyphicon glyphicon-pencil"></i>
							<span>新增配置</span>
						</a>
					</li>
					<li class="header">交易监控</li>
					<!-- Optionally, you can add icons to the links -->
					<li class="active">
						<a href="${rc.contextPath}/monitor/query.htm">
							<i class="glyphicon glyphicon-search"></i>
							<span>监控查询</span>
						</a>
					</li>
					<li>
						<a href="${rc.contextPath}/monitor/realtime.htm">
							<i class="glyphicon glyphicon-search"></i>
							<span>实时监控</span>
						</a>
					</li>
				</ul>
				<!-- /.sidebar-menu -->
			</section>
			<!-- /.sidebar -->
		</aside>
 
		<!-- Content Wrapper. Contains page content -->
		<div class="content-wrapper">
			<!-- Main content -->
			<section class="content">
 
			<div id="message_id" style="display: none;"></div>
 
				<div class="box box-primary">
					<div class="box-header with-border">
						<h3 class="box-title">监控查询</h3>
						<div class="box-tools pull-right">
			                <button type="button" class="btn btn-box-tool" data-widget="collapse">
			                	<i class="fa fa-minus"></i>
			                </button>
			                <button type="button" class="btn btn-box-tool" data-widget="remove"><i class="fa fa-times"></i></button>
		              	</div>
					</div>
					<!-- /.box-header -->
					<div class="box-body">
 
						<div class="row">
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>方法路径</label>
								<select class="form-control" id="method_route">
									<option value="">全部</option>
									<#if Session.method_route_list?exists>
										<#list Session.method_route_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>方法类型</label>
								<select class="form-control" id="method_type">
									<option value="">全部</option>
									<#if Session.method_type_list?exists>
										<#list Session.method_type_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>外部系统</label>
								<select class="form-control" id="outer_system">
									<option value="">全部</option>
									<#if Session.outer_system_list?exists>
										<#list Session.outer_system_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>是否异常发生</label>
								<select class="form-control" id="is_exception">
									<option value="">全部</option>
									<#if Session.is_exception_list?exists>
										<#list Session.is_exception_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>开始时间</label>
								<div class="input-group date">
									<div class="input-group-addon">
										<i class="glyphicon glyphicon-calendar"></i>
									</div>
									<input type="text" class="form-control pull-right" id="begin_time">
								</div>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>结束时间</label>
								<div class="input-group date">
									<div class="input-group-addon">
										<i class="glyphicon glyphicon-calendar"></i>
									</div>
									<input type="text" class="form-control pull-right" id="end_time">
								</div>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>最小耗时(毫秒)(>=)</label>
								<input type="text" class="form-control"
									placeholder="Enter ..." id="begin_used_time">
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>最大耗时(毫秒)(<=)</label>
								<input type="text" class="form-control"
									placeholder="Enter ..." id="end_used_time">
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>机器ip</label>
								<select class="form-control" id="ip">
									<option value="">全部</option>
									<#if Session.ip_list?exists>
										<#list Session.ip_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>备注字段1</label>
								<input type="text" class="form-control"
									placeholder="Enter ..." id="resv1">
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>备注字段2</label>
								<input type="text" class="form-control"
									placeholder="Enter ..." id="resv2">
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>备注字段3</label>
								<input type="text" class="form-control"
									placeholder="Enter ..." id="resv3">
							</div>
							<div class="col-xs-6 col-sm-3 col-md-2">
								<label>&nbsp;</label>
								<button type="button" class="btn btn-block btn-primary"
									onclick="activePage=1;queryMonitor();">查询</button>
							</div>
							<div class="col-xs-6 col-sm-3 col-md-2">
								<label>&nbsp;</label>
								<button type="button" class="btn btn-block btn-primary"
									onclick="activePage=1;countMonitor();">统计</button>
							</div>
						</div>
					</div>
				</div>
 
				<div id="monitor_table" class="box box-primary"
					style="display: none;">
					<div class="box-header with-border">
						<h3 class="box-title">查询结果</h3>
					</div>
					<!-- /.box-header -->
					<div class="box-body table-responsive no-padding">
						<table class="table table-hover">
							<tbody>
								<tr>
									<th style="width: 10px">ID</th>
									<th>环境</th>
									<th>项目</th>
									<th>监控名</th>
									<th>监控值</th>
									<th>描述</th>
									<th style="width: 60px">操作</th>
								</tr>
								<tr>
									<td>1.</td>
									<td>Update software</td>
									<td>Update software</td>
									<td>Update software</td>
									<td>Update software</td>
									<td>Update software</td>
									<td>ware</td>
								</tr>
								<tr>
									<td>2.</td>
									<td>Update software</td>
									<td>Update software</td>
									<td>Update software</td>
									<td>Update software</td>
									<td>Update software</td>
									<td>ware</td>
								</tr>
							</tbody>
						</table>
					</div>
					<!-- /.box-body -->
					<div class="box-footer clearfix">
						<ul class="pagination pagination-sm no-margin pull-right">
							<li><a href="#">«</a></li>
							<li><a href="#">1</a></li>
							<li><a href="#">2</a></li>
							<li><a href="#">3</a></li>
							<li><a href="#">»</a></li>
						</ul>
					</div>
				</div>
				<!-- /.box -->
 
			</section>
			<!-- /.content -->
		</div>
		<!-- /.content-wrapper -->
 
		<!-- Main Footer -->
		<footer class="main-footer">
			<!-- To the right -->
			<div class="pull-right hidden-xs">Anything you want</div>
			<!-- Default to the left -->
			<strong>Copyright &copy; 2016 <a href="#">Company</a>.
			</strong> All rights reserved.
		</footer>
 
		<!-- Add the sidebar's background. This div must be placed
       immediately after the control sidebar -->
		<div class="control-sidebar-bg"></div>
	</div>
	<!-- ./wrapper -->
 
	<!-- REQUIRED JS SCRIPTS -->
 
	<!-- jQuery 2.2.3 -->
	<script src="${rc.contextPath}/plugins/jQuery/jquery-2.2.3.min.js"></script>
	<!-- Bootstrap 3.3.6 -->
	<script src="${rc.contextPath}/bootstrap/js/bootstrap.min.js"></script>
	<!-- AdminLTE App -->
	<script src="${rc.contextPath}/dist/js/app.min.js"></script>
	<!-- bootstrap datepicker -->
	<script src="${rc.contextPath}/plugins/datetimepicker/bootstrap-datetimepicker.js"></script>
 
	<script type="text/javascript">
		//DateTime picker
		$('#begin_time').datetimepicker({format: 'yyyy-mm-dd hh:ii'});
		//DateTime picker
		$('#end_time').datetimepicker({format: 'yyyy-mm-dd hh:ii'});
	</script>
 
	<!-- Optionally, you can add Slimscroll and FastClick plugins.
     Both of these plugins are recommended to enhance the
     user experience. Slimscroll is required when using the
     fixed layout. -->
</body>
</html>

realtime.ftl

realtime.ftl
<!DOCTYPE html>
<!--
This is a starter template page. Use this page to start your new project from
scratch. This page gets rid of all links and provides the needed markup only.
-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>实时监控</title>
<!-- Tell the browser to be responsive to screen width -->
<meta
	content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
	name="viewport">
<!-- Bootstrap 3.3.6 -->
<link rel="stylesheet" href="${rc.contextPath}/bootstrap/css/bootstrap.min.css">
<!-- Font Awesome -->
<link rel="stylesheet"
	href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
<!-- Ionicons -->
<!-- <link rel="stylesheet"
	href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css"> -->
<!-- Theme style -->
<link rel="stylesheet" href="${rc.contextPath}/dist/css/AdminLTE.min.css">
<!-- AdminLTE Skins. We have chosen the skin-blue for this starter
        page. However, you can choose any other skin. Make sure you
        apply the skin class to the body tag so the changes take effect.
  -->
<link rel="stylesheet" href="${rc.contextPath}/dist/css/skins/skin-blue.min.css">
 
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
  <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  <![endif]-->
<!-- daterange picker -->
<link rel="stylesheet"
	href="${rc.contextPath}/plugins/daterangepicker/daterangepicker.css">
<!-- bootstrap datepicker -->
<link rel="stylesheet" href="${rc.contextPath}/plugins/datepicker/datepicker3.css">
<!-- bootstrap datetimepicker -->
<link rel="stylesheet" href="${rc.contextPath}/plugins/datetimepicker/bootstrap-datetimepicker.css">
 
<!--自动换行-->
<style>
td {
	word-wrap:break-word;
	word-break:break-all;
}
</style>
 
<script src="${rc.contextPath}/js/base.js"></script>
 
<script type="text/javascript">
	var contextPath = "${rc.contextPath}/";
	var monitorArray = new Array();//监控信息集合
	var pageSize = 10;//每页大小
	var activePage = 1;//当前页数
	var totalPage = 0;//总页数
	var totalCount = 0;//总数
	var isRequesting = false;//是否正在与服务器端交互
 
	var avgUsedTime = 0;//平均耗时
	var tps = 0;//tps
	var nowBeginTimeString = "";//当前开始统计时间
	var nowEndTimeString = "";//当前开始统计时间
 
	//历史统计
	function queryHistory() {
		var beginTime = $("#begin_time").val();
		var endTime = $("#end_time").val();
		if("" == beginTime || "" == endTime) {
			showAttention("请选择[历史开始时间]和[历史结束时间]!");
			return;
		}
		if(beginTime >= endTime) {
			showAttention("[历史开始时间]必须小于[历史结束时间]!");
			return;
		}
		var beginTimeObj = parseDate(beginTime, 'yyyy-MM-dd HH:mm');
		var endTimeObj = parseDate(endTime, 'yyyy-MM-dd HH:mm');
		var gap = parseInt($("#gap").val()) * 1000;
 
		if((endTimeObj.getTime() - beginTimeObj.getTime())/gap > 60) {
			showAttention("取点时间间隔太小,取点太多,服务器扛不住!");
			return;
		}
 
		config.data.labels = new Array();
		config.data.datasets[0].data = new Array();
		config.data.datasets[1].data = new Array();
		config.data.datasets[2].data = new Array();
 
		//formatDate()
		var nowBeginTime = beginTimeObj.getTime();
		var nowEndTime = nowBeginTime + gap;
		nowBeginTimeString = formatDate(nowBeginTime);
		nowEndTimeString = formatDate(nowEndTime);
		countMonitor();//统计监控信息
 
		nowBeginTime = nowEndTime;
		nowEndTime = nowBeginTime + gap;
		while(nowBeginTime <= endTimeObj.getTime()) {
			nowBeginTimeString = formatDate(nowBeginTime);
			nowEndTimeString = formatDate(nowEndTime);
			countMonitor();//统计监控信息
			nowBeginTime = nowEndTime;
			nowEndTime = nowBeginTime + gap;
		}
	}
 
	//统计监控信息
	function countMonitor(){
		if(isRequesting){
			showAttention("正在与服务器端交互,请稍等!");
			return;
		}
		isRequesting = true;
		$.ajax({
			type: 'POST',
			async: false,
			url: '${rc.contextPath}/monitor/count.htm',
			data: 'methodRoute=' + $("#method_route").val() + '&methodType=' + $("#method_type").val() + '&outerSystem=' + $("#outer_system").val() + 
			'&isException=' + $("#is_exception").val() + '&beginTime=' + nowBeginTimeString + '&endTime=' + nowEndTimeString + 
			'&ip=' + $("#ip").val() + '&resv1=' + $("#resv1").val() + '&resv2=' + $("#resv2").val() + 
			'&resv3=' + $("#resv3").val() + '&pageSize=' + pageSize + '&activePage=' + activePage,
			success: function(data) {
				isRequesting = false;
				totalCount = data.totalCount;
				avgUsedTime = data.avgUsedTime;
				tps = data.tps;
 
				config.data.labels.push(nowBeginTimeString);
				config.data.datasets[0].data.push(totalCount);
				config.data.datasets[1].data.push(avgUsedTime);
				config.data.datasets[2].data.push(tps);
                window.myLine.update();
			}
		});
	}
 
	//实时统计
	function realtimeCount() {
		//待实现
	}
</script>
 
<style type="text/css">
div.alert {
	padding-top: 5px;
	padding-bottom: 5px
}
</style>
 
</head>
<!--
BODY TAG OPTIONS:
=================
Apply one or more of the following classes to get the
desired effect
|---------------------------------------------------------|
| SKINS         | skin-blue                               |
|               | skin-black                              |
|               | skin-purple                             |
|               | skin-yellow                             |
|               | skin-red                                |
|               | skin-green                              |
|---------------------------------------------------------|
|LAYOUT OPTIONS | fixed                                   |
|               | layout-boxed                            |
|               | layout-top-nav                          |
|               | sidebar-collapse                        |
|               | sidebar-mini                            |
|---------------------------------------------------------|
-->
<body class="hold-transition skin-blue sidebar-mini">
	<div class="wrapper">
 
		<!-- Main Header -->
		<header class="main-header">
 
			<!-- Logo -->
			<a href="index2.html" class="logo"> <!-- mini logo for sidebar mini 50x50 pixels -->
				<span class="logo-mini"><b>RA</b></span> <!-- logo for regular state and mobile devices -->
				<span class="logo-lg"><b>Record App</b></span>
			</a>
 
			<!-- Header Navbar -->
			<nav class="navbar navbar-static-top" role="navigation">
				<!-- Sidebar toggle button-->
				<a href="#" class="sidebar-toggle" data-toggle="offcanvas"
					role="button"> <span class="sr-only">Toggle navigation</span>
				</a>
				<!-- Navbar Right Menu -->
				<div class="navbar-custom-menu">
					<ul class="nav navbar-nav">
						<!-- User Account Menu -->
						<li class="dropdown user user-menu">
							<!-- Menu Toggle Button --> <a href="#" class="dropdown-toggle"
							data-toggle="dropdown"> <!-- The user image in the navbar-->
								<img src="${rc.contextPath}/dist/img/user2-160x160.jpg" class="user-image"
								alt="User Image"> <!-- hidden-xs hides the username on small devices so only the image appears. -->
								<span class="hidden-xs">管理员</span>
						</a>
							<ul class="dropdown-menu">
								<!-- The user image in the menu -->
								<li class="user-header"><img
									src="${rc.contextPath}/dist/img/user2-160x160.jpg" class="img-circle"
									alt="User Image">
 
									<p>
										管理员 <small>您已成功登录</small>
									</p></li>
								<!-- Menu Footer-->
								<li class="user-footer">
									<div class="pull-right">
										<a href="${rc.contextPath}/logout.htm" class="btn btn-default btn-flat">退出</a>
									</div>
								</li>
							</ul>
						</li>
					</ul>
				</div>
			</nav>
		</header>
		<!-- Left side column. contains the logo and sidebar -->
		<aside class="main-sidebar">
 
			<!-- sidebar: style can be found in sidebar.less -->
			<section class="sidebar">
 
				<!-- Sidebar user panel (optional) -->
				<div class="user-panel">
					<div class="pull-left image">
						<img src="${rc.contextPath}/dist/img/user2-160x160.jpg" class="img-circle"
							alt="User Image">
					</div>
					<div class="pull-left info">
						<p>管理员</p>
						<!-- Status -->
						<a href="#"><i class="glyphicon glyphicon-record text-success"></i> 已登录</a>
					</div>
				</div>
 
				<!-- Sidebar Menu -->
				<ul class="sidebar-menu">
					<li class="header">配置</li>
					<!-- Optionally, you can add icons to the links -->
					<li>
						<a href="${rc.contextPath}/index.htm">
							<i class="glyphicon glyphicon-search"></i>
							<span>查询配置</span>
						</a>
					</li>
					<li>
						<a href="${rc.contextPath}/config/add.htm">
							<i class="glyphicon glyphicon-pencil"></i>
							<span>新增配置</span>
						</a>
					</li>
					<li class="header">交易监控</li>
					<!-- Optionally, you can add icons to the links -->
					<li>
						<a href="${rc.contextPath}/monitor/query.htm">
							<i class="glyphicon glyphicon-search"></i>
							<span>监控查询</span>
						</a>
					</li>
					<li class="active">
						<a href="${rc.contextPath}/monitor/realtime.htm">
							<i class="glyphicon glyphicon-search"></i>
							<span>实时监控</span>
						</a>
					</li>
				</ul>
				<!-- /.sidebar-menu -->
			</section>
			<!-- /.sidebar -->
		</aside>
 
		<!-- Content Wrapper. Contains page content -->
		<div class="content-wrapper">
			<!-- Main content -->
			<section class="content">
 
			<div id="message_id" style="display: none;"></div>
 
				<div class="box box-primary">
					<div class="box-header with-border">
						<h3 class="box-title">实时监控</h3>
						<div class="box-tools pull-right">
			                <button type="button" class="btn btn-box-tool" data-widget="collapse">
			                	<i class="fa fa-minus"></i>
			                </button>
			                <button type="button" class="btn btn-box-tool" data-widget="remove"><i class="fa fa-times"></i></button>
		              	</div>
					</div>
					<!-- /.box-header -->
					<div class="box-body">
 
						<div class="row">
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>方法路径</label>
								<select class="form-control" id="method_route">
									<option value="">全部</option>
									<#if Session.method_route_list?exists>
										<#list Session.method_route_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>方法类型</label>
								<select class="form-control" id="method_type">
									<option value="">全部</option>
									<#if Session.method_type_list?exists>
										<#list Session.method_type_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>外部系统</label>
								<select class="form-control" id="outer_system">
									<option value="">全部</option>
									<#if Session.outer_system_list?exists>
										<#list Session.outer_system_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>是否异常发生</label>
								<select class="form-control" id="is_exception">
									<option value="">全部</option>
									<#if Session.is_exception_list?exists>
										<#list Session.is_exception_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>机器ip</label>
								<select class="form-control" id="ip">
									<option value="">全部</option>
									<#if Session.ip_list?exists>
										<#list Session.ip_list as node>
											<option value="${node}">${node}</option>
										</#list>
									</#if>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>备注字段1</label>
								<input type="text" class="form-control"
									placeholder="Enter ..." id="resv1">
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>备注字段2</label>
								<input type="text" class="form-control"
									placeholder="Enter ..." id="resv2">
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>备注字段3</label>
								<input type="text" class="form-control"
									placeholder="Enter ..." id="resv3">
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>取点时间间隔</label>
								<select class="form-control" id="gap">
									<option value="60" selected>1分钟</option>
									<option value="600">10分钟</option>
									<option value="1800">30分钟</option>
									<option value="3600">1小时</option>
									<option value="43200">12小时</option>
									<option value="86400">1天</option>
								</select>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>&nbsp;</label>
								<button type="button" class="btn btn-block btn-primary"
									onclick="activePage=1;realtimeCount();">实时统计</button>
							</div>
						</div>
						<div class="row">
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>历史开始时间</label>
								<div class="input-group date">
									<div class="input-group-addon">
										<i class="glyphicon glyphicon-calendar"></i>
									</div>
									<input type="text" class="form-control pull-right" id="begin_time">
								</div>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>历史结束时间</label>
								<div class="input-group date">
									<div class="input-group-addon">
										<i class="glyphicon glyphicon-calendar"></i>
									</div>
									<input type="text" class="form-control pull-right" id="end_time">
								</div>
							</div>
							<div class="col-xs-12 col-sm-6 col-md-4">
								<label>&nbsp;</label>
								<button type="button" class="btn btn-block btn-primary"
									onclick="activePage=1;queryHistory();">历史统计</button>
							</div>
						</div>
					</div>
				</div>
 
				<canvas id="canvas"></canvas>
				<!-- /.box -->
 
			</section>
			<!-- /.content -->
		</div>
		<!-- /.content-wrapper -->
 
		<!-- Main Footer -->
		<footer class="main-footer">
			<!-- To the right -->
			<div class="pull-right hidden-xs">Anything you want</div>
			<!-- Default to the left -->
			<strong>Copyright &copy; 2016 <a href="#">Company</a>.
			</strong> All rights reserved.
		</footer>
 
		<!-- Add the sidebar's background. This div must be placed
       immediately after the control sidebar -->
		<div class="control-sidebar-bg"></div>
	</div>
	<!-- ./wrapper -->
 
	<!-- REQUIRED JS SCRIPTS -->
 
	<!-- jQuery 2.2.3 -->
	<script src="${rc.contextPath}/plugins/jQuery/jquery-2.2.3.min.js"></script>
	<!-- Bootstrap 3.3.6 -->
	<script src="${rc.contextPath}/bootstrap/js/bootstrap.min.js"></script>
	<!-- AdminLTE App -->
	<script src="${rc.contextPath}/dist/js/app.min.js"></script>
	<!-- bootstrap datepicker -->
	<script src="${rc.contextPath}/plugins/datetimepicker/bootstrap-datetimepicker.js"></script>
	<!-- http://www.chartjs.org/ -->
	<script src="http://www.chartjs.org/dist/2.6.0/Chart.bundle.js"></script>
	<script src="http://www.chartjs.org/samples/latest/utils.js"></script>
 
	<script type="text/javascript">
		//DateTime picker
		$('#begin_time').datetimepicker({format: 'yyyy-mm-dd hh:ii'});
		//DateTime picker
		$('#end_time').datetimepicker({format: 'yyyy-mm-dd hh:ii'});
 
        var config = {
            type: 'line',
            data: {
                labels: [],
                datasets: [{
                    label: "并发数",
                    fill: false,
                    backgroundColor: window.chartColors.red,
                    borderColor: window.chartColors.red,
                    data: [
                    ],
                }, {
                    label: "平均耗时(毫秒)",
                    fill: false,
                    backgroundColor: window.chartColors.blue,
                    borderColor: window.chartColors.blue,
                    data: [
                    ],
                }, {
                    label: "tps(事务数/秒)",
                    fill: false,
                    backgroundColor: window.chartColors.yellow,
                    borderColor: window.chartColors.yellow,
                    data: [
                    ],
                }]
            },
            options: {
                responsive: true,
                title:{
                    display:true,
                    text:'记录点滴APP交易监控'
                },
                tooltips: {
                    mode: 'index',
                    intersect: false,
                },
                hover: {
                    mode: 'nearest',
                    intersect: true
                },
                scales: {
                    xAxes: [{
                        display: true,
                        scaleLabel: {
                            display: true,
                            labelString: '时段'
                        }
                    }],
                    yAxes: [{
                        display: true,
                        scaleLabel: {
                            display: true,
                            labelString: '值'
                        }
                    }]
                }
            }
        };
 
        window.onload = function() {
            var ctx = document.getElementById("canvas").getContext("2d");
            window.myLine = new Chart(ctx, config);
        };
 
	</script>
 
	<!-- Optionally, you can add Slimscroll and FastClick plugins.
     Both of these plugins are recommended to enhance the
     user experience. Slimscroll is required when using the
     fixed layout. -->
</body>
</html>

MonitorController.java

config_center下的

MonitorController.java
package com.gxx.config_center.web.monitor;
 
import java.util.HashMap;
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
 
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
 
import com.alibaba.fastjson.JSONArray;
import com.gxx.config_center.dto.MonitorDto;
import com.gxx.config_center.interfaces.BaseInterface;
import com.gxx.config_center.interfaces.MonitorInterface;
import com.gxx.config_center.utils.HttpClientUtils;
 
/**
 * <dl>
 *    <dt><b>Title:</b></dt>
 *    <dd>
 *    	none
 *    </dd>
 *    <dt><b>Description:监控控制器</b></dt>
 *    <dd>
 *    	<p>none
 *    </dd>
 * </dl>
 *
 * @author Administrator
 * @version 1.0, 2017年06月21日
 * @since config_center
 */
@Controller
@RequestMapping("/monitor/")
public class MonitorController {
	/**
	 * 日志处理器
	 */
	private final Logger logger = Logger.getLogger(MonitorController.class);
 
	/**
	 * 访问交易监控查询页面
	 * @return
	 */
	@RequestMapping(value = "/query", method = RequestMethod.GET)
	public String queryGet(HttpServletRequest request) {
		if(null == request.getSession().getAttribute(BaseInterface.KEY_USER)){
			logger.info("访问account/login");
			return "account/login";
		}
 
		/**
		 * 初始化session
		 */
		initSession(request);
 
		logger.info("访问monitor/query");
		return "monitor/query";
	}
 
	/**
	 * 交易监控查询
	 * @param request
	 * @param monitorDto
	 * @return
	 */
	@RequestMapping(value = "/query", method = RequestMethod.POST, produces="application/json")
	public @ResponseBody String query(HttpServletRequest request, MonitorDto monitorDto) {
		logger.info("交易监控查询,方法路径:[" + monitorDto.getMethodRoute() + "],方法类型:[" + monitorDto.getMethodType() + "]"
				+ ",外部系统:[" + monitorDto.getOuterSystem() + "],是否异常发生:[" + monitorDto.getIsException() + "]"
				+ ",开始时间:[" + monitorDto.getBeginTime() + "],结束时间:[" + monitorDto.getEndTime() + "]"
				+ ",最小耗时(毫秒)(>=):[" + monitorDto.getBeginUsedTime() + "],最大耗时(毫秒)(<=):[" + monitorDto.getEndUsedTime() + "]"
				+ ",机器ip:[" + monitorDto.getIp() + "]"
				+ ",备注字段1:[" + monitorDto.getResv1() + "],备注字段2:[" + monitorDto.getResv2() + "]"
				+ ",备注字段3:[" + monitorDto.getResv3() + "],每页个数:[" + monitorDto.getPageSize() + "]"
				+ ",当前页数:[" + monitorDto.getActivePage() + "]");
		/**
		 * 判登录
		 */
		if(null == request.getSession().getAttribute(BaseInterface.KEY_USER)){
			logger.info("请先登录!");
			return "{isSuccess:false,message:'请先登录!'}";
		}
 
		/**
		 * 调record_app查询
		 */
		String url = "http://121.43.104.34:8080/record_app/monitor/query.htm";
		Map<String, String> mapData = new HashMap<String, String>();
		mapData.put("methodRoute", monitorDto.getMethodRoute());
		mapData.put("methodType", processColon(monitorDto.getMethodType()));
		mapData.put("outerSystem", processColon(monitorDto.getOuterSystem()));
		mapData.put("isException", StringUtils.isBlank(monitorDto.getIsException())?"-1":processColon(monitorDto.getIsException()));
		mapData.put("beginTime", monitorDto.getBeginTime());
		mapData.put("endTime", monitorDto.getEndTime());
		mapData.put("beginUsedTime", StringUtils.isBlank(monitorDto.getBeginUsedTime())?"-1":monitorDto.getBeginUsedTime());
		mapData.put("endUsedTime", StringUtils.isBlank(monitorDto.getEndUsedTime())?"-1":monitorDto.getEndUsedTime());
		mapData.put("ip", monitorDto.getIp());
		mapData.put("resv1", monitorDto.getResv1());
		mapData.put("resv2", monitorDto.getResv2());
		mapData.put("resv3", monitorDto.getResv3());
		mapData.put("pageSize", StringUtils.EMPTY + monitorDto.getPageSize());
		mapData.put("activePage", StringUtils.EMPTY + monitorDto.getActivePage());
		return HttpClientUtils.getWebContentByPost(url, mapData, "utf-8");
	}
 
	/**
	 * 交易监控统计
	 * @param request
	 * @param monitorDto
	 * @return
	 */
	@RequestMapping(value = "/count", method = RequestMethod.POST, produces="application/json")
	public @ResponseBody String count(HttpServletRequest request, MonitorDto monitorDto) {
		logger.info("交易监控查询,方法路径:[" + monitorDto.getMethodRoute() + "],方法类型:[" + monitorDto.getMethodType() + "]"
				+ ",外部系统:[" + monitorDto.getOuterSystem() + "],是否异常发生:[" + monitorDto.getIsException() + "]"
				+ ",开始时间:[" + monitorDto.getBeginTime() + "],结束时间:[" + monitorDto.getEndTime() + "]"
				+ ",最小耗时(毫秒)(>=):[" + monitorDto.getBeginUsedTime() + "],最大耗时(毫秒)(<=):[" + monitorDto.getEndUsedTime() + "]"
				+ ",机器ip:[" + monitorDto.getIp() + "]"
				+ ",备注字段1:[" + monitorDto.getResv1() + "],备注字段2:[" + monitorDto.getResv2() + "]"
				+ ",备注字段3:[" + monitorDto.getResv3() + "]");
		/**
		 * 判登录
		 */
		if(null == request.getSession().getAttribute(BaseInterface.KEY_USER)){
			logger.info("请先登录!");
			return "{isSuccess:false,message:'请先登录!'}";
		}
 
		/**
		 * 调record_app查询
		 */
		String url = "http://121.43.104.34:8080/record_app/monitor/count.htm";
		Map<String, String> mapData = new HashMap<String, String>();
		mapData.put("methodRoute", monitorDto.getMethodRoute());
		mapData.put("methodType", processColon(monitorDto.getMethodType()));
		mapData.put("outerSystem", processColon(monitorDto.getOuterSystem()));
		mapData.put("isException", StringUtils.isBlank(monitorDto.getIsException())?"-1":processColon(monitorDto.getIsException()));
		mapData.put("beginTime", monitorDto.getBeginTime());
		mapData.put("endTime", monitorDto.getEndTime());
		mapData.put("beginUsedTime", StringUtils.isBlank(monitorDto.getBeginUsedTime())?"-1":monitorDto.getBeginUsedTime());
		mapData.put("endUsedTime", StringUtils.isBlank(monitorDto.getEndUsedTime())?"-1":monitorDto.getEndUsedTime());
		mapData.put("ip", monitorDto.getIp());
		mapData.put("resv1", monitorDto.getResv1());
		mapData.put("resv2", monitorDto.getResv2());
		mapData.put("resv3", monitorDto.getResv3());
		return HttpClientUtils.getWebContentByPost(url, mapData, "utf-8");
	}
 
	/**
	 * 处理字符串,含有:,则返回:之前的字符
	 * @param string
	 * @return
	 */
	private String processColon(String string) {
		int index = StringUtils.indexOf(string, ":");
		if(index > -1) {
			string = string.substring(0, index);
		}
		return string;
	}
 
	/**
	 * 初始化session
	 * @param request
	 */
	public void initSession(HttpServletRequest request) {
		/**
		 * 调record_app查询
		 */
		String url = "http://121.43.104.34:8080/record_app/monitor/queryAllMethodRoutes.htm";
		String methodRoutes = HttpClientUtils.getWebContentByGet(url, "utf-8");
		JSONArray array = JSONArray.parseArray(methodRoutes);
		Object[] objArray = null;
		if(null != array) {
			objArray = array.toArray();
		}
 
		/**
		 * 方法路径
		 */
		request.getSession().setAttribute(MonitorInterface.METHOD_ROUTE_LIST, objArray);
		/**
		 * 方法类型
		 */
		request.getSession().setAttribute(MonitorInterface.METHOD_TYPE_LIST, new String[]{"PO:提供对外服务方法","IN:内部服务方法","IO:调用外部方法","SQL:SQL"});
		/**
		 * 外部系统
		 */
		request.getSession().setAttribute(MonitorInterface.OUTER_SYSTEM_LIST, new String[]{"record_app:记录点滴"});
		/**
		 * 是否异常发生
		 */
		request.getSession().setAttribute(MonitorInterface.IS_EXCEPTION_LIST, new String[]{"0:无异常发生","1:异常发生"});
		/**
		 * 机器ip
		 */
		request.getSession().setAttribute(MonitorInterface.IP_LIST, new String[]{"10.117.24.172"});
	}
 
	/**
	 * 访问实时监控页面
	 * @return
	 */
	@RequestMapping(value = "/realtime", method = RequestMethod.GET)
	public String realtimeGet(HttpServletRequest request) {
		if(null == request.getSession().getAttribute(BaseInterface.KEY_USER)){
			logger.info("访问account/login");
			return "account/login";
		}
 
		/**
		 * 初始化session
		 */
		initSession(request);
 
		logger.info("访问monitor/realtime");
		return "monitor/realtime";
	}
 
	/**
	 * 实时监控
	 * @param request
	 * @param monitorDto
	 * @return
	 */
	@RequestMapping(value = "/realtime", method = RequestMethod.POST, produces="application/json")
	public @ResponseBody String realtime(HttpServletRequest request, MonitorDto monitorDto) {
		logger.info("交易监控查询,方法路径:[" + monitorDto.getMethodRoute() + "],方法类型:[" + monitorDto.getMethodType() + "]"
				+ ",外部系统:[" + monitorDto.getOuterSystem() + "],是否异常发生:[" + monitorDto.getIsException() + "]"
				+ ",开始时间:[" + monitorDto.getBeginTime() + "],结束时间:[" + monitorDto.getEndTime() + "]"
				+ ",机器ip:[" + monitorDto.getIp() + "]"
				+ ",备注字段1:[" + monitorDto.getResv1() + "],备注字段2:[" + monitorDto.getResv2() + "]"
				+ ",备注字段3:[" + monitorDto.getResv3() + "]");
		/**
		 * 判登录
		 */
		if(null == request.getSession().getAttribute(BaseInterface.KEY_USER)){
			logger.info("请先登录!");
			return "{isSuccess:false,message:'请先登录!'}";
		}
 
		/**
		 * 调record_app查询
		 */
		String url = "http://121.43.104.34:8080/record_app/monitor/count.htm";
		Map<String, String> mapData = new HashMap<String, String>();
		mapData.put("methodRoute", monitorDto.getMethodRoute());
		mapData.put("methodType", processColon(monitorDto.getMethodType()));
		mapData.put("outerSystem", processColon(monitorDto.getOuterSystem()));
		mapData.put("isException", StringUtils.isBlank(monitorDto.getIsException())?"-1":processColon(monitorDto.getIsException()));
		mapData.put("beginTime", monitorDto.getBeginTime());
		mapData.put("endTime", monitorDto.getEndTime());
		mapData.put("beginUsedTime", StringUtils.isBlank(monitorDto.getBeginUsedTime())?"-1":monitorDto.getBeginUsedTime());
		mapData.put("endUsedTime", StringUtils.isBlank(monitorDto.getEndUsedTime())?"-1":monitorDto.getEndUsedTime());
		mapData.put("ip", monitorDto.getIp());
		mapData.put("resv1", monitorDto.getResv1());
		mapData.put("resv2", monitorDto.getResv2());
		mapData.put("resv3", monitorDto.getResv3());
		return HttpClientUtils.getWebContentByPost(url, mapData, "utf-8");
	}
}

MonitorController.java

record_app下的

MonitorController.java
package com.gxx.record_app.web.monitor;
 
import java.util.List;
 
import javax.servlet.http.HttpServletRequest;
 
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
import com.gxx.record_app.base.dao.TransMonitorMapper;
import com.gxx.record_app.base.vo.TransMonitorWithBLOBs;
import com.gxx.record_app.dto.MonitorDto;
import com.gxx.record_app.interfaces.UserInterface;
 
/**
 * <dl>
 *    <dt><b>Title:</b></dt>
 *    <dd>
 *    	none
 *    </dd>
 *    <dt><b>Description:监控控制器</b></dt>
 *    <dd>
 *    	<p>none
 *    </dd>
 * </dl>
 *
 * @author Gxx
 * @version 1.0, 2017年06月22日
 * @since record_app
 */
@Controller
@RequestMapping("/monitor/")
public class MonitorController implements UserInterface {
	/**
	 * 日志处理器
	 */
	private final Logger logger = Logger.getLogger(MonitorController.class);
 
	@Autowired
	private TransMonitorMapper transMonitorMapper;
 
	/**
	 * 交易监控查询
	 * @param request
	 * @param monitorDto
	 * @return
	 */
    @RequestMapping(value = "/query",produces="application/json")
	public @ResponseBody MonitorDto query(HttpServletRequest request, MonitorDto monitorDto) {
		logger.info("交易监控查询,方法路径:[" + monitorDto.getMethodRoute() + "],方法类型:[" + monitorDto.getMethodType() + "]"
				+ ",外部系统:[" + monitorDto.getOuterSystem() + "],是否异常发生:[" + monitorDto.getIsException() + "]"
				+ ",开始时间:[" + monitorDto.getBeginTime() + "],结束时间:[" + monitorDto.getEndTime() + "]"
				+ ",最小耗时(毫秒)(>=):[" + monitorDto.getBeginUsedTime() + "],最大耗时(毫秒)(<=):[" + monitorDto.getEndUsedTime() + "]"
				+ ",机器ip:[" + monitorDto.getIp() + "]"
				+ ",备注字段1:[" + monitorDto.getResv1() + "],备注字段2:[" + monitorDto.getResv2() + "]"
				+ ",备注字段3:[" + monitorDto.getResv3() + "],每页个数:[" + monitorDto.getPageSize() + "]"
				+ ",当前页数:[" + monitorDto.getActivePage() + "]");
 
		monitorDto.setIsSuccess(true);
		monitorDto.setMessage("查询成功!");
 
		List<TransMonitorWithBLOBs> list = transMonitorMapper.queryTransMonitor(monitorDto);
		monitorDto.setList(list);
 
		/**
	     * 查询配置信息总数
	     */
	    long totalCount = transMonitorMapper.countTransMonitor(monitorDto);
	    long totalPage = 0;
	    if(monitorDto.getPageSize() > 0 && totalCount > 0){
		    totalPage = (totalCount-1)/monitorDto.getPageSize()+1;
	    }
	    monitorDto.setTotalCount(totalCount);
	    monitorDto.setTotalPage(totalPage);
		return monitorDto;
	}
 
	/**
	 * 交易监控统计
	 * @param request
	 * @param monitorDto
	 * @return
	 */
    @RequestMapping(value = "/count",produces="application/json")
	public @ResponseBody MonitorDto count(HttpServletRequest request, MonitorDto monitorDto) {
		logger.info("交易监控查询,方法路径:[" + monitorDto.getMethodRoute() + "],方法类型:[" + monitorDto.getMethodType() + "]"
				+ ",外部系统:[" + monitorDto.getOuterSystem() + "],是否异常发生:[" + monitorDto.getIsException() + "]"
				+ ",开始时间:[" + monitorDto.getBeginTime() + "],结束时间:[" + monitorDto.getEndTime() + "]"
				+ ",最小耗时(毫秒)(>=):[" + monitorDto.getBeginUsedTime() + "],最大耗时(毫秒)(<=):[" + monitorDto.getEndUsedTime() + "]"
				+ ",机器ip:[" + monitorDto.getIp() + "]"
				+ ",备注字段1:[" + monitorDto.getResv1() + "],备注字段2:[" + monitorDto.getResv2() + "]"
				+ ",备注字段3:[" + monitorDto.getResv3() + "],每页个数:[" + monitorDto.getPageSize() + "]"
				+ ",当前页数:[" + monitorDto.getActivePage() + "]");
 
		monitorDto.setIsSuccess(true);
		monitorDto.setMessage("查询成功!");
 
	    long totalCount = transMonitorMapper.countTransMonitor(monitorDto);//并发数
	    double avgUsedTime = 0;//平均耗时
	    long tps = 0;//每秒钟支持并发数
	    if(totalCount > 0) {
	    	avgUsedTime = transMonitorMapper.queryAvgUsedTime(monitorDto);//平均耗时
	    	if(avgUsedTime > 0) {
	    		tps = (long)(totalCount *1000.0 / avgUsedTime);
	    	}
	    }
 
	    monitorDto.setTotalCount(totalCount);
	    monitorDto.setAvgUsedTime(avgUsedTime);
	    monitorDto.setTps(tps);
		return monitorDto;
	}
 
	/**
	 * 查询所有监控方法路径
	 * @param request
	 * @return
	 */
    @RequestMapping(value = "/queryAllMethodRoutes",produces="application/json")
	public @ResponseBody List<String> queryAllMethodRoutes(HttpServletRequest request) {
    	return transMonitorMapper.queryAllMethodRoutes();
    }
}

TransMonitorMapper.java

TransMonitorMapper.java
package com.gxx.record_app.base.dao;
 
import java.util.List;
 
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectProvider;
import org.springframework.stereotype.Repository;
 
import com.gxx.record_app.base.vo.TransMonitor;
import com.gxx.record_app.base.vo.TransMonitorWithBLOBs;
import com.gxx.record_app.dto.MonitorDto;
 
@Repository
public interface TransMonitorMapper {
    int deleteByPrimaryKey(Integer id);
 
    int insert(TransMonitorWithBLOBs record);
 
    int insertSelective(TransMonitorWithBLOBs record);
 
    TransMonitorWithBLOBs selectByPrimaryKey(Integer id);
 
    int updateByPrimaryKeySelective(TransMonitorWithBLOBs record);
 
    int updateByPrimaryKeyWithBLOBs(TransMonitorWithBLOBs record);
 
    int updateByPrimaryKey(TransMonitor record);
 
    /**
     * 查询交易监控
     * @param monitorDto
     * @return
     */
	@SelectProvider(type=TransMonitorSqlProvider.class,method="queryTransMonitor")
    public List<TransMonitorWithBLOBs> queryTransMonitor(MonitorDto monitorDto);
 
    /**
     * 查询交易监控总数
     * @param monitorDto
     * @return
     */
	@SelectProvider(type=TransMonitorSqlProvider.class,method="countTransMonitor")
    public long countTransMonitor(MonitorDto monitorDto);
 
    /**
     * 查询平均耗时
     * @param monitorDto
     * @return
     */
	@SelectProvider(type=TransMonitorSqlProvider.class,method="queryAvgUsedTime")
    public double queryAvgUsedTime(MonitorDto monitorDto);
 
	/**
	 * 查询所有监控方法路径
	 * @return
	 */
	@Select("SELECT DISTINCT METHOD_ROUTE FROM TRANS_MONITOR")
	public List<String> queryAllMethodRoutes();
}

TransMonitorSqlProvider.java

TransMonitorSqlProvider.java
package com.gxx.record_app.base.dao;
 
import org.apache.commons.lang3.StringUtils;
 
import com.gxx.record_app.dto.MonitorDto;
 
/**
 * <dl>
 *    <dt><b>Title:</b></dt>
 *    <dd>
 *    	none
 *    </dd>
 *    <dt><b>Description:交易监控查询SQL提供类</b></dt>
 *    <dd>
 *    	<p>none
 *    </dd>
 * </dl>
 *
 * @author Gxx
 * @version 1.0, 2017年06月22日
 * @since record_app
 *
 */
public class TransMonitorSqlProvider {
	/**
	 * 查询交易监控
	 * @param monitorDto
	 * @return
	 */
	public String queryTransMonitor(MonitorDto monitorDto){
		String sql = "SELECT * FROM TRANS_MONITOR WHERE 1=1";
		//方法路径
		if(StringUtils.isNotBlank(monitorDto.getMethodRoute())){
			sql += " AND METHOD_ROUTE = '" + (monitorDto.getMethodRoute()) + "'";
		}
		//方法类型
		if(StringUtils.isNotBlank(monitorDto.getMethodType())){
			sql += " AND METHOD_TYPE = '" + (monitorDto.getMethodType()) + "'";
		}
		//外部系统
		if(StringUtils.isNotBlank(monitorDto.getOuterSystem())){
			sql += " AND OUTER_SYSTEM = '" + (monitorDto.getOuterSystem()) + "'";
		}
		//是否异常发生
		if(monitorDto.getIsException() >= 0){
			sql += " AND IS_EXCEPTION = " + (monitorDto.getIsException());
		}
		//开始时间
		if(StringUtils.isNotBlank(monitorDto.getBeginTime())){
			sql += " AND BEGIN_TIME >= '" + (monitorDto.getBeginTime()) + "'";
		}
		//结束时间
		if(StringUtils.isNotBlank(monitorDto.getEndTime())){
			sql += " AND END_TIME <= '" + (monitorDto.getEndTime()) + "'";
		}
		//最小耗时(毫秒)(>=)
		if(monitorDto.getBeginUsedTime() >= 0){
			sql += " AND USED_TIME >= " + (monitorDto.getBeginUsedTime());
		}
		//最大耗时(毫秒)(<=)
		if(monitorDto.getEndUsedTime() >= 0){
			sql += " AND USED_TIME <= " + (monitorDto.getEndUsedTime());
		}
		//机器ip
		if(StringUtils.isNotBlank(monitorDto.getIp())){
			sql += " AND IP = '" + (monitorDto.getIp()) + "'";
		}
		//备注字段1
		if(StringUtils.isNotBlank(monitorDto.getResv1())){
			sql += " AND RESV1 LIKE '%" + (monitorDto.getResv1()) + "%'";
		}
		//备注字段2
		if(StringUtils.isNotBlank(monitorDto.getResv2())){
			sql += " AND RESV2 LIKE '%" + (monitorDto.getResv2()) + "%'";
		}
		//备注字段3
		if(StringUtils.isNotBlank(monitorDto.getResv3())){
			sql += " AND RESV3 LIKE '%" + (monitorDto.getResv3()) + "%'";
		}
		//id倒序
		sql += " ORDER BY ID DESC";
		//分页
		if(monitorDto.getActivePage() > 0 && monitorDto.getPageSize() > 0){
			sql += " LIMIT " + (monitorDto.getActivePage()-1)*monitorDto.getPageSize() + "," + monitorDto.getPageSize();
		}
		return sql;
	}
 
	/**
	 * 查询交易监控总数
	 * @param monitorDto
	 * @return
	 */
	public String countTransMonitor(MonitorDto monitorDto){
		String sql = "SELECT COUNT(1) FROM TRANS_MONITOR WHERE 1=1";
		//方法路径
		if(StringUtils.isNotBlank(monitorDto.getMethodRoute())){
			sql += " AND METHOD_ROUTE = '" + (monitorDto.getMethodRoute()) + "'";
		}
		//方法类型
		if(StringUtils.isNotBlank(monitorDto.getMethodType())){
			sql += " AND METHOD_TYPE = '" + (monitorDto.getMethodType()) + "'";
		}
		//外部系统
		if(StringUtils.isNotBlank(monitorDto.getOuterSystem())){
			sql += " AND OUTER_SYSTEM = '" + (monitorDto.getOuterSystem()) + "'";
		}
		//是否异常发生
		if(monitorDto.getIsException() >= 0){
			sql += " AND IS_EXCEPTION = " + (monitorDto.getIsException());
		}
		//开始时间
		if(StringUtils.isNotBlank(monitorDto.getBeginTime())){
			sql += " AND BEGIN_TIME >= '" + (monitorDto.getBeginTime()) + "'";
		}
		//结束时间
		if(StringUtils.isNotBlank(monitorDto.getEndTime())){
			sql += " AND END_TIME <= '" + (monitorDto.getEndTime()) + "'";
		}
		//最小耗时(毫秒)(>=)
		if(monitorDto.getBeginUsedTime() >= 0){
			sql += " AND USED_TIME >= " + (monitorDto.getBeginUsedTime());
		}
		//最大耗时(毫秒)(<=)
		if(monitorDto.getEndUsedTime() >= 0){
			sql += " AND USED_TIME <= " + (monitorDto.getEndUsedTime());
		}
		//机器ip
		if(StringUtils.isNotBlank(monitorDto.getIp())){
			sql += " AND IP = '" + (monitorDto.getIp()) + "'";
		}
		//备注字段1
		if(StringUtils.isNotBlank(monitorDto.getResv1())){
			sql += " AND RESV1 LIKE '%" + (monitorDto.getResv1()) + "%'";
		}
		//备注字段2
		if(StringUtils.isNotBlank(monitorDto.getResv2())){
			sql += " AND RESV2 LIKE '%" + (monitorDto.getResv2()) + "%'";
		}
		//备注字段3
		if(StringUtils.isNotBlank(monitorDto.getResv3())){
			sql += " AND RESV3 LIKE '%" + (monitorDto.getResv3()) + "%'";
		}
		return sql;
	}
 
	/**
	 * 查询平均耗时
	 * @param monitorDto
	 * @return
	 */
	public String queryAvgUsedTime(MonitorDto monitorDto){
		String sql = "SELECT AVG(USED_TIME) FROM TRANS_MONITOR WHERE 1=1";
		//方法路径
		if(StringUtils.isNotBlank(monitorDto.getMethodRoute())){
			sql += " AND METHOD_ROUTE = '" + (monitorDto.getMethodRoute()) + "'";
		}
		//方法类型
		if(StringUtils.isNotBlank(monitorDto.getMethodType())){
			sql += " AND METHOD_TYPE = '" + (monitorDto.getMethodType()) + "'";
		}
		//外部系统
		if(StringUtils.isNotBlank(monitorDto.getOuterSystem())){
			sql += " AND OUTER_SYSTEM = '" + (monitorDto.getOuterSystem()) + "'";
		}
		//是否异常发生
		if(monitorDto.getIsException() >= 0){
			sql += " AND IS_EXCEPTION = " + (monitorDto.getIsException());
		}
		//开始时间
		if(StringUtils.isNotBlank(monitorDto.getBeginTime())){
			sql += " AND BEGIN_TIME >= '" + (monitorDto.getBeginTime()) + "'";
		}
		//结束时间
		if(StringUtils.isNotBlank(monitorDto.getEndTime())){
			sql += " AND END_TIME <= '" + (monitorDto.getEndTime()) + "'";
		}
		//最小耗时(毫秒)(>=)
		if(monitorDto.getBeginUsedTime() >= 0){
			sql += " AND USED_TIME >= " + (monitorDto.getBeginUsedTime());
		}
		//最大耗时(毫秒)(<=)
		if(monitorDto.getEndUsedTime() >= 0){
			sql += " AND USED_TIME <= " + (monitorDto.getEndUsedTime());
		}
		//机器ip
		if(StringUtils.isNotBlank(monitorDto.getIp())){
			sql += " AND IP = '" + (monitorDto.getIp()) + "'";
		}
		//备注字段1
		if(StringUtils.isNotBlank(monitorDto.getResv1())){
			sql += " AND RESV1 LIKE '%" + (monitorDto.getResv1()) + "%'";
		}
		//备注字段2
		if(StringUtils.isNotBlank(monitorDto.getResv2())){
			sql += " AND RESV2 LIKE '%" + (monitorDto.getResv2()) + "%'";
		}
		//备注字段3
		if(StringUtils.isNotBlank(monitorDto.getResv3())){
			sql += " AND RESV3 LIKE '%" + (monitorDto.getResv3()) + "%'";
		}
		return sql;
	}
}

MonitorDto.java

record_app下的

MonitorDto.java
package com.gxx.record_app.dto;
 
import java.util.List;
 
import com.gxx.record_app.base.vo.TransMonitorWithBLOBs;
 
/**
 * <dl>
 *    <dt><b>Title:</b></dt>
 *    <dd>
 *    	交易监控对象
 *    </dd>
 *    <dt><b>Description:</b></dt>
 *    <dd>
 *    	<p>none
 *    </dd>
 * </dl>
 *
 * @author Gxx
 * @version 1.0, 2017年6月22日
 * @since config_center
 */
public class MonitorDto extends BaseDto {
    private String methodRoute;//方法路径
    private String methodType;//方法类型
    private String outerSystem;//外部系统
    private int isException;//是否异常发生
    private String beginTime;//开始时间
    private String endTime;//结束时间
    private int beginUsedTime;//最小耗时(毫秒)(>=)
    private int endUsedTime;//最大耗时(毫秒)(<=)
    private String ip;//机器ip
    private String resv1;//备注字段1
    private String resv2;//备注字段2
    private String resv3;//备注字段3
 
    private int pageSize;//每页个数
    private int activePage;//当前页数
 
    private boolean isSuccess;//是否成功
    private String message;//返回信息
 
    private List<TransMonitorWithBLOBs> list;//数据集合
    private long totalCount;//总条数
    private long totalPage;//总页数
 
    private double avgUsedTime;//平均耗时
    private long tps;//每秒钟支持并发数
 
	public String getMethodRoute() {
		return methodRoute;
	}
	public void setMethodRoute(String methodRoute) {
		this.methodRoute = methodRoute;
	}
	public String getMethodType() {
		return methodType;
	}
	public void setMethodType(String methodType) {
		this.methodType = methodType;
	}
	public String getOuterSystem() {
		return outerSystem;
	}
	public void setOuterSystem(String outerSystem) {
		this.outerSystem = outerSystem;
	}
	public int getIsException() {
		return isException;
	}
	public void setIsException(int isException) {
		this.isException = isException;
	}
	public String getBeginTime() {
		return beginTime;
	}
	public void setBeginTime(String beginTime) {
		this.beginTime = beginTime;
	}
	public String getEndTime() {
		return endTime;
	}
	public void setEndTime(String endTime) {
		this.endTime = endTime;
	}
	public int getBeginUsedTime() {
		return beginUsedTime;
	}
	public void setBeginUsedTime(int beginUsedTime) {
		this.beginUsedTime = beginUsedTime;
	}
	public int getEndUsedTime() {
		return endUsedTime;
	}
	public void setEndUsedTime(int endUsedTime) {
		this.endUsedTime = endUsedTime;
	}
	public String getIp() {
		return ip;
	}
	public void setIp(String ip) {
		this.ip = ip;
	}
	public String getResv1() {
		return resv1;
	}
	public void setResv1(String resv1) {
		this.resv1 = resv1;
	}
	public String getResv2() {
		return resv2;
	}
	public void setResv2(String resv2) {
		this.resv2 = resv2;
	}
	public String getResv3() {
		return resv3;
	}
	public void setResv3(String resv3) {
		this.resv3 = resv3;
	}
	public int getPageSize() {
		return pageSize;
	}
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}
	public int getActivePage() {
		return activePage;
	}
	public void setActivePage(int activePage) {
		this.activePage = activePage;
	}
	public boolean isSuccess() {
		return isSuccess;
	}
	public void setSuccess(boolean isSuccess) {
		this.isSuccess = isSuccess;
	}
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
	public List<TransMonitorWithBLOBs> getList() {
		return list;
	}
	public void setList(List<TransMonitorWithBLOBs> list) {
		this.list = list;
	}
	public long getTotalCount() {
		return totalCount;
	}
	public void setTotalCount(long totalCount) {
		this.totalCount = totalCount;
	}
	public long getTotalPage() {
		return totalPage;
	}
	public void setTotalPage(long totalPage) {
		this.totalPage = totalPage;
	}
	public double getAvgUsedTime() {
		return avgUsedTime;
	}
	public void setAvgUsedTime(double avgUsedTime) {
		this.avgUsedTime = avgUsedTime;
	}
	public long getTps() {
		return tps;
	}
	public void setTps(long tps) {
		this.tps = tps;
	}
}

MonitorDto.java

config_center下的

MonitorDto.java
package com.gxx.config_center.dto;
/**
 * <dl>
 *    <dt><b>Title:</b></dt>
 *    <dd>
 *    	交易监控对象
 *    </dd>
 *    <dt><b>Description:</b></dt>
 *    <dd>
 *    	<p>none
 *    </dd>
 * </dl>
 *
 * @author Gxx
 * @version 1.0, 2017年6月22日
 * @since config_center
 */
public class MonitorDto extends BaseDto {
    private String methodRoute;//方法路径
    private String methodType;//方法类型
    private String outerSystem;//外部系统
    private String isException;//是否异常发生
    private String beginTime;//开始时间
    private String endTime;//结束时间
    private String beginUsedTime;//最小耗时(毫秒)(>=)
    private String endUsedTime;//最大耗时(毫秒)(<=)
    private String ip;//机器ip
    private String resv1;//备注字段1
    private String resv2;//备注字段2
    private String resv3;//备注字段3
 
    private int pageSize;//每页个数
    private int activePage;//当前页数
 
	public String getMethodRoute() {
		return methodRoute;
	}
	public void setMethodRoute(String methodRoute) {
		this.methodRoute = methodRoute;
	}
	public String getMethodType() {
		return methodType;
	}
	public void setMethodType(String methodType) {
		this.methodType = methodType;
	}
	public String getOuterSystem() {
		return outerSystem;
	}
	public void setOuterSystem(String outerSystem) {
		this.outerSystem = outerSystem;
	}
	public String getIsException() {
		return isException;
	}
	public void setIsException(String isException) {
		this.isException = isException;
	}
	public String getBeginTime() {
		return beginTime;
	}
	public void setBeginTime(String beginTime) {
		this.beginTime = beginTime;
	}
	public String getEndTime() {
		return endTime;
	}
	public void setEndTime(String endTime) {
		this.endTime = endTime;
	}
	public String getBeginUsedTime() {
		return beginUsedTime;
	}
	public void setBeginUsedTime(String beginUsedTime) {
		this.beginUsedTime = beginUsedTime;
	}
	public String getEndUsedTime() {
		return endUsedTime;
	}
	public void setEndUsedTime(String endUsedTime) {
		this.endUsedTime = endUsedTime;
	}
	public String getIp() {
		return ip;
	}
	public void setIp(String ip) {
		this.ip = ip;
	}
	public String getResv1() {
		return resv1;
	}
	public void setResv1(String resv1) {
		this.resv1 = resv1;
	}
	public String getResv2() {
		return resv2;
	}
	public void setResv2(String resv2) {
		this.resv2 = resv2;
	}
	public String getResv3() {
		return resv3;
	}
	public void setResv3(String resv3) {
		this.resv3 = resv3;
	}
	public int getPageSize() {
		return pageSize;
	}
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}
	public int getActivePage() {
		return activePage;
	}
	public void setActivePage(int activePage) {
		this.activePage = activePage;
	}
}