没有比人更高的山

JSF异常消息机制及应用0

JSF有两种异常消息:

[1] JSF提供的标准异常信息,如标准的验证器和转换器生成的异常信息等

[2] 自定义的异常信息

与消息相关的类是javax.faces.application.FacesMessage,他封装了单一的、本地化的、人类可以理解的消息,除了消息字符串本身外,FacesMessage还有三个属性:severity(严重性),summary(摘要),detail(详细信息)

serverity被定义成FacesMessage的内部类,有四种类型:Info、Warn、Error、Fatal
FacesContext负责维护FacesMessage的两个逻辑集合,一个和组件相关的消息集合、一个不与组件相关的消息集合,定义了如下的和消息相关的方法
public Iterator<FacesMessage> getMessages();
public Iterator<FacesMessage> getMessages(String clientId);
public Iterator<String> getClientIdsWithMessages();//返回有消息绑定的组件id
public void addMessage(String clientId, javax.faces.application.FacesMessage message);//向FacesContext中加入一条FacesMessage
public FacesMessage.Severity getMaximumSeverity();//返回最严重的问题的严重性

FacesMessage的部分源代码如下:


private FacesMessage.Severity _severity;
private String _summary;
private String _detail;

public FacesMessage()
{
    _severity = SEVERITY_INFO;
}

public FacesMessage(String summary)
{
    _summary = summary;
    _severity = SEVERITY_INFO;
}

public FacesMessage(String summary, String detail)
{
    _summary = summary;
    _detail = detail;
    _severity = SEVERITY_INFO;
}

public FacesMessage(FacesMessage.Severity severity, String summary, String detail)
{
    if(severity == null) throw new NullPointerException("severity");
    _severity = severity;
    _summary = summary;
    _detail = detail;
}

和消息相关的两个标签是<h:message>与<h:messages>:
<h:message> 有一个必设属性for,标示消息的绑定组件id;showDetail属性默认为false,showSummary属性默认为true
<h:messages>渲染所有的排队消息,在globalOnly设为true时只渲染哪些没有组件标识符的消息。

我一般会在项目中新建一个MessageUtil类,处理消息,其代码如下:

public class MessageUtil {

    public static void addErrorMessage(FacesContext context, String clientId, String message){
        context.addMessage(clientId, new FacesMessage(message));
    }

    public static void addErrorMessage(FacesContext context, String message) {
        addErrorMessage(context, null, message);
    }

    /**
    * Add a global message, the detail is null and the servity is info by default
    * @param message message summary
    */
    public static void addErrorMessage(String message){
        addErrorMessage(FacesContext.getCurrentInstance(), message);
    }

    /**
    * Binding messages to a ui component
    * @param clientId The ui component id
    * @param message message summary
    */
    public static void addErrorMessage(String clientId, String message){
        addErrorMessage(FacesContext.getCurrentInstance(), clientId, message);
    }
}

如 我们在登录时需要向用户提示“用户名或者密码错误”,可以调用public static void addErrorMessage(String message),然后在页面上使用<h:messages globalOnly=”true”/>来显示这个信息。

VN:F [1.7.5_995]
Rating: 9.0/10 (1 vote cast)
VN:F [1.7.5_995]
Rating: 0 (from 0 votes)

session、cookie与“记住我的登录状态”的功能的实现2

Cookie的机制

     Cookie是浏览器(User Agent)访问一些网站后,这些网站存放在客户端的一组数据,用于使网站等跟踪用户,实现用户自定义功能。

     Cookie的Domain和Path属性标识了这个Cookie是哪一个网站发送给浏览器的;Cookie的Expires属性标识了Cookie的有效时间,当Cookie的有效时间过了之后,这些数据就被自动删除了。

     如果不设置过期时间,则表示这个Cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,Cookie就消失了。这种生命期为浏览会话期的Cookie被称为会话Cookie。会话Cookie一般不保存在硬盘上而是保存在内存里。如果设置了过期时间,浏览器就会把Cookie保存到硬盘上,关闭后再次打开浏览器,这些Cookie依然有效直到超过设定的过期时间。存储在硬盘上的Cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的Cookie,不同的浏览器有不同的处理方式。

Session的机制

     Session是存放在服务器端的类似于HashTable结构(每一种Web开发技术的实现可能不一样,下文直接称之为HashTable)来存放用户数据,当浏览器第一次发送请求时,服务器自动生成了一个HashTable和一个Session ID用来唯一标识这个HashTable,并将其通过响应发送到浏览器。当浏览器第二次发送请求,会将前一次服务器响应中的Session ID放在请求中一并发送到服务器上,服务器从请求中提取出Session ID,并和保存的所有Session ID进行对比,找到这个用户对应的HashTable。

     一般情况下,服务器会在一定时间内(默认20分钟)保存这个HashTable,过了时间限制,就会销毁这个HashTable。在销毁之前,程序员可以将用户的一些数据以Key和Value的形式暂时存放在这个HashTable中。当然,也有使用数据库将这个HashTable序列化后保存起来的,这样的好处是没了时间的限制,坏处是随着时间的增加,这个数据库会急速膨胀,特别是访问量增加的时候。一般还是采取前一种方式,以减轻服务器压力。

Session的客户端实现形式(即Session ID的保存方法)

一般浏览器提供了两种方式来保存,还有一种是程序员使用HTML隐藏域的方式自定义实现:

[1] 使用Cookie来保存,这是最常见的方法,本文“记住我的登录状态”功能的实现正式基于这种方式的。服务器通过设置Cookie的方式将Session ID发送到浏览器。如果我们不设置这个过期时间,那么这个Cookie将不存放在硬盘上,当浏览器关闭的时候,Cookie就消失了,这个Session ID就丢失了。如果我们设置这个时间为若干天之后,那么这个Cookie会保存在客户端硬盘中,即使浏览器关闭,这个值仍然存在,下次访问相应网站时,同样会发送到服务器上。

[2] 使用URL附加信息的方式,也就是像我们经常看到JSP网站会有aaa.jsp?JSESSIONID=*一样的。这种方式和第一种方式里面不设置Cookie过期时间是一样的。

[3] 第三种方式是在页面表单里面增加隐藏域,这种方式实际上和第二种方式一样,只不过前者通过GET方式发送数据,后者使用POST方式发送数据。但是明显后者比较麻烦。

实现“记住我的登录状态”的功能

     前面我们了解到,如果我们将Session ID通过Cookie发送到客户端的时候设置其过期时间为1年,那么在今后的一年时间内,客户端访问我的网站的时候都回将这个Session ID值发送到服务器上,服务器根据这个Session ID从内存或者数据库里面恢复存放Key-Value对的Hashtable。

     其实这已经很好的实现了我们的功能了。但是,前面也提到了,实际上Session并不会一直都存在的,过了一定的时间之后,服务器上的Session就被销毁了,以减轻服务器的访问压力。当服务器上的数据被销毁后,即使客户端上存放了Cookie也没有办法“记住我的登录状态”了。

     通用的实现办法是,将用户的用户名和加密之后的密码也通过Cookie的方式存放在客户端,当服务器上的Session销毁以后,使用Cookie里面存放的用户名和加密之后的密码重新执行一次登录操作,重建Session,并更新客户端上Cookie中存放的的Session ID,而这个操作是发生在用户请求一个需要身份验证的页面资源的背后,对于用户来讲是透明的,于是就达到了“记住我的登录状态”的目的了。

到目前为止,已经基本明确了“记住我的登录状态”的实现方式和理论依据,后文将使用jsp和php两种Web开发技术来具体实现这个功能。

VN:F [1.7.5_995]
Rating: 8.3/10 (8 votes cast)
VN:F [1.7.5_995]
Rating: +3 (from 3 votes)

PHP的特点与发展的草根性0

一直以来都有一个疑问,就是为什么PHP的需求这么多?会有这个疑问,是因为我发现有很多可以合作的机会都是基于PHP的,而我对于PHP技术跟本就不了解。最近有个朋友去了一家公司实习,也是做PHP——这个极大的刺激了我,于是我对比了一下我熟悉的各种Web开发框架(包括ASP,ASP.NET,JSP,Ruby on Rails, Django),发现PHP的发展充满了“草根”特性,以至于很多人都忽略了它。

首先,任何一门技术要使用都需要学习,从学习成本上讲,PHP无疑是最小的,我花了半个小时浏览了W3School的PHP教程的基础部分,花了十几分钟看了看PHP如何连接MySQL数据库,就写出了一个简单的有登录、退出功能的网站,当然在写的过程的不断的在查API。想想学习C#、ruby、python、java、vbscript都得花一个星期或者更长的时间的时候,不禁心里想要是一开始就用了PHP该有多好啊。这几个当中,我自己认为学习难度排序是:(括号中的算是一个数量级的,如果JSP再包括struts、hibernate、spring等这些的话,那么Java又比ASP.NET要高上一个数量级了)。(JSP>ASP.NET)>(Python>ruby)>(ASP>PHP)

我们在比较多种技术的时候往往只是很简单的比较其开发难度,而忽视服务器维护难度和成本。试想,企业本身有一个JSF+Hibernate+Spring架构的OA系统,如果开发者或者维护者一旦离职,继任着得如何上得了手?但是如果是PHP就不一样了,看一看语法,马上就可以开始工作了,这也迎合了目前大部分公司的需要。

其次,市场需求直接决定了开发群体的大小,中国互联网最多的需求都是一些很朴实的需求——一个主页、一个简单的办公系统,中小型企业没有能力和意识去发展自身的信息化,往往只需要一个主页和一个简单办公系统而已,而且在非IT中小企业,互联网营销并没有得到管理者的重视,所以IT人员往往处于很低的地位,往往也只有几个人或者根本没有人。这样的需求PHP能很好的满足了,而且简单直接。

再次,运行成本低,自己架设服务器基本只需要电脑费用、电费、网费,托管服务器价格更便宜,一个月几十块钱就行了。而且容量大,普通PC就可以承受一定的并发需求,不需要配置专门的服务器。前面我提到的那个JSF的OA系统部署的时候就需要1G的内存,这个网站是几年前开发的,那时候内存最大还是512M,想想都有点后怕。

正因为上面几个原因,PHP的发展不是大公司的推动(像IBM推SOA),也不是像若干年前的Java(技术比较先进,相比同时期的ASP功能强大得多),它的发展有着很深厚的群众基础,预计未来的几年在中国Web市场上还将有大的需求。

不过,也因为技术的发展,很多很多额外的因素被添加到PHP中,像面向对象、各种各样的框架等,使PHP不可避免的走向复杂,如何保持其草根性、其简洁决定了PHP能走多远。

VN:F [1.7.5_995]
Rating: 0.0/10 (0 votes cast)
VN:F [1.7.5_995]
Rating: 0 (from 0 votes)

Thickbox在IE8下不垂直居中的解决办法0

这个问题应该是ie8和ie7都有同样的问题,http://jamazon.co.uk/web/2008/03/17/thickbox-31-ie7-positioning-bug/,这篇文章做了很详细的说明,而且提供了补丁,但是这个补丁在ie8下面依然有问题,出现这个问题应该是因为在ie8下,thickbox仍然当作ie6来处理,我在开头加了一个判断,如下:

$.browser.msie6 = $.browser.msie
        && /MSIE 6\.0/i.test(window.navigator.userAgent)
        && !/MSIE 7\.0/i.test(window.navigator.userAgent)
        && !/MSIE 8\.0/i.test(window.navigator.userAgent);

修正后的补丁下载:jquery.thickbox.js

VN:F [1.7.5_995]
Rating: 0.0/10 (0 votes cast)
VN:F [1.7.5_995]
Rating: 0 (from 0 votes)

Java读取文件的编码问题0

在Java的文件操作中,如果一个文件是UTF-8格式,那么一定要使用UTF-8的编码格式去读取,如果按其他格式读取之后再做转换,可能会发生不可预料的问题,如“乱码”,具体原因我没有搞清楚,因为JDK读取文件时采用了sun.nio.cs.StreamDecoder这个类,这个是sun公司的代码实现,并没有源代码可以参考。

下面就两种方式做记录:
1.Java按一定编码读取文件
InputStream is = Main.class.getResourceAsStream(fileName);
BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
String tmp;
while((tmp = br.readLine()) != null){
    System.out.println(tmp);
}

2.Java字符串编码转换
FileReader reader = new FileReader(fileName);
BufferedReader br = new BufferedReader(reader);
String tmp;
while((tmp = br.readLine()) != null){
    byte[] bs = tmp.getBytes();
    System.out.println(new String(bs, "utf-8"));
}

VN:F [1.7.5_995]
Rating: 0.0/10 (0 votes cast)
VN:F [1.7.5_995]
Rating: 0 (from 0 votes)


Switch to our mobile site