Rising Sun

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  148 随笔 :: 0 文章 :: 22 评论 :: 0 Trackbacks

2009年7月17日 #

     摘要: 看了网上的许多对于lucene 分词解析的文章一知半解且代码比较老旧,为透彻、系统、全面、深刻的了解分词是怎么一个过程,通过自定义一个分词器来分析理解。 其中分词部分利用ICTCLAS4j接口实现。结构如下所示:            要实现自定义的ICTCLAS4jAnalyzer必须继承Analy...  阅读全文
posted @ 2015-01-07 10:11 brock 阅读(1082) | 评论 (0)编辑 收藏

Lucene Directory类就像它的意思一样“目录”,如“目录”不存在,第一次启动被创建,一旦文件被创建,它只能打开阅读,或删除。允许读取和写入随机访问。Java I/O api 不能直接使用,只能通过这个API Directory的实现类可以分为文件目录,内存目录和目录的代理类及工具类。具体如下图所示:


一:文件目录

SimpleFSDirectory:FSDirectory的简单实现,并发能力有限,遇到多线程读同一个文件时会遇到瓶颈,通常用NIOFSDirectoryMMapDirectory代替。

NIOFSDirectory:通过java.nio's FileChannel实行定位读取,支持多线程读(默认情况下是线程安全的)。该类仅使用FileChannel进行读操作,写操作则是通过FSIndexOutput实现。

注意:NIOFSDirectory 不适用于Windows系统,另外如果一个访问该类的线程,在IO阻塞时被interruptcancel,将会导致底层的文件描述符被关闭,后续的线程再次访问NIOFSDirectory时将会出现ClosedChannelException异常,此种情况应用SimpleFSDirectory代替。

MMapDirectory:通过内存映射进行读,通过FSIndexOutput进行写的FSDirectory实现类。使用该类时要保证用足够的虚拟地址空间。另外当通过IndexInputclose方法进行关闭时并不会立即关闭底层的文件句柄,只有GC进行资源回收时才会关闭。

 

为了能适应各个操作系统选择最佳Directory方案,lucene 提供FSDirectory类的静态方法open()实现自适应。

 public static FSDirectory open(File path, LockFactory lockFactory) throws IOException {

    if ((Constants.WINDOWS || Constants.SUN_OS || Constants.LINUX)

          && Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) {

      return new MMapDirectory(path, lockFactory);

    } else if (Constants.WINDOWS) {

      return new SimpleFSDirectory(path, lockFactory);

    } else {

      return new NIOFSDirectory(path, lockFactory);

    }

  }

二:内存目录

RAMDirectory:常驻内存的Directory实现方式。默认通过SingleInstanceLockFactory(单实例锁工厂)进行锁的实现。该类不适合大量索引的情况另外也不适用于多线程的情况 在索引数据量大的情况下建议使用MMapDirectory代替。RAMDirectoryDirectory抽象类在使用内存最为文件存储的实现类,其主要是将所有的索引文件保存到内存中。这样可以提高效率。但是如果索引文件过大的话,则会导致内存不足,因此,小型的系统推荐使用,如果大型的,索引文件达到G级别上,推荐使用FSDirectory

NRTCachingDirectory:是对RAMDirectory的封装,适用于近乎时时(near-real-time)操作的环境。

三:Direcotry的代理类及工具类

FileSwitchDirectory:文件切换的Directory实现.针对lucene的不同的索引文件使用不同的Directory .借助FileSwitchDirectory整合不同的Directory实现类的优点于一身
比如MMapDirectory,借助内存映射文件方式提高性能,但又要减少内存切换的可能 ,当索引太大的时候,内存映射也需要不断地切换,这样优点也可能变缺点,而之前的NIOFSDirectory实现java NIO的方式提高高并发性能,但又因高并发也会导致IO过多的影响,所以这次可以借助FileSwitchDirectory发挥他们两的优点。

RateLimitedDirectoryWrapper:通过IOContext来限制读写速率的Directory封装类。

CompoundFileDirectory:用于访问一个组合的数据流。仅适用于读操作。对于同一段内扩展名不同但文件名相同的所有文件合并到一个统一的.cfs文件和一个对应的.cfe文件内。
.cfs文件由HeaderFileDataFileCount组成。.cfe文件由HeaderFileCount,FileName,DataOffset,DataLength组成。.cfs文件中存储着索引的概要信息及组合文件
的数目(FileCount)。.cfe文件存储文件目录的条目内容,内容中包括文件数据扇区的起始位置,文件的长度及文件的名称。

TrackingDirectoryWrapperDirectory的代理类。用于记录哪些文件被写入和删除。

四:Direcotry读写对象的类图




 文章转载过来的!

posted @ 2015-01-07 10:09 brock 阅读(263) | 评论 (0)编辑 收藏

    本机已经安装了jdk1.6,而比较早期的项目需要依赖jdk1.5,于是同时在本机安装了jdk1.5和jdk1.6. 

 安装jdk1.5前,执行java -version得到

java version "1.6.0_38"
Java(TM) SE Runtime Environment (build 1.6.0_38-b05)
Java HotSpot(TM) 64-Bit Server VM (build 20.13-b02, mixed mode)


安装完jdk1.5,并修改环境变量JAVA_HOME为D:\devSoftware\jdk1.5.再执行 java -version时,依然显示:

java version "1.6.0_38"
Java(TM) SE Runtime Environment (build 1.6.0_38-b05)
Java HotSpot(TM) 64-Bit Server VM (build 20.13-b02, mixed mode)


看上去,新的环境变量JAVA_HOME=D:\devSoftware\jdk1.5并没有生效。 在网上找了很多资料才发现:

      在安装JDK1.6时(本机先安装jdk1.6再安装的jdk1.5),自动将java.exe、javaw.exe、javaws.exe三个可执行文件复制到了C:\Windows\System32目录,由于这个目录在WINDOWS环境变量中的优先级高于JAVA_HOME设置的环境变量优先级


解决方案:将java.exe,javaw.exe,javaws.exe删除即可。开启新的命令行窗口,再执行java -version时,就得到了期望中的结果

java version "1.5.0_17"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_17-b04)
Java HotSpot(TM) 64-Bit Server VM (build 1.5.0_17-b04, mixed mode)


posted @ 2015-01-06 11:45 brock 阅读(7004) | 评论 (0)编辑 收藏

在学lucene 之初看了许多书,都是走马观花,没有项目的驱动下,来一个用例demo感觉也不是很难,“我会了”这是我的第一感觉。

         2013年底公司接到一个项目用到lucene,这是我第一次正真接触Lucene,代码比较老3.6版本,不适合新项目的需求(空间查询)。于是下载了最新版本 4.51,有带“空间查询”模块。各大搜索引擎都没有找到像样例子,于是想到了lucene svn trunk目录测试用例中找到了测试例子,开始了一段lucene之旅。

 

写数据,创建IndexWriter,通过它的构造函数需要一个索引目录(Diectory)和索引写入配置项(InderWriterConfig,直接上代码:

//设置写入目录(好几种呵呵)

Directory d=FSDirectory.open(new File("D:/luceneTest"));

//设置分词 StandardAnalyzer(会把句子中的字单个分词)

Analyzer analyzer= new StandardAnalyzer(Version.LUCENE_45);

//设置索引写入配置

IndexWriterConfig config=new IndexWriterConfig(Version.LUCENE_45,analyzer);

//设置创建模式

//config.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);

IndexWriter indexwriter= new IndexWriter(d,config);

 

    上面四行代码就创建好了indexwriter下面把数据填入就好了,写入有多种方式如下图:


         addDocment 举例代码如下:

Document doc=new Document(); 

        doc.add(new StringField("id", "1", Store.YES));

        doc.add(new StringField("name", "brockhong", Store.YES));

        doc.add(new TextField("content", "lucene 文档第一次写看着给分吧", Store.YES)); 

//写入数据

indexwriter.addDocument(doc);

//提交

indexwriter.commit();

Luke 工具查看Text列,这是标准分词惹的祸哦!写入成功。


         读数据查询,创建 IndexSearcher 构造函数设置indexReader ,输入查询条件,上面content字段数据设置了分词,所以必须通过查询解析类QueryParser设定分词字段、版本、分词模式,并通过parse方法得到查询条件。代码如下:       

 //读数据

 //创建 indexReader 这个已过时 IndexReader.open(d),里面的代码一样可能为了兼容老版本

 IndexReader indexReader = DirectoryReader.open(d);

 IndexSearcher indexSearcher = new IndexSearcher(indexReader);

//查询 设置分词字段

QueryParser queryParser = new QueryParser(Version.LUCENE_45, "content",

                   new StandardAnalyzer(Version.LUCENE_45));

 //or 关系 “给”、“分”

         queryParser.setDefaultOperator(QueryParser.OR_OPERATOR);

Query query = queryParser.parse("给分");

 

TopDocs results = indexSearcher.search(query, 100);

int numTotalHits = results.totalHits;

System.out.println(" " + numTotalHits + " 完全匹配的文档");

ScoreDoc[] hits = results.scoreDocs;

for (int i = 0; i < hits.length; i++) {

              Document document = indexSearcher.doc(hits[i].doc);

              System.out.println("content:" + document.get("content"));

}


pasting
posted @ 2014-12-31 17:07 brock 阅读(319) | 评论 (0)编辑 收藏

http://blog.csdn.net/ablipan/article/details/8198692

使用SAXReader的read(File file)方法时,如果xml文件异常会导致文件被服务器占用不能移动文件,建议不使用read(File file)方法而使用read(FileInputStream fis)等流的方式读取文件,异常时关闭流,这样就不会造成流未关闭,文件被锁的现象了。(在服务器中运行时会锁住文件,main方法却不会)。


1、以下方式xml文件异常时会导致文件被锁

  1.                    Document document = null;  
  2. File file = new File(xmlFilePath);  
  3. SAXReader saxReader = new SAXReader();  
  4. try  
  5. {  
  6.     document = saxReader.read(file);  
  7. } catch (DocumentException e)  
  8. {  
  9.     logger.error("将文件[" + xmlFilePath + "]转换成Document异常", e);  
  10. }  


2、以下方式xml文件异常时不会锁文件(也可以使用其他的流来读文件)

  1.                 Document document = null;  
  2. FileInputStream fis = null;  
  3. try  
  4. {  
  5.     fis = new FileInputStream(xmlFilePath);  
  6.     SAXReader reader = new SAXReader();  
  7.     document = reader.read(fis);  
  8. }   
  9. catch (Exception e)  
  10. {  
  11.     logger.error("将文件[" + xmlFilePath + "]转换成Document异常", e);  
  12. }   
  13. finally  
  14. {  
  15.     if(fis != null)  
  16.     {  
  17.         try  
  18.         {  
  19.             fis.close();  
  20.         } catch (IOException e)  
  21.         {  
  22.             logger.error("将文件[" + xmlFilePath + "]转换成Document,输入流关闭异常", e);  
  23.         }  
  24.     }  
  25. }  
posted @ 2014-09-02 14:00 brock 阅读(470) | 评论 (0)编辑 收藏

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>二次开发示例</title>
<link rel="stylesheet" href="../OpenLayers2.11/theme/default/style.css" type="text/css" />
    <script type="text/javascript" src="../OpenLayers2.11/OpenLayers.js"></script>
    <script type="text/javascript" src="../OpenLayers2.11/OpenLayersEx.js?random=8852c822-1ab8-4c0a-9717-b6f4c2b98115"></script>
 
    <!-- Import OpenLayers, reduced, wms read only version -->
    <!--<script src="../OpenLayers.js" type="text/javascript"></script>-->
<script type="text/javascript">
   var map;
var bounds = new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34);
function init() {
    var options = {
                       controls:[new OpenLayers.Control.XPanZoomBar(),new OpenLayers.Control.Navigation(),new OpenLayers.Control.MousePosition({numDigits:2})] ,
                        projection: 'EPSG:900913',
                        maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
                        maxResolution: 156543.0339,
                        units: 'm',
                        zoomLevel: 8
                    };
    map = new OpenLayers.Map('map',options);    
    
/*{
        div: "map",
        projection: "EPSG:900913",
        units: "m",
        maxExtent: new OpenLayers.Bounds(
            -20037508.34, -20037508.34, 20037508.34, 20037508.34
        ),
        maxResolution: 156543.0339,
zoomLevel: 8
    }*/
   // var osm = new OpenLayers.Layer.OSM();
    // If tile matrix identifiers differ from zoom levels (0, 1, 2, ...)
    // then they must be explicitly provided.
    var matrixIds = new Array(19);
    for (var i=0; i<16; ++i) {
        matrixIds[i] = i+"";
    }
var wmts2 = new OpenLayers.Layer.WMTS({
        name: "Medford Buildings",
        url: "http://t0.tianditu.com/cia_w/wmts",
        layer: "cia",
        matrixSet: "w",
        matrixIds: matrixIds,
        format: "tiles",
        style: "default",
        opacity: 0.7,
        isBaseLayer: false
    });       
    var wmts = new OpenLayers.Layer.WMTS({
        name: "vec",
        url: "http://t0.tianditu.com/vec_w/wmts",
        layer: "vec",
        matrixSet: "w",
        matrixIds: matrixIds,
        format: "tiles",
        style: "default",
        opacity:1,
        isBaseLayer: true
    });                
    map.addLayers( [wmts,wmts2]);
  //  map.addControl(new OpenLayers.Control.LayerSwitcher());
  //  map.setCenter(new OpenLayers.LonLat(13391734.740566667,3535411.228859166),7);
map.moveTo(new OpenLayers.LonLat(13391734.740566667,3535411.228859166),7);
}
</script>
</head>
 <body onload="init();">
        <h1 id="title">Web Map Tile Service (WMTS) Layer</h1>
        
    
        
        <div id="map" class="smallmap"></div>
        
       
    </body>
</html>
posted @ 2014-06-24 17:00 brock 阅读(816) | 评论 (0)编辑 收藏

arcgis

CGCS2000_3_Degree_GK_Zone_40

WKID: 4528 Authority: EPSG

 

Projection: Gauss_Kruger

False_Easting: 40500000.0

False_Northing: 0.0

Central_Meridian: 120.0

Scale_Factor: 1.0

Latitude_Of_Origin: 0.0

Linear Unit: Meter (1.0)

 

Geographic Coordinate System: GCS_China_Geodetic_Coordinate_System_2000

Angular Unit: Degree (0.0174532925199433)

Prime Meridian: Greenwich (0.0)

Datum: D_China_2000

  Spheroid: CGCS2000

    Semimajor Axis: 6378137.0

    Semiminor Axis: 6356752.314140356

Inverse Flattening: 298.257222101

 

Java 自定义

 

String [] proj4_w = new String [] { 

"+proj=tmerc", 
"+lat_0=0", 
"+lon_0=120", 
"+ellps=GRS80", 
"+units=m", 
"+x_0=40500000",
"+y_0=0",
"+k=1.0"
};

经纬度转换

       ///+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +units=m +no_defs

                Point2D.Double srcProjec = null;

                Point2D.Double dstProjec = null;

                Projection proj = ProjectionFactory.fromPROJ4Specification (proj4_w);

//  "epsg:4528" 数据从proj4 拷贝 nad

//      Point2D.Double srcProjec = null;

//      Point2D.Double dstProjec = null;

//      Projection proj = ProjectionFactory.getNamedPROJ4CoordinateSystem ("epsg:4528");

 

        srcProjec = new Point2D.Double (120.159,30.267);

        //40515348.2903 3349745.5395

       

        dstProjec = proj.transform (srcProjec, new Point2D.Double ());

        System.out.println ("TM:" + dstProjec);

    // TM: Point2D.Double [644904.399587292, 400717.8948938238]

 

        srcProjec = new Point2D.Double (40515348.2903 ,3349745.5395);

        dstProjec = proj.inverseTransform (srcProjec, new Point2D.Double ());

       

        System.out.println ("TM:" + dstProjec);

posted @ 2014-06-20 11:41 brock 阅读(3708) | 评论 (0)编辑 收藏

今天研究Oracle遇到了这个问题ora-01033:oracle initializationor shutdown in progress

ORA-01033:ORACLEinitialization or shutdown in progress

解决方法

1)开始-运行-cmd

2)命令行中输入SQLPLUS SYS/SYS AS SYSDBA

3)输入SHUTDOWN

4)输入STARTUP.注意这里是最重要的地方,在显示相关数据后,它还会显示为什么不能启动的错误所在.

 

C:\Users\lenovo>SQLPLUSSYS/SYS AS SYSDBA

SQL*Plus: Release 10.2.0.3.0 - Production on星期三 7月 3 11:43:32 2013

Copyright (c) 1982, 2006, Oracle.  All Rights Reserved.

连接到:

Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 -Production

With the Partitioning, OLAPand Data Mining options

SQL> SHUTDOWN

ORA-01109:数据库未打开

已经卸载数据库。

ORACLE例程已经关闭。

SQL> STARTUP

ORACLE例程已经启动。

Total System Global Area 293601280 bytes

Fixed Size                 1290208 bytes

Variable Size            234881056 bytes

Database Buffers           50331648 bytes

Redo Buffers               7098368 bytes

数据库装载完毕。

ORA-01157:无法标识/锁定数据文件 6 - 请参阅 DBWR 跟踪文件

ORA-01110:数据文件 6: 'F:\DC\DB\SDRS\TS_SDRS.DBF'

SQL> alter databasedatafile'F:\DC\DB\SDRS\TS_SDRS.DBF'offline drop;

 

数据库已更改。

 

SQL> alter database open;

 

数据库已更改。

 

SQL> drop tablespaceTS_SDRS including contents;

 

表空间已删除。

SQL> create undo tablespace TS_SDRS

  2  datafile'CracleoradatasmsdbUNDOTBS01.DBF'size 2048M extent management local;

 

表空间已创建。

 

SQL> alter system setundo_tablespace=TS_SDRS;

 

系统已更改。

 

SQL> shutdown

数据库已经关闭。

已经卸载数据库。

ORACLE例程已经关闭。

SQL> startup

ORACLE例程已经启动。

 

Total System Global Area  293601280 bytes

Fixed Size                 1290208 bytes

Variable Size            243269664 bytes

Database Buffers          41943040 bytes

Redo Buffers               7098368 bytes

数据库装载完毕。

数据库已经打开。

SQL>


------------------
ORA-01245、ORA-01547错误的解决            

数据库rman restore database 之后,执行recover database的时候,报告ORA-01245错误,详细的错误信息如下:


SQL> recover database until cancel;
ORA-00279: change 575876 generated at 12/01/2009 08:19:49 needed for thread 1
ORA-00289: suggestion :
/oracle/flash_recovery_area/ORCL/archivelog/2009_12_01/o1_mf_1_2_%u_.arc
ORA-00280: change 575876 for thread 1 is in sequence #2


Specify log: {=suggested | filename | AUTO | CANCEL}
auto
ORA-00308: cannot open archived log
'/oracle/flash_recovery_area/ORCL/archivelog/2009_12_01/o1_mf_1_2_%u_.arc'
ORA-27037: unable to obtain file status
Linux Error: 2: No such file or directory
Additional information: 3


ORA-00308: cannot open archived log
'/oracle/flash_recovery_area/ORCL/archivelog/2009_12_01/o1_mf_1_2_%u_.arc'
ORA-27037: unable to obtain file status
Linux Error: 2: No such file or directory
Additional information: 3


ORA-01547: warning: RECOVER succeeded but OPEN RESETLOGS would get error below
ORA-01245: offline file 2 will be lost if RESETLOGS is done
ORA-01110: data file 2: '/oracle/oradata/orcl/undotbs01.dbf'


SQL>

 

[@more@]

检查ORA-01245那一行,发现是datafile 2状态为offline,解决的方法就是首先将datafile 2 online,然后再recover database。

SQL> alter database datafile 2 online;

Database altered.

SQL> recover database until cancel;
ORA-00279: change 575876 generated at 12/01/2009 08:19:49 needed for thread 1
ORA-00289: suggestion :
/oracle/flash_recovery_area/ORCL/archivelog/2009_12_01/o1_mf_1_2_%u_.arc
ORA-00280: change 575876 for thread 1 is in sequence #2


Specify log: {=suggested | filename | AUTO | CANCEL}
cancel
Media recovery cancelled.
SQL> alter database open resetlogs;

Database altered.

SQL>

--------------------

ORA-01589: 要打开数据库则必须使用 RESETLOGS 或 NOR


ORA-01589: 要打开数据库则必须使用 RESETLOGS 或 NORESETLOGS
选项


SQL> alter database open 
ORA-01589: 要打开数据库则必须使用 RESETLOGS 或
NORESETLOGS 选项

SQL> alter database open resetlogs;
alter database
open resetlogs
*
ERROR 位于第 1 行:
ORA-01113: 文件 1 需要介质恢复
ORA-01110:
数据文件 1: 'E:\ORACLE\ORADATA\EYGLE\SYSTEM01.DBF'

SQL> recover database
using backup controlfile;
ORA-00279: 更改 1670743 (在 04/17/2008 14:13:16 生成)
对于线程 1 是必需的
ORA-00289: 建议: E:\ORACLE\ORA92\RDBMS\ARC00030.001
ORA-00280:
更改 1670743 对于线程 1 是按序列 # 30 进行的

指定日志: {<RET>=suggested | filename |
AUTO | CANCEL}
E:\oracle\oradata\EYGLE\REDO01.LOG
ORA-00310: 存档日志包含序列
29;要求序列 30
ORA-00334: 归档日志:
'E:\ORACLE\ORADATA\EYGLE\REDO01.LOG'

SQL> recover database using
backup controlfile;
ORA-00279: 更改 1670743 (在 04/17/2008 14:13:16 生成) 对于线程 1
是必需的
ORA-00289: 建议: E:\ORACLE\ORA92\RDBMS\ARC00030.001
ORA-00280: 更改
1670743 对于线程 1 是按序列 # 30 进行的

指定日志: {<RET>=suggested | filename |
AUTO |
CANCEL}
E:\oracle\oradata\EYGLE\REDO02.LOG
已应用的日志。
完成介质恢复。
SQL>
alter database open resetlogs;
数据库已更改。


OK,搞定了!

posted @ 2014-04-30 14:38 brock 阅读(9079) | 评论 (0)编辑 收藏

首先来看问题,然后来看函数的定义,其实什么都在函数定义里面说明白了

1.正则表达式字符串问题

首先输入的regex是一个正则表达式,而不是一个普通的字符串,所以导致很多在正则表达式里面有特殊意义的比如 "." "|" "\" ,如果直接使用是不行的,另外一个方面我们输入的regex是以字符串形式传递的,对有些字符必须要转义,尤其是"\",下面请看例子

String[] aa = "aaa|bbb|ccc".split("|");//wrong
String[] aa = "aaa|bbb|ccc".split("\\|"); //

 

 String[] aa = "aaa*bbb*ccc".split("*");//wrong
 String[] aa = "aaa|bbb|ccc".split("\\*");

 

 String[] aa = "aaa*bbb*ccc".split(".");//wrong
 String[] aa = "aaa|bbb|ccc".split("\\.");

 

String[] aa = "aaa\\bbb\\bccc".split("\\");//wrong

String[] aa = "aaa\\bbb\\bccc".split("\\\\");

 

2.数组长度的问题

String a = "";
String[] b = a.split(",");
b.length为 1;
*
String a = "c";
String[] b = a.split(",");
b.length为 1;
**
String a = "c,,,";
String[] b = a.split(",");
b.length为 1;
***
String a = "c,,c";
String[] b = a.split(",");
b.length为 3;
****
String a = ",";
String[] b = a.split(",");
b.length为 0;

 

其实只要添加一个参数即可,例如

String str = "abcdef,ghijk,lmno,pqrst,,,";       

String[] array = str.split(",");
输出:abcdef,ghijk,lmno,pqrst,

 

String str = "abcdef,ghijk,lmno,pqrst,,,";
String[] array 
= str.split(",",-1);

输出:abcdef,ghijk,lmno,pqrst,,,,

 

public String [] split (String  regex, int limit) 

最后一个参数limit是影响返回数组的长度的

=========================请关注红色字体(括号内为注释)==========================================

public String[] split(String regex)

根据给定的正则表达式的匹配来拆分此字符串。

该方法的作用就像是使用给定的表达式和限制参数 0 来调用两参数 split 方法。因此,结果数组中不包括结尾空字符串(直接使用会造成数组大小问题)

例如,字符串 "boo:and:foo" 产生带有下面这些表达式的结果:

Regex结果
:{ "boo", "and", "foo" }
o{ "b", "", ":and:f" }

 

参数:
regex - 定界正则表达式
返回:
字符串数组,根据给定正则表达式的匹配来拆分此字符串,从而生成此数组。

public String[] split(String regex,
                      int limit)

根据匹配给定的正则表达式来拆分此字符串。

此方法返回的数组包含此字符串的每个子字符串,这些子字符串由另一个匹配给定的表达式的子字符串终止或由字符串结束来终止。数组中的子字符串按它们在此字符串中的顺序排列。如果表达式不匹配输入的任何部分,则结果数组只具有一个元素,即此字符串。

limit 参数控制模式应用的次数,因此影响结果数组的长度如果该限制 n 大于 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n,而且数组的最后项将包含超出最后匹配的定界符的所有输入。如果 n 为非正,则模式将被应用尽可能多的次数,而且数组可以是任意长度。如果 n 为零,则模式将被应用尽可能多的次数,数组可有任何长度,并且结尾空字符串将被丢弃

例如,字符串 "boo:and:foo" 使用这些参数可生成下列结果:

RegexLimit结果
:2{ "boo", "and:foo" }
:5{ "boo", "and", "foo" }
:-2{ "boo", "and", "foo" }
o5{ "b", "", ":and:f", "", "" }
o-2{ "b", "", ":and:f", "", "" }
o0{ "b", "", ":and:f" }

这种形式的方法调用 str.split(regex, n) 产生与以下表达式完全相同的结果:

Pattern.compile(regex).split(str, n)

 

参数:
regex - 定界正则表达式
limit - 结果阈值,如上所述
返回:
字符串数组,根据给定正则表达式的匹配来拆分此字符串,从而生成此数组

 

posted @ 2014-04-28 10:15 brock 阅读(237) | 评论 (0)编辑 收藏

  List<Calendar> l = new ArrayList<Calendar>(); 
while (true) {
l.add(Calendar.getInstance());
System.out.println(l.size());
}
605473
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Calendar.<init>(Unknown Source)
at java.util.GregorianCalendar.<init>(Unknown Source)
at java.util.Calendar.createCalendar(Unknown Source)
at java.util.Calendar.getInstance(Unknown Source)
at jodatestmemory.Main.main(Main.java:25)
posted @ 2014-01-08 11:26 brock 阅读(356) | 评论 (0)编辑 收藏

头文件
#ifndef CLASS_GEOMETRYTOSTRING
#define CLASS_GEOMETRYTOSTRING
 
#include <iostream>
#include <FileGDBAPI.h>
using namespace std;
class GeometryToString
{
public:
static  bool getGeometryStr( FileGDBAPI::ShapeBuffer &geometry,string srid,string &geometrystr); 
private:
static void getPointGML(FileGDBAPI::PointShapeBuffer *&pbuffer,string srid,string dimension, string &xml);
static void getLineGML(FileGDBAPI::MultiPartShapeBuffer *&lineGeometry,string srid,string dimension, string &xml);
static void getMultipointGML(FileGDBAPI::MultiPointShapeBuffer *&multipointGeometry,string srid,string dimension, string &xml);
static void getPolygonGML(FileGDBAPI::MultiPartShapeBuffer *&polygonGeometry,string srid,string dimension, string &xml);
};
#endif
--------------------------------
#include <jni.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <fstream>
#include <time.h>
#include <sstream> 
#include <FileGDBAPI.h>
#include "GeometryToString.h"
using namespace FileGDBAPI;
using namespace std;
/**
ShapeBuffer geometry format to gml
*/
bool GeometryToString::getGeometryStr( ShapeBuffer &geometry,string srid,string &geometrystr)     
{
ShapeType pType;
string dimension("2");
try{
geometry.GetShapeType(pType);
if(pType==shapeNull){
return false;
}
if(geometry.HasMs(pType) || geometry.HasZs(pType)){
dimension.assign("3");
}
//点
if(pType==shapePoint){
PointShapeBuffer *pPoint = static_cast<PointShapeBuffer*>(&geometry);
getPointGML(pPoint, srid, dimension, geometrystr);
}
//复杂点 shapeMultipoint         =  8, shapeMultipointM        = 28,  shapeMultipointZM       = 18, shapeMultipointZ        = 20,
else if(pType==shapeMultipoint||pType==shapeMultipointZ){
MultiPointShapeBuffer *pPoint = static_cast<MultiPointShapeBuffer*>(&geometry);
getMultipointGML(pPoint, srid, dimension, geometrystr);
}
//线
else if(pType==shapePolyline||pType==shapePolylineZ){
MultiPartShapeBuffer *pPoint = static_cast<MultiPartShapeBuffer*>(&geometry);
getLineGML(pPoint, srid, dimension, geometrystr);
}
//面 shapePolygon            =  5, shapePolygonM           = 25,  shapePolygonZM          = 15,  shapePolygonZ           = 19,
else if(pType==shapePolygon||pType==shapePolygonZ){
MultiPartShapeBuffer *pPoint = static_cast<MultiPartShapeBuffer*>(&geometry);
getPolygonGML(pPoint, srid, dimension, geometrystr);
}
//geometrystr = xml;
}catch(exception& e){
cout <<"格式化gml出错"<< e.what() << '\n';
return false;
}
return true;
}
/**
<gml:Polygon srsName="SDO:4269" xmlns:gml="http://www.opengis.net/gml">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="2">-73.2580598287651 42.7460586400617 -73.0196951738303 42.740396678634 -72.9229974292253 42.7373644761786 -72.4557700038866 42.7258525290856 -72.4621713056891 42.7468405310805 -72.4793225257782 42.7615879021406 -72.507269529053 42.768732690401 -72.513068008801 42.7892594013537 -72.5389169708409 42.8077338159122 -72.5534284639708 42.8606431711071 -72.5248100213574 42.912614176111 -72.5202170578447 42.951672527189 -72.5042636319544 42.9655846501007 -72.4733411974969 42.9761435837694 -72.4571590376321 42.9996036974295 -72.461752087004 43.0465044640799 -72.4434642578885 43.0790393128302 -72.4376049020671 43.1162700005077 -72.4523985528512 43.1560221784821 -72.4355986440692 43.2322535514026 -72.4024188454006 43.3073827061476 -72.4102315830492 43.3234041461304 -72.3976280543775 43.3510068532968 -72.4121395531362 43.3771255999364 -72.3962478080998 43.4101565518933 -72.3825156946812 43.4846296935806 -72.3949977682121 43.5175538931663 -72.3734983899535 43.5723746289273 -72.3330851941569 43.597364792188 -72.3040399378543 43.6985301192074 -72.2600555952028 43.7353001230665 -72.219122921336 43.7506925284353 -72.2060918209679 43.7646350589214 -72.1848363730122 43.80169046066 -72.1700895247441 43.8789176964692 -72.1216496397887 43.9092173247051 -72.1132040793556 43.9391659598858 -72.0917117306645 43.9579911279466 -72.1128078470402 43.9765149671878 -72.109908766997 43.9892291134735 -72.0852043813773 44.0089239861752 -72.0769190441221 44.0320405986229 -72.0347283650035 44.0833740182692 -72.0324473746587 44.0960996192242 -72.0495148341973 44.1004520944913 -72.034919852375 44.1207459288225 -72.0447245537617 44.1564355666161 -72.0592822460624 44.1821766291117 -72.0443903804218 44.2343798441307 -72.0595660047421 44.2614940911533 -72.0354953753776 44.2994343131499 -71.9944335108703 44.327548202346 -71.9389056579791 44.3257860034125 -71.9283617527138 44.3361121851129 -71.8348159803514 44.3441994129005 -71.821197308355 44.3503600453548 -71.7977291908463 44.3841728130012 -71.7665702593917 44.3982488046659 -71.6768843632127 44.4213427403399 -71.6563990024127 44.4401373612433 -71.6477091613881 44.4691741459765 -71.6365547217831 44.4767309013869 -71.6142227691161 44.4745070427354 -71.5866189807601 44.4945375694191 -71.5752435447921 44.5258056891543 -71.5914413886211 44.5388744007984 -71.5922884113102 44.5512031068491 -71.5367908177936 44.578931263059 -71.554102635183 44.5965889130363 -71.5680271516494 44.6374468081651 -71.588749347522 44.6505994869911 -71.6076787297883 44.6778622938611 -71.6311328527304 44.741710760694 -71.583501209059 44.779196995866 -71.5751009123659 44.8160197976273 -71.5063649605901 44.8996711859762 -71.5169776077168 44.9436961331566 -71.5409270967342 44.9765632062274 -71.5053723006288 45.0133517163227 -71.9018687560566 45.0073398737601 -72.547231170846 45.0053701041526 -73.1885457846918 45.0084861445147 -73.3447234868808 45.0061387945908 -73.3507583871194 44.9819729513452 -73.336414678892 44.9326039308501 -73.3823067594393 44.847933618761 -73.3690541280725 44.8191179021752 -73.3267863194035 44.7992935709543 -73.3731585750219 44.7242364367472 -73.3581509561493 44.6803685644813 -73.3730971364166 44.661276356252 -73.3701366913554 44.6343490646186 -73.3818251037205 44.619807725515 -73.3712960298211 44.5791669569445 -73.3478119840265 44.5539715457203 -73.3344524939974 44.5443282463014 -73.2933197444992 44.4328535783628 -73.2999951630005 44.4055331645411 -73.329788093029 44.3673904680867 -73.3053256664728 44.2601422576288 -73.3773326255291 44.2012475171298 -73.3820623364064 44.1721076120789 -73.4078648304615 44.1362270392698 -73.408756830709 44.1066103535608 -73.4352152780239 44.0638978024284 -73.4360007112789 44.0456791904392 -73.4082513023357 44.0182219013789 -73.4174061301201 43.9881969457531 -73.4053345287368 43.9148075869024 -73.3751207851313 43.8859769501208 -73.3847399017653 43.8045079717314 -73.35899716813 43.7784275686935 -73.3566696765928 43.7565583405993 -73.3709893845573 43.7142811167279 -73.4229598542952 43.6321147289768 -73.4183198417113 43.5824793859982 -73.38811421923 43.569143658301 -73.3636855615672 43.6149988679746 -73.303534516911 43.6247148128503 -73.2941043006646 43.6196528756939 -73.2817362682322 43.593187249577 -73.2914024969012 43.5750335705379 -73.2599837938072 43.5593823395161 -73.2383913589494 43.5128328494146 -73.2500714436228 43.3108539907423 -73.2760052890117 42.9402941192892 -73.2795831999318 42.8371033274803 -73.2961697572314 42.8035493647592 -73.2692753169001 42.7474814329983 -73.2580598287651 42.7460586400617 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
-----------------------------------------
<gml:MultiSurface srsName="SDO:4269" xmlns:gml="http://www.opengis.net/gml">
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="2">-71.7901942031213 41.6013068793251 -71.8027434308056 41.415829054006 -71.8459956537022 41.403854541649 -71.8368696812943 41.3419614666217 -71.8477722040922 41.3253484832966 -71.866678442895 41.3227696452717 -71.7222643227053 41.327264312184 -71.4898880400564 41.3920853196253 -71.427318519639 41.4866893796324 -71.4192468515382 41.6522122329241 -71.3690125475301 41.7032911019032 -71.3935805976545 41.7611558353254 -71.3673874451962 41.7413502009834 -71.2840016520154 41.6795489704365 -71.2289761591777 41.7076939683675 -71.2666285816006 41.7497430522049 -71.3193277902704 41.7721958646079 -71.33979862314 41.784425562696 -71.3454831662469 41.8131613833438 -71.3345427095385 41.8579036075386 -71.3424931202155 41.875782891498 -71.3330859502879 41.8960311596525 -71.3839531547034 41.8884397544728 -71.3824052822434 41.9792630768654 -71.3786442228911 42.0137133195164 -71.4974303691298 42.0092535031424 -71.7978316087618 42.0042748046853 -71.7882488621949 41.721603395324 -71.7926052182918 41.6417579304639 -71.7901942031213 41.6013068793251 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="2">-71.1988086806703 41.6785003452844 -71.1999371652607 41.4633184834308 -71.1171327154704 41.4930619563069 -71.1412126344661 41.6552730544526 -71.1988086806703 41.6785003452844 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="2">-71.2691694549114 41.6212683171835 -71.3495250332551 41.445857741455 -71.288007152861 41.4836193369167 -71.2386732340455 41.4748497781273 -71.2194468005559 41.6356423127122 -71.2691694549114 41.6212683171835 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
*/
void GeometryToString::getPolygonGML(FileGDBAPI::MultiPartShapeBuffer *&polygonGeometry,string srid,string dimension, string &xml){
int numPts;
polygonGeometry->GetNumPoints(numPts);
int numParts;
polygonGeometry->GetNumParts(numParts);
int* parts;
polygonGeometry->GetParts(parts);
Point* points;
polygonGeometry->GetPoints(points);
string gmlSub("");
if(numParts==1){
xml= "<gml:Polygon srsName=\"SDO:"+srid+"\" xmlns:gml=\"http://www.opengis.net/gml\"> \
<gml:exterior> \
<gml:LinearRing> \
<gml:posList srsDimension=\""+dimension+"\">";
for (int i = 0; i < numPts; i++)
{
char buffer[32];
sprintf(buffer, "%1.14g", points[i].x);
gmlSub.append(buffer).append(" ");
sprintf(buffer, "%1.14g", points[i].y);
gmlSub.append(buffer).append(" ");
}  
xml.append(gmlSub);
xml.append("</gml:posList></gml:LinearRing>\
  </gml:exterior>\
  </gml:Polygon>");
return;
}
if(numParts>1){
xml="<gml:MultiSurface srsName=\"SDO:"+srid+"\" xmlns:gml=\"http://www.opengis.net/gml\">";
for(int i=0;i<numParts;i++){
gmlSub.append("<gml:surfaceMember>\
 <gml:Polygon>\
 <gml:exterior>\
 <gml:LinearRing>\
 <gml:posList srsDimension=\"").append(dimension).append("\">");
int gt=0;
if( i==(numParts-1)){
gt=numPts;
}else{
gt=parts[i+1];
}
for (int j= parts[i]; j < gt; j++){
char buffer[32];
sprintf(buffer, "%1.14g", points[j].x);
gmlSub.append(buffer).append(" ");
sprintf(buffer, "%1.14g", points[j].y);
gmlSub.append(buffer).append(" ");
}
gmlSub.append("</gml:posList>\
 </gml:LinearRing>\
 </gml:exterior>\
 </gml:Polygon>\
 </gml:surfaceMember>");
}
xml.append(gmlSub);
xml.append("</gml:MultiSurface>");
return;
}
}
/**
<gml:MultiPoint srsName="SDO:2230" xmlns:gml="http://www.opengis.net/gml">
<gml:pointMember>
<gml:Point>
<gml:posList srsDimension="3">6301153.87493073 1913012.75794829 435.0 </gml:posList>
</gml:Point>
</gml:pointMember>
<gml:pointMember>
<gml:Point>
<gml:posList srsDimension="3">6301172.62522131 1913331.50796697 424.0 </gml:posList>
</gml:Point>
</gml:pointMember>
</gml:MultiPoint>
*/
void GeometryToString::getMultipointGML(FileGDBAPI::MultiPointShapeBuffer *&multipointGeometry,string srid,string dimension, string &xml){
int numPts;
multipointGeometry->GetNumPoints(numPts);
wcout << "Multipoint test:" << endl;
wcout << "Points: " << numPts << endl;
Point* points;
multipointGeometry->GetPoints(points);
double* zArray;
multipointGeometry->GetZs(zArray);
xml= "<gml:MultiPoint srsName=\"SDO:"+srid+"\" xmlns:gml=\"http://www.opengis.net/gml\"> ";
string gmlSub("");
for (int i = 0; i < numPts; i++)
{
gmlSub.append("<gml:pointMember><gml:Point><gml:posList srsDimension=\""+dimension+"\">");
char buffer[32];
sprintf(buffer, "%1.14g", points[i].x);
gmlSub.append(buffer).append(" ");
sprintf(buffer, "%1.14g", points[i].y);
gmlSub.append(buffer).append(" ");
sprintf(buffer, "%1.14g", zArray[i]);
gmlSub.append(buffer).append(" ");
gmlSub.append("</gml:posList></gml:Point></gml:pointMember>");
}
xml.append(gmlSub);
xml.append("</gml:MultiPoint>");
}
/**
<gml:Curve srsName="SDO:4269" xmlns:gml="http://www.opengis.net/gml">
<gml:segments>
<gml:LineStringSegment>
<gml:posList srsDimension="2">-91.3082592401631 40.0073363232732 -91.3055891069314 39.995346341049 -91.3139124547158 39.9690362798168 -91.3254189367963 39.9469572142013 -91.3246098997585 39.9350861975012 -91.32260281264 39.9251371873939 -91.3238158572038 39.896847138931 -91.3220157795743 39.8891571322064 -91.3241598689896 39.8853761196319 -91.3383584637069 39.873997056967 -91.3394875098243 39.8690760451917 -91.3354593387828 39.8630950480564 -91.3031399738825 39.8280070993682 -91.3022619338156 39.8090860744066 -91.2985697775187 39.7987370721841 -91.3005688605598 39.7949870596141 -91.3073361425165 39.7886050259611 -91.3117993281738 39.783596002295 -91.3119823326406 39.7676969773468 -91.3108232836762 39.7648359772821 -91.3049330369361 39.7602849923819 -91.2990957929273 39.7579610108158 -91.1947826970924 39.7164273102698 </gml:posList>
</gml:LineStringSegment>
</gml:segments>
</gml:Curve>
<gml:MultiCurve srsName="SDO:4269" xmlns:gml="http://www.opengis.net/gml">
<gml:curveMember>
<gml:Curve>
<gml:segments>
<gml:LineStringSegment>
<gml:posList srsDimension="2"> sssss</gml:posList>
</gml:LineStringSegment>
</gml:segments>
</gml:Curve>
</gml:curveMember>
<gml:curveMember>
<gml:Curve>
<gml:segments>
<gml:LineStringSegment>
<gml:posList srsDimension="2">sssss </gml:posList>
</gml:LineStringSegment>
</gml:segments>
</gml:Curve>
</gml:curveMember>
</gml:MultiCurve>
*/
void GeometryToString::getLineGML(MultiPartShapeBuffer *&lineGeometry,string srid,string dimension, string &xml)
{
int numPts,numParts;
lineGeometry->GetNumPoints(numPts);
lineGeometry->GetNumParts(numParts);
int* parts;
lineGeometry->GetParts(parts);
Point* points;
lineGeometry->GetPoints(points);
string gmlSub("");
if(numParts==1){
xml= "<gml:Curve srsName=\"SDO:"+srid+"\" xmlns:gml=\"http://www.opengis.net/gml\"> \
 <gml:segments> \
 <gml:LineStringSegment> \
 <gml:posList srsDimension=\""+dimension+"\">";
for (int i = 0; i < numPts; i++)
{
char buffer[32];
sprintf(buffer, "%1.14g", points[i].x);
gmlSub.append(buffer).append(" ");
sprintf(buffer, "%1.14g", points[i].y);
gmlSub.append(buffer).append(" ");
}  
xml.append(gmlSub);
xml.append("</gml:posList> \
  </gml:LineStringSegment>\
  </gml:segments> \
  </gml:Curve>");
return;
}
if(numParts>1){
xml="<gml:MultiCurve srsName=\"SDO:"+srid+"\" xmlns:gml=\"http://www.opengis.net/gml\">";
for(int i=0;i<numParts;i++){
gmlSub.append("<gml:curveMember>\
 <gml:Curve>\
 <gml:segments>\
 <gml:LineStringSegment>\
 <gml:posList srsDimension=\"").append(dimension).append("\">");
int gt=0;
if( i==(numParts-1)){
gt=numPts;
}else{
gt=parts[i+1];
}
for (int j= parts[i]; j < gt; j++){
char buffer[32];
sprintf(buffer, "%1.14g", points[j].x);
gmlSub.append(buffer).append(" ");
sprintf(buffer, "%1.14g", points[j].y);
gmlSub.append(buffer).append(" ");
}
gmlSub.append("</gml:posList>\
 </gml:LineStringSegment>\
 </gml:segments>\
 </gml:Curve>\
 </gml:curveMember>");
}
xml.append(gmlSub);
xml.append("</gml:MultiCurve>");
return;
}
}
/*
<gml:Point srsName="SDO:4269" xmlns:gml="http://www.opengis.net/gml">
<gml:posList srsDimension="2">-88.0261499418109 44.4722440557492 </gml:posList>
</gml:Point>
*/
void GeometryToString::getPointGML( PointShapeBuffer *&pbuffer,string srid,string dimension, string &xml)
{
xml= "<gml:Point srsName=\"SDO:"+srid+"\" xmlns:gml=\"http://www.opengis.net/gml\"><gml:posList srsDimension=\""+dimension+"\">";
Point* points;
pbuffer->GetPoint(points);
char buffer[32];
sprintf(buffer, "%1.14g", points[0].x);
xml.append(buffer).append(" ");
sprintf(buffer, "%1.14g", points[0].y);
xml.append(buffer).append(" ");
xml.append("</gml:posList></gml:Point>");
}
posted @ 2014-01-02 10:19 brock 阅读(324) | 评论 (0)编辑 收藏

写给自己看看
java --HelloJNI ---
import java.io.UnsupportedEncodingException;
public class HelloJNI {
static {
     System.loadLibrary("HelloJNI"); // hello.dll (Windows) or libhello.so (Unixes)
  
  }
  // A native method that receives nothing and returns void
  private native void sayHello();
  
  private native double sayOK(String dd);
  
  private native void getFileGdb(String path);
  
  private native String getFileGdbStr(String path);
  
  private native GeodbEntity getGdbTable(GeodbEntity geo);
 
  /**
* @param args
* @throws UnsupportedEncodingException
*/
/**  
* @param args
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws UnsupportedEncodingException {
//   System.out.println( System.getProperty("java.library.path"));
  HelloJNI hello =  new HelloJNI();
//   hello.sayHello();  // invoke the native method
  
//   System.out.println(hello.sayOK("Apple"));
//   
  //hello.getFileGdb("D:/cpp/FileGDB_API_VS2012_1_3/samples/data/ExecuteSQL.gdb");
  //GeodbEntity dd= hello.getGdbTable("D:/cpp/FileGDB_API_VS2012_1_3/samples/data/ExecuteSQL.gdb","dd");
  GeodbEntity dd= new GeodbEntity();
  dd.setTable("D:/cpp/FileGDB_API_VS2012_1_3/samples/data/ExecuteSQL.gdb 阿切尔");
  
  hello.getGdbTable(dd);
 
 System.out.println("java"+dd.getSrid());
 for(int i=0;i<dd.getFieldValues().size();i++){
 System.out.println(dd.getFieldValues().get(i));
 
 }
 // System.out.println(hello.getFileGdbStr("D:/cpp/FileGDB_API_VS2012_1_3/samples/data/ExecuteSQL.gdb"));
  
  }
}
-----GeodbEntity ----
import java.util.List;
import java.util.ArrayList;
public class GeodbEntity {
//输入
private String table;
private String eodbPath;
//输出
/**列字段##隔开*/
private String Fields;
/**数据表##隔开*/
private ArrayList<String> FieldValues=new ArrayList<String>();
/**空间参考标识符*/
private String srid;
/**维度*/
private String dimension;
public String getTable() {
return table;
}
public void setTable(String table) {
this.table = table;
}
public String getEodbPath() {
return eodbPath;
}
public void setEodbPath(String eodbPath) {
this.eodbPath = eodbPath;
}
public String getSrid() {
return srid;
}
public void setSrid(String srid) {
this.srid = srid;
}
public String getDimension() {
return dimension;
}
public void setDimension(String dimension) {
this.dimension = dimension;
}
public String getFields() {
return Fields;
}
public void setFields(String fields) {
Fields = fields;
}
public ArrayList<String> getFieldValues() {
return FieldValues;
}
public void setFieldValues(ArrayList<String> fieldValues) {
FieldValues = fieldValues;
}
public String toString() {
        return Fields;
    }
}
--c++
hellojni.h
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloJNI
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloJNI_sayHello
  (JNIEnv *, jobject);
/*
 * Class:     HelloJNI
 * Method:    sayOK
 * Signature: (Ljava/lang/String;)D
 */
JNIEXPORT jdouble JNICALL Java_HelloJNI_sayOK
  (JNIEnv *, jobject, jstring);
/*
 * Class:     HelloJNI
 * Method:    getFileGdb
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_HelloJNI_getFileGdb
  (JNIEnv *, jobject, jstring);
/*
 * Class:     HelloJNI
 * Method:    getFileGdbStr
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_HelloJNI_getFileGdbStr
  (JNIEnv *, jobject, jstring);
/*
 * Class:     HelloJNI
 * Method:    getGdbTable
 * Signature: (LGeodbEntity;)LGeodbEntity;
 */
JNIEXPORT jobject JNICALL Java_HelloJNI_getGdbTable
  (JNIEnv *, jobject, jobject);
#ifdef __cplusplus
}
#endif
#endif
----------hello c++------

#include <jni.h>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include "HelloJNI.h"
#include <fstream>
#include <time.h>
#include <FileGDBAPI.h>
using namespace std;
using namespace FileGDBAPI;
using namespace std;
 
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
printf("Hello World!\n");
return;
}
JNIEXPORT jdouble JNICALL Java_HelloJNI_sayOK
(JNIEnv* env, jobject obj, jstring name){
const char* pname=env->GetStringUTFChars(name,NULL);
if(strcmp(pname,"Apple")==0){
env->ReleaseStringUTFChars(name,pname);
cout<<"After release:"<<pname<<endl;
return 1.2;
}
else{
env->ReleaseStringUTFChars(name,pname);
cout<<"After release:"<<pname<<endl;
return 2.1;
}
}
JNIEXPORT jstring JNICALL Java_HelloJNI_getFileGdbStr
(JNIEnv *env, jobject thisObj, jstring path){
/* fgdbError hr;
wstring errorText;
Geodatabase geodatabase;
std::wstring value;
const jchar* raw = env->GetStringChars(path, NULL);
if (raw != NULL) {
jsize len = env->GetStringLength(path);
value.assign(raw, raw + len);
env->ReleaseStringChars(path, raw);
}
if ((hr = OpenGeodatabase(value, geodatabase)) != S_OK)
{
wcout << "An error occurred while opening the geodatabase." << endl;
ErrorInfo::GetErrorDescription(hr, errorText);
wcout << errorText << "(" << hr << ")." << endl;
return (env)->NewStringUTF("7");
}
Row     attrQueryRow;
EnumRows attrQueryRows;
wstring sqlStatement(L"SELECT * FROM Cities WHERE TYPE = 'city' AND OBJECTID < 10");
if ((hr = geodatabase.ExecuteSQL(sqlStatement, true, attrQueryRows)) != S_OK)
{
wcout << "An error occurred while performing the attribute query." << endl;
ErrorInfo::GetErrorDescription(hr, errorText);
wcout << errorText << "(" << hr << ")." << endl;
return (env)->NewStringUTF("7");
}
FieldInfo fieldInfo;
attrQueryRows.GetFieldInformation(fieldInfo);
int       fieldCount;
FieldType fieldType;
wstring   fieldName;
// Iterate through the returned rows printing out all field values.
short     shortField;
int32     longField;
float     floatField;
double    doubleField;
string    stringField;
wstring   wstringField;
tm        dateTimeField;
char      datetime[80];
Guid      globalIDField;
Guid      guidField;
wstring   strGuid;
wstring   strGlobalID;
bool      isNull;
byte * shapeBufferBytes ;
ShapeBuffer geometry;
ByteArray  bss;
while (attrQueryRows.Next(attrQueryRow) == S_OK)
{
fieldInfo.GetFieldCount(fieldCount);
for (long fieldNumber = 0; fieldNumber < fieldCount; fieldNumber++)
{
fieldInfo.GetFieldType(fieldNumber, fieldType);
fieldInfo.GetFieldName(fieldNumber, fieldName);
attrQueryRow.IsNull(fieldName, isNull);
if (!isNull)
{
switch (fieldType)
{
case fieldTypeSmallInteger:
attrQueryRow.GetShort(fieldName, shortField);
wcout <<  shortField << endl;
break;
case fieldTypeInteger:
attrQueryRow.GetInteger(fieldName, longField);
wcout << longField << '\t';
break;
case fieldTypeSingle:
attrQueryRow.GetFloat(fieldName, floatField);
wcout << floatField << '\t';
break;
case fieldTypeDouble:
attrQueryRow.GetDouble(fieldName, doubleField);
wcout << doubleField << '\t';
break;
case fieldTypeString:
attrQueryRow.GetString(fieldName, wstringField);
wcout << wstringField << '\t';
break;
case fieldTypeDate:
attrQueryRow.GetDate(fieldName, dateTimeField);
strftime(datetime,80,"%a %b %d %I:%M:%S%p %Y", &dateTimeField);
wcout << datetime << '\t';
break;
case fieldTypeOID:
attrQueryRow.GetOID(longField);
wcout << longField << '\t';
break;
case fieldTypeGeometry:{
attrQueryRow.GetGeometry(geometry);
// attrQueryRow.GetBinary(fieldName, bss);
double x, y;
shapeBufferBytes = geometry.shapeBuffer;
wcout << "d::x::"<< x<<"y:"<<y<< '\t';;
wcout <<shapeBufferBytes<< "Geometry" << '\t';}
break;
case fieldTypeBlob:
wcout << "Blob" << '\t';
break;
case fieldTypeGUID:
attrQueryRow.GetGUID(fieldName, guidField);
guidField.ToString(strGuid);
wcout << strGuid << '\t';
break;
case fieldTypeGlobalID:
attrQueryRow.GetGlobalID(globalIDField);
globalIDField.ToString(strGlobalID);
wcout << strGlobalID << '\t';
break;
default:
break;
}
}
else
{
wcout << "null" << '\t';
}
}
wcout << endl;
}
attrQueryRows.Close(); // Close the EnumRows
*/
const char * pat="zhy好棒呀 第一个东东出来了";
//定义java String类 strClass  
jclass strClass = (env)->FindClass("Ljava/lang/String;");  
//获取String(byte[],String)的构造器,用于将本地byte[]数组转换为一个新String  
jmethodID ctorID = (env)->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");  
//建立byte数组  
jbyteArray bytes = (env)->NewByteArray(strlen(pat));  
//将char* 转换为byte数组  
(env)->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);  
// 设置String, 保存语言类型,用于byte数组转换至String时的参数  
jstring encoding = (env)->NewStringUTF("GB2312");   
//将byte数组转换为java String,并输出  
return (jstring)(env)->NewObject(strClass, ctorID, bytes, encoding);  
//return path;
}
JNIEXPORT void JNICALL Java_HelloJNI_getFileGdb(JNIEnv *env, jobject thisObj, jstring path) {
fgdbError hr;
wstring errorText;
Geodatabase geodatabase;
// const wchar_t * szStr =(wchar_t * )env->GetStringChars(path, NULL);
std::wstring value;
const jchar* raw = env->GetStringChars(path, NULL);
if (raw != NULL) {
jsize len = env->GetStringLength(path);
value.assign(raw, raw + len);
env->ReleaseStringChars(path, raw);
}
if ((hr = OpenGeodatabase(value, geodatabase)) != S_OK)
{
wcout << "An error occurred while opening the geodatabase." << endl;
ErrorInfo::GetErrorDescription(hr, errorText);
wcout << errorText << "(" << hr << ")." << endl;
return;
}
wstring sqlStatement(L"SELECT CITY_NAME, POP1990 FROM Cities WHERE TYPE = 'city' AND OBJECTID < 10");
EnumRows attrQueryRows;
if ((hr = geodatabase.ExecuteSQL(sqlStatement, true, attrQueryRows)) != S_OK)
{
wcout << "An error occurred while performing the attribute query." << endl;
ErrorInfo::GetErrorDescription(hr, errorText);
wcout << errorText << "(" << hr << ")." << endl;
return ;
}
// Iterate through the returned rows.
Row     attrQueryRow;
int32   cityPop;
wstring cityName;
while (attrQueryRows.Next(attrQueryRow) == S_OK)
{
attrQueryRow.GetInteger(L"POP1990", cityPop);
attrQueryRow.GetString(L"CITY_NAME", cityName);
wcout << cityName << '\t' << cityPop << endl;
}
// SELECT * - Return all fields.
sqlStatement.assign(L"SELECT * FROM Cities WHERE TYPE = 'city' AND OBJECTID < 10");
if ((hr = geodatabase.ExecuteSQL(sqlStatement, true, attrQueryRows)) != S_OK)
{
wcout << "An error occurred while performing the attribute query." << endl;
ErrorInfo::GetErrorDescription(hr, errorText);
wcout << errorText << "(" << hr << ")." << endl;
return;
}
// Get the field type and name from the row enumerator.
FieldInfo fieldInfo;
attrQueryRows.GetFieldInformation(fieldInfo);
int       fieldCount;
FieldType fieldType;
wstring   fieldName;
// Iterate through the returned rows printing out all field values.
short     shortField;
int32     longField;
float     floatField;
double    doubleField;
string    stringField;
wstring   wstringField;
tm        dateTimeField;
char      datetime[80];
Guid      globalIDField;
Guid      guidField;
wstring   strGuid;
wstring   strGlobalID;
bool      isNull;
byte * shapeBufferBytes ;
ShapeBuffer geometry;
while (attrQueryRows.Next(attrQueryRow) == S_OK)
{
fieldInfo.GetFieldCount(fieldCount);
for (long fieldNumber = 0; fieldNumber < fieldCount; fieldNumber++)
{
fieldInfo.GetFieldType(fieldNumber, fieldType);
fieldInfo.GetFieldName(fieldNumber, fieldName);
attrQueryRow.IsNull(fieldName, isNull);
if (!isNull)
{
switch (fieldType)
{
case fieldTypeSmallInteger:
attrQueryRow.GetShort(fieldName, shortField);
wcout <<  shortField << endl;
break;
case fieldTypeInteger:
attrQueryRow.GetInteger(fieldName, longField);
wcout << longField << '\t';
break;
case fieldTypeSingle:
attrQueryRow.GetFloat(fieldName, floatField);
wcout << floatField << '\t';
break;
case fieldTypeDouble:
attrQueryRow.GetDouble(fieldName, doubleField);
wcout << doubleField << '\t';
break;
case fieldTypeString:
attrQueryRow.GetString(fieldName, wstringField);
wcout << wstringField << '\t';
break;
case fieldTypeDate:
attrQueryRow.GetDate(fieldName, dateTimeField);
strftime(datetime,80,"%a %b %d %I:%M:%S%p %Y", &dateTimeField);
wcout << datetime << '\t';
break;
case fieldTypeOID:
attrQueryRow.GetOID(longField);
wcout << longField << '\t';
break;
case fieldTypeGeometry:{
attrQueryRow.GetGeometry(geometry);
// attrQueryRow.GetBinary(fieldName, bss);
double x, y;
shapeBufferBytes = geometry.shapeBuffer;
memcpy(&x, geometry.shapeBuffer + 4, sizeof(x));
memcpy(&y, geometry.shapeBuffer + 12, sizeof(y));
//std::string *str3 = new std::string((char *)shapeBufferBytes);
wcout << "d::x::"<< x<<"y:"<<y<< '\t';;
wcout <<shapeBufferBytes<< "Geometry" << '\t';}
  break;
case fieldTypeBlob:
wcout << "Blob" << '\t';
break;
case fieldTypeGUID:
attrQueryRow.GetGUID(fieldName, guidField);
guidField.ToString(strGuid);
wcout << strGuid << '\t';
break;
case fieldTypeGlobalID:
attrQueryRow.GetGlobalID(globalIDField);
globalIDField.ToString(strGlobalID);
wcout << strGlobalID << '\t';
break;
default:
break;
}
}
else
{
wcout << "null" << '\t';
}
}
wcout << endl;
}
attrQueryRows.Close(); // Close the EnumRows
// Close the geodatabase
if ((hr = CloseGeodatabase(geodatabase)) != S_OK)
{
wcout << "An error occurred while closing the geodatabase." << endl;
ErrorInfo::GetErrorDescription(hr, errorText);
wcout << errorText << "(" << hr << ")." << endl;
return ;
}
printf("Hello World  geodatebase!\n");
return;
}
std::string jstring2str(JNIEnv* env, jstring jstr)  
{     
    char*   rtn   =   NULL;     
    jclass   clsstring   =   env->FindClass("java/lang/String");     
    jstring   strencode   =   env->NewStringUTF("GB2312");     
    jmethodID   mid   =   env->GetMethodID(clsstring,   "getBytes",   "(Ljava/lang/String;)[B");     
    jbyteArray   barr=   (jbyteArray)env->CallObjectMethod(jstr,mid,strencode);     
    jsize   alen   =   env->GetArrayLength(barr);     
    jbyte*   ba   =   env->GetByteArrayElements(barr,JNI_FALSE);     
    if(alen   >   0)     
    {     
        rtn   =   (char*)malloc(alen+1);           
        memcpy(rtn,ba,alen);     
        rtn[alen]=0;     
    }     
    env->ReleaseByteArrayElements(barr,ba,0);     
    std::string stemp(rtn);  
    free(rtn);  
    return   stemp;     
}  
jstring str2jstring(JNIEnv* env,const char* pat)  
{  
    //定义java String类 strClass  
    jclass strClass = (env)->FindClass("Ljava/lang/String;");  
    //获取String(byte[],String)的构造器,用于将本地byte[]数组转换为一个新String  
    jmethodID ctorID = (env)->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");  
    //建立byte数组  
    jbyteArray bytes = (env)->NewByteArray(strlen(pat));  
    //将char* 转换为byte数组  
    (env)->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);  
    // 设置String, 保存语言类型,用于byte数组转换至String时的参数  
    jstring encoding = (env)->NewStringUTF("GB2312");   
    //将byte数组转换为java String,并输出  
    return (jstring)(env)->NewObject(strClass, ctorID, bytes, encoding);  
}  
JNIEXPORT jobject JNICALL Java_HelloJNI_getGdbTable(JNIEnv *env, jobject obj,jobject _GeodbEntity){
const char * dd="4096";
//jclass userClass = env->FindClass("GeodbEntity");  
jclass userClass=env->GetObjectClass(_GeodbEntity); 
//jmethodID userMethod = env->GetMethodID(userClass,"<init>","()V"); 
//jobject userObject = env->NewObject(userClass,userMethod);  
//jmethodID construction_id = env->GetMethodID(userClass, "<init>", "()V"); 
//得到构造方法的ID
    //jobject userObject = env->NewObject(userClass, construction_id); 
//jobject   userObject = env->AllocObject(userClass);     
//
//jmethodID setName_method=env->GetMethodID(userClass,"setSrid","(Ljava/lang/String;)V");
//env->CallVoidMethod(userObject,setName_method,dd);
   //jclass objectClass = (env)->FindClass("GeodbEntity
     jmethodID methodId=env->GetMethodID(userClass,"getTable","()Ljava/lang/String;");
 //调用customer对象的特定方法getName
       jstring js_name=(jstring)env->CallObjectMethod(_GeodbEntity,methodId,NULL);
   //jfieldID table = (env)->GetFieldID(userClass,"table","Ljava/lang/String;");
//jchar dd=(env)->GetCharField(userClass,table);
   //std::string value;
//const jchar* raw = env->GetStringChars(js_name, NULL);
//if (raw != NULL) {
//jsize len = env->GetStringLength(js_name);
//value.assign(raw, raw + len);
//env->ReleaseStringChars(js_name, raw);
//}
cout<<jstring2str(env,js_name)<<endl;
   jfieldID str = (env)->GetFieldID(userClass,"srid","Ljava/lang/String;");
  (env)->SetObjectField(_GeodbEntity,str,(env)->NewStringUTF(dd));
   //获取arraylist 类
   jclass cls_ArrayList = env->FindClass("java/util/ArrayList");
//获得arraylist id
        jmethodID construct = env->GetMethodID(cls_ArrayList,"<init>","()V");  
//创建arraylist
        jobject obj_ArrayList = env->NewObject(cls_ArrayList,construct); 
//获取 arraylist 的add 方法
        jmethodID arrayList_add = env->GetMethodID(cls_ArrayList,"add","(Ljava/lang/Object;)Z");  
for(int i=0;i<10;i++){
jobject alistadd = (env)->NewStringUTF("my name is D:"+i); 
//通过 add 方法 添加数据到 arraylist中
env->CallObjectMethod(obj_ArrayList,arrayList_add,alistadd);  
}
jfieldID str1 = (env)->GetFieldID(userClass,"FieldValues","Ljava/util/ArrayList;");
  (env)->SetObjectField(_GeodbEntity,str1,obj_ArrayList);
return _GeodbEntity;
}



posted @ 2013-12-30 14:18 brock 阅读(215) | 评论 (0)编辑 收藏

-环境的搭建,下载与安装LIBXML2和ICONV

          Libxml2是一个C语言的XML程序库,可以简单方便的提供对XML文档的各种操作,并且支持XPATH查询,以及部分的支持XSLT转换等功能。Libxml2的下载地址是http://xmlsoft.org/downloads.html,完全版的库是开源的,并且带有例子程序和说明文档。完全版的文件名为:libxml2-2.7.8.tar.gz。

          Libxml2中默认的内码是UTF-8,所有使用libxml2进行处理的xml文件,必须首先显式或者默认的转换为UTF-8编码才能被处理。
要在xml中使用中文,就必须能够在UTF-8和GB2312内码(较常用的一种简体中文编码)之间进行转换。Libxml2提供了默认的内码转换机制,并且在libxml2的Tutorial中有一个例子,事实证明这个例子并不适合用来转换中文。所以需要我们显式的使用ICONV来进行内码转换,libxml2本身也是ICONV使用进行转换的。ICONV是一个专门用来进行编码转换的库,基本上支持目前所有常用的编码。它是glibc库的一个部分,常常被用于UNIX系统中。当然,在windows下面使用也没有任何问题。

其下载地址是http://gnuwin32.sourceforge.net/packages/libiconv.htm,文件名为libiconv-1.9.2-1-lib.zip。

          将libiconv-1.9.2-1-lib.zip解压,将其中的iconv.h放入C:\opt\include目录中,将其中的libiconv.lib放入C:\opt\lib中,并改名为iconv.lib.(没有opt目录就新建一个)。

          解压libxml2-2.7.8.tar.gz文件到C盘根目录,在c:\libxml2-2.7.8\libxml2-2.7.8\win32目录中存放了多个Windows平台编译器的Makefile文件,我们使用vs2008,所以待会会用Makefile.msvc文件。

1.进入Visual Studio 2008 Command Prompt;

2.cd c:\libxml2-2.7.8\libxml2-2.7.8\win32

3.输入cscript configure.js compiler=msvc prefix=c:\opt  include=c:\opt\include lib=c:\opt\lib debug=yes,回车执行。

4.最后使用nmake命令进行编译,输入nmake /f Makefile.msvc并回车。

此时会出现一下错误提示,

Makefile.msvc(465) : fatal error U1020: end-of-file found before next directive
Stop.

网上找了下原因,原来是Makefile.msvc中存在错误。

+!if "$(WITH_ICU)" == "1"
+LIBS = $(LIBS) icu.lib
+!endif

将以上三行前面的+号都删掉,重新执行nmake即可。

在当前win32目录中生成了一个bin.msvc目录,其中就有开发需要的libxml2.lib和libxml2.dll文件。

posted @ 2013-12-25 14:49 brock 阅读(220) | 评论 (0)编辑 收藏

Visual Studio Ultimate 2012Visual Studio Ultimate 2012 静态激活密钥,有兴趣的可以试一下。

RBCXF-CVBGR-382MK-DFHJ4-C69G8
posted @ 2013-12-17 11:07 brock 阅读(174) | 评论 (0)编辑 收藏

1、创建索引   
-------------------------------------------------------------------------------------------
GeohashPrefixTree grid = new GeohashPrefixTree(ctx, 12);//< 1 meter == 11 maxLevels
        this.strategy = new RecursivePrefixTreeStrategy(grid, "shape");
        ((RecursivePrefixTreeStrategy) this.strategy).setDistErrPct(LUCENE_4464_distErrPct);//1% radius (small!)

 String wktstr = clobtoString(map.get("wkt"));//图形信息
                String objectid = map.get("objectid").toString();//对象id
                String name = map.get("name").toString();//对象名称
                Shape shape = wktGeoRect(wktstr);
                Document doc = new Document();
                doc.add(new StringField("objectidtable", objectid + tableName, Field.Store.YES));
                doc.add(new StringField("objectid", objectid, Field.Store.YES));
                doc.add(new StringField("tableName", tableName, Field.Store.YES));
                doc.add(new StringField("metadataid", mid.toString(), Field.Store.YES));
                doc.add(new TextField ("title", name, Field.Store.YES));
                if (shape != null) {
                    for (Field f : strategy.createIndexableFields(shape)) {
                        doc.add(f);
                    }
                    doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
                }
  indexWriter.addDocument(doc);
---------------------------------------------------------------
    public Shape wktGeoRect(String wktStr) {
        JtsGeometry jtsGeom = null;
        try {
            if (StringUtils.trim(wktStr.substring(0, wktStr.indexOf("("))).equalsIgnoreCase("POINT")) {
                wktStr = wktStr.substring(wktStr.indexOf("(") + 1, wktStr.lastIndexOf(")"));
                String[] point = wktStr.split(" ");
                return ctx.makePoint(Double.parseDouble(point[0]), Double.parseDouble(point[1]));
            } else {
                jtsGeom = (JtsGeometry) ctx.readShape(wktStr);
            }
        } catch (Exception e) {
        }
        return jtsGeom;
    }
2、查询空间索引

   @Test
    public void testshape() throws Exception {
                JtsSpatialContext ctx = JtsSpatialContext.GEO;
        Directory directory = new SimpleFSDirectory(new File("D:/platform/spatiallucence"));
        IndexReader[] indexReaders1 = new IndexReader[]{IndexReader.open(directory)};
        MultiReader multiReader = new MultiReader(indexReaders1);
        indexSearcher = new IndexSearcher(multiReader);
        indexSearcher.setSimilarity(new NoScoreSimilarity());
        GeohashPrefixTree grid = new GeohashPrefixTree(ctx, 12);//< 1 meter == 11 maxLevels
        strategy = new RecursivePrefixTreeStrategy(grid, "shape");
        ((RecursivePrefixTreeStrategy) strategy).setDistErrPct(0.025);//1% radius (small!)
        //POINT (121.591953019118 28.7566972164043)
        //Shape shape = ctx.readShape("POINT (121.454715099823 28.860595871703)");
        Shape shape = ctx.readShape("POLYGON(" +
                "(121.10836126349 28.84450508816,\n" +
                "121.12569906256 28.84450508816,\n" +
                "121.12569906256 28.856950537989,\n" +
                "121.10836126349 28.856950537989,\n" +
                "121.10836126349 28.84450508816))");
        shape = ctx.makeRectangle(121.10836126349d ,121.12569906256d, 28.84450508816d ,28.856950537989d);
        SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, shape);
        args.setDistErrPct(0.025);
        Query query = strategy.makeQuery(args);
        TopDocs results = indexSearcher.search(query, 1000);
        int numTotalHits = results.totalHits;
        System.out.println("共 " + numTotalHits + " 完全匹配的文档");
        ScoreDoc[] hits = results.scoreDocs;
        for (int i = 0; i < hits.length; i++) {
            Document document = indexSearcher.doc(hits[i].doc);
            System.out.println("Id: " + document);
        }
    }

posted @ 2013-11-29 16:15 brock 阅读(693) | 评论 (0)编辑 收藏

ext grid 删除最后一行数据后还是显示

grid删除最后一行数据后,store reload ,因为数据库中已经没有数据了,所以返回null .

但是ext不认这个东西,所以在service中进行判断。如果数据为null ,则返回

"{total:0,gridData:[]}" ;

重新编译,运行后,删除最后一行数据,就会看不到了。

posted @ 2013-10-24 10:40 brock 阅读(248) | 评论 (0)编辑 收藏


一.问题的提出

/usr/local/webserver/mysql/bin/mysql -u root -h 172.29.141.112  -p -S /tmp/mysql.sock
Enter password: 
ERROR 2003 (HY000): Can't connect to MySQL server on '172.29.141.112' (113)

二.问题的分析

 

出现上述问题,可能有以下几种可能

 

1. my.cnf 配置文件中 skip-networking 被配置

skip-networking 这个参数,导致所有TCP/IP端口没有被监听,也就是说出了本机,其他客户端都无法用网络连接到本mysql服务器

所以需要把这个参数注释掉。

 

2.my.cnf配置文件中 bindaddress 的参数配置

bindaddress,有的是bind-address  ,这个参数是指定哪些ip地址被配置,使得mysql服务器只回应哪些ip地址的请求,所以需要把这个参数注释掉。

 

3.防火墙的原因

通过 /etc/init.d/iptables  stop  关闭防火墙

我的问题,就是因为这个原因引起的。关闭mysql 服务器的防火墙就可以使用了。

 

三.问题的解决

1.  如果是上述第一个原因,那么 找到 my.cnf  ,注释掉 skip-networking 这个参数

sed -i  's%skip-networking%#skip-networking%g'  my.cnf

 

2. 如果是上述第二个原因,那么  找到 my.cnf  ,注释掉 bind-address  这个参数

sed -i  's%bind-address%#bind-address%g'    my.cnf

sed -i  's%bindaddress%#bindaddress%g'      my.cnf

 

最好修改完查看一下,这个参数。

 

3.如果是上述第三个原因,那么 把防火墙关闭,或者进行相应配置

 

/etc/init.d/iptables stop

 

四.参考

http://hi.baidu.com/vbkan/blog/item/cd5035030cefee793812bb56.html

http://dev.firnow.com/course/7_databases/mysql/myxl/20090820/169010.html

http://www.dnbcw.com/biancheng/sql/lojz182597.html

posted @ 2013-10-08 10:34 brock 阅读(209) | 评论 (0)编辑 收藏

  private static double getCpuRateForLinux(){
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader brStat = null;
        StringTokenizer tokenStat = null;
        try{
            System.out.println("Get usage rate of CUP , linux version: "+linuxVersion);
            Process process = Runtime.getRuntime().exec("top -b -n 1");
            is = process.getInputStream();
            isr = new InputStreamReader(is);
            brStat = new BufferedReader(isr);
            if(linuxVersion.equals("2.4")){
                brStat.readLine();
                brStat.readLine();
                brStat.readLine();
                brStat.readLine();
                tokenStat = new StringTokenizer(brStat.readLine());
                tokenStat.nextToken();
                tokenStat.nextToken();
                String user = tokenStat.nextToken();
                tokenStat.nextToken();
                String system = tokenStat.nextToken();
                tokenStat.nextToken();
                String nice = tokenStat.nextToken();
                System.out.println(user+" , "+system+" , "+nice);
                user = user.substring(0,user.indexOf("%"));
                system = system.substring(0,system.indexOf("%"));
                nice = nice.substring(0,nice.indexOf("%"));
                float userUsage = new Float(user).floatValue();
                float systemUsage = new Float(system).floatValue();
                float niceUsage = new Float(nice).floatValue();
                return (userUsage+systemUsage+niceUsage)/100;
            }else{
                brStat.readLine();
                brStat.readLine();
                tokenStat = new StringTokenizer(brStat.readLine());
                tokenStat.nextToken();
                tokenStat.nextToken();
                tokenStat.nextToken();
                tokenStat.nextToken();
                tokenStat.nextToken();
                tokenStat.nextToken();
                tokenStat.nextToken();
                String cpuUsage = tokenStat.nextToken();
                System.out.println("CPU idle : "+cpuUsage);
                Float usage = new Float(cpuUsage.substring(0,cpuUsage.indexOf("%")));
                return (1-usage.floatValue()/100);
            }
        } catch(IOException ioe){
            System.out.println(ioe.getMessage());
            freeResource(is, isr, brStat);
            return 1;
        } finally{
            freeResource(is, isr, brStat);
        }
    }
    private static void freeResource(InputStream is, InputStreamReader isr, BufferedReader br){
        try{
            if(is!=null)
                is.close();
            if(isr!=null)
                isr.close();
            if(br!=null)
                br.close();
        }catch(IOException ioe){
            System.out.println(ioe.getMessage());
        }
    }
    /**
     * 获得CPU使用率.   
     * @return 返回cpu使用率
     * @author GuoHuang
     */
    private double getCpuRatioForWindows() {
        try {
            String procCmd = System.getenv("windir")
                    + "\\system32\\wbem\\wmic.exe process get Caption,CommandLine,"
                    + "KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount";
            // 取进程信息    
            long[] c0 = readCpu(Runtime.getRuntime().exec(procCmd));
            Thread.sleep(CPUTIME);
            long[] c1 = readCpu(Runtime.getRuntime().exec(procCmd));
            if (c0 != null && c1 != null) {
                long idletime = c1[0] - c0[0];
                long busytime = c1[1] - c0[1];
                return Double.valueOf(
                        PERCENT * (busytime) / (busytime + idletime))
                        .doubleValue();
            } else {
                return 0.0;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            return 0.0;
        }
    }
    /**
     * 读取CPU信息.
     * @param proc
     * @return
     * @author GuoHuang
     */
    private long[] readCpu(final Process proc) {
        long[] retn = new long[2];
        try {
            proc.getOutputStream().close();
            InputStreamReader ir = new InputStreamReader(proc.getInputStream());
            LineNumberReader input = new LineNumberReader(ir);
            String line = input.readLine();
            if (line == null || line.length() < FAULTLENGTH) {
                return null;
            }
            int capidx = line.indexOf("Caption");
            int cmdidx = line.indexOf("CommandLine");
            int rocidx = line.indexOf("ReadOperationCount");
            int umtidx = line.indexOf("UserModeTime");
            int kmtidx = line.indexOf("KernelModeTime");
            int wocidx = line.indexOf("WriteOperationCount");
            long idletime = 0;
            long kneltime = 0;
            long usertime = 0;
            while ((line = input.readLine()) != null) {
                if (line.length() < wocidx) {
                    continue;
                }
                // 字段出现顺序:Caption,CommandLine,KernelModeTime,ReadOperationCount,    
                // ThreadCount,UserModeTime,WriteOperation    
                String caption = Bytes.substring(line, capidx, cmdidx - 1)
                        .trim();
                String cmd = Bytes.substring(line, cmdidx, kmtidx - 1).trim();
                if (cmd.indexOf("wmic.exe") >= 0) {
                    continue;
                }
                // log.info("line="+line);    
                if (caption.equals("System Idle Process")
                        || caption.equals("System")) {
                    idletime += Long.valueOf(
                            Bytes.substring(line, kmtidx, rocidx - 1).trim())
                            .longValue();
                    idletime += Long.valueOf(
                            Bytes.substring(line, umtidx, wocidx - 1).trim())
                            .longValue();
                    continue;
                }
                kneltime += Long.valueOf(
                        Bytes.substring(line, kmtidx, rocidx - 1).trim())
                        .longValue();
                usertime += Long.valueOf(
                        Bytes.substring(line, umtidx, wocidx - 1).trim())
                        .longValue();
            }
            retn[0] = idletime;
            retn[1] = kneltime + usertime;
            return retn;
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            try {
                proc.getInputStream().close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
上面方法不行,下面的可以
  String result = "";
        try {
            File file = File.createTempFile("tmp", ".vbs");
            file.deleteOnExit();
            FileWriter fw = new java.io.FileWriter(file);
            String vbs ="Set objProc = GetObject(\"winmgmts:\\\\.\\root\\cimv2:win32_processor='cpu0'\")\n" +
                    "WScript.Echo  \"CPU Load Percentage: \"& chr(13) & chr(10) & Round(objProc.LoadPercentage,2) & \"%\"";
            fw.write(vbs);
            fw.close();
            Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath());
            BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line;
            while ((line = input.readLine()) != null) {
                result += line;
            }
            input.close();
            file.delete();
        } catch (Exception e) {
            e.fillInStackTrace();
        }
        if (result.trim().length() < 1 || result == null) {
        }else{
            System.out.println(result.trim());
        }




posted @ 2013-08-19 10:40 brock 阅读(712) | 评论 (0)编辑 收藏

#encoding=UTF-8
# Configuration files must begin with a line specifying the encoding
#  of the the file.
#********************************************************************
# Wrapper License Properties (Ignored by Community Edition)
#********************************************************************
# Professional and Standard Editions of the Wrapper require a valid
#  License Key to start.  Licenses can be purchased or a trial license
#  requested on the following pages:
# http://wrapper.tanukisoftware.com/purchase
# http://wrapper.tanukisoftware.com/trial
# Include file problems can be debugged by removing the first '#'
#  from the following line:
##include.debug
# The Wrapper will look for either of the following optional files for a
#  valid License Key.  License Key properties can optionally be included
#  directly in this configuration file.
#include ../conf/wrapper-license.conf
#include ../conf/wrapper-license-%WRAPPER_HOST_NAME%.conf
# The following property will output information about which License Key(s)
#  are being found, and can aid in resolving any licensing problems.
#wrapper.license.debug=TRUE
#********************************************************************
# Wrapper Localization
#********************************************************************
# Specify the locale which the Wrapper should use.  By default the system
#  locale is used.
#wrapper.lang=en_US # en_US or ja_JP
# Specify the location of the Wrapper's language resources.  If these are
#  missing, the Wrapper will default to the en_US locale.
wrapper.lang.folder=../lang
#********************************************************************
# Wrapper Java Properties
#********************************************************************
# Java Application
#  Locate the java binary on the system PATH:
wrapper.java.command=java
#  Specify a specific java binary:
#set.JAVA_HOME=/java/path
set.LIB=D:/MonitorApp/lib
#wrapper.java.command=%JAVA_HOME%/bin/java
# Tell the Wrapper to log the full generated Java command line.
#wrapper.java.command.loglevel=INFO
# Java Main class.  This class must implement the WrapperListener interface
#  or guarantee that the WrapperManager class is initialized.  Helper
#  classes are provided to do this for you.  See the Integration section
#  of the documentation for details.
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
# Java Classpath (include wrapper.jar)  Add class path elements as
#  needed starting from 1
echo %LIB%
wrapper.java.classpath.1=%LIB%/wrapper.jar
wrapper.java.classpath.2=%LIB%/commons-beanutils-1.8.3.jar
wrapper.java.classpath.3=%LIB%/commons-codec-1.4.jar
wrapper.java.classpath.4=%LIB%/commons-collections-3.1.jar
wrapper.java.classpath.5=%LIB%/commons-collections-3.2.1.jar
wrapper.java.classpath.6=%LIB%/commons-dbcp-1.3.jar
wrapper.java.classpath.7=%LIB%/commons-dbcp-1.4.jar
wrapper.java.classpath.8=%LIB%/commons-fileupload-1.2.1.jar
wrapper.java.classpath.9=%LIB%/commons-httpclient-3.0.1.jar
wrapper.java.classpath.10=%LIB%/commons-io-1.4.jar
wrapper.java.classpath.11=%LIB%/commons-io-2.0.1.jar
wrapper.java.classpath.12=%LIB%/commons-jexl-1.1.jar
wrapper.java.classpath.13=%LIB%/commons-lang-2.5.jar
wrapper.java.classpath.14=%LIB%/commons-logging-1.1.1.jar
wrapper.java.classpath.15=%LIB%/commons-logging-api-1.1.jar
wrapper.java.classpath.16=%LIB%/commons-management-1.0.jar
wrapper.java.classpath.17=%LIB%/commons-pool-1.5.4.jar
wrapper.java.classpath.18=%LIB%/jedis-2.0.0.jar
wrapper.java.classpath.19=%LIB%/log4j-1.2.14.jar
wrapper.java.classpath.20=%LIB%/quartz-all-1.6.3.jar
wrapper.java.classpath.21=%LIB%/spring-aop-3.0.2.RELEASE.jar
wrapper.java.classpath.22=%LIB%/spring-asm-3.0.2.RELEASE.jar
wrapper.java.classpath.23=%LIB%/spring-beans-3.0.2.RELEASE.jar
wrapper.java.classpath.24=%LIB%/spring-binding-2.0.8.RELEASE.jar
wrapper.java.classpath.25=%LIB%/spring-context-3.0.2.RELEASE.jar
wrapper.java.classpath.26=%LIB%/spring-context-support-3.0.2.RELEASE.jar
wrapper.java.classpath.27=%LIB%/spring-core-3.0.2.RELEASE.jar
wrapper.java.classpath.28=%LIB%/spring-expression-3.0.2.RELEASE.jar
wrapper.java.classpath.29=%LIB%/springside-3.3.2.jar
wrapper.java.classpath.30=%LIB%/spring-test-3.0.2.RELEASE.jar
wrapper.java.classpath.31=%LIB%/spring-tx-3.0.2.RELEASE.jar
wrapper.java.classpath.32=%LIB%/slf4j-api-1.5.8.jar
wrapper.java.classpath.33=%LIB%/slf4j-log4j12-1.5.8.jar
wrapper.java.classpath.34=%LIB%/monitor.jar
wrapper.java.classpath.35=%LIB%   #可以读到这里的文件 xml pro 等       
# Java Library Path (location of Wrapper.DLL or libwrapper.so)
wrapper.java.library.path.1=../bin
# Java Bits.  On applicable platforms, tells the JVM to run in 32 or 64-bit mode.
wrapper.java.additional.auto_bits=TRUE
# Java Additional Parameters
wrapper.java.additional.1=-Dlog4j.configuration=file:%LIB%/log4j.xml
wrapper.java.additional.2=-Dorg.tanukisoftware.wrapper.WrapperManager.mbean=TRUE
# Initial Java Heap Size (in MB)
wrapper.java.initmemory=128
# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=512
# Application parameters.  Add parameters as needed starting from 1
wrapper.app.parameter.1=com.zjasm.tomcat.TomcatStat
#********************************************************************
# Wrapper Logging Properties
#********************************************************************
# Enables Debug output from the Wrapper.
#wrapper.debug=TRUE
# Format of output for the console.  (See docs for formats)
wrapper.console.format=PM
# Log Level for console output.  (See docs for log levels)
wrapper.console.loglevel=INFO
# Log file to use for wrapper output logging.
wrapper.logfile=../logs/wrapper.log
# Format of output for the log file.  (See docs for formats)
wrapper.logfile.format=LPTM
# Log Level for log file output.  (See docs for log levels)
wrapper.logfile.loglevel=INFO
# Maximum size that the log file will be allowed to grow to before
#  the log is rolled. Size is specified in bytes.  The default value
#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=0
# Maximum number of rolled log files which will be allowed before old
#  files are deleted.  The default value of 0 implies no limit.
wrapper.logfile.maxfiles=0
# Log Level for sys/event log output.  (See docs for log levels)
wrapper.syslog.loglevel=NONE
#********************************************************************
# Wrapper General Properties
#********************************************************************
# Allow for the use of non-contiguous numbered properties
wrapper.ignore_sequence_gaps=TRUE
# Do not start if the pid file already exists.
wrapper.pidfile.strict=TRUE
# Title to use when running as a console
wrapper.console.title=Test Wrapper Sample Application
#********************************************************************
# Wrapper JVM Checks
#********************************************************************
# Detect DeadLocked Threads in the JVM. (Requires Standard Edition)
wrapper.check.deadlock=TRUE
wrapper.check.deadlock.interval=10
wrapper.check.deadlock.action=RESTART
wrapper.check.deadlock.output=FULL
# Out Of Memory detection.
# (Ignore output from dumping the configuration to the console.  This is only needed by the TestWrapper sample application.)
wrapper.filter.trigger.999=wrapper.filter.trigger.*java.lang.OutOfMemoryError
wrapper.filter.allow_wildcards.999=TRUE
wrapper.filter.action.999=NONE
#  Ignore -verbose:class output to avoid false positives.
wrapper.filter.trigger.1000=[Loaded java.lang.OutOfMemoryError
wrapper.filter.action.1000=NONE
# (Simple match)
wrapper.filter.trigger.1001=java.lang.OutOfMemoryError
# (Only match text in stack traces if -XX:+PrintClassHistogram is being used.)
#wrapper.filter.trigger.1001=Exception in thread "*" java.lang.OutOfMemoryError
#wrapper.filter.allow_wildcards.1001=TRUE
wrapper.filter.action.1001=RESTART
wrapper.filter.message.1001=The JVM has run out of memory.
#********************************************************************
# Wrapper Email Notifications. (Requires Professional Edition)
#********************************************************************
# Common Event Email settings.
#wrapper.event.default.email.debug=TRUE
#wrapper.event.default.email.smtp.host=<SMTP_Host>
#wrapper.event.default.email.smtp.port=25
#wrapper.event.default.email.subject=[%WRAPPER_HOSTNAME%:%WRAPPER_NAME%:%WRAPPER_EVENT_NAME%] Event Notification
#wrapper.event.default.email.sender=<Sender email>
#wrapper.event.default.email.recipient=<Recipient email>
# Configure the log attached to event emails.
#wrapper.event.default.email.attach_log=TRUE
#wrapper.event.default.email.maillog.lines=50
#wrapper.event.default.email.maillog.format=LPTM
#wrapper.event.default.email.maillog.loglevel=INFO
# Enable specific event emails.
#wrapper.event.wrapper_start.email=TRUE
#wrapper.event.jvm_prelaunch.email=TRUE
#wrapper.event.jvm_start.email=TRUE
#wrapper.event.jvm_started.email=TRUE
#wrapper.event.jvm_deadlock.email=TRUE
#wrapper.event.jvm_stop.email=TRUE
#wrapper.event.jvm_stopped.email=TRUE
#wrapper.event.jvm_restart.email=TRUE
#wrapper.event.jvm_failed_invocation.email=TRUE
#wrapper.event.jvm_max_failed_invocations.email=TRUE
#wrapper.event.jvm_kill.email=TRUE
#wrapper.event.jvm_killed.email=TRUE
#wrapper.event.jvm_unexpected_exit.email=TRUE
#wrapper.event.wrapper_stop.email=TRUE
# Specify custom mail content
wrapper.event.jvm_restart.email.body=The JVM was restarted.\n\nPlease check on its status.\n
#********************************************************************
# Wrapper Windows NT/2000/XP Service Properties
#********************************************************************
# WARNING - Do not modify any of these properties when an application
#  using this configuration file has been installed as a service.
#  Please uninstall the service before modifying this section.  The
#  service can then be reinstalled.
# Name of the service
wrapper.name=testwrapper
# Display name of the service
wrapper.displayname=Test Wrapper Sample Application
# Description of the service
wrapper.description=Test Wrapper Sample Application Description
# Service dependencies.  Add dependencies as needed starting from 1
wrapper.ntservice.dependency.1=
# Mode in which the service is installed.  AUTO_START, DELAY_START or DEMAND_START
wrapper.ntservice.starttype=AUTO_START
# Allow the service to interact with the desktop.
wrapper.ntservice.interactive=false
posted @ 2013-08-09 14:20 brock 阅读(264) | 评论 (0)编辑 收藏

步骤1、配置/etc/sysconfig/network-scripts/ifcfg-eth0 里的文件。it动力的CentOS下的ifcfg-eth0的配置详情:

[root@localhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth0

DEVICE="eth0"
HWADDR="00:0C:29:FD:FF:2A"
NM_CONTROLLED="yes"
ONBOOT="yes"
IPADDR=192.168.1.31
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
BOOTPROTO=static

前面三行是系统睚带的,后面就是手动添加的。
这样设置扣,记得重启网卡:
[root@localhost ~]# /etc/init.d/network stop
[root@localhost ~]# /etc/init.d/network start

行了,现在就可以PING得通网关了,如果还得上网,不必须设置DNS。设置DNS就详见步骤2

步骤2、修改dns
[root@localhost ~]# vi /etc/resolv.conf 
在里面添加二个dns:
nameserver 202.96.134.133
nameserver 8.8.8.8

ok,大攻告成,即可上网了!!!!

posted @ 2013-07-31 18:42 brock 阅读(217) | 评论 (0)编辑 收藏

 The VMware vSphere Web Services SDK includes all the components necessary to work with the VMware vSphere API, including WSDL files, sample code, and libraries. The vSphere Web Services SDK facilitates development of client applications that target the VMware vSphere API. With the vSphere Web Services SDK, developers can create client applications to manage, monitor, and maintain VMware vSphere components, as deployed on VMware®VMware vSphere®ESX®, ESXi™, and VMware®vCenter™ Server systems.

这是官方对vSphere Web Services SDK的介绍,简单来说就是提供了管理vcenter,ESXi的程序接口,目前支持JAVA和.NET平台,下面以windows 7平台为例,介绍JAVA开发环境的部署过程

一、开发环境准备

1、安装JAVA开发环境 J2SE 1.6 b22

http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-javase6-419409.html#jdk-6u22-oth-JPR

安装到c:\java下,不要安装到C:\program files下,目录中有空格,执行脚本的时候会报错

 

2、安装SOAP工具JAX-WS2.1

http://jax-ws.java.net/2.1.1/index.html

双击安装即可

 

3、下载vSphere Web Services SDK 5.1

http://communities.vmware.com/community/vmtn/developer/downloads

解压到c:\devprojects下

 

二、开发环境配置

1、设置系统变量

JAVA_HOME=C:\java\jdk1.6.0_22

JAVAHOME=C:\java\jdk1.6.0_22

SDKHOME=C:\devprojects

VMKEYSTORE=C:\VMware-Certs\vmware.keystore(稍后介绍安装过程)

WEBHOME=C:\devprojects\vsphere-ws\java\Axis\lib\wbem.jar

WS_SDK_HOME=C:\devprojects\SDK\vsphere-ws

CLASSPATH=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;C:\devprojects\SDK\vsphere-ws\java\JAXWS\lib\samples.jar;C:\devprojects\SDK\vsphere-ws\java\JAXWS\lib\vim25.jar(这个变量很重要)

 

2、服务器认证

2.1、将ESX Server或Vcenter的证书导入本机,ESXi的证书在/etc/vmware/ssl/rui.crt;Vcenter的证书在C:/Documents and Settings/All Users/Application Data/VMware/VMware VitualCenter/SSL/rui.crt

2.2、证书拷贝到本机的C:/VMware-Certs目录下,打开windows7的命令行界面,切换到C:/VMware-Certs目录下,使用jdk的keytool工具导入证书:

keytool -import -file <certificate-filename> -alias <server-name> -keystore vmware.keystore

其中certificate-filename为rui.crt,service-name可以为服务器的机器名或IP地址,运行成功后会在C:/VMware-Certs目录下生成vmware.keystore文件。

 

3、重新编译JAX-WS

如果你的安装的版本不是JDK 1.6 b22或者SOAP不是用 JAX-WS2.1,就需要重新编译

打开CMD,切换到C:\devprojects\SDK\vsphere-ws\java\JAXWS\

运行build.bat

运行成功会出现会出现

Generating stubs from wsdl
 
Compiling stubs.
...
Done
 
三、运行简单的客户端脚本以验证安装成功
 
打开CMD,切换到C:\devprojects\SDK\vsphere-ws\java\JAXWS\
 
run.bat com.vmware.general.SimpleClient --urlhttps://yourFQDNservername/sdk --username  username --password password,如下输出表示配置SDK成功
 
 
 
四、错误调试
1、如果出现找不到类的错误,ClassNotFoundException:........,可以这样
 
打开CMD,切换到C:\devprojects\SDK\vsphere-ws\java\JAXWS\
 
java -Djavax.net.ssl.trustStore=%VMKEYSTORE% com.vmware.general.SimpleClient--url https://example.com/sdk --username pubs --password ***
 
2、如果提示JAVA虚拟机的内存不够,可以这样
 
java -Djavax.net.ssl.trustStore=%VMKEYSTORE% -Xms 512M -XMx1024M com.vmware.general.SimpleClient--url https://example.com/sdk --username pubs --password ***
posted @ 2013-07-31 18:41 brock 阅读(879) | 评论 (0)编辑 收藏

BIND-DLZ实验:http://bind-dlz.sourceforge.net/
实验环境:RHEL4,BIND-9.5.0-P2.tar.gz(9.4.0以上版本都已含DLZ补丁),Mysql-5.0.56.tar.gz
1、安装mysql(先安装gcc等相关软件包)
   #tar zxvf mysql-5.0.56.tar.gz 
   #cd mysql-5.0.56
   #./configure --prefix=/usr/local/mysql --localstatedir=/usr/loal/mysql/data --   libexecdir=/usr/local/mysql/lib --disable-shared
   #make
   #make install
   #cd /usr/local/mysql/
   #groupadd -g 1003 mysql
   #useradd -g 1003 mysql
   #chown -R mysql .
   #chgrp -R mysql .
   #chown -R mysql lib
   #./bin/mysql_install_db --user=mysql //以mysql的用户身份安装
   #chown -R root .
   #./bin/mysqld_safe --user=mysql & //在后台启动mysql

# cd /root/mysql-5.0.56
# cp support-files/my-medium.cnf /etc/my.cnf
# cp support-files/mysql.server /etc/rc.d/init.d/mysqld
# chmod 700 !$
# chkconfig --add mysqld
# chkconfig --list mysqld
  mysqld 1:off 2:on 3:on 4:on 5:on 6:off
# service mysqld start[restart/reload/stop]
# vi /etc/my.cnf
 add this:(
防止mysql服务器无查询后8小时自动重连)
wait_timeout = 86400

interactive_timeout = 86400

   #/usr/local/mysql/bin/mysqladmin -uroot password 'aptech'
   #./bin/mysql -uroot -paptech
   #echo "PATH=$PATH:/usr/local/mysql/bin" >> /etc/profile
   #. !$
  
2、安装bind
   #tar zxvf bind-9.5.0-P2.tar.gz 
   #cd bind-9.5.0-P2
   #./configure --prefix=/usr/local/bind9 --with-dlz-mysql=/usr/local/mysql --enable-threads=no
   //--with-dlz-mysql=/usr/local/mysql 要求bind安装中支持DLZ
   //--enable-threads=no 关闭多线程 
   //--disable-openssl-version-check 禁止openssl版本的检查
   #make
   #make install

3、创建database,table
   create database mydata;
   use mydata;
   create table other_dns_records(
   zone varchar(255),
   host varchar(255),
   type varchar(255),
   data varchar(255),
   ttl int(11),
   mx_priority varchar(255), 
   refresh int(11),
   retry int(11),
   expire int(11),
   minimum int(11),
   serial bigint(11),
   resp_person varchar(255), 
   primary_ns varchar(255));
 
   create table cnc_dns_records(
   host varchar(255),
   type varchar(255),
   data varchar(255),
   ttl int(11),
   mx_priority varchar(255), 
   refresh int(11),
   retry int(11),
   expire int(11),
   minimum int(11),
   serial bigint(11),
   resp_person varchar(255), 
   primary_ns varchar(255));
  
   insert other_dns_records(zone,host,type,data,ttl,retry)
   values('aaa.com','www','A','192.168.199.2','86400','13');
   insert cnc_dns_records(zone,host,type,data,ttl,retry)
   values('bbb.com','www','A','192.55.199.199','86400','13');
4、编辑/usr/local/bind9/etc/named.conf
   #cd /usr/local/bind9/etc
   #../sbin/rndc-confgen -a
   #../sbin/rndc-confgen > named.conf
   #vi !$   //vi named.conf
   #less named.conf
 # Use with the following in named.conf, adjusting the allow list as needed:
 key "rndc-key" {
        algorithm hmac-md5;
        secret "c4aUV+N7GbOF773V+/LnAA==";
 };
 
 controls {
        inet 127.0.0.1 port 953
                allow { 127.0.0.1; } keys { "rndc-key"; };
 };
# End of named.conf
options {
directory "/usr/local/bind9/etc/";
pid-file "/usr/local/bind9/var/run/named.pid";
allow-query { any; };
recursion no;
version "gaint-d1";
};
include "/usr/local/bind9/etc/cnc.cl";
include "/usr/local/bind9/etc/other.cl";
view "cnc-user" {
match-clients { cnc; };
dlz "Mysql zone" {
database "mysql
{host=localhost dbname=mydata ssl=false port=3306 user=root pass=aptech}
{select zone from cnc_dns_records where zone = '%zone%'}
{select ttl, type, mx_priority, case when lower(type)='txt' then concat('/"', data, 
'/"')
when lower(type) = 'soa' then concat_ws('
', data, resp_person, serial, refresh, retry, expire, minimum) else data end as mydata from
cnc_dns_records where zone = '%zone%' and host = '%record%'}";
};
};
view "other-user" {
match-clients { other; };
dlz "Mysql zone" {
database "mysql
{host=localhost dbname=mydata ssl=false port=3306 user=root pass=aptech}
{select zone from other_dns_records where zone='%zone%'}
{select ttl, type, mx_priority, case when lower(type) = 'txt' then concat('/"', data, 
'/"')
when lower(type)='soa' then concat_ws('
', data, resp_person, serial, refresh, retry, expire, minimum) else data end as mydata from
other_dns_records where zone = '%zone%' and host = '%record%'}";
};
};
[root@dlz etc]# less cnc.cl 
acl "cnc"{
192.168.9.0/24;
};
[root@dlz etc]# less other.cl 
acl "other" {
127.0.0.0/18;
};
 
5、启动&测试
[root@dlz ~]# /usr/local/bind9/sbin/named -gc  /usr/local/bind9/etc/named.conf
06-Mar-2009 22:23:02.569 starting BIND 9.5.0-P2 -gc /usr/local/bind9/etc/named.conf
06-Mar-2009 22:23:02.579 loading configuration from '/usr/local/bind9/etc/named.conf'
06-Mar-2009 22:23:02.583 listening on IPv4 interface lo, 127.0.0.1#53
06-Mar-2009 22:23:02.586 listening on IPv4 interface eth0, 192.168.1.5#53
06-Mar-2009 22:23:02.588 Loading 'Mysql zone' using driver mysql
06-Mar-2009 22:23:02.604 default max-cache-size (33554432) applies: view cnc-user
06-Mar-2009 22:23:02.609 Loading 'Mysql zone' using driver mysql
06-Mar-2009 22:23:02.612 default max-cache-size (33554432) applies: view other-user
06-Mar-2009 22:23:02.616 default max-cache-size (33554432) applies: view _bind
06-Mar-2009 22:23:02.621 command channel listening on 127.0.0.1#953
06-Mar-2009 22:23:02.621 ignoring config file logging statement due to -g option
06-Mar-2009 22:23:02.623 running
posted @ 2013-07-31 18:40 brock 阅读(333) | 评论 (0)编辑 收藏

     摘要: Spring的事务管理难点剖析(7):数据连接泄漏底层连接资源的访问问题    对于应用开发者来说,数据连接泄漏无疑是一个可怕的梦魇。只要你开发的应用存在数据连接泄漏的问题,应用程序最终都将因数据连接资源的耗尽而崩溃,甚至还可能引起数据库的崩溃。数据连接泄漏像一个黑洞那样让开发者避之唯恐不及。    Spring DAO对所有支持的数据访...  阅读全文
posted @ 2013-05-29 09:53 brock 阅读(1004) | 评论 (0)编辑 收藏

症状:系统运行了一段时间报错:java.sql.SQLException: ORA-01000: 超出打开游标的最大数

step 1:
    查看数据库当前的游标数配置slqplus:show parameter open_cursors;

step 2:
    查看游标使用情况:
select o.sid, osuser, machine, count(*) num_curs
from v$open_cursor o, v$session s
where user_name = 'user' and o.sid=s.sid
group by o.sid, osuser, machine
order by  num_curs desc;
此处的user_name='user'中,user代表占用数据库资源的数据库用户名.

step 3:
    查看游标执行的sql情况:

select o.sid q.sql_text
from v$open_cursor o, v$sql q
where q.hash_value=o.hash_value and o.sid = 123;

step 4:
    根据游标占用情况分析访问数据库的程序在资源释放上是否正常,如果程序释放资源没有问题,则加大游标数。
    alter system set open_cursors=2000 scope=both;
    
    补充:在java代码中,执行conn.createStatement()和conn.prepareStatement()的时候,实际上都是相当与在数据库中打开了一个cursor。尤其是,如果你的createStatement和prepareStatement是在一个循环里面的话,就会非常容易出现这个问题。因为游标一直在不停的打开,而且没有关闭。
     一般来说,我们在写Java代码的时候,createStatement和prepareStatement都应该要放在循环外面,而且使用了这些Statment后,及时关闭。最好是在执行了一次executeQuery、executeUpdate等之后,如果不需要使用结果集(ResultSet)的数据,就马上将Statment关闭,调用close()方法。

posted @ 2013-05-29 09:53 brock 阅读(182) | 评论 (0)编辑 收藏

     摘要: http://vc.hsly0559.cn/c/20111216_957.html首先,马云坑到了很多钱。。。所以确实有一批大神在为他干活  其次,现在阿里系出来又是出书又是演讲跳大神装B。。不是牛人。。给我的感觉。。跳梁小丑一样,给后端的牛人抹黑,我实在看不习惯  第三,最近关于Tengine的讨论很火,简单看了下,在大流量下确实表现不错,而且据说可以过滤掉一些攻击或类似攻击流量,这是其宣称的特...  阅读全文
posted @ 2013-05-16 16:54 brock 阅读(315) | 评论 (0)编辑 收藏

1 做产品经理,而不是功能经理;

2 做产品需求,而不是用户需求;

要锦上添花,而不是画蛇添足;

追求人性化,而不是追求完美。

 

产品经理是个很奇怪的岗位,好像大多数人都能做,因为每个人对某个产品都有自己的看法,都能提出一些意见和想法,甚至能设计实现原理;也好像大多数人都做不好产品经理,因为互联网上成千上万个产品,大部分是垃圾,没几个产品是用户真心觉得很不错的。

 

我做产品经理,还不到两年,以前十来年一直在做技术。之前做技术的时候,我很看不上产品经理。当时想:产品经理自己什么都实现不了,每天就是提点想法,而且想法还经常不靠谱,如果哪天裁员,产品经理的位置最危险了;但等我转来做了产品经理,想法发生了根本的变化:嗯,产品经理太重要的,一个产品的未来就决定在产品经理身上。

 

你问我现在如何看待技术人员?嘿嘿,我现在觉得,技术就是一把刀,让它杀谁就杀谁!当然,这只是开玩笑。一个好的技术团队对于产品经理来说,那是相当重要。

 

对如何做产品经理,我还真的是小学生,自己负责的淘宝搜索最近两年也没什么大提升。特别是看了周鸿祎、张小龙关于对产品的一些访谈以后,我更发现自己在这方面的差距。

 

不过我有个优点,就是善于学习、思考、总结并分享。而且作为一个外行进入到这个领域,观察的角度也会不一样。这一年多下来,也找到一些感觉,发现周围的一些产品经理,容易走入一些误区,分享给大家。

 

做产品经理,而不是功能经理。

 

这句话我最早是听天猫总裁逍遥子说的,当时没有感觉,现在发现非常有道理,因为周围太多的产品经理实际上是在做一名功能经理。

 

他们只是不停的在接产品功能需求,然后不停实现产品功能。缺登录,设计一个登录框;没有数据,找某个平台打通一下;管理不方便,设计一个工具来管理;页面不美观,重新规划一下页面结构……

 

功能经理,每天都很忙,关注还有多少需求在后面排队,需求方是否得到满足。而用户体验到底如何,功能是否真的真有价值,是否可以更加完美,功能经理很少关心。当有人抱怨某个功能不爽的时候,他会说:

这个功能我已经有了啊,你说体验不太好?没办法,工程师资源太紧张啊,你说为啥设计的这么别扭?kao,想起来就来气,大老板非要求这样啊,我们也只能这样设计,没办法!

 

他经常表达的语气是他也不得已而为之,把责任都推到其他人身上。

 

然而做一个合格的产品经理,需要关注用户的体验,真正关注用户的反馈,关注数据的质量,关注每一个细节。就像买一双鞋一样,不只是能穿,还要考虑是否合脚,是否舒服,款式是否漂亮。

 

有一次开会,淘宝的总裁语嫣姐姐说了一句很朴素但很有道理的一句话:产品能用和好用完全不是一回事!

 

(大家不用批评淘宝搜索啊,我知道很多地方还不好用。大家再给我点时间,我也认识到这个问题不是......)

 

实现产品需求,而不是用户需求。

 

这个话题很有意思。当你问用户需要什么的时候,他会回答他需要一匹更快的马。乔布斯说,永远不要问用户想要什么!因为用户都是傻瓜,不知道自己想要什么。

 

这其实是产品经理经常把用户需求当成产品需求。对所有用户说的,他们没错,提的都是自己的期望,不是一个产品需求。前些天有张小龙的采访,张小龙说他不看用户的数据。其实张小龙很关心用户的需求,我和张小龙在一个群里,如果有人在群里提一些微信使用不爽的功能,张小龙会很快给出反馈。

 

这些产品大神们,背后的意思是,不应该简单满足用户需求,而应该思考把用户需求提炼成产品需求。当一个产品的用户有上百万上千万的时候,产品需求的理解和提炼,就相当重要。

 

这个道理比较容易理解,不做多解释。

 

要锦上添花,而不是画蛇添足。

 

互联网的发展,让很多互联网产品经理有个惯性:做产品迭代要快。快速上线,快速修改。这里也有误区,对于一些基本功能,确实要快速上线,快速迭代。因为有市场竞争,需要快速切入市场,获得用户。然而大部分的产品经理,没有机会从零开始设计一个新产品,大部分时候在现有的产品上做升级或优化。这时设计的很多功能,都是锦上添花的功能,还真不能太快。

 

锦上添花的功能,同样重要,会让产品更好玩,更有意思,更有特点。例如微信最早设计的摇一摇功能、朋友圈功能。微博的微刊功能、之前的送礼物的功能。

 

问题在于,锦上添花,添上去的一定是一朵花,说得俗一点,不能添上去是一坨屎。如果是后者,那么就有点画蛇添足了,或者成了鸡肋功能。

 

什么是一朵花?就是功能添加上去以后,会让用户眼前一亮。给人有“哇!!!”的感觉……

 

遗憾的是淘宝搜索之前的很多功能添上去的都不是一朵花,上线了太多的画蛇添足的功能。这些功能一旦上线,就很难下线。因为当你产品的用户群有上亿的时候,再烂的一个功能,每天也会有几十万用户在使用。一旦你下线,会有很多人很不爽。

 

淘宝搜索的同店购就有点这个味道。技术实现成本高,体验一般,用的人也不多。有一段时间我们把这个功能隐藏起来了,有人在微博上说:

妈的,我现在最想做的事情,就是找把刀杀个淘宝搜索的产品经理来解解恨,我居然死活找不到我最常用的同店购了!

 

画蛇添足的功能越多,让产品背负的垃圾就越多,造成好的功能没有资源做,差的功能又无法下线。

 

追求人性化,而不是追求完美。

 

很多产品经理,追求完美。这是作为产品经理很好的品质,然而,有一点却经常被产品经理忽视,产品的人性化。

 

永远没有完美的产品,特别是当一个产品的用户量到达上百万上千万的时候。用户的喜好千差万别。如何让用户能喜欢产品的优点的同时能容忍产品的缺点?

 

大家看选美大赛获胜的美女,经常会有感叹,为什么这么丑还能得前三啊!是因为评委的口味太特别?当然有一部分评委原因,但更多原因在于,大家每个人的审美观不一样。大家是把选美冠军作为一个完美的人来评判。

 

实际上,无论选出谁是冠军,都会有人觉得难看。任何一个产品,无论产品经理推出多么好用的功能,都会有人不喜欢!

 

然而,大家对待周围的朋友,就不会用选美的标准要求他们,他们有明显的缺点,但也有很多值得欣赏的地方。大家订阅鬼脚七的微信,绝大部分人不会期望,鬼脚七每天的文章都会符合自己的口味。有人不看文章,只看看【7哥闲谈】也会觉得很有意思。为什么?因为大家不会期待鬼脚七这个账号是个完美的账号,把鬼脚七作为一个朋友在看待。鬼脚七有缺点,也有优点。

 

如果能让用户把我们的产品当成周围的朋友来看待呢?感觉会完全不一样。

 

淘宝有个做运营的同事有一天跟我感叹说:我忽然觉得攻城狮们离我好近,每个攻城狮内心都住着个诗人!我问为什么会忽然有这种感觉?她说有一天晚上,发现在淘宝内部一个TMS系统的标题栏上忽然多了一句话:

每个人的压力,少部分来自生存,大部分来自攀比。

 

就这一句话,让用户感觉到了产品背后的那位工程师。还记得微信有个版本的欢迎页面上的文字吗:

少发微信,多和朋友见见面!

 

就这一句话,让我感觉到产品背后的那群人的心理活动。微信的一些小瑕疵,我也能容忍。

 

就是这句话,我喜欢上了微信。

 

人性化,是不是让产品开始具有了灵魂?

 

如何让产品更加人性化?如何让淘宝搜索更加人性化?是我最近一直在思考的问题。我定义2013年搜索的关键词:专业和有趣。希望2013年能让更多的人把淘宝搜索当成一个朋友,而不是一个工具。

 

写了这么多,回头看看我这篇文章,好像没有什么产品设计方法,只是一些思考,仅此而已。

 

作者介绍:

鬼脚七,一个简单的人,分享电商资讯、搜索变化、淘宝动态、产品设计、管理心得、生活感悟;偶尔文艺,偶尔深沉。做一个有思想的人!微信账号: taobaoguijiaoqi 加为好友后回复 m 可以看到作者之前的所有文章。

posted @ 2013-03-22 11:16 brock| 编辑 收藏

1、匿名函数

函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途。匿名函数:就是没有函数名的函数。

1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式

第一种:这也是最常规的一种

function double(x){     return 2 * x;    } 

第二种:这种方法使用了Function构造函数,把参数列表和函数体都作为字符串,很不方便,不建议使用。

var double = new Function('x', 'return 2 * x;'); 

第三种:

var double = function(x) {
return 2* x;
}

注意“=”右边的函数就是一个匿名函数,创造完毕函数后,又将该函数赋给了变量square。

1.2 匿名函数的创建

第一种方式:就是上面所讲的定义square函数,这也是最常用的方式之一。

第二种方式:

(function(x, y){
alert(x + y);
})(2, 3);

这里创建了一个匿名函数(在第一个括号内),第二个括号用于调用该匿名函数,并传入参数。

2、闭包

闭包的英文单词是closure,这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看上去更加清晰等等,总之功能十分强大。

闭包的含义:闭包说白了就是函数的嵌套,内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕(这点涉及JavaScript作用域链)。

示例一

function checkClosure(){     var str = 'rain-man';     setTimeout(         function(){ alert(str); } //这是一个匿名函数     , 2000); } checkClosure(); 

这个例子看上去十分的简单,仔细分析下它的执行过程还是有许多知识点的:checkClosure函数的执行是瞬间的(也许用时只是0.00001毫秒),在checkClosure的函数体内创建了一个变量str,在checkClosure执行完毕之后str并没有被释放,这是因为setTimeout内的匿名函数存在这对str的引用。待到2秒后函数体内的匿名函数被执行完毕,str才被释放。

示例二,优化代码

function forTimeout(x, y){
alert(x + y); } function delay(x , y , time){
setTimeout('forTimeout(' + x + ',' + y + ')' , time);
} /** * 上面的delay函数十分难以阅读,也不容易编写,但如果使用闭包就可以让代码更加清晰 *
function delay(x , y , time){ *
setTimeout( *
function(){ *
forTimeout(x , y) *
} * , time);
* }
*/

3、举例

匿名函数最大的用途是创建闭包(这是JavaScript语言的特性之一),并且还可以构建命名空间,以减少全局变量的使用。

示例三:

var oEvent = {}; (function(){      var addEvent = function(){ /*代码的实现省略了*/ };     function removeEvent(){}      oEvent.addEvent = addEvent;     oEvent.removeEvent = removeEvent; })(); 

在这段代码中函数addEvent和removeEvent都是局部变量,但我们可以通过全局变量oEvent使用它,这就大大减少了全局变量的使用,增强了网页的安全性。 我们要想使用此段代码:oEvent.addEvent(document.getElementById('box') , 'click' , function(){});

示例四:

var rainman = (function(x , y){     return x + y; })(2 , 3); /**  * 也可以写成下面的形式,因为第一个括号只是帮助我们阅读,但是不推荐使用下面这种书写格式。  * var rainman = function(x , y){  *    return x + y;  * }(2 , 3);  */ 

在这里我们创建了一个变量rainman,并通过直接调用匿名函数初始化为5,这种小技巧有时十分实用。

示例五:

var outer = null;  (function(){     var one = 1;     function inner (){         one += 1;         alert(one);     }     outer = inner; })();  outer();    //2 outer();    //3 outer();    //4 

这段代码中的变量one是一个局部变量(因为它被定义在一个函数之内),因此外部是不可以访问的。但是这里我们创建了inner函数,inner函数是可以访问变量one的;又将全局变量outer引用了inner,所以三次调用outer会弹出递增的结果。

4、注意

4.1 闭包允许内层函数引用父函数中的变量,但是该变量是最终值

示例六:

/**  * <body>  * <ul>  *     <li>one</li>  *     <li>two</li>  *     <li>three</li>  *     <li>one</li>  * </ul>  */  var lists = document.getElementsByTagName('li'); for(var i = 0 , len = lists.length ; i < len ; i++){     lists[ i ].onmouseover = function(){         alert(i);         }; } 

你会发现当鼠标移过每一个<li&rt;元素时,总是弹出4,而不是我们期待的元素下标。这是为什么呢?注意事项里已经讲了(最终值)。显然这种解释过于简单,当mouseover事件调用监听函数时,首先在匿名函数( function(){ alert(i); })内部查找是否定义了 i,结果是没有定义;因此它会向上查找,查找结果是已经定义了,并且i的值是4(循环后的i值);所以,最终每次弹出的都是4。

解决方法一:

var lists = document.getElementsByTagName('li'); for(var i = 0 , len = lists.length ; i < len ; i++){     (function(index){         lists[ index ].onmouseover = function(){             alert(index);             };                         })(i); } 

解决方法二:

var lists = document.getElementsByTagName('li'); for(var i = 0, len = lists.length; i < len; i++){     lists[ i ].$$index = i;    //通过在Dom元素上绑定$$index属性记录下标     lists[ i ].onmouseover = function(){         alert(this.$$index);         }; } 

解决方法三:

function eventListener(list, index){     list.onmouseover = function(){         alert(index);     }; } var lists = document.getElementsByTagName('li'); for(var i = 0 , len = lists.length ; i < len ; i++){     eventListener(lists[ i ] , i); } 

4.2 内存泄露

使用闭包十分容易造成浏览器的内存泄露,严重情况下会是浏览器挂死,感兴趣的的话可以参考:http://www.cnblogs.com/rainman/archive/2009/03/07/1405624.html

http://www.cnblogs.com/rainman/archive/2009/05/04/1448899.html

posted @ 2013-03-20 10:00 brock 阅读(215) | 评论 (0)编辑 收藏

基本规范

语义

使用符合语义的标签书写 HTML 文档, 选择恰当的元素表达所需的含义;

<!-- 不推荐 --> <div onclick="goToRecommendations();">All recommendations</div> 
<!-- 推荐 --> <a href="recommendations/">All recommendations</a> 

大小写

元素的标签和属性名必须小写, 属性值必须加双引号; 例如

<!-- 不推荐 --> <A HREF='/'>Home</A> 
<!-- 推荐 --> <a href="/">Home</a> 

缩进

  • 使用四个空格来表示缩进,不要使用 tab 键;
  • 在块状元素,列表,表格元素后面使用新行,并且对它的子元素进行缩进.

例如

<ul>     <li>         1     </li> </ul> 

空格

去除比不必要的空格; 例如

<!-- 不推荐 --> <p>test                  </p> 
<!-- 推荐 --> <p>test</p> 

嵌套

  • 元素嵌套遵循 (X)HTML Strict 嵌套规则, 推荐使用Firefox插件 HTML Validator 进行检查;
  • 正确区分自闭合元素和非自闭合元素. 非法闭合包括:<br>..</br>、<script />、<iframe />, 非法闭合会导致页面嵌套错误问题;
<!-- 不推荐 --> <title>Test</title> <article>This is only a test. 
<!-- 推荐 --> <!DOCTYPE html> <meta charset="utf-8"> <title>Test</title> <article>This is only a test.</article> 

引号

使用双引号来标识 html 的属性; 例如

<!-- 不推荐 --> <a class='maia-button maia-button-secondary'>Sign in</a> 
<!-- 推荐 --> <a class="maia-button maia-button-secondary">Sign in</a> 

自定义属性

通过给元素设置自定义属性来存放与 JavaScript 交互的数据, 属性名格式为 data-xx (例如:data-lazyload-url)

DOCTYPE

页面文档类型统一使用HTML5 DOCTYPE. 代码如下:

<!doctype html> 

编码

声明方法遵循HTML5的规范.推荐使用 utf-8 编码.

<meta charset="utf-8" /> 

注释

建议对超过10行的页面模块进行注释, 以降低开发人员的嵌套成本和后期的维护成本. 例如:

<div id="sample">     ... </div> <!-- #sample END --> 
<div class="sample">     ... </div> <!-- .sample END --> 

协议

如果链接和当前页面一致则忽略链接的协议部分,例如

<!-- 不推荐 --> <script src="http://www.taobao.com/fp.js"></script> 
<!-- 推荐 --> <script src="//www.taobao.com/fp.js"></script> 
/* 不推荐 */ .example {   background: url(http://www.taobao.com/fp.css); } 
/* 推荐 */ .example {   background: url(//www.taobao.com/fp.css); } 

TODO

  • 使用 TODO 来标记待做事情,便于后期搜索.
  • 在 TODO 后添加 (姓名或邮件) 来表示分类.

例如

<!-- TODO(yiminghe): remove duplicate tag --> <p><span>2</span></p> 

焦点分离

  • 将表现,行为和结构分离:不要在 html 和模板中加入除了结构以外的东西.
  • 在文档中引入尽可能少的样式和脚本
<!-- 不推荐 --> <!DOCTYPE html> <title>HTML sucks</title> <link rel="stylesheet" href="base.css" media="screen"> <link rel="stylesheet" href="grid.css" media="screen"> <link rel="stylesheet" href="print.css" media="print"> <h1 style="font-size: 1em;">HTML sucks</h1> <p>I’ve read about this on a few sites but now I’m sure:   <u>HTML is stupid!!1</u> <center>I can’t believe there’s no way to control the styling of   my website without doing everything all over again!</center> 
<!-- 推荐 --> <!DOCTYPE html> <title>My first CSS-only redesign</title> <link rel="stylesheet" href="default.css"> <h1>My first CSS-only redesign</h1> <p>I’ve read about this on a few sites but today I’m actually   doing it: separating concerns and avoiding anything in the HTML of   my website that is presentational. <p>It’s awesome! 

元素

结构性元素

  • p 表示段落. 只能包含内联元素, 不能包含块级元素;
  • div 本身无特殊含义, 可用于布局. 几乎可以包含任何元素;
  • br 表示换行符;
  • hr 表示水平分割线;
  • h1-h6 表示标题. 其中 h1 用于表示当前页面最重要的内容的标题;
  • blockquote 表示引用, 可以包含多个段落. 请勿纯粹为了缩进而使用 blockquote, 大部分浏览器默认将 blockquote 渲染为带有左右缩进;
  • pre 表示一段格式化好的文本;

头部元素

  • title 每个页面必须有且仅有一个 title 元素;
  • base 可用场景:首页、频道等大部分链接都为新窗口打开的页面;
  • link link 用于引入 css 资源时, 可省去 media(默认为all) 和 type(默认为text/css) 属性;
  • style type 默认为 text/css, 可以省去;
  • script type 属性可以省去; 不赞成使用lang属性; 不要使用古老的<!– //–>这种hack脚本, 它用于阻止第一代浏览器(Netscape 1和Mosaic)将脚本显示成文字;
<!-- 不推荐 --> <link rel="stylesheet" href="//www.google.com/css/maia.css"   type="text/css">  <!-- 不推荐 --> <script src="//www.google.com/js/gweb/analytics/autotrack.js"   type="text/javascript"></script> 
<!-- 推荐 --> <link rel="stylesheet" href="//www.google.com/css/maia.css">  <!-- 推荐 --> <script src="//www.google.com/js/gweb/analytics/autotrack.js"></script> 
  • noscript 在用户代理不支持 JavaScript 的情况下提供说明;

文本元素

  • a a 存在 href 属性时表示链接, 无 href 属性但有 name 属性表示锚点;
  • em,strong em 表示句意强调, 加与不加会引起语义变化, 可用于表示不同的心情或语调; strong 表示重要性强调, 可用于局部或全局, strong强调的是重要性, 不会改变句意;
  • abbr 表示缩写;
  • sub,sup 主要用于数学和化学公式, sup还可用于脚注;
  • span 本身无特殊含义;
  • ins,del 分别表示从文档中增加(插入)和删除

媒体元素

  • img 请勿将img元素作为定位布局的工具, 不要用他显示空白图片; 给img元素增加alt属性;例如
<!-- 不推荐 --> <img src="spreadsheet.png"> 
<!-- 推荐 --> <img src="spreadsheet.png" alt="Spreadsheet screenshot."> 
  • object 可以用来插入Flash;

列表元素

  • dl 表示关联列表, dd是对dt的解释; dt和dd的对应关系比较随意: 一个dt对应多个dd、多个dt对应一个dd、多个dt对应多个dd, 都合法; 可用于名词/单词解释、日程列表、站点目录;
  • ul 表示无序列表;
  • ol 表示有序列表, 可用于排行榜等;
  • li 表示列表项, 必须是ul/ol的子元素;

表单元素

  • 推荐使用 button 代替 input, 但必须声明 type;
  • 推荐使用 fieldset, legend 组织表单
  • 表单元素的 name 不能设定为 action, enctype, method, novalidate, target, submit 会导致表单提交混乱

文档模板

<!doctype html> <html>     <head>         <meta charset="utf-8" />         <title>Sample page</title>         <link rel="stylesheet" href="css_example_url" />     </head>     <body>         <div id="page">             <div id="header">                 页头             </div>             <div id="content">                 主体             </div>             <div id="footer">                 页尾             </div>         </div>         <script src="js_example_url"></script>         <script>         // 你的代码         </script>     </body> </html> 
posted @ 2013-03-11 17:31 brock 阅读(2446) | 评论 (0)编辑 收藏

     摘要: Google JavaScript 编码规范指南修订版: 2.9Aaron WhyteBob JervisDan PupiusEric ArvidssonFritz SchneiderRobby Walker每个条目都有概述信息, 点击 ▽ 查看详细的内容. 你也可以点击下面的按钮▽ 展开全部目录JavaScript 语言规范变量 常...  阅读全文
posted @ 2013-03-11 15:24 brock 阅读(3051) | 评论 (0)编辑 收藏

http://service.bbs.163.com/bbs/tyro/290302532.html
无意中看到张子阳的博客中的这篇文章,个人觉得挺好的就转载过来跟大家分享了,就擅自转载过来跟大家分享了。——靳建通

收入是由什么决定的?
这位员工辞职的原因主要有两个:
  • 公司的薪水无法达到他的预期,未来一年在公司的收入前景也不是很明确。
  • 想要去做更底层的开发,方向是使用C/C++开发3D图形图像。而我们公司主要是.NET开发。
既然其中的一个原因是薪水无法符合预期,那么首先要搞清楚的就是收入是由什么决定的。
1.积累首先要说的一点就是:积累。积累就是你在这家公司所创造的价值的积累。
你今天所领的薪水,并不是由你现在所创造的价值所决定的,而是包含了以前一段时期内其他同事所创造的价值。举个例子来说,公司目前排名前三的大客户:客户A、客户B、客户C。
  • 客户A是2008年接下来的,现在每年为公司贡献600万。
  • 客户B是2009年接下来的,现在每年为公司贡献500万。
  • 客户C是2010年接下来的,现在每年为公司贡献350万。
我的年薪是你的两倍还多。可我也承认,我现在所能创造的价值,靳建通和我的能力绝对不可能是你的两倍。可问题是:2008年、2009年、2010年这些年份我都在公司,上面的每一个大客户,都有我的贡献。靳建通而你2012年才新进公司,你并没有之前的积累。所以,新员工入职后,工资相较老员工会低一些是正常的。很多新员工总是认为自己的收入低了,吃亏了,实际上,很多情况下,新员工在加入公司的头一年,公司仅能维持平衡,即新员工创造的价值全当工资发给他了。靳建通直到第二年,有了上一年的积累之后,公司才有所盈余。而加入半年就离职的员工,对公司来说基本上是亏本的。靳建通这也就解释了为什么人员流动特别快的公司活不长,因为人力成本太高。
关于积累,我可以再举几个例子说明一下:
洪小莲,李嘉诚的秘书,几十年来一直追随李嘉诚,她从几千元的工薪族,做到身家上亿的工薪族,享受的是公司成长的回报。这种回报并非是她个人的学识和能力有了大幅的提高而得到的等价交换,很大程度上仅仅是因为她忠诚地待在这趟车上。
杨元庆,联想现在的CEO,研究生毕业后就一直追随柳传志,尽管一开始从事的是他并不很乐意的销售工作,但最终还是坚持了下来。上一次注意到他,是看到一则新闻,标题是“杨元庆自掏2000万奖励一线员工”。
上面只是正面的例子,也有反面的例子:
吴士宏,曾写了一本书叫做《逆风飞扬》,可谓是红极一时。1986年进入IBM,1998年离开IBM,进入微软,担任微软中国公司总经理,1999年进入TCL,2002年离开TCL。之后就离开了公众的视线。我特意去百度搜索靳建通“吴士宏现在在哪里”,没有任何的消息。我想如果她很成功的话,一定还属于“公众人物”,不至于连度娘都不知去向。
跳槽的话显然就要放弃先前的积累。比方说,当你跳槽到另一家公司以后,你曾经做过的系统、曾经服务过的客户仍然在为先前的公司创造着利润,可是跟你已经一毛钱关系都没有了(极少数公司有股票,另当别论)。所以跳槽之前要慎重考虑,跳得不好,有可能越跳越低。
既然新员工相对于老员工来说,收入低一些是正常的,那么老员工工资高也是合情合理的。但是有一些公司,我将其归为“无良公司”,它们会在老员工的收入高到一定程度的时候,将老员工砍掉,然后再招募低廉的新人来承担之前老员工的工作,以赚取更高的利润。我觉得这些都是小聪明,最后的结果就是,聪明能干一些的人,在看出公司的这些伎俩之后果断离职;能力一般的员工,也会把你这里当成培训基地,翅膀硬了就飞了,受损的最后还是公司,实在是得不偿失。还不如厚待老员工,也让新进的员工对未来有一个更好的预期。也有一些人向我抱怨说:“老员工待得久了,干劲都被磨光了,每天都是混日子,还不如新员工,不开他开谁?”。然后我反问他:“激励员工难道不正是你工作的一部分吗?”。这种情况的出现,更多时候,是管理者的责任,而非员工。
最后补充一点:我并不认为老员工工资比新员工高就一定是合理的。当公司对一个新员工开出很高的工资时,其实是出于这样一种期望:他能推动公司进步的更快。而如果他真的这样做到了,公司进步的更快了、收益更高了,可以反哺老员工,从而公司的整体待遇水平都提高了,不是皆大欢喜吗?可能一些老员工并不能明白这些,所以,靳建通当招一个新员工工资水平远高于现有的老员工时,为什么要这样做,最好能让老员工知晓。
2.老板这个“老板”是宽泛的老板,不一定是公司最大的老板。有的时候,公司比较大,你的职位又比较低,大老板连有没有你这个人都不知道,此时的老板就是你的顶头上司。很多时候,你的收入与他也有着莫大的关系。靳建通
对于我来说,我的原则是:在我的能力范围内,我会为我的员工争取更好的待遇。表面上看,这样做很蠢,花6000块就能雇到一个人,为什么要花8000块?我不是这样认为的,我期望能和我的员工形成这样一种互动:我尽我的能力为你争取好的待遇,你也尽你的努力做好工作。
我不能要求员工“你先把工作做好,我自然会给你好的待遇”。总是要有人先迈出一步,总是要有一方先信任另一方,所以在你什么还没有做的时候,我就先信任你,并且给你尽可能好的待遇,那么我该做的事情都做了,我问心无愧,剩下的,就看你的表现了。
可能有人会想,都这样了怎么还会有人提出辞职?实际上,提出辞职的是一个毕业刚一年的小伙子,1989年生,毕业1年多,我给他的待遇是试用期9000,转正后9500。在给他这个待遇之前,我是进行过一些调研的,我打电话给我的一个表妹,她是西安电子科技大学的研究生(陕西省排名第三的学校,211院校),她和她的同学在今年毕业找工作的时候,多得是6000到8000的工资。所以从这方面来说,我并没有亏待你,而你要求12K的工资,我并不是不愿意给这么多,你的表现也说明了你是个很有潜力的人才。只是受经济环境的影响,今年公司的效益不及往年,要在一定程度上节省开支。其次,你让其他的老员工情何以堪?所以,综合起来,你的要求超出了我的能力范围之外,我无法开口向公司申请提高你的薪水。
3.门槛除了积累和顶头上司两个决定因素以外,靳建通第三个决定因素就是你从事工作的门槛。为什么餐厅服务员的收入很低?为什么坐在前台收发快递的文员收入很低?因为这些工作的门槛很低,门槛低就意味着你不做有的是人能做,你不做有大批的“后备队伍”在等着做。靳建通由于庞大的后备队伍的竞争,你就无法提高自己的要价。而提升自己所从事工作的门槛,实际上就缩减了竞争者的规模。
程序开发也是一样。如果你想收入高,你就做一些别人做不了,又有市场的。
.NET在程序开发中就属于门槛比较低的一类。个中原因我想大家都懂的,就不在这里赘述了。做.NET不需要你科班出身,或许一点兴趣再加上一点时间,或许一个类似北大青鸟的培训,都可以让你开始从事.NET开发了。你可以不懂指针、不懂数据结构、不懂算法、不懂汇编、不懂很多东西,但照样可以做出一个.NET程序来。而这些人往往又是对薪资的要求没那么高的,这样无形中就拉低了.NET程序员的“身价”。.NET的易学易会,很大程度上是由于它的封装性比较好。底层的东西都屏蔽掉了,你只要知道学习一下命名空间,然后寻找相关的API去调用就好了。记得我们公司曾经开发过一个基于C语言的手持设备程序,没有任何的类库支持,连排序、链表这样.NET中的基本功能,都要自己来实现,更别提内存管理和程序逻辑了,和.NET比起来,门槛就相对高一些了。
所以,如果想收入高一些,那么就去做更高难度的技术工作,这里随便想了几个例子:
  • 百度、谷歌的搜索引擎算法。
  • 微软、谷歌、苹果的操作系统。
  • 网络游戏,例如《征途》的游戏引擎。
  • 大型企业的ERP,比方说SAP。
  • 软硬结合,比如单片机,电气自动化。
  • 以及我这位即将离职的同事说的,3D图形图像。
所以,从这个角度来看,这位同事的辞职是明智的,他很年轻,靳建通有的是机会重新选择自己的道路,所以我也祝愿他能有更好的发展。而这些好赚的钱,就留给我们来做了:-)。
4.平台接下来要说的一个决定因素是平台。很多程序员觉得30岁就瓶颈了,30岁写程序就到头了,实际上,这只是你的平台比较小罢了。就拿我自己的公司来说,平台就不大,只要是踏踏实实工作过5年的程序员,基本上就能够胜任公司90%的技术工作了,剩下的10%,请教一下其他同事,进行一下技术交流,也完全能够解决。这样就存在一个问题:随着你年龄的增长,你的生活压力越来越大,要求越来越高,可是公司只要5年经验的程序员就够用了。假设市场上5年经验的程序员的平均要求是10K,凭什么要给你15K?你的优势在哪里?如果你没有突破,就会有“30岁写程序就到头了”的感觉。
而如果平台大一些情况就会不一样,比方说,你去了IBM,可能5年的经验不过刚刚入门而已。IBM有一个工程院,其中有5位院士(IBM Fellow)获得过诺贝尔奖,很多人钻研技术都超过20年或者更久。如果你对技术感兴趣,并执着去钻研的话,你可以不断地去挑战和攀登。
当然,你可能没那么好的运气和实力进入IBM,那么其他一些中型的平台也是不错的,比方说阿里巴巴、金蝶、百度、腾讯等等。在这里,至少你有足够的理由和需要再去进行深入学习。因为在这些地方,5年的经验是远远不够的,还需要进一步地学习和努力。
如果你和我一样,不巧没有那么大的平台,此时的选择大概有这么几种:
1. 你可以凭借你在公司的积累(第一节讲过的),过比较安逸的日子。如果比较幸运,押对了宝,公司发展得比较好,收入一样会变得非常可观;如果比较不幸,公司经营的状况不好,那就要承担比较大的风险了。说得难听一点,公司倒闭了你去哪里?你过去的积累已经一文不值,靳建通而你的年龄已经35,水平却相当于只有5年经验。你的竞争力在哪里?
2. 你可以凭自己的努力将现在所在的平台做大,换言之,把自己的小公司做大。这当然是比较积极的做法,也是我一直努力的方向。现在你看到的大公司,不也是从小公司一步一步做起的吗?不过这里还有两个问题:1、有的时候,你的力量在公司中的占比没那么大,你再怎么努力推进的速度也还是有限;2、你缺乏慧眼,选中的公司本身就缺乏长大的资质。我们往往只看到成功了的公司,却忽视了更多在竞争中倒下的公司。
3. 主动选择更大的平台,也就是跳槽了。但是跳槽也是有风险的,尤其是过了30岁的程序员,你在这家公司的收入高,是因为有之前的积累,换一家就没有积累了,等于从新人开始,而大多数的公司,5年经验的程序员就够用了。如果跳得不好,收入还可能越跳越低,如果还有老婆、孩子、房贷,那将面临更大的压力。所以当你想要从一个低的平台向更高的平台跳跃的时候,平时就要做足功夫,认真积累自己的实力。对于我来说,我缺乏大型项目的管理经验,但是没关系,我努力学习考一个PMP没什么问题吧?我缺乏大型软件的架构经验,但是没关系,我把.NET的基础知识和各种设计模式掰开了揉碎了没什么问题吧?我缺乏大型团队的管理经验,但是没关系,每次遇到管理方面的问题我都认真思考仔细总结没什么问题吧?有些人总是抱怨没有机会,运气不好,我想机会总是有的,但只属于有准备的人。
5.行业我想说的最后一点就是行业。有时候你觉得已经万事俱备了,可是你所处的这个行业本身就属于极低利润率的,你再怎么努力也很难有很高的收入。很多情况下,可能公司也想提高你的待遇,但是由于缺乏利润的支撑,公司也是有心无力。所以,在选择公司,尤其是小公司的时候,要重点考察一下公司所处的行业如何?是不是前景比较好、利润比较高的行业?如果是大公司的话,靳建通这方面的问题就会少一些,因为如果方向有问题,它就无法做成大公司。
行业是有周期性的,可能在一段时期内这个行业好,下一段时期这个行业就不行了。最典型的一个例子就是软盘,我现在的老板在成立这家公司之前是做销售的,他有一个客户,做索尼软盘的,这种软盘我想很多80后都见过。当时生意做得很大,可是当光盘出来以后,软盘的市场是会急剧萎缩的,可是这家公司的领导层居然没有看到,或者是看到了但不愿意转变,像鸵鸟一样在危机来临时把头埋在土里,继续做它的软盘。几年以后,这家公司就倒掉了。
选择行业也不是选择暴利行业就一定好,比方说房地产。资本都是逐利的,当一个行业属于暴利,同时所有人都知道它是暴利的时候,危机就来了。这个危机就是会有大量的社会资源、人力物力投入到这个行业中企图分一杯羹。而全局上又没有一个统一的把控,这个行业究竟需要多少公司才是合适的?最后的结果就是过剩。就好像股票在崩盘时,也许跌到3000点是比较合理也比较正常的位置,靳建通但是由于人们的恐慌,它就跌到1600点了。
感谢阅读,希望这篇文章能给你带来收获。
不是所有一年工作经验的毕业生都有这样的待遇,我主要是看能力,而不是年龄、学历等。特别说明一下,以免误导。
posted @ 2013-03-07 18:27 brock 阅读(213) | 评论 (0)编辑 收藏

http://sunnylocus.iteye.com/blog/342996
   大多数程序员都知道Servlet的生命周期,简单的概括这就分为四步:servlet类加载--->实例化--->服务--->销毁。对这个过程只是肤浅了解下,对于servlet何时被销毁,还是不太情楚。下面我们描述一下Tomcat与Servlet是如何工作的,首先看下面的时序图.

1、Web Client 向Servlet容器(Tomcat)发出Http请求

2、Servlet容器接收Web Client的请求

3、Servlet容器创建一个HttpRequest对象,将Web Client请求的信息封装到这个对象中

4、Servlet容器创建一个HttpResponse对象

5、Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数

     传给 HttpServlet对象

6、HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息

7、HttpServlet调用HttpResponse对象的有关方法,生成响应数据

8、Servlet容器把HttpServlet的响应结果传给Web Client

 

对于Servlet容器(Tomcat)与HttpServlet是怎样进行交互的呢,看下类图

Servlet的框架是由两个Java包组成的:javax.servlet与javax.servlet.http。在javax.servlet包中定义了所有的Servlet类都必须实现或者扩展的通用接口和类。在javax.servlet.http包中定义了采用Http协议通信的HttpServlet类。Servlet的框架的核心是javax.servlet.Servlet接口,所有的Servlet都必须实现这个接口。

在Servlet接口中定义了5个方法,

其中3个方法代表了Servlet的生命周期:

1、init方法:负责初始化Servlet对象。

2、service方法:负责响应客户的请求。

3、destroy方法:当Servlet对象退出生命周期时,负责释放占用的资源。

 

一、创建Servlet对象的时机

1、Servlet容器启动时:读取web.xml配置文件中的信息,构造指定的Servlet对象,创建ServletConfig对象,同时将ServletConfig对象作为参数来调用Servlet对象的init方法。

2、在Servlet容器启动后:客户首次向Servlet发出请求,Servlet容器会判断内存中是否存在指定的Servlet对象,如果没有则创建它,然后根据客户的请求创建HttpRequest、       HttpResponse对象,从而调用Servlet

     对象的service方法。

3、Servlet的类文件被更新后,重新创建Servlet

      Servlet容器在启动时自动创建Servlet,这是由在web.xml文件中为Servlet设置的<load-on-startup>属性决定

      的。从中我们也能看到同一个类型的Servlet对象在Servlet容器中以单例的形式存在。

二、销毁Servlet对象的时机

1、Servlet容器停止或者重新启动:Servlet容器调用Servlet对象的destroy方法来释放资源。以上所讲的就是Servlet对象的生命周期。那么Servlet容器如何知道创建哪一个Servlet对象?

Servlet对象如何配置?实际上这些信息是通过读取web.xml配置文件来实现的。

我们来看一下web.xml文件中的Servlet对象的配置节信息

-------------------------------------------

<servlet>

    <servlet-name>action<servlet-name>

    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

    <init-param>

        <param-name>config</param-name>

        <param-value>/WEB-INF/struts-config.xml</param-value>

    </init-param>

    <init-param>

        <param-name>detail</param-name>

        <param-value>2</param-value>

    </init-param>

    <init-param>

        <param-name>debug</param-name>

        <param-value>2</param-value>

    </init-param>

    <load-on-startup>2</load-on-startup>

</servlet>

<servlet-mapping>

    <servlet-name>action</servlet-name>

    <url-pattern>*.do</url-pattern>

</servlet-mapping>

--------------------------------------------

下面对上面的配置节信息进行解析

servlet-name:Servlet对象的名称

servlet-class:创建Servlet对象所要调用的类

param-name:参数名称

param-value:参数值

load-on-startup:Servlet容器启动时加载Servlet对象的顺序

servlet-mapping/servlet-name:要与servlet中的servlet-name配置节内容对应

url-pattern:客户访问的Servlet的相对URL路径

 

       当Servlet容器启动的时候读取<servlet>配置节信息,根据<servlet-class>配置节信息创建Servlet对象,同时根据<init-param>配置节信息创建HttpServletConfig对象,然后执行Servlet对象的init方法,并且根据<load-on-startup>配置节信息来决定创建Servlet对象的顺序,如果此配置节信息为负数或者没有配置,那么在Servlet容器启动时,将不加载此Servlet对象。当客户访问Servlet容器时,Servlet容器根据客户访问的URL地址,通过<servlet-mapping>配置节中的<url-pattern>配置节信息找到指定的Servlet对象,并调用此Servlet对象的service方法。

 

为了验证下,我新建了一个web app工程,新建一个Servlet,如下:

Java代码  收藏代码
  1. package com.tdt.servlet;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. public class TestServlet extends HttpServlet {  
  11.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  12.             throws ServletException, IOException {  
  13.         this.doPost(request, response);  
  14.     }  
  15.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  16.             throws ServletException, IOException {  
  17.   
  18.         response.setContentType("text/html");  
  19.         PrintWriter out = response.getWriter();  
  20.         out.println("Hello,this is a test");  
  21.       
  22.         out.flush();  
  23.         out.close();  
  24.     }  
  25.   
  26.     public void destroy() {  
  27.         System.err.println(getServletName()+"生命周期结束");;  
  28.     }  
  29.       
  30.     public void init() throws ServletException {  
  31.         System.out.println(getServletName()+"执行初始化");  
  32.     }  
  33. }  

 当servlet被销毁时会在控制台上打印提示语句,不过我发现在tomcat中,只要不停止web容器,servlet是不会被销毁的。有没有什么方法,当service方法执行完毕就销毁这个servlet呢,我问了下老师,他说写一个监听器,不过我不知道怎么去实现它,如果有朋友知道实现的过程,还请赐教。

posted @ 2013-03-05 14:09 brock 阅读(235) | 评论 (0)编辑 收藏


来源:struts2开发组 翻译:tianxinet(胖猴) 
Action 类: 
• Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。 
• Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。 
线程模式: 
• Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。 
• Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题) 
Servlet 依赖: 
• Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。 
• Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。 
可测性: 
• 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。 
• Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。 
捕获输入: 
• Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。 
• Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。 
表达式语言: 
• Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。 
• Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL). 
绑定值到页面(view): 
• Struts 1使用标准JSP机制把对象绑定到页面中来访问。 
• Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。 
  
类型转换: 
• Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。 
• Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。 
校验: 
• Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。 
• Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性 
Action执行的控制: 
• Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。 
• Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。

posted @ 2013-03-05 10:59 brock 阅读(225) | 评论 (0)编辑 收藏

     摘要: http://penghuaiyi.iteye.com/blog/182616这段时间,看了一些Spring文档和资料,对其有了一个基本的了解。Spring的核心技术由两大部分组成:IoC和AOP,下面我们就分别对它们进行介绍。 1  IoC技术 1.1  预备知识      IoC即Inversion of...  阅读全文
posted @ 2013-03-05 10:37 brock 阅读(319) | 评论 (0)编辑 收藏

     摘要: 1. Struts2架构图 这是Struts2官方站点提供的Struts 2 的整体结构。 2. Struts2部分类介绍 这部分从Struts2参考文档中翻译就可以了。 ActionMapper         ActionMapper其实是HttpServletRequest...  阅读全文
posted @ 2013-03-05 09:31 brock 阅读(209) | 评论 (0)编辑 收藏

     摘要: http://singleant.iteye.com/blog/1177358 接上文 啃啃老菜: Spring IOC核心源码学习(一) ,本文将以 ClassPathXmlApplicationContext 这个容器的实现作为基础,学习容器的初始化过程。ClassPathXmlApplicationContext 类体系结构以下是&...  阅读全文
posted @ 2013-02-28 11:04 brock 阅读(817) | 评论 (0)编辑 收藏

本文主要以spring ioc容器基本代码骨架为切入点,理解ioc容器的基本代码组件结构,各代码组件细节剖析将放在后面的学习文章里。

 http://www.iteye.com/topic/1113459

关于IOC容器

IoC容器:最主要是完成了完成对象的创建和依赖的管理注入等等。

先从我们自己设计这样一个视角来考虑:

所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。

对象和对象关系怎么表示?

可以用xmlproperties文件等语义化配置文件表示。

描述对象关系的文件存放在哪里?

可能是classpathfilesystem,或者是URL网络资源,servletContext等。

回到正题,有了配置文件,还需要对配置文件解析。

不同的配置文件对对象的描述不一样,如标准的,自定义声明式的,如何统一? 在内部需要有一个统一的关于对象的定义,所有外部的描述都必须转化成统一的描述定义。

如何对不同的配置文件进行解析?需要对不同的配置文件语法,采用不同的解析器。

 

基于以上问题,对应过来,刚好是 spring ioc 容器抽象的的几个主要接口:

Resource

BeanDefinition

BeanDefinitionReader

BeanFactory

ApplicationContext

以上五个都是接口,都有各式各样的实现,正是这5个接口定义了spring ioc容器的基本代码组件结构。而其组件各种实现的组合关系组成了一个运行时的具体容器。

 

各代码组件详解

1.Resource

是对资源的抽象,每一个接口实现类都代表了一种资源类型,如ClasspathResourceURLResourceFileSystemResource等。每一个资源类型都封装了对某一种特定资源的访问策略。它是spring资源访问策略的一个基础实现,应用在很多场景。

 

 

 

 

具体可以参考文章:

Spring 资源访问剖析和策略模式应用

http://www.ibm.com/developerworks/cn/java/j-lo-spring-resource/index.html

 

 

2.BeanDefinition

用来抽象和描述一个具体bean对象。是描述一个bean对象的基本数据结构。

3.BeanDefinitionReader

BeanDefinitionReader将外部资源对象描述的bean定义统一转化为统一的内部数据结构BeanDefinition。对应不同的描述需要有不同的Reader。如XmlBeanDefinitionReader用来读取xml描述配置的bean对象。



 

4.BeanFactory

用来定义一个很纯粹的bean容器。它是一个bean容器的必备结构。同时和外部应用环境等隔离。BeanDefinition是它的基本数据结构。它维护一个BeanDefinitions Map,并可根据BeanDefinition的描述进行bean的创建和管理。



 

5.ApplicationContext

从名字来看叫应用上下文,是和应用环境息息相关的。没错这个就是我们平时开发中经常直接使用打交道的一个类,应用上下文,或者也叫做spring容器。其实它的基本实现是会持有一个BeanFactory对象,并基于此提供一些包装和功能扩展。为什么要这么做呢?因为BeanFactory实现了一个容器基本结构和功能,但是与外部环境隔离。那么读取配置文件,并将配置文件解析成BeanDefinition,然后注册到BeanFactory的这一个过程的封装自然就需要ApplicationContextApplicationContext和应用环境细细相关,常见实现有ClasspathXmlApplicationContext,FileSystemXmlApplicationContext,WebApplicationContext等。ClasspathxmlFileSystemWeb等词都代表了应用和环境相关的一些意思,从字面上不难理解各自代表的含义。

当然ApplicationContextBeanFactory的区别远不止于此,有:

1.  资源访问功能:在ResourceResourceLoader的基础上可以灵活的访问不同的资源。

2.  支持不同的信息源。

3.  支持应用事件:继承了接口ApplicationEventPublisher,这样在上下文中为bean之间提供了事件机制。

……



 

 

以上5个组件基本代表了ioc容器的一个最基本组成,而组件的组合是放在ApplicationContext的实现这一层来完成。

 

以ClasspathXmlApplicationContext 容器实现为例,其组合关系如下:

 


ClassPathXmlApplicationContext的refresh() 方法负责完成了整个容器的初始化。

为什么叫refresh?也就是说其实是刷新的意思,该IOC容器里面维护了一个单例的BeanFactory,如果bean的配置有修改,也可以直接调用refresh方法,它将销毁之前的BeanFactory,重新创建一个BeanFactory。所以叫refresh也是能理解的。

以下是Refresh的基本步骤:
1.把配置xml文件转换成resource。resource的转换是先通过ResourcePatternResolver来解析可识别格式的配置文件的路径
(如"classpath*:"等),如果没有指定格式,默认会按照类路径的资源来处理。 
2.利用XmlBeanDefinitionReader完成对xml的解析,将xml Resource里定义的bean对象转换成统一的BeanDefinition。
3.将BeanDefinition注册到BeanFactory,完成对BeanFactory的初始化。BeanFactory里将会维护一个BeanDefinition的Map。

当getBean的时候就会根据调用BeanFactory,根据bean的BeanDifinition来实例化一个bean。当然根据bean的lazy-init、protetype等属性设置不同以上过程略有差别。

 

refresh()代码如下:

Java代码  收藏代码
  1. public void refresh() throws BeansException, IllegalStateException {  
  2.     synchronized (this.startupShutdownMonitor) {  
  3.         // Prepare this context for refreshing.  
  4.         prepareRefresh();  
  5.   
  6.         // Tell the subclass to refresh the internal bean factory.  
  7.         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  8.   
  9.         // Prepare the bean factory for use in this context.  
  10.         prepareBeanFactory(beanFactory);  
  11.   
  12.         try {  
  13.             // Allows post-processing of the bean factory in context subclasses.  
  14.             postProcessBeanFactory(beanFactory);  
  15.   
  16.             // Invoke factory processors registered as beans in the context.  
  17.             invokeBeanFactoryPostProcessors(beanFactory);  
  18.   
  19.             // Register bean processors that intercept bean creation.  
  20.             registerBeanPostProcessors(beanFactory);  
  21.   
  22.             // Initialize message source for this context.  
  23.             initMessageSource();  
  24.   
  25.             // Initialize event multicaster for this context.  
  26.             initApplicationEventMulticaster();  
  27.   
  28.             // Initialize other special beans in specific context subclasses.  
  29.             onRefresh();  
  30.   
  31.             // Check for listener beans and register them.  
  32.             registerListeners();  
  33.   
  34.             // Instantiate all remaining (non-lazy-init) singletons.  
  35.             finishBeanFactoryInitialization(beanFactory);  
  36.   
  37.             // Last step: publish corresponding event.  
  38.             finishRefresh();  
  39.         }  
  40.   
  41.         catch (BeansException ex) {  
  42.             // Destroy already created singletons to avoid dangling resources.  
  43.             beanFactory.destroySingletons();  
  44.   
  45.             // Reset 'active' flag.  
  46.             cancelRefresh(ex);  
  47.   
  48.             // Propagate exception to caller.  
  49.             throw ex;  
  50.         }  
  51.     }  
  52. }  

 以上的obtainFreshBeanFactory是很关键的一个方法,里面会调用loadBeanDefinition方法,如下:

Java代码  收藏代码
  1. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {  
  2.     // Create a new XmlBeanDefinitionReader for the given BeanFactory.  
  3.     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
  4.   
  5.     // Configure the bean definition reader with this context's  
  6.     // resource loading environment.  
  7.     beanDefinitionReader.setResourceLoader(this);  
  8.     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
  9.   
  10.     // Allow a subclass to provide custom initialization of the reader,  
  11.     // then proceed with actually loading the bean definitions.  
  12.     initBeanDefinitionReader(beanDefinitionReader);  
  13.     loadBeanDefinitions(beanDefinitionReader);  
  14. }  

 LoadBeanDifinition方法很关键,这里特定于整个IOC容器,实例化了一个XmlBeanDefinitionReader来解析Resource文件。关于Resource文件如何初始化和xml文件如何解析都在

Java代码  收藏代码
  1. loadBeanDefinitions(beanDefinitionReader);  

 里面的层层调用完成,这里不在累述。

小结 

Spring的扩展性是毋庸置疑的,学习spring的设计是一个很好的实践理论结合。主要个人觉得有几点:

1.  框架顶层的设计有着很好的抽象,遵循面向接口编程的规范。ResourceBeanFactoryApplicationContext都是非常好的接口抽象,非常明确的定义了该组件的一些功能。

2.  利用组合模式。

3.  个组件的实现里大量使用了模板方法模式,提升了同一组件代码的复用性。

4.  各种设计保留了扩展的接口,很多基于spring的框架都可以很容易的介入实现了自己的一些扩展。

5.  框架里采用里很多经典的设计模式,如代理、装饰、策略等等。

posted @ 2013-02-28 10:46 brock 阅读(262) | 评论 (0)编辑 收藏

先来看下一X经典配置:

 

/opt/taobao/java/bin/java -Dprogram.name=run.sh –server

 -Xms4g           //指定 jvm 的最小 heap 大小 (-Xms默认是物理内存的1/4)

 -Xmx4g           //指定 jvm 的最大 heap 大小

 -Xmn2g

 -Xss1m

 -XX:PermSize=96m

 -XX:MaxPermSize=256m

 -XX:SurvivorRatio=10

 -XX:+HeapDumpOnOutOfMemoryError    //

 -XX:HeapDumpPath=/home/admin/logs/java.hprof -verbose:gc -Xloggc:/home/admin/logs/gc.log

 -XX:+PrintGCDetails

 -XX:+PrintGCDateStamps

 -XX:+UseConcMarkSweepGC

 -XX:+UseCMSCompactAtFullCollection

 -XX:CMSInitiatingOccupancyFraction=80

 -XX:+UseCompressedOops

 -XX:+DisableExplicitGC

 -Djava.awt.headless=true

 -Dsun.net.client.defaultConnectTimeout=10000

 -Dsun.net.client.defaultReadTimeout=30000

 -Djava.net.preferIPv4Stack=true

 -Djava.endorsed.dirs=/opt/taobao/jboss/lib/endorsed

 -classpath /opt/taobao/jboss/bin/run.jar:/opt/taobao/java/lib/tools.jar org.jboss.Main -b 0.0.0.0 -Djboss.server.home.dir=/home/admin/purdecision/.default -Djboss.server.home.url=file:/home/admin/purdecision/.default

 

 

这二年来这一堆东西我从来没有怀疑过,“绝对正确完美”,据说是X宝的标配。以至于从来没有去分析了解过(一知半解),可能真的是惰性使然,也可能“忙”吧。无意中看到有人在博客里写到 “温故知新”,就像有人说读think in java一样每一回都有新的发现。下面就分析一下为什么要设置这些参数,有何意义。

 

 

上面参数说明:

-Xmx4g :

 指定 jvm 的最大 heap 大小,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定

 

-Xms4g :

 指定 jvm 的最小 heap 大小。些值设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存

 

-Xmn2g :

设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般

固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推

荐配置为整个堆的3/8(按此说应设置为1.5G)

-Xss1m

每个线程堆栈大小为1M. 根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。(本机由于forest的原因-Xss2m,原因1:物理内存过小 2window线程不能太多 猜的)

 

-XX:PermSize=96m

用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或

者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新

增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置

-XX:PermSize=64MB
最小尺寸,初始分配
-XX:MaxPermSize=256MB
最大允许分配尺寸,按需分配
过小会导致:java.lang.OutOfMemoryError: PermGen space

MaxPermSize
缺省值和-server -client选项相关。
-server
选项下默认MaxPermSize64m
-client
选项下默认MaxPermSize32m

 

(为什么不是64M 可能是webx设置的持久代空间比较多)

 

 

-XX:SurvivorRatio=10

SurvivorRatio=4设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor

区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6

这里设置为10也就是说一个Survivor区占整个年轻代的1/12,这个参数是否能小一点,毕竟我们的应用中没有创建很大的对像。

 

 

这个值设了有什么用?

上面配置中-Xmn2g 年轻代大小,SurvivorRatio10 Eden超过1.66G时触发minor gc(young generation)

我的应用gc 日志一直在young gc 就是如此,看来我的应用 eden区还是设的很大的。

 


 -XX:+HeapDumpOnOutOfMemoryError

参数表示当JVM发生OOM时,自动生成DUMP文件。 

 

-XX:HeapDumpPath=${目录}参数表示生成DUMP文件的路径,也可以指定文件名称,例如:-XX:HeapDumpPath=${目录}/java_heapdump.hprof。如果不指定文件名,默认为:java_<pid>_<date>_<time>_heapDump.hprof

 

-XX:+PrintGCDetails

输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured:

112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

 

-XX:+PrintGCTimeStamps -XX:+PrintGCPrintGCTimeStamps可与上面两个混合使用

输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]

 

 

-XX:+UseConcMarkSweepGC  

设置并发收集器

 

可以保证大部分工作都并发进行(应用不停止),垃圾回收只暂停很少的时间,此收集器适合对响应时间要求

比较高的中、大规模应用。使用-XX:+UseConcMarkSweepGC打开。

并发收集器主要减少年老代的暂停时间,他在应用不停止的情况下使用独立的垃圾回收线程,跟踪可达对

象。在每个年老代垃圾回收周期中,在收集初期并发收集器 会对整个应用进行简短的暂停,在收集中还会再暂

停一次。第二次暂停会比第一次稍长,在此过程中多个线程同时进行垃圾回收工作。

 

CMS采用的基础算法是:标记—清除 所有CMS不会整理、压缩堆空间。这样就会有一个问题:经过CMS收集的堆会产生空间碎片

 

 

-XX:CMSInitiatingOccupancyFraction=80

 

启动并发收集器:因为并发收集在应用运行时进行收集,所以必须保证收集完成之前有足够的内存空间供程

序使用,否则会出现“Concurrent Mode Failure”。通过设置-XX:CMSInitiatingOccupancyFraction=<N>

指定还有多少剩余堆时开始执行并发收集

 

-XX:+UseCMSCompactAtFullCollection

打开对年老代的压缩。可能会影响性能,但是可以消除碎片

 

XX:+UseCompressedOops

通常64JVM消耗的内存会比32位的大1.5倍,这是因为对象指针在64位架构下,长度会翻倍(更宽的寻址)。
对于那些将要从32位平台移植到64位的应用来说,平白无辜多了1/2的内存占用,这是开发者不愿意看到的。
幸运的是,从JDK 1.6 update14开始,64 bit JVM正式支持了 -XX:+UseCompressedOops 这个可以压缩指针,起到节约内存占用的新参数

 

-XX:-DisableExplicitGC

将会忽略手动调用GC的代码,如:System.gc(),将-DisableExplicitGC 改成+DisableExplicitGC即为启用,默认为启用,什么也不写,默认是加号,但是系统内部默认的并不是什么都启用

 

 

至此为什么Xmxxms 一样,为什么用CMS(并发收集器),为什么用了cms 要使用-XX:+UseCMSCompactAtFullCollection,为什么用XX:+UseCompressedOops等等,相信大家和我一样有所了解。不过对于有些还是不清楚理解有误,可能还要来来回回捣腾,不足之处请大家补充。

 

 

posted @ 2013-02-27 14:25 brock 阅读(1050) | 评论 (0)编辑 收藏

1. 代理模式主要有两种:静态代理和动态代理 

2. 静态代理: 

比如要在输出“HelloWorld”前打印一个字符串“Welcome” 

A:先定义一个接口类 
Java代码  收藏代码
  1. package ttitfly.proxy;      
  2.      
  3. public interface HelloWorld {      
  4.     public void print();      
  5. //  public void say();      
  6. }   
   



B: 定义一个该接口的实现类 

java 代码 
Java代码  收藏代码
  1. package ttitfly.proxy;      
  2.      
  3. public class HelloWorldImpl implements HelloWorld{      
  4.      
  5.     public void print(){      
  6.         System.out.println("HelloWorld");      
  7.     }      
  8. //  public void say(){      
  9. //      System.out.println("Say Hello!");      
  10. //  }      
  11. }      




C:定义一个静态代理类 
Java代码  收藏代码
  1. package ttitfly.proxy;      
  2.      
  3. public class StaticProxy implements HelloWorld{      
  4.      
  5.     public HelloWorld helloWorld ;      
  6.     public StaticProxy(HelloWorld helloWorld){      
  7.         this.helloWorld = helloWorld;      
  8.     }      
  9.           
  10.     public void print(){      
  11.         System.out.println("Welcome");      
  12.         //相当于回调      
  13.         helloWorld.print();      
  14.     }      
  15.           
  16. //  public void say(){      
  17. //      //相当于回调      
  18. //      helloWorld.say();      
  19. //  }      
  20. }      




D: 一个测试类: 
Java代码  收藏代码
  1. package ttitfly.proxy;      
  2.      
  3. public class TestStaticProxy {      
  4.      
  5.     public static void main(String[] args){      
  6.         HelloWorld helloWorld = new HelloWorldImpl();      
  7.         StaticProxy staticProxy = new StaticProxy(helloWorld);      
  8.         staticProxy.print();      
  9.               
  10. //      staticProxy.say();      
  11.     }      
  12. }      


可以看出静态代理类有一个很不爽的缺点:当如果接口加一个方法(把上面所有的代码的注释给去掉),所有的实现类和代理类里都需要做个实现。这就增加了代码的复杂度。动态代理就可以避免这个缺点。 

3 。动态代理 

动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。 

动态代理类只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类 

代理类: 
Java代码  收藏代码
  1. package ttitfly.proxy;          
  2.          
  3. import java.lang.reflect.InvocationHandler;          
  4. import java.lang.reflect.Method;          
  5. import java.lang.reflect.Proxy;          
  6. //动态代理类只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类          
  7. public class DynamicProxy implements InvocationHandler{          
  8.               
  9.     private Object object;           
  10.     //绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。      
  11.     //Proxy.newProxyInstance的第三个参数是表明这些被拦截的方法执行时需要执行哪个InvocationHandler的invoke方法      
  12.     public Object bindRelation(Object object){           
  13.         this.object = object;          
  14.         return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);           
  15.     }           
  16.     //拦截关联的这个实现类的方法被调用时将被执行          
  17.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {           
  18.         System.out.println("Welcome");          
  19.         Object result = method.invoke(object, args);           
  20.         return result;          
  21.     }          
  22.          
  23. }          


测试类: 
Java代码  收藏代码
  1. package ttitfly.proxy;          
  2.          
  3. public class TestDynamicProxy {          
  4.     public static void main(String[] args){          
  5.         HelloWorld helloWorld = new HelloWorldImpl();          
  6.         DynamicProxy dp = new DynamicProxy();          
  7.         //在这里绑定的是HelloWorld,也就是HelloWorld是被代理接口。所以绑定关系时,需要传递一个HelloWorld的实现类的实例化对象。          
  8.         HelloWorld helloWorld1 = (HelloWorld)dp.bindRelation(helloWorld);           
  9.         helloWorld1.print();           
  10.         helloWorld1.say();          
  11.               
  12.         //helloWorld2将不被拦截      
  13.         HelloWorld helloWorld2 = new HelloWorldImpl();      
  14.         helloWorld2.print();           
  15.         helloWorld2.say();      
  16.               
  17.     }          
  18. }          



在测试类里调用实现类的print和say方法,因为代理类里代理了HelloWorld的所有方法。所以就不需要像静态代理类那样一一实现了。 
posted @ 2013-02-21 12:01 brock| 编辑 收藏

     摘要: 序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 "serialVer...  阅读全文
posted @ 2013-02-21 11:41 brock| 编辑 收藏

     摘要: 泛型是Java SE 5.0中引入的一项特征,自从这项语言特征出现多年来,我相信,几乎所有的Java程序员不仅听说过,而且使用过它。关于Java泛型的教程,免费的,不免费的,有很多。我遇到的最好的教材有:The Java TutorialJava Generics and Collections, by Maurice Naftalin and Philip WadlerEffective Jav...  阅读全文
posted @ 2013-02-21 11:31 brock| 编辑 收藏

     摘要: 浅拷贝就比如像引用类型,而深拷贝就比如值类型。  浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。举个例子,一个人一开始叫张三,后来改名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。...  阅读全文
posted @ 2013-02-21 11:03 brock| 编辑 收藏

Hashmap loadFactor设置初使化值的时候必须设置 loadFactor

1、请查看 hashmap 如何初使化

 

代码:

 public HashMap(int initialCapacity, float loadFactor) {

        if (initialCapacity < 0)

            throw new IllegalArgumentException("Illegal initial capacity: " +

                                               initialCapacity);

        if (initialCapacity > MAXIMUM_CAPACITY)

            initialCapacity = MAXIMUM_CAPACITY;

        if (loadFactor <= 0 || Float.isNaN(loadFactor))

            throw new IllegalArgumentException("Illegal load factor: " +

                                               loadFactor);

 

        // Find a power of 2 >= initialCapacity

        int capacity = 1;

        while (capacity < initialCapacity)

            capacity <<= 1;

 

        this.loadFactor = loadFactor;

        threshold = (int)(capacity * loadFactor);

        table = new Entry[capacity];

        init();

}

 

Map map = new HashMap(9);

 

while (capacity < initialCapacity)

            capacity <<= 1;

 

capacity的容量为 16

threshold扩容阀值 16*0.75 =12

 

和9没什么关系 哈

 

Map map = new HashMap(91);

 

capacity的容量为 16

threshold扩容阀值 16*1 =16
不过这个 9 变小一点 就不一样了 如3时
capacity 是4



 

posted @ 2013-02-01 16:37 brock 阅读(2911) | 评论 (0)编辑 收藏


学了这么久的Java,才知道Java的对象引用类型有4种。所以,赶紧把不知道的东西补上!

    对于需要长期运行的应用程序来说,如果无用的对象所占用的内存空间不能得到即时的释放的话,那么在一个局部的时间段内便形成了事实上的内存泄露。

    以前我们学过,如果要及时地释放内存,最稳妥的方法就是使用完对象之后,立刻执行"object=null"语句。当然,这也是一种理想状态。

    JDK里面引入了4种对象引用类型,可以算是强行的调用System.gc()这个的垃圾回收的方法了。

   

    强引用:前面我们用的全部对象都是强引用类型的。这个就显示地执行"object=null"语句。

    软引用:被软引用的对象,如果内存空间足够,垃圾回收器是不会回收它的,如果内存空间不足,垃圾回收器将回收这些对象占用的内存空间。软件引用对应着java.lang.ref.SoftReference类,一个对象如果要被软引用,只需将其作为参数传入SoftReference类的构造方法中就行了。感觉还是比较简单而且容易理解。

    弱引用:与前面的软引用相比,被弱引用了的对象拥有更短的内存时间(也就是生命周期)。垃圾回收器一旦发现了被弱引用的对象,不管当前内存空间是不是足够,都会回收它的内存,弱引用对应着java.lang.ref.WeakReference类,同样的道理。一个对象如果想被弱引用,只需将其作为参数传入WeakReference类的构造方法中就行了。

    虚引用:虚引用不是一种真实可用的引用类型,完全可以视为一种“形同虚设”的引用类型。设计虚引用的目的在于结合引用关联队列,实现对对象引用关系的跟踪(太高科技了,这几句话。目前还不知道是什么意思)。虚引用对应着java.lang.ref.PhantomReference类。一个对象如果要被虚引用,只需将其作为参数传入PhantomReference类的构造方法中就行了,同时作为参数传入的还有引用关联队列java.lang.ref.ReferenceQueue的对象实例。(没懂)

    SoftReference,WeakReference,PhantomReference类都继承自java.lang.ref.Reference抽象类。Reference抽象类定义了clear() 方法用于撤销引用关系,get()方法用于返回被引用的对象。

    摘抄一段代码示例:

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.Set;
import java.util.HashSet;

public class TestReferences
{
    public static void main(String[] args)
    {
        int length=10;
       
        //创建length个MyObject对象的强引用
        Set<MyObject> a = new HashSet<MyObject>();
        for(int i = 0; i < length; i++)
        {
            MyObject ref=new MyObject("Hard_" + i);
            System.out.println("创建强引用:" +ref);
            a.add(ref);
        }
        //a=null;
        System.gc();
       
        //创建length个MyObject对象的软引用
        Set<SoftReference<MyObject>> sa = new HashSet<SoftReference<MyObject>>();
        for(int i = 0; i < length; i++)
        {
            SoftReference<MyObject> ref=new SoftReference<MyObject>(new MyObject("Soft_" + i));
            System.out.println("创建软引用:" +ref.get());
            sa.add(ref);
        }
        System.gc();

        //创建length个MyObject对象的弱引用
        Set<WeakReference<MyObject>> wa = new HashSet<WeakReference<MyObject>>();
        for(int i = 0; i < length; i++)
        {
            WeakReference<MyObject> ref=new WeakReference<MyObject>(new MyObject("Weak_" + i));
            System.out.println("创建弱引用:" +ref.get());
            wa.add(ref);
        }
        System.gc();

        //创建length个MyObject对象的虚引用
        ReferenceQueue<MyObject> rq = new ReferenceQueue<MyObject>();
        Set<PhantomReference<MyObject>> pa = new HashSet<PhantomReference<MyObject>>();
        for(int i = 0; i < length; i++)
        {
            PhantomReference<MyObject> ref = new PhantomReference<MyObject>(new MyObject("Phantom_" + i), rq);
            System.out.println("创建虚引用:" +ref.get());
            pa.add(ref);
        }
        System.gc();
    }
}

class MyObject
{
    private String id;

    public MyObject(String id)
    {
        this.id = id;
    }

    public String toString()
    {
        return id;
    }

    public void finalize()
    {
        System.out.println("回收对象:" + id);
    }
}

 

posted @ 2013-01-21 16:40 brock 阅读(254) | 评论 (0)编辑 收藏

一直在学习Java,碰到了很多问题,碰到了很多关于i++和++i的难题,以及最经典的String str = "abc" 共创建了几个对象的疑难杂症。 知道有一日知道了java的反汇编 命令 javap。现将学习记录做一小结,以供自己以后翻看。如果有错误的地方,请指正

1.javap是什么:

where options include:
-c Disassemble the code
-classpath <pathlist> Specify where to find user class files
-extdirs <dirs> Override location of installed extensions
-help Print this usage message
-J<flag> Pass <flag> directly to the runtime system
-l Print line number and local variable tables
-public Show only public classes and members
-protected Show protected/public classes and members
-package Show package/protected/public classes
and members (default)
-private Show all classes and members
-s Print internal type signatures
-bootclasspath <pathlist> Override location of class files loaded
by the bootstrap class loader
-verbose Print stack size, number of locals and args for met
hods
If verifying, print reasons for failure 

以上为百度百科里对它的描述,只是介绍了javap的一些参数和使用方法,而我们要用的就是这一个:-c Disassemble the code。

明确一个问题:javap是什么?网上有人称之为 反汇编器,可以查看java编译器为我们生成的字节码。通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。

2.初步认识javap

从一个最简单的例子开始:

这个例子中,我们只是简单的声明了两个int型变量并赋上初值。下面我们看看javap给我们带来了什么:(当然执行javap命令前,你得首先配置好自己的环境,能用javac编译通过了,即:javac TestJavap.java )

我们只看(方便起见,将注释写到每句后面)

Code:
0: iconst_2
 //把2放到栈顶
1: istore_1 //把栈顶的值放到局部变量1中,即i中
2: iconst_3 //把3放到栈顶
3: istore_2 //把栈顶的值放到局部变量1中,即j中
4: return

是不是很简单?(当然,估计需要点数据结构的知识) ,那我们就补点java的关于堆栈的知识:

对于 int i = 2;首先它会在栈中创建一个变量为i的引用,然后查找有没有字面值为2的地址,没找到,就开辟一个存放2这个字面值的地址,然后将i指向2的地址。

看了这段话,再比较下上面的注释,是不是完全吻合?

为了验证上面这一说法,我们继续实验:

我们将 i 和 j的值都设为2。按照以上理论,在声明j的时候,会去栈中招有没有字面值为2的地址,由于在栈中已经有2这个字面值,便将j直接指向2的地址。这样,就出现了i与j同时均指向2的情况。

拿出javap -c进行反编译:结果如下:

Code:
0: iconst_2 //把2放到栈顶
1: istore_1 //把栈顶的值放到局部变量1中,即i中
2: iconst_2 //把2放到栈顶
3: istore_2 //把栈顶的值放到局部变量2中,即j中(i 和 j同时指向2)
4: return

虽然这里说i和j同时指向2,但这里不等于说i和j指向同一块地址(java是不允许程序员直接修改堆栈中的数据的,所以就不要想着,我是不是可以修改栈中的2,那样岂不是i和j的值都会变化。另:在编译器内部,遇到j=2;时,它就会重新搜索栈中是否有2的字面值,如果没有,重新开辟地址存放2的值;如果已经有了,则直接将j指向这个地址。因此,就算j另被赋值为其他值,如j=4,j值的改变不会影响到i的值。)

再来一个例子:

还是javap -c

Code:
0: iconst_2 //把2放到栈顶
1: istore_1 //把栈顶的值放到局部变量1中,即i中
2: iload_1 //把i的值放到栈顶,也就是说此时栈顶的值是2
3: istore_2 //把栈顶的值放到局部变量2中,即j中
4: return

看到这里是不是有点明确了?

 

 

既然我们对javap有了一定的了解,那我们就开始用它来解决一些实际的问题:

1.i++和++i的问题

反编译结果为

Code:
0: iconst_1
1: istore_1
2: iinc 1, 1 //这个个指令,把局部变量1,也就是i,增加1,这个指令不会导致栈的变化,i此时变成2了
5: iconst_1
6: istore_2
7: iinc 2, 1//这个个指令,把局部变量2,也就是j,增加1,这个指令不会导致栈的变化,j此时变成2了
10: return

可以看出,++在前在后,在这段代码中,没有任何不同。

我们再看另一段代码:

反编译结果:

Code:
0: iconst_1
1: istore_1
2: iload_1
3: iinc 1, 1 //局部变量1(即i)加1变为2,注意这时栈中仍然是1,没有改变
6: istore_1 //把栈顶的值放到局部变量1中,即i这时候由2变成了1
7: iconst_1
8: istore_2
9: iinc 2, 1 //局部变量2(即j)加1变为2,注意这时栈中仍然是1,没有改变
12: iload_2 //把局部变量2(即j)的值放到栈顶,此时栈顶的值变为2
13: istore_2 //把栈顶的值放到局部变量2中,即j这时候真正由1变成了2
14: return

是否看明白了? 如果这个看明白了,那么下面的一个问题应该就是迎刃而解了:

m = m ++;这句话,java虚拟机执行时是这样的: m的值加了1,但这是栈中的值还是0, 马上栈中的值覆盖了m,即m变成0,因此不管循环多少次,m都等于0。

如果改为m = ++m; 程序运行结果就是100了。。。

 

 

posted @ 2013-01-21 15:26 brock 阅读(364) | 评论 (1)编辑 收藏

public static void main(String[] args) {
Calendar c = Calendar.getInstance();
System.out.println(c.get(Calendar.YEAR) * 100 + c.get(Calendar.WEEK_OF_YEAR));
c.set(Calendar.YEAR, 2013);
c.set(Calendar.WEEK_OF_YEAR, c.get(Calendar.WEEK_OF_YEAR));
int w = c.get(Calendar.DAY_OF_WEEK);
for (int i = 1; i <= 7; i++) {
c.set(Calendar.DAY_OF_WEEK, i);
System.out.println("该周第一天是[" + DateFormatUtils.format(c, "yyyy-MM-dd") + "]");
}
int dd = 201205;
System.out.println(dd / 100);
System.out.println(dd % (dd / 100));
}
posted @ 2013-01-10 10:56 brock 阅读(184) | 评论 (0)编辑 收藏

public static void main(String[] args) {
List<Integer> a = new ArrayList<Integer>();
a.add(1);
a.add(5);
a.add(7);
a.add(9);
List<Integer> b = new ArrayList<Integer>();
b.add(2);
b.add(4);
b.add(8);
List<Integer> c = new ArrayList<Integer>();
c.addAll(a);
c.addAll(b);
List<Integer> d = new ArrayList<Integer>();
for (Integer dd : b) {
d.add(dd);
}
// Integer
Collections.sort(c, new Comparator<Integer>() {
@Override
public int compare(Integer source, Integer desc) {
if (source.compareTo(desc) > 0) {
return 1;
}
return -1;
}
});
for (int j = 0; j < a.size(); j++) {
for (int k = 0; k < b.size(); k++) {
if (a.get(j) > b.get(k)) {
if (k == b.size() - 1) {
b.add(b.get(b.size() - 1));
break;
}
continue;
}
//
if (a.get(j) < b.get(k)) {
if (k == 0) {
b.add(k, 0);
} else {
b.add(k, b.get(k - 1));
}
break;
}
}
}
for (int j = 0; j < d.size(); j++) {
for (int k = 0; k < a.size(); k++) {
if (d.get(j) > a.get(k)) {
if (k == a.size() - 1) {
a.add(a.get(a.size() - 1));
break;
}
continue;
}
//
if (d.get(j) < a.get(k)) {
if (k == 0) {
a.add(k, 0);
} else {
a.add(k, a.get(k - 1));
}
break;
}
}
}
System.out.println(c);
System.out.println(a);
System.out.println(b);
}
posted @ 2013-01-07 15:13 brock 阅读(297) | 评论 (0)编辑 收藏

Java.Lang.NoSuchMethodError:仔细检查,原来我自己将tomcat下的lib也导入进来了,里面有一个commons-collection.jar(2.0版本),晕啊!马上砍掉,导入commons-collection.jar 3.0版本,一切OK,郁闷了一个晚上!!!! 
he.Commons.Collections
 
posted @ 2012-10-10 10:15 brock 阅读(278) | 评论 (0)编辑 收藏

    首先感谢阿宝同学的帮助,我才对这个gc算法的调整有了一定的认识,而不是停留在过去仅仅了解的阶段。在读过sun的文档和跟阿宝讨论之后,做个小小的总结,如果有谬误,敬请指正。
    CMS,全称Concurrent Low Pause Collector,是jdk1.4后期版本开始引入的新gc算法,在jdk5和jdk6中得到了进一步改进,它的主要适合场景是对响应时间的重要性需求 大于对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。CMS是用于对tenured generation的回收,也就是年老代的回收,目标是尽量减少应用的暂停时间,减少full gc发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。在我们的应用中,因为有缓存的存在,并且对于响应时间也有比较高的要求,因此希 望能尝试使用CMS来替代默认的server型JVM使用的并行收集器,以便获得更短的垃圾回收的暂停时间,提高程序的响应性。
    CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:
    初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) -> 重新标记(CMS-remark) -> 并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)
    其中的1,3两个步骤需要暂停所有的应用程序线程的。第一次暂停从root对象开始标记存活的对象,这个阶段称为初始标记;第二次暂停是在并发标记之后, 暂停所有应用程序线程,重新标记并发标记阶段遗漏的对象(在并发标记阶段结束后对象状态的更新导致)。第一次暂停会比较短,第二次暂停通常会比较长,并且 remark这个阶段可以并行标记。

    而并发标记、并发清除、并发重设阶段的所谓并发,是指一个或者多个垃圾回收线程和应用程序线程并发地运行,垃圾回收线程不会暂停应用程序的执行,如果你有多于一个处理器,那么并发收集线程将与应用线程在不同的处理器上运行,显然,这样的开销就是会降低应用的吞吐量。Remark阶段的并行,是指暂停了所有应用程序后,启动一定数目的垃圾回收进程进行并行标记,此时的应用线程是暂停的。

    CMS的young generation的回收采用的仍然是并行复制收集器,这个跟Paralle gc算法是一致的。

    下面是参数介绍和遇到的问题总结,

1、启用CMS:-XX:+UseConcMarkSweepGC。 咳咳,这里犯过一个低级错误,竟然将+号写成了-号

 

2。CMS默认启动的回收线程数目是  (ParallelGCThreads + 3)/4) ,如果你需要明确设定,可以通过-XX:ParallelCMSThreads=20来设定,其中ParallelGCThreads是年轻代的并行收集线程数


3、CMS是不会整理堆碎片的,因此为了防止堆碎片引起full gc,通过会开启CMS阶段进行合并碎片选项:-XX:+UseCMSCompactAtFullCollection,开启这个选项一定程度上会影响性能,阿宝的blog里说也许可以通过配置适当的CMSFullGCsBeforeCompaction来调整性能,未实践。

4.为了减少第二次暂停的时间,开启并行remark: -XX:+CMSParallelRemarkEnabled。如果remark还是过长的话,可以开启-XX:+CMSScavengeBeforeRemark选项,强制remark之前开始一次minor gc,减少remark的暂停时间,但是在remark之后也将立即开始又一次minor gc。

5.为了避免Perm区满引起的full gc,建议开启CMS回收Perm区选项:

+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled


6.默认CMS是在tenured generation沾满68%的时候开始进行CMS收集,如果你的年老代增长不是那么快,并且希望降低CMS次数的话,可以适当调高此值:
-XX:CMSInitiatingOccupancyFraction=80

这里修改成80%沾满的时候才开始CMS回收。

7.年轻代的并行收集线程数默认是(cpu <= 8) ? cpu : 3 + ((cpu * 5) / 8),如果你希望降低这个线程数,可以通过-XX:ParallelGCThreads= N 来调整。

8.进入重点,在初步设置了一些参数后,例如:

 

Java代码  收藏代码
  1. -server -Xms1536m -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=64m  
  2. -XX:MaxPermSize=64m -XX:-UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection  
  3. -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSParallelRemarkEnabled  
  4. -XX:SoftRefLRUPolicyMSPerMB=0  

 

需要在生产环境或者压测环境中测量这些参数下系统的表现,这时候需要打开GC日志查看具体的信息,因此加上参数:

-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/home/test/logs/gc.log

在运行相当长一段时间内查看CMS的表现情况,CMS的日志输出类似这样:

 

Java代码  收藏代码
  1. 4391.322: [GC [1 CMS-initial-mark: 655374K(1310720K)] 662197K(1546688K), 0.0303050 secs] [Times: user=0.02 sys=0.02, real=0.03 secs]  
  2. 4391.352: [CMS-concurrent-mark-start]  
  3. 4391.779: [CMS-concurrent-mark: 0.427/0.427 secs] [Times: user=1.24 sys=0.31, real=0.42 secs]  
  4. 4391.779: [CMS-concurrent-preclean-start]  
  5. 4391.821: [CMS-concurrent-preclean: 0.040/0.042 secs] [Times: user=0.13 sys=0.03, real=0.05 secs]  
  6. 4391.821: [CMS-concurrent-abortable-preclean-start]  
  7. 4392.511: [CMS-concurrent-abortable-preclean: 0.349/0.690 secs] [Times: user=2.02 sys=0.51, real=0.69 secs]  
  8. 4392.516: [GC[YG occupancy: 111001 K (235968 K)]4392.516: [Rescan (parallel) , 0.0309960 secs]4392.547: [weak refs processing, 0.0417710 secs] [1 CMS-remark: 655734K(1310720K)] 766736K(1546688K), 0.0932010 secs] [Times: user=0.17 sys=0.00, real=0.09 secs]  
  9. 4392.609: [CMS-concurrent-sweep-start]  
  10. 4394.310: [CMS-concurrent-sweep: 1.595/1.701 secs] [Times: user=4.78 sys=1.05, real=1.70 secs]  
  11. 4394.310: [CMS-concurrent-reset-start]  
  12. 4394.364: [CMS-concurrent-reset: 0.054/0.054 secs] [Times: user=0.14 sys=0.06, real=0.06 secs]  
 


其中可以看到CMS-initial-mark阶段暂停了0.0303050秒,而CMS-remark阶段暂停了0.0932010秒,因此两次暂停的总共时间是0.123506秒,也就是123毫秒左右。两次短暂停的时间之和在200以下可以称为正常现象。

但是你很可能遇到两种fail引起full gc:Prommotion failed和Concurrent mode failed。

Prommotion failed的日志输出大概是这样:

 

Java代码  收藏代码
  1. [ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]42576.951: [CMS: 1139969K->1120688K(  
  2. 166784K), 9.2214860 secs] 1458785K->1120688K(2520704K), 9.4584090 secs]  


这个问题的产生是由于救助空间不够,从而向年老代转移对象,年老代没有足够的空间来容纳这些对象,导致一次full gc的产生。解决这个问题的办法有两种完全相反的倾向:增大救助空间、增大年老代或者去掉救助空间。 增大救助空间就是调整-XX:SurvivorRatio参数,这个参数是Eden区和Survivor区的大小比值,默认是32,也就是说Eden区是 Survivor区的32倍大小,要注意Survivo是有两个区的,因此Surivivor其实占整个young genertation的1/34。调小这个参数将增大survivor区,让对象尽量在survitor区呆长一点,减少进入年老代的对象。去掉救助空 间的想法是让大部分不能马上回收的数据尽快进入年老代,加快年老代的回收频率,减少年老代暴涨的可能性,这个是通过将-XX:SurvivorRatio 设置成比较大的值(比如65536)来做到。在我们的应用中,将young generation设置成256M,这个值相对来说比较大了,而救助空间设置成默认大小(1/34),从压测情况来看,没有出现prommotion failed的现象,年轻代比较大,从GC日志来看,minor gc的时间也在5-20毫秒内,还可以接受,因此暂不调整。

Concurrent mode failed的产生是由于CMS回收年老代的速度太慢,导致年老代在CMS完成前就被沾满,引起full gc,避免这个现象的产生就是调小-XX:CMSInitiatingOccupancyFraction参数的值,让CMS更早更频繁的触发,降低年老代被沾满的可能。我们的应用暂时负载比较低,在生产环境上年老代的增长非常缓慢,因此暂时设置此参数为80。在压测环境下,这个参数的表现还可以,没有出现过Concurrent mode failed。


参考资料:
JDK5.0垃圾收集优化之--Don't Pause》 by 江南白衣
《记一次Java GC调整经历》1,2 by Arbow
Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning
Tuning Garbage Collection with the 5.0 JavaTM Virtual Machine

posted @ 2012-09-12 12:59 brock 阅读(1181) | 评论 (1)编辑 收藏

Linux vim编辑命令总结

Posted on 2011-11-20 22:42 Biffo Lee 阅读(685) 评论(0编辑 收藏 

1.     启动vim编译器

vim filename                     打开原有的文件或创建一个新文件。

vim                                  打开一个新文件,在编辑过程中或结束编辑时再指定文件名。

vim –r filename                恢复因意外停机或终端连接中断而未及时保存最终编辑结果的文件。

view filename                   以只读方式打开文件。除了不能把编辑处理的最终结果写入文件保存之外,view的所有编辑功能均与vim无异。

2.     光标定位命令

←↑↓→                        将光标左移、上移、下移或右移一个字符(行)位置。

h j k l                              同上。

-                                     光标上移一行。

Enter键(或加号“+”)光标下移一行。

退格键                            将光标左移一个字符位置。

空格键                            将光标右移一个字符位置(命令模式)。

Ctrl+F                             往下(文件结尾方向)滚动一屏。

Ctrl+B                             往上(文件开始方向)滚动一屏。

Ctrl+D                             往下滚动半屏。

Ctrl+U                             往上滚动半屏。

Ctrl+E                             编辑窗口中的文件内容整体上移一行。

Ctrl+Y                             编辑窗口中的文件内容整体下移一行。

w                                     将光标右移一个字。光标停留在下一个字的字首位置。

W                                    将光标右移一个字。光标停留在下一个字的字首位置(即使两个字之间存在标点符号)。

b                                     将光标左移一个字。光标停留在下一个字的字首位置。

B                                     将光标左移一个字。光标停留在下一个字的字首位置(即使两个字之间存在标点符号)。

e                                      把光标移至当前所在字(或下一个字)的最后一个字符位置。

E                                     同上,只是以空格字符作为字的分隔符。

^                                      把光标移至当前行的起始位置,也即当前行的第一个非空白字符位置

0(零)                           同上

$                                      把光标移至当前行的行尾,也即当前行的最后一个字符位置。

H                                     把光标移至编辑窗口顶部第一行的行首位置。

M                                    把光标移至编辑窗口中间一行的行首位置。

L                                     把光标移至编辑窗口底部最后一行的行首位置。

3.     插入文本数据

a                                      在光标当前所在字符位置的后面输入文本数据。

A                                     在光标当前所在行的行尾(也即最后一个字符位置)后面输入文本数据。

i                                       在光标当前所在字符位置的前面输入文本数据。

I                                      在光标当前所在行的行首(也即在第一个非空白的起始字符)前面输入文本数据。

o                                      在光标当前所在行下面的行首位置输入文本数据。

O                                     在光标当前所在行上面的行首位置输入文本数据。

4.     修改文本

C                                     替换当前文本行光标所在字符位置之后的所有数据,以Esc键结束。

cw                                   替换光标当前所在字符位置及之后的整个字或部分字,以Esc键结束。

[n]cc                                替换当前行,或从当前行开始的n行文本,以Esc键结束。

[n]s                                  替换光标当前所在位置的单个字符,或从光标当前位置开始的n个字符,以Esc键结束。

S                                     替换当前行,以Esc键结束。

r                                      替换光标当前所在位置的单个字符。

r<Enter>                           断行。也可使用“a”或“i”命令加Enter及Esc键实现。

R                                     从光标当前所在的字符位置开始,替换随后的所有字符,直至按下Esc键。

xp                                    交换字符位置。交换光标当前所在位置开始字符位置。

~                                      转换光标当前所在位置字符的大小写。

u                                      撤销最近一次执行的编辑命令,或依次撤销先前执行的编辑命令。

:u                                     同上(ex编辑命令)。

U                                     撤销施与当前文本行的编辑处理。

5.     删除文本

[n]x                                 删除光标当前所在位置的字符,或删除从光标当前位置开始的n个字符。

[n]X                                删除光标当前所在位置的前一个字符,或删除光标当前所在位置之前的n个字符。

dw                                   删除光标当前所在位置的一个整字或部分字符。如果光标在字首,则删除整字。如果光标在字的中间任何位置,则删除光标位置及之后的字符。

[n]dd                                删除光标当前所在的文本行,或删除从当前行开始的n个文本行。

D                                     删除当前文本行从光标位置开始之后的所有字符。

dG                                   删除从当前行开始直至文件最后一行的所有文本行。

d[n]G                               删除从文件的第n行开始直至当前行的所有文本行。

:line#1,line#2 d                  删除从指定的行号line#1到line#2之间的所有文本行。

6.     复制与移动文本

[n]yy                               复制光标当前所在的文本行,或从当前行开始的n个文本行。

[n]Y                                同上。

p(小写)                       把复制或删除(“dd”命令)的文本行粘贴到光标所在行的下面。

P(大写)                       把复制或删除(“dd”命令)的文本行粘贴到光标所在行的上面。

:line#1,line#2 co line#3      把第line#1~line#2行复制到第line#3行之后。

:line#1,line#2 m line#3       把第line#1~line#2行移至第line#3行之后。

7.     设置行号显示

:set nu                              在编辑期间增加临时行号。

:set nonu                           撤销行号显示(默认情况)。

Ctrl+G                              显示当前文件的名字和当前文本行的行号。

8.     设置大小写字母检索准则

:set ic                                检索字符串时忽略字母的大小写。

:set noic                            检索字符串时严格区分字母的大小写(默认情况)。

9.     定位文本行

G                                     将光标移至文件的组后一行。

[n]G                                 将光标移至文件的第n行。

10. 检索与替换

:/string                              向前(文件结尾方向)检索指定的字符串。

:?string                             向后(文件开头方向)检索指定的字符串。

n                                      将检索方向找出下一个匹配的字符串。

N                                     逆检索方向找出前一个匹配的字符串。

:[g]/search/s//replace/[g][c] 检索并替换字符串。

11. 清除屏幕

Ctrl+L                              清除因其他进程的输出信息而干扰的编辑窗口。

12. 合并文件与合并行

:r filename                        在光标所在行之后插入指定文件的内容。

: line#1 r filename              在第line#1行之后插入指定文件的内容。

J                                      把相邻的两个文本行个并为一行(把下一行合并到光标当前所在行的后面)。

13. 保存编辑结果与退出vim编辑器

:w                                    保存编辑处理后的结果(把内存缓冲区中的数据写到文件中)。

:w!                                   强制保存编辑处理后的结果。

:wq                                  保存编辑处理后的结果,然后退出vim编辑器。

:wq!                                 强制保存编辑处理后的结果,然后退出vim编辑器。

ZZ                                   保存编辑处理后的结果,然后退出vim编辑器。

:q                                     在未做任何编辑处理时,可以使用此命令退出vim编辑器。

:q!                                    强制退出vim编辑器,放弃编辑处理后的结果。

:w filename                       把编辑处理后的结果写到指定的文件中保存。

:w! filename                      把编辑处理后的结果强制写到指定的文件中保存,即使文件已经存在。

:wq! filename                    把编辑处理后的结果强制写到指定的文件中保存,即使文件已经存在,然后退出vim编辑器。

14. 其他

;f 或 Ctrl+G                     显示文件的名字、编辑状态、文件总的行数、光标当前所在行号和列号,以及当前行之前的行数占整个文件总行数的百分比。

Ctrl+V                              输入控制字符。

posted @ 2012-09-04 17:07 brock 阅读(322) | 评论 (0)编辑 收藏

最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下。

由于Java泛型的实现机制,使用了泛型的代码在运行期间相关的泛型参数的类型会被擦除,我们无法在运行期间获知泛型参数的具体类型(所有的泛型类型在运行时都是Object类型)。

但是有的时候,我们确实需要获知泛型参数的类型,比如将使用了泛型的Java代码序列化或者反序列化的时候,这个时候问题就变得比较棘手。

1
2
3
4
5
6
7
8
class Foo<T> {
  T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly
 
gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar

 

对于上面的类Foo<T>,由于在运行期间无法得知T的具体类型,对这个类的对象进行序列化和反序列化都不能正常进行。Gson通过借助TypeToken类来解决这个问题。

1
2
3
4
5
6
7
8
TestGeneric<String> t = new TestGeneric<String>();
  t.setValue("Alo");
  Type type = new TypeToken<TestGeneric<String>>(){}.getType();
   
  String gStr = GsonUtils.gson.toJson(t,type);
  System.out.println(gStr);
  TestGeneric t1 = GsonUtils.gson.fromJson(gStr, type);
  System.out.println(t1.getValue());

 

TypeToken的使用非常简单,如上面的代码,只要将需要获取类型的泛型类作为TypeToken的泛型参数构造一个匿名的子类,就可以通过getType()方法获取到我们使用的泛型类的泛型参数类型。

下面来简单分析一下原理。

要获取泛型参数的类型,一般的做法是在使用了泛型的类的构造函数中显示地传入泛型类的Class类型作为这个泛型类的私有属性,它保存了泛型类的类型信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Foo<T>{
  
 public Class<T> kind;
  
 public Foo(Class<T> clazz){
  this.kind = clazz;
 }
  
 public T[] getInstance(){
  return (T[])Array.newInstance(kind, 5);
 }
  
 public static void main(String[] args){
  Foo<String> foo = new Foo(String.class);
  String[] strArray = foo.getInstance();
 }
 
}

 

这种方法虽然能解决问题,但是每次都要传入一个Class类参数,显得比较麻烦。Gson库里面对于这个问题采用了了另一种解决办法。

同样是为了获取Class的类型,可以通过另一种方式实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class Foo<T>{
  
 Class<T> type;
  
 public Foo(){
  this.type = (Class<T>) getClass();
 }
 
        public static void main(String[] args) {
   
  Foo<String> foo = new Foo<String>(){};
  Class mySuperClass = foo.getClass();
 
 }
  
}

 

声明一个抽象的父类Foo,匿名子类将泛型类作为Foo的泛型参数传入构造一个实例,再调用getClass方法获得这个子类的Class类型。

这里虽然通过另一种方式获得了匿名子类的Class类型,但是并没有直接将泛型参数T的Class类型传进来,那又是如何获得泛型参数的类型的呢, 这要依赖Java的Class字节码中存储的泛型参数信息。Java的泛型机制虽然在运行期间泛型类和非泛型类都相同,但是在编译java源代码成 class文件中还是保存了泛型相关的信息,这些信息被保存在class字节码常量池中,使用了泛型的代码处会生成一个signature签名字段,通过 签名signature字段指明这个常量池的地址。

关于class文件中存储泛型参数类型的具体的详细的知识可以参考这里:http://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files

JDK里面提供了方法去读取这些泛型信息的方法,再借助反射,就可以获得泛型参数的具体类型。同样是对于第一段代码中的foo对象,通过下面的代码可以得到foo<T>中的T的类型:

1
2
3
Type mySuperClass = foo.getClass().getGenericSuperclass();
  Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];
System.out.println(type);

 

运行结果是class java.lang.String。

分析一下这段代码,Class类的getGenericSuperClass()方法的注释是:

Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by thisClass.

If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code. The parameterized type representing the superclass is created if it had not been created before. See the declaration of ParameterizedType for the semantics of the creation process for parameterized types. If thisClass represents either theObject class, an interface, a primitive type, or void, then null is returned. If this object represents an array class then theClass object representing theObject class is returned

概括来说就是对于带有泛型的class,返回一个ParameterizedType对象,对于Object、接口和原始类型返回null,对于数 组class则是返回Object.class。ParameterizedType是表示带有泛型参数的类型的Java类型,JDK1.5引入了泛型之 后,Java中所有的Class都实现了Type接口,ParameterizedType则是继承了Type接口,所有包含泛型的Class类都会实现 这个接口。

实际运用中还要考虑比较多的情况,比如获得泛型参数的个数避免数组越界等,具体可以参看Gson中的TypeToken类及ParameterizedTypeImpl类的代码。

posted @ 2012-08-01 16:26 brock 阅读(42666) | 评论 (6)编辑 收藏

官网:http://lucene.apache.org/solr/index.html 
http://wiki.apache.org/solr/ 
http://wiki.apache.org/solr/UpdateXmlMessages 
教程 
http://lucene.apache.org/solr/api/doc-files/tutorial.html 
http://www.ibm.com/developerworks/cn/java/j-solr1/ 
http://www.ibm.com/developerworks/cn/java/j-solr2/ 
Apache Solr 初级教程 
一些博客 
http://www.cnblogs.com/wycg1984/category/238032.html 
http://www.cnblogs.com/ibook360/tag/Solr/ 
http://blog.chenlb.com/category/solr-search 
http://www.webguo.com/?s=solr 
http://www.kafka0102.com/2010/08/319.html 
posted @ 2012-07-25 19:13 brock 阅读(243) | 评论 (0)编辑 收藏

在 Response-Header 中加上这几项:

Last-Modified: Wed, 18 Jun 2008 14:22:27 GMT
Cache-Control: max-age=600
Expires: Wed, 18 Jun 2008 14:48:39 GMT
Date: Wed, 18 Jun 2008 14:38:39 GMT


其中 Last-Modified 后面的日期是上次更新 config 的时间,Date 后面是当前时间,Expires 后面是当前时间 + 10分钟,10分钟就是 Cache-Control 后面的 max-age,单位是秒。因为看到 GAE 对 static 文件的 Cache 时间也是10分钟,所以我使用了这个数字。

Last-Modified

如果客户端收到的 Response 中包含 Last-Modified,那么下次 request 的时候就会在 Request Header 中包含 If-Modified-Since 字段,值就是上次服务器发送的 Last-Modified,服务器端会判断上次的 config 时间是否比 If-Modified-Since 晚。如果自上次 request 之后又更新了 config,那么服务器就会返回完整的内容;如果期间没有更新 config,那么服务器就没必要返回完整的内容,只需要向客户端发送一个 304 Not Modified 状态码就可以了。

Cache-Control、Date 和 Expires

这几个参数的组合,表示告诉浏览器:这个文件在多长时间之内不会更改,在这个时间内不需要再 request,保守起见,我设置了10分钟。

浏览器行为

如果只是在网站的链接之间 click click click,那么浏览器会完全遵守上述行为。这样可以尽可能地减少请求次数,以及 response 的数据量。

如果在某个页面点击了浏览器的刷新按钮或者按 F5,浏览器会忽略 Expires 时间,把该页面需要的所有的文件都重新请求一遍。

如果按住 Ctrl 再刷新或者 Ctrl-F5 (俗称强制刷新),浏览器将不会发送 Last-Modified Header,将所有需要的文件请求一遍,服务器会返回文件的完整内容,而不是仅仅一个 304 Not Modified 状态码。

后记

经初步观察,现在浏览器不会每次都彪呼呼地去请求一大堆 css、jpg、gif 文件了,浏览器也不会每次都脑残地返回完整内容了,看来是有效了。

posted @ 2012-07-24 17:29 brock 阅读(18895) | 评论 (0)编辑 收藏

最近在VPS上尝试配置安装一个网站,VPS安装了LNMP(Linux+Nginx+MySQL+php)在配置重定规则的时候经常遇到一些问题,直接用Apache的规则到Nginx下没起作用。原来Apache 重写的规则到nginx上还有一些不太一样的地方。

这里只是简单记录一些学习示例,高手略过,新手可以看一下。

Nginx Rewrite规则相关指令
Nginx Rewrite规则相关指令有if、rewrite、set、return、break等,其中rewrite是最关键的指令。一个简单的Nginx Rewrite规则语法如下:

rewrite ^/b/(.*)\.html /play.php?video=$1 break;

如果加上if语句,示例如下:

if (!-f $request_filename)

rewrite ^/img/(.*)$ /site/$host/images/$1 last;

Nginx与Apache的Rewrite规则实例对比

简单的Nginx和Apache 重写规则区别不大,基本上能够完全兼容。例如:

Apache Rewrite 规则:

RewriteRule ^/(mianshi|xianjing)/$ /zl/index.php?name=$1 [L]

RewriteRule ^/ceshi/$ /zl/ceshi.php [L]

RewriteRule ^/(mianshi)_([a-zA-Z]+)/$ /zl/index.php?name=$1_$2 [L]

RewriteRule ^/pingce([0-9]*)/$ /zl/pingce.php?id=$1 [L]

Nginx Rewrite 规则:

rewrite ^/(mianshi|xianjing)/$ /zl/index.php?name=$1 last;

rewrite ^/ceshi/$ /zl/ceshi.php last;

rewrite ^/(mianshi)_([a-zA-Z]+)/$ /zl/index.php?name=$1_$2 last;

rewrite ^/pingce([0-9]*)/$ /zl/pingce.php?id=$1 last;

由以上示例可以看出,Apache的Rewrite规则改为Nginx的Rewrite规则,其实很简单:Apache的RewriteRule指令换成Nginx的rewrite指令,Apache的[L]标记换成Nginx的last标记,中间的内容不变。

如果Apache的Rewrite规则改为Nginx的Rewrite规则后,使用nginx -t命令检查发现nginx.conf配置文件有语法错误,那么可以尝试给条件加上引号。例如一下的Nginx Rewrite规则会报语法错误:

rewrite ^/([0-9]{5}).html$ /x.jsp?id=$1 last;

加上引号就正确了:
rewrite “^/([0-9]{5}).html$” /x.jsp?id=$1 last;

Apache与Nginx的Rewrite规则在URL跳转时有细微的区别:

Apache Rewrite 规则:
RewriteRule ^/html/tagindex/([a-zA-Z]+)/.*$ /$1/ [R=301,L]

Nginx Rewrite 规则:
rewrite ^/html/tagindex/([a-zA-Z]+)/.*$ http://$host/$1/ permanent;

以上示例中,我们注意到,Nginx Rewrite 规则的置换串中增加了“http://$host”,这是在Nginx中要求的。

另外,Apache与Nginx的Rewrite规则在变量名称方面也有区别,例如:

Apache Rewrite 规则:
RewriteRule ^/user/login/$ /user/login.php?login=1&forward=http://%{HTTP_HOST} [L]

Nginx Rewrite 规则:
rewrite ^/user/login/$ /user/login.php?login=1&forward=http://$host   last;

Apache与Nginx Rewrite 规则的一些功能相同或类似的指令、标记对应关系:

Apache的RewriteCond指令对应Nginx的if指令;
Apache的RewriteRule指令对应Nginx的rewrite指令;
Apache的[R]标记对应Nginx的redirect标记;
Apache的[P]标记对应Nginx的last标记;
Apache的[R,L]标记对应Nginx的redirect标记;
Apache的[P,L]标记对应Nginx的last标记;
Apache的[PT,L]标记对应Nginx的last标记;

允许指定的域名访问本站,其他域名一律跳转到http://www.aaa.com

Apache Rewrite 规则:
RewriteCond %{HTTP_HOST}    ^(.*?)\.domain\.com$
RewriteCond %{HTTP_HOST}    !^qita\.domain\.com$
RewriteCond %{DOCUMENT_ROOT}/market/%1/index.htm -f
RewriteRule ^/wu/$ /market/%1/index.htm [L]

Nginx的if指令不支持嵌套,也不支持AND、OR等多条件匹配,相比于Apache的RewriteCond,显得麻烦一些,但是,我们可以通过下一页的Nginx配置写法来实现这个示例:

Nginx Rewrite 规则:
if ($host ~* ^(.*?)\.domain\.com$) set $var_wupin_city $1;
     set $var_wupin ‘1′;

if ($host ~* ^qita\.domain\.com$)

    set $var_wupin ‘0′;

 if (!-f $document_root/market/$var_wupin_city/index.htm)

     set $var_wupin ‘0′;

if ($var_wupin ~ ‘1′)

    rewrite ^/wu/$ /market/$var_wupin_city/index.htm last;
}

 

rewrite 的语法

 

语法: rewrite regex replacement flag

默认: none

作用域: server, location, if

This directive changes URI in accordance with the regular expression and the replacement string. Directives are carried out in order of appearance in the configuration file.

这个指令根据表达式来更改URI,或者修改字符串。指令根据配置文件中的顺序来执行。

Be aware that the rewrite regex only matches the relative path instead of the absolute URL. If you want to match the hostname, you should use an if condition, like so:

注意重写表达式只对相对路径有效。如果你想配对主机名,你应该使用if语句。

rewrite只是会改写路径部分的东东,不会改动用户的输入参数,因此这里的if规则里面,你无需关心用户在浏览器里输入的参数,rewrite后会自动添加的因此,我们只是加上了一个?号和后面我们想要的一个小小的参数 ***https=1就可以了。

nginx的rewrite规则参考:

  1. ~ 为区分大小写匹配
  2. ~* 为不区分大小写匹配
  3. !~和!~*分别为区分大小写不匹配及不区分大小写不匹
  1. -f和!-f用来判断是否存在文件
  2. -d和!-d用来判断是否存在目录
  3. -e和!-e用来判断是否存在文件或目录
  4. -x和!-x用来判断文件是否可执行
  1. last 相当于Apache里的[L]标记,表示完成rewrite,呵呵这应该是最常用的
  2. break 终止匹配, 不再匹配后面的规则
  3. redirect 返回302临时重定向 地址栏会显示跳转后的地址
  4. permanent 返回301永久重定向 地址栏会显示跳转后的地址
  1. $args
  2. $content_length
  3. $content_type
  4. $document_root
  5. $document_uri
  6. $host
  7. $http_user_agent
  8. $http_cookie
  9. $limit_rate
  10. $request_body_file
  11. $request_method
  12. $remote_addr
  13. $remote_port
  14. $remote_user
  15. $request_filename
  16. $request_uri
  17. $query_string
  18. $scheme
  19. $server_protocol
  20. $server_addr
  21. $server_name
  22. $server_port
  23. $uri

结合QeePHP的例子

  1. if (!-d $request_filename) {
  2. rewrite ^/([a-z-A-Z]+)/([a-z-A-Z]+)/?(.*)$ /index.php?namespace=user&amp;controller=$1&amp;action=$2&amp;$3 last;
  3. rewrite ^/([a-z-A-Z]+)/?$ /index.php?namespace=user&amp;controller=$1 last;
  4. break;

多目录转成参数
abc.domian.com/sort/2 => abc.domian.com/index.php?act=sort&name=abc&id=2

  1. if ($host ~* (.*)\.domain\.com) {
  2. set $sub_name $1;
  3. rewrite ^/sort\/(\d+)\/?$ /index.php?act=sort&cid=$sub_name&id=$1 last;
  4. }

目录对换
/123456/xxxx -> /xxxx?id=123456

  1. rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;

例如下面设定nginx在用户使用ie的使用重定向到/nginx-ie目录下:

  1. if ($http_user_agent ~ MSIE) {
  2. rewrite ^(.*)$ /nginx-ie/$1 break;
  3. }

目录自动加“/”

  1. if (-d $request_filename){
  2. rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
  3. }

禁止htaccess

  1. location ~/\.ht {
  2. deny all;
  3. }

禁止多个目录

  1. location ~ ^/(cron|templates)/ {
  2. deny all;
  3. break;
  4. }

禁止以/data开头的文件
可以禁止/data/下多级目录下.log.txt等请求;

  1. location ~ ^/data {
  2. deny all;
  3. }

禁止单个目录
不能禁止.log.txt能请求

  1. location /searchword/cron/ {
  2. deny all;
  3. }

禁止单个文件

  1. location ~ /data/sql/data.sql {
  2. deny all;
  3. }

给favicon.ico和robots.txt设置过期时间;
这里为favicon.ico为99天,robots.txt为7天并不记录404错误日志

  1. location ~(favicon.ico) {
  2. log_not_found off;
  3. expires 99d;
  4. break;
  5. }

  6. location ~(robots.txt) {
  7. log_not_found off;
  8. expires 7d;
  9. break;
  10. }

设定某个文件的过期时间;这里为600秒,并不记录访问日志

  1. location ^~ /html/scripts/loadhead_1.js {
  2. access_log   off;
  3. root /opt/lampp/htdocs/web;
  4. expires 600;
  5. break;
  6. }

文件反盗链并设置过期时间
这里的return 412 为自定义的http状态码,默认为403,方便找出正确的盗链的请求
“rewrite ^/ http://leech.divmy.com/leech.gif;”显示一张防盗链图片
“access_log off;”不记录访问日志,减轻压力
“expires 3d”所有文件3天的浏览器缓存

  1. location ~* ^.+\.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ {
  2. valid_referers none blocked *.c1gstudio.com *.c1gstudio.net localhost 208.97.167.194;
  3. if ($invalid_referer) {
  4. rewrite ^/ http://leech.divmy.com/leech.gif;
  5. return 412;
  6. break;
  7. }
  8. access_log   off;
  9. root /opt/lampp/htdocs/web;
  10. expires 3d;
  11. break;
  12. }

只充许固定ip访问网站,并加上密码

  1. root  /opt/htdocs/www;
  2. allow   208.97.167.194;
  3. allow   222.33.1.2;
  4. allow   231.152.49.4;
  5. deny    all;
  6. auth_basic “C1G_ADMIN”;
  7. auth_basic_user_file htpasswd;

将多级目录下的文件转成一个文件,增强seo效果
/job-123-456-789.html 指向/job/123/456/789.html

  1. rewrite ^/job-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /job/$1/$2/jobshow_$3.html last;

将根目录下某个文件夹指向2级目录
如/shanghaijob/ 指向 /area/shanghai/
如果你将last改成permanent,那么浏览器地址栏显是/location/shanghai/

  1. rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2 last;

上面例子有个问题是访问/shanghai 时将不会匹配

  1. rewrite ^/([0-9a-z]+)job$ /area/$1/ last;
  2. rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2 last;

这样/shanghai 也可以访问了,但页面中的相对链接无法使用,
如./list_1.html真实地址是/area/shanghia/list_1.html会变成/list_1.html,导至无法访问。

那我加上自动跳转也是不行咯
(-d $request_filename)它有个条件是必需为真实目录,而我的rewrite不是的,所以没有效果

  1. if (-d $request_filename){
  2. rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
  3. }

知道原因后就好办了,让我手动跳转吧

  1. rewrite ^/([0-9a-z]+)job$ /$1job/ permanent;
  2. rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2 last;

文件和目录不存在的时候重定向:

  1. if (!-e $request_filename) {
  2. proxy_pass http://127.0.0.1;
  3. }

域名跳转

  1. server
  2. {
  3. listen       80;
  4. server_name  jump.88dgw.com;
  5. index index.html index.htm index.php;
  6. root  /opt/lampp/htdocs/www;
  7. rewrite ^/ http://www.88dgw.com/;
  8. access_log  off;
  9. }

多域名转向

  1. server_name  www.7oom.com/  www.divmy.com/;
  2. index index.html index.htm index.php;
  3. root  /opt/lampp/htdocs;
  4. if ($host ~ “c1gstudio\.net”) {
  5. rewrite ^(.*) http://www.7oom.com$1/ permanent;
  6. }

三级域名跳转

  1. if ($http_host ~* “^(.*)\.i\.c1gstudio\.com$”) {
  2. rewrite ^(.*) http://top.88dgw.com$1/;
  3. break;
  4. }

域名镜向

  1. server
  2. {
  3. listen       80;
  4. server_name  mirror.c1gstudio.com;
  5. index index.html index.htm index.php;
  6. root  /opt/lampp/htdocs/www;
  7. rewrite ^/(.*) http://www.divmy.com/$1 last;
  8. access_log  off;
  9. }

某个子目录作镜向

  1. location ^~ /zhaopinhui {
  2. rewrite ^.+ http://zph.divmy.com/ last;
  3. break;
  4. }

discuz ucenter home (uchome) rewrite

  1. rewrite ^/(space|network)-(.+)\.html$ /$1.php?rewrite=$2 last;
  2. rewrite ^/(space|network)\.html$ /$1.php last;
  3. rewrite ^/([0-9]+)$ /space.php?uid=$1 last;

discuz 7 rewrite

  1. rewrite ^(.*)/archiver/((fid|tid)-[\w\-]+\.html)$ $1/archiver/index.php?$2 last;
  2. rewrite ^(.*)/forum-([0-9]+)-([0-9]+)\.html$ $1/forumdisplay.php?fid=$2&page=$3 last;
  3. rewrite ^(.*)/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1/viewthread.php?tid=$2&extra=page\%3D$4&page=$3 last;
  4. rewrite ^(.*)/profile-(username|uid)-(.+)\.html$ $1/viewpro.php?$2=$3 last;
  5. rewrite ^(.*)/space-(username|uid)-(.+)\.html$ $1/space.php?$2=$3 last;
  6. rewrite ^(.*)/tag-(.+)\.html$ $1/tag.php?name=$2 last;

给discuz某版块单独配置域名

  1. server_name  bbs.c1gstudio.com news.c1gstudio.com;

  2. location = / {
  3. if ($http_host ~ news\.divmy.com$) {
  4. rewrite ^.+ http://news.divmy.com/forum-831-1.html last;
  5. break;
  6. }
  7. }

discuz ucenter 头像 rewrite 优化

  1. location ^~ /ucenter {
  2. location ~ .*\.php?$
  3. {
  4. #fastcgi_pass  unix:/tmp/php-cgi.sock;
  5. fastcgi_pass  127.0.0.1:9000;
  6. fastcgi_index index.php;
  7. include fcgi.conf;
  8. }

  9. location /ucenter/data/avatar {
  10. log_not_found off;
  11. access_log   off;
  12. location ~ /(.*)_big\.jpg$ {
  13. error_page 404 /ucenter/images/noavatar_big.gif;
  14. }
  15. location ~ /(.*)_middle\.jpg$ {
  16. error_page 404 /ucenter/images/noavatar_middle.gif;
  17. }
  18. location ~ /(.*)_small\.jpg$ {
  19. error_page 404 /ucenter/images/noavatar_small.gif;
  20. }
  21. expires 300;
  22. break;
  23. }
  24. }

jspace rewrite

  1. location ~ .*\.php?$
  2. {
  3. #fastcgi_pass  unix:/tmp/php-cgi.sock;
  4. fastcgi_pass  127.0.0.1:9000;
  5. fastcgi_index index.php;
  6. include fcgi.conf;
  7. }

  8. location ~* ^/index.php/
  9. {
  10. rewrite ^/index.php/(.*) /index.php?$1 break;
  11. fastcgi_pass  127.0.0.1:9000;
  12. fastcgi_index index.php;
  13. include fcgi.conf;
  14. }

另外这里还有一个工具可以直接把apache规则转化为nginx规则

http://www.anilcetin.com/convert-apache-htaccess-to-nginx/

参考:

http://wiki.nginx.org/NginxChsHttpRewriteModule

http://blog.csdn.net/cnbird2008/archive/2009/08/04/4409620.aspx

http://www.divmy.com/
posted @ 2012-07-11 09:47 brock 阅读(4297) | 评论 (0)编辑 收藏

memcached如何处理容错的?
不处理!:) 在memcached节点失效的情况下,集群没有必要做任何容错处理。如果发生了节点失效,应对的措施完全取决于用户。节点失效时,下面列出几种方案供您选择:
* 忽略它! 在失效节点被恢复或替换之前,还有很多其他节点可以应对节点失效带来的影响。
* 把失效的节点从节点列表中移除。做这个操作千万要小心!在默认情况下(余数式哈希算法),客户端添加或移除节点,会导致所有的缓存数据不可用!因为哈希参照的节点列表变化了,大部分key会因为哈希值的改变而被映射到(与原来)不同的节点上。
* 启动热备节点,接管失效节点所占用的IP。这样可以防止哈希紊乱(hashing chaos)。


同学们,根据上面的说法,memcached其中一个节点失效以后,memcached本身是没有任何策略维持失效转发的,这对于大型系统是一个无法接受的事实。

Memcached分布式每个服务器端本身没有相互相连的关系,数据分布是由客户端来维持的,也可以说Memcached还没有为集群提供真的高可用方案,因为从集群的定义上来说需要满足:1.压力分载 2.失效转发。

在项目组中lianjie.you同学问我如果在分布式中的其中一台Memcached节点down掉了,应该如何解决?我当时愣住了,一时之间还不能给出任何完整的答案。

今早在座公车来上班的路上用手机上网Google了一下,发现原来在网上有很多人与我们有相同的问题,我Google的关键字是 “Memcached 单点” 、“Memcached 单点故障”。给出的搜索结果都不算让人满意,我才打算写一篇关于解决集群中Memcached单点故障的文章。Javabloger只向大家提供2种解决 思路,暂时不提供具体代码。

现象描述:
在客户端连接的部分写入多个服务器端的ip地址,客户端将会自动的把缓存数据分布的放在每个不同的机器上,如图所示:

http://files.note.sdo.com/2011/04/25/5592/4134/1c75/P15SC~jrjKHFnM01o00E0-/17afb85b-7816-4ed7-be59-6cb81f8e7436.png
查看大图请点击这里

现象后果:
如果其中一个缓存节点的机器down机,那么客户端存入的缓存数据将会丢失一部分,就是图中红色字体描述的“Losed 33% Cache Data”,也就是说那部分数据彻底没有了!如果是用户的关键性信息那么就玩大了,如图所示:http://files.note.sdo.com/2011/04/25/5592/4134/1c75/P15SC~jrjKHFnM01o00E0-/3d9a8f33-0715-4522-a4af-4daa2644995d.png
查看大图请点击这里

解决方案1:本地备份缓存
在本地放一份缓存,同时也在分布式Memcached上放一份缓存,如果当其中一台节点当机了,客户端程序直接读取本地的缓存,本地客户端维护一个HashMap即可,这样的方案虽然很简陋,但是可以满足一部分场景的需要,当你很急需的时候可以作为临时方案暂时替代一下。

解决方案2:采用缓存代理服务器
采用 Magent 缓存代理,防止单点现象,缓存代理也可以做备份,通过客户端连接到缓存代理服务器,缓存代理服务器连接缓存服务器,缓存代理服务器可以连接多台Memcached机器可以将每台Memcached机器进行数据同步。这样的架构比较完善了,如果其中一台缓存代理服务器down机,系统依然可以继续工作,如果其中一台Memcached机器down掉,数据不会丢失并且可以保证数据的完整性,以上描述的系统架构如图所示:
http://files.note.sdo.com/2011/04/25/5592/4134/1c75/P15SC~jrjKHFnM01o00E0-/b009274d-77b3-49bb-a921-9953c378965c.png
查看大图请点击这里

还是那句话:没有任何架构是最完美的,只是最合适的,任何架构都不可能一步到位,都是经过一步一步演变过来的。

posted @ 2012-05-07 17:07 brock 阅读(5280) | 评论 (0)编辑 收藏

操作步骤:
sudo vim /home/admin/{app}/conf/tomcat-server.xml
修改 HTTP/1.1 Connector中的maxPostSize="10000"
以及AJP 1.3 Connector中的maxPostSize="10000"
然后
sudo -u admin cp /home/admin/{app}/conf/tomcat-server.xml /home/admin/{app}/.default/deploy/jboss-web.deployer/server.xml
下来
sudo -u admin /home/admin/{app}/bin/jbossctl restart {app}
最后检查一下应用



估计看pdf的人不多, 简述一下大概意思为:
常见的服务器会将用户post的数据保存在hashmap中. 而向hashmap中插入n对元素的时间复杂度大约是O(n), 但如果精心构造key使得每个key的hash值相同(也就是产生了碰撞),则时间复杂度会恶化到O(n^2),导致消耗大量的CPU时间.
经测试,在tomcat6服务器上, 总大小2MByte的数据就需要消耗一个i7CPU core44分钟,也就是6kbit/s就可以让这个CPU core一直忙碌. 所以只要一个G兆网络就能让100000个i7CPU core一直忙.

再说下相同hash值key的构造:
在java中,字符串的hash函数采用DJBX33A,只不过常数因子改为了31. 这样的函数有个特点,即如果字符串X, Y的hash值相同,那么X,Y都添加任意相同的前缀或后缀的以后的hash值也都相同.比如: "rQ"与 "qp"的hash值相同, 则"rQrQ", "rQqp", "qprQ", "qpqp" 这四个也相同,继续这个模式就可以很容易构造出 2^n 个 2*n长度的不同字符串

posted @ 2012-01-04 11:11 brock 阅读(380) | 评论 (0)编辑 收藏

栈内存

堆内存

基础类型,对象引用(堆内存地址

由new创建的对象和数组,

存取速度快

相对于栈内存较慢

数据大小声明周期必须确定

分配的内存由java虚拟机自动垃圾回收器管理。动态分配内存大小

共享特性

栈中如果有字符串,则直接引用

如果没有,开辟新的空间存入值

每new一次在堆内存中生成一个新的对象。

创建之后值可以改变

String类声明后则不可改变    

一、栈内存

基础类型int, short, long, byte, float, double, boolean, char和对象引用

栈的共享特性

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true

1、编译器先处理String str1 = "abc";它会在栈中创建一个变量为str1的引用,然后查找栈中是否有abc这个值,如果没找到,就将abc存放进来,然后将str1指向abc。

2、   接着处理String str2 = "abc";在创建完b的引用变量后,因为在栈中已经有abc这个值,便将str2直接指向abc。这样,就出现了str1与str2同时均指向abc的情况。

二、堆内存

new、newarray、anewarray和multianewarray等指令建立

  要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的 对象。只有通过new()方法才能保证每次都创建一个新的对象。 由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。

三、  ==   内存地址比对

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true    str1
和str2同时指向 栈内存 中同一个内存空间

String str3 = "abc";
String str4 = new String("abc") ;

System.out.println(str3 == str4);    //flase str3值在栈内存中,str4值在堆内存中

String hello = "hello" ;

String hel = "hel" ;

String lo = "lo" ;

System.out.println(hello == "hel" + "lo") ; //true

//两个常量相加,先检测栈内存中是否有hello如有有,指向已有的栈中的hello空间

System.out.println(hello == "hel" + lo) ;   //flase

System.out.println(hello == hel + lo) ;     //flase

 //lo是在常量池中,不检查栈内存,在堆中产生一个新的hello

 四、  equals  值进行比对

 public boolean equals(Object anObject)

将此字符串与指定的对象比较。当且仅当该参数不为 null,并且是与此对象表示相同字符序列的 String 对象时,结果才为 true。

 String str5 = "abc";
String str6 = new String("abc") ;

System.out.println(str5.equals(str6));    //true   str5的值str6的值比对

 五、  intern    栈中值的内存地址

Public String intern()

当调用 intern 方法时

1、如果池已经包含一个等于此 String 对象的字符串(用equals(Object) 方法确定),则返回池中的字符串。

2、将此 String 对象添加到池中,并返回此 String 对象的引用。

String s7 = new String("abc") ;

String s8 = "abc" ;

System.out.println(s7 == s7.intern()) ;//flase

System.out.println(s8 == s7.intern() );//true

1.检查栈内存中有没有abc对象如果有

2.将s7指向pool中abc

posted @ 2011-03-24 16:58 brock 阅读(4175) | 评论 (0)编辑 收藏

这个手机号码正则验证函数可以说是最新的都支持的,里面有详细的介绍说明,不论以后增加什么号段大家都非常容易的稍微修改一下即可。
javascript 手机号码正则表达式验证函数

代码如下:

//ip与域名验证函数
function checkIP()
{
var ipArray,ip,j;
ip = document.ipform.ip.value;

if(/[A-Za-z_-]/.test(ip)){
if (ip.indexOf(" ")>=0){
ip = ip.replace(/ /g,"");
document.ipform.ip.value = ip;
}
if (ip.toLowerCase().indexOf("http://")==0){
ip = ip.slice(7);
document.ipform.ip.value = ip;
}
if(!/^([\w-]+\.)+((com)|(net)|(org)|(gov\.cn)|(info)|(cc)|(com\.cn)|(net\.cn)|(org\.cn)|(name)|(biz)|(tv)|(cn)|(mobi)|(name)|(sh)|(ac)|(io)|(tw)|(com\.tw)|(hk)|(com\.hk)|(ws)|(travel)|(us)|(tm)|(la)|(me\.uk)|(org\.uk)|(ltd\.uk)|(plc\.uk)|(in)|(eu)|(it)|(jp))$/.test(ip)){
alert("不是正确的域名");
document.ipform.ip.focus();
return false;
}
}
else{
ipArray = ip.split(".");
j = ipArray.length
if(j!=4)
{
alert("不是正确的IP");
document.ipform.ip.focus();
return false;
}

for(var i=0;i<4;i++)
{
if(ipArray[i].length==0 || ipArray[i]>255)
{
alert("不是正确的IP");
document.ipform.ip.focus();
return false;
}
}
}
}
//手机号码验证函数
function checkMobile(){
var sMobile = document.mobileform.mobile.value
if(!(/^1[3|4|5|8][0-9]\d{4,8}$/.test(sMobile))){
alert("不是完整的11位手机号或者正确的手机号前七位");
document.mobileform.mobile.focus();
return false;
}
}
//邮政编码验证函数
function checkZip(){
var sZip = document.zipform.zip.value
if(!(/^\d{4,6}$/.test(sZip))){
alert("请输入邮政编码前4-6位");
return false;
}
}
//区号验证
function checkZone(){
var sZone = document.zoneform.zone.value
if(!(/^0\d{2,6}$/.test(sZone))){
alert("请输入以“0”开头的3-7位区号");
return false;
}
}
//身份证验证
function checkID(){
var sID = document.IDform.userid.value
if(!(/^\d{15}$|^\d{18}$|^\d{17}[xX]$/.test(sID))){
alert("请输入15位或18位身份证号");
document.IDform.userid.focus();
return false;
}

 

posted @ 2010-12-27 10:11 brock| 编辑 收藏

public class Sort implements Comparator<TestO> {
    
   
    
public Sort() {

    }


    
public int compare(TestO o1, TestO o2) {
        
if (o1.getB().compareTo(o2.getB()) <0 ||o1.getA().compareTo(o2.getA()) <0{
            
return -1;
        }
 else if (o1.getB().compareTo(o2.getB()) >0||o1.getA().compareTo(o2.getA()) >0{
                
return 1;
        }
 else {
                
return 0;
        }

    }

}

先排A ,后排B ,,,以B为最优先级
posted @ 2009-12-08 15:40 brock 阅读(213) | 评论 (0)编辑 收藏

JAVA_HOME=C:\j2sdk1.4.2_04
CLASSPATH=.;C:\j2sdk1.4.2_04\lib\tools.jar;C:\j2sdk1.4.2_04\lib\dt.jar;C:\j2sdk1.4.2_04

\bin;
path=C:\j2sdk1.4.2_04\bin;

posted @ 2009-10-15 09:36 brock 阅读(234) | 评论 (0)编辑 收藏

接口编程

 classpath :实现 ModuleInterface 接口的实现类 
// 获得对象的所有属性   
Class cl = Class.forName(classpath) ;
        Object object
= cl.getConstructor(new Class[] {})   
        .newInstance(
new Object[] {}); 
//转型成接口

        ModuleInterface  utilConfig
= (ModuleInterface )object;


     

posted @ 2009-08-26 12:22 brock 阅读(200) | 评论 (0)编辑 收藏

struts2中对action name支持通配符配置,所以使其方便的实现零配置成为可能。

实现零配置后的开发会是怎样,开发员不用配置struts.xml,也不用在action代码中写annotation,是真正干净的零配置。以下的代码是我们希望达到的效果。
action示例
package net.jacker.ww.sys;

public class UserAction extends BaseAction {


  
    
public String execute() throws Exception {
         
         
return "default"
         //
 default表示使用缺省页面,路径名和action所在包和类名相关,为 /sys/User.jsp
    }

    
public String roles(){
        
        
return view("/sys/UserRoles"); // 指定展示页面为 /sys/UserRoles.jsp 
    }


    
public String xxxx(){
       
       
return redirect("/sys/User.do"); // 重定向,url为 /sys/User.do
    
    }




}


以上action的三个方法无需配置,将可以分别用以下链接进行访问:
http://localhost:8080/sys/User.do
http://localhost:8080/sys/User!roles.do
http://localhost:8080/sys/User!xxxx.do(将重定向到User.do)


下面我们来看看以上零配置是如何做到的。
首先,我们需要在struts.xml中做如下的配置。
<struts>
    
<constant name="struts.enable.SlashesInActionNames" value="true" /> <!-- action名可以有'/'字符 -->
    
<constant name="struts.action.extension" value="do"/> <!-- .do为访问扩展名 -->

  
<package name="default" extends="struts-default">
  
  
<!-- 通配符配置,匹配所有的URL对action的访问 -->
    
<action name="*/*!*" class="net.jacker.ww.{1}.{2}Action" method="{3}"> 
      
<result name="default" type="dispatcher">/{1}/{2}.jsp</result>
      
<result name="view" type="dispatcher">${viewpath}.jsp</result>
      
<result name="redirect" type="redirect">${viewpath}</result>
    
</action>
    
<action name="*/*" class="net.jacker.ww.{1}.{2}Action">
      
<result name="default" type="dispatcher">/{1}/{2}.jsp</result>
      
<result name="view" type="dispatcher">${viewpath}.jsp</result>
      
<result name="redirect" type="redirect">${viewpath}</result>
    
</action>
  
</package>

</struts>


然后是写一个Action基类,BaseAction.java
package net.jacker.ww;

import com.opensymphony.xwork2.Action;


public abstract class BaseAction implements Action{

    

    String viewpath; 
//该属性会在struts.xml中用到

    
public String view(String vpath){
        viewpath 
= vpath;
        
return "view";
    }

    
public String redirect(String vpath){
        viewpath 
= vpath;
        
return "redirect";
    }


    
public String getViewpath() {
        
return viewpath;
    }

    

}


做好以上的基础工作,你的action类只要继承BaseAction,符合XxxAction的命名规则,放到对应的包下,页面也放到对应的路径,就可以无需配置而访问了。

如果要替换view层也很简单,只要对struts.xml做简单修改,比如:

<result name="default" type="dispatcher">/{1}/{2}.jsp</result>

改为

 <result name="default" type="velocity">/{1}/{2}.vtl</result>

修改后的struts将统一使用velocity模板取代jsp作为页面展示层。

注意:
实测后发现,以上零配置的做法只在struts2.0.11版本中可以使用,在struts2.0.XX的更高版本中却未能获通过,这不能不说是个遗憾。
posted @ 2009-08-20 17:21 brock 阅读(1305) | 评论 (0)编辑 收藏

1.interceptor的配置

方法1. 普通配置法

<struts>
    <package name="struts2" extends="struts-default">
        <interceptors>
            <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor>
        </interceptors>

        <action name="register" class="edu.hust.action.RegisterAction">
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result>
            
            <!-- 在自定义interceptor并将其ref时, 系统会覆盖掉默认的interceptor-stack(defaultStack), 为了保证系统默认的defaultStack不受印象, 我们需要显式的将其引入 -->
            <!-- 注意两个interceptor-ref的顺序, 顺序不同, 执行效果也不同: 先配置的先执行/后配置的先退出(先进后出) --> 
            <interceptor-ref name="defaultStack"></interceptor-ref> 
            <interceptor-ref name="myInterceptor"></interceptor-ref>
        </action>
    </package>
</struts>
方法2. 配置拦截器栈(即将多个interceptor串联的一种元素)。然后在<action>中引入该拦截器栈就可以了。

<struts>
    <package name="struts2" extends="struts-default">
        
        <interceptors>
            <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor>
        
            <interceptor-stack name="myInterceptorStack">
                <interceptor-ref name="myInterceptor"></interceptor-ref> 
                <interceptor-ref name="defaultStack"></interceptor-ref> 
            </interceptor-stack>
        </interceptors>
        
        <action name="register" class="edu.hust.action.RegisterAction">
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result> 
             
            <interceptor-ref name="myInterceptorStack"></interceptor-ref> 
        </action>
    </package>
</struts>
方法3. 修改默认拦截器,将自定义的拦截器栈定义为struts2的默认拦截器。

<struts>
    <package name="struts2" extends="struts-default">
        
        <interceptors>
            <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor>
            <interceptor-stack name="myInterceptorStack">
                <interceptor-ref name="myInterceptor"></interceptor-ref> 
                <interceptor-ref name="defaultStack"></interceptor-ref> 
            </interceptor-stack>
        </interceptors>

        <!-- 此默认interceptor是针对所有action的 -->
        <!-- 如果某个action中引入了interceptor, 则在这个action中此默认interceptor就会失效 -->
        <default-interceptor-ref name="myInterceptorStack"></default-interceptor-ref>
        
        <action name="register" class="edu.hust.action.RegisterAction">
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result>
        </action>
        
    </package>
</struts>
2. Interceptor的角色对象

(1)拦截目标对象(被代理对象),这里目标对象就是action;

(2)拦截器(一个类,动态的将某些方法插入到目标对象的某方法的before、after);

(3)对目标对象生成的(动态)代理对象(代理对象内部方法综合了目标对象方法+拦截器方法)。程序最终执行的是目标对象的代理,而这个代理已经插入了interceptor。

拦截器作用:拦截action。interceptor相当于一个入口和出口,通过interceptor进入action,执行完action的代码再通过interceptor出去。

针对"struts2 -- interceptor(Interceptor怎么写)"这篇文章的MyInterceptor.class和MyInterceptor2.class。根据下面的配置文件执行程序

<struts>
    <package name="struts2" extends="struts-default">
        
        <interceptors>
            <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor>
            <interceptor name="myInterceptor2" class="edu.hust.interceptor.MyInterceptor2"></interceptor>
            <interceptor-stack name="myInterceptorStack">
                <interceptor-ref name="myInterceptor"></interceptor-ref>
                <interceptor-ref name="myInterceptor2"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        
        <default-interceptor-ref name="myInterceptorStack"></default-interceptor-ref>
        
        <action name="register" class="edu.hust.action.RegisterAction">
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result>
        </action>
        
    </package>
</struts>

Console会得到以下打印输出
intercept start
intercept2 start
2008-9-19 19:42:06 com.opensymphony.xwork2.validator.ActionValidatorManagerFactory <clinit>
信息: Detected AnnotationActionValidatorManager, initializing it...
intercept2 finish
intercept finish

这个结果解释了"interceptor相当于一个入口和出口,通过interceptor进入action,执行完action的代码再通过interceptor出去"这句话。

3. extends MethodFilterInterceptor的拦截器如何配置哪些方法该拦截、哪些方法不该拦截(针对方法拦截的配置)

<struts>
    <package name="struts2" extends="struts-default">
        
        <interceptors>
            <interceptor name="myInterceptor3" class="edu.hust.interceptor.MyInterceptor3"></interceptor>
        </interceptors>
        
        <action name="register" class="edu.hust.action.RegisterAction" method="queryAll">
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result>
            <!-- myInterceptor3拦截器只对RegisterAction中的queryAll()方法和insert()方法进行了拦截, 其他方法未进行拦截 -->
            <interceptor-ref name="myInterceptor3">
                <param name="includeMethods">queryAll, execute</param>
            </interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>
        
        <action name="register" class="edu.hust.action.RegisterAction" method="insert">
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result>
            <interceptor-ref name="myInterceptor3">
                <param name="includeMethods">queryAll, insert</param>
            </interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>
        
        <action name="register" class="edu.hust.action.RegisterAction" method="update">
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result>
            <interceptor-ref name="myInterceptor3">
                <param name="includeMethods">queryAll, insert</param>
            </interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>
        
    </package>
</struts>


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ForWayfarer/archive/2008/09/20/2955586.aspx

posted @ 2009-08-20 11:03 brock 阅读(7510) | 评论 (0)编辑 收藏

1.非Ioc方式

HttpServletRequest request1 
= ServletActionContext.getRequest();
ActionContext context 
= ActionContext.getContext();
HttpServletRequest request2 
= (HttpServletRequest).context.get(ServletActionContext.HTTP_REQUEST);

取值:
<s:property value="#request.key"/>

HttpSession  session1 
= ServletActionContext.getRequest().getSession();

取值:
<s:property value="#session.key"/>
Map  session2 
=(Map) ActionContext.getContext().get(ActionContext.SESSION);
Map  session3 
= ActionContext.getContext().getSession();

取值:
<s:property value="key"/>

2.IoC方式 
     <interceptor-ref name="defaultStack"/>配置一定要真确 不然为null 
这种方式相对来说变化就比较少了,具体流程如下所示。 
获得request对象: 
第一步:让action实现ServletRequestAware接口 
第二步:在action中声明一个HttpServletRequest类型的实例变量 
第三步:在action中实现ServletRequestAware接口的setServletRequest方法,实现方式很简单,如下所示。 


private HttpServletRequest request; 
publicvoid setServletRequest(HttpServletRequest request) 

            
this.request = request; 
    }
 
获得Session对象(注意,此时的session是SessionMap类型): 
第一步:让action实现SessionAware接口 
第二步:在action中声明一个HttpServletRequest类型的实例变量 
第三步:在action中实现SessionAware接口的setSession方法,实现方式很简单,如下所示。 


private Map session; 
publicvoid setSession(Map session) 

            
this. session = session; 
    }
 



本文来自CSDN博客,转载请标明出处:http:
//blog.csdn.net/xxxx1243/archive/2009/02/16/3896133.aspx
posted @ 2009-08-20 10:32 brock 阅读(350) | 评论 (0)编辑 收藏

大多数语言都有包含其它代码文件的命令,如ASP和c/c++下的Include,java下的import,唯独javascript好像没这功能,为了应付工作,特写了如下这个函数:

//******************************************************
// 包含文件 用法: $import('../include/mian.js', 'js');
//                 $import('../style/style.css', 'css');
//******************************************************
function $import(path, type){
 var i,
      base,
      src = "common.js",
      scripts = document.getElementsByTagName("script");

 

 for (i = 0; i < scripts.length; i++) {
      if (scripts[i].src.match(src)) {
          base = scripts[i].src.replace(src, "");
          break;
      }
  }
 
  if (type == "css") {
      document.write("<" + "link href=\"" + base + path + "\" rel=\"stylesheet\" type=\"text/css\"></" + "link>");
  } else {
      document.write("<" + "script src=\"" + base + path + "\"></" + "script>");
  }
}

附带几个类型判断的函数:

//******************************************************
// 判断类型
//******************************************************
function isAlien(a) {
  return isObject(a) && typeof a.constructor != 'function';
}

 

function isArray(a) {
  return isObject(a) && a.constructor == Array;
}

function isBoolean(a) {
  return typeof a == 'boolean';
}

function isEmpty(o) {
  var i, v;
  if (isObject(o)) {
    for (i in o) {
      v = o[i];
      if (isUndefined(v) && isFunction(v)) {
        return false;
      }
    }
  }
  return true;
}

function isFunction(a) {
  return typeof a == 'function';
}

function isNull(a) {
  return typeof a == 'object' && !a;
}

function isNumber(a) {
  return typeof a == 'number' && isFinite(a);
}

function isObject(a) {
  return (a && typeof a == 'object') || isFunction(a);
}

function isString(a) {
  return typeof a == 'string';
}

function isUndefined(a) {
  return typeof a == 'undefined';
}

posted @ 2009-07-23 13:50 brock 阅读(180) | 评论 (0)编辑 收藏

StringUtil.replace(StringUtil.replace(str,"\n","<br/>"),"\r\n","<br/>");  
posted @ 2009-07-17 12:16 brock 阅读(199) | 评论 (0)编辑 收藏