邪修实战系列(3)

发布于:2025-09-11 ⋅ 阅读:(19) ⋅ 点赞:(0)

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)的窗口,应该能看到打印出的接收到的数据信息。
      在这里插入图片描述
  • 这个项目的源码我放到了我的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错误。


网站公告

今日签到

点亮在社区的每一天
去签到