【SpringBoot框架篇】33.优雅集成i18n实现国际化信息返回

news2024/11/16 0:35:48

文章目录

  • 1.简介
  • 2.MessageSource配置和工具类封装
    • 2.1.配置MessageSource相关配置
    • 2.2.配置工具类
    • 2.3.测试返回国际级文本信息
  • 3.不优雅的web调用示例(看看就行,别用)
  • 4.优雅使用示例
    • 4.1.错误响应消息枚举类
    • 4.2.ThreadLocal工具类配置
      • 4.2.1.ThreadLocal工具类数据封装
      • 4.2.2.往ThreadLocal里存放language字段
      • 4.2.3.ThreadLocal内存释放
    • 4.3.http返回通用Json响应数据类
    • 4.4.优化章节3的示例
  • 5.各国的国际化文件规范命名列表
  • 6.项目配套代码

1.简介

由于公司业务需求,需要支持中英两个版本的返回提示信息,使用spring的MessageSource类获取对应语种的i18n文件的提示信息。

i18n(其来源是英文单词 internationalization的首末字符i和n,18为中间的字符数)是“国际化”的简称。在资讯领域,国际化(i18n)指让产品(无需做大的改变就能够适应不同的语言和地区的需要。对程序来说,在不修改内部代码的情况下,能根据不同语言及地区显示相应的界面。 在全球化的时代,国际化尤为重要,因为产品的潜在用户可能来自世界的各个角落。通常与i18n相关的还有L10n(“本地化”的简称)。

2.MessageSource配置和工具类封装

为节省代码量使用了lombok插件,在pom.xml引入

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

查看MessageSource源码可以看到该接口提供了三个方法,我们使用第二个即可。

public interface MessageSource {
    @Nullable
    String getMessage(String var1, @Nullable Object[] var2, @Nullable String var3, Locale var4);
	
    /**
     * 根据key去国际化对应的文件中找文本信息
     * @param var1   key
     * @param var2  占位符参数
     * @param var3  国际化语种
     * @return 对应语种的文本信息
     */
    String getMessage(String var1, @Nullable Object[] var2, Locale var3) throws NoSuchMessageException;

    String getMessage(MessageSourceResolvable var1, Locale var2) throws NoSuchMessageException;
}

2.1.配置MessageSource相关配置

@Configuration
public class LocaleConfig {

    @Bean
    public ResourceBundleMessageSource messageSource() {
        Locale.setDefault(Locale.CHINA);
        ResourceBundleMessageSource source = new ResourceBundleMessageSource();
        //设置国际化文件存储路径和名称    i18n目录,messages文件名
        source.setBasenames("i18n/messages");
        //设置根据key如果没有获取到对应的文本信息,则返回key作为信息
        source.setUseCodeAsDefaultMessage(true);
        //设置字符编码
        source.setDefaultEncoding("UTF-8");
        return source;
    }

}

在resources目录下添加国际化文件
en_US存放英语,zh_CH存放中文
在这里插入图片描述
记得把idea的文件编码格式改成utf8,要不然中文会乱码。
在这里插入图片描述

在代码里用枚举类维护使用的语种

@Getter
@AllArgsConstructor
public enum LanguageEnum {

    ZH_CN("zh_CN", "中文/中国"),
    EN_US( "en_US", "英语/美国"),
    ;

    /**
     * 语言_国家缩写
     */
    private String name;

    /**
     * 描述
     */
    private String desc;

}

2.2.配置工具类

下面代码封装了两个对外暴露的方法

  • get(String key, String language) 根据key获取文本信息
  • get(String key, Object[] params, String language) 根据key获取替换占位符中的文本信息

MessageSource的实例对象这是通过内部类懒加载的方式创建

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MessageUtil {


    /**
     * 根据key信息获取对应语言的内容
     *
     * @param key      消息key值
     * @param language 语言_国家
     * @return
     */
    public static String get(String key, String language) {
        if (!StringUtils.isEmpty(language)) {
            String[] arrs = language.split("_");
            if (arrs.length == 2) {
                return get(key, new Locale(arrs[0], arrs[1]));
            }
        }
        //使用默认的国际化语言
        return get(key, Locale.getDefault());
    }

    /**
     * 根据key信息获取对应语言的内容
     *
     * @param key      消息key值
     * @param params   需要替换到占位符中的参数 占位符下标重0开始  格式如: {0} {1}
     * @param language 语言_国家
     * @return
     */
    public static String get(String key, Object[] params, String language) {
        if (!StringUtils.isEmpty(language)) {
            String arrs[] = language.split("_");
            if (arrs.length == 2) {
                return get(key, params, new Locale(arrs[0], arrs[1]));
            }
        }
        return get(key, params, Locale.getDefault());
    }

    private static String get(String key, Locale language) {
        return get(key, new String[0], language);
    }
    
    private static String get(String key, Object[] params, Locale language) {
        return getInstance().getMessage(key, params, language);
    }

    private static MessageSource getInstance() {
        return Lazy.messageSource;
    }

    /**
     * 使用懒加载方式实例化messageSource国际化工具
     */
    private static class Lazy {
        private static final MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
    }

}

MessageUtil 用到的工具类代码如下

/**
 * @author Dominick Li
 * @description 普通类调用Spring bean对象使用的工具栏
 **/
@Component
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }
    }

    /**
     * 通过class获取Bean.
     */
    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

}

2.3.测试返回国际级文本信息

分别在国际化文件中添加key名称为test的项,并添加{0} 占位符支持动态参数

messages_en_US.properties文件内容如下

test=language:{0} ,Hello World!

messages_zh_CN.properties内容如下

test=语言:{0} ,你好世界

测试代码如下

@RestController
public class TestI18nController {

    /**
     * 测试国际化
     * en_US 英文  http://127.0.0.1:8033/en_US
     * zh_CN 中文 http://127.0.0.1:8033/zh_CN
     */
    @GetMapping("/{language}")
    public String test(@PathVariable String language) {
        String text1 = MessageUtil.get("test", language);
        String text2 = MessageUtil.get("test", new Object[]{language}, language);
        return new StringBuilder("没有替换占位符参数:")
                .append(text1)
                .append("<br/>")
                .append("替换占位符参数后:")
                .append(text2)
                .toString();
    }
}    

用浏览器访问http://127.0.0.1:8033/zh_CN 查看中文国际化信息,访问http://127.0.0.1:8033/en_US 查看英文国际化信息
在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/65abad9a30fc456493f992b1ed05d2d0.png

3.不优雅的web调用示例(看看就行,别用)

像一些固定的参数我们通常会放在Header参数里,例如token,同理我们也可以把language字段放到header里,用于接受客户端选择使用的国际化语言。

Controller和Service的代码如下

@RestController
public class TestI18nController {
    @Autowired
    private LoginService loginService;
    /**
     * 不优雅登录
     */
    @PostMapping("/login")
    public JsonResult login(@RequestHeader String language,@RequestParam String username, @RequestParam String password) {
        return loginService.login(language,username,password);
    }
}    
public interface LoginService {
    JsonResult login(String language,String username,String password); 
}
@Service
public class LoginServiceImpl implements LoginService {
    @Override
    public JsonResult login(String language, String username, String password) {
        if ("123456".equals(password)) {
        	//通过key和语言找到对应文本的提示信息
            return JsonResult.successResult(MessageUtil.get("return.loginOk", language));
        }
        return JsonResult.failureResult(MessageUtil.get("return.pwd_error", language));
    }
}    

在postman中调用测试接口
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
把Header参数中的language改成zh_CN
在这里插入图片描述

上述代码的问题在于

  • 1.国际化使用的language字段需要从controller传递到具体的service类中方法中
  • 2.在每次通过JsonResult返回提示信息的时候都需要显示调用MessageUtil获取对应文本信息

4.优雅使用示例

  • 1.章节3的language字段上下文传递的问题可以通过ThreadLocal的,同理token字段也可以放在ThreadLocal里。
  • 2.显示调用MessageUtil工具类获取提示信息可以封装成响应消息枚举类中使用。

4.1.错误响应消息枚举类

@Getter
public enum ReturnMessageEnum {

    OK("ok"),
    FAILED("failed"),
    LOGIN_OK("loginOk"),
    PASSWORD_ERROR("pwd_error"),
    ACCOUNT_LOCK("account_lock"),
    ;
    /**
     * 国际化信息文件里的Key前缀
     */
    private final static String prefix = "return.";

    /**
     * 返回的国际化key信息
     */
    private String key;


    ReturnMessageEnum(String key) {
        this.key = prefix + key;
    }

    @Override
    public String toString() {
        return MessageUtil.get(key, ThreadLocalManagerUtil.getLanguage());
    }

    /**
     * 替换占位符中的参数
     *
     * @param params 需要替换的参数值 长度可变
     */
    public String setAndToString(Object... params) {
        return MessageUtil.get(key, params, ThreadLocalManagerUtil.getLanguage());
    }

}

国际化文件里也需要添加对应的数据

messages_zh_CN.properties文件

return.ok=操作成功!
return.failed=操作失败!
return.loginOk=登录成功!
return.pwd_error=密码错误!
return.account_lock=账号已被锁定{0}分钟,请稍后重试!

messages_en_US.properties

return.ok=Success!
return.failed=Fail!
return.loginOk=Login succeeded!
return.pwd_error=PW error!
return.account_lock=The account has been locked for {0} minutes. Please try again later!

4.2.ThreadLocal工具类配置

系统参数常量类

/**
 * 系统常量
 */
public interface SystemConstants {

    /**
     * 国际化
     */
    String LANGUAGE = "language";

    /**
     * token名称
     */
    String TOKEN_NAME = "token";

}

4.2.1.ThreadLocal工具类数据封装

public class ThreadLocalManagerUtil {

    @Data
    public static class HeaderInfo {

        /**
         * 用户的token信息
         */
        private String token;

        /**
         * 国际化语言包名称
         */
        private String language;
    }

    /**
     * 存储请求头信息
     */
    private final static ThreadLocal<HeaderInfo> headerInfoThreadLocal = new ThreadLocal<>();

    public static void add(HeaderInfo headerInfo) {
        headerInfoThreadLocal.set(headerInfo);
    }

    public static String getToken() {
        return headerInfoThreadLocal.get().getToken();
    }

    public static String getLanguage() {
        return headerInfoThreadLocal.get() != null ? headerInfoThreadLocal.get().getLanguage() : LanguageEnum.ZH_CN.getName();
    }

    /**
     * 释放资源
     */
    public static void remove() {
        headerInfoThreadLocal.remove();
    }

}

4.2.2.往ThreadLocal里存放language字段

使用过空滤器拦截接口请求,并从请求头中获取language字段存放到ThreadLocal中

@Component
public class HttpFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        ThreadLocalManagerUtil.HeaderInfo headerInfo  = new ThreadLocalManagerUtil.HeaderInfo();
        headerInfo.setLanguage(request.getHeader(SystemConstants.LANGUAGE));
        headerInfo.setToken(request.getHeader(SystemConstants.TOKEN_NAME));
        //在ThreadLocal中添加token和当前国际化信息
        ThreadLocalManagerUtil.add(headerInfo);
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
    }

}

4.2.3.ThreadLocal内存释放

如果ThreadLocal存放的数据不释放,当用户量大的时候会导致系统出现OOM问题

添加拦截器在请求结束的时候释放内存。

public class HttpInterceptor  implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //会话结束移除线程缓存
        ThreadLocalManagerUtil.remove();
        return;
    }
}

注册拦截器到webMVC中

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry interceptor) {
        //需要配置拦截器并指定拦截的接口路径
        interceptor.addInterceptor(new HttpInterceptor()).addPathPatterns("/**");
    }
}

4.3.http返回通用Json响应数据类

public class JsonResult<T> implements Serializable {

    /**
     * 成功标识 200成功,其它异常
     */
    private int code = 200;

    /**
     * 提示信息
     */
    private String msg;

    /**
     * 数据
     */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private T data;

    private static final long serialVersionUID = -7268040542410707954L;


    public JsonResult() {
    }

    public JsonResult(int code) {
        this.setCode(code);
    }

    public JsonResult(int code, String msg) {
        this(code);
        this.setMsg(msg);
    }

    public JsonResult(int code, String msg, T data) {
        this(code, msg);
        this.setData(data);
    }

    public static JsonResult build(boolean flag) {
        return new JsonResult(flag ? HttpStatus.OK.value() : HttpStatus.INTERNAL_SERVER_ERROR.value(), flag ? ReturnMessageEnum.OK.toString() : ReturnMessageEnum.FAILED.toString());
    }

    public static JsonResult successResult() {
        return new JsonResult(HttpStatus.OK.value(), ReturnMessageEnum.OK.toString());
    }

    public static JsonResult successResult(String msg) {
        return new JsonResult(HttpStatus.OK.value(), defaultSuccessMsg(msg));
    }


    public static <T> JsonResult<T> successResult(T obj) {
        return new JsonResult(HttpStatus.OK.value(), ReturnMessageEnum.OK.toString(), obj);
    }

    public static <T> JsonResult<T> successResult(String msg, T obj) {
        return new JsonResult(HttpStatus.OK.value(), defaultSuccessMsg(msg), obj);
    }


    public static JsonResult failureResult() {
        return new JsonResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), ReturnMessageEnum.FAILED.toString());
    }

    public static JsonResult failureResult(String msg) {
        return new JsonResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), defautlErrorMsg(msg));
    }

    public static JsonResult failureResult(ReturnMessageEnum returnMessageEnum) {
        return new JsonResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), returnMessageEnum.toString());
    }


    protected static String defautlErrorMsg(String msg) {
        if (!StringUtils.isEmpty(msg)) {
            return msg;
        } else {
            return ReturnMessageEnum.FAILED.toString();
        }
    }

    protected static String defaultSuccessMsg(String msg) {
        if (!StringUtils.isEmpty(msg)) {
            return msg;
        } else {
            return ReturnMessageEnum.OK.toString();
        }
    }
}

4.4.优化章节3的示例

@RestController
public class TestI18nController {
    @Autowired
    private LoginService loginService;
 	/**
     * 优化后的登录接口
     */
    @PostMapping("/login")
    public JsonResult login(@RequestParam String username, @RequestParam String password) {
        return loginService.login(username,password);
    }
}    
public interface LoginService {
    JsonResult login(String username,String password); 
}
@Service
public class LoginServiceImpl implements LoginService {
    @Override
    public JsonResult login(String username, String password) {
        if ("123456".equals(password)) {
            return JsonResult.successResult(ReturnMessageEnum.LOGIN_OK);
        }
        //使用枚举替换占位符内容后的信息
        System.out.println(ReturnMessageEnum.ACCOUNT_LOCK.setAndToString(3));
        return JsonResult.failureResult(ReturnMessageEnum.PASSWORD_ERROR);
    }
}   

使用postman调用接口测试可以实现同章节3一样的效果。
在这里插入图片描述
改成英语后调用也是一样的。
在这里插入图片描述

使用枚举类替换占位符内容后的信息也打印在控制台上面了。
在这里插入图片描述

5.各国的国际化文件规范命名列表

命名规则 语种_地区,中国,香港,台湾都属于中国,所以前面都是zh开头,_后面则表示地区

中国 : zh_CN
香港 : zh_HK
台湾:zh_TW
日本 : ja_JP
美国 : en_US
英国 : en_GB
秘鲁 : es_PE
巴拿马 : es_PA
波斯尼亚和黑山共和国 : sr_BA
危地马拉 : es_GT
阿拉伯联合酋长国 : ar_AE
挪威 : no_NO
阿尔巴尼亚 : sq_AL
伊拉克 : ar_IQ
也门 : ar_YE
葡萄牙 : pt_PT
塞浦路斯 : el_CY
卡塔尔 : ar_QA
马其顿王国 : mk_MK
瑞士 : de_CH
芬兰 : fi_FI
马耳他 : en_MT
斯洛文尼亚 : sl_SI
斯洛伐克 : sk_SK
土耳其 : tr_TR
沙特阿拉伯 : ar_SA
塞尔维亚及黑山 : sr_CS
新西兰 : en_NZ
挪威 : no_NO
立陶宛 : lt_LT
尼加拉瓜 : es_NI
爱尔兰 : ga_IE
比利时 : fr_BE
西班牙 : es_ES
黎巴嫩 : ar_LB
加拿大 : fr_CA
爱沙尼亚 : et_EE
科威特 : ar_KW
塞尔维亚 : sr_RS
墨西哥 : es_MX
苏丹 : ar_SD
印度尼西亚 : in_ID
乌拉圭 : es_UY
拉脱维亚 : lv_LV
巴西 : pt_BR
叙利亚 : ar_SY
多米尼加共和国 : es_DO
瑞士 : fr_CH
印度 : hi_IN
委内瑞拉 : es_VE
巴林 : ar_BH
菲律宾 : en_PH
突尼斯 : ar_TN
奥地利 : de_AT
荷兰 : nl_NL
厄瓜多尔 : es_EC
约旦 : ar_JO
冰岛 : is_IS
哥伦比亚 : es_CO
哥斯达黎加 : es_CR
智利 : es_CL
埃及 : ar_EG
南非 : en_ZA
泰国 : th_TH
希腊 : el_GR
意大利 : it_IT
匈牙利 : hu_HU
爱尔兰 : en_IE
乌克兰 : uk_UA
波兰 : pl_PL
卢森堡 : fr_LU
比利时 : nl_BE
印度 : en_IN
西班牙 : ca_ES
摩洛哥 : ar_MA
玻利维亚 : es_BO
澳大利亚 : en_AU
新加坡 : zh_SG
萨尔瓦多 : es_SV
俄罗斯 : ru_RU
韩国 : ko_KR
阿尔及利亚 : ar_DZ
越南 : vi_VN
黑山 : sr_ME
利比亚 : ar_LY
白俄罗斯 : be_BY
以色列 : iw_IL
保加利亚 : bg_BG
马耳他 : mt_MT
巴拉圭 : es_PY
法国 : fr_FR
捷克共和国 : cs_CZ
瑞士 : it_CH
罗马尼亚 : ro_RO
波多黎哥 : es_PR
加拿大 : en_CA
德国 : de_DE
卢森堡 : de_LU
阿根廷 : es_AR
马来西亚 : ms_MY
克罗地亚 : hr_HR
新加坡 : en_SG
阿曼 : ar_OM
泰国 : th_TH
瑞典 : sv_SE
丹麦 : da_DK
洪都拉斯 : es_HN

由于前段时间买相机学习摄影相关的知识,导致博客很久没更新了,还是不能忘记初心,要时刻学习,在这个社会一日不学习就会退步,因为会被同行卷下去。。

6.项目配套代码

github地址

创作不易,要是觉得我写的对你有点帮助的话,麻烦在github上帮我点下 Star

【SpringBoot框架篇】其它文章如下,后续会继续更新。

  • 1.搭建第一个springboot项目
  • 2.Thymeleaf模板引擎实战
  • 3.优化代码,让代码更简洁高效
  • 4.集成jta-atomikos实现分布式事务
  • 5.分布式锁的实现方式
  • 6.docker部署,并挂载配置文件到宿主机上面
  • 7.项目发布到生产环境
  • 8.搭建自己的spring-boot-starter
  • 9.dubbo入门实战
  • 10.API接口限流实战
  • 11.Spring Data Jpa实战
  • 12.使用druid的monitor工具查看sql执行性能
  • 13.使用springboot admin对springboot应用进行监控
  • 14.mybatis-plus实战
  • 15.使用shiro对web应用进行权限认证
  • 16.security整合jwt实现对前后端分离的项目进行权限认证
  • 17.使用swagger2生成RESTful风格的接口文档
  • 18.使用Netty加websocket实现在线聊天功能
  • 19.使用spring-session加redis来实现session共享
  • 20.自定义@Configuration配置类启用开关
  • 21.对springboot框架编译后的jar文件瘦身
  • 22.集成RocketMQ实现消息发布和订阅
  • 23.集成smart-doc插件零侵入自动生成RESTful格式API文档
  • 24.集成FastDFS实现文件的分布式存储
  • 25.集成Minio实现文件的私有化对象存储
  • 26.集成spring-boot-starter-validation对接口参数校验
  • 27.集成mail实现邮件推送带网页样式的消息
  • 28.使用JdbcTemplate操作数据库
  • 29.Jpa+vue实现单模型的低代码平台
  • 30.使用sharding-jdbc实现读写分离和分库分表
  • 31.基于分布式锁或xxl-job实现分布式任务调度
  • 32.基于注解+redis实现表单防重复提交
  • 33.优雅集成i18n实现国际化信息返回

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不再限制CPU,这才是Win11完全体的样子嘛

从 Win11 刚问世时&#xff0c;微软就宣称将给其许多 Win10没有也不会支持的新功能。 其中 Android 子系统的支持算得上是最期待&#xff0c;但结果难免有些失望的部分。 先不说使用怎么样&#xff0c;光是安装就困难重重。 绕过限制升级了 Win11 &#xff0c;但没想到安装 W…

idea双击启动无效,idea卡顿问题

idea双击启动无效&#xff1a;大概率是关机时没有正确关闭idea&#xff0c;再次开机导致无法正常启动idea 1.通过任务管理器杀死idea进程后重启idea 2.需要修改配置 打开 &#xff08;以各自电脑实际为准&#xff09;C:\Program Files\JetBrains\IntelliJ IDEA 2020.3.1\bin&am…

LabVIEW使用图像处理检测显微图像中的白血病

LabVIEW使用图像处理检测显微图像中的白血病 人体最重要的部分是血液&#xff0c;因为它使人活着。它执行许多重要功能&#xff0c;例如转移氧气&#xff0c;二氧化碳&#xff0c;矿物质等。血液量不足会极大地影响新陈代谢&#xff0c;如果不及早治疗&#xff0c;这可能是非常…

接口自动化测试框架及接口测试自动化主要知识点

接口自动化测试框架&#xff1a; 接口测试框架&#xff1a;使用最流行的Requests进行接口测试接口请求构造&#xff1a;常见的GET/POST/PUT/HEAD等HTTP请求构造 接口测试断言&#xff1a;状态码、返回内容等断言JSON/XML请求&#xff1a;发送json\xml请求JSON/XML响应断言&…

c语言经典例题讲解(输出菱形,喝汽水问题)

目录 一、输出菱形 二、喝汽水问题 方法1&#xff1a;一步一步来 方法二&#xff1a;直接套公式 一、输出菱形 输出类似于下图的菱形&#xff1a; 通过分析&#xff1a;1、先分为上下两部分输出 2.在输出前先输出空格 3.找规律进行输出 可知&#xff0c;可令上半部分lin…

Python Opencv实践 - 图像属性相关

import numpy as np import cv2 as cv import matplotlib.pyplot as pltimg cv.imread("../SampleImages/pomeranian.png", cv.IMREAD_COLOR) plt.imshow(img[:,:,::-1])#像素操作 pixel img[320,370] print(pixel)#只获取蓝色通道的值 pixel_blue img[320,370,0]…

openwrt dns ssh相关问题

DHCP/DNS中 的技术叫dnsmasq 可配置hosts和 自定义挟持域名配置 image.png image.png 拦截优先级为挟持域名最高&#xff0c;另外需要重启服务方可生效&#xff0c;在系统&#xff0c;启动项中重启dnsmasq ssh 使用root用户SSH登录服务器出现Access Denied错误 只输入root就出现…

Python-OpenCV中的图像处理-图像金字塔

Python-OpenCV中的图像处理-图像金字塔 图像金字塔高斯金字塔拉普拉斯金字塔 金字塔图像融合 图像金字塔 同一图像的不同分辨率的子图集合&#xff0c;如果把最大的图像放在底部&#xff0c;最小的放在顶部&#xff0c;看起来像一座金字塔&#xff0c;故而得名图像金字塔。cv2…

C语言的动态分配空间C++的动态分配空间问题

动态分配空间 C&#xff1a;1、malloc 2、calloc C&#xff1a;new运算符 一 malloc malloc()&#xff1a; 这个函数用于分配一块指定大小的内存块&#xff0c;并返回一个指向该内存块的指针。语法如下&#xff1a; void* malloc(size_t size); 示例&#xff1a; int* ptr …

欧拉操作系统添加磁盘

1、查看磁盘空间 fdisk -l 2、创建新磁盘分区 fdisk /dev/vda 欢迎使用 fdisk (util-linux 2.37.2)。 更改将停留在内存中&#xff0c;直到您决定将更改写入磁盘。 使用写入命令前请三思。 This disk is currently in use - repartitioning is probably a bad idea. Its r…

(力扣)用两个栈实现队列

这里是栈的源代码&#xff1a;栈和队列的实现 当然&#xff0c;自己也可以写一个栈来用&#xff0c;对题目来说不影响&#xff0c;只要符合栈的特点就行。 题目&#xff1a; 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、pe…

c++(空间配置器)[32]

空间配置器 一级空间配置器 || 二级空间配置器 默认先走二级然后判断 二级空间配置器 一个指针指向start_free然后start_free向后移动&#xff0c;相当于哈希桶的头删和头插 8byte&#xff1a;切大补小 C的二级空间配置器按照8字节&#xff08;或者更大的倍数&#xff09;切分…

《流浪地球3》预告片流出?!网友整活竟被郭导翻牌、央视点赞!

年初《流浪地球2》掀起了一股“科幻热”&#xff0c;而这股热潮直至今日还只增不减。这不&#xff0c;一位名叫“数字生命卡兹克”的博主已经开始“整活”了&#xff01;他利用AI技术&#xff0c;自制了《流浪地球3》的预告片&#xff0c;并迅速火遍全网。 更牛的是&#xff0c…

apple pencil二代值不值得买?好用的苹果平替笔推荐

自从苹果的Pencil系列问世以来&#xff0c;在国内电容笔市场的销量大增&#xff0c;而苹果的Pencil系列&#xff0c;其的售价更是贵的让人望而却步。现在市面上有很多平替的电容笔&#xff0c;都能取代苹果的Pencil&#xff0c;用来做笔记、做批注、写写字都绰绰有余了。在这里…

【Vue+Element-plus】记录后台首页多echart图静态页面

一、页面效果 二、完整代码 Index.vue <template><div><div><DateTime /><!-- {{username}} --></div><el-row :gutter"20"><el-col :span"8"><div class"grid-content bg-purple"><P…

Python-OpenCV中的图像处理-图像轮廓

Python-OpenCV中的图像处理-图像轮廓 轮廓什么是轮廓查找轮廓绘制轮廓 轮廓特征图像的矩轮廓面积轮廓周长&#xff08;弧长&#xff09;轮廓近似凸包轮廓边界矩形 轮廓 什么是轮廓 轮廓可以简单认为成将连续的点&#xff08;连着边界&#xff09;连在一起的曲线&#xff0c;具…

分布式 - 服务器Nginx:一小时入门系列之动静分离

文章目录 1. 动静分离的好处2. 分离静态文件3. 修改 Nginx 配置文件 1. 动静分离的好处 Apache Tocmat 严格来说是一款java EE服务器&#xff0c;主要是用来处理 servlet请求。处理css、js、图片这些静态文件的IO性能不够好&#xff0c;因此&#xff0c;将静态文件交给nginx处…

os.listdir()读取文件夹下特定命名的文件并合并保存

import pandas as pd from tqdm import tqdm import os # 合并振动信号的所有数据 path D:/code/data/Learning_set/Bearing1_1 acc_csv_files os.listdir(path)acc_data pd.DataFrame() temp_data pd.DataFrame() # 逐个读取并合并CSV文件 # tqdm的作用是显示进度条&#…

【PNC】AStar及常用规划算法原理与实现

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍AStar规划算法原理与实现。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷…

网工内推 | 信息安全负责人,需8年安全经验,CISSP证书

01 上海鹰角网络 招聘岗位&#xff1a;信息安全负责人 职责描述&#xff1a; 1、负责公司总体的信息安全规划、信息安全管理体系、流程、制度的设计和优化&#xff0c;确保在运营、应用、信息和业务等方面的持续安全、稳定&#xff1b; 2、负责对系统&#xff0c;网络&#xf…