1月27日——培训第56天

今天发烧……今天netmeeting出问题……今天童小军想讲php却被张老师一票否决……田老师认为还是了解一下
php好一些,不能挑食,张老师怕大家因为童小军讲php会有想法,于是呢……这件事情就这么拖下来了,谁知道猴年马月讲呢,
只能希望今天自己脑子能够清醒一点,现在感觉自己好像有点烧糊涂了……
--------------------------------------------------------------------------------------
今天讲hibernate中的高级部分,比如实体间的继承组合、关系映射什么的,大概需要2、3天的时间,现在
大家的hibernate忘的都差不多了,复习一下……

两个比较主要的配置文件:(参照前面的笔记!)
1、连接哪个数据库:配置文件或是属性文件
2、实体映射到哪张表、属性和哪些字段对应:

创建一个实体后如何存呢?用save方法或是saveOrUpdate或是persist
它们的区别是什么呢?
区别:save是无论你的实体是什么样子的状态(游离、托管、持久),都会去将这个对象插入数据库,只要
session的缓存中没有这个对象就可以。动态的插入、动态的更新:默认的情况下把所有的属性都update、
但是动态的情况下会将对象的各属性去和缓存中的对象各属性去比较,如果不一样就更新!

saveOrUpdate:依据的是实体的主键的值跟unsaved-value是否一致,默认状态下unsaved-value是0,
如果和unsaved-value一致的话执行save操作,如果不一致的话执行update操作。

persist是去看主键、如果主键不等于unsaved-value的话,会抛出一个异常,不给你插入,临时状态和托管
状态的区别仅在于主键是不是和unsaved-value一致!

加载:load和get:load有延迟加载,返回的是实体的代理对象,不是实体本身。get不支持延迟加载。
不论get还是load,加载的时候都要提供主键、如果数据库中没有主键的话load也会给你加载进来,但是如果
是get的话,如果数据库中没有这条记录的话,会返回个空值。

游离状态:没有和session发生关系并且不对应数据库中的任何一条记录。
托管:session被关闭后的对象

更新可以使用update方法或是load->setter或是merge方法:
update:要求对象必须有主键,否则没办法使用update更新,并且要求这个主键必须在数据库中存在!!
  使用一个update对一个对象进行更新的时候,要确保对象有主键且主键在数据库中要存在!
load->setter:load进来之后再调用setter方法。update方法不支持动态更新,因为使用update更新
  的时候session中没有缓存,因为是创建完一个对象后直接update,而load->setter就支持动态
  更新,因为load进来之后缓存中就有对象了
merge:用于不确定数据库中是否存在该对象对应的某条记录的情况,如果存在就更新,不存在就save


删除:
delete

上面所有的增删改查都是对单一对象的操作。要是想批量的来或是别的什么要使用HQL、QBC、QBE

auto-import属性的使用……想让HQL执行需要Query,有以下办法可以执行:
list:
iterate:
两个方法的区别:list一次性的把所有记录都返回,iterate先取出所有的主键,迭代一次取出一条记录。
   如果数据量比较大的话应该使用iterate,缓解内存的压力;如果事先知道返回多少个记录、
   比如分页,我知道最多返回多少条记录,所以应该使用list方法

setFirstResult、setMaxResult用来执行分页(注意左边的字符书写可能有误)
如果你确信执行结果只有一个的话使用uniqueResult

还有一种方法叫做scrollResult,创建指针可以轮回的结果集

如果from一个类查询的话,那么找到的都是符合条件的类的实例对象,其中name是实体的属性名。如果我想
查类里面其中的一个属性的话:select name from user

那么返回的list里面是什么类型的对象呢?取决于name的类型,如果name是String类型的话,那么对象就是
String类型的……

如果我选择两个呢?select age,name from user
这时候返回的list集合里面存储的每一个对象是Object数组的类型!!如果你不喜欢这种类型的话,你可以new
一个map,然后存储。但是能否new一个set呢?答案是否定的,因为set里面不可以有重复的元素,但是两个人年龄
或是姓名可能是相同的,也就是元素完全有可能重复,所以不可以放在set里面!!

如果选取的是一个属性的话,集合当中的每一个对象的类型取决于属性的类型,如果属性是原始数据类型的话,返回
的必然是包装类!
----------------------------------
QBC:需要Creteria,一般情况下QBC和QBE不常用(把查询语句变成了面向对象编程的思想),常用的是HQL!!!
QBE里面最核心的是example模版的创建使用。
-----------------------------------

对单独对象的增删改查、弊病是必须知道主键,所以hibernate中增加了各种方法来解决这个问题。
HQL中能否进行插入、更新和删除??答案是肯定的,怎么做呢?应用的时候注意:如果使用HQL进行增删改的话,
不会影响session中的缓存,而是直接影响数据库。

三大块内容:
一、两个配置文件config和mapping文件
二、session中的众多方法的使用和区别
三、HQL语言的使用

上面三大块掌握了就可以了。

sessionFactory是重量级的,要求只有一个,session是轻量级的,要求线程安全,要求每个线程中只有
1个session。threadLocal实现了session线程安全,或者在配置文件中配置currentsessionContext(好像
是这个东西,它可以保证线程结束的时候给你自动的关闭session)

================================================================================
今天要讲的内容:在一个实体里面有集合,集合如何映射到数据库中??
例子:一个person有几本书、每个person具有的书的个数不一样,如何设计表?
或者人和他的头发的关系
又或者楼房和住家单元

楼要知道自己有哪些住家单元,楼没了单元也就没了。双方之间的这种生死相依的关系叫做聚集。

现在设计一个building类,类里面有个集合,
现在集合里面存储了单元的名字。

怎么设计表呢??

每个楼具有的单元数是不一样的,一般来说,只要在hibernate中有集合的映射,那么一定涉及两张表,
实际上是一对多的关系,一个楼对应多个单元,一个单元对应一个楼。

集合映射指的是值的映射,不是实体!如果楼这个类里面存储的是实体的集合,比如building里面的集合
放的是unit这个实体,这叫做实体集合的映射(也就是关系)。我们说的是值的映射,building里面存储
的是Arraylist,里面有很多String类型的单元名字,这叫做值的映射

在java中学了几种类型的集合??
List集合:有序、可以重复、可以通过序号找到
Set:无序,不可以有重复的元素在里面!!
Map:键值对

Hibernate中多了一个bag集合:元素无序、可重复
还有array类,也就是数组。

除了bag类集合外,其他集合均可以在java api中找到对应的接口!

实体里面有个集合,是以上几种之一,然后映射。

--------------------------------------------
先看看bag集合是如何做映射的:

当前的实体必然对应主表、也就是当前实体的主键必然是“一”的那一方。比如老师和学生。
每个学生持有一个外键指向老师。

bag中的key指的就是外键。比如老师的实体里面有学生名字的集合,必须知道students表中
谁是外键,根据外键对应主键。学生名字的集合中的每一个名字对应的是学生表中的哪一个字段
呢??所以必须要知道去哪一个表找,那个表中谁是外键,谁是集合中存储属性的对应字段。

element其实代表的就是查哪一个元素!

比如:
key代表的是外键,拿从表的外键对应主表的主键!这就是值集合映射!
<class name="Building" table="building">
    <id name="id">
      <generator class="native" />
    </id>
    <property name="height" column="height"/>
    <bag name="unitNames" table="unit" lazy="false" order-by="unit_id desc">
       <key column="building_id"/>
       <element column="unit_name" type="string"/>
    </bag>
  </class>
由于Java API中不存在Bag接口,所以Hibernate使用List模拟Bag,例如ArrayList、LinkedList等。

==============================================================================
今天下午一点上课,因为对门被盗,所以这边要装防盗门,需要下午提前一小时下课,所以呢,也要对应的
提前一小时上课……刚才吃了退烧药,希望能有点用,下午是聚会的时间,为什么要今天发烧呢????

building:id、name、height,其中name是varchar型,其他的是integer型
unit:id、unitname、building_id(Integer类型、外键)

需要一个配置文件config,放在类路径的根路径下,可以用xml形式也可以使用properties文件!
从DTD中新建hibernate.cfg.xml,选择hibernate的3.0的DTD

<hibernate-configuration>
 <session-factory>
  <proprety name="dialect">org.hibernate.dialect.MySQLDialect</property>

  <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
  <property name="connection.url">jdbc:mysql:///struts</property>
  <property name="connection.username">root</property>
  <property name="connection.password">root</property>

  <property name="show_sql">true</property>
  <property name="format_sql">true</property>

  <property name="current_session_context_class">thread</property>
 </session-factory>
</hibernate-configuration>

新建工程、加入驱动程序、hibernate的lib中的所有的jar包都拿进来。然后新建一个类Building来
映射数据库中的表:
package vo ;
public class Building
{
 private Integer id ;
 private String username ;
 private Integer height ;
 private List unitNames = new ArrayList();//单元的名字集合。
 加入getter和setter方法………………
}

新建一个Building.hbm.xml,选择Hibernate Mapping DTD3.0
上面的配置文件放到类路径的根路径中,这个则是和上面的那个Building类放在一个包里面,也就是vo包。

<hibernate-mapping  package="vo"> //加入包名
 <class name="Building" table="building">//上面加入了包名,所以这里name不用写类的全名。
  <id name="id" column="id"> //这里如果column和name重名的话,column其实是可以忽略的!
   <generator class="identity" />
  </id>
  <property name="name" column"name" />
  <property name="height" />//由于数据库中也有字段height,所以这里column可以省略。

  <bag name="unitNames" table="unit"> //集合unitNames对应的是unit表!
   <key column="building_id" /> //外键名字叫做building_id
   <element column="unitname" type="string" />//也就是对应的是从表中的unitname字段!
   //把unitname字段中的集合拿出来塞到javaBean中的unitNames这个集合中去
   //现在做的是值集合的映射,根据的是楼来查找单元,所以和单元的id没关系,我们要找的是楼的id
   //由这个楼的id定位它里面的单元名字的集合!
  </bag>
 </class>
</hibernate-mapping>

//下面做一个类:
public class Demo
{
 public static void main(String[] args)
 {
  //addClass会根据类名找那个对应的mapping映射文件!!
  //configure方法只有在你使用的xml配置文件才有必要使用,如果你使用的是properties文件的话,
  //就没必要了。
  SessionFactory factory = new Configuration().addClass(Building.class)
             .configure().
             buildSessionFactory();
  Session = null ;
  try
  {
   Building b = new Building() ;
   b.setName("new building 1") ;
   b.setHeight(new Integer(80)) ;
   b.getUnitNames().add("unit 1");
   b.getUnitNames().add("unit 2");

   session = factory.getCurrentSession() ;
   session.beginTransaction() ;
   session.save(b) ;

   //Building b1 = (Building)session.get(Building.class,new Integer(1));
   //Iterator it = b1.getUnitNames().iterator();
   //while(it.hasNext())
   //{
   //  System.out.println(it.next());
   //}
   //上面这段注释的地方用来把unitNames这个集合给你迭代出来显示!!
   session.getTransaction().commit();

  }
  catch(HibernateException e)
  {
   if(session!=null&&session.getTransaction()!=null)
   {
    session.getTransaction().rollback();
   }
   e.printStackTrace();
  }
  finally
  {
   //session.close();//由于使用的是getCurrentSession,所以这句话不应该写!
   //否则会有空指针异常!!
  }
 }
}
上面的执行过程是先插building表,然后插入unit表的两个记录!可以通过打印出的sql语句观察到!

/*
上面还有一点你千万别忘了!!!使用eclipse根据dtd生成的那两个xml,DTD其实写的是不对的!!!
其实在老师给的hibernate配置中有两个配置文件,一个叫做user.xml,一个叫做hibernate.cfg.xml
这两个演示xml配置文件中的DTD才是真正的我们的上面那两个配置文件cfg.xml和hbm.xml所需要的,切
记一定要用这两个演示文件中的DTD提到eclipse生成的那两个文件中的DTD!否则你绝对没有办法编译过去!
*/
==================================================================================
上午的课程终于结束了,算是挺了一上午,但是就现在这个状态,晚上可怎么去呢……唉,偏偏赶上今天,没想到
这个冬天竟然发烧两次,第一次是做BBS项目的第一天,也就是元旦前的最后几天里面,第二次就是今天了。哎……
简直是闻所未闻啊,身体怎么差成这个样子!……先尽量休息把,晚上看情况,不过最好还是去,毕竟答应人家了,
而且……

==================================================================================
下午了,一点上课,感觉好漫长……

下午课程开始:

上午做了一个实体中的集合,虽然用了List,但是配置中使用的是Bag,也就是用Bag来模拟List……现在的
问题是我能否把实体类中的List改成ArrayList呢??

答案是否定的,会抛出java.lang.ClassCastException:类型转换异常!

在转换成org.hibernate.collection.PersistentBag的时候出错了,人家实现的是List接口,不是
什么ArrayList!!

也就是声明一个实体的集合的时候,除非你使用PersistentBag或者PersistentList声明,那么你其他的选择
只能是用接口去声明具体的集合,而绝对不要用像ArryList这样的实现类!!

也就是不能像下面这么写:

package vo ;
public class Building
{
 private Integer id ;
 private String username ;
 private Integer height ;
 private ArrayList unitNames = new ArrayList();//单元的名字集合。
 加入getter和setter方法………………
}
unitNames前面必须是List,这个集合会被换成PersistentBag这样的代理类,如果不是使用接口
去操纵而是使用具体的实现类的话,肯定会出错!

bag:List接口
set:对应set接口
map:对应map接口
也就是在映射文件中你用哪个集合类去声明的,你在实体类中就最好要用对应的类型!

现在说一下Set集合,其实Set集合和Bag集合的使用方法是异曲同工的,也是要求key和element,你做的只是
将配置文件中的bag改成set

在api的org.hibernate.collection包里面可以清晰的看到bag、set、map等可以使用的具体实现类,几乎
都是以Persist开头的集合类,是hibernate中定义的集合类!

它们的核心都是一致的,都是要有key和element。

----------------------------------------
说完了set和bag,我们来看一下list

无论是bag,还是set,它们都无法对所包含的元素排序,除非加入order-by属性。
如果即希望集合按索引列排序,又希望包含所有重复元素,就应该考虑使用list集合。
List元素中加入index索引,用于指明索引列。
在实现上list集合恰好与Java中的List接口对应,一般使用ArrayList或LinkedList实现,
所以返回的集合可以通过索引方式访问

List里面多了个index或者list-index,除此之外也有key和element!

因为List最终对应到ArrayList里面去,查一下ArrayList的api你可以发现,在ArrayList
里面,有这样一个方法叫做add方法,这里面需要一个整数类型的index和一个对象元素,可以选择
将对象插入到准确的第几个index序列那里。
就是add(int index,Object element)
那个add(Object o)只是加在数组的最后而已

映射文件中的index或者list-index就是上面所说的插入到哪一个索引号那里,二者其实没有区别,
建议你使用list-index,而不是index,因为index容易有混淆的概念,不久将会被淘汰!

使用的PersistentList实现类,应该用List接口声明实体类,如下所示:
package vo ;
public class Building
{
 private Integer id ;
 private String username ;
 private Integer height ;
 private List unitNames = new ArrayList();//单元的名字集合。
 加入getter和setter方法………………
}

 

<hibernate-mapping  package="vo"> //加入包名
 <class name="Building" table="building">//上面加入了包名,所以这里name不用写类的全名。
  <id name="id" column="id"> //这里如果column和name重名的话,column其实是可以忽略的!
   <generator class="identity" />
  </id>
  <property name="name" column"name" />
  <property name="height" />//由于数据库中也有字段height,所以这里column可以省略。

  <list name="unitNames" table="unit"> //集合unitNames对应的是unit表!
   <key column="building_id" /> //外键名字叫做building_id
   <list-index column="id" base="3" />//base表明从3开始
   //注意如果上面这么写的话,如果没有那个base属性的话,执行结果会出现null值,因为会按照索引的id从0开始塞到索引的
   //相应位置里面!!如果有base属性的话会用取出的id减去base值然后插入!这样会引发问题,因为如果使用下面的代码:
   //Building b1 = (Building)session.get(Building.class,new Integer(1));由于取出的id是1,那么1减去3会有
   //负值,这就会发生错误,
   //所以注意使用list的话最好再加上一列表明对应的list的索引值
   <element column="unitname" type="string" />
  </list>
 </class>
</hibernate-mapping>

//我下面说一下如果不加入base的话会出现什么问题,比如说你在上午的demo中执行
//Building b1 = (Building)session.get(Building.class,new Integer(1));
//的话,由于大家都知道List的索引是从0开始的,所以除了取出你想要的1之外还会把0这个索引给取出来,会有一个null值的。
//如果你写的是Building b1 = (Building)session.get(Building.class,new Integer(3));那就更麻烦,0、1和2
//的索引都会取出来,也就是说除了building_id为3的楼对应的单元名字以外呢,还会取出3个空置,解决的办法就是将base设置
//为3就可以了。

//hibernate保证了主外键关系,所以你可以在数据库里面加上主外键约束,你也可以选择不加!

----------------------------------------------------------------------

注意上面对于List和其base的解释是有问题的!

用ArrayList加载的时候不会出异常,但是一旦save的时候就出问题了,
应该在数据库的从表中加上一列叫做order_id,类型是Integer,然后让list-index的column值
为order_id,这样就不需要base了,当然你用base也行……你可以试试看结果怎么样。

<hibernate-mapping  package="vo"> //加入包名
 <class name="Building" table="building">//上面加入了包名,所以这里name不用写类的全名。
  <id name="id" column="id"> //这里如果column和name重名的话,column其实是可以忽略的!
   <generator class="identity" />
  </id>
  <property name="name" column"name" />
  <property name="height" />//由于数据库中也有字段height,所以这里column可以省略。

  <list name="unitNames" table="unit"> //集合unitNames对应的是unit表!
   <key column="building_id" /> //外键名字叫做building_id
   <list-index column="order_id" />
   
   <element column="unitname" type="string" />
  </list>
 </class>
</hibernate-mapping>


===========================================================================
MAP集合

Map集合反映键对象与值对象之间的对应关系,可以通过键对象索引到值对象
在实现上,Map集合与Java API中的Map接口对应,具体由HashMap或TreeMap来实现。
在映射上,主要是使用map-key来表示键对象。这个对象也是在Hibernate3中加入的,有取代index的意思。

<hibernate-mapping  package="vo"> //加入包名
 <class name="Building" table="building">//上面加入了包名,所以这里name不用写类的全名。
  <id name="id" column="id"> //这里如果column和name重名的话,column其实是可以忽略的!
   <generator class="identity" />
  </id>
  <property name="name" column"name" />
  <property name="height" />//由于数据库中也有字段height,所以这里column可以省略。

  <map name="unitNames" table="unit"> //集合unitNames对应的是unit表!
   <key column="building_id" /> //外键名字叫做building_id
   <map-key column="order_id" type="int" />
   
   <element column="unitname" type="string" />
  </map>
 </class>
</hibernate-mapping>


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

注意如果select name,age from User 返回的是Object[]
如果select new list(name,age) from User 返回的是List
如果select new map(name,age) from User 返回的是Map,而且Map里面的key是
  字符串的0和字符串的1!
如果select new UserProxy(name,age) from User,要求构造函数中必须能够接收两个
参数,返回的是个类的实例!这个非常的方便,具体使用方法见前面的日记!!

默认情况下是数组,可以是list,可以是map,或者可以是你自定义的一个类!!

package vo ;
public class Building
{
 private Integer id ;
 private String username ;
 private Integer height ;
 private Map unitNames = new HashMap();//单元的名字集合。
 加入getter和setter方法………………
}


public class Demo
{
 public static void main(String[] args)
 {
  //addClass会根据类名找那个对应的mapping映射文件!!
  //configure方法只有在你使用的xml配置文件才有必要使用,如果你使用的是properties文件的话,
  //就没必要了。
  SessionFactory factory = new Configuration().addClass(Building.class)
             .configure().
             buildSessionFactory();
  Session = null ;
  try
  {
   Building b = new Building() ;
   b.setName("new building 1") ;
   b.setHeight(new Integer(80)) ;
   b.getUnitNames().put(new Integer(6),"unit x");
   
   session = factory.getCurrentSession() ;
   session.beginTransaction() ;
   session.save(b) ;

   //Building b1 = (Building)session.get(Building.class,new Integer(1));
   //Iterator it = b1.getUnitNames().iterator();
   //while(it.hasNext())
   //{
   //  System.out.println(it.next());
   //}
   //上面这段注释的地方用来把unitNames这个集合给你迭代出来显示!!
   session.getTransaction().commit();

  }
  catch(HibernateException e)
  {
   if(session!=null&&session.getTransaction()!=null)
   {
    session.getTransaction().rollback();
   }
   e.printStackTrace();
  }
  finally
  {
   //session.close();//由于使用的是getCurrentSession,所以这句话不应该写!
   //否则会有空指针异常!!
  }
 }
}

================================================================================
今天的内容就到这里了,如果田老师的讲的这些东西能够100%的掌握的话,会比外面工作几年的人有的时候都要强出
不少,这不是我说的,我今天已经烧糊涂了,说不出这样子的话,我今天只是机械的录入而已,上面的List解释有很大
的问题,几乎是不对的,我会找机会在我清醒的时候好好整理一下,因为今天我没有建立工程,没有练习任何东西……
尽管田老师很自信,但是我们也知道经验是教不出来的,田老师曾经做过多次企业级培训,接触过这样的人,他们几乎
是没有什么根基的,很多基础知识什么的并不是很清楚……其实有的时候两年的工作经验就像没有一样,因为换一个公司
就换了一套框架,再进入一个新公司跟什么都没有,重要的东西是反射和代理的机制,如果真正掌握的话对于任何一个
框架都是看起来没有问题的,比如我看的那个JUnit就是大量的使用了反射机制和自省机制。在年后回来也就是2月15日
的时候李春晖将要讲解bean-utils,而我则要讲解Junit,现在我已经有了大概的模型概念,好好扣扣能懂,但是你要
是让我现在讲是绝对没戏啊……我自己还迷迷糊糊的,怎么可能给别人讲呢……年里的14天要好好巩固前面的内容,我对我的
笔记还是有自信的,再加上我还有孙卫琴和夏昕的书,应该是没有问题的,需要的是试验把他们都搞清楚。

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

现在复习一下Struts:

Struts首先是实现了MVC模式的框架,核心是Controller,里面有三个控制器ActionServlet、RequestProcessor和
Action

ActionServlet是Struts中的总控制器,如果要使用的话需要在web.xml中去注册配置,配置方法和Servlet一样,但是
只有一点特别,就是<load-on-startup>0</load-on-startup>
只要不是负值就可以。

ActionServlet的主要工作:三个工作:1、初始化,init里面初始化模块生成ModuleConfig,然后存储到应用程序作用域
里面,Global.Module_key加上模块前缀名为属性名存入。

2、根据请求的路径去找ModuleConfig,然后将ModuleConfig存入请求作用域,属性名字是Globals.MODULE_KEY,不加
前缀名了!

3、找到与这个模块相对应的模块控制器RequestProcessor,然后将请求与响应交给它,让它去处理!!

然后第二个控制器是Action,模块控制器会根据.do前面的地址去找相应的Action,然后调用Action的execute方法,
在Struts1.1中Action的这个方法叫做perform,不是execute!!Action不是线程安全的!在整个应用中实例只有一个,
所以一定要保证线程安全!要进行同步。尽量不要用action的全局属性!Servlet加载的时候也是一个实例,也要保证线程
安全!

还有一个叫做RequestProcessor的控制器,Action的作用实际上是在execute方法里面起到适配器的作用,适配相应的
请求和逻辑。但是RequestProcessor里面干的事情就更多了,它创建ActionForm,将请求参数塞进去,然后validate,然后
创建Action


现在说说视图这里:
视图主要就是ActionForm:它的生命周期需要注意,有请求和session两种生命周期,它可以存储在request和session里面!!
设置生命周期的时候,在进入页面的时候ActionForm的逻辑是怎么样的呢(页面上有htmlform标签)?action里面好像可以加
.do地址也可以不加,struts-config里面就不可以加.do地址了!!取出form后根据里面的默认值设置页面上的默认值,提交
的时候先设置reset方法,然后再把表单里面的值设置到formbean上,然后调用ActionForm的validate方法。

我们扩展了国际化和错误处理的概念。

国际化:
Struts加载资源包的方式,使用message-resource指明,那个元素里面可以指明key和parameter,parameter是资源包的
基名,然后存入应用程序作用域中key指明的属性名,或者默认情况下存在Globals.MESSAGE_KEY

页面上用bean:message取出,注意如果多个资源包的话要使用bundle属性。


错误处理:使用了一个叫做ActionErrors的东西,注意actionError要作废了!加入的时候应该加入ActionMessage,而不是
ActionError
在formbean里面要进行validator进行校验的话,要把默认值设置为true,默认值就是true,还有input属性一定要设置,
input属性中是发生错误后跳回的页面。

如果Action的execute里面返回的ActionErrors不为空的话,那么还会不会转到input指明的页面中去呢?答案是不会的。
取决于你自己配置的ActionForward转回到哪里去,也就是根据actionMapping的findforward方法来转向。但是ActionForm
里的validate如果出错误了的话肯定会跳回到input所指的页面

html:messages必须有id这个属性,id属性的作用是从ActionErrors里面取出ActionMessage,然后将字符串存储到id所指明的
页面作用域的属性名中。如果没有指明的话会去找errors的key然后遍历(这里写的好像有点问题,要注意!)

如果你存储的是ActionMessages,那么就不能用html:errors取了,只能使用html:messages message="true".

还有Action的execute异常抛出机制,其实是由RequestProcessor处理的,在struts-config中去配置。还有Global-exceptions
和Global-forward。

要么使用exception将错误转到特定的页面,要么是用ActionErrors或者ActionMessages的错误处理机制,都可以处理
错误!!!

此外视图组件里面还有一些自定义标签,其中一个比较重要的叫做<logic:iterate>,使用时候需要id和name,具体方法见前面
日记或者api!!!

错误处理是比较乱的地方!

ActionServlet除了config可以配置外,还有6个元素可以配置它,也就是多模块化的编程!

module和contextRelative属性可以帮助你从某一模块转化为默认的模块!

注意这里面有Struts的一个bug,.do的地址由于经过ActionServlet所以可以转地址,而jsp页面由于不经过ActionServlet的话,
就转不了了。(具体见昨天的日记!!!)


ActionFormBean中的convertNull很重要,关系到数值包装类型是null还是0,一般要设为true!否则会出0!

另外还有三个关于XML解析的东西,这关系就不太大了。

这里面穿插了一个token防止表单重复提交的例子,需要session和请求的隐藏作用域里面都存储token,相等就处理,不
相等就不处理!

还讲了两个框架,validator框架和file-upload框架的使用配置方法,最好还有一个叫做Tile的起框架作用的东西。

如果使用validator,首先要有plug-in引入,要有验证规则还有你写的具体验证区域和对应的配置。见前面的日记。
如果要前台进行校验的话,要使用html:javascript,如果左边这个标签里面要是不加method属性配置的话,就会在
jsp页面生成一个默认的javascript的函数名,具体名字可以参考前面的日记或者你自己试试。

文件上传,要求表单中的两个属性必须要配置(具体见前面的日记),至于boundary的机制参考前面的日记,至于那个commons里面
的文件上传包里面的使用方法很简单,参考前面的日记。

如果我使用Struts上传文件的话,我可以把请求中的所有参数都取出来,上传的文件域应该是html:field,还有form:field
(这里写的可能有误)

要配置requestProcessor可以配置struts-config中的controller属性,里面有一个要设置文件上传的最大容量的属性,
其在文件上传中使用的方法参看前面的日记。

文件下载的时候该如何处理其实前面的日记也写的很清楚了,注意头的设置,也就是content-Disposition,
当然把文件直接放到web工程里面的话也可以下载,但是呢,这种下载方式削弱了控制力度。不提倡。
下载之前响应里面的报头content-Disposition要设置,这个响应报头必须要在过滤器里面设置这个响应
的报头!!切记!!!

监听器监听3个作用域,两个事件,应该是有7个过滤器。

tile有三种方式去整理配置,笔记里面记录了两种,第三种可以查看api,第一种是直接引入进来,
第二种是用tile-attribute,第三种tile-definition,注意如果使用xml配置文档的话需要plug-in
的配置!

这里文件上传和下载还有防止表单的重复提交很重要。
===========================================================================================

还有11天的课程就放假了……坚持一下吧……………………今天彻底糊涂了,没想到一总结总结出这么多的东西,疯了……
可能上面的Struts的随堂记录有很多的笔误吧,希望自己再读的时候能够认出来……今天反正是没有心情整理了……

晚上光睡觉捂汗了,哪儿也没去,啥也没干…… 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值