.net 8 集成 MinIO文件存储服务,实现bucket管理,以及文件对象的基本操作

news2024/10/7 18:24:41

一、准备工作

1、本地部署MinIO服务

2、创建MinIO的Access Key

3、创建.net 项目

4、下载MinIO sdk

5、相关文档

二、编写MinIO工具类

三、管理存储桶

1、MyBucket类

(1)判断bucket是否存在

(2)新建bucket

(3)删除bucket 

(4)获取bucket列表

2、BucketController

3、实现效果

(1)判断bucket是否存在

(2)新建bucket

(3)删除bucket

(4)获取bucket列表

四、管理文件

1、MyObject类

(1)下载文件对象

(2)上传文件对象

(3)删除文件对象

(4)获取文件对象URL

2、ObjectController 

3、实现效果

(1)下载指定文件

(2)上传指定文件

(3)删除指定文件 

(4)获取指定文件URL 


一、准备工作

1、本地部署MinIO服务

需要在本地部署MinIO,并启动服务;可以参考这篇文章

Windows部署MinIO,搭建本地对象存储服务-CSDN博客

2、创建MinIO的Access Key

在MinIO控制台,选择【Access Keys】,点击【Create access key】;

点击【Create】创建用于连接MinIO服务的Key和Secret(很重要,一定要另存下来);

3、创建.net 项目

打开Visual Studio,新建项目,选择Web Api框架

选择.net8.0

4、下载MinIO sdk

使用NuGet包管理器找到并安装MinIIO的sdk,如下图所示,

这里安装的是最新版6.0.2;

5、相关文档

.NET API 开发文档(英文)

.NET API 参考文档(中文)

以官网的英文文档为主,中文文档为辅;

二、编写MinIO工具类

在代码中编写一个用来连接MinIO服务的工具类【MinIO.cs】,放在项目的【Helper】文件夹中;

【Helper/MinIO.cs】

using Minio;

namespace Zyl_MinIO_Demo.Helper
{
    public class MinIO
    {
        private static string endPoint = "127.0.0.1:9001";  
        private static string accessKey = "连接minio服务的key";   
        private static string secretKey= "连接minio服务的secret";
        private static bool secure = false; 

        public static MinioClient CreateMinioClient()
        {
            MinioClient minioClient = (MinioClient)new MinioClient()
                  .WithEndpoint(endpoint)
                  .WithCredentials(accessKey, secretKey)
                  .WithSSL(secure)   
                  .Build();
            return minioClient;
        }
    }
}
// 该方法用来初始化MinIO对象。
MinioClient minioClient = new MinioClient()

        .WithEndpoint(endPoint)

        .WithCredentials(accessKey, secretKey)

        .WithSSL(secure)

        .Build(); 
  • endPoint :MinIO服务启动的URL,注意自己启动服务的端口号;

  • accessKey :在MinIO控制台申请的Access Key;
  • secretKey:在MinIO控制台申请的Access Secret;

  • secure :布尔值(默认值  true),是否启用HTTPS;

三、管理存储桶

1、MyBucket类

在【Managers】文件夹中新建【MyBucket】类,用来管理存储桶;

【Managers/MyBucket.cs】

using Minio.DataModel.Args;
using Minio.Exceptions;
using Minio;
using Zyl_MinIO_Demo.Helper;
using Minio.DataModel.Result;

namespace Zyl_MinIO_Demo.Managers
{
    public class MyBucket
    {
        // 实例化 minioClient
        private static MinioClient minioClient = MinIO.CreateMinioClient();

        /// <summary>
        /// 1、判断bucket是否存在
        /// </summary>
        /// <param name="bucketName"></param>
        /// <returns></returns>
        public static async Task<string> IsExistStr(string bucketName){

            try
            {
                BucketExistsArgs args = new BucketExistsArgs().WithBucket(bucketName);

                bool found = await minioClient.BucketExistsAsync(args).ConfigureAwait(false);

                Console.WriteLine("found。。。。。。", found);

                if (found)
                {
                    Console.WriteLine($"{bucketName}桶已存在");
                    return $"{bucketName}桶已存在";
                }
                else
                {
                    Console.WriteLine($"{bucketName}桶不存在");
                    return $"{bucketName}桶不存在";
                }
            }
            catch (MinioException e)
            {
                Console.WriteLine("[Bucket]  Exception: {0}", e);
                return "出错啦!!!";
            }
        }

        /// <summary>
        /// 2、创建一个bucket
        /// </summary>
        /// <param name="bucketName"></param>
        /// <returns></returns>
        public static async Task<string> Create(string? bucketName)
        {
            try
            {
                BucketExistsArgs args = new BucketExistsArgs().WithBucket(bucketName);

                bool found = await minioClient.BucketExistsAsync(args).ConfigureAwait(false);

                if (found)
                {
                    return $"{bucketName}桶已存在";
                }
                else
                {
                    MakeBucketArgs makeBucketArgs = new MakeBucketArgs().WithBucket(bucketName);
                    await minioClient.MakeBucketAsync(makeBucketArgs).ConfigureAwait(false);

                    return $"{bucketName}桶已成功创建";
                }
            }
            catch (MinioException e)
            {
                Console.WriteLine("[Bucket]  Exception: {0}", e);
                return "出错啦!!!";
            }
        }

        /// <summary>
        /// 3、移除一个bucket
        /// </summary>
        /// <param name="bucketName"></param>
        /// <returns></returns>
        public static async Task<string> Delete(string? bucketName)
        {
            try
            {
                BucketExistsArgs args = new BucketExistsArgs().WithBucket(bucketName);

                bool found = await minioClient.BucketExistsAsync(args).ConfigureAwait(false);

                if (!found)
                {
                    return $"{bucketName}桶不存在";
                }
                else
                {
                    RemoveBucketArgs removeBucketArgs = new RemoveBucketArgs().WithBucket(bucketName);

                    await minioClient.RemoveBucketAsync(removeBucketArgs);

                    return $"{bucketName}桶删除成功";
                }
            }
            catch (MinioException e)
            {
                Console.WriteLine("[Bucket]  Exception: {0}", e);
                return "出错啦!!!";
            }
        }

        /// <summary>
        /// 4、获取已有的bucket列表
        /// </summary>
        /// <returns></returns>
        public static async Task<ListAllMyBucketsResult?> GetList()
        {
            try
            {
                return await minioClient.ListBucketsAsync();
            }
            catch (MinioException e)
            {
                Console.WriteLine("Error occurred: " + e);
                return null ;
            }
        }
    }
}

(1)判断bucket是否存在

Task<bool> BucketExistsAsync(BucketExistsArgs args)
  • 判断一个指定名称的存储桶是否存在
  • 返回一个布尔值true(存在),或false(不存在); 

(2)新建bucket

Task MakeBucketAsync(MakeBucketArgs args)
  • 创建一个指定名称的存储桶;
  • 创建失败,则返回异常信息;

(3)删除bucket 

Task RemoveBucketAsync(RemoveBucketArgs args)
  • 移除一个指定名称的存储桶;
  • 任务返回移除失败时的异常信息;
  • 当桶中有内容时,则不会被删除;

(4)获取bucket列表

Task<ListAllMyBucketsResult> ListBucketsAsync()
  • 用来获取buckets列表数据; 

2、BucketController

在Controllers文件夹下,新建一个空的API控制器,用来给前端人员暴露接口;

【Controllers/BucketController.cs】

using Microsoft.AspNetCore.Mvc;
using Minio;
using Minio.DataModel.Result;
using Zyl_MinIO_Demo.Managers;

namespace Zyl_MinIO_Demo.Controllers
{
    /// <summary>
    /// 管理 MinIO 中的 Bucket
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class BucketController : ControllerBase
    {
        /// <summary>
        /// 1、判断指定bucket是否存在
        /// </summary>
        /// <param name="bucketName">bucket 名称</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> IsBucketExit(string bucketName)
        {
            return await MyBucket.IsExist(bucketName) ?  $"{bucketName}桶已存在" : $"{bucketName}桶不存在";
        }

        /// <summary>
        /// 2、 创建bucket
        /// </summary>
        /// <param name="bucketName">bucket 名称</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> CreateBucket(string bucketName)
        {
            return await MyBucket.Create(bucketName);
        }

        /// <summary>
        /// 3、移除bucket
        /// </summary>
        /// <param name="bucketName">bucket 名称</param>
        /// <returns></returns>
        [HttpDelete]
        public async Task<string> DeleteBucket(string bucketName)
        {
            return await MyBucket.Delete(bucketName);
        }

        /// <summary>
        /// 4、获取bucket列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<ListAllMyBucketsResult?> GetBucketList()
        {
            return await MyBucket.GetList();
        }
    }
}

3、实现效果

启动项目,使用Swagger进行接口测试;

注意:

  • 需要确保,项目中已经配置了Swagger;
  • 需要确保,MinIO服务已经启动;

项目启动后的swagger页面:

 先在MinIO控制台中创建一个名为zyl的bucket;

(1)判断bucket是否存在

输入桶名,点击测试;

 执行后可以看到数据正常返回;

(2)新建bucket

(3)删除bucket

(4)获取bucket列表

四、管理文件

1、MyObject类

在【Managers】文件夹中新建【MyObject】类,用来管理存储桶中的文件对象;

【Managers/MyObject.cs】

using Minio.DataModel.Args;
using Minio;
using Zyl_MinIO_Demo.Helper;
using Minio.Exceptions;

namespace Zyl_MinIO_Demo.Managers
{
    public class MyObject
    {
        private static readonly MinioClient minioClient = MinIO.CreateMinioClient();
        
        /// <summary>
        /// 1、下载文件 到本地
        /// </summary>
        public async static Task<String> DownloadFile(string bucketName, string objectName) {
            try
            {
                string folderPath = "D:\\minio-download-files\\";
                if (!Directory.Exists(folderPath)) {
                    DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);
                    directoryInfo.Create();
                }
                
                StatObjectArgs statObjectArgs = new StatObjectArgs()
                                                    .WithBucket(bucketName)
                                                    .WithObject(objectName);
                await minioClient.StatObjectAsync(statObjectArgs);
                
                GetObjectArgs getObjectArgs = new GetObjectArgs()
                                                  .WithBucket(bucketName)
                                                  .WithObject(objectName)
                                                  .WithFile(folderPath + objectName);
                await minioClient.GetObjectAsync(getObjectArgs);
                return "Success";
            }
            catch (MinioException e)
            {
                return $"Failure\r\n{e.Message}";
            }
        }

        /// <summary>
        /// 2、上传文件 指定文件
        /// </summary>
        public async static Task<string> UploadFile(string bucketName,string fileFullPath)
        {
            try
            {
                // 判断bucket是否存在
                bool isExit = await MyBucket.IsExist(bucketName);

                if (!isExit)
                {
                    Console.Out.WriteLine($"{bucketName}桶不存在");

                    return $"{bucketName}桶不存在,文件上传失败";
                }

                string objectName = fileFullPath.Split("\\")[^1];

                // 上传文件
                PutObjectArgs putObjectArgs = new PutObjectArgs()
                    .WithBucket(bucketName)
                    .WithObject(objectName)
                    .WithFileName(fileFullPath)
                    .WithContentType("application/octet-stream");
                await minioClient.PutObjectAsync(putObjectArgs).ConfigureAwait(false);

                return $"{objectName}上传成功";
            }
            catch (Exception e)
            {
                return $"Failure\r\n{e.Message}";
            }
        }

        /// <summary>
        /// 3、删除 指定文件
        /// </summary>
        public async static Task<string> DeleteFile(string bucketName, string objectName)
        {
            try
            {
                // 判断bucket是否存在
                bool isExit = await MyBucket.IsExist(bucketName);

                if (!isExit)
                {
                    return $"{bucketName}桶不存在,文件删除失败";
                }

                RemoveObjectArgs removeObjectArgs = new RemoveObjectArgs()
                                .WithBucket(bucketName)
                                .WithObject(objectName);
                await minioClient.RemoveObjectAsync(removeObjectArgs);

                return $"{bucketName}桶中的{objectName}文件删除成功";
            }
            catch (MinioException e)
            {
                return $"Failure\r\n{e.Message}";
            }
        }

        /// <summary>
        /// 4、获取指定文件的url链接
        /// </summary>
        public async static Task<String> GetFileUrl(string bucketName, string objectName)
        {
            try
            {
                PresignedGetObjectArgs args = new PresignedGetObjectArgs()
                        .WithBucket(bucketName)
                        .WithObject(objectName)
                        .WithExpiry(60 * 60 * 24 * 7);
                return await minioClient.PresignedGetObjectAsync(args);
            }
            catch (MinioException e)
            {
                return $"Failure\r\n{e.Message}";
            }
        }
    
    }
}

(1)下载文件对象

Task GetObjectAsync(GetObjectArgs args)
  •  用来下载一个文件对象,并保存到本地;

(2)上传文件对象

Task PutObjectAsync(PutObjectArgs args)
  •  若上传的文件名于之前相同,则会覆盖;

(3)删除文件对象

Task RemoveObjectAsync(RemoveObjectArgs args)

(4)获取文件对象URL

Task<string> PresignedGetObjectAsync(PresignedGetObjectArgs args)
  • 返回的URL可用来直接下载该文件对象;
  • 返回的URL有效期为7天(默认),也可以自行设置(秒数);

2、ObjectController 

【Controllers/ObjectController.cs】

using Microsoft.AspNetCore.Mvc;
using Zyl_MinIO_Demo.Managers;

namespace Zyl_MinIO_Demo.Controllers
{
    /// <summary>
    /// 管理 MinIO对象(默认zyl bucket桶)
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class ObjectController : ControllerBase
    {
        /// <summary>
        /// 1、下载 bucket中的文件
        /// </summary>
        /// <remarks>
        /// 会保存在 D:\\minio-download-files 文件夹内;
        /// 若本地D盘中没有该文件夹,则会自动创建;
        /// </remarks>
        /// <param name="objectName">文件名</param>
        /// <param name="bucketName">桶名,默认zyl</param>
        [HttpPost]
        public async Task<string> DownloadObject( string objectName, string bucketName = "zyl")
        {
            return await MyObject.DownloadFile(bucketName, objectName);
        }

        ///<summary>
        /// 2、上传 本地指定文件
        /// </summary>
        /// <remarks>
        /// 上传同名文件,会覆盖之前的
        /// </remarks>
        /// <param name="fileFullPath">上传文件的完整绝对路径,例如:D:\test\test.txt</param>
        /// <param name="bucketName">桶名,默认zyl</param>
        [HttpPost]
        public async Task<string> UploadObject(string fileFullPath, string bucketName = "zyl")
        {
            return await MyObject.UploadFile(bucketName, fileFullPath);
        }

        /// <summary>
        /// 3、删除 指定桶中的指定文件
        /// </summary>
        /// <param name="objectName">文件名</param>
        /// <param name="bucketName">桶名,默认zyl</param>
        [HttpDelete]
        public async Task<string> DeleteObject(string objectName, string bucketName = "zyl")
        {
            return await MyObject.DeleteFile(bucketName, objectName);
        }

        /// <summary>
        /// 4、获取 指定文件的Url链接 (有效期 7天)
        /// </summary>
        /// <remarks>
        /// 只能是已经存在于minio中的任意文件
        /// </remarks>
        /// <param name="objectName">文件名</param>
        /// <param name="bucketName">桶名,默认zyl</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> GetObjectUrl(string objectName, string bucketName = "zyl") {
            return await MyObject.GetFileUrl(bucketName, objectName);
        }

    }
}

3、实现效果

在Swagger页面,可以看到我们新增的文件对象相关接口;

(1)下载指定文件

  • 这里的默认bucket,确保在使用之前已经创建;
  • 文件会下载到本地D盘的【minio-downlo-files】文件夹中,没有该文件夹会自动创建;

(2)上传指定文件

  • 第一个参数应该填写待上传文件的完整绝对路径,这里上传的是D盘下test文件夹中的text.txt文件;
  • 上传到minio服务中的文件名取自待上传的文件名,若与之前的文件名相同,会进行覆盖;

(3)删除指定文件 

(4)获取指定文件URL 

  • 需要确保minio中已经上传了该文件;
  • 将返回的URL链接放在浏览器的地址栏,按回车即可下载查看;

 ​

======================================================================

每天进步一点点,记录一下MinIO的学习笔记;

刚开始接触后端,代码略显生涩,嘻嘻嘻;

还望走过路过的各位大佬多多指点~ 

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

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

相关文章

一键解决外勤难题,精细化管理轻松get!

行程打卡是企业总部和分店、销售管理与销售、行政与员工保持信息对称的重要方式&#xff0c;也是区域负责人、督导和行政日常重要的工作之一。 行程打卡不仅承载着确保品牌运营的标准性和一致性的目标&#xff0c;同时也是为了收集行程各阶段存在的问题和不足&#xff0c;对后续…

Win11 搭建 Java 开发环境(JDK)

Win11 搭建 Java 开发环境(JDK) 前言步骤1、下载 JDK2、安装 JDK3、配置环境变量(我设置的顺序可不是随便的哟~)3-1、设置 JAVA_HOME_11和 JAVA_HOME3-2、设置 PATH3-3、设置 CLASS_HOME备注1、可以不必再手动配置 CLASSPATH2、恢复 jre 文件夹(有没有 jre 文件夹其实不影…

实体零售连锁企业如何通过物流接口实现数智化转型升级?

在电子商务浪潮的持续冲击下&#xff0c;传统的实体零售行业面临着巨大的挑战。为了在线上线下融合的新零售时代保持竞争力&#xff0c;众多实体零售企业积极寻求数字化转型的突破。 某中国零售连锁百强企业近年来致力于打造自有品牌的线上销售体系&#xff0c;自2021年8月起接…

双减期末考试成绩怎么公布?

考试一直是衡量学生学习成果的重要手段。不过&#xff0c;随着"双减"政策的实施&#xff0c;我们就不得不重新审视传统的成绩公布方式。期末考试成绩&#xff0c;这个曾经让无数学生心跳加速的数字&#xff0c;如今该如何以一种更加合理、公正的方式呈现给学生和家长…

第1章 物联网模式简介---物联网概述

物联网模式简介 物联网&#xff08;IoT&#xff09;在最近几年获得了巨大的吸引力&#xff0c;该领域在未来几年将呈指数级增长。这一增长将跨越所有主要领域/垂直行业&#xff0c;包括消费者、家庭、制造业、健康、旅游和运输。这本书将为那些想了解基本物联网模式以及如何混…

【知识学习】Unity3D中GPU Instance的概念及使用方法示例

在Unity3D中&#xff0c;GPU Instancing是一种优化技术&#xff0c;它允许开发者在不增加Draw Call&#xff08;绘制调用&#xff09;的情况下&#xff0c;通过GPU绘制多个具有相同Mesh和Material但可能具有不同变换&#xff08;位置、旋转、缩放&#xff09;的对象实例。 GPU…

linux中 nginx+tomcat 部署方式 tomcat挂掉设置自动启动

在Linux环境下&#xff0c;要实现当Tomcat挂掉后自动重启&#xff0c;可以通过编写Shell脚本结合cron定时任务或者使用系统守护进程&#xff08;如Systemd、Upstart或SysVinit&#xff09;来完成。 使用Shell脚本和cron定时任务 编写检查并重启Tomcat的Shell脚本&#xff1a;首…

1976 ssm 营地管理系统开发mysql数据库web结构java编程计算机网页源码Myeclipse项目

一、源码特点 ssm 营地管理系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开…

【管理咨询宝藏137】RB大型卡车集团供应链体系优化设计方案中期汇报

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏137】RB大型卡车集团供应链体系优化设计方案中期汇报 【格式】PDF版本 【关键词】罗兰贝格、供应链管理、运营提升 【核心观点】 - 甲方采取销售…

Parallels Toolbox for mac(pd工具箱) 6.0.2激活版

Parallels Toolbox 是由 Parallels 公司开发的一款实用工具集合软件&#xff0c;它主要面向使用 Parallels Desktop 的用户&#xff0c;提供了许多方便用户在 macOS 和 Windows 之间进行切换和管理的工具。Parallels Desktop 是一款流行的虚拟化软件&#xff0c;允许用户在 mac…

c++ 设计模式 的课本范例(上)

( 0 ) 这里补充面向对象设计的几个原则&#xff1a; 开闭原则 OCP &#xff1a; 面向增补开放&#xff0c;面向代码修改关闭。其实反映到代码设计上就是类的继承&#xff0c;通过继承与多态&#xff0c;可以不修改原代码&#xff0c;又增加新的类似的功能。 依赖倒置原则 Depen…

golang 获取系统的主机 CPU 内存 磁盘等信息

golang 获取系统的主机 CPU 内存 磁盘等信息 要求 需要go1.18或更高版本 官方地址&#xff1a;https://github.com/shirou/gopsutil 使用 #下载包 go get github.com/shirou/gopsutil/v3/cpu go get github.com/shirou/gopsutil/v3/disk go get github.com/shirou/gopsuti…

C语言指针速成下篇

c语言的指针下篇终于迎来了收尾&#xff0c;那么废话不多说&#xff0c;我们直接进入正题 指针访问数组 # include <stdio.h> int main () { int arr[ 10 ] { 0 }; // 输⼊ int i 0 ; int sz sizeof (arr)/ sizeof (arr[ 0 ]); // 输⼊ int * p arr //这…

Linux命令 wc(word count)-l(lines)用于统计文件中的行数。

文章目录 1、wc -l2、实战3、wc --help 1、wc -l 在命令 wc -l 中&#xff0c;-l 的英文全称是 lines。这个选项用于指定 wc&#xff08;word count&#xff0c;单词计数&#xff09;命令来统计文件的行数。 例如&#xff0c;当你运行 wc -l load_user_100w_sort.sql 时&…

ElasticSearch安装、配置详细步骤

一、环境及版本介绍 操作系统&#xff1a; Windows 10 软件版本&#xff1a; elasticsearch-7.17.22、kibana-7.17.22、IK-7.17.22 开发环境选择软件版本应提前考虑正式系统环境&#xff0c;否则会产生软件与服务器环境不兼容的问题出现&#xff0c;ElasticSearch与环境支持…

龙迅#LT6911GXC支持HDMI2.1转MIPI/4PORT LVDS应用功能,分辨率高达8K30HZ/4K120HZ压缩格式。

1. 描述 该LT6911GXC是一款高性能HD-DVI2.1转MIPI或LVDS芯片&#xff0c;适用于VR/显示应用。 HDCP RX作为HDCP中继器的上游&#xff0c;可以与其他芯片的HDCP TX配合实现中继器功能。 对于 HD-DVI2.1 输入&#xff0c;LT6911GXC可以配置为 3/4 通道。 对于MIPI输出&#xff0c…

vue2使用wangEditor5搭建模拟文档的编辑器快速集成

如图 1、下载依赖 2、elm引入&#xff08;可省略&#xff09; main.js 或者 按需引入 3、cv <template><div style"background: #f1f3f4"><div style"width: 100%; height: 42px"><!-- 工具栏 --><Toolbarid"tool-conta…

SAP中通过财务科目确定分析功能来定位解决BILLING问题实例

接用户反馈&#xff0c;一笔销售订单做发货后做销售发票时&#xff0c;没有成功过账到财务&#xff0c;提示财户确定错误。 这个之前可以通过VF02中点击小绿旗来重新执行过财动作&#xff0c;看看有没有相应日志来定位问题。本次尝试用此方法&#xff0c;也没有找到相关线索。 …

英国牛津大学博士后职位—统计学

牛津大学&#xff08;University of Oxford&#xff09;&#xff0c;简称“牛津”&#xff08;Oxford&#xff09;&#xff0c;位于英国牛津&#xff0c;是一所公立研究型大学&#xff0c;采用传统学院制。是罗素大学集团成员&#xff0c;被誉为“金三角名校”、“G5超级精英大…