功能需求:用户在saas-export项目中使用了什么方法,进行了什么操作,都要记录在日志中,然后在日志管理页面可以查看得到。
功能分析
两个功能,一个是分页显示,一个是保存日志
系统日志管理
- (1)分析
记录用户的访问的Controller与ip等信息
属于监控功能
只要查看与保存功能
- (2)数据组成
- 设置登录用户信息
seesion获取
- 设置企业信息
- IP地址
request获取
- 设置记录时间
- 执行的方法名称
新方法获取
- 执行的类名称
- 设置登录用户信息
SysLog
public class SysLog {
private String id ;
private String userName ;
private String ip ;
private Date time ;
private String method ;
private String action ;
private String companyId ;
private String companyName ;
TestSysLogService
- 分页查询
- 添加
package com.lbl.service.system.syslog.impl;
import com.github.pagehelper.PageInfo;
import com.lbl.domain.system.syslog.SysLog;
import com.lbl.service.system.syslog.ISysLogService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Date;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:spring/applicationContext-*.xml")
@Slf4j
public class SysLogServiceImplTest {
@Autowired
ISysLogService iSysLogService;
//增*删改查*
@Test
public void test01(){
//分页列表
//页面上显示分页列表,就要求业务方法中提供查询PageInfo的方法
PageInfo<SysLog> pi= iSysLogService.findByPage(1,5,"1");
log.info("pi = "+pi);
}
@Test
public void test02(){
//将一个表单数据保存在javaBean中,再将javaBean存到数据库
SysLog sysLog = new SysLog();
//设置登录用户信息
sysLog.setUserName("李柏霖");
//设置企业信息
sysLog.setCompanyId("1");
sysLog.setCompanyName("吉首大学");
//IP地址
sysLog.setIp("192.168.21.99");
//设置记录时间
sysLog.setTime(new Date());
//执行的方法名称
sysLog.setMethod("toList");
//执行的类名称
sysLog.setAction("com.lbl.web.company.CompanyController");
sysLog.setCompanyId("1");
sysLog.setCompanyName("吉首大学");
iSysLogService.saveSysLog(sysLog);
}
}
ISysLogService
public interface ISysLogService {
PageInfo<SysLog> findByPage(int curr, int pageSize, String companyId);
void saveSysLog(SysLog sysLog);
}
SysLogServiceImpl
/**
* Created by 李柏霖
* 2020/11/7 20:33
*/
package com.lbl.service.system.syslog.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lbl.dao.system.syslog.ISysLogDao;
import com.lbl.domain.system.syslog.SysLog;
import com.lbl.service.system.syslog.ISysLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
@Service
public class SysLogServiceImpl implements ISysLogService {
//service调用dao
@Autowired
ISysLogDao iSysLogDao;
@Override
public PageInfo<SysLog> findByPage(int curr, int pageSize, String companyId) {
//设置参数
PageHelper.startPage(curr,pageSize);
//调用全查
List<SysLog> list = iSysLogDao.findAll(companyId);
//包装成PageInfo
PageInfo<SysLog> pi = new PageInfo<>(list);
return pi;
}
@Override
public void saveSysLog(SysLog sysLog) {
String uuid= UUID.randomUUID().toString();
sysLog.setId(uuid);
iSysLogDao.save(sysLog);
}
}
ISysLogDao
public interface ISysLogDao {
List<SysLog> findAll(String companyId);
void save(SysLog sysLog);
}
ISysLogDao.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!--namespace: 需要映射的Dao接口类型-->
<mapper namespace="com.lbl.dao.system.syslog.ISysLogDao">
<!-- 配置映射 字段-->
<resultMap id="syslogMap" type="sysLog">
<id column="id" property="id" />
<result column="user_name" property="userName" />
<result column="ip" property="ip" />
<result column="time" property="time" />
<result column="method" property="method" />
<result column="ACTION" property="action" />
<result column="company_id" property="companyId" />
<result column="company_name" property="companyName" />
</resultMap>
<!-- List<SysLog> findAll(String companyId);-->
<select id="findAll" parameterType="string" resultMap="syslogMap">
select * from st_sys_log where company_id =#{companyId} order by time desc
</select>
<!-- void save(SysLog sysLog);-->
<insert id="save" parameterType="sysLog">
insert into st_sys_log
(
id ,
user_name ,
ip ,
time ,
method ,
ACTION ,
company_id ,
company_name
)
values
(
#{id },
#{userName },
#{ip },
#{time },
#{method },
#{action },
#{companyId },
#{companyName }
)
</insert>
</mapper>
SysLogController
/**
* Created by 李柏霖
* 2020/11/7 20:47
*/
package com.lbl.web.controller.system.syslog;
import com.github.pagehelper.PageInfo;
import com.lbl.domain.system.syslog.SysLog;
import com.lbl.service.system.syslog.ISysLogService;
import com.lbl.web.controller.BaseController;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/system/syslog")
@Slf4j
public class SysLogController extends BaseController {
@Autowired
ISysLogService iSysLogService;
@RequestMapping(path = "/toList.do", method = {RequestMethod.GET, RequestMethod.POST})
public String toList(Model model, @RequestParam(defaultValue = "1") int curr, @RequestParam(defaultValue = "5") int pageSize) {
//调查询分页列表的方法
PageInfo<SysLog> pi = iSysLogService.findByPage(curr, pageSize, getLoginCompanyId());
//将pi添加到页面
request.setAttribute("pi", pi);
model.addAttribute("pageSize",pageSize);
return "system/syslog/log-list";
}
}
log-list.jsp
<c:forEach items="${pi.list}" var="log" varStatus="st">
<tr>
<td>${st.count }</td>
<td>${log.userName }</td>
<td>${log.ip}</td>
<td>${log.time}</td>
<td>${log.action}.${log.method}</td>
</tr>
</c:forEach>
系统日志管理 优化日志列表
- (1)分析
日志记录多,生成的页号按钮多 - (2)实现
控制循环次数
并进行边界判断
<c:forEach begin="${pi.pageNum-5 <= 0 ? 1:pi.pageNum-5 }" end="${pi.pageNum+5>pi.pages?pi.pages:pi.pageNum+5}"
var="i">
<li class="paginate_button ${pi.pageNum==i ? 'active':''}"><a href="javascript:goPage(${i})">${i}</a></li>
</c:forEach>
优化
我这边后面还进行了优化,就是分两种情况.
当pageNum<=5时,且pi.pageNum+5>pi.pages时end=10
当pageNum>5时,且pi.pageNum+5>pi.pages时end=pi.pageNum+5
<c:if test="${pi.pageNum<=5}">
<c:forEach begin="${pi.pageNum-5 <= 0 ? 1:pi.pageNum-5 }" end="${pi.pageNum+5>pi.pages?pi.pages:10}"
var="i">
<li class="paginate_button ${pi.pageNum==i ? 'active':''}"><a href="javascript:goPage(${i})">${i}</a></li>
</c:forEach>
</c:if>
<c:if test="${pi.pageNum>5}">
<c:forEach begin="${pi.pageNum-4 <= 0 ? 1:pi.pageNum-4 }" end="${pi.pageNum+5>pi.pages?pi.pages:pi.pageNum+5}"
var="i">
<li class="paginate_button ${pi.pageNum==i ? 'active':''}"><a href="javascript:goPage(${i})">${i}</a></li>
</c:forEach>
</c:if>
优化版
<c:choose>
<c:when test="${pi.pages>10}">
<c:if test="${pi.pageNum<=5}">
<c:forEach begin="${pi.pageNum-5 <= 0 ? 1:pi.pageNum-5 }" end="${pi.pageNum+5>pi.pages?pi.pages:10}"
var="i">
<li class="paginate_button ${pi.pageNum==i ? 'active':''}"><a href="javascript:goPage(${i})">${i}</a></li>
</c:forEach>
</c:if>
<c:if test="${pi.pageNum>5}">
<c:forEach begin="${pi.pageNum-4 <= 0 ? 1:pi.pageNum-4 }" end="${pi.pageNum+5>pi.pages?pi.pages:pi.pageNum+5}"
var="i">
<li class="paginate_button ${pi.pageNum==i ? 'active':''}"><a href="javascript:goPage(${i})">${i}</a></li>
</c:forEach>
</c:if>
</c:when>
<c:when test="${pi.pages<10}">
<c:forEach begin="${pi.pageNum-4 <= 0 ? 1:pi.pageNum-4 }" end="${pi.pageNum+5>pi.pages?pi.pages:pi.pages}"
var="i">
<li class="paginate_button ${pi.pageNum==i ? 'active':''}"><a href="javascript:goPage(${i})">${i}</a></li>
</c:forEach>
</c:when>
</c:choose>
Aop记录日志
- (1)什么是AOP
AOP ,Aspect Oritentd Programing 面向切面编程
本质就是在不改变代码的基础上生成动态代理类(新类)
- (2)应用场景
》日志记录:
》事务管理
》权限管理
》性能数据记录
Aop记录日志
- (1)实现步骤
- 编写springmvc.xml, 开启Aop自动代理
- 编写日志切面类(@Aspect)
- 测试Aop,自动记录日志。
- (2)实现
LogAspect
1. 编写日志切面类(@Aspect)
/**
* Created by 李柏霖
* 2020/11/8 19:30
*/
package com.lbl.web.utils;
import com.lbl.domain.system.syslog.SysLog;
import com.lbl.domain.system.user.User;
import com.lbl.service.system.syslog.ISysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;
//第一步:编写切面类
@Aspect //配置了aop逻辑
@Component //非Controller,Service Repository
@Slf4j
public class LogAspect {
public LogAspect() {
log.info("LogAspect 无参构造方法执行");
}
//要对所有的Controller的方法进行配置
//指定包名 controller 下以及它的所有子包
//
@Around(value = "execution(* com.lbl.web.controller..*.*Controller.*(..))")
public Object writeLog(ProceedingJoinPoint jp) {//切点
// jp表示Controller中的任意方法 toList toAdd toUpdate add update delete
//逻辑
Object result = null;//返回一个表示页面的字符串,也可通是json数据
try {
//前置
result = jp.proceed();//执行
//后置
//保存日志
log.info("切面:writeLog");
saveSysLog(jp);
} catch (Throwable e) {
//异常
} finally {
//最终
}
return result;
}
@Autowired
ISysLogService iSysLogService;
//登录成功之后session中是保存一个user对象的
@Autowired
HttpSession session;
//request对象可以直接获取对方浏览器的IP
@Autowired
HttpServletRequest request;
private void saveSysLog(ProceedingJoinPoint jp) {
//将一个表单数据保存在javaBean中,再将javaBean存到数据库
SysLog sysLog = new SysLog();
User user = (User) session.getAttribute("loginUser");
if (user != null) {
//设置登录用户信息
sysLog.setUserName(user.getUserName());
//设置企业信息
sysLog.setCompanyId(user.getCompanyId());
sysLog.setCompanyName(user.getCompanyName());
}
//IP地址 request.getLocalAddr()获取请求中的ip地址
sysLog.setIp(request.getLocalAddr());
//设置记录时间
sysLog.setTime(new Date());
//执行的方法名称 jp.getSignature() 当前执行的方法 toList
sysLog.setMethod(jp.getSignature().getName());
//执行的类名称 jp.getTarget()目标对象
sysLog.setAction(jp.getTarget().getClass().getName());
log.info("saveSysLog sysLog " + sysLog);
iSysLogService.saveSysLog(sysLog);
}
}
2.编写springmvc.xml, 开启Aop自动代理
<!--开启AOP切面注解: 整个项目扫描有没有@Aspect注解-->
<aop:aspectj-autoproxy/>
如果标签报错,需要添加aop的标签声明,重新打一遍<aop:aspectj-autoproxy/>
就可以了,IDEA会自动加上aop的标签声明。