首次提交

This commit is contained in:
sansenhoshi 2026-01-08 10:25:45 +08:00
commit 5c30dd725f
13 changed files with 190 additions and 0 deletions

36
app.py Normal file
View File

@ -0,0 +1,36 @@
from flask import Flask
from config import Config
from extensions import cors, db, jwt
from blueprints.user import user_bp
from blueprints.auth import auth_bp
from common.exceptions import BusinessException
from common.response import error
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
cors.init_app(app)
db.init_app(app)
jwt.init_app(app)
app.register_blueprint(user_bp)
app.register_blueprint(auth_bp)
@app.errorhandler(BusinessException)
def handle_business_exception(e):
return error(e.code, e.message)
@app.errorhandler(Exception)
def handle_exception(e):
return error(50000, "Internal Server Error")
with app.app_context():
db.create_all()
return app
app = create_app()
if __name__ == "__main__":
app.run(port=5000)

14
blueprints/auth.py Normal file
View File

@ -0,0 +1,14 @@
from flask import Blueprint, request
from common.response import success
from services.auth_service import AuthService
auth_bp = Blueprint("auth", __name__, url_prefix="/api/auth")
@auth_bp.post("/login")
def login():
body = request.get_json()
username = body.get("username")
password = body.get("password")
data = AuthService.login(username, password)
return success(data)

18
blueprints/user.py Normal file
View File

@ -0,0 +1,18 @@
from flask import Blueprint
from flask_jwt_extended import jwt_required, get_jwt_identity
from common.response import success
from services.user_service import UserService
user_bp = Blueprint("user", __name__, url_prefix="/api/users")
@user_bp.get("")
@jwt_required()
def list_users():
data = UserService.list_users()
return success(data)
@user_bp.get("/me")
@jwt_required()
def me():
user_id = get_jwt_identity()
return success({"user_id": user_id})

4
common/exceptions.py Normal file
View File

@ -0,0 +1,4 @@
class BusinessException(Exception):
def __init__(self, code, message):
self.code = code
self.message = message

15
common/response.py Normal file
View File

@ -0,0 +1,15 @@
from flask import jsonify
def success(data=None, message="success"):
return jsonify({
"code": 0,
"message": message,
"data": data
})
def error(code=50000, message="error"):
return jsonify({
"code": code,
"message": message,
"data": None
})

15
config.py Normal file
View File

@ -0,0 +1,15 @@
class Config:
DEBUG = True
DATABASE_USER = "postgres"
DATABASE_PASSWORD = "root"
DATABASE_HOST = "localhost"
DATABASE_PORT = "5432"
DATABASE_NAME = "postgres"
SQLALCHEMY_DATABASE_URI = (
f"postgresql+psycopg2://{DATABASE_USER}:{DATABASE_PASSWORD}@{DATABASE_HOST}:{DATABASE_PORT}/{DATABASE_NAME}"
)
SQLALCHEMY_TRACK_MODIFICATIONS = False
JWT_SECRET_KEY = "114514"

7
extensions.py Normal file
View File

@ -0,0 +1,7 @@
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
from flask_jwt_extended import JWTManager
cors = CORS()
db = SQLAlchemy()
jwt = JWTManager()

BIN
instance/app.db Normal file

Binary file not shown.

28
models/user.py Normal file
View File

@ -0,0 +1,28 @@
from extensions import db # 从扩展模块导入初始化好的 SQLAlchemy 数据库实例
# 定义 User 类,继承自 db.Model使其成为一个数据库模型类对应数据库的一张表
class User(db.Model):
# 【表配置】显式指定在数据库中生成的表名为 "users"
__tablename__ = "users"
# 【字段定义】
# id字段名db.Integer整数类型primary_key=True设为主键通常会自动自增
id = db.Column(db.Integer, primary_key=True)
# username用户名db.String(64)最大长度64的字符串
# unique=True值必须唯一不可重复nullable=False不允许为空必填项
username = db.Column(db.String(64), unique=True, nullable=False)
# password密码db.String(128)最大长度128通常存加密后的哈希串
# nullable=False不允许为空
password = db.Column(db.String(128), nullable=False)
# 【实例方法:序列化】
# 将数据库对象转换为 Python 字典,方便在 Web 开发中返回 JSON 数据给前端
def to_dict(self):
return {
"id": self.id,
"username": self.username
# 注意:出于安全考虑,通常不会在 to_dict 中返回 password 字段
}

19
repositories/user_repo.py Normal file
View File

@ -0,0 +1,19 @@
from models.user import User
from extensions import db
class UserRepository:
@staticmethod
def find_by_username(username: str):
return User.query.filter_by(username=username).first()
@staticmethod
def find_by_id(user_id: int):
return User.query.get(user_id)
@staticmethod
def create(username: str, password: str):
user = User(username=username, password=password)
db.session.add(user)
db.session.commit()
return user

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
Flask==3.0.0
Flask-CORS==4.0.0
Flask-SQLAlchemy==3.1.1
Flask-JWT-Extended==4.6.0

22
services/auth_service.py Normal file
View File

@ -0,0 +1,22 @@
from repositories.user_repo import UserRepository
from common.exceptions import BusinessException
from flask_jwt_extended import create_access_token
class AuthService:
@staticmethod
def login(username: str, password: str):
user = UserRepository.find_by_username(username)
if not user:
raise BusinessException(40101, "User not found")
if user.password != password:
raise BusinessException(40102, "Invalid credentials")
token = create_access_token(identity=user.id)
return {
"token": token,
"user": user.to_dict()
}

8
services/user_service.py Normal file
View File

@ -0,0 +1,8 @@
from repositories.user_repo import UserRepository
class UserService:
@staticmethod
def list_users():
users = UserRepository.find_all()
return [u.to_dict() for u in users]