java常量池

package 测试常量;

public class Test {
public static void main(String[] args){
String s1 = “hello world”;
String s2 = “hello world”;
System.out.println(s1==s2);

String s4 = new String(“你好”);
String s3 = “你好”;
System.out.println(s3==s4);

Integer i1 = 10;
Integer i2 = 10;
System.out.println(i1 == i2);

Integer i3 = 2000;
Integer i4 = 2000;
System.out.println(i3 == i4);

Integer i5 = new Integer(10);
Integer i6 = new Integer(10);
System.out.println(i5 == i6);

int i7 = 2000;
int i8 = 2000;
System.out.println(i7 == i8);

Double f1 = new Double(1.01);
Double f2 = new Double(1.01);
System.out.println(f1 == f2);

Double f3 = 1000.01;
Double f4 = 1000.01;
System.out.println(f3 == f4);

double f5 = 1000.01;
double f6 = 1000.01;
System.out.println(f5 == f6);
}
}


输出结果是

true
false
true
false
false
true
false
false
true

ubuntu下linux创建桌面启动器以及菜单栏点击失效的解决方法

创建桌面启动器

进入/usr/share/applications

vi eclipse.desktop

输入一下内容

[Desktop Entry]
Encoding=UTF-8
Name=eclipse
Comment=Eclipse IDE
Exec=/home/jiang/eclipse/eclipse
Icon=/home/jiang/eclipse/icon.xpm
Terminal=false
StartupNotify=true
Type=Application
Categories=Application;Development;
Exec=env UBUNTU_MENUPROXY=0 /home/jiang/eclipse/eclipse

保存后,将这个文件复制到桌面文件夹
cp /usr/share/applications/eclipse.desktop /home/jiang/桌面

对于eclipse打不开菜单的情况,可以修改eclipase文件夹下的eclipse.ini为

-startup
plugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar
–launcher.GTK_version
2
–launcher.library
plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.300.v20150602-1417
-product
org.eclipse.epp.package.jee.product
–launcher.defaultAction
openFile
-showsplash
org.eclipse.platform
–launcher.XXMaxPermSize
256m
–launcher.defaultAction
openFile
–launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.7
-XX:MaxPermSize=256m
-Xms256m
-Xmx2048m

————————————

–launcher.GTK_version
2

这一部分是新增的部分

linux下编译安装mysql-connector-cpp

首先在github上下载mysql-connector-cpp

git clone https://github.com/mysql/mysql-connector-cpp.git

git上面有两个分支,2.0版本是支持mysql作为文档存储的接口,1.1版本是支持正常的关系数据库存储接口

首先我们编译安装2.0版本,进入代码目录执行

cmake .

cmake –build . –config CCC

cmake –build . –target install –config CCC

到这里已经安装完毕.

然后到testapp下编译测试样例

cmake .

提示出错,WITH-CONCPP没有设置,我试了编辑/etc/profile文件,设置这个变量为/usr/local/mysql/connector-c++-2.0/,但是仍然提示没有设置,于是我将CMakeLists中的

set(WITH_CONCPP $ENV{WITH_CONCPP} CACHE PATH “MySQL Connector/C++ 2.0 install location”)

改为

set(WITH_CONCPP “/usr/local/mysql/connector-c++-2.0/” CACHE PATH “MySQL Connector/C++ 2.0 install location”)

继续cmake .

提示出错,在/usr/local/mysql/connector-c++-2.0/lib64下找不到依赖库

那么将目录下生成的 libmysqlcppconn2.so libmysqlcppconn2.so.1 libmysqlcppconn2.so.1.0 拷贝到/usr/local/mysql/connector-c++-2.0/lib64中,没有的创建一个即可。

cmake .

make

在run文件夹下面生成了两个可执行文件

devapi_test xapi_test

这两个文件的区别在于,xapi_test实现了c的接口,是通过mysql的一个叫做x plugin的插件连接mysql的,而devapi则是使用了c++的接口。所以如果使用xapi接口的话,mysql安装时必须安装x plugin

接下来编译安装1.1版本,先将当前的改动都commit了,然后

git checkout 1.1,

cmake .

如果出错。

报缺少boost库错误,可以

sudo apt-get install libboost-all-dev

报缺少mysql.h等错误,可以通过sudo apt-get install libmysql++-dev

然后make

sudo make install

然后将生成的动态库拷贝的/usr/local/lib下

sudo cp libmysqlcppconn.so* /usr/local/lib/

c++中的中文字符分割

在utf-8编码的前提下,一个字符可能占用的空间为1~4个char,由于这种不确定的字符长度导致在utf-8编码的string中,无法直接使用substr进行字符串分割。

解决的方案的关键在于利用utf-8编码的特点,utf-8的第一个字符的前缀连续为1的个数代表这个”字“占用的字符数量,当只有一个字符时,第一个字符的第一位为0。具体的说明可以参考这篇文章。http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

这里主要说明怎么利用代码解决这个问题

int getUtf8CharLength(char c){
    int len = 0;
    if(c > 0){              //利用计算机中数字的存储特点,第一位为1为负,第一位为0为正,很容易判断
        return len + 1;     //第一位为0时为特殊情况,需要加1
    }
    while(c < 0){
        len++;
        c = c << 1;
    }
    return len;
}

std::string substrWithChinese(std::string str,unsigned int start,unsigned int length){
    unsigned int i = 0;             //标识前进的几个“字符”
    unsigned int cursor = 0;        //标识前进了几个“字”
    unsigned int save = 0;          //保存的字符标识
    unsigned int len = str.length();
    char* c = new char[len + 1];
    while(str[i] != '\0'&&length > 0){
        unsigned int l = getUtf8CharLength(str[i]); //获取字符长度
        if(cursor >= start){
            unsigned int m = l;
            while(m--){
                c[save++] = str[i++];
            }
            length--;
        }else{
            i+=l;
        }
        cursor++;
    }
    c[i] = '\0';
    return std::string(c);
}

ubuntu eclipse mars.2Bug修复

ubuntu eclipse mars.2Bug的bug具体表现为图标异常,菜单无法正常点击切换等等,问题是因为GTK方面,将eclipse的启动方式eclipse.desktop改为一下代码

   [Desktop Entry]
   Name=eclipse
   Comment=develop java app
   Exec=env SWT_GTK3=0 /home/jiang/software/eclipse/eclipse
   Icon=/home/jiang/software/eclipse/icon.xpm
   Terminal=false
   Type=Application
   Categories=devtool

网站登录系统设计

一、前言

一个网站的登录系统可以算作是一个网站的大门,如何让这个大门足够的安全,并且又不用太复杂是一个很考验经验的工作。作为一个没有经验的新手,简单记下一点自己在做网站登录系统设计时做法。

二、前提

首先假设我们设计的网站是一个单服务器的应用,并且他有多种登录方式(邮箱,手机,用户名),以及多种登录途径(web,app)。

三、正文

1.会话状态

因为是单服务器的应用,所以不用担心多台服务器之间的会话状态转移的问题,所以为了简单,我们采用的是cookie方式,这样既不用在用户关闭浏览器后再次访问就要重新登录,也可以通过设定cookie的失效时间,来让浏览器自动在一定时间后让用户重新登录,保护用户设备丢失带来的风险。

2.登录方式

考虑到需要支持邮箱,手机或者是用户名的登录,也就是用户随意输入其中的一种以及密码都要可以登录,所以要对用户名有一定的限制,首先用户名不能重复,并且用户不能是手机或者邮箱,因此要对用户名做一些简单的限制——用户名不能为纯数字,也不能包含@符号。

3.密码存储

密码的存储是一定要足够安全的。因此对密码的存储一定要够安全。我采用的是密码+salt的方式,使用sha-256加密。

4.身份验证

身份验证上,我在cookie中填入用户id和token连接而成的字符串(称为id_token),例如24|dashdiuasdhgiuagsduigaiusdg这种形式,|符号前面是Id,后面是token,token是登录时随机生成的,在登录时会讲登录记录插入到数据库中,这条记录包括用户id,登录名(用户名,邮箱或手机中的任一种)、登录途径(web还是app)、登录时生成的token、登录时间等等,然后之后用户提交请求时都会验证cookie,将cookie中的id和token截取出来,与最新的一条该用户id的登录成功的记录的token对比,如果一致,则表示身份是对的。这种做法可以很好的防止伪造cookie。对于app来说,将这个cookie保存下来就可以一直作为登录凭证。如果遇到手机丢失,想使手机上的登录失效,重新用新手机登录一次即可。

5.多端登录的冲突解决

在4.身份验证中说到,登录的身份验证是根据最新的该用户的登录记录来判断的,所以如果用户在app上登录了,再在网站上登录则会使app的登录失效,为了解决这个问题,可以在登录时附带上登录方式的字段,那么就可以解决web端和app端的冲突问题。

linux下使用crontab进行网站内容和数据库定期备份

crontab有几个常用的命令

crontab -l 列举crontab的任务

crontab -e 编辑crontab的任务

crontab -r 删除crontab的任务

crontab -h crontab的帮助

crontab -i 删除crontab前进行提示

crontab -e进行编辑任务时会使用nano进行编辑,编辑命令如下示例。

分 时 每月的第几天 每周的周几 命令

前5个参数可以使用通配符 *

m h dom mon dow command

设置每两分钟扫描一次,清理过期记录

*/2 * * * * /usr/bin/php /var/www/poker/scan.php >> /$

设置每周二23:29分备份一次

59 23 * * 2 /bin/bash /home/back.sh
59 23 * * 2 /bin/bash /home/back.sh就是我用来定期备份的指令,主要就是配合一个shell脚本

#!/bin/bash
cd /home
mv backup/* oldbackup/
echo “old backup file has been moved to oldbackup folder”;
cd /home/backup
Now=date "+%Y-%m-%d-%H-%M-%S"
File_emlog=”backup-emlog-“{Now}”.sql”
mysqldump -u me -ppassword emlog >
File_emlog
File_java=backup-java-Now.sql
mysqldump -u me -ppassword java >
File_java
File_plan=backup-plan-Now.sql
mysqldump -u me -ppassword plan >
File_plan
File_sms=backup-sms-Now.sql
mysqldump -u me -ppassword sms >
File_sms
File_tu=backup-tu-Now.sql
mysqldump -u me -ppassword tu >
File_tu
File_wordpress=backup-wordpress-Now.sql
mysqldump -u me -ppassword wordpress >
File_wordpress

echo “your databases backup successfully completed”;
#数据文件到这里备份完毕

#下面备份网站的文件
tar -czf /home/backup/back_www.tar.gz /var/www

JavaEE post Base64的图片丢失数据解决

项目中有个提交Base64编码的图片到服务器,服务器端转换成图片的二进制流存放到数据库中。在实际使用中发现,保存到数据库中图片文件有损坏。表现为前一部分二进制数据相同,到了后面就开始不同了。

一开始的步骤为:

st=>start: 准备Base64数据
op1=>operation: Post准备好的Base64数据
op2=>operation: 将数据并转换为byte[]
op3=>operation: 存储到数据库
e=>end

st->op1->op2->op3->end

为了找出问题,将post这个步骤省去,并将数据直接存成图片以便观察

st=>start: 准备Base64数据
op2=>operation: 将数据并转换为byte[]
op3=>operation: 存储成图片
e=>end

st->op2->op3->end

这一步保存的文件的大小是9.0k

st=>start: 准备Base64数据
op1=>operation: Post准备好的Base64数据
op2=>operation: 将数据并转换为byte[]
op3=>operation: 存储成图片
e=>end

st->op1->op2->op3->end

这一步保存的文件的大小是8.9k

上面两步对比可以说明数据在传输的时候出现了丢失的情况,于是我猜测是不是tomcat对post方式做了限制,发现不是。查询资料发现,Base64位数据传输的时候中间的+号容易发生丢失。解决方法是将post过来的数据先UrlEncode一下即可

发生这个问题的没有找到明确的可靠的解释,其中一片文章解释为javascript将+当做字符串连接符号处理导致丢失。

Java虚拟机学习记录(九)——类文件结构(上)

##一、前言
在Java开发中,可以通过javac将.java的源代码编译为.class的类文件。之前一直以为,只有java语言可以编译为.class。但是在前些天的学习中,了解到不仅仅是Java语言可以编译成.class文件然后运行在Java虚拟机上,Clojure、Groovy、JRuby、Jython、Scala等语言都可以运行在Java虚拟机上。觉得这真是太神奇了。今天这一章的内容刚好可以解释这些。

##二、Java虚拟机的无关系特点
一般都说Java是平台无关的,因为Java是运行在Java虚拟机上的,而Java虚拟机是开发成各个平台通用的。那么同时,Java虚拟机其实也是语言无关的,也就是说,Java虚拟机并不要求特定的语言。只要该语言可以被编译生成符合标准的class(类)文件,那么就是可以运行在Java虚拟机上了。那么,类文件的结构是什么样的呢?

##三、类文件的基本知识
##1.基本单位
类文件是以8位字节为基础单位的二进制流,没有任何分割符。当遇到需要占用8位以上的数据时,则会按高位在前的方式分割成若干个8位字节进行存储。
###2.存储数据的数据格式:无符号数和表。
无符号数属于基本数据类型。以u1,u2,u4,u8来分别代表1个字节,2个字节,4个字节,8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者安装UTF-8编码构成的字符串值。
表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性以_info结尾。

##三、类文件的结构
###1.魔数和版本号
class文件的前四个字节称为魔数(Magic Number),用来描述文件的格式,class文件的魔数是0xCAFEBABE。第五六个字节描述次版本号(Minor Version),第七八个字节描述主版本号。
###2.常量池
紧接着主版本号之后是常量池的入口。由于常量池的常量数量是变化的,所以在常量池的入口有一个u2类型(第9,10位)的数据,代表常量池容量计数值。不过这个计数是从1开始的,所以如果这个值是22,则代表有21个常量。
常量池中主要有两种类型:字面量(Literal)和符号引用(Symbolic References)。

a.字面量: 接近java语言的常量的概念,如文本字符串,声明为final的常量值等
b.符号引用:1.类和接口的全限定名(Fully Qualified Name) 2.字段的名称和描述符(Descriptor) 3.方法的名称和描述符

java代码在编译时不会像c/c++一样进行”连接”,这样在编译生成的class文件中不会保存各个方法、字段的最终内存布局信息,而是在运行的时候进行动态连接。也就是从常量池中获得方法、字段对应的符号引用,再在类创建或运行时解析翻译到具体的内存地址之中。

常量池中每一个常量都是一个表,在JDK1.7前共有11中常量,在JDK1.7中为了更好的支持动态语言调用,又额外增加了3种(CONSTANT_MethodHandle_info、CONSTANT_MethodType_info和CONSTANT_InvokeDynamic_info)。

这14个表的共同之处在于,表开始的第一项是一个u1类型的标志位(tag),代表当前这个常量属于哪种常量类型。

类型 标志 描述
CONSTANT_Utf8_info 1 UTF-8编码的字符串
CONSTANT_Integer_info 3 整型字面量
CONSTANT_Float_info 4 浮点型字面量
CONSTANT_Long_info 5 长整型字面量
CONSTANT_Double_info 6 双精度浮点型字面量
CONSTANT_Class_info 7 类或接口的符号引用
CONSTANT_String_info 8 字符串类型字面量
CONSTANT_Fieldref_info 9 字段的符号引用
CONSTANT_Methodref_info 10 类中方法的符号引用
CONSTANT_InterfaceMathodref_info 11 接口中方法的符号引用
CONSTANT_NameAndType_info 12 字段或方法的部分符号引用
CONSTANT_MethodHandle_info 15 表示方法句柄
CONSTANT_MethodType_info 16 表示方法类型
CONSTANT_InvokeDynamic_info 18 表示一个动态方法调用点

###3.访问标志
在常量池结束之后,紧接着的是访问标志,用来描述一些类和接口的访问信息,包括这个Class是类还是接口,是否定义为public,是否是abstract如果是类的话,是否是final。

###4.类索引,父类索引与接口索引集合
访问标志之后是类索引,父类索引与接口索引集合。类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合(interfaces)是一组u2类型的数据集合(对应java语言中的单继承和多接口实现),

###5.字段表集合
再之后是字段表集合。字段表(Field_info)用于描述接口或者类中声明的变量。字段(field)包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。一个字段的描述包括:字段的作用域(public,private,protected修饰符)、是实例变量还是类变量(static修饰符)、可变性(final)、并发可见性(volatile修饰符,是否强制从主内存读写)、可否被序列化(transient修饰符)、字段数据类型(基本类型,数组,对象)、字段名称。

###6.方法表集合
字段表之后是方法表集合。很显然,对方法的描述和对字段的描述是很像的。volatile和transient不能描述方法,但是syncronized、native、strictfp和abstract是方法独有的。

Java虚拟机学习记录(八) —— 虚拟机性能监控与故障处理工具

一、前言

我觉得Java的强大之处在于它有非常完善的生态环境,从开发工具到分析处理工具。使用JDK中提供的工具可以在遇到程序故障时快速定位故障发生的原因并进行调优。

二、JDK命令行工具

a、jps(JVM Process Status):虚拟机进程状况工具

jps可以用来列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main class,main函数所在的类)名称以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID)。

jps命令格式:
jps [option] [hostid]
使用范例:
jiang@jiang-HP-ENVY-Notebook:~$ jps -l
6084 /home/jiang/eclipse//plugins/org.eclipse.equinox.launcher_1.3.200.v20160318-1642.jar
6152 sun.tools.jps.Jps
jps可以通过RMI协议查询开启了RMI服务的远程虚拟机进程状态,hostid为RMI注册表中注册的主机名。

选项 作用
-q 只输出LVMID,省略主类的名称
-m 输出虚拟机进程启动时传递给主类main()函数的参数
-l 输出主类的全名,如果进程执行的是Jar包,输出Jar路径
-v 输出虚拟机进程启动时JVM参数

b、jstat(JVM Statistics Monitoring Tool): 虚拟机统计信息监视工具

jstat是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类加载、内存、垃圾收集、JIT编译等运行数据。

jstat命令格式为:
jstat [option vmid [interval [s|ms] [count]] ]
如果VMID是本地进程,和LVMID是一样的,如果是远程虚拟机进程,那VMID的格式是:
[protocol:][//]lvmid[@hostname[:port]/servername]
参数inerval和count代表查询间隔和次数,如果省略则表示只查询一次。
使用范例:
jstat -gc 2764 250 20
代表每250ms查询一次进程2764垃圾收集状况,一共查询20次

选项 作用
-class 监视类装载,卸载数量,总空间以及类装载所耗费的时间
-gc 监视Java堆状况,包括Eden区,两个survivor区,老年代,永久代等的容量、已用空间、GC时间合计等信息
-gccapacity 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-gcutil 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause 与-gcutil功能一样,但会额外输出导致上一次GC的原因
-gcnew 监视新生代GC状况
-gcnewcapacity 监视新生代使用到的最大、最小空间
-gcold 监视老年代GC状况
-gcoldcapacity 监视老年代使用到的最大、最小空间
-gcpermcapacity 输出永久代使用到的最大、最小空间
-compiler 输出JIT编译器编译过的方法、耗时等信息
-printcompilation 输出已被JIT编译的方法