添加 thiserror、log 和 env_logger 依赖,重构用户服务和数据库连接池,优化用户注册功能的错误处理

This commit is contained in:
rsgl 2024-11-17 11:10:04 +08:00
parent 7f89249f83
commit c49734430b
8 changed files with 243 additions and 138 deletions

153
Cargo.lock generated
View File

@ -250,9 +250,9 @@ dependencies = [
[[package]]
name = "allocator-api2"
version = "0.2.18"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
[[package]]
name = "arrayvec"
@ -260,6 +260,17 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.4.0"
@ -376,9 +387,9 @@ dependencies = [
[[package]]
name = "borsh"
version = "1.5.1"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed"
checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03"
dependencies = [
"borsh-derive",
"cfg_aliases",
@ -386,16 +397,15 @@ dependencies = [
[[package]]
name = "borsh-derive"
version = "1.5.1"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b"
checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244"
dependencies = [
"once_cell",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.87",
"syn_derive",
]
[[package]]
@ -479,9 +489,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.1.36"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70"
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
dependencies = [
"jobserver",
"libc",
@ -574,9 +584,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cpufeatures"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6"
dependencies = [
"libc",
]
@ -697,11 +707,14 @@ version = "0.1.0"
dependencies = [
"actix-web",
"bcrypt",
"env_logger",
"log",
"mysql",
"r2d2",
"r2d2_mysql",
"serde",
"serde_derive",
"thiserror",
"uuid",
]
@ -774,6 +787,19 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "env_logger"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@ -792,15 +818,15 @@ dependencies = [
[[package]]
name = "fastrand"
version = "2.1.1"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
[[package]]
name = "flate2"
version = "1.0.34"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [
"crc32fast",
"libz-sys",
@ -1009,9 +1035,18 @@ dependencies = [
[[package]]
name = "heck"
version = "0.4.1"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
@ -1042,6 +1077,12 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "icu_collections"
version = "1.5.0"
@ -1259,9 +1300,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.162"
version = "0.2.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
[[package]]
name = "libloading"
@ -1377,7 +1418,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [
"hermit-abi",
"hermit-abi 0.3.9",
"libc",
"log",
"wasi",
@ -1411,15 +1452,15 @@ dependencies = [
[[package]]
name = "mysql-common-derive"
version = "0.31.1"
version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afe0450cc9344afff34915f8328600ab5ae19260802a334d0f72d2d5bdda3bfe"
checksum = "63c3512cf11487168e0e9db7157801bf5273be13055a9cc95356dc9e0035e49c"
dependencies = [
"darling",
"heck",
"num-bigint",
"proc-macro-crate",
"proc-macro-error",
"proc-macro-error2",
"proc-macro2",
"quote",
"syn 2.0.87",
@ -1683,27 +1724,25 @@ dependencies = [
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"version_check",
"syn 2.0.87",
]
[[package]]
@ -1824,9 +1863,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.8"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@ -1922,9 +1961,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.39"
version = "0.38.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee"
checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0"
dependencies = [
"bitflags",
"errno",
@ -1990,9 +2029,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
version = "2.12.0"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
dependencies = [
"core-foundation-sys",
"libc",
@ -2006,18 +2045,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "serde"
version = "1.0.214"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.214"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [
"proc-macro2",
"quote",
@ -2026,9 +2065,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.132"
version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
dependencies = [
"itoa",
"memchr",
@ -2172,18 +2211,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "syn_derive"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.87",
]
[[package]]
name = "synstructure"
version = "0.13.1"
@ -2203,9 +2230,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tempfile"
version = "3.13.0"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [
"cfg-if",
"fastrand",
@ -2225,18 +2252,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.68"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.68"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",

View File

@ -12,3 +12,6 @@ serde = "1.0"
serde_derive = "1.0"
uuid = { version = "1.11.0", features = ["v4"] }
bcrypt = "0.15.1"
thiserror = "1.0"
log = "0.4"
env_logger = "0.9"

View File

@ -1,4 +1,8 @@
use actix_web::{App, HttpServer};
use actix_web::{web, App, HttpServer};
use log::{error, info};
use r2d2_mysql::MySqlConnectionManager;
use std::io;
mod models;
mod repositories;
mod routes;
@ -8,9 +12,43 @@ mod utils;
use crate::routes::user_routes;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().configure(user_routes::register))
.bind("127.0.0.1:8080")?
.run()
.await
async fn main() -> io::Result<()> {
env_logger::init();
info!("Starting server!!!!!!!!");
let url = "mysql://root:0andrx@122.152.201.90:9912/test_server";
let opts = match r2d2_mysql::mysql::Opts::from_url(url) {
Ok(opts) => opts,
Err(e) => {
eprintln!("Failed to parse MySQL connection URL: {}", e);
std::process::exit(1);
}
};
let opts_builder = r2d2_mysql::mysql::OptsBuilder::from_opts(opts);
let manager = MySqlConnectionManager::new(opts_builder);
let pool = match r2d2::Pool::builder().max_size(15).build(manager) {
Ok(pool) => {
info!("Successfully created connection pool");
pool
}
Err(e) => {
error!("Failed to create connection pool: {}", e);
return Err(io::Error::new(
io::ErrorKind::Other,
"Failed to create connection pool",
));
}
};
let pool_data = web::Data::new(pool.clone());
HttpServer::new(move || {
App::new()
.app_data(pool_data.clone())
.configure(user_routes::register)
})
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,6 +1,3 @@
use mysql::prelude::FromRow;
use mysql::{FromRowError, Row};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct User {
pub id: Option<i32>,
@ -9,17 +6,3 @@ pub struct User {
pub email: String,
pub password: String,
}
impl FromRow for User {
fn from_row_opt(row: Row) -> mysql::Result<Self, FromRowError> {
let (id, name, age, email, password) =
mysql::from_row::<(i32, String, i32, String, String)>(row);
Ok(User {
id: Some(id),
name,
age,
email,
password,
})
}
}

View File

@ -1,20 +1,32 @@
use crate::models::user::User;
use mysql::params;
use mysql::prelude::Queryable;
use mysql::{params, Error as MysqlError};
use r2d2::{Error as R2D2Error, Pool};
use r2d2_mysql::MySqlConnectionManager;
use thiserror::Error;
pub struct UserRepository<'a> {
pub pool: &'a mut r2d2::Pool<r2d2_mysql::MySqlConnectionManager>,
#[derive(Error, Debug)]
pub enum UserRepositoryError {
#[error("mysql error: {0}")]
MySqlError(#[from] MysqlError),
#[error("Connection pool error: {0}")]
PoolError(#[from] R2D2Error),
}
impl<'a> UserRepository<'a> {
pub fn new(pool: &'a mut r2d2::Pool<r2d2_mysql::MySqlConnectionManager>) -> UserRepository {
pub struct UserRepository {
pool: Pool<MySqlConnectionManager>,
}
impl UserRepository {
pub fn new(pool: Pool<MySqlConnectionManager>) -> Self {
UserRepository { pool }
}
/**
*
*/
pub fn create_user(&mut self, user: &mut User) -> Result<(), mysql::Error> {
pub fn create_user(&self, user: &User) -> Result<(), UserRepositoryError> {
let mut conn = self.pool.get().unwrap();
let sql = r"INSERT INTO users (id, name, age, email, password) VALUES (:id, :name, :age, :email, :password)";
conn.exec_drop(
@ -26,7 +38,8 @@ impl<'a> UserRepository<'a> {
"email" => &user.email,
"password" => &user.password,
},
)
)?;
Ok(())
}
// /**

View File

@ -1,18 +1,50 @@
use crate::models::user_input::UserInput;
use crate::repositories::user_repository;
use crate::repositories::user_repository::UserRepository;
use crate::services::user_service;
use crate::utils::pool;
use crate::{models::user_input::UserInput, services::user_service::UserServiceError};
use actix_web::{post, web, HttpResponse, Responder};
use r2d2_mysql::MySqlConnectionManager;
use serde::Serialize;
#[derive(Serialize)]
struct ApiResponse<T> {
status: String,
message: Option<T>,
error: Option<String>,
}
pub(crate) fn register(config: &mut web::ServiceConfig) {
config.service(register_user);
}
#[post("/user/register")]
async fn register_user(mut user: web::Json<UserInput>) -> impl Responder {
let mut pool = pool::get_database_pool().unwrap();
let mut user_repository = user_repository::UserRepository::new(&mut pool);
let mut user_service = user_service::UserService::new(&mut user_repository);
user_service.create_user(&mut user).unwrap();
HttpResponse::Ok().json("SUCCESS")
async fn register_user(
user: web::Json<UserInput>,
pool: web::Data<r2d2::Pool<MySqlConnectionManager>>,
) -> impl Responder {
let user_repository = UserRepository::new(pool.get_ref().clone());
let user_service = user_service::UserService::new(user_repository);
match user_service.create_user(&user) {
Ok(_) => HttpResponse::Ok().json(ApiResponse {
status: "success".to_string(),
message: Some("User created successfully".to_string()),
error: None,
}),
Err(e) => {
// 根据错误类型返回不同的 HTTP 状态码
let response = if matches!(e, UserServiceError::MissingField(_)) {
HttpResponse::BadRequest().json(ApiResponse::<()> {
status: "error".to_string(),
message: None,
error: Some(e.to_string()),
})
} else {
HttpResponse::InternalServerError().json(ApiResponse::<()> {
status: "error".to_string(),
message: None,
error: Some(e.to_string()),
})
};
response
}
}
}

View File

@ -1,31 +1,65 @@
use crate::{
models::{user::User, user_input::UserInput},
repositories::user_repository::UserRepository,
repositories::user_repository::{UserRepository, UserRepositoryError},
};
use bcrypt::{hash, DEFAULT_COST};
use mysql::*;
use thiserror::Error;
pub struct UserService<'a> {
repository: &'a mut UserRepository<'a>,
#[derive(Error, Debug)]
pub enum UserServiceError {
#[error("mysql error: {0}")]
MySqlError(#[from] UserRepositoryError),
#[error("Missing field: {0}")]
MissingField(&'static str),
#[error("Password hashing failed: {0}")]
HashError(#[from] bcrypt::BcryptError),
}
impl<'a> UserService<'a> {
pub fn new(repository: &'a mut UserRepository<'a>) -> Self {
pub struct UserService {
repository: UserRepository,
}
impl UserService {
pub fn new(repository: UserRepository) -> Self {
UserService { repository }
}
/**
*
*/
pub fn create_user(&mut self, user: &UserInput) -> Result<(), mysql::Error> {
pub fn create_user(&self, user: &UserInput) -> Result<(), UserServiceError> {
let name = user
.name
.as_ref()
.ok_or(UserServiceError::MissingField("name"))?
.to_string();
let age = user
.age
.as_ref()
.ok_or(UserServiceError::MissingField("age"))?;
let email = user
.email
.as_ref()
.ok_or(UserServiceError::MissingField("email"))?
.to_string();
let password = user
.password
.as_ref()
.ok_or(UserServiceError::MissingField("password"))?
.to_string();
let mut new_user = User {
id: Some(0),
name: user.name.as_ref().unwrap().to_string(),
age: *user.age.as_ref().unwrap(),
email: user.email.as_ref().unwrap().to_string(),
password: hash(user.password.as_ref().unwrap(), DEFAULT_COST).unwrap(),
name,
age: *age,
email,
password: hash(password, DEFAULT_COST).unwrap(),
};
self.repository.create_user(&mut &mut new_user)
self.repository.create_user(&mut new_user)?;
Ok(())
}
}

View File

@ -1,25 +0,0 @@
// use mysql::*;
// /**
// * 获取数据库连接池
// */
// pub fn get_database_pool().unwrap -> Pool {
// let url = "mysql://root:0andrx@122.152.201.90:9912/test_server";
// Pool::new(url).expect("TODO: panic message")
// }
use r2d2::Pool;
use r2d2_mysql::MySqlConnectionManager;
pub fn get_database_pool() -> Result<Pool<MySqlConnectionManager>, r2d2::Error> {
let url = "mysql://root:0andrx@122.152.201.90:9912/test_server";
let opts =
r2d2_mysql::mysql::OptsBuilder::from_opts(r2d2_mysql::mysql::Opts::from_url(url).unwrap());
let manager = r2d2_mysql::MySqlConnectionManager::new(opts);
let pool = Pool::builder()
.max_size(10)
.min_idle(Some(5))
.build(manager)
.unwrap();
Ok(pool)
}