Xuan's blog - springboot
type: channel
link: https://blog.ybyq.wang/tag/springboot/
items: 基于Spring Boot + Vue.js的GPT AI聊天应用：从开发到部署的完整实践
items: 软件工程实践五：Spring Boot 接口拦截与 API 监控、流量控制
items: 软件工程实践四：MyBatis-Plus 教程（连接、分页、查询）
items: 软件工程实践三：RESTful API 设计原则
items: 软件工程实践二：Spring Boot 知识回顾
items: Springboot实现后台图片上传
items: Springboot 手机号短信验证码注册登录实现
items: Springboot 邮箱验证码注册登录实现
items: Springboot中 MyBatis-Flex TableDef 的使用
items: 智慧零工平台后端开发实战：SpringBoot + MyBatis-Flex 现代化架构

基于Spring Boot + Vue.js的GPT AI聊天应用：从开发到部署的完整实践
type: item
date: 2025-09-23T21:57:00+08:00
description: 前言一个人一个下午做成的，为了应对周四的作业答辩。🚀 项目概述本文将详细介绍一个基于Spring Boot后端和Vue.js前端的GPT AI聊天应用的完整开发流程。该项目集成了OpenAI、阿里云通义千问、DeepSeek、豆包、Kimi等多个主流AI平台，支持文本对话和图像生成功能，并实现了用户认证、会话管理、管理员面板、用户统计等完整的业务功能。体验地址：https://gpt.xuan.cyou/技术栈后端: Spring Boot 3.5.5, Java 17, SQLite, JPA/Hibernate前端: Vue.js 3, Vite, Pinia, JavaScript ES6+AI集成: OpenAI GPT-4, 阿里云通义千问, DeepSeek, 豆包, Kimi部署: 宝塔面板, Nginx, SSL证书📁 项目架构GPT-AI-Project/ ├── gpt-ai-java/ # Spring Boot 后端 │ ├── src/main/java/ │ │ ├── controller/ # REST API控制器 (用户, AI, 管理员等) │ │ ├── service/ # 业务逻辑层 (多AI平台服务, 用户统计等) │ │ ├── entity/ # 数据实体 (用户, 对话历史, 统计数据等) │ │ ├── config/ # 配置类 │ │ └── adopter/ # AI平台适配器 (OpenAI, Ali, DeepSeek, Kimi等) │ ├── src/main/resources/ │ │ └── application.yaml # 应用配置 │ └── pom.xml # Maven依赖配置 └── frontend/ # Vue.js 前端 ├── src/ │ ├── components/ # Vue组件 │ ├── views/ # 页面视图 (聊天, 图像, 管理面板, 用户后台等) │ ├── api/ # API调用封装 │ └── store/ # 状态管理 (Pinia) ├── public/ # 静态资源 └── package.json # NPM依赖配置🔧 核心功能实现1. 后端核心架构1.1 多AI平台集成项目支持OpenAI和阿里云通义千问两个AI平台，通过适配器模式实现：// AI控制器统一入口 @RestController @RequestMapping("/api/ai") public class AiController { @GetMapping("/chat/text/stream") public SseEmitter streamChat( @RequestParam String platform, @RequestParam String model, @RequestParam String message ) { // 根据平台选择对应的AI服务 (示例) if ("openai".equals(platform)) { return openAiController.sendTextStream(model, message); } else if ("ali".equals(platform)) { return aliAiController.sendTextStream(model, message); } // ... 此处添加对 deepseek, doubao, kimi 等平台的路由逻辑 return null; // or throw an exception } }1.2 流式响应实现使用Server-Sent Events (SSE) 实现实时流式对话：@PostMapping("/chat/text/stream") public SseEmitter sendTextStream(String model, String message) { SseEmitter emitter = new SseEmitter(0L); CompletableFuture.runAsync(() -> { try { // 流式读取AI响应并实时推送 openAIService.sendText(model, message, true, delta -> { emitter.send(SseEmitter.event().name("delta").data(delta)); }); emitter.send(SseEmitter.event().name("done").data("[DONE]")); emitter.complete(); } catch (Exception e…

软件工程实践五：Spring Boot 接口拦截与 API 监控、流量控制
type: item
date: 2025-09-18T14:55:00+08:00
description: 适合人群：具备 Spring Web 基础、希望在接口层做统一治理的开发者或技术爱好者。建议先看：软件工程实践二（Spring Boot 知识回顾）、实践三（RESTful API 设计原则）。1. 方案选型速览Filter（Servlet 层）：最靠前，处理包括静态资源；适合全局跨域、XSS、统一编码等。HandlerInterceptor（Spring MVC 层）：在进入 Controller 前后执行；适合接口打点、鉴权、限流、审计。AOP（方法层）：对注解/切点进行横切；适合注解式限流、审计、幂等等。API Gateway（边界层）：最靠外；适合全局流控、黑白名单、熔断、灰度，一处管多服务。一般应用内优先用 Interceptor + AOP；如果有网关，也可在网关做粗粒度限流，在应用内做精细化限流与监控。国内比较熟悉的：Sentinel2. 基于 HandlerInterceptor 的接口监控目标：记录每次请求的关键信息与耗时，并输出到日志或指标系统。示例：// RequestLoggingInterceptor.java // 功能：为每个进入的 HTTP 请求生成请求ID、记录入站/出站日志与耗时 package com.example.demo.web; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import java.util.UUID; public class RequestLoggingInterceptor implements HandlerInterceptor { private static final Logger log = LoggerFactory.getLogger(RequestLoggingInterceptor.class); private static final String REQ_ID = "reqId"; // MDC 中的请求 ID 键 private static final String START = "startAt"; // 请求开始时间属性键 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String requestId = UUID.randomUUID().toString(); // 生成请求唯一 ID，便于链路追踪 MDC.put(REQ_ID, requestId); // 放入日志 MDC request.setAttribute(START, System.currentTimeMillis()); // 记录起始时间 String method = request.getMethod(); String uri = request.getRequestURI(); String ip = getClientIp(request); // 识别真实客户端 IP（支持代理场景） log.info("[IN] {} {} ip={} ua={}", method, uri, ip, request.getHeader("User-Agent")); return true; // 返回 true 放行请求 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { // 可在此处添加对响应体或模型的额外处理 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { Long start = (Long) request.getAtt…

软件工程实践四：MyBatis-Plus 教程（连接、分页、查询）
type: item
date: 2025-09-11T12:41:00+08:00
description: 概述目标：用最少代码完成单表 CRUD、分页查询，并给出 JOIN 查询的常见做法。环境：Spring Boot 3.x + MyBatis-Plus 3.5+ + MySQL 8.x。1. 依赖与连接配置1.1 Maven 依赖（片段）<dependencies> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.12</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>1.2 application.yml 连接spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC username: root password: root mybatis-plus: configuration: map-underscore-to-camel-case: true mapper-locations: classpath*:mapper/**/*.xml1.3 启动类与包扫描@SpringBootApplication @MapperScan("com.example.demo.mapper") // 若在接口上使用 @Mapper，可不加 @MapperScan public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }1.4 分页插件配置@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }2. 示例模型与 Mapper2.1 表结构（示例）CREATE TABLE `t_user` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(64) NOT NULL, `age` INT NOT NULL, `email` VARCHAR(128), `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP );2.2 实体 Entity@Data @TableName("t_user") public class User { @TableId(type = IdType.AUTO) private Long id; private String name; private Integer age; private String email; @TableField("created_at") private LocalDateTime createdAt; }2.3 Mapper 接口public interface UserMapper extends BaseMapper<User> {}3. 常见查询（QueryWrapper / Lambda）3.1 基础查询@Autowired private UserMapper userMapper; // 主键 User u1 = userMapper.s…

软件工程实践三：RESTful API 设计原则
type: item
date: 2025-09-11T10:30:00+08:00
description: 目标与范围明确一致的接口风格，降低客户端心智负担，提升跨团队协作效率。规范涵盖：资源建模、URI 设计、HTTP 方法与状态码、请求/响应、错误、分页过滤排序、版本化、安全、缓存、可观测性与文档。1. 核心理念资源导向：一切皆资源（名词复数命名），动作用 HTTP 方法表达。统一接口：方法、状态码、媒体类型、错误结构一致。无状态：每个请求自包含认证与上下文，不依赖服务器会话。可缓存：合理使用条件请求与缓存头，降低延迟与负载。可演进：通过版本化与向后兼容策略平滑升级。2. 资源建模与 URI 规范资源命名：使用复数、短小、层级表达从属关系。/api/v1/users/api/v1/users/{userId}/api/v1/users/{userId}/orders关联过滤：也可使用查询参数表达关联（优先简单方案）。/api/v1/orders?userId=123避免在路径中使用动词；确需动作，用子资源表达。POST /api/v1/invoices/{id}/pay标识符：建议使用不可泄漏信息的 ID（UUID/雪花），避免自增 ID 暴露业务规模。路径示例与反例：推荐：GET /api/v1/users/{id}，PATCH /api/v1/users/{id}，DELETE /api/v1/users/{id}不推荐：POST /api/update/users/{id}、POST /api/create/users/{id}（应分别使用 PUT/PATCH 与 POST /api/v1/users）3. HTTP 方法语义与幂等性GET（安全、幂等）：获取资源或集合。POST（非幂等）：创建资源、触发计算/异步任务。PUT（幂等）：整体替换资源（客户端提供完整表述）。PATCH（建议近幂等）：局部更新，使用 JSON Merge Patch 或 JSON Patch。DELETE（幂等）：删除资源（软删/硬删在语义上对客户端保持透明）。4. 标准状态码2xx：200 OK：成功，返回资源或结果；201 Created：创建成功，Location 指向新资源；202 Accepted：已受理异步任务；204 No Content：成功但无响应体（删除、幂等更新）。4xx：400 Bad Request：参数错误/校验失败；401 Unauthorized：未认证或凭证无效；403 Forbidden：已认证但无权限；404 Not Found：资源不存在；409 Conflict：资源状态冲突（如唯一键冲突）；412 Precondition Failed：条件请求失败（ETag 并发控制）；415 Unsupported Media Type：媒体类型不支持；422 Unprocessable Entity：语义错误（校验未通过）；429 Too Many Requests：限流触发。5xx：服务器错误，尽量避免；记录告警并快速恢复。5. 请求与响应规范媒体类型：请求/响应 Content-Type/Accept 统一使用 application/json; charset=utf-8。字段命名与格式：推荐 camelCase；时间使用 ISO 8601（UTC），如 2025-08-20T10:30:00Z。大整数（如 ID）防止前端精度丢失可按 string 传输。统一返回结构（可选但推荐，便于一致性与观测）：{ "code": "OK", // 可选 "message": "success", // 可选 "data": { /* 资源对象或结果 */ }, "requestId": "f7a2b..."， }错误返回结构：{ "code": "VALIDATION_ERROR", // 可以是数字，字符串 "message": "email is invalid",// 提示 "requestId": "9e6d7...", // 可选 "details": [ // 可选 { "field": "email", "issue": "must be a valid email" } ] }6. 示例：Todo 列表接口（内存 List）用途：演示使用内存 List 存储并返回 todo 集合（示例代码，非生产）。路径：GET /api/v1/todos返回：200 OK，application/json; charset=utf-86.1 控制器示例（Java / Spring）package com.example.demo.todo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.w…

软件工程实践二：Spring Boot 知识回顾
type: item
date: 2025-09-10T09:49:21+08:00
description: 使用 IntelliJ IDEA 创建 Spring Boot Web 项目（仅 Web 依赖）目标：用 IntelliJ IDEA 快速创建只包含 Spring Web 的最小可运行项目，启动后通过浏览器访问 http://localhost:8080/api/hello 返回 JSON。一、创建项目（Spring Boot 向导）步骤说明：打开 IDEA → New Project → 选择 Spring Boot；服务地址保持默认。Project Metadata：Group：如 com.exampleArtifact/Name：如 demoPackaging：jar（默认）Java：17（或本机已安装的 LTS 版本）Build system：Maven（不要选 Gradle）Dependencies：搜索并仅勾选 Spring Web。Finish → 等待 Maven 下载依赖与索引完成。提示：若看不到 Spring Boot(Initializr)，确保安装了 IntelliJ 的 Spring 插件，或使用 File > New > Project... 再选择。二、项目最小代码示例1) 主启动类（IDE 已生成，检查包名与类名）package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }2) Hello 控制器（新增）package com.example.demo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Date; import java.util.Map; @RestController @RequestMapping("/api") public class HelloController { @GetMapping("/hello") public Map<String, Object> hello() { return Map.of( "msg", "hello", "time", new Date() ); } }3) 应用配置（可选）# src/main/resources/application.yml server: # 如需修改端口，取消注释并调整值 # port: 8080三、运行与验证在 DemoApplication 类左侧点击绿色运行箭头，或使用菜单 Run。控制台看到 Started DemoApplication ... 表示启动成功。浏览器/工具访问：http://localhost:8080/api/hello期望响应示例：{"msg":"hello","time":"2025-01-01T00:00:00Z"}常见问题：端口占用：在 application.yml 配置 server.port: 8081。依赖未下载：检查网络代理或尝试 Reload All Maven Projects。JDK 不匹配：Project Structure > Project/Modules 指定与向导一致的 Java 版本。四、标准目录结构与说明 demo/ ← 工程根目录 ├─ pom.xml ← 构建脚本（Maven） ├─ src │ ├─ main │ │ ├─ java │ │ │ └─ com │ │ │ └─ example │ │ │ └─ demo │ │ │ ├─ DemoApplication.java ← 启动类 │ │ │ └─ controller │ │ │ └─ HelloController.java ← Web 控制器 │ │ └─ resources │ │ ├─ application.yml ← 应用配置 │ │ └─ static/ temp…

Springboot实现后台图片上传
type: item
date: 2025-07-02T20:05:00+08:00
description: 本文将深入探讨一个标准的Web应用后台管理系统中，图片上传功能的完整实现流程。我们将从前端用户交互开始，一直到后端的文件处理、存储和最终的URL返回。整体流程概览图片上传功能的核心流程可以分为以下几个步骤：前端交互：管理员在前端页面选择图片文件。文件上传：前端将图片文件通过HTTP POST请求发送到后端指定的API端点。后端接收：后端控制器（Controller）接收到上传的文件。文件处理：后端服务对文件进行处理，如生成唯一文件名、校验文件类型和大小等。文件存储：将处理后的文件保存到服务器的指定目录中。返回结果：后端向前端返回一个包含图片可访问URL的成功响应。前端展示：前端接收到URL后，将其用于图片预览或表单提交。下面是这个流程的可视化图表：后端实现细节后端采用Spring Boot框架，下面是关键代码的解析。1. 文件上传控制器 (UploadController.java)这个控制器是处理文件上传请求的入口。@RestController @RequestMapping("/api/admin/upload") @CrossOrigin(origins = "*") public class UploadController { private static final Logger logger = LoggerFactory.getLogger(UploadController.class); /** * 上传图片 */ @PostMapping("/image") public Result<?> uploadImage(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return Result.error("上传失败，请选择文件"); } try { // 定义存储目录 String resourcePath = "src/main/resources/static/images"; File directory = new File(resourcePath); if (!directory.exists()) { directory.mkdirs(); } // 生成唯一文件名，防止重名覆盖 String originalFilename = file.getOriginalFilename(); String extension = originalFilename.substring(originalFilename.lastIndexOf(".")); String filename = UUID.randomUUID().toString() + extension; // 保存文件 Path filePath = Paths.get(directory.getAbsolutePath(), filename); Files.write(filePath, file.getBytes()); // 构建返回给前端的数据 Map<String, String> data = new HashMap<>(); data.put("url", "/images/" + filename); // 返回相对路径 return Result.success(data); } catch (IOException e) { logger.error("上传图片失败", e); return Result.error("上传图片失败: " + e.getMessage()); } } }关键点：@PostMapping("/image")：定义了处理POST请求的API端点。@RequestParam("file") MultipartFile file：通过Spring MVC接收上传的文件。唯一文件名：使用 UUID.randomUUID() 来生成一个全球唯一的文件名，避免了用户上传同名文件时互相覆盖的问题。文件存储：文件被保存在 src/main/resources/static/images/ 目录下。这是一个标准的Maven项目静态资源目录。返回URL：向前端返回的是一个相对URL，如 /images/xxxx.png，而不是完整的文件系统路径。2. 静态资源服务控制器 (StaticResourceController.java)文件上传到服务器后，我们还需要一个机制让浏览器能够通过URL访问到这些图片。StaticResourceController 就是为此而生。@Controller @RequestMapping("/images") public class StaticResourceControlle…

Springboot 手机号短信验证码注册登录实现
type: item
date: 2025-06-24T22:52:00+08:00
description: 本文将介绍如何在Spring Boot应用中实现短信验证码注册和登录功能，为用户提供便捷的移动端认证体验。1. 功能概述我们将实现以下功能：手机号+验证码注册手机号+验证码登录2. 技术栈Spring Boot 3.2.0互亿无线短信平台MyBatis FlexJWT3. 实现步骤3.1 短信服务集成首先，需要在application.properties中配置短信平台信息：# 短信配置 sms.account=C09251523 sms.apikey=826efdf7322e3c49355428a523c10eec3.2 创建短信工具类创建SmsUtil工具类处理短信发送：@Component public class SmsUtil { private static final Logger logger = LoggerFactory.getLogger(SmsUtil.class); // 短信发送API地址 private static final String SMS_API_URL = "http://106.ihuyi.com/webservice/sms.php?method=Submit"; // API账号和密码 @Value("${sms.account:C09***523}") private String account; @Value("${sms.apikey:826efdf7322e3c49355***a523c10eec}") private String apiKey; /** * 发送短信验证码 * @param phone 手机号 * @param code 验证码 * @return 发送结果，包含code和msg */ public Map<String, String> sendVerificationCode(String phone, String code) { Map<String, String> result = new HashMap<>(); try { // 短信内容 String content = "您的验证码是：" + code + "。请不要把验证码泄露给其他人。"; // 发送请求 String response = sendSmsRequest(phone, content); // 解析结果 result = parseXmlResponse(response); // 记录日志 if ("2".equals(result.get("code"))) { logger.info("短信发送成功，手机号: {}, 验证码: {}", phone, code); } else { logger.error("短信发送失败，手机号: {}, 错误信息: {}", phone, result.get("msg")); } } catch (Exception e) { logger.error("发送短信验证码异常", e); result.put("code", "0"); result.put("msg", "系统异常，短信发送失败"); } return result; } // 省略发送请求和解析响应的方法... }3.3 验证码生成和存储在UserServiceImpl中实现验证码管理：// 在UserServiceImpl中 private final Map<String, String> smsCodeCache = new HashMap<>(); @Override public boolean sendSmsCode(String phone, String type) { try { // 校验手机号格式 if (!isValidPhoneNumber(phone)) { return false; } // 生成6位随机验证码 String code = generateRandomCode(6); // 将验证码存入缓存，实际项目中应使用Redis等缓存服务 smsCodeCache.put(phone + ":" + type, code); // 发送短信 Map<String, String> result = smsUtil.sendVerificationCode(phone, code); // 检查发送结果 return "2".equals(result.get("code")); } catch (Exception e) { logger.error("发送短信验证码失败", e); return false; } } @Override public String getSmsCode(String pho…

Springboot 邮箱验证码注册登录实现
type: item
date: 2025-06-24T22:48:00+08:00
description: 课设需要做一个宠物商店APP，在登录时我加了一个邮箱注册登录。本文将详细介绍如何在Spring Boot应用中实现邮箱验证码注册和登录功能。1. 功能概述我们将实现以下功能：邮箱+验证码注册邮箱+验证码登录邮箱+密码登录（传统登录方式）这些功能涵盖了用户注册和登录的主要场景，为用户提供了灵活的选择。效果预览2. 技术栈Spring Boot 3.2.0Spring SecuritySpring MailThymeleaf (邮件模板)MyBatis FlexJWT (认证)3. 实现步骤3.1 邮件服务配置首先，我们需要配置邮件服务。在application.properties文件中添加：# 邮件服务配置 spring.mail.host=smtp.qq.com spring.mail.port=587 spring.mail.username=your-email@qq.com spring.mail.password=your-authorization-code spring.mail.default-encoding=UTF-8 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true[scode type="blue"]对于QQ邮箱，密码不是邮箱密码，而是授权码，需要在QQ邮箱设置中获取。[/scode]3.2 创建邮件服务创建EmailService接口和实现类：public interface EmailService { boolean sendVerificationEmail(String to, String subject, String code, String type); }@Service public class EmailServiceImpl implements EmailService { private static final Logger logger = LoggerFactory.getLogger(EmailServiceImpl.class); private final JavaMailSender mailSender; private final TemplateEngine templateEngine; @Value("${spring.mail.username}") private String from; public EmailServiceImpl(JavaMailSender mailSender, TemplateEngine templateEngine) { this.mailSender = mailSender; this.templateEngine = templateEngine; } @Override public boolean sendVerificationEmail(String to, String subject, String code, String type) { try { // 准备Thymeleaf模板上下文 Context context = new Context(); context.setVariable("code", code); context.setVariable("type", type); context.setVariable("time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); // 处理模板生成HTML内容 String htmlContent = templateEngine.process("email/verification-code", context); // 创建MIME消息 MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(htmlContent, true); // 发送邮件 mailSender.send(message); logger.info("邮件发送成功：{}", to); return true; } catch (Excep…

Springboot中 MyBatis-Flex TableDef 的使用
type: item
date: 2025-06-11T14:08:37+08:00
description: 什么是 TableDef？TableDef 是 MyBatis-Flex 框架提供的一个强大特性，用于定义数据库表的元数据。它提供了一种类型安全的方式来引用数据库表和列，避免了直接使用字符串字面量可能带来的问题。为什么需要 TableDef？在传统的 MyBatis 开发中，我们经常需要写这样的代码：QueryWrapper query = QueryWrapper.create() .where("user_id = ?", userId) .and("status = ?", status);这种方式存在以下问题：容易拼写错误重构困难没有代码提示类型不安全TableDef 的优势使用 TableDef 后，代码变成了这样：QueryWrapper query = QueryWrapper.create() .where(USER.USER_ID.eq(userId)) .and(USER.STATUS.eq(status));主要优势：类型安全，编译时就能发现错误代码提示，IDE 可以自动补全重构方便，如果表名或字段名改变，只需要修改一处代码更清晰，易于维护实际项目中的应用让我们通过宠物商店项目中的实际例子来看看 TableDef 的使用：1. 定义 TableDef首先，我们需要为每个表创建一个 TableDef 类：public class PetTableDef extends TableDef { public static final PetTableDef PET = new PetTableDef(); public final QueryColumn ID = new QueryColumn(this, "id"); public final QueryColumn USER_ID = new QueryColumn(this, "user_id"); public final QueryColumn NAME = new QueryColumn(this, "name"); public final QueryColumn BREED = new QueryColumn(this, "breed"); public final QueryColumn AVATAR = new QueryColumn(this, "avatar"); public PetTableDef() { super("pet", "p"); } }2. 在查询中使用在 Service 层中使用 TableDef 进行查询：@Service public class PetServiceImpl implements PetService { @Autowired private PetMapper petMapper; @Override public List<Pet> getPetsByUserId(Integer userId) { return petMapper.selectListByQuery( QueryWrapper.create() .where(PET.USER_ID.eq(userId)) ); } }3. 复杂查询示例使用 TableDef 可以轻松构建复杂的查询：// 多表联查 QueryWrapper query = QueryWrapper.create() .select( PET.NAME, PET.BREED, USER.NICKNAME.as("ownerName") ) .from(PET) .leftJoin(USER).on(PET.USER_ID.eq(USER.ID)) .where(PET.USER_ID.eq(userId)); // 条件查询 QueryWrapper query = QueryWrapper.create() .where(PET.NAME.like(keyword)) .and(PET.BREED.eq(breed)) .orderBy(PET.ID.desc()); // 分页查询 Page<Pet> page = petMapper.paginate( new Page<>(pageNum, pageSize), QueryWrapper.create() .where(PET.USER_ID.eq(userId)) );4. 动态 SQLTableDef 也支持动态 SQL 的构建：QueryWrapper query = QueryWrapper.create() .where(PET.USER_ID.eq(userId)); if (StringUtils.isNotBlank(keyword)) { query.and(PET.NAME.lik…

智慧零工平台后端开发实战：SpringBoot + MyBatis-Flex 现代化架构
type: item
date: 2025-06-02T17:46:00+08:00
description: 本文将详细分享我使用Spring Boot 3.3.5 + MyBatis-Flex + SQLite构建零工平台后端系统的完整经验，包含架构设计、技术选型、核心功能实现和生产部署。项目背景随着零工经济的快速发展，我决定开发一个现代化的零工服务平台。后端系统需要支持工作发布、申请匹配、用户管理、支付结算等复杂业务场景，同时要保证高性能、高可用和易扩展。项目概览项目名称: 智慧零工平台后端系统技术栈: Spring Boot 3.3.5 + Java 21 + MyBatis-Flex + SQLite项目地址: GitHub - Gigplatform_backendAPI文档: 24个业务模块，100+接口部署方式: 宝塔面板 + PM2 + Nginx技术选型分析为什么选择Spring Boot 3？Java 21支持: 享受最新的语言特性和性能优化原生镜像: 支持GraalVM原生编译，启动更快响应式编程: 内置WebFlux支持可观测性: 增强的监控和链路追踪安全性: 升级的Spring SecurityMyBatis-Flex vs MyBatis-Plus经过对比，我选择了MyBatis-Flex：// MyBatis-Flex 优势示例 // 1. 类型安全的查询 List<Job> jobs = queryWrapper .select(JOB.ALL_COLUMNS) .from(JOB) .where(JOB.STATUS.eq("ACTIVE")) .and(JOB.SALARY.ge(5000)) .orderBy(JOB.CREATE_TIME.desc()) .limit(10) .list(); // 2. 智能字段映射 @Table("t_job") public class Job { @Id(keyType = KeyType.Auto) private Long id; @Column("job_title") private String title; // 自动处理驼峰命名 private String companyName; // -> company_name }SQLite的选择对于中小型项目，SQLite具有独特优势：零配置: 无需独立数据库服务器高性能: 本地文件访问，减少网络开销事务支持: 完整的ACID特性跨平台: 易于开发和部署成本低: 降低运维复杂度架构设计整体架构┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 前端应用 │ │ API网关 │ │ 负载均衡 │ │ (uni-app) │◄───│ (Nginx) │◄───│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ▼ ┌─────────────────────────┐ │ Spring Boot │ │ (业务逻辑层) │ └─────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 认证授权 │ │ 业务服务 │ │ 数据访问 │ │ (JWT) │ │ (Service) │ │ (MyBatis) │ └─────────────┘ └─────────────┘ └─────────────┘ │ ▼ ┌─────────────────┐ │ SQLite 数据库 │ └─────────────────┘项目模块结构com.example.backend/ ├── controller/ # 控制器层 │ ├── AuthController # 认证授权 │ ├── JobsController # 工作管理 │ ├── UsersController # 用户管理 │ └── ... # 其他业务控制器 ├── service/ # 业务逻辑层 │ ├── impl/ # 实现类 │ └── interfaces/ # 接口定义 ├── mapper/ # 数据访问层 ├── entity/ # 实体类 ├── config/ # 配置类 ├── common/ # 公共组件 │ ├── Result.java # 统一返回结果 │ ├── JwtUtil.java # JWT工具 │ └── JwtFilter.java # JWT过滤器 └── BackendApplication.java # 启动类核心功能实现1. JWT认证体系@Componen…