【SpringBoot教程】SpringBoot整合Mybatis - 前后端分离项目 - vue3


🌈个人首页: 神马都会亿点点的毛毛张

今天毛毛张将通过一个完整的前后端分离的任务来介绍SpringBoot整合Mybatis过程!
文章目录
- 1.前言
- 1.1 任务描述
- 1.2 SpringBoot整合Mybatis概述
- 1.3 完整项目文件
- 2.后端工程搭建
- 2.1 项目搭建
- 2.2 导入依赖pom.xml
- 2.3 初始化数据
- 2.4 编写配置文件`application.yaml`
- 2.5 创建User类
- 2.6 编写controller | service | mapper
- 2.7 工具类
- 2.8 拦截器-跨域资源共享CorsInterceptor
- 2.9 配置类WebConfig
- 2.10 最重要一步:修改启动类扫描Mapper接口
- 2.11 编写测试类
- 2.12 使用Postman测试接口
- 3.前端工程搭建
- 3.1 前端项目搭建
- 3.2 修改配置文件vite.config.js
- 3.3 引入插件main.js
- 3.4 修改主页App.vue
- 3.5 用户信息展示逻辑showAllUserInfo.vue
- 3.6 数据传递与请求发送
- 3.7 路由代码
- 3.8 请求拦截处理
- 4.源代码
1.前言
- 今天毛毛张要分享的是SpringBoot整合Mybatis的教程,毛毛张将从前后端分离的方式、通过一个完整的任务来教大家整合的整个过程
- 毛毛张在这里只是为了分享一个整合的流程和步骤以及注意事项,让大家先能用起来,等会用了之后就可以去官网查看更多的教程了:Mybatis3中文教程官网
- 我记得在《县委大院》电视剧里面有这样一句话:功在千秋的事情 能理解最好 不能理解就先干着 慢慢理解。虽然用在这里不是很对,但是我想说的是,在新学一门技术的时候要先学会如何使用,等会使用了,在去慢慢的深入理解,去官网看更多的信息,Mybatis有很多内容,毛毛张很难通过文字的方式把全部内容介绍完毕。
- 版本:
- 后端:
- SpringBoot:2.7.6
- JDK:17
- Mybatis:2.2.2
- 前端
- vite:6.0.5
- vue:3.5.13
- vue-router:4.5.0
- pinia:2.3.0
- axios:1.7.9
- 后端:
1.1 任务描述
- 通过SpringBoot整合Mybatis框架,查询数据库所有用户信息,并展示给前端
1.2 SpringBoot整合Mybatis概述
-
毛毛张首先在这里介绍整合SpringBoot的几个关键点
-
首先是导入依赖:不光是只导入Mybatis依赖
<!-- MyBatis 依赖 --> <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version> </dependency><!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! --> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope> <!-- 运行时依赖 --> </dependency>
-
然后是根据数据库编写对应的实体类,比如说用户信息表对应的实体类:
package com.zzx.user.repository.entity;import lombok.Data;@Data public class User {private Integer id; // 对应数据库中的 `u_id`private String userName; // 对应数据库中的 `u_username`private String passWord; // 对应数据库中的 `u_password`private Integer age; // 对应数据库中的 `u_age`private String gender; // 对应数据库中的 `u_gender` }
-
接着编写MyBatis 框架中用于映射 SQL 语句的配置文件
XXXMapper.xml
文件以及对应的Mapper
接口类:package com.zzx.user.repository.mapper;import com.zzx.user.repository.entity.User;import java.util.List;public interface UserMapper {List<User> queryAllUserInfo(); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace = mapper 对应接口的全限定符 --> <mapper namespace="com.zzx.user.repository.mapper.UserMapper"><!-- 声明标签写sql语句 crud select insert update delete每个标签对应接口的一个方法! 方法的一个实现!注意:mapper接口不能重载!!! 因为mapper.xml无法识别! 根据方法名识别!--><!-- 查询所有用户的mysql语句 --><!-- <select id="queryAllUserInfo" resultType="com.zzx.user.repository.entity.User">--><!-- 我已经把实体包的路径写在了yaml文件的mybatis配置下了,所以下面可以直接写resultType="User" --><select id="queryAllUserInfo" resultType="User">SELECTid,user_name,pass_word,age,genderFROM user_info <!-- 使用带有前缀的表名 --></select> </mapper>
-
然后是在配置文件中编写Mybatis相关的配置:
mybatis:# Mapper 文件的位置mapper-locations: classpath:mappers/*Mapper.xml# 实体类的包路径type-aliases-package: com.zzx.user.repository.entity # 修改成自己的configuration:# 自动下划线转驼峰map-underscore-to-camel-case: true
-
最后一步,最重要的一步,不要忘记扫描
Mapper
接口所在的包:package com.zzx;import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication @MapperScan("com.zzx.user.repository.mapper") // 扫描 Mapper 接口所在的包 public class SpringbootMybatisDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootMybatisDemoApplication.class, args);}}
1.3 完整项目文件
- 访问毛毛张Github仓库:https://github.com/zzxrepository/SpringBootTutorial/tree/master/springboot-mybatis
2.后端工程搭建
2.1 项目搭建
- 如何快速创建一个Maven项目注意的细节可以参看毛毛张的上一篇文章:【SpringBoot教程】IDEA快速搭建正确的SpringBoot版本和Java版本的项目
- 毛毛张在这里选择的
SpringBoot
版本为2.7.6
,JDK
选择的是JDK17
,下面是毛毛张搭建好的整个项目的完整文件夹:
- 毛毛张在这里使用的是阿里云的国内源创建的SpringBoot项目,这样才能创建2.7.x的项目,具体原因参见这篇文章:【SpringBoot教程】IDEA快速搭建正确的SpringBoot版本和Java版本的项目
- 创建好之后的项目如下所示,可用把下图中两个没用的文件去掉
2.2 导入依赖pom.xml
-
在整合
Mybatis
的时候很显然的是需要导入Mybatis
依赖,MyBatis 用于数据库操作,在 Spring Boot 中使用时,也需要导入数据库驱动的依赖,这是很多教程忽略的地方<!-- MyBatis 依赖 --> <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version> </dependency><!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! --> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope> <!-- 运行时依赖 --> </dependency>
-
对于一个完整的项目来说,为了简化实体类对象的构造方法以及Getter\Setter方法,还需要导入
Lombok
依赖,不熟悉该依赖的可以直接手写;用于测试代码的依赖,毛毛张这里选择的是SpringBoot的spring-boot-starter-test
,如果熟悉的选择juint
也行;这是一个前后端分离的项目,还需要导入用于构建Web
应用的依赖spring-boot-starter-web
-
还需要注意的是,毛毛张在这里使用的是SpringBoot默认的连接池
hikari
,而没有选择Druid
连接池,所以没有导入连接池的依赖,毛毛张后面还会出专门的教程分享这个知识点 -
项目完整的
pom.xml
文件如下:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!-- 父项目配置:使用 Spring Boot 的父项目来简化配置 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.6</version> <!-- Spring Boot 的版本 --><relativePath/> <!-- 从仓库中查找父项目 --></parent><!-- 项目基础信息 --><groupId>com.zzx</groupId> <!-- 组织标识 --><artifactId>springboot-mybatis-demo</artifactId> <!-- 项目名称 --><version>0.0.1-SNAPSHOT</version> <!-- 项目版本 --><name>springboot-mybatis-demo</name> <!-- 项目名称 --><description>springboot-mybatis-demo</description> <!-- 项目描述 --><!-- Java 版本配置 --><properties><java.version>17</java.version> <!-- 项目使用的 Java 版本 --></properties><!-- 依赖项配置 --><dependencies><!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope> <!-- 运行时依赖 --></dependency><!-- MyBatis 依赖 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version></dependency><!-- Lombok 依赖 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.36</version><scope>provided</scope> <!-- 可选:标记为 provided --></dependency><!-- Spring Boot Starter Web 依赖,用于构建 Web 应用 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot Starter Test 依赖,用于测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope> <!-- 测试范围依赖 --></dependency></dependencies><!-- 构建配置 --><build><plugins><!-- Maven 编译插件,用于处理注解处理器(如 Lombok) --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version> <!-- 指定插件版本 --><configuration><source>${java.version}</source> <!-- Java 源代码版本 --><target>${java.version}</target> <!-- Java 字节码版本 --><annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.36</version> <!-- 确保版本匹配 --></path></annotationProcessorPaths></configuration></plugin><!-- Spring Boot Maven 插件,用于构建可执行的 Spring Boot JAR --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.7.1</version> <!-- 确保版本与父项目一致 --><!-- 不需要排除 Lombok,除非有特定需求 --></plugin></plugins></build> </project>
2.3 初始化数据
- 通过Navicat工具创建数据库
springboot
,并执行下面mysql
语句,创建用户信息表user_info
mysql
语句:/*Navicat Premium Dump SQLSource Server : 本地数据库Source Server Type : MySQLSource Server Version : 80026 (8.0.26)Source Host : localhost:3306Source Schema : springbootTarget Server Type : MySQLTarget Server Version : 80026 (8.0.26)File Encoding : 65001Date: 29/12/2024 18:39:38 */SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0;-- ---------------------------- -- Table structure for user_info -- ---------------------------- DROP TABLE IF EXISTS `user_info`; CREATE TABLE `user_info` (`id` int NOT NULL AUTO_INCREMENT,`user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,`pass_word` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,`age` int NULL DEFAULT NULL,`gender` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;-- ---------------------------- -- Records of user_info -- ---------------------------- INSERT INTO `user_info` VALUES (1, 'sam', 'password123', 32, 'M'); INSERT INTO `user_info` VALUES (2, 'hah', 'password456', 10, 'F');SET FOREIGN_KEY_CHECKS = 1;
2.4 编写配置文件application.yaml
- 根据注释的指示修改对应的地方(数据库名、数据库用户名、数据库密码、实体类对应的包)
server:port: 8080spring:# HikariCP 连接池配置# 参考链接:https://www.cnblogs.com/goloving/p/14884802.htmldatasource:url: jdbc:mysql://localhost:3306/springboot?useSSL=false&autoReconnect=true&characterEncoding=utf8 driver-class-name: com.mysql.cj.jdbc.Driverusername: root # 改成自己的password: abc123 # 改成自己的# 指定数据源类型为 HikariDataSourcetype: com.zaxxer.hikari.HikariDataSource# Hikari 连接池的详细配置hikari:# 连接池名称pool-name: HikariCP# 最小空闲连接数minimum-idle: 5# 空闲连接超时时间(毫秒)idle-timeout: 600000# 连接池的最大大小maximum-pool-size: 10# 是否自动提交事务auto-commit: true# 连接的最大生命周期(毫秒)max-lifetime: 1800000# 连接超时时间(毫秒)connection-timeout: 30000# 测试连接的 SQL 语句connection-test-query: SELECT 1logging:level:org.springframework.jdbc.core.JdbcTemplate: DEBUGmybatis:# Mapper 文件的位置mapper-locations: classpath:mappers/*Mapper.xml# 实体类的包路径type-aliases-package: com.zzx.user.repository.entity # 修改成自己的configuration:# 自动下划线转驼峰map-underscore-to-camel-case: true
- 注意,由于在数据库的设计中,毛毛张对用户信息的用户名和密码使用的是下划线的方式,所以在配置文件中开启了自动下划线转驼峰
map-underscore-to-camel-case: true
,这是为了考察知识点,毛毛张特地设计的
2.5 创建User类
package com.zzx.user.repository.entity;import lombok.Data;@Data
public class User {private Integer id; // 对应数据库中的 `u_id`private String userName; // 对应数据库中的 `u_username`private String passWord; // 对应数据库中的 `u_password`private Integer age; // 对应数据库中的 `u_age`private String gender; // 对应数据库中的 `u_gender`
}
2.6 编写controller | service | mapper
-
controller类:查询所有用户信息
package com.zzx.user.controller;import com.zzx.user.converter.UserConverter; import com.zzx.user.model.vo.dto.UserInfoDTO; import com.zzx.user.reponse.ResVo; import com.zzx.user.repository.entity.User; import com.zzx.user.service.UserService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource; import java.util.List;@RestController @RequestMapping("user") public class UserController {@Resourceprivate UserService userService;@GetMapping("queryAllUserInfo") // 使用 GET 请求public ResVo<List<UserInfoDTO>> queryAllUserInfo() {List<User> userList = userService.queryAllUserInfo();List<UserInfoDTO> userInfoDTOList = UserConverter.toUserInfoDTOList(userList);return ResVo.success(userInfoDTOList);} }
-
service类:
package com.zzx.user.service;import com.zzx.user.repository.entity.User; import org.springframework.stereotype.Service;import java.util.List;public interface UserService {List<User> queryAllUserInfo(); }
-
service实现类:
package com.zzx.user.service.impl;import com.zzx.user.repository.entity.User; import com.zzx.user.repository.mapper.UserMapper; import com.zzx.user.service.UserService; import org.springframework.stereotype.Service;import javax.annotation.Resource; import java.util.List;@Service public class UserServiceImpl implements UserService {@Resourceprivate UserMapper userMapper;@Overridepublic List<User> queryAllUserInfo() {return userMapper.queryAllUserInfo();} }
-
mapper接口:
package com.zzx.user.repository.mapper;import com.zzx.user.repository.entity.User;import java.util.List;public interface UserMapper {List<User> queryAllUserInfo(); }
-
mapper.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace = mapper 对应接口的全限定符 --> <mapper namespace="com.zzx.user.repository.mapper.UserMapper"><!-- 声明标签写sql语句 crud select insert update delete每个标签对应接口的一个方法! 方法的一个实现!注意:mapper接口不能重载!!! 因为mapper.xml无法识别! 根据方法名识别!--><!-- 查询所有用户 --><!-- <select id="queryAllUserInfo" resultType="com.zzx.user.repository.entity.User">--><!-- 我已经把实体包的路径写在了yaml文件的mybatis配置下了,所以下面可以直接写resultType="User" --><select id="queryAllUserInfo" resultType="User">SELECTid,user_name,pass_word,age,genderFROM user_info <!-- 使用带有前缀的表名 --></select> </mapper>
2.7 工具类
-
响应类ResVo:
package com.zzx.user.reponse;public class ResVo<T> {private Integer code; // 状态码private String message; // 消息内容private T content; // 内容,可以是任何类型的数据// 构造方法public ResVo(Integer code, String message, T content) {this.code = code;this.message = message;this.content = content;}// 成功的返回,通常是常用的,内容可以为空public static <T> ResVo<T> success(T content) {return new ResVo<>(200, "成功", content);}// 失败的返回,通常返回错误信息public static <T> ResVo<T> error(Integer code, String message) {return new ResVo<>(code, message, null);}// Getters and Setterspublic Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getContent() {return content;}public void setContent(T content) {this.content = content;} }
-
前端对象返回类
UserInfoDTO
,在查询用户信息时通过是把查询到的结果封装在一个实体类中,但是返回给前端的信息不一定是用户的全部信息,例如用户的密码就不能直接返回给前端,或者不要返回,所以毛毛张设计了一个这个类:package com.zzx.user.model.vo.dto;import lombok.Data;@Data public class UserInfoDTO {// 返回给前端的用户信息,不需要密码,同时要将性别转化成数字private Integer id;private String username;private Integer age;private Integer gender; }
-
为了节省传输的字符,毛毛张将用户的信息对应的内容转化成数字再返回给前端,因此设计了一个枚举类型
UserSexEnum
:package com.zzx.user.model.enums;public enum UserSexEnum {M(1, "男"), // M对应男,值为 1F(0, "女"); // F对应女,值为 0private int code; // 对应的数字值(1 或 0)private String description; // 性别描述(男 或 女)// 构造方法,用于设置枚举常量的描述和对应的代码UserSexEnum(int code, String description) {this.code = code;this.description = description;}// 获取性别描述public String getDescription() {return description;}// 获取对应的数字代码public int getCode() {return code;}// 根据传入的字符串 'M' 或 'F' 获取对应的性别枚举public static UserSexEnum fromString(String sexStr) {for (UserSexEnum sex : UserSexEnum.values()) {if (sex.name().equalsIgnoreCase(sexStr)) {return sex;}}throw new IllegalArgumentException("无效的性别字符串: " + sexStr);}// 根据 'M' 或 'F' 获取对应的数字代码public static int getCodeByString(String sexStr) {UserSexEnum sex = fromString(sexStr);return sex.getCode();} }
-
由于
User
类和UserInfoDTO
不是完全一一对应的,所以为了数据转换的方便,毛毛张再这里专门写了一个转换类UserConverter
:package com.zzx.user.converter;import com.zzx.user.model.enums.UserSexEnum; import com.zzx.user.model.vo.dto.UserInfoDTO; import com.zzx.user.repository.entity.User;import java.util.List; import java.util.stream.Collectors;public class UserConverter {// 单个转换public static UserInfoDTO toUserInfoDTO(User user) {UserInfoDTO userInfoDTO = new UserInfoDTO();userInfoDTO.setId(user.getId());userInfoDTO.setUsername(user.getUserName());userInfoDTO.setAge(user.getAge());userInfoDTO.setGender(UserSexEnum.getCodeByString(user.getGender()));return userInfoDTO;}// 批量转换public static List<UserInfoDTO> toUserInfoDTOList(List<User> users) {// 使用 Java 8 的 stream API 进行批量转换return users.stream().map(UserConverter::toUserInfoDTO) // 对每个 User 对象进行转换.collect(Collectors.toList()); // 收集成 List<UserInfoDTO>} }
2.8 拦截器-跨域资源共享CorsInterceptor
package com.zzx.user.interceptor;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class CorsInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {response.setHeader("Access-Control-Allow-Origin", "*"); // 允许所有来源response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");response.setHeader("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization");response.setHeader("Access-Control-Allow-Credentials", "true");// 处理OPTIONS请求if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {response.setStatus(HttpServletResponse.SC_OK);return false; // 返回false,表示不再执行后续的Controller方法}return true; // 继续执行其他拦截器或Controller方法}
}
2.9 配置类WebConfig
package com.zzx.user.config;import com.zzx.user.interceptor.CorsInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册 CORS 拦截器registry.addInterceptor(new CorsInterceptor()).addPathPatterns("/**") // 拦截所有路径.excludePathPatterns("/login", "/error"); // 排除登录和错误页面}
}
2.10 最重要一步:修改启动类扫描Mapper接口
package com.zzx;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.zzx.user.repository.mapper") // 扫描 Mapper 接口所在的包
public class SpringbootMybatisDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootMybatisDemoApplication.class, args);}}
2.11 编写测试类
- 测试类位于
test
文件夹下:
- 测试类代码:
package com.zzx;import com.zzx.user.repository.entity.User;
import com.zzx.user.service.UserService;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource;
import java.util.List;@SpringBootTest
@MapperScan("com.zzx.user.repository.mapper") // 扫描 Mapper 接口所在的包
class SpringbootMybatisDemoApplicationTests {@Resourceprivate UserService userService;@Testpublic void getAllUserInfo(){List<User> users = userService.queryAllUserInfo();users.forEach(System.out::println);}}
2.12 使用Postman测试接口
- 使用Postman测试接口
后端工程的搭建到此结束了,如果只想学习后端的人可以直接到此结束了
3.前端工程搭建
- 前端代码编写步骤:
- 1.初始化项目:使用 Vite 创建 Vue 项目并进入项目目录。
- 2.安装依赖:安装 Pinia、Vue Router、Axios 等必要的依赖。
- 3.配置 Vite:编辑 vite.config.js,设置开发服务器和代理。
- 4.配置 Axios:在 src/services/axios.js 中创建自定义 Axios 实例,并配置拦截器。
- 5.设置 Pinia:创建 src/pinia.js,初始化 Pinia 并在 main.js 中引入。
- 6.创建 Store:在 src/store/userStore.js 中定义用户相关的状态和操作。
- 7.配置 Router:在 src/router/router.js 中定义路由规则和全局守卫。
- 8.编写主入口文件:在 src/main.js 中创建 Vue 应用实例,挂载路由和 Pinia。
- 9.创建根组件:编写 src/App.vue,主要负责渲染路由视图。
- 10.创建展示组件:编写 src/components/ShowAllUserInfo.vue,展示用户信息并处理加载和错误状态。
3.1 前端项目搭建
- 打开vscode,打开控制台,在指定目录下执行下面命令:
npm create vite@latest
-
输入项目名称后回车,选择
vue
-
然后选择
JavaScripts
-
进入到该目录下,即可看见初始化的项目
-
执行如下命令:
npm install
-
由于前端项目还用到了
axios
(ajax异步请求封装技术实现前后端数据交互)、pinia
(通过状态管理实现组件数据传递)、router
(通过路由实现页面切换),因此还需要安装下面三个包:npm install axios vue-router pinia
-
毛毛张搭建好的前端完整的文件目录如下:
3.2 修改配置文件vite.config.js
// vite.config.js// 从 Vite 中导入 defineConfig 工具,用于类型提示和配置验证
import { defineConfig } from 'vite';// 从 Vite 插件库中导入 Vue 插件,以支持 Vue 单文件组件(.vue 文件)
import vue from '@vitejs/plugin-vue';// 导出 Vite 的配置,使用 defineConfig 包装配置对象
export default defineConfig(() => {return {// 配置 Vite 使用的插件plugins: [vue() // 启用 Vue 插件,允许 Vite 识别和处理 .vue 文件],// 配置开发服务器相关设置server: {port: 8081, // 设置前端开发服务器的端口号为 8081open: true, // 启动开发服务器后,自动在默认浏览器中打开应用// 配置开发服务器的代理,用于解决前后端分离时的跨域问题proxy: {'/api': { // 代理匹配以 /api 开头的所有请求路径target: 'http://localhost:8080/', // 代理目标地址,即后端服务器的地址changeOrigin: true, // 改变请求头中的 Origin 字段为目标地址,避免因跨域而导致的问题// 重写请求路径,将 /api 前缀替换为空字符串// 例如,/api/user/queryAllUserInfo 会被重写为 /user/queryAllUserInforewrite: (path) => path.replace(/^\/api/, '')}}}};
});
3.3 引入插件main.js
- 文件路径:
src/main.js
import { createApp } from 'vue';// 引入 Vue 的 createApp 方法,用于创建应用实例
import App from './App.vue';// 引入根组件
import router from './router/router';// 引入路由配置
import pinia from './store/pinia';// 引入 Pinia 状态管理// 创建 Vue 应用实例,并通过链式调用注册插件和功能
export const app = createApp(App).use(router) // 注册路由.use(pinia) // 注册 Pinia 状态管理
app.mount('#app'); // 挂载到 DOM 中的 #app 节点
3.4 修改主页App.vue
- 文件路径:
src/App.vue
<script setup></script><template><div><!-- 用于路由切换视图--><router-view></router-view></div></template><style scoped>
.logo {height: 6em;padding: 1.5em;will-change: filter;transition: filter 300ms;
}
.logo:hover {filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
3.5 用户信息展示逻辑showAllUserInfo.vue
- 文件路径:
src/components/showAllUserInfo.vue
<template><div class="user-info"><h2>用户信息</h2><table class="user-table"><thead><tr><th>用户名</th><th>年龄</th><th>性别</th></tr></thead><tbody><!-- 使用 v-for 循环显示多个用户,每行显示一个用户的属性 --><tr v-for="user in userStore.users" :key="user.id"><td>{{ user.username }}</td><td>{{ user.age }}</td><td>{{ user.gender === 1 ? '男' : '女' }}</td></tr></tbody></table></div>
</template><script setup>
import { ref, computed, onMounted } from 'vue'
import { useUserStore } from '../store/userStore' // 引入 Pinia store// 使用 Pinia store
const userStore = useUserStore()// 计算属性,根据 gender 字段返回对应的文字
const genderText = computed(() => {return userStore.users.length && userStore.users[0].gender === 1 ? '男' : '女'
})// 在组件挂载时获取用户信息
onMounted(() => {userStore.fetchUserInfo() // 获取用户信息
})
</script><style scoped>
.b1b {background-color: #007bff;color: white;padding: 10px 15px;border: none;border-radius: 5px;cursor: pointer;margin: 10px;
}.b1b:hover {background-color: #0056b3;
}.user-info {margin-top: 30px;text-align: center; /* 使整个 .user-info 区域的内容居中 */
}.user-info h2 {text-align: center; /* 使标题居中 */
}.user-table {width: 80%;margin: 0 auto;border-collapse: collapse;
}.user-table th, .user-table td {padding: 8px 16px;border: 1px solid #ccc;text-align: center;
}.user-table th {background-color: #f4f4f4;
}.user-table tr:nth-child(even) {background-color: #f9f9f9;
}
</style>
3.6 数据传递与请求发送
- 文件路径:
/src/store/pinia.js
// 从 Pinia 中导入 createPinia 函数,用于创建 Pinia 实例
import { createPinia } from 'pinia';// 使用 createPinia 函数创建一个 Pinia 实例
// Pinia 是 Vue 3 官方推荐的状态管理工具,用于管理应用中的全局状态
let pinia = createPinia();// 导出创建好的 Pinia 实例
// 在 main.js 中引入并注册到 Vue 应用中,使得所有组件都可以使用 Pinia 管理状态
export default pinia;
- 文件路径:
/src/store/userStore.js
// 从 Pinia 中导入 defineStore 函数,用于创建一个新的 Store
import { defineStore } from 'pinia';// 导入自定义的 Axios 实例,用于发起 HTTP 请求
import axios from '../services/axios';// 使用 defineStore 创建一个名为 'userStore' 的 Store
export const useUserStore = defineStore('userStore', {// 定义 Store 的状态state: () => ({users: [], // 用于存储多个用户的信息,初始为空数组}),// 定义 Store 的动作(方法)actions: {/*** 异步方法:获取所有用户信息* 该方法使用 Axios 实例发送 GET 请求到后端 API,* 并将返回的用户数据存储在 state 中的 users 数组里*/async fetchUserInfo() {try {// 使用自定义的 Axios 实例发送 GET 请求到 '/user/queryAllUserInfo' 端点const response = await axios.get('/user/queryAllUserInfo');// 检查响应数据中的 code 是否为 200,表示请求成功if (response.data.code === 200) {// 假设返回的数据结构为 { code: 200, message: '成功', content: [...] }// 将返回的用户数组赋值给 state 中的 usersthis.users = response.data.content;} else {// 如果 code 不是 200,表示请求成功但业务逻辑失败// 打印错误信息到控制台,方便调试console.error('获取用户信息失败', response.data.message);}} catch (error) {// 捕捉并处理请求过程中发生的任何错误// 例如网络问题、服务器错误等console.error('请求失败', error);}},},
});
3.7 路由代码
- 文件路径:
/src/router/router.js
// 导入路由创建的相关方法
import { createRouter, createWebHashHistory,createWebHistory } from 'vue-router'const routes = [{path: '/',redirect: '/user/queryAllUserInfo' // 重定向到 /user/queryAllUserInfo 路由},{path: '/user/queryAllUserInfo',name: 'ShowAllUserInfo',component: () => import('../components/ShowAllUserInfo.vue') // 动态导入}
];// 创建路由对象,声明路由规则
const router = createRouter({history: createWebHistory(),// history: createWebHashHistory(),routes
})// 设置路由的全局前置守卫
router.beforeEach((to, from, next) => {/* to 要去哪里from 从哪里来next 放行路由时需要调用的方法,不调用则不放行*/console.log(to)next() // 直接放行所有路由
})// 设置路由的全局后置守卫
router.afterEach((to, from) => {console.log(`从哪里来:${from.path}, 到哪里去:${to.path}`)
})// 对外暴露路由对象
export default router
3.8 请求拦截处理
- 文件路径:
/src/services/axios.js
import axios from 'axios';// 导入 Axios 库// 创建 Axios 实例
const instance = axios.create({// 基础 URL,所有请求都会在此基础上拼接路径// '/api' 是前端代理路径,实际会被 Vite 配置代理到后端地址baseURL: "/api",// 超时时间,单位是毫秒。如果请求超过这个时间没有响应,将抛出超时错误timeout: 10000,
});// 添加请求拦截器,在请求发送之前做一些处理
instance.interceptors.request.use(// 成功拦截的回调函数config => {// 处理请求头,例如添加 Content-Type 或自定义头console.log("before request"); // 打印日志,便于调试config.headers.Accept = 'application/json, text/plain, text/html,*/*'; // 设置通用的 Accept 请求头return config; // 返回配置好的请求对象,继续发送请求},// 请求错误的回调函数error => {console.log("request error"); // 打印错误信息return Promise.reject(error); // 返回错误,阻止请求发送}
);// 添加响应拦截器,在服务器响应后统一处理数据
instance.interceptors.response.use(// 处理成功响应的回调函数response => {console.log("after success response"); // 打印日志console.log("这是拦截器"); // 打印标志信息,便于调试console.log(response); // 打印完整的响应对象return response; // 返回响应数据,供后续逻辑使用},// 处理失败响应的回调函数error => {console.log("after fail response"); // 打印错误日志console.log(error); // 打印错误对象,便于调试return Promise.reject(error); // 返回错误,供调用者处理}
);// 导出创建的 Axios 实例,便于在项目中复用
export default instance;
4.源代码
- 源代码可用访问毛毛张的github仓库:
- 前端代码:https://github.com/zzxrepository/SpringBootTutorial/tree/master/springboot-mybatis/springboot-mybatis-demo-vue
- 后端代码:https://github.com/zzxrepository/SpringBootTutorial/tree/master/springboot-mybatis/springboot-mybatis-demo

🌈欢迎和毛毛张一起探讨和交流!
联系方式点击下方个人名片
相关文章:
【SpringBoot教程】SpringBoot整合Mybatis - 前后端分离项目 - vue3
🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 今天毛毛张将通过一个完整的前后端分离的任务来介绍SpringBoot整合Mybatis过程! 文章目录 1.前言1.1 任务描述1.2 SpringBoot整合Mybatis概述1.3 完整项目…...
node.js之---事件驱动编程
详解事件驱动 事件驱动是基于什么实现的 事件驱动和I/O操作的关系 I/O操作和事件循环的关系 详解事件驱动 事件驱动编程(Event-driven Programming)是一种编程范式,其中程序的控制流是由“事件”驱动的。事件通常指的是用户操作、网络请…...
RK3588+FPGA全国产异步LED显示屏控制卡/屏幕拼接解决方案
RK3588FPGA核心板采用Rockchip RK3588新一代旗舰 级八核64位处理器,支持8K视频编解码,多屏4K输出,可实现12屏联屏拼接、同显、异显,适配多种操作系统,广泛适用于展览展示、广告内容投放、新零售、商超等领域实现各种媒…...
Postman测试big-event
报错500。看弹幕,知道可能是yml或sql有问题。 所以检查idea工作台, 直接找UserMapper检查,发现完全OK。 顺着这个error发现可能是sql有问题。因为提示是sql问题,而且是有now()的那个sql。 之后通过给的课件,复制课件…...
38. 考古学家
题目描述 有一个考古学家发现一个石碑,但是很可惜,发现时其已经断成多段,原地发现n个断口整齐的石碑碎片。为了破解石碑内容,考古学家希望有程序能帮忙计算复原后的石碑文字组合数,你能帮忙吗? 输入描述 第…...
商用车自动驾驶,迎来大规模量产「临界点」?
商用车自动驾驶,正迎来新的行业拐点。 今年初,交通部公开发布AEB系统运营车辆标配征求意见稿,首次将法规限制条件全面放开,有望推动商用车AEB全面标配,为开放场景的商用车智能驾驶市场加了一把火。 另外,…...
中建海龙:科技助力福城南产业片区绿色建筑发展
在快速发展的城市化进程中,绿色建筑以其环保、节能、可持续的特点日益受到重视。作为建筑工业化领域的领军企业,中建海龙科技有限公司(简称“中建海龙”)凭借其卓越的科技实力和创新举措,在推动绿色建筑发展方面做出了…...
selenium-side-runner + edge快速使用
安装和配置 Node.js 与 Selenium-Side-Runner 1. 安装 Node.js 为了使用 selenium-side-runner,首先需要在你的系统上安装 Node.js。Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时,它允许开发者编写服务器端代码。 通过 Winget 安装 Node.js(适用于 Windows 10/…...
ARM发布Armv9.5架构:迈向更强性能与灵活性的新时代
2024年11月30日,ARM正式发布了其最新的Armv9.5架构,这是Arm技术发展的又一重要里程碑。从表中信息来看,Armv9.5架构的发布标志着该公司的架构系列在性能、灵活性和可扩展性方面取得了进一步突破。本次发布不仅是技术上的提升,更是…...
Pytorch的自动求导模块
文章目录 torch.autograd.backward()基本用法非标量张量的反向传播保留计算图指定输入张量高阶梯度计算 与 y.backward() 的区别torch.autograd.grad()基本用法非标量张量的梯度高阶梯度计算多输入、多输出的梯度计算未使用的输入张量保留计算图 与 backward() 的区别 torch.au…...
【React】- 跨域PDF预览、下载(改文件名)、打印
我们经常会碰到跨域来方位PDF,同时需要下载、打印的需求,通常由于浏览器的安全策略,可以预览,但是下载和打印可能会受限,这时候怎么办呢? 1.创建一个隐藏的标签 要下载 iframe 中的 PDF 文件,…...
HuggingFace 模型文件详解:如何加载本地模型?
HuggingFace 模型文件详解 在使用 HuggingFace 下载大型语言模型(如 LLaMA-3-1-8B)后,会发现模型目录下包含多个文件和文件夹。本文将详细介绍这些文件的作用以及它们在模型加载和推理过程中的功能。 文件结构总览 models--meta-llama--Lla…...
Boost之buffer
目录 一、定义和介绍 二、示例 1、点 单点 多点 2、线 3、面 单面 多面 三、总结 四、测试代码 一、定义和介绍 buffer函数是boost库(algorithms)算法模块中的构建缓冲区函数。 其函数原型为(此处为带策略型): template<typename GeometryIn, typename MultiPolygon, typen…...
[redux] ts声明useSelector和useDispatch
先安装 安装 | Redux 中文官网 npm install react-redux npm install reduxjs/toolkit 定义一个切片 import { createSlice } from reduxjs/toolkit;const userSlice createSlice({name: user,initialState: {name: lsm,age: 24,},reducers: {}, }); //注意这里写导出redu…...
计算机网络 (19)扩展的以太网
前言 以太网(Ethernet)是一种局域网(LAN)技术,它规定了包括物理层的连线、电子信号和介质访问层协议的内容。以太网技术不断演进,从最初的10Mbps到如今的10Gbps、25Gbps、40Gbps、100Gbps等,已成…...
Ubuntu 23.10 换源
查看当前Ubuntu系统的版本 使用命令: lsb_release -a 中科大源: deb https://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ mantic main restricted universe multiverse deb-src https://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ man…...
如何在 Ubuntu 22.04 上优化 Apache 以应对高流量网站教程
简介 在本教程中,我们将学习如何优化 Apache 以应对高流量网站。 当运行高流量网站时,确保你的 Apache Web 服务器得到优化对于有效处理负载至关重要。在本指南中,我们将介绍配置 Apache 以提高性能和可扩展性的基本技巧。 为高流量网站优…...
Android 性能优化:内存优化(实践篇)
1. 前言 前一篇文章Android性能优化:内存优化 (思路篇) 大概梳理了Android 内存原理和优化的必要性及应该如何优化,输出了一套短期和长期内存优化治理的SOP方案。 那么这一篇文章就总结下我最近在做内存优化如何实践的࿰…...
开源数据集成平台白皮书重磅发布《Apache SeaTunnel 2024用户案例合集》!
2025年新年临近,Apache SeaTunnel 社区用户案例精选📘也跟大家见面啦!在过去的时间里,SeaTunnel 社区持续成长,吸引了众多开发者的关注与支持。 为了致谢一路同行的伙伴,也为了激励更多人加入技术共创&…...
用python编写一个放烟花的小程序
import pygame import random # 代码解释及使用说明: # 首先,导入 pygame 和 random 库。pygame 用于创建游戏窗口和图形绘制,random 用于生成随机数。 # 初始化 pygame,并设置屏幕尺寸为 800x600 像素,设置窗口标题为…...
以一个实际例子来学习Linux驱动程序开发之“设备类”的相关知识【利用设备类实现对同一设备类下的多个LED灯实现点亮或关闭】
前言 对于一个设备的驱动程序来说,其实上层用户主要看到的、用到的就是设备文件和设备类,当然用得最多的是设备文件,虽然设备类用得不多,但也是每一个设备注册实例化时必须要用到的东西,本篇博文就以一个简单的例子说…...
培训机构Day22
今天主要还是围绕着jquery讲解的,没有什么可说的。 知识点: 常用事件类型: 1.click:单击事件。鼠标,或键盘都可以触发。 2.dblclick:双击事件。 3.contextmenu:右键事件。 4.键盘相关事件&…...
Synopsys软件基本使用方法
Synopsys软件基本使用方法 1 文件说明2 编译流程3 查看波形4 联合仿真 本文主要介绍Synopsys软件vcs、verdi的基本使用方法,相关文件可从 GitHub下载。 1 文件说明 创建verilog源文件add.v、mult.v、top.vmodule add (input signed [31:0] dina,input signed [3…...
信息科技伦理与道德1:研究方法
1 问题描述 1.1 讨论? 请挑一项信息技术,谈一谈为什么认为他是道德的/不道德的,或者根据使用场景才能判断是否道德。判断的依据是什么(自身的道德准则)?为什么你觉得你的道德准则是合理的,其他…...
手机租赁平台开发实用指南与市场趋势分析
内容概要 在当今快速变化的科技时代,手机租赁平台的发展如火如荼。随着越来越多的人希望使用最新款的智能手机,但又不愿意承担昂贵的购机成本,手机租赁平台应运而生。这种模式不仅为用户提供了灵活的选择,还为企业创造了新的商机…...
ABAQUS三维Voronoi晶体几何建模
材料晶体塑性理论与细观尺度上晶体几何模型相融合的模拟方法为探究材料在塑性变形过程中的行为机制以及晶体材料优化开辟了新途径。本案例演示在CAD软件内通过Voronoi建立晶体三维模型,并将模型导入到Abaqus CAE内,完成晶体材料的有限元建模。 在AutoC…...
职场常用Excel基础04-二维表转换
大家好,今天和大家一起分享一下excel的二维表转换相关内容~ 在Excel中,二维表(也称为矩阵或表格)是一种组织数据的方式,其中数据按照行和列的格式进行排列。然而,在实际的数据分析过程中,我们常…...
如何使用 ChatGPT Prompts 写学术论文?
第 1 部分:学术写作之旅:使用 ChatGPT Prompts 进行学术写作的结构化指南 踏上学术写作过程的结构化旅程,每个 ChatGPT 提示都旨在解决特定方面,确保对您的主题进行全面探索。 制定研究问题: “制定一个关于量子计算的社会影响的研究问题,确保清晰并与您的研究目标保持一…...
【深度学习】Java DL4J基于 LSTM 构建新能源预测模型
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探…...
Jetson系列部署YOLOv8模型教程
简介 NVIDIA Jetson系列是专为边缘计算设计的紧凑型计算模块,其目标用户为AI开发者、嵌入式系统工程师以及需要在设备端实时进行数据处理与AI推断的创新者。通过提供灵活的硬件平台,结合NVIDIA强大的GPU计算资源,Jetson系列能够支持复杂的机…...
【HAProxy】如何在Ubuntu下配置HAProxy服务器
HAProxy 是一款免费、开源且强大的反向代理程序,它为 HTTP 和 TCP 基础的应用提供了高可用性、负载均衡以及代理功能,因此对于管理高流量服务器(或 Web 应用)来说,通过将负载分散到多个节点服务器上,它是一…...
gesp(C++一级)(7)洛谷:B3863:[GESP202309 一级] 小明的幸运数
gesp(C一级)(7)洛谷:B3863:[GESP202309 一级] 小明的幸运数 题目描述 所有个位数为 k k k 的正整数,以及所有 k k k 的倍数,都被小明称为“ k k k 幸运数”。小明想知道正整数 L L L 和 R R R 之间&a…...
【数据库系统概论】数据库完整性与触发器--复习
在数据库系统概论中,数据库完整性是指确保数据库中数据的准确性、一致性和有效性的一组规则和约束。数据库完整性主要包括实体完整性、参照完整性和用户定义完整性。以下是详细的复习内容: 1. 数据库完整性概述 数据库完整性是指一组规则,这…...
【YOLOv8模型网络结构图理解】
YOLOv8模型网络结构图理解 1 YOLOv8的yaml配置文件2 YOLOv8网络结构2.1 Conv2.2 C3与C2f2.3 SPPF2.4 Upsample2.5 Detect层 1 YOLOv8的yaml配置文件 YOLOv8的配置文件定义了模型的关键参数和结构,包括类别数、模型尺寸、骨干(backbone)和头部…...
使用 commitlint 和 husky 检查提交描述是否符合规范要求
在上一小节中,我们了解了 Git hooks 的概念,那么接下来我们就使用 Git hooks 来去校验我们的提交信息。 要完成这么个目标,那么我们需要使用两个工具: 注意:npm 需要在 7.x 以上版本。 1. commitlint 用于检查提交信…...
QT集成IntelRealSense双目摄像头3,3D显示
前两篇文章,介绍了如何继承intel realsense相机和opengl。 这里介绍如何给深度数据和色彩数据一块显示到opengl里面。 首先,需要了解深度数据和彩色数据是如何存储的。先说彩色数据。彩色图像一般都是RGB,也就是每个像素有三个字节…...
Vue 中el-table-column 进行循环,页面没渲染成功
文章目录 前言效果图代码示例可能出现的问题及原因解决思路 前言 实现效果:el-table-column 进行循环,使之代码简化 遇到的问题: data进行默认赋值,操作列的删除都可以出来,其他表格里面的数据没出来 效果图 示例&am…...
渗透测试-非寻常漏洞案例
声明 本文章所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法. 此文章不允许未经授权转发至除先知社区以外的其它平台!࿰…...
Spring Boot 实战篇(四):实现用户登录与注册功能
目录 Spring Boot 实战篇(四):实现用户登录与注册功能 一、用户注册功能 (一)前端页面设计(简要提及) (二)后端实现 二、用户登录功能 (一)…...
VScode SSH 错误:Got bad result from install script 解決
之前vscode好好的,某天突然连接报错如下 尝试1. 服务器没有断开,ssh可以正常连接 2. 用管理员权限运行vscode,无效 3. 删除服务器上的~/.vscode-server 文件夹,无效 试过很多后,原来很可能是前一天anaconda卸载导致注册表项 步…...
openGauss与GaussDB系统架构对比
openGauss与GaussDB系统架构对比 系统架构对比openGauss架构GaussDB架构 GaussDB集群管理组件 系统架构对比 openGauss架构 openGauss是集中式数据库系统,业务数据存储在单个物理节点上,数据访问任务被推送到服务节点执行,通过服务器的高并…...
【ArcGISPro/GeoScenePro】检查并处理高程数据
数据 https://arcgis.com/sharing/rest/content/items/535efce0e3a04c8790ed7cc7ea96d02d/data 数字高程模型 (DEM) 是一种栅格,可显示地面或地形的高程。 数字表面模型 (DSM) 是另一种高程栅格,可显示表面的高度,例如建筑物或树冠的顶部。 您需要准备 DEM 和 DSM 以供分析…...
WebRTC的三大线程
WebRTC中的三个主要线程: signaling_thread,信号线程:用于与应用层交互worker_thread,工作线程(最核心):负责内部逻辑处理network_thread,网络线程:负责网络数据包的收发…...
HTML-文本标签
历史上,网页的主要功能是文本展示。所以,HTML 提供了大量的文本处理标签。 1.<div> <div>是一个通用标签,表示一个区块(division)。它没有语义,如果网页需要一个块级元素容器,又没…...
C# 在PDF中添加和删除水印注释 (Watermark Annotation)
目录 使用工具 C# 在PDF文档中添加水印注释 C# 在PDF文档中删除水印注释 PDF中的水印注释是一种独特的注释类型,它通常以透明的文本或图片形式叠加在页面内容之上,为文档添加标识或信息提示。与传统的静态水印不同,水印注释并不会永久嵌入…...
Unity2022接入Google广告与支付SDK、导出工程到Android Studio使用JDK17进行打包完整流程与过程中的相关错误及处理经验总结
注:因为本人也是第一次接入广告与支付SDK相关的操作,网上也查了很多教程,很多也都是只言片语或者缺少一些关键步骤的说明,导致本人也是花了很多时间与精力踩了很多的坑才搞定,发出来也是希望能帮助到其他人在遇到相似问…...
docker部署项目
docker部署项目 (加载tar包:docker image load -i mysql.tar) 一、jdk环境配置 1.jdk下载地址 --Java Archive | Oracle 中国 --选择好版本进入 --下载Linux x64 Compressed Archive的链接 2.解压 --创建文件夹:mkdir /ro…...
C# 设计模式(创建型模式):工厂模式
C# 设计模式(创建型模式):工厂模式 引言 在软件设计中,创建型模式是用来创建对象的设计模式,它们帮助我们将对象的创建过程从业务逻辑中分离出来,减少代码的重复性和耦合度。工厂模式作为创建型设计模式之…...
REMARK-LLM:用于生成大型语言模型的稳健且高效的水印框架
REMARK-LLM:用于生成大型语言模型的稳健且高效的水印框架 前言 提出这一模型的初衷为了应对大量计算资源和数据集出现伴随的知识产权问题。使用LLM合成类似人类的内容容易受到恶意利用,包括垃圾邮件和抄袭。 ChatGPT等大语言模型LLM的开发取得的进展标志着人机对话交互的范式…...
Lumos学习王佩丰Excel第二十三讲:Excel图表与PPT
一、双坐标柱形图的补充知识 1、主次坐标设置 2、主次坐标柱形避让(通过增加两个系列,挤压使得两个柱形挨在一起) 增加两个系列 将一个系列设置成主坐标轴,另一个设成次坐标轴 调整系列位置 二、饼图美化 1、饼图美化常见设置 …...