使用Spring Gateway为对象存储系统MinIo和kkFileView文档预览增加登录验证

文章目录

    • 1、kkfileview下载部署
      • 1.1、安装包部署运行
        • 1.1.1、物理机或虚拟机上运行
        • 1.1.2、Docker容器环境环境运行
      • 1.2、接入说明
    • 2、使用Spring Gateway增加登录认证
      • 2.1、网关实现代码
      • 2.2、文件服务实现代码
      • 2.3、Demo运行效果

官网介绍:kkFileView为文件文档在线预览解决方案,该项目使用流行的spring boot搭建,易上手和部署,基本支持主流办公文档的在线预览,如doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,图片,视频,音频等等。

前一文章《开源对象存储系统MinIo部署配置与SpringBoot客户端整合访问》已经介绍MinIo部署和SpringBoot的基本整合。
本文介绍kkFileView的部署,并可以预览MiniIo存储的文档。
kkFileView没有权限认证功能,本文使用Spring Gateway为kkFileView增加登录才能预览文档的功能。

1、kkfileview下载部署

官网:https://kkview.cn
码云源码:https://gitee.com/kekingcn/file-online-preview

1.1、安装包部署运行

1.1.1、物理机或虚拟机上运行

自v4.1.0 版本开始 kkFileView 不再免费提供 Windows 和 Linux 的发行安装包了,可以自己基于源码编译打包运行。
本文测试用的4.0.0版本来自文章:https://blog.csdn.net/qq_37284798/article/details/129377354提供。
解压kkFileView-x.x.x文件(Windows用.zip包,Linux/MacOS用.tar.gz包)
打开解压后文件夹的bin目录,运行startup脚本(Windows下以管理员身份运行startup.bat,Linux以root用户运行startup.sh)
浏览器访问本机8012端口 http://127.0.0.1:8012 即可看到项目演示用首页

1.1.2、Docker容器环境环境运行

使用docker部署

# 拉取镜像 
# docker中央仓库https://hub.docker.com/r/keking/kkfileview,仓库最新版本只有4.1.0版本;Gitee源码最新版本为4.3.0
docker pull keking/kkfileview:4.1.0# 运行
docker run -it -p 8012:8012 keking/kkfileview:4.1.0

浏览器访问容器8012端口 http://127.0.0.1:8012 即可看到项目演示用首页

使用docker-compose部署

# 配置文件docker-compose.yml
version: '3'
services:web:restart: alwayscontainer_name: kkfileviewimage: keking/kkfileview:4.1.0ports:- "8012:8012"privileged: truevolumes:- "./config/application.properties:/opt/kkFileView-4.1.0/config/application.properties"- "./log:/opt/kkFileView-4.1.0/log"## 启动命令
docker-compose up -d
## 关闭
docker-compose down

kkfileview官方参考配置application.properties内容

#######################################不可动态配置,需要重启生效#######################################
server.port = ${KK_SERVER_PORT:8012}
#server.servlet.context-path= ${KK_CONTEXT_PATH:/}
server.servlet.context-path= /preview
server.servlet.encoding.charset = utf-8
#文件上传限制
spring.servlet.multipart.max-file-size=500MB
spring.servlet.multipart.max-request-size=500MB
## Freemarker 配置
spring.freemarker.template-loader-path = classpath:/web/
spring.freemarker.cache = false
spring.freemarker.charset = UTF-8
spring.freemarker.check-template-location = true
spring.freemarker.content-type = text/html
spring.freemarker.expose-request-attributes = true
spring.freemarker.expose-session-attributes = true
spring.freemarker.request-context-attribute = request
spring.freemarker.suffix = .ftl# office-plugin
## office转换服务的进程数,默认开启两个进程
office.plugin.server.ports = 2001,2002
## office 转换服务 task 超时时间,默认五分钟
office.plugin.task.timeout = 5m#预览生成资源路径(默认为打包根路径下的file目录下)
#file.dir = D:\\kkFileview\\
file.dir = ${KK_FILE_DIR:default}#允许预览的本地文件夹 默认不允许任何本地文件被预览
#file.dir = D:\\kkFileview\\
local.preview.dir = ${KK_LOCAL_PREVIEW_DIR:default}#openoffice home路径
#office.home = C:\\Program Files (x86)\\OpenOffice 4
office.home = ${KK_OFFICE_HOME:default}#缓存实现类型,不配默认为内嵌RocksDB(type = default)实现,可配置为redis(type = redis)实现(需要配置spring.redisson.address等参数)和 JDK 内置对象实现(type = jdk),
cache.type =  ${KK_CACHE_TYPE:jdk}
#redis连接,只有当cache.type = redis时才有用
spring.redisson.address = ${KK_SPRING_REDISSON_ADDRESS:127.0.0.1:6379}
spring.redisson.password = ${KK_SPRING_REDISSON_PASSWORD:}
#缓存是否自动清理 true 为开启,注释掉或其他值都为关闭
cache.clean.enabled = ${KK_CACHE_CLEAN_ENABLED:true}
#缓存自动清理时间,cache.clean.enabled = true时才有用,cron表达式,基于Quartz cron
cache.clean.cron = ${KK_CACHE_CLEAN_CRON:0 0 3 * * ?}#######################################可在运行时动态配置#######################################
#提供预览服务的地址,默认从请求url读,如果使用nginx等反向代理,需要手动设置
#base.url = https://file.keking.cn
#base.url = ${KK_BASE_URL:default}
base.url = http://127.0.0.1:8012/preview#信任站点,多个用','隔开,设置了之后,会限制只能预览来自信任站点列表的文件,默认不限制
#trust.host = file.keking.cn,kkfileview.keking.cn
trust.host = ${KK_TRUST_HOST:default}#是否启用缓存
cache.enabled = ${KK_CACHE_ENABLED:true}#文本类型,默认如下,可自定义添加
simText = ${KK_SIMTEXT:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd}
#多媒体类型,默认如下,可自定义添加
media = ${KK_MEDIA:mp3,wav,mp4,flv}
#是否开启多媒体类型转视频格式转换,目前可转换视频格式有:avi,mov,wmv,3gp,rm
#请谨慎开启此功能,建议异步调用添加到处理队列,并且增加任务队列处理线程,防止视频转换占用完线程资源,转换比较耗费时间,并且控制了只能串行处理转换任务
media.convert.disable = ${KK_MEDIA_CONVERT_DISABLE:false}
#支持转换的视频类型
convertMedias = ${KK_CONVERTMEDIAS:avi,mov,wmv,mkv,3gp,rm}
#office类型文档(word ppt)样式,默认为图片(image),可配置为pdf(预览时也有按钮切换)
office.preview.type = ${KK_OFFICE_PREVIEW_TYPE:image}
#是否关闭office预览切换开关,默认为false,可配置为true关闭
office.preview.switch.disabled = ${KK_OFFICE_PREVIEW_SWITCH_DISABLED:false}#是否禁止演示模式
pdf.presentationMode.disable = ${KK_PDF_PRESENTATION_MODE_DISABLE:true}
#是否禁止打开文件
pdf.openFile.disable = ${KK_PDF_OPEN_FILE_DISABLE:true}
#是否禁止打印转换生成的pdf文件
pdf.print.disable = ${KK_PDF_PRINT_DISABLE:true}
#是否禁止下载转换生成的pdf文件
pdf.download.disable = ${KK_PDF_DOWNLOAD_DISABLE:true}
#是否禁止bookmark
pdf.bookmark.disable = ${KK_PDF_BOOKMARK_DISABLE:true}
#是否禁用首页文件上传
file.upload.disable = ${KK_FILE_UPLOAD_ENABLED:false}#预览源为FTP时 FTP用户名,可在ftp url后面加参数ftp.username=ftpuser指定,不指定默认用配置的
ftp.username = ${KK_FTP_USERNAME:ftpuser}
#预览源为FTP时 FTP密码,可在ftp url后面加参数ftp.password=123456指定,不指定默认用配置的
ftp.password = ${KK_FTP_PASSWORD:123456}
#预览源为FTP时, FTP连接默认ControlEncoding(根据FTP服务器操作系统选择,Linux一般为UTF-8,Windows一般为GBK),可在ftp url后面加参数ftp.control.encoding=UTF-8指定,不指定默认用配置的
ftp.control.encoding = ${KK_FTP_CONTROL_ENCODING:UTF-8}#水印内容
#例:watermark.txt = ${WATERMARK_TXT:凯京科技内部文件,严禁外泄}
#如需取消水印,内容设置为空即可,例:watermark.txt = ${WATERMARK_TXT:}
watermark.txt = ${WATERMARK_TXT:}
#水印x轴间隔
watermark.x.space = ${WATERMARK_X_SPACE:10}
#水印y轴间隔
watermark.y.space = ${WATERMARK_Y_SPACE:10}
#水印字体
watermark.font = ${WATERMARK_FONT:微软雅黑}
#水印字体大小
watermark.fontsize = ${WATERMARK_FONTSIZE:18px}
#水印字体颜色
watermark.color = ${WATERMARK_COLOR:black}
#水印透明度,要求设置在大于等于0.005,小于1
watermark.alpha = ${WATERMARK_ALPHA:0.2}
#水印宽度
watermark.width = ${WATERMARK_WIDTH:180}
#水印高度
watermark.height = ${WATERMARK_HEIGHT:80}
#水印倾斜度数,要求设置在大于等于0,小于90
watermark.angle = ${WATERMARK_ANGLE:10}#Tif类型图片浏览模式:tif(利用前端js插件浏览);jpg(转换为jpg后前端显示);pdf(转换为pdf后显示,便于打印)
tif.preview.type = ${KK_TIF_PREVIEW_TYPE:tif}

1.2、接入说明

参考自官方Demo接入说明:http://127.0.0.1:8012/index
如果你的项目需要接入文件预览项目,达到对docx、excel、ppt、jpg等文件的预览效果,那么通过在你的项目中加入下面的代码就可以成功实现:

var url = 'http://127.0.0.1:8080/file/test.txt'; //要预览文件的访问地址
window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(base64Encode(url)));

新增多图片同时预览功能,接口如下:

var fileUrl =url1+'|'+url2;//多url使用'|'字符隔开
window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(base64Encode(fileUrl)));

2、使用Spring Gateway增加登录认证

2.1、网关实现代码

Spring Gateway使用前文的例子:Spring Cloud 2022.x版本使用gateway和nacos实现动态路由和负载均衡。
增加一个全局过滤器类FileViewFilter.java,检查用户登录cookie是否存在。

package com.penngo.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;@Component
public class FileViewFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {try{ServerHttpRequest request = exchange.getRequest();HttpHeaders headers = request.getHeaders();ServerHttpResponse response = exchange.getResponse();MultiValueMap<String, HttpCookie> cookieMap = request.getCookies();String currentUrl = request.getURI().getPath();if(currentUrl.startsWith("/preview")){boolean isForbid = true;if(cookieMap != null ){List<HttpCookie> cookies = cookieMap.get("token");if(cookies != null){for(HttpCookie cookie:cookies){if(cookie.getName().equals("token") && cookie.getValue().equals("test123456")){isForbid = false;}}}}if(isForbid == false){return chain.filter(exchange);}else{DataBuffer dataBuffer = response.bufferFactory().wrap("No permission, please login first!".getBytes());response.setStatusCode(HttpStatus.OK);return response.writeWith(Flux.just(dataBuffer));}}}catch(Exception e){e.printStackTrace();}return chain.filter(exchange);}@Overridepublic int getOrder() {return -200;}
}

Nacos配置:

spring:cloud:gateway:routes:- id: previewiduri: http://192.168.245.139:8012/predicates:- Path=/preview/**- id: fileiduri: http://127.0.0.1:8080/predicates:- Path=/index/**filters:- StripPrefix=1

2.2、文件服务实现代码

文档预览服务基于开源对象存储系统minio部署配置与SpringBoot客户端整合访问上修改。
pom.xml增加依赖包:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

application.yml增加thymeleaf配置:

server:port: 8080servlet:encoding:force: truecharset: UTF-8enabled: truetomcat:uri-encoding: UTF-8thymeleaf:mode: HTMLcache: falseencoding: UTF-8

FileController增加方法:

package com.penngo.example.controlleer;import com.penngo.example.component.MinioUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;import java.io.File;
import java.io.FileInputStream;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;@Controller
public class FileController {@Resourceprivate MinioUtils minioUtils;@GetMapping("/fileListView")public String fileListView(HttpServletRequest request, Model model){Map<String, String> files =  minioUtils.getFileList();StringBuffer sff = new StringBuffer();Base64.Encoder encoder = Base64.getEncoder();Map<String, String> fileUrls =  new HashMap<>();files.forEach((k,v)->{String url = encoder.encodeToString(v.getBytes());url = "http://127.0.0.1:9090/preview/onlinePreview?url=" + URLEncoder.encode(url);fileUrls.put(k, url);});model.addAttribute("files",fileUrls);return "/index/fileList";}@RequestMapping("/login")public String login(HttpServletRequest request) {return "/index/login";}@RequestMapping( value ="/save", method = RequestMethod.POST)public String save(HttpServletRequest request, HttpServletResponse response, Model model, @RequestParam String user, @RequestParam String passwd){model.addAttribute("stat", "登录失败");if(user.equals("admin") && passwd.equals("123456")){model.addAttribute("stat", "登录成功");Cookie[] Cookies =  request.getCookies();Cookie cookie = new Cookie("token", "test123456");cookie.setPath("/");cookie.setMaxAge(60 * 60 * 24);response.addCookie(cookie);}return "/index/login";}@RequestMapping( value ="/logout", method = RequestMethod.GET)public String logout(HttpServletRequest request, HttpServletResponse response, Model model){Map<String, String> data = new HashMap<>();model.addAttribute("stat", "退出成功");Cookie cookie = new Cookie("token", "");cookie.setPath("/");cookie.setMaxAge(0);response.addCookie(cookie);return "/index/logout";}
}

resources\templates\index\login.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<span th:text="${stat}"></span>
<form action="./save" method="post">用户名: <input type="text" name="user" value=""><br>密 码: <input type="text" name="passwd" value=""><br><input type="submit" value="提交">
</form>
</body>
</html>

模板文件
fileList.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<table ><tr th:each="file,url:${files}"><td style="white-space:nowrap;" th:text="${file.key}"></td><td ><a target="_blank" th:href="${file.value}"><span th:text="${file.value}"></span></a></td></tr>
</table>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<span th:text="${stat}"></span>
<form action="./save" method="post">用户名: <input type="text" name="user" value=""><br>密 码: <input type="text" name="passwd" value=""><br><input type="submit" value="提交">
</form>
</body>
</html>

2.3、Demo运行效果

文件浏览列表,例子只放了一个office文档
访问文件列表
在这里插入图片描述
未登录前访问文档,提示“没有权限,请先登录”
在这里插入图片描述
登录
在这里插入图片描述

在这里插入图片描述
登录后再访问文档地址,已能成功预览docx文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/132522.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

易点易动固定资产管理系统:为企业提供高效资产管理的必备利器

在如今竞争激烈的商业环境中&#xff0c;企业对于固定资产的管理显得尤为重要。然而&#xff0c;传统的手工管理方式已经无法满足企业对于高效、准确、智能化管理的需求。因此&#xff0c;引入一款先进的固定资产管理系统是必不可少的。易点易动固定资产管理系统作为一款领先的…

C#自定义控件组件实现Chart图表(多Y轴,选择图例加粗,选择放大,缩放,点击查看信息等功能)

先看看ECharts的效果 C# 工具箱里的Chart控件就不演示了,很多效果没办法做出来,做出来效果也很不理想。所以,需要自己去手动实现工具箱里的Chart没办法实现的效果; 先看看实现后的效果 绑定数据 点击图表 点击右侧图例加粗 选择放大 右键 点击缩小,恢复

重建大师提交空三后引擎状态是等待,怎么开启?

答&#xff1a;图片中这是在自由网空三阶段&#xff0c;整个AT都是等待中&#xff0c;可以修改任务目录和监控目录看一下&#xff0c;先设置引擎&#xff0c;再提交空三。

建站系列(三)--- 网络协议

目录 相关系列文章前言一、定义二、术语简介三、协议的组成要素四、网络层次划分五、常见网络协议划分六、常用协议介绍&#xff08;一&#xff09;TCP/IP&#xff08;二&#xff09;HTTP协议&#xff08;超文本传输协议&#xff09;&#xff08;三&#xff09;SSH协议 相关系列…

DC/DC开关电源学习笔记(五)开关电源的主要技术指标

(五)开关电源的主要技术指标 1.输入参数2.输出参数3.效率4.电压调整率和负载调整率5.动态特性:负载突变时输出电压的变化6.电源启动时间(Set-Up Time)与保持时间(Hold-Up Time)1.输入参数 输入电压大小,交流还是直流,相数,频率等。 2.输出参数 输出功率,输出电压,输出…

算法-26. 删除有序数组中的重复项-⭐

给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff0c;你需要做…

2023-9-10 集合-Nim游戏

题目链接&#xff1a;集合-Nim游戏 #include <iostream> #include <cstring> #include <algorithm> #include <unordered_set>using namespace std;const int N 110, M 10010;int n, m; int s[N], f[M];int sg(int x) {if(f[x] ! -1) return f[x];//…

NeuroFlash:AI文章写作与生成工具

【产品介绍 ​ 】 名称 NeuroFlash 上线时间 2015 具体描述 Neuroflash是一款基于人工智能的文本和图像生成器&#xff0c;可以帮助用户快速创建高质量的内容。Neuroflash拥有超过100种短文和长文的文本类型&#xff0c;涵盖了各种营销场景和需求。只需要输入简单的指示&#…

云计算与虚拟化

一、概念 什么是云计算&#xff1f; 云计算&#xff08;cloud computing&#xff09;是分布式计算的一种&#xff0c;指的是通过网络“云”将巨大的数据计算处理程序分解成无数个小程序&#xff0c;然后&#xff0c;通过多部服务器组成的系统进行处理和分析这些小程序得到结果…

【LeetCode】210. 课程表 II——拓扑排序

题目链接&#xff1a;210. 课程表 II 题目描述&#xff1a; 现在你总共有 numCourses 门课需要选&#xff0c;记为 0 到 numCourses - 1。给你一个数组 prerequisites &#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示在选修课程 ai 前 必须 先选修 bi 。 例如…

gmssl v2 用 dgst 命令通过 sm2 签名出的结果,在别的工具上无法验签的问题分析

结论 通过分析发现&#xff0c;导致问题的原因是&#xff1a;gmssl v2 调用的算法不是 sm2 算法。 分析详情 具体情况如下所述 在 gmssl 调用 pkey_ec_init 函数时&#xff0c;默认会把 ec_scheme 设置为 NID_secg_scheme 签名的过程中会调用 pkey_ec_sign 函数&#xff0c…

29.Xaml TreeView控件---->树形控件,节点的形式显示数据

1.运行效果 2.运行源码 a.Xaml源码 <Window x:Class="testView.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mic…

删除linux(centos7)系统自带的open jdk,安装配置jdk环境

查看jdk版本 安装的linux自带jdk8版本&#xff0c;我们不用自带的。 安装jdk步骤 1、下载 下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads 2、创建目录 创建文件夹&#xff0c;用来部署JDK&#xff0c;将JDK安装部署到&#xff1a;/export/se…

云原生Kubernetes:pod资源管理与配置

目录 一、理论 1.pod 2.pod容器分类 3.镜像拉取策略 4.pod 的重启策略 二、实验 1.Pod容器的分类 2.镜像拉取策略 三、问题 1.apiVersion 报错 2.pod v1版本资源未注册 3.格式错误 4.取行显示指定pod信息 四、总结 一、理论 1.pod (1) 概念 Pod是kubernetes中…

Matlab学习-自定义函数

Matlab学习-自定义函数 常用自定义函数 文章目录 Matlab学习-自定义函数1. 打印时间2. 计算统计参数3. 画图函数 1. 打印时间 function result calculate_time(time)% Function describe : calculate time% Input : time:N*1% Output : result.hour/min/sec hour/min/sec…

中断子系统 --- 硬件相关层

中断控制器驱动 由于linux支持中断控制器的级联&#xff0c;因此多个中断控制器就可能包含相同的硬件中断号。为了可以通过中断号唯一地标识一个中断&#xff0c;linux引入了irq domain机制以实现将硬件中断号映射为全局唯一的逻辑中断号。 Hwirq映射到irq 每个中断控制器都对…

Day59|leetcode 503.下一个更大元素II、42. 接雨水

leetcode 503.下一个更大元素II 题目链接&#xff1a;503. 下一个更大元素 II - 力扣&#xff08;LeetCode&#xff09; 视频链接&#xff1a;单调栈&#xff0c;成环了可怎么办&#xff1f;LeetCode&#xff1a;503.下一个更大元素II_哔哩哔哩_bilibili 题目概述 给定一个循环…

HDMI 直通 ILA 调试实验

FPGA教程学习 第十四章 HDMI 直通 ILA 调试实验 文章目录 FPGA教程学习前言实验原理程序设计实验过程实验尝试总结TODO 前言 HDMI 输入直通到 HDMI 输出的显示&#xff0c;完成一个简单的 HDMI 输入输出检测。 实验原理 开发板 HDMI 输出接口芯片使用 ADV7511&#xff0c;HD…

使用Jconsole监控JMX

使用Jconsole监控 Jconsole启动 直接本地启动jdk工具 本地连接 本地启动java应用直接点击就可以连接 本地远程连接 idea启动服务连接 配置运行配置 配置远程参数 -Djava.rmi.server.hostname127.0.0.1 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxrem…

【搭建私人图床】本地PHP搭建简单Imagewheel云图床,在外远程访问

文章目录 1.前言2. Imagewheel网站搭建2.1. Imagewheel下载和安装2.2. Imagewheel网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…