ABOUT ME

-

Total
-
  • Rust: actix-rs에서 HTML tera 엔진 렌더링
    컴퓨터/Rust 2022. 6. 24. 11:24
    728x90
    반응형

    actix-rs

     

    Actix Web | A powerful, pragmatic, and extremely fast web framework for Rust.

    Request Routing The built-in Actix Web request router can be used with or without macros attached to handlers, and always provides flexible and composable methods of creating routing tables. Includes support for matching dynamic path segments, path prefix

    actix.rs

     

    소개

    이 글에선 Python django 처럼

    HTML 엔진을 이용해서 코드를 HTML에 inject 해볼 것이다.

    최종 결과로는 Vec<Review>를 HTML에 넣어서 다음과 같이 나온다.

     

    코드

    Tera 템플릿 엔진을 사용할 것이다.

    Cargo.toml

    [dependencies]
    actix-rt = "2"  # 웹 서버 열기
    actix-http = "3"  # 웹 서버 열기
    actix-web = "4"  # 웹 서버 열기
    serde = { version = "1.0", features = ["derive"] }  # JSON
    serde_json = "1.0"  # JSON
    serde_derive = "1.0"  # JSON
    futures = "0.3"  # 비동기 support
    
    tera = "1.16.0"  # 웹 홈페이지 tera template

    review.html

    reviews에 Rust Vec<Review>가 들어간다.

        <main>
          <section>
            {% for review in reviews %}
            <div class="review review-left">
              <div class="name">{{ review.writer }}</div>
              <div class="rating score">
                <span class="star">
                  ★★★★★
                  <span style="width: {{ review.rate * 10 }}%">★★★★★</span>
                  <input
                    id="star_rate"
                    type="range"
                    value="1"
                    step="1"
                    min="0"
                    max="10"
                    name="rate_param"
                  />
                </span>
                <div class="content">{{ review.review_txt }}</div>
              </div>
            </div>
            {% endfor %}
          </section>
        </main>

    main.rs

    actix.app_data를 이용해서 global하게 사용한다.

    use actix_web::middleware::{Compress, Logger, NormalizePath};
    use actix_web::{web, App, HttpServer};
    
    use std::sync::Mutex;
    use tera::{Context, Tera};
    
    #[actix_web::main]
    async fn main() -> std::io::Result<()> {
        let tera = web::Data::new(Mutex::new(
            Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*.html")).unwrap(),
        )); // 테라 global
    
        // 서버 실행
        HttpServer::new(move || {
            App::new()
                .app_data(tera.clone())
                // 미들웨어
                .wrap(Compress::default())
                .wrap(NormalizePath::default())
                .wrap(Logger::default())
                // 홈페이지
                .service(backend::review::review_html) // review get 함수
        })
        .bind(backend::SERVER)?
        .run()
        .await
    }

    review.rs

    GET/POST 엔드 포인트 함수에 tera로 렌더링 한다.

    html에 원하는 이름에 알맞게 데이터를 넣는다. (De/Serializable 가능해야 함)

    use serde::{Deserialize, Serialize};
    use tera::{Context, Tera};
    
    
    #[derive(Debug, Default, Serialize, Deserialize)]
    pub struct Review {
        pub writer: String,
        pub review_txt: String,
        pub rate: u8,
    }
    
    impl Review {
        pub fn new() -> Self {
            Default::default()
        }
    }
    
    #[get("/review/{food}")]
    async fn review_html(
        tera: web::Data<Mutex<Tera>>,
        food: web::Path<String>,
    ) -> impl Responder {
        println!("=> 리뷰 페이지");
    
        let food_name = food.into_inner();
    
        let mut reviews: Vec<Review> = DB에서 메뉴에 맞는 모든 Review 불러오기(food_name.to_string());
        reviews.reverse(); // 최신 리뷰순
    
        let mut ctx = Context::new();
        ctx.insert("reviews", &reviews);  // html에 reviews에 Rust reviews 넘김
    
        // println!("{:?}", ctx);
    
        let tera = tera.lock().unwrap();
    
        let rendered = tera.render("review.html", &ctx).unwrap(); // review.html 렌더링
        HttpResponse::Ok().content_type("text/html").body(rendered)
    }

     

    728x90

    댓글