首页
关于这个博客
Search
1
Java 实现Google 账号单点登录(OAuth 2.0)全流程解析
231 阅读
2
Spring AI 无法获取大模型深度思考内容?解决方案来了
201 阅读
3
微信小程序实现页面返回前确认弹窗:兼容左上角返回与右滑返回
91 阅读
4
服务器遭遇 XMRig 挖矿程序入侵排查与清理全记录
66 阅读
5
解决 Mac 版 PicGo 无法打开问题:“已损坏,无法打开” 报错处理指南
37 阅读
Java 核心
框架与中间件
数据库技术
开发工具与效率
问题排查与踩坑记录
程序员成长与思考
前端
登录
Search
标签搜索
java虚拟机
JVM
保姆级教程
Java
Spring AI
SpringBoot
Nginx
WebFlux
Spring
cdn
https
dcdn
网站加速
Tool
图片导出
服务部署
源码解析
单点登录
google
sso
Luca Ju
累计撰写
35
篇文章
累计收到
1
条评论
首页
栏目
Java 核心
框架与中间件
数据库技术
开发工具与效率
问题排查与踩坑记录
程序员成长与思考
前端
页面
关于这个博客
搜索到
6
篇与
的结果
2025-08-11
接入 DeepSeek | Java 调用大模型实战保姆级教程:新手快速上手
接入 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+版本,兼容性更好):<!-- Spring AI 核心依赖 --> <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<>(); messages.add(new SystemMessage("你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。")); messages.add(new UserMessage("你好,请问你是谁")); // 调用模型并获取结果 ChatResponse response = chatModel.call(new Prompt(messages)); // 打印完整回复 System.out.println("完整回复:" + response.getResult().getOutput().getText()); } // 测试2:流式输出(适合用户体验场景,逐字显示回复) @Test public void testStreamCall() { // 准备参数 List<Message> messages = new ArrayList<>(); messages.add(new SystemMessage("你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。")); messages.add(new UserMessage("你好,请问你是谁")); // 调用 Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages)); // 打印结果 flux.subscribe(resp -> System.out.println(resp.getResult().getOutput().getText())); // 阻塞等待(测试环境用,实际项目无需此操作) try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }代码说明DeepSeekChatModel:DeepSeek SDK 的核心类,通过建造者模式配置 API Key 和模型参数。call()方法:阻塞式调用,适合不需要实时显示的场景(如后端批量处理),结果如下图。stream()方法:流式调用,返回Flux对象,通过subscribe()实时接收输出(前端可配合 SSE 显示)。模型参数:temperature控制回复随机性(0 = 严谨,1= creative),model可切换为代码模型deepseek-coder。方式二:通过 OpenAI 兼容 SDK 调用(推荐!)大多数主流大模型(包括 DeepSeek)都兼容 OpenAI 的 API 格式,用 OpenAI 的 SDK 调用更通用,后续切换模型(如 GPT、 Claude)几乎不用改代码。1. 添加依赖引入 Spring AI 对 OpenAI 的支持(和方式一的依赖不冲突,可共存):<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>1.0.0</version> <!-- 与DeepSeek依赖版本保持一致 --> </dependency>2. 编码实现:兼容 OpenAI 格式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.openai.OpenAiChatModel; import org.springframework.ai.openai.OpenAiChatOptions; import org.springframework.ai.openai.api.OpenAiApi; import reactor.core.publisher.Flux; import java.util.ArrayList; import java.util.List; public class OpenAiCompatibleTest { // 初始化OpenAI兼容模型(核心是替换baseUrl为DeepSeek) private final OpenAiChatModel chatModel = OpenAiChatModel.builder() .openAiApi(OpenAiApi.builder() .baseUrl("https://api.deepseek.com/") // DeepSeek的OpenAI兼容接口地址 .apiKey("你的API Key") // 同样使用DeepSeek的API Key .build()) .defaultOptions(OpenAiChatOptions.builder() .model("deepseek-chat") // 模型名称与DeepSeek一致 .temperature(0.7) .build()) .build(); // 测试阻塞式输出(和方式一用法几乎一致) @Test public void testBlockingCall() { List<Message> messages = new ArrayList<>(); messages.add(new SystemMessage("你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。")); messages.add(new UserMessage("你好,请问你是谁")); ChatResponse response = chatModel.call(new Prompt(messages)); System.out.println("完整回复:" + response.getResult().getOutput().getText()); } // 测试流式输出 @Test public void testStreamCall() { // 准备参数 List<Message> messages = new ArrayList<>(); messages.add(new SystemMessage("你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。")); messages.add(new UserMessage("你好,请问你是谁")); // 调用 Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages)); // 打印结果 flux.subscribe(resp -> System.out.println(resp.getResult().getOutput().getText())); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }为什么推荐这种方式?兼容性强:后续想切换到 GPT-4、Anthropic Claude 等模型,只需修改baseUrl和model参数。生态成熟:OpenAI 的 SDK 文档和社区支持更丰富,遇到问题更容易找到解决方案。代码复用:团队中如果已有 OpenAI 调用逻辑,无需重复开发,直接适配 DeepSeek。方式三:原生 HTTP 请求调用(无 SDK,更灵活)如果不想依赖第三方 SDK,也可以直接通过 HTTP 请求调用 DeepSeek 的 API,适合需要自定义请求 / 响应处理的场景。1. 核心原理DeepSeek 的聊天接口地址为:https://api.deepseek.com/v1/chat/completions,支持 POST 请求,通过stream: true参数开启流式输出。请求头需携带Authorization: Bearer 你的API Key,请求体为 JSON 格式(包含对话消息、模型参数等)。2. 编码实现:用 WebClient 发送请求import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Flux; public class HttpDirectCallTest { // 你的DeepSeek API Key private static final String API_KEY = "你的API Key"; // DeepSeek聊天接口地址 private static final String API_URL = "https://api.deepseek.com/v1/chat/completions"; @Test public void testStreamHttpCall() { // 构建请求体JSON(流式输出需设置stream: true) String requestBody = """ { "messages": [ { "role": "system", "content": "你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。" }, { "role": "user", "content": "如何用Java发送HTTP请求?" } ], "model": "deepseek-chat", "stream": true, "temperature": 0.7, "max_tokens": 2048 } """; // 用WebClient发送POST请求(响应式HTTP客户端) WebClient webClient = WebClient.create(API_URL); Flux<String> responseFlux = webClient.post() .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + API_KEY) .bodyValue(requestBody) .retrieve() .bodyToFlux(String.class); // 流式接收响应 // 订阅并处理响应 responseFlux.subscribe( chunk -> { // 每一段流式输出(SSE格式,需解析data字段) if (chunk.contains("\"data\":")) { String content = chunk.split("\"data\":")[1].replace("}", "").replace("\"", "").trim(); if (!content.equals("[DONE]")) { // 过滤结束标识 System.out.print(content); } } }, error -> System.err.println("HTTP请求错误:" + error.getMessage()), () -> System.out.println("\nHTTP流式输出结束~") ); // 阻塞等待 try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }代码说明请求体参数:messages是对话历史(role支持system/user/assistant),stream: true开启流式输出。响应处理:流式响应为 SSE(Server-Sent Events)格式,每一行是data: {内容},需解析data字段获取实际输出。灵活性:可自定义超时时间、重试机制、请求拦截器等,适合复杂场景(如企业级网关适配)。三种方式对比与选择建议方式优点缺点适合场景DeepSeek 官方 SDK原生支持,参数适配性好仅支持 DeepSeek,切换模型需改代码仅用 DeepSeek,快速集成OpenAI 兼容 SDK跨模型兼容,生态成熟需确认模型兼容性(部分参数可能不同)可能切换模型,追求代码复用原生 HTTP 请求无依赖,高度自定义需手动处理参数、解析响应,开发效率低自定义需求高,避免第三方 SDK 依赖👉 新手推荐方式二,兼顾简单性和灵活性;追求极致自定义用方式三;仅深度集成 DeepSeek 用方式一。避坑指南API Key 安全:不要硬编码 API Key,建议通过配置文件(如application.yml)或环境变量注入,避免泄露。超时设置:大模型响应可能较慢,需在 HTTP 客户端或 SDK 中设置合理超时时间(如 30 秒以上)。流式输出前端适配:如果前端需要显示流式效果,可通过 SSE(Server-Sent Events)或 WebSocket 接收后端的Flux输出。模型参数调试:temperature和top_p控制输出风格,可根据需求调整(技术问答建议temperature=0.3更严谨)。总结通过本文的 3 种方式,介绍了 Java 调用 DeepSeek 大模型的核心方法。无论是快速集成的 SDK 方式,还是灵活的原生 HTTP 请求,都能满足不同场景的需求。接下来可以尝试扩展功能:比如添加对话历史管理、实现多轮对话,或者集成到 Spring Boot 项目中提供 API 接口。如果遇到问题,欢迎在评论区留言, 祝大家开发顺利! 🚀
2025年08月11日
11 阅读
0 评论
0 点赞
2025-08-06
Ubuntu环境Mysql安装的保姆级教程
一、Ubuntu简介Ubuntu 是一款基于 Debian 的开源 Linux 操作系统,由南非企业家马克・沙特尔沃思(Mark Shuttleworth)创立的 Canonical 公司主导开发,首次发布于 2004 年。其名称源自非洲祖鲁语或科萨语,意为 “人性” 或 “共享的关怀”,体现了开源社区协作共享的理念。二、Mysql简介MySQL 是一款开源的关系型数据库管理系统(RDBMS),由瑞典 MySQL AB 公司开发,后被 Sun 公司收购,最终随 Sun 并入 Oracle 公司。它以高性能、稳定性、易用性和开源免费为核心优势,成为全球最流行的数据库之一,广泛应用于 Web 开发、企业级应用、数据存储等场景。三、安装 本文介绍Mysql的在线安装过程1、更新软件包sudo apt update2、下载Mysql# 安装最新版本 sudo apt install -y mysql-server # 安装指定版本 sudo apt install -y mysql-server-8.03、启动Mysql、并设置为开机运行sudo systemctl start mysql sudo systemctl enable mysql4、检查mysql状态sudo systemctl status mysql如果出现active(running),则表示安装启动成功了四、允许远程可视化工具连接1、修改 MySQL 配置文件:找到配置文件,Linux 系统一般位于/etc/mysql/mysql.conf.d/mysqld.cnf,可以使用命令mysql --help | grep "my.cnf"查找。打开配置文件,找到bind-address = 127.0.0.1这一行,将其改为bind-address = 0.0.0.0,表示监听所有 IP 地址上的连接请求。如果是生产环境,也可指定特定 IP,如bind-address = 192.168.1.100。2、创建或授权远程访问用户: 1) 登录 MySQL 服务打开终端,执行以下命令登录 MySQL ,输入 root 密码完成认证(若首次安装无密码,直接回车即可)mysql -u root -p2) 创建并授权新用户(推荐方式)2.1 创建远程访问用户通过 SQL 命令创建新用户,支持自定义用户名、密码,以及控制可访问的 IP 范围:-- 允许任意 IP 访问(% 代表所有 IP) CREATE USER 'remote_user'@'%' IDENTIFIED BY 'your_password'; -- 仅允许指定 IP(如 192.168.1.100)访问,按需替换 -- CREATE USER 'remote_user'@'192.168.1.100' IDENTIFIED BY 'your_password'; 说明: - remote_user:自定义的用户名,可根据需求修改 - your_password:设置的用户密码,建议复杂度足够(字母 + 数字 + 特殊字符) - % 或 192.168.1.100:控制允许登录的 IP 范围,% 适合信任网络,指定 IP 更安全2.2 授予用户远程访问权限创建用户后,需赋予权限并刷新使配置生效:-- 授予所有权限(生产环境可按需缩小权限范围,如指定数据库) GRANT ALL PRIVILEGES ON *.* TO 'remote_user'@'%' WITH GRANT OPTION; -- 刷新权限,让配置立即生效 FLUSH PRIVILEGES; 说明: - ALL PRIVILEGES:授予全部权限(谨慎使用,生产环境建议细化,如 GRANT SELECT,INSERT ON db_name.* TO ... ) - .:表示所有数据库的所有表,可替换为 db_name.* 限制特定数据库3) 修改已有用户权限(备用方案)若不想新建用户,可直接修改现有用户的远程访问权限:-- 允许任意 IP 访问已有用户(替换 existing_user 和 password) GRANT ALL PRIVILEGES ON *.* TO 'existing_user'@'%' IDENTIFIED BY 'password'; -- 刷新权限 FLUSH PRIVILEGES; 说明: - existing_user:替换为实际的已有用户名 - password:替换为该用户对应的密码 - 此操作会同时重置用户密码(若无需改密码,需保持原密码一致)注意如果安装的是msyql8.0及以上版本GRANT 语句的语法有变化,不再支持在 GRANT 语句里直接用 IDENTIFIED BY 创建 / 修改用户密码,得拆分成两步操作。解决方法(分两步执行)1. 先创建 / 修改用户并设置密码(用 CREATE USER 或 ALTER USER):-- 若用户 root@% 不存在,创建并设密码 CREATE USER 'root'@'%' IDENTIFIED BY 'yourpassword'; -- 若用户已存在,修改密码用这个: -- ALTER USER 'root'@'%' IDENTIFIED BY 'yourpassword'; 2. 再给用户授权:GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'; -- 刷新权限让修改生效 FLUSH PRIVILEGES; ## 3、重启 MySQL 服务:使配置生效执行命令sudo systemctl restart mysql4、配置防火墙或安全组,开放3306端口五、远程连接验证结果如图
2025年08月06日
23 阅读
0 评论
0 点赞
2025-08-05
从零起步,Ubuntu环境搭建Typecho个人博客的保姆级教程
一、确认服务器环境是否满足要求根据Typecho官网要求,运行需要基础环境支持,先检查是否安装以下组件:Web 服务器:Nginx 或 Apache(推荐 Nginx,更轻量)。PHP:5.6 及以上版本(推荐 7.2+),并需启用必要扩展(如 pdo_mysql、mbstring、json、gd 等)。数据库:MySQL 或 MariaDB(用于存储博客数据)。 官网链接: https://typecho.org/二、快速安装基础环境默认大家没有任何环境,从零开始# 安装 Nginx、PHP、MySQL sudo apt update sudo apt install nginx php php-fpm php-mysql php-mbstring php-gd php-json mysql-server三、下载并上传至服务器根据官网下载链接,将下载的zip压缩包,放在服务器自定义的目录下,以/usr/local/typecho 为例四、配置 Web 服务器(以 Nginx 为例)Web 服务器需要将访问请求指向 Typecho 的安装目录(/usr/local/typecho),并处理 PHP 解析。1、创建 Nginx 配置文件sudo nano /etc/nginx/sites-available/typecho # 新建配置文件2、写入配置内容根据你的服务器 IP 或域名修改以下内容(假设用 IP 访问,或已解析域名):server { listen 80; # 监听 80 端口(HTTP) server_name your_domain.com; # 替换为你的域名或服务器 IP(如 1.2.3.4) # 网站根目录指向 Typecho 解压目录 root /usr/local/typecho; index index.php index.html; # 默认索引文件 # 关键:Typecho 伪静态规则(必须添加) location / { # 如果请求的文件或目录不存在,将请求转发给 index.php 处理 if (!-e $request_filename) { rewrite ^(.*)$ /index.php?$1 last; } } # PHP 解析配置(保持不变) location ~ \.php$ { fastcgi_pass unix:/run/php/php8.1-fpm.sock; # 替换为你的 PHP 版本 fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } # 禁止访问隐藏文件(保持不变) location ~ /\. { deny all; access_log off; log_not_found off; } # 静态资源缓存(保持不变) location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { expires 30d; add_header Cache-Control "public, max-age=2592000"; } # 日志配置(可选) access_log /var/log/nginx/typecho_access.log; error_log /var/log/nginx/typecho_error.log; }注意:fastcgi_pass 中的 PHP 版本需与你安装的一致(可通过 ls /run/php/ 查看实际 sock 文件名)。3、启用配置并重启 Nginxsudo ln -s /etc/nginx/sites-available/typecho /etc/nginx/sites-enabled/ # 启用站点 sudo nginx -t # 检查配置是否有误 sudo systemctl restart nginx # 重启 Nginx五、设置 Typecho 目录权限Typecho 需要对部分目录有写入权限(如配置文件、缓存、上传目录),否则安装时会提示 “无法写入配置文件”。执行以下命令修改权限:# 递归设置目录所有者为 Web 服务器用户(Nginx 通常用 www-data) sudo chown -R www-data:www-data /usr/local/typecho # 确保关键目录可写(可选,根据实际提示调整) sudo chmod -R 755 /usr/local/typecho/usr # 上传和缓存目录 sudo chmod 755 /usr/local/typecho # 根目录(确保能生成 config.inc.php)六、准备数据库Typecho 需要数据库存储文章、用户等数据,需提前创建数据库和用户。1、登录mysqlsudo mysql -u root -p # 输入 root 密码(首次安装可能无密码,直接回车)2、执行sql命令创建数据库和用户-- 创建数据库(名称自定义,如 typecho_db) CREATE DATABASE typecho_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建数据库用户(用户名和密码自定义,如 typecho_user / your_password) CREATE USER 'typecho_user'@'localhost' IDENTIFIED BY 'your_password'; -- 授权用户访问数据库 GRANT ALL PRIVILEGES ON typecho_db.* TO 'typecho_user'@'localhost'; -- 刷新权限 FLUSH PRIVILEGES; -- 退出 MySQL exit;七、通过浏览器访问并完成安装打开本地电脑的浏览器,输入服务器的 IP 地址 或 域名(如 http://1.2.3.4 或 http://your_domain.com)。如果配置正确,会看到 Typecho 的安装向导页面。
2025年08月05日
18 阅读
0 评论
1 点赞
2025-08-05
在 Ubuntu 环境下安装与配置 Nginx 的完整指南
Nginx简介 Nginx是一款高性能的开源 Web 服务器、反向代理服务器、负载均衡器和 HTTP 缓存工具。它由俄罗斯程序员伊戈尔・赛索耶夫(Igor Sysoev)于 2004 年首次公开发布,最初设计的目标是解决高并发场景下的性能瓶颈,如今已成为全球最流行的服务器软件之一,被 Netflix、Airbnb、GitHub、腾讯、阿里等众多大型企业广泛使用。本文将详细介绍如何在 Ubuntu 系统中安装、配置并优化 Nginx,适合初学者入门参考。一、安装 NginxUbuntu 的官方软件仓库中已经包含了 Nginx,我们可以通过 APT 包管理器轻松安装。更新系统包列表首先确保系统包列表是最新的:sudo apt update安装 Nginx执行以下命令安装 Nginx:sudo apt install nginx验证安装是否成功安装完成后,Nginx 会自动启动。可以通过以下命令检查其运行状态:sudo systemctl status nginx如果看到 "active (running)" 字样,说明 Nginx 已经成功启动。配置防火墙 4.1 如果你的 Ubuntu 系统启用了 UFW 防火墙,需要允许 HTTP(80 端口)和 HTTPS(443 端口)流量:sudo ufw allow 'Nginx Full'可以通过以下命令验证防火墙规则:sudo ufw status 4.2 如果你跟我一样,使用的是云服务器,那么只需要在安全组中开放80端口即可二、Nginx的基本操作掌握以下基本命令可以帮助你管理 Nginx 服务:启动 Nginx:sudo systemctl start nginx停止 Nginx:sudo systemctl stop nginx重启 Nginx:sudo systemctl restart nginx重新加载配置(不中断服务):sudo systemctl reload nginx设置开机自启动:sudo systemctl enable nginx禁止开机自启动:sudo systemctl disable nginx三、Nginx 的配置文件结构Nginx 的配置文件位于/etc/nginx目录下,主要文件和目录包括:/etc/nginx/nginx.conf:主配置文件/etc/nginx/sites-available/:存储所有网站的配置文件/etc/nginx/sites-enabled/:存储启用的网站配置(通常是指向 sites-available 目录的软链接)/etc/nginx/conf.d/:可以存放额外的配置片段/etc/nginx/mime.types:定义 MIME 类型这种结构允许我们为每个网站创建独立的配置文件,便于管理。四、配置一个基本的 Web 站点下面我们创建一个简单的 Web 站点配置:创建网站目录首先为网站创建一个目录,并设置适当的权限:sudo mkdir -p /var/www/example.com/html sudo chown -R $USER:$USER /var/www/example.com/html sudo chmod -R 755 /var/www创建测试页面在网站目录下创建一个简单的 HTML 文件:nano /var/www/example.com/html/index.html添加以下内容:预览 <!DOCTYPE html> <html> <head> <title>Welcome to Example.com!</title> </head> <body> <h1>Success! The example.com server block is working!</h1> </body> </html>保存并关闭文件。创建服务器配置文件在sites-available目录下创建一个新的配置文件:sudo nano /etc/nginx/sites-available/example.com添加以下配置:server { listen 80; listen [::]:80; root /var/www/example.com/html; index index.html index.htm index.nginx-debian.html; server_name example.com www.example.com; # 替换为你的域名或服务器 IP(如 1.2.3.4) location / { try_files $uri $uri/ =404; } }这个配置指定了:监听 80 端口(HTTP)网站文件根目录默认索引文件服务器域名基本的请求处理规则启用站点配置通过创建软链接将配置文件链接到sites-enabled目录:sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/检查配置文件语法在应用配置之前,先检查语法是否正确:sudo nginx -t如果输出 "nginx: configuration file /etc/nginx/nginx.conf test is successful",说明配置没有问题。重新加载 Nginx使配置生效:sudo systemctl reload nginx测试网站如果你的域名已经解析到服务器 IP,现在可以通过浏览器访问http://example.com来查看效果。如果没有域名,可以修改本地hosts文件进行测试。五、注意如果访问80端口,显示Apache2默认页面,说明80端口被Apache服务器占用了,可以通过一下命令停止Apache服务器sudo systemctl stop apache2再次访问就可以成功访问到我们部署的页面了
2025年08月05日
11 阅读
0 评论
0 点赞
2020-04-11
写给新同学的SpringBoot教程 — 高级篇
写给新同学的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 = "emp", key = "#result.id"), @CachePut(value = "emp",key = "#result.email") } ) public Employee selBylastName(String lastName){ return employeeMapper.selBylastName(lastName); } 2、整合redis1、redis命令常用命令网址2、步骤在pom.xml中引入下列依赖<!--引入redis启动器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>配置文件如下#配置redis spring.redis.host=192.168.91.128SpringBoot把对redis的操作封装在RedisTemplate 和 StringRedisTemplate中@SpringBootTest class Springboot09CacheApplicationTests { @Autowired private RedisTemplate redisTemplate; @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private EmployeeService employeeService; @Test public void testRedis(){ //添加字符串 // stringRedisTemplate.opsForValue().append("msg","helloworld"); //添加list // stringRedisTemplate.opsForList().leftPushAll("mylist","1","2","3"); //取出list // String str = stringRedisTemplate.opsForList().leftPop("mylist"); // System.out.println(str); Employee emp = employeeService.getEmp(1); //添加对象 redisTemplate.opsForValue().set("emp",emp); }3、添加自定义组件,将对象转化为json字符串存储@Configuration public class MyRedisTemplate { @Bean public RedisTemplate<Object, Employee> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Employee> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); template.setDefaultSerializer(new Jackson2JsonRedisSerializer(Employee.class)); return template; } }而在服务启动过程中,使用的CacheManager依旧默认按照序列化的方式进行对象存储,所以还需要添加组件来达到将对象用json存储的目的 /** * 缓存管理器 */ @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { //初始化一个RedisCacheWriter RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory); //设置CacheManager的值序列化方式为json序列化 RedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer(); RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair .fromSerializer(jsonSerializer); RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(pair); //设置默认超过期时间是30秒 defaultCacheConfig.entryTtl(Duration.ofSeconds(30)); //初始化RedisCacheManager return new RedisCacheManager(redisCacheWriter, defaultCacheConfig); }二、SpringBoot与消息1、使用docker安装rabbitmq//下载rabbitmq docker pull rabbitmq:3-management //运行 docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq id默认用户名密码均为:guest转换器类型:direct:只有key相同的队列才可以收到消息fanout:任意队列都能收到消息atguigu.# : #表示0或多个词.news : 表示0或一个单词2、SpringBoot整合Rabbitmq1、基础使用配置文件:**spring.rabbitmq.username=guest spring.rabbitmq.password=guest spring.rabbitmq.host=192.168.91.128 #默认为5672,不需要配置 #spring.rabbitmq.port=5672测试代码: /** * 单播 */ @Test void contextLoads() { Map<String, Object> map = new HashMap<>(); map.put("name", "张三"); map.put("age", 18); rabbitTemplate.convertAndSend("exchange.direct","atguigu.news",map); }但是这样发送的消息,会以默认的序列化方式进行存储。效果接收消息: /** * 接收消息 */ @Test void recieve(){ Object o = rabbitTemplate.receiveAndConvert("atguigu.news"); System.out.println(o.getClass()); System.out.println(o); }自定义组件,使用json格式进行对象转化@Configuration public class MyAMQPConfig { @Bean public MessageConverter messageConverter(){ return new Jackson2JsonMessageConverter(); } }广播测试代码 /** * 广播 */ @Test void sendMsg(){ rabbitTemplate.convertAndSend("exchange.fanout","",new Book("SpringMVC","张佳明")); }2、消息监听主类上添加@EnableRabbit注解@EnableRabbit @SpringBootApplication public class SpringBoot10AmqpApplication { public static void main(String[] args) { SpringApplication.run(SpringBoot10AmqpApplication.class, args); } }业务代码如下:@Service public class BookService { @RabbitListener(queues = "atguigu.news") public void bookLinstener(Book book){ System.out.println("接收到消息"+book); } }3、使用AmqpAdmin管理工具 @Autowired private AmqpAdmin amqpAdmin; @Test void createRabbit(){ //创建转换器 // amqpAdmin.declareExchange(new DirectExchange("AmqpAdmin.exchange")); // System.out.println("转换器创建成功"); //创建消息队列 // amqpAdmin.declareQueue(new Queue("AmqpAdmin.news")); // System.out.println("消息队列创建成功"); //创建绑定规则 amqpAdmin.declareBinding(new Binding("AmqpAdmin.news", Binding.DestinationType.QUEUE, "AmqpAdmin.exchange", "AmqpAdmin.haha", null)); System.out.println("创建绑定成功"); //删除队列 amqpAdmin.deleteQueue("AmqpAdmin.news"); System.out.println("删除队列"); amqpAdmin.deleteExchange("AmqpAdmin.exchange"); System.out.println("删除转换器"); }三、SpringBoot与检索ElasticSearch1、搭建环境1、下载es docker pull elasticsearch 2、启动命令 [root@localhost ~]# docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 --name ES01 5acf0e8da90b 7d33661ebabc32621173c4c9648047016e6ede9fc625c51340692736b7fdf170 其中: ES_JAVA_OPTS="-Xms256m -Xmx256m" :-Xms 初始堆内存大小 -Xmx 最大使用内存 9200:es默认web通信使用9200端口 9300:当分布式情况下es多个节点之间通信使用9300端口 文档地址:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index-doc.htmlSpringBoot默认支持两种技术和ElasticSearch交互一、Jest(默认不生效)需要导入jest的工具包(io.serachbox.chlient.JestClient)需要将默认的SpringBoot-data-Elasticsearch注释掉导入jest依赖但是jest已经过时,不演示了二、SpringDataClient节点信息clusterNodes,clusterNameElasticsearchTemplate来操作es编写一个ElasticsearchRepository子接口来操作es因版本问题,暂时没有解决SpringBoot2.X版本整合es的方法,使用会报错四、SpringBoot与任务1、异步任务1、在主类添加@EnableAsync注解2、在业务层添加@Async注解即可实现异步任务@Async @Service public class AsyncService { public void testAsync(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("方法执行完毕"); } }2、定时任务cron表达式:Cron表达式的格式:秒 分 时 日 月 周 年(可选)。字段名 允许的值 允许的特殊字符 秒 0-59 , - * / 分 0-59 , - * / 小时 0-23 , - * / 日 1-31 , - * ? / L W C月 1-12 or JAN-DEC , - * / 周几 1-7 or SUN-SAT , - * ? / L C # 年(可选字段) empty 1970-2099 , - * /具体的用法:https://www.cnblogs.com/lazyInsects/p/8075487.html @Scheduled(cron = "0 * * * * MON-FRI") 周一到周五,没整分运行一次 // @Scheduled(cron = "0/4 * * * * MON-FRI") 没整分,间隔4秒执行 @Scheduled(cron = ) public void testAsync(){ System.out.println("方法执行完毕"); } }在方法上加上@Scheduled注解在主类添加@EnableSchelding注解主类代码如下//@EnableAsync @EnableScheduling @SpringBootApplication public class SpringBoot12TaskApplication { public static void main(String[] args) { SpringApplication.run(SpringBoot12TaskApplication.class, args); } } 3、邮件任务配置文件spring.mail.username=1036658425@qq.com spring.mail.password=kersbnhzzuhfbdih spring.mail.host=smtp.qq.com@Autowired JavaMailSenderImpl mailSender; @Test void contextLoads() { //创建简单邮件对象 SimpleMailMessage massage = new SimpleMailMessage(); //设置主题 massage.setSubject("简单测试"); //设置内容 massage.setText("测试简单邮件发送"); //设置收件方 massage.setTo("594082079@qq.com"); //设置发送方 massage.setFrom("1036658425@qq.com"); mailSender.send(massage); } @Test public void test02() throws MessagingException { //测试复杂邮件发送 MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true); helper.setSubject("复杂发送"); helper.setText("<b style='color:red'>测试复杂邮件发送</b>",true); helper.addAttachment("a.jpg",new File("E:\\笔记\\SpringBoot\\springboot高级\\SpringBoot高级.assets\\image-20200310195943079.png")); helper.addAttachment("b.jpg",new File("E:\\笔记\\SpringBoot\\springboot高级\\SpringBoot高级.assets\\image-20200310201323308.png")); helper.setTo("594082079@qq.com"); helper.setFrom("1036658425@qq.com"); mailSender.send(mimeMessage); } 五、SpringBoot与安全1、业务部分代码编写配置类@EnableWebSecurity public class MySecurityConfig extends WebSecurityConfigurerAdapter { //添加认证功能 @Override protected void configure(HttpSecurity http) throws Exception { // super.configure(http); http.authorizeRequests().mvcMatchers("/").permitAll() .mvcMatchers("/level1/**").hasRole("VIP1") .mvcMatchers("/level2/**").hasRole("VIP2") .mvcMatchers("/level3/**").hasRole("VIP3"); //开启登录认证页面 http.formLogin(); //开启自动配置注销功能 http.logout().logoutSuccessUrl("/"); //访问/logout 清除session //开启自动配置记住我功能 http.rememberMe(); } //添加登录授权功能 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // super.configure(auth); auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("zhangsan").password(new BCryptPasswordEncoder().encode("123456")).roles("VIP1","VIP2") .and().withUser("lisi").password(new BCryptPasswordEncoder().encode("123456")).roles("VIP2","VIP3") .and().withUser("wangwu").password(new BCryptPasswordEncoder().encode("123456")).roles("VIP3","VIP1"); }整合页面部分,因版本问题,暂时没有效果,先不放图片了六、分布式1、Dubbo下载镜像[root@localhost ~]# docker pull zookeeper [root@localhost ~]# docker run --name zk01 -p 2181:2181 --restart always -d bbebb888169c 1、提供者将服务提供者注册到注册中心导入相关依赖Dubbo和Zkclient<!--引入Dubbo服务启动器--> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.1.0</version> </dependency> <!--引入zookeeper的客户端工具--> <!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient --> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency>2. 在主类添加启用Dubbo的注解 @EnableDubbo @SpringBootApplication public class ProviderTicketApplication { public static void main(String[] args) { SpringApplication.run(ProviderTicketApplication.class, args); } }如果不加此注解,消费者会报空指针异常 2. 配置application配置文件 dubbo.application.name=provider dubbo.registry.address=zookeeper://192.168.91.128:2181 dubbo.scan.base-packages=com.jcq.ticket.service使用@service发布服务@Component @Service public class TickerServiceImpl implements TickerService { @Override public String getTicker() { return "《厉害了,我的国》"; } }2、消费者导入相关依赖<!--引入Dubbo服务启动器--> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.1.0</version> </dependency> <!--引入zookeeper的客户端工具--> <!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient --> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency>配置文件dubbo.application.name=consumer dubbo.registry.address=zookeeper://192.168.91.128:2181 server.port=8081引用服务需要把提供者的包个接口复制到项目中,且保持路径同一加下来就是编写业务代码了import com.alibaba.dubbo.config.annotation.Reference; import org.springframework.stereotype.Service; @Service public class UserServiceImpl { @Reference private TickerService tickerService; public String getTicker(){ return tickerService.getTicker(); } }注意不要到错包了,会导致空指针异常。2、SpringCloud1、注册中心1、首先在主类添加@EnableEurekaServer注解@EnableEurekaServer @SpringBootApplication public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }2、添加配置文件server: port: 8761 #修改服务端口 eureka: client: fetch-registry: false #不从注册中心获取服务 register-with-eureka: false #不在服务中心注册服务 service-url: defaultZone: http://localhost:8761/eureka/ #访问路径 instance: hostname: eureka-server #主机名称3、登录页面查看是否启动成功网址:http://localhost:8761/2、提供者1、编写配置文件server: port: 8001 spring: application: name: provider-ticket eureka: instance: prefer-ip-address: true #注册服务时,使用服务的ip地址 service-url: defaultZone: http://localhost:8761/eureka/2、正常编写业务代码及控制器代码一个项目注册多个服务直接将不同端口好的项目进行打包,使用cmd命令分别执行即可项目打包后的图片管理页面显示内容入下3、消费者1、编写配置文件server: port: 8200 eureka: instance: prefer-ip-address: true service-url: defaultZone: http://localhost:8761/eureka/ spring: application: name: consumer-user2、主类代码:@EnableDiscoveryClient //开启到注册中心查找服务 @SpringBootApplication public class ConsumerUserApplication { public static void main(String[] args) { SpringApplication.run(ConsumerUserApplication.class, args); } /** * 给容器添加组件 * 可以发送远程http请求 * @return */ @LoadBalanced //开启负载均衡功能 @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }3、业务代码@RestController public class UserController { @Autowired private RestTemplate restTemplate; @GetMapping("/buy") public String buyTicket(String name){ //发送远程请求,请求注册中心的业务方法。地址直接写注册中心中的服务名,不需写端口号 String ticket = restTemplate.getForObject("http://PROVIDER-TICKET/get", String.class); return name+"购买了"+ticket; } }七、热部署只需要到如SpringBoot提供的依赖即可<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency>更改代码后,手动CTRL+F9 重新编译,即可实现热部署
2020年04月11日
4 阅读
0 评论
0 点赞
1
2