<2021SC@SDUSC>博客(11)山东大学软件工程应用与实践JPress代码分析(十)

2021SC@SDUSC

前言

在前面的四篇文章中,我对 module-article-service-provider 模块中的三个核心 ServiceProvider 类做了详细阐述,而在该模块下还有一部分其它的 ServiceProvider 类,但属于边缘代码,这里不再做分析。

回到 module-article 模块,我们已经分析完了 module-article-modelmodule-article-service 模块,剩余 module-article-searchmodule-article-web 模块。

module-article-search 模块简介

module-article-search 模块下只有一个接口类 ArticleSearcher,用于提供接口方法以全局搜索文章,其代码如下:

public interface ArticleSearcher {

    String HIGH_LIGHT_CLASS = "search-highlight";

    void addArticle(Article article);

    void deleteArticle(Object id);

    void updateArticle(Article article);

    Page<Article> search(String keyword, int pageNum, int pageSize);
}

接口很简单,提供了一个字符串常量 HIGH_LIGHT_CLASS 以及增删改查的接口方法,但这里暂时看不出该字符串常量的用法,后面应该会遇到。

通过 IntelliJ IDEA 的类追踪可以得知,一共有五个类实现了 ArticleSearcher 接口,分别是阿里云的智能开放搜索 AliyunOpenSearcher、JBoot 框架自带的数据库搜索 DbSearcher、著名的 ElasticSearcherLuceneSearcher 以及无搜索 NoneSearcher

image.png

在这些类中,NoneSercher 类是一个空类,用于不需要搜索但必须要实现该接口的地方;而 DbSearcher 类则只实现了 search() 方法,并且只是调用了 ArticleService 类中的 searchIndb() 方法,没有什么分析价值。

//io.jpress.module.article.searcher.DbSearcher.search()
public Page<Article> search(String keyword, int pageNum, int pageSize) {
    return articleService.searchIndb(keyword, pageNum, pageSize);
}

而其余的三个类则调用了第三方库,超出了分析 JPress 项目的范围,当然主要是我也看得不是很懂,这里不做分析。

module-article-web 模块简介

JPress 项目采用的是 MVC 架构,而在前面的文章我分析的是 Model 和 Service,在该模块下的内容即为 View 和 Controller。因为涉及到 View 模块,所以我们可以在该模块下看到 javawebapp 两个文件夹,分别用于存放前端和后端代码。

image.png

我们首先从 Controller 开始。

Controller

module-article 模块 Controller 的结构如下,共有四个部分。观察后可知, admin 为管理员对所有文章进行操作的部分,api 为对开放接口进行处理的部分,front 为访问文章内容、类型、标签或搜索进行处理的部分,ucenter 是用户在用户中心对与自己相关的文章进行操作的部分。

image.png

这部分是 module-article 模块的核心 Controller 部分,可能需要多篇文章进行分析,我们首先从 admin 开始。

admin

admin 部分一共有 5 个类,其中 _ArticleCommentController_ArticleController 类是管理员对全部文章和全部评论进行修改的类,_MarkdownImport_WechatArticleImport_WordpressImport 顾名思义可知 JPress 支持通过 Markdown、微信和 WordPress 直接导入成文章。

该部分下每个类前面都添加了一个下划线,虽然 JPress 没有直接说明其含义,但在 Python 中这种写法被赋予「私有类」的含义,可能是为了和后面 front 部分中重名的两个类进行区分,并指明两者的差别而成。

我们首先来看 _ArticleController

_ArticleController

基本结构

该类是管理员对全局文章进行操控的类,顺着该类继承链,我们最终可以得知其来自于 JFinal 框架下 com.jfinal.core 包中的核心类 Controller

_ArticleControllerAdminControllerBaseControllerBaseJbootControllerController

注解 @RequestMapping 用于请求映射配置,即通过域名加上此映射的地址可以访问该 Controller 资源。

@RequestMapping(value = "/admin/article", viewPath = JPressConsts.DEFAULT_ADMIN_VIEW)
public class _ArticleController extends AdminControllerBase {}
静态常量与成员变量
@Inject
private ArticleService articleService;
@Inject
private ArticleCategoryService categoryService;
@Inject
private MenuService menuService;

ArticleServiceArticleCategoryService 类已经在前文介绍过,而 MenuService 是与菜单有关的 Service,但这个类并没有被使用,所以并不是很重要。

image.png

文章管理
//io.jpress.module.article.controller.admin._ArticleController.list()
@AdminMenu(text = "文章管理", groupId = "article", order = 0)
public void list() {

    String status = getPara("status");
    String title = getPara("title");
    Long categoryId = getParaToLong("categoryId");

    Page<Article> page = StringUtils.isBlank(status)
                    ? articleService._paginateWithoutTrash(getPagePara(), getPageSizePara(), title, categoryId)
                    : articleService._paginateByStatus(getPagePara(), getPageSizePara(), title, categoryId, status);

    setAttr("page", page);

    Long draftCount = articleService.findCountByStatus(Article.STATUS_DRAFT);
    Long trashCount = articleService.findCountByStatus(Article.STATUS_TRASH);
    Long normalCount = articleService.findCountByStatus(Article.STATUS_NORMAL);

    setAttr("draftCount", draftCount);
    setAttr("trashCount", trashCount);
    setAttr("normalCount", normalCount);

    setAttr("totalCount", draftCount + trashCount + normalCount);


    List<ArticleCategory> categories = categoryService.findListByType(ArticleCategory.TYPE_CATEGORY);
    SortKit.toLayer(categories);
    setAttr("categories", categories);

    flagCheck(categories, categoryId);

    render("article/article_list.html");
}

//io.jpress.core.menu.annotation.@AdminMenu
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface AdminMenu {

    String groupId();

    String text();

    String icon() default "";

    String target() default "";

    int order() default 100; //越小在越前面
}

//io.jpress.module.article.controller.admin._ArticleController.flagCheck()
private void flagCheck(List<ArticleCategory> categories, Long... checkIds) {
    if (checkIds == null || checkIds.length == 0
            || categories == null || categories.size() == 0) {
        return;
    }

    for (ArticleCategory category : categories) {
        for (Long id : checkIds) {
            if (id != null && id.equals(category.getId())) {
                category.put("isCheck", true);
            }
        }
    }
}

注解 @AdminMenu 是 JPress 项目 io.jpress.core.menu.annotation 包下的内容,用于给 Controller 的方法进行标注,申明此方法为一个后台菜单方法。后台菜单被包含在 Group 里,而 Group 是由 Module 来定义的,JPress 系统也内置了几个 Group,groupId 则用于标识这个方法被放在哪个 Group 里。

List() 方法中的写法来自 JFinal 框架的 Action,并使用了 get / getPara 系列方法,获取或设置了大量与文章相关的参数,而后则调用了私有方法 flagCheck() 以检查文章类型和类型 ID 是否相同,最后返回 article/article_list.html

分类与标签
@AdminMenu(text = "分类", groupId = "article", order = 2)
public void category() {
    List<ArticleCategory> categories = categoryService.findListByType(ArticleCategory.TYPE_CATEGORY);
    SortKit.toLayer(categories);
    setAttr("categories", categories);
    long id = getParaToLong(0, 0L);
    if (id > 0 && categories != null) {
        for (ArticleCategory category : categories) {
            if (category.getId().equals(id)) {
                setAttr("category", category);
                setAttr("isDisplayInMenu", menuService.findFirstByRelatives("article_category", id) != null);
            }
        }
    }
    initStylesAttr("artlist_");
    render("article/category_list.html");
}

分类与标签方法非常类似,这里贴出分类方法作为示例。

首先通过 Service 获取与该类型有关的文章,接着对类型进行包装,然后逐个检查类型是否正确、一致,最后返回相关的 View。

结语

_AricleController 中有非常多的代码,但是绝大多数差不多,基本的形式与上面的分析相差无几,所以不做过多分析。下面的文章将对其它 Controller 进行分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值