From 132fbb13b79e44db2138d475af8ed1af2c8110f5 Mon Sep 17 00:00:00 2001 From: Cxx0822 <1556464090@qq.com> Date: Sun, 12 Oct 2025 22:56:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=8D=9A=E5=AE=A2=E7=9B=B8=E9=82=BB=E8=AE=B0=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/blog.py | 8 ++- config/database.py | 2 +- config/elastic.py | 5 +- config/logging.py | 2 +- config/setting.py | 10 ++-- schemas/blog.py | 8 +++ service/blog_elastic_service.py | 16 ++++++ service/blog_service.py | 95 +++++++++++++++++++++++---------- 8 files changed, 106 insertions(+), 40 deletions(-) diff --git a/api/blog.py b/api/blog.py index a881f9c..2d32ca8 100644 --- a/api/blog.py +++ b/api/blog.py @@ -5,7 +5,8 @@ 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 + BlogLatestResponse, BlogCommentCreate, BlogCommentResponse, BlogVisitResponse, BlogCreate, BlogUpdate, \ + BlogAdjacentResponse from schemas.blog_elastic import BlogSearch from schemas.pagination import PageResult from config.database import get_db @@ -61,6 +62,11 @@ def delete_blog(blog_id: int, db: Session = Depends(get_db), _=Depends(verify_to return blog_service.delete_blog(db, blog_id) +@router.get("/{blog_id}/adjacent", summary="查询相邻博客", response_model=List[BlogAdjacentResponse]) +def query_blog_latest(blog_id: int, db: Session = Depends(get_db)): + return blog_service.query_blog_adjacent(db, blog_id) + + @router.put("/{blog_id}/comment", summary="新增博客评论", response_model=bool) def add_blog_comment(blog_id: int, blog_comment: BlogCommentCreate, request: Request, db: Session = Depends(get_db)): return blog_service.add_blog_comment(db, request, blog_id, blog_comment) diff --git a/config/database.py b/config/database.py index d7c8a97..6749642 100644 --- a/config/database.py +++ b/config/database.py @@ -4,7 +4,7 @@ from sqlalchemy.orm import sessionmaker from config.setting import settings -DATABASE_URL = f"mysql+pymysql://{settings.DB_USER}:{settings.DB_PASSWORD}@{settings.DB_HOST}:{settings.DB_PORT}/{settings.DB_NAME}" +DATABASE_URL = f"mysql+pymysql://root:{settings.DB_PASSWORD}@{settings.DB_HOST}:3306/blog" engine = create_engine(url=DATABASE_URL, pool_pre_ping=True, pool_recycle=3600) diff --git a/config/elastic.py b/config/elastic.py index 3aa4fad..bf589e9 100644 --- a/config/elastic.py +++ b/config/elastic.py @@ -1,15 +1,16 @@ from elasticsearch import Elasticsearch +from config.setting import settings from schemas.blog_elastic import BLOG_MAPPING from config.logging import logger -ES_HOSTS = "http://host.docker.internal:9200" +ES_HOST = f"http://{settings.ES_HOST}:9200" ES_USER = "elastic" ES_PASSWORD = "19940822Cxx" BLOG_INDEX = "blog" # 注意Python的elasticsearch的版本要和服务器的一致 -es = Elasticsearch(ES_HOSTS, http_auth=(ES_USER, ES_PASSWORD)) +es = Elasticsearch(ES_HOST, http_auth=(ES_USER, ES_PASSWORD)) if not es.indices.exists(index=BLOG_INDEX): es.indices.create(index=BLOG_INDEX, body=BLOG_MAPPING) diff --git a/config/logging.py b/config/logging.py index d3c9193..2c6a00a 100644 --- a/config/logging.py +++ b/config/logging.py @@ -82,7 +82,7 @@ logger.add( logger.add( log_to_fluent, - level="INFO", # 处理 INFO 及以上级别 + level=LOG_LEVEL, # 处理 INFO 及以上级别 format="{message}", # 原始消息(实际使用结构化数据) backtrace=True, # 启用堆栈回溯 diagnose=True # 显示诊断信息 diff --git a/config/setting.py b/config/setting.py index 6f53870..c013a85 100644 --- a/config/setting.py +++ b/config/setting.py @@ -2,13 +2,11 @@ from pydantic_settings import BaseSettings class Settings(BaseSettings): - DB_HOST: str - DB_PORT: int - DB_USER: str - DB_PASSWORD: str - DB_NAME: str - + ENVIRONMENT: str LOG_LEVEL: str + DB_HOST: str + DB_PASSWORD: str + ES_HOST: str class Config: env_file = ".env" # 指定.env文件路径 diff --git a/schemas/blog.py b/schemas/blog.py index d3eac68..817748e 100644 --- a/schemas/blog.py +++ b/schemas/blog.py @@ -83,6 +83,14 @@ class BlogLatestResponse(BaseModel): from_attributes = True +class BlogAdjacentResponse(BaseModel): + id: int + title: str + + class Config: + from_attributes = True + + class BlogCommentCreate(BaseModel): parentId: int name: str diff --git a/service/blog_elastic_service.py b/service/blog_elastic_service.py index 7c51fd6..3858c25 100644 --- a/service/blog_elastic_service.py +++ b/service/blog_elastic_service.py @@ -8,11 +8,15 @@ from sqlalchemy import select from sqlalchemy.orm import Session from config.elastic import es, BLOG_INDEX +from config.setting import settings from models.blog import Blog, BlogCategory, BlogContent from schemas.blog_elastic import BlogElastic, BlogSearch def sync_all_blog(db: Session) -> bool: + if settings.ENVIRONMENT == 'dev': + return True + query = select( Blog.id, Blog.title, @@ -54,6 +58,9 @@ def sync_all_blog(db: Session) -> bool: def add_blog_elastic(blog: BlogElastic) -> bool: + if settings.ENVIRONMENT == 'dev': + return True + now = datetime.now() blog.createTime = now.strftime("%Y-%m-%d %H:%M:%S") blog.updateTime = now.strftime("%Y-%m-%d %H:%M:%S") @@ -64,10 +71,14 @@ def add_blog_elastic(blog: BlogElastic) -> bool: body=blog.model_dump() ) + logger.info(f"成功新增博客 {blog.id} 到 Elasticsearch") return True def update_blog_elastic(blog: BlogElastic) -> bool: + if settings.ENVIRONMENT == 'dev': + return True + now = datetime.now() blog.updateTime = now.strftime("%Y-%m-%d %H:%M:%S") @@ -77,12 +88,17 @@ def update_blog_elastic(blog: BlogElastic) -> bool: body=blog.model_dump() ) + logger.info(f"成功修改博客 {blog.id} 到 Elasticsearch") return True def delete_blog(blog_id: int) -> bool: + if settings.ENVIRONMENT == 'dev': + return True + es.delete(index=BLOG_INDEX, id=blog_id) + logger.info(f"成功删除博客 {blog_id} 到 Elasticsearch") return True diff --git a/service/blog_service.py b/service/blog_service.py index b5b7eaa..596c438 100644 --- a/service/blog_service.py +++ b/service/blog_service.py @@ -1,12 +1,13 @@ from typing import List from fastapi import Request -from sqlalchemy import select, func, desc, and_ +from sqlalchemy import select, func, desc, and_, asc, delete from sqlalchemy.orm import Session from models.blog import Blog, BlogCategory, BlogVisit, BlogContent, BlogComment from schemas.blog import BlogResponse, BlogQuery, BlogCategoryResponse, BlogStatsResponse, \ - BlogLatestResponse, BlogCommentCreate, BlogCommentResponse, BlogVisitResponse, BlogCreate, BlogUpdate + BlogLatestResponse, BlogCommentCreate, BlogCommentResponse, BlogVisitResponse, BlogCreate, BlogUpdate, \ + BlogAdjacentResponse from schemas.blog_elastic import BlogElastic from schemas.pagination import PageResult from schemas.paginate_query import paginate_query @@ -82,6 +83,8 @@ def query_blog_by_condition(db: Session, blog_query: BlogQuery) -> List[BlogResp def query_blog_by_id(db: Session, blog_id: int) -> BlogResponse: + check_blog_exist(db, blog_id) + query = db.query( Blog.id.label("id"), Blog.title.label("title"), @@ -104,8 +107,6 @@ def query_blog_by_id(db: Session, blog_id: int) -> BlogResponse: ).filter(Blog.id == blog_id) blog = query.first() - if blog[0] is None: - raise AppException("博客不存在") return BlogResponse.from_orm(blog) @@ -140,7 +141,8 @@ def add_blog(db: Session, blog: BlogCreate) -> bool: def add_blog_category(db: Session, category: str) -> int: - db_blog_category = db.query(BlogCategory).filter(BlogCategory.name == category).first() + db_blog_category = db.execute(select(BlogCategory).where(BlogCategory.name == category)).scalar_one_or_none() + if db_blog_category is None: db_new_blog_category = BlogCategory(name=category) db.add(db_new_blog_category) @@ -161,9 +163,7 @@ def add_blog_content(db: Session, content: str) -> int: def update_blog(db: Session, blog_id: int, blog: BlogUpdate) -> bool: - db_blog = db.query(Blog).filter(Blog.id == blog_id).first() - if not db_blog: - raise AppException("博客不存在") + db_blog = check_blog_exist(db, blog_id) update_data = blog.model_dump(exclude_unset=True) @@ -186,7 +186,7 @@ def update_blog(db: Session, blog_id: int, blog: BlogUpdate) -> bool: def update_blog_category(db: Session, category: str) -> int: - db_blog_category = db.query(BlogCategory).filter(BlogCategory.name == category).first() + db_blog_category = db.execute(select(BlogCategory).where(BlogCategory.name == category)).scalar_one_or_none() if db_blog_category is None: return add_blog_category(db, category) @@ -195,12 +195,9 @@ def update_blog_category(db: Session, category: str) -> int: def update_blog_content(db: Session, blog_content_id: int, blog_content: str) -> bool: - db_blog_content = db.query(BlogContent).filter(BlogContent.id == blog_content_id).first() - if not db_blog_content: - raise AppException("博客内容不存在") + db_blog_content = check_blog_content_exist(db, blog_content_id) db_blog_content.content = blog_content.encode('utf-8') - db.commit() db.refresh(db_blog_content) @@ -208,24 +205,19 @@ def update_blog_content(db: Session, blog_content_id: int, blog_content: str) -> def delete_blog(db: Session, blog_id: int) -> bool: - db_blog = db.query(Blog).filter(Blog.id == blog_id).first() - if not db_blog: - raise AppException("博客不存在") + db_blog = check_blog_exist(db, blog_id) delete_blog_content(db, db_blog.content_id) - - db.delete(db_blog) + db.execute(delete(Blog).where(Blog.id == blog_id)) db.commit() return True def delete_blog_content(db: Session, blog_content_id: int) -> bool: - db_blog_content = db.query(BlogContent).filter(BlogContent.id == blog_content_id).first() - if not db_blog_content: - raise AppException("博客内容不存在") + check_blog_content_exist(db, blog_content_id) - db.delete(db_blog_content) + db.execute(delete(BlogContent).where(BlogContent.id == blog_content_id)) db.commit() return True @@ -265,6 +257,35 @@ def query_blog_latest(db: Session) -> List[BlogLatestResponse]: return [BlogLatestResponse.from_orm(result) for result in results] +def query_blog_adjacent(db: Session, blog_id: int) -> List[BlogAdjacentResponse]: + check_blog_exist(db, blog_id) + + prev_result = db.execute( + select(Blog.id, Blog.title) + .where(Blog.id < blog_id) + .order_by(desc(Blog.id)) + .limit(1) + ).first() + + next_result = db.execute( + select(Blog.id, Blog.title) + .where(Blog.id > blog_id) + .order_by(asc(Blog.id)) + .limit(1) + ).first() + + return [ + BlogAdjacentResponse( + id=prev_result[0] if prev_result else 0, + title=prev_result[1] if prev_result else "" + ), + BlogAdjacentResponse( + id=next_result[0] if next_result else 0, + title=next_result[1] if next_result else "" + ) + ] + + def add_blog_visit(db: Session, blog_visit: BlogVisit): db.add(blog_visit) db.commit() @@ -305,15 +326,14 @@ def query_blog_comment(db: Session, blog_id: int) -> List[BlogCommentResponse]: def add_blog_comment(db: Session, request: Request, blog_id: int, blog_comment: BlogCommentCreate) -> bool: - blog = db.query(Blog).filter(Blog.id == blog_id).first() - if not blog: - raise AppException("博客不存在") + check_blog_exist(db, blog_id) if blog_comment.parentId != 0: - parent_comment = db.query(BlogComment).filter( - BlogComment.id == blog_comment.parentId, - BlogComment.blog_id == blog_id - ).first() + parent_comment = db.execute( + select(BlogComment) + .where(BlogComment.id == blog_comment.parentId) + .where(BlogComment.blog_id == blog_id) + ).scalar_one_or_none() if not parent_comment: raise AppException("父评论不存在") @@ -334,3 +354,20 @@ def add_blog_comment(db: Session, request: Request, blog_id: int, blog_comment: db.refresh(db_comment) return True + + +def check_blog_exist(db: Session, blog_id: int) -> Blog: + result = db.execute(select(Blog).where(Blog.id == blog_id)).scalar_one_or_none() + + if not result: + raise AppException("博客不存在") + + return result + + +def check_blog_content_exist(db: Session, blog_content_id: int) -> BlogContent: + result = db.execute(select(BlogContent).where(BlogContent.id == blog_content_id)).scalar_one_or_none() + if not result: + raise AppException("博客内容不存在") + + return result