diff --git a/api/blog.py b/api/blog.py index 12449ff..09aaf0e 100644 --- a/api/blog.py +++ b/api/blog.py @@ -6,9 +6,10 @@ from sqlalchemy.orm import Session from config.auth import verify_token from schemas.blog import BlogResponse, BlogQuery, BlogCategoryResponse, BlogStatsResponse, \ BlogLatestResponse, BlogCommentCreate, BlogCommentResponse, BlogVisitResponse, BlogCreate, BlogUpdate +from schemas.blog_elastic import BlogSearch from schemas.pagination import PageResult from config.database import get_db -from service import blog_service +from service import blog_service, blog_elastic_service router = APIRouter( prefix="/blog", @@ -17,6 +18,16 @@ router = APIRouter( ) +@router.get("/sync", summary="同步博客到elastic", response_model=bool) +def sync_all_blog(db: Session = Depends(get_db)): + return blog_elastic_service.sync_all_blog(db) + + +@router.get("/search", summary="搜索elastic", response_model=List[BlogSearch]) +def search_blog(keyword: str): + return blog_elastic_service.search_blog(keyword) + + @router.get("/page", summary="分页查询博客", response_model=PageResult[BlogResponse]) def query_blog_by_page(current_page: int = Query(1, ge=1, alias="currentPage", description="当前页码"), page_size: int = Query(10, ge=1, le=100, alias="pageSize", description="每页数量"), @@ -36,17 +47,17 @@ def query_blog_by_id(blog_id: int, db: Session = Depends(get_db)): @router.post("", summary="新增博客内容", response_model=bool) -def add_blog(blog: BlogCreate, db: Session = Depends(get_db), _ = Depends(verify_token)): +def add_blog(blog: BlogCreate, db: Session = Depends(get_db), _=Depends(verify_token)): return blog_service.add_blog(db, blog) @router.put("/{blog_id}", summary="更新博客内容", response_model=bool) -def update_blog(blog_id: int, blog: BlogUpdate, db: Session = Depends(get_db), _ = Depends(verify_token)): +def update_blog(blog_id: int, blog: BlogUpdate, db: Session = Depends(get_db), _=Depends(verify_token)): return blog_service.update_blog(db, blog_id, blog) @router.delete("/{blog_id}", summary="删除博客内容", response_model=bool) -def delete_blog(blog_id: int, db: Session = Depends(get_db), _ = Depends(verify_token)): +def delete_blog(blog_id: int, db: Session = Depends(get_db), _=Depends(verify_token)): return blog_service.delete_blog(db, blog_id) diff --git a/requirements.txt b/requirements.txt index 769fb15..117d969 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -fastapi~=0.115.12 sqlalchemy~=2.0.41 pydantic~=2.11.4 PyJWT~=2.10.1 passlib~=1.7.4 loguru~=0.7.3 pydantic-settings~=2.9.1 pymysql~=1.1.1 python-multipart~=0.0.20 uvicorn~=0.23.0 elasticsearch~=8.12.0 # pip download -r requirements.txt -d ./packages --only-binary=:all: --platform manylinux2014_x86_64 -i https://pypi.tuna.tsinghua.edu.cn/simple \ No newline at end of file +fastapi~=0.115.12 sqlalchemy~=2.0.41 pydantic~=2.11.4 PyJWT~=2.10.1 passlib~=1.7.4 loguru~=0.7.3 pydantic-settings~=2.9.1 pymysql~=1.1.1 python-multipart~=0.0.20 uvicorn~=0.23.0 elasticsearch~=8.12.0 # pip download -r requirements.txt -d ./packages --only-binary=:all: --platform manylinux2014_x86_64 -i https://pypi.tuna.tsinghua.edu.cn/simple \ No newline at end of file diff --git a/schemas/blog_elastic.py b/schemas/blog_elastic.py index e769533..981b12a 100644 --- a/schemas/blog_elastic.py +++ b/schemas/blog_elastic.py @@ -12,6 +12,19 @@ class BlogElastic(BaseModel): createTime: Optional[Union[datetime, str]] = None updateTime: Optional[Union[datetime, str]] = None + class Config: + from_attributes = True + + +class BlogSearch(BaseModel): + id: int + title: str + content: str + highlight: str + + class Config: + from_attributes = True + BLOG_MAPPING = { "mappings": { diff --git a/service/blog_elastic_service.py b/service/blog_elastic_service.py index 8ed2237..7c51fd6 100644 --- a/service/blog_elastic_service.py +++ b/service/blog_elastic_service.py @@ -1,7 +1,56 @@ from datetime import datetime +from typing import List + +from config.logging import logger + +from elasticsearch.helpers import bulk +from sqlalchemy import select +from sqlalchemy.orm import Session from config.elastic import es, BLOG_INDEX -from schemas.blog_elastic import BlogElastic +from models.blog import Blog, BlogCategory, BlogContent +from schemas.blog_elastic import BlogElastic, BlogSearch + + +def sync_all_blog(db: Session) -> bool: + query = select( + Blog.id, + Blog.title, + BlogCategory.name.label("category"), + BlogContent.content.label("content"), + Blog.create_time.label("createTime"), + Blog.update_time.label("updateTime"), + ).select_from(Blog).outerjoin( + BlogCategory, Blog.category_id == BlogCategory.id + ).outerjoin( + BlogContent, Blog.content_id == BlogContent.id + ) + results = db.execute(query).fetchall() + + actions = [ + { + "_op_type": "index", # 如果存在则更新,不存在则创建 + "_index": BLOG_INDEX, + "_id": blog.id, + "_source": { + "title": blog.title, + "category": blog.category, + "content": blog.content.decode("utf-8"), + "createTime": blog.createTime.strftime("%Y-%m-%d %H:%M:%S"), + "updateTime": blog.updateTime.strftime("%Y-%m-%d %H:%M:%S") + } + } + for blog in results + ] + + success_count, errors = bulk(es, actions=actions) + + if errors: + logger.error(f"部分文档同步失败,成功同步 {success_count} 条") + return False + + logger.info(f"成功同步 {success_count} 条博客到 Elasticsearch") + return True def add_blog_elastic(blog: BlogElastic) -> bool: @@ -35,3 +84,55 @@ def delete_blog(blog_id: int) -> bool: es.delete(index=BLOG_INDEX, id=blog_id) return True + + +def search_blog(keyword: str) -> List[BlogSearch]: + # 构造查询请求 + body = { + "query": { + "multi_match": { + "query": keyword, + "fields": ["title^3", "content"], + "type": "phrase" + } + }, + "highlight": { + "pre_tags": [""], + "post_tags": [""], + "fields": { + "title": {}, + "content": { + "fragment_size": 150, + "number_of_fragments": 2, + "no_match_size": 100 + } + } + }, + "_source": ["title", "content"] + } + + response = es.search(index=BLOG_INDEX, body=body) + + results = [] + for hit in response["hits"]["hits"]: + highlight = hit.get("highlight", {}) + + # 合并所有高亮片段(标题+内容) + all_highlights = [] + if "title" in highlight: + all_highlights.extend(highlight["title"]) + if "content" in highlight: + all_highlights.extend(highlight["content"]) + + # 优先使用高亮内容,否则截取内容开头 + displayed_content = " ".join(all_highlights) if all_highlights \ + else hit["_source"].get("content", "")[:200] + "..." + + results.append(BlogSearch( + id=hit["_id"], + title=hit["_source"]["title"], + content=displayed_content, + highlight=" | ".join(all_highlights) # 合并所有高亮片段 + )) + + return results diff --git a/sys.stdout b/sys.stdout index f2c7343..e281689 100644 --- a/sys.stdout +++ b/sys.stdout @@ -858,3 +858,253 @@ category 2025-09-25 00:06:40.224 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: POST http://127.0.0.1:8082/blog 2025-09-25 00:07:13.887 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: POST http://127.0.0.1:8082/blog 2025-09-25 00:07:15.655 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: POST http://127.0.0.1:8082/blog +2025-09-25 11:44:15.070 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/ +2025-09-25 11:44:15.071 | WARNING  | middleware.exceptions:global_exception_handler:26 - 响应: 404 +2025-09-25 11:44:15.173 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/favicon.ico +2025-09-25 11:44:15.174 | WARNING  | middleware.exceptions:global_exception_handler:26 - 响应: 404 +2025-09-25 11:44:20.341 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/docs +2025-09-25 11:44:21.109 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/openapi.json +2025-09-25 11:44:24.250 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 11:44:24.410 | CRITICAL | middleware.exceptions:global_exception_handler:44 - 未知异常: 1 validation error for BlogElastic + Input should be a valid dictionary or instance of BlogElastic [type=model_type, input_value=(591259203186757, 'MyBati...xe3\x80\x82\n\n'), input_type=Row] + For further information visit https://errors.pydantic.dev/2.11/v/model_type +2025-09-25 11:45:40.490 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 11:45:40.555 | CRITICAL | middleware.exceptions:global_exception_handler:44 - 未知异常: You must set the config attribute `from_attributes=True` to use from_orm +2025-09-25 11:46:36.849 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 11:46:36.917 | CRITICAL | middleware.exceptions:global_exception_handler:44 - 未知异常: list.count() takes exactly one argument (0 given) +2025-09-25 11:47:47.735 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 13:02:12.322 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 13:07:05.987 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 13:09:49.942 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 13:11:29.949 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 13:12:05.262 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 13:20:22.224 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 13:20:22.403 | INFO  | service.blog_elastic_service:sync_all_blog:50 - 成功同步 13 条博客到 Elasticsearch +2025-09-25 13:21:18.623 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/sync +2025-09-25 13:21:18.753 | INFO  | service.blog_elastic_service:sync_all_blog:50 - 成功同步 13 条博客到 Elasticsearch +2025-09-25 13:26:43.033 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/docs +2025-09-25 13:26:43.260 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/openapi.json +2025-09-25 13:26:51.271 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:26:51.272 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:27:28.435 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:27:28.436 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:28:02.588 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:28:02.589 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:28:26.051 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:28:26.051 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:29:14.437 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:29:14.438 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:30:29.031 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:30:29.031 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:34:01.586 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:34:01.587 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:34:20.735 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:34:20.735 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:38:11.466 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:38:11.466 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:38:15.478 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/docs +2025-09-25 13:38:15.663 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/openapi.json +2025-09-25 13:38:20.698 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:38:20.699 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:40:27.142 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 13:40:27.142 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 13:43:19.045 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=Spring +2025-09-25 13:43:19.045 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': 'Spring'} +2025-09-25 13:47:02.900 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 13:47:02.946 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/page?currentPage=1&pageSize=10 +2025-09-25 13:47:02.946 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'currentPage': '1', 'pageSize': '10'} +2025-09-25 13:47:03.063 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 13:48:14.267 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 13:48:14.271 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/page?currentPage=1&pageSize=10 +2025-09-25 13:48:14.272 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'currentPage': '1', 'pageSize': '10'} +2025-09-25 13:48:14.291 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 13:51:19.419 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 13:51:19.420 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 13:51:21.402 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/category +2025-09-25 13:55:21.251 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 13:55:21.252 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/category +2025-09-25 13:55:21.285 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 13:55:22.087 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 13:55:22.087 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 13:56:07.890 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 13:56:07.891 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 13:56:07.891 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 13:56:07.916 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 13:56:10.251 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 13:56:10.252 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 13:56:10.252 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 13:56:10.276 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 13:57:22.388 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 13:57:22.389 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 13:57:22.390 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 13:57:22.428 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 13:57:23.517 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 13:57:23.519 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 13:57:23.519 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 13:57:23.553 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:06:40.887 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:06:40.923 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:06:42.166 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:06:42.194 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:06:47.716 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:06:47.762 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:07:28.984 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:07:29.031 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:27:09.163 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:27:09.192 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:27:26.494 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 14:27:26.494 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 14:29:40.269 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:29:40.286 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:30:40.527 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:30:40.556 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:30:40.637 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:30:40.652 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:31:44.236 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:31:44.249 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:34:54.316 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:34:54.333 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:34:58.160 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:34:58.198 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:35:07.966 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=dd +2025-09-25 14:35:07.967 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': 'dd'} +2025-09-25 14:35:22.188 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 14:35:22.188 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 14:35:40.918 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:35:40.956 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:35:48.222 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 14:35:48.222 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 14:38:13.931 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:38:13.970 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:39:00.228 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:39:00.242 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:39:06.442 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:39:06.491 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:39:16.760 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:39:16.861 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:39:19.369 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:39:19.370 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:39:26.761 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:39:26.822 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:41:32.350 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E5%8D%95%E7%8B%AC +2025-09-25 14:41:32.350 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '单独'} +2025-09-25 14:41:35.148 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E5%8D%95 +2025-09-25 14:41:35.148 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '单'} +2025-09-25 14:41:35.643 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=1 +2025-09-25 14:41:35.644 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '1'} +2025-09-25 14:41:47.057 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:41:47.111 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:41:48.341 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E9%97%AE%E9%97%AE +2025-09-25 14:41:48.341 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '问问'} +2025-09-25 14:41:49.268 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E9%97%AE +2025-09-25 14:41:49.269 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '问'} +2025-09-25 14:41:49.447 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword= +2025-09-25 14:41:49.447 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': ''} +2025-09-25 14:41:49.875 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%88%91 +2025-09-25 14:41:49.876 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '我'} +2025-09-25 14:41:51.018 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword= +2025-09-25 14:41:51.018 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': ''} +2025-09-25 14:41:52.360 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 14:41:52.360 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 14:41:53.388 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86 +2025-09-25 14:41:53.389 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框'} +2025-09-25 14:41:54.484 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword= +2025-09-25 14:41:54.484 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': ''} +2025-09-25 14:42:07.744 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 14:42:07.744 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 14:42:09.517 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword= +2025-09-25 14:42:09.518 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': ''} +2025-09-25 14:42:22.609 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E7%9A%84 +2025-09-25 14:42:22.609 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '的'} +2025-09-25 14:45:38.620 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%88%91 +2025-09-25 14:45:38.620 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '我'} +2025-09-25 14:45:40.520 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E4%BD%A0 +2025-09-25 14:45:40.520 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '你'} +2025-09-25 14:46:17.291 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:46:17.292 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:46:26.237 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:46:26.256 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:46:29.766 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:46:29.766 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:46:33.114 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:46:33.135 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:46:34.508 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:46:34.508 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:46:57.691 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:46:57.737 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:46:58.594 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:46:58.595 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:47:04.608 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:47:04.627 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:47:06.837 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:47:06.896 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:47:08.113 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:47:08.113 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:48:59.162 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:48:59.223 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:49:00.880 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:49:00.880 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:51:02.407 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:51:02.433 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:51:03.966 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:51:03.966 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:53:00.197 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:53:00.251 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:53:01.530 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:53:01.530 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:54:26.078 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:54:26.186 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:54:30.854 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:54:30.854 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:54:42.278 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:54:42.306 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:54:43.851 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%98%AF +2025-09-25 14:54:43.851 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '是'} +2025-09-25 14:56:17.101 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 14:56:17.102 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 14:56:22.995 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/content/:591259203186757 +2025-09-25 14:56:22.997 | WARNING  | middleware.exceptions:global_exception_handler:26 - 响应: 422 +2025-09-25 14:56:30.426 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/page?currentPage=1&pageSize=10 +2025-09-25 14:56:30.426 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'currentPage': '1', 'pageSize': '10'} +2025-09-25 14:56:54.085 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:56:54.159 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:56:56.193 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 14:56:56.193 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 14:57:03.178 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:57:03.194 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:57:04.483 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/page?currentPage=1&pageSize=10 +2025-09-25 14:57:04.483 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'currentPage': '1', 'pageSize': '10'} +2025-09-25 14:57:07.503 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/content/631305371107398 +2025-09-25 14:57:07.541 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/comment/631305371107398 +2025-09-25 14:57:29.779 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:57:29.780 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/page?currentPage=1&pageSize=10 +2025-09-25 14:57:29.780 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'currentPage': '1', 'pageSize': '10'} +2025-09-25 14:57:29.801 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:57:31.697 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/content/631305371107398 +2025-09-25 14:57:31.716 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/comment/631305371107398 +2025-09-25 14:57:39.093 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E6%A1%86%E6%9E%B6 +2025-09-25 14:57:39.093 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '框架'} +2025-09-25 14:57:40.678 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/content/676185644712005 +2025-09-25 14:57:40.693 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/comment/676185644712005 +2025-09-25 14:58:06.963 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E4%BD%A0 +2025-09-25 14:58:06.963 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '你'} +2025-09-25 14:59:27.179 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:59:27.241 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:59:31.417 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 14:59:31.418 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 14:59:34.828 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E4%BD%A0%E5%A5%BD +2025-09-25 14:59:34.829 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '你好'} +2025-09-25 14:59:35.815 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E4%BD%A0 +2025-09-25 14:59:35.815 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '你'} +2025-09-25 14:59:37.358 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 14:59:37.359 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 14:59:49.964 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/stats +2025-09-25 14:59:50.045 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/latest +2025-09-25 14:59:50.680 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 14:59:50.680 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 14:59:52.852 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/search?keyword=%E4%BD%A0 +2025-09-25 14:59:52.853 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'keyword': '你'} +2025-09-25 14:59:54.375 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/condition?year=2025 +2025-09-25 14:59:54.375 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'year': '2025'} +2025-09-25 15:00:09.535 | INFO  | middleware.exceptions:global_exception_handler:18 - 请求: GET http://127.0.0.1:8082/blog/page?currentPage=1&pageSize=10 +2025-09-25 15:00:09.536 | INFO  | middleware.exceptions:global_exception_handler:20 - 查询参数: {'currentPage': '1', 'pageSize': '10'}