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

SpringBoot国际化配置组件支持本地配置和数据库配置

文章目录

  • 0. 前言
  • i18n-spring-boot-starter
  • 1. 使用方式
    • 0.引入依赖
    • 1.配置项
    • 2.初始化国际化配置表
    • 3.如何使用
  • 2. 核心源码
    • 实现一个拦截器I18nInterceptor
    • I18nMessageResource 加载国际化配置
  • 3.源码地址

在这里插入图片描述

0. 前言

写个了原生的SpringBoot国际化配置组件支持本地配置和数据库配置

背景:最近花时间把项目用到的国际化组件Starter 重构了一下,使用更简单。基本上支持从本地配置读取和数据库配置读取,支持web端和小程序等移动端的国际化需求。

i18n-spring-boot-starter

1. 使用方式

Spring Boot 国际化组件

0.引入依赖

代码在本地打包后
给需要国际化的工程引入


<dependency><groupId>com.bdkjzx.project</groupId><artifactId>i18n-spring-boot-starter</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

1.配置项


#添加国际化
spring.ex.i18n.enable=true
# 如果未翻译是否将code 初始化入库
spring.ex.i18n.mark=false
spring.ex.i18n.default-locale=zh-CN
spring.ex.i18n.data-source=primary
spring.ex.i18n.config-table=config_i18n_message

2.初始化国际化配置表


CREATE TABLE `config_i18n_message` (`code` varchar(128)   NOT NULL,`zh-CN` varchar(128)  DEFAULT NULL,`zh-TW` varchar(128)  DEFAULT NULL,`en-US` varchar(1024)   DEFAULT NULL COMMENT '英文',PRIMARY KEY (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='国际化配置表'

如果本地配置的话使用原生配置方式.缺点是需要手动更新,并且每个服务都需要配置。建议使用数据库表配置
messages_zh_CN.properties , messages_en_US.properties

3.如何使用

I.n("操作成功")

或者在返回的统一结果对象上,以下是个示例,你需要加在你的项目的统一响应中

public class ApiResponse<T> {private int code;private String message;private T data;private ErrorDetails error;public ApiResponse() {}/*** message给消息进行国际化包装* @param message*/public ApiResponse(int code, String message, T data, ErrorDetails error) {this.code = code;this.message = I.n(message);this.data = data;this.error = error;}// Getter and Setter methodspublic int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMessage() {return message;}/*** 给消息进行国际化包装* @param message*/public void setMessage(String message) {this.message = I.n(message);}public T getData() {return data;}public void setData(T data) {this.data = data;}public ErrorDetails getError() {return error;}public void setError(ErrorDetails error) {this.error = error;}
}

5.扩展请看入口

  com.bdkjzx.project.i18n.config.I18nAutoConfig

2. 核心源码

package com.bdkjzx.project.i18n.config;import com.bdkjzx.project.i18n.I18nHolder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "spring.ex.i18n")
@Setter
@Getter
public class I18nProperties {/*** 是否启用国际化功能:<br>*     - 启用:会创建和国际化相关的数据源、缓存等等;<br>*     - 不启用:{@link I18nHolder} 可以正常使用,返回原值,不会创建国际化相关的各种Bean<br>**  默认:不启用,需要手动开启*/private Boolean enable = false;/*** 国际化数据表所在的数据源,入需指定,则写入数据源名称。<br>*     此配置的作用是允许多个服务通过共享一个i18n配置表,从而共用一套i18n翻译。<br>*     默认为空,表示使用primary数据源。*/private String dataSource = "primary";/*** 默认地区(语言)*/private String defaultLocale = "zh_CN";/*** 查询i18n配置表的名称,用于自定义修改表。<br>*     默认:config_i18n_message*/private String configTable = "config_i18n_message";/*** i18n配置表的字段名。根据i18n配置表决定此配置<br>*  默认:code*/private String configCodeColumn = "code";/*** i18n缓存更新时间(小时数),会提供手工刷新缓存的入口,所以不必频繁刷新<br>*     默认值为-1,表示长期有效。<br>*/private Integer cacheHours = -1;/*** 当未找到i18n的code时,是否将其记录到表中,以便统一处理<br>*     默认:关闭*/private Boolean mark = false;/*** 用于记录无效code的线程池缓冲区大小*/private Integer markPoolSize = 2000;/*** 是否在 {@link com.bdkjzx.project.i18n.repository.I18nMessageResource} 未找到配置时,再使用Spring默认方案,*     从本地加载国际化资源。*  默认:关闭*/private Boolean useLocale = false;}
package com.bdkjzx.project.i18n.config;import com.bdkjzx.project.i18n.I18nHolder;
import com.bdkjzx.project.i18n.filter.I18nFilter;import com.bdkjzx.project.i18n.repository.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.context.MessageSourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import com.bdkjzx.project.i18n.interceptor.I18nInterceptor;import javax.sql.DataSource;
import java.util.Locale;
import java.util.concurrent.Executor;@Configuration
@EnableConfigurationProperties({I18nProperties.class})
@Slf4j
public class I18nAutoConfig {@Beanpublic I18nHolder getI18nUtil(@Autowired(required = false) I18nMessageResource messageSource,@Autowired(required = false) I18nLocaleHolder i18nLocaleHolder,@Autowired I18nProperties i18NProperties) {// 不论是否启用都会配置,保证这个工具类不会报错return i18NProperties.getEnable() ? new I18nHolder(messageSource, i18nLocaleHolder) : new I18nHolder();}@ConditionalOnProperty(prefix = "spring.ex.i18n", name = "enable", havingValue = "true")@Configurationstatic class I18nFilterConfig {@Autowiredprivate I18nLocaleHolder i18nLocaleHolder;@Beanpublic I18nFilter i18nFilter() {I18nFilter i18nFilter = new I18nFilter();I18nInterceptor interceptor = new I18nInterceptor();interceptor.setI18nLocaleHolder(i18nLocaleHolder);i18nFilter.setI18nInterceptor(interceptor);return i18nFilter;}}@ConditionalOnProperty(prefix = "spring.ex.i18n", name = "enable", havingValue = "true")@Configuration@EnableCaching@ComponentScan("com.bdkjzx.project.i18n")static class I18nResourceConfig {/*** 采用默认的配置文件配置 messages开头的文件,编码为utf8<br>* 如 messages_zh_CN.properties ,  messages_en_US.properties** @return {@link MessageSourceProperties}*/@Beanpublic MessageSourceProperties messageSourceProperties() {return new MessageSourceProperties();}@Beanpublic ResourceBundleMessageSource initResourceBundleMessageSource(MessageSourceProperties messageSourceProperties) {ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();resourceBundleMessageSource.setBasename(messageSourceProperties.getBasename());resourceBundleMessageSource.setDefaultEncoding(messageSourceProperties.getEncoding().name());return resourceBundleMessageSource;}@Bean@Autowiredpublic I18nMessageResource initMessageResource(ResourceBundleMessageSource resourceBundleMessageSource,I18nLocaleHolder i18NLocaleSettings) {I18nMessageResource i18nMessageResource = new I18nMessageResource(i18NLocaleSettings.getDefaultLocale());i18nMessageResource.setParentMessageSource(resourceBundleMessageSource);return i18nMessageResource;}@Bean@Autowiredpublic I18nLocaleHolder getI18nLocaleSetting(I18nProperties i18nProperties) {Locale locale;try {locale = new Locale.Builder().setLanguageTag(i18nProperties.getDefaultLocale().replace("_", "-").toLowerCase()).build();} catch (Exception e) {log.error(String.format("解析默认语言时出现错误, setting = %s", i18nProperties.getDefaultLocale()), e);throw new IllegalArgumentException("解析默认语言时出现错误,请查看日志");}return new I18nLocaleHolder(locale);}@Bean(name = "i18nJdbcTemplate")@ConditionalOnMissingBean(name = "i18nJdbcTemplate")public JdbcTemplate getJdbcTemplate(@Autowired(required = false) @Qualifier("i18nDataSource") DataSource i18nDataSource) {try {if (i18nDataSource == null) {log.error("未配置国家化数据源,请使用@Bean构造一个名为i18nDataSource的DataSource或者直接重新此方法");}return new JdbcTemplate(i18nDataSource);} catch (BeansException e) {log.error("无效的数据源{}", i18nDataSource, e);throw new IllegalArgumentException("创建数据源时出现错误,请查看日志");}}@Autowired@Bean(name = "defaultI18nDataLoadService")public I18nConfigDbLoader getI18nDataLoadService(I18nProperties i18nProperties,@Qualifier("i18nJdbcTemplate") JdbcTemplate jdbcTemplate) {return new SimpleI18NConfigDbLoaderImpl(i18nProperties.getConfigCodeColumn(),i18nProperties.getConfigTable(), jdbcTemplate);}@Autowired@Bean(name = "i18nCacheManager")public CacheManager getCacheManager(I18nProperties i18nProperties) {CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();if (i18nProperties.getCacheHours() > 0) {// 缓存创建后,经过固定时间(小时),更新caffeineCacheManager.setCacheSpecification(String.format("refreshAfterWrite=%sH", i18nProperties.getCacheHours()));}return caffeineCacheManager;}/*** 线程池配置*/@ConditionalOnProperty(prefix = "spring.ex.i18n", name = "mark", havingValue = "true")@Configuration@EnableAsyncstatic class I18nInvalidMarkerConfig {@Bean("i18nExecutor")@Autowiredpublic Executor getAsyncExecutor(I18nProperties i18NProperties) {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(0);executor.setMaxPoolSize(2);executor.setQueueCapacity(i18NProperties.getMarkPoolSize());executor.setThreadNamePrefix("i18n-executor-");executor.initialize();return executor;}@Beanpublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return new SimpleAsyncUncaughtExceptionHandler();}}}}

实现一个拦截器I18nInterceptor

作用是实现国际化(i18n)功能的拦截器。用于处理Web应用程序的国际化,即根据用户的语言设置显示对应的国际化资源文件。

  1. 从请求的cookie或header中获取语言设置。
  2. 将语言设置存储到i18nLocaleHolder中,以便在后续的请求处理中使用。
  3. 在请求处理完成后,清除i18nLocaleHolder中的语言设置。
package com.bdkjzx.project.i18n.interceptor;import com.bdkjzx.project.i18n.repository.I18nLocaleHolder;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.lang.NonNull;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;import static org.slf4j.LoggerFactory.getLogger;/*** 国际化拦截器,用于处理Web应用的国际化(i18n)。*/
@Slf4j
public class I18nInterceptor implements HandlerInterceptor {private I18nLocaleHolder i18nLocaleHolder;private final Map<String, Locale> localeMap = new HashMap<>(8);private static final String NAME_OF_LANGUAGE_SETTING = "lang";/*** 在实际处理程序方法调用之前执行的预处理方法。* 从请求的cookie或header中获取语言设置,并将其设置到i18nLocaleHolder中。* 如果语言设置为空或无效,则返回true以允许请求继续进行。*/@Overridepublic boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) throws Exception {String lang = getLangFromCookies(request);if (StringUtils.isEmpty(lang)) {lang = getLangFromHeader(request);}if (StringUtils.isEmpty(lang)) {return true;}try {i18nLocaleHolder.setThreadLocale(getLocaleByLang(lang));} catch (Exception e) {log.error("无效的语言设置:{}", lang, e);}return true;}/*** 在完成请求处理后执行的方法。* 清除i18nLocaleHolder中的语言设置。*/@Overridepublic void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) {try {i18nLocaleHolder.clear();} catch (Exception e) {log.error("清理语言设置时遇到错误:", e);}}public I18nLocaleHolder getI18nLocaleHolder() {return i18nLocaleHolder;}public void setI18nLocaleHolder(I18nLocaleHolder i18nLocaleHolder) {this.i18nLocaleHolder = i18nLocaleHolder;}/*** 根据语言设置获取Locale对象。** @param lang 语言设置* @return Locale对象*/private Locale getLocaleByLang(String lang) {return Optional.ofNullable(localeMap.get(lang)).orElseGet(() -> {Locale locale = new Locale.Builder().setLanguageTag(lang).build();localeMap.put(lang, locale);return locale;});}/*** 从cookie中获取国际化语言设置。** @param request HttpServletRequest对象* @return 国际化语言设置*/private static String getLangFromCookies(HttpServletRequest request) {String lang = Optional.ofNullable(request.getCookies()).flatMap(cookies -> Arrays.stream(cookies).filter(cookie -> NAME_OF_LANGUAGE_SETTING.equals(cookie.getName())).findFirst()).map(Cookie::getValue).orElse("");return lang;}/*** 从header中获取国际化语言设置。** @param request HttpServletRequest对象* @return 国际化语言设置*/private String getLangFromHeader(HttpServletRequest request) {String acceptLanguage = request.getHeader("Accept-Language");return Optional.ofNullable(acceptLanguage).map(lang -> lang.split(",")).filter(array -> array.length > 0).map(array -> array[0]).orElse("");}}

I18nMessageResource 加载国际化配置

支持本地和数据库

package com.bdkjzx.project.i18n.repository;import com.bdkjzx.project.i18n.config.I18nProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.lang.NonNull;
import org.springframework.util.StringUtils;import javax.annotation.PostConstruct;
import java.text.MessageFormat;
import java.util.*;
import java.util.function.BiFunction;@Slf4j
public class I18nMessageResource extends AbstractMessageSource implements ResourceLoaderAware {private final Locale defaultLocale;@Autowiredprivate List<I18nConfigDbLoader> i18NConfigDbLoaders;@Autowiredprivate I18nProperties i18NProperties;@Lazy@Autowired(required = false)private I18nConfigDbLoader i18nConfigDbLoader;private final List<BiFunction<String, Locale, String>> getTextFunctionList = new ArrayList<>();public I18nMessageResource(Locale defaultLocale) {this.defaultLocale = defaultLocale;}@PostConstructpublic void init() {if (this.i18NProperties.getEnable()) {getTextFunctionList.add(this::normalFinder);getTextFunctionList.add(this::languageFinder);getTextFunctionList.add(this::defaultLocaleFinder);if (i18NProperties.getUseLocale() && getParentMessageSource() != null) {getTextFunctionList.add(this::localFinder);getTextFunctionList.add(this::localDefaultFinder);}}}@Overridepublic void setResourceLoader(@NonNull ResourceLoader resourceLoader) {}@Overrideprotected MessageFormat resolveCode(@NonNull String code, @NonNull Locale locale) {String msg = getText(code, locale);return createMessageFormat(msg, locale);}@Overrideprotected String resolveCodeWithoutArguments(@NonNull String code, @NonNull Locale locale) {return getText(code, locale);}/*** 这是加载国际化变量的核心方法,先从自己控制的内存中取,取不到了再到资源文件中取** @param code   编码* @param locale 本地化语言* @return 查询对应语言的信息*/private String getText(String code, Locale locale) {String result = getTextWithOutMark(code, locale);if (StringUtils.isEmpty(result)) {return result;}// 确实没有这项配置,确定是否要记录logger.warn("未找到国际化配置:" + code);if (i18NProperties.getMark()) {i18nConfigDbLoader.markInvalidCode(code);}//如果最终还是取不到,返回了NULL,则外面会用默认值,如果没有默认值,最终会返回给页面变量名称,所以变量名称尽量有含义,以作为遗漏配置的最后保障return code;}public String getTextWithOutMark(String code, Locale locale) {String result = "";// 从 function list中依次使用各种策略查询for (BiFunction<String, Locale, String> func : getTextFunctionList) {result = func.apply(code, locale);if (!StringUtils.isEmpty(result)) {return result;}}return result;}/*** 从指定locale获取值** @param code   i18n code* @param locale 语言* @return 查询对应语言的信息*/private String findValueFromLocale(String code, Locale locale) {String resultValue;for (I18nConfigDbLoader i18NConfigDbLoader : i18NConfigDbLoaders) {// 在loadE6I18nDictByLocaleEntity中做过缓存了resultValue = Optional.ofNullable(i18NConfigDbLoader.loadI18nDictByLocaleEntity()).flatMap(localeMap -> Optional.ofNullable(localeMap.get(locale)).map(codeMap -> codeMap.get(code))).orElse(null);if (!org.springframework.util.StringUtils.isEmpty(resultValue)) {return resultValue;}}return null;}// ======================================   查询字符的五种策略,加入function list   ======================================/*** 第一种情况:通过期望的语言类型查找** @param code   国际化代码* @param locale 语言* @return 没找到时返回null*/private String normalFinder(String code, Locale locale) {return findValueFromLocale(code, locale);}/*** 第二种情况,如果期望是 语言-国家 没有找到,那么尝试只找一下语言,比如zh-tw没找到,那就尝试找一下zh** @param code   国际化代码* @param locale 语言* @return 没找到时返回null*/private String languageFinder(String code, Locale locale) {if (locale.getLanguage() != null) {return findValueFromLocale(code, Locale.forLanguageTag(locale.getLanguage()));}return null;}/*** 第三种情况,如果没有找到 且不是默认语言包,则取默认语言包** @param code   国际化代码* @param locale 语言* @return 没找到时返回null*/private String defaultLocaleFinder(String code, Locale locale) {if (!Objects.equals(locale, defaultLocale)) {return findValueFromLocale(code, defaultLocale);}return null;}/*** 第四种情况,通过以上三种方式都没找到,那么尝试从本地配置文件加载期望的语言类型是否有** @param code   国际化代码* @param locale 语言* @return 没找到时返回null*/private String localFinder(String code, Locale locale) {String value = Objects.requireNonNull(getParentMessageSource()).getMessage(code, null, null, locale);if (logger.isDebugEnabled() && !StringUtils.isEmpty(value)) {logger.debug("从配置文件" + locale.toString() + "找到变量" + code + "=" + value);}return value;}/*** 第五种情况,如果没有找到,则从本地配置文件加载默认的语言类型是否有** @param code   国际化代码* @param locale 语言* @return 没找到时返回null*/private String localDefaultFinder(String code, Locale locale) {if (!Objects.equals(locale, defaultLocale)) {return this.localFinder(code, defaultLocale);}return null;}}

pom 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.bdkjzx.project</groupId><artifactId>i18n-spring-boot-starter</artifactId><version>0.0.1-SNAPSHOT</version><name>i18n-spring-boot-starter</name><description>Spring boot 国际化配置</description><properties><java.version>8</java.version><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!--版本支持到2.7.x--><spring-boot.version>2.0.3.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency></dependencies>
<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>8</source><target>8</target></configuration></plugin></plugins></build></project>

3.源码地址

https://github.com/wangshuai67/i18n-spring-boot-starter/
在这里插入图片描述大家好,我是冰点,今天的原生的SpringBoot国际化配置组件支持本地配置和数据库配置 内容分享就到这儿,写的有点粗糙。如果你有疑问或见解可以在评论区留言。

相关文章:

SpringBoot国际化配置组件支持本地配置和数据库配置

文章目录 0. 前言i18n-spring-boot-starter1. 使用方式0.引入依赖1.配置项2.初始化国际化配置表3.如何使用 2. 核心源码实现一个拦截器I18nInterceptorI18nMessageResource 加载国际化配置 3.源码地址 0. 前言 写个了原生的SpringBoot国际化配置组件支持本地配置和数据库配置 背…...

Shell编程之sort

sort 命令将文件的每一行作为比较对象&#xff0c;通过将不同行进行相互比较&#xff0c;从而得到最终结果。从首字符开始&#xff0c;依次按ASCII码值进行比较&#xff0c;最后将结果按升序输出。 基本语法 sort (选项)(参数) 常用选项 常用选项 -n根据字符串的数字比较-r…...

windows docker 容器启动报错:Ports are not available

docker 启动容器报错&#xff1a; (HTTP code 500) server error - Ports are not available: listen tcp 0.0.0.0:6379: bind: An attempt was made to access a socket in a way forbidden by its access permissions. 问题排查 检查端口是否被其它程序占用&#xff1a;nets…...

300. 最长递增子序列

题目描述 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 示…...

DNS(域名解析系统)

含义 当我们在上网要访问莫个服务器的时候&#xff0c;就需要知道服务器的IP地址&#xff0c;但IP地址是一串数字&#xff0c;虽然这串数字用点分十进制已经清晰不少了&#xff0c;但还是不利于人们记忆和传播&#xff0c;于是人们使用单词来代替IP地址&#xff08;例如baidu&a…...

解决jsp/html界面跳转servlet出现404错误的方法

解决jsp/html界面跳转servlet出现404错误的方法 最近在学习黑马项目过程中遇到的问题 问题一&#xff1a; 检查页面的跳转路径和名称拼写是否正确 问题二&#xff1a; tomcat发布项目时所使用的路径名称与项目不同 在idea右上角点击如图圈住的按钮 在deployment中更改出现…...

catface,使用Interface定义Controller,实现基于Http协议的RPC调用

catface 前言cat-client 模块EnableCatClientCatClientCatMethodCatNoteCatResponesWrapperCatClientConfigurationCatClientProviderCatClientFactoryCatSendInterceptorCatHttpCatPayloadResolverCatObjectResolverCatLoggerProcessorCatResultProcessorCatSendProcessorAbst…...

Linux:LVS (NAT群集搭建)

模拟环境 外网入口服务器 外网 192.168.8.88 内网ip 192.168.254.4 web1 服务器 ip 192.168.254.1 网关&#xff1a; 192.168.254.4 web2 服务器 ip 192.168.254.2 网关&#xff1a; 192.168.254.4 共享存储服务器 ip 192.168.254.3 介绍 访问 外网192.16…...

音乐格式转换mp3怎么转?跟着步骤操作一遍

音乐格式转换mp3怎么转&#xff1f;mp3&#xff0c;一种音频数据压缩格式&#xff0c;由于其极具优势的文件尺寸小和高质量音效&#xff0c;自诞生之日起就占据了主流音乐格式的头把交椅&#xff0c;并且至今仍然受到用户的青睐&#xff0c;稳居音乐领域的霸主地位。在我们繁忙…...

it监控系统可以电脑吗?有什么效果

IT业务监控已经成为公司不可或缺的一部分&#xff0c;以确保业务的正常运行&#xff0c;提高企业的竞争能力。本文将详细介绍IT业务监控的必要性、实施方法以及如何选择合适的监控工具。 IT业务监控的必要性 确保业务稳定运行  IT业务监控可以实时检测公司的工作流程&#x…...

jvs-智能bi(自助式数据分析)9.1更新内容

​jvs-智能bi更新功能 1.报表增加权限功能&#xff08;服务、模板、数据集、数据源可进行后台权限分配&#xff09; 每个报表可以独立设置权限&#xff0c;通过自定义分配&#xff0c;给不同的人员分配不同的权限。 2.报表新增执行模式 可选择首次报表加载数据为最新数据和历…...

MyBatis-Plus-扩展操作(3)

3.扩展 代码生成 逻辑删除 枚举处理器 json处理器 配置加密 分页插件 3.1 代码生成 https://blog.csdn.net/weixin_41957626/article/details/132651552 下载下面的插件 红色的是刚刚生成的。 我觉得不如官方的那个好用&#xff0c;唯一的好处就是勾选的选项能够看的懂得。…...

react 中 antd 的 样式和 tailwind 样式冲突

问题原因&#xff1a;在使用 tailwindcss 时&#xff0c;会导入大量的 tailwindcss 默认属性&#xff0c;而默认样式中 button, [typebutton] 包含了 background-color: transparent; 从而导致 antd Button 按钮背景色变成透明。解决办法&#xff1a;禁止 tailwindcss 的默认属…...

获取该虚拟机的所有权失败,主机上的某个应用程序正在使用该虚拟机

点击“openstack-controller”虚机 打开出现如下错误&#xff0c;点击“获取所有权” 点击“取消” 这时候不要删除虚拟机&#xff0c;这种错误一般是由于虚拟机没有正常关闭引起的。 找到openstack-controller的虚拟磁盘文件及配置文件存放的位置&#xff0c;删除openstack-…...

2024届校招-Java开发笔试题-S4卷

有三种题型&#xff1a;单项选择题&#xff08;10道&#xff09;、不定项选择题&#xff08;10道&#xff09;、编程题&#xff08;3道&#xff09; 下面是一些回忆的题目&#xff1a; 1.哪种设计模式将对象的创建与使用分离&#xff0c;通过工厂类创建对象 答&#xff1a;工…...

数据分析面试题(2023.09.08)

数据分析流程 总体分为四层&#xff1a;需求层、数据层、分析层和结论层 一、统计学问题 1、贝叶斯公式复述并解释应用场景 公式&#xff1a;P(A|B) P(B|A)*P(A) / P(B)应用场景&#xff1a;如搜索query纠错&#xff0c;设A为正确的词&#xff0c;B为输入的词&#xff0c;那…...

jenkins 报错fatal:could not read Username for ‘XXX‘:No such device or address

#原因&#xff1a;机器做迁移&#xff0c;或者断电&#xff0c;遇到突发情况 #解决&#xff1a; 一.排查HOME和USER环境变量 可以在项目执行shell脚本的时候echo $HOME和USER 也可以在构建记录位置点击compare environment 对比两次构建的环境变量 二.查看指定节点的git凭证 查…...

LRU算法之我见

文章目录 一、LRU算法是什么&#xff1f;二、使用原理三、代码实现总结 一、LRU算法是什么&#xff1f; LRU算法又称最近最少使用算法&#xff0c;它是是大部分操作系统为最大化页面命中率而广泛采用的一种页面置换算法。是一种缓存淘汰策略&#xff0c;根据使用频率来淘汰无用…...

【第20例】华为 IPD 体系 | IPD 的底层思考逻辑(限制版)

目录 简介 更新情况 IPD体系 CSDN学院 专栏目录 作者简介 简介 最近随着华为 Mate 60 系列的爆火发布。 这家差不多沉寂了 4 年的企业再次映入大众的眼帘。 其实,华为手机业务发展的元年最早可以追溯...

spaCy库的实体链接踩坑,以及spaCy-entity-linker的knowledge_base下载问题

问题1. spacy Can’t find factory for ‘entityLinker’ 1&#xff09;问题 写了一个实体链接类&#xff0c;代码如下&#xff1a; nlp spacy.load("en_core_web_md")class entieyLink:def __init__(self, doc, nlp):self.nlp nlpself.doc self.nlp(doc)# Che…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...

OCR MLLM Evaluation

为什么需要评测体系&#xff1f;——背景与矛盾 ​​ 能干的事&#xff1a;​​ 看清楚发票、身份证上的字&#xff08;准确率>90%&#xff09;&#xff0c;速度飞快&#xff08;眨眼间完成&#xff09;。​​干不了的事&#xff1a;​​ 碰到复杂表格&#xff08;合并单元…...

【大厂机试题解法笔记】矩阵匹配

题目 从一个 N * M&#xff08;N ≤ M&#xff09;的矩阵中选出 N 个数&#xff0c;任意两个数字不能在同一行或同一列&#xff0c;求选出来的 N 个数中第 K 大的数字的最小值是多少。 输入描述 输入矩阵要求&#xff1a;1 ≤ K ≤ N ≤ M ≤ 150 输入格式 N M K N*M矩阵 输…...

SDU棋界精灵——硬件程序ESP32实现opus编码

一、 ​​音频处理框架​ 该项目基于Espressif的音频处理框架构建,核心组件包括 ESP-ADF 和 ESP-SR,以下是完整的音频处理框架实现细节: 1.核心组件 (1) 音频前端处理 (AFE - Audio Front-End) ​​main/components/audio_pipeline/afe_processor.c​​功能​​: 声学回声…...

触发DMA传输错误中断问题排查

在STM32项目中&#xff0c;集成BLE模块后触发DMA传输错误中断&#xff08;DMA2_Stream1_IRQHandler进入错误流程&#xff09;&#xff0c;但单独运行BLE模块时正常&#xff0c;表明问题可能源于原有线程与BLE模块的交互冲突。以下是逐步排查与解决方案&#xff1a; 一、问题根源…...