Java 项目实战: 交友项目 - 阿里云 OSS 对象存储介绍

概述

交友项目的头像要存在一个独立于应用服务器的公共可访问位置。本篇把「阿里云 OSS 这个产品本身」讲清楚:它是什么、有哪几个核心概念、控制台怎么点、接入之前要准备什么。至于为什么在本地磁盘 / 分布式文件系统 / 第三方云存储里选了它,属于选型话题,见同系列《文件存储方案介绍》。

纲要

  • 一句话定位:OSS 不是"一块磁盘",而是"键值对式的对象仓库"
  • 核心概念:Bucket、Object、Region、Endpoint、AccessKey
  • 用一个真实 URL 把五个概念串起来
  • 控制台操作路径(创建 Bucket → 文件列表 → 权限 → 基础设置 → 用量费用)
  • 读写权限:私有 / 公共读 / 公共读写,以及签名 URL
  • 存储类型与成本分档
  • 计费四个维度,以及哪一项最容易超预算
  • OSS 的进阶能力(点到为止)
  • 接入前准备清单,以及与配置项的对应关系
  • 常见误解澄清

OSS 是什么

阿里云对象存储 OSS(Object Storage Service)官方定义是:一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件,容量和处理能力弹性扩展。落到工程里,它的使用方式只有一句话:通过 HTTP RESTful API 往里面放文件、从里面取文件。

这里有个认知必须先纠正,否则后面全乱:OSS 不是一块能 ls、能 cd 的磁盘,它是一个键值对仓库。 你给它一个 key,它还你一段 value;没有目录层级,没有 inode,没有"文件夹"这个实体的概念。你在控制台里看到的那些"文件夹",只是 key 里带了斜杠前缀后的显示效果------avatar/2026/09/a.jpg 是一个完整的 key,avatar/2026/09/ 并不真实存在。

对比着看更清楚:

维度 传统文件系统 阿里云 OSS
基本单位 文件(有 inode) Object(key + data + meta)
层级结构 真实目录树 扁平,斜杠只是 key 的命名约定
访问方式 本地路径 / 挂载 HTTP(S) URL 或 SDK
扩容 加盘、迁移、做 RAID 无感知,容量自动扩展
重命名目录 mv 即可 实质是复制每个 key 再删旧的,代价高
定位 给操作系统用 给应用程序用

最后一行值得强调:OSS 是面向应用的 API 存储服务,不是给人用的同步网盘。它的设计目标是程序化地存海量非结构化数据(图片、视频、备份、日志),而不是让你拖拽文件做版本同步。

五个核心概念

先把五个概念摆在一张表里,再逐个展开。

概念 是什么 关键约束
Bucket 存储空间,对象的容器 名称全局唯一,归属某个 Region
Object 存储的基本单元 由 Key + Data + Meta 组成,Key 在 Bucket 内唯一
Region Bucket 所在的地理区域 决定了 Endpoint,选离用户近的
Endpoint 访问服务的入口域名 随 Region 变化,不是固定的
AccessKey 身份凭据(AK/SK) 必须走 RAM 子账号 + 最小权限

Bucket(存储空间)

Bucket 是对象的容器,译过来就是"桶"。名称必须全局唯一 ------不是在你的账号内唯一,而是全阿里云所有用户里唯一。原因很直接:Bucket 名会直接出现在访问 URL 的域名部分(https://{bucket}.{endpoint}/...),如果允许重名,DNS 就不知道该解析到谁的存储。项目项目里用的 Bucket 名是 tanhua001。

一个 Bucket 绑定一个 Region,创建时选定,之后不能改。同一账号可以在不同 Region 建多个 Bucket。Bucket 上还能挂一堆配置:读写权限、生命周期规则、防盗链、跨域、版本控制等,后面会逐个提到。

Object(对象)

Object 是 OSS 里存东西的基本单元。它由三部分组成:

  • Key(对象名):对象的唯一标识,在同一个 Bucket 内不能重复
  • Data(内容):文件本体,字节流
  • Meta(元数据) :描述信息,分两类。一类是 HTTP 标准头(Content-Type、Content-Length、Last-Modified 等),另一类是用户自定义元数据(以 x-oss-meta- 开头的键值对,比如给图片挂个 author、source)

Key 可以带斜杠来"模拟"目录,比如 avatar/2026/09/2f9b3f7a.jpg。但请记住这只是命名约定:当你调 putObject 传这个 key 时,OSS 不会真的去建三层目录 ,它只是把这个字符串当作一整个键存下来。好处是取的时候同样按字符串前缀定位,配合 prefix 参数就能列出"某个虚拟目录下的所有对象";坏处是"移动目录"这类操作在 OSS 上没有廉价实现。

Region(地域)

Region 是 Bucket 所在的地理区域,控制台上表现为"华东1(杭州)""华北2(北京)"这类选项。选 Region 的原则只有一条:离你的用户近。项目项目服务端在北京,用户也主要在国内,所以 Bucket 建在华北2(北京)。

不这么做会踩两个坑:一是跨 Region 访问的延迟会更明显 ,二是跨 Region 的流量会产生额外费用。所以别为了"某个区域便宜一点"就把 Bucket 建在离用户很远的地方,省下的存储费还不够填流量费的坑。

Region 与 Endpoint 是一一对应的:选了北京,Endpoint 就是 oss-cn-beijing.aliyuncs.com。

Endpoint(访问域名)

Endpoint 是访问 OSS 服务的入口地址,格式形如 oss-cn-beijing.aliyuncs.com(华东1杭州则是 oss-cn-hangzhou.aliyuncs.com)。它随 Region 变化,不是固定值,这一点很多人第一次接触时会记错。

存取对象时,实际访问地址通常长这样:

text 复制代码
https://{bucket}.{endpoint}/{key}

也就是把 Bucket 名拼在 Endpoint 前面当子域名。传给 SDK 的 Endpoint 一般不带 https:// 前缀(如 oss-cn-beijing.aliyuncs.com),也有的写法会带上协议头,两种都能用,看 SDK 对签名的处理。SDK 内部会拿这个地址去计算签名并拼出真实请求 URL。

AccessKey(访问密钥)

AccessKey 是一对身份凭据:AccessKey ID(标识)加 AccessKey Secret(密钥),合称 AK/SK。程序调用 OSS API 时用它来证明"我是谁"。

这里有一条不能破的规矩:不要用主账号的 AccessKey,要用 RAM 子账号,并且只授予需要的那一个 Bucket 的权限 。主账号 AK 拥有全账号所有资源的访问权,一旦泄露,等于把整个云账号交出去。RAM(访问控制)子账号可以精确授权,比如"只允许读写 tanhua001 这个 Bucket"。

还有一条同样重要:AK 绝不能硬编码进代码仓库。项目项目把它写在配置里(见下文配置项),但要清楚这是教学环境的做法,生产环境应该走配置中心加密或者 RAM 角色临时凭据。讲义里那行注释写得很直白:主账号 AccessKey 拥有所有 API 访问权限,风险很高,强烈建议创建并使用 RAM 账号。

用一个 URL 串起五个概念

抽象概念讲完了,用项目项目里一个真实的图片地址把它们串起来。这一段是理解 OSS 最有效的方式:

text 复制代码
https://tanhua001.oss-cn-beijing.aliyuncs.com/avatar/2026/09/2f9b3f7a-9c1e-4d3a.jpg
└─┬──┘ └──┬───┘ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘
 协议   Bucket名      Endpoint        Region 编码         Object 的 Key
      └──────────── 访问域名(Bucket + Endpoint)────────────┘

按段拆开:

片段 对应概念 说明
https 协议 OSS 走标准 HTTP/HTTPS
tanhua001 Bucket 全局唯一的桶名,作为子域名出现
oss-cn-beijing.aliyuncs.com Endpoint 由 Region(华北2北京)决定
avatar/2026/09/2f9b3f7a....jpg Object 的 Key 含斜杠前缀,但整体是一个 key

那么 Region 和 AccessKey 在哪?Region 是隐含在 Endpoint 里的------oss-cn-beijing 这个编码就代表了地域;AccessKey 则不出现在 URL 里,它是调用方在发请求时用来签名的凭据,只对写操作或私有 Bucket 的读操作生效。公共读的图片,任何人拿着这个 URL 直接就能打开,URL 里看不出任何身份信息。

这也就解释了为什么 Bucket 名要全局唯一------它实实在在占着一个 DNS 子域名。

一次完整的"上传 + 访问"链路,本质就是拿着这套地址把文件放进去、再把地址记下来:
#mermaid-svg-8DVirRaLy5gRfY9V{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8DVirRaLy5gRfY9V .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8DVirRaLy5gRfY9V .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8DVirRaLy5gRfY9V .error-icon{fill:#552222;}#mermaid-svg-8DVirRaLy5gRfY9V .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8DVirRaLy5gRfY9V .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8DVirRaLy5gRfY9V .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8DVirRaLy5gRfY9V .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8DVirRaLy5gRfY9V .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8DVirRaLy5gRfY9V .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8DVirRaLy5gRfY9V .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8DVirRaLy5gRfY9V .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8DVirRaLy5gRfY9V .marker.cross{stroke:#333333;}#mermaid-svg-8DVirRaLy5gRfY9V svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8DVirRaLy5gRfY9V p{margin:0;}#mermaid-svg-8DVirRaLy5gRfY9V .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8DVirRaLy5gRfY9V .cluster-label text{fill:#333;}#mermaid-svg-8DVirRaLy5gRfY9V .cluster-label span{color:#333;}#mermaid-svg-8DVirRaLy5gRfY9V .cluster-label span p{background-color:transparent;}#mermaid-svg-8DVirRaLy5gRfY9V .label text,#mermaid-svg-8DVirRaLy5gRfY9V span{fill:#333;color:#333;}#mermaid-svg-8DVirRaLy5gRfY9V .node rect,#mermaid-svg-8DVirRaLy5gRfY9V .node circle,#mermaid-svg-8DVirRaLy5gRfY9V .node ellipse,#mermaid-svg-8DVirRaLy5gRfY9V .node polygon,#mermaid-svg-8DVirRaLy5gRfY9V .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8DVirRaLy5gRfY9V .rough-node .label text,#mermaid-svg-8DVirRaLy5gRfY9V .node .label text,#mermaid-svg-8DVirRaLy5gRfY9V .image-shape .label,#mermaid-svg-8DVirRaLy5gRfY9V .icon-shape .label{text-anchor:middle;}#mermaid-svg-8DVirRaLy5gRfY9V .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8DVirRaLy5gRfY9V .rough-node .label,#mermaid-svg-8DVirRaLy5gRfY9V .node .label,#mermaid-svg-8DVirRaLy5gRfY9V .image-shape .label,#mermaid-svg-8DVirRaLy5gRfY9V .icon-shape .label{text-align:center;}#mermaid-svg-8DVirRaLy5gRfY9V .node.clickable{cursor:pointer;}#mermaid-svg-8DVirRaLy5gRfY9V .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8DVirRaLy5gRfY9V .arrowheadPath{fill:#333333;}#mermaid-svg-8DVirRaLy5gRfY9V .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8DVirRaLy5gRfY9V .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8DVirRaLy5gRfY9V .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8DVirRaLy5gRfY9V .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8DVirRaLy5gRfY9V .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8DVirRaLy5gRfY9V .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8DVirRaLy5gRfY9V .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8DVirRaLy5gRfY9V .cluster text{fill:#333;}#mermaid-svg-8DVirRaLy5gRfY9V .cluster span{color:#333;}#mermaid-svg-8DVirRaLy5gRfY9V div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8DVirRaLy5gRfY9V .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8DVirRaLy5gRfY9V rect.text{fill:none;stroke-width:0;}#mermaid-svg-8DVirRaLy5gRfY9V .icon-shape,#mermaid-svg-8DVirRaLy5gRfY9V .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8DVirRaLy5gRfY9V .icon-shape p,#mermaid-svg-8DVirRaLy5gRfY9V .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8DVirRaLy5gRfY9V .icon-shape .label rect,#mermaid-svg-8DVirRaLy5gRfY9V .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8DVirRaLy5gRfY9V .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8DVirRaLy5gRfY9V .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8DVirRaLy5gRfY9V :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1. 上传图片
2. 调 OSS API

putObject
3. 返回访问地址
4. 存地址入库
5. 用地址访问图片
6. 从数据库取地址
客户端
Java 服务端
阿里云 OSS
数据库

关键点在第 3、4 步:上传成功后一定要取到 OSS 返回的访问地址并落库,否则文件在云上、你却不知道它在哪。后面客户端要显示这张图,直接拿这个地址就能打开,不再经过 Java 服务端。

控制台要会用

开发阶段,控制台里出现频率最高的其实是"文件列表"这个界面:上传完之后去看一眼,确认文件是不是真的进去了。完整路径如下。

tree 复制代码
阿里云控制台
├── 对象存储 OSS
│   ├── Bucket 列表        # 创建 / 管理所有桶
│   │   └── tanhua001
│   │       ├── 文件管理    # ★ 最常用:看文件是否真的上传成功
│   │       │   ├── 上传 / 下载 / 删除
│   │       │   └── 获取文件 URL(可设有效期)
│   │       ├── 权限管理    # 读写权限:私有 / 公共读 / 公共读写
│   │       ├── 基础设置    # 防盗链 / 生命周期 / 跨域 CORS
│   │       └── 用量查询    # 存储量 / 流量 / 请求次数
│   └── 概览
└── 访问控制 RAM
    ├── 用户               # 创建子账号,拿 AK
    └── 权限策略           # 只授权指定 Bucket

进入某个 Bucket 后左侧菜单固定是这几项:文件管理、权限管理、基础设置、用量查询。日常用不到的一半,但权限管理和文件管理两个入口必须熟练------前者决定"上传成功却打不开"会不会发生,后者是你排查一切上传问题的第一现场。

读写权限要讲透

读写权限是"文件明明上传成功、URL 却打不开"这类问题的头号根因。三种权限的行为差异如下:

权限 谁能读 谁能写 访问方式 安全风险
私有 仅授权账号 仅授权账号 必须带签名(或签名 URL) 最低,默认推荐
公共读 任何人 仅授权账号 直接 GET URL 即可 内容对外公开
公共读写 任何人 任何人 任何人可 PUT/DELETE 极高,等于开放存储桶

「公共读写」听起来方便,实际是安全事故的高发点:任何人都能往你的桶里塞文件、也能删你的文件,最坏的情况是被当作恶意内容的分发站,费用和合规风险都由你承担。除非明确知道自己在做什么,否则不要选。

「私有」是最安全的默认值,但私有不等于不能对外提供访问。OSS 提供了签名 URL 机制:服务端用 AK 对 URL 计算一个带时效的签名,客户端拿着这个 URL 就能在过期前临时访问私有对象,过期后自动失效。这样既能控制访问窗口,又不用把 Bucket 开放出去。项目项目里存私密内容时走的就是私有 + 签名 URL。

「公共读」则适合本就该公开的资源------公开的头像、动态配图。项目项目教程里把 Bucket 设成了这一类,因为上传要鉴权、查看要人人可及。

顺带说清一个易混点:读写权限是 Bucket 级的默认值,但单个 Object 也可以单独设置 ACL 覆盖它。

存储类型与成本

OSS 按"访问频率高低"把存储分成几档。越冷的数据存得越便宜,但取回时越慢、越贵。

存储类型 适用数据 取回成本 取回延迟
标准 频繁访问的热数据 无额外取回费 毫秒级
低频访问 偶尔访问(如一月几次) 有取回费 毫秒级
归档 很少访问(如一年几次) 取回费较高 分钟级
冷归档 几乎不访问的长期留存 取回费最高 小时级

选型的逻辑是"热数据用标准、冷数据往下沉",而且可以配生命周期规则 自动下沉:比如规定"上传满 30 天后转低频、满 180 天转归档"。项目项目的头像需要即时访问、随时展示,所以用标准存储,不做下沉。

注意趋势是反的:存储单价从标准到冷归档越来越低,但取回费用和延迟越来越高。如果你为了省存储费把热数据沉到冷归档,用户访问时既慢又要付高额取回费,算总账反而更贵。

计费四个维度

OSS 的花费由四块构成,读者最该关心的是第二块。

计费项 计什么 量级认知
存储容量 存了多少 GB(按月均) 单价低,通常不是大头
流量 下行(外网流出)收费,上行(上传)免费 最容易超预算的一项
请求次数 API 调用次数 单价极低,一般可忽略
CDN 回源 接了 CDN 后的回源流量 另计,取决于 CDN 配置

"上传免费、下载收费" 这条要记牢,很多人以为上传也要流量费。实际是:你把图片 putObject 上去不花钱,用户每次打开这张图(外网流出)才计费。低峰期无所谓,一旦图片被大量访问,下行流量就是账单暴涨的主因。

如果流量压力大,通常的解法是接 CDN:让 CDN 缓存图片,用户从边缘节点取,回源次数大幅减少,下行流量费转为更便宜的 CDN 流量费。代价是回源流量另计,需要算总账。

具体单价随地域和活动浮动,以阿里云官方定价页为准,这里不给死数字。

进阶能力(点到为止)

知道边界就行,本篇不展开:

  • 图片处理 :上传原图后,通过在 URL 后缀参数(如 ?x-oss-process=image/resize,w_200)实时生成缩略图、水印、裁剪,不用自己写图片处理代码。项目项目的头像缩略图很可能用得上这一招------存一张原图,展示时按需出小图。
  • 跨区域复制:把对象自动复制到另一个 Region 的 Bucket,用于容灾或就近访问。
  • 版本控制:同名 key 覆盖时保留历史版本,可回滚。开启后会额外产生存储费。
  • 静态网站托管:把 Bucket 当静态站点根目录直接对外提供网页。
  • 与 CDN 联动:把 Bucket 作为 CDN 源站。

接入前准备清单

真正开始写代码前,这四步是前置条件,缺一不可:

步骤 做什么 产出
开通服务 注册阿里云账号 → 开通对象存储 OSS 可用 OSS 的账号
创建 Bucket 选 Region(北京)、设读写权限(公共读)、存储类型标准 Bucket 名 tanhua001
创建 RAM 用户并授权 建子账号,只授予该 Bucket 的读写权限 AccessKey ID / Secret
准备配置项 收集 Endpoint、BucketName、访问域名 三个配置值

这几步的结果,直接对应到项目里 OssProperties 的字段。实读项目工程 tanhua-autoconfig 模块的配置类:

java 复制代码
package com.tanhua.autoconfig.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "tanhua.oss")
public class OssProperties {

    private String accessKey;   // RAM 子账号的 AccessKey ID
    private String secret;      // RAM 子账号的 AccessKey Secret
    private String bucketName;  // 全局唯一的桶名,如 tanhua001
    private String url;         // 访问域名(含协议头,末尾带斜杠)
    private String endpoint;    // 随 Region 变化,如 oss-cn-beijing.aliyuncs.com
}

对应的配置(教程工程 application.yml 的实际内容):

yaml 复制代码
tanhua:
  oss:
    accessKey: 你的AccessKeyId
    secret: 你的AccessKeySecret
    endpoint: oss-cn-beijing.aliyuncs.com
    bucketName: tanhua001
    url: https://tanhua001.oss-cn-beijing.aliyuncs.com/

五个字段和前面五个概念一一对上:accessKey + secret 是 AccessKey 那一对,bucketName 是 Bucket,endpoint 是 Endpoint,url 则是拼好的访问域名前缀------上传完拿到返回的 key 之后,用它拼出可直接访问的完整地址。注意这里的 AK 是教程写死的示例值,别照抄,更别提交进 git。

常见误解澄清

  • 以为 OSS 有目录结构 :没有。avatar/2026/09/ 只是一个 key 前缀,斜杠是命名约定,不是物理目录。
  • 以为 Bucket 名可以随便取 :不行,全局唯一,因为要占 DNS 子域名。
  • 以为上传也收流量费 :上传(上行)免费,下载(下行)才收费。
  • 以为公共读最省事就全用它 :私密内容必须用私有 + 签名 URL,公共读只适用于本就公开的资源。
  • 以为 Endpoint 是固定的 :它随 Region 变化 ,北京是 oss-cn-beijing.aliyuncs.com,杭州是 oss-cn-hangzhou.aliyuncs.com。
  • 以为 OSS 就是网盘 :它是面向应用的 API 存储服务,不是给人用的同步盘。

官方文档

总结

  • OSS 的本质是键值对对象仓库,key → value,没有真实目录层级,斜杠只是命名约定。
  • 五个概念构成访问路径:Bucket(容器)+ Region(决定 Endpoint)+ Endpoint(域名)+ Key(对象名)+ AccessKey(凭据)。
  • 一个 URL 就能把它们全串起来:https://{bucket}.{endpoint}/{key}。
  • 读写权限优先选私有 + 签名 URL,公共读留给公开资源,公共读写坚决不用。
  • 计费上下行流量最容易超预算,存储类型按访问热度分档,冷数据可自动下沉。
  • 接入前的四个准备动作,最终落成 OssProperties 的五个字段。

具体怎么用 SDK 把第一张图片传上去,见下一篇《阿里云oss:入门案例》;把上传能力封装成可复用的自动装配组件,见《阿里云oss:抽取自动装配组件》。

相关推荐
yyuuuzz1 小时前
云服务器部署 web 项目的进程常驻记录
运维·服务器·前端·阿里云·云计算·aws
Yyyyyy~1 小时前
【Maven】基础
java·maven
weixin_BYSJ19871 小时前
【计算机毕设】基于Spring_Boot_Vue的马拉松报名与选手成绩追踪系统05445
java·vue.js·spring boot·学习·spring·django·课程设计
ha_lydms2 小时前
String Functions(字符串函数)
大数据·hadoop·阿里云·spark·数据处理·dataworks·maxcompute
Shaoshing2 小时前
消息类型
java
2301_32241428042 小时前
springboot学生课堂出勤统计系统15835-计算机毕设 原创(免费领源码+部署教程+开发环境)
java·mysql·随机森林·微信小程序·uni-app·微信开发者工具·推荐算法
程序员夏洛3 小时前
VMware Workstation Pro 卸载失败:安装向导提前结束、错误 1603 的排查与解决
java
User_芊芊君子3 小时前
【JavaEE初阶 - 网络原理】网络分几层?从自定义协议聊到 DNS
java·网络·java-ee
聚美智数10 小时前
智能结构化识别-图片结构解析-图像结构化解析-照片结构化解析
android·java·数据库