Rising Sun

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

2006年12月30日 #

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

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

RBCXF-CVBGR-382MK-DFHJ4-C69G8
posted @ 2013-12-17 11:07 brock 阅读(170) | 评论 (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 阅读(684) | 评论 (0)编辑 收藏

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

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

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

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

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

posted @ 2013-10-24 10:40 brock 阅读(240) | 评论 (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 阅读(205) | 评论 (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 阅读(707) | 评论 (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 阅读(259) | 评论 (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 阅读(213) | 评论 (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 阅读(866) | 评论 (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 阅读(327) | 评论 (0)编辑 收藏

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

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

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

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

     摘要: http://singleant.iteye.com/blog/1177358 接上文 啃啃老菜: Spring IOC核心源码学习(一) ,本文将以 ClassPathXmlApplicationContext 这个容器的实现作为基础,学习容器的初始化过程。ClassPathXmlApplicationContext 类体系结构以下是&...  阅读全文
posted @ 2013-02-28 11:04 brock 阅读(813) | 评论 (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 阅读(257) | 评论 (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 阅读(1042) | 评论 (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 阅读(2903) | 评论 (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 阅读(245) | 评论 (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 阅读(358) | 评论 (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 阅读(179) | 评论 (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 阅读(289) | 评论 (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 阅读(272) | 评论 (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 阅读(1174) | 评论 (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 阅读(315) | 评论 (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 阅读(42648) | 评论 (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 阅读(239) | 评论 (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 阅读(18886) | 评论 (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 阅读(4290) | 评论 (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 阅读(5273) | 评论 (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 阅读(373) | 评论 (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 阅读(4161) | 评论 (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 阅读(208) | 评论 (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 阅读(225) | 评论 (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 阅读(189) | 评论 (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 阅读(1298) | 评论 (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 阅读(7505) | 评论 (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 阅读(345) | 评论 (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 阅读(165) | 评论 (0)编辑 收藏

StringUtil.replace(StringUtil.replace(str,"\n","<br/>"),"\r\n","<br/>");  
posted @ 2009-07-17 12:16 brock 阅读(196) | 评论 (0)编辑 收藏

ifconfig -a
/sbin/ifconfig
看IP

export LANG=zh_CN.UTF-8


locale 看字体


ps -ef|grep serverName


kill -9 num


dos2unix run-wetv.sh


rz 上传


#date -s 11:12:00
#date -s 07/26/2005

1)uname -a
2)cat /proc/version
3)cat /etc/issue  重点

查看gcc的版本
gcc --version

查看 libc的版本
rpm -qa|grep glibc

建目录
mkdir -p ivas


useradd ivas
passwd ivas


修改用户主目录
修改用户的主目录主要使用usermod命令的-d参数,例如:
usermod -d /www floatboat
这一行将floatboat的主目录改到/www。如果想将现有主目录的主要内容转移到新的目录,应该使用-m开关,如下所示:
usermod -d -m /www floatboat

远程拷备
scp 文件 ivas@10.0.86.230:/ivas  指定文件
scp -r * ivas@10.0.86.230:/ivas  所有文件

tar -zxvf xxx.tar.gz

安装apache
所需要安装文件:
httpd-2.2.0.tar.gz
apache-tomcat-5.5.12.tar.gz
jakarta-tomcat-connectors-1.2.15-src.tar.gz
Linux下安装:
# tar xzvf httpd-2.2.0.tar.gz
# cd httpd-2.2.0
# ./configure --prefix=/usr/local/apache2 --enable-so
# make
# make install

起动
apache2/bin/apachectl -f /usr/local/apache2/conf/httpd.conf

[root@localhost bin]# ./apachectl stop
[root@localhost bin]# ./apachectl start

 


我在Fedora Core 3上已经成功安装了jdk(jdk-1_5_0_02-linux-i586.rpm),其它版本的Linux基本相同,过程如下:

1. 先从网上下载jdk(jdk-1_5_0_02-linux-i586.rpm) ,推荐SUN的官方网站www.sun.com,下载后放在/home目录中,当然其它地方也行。

进入安装目录
#cd /home
#cp jdk-1_5_0_02-linux-i586.rpm /usr/local
#cd /usr/local
给所有用户添加可执行的权限
#chmod +x jdk-1_5_0_02-linux-i586.rpm.bin
#./jdk-1_5_0_02-linux-i586.rpm.bin
此时会生成文件jdk-1_5_0_02-linux-i586.rpm,同样给所有用户添加可执行的权限
#chmod +x jdk-1_5_0_02-linux-i586.rpm
安装程序
#rpm -ivh jdk-1_5_0_02-linux-i586.rpm
出现安装协议等,按接受即可。

2.设置环境变量。
#vi /etc/profile
在最后面加入
#set java environment
JAVA_HOME=/usr/java/jdk-1_5_0_02
CLASSPATH=.:$JAVA_HOME/lib.tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
保存退出。

要使JDK在所有的用户中使用,可以这样:
vi /etc/profile.d/java.sh
在新的java.sh中输入以下内容:
#set java environment
JAVA_HOME=/usr/java/jdk-1_5_0_02
CLASSPATH=.:$JAVA_HOME/lib/tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
保存退出,然后给java.sh分配权限:chmod 755 /etc/profile.d/java.sh

3.在终端使用echo命令检查环境变量设置情况。
#echo $JAVA_HOME
#echo $CLASSPATH
#echo $PATH

4.检查JDK是否安装成功。
#java -version
如果看到JVM版本及相关信息,即安装成功!

------------------------------------------------------------
netstat   -anp   |   grep 6500

 liunx 版本
cat   /proc/version
----------------------------------------------------------------
从官网下载mysql-5.0.67-linux-i686.tar.gz,下载的这个版本不需要编译安装,解压就能用了。
#tar -zvxf mysql-5.0.67-linux-i686.tar.gz
#mv mysql-5.0.67   /usr/local/mysql
#cd /usr/local/mysql
#groupadd mysql
#useradd -g mysql mysql
#chown -R mysql .  // 注意后面有个点
#chgrp -R mysql .
#scripts/mysql_install_db --user=mysql
#chown -R root .
#chown -R mysql data
#bin/mysqld_safe --user=mysql &  // 启动
#cp ./support-files/mysql.server /etc/init.d/mysql      // 让mysql以后可以随系统一起启动
#/sbin/chkconfig --add mysql
#./bin/mysql_secure_installation            // 运行这个脚本,会有个mysql的配置向导
# /etc/rc.d/init.d/mysqld start     //重启一下机器,就可以启动 MySQL
# ./bin/mysqladmin -u root password 'password_for_root'
# ./bin/mysqladmin -uroot -p password "新密码"   //可以通过这方式修改密码
# service mysqld stop //关闭 MySQL

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

posted @ 2009-07-10 17:15 brock 阅读(210) | 评论 (0)编辑 收藏

http://www.blogjava.net/justfly/archive/2007/02/05/98090.html
Remote Debugging with Eclipse说明了远程调试的原理,说明了让java程序支持被远程调用所需要的java参数如下
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044
以及如何配置远程调试weblogic、jboss和tomcat,但是里面对如何让tomcat支持远程调用并没有仔细说。再搜索,在tomcat的FAQ就找到了:
How do I configure Tomcat to support remote debugging?
如上面所示,其中的关键在于如何正确的启动tomcat。对于非windows平台下的操作来说,需要把%TOMCAT_HOME%/bin/startup.sh中的最后一行exec "$PRGDIR"/"$EXECUTABLE" start "$@" 中的start改成jpda start。如果的8000端口有其他用处的话,那么还需要修改catalina.sh文件,看其中的说明,添加一行JPDA_ADDRESS=”1044”或者其他你指定的端口。这样就可以通过startup.sh或者catalina.sh jpda start来其中支持远程调试的tomcat了。
在windows平台上是一样的步骤,只不过.sh文件改成了.bat文件了。然后需要注意以下这些地方,
1、 catalina.bat文件默认的JPDA_TRANSPORT是dt_shmem,但是Eclipse只支持dt_socket,所以需要在catalina.bat中添加一行set JPDA_TRANSPORT=”dt_socket”
2、 catalina.bat文件默认的端口是jdbconn,我也不知道这个端口是多少,因此添加一个set JPDA_ADDRESS="1044"
posted @ 2009-06-10 16:36 brock 阅读(470) | 评论 (0)编辑 收藏

      在使用MINA做客户端程序时,发现虽然调用了session.close()方法,通过日志也确实看到当前session已经被关闭了,但未什么客户端程序进程却没有停止呢?即MINA客户端没有根本的关闭。这个现象在版本1和2中都存在。这是MINA的bug吗???其实不然...

      我们可以启动2个服务器端,然后用同一个connector实例来连接这2台服务器,通过结果可以发现2个连接是相互独立工作的,及connector和session不是一对一的。

      通过查阅API和源代码,我们可以发现这里的connector实际是一个连接管理器,其内部通过一个connectQueue队列同步存储一个连接列表。并在调用connect()方法时,将当前连接请求注册到队列中;同时connector中启动着一个内部的Worker(工作线程)来管理这些连接。当我们关闭某个session之后,只是关闭了某个请求,工作线程其实并没有被关闭,所以出现程序没有停止的现象。

MINA1.1.7

可以通过设置工作超时来关闭连接,当所有的连接都被关闭后worker线程将停止,即connector停止。

Java代码 复制代码
  1. connector.setWorkerTimeout(1);   //1秒钟(默认超时60秒)  

PS:Worker定义在SocketConnector类中,内部直接实现管理

MINA2.0

可以调用connector的dispose()方法。该方法通过调用ExecutorService的shutdown()方法停止业务处理线程,并设置内部disposed标志位标识需要停止连接管理器;Worker线程通过该标识停止。

Java代码 复制代码
  1. connector.dispose();  

PS: Worker定义在AbstractPollingIoConnector类中,disposed标志在AbstractIoService类中,通过dispose()方法停止ExecutorService并设置disposed标志

posted @ 2009-06-04 13:18 brock 阅读(2873) | 评论 (0)编辑 收藏


导出数据
mysqldump --opt -h10.10.10.33 -upoi_user -pa_user --skip-lock-tables a_mis_database>/tmp/database.sql 


shell> mysqldump [OPTIONS] database [tables]  

如果你不给定任何表,整个数据库将被导出。  

通过执行mysqldump --help,你能得到你mysqldump的版本支持的选项表。  

注意,如果你运行mysqldump没有--quick或--opt选项,mysqldump将在导出结果前装载整个结果集到内存中,如果你正在导出一个大的数据库,这将可能是一个问题。  

mysqldump支持下列选项:  

--add-locks  
在每个表导出之前增加LOCK TABLES并且之后UNLOCK TABLE。(为了使得更快地插入到MySQL)。  
--add-drop-table  
在每个create语句之前增加一个drop table。  
--allow-keywords  
允许创建是关键词的列名字。这由表名前缀于每个列名做到。  
-c, --complete-insert  
使用完整的insert语句(用列名字)。  
-C, --compress  
如果客户和服务器均支持压缩,压缩两者间所有的信息。  
--delayed  
用INSERT DELAYED命令插入行。  
-e, --extended-insert  
使用全新多行INSERT语法。(给出更紧缩并且更快的插入语句)  
-#, --debug[=option_string]  
跟踪程序的使用(为了调试)。  
--help  
显示一条帮助消息并且退出。  
--fields-terminated-by=...  
   
--fields-enclosed-by=...  
   
--fields-optionally-enclosed-by=...  
   
--fields-escaped-by=...  
   
--fields-terminated-by=...  
这些选择与-T选择一起使用,并且有相应的LOAD DATA INFILE子句相同的含义。  
LOAD DATA INFILE语法。  
-F, --flush-logs  
在开始导出前,洗掉在MySQL服务器中的日志文件。  
-f, --force,  
即使我们在一个表导出期间得到一个SQL错误,继续。  
-h, --host=..  
从命名的主机上的MySQL服务器导出数据。缺省主机是localhost。  
-l, --lock-tables.  
为开始导出锁定所有表。  
-t, --no-create-info  
不写入表创建信息(CREATE TABLE语句)  
-d, --no-data  
不写入表的任何行信息。如果你只想得到一个表的结构的导出,这是很有用的!  
--opt  
同--quick --add-drop-table --add-locks --extended-insert --lock-tables。  
应该给你为读入一个MySQL服务器的尽可能最快的导出。  
-pyour_pass, --password[=your_pass]  
与服务器连接时使用的口令。如果你不指定“=your_pass”部分,mysqldump需要来自终端的口令。  
-P port_num, --port=port_num  
与一台主机连接时使用的TCP/IP端口号。(这用于连接到localhost以外的主机,因为它使用 Unix套接字。)  
-q, --quick  
不缓冲查询,直接导出至stdout;使用mysql_use_result()做它。  
-S /path/to/socket, --socket=/path/to/socket  
与localhost连接时(它是缺省主机)使用的套接字文件。  
-T, --tab=path-to-some-directory  
对于每个给定的表,创建一个table_name.sql文件,它包含SQL CREATE 命令,和一个table_name.txt文件,它包含数据。 注意:这只有在mysqldump运行在mysqld守护进程运行的同一台机器上的时候才工作。.txt文件的格式根据--fields-xxx和--lines--xxx选项来定。  
-u user_name, --user=user_name  
与服务器连接时,MySQL使用的用户名。缺省值是你的Unix登录名。  
-O var=option, --set-variable var=option设置一个变量的值。可能的变量被列在下面。  
-v, --verbose  
冗长模式。打印出程序所做的更多的信息。  
-V, --version  
打印版本信息并且退出。  
-w, --where='where-condition'  
只导出被选择了的记录;注意引号是强制的!  
"--where=user='jimf'" "-wuserid>1" "-wuserid<1" 

最常见的mysqldump使用可能制作整个数据库的一个备份: 

mysqldump --opt database > backup-file.sql  

但是它对用来自于一个数据库的信息充实另外一个MySQL数据库也是有用的:  

mysqldump --opt database | mysql --host=remote-host -C database  

由于mysqldump导出的是完整的SQL语句,所以用mysql客户程序很容易就能把数据导入了:  

shell> mysqladmin create target_db_name  
shell> mysql target_db_name < backup-file.sql 
就是 
shell> mysql 库名 < 文件名 
posted @ 2009-05-20 11:20 brock 阅读(168) | 评论 (0)编辑 收藏

 

定义Hibernate Dialect解决createSQLQuery时的decimal,long类型问题

org.hibernate.MappingException: No Dialect mapping for JDBC type: 3

首先建一个类,继承org.hibernate.dialect.DB2Dialect,该类的内容如下:

import java.sql.Types;

import org.hibernate.Hibernate;
import org.hibernate.dialect.DB2Dialect;

public class PmDb2Dialect extends DB2Dialect
{
public PmDb2Dialect()
{
     super();
     registerHibernateType(Types.DECIMAL, Hibernate.BIG_DECIMAL.getName());
}
}

第二步,就是修改hibernate的配置文件hibernate.cfg.xml:

将:

     <property name="hibernate.dialect">
      org.hibernate.dialect.DB2Dialect
     </property>

改为:

     <property name="hibernate.dialect">
      com.yonder.pm.common.PmDb2Dialect
     </property>

posted @ 2009-05-12 11:11 brock 阅读(1477) | 评论 (0)编辑 收藏

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'youpassword' WITH GRANT OPTION;  
posted @ 2009-04-22 12:51 brock 阅读(162) | 评论 (0)编辑 收藏

http://blog.chinaunix.net/u/29134/showart_355336.html



MYSQL在默认的情况下查询是不区分大小写的,例如:

mysql> create table t1(
    -> name varchar(10));
Query OK, 0 rows affected (0.09 sec)

mysql> insert into t1 values('you'),('You'),('YOU');
Query OK, 3 rows affected (0.05 sec)
Records: 3  Duplicates: 0  Warnings: 0
对这个表,缺省情况下,下面两个查询的结果是一样的:


mysql> select * from t1 where name = 'you';
+------+
| name |
+------+
| you  |
| You  |
| YOU  |
+------+
3 rows in set (0.00 sec)

mysql> select * from t1 where name = 'YOU';
+------+
| name |
+------+
| you  |
| You  |
| YOU  |
+------+
3 rows in set (0.00 sec)

如果想让MYSQL知道你输入的字母是大写还是小写的,修改表:

mysql> alter table t1 change name name varchar(10) binary;
Query OK, 3 rows affected (0.20 sec)
Records: 3  Duplicates: 0  Warnings: 0


mysql> select * from t1 where name = 'you';
+------+
| name |
+------+
| you  |
+------+
1 row in set (0.00 sec)

mysql> select * from t1 where name = 'YOU';
+------+
| name |
+------+
| YOU  |
+------+
1 row in set (0.00 sec)

如果你只是想在SQL语句中实现的话:

mysql> select * from t1 where name = binary 'YOU';
+------+
| name |
+------+
| YOU  |
+------+
1 row in set (0.02 sec)

mysql> select * from t1 where name = binary 'you';
+------+
| name |
+------+
| you  |
+------+
1 row in set (0.00 sec)

如果不想这么麻烦而想服务一开启就让大小写一致的话:
可以修改my.ini或者my.cnf
[mysqld]
 lower_case_table_names=1
(0:区分;1:不区分)
然后重启MYSQL服务。

mysql> show variables like '%case_table%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| lower_case_table_names | 1     |
+------------------------+-------+
1 row in set (0.00 sec)

注:WINDOWS系统不用修改,系统默认就是1
LINUX 系统默认是0。因为LINUX下的脚本都是区分大小写的。
posted @ 2009-04-17 15:30 brock 阅读(7301) | 评论 (1)编辑 收藏

在使用MySQL-Front连接mysql的时候发生的这个错误

ERROR 1130: Host 192.168.88.160 is not allowed to connect to this MySQL server

更改 mysql 数据库里的 user表里的 host项
localhost改称%

mysql -u root -p

mysql>use mysql;

mysql>update user set host = '%'  where user ='root';

mysql>flush privileges;

mysql>select 'host','user' from user where user='root';

现在就可以连接了! 

权限

 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' with grant option;

posted @ 2009-04-13 16:52 brock 阅读(4407) | 评论 (1)编辑 收藏

简介     在jsp页面上经常遇到得到集合长度、字符长度、字符切取等应用需,在2.0以前这种需是许多程序员对JSTL及为不满意的地方之一。为此在2.0 中添加了functions标签,其提供对以上需求的支持。     使用方法     引用<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>函数说明:   函数 描述
fn:contains(string, substring) 如果参数string中包含参数substring,返回true
fn:containsIgnoreCase(string, substring) 如果参数string中包含参数substring(忽略大小写),返回true
fn:endsWith(string, suffix) 如果参数 string 以参数suffix结尾,返回true
fn:escapeXml(string) 将有特殊意义的XML (和HTML)转换为对应的XML character entity code,并返回
fn:indexOf(string, substring) 返回参数substring在参数string中第一次出现的位置
fn:join(array, separator) 将一个给定的数组array用给定的间隔符separator串在一起,组成一个新的字符串并返回。
fn:length(item) 返回参数item中包含元素的数量。参数Item类型是数组、collection或者String。如果是String类型,返回值是String中的字符数。
fn:replace(string, before, after) 返回一个String对象。用参数after字符串替换参数string中所有出现参数before字符串的地方,并返回替换后的结果
fn:split(string, separator) 返回一个数组,以参数separator 为分割符分割参数string,分割后的每一部分就是数组的一个元素
fn:startsWith(string, prefix) 如果参数string以参数prefix开头,返回true
fn:substring(string, begin, end) 返回参数string部分字符串, 从参数begin开始到参数end位置,包括end位置的字符
fn:substringAfter(string, substring) 返回参数substring在参数string中后面的那一部分字符串
fn:substringBefore(string, substring) 返回参数substring在参数string中前面的那一部分字符串
fn:toLowerCase(string) 将参数string所有的字符变为小写,并将其返回
fn:toUpperCase(string) 将参数string所有的字符变为大写,并将其返回
fn:trim(string) 去除参数string 首尾的空格,并将其返回
示例
${fn.substring(string,begin,end)}

来一个我自己测试用的代码

 

<%@ page contentType="text/html;charset=gbk"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<html>
<head>
<title>这个是 JSTL的    测试</title>
</head>
<body>
<c:set var="str" value="stringStRiNg"/>
<c:set var="t" value="tr"/>
<c:out value="${str} = ${fn:length(str)}"/>
<c:out value="${fn:toLowerCase(str)}"/>
<c:out value="${fn:toUpperCase('   ')}"/>
<c:out value="${fn:toUpperCase('AbCdEfg')}"/><br>
<c:out value="${fn:substring('asdfefg',0,3)}"/><br>
<c:out value="${fn:substringAfter('asdf','s')}"/><Br>
<c:out value="${fn:substringBefore(str,'g')}"/><Br>
<c:out value="${fn:trim(' sd dew e ')}"/><Br>

 

<c:out value=" d sd dew e "/><Br>
<c:out value="${fn:replace(str,'ing','IN')}"/><Br>
</body>
</html>

posted @ 2008-11-20 10:08 brock 阅读(353) | 评论 (0)编辑 收藏


function delRepeat(arr){
 var len = arr.length;
 for(var i=len-1;i>=1;i--)
 {       
 if(arr[i-1] == arr[i])    
    {         
   arr.splice(i,1);//splice()方法的应用   
     } 
   }
 //return arr;
}

Array.prototype.delRepeat=function()
{
var tmpArr=[],rs=[],i,val;
for(i=this.length;i>0;i--)
{
val = this[i-1];
if(!tmpArr[val])
{
tmpArr[val]=1;
}else
{
rs.push(val);
this.splice(i-1,1);
}
}
tmpArr = null;
return rs;
}

两个优点:
1、预先将this[i-1]保存在变量val中,减少访问次数。
2、使用array.push方法,替换用变量保存数组长度的办法。



JavaScript splice() 方法
返回 JavaScript Array 对象参考手册
定义和用法
splice() 方法用于插入、删除或替换数组的元素。

语法
arrayObject.splice(index,howmany,element1,..,elementX)参数 描述 
index 必需。规定从何处添加
/删除元素。

该参数是开始插入和(或)删除的数组元素的下标,必须是数字。
 
howmany 必需。规定应该删除多少元素。必须是数字,但可以是 
"0"

如果未规定此参数,则删除从 index 开始到原数组结尾的所有元素。
 
element1 可选。规定要添加到数组的新元素。从 index 所指的下标处开始插入。 
elementX 可选。可向数组添加若干元素。 

返回值
如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组。

说明
splice() 方法可删除从 index 处开始的零个或多个元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素。
提示和注释
注释:请注意,splice() 方法与 slice() 方法的作用是不同的,splice() 方法会直接对数组进行修改。
实例
例子 
1
在本例中,我们将创建一个新数组,并向其添加一个元素:

<script type="text/javascript">

var arr = new Array(6)
arr[
0= "George"
arr[
1= "John"
arr[
2= "Thomas"
arr[
3= "James"
arr[
4= "Adrew"
arr[
5= "Martin"

document.write(arr 
+ "<br />")
arr.splice(
2,0,"William")
document.write(arr 
+ "<br />")

</script>输出:

George,John,Thomas,James,Adrew,Martin
George,John,William,Thomas,James,Adrew,Martin例子 
2
在本例中我们将删除位于 index 
2 的元素,并添加一个新元素来替代被删除的元素:

<script type="text/javascript">

var arr = new Array(6)
arr[
0= "George"
arr[
1= "John"
arr[
2= "Thomas"
arr[
3= "James"
arr[
4= "Adrew"
arr[
5= "Martin"

document.write(arr 
+ "<br />")
arr.splice(
2,1,"William")
document.write(arr)

</script>输出:

George,John,Thomas,James,Adrew,MartinGeorge,John,William,James,Adrew,Martin例子 
3
在本例中我们将删除从 index 
2 ("Thomas") 开始的三个元素,并添加一个新元素 ("William") 来替代被删除的元素:

<script type="text/javascript">

var arr = new Array(6)
arr[
0= "George"
arr[
1= "John"
arr[
2= "Thomas"
arr[
3= "James"
arr[
4= "Adrew"
arr[
5= "Martin"

document.write(arr 
+ "<br />")
arr.splice(
2,3,"William")
document.write(arr)

</script>输出:

George,John,Thomas,James,Adrew,MartinGeorge,John,William,MartinTIY
splice() 
如何使用 splice() 来更改数组。 
posted @ 2008-11-19 20:00 brock 阅读(300) | 评论 (0)编辑 收藏

  <HTML>  
  <HEAD>  
  <TITLE>   New   Document   </TITLE>  
  <script>  
  //判断当前页面是刷新还是关闭  
  function   a(){  
  if(event.clientX<=0&&   event.clientY   <   0){//>0是刷新,<=0是关闭当前页  
        alert("开新的");  
                          openwin();  
                    }else{  
        alert("不开新的");  
                    }  
  }  
  </script>  
  </HEAD>  
   
  <BODY   onUnload="a();">  
   
  </BODY>  
  </HTML>  
posted @ 2008-11-19 16:36 brock 阅读(350) | 评论 (0)编辑 收藏

http://space.itpub.net/10707242/viewspace-136175
posted @ 2008-10-16 10:31 brock 阅读(137) | 评论 (0)编辑 收藏

javascript 中文字符长度判断

if(srt.charCodeAt(i) > 255{
//if(friendnick.charCodeAt(i) < 0x4E00 || friendnick.charCodeAt(i) > 0x9FA5) {
     charlen 
+=2;
    }
else{
    
     charlen 
+=1;
    }

java 中文字符长度判断
 if(tempProperty.getBytes().length > cut*2 ){
                
if (tempProperty.length() >= (cut + 1)) {
                    
byte [] src = tempProperty.getBytes();
                    
byte [] dest = new byte[cut*2+2];
                    
int flag = 0;
                    
for(int j=0;j<src.length;j++){  
                        
if(j<= cut*2){
                           
// System.out.println(j);
                            if(src[j]<0)
                                flag
++;
                            dest[j]
= src[j];
                        }

                    }

                  
                    
if(flag % 2 !=0){
                        dest[cut
*2]= 0;
                    }

                    tempProperty 
=  new String(dest).trim()+ ""
这个代码有问题  "sss顺磾村厈士大夫"  tempProperty.getBytes() 其中一个数字不为负数
  修改过的代码

 String s = "stss顺磾村厈士大夫";
        String badChar 
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        badChar 
+= "abcdefghijklmnopqrstuvwxyz"
        badChar 
+= "0123456789"
        badChar 
+= " "+" ";//半角与全角空格 
        badChar += ".`~!@#$%^&()-_=+]\\|:;\"\'<,>?/*";
        String result = "";
        
int len = 0;
            
for(int i=0;i<s.length();i++)
                
char c = s.charAt(i);
                
if(badChar.indexOf(c)==-1){//如果是中文
                   result = result+c;
                   len 
+= 2;
                }
else{
                   result 
=  result+c;
                   len 
+= 1;
                }

                
if(len>=15break;
            }
 
posted @ 2008-10-14 09:22 brock 阅读(632) | 评论 (0)编辑 收藏

[Java]用OSCache进行缓存对象

1、OSCache是什么?
     OSCache标记库由OpenSymphony设计,它是一种开创性的缓存方案,它提供了在现有JSP页面之内实现内存缓存的功能。OSCache是个一个被广泛采用的高性能的J2EE缓存框架,OSCache还能应用于任何Java应用程序的普通的缓存解决方案。
2、OSCache的特点
    (1) 缓存任何对象:你可以不受限制的缓存部分jsp页面或HTTP请求,任何java对象都可以缓存。
    (2) 拥有全面的API:OSCache API允许你通过编程的方式来控制所有的OSCache特性。
    (3) 永久缓存:缓存能被配置写入硬盘,因此允许在应用服务器的多次生命周期间缓存创建开销昂贵的数据。
    (4) 支持集群:集群缓存数据能被单个的进行参数配置,不需要修改代码。
    (5) 缓存过期:你可以有最大限度的控制缓存对象的过期,包括可插入式的刷新策略(如果默认性能不能满足需要时)。
3、OSCache的安装与配置
    网上已经有一个不错的使用教程:http://blog.csdn.net/ezerg/archive/2004/10/14/135769.aspx
4、有关“用OSCache进行缓存对象”的研究
    这个是我今天要说的东西。网上对于OSCache缓存Web页面很多说明和例子,但对于缓存对象方面说得不多,我就把自已写得一些东西放出来,让大家看一看是怎样缓存对象的!
    我基于GeneralCacheAdministrator类来写的BaseCache类
   
  1. package com.klstudio.cache;   
  2.   
  3. import java.util.Date;   
  4.   
  5. import com.opensymphony.oscache.base.NeedsRefreshException;   
  6. import com.opensymphony.oscache.general.GeneralCacheAdministrator;   
  7.   
  8. public class BaseCache extends GeneralCacheAdministrator {   
  9.     //过期时间(单位为秒);   
  10.     private int refreshPeriod;   
  11.     //关键字前缀字符;   
  12.     private String keyPrefix;   
  13.        
  14.     private static final long serialVersionUID = -4397192926052141162L;   
  15.        
  16.     public BaseCache(String keyPrefix,int refreshPeriod){   
  17.         super();   
  18.         this.keyPrefix = keyPrefix;   
  19.         this.refreshPeriod = refreshPeriod;   
  20.     }   
  21.     //添加被缓存的对象;   
  22.     public void put(String key,Object value){   
  23.         this.putInCache(this.keyPrefix+"_"+key,value);   
  24.     }   
  25.     //删除被缓存的对象;   
  26.     public void remove(String key){   
  27.         this.flushEntry(this.keyPrefix+"_"+key);   
  28.     }   
  29.     //删除所有被缓存的对象;   
  30.     public void removeAll(Date date){   
  31.         this.flushAll(date);   
  32.     }   
  33.        
  34.     public void removeAll(){   
  35.         this.flushAll();   
  36.     }   
  37.     //获取被缓存的对象;   
  38.     public Object get(String key) throws Exception{   
  39.         try{   
  40.             return this.getFromCache(this.keyPrefix+"_"+key,this.refreshPeriod);   
  41.         } catch (NeedsRefreshException e) {   
  42.             this.cancelUpdate(this.keyPrefix+"_"+key);   
  43.             throw e;   
  44.         }   
  45.   
  46.     }   
  47.        
  48. }   
  49.   
  50.   

   通过CacheManager类来看怎样缓存对象的,这个类中所用的News只是具体功能的类,我就不贴出来了,你可以自己写一个!
   
  1. package com.klstudio;   
  2.   
  3. import com.klstudio.News;   
  4. import com.klstudio.cache.BaseCache;   
  5.   
  6. public class CacheManager {   
  7.        
  8.     private BaseCache newsCache;   
  9.   
  10.        
  11.     private static CacheManager instance;   
  12.     private static Object lock = new Object();   
  13.        
  14.     public CacheManager() {   
  15.         //这个根据配置文件来,初始BaseCache而已;   
  16.         newsCache = new BaseCache("news",1800);        
  17.     }   
  18.        
  19.     public static CacheManager getInstance(){   
  20.         if (instance == null){   
  21.             synchronized( lock ){   
  22.                 if (instance == null){   
  23.                     instance = new CacheManager();   
  24.                 }   
  25.             }   
  26.         }   
  27.         return instance;   
  28.     }   
  29.   
  30.     public void putNews(News news) {   
  31.         // TODO 自动生成方法存根   
  32.         newsCache.put(news.getID(),news);   
  33.     }   
  34.   
  35.     public void removeNews(String newsID) {   
  36.         // TODO 自动生成方法存根   
  37.         newsCache.remove(newsID);   
  38.     }   
  39.   
  40.     public News getNews(String newsID) {   
  41.         // TODO 自动生成方法存根   
  42.         try {   
  43.             return (News) newsCache.get(newsID);   
  44.         } catch (Exception e) {   
  45.             // TODO 自动生成 catch 块   
  46.             System.out.println("getNews>>newsID["+newsID+"]>>"+e.getMessage());   
  47.             News news = new News(newsID);   
  48.             this.putNews(news);   
  49.             return news;   
  50.         }   
  51.     }   
  52.   
  53.     public void removeAllNews() {   
  54.         // TODO 自动生成方法存根   
  55.         newsCache.removeAll();   
  56.     }   
  57.   
  58. }   
  59.   
posted @ 2008-09-09 10:39 brock 阅读(681) | 评论 (0)编辑 收藏

根据上面英文的意思,我认为:
之前大量的符合jsp1.2标准的项目中用到了${***},比如${1+2},但本意就是想显示${1+2},而不是3,所以应该有控制是否解析el表达式的选项,我觉得分为三个级别:

1、设置整个应用服务器下的所有项目是否解析el表达式(控制所有项目)
(这个我还没找到在哪,但应该有)。

2、设置整个项目使用el表达式,需要在web.xml中加上 (控制一个项目)
<jsp-config>
<jsp-property-group>
<el-ignored>false</el-ignored>
</jsp-property-group>
</jsp-config>


3、设置某个jsp页面使用el表达式,需要在jsp页面加上(控制单个页面)
<%@ page isELIgnored="false"%>

你的应用服务器默认设为不解析el表达式了(我的tomcat5.0也是一样),所以要用上面的方法修改,以在页面/项目/应用服务器,级别解析el表达式。
posted @ 2008-08-26 10:57 brock 阅读(141) | 评论 (0)编辑 收藏

准备工作:
安装tomcat5.5(注意这点)
安装mysql
拷贝mysql驱动到tomcat_home/common/lib下
新建一个web工程
在工程中加入index.jsp


<%@page import="java.util.*,javax.naming.*,java.sql.*,javax.sql.*" %>
<%@page contentType="text/html;charset=BIG5"%>
<%    
    Context ctx 
= new InitialContext();      
    String strLookup 
= "java:comp/env/jdbc/test"
    DataSource ds 
=(DataSource) ctx.lookup(strLookup);
    Connection con 
= ds.getConnection();
    
if (con != null){
        out.print(
"success");
    }
else{
        out.print(
"failure");
    }
       
%>

web.xml中加入

<resource-ref>
    
<res-ref-name>jdbc/test</res-ref-name>
    
<res-type>javax.sql.DataSource</res-type>
    
<res-auth>Container</res-auth>
    
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

配置tomcat
这一步的目的就是告诉tomcat如何连接数据库
可以分为两种大的类型,每种类型又有很多种配置方式
配置类型一;
(直接配置的类型,这种方式最简单)

方法一:
直接在tomcat_home/conf/localhost/下建立一个xml文件,文件名是<yourAppName>.xml
例如我的工程名叫jndi,对应的名字叫jdni.xml
内容如下:

<Context>
 
<Resource
          name
="jdbc/test"
          type
="javax.sql.DataSource"
          password
="bb"
          driverClassName
="com.mysql.jdbc.Driver"
          maxIdle
="2"
          maxWait
="50"
          username
="root"
          url
="jdbc:mysql://localhost:3306/test"
          maxActive
="4"/>
</Context>

方法二:
只需在tomcat_home\webapps\myapps\META-INF\context.xml中增加:
<context>
<Resource
          name
="jdbc/test"
          type
="javax.sql.DataSource"
          password
="bb"
          driverClassName
="com.mysql.jdbc.Driver"
          maxIdle
="2"
          maxWait
="50"
          username
="root"
          url
="jdbc:mysql://localhost:3306/test"
          maxActive
="4"/>
</context>


说明:这种配置需要告诉tomcat resource的内容,resource应用于什么地方
第一种方法通过文件名知道了app的name
第二种方式本身就在app内部,所以name肯定知道
两种方式都要放在context中

配置类型二:
(配置全局resource,然后通过resourcelink来映射)

步骤一:配置全局resource(这一步对于所有的配置都是一样的)
打开tomcat_home/conf/server.xml加入

<Resource
          name
="jdbc/test"
          type
="javax.sql.DataSource"
          password
="bb"
          driverClassName
="com.mysql.jdbc.Driver"
          maxIdle
="2"
          maxWait
="50"
          username
="root"
          url
="jdbc:mysql://localhost:3306/test"
          maxActive
="4"/>


步骤二:映射
(映射可以配置在多个地方,也就有多个配置方法:)

方法一:(对比类型一的配置理解)
直接在tomcat_home/conf/localhost/下建立一个xml文件,文件名是<yourAppName>.xml
例如我的工程名叫jndi,对应的名字叫jdni.xml加入如下内容

<Context>
<ResourceLink global="jdbc/test" name="jdbc/test" type="javax.sql.DataSource"/>
</Context>

方法二:(对比类型一的配置理解)
在tomcat_home\webapps\myapps\META-INF\context.xml的Context中增加:


<context>
<ResourceLink global="jdbc/test" name="jdbc/test" type="javax.sql.DataSource"/> 
</context>


方法三:(上边两种方法都是把全局的resource 映射给jndi这个web应用,第三种方法就是把这个
全局的resource直接公开给所有的应用)
在tomcat_home/conf/context.xml的<Context></context>之间加入
<ResourceLink global="jdbc/test" name="jdbc/test" type="javax.sql.DataSource"/>


运行测试:
打开ie,输入http://localhost:8080/jndi/index.jsp
看到success

常见错误:
1,Name jdbc is not bound in this Context
2,Cannot create JDBC driver of class '' for connect URL 'null' conf localhost
原因:
大多数是因为配置了全局的resource,但没有link造成的。
解决:
加入link就行了,link的方式见类型二的三种方法。

分析:
看到上边这么多方法,是否感觉眼花缭乱,其实不要死记配置,按照原理分析一下就好了。
你需要的是告诉tomcat哪个应用如何连接数据库。

类型一的方式对应一个应用单独使用这个配置的情况
就是直接告诉tomcat"应用名"  "连接数据库需要的参数"

类型二的方式对应多个应用共享一个配置的情况
这样先配置server.xml告诉tomcat全局范围的"连接数据库需要的参数"
然后映射,映射的时候
1,如果不知道"app name(应用名)"就只需要通过文件名来传递这个信息
2,如果"app name"都知道就只需要加入映射的内容
3,如果要配置成全局公用的,就不需要"app name",本身放在tomcat的context.xml中

最后再次提醒一下:所有的配置必须放在<context></context>之间 

posted @ 2008-08-06 12:52 brock 阅读(169) | 评论 (0)编辑 收藏

我这有个系统是以tomcat5.5+sqlserver2000配置的。我将tomcat使用的初始内存和最大内存分别设置为100M和1024M,然后通过server.xml修改相关的线程数,但minSpareThreads和maxSpareThreads设置的很大或者应经足够小了,通过压力测试,看tomcat5.exe进程占用的内存数的走向图没有什么变化,比如通过压力测试可以使tomcat占到最大800M内存,而压力测试过后放置一晚上tomcat会回落并一直保持在600M。
但通过下面的解释tomcat占用的内存是否应该有变化
minSpareThreads Tomcat初始化时创建的线程数。
maxSpareThreads 一旦创建的线程超过这个值,Tomcat就会关闭不再需要
的socket线程。

下面是我分别设置的线程参数

<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<Connector port="9080"
maxHttpHeaderSize="8192"
maxThreads="10000" minSpareThreads="1000" maxSpareThreads="2000"
enableLookups="false" redirectPort="8443" acceptCount="10000"
connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="UTF-8"/>



<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<Connector port="9080"
maxHttpHeaderSize="8192"
maxThreads="10000" minSpareThreads="50" maxSpareThreads="100"
enableLookups="false" redirectPort="8443" acceptCount="10000"
connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="UTF-8"/>
posted @ 2008-07-31 15:10 brock 阅读(707) | 评论 (0)编辑 收藏

. 条件标签
    JSTL: 
 1 <c:if test="${user.password == 'hello'}">
 2     <c:choose>
 3         <c:when test="${user.age <= 18}">
 4             <font color="blue" />
 5         </c:when>
 6         <c:when test="${user.age <= 30 && user.age > 18}">
 7             <font color="red" />
 8         </c:when>
 9         <c:otherwise>
10             <font color="green" />
11         </c:otherwise>
12     </c:choose>
13 </c:if>
    Struts2:
1 <s:if test="#user.age <= 18">
2     <font color="blue" />
3 </s:if>
4 <s:elseif test="#user.age <= 30 && user.age > 18">
5     <font color="red" />
6 </s:elseif>
7     <font color="green" />
8 </s:else>

2. 迭代标签
    JSTL:
1 <c:forEach var="user" items="${users}">
2     <c:out value="${user.userName}" />
3 </c:forEach>
4 <!-- 迭代固定次数 -->
5 <c:forEach var="i" begin="1" end="10" step="3">
6     <c:out value="${i}" />
7 </c:forEach>
8 <!-- 这种循环相当于for(int i=1; i<10; i++), 其中step是指迭代的步长,默认为1. -->
    Struts2:
1 <s:iterator value="#users" status="stuts">                
2     <s:if test="#stuts.odd == true">   <!-- 判断是否为奇数行 -->
3         <s:property value="userName" />
4     </s:if>
5     <s:else>
6         <s:property value="passWord" />
7     </s:else>
8 </s:iterator>

3. URL相关标签
    JSTL:
 1 <!-- 绝对路径 -->
 2 <c:import url="http://127.0.0.1:8080/hello/hello.jsp" />
 3 <!-- 相对路径 -->
 4 <c:import url="hello.jsp" />
 5 <!-- Encode -->
 6 <href="<c:url value='hello.jsp'><c:param name='userName' value='cyanbomb' /></c:url>"></a>
 7 <!-- 传递参数到指定的URL -->
 8 <c:import url="hello.jsp" charEncoding="gb2312" >
 9     <c:param name="userName" value="cyanbomb" />
10 </c:import>
11 <!-- URL重定向 -->
12 <c:redirect url="${myurl}" />
13 <!-- 构造URL -->
14 <c:url value="myurl" var="hello.jsp" scope="session">
15     <c:param name="userName" value="cyanbomb" />
16 </c:url>
    Struts2:
1 <href='<s:url value="/hello.jsp" />'>Hello</a><br />
2 <s:url id="url" value="/hello.jsp">
3     <s:param name="name">cyanbomb</s:param>
4 </s:url>        
5 <s:a href="%{url}">Hello</s:a>

解除的疑问,list遍历问题

像这样一个list,里面有3条记录,每条记录包含两个对象,我把结果集(lstRooms)request到了页面,想遍历显示RrmRooms里的id,和RrmRoomType里的name.
我用JSTL实现如下:
1 <table>
2     <c:forEach var="rm" items="${lstRooms}">
3         <tr>
4             <td>${rm[0].id}</td>
5             <td>${rm[1].name}</td>
6         <tr>
7     </c:forEach>
8 </table>
STRUTS2实现如下:
1<table>
2     <s:iterator value="#lstRooms" status="stat">
3         <tr>
4             <td><s:property value="#lstRooms[#stat.index][0].id" /></td>
5             <td><s:property value="#lstRooms[#stat.index][1].name" /></td>
6         <tr>
7     </s:iterator>
8</table>
posted @ 2008-07-30 09:02 brock 阅读(281) | 评论 (0)编辑 收藏

利用w3c的dom:

 

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
  DocumentBuilder builder;
  
try   {
   builder 
=  factory.newDocumentBuilder();
   Document doc 
=  builder.parse( new  ByteArrayInputStream(str.getBytes())); 
  }
  catch  (ParserConfigurationException e)  {
   
//  TODO Auto-generated catch block
   e.printStackTrace();
  }
  catch  (SAXException e)  {
   
//  TODO Auto-generated catch block
   e.printStackTrace();
  }
  catch  (IOException e)  {
   
//  TODO Auto-generated catch block
   e.printStackTrace();
  }
 


利用1 dom4j

SAXReader saxReader = new SAXReader();
        Document document;
        
try {
            document 
= saxReader.read(new ByteArrayInputStream(str.getBytes()));
            Element incomingForm 
= document.getRootElement();
        }
 catch (DocumentException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        }


利用 2 dom4j :


String text = "<person> <name>James</name> </person>";
Document document = DocumentHelper.parseText(text);
posted @ 2008-07-29 11:17 brock 阅读(163) | 评论 (0)编辑 收藏

Weblogic 中报Ora-01483

数据库 oralce 9i 版本9.2.0.1.0
Server: Weblogic 814
数据库连接方式:Hibernate3+DataSource + ConnectionPool

问题:
往数据库中某表插入Blog对象时偶尔(并不是每次都,现象是第一次不出错,之后每次都出错)出错,错误异常:
{org.springframework.jdbc.UncategorizedSQLException: Hibernate operation: Could not execute JDBC batch update: encountered SQLException [ORA-01483: invalid length for DATE or NUMBER bind variable]; nested exception is java.sql.BatchUpdateException: ORA-01483: invalid length for DATE or NUMBER bind variable.
java.sql.BatchUpdateException: ORA-01483: invalid length for DATE or NUMBER bind variable

原因分析:
出现这个问题后,使用spring提供的org.springframework.jdbc.datasource.DriverManagerDataSource连数据库执行相同的操作并没有问题,由于使用的是server上配置的DataSource+ConnectionPool,数据库驱动的获取是server选择的。经查找,server选择的是%bea_home%/weblogic81/server/lib/ojdbc14.jar (version 10.1.0.6.0)。用类路径里的驱动替代,该问题不再出现。

解决办法:使用version为10.1.0.4.0的ojdbc.jar代替%bea_home%/weblogic81/server/lib/ojdbc14.jar。

转载 
我的weblogic9
ojdbc14.jar 从orcale 10中找一个来odbc14.jar
posted @ 2008-05-04 17:12 brock 阅读(2322) | 评论 (0)编辑 收藏

oracle的分析函数over 及开窗函数
一:分析函数over
Oracle从8.1.6开始提供分析函数,分析函数用于计算基于组的某种聚合值,它和聚合函数的不同之处是
对于每个组返回多行,而聚合函数对于每个组只返回一行。
下面通过几个例子来说明其应用。                                       
1:统计某商店的营业额。        
     date       sale
     1           20
     2           15
     3           14
     4           18
     5           30
    规则:按天统计:每天都统计前面几天的总额
    得到的结果:
    DATE   SALE       SUM
    ----- -------- ------
    1      20        20           --1天           
    2      15        35           --1天+2天           
    3      14        49           --1天+2天+3天           
    4      18        67            .          
    5      30        97            .
     
2:统计各班成绩第一名的同学信息
    NAME   CLASS S                         
    ----- ----- ----------------------
    fda    1      80                     
    ffd    1      78                     
    dss    1      95                     
    cfe    2      74                     
    gds    2      92                     
    gf     3      99                     
    ddd    3      99                     
    adf    3      45                     
    asdf   3      55                     
    3dd    3      78              
   
    通过:   
    --
    select * from                                                                       
    (                                                                            
    select name,class,s,rank()over(partition by class order by s desc) mm from t2
    )                                                                            
    where mm=1
    --
    得到结果:
    NAME   CLASS S                       MM                                                                                        
    ----- ----- ---------------------- ----------------------
    dss    1      95                      1                      
    gds    2      92                      1                      
    gf     3      99                      1                      
    ddd    3      99                      1          
   
    注意:
    1.在求第一名成绩的时候,不能用row_number(),因为如果同班有两个并列第一,row_number()只返回一个结果          
    2.rank()和dense_rank()的区别是:
      --rank()是跳跃排序,有两个第二名时接下来就是第四名
      --dense_rank()l是连续排序,有两个第二名时仍然跟着第三名
     
     
3.分类统计 (并显示信息)
    A   B   C                      
    -- -- ----------------------
    m   a   2                      
    n   a   3                      
    m   a   2                      
    n   b   2                      
    n   b   1                      
    x   b   3                      
    x   b   2                      
    x   b   4                      
    h   b   3
   select a,c,sum(c)over(partition by a) from t2                
   得到结果:
   A   B   C        SUM(C)OVER(PARTITIONBYA)      
   -- -- ------- ------------------------
   h   b   3        3                        
   m   a   2        4                        
   m   a   2        4                        
   n   a   3        6                        
   n   b   2        6                        
   n   b   1        6                        
   x   b   3        9                        
   x   b   2        9                        
   x   b   4        9                        
  
   如果用sum,group by 则只能得到
   A   SUM(C)                            
   -- ----------------------
   h   3                      
   m   4                      
   n   6                      
   x   9                      
   无法得到B列值       
  
=====

select * from test

数据:
A B C
1 1 1
1 2 2
1 3 3
2 2 5
3 4 6


---将B栏位值相同的对应的C 栏位值加总
select a,b,c, SUM(C) OVER (PARTITION BY B) C_Sum
from test

A B C C_SUM
1 1 1 1
1 2 2 7
2 2 5 7
1 3 3 3
3 4 6 6



---如果不需要已某个栏位的值分割,那就要用 null

eg: 就是将C的栏位值summary 放在每行后面

select a,b,c, SUM(C) OVER (PARTITION BY null) C_Sum
from test

A B C C_SUM
1 1 1 17
1 2 2 17
1 3 3 17
2 2 5 17
3 4 6 17

 

求个人工资占部门工资的百分比

SQL> select * from salary;

NAME DEPT SAL
---------- ---- -----
a 10 2000
b 10 3000
c 10 5000
d 20 4000

SQL> select name,dept,sal,sal*100/sum(sal) over(partition by dept) percent from salary;

NAME DEPT SAL PERCENT
---------- ---- ----- ----------
a 10 2000 20
b 10 3000 30
c 10 5000 50
d 20 4000 100

二:开窗函数           
      开窗函数指定了分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化,举例如下:
1:     
   over(order by salary) 按照salary排序进行累计,order by是个默认的开窗函数
   over(partition by deptno)按照部门分区
2:
  over(order by salary range between 5 preceding and 5 following)
   每行对应的数据窗口是之前行幅度值不超过5,之后行幅度值不超过5
   例如:对于以下列
     aa
     1
     2
     2
     2
     3
     4
     5
     6
     7
     9
   
   sum(aa)over(order by aa range between 2 preceding and 2 following)
   得出的结果是
            AA                       SUM
            ---------------------- -------------------------------------------------------
            1                       10                                                      
            2                       14                                                      
            2                       14                                                      
            2                       14                                                      
            3                       18                                                      
            4                       18                                                      
            5                       22                                                      
            6                       18                                                                
            7                       22                                                                
            9                       9                                                                 
             
   就是说,对于aa=5的一行 ,sum为   5-1<=aa<=5+2 的和
   对于aa=2来说 ,sum=1+2+2+2+3+4=14     ;
   又如 对于aa=9 ,9-1<=aa<=9+2 只有9一个数,所以sum=9    ;
              
3:其它:
     over(order by salary rows between 2 preceding and 4 following)
          每行对应的数据窗口是之前2行,之后4行
4:下面三条语句等效:           
     over(order by salary rows between unbounded preceding and unbounded following)
          每行对应的数据窗口是从第一行到最后一行,等效:
     over(order by salary range between unbounded preceding and unbounded following)
           等效
     over(partition by null)
posted @ 2007-11-26 10:54 brock 阅读(476) | 评论 (0)编辑 收藏

在JDK1.4中使用JAXP1.3
由于JDK1.5以上已经自带jaxp了,而jdk1.4以下版本需要自己添加jaxp库文件。
 
1。下载
因为jwsdp-1.5中带的jaxp是1.26版本,因此需要单独重新下载jaxp
https://jaxp.dev.java.net/files/documents/913/7831/JAXP_RI_20041025.class
 
参考:
https://jaxp.dev.java.net
http://java.sun.com/xml/jaxp/index.jsp
 
2.安装:
JAXP_RI_20041025.class所在的目录下,进入命令行,
运行:java -cp . JAXP_RI_20041025
然后屏幕上列出所有解压出来的文件名字。
此时,在当前目录下会有一个叫jaxp-1_3的目录,里面有jaxp的jar文件和api文档。
 
3.jaxp需要用到的jar为(都在jaxp-1_3目录下):
dom.jar,jaxp-api.jar,sax.jar,xalan.jar,xercesImpl.jar
 
4.接下来就可以根据自己需要来使用jaxp1.3了
 
5.由于sun默认使用的解析器是经过其包装后的(基于Xerces version 2.6.0 和 XSLTC version 2.5.2),比如:
com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl(可查看javax.xml.parsers.SAXParserFactory 的源代码),
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl(可查看javax.xml.transform.TransformerFactory 的源代码).
因此在需要使用其它解析器的时候,需要通过设置系统属性值的方式,
或者在$java.home/lib/jaxp.properties进行配置($java.home为System.getProperty("java.home")所得到的路径,具体可以查看javax.xml.parsers.FactoryFinder源代码中的 static Object find(String factoryId, String fallbackClassName) 方法)来选择具体的解析器实现。
jaxp.properties中支持以下属性.
 
示例文件如下(实际就是jaxp的默认值):
javax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
javax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl javax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
javax.xml.datatype.DatatypeFactory=com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl
 
假如需要使用apache的解析器,那么如下操作 。
a.下载http://www.apache.org/dist/xml/xerces-j/Xerces-J-bin.2.6.2.zip
http://www.eu.apache.org/dist/xml/xalan-j/binaries/xalan-j_2_6_0-bin.zip
(均为当前最新版本)
b.解压获得相应的jar文件,放入classpath中。
3.配置jaxp.properties为:
javax.xml.transform.TransformerFactory=org.apache.xalan.xsltc.trax.TransformerFactoryImpl
#也可以使用
#javax.xml.transform.TransformerFactory=org.apache.xalan.processor.TransformerFactoryImpl
javax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl
javax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
javax.xml.datatype.DatatypeFactory=org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl
 
 
 
 
 
6.需要关于jaxp的调试信息,设置系统属性jaxp.debug为1即可
   System.setProperty("jaxp.debug","1");
或者运行时的命令为: java -Djaxp.debug=1 com.lizongbo.TestJAXP
 
 
 
几篇非常好的资料:
 
JAXP 专述 Sun 的 Java API for XML 语法分析
JAXP 再述 Sun 的 Java API for XML Parsing,1.1 版
http://www-128.ibm.com/developerworks/cn/xml/jaxp1/index.html
 
JAXP 1.3 的新特性,第 1 部分
技术综述,考察解析 API 的变化和新的验证 API
http://www-128.ibm.com/developerworks/cn/xml/x-jaxp13a.html
JAXP 1.3 的新特性,第 2 部分
XPath 功能、支持名称空间的工具和其他改进
http://www-128.ibm.com/developerworks/cn/xml/x-jaxp13b.html
JAXP 全面介绍,第 1 部分
XML 处理工具包使解析和验证变得更容易
http://www-128.ibm.com/developerworks/cn/xml/x-jaxp/index.html
 
Factory模式和Abstract Factory模式
http://www.netbei.com/Article/jsp/jsp6/200409/2771.html
 
Java中关于XML的API一瞥
http://www.matrix.org.cn/article/1073.html
 
 


Trackback: http://tb.donews.net/TrackBack.aspx?PostId=418679

posted @ 2007-10-31 14:51 brock 阅读(289) | 评论 (0)编辑 收藏

 1select
 2 a.tsjbxx_djrq,
 3 b.sqxz_desc,
 4 a.TSJBXX_TSNR,
 5 a.TSJBXX_SSQX,
 6 c.wtxz_mc,
 7 decode(a.tsjbxx_Bjcsjg,'01','结案',
 8        '02','跟踪',
 9        '03','改派',
10        '04','续办',
11        '05','督办',
12        a.tsjbxx_Bjcsjg) tsjbxx_Bjcsjg
13
14/*
15(CASE 
16WHEN a.TSJBXX_BJCSJG='01' THEN '结案'
17WHEN a.TSJBXX_BJCSJG='02' THEN '跟踪'
18WHEN a.TSJBXX_BJCSJG='03' THEN '改派'
19ELSE a.tsjbxx_Bjcsjg
20END
21)
22*/

23
24from tsgl_tsjbxx a ,code_sqxz b , code_wtxz c
25
26where a.Tsjbxx_Wgxzfl= b.sqxz_code(+)
27       and  a.TSJBXX_WGWTFL=c.wtxz_id(+)



------------------------------------
--select DISTINCT t.tsjbxx_blbm  from tsgl_tsjbxx t
--select  t.tsjbxx_blbm  from tsgl_tsjbxx t group by tsjbxx_blbm
--------------------------------------------
posted @ 2007-10-30 12:07 brock 阅读(146) | 评论 (0)编辑 收藏

 

问?: 
表:
col1 col2 col3
1.5 a
1.5 b
2.5 c
2.5 d
5.5 e
5.5 f
1.2 g
1.2 h
1.2 i
1.1 j

我想取得这样的结果:
1.5 a,b
2.5 c,d
1.1 J
1.2 i
5.5 e,f
1.2 h

也就是按col1、col2分组统计,将col3的值用“,”连接起来。

其中col1 是 字符型 col2是数字型。这两个字段的唯一值的个数是未知的

不知该如何才能做到,请各位高手帮忙。


答!: 
1:
id name
1 aa
2 bb
3 cc
4 dd
1 ee
1 xxx
ID相同的行只显示一条记录并把相同ID的NAME加起来用,隔开
怎么搞
???
我需要的结果集是: 
id name
1 aa,ee,xxx
2 bb
3 cc
4 dd
---------------------------------
假设你的table 是 tmp_1;
--------------------------------------------
create table tmp_2 as select 
* from tmp_1 where 1=2;
insert into tmp_2 select distinct id,
null from tmp_1;
declare
i number(
4);
cursor c_v is select 
* from ttmp_1;
begin 
for v_n in c loop
select count(
*) into i from ttmp_2 b where b.name is not null and b.id=v_n.id;
if i=0 then
update ttmp_2 a set name 
= v_n.name where a.id=v_n.id;
else
update ttmp_2 a set name 
= name||','||v_n.name where a.id=v_n.id;
end 
if;
end loop;
end;
/
------------------------------------
或许以下的更有帮助

给你看看duanzilin (寻)的文章吧,一个强贴,地址忘记了,还好有保存


主  题: 原创+突发奇想+分享+散分-----关于分组后字段拼接的问题

作  者: duanzilin (寻) 
信 誉 值: 
120 
所属论坛: Oracle 基础和管理 
问题点数: 
200 
回复次数: 
29 
发表时间: 
2005-7-22 11:52:56 





最近在论坛上,经常会看到关于分组后字段拼接的问题,
大概是类似下列的情形:
SQL
> select no,q from test
2 /

NO Q
---------- ------------------------------
001 n1
001 n2
001 n3
001 n4
001 n5
002 m1
003 t1
003 t2
003 t3
003 t4
003 t5
003 t6

12 rows selected

最后要得到类似于如下的结果:
001 n1;n2;n3;n4;n5
002 m1
003 t1;t2;t3;t4;t5;t6

通常大家都认为这类问题无法用一句SQL解决,本来我也这么认为,可是今天无意中突然有了灵感,原来是可以这么做的:
前几天有人提到过sys_connect_by_path的用法,我想这里是不是也能用到这个方法,如果能做到的话,不用函数或存贮过程也可以做到了;要用到sys_connect_by_path,首先要自己构建树型的结构,并且树的每个分支都是单根的,例如1
-2-3-4,不会存在1-21-〉3的情况;
我是这么构建树,很简单的,看下面的结果就会知道了:
SQL
> select no,q,rn,lead(rn) over(partition by no order by rn) rn1
2 from (select no,q,row_number() over(order by no,q desc) rn from test)
3 /

NO Q RN RN1
---------- ------------------------------ ---------- ----------
001 n5 1 2
001 n4 2 3
001 n3 3 4
001 n2 4 5
001 n1 5 
002 m1 6 
003 t6 7 8
003 t5 8 9
003 t4 9 10
003 t3 10 11
003 t2 11 12
003 t1 12 

12 rows selected

有了这个树型的结构,接下来的事就好办了,只要取出拥有全路径的那个path,问题就解决了,先看no
=001’的分组:
select no,sys_connect_by_path(q,
';') result from 
(select no,q,rn,lead(rn) over(partition by no order by rn) rn1 
from (select no,q,row_number() over(order by no,q desc) rn from test)
)
start with no 
= '001' and rn1 is null connect by rn1 = prior rn
SQL
> 
6 /

NO RESULT
---------- --------------------------------------------------------------------------------
001 ;n1
001 ;n1;n2
001 ;n1;n2;n3
001 ;n1;n2;n3;n4
001 ;n1;n2;n3;n4;n5

上面结果的最后1条就是我们要得结果了
要得到每组的结果,可以下面这样

select t.
*,
(
select max(sys_connect_by_path(q,
';')) result from 
(select no,q,rn,lead(rn) over(partition by no order by rn) rn1 
from (select no,q,row_number() over(order by no,q desc) rn from test)
)
start with no 
= t.no and rn1 is null connect by rn1 = prior rn
) value
from (select distinct no from test) t

SQL
> 
10 /

NO VALUE
---------- --------------------------------------------------------------------------------
001 ;n1;n2;n3;n4;n5
002 ;m1
003 ;t1;t2;t3;t4;t5;t6

对上面结果稍加处理就可以了,希望对大家有帮助:) 
答!: 
2:
注意注意 

sys_connect_by_path有长度限制,不能超过4K 
posted @ 2007-09-13 10:14 brock 阅读(536) | 评论 (0)编辑 收藏

1问题: hibernate不用外键作查询:
1.1最终解办法: 利用hibernate 的视图功能
Hibernate3增加了视图功能

1. 定义hbm

    <class name="Customer" table="customer">        
        
<id name="id" unsaved-value="0" column="id">
            
<generator class="hilo"/>
        
</id>        
        
<property name="name"  not-null="true"/>        
    
</class>
    
    
<class name="Supplier" table="supplier">        
        
<id name="id" unsaved-value="0" column="id">
            
<generator class="hilo"/>
        
</id>
        
<property name="name" not-null="true"/>            
    
</class>
    
    
<class name="All" mutable="false">    
        <subselect>
            select id, name from customer
            union 
            select id, name from supplier
        
</subselect>
        
        
<synchronize table="customer"/>
        
<synchronize table="supplier"/>
        
        
<id name="id" unsaved-value="0" column="id">
            
<generator class="hilo"/>
        
</id>        
        
<property name="name"/>        
    
</class>


2. 定义POJO

pulic class Customer {
    
public Integer id;
    
public String name;
}


pulic 
class Supplier {
    
public Integer id;
    
public String name;
}


pulic 
class All {
    
public Integer id;
    
public String name;
}


3. 查询

List all = session.createQuery("from All").list();
注意:黄色地区


解决办法二

1.2 在数据表里 建视图, 把视图当表操作.

解决办法三
1.3 设外键=没说,,哈哈

总结,不用外键.为了建表方便.  

To Be Continued……



posted @ 2007-09-04 11:02 brock 阅读(296) | 评论 (0)编辑 收藏

使用<%! %>方式所声明的变量为全局变量,即表示:若同时n 个用户在执行此JSP网页时,
将会共享此变量。因此笔者强烈建议读者,千万别使用<%! %>来声明您的变量。
若要声明变量时,请直接在<% %>之中声明使用即可。
----------------------------------------------------------------------------------
有时候,我们想要让网页自己能自动更新,因此,须使用到Refresh 这个标头。举个例子,我
们告诉浏览器,每隔三分钟,就重新加载此网页:
response.setIntHeader("Refresh" , 180)
如果想要过十秒后,调用浏览器转到http://Server/Path 的网页时,可用如下代码:
response.setHeader("Refresh","10; URL=http://Server/Path" )
如果大家对HTML 语法还熟悉,则HTML 语法中也有类似的功能:
<META HTTP-EQUIV="Refresh" CONTENT=" 10; URL=http://Server/Path" >
上述两种方法皆可以做到自动重新加载。
----------------------------------------------------------------------------------

jsp隐式对象

输入输出对象 out request response
作用域通讯对象 session application pagecontext
servlet对象  page config
错误对象  exception
----------------------------------------------------------------------------------

servlet:
request.setAttribute("articleComment",articleCommentArrayList);
        RequestDispatcher dispatcher = request.getRequestDispatcher("pages/delcomment.jsp");

jsp:
ArrayList articletypeArrayList = (ArrayList)request.getAttribute("articleType");
----------------------------------------------------------------------------------
jsp标准动作

jsp:useBean
jsp:setProperty
jsp:getProperty
jsp:include
jsp:forword
jsp:parm
----------------------------------------------------------------------------------
<button name="but" onclick="document.form1.submit()">提交</button>
location.href="abc.htm";   跳到另一页 也可刷新本页
----------------------------------------------------------------------------------
Core 主要

表达式操作:out ,set ,remove,catch等;
流程控制:if choose when otherwise
迭代操作:forEach forTokens

前提条件是用taglib 引入核心标签库
--------------------------------------------------------------------------------------
表达式操作
-------------------------------------------
<c:out>不可以不带主体
<c:out value=需要显示的内容 default=如果value的值为空,则显示default的值 escapeXml是否转换特殊字符,如设定为真,默认会将<,>,、等字符转换成&lt等;
<c:out value ="<p>有特殊字符</p>">
<c:out value ="<p>有特殊字符</p> escapeXml="false" ">
<c:set>将变量存贮在JSP范围内或javabean中
-------------------------------------------

<c:set>
可以带主体也可以不带
<c:set value="要存在变量中的值" var scope=默认page/>
<c:set  var scope>主体中的内容存在变量中 </c:set>
<c:set  value ="要存在对象中的值" target="javabean的对象" property="属性名"/>
<c:set  target="javabean的对象" property="属性名">
主体中的内容存在对象中 </c:set>
<c:set var="num"> 1+1 </c:set>
-------------------------------------------
<c:remove var="要移出的变量名" scope可有可无>  如果不写scope就会按照page->request->session->application的范围顺序依次删除
-------------------------------------------
<c:catch>主要将可能发生的错误放在<c:catch>和</c:catch>之间
如果真的发生错误将把错误信息存贮在var中
<c:catch var="errorMessage">
<% String str="no number" ; int i=Integer.parseInt(str);%>
</catch>
${errorMessage}
-------------------------------------------


流程控制<c:if> <c:choose> <c:when> <c:otherwise>

--------------------------------------------------------------------------------------
<c:if test(必须有test属性)="测试条件" var="用来存储test后的结果">
当条件为真时,执行主体内容
</c:if>
<c:if test="{param.username}=='admin'" var="con" >
您好,admin
</c:if>
${con}
执行的时候在jsp的后面直接加上?username=admin
-------------------------------------------
<c:choose>本身只当作<c:when>和<c:otherwise>的父标签
<c:choose></c:choose>主体内容为
1.空白
2.1或多个<c:when>
3.0个或1个<c:otherwise>,<c:when>必须在<c:otherwise>之前
<c:when test="必须的测试条件">
-------------------------------------------
<c:forEach>为循环控制,它可以将集合(Collection)中的成员按循序浏览一遍,当条件符合时,就会继续;
var用于存放现在指到的成员;String
varstatus用来存放现在知道的相关成员的信息  String
例如:varstatus="a"
则a还有四个属性,index,count,first和last
index:number 现在指到的成员的索引
count:number 总共指到的成员的总数
first:boolean 现在指到的成员是否是第一个成员
last:boolean 现在指到的成员是否为最后一个成员
items 被迭代的集合对象,包括:Arrays Collection Iterator Enumeration Map String

begin开始的位置int
end结束的位置int
step每次迭代的间隔数int
限定begin如果有必须大于0,end必须大于begin
step必须大于等于1

<%
   String a[]= new String[3];
  a[0]="hello ";
  a[1]="this";
  a[2]=" is a test";
  request.setAttribute("att",a);
%>
<c:forEach items="${"att"}" var="items" varStatus="s">
  ${item}
  item有效范围在foreach中
  index:${s.index}
  count:${s.count}
  first:${s.first}
  last:${s.last}
</c:forEach>
不同的begin和end的设置输出不一样
-------------------------------------------
<c:forTokens>
</c:forTokens>用来浏览一字符串中所有的成员,其成员定义由定义符号来分隔
delims定义用来分隔字符串的字符
<c:forEach>也可以分隔字符串,但不能设定分隔符
<c:forEach items="a,b,c,d" var="item">
  ${item}
</c:forEach>
<c:forToken items="a,b,c,d" var="item" delims=",">
  ${item}
</c:forEach>
<c:forToken items="123-456-789" var="item" delims="-">
  ${item}
</c:forEach>
-------------------------------------------
此外,笔者还使用<c:set>来传递值给Core_import.jsp,这就是<c:param>无法做到的动作,
<c:param>只能从包含端抛给被包含端,但是在属性范围中,可以让包含端也能得到被包含端传来的
数据
-------------------------------------------
国际化与格式化标签库 I18N

重写客户端的区域设置
<fmt:setLocale value="语言与国家代码" variant="浏览器变量" scope="page|request|session|application"/>


区域代码  区域,语言
en        英文
en_US     英文(美国)
zh_TW     中文(台湾)
zh_CN     中文(中国)
de_CH      瑞士,德国样式

创建一个I18N本地化上下文,并将资源包加载到其中
<fmt:bundle basename="无扩展名的资源文件名">Body</fmt:bundle>

创建一个I18N本地化上下文,并存在范围变量里
<fmt:setBundle basename="无扩展名的资源文件名" var="指定导出的范围变量的名称" scope="page|request|session|application"/>

给出资源包的输出值
<fmt:message key="消息关键字"/>

格式化数字
<fmt:formatNumber value="要格式化的数字" type="格式类型" minFractionDigits="小数点后保留几位"/>

格式化时间
<fmt:formatDate value=""/>

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

JSTL中最重要的就是国际化格式(I18N)的支持,此功能可以对一个特定的语言请求作出合适的响应。
不同的国家有不同的数据显示格式。如数字356987.589,在法国为356 987,589
在德国356.987,589 在美国356,987.589

I18N格式符主要包含:国际化,消息,数字日期格式化。

详细分类:
国际化setLocale
      requestEncoding:用来设定字符串编码,功能和ServletRequest.setCharacterEncoding()相同

<fmt:setLocale value="一定要有value属性,设定地区代码。其中最少有两个字符的语言代码如zh ,en 然后再加上两个字母的国家和地区代码,用-或_连接"  varitant="浏览器或供应商,如WIN,Mac" >

<%Date n= new Date();
  request.setAttribute("d",n);
%>
<fmt:setLocale value="zh_CN"/><fmt:formatDate value=${d}/>

--消息     bundle     message      param     setBundle
      抓取系统设定的语系资源,作为国际化信息.通过建立存放国际化信息的数据来源.建立propertie文件,并存储在we-inf/classes目录下
      写的时候必须依照key=value
      MyResource.properties
      str1=hello
      str2=My name is Bunny
<fmt:bundle basename="basename" prefix="属性的前缀">
basename是设定要使用的数据源,千万不可有任何的文件类型即扩展名,如.class,或.properties
prefix是前置关键字,如当如下的propertites:
  requestinfo.label.method=Method;
  requestinfo.label.requesturi=URI;
  requestinfo.label.protocol=Protocol;
 我们就可以用以下方法打开
<fmt:bundle basename="MyResource" prefix="requestinfo.label.">
<fmt:message key="protocol"/>
<fmt:message key="method"/>
</fmt:bundle>

 

 <fmt:message>会从指定的资源中把特定的关键字的值抓取出来。
<fmt:setbundle>设定默认的数据源
<fmt:setbundle basename=""  var="存储资源的名称">

<fmt:setbundle>和<fmt:bundle>都可以和<fme:setLocale>搭配使用.多种语言源时,可以将文件名取成如书上例子所示的,当语言取成zh_TW时,它默认去找MyResource_zh_TW.properties作为数据源,如果设定的区域没有符合的文件名,将会使用MyResource.properties 来作为数据源。

如是中文的资源文件,它的内容大部分是Unicode的符号,他们都代表一些中文字,在执行jsp时,会出现乱码,无法正常显示中文;
--------------------------------------------------------------------------------------
SQL标签库
1.设置数据源
  <sql:setDataSource driver="驱动的名字'sun.jdbc.odbc.JdbcOdbcDriver'" url="jdbc:odbc:blog" var="conn"/>
2.用事务建表
  <sql:transaction dataSource="${conn}">
    <sql:update var="newTable">
      sql语句来见表
    </sql:update>
  </sql:transaction>
3.插入记录
  <sql:update var="newRow" dataSource="${conn}">
      insert into tablename values(?,?,?)
      <sql:param value=""/>
      <sql:param value=""/>
  </sql:update>
4.查询记录
  <sql:query var="rs" dataSource="${conn}">
      select * from tablename
  </sql:query>
5.用表格显示记录
  <table border="1">
   <tr>
    <c:forEach var="columnName" items="${rs.columnNames}">
     <th>
      <c:out value="${columnName}"/>
     </th>
    </c:forEach>
   </tr>
   <c:forEach var="row" items="${rs.rowsByIndex}">
    <tr>
      <c:forEach var="column" items="${row}">
    <td>
      <c:out value="${column}"/>
    </td>
   </c:forEach>
    </tr>
   </c:forEach>
  </table>
--------------------------------------------------------------------------------------

import java.util.Calendar;
import java.util.GregorianCalendar;

public class Test {
    public static void main(String[] argv) {
        //返回一个当前日期和时间的Calendar
        Calendar curDate = Calendar.getInstance();
        //返回今天夜里零时的Calendar(这里不明白看API)
        Calendar tommorowDate = new GregorianCalendar(curDate
                .get(Calendar.YEAR), curDate.get(Calendar.MONTH), curDate
                .get(Calendar.DATE) + 1, 0, 0, 0);
        //一天24小时当中,当前过了多少毫秒(用一天24小时的毫秒数减去一天剩余时间的毫秒数)
        System.out.println((60*60*24*1000-(tommorowDate.getTimeInMillis() - curDate
                .getTimeInMillis())));
    }
}

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

转换成时间
DateFormat format = new SimpleDateFormat("H:dd");
Date date = format.parse("8:00");

加上20分钟,如果是减去20分钟的话用-20
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.MINUTE, 20);

--------------------------------------------------------------------------------------
11.JSP中动态INCLUDE与静态INCLUDE的区别?
动态INCLUDE用jsp:include动作实现
它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数
静态INCLUDE用include伪码实现,定不会检查所含文件的变化,适用于包含静态页面
--------------------------------------------------------------------------------------
int i=100;
String binStr=Integer.toBinaryString(i);
String otcStr=Integer.toOctalString(i);
String hexStr=Integer.toHexString(i);
System.out.println(binStr);
System.out.println(otcStr);
System.out.println(hexStr);
--------------------------------------------------------------------------------------
Calendar date=Calendar.getInstance();
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");

String name=format.format(date.getTime());
--------------------------------------------------------------------------------------

使用WEB容器捕获异常进行处理,在web.xml文件头部加上:
<error-page>
   <exception-type>java.lang.Exception</exception-type>
   <location>/system_error.jsp</location>-----出错后转向system_error.jsp页面
</error-page>
<error-page>
   <error-code>404</error-code>
   <location>/system_error.jsp</location>-----出错后转向system_error.jsp页面
</error-page>
<error-page>
   <error-code>400</error-code>
   <location>/system_error.jsp</location>-----出错后转向system_error.jsp页面
</error-page>
<error-page>
   <error-code>500</error-code>
   <location>/system_error.jsp</location>-----出错后转向system_error.jsp页面
</error-page>
--------------------------------------------------------------------------------------
Java 运行 记事本
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("notepad"); 



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1535545

posted @ 2007-08-25 14:32 brock 阅读(1567) | 评论 (0)编辑 收藏

request.getParameterValues与request.getParameter的区别:
request.getParameterValues(String   name)是获得如checkbox类(名字相同,但值有多个)的数据。   接收数组变量,如才、checkobx类型    
request.getParameter(String   name)是获得相应名的数据,如果有重复的名,则返回第一个的值. 接收一般变量,如text类型
 

JSP中request.getParameterNames和getParameterValues应用
 

try...{
String name; 
Enumeration  pNames=request.getParameterNames(); 
 while(pNames.hasMoreElements())...{ 
  name=(String)pNames.nextElement();
  out.print(name+"="+request.getParameter(name));
  }
}catch(Exception e)...{
out.print(e.toString());
}
 
 

for (Enumeration iter = request.getParameterNames(); iter.hasMoreElements();) ...{
            String element = (String) iter.nextElement();
            logger.debug("parameter:"+element);
            logger.debug("value:"+request.getParameter(element));
        }
 

String[]   userId   =   request.getParameterValues("userId");  

posted @ 2007-08-25 10:42 brock 阅读(1662) | 评论 (1)编辑 收藏

[http://blog.javascud.org/rss.php?blogId=25&categoryId=32]
测试类 ClobTest.java

/**
 *
 */
package com.chinantn.test;

import java.io.Writer;
import java.sql.Clob;

import oracle.sql.CLOB;

import org.hibernate.Hibernate;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.lob.SerializableClob;

import com.chinantn.sdfda.common.hibernate.HibernateSessionFactory;
import com.chinantn.sdfda.content.domain.Test;

/**
 * @author Administrator
 *
 */
public class ClobTest {

 /**
  * @param args
  */
 public static void main(String[] args) throws Exception{
  Session s = HibernateSessionFactory.currentSession();
  /*//写CLOB
  Transaction tx = s.beginTransaction();
  Test t = new Test();
  t.setContent(Hibernate.createClob(" "));
  s.save(t);
  s.flush();
  s.refresh(t,LockMode.UPGRADE);
  //CLOB clob = (CLOB)t.getContent();
  
  SerializableClob sc= (SerializableClob)t.getContent();
  Clob wrapclob = sc.getWrappedClob();
  CLOB clob = (CLOB)wrapclob;
  
  
// Writer cout = clob.getCharacterOutputStream();
//用文件上传到 clob 字段是乱码 (中文)//
// File file = new File("C:\\1.txt");//修改你要存如的文本
// FileInputStream fin = new FileInputStream(file);
//int read;
//while((read = fin.read())!= -1){
 //        cout.write(read);
 / }
 //fin.close();
//
//下面是正常
  StringBuffer sb = new StringBuffer();
  for(int i = 0; i < 10000; i ++){
   sb.append("我要忍!!!");
  }
  w.write(sb.toString());
  w.flush();
  w.close();
  tx.commit();*/
  /*
  //读CLOB
  Test t = (Test)s.get(Test.class,"109a1b7438[142bece]-8000");
  Clob clob = t.getContent();
  if(clob != null){
   String clobStr = clob.getSubString(1,(int)clob.length());
   System.out.println(clobStr.length());
   System.out.println(clobStr);
  }*/
  
  //更新CLOB
  Transaction tx = s.beginTransaction();
  Test t = (Test)s.get(Test.class,"109a1b7438[142bece]-8000");
  t.setContent(Hibernate.createClob(" "));
  s.update(t);
  s.flush();
  s.refresh(t,LockMode.UPGRADE);
  
  SerializableClob sc= (SerializableClob)t.getContent();
  Clob wrapclob = sc.getWrappedClob();
  CLOB clob = (CLOB)wrapclob;
  
  Writer w = clob.getCharacterOutputStream();
  StringBuffer sb = new StringBuffer();
  for(int i = 0; i < 1000; i ++){
   sb.append("我很努力!!!");
  }
  w.write(sb.toString());
  w.flush();
  w.close();
  tx.commit();
  
  if(clob != null){
   String clobStr = clob.getSubString(1,(int)clob.length());
   System.out.println(clobStr.length());
   System.out.println(clobStr);
  }
  HibernateSessionFactory.closeSession();

 }

}

posted @ 2007-08-13 09:58 brock 阅读(1953) | 评论 (1)编辑 收藏

<SCRIPT LANGUAGE="JavaScript">
<!--
//出处:网上搜集
//made by yaosansi 2005-12-02
//For more visit http://www.yaosansi.com
// Trim() , Ltrim() , RTrim()

String.prototype.Trim = function()
{
return this.replace(/(^\s*)|(\s*$)/g, "");
}

String.prototype.LTrim = function()
{
return this.replace(/(^\s*)/g, "");
}

String.prototype.RTrim = function()
{
return this.replace(/(\s*$)/g, "");
}

//-->
</SCRIPT>

posted @ 2007-07-19 13:59 brock 阅读(281) | 评论 (0)编辑 收藏

function AjaxScript(url, varName, params, onsuccess)
{    
    
var arr = document.getElementsByTagName("script");
    
var url =url.toLowerCase();
    
var isLoad = true;
    
if (arr)
    
{
        
for(i=0; i<arr.length; i++)
        
{
            
var src = arr[i].src;
            
if (src) 
            
{
                
if (src.toLowerCase() == url) { isLoad = false; }
            }

        }

    }

    
    
if (isLoad)
    
{
        
var s = document.createElement("script");
        
        
var params = (params ? params : ""+ (params && varName ? "&" : ""+ (varName ? "varName=" + varName : "")
        
        
if (url.indexOf("?">= 0)
        
{
            url 
+= (params && params != "" ? "&" + params  : "");
        }

        
else
        
{
            url 
+= (params && params != "" ? "?" + params : "");
        }

        
        s.src 
= url;
        s.type 
= "text/javascript";
        s.onreadystatechange 
= function()
        
{    
            
switch(this.readyState)
            
{
                
case "complete":
                
case "loaded":
                    eval(
"try {    if (onsuccess) { onsuccess({0}); delete {0}; }    }catch(e){}".format((varName ?  varName : "")));
                    
break;
                    
                
case "loading":
                    
break;
            }

        }

        s.onload 
= function() { eval("try {    if (onsuccess) { onsuccess({0}); delete {0}; }    }catch(e){}".format((varName ?  varName : ""))); }
        
var arr = document.getElementsByTagName("head");
        
var h= arr[0];
        document.body.appendChild(s);
    }

}
posted @ 2007-07-16 14:17 brock 阅读(328) | 评论 (0)编辑 收藏

exp/imp命令详解

exp/imp两个命令可以说是oracle中最常用的命令了.
ORACLE数据库有两类备份方法。第一类为物理备份,该方法实现数据库的完整恢复,但
数据库必须运行在归挡模式下(业务数据库在非归挡模式下运行),且需要极大的外部
存储设备,例如磁带库;第二类备份方式为逻辑备份,业务数据库采用此种方式,此方
法不需要数据库运行在归挡模式下,不但备份简单,而且可以不需要外部存储设备。
数据库逻辑备份方法
ORACLE数据库的逻辑备份分为三种模式:表备份、用户备份和完全备份。
表模式
备份某个用户模式下指定的对象(表)。业务数据库通常采用这种备份方式。
若备份到本地文件,使用如下命令:
exp icdmain/icd rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0
file=exp_icdmain_csd_yyyymmdd.dmp
log=exp_icdmain_csd_yyyymmdd.log
tables=icdmain.commoninformation,icdmain.serviceinfo,icdmain.dealinfo
若直接备份到磁带设备,使用如下命令:
exp icdmain/icd rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0
file=/dev/rmt0
log=exp_icdmain_csd_yyyymmdd.log
tables=icdmain.commoninformation,icdmain.serviceinfo,icdmain.dealinfo
注:在磁盘空间允许的情况下,应先备份到本地服务器,然后再拷贝到磁带。出于速度
方面的考虑,尽量不要直接备份到磁带设备。
用户模式
备份某个用户模式下的所有对象。业务数据库通常采用这种备份方式。
若备份到本地文件,使用如下命令:
exp icdmain/icd owner=icdmain rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0
file=exp_icdmain_yyyymmdd.dmp
log=exp_icdmain_yyyymmdd.log
若直接备份到磁带设备,使用如下命令:
exp icdmain/icd owner=icdmain rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0
file=/dev/rmt0
log=exp_icdmain_yyyymmdd.log
注:如果磁盘有空间,建议备份到磁盘,然后再拷贝到磁带。如果数据库数据量较小,
可采用这种办法备份。
完全模式
备份完整的数据库。业务数据库不采用这种备份方式。备份命令为:
exp icdmain/icd rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0 full=y
file=exp_fulldb_yyyymmdd.dmp(磁带设备则为/dev/rmt0)
log=exp_fulldb_yyyymmdd.log
对于数据库备份,建议采用增量备份,即只备份上一次备份以来更改的数据。增量备份
命令:
exp icdmain/icd rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0 full=y inctype=incremental
file=exp_fulldb_yyyymmdd.dmp(磁带设备则为/dev/rmt0)
log=exp_fulldb_yyyymmdd.log
注:关于增量备份必须满足下列条件:
1.
只对完整数据库备份有效,且第一次需要full=y参数,以后需要inctype=increment
al参数。
2. 用户必须有EXP_FULL_DATABASE的系统角色。
3. 话务量较小时方可采用数据库备份。
4. 如果磁盘有空间,建议备份到磁盘,然后再备份到磁带。
业务数据库备份方法及周期
用EXP进行备份前,先在SYS用户下运行CATEXP.SQL文件(如果以前已运行该文件,则不
要执行这个脚本)。
没有特殊说明,不允许在客户端执行备份命令。
备份命令参照表模式下的备份命令。
从磁盘文件备份到磁带
如果首先备份到本地磁盘文件,则需要转储到磁带设备上。
1. 若需查看主机上配置的磁带设备,使用如下命令:
lsdev -Cc tape
显示的结果如下例所示:
rmt0 Available 30-58-00-2,0 SCSI 4mm Tape Drive
rmt1 Defined  30-58-00-0,0 SCSI 4mm Tape Drive
标明Available的设备是可用的磁带设备。
2. 若需查看磁带存储的内容,使用如下命令:
tar -tvf /dev/rmt0
显示的结果如下例所示:
-rw-r--r-- 300 400 8089600 Jan 11 14:33:57 2001 exp_icdmain_20010111.dmp
如果显示类似如下内容,则表示该磁带存储的备份数据是从数据库直接备份到磁带上,
而非从本地磁盘转储到磁带的备份文件,因此操作系统无法识别。
tar: 0511-193 An error occurred while reading from the media.
There is an input or output error.

tar: 0511-169 A directory checksum error on media; -267331077 not equal to
2
5626.
3. 对于新磁带或无需保留现存数据的磁带,使用如下命令:
tar -cvf /dev/rmt0 exp_icdmain_yyyymmdd.dmp
注:A. 该命令将无条件覆盖磁带上的现存数据。
  B. 文件名不允许包含路径信息,如:/backup/exp_icdmain_yyyymmdd.dmp。
4. 对于需要保留现存数据的磁带,使用如下命令:
tar -rvf /dev/rmt0 exp_icdmain_yyyymmdd.dmp
注:该命令将文件exp_icdmain_yyyymmdd.dmp追加到磁带的末端,不会覆盖现存的数据

特别强调:如果备份时是从数据库直接备份到磁带上,则不可再向该磁带上追加复制任
何其他文件,否则该备份数据失效。
5. 若需将转储到磁带上的备份文件复制到本地硬盘,使用如下命令:
A. 将磁带上的全部文件复制到本地硬盘的当前目录
tar -xvf /dev/rmt0
B. 将磁带上的指定文件复制到本地硬盘的当前目录
tar -xvf /dev/rmt0 exp_icdmain_yyyymmdd.dmp
备份时间安排
由于备份时对系统I/O有较大影响,所以,建议在晚上11点以后进行备份工作。
业务数据库Oracle版本的恢复
恢复方案需根据备份方案确定。由于业务数据库采用表备份和用户备份相结合的方案,
所以业务数据库的恢复需根据实际情况采用表恢复和用户恢复相结合的方案。
恢复方案
数据库的逻辑恢复分为表恢复、用户恢复、完全恢复三种模式。
表模式
此方式将根据按照表模式备份的数据进行恢复。
A. 恢复备份数据的全部内容
若从本地文件恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=exp_icdmain_cs
d_yyyymmdd.dmp
log=imp_icdmain_csd_yyyymmdd.log
若从磁带设备恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0 file=/dev/rmt0
log=imp_icdmain_csd_yyyymmdd.log
B. 恢复备份数据中的指定表
若从本地文件恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=exp_icdmain_cs
d_yyyymmdd.dmp
log=imp_icdmain_csd_yyyymmdd.log
tables=commoninformation,serviceinfo
若从磁带设备恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=/dev/rmt0
log=imp_icdmain_csd_yyyymmdd.log
tables=commoninformation,serviceinfo
用户模式
此方式将根据按照用户模式备份的数据进行恢复。
A. 恢复备份数据的全部内容
若从本地文件恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=exp_icdmain_yy
yymmdd.dmp
log=imp_icdmain_yyyymmdd.log
若从磁带设备恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0 file=/dev/rmt0
log=imp_icdmain_yyyymmdd.log
B. 恢复备份数据中的指定表
若从本地文件恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=exp_icdmain_yy
yymmdd.dmp
log=imp_icdmain_yyyymmdd.log
tables=commoninformation,serviceinfo
若从磁带设备恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0 file=/dev/rmt0
log=imp_icdmain_yyyymmdd.log
tables=commoninformation,serviceinfo
完全模式
如果备份方式为完全模式,采用下列恢复方法:
若从本地文件恢复,使用如下命令:
imp system/manager rows=y indexes=n commit=y buffer=65536
feedback=100000 ignore=y volsize=0 full=y
file=exp_icdmain_yyyymmdd.dmp
log=imp_icdmain_yyyymmdd.log
若从磁带设备恢复,使用如下命令:
imp system/manager rows=y indexes=n commit=y buffer=65536
feedback=100000 ignore=y volsize=0 full=y
file=/dev/rmt0
log=imp_icdmain_yyyymmdd.log
参数说明
1. ignore参数
Oracle在恢复数据的过程中,当恢复某个表时,该表已经存在,
就要根据ignore参数的设置来决定如何操作。
若ignore=y,Oracle不执行CREATE TABLE语句,直接将数据
插入到表中,如果插入的记录违背了约束条件,比如主键约束,
则出错的记录不会插入,但合法的记录会添加到表中。
若ignore=n,Oracle不执行CREATE TABLE语句,同时也不会
将数据插入到表中,而是忽略该表的错误,继续恢复下一个表。
2. indexes参数
在恢复数据的过程中,若indexes=n,则表上的索引不会被恢复
,但是主键对应的唯一索引将无条件恢复,这是为了保证数据
的完整性。
字符集转换
对于单字节字符集(例如US7ASCII),恢复时,数据库自动转
换为该会话的字符集(NLS_LANG参数);对于多字节字符集
(例如ZHS16CGB231280),恢复时,应尽量使字符集相同
(避免转换),如果要转换,目标数据库的字符集应是输出数
据库字符集的超集。
恢复方法
业务数据库采用表恢复方案。在用IMP进行恢复前,先在SYS
用户下运行CATEXP.SQL文件(如果以前已运行该文件,则
不要执行这个脚本),然后执行下列命令:
IMP ICDMAIN/ICD FILE=文件名 LOG=LOG文件名 ROWS=Y
COMMIT=Y BUFFER=Y IGNORE=Y TABLES=表名
注:要恢复的表名参照备份的表名
  。恢复是在原表基础上累加数据
  。没有特殊说明,不允许在客户端执行恢复命令

将一个数据库的某用户的所有表导到另外数据库的一个用户下面的例子  
exp userid=system/manager owner=username1 file=expfile.dmp
imp userid=system/manager fromuser=username1 touser=username2 ignore=y file=expfile.dmp



将一个数据库的某用户的所有表导到另外数据库的一个用户下面的例子  

exp userid=system/manager owner=username1 file=expfile.dmp
imp userid=system/manager fromuser=username1 touser=username2 ignore=y file=expfile.dmp

ORACLE数据库有两类备份方法。第一类为物理备份,该方法实现数据库的完整恢复,但
数据库必须运行在归挡模式下(业务数据库在非归挡模式下运行),且需要极大的外部
存储设备,例如磁带库;第二类备份方式为逻辑备份,业务数据库采用此种方式,此方
法不需要数据库运行在归挡模式下,不但备份简单,而且可以不需要外部存储设备。
数据库逻辑备份方法
ORACLE数据库的逻辑备份分为三种模式:表备份、用户备份和完全备份。
表模式
备份某个用户模式下指定的对象(表)。业务数据库通常采用这种备份方式。
若备份到本地文件,使用如下命令:
exp icdmain/icd rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0
file=exp_icdmain_csd_yyyymmdd.dmp
log=exp_icdmain_csd_yyyymmdd.log
tables=icdmain.commoninformation,icdmain.serviceinfo,icdmain.dealinfo
若直接备份到磁带设备,使用如下命令:
exp icdmain/icd rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0
file=/dev/rmt0
log=exp_icdmain_csd_yyyymmdd.log
tables=icdmain.commoninformation,icdmain.serviceinfo,icdmain.dealinfo
注:在磁盘空间允许的情况下,应先备份到本地服务器,然后再拷贝到磁带。出于速度
方面的考虑,尽量不要直接备份到磁带设备。
用户模式
备份某个用户模式下的所有对象。业务数据库通常采用这种备份方式。
若备份到本地文件,使用如下命令:
exp icdmain/icd owner=icdmain rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0
file=exp_icdmain_yyyymmdd.dmp
log=exp_icdmain_yyyymmdd.log
若直接备份到磁带设备,使用如下命令:
exp icdmain/icd owner=icdmain rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0
file=/dev/rmt0
log=exp_icdmain_yyyymmdd.log
注:如果磁盘有空间,建议备份到磁盘,然后再拷贝到磁带。如果数据库数据量较小,
可采用这种办法备份。
完全模式
备份完整的数据库。业务数据库不采用这种备份方式。备份命令为:
exp icdmain/icd rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0 full=y
file=exp_fulldb_yyyymmdd.dmp(磁带设备则为/dev/rmt0)
log=exp_fulldb_yyyymmdd.log
对于数据库备份,建议采用增量备份,即只备份上一次备份以来更改的数据。增量备份
命令:
exp icdmain/icd rows=y indexes=n compress=n buffer=65536
feedback=100000 volsize=0 full=y inctype=incremental
file=exp_fulldb_yyyymmdd.dmp(磁带设备则为/dev/rmt0)
log=exp_fulldb_yyyymmdd.log
注:关于增量备份必须满足下列条件:
1.
只对完整数据库备份有效,且第一次需要full=y参数,以后需要inctype=increment
al参数。
2. 用户必须有EXP_FULL_DATABASE的系统角色。
3. 话务量较小时方可采用数据库备份。
4. 如果磁盘有空间,建议备份到磁盘,然后再备份到磁带。
业务数据库备份方法及周期
用EXP进行备份前,先在SYS用户下运行CATEXP.SQL文件(如果以前已运行该文件,则不
要执行这个脚本)。
没有特殊说明,不允许在客户端执行备份命令。

备份命令参照表模式下的备份命令。
从磁盘文件备份到磁带
如果首先备份到本地磁盘文件,则需要转储到磁带设备上。
1. 若需查看主机上配置的磁带设备,使用如下命令:
lsdev -Cc tape
显示的结果如下例所示:
rmt0 Available 30-58-00-2,0 SCSI 4mm Tape Drive
rmt1 Defined  30-58-00-0,0 SCSI 4mm Tape Drive
标明Available的设备是可用的磁带设备。
2. 若需查看磁带存储的内容,使用如下命令:
tar -tvf /dev/rmt0
显示的结果如下例所示:
-rw-r--r-- 300 400 8089600 Jan 11 14:33:57 2001 exp_icdmain_20010111.dmp
如果显示类似如下内容,则表示该磁带存储的备份数据是从数据库直接备份到磁带上,
而非从本地磁盘转储到磁带的备份文件,因此操作系统无法识别。
tar: 0511-193 An error occurred while reading from the media.
There is an input or output error.

tar: 0511-169 A directory checksum error on media; -267331077 not equal to
2
5626.
3. 对于新磁带或无需保留现存数据的磁带,使用如下命令:
tar -cvf /dev/rmt0 exp_icdmain_yyyymmdd.dmp
注:A. 该命令将无条件覆盖磁带上的现存数据。
  B. 文件名不允许包含路径信息,如:/backup/exp_icdmain_yyyymmdd.dmp。
4. 对于需要保留现存数据的磁带,使用如下命令:
tar -rvf /dev/rmt0 exp_icdmain_yyyymmdd.dmp
注:该命令将文件exp_icdmain_yyyymmdd.dmp追加到磁带的末端,不会覆盖现存的数据

特别强调:如果备份时是从数据库直接备份到磁带上,则不可再向该磁带上追加复制任
何其他文件,否则该备份数据失效。
5. 若需将转储到磁带上的备份文件复制到本地硬盘,使用如下命令:
A. 将磁带上的全部文件复制到本地硬盘的当前目录
tar -xvf /dev/rmt0
B. 将磁带上的指定文件复制到本地硬盘的当前目录
tar -xvf /dev/rmt0 exp_icdmain_yyyymmdd.dmp
备份时间安排
由于备份时对系统I/O有较大影响,所以,建议在晚上11点以后进行备份工作。
业务数据库Oracle版本的恢复
恢复方案需根据备份方案确定。由于业务数据库采用表备份和用户备份相结合的方案,
所以业务数据库的恢复需根据实际情况采用表恢复和用户恢复相结合的方案。
恢复方案
数据库的逻辑恢复分为表恢复、用户恢复、完全恢复三种模式。
表模式
此方式将根据按照表模式备份的数据进行恢复。
A. 恢复备份数据的全部内容
若从本地文件恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=exp_icdmain_cs
d_yyyymmdd.dmp
log=imp_icdmain_csd_yyyymmdd.log
若从磁带设备恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0 file=/dev/rmt0
log=imp_icdmain_csd_yyyymmdd.log
B. 恢复备份数据中的指定表
若从本地文件恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=exp_icdmain_cs
d_yyyymmdd.dmp
log=imp_icdmain_csd_yyyymmdd.log
tables=commoninformation,serviceinfo
若从磁带设备恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=/dev/rmt0
log=imp_icdmain_csd_yyyymmdd.log
tables=commoninformation,serviceinfo
用户模式
此方式将根据按照用户模式备份的数据进行恢复。
A. 恢复备份数据的全部内容
若从本地文件恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=exp_icdmain_yy
yymmdd.dmp
log=imp_icdmain_yyyymmdd.log
若从磁带设备恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0 file=/dev/rmt0
log=imp_icdmain_yyyymmdd.log
B. 恢复备份数据中的指定表
若从本地文件恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0
file=exp_icdmain_yy
yymmdd.dmp
log=imp_icdmain_yyyymmdd.log
tables=commoninformation,serviceinfo
若从磁带设备恢复,使用如下命令:
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n
commit=y buffer=65536 feedback=100000 ignore=n volsize=0 file=/dev/rmt0
log=imp_icdmain_yyyymmdd.log
tables=commoninformation,serviceinfo
完全模式
如果备份方式为完全模式,采用下列恢复方法:
若从本地文件恢复,使用如下命令:
imp system/manager rows=y indexes=n commit=y buffer=65536
feedback=100000 ignore=y volsize=0 full=y
file=exp_icdmain_yyyymmdd.dmp
log=imp_icdmain_yyyymmdd.log
若从磁带设备恢复,使用如下命令:
imp system/manager rows=y indexes=n commit=y buffer=65536
feedback=100000 ignore=y volsize=0 full=y
file=/dev/rmt0
log=imp_icdmain_yyyymmdd.log
参数说明
1. ignore参数
Oracle在恢复数据的过程中,当恢复某个表时,该表已经存在,
就要根据ignore参数的设置来决定如何操作。
若ignore=y,Oracle不执行CREATE TABLE语句,直接将数据
插入到表中,如果插入的记录违背了约束条件,比如主键约束,
则出错的记录不会插入,但合法的记录会添加到表中。
若ignore=n,Oracle不执行CREATE TABLE语句,同时也不会
将数据插入到表中,而是忽略该表的错误,继续恢复下一个表。
2. indexes参数
在恢复数据的过程中,若indexes=n,则表上的索引不会被恢复
,但是主键对应的唯一索引将无条件恢复,这是为了保证数据
的完整性。
字符集转换
对于单字节字符集(例如US7ASCII),恢复时,数据库自动转
换为该会话的字符集(NLS_LANG参数);对于多字节字符集
(例如ZHS16CGB231280),恢复时,应尽量使字符集相同
(避免转换),如果要转换,目标数据库的字符集应是输出数
据库字符集的超集。
恢复方法
业务数据库采用表恢复方案。在用IMP进行恢复前,先在SYS
用户下运行CATEXP.SQL文件(如果以前已运行该文件,则
不要执行这个脚本),然后执行下列命令:
IMP ICDMAIN/ICD FILE=文件名 LOG=LOG文件名 ROWS=Y
COMMIT=Y BUFFER=Y IGNORE=Y TABLES=表名
注:要恢复的表名参照备份的表名
  。恢复是在原表基础上累加数据
  。没有特殊说明,不允许在客户端执行恢复命令

posted @ 2007-07-03 18:09 brock 阅读(496) | 评论 (0)编辑 收藏

Building Applications Using Ant 1.6
posted @ 2007-07-03 14:47 brock 阅读(107) | 评论 (0)编辑 收藏

蚂蚁啃骨头
posted @ 2007-07-03 14:43 brock 阅读(93) | 评论 (0)编辑 收藏

 1 /**
 2  * Project:        
 3  * Author:        zhy
 4  * Company:     
 5  * Created Date:    2007-6-29
 6  * 
 7  * Copyright @ 2007
 8  * 
 9  * History:
10  * ------------------------------------------------------------------------------
11  * Date            |time        |Author    |Change Description        */
12 
13 var Obj = function (key ,value){
14    this.key = key; 
15    this.value = value;
16 };
17 var ha = new Array();
18 var Hash = function (){
19    //this.a =ha;
20 }
21 Hash.prototype.haa = function (){
22     return ha;
23 }
24 Hash.prototype.clear = function (){
25     ha = new Array();
26 }
27 Hash.prototype.clone = function (){
28     return this;
29 }
30 Hash.prototype.get = function (key){
31    
32     for(var i=0;i<ha.length ;i++){
33         if(ha[i].key==key){
34             return ha[i].value;
35         }
36     }
37    
38 }
39 Hash.prototype.put = function (key ,value){
40 
41     if(ha.length !=0){
42        
43          for(var i=0;i<ha.length;i++){
44             if(ha[i].key != key){
45                  ha[ha.length]=new Obj(key ,value);
46             }
47          }    
48     }else{
49          ha[ha.length]=new Obj(key ,value);
50    }
51    
52  
53 }
54 
55 Hash.prototype.size = function (){
56     return ha.length ;
57 }
58 
59 Hash.prototype.remove = function (key){
60       for(var i=0;i<ha.length;i++){
61         if(ha[i].key == key){
62            ha.without(ha[i]);
63         }
64     }
65 

posted @ 2007-07-03 14:38 brock 阅读(1284) | 评论 (0)编辑 收藏

url?
String skey = request.getParameter("key");
当url没有 key=""时  skey 为Null
url? key=
当url 有时skey 为 "" 也就是一个为空的对象
posted @ 2007-06-20 11:14 brock 阅读(225) | 评论 (0)编辑 收藏

翻译自:In Search of the Holy Grail
原文:http://www.alistapart.com/articles/holygrail
这个翻译的页面版权归greengnn所有,转载请注明出处
第一步:创建一个结构

xhtml开始于header, footer, and container
<div id="header"></div>

<div id="container"></div>

<div id="footer"></div>

CSS先定义container,给将要加入的sideleft,和sideright留下个位置
#container {
 padding-left: 200px; /* LC width */
 padding-right: 150px; /* RC width */
}

我们的布局现在看起来是这样的

uploads/200602/13_074820_diagram_01.gif


图1——创建框架

第二步:增加内容元素

在第一步基础上增加内容元素<div id="header"></div>

<div id="container">
 <div id="center" class="column"></div>
 <div id="left" class="column"></div>
 <div id="right" class="column"></div>
</div>

<div id="footer"></div>

然后分别定义widths和float 让元素排列在一条线上,还有清除footer的浮动对齐
#container .column {
 float: left;
}
#center {
 width: 100%;
}
#left {
 width: 200px; /* LC width */
}
#right {
 width: 150px; /* RC width */
}
#footer {
 clear: both;
}

这里给center元素定义了100% width,让它占满montainer的可用空间,现在的布局变成了这样

uploads/200602/13_074922_diagram_02.gif


图2:增加内容元素

第三步:把left放到正确的位置

要把left放到正确的位置,我们分两步

1.让left和center在同一水平线#left {
 width: 200px; /* LC width */
 margin-left: -100%;
}

看看效果

uploads/200602/13_075000_diagram_03.gif


图3——left移动完成一半

2.用相对定位,把left继续移动到正确的位置#container .columns {
 float: left;
 position: relative;
}
#left {
 width: 200px; /* LC width */
 margin-left: -100%;
 right: 200px; /* LC width */
}

上一步,left还需要左移200px,就可以了,所以就采用相对定位,将他再向左推200px,就达到了想要的效果。让left距离他右边元素center 200px后,行了,left终于到自己位置上了。

uploads/200602/13_075037_diagram_04.gif


图4——left到了自己的位置

第四步:让right也到自己的正确的位置上

从上图看,我们只需要把right推倒container的padding-right里面,看看怎么做
#right {
 width: 150px; /* RC width */
 margin-right: -150px; /* RC width */
}

好了,现在元素们都正确归位了。

uploads/200602/13_075115_diagram_05.gif


图5——right到了自己正确的位置

第五步:解决bug让布局更完美
如果浏览器类型变更,center就变得比left小了,完美的布局就被打破,我们给body 设置一个min-width
来解决这个问题,因为IE不支持他,所以不会有负面影响,调整如下
body {
 min-width: 550px; /* 2x LC width + RC width */
}

这时在IE6(完全打开的窗口)下,left元素距离左侧又太远了,再调整
* html #left {
 left: 150px; /* RC width */
}

这些大小调整是根据上面已经定义的宽度来的,你调整的时候也要根据自己的实际情况。

现在增加padding

内容文字贴着容器的边,相信你看得时候,不会很舒服,调整一下
#left {
 width: 180px; /* LC fullwidth - padding */
 padding: 0 10px;
 right: 200px; /* LC fullwidth */
 margin-left: -100%;
}

当然不能只增加left就算完事,要给一系列元素都必须加上,也要调整增加padding,带来的新的bug,调整如下
body {
 min-width: 630px; /* 2x (LC fullwidth +
 CC padding) + RC fullwidth */
}
#container {
 padding-left: 200px; /* LC fullwidth */
 padding-right: 190px; /* RC fullwidth + CC padding */
}
#container .column {
 position: relative;
 float: left;
}
#center {
 padding: 10px 20px; /* CC padding */
 width: 100%;
}
#left {
 width: 180px; /* LC width */
 padding: 0 10px; /* LC padding */
 right: 240px; /* LC fullwidth + CC padding */
 margin-left: -100%;
}
#right {
 width: 130px; /* RC width */
 padding: 0 10px; /* RC padding */
 margin-right: -190px; /* RC fullwidth + CC padding */
}
#footer {
 clear: both;
}

/*** IE Fix ***/
* html #left {
 left: 150px; /* RC fullwidth */
}
header和footer的padding可以随意增加,这里就不提了,还有长度单位用em更具亲和力(em可以让用户使用浏览器来调整自己需要的字体大小)
但是不能混合使用,选择em和px的时候明智些,察看效果

元素等高问题
采用http://www.positioniseverything.net/articles/onetruelayout/equalheight
有人翻译过来的:http://www.blueidea.com/tech/web/2006/3210.asp
里提到的方法,就不具体解释了。
#container {
 overflow: hidden;
}
#container .column {
 padding-bottom: 20010px; /* X + padding-bottom */
 margin-bottom: -20000px; /* X */
}
#footer {
 position: relative;
}

再解决opera 8的bug,代码调整如下
<div id="footer-wrapper">
 <div id="footer"></div>
</div>
* html body {
 overflow: hidden;
}
* html #footer-wrapper {
 float: left;
 position: relative;
 width: 100%;
 padding-bottom: 10010px;
 margin-bottom: -10000px;
 background: #fff; /* Same as body
 background */
}
posted @ 2007-06-14 10:00 brock 阅读(226) | 评论 (0)编辑 收藏

<style>
body{
margin:0 auto;
}
#ddd{
margin:0 auto;
padding: 3px;
background:#00FFCC;
border:solid 1px;
height: 300px;
}
#ddd h4{
margin:0px;
background:#6666FF;
line-height:20px;

}
#ddd ul{
margin:0px;
padding: 3px;
list-style:none;
}
#ddd ul li {

float:left;
}

#ddd a:visited{
background:#999999 url(../Mcredits.gif);
}
#ddd a:link{
background:#999999 url(../credits.gif);
}
#ddd a:hover{
background:#ff0000;
}

#leftmenu
{
    position: absolute;
    left: 0px;
    width: 400px;
    height: auto;
    background-color: WhiteSmoke;
    padding-top: 0px;
}

#leftmenu h3
{
    font-size: 11.5;
    margin: 0px;
    margin-top: 10px;
    padding-bottom: 2px;
    padding-left: 3px;
    border-top: solid 1px Gainsboro;
    padding-top: 3px;
}

#leftmenu ul
{
list-style:none;

    margin: 0px;
    padding-left: 5px;
    margin-left: 5px;
    margin-bottom: 10px;
    font-size: 11.5;
}
#leftmenu ul li
{
margin:0px;
float:left;
}

#leftmenu a
{
    padding: 1px;
    text-decoration: none;
}

#leftmenu a:active, #leftmenu a:visited, #leftmenu a:link
{
}

#leftmenu a:hover
{
    font-style: italic;
}


</style>
posted @ 2007-06-13 18:13 brock 阅读(210) | 评论 (0)编辑 收藏

初试javax.mail

最近在项目中用到发送邮件的功能,由于以前没有接触过,找了很多资料才终于把它弄出来,今天写下这些,算是做个总结吧。
1、首先定义一个邮件的数据结构类
public class EmailData() {
     String from   = null;  //发件人
     String[] recipients = null;  //收件人,可以多个
     String subject   = null;  //邮件主题
     String content   = null;  //邮件内容
     String contentType  = null;  //邮件内容格式(文本或html)
     String fileName  = null;  //附件文件名(目前只提供一个附件)
 
     //下面是相应的setter/getter方法,省略..
}
2、发送不带附件的邮件(包括文本格式和html两种格式)
public void postMail(EmailData emailData)
 throws MessagingException,Exception {
  
 String from   = emailData.getFrom();
 String[] recipients = emailData.getRecipents();
 String subject   = emailData.getSubject();
 String content   = emailData.getContent();
 String contentType = emailData.getContentType();
 String fileName  = emailData.getFileName();
 
    if (recipients != null && recipients.length > 0) {

     Properties props = new Properties();
     //设置邮件服务器地址,连接超时时限等信息
     props.put("mail.smtp.host", "10.30.1.233"); //10.30.1.233邮件服务器
     props.put("mail.smtp.connectiontimeout", "10000"); //
  props.put("mail.smtp.timeout", "10000");   //
    
     //创建缺省的session对象
     Session session = Session.getDefaultInstance(props, null);
 
     //创建message对象
     Message msg = new MimeMessage(session);
 
     //设置发件人和收件人
     InternetAddress addressFrom = new InternetAddress(from);
     msg.setFrom(addressFrom);  
     InternetAddress[] addressTo = new InternetAddress[recipients.length];
     for (int i = 0; i < recipients.length; i++){
         addressTo[i] = new InternetAddress(recipients[i]);
     }
     msg.setRecipients(Message.RecipientType.TO, addressTo);
  
  //设置邮件标题,中文编码
     subject = MimeUtility.encodeText(new String(subject.getBytes(), "GB2312"), "GB2312", "B");
     msg.setSubject(subject);
    
     //设置邮件内容,区分文本格式和HTML格式
     if (contentType == null || contentType.equals("text")) {
      msg.setText(content);
  } else if (contentType.equals("html")) {
   //给消息对象设置内容
   BodyPart bodyPart1 = new MimeBodyPart(); //新建一个存放信件内容的BodyPart对象
   mdp.setContent(content, "text/html;charset=gb2312");//给BodyPart对象设置内容和格式/编码方式
   Multipart mmp = new MimeMultipart();//新建一个MimeMultipart对象用来存放BodyPart对象(事实上可以存放多个)
   //设置邮件附件
   BodyPart bodyPart2 = new MimeBodyPart(); 
   FileDataSource fileDataSource = new FileDataSource(fileName);
   bodyPart2.setDataHandler(new DataHandler(fileDataSource));       
   bodyPart2.setFileName("=?GB2312?B?"+enc.encode(fileName.getBytes())+"?=");
   
     
   Multipart multipart = new MimeMultipart();
   multipart.addBodyPart(bodyPart1);
   multipart.addBodyPart(bodyPart2);
   
   mmp.addBodyPart(mdp);//将BodyPart加入到MimeMultipart对象中(可以加入多个BodyPart)
   msg.setContent(mmp);//把mm作为消息对象的内容
  }
     
     //设置邮件发送时间
        msg.setSentDate(new java.util.Date());
        //调用抽象类的静态方法send()发送邮件
     Transport.send(msg);
    }
}

3、发送带附件的邮件稍微复杂一些,跟发送普通邮件的区别主要如下:
   //设置邮件内容
   BodyPart bodyPart1 = new MimeBodyPart();
   bodyPart1.setDataHandler(new DataHandler( new MailDataSource(content,"text/html")));
   
   //设置邮件附件
   BodyPart bodyPart2 = new MimeBodyPart(); 
   FileDataSource fileDataSource = new FileDataSource(fileName);
   bodyPart2.setDataHandler(new DataHandler(fileDataSource));       
   //需要对附件文件名称进行转码,不然会出现乱码
   bodyPart2.setFileName("=?GB2312?B?"+enc.encode(fileName.getBytes())+"?=");
        
   Multipart multipart = new MimeMultipart();
   multipart.addBodyPart(bodyPart1);
   multipart.addBodyPart(bodyPart2);

   //将Multipart加入到信件
   newMessage.setContent(multipart);

4、以下是转载的关于java mail的介绍
Session
--------------------------------------------------------------------
 Session 定义了一个基本的邮件会话,任何工作都是基于这个Session的。Session 对象需要一个 java.util.Properties 对象来得到类似 邮件服务器,用户名,密码这样的信息。
 
 Session 的构造函数是私有的,你可以通过 getDefaultInstance() 方法来取得一个单一的可以被共享的默认session 如:

  Properties props = new Properties();
  // 填写一些信息
  Session session = Session.getDefaultInstance(props,null);

 或者,你可以使用 getInstance() 方法来创建一个唯一的 session如:

  Properties props = new Properties();
  // 填写一些信息
  Session session = Session.getInstance(props,null);
 
 在这两种方法中 其中的 null 参数是一个 Authenticator 对象,在这里没有被使用的,所以就是null
 
 在大多数案例中,使用一个共享session 已经做够了。

Message
----------------------------------------------------------------
 一旦你创建了Session对象,那么下面要做的就是创建 message 来发送。Message 是一个抽象类,在大部分应用中你可以使用它的子类 javax.mail.internet.MimeMessage 。MimeMessage 是一个理解在不同RFCs中定义的MIME类型以及headers的e-mail message&nbsp;。 Message headers 必须使用 US-ASCII 字符集。

 可以用如下的方法创建一个 Message 
  MimeMessage message = new MimeMessage(session);
 我们注意到,这里需要用session对象作为构造函数的参数。当然,还有其它的构造函数,比如从用RFC822格式化过的输入流来创建message。

 一旦你得到了 message ,你就可以来设置它的各个部分(parts)。设置内容(content)的基本的机制是使用setContent() 方法。

  message.setContent("Email Content. ","text/plain");

 如果,你能够明确你的使用MimeMessage来创建message 并且只是使用普通的文本(plain text) 那么你也可以使用 setText() 方法,setTest()方法只需要设置具体的内容,它默认的MIME类型是 text/plain
  
  message.setText("Email Content. ");
 
 对于普通文本类型的邮件,有一种机制是首选( message.setText("Email Content. "))的设置内容的方法。如果要创建其它类型的message ,比如 HTML类型的message  那么还是需要使用前者 ( message.setContent("Email Content. ","text/html"); )

 设置主题(subject ),使用setSubject() 方法
  
  message.setSubject(" Subject ");

Address 
----------------------------------------------------------------
 
 当你已经创建Session 以及 Message,并且已经为message 填充了内容,那么接下来要做的就是给你的邮件添加一个地址(Address)。 就像Message一样,Address也是一个抽象类,我们可以使用它的一个子类javax.mail.internet.InternetAddress 。

 创建一个地址非常简单

  Address address = new InternetAddress("suixin@asiainfo.com");

 如果,你希望在出现邮件地址的地方出现一个名称,那么你只需要再多传递一个参数。

  Address address = new InternetAddress("suixin@asiainfo.com","Steve");

 你需要为 message 的from以及 to 字段创建address对象。为了识别发送者,你需要使用setFrom() 和 setReplyTo() 方法。
  
  messge.setFrom(address);

 如果你的message 需要显示多个 from 地址,可以使用 addFrom() 方法

  Address address[] = {....};
  message.addFrom(address);

 为了辨识message 的收件人,你需要使用 setRecipient() 方法。这个方法除了address参数之外,还需要一个Message.RecipientType 。

 message.addRecipient(type,address);

 Message.RecipientType有几个预先定义好的类型
 
 Message.RecipientType.TO  收件人
 Message.RecipientType.CC  抄送
 Message.RecipientType.BCC  暗送

 如果你的一封邮件,需要发送给你的老师,并还要给你的几个同学,那么你可以这样

 Address toAddress = new InternetAddress("teacher@17288.com");
 Address[] ccAddress = {new InternetAddress("schoolmate1@17288.com"),new InternetAddress("schoolmate2@17288.com")};

 message.addRecipient(Message.RecipientType.To, toAddress);
 message.addRecipient(Message.RecipientType.CC, ccAddress);
 
 JavaMail 没有提供电子邮件地址有效性的检测。这些超越了JavaMail API的范围。

Authenticator
 
 通过Authenticator设置用户名、密码,来访问受保护的资源,这里的资源一般指的是邮件服务器。
 
 Authenticator也是一个抽象类,你需要自己编写子类已备应用。你需要实现getPasswordAuthentication()方法,并返回一个PasswordAuthentication实例。你必须在 session被创建时, 注册你的 Authenticator。这样,当需要进行认证是,你的Authenticator就可以被得到。

  Properties props = new Properties();
  //设置属性
  Authenticator auth = new YourAuthenticator();
  Session session = Session.getDefaultInstance(props, auth);
 
Transport
----------------------------------------------------------------

 发送消息最后的一步就是使用Transport类,你可以通过两种方法来进行发送。
 Transport 是一个抽象类,你可以调用它静态的send() 方法来发送

  Transport.send(message);

 或者,你可以为你使用的协议从session中取得一个指定的实例,

  Transport transport = session.getTransport("smtp");
  transport.sendMessage(message, message.getAllRecipients());
  transport.close();

Store and Folder
 
 这两个类重要用于取得信息。在创建了Session之后,需要连接到一个 Store ,你需要告诉Store  你使用的是什么协议。

  // Store store = session.getStore("imap");
  Store store = session.getStore("pop3");
  store.connect(host, username, password);

 在连接到一个 Store 后,你可以得到一个 Folder,当然,这个Floder必须是打开的。

  Folder folder = store.getFolder("INBOX");
  folder.open(Folder.READ_ONLY);
  Message message[] = folder.getMessages();

 如果使用POP3那么,INDEX是唯一可用的文件夹。如果使用的是IMAP,你就可以使用其它的文件夹。 

posted @ 2007-04-29 10:33 brock 阅读(186) | 评论 (0)编辑 收藏

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>written by misshjn</title>
<SCRIPT LANGUAGE="JavaScript">
<!--
function test(value){
    var opt = document.getElementById("ss").innerHTML.toString();
    var re = new RegExp(value,"g");
    opt = opt.replace(/<OPTION|<\/OPTION>| selected|value/g,"").match(/=.*?>/g).toString().replace(/=|>/g,"").replace(re,"┢").replace(/[^,┢]/g,"").indexOf("┢");
    document.getElementById("ss").getElementsByTagName("option")[opt].selected = true;
}
function randomselect(){
    document.getElementById("ss").getElementsByTagName("option")[Math.floor(Math.random()*document.getElementById("ss").getElementsByTagName("option").length)].selected = true;
}
//-->
</SCRIPT>
</head>
<body>
<!--
<select id="ss">
<option value="1998">1998年</option>
<option value="1999">1999年</option>
<option value="2000">2000年</option>
<option value="2001">2001年</option>
<option value="2002">2002年</option>
<option value="2003">2003年</option>
<option value="2004">2004年</option>
<option value="2005">2005年</option>
</select>
-->

<SCRIPT LANGUAGE="JavaScript">
<!--
var opts;
for (i=1900; i<2008; i++){
    opts +="<option value='"+i+"'>第 "+i+" 年</option>";
}
document.write("<select id='ss'>"+opts+"</select>");
//-->
</SCRIPT>

<input type="button" value="选中 value=2001 的选项" onclick="test('2001')">
<input type="button" value="随机选择" onclick="randomselect()">
</body>
</html>
posted @ 2007-04-18 10:43 brock 阅读(1564) | 评论 (0)编辑 收藏

使用缩写可以帮助减少你CSS文件的大小,更加容易阅读。css缩写的主要规则如下:

颜色

16进制的色彩值,如果每两位的值相同,可以缩写一半,例如:
#000000可以缩写为#000;#336699可以缩写为#369;

盒尺寸

通常有下面四种书写方法:

  • property:value1; 表示所有边都是一个值value1;
  • property:value1 value2; 表示top和bottom的值是value1,right和left的值是value2
  • property:value1 value2 value3; 表示top的值是value1,right和left的值是value2,bottom的值是value3
  • property:value1 value2 value3 value4; 四个值依次表示top,right,bottom,left

方便的记忆方法是顺时针,上右下左。具体应用在margin和padding的例子如下:
margin:1em 0 2em 0.5em;

边框(border)

边框的属性如下:

  • border-width:1px;
  • border-style:solid;
  • border-color:#000;

可以缩写为一句:border:1px solid #000;

语法是border:width style color;

背景(Backgrounds)

背景的属性如下:

  • background-color:#f00;
  • background-image:url(background.gif);
  • background-repeat:no-repeat;
  • background-attachment:fixed;
  • background-position:0 0;

可以缩写为一句:background:#f00 url(background.gif) no-repeat fixed 0 0;

语法是background:color image repeat attachment position;

你可以省略其中一个或多个属性值,如果省略,该属性值将用浏览器默认值,默认值为:

  • color: transparent
  • image: none
  • repeat: repeat
  • attachment: scroll
  • position: 0% 0%

字体(fonts)

字体的属性如下:

  • font-style:italic;
  • font-variant:small-caps;
  • font-weight:bold;
  • font-size:1em;
  • line-height:140%;
  • font-family:"Lucida Grande",sans-serif;

可以缩写为一句:font:italic small-caps bold 1em/140% "Lucida Grande",sans-serif;

注意,如果你缩写字体定义,至少要定义font-size和font-family两个值。

列表(lists)

取消默认的圆点和序号可以这样写list-style:none;,

list的属性如下:

  • list-style-type:square;
  • list-style-position:inside;
  • list-style-image:url(image.gif);

可以缩写为一句:list-style:square inside url(image.gif);

posted @ 2006-12-30 11:05 brock 阅读(322) | 评论 (1)编辑 收藏

  • 原文作者:Roger Johansson
  • 作者简介:住在瑞典哥德堡,1994年开始接触和参与web设计,456 Berea Street是他的住址,因此采用这个名字作为他的个人主页域名
  • 原文出处:www.456bereastreet.com
  • 原文发表时间:2005年3月15日
  • 阿捷说明:此文原名"CSS tips and tricks",有2篇,我将它们合并翻译在本文中。
作者Roger Johansson照片

最近,经常有朋友问我一些工作中遇到的CSS问题。他们总是不能很好的控制CSS,影响CSS的效率发挥。我来分析总结一下错误所在,帮助大家更加容易使用CSS。

本文总结了我开始使用CSS布局方法以来所有的技巧和兼容方案,我愿意把这些与你分享,我会重点解释一些新手容易犯的错误(包括我自己也犯过的),如果你已经是CSS高手,这些经验技巧可能已经都知道,如果你有更多的,希望可以帮我补充。

一.使用css缩写

使用缩写可以帮助减少你CSS文件的大小,更加容易阅读。css缩写的主要规则请参看《常用css缩写语法总结》,这里就不展开描述。

二.明确定义单位,除非值为0

忘记定义尺寸的单位是CSS新手普遍的错误。在HTML中你可以只写width="100",但是在CSS中,你必须给一个准确的单位,比如:width:100px width:100em。只有两个例外情况可以不定义单位:行高和0值。除此以外,其他值都必须紧跟单位,注意,不要在数值和单位之间加空格。

三.区分大小写

当在XHTML中使用CSS,CSS里定义的元素名称是区分大小写的。为了避免这种错误,我建议所有的定义名称都采用小写。

class和id的值在HTML和XHTML中也是区分大小写的,如果你一定要大小写混合写,请仔细确认你在CSS的定义和XHTML里的标签是一致的。

四.取消class和id前的元素限定

当你写给一个元素定义class或者id,你可以省略前面的元素限定,因为ID在一个页面里是唯一的,而clas s可以在页面中多次使用。你限定某个元素毫无意义。例如:

div#content { /* declarations */ }
fieldset.details { /* declarations */ }

可以写成

#content { /* declarations */ }
.details { /* declarations */ }

这样可以节省一些字节。

五.默认值

通常padding的默认值为0,background-color的默认值是transparent。但是在不同的浏览器默认值可能不同。如果怕有冲突,可以在样式表一开始就先定义所有元素的margin和padding值都为0,象这样:

* {
margin:0;
padding:0;
}

六.不需要重复定义可继承的值

CSS中,子元素自动继承父元素的属性值,象颜色、字体等,已经在父元素中定义过的,在子元素中可以直接继承,不需要重复定义。但是要注意,浏览器可能用一些默认值覆盖你的定义。

七.最近优先原则

如果对同一个元素的定义有多种,以最接近(最小一级)的定义为最优先,例如有这么一段代码

Update: Lorem ipsum dolor set

在CSS文件中,你已经定义了元素p,又定义了一个class"update"

p {
margin:1em 0;
font-size:1em;
color:#333;
}
.update {
font-weight:bold;
color:#600;
}

这两个定义中,class="update"将被使用,因为class比p更近。你可以查阅W3C的《 Calculating a selector’s specificity》 了解更多。

八.多重class定义

一个标签可以同时定义多个class。例如:我们先定义两个样式,第一个样式背景为#666;第二个样式有10 px的边框。

.one{width:200px;background:#666;}
.two{border:10px solid #F00;}

在页面代码中,我们可以这样调用

<div class="one two"></div>

这样最终的显示效果是这个div既有#666的背景,也有10px的边框。是的,这样做是可以的,你可以尝试一下。

九.使用子选择器(descendant selectors)

CSS初学者不知道使用子选择器是影响他们效率的原因之一。子选择器可以帮助你节约大量的class定义。我们来看下面这段代码:

<div id="subnav">
<ul>
<li class="subnavitem"> <a href="#" class="subnavitem">Item 1</a></li>>
<li class="subnavitemselected"> <a href="#" class="subnavitemselected"> Item 1</a> </li>
<li class="subnavitem"> <a href="#" class="subnavitem"> Item 1</a> </li>
</ul>
</div>

这段代码的CSS定义是:

div#subnav ul { /* Some styling */ }
div#subnav ul li.subnavitem { /* Some styling */ }
div#subnav ul li.subnavitem a.subnavitem { /* Some styling */ }
div#subnav ul li.subnavitemselected { /* Some styling */ }
div#subnav ul li.subnavitemselected a.subnavitemselected { /* Some styling */ }

你可以用下面的方法替代上面的代码

<ul id="subnav">
<li> <a href="#"> Item 1</a> </li>
<li class="sel"> <a href="#"> Item 1</a> </li>
<li> <a href="#"> Item 1</a> </li>
</ul>

样式定义是:

#subnav { /* Some styling */ }
#subnav li { /* Some styling */ }
#subnav a { /* Some styling */ }
#subnav .sel { /* Some styling */ }
#subnav .sel a { /* Some styling */ }

用子选择器可以使你的代码和CSS更加简洁、更加容易阅读。

十.不需要给背景图片路径加引号

为了节省字节,我建议不要给背景图片路径加引号,因为引号不是必须的。例如:

background:url("images/***.gif") #333;

可以写为

background:url(images/***.gif) #333;

如果你加了引号,反而会引起一些浏览器的错误。

十一.组选择器(Group selectors)

当一些元素类型、class或者id都有共同的一些属性,你就可以使用组选择器来避免多次的重复定义。这可以节省不少字节。

例如:定义所有标题的字体、颜色和margin,你可以这样写:

h1,h2,h3,h4,h5,h6 {
font-family:"Lucida Grande",Lucida,Arial,Helvetica,sans-serif;
color:#333;
margin:1em 0;
}

如果在使用时,有个别元素需要定义独立样式,你可以再加上新的定义,可以覆盖老的定义,例如:

h1 { font-size:2em; }
h2 { font-size:1.6em; }

十二.用正确的顺序指定链接的样式

当你用CSS来定义链接的多个状态样式时,要注意它们书写的顺序,正确的顺序是::link :visited :hover :active。抽取第一个字母是"LVHA",你可以记忆成"LoVe HAte"(喜欢讨厌)。为什么这么定义,可以参考Eric Meyer的《Link Specificity》。

如果你的用户需要用键盘来控制,需要知道当前链接的焦点,你还可以定义:focus属性。:focus属性的效果也取决与你书写的位置,如果你希望聚焦元素显示:hover效果,你就把:focus写在:hover前面;如果你希望聚焦效果替代:hover效果,你就把:focus放在:hover后面。

十三.清除浮动

一个非常常见的CSS问题,定位使用浮动的时候,下面的层被浮动的层所覆盖,或者层里嵌套的子层超出了外层的范围。

通常的解决办法是在浮动层后面添加一个额外元素,例如一个div或者一个br,并且定义它的样式为clear: both。这个办法有一点牵强,幸运的是还有一个好办法可以解决,参看这篇文章《How To Clear Floats Without Structural Markup》(注:本站将尽快翻译此文)。

上面2种方法可以很好解决浮动超出的问题,但是如果当你真的需要对层或者层里的对象进行clear的时候怎么办?一种简单的方法就是用overflow属性,这个方法最初的发表在《Simple Clearing of Floats》,又在《Clearance》和《Super simple clearing floats》中被广泛讨论。

上面那一种clear方法更适合你,要看具体的情况,这里不再展开论述。另外关于float的应用,一些优秀的文章已经说得很清楚,推荐你阅读:《Floatutorial》、《Containing Floats》和《Float Layouts

十四.横向居中(centering)

这是一个简单的技巧,但是值得再说一遍,因为我看见太多的新手问题都是问这个:CSS如何横向居中?你需要定义元素的宽,并且定义横向的margin,如果你的布局包含在一个层(容器)中,就象这样:

你可以这样定义使它横向居中:

#wrap {
width:760px; /* 修改为你的层的宽度 */
margin:0 auto;
}

但是IE5/Win不能正确显示这个定义,我们采用一个非常有用的技巧来解决:用text-align属性。就象这样:

body {
text-align:center;
}
#wrap {
width:760px; /* 修改为你的层的宽度 */
margin:0 auto;
text-align:left;
}

第一个body的text-align:center; 规则定义IE5/Win中body的所有元素居中(其他浏览器只是将文字居中) ,第二个text-align:left;是将#warp中的文字居左。

十五.导入(Import)和隐藏CSS

因为老版本浏览器不支持CSS,一个通常的做法是使用@import技巧来把CSS隐藏起来。例如:

@import url("main.css");

然而,这个方法对IE4不起作用,这让我很是头疼了一阵子。后来我用这样的写法:

@import "main.css";

这样就可以在IE4中也隐藏CSS了,呵呵,还节省了5个字节呢。想了解@import语法的详细说明,可以看这里《centricle’s css filter chart

十六.针对IE的优化

有些时候,你需要对IE浏览器的bug定义一些特别的规则,这里有太多的CSS技巧(hacks),我只使用其中的两种方法,不管微软在即将发布的IE7 beta版里是否更好的支持CSS,这两种方法都是最安全的。

  • 1.注释的方法
    • (a)在IE中隐藏一个CSS定义,你可以使用子选择器(child selector):
      html>body p {
      /* 定义内容 */
      }
    • (b)下面这个写法只有IE浏览器可以理解(对其他浏览器都隐藏)
      * html p {
      /* declarations */
      }
    • (c)还有些时候,你希望IE/Win有效而IE/Mac隐藏,你可以使用"反斜线"技巧:
      /* \*/
      * html p {
      declarations
      }
      /* */
  • 2.条件注释(conditional comments)的方法

    另外一种方法,我认为比CSS Hacks更加经得起考验就是采用微软的私有属性条件注释(conditional comments)。用这个方法你可以给IE单独定义一些样式,而不影响主样式表的定义。就象这样:

    <!--[if IE]>
    <link rel="stylesheet" type="text/css" href="ie.css" />
    <![endif]-->

十七.调试技巧:层有多大?

当调试CSS发生错误,你就要象排版工人,逐行分析CSS代码。我通常在出问题的层上定义一个背景颜色,这样就能很明显看到层占据多大空间。有些人建议用border,一般情况也是可以的,但问题是,有时候border 会增加元素的尺寸,border-top和boeder-bottom会破坏纵向margin的值,所以使用background更加安全些。

另外一个经常出问题的属性是outline。outline看起来象boeder,但不会影响元素的尺寸或者位置。只有少数浏览器支持outline属性,我所知道的只有Safari、OmniWeb、和Opera。

十八.CSS代码书写样式

在写CSS代码的时候,对于缩进、断行、空格,每个人有每个人的书写习惯。在经过不断实践后,我决定采用下面这样的书写样式:

selector1,
selector2 {
property:value;
}

当使用联合定义时,我通常将每个选择器单独写一行,这样方便在CSS文件中找到它们。在最后一个选择器和大括号{之间加一个空格,每个定义也单独写一行,分号直接在属性值后,不要加空格。

我习惯在每个属性值后面都加分号,虽然规则上允许最后一个属性值后面可以不写分号,但是如果你要加新样式时容易忘记补上分号而产生错误,所以还是都加比较好。

最后,关闭的大括号}单独写一行。

空格和换行有助与阅读。

posted @ 2006-12-30 11:04 brock 阅读(268) | 评论 (0)编辑 收藏