前言:
小米商城全栈项目采用了前后端分离的设计思路,后端的我使用到了nest.js框架,数据库方面,项目选择了MySQL来存储用户信息和商品数据。然后通过引用axios来获取后端数据,确保数据的实时性和准确性,因为刚刚才学习了nest.js框架,在本次项目中也遇到了一些问题,同时,我会将遇到的问题与解决思路给到大家,希望看完这篇博客对您会有一些帮助。
小米商城官网地址:点这里<<<
进入小米商城需要注意的是,因为小米商城全栈是移动端的项目,如果您是PC端,需要开启浏览器的模拟器来进入该页面:1.点击F12进入控制台 —— 2.ctrl+shift+M即可进入模拟器。否则会进入小米官网。
1.引入nest.js
首先确保您的电脑下载了Node.js,Node.js安装会附带npx和npm包运行程序。要创建新的Nest.js,需要在终端上运行以下的命令:
pnpm i -g @nestjs/cli // 全局安装Nest
nest new project-name // 创建项目
创建好项目后会询问您是想用什么方式去管理依赖包,这边建议优先去使用pnpm,不行的话改用npm。
创建好后就会自动生成文件,我们还需要创建一个数据库,这边我用的是小皮,然后在数据库中插入表,添加我们想要的数据,最后使用Nest.js连接数据库。
2.连接数据库
以上是我在数据库中创建的表,从上到下对应的是小米商城中的分类页面,米圈页面,轮播图以及用户的信息,用于登录页面中判断用户信息是否存在,存在就登录成功,否则就登录失败。
在app.module.ts中连接数据库,首先需要在该目录下下载@nestjs/typeorm、typeorm以及mysql执行命令,在文件中使用import导入:
import { TypeOrmModule } from '@nestjs/typeorm'
安装vscode的mysql插件: Database Client 用于在创建数据库
然后就可以去连接我们创建的数据库了。
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm'
@Module({
// 连接创建的数据库
imports: [
TypeOrmModule.forRoot({
type:'mysql',
host:'127.0.0.1',
port:3306,
username:'root',
password:'root',
database:'mi_data',
autoLoadEntities:true, // 自动加载实体
synchronize:true, // 自动同步实体
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
我们也可以添加全局前缀,在main.ts中添加:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 设置全局路由前缀
app.setGlobalPrefix('/api')
await app.listen(3000);
}
bootstrap();
到这里我们可以先去将页面的静态效果先去制作好,通过html、css、js来实现。
3.首页
将首页的静态页面做完后,将轮播图的图片地址改为用后端传来的图片地址,我们首先需要使用 nest g res swiper 生成轮播图模块。
选择REST API,在 swiper.entity.ts 文件里面添加实体,实体是一 个映射到数据库表的类。换句话说实体就是一张数据表,在typeorm中我们不需要对数据库的表使用相 关工具进行创建与关联,而只需要创建一个实体,并且将实体中的数据内容设置好,那么在项目启动 后,就会自动生成对应的表,并且将表与表之间的关系给创建好。
以上是数据库中的数据。
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
@Entity('swiper')
export class Swiper {
@PrimaryGeneratedColumn('uuid')
id:number
@Column({
type:'timestamp', // 列类型
nullable: true,
comment:'创建时间' //注释
})
create_at:string
@Column({
type:'timestamp',
nullable: true,
comment:'更新时间'
})
update_at:string
@Column({
type:'varchar',
length:50,
unique:true,
comment:'图片名称'
})
name:string
}
添加实体,与数据库中的数据要一一对应。
首先我们了解我们需要做什么,就是想要拿取数据库的中数据,然后渲染到页面上,我们就只用去查数据,增删改都不需要去实现。就拿swiper这个表,nest.js的查询过程是这个表的数据会首先进入到swiper.controller.ts然后再会到swiper.service.ts中,然后我们就可以根据地址去访问到数据。
在swiper.controller.ts中,因为我们需要的是查数据,就用Get请求去查询,我们发现该文件下有两个Get请求。
@Get('')
findAll() {
return this.swiperService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.swiperService.findOne(+id);
}
上面的是查询所有数据,下面的是通过id去查询单个数据,从使用到的方法上就能看出来,查询所有数据使用的是findAll方法,单个数据则使用的是findOne方法。
然后根据直接的需求去对应使用,这里我需要查询所有数据,我就使用上面这个,给其添加一个路由前缀。
@Get('/all')
findAll() {
return this.swiperService.findAll();
}
在swiper.service.ts文件中,我们需要手动通过import去引入实体,以及下载的typeorm和@nestjs/typeorm。
import { Injectable } from '@nestjs/common';
import { CreateSwiperDto } from './dto/create-swiper.dto';
import { UpdateSwiperDto } from './dto/update-swiper.dto';
import { Swiper } from './entities/swiper.entity';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
@Injectable()
export class SwiperService {
// 依赖注入
constructor(
@InjectRepository(Swiper)
private swiperRepository: Repository<Swiper>
){}
async create(createSwiperDto: CreateSwiperDto) {
return await this.swiperRepository.save(createSwiperDto);
}
async findAll() {
return await this.swiperRepository.find();
}
async findOne(id: number) {
return await this.swiperRepository.findOne({ where: { id } });
}
async update(id: number, updateSwiperDto: UpdateSwiperDto) {
return await this.swiperRepository.update(id, updateSwiperDto);
}
remove(id: number) {
return `This action removes a #${id} swiper`;
}
}
在swiper.module.ts中导入@nestjs/typeorm和实体
import { Module } from '@nestjs/common';
import { SwiperService } from './swiper.service';
import { SwiperController } from './swiper.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Swiper } from './entities/swiper.entity';
@Module({
imports: [TypeOrmModule.forFeature([Swiper])],
controllers: [SwiperController],
providers: [SwiperService],
})
export class SwiperModule {}
这里可以在vscode中下载一个扩展Postcode。它主要作为Postman的替代品,为开发者提供了在VSCode环境中进行API测试的功能。
直接在Postcode可以输入地址,获取数据库中的数据。
到这里我们就已经成功获取到了数据。在再首页中使用axios获取数据并渲染到页面。
const swiperBox = document.getElementById("swiperBox");
axios.get("http://127.0.0.1:3000/api/swiper/all")
.then((res) => {
let html = "";
for (let i = 0; i < res.data.length; i++) {
// console.log(res.data[i].name);
html += `
<div class="swiper-slide">
<img src="./小米商城图片资源/${res.data[i].name}" alt="" />
</div>
`;
}
swiperBox.innerHTML = html;
})
.catch((error) => {
console.error("Error fetching images:", error);
});
};
4.登录页面
在中登录页面时,需要和上述步骤一样,首先要获取数据库的数据,然后前端需要将用户填写的用户名和密码的数据传给后端,后端需要对传过来的数据进行判断,如果传过来的数据后后端数据库的数据匹配上了,就将数据发给前端,否则就返回null。前端也可以从后端去拿取数据做判断,但前端是不安全的,这种操作一般是需要后端去完成的。
登录接口逻辑:
1.后端登录接口/api/user/login
2.前端提交用户名密码到后端
3. 后端获取前端传的数据,通过该数据查询数据库,如果查询到数据,则返回登录成功以及用户信息和token,否则返回登录失败
4.前端根据返回结果做出相应的提示
5.如果登录成功就跳转到首页,否则就提示登录失败
axios.post("http://127.0.0.1:3000/api/user/login", {
username: username,
password: password,
})
上述代码将数据传给后端。后端先先是需要获取到前端传来的数据。
这里需要先在user.controller.ts中创建一个post请求来接收数据。
@Post('/login')
login(@Body() data: any) {
return this.userService.login(data);
}
然后到user.service.ts中继续判断,我们只需要数据库的一条数据就可以了,不用获取全部数据,使用findOne方法。
// 登录
async login(data) {
const user = await this.userRepository.findOne({
where:{username: data.username, password: data.password}
})
console.log(user)
if(user){
return {
code: 0,
data: user,
message: '登录成功'
}
}else{
return {
code: 1,
message: '用户名或密码错误',
data: null
}
}
}
将判断结果返回给前端。然后前端可以通过传来的code来进行一个成功和失败的判断,将用户的头像和用户名保存到本地存储中。我这里的话登录成功后会跳转到首页。
axios.post("http://127.0.0.1:3000/api/user/login", {
username: username,
password: password,
})
.then((res) => {
if (res.data.code === 0) {
console.log("登录成功");
localStorage.setItem("avatar",res.data.data.avatar);
localStorage.setItem("username", res.data.data.username);
window.location.href =
"./index.html";
} else {
text.textContent = "用户名或密码错误";
}
});
});
5.项目总结
小米商城全栈项目是一个充满挑战和机遇的项目。通过本次项目的开发,我们不仅提升了技术能力,还积累了宝贵的项目经验。相信在未来的日子里,我们将能够创造出更多优秀的项目,为互联网行业的发展贡献自己的力量。
通过本次小米商城全栈项目的开发,不仅加深了对前后端分离开发模式的理解,还掌握了nest.js的基本使用。在项目实现过程中,遇到了许多技术难点和挑战,但通过不断学习和实践,最终成功完成了项目的开发。