当前位置: 首页 > news >正文

生物公司网站建设qq空间认证的网站后台根目录

生物公司网站建设,qq空间认证的网站后台根目录,咸宁网站设计公司,上海seo推广外包最近在使用Golang做了一个网盘项目#xff08;学习#xff09;#xff0c;文件存储一直保存在本地#xff08;各厂商提供的oss贵#xff09;#xff0c;所以就在思考怎么来处理这些文件#xff0c;类似的方案很对hdfs、fastdfs#xff0c;但这其中MinIO是最近几年比较火…最近在使用Golang做了一个网盘项目学习文件存储一直保存在本地各厂商提供的oss贵所以就在思考怎么来处理这些文件类似的方案很对hdfs、fastdfs但这其中MinIO是最近几年比较火热的一个项目所以尝试使用这个试一试。 1、MinIO的安装 MinIO的安装特别简单大家可以前去官网按照步骤完成注意以下几点即可 注意你服务器是amd还是arm架构注意你自己的网络确保你按照官网的命令开启了minio服务 minio server ~/minio --console-address :9090目前不要随便乱修改按照原始的方案 2、创建Golang项目 mkdir minio-api cd minio-api go mod init v13、Goland打开项目构建一个上传文件demo 创建一个main.go在这个函数中我们首先创建一个用于初始化MinIOClient的函数该函数细节如下 func InitMinioClient() *minio.Client {// 基本的配置信息endpoint : 172.16.59.130:9000accessKeyID : IdoSKNGz7evlQXVVqGJFsecretAccessKey : s4hnwC9yWOsU8TTmODFcMcw0TdExa4GsTpGzibEc// 初始化一个minio客户端对象minioClient, err : minio.New(endpoint, minio.Options{Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ),})if err ! nil {log.Fatalf(初始化MinioClient错误%s, err.Error())}return minioClient }有几点基本的注意事项首先是基本的配置信息你需要更改为你自己的一般端口都为9000注意不是9090针对这个地方的accessKeyID和secretAccessKey的创建如下图 然后我们构建一个main函数在这个main函数中我们首先调用初始化客户端的函数InitMinioClient然后我们在main实现一个简单的上传文件的demo func main() {// 创建客户端minioClient : InitMinioClient()// bucket名称bucketName : mypicctx : context.Background()// 创建这个bucketerr : minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{})if err ! nil {// 检测这个bucket是否已经存在exists, errBucketExists : minioClient.BucketExists(ctx, bucketName)if errBucketExists nil exists {log.Printf(We already own %s\n, bucketName)} else {log.Fatalln(err)}} else {log.Printf(Successfully created %s\n, bucketName)}// 需要上传文件的基本信息objectName : 头像.jpgfilePath : imagecontentType : multipart/form-datafPath : filepath.Join(filePath, objectName)fileInfo, err : os.Stat(fPath)if err os.ErrNotExist {log.Printf(%s目标文件不存在, fPath)}f, err : os.Open(fPath)if err ! nil {return}uploadInfo, err : minioClient.PutObject(ctx, bucketName, objectName, f, fileInfo.Size(), minio.PutObjectOptions{ContentType: contentType})if err ! nil {log.Fatalln(err)}log.Printf(Successfully uploaded %s of size %d\n, objectName, uploadInfo.Size) }上传文件即成功然后打开网页页面刷新出现下面页面即可同时你打开你的服务器可以发现你上传的文件。 观察上面的代码至少包括三个API包括创建Bucket、检测Bucket是否存在、上传文件到指定的Bucket。为了更好的研究这些API现在我从Bucket开始研究一下常用的API。 4.创建客户端对象 API接口 New(endpoint string, opts *Options) (*Client, error)初步观察这个接口在结合我们上面的示例可以发现 endpoint目前存储地址127.0.0.1:9000当然这里需要根据自身开启的minio服务所在的位置和服务端口。opts这个是一个minio.Options对象然后我们来具体了解一哈这个对象有哪些常用的属性注意这些属性的类 Creds存储的一个身份信任SecureAPI的请求方式HTTP/HTTPS 完整的一个创建Client的代码可以根据自身需要再改造 func InitMinioClient() *minio.Client {// 基本的配置信息endpoint : 172.16.59.130:9000accessKeyID : IdoSKNGz7evlQXVVqGJFsecretAccessKey : s4hnwC9yWOsU8TTmODFcMcw0TdExa4GsTpGzibEc// 初始化一个minio客户端对象minioClient, err : minio.New(endpoint, minio.Options{Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ),})if err ! nil {log.Fatalf(初始化MinioClient错误%s, err.Error())}return minioClient }你自己可以尝试创建一个bucket01和bucket02 5.Bucket的基本操作 5.1 创建Bucket MakeBucket(ctx context.Context, bucketName string, opts MakeBucketOptions)前两个参数不作过多的介绍非常的清晰所谓的BuketName你可以简单理解为就是你文件保存的文件夹在这里我们详细得介绍一哈MakeBucketOptionsminio.MakeBucketOptions其主要是用于指定Bucket的一些选项比如说Region这个地方的Region表示在哪里创建你的Bucket默认为us-east-1其它的一些选项可以参考官网文档在这里需要注意如果你是自己服务器搭建而不是使用他所提供的存储服务其实你是不用指定这个就默认值问题也不大一个完整的示例如下确保你事先已经有这样的minioClient err minioClient.MakeBucket(context.Background(),minio.MakeBucketOptions{Region: us-east-1, ObjectLocking: true}) if err ! nil {fmt.Println(err)return } fmt.Println(Successfully created mybucket.)5.2 展示Bucket ListBuckets(ctx context.Context) ([]BucketInfo, error)这个接口非常明了返回的是一个BucketInfo的slice在这里我们可以遍历该元素然后获取到对应的BucketInfo对象直接看下面的demo func ListBuckets(minioClient *minio.Client) {bucketInfos, err : minioClient.ListBuckets(context.Background())if err ! nil {fmt.Println(List Buckets err, err.Error())return}for index, bucketInfo : range bucketInfos {fmt.Printf(List Bucket No {%d}----filename{%s}-----createTime{%s}\n, index1, bucketInfo.Name, bucketInfo.CreationDate.Format(2006-01-02 15:04:05))} }输出为 List Bucket No {1}----filename{bucket01}-----createTime{2023-08-18 04:03:18} List Bucket No {2}----filename{bucket02}-----createTime{2023-08-18 03:54:42} 注意bucket是不支持修改名称的如果你要修改名称一般是新建一个bucket然后讲原来需要改名的bucket的内容移到新建的一个bucket。 5.3 检测Bucket BucketExists(ctx context.Context, bucketName string) (found bool, err error)检查Bucket是否存在查看下面demo func CheckBuckets(minioClient *minio.Client) {bucketName01 : bucket01bucketName02 : bucket03isExist, err : minioClient.BucketExists(context.Background(), bucketName01)if err ! nil {fmt.Printf(Check %s err%s, bucketName01, err.Error())return}if isExist {fmt.Printf(%s exists!\n, bucketName01)} else {fmt.Printf(%s not exists!\n, bucketName01)}isExist, err minioClient.BucketExists(context.Background(), bucketName02)if err ! nil {fmt.Printf(Check %s err%s, bucketName02, err.Error())return}if isExist {fmt.Printf(%s exists!\n, bucketName02)} else {fmt.Printf(%s not exists!\n, bucketName02)} }输出 bucket01 exists! bucket03 not exists! 5.4 删除Bucket RemoveBucket(ctx context.Context, bucketName string) error删除名称为bucketName的bucket删除之前建议先检查该bucket是否存在查看下面的demo func RemoveBucket(minioClient *minio.Client) {bucketName01 : bucket01isExist, err : minioClient.BucketExists(context.Background(), bucketName01)if err ! nil {fmt.Printf(Check %s err%s, bucketName01, err.Error())return}if isExist {fmt.Printf(%s exists! Start delete....\n, bucketName01)// 开始删除逻辑err minioClient.RemoveBucket(context.Background(), bucketName01)if err ! nil {fmt.Printf(Fail to remove %s:%s\n, bucketName01, err.Error())return}fmt.Printf(Success to remove %s\n, bucketName01)} else {fmt.Printf(%s not exists!\n, bucketName01)} } 输出为 bucket01 exists! Start delete… Success to remove bucket01 5.6 展示对象Object ListObjects(ctx context.Context, bucketName string, opts ListObjectsOptions) -chan ObjectInfo展示一个Object中的所有对象注意返回的是一个channel。在查看下面的demo请参考之前的内容先上传一些对象 func ListObjects(minioClient *minio.Client) {ctx, cancel : context.WithCancel(context.Background())defer cancel()bucketName : bucket02opts : minio.ListObjectsOptions{Prefix: 头,Recursive: true,}objectCh : minioClient.ListObjects(ctx, bucketName, opts)for obj : range objectCh {fmt.Printf(Name:%s\tSize:%d\tMD5:%s\tModifiedTime:%s\n,obj.Key, obj.Size, obj.ETag, obj.LastModified.Format(2006-01-02 03:04:05))} }输出为 Name:头像.jpg Size:739938 MD5:10bf76e379cd8f381791c6924f33dcd6 ModifiedTime:2023-08-18 05:22:34 注意在这里Prefix就是所有Object的的前缀。 针对Bucket的操作就到这里但是minio还提供其余操作比喻设置tag等等上面所列举的是常用的一些操作 6. Object操作 6.1 获取Object GetObject(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (*Object, error)返回一个数据流对象注意是一个数据流所以要写入到一个具体的对象中详见下面demo的使用 func GetObjects(minioClient *minio.Client) {bucketName : bucket02objectName : 头像.jpgobject, err : minioClient.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})if err ! nil {fmt.Println(err)return}defer func(object *minio.Object) {err : object.Close()if err ! nil {fmt.Println(err)return}}(object)localFile, err : os.Create(image/local-file.jpg)if err ! nil {fmt.Println(err)return}defer func(localFile *os.File) {err : localFile.Close()if err ! nil {return}}(localFile)if _, err io.Copy(localFile, object); err ! nil {fmt.Println(err)return} }注意这个地方文件的写入。 6.2 放入Object PutObject(ctx context.Context, bucketName, objectName string, reader io.Reader, objectSize int64,opts PutObjectOptions) (info UploadInfo, err error)将一个文件放入到bucket中详细见下面的操作其实之前我们的demo中已经有了这个操作 func PutObjects(minioClient *minio.Client) {bucketName : bucket02// 检查bucket是否存在isExist, err : minioClient.BucketExists(context.Background(), bucketName)if err ! nil {fmt.Printf(Check %s err%s, bucketName, err.Error())return}if !isExist {fmt.Printf(%s not exists!\n, bucketName)}// 对象信息objectName : 头像.jpgfilePath : imagecontentType : multipart/form-datafPath : filepath.Join(filePath, objectName)// 读取对象流fileInfo, err : os.Stat(fPath)if err os.ErrNotExist {log.Printf(%s目标文件不存在, fPath)}f, err : os.Open(fPath)if err ! nil {log.Printf(%s打开目标文件, fPath)return}// 上传文件uploadInfo, err : minioClient.PutObject(context.Background(), bucketName,objectName, f, fileInfo.Size(),minio.PutObjectOptions{ContentType: contentType})if err ! nil {log.Fatalln(err)return}log.Printf(Successfully uploaded %s of size %d\n, objectName, uploadInfo.Size) } 最后这个文件会被放在你minio服务器上的minio下你可以去该文件下查看 6.3 复制Objects CopyObject(ctx context.Context, dst CopyDestOptions, src CopySrcOptions) (UploadInfo, error)将一个文件复制到另一个bucket中详见下面demo: func CopyObjects(minioClient *minio.Client) {// Source objectsrcOpts : minio.CopySrcOptions{Bucket: bucket02,Object: 头像.jpg,}// Destination objectdstOpts : minio.CopyDestOptions{Bucket: bucket01,Object: 图片.jpg,}// copyuploadInfo, err : minioClient.CopyObject(context.Background(), dstOpts, srcOpts)if err ! nil {fmt.Println(err)return}fmt.Println(Successfully copied object:, uploadInfo) }输出为 Successfully copied object: {bucket01 图片.jpg 10bf76e379cd8f381791c6924f33dcd6 0 2023-08-18 08:144.773 0000 UTC 0001-01-01 00:00:00 0000 UTC } 6.4 状态Objects StatObject(ctx context.Context, bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error)返回一个object的元数据demo如下 func StateObjects(minioClient *minio.Client) {ObjInfo, err : minioClient.StatObject(context.Background(), bucket02, 头像.jpg, minio.StatObjectOptions{})if err ! nil {fmt.Println(err)return}fmt.Printf(LastModified:%s\tETag:%s\tContentType:%s\tSize:%d\n,ObjInfo.LastModified.Format(2006-01-02 03:04:05),ObjInfo.ETag, ObjInfo.ContentType, ObjInfo.Size) }输出为 LastModified:2023-08-18 05:22:34 ETag:10bf76e379cd8f381791c6924f33dcd6 ContentType:multipart/form-data Size:739938 6.5 删除Object RemoveObject(ctx context.Context, bucketName, objectName string, opts minio.RemoveObjectOptions) error删除一个object注意下面demo func RemoveObject(minioClient *minio.Client) {opts : minio.RemoveObjectOptions{}err : minioClient.RemoveObject(context.Background(), bucket01, 图片.jpg, opts)if err ! nil {fmt.Println(err)return} }6.6 批量删除Object RemoveObjects(ctx context.Context, bucketName string, objectsCh -chan ObjectInfo, opts RemoveObjectsOptions) -chan RemoveObjectError批量删除一个bucket中的object关键就是构造这里的objectsCh详细见demo func RemoveObjects(minioClient *minio.Client) {objectsCh : make(chan minio.ObjectInfo)// 注意一般不要自己来构造直接选择从bucket中查询查询到的对象放入objectsChfor object : range minioClient.ListObjects(context.Background(), bucket02, minio.ListObjectsOptions{}) {if object.Key 头像.jpg {objectsCh - object}}defer close(objectsCh)// 删除for rErr : range minioClient.RemoveObjects(context.Background(), bucket02, objectsCh, minio.RemoveObjectsOptions{}) {fmt.Println(Delete err:, rErr.Err.Error())} }6.7 上传大对象Object FPutObject(ctx context.Context, bucketName, objectName, filePath, opts PutObjectOptions) (info UploadInfo, err error)该demo如下 func UploadLargeFileObjects(minioClient *minio.Client) {uploadInfo, err : minioClient.FPutObject(context.Background(), bucket02, test.csv, data, minio.PutObjectOptions{ContentType: application/csv,})if err ! nil {fmt.Println(err)return}fmt.Println(Successfully uploaded object: , uploadInfo) }在MinIO中,PutObject和FPutObject主要有以下几点区别: 操作对象方式不同: PutObject上传对象采用单个对象上传方式,一次请求上传一个对象。FPutObject上传对象采用分片上传方式,可以在多个请求中上传同一个对象。 适用场景不同: PutObject适用于小对象的上传。FPutObject适用于大对象的上传,可以支持超过5GB的对象上传。 上传方式不同: PutObject直接上传对象。FPutObject需要首先调用InitiateMultipartUpload初始化分片上传,然后调用UploadPart上传每个分片,最后调用CompleteMultipartUpload完成上传。 错误处理不同: PutObject上传错误需要重新上传整个对象。FPutObject上传错误只需要重新上传出错的分片。 上传事务不同: PutObject上传具有原子性,一个对象要么完全上传,要么失败。FPutObject上传可以暂停和恢复,但多个分片上传完成后才视为成功。 所以简单来说,对于小对象可以直接使用PutObject,对于大对象建议使用FPutObject分片上传。 6.8 下载大对象 FGetObject(ctx context.Context, bucketName, objectName, filePath string, opts GetObjectOptions) error下载大文件详见下面demo: func DownloadLargeFileObjects(minioClient *minio.Client) {err : minioClient.FGetObject(context.Background(), bucket02, test.csv, /tmp/myobject, minio.GetObjectOptions{})if err ! nil {fmt.Println(err)return} }基本上的操作就是这样当然这里还可以需要设置一些策略设置就不在这里详讲了可以去官网查看. 完整代码 package mainimport (contextfmtgithub.com/minio/minio-go/v7github.com/minio/minio-go/v7/pkg/credentialsiologospath/filepath )func InitMinioClient() *minio.Client {// 基本的配置信息endpoint : 172.16.59.129:9000accessKeyID : 6b6U1MlseU8h9dDkACNjsecretAccessKey : Hf6NSEHjXwHiApoymYR0yktNUkbZwt3MYYRmXOgT// 初始化一个minio客户端对象minioClient, err : minio.New(endpoint, minio.Options{Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ),})if err ! nil {log.Fatalf(初始化MinioClient错误%s, err.Error())}return minioClient }func main() {// 创建客户端minioClient : InitMinioClient()// Make a new bucket called mymusic.// bucketName : mypic//ctx : context.Background()//err : minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{})//if err ! nil {// // Check to see if we already own this bucket (which happens if you run this twice)// exists, errBucketExists : minioClient.BucketExists(ctx, bucketName)// if errBucketExists nil exists {// log.Printf(We already own %s\n, bucketName)// } else {// log.Fatalln(err)// }//} else {// log.Printf(Successfully created %s\n, bucketName)//}// Upload the zip file//objectName : 头像.jpg//filePath : image//contentType : multipart/form-data//fPath : filepath.Join(filePath, objectName)//fileInfo, err : os.Stat(fPath)//if err os.ErrNotExist {// log.Printf(%s目标文件不存在, fPath)//}////f, err : os.Open(fPath)//if err ! nil {// return//}////uploadInfo, err : minioClient.PutObject(ctx, bucketName, objectName, f, fileInfo.Size(), minio.PutObjectOptions{ContentType: contentType})//if err ! nil {// log.Fatalln(err)//}////log.Printf(Successfully uploaded %s of size %d\n, objectName, uploadInfo.Size)// ListBuckets(minioClient)//CheckBuckets(minioClient)//RemoveBucket(minioClient)//UploadObjToBucket(minioClient)//ListObjects(minioClient)//GetObjects(minioClient)//CopyObjects(minioClient)//StateObjects(minioClient)//RemoveObject(minioClient)RemoveObjects(minioClient) }func ListBuckets(minioClient *minio.Client) {bucketInfos, err : minioClient.ListBuckets(context.Background())if err ! nil {fmt.Println(List Buckets err, err.Error())return}for index, bucketInfo : range bucketInfos {fmt.Printf(List Bucket No {%d}----filename{%s}-----createTime{%s}\n, index1, bucketInfo.Name, bucketInfo.CreationDate.Format(2006-01-02 15:04:05))} }func CheckBuckets(minioClient *minio.Client) {bucketName01 : bucket01bucketName02 : bucket03isExist, err : minioClient.BucketExists(context.Background(), bucketName01)if err ! nil {fmt.Printf(Check %s err%s, bucketName01, err.Error())return}if isExist {fmt.Printf(%s exists!\n, bucketName01)} else {fmt.Printf(%s not exists!\n, bucketName01)}isExist, err minioClient.BucketExists(context.Background(), bucketName02)if err ! nil {fmt.Printf(Check %s err%s, bucketName02, err.Error())return}if isExist {fmt.Printf(%s exists!\n, bucketName02)} else {fmt.Printf(%s not exists!\n, bucketName02)} }func RemoveBucket(minioClient *minio.Client) {bucketName01 : bucket01isExist, err : minioClient.BucketExists(context.Background(), bucketName01)if err ! nil {fmt.Printf(Check %s err%s, bucketName01, err.Error())return}if isExist {fmt.Printf(%s exists! Start delete....\n, bucketName01)// 开始删除逻辑err minioClient.RemoveBucket(context.Background(), bucketName01)if err ! nil {fmt.Printf(Fail to remove %s:%s\n, bucketName01, err.Error())return}fmt.Printf(Success to remove %s\n, bucketName01)} else {fmt.Printf(%s not exists!\n, bucketName01)} }func ListObjects(minioClient *minio.Client) {ctx, cancel : context.WithCancel(context.Background())defer cancel()bucketName : bucket02opts : minio.ListObjectsOptions{Prefix: 头,Recursive: true,}objectCh : minioClient.ListObjects(ctx, bucketName, opts)for obj : range objectCh {fmt.Printf(Name:%s\tSize:%d\tMD5:%s\tModifiedTime:%s\n,obj.Key, obj.Size, obj.ETag, obj.LastModified.Format(2006-01-02 03:04:05))} }func GetObjects(minioClient *minio.Client) {bucketName : bucket02objectName : 头像.jpgobject, err : minioClient.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})if err ! nil {fmt.Println(err)return}defer func(object *minio.Object) {err : object.Close()if err ! nil {fmt.Println(err)return}}(object)localFile, err : os.Create(image/local-file.jpg)if err ! nil {fmt.Println(err)return}defer func(localFile *os.File) {err : localFile.Close()if err ! nil {return}}(localFile)if _, err io.Copy(localFile, object); err ! nil {fmt.Println(err)return} }func PutObjects(minioClient *minio.Client) {bucketName : bucket02// 检查bucket是否存在isExist, err : minioClient.BucketExists(context.Background(), bucketName)if err ! nil {fmt.Printf(Check %s err%s, bucketName, err.Error())return}if !isExist {fmt.Printf(%s not exists!\n, bucketName)}// 对象信息objectName : 头像.jpgfilePath : imagecontentType : multipart/form-datafPath : filepath.Join(filePath, objectName)// 读取对象流fileInfo, err : os.Stat(fPath)if err os.ErrNotExist {log.Printf(%s目标文件不存在, fPath)}f, err : os.Open(fPath)if err ! nil {log.Printf(%s打开目标文件, fPath)return}// 上传文件uploadInfo, err : minioClient.PutObject(context.Background(), bucketName,objectName, f, fileInfo.Size(),minio.PutObjectOptions{ContentType: contentType})if err ! nil {log.Fatalln(err)return}log.Printf(Successfully uploaded %s of size %d\n, objectName, uploadInfo.Size) }func CopyObjects(minioClient *minio.Client) {// Source objectsrcOpts : minio.CopySrcOptions{Bucket: bucket02,Object: 头像.jpg,}// Destination objectdstOpts : minio.CopyDestOptions{Bucket: bucket01,Object: 图片.jpg,}// copyuploadInfo, err : minioClient.CopyObject(context.Background(), dstOpts, srcOpts)if err ! nil {fmt.Println(err)return}fmt.Println(Successfully copied object:, uploadInfo) }func StateObjects(minioClient *minio.Client) {ObjInfo, err : minioClient.StatObject(context.Background(), bucket02, 头像.jpg, minio.StatObjectOptions{})if err ! nil {fmt.Println(err)return}fmt.Printf(LastModified:%s\tETag:%s\tContentType:%s\tSize:%d\n,ObjInfo.LastModified.Format(2006-01-02 03:04:05),ObjInfo.ETag, ObjInfo.ContentType, ObjInfo.Size) }func RemoveObject(minioClient *minio.Client) {opts : minio.RemoveObjectOptions{}err : minioClient.RemoveObject(context.Background(), bucket01, 图片.jpg, opts)if err ! nil {fmt.Println(err)return} }func RemoveObjects(minioClient *minio.Client) {objectsCh : make(chan minio.ObjectInfo)// 注意一般不要自己来构造直接选择从bucket中查询查询到的对象放入objectsChfor object : range minioClient.ListObjects(context.Background(), bucket02, minio.ListObjectsOptions{}) {if object.Key 头像.jpg {objectsCh - object}}defer close(objectsCh)// 删除for rErr : range minioClient.RemoveObjects(context.Background(), bucket02, objectsCh, minio.RemoveObjectsOptions{}) {fmt.Println(Delete err:, rErr.Err.Error())} }func UploadLargeFileObjects(minioClient *minio.Client) {uploadInfo, err : minioClient.FPutObject(context.Background(), bucket02, test.csv, data, minio.PutObjectOptions{ContentType: application/csv,})if err ! nil {fmt.Println(err)return}fmt.Println(Successfully uploaded object: , uploadInfo) }func DownloadLargeFileObjects(minioClient *minio.Client) {err : minioClient.FGetObject(context.Background(), bucket02, test.csv, /tmp/myobject, minio.GetObjectOptions{})if err ! nil {fmt.Println(err)return} }
http://www.yutouwan.com/news/345533/

相关文章:

  • 密云微网站建设网站优化试卷
  • 我想做网站张家港网站建设门店
  • 网站描述技巧做家教网站的资源是什么
  • 网站排名做不上去吗电子代加工东莞网站建设
  • 东莞网站建设网站排名优化自己做企业网站服务器
  • 深圳网站设计公司yx成都柚米科技15网站建设为中心
  • cms网站管理主机如何做网站空间
  • 滁州58同城网站怎么做杭州桐庐网站建设
  • 网站访客唯尚广告联盟app下载
  • 网站技术实现方案网站seo快速优化
  • 如何自己学做网站网站优化公司免费咨询
  • 企业制作企业网站企业网络营销策划与分析
  • 东阳网站建设公司做娱乐网站的意义目的
  • 网站后台ftp如何在百度里做推广网站
  • 新建网站的价格劳动局免费咨询律师电话
  • 世界建设企业网站wordpress 制作瀑布流
  • 保定建站软件wordpress中文相册插件
  • 珠海门户网站建设seo销售是做什么的
  • 企业网站里面的qq咨询怎么做wordpress备份数据
  • 心理学重点学科建设网站什么软件可以做app
  • 摄影网站哪个最好网页设计尺寸1080
  • wordpress网站合并如何弄一个自己的公众号
  • 如何给公司做一个网站北京网站优化哪家公司好
  • 网站seo排名公司微信公众号小程序助手
  • 沈阳专门做网站网站关键字被改了
  • 怎么在备案号添加网站佛山专业做网站的
  • 如何阿里网站建设1元购类似网站架设药多少钱
  • 唐山哪个公司做网站网站怎么添加滤镜功能吗
  • 邯郸市教育考试院网站建设网站的整个费用预算
  • 网站建设审核需要多长时间门户网站想要微信登录怎么做