您的当前位置:首页推荐一套整合内容发布的高颜值全家桶

推荐一套整合内容发布的高颜值全家桶

2024-12-13 来源:哗拓教育

楔子

去年的时候,因为工作需要重新把代码捡起来。不过并不是开发企业级管理系统,而是面向客户的内容发布平台,用来,目前核心业务已经对外发布,所以这个图也终于不用保密了。

这张图等到下半年可以找一个机会详细再写一篇文章,说回正题,由于是面向客户的系统,颜值是第一位的,寻寻觅觅很久,也试用了很多款开源框架以及一些云存储平台,下面罗列一下,需要注意的是,也许这些开源产品原本的用途并不是我所应用的用途,在我组合的框架里面可能定位有些偏颇

小程序UI库:

  • image
  • image
  • image
image

最终我选择使用ColorUI主要是两个方面:

  1. 颜值,ColorUI的颜值非常高,可以看一下我用Mock做的这张图

    image
  2. ColorUI使用的是传统的css引用,这就避免了上面那些UI的组件注入,很大程度的节省了代码空间,要知道小程序的包大小限制在4M,最近群里很多人都在劝说作者封装组件,我想说的是,还是要保持初心,你最早做UI就是面向小程序的,完全没必要去封装,如果是要适应uni-app,改一个参数不就好了,也是没必要封装组件。

内容管理系统:

    1. 嗯,是因为颜值。
    2. 同时,它的模块拆分比较合理,可能也是定位比较清晰,就是博客应用,因此部署简单,因为对于应用整合来说,引入一个开源系统就是直接应用加轻度开发,开发完毕后打成docker镜像直接扔到宿主机上启动就可以了,方便快捷。
    image

    当然,Halo还是有自己的问题,Api太少了!!!!,目前仅有三个接口,一个获取全部文章、一个获取评论是否开启、还有一个获取标签分类,但没有获取标签分类下的文章,实际上加一个Api很简单,而且看源码里面service里面已经有了根据tags查找文章的方法,但不知道作者为什么一直没有把Api抛出来,我猜测作者的心理可能仅仅想要做博客应用,不希望把Halo变成内容管理平台吧?

  • 这里插一个题外话,在开源界,JFinal应该不用再过多介绍,谁不知道JFinal都不好意思说混开源圈,JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。在拥有Java语言所有优势的同时再拥有ruby、python等动态语言的开发效率!尤其是jfinal-undertow的出现,直接影响到一部分已经转IDEA的开发者回到了eclipse!

    Jboot是一个开源的分布式、商业级的微服务架构,基于JFinal的MVC,其实应该这样介绍,JFinal+jboot面向的竞手就是Spring Boot + Spring Cloud,当然,以目前的体量可以说是蚂蚁吞大象,但是将来,谁知道呢,做人嘛,总要有理想。

    你会看到我对于上面的UI部分,没有选择的就没有直接评价,但是这里却说了很多,因为Jpress真的是一套非常好的开源框架:

    1. 继承JFinal的轻量级,基础代码非常少,很容易理解和二次开发
    2. 写好了最基本的后台管理,并配套对接了各种云存储、微信公众号、腾讯邮箱、阿里云短信等本地化服务
    3. 模块化做的非常好,新增模块相对非常容易,通过基本模块可以变化成博客、论坛、问答、商城等各式各样的web应用

    说了那么多优点,是为什么原因让我放弃使用呢?主要有两点:

    1. docker hub上的镜像版本太低了,还是1.05的(刚刚上去看,终于更新了),所以只能自己下源码封装最新版,这就带来的第二个问题

      image
    2. 作者不知道出于什么目的,可能是为了极致的拆分服务吧?将JPress拆成非常多的模块,大概十几个,同时引用了非常多的maven类库,直接导致我的本地maven库变成了1.95G,我想说微服务的概念在服务拆分这部分,颗粒度还是有争议的,文章|页面|附件|用户|微信|模版|系统,这些应用拆成了十几个模块可能是有些太细了。

      当然我相信这都是过程,无论如何Jpress都是非常优秀的开源平台,并且目前正在不断调整作品的定位,作者的更新速度还是非常快。从上面的tags大小也能看出来,作者应该是意识到了jar包引用的问题,并且已经修复了,同时看到最新的版本里面添加了代码生成器,不过短时间我暂时没时间深入研究了,也许后期等做SNS应用的时候可以再深入研究一下

云存储:

其实云存储没什么好选的,阿里的虽然流量免费但是存储空间按月收费,费用不高,但,收费。又拍云的CDN很不错,但是收费。七牛云做完实名认证之后有10G的免费空间可以使用,下载流量也是10G之内免费,唯一需要付费的就是Https的流量。嗯,怎么看都像一个个人开发者的思考逻辑,而不是公司行为,啧啧。

开始组装

系统都选好了,那么接下来就是组装了,组装非常简单:

image

对Halo进行二次开发

首先clone最新的Halo源码,然后抛出我们所需要的API,这里主要是根据分类和根据标签查询文章,在package cc.ryanc.halo.web.controller.api.ApiPostController;里面添加一个方法:通过文章分类查找文章

    /**
     * 根据分类目录查询所有文章 分页
     *
     *
     * @param cateUrl 分类目录路径
     * @param page    页码
     * @return String
     */
    @GetMapping("/cate/{cateUrl}/{page}")
    public JsonResult categories(@PathVariable("cateUrl") String cateUrl,
                             @PathVariable("page") Integer page,
                             @SortDefault(sort = "postDate", direction = DESC) Sort sort) {
        final Category category = categoryService.findByCateUrl(cateUrl);
        int size = 10;
        if (StrUtil.isNotBlank(OPTIONS.get(BlogPropertiesEnum.INDEX_POSTS.getProp()))) {
            size = Integer.parseInt(OPTIONS.get(BlogPropertiesEnum.INDEX_POSTS.getProp()));
        }
        final Pageable pageable = PageRequest.of(page - 1, size, sort);
        final Page<Post> posts = postService.findPostByCategories(category, pageable);
        if (null == posts) {
            return new JsonResult(HttpStatus.NO_CONTENT.value(), HttpStatus.NO_CONTENT.getReasonPhrase());
        }
        return new JsonResult(HttpStatus.OK.value(), HttpStatus.OK.getReasonPhrase(), posts);
    }



    /**
     * 根据标签路径查询所有文章 分页
     *
     *
     * @param tagUrl 标签路径
     * @param page   页码
     * @return String
     */
    @GetMapping(value = "/tag/{tagUrl}/{page}")
    public JsonResult tags(@PathVariable("tagUrl") String tagUrl,
                       @PathVariable("page") Integer page,
                       @SortDefault(sort = "postDate", direction = DESC) Sort sort) {
        final Tag tag = tagService.findByTagUrl(tagUrl);
        int size = 10;
        if (StrUtil.isNotBlank(OPTIONS.get(BlogPropertiesEnum.INDEX_POSTS.getProp()))) {
            size = Integer.parseInt(OPTIONS.get(BlogPropertiesEnum.INDEX_POSTS.getProp()));
        }
        final Pageable pageable = PageRequest.of(page - 1, size, sort);
        final Page<Post> posts = postService.findPostsByTags(tag, pageable);
        if (null == posts) {
            return new JsonResult(HttpStatus.NO_CONTENT.value(), HttpStatus.NO_CONTENT.getReasonPhrase());
        }
        return new JsonResult(HttpStatus.OK.value(), HttpStatus.OK.getReasonPhrase(), posts);
    }

需要注意的是,这里的findPostByCategories方法需要传入Categories,categoryService里面有一个写好的方法findByCateName,在因此需要在类上面categoryService

    @Autowired
    private TagService tagService;
    @Autowired
    private CategoryService categoryService;

OK了,就这么简单,接下来直接用源码里面的dockerfile打包成镜像扔到服务器上就可以了。

作者还非常贴心的整合了个docker-compose文件,也可以用,不过我是直接敲命令的。

version: '2'
services:

  nginx:
    restart: always
    image: nginx
    container_name: nginx
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/nginx/conf.d:/etc/nginx/conf.d
      - /etc/nginx/vhost.d:/etc/nginx/vhost.d
      - /usr/share/nginx/html:/usr/share/nginx/html
      - /etc/nginx/certs:/etc/nginx/certs:ro

  halo:
    restart: always
    image: ruibaby/halo
    container_name: halo
    ports:
      - 8090:8090
    environment:
      - VIRTUAL_PORT=8090
      - VIRTUAL_HOST=localhost  # 监听的地址(务必修改)
      - LETSENCRYPT_HOST=localhost # 证书的域名 (务必修改)
      -  # 证书所有者的邮箱,快过期时会提醒(务必修改)
      - DB_USER=admin # h2数据库用户名,自定义(务必修改)
      - DB_PASSWORD=123456 # h2数据库密码,自定义(务必修改)
    volumes:
      - ~/halo:/root/halo

  docker-gen:
    restart: always
    image: jwilder/docker-gen
    container_name: docker-gen
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - /etc/nginx/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro
    volumes_from:
      - nginx
    entrypoint: /usr/local/bin/docker-gen -notify-sighup nginx -watch -wait 5s:30s
      /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf

  letsencrypt-nginx-proxy-companion:
    restart: always
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: letsencrypt-nginx-proxy-companion
    volumes_from:
      - nginx
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /etc/nginx/certs:/etc/nginx/certs:rw
    environment:
      - NGINX_DOCKER_GEN_CONTAINER=docker-gen

配置Halo后台多媒体文件保存在七牛云

这个操作比较简单,直接在后台设置-博客设置-附件设置里面选择,并填写入对应申请的信息即可,Bucket就是你对象存储空间的名字,一开始我也是懵逼半天。

image

用ColorUI开发小程序展示页面

ColorUI的使用方法异常简单,Demo就在源码里面,所以虽然群里面一直有人喊让作者写文档,我觉得除了自定义tabBar之外应该都不太用写吧?整个源码就两个文件夹templatedemo

image

查看demo的方法:先自己建一个空的小程序,把路径里面除了project.config.json其他的文件全都删掉,然后把demo文件夹里面除了project.config.json的所有内容复制小程序路径里面,直接微信开发者工具打开就可以了,所有的实现都在里面,喜欢那个样式直接复制即可。

如果需要在现有小程序里面引用:

  1. 需要复制colorui.wxssicon.wxss两个文件到你的小程序根目录,如果你开启了云开发的话,就是在miniprogram
image
  1. app.wxss里面加入引用
@import "icon.wxss";
@import "colorui.wxss";

view {
  overflow: initial;
}
  1. 喜欢哪个就复制哪个wxml就可以了,page里面的wxss不用管

自定义tabBar的说明

需要多说一句的是自定义tabBar,作者在2.0.5版本里面加入了自定义tabBar,不过微信官方支持自定义的基础库版本是2.5以上,所以设置自定义tabBar需要考虑清楚,如果确定要用,那么也是分两步:

  • 首先,需要把demo包里面的custom-tab-bar文件夹复制进小程序根目录,就是跟app.json的同级目录

  • 然后在app.json里面的"tabBar"部分加入"custom": true

    此时就可以开启自定义的tarBar了,之后的tarBar维护和更改都应该在custom-tab-bar文件夹内进行配置,而不是在app.json里面配置,这里在安利一点,由于使用了自定义tarBar,我们的tarBar可以实现透明效果了,同时icon可以直接用字体图标而不是81px的图片,demo当中仍然使用的是图片,可以参考我下面这两个文件的写法。

    index.js

   Component({
     options: {
       addGlobalClass: true,
     },
     data: {
       selected: 0,
       color: "#808080",
       selectedColor: "#FFFFFF",
       backroundColor: "#000",
       modalName:false,
       list: [{
         pagePath: "/pages/index/index",
         icon:"icon-repeal",
         text: "来往"
         },
         {
           pagePath: "/pages/halo/index",
           icon: "icon-comment",
           text: "课堂"
         },
         {
           pagePath: "/pages/translator/translator",
           icon: "icon-cart",
           text: "翻译"
         },
         {
           pagePath: "/pages/walk/walk",
           icon: "icon-footprint",
           text: "漫步"
         },
         {
           pagePath: "/pages/halo/index",
           icon: "icon-list",
           text: "生活"
         }
       ]
     },
     methods: {
       switchTab(e) {      
         const url = e.currentTarget.dataset.path
         console.log(e)   
         wx.switchTab({
           url
         })
        
       }
     },
     pageLifetimes: {
     }
   })

index.wxml

   <view class="cu-bar tabbar bg-black shadow padding-tb-sm"  style='background-color:rgba(0, 0, 0, 0.2)'>
   
     <view class='action {{index == 2 ? "add-action" : ""}}' wx:for="{{list}}" wx:key="index" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab" style='color: {{selected === index ? selectedColor : color}}'>
       <view wx:if="{{index != 2}}" class='{{item.icon}}'></view>
       <view wx:if="{{index == 2}}" class='cu-btn icon-order bg-bjfunred shadow'></view>
       {{item.text}}
     </view>
   
   </view>

使用html2wxml插件进行html页面渲染

image

在app.json里面进行插件声明:

"plugins": {
    "htmltowxml": {
        "version": "1.3.1",
        "provider": "wxa51b9c855ae38f3c"
    }
}

然后在需要页面的json文件中进行如下注册:

"usingComponents": {
    "htmltowxml": "plugin://htmltowxml/view"
  }

最后在需要页面的wxml文件里面直接使用,将html文件内容注入标签即可:

  <view class='margin-lrji solid-top padding-top'>
    <htmltowxml text="{{post.postContent}}" highlightStyle="{{style}}" linenums="{{false}}" showLoading="{{false}}" bindWxmlTagATap="wxmlTagATap"></htmltowxml>
  </view>

最后看一下呈现效果:

image 欢迎关注个人公众号
显示全文