Джин (3): с шаблоном tmpl

Go Gin

больше статейСумасшедшая точка ->ISLAND

Предыдущее исследование уже имело предварительное представление и понимание Джина.routerПростое использование Gin также было освоено, поэтому сегодня мы будем использовать Gin для рендеринга нашегоhtmlстраница.

Добавить шаблон

Мы все еще вносим изменения в проект из предыдущей главы.

Сначала создайте новыйtemplatesПапка, используемая для хранения наших файлов шаблонов, вновь созданных в папкеindex.tmpl. И пишем наш шаблон.

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Gin Hello</title>
</head>
<body>
<main>{{ .title }}</main>
</body>
</html>

намекатьВ GoLand пока нет подсветки синтаксиса для tmpl, мы можем добавить файл суффикса .tmpl в шаблон шаблона go. Методы, как показано ниже:File-settings-Editor-File Types. (Или мы можем напрямую использовать *.gohtml в качестве шаблона), как показано на рисунке:

添加模板

мы можем пройтиLoadHTMLGlobиLoadHTMLFilesДва способа загрузить наш шаблон. вLoadHTMLGlobметод может загружать все шаблоны в каталоге иLoadHTMLFilesБудет загружен только один файл, и его параметры являются параметрами переменной длины, и нам нужно вручную заполнить файлы шаблона один за другим. Здесь мы используемLoadHTMLGlobметод.

	router.LoadHTMLGlob("templates/*")

На этом этапе нам нужно изменить наш/Маршрутизация вместо того, чтобы возвращать строку, возвращает шаблон нашей страницы.

существуетhandlerКитайско-СингапурскийindexHandler.go, используемый для обработки нашего/маршрутизация.

func Index(context *gin.Context) {
	context.HTML(http.StatusOK, "index.tmpl", gin.H{
		"title": "hello gin " + strings.ToLower(context.Request.Method) + " method",
	})
}

В настоящее время при посещении нашей страницы по-прежнемуhello gin get method, но это отличается от строки, которую мы вернули ранее.

Открытым浏览器-NetworkВы можете увидеть разницу между этими двумя страницами, одна из нихtextодинhtml

После написания конкретных функций нам нужно преобразовать наши модульные тесты, так как исходные модульные тесты для новой логики интерфейса больше не применимы.

Переработаны модульные тесты.

func TestIndexHtml(t *testing.T) {
	router := initRouter.SetupRouter()
	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodGet, "/", nil)
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
}

При выполнении модульного тестирования я обнаружил, что сообщалось об ошибке, и причина ошибки заключалась в том, что ее не удалось найти.html.

--- FAIL: TestIndexGetRouter (0.00s)
panic: html/template: pattern matches no files: `templates/*` [recovered]
	panic: html/template: pattern matches no files: `templates/*`

В этот момент я чувствую себя очень странно, почему веб-страница доступна очень хорошо, но недоступна в тесте?

Я проверил много информации и не смог найти причину.Многие решения заключаются в том, чтобыtemplatesНаписанный как полный путь, это явно не очень хорошее решение. Официальное введение в модульное тестирование оставляет желать лучшего.

Здесь я представляю метод:

Нам нужно изменить метод, оценивая различные режимы (debug,release,test) для загрузки файлов по разным путямtemplates.

initRouter.go

// 省略部分代码	
    if mode := gin.Mode(); mode == gin.TestMode {
		router.LoadHTMLGlob("./../templates/*")
	} else {
		router.LoadHTMLGlob("templates/*")
	}

При этом необходимо модифицироватьtest, мы будем писатьinitметод, здесьinitметод подобенjavaсерединаJunitсередина@Before

package test

import (
	"GinHello/initRouter"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"net/http"
	"net/http/httptest"
	"testing"
)

var router *gin.Engine

func init() {
	gin.SetMode(gin.TestMode)
	router = initRouter.SetupRouter()
}

func TestIndexHtml(t *testing.T) {
	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodGet, "/", nil)
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	assert.Contains(t,w.Body.String(),"hello gin get method","返回的HTML页面中应该包含 hello gin get method")
}

Это завершает модульные тесты и облегчает будущие функциональные изменения.

Добавьте статические ресурсы

Когда веб-страница может отображаться нормально, мы можем добавить некоторые статические ресурсы, чтобы сделать нашу страницу более красивой. я выбрал здесьBootstrap 4Как фреймворк пользовательского интерфейса.Bootstrap 4 скачать

также представитьJqueryиPopper.

мы создаем новыйstaticsпапка, мы будемBootstrapраспаковать, будетjsиcssскопировать вstaticsПод содержанием.

в нашемinitRouter, добавьте статические ресурсы.

	router.Static("/statics","./statics")

новыйheader.tmpl

{{ define "header" }}
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="#">Gin Hello</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
                aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item active">
                    <a class="nav-link" href="#">主页 <span class="sr-only">(current)</span></a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">文章列表</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link " href="#" tabindex="-1" aria-disabled="true">关于</a>
                </li>
            </ul>
            <form class="form-inline my-2 my-lg-0">
                <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
                <button class="btn btn-outline-success my-2 my-sm-0" type="submit">搜索</button>
            </form>
            <ul class="navbar-nav ">
                <li class="nav-item">
                    <a class="nav-link" href="#">登录</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">注册</a>
                </li>
            </ul>
        </div>
    </nav>
{{end}}

и в нашемindex.tmplдобавить

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="/statics/css/bootstrap.min.css">
    <link rel="stylesheet" href="/statics/css/bootstrap-grid.min.css">
    <link rel="stylesheet" href="/statics/css/bootstrap-reboot.min.css">
    <script src="/statics/js/jquery.min.js" rel="script"></script>
    <script src="/statics/js/Popper.js" rel="script"></script>
    <script rel="script" src="/statics/js/bootstrap.bundle.js"></script>
    <title>Gin Hello</title>
</head>
<body>
<header>
    {{template "header"}}
</header>
<main>
    {{ .title }}
</main>
</body>

В этот момент запустите наш веб-сайт, и появится следующий стиль.

Добавить фавикон

Все готово, я должен только одинicon.

В настоящее время на веб-сайте по-прежнему отсутствует значок веб-сайта, и значок веб-сайта также устанавливается функцией, заданной Джином. мы будем.icoОбраз помещается в корневой каталог проекта, а затем вinitRouterв настройках.

	router.StaticFile("/favicon.ico","./favicon.ico")

Запустите наш веб-сайт еще раз, и вы обнаружите, что значок набора появляется в верхнем левом углу веб-сайта.

Код для этой главы

Github