需求:
針對不同的action 方法中有修改刪除的敏感操作的接口,需要記錄對應的參數,ip地址,員工的id名稱等信息,方便追責定位問題
分析:
1.使用註解將對應方法打上標記
2.每次調用完該方法的時候纔開始記錄日誌
3.需要記錄用戶請求的ip地址,參數,用戶名稱等等
①定義註解
import java.lang.annotation.*;
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {
//對標記接口的補充說明
String content() default "";
String operType() default "0";
int operLevel() default 0; //操作等級
}
②定義切面
/**
* 操作日誌切面配置
*/
@Aspect
@Component("operateLogAspect")
public class OperateLogAspect {
private Logger logger = LoggerFactory.getLogger(getClass());
//注入持久化該日誌信息的service
@Autowired
private OperateService operateService;
//注入根據request獲取登錄用戶信息的service
@Autowired
private SysUserService sysUserService;
@After(value = "execution (* com.web.controller..*.*(..))") //指定切點,使用after 讓該切面在方法執行完成後切入
public void after(JoinPoint point) throws Throwable {
try {
// 攔截的action方法上面的標記是否包含 MethodLog 的註解
Map<String, Object> map = getMthodRemark(point);
if (map.isEmpty()) {
// 沒有MethodLog 註解標記 ,無此配置,直接返回
return;
}
//獲取requestBody 參數信息,過濾掉 ServletRequest 和 ServletResponse 類型的參數
Object object = Arrays.stream(point.getArgs()).filter(t ->!( t instanceof ServletRequest) && !( t instanceof ServletResponse) ).collect(Collectors.toList());
//請求參數轉成jsonString
String requestBody = JSONObject.toJSONString(object);
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
if (null == request) {
logger.info("獲取request失敗.直接返回");
return;
}
//根據request獲取用戶ID
Long userId = this.getSysUserId(request);
if (userId == null) {
logger.error("未從request中獲取到員工信息,直接返回");
return;
}
//獲取用戶數使用客戶端信息
String userAgent = request.getHeader("user-agent");
//根據用戶ID調用service獲取用戶信息
SystemUser myUser = sysUserService.queryOne(userId);
//獲取該方法的名稱
String requestMethod = request.getMethod();
StringBuffer params = new StringBuffer();
// action方法名稱
String actionName = point.getSignature().getName();
String pms = requestBody;
// 構建操作日誌對象
OperateLog log = new OperateLog();
log.setUserId(Integer.parseInt("" + myUser.getUserId()));
log.setUserName(myUser.getUserName());
log.setOperContent(null == map.get("content") ? "" : map.get("content").toString());
log.setOperLevel(null == map.get("operLevel") ? 0 : Integer.parseInt(map.get("operLevel").toString()));
log.setOpParams(pms);
log.setOperUserAgent(userAgent);
log.setOpIp(getIpAdrress(request));
log.setOpSysType(null == map.get("operType") ? 0 : Integer.parseInt(map.get("operType").toString()));
log.setOperMethod(actionName);
log.setOpDisplayMode("");
operateLogService.insertOperateLog(log);
}catch (JSONException je){
logger.error("記錄操作日誌參數異常,json轉型異常:{}", je.getMessage());
} catch (Exception e) {
logger.error("記錄操作日誌出錯:{}", StackTraceLogUtil.getStackTraceAsString(e));
}
return;
}
/**
* 計算兩天是否同一天
*
* @param day1
* @param day2
* @return
*/
public boolean isSameDay(Date day1, Date day2) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String ds1 = sdf.format(day1);
String ds2 = sdf.format(day2);
return ds1.equals(ds2) ? true : false;
}
/**
* @param request
* @return 當前登陸員工Id
* @desc 獲取當前登陸用戶Id
*/
protected Long getSysUserId(HttpServletRequest request) {
Object object = request.getAttribute(CommonConstant.UID);
if (object == null)
object = request.getHeader(CommonConstant.UID);
return Optional.ofNullable(object).isPresent() ? Long.valueOf(String.valueOf(object)) : null;
}
/**
* 是否相差time
*
* @param d1
* @param d2
* @param time
* @return
*/
public boolean isDifferTime(Date d1, Date d2, int time) {
if ((d2.getTime() - d1.getTime()) / 1000 / 60 > time)
return true;
else
return false;
}
/**
* 獲取Ip地址
* @param request
* @return
*/
private static String getIpAdrress(HttpServletRequest request) {
String Xip = request.getHeader("X-Real-IP");
String XFor = request.getHeader("X-Forwarded-For");
if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
//多次反向代理後會有多個ip值,第一個ip纔是真實ip
int index = XFor.indexOf(",");
if(index != -1){
return XFor.substring(0,index);
}else{
return XFor;
}
}
XFor = Xip;
if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
return XFor;
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getRemoteAddr();
}
return XFor;
}
// 獲取方法的中文備註____用於記錄用戶的操作日誌描述
@SuppressWarnings("rawtypes")
public static Map<String, Object> getMthodRemark(JoinPoint joinPoint)
throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Map<String, Object> map = Maps.newHashMap();
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
String methode = "";
for (Method m : method) {
if (m.getName().equals(methodName)) {
Class[] tmpCs = m.getParameterTypes();
if (tmpCs.length == arguments.length) {
MethodLog methodCache = m.getAnnotation(MethodLog.class);
if (methodCache != null) {
methode = methodCache.content();
String operType = methodCache.operType();
int level = methodCache.operLevel();
map.put("content", methode);
map.put("operLevel", level);
map.put("operType", operType);
}
break;
}
}
}
return map;
}
}
具體是持久化方法之類的我就不貼了,這裏只是提供一個思路,如果有問題的歡迎指正,謝謝