文章目录
- 二、ZK的watch
- 三、java后台获取nginx代理实际用户ip地址
- 四、request中获取url方法的区别
- 五、存入数据库时间格式的问题
- 六、equalsignorecase
- 七、idea快捷键
- 总结
# 一、使用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事件
同一个事件类型在不同的通知状态中代表的含义有所不同,下表列举了常见的通知状态和事件类型
回调方法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提供了大量能使我们快速便捷地处理数据的函数和方法。