- vừa được xem lúc

(EzyPlatform) hướng dẫn lấy ra danh sách bài viết highlight trong dự án Web Blog

0 0 5

Người đăng: Tien Bui

Theo Viblo Asia

Tạo ra các data trong cơ sở dữ liệu

B1: Tạo ra các term có Term Type là HIGHLIGHT. Term Type sẽ đại diện cho 1 danh mục cha, còn Term sẽ là danh mục con.

B2: Sau khi tạo ra các Term, chúng ta tiếp tục tạo ra các bài viết có những Term vừa tạo ra như sau:

Làm việc phía Backend

B1: Trong package repository, sửa nội dung interface WebBlogTermRepository như sau:

package com.blog.blog.web.repository; import com.tvd12.ezydata.database.EzyDatabaseRepository;
import com.tvd12.ezyfox.database.annotation.EzyQuery;
import com.tvd12.ezyfox.database.annotation.EzyRepository;
import org.youngmonkeys.ezyarticle.sdk.entity.PostTerm;
import org.youngmonkeys.ezyarticle.sdk.entity.PostTermId;
import org.youngmonkeys.ezyarticle.sdk.entity.Term; import java.util.Collection;
import java.util.List; @EzyRepository
public interface WebBlogTermRepository extends EzyDatabaseRepository<PostTermId, PostTerm> { @EzyQuery( "SELECT e FROM PostTerm e " + "INNER JOIN Term t " + "ON e.termId = t.id " + "WHERE t.name IN ?0" ) List<PostTerm> findHighlightPostTermsByTermNameIn( Collection<String> termNames );
}

Đây là hàm để truy vấn các thông tin của các PostTerm theo một danh sách tên term.

B2: Tạo ra 1 package có tên là model chứa 1 class WebPostTermModel có nội dung như sau:

package com.blog.blog.web.model; import lombok.Builder;
import lombok.Getter; @Getter
@Builder
public class WebPostTermModel { private final long postId; private final long termId;
}

B3: Trong package converter, tạo ra class WebBlogEntityToModelConverter có nội dung như sau:

package com.blog.blog.web.converter; import com.blog.blog.web.model.WebPostTermModel;
import com.tvd12.ezyfox.bean.annotation.EzySingleton;
import org.youngmonkeys.ezyarticle.sdk.entity.PostTerm; @EzySingleton
public class WebBlogEntityToModelConverter { public WebPostTermModel toModel(PostTerm entity) { if (entity == null) { return null; } return WebPostTermModel.builder() .postId(entity.getPostId()) .termId(entity.getTermId()) .build(); }
}

B4: Sửa nội dung của class WebBlogTermService trong package service như sau:

package com.blog.blog.web.service; import com.blog.blog.web.converter.WebBlogEntityToModelConverter;
import com.blog.blog.web.model.WebPostTermModel;
import com.blog.blog.web.repository.WebBlogTermRepository;
import com.tvd12.ezyhttp.server.core.annotation.Service;
import lombok.AllArgsConstructor; import java.util.Collection;
import java.util.List; import static com.tvd12.ezyfox.io.EzyLists.newArrayList; @Service
@AllArgsConstructor
public class WebBlogTermService { private final WebBlogTermRepository blogTermRepository; private final WebBlogEntityToModelConverter entityToModelConverter; public List<WebPostTermModel> getHighlightPostTermsByTermNames( Collection<String> termNames ) { return newArrayList( blogTermRepository.findHighlightPostTermsByTermNameIn( termNames ), entityToModelConverter::toModel ); }
}

Tại đây viết hàm getHighlightPostTermsByTermNames có tham số truyền vào là 1 danh sách termNames. Hàm này có nhiệm vụ là chuyển đổi từ danh sách PostTerm mình lấy được trong hàm findHighlightPostTermsByTermNameIn() sang 1 List các WebPostTermModel qua hàm toModel trong class WebBlogEntityToModelConverter .

B5: Trong WebBlogPostModelDecorator, viết 2 hàm decoratePostTerms() như sau:

package com.blog.blog.web.controller.decorator; import com.blog.blog.web.converter.WebBlogModelToResponseConverter;
import com.blog.blog.web.model.WebPostTermModel;
import com.blog.blog.web.response.WebBlogPostResponse;
import com.blog.blog.web.service.WebBlogTermService;
import com.tvd12.ezyfox.bean.annotation.EzySingleton;
import lombok.AllArgsConstructor;
import org.youngmonkeys.ezyarticle.sdk.model.PostModel;
import org.youngmonkeys.ezyarticle.sdk.model.TermModel;
import org.youngmonkeys.ezyarticle.web.service.WebPostService;
import org.youngmonkeys.ezyarticle.web.service.WebPostSlugService;
import org.youngmonkeys.ezyarticle.web.service.WebTermService;
import org.youngmonkeys.ezyplatform.model.MediaNameModel;
import org.youngmonkeys.ezyplatform.model.UuidNameModel;
import org.youngmonkeys.ezyplatform.web.service.WebAdminService;
import org.youngmonkeys.ezyplatform.web.service.WebMediaService; import java.util.List;
import java.util.Map;
import java.util.Set; import static com.tvd12.ezyfox.io.EzyLists.newArrayList;
import static com.tvd12.ezyfox.io.EzyMaps.newHashMap;
import static com.tvd12.ezyfox.io.EzySets.newHashSet; @EzySingleton
@AllArgsConstructor
public class WebBlogPostModelDecorator { private final WebAdminService adminService; private final WebBlogTermService blogTermService; private final WebMediaService mediaService; private final WebPostService postService; private final WebPostSlugService postSlugService; private final WebTermService termService; private final WebBlogModelToResponseConverter blogModelToResponseConverter; public List<WebBlogPostResponse> decoratePostTerms( List<WebPostTermModel> models ) { Set<Long> postIds = newHashSet( models, WebPostTermModel::getPostId ); Map<Long, PostModel> postById = postService.getPostMapByIds( postIds ); return decoratePostTerms( models, postById ); } public List<WebBlogPostResponse> decoratePostTerms( List<WebPostTermModel> models, Map<Long, PostModel> postById ) { Set<Long> postIds = newHashSet( models, WebPostTermModel::getPostId ); Set<Long> imageIds = newHashSet( postById.values(), PostModel::getFeaturedImageId ); Map<Long, MediaNameModel> imageById = mediaService .getMediaNameMapByIds(imageIds); Set<Long> authorIds = newHashSet( postById.values(), PostModel::getAuthorAdminId ); Map<Long, UuidNameModel> authorById = adminService .getAdminUuidNameMapByIds(authorIds); Map<Long, String> slugByPostId = postSlugService.getLatestSlugMapByPostIds( postIds ); Set<Long> termIds = newHashSet( models, WebPostTermModel::getTermId ); Map<Long, TermModel> termById = termService.getTermMapByIds( termIds ); return newArrayList( models, postTerm -> { PostModel post = postById.get(postTerm.getPostId()); return blogModelToResponseConverter.toPostResponse( post, authorById.get(post.getAuthorAdminId()), imageById.getOrDefault( post.getFeaturedImageId(), MediaNameModel.builder().build() ), termById.get(postTerm.getTermId()), slugByPostId.get(post.getId()) ); } ); }
}
  1. Hàm thứ nhất: có tham số truyền vào là 1 List<WebPostTermModel>, chúng ta lấy được 1 set các PostId, sau đó tạo ra 1 map các PostModel có key là PostId qua phương thức postService.getPostMapByIds(postTds) có sẵn trong thư viện. Cuối cung là return lại hàm decoratePostTerms thứ 2.

  2. Hàm thứ hai: có 2 tham số truyền vào là List<WebPostTermModel>Map<Long,PostModel> có key là PostId. Sau khi lấy được các dữ liệu cần thiết ta sử dụng hàm blogModelToResponseConverter.toPostResponse() để trả về dữ liệu cần thiết là 1 List<WebBlogPostResponse>.

    • Từ List<WebPostTermModel>, ta lấy ra được postIdstermIds. Sau đó, từ postIds, ta lấy được slugByPostId - map các slug có key là postId. Còn termIds lấy được termById - map các TermModel có key là termId.
    • Từ Map<Long,PostModel>, ta lấy được imageIdsauthorIds. Từ imageIds lấy được map các hình ảnh và từ authorIds sẽ lấy được map các tác giả.

B6: Trong WebBlogPostControllerService, viết hàm getHighlightPosts() trả về List các WebBlogPostResponse. Hàm này sử dụng getHighlightPostTermsByTermNames() để lấy ra list WebPostTermModel. Sau đó lấy list này làm tham số cho hàm decoratePostTerms() để lấy được danh sách WebBlogPostResponse cần lấy.

package com.blog.blog.web.controller.service; import com.blog.blog.web.controller.decorator.WebBlogPostModelDecorator;
import com.blog.blog.web.model.WebPostTermModel;
import com.blog.blog.web.response.WebBlogPostResponse;
import com.blog.blog.web.service.WebBlogPostService;
import com.blog.blog.web.service.WebBlogTermService;
import com.tvd12.ezyhttp.server.core.annotation.Service;
import lombok.AllArgsConstructor;
import org.youngmonkeys.ezyarticle.sdk.model.PostModel; import java.util.Arrays;
import java.util.List; @Service
@AllArgsConstructor
public class WebBlogPostControllerService { private final WebBlogTermService blogTermService; private final WebBlogPostService webBlogPostService; private final WebBlogPostModelDecorator blogPostModelDecorator; public List<WebBlogPostResponse> getHighlightPosts() { List<WebPostTermModel> postTerms = blogTermService .getHighlightPostTermsByTermNames( Arrays.asList( "main1", "main2", "main3", "main4" ) ); return blogPostModelDecorator.decoratePostTerms( postTerms ); }
}

B7:: Cuối cùng, tại HomeController sửa như sau:

package com.blog.blog.web.controller.view; import com.blog.blog.web.controller.service.WebBlogPostControllerService;
import com.blog.blog.web.response.WebBlogPostResponse;
import com.tvd12.ezyhttp.server.core.annotation.Controller;
import com.tvd12.ezyhttp.server.core.annotation.DoGet;
import com.tvd12.ezyhttp.server.core.view.View;
import lombok.AllArgsConstructor; import java.util.List; import static org.youngmonkeys.ezyplatform.constant.CommonConstants.VIEW_VARIABLE_PAGE_TITLE; @Controller
@AllArgsConstructor
public class HomeController { private final WebBlogPostControllerService blogPostControllerService; @DoGet("/") public View home() { return View.builder() .template("home") //--> Hàm .addVariable( "highlightPosts", blogPostControllerService.getHighlightPosts() ) .addVariable(VIEW_VARIABLE_PAGE_TITLE, "Trang chủ") .build(); }
}

Làm việc phía Fontend

Sửa lại html phần blog highlight như sau:

 <div class="row mt-4"> <div th:if="${highlightPosts.size() > 0}" class="col-8"> <div class="card overflow-hidden " > <div class="card-img position-relative"> <img loading="lazy" decoding="async" th:src="${highlightPosts.get(0).image.getUrlOrNull()}" alt="img1"> <div class="position-absolute bottom-0 start-50 translate-middle-x card-info w-100 text-center"> <button class="tag text-capitalize" >[[${highlightPosts.get(0).term.name}]]</button><br> <h3 class="line-container text-capitalize">[[${highlightPosts.get(0).title}]]</h3> <p class="text-capitalize date-string">[[${highlightPosts.get(0).publishedAt}]]</p> </div> </div> </div> </div> <div class="col-4"> <div class="card overflow-hidden" style="height: 576px"> <div class="card-img position-relative"> <img loading="lazy" decoding="async" th:src="${highlightPosts.get(1).image.getUrlOrNull()}" alt="img2"> <div class="position-absolute bottom-0 start-50 translate-middle-x card-info w-100 text-center"> <button class="tag text-capitalize" >[[${highlightPosts.get(1).term.name}]]</button><br> <h3 class="line-container text-capitalize">[[${highlightPosts.get(1).title}]]</h3> <p class="text-capitalize date-string">[[${highlightPosts.get(1).publishedAt}]]</p> </div> </div> </div> </div> </div>

Sau khi sửa xong ta sẽ có được giao diện bao gồm ảnh, term, title, publishedAt như sau:

Bình luận

Bài viết tương tự

- vừa được xem lúc

EzyPlatform - Giới thiệu về nền tảng Lập trình từ người Việt

Giới thiệu về Ezyplatform - Nền tảng lập trình từ người Việt. Ezyplatform là gì.

0 0 16

- vừa được xem lúc

EzyPlatform - Tạo blog dễ dàng với EzyBlog - Không cần code hay thiết kế

Giới thiệu. Bạn muốn tạo một trang blog nhưng không muốn đối mặt với sự phức tạp của việc lập trình hay thiết kế web? Đừng lo, EzyPlatform là giải pháp cho bạn.

0 0 16

- vừa được xem lúc

EzyPlatform - Cách tích hợp đăng nhập nhanh chóng với EzyLogin - Không cần code hay thiết kế

Giới thiệu. Bạn muốn tạo một trang web với tính năng đăng nhập, đăng ký cho người dùng, nhưng không muốn phải đối mặt với sự phức tạp của việc lập trình hay thiết kế giao diện đăng nhập? Đừng lo, EzyL

0 0 15

- vừa được xem lúc

Tích hợp Đăng nhập với Google vào Ứng dụng Web với EzyLogin - Phần 2

Giới thiệu. Trong phần 1, chúng ta đã khám phá cách tích hợp tính năng đăng nhập và đăng ký cơ bản vào ứng dụng web của bạn bằng EzyLogin.

0 0 26

- vừa được xem lúc

Tích hợp Đăng nhập với Facebook vào Ứng dụng Web với EzyLogin - Phần 3

Giới thiệu. Trong phần 2 chúng ta đã tìm hiểu cách tích hợp tính năng đăng nhập và đăng ký bằng Google với EzyLogin.

0 0 18

- vừa được xem lúc

Tạo dự án EzyPlatform

Khởi tạo project. Bước 1: Cài đặt SDK và giải nén. . Bước 3: Thêm %EZYPLATFORM_SDK%in vào biến path.

0 0 10