Spring Boot + vue-element 开发个人博客项目实战教程(十八、操作日志功能实现)2

简介: Spring Boot + vue-element 开发个人博客项目实战教程(十八、操作日志功能实现)2

4、添加注解

下面我们写完了注解,接下来我们肯定要使用这个注解,但是在什么地方引用呢,当然在我们程序的入库,那就是Controller层,这个是前端操作第一个进来的入口。例如:我们在分类的Controller中添加分类的方法上添加一个注解。

@OperationLogSys(desc = "添加分类", operationType = OperationType.INSERT)

完整代码:

  /**
     * 添加分类
     * @return
     */
    @ApiOperation(value = "添加分类")
    @PostMapping("/create")
    @OperationLogSys(desc = "添加分类", operationType = OperationType.INSERT)
    public JsonResult<Object> categoryCreate(@RequestBody @Valid Category category) {
        int isStatus = categoryService.saveCategory(category);
        if (isStatus == 0) {
            return JsonResult.error("添加分类失败");
        }
        return JsonResult.success();
    }

我们先测试一下这个注解是否有用,操作数据是否保存到了数据中。

打开postman,因为我们上一篇加了登录验证,所以我们在操作其他接口时,要先登录,重启项目之后也要重新登录。

我们先进行登录:登录成功之后,然后我们打开添加分类的接口,新添加一个分类。

看着添加成功了,我们去看下数据库,操作日志有没有数据。看到有数据,也是我们添加的分类,就说明我们添加成功了。好啦,我只添加一个操作日志,大家把所有的增加、删除、修改都进行添加一下,查询数据比较多可加可不加。

接下来我们写一下操作日志,操作日志就比较简单啦,不用写注解啦,直接添加即可。

四、登录日志

接下来我们写一下登录日志,我们只需要再登录的接口的地方写一个插入登录操作的日志即可,由于我们设计的登录日志和操作日志是两张表,所以我们还得写一套登录日志的CRDU操作,废话不多说,开整。

下面我直接写了,大家应该可以看懂。

1、建表语句

DROP TABLE IF EXISTS `person_login_log`;
CREATE TABLE `person_login_log` (
  `id`                BIGINT(20)         NOT NULL   PRIMARY KEY AUTO_INCREMENT        COMMENT '登录访问id',
  `login_name`        VARCHAR(50)        NULL   DEFAULT ''                    COMMENT '登录账号',
  `ip_address`        VARCHAR(128)       NULL   DEFAULT ''                    COMMENT '登录IP地址',
  `login_location`    VARCHAR(255)       NULL       DEFAULT ''                    COMMENT '登录地点',
  `browser_type`      VARCHAR(50)        NULL       DEFAULT ''                    COMMENT '浏览器类型',
  `os`                VARCHAR(50)        NULL       DEFAULT ''                    COMMENT '操作系统',
  `login_status`      TINYINT            NULL       DEFAULT 0                   COMMENT '登录状态,默认0, 0-成功, 1-失败',
  `create_time`       DATETIME               NULL       DEFAULT CURRENT_TIMESTAMP       COMMENT '创建时间'
) ENGINE = InnoDB
  CHARACTER SET = utf8mb4
  COLLATE = utf8mb4_bin
  ROW_FORMAT = Dynamic
  COMMENT '登录日志表';

2、实体类

新建一个LoginOperationLog.java

package com.blog.personalblog.entity;
import lombok.Data;
import java.time.LocalDateTime;
/**
 * @author: SuperMan
 * @create: 2022-04-05
 **/
@Data
public class LoginOperationLog {
    /**
     * 主键id
     */
    private Integer id;
    /**
     * 登录账号
     */
    private String loginName;
    /**
     * 登录IP地址
     */
    private String ipAddress;
    /**
     * 登录地点
     */
    private String loginLocation;
    /**
     * 浏览器类型
     */
    private String browserType;
    /**
     * 操作系统
     */
    private String os;
    /**
     * 登录状态,默认0, 0-成功, 1-失败
     */
    private Integer loginStatus;
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
}

3、业务类

(1)新建一个LoginOperationLogService.java业务接口类

package com.blog.personalblog.service;
import com.blog.personalblog.config.page.PageRequest;
import com.blog.personalblog.entity.LoginOperationLog;
import java.util.List;
/**
 * @author: SuperMan
 * @create: 2022-04-05
 **/
public interface LoginOperationLogService {
    /**
     * 添加登录日志
     *
     * @param loginOperationLog
     * @return
     */
    void saveOperationLog(LoginOperationLog loginOperationLog);
    /**
     * 登录日志列表(分页)
     *
     * @param pageRequest
     * @return
     */
    List<LoginOperationLog> getLoginOperationLogPage(PageRequest pageRequest);
}

(2)新建一个LoginOperationLogServiceImpl.java业务实现类

package com.blog.personalblog.service.Impl;
import com.blog.personalblog.config.page.PageRequest;
import com.blog.personalblog.entity.LoginOperationLog;
import com.blog.personalblog.mapper.LoginOperationLogMapper;
import com.blog.personalblog.service.LoginOperationLogService;
import com.github.pagehelper.PageHelper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
 *
 * @author: SuperMan
 * @create: 2022-04-05
 **/
@Service
public class LoginOperationLogServiceImpl implements LoginOperationLogService {
    @Resource
    private LoginOperationLogMapper loginOperationLogMapper;
    @Override
    public void saveOperationLog(LoginOperationLog loginOperationLog) {
        loginOperationLogMapper.createLoginOperationLog(loginOperationLog);
    }
    @Override
    public List<LoginOperationLog> getLoginOperationLogPage(PageRequest pageRequest) {
        int pageNum = pageRequest.getPageNum();
        int pageSize = pageRequest.getPageSize();
        PageHelper.startPage(pageNum,pageSize);
        List<LoginOperationLog> loginOperationLogList = loginOperationLogMapper.getLoginOperationLogPage();
        return loginOperationLogList;
    }
}

4、数据接口Mapper

新建一个LoginOperationLogMapper.java接口

package com.blog.personalblog.mapper;
import com.blog.personalblog.entity.LoginOperationLog;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
 *
 * @author: SuperMan
 * @create: 2022-04-06
 **/
@Repository
public interface LoginOperationLogMapper {
    /**
     * 创建登录日志
     * @param loginOperationLog
     * @return
     */
    int createLoginOperationLog(LoginOperationLog loginOperationLog);
    /**
     * 分类列表(分页)
     * @return
     */
    List<LoginOperationLog> getLoginOperationLogPage();
}

5、xml文件

新建一个登录日志的LoginOperationLogMapper.xml文件,用来写sql语句。

<?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">
<mapper namespace="com.blog.personalblog.mapper.LoginOperationLogMapper">
    <resultMap id="BaseResultMap" type="com.blog.personalblog.entity.LoginOperationLog">
        <result column="id" jdbcType="INTEGER" property="id"/>
        <result column="login_name" jdbcType="VARCHAR" property="loginName"/>
        <result column="ip_address" jdbcType="VARCHAR" property="ipAddress"/>
        <result column="login_location" jdbcType="VARCHAR" property="loginLocation"/>
        <result column="browser_type" jdbcType="VARCHAR" property="browserType"/>
        <result column="os" jdbcType="VARCHAR" property="os"/>
        <result column="login_status" jdbcType="INTEGER" property="loginStatus"/>
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    </resultMap>
    <insert id="createLoginOperationLog" parameterType="com.blog.personalblog.entity.LoginOperationLog" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO person_login_log (login_name, ip_address, login_location, browser_type, os, login_status)
        VALUES(#{loginName}, #{ipAddress}, #{loginLocation}, #{browserType}, #{os}, #{loginStatus})
    </insert>
    <select id="getLoginOperationLogPage" resultMap="BaseResultMap">
        select * from person_login_log
    </select>
</mapper>

6、接口层

新建一个日志的接口,我看了一下上边的操作日志我也没写接口层,所以我们将操作日志和登录日志写在一个Controller层中了。

先建一个OperationLogController.java

package com.blog.personalblog.controller;
import com.blog.personalblog.config.page.PageRequest;
import com.blog.personalblog.config.page.PageResult;
import com.blog.personalblog.entity.LoginOperationLog;
import com.blog.personalblog.entity.OperationLog;
import com.blog.personalblog.service.LoginOperationLogService;
import com.blog.personalblog.service.OperationLogService;
import com.blog.personalblog.util.JsonResult;
import com.blog.personalblog.util.PageUtil;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
/**
 *
 * @author: SuperMan
 * @create: 2022-04-06
 **/
@Api(tags = "操作日志")
@RestController
@RequestMapping("/log")
public class OperationLogController {
    @Resource
    private LoginOperationLogService loginOperationLogService;
    @Resource
    private OperationLogService operationLogService;
    /**
     * 操作日志列表
     * @param pageRequest
     * @return
     */
    @ApiOperation(value = "操作日志列表")
    @PostMapping("list")
    public JsonResult<Object> OperationLogListPage(@RequestBody @Valid PageRequest pageRequest) {
        List<OperationLog> operationLogPage = operationLogService.getOperationLogPage(pageRequest);
        PageInfo pageInfo = new PageInfo(operationLogPage);
        PageResult pageResult = PageUtil.getPageResult(pageRequest, pageInfo);
        return JsonResult.success(pageResult);
    }
    /**
     * 登录日志列表
     * @param pageRequest
     * @return
     */
    @ApiOperation(value = "登录日志列表")
    @PostMapping("list")
    public JsonResult<Object> LoginOperationLogListPage(@RequestBody @Valid PageRequest pageRequest) {
        List<LoginOperationLog> loginOperationLogPage = loginOperationLogService.getLoginOperationLogPage(pageRequest);
        PageInfo pageInfo = new PageInfo(loginOperationLogPage);
        PageResult pageResult = PageUtil.getPageResult(pageRequest, pageInfo);
        return JsonResult.success(pageResult);
    }
}

好啦,准备工作基本上完成了,接下来我们再登录的时候插入我们的登录日志即可。

7、登录日志编写

打开我们的UserController.java类,然后找到我们的登录方法,我们再UserController中新添加一个方法,用来获取登录信息并且将登录的信息插入到登录日志表中。我们设计的表里有要获取浏览器类型和操作系统,所以我们使用了user-agent-utils 是一个用来解析 User-Agent 字符串的 Java 类库。 其能够识别的内容包括: 超过150种不同的浏览器; 7种不同的浏览器类型; 超过60种不同的操作系统; 6种不同的设备类型; 9种不同的渲染引擎; 9种不同的Web应用,如HttpClient、Bot。


1、添加maven

<dependency>
    <groupId>eu.bitwalker</groupId>
    <artifactId>UserAgentUtils</artifactId>
    <version>1.21</version>
 </dependency>

2、客户端工具类

package com.blog.personalblog.util;
import cn.hutool.core.convert.Convert;
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 javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
 * 客户端工具类
 *
 */
public class ServletUtils {
    /**
     * 获取String参数
     */
    public static String getParameter(String name)
    {
        return getRequest().getParameter(name);
    }
    /**
     * 获取String参数
     */
    public static String getParameter(String name, String defaultValue)
    {
        return Convert.toStr(getRequest().getParameter(name), defaultValue);
    }
    /**
     * 获取Integer参数
     */
    public static Integer getParameterToInt(String name)
    {
        return Convert.toInt(getRequest().getParameter(name));
    }
    /**
     * 获取Integer参数
     */
    public static Integer getParameterToInt(String name, Integer defaultValue)
    {
        return Convert.toInt(getRequest().getParameter(name), defaultValue);
    }
    /**
     * 获取request
     */
    public static HttpServletRequest getRequest()
    {
        return getRequestAttributes().getRequest();
    }
    /**
     * 获取response
     */
    public static HttpServletResponse getResponse()
    {
        return getRequestAttributes().getResponse();
    }
    /**
     * 获取session
     */
    public static HttpSession getSession()
    {
        return getRequest().getSession();
    }
    public static ServletRequestAttributes getRequestAttributes()
    {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
    }
}

下面进行解析agent字符串

UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));

其他的也没有什么,下面就是我们添加登录日志的方法

    /**
     * 获取登录日志
     */
    public void getLoginInfoLog(LoginModel loginModel, Integer status) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes).resolveReference(RequestAttributes.REFERENCE_REQUEST);
        //解析agent字符串
        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        //登录账号
        LoginOperationLog loginOperationLog = new LoginOperationLog();
        loginOperationLog.setLoginName(loginModel.getUsername());
        //登录IP地址
        String ipAddr = IpUtil.getIpAddr(request);
        loginOperationLog.setIpAddress(ipAddr);
        //登录地点
        String ipInfo = IpUtil.getIpInfo(ipAddr);
        loginOperationLog.setLoginLocation(ipInfo);
        //浏览器类型
        String browser = userAgent.getBrowser().getName();
        loginOperationLog.setBrowserType(browser);
        //操作系统
        String os = userAgent.getOperatingSystem().getName();
        loginOperationLog.setOs(os);
        //登录状态
        loginOperationLog.setLoginStatus(status);
        loginOperationLogService.saveOperationLog(loginOperationLog);
    }

然后我们在登录的方法中添加这个方法,一共传了两个参数,其中status是登录的状态,成功是0,失败是1。

    /**
     * 登录
     * @param loginModel
     * @return
     */
    @ApiOperation(value = "登录")
    @PostMapping("/login")
    @OperationLogSys(desc = "登录", operationType = OperationType.LOGIN)
    public JsonResult<Object> login(@RequestBody LoginModel loginModel){
        logger.info("{} 在请求登录! ", loginModel.getUsername());
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(loginModel.getUsername(), loginModel.getPassword(), false);
        try {
            subject.login(token);
            Map<String, Object> ret = new HashedMap();
            ret.put("token", subject.getSession().getId());
            logger.info("{} login success", loginModel.getUsername());
            getLoginInfoLog(loginModel, 0);
            return JsonResult.success(ret);
        } catch (IncorrectCredentialsException e) {
            logger.info("login fail {}", e.getMessage());
            return JsonResult.error(ErrorCode.NOT_LOGIN);
        } catch (LockedAccountException e) {
            logger.info("login fail {}", e.getMessage());
            return JsonResult.error(ErrorCode.ERROR_CODE);
        } catch (AuthenticationException e) {
            logger.info("login fail {}", e.getMessage());
            return JsonResult.error(ErrorCode.USER_NOT_EXIST);
        } catch (Exception e) {
            e.printStackTrace();
            getLoginInfoLog(loginModel, 1);
            logger.info("login fail {}", e.getMessage());
            return JsonResult.error(ErrorCode.ERROR_CODE);
        }
    }

下面是UserController的完整代码:(有些地方改了一点,大家可以看一下)

package com.blog.personalblog.controller;
import cn.hutool.core.util.StrUtil;
import com.blog.personalblog.annotation.OperationLogSys;
import com.blog.personalblog.annotation.OperationType;
import com.blog.personalblog.entity.ErrorCode;
import com.blog.personalblog.entity.LoginModel;
import com.blog.personalblog.entity.LoginOperationLog;
import com.blog.personalblog.service.LoginOperationLogService;
import com.blog.personalblog.util.IpUtil;
import com.blog.personalblog.util.JsonResult;
import com.blog.personalblog.entity.User;
import com.blog.personalblog.service.UserService;
import com.blog.personalblog.util.MD5Util;
import com.blog.personalblog.util.PhoneUtil;
import com.blog.personalblog.util.ServletUtils;
import eu.bitwalker.useragentutils.UserAgent;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.map.HashedMap;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
 * @author: SuperMan
 * 欢迎关注我的公众号:码上言
 * @create: 2021-11-03
 */
@Api(tags = "用户管理")
@RestController
@RequestMapping("/user")
public class UserController {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Resource
    private UserService userService;
    @Resource
    private LoginOperationLogService loginOperationLogService;
    /**
     * 用户列表
     * @return
     */
    @ApiOperation(value = "用户列表")
    @PostMapping("/list")
    public JsonResult<Object> list() {
        List<User> userList = userService.findAll();
        return JsonResult.success(userList);
    }
    /**
     * 添加用户
     * @return
     */
    @ApiOperation(value = "添加用户")
    @PostMapping("/create")
    @OperationLogSys(desc = "添加用户", operationType = OperationType.INSERT)
    public JsonResult<Object> userCreate(@RequestBody @Valid User user) {
        if (StrUtil.isEmpty(user.getPassWord())) {
            return JsonResult.error("密码为空,请填写密码!");
        }
        //密码加密存储
        user.setPassWord(MD5Util.MD5(user.getPassWord()));
        //判断手机号,这里用hutool工具类也可以
        if (!PhoneUtil.checkMobile(user.getPhone())) {
            return JsonResult.error("手机号码格式错误!");
        }
        userService.createUser(user);
        return JsonResult.success();
    }
    /**
     *
     * 修改用户
     * @return
     */
    @ApiOperation(value = "修改用户")
    @PostMapping("/update")
    @OperationLogSys(desc = "修改用户", operationType = OperationType.UPDATE)
    public JsonResult<Object> userUpdate(@RequestBody @Valid User user) {
        if (StrUtil.isEmpty(user.getPassWord())) {
            return JsonResult.error("密码为空,请填写密码!");
        }
        //密码加密存储
        user.setPassWord(MD5Util.MD5(user.getPassWord()));
        //判断手机号,这里用hutool工具类也可以
        if (!PhoneUtil.checkMobile(user.getPhone())) {
            return JsonResult.error("手机号码格式错误!");
        }
        userService.updateUser(user);
        return JsonResult.success();
    }
    /**
     * 删除
     * @return
     */
    @ApiOperation(value = "删除用户")
    @PostMapping("/delete/{id}")
    @OperationLogSys(desc = "删除用户", operationType = OperationType.DELETE)
    public JsonResult<Object> userDelete(@PathVariable(value = "id") int id) {
        userService.deleteUser(id);
        return JsonResult.success();
    }
    /**
     * 登录
     * @param loginModel
     * @return
     */
    @ApiOperation(value = "登录")
    @PostMapping("/login")
    @OperationLogSys(desc = "登录", operationType = OperationType.LOGIN)
    public JsonResult<Object> login(@RequestBody LoginModel loginModel){
        logger.info("{} 在请求登录! ", loginModel.getUsername());
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(loginModel.getUsername(), loginModel.getPassword(), false);
        try {
            subject.login(token);
            Map<String, Object> ret = new HashedMap();
            ret.put("token", subject.getSession().getId());
            logger.info("{} login success", loginModel.getUsername());
            getLoginInfoLog(loginModel, 0);
            return JsonResult.success(ret);
        } catch (IncorrectCredentialsException e) {
            logger.info("login fail {}", e.getMessage());
            return JsonResult.error(ErrorCode.NOT_LOGIN);
        } catch (LockedAccountException e) {
            logger.info("login fail {}", e.getMessage());
            return JsonResult.error(ErrorCode.ERROR_CODE);
        } catch (AuthenticationException e) {
            logger.info("login fail {}", e.getMessage());
            return JsonResult.error(ErrorCode.USER_NOT_EXIST);
        } catch (Exception e) {
            e.printStackTrace();
            getLoginInfoLog(loginModel, 1);
            logger.info("login fail {}", e.getMessage());
            return JsonResult.error(ErrorCode.ERROR_CODE);
        }
    }
    /**
     * 登录info信息
     * @return
     */
    @GetMapping("/info")
    public JsonResult<Object> info(){
        Map<String, Object> ret = new HashMap<>(3);
        ret.put("roles", "[admin]");
        ret.put("name", "admin");
        ret.put("avatar","https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
        return JsonResult.success(ret);
    }
    /**
     * 获取登录日志
     */
    public void getLoginInfoLog(LoginModel loginModel, Integer status) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes).resolveReference(RequestAttributes.REFERENCE_REQUEST);
        //解析agent字符串
        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        //登录账号
        LoginOperationLog loginOperationLog = new LoginOperationLog();
        loginOperationLog.setLoginName(loginModel.getUsername());
        //登录IP地址
        String ipAddr = IpUtil.getIpAddr(request);
        loginOperationLog.setIpAddress(ipAddr);
        //登录地点
        String ipInfo = IpUtil.getIpInfo(ipAddr);
        loginOperationLog.setLoginLocation(ipInfo);
        //浏览器类型
        String browser = userAgent.getBrowser().getName();
        loginOperationLog.setBrowserType(browser);
        //操作系统
        String os = userAgent.getOperatingSystem().getName();
        loginOperationLog.setOs(os);
        //登录状态
        loginOperationLog.setLoginStatus(status);
        loginOperationLogService.saveOperationLog(loginOperationLog);
    }
}

8、测试

我们在postman中模拟登录,然后我们在sql中查看有没有登录日志,这里要说一下,如果你是用的地址为localhost或者127.0.0.1进行请求,我们在获取ip归属地的时候会获取不到,我们可以使用电脑的ip就可以看到。好啦,到这里我们的操作日志就完成了,到此我们所有的后端功能都开发完了,下面我们就写前端代码,后端提供api即可,我们的项目开发2/3了,即将完成了,大家努力啊。

看到现在的阅读量,着实有点惨不忍睹,希望大家多多点赞、收藏、分享啊,大家帮我宣传一下,感谢感谢!

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
目录
相关文章
|
5月前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
6558 89
|
6月前
|
消息中间件 Java Kafka
搭建ELK日志收集,保姆级教程
本文介绍了分布式日志采集的背景及ELK与Kafka的整合应用。传统多服务器环境下,日志查询效率低下,因此需要集中化日志管理。ELK(Elasticsearch、Logstash、Kibana)应运而生,但单独使用ELK在性能上存在瓶颈,故结合Kafka实现高效的日志采集与处理。文章还详细讲解了基于Docker Compose构建ELK+Kafka环境的方法、验证步骤,以及如何在Spring Boot项目中整合ELK+Kafka,并通过Logback配置实现日志的采集与展示。
1144 64
搭建ELK日志收集,保姆级教程
|
7月前
|
前端开发 Java API
利用 Spring WebFlux 技术打造高效非阻塞 API 的完整开发方案与实践技巧
本文介绍了如何使用Spring WebFlux构建高效、可扩展的非阻塞API,涵盖响应式编程核心概念、技术方案设计及具体实现示例,适用于高并发场景下的API开发。
566 0
|
5月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
5月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
636 2
|
6月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
1129 5
|
6月前
|
安全 数据可视化 Java
AiPy开发的 Spring 漏洞检测神器,未授权访问无所遁形
针对Spring站点未授权访问问题,现有工具难以检测如Swagger、Actuator等组件漏洞,且缺乏修复建议。全新AI工具基于Aipy开发,具备图形界面,支持一键扫描常见Spring组件,自动识别未授权访问风险,按漏洞类型标注并提供修复方案,扫描结果可视化展示,支持导出报告,大幅提升渗透测试与漏洞定位效率。
|
7月前
|
缓存 Java API
Spring WebFlux 2025 实操指南详解高性能非阻塞 API 开发全流程核心技巧
本指南基于Spring WebFlux 2025最新技术栈,详解如何构建高性能非阻塞API。涵盖环境搭建、响应式数据访问、注解与函数式两种API开发模式、响应式客户端使用、测试方法及性能优化技巧,助你掌握Spring WebFlux全流程开发核心实践。
1348 0
|
7月前
|
存储 NoSQL Java
探索Spring Boot的函数式Web应用开发
通过这种方式,开发者能以声明式和函数式的编程习惯,构建高效、易测试、并发友好的Web应用,同时也能以较小的学习曲线迅速上手,因为这些概念与Spring Framework其他部分保持一致性。在设计和编码过程中,保持代码的简洁性和高内聚性,有助于维持项目的可管理性,也便于其他开发者阅读和理解。
228 0
|
8月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1236 0