by agate - Published: 2008-09-01 [11:09 下午] - Category: 程序编码

老是觉得 syntaxhighlighter-plus 默认的样式和现在的模板不是很搭配, 就是觉得宽度稍微窄了点~ 就操刀小改了一下这个插件的样式表. 改动如下:

.dp-highlighter {
	/* 修改 */
	width: 640px;
	/* 添加 */
	height: expression(this.scrollHeight > 320 ? "320px" : "auto");
	max-height: 320px;
	/* 注释 */
	/* overflow: auto; */
}

这样便达到刚好的宽度, 合适的高度. 这里要提及一下从中学了一招~ 就是 IE 不支持 css 的 max-height 属性, 但是支持自家的 expression 表达式! 所以可以如上进行 hack 得到和标准同样的效果! 这个方法学习自 LINK

Tags: [ , , ] - Comments: View Comments
by agate - Published: 2008-04-06 [4:38 下午] - Category: 程序编码

今天郁闷了2个小时,不停地试验,就是没成功……(试验什么呢?)就是这个,用HQL来查出一个List,条件是某个字段为空。

两个领域类:

public class User {
	private String username;
	private Group group;
	// ------------- setter
	// ------------- getter
}
public class Group {
	private String groupName;
	private List<user> users;
	// ------------- setter
	// ------------- getter
}

让你查数据库中所有group为空的(即加入组的)所有用户。
Read more...

Tags: [ , , , ] - Comments: View Comments
by agate - Published: 2008-04-03 [11:01 上午] - Category: 程序编码

原来还是自己的问题……首先自我检讨一下,常常总是自以为是用自己的思维方式想问题。呵呵,这个真的是打开眼界啊!原来 OGNL 这个玩意有如此大的魔力,难怪 Struts2 使用他哈!厉害……

说道上回写的那个中文问题,本来是以为是转换成什么 Unicode 编码方式了,其实不然,只不过 Struts2 的 OGNL 有点低智商,只认 '' 符号里的西欧字符为字符串,其他的字符出现就会抛个 FormatException 异常……比较罕见,但是这个也使我研究了一小下 OGNL 的“真才实学”。

发现 Struts2 中
<s:if test="#user.sex == 'male' "> ... </s:if>
是可以的

<s:if test="#user.sex == '男' "> ... </s:if>
是不行的,必须改成
<s:if test="#user.sex == '男'.toString() "> ... </s:if>

发现牛逼在何处了吧…… OGNL 竟然除了属性的调用,还可以调用方法。像上面这样使用的话,中文的 OGNL 比较就基本没有问题了。

by agate - Published: 2008-04-02 [5:45 下午] - Category: 程序编码

虽然如今的ws标准都已经很智能了,大多的数据类型都可以识别。但是在GlassFish中,发布的ws方法中参数和返回值不可以为hashmap的,但是如果非要要使用键值对该如何使用呢?
最简单的方法就是再次包装:

public class MapBean {
	private HashMap<String,String> hm;
	public HashMap<String, String> getHm() {
		return hm;
	}
	public void setHm(HashMap<String, String> hm) {
		this.hm = hm;
	}
}
@WebService()
public class HelloWorld {
	public HelloWorld() {
	}
	@WebMethod
	public MapBean getMapBean(HashMap<String,String> hm) {
		MapBean mb = new MapBean();
		hm.put("server", "serverHashMap");
		mb.setHm(hm);
		System.out.println("Hello HashMap...");
		return mb;
	}
}

这样,加一层包装之后,就可以间接地使用Map了。

by agate - Published: 2008-03-27 [7:20 下午] - Category: 未分类

使用hibernate开发的朋友都知道,想在使用hibernate进行持久层操作的时候显示对应的sql语句,可以设置hibernate配置文件中的show_sql属性为true来实现这个需求。可是这个功能比较让人失望……他的语句是没错,但是参数值全是?这个带传入的参数符号,每个调试带来什么方便。

在这里,我介绍两个工具包来解决这个问题:[p6spy]和[sql_profiler],具体主页地址在下列给出
p6spy: http://www.p6spy.com
SQL Profile: http://www.jahia.net/jahia/page597.html

我们先来说说p6spy这个工具。在我理解上,他其实就是一个中间驱动,在数据库调用端和实际数据库驱动间做一个代理人的角色,进而加入了一些特有的辅助功能。在这里我们使用的调用端就是hibernate这个数据持久层框架,而数据库驱动我们用的是mysql的默认驱动(一般就是com.mysql.jdbc.Driver)。好,解释完理论开始实际试验:
* 将p6syp.zip(可能是tar文件包)下载好
* 将包中的p6syp.jar包放入你工程的classpath下(web项目就丢到WEB-INF/lib中)
* 将包中的spy.properties放入src目录中
* 修改hibernate配置文件中的数据库驱动为com.p6spy.engine.spy.P6SpyDriver这个中间驱动
* 修改刚才拷贝进src中的spy.properties文件,将realdriver的值设置成原来hibernate中的真正驱动(这里我是com.mysql.jdbc.Driver)

OK搞定!重新编译项目,以保证p6syp.jar和spy.properties编译进入目标地址。

接着就运行你的程序吧,看看控制台……(不要打我啊,我又没说控制台会有变化=.=)。但是看看你的工程根目录下是不是出现了spy.log,这里面就是你要的数据库操作历史,包括了真正传入的参数的具体值。

如果需要改变spy.log日志的生成地址,可以对应设置spy.properties文件的logfile属性给出绝对地址。(logfile默认是spy.log可以加上路径比如logfile = c:\xxx\xxx.log)

好了,似乎hibernate的?参数问题解决了,但是我的好多朋友都抱怨:“怎么这个log格式这么难懂啊!看着好不爽啊!”的确!p6syp的日志格式让人确实分外头大,于是乎介绍个SQL Profile来帮帮痛苦的大众。

照惯例,介绍介绍理论知识。SQL Profiler是一个基于p6syp的一个辅助包,可以实现很多功能,比如根据你的query来帮你生成合适的索引功能。在这里我们使用它的GUI控制介面,说白了就是一个监听器,在你通过p6spy进行数据库操作时,他就会很清晰地跟踪并列出你的操作,比单单查看那个恶心的spy.log来得舒服!既然基于p6syp当然也要用到p6syp.jar这个包咯,只是必须使用我们下载到的sqlprofiler.zip中的spy.properties来替换原来的项目中的那个文件,因为这个文件是定制过的,所谓的监听器也是靠这个文件才起作用的。好,废话说多了毕竟会烦,来说说具体步骤:
* 将下载好的sqlprofiler.zip包中的 sqlprofiler.jar 和spy.properties两个文件解压出来
* 使用新的spy.properties文件替换工程中原来的那个文件
* 根据刚才添加p6syp的过程,修改 spy.properties 文件的参数
* 使用 java -jar sqlprofiler.jar 命令启动sqlprofiler的GUI介面
* 再次启动你的应用吧,看看是不是在进行数据持久层操作的时候sqlprofiler的GUI介面中便出现了对应的操作记录,很清晰的列了出来:

Tags: [ , , , , ] - Comments: View Comments
by agate - Published: 2008-03-15 [9:09 上午] - Category: 程序编码

相信每位初学OOP的同学都知道在这面向对象的世界里比较两个对象的方法是使用Equals来实现,可是如何写一个比较完美的又代码量小的Equals函数呢?

还有就是在散列表的数据结构中,散列表自身的数据结构算法需要用到对象比较的方法HashCode,所以常常我们会听到“老者”对我们谆谆而训曰:重写Equals方法是必须的,可是别忘了重写HashCode哦!

HashCode和Equals这两个方法的渊源可谓不浅,在这里我通过简单的代码片段,展示一个目前常用的比较完美且代码量小的方法重写方式:

	/**
	 * 这里我们假定改类的名字为Example
	 */

	@Override
	public int hashCode() {
		int result = 关键属性.hashCode();
		//这里31其实可以由任何一个质素代替,用来保证hashcode的不重复
		result = 31 * result;
		//关键属性不止一个的话可以加上
		//result = result + 关键属性2.hashCode() + ……;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}

		if (obj == null) {
			return false;
		}

		if (getClass() != obj.getClass()) {
			return false;
		}

		Example other = (Example) obj;

		//如果关键属性不止一个的话就多写几个判断
		if (!关键属性.equals(other.关键属性)) {
			return false;
		}

		return true;
	}
Tags: [ , ] - Comments: View Comments
by agate - Published: 2008-01-31 [4:44 下午] - Category: 程序编码

所谓 OpenSessionInView 就是真对 Hibernate 这个数据持久层框架的一个Web下的使用技巧。我们在日常 MVC 程序开发的过程中,如果使用的是 Hibernate 的数据持久层框架,一定常常在业务逻辑层中出现 Session is closed 的 laze 异常,这是由于 Hibernate 的Session 在上一个操作中我们为了保证 Session 已经及时的回收时被我们关掉了。

我们常常被放在一个很尴尬的地带:我们的 DAO 成负责 CRUD 在执行完成后根据我上面说的那个“好习惯”,肯定要把本次操作的Session关掉,或者说在一个点统一被关掉。那么导致的结果是,当我拿到我们需要的对象时,该对象虽然说是数据完整的,但是他可能有一个 Link 对象,这个对象可是不完整的!顶多是一个包含 ID 的空壳。那很自然的,当我们要访问这个对象中的 Link 对象的某个非ID值的时候,必然抛出“Laze”异常。如果我们之前不关闭那个 Session 似乎一般的解决方案没法告诉在下一个使用层的代码何时关闭,虽然可以成功访问 Link 对象,但是长此以往 Session 就大大占用内存了。

如何设计才好呢?在很多 Hibernate 的使用者中就有人很早地提出了 Open Session In View 这个Web开发的重要理念,即让 Hibernate 的 Session 在整个请求周期中生存(包括建立和消亡)。当然这个是理念,实现手段有很多种了,包括什么参数传递、建立辅助包等等等等。这里我们专门提及 Spring 这个万能的整合型框架是如何处理的。

Spring 为我们提供了一个叫做 OpenSessionInViewFilter 的过滤器,他是标准的 Servlet Filter 所以我们把它按照规范配置到 web.xml 中方可使用。使用中我们必须配合使用 Spring 的 HibernateDaoSupport 来进行开发,也就是说,我们的dao层的类都要继承于 HibernateDaoSupport,从中由 Spring 来控制 Hibernate 的 Session 在请求来的时候开启,走的时候关闭,保证了我们访问数据对象时的稳定性。

下面我大概描述一下使用的方法:

1. 在 web.xml 中加入对应过滤器配置文件

<!-- Spring的OpenSessionInView实现 -->
<filter>
	<filter-name>openSessionInViewFilter</filter-name>
	<filter-class>
		org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
	</filter-class>
</filter>
<filter-mapping>
	<filter-name>openSessionInViewFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

2. 在我们访问持久层数据是使用 Spring 为我们的 HibernateDaoSupport 的支持,并使用其中的对应方法操作我们的持久层数据

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class XxxDAO extends HibernateDaoSupport {

	public void save(Xxx transientInstance) {
		try {
			getHibernateTemplate().save(transientInstance);
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public void delete(Xxx persistentInstance) {
		try {
			getHibernateTemplate().delete(persistentInstance);
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public Xxx findById(Integer id) {
		try {
			Role instance = (Xxx) getHibernateTemplate().get("Xxx", id);
			return instance;
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public List findByProperty(String propertyName, Object value) {
		try {
			String queryString = "from Xxx as model where model."
					+ propertyName + "= ?";
			return getHibernateTemplate().find(queryString, value);
		} catch (RuntimeException re) {
			throw re;
		}
	}
}

其实啊,就是调用 HibernateDaoSupport 中的 getHibernateTemplate() 这个模板方法,再使用里头的对应对持久层操作的方法。

这样,Spring 这个优秀的整合型框架就是轻松地帮我们把烦恼已久的问题解决了。