Java Web 7 请求响应(Postman)

前言(SpringBoot程序请求响应流程)

以上一章的程序为例,一个基于SpringBoot的方式开发一个web应用,浏览器发起请求 /hello 后 ,给浏览器返回字符串 “Hello World ~”。

而我们在开发web程序时呢,定义了一个控制器类Controller,请求会被部署在Tomcat中的Controller接收,然后Controller再给浏览器一个响应,响应一个字符在浏览器发起请求,请求了我们的后端web服务器(也就是内置串 “Hello World”。 而在请求响应的过程中是遵循HTTP协议的。

但是在Tomcat这类Web服务器中,是不识别我们自己定义的Controller的。而Tomcat是一个Servlet容器,支持Serlvet规范,因此在tomcat中是可以识别 Servlet程序的。

  • Servlet(服务器小程序)是一种运行在 Web 服务器或应用服务器上的 Java 程序,用于处理客户端(如浏览器)发送的 HTTP 请求并生成响应。它是 Java Web 开发的核心组件之一,遵循 Java Servlet API 规范。
  • 简单来说,当用户通过浏览器访问一个网站时,浏览器会发送 HTTP 请求到 Web 服务器,服务器中的 Servlet 程序就会接收并处理这些请求,比如获取用户请求的页面内容、处理用户提交的表单数据等,然后生成一个响应返回给浏览器,这个响应可以是 HTML 页面、XML 数据、JSON 数据或者其他类型的内容。

那么在SpringBoot进行web程序开发时,它其实内置了一个核心的Servlet程序 DispatcherServlet,称之为 核心控制器,也可以叫做 前端控制器。 DispatcherServlet 负责接收页面发送的请求,然后根据执行的规则,将请求再转发给后面的请求处理器Controller,请求处理器处理完请求之后,最终再由DispatcherServlet给浏览器响应数据。

那将来浏览器发送请求,会携带请求数据,包括:请求行、请求头;请求到达tomcat之后,tomcat会负责解析这些请求数据,然后呢将解析后的请求数据会传递给Servlet程序中的HttpServletRequest对象,那也就意味着 HttpServletRequest 对象就可以获取到请求数据。 而Tomcat,还给Servlet程序传递了一个参数 HttpServletResponse,通过这个对象,我们就可以给浏览器设置响应数据 。

一 请求

 

1、Postman(接口测试工具)

postman的安装使用教程 我已经在另一篇文章详细介绍 Postman安装使用教程-CSDN博客

2、简单参数

①、原始方式

Tomcat接收到http请求时:把请求的相关信息封装到HttpServletRequest对象中

在Controller中,我们要想获取Request对象,可以直接在方法的形参中声明 HttpServletRequest 对象。然后就可以通过该对象来获取请求信息:

②、SpringBoot方法
在Springboot方法中可以自动进行类型转换。在Springboot的环境中,对原始的API进行了封装,接收参数的形式更加简单。 对于简单参数来讲,只要保证请求参数名和Controller方法中的形参名保持一致,就可以获取到请求参数中的数据值。

发送Post请求: 

如果形参与请求参数对应不上,也可以通过注解@RequestParam来进行映射:

 

但是如果没有设置@RequestParam注解,且方法形参名与请求参数名不一致,那么虽然会无法接收到请求数据,但是它不会报错 

注解@RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递就会报错:

 

 

③、小结

 

3、实体参数

在使用简单参数做为数据传递方式时,前端传递了多少个请求参数,后端controller方法中的形参就要书写多少个。如果请求参数比较多,通过上述的方式一个参数一个参数的接收,会比较繁琐。

①、简单实体对象

此时,我们可以考虑将请求参数封装到一个实体类对象中。 要想完成数据封装,需要遵守如下规则:请求参数名与实体类的属性名相同

User类 定义在实体类Pojo中 

②、复杂实体对象 

 

 

 

③、小结 

如果是复杂实体对象,也只需按照对象层次结构关系即可接收嵌套实体类属性参数

 

4、数组集合参数

数组集合参数的使用场景:在HTML的表单中,有一个表单项是支持多选的(复选框),可以提交选择的多个值

多个值是怎么提交的呢?其实多个值也是一个一个逐个提交的

①、数组

 

 ②、集合

 

requestparam适用场景:

**`@RequestParam`注解的使用场景**

1- **绑定单个请求参数** - 当你需要从HTTP请求(通常是GET或POST请求)中获取单个参数时,可以使用`@RequestParam`。

例如,在一个处理用户登录的方法中,如果前端通过表单提交了用户的用户名和密码,后端方法可以使用`@RequestParam`来获取这些参数。

```java @RequestMapping("/login")

public String login(@RequestParam("username") String username, @RequestParam("password") String password) {

        // 在这里进行登录验证逻辑

        return "loginSuccess";

} ```

- 这里`@RequestParam("username")`和`@RequestParam("password")`分别用于获取名为“username”和“password”的请求参数,并将其绑定到对应的方法参数上。

2- **参数非必需情况** - `@RequestParam`还可以处理参数不是必需的情况。你可以通过设置`required`属性来指定参数是否必需。例如:

```java @RequestMapping("/search")

public String search(@RequestParam(name = "keyword", required = false) String keyword) {

        if (keyword!= null) { // 进行搜索逻辑 }

         return "searchResult";

} ```

- 在这个例子中,“keyword”参数不是必需的。如果前端没有传递“keyword”参数,`keyword`方法参数将为`null`。

3- **设置默认值** - 当参数不是必需且你希望在参数未传递时给方法参数赋予一个默认值时,可以使用`@RequestParam`的`defaultValue`属性。

例如: ```java

@RequestMapping("/page")

public String showPage(@RequestParam(name = "pageNum", defaultValue = "1") int pageNum) {

         // 根据pageNum进行分页逻辑

        return "pageContent"; }

```

- 这里如果前端没有传递“pageNum”参数,`pageNum`方法参数将默认为`1`。

4- **绑定复杂类型列表或数组** - 除了单个参数,`@RequestParam`还可以用于绑定列表或数组类型的参数。例如,当你希望从前端获取多个同名参数的值时(比如多选框的值): ```java

@RequestMapping("/select") public String selectOptions(@RequestParam("selectedOptions") List<String> selectedOptions) {

         // 处理选中的选项

        return "selectionResult";

} ```

- 前端可能通过`?selectedOptions=option1&selectedOptions=option2`这种形式传递参数,后端使用`@RequestParam`将这些同名参数值绑定到`List<String>`中。

 一个细节点:

Array需要toString转换为字符串 而 List不需要 是因为:

 1. **`String[]`数组的情况**

- 在Java中,`System.out.println()`方法没有对数组类型进行特殊的重载处理。当直接传递一个数组给`System.out.println()`时,它实际上是调用`Object`类的`toString()`方法。对于数组来说,`Object`类的`toString()`方法返回的是一个类似`[类型@哈希码]`的字符串,这并不是我们想要的数组内容的表示形式。

- 而`Arrays.toString()`方法是`java.util.Arrays`类提供的一个工具方法,它专门用于将数组转换为一个包含数组元素的字符串,格式为`[元素1, 元素2,...]`。所以当我们有一个`String[]`类型的参数时,需要使用`Arrays.toString()`来将数组内容以可读的形式输出。

2. **`List<String>`列表的情况** - 对于`List`类型,`java.util.List`继承自`java.util.Collection`,而`Collection`类已经重写了`toString()`方法。当调用`System.out.println()`输出一个`List`对象时,实际上调用的是`List`类重写后的`toString()`方法。

- 重写后的`toString()`方法会按照`[元素1, 元素2,...]`的格式返回列表中的元素。所以,当我们有一个`List<String>`类型的参数时,可以直接将其传递给`System.out.println()`,就能得到列表内容的可读形式输出。

 

5、日期参数

因为日期的格式多种多样(如:2022-12-12 10:05:45 、2022/12/12 10:05:45),那么对于日期类型的参数在进行封装的时候,需要通过@DateTimeFormat注解,以及其pattern属性来设置日期的格式

 

 

 

 

 两个细节点:

1. **关于日期时间格式化模式中的大小写**

- 在`SimpleDateFormat`(用于格式化`java.util.Date`类型)以及相关的日期时间格式化模式中,`MM`和`HH`大写是有特定含义的,并且在`@DateTimeFormat`注解用于格式化`java.time.LocalDateTime`等类型时也遵循类似规则。

- `MM`用于表示月份,是月份的数字表示,范围是`01 - 12`。如果写成`mm`,则表示分钟,范围是`00 - 59`。

- `HH`用于表示24小时制的小时数,范围是`00 - 23`。如果写成`hh`,则表示12小时制的小时数,范围是`01 - 12`。

所以,为了准确表示你想要的日期时间格式部分,这些字母的大小写是很重要的。

2. **关于`LocalDateTime`输出中的`T`**

- `LocalDateTime`是Java 8引入的日期时间类型,它遵循ISO 8601日期时间格式标准。在ISO 8601格式中,日期和时间部分是通过`T`来分隔的。

- 例如,`2024 - 12 - 08T15:25:05`表示2024年12月8日15时25分05秒。`T`只是一个标准的分隔符,用于清晰地区分日期部分(`yyyy - MM - dd`)和时间部分(`HH:mm:ss`)。当你将`LocalDateTime`对象打印输出或者序列化为字符串时,就会按照这种标准格式来显示,方便在不同系统和应用之间进行日期时间信息的统一表示和交换。

6、JSON参数

在前后端进行交互时,如果是比较复杂的参数,前后端通过会使用JSON格式的数据进行传输。 (JSON是开发中最常用的前后端数据交互方式)

①、Postman在发送请求时,如何传递json格式的请求参数

 

 ②、在服务端的controller方法中,如何接收json格式的请求参数

服务端Controller方法接收JSON格式数据:

- 传递json格式的参数,在Controller中会使用实体类进行封装。

- 封装规则:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数。需要使用 @RequestBody标识。

- @RequestBody注解:将JSON数据映射到形参的实体类对象中(JSON中的key和实体类中的属性名保持一致)

 

requestbody注解

1. **处理HTTP请求体中的数据时使用`@RequestBody`**

- **接收JSON数据**

- 在现代Web开发中,当客户端(如前端应用或者其他外部系统)通过POST、PUT等请求方法发送JSON数据给后端服务时,后端通常使用`@RequestBody`来接收和解析这些数据。例如,在一个基于Spring Boot的Web应用中,有一个用户注册的功能。前端会收集用户的姓名、年龄、邮箱等信息,并将这些信息组装成一个JSON对象,像这样:

```json { "name": "John Doe",

                "age": 30,

                "email": "johndoe@example.com" } ```

后端的Spring Boot控制器方法可以这样接收数据:

```java

@RequestMapping(value = "/register", method = RequestMethod.POST)

        public String registerUser(@RequestBody User user) {

         // 将用户信息保存到数据库等操作

        return "success"; }

``` 这里假设`User`是一个Java类,包含`name`、`age`、`email`等属性。`@RequestBody`注解会自动将JSON数据解析并绑定到`User`对象的相应属性上。

- **接收XML数据(虽然现在JSON更常用)**

- 如果客户端发送XML格式的数据,也可以使用`@RequestBody`来处理。例如,假设客户端发送如下XML数据来表示一个订单:

```xml

        <order>

                <productId>

                        123

                </productId>

                <quantity>

                        5

                </quantity>

                <customerName>

                        Alice

                </customerName>

        </order> ```

后端可以定义一个`Order`类来匹配XML数据的结构,并且在控制器方法中使用`@RequestBody`来接收: ```java

@RequestMapping(value = "/placeOrder", method = RequestMethod.POST)

public String placeOrder(@RequestBody Order order) {

        // 处理订单逻辑,如保存订单到数据库等

        return "orderPlaced";

} ```

- **复杂数据类型传输**

- 当需要传输复杂的数据结构,如包含嵌套对象或者集合的对象时,`@RequestBody`非常有用。例如,一个包含多个商品信息的购物车对象,其中每个商品对象又包含商品名称、价格、数量等信息。前端将购物车数据以JSON格式发送: ```json

{

        "cartId": "C001",

        "items": [

                 {

                        "productName": "Book",

                        "price": 20.0,

                        "quantity": 2

                 },

                {

                        "productName": "Pen",

                         "price": 3.0,

                         "quantity": 5

                }

                     ]

} ```

后端可以通过`@RequestBody`接收并解析这个复杂的购物车对象: ```java @RequestMapping(value = "/checkout", method = RequestMethod.POST)

public String checkout(@RequestBody ShoppingCart cart) {

        // 计算总价、处理库存等结账逻辑

        return "checkoutSuccess";

} ``` 

requestmapping注解:

@RequestMapping注解的基本概念和用途

  • @RequestMapping是 Spring MVC 中用于处理请求地址映射的注解。它可以用在类和方法级别上。

@RequestMapping注解的属性

  • value属性(或path属性,它们是等价的):用于指定请求路径。可以是一个简单的字符串路径,也可以是一个包含多个路径的数组
  • method属性:用于指定请求方法。除了RequestMethod.GETRequestMethod.POST外,还可以指定RequestMethod.PUTRequestMethod.DELETERequestMethod.HEADRequestMethod.OPTIONS等。
  • consumes属性:用于指定请求的MIME类型(媒体类型)。例如,consumes = "application/json"表示该方法只处理JSON格式的请求体。
  • produces属性:用于指定响应的MIME类型。例如,produces = "application/json"表示该方法返回的响应是JSON格式。

7、路径参数

传统的开发中请求参数是放在请求体(POST请求)传递或跟在URL后面通过?key=value的形式传递(GET请求)

而在现在的开发中,还是经常会直接在请求的URL中传递参数。例如:

http://localhost:8080/user/1                

http://localhost:880/user/1/0

上述的这种传递请求参数的形式,就称之为 路径参数

①、传递单个参数

 

 

②、传递多个参数

和传递单个参数方法相同,无非就是多写一个形参和注解,需要注意的是:形参要和传递的参数相同才能接收成功

 

 

 8、相关代码

RequestController.java
package com.example.demo.controller;import com.example.demo.pojo.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;@RestController
public class RequestController {/*@RequestMapping("/simpleParam")public String simpleParam(String name, int age) {System.out.println(name + " " + age);return "OK";}*///1 简单参数@RequestMapping("/simpleParam")public String simpleParam(@RequestParam(name="name",required = false) String username, int age) {System.out.println(username + " " + age);return "OK";}//2 实体参数 简单实体参数 复杂实体参数@RequestMapping("/simplePojo")public String simplePojo(User user) {System.out.println(user);return "OK";}@RequestMapping("/complexPojo")public String complexPojo(User user) {System.out.println(user);return "OK";}//3 数组参数 集合参数@RequestMapping("/arrayParam")public String arrayParam(String[] hobby) {System.out.println(Arrays.toString(hobby));return "OK";}@RequestMapping("/listParam")public String listParam(@RequestParam List<String> hobby) {System.out.println(hobby);return "OK";}//4 日期参数@RequestMapping("/dateParam")public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime) {System.out.println(updateTime);return "OK";}//5 json参数@RequestMapping("/jsonParam")public String jsonParam(@RequestBody User user) {System.out.println(user);return "OK";}//6 路径参数@RequestMapping("/path/{id}")public String pathParam(@PathVariable Integer id) {System.out.println(id);return "OK";}@RequestMapping("/path/{id}/{name}")public String pathParam(@PathVariable Integer id, @PathVariable String name) {System.out.println(id + " " + name);return "OK";}
}

二、响应

1、@ResponseBody

在我们前面所编写的controller方法中,都已经设置了响应数据,那controller方法中的return的结果,怎么就可以响应给浏览器呢?

 

@RestController是两个注解的组合,@RestController = @Controller + @ResponseBody 

 

2、统一响应结果

大家有没有发现一个问题,我们在前面所编写的这些Controller方法中,返回值各种各样,没有任何的规范

 如果我们开发一个大型项目,项目中controller方法将成千上万,使用上述方式将造成整个项目难以维护。那在真实的项目开发中是什么样子的呢?

①、定义一个统一响应结构类 Result

在真实的项目开发中,无论是哪种方法,我们都会定义一个统一的返回结果。方案如下:

> 前端:只需要按照统一格式的返回结果进行解析(仅一种解析方案),就可以拿到数据

 定义在一个实体类Result来包含以上信息,代码如下:

public class Result {

    private Integer code;//响应码,1 代表成功; 0 代表失败

    private String msg;  //响应码 描述字符串

    private Object data; //返回的数据

    public Result() { }

    public Result(Integer code, String msg, Object data) {

        this.code = code;

        this.msg = msg;

        this.data = data;

    }

    public Integer getCode() {

        return code;

    }

    public void setCode(Integer code) {

        this.code = code;

    }

    public String getMsg() {

        return msg;

    }

    public void setMsg(String msg) {

        this.msg = msg;

    }

    public Object getData() {

        return data;

    }

    public void setData(Object data) {

        this.data = data;

    }

    //增删改 成功响应(不需要给前端返回数据)

    public static Result success(){

        return new Result(1,"success",null);

    }

    //查询 成功响应(把查询结果做为返回数据响应给前端)

    public static Result success(Object data){

        return new Result(1,"success",data);

    }

    //失败响应

    public static Result error(String msg){

        return new Result(0,msg,null);

    }

}

 效果展示:

②、小结 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/889045.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch多GPU训练教程

pytorch多GPU训练教程 文章目录 pytorch多GPU训练教程1. Torch 的两种并行化模型封装1.1 DataParallel1.2 DistributedDataParallel 2. 多GPU训练的三种架构组织方式2.2 数据不拆分&#xff0c;模型拆分&#xff08;Model Parallelism&#xff09;2.3 数据拆分&#xff0c;模型…

【opencv入门教程】9.视频加载

文章选自&#xff1a; 一、VideoCapture类 用于从视频文件、图像序列或摄像头捕获视频的类。函数&#xff1a;CV_WRAP VideoCapture();brief 默认构造函数CV_WRAP explicit VideoCapture(const String& filename, int apiPreference CAP_ANY);brief 使用 API 首选项打开…

海外的bug-hunters,不一样的403bypass

一种绕过403的新技术&#xff0c;跟大家分享一下。研究HTTP协议已经有一段时间了。发现HTTP协议的1.0版本可以绕过403。于是开始对lyncdiscover.microsoft.com域做FUZZ并且发现了几个403Forbidden的文件。 &#xff08;访问fsip.svc为403&#xff09; 在经过尝试后&#xff0…

阿里内部正式开源“Spring Cloud Alibaba (全彩小册)”

年轻的毕业生们满怀希望与忐忑&#xff0c;去寻找、竞争一个工作机会。已经在职的开发同学&#xff0c;也想通过社会招聘或者内推的时机争取到更好的待遇、更大的平台。 然而&#xff0c;面试人群众多&#xff0c;技术市场却相对冷淡&#xff0c;面试的同学们不得不面临着 1 个…

乘上 SpringBoot 东风,广场舞团掀起律动热潮

2 系统开发环境 2.1 Java技术 Java是由Sun公司推出的一门跨平台的面向对象的程序设计语言。因为Java 技术具有卓越的通用性、高效性、健壮的安全性和平台移植性的特点&#xff0c;而且Java是开源的&#xff0c;拥有全世界最大的开发者专业社群&#xff0c;所以Java的发展迅速。…

【PlantUML系列】状态图(六)

一、状态图的组成部分 状态&#xff1a;对象在其生命周期内可能处于的条件或情形&#xff0c;使用 state "State Name" as Statename 表示。初始状态&#xff1a;表示对象生命周期的开始&#xff0c;使用 [*] 表示。最终状态&#xff1a;表示对象生命周期的结束&…

创建 React Native 项目

创建 React Native 项目 npx react-nativelatest init YourProject切换依赖源 切换好源之后&#xff0c;你需要进入 android 目录&#xff0c;然后运行 gradlew build 命令。 Android 依赖安装是使用 gradlew 进行管理的。 $ cd android $ ./gradlew build --refresh-depend…

Linx下自动化之路:Redis安装包一键安装脚本实现无网极速部署并注册成服务

目录 简介 安装包下载 安装脚本 服务常用命令 简介 通过一键安装脚本实现 Redis 安装包的无网极速部署&#xff0c;并将其成功注册为系统服务&#xff0c;开机自启。 安装包下载 redis-7.0.8.tar.gzhttp://download.redis.io/releases/redis-7.0.8.tar.gz 安装脚本 修…

Meta Llama 3.3 70B:性能卓越且成本效益的新选择

Meta Llama 3.3 70B&#xff1a;性能卓越且成本效益的新选择 引言 在人工智能领域&#xff0c;大型语言模型一直是研究和应用的热点。Meta公司最近发布了其最新的Llama系列模型——Llama 3.3 70B&#xff0c;这是一个具有70亿参数的生成式AI模型&#xff0c;它在性能上与4050…

idea_maven详解

秒懂Maven maven简介maven安装和配置maven本地配置maven工程的GAVP创建maven工程项目结构说明项目构建说明 Maven依赖管理核心信息配置依赖管理配置依赖信息查询依赖范围设置依赖属性配置依赖下载失败错误解决Build构建配置依赖传递依赖冲突 maven工程继承继承作用应用场景继承…

Linux Ubuntu 安装配置RabbitMQ,springboot使用RabbitMQ

rabbit-Ubuntu 一篇文章学会RabbitMQ 在Ubuntu上查看RabbitMQ状态可以通过多种方式进行&#xff0c;包括使用命令行工具和Web管理界面。以下是一些常用的方法&#xff1a; 1-使用systemctl命令&#xff1a; sudo systemctl start rabbitmq-server sudo systemctl status ra…

LeetCode—189. 轮转数组(中等)

题目描述&#xff1a; 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例1&#xff1a; 输入: nums [1,2,3,4,5,6,7], k 3输出:[5,6,7,1,2,3,4] 解释: 向右轮转 1 步:[7,1,2,3,4,5,6] 向右轮转 2 步:[6,7,1,2,3,4,5] 向…

微信小程序报错:http://159.75.169.224:7300不在以下 request 合法域名列表中,请参考文档

要解决此问题&#xff0c;需打开微信小程序开发者工具进行设置&#xff0c;打开详情-本地设置重新运行&#xff0c;该报错就没有啦

vrrp主备备份

VRRP&#xff08;Virtual Router Redundancy Protocol&#xff0c;虚拟路由冗余协议&#xff09;是一种用于实现路由器冗余以提高网络可靠性的协议。以下是对VRRP的详细介绍&#xff1a; 基本概念 VRRP路由器&#xff1a;运行VRRP协议的路由器称为VRRP路由器。虚拟路由器&#…

Selenium:强大的 Web 自动化测试工具

Selenium&#xff1a;强大的 Web 自动化测试工具 在当今的软件开发和测试领域&#xff0c;自动化工具的重要性日益凸显。Selenium 就是一款备受欢迎的 Web 自动化测试工具&#xff0c;它为开发者和测试人员提供了强大的功能和便利。本文将详细介绍 Selenium 是什么&#xff0c…

Spark架构及运行流程

Spark架构图 Driver&#xff1a; 解析用户的应用程序代码&#xff0c;转化为作业(job)。创建SparkContext上下文对象&#xff0c;其负责与资源管理器(ClusterManager)通信&#xff0c;进行资源的申请、任务的分配和监控等。跟踪Executor的执行情况。可通过UI界面查询运行情况。…

【大模型系列篇】LLaMA-Factory大模型微调实践 - 从零开始

前一次我们使用了NVIDIA TensorRT-LLM 大模型推理框架对智谱chatglm3-6b模型格式进行了转换和量化压缩&#xff0c;并成功部署了推理服务&#xff0c;有兴趣的同学可以翻阅《NVIDIA TensorRT-LLM 大模型推理框架实践》&#xff0c;今天我们来实践如何通过LLaMA-Factory对大模型…

iOS如何自定义一个类似UITextView的本文编辑View

对于IOS涉及文本输入常用的两个View是UITextView和UITextField&#xff0c;一个用于复杂文本输入&#xff0c;一个用于简单文本输入&#xff0c;在大多数开发中涉及文本输入的场景使用这两个View能够满足需求。但是对于富文本编辑相关的开发&#xff0c;这两个View就无法满足自…

Android 使用 Canvas 和 Paint 实现圆角图片

学习笔记 效果展示: 全部代码: public class YuanActivity extends AppCompatActivity {private ActivityYuanBinding binding;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 通过 DataBinding 获取布局文件binding …

Java设计模式 —— 【创建型模式】建造者模式详解

文章目录 一、建造者模式二、案例实现三、优缺点四、模式拓展五、对比1、工厂方法模式VS建造者模式2、抽象工厂模式VS建造者模式 一、建造者模式 建造者模式&#xff08;Builder Pattern&#xff09; 又叫生成器模式&#xff0c;是一种对象构建模式。它可以将复杂对象的建造过…