Eclipse热键大全~~转滴!

个人常用快捷键

【Content Assist 】:默认为【ctrl+space】与其他快捷建冲突失效,修改为【Alt+/】(原来【Alt+/】为【word completion】的默认快捷键,有了【Content Assist 】这个可以不用了。)

(1)Ctrl+M切换窗口的大小
(2)Ctrl+Q跳到最后一次的编辑处
(3)F2当鼠标放在一个标记处出现Tooltip时候按F2则把鼠标移开时Tooltip还会显示即Show Tooltip Description。
            F3跳到声明或定义的地方。
            F5单步调试进入函数内部。
            F6单步调试不进入函数内部,如果装了金山词霸2006则要把“取词开关”的快捷键改成其他的。
            F7由函数内部返回到调用处。
            F8一直执行到下一个断点。
(4)Ctrl+Pg~对于XML文件是切换代码和图示窗口
(5)Ctrl+Alt+I看Java文件中变量的相关信息
(6)Ctrl+PgUp对于代码窗口是打开“Show List”下拉框,在此下拉框里显示有最近曾打开的文件
(7)Ctrl+/ 在代码窗口中是这种//~注释。
            Ctrl+Shift+/ 在代码窗口中是这种/*~*/注释,在JSP文件窗口中是<!–~–>。
(8)Alt+Shift+O(或点击工具栏中的Toggle Mark Occurrences按钮) 当点击某个标记时可使本页面中其他地方的此标记黄色凸显,并且窗口的右边框会出现白色的方块,点击此方块会跳到此标记处。
(9)右击窗口的左边框即加断点的地方选Show Line Numbers可以加行号。
(10)Ctrl+I格式化激活的元素Format Active Elements。
              Ctrl+Shift+F格式化文件Format Document。
(11)Ctrl+S保存当前文件。
              Ctrl+Shift+S保存所有未保存的文件。
(12)Ctrl+Shift+M(先把光标放在需导入包的类名上) 作用是加Import语句。
              Ctrl+Shift+O作用是缺少的Import语句被加入,多余的Import语句被删除。
(13)Ctrl+Space提示键入内容即Content Assist,此时要将输入法中Chinese(Simplified)IME-Ime/Nonlme Toggle的快捷键(用于切换英文和其他文字)改成其他的。
              Ctrl+Shift+Space提示信息即Context Information。
(14)双击窗口的左边框可以加断点。
(15)Ctrl+D删除当前行。

Alt+↓ 当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)
Alt+↑ 当前行和上面一行交互位置(同上)
Alt+← 前一个编辑的页面
Alt+→ 下一个编辑的页面(当然是针对上面那条来说了)

Alt+Enter 显示当前选择资源(工程,or 文件 or文件)的属性

Shift+Enter 在当前行的下一行插入空行(这时鼠标可以在当前行的任一位置,不一定是最后)
Shift+Ctrl+Enter 在当前行插入空行(原理同上条)

Ctrl+Q 定位到最后编辑的地方
Ctrl+L 定位在某行 (对于程序超过100的人就有福音了)
Ctrl+M 最大化当前的Edit或View (再按则反之)
Ctrl+/ 注释当前行,再按则取消注释
Ctrl+O 快速显示 OutLine
Ctrl+T 快速显示当前类的继承结构
Ctrl+W 关闭当前Editer
Ctrl+K 参照选中的Word快速定位到下一个
Ctrl+E 快速显示当前Editer的下拉列表(如果当前页面没有显示的用黑体表示)

Ctrl+/(小键盘) 折叠当前类中的所有代码

Ctrl+×(小键盘) 展开当前类中的所有代码

Ctrl+Space 代码助手完成一些代码的插入(但一般和输入法有冲突,可以修改输入法的热键,也可以暂用Alt+/来代替)

Ctrl+Shift+E 显示管理当前打开的所有的View的管理器(可以选择关闭,激活等操作)

Ctrl+J 正向增量查找(按下Ctrl+J后,你所输入的每个字母编辑器都提供快速匹配定位到某个单词,如果没有,则在stutes line中显示没有找到了,查一个单词时,特别实用,这个功能Idea两年前就有了)

Ctrl+Shift+J 反向增量查找(和上条相同,只不过是从后往前查)

Ctrl+Shift+F4 关闭所有打开的Editer

Ctrl+Shift+X 把当前选中的文本全部变味小写

Ctrl+Shift+Y 把当前选中的文本全部变为小写

Ctrl+Shift+F 格式化当前代码

Ctrl+Shift+P 定位到对于的匹配符(譬如{}) (从前面定位后面时,光标要在匹配符里面,后面到前面,则反之)

下面的快捷键是重构里面常用的,本人就自己喜欢且常用的整理一下(注:一般重构的快捷键都是Alt+Shift开头的了)

Alt+Shift+R 重命名 (是我自己最爱用的一个了,尤其是变量和类的Rename,比手工方法能节省很多劳动力)

Alt+Shift+M 抽取方法 (这是重构里面最常用的方法之一了,尤其是对一大堆泥团代码有用)

Alt+Shift+C 修改函数结构(比较实用,有N个函数调用了这个方法,修改一次搞定)

Alt+Shift+L 抽取本地变量( 可以直接把一些魔法数字和字符串抽取成一个变量,尤其是多处调用的时候)

Alt+Shift+F 把Class中的local变量变为field变量 (比较实用的功能)

Alt+Shift+I 合并变量(可能这样说有点不妥Inline)
Alt+Shift+V 移动函数和变量(不怎么常用)
Alt+Shift+Z 重构的后悔药(Undo)


Eclipse快捷键大全
Ctrl+1 快速修复(最经典的快捷键,就不用多说了)
Ctrl+D: 删除当前行
Ctrl+Alt+↓ 复制当前行到下一行(复制增加)
Ctrl+Alt+↑ 复制当前行到上一行(复制增加)

Spring中基于aop命名空间的AOP


本文地址:http://www.blogjava.net/cmzy/archive/2008/08/23/223870.html
下篇地址:Spring中基于aop命名空间的AOP 二(声明一个切面、切入点和通知)


    在某些时候,我们工程中使用的JDK 不一定就是1.5 以上,也就是说可能不支持Annotation 注解,这时自然也就不能使用@AspectJ 注解驱动的AOP 了,那么如果我们仍然想使用AspectJ 灵活的切入点表达式,那么该如何呢?Spring 为我们提供了基于xml schematic 的aop 命名空间,它的使用方式和@AspectJ 注解类似,不同的是配置信息从注解中转移到了Spring 配置文件中。在这里,我们将详细介绍如何使用Spring 提供的<aop:config/> 标签来配置Spring AOP 。



1 、一点准备工作和一个例子


    使用<aop:config/> 标签,需要给Spring 配置文件中引入基于xml schema 的Spring AOP 命名空间。完成后的Spring 配置文件如下(在该节,所有例程的配置文件中添加了Spring AOP 命名空间,除非特殊情况外,为了节约空间,这部分将在给出的代码中省略),粗体内容即为我们需要添加的内容:






  1. <?xml version=“1.0” encoding=“UTF-8”?>  

  2. <beans xmlns=“http://www.springframework.org/schema/beans”  

  3.         xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”  

  4.         xmlns:aop=“http://www.springframework.org/schema/aop”  

  5.         xsi:schemaLocation=”http://www.springframework.org/schema/beans   

  6.               http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    

  7.               http://www.springframework.org/schema/aop    

  8.               http://www.springframework.org/schema/aop/spring-aop-2.5.xsd >  

  9. ………… Spring配置信息   

  10. </beans>  


    关于aop命名空间的标签,我们前面使用过的有<aop:aspectj-autoproxy/>,在这一节,我们将以<aop:config/>标签作为重点。事实上,我们在这一节介绍的所有标签都是该标签的子标签。



   下面有一个例程来直观的展示如何使用<aop:config/>标签来配置Spring AOP(完整代码见例程4.15)。在例子中,我们使用<aop:config/>配置一个切面并拦截目标对象Peoples的SayHello()方法,在它执行前输出提示信息。
首先创建工程AOP_Test4.15,添加Spring IoC和Spring AOP库后,创建aop.test包,新建目标类People,代码如下:






  1. package aop.test;   

  2.   

  3. /**  

  4.  * 该类将作为目标对象对应的类。  

  5.  * @author zhangyong  

  6.  * */  

  7. public class People{   

  8.   

  9.         public String SayHello(String str){   

  10.                 System.out.println(this.getClass().getName()+ “说:”+str);   

  11.                 return str;   

  12.         }   

  13. }   


    修改Spring xml配置文件,将该类注册为一个受管Bean:






  1. <bean id=“TestBean” class=“aop.test.People” />  


    创建含有main()方法的测试类TestMain,从Spring IoC容器中获取Peoples对象,并调用其SayHello()方法,代码如下:






  1. package aop.test;   

  2.   

  3. // import省略   

  4. public class TestMain {   

  5.         public static void main(String[] args) {   

  6.                 // 实例化Spring IoC容器   

  7.                 ApplicationContext ac = new ClassPathXmlApplicationContext(   

  8.                                 “applicationContext.xml”);   

  9.                 // 获取受管Bean的实例   

  10.                 People p = (People) ac.getBean(“TestBean”);   

  11.                 p.SayHello(“传入的参数值”);   

  12.         }   

  13. }   


   创建MyAspect类,添加一个beforeAdvice()方法作为前置通知方法,代码如下:






  1. package aop.test;   

  2.   

  3. import org.aspectj.lang.JoinPoint;   

  4.   

  5. public class MyAspect {   

  6.            

  7.         public void beforeAdvice(JoinPoint point) {   

  8.             System.out.println(“前置通知被触发:” +    

  9.                                 point.getTarget().getClass().getName()+    

  10.                                 “将要” + point.getSignature().getName());   

  11.         }   

  12. }   


    修改xml配置文件,为其添加aop命名空间,并把MyAspect注册为一个受管Bean,作为我们下面定义切面的backing bean。代码如下:






  1. <?xml version=“1.0” encoding=“UTF-8”?>  

  2. <beans xmlns=“http://www.springframework.org/schema/beans”  

  3.         xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”  

  4.         xmlns:aop=“http://www.springframework.org/schema/aop”  

  5.         xsi:schemaLocation=”http://www.springframework.org/schema/beans   

  6. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    

  7.                http://www.springframework.org/schema/aop    

  8. http://www.springframework.org/schema/aop/spring-aop-2.5.xsd”>  

  9.   

  10.         <bean id=“MyAspect” class=“aop.test.MyAspect” />  

  11.         <bean id=“TestBean” class=“aop.test.People” />  

  12.            

  13.         <aop:config proxy-target-class=“true”>  

  14.                 <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  15.                         <aop:pointcut id=“testPointcut”  

  16.                                 expression=“execution(* aop..*(..))” />  

  17.                         <aop:before pointcut-ref=“testPointcut”  

  18.                                 method=“beforeAdvice” />  

  19.                 </aop:aspect>  

  20.         </aop:config>  

  21. </beans>  


    运行主类,输出如下:


例程4.15输出结果


例程4.15输出结果


 


2、声明一个切面
      在基于AOP命名空间的Spring AOP中,要声明一个切面,需要使用<aop:config/>的子标签<aop:aspect>。<aop:aspect>标签有一个ref属性必须被赋值,它用于指定和该切面关联的受管Bean(backing bean,以后我们都将使用Backing Bean来称呼这样的Bean)。正如下例所示,该Bean对应的java类是一个普通的java类,在该类中定义了切面的通知方法。此外,<aop:aspect>标签还有两个可选的order属性和id属性,order属性用于指定该切面的加载顺序,id属性用于标识该切面。范例如下:





  1. <?xml version=“1.0” encoding=“UTF-8”?>  

  2. <beans ……>  

  3.         <bean id=“MyAspect” class=“aop.test.MyAspect” />  

  4.         <aop:config proxy-target-class=“true”>  

  5.                 <aop:aspect ref=“MyAspect” order=“1” id=“TestAspectName”>  

  6.                         ……切面其他配置   

  7.                 </aop:aspect>  

  8.         </aop:config>  

  9. ……其他配置   

  10. </beans>    

 



3、声明一个切入点
      要声明一个切入点,可以使用<aop:aspect>的子标签<aop:pointcut>,在Spring2.5中它有两个属性id和expression,分别用于标示该切入点和设定该切入点表达式。例如:






  1. <?xml version=“1.0” encoding=“UTF-8”?>  

  2. <beans ……>  

  3.     <bean id=“MyAspect” class=“aop.test.MyAspect”/>  

  4.     <aop:config proxy-target-class=“true”>  

  5.         <aop:aspect ref=“MyAspect” order=“1” id=”TestAspectName”>  

  6.               <aop:pointcut id=“test”  

  7.                 expression=“execution(* aop.test.TestBean.*(..))”/>  

  8.               <aop:before pointcut=“aop.test.MyAspect.Pointcut1()”    

  9.                                method=“beforeAdvice” />  

  10.         </aop:aspect>  

  11.     </aop:config>  

  12. ……其他配置   

  13. </beans>  

 




<aop:pointcut>标签的expression属性使用前面介绍的切入点表达式语言,也就是说支持AspectJ切入点表达式。但是由于xml对”&&”、”||”、”!”等逻辑运算符不友好,@AspectJ切入点表达式语言中使用的这些逻辑运算符在xml配置中需要分别用”and”、”or”和”not”来代替。
有时候,我们也需要在xml中使用@Pointcut注解声明的切入点,那么该如何呢?大家可能记得,我们可以在切入点表达式中可以引用另一个切入点。对了,就在这里,我们使用该特性可以完成这个任务,如下:






  1. <aop:pointcut id=“test”   expression=“aop.test.MyAspect.Pointcut1()” />  

 



注意:这里我们必须使用全路径来标示引用的切入点。


4、 声明一个通知
      和@AspectJ一样,基于AOP命名空间的配置也可以定义五种通知类型,并且使用方式和特性类似。与@AspectJ不同的是,配置信息从Annotation中转移到了xml配置文件。
    1)、前置通知
    声明一个前置通知可以使用<aop:aspect>的子标签<aop:before/>。该标签的属性说明如下表:

<aop:before/>标签属性说明





















属性


说明


pointcut


指定该通知的内置切入点


pointcut-ref


通过 id 引用已定义的切入点


method


指定通知对应的方法,该方法必须已在切面的 backing bean 中被声明


arg-names


通过方法的参数名字来匹配切入点参数


      对于一个通知来说,切入点和对应的通知方法是必须的。也就是说,在这些属性中,method属性是必须的,我们必须要给通知指定一个对应的方法;pointcut属性和pointcut-ref必须有一个被指定,以此确定该通知的切入点。范例如下:




  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.     <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))”/>  

  4.     <aop:before pointcut-ref=“testPointcut” method=“beforeAdvice”/>  

  5. </aop:aspect>  

 



     2)、 后置通知
     声明一个后置通知使用<aop:after/>标签,它的属性等和<aop:before/>标签类似,下面是范例:




  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.     <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))” />  

  4.     <aop:after  pointcut-ref=“testPointcut” method=“AfterAdvice”/>  

  5. </aop:aspect>  

 



     3)、 返回后通知
      <aop:after-returning/>标签可以声明一个返回后通知,该标签的属性和<aop:before/>相比它多了一个returning属性。该属性的意义类似于@AfterReturning注解的returning属性,用于将链接点的返回值传给通知方法。用法如下:




  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.     <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))” />  

  4.     <aop:after-returning pointcut-ref=“testPointcut”  

  5.         method=“AfterReturnAdvice” returning=“reVlue” />  

  6. </aop:aspect>  

 



       4)、 异常通知
        声明一个异常通知使用<aop:after-throwing />标签,它有一个类似于throwing属性又来指定该通知匹配的异常类型。用法如下:




  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.      <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))” />  

  4.      <aop:after-throwing pointcut-ref=“testPointcut”  

  5.         method=“afterThrowingAdvice” throwing=“throwable” />  

  6. </aop:aspect>  

 



      5)、 环绕通知
      环绕通知是所有通知中功能最强大的通知,用<aop:around/>标签来声明。用法如下:




  1. <aop:aspect ref=“MyAspect” order=“0” id=“Test”>  

  2.     <aop:pointcut id=“testPointcut”  

  3.         expression=“execution(* aop.test.TestBean.*(..))” />  

  4.         <aop:around pointcut-ref=“testPointcut” method=“aroundAdvice”/>  

  5. </aop:aspect>  




(完)


JavaRebel 1.2发布,充分支持Spring

JavaRebel是一个JVM插件(-javaagent),能够即时重载java class更改,因此不需要重新部署一个应用或者重启容器,节约开发者时间。它是一个Java EE和Java 独立应用的常用解决方案。最新的稳定版本JavaRebel代码加载包含一个Spring的插件,能重新加载Spring配置快速的促进生产力的发展,甚至更多。查看Screencast ,下载JavaRebel插件

这个稳定的JavaRebel主要致力于两个主题:稳定和可扩展性。下面是它与1.1版本的区别:

core:增强了core的JavaRebel现在可以处理任何复杂的代码或容器。
SDK:您可以对应用程序和库的任何部分进行增值,无论您身在何处或怎么设置。SDk 为开放源代码。
JavaRebel插件:现在支持自定义的classloaders更容易,容器和框架只需登记一个小插件即可。
Eauinox OSGi容器,现在支持IBM WebSphere 和 Atlassian 混合插件。

查看完整的更新列表 或现在就开始下载JavaRebel

我们已经准备了一个Screencast来说明Spring插件的功能。查看该插件的安装手册 ,了解更多的详情或现在就下载

另类加水印——根据明暗度分别加不同的水印


  1. package image;   

  2.   

  3. import java.awt.AlphaComposite;   

  4. import java.awt.Color;   

  5. import java.awt.Font;   

  6. import java.awt.Graphics;   

  7. import java.awt.Graphics2D;   

  8. import java.awt.Image;   

  9. import java.awt.image.BufferedImage;   

  10. import java.awt.image.ColorModel;   

  11. import java.awt.image.PixelGrabber;   

  12. import java.io.File;   

  13. import java.io.FileOutputStream;   

  14.   

  15. import javax.imageio.ImageIO;   

  16.   

  17. import com.sun.image.codec.jpeg.JPEGCodec;   

  18. import com.sun.image.codec.jpeg.JPEGImageEncoder;   

  19.   

  20. public class WaterMark {   

  21.   

  22.     /**  

  23.      * 获取指定矩形中的像素的矩阵  

  24.      *   

  25.      * @param imageSrc  

  26.      * @param startX  

  27.      * @param startY  

  28.      * @param w  

  29.      * @param h  

  30.      * @return  

  31.      */  

  32.     private int[] getPixArray(Image imageSrc, int startX, int startY,   

  33.             int w, int h) {   

  34.         int[] pix = new int[(w – startX) * (h – startY)];   

  35.            

  36.         /*下面是别人程序中的一段,我实在不明白为何要加这一段,因为我去掉也没有问题,加上还会报错*/  

  37.         PixelGrabber pg = null;   

  38.         try {   

  39.             pg = new PixelGrabber(imageSrc, startX, startY, w-startX, h-startY, pix, 0, w);   

  40.             if (pg.grabPixels() != true) {   

  41.                 try {   

  42.                     throw new java.awt.AWTException(“pg error” + pg.status());   

  43.                 } catch (Exception eq) {   

  44.                     eq.printStackTrace();   

  45.                 }   

  46.             }   

  47.         } catch (Exception ex) {   

  48.             ex.printStackTrace();   

  49.         }   

  50.         return pix;   

  51.     }   

  52.   

  53.     /**  

  54.      * 将1张图片和另1张图片的指定区域重合。可用于制作水印。图片的左上角坐标为0,0  

  55.      *   

  56.      * @param lightnessWaterImg  

  57.      *            颜色比较亮的水印图片,适合底色比较暗的情况  

  58.      * @param darknessWaterImg  

  59.      *            颜色比较暗的水印图片,适合底色比较亮的情况,如果不想区分,则输入null,平均灰度边界同时失效。  

  60.      * @param targetImg  

  61.      *            源图片  

  62.      * @param startX  

  63.      * @param startY  

  64.      * @param x  

  65.      * @param y  

  66.      * @param alpha  

  67.      *            透明度,0f为全透明,1f为完全不透明,0.5f为半透明  

  68.      * @param averageGray  

  69.      *            平均灰度边界(0-255),大于此值,则打暗的水印图片,小于此值则打亮的水印图片。  

  70.      *            默认值128。超过范围,按默认值进行。  

  71.      */  

  72.     private final void pressImage(String lightnessWaterImg,   

  73.             String darknessWaterImg, String targetImg, int startX, int startY,   

  74.             int x, int y, float alpha, float averageGray) {   

  75.         try {   

  76.             // 先判断亮水印和源文件的值是否为null,否则抛出异常   

  77.             if (lightnessWaterImg == null || lightnessWaterImg == “”  

  78.                     || targetImg == null || targetImg == “”) {   

  79.                 throw new Exception(“亮水印或者源图片的地址不能为空”);   

  80.             }    

  81.             // 再判断平均灰度边界是否越界   

  82.             if (averageGray>255||averageGray<0) {   

  83.                 averageGray = 128;   

  84.             }   

  85.                

  86.   

  87.             // 装载源图片   

  88.             File _file = new File(targetImg);   

  89.             // 图片装入内存   

  90.             BufferedImage src = ImageIO.read(_file);   

  91.             // 获取图片的尺寸   

  92.             int width = src.getWidth(null);   

  93.             int height = src.getHeight(null);   

  94.             // 根据源图片尺寸,设置预装载的一个图片,默认是RGB格式的   

  95.             BufferedImage image = new BufferedImage(width, height,   

  96.                     BufferedImage.TYPE_INT_RGB);   

  97.             Graphics2D graphics = image.createGraphics();   

  98.             // 绘制内存中的源图片至指定的矩形内   

  99.             graphics.drawImage(src, 00, width, height, null);   

  100.             // 在已经绘制的图片中加入透明度通道   

  101.             graphics.setComposite(AlphaComposite.getInstance(   

  102.                     AlphaComposite.SRC_ATOP, alpha));   

  103.                

  104.   

  105.             // 获取源图片中和设定的同样大小的区域内的像素集合   

  106.             int[] pixels = getPixArray(src, startX, startY, x, y);   

  107.   

  108.             //查询此集合的平均灰度   

  109.             float average = getAverageGrap(x-startX,y-startY,pixels);   

  110.   

  111.             // 如果平均灰度大于130,则说明此区域比较亮,否则则比较暗   

  112.             System.out.println(average);   

  113.   

  114.                

  115.             //装载水印图片所需参数   

  116.             File water;   

  117.             BufferedImage bufferwater;   

  118.                

  119.             // 根据设定的平均灰度边界来装载不同的水印   

  120.             if (darknessWaterImg == null||average>=averageGray) {   

  121.                 // 装载亮水印文件   

  122.                 water = new File(darknessWaterImg);   

  123.             }else{   

  124.                 // 装载暗水印文件   

  125.                 water = new File(lightnessWaterImg);   

  126.             }   

  127.             // 装入内存   

  128.             bufferwater = ImageIO.read(water);   

  129.                            

  130.             graphics.drawImage(bufferwater, startX, startY, x, y,   

  131.                     null);   

  132.             // 水印文件结束   

  133.             graphics.dispose();   

  134.             FileOutputStream out = new FileOutputStream(targetImg);   

  135.             JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);   

  136.             // 绘制新的文件   

  137.             encoder.encode(image);   

  138.             out.close();   

  139.                

  140.         } catch (Exception e) {   

  141.             e.printStackTrace();   

  142.         }   

  143.     }   

  144.            

  145.     /**  

  146.      * 查询某个区域的平均灰度  

  147.      * @param width  

  148.      * @param height  

  149.      * @param pixels  

  150.      * @return  

  151.      */  

  152.     private float getAverageGrap(int width,int height,int[] pixels){   

  153.         /* 下面是开始算这个区域的亮度了,灰度等同于亮度 */  

  154.         ColorModel colorModel = ColorModel.getRGBdefault();   

  155.         int i = 0;   

  156.         int j = 0;   

  157.         int k = 0;   

  158.         int r = 0;   

  159.         int g = 0;   

  160.         int b = 0;   

  161.         int gray = 0;   

  162.         float average = 0;// 平均灰度   

  163.         for (i = 0; i < height; i++) {   

  164.             for (j = 0; j < width; j++) {   

  165.                 // 定位像素点   

  166.                 k = i * width + j;   

  167.                 r = colorModel.getRed(pixels[k]);   

  168.                 g = colorModel.getGreen(pixels[k]);   

  169.                 b = colorModel.getBlue(pixels[k]);   

  170.   

  171.                 // 计算灰度值   

  172.                 gray = (r * 38 + g * 75 + b * 15) >> 7;   

  173.   

  174.                 average = average + gray;   

  175.             }   

  176.         }   

  177.         // 计算平均灰度   

  178.         average = average / ((i – 1) * (j – 1));   

  179.         return average;   

  180.     }   

  181.     public static void main(String[] args) {   

  182.         WaterMark waterMark = new WaterMark();   

  183.   

  184.         waterMark.pressImage(“F:\\Mine\\My Pictures\\素材\\w2.png”“F:\\Mine\\My Pictures\\素材\\w1.png”,   

  185.                 “F:\\Mine\\My Pictures\\素材\\2.jpg”5205009008000.5f, 50);   

  186.         System.out.print(“添加成功”);   

  187.     }   

  188.   

  189. }  

一个体现Java接口及工厂模式优点的例子

     随着模式概念的普及,了解模式和使用模式的程序员越来越多,很多人在学习模式的时候,都会有这样一种疑惑:“有必要搞得这么复杂吗?”。的确,因为教程的例子过于简单化(这样方便读者学习),或者是作者选例子的时候并没有很好体现所讲模式的优点,很多情况下如果仅就其例子的问题来说,用模式是太复杂了。因此才导致这样的误解:“模式就是把简单的问题复杂化吗?”。当然不是,随着你开发实践的不断丰富,你终会发现模式强大威力,而且模式也并非贵族化的编程方式,它就是一些经过提炼了的解决问题的方法技巧。

 

      通过学习模式,程序员开始告别过去准直线式的代码方式,模式开扩了我们的视野,强化了我们面向对象编程的思维方式。然而现在又出现了另一个普遍的问题,盲目应用模式。模式是问题的解决方案,先有问题才有模式,模式是依附于所要解决的问题的而生的。必须了解模式在很多情况下是以提高代码的复杂度为代价来增强灵活性、可复用性。如果在自已的代码中使用某一模式仅只提高了代码的复杂度,而其它方面收效甚微,或者某部份代码根本就不存在灵活性及高复用性的需求,那么我们就没有必要为使用模式而放弃更直观简单的代码写法。

 

      一流的高手90%精力关注问题的解决方案,因为找到了好的解决方案,再写起代码会很轻松代码也简洁流畅,看这样的代码是一种享受和提高;二流的熟手90%精力关注代码实现,因为问题的解决方案并非最佳,实现的代码也会比较复杂;三流菜鸟记流水帐,90%精力在敲键盘,常常做了大半才发现行不通,回过头来再用90%的时间敲键盘,根本不会用到任何模式,写出来的代码的只有他自已才能看懂。做出来的软件也是支离破碎,做一丁点改动都要大费周折,而且你还不知道改动后会产生什么问题,大有住危房里的感觉。

 

      在这里还是举一个滥用模式的例子吧。我曾参与过一个大集团公司OA系统的第二期开发,开发沿用原有代码架构并增加新的功能模块。文档很少我读原代码时就被它程序里的代码转来转去搞得头大如斗,最后读懂了:原代码架构总体采用工厂模式,而且是最复杂的抽象工厂模式。它把所有模块类都通过工厂生成还工厂套工厂,并且每一个模块类都有一个接口,每个接口也只有一个模块现实类,因为涉及权限控制还用了代理(proxy)模式。 读懂代码后我开始嵌入代码,发现每新增一个类,都要到六个Java文件中去增加相应代码,而在类中每增加一个方法,也要到它的接口等四个Java文件中去增加相应代码。天呀!!!记得当时我的小姆指常会不听使唤,就是因为频繁的使用Ctrl+C 、Ctrl+V,小姆指按着Ctrl键给累的。整个项目组苦不堪言,真烦透了。项目结束后我回顾发现:代理模式用得还对(现在针对权限这类横向控制有AOP编程这种新的解决办法了)但工厂模式在这里根本就是画蛇添足,不仅没有解决什么问题,反而增加代码复杂度和耦合性,降低了开发效率连维护难度都提高了。而且那种每个类简单的加一个接口的方式,更是没有道理,这让我很想说周星驰说过的一句话:“球~~~不是这么踢~~~~的,接口~~~不是这么用~~~的”。言归正传,我们先来看这样一个常见问题:某系统需要支持多种类型的数据库。用过Oracle、MSSQL等数据库的人都知道,它们的SQL编写方式都各有些不同。比如说Oracle的唯一标识自动+1字段用的是序列,MSSQL改一下字段属性就成了,还有各种各自特有的SQL用法。为了支持多数据库,难道我们要开发多套系统?当然NO。请看下面的解决方案。

 

      即然数据库存在多种,我们可以将系统中所有对数据库的操作抽象出来,写成一个个方法组合到一个类中,有几种数据库我们就写几个这样的类。具体设计类图如下:

20060910.gif

 

 

简要说明:


  • OracleDataOperate、SqlserverDataOperate、MysqlDataOperate,分别代表Oracle、Sqlserver、Mysql这三种数据库的操作类。继承自AbstractDataOperate
  • AbstractDataOperate是一个抽象类,包含了那些不同种类数据库都是一样代码的操作方法。继承自DataOperate
  • DataOperate是上面说的数据操作类的统一接口,只有两个方法:取得一条记录、插入一条记录。
  • DataOperateFactory是一个工厂方法,统一用它的方法来得到数据库操作类的实例。
  • SampleClass是我们系统的某个功能模块的类。
  • People是一个实体类,代表一条记录。三个字段 oid唯一标识符、name姓名、date生日。

 

详细说明:

1、所有系统功能模块类只认DataOperat这个接口还不必管具体的实现类是OracleDataOperate还SqlserverDataOperate。DataOperate源代码如下:

publicinterface DataOperate {

    //根据记录的唯一标识取出一条记录

    People getPeople(String oid);

    //插入一条记录

    boolean insertPeople(People people);

}

 

2、AbstractDataOperate、OracleDataOperate、SqlserverDataOperate、MysqlDataOperate都是继承DataOperate接口的,没什么好说的,省略。

 

3、DataOperateFactory。我们看看工厂方法怎么写的。

publicclass DataOperateFactory {

    publicstaticfinalint ORACLE = 0; //定义三个表示数据库类型的常量

    publicstaticfinalint MYSQL = 1;

    publicstaticfinalint SQLSERVER = 2;

 

    privatestatic DataOperate db;

    privatestaticint dataType = MYSQL;

    /**

     * 根据数据库类型(dataType)取得一个数据库操作类的实例,

     * 这里对DataOperate使用了单例模式,因为OracelDataOperate等都是无状态的工具类,

     * 所以整个系统只保留一个实例就行了。

     *

     * @return 返回的是接口,客户端不必关心具体是用那个实现类

     */

    publicstatic DataOperate getInstance() {

        if (db == null) {

            if (dataType == ORACLE) //根据dateType返回相应的实现类

                returnnew OracelDataOperate();

            if (dataType == MYSQL)

                returnnew MysqlDataOperate();

            if (dataType == SQLSERVER)

                returnnew SqlserverDataOperate();

        }

        return db;

    }

}

 

4、接下来就看看使用端是如何调用工厂方法和使用数据操作类的。

/**

 * 系统某个功能类

 */

publicclass SampleClass {

private DataOperate db; //声明一个数据库操作类,注意这里用的是接口噢

    /**某方法*/

    publicvoid sampleMethod() {

        db = DataOperateFactory.getInstance();//得到单一实例

        People p = db.getPeople(“123”); //取得一条记录

        db.insertPeople(p);//再插回去

    }

}

 

  我们发现SampleClass中根本没有出现OracelDataOperate、MysqlDataOperate等的影子,这就是接口的威力。客户端不必针对OracelDataOperate等写不同的代码,它只关心DataOperate即可,具体要取那个类的逻辑就由DataOperateFactory负责了。

 

总结:



  • 从例子中我们可以看到什么是面向接口的编程方式。SampleClass使用数据操作类可以不必关心具体是那个类,只要是符合接口的都行


  • 要实例?只须调用DataOperateFactory.getInstance()即可,其它的交于DataOperateFactory这个工厂来做吧,使用端什么都不用关心。


  • 我们要支持新的数据库类型,只须要象OracelDataOperate那样,再写一个继承AbstractDataOperate的类即可,比如SysbaseDataOperate。然后到DataOperateFactory中加入相应代码即可。


  • 如果我们想要可配置性更高,可以用privatestaticint dataType = MYSQL;中的值设置到一个文本文件中。

  对于开发支持多种数据库的系统,强烈建议使用hibernate,我现在做的系统就是用hibernate的,开发时用Mysql,到要给客户时将数据库换了DB2,程序不用做任何改动,真正的无逢移植。不过这样,本文所提到的方法就没什么用了.

使用JRockit Mission Control进行性能分析和调优


Mission ControlBEA JRockit JVM自带的一组以极低的开销来监控、管理和分析生产环境中的应用程序的工具。它包括三个独立的应用程序:内存泄漏监测器(Memory Leak Detector)、JVM运行时分析器(Runtime Analyzer)和管理控制台(Management Console)。BEAJRockit R26版本就开始捆绑这个工具套件,目前最新的版本是3.0。最近我们使用其中的Runtime Analyzer对国内某著名行业解决方案进行性分析和调优。


 


JRockit Runtime AnalyzerJRA)是一个JVM分析器,是一个随需应变的“动态记录器”。它记录了Java应用程序和JVM在一段预定的时间内的详细记录。然后通过JRA应用程序对记录下来的文件进行离线分析。所记录的数据包括对方法的调用跟踪、错误的同步、锁定的分析,还有垃圾收集统计信息,优化决策以及对象统计信息和其他重要的应用程序/JVM行为。它的目的是让JRockit开发人员能够找到良好的方法来基于现实应用程序优化JVM,对于帮助客户在生产和开发环境中解决问题十分有用。


 


2.性能数据分析和调优


 


在本次项目中,操作|A和操作B的百人并发脚本执行完成的时间接近两分钟,因此我们使用JRA进行了2分钟(120)的记录。在GC常规信息中,我们发现在短短两分钟时间内,垃圾收集的总数高达365次,而由此造成的暂停时间有42.5秒之多。也就是说35%的执行时间是在做垃圾收集。


 


因为最大堆尺寸已经设置成1024M,对于32位操作系统上的Java应用已经是足够大了(在IA32构架下,由于操作系统给每个进程的最大内存寻址空间为1.8G,因此最大堆尺寸不能超过1.8G),因此堆的大小并不是造成频繁垃圾收集的原因。那么在高并发度的场景下,可能的影响因素很可能是Nursery大小。


 


Nursery 也称为新代,是指运行分代式垃圾收集器时,在堆中分配 新对象 的可用块区域。 Nursery 变满时,会在新垃圾收集中单独对其进行垃圾收集。Nursery 大小决定了新收集的频率和持续时间。较大 Nursery 会降低收集的频率,但是会稍微增加每个新收集的持续时间。 Nursery 之所以具有价值,是因为 Java 应用程序中的大多数对象都是在新代中夭亡的。与收集整个堆相比,应首选从新空间中收集垃圾,因为该收集过程的开销更低,而且在触发收集时,新空间中的大多数对象均已死亡。在新收集过程中,JVM 首先确定 Nursery 中的哪些对象是活动的,此后将它们提升到旧空间,并释放 Nursery,供分配新的小对象使用


 


Nursery的默认缺省值是10M/CPU,对于我们Clovertown服务器来说,只有20M。由于出现频繁收集的情况,那么我们推断是由于Nursery的默认值太低的原因。一方面在高并发用户的场景下,肯定是有大量的新对象产生,那么Nursery的空闲空间很容易就被耗尽。因此Nursery发生垃圾收集频率就会比较高。另一方面更短的垃圾收集间隔会使得新对象在Nursery的存活率提高因为很多新对象可能还没来得及使用完毕就已经发生垃圾收集。这样更多的对象会被提升到旧代,使得旧代的对象也会急剧增加,从而使得旧代发生垃圾收集的频率也增加。


 


因为JRockit JVM可以使用-Xns:<size>来设置Nursery的尺寸,我们要在保证垃圾回收停顿时间(garbage collection-pause)尽可能短的同时,尽量加大Nursery的尺寸,这在创建了大量的临时对象时尤其重要。推荐值是最大堆尺寸的10%,因此我们在JRockit的运行时参数上添加了 –Xns100m。再次运行脚本后,JRA收集的信息显示GC暂停时间骤降到15.3s,次数也有所减少,降到296


 




















Nursery大小


20M(默认值)


100M


GC暂停时间


42.5s


15.3s


垃圾收集的总数


365


296


平均暂停时间


116ms


52ms


 


此外,我们从方法信息中可以看到调用次数最多耗时间最长的两个方法分别是jrockit.vm.Locks.monitorEnterSecondStagecom.ABC.StateManager.makeState两个方法。展开前置任务后发现调用这两个方法最多的方法是com.ABC.SqlQueryAction.query。而jrockit.vm.Locks.monitorEnterSecondStage显然是JRockit实现锁机制的特定的API。因此我们怀疑是对数据库的操作时有资源互斥的现象发现。


 


考虑到高并发用户的场景下,对数据库操作的并发度也很高,因此对数据库连接的争用比较激烈。我们察看了一下当时WebLogic JDBC的配置,发现connection pool的大小只是缺省值20,相对来说偏小了,对性能会有一定的影响。因此我们增大connection pool的大小到100。重新运行测试脚本后发现性能有较大提升。


 


 



















 


JDBC connection size 20  w/ default nursery


JDBC connection size 100 w/ 100M nursery


Increase %


 


操作A


22.125


12.079


83%


操作B


35.195


21.773


62%


 


 


在性能调优完成后,我们又进行了功能测试(回归测试),以验证上述改动没有影响系统的功能性正确。


四、小结


其实利用Mission ControlJava应用进行调优并不难,对吧?希望本次性能分析调优的过程可以给大家一些启发,今后可以应用到日常工作中。

使用JRockit作为Eclipse的Java VM


早些天写了一篇关于调整Eclipse启动的blog,目的还是希望提升Eclipse(包括启动时)的总体性能。 今天,尝试了一下使用BEA JRockit来作为Eclipse的JVM,同时使用JRockit来编译所有的项目。


安装JRockit:


1. 从BEA下载最新的JRockit。 JRockit据说是Wintel平台下最快的Java编译器(以前还有IBM的JDK和Jike,IBM JDK现在是WebSphere的一部分,而最先支持增量编译的Jike已经贡献给Eclipse了,BEA也将会把JRockit贡献给Eclipse。 天下归一啊)。 BEA的JRockit主页在这里,从这里下载最新的JRockit 5.0(我下载的是R26.4.0),大约75MB。


2. 安装JRockit非常容易,不停的”Next”即可。 安装完以后,可以把JAVA_HOME设置为JRockit(可选项)。


配置Eclipse:


1. Eclipse启动参数。 其实就是像前一篇所说的那样,在Eclipse启动参数里面修改-vm的值,使用JRockit来启动Eclipse。比如我修改为:


C:\Java\eclipse\eclipse.exe -vm C:\java\jrockit-R26.4.0-jdk1.5.0_06\ bin\javaw.exe -vmargs -Xms256m -Xmx512m -XXsetgc:singleparpar -XXcompactratio:1


2. 在Eclipse里面,安装JRockit,即在Installed JRE中添加JRockit,并设置为默认。 这样,就可以用JRockit来编译项目了。


至于性能:


Eclipse(我的Eclipse是v3.2 Callisto,含所有的插件,以及Crystal Report, SWT Designer, PowerDesigner,Mylar, FindBugs等插件)启动的时候,比使用Sun JDK 1.5要快一些(但不是快很多很多,毕竟Sun JDK 1.5的性能已经提升了),大约能有10-15%的改进吧。 我的工程一共有95个plug-in项目和1个Web项目。


之后,我可能会尝试一下把JRockit用到Glassfish的服务器上,看看效果如何。


【参考文章】Running BEA Workshop/Eclipse with JRockit 5.0


Technorati : ,
Del.icio.us : ,

Google Guice Example

最近在研究Google 的 Guice,感觉用起来挺简单的,入门应该比Spring要容易的多,这也许是因为Guice刚刚出世,很功能还没有完善吧,但据说Google内部已经在用了,我想再过一段时间取Spring而代之也不是没有可能,至少也能跟Spring平分天下吧。

下面是一个简单的小实例

1.业务逻辑接口

package com.hawkunion.guice;

/**

*

* @author 杜庆明

*/

public interface Work {

     public void sayHello(String userName);

}

2.实现接口的业务逻辑

package com.hawkunion.guice;

/**

*

* @author 杜庆明

*/

public class WorkImpl implements Work{

   

     public void sayHello(String userName) {

         System.out.println(“Hello! 欢迎你:”+userName);

     }

   

}

3.要用到业务逻辑的类

package com.hawkunion.guice;

import com.google.inject.Inject;

/**

*

* @author 杜庆明

*/

public class RunWorkClass {

   

     private Work work = null;

   

     @Inject

     public void setWork(Work workimpl){

         this.work = workimpl;

     }

   

     public void runWork(){

         work.sayHello(“阿杜”);

     }   

}

4.Module

package com.hawkunion.guice;

import com.google.inject.Binder;

import com.google.inject.Module;

/**

*

* @author 杜庆明

*/

public class MyModule implements Module {

     public void configure(Binder binder) {

         binder.bind(Work.class).to(WorkImpl.class);

     }

}

5.测试

package com.hawkunion.guice;

import com.google.inject.Guice;

import com.google.inject.Injector;

import com.google.inject.Module;

/**

*

* @author 杜庆明

*/

public class TestWork {

   

     public static void main(String args[]){

         RunWorkClass runWorkClass = new RunWorkClass();

         Module module = new MyModule();

       

         Injector in = Guice.createInjector(module);//把module给Guice

         in.injectMembers(runWorkClass);//让Guice把需要注入的业务逻辑注入给对象

         runWorkClass.runWork();//   运行work

     }

}

Lucene Query Parser

Lucene Query Parser


翻译这篇文章的初衷是希望能更系统的理解Lucene的用法,同时试试自己的翻译水平:)


原文:http://jakarta.apache.org/lucene/docs/queryparsersyntax.html


概述


虽然Lucene提供的API允许你创建你自己的Query(查询语句),但它同时也通过Query Parser(查询分析器)提供了丰富的查询语言。


这个页面提供的是Lucene的Query Parser的语法介绍:一个可通过用JavaCC把一个字符串解释成为Lucene的查询语句的规则。


在选择使用被提供的Query Parser前,请考虑一下几点:


1、如果你是通过编写程序生成一个查询语句,然后通过Query Parser分析,那么你需要认真的考虑是否该直接利用Query的API构造你的查询。换句话说,Query Parser是为那些人工输入的文本所设计的,而不是为了程序生成的文本。


2、未分词的字段最好直接加到Query中,而不要通过Query Parser。如果一个字段的值是由程序生成的,那么需要为这个字段生成一个Query Clause(查询子句)。Query Parser所用的Analyzer是为转换人工输入的文本为分词的。而程序生成的值,比如日期、关键字等,一般都由程序直接生成(?)。


3、在一个查询表单里,通常是文本的字段应该使用Query Parser。所有其他的,比如日期范围、关键字等等,最好是通过Query API直接加入到Query中。一个有有限个值的字段,比如通过下拉表单定义的那些,不应该被加到查询字串中(后面会分析到),而应该被添加为一个TermQuery子句。


分词


一个查询语句是有分词和操作符组成的。这里有两种类型的:单个的分词和短语。


一个单一分词就是一个简单的单词,比如”test”或”hello”。


一个短语就是一组被双引号包括的单词,比如”hello dolly”。


多个分词可以用布尔操作符组合起来形成一个更复杂的查询语句(下面会详细介绍)。


注意:用于建立索引的分析器(Analyzer)将被用于解释查询语句中的分词和短语。因此,合理的选择一个分析器是很重要的,当然这不会影响你在查询语句中使用的分词。


字段


Lucene支持字段数据。当执行一个搜索时,你可以指定一个字段,或者使用默认的字段。字段的名字和默认的字段是取决于实现细节的。


你可以搜索任何字段,做法是输入字段名称,结尾跟上一个冒号 “:” , 然后输入你想查找的分词。


举个例子,让我们假设Lucene的索引包含两个字段,标题和正文,正文是默认字段。如果你想标题为 “The Right Way” 并且正文包含文本 “don’t go this way”的记录的话,你可以输入:


  title:”The Right Way” AND text:go 


或者


  title:”Do it right” AND right


由于正文是默认字段,所以字段指示就没有必要了。


注意:字段的搜索值只能是紧跟在冒号后的一个分词,所以搜索字串:


 title:Do it right


只会找到标题含有 “Do” 的记录。它会在默认字段(这里是正文字段)里查找 “it” 和 “right”。


分词修饰语


Lucene支持对查询分词做修饰以提供一个更广的查询选项。
 
通配符搜索


ucene支持一个或多个字符的通配符搜索。


执行一个字符的通配符搜索可以用 “?”,比如你要搜索 “text” or “test” ,你可以用:


 te?t


执行多个字符的通配符搜索可以用 “*”,比如,搜索 “test” , “tests” 或 “tester” ,你可以用


 test*


你也可以把通配符放在分词中将进行搜索,比如


 te*t


注意:不可以使用 * 或 ? 作为搜索字串的第一个支付。


模糊搜索


Lucene支持基于Levenshtein Distance(一种字符串相似程度算法)或Edit Distance(一种字符串相似程度算法)算法的模糊查询。要执行模糊查询需要用到 “~” 符号,紧随单个分词。比如,用模糊查询搜索一个拼写上和 “roam” 类似的内容:


 roam~


这个搜索可以搜索到像 foam 和 roams 这样的分词。


 “jakarta apache”~10


 近似搜索


Lucene支持根据一个指定的近似程度查找。与模糊搜索类似,在短语的末尾使用 “~” 。


范围搜索


范围搜索可以搜索到那些列的值在被范围搜索所指定的上限和下限之间的记录。范围搜索可以包括或不包括上限和下限。如果不是日期类型的字段,会根据字典的排序来决定上下限。


 mod_date:[20020101 TO 20030101]


这个会搜索 mod_date 字段的值在 20020101 和 20030101 之间的,包括上下限。注意,范围搜索不仅仅是为日期字段准备的,你也可以在非日期的字段上使用它:


 title:{Aida TO Carmen}


这个会搜索 title 字段的值在 Aida 和 Carmen (根据字典的顺序) 的记录,不包括 Aida 和 Carmen 本身。


包含的范围查询是用方括号指定的 “[” 、 “]” ,而不包含的范围查询是有波形括号指定的 “{” 、 “}”。


提高一个分词的相似度


Lucene提供基于被搜索的分词的匹配文档的相似度这一概念。为了提高一个分词的相似度,可以使用 “^”和一个相似因子(一个数字)跟在需要搜索的分词后面。这个匹配因子越高,这个分词所获得相似度就越高。


提高匹配允许你通过提高分词的相似程度来控制一个文档的相似程度。比如,如果你在搜索


 jakarta apache


并且,你希望 “jakarta” 有更高的相似程度,就用让 “^” 和一个匹配因子紧随它。你将输入:


 jakarta^4 apache


这样会使包含分词 jakarta 的文档有更高的相似度(Lucene默认是按照相似度对搜索结果排序的,所以带来的直接影响就是该搜索结果文档排位靠前)。你也可以对短语分词提高匹配度,比如:


 “jakarta apache”^4 “jakarta lucene”


默认的情况下,匹配因子是1。虽然匹配因子必须是正数,当它可以小于1 (比如 0.2)


布尔操作符


布尔操作符允许分词通过逻辑操作符被组合。Lucene支持 AND, “+”, OR, NOT and “-” 作为布尔操作符(注意:布尔操作符必须全部大写)。


OR


OR操作符是默认的连接操作。这意味着如果没有布尔值在两个分词之间的话,OR操作符将被使用。OR操作符连接两个分词,并且搜索包含任意一个分词的文档。这等价于与集合概念中的并集。 “||” 可以替代 OR。


搜索包含 “jakarta apache” 或者 只是 “jakarta” 的文档使用查询语句:


“jakarta apache” jakarta


或者


 “jakarta apache” OR jakarta


AND


AND操作符会匹配那些包含所有分词的文档。这等价与集合概念中的交集。”&&” 可以替代 AND。


搜索既包含 “jakarta apache” 又包含 “jakarta” 的文档使用查询语句:


 “jakarta apache” AND “jakarta lucene”
 
+作为必需操作符,需要 “+” 后的分词必须存在于被搜索文档的某个字段中。


搜索必须含有 “jakarta” 同时可能含有 “lucene” 的文档使用查询语句:


 +jakarta apache


NOT


NOT操作符会排除包含NOT后的分词的文档。这等价于集合概念中的补集。”!” 可以替代 NOT。


搜索包含”jakarta apache” 但不包含 “jakarta lucene”的文档使用查询语句:


 “jakarta apache” NOT “jakarta lucene”


注意:NOT操作符不能只和一个分词一起使用,下面这个查询不会返回任何结果:


 NOT “jakarta apache”


“-“作为禁止操作符将不匹配包含”-“所跟随的分词的文档。


搜索包含”jakarta apache” 而不包含 “jakarta lucene” 使用查询语句:


 “jakarta apache” -“jakarta lucene”
 
分组


Lucene支付使用圆括号把子句分组形成子查询。如果你想控制一个查询语句的布尔逻辑,那么这个将非常有用。


查找包含 “jakarta” 或者 “apache” , 同时包含 “website” 使用查询语句:


 (jakarta OR apache) AND website


这个将会排除任何混淆,并确定被搜索的文档必须包括 website 这个分词并且包括 jakarta 或者 apache 中的一个。
 
字段分组


Lucene支持针对单一字段使用圆括号对多个子句分组。


要搜索一个标题既包含分词”return” , 又包含短语 “pink panther” 使用查询语句:


特殊字符转换


作为查询语法的一部分,Lucene支持特殊字符。当前特殊支付包括:


+ – && || ! ( ) { } [ ] ^ ” ~ * ? : \


要转化一个特殊字符,就在要转化的字符前加上 “\” , 例如,搜索 (1+1):2 使用查询语句:


 \(1\+1\)\:2


原文:http://jakarta.apache.org/lucene/docs/queryparsersyntax.html