基于Go语言的网盘开发(GloudDisk)

news2024/11/28 20:47:27

(记录一下自己做项目的过程) 基于go-zero实现的简易的网盘系统,如果有小伙伴对这个项目感兴趣,可以去网上搜索一些资料。这里推荐一下我学习的来源:【项目实战】基于Go-zero、Xorm的网盘系统_哔哩哔哩_bilibili 

确定功能模块:

目录

 xorm连接数据库并创建表结构

 集成go—zero

一、用户模块

(1)密码登录

(2)邮箱注册

 (3)个人资料详情

二、存储池模块

(1)中心存储池资源管理

①文件上传

(2)个人存储池资源管理 

①文件关联存储

②用户文件列表 

③用户文件名称修改

④用户文件夹创建

⑤用户文件删除

⑥用户文件移动

三、文件共享模块

(1)文件分享

①创建分享记录

②获取资源详情

③资源保存


 xorm连接数据库并创建表结构

 创建项目--安装xorm( go get xorm.io/xorm)

文档地址:Xorm

连接数据库:

xorm.NewEngine("mysql", "root:123@/test?charset=utf8")

先创建UserBasic结构体,为了之后的测试,如下:(新建models文件夹,在文件夹下新建user_basic.go)

package Models

type UserBasic struct {
	ID int
	Identity string
	Name string
	Password string
	Email string
}

func (table UserBasic) TableName() string {
	return "user_basic"
}

之后通过 engine.CreateTables(),参数为一个或多个空的对应Struct的指针,创建数据表,具体操作如下:(为了测试,新建一个文件夹test,新建xorm_test.go)

package test

import (
	"CloudDisk/Models"
	bytes2 "bytes"
	"encoding/json"
	_ "github.com/go-sql-driver/mysql"
	"testing"
	"xorm.io/xorm"
)

func TestXorm(t *testing.T) {
	engine, err := xorm.NewEngine("mysql", "root:123456@tcp(127.0.0.1:3306)/clouddisk?charset=utf8")
	if err!=nil {
		t.Fatal(err)
	}
	TableUser:=make([]*Models.UserBasic,0)
	m := new(Models.UserBasic)
	err = engine.CreateTables(m)
	if err!=nil {
		t.Fatal(err)
	}
	err = engine.Find(&TableUser)//这里查出来的是地址
	if err!=nil {
		t.Fatal(err)
	}
	//将以json格式输出
	bytes, err:= json.Marshal(TableUser)//转换成BYTE数组
	if err!=nil {
		t.Fatal(err)
	}
	dst := new(bytes2.Buffer)
	err = json.Indent(dst, bytes, "", "  ") //转换为buffer
	if err!=nil {
		t.Fatal(err)
	}
	println(dst.String())
}

 集成go—zero

文档地址:简介 · go-zero document

 安装:

go get -u github.com/zeromicro/go-zero

因为项目比较小,所以直接选择单体服务就可以了,

安装Goctl,完成后执行 goctl -v,如果输出版本信息则代表安装成功

# Go 1.15 及之前版本
go get -u github.com/zeromicro/go-zero/tools/goctl@latest

# Go 1.16 及以后版本
go install github.com/zeromicro/go-zero/tools/goctl@latest

创建greet服务,如下图,因为我们 mkdircd 都已经完成了,所以直接  goctl api new [可自定义名字] (我的是goctl api new code,因为下面我会直接说code文件,所以希望大家不要迷糊我这code是啥了)

 之后启动服务:

$ cd greet
$ go run greet.go -f etc/greet-api.yaml

之后通过http://localhost:8888/from/you来访问服务,如下图:

 可以看到当前的返回值为null,那是因为我们在 logic 文件里的 .go文件 没有写任何的业务逻辑(我的名字是code,所以这里是codelogic.go),如下图:

如果我们改成 

重新启动服务,会出现这样的页面:

 

但是为什么返回的是Message呢?因为返回的response里面定义的是一个Message集。在code.api中可以看到,如下图: 

 以后我们就可以在这里写业务逻辑了。

接下来我们来整合一下,将models文件放入code目录下,并在models中创建init.go用来连接数据库。如下:

 代码:

package Models

import (
	"log"
	"xorm.io/xorm"
	_ "github.com/go-sql-driver/mysql"
)
var Engine=Init()
func Init() *xorm.Engine {
	engine, err := xorm.NewEngine("mysql", "root:123456@tcp(127.0.0.1:3306)/clouddisk?charset=utf8")
	if err!=nil {
		log.Println("engine Error:",err)//log包的println会自动return
	}
	return engine
}

然后在 codelogic.go 进行业务逻辑的实现: (其实就是将文件 xorm_test.go 中的代码复制过来进行测试)

package logic

import (
	"CloudDisk/code/Models"
	bytes2 "bytes"
	"context"
	"encoding/json"
	"log"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"
	"github.com/zeromicro/go-zero/core/logx"
)

type CodeLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CodeLogic {
	return &CodeLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *CodeLogic) Code(req *types.Request) (resp *types.Response, err error) {
	TableUser:=make([]*Models.UserBasic,0)
	err = Models.Engine.Find(&TableUser)//这里查出来的是地址
	if err!=nil {
		log.Println("Find Error:",err)
	}
	//将以json格式输出
	bytes, err:= json.Marshal(TableUser)//转换成BYTE数组
	if err!=nil {
		log.Println("json Error:",err)
	}
	dst := new(bytes2.Buffer)
	err = json.Indent(dst, bytes, "", "  ") //转换为buffer
	if err!=nil {
		log.Println("Indent Error:",err)
	}
	println(dst.String())
	resp=new(types.Response)
	resp.Message=dst.String()
	return
}

一、用户模块

(1)密码登录

在 code.api 中写登录handler的相关配置

service code-api {
	@handler User//这个handler指的是生成在handler与logic下的文件所处理的句柄
	get /user/login (LoginRequest) returns (LoginReply)
}

type LoginRequest {
	Name     string `form:"name"`
	Password string `json:"password"`
}

type LoginReply {
	Token string `json:"token"`
}

 更新api,之后在 handler 与 logic 文件下都会出现新的.go文件

goctl api go  -api code.api -dir . -style go_zero

 在用户成功登陆之后,那么存到数据库的密码,我们也需要加密一下,这里用到的是MD5。

两个方法:

(1)md5.New() 初始化一个MD5对象,返回的是hash.Hash对象。

         函数原型: func New() hash.Hash

         该对象实现了hash.Hash的Sum接口。

(2)md5.Sum() 计算出MD5校验和。

         函数原型:func Sum(data []byte) [Size]byte
         他并不是对data进行校验计算,而是对hash.Hash对象内部存储的内容进行校验和计算然后将其追加到data的后面形成一个新的byte切片。该方法返回一个Size大小为16的byte数组,对于MD5来说就是一个128bit的16字节byte数组。

新建文件 helper,创建 helper.go 写入MD5函数 

package helper

import (
	"crypto/md5"
	"fmt"
)

func Md5(s string) string {
	return fmt.Sprintf("%x",md5.Sum([]byte(s)))
}

我们需要生成 token,而 token 需要用到 jwt 进行加密。这里介绍一下 jwt-go 库

使用 jwt-go 库生成 token,我们需要定义需求(claims),也就是说我们需要通过 jwt 传输的数据。假如我们需要传输 ID 和 Username,我们可以定义 Claims 结构体,其中包含 ID 和 Username 字段,还有在 jwt-go 包预定义的 jwt.StandardClaims。

使用 jwt-go 库根据指定的算法生成 jwt token ,主要用到两个方法:

(1)jwt.NewWithClaims 方法:

func jwt.NewWithClaims(method jwt.SigningMethod, claims jwt.Claims) *jwt.Token

jwt.NewWithClaims 方法根据 Claims 结构体创建 Token 示例。

参数 1 是 jwt.SigningMethod,最常用的是 jwt.SigningMethodHS256 这种 crypto.Hash 加密算法的方案。

参数 2 是 Claims,也就是我们自己定义的UserClaim,UserClaim嵌入在自定义类型中,以方便对标准声明进行编码,解析和验证。

(2)SignedString 方法:

func (*jwt.Token).SignedString(key interface{}) (string, error)

SignedString 方法根据传入的空接口类型参数 key,返回完整的签名令牌。

解析 token

使用 jwt-go 库解析 token

(1)jwt.ParseWithClaims 方法:

func jwt.ParseWithClaims(tokenString string, claims jwt.Claims, keyFunc jwt.Keyfunc) (*jwt.Token, error)

jwt.ParseWithClaims 方法用于解析鉴权的声明,返回 *jwt.Token。

创建文件夹define,用来定义token需要用到的claims

package define

import "github.com/dgrijalva/jwt-go"

type UserClaim struct {
	Id int
	Identity string
	Name string
	jwt.StandardClaims
}
var JwtKey="cloud-disk-key"

接下来定义生成token的方法,写在helper文件里

func GenerateToken(id int,name,identity string) (string,error) {
	uc:=define.UserClaim{
		Id:id,
		Identity: identity,
		Name: name,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, uc) //生成token
	//给token进行加密
	tokenString, err := token.SignedString([]byte(define.JwtKey))
	if err!=nil {
		return "", err
	}
	return tokenString,nil
}

 准备工作都做好了,接下来我们来写user-login业务逻辑,user_logic.go 代码如下:

package logic

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/helper"
	"context"
	"errors"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserLogic {
	return &UserLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserLogic) User(req *types.LoginRequest) (resp *types.LoginReply, err error) {
	// todo: add your logic here and delete this line
	user := new(Models.UserBasic)
	//1.从数据库中查询当前用户
	get, err := Models.Engine.Where("name= ? AND password= ?", req.Name, helper.Md5(req.Password)).Get(user)
	if err!=nil {
		return nil, err
	}
	if !get {
		return nil,errors.New("用户名或密码错误")
	}
	//2.生成token
	token, err := helper.GenerateToken(user.ID, user.Name, user.Identity)
	if err!=nil {
		return nil,err
	}
	resp=new(types.LoginReply)
	resp.Token=token
	return
}

之后我们进行重新编译(下面两句话会频繁的用到,每次写完code.api都要goctl一下)

goctl api go -api code.api -dir . -style go_zero

 然后运行

go run code.go -f etc/code-api.yaml

使用postman软件,帮助测试 (这里在code.api中我将输入json改为了form形式)

(2)邮箱注册

go get github.com/jordan-wright/email

 安装email,源址https://github.com/jordan-wright/email

go get github.com/go-redis/redis/v8

 安装redis,源址GitHub - go-redis/redis: Type-safe Redis client for Golang

$ go get github.com/satori/go.uuid

 安装uuid ,源址GitHub - satori/go.uuid: UUID package for Go

在 init.go 中加入 redis 的配置

package Models

import (
	"context"
	"github.com/go-redis/redis/v8"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"xorm.io/xorm"
)
var Engine=Init()
var ctx = context.Background()
var Redis = InitRedis()
func Init() *xorm.Engine {
	engine, err := xorm.NewEngine("mysql", "root:123456@tcp(127.0.0.1:3306)/clouddisk?charset=utf8")
	if err!=nil {
		log.Println("engine Error:",err)//log包的println会自动return
	}
	return engine
}
func InitRedis() *redis.Client {
	return redis.NewClient(&redis.Options{
		Addr:     "127.0.0.1:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})
}

 在 helper 中定义随机数生成,为了生成随机的验证码;以及 uuid ,为了生成 identity

package helper

import (
	"CloudDisk/code/define"
	"crypto/md5"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/jordan-wright/email"
	uuid "github.com/satori/go.uuid"
	"math/rand"
	"net/smtp"
	"time"
)

func Md5(s string) string {
	return fmt.Sprintf("%x",md5.Sum([]byte(s)))
}
func GenerateToken(id int,name,identity string) (string,error) {
	uc:=define.UserClaim{
		Id:id,
		Identity: identity,
		Name: name,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, uc) //生成token
	//给token进行加密
	tokenString, err := token.SignedString([]byte(define.JwtKey))
	if err!=nil {
		return "", err
	}
	return tokenString,nil
}
func MailSendCode(mail,code string) error {
	e := email.NewEmail()
	e.From = ""//发送者姓名,发送者邮箱地址
	e.To = []string{mail}//接收着
	e.Subject = "验证码测试"//发送的主题
	e.HTML = []byte("<h1>"+code+"</h1>")
	err := e.Send("smtp.qq.com:25", smtp.PlainAuth("", "@qq.com", "jjj", "smtp.qq.com"), )
	if err!=nil {
		return err
	}
	return nil
}
func RandCode() string {
	s:="1234567890"
	rand.Seed(time.Now().UnixNano())
	code:=""
	for i := 0; i < 6; i++ {
		code+=string(s[rand.Intn(len(s))])
	}
	return code
}
func GetUUID() string {
	return uuid.NewV4().String()
}

 发送验证码的业务逻辑

package logic

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/helper"
	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"
	"context"
	"errors"
	"time"

	"github.com/zeromicro/go-zero/core/logx"
)

type MailCodeSendLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewMailCodeSendLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MailCodeSendLogic {
	return &MailCodeSendLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *MailCodeSendLogic) MailCodeSend(req *types.MailCodeSendRequest) (resp *types.MailCodeSendReply, err error) {
	// todo: add your logic here and delete this line
	//该邮箱未被注册
	count, err := Models.Engine.Where("email= ?", req.Email).Count(new(Models.UserBasic))
	if err!=nil {
		return
	}
	if count>0 {
		err=errors.New("该邮箱已经被注册过了")
		return
	}
	//获取验证码
	code:=helper.RandCode()
	//存储验证码
	Models.Redis.Set(l.ctx, req.Email,code,time.Second * 300)
	//发送验证码
	err = helper.MailSendCode(req.Email, code)
	if err!=nil {
		return nil, err
	}
	return
}

用户注册的业务逻辑

package logic

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/helper"
	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"
	"context"
	"errors"
	"github.com/zeromicro/go-zero/core/logx"
	"log"
)

type UserRegisterLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserRegisterLogic {
	return &UserRegisterLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp *types.UserRegisterReply, err error) {
	//判断code是否一致
	result, err := Models.Redis.Get(l.ctx, req.Email).Result()
	if err!=nil {
		return nil, errors.New("未获取该邮箱的验证码")
	}
	if result!=req.Code {
		err=errors.New("验证码错误")
		return
	}
	//判断用户名是否已经存在
	count, err := Models.Engine.Where("name= ?", req.Name).Count(new(Models.UserBasic))
	if err!=nil {
		return nil, err
	}
	if count>0 {
		err=errors.New("用户名已经存在")
		return
	}
	//数据入库,开始注册信息
	user:=&Models.UserBasic{
		Name: req.Name,
		Identity:helper.GetUUID(),
		Email: req.Email,
		Password: helper.Md5(req.Password),
	}
	insert, err := Models.Engine.Insert(user)
	if err!=nil {
		return nil, err
	}
	log.Println("insert user row:",insert)
	return
}

 (3)个人资料详情

 通过 identity 来获取用户信息

code.api新增:

service code-api {
	//用户登录
	@handler UserLogin//这个handler指的是生成在handler与logic下的文件所处理的句柄
	post /user/login (LoginRequest) returns (LoginReply)
	//用户详情
	@handler UserDetail
	post /user/detail (DetailRequest) returns (DetailReply)
}

type LoginRequest {
	Name     string `form:"name"`
	Password string `form:"password"`
}

type LoginReply {
	Token string `json:"token"`
}
type DetailRequest {
	Identity string `json:"identity"`
}
type DetailReply {
	Name  string `json:"name"`
	Email string `json:"email"`
}

 之后 goctl api go -api code.api -dir . -style go_zero 生成编译,编写detail业务逻辑

package logic

import (
	"CloudDisk/code/Models"
	"context"
	"errors"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserDetailLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserDetailLogic {
	return &UserDetailLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserDetailLogic) UserDetail(req *types.DetailRequest) (resp *types.DetailReply, err error) {
	// todo: add your logic here and delete this line
	resp=&types.DetailReply{}
	m := new(Models.UserBasic)
	get, err := Models.Engine.Where("identity= ? ", req.Identity).Get(m)
	if err!=nil {
		return nil, err
	}
	if !get {
		return nil, errors.New("该用户不存在")
	}
	resp.Name=m.Name
	resp.Email=m.Email
	return
}

二、存储池模块

我们先修改一下数据库配置路由,在etc文件的 code_api.yaml 中加入如下:

Name: code-api
Host: 0.0.0.0
Port: 8888

Mysql:
  DataSource: root:123456@tcp(127.0.0.1:3306)/clouddisk?charset=utf8

Redis:
  Addr: 127.0.0.1:6379

在config文件中加入:

package config

import "github.com/zeromicro/go-zero/rest"

type Config struct {
	rest.RestConf
	Mysql struct{
		DataSource string
	}
	Redis struct{
		Addr string
	}
}

同样在 service_context.go 中也要加入:

package svc

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/internal/config"
	"CloudDisk/code/internal/middleware"
	"github.com/go-redis/redis/v8"
	"github.com/zeromicro/go-zero/rest"
	"xorm.io/xorm"
)

type ServiceContext struct {
	Config config.Config
	Engine *xorm.Engine
	RDB *redis.Client
	Auth rest.Middleware
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config: c,
		Engine:Models.Init(c.Mysql.DataSource),
		RDB:Models.InitRedis(c),
		Auth: middleware.NewAuthMiddleware().Handle,
	}
}

当然,在做以下业务逻辑的时候,首先需要加一个中间件,用来验证用户是否已经登录,如果不登录是无法使用以下功能的。在go-zero中,中间件可以分为路由中间件和全局中间件,路由中间件是指某一些特定路由需要实现中间件逻辑,而全局中间件的服务范围则是整个服务。我们这里使用的是路由中间件 。对于中间件,需要添加 Middleware 声明。

所以我们需要再写一对 service code-api{},在这之上需要 Middleware 声明。例如文件上传的code.api配置,然后 goctl api go -api code.api -dir . -style go_zero 一下会自动生成Middleware的文件,在文件中配置如下

package middleware

import (
	"CloudDisk/code/helper"
	"net/http"
)

type AuthMiddleware struct {
}

func NewAuthMiddleware() *AuthMiddleware {
	return &AuthMiddleware{}
}

func (m *AuthMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// TODO generate middleware implement function, delete after code implementation
		auth:=r.Header.Get("Authorization")
		if auth =="" {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Unauthorized"))
			return
		}
		uc, err := helper.AnalyzeToken(auth)
		if err!=nil {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte(err.Error()))
			return
		}
		r.Header.Set("UserId",string(rune(uc.Id)))
		r.Header.Set("UserIdentity",uc.Identity)
		r.Header.Set("UserName",uc.Name)
		// Passthrough to next handler if need
	    next(w, r)
	}
}

这里用到了token的解析,具体如下:

//AnalyzeToken Token解析
func AnalyzeToken(token string) (*define.UserClaim, error) {
	uc:=new(define.UserClaim)
	claims, err := jwt.ParseWithClaims(token, uc, func(token *jwt.Token) (interface{}, error) {
		return []byte(define.JwtKey), nil
	})
	if err != nil {
		return nil,err
	}
	if !claims .Valid{
		return uc,errors.New("token is invalid")
	}
	return uc,err
}

  当然同样也要在 service_context.go 中也要加入Middleware 的声明。(代码跟上面一样,不在复制!)

(1)中心存储池资源管理

①文件上传

在Models里加入 RepositoryPool

package Models

import "time"

type RepositoryPool struct {
	Id        int
	Identity  string
	Hash      string
	Name      string
	Ext       string
	Size      int64
	Path      string
	createdAt time.Time `xorm:"created"`
	UpdatedAt time.Time `xorm:"updated"`
	DeletedAt time.Time `xorm:"deleted"`
}
func (table RepositoryPool) TableName() string {
	return "repository_pool"
}

 在code.api代码中,添加如下代码:

@server(
	middleware : Auth
)
service code-api {
	//文件上传
	@handler FileUpload
	post /file/upload (FileUploadRequest) returns (FileUploadReply)
}
type FileUploadRequest {
	Hash string `json:"hash,optional"`
	Name string `json:"name,optional"`
	Ext  string `json:"ext,optional"`
	Size int    `json:"size,optional"`
	Path string `json:"path,optional"`
}
type FileUploadReply {
	Identity string `json:"identity"`
	Ext      string `json:"ext"`
	Name     string `json:"name"`
}

 在文件上传这里我们采用 CosUpload 文件上传到腾讯云,帮助文档在这里---------------------------------------------------------------》》》》》对象存储 快速入门-SDK 文档-文档中心-腾讯云

在 helper 文件中加入 CosUpload 文件上传的业务逻辑

//CosUpload 文件上传到腾讯云
func CosUpload(r *http.Request) (string,error) {
	u, _ := url.Parse(define.CosBucket)
	b := &cos.BaseURL{BucketURL: u}
	c := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			//如实填写账号和密钥,也可以设置为环境变量
			SecretID:  define.TencentSecretID,
			SecretKey: define.TencentSecretKey,
		},
	})
	file, fileHeader, err := r.FormFile("file")
	name := "cloud-disk/"+GetUUID()+path.Ext(fileHeader.Filename)
	_, err = c.Object.Put(context.Background(), name, file,nil)
	if err != nil {
		panic(err)
	}
	return define.CosBucket+"/"+name,nil
}

file_upload_handler.go 中写入如下代码:这次我们是先判断一下文件是否上传过,之后将信息写给 logic 中的 req 。

package handler

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/helper"
	"crypto/md5"
	"fmt"
	"net/http"
	"path"

	"CloudDisk/code/internal/logic"
	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"
	"github.com/zeromicro/go-zero/rest/httpx"
)

func FileUploadHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req types.FileUploadRequest
		if err := httpx.Parse(r, &req); err != nil {
			httpx.Error(w, err)
			return
		}
		file, fileHeader, err2 := r.FormFile("file")
		if err2!=nil {
			return
		}
		//判断文件是否存在
		bytes := make([]byte, fileHeader.Size)
		_, err2 = file.Read(bytes)
		if err2!=nil {
			return
		}
		hash:=fmt.Sprintf("%x",md5.Sum(bytes))
		rp:=new(Models.RepositoryPool)
		get, err2 := svcCtx.Engine.Where("hash=?", hash).Get(rp)
		if err2!=nil {
			return
		}
		if get {
			httpx.OkJson(w,&types.FileUploadReply{Identity: rp.Identity, Ext: rp.Ext, Name: rp.Name})
			return
		}
		//往cos中存储文件
		cosPath, err2 := helper.CosUpload(r)
		if err2!=nil {
			return
		}
		//往 logic 中传递req
		req.Name=fileHeader.Filename
		req.Ext=path.Ext(fileHeader.Filename)
		req.Size= int(fileHeader.Size)
		req.Hash=hash
		req.Path=cosPath

		l := logic.NewFileUploadLogic(r.Context(), svcCtx)
		resp, err := l.FileUpload(&req)
		if err != nil {
			httpx.Error(w, err)
		} else {
			httpx.OkJson(w, resp)
		}
	}
}

file_upload_logic.go 业务逻辑代码如下:

package logic

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/helper"
	"context"
	"fmt"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type FileUploadLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewFileUploadLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FileUploadLogic {
	return &FileUploadLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *FileUploadLogic) FileUpload(req *types.FileUploadRequest) (resp *types.FileUploadReply, err error) {
	// todo: add your logic here and delete this line
	rp := &Models.RepositoryPool{
		Identity: helper.GetUUID(),
		Hash:     req.Hash,
		Name:     req.Name,
		Ext:      req.Ext,
		Size:     int64(req.Size),
		Path:     req.Path,
	}
	_, err = l.svcCtx.Engine.Insert(rp)
	if err!=nil {
		return nil, err
	}
	resp=new(types.FileUploadReply)
	resp.Identity=rp.Identity
	resp.Ext=rp.Ext
	resp.Name=rp.Name
	fmt.Println(resp.Identity)
	return
}

(2)个人存储池资源管理 

①文件关联存储

code.api

//用户文件的关联存储
	@handler UserRepositorySave
	post /user/repository/save (UserRepositorySaveRequest) returns (UserRepositorySaveReply)
type UserRepositorySaveRequest {
	ParentId           int64  `json:"parentId"`
	RepositoryIdentity string `json:"repositoryIdentity"`
	Ext                string `json:"ext"`
	Name               string `json:"name"`
}
type UserRepositorySaveReply {
}

 Models新增

package Models

import "time"

type UserRepository struct {
	Id                 int
	Identity           string
	UserIdentity       string
	ParentId           int64
	RepositoryIdentity string
	Ext                string
	Name               string
	CreatedAt          time.Time `xorm:"created"`
	UpdatedAt          time.Time `xorm:"updated"`
	DeletedAt          time.Time `xorm:"deleted"`
}

func (table UserRepository) TableName() string {
	return "user_repository"
}

 在 user_repository_save_handler.go 修改一下 UserRepositorySave 函数的参数,将UserIdentity 传入,代码如下:

package handler

import (
	"net/http"

	"CloudDisk/code/internal/logic"
	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"
	"github.com/zeromicro/go-zero/rest/httpx"
)

func UserRepositorySaveHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req types.UserRepositorySaveRequest
		if err := httpx.Parse(r, &req); err != nil {
			httpx.Error(w, err)
			return
		}

		l := logic.NewUserRepositorySaveLogic(r.Context(), svcCtx)
		resp, err := l.UserRepositorySave(&req,r.Header.Get("UserIdentity"))
		if err != nil {
			httpx.Error(w, err)
		} else {
			httpx.OkJson(w, resp)
		}
	}
}

 接下来的每一个业务逻辑块都需要在 handler 里加入,之后我就不再详细说明了。

logic业务逻辑:(非常简单,就是个插入) 

package logic

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/helper"
	"context"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserRepositorySaveLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserRepositorySaveLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserRepositorySaveLogic {
	return &UserRepositorySaveLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserRepositorySaveLogic) UserRepositorySave(req *types.UserRepositorySaveRequest, userIdentity string) (resp *types.UserRepositorySaveReply, err error) {
	// todo: add your logic here and delete this line
	ur := &Models.UserRepository{
		Identity:           helper.GetUUID(),
		UserIdentity:       userIdentity,
		ParentId:           req.ParentId,
		RepositoryIdentity: req.RepositoryIdentity,
		Ext:                req.Ext,
		Name:               req.Name,
	}
	_, err = l.svcCtx.Engine.Insert(ur)
	if err!=nil {
		return
	}
	return
}

②用户文件列表 

code.api 

	//用户文件列表
	@handler UserFileList
	get /user/file/list (UserFileListReguest) returns (UserFileListReply)
type UserFileListReguest {
	Id   int64 `json:"id,optional"`
	Page int   `json:"page,optional"`
	Size int   `json:"size,optional"`
}

type UserFileListReply {
	List  []*UserFile `json:"list"`
	Count int         `json:"count"`
}

logic 业务逻辑做到了分页的多表 join 查询 

package logic

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/define"
	"context"
	"time"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserFileListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserFileListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserFileListLogic {
	return &UserFileListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserFileListLogic) UserFileList(req *types.UserFileListReguest,userIdentity string) (resp *types.UserFileListReply, err error) {
	// todo: add your logic here and delete this line
	uf := make( []*types.UserFile,0)
	//var cnt int64
	resp = new(types.UserFileListReply)
	size:=req.Size
	if size==0 {
		size=define.PageSize
	}
	page:=req.Page
	if page ==0{
		page=1
	}
	offset:=(page-1)*size
	//查询用户文件列表
	l.svcCtx.Engine.ShowSQL(true)//这样就可以看到运行时的sql语句
	err = l.svcCtx.Engine.Table("user_repository"). Where("parent_id = ? AND user_identity = ? ",req.Id,userIdentity).
		Select("user_repository.id,user_repository.identity,user_repository.repository_identity,user_repository.ext,"+
			"user_repository.name,repository_pool.path,repository_pool.size").
		Join("LEFT","repository_pool","user_repository.repository_identity=repository_pool.identity").
		Where("user_repository.deleted_at=? OR user_repository.deleted_at IS NULL",time.Time{}.Format("2006-01-02 15:04:05")).
		Limit(size,offset).Find(&uf)
	if err != nil {
		return
	}
	count, err := l.svcCtx.Engine.Where("parent_id = ? AND user_identity = ? ", req.Id, userIdentity).Count(new(Models.UserRepository))
	if err!=nil {
		return
	}
	resp.List = uf
	resp.Count = int(count)

	return
}

③用户文件名称修改

code.api

	//用户文件名称修改
	@handler UserFileNameUpdate
	post /user/file/name/update (UserFileNameUpdateReguest) returns (UserFileNameUpdateReply)
type UserFileNameUpdateReguest {
	Identity string `json:"identity"`
	Name     string `json:"name"`
}

type UserFileNameUpdateReply {
}

 logic 业务实现

package logic

import (
	"CloudDisk/code/Models"
	"context"
	"errors"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserFileNameUpdateLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserFileNameUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserFileNameUpdateLogic {
	return &UserFileNameUpdateLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserFileNameUpdateLogic) UserFileNameUpdate(req *types.UserFileNameUpdateReguest,userIdentity string) (resp *types.UserFileNameUpdateReply, err error) {
	// todo: add your logic here and delete this line
	//判断当前名称在该层下面是否存在
	count, err := l.svcCtx.Engine.Where("name=? AND parent_id=(SELECT parent_id FROM user_repository ur WHERE ur.identity=?)", req.Name, req.Identity).Count(new(Models.UserRepository))
	if err!=nil {
		return nil, err
	}
	if count >0{
		return nil,errors.New("该名称已经存在")
	}
	//文件修改
	data := &Models.UserRepository{Name: req.Name}
	l.svcCtx.Engine.Where("identity = ? AND user_identity = ? ", req.Identity, userIdentity).Update(data)
	if err != nil {
		return
	}
	return
}

④用户文件夹创建

code.api

	//用户文件夹创建
	@handler UserFolderCreate
	post /user/folder/create (UserFolderCreateReguest) returns (UserFolderCreateReply)
type UserFolderCreateReguest {
	Name     string `json:"name"`
	ParentId int64  `json:"parent_id"`
}

type UserFolderCreateReply {
	Identity string `json:"identity"`
}

 logic

package logic

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/helper"
	"context"
	"errors"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserFolderCreateLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserFolderCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserFolderCreateLogic {
	return &UserFolderCreateLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserFolderCreateLogic) UserFolderCreate(req *types.UserFolderCreateReguest,userIdentity string) (resp *types.UserFolderCreateReply, err error) {
	// todo: add your logic here and delete this line
	//判断当前名称在该层下面是否存在
	count, err := l.svcCtx.Engine.Where("name=? AND parent_id=?", req.Name, req.ParentId).Count(new(Models.UserRepository))
	if err!=nil {
		return nil, err
	}
	if count >0{
		return nil,errors.New("该名称已经存在")
	}
	//创建文件夹
	data:=&Models.UserRepository{
		Identity: helper.GetUUID(),
		UserIdentity: userIdentity,
		ParentId: req.ParentId,
		Name: req.Name,
	}
	_, err = l.svcCtx.Engine.Insert(data)
	if err != nil {
		return
	}
	return
}

⑤用户文件删除

code.api

	//用户文件删除
	@handler UserFileDelete
	post /user/file/delete (UserFileDeleteReguest) returns (UserFileDeleteReply)
type UserFileDeleteReguest {
	Identity string `json:"identity"`
}

type UserFileDeleteReply {
}

 logic

package logic

import (
	"CloudDisk/code/Models"
	"context"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserFileDeleteLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserFileDeleteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserFileDeleteLogic {
	return &UserFileDeleteLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserFileDeleteLogic) UserFileDelete(req *types.UserFileDeleteReguest,userIdentity string) (resp *types.UserFileDeleteReply, err error) {
	// todo: add your logic here and delete this line
	_, err = l.svcCtx.Engine.Where("user_identity=? AND identity=?", userIdentity, req.Identity).Delete(new(Models.UserRepository))
	if err!=nil {
		return
	}
	return
}

⑥用户文件移动

code.api,注意是 PUT 请求

	//用户文件移动
	@handler UserFileMove
	put  /user/file/move (UserFileMoveReguest) returns (UserFileMoveReply)
type UserFileMoveReguest {
	Identity       string `json:"identity"`
	ParentIdentity string `json:"parentIdentity"`
}

type UserFileMoveReply {
}

 logic

package logic

import (
	"CloudDisk/code/Models"
	"context"
	"errors"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserFileMoveLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserFileMoveLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserFileMoveLogic {
	return &UserFileMoveLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserFileMoveLogic) UserFileMove(req *types.UserFileMoveReguest,userIdentity string) (resp *types.UserFileMoveReply, err error) {
	// todo: add your logic here and delete this line
	parentDate := new(Models.UserRepository)
	has, err := l.svcCtx.Engine.Where("identity=? AND user_identity=?", req.ParentIdentity, userIdentity).Get(parentDate)
	if err!=nil {
		return nil, err
	}
	if !has {
		return nil,errors.New("文件夹不存在!")
	}
	//更新记录的ParentID
	_, err = l.svcCtx.Engine.Where("identity=?", req.Identity).Update(Models.UserRepository{
		ParentId: int64(parentDate.Id),
	})
	return
}

三、文件共享模块

(1)文件分享

①创建分享记录

code.api

	//创建分享记录
	@handler ShareBasicCreate
	post /share/basic/create (ShareBasicCreateRequest) returns (ShareBasicCreateReply)
type ShareBasicCreateRequest {
	RepositoryIdentity string `json:"repository_identity"`
	ExpiredTime        int    `json:"expired_time"`
}

type ShareBasicCreateReply {
	Identity string `json:"identity"`
}

logic

package logic

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/helper"
	"context"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type ShareBasicCreateLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewShareBasicCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ShareBasicCreateLogic {
	return &ShareBasicCreateLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ShareBasicCreateLogic) ShareBasicCreate(req *types.ShareBasicCreateRequest, userIdentity string) (resp *types.ShareBasicCreateReply, err error) {
	// todo: add your logic here and delete this line
	uuid := helper.GetUUID()
	data := &Models.ShareBasic{
		Identity:           uuid,
		UserIdentity:       userIdentity,
		RepositoryIdentity: req.RepositoryIdentity,
		ExpiredTime:        req.ExpiredTime,
	}
	_, err = l.svcCtx.Engine.Insert(data)
	if err != nil {
		return
	}
	resp = &types.ShareBasicCreateReply{
		Identity: uuid,
	}
	return
}

②获取资源详情

对于这个模块,就不用登录的中间件了,因为未登录的应该也可以获取到别人分享的文件。所以就写在用户登录等的那个api块里就行。

code.api

	//获取资源详情
	@handler ShareBasicDetail
	get /share/basic/detail (ShareBasicDetailRequest) returns (ShareBasicDetailReply)
type ShareBasicDetailRequest {
	Identity string `json:"identity"`
}

type ShareBasicDetailReply {
	RepositoryIdentity string `json:"repository_identity"`
	Name               string `json:"name"`
	Ext                string `json:"ext"`
	Size               int64  `json:"size"`
	Path               string `json:"path"`
}

Models

package Models

import "time"

type ShareBasic struct {
	Id int
	Identity string
	UserIdentity string
	RepositoryIdentity string
	ExpiredTime int
	ClickNum int
	CreatedAt time.Time `xorm:"created"`
	UpdatedAt time.Time `xorm:"updated"`
	DeletedAt time.Time `xorm:"deleted"`
}

func (table ShareBasic)TableName( ) string {
	return "share_basic"
}

logic

package logic

import (
	"context"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type ShareBasicDetailLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewShareBasicDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ShareBasicDetailLogic {
	return &ShareBasicDetailLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ShareBasicDetailLogic) ShareBasicDetail(req *types.ShareBasicDetailRequest) (resp *types.ShareBasicDetailReply, err error) {
	// todo: add your logic here and delete this line
	//对分享记录的点击次数进行 +1 操作
	_, err = l.svcCtx.Engine.Exec("UPDATE share_basic SET click_num = click_num + 1 WHERE identity = ?", req.Identity)
	if err!=nil {
		return
	}
	//获取资源的详细信息
	resp= new(types.ShareBasicDetailReply)
	_, err = l.svcCtx.Engine.Table("share_basic").
		Select("share_basic.repository_identity,repository_pool.name,repository_pool.ext,repository_pool.size,repository_pool.path").
		Join("LEFT", "repository_pool", "share_basic.repository_identity=repository_pool.identity").
		Where("share_basic.identity=?", req.Identity).Get(resp)
	return
}

③资源保存

需要用户登录的中间件,code.api 

	//资源保存
	@handler ShareBasicSave
	post /share/basic/save (ShareBasicSaveRequest) returns (ShareBasicSaveReply)
type ShareBasicSaveRequest {
	RepositoryIdentity string `json:"repository_identity"`
	ParentId           int64  `json:"parent_id"`
}

type ShareBasicSaveReply {
	Identity string `json:"identity"`
}

logic

package logic

import (
	"CloudDisk/code/Models"
	"CloudDisk/code/helper"
	"context"
	"errors"

	"CloudDisk/code/internal/svc"
	"CloudDisk/code/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type ShareBasicSaveLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewShareBasicSaveLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ShareBasicSaveLogic {
	return &ShareBasicSaveLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ShareBasicSaveLogic) ShareBasicSave(req *types.ShareBasicSaveRequest,userIdentity string) (resp *types.ShareBasicSaveReply, err error) {
	// todo: add your logic here and delete this line
	//获取资源详情
	rp:=new(Models.RepositoryPool)
	has, err := l.svcCtx.Engine.Where("identity=?", req.RepositoryIdentity).Get(rp)
	if err!=nil {
		return nil, err
	}
	if !has {
		return nil,errors.New("资源不存在")
	}
	//user_repository 资源保存
	ur:=&Models.UserRepository{
		Identity: helper.GetUUID(),
		UserIdentity: userIdentity,
		ParentId: req.ParentId,
		RepositoryIdentity: req.RepositoryIdentity,
		Ext: rp.Ext,
		Name: rp.Name,
	}
	_, err = l.svcCtx.Engine.Insert(ur)
	resp=new(types.ShareBasicSaveReply)
	resp.Identity=ur.Identity
	return
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/49375.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AutoCAD Electrical 2022—项目中新建、添加、删除图纸

右键点击项目—选择新建图纸&#xff1b; 点击快捷图标&#xff0c;新建图形&#xff1b; 弹出对话框&#xff0c;在名称中输入图纸名称&#xff1b; 模板为图框的样式&#xff0c;位置代号&#xff0c;图纸保存的位置&#xff1b; 其他根据需要填写&#xff1b; 填写完点击…

JavaScript -- 02. 变量和数据类型

文章目录变量和数据类型1 数值(Number)1.1 普通数值1.2 其他进制的数字2 大整数&#xff08;BigInt&#xff09;3 字符串(String)3.1 基础表示3.2 转义字符3.3 模板字符串4 布尔值(Boolean)5 空值(Null)6 未定义&#xff08;Undefined&#xff09;7 符号&#xff08;Symbol&…

6-2 装载问题(分支限界)

6-2 装载问题&#xff08;分支限界&#xff09; 一、问题描述 有一批共个集装箱要装上2艘载重量分别为C1和C2的轮船&#xff0c;其中集装箱i的重量为Wi&#xff0c;且 采用下面的策略可得到最优装载方案&#xff1a; (1)将第一艘轮船尽可能装满; (2)将剩余集装箱装上第二艘轮…

基于rsync daemon 实现 sersync——sersync实现实时数据同步

1 sersync 介绍 sersync类似于inotify&#xff0c;同样用于监控&#xff0c;但它克服了inotify的缺点. inotify最大的不足是会产生重复事件&#xff0c;或者同一个目录下多个文件的操作会产生多个事件&#xff0c;例如&#xff0c;当监控目录中有5个文件时&#xff0c;删除目录…

[附源码]计算机毕业设计springboot考试系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

学习C语言的优质网站

1. 初衷 C语言是最原始的操作操作数据结构和算法的一门编程语言&#xff0c;没有高级语言的封装&#xff0c;最能锻炼个人的算法思维和能力。 2. 编程网站推荐 2.1 javatpoint https://www.javatpoint.com/static-in-c 2.2 includehelp https://www.includehelp.com/c/ 2.…

Hadoop学习笔记——HDFS

文章目录一、HDFS概述1.1、HDFS产出背景及定义1.1.1 HDFS产生背景1.1.2 HDFS定义1.2、HDFS优缺点1.2.1、HDFS优点1.2.2、HDFS缺点1.3、HDFS组成架构1.4、HDFS文件块大小1.5、限制二、HDFS的Shell操作2.1、基本语法2.2、命令大全2.3、常用命令实操2.3.1 准备工作2.3.2 上传一、H…

快速复现 实现 facenet-retinaface-pytorch 人脸识别 windows上 使用cpu实现

目录0 前言1 搭建环境与项目2 人脸预测与结果展示0 前言 这一次要复现的是人脸识别中的 facenet-retinaface-pytorch 是在上一次博客的内容上更进一步 快速复现 实现 facenet-pytorch 人脸识别 windows上 使用cpu实现 人脸对比 参考了&#xff1a; Pytorch 利用Facenet和Reti…

10 Deployment:让应用永不宕机

文章目录1. 前言2. 为什么要有deployment 对象&#xff1f;3. 如何使用 YAML 描述 Deployment?3.1 查看 Deployment 的基本信息3.2 命令式创建Deployment 的YAML模板3.2.1 Deployment 的关键字段3.2.1.1 replicas 副本字段3.2.1.2 selector 标签筛选字段3.2.1.3 为什么在 YAML…

JAVA学习-java基础讲义02

java基础讲义02一 进制1.1 进制介绍1.2 二进制1.3 任意进制到十进制转换1.4 十进制到任意进制之间的转换1.5 快速转换法1.6 有符号数据表示法二 Java变量和数据类型1.1 变量概述1.2 数据类型1.3 变量定义三 Java数据类型转换3.1 数据类型转换概述3.2 数据类型转换之自动类型转换…

使用自己的数据集测试Unbiased Mean Teacher for Cross-domain Object Detection

要复现Unbiased Mean Teacher for Cross-domain Object Detection&#xff08;UMT&#xff09;&#xff0c;首先要正确运行CycleGAN。 1. CycleGAN CycleGAN的github链接&#xff1a;https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix 1.1 CycleGAN环境配置 git cl…

低代码助力生产管理:车间管理系统

在当前制造业全球化、网络化、敏捷化的背景下&#xff0c;制造业信息化是目前生产的主要趋势。其中车间是制造企业的核心单元&#xff0c;是企业生产计划的具体实施环节&#xff0c;同时负责反馈实时生产信息。因此车间层的信息资源集成和生产管理控制是整个企业生产供应链控制…

[Power Query] 快速计算列

对两列或者多列的计算&#xff0c;在Power Query中除了通过自定义列来实现以外&#xff0c;我们也可以通过利用功能区的【添加列】|【标准】运算功能进行列的计算 数据源 将数据源导入到Power BI Desktop&#xff0c;单击【转换数据】选项&#xff0c;进入Power Query查询编辑…

python对异常的处理

了解异常当检测到一个错误时&#xff0c;解释器就无法继续执行了&#xff0c;反而出现一些错误的提示&#xff0c;这就是异常。测试&#xff1a;f open(test.txt,r) #以读模式打开文件&#xff0c;文件不存在则报错 运行了解释器报错避免出现异常提示的写法 #需求&#xff1a;…

串口通信及串口转蓝牙相关知识

之前没有接触过硬件相关的工作&#xff0c; 因此对硬件的知识一知半解。 最近由于项目需要&#xff0c; 用到了串口通信以及串口跟蓝牙之间通信相关的东西。记录下来&#xff0c; 希望对新手有所帮助。 如有疏漏之处&#xff0c; 欢迎指正。 1 串口通信 https://www.jishulin…

docker-compose安装部署gitlab中文版

文章目录前言一、环境信息二、准备部署1.准备路径2.安装docker-compse&#xff0c;下载镜像3.引入库2.执行部署三、登陆页面前言 记录一下使用docker-compose部署gitlab平台的过程 一、环境信息 操作系统版本&#xff1a;CentOS Linux release 7.9.2009 (Core) gitlab镜像版本…

世界杯winner只属于你——MESSI

其实现在大脑中还在回忆着那一脚精彩的进球。 看官方怎么说的&#xff1a; 北京时间11月27日凌晨3点&#xff0c;世界杯C组第2轮&#xff0c;阿根廷2-0战胜墨西哥。 梅西在11月27日用1进球1助攻&#xff0c;上帝降临&#xff0c;拯救阿根廷。特别是那个进球&#xff0c;直接让…

矩阵快速幂 笔记加理解

文章目录1.何为快速幂1.1学习快速幂的好文章1.2快速幂取模代码&#xff08;对1000取模&#xff09;2.矩阵快速幂1.何为快速幂 补充一个公式证明&#xff1a; 1.1学习快速幂的好文章 http://t.csdn.cn/agKop 1.2快速幂取模代码&#xff08;对1000取模&#xff09; ll fast…

VMware虚拟网络编辑器配置

一&#xff0c;NAT模式网络设置。 把下面的ip&#xff0c;子网掩码&#xff0c;网关记住。 切换到network-scripts 目录下。 cd /etc/sysconfig/network-scripts/修改ifcfg-ens33 这个文件。 然后重启网络服务&#xff1a; 对于openEuler&#xff1a; systemctl restart Ne…

关于Eslint语法检查

在vue创建项目中&#xff0c;选择eslintStandard config -标准规范- 在保存时就开启检查 eslintrc.js配置&#xff0c;没反应重启项目 语法报错&#xff0c;根据错误提示&#xff0c;去eslint官网搜索规则 在eslintrc.js文件中rules中添加或者修改规则&#xff0c;自定义的…