みなさんこんにちは、砂漠の果ての狼です。

サイト管理者がGoで書いたこのバージョンのブログのコードはかなり素朴で、フレームワークも使っていません。当初は後でリファクタリングしてから詳しく書こうと思っていましたが、今日グループのメンバーからリクエストがあったので、簡単に書いてみます。
オンラインアクセス先: https://go.dotnet9.com
トップページのスクリーンショット:

この記事はとても簡単に書いてあるので、目次を示します。
- Goの基礎学習
- Goでブログを構築する際の参考
- Goバージョンのブログソースコード
- 今後の計画
1. Goの基礎学習
- Go 日本語ドキュメント: https://go.p2hp.com/doc/
- Go Web プログラミング: QQグループ(771992300)にPDFファイルあり
上記のURLとPDFは、基礎を固め、Goの基本文法を強化するのに適しています。PDFファイルはおそらく京东で販売されている『Go Webプログラミング』([シンガポール] 郑兆雄)の本ではなく、非常に優れた内容で、多くのWeb基礎知識を解説しています。ネット上のある達人のまとめと思われ、一読の価値があります。以下はそのPDFの目次です。

上記の基礎資料は、Goに触れたことのない方にお勧めします。基礎は重要です。
2. Goでブログを構築する際の参考
今回リファクタリングしたブログのフロントエンドテンプレートとGoバージョンの学習資料の出典:
B站のUp主【码神之路】B站ホームページ: https://space.bilibili.com/473844125
チュートリアルタイトル: 【码神之路】原生Go言語ブログ実戦チュートリアル、練習用プロジェクト実戦チュートリアル、フレームワーク不使用、わかりやすく、10年大手工ンジニアが解説
ビデオの目次は以下の通り:

ビデオ付属のブログ記事のスクリーンショット:

ビデオは学習・実践に適しており、Up主のブログ記事はコードが正しいか確認するのに役立ちます。ブログに付属するフロントエンドテンプレートはUp主のグループで共有されています(グループ番号【718840650】)。サイト管理者のコード倉庫にもアップロードされていますが、Up主とは一部変更が異なり、以下のような個別のカスタマイズがあります。
- サイト管理者はフロントエンドの記事編集機能を追加していません。Dotnet9サイトにはバックエンドの記事管理機能があり、機能が重複するためです。
- ORMの選択が異なります。サイト管理者はGORMを選択しました。
- 記事検索は、サイト管理者はDotnet9サイトのバックエンドAPIを直接呼び出しており、Goで新たにインターフェースを実装していません。Web APIとフロントエンドの責務を分離し、他のクライアントインターフェースとの共用も考慮しています(例:Razor Pagesブログのフロントエンドも同じ記事検索インターフェースを使用)。
- その他。
3. Goバージョンのブログソースコード
B站のUp主【码神之路】のビデオチュートリアルのタイトルにあるように「原生Go言語ブログ実戦チュートリアル、練習用プロジェクト実戦チュートリアル、フレームワーク不使用、わかりやすい」。重要なのは「原生」であることです。サイト管理者が実践してみたところ、Up主のルーティング関連の書き方は ASP.NET Core の Minimal APIs(最小API)と似ていることがわかりました。前者は主にWeb(MVC)を書き、後者はWeb APIを書きます。実際に使い慣れた技術と比較しながら学ぶことで理解が深まります。以下、Go版ブログのソースコードについて簡単に紹介します。
3.1 エントリ
main.go はプログラムのエントリファイルで、ASP.NET Core の Program.cs ファイルに相当します。ファイル名は変更可能ですが、コードの先頭が package main である必要があります。
全コードは以下の通り:
package main
import (
"log"
"net/http"
"dotnet9.com/goweb/common"
"dotnet9.com/goweb/router"
)
func init() {
// テンプレートロード:HTMLファイル(例:トップページの記事リスト、カテゴリ別記事リスト、ヘッダー、フッターなど)
common.LoadTemplate()
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
router.Router()
if err := server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
サービスがバインドするIPとポートはハードコードされていますが、設定ファイルに書き出すことも可能です。以下の ASP.NET Core 最小APIと似ていると思いませんか:
var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World!");
app.Run("http://localhost:3000");
router.Router() は簡易的なルーティングラッパー(以下にラップを示す)で、上記の最小API app.MapGet("/", () => "Hello World!"); とどれだけ似ているか、8点はあげられるでしょうか?:
Goの簡易ルーティングラッパー: router.go
package router
import (
"net/http"
"dotnet9.com/goweb/views"
"dotnet9.com/goweb/api"
)
func Router() {
http.HandleFunc("/", views.HTML.Index)
http.HandleFunc("/c/", views.HTML.Category)
http.HandleFunc("/p/", views.HTML.Detail)
http.HandleFunc("/login", views.HTML.Login)
http.HandleFunc("/api/v1/post", api.API.SaveAndUpdatePost)
http.Handle("/resource/", http.StripPrefix("/resource/", http.FileServer(http.Dir("public/resource/"))))
}
ルーティングのトップページのコードは以下の通り:
./views/index.go
package views
import (
"errors"
"log"
"net/http"
"strconv"
"dotnet9.com/goweb/common"
"dotnet9.com/goweb/service"
)
func (*HTMLApi) Index(w http.ResponseWriter, r *http.Request) {
// ここはビジネスロジック:記事リストを読み込み、テンプレートにバインド
}
3.n テンプレートバインディング
ORMなどの使用は飛ばして、テンプレートバインディングについて説明します。
以下はGoの記事リストテンプレート: ./template/layout/post-list.html
{{define "post-list"}}
<ul class="post-box">
{{range $index, $elem := .Posts}}
<li class="post-label">
<a href="/p/{{$elem.Slug}}"><h2>{{$elem.Title}}</h2></a>
<p>{{$elem.Description}}</p>
<div class="post-action">
<span>
<i class="iconfont icon-yonghu"></i>
{{$elem.Original}}
</span>
<span>
<i class="iconfont icon-wenjianjia"></i>
{{range $catIndex, $cat := $elem.Categories}}
<a href="/c/{{$cat.Slug}}">{{$cat.Name}}</a>
{{end}}
</span>
<span>
<i class="iconfont icon-riqi"></i>
{{$elem.CreationTime}}
</span>
<span>
<i class="iconfont icon-yanjing"></i>
{{$elem.ViewCount}}
</span>
</div>
</li>
{{end}}
</ul>
{{end}}
比較として、Razor Pages の記事リストテンプレートバインディング:
@page
@inject IOptionsSnapshot<SiteOptions> SiteOptions
@using Dotnet9.Web.ViewModel.Commons
@model IndexModel
@{
ViewData["Title"] = "ホーム";
}
<ul class="post-box">
@if (Model.BlogPosts?.Any() == false)
{
<span>データがありません</span>
}
else
{
@foreach (var blogPost in Model.BlogPosts!)
{
<li class="post-label">
<a href="@blogPost.CreationTime.ToString("/yyyy/dd")/@blogPost.Slug">
<h2>@blogPost.Title</h2>
</a>
<p>@blogPost.Description</p>
<div class="post-action">
<span>
<i class="iconfont icon-yonghu"></i>
@(blogPost.Original.IsNullOrWhiteSpace() ? SiteOptions.Value.Owner : blogPost.Original)
</span>
<span>
<i class="iconfont icon-wenjianjia"></i>
@foreach (var cat in blogPost.Categories)
{
<a href="/cat/@cat.Slug" title="@cat.Description">@cat.Name</a>
}
</span>
<span>
<i class="iconfont icon-riqi"></i>
@blogPost.CreationTime.ToString("yyyy-MM-dd")
</span>
<span>
<i class="iconfont icon-yanjing"></i>
@blogPost.ViewCount
</span>
</div>
</li>
}
}
</ul>
@await Html.PartialAsync("_PaginationPartial", new PaginationModel(Model.Current, Model.Pages, Model.Total, Model.PageSize, Model.PageCount))
コードはおおまかに見てください:
- Goのテンプレートバインディングは
{{.オブジェクト.フィールド}}を使用し、先頭のドットに注意。 - Razorの構文バインディングは
@Model.オブジェクト。
言語は似ています。ある技術スタックに慣れていれば、他の技術スタックも類推できます。
3.n+1 コメント
コメントはサードパーティインターフェース Valine を利用しています。将来的には自前で開発することを検討しています。
Valine - 高速・シンプル・効率的なバックエンド不要のコメントシステム。
特徴
- 高速
- 安全
- Emoji 😉
- バックエンド不要
- MarkDown 全構文サポート
- 軽量で使いやすい
- 記事の読了数カウント v1.2.0+
サイトでの使用例:

Valineコメントのバックエンド管理:

4. 今後の計画
Go、あるいは新しい技術を学ぶ際には、学ぶだけでなく、使う機会を探す必要があります。Goを使って自分が興味のあるプロジェクト、例えばシンプルなブログのフロントエンドを開発してみることをお勧めします。そうすることで、より意欲的に学習できるでしょう。最初はフレームワークを使わないネイティブ開発から始めてみるのも、言語の基本文法を理解するのに役立ちます。
ビジネス開発やイテレーションを迅速に行いたい場合には、フレームワークを検討してもよいでしょう。サイト管理者は最近 goframe に注目しています。
GoFrameは、モジュール化・高性能・エンタープライズ向けのGo基本開発フレームワークです。GoFrameは汎用性の高い基本開発フレームワークであり、Golang標準ライブラリの強化拡張版とも言えます。共通コアの基本開発コンポーネントを含み、実戦的、モジュール化、ドキュメント充実、豊富なモジュール、使いやすさ、汎用性の高さ、チーム志向が特徴です。Goを使用してビジネス型プロジェクト(小中規模から大規模まで)を開発したい場合、GoFrameは最適な選択です。Goのコンポーネントライブラリを開発したい場合、GoFrameはすぐに使える強力な基本コンポーネントライブラリを提供し、作業の効率を大幅に向上させます。チームリーダーであれば、GoFrameの豊富な資料・ドキュメント、詳細なコードコメント、活発なコミュニティメンバーが指導コストを大幅に削減し、チームの迅速な導入、言語転換、能力向上をサポートします。
GoFrame公式ドキュメント: https://goframe.org/pages/viewpage.action?pageId=1114119

今後はgoframeを使ってこのGoブログをリファクタリングする予定です。もちろん、その前に Razor Pages バージョンのブログを完成させて改良するのが先決です。バックエンドも含めて...
駄文終了(2時間かかりました)。時間をかけて学ぼうとすれば、学べないものはありません。不服なら一言: やるだけだ。