2019-12-05

阿里云aliyun-java-sdk-core(4.4.2)设置代理服务器
媒体服务转码请求:
                                    DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", accesskey, secretKey);
                                    // 如果时内网环境,设置代理服务器
                                    if (needProxy) {
                                        HttpClientConfig httpClientConfig = HttpClientConfig.getDefault();
                                        httpClientConfig.setHttpProxy("http://pengbo:12345678@110.110.110.001:3128");
                                        httpClientConfig.setHttpsProxy("https://pengbo:12345678@110.110.110.001:3128");
                                        profile.setHttpClientConfig(httpClientConfig);
                                    }
                                    IAcsClient client = new DefaultAcsClient(profile);
                                    SubmitJobsRequest request = new SubmitJobsRequest();
                                    ...
                                

2019-11-19

redis模糊查询key

生产环境中不要使用keys命令

1、redis是单线程的,其所有操作都是原子的,不会因并发产生数据异常; 2、使用高耗时的Redis命令是很危险的,会占用唯一的一个线程的大量处理时间,导致所有的请求都被拖慢。(例如时间复杂度为O(N)的KEYS命令,严格禁止在生产环境中使用);

单机使用scan接口获取key

1、scan命令的时间复杂度虽然也是O(N),但它是分次进行的,不会阻塞线程。 2、scan命令提供了limit参数,可以控制每次返回结果的最大条数。 这两个优势就帮助我们解决了上面的难题,不过scan命令也并不是完美的,它返回的结果有可能重复,因此需要客户端去重。
深入理解Redis的scan命令
spring-data-redis中,注意使用完毕后及时释放连接,调用cursor.close()方法;否则将一直占用
在集群模式下,scan接口没有作用,会报错 scan is not supported across multiple nodes within a cluster

2019-11-04

react-cookie 使用注意
低版本load(name, doNotParse ) 经常忽略第二个参数,是否对值做JSON.parse() 当存储的是数据是纯数字的字符串,将会导致数据类型变化
"12345678" => 12345678
导致后面使用时出现非预期现象,如使用Number类型JSEncrypt做RSA加密时,在后台得到的是空字符串
                                    function load(name, doNotParse) {
                                      var cookies = (typeof document === 'undefined') ? _rawCookie : cookie.parse(document.cookie);
                                      var cookieVal = cookies && cookies[name];

                                      if (!doNotParse) {
                                        try {
                                          cookieVal = JSON.parse(cookieVal);
                                        } catch(e) {
                                          // Not serialized object
                                        }
                                      }

                                      return cookieVal;
                                    }
                                
高版本 get(name, [options.doNotParse]) 已作了处理,猜测value是否是序列化后的值, 而不是全由doNotParse值确定
                                    export function readCookie(value: Cookie, options: CookieGetOptions = {}) {
                                      const cleanValue = cleanupCookieValue(value);
                                      if (isParsingCookie(cleanValue, options.doNotParse)) {
                                        try {
                                          return JSON.parse(cleanValue);
                                        } catch (e) {
                                          // At least we tried
                                        }
                                      }
                                
                                    function cleanupCookieValue(value: Cookie): Cookie {
                                      // express prepend j: before serializing a cookie
                                      if (value && value[0] === 'j' && value[1] === ':') {
                                        return value.substr(2);
                                      }

                                      return value;
                                    }
                                
                                    export function isParsingCookie(value: Cookie, doNotParse?: boolean) {
                                      if (typeof doNotParse === 'undefined') {
                                        // We guess if the cookie start with { or [, it has been serialized
                                        doNotParse =
                                          !value || (value[0] !== '{' && value[0] !== '[' && value[0] !== '"');
                                      }

                                      return !doNotParse;
                                    }
                                
JSON.parse("12345678") => 12345678
JSON.parse("abcdefg") => 报错,返回原始字符串
JSON.parse("\"abc\"") => "abc"

2019-11-01

将 JS 的正则表达式转成图形解释的在线工具

2019-10-31

FastJson转换时的一些奇怪现象
java属性第二个字母大写,转字符串后会变小写 pId => pid
fastjson转换json时,碰到的那些首字母大小写转换的坑!

2019-19-29

react+antd+mobx umi项目 less文件引入
import styles from '../less/index.less';
使用:
<Layout className={styles.layout}>
问题:umi默认开启了webpack的ccs-loader的CSS Modules,但是当想要在less文件样式中覆盖antd的默认样式时无法生效,且原有非umi的工程迁移时,需要改造大量样式使用方式
解决方式:
1 .umirc.js文件中增加配置:disableCSSModules:true,
禁用webpack的CSS Modules
2.在less中使用全局样式 :global 用来覆盖antd原有样式,把非CSS Modules的写法改写成CSS Modules的写法(CSS Modules还是挺好用的)

2019-07-24

公司重启了路由器和交换机,本机的IP地址发生了改变,导致开发的网站使用的一个外网的JS文件报 net::ERR_CONNECTION_RESET,断下网,再连回来就好了,原因待查

2019-07-23

嗯。。页面右键“重新加载”不会处发页面unload,会触发beforeunload事件

2019-07-11

Java图片上传背景变黑问题

前端上传的png图片(如canvas画图),如果背景是透明的,在使用 java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, java.awt.image.ImageObserver)压缩处理时, 注意透明的处理,否则会出现背景变黑的情况
需要在正常处理中加入:

                                    BufferedImage to = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
                                    Graphics2D g2d = to.createGraphics();
                                    to = g2d.getDeviceConfiguration().createCompatibleImage(newWidth, newHeight, Transparency.TRANSLUCENT);
                                    g2d.dispose();
                                

2019-07-08

表单中使用bootstrap组件iCheck

在表单中使用时,如果调用重置表单,iCheck的显示会错乱;
原因:使用iCheck的选中样式是由input外面包裹他的div的checked class样式的有无决定的,如果使用表单的reset的方法,不会影响div样式; 如果checkbox的初始是没有选中的,选中checkbox后,reset表单,导致input的选中状态已经是uncheck的,但是iCheck样式还是显示选中状态;
解决办法:在reset form之前,将iCheck的input表单项使用iCheck方法重置其初始状态(但是如果绑定了check uncheck事件,可能会处发,注意业务逻辑处理)

2019-07-08

Bean 属性复制

不要使用Apache BeanUtils,建议使用Spring BeanUtilsCglib BeanCopier
为什么阿里代码规约要求避免使用 Apache BeanUtils 进行属性复制
原因:1,性能问题 输出了大量的日志调试信息,重复的对象类型检查和类型转换;2.在进行属性拷贝时,低版本CommonsBeanUtils 为了解决Date为空的问题会导致为目标对象的原始类型的包装类属性赋予初始值,如 Integer 属性默认赋值为 0,尽管你的来源对象该字段的值为 null。

2019-07-04

iframe中调用摄像头和麦克风

需要在iframe中增加allow属性allow="geolocation; microphone; camera; midi; encrypted-media;"
在react中

                                    
                                
或者使用react组件react-iframe
                                    import Iframe from 'react-iframe'
                                    
                                
但是在一些低版本react中,不支持allow属性,代码中加了打包之后allow属性会消失 需要其他方式设置
                                    componentDidMount() {
                                        let iframe = window.document.getElementById("mainIframe");
                                        iframe.allow="microphone;camera;midi;encrypted-media;";
                                    }
                                

顶级window必须是https的(iframe一定得是https的,不然浏览器会报错:Mixed Content),iframe可以与顶级window是跨域的, 否则window.navigator.mediaDevices对象回事undefined,无法访问媒体设备;
Mixed Content:
https网页中,如果请求的内容属于http协议,则称为 Mixed Content,W3C 将 Mixed Content 分为 Optionally-blockable 和 Blockable,Optionally-blockable定义为:
1.通过 <img> 标签加载的图片; 2.通过 <video> / <audio> 和 <source> 标签加载的视频或音频; 3.预读的(Prefetched)资源;
除Optionally-blockable之外所有的 Mixed Content 都是Blockable,浏览器必须禁止加载这类资源。所以现代浏览器中,对于 HTTPS 页面中的 JavaScript、CSS,iframe等 HTTP 资源,一律不加载,直接在控制台打印错误信息

2019-06-26

使用了dubbo的tomcat不能使用shutdown.sh关闭

原因: com.alibaba.dubbo.remoting.transport.netty.NettyClient创建了NioClientSocketChannelFactory, NioClientSocketChannelFactory创建了NioClientBossPool, NioClientBossPool构造时创建了HashedWheelTimer, HashedWheelTimer创建时使用的是Executors.defaultThreadFactory(), 这个线程工厂创建的线程是非daemon的,因此必须调用NioClientSocketChannelFactoryreleaseExternalResources方法才可以优雅地停止这些非daemon线程。而dubbo出于规避netty的一个bug https://issues.jboss.org/browse/NETTY-424 所以注释掉了NettyClient里的doClose方法里的逻辑,而采用注册shutdownhook的方式进行资源的释放,但这个方案其实并不能释放Netty的资源, 正常关闭java进程时,因为有非daemon线程存在,所以shutdownhook并不会执行.

                                    @Override
                                    protected void doClose() throws Throwable {
                                        /*try {
                                            bootstrap.releaseExternalResources();
                                        } catch (Throwable t) {
                                            logger.warn(t.getMessage());
                                        }*/
                                    }
                                
                                    static {
                                        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                                            public void run() {
                                                if (logger.isInfoEnabled()) {
                                                    logger.info("Run shutdown hook of netty client now.");
                                                }
                                                try {
                                                    channelFactory.releaseExternalResources();
                                                } catch (Throwable t) {
                                                    logger.warn(t.getMessage());
                                                }
                                            }
                                        }, "DubboShutdownHook-NettyClient"));
                                    }
                                

tomcat 关闭方式 1.tomcat启动时,代码await()方法根据server.xml中的配置,阻塞监听关闭端口,直到有关闭消息进来;

org.apache.catalina.startup.Catalina.java
                                    if (await) {
                                        await();
                                        stop();
                                    }
                                
2.shutdown.sh 调用org.apache.catalina.startup.Bootstrapmain方法, 反射调用org.apache.catalina.startup.CatalinastopServer方法, stopServer方法根据server.xml中的配置,
                                    
                                        ...
                                    
                                
找到配置的端口8005,向这个端口发送配置的字符串SHUTDOWN"

3.await()方法监听到有数据到来,并且是配置的SHUTDOWN,则await方法成功返回,并执行stop()和 注册的ShutdownHooks,成功退出。

4.tomcat自己创建的线程都是守护线程pollerThread.setDaemon(true);
                                    // Start poller threads
                                    pollers = new Poller[pollerThreadCount];
                                    for (int i = 0; i < pollerThreadCount; i++) {
                                        pollers[i] = new Poller(false);
                                        pollers[i].init();
                                        Thread pollerThread = new Thread(pollers[i], getName() + "-Poller-" + i);
                                        pollerThread.setPriority(threadPriority);
                                        pollerThread.setDaemon(true);
                                        pollerThread.start();
                                    }
                                

SO,web项目中慎用Executors以及非守护线程, 使用Executors时要自定义线程创建工厂类


关于server.xml中的AJP协议的端口监听
                                
                                    ....
                                
                            

"ajp13是一个二进制的TCP传输协议,相比HTTP这种纯文本的协议来说,效率和性能更高,也做了很多优化。显然,浏览器并不能直接支持AJP13协议, 只支持HTTP协议。所以实际情况是,通过Apache的proxy_ajp模块进行反向代理,暴露成http协议给客户端访问。
其他支持AJP协议的代理服务器当然也可以用这种做法。但是实际情况是,支持AJP代理的服务器非常少,比如目前很火爆的Nginx就没这个模块 (默认没有这种模块,有用户自己实现的模块)。 因此tomcat的配置大部分都是关闭AJP协议端口的, 因为除了Apache之外别的http server几乎都不能反代AJP13协议,自然就没太大用处了。"

2019-06-20

log4j2日志:开发环境正常,服务器上不输出

参考链接:记一次项目上线后Log4j2不输出日志的坑

防链接丢失,简要记录

1.查看日志:Class path contains multiple SLF4J bindings.
maven依赖中有两个对日志实现的桥接包 slf4j-log4j12-1.7.22.jar(log4j),log4j-slf4j-impl-2.6.6.jar (log4j2)

2.官方资料发现slf4j在绑定时,如果有多个可以绑定的包,SLF4J选择绑定的方式由JVM确定,并且出于所有实际目的应该被认为是随机的。
slf4j-api.1.7.21.jar 中的LoggerFactory.java

                                    import org.slf4j.helpers.SubstituteLoggerFactory;
                                    import org.slf4j.helpers.Util;
                                    import org.slf4j.impl.StaticLoggerBinder; // 此行 import的是桥接包中的类,由JVM选择
                                    ...
                                    // 绑定方法
                                    private final static void bind() {
                                        try {
                                            Set>URL> staticLoggerBinderPathSet = null;
                                            // skip check under android, see also
                                            // http://jira.qos.ch/browse/SLF4J-328
                                            if (!isAndroid()) {
                                                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
                                                reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
                                            }
                                            // the next line does the binding
                                            StaticLoggerBinder.getSingleton(); // 桥接包的类在此使用
                                            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
                                            reportActualBinding(staticLoggerBinderPathSet);
                                            fixSubstituteLoggers();
                                            replayEvents();
                                            // release all resources in SUBST_FACTORY
                                            SUBST_FACTORY.clear();
                                
3.所以可能开发时,JVM选择了log4j-slf4j-impl, 服务器上选择了slf4j-log4j12,导致没有日志输出和报错

4.使用dependency:tree 命令查看多余的依赖并删除

2019-06-19

java 8:java.library.path dll 和 so 该放在哪里
默认情况下:System.getProperty("java.library.path");

1.windows 10: = %PATH%

2.linux:

                                    =$LD_LIBRARY_PATH:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
                                

3.mac 10.14

                                     =$JAVA_LIBRARY_PATH:~/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
                                

DYLD_LIBRARY_PATH 和 LD_LIBRARY_PATH 将会被忽略


如果指定了JVM参数,-Djava.library.path 将会覆盖默认值, 结果将是你设定的值

2019-06-01

“疼痛是一个了不起的老师,但前提是它必须很尖锐。慢性疼痛会劫持你的反应、你的想法、你的人际关系以及你的生产力,并让它们都变得畸形。慢性疼痛的可怕之处是,你会变得习惯它们。”

2019-05-20

BigDecimal等值比较不能用equals, 要用compareTo...
用equals方法不仅会比较值的大小,还会比较两个对象的精确度,而compareTo方法则不会比较精确度,只比较数值的大小

2019-05-15

LeBlanc Rule:Later equals never

2019-05-14

"有脾气是本能,控制住脾气是本事"

2019-05-13

JS取深度对象中的值
https://www.jianshu.com/p/77ce60122346
https://segmentfault.com/q/1010000016285893

几种方式

可选运算符最方便,但不一定能用;还是lodash的调用方便些