Lucaju 的技术笔记 - SpringBoot
type: channel
link: https://www.lucaju.cn/index.php/tag/SpringBoot/
items: 接入 DeepSeek | Java 调用大模型实战保姆级教程：新手快速上手
items: 自定义 Spring-Boot-Starter 结合 TrueLicense 实现证书授权拦截
items: 写给新同学的SpringBoot教程 — 高级篇
items: 写给新同学的SpringBoot教程 — 入门篇

接入 DeepSeek | Java 调用大模型实战保姆级教程：新手快速上手
type: item
date: 2025-08-11T17:33:00+08:00
description: 接入 DeepSeek | Java 调用大模型实战保姆级教程：新手快速上手最近各大平台接入 DeepSeek 大模型的案例越来越多，作为程序员，你是不是也想亲手实现一次？别担心，这篇教程会用3 种实战方式，带你从零开始用 Java 接入 DeepSeek 大模型，从 SDK 调用到原生 HTTP 请求全覆盖，新手也能轻松上手～前置知识：为什么需要响应式编程？大模型对话为了提升用户体验，通常会采用流式输出（像 ChatGPT 那样逐字显示回复）。而 Java 中实现流式输出需要用到响应式编程（Reactive Programming），核心是通过Flux（Reactor 框架）处理异步数据流。如果你对响应式编程不太熟悉，可以先简单理解：Flux能帮你 “实时接收” 大模型的每一段输出，而不是等全部结果返回后才处理。👉 快速入门参考：Spring 响应式编程官方文档👉 也可参考我的博客：响应式编程学习笔记准备工作：先获取 DeepSeek API Key在开始编码前，需要先申请 DeepSeek 的 API Key：访问 DeepSeek 开放平台：https://platform.deepseek.com/api_keys注册 / 登录账号后，在 “API Keys” 页面点击 “创建 API Key”，保存生成的密钥（后续代码中会用到）。方式一：通过 DeepSeek 官方 SDK 调用（最直接）DeepSeek 官方提供了适配 Spring AI 的 SDK，开箱即用，适合快速集成。1. 添加依赖在pom.xml中引入 Spring AI 对 DeepSeek 的支持（建议使用1.0.0+版本，兼容性更好）： <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-deepseek</artifactId> <version>1.0.0</version> </dependency>2. 编码实现：阻塞式与流式输出import org.junit.jupiter.api.Test; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.deepseek.DeepSeekChatModel; import org.springframework.ai.deepseek.DeepSeekChatOptions; import org.springframework.ai.deepseek.api.DeepSeekApi; import reactor.core.publisher.Flux; import java.util.ArrayList; import java.util.List; public class DeepSeekSdkTest { // 初始化DeepSeek模型（核心对象） private final DeepSeekChatModel chatModel = DeepSeekChatModel.builder() .deepSeekApi(DeepSeekApi.builder() .apiKey("你的API Key") // 替换为你的DeepSeek API Key .build()) .defaultOptions(DeepSeekChatOptions.builder() .model("deepseek-chat") // 指定模型（支持deepseek-chat、deepseek-coder等） .temperature(0.7) // 控制输出随机性（0-1，值越高越随机） .build()) .build(); // 测试1：阻塞式输出（适合简单场景，等待完整结果返回） @Test public void testBlockingCall() { // 构建对话消息（SystemMessage设定角色，UserMessage是用户提问） List<Message> messages = new ArrayList<>…

自定义 Spring-Boot-Starter 结合 TrueLicense 实现证书授权拦截
type: item
date: 2025-03-14T13:30:00+08:00
description: 引言在软件产品交付场景中，授权管理是保障软件权益的重要手段。传统的硬编码时间限制方式存在修改麻烦、需重新部署等问题，而基于证书（License）的授权方式可通过替换证书文件实现灵活授权，无需改动源码。本文将详解如何基于 Spring Boot 自定义 Starter，并整合开源证书管理引擎 TrueLicense，实现对接口的证书授权拦截功能，帮助开发者快速搭建可控的授权体系。一、技术背景与场景说明1.1 什么是 TrueLicense？TrueLicense 是一个基于 Java 的开源证书管理引擎，提供了证书的生成、颁发、验证等核心功能，支持通过密钥对加密证书内容，确保授权信息的安全性。其官网地址为：https://truelicense.java.net。1.2 为什么需要自定义 Spring Boot Starter？Spring Boot Starter 的核心作用是简化依赖管理和自动配置。通过自定义 Starter，我们可以将证书校验逻辑封装为独立组件，只需在目标项目中引入依赖并配置参数，即可快速集成证书授权功能，实现 "即插即用"。1.3 核心场景软件试用期授权：通过证书指定有效期，到期后自动限制使用。硬件绑定授权：限制软件仅能在指定 MAC 地址的设备上运行。接口级授权控制：对敏感接口添加证书校验，未授权请求直接拦截。二、密钥对生成（基于 keytool）证书的安全性依赖于非对称加密的密钥对（私钥用于生成证书，公钥用于验证证书）。我们使用 JDK 自带的keytool工具生成密钥对，步骤如下：2.1 生成私钥库私钥库用于存储生成证书的私钥，执行以下命令：keytool -genkey -alias privatekey -keystore privateKeys.store -storepass "123456q" -keypass "123456q" -keysize 1024 -validity 3650参数说明：-alias privatekey：私钥别名（后续生成证书需引用）。-keystore privateKeys.store：生成的私钥库文件名。-storepass "123456q"：私钥库访问密码。-keypass "123456q"：私钥本身的密码（建议与 storepass 一致，简化管理）。-keysize 1024：密钥长度（1024 位及以上确保安全性）。-validity 3650：私钥有效期（单位：天，此处为 10 年）。执行后需输入所有者信息（如姓名、组织等），可根据实际情况填写。2.2 导出公钥证书从私钥库中导出公钥证书（用于校验证书的合法性）：keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store -storepass "123456q"参数说明：-export：指定操作类型为导出证书。-file certfile.cer：导出的公钥证书文件名。执行成功后，当前目录会生成certfile.cer公钥文件。2.3 导入公钥到公钥库将公钥证书导入公钥库（供应用程序验证证书时使用）：keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store -storepass "123456q"参数说明：-alias publiccert：公钥在公钥库中的别名（后续校验需引用）。-keystore publicCerts.store：生成的公钥库文件名。执行时需确认导入（输入yes），完成后公钥库publicCerts.store生成。注意：私钥库（privateKeys.store）需妥善保管，公钥库（publicCerts.store）和公钥证书（certfile.cer）可随应用程序部署。三、证书生成工具实现基于 TrueLicense 的 API，我们可以通过代码生成证书文件。以下是核心实现步骤：3.1 核心参数类定义首先定义证书生成所需的参数封装类（LicenseCreatorParam）：/** * License证书生成类需要的参数 * @author : jucunqi * @since : 2025/3/12 */ @Data public class LicenseCreatorParam implements Serializable { private static final long serialVersionUID = 2832129012982731724L; /** * 证书subject * */ private String subject; /** …

写给新同学的SpringBoot教程 — 高级篇
type: item
date: 2020-04-11T14:49:00+08:00
description: 写给新同学的SpringBoot教程 — 高级篇一、添加缓存1、使用SpringBoot自带缓存功能1、基本使用在主类上添加注解@EnableCaching在业务方法上添加@Cacheable(cacheNames = "xxx")注解这样即可实现基础的缓存功能基本流程：@Cacheable:方法执行之前，先去查询Cache（缓存组件），按照CacheNames指定的名字获取，（CacheManager先获取相应的缓存），第一次获取缓存如果没有Cache组件会自行创建去Cache中查找缓存的内容，使用一个key，默认就是方法的参数key是按照某种策略生成的，默认hi使用keyGenerator生成的。默认使用SimplekeyGenerator生成key：​ 如果有一个参数，key=参数的值​ 如果没有参数，key=new SimpleKey();​ 如果有多个参数，key=new SimpleKey(params);没有查到缓存就去调用目标方法；方法查询结束后，将目标方法返回的结果放入到缓存中。总结：​ @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据，默认按照参数的值作为key去查询缓存，如果缓存中没有，就执行方法并将结果放入到缓存中；以后再来调用就可以直接将缓存中的数据进行返回。核心：使用CaCheManager【ConCurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件key是使用keyGenerator生成的，默认是SimpleKeyGenerator主类：@SpringBootApplication @MapperScan(value = "com.jcq.cache.mapper") @EnableCaching //这个注解不要忘了 public class Springboot09CacheApplication { public static void main(String[] args) { SpringApplication.run(Springboot09CacheApplication.class, args); } }业务方法@Service public class EmployeeService { @Resource private EmployeeMapper employeeMapper; @Cacheable(cacheNames = "emp",key = "#root.methodName+'['+#id+']'") public Employee getEmp(Integer id){ return employeeMapper.selEmpByid(id); } }2、其他属性keyGenerator：key的生成器，可以自己指定key的生成器组件的id ，key/keyGenerator二选一使用。cacheManager:指定缓存管理器，或者cacheResolver指定获取解析器。condition：满足条件是放入缓存。unless：满足条件是不放入缓存，与condition正好相反。sync：默认为false，true为开启异步缓存。若开启异步，unless注解无效3、其他注解@CachePut注解：方法运行完后，将数据放入缓存中@CachePut与@Cacheable的区别：​ 后者在方法运行前先到缓存总查询，前者在方法执行后，将数据放入缓存中。注意：​ 只有保持数据的key相同，才能实现数据的同步更新。 @CachePut(cacheNames = "emp",key = "#employee.id") public Employee update(Employee employee){ employeeMapper.updEmp(employee); return employee; }@CacheEvict:清除缓存数据allEntries:清空所有缓存，默认为falsebeforeInvocation：在方法执行前清空缓存，默认为false注意：保持数据key同一，才可以保持数据同步。 //测试清除缓存中的数据 @CacheEvict(cacheNames = "emp",key = "#id") public void delEmpCache(Integer id){ System.out.println("清除缓存"); }@Caching：可以将多个注解组合//测试Caching的使用 @Caching(cacheable = { @Cacheable(value = "emp", key = "#lastName") }, put = {@CachePut(value = …

写给新同学的SpringBoot教程 — 入门篇
type: item
date: 2020-04-06T13:45:00+08:00
description: 一、写给新同学的SpringBoot教程 — 入门篇1、springboot简介在 Java 开发的世界里，Spring Boot 绝对是一个绕不开的重要框架。它是由 Pivotal 团队在 2014 年推出的，基于 Spring 框架的开源项目，旨在简化 Spring 应用的初始搭建和开发过程。2、微服务2014，martin fowler微服务：架构风格（服务微化）一个应用应该是一组小型服务；可以通过HTTP的方式进行互通；单体应用：ALL IN ONE微服务：每一个功能元素最终都是一个可独立替换和独立升级的软件单元；3、环境准备1、maven设置推荐使用3.X我使用的是3.3.32、IDEA配置配置maven、jdk等相关设置4、springboot编写helloworld通过idea自动提供的脚手架功能快速创建springboot项目1、创建springboot时可能出现的错误1、连接springboot网站超时问题​ 如图给与解决方式​ 1、1 点击设置​ 1、2 一次点击图示位置进行网站设置​ ​ 1、3 在弹出的界面中数据一下网址，并测试连接情况​ 1、4 出现图示连接成功后，重新创建springboot项目即可​5、HelloWorld探究1、pom文件1、父项目<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> </parent>​ springboot会自动依赖一个父项目2、启动器<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>​ 不同的项目会导入不同的启动器，springboot会根据启动器而去选择导入相应的包，从而省去了我们之前配置的xml文件3、主程序类​ 主程序的main方法要写在最外层的包中，即包含所有的子包，这样就可以加载到所有的配置文件，这是必须的​ 主程序类需要配置相应的注解：@SpringBootApplication​ @EnableAutoConfiguration：此注解的作用为，开启自动配置​ 我们需要自己配置的东西，自动配置类都帮我们解决了。​ 以上配置都在springboot-autoconfigure这个jar包中6、使用idea快速创建项目1、java目录​ 1、使用快速创建的项目，java目录中会自动生成主方法，我们只需编写业务逻辑代码即可。​ 2、@SpringBootApplication：该注解等同于@RequestMapping（）和ResponseBody相结合2、resource目录​ 1、static文件夹：用于存放静态资源，如js、html、image、等​ 2、templates文件夹：用户放页面显示文件，springboot默认不支持jsp，但是也可以引用模板来使用jsp或他模板3、application.properties​ 1、该文件中可以修改一些springboot的默认配置，如Tomcat默认端口号等。项目目录结构见下图二、配置文件1、spring认同的配置文件1、application.properties​ 与我们之前用的配置文件使用方法相同。2、application.yml2、yml文件​ yaml 是一种文件类型 也可以也做ymlyaml yaml ain't markup language 这句话可以理解为：yaml a markup language yaml是一个标记语言yaml ism't a markup language yaml不是一个标记语言其实yaml还是标记语言yaml与xml的区别yaml以数据为中心，比xml、json等更适合作为配置文件server: port: 8081 xml<servetr> <port>8081</port> </servetr>3、yaml语法1、基本语法​ yaml文件中默认的格式为 k: v k与v中间的空格是不可缺少的，所有左对齐的数据为同一级别。​ yaml文件只可以使用空格，不可以使用tab键2、值得表示字面量：普通的值​ 包括：数字，字符串，布尔值等​ 语法： k: v 直接在后面写值即可​ 如： name: zhangsan yaml中“” 与‘’ 的区别：​ yaml 中双引号不会对内容进行转义​ name: "zhangsan…