爲了增長數據的安全性,在數據管理的過程當中,咱們須要將操做者訪問時間,操做者的名稱,訪問的IP,訪問資源的URL,執行時長,訪問方法記錄下來存儲到數據庫中,並能夠經過頁面查看。java
日誌表syslogweb
SysLog類spring
1 package club.nipengfei.ssm.domain; 2 3 import java.util.Date; 4 5 public class SysLog { 6 private String id; 7 private Date visitTime; 8 private String visitTimeStr; 9 private String username; 10 private String ip; 11 private String url; 12 private Long executionTime; 13 private String method; 14 15 public String getId() { 16 return id; 17 } 18 19 public void setId(String id) { 20 this.id = id; 21 } 22 23 public Date getVisitTime() { 24 return visitTime; 25 } 26 27 public void setVisitTime(Date visitTime) { 28 this.visitTime = visitTime; 29 } 30 31 public String getVisitTimeStr() { 32 return visitTimeStr; 33 } 34 35 public void setVisitTimeStr(String visitTimeStr) { 36 this.visitTimeStr = visitTimeStr; 37 } 38 39 public String getUsername() { 40 return username; 41 } 42 43 public void setUsername(String username) { 44 this.username = username; 45 } 46 47 public String getIp() { 48 return ip; 49 } 50 51 public void setIp(String ip) { 52 this.ip = ip; 53 } 54 55 public String getUrl() { 56 return url; 57 } 58 59 public void setUrl(String url) { 60 this.url = url; 61 } 62 63 public Long getExecutionTime() { 64 return executionTime; 65 } 66 67 public void setExecutionTime(Long executionTime) { 68 this.executionTime = executionTime; 69 } 70 71 public String getMethod() { 72 return method; 73 } 74 75 public void setMethod(String method) { 76 this.method = method; 77 } 78 }
注意該類做爲切面類須要註解@Aspect數據庫
在該切面類內建立一個前置通知@Before("execution(* club.nipengfei.ssm.controller.*.*(..))"),一個後置通知@After("execution(* club.nipengfei.ssm.controller.*.*(..))"),註解內的屬性表示切入點表達式,在這裏表示controller包下的全部類。apache
直接在前置通知內new一個Date()安全
1 // 獲取當前操做的用戶 2 SecurityContext context = SecurityContextHolder.getContext(); 3 User user =(User) context.getAuthentication().getPrincipal(); 4 String username = user.getUsername();
先在web.xml中新增一個監聽器app
1 <listener> 2 <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> 3 </listener>
經過getRemoteAddr()方法獲取IPdom
1 // 獲取IP地址 2 String ip = request.getRemoteAddr();
思路:獲取類上註解的@RequestMapping的屬性值和方法上註解@RequestMapping的屬性值,並將二者拼接。ide
獲取類上註解屬性值:經過反射獲取操做的類,使用getAnnotation(RequestMapping.class)方法獲取@RequestMapping註解,使用value()獲取屬性this
獲取方法上註解屬性值:經過反射獲取操做的類,使用getMethod()方法獲取方法,使用getAnnotation(RequestMapping.class)方法獲取@RequestMapping註解,使用value()獲取屬性
具體代碼放下面。
在後置通知內new一個Date()減去前置通知的Date()。
1 // 獲取訪問時長 2 long time = new Date().getTime()-visitTime.getTime();
經過類的getMethod()方法獲取方法。
注意:有些方法含參,有些不含參須要分開處理。
1 @Before("execution(* club.nipengfei.ssm.controller.*.*(..))") 2 public void doBefore(JoinPoint jp) throws NoSuchMethodException { 3 visitTime = new Date(); // 當前時間就是開始訪問的類 4 clazz = jp.getTarget().getClass(); // 具體訪問的類 5 String methodName = jp.getSignature().getName(); // 獲取訪問方法名稱 6 Object[] args = jp.getArgs(); // 獲取訪問方法參數 7 8 // 獲取具體執行方法Method對象 9 if (args==null || args.length==0){ 10 method = clazz.getMethod(methodName); 11 } else { 12 Class[] classArgs = new Class[args.length]; 13 for (int i=0;i<args.length;i++){ 14 classArgs[i] = args[i].getClass(); 15 } 16 method = clazz.getMethod(methodName,classArgs); 17 } 18 }
LogAop類的代碼:
1 package club.nipengfei.ssm.controller; 2 3 import club.nipengfei.ssm.domain.SysLog; 4 import club.nipengfei.ssm.service.ISysLogService; 5 import org.aspectj.lang.JoinPoint; 6 import org.aspectj.lang.annotation.After; 7 import org.aspectj.lang.annotation.Aspect; 8 import org.aspectj.lang.annotation.Before; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.security.core.context.SecurityContext; 11 import org.springframework.security.core.context.SecurityContextHolder; 12 import org.springframework.security.core.userdetails.User; 13 import org.springframework.stereotype.Component; 14 import org.springframework.web.bind.annotation.RequestMapping; 15 16 import javax.servlet.http.HttpServletRequest; 17 import java.lang.reflect.Method; 18 import java.util.Date; 19 20 @Component 21 @Aspect 22 public class LogAop { 23 24 @Autowired 25 private HttpServletRequest request; 26 27 @Autowired 28 private ISysLogService sysLogService; 29 30 private Date visitTime; // 開始時間 31 private Class clazz; // 訪問的類 32 private Method method; // 訪問的方法 33 34 // 前置通知 主要獲取開始時間,執行的類哪個,執行的哪個方法 35 @Before("execution(* club.nipengfei.ssm.controller.*.*(..))") 36 public void doBefore(JoinPoint jp) throws NoSuchMethodException { 37 visitTime = new Date(); // 當前時間就是開始訪問的類 38 clazz = jp.getTarget().getClass(); // 具體訪問的類 39 String methodName = jp.getSignature().getName(); // 獲取訪問方法名稱 40 Object[] args = jp.getArgs(); // 獲取訪問方法參數 41 42 // 獲取具體執行方法Method對象 43 if (args==null || args.length==0){ 44 method = clazz.getMethod(methodName); 45 } else { 46 Class[] classArgs = new Class[args.length]; 47 for (int i=0;i<args.length;i++){ 48 classArgs[i] = args[i].getClass(); 49 } 50 method = clazz.getMethod(methodName,classArgs); 51 } 52 } 53 54 // 後置通知 55 @After("execution(* club.nipengfei.ssm.controller.*.*(..))") 56 public void doAfter(JoinPoint jp) throws Exception { 57 58 // 獲取訪問時長 59 long time = new Date().getTime()-visitTime.getTime(); 60 61 String url = ""; 62 // 獲取url 63 if (clazz != null && method !=null && clazz!=LogAop.class){ 64 // 獲取類的@RequestMapping("/orders") 65 RequestMapping clazzAnnotation =(RequestMapping) clazz.getAnnotation(RequestMapping.class); 66 if (clazzAnnotation != null){ 67 String[] classValue = clazzAnnotation.value(); 68 // 獲取方法上的@RequestMapping("xxx") 69 RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class); 70 if (methodAnnotation != null){ 71 String[] methodValue = methodAnnotation.value(); 72 url=classValue[0]+methodValue[0]; 73 74 // 獲取IP地址 75 String ip = request.getRemoteAddr(); 76 77 // 獲取當前操做的用戶 78 SecurityContext context = SecurityContextHolder.getContext(); 79 User user =(User) context.getAuthentication().getPrincipal(); 80 String username = user.getUsername(); 81 82 // 將日誌相關信息封裝到SysLog對象 83 SysLog sysLog = new SysLog(); 84 sysLog.setExecutionTime(time); 85 sysLog.setIp(ip); 86 sysLog.setMethod("[類名] "+clazz.getName()+"[方法名] "+method.getName()); 87 sysLog.setUrl(url); 88 sysLog.setUsername(username); 89 sysLog.setVisitTime(visitTime); 90 91 // 調用service完成操做 92 sysLogService.save(sysLog); 93 } 94 } 95 96 } 97 } 98 }
1 package club.nipengfei.ssm.service.impl; 2 3 import club.nipengfei.ssm.dao.ISysLogDao; 4 import club.nipengfei.ssm.domain.SysLog; 5 import club.nipengfei.ssm.service.ISysLogService; 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.stereotype.Service; 8 import org.springframework.transaction.annotation.Transactional; 9 10 import java.util.List; 11 12 @Service 13 @Transactional 14 public class SysLogServiceImpl implements ISysLogService { 15 16 @Autowired 17 private ISysLogDao sysLogDao; 18 19 @Override 20 public void save(SysLog sysLog) throws Exception { 21 sysLogDao.save(sysLog); 22 } 23 24 }
1 package club.nipengfei.ssm.dao; 2 3 import club.nipengfei.ssm.domain.SysLog; 4 import org.apache.ibatis.annotations.Insert; 5 import org.apache.ibatis.annotations.Select; 6 7 import java.util.List; 8 9 public interface ISysLogDao { 10 11 @Insert("insert into syslog(visitTime,username,ip,url,executionTime,method) values(#{visitTime},#{username},#{ip},#{url},#{executionTime},#{method})") 12 public void save(SysLog sysLog) throws Exception; 13 14 }
當點擊訂單管理時發現,不能正常訪問
查看資料發現由於該findAll方法傳入的形參是int類型,而咱們的切面類經過反射獲取該類的方法時傳入的參數Integer類型。將findAll方法的int改成Integer,發現能正常訪問了。
流程分析圖:
1 package club.nipengfei.ssm.dao; 2 3 import club.nipengfei.ssm.domain.SysLog; 4 import org.apache.ibatis.annotations.Insert; 5 import org.apache.ibatis.annotations.Select; 6 7 import java.util.List; 8 9 public interface ISysLogDao { 10 11 @Insert("insert into syslog(visitTime,username,ip,url,executionTime,method) values(#{visitTime},#{username},#{ip},#{url},#{executionTime},#{method})") 12 public void save(SysLog sysLog) throws Exception; 13 14 @Select("select * from sysLog") 15 List<SysLog> findAll() throws Exception; 16 }
1 package club.nipengfei.ssm.service.impl; 2 3 import club.nipengfei.ssm.dao.ISysLogDao; 4 import club.nipengfei.ssm.domain.SysLog; 5 import club.nipengfei.ssm.service.ISysLogService; 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.stereotype.Service; 8 import org.springframework.transaction.annotation.Transactional; 9 10 import java.util.List; 11 12 @Service 13 @Transactional 14 public class SysLogServiceImpl implements ISysLogService { 15 16 @Autowired 17 private ISysLogDao sysLogDao; 18 19 @Override 20 public void save(SysLog sysLog) throws Exception { 21 sysLogDao.save(sysLog); 22 } 23 24 @Override 25 public List<SysLog> findAll() throws Exception { 26 return sysLogDao.findAll(); 27 } 28 }
1 package club.nipengfei.ssm.controller; 2 3 import club.nipengfei.ssm.domain.SysLog; 4 import club.nipengfei.ssm.service.ISysLogService; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.stereotype.Controller; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.servlet.ModelAndView; 9 10 import java.util.List; 11 12 @Controller 13 @RequestMapping("/sysLog") 14 public class SysLogController { 15 16 @Autowired 17 private ISysLogService sysLogService; 18 19 @RequestMapping("/findAll.do") 20 public ModelAndView findAll() throws Exception { 21 ModelAndView mv = new ModelAndView(); 22 List<SysLog> sysLogList = sysLogService.findAll(); 23 mv.addObject("sysLogs",sysLogList); 24 mv.setViewName("syslog-list"); 25 return mv; 26 } 27 }