# rust mutithread web-server Diesel orm framework # Diesel https://diesel.rs/ 在開始使用前要先安裝 Diesel 的工具,請輸入以下指令: > $ cargo install diesel_cli > 預設它會開啟所有能支援的資料庫,若你只需要它支援部份的資料庫可以用以下指令 > $ cargo install diesel_cli --no-default-features --features sqlite ![](https://i.imgur.com/ZXLy0Ul.png) # Migration 我們先建一個存貼文的表格吧: > $ diesel migration generate create_posts 它會在 migrations 的資料夾下建立一個以日期、一組號碼與 create_post 命名的資料夾,在底下會有兩個檔案, up.sql 與 down.sql 分別為建立的 SQL 與撤消的 SQL ,我們先在 up.sql 中寫入建立資料表的指令: ```sql= CREATE TABLE posts ( id INTEGER NOT NULL PRIMARY KEY, author VARCHAR NOT NULL, title VARCHAR NOT NULL, body TEXT NOT NULL ); ``` 然後在 down.sql 中寫入刪除資料表的指令: ```sql= DROP TABLE posts; ``` 接著執行: > $ diesel migration run > 它會執行剛剛寫好的 SQL ,同時也會更新 src/schema.rs 這個檔案,你可以打開來,應該會看到以下內容: ```sql= table! { posts (id) { id -> Integer, author -> Text, title -> Text, body -> Text, } } ``` # 結合orm ## module.rs ```rust= use std::fmt; // Insertable 產生的程式碼會使用到,所以必須要引入 use super::schema::posts; // 一個可以用來查詢的 struct #[derive(Queryable, Debug)] pub struct Post { pub id: i32, pub author: String, pub title: String, pub body: String, } impl fmt::Display for Post { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{},{},{},{}\n", self.id,self.author,self.title,self.body) } } // 新增用的 struct ,唯一的差別是沒有 id 的欄位,以及使用的是 str #[derive(Insertable)] // 這邊要指定資料表的名稱,不然 diesel 會嘗試用 struct 的名稱 #[table_name = "posts"] pub struct NewPost<'a> { pub author: &'a str, pub title: &'a str, pub body: &'a str, } ``` ## main.rs ```rust= use diesel::{prelude::*, sqlite::SqliteConnection}; use dotenv::dotenv; use std::env; mod models; mod schema; use models::NewPost; use crate::models::Post; fn establish_connection() -> SqliteConnection { let url = env::var("DATABASE_URL").expect("找不到資料庫位置"); SqliteConnection::establish(&url).expect("連線失敗") } fn list_posts(conn: &SqliteConnection) -> Vec<Post> { // 引入資料表的所有東西 use self::schema::posts::dsl::*; // 載入所有的貼文 posts.load::<Post>(conn).expect("取得貼文列表失敗") } // ... fn create_post(conn: &SqliteConnection, author: &str, title: &str, body: &str) { // 引入我們的資料表 use self::schema::posts; // 建立要準備新增的資料的 struct let new_post = NewPost { author, title, body, }; // 指明要新增的表與新的值 diesel::insert_into(posts::table) .values(&new_post) // 執行 .execute(conn) .expect("新增貼文失敗"); } fn main(){ dotenv().ok(); let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); let pool = ThreadPool::new(4); for stream in listener.incoming() { let stream = stream.unwrap(); for stream in listener.incoming() { let stream = stream.unwrap(); pool.execute(|| { handle_connection(stream); }); } } } fn handle_connection(mut stream: TcpStream) { let conn = establish_connection(); // 呼叫 create_post 建立貼文 let mut buffer = [0; 512]; stream.read(&mut buffer).unwrap(); let get = b"GET / HTTP/1.1\r\n"; let get2 = b"GET /test HTTP/1.1\r\n"; let (status_line, filename) = if buffer.starts_with(get) { ("HTTP/1.1 200 OK\r\n\r\n", "/root/rust/www/hello.html") } else if buffer.starts_with(get2) { ("HTTP/1.1 200 OK\r\n\r\n", "/root/rust/www/hello.html") } else { ( "HTTP/1.1 404 NOT FOUND\r\n\r\n", "/root/rust/www/error.html", ) }; let mut data=String::new(); unsafe { // let serialized_user = serde_json::to_string(&user).unwrap(); for x in list_posts(&conn).iter() { let get_str:&str = &x.to_string()[..]; data.push_str(get_str); println!("> {}", get_str); } // data = list_posts(&conn).to_string(); } let contents = data; let response = format!("{}{}", status_line, contents); stream.write(response.as_bytes()).unwrap(); stream.flush().unwrap(); } ``` # run 如果要實作restful 的話,可能要對細部做調整,包括返回的string 要to json 之類的 ![](https://i.imgur.com/IJJ1p6m.png)