NutzCN Logo
问答 请教大佬们一个问题,怎么记录用户的操作日志到oracle,就是谁对哪张表哪些字段进行了增删改,请大佬们指教,谢谢!
发布于 1887天前 作者 MrAndy666 2147 次浏览 复制 上一个帖子 下一个帖子
标签:

本人新手,还没搞明白dao拦截器或aop,但是boss给的时间紧,希望哪位大佬有宝贵时间帮我具体说一下,蟹蟹!

32 回复

精确到字段的话,太难太烦了,精确到service方法就够啦,用nutzmore项目里面的slog插件

谢谢!请问slog要求最低版本是多少,我用的1.r.60可以吗?

默认创建数据库表的时候msg字段varchar2类型的长度为8192,超多最大长度,请问怎么设置啊?

CREATE TABLE t_syslog_201910(
t VARCHAR2(128),
tg VARCHAR2(128),
src VARCHAR2(1024),
u_id NUMBER(16),
u_name VARCHAR2(128),
ip VARCHAR2(128),
msg VARCHAR2(8192),
ct DATE)

还有一个问题就是,我代码是这么写的,u_id和u_name怎么获取呢?

@Slog(tag="用户登录", before="用户名[${account}]正在尝试登录", after="用户[${account}]登录结果: ${re.msg}")
	public Object login(String account, String password,HttpSession session) {
		JSONObject jsonObject = new JSONObject();
		try {
			List<SystemAccountLoginV> list = dao.query(SystemAccountLoginV.class, 
					//Cnd.where("faccount","=",account).and("fpassword","=",MD5.MD5(password)).and("fstate","=","2").and("fsfsc","=","0"));
			Cnd.where("faccount","=",account).and("fpassword","=",password).and("fstate","=","2").and("fsfsc","=","0"));
			System.out.println(list);
			if(list.size()==1){
				SystemAccountLoginV obj = list.get(0);
//				session.setAttribute("hospitalid", 484);
//				session.setAttribute("hospitalname", "某医院");
				session.setAttribute("account", obj.getFaccount());
				session.setAttribute("accountid", obj.getId());
				session.setAttribute("accountname", obj.getFname());
				session.setAttribute("accounttype", obj.getFzhlx());
				session.setAttribute("staffid", obj.getFstaffid());
				session.setAttribute("staffname", obj.getFstaffname());
				session.setAttribute("deptid", obj.getFdeptid());
				session.setAttribute("deptname", obj.getFdeptname());
				
				List permisslist = getPermissList(obj.getId());
				session.setAttribute("permisslist", permisslist.toArray());
				List rolelist = getRoleList(obj.getId());
				session.setAttribute("rolelist", rolelist.toArray());
				
				session.setMaxInactiveInterval(60*60*24);
				MySessionContext.AddSession(session);
				//获取角色对应的权限
				jsonObject.put("success", true);
				jsonObject.put("msg", "登录成功");
				jsonObject.put("token", account);
				jsonObject.put("sessionId", session.getId());//list.get(0)
				
			}else{
				jsonObject.put("success", false);
				jsonObject.put("msg", "账号或密码错误");
				jsonObject.put("token", "");
				jsonObject.put("sessionId", "");
			}
		} catch (Exception e) {
			e.printStackTrace();
			jsonObject.put("success", false);
			jsonObject.put("msg", "未知错误,登录失败");
			jsonObject.put("token", "");
			jsonObject.put("sessionId", "");
		}
		return jsonObject;
	}

那是两个回调,在MainSetup.init方法内设置成你自己的实现

@wendal 谢谢!请问,MainSetup.init方法是初始化方法,无法取到request,那么怎么才能在里边取到不同用户登录的id和name呢?

SlogService.GET_USER_ID = new Callable<Object>() {
            public Object call() throws Exception {
                return 123; // 获取不同登录用户id
            };
        };
        SlogService.GET_USER_NAME = new Callable<Object>() {
            public Object call() throws Exception {
                return "666888"; // 获取不同登录用户name
            };
        };

Mvcs.getReq()

您好,麻烦您了,这样写Mvcs.getReq()取不到每次发送request吧?因为我想要多有用户的所有操作全都要记录,而用户信息是登陆的时候存到session里边的。

public void init(NutConfig conf) {
        SlogService.GET_USER_ID = new Callable<Object>() {
            HttpServletRequest request = Mvcs.getReq();
            HttpSession session = MySessionContext.getSession(request);
            public Object call() throws Exception {
                if(session != null){
                    return session.getAttribute("accountid"); // 获取不同登录用户id
                }else{
                    return -1;
                }
                
            };
        };
        SlogService.GET_USER_NAME = new Callable<Object>() {
            public Object call() throws Exception {
                return "666888"; // 获取不同登录用户name
            };
        };
        
    }

能取到的, 那是在生成具体slog日志的时候才执行的回调, 就是调用入口方法/service方法的时候

不是在MainSetup.init里面一次性执行的

每次生成slog日志对象, 都会执行这两个回调

我晕, 仔细看你代码才发现问题

        SlogService.GET_USER_ID = new Callable<Object>() {
            public Object call() throws Exception {
                // 放这里呀
                HttpServletRequest request = Mvcs.getReq();
                HttpSession session = MySessionContext.getSession(request);
                if(session != null){
                    return session.getAttribute("accountid"); // 获取不同登录用户id
                }else{
                    return -1;
                }
                
            };
        };

这么写也取不到呢,id是-1,name是空,是我哪里出问题了吗?

public void init(NutConfig conf) {
        SlogService.GET_USER_ID = new Callable<Object>() {
            public Object call() throws Exception {
                HttpServletRequest request = Mvcs.getReq();
                HttpSession session = MySessionContext.getSession(request);
                if(session != null){
                    return session.getAttribute("accountid"); // 获取不同登录用户name
                }else{
                    return -1;
                } 
            };
        };
        SlogService.GET_USER_NAME = new Callable<Object>() {
            public Object call() throws Exception {
                HttpServletRequest request = Mvcs.getReq();
                HttpSession session = MySessionContext.getSession(request);
                if(session != null){
                    return session.getAttribute("accountname"); // 获取不同登录用户name
                }else{
                    return "";
                } 
            };
        };
        
    }
2019-10-24 15:41:40,536 org.nutz.dao.impl.sql.run.NutDaoExecutor.printSQL(NutDaoExecutor.java:388) DEBUG - INSERT INTO t_syslog_201910(t,tg,src,u_id,u_name,ip,msg,ct) VALUES(?,?,?,?,?,?,?,?) 
    |         1 |    2 |                                                 3 |  4 | 5 |               6 |                  7 |                   8 |
    |-----------|------|---------------------------------------------------|----|--|-----------------|--------------------|---------------------|
    | aop.after | 用户登录 | com.ysu.system.proxy.dao.SystemLoginDaoImpI#login | -1 |  | 0:0:0:0:0:0:0:1 | 用户[rlzy]登录结果: 登录成功 | 2019-10-24 15:41:40 |
  For example:> "INSERT INTO t_syslog_201910(t,tg,src,u_id,u_name,ip,msg,ct) VALUES('aop.after','用户登录','com.ysu.system.proxy.dao.SystemLoginDaoImpI#login',-1,'','0:0:0:0:0:0:0:1','用户[rlzy]登录结果: 登录成功','2019-10-24 15:41:40') "

我知道了,我是在登录生成日志方法里边设置session属性的,当我登录生成日志 执行回调的时候还没往session里边setAttribute,我在登录的时候手动给u_id和u_name赋值就行了,应该是这个原因吧。。。

还有一个问题,默认创建oracle表的时候msg字段varchar2类型的长度为8192,超多最大长度4000报错,请问这个能设置吗?

CREATE TABLE t_syslog_201910(
t VARCHAR2(128),
tg VARCHAR2(128),
src VARCHAR2(1024),
u_id NUMBER(16),
u_name VARCHAR2(128),
ip VARCHAR2(128),
msg VARCHAR2(8192),
ct DATE)

额, 有一点麻烦

方法1, 把org.nutz.plugins.slog.bean.SlogBean的源码拷贝到项目里面, 改一下注解

方法2, 继承SlogService,写个子类

@IocBean(name="slogService") public class MySlogService extends SlogService {

   public Dao dao(String key) { } // 复写里面的逻辑
}

谢谢!刚才获取不同用户request的还有点问题,下边是插入的日志表数据,一、702登录成功;二、703登录成功;三、703添加成功;四、应该是702添加成功,但插入数据还是703,IP是对的。如果我每次都在@slog的方法里面手动调用一边u_id和u_name的方法可以吗?但我需要在所有修改表的方法都加上@slog,太多会不会有问题呢?

1	aop.after	用户登录	com.ysu.system.proxy.dao.SystemLoginDaoImpI#login	702	人力管理员	192.168.0.136	用户[rlzy]登录结果: 登录成功	2019/10/24 16:12
2	aop.after	用户登录	com.ysu.system.proxy.dao.SystemLoginDaoImpI#login	703	管理员	192.168.0.143	用户[admin]登录结果: 登录成功	2019/10/24 16:17
3	aop.after	新增学历	com.ysu.human.proxy.dao.EducationManagementDaoImpl#addXl	703	管理员	192.168.0.143	结果: 添加成功!	2019/10/24 16:18
4	aop.after	新增学历	com.ysu.human.proxy.dao.EducationManagementDaoImpl#addXl	703	管理员	192.168.0.136	结果: 添加成功!	2019/10/24 16:18

登录后session里面没有用户信息吗? 那你的代码怎么区分用户的...

同一个浏览器登录2次???

是用两台电脑登录的,ip不一样,用户登录的时候把信息存到session的,是这儿有问题吗?这个是action

@At("/login")
	public void login(@Param("userName")String userName,@Param("password")String password,
			HttpServletRequest request,HttpServletResponse response,HttpSession session) {
		JSONObject jsonObject = new JSONObject();
		jsonObject = (JSONObject)loginservice.login(userName,password,session);//
		ResponseDate.sendDataLogin(request, response, jsonObject);
    }

这个是dao

@Slog(tag="用户登录",after="用户[${account}]登录结果: ${re.msg}")
	public Object login(String account, String password,HttpSession session) {
        MyUtils.setUserIdAndName(session);
		JSONObject jsonObject = new JSONObject();
		try {
			List<SystemAccountLoginV> list = dao.query(SystemAccountLoginV.class, 
			Cnd.where("faccount","=",account).and("fpassword","=",password).and("fstate","=","2").and("fsfsc","=","0"));
			if(list.size()==1){
				SystemAccountLoginV obj = list.get(0);
				session.setAttribute("account", obj.getFaccount());
				session.setAttribute("accountid", obj.getId());
				session.setAttribute("accountname", obj.getFname());
				session.setAttribute("accounttype", obj.getFzhlx());
				session.setAttribute("staffid", obj.getFstaffid());
				session.setAttribute("staffname", obj.getFstaffname());
				session.setAttribute("deptid", obj.getFdeptid());
				session.setAttribute("deptname", obj.getFdeptname());
				
				List permisslist = getPermissList(obj.getId());
				session.setAttribute("permisslist", permisslist.toArray());
				List rolelist = getRoleList(obj.getId());
				session.setAttribute("rolelist", rolelist.toArray());
				
				session.setMaxInactiveInterval(60*60*24);
				MySessionContext.AddSession(session);
				//获取角色对应的权限
				jsonObject.put("success", true);
				jsonObject.put("msg", "登录成功");
				jsonObject.put("token", account);
				jsonObject.put("sessionId", session.getId());//list.get(0)
				
			}else{
				jsonObject.put("success", false);
				jsonObject.put("msg", "账号或密码错误");
				jsonObject.put("token", "");
				jsonObject.put("sessionId", "");
			}
		} catch (Exception e) {
			e.printStackTrace();
			jsonObject.put("success", false);
			jsonObject.put("msg", "未知错误,登录失败");
			jsonObject.put("token", "");
			jsonObject.put("sessionId", "");
		}
		return jsonObject;
	}

为啥你要这样取session呢?直接req.getSession就好啦

HttpSession session = MySessionContext.getSession(request);

不同用户的session里面的accountid肯定不同呀

这些是什么操作??

MySessionContext.AddSession(session);

MySessionContext 是项目里自己写的工具类,用来存储和获取session的,是这个有问题吗?

public class MySessionContext {
    private static HashMap mymap = new HashMap();
    public static synchronized void AddSession(HttpSession session) {
        if (session != null) {
            mymap.put(session.getId(), session);
        }
    }

    public static synchronized void DelSession(HttpSession session) {
        if (session != null) {
            mymap.remove(session.getId());
        }
    }

    public static synchronized HttpSession getSession(String session_id) {
        if (session_id == null)
        return null;
        return (HttpSession) mymap.get(session_id);
    }
    
    public static synchronized HttpSession getSession(HttpServletRequest request) {
        if (request == null)
        return null;
        String session_id = request.getHeader("x-auth-sid");
        System.out.println(session_id);
        HttpSession session = (HttpSession) mymap.get(session_id);
        if(session == null){
        	mymap.remove(session_id);
        }
        return session;
    }
}

客户端会确保每个请求都带上x-auth-sid?

暂时还没发现不带x-auth-sid的,我在回调函数里打桩,发现每次插入日志的时候都没走回调函数呢,所以没有给u_id和u_name重新复制?

debug一下org.nutz.plugins.slog.service.SlogService.log(String, String, String, String, boolean)方法

我把SlogService自定义了一个,改了相关代码就好了;然后关于创建表时msg长度问题,我重新下载了最新版的slog插件,应该能和nutz1.60完美结合吧?

其实你可以把插件源码拷贝进项目里,怎么改都行

嗯嗯,谢谢!日志输出基本搞定,然后我现在想在dao调用insert、update、delete方法的时候获取到执行的具体SQL语句,查了一下您说过可以写一个dao拦截器,但是我不知道怎么写。。。请问哪里有详细的介绍吗?

package com.ysu.common.utils;

import org.nutz.dao.DaoException;
import org.nutz.dao.DaoInterceptor;
import org.nutz.dao.DaoInterceptorChain;
import org.nutz.dao.impl.jdbc.NutPojo;
import org.nutz.dao.impl.sql.NutSql;
import org.nutz.dao.sql.DaoStatement;

public class MyDaoInterceptor implements DaoInterceptor {
    public void filter(DaoInterceptorChain chain) throws DaoException {
        DaoStatement st = chain.getDaoStatement();
        if (st instanceof NutPojo) {
            // 如果是dao.insert(user)之类的操作,会进入这个分支
            System.out.println("st instanceof NutPojo----------------------------------------------------------------------------------");
            if (st.isInsert() || st.isUpdate() || st.isDelete()){
                System.out.println(st.toPreparedStatement());
            }
        } else if (st instanceof NutSql) {
            // 如果是自定义SQL,会进入这个分支
            System.out.println("自定义SQL------------------------------------------------------------------------------------------");
        }
        chain.doChain();//继续下一个拦截器执行
    }
}

参考 nutzsite
https://github.com/TomYule/NutzSite/blob/master/src/main/java/org/nutz/plugins/slog/service/SlogService.java

Map<String, String[]> map = Mvcs.getReq().getParameterMap();
            String params = JSONObject.toJSONString(map);

获取页面所有请求参数 转成json 保存数据库

添加回复
请先登陆
回到顶部