Перейти в веб-учебник

Go
Перейти в веб-учебник

Учебное пособие для начинающих веб-пользователей

Всем привет, меня зовут Се Вэй, я программист.

webПриложения — очень популярная область применения самых разных языков программирования.

ТакwebКакие знания включает в себя фоновое развитие?

  • Проектирование модели: проектирование модели реляционной базы данных
  • SQL, ОРМ
  • Спокойный дизайн API

дизайн модели

Разработка веб-бэкенда, как правило, ориентирована на бизнес, то есть разработка представляет собой прикладную сущность: например, она ориентирована на область электронной коммерции, такую ​​как поле данных, например, социальное поле и т. д.

В разных областях используются разные абстрактные модели.Электронная коммерция в основном нацелена на такие модели, как товары, магазины, заказы и логистика, а социальные сети нацелены в основном на такие модели, как люди, сообщения, группы и посты.

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

Его можно быстро применить к бизнес-сценариям.Только когда данные достигают определенной точки, возникает какое-то узкое место, например, слишком много данных и медленный запрос.В это время подбаза данных, подтаблица, режим ведущий-ведомый, и т. д. будут выбраны.

Разработка модели базы данных остается важной темой. Хорошая модель данных очень полезна для непрерывной итерации и расширения последующих требований.

Как спроектировать хорошую модель базы данных?

  • Следуйте некоторым парадигмам: например, знаменитым трем парадигмам проектирования баз данных.
  • Разрешить небольшую избыточность

В деталях это не что иное, как: 1. Структура таблицы базы данных 2. Дизайн полей БД, шрифтовой дизайн 3. Дизайн взаимосвязей таблиц данных: 1-к-1, 1-ко-многим, многие-ко-многим

1. дизайн таблицы базы данных

Имя таблицыЭто не о чем говорить, это можно назвать по смыслу знания, но я все же рекомендую использоватьdatabase+实体форма.

Например:beeQuick_productsПредставление: база данных:beeQuick,поверхность:products

Реальная сцена разработана: свежая платформа: таблица товаров в любви

2. дизайн поля базы данных

Полевой дизайн, шрифтовой дизайн

  • Количество полей: если полей слишком много, таблицу нужно разделить на более позднем этапе, если полей слишком мало, будут задействованы многотабличные операции, поэтому очень важно настроить масштаб. показатель: менее 12 полей.
  • Как оформить поля? : По абстрактным объектам, таким как система образования: информация об учениках, информация об учителях, роли и т. д., легко узнать, какие поля и типы полей требуются в таблице.
  • Если вы знаете реальную сцену, постарайтесь ограничить пространство, занимаемое полем, например: номер телефона 11 цифр, например: длина пароля не более 12 цифр

дизайн внешнего ключа

  • Внешний ключ изначально используется для обеспечения согласованности данных, но он не используется в реальных сценариях использования, а зависит от бизнес-оценки.Например, первичный ключ записи рассматривается как поле таблицы.

Отношения 1-к-1, 1-ко-многим, многие-ко-многим

  • 1 к 1: поле одной таблицы является первичным ключом другой таблицы.
type Order struct{
    base
    AccountId  int64
}
  • 1-ко-многим: поле одной таблицы представляет собой набор первичных ключей другой таблицы.
type Order struct {
	base       `xorm:"extends"`
	ProductIds []int `xorm:"blob"`
	Status     int
	AccountId  int64
	Account    Account `xorm:"-"`
	Total      float64
}
  • «Многие ко многим»: используйте третью таблицу для поддержания отношений «многие ко многим».
type Shop2Tags struct {
	TagsId int64 `xorm:"index"`
	ShopId int64 `xorm:"index"`
}

ORM

Идея ORM заключается в отображении объектов в таблицы базы данных.

В конкретном использовании:

1. В соответствии с сопоставлением между языком программирования ORM и типом данных базы данных разумно определите поля и типы полей. 2. определить имя таблицы 3. Создание таблицы базы данных, удаление и т. д.

Более популярные библиотеки ORM в Go: GORM и XORM, правила определения таблиц базы данных, в основном начинаются с полей структуры и тегов.

Поле соответствует имени столбца в таблице базы данных, а тип, тип ограничения, индекс и т. д. указываются в теге. Если тег не определен, используется форма по умолчанию. Для конкретного типа языка программирования и соответствующей связи в базе данных вам необходимо проверить конкретный документ ORM.

// XORM
type Account struct {
	base     `xorm:"extends"`
	Phone    string    `xorm:"varchar(11) notnull unique 'phone'" json:"phone"`
	Password string    `xorm:"varchar(128)" json:"password"`
	Token    string    `xorm:"varchar(128) 'token'" json:"token"`
	Avatar   string    `xorm:"varchar(128) 'avatar'" json:"avatar"`
	Gender   string    `xorm:"varchar(1) 'gender'" json:"gender"`
	Birthday time.Time `json:"birthday"`

	Points      int       `json:"points"`
	VipMemberID uint      `xorm:"index"`
	VipMember   VipMember `xorm:"-"`
	VipTime     time.Time `json:"vip_time"`
}

// GORM
type Account struct {
	gorm.Model
	LevelID  uint
	Phone    string    `gorm:"type:varchar" json:"phone"`
	Avatar   string    `gorm:"type:varchar" json:"avatar"`
	Name     string    `gorm:"type:varchar" json:"name"`
	Gender   int       `gorm:"type:integer" json:"gender"` // 0 男 1 女
	Birthday time.Time `gorm:"type:timestamp with time zone" json:"birthday"`
	Points   sql.NullFloat64
}

Другая конкретная операция: Завершите добавление, удаление, изменение и запрос базы данных.Конкретная идея по-прежнему состоит в том, чтобы управлять объектом структуры и завершать операцию SQL базы данных.

Конечно, в соответствии с дизайном каждой модели я обычно определяю сериализованную структуру, а метод сериализации реальной модели заключается в возврате определенной сериализованной структуры.

Конкретно:

// 定义一个具体的序列化结构体,注意名称的命名,一致性
type AccountSerializer struct {
	ID        uint                `json:"id"`
	CreatedAt time.Time           `json:"created_at"`
	UpdatedAt time.Time           `json:"updated_at"`
	Phone     string              `json:"phone"`
	Password  string              `json:"-"`
	Token     string              `json:"token"`
	Avatar    string              `json:"avatar"`
	Gender    string              `json:"gender"`
	Age       int                 `json:"age"`
	Points    int                 `json:"points"`
	VipMember VipMemberSerializer `json:"vip_member"`
	VipTime   time.Time           `json:"vip_time"`
}

// 具体的模型的序列化方法返回定义的序列化结构体
func (a Account) Serializer() AccountSerializer {

	gender := func() string {
		if a.Gender == "0" {
			return "男"
		}
		if a.Gender == "1" {
			return "女"
		}
		return a.Gender
	}

	age := func() int {
		if a.Birthday.IsZero() {
			return 0
		}
		nowYear, _, _ := time.Now().Date()
		year, _, _ := a.Birthday.Date()
		if a.Birthday.After(time.Now()) {
			return 0
		}
		return nowYear - year
	}

	return AccountSerializer{
		ID:        a.ID,
		CreatedAt: a.CreatedAt.Truncate(time.Minute),
		UpdatedAt: a.UpdatedAt.Truncate(time.Minute),
		Phone:     a.Phone,
		Password:  a.Password,
		Token:     a.Token,
		Avatar:    a.Avatar,
		Points:    a.Points,
		Age:       age(),
		Gender:    gender(),
		VipTime:   a.VipTime.Truncate(time.Minute),
		VipMember: a.VipMember.Serializer(),
	}
}

проектирование структуры проекта

├── cmd
├── configs
├── deployments
├── model
│   ├── v1
│   └── v2
├── pkg
│   ├── database.v1
│   ├── error.v1
│   ├── log.v1
│   ├── middleware
│   └── router.v1
├── src
│   ├── account
│   ├── activity
│   ├── brand
│   ├── exchange_coupons
│   ├── make_param
│   ├── make_response
│   ├── order
│   ├── product
│   ├── province
│   ├── rule
│   ├── shop
│   ├── tags
│   ├── unit
│   └── vip_member
└── main.go
└── Makefile

Зачем организовывать структуру проекта? Позвольте задать вам вопрос: в грязном доме быстрее найти предмет, или в чистом и опрятном доме быстрее найти предмет?

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

  • cmd для командной строки
  • конфиги для конфигурационных файлов
  • сценарий развертывания развертываний, Dockerfile
  • модель для модельного дизайна
  • pkg для вспомогательных библиотек
  • Основной логический слой src, этот слой, мой общий метод организации: разделить разные папки в соответствии с объектами, разработанными моделью, такими как указанные выше учетные записи, действия, бренды, купоны и т. д., и конкретной логикой обработки, я разделяю ее вот так:
├── assistance.go // 辅助函数,如果重复使用的辅助函数,会提取到 pkg 层,或者 utils 层
├── controller.go // 核心逻辑处理层
├── param.go // 请求参数层:包括参数校验
├── response.go // 响应信息
└── router.go // 路由

  • Вход в функцию main.go
  • Сборка проекта Makefile

Конечно, вы также можете обратиться к:GitHub.com/go wave-beach…

выбор кадра

  • gin
  • iris
  • echo ...

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

Разработка API в спокойном стиле

  • дизайн маршрутизации
  • проверка параметров
  • ответная информация

дизайн маршрутизации

Хотя в Интернете есть много руководств по дизайну API в стиле Restful, я все же рекомендую вам ознакомиться с приведенным ниже введением.

Доменное имя (хост)

Рекомендуется использовать выделенное доменное имя API, например:https://api.example.com

Но на самом деле поместите его прямо под хостом:https://example.com/api

Версия

Требования будут продолжать меняться, и интерфейс будет продолжать меняться, поэтому лучше всего привести версию к API: например:https://example.com/api/v1, что указывает на первую версию.

Некоторые из них содержат информацию о версии в заголовке, что не рекомендуется и не интуитивно понятно.

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

метод запроса

  • POST: создайте ресурс на сервере, соответствующая операция базы данных: создать
  • ИСПРАВЛЕНИЕ: Обновите ресурсы на сервере, соответствующая операция базы данных: обновление
  • УДАЛИТЬ: удалить ресурс на сервере, соответствующая операция базы данных: удалить
  • GET: получить ресурсы на сервере, соответствующая операция базы данных: выбрать
  • Другое: обычно не используется

дизайн маршрутизации

Общая рекомендация:版本 + 实体(名词)форма:

Например: в вышеуказанной структуре проектаorderПредставляет сущность заказа.

Итак, как устроен маршрут?

POST /api/v1/order
PATCH /api/v1/order/{order_id:int}
DELETE /api/v1/order/{order_id:int}
GET /api/v1/orders

Хотя есть и другие способы, я все же рекомендую необходимость последовательности.

Например, интерфейс активности:

POST /api/v1/activity
PATCH /api/v1/activity/{activity_id:int}
DELETE /api/v1/activity/{activity_id:int}
GET /api/v1/activities

Быть последовательным.

проверка параметров

Проектирование маршрутизации является важным знанием, включающим в себя: Проверка параметров

  • например, проверка типа параметра
  • Например, проверка длины параметра
  • Например, указание проверки опции

Конкретная структура проекта интерфейса каждой сущности в приведенном выше примере проекта выглядит следующим образом:

├── assistance.go
├── controller.go
├── param.go
├── response.go
└── router.go
  • Ядром param.go является организация определения параметров в интерфейсе и проверка параметров.

Существует два способа проверки параметров: 1: использовать метод структуры для реализации логики проверки; 2: использовать тег в структуре для определения проверки.

type RegisterParam struct {
	Phone    string `json:"phone"`
	Password string `json:"password"`
}

func (param RegisterParam) suitable() (bool, error) {
	if param.Password == "" || len(param.Phone) != 11 {
		return false, fmt.Errorf("password should not be nil or the length of phone is not 11")
	}
	if unicode.IsNumber(rune(param.Password[0])) {
		return false, fmt.Errorf("password should start with number")
	}
	return true, nil
}

Таким образом, настройте структуру параметров и метод структуры для проверки параметров.

Недостатком является то, что нужно написать много кода и рассмотреть множество сценариев.

Другой способ: используйте тег структуры для достижения.

type RegisterParam struct {
	Phone    string `form:"phone" json:"phone" validate:"required,len=11"`
	Password string `form:"password" json:"password"`
}

func (r RegisterParam) Valid() error {
    return validator.New().Struct(r)
}
 

Последний использует:перейти на doc.org/GOP кг.in/go…Библиотека проверки, проверка параметров веб-фреймворка gin также использует эту схему.

Существует множество сценариев, и пользователям нужно только обратить внимание на значение тега Tag в структуре.

  • Логарифмический параметр: Направление проверки: 1. Является ли оно 0. 2. Максимальное значение, минимальное значение (например, операция перелистывания страниц, отображение каждой страницы) 3. Интервал, больше, меньше и т. д.
  • Для строковых параметров: направление проверки: 1. Является ли оно нулевым, 2. Перечисление или конкретное значение: eq="a"|eq="b" и т. д.
  • Конкретные сценарии: такие как почтовые ящики, цвета, Base64, hex и т. д.

Наиболее часто используются числовые и строковые типы.

ответная информация

Фронтенд и бэкенд разделены, а самый популярный формат обмена данными — json. Хотя он поддерживает разнообразную ответную информацию, такую ​​как html, xml, string, json и т. д.

Для создания API в стиле Restful я рекомендую только json, который удобен для вызова разработчиками внешнего интерфейса или клиентской стороны.

После определения, что формат обмена данными json, какие еще заботы нужны?

  • код состояния
  • конкретная информация об ответе
{
    "code": 200,
    "data": {
        "id": 1,
        "created_at": "2019-06-19T23:14:11+08:00",
        "updated_at": "2019-06-20T10:40:09+08:00",
        "status": "已付款",
        "phone": "18717711717",
        "account_id": 1,
        "total": 9.6,
        "product_ids": [
            2,
            3
        ]
    }
} 

Рекомендуется использовать приведенный выше формат единообразно: код используется для представления кода состояния, а данные используются для представления конкретной информации об ответе.

В случае ошибки рекомендуется следующий формат:

{
    "code": 404,
    "detail": "/v1/ordeda",
    "error": "no route /v1/orderda"
}

Также существует множество типов кодов состояния:

  • 1XX: запрос получен
  • 2xx: успех
  • 3XX: перенаправление
  • 4XX: ошибка клиента
  • 5XX: ошибка сервера

Выберите код состояния в соответствии с конкретным сценарием.

Реальное применение: определить пакет err в пакете pkg и реализовать метод Error.

type ErrorV1 struct {
	Detail  string `json:"detail"`
	Message string `json:"message"`
	Code    int    `json:"code"`
}

type ErrorV1s []ErrorV1

func (e ErrorV1) Error() string {
	return fmt.Sprintf("Detail: %s, Message: %s, Code: %d", e.Detail, e.Message, e.Code)
}

Определите некоторые распространенные сообщения об ошибках и коды ошибок:

var (

	// database
	ErrorDatabase       = ErrorV1{Code: 400, Detail: "数据库错误", Message: "database error"}
	ErrorRecordNotFound = ErrorV1{Code: 400, Detail: "记录不存在", Message: "record not found"}

	// body
	ErrorBodyJson   = ErrorV1{Code: 400, Detail: "请求消息体失败", Message: "read json body fail"}
	ErrorBodyIsNull = ErrorV1{Code: 400, Detail: "参数为空", Message: "body is null"}
)

разное

  • Документация по API: документация по swagger более популярна. Документация — важный способ для других разработчиков понять интерфейс. Учитывая стоимость связи, документация по API имеет важное значение.
  • Журналы: журналы необходимы разработчикам для просмотра проблем. Бизнес-объем не сложен. Журналы можно записывать в файлы и сохранять. Для более сложных сценариев можно выбрать ELK.
  • Dockerfile: веб-приложение, конечно, очень подходящее для развертывания на хосте в виде контейнера.
  • Makefile: команды сборки проекта, включая некоторые тесты, сборки, запуск автозапуска и т. д.

Перейти в веб-дорожную карту