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

做网站的公司首选智投未来/实时seo排名点击软件

做网站的公司首选智投未来,实时seo排名点击软件,网站怎么做跳转,企业网站流量怎么做前言 最近有个项目需求是实现前端页面可以对word文档进行编辑,并且可以进行保存,于是一顿搜索,找到开源第三方onlyoffice,实际上onlyOffice有很多功能,例如文档转化、多人协同编辑文档、文档打印等,我们只用…

前言

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

目 录

前言

1、onlyoffice的部署

2、代码逻辑开发

2.1、前端代码

2.2、后端代码

3、问题总结

3.1、访问案例失败

3.2、加载word文档失败

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

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

4、后记


1、onlyoffice的部署

        部署分为docker部署方式和本地直接安装的方式,比较两种部署方式,docker是比较简单的一种,因为只要拉取相关镜像,然后启动时配置好对应的配置文件即可。由于搜索的时候先看到的是linux本地部署,所以采用了第二种方式,下面我将给出两个参考博客:

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

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

2、代码逻辑开发

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

2.1、前端代码

参考官方文档API

参考文档

记得添加下面的js文件

<div id="placeholder"></div>
<script type="text/javascript" src="https://documentserver/web-apps/apps/api/documents/api.js"></script>
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%',}new window.DocsAPI.DocEditor('onlyoffice', config)

        其中import.meta.env.VITE_APP_API_URL为你实际的onlyoffice地址,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")
@RestController
public class OnlyOfficeController {@Autowiredprivate 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)) {return null;   //当会议纪要文件为空的时候,就返回null}File file = new File(meetingMinutesFilePath);FileInputStream fileInputStream = null;InputStream fis = null;try {fileInputStream = new FileInputStream(file);fis = new BufferedInputStream(fileInputStream);byte[] buffer = new byte[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"));return new ResponseEntity<>(buffer, headers, HttpStatus.OK);} catch (Exception e) {throw new 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/callbackInteger status = callbackData.getStatus();switch (status) {case 1: {//document is being edited  文档已经被编辑break;}case 2: {//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;}case 3: {//document saving error has occurred,保存出错System.out.println("document saving error has occurred,保存出错");break;}case 4: {//document is closed with no changes,未保存退出System.out.println("document is closed with no changes,未保存退出");break;}case 6: {//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.");}case 7: {//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@Getterpublic static class 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**/
public class HttpsKitWithProxyAuth {private static Logger logger = LoggerFactory.getLogger(HttpsKitWithProxyAuth.class);private static final int CONNECT_TIMEOUT = 10000;// 设置连接建立的超时时间为10000msprivate static final int SOCKET_TIMEOUT = 30000; // 多少时间没有数据传输private static final int HttpIdelTimeout = 30000;//空闲时间private static final int HttpMonitorInterval = 10000;//多久检查一次private static final int MAX_CONN = 200; // 最大连接数private static final int Max_PRE_ROUTE = 200; //设置到路由的最大连接数,private static CloseableHttpClient httpClient; // 发送请求的客户端单例private static PoolingHttpClientConnectionManager manager; // 连接池管理类private static ScheduledExecutorService monitorExecutor;private static final String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded";private static final String APPLICATION_JSON = "application/json";private static final 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";private static final Object syncLock = new Object(); // 相当于线程锁,用于线程安全/*** 代理相关的变量,*/public static final String HTTP = "http";//proxyType的取值之一httppublic static final String SOCKS = "socks";//proxyType的取值之一socksprivate static boolean needProxy = false; //是否需要代理连接private static boolean needLogin = false;//代理连接是否需要账号和密码,为true时填上proxyUsername和proxyPasswordprivate static String proxyType = HTTP; //代理类型,http,socks分别为http代理和sock5代理private static String proxyHost = "127.0.0.1"; //代理IPprivate static int proxyPort = 1080; //代理端口private static String proxyUsername = "sendi";//代理账号,needLogin为true时不能为空private static String proxyPassword = "123456";//代理密码,needLogin为true时不能为空private static 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() {@Overridepublic 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() {@Overridepublic boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {return true;}});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() {@Overridepublic boolean retryRequest(IOException e, int i,	HttpContext httpContext) {if (i > 3) {// 重试超过3次,放弃请求logger.error("retry has more than 3 time, give up request");return false;}if (e instanceof NoHttpResponseException) {// 服务器没有响应,可能是服务器断开了连接,应该重试logger.error("receive no response from server, retry");return true;}if (e instanceof SSLHandshakeException) {// SSL握手异常logger.error("SSL hand shake exception");return false;}if (e instanceof InterruptedIOException) {// 超时logger.error("InterruptedIOException");return false;}if (e instanceof UnknownHostException) {// 服务器不可达logger.error("server host unknown");return false;}if (e instanceof ConnectTimeoutException) {// 连接超时logger.error("Connection Time out");return false;}if (e instanceof SSLException) {logger.error("SSLException");return false;}HttpClientContext context = HttpClientContext.adapt(httpContext);HttpRequest request = context.getRequest();if (!(request instanceof HttpEntityEnclosingRequest)) {// 如果请求不是关闭连接的请求return true;}return false;}};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=12public 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/jsonhttppost.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;}private static class MyConnectionSocketFactory extends PlainConnectionSocketFactory {@Overridepublic Socket createSocket(final HttpContext context) throws IOException {InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);return new Socket(proxy);}@Overridepublic Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,InetSocketAddress localAddress, HttpContext context) throws IOException {// Convert address to unresolvedInetSocketAddress unresolvedRemote = InetSocketAddress.createUnresolved(host.getHostName(), remoteAddress.getPort());return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context);}}private static class MySSLConnectionSocketFactory extends SSLConnectionSocketFactory {public MySSLConnectionSocketFactory(final SSLContext sslContext) {// You may need this verifier if target site's certificate is not securesuper(sslContext, NoopHostnameVerifier.INSTANCE);}@Overridepublic Socket createSocket(final HttpContext context) throws IOException {InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);return new Socket(proxy);}@Overridepublic Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,InetSocketAddress localAddress, HttpContext context) throws IOException {// Convert address to unresolvedInetSocketAddress unresolvedRemote = InetSocketAddress.createUnresolved(host.getHostName(), remoteAddress.getPort());return super.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.html
public class JsonUtil {private final static Logger logger = LoggerFactory.getLogger(JsonUtil.class);//日期格式化private static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";private static 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:ssobjectMapper.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) {return null;}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) ){return null;}try {return objectMapper.readValue(fromValue, Map.class);} catch (Exception e) {logger.error("Parse String to Object error:", e);return null;}}/*** 字符串转换为自定义对象* @param str 要转换的字符串* @param clazz 自定义对象的class对象* @return 自定义对象*/@SuppressWarnings("unchecked")public static <T> T castToObject(String fromValue, Class<T> clazz){if(fromValue == null || "".equals(fromValue) || clazz == null){return null;}try {return clazz.equals(String.class) ? (T) fromValue : objectMapper.readValue(fromValue, clazz);} catch (Exception e) {logger.error("Parse String to Object error:", e);return null;}}@SuppressWarnings("unchecked")public static <T> T castToObject(String fromValue, TypeReference<T> typeReference) {if (fromValue == null || "".equals(fromValue) || typeReference == null) {return null;}try {return (T) (typeReference.getType().equals(String.class) ? fromValue : objectMapper.readValue(fromValue, typeReference));} catch (IOException e) {logger.error("Parse String to Object error:", e);return null;}}public static <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());return null;}}public static <T> T getValue(String fromValue, Class<T> clazz){return castToObject(fromValue,clazz);}public static <T> T getValue(String fromValue, TypeReference<T> toValueTypeRef){return castToObject(fromValue, toValueTypeRef);}public static <T> T getValue(String fromValue, Class<?> collectionClazz, Class<?>... elementClazzes){return castToObject(fromValue, collectionClazz, elementClazzes);}//可通过点语法获取数据,如getValue("data.list","xxxxxxxx",List.class);public static <T> T getValue(String key, String fromValue, Class<T> clazz){Map<String,Object> infoMap = castToObject(fromValue);if(infoMap == null) return null;return getValue(key, infoMap, clazz);}//可通过点语法获取数据,如getValue("data.list","xxxxxxxx",new TypeReference<List<User>>(){});public static <T> T getValue(String key, String fromValue, TypeReference<T> toValueTypeRef){Map<String,Object> infoMap = castToObject(fromValue);if(infoMap == null) return null;return getValue(key, infoMap, toValueTypeRef);}public static <T> T getValue(String key, String fromValue, Class<?> collectionClazz, Class<?>... elementClazzes){Map<String,Object> infoMap = castToObject(fromValue);if(infoMap == null) return null;return getValue(key, infoMap, collectionClazz, elementClazzes);}//可通过点语法获取数据,如getValue("data.list",new TypeReference<List<User>>(){});@SuppressWarnings("rawtypes")public static <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) return null;if (i < keys.length - 1) {fromMap = (Map) value;}else {return objectMapper.convertValue(value, clazz);}}} catch (Exception e) {logger.error("getValue error : ", e.getMessage());return null;}return null;}@SuppressWarnings("rawtypes")public static <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) return null;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());return null;}return null;}@SuppressWarnings("rawtypes")public static <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) return null;if (i < keys.length - 1) {fromMap = (Map) value;}else {return objectMapper.convertValue(value, toValueTypeRef);}}} catch (Exception e) {logger.error("getValue error : ", e.getMessage());return null;}return null;}/*** 将对像转换成具体的其他Bean对像* @param fromValue* @param toValueTypeRef* @return*/public static <T> T convertValue(Object fromValue, TypeReference<T> toValueTypeRef){try {return objectMapper.convertValue(fromValue, toValueTypeRef);} catch (Exception e) {logger.error("convertValue error : ", e.getMessage());return null;}}public static <T> T convertValue(Object fromValue, Class<T> toValueType){try {return objectMapper.convertValue(fromValue, toValueType);} catch (Exception e) {logger.error("convertValue error : ", e.getMessage());return null;}}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);}public static <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、后记

        如果你看到这里,那么代表你将要成功了,整个过程比较艰难,前后弄了两三天,还好最后结果是好的,所以简单总结一下,勉励自己。可能有些地方没有描述清楚,有让你疑惑,欢迎留言call我,如果比较急也可以+我v 1450053947(一般别打扰,thankyou!)

后端参考博客:springboot集成开源office软件onlyoffice - 知乎 (zhihu.com)

OnlyOffice文档服务器安装及集成使用_冰之杍-GitCode 开源社区 (csdn.net)

学习之所以会想睡觉,是因为那是梦开始的地方。
ଘ(੭ˊᵕˋ)੭ (开心) ଘ(੭ˊᵕˋ)੭ (开心)ଘ(੭ˊᵕˋ)੭ (开心)ଘ(੭ˊᵕˋ)੭ (开心)ଘ(੭ˊᵕˋ)੭ (开心)
                                                                                                        ------不写代码不会凸的小刘

相关文章:

springboot集成onlyoffice(部署+开发)

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

LabVIEW编程基础教学(二)--数据类型

在LabVIEW中&#xff0c;数据类型是非常重要的基本概念&#xff0c;因为它们决定了如何存储和操作数据。掌握这些基础数据类型对于编写有效的程序非常关键。以下是LabVIEW中的基础数据类型介绍&#xff1a; 1. 数值类型&#xff08;Numeric&#xff09; 整型&#xff08;Inte…...

「Mac畅玩鸿蒙与硬件29」UI互动应用篇6 - 多选问卷小应用

本篇将带你实现一个多选问卷小应用&#xff0c;用户可以勾选选项并点击提交按钮查看选择的结果。通过本教程&#xff0c;你将学习如何使用 Checkbox 组件、动态渲染列表、状态管理及用户交互&#xff0c;构建完整的应用程序。 关键词 UI互动应用Checkbox 组件状态管理动态列表…...

Flutter中文字体设置指南:打造个性化的应用体验

在使用Flutter进行开发时&#xff0c;可能会遇到中文字体显示不正常或者字体不符合设计需求的情况。Flutter默认的中文字体往往无法满足某些用户对个性化和美观的需求。今天&#xff0c;我们就来详细探讨如何在Flutter应用中设置中文字体&#xff0c;并结合不同场景提供相应的解…...

git下载慢下载不了?Git国内国外下载地址镜像,git安装视频教程

git安装下载的视频教程在这 3分钟完成git下载和安装&#xff0c;git国内外下载地址镜像&#xff0c;Windows为例_哔哩哔哩_bilibili 一、Git安装包国内和国外下载地址镜像 1.1国外官方下载地址 打开Git的官方网站&#xff1a;Git官网下载页面。在页面上选择对应的系统&…...

安卓属性动画插值器(Interpolator)详解

属性动画&#xff08;Property Animation&#xff09;是 Android 中一个强大的动画框架&#xff0c;允许开发者对视图的任意属性&#xff08;如位置、透明度、尺寸、颜色等&#xff09;进行平滑的动态变化。插值器&#xff08;Interpolator&#xff09;作为属性动画的一部分&am…...

OSPF总结

1.定义及相关信息 (1)全称:Open ShortestPath First,开放式最短路径优先 (2)是一种基于链路状态算法的路由协议 (3)目前针对IPv4协议使用的是OSPF Version2(RFC2328) 目前针对IPv6 协议使用的是 OSPF Version3 ( RFC2740 ) (4)运行 OSPF 路由器之间…...

Spring Boot驱动的多维分类知识管理系统

1 绪论 1.1 研究背景 在这个推荐个性化的时代&#xff0c;采用新技术开发一个多维分类的知识管理系统来分享和展示内容是一个永恒不变的需求。本次设计的多维分类的知识管理系统有管理员和用户两个角色。 管理员可以管理用户信息&#xff0c;知识分类&#xff0c;知识信息等&am…...

CSS教程(七)- 背景

介绍 背景属性可以设置背景颜色、背景图片、背景平铺、背景图片位置、背景图像固定等。 1 背景颜色 属性名&#xff1a;background-color 作用&#xff1a;指定HTML元素的背景色。 取值&#xff1a;英文颜色、16进制、rgb、rgba、transparent&#xff08;一般为透明&#…...

PNG图片批量压缩exe工具+功能纯净+不改变原始尺寸

小编最近有一篇png图片要批量压缩&#xff0c;大小都在5MB之上&#xff0c;在网上找了半天要么就是有广告&#xff0c;要么就是有毒&#xff0c;要么就是功能复杂&#xff0c;整的我心烦意乱。 于是我自己用python写了一个纯净工具&#xff0c;只能压缩png图片&#xff0c;没任…...

【双十一特惠】腾讯云省钱攻略:如何智取云计算资源

前言 双十一不仅是购物的狂欢节&#xff0c;对于云计算用户来说&#xff0c;更是一个节省成本的绝佳时机。腾讯云&#xff0c;作为国内领先的云计算服务商&#xff0c;每年双十一都会推出一系列优惠活动。本文将为您揭开如何在这个购物节中&#xff0c;最大化利用腾讯云的优惠…...

爬虫学习8

Frida是一个动态代码插桩工具&#xff0c;允许开发者在运行时修改和调试应用程序 import ...&#xff1a;这行代码表示导入所需的模块或库&#xff0c;但具体的导入内容在图片中被省略了。 rdev frida.get_remote_device()&#xff1a;这行代码获取一个远程设备实例&#xff…...

双指针算法的妙用:提高代码效率的秘密(2)

双指针算法的妙用&#xff1a;提高代码效率的秘密&#xff08;2&#xff09; 前言&#xff1a; 小编在前几日讲述了有关双指针算法两道题目的讲解&#xff0c;今天小编继续进行有关双指针算法习题的讲解&#xff0c;老规矩&#xff0c;今天还是两道题目的讲解&#xff0c;希望…...

笔记--(网络3)、交换机、VLAN

交换机 交换机&#xff08;Switch&#xff09;意为“开关”是一种用于电&#xff08;光&#xff09;信号转发的网络设备。它可以为接入交换机的任意两个网络节点提供独享的电信号通路。最常见的交换机是以太网交换机。其他常见的还有电话语音交换机、光纤交换机等。 交换机的…...

昇思大模型平台打卡体验活动:基于MindSpore实现GPT1影评分类

如果你对MindSpore感兴趣&#xff0c;可以关注昇思MindSpore社区 大模型平台 平台说明 昇思大模型平台旨在为AI学习者和开发者提供在线学习的项目、模型、大模型体验和数据集的平台。我们也添加了各领域的经典数据集来帮助学习者解决AI学习过程中的一系列难题&#xff0c; 如…...

如何调整pdf的页面尺寸

用福昕阅读器打开pdf&#xff0c;进入打印页面&#xff0c;选择“属性”&#xff0c;在弹出的页面选择“高级” 选择你想调成的纸张尺寸&#xff0c;然后打印&#xff0c;打印出来的pdf就是调整尺寸后的pdf...

IDA*算法 Power Calculus————poj 3134

目录 闲聊 前言 DFS算法的无效搜索 BFS算法的空间浪费 IDDFS A*算法 IDA* Power Calculus 问题描述 输入 输出 问题分析 代码 闲聊 前几周在忙着数学竞赛&#xff0c;所以就没时间更新&#xff0c;高等数学&#xff0c;一生之敌&#xff0c;真不知道报名的时候我是怎么想…...

重磅!CoRL 2024顶刊会议 清华大学高阳研究组发布“基于大模型先验知识的强化学习”

正在德国举办的机器人研究领域的顶级学术会议CoRL 2024&#xff0c;清华大学交叉信息研究院高阳研究组发布重磅研究成果&#xff0c;提出“基于大模型先验知识的强化学习”框架&#xff08;Reinforcement Learning with Foundation Priors) 来促进具身智能体在操作任务中的学习…...

泷羽sec学习打卡-Windows基础命令

声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 关于windows的那些事儿-Base 一、Windows-BaseWindows有哪些版本呢&#xff0c;有什么区别呢&#xff1f…...

RTC精度及校准

RTC精度偏差&#xff1a; RTC的基准时间和精度与石英晶体的频率相关&#xff0c;晶体的谐振频率取决于温度&#xff0c;因此RTC性能与温度相关&#xff0c;晶体的频率偏差是晶体正常频率的温度反转函数。 一、硬件方面&#xff1a; 1.使用高精度振荡器的RTC模块&#xff1b; …...

jQuery案例

以下是几个常见的 jQuery 示例&#xff0c;展示了它在不同场景下的应用&#xff1a; 1. 隐藏和显示元素 通过按钮点击隐藏和显示一个 <div> 元素。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><met…...

常见 HTTP 状态码分类和解释及服务端向前端返回响应时的最完整格式

目前开发的项目很大程度上是为明年的国产化做准备了&#xff0c;所以借这个机会把用了十年的自研系统全部重写&#xff0c;订立更严格的规范&#xff0c;本文记录一下返回格式及对应状态码。 常见 HTTP 状态码及解释 HTTP 状态码用于表示客户端请求的响应状态&#xff0c;它们…...

MySQL系列之如何在Linux只安装客户端

导览 前言Q&#xff1a;如何安装一个Linux环境下的MySQL客户端一、准备文件1. 确认Server版本2. 选择Client安装文件 二、下载并安装1. 下载1.1 寻找文件1.2 文件说明 2. 安装2.1 上传至Linux服务器2.2 执行安装 三、连接验证1. 确认远程授权2. 建立远程连接 结语精彩回放 前言…...

内核设备树,你真的了解吗?

在嵌入式系统和内核开发中&#xff0c;设备树&#xff08;Device Tree, 简称 DT&#xff09;扮演着至关重要的角色&#xff0c;帮助系统在启动时准确识别硬件配置并匹配合适的驱动程序。虽然设备树应用广泛&#xff0c;但其结构、工作机制及应用细节却不总是被深入理解。本文将…...

MySQL:客户端工具创建数据库

MySQL 是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;用于存储、管理和检索数据。MySQL是基于SQL语言的&#xff0c;它具有高效、可靠、易用的特点。 客户端工具 这个mysqld.exe就在计算机安装的数据可服务&#xff0c;启动之后&#xff0c;mys…...

Linux笔记之pandoc实现各种文档格式间的相互转换

Linux笔记之pandoc实现各种文档格式间的相互转换 code review! 文章目录 Linux笔记之pandoc实现各种文档格式间的相互转换1.安装 Pandoc2.Word转Markdown3.markdown转html4.Pandoc 支持的一些常见格式4.1.输入格式4.2.输出格式 1.安装 Pandoc sudo apt-get install pandoc # …...

【iOS】知乎日报第三周总结

【iOS】知乎日报第三周总结 文章目录 【iOS】知乎日报第三周总结前言评论区文字评论区的一个展开效果评论区数据的一个请求修改了主页获取数据的逻辑主页无限轮播图图片主色调的一个获取将一些拓展部分的内容写在分类里小结 前言 本周笔者因为金工实习整个项目进展比较慢&#…...

【p2p、分布式,区块链笔记 Torrent】WebTorrent的add和seed函数

在【p2p、分布式&#xff0c;区块链笔记 Torrent】WebTorrent的上传和下载界面的示例中&#xff0c;主要通过WebTorrent类的add和seed函数实现相关功能。这两个函数都返回一个Torrent类对象的实例。 seed函数 import createTorrent, { parseInput } from create-torrent // &…...

Redis穿透、击穿、雪崩

redis是一款常用的非关系型数据库&#xff0c;我们常用与作为数据缓存的组件。 接下来介绍一下面试中常被问到的三个概念以及简单的解决方法。 穿透 什么叫缓存穿透 缓冲穿透&#xff0c;是当有一个请求过来时&#xff0c;查询redis缓存不存在&#xff0c;又去查询数据库&…...

VBA高级应用30例应用3在Excel中的ListObject对象:插入行和列

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…...