没有比人更高的山

MySQL中drop user if exists功能的实现方法0

在编写可以重复执行的创建数据库的脚本时,我们知道下面语句可以测试数据库是否存在,如果存在的话就删除掉

1
DROP DATABASE IF EXISTS testdb;

但是我们没办法测试用户是否存在,MySQL是没有drop user if exist这样的功能的。详见:http://bugs.mysql.com/bug.php?id=19166

不过有另外一种变通的办法可以实现同样的功能,代码如下:

1
2
3
4
# a way to implement the functionality of 'drop user if exists' which mysql does
# not support for now
GRANT usage ON *.* TO testdb IDENTIFIED BY 'testdb';
DROP user testdb;

在执行grant的时候,如果数据库中不存在这个用户,那么MySQL会创建一个用户,并且赋以usage权限,usage权限等同于“no privileges”,至于为什么会有这个特殊的权限请见http://dev.mysql.com/doc/refman/5.0/en/privileges-provided.html#priv_usage,主要是在修改已有用户的grant option时使用的。

另外,使用MySQL5.0.0时,执行drop user时并不会删除其权限。MySQL5.0.2已经修正了这个问题,删除用户的时候会一并连权限以前删除。详见:http://dev.mysql.com/doc/refman/5.0/en/drop-user.html

VN:F [1.7.5_995]
Rating: 0.0/10 (0 votes cast)
VN:F [1.7.5_995]
Rating: 0 (from 0 votes)

Java反编译工具Jad详解1

做项目过程中需要反编译一个jar包,于是作了一些学习,记录下来。

Jad(JAva Decompiler)是一个Java的反编译器,可以通过命令行把Java的class文件反编译成源代码。

如果你在使用编写代码的时候遇到找不到源代码的第三方库,而且你又需要看看这个库的具体实现,那么你就需要使用这个东西。而且如果你是使用Eclipse的话,还有一个Eclipse插件JadClipseJadClipse提供一个class文件查看器可以直接打开class文件查看其反编译后的源代码, 太方便了,太方便了!

不过,可惜的是这个开源项目似乎已经关闭了,官方网站已经上不去了,有个叫Tomas Varaneckas的好心人收集了所有的版本提供给大家下载:JAD Java Decompiler Download

而且这个最新的版本也只支持Java 4,不支持Java 5。还有一个叫做JD-Core的工具支持Java 5的新特性,如enum等,而且它提供独立的GUI程序JD-GUI和基于Eclipse的插件JD-Eclipse,也很方便。但是对于JD-Core,作者没有提供下载的链接,他说“Open the sources of JD-Core is not on my roadmap: I spent too many time on this project.”当然后面也有一大篇文章是别人用来骂他的,可以看Add JD-Core to the download list,蛮有意思。

我的项目中需要将第三方库反编译出来,让后对其进行修改,然后再编译,不仅仅是查看,因此只能用命令行的Jad来做。

使用方法:

[1] 反编译一个class文件:jad example.class,会生成example.jad,用文本编辑器打开就是java源代码

[2] 指定生成源代码的后缀名:jad -sjava example.class,生成example.java

[3] 改变生成的源代码的名称,可以先使用-p将反编译后的源代码输出到控制台窗口,然后使用重定向,输出到文件:jad -p example.class > myexample.java

[4] 把源代码文件输出到指定的目录:jad -dnewdir -sjava example.class,在newdir目录下生成example.java

[5] 把packages目录下的class文件全部反编译:jad -sjava packages/*.class

[6] 把packages目录以及子目录下的文件全部反编译:jad -sjava packages/**/*.class,不过你仍然会发现所有的源代码文件被放到了同一个文件中,没有按照class文件的包路径建立起路径

[7] 把packages目录以及子目录下的文件全部反编译并建立和java包一致的文件夹路径,可以使用-r命令:jad -r -sjava packages/**/*.class

[8] 当重复使用命令反编译时,Jad会提示“whether you want to overwrite it or not”,使用-o可以强制覆盖旧文件

[9] 还有其他的参数可以设置生成的源代码的格式,可以输入jad命令查看帮助,这里有个人做了简单的翻译:jad命令总结

[10] 当然,你会发现有些源文件头部有些注释信息,不用找了,jad没有参数可以去掉它,用别的办法吧。

最后,jad不能直接反编译jar包,直接解压了再反编译吧(这个方法很显然,我实在不好意思写出来)。

VN:F [1.7.5_995]
Rating: 0.0/10 (0 votes cast)
VN:F [1.7.5_995]
Rating: 0 (from 2 votes)

一个隐藏了将近2年的Bug2

最近在维护华中科技大学电信系的电子档案库,发现了一个隐藏了将近2年的Bug,记录如下:

需求:一个科研项目有一定的工作量,而每个项目有很多参与人,需要为每个参与人设置其工作量分配额度。当用户添加了一个项目时,需要同时添加其参与人:

实现:当用户录入了科研项目信息之后,点击“添加参与人”的按钮,转向到选择参与人的页面,可以勾选任意数目的参与人,点击“保存”按钮后返回科研项目信息页面。

在执行保存选择的参与人信息时,检查所选择的人员是否已经在科研项目的参与人中存在的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
for (Iterator<string> iterator = selectedMemberList.iterator(); iterator.hasNext();) {
    ParticipatorBean participatorBean = new ParticipatorBean();
    long teacherId = Long.parseLong(iterator.next());
    Teacherbasicinfo teacher = ServiceProvider.getTeacherInfoService().findById(teacherId);
    Long id = teacher.getTeacherId();
    participatorBean.setTeacherId(id);
    participatorBean.setTeacherName(teacher.getTeacherName());
    if (participatorsMap.get(id) == null) {
        participatorsMap.put(String.valueOf(id), String.valueOf(id));
        participators.add(participatorBean);
    }
}
</string>

其中,selectedMemberList是选中的用户列表,ParticipatorBean是用来传递给前一个页面的参与人的Java类,Teacherbasicinfo是领域模型,代表教师基本信息,老师编号teacherId为Long型。

participatorsMap是我从来去除重复的一个HashMap,也就是说我每遍历一个Teacherbasicinfo,就将其teacherId转换成字符串型添加到这个Map中,在每次添加之前我先检查这个Map是否已经存在了(且不论这种方法的好与坏,这是我们几年前的代码了)

这段代码无编译异常、无运行异常,但是却有逻辑异常。有用户反映。多次选择的时候会有重复的项出现。

经过多番调试,最后发现第八行代码有误,应该将

1
if (participatorsMap.get(id) == null) {

改成为:

1
if (participatorsMap.get(String.valueOf(id)) == null) {

恍然大悟,虽然我使用的是范型,但是Map的get方法仍然接受的是Object类型的参数,不对其参数进行检查,其put方法的签名为V put(K key, V value),则会对key和value的类型都进行检查。

这是我的错呢,还是Java的错,为啥不把get方法的参数用范型类型检查一下呢?可能是sun的工程师有别的考虑吧。

VN:F [1.7.5_995]
Rating: 7.0/10 (2 votes cast)
VN:F [1.7.5_995]
Rating: -1 (from 1 vote)

Java int型转换中文大写数字表示方法0

之前写过一篇博客,记录的是如何将Java中文大写数字转int型,今天遇到的问题是将Java int型转换成中文大写数字表示。

下面是程序,很容易理解,不过,只支持10000以内的数字转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public static String intToChnNumConverter(int num){
    String resultNumber = null;
    if(num > 10000 || num < 0){
        return "";
    }
    HashMap chnNumbers = new HashMap();
    chnNumbers.put(0, "零");
    chnNumbers.put(1, "一");
    chnNumbers.put(2, "二");
    chnNumbers.put(3, "三");
    chnNumbers.put(4, "四");
    chnNumbers.put(5, "五");
    chnNumbers.put(6, "六");
    chnNumbers.put(7, "七");
    chnNumbers.put(8, "八");
    chnNumbers.put(9, "九");
 
    HashMap unitMap = new HashMap();
    unitMap.put(1, "");
    unitMap.put(10, "十");
    unitMap.put(100, "百");
    unitMap.put(1000, "千");
    int[] unitArray = {1000, 100, 10, 1};
 
    StringBuilder result = new StringBuilder();
    int i = 0;
    while(num > 0){
        int n1 = num / unitArray[i];
        if(n1 > 0){
            result.append(chnNumbers.get(n1)).append(unitMap.get(unitArray[i]));
        }
        if(n1 == 0){
            if(result.lastIndexOf("零") != result.length()-1){
                result.append("零");
            }
        }
        num = num % unitArray[i++];
        if(num == 0){
            break;
        }
    }
    resultNumber = result.toString();
    if(resultNumber.startsWith("零")){
        resultNumber = resultNumber.substring(1);
    }
    if(resultNumber.startsWith("一十")){
        resultNumber = resultNumber.substring(1);
    }
    return resultNumber;
}
VN:F [1.7.5_995]
Rating: 5.5/10 (2 votes cast)
VN:F [1.7.5_995]
Rating: +1 (from 1 vote)

Java中文大写数字转int型0

暂时不支持万以上级别,后面会加上这个。道理很简单,但我搜了一下google,找到的代码没有几个能直接用,所以分享下,直接贴代码了:

    public static int chnNumToIntConverter(String chnNum){
        HashMap<String, Integer> numbers = new HashMap<String, Integer>();
        numbers.put(”零”, 0);
        numbers.put(”一”, 1);
        numbers.put(”二”, 2);
        numbers.put(”三”, 3);
        numbers.put(”四”, 4);
        numbers.put(”五”, 5);
        numbers.put(”六”, 6);
        numbers.put(”七”, 7);
        numbers.put(”八”, 8);
        numbers.put(”九”, 9);
        HashMap<String, Integer> units = new HashMap<String, Integer>();
        units.put(”十”, 10);
        units.put(”百”, 100);
        units.put(”千”, 1000);
       
        int result = 0;
       
        //补全“十三”这种类型前的“一”
        if(chnNum.startsWith(”十”)){
            chnNum = “一” + chnNum;
        }
       
        int length = chnNum.length();
        for(int i=0; i<length; i++){
            String num = chnNum.substring(i, i+1);
            if(! num.equals(”零”)){
                if(i+2 > length){
                    result += numbers.get(num);
                }else{
                    String unit = chnNum.substring(i+1, i+2);
                    result += numbers.get(num) * units.get(unit);
                }
                i++;
            }
        }
       
        return result;
    }

VN:F [1.7.5_995]
Rating: 1.5/10 (2 votes cast)
VN:F [1.7.5_995]
Rating: 0 (from 0 votes)


Switch to our mobile site