这里有新鲜出炉的Java设计模式,程序狗速度看过来!
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称。
本篇文章主要介绍了JAVA实现通用日志记录方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
前言:
之前想在filter层直接过滤httpServerletRequest请求进行日志处理,但是之后再getWriter()的 时候报already been call异常。查了下,才发现原来流形式的只能读取一次。。就好像食物,吃了就没了。。 所以在filter和inteceptor里面是没法通过获取request的流来进行日志记录的。
于是还是准备用通用的方法:controller层aop进行切面记录日志。
使用Aop记录操作日志
第一步:添加Aop
- /**
- * 统一日志处理Handler
- * @author Mingchenchen
- *
- */
- public class LogAopHandler {@Autowired private AuditLogDao auditLogDao;
- /**
- * controller层面记录操作日志
- * 注意此处是aop:around的 因为需要得到请求前的参数以及请求后接口返回的结果
- * @throws Throwable
- */
- public Object doSaveLog(ProceedingJoinPoint joinPoint) throws Throwable {
- MethodSignature method = (MethodSignature) joinPoint.getSignature();
- String methodName = method.getName();
- Object[] objects = joinPoint.getArgs();
- String requestBody = null;
- if (objects != null && objects.length > 0) {
- for (Object object: objects) {
- if (object == null) {
- requestBody = null; //POST接口参数为空 比如删除XXX
- } else if (object instanceof String) {
- requestBody = (String) object; //有些接口直接把参数转换成对象了
- } else {
- requestBody = JSONObject.toJSONString(object);
- }
- }
- }
- //只记录POST方法的日志
- boolean isNeedSaveLog = false;
- //此处不能用getAnnotationByType 是JAVA8的特性,因为注解能够重名,所以得到的是数组
- RequestMapping annotation = method.getMethod().getAnnotation(RequestMapping.class);
- for (RequestMethod requestMethod: annotation.method()) {
- if (requestMethod == RequestMethod.POST) {
- isNeedSaveLog = true;
- }
- }
- JSONObject requestBodyJson = null;
- try {
- requestBodyJson = JSONObject.parseObject(requestBody);
- } catch(Exception e) {
- //do nothing 即POST请求没传body
- }
- HttpServletRequest request = RequestContextUtil.getRequestByCurrentContext();
- String userName = RequestContextUtil.getUserNameByCurrentContext();
- if (StringUtil.isEmpty(userName)) {
- try {
- userName = DmsCache.get(requestBodyJson.getString("userName")).getName();
- } catch(Exception e) {
- userName = RequestContextUtil.getAsynUserInfoByAutoDeploy().getName();
- }
- }
- //得到request的参数后让方法执行它
- //注意around的情况下需要返回result 否则将不会返回值给请求者
- Object result = joinPoint.proceed(objects);
- try {
- JSONObject resultJson = JSONObject.parseObject(result.toString());
- if (isNeedSaveLog) { //如果是POST请求 则记录日志
- LogTypeEnum logTypeEnum = LogTypeEnum.getDesByMethodName(methodName);
- if (logTypeEnum != null) {
- AuditLogEntity auditLogEntity = new AuditLogEntity();
- auditLogEntity.setUuid(StringUtil.createRandomUuid());
- auditLogEntity.setOperator(userName);
- auditLogEntity.setRequestIp(request.getRemoteAddr());
- auditLogEntity.setRequestUrl(request.getRequestURI().replace("/cloud-master", ""));
- auditLogEntity.setEventType(logTypeEnum.getKey());
- auditLogEntity.setEventDesc(logTypeEnum.getDescription());
- auditLogEntity.setRequest(requestBody);
- int isSuccess = "200".equals(resultJson.getString("code")) ? 1 : 0;
- auditLogEntity.setSuccessFlag(isSuccess);
- auditLogEntity.setResponse(result.toString());
- auditLogEntity.setCreateTime(new Date());
- auditLogDao.insert(auditLogEntity);
- }
- }
- } catch(Exception e) {
- e.printStackTrace();
- }
- return result;
- }
- }
第二步:在spring的xml中声明
- <!-- 记录操作日志 -->
- <bean id="operationLogAop" class="com.ming.learn.core.aop.LogAopHandler"/>
- <aop:config>
- <aop:aspect id="logAOP" ref="operationLogAop">
- <aop:pointcut id="target" expression="execution(* com.ming.learn..*Controller.*(..))"/>
- <aop:around method="doSaveLog" pointcut-ref="target"/>
- </aop:aspect>
- </aop:config>
如此一来,核心步骤就完成了,剩下的就是自己组装需要记录的东西了。
第三步:写Dao、Entity、Mapper
- import java.util.Date;
- import javax.persistence.Column;
- import javax.persistence.Id;
- import javax.persistence.Table;
- /**
- * 日志审计
- * @author Mingchenchen
- *
- */
- @Table(name="audit_log")
- public class AuditLogEntity {
- @Id
- private String uuid;
- @Column(name="event_type")
- private String eventType;//事件类型
- @Column(name="event_desc")
- private String eventDesc;//事件中文描述
- @Column(name="operator")
- private String operator;//操作者
- @Column(name="request_ip")
- private String requestIp;//客户端地址
- @Column(name="request_url")
- private String requestUrl;//请求地址
- @Column(name="request")
- private String request;//请求body
- @Column(name="response")
- private String response;//请求返回值
- @Column(name="create_time")
- private Date createTime;
- public String getUuid() {
- return uuid;
- }
- public void setUuid(String uuid) {
- this.uuid = uuid;
- }
- public String getEventType() {
- return eventType;
- }
- public void setEventType(String eventType) {
- this.eventType = eventType;
- }
- public String getEventDesc() {
- return eventDesc;
- }
- public void setEventDesc(String eventDesc) {
- this.eventDesc = eventDesc;
- }
- public String getOperator() {
- return operator;
- }
- public void setOperator(String operator) {
- this.operator = operator;
- }
- public String getRequestIp() {
- return requestIp;
- }
- public void setRequestIp(String requestIp) {
- this.requestIp = requestIp;
- }
- public String getRequestUrl() {
- return requestUrl;
- }
- public void setRequestUrl(String requestUrl) {
- this.requestUrl = requestUrl;
- }
- public String getRequest() {
- return request;
- }
- public void setRequest(String request) {
- this.request = request;
- }
- public String getResponse() {
- return response;
- }
- public void setResponse(String response) {
- this.response = response;
- }
- public Date getCreateTime() {
- return createTime;
- }
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
- }
第四步:根据Controller的方法名称定制响应的事件类型
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- /**
- * 操作日志类型
- * @author Mingchenchen
- *
- */
- public enum LogTypeEnum {
- //用户
- COMMON_LOGIN("login", "login", "登录");
- //其他
- private String methodName; //方法名称与controller一致
- private String key; //保存到数据库的事件类型
- private String description; //保存到数据库的描述
- private LogTypeEnum(String methodName, String key, String description) {
- this.methodName = methodName;
- this.key = key;
- this.description = description;
- }
- public String getMethodName() {
- return methodName;
- }
- public void setMethodName(String methodName) {
- this.methodName = methodName;
- }
- public String getKey() {
- return key;
- }
- public void setKey(String key) {
- this.key = key;
- }
- public String getDescription() {
- return description;
- }
- public void setDescription(String description) {
- this.description = description;
- }
- /**
- * 根据方法名返回
- * @param methodName
- * @return
- */
- public static LogTypeEnum getDesByMethodName(String methodName) {
- return innerMap.map.get(methodName);
- }
- /**
- * 内部类 用户保存所有的enum 无须通过Enum.values()每次遍历
- * @author Mingchenchen
- *
- */
- private static class innerMap {
- private static Map < String,
- LogTypeEnum > map = new ConcurrentHashMap < >(128);
- static {
- //初始化整个枚举类到Map
- for (LogTypeEnum logTypeEnum: LogTypeEnum.values()) {
- map.put(logTypeEnum.getMethodName(), logTypeEnum);
- }
- }
- }
- }
来源: http://www.phperz.com/article/17/0824/338417.html