目录
一、新建白板Spring项目
二、搭建spring框架
三、引入记录操作日志切面
四、登录
五、登录日志
一、新建白板Spring项目
1、新建一个Spring项目
2、选择Lombok依赖和Spring Web依赖
3、更换2.1.3.RELEASE版本+刷新(稳定版本)——白板项目新建完成
4、启动(会报一个错,把引入包删掉在启动)
二、搭建spring框架
1、引入mybatis依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2、引入Mybatis Plus依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
3、 resource下面新建一个application.yaml文件,加入数据库连接和mybatis plus配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/qcby_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=CTT
username: root
password:
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis-plus配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
typeAliasesPackage: com.qcbt.lxt.byg0417.entity
mapperLocations: classpath:mapper/*.xml
# 全局配置id自增 =>
global-config:
db-config:
id-type: auto
一一对应上
4、添加分页插件,在config包下面新建一个MybatisPlusConfig.java类
@MapperScan("com.example.demo2022.mapper")
@Configuration
public class MybatisPlusConfig {
// 最新版
@Bean // <bean id=""/>
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
5、 在common包下web包下新建一个返回值类WebResultJson.java
/**
* 通用的返回结果封装
*/
@Data
public class WebResultJson {
/**
* 1 返回成功
* 0 返回失败
*/
public final static int OK = 1;
public final static String OK_MSG = "操作成功!";
public final static int FAIL = 0;
public final static String FAIL_MSG = "操作失败!";
private int code;
private String msg;
private Object data;
private WebResultJson(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static WebResultJson ok(){
return ok(OK_MSG,null);
}
public static WebResultJson ok(String msg){
return new WebResultJson(OK,msg,null);
}
public static WebResultJson ok(Object data){
return new WebResultJson(OK,OK_MSG,data);
}
public static WebResultJson ok(String msg,Object data){
return new WebResultJson(OK,msg,data);
}
public static WebResultJson fail(){
return fail(FAIL_MSG,null);
}
public static WebResultJson fail(String msg){
return new WebResultJson(FAIL,msg,null);
}
public static WebResultJson fail(Object data){
return new WebResultJson(FAIL,FAIL_MSG,data);
}
public static WebResultJson fail(String msg,Object data){
return new WebResultJson(FAIL,msg,data);
}
}
6、新建一个测试类User.java、UserMapper、IUserService、UserServiceImpl、UserController(全略)
controller中
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
@RequestMapping("/listAll")
public WebResultJson listAll() {
return WebResultJson.ok(userService.list());
}
}
7、运行http://localhost:8080/user/listAll 测试成功
三、引入记录操作日志切面
1、引入切面依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.35</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、common下面constant包下新建一个全局变量类GlobalConstant.java
public class GlobalConstant {
/**
* 请求头中的token的名称
*
*/
public final static String HEADER_TOKEN = "token";
}
3、把数据库中的OperatorLog表实现mapper、service、等等
4、在demmo2022下的util包下建立TokenUtil.java
public class TokenUtil {
/**
* 创建一个map 用于存储所有的令牌
*
* token - User
*/
private static Map<String, User> tokenMap = new HashMap<>();
/**
* 生成token,存储token-user的对应关系
* 返回token令牌
* @param user
* @return
*/
public static String generateToken(User user){
// 生成唯一不重复的字符串
String token = UUID.randomUUID().toString();
tokenMap.put(token,user);
return token;
}
/**
* 验证token是否合法
* @param token
* @return
*/
public static boolean verify(String token){
return tokenMap.containsKey(token);
}
/**
* 根据token获取用户信息
* @param token
* @return
*/
public static User getUser(String token){
return tokenMap.get(token);
}
public static void main(String[] args) {
for (int i=0; i<20; i++){
System.out.println(UUID.randomUUID().toString());
}
}
}
5、在demmo2022下的aop包下新建OperatorLogAop.java
@Aspect
@Component
@Slf4j
public class OperatorLogAop {
@Autowired
private HttpServletRequest request;
@Autowired
private IOperatorLogService operatorLogService;
//定义切点,注解作为切入点
@Pointcut("execution(public * com.example.demo2022.controller..*.*(..))")
public void logPoinCut() {
}
@Around("logPoinCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
OperatorLog operatorLog = new OperatorLog();
String token = request.getHeader(GlobalConstant.HEADER_TOKEN);
if(!StringUtils.isEmpty(token)){
// 可以从session获取 / token获取
// 从token中获取到用户ID
User user = TokenUtil.getUser(token);
operatorLog.setUserId(user.getId());
}
/**
* 进行业务操作
*/
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
String clz = joinPoint.getTarget().getClass().toString();
operatorLog.setMethodName(clz +"."+ method.getName());
operatorLog.setUrl(request.getRequestURI());
//获取切入点方法参数
Object[] objects = joinPoint.getArgs();
String[] paramNames = signature.getParameterNames();
Map<String,Object> map = new HashMap<>();
for (int i =0;i<paramNames.length;i++){
map.put(paramNames[i],objects[i]);
}
// 入参转化成json
operatorLog.setInParameter(JSONObject.toJSONString(map));
// 执行目标方法 获取返回值
Object r = joinPoint.proceed();
// 如果我们封装了通用的返回结果可以直接转json
operatorLog.setOutParameter(JSONObject.toJSONString(r.toString()));
operatorLog.setCreateTime(LocalDateTime.now());
// 插入数据库,操作日志:
operatorLogService.save(operatorLog);
return r;
}
}
6、运行成功,看数据库operator_log这个表
四、登录
UserController.java中,引入登录方法
@RequestMapping(value = "/login",method = {RequestMethod.GET,RequestMethod.POST})
public WebResultJson login(User user){
if(StringUtils.isEmpty(user.getUsername()) || StringUtils.isEmpty(user.getPassword()) ){
return WebResultJson.fail("用户或者密码为空!");
}
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username",user.getUsername())
.eq("password",user.getPassword());
User userDb = userService.getOne(queryWrapper);
if(userDb != null){
// 获取用户所有的权限信息
// Set<String> menuUrlList = menuService.listUrlByUserId(userDb.getId());
// userDb.setMenuUrlList(menuUrlList);
// 登陆成功了
String token = TokenUtil.generateToken(userDb);
userDb.setToken(token);
// loginLogService.saveLoginLog(userDb.getId());
return WebResultJson.ok(userDb);
}else{
return WebResultJson.fail("用户名或密码错误!");
}
}
http://localhost:8080/user/login?username=admin&password=123456
五、登录日志
1、按数据库login_log表生成实体类,service,mapper,impl
2、在util包下添加一个获取ip,浏览器的名字的类RequestUtil.java
public class RequestUtil {
public static String getIPAddress(HttpServletRequest request) {
String ip = null; //X-Forwarded-For:Squid 服务代理
String ipAddresses = request.getHeader("X-Forwarded-For");
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //Proxy-Client-IP:apache 服务代理
ipAddresses = request.getHeader("Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //WL-Proxy-Client-IP:weblogic 服务代理
ipAddresses = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //HTTP_CLIENT_IP:有些代理服务器
ipAddresses = request.getHeader("HTTP_CLIENT_IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //X-Real-IP:nginx服务代理
ipAddresses = request.getHeader("X-Real-IP");
} //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
if (ipAddresses != null && ipAddresses.length() != 0) {
ip = ipAddresses.split(",")[0];
} //还是不能获取到,最后再通过request.getRemoteAddr();获取
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ip = request.getRemoteAddr();
}
if("0:0:0:0:0:0:0:1".equals(ip)){
return "127.0.0.1";
}
return ip;
}
/**
* 获取操作系统,浏览器及浏览器版本信息
* @param request
* @return
*/
public static String getOsAndBrowserInfo(HttpServletRequest request){
String browserDetails = request.getHeader("User-Agent");
String userAgent = browserDetails;
String user = userAgent.toLowerCase();
String os = "";
String browser = "";
//=================OS Info=======================
if (userAgent.toLowerCase().indexOf("windows") >= 0 )
{
os = "Windows";
} else if(userAgent.toLowerCase().indexOf("mac") >= 0)
{
os = "Mac";
} else if(userAgent.toLowerCase().indexOf("x11") >= 0)
{
os = "Unix";
} else if(userAgent.toLowerCase().indexOf("android") >= 0)
{
os = "Android";
} else if(userAgent.toLowerCase().indexOf("iphone") >= 0)
{
os = "IPhone";
}else{
os = "UnKnown, More-Info: "+userAgent;
}
//===============Browser===========================
if (user.contains("edge"))
{
browser=(userAgent.substring(userAgent.indexOf("Edge")).split(" ")[0]).replace("/", "-");
} else if (user.contains("msie"))
{
String substring=userAgent.substring(userAgent.indexOf("MSIE")).split(";")[0];
browser=substring.split(" ")[0].replace("MSIE", "IE")+"-"+substring.split(" ")[1];
} else if (user.contains("safari") && user.contains("version"))
{
browser=(userAgent.substring(userAgent.indexOf("Safari")).split(" ")[0]).split("/")[0]
+ "-" +(userAgent.substring(userAgent.indexOf("Version")).split(" ")[0]).split("/")[1];
} else if ( user.contains("opr") || user.contains("opera"))
{
if(user.contains("opera")){
browser=(userAgent.substring(userAgent.indexOf("Opera")).split(" ")[0]).split("/")[0]
+"-"+(userAgent.substring(userAgent.indexOf("Version")).split(" ")[0]).split("/")[1];
}else if(user.contains("opr")){
browser=((userAgent.substring(userAgent.indexOf("OPR")).split(" ")[0]).replace("/", "-"))
.replace("OPR", "Opera");
}
} else if (user.contains("chrome"))
{
browser=(userAgent.substring(userAgent.indexOf("Chrome")).split(" ")[0]).replace("/", "-");
} else if ((user.indexOf("mozilla/7.0") > -1) || (user.indexOf("netscape6") != -1) ||
(user.indexOf("mozilla/4.7") != -1) || (user.indexOf("mozilla/4.78") != -1) ||
(user.indexOf("mozilla/4.08") != -1) || (user.indexOf("mozilla/3") != -1) )
{
browser = "Netscape-?";
} else if (user.contains("firefox"))
{
browser=(userAgent.substring(userAgent.indexOf("Firefox")).split(" ")[0]).replace("/", "-");
} else if(user.contains("rv"))
{
String IEVersion = (userAgent.substring(userAgent.indexOf("rv")).split(" ")[0]).replace("rv:", "-");
browser="IE" + IEVersion.substring(0,IEVersion.length() - 1);
} else
{
browser = "UnKnown, More-Info: "+userAgent;
}
return os +" --- "+ browser ;
}
}
3、在LoginLogServiceImpl.java中实现
@Service
public class LoginLogServiceImpl extends ServiceImpl<LoginLogMapper, LoginLog> implements ILoginLogService {
@Autowired
private HttpServletRequest request;
@Override
public void saveLoginLog(long userId){
LoginLog loginLog = new LoginLog();
loginLog.setLoginTime(LocalDateTime.now());
loginLog.setUserId(userId);
//获取ip
loginLog.setIp(RequestUtil.getIPAddress(request));
//获取浏览器信息
loginLog.setBrowserName(RequestUtil.getOsAndBrowserInfo(request));
this.save(loginLog);
}
}
4、在UserController.java中加入
5、浏览器登录http://localhost:8080/user/login?username=admin&password=123456
数据库中会加入字段