1.在log服务中工程写一个Receiver类,用于接收RabbitMQ服务器的消息,并将消息交给sysLogService进行数据库的持久化
@Component
public class Receiver {
private CountDownLatch latch = new CountDownLatch(1);
@Autowired
SysLogService sysLogService;
public void receiveMessage(String message) {
System.out.println("Received <" + message + ">");
SysLog sysLog= JSON.parseObject(message,SysLog.class);
sysLogService.saveLogger(sysLog);
latch.countDown();
}
}
在上述代码中,CountDownLatch起到了类似于信号量的作用,只有其他线程完成一系列的操作,通过latch.countDown()释放信号,其他被阻塞的线程获取到信号才能被唤醒.然后将Receiver注册到MessageListenerAdapter,方法是将Receiver类和类中的接收消息的方法名传到MessageListenerAdapter中:
@Configuration
public class RabbitListener {
public final static String queueName = "spring-boot";
@Bean
Queue queue() {
return new Queue(queueName, false);
}
@Bean
TopicExchange exchange() {
return new TopicExchange("spring-boot-exchange");
}
@Bean
Binding binding(Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(queueName);
}
@Bean
SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(queueName);
container.setMessageListener(listenerAdapter);
return container;
}
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
return new MessageListenerAdapter(receiver, "receiveMessage");
}
}
3.service层,通过dao将消息保存到数据库
4.发送消息:通过AmqpTemplate
@Service
public class LoggerService {
@Autowired
private AmqpTemplate rabbitTemplate;
public void log(SysLog sysLog){
rabbitTemplate.convertAndSend(RabbitConfig.queueName, JSON.toJSONString(sysLog));
}
}
5.通过自定义注解@SysLogger写一个AOP切面,拦截被@SysLogger注解修饰的方法,提取方法中的信息,再通过上述代码发送,这样可以将业务代码和发送日志的代码进行了松耦合
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLogger {
String value() default "";
}
6.写一个类,加上@Aspect注解开启切面,通过@PointCut来声明一个切点,通过@Before注解表明在进入切点之前进行拦截
@Aspect
@Component
public class SysLoggerAspect {
@Autowired
private LoggerService loggerService;
@Pointcut("@annotation(com.yunchao.annotation.SysLogger)")
public void loggerPointCut() {
}
@Before("loggerPointCut()")
public void saveSysLog(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLog sysLog = new SysLog();
SysLogger sysLogger = method.getAnnotation(SysLogger.class);
if(sysLogger != null){
//注解上的描述
sysLog.setOperation(sysLogger.value());
}
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
//请求的参数
Object[] args = joinPoint.getArgs();
String params="";
for(Object o:args){
params+=JSON.toJSONString(o);
}
if(!StringUtils.isEmpty(params)) {
sysLog.setParams(params);
}
//设置IP地址
sysLog.setIp(HttpUtils.getIpAddress());
//用户名
String username = UserUtils.getCurrentPrinciple();
if(!StringUtils.isEmpty(username)) {
sysLog.setUsername(username);
}
sysLog.setCreateDate(new Date());
//保存系统日志
loggerService.log(sysLog);
}
}
7.使用注解的方法:
@ApiOperation(value = "登录", notes = "username和password为必选项")
@PostMapping("/login")
@SysLogger("login")
public RespDTO login(@RequestParam String username , @RequestParam String password){
return userService.login(username,password);
}
8.附上两个工具类:
public class HttpUtils {
/**
* 尝试获取当前请求的HttpServletRequest实例
*
* @return HttpServletRequest
*/
public static HttpServletRequest getHttpServletRequest() {
try {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
} catch (Exception e) {
return null;
}
}
public static Map<String, String> getHeaders(HttpServletRequest request) {
Map<String, String> map = new LinkedHashMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
return map;
}
/**
* 获取请求客户端的真实ip地址
*
* @param request 请求对象
* @return ip地址
*/
public static String getIpAddress(HttpServletRequest request) {
// 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
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.getRemoteAddr();
}
} else if (ip.length() > 15) {
String[] ips = ip.split(",");
for (int index = 0; index < ips.length; index++) {
String strIp = (String) ips[index];
if (!("unknown".equalsIgnoreCase(strIp))) {
ip = strIp;
break;
}
}
}
return ip;
}
/**
* 获取请求客户端的真实ip地址
*
* @param
* @return ip地址
*/
public static String getIpAddress() {
// 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
return getIpAddress(getHttpServletRequest());
}
}
public class UserUtils {
private static final String AUTHORIZATION = "authorization";
/**
* 获取当前请求的token
* @return
*/
public static String getCurrentToken() {
return HttpUtils.getHeaders(HttpUtils.getHttpServletRequest()).get(AUTHORIZATION);
}
/**
* 获取当前请求的用户Id
* @return
*/
public static String getCurrentPrinciple() {
return (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
/**
* 判读当前token用户是否为接口所需的参数username
*
* @param username
* @return
*/
public static boolean isMyself(String username) {
return username.equals(getCurrentPrinciple());
}
/**
* 获取当前请求Authentication
*
* @return
*/
public static Authentication getCurrentAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
/**
* 获取当前请求的权限信息
* @return
*/
public static List<SimpleGrantedAuthority> getCurrentAuthorities() {
return (List<SimpleGrantedAuthority>) SecurityContextHolder.getContext().getAuthentication().getAuthorities();
}
/**
* @param role
* @return
*/
public static boolean hasRole(String role) {
if (!role.startsWith("ROLE_")) {
role = "ROLE_" + role;
}
boolean hasRole = false;
List<SimpleGrantedAuthority> list = getCurrentAuthorities();
for (SimpleGrantedAuthority s : list) {
if (role.equals(s.getAuthority())) {
hasRole = true;
break;
}
}
return hasRole;
}
}