颠覆软件

关注 : 架构与设计,敏捷,快速开发,项目管理,执行力,SSH,RoR

[zt]JDBMonitor全攻略

Filed under: java开发技术, 数据库 — Alex at 12:13 pm on Thursday, August 31, 2006

key words: dbmonitor,sql跟踪,sql监控

 

JDBMonitor是一个开源项目。使用它开发者可以很轻松为系统增加数据库执行日志功能。它使用十分方便,您所需要做的唯一事情就是在您系统的JDBC连接字符串前增加类似于 “listenerconfig=/config.xml:url=” 的字符即可,不用写任何代码。

使用 JDBMonitor,您可以把数据库执行情况记录通过各种方式记录下来,比如打印到控制台、输出到文件或者通过socket传送给远程客户端。JDBMonitor是可扩展的,您可以扩展它来将执行情况通过其他方式记录下来,您所需要做的就是写一个实现IDBListener接口的类即可。

JDBMonitor遵守 GNU Lesser General Public Licence (LGPL)协议。此协议包含在发行包中。

入门

几乎所有大型数据库应用都包含有自己的SQL执行日志功能,此功能不仅能帮助开发人员调试,而且可以为DBA(数据库管理员)提供系统的运行信息。

(1)很难将业务逻辑同日志代码分离

(2)降低了代码的可读性。

(3)降低了系统的运行速度。在记录日志的时候,程序会暂停运行等待直到记录完成,而I/O操作是相当耗时的。

(4)很难记录运行耗时、语句参数等其他信息

(5)很难为我们无法修改代码的系统(例如没有源代码的系统)或者很难增加记录日志功能代码的系统(比如系统使用了ORMapping)增加日志功能。

JDBMonitor 则不同:

(1)您最多只需要修改一行代码。您需要修改的代码就是这一行:Class.forName(”com.cownew.JDBMonitor.jdbc.DBDriver”) ,然后再修改一下 JDBC连接字符串,只要从 “jdbc:db2://10.74.198.247:50000/app”修改成” listenerconfig=config.xml:url= jdbc:db2://10.74.198.247:50000/app”就可以了。在您使用WebLogic ,Tomcat或其他服务器的数据源功能的时候,连修改代码这一步都是无需的。

(2)JDBMonitor另起一个线程来记录SQL,所以它不会对程序运行速度有任何影响。

(3)它是高度可扩展的,所以您可以扩展它来把执行情况通过其他方式记录。比如,您可以写一个扩展类,来通过电子邮件将日志发送出去。

取得 JDBMonitor

JDBMonitor的最新稳定版本可以在JDBMonitor的网站上取得:

http://www.cownew.com/JDBMonitor

使用 JDBMonitor

1 将 jdbmonitor.jar放到您系统的类路径下。

2 让系统加载 JDBMonitor的JDBC驱动。

这一步将会依您系统加载JDBC驱动的方式的不同而不同。

(1)如果您通过代码的形式加载JDBC驱动,例如:

Class.forName(“com.microsoft.jdbc.sqlserver.SQLServerDriver”);
Connection cn = DriverManager.getConnection(……);

在这种情况下 ,您必须修改 “Class.forName”这一句来加载JDBMonitor的JDBC驱动(“com.cownew.JDBMonitor.jdbc.DBDriver”),而非以前的数据库JDBC驱动。

例如:

Class.forName(“com.cownew.JDBMonitor.jdbc.DBDriver”);
Connection cn = DriverManager.getConnection(……);

(2)如果您在配置文件中指定JDBC驱动,比如,数据源配置文件或者其他类似的文件。

请修改原来的  JDBC驱动类为 “com.cownew.JDBMonitor.jdbc.DBDriver” 。

3 让 JDBMonitor加载能够加载原来的JDBC驱动

JDBMonitor的工作原理就是截获JDBC驱动的SQL语句调用、记录SQL语句,然后将SQL语句重新转发给原来的JDBC驱动,所以JDBMonitor必须首先向DriverManager注册JDBC驱动。

原来的JDBC驱动定义在配置文件的“JdbcDrivers” 段中。
<JdbcDrivers>
<JdbcDriver class=” com.mysql.jdbc.Driver”/>
</JdbcDrivers>

4 在原来的JDBC连接字符串前增加 JDBMonitor所需的信息。

您所需要做的就是将” listenerconfig=<configfilepath>:url=” 增加到原来的JDBC连接字符串前。“<configfilepath>”代表配置文件的路径,下面集中路径都是合法的:

/com/jdbmonitor/config.xml
com/jdbmonitor/config.xml
c:/ jdbmonitor /config.xml

JDBMoinitor使用getClass().getResourceAsStream加载类似于“/com/jdbmonitor/config.xml” and “com/jdbmonitor/config.xml” 的类路径文件,使用 FileInputStream加载类似于 “c:/ jdbmonitor /config.xml”的配置文件。

5 指定您要使用监听器:

您可以把数据库执行情况记录通过各种方式记录下来,比如打印到控制台、输出到文件或者通过socket传送给远程客户端。

我们已经开发了如下常用的监听器:FileDBListener、ConsoleDBListener、 SocketDBListene、DataBaseDBListener。当然您也可以开发满足您要求的监听器。
监听器定义在配置文件的 “Listeners”段中:

<Listeners>
<!–ConsoleDBListener no arguments–>
<Listener class=”com.cownew.JDBMonitor.listenerImpl.ConsoleDBListener” arg=”"/>

<!–the arguments of FileDBListener is the file to log the SQL statement –>
<Listener class=”com.cownew.JDBMonitor.listenerImpl.FileDBListener” arg=”c:/aaa.txt”/>

<!–the arguments of SocketDBListener is the bound socket port of the listener server –>
<Listener class=”com.cownew.JDBMonitor.listenerImpl.SocketDBListener” arg=”9527″/>
</Listeners>

搞定!启动您的系统。耶!SQL语句被记录下来了,我们可以在控制台、文件甚至远程监视器中看到日志了。

举例

mvnforum的例子:

您可以从http://www.mvnForum.com得到mvnforum。我演示用的版本是1.0。

(1)打开webapp\WEB-INF\classes\ mvncore.xml,重新配置:

修改之前:

<driver_class_name>com.mysql.jdbc.Driver</driver_class_name>
<database_url>listenerconfig=c:/log/jdbmonitor/config.xml:url= jdbc:mysql://localhost/mvnforum?useUnicode=true&amp;characterEncoding=utf-8</database_url>

修改之后:
<driver_class_name> com.cownew.JDBMonitor.jdbc.DBDriver </driver_class_name>
<database_url>jdbc:mysql://localhost/mvnforum?useUnicode=true&amp;characterEncoding=utf-8</database_url>

(2)创建文件 c:/log/jdbmonitor/config.xml。我只想将SQL语句记录到文本文件中,所以我做如下配置:
<config>
<Listeners>
<!–the arguments of FileDBListener is the file to log the SQL statement –>
<Listener class=”com.cownew.JDBMonitor.listenerImpl.FileDBListener” arg=”c:/log.txt”/>
</Listeners>
<JdbcDrivers>
<JdbcDriver class=”com.mysql.jdbc.Driver”/>
</JdbcDrivers>
</config>
(3) 将 jdbmonitor.jar放到webapp\WEB-INF\lib下。
(4) 搞定!

Jive的例子:

您可以从http://www.jivesoftware.com得到Jive。我演示用的版本是 Jive 2.0 beta版。

(1)打开http://localhost:8080/jive/admin/

“jdbc” 填为:com.cownew.JDBMonitor.jdbc.DBDriver

“server” 填为:c:/log/jdbmonitor/config.xml:url=jdbc:mysql://locahost/jive
(2)将 jdbmonitor.jar放到WEB-INF\lib下
(3) 象mvnforum中一样创建同样的 c:/log/jdbmonitor/config.xml 文件.
(4) 搞定!

代码方式的例子:

尽管直接在代码中指定系统所用的JDBC驱动类名和JDBC连接字符串是不推荐的,但是仍然有系统是这么做的。

比如:

              Class.forName(”sun.jdbc.odbc.JdbcOdbcDriver”);
              Connection conn = null;
              PreparedStatement ps = null;
              try
              {
                     conn = DriverManager
                                   .getConnection(”jdbc:odbc:MQIS”);
                     for (int i = 0; i < 1000; i++)
                     {                   
                            ps = conn.prepareStatement(”update T_Material set fid=fid”);
                            ps.execute();
                            ps.close();
                     }
              } finally
              {
                     ….         
              }

(1)修改一下代码为:
              Class.forName(”com.cownew.JDBMonitor.jdbc.DBDriver”);
              Connection conn = null;
              PreparedStatement ps = null;
              try
              {
                     conn = DriverManager.getConnection(”listenerconfig= c:/log/jdbmonitor/config.xml:url=jdbc:odbc:MQIS”);
                     for (int i = 0; i < 1000; i++)
                     {
                            ps = conn.prepareStatement(”update T_Material set fid=fid”);
                            ps.execute();
                            ps.close();
                     }
              } finally
              {
                     ….         
              }

(2)创建c:/log/jdbmonitor/config.xml文件。我想记录SQL语句到文本文件中同时输出到控制台,这样可以辅助我进行调试,所以我配置如下:
<config>
<Listeners>
<!–the arguments of FileDBListener is the file to log the SQL statement –>
<Listener class=”com.cownew.JDBMonitor.listenerImpl.FileDBListener” arg=”c:/log.txt”/>

<!–ConsoleDBListener no arguments–>
<Listener class=”com.cownew.JDBMonitor.listenerImpl.ConsoleDBListener” arg=”"/>
</Listeners>
<JdbcDrivers>
<JdbcDriver class=”com.mysql.jdbc.Driver”/>
</JdbcDrivers>
</config>
(3) 将 jdbmonitor.jar放到类路径下。
(4) 搞定!

监听器

我们已经开发了如下常用的监听器:FileDBListener、ConsoleDBListener、 SocketDBListener、DataBaseDBListener。

1、ConsoleDBListener 控制台监听器

ConsoleDBListener会将SQL语句打印到控制台中。

这个监听器很容易配置:

<Listener class=”com.cownew.JDBMonitor.listenerImpl.ConsoleDBListener” arg=”"/>

2、FileDBListener 文件监听器

FileDBListener 会将SQL语句保存到文本文件中。

如下配置:

<Listener class=”com.cownew.JDBMonitor.listenerImpl.FileDBListener” arg=”c:/aaa.txt”/>

arg=”c:/aaa.txt”表示日志将保存到文件c:/aaa.txt中。

3、SocketDBListener Socket监听器

SocketDBListener是一个socket服务器,客户端连接到它上边以后就可以接收到它发出的SQL语句。

如下配置:

<Listener class=”com.cownew.JDBMonitor.listenerImpl.SocketDBListener” arg=”9527″/>

arg=”9527″表示服务器将在9527端口监听。

我们已经开发了如下两种客户端:SocketConsoleClient(Socket控制台客户端) 和 SocketSwingClient(Socket Swing客户端)。

SocketConsoleClient工作在控制台中:

SocketSwingClient是一个Swing GUI客户端:

您可以运行“java -classpath jdbmonitor.jar com.cownew.JDBMonitor.listenerImpl.sckListenerClient.SocketConsoleClient” 来启动SocketConsoleClient,运行“java -classpath jdbmonitor.jar com.cownew.JDBMonitor.listenerImpl.sckListenerClient.SocketSwingClient”启动SocketSwingClient

您可以编写符合您自己要求的客户端,具体细节请参考com.cownew.JDBMonitor.listenerImpl.sckListenerClient.ListenerClientcom.cownew.JDBMonitor.listenerImpl.sckListenerClient.IDBSocketClientListener.

4、DataBaseDBListener

DataBaseDBListener将会把SQL语句记录到数据库中:

如下配置:

<Listener class=”com.cownew.JDBMonitor.listenerImpl.DataBaseDBListener”
arg=”dburl=jdbc:odbc:MQIS;user=;password=;logtable=T_Log_SQLLog”/>

“dburl=jdbc:odbc:MQIS;user=;password=;”表示目标数据库的JDBC连接字符串。“logtable=T_Log_SQLLog” 表示SQL记录将被保存到哪个表中,默认的是T_Log_SQLLog

如果目标数据库用的JDBC驱动与被监控的数据库不同,请将它加入配置文件的 “JdbcDrivers” 部分,例如:

<config>
<Active>true</Active>
<Listeners>

<Listener class=”com.cownew.JDBMonitor.listenerImpl.ConsoleDBListener” arg=”"/>

<Listener class=”com.cownew.JDBMonitor.listenerImpl.DataBaseDBListener”
arg=”dburl=jdbc:odbc:MQIS;user=;password=;logtable=T_Log_SQLLog”/>
</Listeners>
<JdbcDrivers>
<JdbcDriver class=”com.microsoft.jdbc.sqlserver.SQLServerDriver”/>
<JdbcDriver class=”sun.jdbc.odbc.JdbcOdbcDriver”/>
</JdbcDrivers>
</config>

T_Log_SQLLog“的结构是:

T_Log_SQLLog“的建库脚本在com/cownew/JDBMonitor/listenerImpl/dataBaseListener,(db2.sql,mssqlserver.sql,oracle.sql)。

DataBaseDBListener是跨数据库的,你可以把记录SQL到任何关系数据库中。

FAQ:

1 如果我暂时不想记录SQL语句执行怎么办?难道我要重新修改成原来的样子?

答:无须如此。您只要修改config.xml,增加<Active>false</Active>到文件中即可。

如下:

<config>
  <Active> false </Active>
  <Listeners>
……
</config>

如何扩展JDBMonitor?

我们已经开发了如下常用的监听器:FileDBListener、ConsoleDBListener、 SocketDBListener、DataBaseDBListener。当然您也可以开发满足您要求的监听器。所有的监听器必须实现接口:com.cownew.JDBMonitor.commo. IDBListener。IDBListener有两个方法需要实现:

public void init(String arg);
public void logSql(SQLInfo info);

JDBMonitor会将配置文件中监听器定义中“arg”的值传递给 “init”方法、将代表SQL语句执行信息的SQLInfo传递给“logSql”方法。

更多信息请参考API文档。

pd:怎么样使CODE不跟这改变?

Filed under: 开发工具, 数据库 — Alex at 12:15 pm on Saturday, August 26, 2006

反向工程生成的PDM,表中NAME和CODE都一样,现在要修改NAME.
在修改一个表的NAME属性时,CODE属性也会跟着一起改变,怎么样才能让CODE不跟着NAME变呢?

Tools->General Options->Dialog->Name to Code Mirroring (去掉)

js:window.opener问题

Filed under: HTML — Alex at 12:16 pm on Wednesday, August 23, 2006

在应用中有这样一个情况,
在A窗口中打开B窗口,在B窗口中操作完以后关闭B窗口,同时自动刷新A窗口

function closeWin(){
hasClosed 
= true;
window.opener.location
=javascript:reloadPage();;
window.close();
}
function window.onbeforeunload(){
if(!hasClosed){
window.opener.location
=javascript:reloadPage();;
}
}

</script>
上面的代码在关闭B窗口的时候会提示错误,说缺少Object,正确的代码如下:

function closeWin(){
hasClosed 
= true;
window.opener.location
=javascript:reloadPage();;
window.opener
=null;
window.close();
}
function window.onbeforeunload(){
if(!hasClosed){//如果已经执行了closeWin方法,则不执行本方法
window.opener.location
=javascript:reloadPage();;
}
}

</script>
reloadPage方法如下:

function reloadPage() {
history.go(
0);
document.execCommand(
refresh)
document.location 
= document.location;
document.location.reload();
}

PS:由于需要支持正常关闭和强制关闭窗口时能捕捉到事件,用了全局变量hasClosed

==============================================

补充,在父窗口是frame的时候在刷新父窗口的时候会出现问题:

The page cannot be refreshed without resending the information.
后修改如下:

window.opener.parent.document.frames.item(’mainFrame’).location.href = window.opener.location.href;
不需要执行自带的reload()方法,注意,不要再画蛇添足加上这一句:

window.opener.parent.document.frames.item(’mainFrame’).location.reload();

========================================================================================
最后,为了同时支持刷新普通父窗口和frame父窗口,代码如下:

function closeWin() {
hasClosed 
= true;
<%if(null != frame){%>
window.opener.parent.document.frames.item(’mainFrame’).location.href 
= window.opener.location.href;
<%}else{%>
window.opener.location 
= javascript:reloadPage();;
<%}%>
//window.opener.top.mainFrame.location=”javascript:reloadPage();”;
        //self.opener.frames.mainFrame.location.reload(true);
        window.opener = null;
window.close();
}
function window.onbeforeunload(){
if (!hasClosed) {
<%if(null != frame){%>
window.opener.parent.document.frames.item(’mainFrame’).location.href 
= window.opener.location.href;
<%}else{%>
window.opener.location 
= javascript:reloadPage();;
<%}%>
window.opener 
= null;
}
}

js : 怎样从子窗口调用父窗口的方法

Filed under: HTML — Alex at 12:19 pm on Monday, August 21, 2006

key words: 在子窗口中如何调用父窗口的方法,属于”回调”,直接拿到父窗口的句柄,然后直接调用方法不行,比如:

parent.window.show(b)
window.opener.show(b)

都不行,正确的做法是:

opener.location=javascript:show(’hello’);
PS: 直接调用父窗口的对象与此不同,参考这篇: 用javaScript操作两个页面

oracle中查询被锁的表并释放session

Filed under: Oracle — Alex at 12:17 pm on Monday, August 21, 2006

key words: 锁表 解锁
查询sql:

SELECT A.OWNER,
A.
OBJECT_NAME,
B.XIDUSN,
B.XIDSLOT,
B.XIDSQN,
B.SESSION_ID,
B.ORACLE_USERNAME,
B.OS_USER_NAME,
B.PROCESS,
B.LOCKED_MODE,
C.MACHINE,
C.STATUS,
C.SERVER,
C.SID,
C.SERIAL#,
C.PROGRAM
FROM ALL_OBJECTS A,
V$LOCKED_OBJECT B,
SYS.GV_$SESSION C
WHERE ( A.OBJECT_ID = B.OBJECT_ID )
AND (B.PROCESS = C.PROCESS )
ORDER BY 1,2 
释放session Sql:

alter system kill session sid, serial#

alter system kill session 379, 21132
alter system kill session 374, 6938

js:获得select的text的值

Filed under: HTML — Alex at 12:16 pm on Monday, August 21, 2006

key words:select text值
获得select的value很容易,但是如何获得其text的内容呢,下面的代码借助了prototype.js库:

<script language=”javascript”>
function getSelect(selectName){
var options = $(selectName).getElementsByTagName(’option’);
options 
= $A(options);
var opt = options.find( function(employee){
return (employee.value == $F(selectName));
});
alert(opt.innerHTML);
}
</script>

<select name=”hi” onchange=”getSelect(’hi’);”>
<option value=”01″></option>
<option value=”02″></option>
<option value=”03″></option>
<option value=”04″></option>
</select>
PS: $A : 转换成数组格式
opt.innerHTML:nodeText

js中获取radio的值

Filed under: HTML — Alex at 12:20 pm on Sunday, August 20, 2006

在jsp中获取radio的值很容易,直接 request.getParameter(”myRadio”);
但是在js中不行,我试验了一下,如果选择第一个没问题,但是你选第二个第三个的话就出现undefined.办法如下:

function Foo()
{
var selectedIndex = -1;
var form1 = document.getElementById(form1);
var i = 0;

for (i=0; i<form1.r.length; i++)
{
if (form1.r[i].checked)
{
selectedIndex 
= i;
alert(
您选择项的 value 是: + form1.r[i].value);
break;
}
}

if (selectedIndex < 0)
{
alert(
您没有选择任何项);
}
}

关于java与javaScript的互相访问

Filed under: HTML, java开发技术 — Alex at 12:21 pm on Saturday, August 19, 2006

key words: 脚本编码 中文乱码 js
在jsp中,通过js访问java代码比较容易(不过,也有缺陷,比如java代码的声明必须先于js),反过来则不方便,网上看到有通过其他组件的方式来做,感觉也不是很好,其实平时用的更多的是在js中有中文编码,而需要到下一个jsp页面中得到这个对应的值。

js中有函数escape和unescape,可惜的是java.net.*中的编码和解码与js的不一致,所以他们不能协同工作,有一个方法就是在java中重新实现一遍js里对应的方法,代码如下:

/**
* java版本的escape和 unescape[对应javaScript里的函数]
*/
public class EscapeUnescape {
/**
* escape ==> escape
@param src
@return String
*/
public static String escape(String src) {
int i;
char j;
StringBuffer tmp 
= new StringBuffer();
tmp.ensureCapacity(src.length() 
* 6);
for (i = 0; i < src.length(); i++) {
= src.charAt(i);
if (Character.isDigit(j) || Character.isLowerCase(j)
|| Character.isUpperCase(j))
tmp.append(j);
else if (j < 256) {
tmp.append(
%);
if (j < 16)
tmp.append(
0);
tmp.append(Integer.toString(j, 
16));
else {
tmp.append(
%u);
tmp.append(Integer.toString(j, 
16));
}
}
return tmp.toString();
}

/**
* unescape ===>js
@param src
@return String
*/
public static String unescape(String src) {
StringBuffer tmp 
= new StringBuffer();
tmp.ensureCapacity(src.length());
int lastPos = 0, pos = 0;
char ch;
while (lastPos < src.length()) {
pos 
= src.indexOf(%, lastPos);
if (pos == lastPos) {
if (src.charAt(pos + 1== u) {
ch 
= (char) Integer.parseInt(src.substring(pos + 2, pos + 6), 16);
tmp.append(ch);
lastPos 
= pos + 6;
else {
ch 
= (char) Integer.parseInt(src.substring(pos + 1, pos + 3), 16);
tmp.append(ch);
lastPos 
= pos + 3;
}
else {
if (pos == -1) {
tmp.append(src.substring(lastPos));
lastPos 
= src.length();
else {
tmp.append(src.substring(lastPos, pos));
lastPos 
= pos;
}
}
}
return tmp.toString();
}
}

[zt]在Redhat9 Linux下安装,配置Subversion 1.3.1

Filed under: Linux — Alex at 1:24 pm on Thursday, August 10, 2006
By: Wu Yin
Date: 2006-06-30
Email: lazy_fox#msn.com
Link: http://blog.csdn.net/wooin/archive/2006/07/11/903974.aspx
版权信息: 该文章版权由Wu Yin所有。可在非商业目的下任意传播和复制。
对于商业目的下对本文的任何行为需经作者同意。
联系方式:lazy_fox#msn.com

1. 本文需要两个文件,httpd和subversion。
·httpd是web服务器,用来通过web访问subversion,这里是官方网站,这里是它的下载网页,
这里可以下载到httpd-2.2.2.tar.bz2。
·subversion就是本文的主角,这里是他的官方网站,这里是它的下载网页,
这里可以下载到subversion-1.3.1.tar.bz2
2. 新建一个用户:svnroot
最好不要让root用户参与到svn的权限管理和日常的运行和维护工作中来,但是下面的一些安装和配置操作还是 需要root用户来完成的,因为有些操作只有root才能做。
3. 编译安装httpd (root用户操作):

//解压apache2安装包
# tar xvzf httpd-2.2.2.tar.gz
//进入解压后的目录
# cd httpd-2.2.2
//配置apache安装,前两个参数是必须要加的,你还可以根据您的需要添加其他的参数。
//后面的参数制定你要把apache安装哪里
# ./configure –enable-dav –enable-so –prefix=/usr/local/apache2/
# make
//安装
# make install
# cd /usr/local/apache2/bin
//启动apache服务
# ./apachectl start
//打开浏览器http://localhost/如果有测试页”It works!”出现则证明已经安装成功。
3. 安装Subversion

//解压SubVersion安装包 (root用户进行下面的操作)
# tar xvzf Subversion-1.3.1.tar.gz
//进入解压后的目录
# cd Subversion-1.3.1
//配置subversion安装
#./configure –with-apxs=/usr/local/apache2/bin/apxs –prefix=/usr/local/subversion
–with-apr=/usr/local/apache2 –with-apr-util=/usr/local/apache2 –with-ssl –with-zlib
–enable-maintainer-mode
# make
//安装
# make install
//创建库文件所在的目录 (svnroot用户进行下面的操作)
# mkdir /home/svnroot/repository
//进入subversion的bin目录
# cd /usr/local/subversion/bin
//创建仓库”test”
# ./svnadmin create /home/svnroot/repository/test
# cd /home/svnroot/repository/test
//看看是不是多了些文件,如果是则说明Subversion安装成功了
# ls –l
# cd /usr/local/subversion/bin
//这条语句将把路径/home/user/import下找到的文件导入到你创建的Subversion 仓库中去,
//提交后的修订版为1。
# ./svn import /home/user/import file:///home/svnroot/repository/test –m “注释”
//不让其他人有该目录的权限
# chmod 700 /home/svnroot/repository
4. 修改Apache配置文件

# cd /usr/local/apadche2/bin
//启动Apache
# ./apachect1 start
# vi /usr/local/apache2/conf/httpd.conf
//在最下面添加
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
<Location /svn>
DAV svn
SVNParentPath /home/svnroot/repository/ //svn父目录
AuthzSVNAccessFile /home/svnroot/repository/authz.conf //权限配置文件
AuthType Basic //连接类型设置
AuthName “Subversion.zoneyump” //连接框提示
AuthUserFile /home/svnroot/repository/authfile //用户配置文件
Require valid-user //采用何种认证
</Location>
   //其中authfile是通过”htpasswd [–c] /home/svnroot/repository/authfile username password”来创建的
//”Require valid-user”告诉apache在authfile中所有的用户都可以访问。如果没有它,
//则只能第一个用户可以访问新建库
5. 重启apache

# ./usr/local/apache2/bin/apachectl restart
//打开浏览器访问http://localhost/svn/test/,如果有东西显示就说明成功。
6. 权限管理
1)增加用户

# htpasswd [-c] /home/svnroot/repository/authfile wooin
//第一次设置用户时使用-c表示新建一个用户文件。回车后输入用户密码,完成对用户的增加
# htpasswd authfile 用户名(加入新的用户)

2)权限分配

# vi /home/svnroot/repository/authz.conf
[test:/] //这表示,仓库test的根目录下的访问权限
wooin = rw //test仓库wooin用户具有读和写权限
bao = r //test仓库bao用户具有读权限
[test2:/] //test2仓库根目录下的访问权限
wooin = r //wooin用户在test2仓库根目录下只有读权限
bao = //bao用户在 test2仓库根目录下无任何权限
[/] //这个表示在所有仓库的根目录下
* = r //这个表示对所有的用户都具有读权限
#[groups] //这个表示群组设置
#svn1-developers = wooin, bao //这个表示某群组里的成员
#svn2-developers = wooin
#[svn1:/]
#@svn1-developers = rw //如果在前面加上@符号,则表示这是个群组权限设置

将这个设置完成后。重启Apache,就可以通过
http://localhost/svn/test
这个URL来访问仓库了,当然,受权限的限制,必须是合法用户才能访问且具有相应的权限

7. 一些备忘:
1. svn checkout http://localhost/svn/hello.world

2. svn commit 时的默认编辑器的环境变量$SVN_EDITOR=vi需要手动设定,用kate好像有问题

3. 如果linux的登录用户名密码都和svn的其中一个用户名密码相同时,在checkout的时候不会要求输入用户名密码直接就可以checkout出来。比如:linux有个用户wooin,svn也有一个用户wooin,并且密码都是一样的,当用wooin登录linux后,执行checkout,可以直接提取出源码文件,不用输入认证信息。

4. 在svn使用过程中牵扯到几种权限:文件系统的权限,linux系统权限,svn用户的权限,apache进程的权限。

文件系统的权限,linux系统权限:这里相同的意思,就是平时大家使用linux时文件夹和文件的访问权限。在 svn建立仓库,文件夹,配置文件的时候用svnroot用户,并将仓库权限设置为700,不允许其他用户直接通过文件系统查看,只能由svnroot进行管理。

apache进程的权限:因为所有跟仓库传输的操作都是通过apache进程进行的,所以即使你给svn用户设置了很大的权限,但是apache进程没有访问仓库或者相关文件的权限也没有用,apache进程的权限设置在 /usr/local/apache2/conf/httpd.conf 文件中配置,找到文件中的这两行:

User daemon # 将daemon改为svnroot,让apache进程以svnroot的身份运行
Group daemon

svn用户的权限:就是在repository/authz.conf文件中设置的权限信息,是svn用来管理仓库访问权限的。

5. svn服务器设置有两种方式:http 和 svnserve。这里介绍的是http方法

6. 在/etc/profile的结尾设置一些svn启动时要做的工作

# start apache server for svn
/usr/sbin/apachectl start
export SVN_EDITOR=vi

7. APR libraries 安装 SVN 的时候最好指定 –with-apr= 和 –with-apr-util= 参数到 Apache 安装的根目录
(ServerRoot)下,而不是使用缺省的 SVN 安装包中自带的 apr 。否则如果你安装的 Apache
版本不同有可能导致 APR 库不匹配,出现类似:
Can’t set position pointer in file ‘/svn/test/db/revs/1′: Invalid argument 的错误。
Updated 2006-04-20 16:30 — 比如说如果你安装的是apache 2.2.0版本,就需要在编译安装svn的时候指定
–with-apxs和–with-apr参数到你的apache2.2.0安装目录下:
./configure –prefix=${subversionInstallFolder} /
–with-apxs=${apacheInstallFolder}/bin/apxs /
–with-apr=${apacheInstallFolder} /
–with-apr-util=${apacheInstallFolder} /
–with-ssl /
–with-zlib /
–enable-maintainer-mode


参考资料:
1. SVN學習筆記
2. Subversion版本管理器简单配置说明
3. 关于Subversion的安装、配置和权限管理

POI的一个bug问题

Filed under: java开发技术 — Alex at 1:24 pm on Thursday, August 10, 2006

key words : POI java读取Excel  java.io.IOException Unable to read entire block

版本:2.5.1final
错误提示:
java.io.IOException Unable to read entire block

出这个问题具有随机性,有时候没问题,有时候将Excel里的CellType改一下好像就没问题,但也不总是这样,真是莫名其妙.

Google了一下是一个bug,重新下载src文件,将RawDataBlock.java文件的RawDataBlock(final InputStream stream)constructor覆盖:

public RawDataBlock(final InputStream stream) throws IOException
{
_data 
= new byte[ POIFSConstants.BIG_BLOCK_SIZE ];
int count = 0;
int totalBytesRead = 0;
while ((totalBytesRead < POIFSConstants.BIG_BLOCK_SIZE) &&
(count 
!= -1)) {
count 
= stream.read(_data, totalBytesRead,
POIFSConstants.BIG_BLOCK_SIZE 
- totalBytesRead);
if (count != -1) {
totalBytesRead 
+= count;
}
}
if (count == -1) {
_eof 
= true;
else {
_eof 
= false;
}
if ((totalBytesRead != POIFSConstants.BIG_BLOCK_SIZE) && (totalBytesRead != 0)) {
String type 
=  byte + ((totalBytesRead == 1? (“”): (s));
throw new IOException(Unable to read entire block;  +
totalBytesRead 
+ type +  read; expected  + POIFSConstants.BIG_BLOCK_SIZE + bytes);
}
}


打包:

ant jar
重启app,OK!

说明:
主要问题出在 InputStream的read上,原来的实现用ReadFully方法:

public static int readFully(InputStream in, byte[] b, int off, int len)
throws IOException
{
int total = 0;
for (;;) {
int got = in.read(b, off + total, len - total);
if (got < 0) {
return (total == 0? -1 : total;
else {
total 
+= got;
if (total == len)
return total;
}
}
}

InputStream的read不能确保返回的是最大字节数,但是另一个实现却可以:
ByteInputStream
所以,下面的方法也可以修改这个问题:

 // read entire stream into byte array:
    ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count;
while (count = inputStream.read(buffer)) != -1)
byteOS.append(buffer, 
0, count);
byteOS.close();
byte[] allBytes = byteOS.betByteArray();

// create workbook from array:
InputStream byteIS = new ByteArrayInputStream(allBytes);
HSSFWorkbook wb 
= new HSSFWorkbook(byteIS);

Next Page »