在ssm框架中因为要记录使用者的访问信息,所以要使用日志系统;
首先定义一个类,用来保存访问的信息;
public class SysLog { private Integer id; private Date visitTime;//访问时间 private String username; private String ip; private String url; private Long executionTime;//执行时长 private String method;//访问的方法
然后定义一个切面方法。
@Component @Aspect public class LogAop {
使用@Component和@Aspect注解,因为这个类不是controller方法或者service方法,所以使用Component注解,Aspect是
定义两个方法
@Before("execution(* com.hengheng.controller.*.*(..))") public void doBefore(JoinPoint jp) throws NoSuchMethodException { @After("execution(* com.hengheng.controller.*.*(..))") public void doAfter(JoinPoint jp){
一个前置通知,一个后置通知,使用JoinPoint 获取
JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
常用api:
方法名 | 功能 |
---|---|
Signature getSignature(); | 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
Object[] getArgs(); | 获取传入目标方法的参数对象 |
Object getTarget(); | 获取被代理的对象 |
Object getThis(); | 获取代理对象 |
首先在SysAop类中定义一些属性,用来接收访问信息,
private Date visitTime;//访问时间 private Class clazz;//访问的类 private Method method;//访问的方法
然后就可以开始获取自己需要的信息了
在前置方法中获取访问的时间,还有访问的类,和访问的方法
//前置通知 主要是获取开始时间 ,执行的是哪个类,执行的是哪个方法 @Before("execution(* com.hengheng.controller.*.*(..))") public void doBefore(JoinPoint jp) throws NoSuchMethodException { visitTime = new Date();//访问的时间 clazz = jp.getTarget().getClass();//jp.getTarget()获取被代理对象 String methodName = jp.getSignature().getName();//获取访问的方法的名字.joinpoint.getSignature():(signature是信号,标识的意思):获取被增强的方法相关信息 Object[] args = jp.getArgs();//获取访问方法的参数 //获取具体的访问的方法 if(args == null || args.length == 0){//无参数 method = clazz.getMethod(methodName);//获取无参数的方法 }else { Class[] classArgs = new Class[args.length]; for (int i = 0;i<args.length;i++){ classArgs[i] = args[i].getClass(); } method = clazz.getMethod(methodName, classArgs);//getMethod(String, Class<?>...) } }
在后置方法中可以获取总时长,访问的URL,访问的用户,访问的ip
@After("execution(* com.hengheng.controller.*.*(..))") public void doAfter(JoinPoint jp){ //访问的时长 Long totalTime = new Date().getTime() - visitTime.getTime(); String url = ""; //clazz访问的类;method访问的方法;clazz != LogAop.class 访问的类不是LogAop if(clazz != null&&method != null&&clazz != LogAop.class){ //获取类上的注解 RequestMapping clazzAnnotation = (RequestMapping) clazz.getAnnotation(RequestMapping.class); //获取注解中的值@RequestMapping("/findUserByIdAndAllRole.do")中的值 String[] clazzUrl = clazzAnnotation.value(); //获取方法上的注解 RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class); String[] methodUrl = methodAnnotation.value(); url = clazzUrl[0]+methodUrl[0]; } //获取当前的访问用户,因我是用的是shiro所以在realm中曾经获取过用户,可以参考 String username = (String) SecurityUtils.getSubject().getPrincipal(); //获取访问的ip,要使用request对象,但是首先要在web.xml中配置request的过滤器RequestContextListener,这样在 本类中就可以注入一个 request的对象 //@Autowired // private HttpServletRequest request; //就可以使用request对象了 String ip = request.getRemoteAddr(); SysLog sysLog = new SysLog(); sysLog.setExecutionTime(totalTime); sysLog.setIp(ip); sysLog.setMethod("[类名] "+clazz.getName()+"[方法名] "+method.getName()); sysLog.setUrl(url); sysLog.setUsername(username); sysLog.setVisitTime(visitTime); System.out.println(sysLog); }
注意当需要使用request对象的时候要在web。xml中 配置request的listener监听器
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
这样就可以注入HttpServletRequest对象了,或者使用shiro获取也可以。
@Autowired private HttpServletRequest request;
//就可以使用request对象了 String ip = request.getRemoteAddr();
使用shiro 获取用户名和ip(参考)
private String getUsername() { Object principal = SecurityUtils.getSubject().getPrincipal(); return principal.toString(); } private String getIp(){ Subject subject = SecurityUtils.getSubject(); String host = subject.getSession().getHost(); return host; }
注意,获取用户时,因为使用的是shiro框架,所以要使用
//获取当前的访问用户,因我是用的是shiro所以在realm中曾经获取过用户,可以参考 String username = (String) SecurityUtils.getSubject().getPrincipal();
SecurityUtils.getSubject(),获取shiro的Subject主体
SecurityUtils.getSubject().getPrincipal()这个方法获取的是在自定义的Realm中
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,credentialsSalt, getName());
标红的位置传的是什么,SecurityUtils.getSubject().getPrincipal()获取的就是什么,可以是User对象,或者用户名。
//获取当前的访问用户,因我是用的是shiro所以在realm中曾经获取过用户,可以参考
String username = (String) SecurityUtils.getSubject().getPrincipal();