Я пишу проект Java SpringBoot на переднем конце.



Предисловие
Давайте веселиться, давайте создавать проблемы, не высмеивайте сторону C! Не рекомендуется использовать службу Node в качестве службы стороны C. В конце концов, это однопоточный многозадачный механизм. Эта особенность определяет миссию языка Javascript с самого начала его создания - Java >>>[Script]. Я не буду здесь много объяснять. Просто посмотрите историю JavaScript и вы все поймете. Это также определяет его миссию "Он не может быть многопоточным и многозадачным, как серверный язык. Он может выдерживать небольшое количество посещений пользователей. Но как только он выдержит большое количество посещений и высокий уровень параллелизма, это будет круто~"
Так почему же нам все еще нужно писать сервисы Node? Основная причина в том, что это удобно и быстро.Для небольших проектов строительство может быть завершено быстро, а стоимость разработки невелика. Во-вторых, следующие выгоды достигаются в основном за счет написания Nest:
  • Изучите синтаксис декоратора и почувствуйте его простоту и красоту;
  • Изучите новую среду разработки самостоятельно, почувствуйте преимущества и недостатки различных платформ и заложите основу для будущей разработки и выбора;
  • Почувствуйте сложность устранения неполадок на стороне сервера и найдите вдохновение для дизайна внешнего интерфейса.
В этой статье в основном используются NestJs + Sequelize + MySQL для выполнения основной операции. Она покажет вам базовую конструкцию Node-сервера. Вы также можете взглянуть на базовую структуру проекта Java SpringBoot. Они действительно очень похожи. Если не веришь, спроси про разработку серверов одноклассник.


Шаг первый: запустить проект

При выборе сервера я раньше использовал Egg.js, поэтому в этот раз его выбирать не буду. Во-вторых, Egg также унаследовал основу разработки Koa, а Express также является инновационным продуктом, основанным на Koa. Они должны быть похожими, поэтому я не выбираю Koa и Express.
Поэтому я хочу попробовать Nest.js, чтобы увидеть, что синтаксис такой же, как у Java.Кроме того, ранее я разработал проект Java + SpringBoot.Конечно, более старый SSH 2.0 также был построен с нуля, то есть: Spring2.0 + Struts2+Hibernate3.2, я думаю, что начать работу будет легко, и я напишу об этом ретроспективно.
Справочная документация:
  •  https://www.geeksforgeeks.org/best-nodejs-frameworks-for-app-development/ 
  •  https://anywhere.epam.com/business/best-node-js-frameworks 
Позвольте мне рассказать вам свои мысли.Во-первых, мы только начали, и, вероятно, будет много неясных ловушек.Давайте сначала сделаем это простым, а потом продолжим углублять его. Поскольку мы хотим развивать серверную часть, если мы хотим это сделать, делайте больше. Давайте все попробуем и получим удовольствие. Мы планируем использовать Nest в качестве внешней среды и Graphql в качестве промежуточного уровня обработки. В качестве базовой базы данных мы используем традиционную MySQL, которая относительно стабильна, надежна и относительно привычна. Я не буду использовать здесь ничего нового. В конце концов, база данных — это краеугольный камень всего.
Давайте поговорим о наших конкретных этапах реализации:
  1. [Обязательно] База данных отсутствует, запрос интерфейса выполнен и его можно запускать;
  2. [Обязательно] Создайте базовую базу данных MySQL и получите доступ к библиотеке @nestjs/sequelize для выполнения функций добавления, удаления, изменения и запроса: CRUD
  3. [Необязательно] Мы планируем использовать Graphql для обработки запросов API для получения точных запросов данных. Это популярно уже давно, и в будущем мы планируем использовать его непосредственно в бизнесе.
  4. [Необязательно] Подключитесь к Swagger, чтобы автоматически генерировать документы API и быстро проводить совместную отладку и тестирование интерфейсных и серверных сервисов. Swagger — это инструмент с открытым исходным кодом для проектирования, создания, документирования и использования веб-сервисов RESTful.
  5. [Необязательно] Запрос интерфейса, обработка оптимизации базы данных
    1. Разгрузка запросов, блокировка записи в базу данных и параллельная обработка процессов
    2. Добавьте промежуточное программное обеспечение для единообразной обработки запросов и ответов, выполнения обработки аутентификации, перехвата запросов и других операций.
    3. Разделенное резервное копирование базы данных, обработка аварийного восстановления базы данных, разделенная на: первичную, резервную, аварийную.
    4. Чтение и запись в базе данных разделены, данные записываются дважды, установлен механизм кэширования базы данных, для обработки используется redis.
Вы также можете добавить дополнительные точки оптимизации, и мы обсудим их вместе~ Если вам интересно, вы можете помочь добавить код~
Определившись с общим направлением, мы приступили к организации. Давайте не будем зацикливаться на одном шаге, иначе чем больше вещей мы добавим, тем больше хаоса мы получим. Вишенку на торт мы можем добавить позже, и мы должны расставить приоритеты в выполнении основных функций. Официальный сайт Nest.js: https://docs.nestjs.com/ Без лишних слов, давайте перейдем непосредственно к деталям.
  
  
  
  
  
# 进入文件夹目录cd full-stack-demo/packages# 安装脚手架npm i -g @nestjs/cli# 创建基础项目nest new node-server-demo # 进入项目 cd new node-server-demo # 运行项目测试npm run start:dev
Давайте удалим кое-что лишнее, начнем с простого, а потом сложного, не запутайтесь. Далее я напишу простой пример, чтобы почувствовать эту структуру, а затем опубликую полный код позже. Без лишних слов, давайте начнем! Структура каталогов после настройки:
  • common — класс общедоступного метода
  • config — файл класса конфигурации
  • контроллер — контроллер, используемый для обработки различных запросов, инициированных внешним интерфейсом
  • service - класс сервиса, используемый для обработки логики взаимодействия с базой данных
  • dto — DTO (объект передачи данных) можно использовать для проверки входных данных и ограничения передаваемых полей или форматов.
  • сущности — класс сущностей, используемый для описания информации об атрибутах, связанных с объектом.
  • модуль — модуль, используемый для регистрации всех классов обслуживания и классов контроллеров, аналогичный bean-компонентам в Spring.

Они не полностью эквивалентны. Два механизма реализации различны. Это просто, чтобы помочь всем понять.

  • main.ts — входная запись запуска

  • типы — типы объявлений, связанные с машинописным текстом

 Я просто пишу демо, поэтому мне не придется писать комментарии, если я потороплюсь. Я чувствую, что могу понять это с первого взгляда, и это очень соответствует методу написания Java SpringBoot. Часть кода Показано:
  • контроллерконтроллер
  
  
  
  
  
// packages/node-server-demo/src/controller/user/index.tsimport { Controller, Get, Query } from '@nestjs/common';import UserServices from '@/service/user';import { GetUserDto, GetUserInfoDto } from '@/dto/user';
@Controller('user')export class UserController { constructor(private readonly userService: UserServices) {}
// Get 请求 user/name?name=bricechou @Get('name') async findByName(@Query() getUserDto: GetUserDto) { return this.userService.read.findByName(getUserDto.name); } // Get 请求 user/info?id=123 @Get('info') async findById(@Query() getUserInfoDto: GetUserInfoDto) { const user = await this.userService.read.findById(getUserInfoDto.id); return { gender: user.gender, job: user.job }; }}
// packages/node-server-demo/src/controller/log/add.tsimport { Controller, Post, Body } from '@nestjs/common';import { AddLogDto } from '@/dto/log';import LogServices from '@/service/log';
@Controller('log')export class CreateLogController { constructor(private readonly logServices: LogServices) {}
// post('/log/add') @Post('add') create(@Body() createLogDto: AddLogDto) { return this.logServices.create.create(createLogDto); }}

  • Передача данныхОбъект передачи данных
  
  
  
  
  
// packages/node-server-demo/src/dto/user.tsexport class CreateUserDto {  name: string;  age: number;  gender: string;  job: string;}
// 可以分开写,也可以合并export class GetUserDto { id?: number; name: string;}
// 可以分开写,也可以合并export class GetUserInfoDto { id: number;}

  • класс обработки взаимодействия с базой данных службы
  
  
  
  
  
// packages/node-server-demo/src/service/user/read.tsimport { Injectable } from '@nestjs/common';import { User } from '@/entities/User';
@Injectable()export class ReadUserService { constructor() {}
async findByName(name: string): Promise<User> { // 可以处理判空,从数据库读取/写入数据,可能会被多个 controller 进行调用 console.info('ReadUserService findByName > ', name); return Promise.resolve({ id: 1, name, job: '程序员', gender: 1, age: 18 }); }
async findById(id: number): Promise<User> { console.info('ReadUserService findById > ', id); return Promise.resolve({ id: 1, name: 'BriceChou', job: '程序员', gender: 1, age: 18, }); }}

  • модуль регистрация модуля, класс обслуживания/класс управления
  
  
  
  
  
// packages/node-server-demo/src/module/user.tsimport { Module } from '@nestjs/common';import UserService, { ReadUserService } from '@/service/user';import { UserController } from '@/controller/user';
@Module({ providers: [UserService, ReadUserService], controllers: [UserController],})export class UserModule {}

// packages/node-server-demo/src/module/index.ts 根模块注入import { Module } from '@nestjs/common';import { UserModule } from './user';import { LogModule } from './log';
@Module({ imports: [ UserModule, LogModule, ],})export class AppModule {}
  • main.js запускает все зарегистрированные классы
  
  
  
  
  
// packages/node-server-demo/src/main.tsimport { AppModule } from '@/module';import { NestFactory } from '@nestjs/core';import { NestExpressApplication } from '@nestjs/platform-express';
async function bootstrap() { const app = await NestFactory.create<NestExpressApplication>(AppModule); // 监听端口 3000 await app.listen(3000);}
bootstrap();
Таким образом запускается автономный сервер.Мы можем использовать Post Woman [ https://hoppscotch.io/ ], чтобы сделать запрос и увидеть эффект возврата.
 Консоль также получила журналы. Эти запросы журналов можно позже сохранить в виде файлов .log, чтобы журналы запросов также были доступны, отлично! Далее начинаем подключаться к базе данных, чтобы не пришлось играть в грязь на одной машине~


Шаг 2. Настройте MySQL

Установка MySQL на самом деле очень проста. Мой компьютер — Mac, поэтому все снимки экрана ниже основаны на Mac. Сначала загрузите соответствующую базу данных.
Адрес загрузки: https://dev.mysql.com/downloads/mysql/ Что касается других систем, вы можете найти руководства в Интернете. Это, вероятно, довольно распространено, поэтому я не буду повторять руководство.
  • Примечание. Вы должны установить пароль для установленной базы данных, а также у вас должен быть пароль для подключения к базе данных, в противном случае соединение с базой данных не удастся.
  • Для MySQL нам нужно только установить базу данных.Если вы знакомы с инструкциями, вы можете просто управлять ею прямо из командной строки.
  • Если вы с ним не знакомы, скачайте графический инструмент управления.
Официальная консоль MySQL https://dev.mysql.com/downloads/workbench/ 
Windows также может использовать https://www.heidisql.com/download.php?download=installer . 
PS: При установке Workbench я обнаружил, что требуется MacOS 13 или выше, а на моем компьютере установлена ​​MacOS 12.
白白下载,所以只能 https://downloads.mysql.com/archives/workbench/ 从归档里面找低版本 8.0.31。对于数据库服务也有版本要求,大家按照自己电脑版本,选择支持的版本即可。 https://downloads.mysql.com/archives/community/ 。我这边选择的是默认最新版本:8.0.34,下载好直接安装,一路 Next 到底,记住自己输入的 Root 密码!!!
确认好当前数据库是否已经运行起来了,启动 Workbench 查看状态。
1.创建数据库
 数据库存在字符集选择,不同的字符集和校验规则,会对存储数据产生影响,所以大家可以自行查询,按照自己存储数据原则选择,我这里默认选最广泛的。 确认好,就选择右下角的应用按钮。
2.创建表和属性
 选项解答:
  • PRIMARY KEY 是表中的一个或多个列的组合,它用于唯一标识表中的每一行。
  • Not NULL 和 Unique 就不解释,就是直译的那个意思。
  • GENERATED 生成列是表中的一种特殊类型的列,它的值不是从插入语句中获取的,而是根据其他列的值通过一个表达式或函数生成的。
  
  
  
  
  
CREATE TABLE people (    first_name VARCHAR(100),    last_name VARCHAR(100),    full_name VARCHAR(200) AS (CONCAT(first_name, ' ', last_name)));
  • UNS IGNED 这个数值类型就只能存储正数(包括零),不会存储负数。
  • ZEROFILL 将数值类型的字段的前面填充零,他会自动使字段变为 UNSIGNED,直到该字段达到声明的长度,如: 00007
  • BINARY 用于存储二进制字符串,如声明一个字段为 BINARY(5),那么存储在这个字段中的字符串都将被处理为长度为 5 的二进制字符串。
如尝试存储一个长度为 3 的字符串,那么它将在右侧用两个空字节填充。
如果你尝试存储一个长度为 6 的字符串,那么它将被截断为长度为 5
主要用途是存储那些需要按字节进行比较的数据,例如加密哈希值
  • 此外也可顺手创建一个索引,方便快速查找。
  
  
  
  
  
CREATE TABLE `rrweb`.`test_sys_req_log` (  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,  `content` TEXT NOT NULL,  `l_level` INT UNSIGNED NOT NULL,  `l_category` VARCHAR(255) NOT NULL,  `l_created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,  `l_updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,  PRIMARY KEY (`id`),  UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE,  INDEX `table_index` (`l_level` ASC, `l_category` ASC, `l_time` ASC) VISIBLE);
3.连接数据库
由于目前 node-oracledb 官方尚未提供针对 Apple Silicon 架构的预编译二进制文件。导致我们无法在 Mac M1 芯片上使用 TypeORM 链接数据库操作,它目前只支持 Mac x86 芯片。哎~折腾老半天,查阅各种文档,居然有这个坑,没关系我们换个方式打开。
我们不得不放弃,从而选用 https://docs.nestjs.com/techniques/database#sequelize-integration 哐哐哐~一顿操作猛如虎,盘它!
  • 安装 Sequelize
  
  
  
  
  
# 安装连接库npm install --save @nestjs/sequelize sequelize sequelize-typescript mysql2# 安装 typenpm install --save-dev @types/sequelize
  • 配置数据库基础信息
  
  
  
  
  
// packages/node-server-demo/src/module/index.tsimport { Module } from '@nestjs/common';import { UserModule } from './user';import { LogModule } from './log';import { Log } from '@/entities/Log';import { SequelizeModule } from '@nestjs/sequelize';
@Module({ imports: [ SequelizeModule.forRoot({ dialect: 'mysql', // 按数据库实际配置 host: '127.0.0.1', // 按数据库实际配置 port: 3306, // 按数据库实际配置 username: 'root', // 按数据库实际配置 password: 'hello', // 按数据库实际配置 database: 'world', synchronize: true, models: [Log], autoLoadModels: true, }), LogModule, UserModule, ],})export class AppModule {}

  • 实体与数据库一一映射处理
  
  
  
  
  
import { getNow } from '@/common/date';import {  Model,  Table,  Column,  PrimaryKey,  DataType,} from 'sequelize-typescript';
@Table({ tableName: 'test_sys_req_log' })export class Log extends Model<Log> { @PrimaryKey @Column({ type: DataType.INTEGER, autoIncrement: true, field: 'id', }) id: number;
@Column({ field: 'content', type: DataType.TEXT }) content: string;
@Column({ field: 'l_level', type: DataType.INTEGER }) level: number; // 3严重,2危险,1轻微
@Column({ field: 'l_category' }) category: string; // 模块分类/来源分类
@Column({ field: 'l_created_at', type: DataType.NOW, defaultValue: getNow(), }) createdAt: number;
@Column({ field: 'l_updated_at', type: DataType.NOW, defaultValue: getNow(), }) updatedAt: number;}

  • module 注册实体
  
  
  
  
  
// packages/node-server-demo/src/module/log.tsimport { Module } from '@nestjs/common';import { SequelizeModule } from '@nestjs/sequelize';import { Log } from '@/entities/Log';import LogServices, {  CreateLogService,  UpdateLogService,  DeleteLogService,  ReadLogService,} from '@/service/log';import {  CreateLogController,  RemoveLogController,  UpdateLogController,} from '@/controller/log';
@Module({ imports: [SequelizeModule.forFeature([Log])], providers: [ LogServices, CreateLogService, UpdateLogService, DeleteLogService, ReadLogService, ], controllers: [CreateLogController, RemoveLogController, UpdateLogController],})export class LogModule {}

  • service 操作数据库处理数据
  
  
  
  
  
import { Log } from '@/entities/Log';import { Injectable } from '@nestjs/common';import { AddLogDto } from '@/dto/log';import { InjectModel } from '@nestjs/sequelize';import { ResponseStatus } from '@/types/BaseResponse';import { getErrRes, getSucVoidRes } from '@/common/response';
@Injectable()export class CreateLogService { constructor( @InjectModel(Log) private logModel: typeof Log,) {}
async create(createLogDto: AddLogDto): Promise<ResponseStatus<null>> { console.info('CreateLogService create > ', createLogDto); const { level = 1, content = '', category = 'INFO' } = createLogDto || {}; const str = content.trim(); if (!str) { return getErrRes(500, '日志内容为空'); } const item = { level, category, // Tips: 为防止外部数据进行数据注入,我们可以对内容进行 encode 处理。 // content: encodeURIComponent(str), content: str, }; await this.logModel.create(item); return getSucVoidRes(); }}
一路操作猛如虎,回头一看嘿嘿嘿~终于,我们收到了来自外界的第一条数据!hello world!
 连接及创建数据成功! 此时已经完成基础功能啦~


第三步:实现CRUD基础功能

剩下的内容,其实大家可以自行脑补了,就是调用数据库的操作逻辑。先说说什么是 CRUD
  • C create 创建
  • R read 读取
  • U update 更新
  • D delete 删除
下面给个简单示例,大家看看,剩下就去找文档,实现业务逻辑即可:
  
  
  
  
  
import { Injectable } from '@nestjs/common';import { InjectModel } from '@nestjs/sequelize';import { User } from './user.model';
@Injectable()export class UserService { constructor( @InjectModel(User) private userModel: typeof User,) {} // 创建新数据 async create(user: User) { const newUser = await this.userModel.create(user); return newUser; } // 查找所有数据 async findAll() { return this.userModel.findAll(); } // 按要求查找单个 async findOne(id: string) { return this.userModel.findOne({ where: { id } }); } // 按要求更新 async update(id: string, user: User) { await this.userModel.update(user, { where: { id } }); return this.userModel.findOne({ where: { id } }); } // 按要求删除 async delete(id: string) { const user = await this.userModel.findOne({ where: { id } }); await user.destroy(); }}
Tips: 进行删除的时候,我们可以进行假删除,两个数据库,一个是备份数据库,一个是主数据库。主数据库可以直接删除或者增加标识表示删除。备份数据库,可以不用删除只写入和更新操作,这样可以进行数据还原操作。
此外,为了防止 SQL 数据库注入,大家需要对数据来源进行统一校验处理或者直接进行 encode 处理,对于重要数据可以直接进行 MD5 加密处理,防止数据库被直接下载泄露。关于 SQL 数据库的安全处理,网上教程有很多,大家找一找就可以啦~
部署就比较简单了,我们就不需要一一赘述了,数据库可以用集团提供的云数据库,而 Nest 就是普通的 node 部署。
-end-

本文分享自微信公众号 - 京东云开发者(JDT_Developers)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

雷军:小米全新操作系统澎湃 OS 正式版已完成封包 国美 App 抽奖页面弹窗辱骂其创始人 美国政府限制向中国出口 NVIDIA H800 GPU 小米澎湃OS界面曝光 大神用 Scratch 手搓 RISC-V 模拟器,成功运行 Linux 内核 RustDesk 远程桌面 1.2.3 发布,增强 Wayland 支持 拔出罗技 USB 接收器后,Linux 内核竟然崩溃了 DHH 锐评“打包工具”:前端根本不需要构建 (No Build) JetBrains 推出 Writerside,创建技术文档的工具 Node.js 21 正式发布
{{o.name}}
{{m.name}}

Supongo que te gusta

Origin my.oschina.net/u/4090830/blog/10120392
Recomendado
Clasificación