1、第一阶段邪修实战总览(9.1-9.30)
把第一阶段(基础夯实期)的学习计划拆解成极具操作性的每日行动方案。这个计划充分利用我“在职学习”的特殊优势,强调“用输出倒逼输入”,确保每一分钟的学习都直接服务于面试和实战。
- 核心目标:构建起Java后端开发的知识树主干,并能通过一个小型项目串联起所有知识点。
- 核心策略:每天3小时雷打不动的高效学习(工作日可分散,周末集中攻坚)。
2、周目标(9.1-9.14)
Java核心+Sprig Boot破冰,能独立使用Spring搭建Web后端并提供RESTful接口。
3、分日目标与邪修技巧
3.1、Day 9-10: Spring Boot开发RESTful API
- 行动:设计/api/ads相关的接口(GET、POST),用@PostMapping接收前端传过来的JSON数据并解析。
- 邪修技巧:使用Postman软件测试自己写的接口,确保能通。这个过程和前端联调一模一样,这就是经验。
3.1.1、学习分享
接下来我会讲解一下我在学习这部分知识的时候编写与测试GET接口的详细步骤:
第一步:设计我们的数据模型
在编写接收数据的API之前,需要先定义数据长什么样。我们可以直接在我们7-8天测试的那个demo中进行修改。
- 创建实体类:在scr/main/java/com/adcampaign下新建一个entity包,并在该包下创建一个新的Java类,名为AdAdvertisement
- 编写类代码:
package com.adcampaign.entity;
/**
* 广告活动数据模型类
* 用于存储广告活动的核心数据,并提供数据计算和分析功能
* 每个实例代表一天的广告活动数据
*/
public class AdAdvertisement {
// 日期(例如:"2023-10-01")
private String date;
// 广告花费(单位:元)
private double cost;
// 线索提交个数(用户提交的潜在客户信息数量)
private int leadCount;
// 私信消息数(收到的用户私信数量)
private int messageCount;
/**
* 构造方法:创建广告活动数据对象
* @param date 日期字符串
* @param cost 广告花费金额
* @param leadCount 线索数量
* @param messageCount 私信消息数量
*/
public AdAdvertisement(String date, double cost, int leadCount, int messageCount) {
this.date = date;
this.cost = cost;
this.leadCount = leadCount;
this.messageCount = messageCount;
}
// Getter方法:获取私有属性的值
public String getDate() { return date; }
public double getCost() { return cost; }
public int getLeadCount() { return leadCount; }
public int getMessageCount() { return messageCount; }
// Setter方法:修改私有属性的值
public void setDate(String date) { this.date = date; }
public void setCost(double cost) { this.cost = cost; }
public void setLeadCount(int leadCount) { this.leadCount = leadCount; }
public void setMessageCount(int messageCount) { this.messageCount = messageCount; }
/**
* 计算单个线索成本
* 公式:单个线索成本 = 广告花费 ÷ 线索数量
* @return 单个线索成本(元/个),如果线索数量为0则返回0
*/
public double calculateCostPerLead() {
// 防止除以零错误:如果线索数为0,返回0
return (leadCount > 0) ? cost / leadCount : 0;
}
/**
* 计算私信消息转化成本
* 公式:私信转化成本 = 广告花费 ÷ 私信消息数
* @return 私信转化成本(元/条),如果私信数为0则返回0
*/
public double calculateCostPerMessage() {
// 防止除以零错误:如果私信数为0,返回0
return (messageCount > 0) ? cost / messageCount : 0;
}
/**
* 分析广告花费随日期的变动情况
* @param previousCampaign 上一个日期的广告活动数据(用于比较)
* @return 变动情况描述,包含变动金额和百分比
*/
public String analyzeCostChange(AdAdvertisement previousCampaign) {
// 检查是否有历史数据可供比较
if (previousCampaign == null) return "无历史数据可供比较";
// 计算变动金额:当前花费 - 上一期花费
double changeAmount = this.cost - previousCampaign.getCost();
// 计算变动百分比:(变动金额 ÷ 上一期花费) × 100%
double changeRate = (changeAmount / previousCampaign.getCost()) * 100;
// 格式化输出:保留两位小数,显示变动金额和百分比
return String.format("花费变动: %.2f元 (%.2f%%)", changeAmount, changeRate);
}
/**
* 分析单个线索成本随日期的变动情况
* @param previousCampaign 上一个日期的广告活动数据(用于比较)
* @return 变动情况描述,包含变动金额和百分比
*/
public String analyzeCostPerLeadChange(AdAdvertisement previousCampaign) {
if (previousCampaign == null) return "无历史数据可供比较";
// 获取当前和上一期的单个线索成本(调用已有的计算方法)
double currentCpl = this.calculateCostPerLead();
double previousCpl = previousCampaign.calculateCostPerLead();
// 防止除以零错误
if (previousCpl <= 0) return "历史单个线索成本为0,无法计算变动率";
double changeAmount = currentCpl - previousCpl;
double changeRate = (changeAmount / previousCpl) * 100;
return String.format("单个线索成本变动: %.2f元 (%.2f%%)", changeAmount, changeRate);
}
/**
* 分析私信消息转化成本随日期的变动情况
* @param previousCampaign 上一个日期的广告活动数据(用于比较)
* @return 变动情况描述,包含变动金额和百分比
*/
public String analyzeMessageCostChange(AdAdvertisement previousCampaign) {
if (previousCampaign == null) return "无历史数据可供比较";
// 获取当前和上一期的私信转化成本(调用已有的计算方法)
double currentCpm = this.calculateCostPerMessage();
double previousCpm = previousCampaign.calculateCostPerMessage();
// 防止除以零错误
if (previousCpm <= 0) return "历史私信转化成本为0,无法计算变动率";
double changeAmount = currentCpm - previousCpm;
double changeRate = (changeAmount / previousCpm) * 100;
return String.format("私信转化成本变动: %.2f元 (%.2f%%)", changeAmount, changeRate);
}
}
(其实要是大家仔细研究过这个系列的前面,并且看了Data_Board-README文档的话,不难发现,其实这个类是直接复制的,仅仅只是改了名字而已)
第二步:升级控制器
现在我们需要改造我们Day7-8创建的控制器或者来创建一个更专业的控制器,我们这里直接来创建吧
- 创建控制器:在controller包下,创建AdController.java
- 编写Get接口(返回数据列表):
package com.adcampaign.controller;
import com.adcampaign.entity.AdAdvertisement; // 导入刚刚创建的实体类
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/api/ads") // 所有这个控制器下的接口路径都以 /api/ads 开头
public class AdController {
// 模拟一些静态数据
private List<AdAdvertisement> adList = Arrays.asList(
new AdAdvertisement("2025-9-28",5000,10,50),
new AdAdvertisement("2025-9-29",6000,15,60)
);
@GetMapping // 等价于 @GetMapping(""),访问路径是 /api/ads
public List<AdAdvertisement> getAllAds() {
return adList; // Spring Boot会自动将这个List序列化为JSON返回
}
}
第三步:编写启动类
启动类通常位于项目最顶级的包下,之前7-8天的测试自动生成了一个启动类,我们这里直接删除即可,接下来在src/main/java/com/adcampaign包下新建一个启动类叫Data_Board_Application.java
- 编写启动类代码:
package com.adcampaign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
// 核心注解:标记这是一个Spring Boot应用的主配置类
@SpringBootApplication
@RestController
public class Data_Board_Appliction {
public static void main(String[] args) {
SpringApplication.run(Data_Board_Appliction.class, args);
}
}
- 测试GET接口
-
- 启动项目,运行启动类
Data_Board_Application.java
,然后在在终端窗口如果出现下面的样式则代表运行成功:
- 启动项目,运行启动类
-
- 打开浏览器,访问网址
http://localhost:8080/api/ads
,如果在浏览器中显示如图所示的两条包含广告数据的JSON数组,就证明成功了。
- 打开浏览器,访问网址
第四步:编写POST接口(接收数据)
这是最关键的一步,可以学会如何接收前端发送的JOSN数据。
- 在AdController中添加POST接口:
// 新增POST接口
@PostMapping
public String createAd(@RequestBody AdAdvertisement newAd) {
// @RequestBody 注解告诉Spring:“请把请求体里的JSON数据,转换成一个AdAdvertisement对象”
// 模拟处理:打印接收到数据
System.out.println("接收到新的广告数据:");
System.out.println("日期: " + newAd.getDate());
System.out.println("广告花费: " + newAd.getCost());
System.out.println("线索提交个数: " + newAd.getLeadCount());
System.out.println("私信消息数: " + newAd.getMessageCount());
// 这里暂时不做实际存储,只是返回成功消息
return "广告数据创建成功! " + newAd.getDate();
}
- AdController控制器的完整代码如下:
package com.adcampaign.controller;
import com.adcampaign.entity.AdAdvertisement; // 导入刚刚创建的实体类
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/api/ads") // 所有这个控制器下的接口路径都以 /api/ads 开头
public class AdController {
// 模拟一些静态数据
private List<AdAdvertisement> adList = Arrays.asList(
new AdAdvertisement("2025-9-28",5000,10,50),
new AdAdvertisement("2025-9-29",6000,15,60)
);
@GetMapping // 等价于 @GetMapping(""),访问路径是 /api/ads
public List<AdAdvertisement> getAllAds() {
return adList; // Spring Boot会自动将这个List序列化为JSON返回
}
// 新增POST接口
@PostMapping
public String createAd(@RequestBody AdAdvertisement newAd) {
// @RequestBody 注解告诉Spring:“请把请求体里的JSON数据,转换成一个AdAdvertisement对象”
// 模拟处理:打印接收到数据
System.out.println("接收到新的广告数据:");
System.out.println("日期: " + newAd.getDate());
System.out.println("广告花费: " + newAd.getCost());
System.out.println("线索提交个数: " + newAd.getLeadCount());
System.out.println("私信消息数: " + newAd.getMessageCount());
// 这里暂时不做实际存储,只是返回成功消息
return "广告数据创建成功! " + newAd.getDate();
}
}
第五步:测试POST接口(使用Postman)
由于我们不能用浏览器地址栏测试POST请求,必须使用Postman或类似的API测试工具,所以需要我们来下载并安装一个Postman来进行测试。
- 大家可以跟着这篇文章来初步了解一下Postman,postman接口测试工具详解【全】,这篇文章中详细介绍了如何下载、安装与一些简单的使用。
- 创建一个新请求:
-
- 方法选择:POST
-
- URL输入:localhost:8080/api/ads
- 设置请求头:
-
- 点击Headers标签
-
- 添加一个Key:Content-Type,Value:application/json
- 设置请求体:
-
- 点击Body标签
-
- 选择raw和JOSN
-
- 在下方文本框中输入一段JOSN数据:
{
"date": "2025-09-30",
"cost": 100.5,
"leadCount": 5,
"messageCount": 7
}
点击Send:
-
- 成功标志:下方响应去会看到
广告数据创建成功2025-9-30
- 成功标志:下方响应去会看到
-
- 同时,回头看我们的IDE控制台(运行Spring Boot)的窗口,应该能看到打印出的接收到的数据信息。
- 同时,回头看我们的IDE控制台(运行Spring Boot)的窗口,应该能看到打印出的接收到的数据信息。
这个项目的源码我放到了我的GitHub里,点击Data_Board_Spring_Boot链接直接学习和使用即可~
总结
@RequestBody是灵魂:
- 它完成了
HTTP请求体 -> Java对象
的魔法转换。这个过程叫“反序列化”,由Spring内置的Jackson库自动完成。只需要定义一个Java类,字段名能和JSON的key对上就行。
为什么要有无参构造器和Getter/Setter?
- Jackson库在创建对象和读取/设置属性时需要使用它们。没有他们,转换就会失败。这也是之前为什么要强调生成这些方法的原因。
Web开发经验
- 使用Spring Boot的@RestController开发过RESTful接口,包括处理GET和POST请求。并且我知道如何使用@RequestBody注解来接收前端发送的JSON格式参数,完成反序列化。
@SpringBootApplication
是一个组合注解,它包含了三个核心功能:
@SpringBootConfiguration
:标记该类为配置类@EnableAutoConfiguration
:开启自动配置,这是Spring Boot的魔法所在,它根据您引入的jar包依赖(如Spring-Web,MySQL Driver),自动配置应用程序锁需的组件(如Tomcat服务器、SpringMVC)。@ComponentScan
:自动扫描当前包及其子包下的组件(如@Controller,@Service,@RestController,@Component等),并注册为Spring Bean。
包路径的重要性
AdControlle控制器类
必须放在启动类
的同级或者子包下!例如,如果启动类在com.example.demo
包下,那么您的控制器最好放在com.example.demo.controller
包下。如果放在一个毫不相干的包路径下,@ComponentScan
将无法发现它,导致404错误。