2010年7月30日星期五

充血模型设想实现

充血模型设想实现: " 早两年,贫血模型和充血模型在javaeye讨论的很热闹,但在具体实现时争论的比较多,关键还是由于Java不比动态语言那么容易去实现,如果能够在领域模型中动态添加相关访问数据库的方法,会是什么情况。下面借鉴rails去实现一个充血领域模型。

最近对操作字节码比较感兴趣,想到在编译领域模型时,动态添加相关的字节码,达到丰富领域模型,同时需要hibernate 的支持,获取所有@Entity的领域模型,添加HibernateTemplate Field,借助aspectj,实例化领域模型时,注入hibernateTemplate。(Spring Roo就是这么实现的...),考虑也把jdbcTemplate添加进去。。。


顺带为所有field生成getter和setter。
// ASM 添加的方法:
@Transient
private HibernateTemplate hibernateTemplate;
public HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}


每一个entity添加一些persistence方法,可以省去DAO层。业务层管理事务,安全等方面逻辑, 添加如下的代码的字节码,具体参考附件中代码。在实际中,增加一个ant命令。批量添加字节码。


public void create() throws DataAccessException {
hibernateTemplate.save(this);
}

public void createOrUpdate() throws DataAccessException {
hibernateTemplate.saveOrUpdate(this);
}

public void delete() throws DataAccessException {
hibernateTemplate.delete(this);
}

public Message find() throws DataAccessException {
return hibernateTemplate.get(this.getClass(), id);
}

public void update() throws DataAccessException {
hibernateTemplate.update(this);
}

public List<Message> findByProperty(String propertyName, Object value) throws DataAccessException {
Assert.hasText(propertyName);
Assert.notNull(value);

StringBuilder buf = new StringBuilder();
buf.append("FROM ").append(this.getClass().getSimpleName()).append(" WHERE ").append(propertyName).append(" = :condition");
List<Message> entities = this.getHibernateTemplate().findByNamedParam(buf.toString(), "condition", value);
return entities;
}

public List<Message> findAll() throws DataAccessException {
return (List<Message>) hibernateTemplate.loadAll(this.getClass());
}




测试的实例如下:

原始Message entity代码只定义Field


@Entity
@Table(name='messages')
public class Message1 {
@Id
@GeneratedValue
@Column(name='message_id')
private Long id;
@Column(name='message_text')
private String text;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name='next_message_id')
private Message1 nextMessage;
}


为方便测试手动注入hibernateTemplate到message对象中。


final HibernateTemplate hibernateTemplate = new HibernateTemplate();
HibernateTransactionManager transactionManager = new HibernateTransactionManager(HibernateSessionFactory.getSessionFactory());
hibernateTemplate.setSessionFactory(HibernateSessionFactory.getSessionFactory());
hibernateTemplate.afterPropertiesSet();
transactionManager.afterPropertiesSet();

TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
Message message = new Message();
message.setHibernateTemplate(hibernateTemplate);

message.setText("Hello World");
message.create();

List<Message> list = message.findAll();
System.out.println(list.size() + "message(s) found");
}
});

HibernateSessionFactory.getSessionFactory().close();




完成了试验测试以后,但感觉实际开发有点不方便。修改了entity代码,就需要重新修改字节码,虽然用ant可以带来一些方便, 如果不在entity添加业务方法,修改entity机会不多,可以接受的,如果想在entity添加业务方法,丰富充血模型,就有点麻烦。

不过还好,从lombok那,学到一种解决思路,在eclipse编译java代码时,同时添加字节码,看了lombok的代码,有的复杂... 后期有时间再去实现...







    本文附件下载:

  • Roo.rar (40.7 KB)







作者: melin


声明: 本文系JavaEye网站发布的原创文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!




已有 0 人发表回复,猛击->>这里<<-参与讨论





JavaEye推荐






"

关于Velocity

关于Velocity: "2. 什么是Velocity?

Velocity 是一个基于Java的模版引擎。它允许web 页面设计者引用JAVA代码预定义的方法。Web 设计者可以根据MVC模式和JAVA程序员并行工作,这意味着Web设计者可以单独专注于设计良好的站点,而程序员则可单独专注于编写底层代码。Velocity 将Java 代码从web页面中分离出来,使站点在长时间运行后仍然具有很好的可维护性,并提供了一个除JSP和PHP之外的可行的被选方案。

Velocity可用来从模板产生web 页面,SQL, PostScript以及其他输出。他也可用于一个独立的程序以产生源代码和报告,或者作为其它系统的一个集成组件。这个项目完成后,Velocity将为Turbine web 应用程序框架提供模板服务。Velocity+Turbine 方案提供的模板服务将允许web 应用按真正的mvc模式进行开发。



3. Velocity 可以做什么?

3.1. Mud Store 示例

假设你是一个专门销售泥浆(MUD)的在线商店的页面设计者。我们称他为'The Online Mud Store'。生意很好。客户订购各种各样的类型和数量的泥浆。他们使用他们的用户名和密码登陆到商店中来,就可以浏览他们的订货和购买其他东西。现在,赤土陶泥正在促销,这是一种很常用的泥巴。一少部分顾客很有规律的购买一种亮红土Bright Red Mud,这也是促销产品,但是不太常用,因此被移到页面的边缘。所有顾客的信息都在数据库中被跟踪,因此有一天问题出现了: 为什么不使用Velocity来定位目标客户,这些客户对某种类型的产品特别感兴趣?

Velocity 使针对访问者个性的WEB页面客户化(个性化)非常容易。作为一个在线泥巴商店的站点设计者,以想在客户以登陆进展点后就看到它们想看的页面。

你遇到你公司的软件工程师,每个人都认为$customer 将保持当前登陆进入的客户信息,而$mudsOnSpecial 将士当前所有促销的泥巴。$flogger 对象包含有助于促销的方法。对于当前的任务,让我们仅关注这三个问题。记住,你不需要担心软件工程师如何从数据库中取得顾客信息,但你必须知道他们可以。这样可以使你专注于你的工作而软件工程师则忙于他们自己的工作。

你可以在你的页面中嵌入如下的VTL语句:

<HTML>

<BODY>

Hello $customer.Name!

<table>

#foreach( $mud in $mudsOnSpecial )

#if ( $customer.hasPurchased($mud) )

<tr>

<td>

$flogger.getPromo( $mud )

</td>

</tr>

#end

#end

</table>



foreach 语句的细节将进一步细说,但重要的是这个短小的脚本居然可以在你的站点上运行。当有一个倾向于亮红土的顾客登陆进来时,亮红土正在促销,这就是这个顾客所看到的,并且促销显示非常显著。如果另外一个长期购买赤陶土的顾客登陆进来,赤陶土促销的提示信息则应该在前面中间位置。Velocity是非常灵活的,受限的只是你的创造力。

写在VTL参考文档中的是其他Velocity 元素,他们一起给你很强大的能力和灵活性以创建很好的站点。待你更加了解这些元素,就可以开始释放Velocity的强大动力。

4. Velocity模板语言(VTL): 介绍

Velocity模板语言(VTL)旨在为Web页面结合动态内容提供最容易、简单和简洁的方法。即使有一点或者没有编程经验的页面设计者也可以很快能为页面提供动态内容。

VTL 使用引用(references )来将动态内容嵌入web页面,每个变量就是某一个类型的引用。变量实际上是一个可以调用定义在java代码中的内容的引用,或者它可以从页面内的VTL语句得出自身的值。下面是一个例子,说明可以嵌入到HTML文档中的VTL语句。



#set( $a = 'Velocity' )





这个VTL语句,就像所有的VTL语句一样,以 # 字符开始,并跟着一个指令set。 当一个在线访问这请求页面时, Velocity 模伴引擎在页面内搜索所有# 字符,然后决定是哪一个标记了VTL语句的开始,哪个标记不需要VTL做什么动作。



# 字符后面紧跟一个指令 set.。set 指令使用一个括在括号内的表达式---一个等式将一个值指派给一个变量。变量在等号的左边而值在等号的右边。



在上面的示例中,变量是 $a 值是Velocity。 这个变量就象其他引用一样,以一个$字符开始。值通常在引号之中,对Velocity来说一般没有类型冲突的问题,因为只有字符串 (基于文本的信息)可以传递给变量。



下面的主要规则可能有助于理解Velocity 是如何工作的:引用以$开头用于取得什么东西,而指令以# 开始用于做什么事情。

在上面的例子中,#set 用于将一个值指派给一个变量。而变量$a 则可以用来在模板中输出'Velocity' 。

5. Hello Velocity World!

一旦一个值被赋给一个变量,便可以在HTML中随处引用它。在下面的示例中,先给变量$foo 赋值然后引用它。

<html>

<body>

#set( $foo = 'Velocity' )

Hello $foo World!

</body>

<html>



这个页面的结果是输出'Hello Velocity World!'。

为了使包含VTL 指令的语句具有可读性,我们鼓励每个VTL语句在一个新行开始,虽然并不一定要这样做。 set 将随后深入解释。



6. 注释

可以用注释加入描述性文本,他们并不在模板引擎中输出。注释可以有助于你的记忆或者想其他人解释你的VTL语句正在做什么。

## This is a single line comment.



单行注释以## 开始,并在本行结束。如果需要加入多行注释,并不需要加入很多的单行注释。多行注释,以#* 开始并以*#结束可以处理这种情况。

This is text that is outside the multi-line comment.

Online visitors can see it.



#*

Thus begins a multi-line comment. Online visitors won't

see this text because the Velocity Templating Engine will

ignore it.

*#



Here is text outside the multi-line comment; it is visible.





下面事一些例子说明单行注释和多行注释如何工作。

This text is visible. ## This text is not.

This text is visible.

This text is visible. #* This text, as part of a multi-line comment,

is not visible. This text is not visible; it is also part of the

multi-line comment. This text still not visible. *# This text is outside

the comment, so it is visible.

## This text is not visible.



还有第三种注释, VTL 注释块,可以用来存储诸如文档作者、版本信息等。



#**

This is a VTL comment block and

may be used to store such information

as the document author and versioning

information:

@author

@version 5

*#



7. 引用

VTL中有三种类型的引用:变量,属性和方法。作为使用VTL的设计者,你和你的工程师必须在饮用的特定命名上取得一致,以便在你的模板中正确的使用他们。



有关引用的所有参数都处理为字符串对象。Everything coming to and from a reference is treated as a String object. 假如有一个对象表示$foo (比如说是整型对象),Velocity 将调用其toString() 方法来将此对象转换为一个字符串。

7.1. 变量Variables

变量的简略标记是有一个前导'$'字符后跟一个 VTL 标识符(Identifier.)组成。一个VTL 标识符必须以一个字母开始(a .. z或 A .. Z)。剩下的字符将由以下类型的字符组成:

字母 (a .. z, A .. Z)

数字 (0 .. 9)

连字符('-')

下划线 ('_')

下面是一些有效的变量引用:

$foo

$mudSlinger

$mud-slinger

$mud_slinger

$mudSlinger1



当VTL 引用一个变量时,比如$foo,变量可以从模板的set 指令取得值,也可以从

Java 代码中取得。例如,如果Java 变量 $foo 在模板被请求的时候具有值bar ,则bar 将替换页面中的所有$foo 的实例。或者,如果包含下面的语句:

#set( $foo = 'bar' )



紧跟指令后的所有$foo 的实例的输出将会一样值。

7.2. 属性



VTL引用的第二种元素是属性,而属性具有独特的格式。属性的简略标记识前导符$ 后跟一个VTL 标识符,在后跟一个点号('.')最后又是一个VTL 标识符。这是一些有效的示例:

$customer.Address

$purchase.Total



请看第一个例子, $customer.Address.。他有两种意思。 它可以意味着,查询由customer 标是的哈希表并按关键字Address返回值。但是 $customer.Address 也可能引用一个方法(下述,$customer.Address 可能是$customer.getAddress().的缩写。当一个页面被请求时,Velocity 将决定这两种可能到底是哪一个,然后返回相应的值。

7.3. 方法

方法在JAVA代码中定义,并作一些有用的事情,比如运行一个计算器或者作出一个决定。方法是实际上也是引用,由前导符'$'后跟一个VTL 标识符,后跟一个VTL 方法体(Method Body)。 VTL 方法体由一个VTL 标识符后跟一个左括号,再跟可选的参数列表,最后是右括号。下面是一些有效的方法示例:



$customer.getAddress()

$purchase.getTotal()

$page.setTitle( 'My Home Page' )

$person.setAttributes( ['Strange', 'Weird', 'Excited'] )



前面两个例子-- $customer.getAddress() 和 $purchase.getTotal() – 看起来有点象上面属性一节中所用的样子, $customer.Address 和 $purchase.Total.。如果你想这些例子在某些方面相关,那你就对了。



VTL 属性可以为VTL方法用作简略标记。属性$customer.Address 具有和方法$customer.getAddress() 完全一样的效果。属性和方法的主要不同点是方法中可以添加参数列表。

简略标记可以用在下面的方法中:

sun.getPlanets()

$annelid.getDirt()

$album.getPhoto()



我们或许希望方法可以为我们放回属于太阳系的行星的名字,喂养我们的蚯蚓,或者从相册中返回一张照片。下面只有长的那个标记是可以工作的方法:

$sun.getPlanet( ['Earth', 'Mars', 'Neptune'] )

## 不能将参数列表传递给$sun.Planets



$sisyphus.pushRock()

## Velocity 假定我意思是$sisyphus.getRock()



$book.setTitle( 'Homage to Catalonia' )

## 不能传递一个参数列表



7.4. 形式引用符Formal Reference Notation

引用的简略符号如上所述,但是另外还有一种引用的形式符号,示例如下:

${mudSlinger}

${customer.Address}

${purchase.getTotal()}



在大多数情况下,我们将使用引用的简略符号,但在一些情况下,也需要拥戴哦形式引用符以便正确处理。

假定你正在纸片上构件一个句子,将使用$vice 作为句子中名词的词根。我们的目标是允许人们选择词根,然后产生以下两种结果之一:

'Jack is a pyromaniac.'

或者 'Jack is a kleptomaniac.'。

在这种情况下,使用简略符号是不太充分的。考虑到下面的例子:

Jack is a $vicemaniac.





这里有个不确定性, Velocity 假定 $vicemaniac,(而不是 $vice) 是一个你想要使用的标识符。 找不到$vicemaniac的值,他将返回$vicemaniac。使用形式符号便可解决这个问题:

Jack is a ${vice}maniac

现在Velocity 知道 $vice(而不是 $vicemaniac) 是一个引用。形式符号常用在饮用咋模板中和文本直接邻近的地方。



7.5. 安静引用符Quiet Reference Notation

当 Velocity 遇到一个位定义的引用时,其通常行为是输出这个引用的映像。比如,假设下面的引用出现在模板中的一部分:

<input type="text" name="email" value="$email"/>

当表单初次装入时,变量引用$email 无值,你宁愿是一个空白域而不是具有值'$email'。使用安静引用符可以绕过Velocity的常规行为,在VTL中不用$email 而是用$!email 符号。 所以,上面的例子将会看起来像下面的样子:

<input type="text" name="email" value="$!email"/>

现在,当表单初次装入时, $email 仍然没有值,但是将输出空字符串而不是'$email'。



形式和安静引用符可以一起使用,如下所示:

<input type="text" name="email" value="$!{email}"/>





1. 取得语义Getting literal

VTL 特别的字符,比如$ 和 #, 来做这个工作,因此在模板中使用这些自负的时候必须格外小心。本节讲述$ 的转义。

1.1. 货币

我们写下句子 'I bought a 4 lb. sack of potatoes at the farmer's market for only $2.50!' ,这并没有什么问题。但如前所述,VTL标识符总是以大写或是小写字母开始,所以$2.50 在引用中将不能出错。

1.2. 转义有效的VTL 引用

问题将会出现,因为Velocity 将有一个潜在的冲突。转义特殊字符是处理VTL模板种特殊字符的最好的办法,者可以用一个反斜线来进行。

foo

$email

\foo

\$email



如果 Velocity 在VTL模板中遇到一个$email引用,他将在上下文中查找相应的值。这里,输出将是foo,因为 $email 是定义了的。如果$email 未定义,输出将是$email 。



假设$email 是定义了的(比如,具有值foo),但是你想输出 $email。可以有几种方法来做这个事情,不是最简单的是使用转义符。

## The following line defines $email in this template:

#set( $email = 'foo' )

$email

\$email

\\$email

\\\$email



将输出是

foo

$email

\foo

\$email



注意: \ 绑定在$ 的左边。从做绑定原则使\\\$email 被解释为\\$email。 和上面例子比较下面的例子,这里$email 未定义。

$email

\$email

\\$email

\\\$email

输出



$email

\$email

\\$email

\\\$email



注意,Velocity 处理定义和未定义的引用是不同的。下面一个set 指令将$foo 设为值gibbous.。

#set( $foo = 'gibbous' )

$moon = $foo



输出将是$moon = gibbous

-- 这里 $moon 作为字面输出,因为他并没有定义。而gibbous 将在$foo 的位置输出。



我们也可以转义VTL 指令,这将在指令一节祥述。



2. Case Substitution

现在你大致了解了引用,可以在模板中使用它们了。Velocity 采用了很多JAVA原理的优点,模板设计人员会发现非常容易使用。例如:

$foo



$foo.getBar()

## is the same as

$foo.Bar



$data.getUser('jon')

## is the same as

$data.User('jon')



$data.getRequest().getServerName()

## is the same as

$data.Request.ServerName

## is the same as

${data.Request.ServerName}

这个例子显示了引用的一些其他用法。Velocity 借鉴了Java的自省和组件bean特征,来解决引用名在上下文中作为对象和对象方法的问题。可以在你的模板的任何地方插入引用和求值。

Velocity, 建模在Sun Microsystems定义的BEAN规范之上,是大小写敏感的;开发者努力捕捉和纠正可能出现的用户错误。当方法getFoo() 在模板中通过$bar.foo引用时,Velocity 首先尝试$getfoo。如果失败,他会再尝试 $getFoo。类似地,当一个模板引用到 $bar.Foo, Velocity 将尝试 $getFoo() 先,然后尝试 getfoo()。

注意: 模板中引用示例变量的问题仍然没有解决。 只有引用等价于JavaBean的 getter/setter 方法解决了。(比如 $foo.Name 解决了到类 Foo的 getName() 示例方法的引用,但不能引用Foo的一个公共实例变量Name)。

3. 指令

因为指令(使用脚本来有效操控JAVA代码的输出)允许页面设计员真正专注于咱点的外观和内容设计,引用允许模板设计员为Web页面产生动态内容。



3.1. #set

#set 指令用来为引用设置相应的值。值可以被值派给变量引用或者是属性引用,而且赋值要在括号里括起来。

#set( $primate = 'monkey' )

#set( $customer.Behavior = $primate )

赋值的左边必须是一个变量应用或者是属性引用。右边可以是下面的类型之一:

变量引用

字面字符串

属性引用

方法引用

字面数字

数组列表



这些例子演示了上述的每种类型:

#set( $monkey = $bill ) ## variable reference

#set( $monkey.Friend = 'monica' ) ## string literal

#set( $monkey.Blame = $whitehouse.Leak ) ## property reference

#set( $monkey.Plan = $spindoctor.weave($web) ) ## method reference

#set( $monkey.Number = 123 ) ##number literal

#set( $monkey.Say = ['Not', $my, 'fault'] ) ## ArrayList

注意:最后一个例子中,在方括号[..] 中定义的项目可以被ArrayList 类定义的方法访问。 比如,你可以使用$monkey.Say.get(0)访问上述的第一个元素。

右边也可以是一个简单的算术表达式:

#set( $value = $foo + 1 )

#set( $value = $bar - 1 )

#set( $value = $foo * $bar )

#set( $value = $foo / $bar )

如果右边是一个属性或方法引用,取值是NULL,他将不会赋值给左边。通过这种机制将一个存在的引用从上下文中删除是不可能的。这对Velocity的新手可能会混淆。例如:

#set( $result = $query.criteria('name') )

The result of the first query is $result



#set( $result = $query.criteria('address') )

The result of the second query is $result





如果, $query.criteria('name') 放回字符串'bill',而$query.criteria('address') 返回 null,上述VTL 将解释为:

The result of the first query is bill



The result of the second query is bill

这往往会给那些想构建#foreach循环来试图通过属性和方法引用来设置一个引用的新手带来困惑,下面马上通过#if指令测试一下。例如:

#set( $criteria = ['name', 'address'] )



#foreach( $criterion in $criteria )



#set( $result = $query.criteria($criterion) )



#if( $result )

Query was successful

#end



#end

在上面的例子中,依靠$result 的去值来决定查询是否成功恐怕不是英明的做法。 当$result 被#set设置后(添加到上下文中),他就不能再被设值为null (从上下文中删除)。



我们对此的解决方法是预设$result 为 false。 然后如果 $query.criteria() 调用失败,你就可以检查之。



#set( $criteria = ['name', 'address'] )



#foreach( $criterion in $criteria )



#set( $result = false )

#set( $result = $query.criteria($criterion) )



#if( $result )

Query was successful

#end



#end

不象其他Velocity 指令, #set 指令没有#end 语句。

3.2. 字面字符串

当使用#set 指令时,括在双引号中的字面字符串将解析和重新解释,如下所示:

#set( $directoryRoot = 'www' )

#set( $templateName = 'index.vm' )

#set( $template = '$directoryRoot/$templateName' )

$template

输出将会是:

www/index.vm



然而,当字面字符串括在单引号中时,他将不被解析:

#set( $foo = 'bar' )

$foo

#set( $blargh = '$foo' )

$blargh



输出是:

Bar

$foo

默认情况下,使用单引号来渲染未解析文本在Velocity是有效的。这种特征可以通过编辑velocity.properties 中的 stringliterals.interpolate=false来改变。



3.3. 条件

3.4. If / ElseIf / Else

Velocity中的#if 指令允许在页面生成时,在IF条件为真的情况下包含文本。例如:

#if( $foo )

<strong>Velocity!</strong>

#end



变量 $foo 先求值,以决定是否为真。在这两种情况下为真: (i) $foo 是一个逻辑变量并具有真的值,或者 (ii) 值非空。要记住Velocity 上下文仅包括对象,所以当我们说“布尔”'boolean'时,他会被表示为“布尔类”(Boolean class)。 这对即使是返回布尔类型的方法也是真的—自省架构将返回一个具有相同逻辑值的布尔类。

如果求值为真时, #if 和 #end 语句之间的内容将输出。在这种情况下,如果 $foo 为真,输出将是'Velocity!'。相反,如果 $foo 具有一个null 值,或者逻辑假,语句求值为假,则没有输出。

一个 #elseif 或者 #else 项可以用在#if 语句中。请注意, Velocity 模板引擎将在第一个为真的表达式时停止。下面的例子中,假设$foo 具有值15 而 $bar 等于 6。



#if( $foo < 10 )

<strong>Go North</strong>

#elseif( $foo == 10 )

<strong>Go East</strong>

#elseif( $bar == 6 )

<strong>Go South</strong>

#else

<strong>Go West</strong>

#end

在这个例子中,$foo 大于10,所以前面两个比较失败。接下来比较$bar 和6,结果为真,所以输出为Go South。

请注意在现在, Velocity的数值比较约束为整型—其他类型都将求值为false。 仅有一个例外是等于'==',这时Velocity 要求等号两边的对象具有相同的类型。

3.5. 关系和逻辑操作符

Velocity 使用等式操作符来决定两个变量间的关系。这里是一个简单的例子演示如何使用等式操作符:

#set ($foo = 'deoxyribonucleic acid')

#set ($bar = 'ribonucleic acid')



#if ($foo == $bar)

In this case it's clear they aren't equivalent. So...

#else

They are not equivalent and this will be the output.

#end

Velocity 也具有逻辑AND, OR 和 NOT 操作符。更进一步的信息,请看VTL参考手册VTL Reference Guide 。下面是一些演示如何使用逻辑操作符的例子:

## logical AND



#if( $foo && $bar )

<strong> This AND that</strong>

#end



例子中#if() 指令仅在$foo 和$bar 斗为真的时候才为真。如果$foo 为假,则表达式也为假;并且 $bar 将不被求值。如果 $foo 为真,Velocity 模板引擎将继续检查$bar;的值,如果 $bar 为真,则整个表达式为真。并且输出This AND that 。如果 $bar 为假,将没有输出因为整个表达式为假。

逻辑OR 的工作方式相同,唯一的例外是其中一个表达式要被求值,以便决定整个表达式是否为真。请看下面的例子:



## logical OR



#if( $foo || $bar )

<strong>This OR That</strong>

#end

如果 $foo 为真,Velocity 模板引擎就不需要去察看$bar 的值,不管 $bar 是否为真,真个表达式都为真,因此输出This OR That 。如果 $foo 为假,$bar 就必须检查其值了。在这种情况下,如果$bar 也是为假,表达式将为假,没有任何输出。当然,如果$bar 为真,则真个表达式为真,输出This OR That。

对于逻辑NOT 操作符,只有一个操作数:

##logical NOT



#if( !$foo )

<strong>NOT that</strong>

#end



这里,如果$foo 为真,!$foo 求值为假,没有输出。如果$foo 为假,!$foo 求值为真,输出NOT that 。请当心,不要和安静引用quiet reference $!foo 混淆它们是完全不同的。





1. 循环

1.1. Foreach 循环

#foreach 元素允许进行循环,例如:

<ul>

#foreach( $product in $allProducts )

<li>$product</li>

#end

</ul>

这个#foreach 循环将导致$allProducts 列表 (对象) 为查询所有的产品$products (目标)遍历一遍。每次经过循环,从$allProducts 取得的值将置于$product 变量之中。

$allProducts 变量的内容是一个矢量,一个哈希表或者数组。赋给$product 变量的值是一个Java 对象并且可以从一个类似的变量引用。例如,如果 $product 真是一个Java的产品类,其名称可以通过引用$product.Name 方法来检索(即: $Product.getName())。



我们假定 $allProducts 是一个哈希表。如果你想检索关键字的值或者在哈希表中的对象,你可以使用以下的代码:



<ul>

#foreach( $key in $allProducts.keySet() )

<li>Key: $key -> Value: $allProducts.get($key)</li>

#end

</ul>



Velocity 提供一个更容易的方式或的循环计数,以便你可以做下面类似的工作:

<table>

#foreach( $customer in $customerList )

<tr><td>$velocityCount</td><td>$customer.Name</td></tr>

#end

</table>



循环计数变量的缺省名称是$velocityCount,在velocity.properties 配置文件中标明。默认情况下,该变量从1开始计数,但是可以在velocity.properties 文件中设为从0或者1开始。 下面是velocity.properties 文件中循环变量设置一节:

# Default name of the loop counter

# variable reference.

directive.foreach.counter.name = velocityCount



# Default starting value of the loop

# counter variable reference.

directive.foreach.counter.initial.value = 1



2. 包含

#include 脚本元素允许模板设计人员包含(导入)本地文件, 这个文件将插入到#include 指令被定义的地方。文件的内容并不通过模板引擎来渲染。处于安全的原因,被包含的文件只可以放在TEMPLATE_ROOT下。



#include( 'one.txt' )

#include 指令引用的文件在双引号内。如果超过一个文件,其间用逗号隔开。

#include( 'one.gif','two.txt','three.htm' )



被包含的文件并不是一定要用文件名来引用,事实上,最好的办法是使用变量而不是文件名。这在根据规则决定何时提交页面时,决定目标输出是很有用的。

#include( 'greetings.txt', $seasonalstock )





3. 解析

#parse 脚本元素允许页面设计员导入包含VTL的本地文件。 Velocity将解析和渲染指定的模板。

#parse( 'me.vm' )



就象 #include 指令,#parse 可以使用变量而不是一个实在的模板文件。#parse 引用的模板文件必须包含的TEMPLATE_ROOT指定的目录之下。和 #include 指令不一样, #parse 只有一个参数。

VTL 模板templates can have #parse statements referring to templates that in turn have #parse statements. By default set to 10, the parse_directive.maxdepth line of the velocity.properties allows users to customize maximum number of #parse referrals that can occur from a single template. (Note: If the parse_directive.maxdepth property is absent from the velocity.properties file, Velocity will set this default to 10.) Recursion is permitted, for example, if the template dofoo.vm contains the following lines:

Count down.

#set( $count = 8 )

#parse( 'parsefoo.vm' )

All done with dofoo.vm!



It would reference the template parsefoo.vm, which might contain the following VTL:

$count

#set( $count = $count - 1 )

#if( $count > 0 )

#parse( "parsefoo.vm" )

#else

All done with parsefoo.vm!

#end



After 'Count down.' is displayed, Velocity passes through parsefoo.vm, counting down from 8. When the count reaches 0, it will display the 'All done with parsefoo.vm!' message. At this point, Velocity will return to dofoo.vm and output the 'All done with dofoo.vm!' message







1. 宏

#macro 脚本元素允许模板设计者在VTL 模板中定义重复的段。 Velocimacros 不管是在复杂还是简单的场合都非常有用。下面这个Velocimacro,仅用来节省击键和减少排版错误,介绍了一些Velocity宏的概念。

#macro( d )

<tr><td></td></tr>

#end



在例子中,Velocimacro定义为d,它可以象调用其他VTL指令一样的形式来进行调用:

#d()



当这个模板被调用时, Velocity 将 #d() 替换为一个单行的空表格。



Velocimacro 可以带一些参数,也可以不带参数(如上例所示)。但在他被调用时,所带的参数必须和其定义时的参数一样。很多Velocimacros 定义为不止一个参数。下面这个宏带有两个参数,一个颜色,一个数组。

#macro( tablerows $color $somelist )

#foreach( $something in $somelist )

<tr><td bgcolor=$color>$something</td></tr>

#end

#end



在这个例子中定义的Velocimacro,名为tablerows, 要求两个参数。 第一个参数代替$color, 第二个代替$somelist。

可以写进VTL 模板中的东西都可以写进Velocimacro 的主体部分。tablerows 宏其实是一个foreach 语句。在#tablerows 宏的定义中有两个#ende语句,第一个属于#foreach, 第二个结束宏定义。

#set( $greatlakes = ['Superior','Michigan','Huron','Erie','Ontario'] )

#set( $color = 'blue' )

<table>

#tablerows( $color $greatlakes )

</table>



请注意$greatlakes 替换了$somelist。 这样,当#tablerows 宏被调用时,将产生以下输出:

<table>

<tr><td bgcolor="blue">Superior</td></tr>

<tr><td bgcolor="blue">Michigan</td></tr>

<tr><td bgcolor="blue">Huron</td></tr>

<tr><td bgcolor="blue">Erie</td></tr>

<tr><td bgcolor="blue">Ontario</td></tr>

</table>



Velocimacros 在Velocity 模板语句内定义,这意味着它在同一站点内的其他Velocity 模板中并不有效。定义一个宏,并使其与其他模板共享很具有明显的优点:他减少了在大量的模板内重复定义宏的工作,并减少了出错的机会,并确保对其他宏的改变对其他所有模板有效。

但如果 #tablerows($color $list) 宏是在一个Velocimacros 模板库内定义的,它就可以被其他常规模板所用。当然,它可以用于各种目的,也可重用多次。在表示所有真菌类(fungi)的mushroom.vm 模板中,#tablerows 宏可以被用来列出典型的蘑菇。

#set( $parts = ['volva','stipe','annulus','gills','pileus'] )

#set( $cellbgcol = '#CC00FF' )

<table>

#tablerows( $cellbgcol $parts )

</table>



我们对mushroom.vm执行请求,Velocity 将在模板库内找到#tablerows 宏 (在velocity.properties 文件中定义)并产生以下输出:

<table>

<tr><td bgcolor="#CC00FF">volva</td></tr>

<tr><td bgcolor="#CC00FF">stipe</td></tr>

<tr><td bgcolor="#CC00FF">annulus</td></tr>

<tr><td bgcolor="#CC00FF">gills</td></tr>

<tr><td bgcolor="#CC00FF">pileus</td></tr>

</table>



Velocimacro 参数

Velocimacros 的参数可以是以下的VTL元素:

引用(Reference): 以 ' 打头的元素

字面字符串(String literal) : 比如'$foo' 或 'hello'

字面数字: 1, 2 ….

整数范围: [ 1..2] 或 [$foo .. $bar]

对象数组: [ 'a', 'b', 'c']

布尔真

布尔假



当把引用作为参数传递给Velocimacros时,请注意引用是按“名字”传递的。这意味着他们的值在每次使用他们的Velocimacro中产生。这个特性允许你在方法调用是传递引用,并在每次使用时进行方法调用。例如,Fo,当调用下面的Velocimacro 时,

#macro( callme $a )

$a $a $a

#end



#callme( $foo.bar() )



结果是,在方法bar() 中,引用 $foo 被调用了3次。

咋看时,这个特征让人吃惊,当当你考虑一下Velocimacros的原本动机 – 在VTL模板中避免很多“剪切复制”操作—你就会明白。它允许你将无状态对象,比如在一个颜色表格行内重复产生一些颜色次序的对象,传递给Velocimacro。

如果你需要使用这个特征,你通常可以从方法内取得一个值,作为一个新的引用传递给宏:

#set( $myval = $foo.bar() )

#callme( $myval )



Velocimacro 属性

在velocity.properties 文件中有数行定义可以用来灵活实现Velocimacros。详细情况请参见开发指南(Developer Guide)。

velocimacro.library – 是一个逗号分隔的所有Velocimacro 模板库的列表。默认情况下, Velocity 搜寻一个单一的库VM_global_library.vm.。预先配置的模板路径用来查找Velocimacro 库。



velocimacro.permissions.allow.inline – 这个属性决定Velocimacros 是否可以在常规模板内定义,取值为逻辑True或者False。默认情况下,设置为true,允许设计者在产规模板内定义宏。

velocimacro.permissions.allow.inline.to.replace.global – 逻辑true 或者false,允许标明是否允许在常规模板内定义的Velocimacro 代替在模板库中定义并通过velocimacro.library属性在启动时装入的全局宏。默认设置为false。

velocimacro.permissions.allow.inline.local.scope – 逻辑true 或者false,默认值为false。 控制是否 在模板内定义的Velocimacros 仅在定义它的模板内可见。换句话说,如果设置为true,一个模板可以定义仅能被他所用的宏。你可以用它来做一些漂亮的宏,如果一个全局调用另一个全局宏,在局部(inline)范围内,当被一个模板调用时,该模板可以定义一个被第一个全局宏调用的第二个全局宏的私有实现。其他所有模板都不受影响。



velocimacro.context.localscope – 逻辑值true 或者 false,缺省值为false。但设置为true时,所有在Velocimacro 内通过 #set() 进行的修改都将被视为Velocimacro 的本地行为,不会影响到其上下文。

velocimacro.library.autoreload – 此属性控制Velocimacro 库的自动载入。缺省值为false。如果设置为true,被调用的Velocimacro得源库将被检查是否改变,并在必要是重新载入。这将使你可以改变和测试Velocimacro 库,而不必重新启动应用服务器或者servlet容器,就象你工作在常规模板一样。这个模时仅在资源载入器的缓存模时被关闭的情况下有效 (如 file.resource.loader.cache = false )。此特征为开发时设计,不要在生产模式时使用。

Velocimacro Trivia

当前, Velocimacros 在其首次在模版中使用前必须首先定义它。这意味着, #macro() 宣称应该在使用Velocimacros之前。

如果你想#parse() 一个包含#macro() 指令的模板,记住这个非常重要。因为#parse() 在运行时发生,解析器在解析时要决定是否模版中一个看起来像VM的元素真是VM,所以解析一系列VM 宣称可能并不能如愿地工作的很好。为避免如此,可以简单地使用velocimacro.library 的办法,使Velocity 在启动时载入VM。



2. 转义 VTL 指令

VTL 可以通过反斜杠("\")来进行转义,directives can be escaped with the backslash character in a manner similar to valid VTL references.

## #include( "a.txt" ) renders as <contents of a.txt>

#include( 'a.txt' )



## \#include( 'a.txt' ) renders as \#include( 'a.txt' )

\#include( 'a.txt' )



## \\#include ( "a.txt" ) renders as \<contents of a.txt>

\\#include ( 'a.txt' )



在转义在一个单一指令内包含多个脚本元素(比如f-else-end语句)的指令时应多加小心。下面是一个典型的VTL if语句;

#if( $jazz )

Vyacheslav Ganelin

#end



如果 $jazz为 true,输出是

Vyacheslav Ganelin



如果 $jazz 为false,将没有输出。转义脚本元素将改变输出。考虑下面的情况;

\#if( $jazz )

Vyacheslav Ganelin

\#end



不管 $jazz 是真或假,输出都是

#if($ jazz )

Vyacheslav Ganelin

#end





事实上,因为所有脚本元素都被转义了, $jazz 永远不会被求值。将设反斜杠在被合法转义的脚本元素之前

\\#if( $jazz )

Vyacheslav Ganelin

\\#end



这时,如果$jazz 为真,输出是

\ Vyacheslav Ganelin

\



为理解这个情况,请注意在一个新行结束是将在输出中忽略新的一行。因此,经过#if()前的'\\' 加工后,#if()块紧跟第一个'\'。最后一个\位于新的一行,因为在'Ganelin'后又一个新行,所以,最后的那个位于#end 之前的\\是语句块的一部分。

如果 $jazz 为false,这里将没有输出。注意,在开始破坏了if语句的情况将不能被正确转义:

\\\#if( $jazz )

Vyacheslave Ganelin

\\#end



这里,#if 被转义,但有一个#end 被保留了;所以有多个结束语句将导致解析错误。





1. VTL: 格式化

虽然在本指南中的VTL经常显示在新行中或者有空格,但是下面的VTL

#set( $imperial = ['Munetaka','Koreyasu','Hisakira','Morikune'] )

#foreach( $shogun in $imperial )

$shogun

#end



和下面的写法同样有效。

Send me #set($foo = ['$10 and ','a cake'])#foreach($a in $foo)$a #end please.



Velocity的行为并不受空格的影响,前述的指令也可以写成:

Send me

#set( $foo = ['$10 and ','a cake'] )

#foreach( $a in $foo )

$a

#end

please.



或者

Send me

#set($foo = ["$10 and ","a cake"])

#foreach ($a in $foo )$a

#end please.



上面每种写法结果都一样。

2. 其它特征和杂项

2.1. 数学特征

Velocity 有一些内建的数学功能,可以使用set指令用在模版中。下面的共识分别演示了加减乘除运算:

#set( $foo = $bar + 3 )

#set( $foo = $bar - 4 )

#set( $foo = $bar * 6 )

#set( $foo = $bar / 2 )



当进行除法运算时,结果将会是整数。When a division operation is performed, the result will be an integer. 余数则可以通过模(%)运算获得。

#set( $foo = $bar % 5 )



在Velocity 中,只有整数可以进行数学运算;如果执行非整数的数学运算,将被记录下来,并返回null 。

2.2. 范围操作符

范围操作符可以和#set 和#foreach 语句一起使用。有助于产生一个整数的目标数组,范围操作符有以下的结构:

[n..m]






作者: yhy272711697


声明: 本文系JavaEye网站发布的原创文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!




已有 0 人发表回复,猛击->>这里<<-参与讨论





JavaEye推荐






"

2010年7月29日星期四

rails guy小抄大全

rails guy小抄大全: " 昨晚燕子在群里(燕子讓我多推廣我們群)問我有沒有關于rails學習的常用技術列表,我發現不知道怎么回答...然后他貼了份Hooopo發給他的給我看....看了下(其實只有標題),發現自己不能自已的想去擴充它...具體做法就是在每一項下面,加上一些快速應用指南..于是有了這個貼..(BTW,這個貼里只是個人看法,某些貼你覺得沒用,不看便是...請勿罵車車..)



為了方便閱讀,先奉上傳說中的神貼,據說行內幾乎每個人收藏夾里都有這個神貼,看看吧..

引用




收藏好上面的神貼,可以看看rails guy的小抄了..



*ruby

(1)基礎語法篇

Ruby 入門 第一次就上手

http://ihower.tw/blog/archives/3201

ffm:當時看的時候就覺得以前算白搞了...



for循环与each的区别(-->認真看回復)

http://www.letrails.cn/archives/difference-between-for-loop-and-each/



Ruby技巧3则

http://www.letrails.cn/archives/3-ruby-tips/



and && or ||

http://hi.baidu.com/kenrome/blog/item/dedd2f973535046054fb96ad.html



每天一条Ruby小道之Symbol

http://www.javaeye.com/topic/109697



玩转闭包(Block,Proc,lambda)

http://www.javaeye.com/topic/350992



alias,alias_method和 alias_method_chain

http://yuan.javaeye.com/blog/550156



Ruby的include和 extend

http://vincent253.javaeye.com/blog/135213



Ruby中的%表示法(百分号表示法)

http://www.javaeye.com/topic/440195



Ruby Tricks 大全

http://www.javaeye.com/topic/414412



如何寫出有效率的 Ruby Code

http://ihower.tw/blog/archives/1691



获取ruby运行的操作系统版本

http://www.javaeye.com/topic/160756



ruby way之IO之一(這里有一座小墳,自己挖挖吧)

http://simohayha.javaeye.com/blog/153398



欢迎大家贴出自己认为优雅简约的ruby代码

http://www.javaeye.com/topic/400501

ffm:看到名稱你就該知道這個是什么貼了...標準的內涵貼..



ruby动态编程

http://www.javaeye.com/topic/375531



相信看完上面的東西后,ruby語法算基礎入門了...接下來看些有意思的算法吧..



(2)算法篇

用Ruby玩算法:冒泡排序

http://samsam.javaeye.com/blog/316645



Ruby玩算法:汉诺塔

http://samsam.javaeye.com/blog/337417



用Ruby玩算法:插入排序

http://samsam.javaeye.com/blog/317394



最҉近҉流҉行҉菊҉花҉文.҉.҉.҉

http://www.javaeye.com/topic/377628

ffm:這個東西出自群里的Hooopo



各种排序的Ruby实现

http://www.javaeye.com/topic/280891



對于ruby算法方面的東西,由于本人能力一般,歡迎大家也貼出你們的算法貼來..接下來,看實際應用篇吧..



(3)實操篇

Ruby 錦囊妙計

http://ihower.tw/training/ruby-library.html

ffm:列舉了各種用法,可以作為使用參考



飞信的ruby gem──rfetion(這個是關于飛信應用的問題...)

http://www.javaeye.com/topic/470756



引用


Ruby转Exe -- Exerb研究(轉成exe這個需求,還算有人有興趣的吧)

http://jimmykuu.javaeye.com/blog/51526

OCRA

http://www.javaeye.com/topic/418169







ruby_parser 1.0:Ruby语言实现的Ruby语法分析器

http://www.infoq.com/cn/news/2008/01/ruby_ruby_parser



引用
HTML Entities for Ruby

http://htmlentities.rubyforge.org/

ruby处理中文URL的办法

http://www.javaeye.com/topic/250355




Try() 和 Maybe Monad

http://www.javaeye.com/topic/169001



UTF8编码和正则表达式

http://www.javaeye.com/topic/369753



ruby文件操作大全

http://www.javaeye.com/topic/517410

ffm:樣式是丑了點,不過的確很詳細..



将常用功能插件化 - 提高开发效率

http://www.javaeye.com/topic/448235



Designing Ruby APIs

http://www.slideshare.net/ihower/designing-ruby-apis



*rails

rails入门索引

http://fireflyman.javaeye.com/blog/708542



Rails版本变迁历程

http://fireflyman.javaeye.com/blog/694335



ffm:上面兩個貼都是我收集資料寫的,我覺得搞完rails也就差不多清楚什么回事了..至于更高級的應用,那不存在于任何blog里,只有實踐才是檢驗rails的唯一標準.





*memcache

Memcached 协议中英文对照

http://blog.s135.com/book/memcached/



漫谈应用缓存的命中率问题

http://www.javaeye.com/topic/78234



扩展Tomcat 6.x,使用memcached存放session信息

http://www.javaeye.com/topic/81641



MemCached Cache Java Client封装优化历程

http://www.javaeye.com/topic/246729



分布式缓存系统Memcached学习心得

http://www.javaeye.com/topic/208981



memcached for win32

http://www.javaeye.com/topic/24505



Memcached 学习笔记一

http://www.javaeye.com/topic/264010



Yes, there is a hash in the sky

http://hooopo.javaeye.com/blog/582496



*mysql

ffm:這個沒啥好說的..



mysql常用命令

http://jyangzi5.javaeye.com/blog/691513



MySQL数据库操作实战

http://www.javaeye.com/topic/251307



*nginx

Nginx安装

http://www.weekface.info/2010/05/20/nginx



服务器系统架构分析日志

http://www.sudone.com



Nginx+Thin+Rails部署

http://www.weekface.info/2010/05/30/linux-ginx-thin-rails-ruby-rake



nginx+mongrel cluster配置指南

http://www.javaeye.com/wiki/rails_deployment/1264-nginx-mongrel-cluster-configuration-guide



nginx詳細指南(詳細參考附件)





*HTTP協議

HTTP协议

http://fireflyman.javaeye.com/blog/722274

ffm:是從其它地方抄來的貼,目前還沒發布..等什么時候資料夠了,再發..有興趣的可以私下聯系..



HTTP Cache 学习

http://wuhua.javaeye.com/blog/400368



HTTP header中的 Cache-control

http://letle.javaeye.com/blog/236018



MIME类型-服务端验证上传文件的类型

http://www.javaeye.com/topic/244016



*rack

ffm:相信下面的資料足夠你掌握rack了吧...



深入Rails2.3 Rack

http://www.javaeye.com/topic/461012



一篇Rack的文章

http://www.javaeye.com/topic/605707



用Rack追踪服务器端性能rack-speedtracer

http://chinaonrails.com/topic/view/4210.html



*rake

ffm:本人水平有限,只能貼些基本使用



我的第一关rake文件

http://www.javaeye.com/topic/126309



rake任務詳解

http://fireflyman.javaeye.com/blog/719362



用 Rake 自动执行任务

http://www.javaeye.com/topic/29857



rake 对数据库操作深度示例说明

http://hlee.javaeye.com/blog/380928



*jquery

有用的jQuery插件Accordion

http://www.lycom.de/past/2008/6/30/jquery-2008-07-04/



集成jQuery到Rails软件

http://www.lycom.de/past/2008/6/29/jquery-2008-07-04-001828/



jQuery

http://cn.asciicasts.com/episodes/136-jquery



模拟alert对话框,N秒不点击自动关闭(基于jQuery模式对话框)

http://hooopo.javaeye.com/blog/541116



JQuery笔记

http://hooopo.javaeye.com/blog/472385



*JS

ffm:對于javascript我并不擅長,因此只找到下面一些入門貼..



javascript面向对象技术基础(一)

http://sdcyst.javaeye.com/blog/287882



javascript面向对象技术基础(二)

http://www.javaeye.com/topic/288159



javascript面向对象技术基础(三)

http://www.javaeye.com/topic/288397



javascript面向对象技术基础(四)

http://sdcyst.javaeye.com/blog/288808



javascript总结(一)有关框架

http://www.javaeye.com/topic/625734



js图片轮换效果(一)

http://www.javaeye.com/topic/294668#814814



*CSS

雖然我很想大大聲的說,頁面設計管我鳥事啊..找美工去...但據我所知,很多rails guy都是蛋疼的天使---(木有美工)



彻底弄懂CSS盒子模式

http://www.blueidea.com/tech/web/2007/4545.asp



CSS布局大全:40多个教程,提示,例子和最佳实践

http://www.javaeye.com/news/3053

120个非常优秀的CSS水平导航菜单

http://www.javaeye.com/news/16874

深入 CSS 行高
http://isd.tencent.com/?p=1503

泛泛而谈界面中的斑马纹设计
http://ucdchina.com/snap/7342

*linux

25+ 实用的Linux和Unix手册

http://www.javaeye.com/news/11049-25-linux-unix

ffm:不解析...

作者: fireflyman

"

2010年7月28日星期三

打败 IE 的葵花宝典:CSS Bug Table

打败 IE 的葵花宝典:CSS Bug Table

Alipay UED发表于2010-07-28 20:21:02

作为一名前端,我们通常要做的就是让页面在各系统A-Grade浏览器,甚至网站浏览份额0.1%以上的浏览器上良好显示。当然,还有性能问题。不过,今天要说的是样式的兼容问题。在IE/Mozilla/Webkit/Opera四分天下的今天,IE6-9/Mozilla(Gecko)系列/Chrome/Safari/Opera etc. 这些浏览器的兼容,无不让前端们头痛。而在这之中,最让人头痛的当数IE,特别是IE6。搞定了IE6,基本也就能称霸半个江山了。搞定了IE,也相当于占领了7、80%的领地。你想做一个统治页面兼容的主么?反正我是想的。

今天,趁着想完美公司的内部样式框架,把HasLayout.net的IE CSS Bug过了一遍。整理中收获了不少东西,一些官方的不足,也根据自己的知识升级了一下。当然,也顺利地升级了框架的一些内容,感觉甚爽。随后,便将一些值得去看的Bug整理成一个列表,基于Alipay前端伟大的分享精神,分享出来以供团队工友们和大家参考。

同时,由于整理仓促,有些理解和表达不当和其他纰漏在所难免,还请大家帮忙更正。谢谢。

问题浏览器DEMO解决方法
Hacking Rules:
property:all-ie\9; property:gte-ie8\0;*property:lte-ie7; +property:ie7; _property:ie6;
1input[button | submit] 不能用 margin:0 auto; 居中IE8bug | fixed为input添加width
2body{overflow:hidden;}没有去掉滚动条IE6/7bug | fixed设置html{overflow:hidden;}
3hasLayout的标签拥有高度IE6/7bug | fixed*height:0;
_overflow:hidden;
4form>[hasLayout]元素有margin-left时,子元素中的[input | textarea] 出现2×margin-leftIE6/7bug | fixedform > [hasLayout 元素]{margin-left:宽度;}
form div{*margin-left:宽度÷2;}
5当border-width有1条<边3条时被设置成dotted时,1px的边dotted显示成dashedIE7bug | fixed不在同一个元素上使用不同宽度的 dotted
6当子元素有position:relative的时候,父元素设置overflow:[hidden|auto]相当于给子元素设置了position:visible;IE6/7bug | fixed给父元素设置position:relative;
7:hover伪类不能改变有position:absolute的子级元素的left/top值IE7bug | fixed把top/left的值设置成除0%外的所有百分值;或添加一个margin-[所有方向]除0外的所有值,包括0%
8:focus + selector {} 选择器失效IE8bug | fixed在失效选择器后面添加一个空选择器, :focus{}
9列表中混乱的浮动:在list中浮动图片时,图片出现溢出正常位置;或没有list-styleIE8bug | fixed用背景图片替换list-style
10th 不会自动继承上级元素的 text-alignIE8bug | fixed给th添加text-align:inherit; (base.css中已包含)
11样式(包括link/style/@import(link)) 最多允许个为是:32IE6-8─ 常识99.99%的情况下,不会遇到
12:hover 时若background-color为#fff, 失效IE7bug | fixed把background-color改成background。或者,非#fff || #ffffff
13忽略’>’后有注释的选择器:selector> /**/ selector{}IE6bug | fixed[官方误判] 这个bug是IE6 BUG
14* htmlIE6─ HACK只对IE6有效
15PNG图片中的颜色和背景颜色的值相同,但显示不同IE6-7bug | fixed利用 pngcrush 去除图片中的 Gamma profiles
16margin:0 auto; 不能让block元素水平居中IE6-8bug | fixed给block元素添加一个width
17使用伪类 :first-line | :first-letter, 属性的值中出现!important 会使属性失效IE8bug | fixed!important is evil, don’t use it anymore
18:first-letter 失效IE6bug | fixed把 :first-letter 移到离{}最近的地方,如 h1, p:first-letter{},而非 p:first-letter h1{}
19Position:absolute元素中,a display:block, 在非:hover时只有文本可点击IE6/7bug | fixed给a添加background, 如果背景透明,使用background:url(‘任何页面中已经缓存的文件链接’),不推荐background:url(#)[官方的解决方法],因为会增加一下HTTP请求
20float列表元素不水平对齐:li不设置float,a设置display:block;float:[方向],li不水平对齐IE6/7bug | fixed给li设置display:inline 或 float:[方向]
21dt, dd, li 背景失效IE6bug | fixeddt, dd, li{position:relative;} (base.css中已包含)
22IE6-8bug | fixed利用js给
23使用filter处理的透明背景图片的透明部分不可点IE6-8bug | fixed把background:none变成background:url(‘链接’),链接到本身和图片之外的任何文件
24li内元素偏离 baseline 向下拉IE8bug | fixed给li设置display:inline 或 float:[方向]
25列表中li的list-style不显示IE6/7bug | fixed给li添加margin-left,留空间来显示(不要加在ul上)
26图片不能垂直居中IE6/7bug/fixed添加一个空标签,并赋给”Layout”, 比如display:inline-block;
27不能自定义指针样式IE6-8bug | fixed给指针文件设置绝对路径
28背景溢出,拖动滚动条后显示正常IE6bug | fixed给父元素添加overflow:hidden防止溢出,并赋予hasLayout,如果添加_zoom:1;
29高度超过height定义的高IE6bug/fixed添加_overflow:hidden;(推荐)或者_font-size:0;
30宽度超过width定义的宽IE6bug/fixed添加_overflow:hidden; 或使用alice v3 中的 .sl-word-break 类(table用.sl-table-break)
31双倍边距IE6─ 常识添加display:inline到float元素中
32margin负值隐藏:hasLayout的父元素内的非hasLayout元素,使用负边距时,超出父元素部分不可见IE6/7bug/fixed去掉父元素的hasLayout;或者赋hasLayout给子元素,并添加position:relative;
33给两个浮动元素的某中一个的文字设定为斜体,另一个元素下拉在有斜体文字元素的下面IE6bug/fixed给有斜体文字的元素添加overflow:hidden;
353px 间隔:在float元素后的元素,会有3px间隔IE6bug/fixed因为是确切的3px,所以,用“暴力破解”吧,比如_margin-left:-3px;
35text-align 影响块级元素IE6/7bug/fixed整理你的float;或者分开设置text-align







































































































































































































































































问题浏览器DEMO解决方法

Hacking Rules:

property:all-ie\9; property:gte-ie8\0;*property:lte-ie7; +property:ie7; _property:ie6;
1input[button | submit] 不能用 margin:0 auto; 居中IE8bug | fixed为input添加width
2body{overflow:hidden;}没有去掉滚动条IE6/7bug | fixed设置html{overflow:hidden;}
3hasLayout的标签拥有高度IE6/7bug | fixed*height:0;
_overflow:hidden;
4form>[hasLayout]元素有margin-left时,子元素中的[input | textarea] 出现2×margin-leftIE6/7bug | fixedform > [hasLayout 元素]{margin-left:宽度;}
form div{*margin-left:宽度÷2;}
5当border-width有1条<边3条时被设置成dotted时,1px的边dotted显示成dashedIE7bug | fixed不在同一个元素上使用不同宽度的 dotted
6当子元素有position:relative的时候,父元素设置overflow:[hidden|auto]相当于给子元素设置了position:visible;IE6/7bug | fixed给父元素设置position:relative;
7:hover伪类不能改变有position:absolute的子级元素的left/top值IE7bug | fixed把top/left的值设置成除0%外的所有百分值;或添加一个margin-[所有方向]除0外的所有值,包括0%
8:focus + selector {} 选择器失效IE8bug | fixed在失效选择器后面添加一个空选择器, :focus{}
9列表中混乱的浮动:在list中浮动图片时,图片出现溢出正常位置;或没有list-styleIE8bug | fixed用背景图片替换list-style
10th 不会自动继承上级元素的 text-alignIE8bug | fixed给th添加text-align:inherit; (base.css中已包含)
11样式(包括link/style/@import(link)) 最多允许个为是:32IE6-8─ 常识99.99%的情况下,不会遇到
12:hover 时若background-color为#fff, 失效IE7bug | fixed把background-color改成background。或者,非#fff || #ffffff
13忽略’>’后有注释的选择器:selector> /**/ selector{}IE6bug | fixed[官方误判] 这个bug是IE6 BUG
14* htmlIE6─ HACK只对IE6有效
15PNG图片中的颜色和背景颜色的值相同,但显示不同IE6-7bug | fixed利用 pngcrush 去除图片中的 Gamma profiles
16margin:0 auto; 不能让block元素水平居中IE6-8bug | fixed给block元素添加一个width
17使用伪类 :first-line | :first-letter, 属性的值中出现!important 会使属性失效IE8bug | fixed!important is evil, don’t use it anymore
18:first-letter 失效IE6bug | fixed把 :first-letter 移到离{}最近的地方,如 h1, p:first-letter{},而非 p:first-letter h1{}
19Position:absolute元素中,a display:block, 在非:hover时只有文本可点击IE6/7bug | fixed给a添加background, 如果背景透明,使用background:url(‘任何页面中已经缓存的文件链接’),不推荐background:url(#)[官方的解决方法],因为会增加一下HTTP请求
20float列表元素不水平对齐:li不设置float,a设置display:block;float:[方向],li不水平对齐IE6/7bug | fixed给li设置display:inline 或 float:[方向]
21dt, dd, li 背景失效IE6bug | fixeddt, dd, li{position:relative;} (base.css中已包含)
22<noscript />元素的样式在启用javascript的情况下显示了样式IE6-8bug | fixed利用js给<noscript />添加display:none;
23使用filter处理的透明背景图片的透明部分不可点IE6-8bug | fixed把background:none变成background:url(‘链接’),链接到本身和图片之外的任何文件
24li内元素偏离 baseline 向下拉IE8bug | fixed给li设置display:inline 或 float:[方向]
25列表中li的list-style不显示IE6/7bug | fixed给li添加margin-left,留空间来显示(不要加在ul上)
26图片不能垂直居中IE6/7bug/fixed添加一个空标签,并赋给”Layout”, 比如display:inline-block;
27不能自定义指针样式IE6-8bug | fixed给指针文件设置绝对路径
28背景溢出,拖动滚动条后显示正常IE6bug | fixed给父元素添加overflow:hidden防止溢出,并赋予hasLayout,如果添加_zoom:1;
29高度超过height定义的高IE6bug/fixed添加_overflow:hidden;(推荐)或者_font-size:0;
30宽度超过width定义的宽IE6bug/fixed添加_overflow:hidden; 或使用alice v3 中的 .sl-word-break 类(table用.sl-table-break)
31双倍边距IE6─ 常识添加display:inline到float元素中
32margin负值隐藏:hasLayout的父元素内的非hasLayout元素,使用负边距时,超出父元素部分不可见IE6/7bug/fixed去掉父元素的hasLayout;或者赋hasLayout给子元素,并添加position:relative;
33给两个浮动元素的某中一个的文字设定为斜体,另一个元素下拉在有斜体文字元素的下面IE6bug/fixed给有斜体文字的元素添加overflow:hidden;
353px 间隔:在float元素后的元素,会有3px间隔IE6bug/fixed因为是确切的3px,所以,用“暴力破解”吧,比如_margin-left:-3px;
35text-align 影响块级元素IE6/7bug/fixed整理你的float;或者分开设置text-align

JS 常用继承实现方式

JS 常用继承实现方式: "

标签: 继承

看《JavaScript 设计模式》,关于里面提到的JS继承实现的方式,分为三种,且书中都给出了相关实现。这里也不再做讲解,只求记录一下,因为自己总是有时候会忘记这些东西。



  1. 类式继承,extend
  2. 原型式继承,clone
  3. 掺元类继承,augment

类式继承的实现,这里面很有必要引人注意的是,superclass.prototype.constructor = superclass; 而且实现空实例要省很多资源。


如果还想调用类里面的方法,而非其原型对象的方法,可以使用call函数或者apply函数,这里不再缀述。



function extend(subClass, superClass) {
var F = function() {};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;

subClass.superclass = superClass.prototype;
if(superClass.prototype.constructor == Object.prototype.constructor) {
superClass.prototype.constructor = superClass;
}
}

原型继承相对看起来可能要晕一些,此种方式继承适用于非函数式对象,字面直接量这种方式的继承实现。因为看函数名就能看出来,实现的是对象的克隆,那么当然最简单的方法就是将对象设置成一个空对象的原型。然后再将这个空对象返回。



function clone(object) {
function F() {}
F.prototype = object;
return new F;
}

掺元类的方式适用于那些子类与父类之间关系不大,只是单纯的想通过子类调用其父类的方法,把有用的方法继承过来。



function augment(receivingClass, givingClass) {
if(arguments[2]) { // Only give certain methods.
for(var i = 2, len = arguments.length; i < len; i++) {
receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
}
}
else { // Give all methods.
for(methodName in givingClass.prototype) {
if(!receivingClass.prototype[methodName]) {
receivingClass.prototype[methodName] = givingClass.prototype[methodName];
}
}
}
}

您可能还对下面的文章感兴趣:


  1. 再论Javascript的类继承 [2010-06-20 23:46:10]
  2. Javascript面向对象编程(三):非函数对象的继承 [2010-05-25 13:28:44]
  3. Javascript面向对象编程(二):继承 [2010-05-24 09:46:15]
  4. C++ 中的接口继承与实现继承 [2010-02-23 22:09:41]

"

三谈Iframe自适应高度

三谈Iframe自适应高度: "

标签: iframe 跨域 自适应

为什么是三谈



为什么是三谈呢?一是因为这真的是一个被说烂的话题,二是因为太师傅在n年前就写过这篇再谈iframe自适应高度。之所以再提该问题,一是因为之前项目中确实遇到了这个问题的方方面面,有必要总结一下,二是因为师傅的“威逼利诱”。希望对各位有帮助,有错误请指正。


同域、子页面高度不会动态增加



这种情况最简单,直接通过脚本获取字页面实际高度,修改iframe元素高度即可。但有二点必须注意:



  1. 如果页面内有绝对定位或者没有清浮动的元素,情况有些复杂,不同浏览器处理结果不同,甚至包括Webkit内核的浏览器,具体请看这个Demo。所以你要么进行浏览器检测,要么用Math.max计算一个最大值,要么你想别的方法。
  2. iframe所包含页面可能非常大,需要很长的加载时间,为此直接计算高度的时候,很可能页面还没下载完,高度计算就会有问题。所以最好在iframeonload事件中计算高度。这里还要注意的是,IE下必须使用微软事件模型obj.attachEvent来绑定onload事件。而别的浏览器直接obj.onload = function(){}也可以。


以下是代码片段:
(function(){
var frame = document.getElementById("frame_content_parent"),
setIframeHeight = function(){
var frameContent = frame.contentWindow.document,
frameHeight = Math.max(frameContent.body.scrollHeight,frameContent.documentElement.scrollHeight);

frame.height = frameHeight;
};
if(frame.addEventListener){
frame.addEventListener("load",setIframeHeight,false);
}else{
frame.attachEvent("onload",setIframeHeight);
}
})();



同域、子页面高度会动态增加



原理与第一种情况一样,多一个计时器,一直检测字页面高度,当子页面高度和iframe的高度不一致时,重新设置iframe的高度。这边也可以加一个try在js出错时,加一个足够的高度。




以下是代码片段:
(function(){
var _reSetIframe = function(){
var frame = document.getElementById("frame_content_parent")
try {
var frameContent = frame.contentWindow.document,
bodyHeight = Math.max(frameContent.body.scrollHeight,frameContent.documentElement.scrollHeight);
if (bodyHeight != frame.height){
frame.height = bodyHeight;
}
}
catch(ex) {
frame.height = 1800;
}
}
if(frame.addEventListener){
frame.addEventListener("load",function(){setInterval(_reSetIframe,200);},false);
}else{
frame.attachEvent("onload",function(){setInterval(_reSetIframe,200);});
}
})();



同域、子页面高度会动态增加、脚本可能完全失效



第二个例子中,考虑到了脚本出错的情况,但是万一脚本根本不执行了呢,那iframe中的内容就会因为iframe的高度不够而显示不了。为此我们通常事先设置一个足够的高度,为了前端控制方便,我觉得写在CSS文件中比较合适,需要修改时只改CSS就行了。这里我设置了selector{ height:1800px; }。需要注意的是,写在样式表里的样式,不能直接用node.style[property]来取,对于微软模型,要用node.currentStyle[property](题外话:悲剧的IE模型不支持CSS伪类),对于W3C模型,要用window.getComputedStyle(node,null)[property]来取。我这里图方便直接用了YUI。


这里又有一个问题,设置iframe的高度大于其包含页面的高度时,各个浏览器的处理不一样。例如在Firefox下,必须计算body元素的高度,而html元素的高度等于iframe的高度,然而当恰巧这个页面又有绝对定位未清浮动元素时,又不能通过body元素来取,显然第一种方法缺点更小一些。具体请看这个Demo


从上面这个Demo可以看到,除IE浏览器外,别的浏览器计算出来的都是iframe的高度,即CSS里设置的#frame_content_parent{ height:1800px; }。而IE计算出来的是iframe所引用页面的实际高度。



以下是代码片段:

#frame_content_parent{ height:1800px; }


(function(){
var $ = YAHOO.util.Dom,
frame = $.get("frame_content_parent");
function reSetIframe(){
var frameContent = frame.contentWindow.document,
bodyHeight = Math.max(frameContent.documentElement.scrollHeight,frameContent.body.scrollHeight);
if (bodyHeight != $.getStyle(frame, "height")){
$.setStyle(frame, "height", bodyHeight + "px");
}
}
if(frame){
$.setStyle(frame,"height","auto");
setInterval(reSetIframe,300);
}
})();



跨域



这里提供一个Iframe代理的方法,简单地说一下原理。假设有3个页面,分别是主页面A.html,字页面B.html,代理页面C.html。其中A与B是跨域的,而A和C是同域的。它们的关系:A包含B,B包含C。很显然A和B,以及B和C,因为跨域不能相互通信,而A和C同域,可以相互通信。为此我们就想到让C页面告诉A页面,B页面到底有多少高。因为B和C也是跨域的不能相互通信,所以想在C页面中,直接window.parent.document.body.scrollHeight这样是行不通的,所以我们只能让B页面自己计算自身的高度,然后通过某种方法告诉C页面,再由C页面告诉A页面。这里的一个方法就是在B页面生成一个Iframe节点,然后设置它的src属性,在这个地址上附加一个参数,即B页面计算出来的高度,然后C页面就可以通过window.location获取这个地址栏中的地址,提取出高度值,通过window.top找到A页面,设置A页面的Iframe的高度。基本的原理就是这样,看代码吧:


DEMO





以下是代码片段:
//B页面脚本
//任务:计算其实际高度,然后生成一个iframe节点,将高度作为代理页面C的地址的一部分赋值给Src属性
(function(){
var agent_iframe = document.createElement("iframe"),
b_height = Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);
agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe_once.html#" + b_height;
document.body.appendChild(agent_iframe);
agent_iframe.style.display = "none";
})();


//C页面脚本
//任务:获取请求地址中的高度值,将其赋值给A页面的Iframe的高度
window.top.document.getElementById("frame_content_parent").height = parseInt(window.location.hash.substring(1),10);



跨域、字页面高度动态变化



这里结合了第2、第4两种方法,我的想法是在B页面通过一个计时器,不停计算B页面的高度,一但变化,马上修改iframe标签的src属性,而C页面也有计时器不断监听src的变化,改变Aiframe标签的高度。需要注意的是仅仅修改src属性后面的锚点值(如“#1234”),页面并不会刷新,不会重新请求,这也是在C页面增加计时器的原因。


DEMO



以下是代码片段:

//B页面脚本
(function(){
var getHeight = function(){
return Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);
};

var preHeight = getHeight(),
agent_iframe;

var createIframe = function(height){
agent_iframe = document.createElement("iframe");
agent_iframe.style.height = "0";
agent_iframe.style.width = "0";
agent_iframe.style.border = "none";
agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html#" + height;
document.body.appendChild(agent_iframe);
}

createIframe(preHeight);

var checkHeight = function(){
var currentHeight = getHeight();
if(currentHeight != preHeight){
agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html#" + currentHeight;
preHeight = currentHeight;
}
setTimeout(checkHeight,500);
}

setTimeout(checkHeight,500);
})();


//C页面脚本
(function(){
var preHeight = parseInt(window.location.hash.substring(1),10),
ifrmae = window.top.document.getElementById("frame_content_parent");

ifrmae.height = preHeight;
setInterval(function(){
var newHeight = parseInt(window.location.hash.substring(1),10);
if (newHeight !== preHeight){
ifrmae.height = newHeight;
preHeight = newHeight;
}
},500);
})();




这里还有另一种方案,就是让iframe每一次都重新请求,这样C页面就不需要计时器了,但是如果2次计算高度重复的话,就会导致src属性的值相同,这样浏览器就很可能不重新请求该页面了,那么C页面中的脚本也就不运行了。要修复这个问题很简单,只要在每次计算出来的src属性上增加一个随机数的参数就行了。比如http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html?temp=123123423712937#1563




//B页面关键脚本
以下是代码片段:
agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html?a=" + Math.random() + "#" + currentHeight;




//C页面脚本
以下是代码片段:
window.top.document.getElementById("frame_content_parent").height = parseInt(window.location.hash.substring(1),10);



您可能还对下面的文章感兴趣:


  1. 一个兼容多种场合的Javascript图片大小自适应function [2010-03-31 09:24:22]
  2. 自适应圆角 [2009-11-22 20:50:44]

"

2010年7月27日星期二

JS对话框组件 artDialog

JS对话框组件 artDialog: "

artDialog是一个轻巧且高度兼容的javascript对话框组件,可让你的网页交互拥有桌面软件般的用户体验。

功能: 支持锁定屏幕(遮罩)、模拟alert和confirm、多窗口弹出、静止定位、支持Ese键关闭对话框、定时关闭、自定义位置、拖动、鼠标调节窗口大小、换肤……
"

2010年7月26日星期一

JMeter技巧集锦

JMeter技巧集锦

收藏些介绍JMeter使用知识的文章

1.JMeter技巧集锦

http://www.javaworld.com/javaworld/jw-07-2005/jw-0711-jmeter.html

(网上该篇的中文译文)

2.JMeter高级技巧

http://www.informit.com/guides/content.aspx?g=java&seqNum=520

3.使用 JMeter 完成常用的压力测试

http://www.ibm.com/developerworks/cn/opensource/os-pressiontest/index.html?ca=drs-

程序员高薪的秘诀

程序员高薪的秘诀

一、程序员高薪的秘诀
无非一个:机遇+经验+灵感。
程序员的薪资与所用语言关系不大,并且高薪的程序员的学历也参差不齐,而从业的时间和业绩更大程度上影响了程序员所能得到的待遇,如下表所示
年限
月薪
0
800-3000
2
3000-6000
3
5000-15000
4年以上
6000-40000
一个合格的程序员应当具有敬业、灵活、创新、博学等全面优秀的素质。很多程序员抱怨自己待遇不公,但往往忽略了自身的因素,首先程序员在要求月薪之前,就应当首先考虑自己在所在的企业的位置,自己的能力专长是否正是该企业所需要的,能给企业带来多少产出。当然,初入行业时,也许会因为管理的因素造成不公的待遇,但是当逐渐融入工作之后,对企业以及环境有了一定的了解,就可以根据自己的实际情况理直气壮地提出要求。同时,由于软件行业的变动很大,程序员跳槽或“下课”是常有是事,有时候一些工作岗位也不能只注重它的薪酬多少,关键是看自己能够得到多大的提高与发展,某些时候,低薪但富有挑战力的工作也不失为开拓自己以后道路的跳板。
一个小网络公司的招聘广告:
招聘程序员,要求熟练掌握 VC、 VB、JAVA脚本、 SQLServer、 Access、 月薪800-1500、 包食宿。
二、程序员的报酬有几种方式:

1、传统的月薪或年薪+奖金
追求稳定的程序员可以选择基础好的企业以薪金谋生,并求稳步发展。
2、期权方式
有创业精神的则可以选择有发展前景的企业或团队,获得效益分享,期权曾经造就了不少程序员暴富的神话,但其风险也比较大。
3、临时工
只做一两个项目,做完走人,按项目获取相应酬劳。

三、软件公司对软件开发人员的资源分配
1、传统意义的软件公司??大公司
一般有明确的分工,各个流程或模块由不同的程序员完成。也许你是相当优秀并且知识是相当全面的,但是实际上的工作当中并不需要你做超出范围的事情,工作一般比较单一,同时也能得到稳定的收入。
2、作坊式的软件公司??小公司
一个技术人员通常要完成更多方面的工作,诸如需求分析、系统设计、详细设计、编写代码、软件测试、撰写文档、安装调试、系统维护等,这些工作通常会混在一起,而不是按照什么软件工程的顺序来完成。

注: 在从创业的趣味性来说,有的程序员会更加喜欢后者,但是这同时也要考虑到薪酬的分配是否合理,自己所付出的劳动是否得到了应有的回报。

四、将自己改造成为一个复合型人才

具备多种能力和素质,并能够将多种能力进行综合运用
1、软件开发的技能水平
(1)、对使用的开发工具要了解透彻;
(2)、对使用的开发语言要熟练和精通。
2、应用行业的了解程度
(1)、对应用行业方面的知识要了解;
(2)、对应用行业的运作模式要了解。
3、软件开发技术知识与行业知识的结合
(1)、将行业中的管理流程进行转化,用计算机代替手工;
(2)、在转化过程中不断提高程序开发的水平。
注:仅仅只会计算机的程序员是不可能适合这些专业性极强的行业的,对特殊行业本身有深刻了解的程序员到这些部门肯定会大受欢迎
五、软件企业要求基础软件工程师具备六大基本素质
1、良好的编码能力
软件人员的一个重要职责是把用户的需求功能用某种计算机语言予以实现。编码能力直接决定了项目开发的效率。
2、自觉的规范意识和团队精神
程序员分为两种,一种是程序“游击队员”,他们可能对编程工具很熟,能力很强,把编码编得很简洁高效,但却缺乏规范和合作的观念;另一种程序员编程不一定很快,但是很规范,个人能力不一定很强,但合作意识很好。
3、认识和运用数据库的能力
信息是以数据为中心的,因此与数据库的交互在所有软件中都是必不可少的,了解数据库操作和编程是软件工程师需要具备的基本素质之一。
4、较强的英语阅读和写作能力
编写程序开发文档和开发工具帮助文件离不开英文,了解业界的最新动向、阅读技术文章离不开英文,与世界各地编程高手交流、发布帮助请求同样离不开英文。
5、具有软件工程的概念
从项目需求分析开始到安装调试完毕,基础软件工程师都必须能清楚地理解和把握这些过程,并能胜任各种环节的具体工作
6、求知欲和进取心
软件工程师应具有较强的学习总结能力、需求理解能力和对IT新技术比较敏感,同时,掌握最新的IT实用技术。
六、必须掌握的开发方法
采用瀑布型和快速原型法结合的开发方法,
即:系统需求分析->开发方案设计->子系统实现->系统集成与确认下,
图为开发模型示意图
七、独立设计开发软件必须经过的九个过程
1、需求分析
从用户的业务中提取出软件系统能够帮助用户解决的业务问题,通过对用户业务问题的分析,规划出我们的软件产品。
A、 提取出核心、主要、急迫的业务,明晰业务流程
(1)针对客户对软件项目或产品的最初提出的需求目标和范围,为用户解决什么样的问题,从众多的业务中提取出用户核心的、主要的、急需的业务。
(2)从用户繁杂的业务中进行业务、业务流程的提取,把那些分布在各个部门的同一种业务提取出来。分析用户的这个业务流程中哪些是系统能帮助管理的,哪些是要在系统外处理的,充分分析用户现有的业务和业务流程。
B、 运用管理思想,优化业务流程
(1)采用网络计算机这些新的技术手段代替原先手工、电话等方式在信息的传递、信息的共享、数据的处理等方面将会带来新的方式,必将改变原有的业务流程。
(2)根据对用户业务的理解,考虑是否可以运用先进的管理思想,比如MRPII、ERP、JIT等等管理模型,进行现有业务流程的重组或优化。
制造资源计划管理系统(MRPⅡ)、企业资源计划管理系统(ERP)。
C、要求最终用户参与到项目的整个开发过程
一个软件项目在需求分析阶段时的信息收集非常重要,但由于每个企业的管理模式不同,企业内部各部门所需要的软件功能也不同,在收集信息时,公司高层提供的信息量为实现软件项目80%的内容,部门主管根据公司高层提出的要求进行理解能提供本部门80%的内容,具体岗位的工作人员根据主管提出的要求进行理解能够提供本岗位80%的内容,根据三方面收集到的信息能够在软件项目完成后实现预定目标的
100*0.8*0.8*0.8=51.2%,剩下的48.8%要经过很长时间,开发者与企业各部门之间进行协商,再原来80%的基础上提取出15%的信息100*0.95*0.95*0.95=94.12%,最后剩下的5.88%只能做为软件项目完工投入使用后的维护升级中进行解决
2、系统设计
A、 根据需求分析绘制出系统框架图和系统流程图
(1)、 系统框架图要体现出软件的整体架构;
(2)、 采用松散组合式设计,使各功能模块间即相互独立又可相互配合;
(3)、 系统流程图要体现出客户的业务流程;
(4)、系统框架就象人的骨架、系统流程就象人的神精、血液?环系统和肌肉
(5)、系统框架、流程的设计直接影响到软件的开发周期和最终产品的质量。
B、 制定项目实施计划
(1)、 项目总体需要多少时间、多少人、多少设备、多少钱;
(2)、 每个功能模块需要多少时间、多少人、多少钱;
(3)、 对每个功能模块的测试需要多少时间多少人、多少钱;
(4)、 培训需要多少时间、多少人、多少钱;
(5)、 软件过行后期维护需要多少人、多少钱;
3、详细设计
A、 根据系统框架图对每个功能模块进行分解设计;
B、 根据系统框架图绘制各功能模块的子框架图;
C、 根据系统流程图绘制各功能模块的子流程图;
D、 各子功能模块之间要做好数据接口;
E、 根据子框架和子流程设计数据字典;
F、 数据字典要结构设计合理,不合理的设计将给软件造成巨大的隐患;
Verify(用户信息及密码验证表)
序号主键字段名中文对照数据类型长度小数默认值允许空
1ID用户IDvarchar10  Not Null
2 password密码varchar72  Not Null
3 level等级varchar10  Not Null
4 name姓名varchar10  Not Null
5 station岗位varchar30  Not Null
6 dept部门varchar10  Not Null
System_Function(系统功能表)
序号主键字段名中文对照数据类型长度小数默认值允许空
1 akey主功能键varchar10  Not Null
2 bkey次功能键varchar10  Not Null
3mkmc模块名称varchar20  Not Null
4 id用户IDvarchar10  Null
5 enabled功能使用标记bit  0Null
6 imageurl功能图标名varchar30  Not Null
7 navigateurl功能文件名varchar30  Null
User_Purview(用户权限表)
序号主键字段名中文对照数据类型长度小数默认值允许空
1 akey主功能键varchar10  Not Null
2 bkey次功能键varchar10  Not Null
3mkmc模块名称varchar20  Not Null
4 id用户IDvarchar10  Null
5 enabled功能使用标记bit  0Null
6 imageurl功能图标名varchar30  Not Null
7 navigateurl功能文件名varchar30  Null
Dept(部门表)
序号主键字段名中文对照数据类型长度小数默认值允许空
1id部门IDvarchar10  Not Null
2 dept部门名称varchar10  Not Null
4、编写代码
A、 编写代码时要标准化、规范化;
B、 每行或每段代码要做出中文或英文注释;
C、 一个功能可实现的代码不要分解到两个功能模块中;
D、 前台定义数据名称要尽可能与后台数据库定义一致;
E、 重复使用的代码段要做到一个类中,以提高开发效率和软件运行效率;
F、程序界面各控件的布局摆放要符合人机工程,充分考虑到用户的需求,方便用户操作;
G、做好代码的防错和容错,在出现意外情况时要给出错误提示,以便用户找出解决问题的方法。
5、软件测试
A、 单个功能模块的独立测试,可以与编码同时进行;
B、 各个功能模块的整体配合测试,找出各模块接口出现的问题,并尽快加以解决。
C、 在软件测试中灵活运用逆向思维,找出软件中的错误,尽可能将可预知的错误在软件投入使用前解决掉;
D、负责测试的人员不能和代码编写人员是同一个人;
E、对测试的过程和结果要作好记录,以便以后出现问题时可以尽快找出解决的方法;

6、撰写文档
A、 对软件进行整体综合的描述;
B、 对软件各功能模块作出详细的使用说明;
C、 作好帮助索引,以方便用户可以尽快的找到答案;
D、 软件各功能模块要与帮助文档动态联接;
E、 帮助文档要尽可能的作到图文并茂,充分体现出软件
的功能和流程。
F、 帮助文档要尽可能的将程序运行过程中出现的错误作
出说明,并明确出解决问题的方法和手段。
7、安装调试
A、 软件开发完毕后要进行产品打包发布;
B、 要给软件安装运行作出详细的操作说明;
C、 做好软件与操作系统之间的配合;
8、人员培训
A、 软件在开发完毕后需要对最终用户进行操作培训;
B、 除了培训软件的基本操作外,还要指导用户在软件出
错时如何找到解决的方法;
C、最终用户的文化水平和业务水平各有不同,要根据用
户的接受理解能力来制定培训计划;
D、切记用户永远是对的,如果用户出现错误,那是培训不到位造成的,对用户提出的每一个问题要耐心的解答。
E、做好培训记录,以便在以后出现问题时明确责任。
9、系统维护
A、软件运行后会出现各种问题,这些问题在软件开发过程中是不可预知的;
B、对出现的问题要尽快加以解决,以满足客户的需求;
C、软件所以要设计成松散组合架构,给软件后期维护和升级提供了有利条件;
D、系统应具备动态数据备份与恢复功能,使用户可以随时对系统进行备份,在数据出现问题时可以将数据恢复到操作前的状态。
八、设计一套通用系统架构
1、程序加载;
2、程序登录验证;
3、用户密码更改;
4、主程序,包括系统菜单、工具栏、状态栏等;
5、系统用户管理;
6、系统用户使用权限分配;
7、系统功能管理;
8、系统备份与恢复;
9、重新登录和退出系统;
九、设计软件架构所需要运用的知识点

1、数据库操作:
包括数据库连接、对数据的增删改、存储过程的应用;
2、基本界面元素的使用:
包括标签、文本框、下拉列表框、进度条、工具栏、菜单、
状态栏、按钮、选项组、树控件、计时器、图象控件、
视图控件、页框、数据表格等
3、基本编程语言的使用:
包括变量、数组、判断语句、?环语句、 API函数、
错误提示语句、错误异常处理语句等
4、函数和类的设计
5、与办公软件集成应用:
包括对EXCL表格、WORD文档、文本文件的处理等