Log4j+Spring配置

0 评论  

    现在的公司项目原有的log4j是采用的最传统的方式,即在classpath下面新建一个log4j.properties文件,待Tomcat启动的时候log4j.jar会自动扫描这个路径,如果发现这个文件,则加载它,如果没有,打印警告信息并采用默认配置。 这样的配置应该是最简单的,但却很难实现一些比较实在的需求,比如日志输出文件路径采用相对路径,对日志配置文件的监听和动态加载。


    Spring看到了这些需求,发挥其无所不包的特性,对log4做了封装,实现了上述的功能。具体配置如下:
    在web.xml 添加

    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>webName.root</param-value>
    </context-param>
    <context-param>
  <param-name>log4jExposeWebAppRoot</param-name>
  <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>WEB-INF/log4j.properties</param-value>
    </context-param>

    <context-param>
        <param-name>log4jRefreshInterval</param-name>
        <param-value>60000</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>

  1. 这里的webAppRootKey是保存整个web应用的相对路径的Key,在你的log4j.properties文件中引用这个路径的时候只需要类似 ${webName.root}就可以了,
  2. log4jExposeWebAppRoot则是表示是否需要把Web应用的根路径导出到webAppRootKey中
  3. log4jConfigLocation,没的说,你的配置文件,这里之所以要你指明,还是有一点玄机的
  4. log4jRefreshInterval,对日志配置文件的监听线程刷新间隔,毫秒为单位
  5. org.springframework.web.util.Log4jConfigListener,上述的context-param最终都是被这个Listener读取并借此初始化以及动态修改log4j配置的

配置算是相当简单了,但 有两个需要值得注意的地方

  1. webAppRootKey不是必须的,如果不填,会自动默认会webapp.root,但如果你有多个web应用运行在同一个JVM中,则必须要指定,不然大家都是webapp.root,所有的webapp.root会指向JVM加载的最后一个web应用的根路径。
  2. log4jConfigLocation这个路径很重要,如果直接沿用传统的方式的路径,WEB-INF/classes/log4j.properties或者classpath:log4j.properties,虽然一样能加载,但是由于log4j自身会自动扫描这个路径,所以应用启动的时候会先抛出多个找不到路径的异常(java.io.FileNotFoundException:),因为你所指定的,根据${webapp.root}来的相对路径log4j本身是不认识的。

Py2exe Bad file Descriptor

0 评论  

       前段时间用python做的上传工具,是用wxPython做UI的,再结合py2exe打包成直接可以运行的exe,虽然打包的时候遇到了乱码的问题,但误打乱撞的也解决了这个问题,不过经验告诉我们,用一个新的东西的时候,问题总是会有的,果然,后来一直遇到一个很奇怪的问题,代码在IDE里面运行得好好的,打包成exe后就经常会报一个 error, bad file descriptor的错误。 而且最离奇的就是这个错误好像是随机出现的,一会有,一会又没有,google一下这个错误,它本身的意思就是打开文件或者读写文件的时候出错了,类似共享冲突,锁 之类。


       这个问题困扰了我很久,我也尝试过很多种方法,后来偶然一次把日志输出的功能关掉,问题暂时得到了解决,但也只是出现的频率少了,还是会出现,真是吐血,关键是搞了这么久也不知道是啥原因啊。。。


       今天又Google了一下,不经意间看到一行文字[Errno 9] Bad file descriptor. 39, #. 40, # In other words, after printing a certain number of bytes to the。。。。 突然想起,难道是因为打包过后 print 函数输出的东西没地方去了,原本是到标准输出的,现在是GUI了,没有命令行窗口了,就会出错了? 一念及此,立马把所有的print都注释掉,再重新打包,运行,呵呵,还真是这个问题


       看来编程序不能马虎啊,当初为省力,一开始没配日志模块,全用print了,方便,也就是祸根了。 另一方面,要想很快的解决问题,多学点基础,原理才是正理啊

修改网站图标(favicon)

0 评论  

什么是favicon? 所谓favicon,即Favorites Icon的缩写,顾名思义,便是其可以让浏览器的收藏夹中除显示相应的标题外,还以图标的方式区别不同的网站。 用IE6的时候一直都没有没有这个概念,直到用了Firefox,才发现,每个Tab上面都有个图标,像网易,就是一个易字,当时也觉得就是在某个地方设置了一下图标的地址就可以这样显示了,但一直都不知道具体是怎么实现的。
昨天看Google App Engine里面的数据统计时,发现一个对网站根目录的favicon.ico文件的请求,看文件名就感觉这个文件就是用来做图标用的,当即google了一把,原来如果把这个图标放在网站的根目录下,名字就叫favicon.ico的话,浏览器会默认请求这个文件,并把它做为图标文件,当然IE6就不用说了,没效果的。
问题又来了,到哪去找这个Favicon呢,Google一下,发现一个在线制作的网站http://www.html-kit.com/favicon/,,把你的图片上传上去,就可以自动生成出对应的图标,而且还是动态的,很好。就随便找了个图片,把博客的图标换了,呵呵。具体效果嘛,自己看咯。

Python点滴

0 评论  

最近在用wxPython做一个小工具,给公司内部用,Python的确很简洁,Java Swing比wxPython可是要麻烦多了,不过还是碰到一些问题,都是一说就明白的问题,只是我写这个工具也是东拼西凑的找的别人的代码,好写代码而不求胜解,才会碰到这些问题了。如下:

  • wxPython关于RadioBox事件处理的Bug
wxPython里面的UI控件很丰富,刚开始画UI的时候我就加了一个RadioBox在wxFrame上,按照Swing里面的理解,Frame才是 正牌的窗口,我也就跟着用Frame了,wxPython里面的事件处理机制也是比较简单的,只需要定义好一个组件的事件ID,再把这个事件ID关联到一 个事件处理函数即可,但是,RadioBox却始终没有触发事件,一开始我以为是我代码的问题,就仔细和原有的例子代码做比较,没找到什么地方有问题,后 来我把页面上的其它控件全部注释掉,只剩下光杆的RadioBox,还是没有事件产生,,,只好Google一把,发现有人说wxRadioBox有 bug,在Frame里面不会产生事件的Bug,真晕啊,后来把Frame页面的控件移到一个Panel里面,事件的问题就OK了。
  • python格式化当前时间
import time print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) 做参数的格式化字符串可以用Unicode,可以写中文, 像这样:u'%Y年-%m月-%d日 %H:%M:%S'
  • Example 8.12. locals 是只读的,globals 不是
DiveIntoPython里的原话: Example :. def foo(arg): x = 1 print locals() (1) locals()["x"] = 2 (2) print "x=",x (3) z = 7 print "z=",z foo(3) globals()["z"] = 8 (4) print "z=",z (5) (1) 因为使用 因为使用 因为使用 3 来调用 来调用 foo,会打印出 ,会打印出 ,会打印出 {'arg': 3, 'x': 1}。这个应该没什么奇怪的。这个应该没什么奇怪的。这个应该没什么奇怪的。这个应该没什么奇怪的。这个应该没什么奇怪的。这个应该没什么奇怪的。 这个应该没什么奇怪的(2) locals 是一个返回 是一个返回 是一个返回 是一个返回 dictionary 的函数,这里您在 的函数,这里您在 的函数,这里您在 的函数,这里您在 dictionary 中设置了一个值中设置了一个值中设置了一个值中设置了一个值。您可能认为这样会改变局部量 您可能认为这样会改变局部量 您可能认为这样会改变局部量 您可能认为这样会改变局部量 您可能认为这样会改变局部量 您可能认为这样会改变局部量 您可能认为这样会改变局部量 您可能认为这样会改变局部量 您可能认为这样会改变局部量 您可能认为这样会改变局部量 x 的值为 的值为 的值为 2,但并不会。,但并不会。,但并不会。,但并不会。locals 实际上没有实际上没有实际上没有实际上没有返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变返回局部名字空间,它的是一个拷贝。所以对进行改变空间中的变量值并无影响。空间中的变量值并无影响。空间中的变量值并无影响。空间中的变量值并无影响。空间中的变量值并无影响。 (3) 这样会打印出 这样会打印出 这样会打印出 这样会打印出 这样会打印出 x= 1,而不是 ,而不是 ,而不是 x= 2。 (4) 在有了对 locals 的经验之后,您可能认为这样的经验之后,您可能认为这样的经验之后,您可能认为这样的经验之后,您可能认为这样的经验之后,您可能认为这样的经验之后,您可能认为这样的经验之后,您可能认为这样的经验之后,您可能认为这样不会 改变 改变 z 的值,但是可以的值,但是可以的值,但是可以的值,但是可以。由于 由于 由于 Python 在实现过程中内部有所区别 在实现过程中内部有所区别 在实现过程中内部有所区别 在实现过程中内部有所区别 在实现过程中内部有所区别 在实现过程中内部有所区别 在实现过程中内部有所区别 (关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,关于这些区别我宁可不去研究,因为我自已还没有完全理解因为我自已还没有完全理解因为我自已还没有完全理解因为我自已还没有完全理解因为我自已还没有完全理解因为我自已还没有完全理解因为我自已还没有完全理解因为我自已还没有完全理解因为我自已还没有完全理解) ,globals 返回实际的全局名字空间,而不是返回实际的全局名字空间,而不是返回实际的全局名字空间,而不是返回实际的全局名字空间,而不是返回实际的全局名字空间,而不是返回实际的全局名字空间,而不是返回实际的全局名字空间,而不是返回实际的全局名字空间,而不是返回实际的全局名字空间,而不是返回实际的全局名字空间,而不是一个拷贝:与 一个拷贝:与 一个拷贝:与 locals 的行为完全相反。所以对 的行为完全相反。所以对 的行为完全相反。所以对 的行为完全相反。所以对 的行为完全相反。所以对 的行为完全相反。所以对 的行为完全相反。所以对 的行为完全相反。所以对 globals 所返回的 所返回的 所返回的 所返回的 dictionary - 155 - Dive Into Python http://diveintopython.org/ 的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。的任何改动都会直接影响到全局变量。 (5) 这样会打印出 这样会打印出 这样会打印出 这样会打印出 这样会打印出 z= 8,而不是 ,而不是 ,而不是 z= 7。 之所以注意到这个是因为我在python里面定义的全局变量A=7,直接在代码里改成A=8,后面用到A的时候还是7,后来换成globals()['A'] = 8才OK。
  • repr函数
repr函数用来取得对象的规范字符串表示。反引号(也称转换符)可以完成相同的功能。注意,在大多数时候有eval(repr(object)) == object。 >>> i = [] >>> i.append('item') >>> `i` "['item']" >>> repr(i) "['item']" 基本上,repr函数和反引号用来获取对象的可打印的表示形式。你可以通过定义类的__repr__方法来控制你的对象在被repr函数调用的时候返回的内容。 这个是在自定义异常里面发现的,我要抛出一个自定义的异常,按照不知道什么地方来的代码,在异常的__str__方法也就是tostring方法里面用到了这个函数,导致我抛出的异常内容本是Unicode,显示出来确是类似"\\u6578"的东西。
  • wx.Sizer怎样才有Padding效果
wxSizer还是比较好定位的,我只用了BoxSizer和FlexGridSizer,不过我发现这两个里面都没有一个明确的地方可以设置padding,FlexGridSizer倒是可以设置gab,不过这时在Sizer里面的,后来才发现sizer的Add方法里面可以指定Border的宽度,和Border的上下左右组合,这样就可以实现padding效果了

wxPython学习笔记(二) 创建基本的wxPython程序

0 评论  

创建基本的wxPython程序

  • 主题:

    • 创建一个基本的wxPython程序
    • 将这个程序打造成一个简单的文本编辑器

本节将介绍如何使用wxPython构建一个小型的文本编辑器。通过这个看似复杂的任务你将会体验到wxPython有多方便和简单。

概述

  • 每当大家提前GUI编程的时候,总是会牵扯到窗体,菜单,鼠标,图标等等。或许你的第一感觉wx.Windows就对应一个显示在屏幕上的窗口,但你错了,在wxPython中,wx.Window表示任意可以显示在屏幕上的东西的对象,wx.Window这个类是所有屏幕上可见的对象的基类,诸如输入框,下拉列表都是由它派生而来。屏幕上的可见对象都有一些共同的属性和行为,比如位置,尺寸,是否可见,是否处于输入焦点等等,这些在wx.Window里面都有定义。 所以如果你要找一个类来表示窗口,就应该用继承自wx.Window的wx.Frame而不是wx.Window. wx.Frame实现了所有与屏幕相关的行为和属性(当然如果wx.Frame位于MDI中则另当别论) .要创建一个窗体,可以用wx.Frame,也可以用其子类如wx.Dialog,但不能再按照思维定势去想wx.Window了。

一个简单的例子

添加编辑控件

要编写一个文本编辑器,首先当然需要一个编辑控件,如下:
import wx
class MainWindow(wx.Frame):
""" We simply derive a new class of Frame. """
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(200,100))
self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE)
self.Show(True)
app = wx.PySimpleApp()
frame=MainWindow(None, wx.ID_ANY, 'Small editor')
app.MainLoop()
  • (需要注意的是这里我们定义了一个继承自wx.Frame的类,在类的初始化方法最后调用了父类的show方法,这也就不需要在额外调用show方法。) 如你所见,这段代码还是非常简洁, 我们所做的只是继承了一个wxFrame然后覆写了它的构造函数,在构造函数中新建一个简单的文本编辑框控件,就这样,就有了如下的效果图:

添加菜单栏

多数你所见到的GUI程序都有一个菜单栏和一个状态栏,下面就开始添加这两个组件:
import wx
ID_ABOUT=101
ID_EXIT=110
class MainWindow(wx.Frame):
def __init__(self,parent,id,title):
wx.Frame.__init__(self,parent,wx.ID_ANY, title, size = (300,200))
self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE)
self.CreateStatusBar() # A Statusbar in the bottom of the window
# Setting up the menu.
filemenu= wx.Menu()
filemenu.Append(ID_ABOUT, "&About"," Information about this program")
filemenu.AppendSeparator()
filemenu.Append(ID_EXIT,"E&xit"," Terminate the program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.
self.Show(True)
app = wx.PySimpleApp()
frame = MainWindow(None, -1, "Sample editor")
app.MainLoop()

  • 菜单有了,但是点击菜单却没有任何反应,下面添加事件处理:

实战事件处理

  • 对事件做处理就是人们常说的事件处理,wxPython的一大特色就是在事件处理上有极高的灵活性。接下来我们将添加一下实战的代码,这些代码或许已经超越了基于前面一章的理解能力,所以对他们的讨论将放到后续章节。 简单的说,一个事件就是一条发送到wxPython得消息告知有什么事情发生了,需要处理了 [6].通常来说,你所要做的就是把这个事件连接到一个特定的方法,让这个方法去处理,仅仅需要调用

    EVT_*. (Also see Avoiding EVT_MENU.) 方法,如下:

    EVT_MENU(self, ID_ABOUT, self.OnAbout)
    这个函数的作用在将对菜单ID 为ID_ABOUT的事件都扔给self.OnAbout去处理。

    self.OnAbout函数可能就像下面这个样子:

    def OnAbout(self, event)

    OnAbout的参数是event对象,它所做的就是在事件发生时:

  • 跳过这个事件, 让事件在事件处理周期里转到另外的处理程序。
  • 或者处理这个事件,事件消息在被程序处理后就不会在事件处理周期继续传播。

让我们看看现在的程序:

import os
import wx
ID_ABOUT=101
ID_EXIT=110
class MainWindow(wx.Frame):
def __init__(self,parent,id,title):
 wx.Frame.__init__(self,parent,wx.ID_ANY, title, size = (200,100))
 self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE)
 self.CreateStatusBar() # A StatusBar in the bottom of the window
 # Setting up the menu.
 filemenu= wx.Menu()
 filemenu.Append(ID_ABOUT, "&About"," Information about this program")
 filemenu.AppendSeparator()
 filemenu.Append(ID_EXIT,"E&xit"," Terminate the program")
 # Creating the menubar.
 menuBar = wx.MenuBar()
 menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
 self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.
 wx.EVT_MENU(self, ID_ABOUT, self.OnAbout) # attach the menu-event ID_ABOUT to the
                                                    # method self.OnAbout
 wx.EVT_MENU(self, ID_EXIT, self.OnExit)   # attach the menu-event ID_EXIT to the
                                                    # method self.OnExit
 self.Show(True)
def OnAbout(self,e):
 d= wx.MessageDialog( self, " A sample editor \n"
                     " in wxPython","About Sample Editor", wx.OK)
                     # Create a message dialog box
 d.ShowModal() # Shows it
 d.Destroy() # finally destroy it when finished.
def OnExit(self,e):
 self.Close(True)  # Close the frame.
app = wx.PySimpleApp()
frame = MainWindow(None, -1, "Sample editor")
app.MainLoop()

更多有趣的东西

  • 如果一个文本编辑器不能保存用户的输入,不能打开一个已有的文档,那这个编辑器可以算一个废品。下面我们加上打开已有文档的代码,通过一个系统的文件浏览对话框打开文件:
        def OnOpen(self,e):
       """ Open a file"""
       self.dirname = ''
       dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN)
       if dlg.ShowModal() == wx.ID_OK:
           self.filename=dlg.GetFilename()
           self.dirname=dlg.GetDirectory()
           f=open(os.path.join(self.dirname,self.filename),'r')
           self.control.SetValue(f.read())
           f.close()
       dlg.Destroy()
    
    • 上面的代码其实只有简单的三个步骤:
      • 首先,创建一个系统的文件浏览对话框
      • 然后,调用ShowModal方法,弹出一个模态对话框,等待用户按下OK按钮或者Cancel按钮。

      • 最后,得到用户所选择的文件夹和文件名,调用destroy方法然后销毁这个窗口
      这里没有给出怎么添加一个打开菜单并将它的事件连接到onOpen方法的代码,相信你看过上面的例子应该已经可以自己完成了。

    可能的扩展

    我们的编辑器还远远不能算是一个专业的编辑器,还有更多的技术可以用到这个编辑器上让它更专业,诸如:
    • 拖拽操作.
    • MDI (多窗口窗体)
    • Tab view/multiple files (通过标签视图显示更多文件)
    • Find/Replace dialog (查找,替换功能)
    • Print dialog (打印功能)

    • Macro-commands in python ( 在编辑器里面编写Python代码并运行)
    • etc ...