spring boot項目整合百度翻譯

本片文章教大家怎樣在spring boot項目中引入百度翻譯,并且優雅的使用百度翻譯。

首先,我們要了解為什么要使用翻譯插件。為了支持多語言的國際化;

目前市面上最常見的后端國際化就是在resource資源目錄下設置多個語言文檔,這些文檔中是一些key、value類型的鍵值對,然后我們展示的時候語言不直接寫死,而是通過使用key的形式來進行引用,從而實現國際化的方式。但是這種方式有很大的局限性。我們要做的國際化只能是一些提前寫死的鍵值。這就很不友好了;

我們公司的業務需求是,我只要點擊切換語言之后。中文的就是中文環境,點擊切換英文之后,就是英文環境了。這就需要我們至少需要多套語言環境,如果是中文,那么所有的中文數據都放在中文的數據庫中,如果是英文,那么所有的英文數據都放在英文的數據庫。多語言的環境直接切換出來。這個時候就需要我們就行翻譯了,直接把一整條數據就行翻譯,飯后插入到不同的語言環境(數據庫)中。本次使用百度的翻譯插件

1、進入百度翻譯官網,注冊賬號

百度翻譯開放平臺

進入官網,登錄、注冊,并且申請相應的賬號。

然后,點擊產品服務,選擇相應的服務類型;

最后,在管理控制臺的開發者信息中找到自己額度appID和相應的密鑰

2、創建spring boot項目,整合翻譯接口

由于我們調用百度的翻譯接口時通過網絡請求來調用的,所以,我們不需要引入任何第三方的百度APi依賴。

基本的maven依賴如下:

 <!-- 依賴配置 --><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--            自動裝配依賴--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><!--自動裝配依賴非必需依賴,該依賴作用是在使用IDEA編寫配置文件有代碼提示--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId></dependency><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId></dependency></dependencies>

我想要實現的功能是,傳入一個Object類型的對象,或者泛型T。不管這個對象中有多少屬性,我們只翻譯其中的String類型的屬性,并且這個String類型的屬性值不為null,并且不為空字符串。并且自定義了一個注解,只要在屬性值上加上了這個注解,那么,這個屬性值也不會被翻譯了。

最后,我想要寫成翻譯的jar包,打到我們公司的maven私服上。只要在項目中引入了翻譯的maven坐標就可以直接使用了。

自定義一個注解,這個注解的作用是,加上這個注解的屬性值不會被翻譯。

/*** 不進行翻譯的字段注解*/
@Target(ElementType.FIELD) // 只能應用于字段
@Retention(RetentionPolicy.RUNTIME) // 運行時保留,便于反射獲取
public @interface NoTranslation {// 可選:添加屬性如原因說明String reason() default "";
}

自定義屬性類,用來獲取到百度翻譯的一些屬性值。

@ConfigurationProperties("tools.translate.baidu")
@Component
@Data
public class BaiDuTranslateParams {/*** 百度翻譯的appId*/private String appId;/*** 百度翻譯的密鑰*/private String secretKey;/*** 翻譯的源語言,默認為自動檢測語言*/private String from="auto";/*** 翻譯的目標語言,默認為英文*/private String to="en";/*** 翻譯的url*/private String url;
}

翻譯的url是根據你選擇的不同翻譯服務來的,可以去百度翻譯的官網查看相應的翻譯地址。我使用的是百度的通用翻譯,所以引用百度的通用翻譯的url地址。

設置百度翻譯的MD5工具類,這個百度翻譯的MD5工具是百度翻譯官方提供的,所以不是隨便的一個MD5生成器就可以使用的。

/*** MD5編碼相關的類* * @author wangjingtao* */
public class MD5 {// 首先初始化一個字符數組,用來存放每個16進制字符private static final char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd','e', 'f' };/*** 獲得一個字符串的MD5值* * @param input 輸入的字符串* @return 輸入字符串的MD5值* */public static String md5(String input) {if (input == null)return null;try {// 拿到一個MD5轉換器(如果想要SHA1參數換成”SHA1”)MessageDigest messageDigest = MessageDigest.getInstance("MD5");// 輸入的字符串轉換成字節數組byte[] inputByteArray = input.getBytes(StandardCharsets.UTF_8);// inputByteArray是輸入字符串轉換得到的字節數組messageDigest.update(inputByteArray);// 轉換并返回結果,也是字節數組,包含16個元素byte[] resultByteArray = messageDigest.digest();// 字符數組轉換成字符串返回return byteArrayToHex(resultByteArray);} catch (NoSuchAlgorithmException e) {return null;}}/*** 獲取文件的MD5值* * @param file* @return*/public static String md5(File file) {try {if (!file.isFile()) {System.err.println("文件" + file.getAbsolutePath() + "不存在或者不是文件");return null;}FileInputStream in = new FileInputStream(file);String result = md5(in);in.close();return result;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}public static String md5(InputStream in) {try {MessageDigest messagedigest = MessageDigest.getInstance("MD5");byte[] buffer = new byte[1024];int read = 0;while ((read = in.read(buffer)) != -1) {messagedigest.update(buffer, 0, read);}in.close();String result = byteArrayToHex(messagedigest.digest());return result;} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}private static String byteArrayToHex(byte[] byteArray) {// new一個字符數組,這個就是用來組成結果字符串的(解釋一下:一個byte是八位二進制,也就是2位十六進制字符(2的8次方等于16的2次方))char[] resultCharArray = new char[byteArray.length * 2];// 遍歷字節數組,通過位運算(位運算效率高),轉換成字符放到字符數組中去int index = 0;for (byte b : byteArray) {resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];resultCharArray[index++] = hexDigits[b & 0xf];}// 字符數組組合成字符串返回return new String(resultCharArray);}}

設置百度翻譯的響應結果的工具類:

@Data
public class BaiduTranslationUtils{private String from;private String to;private List<TranslationResult> trans_result;//    // 獲取第一個翻譯結果(安全處理空列表)
//    public TranslationResult getFirstTranslation() {
//        return trans_result != null && !trans_result.isEmpty() ?
//                trans_result.getFirst() : null;
//    }// 內部類表示單個翻譯結果@Datapublic static class TranslationResult {private String src;private String dst;}
}

設置HTTP的發送請求工具類;本次使用HTTPClient來繼續HTTP請求的發送。

@Component
@RequiredArgsConstructor
public class HttpClientUtils {private final RestTemplate restTemplate;/*** 發送 application/x-www-form-urlencoded 格式的 POST 請求* @param url 請求地址* @param formData 表單數據 (鍵值對)* @param responseType 返回類型* @return ResponseEntity 包含響應體和狀態碼*/public <T> ResponseEntity<T> postForm(String url,MultiValueMap<String, Object> formData,Class<T> responseType) {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, Object>> entity = newHttpEntity<>(formData, headers);return restTemplate.exchange(url,HttpMethod.POST,entity,responseType);}/*** 發送 application/x-www-form-urlencoded 格式的 POST 請求(Map 簡化版)* @param url 請求地址* @param formData 表單數據 (鍵值對)* @param responseType 返回類型* @return ResponseEntity 包含響應體和狀態碼*/public <T> ResponseEntity<T> postForm(String url,Map<String, String> formData,Class<T> responseType) {MultiValueMap<String, Object> multiValueMap =new LinkedMultiValueMap<>();formData.forEach(multiValueMap::add);return postForm(url, multiValueMap, responseType);}public <T> ResponseEntity<T> request(String url,HttpMethod method,Object requestBody,HttpHeaders headers,MultiValueMap<String, String> params,Class<T> responseType) {// 構建帶參數的URLUriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);if (params != null && !params.isEmpty()) {builder.queryParams(params);}String finalUrl = builder.build().encode().toUriString();HttpEntity<Object> entity = new HttpEntity<>(requestBody, headers);return restTemplate.exchange(finalUrl, method, entity, responseType);}}

設置百度翻譯的發送請求的service類,用來發送百度請求,接收一個List<String>類型的參數,接收翻譯的源語言和目標語言。

@Service
@RequiredArgsConstructor
@Slf4j
public class BaiduTranslateService {private final BaiDuTranslateParams config;
private final ObjectMapper objectMapper;private  final HttpClientUtils httpClient;public List<String> translate(List<String> texts, String from, String to) throws Exception {String salt = String.valueOf(System.currentTimeMillis());String query = String.join("\n", texts);String md=config.getAppId() + query +salt +config.getSecretKey();String sign= MD5.md5(md);Map<String, Object>  params = new HashMap<>();params.put("q", query);params.put("from", from);params.put("to", to);params.put("appid", config.getAppId());params.put("salt", salt);params.put("sign", sign);MultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();requestParams.setAll(params);ResponseEntity<Object> response =httpClient.postForm(config.getUrl(), requestParams, Object.class);Object body = response.getBody();if (body == null) {return Collections.singletonList("翻譯失敗");}BaiduTranslationUtils result = objectMapper.readValue(JSON.toJSONString(body), BaiduTranslationUtils.class);return result.getTrans_result().stream().map(BaiduTranslationUtils.TranslationResult::getDst).collect(Collectors.toList());}
}

設置翻譯發送的工具類,用來發送翻譯的請求。我們想要實現的這樣;我傳入一個T泛型的對象,

然后返回一個T泛型的對象。只翻譯這個對象中的String類型的屬性,其他屬性不翻譯。String類型的屬性也不是說全部翻譯的,String屬性為null或者為空字符串,或者在String屬性上加上了@NoTranslation不翻譯注解。這幾種情況下的String屬性都不進行翻譯。

工具類中有三個方法;

1、傳入T 泛型對象,返回T翻譯好的對象。

2、傳入T泛型對象,傳入翻譯的源語言,傳入翻譯的目標語言。返回T翻譯好的對象

3、傳入List<T>泛型對象,傳入翻譯的源語言,傳入翻譯的目標語言。返回T翻譯好的對象

要注意,百度翻譯的字符數量一次大概限定在6000個字符,換算成文字大概為2000個漢字。

相應的翻譯工具類如下:

/*** @Author 張喬* @Date 2025/5/29 14:21*/
@Component
@RequiredArgsConstructor
@Slf4j
public class BaiduTranslationSend {private static final Logger logger = LoggerFactory.getLogger(BaiduTranslationSend.class);private final BaiduTranslateService translateService;private final BaiDuTranslateParams baiDuTranslateParams;/*** 批量翻譯對象列表中所有標記為可翻譯的字段* 該方法遍歷對象列表中的每個對象,識別帶有@Translatable注解的字段,收集需要翻譯的文本,* 通過翻譯服務進行批量翻譯,最后將翻譯結果回寫到原對象的對應字段中。** @param <T> 對象類型* @param objList 待翻譯的對象列表(允許為null或空列表)* @param fromLang 原始語言代碼(支持"0"/"1"/"2"數字代碼自動轉換)* @param toLang 目標語言代碼(支持"0"/"1"/"2"數字代碼自動轉換)* @return 翻譯后的對象列表(發生錯誤時返回原列表)*/public <T> List<T> translateObjectFieldsList(List<T> objList, String fromLang, String toLang) {if (objList == null || objList.isEmpty()) {logger.warn("傳入對象列表為空或空列表,無法進行翻譯操作。");return objList;}// 語言代碼轉換(復用單個對象的轉換邏輯)Map<String, String> langCodeMap = Map.of("0", "zh", "1", "en", "2", "jp");fromLang = langCodeMap.getOrDefault(fromLang, fromLang);toLang = langCodeMap.getOrDefault(toLang, toLang);try {// 1. 收集所有需要翻譯的文本及其元數據List<TextTranslationTask> translationTasks = new ArrayList<>();Map<Class<?>, List<Field>> classFieldCache = new HashMap<>();for (T obj : objList) {if (obj == null) continue;// 獲取或緩存類字段信息List<Field> translatableFields = classFieldCache.computeIfAbsent(obj.getClass(),this::getTranslatableFields);for (Field field : translatableFields) {try {String value = (String) field.get(obj);if (isValidForTranslation(value)) {translationTasks.add(new TextTranslationTask(obj, field, value));}} catch (IllegalAccessException e) {logger.warn("對象 [{}] 字段 [{}] 訪問失敗: {}",obj.getClass().getSimpleName(), field.getName(), e.getMessage());}}}// 2. 如果沒有需要翻譯的內容,提前返回if (translationTasks.isEmpty()) {logger.info("列表中共 {} 個對象,均無可翻譯字段", objList.size());return objList;}// 3. 提取所有需要翻譯的文本List<String> textsToTranslate = translationTasks.stream().map(task -> task.originalText).collect(Collectors.toList());// 4. 批量翻譯(支持自動分批處理大量文本)List<String> translatedTexts = translateService.translate(textsToTranslate, fromLang, toLang);// 5. 應用翻譯結果到所有對象applyBatchTranslations(translationTasks, translatedTexts);logger.info("成功翻譯 {} 個對象中的 {} 個字段",objList.size(), translationTasks.size());return objList;} catch (Exception e) {logger.error("批量翻譯對象列表時出錯: {}", e.getMessage(), e);return objList; // 出錯時返回原列表}}// 翻譯任務內部類(記錄文本的元數據)private static class TextTranslationTask {final Object targetObject;final Field targetField;final String originalText;TextTranslationTask(Object targetObject, Field targetField, String originalText) {this.targetObject = targetObject;this.targetField = targetField;this.originalText = originalText;}}// 批量應用翻譯結果private void applyBatchTranslations(List<TextTranslationTask> tasks, List<String> translatedTexts) {if (tasks.size() != translatedTexts.size()) {logger.error("翻譯結果數量 {} 與任務數量 {} 不匹配",translatedTexts.size(), tasks.size());return;}for (int i = 0; i < tasks.size(); i++) {TextTranslationTask task = tasks.get(i);String translatedText = translatedTexts.get(i);try {task.targetField.set(task.targetObject, translatedText);} catch (IllegalAccessException e) {logger.error("設置對象 [{}] 字段 [{}] 翻譯值失敗: {}",task.targetObject.getClass().getSimpleName(),task.targetField.getName(),e.getMessage());}}}// 復用單個對象翻譯的字段獲取方法private List<Field> getTranslatableFields(Class<?> clazz) {return TRANSLATABLE_FIELD_CACHE.computeIfAbsent(clazz, k -> {List<Field> fields = new ArrayList<>();Class<?> current = clazz;while (current != null && current != Object.class) {for (Field field : current.getDeclaredFields()) {if (field.getType() == String.class &&!field.isAnnotationPresent(NoTranslation.class)) {field.setAccessible(true);fields.add(field);}}current = current.getSuperclass();}return Collections.unmodifiableList(fields);});}/*** 翻譯對象的字符串字段。** @param <T> 對象的類型* @param obj 需要翻譯的對象*/public <T> T translateObjectFields(T obj) {// 1. 空對象檢查if (obj == null) {logger.warn("傳入對象為空,無法進行翻譯操作。");return null;}try {// 3. 獲取可翻譯字段(帶緩存)List<Field> translatableFields = getTranslatableFields(obj.getClass());// 4. 收集需要翻譯的字段值Map<Field, String> fieldValueMap = new LinkedHashMap<>();List<String> textsToTranslate = new ArrayList<>();for (Field field : translatableFields) {try {String value = (String) field.get(obj);if (isValidForTranslation(value)) {fieldValueMap.put(field, value);textsToTranslate.add(value);}} catch (IllegalAccessException e) {logger.warn("字段 [{}] 訪問失敗: {}", field.getName(), e.getMessage());}}// 5. 無翻譯內容提前返回if (textsToTranslate.isEmpty()) {logger.debug("類型 [{}] 無可翻譯字段", obj.getClass().getSimpleName());return obj;}// 6. 執行批量翻譯List<String> translatedTexts = translateService.translate(textsToTranslate,baiDuTranslateParams.getFrom(), baiDuTranslateParams.getTo());// 7. 回填翻譯結果(帶安全檢查)applyTranslations(obj, fieldValueMap, translatedTexts);logger.info("成功翻譯 {} 個字段: [{}]",fieldValueMap.size(), obj.getClass().getSimpleName());return obj;} catch (Exception e) {logger.error("翻譯對象 [{}] 時出錯: {}",obj.getClass().getSimpleName(), e.getMessage(), e);return obj; // 出錯時返回原對象而非null}}/*** 翻譯對象中的字符串字段。** @param <T>      對象類型* @param obj      需要翻譯的對象* @param fromLang 源語言* @param toLang   目標語言*/// 類級緩存,避免重復反射掃描private static final Map<Class<?>, List<Field>> TRANSLATABLE_FIELD_CACHE = new ConcurrentHashMap<>();public <T> T translateObjectFields(T obj, String fromLang, String toLang) {// 1. 空對象檢查if (obj == null) {logger.warn("傳入對象為空,無法進行翻譯操作。");return null;}// 2. 語言代碼轉換(使用Map更靈活)Map<String, String> langCodeMap = Map.of("0", "zh", "1", "en", "2", "jp");fromLang = langCodeMap.getOrDefault(fromLang, fromLang);toLang = langCodeMap.getOrDefault(toLang, toLang);try {// 3. 獲取可翻譯字段(帶緩存)List<Field> translatableFields = getTranslatableFields(obj.getClass());// 4. 收集需要翻譯的字段值Map<Field, String> fieldValueMap = new LinkedHashMap<>();List<String> textsToTranslate = new ArrayList<>();for (Field field : translatableFields) {try {String value = (String) field.get(obj);if (isValidForTranslation(value)) {fieldValueMap.put(field, value);textsToTranslate.add(value);}} catch (IllegalAccessException e) {logger.warn("字段 [{}] 訪問失敗: {}", field.getName(), e.getMessage());}}// 5. 無翻譯內容提前返回if (textsToTranslate.isEmpty()) {logger.debug("類型 [{}] 無可翻譯字段", obj.getClass().getSimpleName());return obj;}// 6. 執行批量翻譯List<String> translatedTexts = translateService.translate(textsToTranslate, fromLang, toLang);// 7. 回填翻譯結果(帶安全檢查)applyTranslations(obj, fieldValueMap, translatedTexts);logger.info("成功翻譯 {} 個字段: [{}]",fieldValueMap.size(), obj.getClass().getSimpleName());return obj;} catch (Exception e) {logger.error("翻譯對象 [{}] 時出錯: {}",obj.getClass().getSimpleName(), e.getMessage(), e);return obj; // 出錯時返回原對象而非null}}// 判斷字符串是否適合翻譯private boolean isValidForTranslation(String value) {return value != null && !value.trim().isEmpty();}// 應用翻譯結果到對象字段private <T> void applyTranslations(T obj, Map<Field, String> fieldMap, List<String> translations) {if (fieldMap.size() != translations.size()) {logger.error("翻譯結果數量 {} 與字段數量 {} 不匹配",translations.size(), fieldMap.size());return;}int index = 0;for (Map.Entry<Field, String> entry : fieldMap.entrySet()) {Field field = entry.getKey();try {field.set(obj, translations.get(index++));} catch (IllegalAccessException e) {logger.error("設置字段 [{}] 翻譯值失敗: {}", field.getName(), e.getMessage());}}}}

然后,記得打成jar包的形式。

如果,不知道第三方spring boot的jar包怎樣打的,可以查看一下我的這篇文章。

springboot3自定義starter(詳細入門)-CSDN博客

然后,在項目中引入下相應的maven坐標。在yml配置文件中引入相應的百度翻譯的屬性值。

那么,現在就可以使用這個翻譯配置類了。

在Test測試類中寫一個測試方法:

相應的運行結果如下:

因為這個屬性里面只有兩個屬性是String類型需要翻譯,所以只翻譯了兩個屬性。我這邊源語言是百度自動識別,目標語言是小日子語。

翻譯工具類的原理是,收集傳入T泛型的所有需要翻譯的String屬性值,統一存放在一個List<String>中,然后,在通過拼接換行符\n的形式來發送翻譯請求。

百度翻譯相應的參數中有翻譯的原始數據和翻譯之后的目標數據,通過進行比對,再把翻譯后的目標數據填充到相應的泛型對象T中。

以上,就是正片文章的內容了。如果覺得文章寫的不錯,請給博主點個贊,非常感謝!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/912557.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/912557.shtml
英文地址,請注明出處:http://en.pswp.cn/news/912557.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

凌晨2點自動備份mysql 數據庫,mysql_backup.sh

1、編寫備份腳本&#xff1a;vim mysql_backup.sh #!/bin/bash DATE$(date %Y%m%d_%H%M%S) BACKUP_DIR"/data/mysql/backup" USER"backup_user" PASSWORD"backup**"# 邏輯備份所有數據庫 mysqldump -u$USER -p$PASSWORD eblp | gzip > $BA…

Linux系統之Tomcat服務

目錄 一、Tomcat概述 1、Tomcat介紹 2、Tomcat歷史 二、Tomcat原理分析 1、Http工作原理 2、Tomcat整體架構 3、Coyote連接器架構 4、Catalina容器架構 5、Jasper處理流程 6、JSP編譯過程 7、Tomcat啟動流程 8、Tomcat請求處理流程 三、Tomcat安裝與配置 1、單實…

FPGA芯片的供電

FPGA芯片的供電 文章目錄 FPGA芯片的供電1. 外部端口供電機制2. 內部邏輯供電機制3. 專有電路供電機制4. 電源穩定性討論總結 1. 外部端口供電機制 FPGA是專門用于數字系統設計的芯片&#xff0c;能夠正確、可靠、高效地和外界其他數字電路進行通信是FPGA芯片必備的一個功能。…

構建可無限擴展的系統:基于 FreeMarker + 存儲過程 + Spring Boot 的元數據驅動架構設計

在構建面向多行業、多客戶的大型業務系統時&#xff0c;系統的靈活性與擴展能力成為架構設計的核心目標。傳統硬編碼的開發方式在面對高頻變化、復雜組合查詢、多租戶自定義字段時&#xff0c;往往難以適應。 為了解決上述問題&#xff0c;我們提出一種 以 FreeMarker 腳本托管…

2-深度學習挖短線股-3-訓練數據計算

2-3 合并輸入特征 首先定義了數據預處理函數&#xff0c;將連續 n 天的 K 線數據&#xff08;如開盤價、收盤價、成交量等&#xff09;合并為一行特征&#xff0c;同時保留對應的目標標簽&#xff08;buy 列&#xff0c;表示是否應該買入&#xff09;&#xff1b;然后讀取股票代…

SpringMVC系列(四)(請求處理的十個實驗(下))

0 引言 作者正在學習SpringMVC相關內容&#xff0c;學到了一些知識&#xff0c;希望分享給需要短時間想要了解SpringMVC的讀者朋友們&#xff0c;想用通俗的語言講述其中的知識&#xff0c;希望與諸位共勉&#xff0c;共同進步&#xff01; 本系列會持續更新&#xff01;&…

產線通信“變形記”:PROFIBUS-DP與ETHERNET/IP的食品飲料跨界融合

在食品飲料加工行業&#xff0c;為實現不同設備間高效通信&#xff0c;JH-PB-EIP疆鴻智能PROFIBUS DP轉ETHERNET/IP網關發揮著關鍵作用。西門子PLC常采用PROFIBUS DP協議&#xff0c;而碼垛機器人等設備多使用ETHERNET/IP協議&#xff0c;網關成為連接二者的橋梁。 將DP作為從站…

設計模式-觀察者模式(發布訂閱模式)

一、需要的類 一個發布類&#xff1a;里面一個是別人需要訂閱的屬性&#xff0c;以及用于存儲訂閱者的list&#xff0c;attach方法是往list集合里面添加元素&#xff0c;notifyObservers通知方法&#xff0c;也就是循環調用訂閱者里面的一個方法&#xff0c;這個notifyObserve…

Linux測試是否能聯網

ping百度看是否有返回包&#xff1a; ping www.baidu.com ping -c可以通過參數提前設置發送的包數量&#xff1a; ping -c 4 www.baidu.com 終止ping快捷鍵&#xff1a; 按下 Ctrl C&#xff1a;立即終止ping進程&#xff0c;并顯示統計信息。按下 Ctrl Z&#xff1a;將進…

TOGAF? 架構分區:優秀架構的秘密

TOGAF &#xff08;The Open Group架構框架&#xff09;已成為企業架構事實上的全球標準, 是世界上使用最廣泛的企業架構框架。 它為企業 IT 架構的設計、規劃、實施和管理提供了一套全面的方法和工具。但是&#xff0c;即使是經驗豐富的架構師也經常會忽略 TOGAF 中隱藏的寶…

如何讓視頻在特定的網站上播放/禁止播放?(常見的視頻防盜鏈技術之一)

一、需求背景 在各行各業中,不論是教育、貿易還是醫療領域,視頻內容都存在被盜用的風險。為加強視頻安全性,我們可以采取特殊設置措施,例如限制視頻僅在高安全性網站播放,或屏蔽高風險網站。那么,具體有哪些方法可以有效保護視頻安全呢? 二、需求解決 通過OVP防盜鏈技…

如何調鼠標的靈敏度 快速調節超簡單

鼠標靈敏度是指鼠標在移動時&#xff0c;指針在屏幕上移動的速度。適當的鼠標靈敏度不僅能夠提高工作效率&#xff0c;還能減少手部疲勞&#xff0c;優化游戲體驗。那么不同的使用場景&#xff0c;鼠標靈敏度怎么調呢&#xff1f;本文將詳細探討如何調整鼠標靈敏度&#xff0c;…

基于單次常規腦MRI的深度學習檢測多發性硬化癥急性和亞急性病變活動性|文獻速遞-最新論文分享

Title 題目 Deep learning detection of acute and sub-acute lesion activity from single-timepoint conventional brain MRI in multiple sclerosis 基于單次常規腦MRI的深度學習檢測多發性硬化癥急性和亞急性病變活動性 01 文獻速遞介紹 多發性硬化癥&#xff08;MS&am…

CloudFormation 實現 GitHub Actions OIDC 與 AWS ECR 的安全集成

引言:現代 CI/CD 的安全挑戰 在容器化應用部署流程中,傳統長期憑證管理已成為主要安全痛點。本文將詳細介紹如何通過 AWS CloudFormation 實現 GitHub Actions 與 Amazon ECR 的安全集成,利用 OIDC(OpenID Connect)技術消除長期憑證風險,構建符合企業級安全標準的 CI/CD…

JMeter常用斷言方式

簡介 接口斷言是接口測試中用于驗證響應結果是否符合預期的關鍵機制&#xff0c;根據業務需求編寫腳本添加斷言&#xff0c;可驗證接口的正確性。以下內容僅記錄常用的斷言方式&#xff0c;多個接口都有斷言時可以使用事務控制器來隔離不同的斷言。 斷言方式 1、響應斷言 1.…

web服務器搭建nginx

1 配置主機ip 1.1獲取主機ip ip a rootpc:/home/ruxin# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft foreve…

ubuntu ollama 遇到的若干問題

服務器原先有ollama&#xff0c;想要重裝&#xff0c;遇到一系列問題 安裝下載連接&#xff1a;https://github.com/ollama/ollama/blob/main/docs/linux.md模型下載鏈接&#xff1a;https://ollama.com/library/deepseek-r1:1.5b 一、安裝新的ollama 在root用戶下操作 1.卸…

Linux: errno: EMSGSIZE 5

最近看到一個envoy在發送UDP包時返回的錯誤:sendmsg failed with error code 5 這里的error code 5其實是,envoy自己定義的error code: case SOCKET_ERROR_MSG_SIZE:return IoErrorCode::MessageTooBig;class IoError {public:enum class

深度剖析 LNK 參數隱藏攻擊 (ZDI-CAN-25373)

1、漏洞描述 ZDI-CAN-25373 是一個 Windows 快捷方式文件(.LNK)漏洞,它允許攻擊者通過精心制作的惡意快捷方式文件來執行隱藏的惡意命令。攻擊者通過在 .LNK 文件的 COMMAND_LINE_ARGUMENTS 結構中填充大量空白字符(如空格、水平制表符、換行符等)來隱藏惡意命令。這些填…

Linux操作系統筆記3

接口管理命令&#xff1a; ip命令 字符終端 nmcli命令 字符終端 nmtui命令 可視化終端 ip命令&#xff1a; 使用 ip 命令可以配置臨時網絡的連接信息&#xff0c;相關命令如下&#xff1a; ip link&#xff1a;顯示網絡設備運行狀態 ip -s link&#xff1a;顯示更詳細的設備信…