当前位置: 首页 > news >正文

3. SpringMVC Rest 风格

1. REST 简介

REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格。

当要表示一个网络资源的时候,可以使用两种方式:

  • 传统风格资源描述形式
    http://localhost/user/getById?id=1 查询 id 为 1 的用户信息
    http://localhost/user/saveUser 保存用户信息
  • REST风格描述形式
    http://localhost/user/1 查询 id 为 1 的用户信息
    http://localhost/user 保存用户信息

传统方式一般是一个请求 url 对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读了请求 url 地址,就大概知道该 url 实现的是什么操作。

查看 REST 风格的描述,会发现请求地址变简单了,并且只看请求 URL 并不能轻易猜出该 URL 的具体功能。

所以 REST 的优点有:

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作。
  • 书写简化。

但是问题也随之而来,一个相同的 url 地址既可以是新增也可以是修改或者查询,该如何区分该请求到底是什么操作呢?

按照 REST 风格访问资源时使用请求动作区分对资源进行了何种操作:

在这里插入图片描述

请求的方式比较多,但是比较常用的就 4 种,分别是 GET、POST、PUT、DELETE。不同的请求方式代表不同的操作类型:

  • 发送 GET 请求是用来做查询
  • 发送 POST 请求是用来做新增
  • 发送 PUT 请求是用来做修改
  • 发送 DELETE 请求是用来做删除

上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范。可以不这样做,但不建议。

描述模块的名称通常使用复数,也就是加 “s”。这样表示此类资源,而非单个资源,例如:users、books、accounts…

根据 REST 风格对资源进行访问称为 RESTful。
在开发过程中,大多都遵从 REST 风格来访问后台服务,所以可以说以后都是基于 RESTful 来进行开发。

2. RESTful 入门案例

@PathVariable 注解绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应。

public class BookController {//用postman发post请求,请求路径:http://localhost/books@RequestMapping(value = "/books",method = RequestMethod.POST)@ResponseBodypublic String save(@RequestBody Book book){System.out.println("book save..." + book);return "{'module':'book save'}";}//用postman发delete请求,请求路径:http://localhost/books/1//请求路径中的“1”传给id@RequestMapping(value = "/books/{id}",method = RequestMethod.DELETE)@ResponseBody//@PathVariable:把请求路径中的变量值传给形参public String delete(@PathVariable Integer id){System.out.println("book delete..." + id);return "{'module':'book delete'}";}//用postman发put请求,请求路径:http://localhost/books@RequestMapping(value = "/books",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody Book book){System.out.println("book update..." + book);return "{'module':'book update'}";}//用postman发get请求,请求路径:http://localhost/books/1@RequestMapping(value = "/books/{id}",method = RequestMethod.GET)@ResponseBody//@PathVariable:把请求路径中的变量值传给形参public String getById(@PathVariable Integer id){System.out.println("book getById..." + id);return "{'module':'book getById'}";}//用postman发get请求,请求路径:http://localhost/books@RequestMapping(value = "/books",method = RequestMethod.GET)@ResponseBodypublic String getAll(){System.out.println("book getAll...");return "{'module':'book getAll'}";}
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

@RequestBody、@RequestParam、@PathVariable 三个注解之间的区别和应用分别是什么?

区别:

  • @RequestParam 用于接收 url 地址传参或表单传参。
  • @RequestBody 用于接收 json 数据。
  • @PathVariable 用于接收路径参数,使用 {参数名称} 描述路径参数。

应用:

  • 后期开发中,发送请求参数超过 1 个时,以 json 格式为主,@RequestBody 应用较广。
  • 如果发送非 json 格式数据,选用 @RequestParam 接收请求参数。
  • 采用 RESTful 进行开发,当参数数量较少时,例如 1 个,可以采用 @PathVariable 接收请求路径变量,通常用于传递 id 值。

3. RESTful 快速开发

在前面基础上,

  • 可以把相同的路径前缀写在类上,即:把@RequestMapping("/books")提到类上。
  • 由于之前每个方法上都有@ResponseBody注解,所以可以统一写在类上。

得到如下代码:

@Controller
@ResponseBody
@RequestMapping("/books")
public class BookController {//用postman发post请求,请求路径:http://localhost/books@RequestMapping(method = RequestMethod.POST)public String save(@RequestBody Book book){System.out.println("book save..."+ book);return "{'module':'book save'}";}//用postman发delete请求,请求路径:http://localhost/books/1//请求路径中的“1”传给id@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)//@PathVariable:把请求路径中的变量值传给形参public String delete(@PathVariable Integer id){System.out.println("book delete..." + id);return "{'module':'book delete'}";}//用postman发put请求,请求路径:http://localhost/books@RequestMapping(method = RequestMethod.PUT)public String update(@RequestBody Book book){System.out.println("book update..." + book);return "{'module':'book update'}";}//用postman发get请求,请求路径:http://localhost/books/1@RequestMapping(value = "/{id}",method = RequestMethod.GET)//@PathVariable:把请求路径中的变量值传给形参public String getById(@PathVariable Integer id){System.out.println("book getById..." + id);return "{'module':'book getById'}";}//用postman发get请求,请求路径:http://localhost/books@RequestMapping(method = RequestMethod.GET)public String getAll(){System.out.println("book getAll...");return "{'module':'book getAll'}";}
}

在上面代码的基础上,@Controller@ResponseBody注解可以用一个注解@RestController替代。

请求动作也可以用更简单的注解表示。

// @Controller
// @ResponseBody
@RestController
@RequestMapping("/books")
public class BookController {//用postman发post请求,请求路径:http://localhost/books// @RequestMapping(method = RequestMethod.POST)@PostMappingpublic String save(@RequestBody Book book){System.out.println("book save..."+ book);return "{'module':'book save'}";}//用postman发delete请求,请求路径:http://localhost/books/1//请求路径中的“1”传给id// @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)@DeleteMapping("/{id}")//@PathVariable:把请求路径中的变量值传给形参public String delete(@PathVariable Integer id){System.out.println("book delete..." + id);return "{'module':'book delete'}";}//用postman发put请求,请求路径:http://localhost/books// @RequestMapping(method = RequestMethod.PUT)@PutMappingpublic String update(@RequestBody Book book){System.out.println("book update..." + book);return "{'module':'book update'}";}//用postman发get请求,请求路径:http://localhost/books/1// @RequestMapping(value = "/{id}",method = RequestMethod.GET)@GetMapping("/{id}")//@PathVariable:把请求路径中的变量值传给形参public String getById(@PathVariable Integer id){System.out.println("book getById..." + id);return "{'module':'book getById'}";}//用postman发get请求,请求路径:http://localhost/books// @RequestMapping(method = RequestMethod.GET)@GetMappingpublic String getAll(){System.out.println("book getAll...");return "{'module':'book getAll'}";}
}

上面的代码去掉注释后:

@RestController
@RequestMapping("/books")
public class BookController {//用postman发post请求,请求路径:http://localhost/books@PostMappingpublic String save(@RequestBody Book book){System.out.println("book save..."+ book);return "{'module':'book save'}";}//用postman发delete请求,请求路径:http://localhost/books/1//请求路径中的“1”传给id@DeleteMapping("/{id}")//@PathVariable:把请求路径中的变量值传给形参public String delete(@PathVariable Integer id){System.out.println("book delete..." + id);return "{'module':'book delete'}";}//用postman发put请求,请求路径:http://localhost/books@PutMappingpublic String update(@RequestBody Book book){System.out.println("book update..." + book);return "{'module':'book update'}";}//用postman发get请求,请求路径:http://localhost/books/1@GetMapping("/{id}")//@PathVariable:把请求路径中的变量值传给形参public String getById(@PathVariable Integer id){System.out.println("book getById..." + id);return "{'module':'book getById'}";}//用postman发get请求,请求路径:http://localhost/books@GetMappingpublic String getAll(){System.out.println("book getAll...");return "{'module':'book getAll'}";}
}

4. 基于 RESTful 的页面数据交互

4.1 需求分析

在这里插入图片描述

需求一:图片列表查询,从后台返回数据,将数据展示在页面上。

需求二:新增图书,将新增图书的数据传递到后台,并在控制台打印。

说明:此次案例的重点是在 SpringMVC 中使用 RESTful 实现前后台交互,所以并没有和数据库进行交互,所有数据使用假数据来完成开发。

4.2 后台接口开发

@RestController
@RequestMapping("/books")
public class BookController {//保存图书@PostMappingpublic String save(@RequestBody Book book){System.out.println("保存图书:"+book);return "{'module':'save book success'}";}//查询所有图书@GetMappingpublic List<Book> getAll(){System.out.println("查询所有图书...");List<Book> bookList = new ArrayList<>();Book book1 = new Book();book1.setType("计算机");book1.setName("SpringMVC入门教程");book1.setDescription("小试牛刀");bookList.add(book1);Book book2 = new Book();book2.setType("计算机");book2.setName("SpringMVC实战教程");book2.setDescription("一代宗师");bookList.add(book2);return bookList;}
}

postman 测试:

① 测试新增

在这里插入图片描述

② 测试查询

在这里插入图片描述

4.2 页面访问处理

(1) 拷贝静态页面:将资料\功能页面下的所有内容拷贝到项目的 webapp 目录下。

在这里插入图片描述

(2) 访问 pages 目录下的 books.html

打开浏览器输入http://localhost/pages/books.html

在这里插入图片描述
为什么会出现错误?

在这里插入图片描述

SpringMVC 拦截了静态资源,根据 /pages/books.html去 controller 找对应的方法,找不到所以会报 404 的错误。

SpringMVC 为什么会拦截静态资源呢?

在这里插入图片描述

解决方案:SpringMVC 需要将静态资源放行。

//设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {// 当访问/pages/...的时候,从/pages目录下查找内容registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");}
}

该配置类在 config 目录下,SpringMVC 当前扫描的是 controller 包,所以该配置类还未生效,要想生效需要修改 SpringMvcConfig 配置类的扫描范围。

@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc//开启将JSON转换成对象的功能
public class SpringMvcConfig {
}//或者@Configuration
@ComponentScan("com.itheima")
@EnableWebMvc
public class SpringMvcConfig {
}

(3) 修改 books.html 页面

在这里插入图片描述

页面完整代码:

<!DOCTYPE html><html><head><!-- 页面meta --><meta charset="utf-8"><title>SpringMVC案例</title><!-- 引入样式 --><link rel="stylesheet" href="../plugins/elementui/index.css"><link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min.css"><link rel="stylesheet" href="../css/style.css"></head><body class="hold-transition"><div id="app"><div class="content-header"><h1>图书管理</h1></div><div class="app-container"><div class="box"><div class="filter-container"><el-input placeholder="图书名称" style="width: 200px;" class="filter-item"></el-input><el-button class="dalfBut">查询</el-button><el-button type="primary" class="butT" @click="openSave()">新建</el-button></div><el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row><el-table-column type="index" align="center" label="序号"></el-table-column><el-table-column prop="type" label="图书类别" align="center"></el-table-column><el-table-column prop="name" label="图书名称" align="center"></el-table-column><el-table-column prop="description" label="描述" align="center"></el-table-column><el-table-column label="操作" align="center"><template slot-scope="scope"><el-button type="primary" size="mini">编辑</el-button><el-button size="mini" type="danger">删除</el-button></template></el-table-column></el-table><div class="pagination-container"><el-paginationclass="pagiantion"@current-change="handleCurrentChange":current-page="pagination.currentPage":page-size="pagination.pageSize"layout="total, prev, pager, next, jumper":total="pagination.total"></el-pagination></div><!-- 新增标签弹层 --><div class="add-form"><el-dialog title="新增图书" :visible.sync="dialogFormVisible"><el-form ref="dataAddForm" :model="formData" :rules="rules" label-position="right" label-width="100px"><el-row><el-col :span="12"><el-form-item label="图书类别" prop="type"><el-input v-model="formData.type"/></el-form-item></el-col><el-col :span="12"><el-form-item label="图书名称" prop="name"><el-input v-model="formData.name"/></el-form-item></el-col></el-row><el-row><el-col :span="24"><el-form-item label="描述"><el-input v-model="formData.description" type="textarea"></el-input></el-form-item></el-col></el-row></el-form><div slot="footer" class="dialog-footer"><el-button @click="dialogFormVisible = false">取消</el-button><el-button type="primary" @click="saveBook()">确定</el-button></div></el-dialog></div></div></div></div></body><!-- 引入组件库 --><script src="../js/vue.js"></script><script src="../plugins/elementui/index.js"></script><script type="text/javascript" src="../js/jquery.min.js"></script><script src="../js/axios-0.18.0.js"></script><script>var vue = new Vue({el: '#app',data:{dataList: [],//当前页要展示的分页列表数据formData: {},//表单数据dialogFormVisible: false,//增加表单是否可见dialogFormVisible4Edit:false,//编辑表单是否可见pagination: {},//分页模型数据,暂时弃用},//钩子函数,VUE对象初始化完成后自动执行created() {this.getAll();},methods: {// 重置表单resetForm() {//清空输入框this.formData = {};},// 弹出添加窗口openSave() {this.dialogFormVisible = true;this.resetForm();},//添加saveBook () {axios.post("/books",this.formData).then((res)=>{});},//主页列表查询getAll() {axios.get("/books").then((res)=>{this.dataList = res.data;});},}})</script>
</html>

相关文章:

3. SpringMVC Rest 风格

1. REST 简介 REST&#xff08;Representational State Transfer&#xff09;&#xff0c;表现形式状态转换&#xff0c;它是一种软件架构风格。 当要表示一个网络资源的时候&#xff0c;可以使用两种方式&#xff1a; 传统风格资源描述形式 http://localhost/user/getById?…...

Python3简介

Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&#xff0c;相比其他语言经常使用英文关键字&#xff0c;其他语言的一些标点符号&#xff0c;它具有比其他语言更有特色语法结构。 Python 是面向对象语言: 这意味着P…...

如何学习PMP?

★基础要打牢 方法&#xff1a;“基础不牢&#xff0c;地动山摇”&#xff0c;如果基础不牢那么就很难拿高分&#xff0c;因为连最基础的题目分都不一定能拿到。 可以在针对基础知识&#xff0c;把PMBOK看一两遍&#xff0c;再次加深印象&#xff0c;再把平时做章节练习、每日5…...

【DSP视频教程】第11期:插补算法,曲线拟合丝滑顺畅,统计函数和基础函数加速实现,汇集SIMD,饱和和MAC乘累加应用实战(2023-02-12)

视频教程汇总帖&#xff1a;https://www.armbbs.cn/forum.php?modviewthread&tid110519 DSP视频教程有段时间没有更新了。 当前DSP库从CMSIS软件包里面独立出来&#xff0c;并且更新非常频繁&#xff0c;所以本期视频教程优先给大家简单介绍下新版DSP&#xff0c; 然后为…...

分类模型评估:混淆矩阵、准确率、召回率、ROC

1. 混淆矩阵 在二分类问题中&#xff0c;混淆矩阵被用来度量模型的准确率。因为在二分类问题中单一样本的预测结果只有Yes or No&#xff0c;即&#xff1a;真或者假两种结果&#xff0c;所以全体样本的经二分类模型处理后&#xff0c;处理结果不外乎四种情况&#xff0c;每种…...

算法 ——世界 一

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。个人爱好: 编程&#xff0c;打篮球&#xff0c;计算机知识个人名言&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石…...

2023年3月AMA-CDGA/CDGP数据治理认证考试这些城市可以报名

目前2023年3月5日CDGA&CDGP开放报名的城市有&#xff1a;北京、上海、广州、深圳、杭州、重庆&#xff0c;西安&#xff0c;成都&#xff0c;长沙&#xff0c;济南&#xff0c;更多考场正在增加中… DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业…...

Java变量和数据类型,超详细整理,适合新手入门

目录 一、什么是变量&#xff1f; 二、变量 变量值互换 三、基本数据类型 1、八种基本数据类型 2、布尔值 3、字符串 四、从控制台输入 一、什么是变量&#xff1f; 变量是一种存储值的容器&#xff0c;它可以在程序的不同部分之间共享&#xff1b;变量可以存储数字、字…...

Echarts 设置折线图拐点的颜色,边框等样式,hover时改变颜色

第014个点击查看专栏目录上一篇文章我们讲到了如何设置拐点大小,图形类型&#xff0c;旋转角度&#xff0c;缩放同比&#xff0c;位置偏移等&#xff0c;这篇文章介绍如何设置拐点的颜色、边框大小颜色等样式。hover轴线时候&#xff0c;拐点的填充颜色改变文章目录示例效果示例…...

做 SQL 性能优化真是让人干瞪眼

很多大数据计算都是用SQL实现的&#xff0c;跑得慢时就要去优化SQL&#xff0c;但常常碰到让人干瞪眼的情况。 比如&#xff0c;存储过程中有三条大概形如这样的语句执行得很慢&#xff1a; select a,b,sum(x) from T group by a,b where …; select c,d,max(y) from T grou…...

SpringBoot(3)之包结构

根据spring可知道&#xff0c;注解之所以可以使用&#xff0c;是因为通过包扫描器&#xff0c;扫描包&#xff0c;然后才能通过注解开发。 那么springboot需要扫描哪里呢&#xff1f; springboot的默认包扫描器&#xff0c;扫描的是自己所在的包和子包&#xff0c;例子如下 我…...

test2

物理层故障分析 一、传输介质故障 a.主要用途简述 传输介质主要分为 导向传输介质和非导向传输介质。前者包括双绞线&#xff08;两根铜线并排绞合&#xff0c;距离过远会失真&#xff09;、同轴电缆&#xff08;铜质芯线屏蔽层&#xff0c;抗干扰性强&#xff0c;传输距离更…...

LoadRunner安装教程

备注&#xff1a;电脑最好安装有IE浏览器或者360极速版浏览器 一、下载安装包 提前下载安装文件&#xff0c;必须下载。 链接: https://pan.baidu.com/s/1blFiMIJcoE8s3uVhAxdzdA?pwdqhpt 提取码: qhpt 包含的文件有&#xff1a; 二、安装loadrunner 注意&#xff0c;以…...

VHDL语言基础-Testbech

目录 VHDL仿真概述: 基本结构: VHDL一般仿真过程: 仿真测试平台文件: 编写测试平台文件的语言: 一个测试平台文件的基本结构如下&#xff1a; 测试平台文件包含的基本语句: 产生激励信号的方式: 时钟信号: 复位信号: 周期信性信号: 使用延迟DELAYD: 一般的激励信号…...

机器学习基础总结

一&#xff0c;机器学习系统分类 机器学习系统分为三个类别&#xff0c;如下图所示: 二&#xff0c;如何处理数据中的缺失值 可以分为以下 2 种情况&#xff1a; 缺失值较多&#xff1a;直接舍弃该列特征&#xff0c;否则可能会带来较大噪声&#xff0c;从而对结果造成不良影…...

linux的三权分立设计思路和用户创建(安全管理员、系统管理员和审计管理员)

目录 一、三权分立设计思路 1、什么是三权 2、三员及权限的理解 3、三员之三权 4、权限划分 5、“三员”职责 6、“三员”配置要求 二、linux三权分立的用户创建 1、系统管理员 2、安全管理员 3、审计管理员 一、三权分立设计思路 1、什么是三权 三权指的是配置、…...

revit中如何创建有坡度的排水沟及基坑?

一、revit中如何创建有坡度的排水沟? 先分享一张有坡度排水沟的族的照片给大家加深一下印象&#xff0c;有了一个粗略的直观认识&#xff0c;小编就来说说做这个族的前期思路吧。 一、前期思路&#xff1a; 1、 用拼接的方式把这个族形状拼出来&#xff0c;先用放样&#xff0…...

Web自动化测试——selenium篇(一)

文章目录一、环境准备二、Web 自动化测试 Demo三、元素定位常用方法四、元素定位失败可能原因五、测试对象操作六、等待操作七、信息打印在学习 Web 自动化测试的过程中&#xff0c;selenium 是其中的常用工具。除了其开源免费&#xff0c;包含丰富的 API 以外&#xff0c;它还…...

认识 CSS pointer-events 属性

pointer-events 的基本信息 pointer-events 属性用来控制一个元素能否响应鼠标操作&#xff0c;常用的关键字有 auto 和 none pointer-events: none; // 让一个元素忽略鼠标操作 pointer-events: auto; // 还原浏览器设定的默认行为 规范定义 条目状态初始值auto可用值适用所…...

【java】springboot和springcloud区别

文章目录1、含义不同2、作用不同3、使用方式不同4、特征不同5、注释不同6、优势不同7、组件不同8、设计目的不同1、含义不同 springboot&#xff1a;一个快速开发框架&#xff0c;它简化了传统MVC的XML配置&#xff0c;使配置变得更加方便、简洁。 springcloud&#xff1a;是…...

4 生成器模式

生成器模式 的核心是&#xff1a;将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。简单说&#xff1a;像搭积木一样&#xff0c;用相同的步骤可以搭出不同样式的房子。建造房子的步骤是固定的&#xff1a;打地基建墙体安装屋顶装修内部但…...

龙为权,凰为心:凰标守住文化最柔软的底线@凤凰标志

龙为权凰为心 中国文艺生态的双轨平衡宣言秩序权力与创作初心&#xff0c;一刚一柔&#xff0c; 如日月轮值&#xff0c;缺一不可。 龙标掌「权」&#xff0c;凰标守「心」&#xff0c; 双轨并行&#xff0c;方可让文化既筋骨强健&#xff0c;又血肉温润。一、龙标&#xff1a;…...

告别混乱XML:Notepad++插件一键美化与智能纠错实战

1. 为什么我们需要XML格式化工具&#xff1f; 作为一个常年和XML打交道的开发者&#xff0c;我太清楚那种打开一个几千行XML文件时的绝望了——所有标签挤在一起&#xff0c;缩进混乱得像被猫抓过的毛线球&#xff0c;想找个节点得用CtrlF来回搜三遍。更可怕的是&#xff0c;有…...

基于LLM与RAG的法律AI工具:从架构解析到工程实践

1. 项目概述&#xff1a;一个法律文本智能生成与分析的AI工具最近在和一些做法律科技的朋友聊天时&#xff0c;他们反复提到一个痛点&#xff1a;处理海量的、格式固定的法律文书&#xff0c;比如起诉状、合同、律师函&#xff0c;既耗时又容易在细节上出错。人工起草一份严谨的…...

告别复杂配置:用MobaXterm+网线直连,5分钟让树莓派SSH并上网(Windows环境)

极简主义者的树莓派连接方案&#xff1a;MobaXterm全流程实战指南 树莓派作为一款功能强大的微型计算机&#xff0c;在嵌入式开发、物联网项目和教育领域广受欢迎。然而对于许多初学者甚至有一定经验的开发者来说&#xff0c;如何快速、稳定地连接树莓派始终是个令人头疼的问题…...

普遍认为赠送福利越多客户留存越高,编程统计福利投入,客户留存数据过度福利,会造成客户贪婪流失率上升。

“福利投入强度与客户留存的非线性关系分析” 为主题。一、实际应用场景描述&#xff08;Business Context&#xff09;在 SaaS、电商、会员制平台、在线教育等商业场景中&#xff0c;赠送福利&#xff08;优惠券、积分、试用权益、赠品等&#xff09;被广泛用于&#xff1a;- …...

Backlink Pilot:开源SEO自动化工具,提升外链建设效率

1. 项目概述&#xff1a;一个被低估的SEO自动化利器如果你在独立站、内容营销或者SEO领域摸爬滚打过一段时间&#xff0c;肯定对“外链建设”这四个字又爱又恨。爱的是&#xff0c;它确实是搜索引擎排名算法中一个极其重要的权重因子&#xff1b;恨的是&#xff0c;这个过程枯燥…...

3步打造专属桌面歌词体验:LyricsX macOS歌词神器完全指南

3步打造专属桌面歌词体验&#xff1a;LyricsX macOS歌词神器完全指南 【免费下载链接】Lyrics Swift-based iTunes plug-in to display lyrics on the desktop. 项目地址: https://gitcode.com/gh_mirrors/lyr/Lyrics LyricsX是一款专为macOS用户设计的开源桌面歌词显示…...

工程师幽默:从EE Times标题竞赛看技术文化表达与沟通艺术

1. 从“Wizard of Woz”看工程师文化的幽默表达看到“Wizard of Woz”这个标题&#xff0c;很多老电子工程师或硅谷历史爱好者大概会心一笑。这显然是在玩一个经典的双关梗——“Wizard of Oz”&#xff08;绿野仙踪&#xff09;和“Woz”&#xff08;史蒂夫沃兹尼亚克&#xf…...

FanControl终极指南:5步解决Windows风扇噪音与过热难题

FanControl终极指南&#xff1a;5步解决Windows风扇噪音与过热难题 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/f…...