ELK 从入门到精通:Spring Boot 实战三部曲(二)—— 进阶特性与性能优化

ELK 从入门到精通:Spring Boot 实战三部曲(二)------ 进阶特性与性能优化

专题导读:本系列共三篇,带你系统掌握 ELK 在 Spring Boot 项目中的实战应用。

  • 第一篇 基础核心与快速上手
  • 第二篇:进阶特性与性能优化(本文)
  • 第三篇 高级应用与架构设计

📖 前言

在上一篇文章中,我们学习了 ELK 的基础概念和基本操作。本文将深入探讨 Elasticsearch 的高级查询、性能优化技巧、Logstash 高级处理以及 Kibana 高级可视化,帮助你构建高性能的日志分析系统。

学完本文你将掌握:

  • ✅ Elasticsearch 高级查询与聚合分析
  • ✅ 性能优化技巧与参数调优
  • ✅ Logstash 高级过滤器与数据处理
  • ✅ Kibana 高级可视化与告警配置
  • ✅ 安全加固与权限控制
  • ✅ 数据备份与恢复策略

一、Elasticsearch 高级查询

1.1 全文检索优化

Multi-Match 查询
java 复制代码
/**
 * 多字段搜索
 */
public List<ProductDocument> searchProducts(String keyword) {
    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(QueryBuilders.multiMatchQuery(keyword)
            .field("name", 3.0f)        // name 字段权重更高
            .field("description", 1.0f)
            .field("category", 1.5f)
            .type(MultiMatchQueryBuilder.Type.BEST_FIELDS)
        )
        .withPageable(PageRequest.of(0, 20))
        .build();
    
    SearchHits<ProductDocument> hits = elasticsearchTemplate.search(
        query, ProductDocument.class
    );
    
    return hits.stream()
        .map(SearchHit::getContent)
        .collect(Collectors.toList());
}
高亮显示
java 复制代码
/**
 * 带高亮的搜索
 */
public Map<String, Object> searchWithHighlight(String keyword) {
    HighlightBuilder highlightBuilder = new HighlightBuilder()
        .field(new HighlightBuilder.Field("name")
            .preTags("<em class=\"highlight\">")
            .postTags("</em>"))
        .field(new HighlightBuilder.Field("description")
            .fragmentSize(150)
            .numOfFragments(3));
    
    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(QueryBuilders.matchQuery("name", keyword))
        .withHighlightBuilder(highlightBuilder)
        .withPageable(PageRequest.of(0, 10))
        .build();
    
    SearchHits<ProductDocument> hits = elasticsearchTemplate.search(
        query, ProductDocument.class
    );
    
    List<Map<String, Object>> results = new ArrayList<>();
    for (SearchHit<ProductDocument> hit : hits) {
        Map<String, Object> result = new HashMap<>();
        result.put("document", hit.getContent());
        result.put("highlights", hit.getHighlightFields());
        results.add(result);
    }
    
    Map<String, Object> response = new HashMap<>();
    response.put("total", hits.getTotalHits());
    response.put("results", results);
    
    return response;
}

1.2 复杂聚合分析

嵌套聚合
java 复制代码
/**
 * 多维度统计分析
 */
public Map<String, Object> complexAggregation() {
    // 按类别分组,再按价格区间统计
    TermsAggregationBuilder categoryAgg = AggregationBuilders
        .terms("by_category")
        .field("category.keyword")
        .size(10)
        .subAggregation(
            AggregationBuilders.range("price_range")
                .field("price")
                .addUnboundedTo(100)
                .addRange(100, 500)
                .addRange(500, 1000)
                .addUnboundedFrom(1000)
        )
        .subAggregation(
            AggregationBuilders.avg("avg_price")
                .field("price")
        );
    
    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .addAggregation(categoryAgg)
        .build();
    
    SearchHits<ProductDocument> hits = elasticsearchTemplate.search(
        query, ProductDocument.class
    );
    
    Terms categories = hits.getAggregations().get("by_category");
    
    Map<String, Object> result = new HashMap<>();
    List<Map<String, Object>> categoryStats = new ArrayList<>();
    
    for (Terms.Bucket bucket : categories.getBuckets()) {
        Map<String, Object> categoryData = new HashMap<>();
        categoryData.put("category", bucket.getKeyAsString());
        categoryData.put("count", bucket.getDocCount());
        
        // 价格区间分布
        Range priceRange = bucket.getAggregations().get("price_range");
        List<Map<String, Object>> ranges = new ArrayList<>();
        for (Range.Bucket rangeBucket : priceRange.getBuckets()) {
            Map<String, Object> rangeData = new HashMap<>();
            rangeData.put("range", rangeBucket.getKeyAsString());
            rangeData.put("count", rangeBucket.getDocCount());
            ranges.add(rangeData);
        }
        categoryData.put("priceDistribution", ranges);
        
        // 平均价格
        Avg avgPrice = bucket.getAggregations().get("avg_price");
        categoryData.put("avgPrice", avgPrice.getValue());
        
        categoryStats.add(categoryData);
    }
    
    result.put("categories", categoryStats);
    return result;
}
日期直方图聚合
java 复制代码
/**
 * 时间序列分析
 */
public List<Map<String, Object>> timeSeriesAnalysis() {
    DateHistogramAggregationBuilder dateHistogram = AggregationBuilders
        .dateHistogram("sales_over_time")
        .field("createTime")
        .calendarInterval(DateHistogramInterval.DAY)
        .format("yyyy-MM-dd")
        .subAggregation(
            AggregationBuilders.sum("daily_sales")
                .field("price")
        )
        .subAggregation(
            AggregationBuilders.cardinality("unique_customers")
                .field("customerId.keyword")
        );
    
    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .addAggregation(dateHistogram)
        .build();
    
    SearchHits<OrderDocument> hits = elasticsearchTemplate.search(
        query, OrderDocument.class
    );
    
    Histogram histogram = hits.getAggregations().get("sales_over_time");
    
    List<Map<String, Object>> result = new ArrayList<>();
    for (Histogram.Bucket bucket : histogram.getBuckets()) {
        Map<String, Object> data = new HashMap<>();
        data.put("date", bucket.getKeyAsString());
        data.put("orderCount", bucket.getDocCount());
        
        Sum dailySales = bucket.getAggregations().get("daily_sales");
        data.put("totalSales", dailySales.getValue());
        
        Cardinality uniqueCustomers = bucket.getAggregations().get("unique_customers");
        data.put("uniqueCustomers", uniqueCustomers.getValue());
        
        result.add(data);
    }
    
    return result;
}

1.3 地理位置查询

java 复制代码
@Data
@Document(indexName = "store_index")
public class StoreDocument {
    
    @Id
    private String id;
    
    @Field(type = FieldType.Text)
    private String name;
    
    @GeoPointField
    private GeoPoint location;
    
    @Field(type = FieldType.Keyword)
    private String address;
}

/**
 * 附近搜索
 */
public List<StoreDocument> searchNearby(double lat, double lon, double distanceKm) {
    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(QueryBuilders.geoDistanceQuery("location")
            .point(lat, lon)
            .distance(distanceKm, DistanceUnit.KILOMETERS)
        )
        .withSort(SortBuilders.geoDistanceSort("location", lat, lon)
            .order(SortOrder.ASC)
            .unit(DistanceUnit.KILOMETERS)
        )
        .withPageable(PageRequest.of(0, 20))
        .build();
    
    SearchHits<StoreDocument> hits = elasticsearchTemplate.search(
        query, StoreDocument.class
    );
    
    return hits.stream()
        .map(SearchHit::getContent)
        .collect(Collectors.toList());
}

二、性能优化实战

2.1 索引优化

Mapping 优化
java 复制代码
@Data
@Document(indexName = "optimized_index")
@Setting(settingPath = "/elasticsearch/settings.json")
public class OptimizedDocument {
    
    @Id
    private String id;
    
    // 不需要分词的字段使用 keyword
    @Field(type = FieldType.Keyword)
    private String status;
    
    // 需要全文检索的字段使用 text + ik 分词
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String content;
    
    // 数值类型选择合适的精度
    @Field(type = FieldType.Integer)
    private Integer count;
    
    @Field(type = FieldType.Long)
    private Long timestamp;
    
    // 不需要存储的字段
    @Field(type = FieldType.Text, store = false)
    private String description;
    
    // 禁用 _all 字段(7.x已移除)
    // 禁用 source(谨慎使用)
}

settings.json:

json 复制代码
{
  "index": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "refresh_interval": "30s",
    "translog": {
      "durability": "async",
      "sync_interval": "5s"
    },
    "merge": {
      "policy": {
        "max_merged_segment": "5gb",
        "segments_per_tier": 10
      }
    }
  }
}
批量导入优化
java 复制代码
@Service
public class BulkImportService {
    
    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;
    
    private static final int BATCH_SIZE = 1000;

    /**
     * 批量导入数据
     */
    public void bulkImport(List<ProductDocument> products) {
        List<IndexQuery> queries = new ArrayList<>();
        
        for (ProductDocument product : products) {
            IndexQuery indexQuery = new IndexQueryBuilder()
                .withId(product.getId())
                .withObject(product)
                .build();
            queries.add(indexQuery);
            
            // 分批提交
            if (queries.size() >= BATCH_SIZE) {
                elasticsearchTemplate.bulkIndex(queries, IndexCoordinates.of("product_index"));
                queries.clear();
                log.info("已导入 {} 条数据", products.size());
            }
        }
        
        // 提交剩余数据
        if (!queries.isEmpty()) {
            elasticsearchTemplate.bulkIndex(queries, IndexCoordinates.of("product_index"));
        }
        
        // 强制刷新
        elasticsearchTemplate.indexOps(IndexCoordinates.of("product_index")).refresh();
    }
}

2.2 查询优化

使用 Filter 缓存
java 复制代码
/**
 * 优化查询:将不变的条件放在 filter 中
 */
public List<ProductDocument> optimizedSearch(String keyword, String category) {
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
        .must(QueryBuilders.matchQuery("name", keyword))  // 会计算评分
        .filter(QueryBuilders.termQuery("category", category))  // 使用缓存,不计算评分
        .filter(QueryBuilders.termQuery("status", "ACTIVE"));
    
    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(boolQuery)
        .withPageable(PageRequest.of(0, 20))
        .build();
    
    SearchHits<ProductDocument> hits = elasticsearchTemplate.search(
        query, ProductDocument.class
    );
    
    return hits.stream()
        .map(SearchHit::getContent)
        .collect(Collectors.toList());
}
分页优化:Search After
java 复制代码
/**
 * 深分页优化:使用 search_after
 */
public List<ProductDocument> deepPagination(String keyword, int pageSize, String sortValue) {
    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(QueryBuilders.matchQuery("name", keyword))
        .withSort(SortBuilders.fieldSort("id").order(SortOrder.ASC))
        .withPageable(PageRequest.of(0, pageSize))
        .build();
    
    // 如果有上一页的最后一条记录的排序值
    if (sortValue != null) {
        query.setSearchAfter(new Object[]{sortValue});
    }
    
    SearchHits<ProductDocument> hits = elasticsearchTemplate.search(
        query, ProductDocument.class
    );
    
    return hits.stream()
        .map(SearchHit::getContent)
        .collect(Collectors.toList());
}
路由优化
java 复制代码
/**
 * 使用路由提高查询效率
 */
public void saveWithRouting(ProductDocument product) {
    IndexQuery indexQuery = new IndexQueryBuilder()
        .withId(product.getId())
        .withObject(product)
        .withRouting(product.getCategoryId())  // 指定路由
        .build();
    
    elasticsearchTemplate.index(indexQuery, IndexCoordinates.of("product_index"));
}

public List<ProductDocument> searchWithRouting(String keyword, String categoryId) {
    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(QueryBuilders.matchQuery("name", keyword))
        .withRoute(categoryId)  // 只查询特定分片
        .build();
    
    SearchHits<ProductDocument> hits = elasticsearchTemplate.search(
        query, ProductDocument.class
    );
    
    return hits.stream()
        .map(SearchHit::getContent)
        .collect(Collectors.toList());
}

2.3 JVM 与系统优化

JVM 参数调优
conf 复制代码
# jvm.options
-Xms4g
-Xmx4g

# GC 配置
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSize=16m

# 禁止 Swap
-XX:+AlwaysPreTouch
系统配置
bash 复制代码
# /etc/sysctl.conf
vm.max_map_count=262144

# /etc/security/limits.conf
elasticsearch soft nofile 65536
elasticsearch hard nofile 65536
elasticsearch soft nproc 4096
elasticsearch hard nproc 4096

三、Logstash 高级处理

3.1 多管道配置

logstash/pipeline/multi-pipeline.yml:

yaml 复制代码
- pipeline.id: app-logs
  path.config: "/usr/share/logstash/pipeline/app-logs.conf"
  pipeline.workers: 4
  
- pipeline.id: error-logs
  path.config: "/usr/share/logstash/pipeline/error-logs.conf"
  pipeline.workers: 2
  
- pipeline.id: metrics
  path.config: "/usr/share/logstash/pipeline/metrics.conf"
  pipeline.workers: 2

3.2 高级过滤器

Grok 解析日志
conf 复制代码
filter {
  # 解析 Nginx 访问日志
  grok {
    match => { 
      "message" => "%{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] \"%{WORD:verb} %{DATA:request} HTTP/%{NUMBER:httpversion}\" %{NUMBER:response} %{NUMBER:bytes}" 
    }
  }
  
  # 解析日期
  date {
    match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
    target => "@timestamp"
  }
  
  # IP 地理位置
  geoip {
    source => "clientip"
    target => "geoip"
  }
  
  # 用户代理解析
  useragent {
    source => "agent"
    target => "useragent"
  }
}
条件判断
conf 复制代码
filter {
  # 根据日志级别分流
  if [level] == "ERROR" {
    mutate {
      add_tag => ["error"]
      add_field => { "alert_level" => "high" }
    }
  } else if [level] == "WARN" {
    mutate {
      add_tag => ["warning"]
      add_field => { "alert_level" => "medium" }
    }
  }
  
  # 删除调试日志
  if [level] == "DEBUG" and [environment] == "production" {
    drop {}
  }
}
Ruby 脚本处理
conf 复制代码
filter {
  ruby {
    code => "
      # 计算响应时间等级
      response_time = event.get('response_time').to_f
      
      if response_time < 100
        event.set('performance_level', 'fast')
      elsif response_time < 500
        event.set('performance_level', 'normal')
      else
        event.set('performance_level', 'slow')
      end
      
      # 添加小时字段用于聚合
      timestamp = event.get('@timestamp')
      hour = timestamp.strftime('%H')
      event.set('hour_of_day', hour)
    "
  }
}

3.3 输出优化

conf 复制代码
output {
  # 根据日志级别输出到不同索引
  if "error" in [tags] {
    elasticsearch {
      hosts => ["http://elasticsearch:9200"]
      index => "error-logs-%{+YYYY.MM.dd}"
      template_overwrite => true
    }
  } else {
    elasticsearch {
      hosts => ["http://elasticsearch:9200"]
      index => "app-logs-%{+YYYY.MM.dd}"
    }
  }
  
  # 错误日志发送到告警系统
  if [alert_level] == "high" {
    http {
      url => "http://alert-system/api/alerts"
      http_method => "post"
      format => "json"
    }
  }
}

四、Kibana 高级可视化

4.1 Lens 可视化

创建交互式仪表板:

  1. 进入 Visualize LibraryCreate visualizationLens
  2. 拖拽字段创建图表
  3. 添加多个图层
  4. 配置交互:点击下钻、联动过滤

4.2 TSVB 时间序列

监控系统性能指标:

  1. 选择 Time Series Visual Builder
  2. 配置面板:
    • Panel 1: CPU 使用率(折线图)
    • Panel 2: 内存使用率(面积图)
    • Panel 3: 磁盘 IO(柱状图)
  3. 设置阈值线和告警

4.3 Canvas 实时大屏

创建实时监控大屏:

  1. 进入 CanvasCreate workpad
  2. 添加元素:
    • 实时数据卡片
    • 动态图表
    • 地图展示
    • 滚动列表
  3. 设置自动刷新(5秒)

示例表达式:

复制代码
filters
| essql query="SELECT COUNT(*) as count FROM \"app-logs-*\" WHERE level='ERROR' AND @timestamp > NOW() - 1 HOUR"
| metric "当前错误数" font={font family="'Open Sans', Helvetica, Arial, sans-serif" size=48 align="center"}
| render

4.4 告警配置

Watcher 告警
json 复制代码
PUT _watcher/watch/error_rate_alert
{
  "trigger": {
    "schedule": {
      "interval": "5m"
    }
  },
  "input": {
    "search": {
      "request": {
        "indices": ["app-logs-*"],
        "body": {
          "query": {
            "bool": {
              "must": [
                { "term": { "level": "ERROR" } },
                { "range": { "@timestamp": { "gte": "now-5m" } } }
              ]
            }
          },
          "aggs": {
            "error_count": {
              "value_count": { "field": "_id" }
            }
          }
        }
      }
    }
  },
  "condition": {
    "compare": {
      "ctx.payload.aggregations.error_count.value": {
        "gt": 100
      }
    }
  },
  "actions": {
    "send_email": {
      "email": {
        "to": "admin@example.com",
        "subject": "错误率告警",
        "body": "过去5分钟错误数量超过阈值: {{ctx.payload.aggregations.error_count.value}}"
      }
    },
    "webhook": {
      "webhook": {
        "method": "POST",
        "url": "http://dingtalk-webhook",
        "body": "{\"msgtype\": \"text\", \"text\": {\"content\": \"错误率告警!\"}}"
      }
    }
  }
}

五、安全加固

5.1 启用 X-Pack Security

docker-compose.yml:

yaml 复制代码
services:
  elasticsearch:
    environment:
      - xpack.security.enabled=true
      - xpack.security.enrollment.enabled=true
      - ELASTIC_PASSWORD=your_password

  kibana:
    environment:
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=your_password

生成密码:

bash 复制代码
docker exec -it elasticsearch bin/elasticsearch-setup-passwords auto

5.2 角色与权限

json 复制代码
// 创建只读角色
POST /_security/role/log_reader
{
  "cluster": ["monitor"],
  "indices": [
    {
      "names": ["app-logs-*"],
      "privileges": ["read", "view_index_metadata"]
    }
  ]
}

// 创建用户并分配角色
POST /_security/user/log_user
{
  "password": "user_password",
  "roles": ["log_reader"],
  "full_name": "Log Reader"
}

5.3 SSL/TLS 加密

yaml 复制代码
# elasticsearch.yml
xpack.security.http.ssl:
  enabled: true
  keystore.path: certs/http.p12

xpack.security.transport.ssl:
  enabled: true
  verification_mode: certificate
  keystore.path: certs/transport.p12
  truststore.path: certs/transport.p12

六、数据备份与恢复

6.1 快照仓库

bash 复制代码
# 注册快照仓库
PUT _snapshot/my_backup
{
  "type": "fs",
  "settings": {
    "location": "/mnt/backups"
  }
}

# 创建快照
PUT _snapshot/my_backup/snapshot_2024_01_01?wait_for_completion=true
{
  "indices": "app-logs-*",
  "ignore_unavailable": true,
  "include_global_state": false
}

# 查看快照
GET _snapshot/my_backup/_all

# 恢复快照
POST _snapshot/my_backup/snapshot_2024_01_01/_restore
{
  "indices": "app-logs-*",
  "rename_pattern": "(.+)",
  "rename_replacement": "restored_$1"
}

6.2 自动化备份脚本

bash 复制代码
#!/bin/bash

BACKUP_DIR="/mnt/backups"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30

# 创建快照
curl -X PUT "localhost:9200/_snapshot/my_backup/snapshot_${DATE}?wait_for_completion=true" \
  -H 'Content-Type: application/json' \
  -d '{
    "indices": "app-logs-*",
    "ignore_unavailable": true,
    "include_global_state": false
  }'

# 删除过期快照
OLD_SNAPSHOTS=$(curl -s "localhost:9200/_snapshot/my_backup/_all" | jq -r ".snapshots[] | select(.start_timeInMillis < $(($(date +%s%N)/1000000 - ${RETENTION_DAYS}*86400*1000))) | .snapshot")

for snapshot in $OLD_SNAPSHOTS; do
  curl -X DELETE "localhost:9200/_snapshot/my_backup/$snapshot"
  echo "Deleted old snapshot: $snapshot"
done

七、监控与运维

7.1 Elastic Stack Monitoring

启用监控:

yaml 复制代码
# elasticsearch.yml
xpack.monitoring.enabled: true
xpack.monitoring.collection.enabled: true

# kibana.yml
monitoring.ui.enabled: true
monitoring.kibana.collection.enabled: true

访问监控页面:

复制代码
Kibana → Stack Management → Monitoring

7.2 关键指标监控

bash 复制代码
# 集群健康
GET /_cluster/health

# 节点状态
GET /_nodes/stats

# 索引状态
GET /_cat/indices?v

# 慢查询日志
PUT /_cluster/settings
{
  "persistent": {
    "index.search.slowlog.threshold.query.warn": "10s",
    "index.search.slowlog.threshold.fetch.debug": "500ms"
  }
}

7.3 Prometheus 集成

安装 elasticsearch_exporter:

bash 复制代码
docker run -d --name es-exporter \
  -p 9114:9114 \
  justwatch/elasticsearch_exporter \
  --es.uri=http://elasticsearch:9200

Prometheus 配置:

yaml 复制代码
scrape_configs:
  - job_name: 'elasticsearch'
    static_configs:
      - targets: ['localhost:9114']

八、总结与展望

8.1 本文要点回顾

高级查询 :全文检索、聚合分析、地理位置

性能优化 :索引优化、查询优化、JVM 调优

Logstash 高级 :多管道、Grok、条件判断

Kibana 高级 :Lens、TSVB、Canvas、告警

安全加固 :X-Pack Security、SSL/TLS

备份恢复:快照管理、自动化脚本

8.2 下篇预告

在下一篇文章《ELK 从入门到精通:Spring Boot 实战三部曲(三)------ 高级应用与架构设计》中,我们将探讨:

  • 🏗️ 大规模 ELK 集群架构设计
  • 🔧 Filebeat 轻量级数据采集
  • 🌐 APM 应用性能监控
  • 📊 业务数据分析实战
  • 🚀 云原生 ELK 部署
  • 💡 最佳实践与案例分享

8.3 学习建议

  1. 持续优化:定期审查性能和资源使用
  2. 安全第一:生产环境必须启用安全认证
  3. 备份策略:制定完善的备份和恢复计划
  4. 监控告警:及时发现问题,避免故障扩大

📚 参考资料


觉得有用?欢迎点赞、收藏、转发!

下一篇更精彩,敬请期待! 🚀

系列文章:

  • 第一篇 ELK 从入门到精通:Spring Boot 实战三部曲(一)------ 基础核心与快速上手
  • 第二篇 ELK 从入门到精通:Spring Boot 实战三部曲(二)------ 进阶特性与性能优化
  • 第三篇 ELK 从入门到精通:Spring Boot 实战三部曲(三)------ 高级应用与架构设计
相关推荐
绝知此事1 小时前
ELK 从入门到精通:Spring Boot 实战三部曲(一)—— 基础核心与快速上手
spring boot·后端·elk
MaCa .BaKa1 小时前
56-非遗手工艺品定制平台系统
java·vue.js·spring boot·mysql·maven·非遗手工制作平台系统·非遗制作
憧憬成为java架构高手的小白12 小时前
苍穹外卖--day09
java·spring boot·百度
Jasonakeke13 小时前
SpringBoot自动配置原理揭秘
java·spring boot·后端
Ramble_Naylor14 小时前
东方通(TongWeb)SpringBoot开发指导
java·spring boot
JacksonMx15 小时前
@Transactional 最佳实践
java·spring boot·spring·性能优化
智研数智工坊17 小时前
SpringBoot4.0.6 + Security7.x + JWT 最新完整实战|无状态权限认证、统一异常处理、可直接落地
java·spring boot·spring security·jwt·权限认证
一 乐18 小时前
汽车租赁|基于SprinBoot+vue的汽车租赁管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·汽车·论文·毕设·汽车租赁管理系统
夕除18 小时前
实战--2
java·spring boot·spring