feat: 优化文件上传

master
绝弹 2023-08-02 21:50:54 +08:00
parent f11b7e85e1
commit 2ec5aac04c
16 changed files with 71 additions and 100 deletions

Binary file not shown.

View File

@ -1,5 +1,5 @@
import { Inject } from '@nestjs/common';
import { ConfigService } from '@/config'; import { ConfigService } from '@/config';
import { Inject } from '@nestjs/common';
/** /**
* *
@ -15,6 +15,9 @@ export class BaseService {
* *
*/ */
formatPagination(page = this.config.defaultPage, size = this.config.defaultPageSize) { formatPagination(page = this.config.defaultPage, size = this.config.defaultPageSize) {
if (size == 0) {
return {};
}
return { return {
skip: (page - 1) * size, skip: (page - 1) * size,
take: size, take: size,

View File

@ -22,7 +22,7 @@ export class PaginationDto {
*/ */
@IsOptional() @IsOptional()
@IsNumber() @IsNumber()
@Min(1) @Min(0)
@Transform(({ value }) => Number(value)) @Transform(({ value }) => Number(value))
size?: number; size?: number;
} }

View File

@ -1,8 +1,8 @@
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { Public } from './jwt';
import { AuthUserDto } from './dto/auth-user.dto'; import { AuthUserDto } from './dto/auth-user.dto';
import { Public } from './jwt';
@ApiTags('auth') @ApiTags('auth')
@Controller('auth') @Controller('auth')
@ -14,7 +14,7 @@ export class AuthController {
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.OK)
@ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '账号或密码错误' }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '账号或密码错误' })
@ApiResponse({ description: '登录成功' }) @ApiResponse({ description: '登录成功' })
@ApiOperation({ summary: '账号登录', operationId: 'login' }) @ApiOperation({ description: '账号登录', operationId: 'login' })
login(@Body() user: AuthUserDto) { login(@Body() user: AuthUserDto) {
return this.authService.signIn(user); return this.authService.signIn(user);
} }

View File

@ -1,9 +1,9 @@
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; import { Respond } from '@/common/response';
import { PermissionService } from './permission.service'; import { Body, Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { CreatePermissionDto } from './dto/create-permission.dto'; import { CreatePermissionDto } from './dto/create-permission.dto';
import { UpdatePermissionDto } from './dto/update-permission.dto'; import { UpdatePermissionDto } from './dto/update-permission.dto';
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { PermissionService } from './permission.service';
import { Respond } from '@/common/response';
@ApiTags('permission') @ApiTags('permission')
@Controller('permissions') @Controller('permissions')
@ -11,32 +11,32 @@ export class PermissionController {
constructor(private readonly permissionService: PermissionService) {} constructor(private readonly permissionService: PermissionService) {}
@Post() @Post()
@ApiOperation({ summary: '创建权限', operationId: 'addPermission' }) @ApiOperation({ description: '创建权限', operationId: 'addPermission' })
create(@Body() createPermissionDto: CreatePermissionDto) { create(@Body() createPermissionDto: CreatePermissionDto) {
return this.permissionService.create(createPermissionDto); return this.permissionService.create(createPermissionDto);
} }
@Get() @Get()
@Respond(Respond.PAGINATION) @Respond(Respond.PAGINATION)
@ApiOperation({ summary: '批量查询权限', operationId: 'getPermissions' }) @ApiOperation({ description: '批量查询权限', operationId: 'getPermissions' })
findAll() { findAll() {
return this.permissionService.findAll(); return this.permissionService.findAll();
} }
@Get(':id') @Get(':id')
@ApiOperation({ summary: '查询权限', operationId: 'getPermission' }) @ApiOperation({ description: '查询权限', operationId: 'getPermission' })
findOne(@Param('id') id: string) { findOne(@Param('id') id: string) {
return this.permissionService.findOne(+id); return this.permissionService.findOne(+id);
} }
@Patch(':id') @Patch(':id')
@ApiOperation({ summary: '更新权限', operationId: 'updatePermission' }) @ApiOperation({ description: '更新权限', operationId: 'updatePermission' })
update(@Param('id') id: string, @Body() updatePermissionDto: UpdatePermissionDto) { update(@Param('id') id: string, @Body() updatePermissionDto: UpdatePermissionDto) {
return this.permissionService.update(+id, updatePermissionDto); return this.permissionService.update(+id, updatePermissionDto);
} }
@Delete(':id') @Delete(':id')
@ApiOperation({ summary: '删除权限', operationId: 'delPermission' }) @ApiOperation({ description: '删除权限', operationId: 'delPermission' })
remove(@Param('id') id: string) { remove(@Param('id') id: string) {
return this.permissionService.remove(+id); return this.permissionService.remove(+id);
} }

View File

@ -23,13 +23,8 @@ export class PermissionService {
return `This action returns a #${id} permission`; return `This action returns a #${id} permission`;
} }
<<<<<<< HEAD
async update(id: number, updatePermissionDto: UpdatePermissionDto) {
await this.permissionRepository.update(id, updatePermissionDto);
=======
update(id: number, updatePermissionDto: UpdatePermissionDto) { update(id: number, updatePermissionDto: UpdatePermissionDto) {
return this.permissionRepository.update(id, updatePermissionDto); return this.permissionRepository.update(id, updatePermissionDto);
>>>>>>> 1a32173fc73bbb94906f9ffde5874d47f6dfdad8
} }
remove(id: number) { remove(id: number) {

View File

@ -1,8 +1,8 @@
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common';
import { PostService } from './post.service'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { CreatePostDto } from './dto/create-post.dto'; import { CreatePostDto } from './dto/create-post.dto';
import { UpdatePostDto } from './dto/update-post.dto'; import { UpdatePostDto } from './dto/update-post.dto';
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { PostService } from './post.service';
@Controller('post') @Controller('post')
@ApiTags('post') @ApiTags('post')
@ -10,31 +10,31 @@ export class PostController {
constructor(private readonly postService: PostService) {} constructor(private readonly postService: PostService) {}
@Post() @Post()
@ApiOperation({ summary: '创建文章', operationId: 'addPost' }) @ApiOperation({ description: '创建文章', operationId: 'addPost' })
create(@Body() createPostDto: CreatePostDto) { create(@Body() createPostDto: CreatePostDto) {
return this.postService.create(createPostDto); return this.postService.create(createPostDto);
} }
@Get() @Get()
@ApiOperation({ summary: '批量查询文章', operationId: 'getPosts' }) @ApiOperation({ description: '批量查询文章', operationId: 'getPosts' })
findAll() { findAll() {
return this.postService.findAll(); return this.postService.findAll();
} }
@Get(':id') @Get(':id')
@ApiOperation({ summary: '查询文章', operationId: 'getPost' }) @ApiOperation({ description: '查询文章', operationId: 'getPost' })
findOne(@Param('id') id: string) { findOne(@Param('id') id: string) {
return this.postService.findOne(+id); return this.postService.findOne(+id);
} }
@Patch(':id') @Patch(':id')
@ApiOperation({ summary: '更新文章', operationId: 'updatePost' }) @ApiOperation({ description: '更新文章', operationId: 'updatePost' })
update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) { update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) {
return this.postService.update(+id, updatePostDto); return this.postService.update(+id, updatePostDto);
} }
@Delete(':id') @Delete(':id')
@ApiOperation({ summary: '删除文章', operationId: 'delPost' }) @ApiOperation({ description: '删除文章', operationId: 'delPost' })
remove(@Param('id') id: string) { remove(@Param('id') id: string) {
return this.postService.remove(+id); return this.postService.remove(+id);
} }

View File

@ -1,9 +1,9 @@
import { Respond } from '@/common/response';
import { Body, Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { CreateRoleDto } from './dto/create-role.dto'; import { CreateRoleDto } from './dto/create-role.dto';
import { UpdateRoleDto } from './dto/update-role.dto'; import { UpdateRoleDto } from './dto/update-role.dto';
import { RoleService } from './role.service'; import { RoleService } from './role.service';
import { Respond } from '@/common/response';
@ApiTags('role') @ApiTags('role')
@Controller('roles') @Controller('roles')
@ -11,32 +11,32 @@ export class RoleController {
constructor(private readonly roleService: RoleService) {} constructor(private readonly roleService: RoleService) {}
@Post() @Post()
@ApiOperation({ summary: '创建角色', operationId: 'addRole' }) @ApiOperation({ description: '创建角色', operationId: 'addRole' })
create(@Body() createRoleDto: CreateRoleDto) { create(@Body() createRoleDto: CreateRoleDto) {
return this.roleService.create(createRoleDto); return this.roleService.create(createRoleDto);
} }
@Get() @Get()
@Respond(Respond.PAGINATION) @Respond(Respond.PAGINATION)
@ApiOperation({ summary: '批量查询角色', operationId: 'getRoles' }) @ApiOperation({ description: '批量查询角色', operationId: 'getRoles' })
findAll() { findAll() {
return this.roleService.findAll(); return this.roleService.findAll();
} }
@Get(':id') @Get(':id')
@ApiOperation({ summary: '查询角色', operationId: 'getRole' }) @ApiOperation({ description: '查询角色', operationId: 'getRole' })
findOne(@Param('id') id: string) { findOne(@Param('id') id: string) {
return this.roleService.findOne(+id); return this.roleService.findOne(+id);
} }
@Patch(':id') @Patch(':id')
@ApiOperation({ summary: '更新角色', operationId: 'updateRole' }) @ApiOperation({ description: '更新角色', operationId: 'updateRole' })
update(@Param('id') id: string, @Body() updateRoleDto: UpdateRoleDto) { update(@Param('id') id: string, @Body() updateRoleDto: UpdateRoleDto) {
return this.roleService.update(+id, updateRoleDto); return this.roleService.update(+id, updateRoleDto);
} }
@Delete(':id') @Delete(':id')
@ApiOperation({ summary: '删除角色', operationId: 'delRole' }) @ApiOperation({ description: '删除角色', operationId: 'delRole' })
remove(@Param('id') id: string) { remove(@Param('id') id: string) {
return this.roleService.remove(+id); return this.roleService.remove(+id);
} }

View File

@ -26,16 +26,8 @@ export class RoleService {
return `This action returns a #${id} role`; return `This action returns a #${id} role`;
} }
<<<<<<< HEAD
async update(id: number, updateRoleDto: UpdateRoleDto) {
if (updateRoleDto.permissions) {
delete updateRoleDto.permissions;
}
await this.roleRepository.update(id, updateRoleDto);
=======
update(id: number, updateRoleDto: UpdateRoleDto) { update(id: number, updateRoleDto: UpdateRoleDto) {
return this.roleRepository.update(id, updateRoleDto); return this.roleRepository.update(id, updateRoleDto);
>>>>>>> 1a32173fc73bbb94906f9ffde5874d47f6dfdad8
} }
remove(id: number) { remove(id: number) {

View File

@ -9,30 +9,35 @@ export class Upload extends BaseEntity {
*/ */
@Column({ comment: '文件名' }) @Column({ comment: '文件名' })
name: string; name: string;
/** /**
* *
* @example 1024 * @example 1024
*/ */
@Column({ comment: '文件大小' }) @Column({ comment: '文件大小' })
size: number; size: number;
/** /**
* *
* @example "image/jpeg" * @example "image/jpeg"
*/ */
@Column({ comment: '文件类型' }) @Column({ comment: '文件类型' })
mimetype: string; mimetype: string;
/** /**
* *
* @example "/upload/2021/10/01/xxx.jpg" * @example "/upload/2021/10/01/xxx.jpg"
*/ */
@Column({ comment: '文件路径' }) @Column({ comment: '文件路径' })
path: string; path: string;
/** /**
* *
* @example "xxx" * @example "xxx"
*/ */
@Column({ comment: '文件哈希' }) @Column({ comment: '文件哈希' })
hash: string; hash: string;
/** /**
* *
* @example ".jpg" * @example ".jpg"

View File

@ -1,9 +1,9 @@
import { Controller, Delete, Get, Param, Patch, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { ApiBody, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger';
import { UploadService } from './upload.service';
import { FileInterceptor } from '@nestjs/platform-express';
import { Respond } from '@/common/response'; import { Respond } from '@/common/response';
import { Controller, Delete, Get, Param, Patch, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiBody, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger';
import { CreateUploadDto } from './dto/create-upload.dto'; import { CreateUploadDto } from './dto/create-upload.dto';
import { UploadService } from './upload.service';
@ApiTags('upload') @ApiTags('upload')
@Controller('upload') @Controller('upload')
@ -12,34 +12,34 @@ export class UploadController {
@Post() @Post()
@UseInterceptors(FileInterceptor('file')) @UseInterceptors(FileInterceptor('file'))
@ApiOperation({ summary: '上传文件', operationId: 'upload' })
@ApiConsumes('multipart/form-data') @ApiConsumes('multipart/form-data')
@ApiBody({ description: '文件', type: CreateUploadDto }) @ApiBody({ description: '要上传的文件', type: CreateUploadDto })
@ApiOperation({ description: '上传文件', operationId: 'upload' })
create(@UploadedFile() file: Express.Multer.File) { create(@UploadedFile() file: Express.Multer.File) {
return this.uploadService.create(file); return this.uploadService.create(file);
} }
@Get() @Get()
@Respond(Respond.PAGINATION) @Respond(Respond.PAGINATION)
@ApiOperation({ summary: '批量查询', operationId: 'getUploads' }) @ApiOperation({ description: '批量查询', operationId: 'getUploads' })
findAll() { findAll() {
return this.uploadService.findAll(); return this.uploadService.findAll();
} }
@Get(':id') @Get(':id')
@ApiOperation({ summary: '查询', operationId: 'getUpload' }) @ApiOperation({ description: '查询', operationId: 'getUpload' })
findOne(@Param('id') id: string) { findOne(@Param('id') id: string) {
return this.uploadService.findOne(+id); return this.uploadService.findOne(+id);
} }
@Patch(':id') @Patch(':id')
@ApiOperation({ summary: '更新', operationId: 'updateUpload' }) @ApiOperation({ description: '更新', operationId: 'updateUpload' })
update() { update() {
return this.uploadService.update(); return this.uploadService.update();
} }
@Delete(':id') @Delete(':id')
@ApiOperation({ summary: '删除', operationId: 'delUpload' }) @ApiOperation({ description: '删除', operationId: 'delUpload' })
remove(@Param('id') id: string) { remove(@Param('id') id: string) {
return this.uploadService.remove(+id); return this.uploadService.remove(+id);
} }

View File

@ -1,33 +1,25 @@
import { ConfigService } from '@/config';
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { MulterModule } from '@nestjs/platform-express';
import { TypeOrmModule } from '@nestjs/typeorm';
import { diskStorage } from 'multer';
import { Upload } from './entities/upload.entity';
import { UploadController } from './upload.controller'; import { UploadController } from './upload.controller';
import { UploadService } from './upload.service'; import { UploadService } from './upload.service';
import { MulterModule } from '@nestjs/platform-express';
import { ConfigService } from '@/config';
import dayjs from 'dayjs';
import { join, parse } from 'path';
import { diskStorage } from 'multer';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Upload } from './entities/upload.entity';
@Module({ @Module({
imports: [ imports: [
TypeOrmModule.forFeature([Upload]), TypeOrmModule.forFeature([Upload]),
MulterModule.registerAsync({ MulterModule.registerAsync({
useFactory: async (config: ConfigService) => { useFactory: async (config: ConfigService) => {
const dest = config.uploadDir; return {
const storage = diskStorage({ storage: diskStorage({
destination: join(dest), destination: config.uploadDir,
filename: (req, file, cb) => { filename: (req, file, cb) => {
const yearMonth = dayjs().format('YYYY-MM'); cb(null, file.originalname);
const { name, ext } = parse(file.originalname);
const randomName = Array(32)
.fill(null)
.map(() => Math.round(Math.random() * 16).toString(16))
.join('');
cb(null, `${yearMonth}/${name}-${randomName}${ext}`);
}, },
}); }),
return { storage }; };
}, },
inject: [ConfigService], inject: [ConfigService],
}), }),

View File

@ -1,7 +1,8 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { Upload } from './entities/upload.entity';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { parse } from 'path';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { Upload } from './entities/upload.entity';
@Injectable() @Injectable()
export class UploadService { export class UploadService {
@ -14,6 +15,7 @@ export class UploadService {
size: file.size, size: file.size,
hash: file.filename, hash: file.filename,
path: file.path, path: file.path,
extension: parse(file.originalname).ext,
}); });
await this.uploadRepository.save(upload); await this.uploadRepository.save(upload);
return upload.id; return upload.id;

View File

@ -1,10 +1,6 @@
import { PaginationDto } from '@/features/pagination'; import { PaginationDto } from '@/common/response';
import { IntersectionType } from '@nestjs/swagger'; import { IntersectionType } from '@nestjs/swagger';
import { IsOptional, IsString } from 'class-validator'; import { IsOptional, IsString } from 'class-validator';
<<<<<<< HEAD
=======
import { PaginationDto } from '@/common/response';
>>>>>>> 1a32173fc73bbb94906f9ffde5874d47f6dfdad8
export class FindUserDto extends IntersectionType(PaginationDto) { export class FindUserDto extends IntersectionType(PaginationDto) {
/** /**

View File

@ -1,21 +1,12 @@
import { BaseController } from '@/features/base'; import { BaseController } from '@/common/base';
import { Respond } from '@/features/response'; import { Respond } from '@/common/response';
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, Version } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, Patch, Post, Query, Version } from '@nestjs/common';
import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
<<<<<<< HEAD
import { CreateUserDto, UpdateUserDto } from './dto';
=======
import { Respond } from '@/common/response';
import { BaseController } from '@/common/base';
import { CreateUserDto } from './dto/create-user.dto'; import { CreateUserDto } from './dto/create-user.dto';
>>>>>>> 1a32173fc73bbb94906f9ffde5874d47f6dfdad8
import { FindUserDto } from './dto/find-user.dto'; import { FindUserDto } from './dto/find-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User } from './entities/user.entity'; import { User } from './entities/user.entity';
import { UserService } from './user.service'; import { UserService } from './user.service';
<<<<<<< HEAD
=======
import { UpdateUserDto } from './dto/update-user.dto';
>>>>>>> 1a32173fc73bbb94906f9ffde5874d47f6dfdad8
@ApiTags('user') @ApiTags('user')
@Controller('users') @Controller('users')

View File

@ -1,11 +1,11 @@
import { BaseService } from '@/common/base';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { Like, Repository } from 'typeorm'; import { Like, Repository } from 'typeorm';
import { FindUserDto } from './dto/find-user.dto';
import { User } from './entities/user.entity';
import { BaseService } from '@/common/base';
import { CreateUserDto } from './dto/create-user.dto'; import { CreateUserDto } from './dto/create-user.dto';
import { FindUserDto } from './dto/find-user.dto';
import { UpdateUserDto } from './dto/update-user.dto'; import { UpdateUserDto } from './dto/update-user.dto';
import { User } from './entities/user.entity';
@Injectable() @Injectable()
export class UserService extends BaseService { export class UserService extends BaseService {
@ -29,15 +29,10 @@ export class UserService extends BaseService {
* *
*/ */
async findMany(findUserdto: FindUserDto) { async findMany(findUserdto: FindUserDto) {
const { nickname, page, size } = findUserdto; const { nickname: _nickname, page, size } = findUserdto;
const nickname = _nickname && Like(`%${_nickname}%`);
const { skip, take } = this.formatPagination(page, size); const { skip, take } = this.formatPagination(page, size);
return this.userRepository.findAndCount({ return this.userRepository.findAndCount({ skip, take, where: { nickname } });
skip,
take,
where: {
nickname: nickname && Like(`%${nickname}%`),
},
});
} }
/** /**