咕咕鸽爱学习 - 后端学习
type: channel
link: https://bitday.top/category/%E5%90%8E%E7%AB%AF%E5%AD%A6%E4%B9%A0/
items: 测试
items: Mybatis&-Plus
items: DDD领域驱动设计
items: 消息队列MQ
items: Jmeter快速入门
items: 微信小程序
items: Maven
items: JAVA面试题
items: JavaWeb——后端

测试
type: item
date: 2025-07-31T00:10:03+08:00
description: 测试 小明今天15岁了，它是天水小学上学。

Mybatis&-Plus
type: item
date: 2025-07-05T14:55:21+08:00
description: Mybatis 快速创建 创建springboot工程（Spring Initializr），并导入 mybatis的起步依赖、mysql的驱动包。创建用户表user，并创建对应的实体类User 在springboot项目中，可以编写main/resources/application.properties文件，配置数据库连接信息。 #驱动类名称 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.url=jdbc:mysql://localhost:3306/mybatis #连接数据库的用户名 spring.datasource.username=root #连接数据库的密码 spring.datasource.password=1234 在引导类所在包下，在创建一个包 mapper。在mapper包下创建一个接口 UserMapper @Mapper注解：表示是mybatis中的Mapper接口 ​ -程序运行时：框架会自动生成接口的实现类对象(代理对象)，并交给Spring的IOC容器管理 @Select注解：代表的就是select查询，用于书写select查询语句 @Mapper public interface UserMapper { //查询所有用户数据 @Select("select * from user") public List<User> list(); } 数据库连接池 数据库连接池是一个容器，负责管理和分配数据库连接（Connection）。 在程序启动时，连接池会创建一定数量的数据库连接。 客户端在执行 SQL 时，从连接池获取连接对象，执行完 SQL 后，将连接归还给连接池，以供其他客户端复用。 如果连接对象长时间空闲且超过预设的最大空闲时间，连接池会自动释放该连接。 优势：避免频繁创建和销毁连接，提高数据库访问效率。 Druid（德鲁伊） Druid连接池是阿里巴巴开源的数据库连接池项目 功能强大，性能优秀，是Java语言最好的数据库连接池之一 把默认的 Hikari 数据库连接池切换为 Druid 数据库连接池： 在pom.xml文件中引入依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency> 在application.properties中引入数据库连接配置 spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis spring.datasource.druid.username=root spring.datasource.druid.password=123456 SQL注入问题$和# SQL注入：由于没有对用户输入进行充分检查，而SQL又是拼接而成，在用户输入参数时，在参数中添加一些SQL关键字，达到改变SQL运行结果的目的，也可以完成恶意攻击。 在Mybatis中提供的参数占位符有两种：${...} 、#{...} #{...} 执行SQL时，会将#{…}替换为?，生成预编译SQL，会自动设置参数值 使用时机：参数传递，都使用#{…} ${...} 拼接SQL。直接将参数拼接在SQL语句中，存在SQL注入问题 使用时机：如果对表名、列表进行动态设置时使用 SELECT * FROM ${tableName} WHERE id = #{id} userMapper.selectFromDynamicTable("user_2025", 1); 驼峰命名法 在 Java 项目中，数据库表字段名一般使用 下划线命名法（snake_case），而 Java 中的变量名使用 驼峰命名法（camelCase）。 小驼峰命名（lowerCamelCase）： 第一个单词的首字母小写，后续单词的首字母大写。 例子：firstName, userName, myVariable 大驼峰命名（UpperCamelCase）： 每个单词的首字母都大写，通常用于类名或类型名。 例子：MyClass, EmployeeData, OrderDetails 表中查询的数据封装到实体类中 实体类属性名和数据库表查询返回的字段名一致，mybatis会自动封装。 如果实体类…

DDD领域驱动设计
type: item
date: 2025-06-27T00:10:00+08:00
description: DDD领域驱动设计 什么是 DDD？ DDD（领域驱动设计，Domain-Driven Design）是一种软件设计方法论，它为软件工程设计提供了一套完整的指导思想与实践手段。通过领域、界限上下文、实体、值对象、聚合、工厂、仓储等概念，DDD 帮助我们合理划分工程模型，从而在前期投入更多思考，规划出可持续迭代和演进的系统架构。 在工程实践中，DDD 通常分为两个层面的设计： 1. 战略设计 战略设计关注复杂业务的宏观拆分。通过限界上下文和子域划分，将系统分治为独立模块或服务。拆分是否合理取决于上线效率：若每次改动牵涉多个服务，即是失败的“微服务单体”。更实用的方式是：以少数中等规模的核心应用为主体，构建周边服务生态，既保持灵活性，又避免过度拆分。 2. 战术设计 战术设计关注如何在代码层面表达业务概念。它强调通过面向对象建模，将业务逻辑封装进领域模型，并以实体、值对象、聚合和领域服务来承载业务行为，确保代码贴合业务语义。 传统的 MVC 三层架构往往只是 Service 层加数据模型的简单组合，容易导致 Service 类臃肿、逻辑复杂，甚至出现“贫血模型”问题——数据与行为分离，增加了维护难度。DDD 的战术设计通过丰富的领域模型来规避这一问题，使系统结构更清晰、业务逻辑更可维护。 为什么要用DDD？ 先说说传统Spring MVC： Spring MVC 传统上多采用 分层架构（Controller-Service-DAO）。 对于 简单业务 或 原型开发，这种方式足够清晰，开发成本低，上手快。 说说Spring MVC的不足： 在 复杂业务场景（核心逻辑复杂、规则频繁变化的系统）中，传统分层模式会暴露出明显问题： 1）业务逻辑分散： 大量 if-else、规则判断和外部调用混杂在 Service 中。 代码难以维护，稍有业务变更，就需要在已有方法里继续堆条件分支。 @Service public class OrderService { @Autowired private OrderRepository orderRepository; @Autowired private PaymentGateway paymentGateway; public void payOrder(Long orderId, String payMethod) { Order order = orderRepository.findById(orderId); // 校验订单 if (order == null) { throw new IllegalArgumentException("订单不存在"); } if (!order.getStatus().equals("UNPAID")) { throw new IllegalStateException("订单状态不允许支付"); } // 校验金额 if (order.getAmount().compareTo(BigDecimal.ZERO) <= 0) { throw new IllegalStateException("订单金额异常"); } // 支付逻辑 boolean success = paymentGateway.pay(order.getId(), order.getAmount(), payMethod); if (!success) { throw new RuntimeException("支付失败"); } // 修改状态 order.setStatus("PAID"); orderRepository.save(order); } } 一个 Service 同时承担校验、业务逻辑、状态修改、持久化和外部调用，演变成“上帝类”。 2）贫血模型：Entity/POJO 只存数据，业务逻辑全堆在 Service，对象与业务语义严重脱节，比如Order 类里找不到 pay()，只能在 OrderService 找到 payOrder()。 3）随着需求增长，Service 越来越庞大，修改风险高、测试困难。 引出DDD的价值 1）业务逻辑回归领域模型（充血模型） 通过 实体、值对象、聚合、领域服务 等概念，把业务规则放回领域模型中，实现高内聚： public class Order { private Long id; private BigDecimal amount; private String status; // 领域方法：支付 public void pay(PaymentGateway paymentGateway, String payMethod) { validateBeforePay(); boolean success = paymentGa…

消息队列MQ
type: item
date: 2025-05-28T00:10:00+08:00
description: 消息队列MQ 初识MQ 同步调用 同步调用有3个问题： 拓展性差，每次有新的需求，现有支付逻辑都要跟着变化，代码经常变动 性能下降，每次远程调用，调用者都是阻塞等待状态。最终整个业务的响应时长就是每次远程调用的执行时长之和 级联失败，当交易服务、通知服务出现故障时，整个事务都会回滚，交易失败。 异步调用 技术选型 RabbitMQ 部署 mq: #消息队列 image: rabbitmq:3.8-management container_name: mq restart: unless-stopped hostname: mq environment: TZ: "Asia/Shanghai" RABBITMQ_DEFAULT_USER: admin RABBITMQ_DEFAULT_PASS: "admin" ports: - "15672:15672" - "5672:5672" volumes: - mq-plugins:/plugins # 持久化数据卷，保存用户/队列/交换机等元数据 - ./mq-data:/var/lib/rabbitmq networks: - hmall-net volumes: mq-plugins: http://localhost:15672/ 访问控制台 架构图 publisher：生产者，发送消息的一方 consumer：消费者，消费消息的一方 queue：队列，存储消息。生产者投递的消息会暂存在消息队列中，等待消费者处理 exchange：交换机，负责消息路由。生产者发送的消息由交换机决定投递到哪个队列。不存储 virtual host：虚拟主机，起到数据隔离的作用。每个虚拟主机相互独立，有各自的exchange、queue（每个项目+环境有各自的vhost） 一个队列最多指定给一个消费者！ Spring AMQP 快速开始 交换机和队列都是直接在控制台创建，消息的发送和接收在Java应用中实现！ 简单案例：直接向队列发送消息，不经过交换机 引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> 配置MQ地址，在publisher和consumer服务的application.yml中添加配置： spring: rabbitmq: host: localhost # 你的虚拟机IP port: 5672 # 端口 virtual-host: /hmall # 虚拟主机 username: hmall # 用户名 password: 123 # 密码 消息发送： 然后在publisher服务中编写测试类SpringAmqpTest，并利用**RabbitTemplate**实现消息发送： @SpringBootTest public class SpringAmqpTest { @Autowired private RabbitTemplate rabbitTemplate; @Test public void testSimpleQueue() { // 队列名称 String queueName = "simple.queue"; // 消息 String message = "hello, spring amqp!"; // 发送消息 rabbitTemplate.convertAndSend(queueName, message); } } convertAndSend如果 2 个参数，第一个表示队列名，第二个表示消息； 消息接收 @Component public class SpringRabbitListener { // 利用RabbitListener来声明要监听的队列信息 // 将来一旦监听的队列中有了消息，就会推送给当前服务，调用当前方法，处理消息。 // 可以看到方法体中接收的就是消息体的内容 @RabbitListener(queues = "simple.queue") public void listenSimpleQueueMessage(String msg) throws InterruptedException { System.out.println("spring 消费者接收到消息：【" + msg + "】"); } } 然后启动启动类，它能自动从队列中取出消息。取出后队列中就没消息了！ 交换机 无论是 直连Direct、主题Topic 还是 扇形Fanout 交换机，你都可以用 同一个 Binding Key 把多条队列绑定到同一个交换机上。 1）…

Jmeter快速入门
type: item
date: 2025-05-27T00:10:00+08:00
description: Jmeter快速入门 1.安装Jmeter Jmeter依赖于JDK，所以必须确保当前计算机上已经安装了JDK，并且配置了环境变量。 1.1.下载 可以Apache Jmeter官网下载，地址：http://jmeter.apache.org/download_jmeter.cgi 1.2.解压 因为下载的是zip包，解压缩即可使用，目录结构如下： 其中的bin目录就是执行的脚本，其中包含启动脚本： 1.3.运行 双击即可运行，但是有两点注意： 启动速度比较慢，要耐心等待 启动后黑窗口不能关闭，否则Jmeter也跟着关闭了 2.快速入门 2.1.设置中文语言 默认Jmeter的语言是英文，需要设置： 效果： 注意：上面的配置只能保证本次运行是中文，如果要永久中文，需要修改Jmeter的配置文件 打开jmeter文件夹，在bin目录中找到 jmeter.properties，添加下面配置： language=zh_CN 注意：前面不要出现#，#代表注释，另外这里是下划线，不是中划线 2.2.基本用法 在测试计划上点鼠标右键，选择添加 > 线程（用户） > 线程组： 在新增的线程组中，填写线程信息： 给线程组点鼠标右键，添加http取样器： 编写取样器内容： 添加HTTP Header Content-Type=application/json 添加监听报告： 添加监听结果树： 汇总报告结果： 结果树： 清理结果，一个个监听器清理 或者全部清理：

Mybatis&-Plus
type: item
date: 2025-05-21T00:10:00+08:00
description: Mybatis 快速创建 创建springboot工程（Spring Initializr），并导入 mybatis的起步依赖、mysql的驱动包。创建用户表user，并创建对应的实体类User 在springboot项目中，可以编写main/resources/application.properties文件，配置数据库连接信息。 #驱动类名称 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.url=jdbc:mysql://localhost:3306/mybatis #连接数据库的用户名 spring.datasource.username=root #连接数据库的密码 spring.datasource.password=1234 在引导类所在包下，在创建一个包 mapper。在mapper包下创建一个接口 UserMapper @Mapper注解：表示是mybatis中的Mapper接口 ​ -程序运行时：框架会自动生成接口的实现类对象(代理对象)，并交给Spring的IOC容器管理 @Select注解：代表的就是select查询，用于书写select查询语句 @Mapper public interface UserMapper { //查询所有用户数据 @Select("select * from user") public List<User> list(); } 数据库连接池 数据库连接池是一个容器，负责管理和分配数据库连接（Connection）。 在程序启动时，连接池会创建一定数量的数据库连接。 客户端在执行 SQL 时，从连接池获取连接对象，执行完 SQL 后，将连接归还给连接池，以供其他客户端复用。 如果连接对象长时间空闲且超过预设的最大空闲时间，连接池会自动释放该连接。 优势：避免频繁创建和销毁连接，提高数据库访问效率。 Druid（德鲁伊） Druid连接池是阿里巴巴开源的数据库连接池项目 功能强大，性能优秀，是Java语言最好的数据库连接池之一 把默认的 Hikari 数据库连接池切换为 Druid 数据库连接池： 在pom.xml文件中引入依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency> 在application.properties中引入数据库连接配置 spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis spring.datasource.druid.username=root spring.datasource.druid.password=123456 SQL注入问题 SQL注入：由于没有对用户输入进行充分检查，而SQL又是拼接而成，在用户输入参数时，在参数中添加一些SQL关键字，达到改变SQL运行结果的目的，也可以完成恶意攻击。 在Mybatis中提供的参数占位符有两种：${...} 、#{...} #{...} 执行SQL时，会将#{…}替换为?，生成预编译SQL，会自动设置参数值 使用时机：参数传递，都使用#{…} ${...} 拼接SQL。直接将参数拼接在SQL语句中，存在SQL注入问题 使用时机：如果对表名、列表进行动态设置时使用 日志输出 只建议开发环境使用：在Mybatis当中我们可以借助日志，查看到sql语句的执行、执行传递的参数以及执行结果 打开application.properties文件 开启mybatis的日志，并指定输出到控制台 #指定mybatis输出日志的位置, 输出控制台 mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl 驼峰命名法 在 Java 项目中，数据库表字段名一般使用 下划线命名法（snake_case），而 Java 中的变量名使用 驼峰命名法（camelCase）。 小驼峰命名（lowerCamelCase）： 第一个单词的首字母小写，后续单词的首字母大写。 例子：firstName, userName, myVariable 大驼峰命名（UpperCamelCase）： 每个单词的首字…

微信小程序
type: item
date: 2025-04-26T19:59:00+08:00
description: 微信小程序 转载自黑马程序员。 微信小程序开发 介绍 小程序是一种新的开放能力，开发者可以快速地开发一个小程序。可以在微信内被便捷地获取和传播，同时具有出色的使用体验。 **官方网址：**https://mp.weixin.qq.com/cgi-bin/wx?token=&lang=zh_CN 小程序主要运行微信内部，可通过上述网站来整体了解微信小程序的开发。 **首先，**在进行小程序开发时，需要先去注册一个小程序，在注册的时候，它实际上又分成了不同的注册的主体。我们可以以个人的身份来注册一个小程序，当然，也可以以企业政府、媒体或者其他组织的方式来注册小程序。那么，不同的主体注册小程序，最终开放的权限也是不一样的。比如以个人身份来注册小程序，是无法开通支付权限的。若要提供支付功能，必须是企业、政府或者其它组织等。所以，不同的主体注册小程序后，可开发的功能是不一样的。 **然后，**微信小程序我们提供的一些开发的支持，实际上微信的官方是提供了一系列的工具来帮助开发者快速的接入 并且完成小程序的开发，提供了完善的开发文档，并且专门提供了一个开发者工具，还提供了相应的设计指南，同时也提供了一些小程序体验DEMO，可以快速的体验小程序实现的功能。 **最后，**开发完一个小程序要上线，也给我们提供了详细地接入流程。 准备工作 开发微信小程序之前需要做如下准备工作： 注册小程序 完善小程序信息 下载开发者工具 1). 注册小程序 注册地址：https://mp.weixin.qq.com/wxopen/waregister?action=step1 2). 完善小程序信息 登录小程序后台：https://mp.weixin.qq.com/ 两种登录方式选其一即可 完善小程序信息、小程序类目 查看小程序的 AppID与AppSecret 3). 下载开发者工具 资料中已提供，无需下载，熟悉下载步骤即可。 下载地址： https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html 扫描登录开发者工具 创建小程序项目 熟悉开发者工具布局 设置不校验合法域名 **注：**开发阶段，小程序发出请求到后端的Tomcat服务器，若不勾选，请求发送失败。 入门案例 实际上，小程序的开发本质上属于前端开发，主要使用JavaScript开发，咱们现在的定位主要还是在后端，所以，对于小程序开发简单了解即可。 小程序目录结构 小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。一个小程序主体部分由三个文件组成，必须放在项目的根目录，如下： 文件说明： **app.js：**必须存在，主要存放小程序的逻辑代码 **app.json：**必须存在，小程序配置文件，主要存放小程序的公共配置 app.wxss: 非必须存在，主要存放小程序公共样式表，类似于前端的CSS样式 对小程序主体三个文件了解后，其实一个小程序又有多个页面。比如说，有商品浏览页面、购物车的页面、订单支付的页面、商品的详情页面等等。那这些页面会放在哪呢？ 会存放在pages目录。 每个小程序页面主要由四个文件组成： 文件说明： **js文件：**必须存在，存放页面业务逻辑代码，编写的js代码。 **wxml文件：**必须存在，存放页面结构，主要是做页面布局，页面效果展示的，类似于HTML页面。 **json文件：**非必须，存放页面相关的配置。 **wxss文件：**非必须，存放页面样式表，相当于CSS文件。 编写和编译小程序 1). 编写 进入到index.wxml，编写页面布局 <view class="container"> <view>{{msg}}</view> <view> <button type="default" bindtap="getUserInfo">获取用户信息 <image style="width: 100px;height: 100px;" src="{{avatarUrl}}"></image> {{nickName}} </view> <view> <button type="primary" bindtap="wxlogin">微信登录 授权码：{{code}} </view> <view> <button type="warn" bindtap="sendRequest">发送请求 响应结果：{{result}} </view> </view> 进入到index.js，编写业务逻辑代码 Page({ data:{ msg:'hello world', avatarUrl:'', nickName:'', code:'', result:'' }, getUserIn…

Maven
type: item
date: 2025-04-17T18:56:00+08:00
description: Maven Maven仓库分为： 本地仓库：自己计算机上的一个目录(用来存储jar包) 中央仓库：由Maven团队维护的全球唯一的。仓库地址：https://repo1.maven.org/maven2/ 远程仓库(私服)：一般由公司团队搭建的私有仓库 POM文件导入依赖的时候，先看本地仓库有没有，没有就看私服，再没有就从中央仓库下载。 Maven创建/导入项目 创建Maven项目 勾选 Create from archetype（可选），也可以选择 maven-archetype-quickstart 等模版。 点击 Next，填写 GAV 坐标 。 GroupId：标识组织或公司（通常使用域名反写，如 com.example） ArtifactId：标识具体项目或模块（如 my-app、spring-boot-starter-web）。 Version：标识版本号（如 1.0-SNAPSHOT、2.7.3） 导入Maven项目 （一）单独的Maven项目 打开 IDEA，在主界面选择 Open（或者在菜单栏选择 File -> Open）。 在文件选择对话框中，定位到已有项目的根目录（包含 pom.xml 的目录）。 选择该目录后，IDEA 会检测到 pom.xml 并询问是否导入为 Maven 项目，点击 OK 或 Import 即可。 IDEA 会自动解析 pom.xml，下载依赖并构建项目结构。 （二）在现有Maven项目中导入独立的Maven项目 在已经打开的 IDEA 窗口中，使用 File -> New -> Module from Existing Sources... 选择待导入项目的根目录（其中包含 pom.xml），IDEA 会将其导入为同一个工程下的另一个模块（Module）。 它们 看起来在一个工程里了，但仍然是两个独立的 Maven 模块。 （三）两个模块属于同一个工程下 可以用一个父pom进行统一管理！ 1.新建一个上层目录，如下，MyProject1和MyProject2的内容拷贝过去。 ParentProject/ ├── pom.xml <-- 父模块（聚合模块） ├── MyProject1/ <-- 子模块1 │ └── pom.xml └── MyProject2/ <-- 子模块2 └── pom.xml 2.创建父级pom 父模块 pom.xml 示例： <project> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>ParentProject</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> //必写 <modules> <module>MyProject1</module> //必写 <module>MyProject2</module> </modules> </project> 3.修改子模块 pom.xml ，加上： <parent> <groupId>com.example</groupId> <artifactId>ParentProject</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> 如果子模块中无需与父级不同的配置，可以不写，就自动继承父级配置；若写了同名配置，则表示你想要覆盖或合并父级配置。 4.File -> Open选择父级的pom，会自动导入其下面两个项目。 但是，仅仅这样无法让模块之间产生联动！需要在此基础上进行（四）的操作！ （四）通过 Maven 依赖引用 如果你的两个模块之间存在依赖关系（如第一个模块需要使用第二个模块的类）还必须在 MyProject1 的 POM 里显式声明对 MyProject2 的依赖。 MyProject1的pom.xml: <project> <parent> <groupId>com.example</groupId> <artifactId>ParentProject</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <artifactId>MyProject1</artifactId> <packaging>jar</packaging> <dependencies> <dependency> <groupId>com.examp…

JAVA面试题
type: item
date: 2025-04-03T00:10:00+08:00
description: JAVA基础 JDK和JRE JDK 是开发环境，JRE 是运行环境。 JDK（Java Development Kit） = JRE + 开发工具（如 javac 编译器、调试器等）； JRE（Java Runtime Environment） = JVM + 核心类库，只负责运行 Java 程序。 开发用 JDK，运行用 JRE。 Java 面向对象的四大特性 封装（Encapsulation） 含义：把数据和操作数据的方法封装在对象内部，对外只暴露必要的接口，隐藏实现细节。 好处：降低耦合、提高安全性、便于维护。 继承（Inheritance） 含义：子类继承父类，复用代码，同时可以扩展或重写父类功能。 好处：提高代码复用性，建立层次结构。 多态（Polymorphism） 含义：同一方法调用在不同对象上表现出不同的行为（编译时多态/运行时多态）。 好处：增强灵活性、可扩展性。 在框架层面的应用 封装：Spring 的 Bean的字段通常 private，通过 setter/getter 控制访问。 继承：模板方法模式提供了执行流程的骨架,子类必须继承才能扩展步骤。 而策略模式继承只是辅助，真正的精髓是组合和可替换性。 // 伪代码示例：JdbcTemplate的execute骨架 public abstract class JdbcTemplate { public final void execute() { // final防止子类重写算法骨架 getConnection(); // 固定步骤1 doStatement(); // 抽象方法，由子类实现 releaseConnection(); // 固定步骤2 } protected abstract void doStatement(); // 可变部分，子类实现 } 多态：多态的前提之一是继承/实现。Spring 的依赖注入（DI）注入接口类型，运行时由容器选择具体实现（Servcie）。多态强调的是运行时动态分派。 编译期用的是 接口引用，运行期执行的是 实现类方法，这就是多态。 JAVA创建对象的方法 1.运用反射 Class 类的 newInstance() 方法 MyClass obj = (MyClass) Class.forName("MyClass").newInstance(); 依赖无参构造方法； 2.运用反射 Constructor 类的 newInstance() 方法 Constructor<MyClass> cons = MyClass.class.getConstructor(); MyClass obj = cons.newInstance(); 这是 反射创建对象 的推荐方式； 可调用有参或无参构造函数； 3.调用对象的 clone() 方法 MyClass obj1 = new MyClass(); MyClass obj2 = (MyClass) obj1.clone(); clone() 创建的是一个新的对象（地址不同），但复制了字段值。 是一种基于已有对象复制的创建方式。 实现类必须实现 Cloneable 接口： class MyClass implements Cloneable { int x = 10; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); // 调用 Object 的 clone() } } 4.使用 new 关键字创建 MyClass obj = new MyClass(); 说说 Java 中 HashMap 的原理？ HashMap 允许 1 个 null key、多条 null value，因为单线程场景下没歧义。 为什么引入红黑树: 当hash冲突较多的时候，链表中的元素会增多，插入、删除、查询的效率会变低，退化成O(n)使用红黑树可以优化插入、删除、查询的效率，logN级别。 转换时机: 链表上的元素个数大于等于8 且 数组长度大于等于64； 链表上的元素个数小于等于6的时候，红黑树退化成链表。 JDK8为什么从"头插法"改为"尾插法" 头插法特点： 插入时不需要遍历链表 直接替换头结点 扩容时会导致链表逆序 多线程环境下可能产生死循环 尾插法改进： 避免扩容时的链表逆序 解决多线程环境下的潜在死循环问题 死循环产生场景 旧桶链表： A -> B -> C -> null 线程1 迁移时： 先拿到 A，放到新桶头部。 此时新桶是 A -> null。 线程 2 也在迁移，刚好也拿到 B，打算放到新桶头： 修改 B.next = A，新桶成了 B -> A…

JavaWeb——后端
type: item
date: 2025-03-21T16:12:00+08:00
description: JavaWeb——后端 好用的操作 右键文件/文件夹选择Copy Path/Reference，可以获得完整的包路径 Java版本解决方案 单个Java文件运行： Edit Configurations 针对单个运行配置：每个 Java 运行配置（如主类、测试类等）可以独立设置其运行环境（如 JRE 版本、程序参数、环境变量等）。 不影响全局项目：修改某个运行配置的环境不会影响其他运行配置或项目的全局设置。 如何调整全局项目的环境 打开 File -> Project Structure -> Project。 在 Project SDK 中选择全局的 JDK 版本（如 JDK 17）。 在 Project language level 中设置全局的语言级别（如 17）。 Java Compiler File -> Settings -> Build, Execution, Deployment -> Compiler -> Java Compiler Maven Runner File -> Settings -> Build, Execution, Deployment -> Build Tools -> Maven -> Runner 三者之间的关系 全局项目环境 是基准，决定项目的默认 JDK 和语言级别。 Java Compiler 控制编译行为，可以覆盖全局的 Project language level。 Maven Runner 控制 Maven 命令的运行环境，可以覆盖全局的 Project SDK。 Maven 项目： 确保 pom.xml 中的 <maven.compiler.source> 和 <maven.compiler.target> 与 Project SDK 和 Java Compiler 的配置一致。 确保 Maven Runner 中的 JRE 与 Project SDK 一致。 如果还是不行，pom文件右键点击maven->reload project HTTP协议 响应状态码 状态码分类 说明 1xx 响应中 --- 临时状态码。表示请求已经接受，告诉客户端应该继续请求或者如果已经完成则忽略 2xx 成功 --- 表示请求已经被成功接收，处理已完成 3xx 重定向 --- 重定向到其它地方，让客户端再发起一个请求以完成整个处理 4xx 客户端错误 --- 处理发生错误，责任在客户端，如：客户端的请求一个不存在的资源，客户端未被授权，禁止访问等 5xx 服务器端错误 --- 处理发生错误，责任在服务端，如：服务端抛出异常，路由出错，HTTP版本不支持等 状态码 英文描述 解释 200 OK 客户端请求成功，即处理成功，这是我们最想看到的状态码 302 Found 指示所请求的资源已移动到由Location响应头给定的 URL，浏览器会自动重新访问到这个页面 304 Not Modified 告诉客户端，你请求的资源至上次取得后，服务端并未更改，你直接用你本地缓存吧。隐式重定向 400 Bad Request 客户端请求有语法错误，不能被服务器所理解 403 Forbidden 服务器收到请求，但是拒绝提供服务，比如：没有权限访问相关资源 404 Not Found 请求资源不存在，一般是URL输入有误，或者网站资源被删除了 405 Method Not Allowed 请求方式有误，比如应该用GET请求方式的资源，用了POST 429 Too Many Requests 指示用户在给定时间内发送了太多请求（“限速”），配合 Retry-After(多长时间后可以请求)响应头一起使用 500 Internal Server Error 服务器发生不可预期的错误。服务器出异常了，赶紧看日志去吧 503 Service Unavailable 服务器尚未准备好处理请求，服务器刚刚启动，还未初始化好 开发规范 REST风格 在前后端进行交互的时候，我们需要基于当前主流的REST风格的API接口进行交互。 什么是REST风格呢? REST（Representational State Transfer），表述性状态转换，它是一种软件架构风格。 传统URL风格如下： http://localhost:8080/user/getById?id=1 GET：查询id为1的用户 http://localhost:8080/user/saveUser POST：新增用户 http://localhost:8080/user/updateUser PUT：修改用户 http://localhost:8080/user/deleteUser?id=1 DELETE：删除id为1的用户 我们看到，原始的传统URL…