2021.6.28-2021.7.2

文章目录


# 一、使用Aop给项目加上用户操作日志记录 1.定义日志的实体类
package com.aaa.demo.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Date;


@Data
@EqualsAndHashCode(callSuper = false)
public class Log {
    private int id;
    private String username;
    private String operation;
    private String method;
    private Date time;
    private String ip;
}

2.定义元注解

package com.aaa.demo.config;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Mylog {
    String value() default "";
}

3.定义切面

package com.aaa.demo.config;
import com.aaa.demo.entity.Log;
import com.aaa.demo.service.SysLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
@Aspect
@Component
public class SysLogAspect {
    @Autowired
    private SysLogService sysLogService;
    @Autowired
    HttpServletRequest request;
    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut("@annotation( com.aaa.demo.config.Mylog)")
    public void logPoinCut() {
    }
    /**
     * 使用注解拦截的是加上注解的方法、这里注释的是拦截的所有控制层下的方法
     */
//    @Pointcut("execution(public * com.aaa.demo.controller..*.*(..))")
//    public void pointcutController() {}
//
//    @Before("pointcutController()")
//    public void around2(JoinPoint point) {
//        //获取目标方法
//        String methodNam = point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName();
//        //获取方法参数
//        String params = Arrays.toString(point.getArgs());
//        System.out.println("get in:"+methodNam+"params :"+params);
//
//    }
//    @AfterReturning(returning = "result",value = "pointcutController()")
//    public void around3(JoinPoint point,Object result){
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//         从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        String ip = request.getRemoteAddr();
        System.out.println(ip);
//        if(result!=null){
//            System.out.println(result.toString());
//        }
//
//
//    }
    //切面 配置通知
    @AfterReturning("logPoinCut()")
    public void saveSysLog(JoinPoint joinPoint) {
        System.out.println("切面。。。。。");
        //保存日志
        Log log = new Log();
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        //获取操作
        Mylog myLog = method.getAnnotation(Mylog.class);
        if (myLog != null) {
            String value = myLog.value();
            log.setOperation(value);//保存获取的操作
        }
        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        log.setMethod(className + "." + methodName);
//        //请求的参数
//        Object[] args = joinPoint.getArgs();
//        //将参数所在的数组转换成json
//        String params = JSON.toJSONString(args);
//        sysLog.setParams(params);
        Date date = new java.sql.Date(new Date().getTime());
        log.setTime(date);
        //获取用户名
//        sysLog.setUsername(ShiroUtils.getUserEntity().getUsername());
        //获取用户ip地址
//        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
//        sysLog.setIp(IPUtils.getIpAddr(request));
        //调用service保存SysLog实体类到数据库
//        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//        System.out.println(request);
//        String remoteHost = request.getRemoteHost();
//        System.out.println(remoteHost+"-----------------------");
        System.out.println(log);
        sysLogService.save(log);
    }
}

4.在控制层加上相应的注解

package com.aaa.demo.controller;


import com.aaa.demo.config.Mylog;
import com.aaa.demo.entity.FilmInfo;
import com.aaa.demo.service.IFilmInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author gs
 * @since 2021-04-13
 */
@RestController
@RequestMapping("/demo/film-info")
public class FilmInfoController {
    @Resource
    private IFilmInfoService iFilmInfoServicel;
    @Mylog(value = "查询")
    @GetMapping("findAll")
    public List<FilmInfo> findAll(){
        List<FilmInfo> list = iFilmInfoServicel.list();
        return list;
    }
    @Mylog(value = "查询")
    @GetMapping("query")
    public List<FilmInfo> query(Integer typeId){
        System.out.println(typeId);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("film_type",typeId);
        List<FilmInfo> list = iFilmInfoServicel.list(queryWrapper);
        return list;
    }

    @Mylog(value = "新增")
    @PostMapping("add")
    public boolean add(FilmInfo filmInfo){
        System.out.println(filmInfo);
        boolean save = iFilmInfoServicel.save(filmInfo);
        return save;
    }
}

二、ZK的watch

atcher接口
在ZooKeeper中,接口类Watcher用于表示一个标准的事件处理器,其定义了事件通知相关的逻辑,包含KeeperState和EventType两个枚举类,分别代表了通知状态和事件类型,同时定义了事件的回调方法:process(WatchedEvent event)。

Watcher事件
同一个事件类型在不同的通知状态中代表的含义有所不同,下表列举了常见的通知状态和事件类型
2021.6.28-2021.7.2

回调方法process()

process方法是Watcher接口中的一个回调方法,当ZooKeeper向客户端发送一个Watcher事件通知时,客户端就会对相应的process方法进行回调,从而实现对事件的处理。process方法的定义如下:

abstract public void process(WatchedEvent event);

这个回调方法的定义非常简单,我们重点看下方法的参数定义:WatchedEvent。

WatchedEvent包含了每一个事件的三个基本属性:通知状态(keeperState),事件类型(EventType)和节点路径(path),其数据结构如图7-5所示。ZooKeeper使用WatchedEvent对象来封装服务端事件并传递给Watcher,从而方便回调方法process对服务端事件进行处理。

提到WatchedEvent,不得不讲下WatcherEvent实体。笼统地讲,两者表示的是同一个事物,都是对一个服务端事件的封装。不同的是,WatchedEvent是一个逻辑事件,用于服务端和客户端程序执行过程中所需的逻辑对象,而WatcherEvent因为实现了序列化接口,因此可以用于网络传输。

服务端在生成WatchedEvent事件之后,会调用getWrapper方法将自己包装成一个可序列化的WatcherEvent事件,以便通过网络传输到客户端。客户端在接收到服务端的这个事件对象后,首先会将WatcherEvent还原成一个WatchedEvent事件,并传递给process方法处理,回调方法process根据入参就能够解析出完整的服务端事件了。

需要注意的一点是,无论是WatchedEvent还是WatcherEvent,其对ZooKeeper服务端事件的封装都是机及其简单的。举个例子来说,当/zk-book这个节点的数据发生变更时,服务端会发送给客户端一个“ZNode数据内容变更”事件,客户端只能够接收到如下信

三、java后台获取nginx代理实际用户ip地址

原理解释:https://blog.csdn.net/u010020099/article/details/82110988

 public static String getIpAddress(HttpServletRequest request) {  
        String ip = request.getHeader("x-forwarded-for");  
        
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("Proxy-Client-IP");  
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("WL-Proxy-Client-IP");  
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("HTTP_CLIENT_IP");  
        }  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");  
        } 
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getHeader("X-Real-IP");  
        } 
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
            ip = request.getRemoteAddr();  
        }  
        return ip;  
    }

nginx中的配置:

server {
        listen       8100;
        server_name  localhost;
 
        #charset koi8-r;
 
        #access_log  logs/host.access.log  main;
 
        root   html/dist;
 
        location / {
            try_files $uri $uri/ @router;
            index  index.html index.htm;
 
 
        }
 
        location @router {
            rewrite ^.*$ /index.html last;
        }
		
		#设置proxy_set_header值,后端可以根据“ X-Forwarded-For”或“X-real-ip”获取客户端实际ip地址
        location /api/{
            proxy_pass  http://localhost:9001/myWeb/; 
						
			proxy_redirect              off;
 
			proxy_set_header            Host $host;
 
			proxy_set_header            X-real-ip $remote_addr;
 
			proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
        }
 
        #error_page  404              /404.html;
 
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
 
        
    }

经过多个代理的java代码:

 public static final String getClientIp(HttpServletRequest request) {
    String ip = request.getHeader("X-Forwarded-For");
    if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)|| "127.0.0.1".equalsIgnoreCase(ip)) {
      ip = request.getHeader("Proxy-Client-IP");
    }
    if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)|| "127.0.0.1".equalsIgnoreCase(ip)) {
      ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)|| "127.0.0.1".equalsIgnoreCase(ip)) {
      ip = request.getHeader("X-Real-IP");
    }
    if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)|| "127.0.0.1".equalsIgnoreCase(ip)) {
      ip = request.getRemoteAddr();
    }
    if (StringUtils.isBlank(ip) ||"127.0.0.1".equals(ip)|| ip.indexOf(":") > -1) {
      try {
        ip = InetAddress.getLocalHost().getHostAddress();
      } catch (UnknownHostException e) {
        ip = null;
      }
    }
    // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
    if (ip != null && ip.length() > 15) {
      if (ip.indexOf(",") > 0) {
        ip = ip.substring(0, ip.indexOf(","));
      }
    }
    return ip;
  }

四、request中获取url方法的区别

request.getRequestURL() 返回全路径

request.getRequestURI() 返回除去host(域名或者ip)部分的路径

request.getContextPath() 返回工程名部分,如果工程映射为/,此处返回则为空
request.getServletPath() 返回除去host和工程名部分的路径

例如:
request.getRequestURL() http://localhost:8080/jqueryLearn/resources/request.jsp
request.getRequestURI() /jqueryLearn/resources/request.jsp
request.getContextPath()/jqueryLearn
request.getServletPath()/resources/request.jsp

五、存入数据库时间格式的问题

实体类中写Date 数据库中写datetime 可以达到储存年月日时分秒的效果

如果想存入毫秒 可以使用timestamp类型 需要注意的是这个范围在1970-203x之间超过了就无效了

六、equalsignorecase

用来比较字符串是否相等。
与equals不同的是它不区分大小写

七、idea快捷键

类内搜索 ctrl+f
全局搜索 Ctrl+N
整理代码格式 ctrl+alt+f

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

上一篇:2021 4 29


下一篇:java获取访问地址IP的简单方法