1月30号晚上,整理完当天的学习笔记已经快十一点了。后端这行学得越深,越觉得“接口”这两个字能延伸出一大串问题:后端到底在提供什么?前端拿到数据之后怎么展示?一个请求从发出到返回,中间究竟经过了哪些环节?今天这篇“后端学习日记1.30”我就把头一天积压下来的这些问题从头到尾捋了一遍,顺便把一个最简单的SpringBoot后端项目从零搭起来,也踩了不少启动失败、跨域、字段精度上的坑。这篇内容适合两类人:一类是刚走完Java基础、准备往后端开发方向走的人;另一类是已经能写接口,但一直没搞懂前后端怎么对接、数据库配置在哪看、为什么BigInt字段传回前端就变精度、Base64文件流怎么处理这类实际问题的人。
1. 后端接口到底是个啥
1.1 接口不是玄学
很多人刚开始学后端,经常听到一句话:“后端就是提供接口的。”然后就开始困惑,接口是什么?跟Java里的interface是一个东西吗?其实不是一回事,但又有一点点联系。
后端开发说的接口,本质上就是一个“约定好的入口地址”。前端通过这个地址,把要处理的事情告诉后端,后端再根据规则返回结果。日常去餐厅吃饭就是最贴近的例子:菜单就是接口文档,你跟服务员说的“来一份宫保鸡丁”就是一次请求,后厨做出来的菜就是响应结果。你不需要关心后厨用什么锅、什么火候,只要菜能端上来就行。后端接口对前端来说也是这样,前端不需要关心数据库里到底怎么存的,只要按接口约定把参数传过去,就能拿到自己想要的数据。
一个标准接口,包含以下几样东西:请求地址、请求方式、请求参数、返回数据格式。请求地址决定了你去哪台服务器上的哪个方法;请求方式决定了这件事是“查一下”“建一个”“改一下”还是“删一条”,对应HTTP协议里的GET、POST、PUT、DELETE;请求参数是前端带给后端的信息;返回数据则是后端给前端的反馈。
我现在给新手讲后端,一定会先让对方建立一个认知:不要觉得接口是个高大上的东西,它就是一个“传话渠道”,把前端想要的数据从数据库里搬出来,再把前端要保存的东西写进数据库。搞明白这个本质,后面学再多的框架也不会迷路。
1.2 一个接口从请求到返回的完整链路
如果你在浏览器里打开一个带搜索功能的页面,输入关键词点搜索,你肉眼看到的是页面“唰”一下刷出了数据。但背后发生的事,其实是一条很长很长的链路。
前端页面上的搜索框,先把关键词变成一串HTTP请求,发到后端服务器。后端服务器收到请求后,先判断这个请求应该交给哪个“处理器”,这个过程叫路由分发。在SpringBoot里,就是通过@RequestMapping这类注解找到对应的Controller方法。Controller拿到参数之后,一般不会自己去数据库查,而是会交给Service层去处理。Service层是后端项目的业务核心,这里会做参数校验、业务判断,比如关键词是不是空的、要查哪些字段,然后Service再调用Mapper层(也叫Dao层),Mapper负责真正跟数据库打交道,把SQL发出去,把结果集取回来。数据回到Controller之后,通常会包装成一个统一的JSON结构,再通过网络返回给前端。前端拿到JSON,解析、渲染,最终呈现到网页上。
这一条链路,就是后端开发人员每天的工作对象。你可以不背框架源码,但这条链路必须在脑子里画得滚瓜烂熟,因为面试、排错、性能优化,全部围绕它展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 前后端分离,分离的到底是什么
2.1 不再是一锅炖
热词里反复出现“前后端分离项目实战”“前端和后端”“java 前后端工作原理”,说明很多人卡在这个概念上。所谓前后端分离,最直观的理解就是:前端项目和后端项目是两个独立的工程,跑在两套不同的进程里,甚至可以部署在不同的服务器上,它们之间只通过HTTP接口沟通。
以前的老式开发方式叫前后端不分离,JSP页面里直接嵌Java代码,前端写页面的时候要懂Java,后端改哪一行JSP代码也得小心翼翼,生怕破坏页面展示。后来业务逻辑复杂了,前端特效越来越花哨,这种一锅炖的模式改起来太痛苦,于是前后端分离就火起来了。
分离模式下的前端工程,比如Vue项目,它是一个纯粹的前端工程,负责页面结构和交互;后端工程,比如SpringBoot项目,它只负责数据和业务逻辑,完全不关心数据在页面上长什么样。两边都开发完了,先各自本地调试,前端可以连本地后端,后端也可以把接口文档丢给前端让他们用Mock数据先行开发,最后联调、打包、分开部署。这样各司其职,开发效率高很多,也方便并行开发。
我见过一些刚入行的朋友以为前后端分离就是“前端一个文件夹、后端一个文件夹,放一个Git仓库里就行”。真要这么干,项目一复杂就会乱套。真正的分离,应该是两个独立工程、独立依赖、独立构建,最多在部署阶段用Nginx把前端静态资源和后端接口地址放在同一个域名下,解决跨域问题。
2.2 没有后端,前端寸步难行
前端页面的HTML、CSS、JavaScript,严格来说都只是“壳子”。壳子里的数据从哪来?全部靠后端接口喂。今天热搜里有“小程序云开发是不是不用写后端代码”,答案是可以不用自己搭后端服务器,但数据仍然需要某种“云端接口”来提供,只是这个“后端”由云服务商给你托管了。所以说到底,后端接口永远是Web应用不可或缺的一环。
前后端分离真正考验一个人水平的点,往往是接口设计。接口路径怎么规划、参数命名怎么统一、返回结构怎么定,都得前后端商量好。我一般建议按照RESTful风格来设计,资源用名词,动作由HTTP方法表达,比如GET /api/users是查用户列表,POST /api/users是新增用户。返回结构也建议统一,比如{ code: 200, message: "success", data: {...} },这样前端解析逻辑可以写得很通用,不用每个接口单独判断。
3. 从零搭一个Java后端项目
3.1 技术选型:为什么是SpringBoot
想学后端开发,Java这个方向绕不开Spring家族。SpringBoot是当前Java后端开发的事实标准,几乎所有的招聘JD里都会写“熟悉Spring Boot优先”。
SpringBoot的好处是启动快、约定优于配置、生态庞大。它把过去Spring需要手动配置一大堆XML配置文件的工作量砍掉了,大多数场景只需要一个application.yml配置文件就能搞定。用它搭一个项目,配合Maven或Gradle依赖管理,从零搭起来非常快,特别适合拿来当学习项目试手。
我知道有些人不喜欢Java,觉得它笨重,想用Python写后端。Python的FastAPI也确实是个不错的选择,轻量、开发效率高。但如果你是奔着找工作去的,老老实实学Java后端,岗位更多、天花板也更高。FastAPI可以当兴趣或业余项目用,职业路线建议以Java为主。
3.2 手把手搭一个最小后端
准备一台电脑,装好JDK 17、Maven、IDEA,就可以开始了。我用一个“用户订单查询”的简单例子演示,这个例子里有用户,有订单,一个用户能查自己的订单,这正好把Controller、Service、Mapper三层串起来。
第一步,去Spring Initializr(start.spring.io)生成一个基础工程,依赖选这四项:Spring Web、MyBatis Framework、MySQL Driver、Lombok。生成之后解压,用IDEA打开,等Maven把依赖下载完。
第二步,看一下项目结构。最外层是pom.xml,Maven的配置文件,所有依赖都在这里声明。然后是src/main/java和src/main/resources,前者放Java代码,后者放配置文件和静态资源。Java代码里按包名分层,常见的是controller、service、mapper、entity、dto。
第三步,写第一个接口。创建一个HelloController.java,内容大概是:
java复制@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping("/{name}")
public String hello(@PathVariable String name) {
return "Hello, " + name + "! This is from backend.";
}
}
然后启动Application主类,浏览器访问http://localhost:8080/api/hello/zhangsan,能看到返回内容,说明后端已经跑通了。
3.3 接口开发里三个最常用的注解
写后端接口,天天跟注解打交道,三个最基础也最重要的注解必须吃透。
@RestController是Controller类的标记,表示这个类里的方法都会以JSON格式返回数据。以前老项目用@Controller还需要配合@ResponseBody才能返回JSON,现在SpringBoot直接合并成@RestController,省事不少。
@RequestMapping以及它的简写版@GetMapping、@PostMapping是路由注解,用来把URL路径映射到Java方法上。路径里还能用{}定义路径参数,比如/api/orders/{orderId},方法里用@PathVariable Long orderId接收,非常方便。
@RequestBody用来把前端传来的JSON字符串自动反序列化成Java对象。这个注解一定要记得加,不加的话,Spring不知道要把请求体里的内容绑定到方法参数上,前端传了数据你也拿不到。
这三个注解组合使用,基本就能写出一套像样的CRUD接口。剩下的就是业务逻辑和数据访问的打磨。
4. 数据库配置与常见的启动失败问题
4.1 配置文件到底放在哪
热词里有“后端配置数据库的文件在哪儿”,这是新手特别喜欢问的问题。在SpringBoot项目里,配置文件默认放在src/main/resources/目录下,文件名通常是application.yml或者application.properties。如果你用了spring-boot-starter-parent,SpringBoot会自动加载这个位置的配置文件。
数据库相关配置写在spring.datasource开头的一组配置项里。比如MySQL连接串:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/my_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
这里最容易踩的坑有两个。一个是serverTimezone不设置,连接MySQL 8会报时区错误;另一个是driver-class-name写错,MySQL 5.x和8.x的驱动类名不一样,8.x要用com.mysql.cj.jdbc.Driver。
另外,现代项目一般会区分开发环境、测试环境、生产环境,配置文件对应拆成application-dev.yml、application-prod.yml,然后在主配置文件里用spring.profiles.active: dev指定当前生效的配置。这样就不会出现测试连生产库、生产连测试库的惨剧。
4.2 启动失败的高频原因与处理套路
今天热词里有一条很典型的启动报错:“后端未能完成启动。从源码运行时,请先执行 uv sync,并确保 uv 和 python 已在……”这条看起来像是Python项目的报错,但背后暴露的启动排查思路是通用的。后端项目启动不起来的常见原因,我总结了五个高频场景,按出现频率排:
-
端口被占用。SpringBoot默认端口8080,如果你的电脑上已经有一个程序占用了8080,SpringBoot启动会直接报
Port 8080 was already in use。处理办法是杀掉占用进程,或者在配置里改端口:server.port: 8081。 -
依赖没下载完整。Maven或Gradle项目在换电脑、清理缓存后重新导入,经常出现依赖不完整的情况。Maven项目可以执行
mvn clean install重新下载依赖,或者用IDEA右侧的Maven面板点刷新。Python项目对应的就是执行uv sync这类命令把依赖同步下来。 -
数据库连接不上。启动时项目会自动初始化数据源,如果MySQL没启动、账号密码不对、连接串写错,就会启动失败。排查顺序是:先看MySQL服务有没有起来,再在Navicat里用同样的账号密码手动连一次,最后看控制台报错是连接超时还是Access denied。
-
配置项有误。
application.yml的缩进非常严格,YAML格式写错一个缩进,整个配置文件解析失败,项目一样起不来。检查方法是用IDEA打开,看有没有红色波浪线提示。 -
Java或Maven版本不匹配。SpringBoot 3.x要求JDK 17及以上,如果你本机还是JDK 8,启动会直接提示UnsupportedClassVersionError。版本不匹配这类问题在多个语言生态里都常见,看到类似的报错先检查运行时版本,往往能省下大量时间。
排查启动问题有一个通用套路:不要只盯着最下面几行红色日志,要往上翻,找到第一处出现ERROR或者Caused by的地方,那里往往才是指向真正原因的线索。我见过太多人一看日志拉得很长就慌了,其实只要顺着Caused by往底层找,绝大多数问题都能在两分钟里定位。
5. 后端学习路线与面试题准备
5.1 零基础到能干活的学习路径
搜热词的时候看到“后端开发学习路线”“java后端学习路线”“后端开发需要学什么”这些词频繁出现,说明大家最迷茫的就是不知道先学什么、后学什么。我结合自己的学习经历和带新人的经验,整理一条比较稳的路线。
第一阶段,打牢Java语言基础。这阶段不需要碰框架,专心把Java核心语法吃透,包括面向对象、集合、异常处理、泛型、多线程、I/O流。我建议多写Demo,自己用Java实现一个图书管理系统的控制台版,把类、集合、循环都用上,这门语言的基本功就算有了。
第二阶段,学数据库基础。后端开发逃不开数据存储,MySQL是首选。重点掌握SQL增删改查、多表联查、聚合函数、索引原理、事务四大特性。不要只停留在背命令,一定要自己建几张表,模拟一个电商场景,写几十条查询语句。SQL写得好不好,直接决定你做后端的天花板,后期做报表、优化接口性能全靠它。
第三阶段,学Java Web基础。理解HTTP协议、Servlet生命周期、Session与Cookie。这部分虽然工作中很少直接写Servlet了,但它是理解SpringMVC的基石。很多人直接跳过去学SpringBoot,遇到拦截器、过滤器这些概念时会觉得抽象,其实就是没打好这层底子。
第四阶段,上手SpringBoot和MyBatis。这时候可以开始做项目了,先用SpringBoot连MySQL实现一个完整的增删改查接口。不需要背源码,能把流程跑通,知道每个注解是干嘛的,就算过关。之后再加SpringMVC细节、MyBatis动态SQL、事务管理。
第五阶段,补充工程化知识。Git、Maven、Linux基础命令、Docker部署、Redis缓存,这些是工作后每天都要用的。建议学到这里时,尝试把自己的项目打包成一个jar包,部署到一台远程Linux服务器上,用Docker跑起来,整个部署流程走一遍,心里就非常有底了。
5.2 后端面试里出现频率最高的几道题
热词里有“后端面试题”“2026后端面试题”,说明面试准备是大多数人的刚需。后端面试的考察重点,跟工作内容高度相关,翻来覆去就是那么些东西。我按出现频率整理了若干必考题,供大家参考:
- Java HashMap的底层实现原理。问的是数组加链表加红黑树,扩容机制,为什么链表长度到8才转红黑树。这是Java岗基础中的基础,几乎每家都问。
- SpringBoot自动配置原理。核心是
@EnableAutoConfiguration注解配合spring.factories文件,按条件装配Bean。能用自己的话讲清楚,面试官会觉得你真的用过。 - 什么是事务,事务的隔离级别有哪几种。MySQL默认是可重复读,要能说出读未提交、读已提交、可重复读、串行化四者区别,以及脏读、不可重复读、幻读分别被哪一级解决。
- Redis常用数据结构以及缓存穿透、缓存击穿、缓存雪崩。这三个问题几乎是固定组合,解决办法分别是布隆过滤器、互斥锁/逻辑过期、随机过期时间加集群高可用。
- 索引失效的场景。比如对索引列使用函数、隐式类型转换、like以%开头、联合索引不满足最左前缀原则。答这些例子容易,关键是理解每个场景背后的原因。
5.2.1 现场答一道“接口幂等性”题
面试还爱问“接口怎么做幂等”。第一次听到的人容易懵,其实幂等就是同一个请求发多次,结果跟发一次一样。比如用户提交订单,网络抖动导致前端重试了两次,后端不能创建两个订单出来。常用做法有:前端生成唯一请求ID,后端收到时先查这个ID是否处理过;或者利用数据库唯一索引约束;或者用Redis的SETNX保证同一时刻只有一个请求能通过。答这个题,最好结合真实项目讲,说“我在支付回调里用唯一交易号做了去重”,比空讲理论有说服力得多。
后端面试从来不是死记硬背,而是考察你能否把知识点串起来。这也是我为什么一直强调要手写项目的原因,光背题没有体感,一被追问就露馅。
6. 今天踩过的坑与排查心得
6.1 跨域问题:前后端分离最容易卡住的点
用Vue写前端,SpringBoot写后端,本地联调时最常见的坑就是跨域。浏览器访问http://localhost:5173的前端页面,去请求http://localhost:8080的后端接口,端口不同,浏览器会认为是跨域请求,直接拦截响应。这时候前端控制台会报Access-Control-Allow-Origin相关的错误,有经验的人一看就知道是跨域。
跨域的解决方案有很多,开发环境最常用的是后端加CORS配置。在SpringBoot里可以用@CrossOrigin注解加在Controller类上,或者写一个全局配置类。生产环境则更推荐让Nginx做反向代理,把前端请求/api开头的路径转发给后端服务,从浏览器视角看,你的请求始终是同源的,自然就没有跨域问题。
我踩过的坑是,后端配了@CrossOrigin但仍然报跨域错误。后来发现是没处理预检请求。当前端发起非简单请求(比如带自定义Header)时,浏览器会先发一个OPTIONS请求试探,如果后端没有正确响应这个OPTIONS,跨域就依然会被拦截。SpringMVC里可以通过重写WebMvcConfigurer的addCorsMappings方法统一处理,而不只是加一个注解。
6.2 BigInt对应精度丢失问题
热词里有“后端bigint,前端怎么传值”,这个问题做过后端的都会遇到。数据库表里主键一般用自增ID的类型,在Java里对应Long,但如果用MyBatis查出来直接塞进JSON返回,前端JavaScript的Number类型会悄悄丢精度。常见表现是ID末尾两位变成0,下单记录串单,排查起来很崩溃。
为什么丢精度?因为JavaScript的Number安全整数范围是2的53次方减1,约等于九千万亿,超过这个范围的整数就无法精确表示了。而数据库BigInt类型可以到2的63次方减1,MySQL生成的雪花ID通常20位左右,已经超过JavaScript的安全范围。
解决方法是把这个字段转成字符串再返回给前端。在SpringBoot里可以给对应字段单独处理,比如在实体类里把ID类型改成String,或者用Jackson的@JsonSerialize注解指定ToStringSerializer。前端拿到字符串之后,用它做展示和传参没问题,需要给后端传主键时也直接传字符串,后端再转成Long即可。这个细节项目里只要忽略一次,就是一个线上P0事故的级别,务必重视。
6.3 Base64文件流怎么下载
热词里还有一个“后端在接口某个字段返回了base64格式的文件流我如何下载查看”,这也是实际开发中比较常见的需求。比如后端返回的JSON里有个fileBase64字段,内容是data:application/pdf;base64,JVBERi0xLjQ...一长串。这种数据的处理思路是:前端把逗号后面的Base64字符串解码成二进制Blob,再生成一个临时下载链接,触发浏览器下载。
JavaScript的核心代码大致是:
javascript复制const base64 = response.fileBase64.split(',')[1];
const byteCharacters = atob(base64);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'download.pdf';
a.click();
URL.revokeObjectURL(url);
如果文件体积比较大,比如几十MB的Excel导出,用Base64传输会额外增加约三分之一的体积,内存占用也很高。这种场景我更建议后端直接提供一个文件下载接口,用二进制流的方式返回,前端用window.open或axios的responseType: 'blob'来处理。Base64适合小文件、临时查看的场景,要分清场景来选择方案。
7. 学习后端过程中的一些个人建议
这些经验是从一次次掉坑里换来的。第一个建议是不要急着追新框架。有些同学看到某个新框架的教程就收藏,收藏夹里存了几十个链接,Java基础却还停留在会写HelloWorld的程度。后端这个领域,基础能力远比框架版本重要,Java集合源码、MySQL索引原理、HTTP协议,这些东西十年不过时,把它们吃透,换任何框架都能快速上手。
第二个建议是学知识一定要做笔记。这个建议听起来很普通,但真正做到的人不多。后端知识链太长,今天学了MyBatis动态SQL,可能下周才用到,不记笔记基本等于白学。我自己的习惯是用Markdown按主题记录,每个知识点只写核心结论、配套代码、踩坑经历,复习的时候一个小时能过完一个月的知识点,效率非常明显。
第三个建议是尽早接触真实项目。所谓真实,不一定是公司的商业项目,完全可以自己定一个小项目来做,比如做一个个人记账本的博客,前端用Vue,后端用SpringBoot,加上登录、增删改查、权限控制、文件上传,做完这个项目,你对后端开发的理解会上一个台阶。只看教程不实做,就像光看菜谱不下厨,以为自己会了,真上手一塌糊涂。
第四个建议是遇到报错先自己拆解。刚开始写后端,报错日志一拍全扔进群里问人,不是什么好习惯。我的做法是先读日志,把Caused by那部分找出来,再根据关键信息去搜索引擎查,基本上能解决八成问题。实在搞不定再发群里,这时候你能把自己的排查过程讲出来,别人也愿意帮你。
后端开发这条路,入门简单,深入很难。但只要把每一个基础概念的原理吃透,每踩一个坑都总结成经验,成长速度快得连自己都会惊讶。这篇“后端学习日记1.30”就先记到这里,明天继续把接口安全、权限认证这部分内容补上,到时候再跟大家分享新的体会。
