解决python 3.6 from http.client import HTTPSConnection ImportError: cannot import name ‘HTTPSConnection’的方法

我今天在用python3.6的时候出现了报错

from http.client import HTTPSConnection ImportError: cannot import name 'HTTPSConnection'

后来查看了python 3.6的client.py的源码和查阅了一些资料后,发现是我服务器没有安装ssl的问题。

rpm -aq|grep openssl
yum install openssl-devel -y
rpm -aq|grep openssl

然后重新编译安装python 3.6

./configure --with-ssl --enable-optimizations
make
make install

然后就ok啦!

SpringMVC视图解析器InternalResourceViewResolver问题分析

今天在搭建SpringMVC开发框架的时候,出现freemarker的视图没有找到,报404错误。我的配置代码如下:

<!--freemarker -->
<mvc:view-controller path="/" view-name="homepage/index”/>

<!-- jsp -->
<mvc:view-controller path="/login" view-name="login”/>

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
    <property name="contentType" value="text/html;charset=UTF-8"/>
    <property name="order" value="2"/>
</bean>

<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
    <property name="prefix" value="" />
    <property name="suffix" value=".ftl" />
    <property name="contentType" value="text/html;charset=UTF-8"/>
    <property name="order" value="3"/>
</bean>

我配置了两个视图解析器,所以视图解析是链式的,如果一个视图解析器没有找到对应的view-name,则开始找第二的解析器。InternalResourceViewResolver的property中的order值是2,FreeMarkerViewResolver的property的order为3,我们知道order,从小到大,越小的优先级越高,那么InternalResourceViewResolver一定是先运行的。

InternalResourceViewResolver的父类UrlBasedViewResolver中有一个方法loadView用于创建加载视图,源码如下:

/**
 * Delegates to {@code buildView} for creating a new instance of the
 * specified view class, and applies the following Spring lifecycle methods
 * (as supported by the generic Spring bean factory):
 * <ul>
 * <li>ApplicationContextAware's {@code setApplicationContext}
 * <li>InitializingBean's {@code afterPropertiesSet}
 * </ul>
 *
 * @param viewName the name of the view to retrieve
 * @return the View instance
 * @throws Exception if the view couldn't be resolved
 * @see #buildView(String)
 * @see org.springframework.context.ApplicationContextAware#setApplicationContext
 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
 */
@Override
protected View loadView(String viewName, Locale locale) throws Exception {
    AbstractUrlBasedView view = buildView(viewName);
    View result = applyLifecycleMethods(viewName, view);
    return (view.checkResource(locale) ? result : null);
}

最后一行用到了view的checkResource方法。
我们看到InternalResourceViewResolver对应的view是InternalResourceView,它的子类只有JstlView,下面是view的类图关系。

查看InternalResourceView的父类AbstractUrlBasedView,可以找到它里面的checkResource方法,源码如下:

/**
 * Check whether the underlying resource that the configured URL points to
 * actually exists.
 *
 * @param locale the desired Locale that we're looking for
 * @return {@code true} if the resource exists (or is assumed to exist);
 * {@code false} if we know that it does not exist
 * @throws Exception if the resource exists but is invalid (e.g. could not be parsed)
 */
public boolean checkResource(Locale locale) throws Exception {
    return true;
}

可以看到这个方法直接返回true,根本就没有check。
至此我们就找到问题的原因了,InternalResourceView是不会check资源文件是否存在,当InternalResourceViewResolver先运行的时候,遇到其他的view-name如本例的freemarker的文件根本不会做check,导致最终出现404的情况。

如何解决这个问题呢?
第一种方法:把order的值修改下,把InternalResourceViewResolver的order改成最大的,即最后解析让其他的会check文件是否存在的解析器先运行。
第二种方法:自定义一个view类继承JstlView,自己写一个checkResource将父类的的checkResource override掉。代码如下:

package com.tonitech.ancestor.common;

import org.springframework.web.servlet.view.JstlView;

import java.io.File;
import java.util.Locale;

/**
* 解决多个ViewResolver时jsp获取不到时,跳转到下一个ViewResolver
*/
public class DefaultJstlView extends JstlView {

    @Override
    public boolean checkResource(Locale locale) throws Exception {
        File file = new File(this.getServletContext().getRealPath("/") + getUrl());
        return file.exists();//判断该jsp页面是否存在
    }
}

然后在InternalResourceViewResolver的bean配置里加一行:

<property name="viewClass" value="com.tonitech.ancestor.common.DefaultJstlView"/>

通过这两种方法都可以解决问题。

MySQL datetime类型使用like导致全表扫描的问题总结

最近项目里有一段mysql语句导致了数据库服务器的load过高报警,语句如下:

SELECT
    content
FROM
    communication_log
WHERE
    gmt_create LIKE '2016-12-02%';

explain了这条sql之后可以看出执行计划是全表扫描,查询了882210条记录,字段的索引没有用上,查询的时间为1.23:2be95c40-3efa-4a59-be3c-4437c1744c0a

原因是gmt_create是datetime类型,条件中写了like,会有隐式转换,gmt_create字段需要在比较前转换成String类型,字段的索引将不会被用到,查询变为全表扫描。

解决方法是把原来的SQL改成:
SELECT
    content
FROM
    communication_log
WHERE
    gmt_create BETWEEN '2016-12-02 00:00:00' AND '2016-12-02 23:59:59';

explain的结果,用上了索引只检索给定范围的行,扫描的行数也减少到了108行,查询的时间为0.02:

1b89fe5c-7e16-4a86-8ec5-c6d9c9008167

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory解决方法

今天在搭建一个项目单元测试环境跑测试用例的时候遇到了致命错误:
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory
这个是什么情况?
翻看控制台输出信息看到一段:
SLF4J: Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting StackOverflowError.
SLF4J: See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.

翻看了上面说的网站提示信息:
The purpose of slf4j-log4j12 module is to delegate or redirect calls made to an SLF4J logger to log4j. The purpose of the log4j-over-slf4j module is to redirect calls made to a log4j logger to SLF4J. If SLF4J is bound with slf4j-log4j12.jar and log4j-over-slf4j.jar is also present on the class path, a StackOverflowError will inevitably occur immediately after the first invocation of an SLF4J or a log4j logger.

意思是slf4j-log4j12是用来代理或者重定向调用使一个SLF4J的日志通过log4j输出,log4j-over-slf4j的目的是将log4j的日志重定向输出到SLF4J,如果它俩在一个class path下造成StackOverflow的错误,因为它俩会陷入一个死循环。如果不明白SLF4J和log4j的同学可以转到:http://www.importnew.com/7450.html 仔细阅读。

于是我寻找了项目的maven依赖,发现有3个依赖中出现了slf4j-log4j12.jar,在每个依赖里加上:

<exclusion>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
</exclusion>

最终解决了问题。

再次跑测试用例的时候,还有一堆报错也不见了:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/wangzhiang/.m2/repository/ch/qos/logback/logback-classic/1.1.3/logback-classic-1.1.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/wangzhiang/.m2/repository/org/slf4j/slf4j-log4j12/1.6.1/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

原因是:SLF4J会在编译时会绑定import org.slf4j.impl.StaticLoggerBinder; 该类里面实现对具体日志方案的绑定接入。任何一种基于SLF4J的实现都要有一个这个类。如:slf4j-log4j12-1.6.1提供对log4j的一种适配实现。我的项目中存在logback-classic-1.1.3和slf4j-log4j12-1.6.1两个实现SLF4J的包同时出现,就出现了上面的报错,加上依赖的exclusion去掉slf4j-log4j12即可。

CentOS 6.7下安装vsftpd FTP服务器经验

最近Wordpress从虚拟主机迁移到了VPS上,原来虚拟主机服务商有提供FTP,现在VPS需要自己安装一个FTP服务器来支持Wordpress的插件和主题升级。vsftpd是Linux下比较著名的FTP服务器,我选择它搭建FTP服务器。

 

第一步:安装vsftpd

查看你的服务器是否已经安装vsftpd

rpm -qa | grep vsftpd

如果已经安装就略过下一步yum安装。如果没有安装过就执行以下命令:

yum -y install vsftpd

 

第二步:基于虚拟用户的配置

所谓虚拟用户就是没有使用真实的帐户,只是通过映射到真实帐户和设置权限的目的。虚拟用户不能登录CentOS系统。

1. 修改配置文件

打开/etc/vsftpd/vsftpd.conf,修改该文件原来的配置,如下(这里需要一个一个项目在编辑器里查找并修改,注意YES或NO等配置项后面不要在复制过程中多出不必要的空格):

#设定不允许匿名访问
anonymous_enable=NO

#设定本地用户可以访问。注:如使用虚拟宿主用户,在该项目设定为NO的情况下所有虚拟用户将无法访问
local_enable=YES

#使用户不能离开主目录
chroot_list_enable=YES

ascii_upload_enable=YES

#设定支持ASCII模式的上传和下载功能
ascii_download_enable=YES

#PAM认证文件名。PAM将根据/etc/pam.d/vsftpd进行认证
pam_service_name=vsftpd

以下这些是关于vsftpd虚拟用户支持的重要配置项,默认vsftpd.conf中不包含这些设定项目,需要自己手动添加到/etc/vsftpd/vsftpd.conf中:

#设定启用虚拟用户功能
guest_enable=YES

#指定虚拟用户的宿主用户,CentOS中已经有内置的ftp用户了
guest_username=ftp

#设定虚拟用户个人vsftp的CentOS FTP服务文件存放路径。存放虚拟用户个性的CentOS FTP服务文件(配置文件名=虚拟用户名
user_config_dir=/etc/vsftpd/vuser_conf

 

2. 进行认证

首先,安装Berkeley DB工具,很多人找不到db_load的问题就是没有安装这个包。

yum install db4 db4-utils

然后,创建用户密码文本/etc/vsftpd/vuser_passwd.txt ,注意奇行是用户名,偶行是密码:

wordpress
123456

接着,生成虚拟用户认证的db文件:

db_load -T -t hash -f /etc/vsftpd/vuser_passwd.txt /etc/vsftpd/vuser_passwd.db

随后,编辑认证文件/etc/pam.d/vsftpd,全部注释掉原来语句,再增加以下两句:

auth required pam_userdb.so db=/etc/vsftpd/vuser_passwd
account required pam_userdb.so db=/etc/vsftpd/vuser_passwd

最后,创建虚拟用户配置文件:

mkdir /etc/vsftpd/vuser_conf/
vi /etc/vsftpd/vuser_conf/wordpress  //文件名等于vuser_passwd.txt里面的账户名,否则下面设置无效

内容如下(这里需要注意YES或NO等配置项后面不要在复制过程中多出不必要的空格):

local_root=/home/wwwroot
write_enable=YES
anon_umask=022
anon_world_readable_only=NO
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES

 

3. 设置Selinux(可省略)

setsebool -P ftp_home_dir=1   //设置ftp可以使用home目录
setsebool -P allow_ftpd_full_access=1   //设置ftp用户可以有所有权限

 

4. 设置FTP根目录权限

mkdir /home/wwwroot   //创建目录,如果目录已存在请省略
chmod a-w /home
chmod -R 777 /home/wwwroot

最新的vsftpd要求对主目录不能有写的权限所以/home为a-w,主目录下面的子目录再设置777权限。

 

5. 设置防火墙

打开/etc/sysconfig/iptables,添加一句:

-A INPUT -p tcp -m tcp --dport 21 -j ACCEPT

然后保存,并关闭该文件,在终端内运行下面的命令,刷新防火墙配置:

service iptables restart

启动FTP服务器:

service vsftpd start

 

6. 连接FTP服务器

现在你就可以使用FTP工具连接服务器了,建议使用FileZilla工具连接,连接的过程中如果出现报错,你只需要去搜索报错的内容调整服务器的配置就好了。

 

参考文章:http://www.cnblogs.com/xiongpq/p/3384759.html