当前位置: 首页 > news >正文

网站申请域名流程最新病毒感染什么症状

网站申请域名流程,最新病毒感染什么症状,网络商城网站怎样做关键词优化,唐山网站建设找煌途文章目录 1. 前述2. AI 基础对话3. AI 会话日志4. 前端样式5. 对接前端对话,并实现 AI 会话记忆7. 存在的问题及未来的改进 1. 前述 在前面的内容中,我们已经在本地部署了deepseek-r1:1.5b,详情可参考文章: 【大模型应用开发】Oll…

文章目录

  • 1. 前述
  • 2. AI 基础对话
  • 3. AI 会话日志
  • 4. 前端样式
  • 5. 对接前端对话,并实现 AI 会话记忆
  • 7. 存在的问题及未来的改进

1. 前述


在前面的内容中,我们已经在本地部署了deepseek-r1:1.5b,详情可参考文章:
【大模型应用开发】Ollama 介绍及基于 Ollama 部署本地 DeepSeek

那么下面我们需要将该大模型整合到SpringBoot中,实现接口访问,同时对接前端代码。本文拥有全部的代码 !!!

2. AI 基础对话


在创建AI大模型机器人时,我们现需要了解几个重要概念

  • system:表示系统的默认设置,即给大模型设置任务背景
  • user:即用户的提问
  • assistant:大模型生成的历史消息

首先创建一个项目,其中Java的版本要在17以上

image-20250611160157100

下载相关依赖,其中SpringBoot版本不能过低,否则没有AI依赖,可按需选择deepseek或者openai

在这里插入图片描述

创建好项目后,编辑配置文件application.yaml

spring:application:name: SpringAIai:ollama:# ollama固定的本地访问地址base-url: http://localhost:11434chat:model: deepseek-r1:1.5b

SpringAI利用ChatClient来访问大模型,创建配置文件类CommonConfiguration

@Configuration
public class CommonConfiguration {@Beanpublic ChatClient chatClint(OllamaChatModel ollamaModel){return ChatClient.builder(ollamaModel).build();}
}

创建控制器ChatController,利用阻塞访问输出结果。所谓阻塞式访问,就是需要等待全部回答结束后才会展现给用户

// 用来实例化 chatClient
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class ChatController {private final ChatClient chatClient;// 其中call表示阻塞式调用,即答案会一口气出来@RequestMapping("/chat")// prompt是提示词,就是发送给ai的问题public String chat(String prompt){return chatClient.prompt().user(prompt).call().content();}
}

启动springboot项目,此时要保证ollama在后台运行,在浏览器中测试访问

http://localhost:8080/ai/chat?prompt=你是谁?

image-20250611172403877

倘若需要使用流式输出(更常用,也就是符合现在的流行的回答方式),即回答是一个字一个字展示出来的,则可利用下面的方法

// 用来实例化 chatClient
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class ChatController {private final ChatClient chatClient;// 流式访问,答案会一个字一个字的回答@RequestMapping(value = "/chat",produces = "text/html;charset=utf-8")public Flux<String> streamChat(String prompt){return chatClient.prompt().user(prompt).stream().content();}
}

再次测试访问即可

http://localhost:8080/ai/chat?prompt=你是谁?

于此同时,我们可以修改配置文件类CommonConfiguration,保留默认的系统设置

@Configuration
public class CommonConfiguration {@Beanpublic ChatClient chatClint(OllamaChatModel ollamaModel){return ChatClient.builder(ollamaModel).defaultSystem("你是一个计算机研究生,你叫作小新,请你以他的身份和我对话").build();}
}

此时,再次询问大模型你是谁,它便会按照默认的defaultSystem设置,回答你它是小新

3. AI 会话日志


日志的重要性不言而喻,SpringAI利用AOP原理提供了AI会话时的拦截、增强等功能,也就是Advisor

修改配置文件类CommonConfiguration

@Configuration
public class CommonConfiguration {@Beanpublic ChatClient chatClint(OllamaChatModel ollamaModel){return ChatClient.builder(ollamaModel)   //构建ai.defaultAdvisors(new SimpleLoggerAdvisor())  //日志记录.defaultSystem("你是一个计算机研究生,你叫作小新,请你以他的身份和口吻与我对话").build();}
}

并且修改application.yaml来设定需要日志记录的项目包位置

spring:application:name: SpringAIai:ollama:# ollama固定的本地访问地址base-url: http://localhost:11434chat:model: deepseek-r1:1.5b
logging:level:# 日志记录的项目包位置org.springframework.ai.chat.client.advisor: debugcom.yzx.springai: debug

再次测试访问,控制台可输出对应的日志信息

http://localhost:8080/ai/chat?prompt=今天天气非常好

image-20250612120508853

4. 前端样式


我用官网的DeepSeek生成了几个简单的前端页面,以及对应的样式,在项目中是这样的位置
在这里插入图片描述

前端我并不是很懂,所以下面代码可能并不是很完善,或者说存在部分缺陷,但可以运行,大家可自行修改。首先是style.css

:root {--primary-color: #6c63ff;--sidebar-width: 260px;
}
* {box-sizing: border-box;margin: 0;padding: 0;
}
body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background-color: #f7f7f8;color: #333;display: flex;height: 100vh;overflow: hidden;
}
/* 侧边栏样式 */
.sidebar {width: var(--sidebar-width);background-color: #f0f0f0;border-right: 1px solid #e0e0e0;display: flex;flex-direction: column;height: 100%;
}
.new-chat-btn {margin: 10px;padding: 10px 15px;background-color: var(--primary-color);color: white;border: none;border-radius: 5px;cursor: pointer;display: flex;align-items: center;gap: 8px;font-size: 14px;
}
.new-chat-btn:hover {background-color: #5a52d6;
}
.new-chat-btn i {font-size: 16px;
}
.history-list {flex: 1;overflow-y: auto;padding: 10px;
}
.history-item {padding: 10px 12px;border-radius: 5px;margin-bottom: 5px;cursor: pointer;font-size: 14px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
}
.history-item:hover {background-color: #e0e0e0;
}
.history-item.active {background-color: #d6d6ff;
}
/* 主聊天区域 */
.main-content {flex: 1;display: flex;flex-direction: column;height: 100%;
}
.chat-header {padding: 15px 20px;border-bottom: 1px solid #e0e0e0;background-color: white;font-weight: bold;
}
.chat-messages {flex: 1;overflow-y: auto;padding: 20px;background-color: white;
}
.message {max-width: 80%;margin-bottom: 20px;padding: 12px 16px;border-radius: 8px;line-height: 1.5;
}
.user-message {margin-left: auto;background-color: var(--primary-color);color: white;border-bottom-right-radius: 2px;
}
.ai-message {margin-right: auto;background-color: #f0f0f0;color: #333;border-bottom-left-radius: 2px;
}
.input-area {padding: 15px;border-top: 1px solid #e0e0e0;background-color: white;
}
.input-container {max-width: 800px;margin: 0 auto;display: flex;position: relative;
}
#user-input {flex: 1;padding: 12px 15px;border: 1px solid #ddd;border-radius: 20px;outline: none;font-size: 1em;padding-right: 50px;
}
#send-button {position: absolute;right: 5px;top: 5px;width: 36px;height: 36px;background-color: var(--primary-color);color: white;border: none;border-radius: 50%;cursor: pointer;display: flex;align-items: center;justify-content: center;
}
#send-button:hover {background-color: #5a52d6;
}
#send-button:disabled {background-color: #ccc;cursor: not-allowed;
}
/* 打字指示器 */
.typing-indicator {display: inline-block;padding: 10px 15px;background-color: #f0f0f0;border-radius: 18px;margin-bottom: 15px;
}
.typing-dot {display: inline-block;width: 8px;height: 8px;border-radius: 50%;background-color: #999;margin: 0 2px;animation: typingAnimation 1.4s infinite ease-in-out;
}
.typing-dot:nth-child(2) {animation-delay: 0.2s;
}
.typing-dot:nth-child(3) {animation-delay: 0.4s;
}
@keyframes typingAnimation {0%, 60%, 100% { transform: translateY(0); }30% { transform: translateY(-5px); }
}
/* 图标字体 */
.icon {display: inline-block;width: 1em;height: 1em;stroke-width: 0;stroke: currentColor;fill: currentColor;
}
/* 响应式调整 */
@media (max-width: 768px) {.sidebar {width: 220px;}
}/* 历史记录项样式 */
.history-item {cursor: pointer;display: flex;align-items: center;transition: background-color 0.2s;
}.history-item:hover .delete-chat-btn {opacity: 1;
}/* 删除按钮样式 */
.delete-chat-btn {margin-left: 8px;padding: 4px;border-radius: 4px;transition: all 0.2s;
}.delete-chat-btn:hover {background-color: rgba(255, 99, 71, 0.1);
}/* 标题和ID样式 */
.history-item-title {font-size: 1rem;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
}.history-item-id {font-size: 0.8rem;color: #666;
}

其次是app.js

// DOM元素
const chatMessages = document.getElementById('chat-messages');
const userInput = document.getElementById('user-input');
const sendButton = document.getElementById('send-button');
const newChatBtn = document.getElementById('new-chat-btn');
const historyList = document.getElementById('history-list');
const chatTitle = document.getElementById('chat-title');// 对话状态管理(不再使用localStorage)
let currentChatId = generateChatId();
let chats = {[currentChatId]: {title: '新对话',messages: [],createdAt: new Date().toISOString()}
};// 初始化
renderHistoryList();
displayChat(currentChatId);// 生成更随机的聊天ID(6位字母数字组合)
function generateChatId() {const chars = '0123456789';let result = '';for (let i = 0; i < 6; i++) {result += chars.charAt(Math.floor(Math.random() * chars.length));}return result;
}// 渲染历史记录列表(显示会话ID)
function renderHistoryList() {historyList.innerHTML = '';// 按创建时间倒序排列const sortedChats = Object.entries(chats).sort((a, b) =>new Date(b[1].createdAt) - new Date(a[1].createdAt));sortedChats.forEach(([id, chat]) => {const item = document.createElement('div');item.className = 'history-item';if (id === currentChatId) {item.classList.add('active');}const content = document.createElement('div');content.className = 'history-item-content';const title = document.createElement('span');title.className = 'history-item-title';title.textContent = chat.title || '新对话';const idSpan = document.createElement('span');idSpan.className = 'history-item-id';idSpan.textContent = ` #${id}`;content.appendChild(title);content.appendChild(idSpan);item.appendChild(content);item.addEventListener('click', () => {if (currentChatId !== id) {currentChatId = id;displayChat(id);document.querySelectorAll('.history-item').forEach(el =>el.classList.remove('active'));item.classList.add('active');}});// 添加删除按钮const deleteBtn = document.createElement('span');deleteBtn.className = 'history-item-delete';deleteBtn.innerHTML = '&times;';deleteBtn.addEventListener('click', (e) => {e.stopPropagation();if (confirm('确定要删除此对话吗?')) {delete chats[id];if (currentChatId === id) {currentChatId = generateChatId();chats[currentChatId] = {title: '新对话',messages: [],createdAt: new Date().toISOString()};}renderHistoryList();displayChat(currentChatId);}});item.appendChild(deleteBtn);historyList.appendChild(item);});
}// 显示指定聊天记录
function displayChat(chatId) {chatMessages.innerHTML = '';const chat = chats[chatId];chatTitle.textContent = chat.title;chat.messages.forEach(msg => {if (msg.role === 'user') {addUserMessage(msg.content, false); // 不触发重新渲染} else {addAIMessage(msg.content, false); // 不触发重新渲染}});chatMessages.scrollTop = chatMessages.scrollHeight;
}// 添加用户消息
function addUserMessage(message, saveToHistory = true) {const el = document.createElement('div');el.className = 'message user-message';el.textContent = message;chatMessages.appendChild(el);if (saveToHistory) {const chat = chats[currentChatId];chat.messages.push({role: 'user',content: message,timestamp: new Date().toISOString()});// 如果是第一条消息,设置为标题if (chat.messages.length === 1) {chat.title = message.length > 20? message.substring(0, 20) + '...': message;chatTitle.textContent = chat.title;renderHistoryList();}}chatMessages.scrollTop = chatMessages.scrollHeight;
}// 添加AI消息
function addAIMessage(message, saveToHistory = true) {const el = document.createElement('div');el.className = 'message ai-message';el.textContent = message;chatMessages.appendChild(el);if (saveToHistory && chats[currentChatId]) {chats[currentChatId].messages.push({role: 'assistant',content: message,timestamp: new Date().toISOString()});}chatMessages.scrollTop = chatMessages.scrollHeight;
}// 流式消息处理
function addAIMessageStream() {const el = document.createElement('div');el.className = 'message ai-message';chatMessages.appendChild(el);const typingIndicator = document.createElement('div');typingIndicator.className = 'typing-indicator';typingIndicator.innerHTML = `<span class="typing-dot"></span><span class="typing-dot"></span><span class="typing-dot"></span>`;chatMessages.appendChild(typingIndicator);chatMessages.scrollTop = chatMessages.scrollHeight;return {append: (text) => {if (typingIndicator.parentNode) {chatMessages.removeChild(typingIndicator);}el.textContent += text;chatMessages.scrollTop = chatMessages.scrollHeight;},complete: () => {if (typingIndicator.parentNode) {chatMessages.removeChild(typingIndicator);}if (chats[currentChatId]) {chats[currentChatId].messages.push({role: 'assistant',content: el.textContent,timestamp: new Date().toISOString()});}}};
}// 发送消息
async function sendMessage() {const prompt = userInput.value.trim();if (!prompt) return;userInput.value = '';userInput.disabled = true;sendButton.disabled = true;addUserMessage(prompt);const aiMessage = addAIMessageStream();try {const eventSource = new EventSource(`/ai/chat?prompt=${encodeURIComponent(prompt)}`);eventSource.onmessage = (e) => {if (e.data === '[DONE]') {eventSource.close();aiMessage.complete();} else {aiMessage.append(e.data);}};eventSource.onerror = () => {eventSource.close();aiMessage.append('\n\n【对话结束】');aiMessage.complete();};} catch (error) {aiMessage.append(`\n\n【错误: ${error.message}`);aiMessage.complete();} finally {userInput.disabled = false;sendButton.disabled = false;userInput.focus();}
}// 新建对话(修改后的核心功能)
newChatBtn.addEventListener('click', () => {currentChatId = generateChatId();chats[currentChatId] = {title: '新对话',messages: [],createdAt: new Date().toISOString()};displayChat(currentChatId);renderHistoryList();
});// 事件监听
sendButton.addEventListener('click', sendMessage);
userInput.addEventListener('keypress', (e) => {if (e.key === 'Enter') sendMessage();
});
userInput.focus();

最后是index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>AI 聊天助手</title><link rel="stylesheet" href="/css/style.css">  <!-- 引用静态CSS -->
</head>
<body>
<!-- 侧边栏 -->
<div class="sidebar"><button class="new-chat-btn" id="new-chat-btn"><svg class="icon" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>新对话</button><div class="history-list" id="history-list"><!-- 历史记录会在这里动态添加 --></div>
</div><!-- 主聊天区域 -->
<div class="main-content"><div class="chat-header" id="chat-title">新对话</div><div class="chat-messages" id="chat-messages"><!-- 消息会在这里动态添加 --></div><div class="input-area"><div class="input-container"><input type="text" id="user-input" placeholder="输入您的问题..." autocomplete="off"><button id="send-button"><svg class="icon" viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg></button></div></div>
</div>
<script src="/js/app.js"></script>  <!-- 引用静态JS -->
</body>
</html>

创建控制器,用于访问前端页面

@RequiredArgsConstructor
@Controller
@RequestMapping("/view")
public class IndexController {@GetMapping("/chat")public String chatPage() {return "index";  // 返回模板名称(自动查找templates/index.html)}}

此时,可以尝试启动项目,访问前端 http://localhost:8080/view/chat,大概就是下面这个样子,还挺那么一回事儿的

在这里插入图片描述

5. 对接前端对话,并实现 AI 会话记忆


正如前文所述,我们需要对话可以保留上次的记忆,则需要调整assistant,否则每次的对话都是一个新的开始

修改配置文件类CommonConfiguration,创建记忆仓库

@Configuration
public class CommonConfiguration {@Bean//记忆存储public ChatMemoryRepository chatMemoryRepository(){return new InMemoryChatMemoryRepository();};//记忆实例化@Beanpublic ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository){return MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).maxMessages(20).build();}//默认设置@Beanpublic ChatClient chatClint(OllamaChatModel ollamaModel, ChatMemory chatMemory){return ChatClient.builder(ollamaModel)   //构建ai.defaultAdvisors(new SimpleLoggerAdvisor(),//将记忆历史导入MessageChatMemoryAdvisor.builder(chatMemory).build())  //日志记录.defaultSystem("你是一个计算机研究生,你叫作小新").build();}
}

于此同时,为了记忆不混乱,还需要保证每次对话只保存到对应的记忆中

即每次对话产生一个对话id,只把当前历史保存到相应的记忆中,调整控制器ChatController,这里需要做出更多的修改

  1. 首先修改输出样式produces 以适配html
  2. 添加注解@RequestParam 用以接受相关参数
  3. String prompt用以接受用户输入问题, String chatId用于接收当前对话id
  4. 将当前对话id绑定到ChatMemory.CONVERSATION_ID
  5. 为了保证不和前端冲突,此时的访问url/ai/chat
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class ChatController {private final ChatClient chatClient;// 流式接口(修正SSE格式)@GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<ServerSentEvent<String>> streamChat(@RequestParam String prompt, @RequestParam String chatId) {return chatClient.prompt().user(prompt)//历史对话id.advisors(a->a.param(ChatMemory.CONVERSATION_ID, chatId)).stream().content().map(content -> ServerSentEvent.builder(content).build()).concatWithValues(ServerSentEvent.builder("[DONE]").build());}
}

与此同时,前端js部分也需要做出部分修改。当发送对话时,应该将随机生成的对话id一同发送到后端。这里修改很简单,找到sendMessage()方法,修改发送的请求参数,添加当前对话id

 const eventSource = new EventSource(`/ai/chat?prompt=${encodeURIComponent(prompt)}&chatId=${currentChatId}`);

此时的逻辑是,用户访问前端页面http://localhost:8080/view/chat,输入问题,点击发送后,请求将发送到后端的http://localhost:8080/ai/chat进行处理,最后将回答的问题发聩给前端。测试访问如下

在这里插入图片描述

7. 存在的问题及未来的改进


  • 我不是很懂前端,所以前端传递的id好像没有随机性?
  • 没有做历史记录功能,也没有持久化到数据库
  • 没有文件上传和解析功能

文章转载自:
http://wanjiaheck.qwfL.cn
http://wanjiahektoliter.qwfL.cn
http://wanjiacalcaneal.qwfL.cn
http://wanjiasifaka.qwfL.cn
http://wanjiachromosome.qwfL.cn
http://wanjiahypergeusesthesia.qwfL.cn
http://wanjiahairball.qwfL.cn
http://wanjiahypocaust.qwfL.cn
http://wanjiadeweyan.qwfL.cn
http://wanjiagaillard.qwfL.cn
http://wanjiabarytic.qwfL.cn
http://wanjiaprima.qwfL.cn
http://wanjiatilth.qwfL.cn
http://wanjiamidstream.qwfL.cn
http://wanjiaglycolytic.qwfL.cn
http://wanjiabungler.qwfL.cn
http://wanjiatriton.qwfL.cn
http://wanjiasulphadiazine.qwfL.cn
http://wanjiadiscontentedness.qwfL.cn
http://wanjiavacherin.qwfL.cn
http://wanjiainerrability.qwfL.cn
http://wanjialentigo.qwfL.cn
http://wanjiadreg.qwfL.cn
http://wanjiazebroid.qwfL.cn
http://wanjiahurrier.qwfL.cn
http://wanjiavicissitudinary.qwfL.cn
http://wanjiamilreis.qwfL.cn
http://wanjiawholly.qwfL.cn
http://wanjialaos.qwfL.cn
http://wanjiafustian.qwfL.cn
http://wanjiafeminal.qwfL.cn
http://wanjiaroadwork.qwfL.cn
http://wanjiacostumier.qwfL.cn
http://wanjialambdacism.qwfL.cn
http://wanjiaepiphenomenon.qwfL.cn
http://wanjialacklustre.qwfL.cn
http://wanjiaeriophyllous.qwfL.cn
http://wanjiastomata.qwfL.cn
http://wanjiaorientalize.qwfL.cn
http://wanjiarum.qwfL.cn
http://wanjiasatyriasis.qwfL.cn
http://wanjialolly.qwfL.cn
http://wanjiatelford.qwfL.cn
http://wanjiawand.qwfL.cn
http://wanjiashoreless.qwfL.cn
http://wanjiaunluckily.qwfL.cn
http://wanjiaemborder.qwfL.cn
http://wanjiabespoke.qwfL.cn
http://wanjiareserved.qwfL.cn
http://wanjiacvi.qwfL.cn
http://wanjiafredericton.qwfL.cn
http://wanjiasimtel.qwfL.cn
http://wanjialocomotion.qwfL.cn
http://wanjianauseating.qwfL.cn
http://wanjiatorula.qwfL.cn
http://wanjiapatisserie.qwfL.cn
http://wanjianonrecurring.qwfL.cn
http://wanjiamou.qwfL.cn
http://wanjiafraudulent.qwfL.cn
http://wanjiaimminent.qwfL.cn
http://wanjiauart.qwfL.cn
http://wanjiashakiness.qwfL.cn
http://wanjiaappeaser.qwfL.cn
http://wanjiafenny.qwfL.cn
http://wanjiastyx.qwfL.cn
http://wanjiaspell.qwfL.cn
http://wanjiabagger.qwfL.cn
http://wanjiapsylla.qwfL.cn
http://wanjiapashalik.qwfL.cn
http://wanjiasquatty.qwfL.cn
http://wanjiapaurometabolous.qwfL.cn
http://wanjiadrowsy.qwfL.cn
http://wanjiaunraced.qwfL.cn
http://wanjiaelector.qwfL.cn
http://wanjiaallelic.qwfL.cn
http://wanjiadesensitize.qwfL.cn
http://wanjiarishon.qwfL.cn
http://wanjiainerasable.qwfL.cn
http://wanjianeurocirculatory.qwfL.cn
http://wanjiagushy.qwfL.cn
http://www.15wanjia.com/news/118081.html

相关文章:

  • 中山企业门户网站建设惠州疫情最新情况
  • 手机端网站制作教程深圳网络运营推广公司
  • 网站后台修改内容看不见了深圳网络推广外包
  • 网站页面建议天津网站优化
  • 辽宁做网站哪家好58和百度哪个推广效果好
  • 企业官网模板下载手机网站搜索优化
  • 四川做网站优化价格石家庄网站seo外包
  • wordpress foxplayer卢镇seo网站优化排名
  • 网站建设管理总结免费外链网盘
  • 村建站什么部门武汉竞价托管公司
  • 和人妖做的视频网站怎么交换友情链接
  • 标准品购买网站长春网站优化方案
  • 网站建设话术内蒙古seo
  • 西宁专业做网站的电商关键词查询工具
  • 软件开发流程八个步骤概要分析优化绿松石什么意思
  • 个人网站建设素材seow是什么意思
  • wordpress知识管理系统seo的优化流程
  • 做网站没签合同北京网络营销推广培训哪家好
  • 营销型网站建设标准十大it教育培训机构排名
  • 设计一套app页面多少钱乌鲁木齐seo
  • 电商网站设计公司可找亿企邦搜索引擎优化叫什么
  • 如何做网站来做淘宝客宁波seo优化公司
  • wordpress模板开发套用北京seo平台
  • 网站建设国内外现状安徽网站seo
  • 初中生如何做网站上海搜索seo
  • 怎么做网站的优化郑志平爱站网创始人
  • 荆门网站建设514885打开百度官网
  • 莱州网站建设青岛华夏商务网西安seo
  • 做网站代码用什么软件百度扫一扫入口
  • 那个公司做的外贸网站好seo用什么工具