乐于分享
好东西不私藏

SpringBoot+OnlyOffice:优雅实现在线 Word 编辑、转化、保存等功能

SpringBoot+OnlyOffice:优雅实现在线 Word 编辑、转化、保存等功能

前言

最近有个项目需求是实现前端页面可以对word文档进行编辑,并且可以进行保存,于是一顿搜索,找到开源第三方onlyoffice,实际上onlyOffice有很多功能,例如文档转化、多人协同编辑文档、文档打印等,我们只用到了文档编辑功能。

1、onlyoffice的部署

部署分为docker部署方式和本地直接安装的方式,比较两种部署方式,docker是比较简单的一种,因为只要拉取相关镜像,然后启动时配置好对应的配置文件即可。

由于搜索的时候先看到的是linux本地部署,所以采用了第二种方式,下面我将给出两个参考博客:

docker的方式:(我未进行尝试,对于是否能成功是不知的)

https://blog.csdn.net/wangchange/article/details/140185623

ubuntu部署方式:(我按照这个方式走下来是可以走通的)

https://blog.csdn.net/qq_36437991/article/details/139859247

2、代码逻辑开发

前端使用的element框架vue版本,后端采用springboot

2.1、前端代码

参考官方文档API

https://api.onlyoffice.com/docs/docs-api/get-started/basic-concepts/

参考文档

https://api.onlyoffice.com/docs/docs-api/usage-api/advanced-parameters/

记得添加下面的js文件

<div id="placeholder"></div><script type="text/javascript" src="https://documentserver/web-apps/apps/api/documents/api.js"></script>

记得将documentserver替换为部署onlyoffice的地址。

const config = {    document: {      mode: 'edit',      fileType: 'docx',      key: String( Math.floor(Math.random() * 10000)),      title: route.query.name + '.docx',      url: import.meta.env.VITE_APP_API_URL+`/getFile/${route.query.id}`,      permissions: {          comment: true,          download: true,          modifyContentControl: true,          modifyFilter: true,          edit: true,          fillForms: true,          review: true,      },  },    documentType: 'word',    editorConfig: {      user: {        id: 'liu',        name: 'liu',      },      // 隐藏插件菜单      customization: {        plugins: false,        forcesave: true,      },      lang: 'zh',      // callbackUrl: `${import.meta.env.VITE_APP_API_URL} +'/callback' `,      callbackUrl: import.meta.env.VITE_APP_API_URL+`/callback`,    },    height: '100%',    width: '100%',  }newwindow.DocsAPI.DocEditor('onlyoffice', config)

其中import.meta.env.VITE_APP_API_URL为你实际的后端地址,http:ip:端口号/访问路径,例如我们就是:http:192.168.123.123:8089/getFile/12,其中12为会议号,用于得到文件地址。

其中import.meta.env.VITE_APP_API_URL+/callback为回调函数,即文档有什么操作后,都会通过这个函数进行回调,例如:编辑保存操作。

2.2、后端代码

pom依赖

<!-- httpclient start --><dependency>    <groupId>org.apache.httpcomponents</groupId>    <artifactId>httpclient</artifactId></dependency><dependency>    <groupId>org.apache.httpcomponents</groupId>    <artifactId>httpmime</artifactId></dependency>package com.ruoyi.web.controller.meetingminutes.onlyoffice;/** * @Author 不要有情绪的  ljy * @Date 2024/10/31 20:26 * @Description: */import com.ruoyi.system.domain.MeetingTable;import com.ruoyi.system.service.IMeetingTableService;import com.ruoyi.web.controller.meetingminutes.utils.HttpsKitWithProxyAuth;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import lombok.Getter;import lombok.Setter;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.MediaType;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletResponse;import java.io.*;import java.net.URISyntaxException;import java.net.URLEncoder;import java.util.Collections;/** * */@Api(value = "OnlyOfficeController")@RestControllerpublicclass OnlyOfficeController {    @Autowired    private IMeetingTableService meetingTableService;    //这里仅写死路径测试    //    private String meetingMinutesFilePath = "C:\\Users\\qrs-ljy\\Desktop\\王勋\\c1f15837-d8b4-4380-8161-b85e970ad174\\123435_会议纪要(公开).docx"; //这里仅写死路径测试    private String meetingMinutesFilePath;    /**     * 传入参数 会议id,得到会议纪要文件流,并进行打开     *     * @param response     * @param meeting_id     * @return     * @throws IOException     */    @ApiOperation(value = "OnlyOffice")    @GetMapping("/getFile/{meeting_id}")    public ResponseEntity<byte[]> getFile(HttpServletResponse response, @PathVariable Long meeting_id) throws IOException {        MeetingTable meetingTable = meetingTableService.selectMeetingTableById(meeting_id);        meetingMinutesFilePath = meetingTable.getMeetingMinutesFilePath();if (meetingMinutesFilePath == null || "".equals(meetingMinutesFilePath)) {            returnnull;   //当会议纪要文件为空的时候,就返回null        }        File file = new File(meetingMinutesFilePath);        FileInputStream fileInputStream = null;        InputStream fis = null;        try {            fileInputStream = new FileInputStream(file);            fis = new BufferedInputStream(fileInputStream);            byte[] buffer = newbyte[fis.available()];            fis.read(buffer);            fis.close();            HttpHeaders headers = new HttpHeaders();            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);            // 替换为实际的文档名称            headers.setContentDispositionFormData("attachment", URLEncoder.encode(file.getName(), "UTF-8"));            returnnew ResponseEntity<>(buffer, headers, HttpStatus.OK);        } catch (Exception e) {            thrownew RuntimeException("e -> ", e);        } finally {            try {if (fis != null) fis.close();            } catch (Exception e) {            }            try {if (fileInputStream != null) fileInputStream.close();            } catch (Exception e) {            }        }    }    @CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS})    @PostMapping("/callback")    public ResponseEntity<Object> handleCallback(@RequestBody CallbackData callbackData) {        //状态监听        //参见https://api.onlyoffice.com/editors/callback        Integer status = callbackData.getStatus();        switch (status) {            case1: {                //document is being edited  文档已经被编辑break;            }            case2: {                //document is ready for saving,文档已准备好保存                System.out.println("document is ready for saving");                String url = callbackData.getUrl();                try {                    saveFile(url); //保存文件                } catch (Exception e) {                    System.out.println("保存文件异常");                }                System.out.println("save success.");break;            }            case3: {                //document saving error has occurred,保存出错                System.out.println("document saving error has occurred,保存出错");break;            }            case4: {                //document is closed with no changes,未保存退出                System.out.println("document is closed with no changes,未保存退出");break;            }            case6: {                //document is being edited, but the current document state is saved,编辑保存                String url = callbackData.getUrl();                try {                    saveFile(url); //保存文件                } catch (Exception e) {                    System.out.println("保存文件异常");                }                System.out.println("save success.");            }            case7: {                //error has occurred while force saving the document. 强制保存文档出错                System.out.println("error has occurred while force saving the document. 强制保存文档出错");            }            default: {            }        }        // 返回响应return ResponseEntity.<Object>ok(Collections.singletonMap("error", 0));    }    public void saveFile(String downloadUrl) throws URISyntaxException, IOException {        HttpsKitWithProxyAuth.downloadFile(downloadUrl, meetingMinutesFilePath);    }    @Setter    @Getter    publicstaticclass CallbackData {        /**         * 用户与文档的交互状态。0:用户断开与文档共同编辑的连接;1:新用户连接到文档共同编辑;2:用户单击强制保存按钮         *///        @IsArray()//        actions?:IActions[] =null;        /**         * 字段已在 4.2 后版本废弃,请使用 history 代替         */        Object changeshistory;        /**         * 文档变更的历史记录,仅当 status 等于 2 或者 3 时该字段才有值。其中的 serverVersion 字段也是 refreshHistory 方法的入参         */        Object history;        /**         * 文档编辑的元数据信息,用来跟踪显示文档更改记录,仅当 status 等于 2 或者 2 时该字段才有值。该字段也是 setHistoryData(显示与特定文档版本对应的更改,类似 Git 历史记录)方法的入参         */        String changesurl;        /**         * url 字段下载的文档扩展名,文件类型默认为 OOXML 格式,如果启用了 assemblyFormatAsOrigin(https://api.onlyoffice.com/editors/save#assemblyFormatAsOrigin) 服务器设置则文件以原始格式保存         */        String filetype;        /**         * 文档强制保存类型。0:对命令服务(https://api.onlyoffice.com/editors/command/forcesave)执行强制保存;1:每次保存完成时都会执行强制保存请求,仅设置 forcesave 等于 true 时生效;2:强制保存请求由计时器使用服务器中的设置执行。该字段仅 status 等于 7 或者 7 时才有值         */        Integer forcesavetype;        /**         * 文档标识符,类似 id,在 Onlyoffice 服务内部唯一         */        String key;        /**         * 文档状态。1:文档编辑中;2:文档已准备好保存;3:文档保存出错;4:文档没有变化无需保存;6:正在编辑文档,但保存了当前文档状态;7:强制保存文档出错         */        Integer status;        /**         * 已编辑文档的链接,可以通过它下载到最新的文档,仅当 status 等于 2、3、6 或 7 时该字段才有值         */        String url;        /**         * 自定义参数,对应指令服务的 userdata 字段         */        Object userdata;        /**         * 打开文档进行编辑的用户标识列表,当文档被修改时,该字段将返回最后编辑文档的用户标识符,当 status 字段等于 2 或者 6 时有值         */        String[] users;        /**         * 最近保存时间         */        String lastsave;        /**         * 加密令牌         */        String token;    }}

代码中使用了其他类,这儿贴出(我也是参考的别人的博客,后面会给出参考链接)

package com.ruoyi.web.controller.meetingminutes.utils;/** * @Author 不要有情绪的  ljy * @Date 2024/10/31 20:34 * @Description: */import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InterruptedIOException;import java.net.Authenticator;import java.net.InetSocketAddress;import java.net.MalformedURLException;import java.net.PasswordAuthentication;import java.net.Proxy;import java.net.Socket;import java.net.UnknownHostException;import java.security.KeyManagementException;import java.security.KeyStoreException;import java.security.NoSuchAlgorithmException;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.TimerTask;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLException;import javax.net.ssl.SSLHandshakeException;import org.apache.commons.codec.CharEncoding;import org.apache.commons.io.IOUtils;import org.apache.http.Consts;import org.apache.http.HttpEntity;import org.apache.http.HttpEntityEnclosingRequest;import org.apache.http.HttpHost;import org.apache.http.HttpRequest;import org.apache.http.NameValuePair;import org.apache.http.NoHttpResponseException;import org.apache.http.auth.AUTH;import org.apache.http.auth.AuthState;import org.apache.http.auth.MalformedChallengeException;import org.apache.http.auth.UsernamePasswordCredentials;import org.apache.http.client.HttpRequestRetryHandler;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.client.methods.HttpPut;import org.apache.http.client.protocol.HttpClientContext;import org.apache.http.config.Registry;import org.apache.http.config.RegistryBuilder;import org.apache.http.conn.ConnectTimeoutException;import org.apache.http.conn.socket.ConnectionSocketFactory;import org.apache.http.conn.socket.LayeredConnectionSocketFactory;import org.apache.http.conn.socket.PlainConnectionSocketFactory;import org.apache.http.conn.ssl.NoopHostnameVerifier;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.conn.ssl.TrustStrategy;import org.apache.http.entity.ContentType;import org.apache.http.entity.StringEntity;import org.apache.http.entity.mime.MultipartEntityBuilder;import org.apache.http.entity.mime.content.InputStreamBody;import org.apache.http.entity.mime.content.StringBody;import org.apache.http.impl.auth.BasicScheme;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;import org.apache.http.message.BasicHeader;import org.apache.http.message.BasicNameValuePair;import org.apache.http.protocol.HttpContext;import org.apache.http.ssl.SSLContextBuilder;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * httpclient Sock5支持参考:https://blog.csdn.net/weixin_34075268/article/details/92040047 * @author liujh * */publicclass HttpsKitWithProxyAuth {    privatestatic Logger logger = LoggerFactory.getLogger(HttpsKitWithProxyAuth.class);    privatestaticfinalint CONNECT_TIMEOUT = 10000;// 设置连接建立的超时时间为10000ms    privatestaticfinalint SOCKET_TIMEOUT = 30000; // 多少时间没有数据传输    privatestaticfinalint HttpIdelTimeout = 30000;//空闲时间    privatestaticfinalint HttpMonitorInterval = 10000;//多久检查一次    privatestaticfinalint MAX_CONN = 200; // 最大连接数    privatestaticfinalint Max_PRE_ROUTE = 200; //设置到路由的最大连接数,    privatestatic CloseableHttpClient httpClient; // 发送请求的客户端单例    privatestatic PoolingHttpClientConnectionManager manager; // 连接池管理类    privatestatic ScheduledExecutorService monitorExecutor;    privatestaticfinal String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded";    privatestaticfinal String APPLICATION_JSON = "application/json";    privatestaticfinal String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36";    privatestaticfinal Object syncLock = new Object(); // 相当于线程锁,用于线程安全    /**     * 代理相关的变量,     */    publicstaticfinal String HTTP = "http";//proxyType的取值之一http    publicstaticfinal String SOCKS = "socks";//proxyType的取值之一socks    privatestaticboolean needProxy = false; //是否需要代理连接    privatestaticboolean needLogin = false;//代理连接是否需要账号和密码,为true时填上proxyUsername和proxyPassword    privatestatic String proxyType = HTTP; //代理类型,http,socks分别为http代理和sock5代理    privatestatic String proxyHost = "127.0.0.1"; //代理IP    privatestaticint proxyPort = 1080; //代理端口    privatestatic String proxyUsername = "sendi";//代理账号,needLogin为true时不能为空    privatestatic String proxyPassword = "123456";//代理密码,needLogin为true时不能为空    privatestatic RequestConfig requestConfig = RequestConfig.custom()            .setConnectionRequestTimeout(CONNECT_TIMEOUT)            .setConnectTimeout(CONNECT_TIMEOUT)            //.setCookieSpec(CookieSpecs.IGNORE_COOKIES)            .setSocketTimeout(SOCKET_TIMEOUT).build();    static {        /**         * Sock5代理账号和密码设置         * 如果账号和密码都不为空表示需要账号密码认证,因为这个是全局生效,因此在这里直接设置         * 可通过Authenticator.setDefault(null)取消全局配置         * Authenticator.setDefault(Authenticator a)关于a参数的说明如下:         * (The authenticator to be set. If a is {@code null} then any previously set authenticator is removed.)         */if(needProxy && SOCKS.equals(proxyType) && needLogin){            //用户名和密码验证            Authenticator.setDefault(new Authenticator(){                protected  PasswordAuthentication  getPasswordAuthentication(){                    PasswordAuthentication p = new PasswordAuthentication(proxyUsername, proxyPassword.toCharArray());return p;                }            });        }    }    /**     * 设置代理信息,可以在发请求前进行调用,用于替换此类中的代理相关的变量,全局设置一次就可     * needProxy 是否需要代理连接     * needLogin 代理连接是否需要账号和密码,为true时填上proxyUsername和proxyPassword     * proxyType 代理类型,http,socks分别为http代理和sock5代理     * proxyHost 代理IP     * proxyPort 代理端口     * proxyUsername 代理账号,needLogin为true时不能为空     * proxyPassword 代理密码,needLogin为true时不能为空     */    public static void setProxy(boolean needProxy,boolean needLogin,String proxyType,String proxyHost,int proxyPort,String proxyUserName,String proxyPassword){        HttpsKitWithProxyAuth.needProxy = needProxy;        HttpsKitWithProxyAuth.needLogin = needLogin;        HttpsKitWithProxyAuth.proxyType = proxyType;        HttpsKitWithProxyAuth.proxyHost = proxyHost;        HttpsKitWithProxyAuth.proxyPort = proxyPort;        HttpsKitWithProxyAuth.proxyUsername = proxyUserName;        HttpsKitWithProxyAuth.proxyPassword = proxyPassword;    }    private static CloseableHttpClient getHttpClient() {if (httpClient == null) {            // 多线程下多个线程同时调用getHttpClient容易导致重复创建httpClient对象的问题,所以加上了同步锁            synchronized (syncLock) {if (httpClient == null) {                    try {                        httpClient = createHttpClient();                    } catch (KeyManagementException e) {                        logger.error("error",e);                    } catch (NoSuchAlgorithmException e) {                        logger.error("error",e);                    } catch (KeyStoreException e) {                        logger.error("error",e);                    }                    // 开启监控线程,对异常和空闲线程进行关闭                    monitorExecutor = Executors.newScheduledThreadPool(1);                    monitorExecutor.scheduleAtFixedRate(new TimerTask() {                        @Override                        public void run() {                            // 关闭异常连接                            manager.closeExpiredConnections();                            // 关闭5s空闲的连接                            manager.closeIdleConnections(HttpIdelTimeout,TimeUnit.MILLISECONDS);                            //logger.info(manager.getTotalStats().toString());                            //logger.info("close expired and idle for over "+HttpIdelTimeout+"ms connection");                        }                    }, HttpMonitorInterval, HttpMonitorInterval, TimeUnit.MILLISECONDS);                }            }        }return httpClient;    }    /**     * 构建httpclient实例     * @return     * @throws KeyStoreException     * @throws NoSuchAlgorithmException     * @throws KeyManagementException     */    private static CloseableHttpClient createHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {        SSLContextBuilder builder = new SSLContextBuilder();        // 全部信任 不做身份鉴定        builder.loadTrustMaterial(null, new TrustStrategy() {            @Override            public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {                returntrue;            }        });        ConnectionSocketFactory plainSocketFactory = null;        LayeredConnectionSocketFactory sslSocketFactory = null;        /**         * 如果需要进行Sock5代理访问开放如下代码         * */if(needProxy && SOCKS.endsWith(proxyType)){            plainSocketFactory = new MyConnectionSocketFactory();            sslSocketFactory = new MySSLConnectionSocketFactory(builder.build());        }else {            plainSocketFactory = PlainConnectionSocketFactory.getSocketFactory();            sslSocketFactory = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE);        }        Registry<ConnectionSocketFactory> registry = RegistryBuilder                .<ConnectionSocketFactory> create()                .register("http", plainSocketFactory)                .register("https", sslSocketFactory).build();        manager = new PoolingHttpClientConnectionManager(registry);        // 设置连接参数        manager.setMaxTotal(MAX_CONN); // 最大连接数        manager.setDefaultMaxPerRoute(Max_PRE_ROUTE); // 路由最大连接数        // 请求失败时,进行请求重试        HttpRequestRetryHandler handler = new HttpRequestRetryHandler() {            @Override            public boolean retryRequest(IOException e, int i, HttpContext httpContext) {if (i > 3) {                    // 重试超过3次,放弃请求                    logger.error("retry has more than 3 time, give up request");                    returnfalse;                }if (e instanceof NoHttpResponseException) {                    // 服务器没有响应,可能是服务器断开了连接,应该重试                    logger.error("receive no response from server, retry");                    returntrue;                }if (e instanceof SSLHandshakeException) {                    // SSL握手异常                    logger.error("SSL hand shake exception");                    returnfalse;                }if (e instanceof InterruptedIOException) {                    // 超时                    logger.error("InterruptedIOException");                    returnfalse;                }if (e instanceof UnknownHostException) {                    // 服务器不可达                    logger.error("server host unknown");                    returnfalse;                }if (e instanceof ConnectTimeoutException) {                    // 连接超时                    logger.error("Connection Time out");                    returnfalse;                }if (e instanceof SSLException) {                    logger.error("SSLException");                    returnfalse;                }                HttpClientContext context = HttpClientContext.adapt(httpContext);                HttpRequest request = context.getRequest();if (!(request instanceof HttpEntityEnclosingRequest)) {                    // 如果请求不是关闭连接的请求                    returntrue;                }                returnfalse;            }        };        CloseableHttpClient client = null;        /**         * 如果需要进行HTTPS代理访问开放如下代码         * */if(needProxy && HTTP.endsWith(proxyType)){            client = HttpClients.custom()                    .setConnectionManager(manager)                    .setProxy(new HttpHost(proxyHost, proxyPort))                    .setRetryHandler(handler).build();        }else {            client = HttpClients.custom()                    .setConnectionManager(manager)                    .setRetryHandler(handler).build();        }return client;    }    public static String get(String url) {return get(url, null);    }    public static String get(String url,Map<String,Object> headerParams) {        HttpGet httpGet = new HttpGet(url);        httpGet.setHeader("User-Agent",USER_AGENT);        httpGet.setConfig(requestConfig);if(headerParams != null && headerParams.size()>0){for(String headerName : headerParams.keySet()) {                httpGet.setHeader(headerName,headerParams.get(headerName)+"");            }        }        CloseableHttpResponse response = null;        InputStream in = null;        String result = null;        try {            HttpClientContext ctx  = createContext();            response = getHttpClient().execute(httpGet,ctx);            HttpEntity entity = response.getEntity();if (entity != null) {in = entity.getContent();                result = IOUtils.toString(in"utf-8");            }        } catch (Exception e) {            logger.error("error",e);        } finally {            try {if (in != null) in.close();            } catch (IOException e) {                logger.error("error",e);            }            try {if (response != null) response.close();            } catch (IOException e) {                logger.error("error",e);            }        }return result;    }    public static String postJson(String url,Map<String,Object> requestParams) {return postJson(url, JsonUtil.toJSONString(requestParams));    }    public static String postJson(String url,Map<String,Object> requestParams,Map<String,String> headerParams) {return postJson(url, JsonUtil.toJSONString(requestParams),headerParams);    }    public static String postJson(String url,String requestParamStr) {return postJson(url, requestParamStr, null);    }    /**     * PUT方式调用http请求方法     * @param url     * @param requestParamStr     * @param headerParams     * @return     */    public static String put(String url,String requestParamStr,Map<String,String> headerParams) {        HttpPut httpput = new HttpPut(url);        httpput.setHeader("Content-Type", APPLICATION_JSON+";charset=" + CharEncoding.UTF_8);        httpput.setHeader("Accept",APPLICATION_JSON+";charset=" +CharEncoding.UTF_8);        httpput.setHeader("User-Agent",USER_AGENT);if(headerParams != null && headerParams.size()>0){for(String headerName : headerParams.keySet()) {                httpput.setHeader(headerName,headerParams.get(headerName)+"");            }        }        StringEntity se = new StringEntity(requestParamStr,CharEncoding.UTF_8);        se.setContentType(APPLICATION_JSON+";charset=" +CharEncoding.UTF_8);        httpput.setEntity(se);        httpput.setConfig(requestConfig);        CloseableHttpResponse response = null;        InputStream in = null;        String result = null;        try {            HttpClientContext ctx  = createContext();            response = getHttpClient().execute(httpput,ctx);            HttpEntity entity = response.getEntity();if (entity != null) {in = entity.getContent();                result = IOUtils.toString(in"utf-8");            }        } catch (Exception e) {            logger.error("error",e);        } finally {            try {if (in != null) in.close();            } catch (IOException e) {                logger.error("error",e);            }            try {if (response != null) response.close();            } catch (IOException e) {                logger.error("error",e);            }        }return result;    }    /**     * 创建一个HttpClientContext     * @return     * @throws MalformedChallengeException     */    public static HttpClientContext createContext() throws MalformedChallengeException{        HttpClientContext ctx  = HttpClientContext.create();        /**         * 如果需要进行Sock5代理访问         */if(needProxy && SOCKS.endsWith(proxyType)){            InetSocketAddress socksaddr = new InetSocketAddress(proxyHost,proxyPort);            ctx.setAttribute("socks.address", socksaddr);        }else{            /**             * 如果需要进行HTTPS代理访问开放如下代码             */if(needProxy && HTTP.endsWith(proxyType)){                /**                 * 代理连接认证如果需要认证账号和密码时处理                 */if(needLogin){                    AuthState authState = new AuthState();                    BasicScheme basicScheme = new BasicScheme();                    basicScheme.processChallenge(new BasicHeader(AUTH.PROXY_AUTH, "BASIC realm=default"));                    authState.update(basicScheme, new UsernamePasswordCredentials(proxyUsername, proxyPassword));                    ctx.setAttribute(HttpClientContext.PROXY_AUTH_STATE, authState);                }            }        }return ctx;    }    public static String postJson(String url,String requestParamStr,Map<String,String> headerParams) {        HttpPost httppost = new HttpPost(url);        httppost.setHeader("Content-Type", APPLICATION_JSON+";charset=" + CharEncoding.UTF_8);        httppost.setHeader("Accept",APPLICATION_JSON+";charset=" +CharEncoding.UTF_8);        httppost.setHeader("User-Agent",USER_AGENT);if(headerParams != null && headerParams.size()>0){for(String headerName : headerParams.keySet()) {                httppost.setHeader(headerName,headerParams.get(headerName)+"");            }        }        StringEntity se = new StringEntity(requestParamStr,CharEncoding.UTF_8);        se.setContentType(APPLICATION_JSON+";charset=" +CharEncoding.UTF_8);        httppost.setEntity(se);        httppost.setConfig(requestConfig);        CloseableHttpResponse response = null;        InputStream in = null;        String result = null;        try {            HttpClientContext ctx  = createContext();            response = getHttpClient().execute(httppost,ctx);            HttpEntity entity = response.getEntity();if (entity != null) {in = entity.getContent();                result = IOUtils.toString(in"utf-8");            }        } catch (Exception e) {            logger.error("error",e);        } finally {            try {if (in != null) in.close();            } catch (IOException e) {                logger.error("error",e);            }            try {if (response != null) response.close();            } catch (IOException e) {                logger.error("error",e);            }        }return result;    }    //requestParamStr---------->>> name=test&age=12    public static String postFormUrlencoded(String url,String requestParamStr) {return postFormUrlencoded(url, requestParamStr ,null);    }    public static String postFormUrlencoded(String url,String requestParamStr,Map<String,Object> headerParams) {        Map<String,String> requestParams = new HashMap<String,String>();        String[] strs = requestParamStr.split("&");for(String str : strs) {            String[] keyValues = str.split("=");if(keyValues.length == 2) {                requestParams.put(keyValues[0], keyValues[1]);            }        }return postFormUrlencoded(url, requestParams,headerParams);    }    public static String postFormUrlencoded(String url,Map<String,String> requestParams) {return postFormUrlencoded(url,requestParams,null);    }    public static String postFormUrlencoded(String url,Map<String,String> requestParams,Map<String,Object> headerParams) {        HttpPost httppost = new HttpPost(url);        //application/json        httppost.setHeader("Content-Type", APPLICATION_FORM_URLENCODED+";charset=" + CharEncoding.UTF_8);        httppost.setHeader("Accept",APPLICATION_JSON+";charset=" +CharEncoding.UTF_8);        httppost.setHeader("User-Agent",USER_AGENT);if(headerParams != null && headerParams.size()>0){for(String headerName : headerParams.keySet()) {                httppost.setHeader(headerName,headerParams.get(headerName)+"");            }        }        List<NameValuePair> formparams = new ArrayList<NameValuePair>();for(String keyStr : requestParams.keySet()) {            formparams.add(new BasicNameValuePair(keyStr, requestParams.get(keyStr)));        }        UrlEncodedFormEntity uefe = new UrlEncodedFormEntity(formparams, Consts.UTF_8);        httppost.setEntity(uefe);        httppost.setConfig(requestConfig);        CloseableHttpResponse response = null;        InputStream in = null;        String result = null;        try {            HttpClientContext ctx  = createContext();            response = getHttpClient().execute(httppost,ctx);            HttpEntity entity = response.getEntity();if (entity != null) {in = entity.getContent();                result = IOUtils.toString(in"utf-8");            }        } catch (Exception e) {            logger.error("error",e);        } finally {            try {if (in != null) in.close();            } catch (IOException e) {                logger.error("error",e);            }            try {if (response != null) response.close();            } catch (IOException e) {                logger.error("error",e);            }        }return result;    }    //文件上传的通用方法例子测试, 除了file部分参数外,写死了格外的字段参数如scene,output,后台将接收到file,scene,output三个参数,可以根据需求修改    public static String postFormMultipart(String url,InputStream fin,String originalFilename) {        HttpPost httppost = new HttpPost(url);        httppost.setConfig(requestConfig);        InputStreamBody bin = new InputStreamBody(fin, originalFilename);        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();        multipartEntityBuilder.addPart("file",bin);        multipartEntityBuilder.addPart("fileName",new StringBody(originalFilename,ContentType.TEXT_PLAIN));        multipartEntityBuilder.addPart("fileSize",new StringBody("1024",ContentType.TEXT_PLAIN));        multipartEntityBuilder.addPart("scene", new StringBody("default",ContentType.TEXT_PLAIN));        multipartEntityBuilder.addPart("output", new StringBody("json2",ContentType.TEXT_PLAIN));        HttpEntity reqEntity = multipartEntityBuilder.build();        httppost.setEntity(reqEntity);        CloseableHttpResponse response = null;        InputStream in = null;        String result = null;        try {            HttpClientContext ctx  = createContext();            response = getHttpClient().execute(httppost,ctx);            HttpEntity entity = response.getEntity();if (entity != null) {in = entity.getContent();                result = IOUtils.toString(in"utf-8");            }        } catch (Exception e) {            logger.error("error",e);        } finally {            try {if (in != null) in.close();            } catch (IOException e) {                logger.error("error",e);            }            try {if (response != null) response.close();            } catch (IOException e) {                logger.error("error",e);            }        }return result;    }    /**     * 下载文件到本地     * @param downloadUrl     * @param savePathAndName     */    public static void downloadFile(String downloadUrl,String savePathAndName){        HttpGet httpGet = new HttpGet(downloadUrl);        httpGet.setHeader("User-Agent",USER_AGENT);        httpGet.setConfig(requestConfig);        CloseableHttpResponse response = null;        InputStream in = null;        try {            response = getHttpClient().execute(httpGet,HttpClientContext.create());            HttpEntity entity = response.getEntity();if (entity != null) {in = entity.getContent();                //如果path传进来是/结束的话处理一下,先去掉。                FileOutputStream out = new FileOutputStream(new File(savePathAndName));                IOUtils.copy(in, out);                out.close();            }        } catch (IOException e) {            logger.error("error",e);        } finally {            try {if (in != null) in.close();            } catch (IOException e) {                logger.error("error",e);            }            try {if (response != null) response.close();            } catch (IOException e) {                logger.error("error",e);            }        }    }    /**     * 下载文件到本地     * @param downloadUrl     * @param saveFileName     * @param savePath     */    public static void downloadFile(String downloadUrl,String saveFileName,String savePath){        //如果path传进来是/结束的话处理一下,先去掉。        String savePathAndName = savePath.endsWith("/") ? savePath.substring(0,savePath.lastIndexOf("/")) : savePath;        downloadFile(downloadUrl, savePathAndName);    }    /**     * 关闭连接池     */    public static void closeConnectionPool() {if(manager != null) manager.close();if(monitorExecutor != null) monitorExecutor.shutdown();        try {if(httpClient != null) httpClient.close();} catch (IOException e) {logger.error("error",e);}        manager = null;        monitorExecutor = null;        httpClient = null;    }    privatestaticclass MyConnectionSocketFactory extends PlainConnectionSocketFactory {        @Override        public Socket createSocket(final HttpContext context) throws IOException {            InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");            Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);            returnnew Socket(proxy);        }        @Override        public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,                                    InetSocketAddress localAddress, HttpContext context) throws IOException {            // Convert address to unresolved            InetSocketAddress unresolvedRemote = InetSocketAddress                    .createUnresolved(host.getHostName(), remoteAddress.getPort());            returnsuper.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context);        }    }    privatestaticclass MySSLConnectionSocketFactory extends SSLConnectionSocketFactory {        public MySSLConnectionSocketFactory(final SSLContext sslContext) {            // You may need this verifier if target site's certificate is not secure            super(sslContext, NoopHostnameVerifier.INSTANCE);        }        @Override        public Socket createSocket(final HttpContext context) throws IOException {            InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");            Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);            returnnew Socket(proxy);        }        @Override        public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,                                    InetSocketAddress localAddress, HttpContext context) throws IOException {            // Convert address to unresolved            InetSocketAddress unresolvedRemote = InetSocketAddress                    .createUnresolved(host.getHostName(), remoteAddress.getPort());            returnsuper.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context);        }    }    public static void main(String[] args) throws InterruptedException, MalformedURLException {        String url = "https://api.openai.com/v1/chat/completions";        url = "https://www.baidu.com";        System.out.println(HttpsKitWithProxyAuth.get(url));        //关闭连接池,正式环境中这个不要关闭        HttpsKitWithProxyAuth.closeConnectionPool();    }}package com.ruoyi.web.controller.meetingminutes.utils;/** * @Author 不要有情绪的  ljy * @Date 2024/10/31 20:35 * @Description: */import java.io.IOException;import java.text.SimpleDateFormat;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.List;import java.util.Map;import java.util.TimeZone;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;import com.fasterxml.jackson.annotation.JsonInclude;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.core.type.TypeReference;import com.fasterxml.jackson.databind.DeserializationFeature;import com.fasterxml.jackson.databind.JavaType;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.SerializationFeature;import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;//https://www.cnblogs.com/christopherchan/p/11071098.htmlpublicclass JsonUtil {    privatefinalstatic Logger logger = LoggerFactory.getLogger(JsonUtil.class);    //日期格式化    privatestaticfinal String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";    privatestatic ObjectMapper objectMapper;    static{        /**         * ObjectobjectMapper是JSON操作的核心,Jackson的所有JSON操作都是在ObjectobjectMapper中实现。         * ObjectobjectMapper有多个JSON序列化的方法,可以把JSON字符串保存File、OutputStream等不同的介质中。         * writeValue(File arg0, Object arg1)把arg1转成json序列,并保存到arg0文件中。         * writeValue(OutputStream arg0, Object arg1)把arg1转成json序列,并保存到arg0输出流中。         * writeValueAsBytes(Object arg0)把arg0转成json序列,并把结果输出成字节数组。         * writeValueAsString(Object arg0)把arg0转成json序列,并把结果输出成字符串。         */        objectMapper = new ObjectMapper();        //对象的所有字段全部列入        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);        //取消默认转换timestamps形式        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);        //忽略空Bean转json的错误        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);        //所有的日期格式都统一为以下的样式,即yyyy-MM-dd HH:mm:ss        objectMapper.setDateFormat(new SimpleDateFormat(STANDARD_FORMAT));        //忽略 在json字符串中存在,但是在java对象中不存在对应属性的情况。防止错误        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));        objectMapper.setVisibility(PropertyAccessor.ALL, Visibility.ANY);        //开启美化功能        //objectMapper.enable(SerializationFeature.INDENT_OUTPUT);        //解决Java8 LocalDate,LocalDateTime等序列化问题        JavaTimeModule module=new JavaTimeModule();        module.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));        module.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));        module.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));        module.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));        objectMapper.registerModule(module);    }    /**     * 对象转Json格式字符串     * @param obj 对象     * @return Json格式字符串     */    public static String toJSONString(Object o) {        if (o == null) {            returnnull;        }        if (o instanceof String)            return (String) o;        String jsonValue = null;        try {            jsonValue = objectMapper.writeValueAsString(o);        } catch (JsonProcessingException e) {            logger.error("Parse Object to String error",e);        }        return jsonValue;    }    @SuppressWarnings("unchecked")    public static Map<String,Object> castToObject(String fromValue){        if(fromValue == null || "".equals(fromValue) ){            returnnull;        }        try {            return objectMapper.readValue(fromValue, Map.class);        } catch (Exception e) {            logger.error("Parse String to Object error:", e);            returnnull;        }    }    /**     * 字符串转换为自定义对象     * @param str 要转换的字符串     * @param clazz 自定义对象的class对象     * @return 自定义对象     */    @SuppressWarnings("unchecked")    publicstatic <T> T castToObject(String fromValue, Class<T> clazz){        if(fromValue == null || "".equals(fromValue) || clazz == null){            returnnull;        }        try {            return clazz.equals(String.class) ? (T) fromValue : objectMapper.readValue(fromValue, clazz);        } catch (Exception e) {            logger.error("Parse String to Object error:", e);            returnnull;        }    }    @SuppressWarnings("unchecked")    publicstatic <T> T castToObject(String fromValue, TypeReference<T> typeReference) {        if (fromValue == null || "".equals(fromValue) || typeReference == null) {            returnnull;        }        try {            return (T) (typeReference.getType().equals(String.class) ? fromValue : objectMapper.readValue(fromValue, typeReference));        } catch (IOException e) {            logger.error("Parse String to Object error:", e);            returnnull;        }    }    publicstatic <T> T castToObject(String fromValue, Class<?> collectionClazz, Class<?>... elementClazzes) {        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClazz, elementClazzes);        try {            return objectMapper.readValue(fromValue, javaType);        } catch (IOException e) {            logger.error("Parse String to Object error : ", e.getMessage());            returnnull;        }    }    publicstatic <T> T getValue(String fromValue, Class<T> clazz){        return castToObject(fromValue,clazz);    }    publicstatic <T> T getValue(String fromValue, TypeReference<T> toValueTypeRef){        return castToObject(fromValue, toValueTypeRef);    }    publicstatic <T> T getValue(String fromValue, Class<?> collectionClazz, Class<?>... elementClazzes){        return castToObject(fromValue, collectionClazz, elementClazzes);    }    //可通过点语法获取数据,如getValue("data.list","xxxxxxxx",List.class);    publicstatic <T> T getValue(String key, String fromValue, Class<T> clazz){        Map<String,Object> infoMap = castToObject(fromValue);        if(infoMap == null) returnnull;        return getValue(key, infoMap, clazz);    }    //可通过点语法获取数据,如getValue("data.list","xxxxxxxx",new TypeReference<List<User>>(){});    publicstatic <T> T getValue(String key, String fromValue, TypeReference<T> toValueTypeRef){        Map<String,Object> infoMap = castToObject(fromValue);        if(infoMap == null) returnnull;        return getValue(key, infoMap, toValueTypeRef);    }    publicstatic <T> T getValue(String key, String fromValue, Class<?> collectionClazz, Class<?>... elementClazzes){        Map<String,Object> infoMap = castToObject(fromValue);        if(infoMap == null) returnnull;        return getValue(key, infoMap, collectionClazz, elementClazzes);    }    //可通过点语法获取数据,如getValue("data.list",new TypeReference<List<User>>(){});    @SuppressWarnings("rawtypes")    publicstatic <T> T getValue(String key, Map fromMap, Class<T> clazz){        try {            // 首先将key进行拆分            String[] keys = key.split("[.]");            for (int i = 0; i < keys.length; i++) {                Object value = fromMap.get(keys[i]);                if(value == null) returnnull;                if (i < keys.length - 1) {                    fromMap = (Map) value;                }else {                    return objectMapper.convertValue(value, clazz);                }            }        } catch (Exception e) {            logger.error("getValue error : ", e.getMessage());            returnnull;        }        returnnull;    }    @SuppressWarnings("rawtypes")    publicstatic <T> T getValue(String key, Map fromMap, Class<?> collectionClazz, Class<?>... elementClazzes){        try {            // 首先将key进行拆分            String[] keys = key.split("[.]");            for (int i = 0; i < keys.length; i++) {                Object value = fromMap.get(keys[i]);                if(value == null) returnnull;                if (i < keys.length - 1) {                    fromMap = (Map) value;                }else {                    JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClazz, elementClazzes);                    return objectMapper.convertValue(value, javaType);                }            }        } catch (Exception e) {            logger.error("getValue error : ", e.getMessage());            returnnull;        }        returnnull;    }    @SuppressWarnings("rawtypes")    publicstatic <T> T getValue(String key, Map fromMap, TypeReference<T> toValueTypeRef){        try {            // 首先将key进行拆分            String[] keys = key.split("[.]");            for (int i = 0; i < keys.length; i++) {                Object value = fromMap.get(keys[i]);                if(value == null) returnnull;                if (i < keys.length - 1) {                    fromMap = (Map) value;                }else {                    return objectMapper.convertValue(value, toValueTypeRef);                }            }        } catch (Exception e) {            logger.error("getValue error : ", e.getMessage());            returnnull;        }        returnnull;    }    /**     * 将对像转换成具体的其他Bean对像     * @param fromValue     * @param toValueTypeRef     * @return     */    publicstatic <T> T convertValue(Object fromValue, TypeReference<T> toValueTypeRef){        try {            return objectMapper.convertValue(fromValue, toValueTypeRef);        } catch (Exception e) {            logger.error("convertValue error : ", e.getMessage());            returnnull;        }    }    publicstatic <T> T convertValue(Object fromValue, Class<T> toValueType){        try {            return objectMapper.convertValue(fromValue, toValueType);        } catch (Exception e) {            logger.error("convertValue error : ", e.getMessage());            returnnull;        }    }    public static String getString(Map<String,Object> fromMap, String fieldName){        return fromMap.get(fieldName)==null ? null : fromMap.get(fieldName).toString();    }    //根据filedName的key查找map为空时,使用对应的defaultValue默认值替换返回    public static String getString(Map<String,Object> jsonObject, String fieldName,String defaultValue){        return jsonObject.get(fieldName)==null ? defaultValue : jsonObject.get(fieldName).toString();    }    public static Integer getInteger(Map<String,Object> jsonObject, String fieldName){        return jsonObject.get(fieldName)==null ? null : (Integer)jsonObject.get(fieldName);    }    public static Double getDouble(Map<String,Object> jsonObject, String fieldName){        return jsonObject.get(fieldName)==null ? null : (Double)jsonObject.get(fieldName);    }    public static Boolean getBoolean(Map<String,Object> jsonObject, String fieldName){        return jsonObject.get(fieldName)==null ? false : (Boolean)jsonObject.get(fieldName);    }    public static Long getLong(Map<String,Object> jsonObject, String fieldName){        return jsonObject.get(fieldName)==null ? null : (Long)jsonObject.get(fieldName);    }    publicstatic <T> List<T> getList(Map<String,Object> jsonObject, String fieldName,Class<T> clazz){        return jsonObject.get(fieldName)==null ? null : JsonUtil.getValue(fieldName, jsonObject, List.class,clazz);    }}

3、问题总结

开始敲黑板了

3.1、访问案例失败

部署完成后,可能存在很多问题,例如:访问example访问失败,那么使用

systemctl status ds*

查看有没有启动对应的服务

3.2、加载word文档失败

修改启动的配置文件,将token去除,更改配置文件local.json和default.json,配置文件位置

/etc/onlyoffice/documentserver

local.json中将参数token都改为false,去除token

"token": {"enable": {"request": {"inbox"false,"outbox"false     },"browser"false   },

default.json中将参数request-filtering-agent改为true,token也改为false,rejectUnauthorized改为false

"request-filtering-agent" : {"allowPrivateIPAddress"true,"allowMetaIPAddress"true    },"token": {"enable": {"browser"false,"request": {"inbox"false,"outbox"false      }   },"rejectUnauthorized"false

修改了以上配置参数后,重启服务,再次测试。

以上更基本能解决报错文档权限问题,文档保存失败问题,文档下载问题等报错信息。

3.3、系统后端有token验证问题

如果你访问的地址需要携带token,进行token验证(自己的系统后台,并非onlyoffice的token),那么可以通过配置下面代码的形式进行解决,例如:我的访问路径为http:192.168.123.123:8089/getFile/12,去除token验证(requests.antMatchers("/callback", "/getFile/*", "/login", "/register", "/captchaImage").permitAll()

@Beanprotected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return httpSecurity            // CSRF禁用,因为不使用session            .csrf(csrf -> csrf.disable())            // 禁用HTTP响应标头            .headers((headersCustomizer) -> {                headersCustomizer.cacheControl(cache -> cache.disable()).frameOptions(options -> options.sameOrigin());            })            // 认证失败处理类            .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))            // 基于token,所以不需要session            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))            // 注解标记允许匿名访问的url            .authorizeHttpRequests((requests) -> {                permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());                // 对于登录login 注册register 验证码captchaImage 允许匿名访问                requests.antMatchers("/callback""/getFile/*""/login""/register""/captchaImage").permitAll()                        // 静态资源,可匿名访问                        .antMatchers(HttpMethod.GET, "/""/*.html""/**/*.html""/**/*.css""/**/*.js""/profile/**").permitAll()                        .antMatchers("/swagger-ui.html""/swagger-resources/**""/webjars/**""/*/api-docs""/druid/**").permitAll()                        // 除上面外的所有请求全部需要鉴权认证                        .anyRequest().authenticated();            })            // 添加Logout filter            .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))            // 添加JWT filter            .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)           添加CORS filter            .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)            .addFilterBefore(corsFilter, LogoutFilter.class)            .build();}

3.4、使用文档地址访问问题

如果你不采用上面的方式,即http:192.168.123.123:8089/getFile/12 的方式,你想采用http:192.168.123.123:8089/word/1234.docx 的方式,也是可以的,但是你需要将文档挂到一个服务上,例如使用ngnix作为代理,进行/word/1234.docx的重定向。

下面你可以直接使用一个在线的docx链接来测试你是否部署成功,在线链接:

https://d2nlctn12v279m.cloudfront.net/assets/docs/samples/zh/demo.docx

即将前端代码中的url替换为上面的链接。

4、后记

如果你看到这里,那么代表你将要成功了,整个过程比较艰难,前后弄了两三天,还好最后结果是好的,所以简单总结一下,勉励自己。

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-04-02 16:56:44 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/496755.html
  2. 运行时间 : 0.123155s [ 吞吐率:8.12req/s ] 内存消耗:4,834.98kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=bfdad43091e05c4e75fb9fd3619b2988
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.80 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000487s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000699s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000441s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000293s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000463s ]
  6. SELECT * FROM `set` [ RunTime:0.000189s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000578s ]
  8. SELECT * FROM `article` WHERE `id` = 496755 LIMIT 1 [ RunTime:0.000576s ]
  9. UPDATE `article` SET `lasttime` = 1775120204 WHERE `id` = 496755 [ RunTime:0.018861s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.005153s ]
  11. SELECT * FROM `article` WHERE `id` < 496755 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000557s ]
  12. SELECT * FROM `article` WHERE `id` > 496755 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000457s ]
  13. SELECT * FROM `article` WHERE `id` < 496755 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000864s ]
  14. SELECT * FROM `article` WHERE `id` < 496755 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.000798s ]
  15. SELECT * FROM `article` WHERE `id` < 496755 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.000670s ]
0.124855s