整理一下逻辑,一个类中的一个方法被调用时,AOP配置文件会去检查你是否对此方法配置了日志切面,如果配置了,这儿是后向切入,他会在
执行此方法之后执行切入类的一个方法(AOP配置此方法),切入类得到了此方法的完整路径名称,他会到一个配置文件中去读取方法描述,然后用log4j记录此描述信息,后面的工作就交给log4j了,log4j会把信息从屏幕输出,并记录到一个日志文件,位一WEB-INF/log下,还会把数据插入到数据库,但是还需要用户信息,不过Filter已经为我准备好了,系统可以记录一条日志信息类似:
2010-01-01 17:34 用户dreamsover[id号]添加了审核信息
这是log4j的配置文件,定义了3个输出域,此文件位于WEB-INF/conif/log4j(因为我定义了一个输出域为文件,而且要存储到本项目的WEB-INF子目录下,要用到${webapp.root}变量,把log4j配置文件放到WEB-INF下最好,在系统启动时用spring加载,下面贴上web.xml中的配置,包括加载此文件)
- ERROR>INFO>DEBUG
- log4j.properties
- log4j.rootLogger=INFO,stdout,logfile,db
- #spring log
- log4j.logger.org.springframework=ERROR
- #Console
- log4j.appender.stdout=org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %X{id},%X{name},%m %C%l%n
- #Filelogfile
- log4j.appender.logfile=org.apache.log4j.FileAppender
- log4j.appender.logfile.File=${webapp.root.webtools}/WEB-INF/logs/system.log
- log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
- log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %X{name},%m %n
- #JDBC Appender
- log4j.appender.db=org.apache.log4j.jdbc.JDBCAppender
- log4j.appender.db.BufferSize=2
- log4j.appender.db.driver=sun.jdbc.odbc.JdbcOdbcDriver
- log4j.appender.db.URL=jdbcdbc:report
- log4j.appender.db.user=loveus
- log4j.appender.db.password=123456
- log4j.appender.db.sql=insert into LOG (USERID,NAME,[TIME],INFO) values ('%X{id}','%X{name}','%d{yyyy-MM-dd HH\:mm\:ss}','%m')
web.xml配置文件,此文件加载了struts,spring,并用spring加载了log4j,注意里面配置了一个Filter : GetUserFilter ,他的作用是从SESSION中获取当前登录用户的信息,在Log4j配置文件中用到了, 比如%X{name}是获取用户姓名,但是要在此Filter中先设置name属性。GetUserFilter是关键所在,因为等一下用AOP切入的方法已经得不到用户信息了,就要靠他了。GetUserFilter我会在最后贴出来。
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <context-param>
- <param-name>webAppRootKey</param-name>
- <param-value>webapp.root.webtools</param-value>
- </context-param>
- <!-- Spring ApplicationContext配置文件的路径,可使用通配符。多个路径用逗号分隔。此参数用于后面的Spring-Context loader -->
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/conif/spring/applicationContext-*.xml</param-value>
- </context-param>
- <!--由Spring载入的Log4j配置文件位置-->
- <context-param>
- <param-name>log4jConfigLocation</param-name>
- <param-value>/WEB-INF/conif/log4j/log4j.properties</param-value>
- </context-param>
- <!--Spring默认刷新Log4j配置文件的间隔,单位为millisecond-->
- <context-param>
- <param-name>log4jRefreshInterval</param-name>
- <param-value>60000</param-value>
- </context-param>
- <!-- Log4jConfigListener会去log4j.propeties 读取配置文件;开一条watchdog线程每60秒扫描一下配置文件的变化 -->
- <listener>
- <listener-class>
- org.springframework.web.util.Log4jConfigListener
- </listener-class>
- </listener>
- <!-- 根据spring的配置文件加载spring -->
- <listener>
- <listener-class>
- org.springframework.web.context.ContextLoaderListener
- </listener-class>
- </listener>
- <!-- Spring 刷新Introspector防止内存泄露 -->
- <listener>
- <listener-class>
- org.springframework.web.util.IntrospectorCleanupListener
- </listener-class>
- </listener>
- <servlet>
- <servlet-name>action</servlet-name>
- <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
- <init-param>
- <param-name>config</param-name>
- <param-value>/WEB-INF/conif/struts/struts-config.xml</param-value>
- </init-param>
- <init-param>
- <param-name>debug</param-name>
- <param-value>3</param-value>
- </init-param>
- <init-param>
- <param-name>detail</param-name>
- <param-value>3</param-value>
- </init-param>
- <load-on-startup>0</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>action</servlet-name>
- <url-pattern>*.do</url-pattern>
- </servlet-mapping>
- <welcome-file-list>
- <welcome-file>index.jsp</welcome-file>
- </welcome-file-list>
- <filter>
- <filter-name>Filter</filter-name>
- <filter-class>util.Filter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>Filter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter>
- <filter-name>GetUserFilter</filter-name>
- <filter-class>util.GetUserFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>GetUserFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <error-page>
- <error-code>404</error-code>
- <location>/jsp/error/404.jsp</location>
- </error-page>
- </web-app>
AOP的切面类,他是一个普通类,这个类很简单,这么多代码其实就是为了读取一个配置文件WEB-INF/conif/log4j/Log.properties, 这个文件中配置了方法的具体描述信息:
com.dreamsover.report.assessManage.bs.impl.AssessBsImpl.addAssess=\u6DFB\u52A0\u6BCF\u6708\u5BA1\u6838\u4FE1\u606F
com.dreamsover.report.assessManage.bs.impl.AssessBsImpl.getLineAssesssThisMonth=\u67E5\u8BE2\u672C\u6708\u6240\u6709\u5BA1\u6838\u60C5\u51B5
com.dreamsover.report.checkManage.bs.impl.CheckBsImpl.addCheck=\u6DFB\u52A0\u672C\u6708\u68C0\u67E5\u62A5\u8868
系统记录的就是这些描述信息,AOP用到的方法是addLog,这个方法读取相应的方法名(com.dreamsover.report.assessManage.bs.impl.AssessBsImpl.addAssess),从配置文件得到描述信息,然后用log4j记录。稍候贴出AOP的配置。
- /**
- * 文件名: addLog.java
- * 描述: TODO(日志AOP切面类)
- * 修改人: dreamsover
- * 修改时间: 2010-1-19
- * 修改内容:创建类
- * @author: lio
- * @date: 2010-1-19
- * @version V1.0
- */
- package util;
- import java.io.BufferedInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Properties;
- import javax.servlet.http.HttpServletRequest;
- import org.apache.log4j.Logger;
- import org.aspectj.lang.JoinPoint;
- import org.springframework.core.io.ClassPathResource;
- import org.springframework.jdbc.core.JdbcTemplate;
- import com.dreamsover.report.systemManage.vo.Employee;
- /**
- * 类名:addLog
- *
- * @author: lio
- * @version 1.0
- */
- public class AddLog {
- // 定义LOG4J对象
- static Logger logger = Logger.getLogger(AddLog.class.getName());
- // 日志配置文件
- static Properties properties = null;
- // 读取日志配置文件
- static {
- properties = new Properties();
- try {
- FileInputStream in = new FileInputStream("/" + getWEBINFAddress()
- + File.separator + "conif/log4j/Log.properties");
- properties.load(in);
- } catch (FileNotFoundException e) {
- logger.error("没有找到日志配置文件,请确认你的路径是否正确。");
- } catch (IOException e) {
- logger.error("日志配置文件读写错误");
- }
- }
- /**
- * 描述: 记录系统安全日志的方法
- *
- * @author: lio
- * @param joinPoint
- * @version: 1.0
- */
- @SuppressWarnings("unused")
- private void addLog(JoinPoint joinPoint) {
- String key = joinPoint.getTarget().getClass().getName() + "."
- + joinPoint.getSignature().getName();
- // 得到方法描述信息
- String info = properties.getProperty(key);
- if (info != null && !info.equals("") && !info.equals(" ")) {
- logger.info(info);
- } else {
- /* System.out.println("请检查您的日志配置文件,AOP" +
- "中配置了此方法记录日志,但是没有在配置文件中找到该方法的描述,方法名:" + key);
- */
- }
- }
- /**
- * 处理路径
- * @return
- */
- public static String getWEBINFAddress() {
- Class theClass = AddLog.class;
- java.net.URL u = theClass.getResource("");
- // str会得到这个函数所在类的路径
- String str = u.toString();
- // 截去一些前面6个无用的字符
- str = str.substring(6, str.length());
- // 将%20换成空格(如果文件夹的名称带有空格的话,会在取得的字符串上变成%20)
- str = str.replaceAll("%20", " ");
- // 查找“WEB-INF”在该字符串的位置
- int num = str.indexOf("WEB-INF");
- // 截取即可
- str = str.substring(0, num + "WEB-INF".length());
- return str;
- }
- }
AOP配置文件,AOP实现全靠他了,我就留了一个模块的配置,需要可以轻松的添加,但是记得在WEB-INF/conif/log4j/Log.properties文件中添加相应的描述信息
- <?xml version="1.0" encoding="UTF-8"?>
- <beans
- xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:p="http://www.springframework.org/schema/p"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
- <!-- 日志配置 -->
- <bean id="logClass" class="util.AddLog" />
- <!-- AOP配置 -->
- <aop:aspectj-autoproxy proxy-target-class="true"/>
- <aop:config>
- <aop:aspect id="log" ref="logClass">
- <!-- 审核模块BS层 -->
- <aop:pointcut expression="execution (* com.dreamsover.report.assessManage.bs..*.*(..))" id="logbsAssessPoint"/>
- <aop:after method="addLog" pointcut-ref="logbsAssessPoint"/>
- </aop:aspect>
- </aop:config>
- </beans>
至此,只差一个得到用户的Filter了,其中最重要的是MDC,在log4j中得到用户信息就靠他了
- /**
- * 文件名: GetUserFilter.java
- * 描述: TODO(得到SESSION中的用户)
- * 修改人: lio
- * 修改时间: 2010-1-20
- * 修改内容:创建类
- * @author: lio
- * @date: 2010-1-20
- * @version V1.0
- */
- package util;
- import java.io.IOException;
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import org.apache.log4j.MDC;
- import com.dreamsover.report.systemManage.vo.Employee;
- /**
- * 类名:GetUserFilter
- *
- * @author: dreamsover
- * @version 1.0
- */
- public class GetUserFilter implements Filter {
- //定义默认用户姓名
- private final static String DEFAULT_USER = "guest";
- public void destroy() {
- }
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException, ServletException {
- HttpServletRequest req = (HttpServletRequest) request;
- HttpSession session = req.getSession();
- if (session == null) {
- MDC.put("id", (int) (Math.random() * 1000));
- MDC.put("name", DEFAULT_USER);
- MDC.put("username", DEFAULT_USER);
- } else {
- Employee user = (Employee) session.getAttribute("user");
- if (user == null) {
- MDC.put("id", (int) (Math.random() * 1000));
- MDC.put("name", DEFAULT_USER);
- MDC.put("username", DEFAULT_USER);
- } else {
- MDC.put("id", user.getId());
- MDC.put("name", user.getName());
- MDC.put("username", user.getUsername());
- }
- }
- chain.doFilter(request, response);
- }
- public void init(FilterConfig Config) throws ServletException {
- }
- }
- /**
- * 文件名: GetUserFilter.java
- * 描述: TODO(得到SESSION中的用户)
- * 修改人: lio
- * 修改时间: 2010-1-20
- * 修改内容:创建类
- * @author: lio
- * @date: 2010-1-20
- * @version V1.0
- */
- package util;
- import java.io.IOException;
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import org.apache.log4j.MDC;
- import com.dreamsover.report.systemManage.vo.Employee;
- /**
- * 类名:GetUserFilter
- *
- * @author: dreamsover
- * @version 1.0
- */
- public class GetUserFilter implements Filter {
- //定义默认用户姓名
- private final static String DEFAULT_USER = "guest";
- public void destroy() {
- }
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException, ServletException {
- HttpServletRequest req = (HttpServletRequest) request;
- HttpSession session = req.getSession();
- if (session == null) {
- MDC.put("id", (int) (Math.random() * 1000));
- MDC.put("name", DEFAULT_USER);
- MDC.put("username", DEFAULT_USER);
- } else {
- Employee user = (Employee) session.getAttribute("user");
- if (user == null) {
- MDC.put("id", (int) (Math.random() * 1000));
- MDC.put("name", DEFAULT_USER);
- MDC.put("username", DEFAULT_USER);
- } else {
- MDC.put("id", user.getId());
- MDC.put("name", user.getName());
- MDC.put("username", user.getUsername());
- }
- }
- chain.doFilter(request, response);
- }
- public void init(FilterConfig Config) throws ServletException {
- }
- }
好了,所有代码已经完成了,再整理一下逻辑,一个类中的一个方法被调用时,AOP配置文件会去检查你是否对此方法配置了日志切面,如果配置了,这儿是后向切入,他会在执行此方法之后执行切入类的一个方法(AOP配置此方法),切入类得到了此方法的完整路径名称,他会到一个配置文件中去读取方法描述,然后用log4j记录此描述信息,后面的工作就交给log4j了,log4j会把信息从屏幕输出,并记录到一个日志文件,位一WEB-INF/log下,还会把数据插入到数据库,但是还需要用户信息,不过Filter已经为我准备好了,系统可以记录一条日志信息类似:
2010-01-01 17:34 用户dreamsover[id号]添加了审核信息