`

J2EE常见问题及经验汇总(转载)

阅读更多

*****************web开发的问题汇总********************


2.      Hibernate优化问题。如何优化数据库访问,使程序访问数据库更优化。

 初用HIBERNATE的人也许都遇到过性能问题,实现同一功能,用HIBERNATE与用JDBC性能相差十几倍很正常,如果不及早调整,很可能影响整个项目的进度。

  大体上,对于HIBERNATE性能调优的主要考虑点如下:

  * 数据库设计调整

  * HQL优化

  *  API的正确使用(如根据不同的业务类型选用不同的集合及查询API)

  * 主配置参数(日志,查询缓存,fetch_size, batch_size等)

* 映射文件优化(ID生成策略,二级缓存,延迟加载,关联优化)

  * 一级缓存的管理

  * 针对二级缓存,还有许多特有的策略

  * 事务控制策略。

  1、 数据库设计

  a) 降低关联的复杂性

  b) 尽量不使用联合主键

  c) ID的生成机制,不同的数据库所提供的机制并不完全一样

  d) 适当的冗余数据,不过分追求高范式

  2、 HQL优化

  HQL如果抛开它同HIBERNATE本身一些缓存机制的关联,HQL的优化技巧同普通的SQL优化技巧一样,可以很容易在网上找到一些经验之谈。

  3、 主配置

  a) 查询缓存,同下面讲的缓存不太一样,它是针对HQL语句的缓存,即完全一样的语句再次执行时可以利用缓存数据。但是,查询缓存在一个交易系统(数据变更频繁,查询条件相同的机率并不大)中可能会起反作用:它会白白耗费大量的系统资源但却难以派上用场。

  b) fetch_size,同JDBC的相关参数作用类似,参数并不是越大越好,而应根据业务特征去设置

  c) batch_size同上。

  d) 生产系统中,切记要关掉SQL语句打印。

  4、 缓存

  a) 数据库级缓存:这级缓存是最高效和安全的,但不同的数据库可管理的层次并不一样,比如,在ORACLE中,可以在建表时指定将整个表置于缓存当中。

  b) SESSION缓存:在一个HIBERNATE SESSION有效,这级缓存的可干预性不强,大多于HIBERNATE自动管理,但它提供清除缓存的方法,这在大批量增加/更新操作是有效的。比如,同时增加十万条记录,按常规方式进行,很可能会发现OutofMemeroy的异常,这时可能需要手动清除这一级缓存:Session.evict以及Session.clear

  c) 应用缓存:在一个SESSIONFACTORY中有效,因此也是优化的重中之重,因此,各类策略也考虑的较多,在将数据放入这一级缓存之前,需要考虑一些前提条件:

  i. 数据不会被第三方修改(比如,是否有另一个应用也在修改这些数据?)

  ii. 数据不会太大

  iii. 数据不会频繁更新(否则使用CACHE可能适得其反)

  iv. 数据会被频繁查询

  v. 数据不是关键数据(如涉及钱,安全等方面的问题)。

  缓存有几种形式,可以在映射文件中配置:read-only(只读,适用于很少变更的静态数据/历史数据),nonstrict-read-write,read-write(比较普遍的形式,效率一般),transactional(JTA中,且支持的缓存产品较少)

  d) 分布式缓存:同c)的配置一样,只是缓存产品的选用不同,在目前的HIBERNATE中可供选择的不多,oscache, jboss cache,目前的大多数项目,对它们的用于集群的使用(特别是关键交易系统)都持保守态度。在集群环境中,只利用数据库级的缓存是最安全的。

  5、 延迟加载

  a) 实体延迟加载:通过使用动态代理实现

  b) 集合延迟加载:通过实现自有的SET/LIST,HIBERNATE提供了这方面的支持

  c) 属性延迟加载:

  6、 方法选用

  a) 完成同样一件事,HIBERNATE提供了可供选择的一些方式,但具体使用什么方式,可能用性能/代码都会有影响。显示,一次返回十万条记录(List/Set/Bag/Map等)进行处理,很可能导致内存不够的问题,而如果用基于游标(ScrollableResults)或Iterator的结果集,则不存在这样的问题。

  b) Session的load/get方法,前者会使用二级缓存,而后者则不使用。

  c) Query和list/iterator,如果去仔细研究一下它们,你可能会发现很多有意思的情况,二者主要区别(如果使用了Spring,在HibernateTemplate中对应find,iterator方法):

  i. list只能利用查询缓存(但在交易系统中查询缓存作用不大),无法利用二级缓存中的单个实体,但list查出的对象会写入二级缓存,但它一般只生成较少的执行SQL语句,很多情况就是一条(无关联)。

  ii. iterator则可以利用二级缓存,对于一条查询语句,它会先从数据库中找出所有符合条件的记录的ID,再通过ID去缓存找,对于缓存中没有的记录,再构造语句从数据库中查出,因此很容易知道,如果缓存中没有任何符合条件的记录,使用iterator会产生N+1条SQL语句(N为符合条件的记录数)

  iii. 通过iterator,配合缓存管理API,在海量数据查询中可以很好的解决内存问题,如:

  while(it.hasNext()){

  YouObject object = (YouObject)it.next();

  session.evict(youObject);

 sessionFactory.evice(YouObject.class, youObject.getId());

  }

  如果用list方法,很可能就出OutofMemory错误了。

  iv. 通过上面的说明,我想你应该知道如何去使用这两个方法了。

  7、 集合的选用

  在HIBERNATE 3.1文档的“19.5. Understanding Collection performance”中有详细的说明。

  8、 事务控制

  事务方面对性能有影响的主要包括:事务方式的选用,事务隔离级别以及锁的选用

  a) 事务方式选用:如果不涉及多个事务管理器事务的话,不需要使用JTA,只有JDBC的事务控制就可以。

  b) 事务隔离级别:参见标准的SQL事务隔离级别

  c) 锁的选用:悲观锁(一般由具体的事务管理器实现),对于长事务效率低,但安全。乐观锁(一般在应用级别实现),如在HIBERNATE中可以定义VERSION字段,显然,如果有多个应用操作数据,且这些应用不是用同一种乐观锁机制,则乐观锁会失效。因此,针对不同的数据应有不同的策略,同前面许多情况一样,很多时候我们是在效率与安全/准确性上找一个平衡点,无论如何,优化都不是一个纯技术的问题,你应该对你的应用和业务特征有足够的了解。

  9、 批量操作

  即使是使用JDBC,在进行大批数据更新时,BATCH与不使用BATCH有效率上也有很大的差别。我们可以通过设置batch_size来让其支持批量操作。

  举个例子,要批量删除某表中的对象,如“delete Account”,打出来的语句,会发现HIBERNATE找出了所有ACCOUNT的ID,再进行删除,这主要是为了维护二级缓存,这样效率肯定高不了,在后续的版本中增加了bulk delete/update,但这也无法解决缓存的维护问题。也就是说,由于有了二级缓存的维护问题,HIBERNATE的批量操作效率并不尽如人意!

3.      网站是动态的,需要频繁访问数据库,如何提高访问速度,减少服务器压力?

提供JDBC数据库链接池共享,大大降低数据库压力;

智能动态HTML,大大减少网络数据流量;

海量数据优化,大大提高登录和访问速度;

用户界面和数据缓存,大大提高登录速度;

多层次体系结构,支持多个应用程序服务器并行,大大提高系统伸缩性,并发访问用户数目和数据安全性

4.      搜索引擎优化,如何提高网站排名。优化有哪些具体技术措施?

   网站结构设计中面向搜索引擎的优化注意事项包括:

1)链接引用的重要性

a.以量取胜:不一定加入传统门户网站的分类目录才是网站推广,来自其他网站的任何反相链接都是有用的

b. 以质取胜:被PageRank高的网站引用能更快地提高PageRank

c. 了解搜索引擎的"价值观":不要通过Link Farm提高自身的站点排名:Google会惩罚那些主动链接到Link Farm站点以提高自身排名站点,相应站点的页面将不会被收入到索引中。但如果你的页面被别的Link Farm链接了也不必担心,因为这种被动的链接是不会被惩罚的。

d. 不要吝啬给其他网站的链接:如果一个网页只有大量的进入链接,而缺乏导出链接,也会被搜索引擎认为是没有价值的站点。

2)如何突出关键词:网页标题、主题的设计

a.Theme Engine正在逐步超过PR,成为结果排序中更主要的因素

b.不要空着标题:空着<title></title>无异于浪费了最有价值的一块阵地

c. 标题长度和内容:不要过长,一般在40个字(80个字节)以内,并充分突出关键词的比重

d. 如果网页很多的话,尽量使用不同的网页标题,争取让自己网站的内容更多的进入搜索引擎索引范围

e. 除了<title></title>外,还可以用<h1></h1>标题行突出内容主题, 加强标题的效果

3)页面及站点结构设计注意事项

a. 静态链接: 大部分搜索引擎都认为静态链接的网页是优质网页,Google在优先抓取索引的网页中70%以上是不带参数链接的静态网页。而且即使同样的内容,静态网页也 会比动态网页权重高

b. 能够进入Google索引的页面数量越多越好

c. 网站目录结构要扁平,因为每深一级目录,PAGERANK降低1-2个档次。假设首页是3,其子可能目录就是1了,更深可能就无法列入评级范围了。

d. 表现和内容的分离:“绿色”网页

网页中的javascript和css尽可能和网页分离,一方面提高代码重用度(也方便页面缓存),另外一方面,由于有效内容占网页长度的百分比高,也能提高相关关键词在页面中的比重也增加了。总之,应该鼓励遵循w3c的规范,使用更规范的XHTML和XML作为显示格式便于内容更长时间的保存。

e. 让所有的页面都有能够快速入口:站点地图, 方便网页爬虫(spider)快速遍历网站所有需要发布的内容。如果首页就是用Flash或图片进入的话,无异于将搜索引擎拒之门外,除了UI设计的用户 友好外,spider friendly也是非常重要的

f. 保持网站自身的健康:经常利用坏 链检查工具检查网站中是否有死链

g. 保持网页内容/链接的稳定性和持久性:在搜索引擎索引中网页存在的历史也是一个比较重要的因素,而且历史比较久的网页被链接的几率越高。为了 保证自己网页能够被比较持久的被其他网站的页面引用,如果自己网页中有链接更新时,最好能保留旧的页面并做好链接转向,以保持内容的连续性。

h. 文件类型因素:Google有对PDF, Word(Power Point, Excel), PS文档的索引能力,由于这种文档的内容比一般的HTML经过了更多的整理,学术价值一般比较高,所以这些类型的文档天生就比一般的HTML类型的文档 PageRank要高。因此,对于比较重要的文档:技术白皮书,FAQ,安装文档等建议使用PDF PS等高级格式存取,这样在搜索结果中也能获得比较靠前的位zhi点访问统计的重要性等;,的设计 

4)以及站点访问统计的重要性等

5)Google的站点设计指南

1.Make a site with a clear hierarchy and text links. Every page should be reachable from at least one static text link.  让网站有着清晰的结构和文本链接,所有的页面至少要有一个静态文本链接入口

批注:尽量不要用图片和JAVASCRIPT

2.Offer a site map to your users with links that point to the important parts of your site. If the site map is larger than 100 or so links, you may want to break the site map into separate pages.

为用户提供一个站点地图:转向网站的重要部分。如果站点地图页面超过100个链接,则需要将页面分成多个页面。

批注:索引页不要超过100个链接:SPIDER只考虑页面中头100个链接

3.Create a useful, information-rich site and write pages that clearly and accurately describe your content.

用一些有用的,信息量丰富的站点,清晰并正确的描述你的信息。

4.Think about the words users would type to find your pages, and make sure that your site actually includes those words within it.

想像用户可能用来找到你的关键词,并保证这些关键词在网站中出现。

批注:少用“最大”,“最好”之类的形容词,用用户最关心的词,比如:下载,歌星名字,而不是一些抽象名词。

5.Try to use text instead of images to display important names, content, or links. The Google crawler doesn't recognize text contained in images.

尽可能使用文本,而不是图片显示重要的名称,内容和链接。GOOGLE的机器人不认识图片中的文字。

6.Make sure that your TITLE and ALT tags are descriptive and accurate.

保证:页面的TITLE和ALT标记正确的精确描述

7.Check for broken links and correct HTML.

检查坏链并修正这些HTML错误。

8.If you decide to use dynamic pages (i.e., the URL contains a '?' character), be aware that not every search engine spider crawls dynamic pages as well as static pages. It helps to keep the parameters short and the number of them small.

如果你打算使用动态页面:链接中包含"?",必须了解:并非所有的搜索引擎的机器人能想对待静态页面一样对待动态页面,保持动态页面的参数尽可能的少也会 很有帮助。

9.Keep the links on a given page to a reasonable number (fewer than 100).

让一个页面中的链接少于100个。

批注:用lynx -dump http://www.chedong.com/ 可以模拟从robot角度看到的页面。其最后有链接统计

5.      hibernate对动态查询的理解,如何应用,并作应用示例。

定义:

?静态查询:在编程时已经确定要查询的字段,这时编写的HQL或QBC称为静态查询。

?动态查询:在编程时无法确定要查询的字段,这时编写的HQL或QBC称为动态查询。比如组合查询时,往往需要查询的项很多,但不是每个项都必需。

(HQL适用于静态查询,QBC适用于动态查询)

以下分别用HQL和QBC实现动态查询:

1)下面的程序通过对字符串的拼装使用HQL语句实现动态查询:

Public List findStu(String name, int age){

StringBuffer queryString= new StringBuffer();

Boolean conditionFound= false;

if(name!=null){

queryString.append(“lower(s.name) like :name”);

conditionFound= true;

}if(age!= 0){

if(conditionFound) queryString.append(“and”);

queryString.append(“s.age= :age”);

conditionFound=true;

}

String fromClause= conditionFound?”fromStudent s where” : ”fromStudent s”;

queryString.insert(0,fromClause).append(“order by s.name”);

Query query=getSession().createQuery(“queryString.toString()”);

if(name!=null)query.setString(“name”,’%’+name.toLowerCase()+’%’);

if(age!=0)query.setInteger(“age”,newInteger(age));

return query.list();

}

上面的代码虽然可以正常工作,但是把简单的功能实现的相当复杂,维护起来不方便。我们来看一下使用QBC查询。

Public List findStu(String name, int age){

Criteria crit= getSession().createCriteria(Student.class);

if(name!=null){

crit.add(Restrictions.like(“name”,name,MatchMode.ANYWHERE));

}if(age!=0){

crit.add(Restrictions.eq(“age”,newInteger(age)));

}

crit.addOrder(Order.asc(“name”));

return crit.list();

}

6.      Hibernate问题

●     a different object with the same identifier value was already associated with the session是什么原因导致的?

在hibernate中同一个session里面有了两个相同标识但是是不同实体,当这时运行saveOrUpdate(object)操作的时候就会报这个错误。种错误经常出现在一对多映射和多对多映射

在hibernate的开发中,HBM文件中会涉及到n2m的种种关系,但是,只有在出于必要性考虑的时候,才加上cascade="all" ,同时,需小心规避由此引起的程序Exception.

考虑不周,会导致可能出现的最常见Exception是:

net.sf.hibernate.NonUniqueObjectException

a different object with the same identifier value was already associated with the session:......

解决办法是:

1. 去掉引起Exception的associated Class对映HBM中的不必要cascade;

2. 检查Exception发生位置的session的使用情况;

●     Object references an unsaved transient instance-save the transient instance before flushing是什么原因导致的?

某个对象的某个属性是一个实体,在这个实体没有保存之前就保存这个对象而造成了这个错误。

以下举个例子说明以下

Session session = dao.getSession();

Transaction tx = session.beginTransaction();

Bo.setBman( form ,man,session);

Bo.saveChangeTable( man,session); // 把man当作属性赋给ChangeTable,并保存ChangeTable. 就是这出的错,

dao.save(man,session);  // 保存man

tx.commit();

==================== 应该这样写:===============

Session session = dao.getSession();

Transaction tx = session.beginTransaction();

Bo.setBman( form ,man,session);

dao.save(man,session);  // 保存man

Bo.saveChangeTable( man,session); // 把man当作属性赋给ChangeTable,并保存ChangeTable

tx.commit();

这样,问题就解决了。

 

●     如果修改一个列表中的一个数据,会发现这个数据不稳定,一会是修改后的,一会是修改前的,说出其原因

因为hibernate利用了缓存技术,sql适时提交,当数据修改以后,数据并不一定及时提交到数据库,而是放在hibernate的缓存中,当我们察看数据时,可能是提交完的,也可能是没有提交的,所以就会出现数据的脏读。

如何避免使用缓存技术所带来的脏数据问题呢?

在设计、实现和测试时,应该清晰定义缓存数据的更新:

i. 不考虑缓存数据的更新,重启软件系统是一种必要的方式;

ii. 不考虑缓存数据的更新,缓存数据不可能成为脏数据(但在软件系统中,往往“不可能”会在一次又一次的重构之后变为“可能”);

iii. 考虑缓存数据的更新,当源数据变化时,实时更新缓存数据。

●     对于数据库自增长来说,在映射文件中主键配置,用哪种配置方案最好,最不容易出现问题?

Hibernate标识生成策略:

标识符生成器 描述

increment 适用于代理主键。由Hibernate自动以递增方式生成。

identity     适用于代理主键。由底层数据库生成标识符。

sequence  适用于代理主键。Hibernate根据底层数据库的序列生成标识符,这要求底层数据库支持序列。

hilo       适用于代理主键。Hibernate分局high/low算法生成标识符。

seqhilo     适用于代理主键。使用一个高/低位算法来高效的生成long,short或者int类型的标识符。

native适用于代理主键。根据底层数据库对自动生成标识符的方式,自动选择identity、sequence或hilo。

uuid.hex   适用于代理主键。Hibernate采用128位的UUID算法生成标识符。

uuid.string       适用于代理主键。UUID被编码成一个16字符长的字符串。

assigned   适用于自然主键。由Java应用程序负责生成标识符。

foreign     适用于代理主键。使用另外一个相关联的对象的标识符。

就这个问题我认为应该用increment、native都可以

7.       概括你常用的框架的优缺点。

1. Struts的优缺点:

具体来讲,Struts的优点有:

1. 实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现.

2. 有丰富的tag可以用 ,Struts的标记库(Taglib),如能灵活动用,则能大大提高开发效率。另外,就目前国内的JSP开发者而言,除了使用JSP自带的常用标记外,很少开发自己的标记,或许Struts是一个很好的起点。

3. 页面导航.页面导航将是今后的一个发展方向,事实上,这样做,使系统的脉络更加清晰。通过一个配置文件,即可把握整个系统各部分之间的联系,这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时,这种优势体现得更加明显。

4. 提供Exception处理机制 .

5. 数据库链接池管理

6. 支持I18N

缺点:

一、 转到展示层时,需要配置forward,每一次转到展示层,相信大多数都是直接转到jsp,而涉及到转向,需要配置forward,如果有十个展示层的jsp,需要配置十次struts,而且还不包括有时候目录、文件变更,需要重新修改forward,注意,每次修改配置之后,要求重新部署整个项目,而tomcate这样的服务器,还必须重新启动服务器,如果业务变更复杂频繁的系统,这样的操作简单不可想象。现在就是这样,几十上百个人同时在线使用我们的系统,大家可以想象一下,我的烦恼有多大。

二、 Struts 的Action必需是thread-safe方式,它仅仅允许一个实例去处理所有的请求。所以action用到的所有的资源都必需统一同步,这个就引起了线程安全的问题。

三、 测试不方便. Struts的每个Action都同Web层耦合在一起,这样它的测试依赖于Web容器,单元测试也很难实现。不过有一个Junit的扩展工具Struts TestCase可以实现它的单元测试。

四、 类型的转换. Struts的FormBean把所有的数据都作为String类型,它可以使用工具Commons-Beanutils进行类型转化。但它的转化都是在Class级别,而且转化的类型是不可配置的。类型转化时的错误信息返回给用户也是非常困难的。

五、 对Servlet的依赖性过强. Struts处理Action时必需要依赖ServletRequest 和ServletResponse,所有它摆脱不了Servlet容器。

六、 前端表达式语言方面.Struts集成了JSTL,所以它主要使用JSTL的表达式语言来获取数据。可是JSTL的表达式语言在Collection和索引属性方面处理显得很弱。

七、 对Action执行的控制困难. Struts创建一个Action,如果想控制它的执行顺序将会非常困难。甚至你要重新去写Servlet来实现你的这个功能需求。

八、 对Action 执行前和后的处理. Struts处理Action的时候是基于class的hierarchies,很难在action处理前和后进行操作。

九、 对事件支持不够. 在struts中,实际是一个表单Form对应一个Action类(或DispatchAction),换一句话说:在Struts中实际是一个表单只能对应一个事件,struts这种事件方式称为application event,application event和component event相比是一种粗粒度的事件。

Struts重要的表单对象ActionForm是一种对象,它代表了一种应用,这个对象中至少包含几个字段,这些字段是Jsp页面表单中的input字段,因为一个表单对应一个事件,所以,当我们需要将事件粒度细化到表单中这些字段时,也就是说,一个字段对应一个事件时,单纯使用Struts就不太可能,当然通过结合JavaScript也是可以转弯实现的。

 

       2.Hibernate的优缺点:

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序实用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。

大多数开发机构经常采取创建各自独立的数据持久层。一旦底层的数据结构发生改变,那么修改应用的其余部分使之适应这种改变的代价将是十分巨大的。Hibernate适时的填补了这一空白,它为Java应用提供了一个易用的、高效率的对象关系映射框架。hibernate是个轻量级的持久性框架,功能却非常丰富。

优点:

a. Hibernate 使用 Java 反射机制而不是字节码增强程序来实现透明性。

b. Hibernate 的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。

c. 它支持各种关系数据库,从一对一到多对多的各种复杂关系。

缺点:它限制您所使用的对象模型。(例如,一个持久性类不能映射到多个表)其独有的界面和可怜的市场份额也让人不安,尽管如此,Hibernate 还是以其强大的发展动力减轻了这些风险。其他的开源持久性框架也有一些,不过都没有 Hibernate 这样有市场冲击力。

3. Spring框架的优缺点

它是一个开源的项目,而且目前非常活跃;它基于IoC(Inversion of Control,反向控制)和AOP的构架多层j2ee系统的框架,但它不强迫你必须在每一层中必须使用Spring,因为它模块化的很好,允许你根据自己的需要选择使用它的某一个模块;它实现了很优雅的MVC,对不同的数据访问技术提供了统一的接口,采用IoC使得可以很容易的实现bean的装配,提供了简洁的AOP并据此实现Transcation Managment,等等

优点

   a. Spring能有效地组织你的中间层对象,不管你是否选择使用了EJB。如果你仅仅使用了Struts或其他为J2EE的 API特制的framework,Spring致力于解决剩下的问题。

   b. Spring能消除在许多工程中常见的对Singleton的过多使用。根据我的经验,这是一个很大的问题,它降低了系统的可测试性和面向对象的程度。

   c. 通过一种在不同应用程序和项目间一致的方法来处理配置文件,Spring能消除各种各样自定义格式的属性文件的需要。曾经对某个类要寻找的是哪个魔法般的属性项或系统属性感到不解,为此不得不去读Javadoc甚至源编码?有了Spring,你仅仅需要看看类的JavaBean属性。Inversion of Control的使用(在下面讨论)帮助完成了这种简化。

  d.  通过把对接口编程而不是对类编程的代价几乎减少到没有,Spring能够促进养成好的编程习惯。

  e. Spring被设计为让使用它创建的应用尽可能少的依赖于他的APIs。在Spring应用中的大多数业务对象没有依赖于Spring。

  f. 使用Spring构建的应用程序易于单元测试。

  g.  Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实现业务接口,却不会影响调用代码。

  h. Spring帮助你解决许多问题而无需使用EJB。Spring能提供一种EJB的替换物,它们适用于许多web应用。例如,Spring能使用AOP提供声明性事务管理而不通过EJB容器,如果你仅仅需要与单个数据库打交道,甚至不需要一个JTA实现。

  i.  Spring为数据存取提供了一个一致的框架,不论是使用的是JDBC还是O/R mapping产品

Spring确实使你能通过最简单可行的解决办法来解决你的问题。而这是有有很大价值的。

缺点:使用人数不多、jsp中要写很多代码、控制器过于灵活,缺少一个公用控制器

8.       是否了解设计模式,将几种常用的设计模式的思想、并举例。

创建模式:

Factory、Prototype(原型)、Builder、Singleton

结构模式:

Facade(外观)、Proxy(代理)、Adapter(适配器)、Composite(组合)、Decorator(油漆工)、Bridge、Flyweight(享元)

行为模式:

Template、Memento(备忘机制)、Observer、Chain of Responsibility(职责链)、Command、State、Strategy(策略)、Mediator(中介者)、Interdivter(解释器)、Visitor

9.       页面重复刷新,如何解决?客户的行为是无法控制的,那如何控制客户的重复刷新导致的重复提交。

Jsp防止页面刷新表单自提交重复提交思路:

1. 提交后禁用提交按钮(大部分人都是这样做的)

2. 用javascript实现

10.   如何精确记录同时在线人数

   我们可以利用Servlet规范中定义的事件监听器(Listener)来解决这个问题,实现更准确的在线人数统计功能。对每一个正在访问的用户,J2EE应用服务器会为其建立一个对应的HttpSession对象。当一个浏览器第一次访问网站的时候,J2EE应用服务器会新建一个HttpSession对象,并触发HttpSession创建事件,如果注册了HttpSessionListener事件监听器,则会调用HttpSessionListener事件监听器的sessionCreated方法。相反,当这个浏览器访问结束超时的时候,J2EE应用服务器会销毁相应的HttpSession对象,触发HttpSession销毁事件,同时调用所注册HttpSessionListener事件监听器的sessionDestroyed方法。

  可见,对应于一个用户访问的开始和结束,相应的有sessionCreated方法和sessionDestroyed方法执行。这样,我们只需要在HttpSessionListener实现类的sessionCreated方法中让计数器加1,在sessionDestroyed方法中让计数器减1,就轻松实现了网站在线人数的统计功能。

  下面就是利用HttpSessionListener实现在线人数统计的一个例子,这个例子已经在中创软件的J2EE应用服务器InforWeb中测试通过。

  首先,编写一个简单的计数器,代码如下:

package gongfei.cmc.articles.onlinecounter;

public class OnlineCounter {

    private static long online = 0;    

    public static long getOnline() {

        return online;

    }    

    public static void raise(){

        online++;

    } 

    public static void reduce(){

        online--;

   }

}

  然后,编写HttpSessionListener实现类,在这个实现类的sessionCreated方法中调用OnlineCounter的raise方法,在sessionDestroyed方法中调用OnlineCounter的reduce方法,代码如下:

package gongfei.cmc.articles.onlinecounter;

import javax.servlet.http.HttpSessionEvent;

import javax.servlet.http.HttpSessionListener;

public class OnlineCounterListener implements HttpSessionListener {

    public void sessionCreated(HttpSessionEvent hse) {

        OnlineCounter.raise();

    }

    public void sessionDestroyed(HttpSessionEvent hse) {

        OnlineCounter.reduce();

    }

}

  再然后,把这个HttpSessionListener实现类注册到网站应用中,也就是在网站应用的web.xml中加入如下内容:

<web-app>

    ……

    <listener>

        <listener-class>

            gongfei.cmc.articles.example.OnlineCounterListener

        </listener-class>

    </listener>

    ……

</web-app>

OK,在线人数统计功能已经实现,只要在JSP页面中加入下面这样的脚本就能显示但前在线人数了:

<%@ page language="java" pageEncoding="GB2312" %>

<%@ page language="java" pageEncoding="GB2312" %>

<%@ page import="gongfei.cmc.articles.onlinecounter.OnlineCounter" %>

<html>

    <head><title>On Line Counert</title></head>

    <body bgcolor="#FFFFFF">

        On line:<%=OnlineCounter.getOnline()%>

    </body>

</html>

11.   乱码解决方案。是否遇到过?有哪些?讲解具体遇到的情形,并说出你在具体的应用中的解决方案。

1.JSP输出中文的乱码问题

所谓在jsp输出中文,即直接在jsp中输出中文,或者给变量赋中文值再输出等,这种情况下的乱码问题往往是因为没有给jsp页面制定显示中文字符的编码方式,解决办法如下:

1)在jsp页面头部加上语句<%@ page contentType="text/html;charset=utf-8"%>(在Servlet中使用httpServletResponse.setContentType("text/html;charset=utf-8"),最好同时在jsp页面的head部分加上<meta http-equiv="Content-Type" content="text/html;charset="utf-8">

2)在每次要输出中文的地方主动转换编码方式,比如要在页面中输入“中文”二字,就可以用以下的方法:

<%

   String str="中文";

   byte[] tmpbyte=str.getBytes("ISO8859_1");

   str=new String(tmpbyte);

   out.println(str);

%>

对于以上这两种方法,显然第一种方法更通用一点,只需要在一个页面中添加一次代码即可;而对于第二种方法,在每个需要输出中文的地方都需要转码,如果这样的地方很多,这将是一个繁重的工作。

2.获取表单提交的数据时的中文乱码问题

在没有加任何其他处理之前,用request.getParameter("paramName")获取表单提交中的数据,且表单数据中含有中文时,返回的字符串会呈现乱码。出现这种问题的原因是Tomcat的j2ee实现对表单提交,即以POST方式提交的参数采用默认的ISO-8859-1来处理。

解决此问题的办法有两个:

1)不修改其他配置,只是在将表单中的中文数据区出来后再转换编码,方法如语句 String str=request.getParameter("chStr");String str = new String(str.getBytes("ISO-8859-1"),"UTF-8");但这种方法只是从一个局部来考虑问题,如果这样的情况很多,就要写很多次,势必加大工作量。

2)让对所有页面的请求都通过一个Filter,将处理字符集设置为utf-8(根据自己需要也可以设置成其他的,如gb2312,gbk)。具体做法参考Tomcat的webapps/servlet-exemples目录有一个完整的例子,也可以参考其中web.xml和SetCharacterEncodingFilter的配置.

3.URL中的中文问题

对于直接通过在url中传递中文参数,如http://localhost:8080/a.jsp?str="中文"这样的get请求,在服务器端用request.getParameter("name")时返回的往往是乱码。按照以上的做法设置Filter没有用,用request.setCharacterEncoding("utf-8")的方式,仍然不管用。造成这种结果的原因是Tomcat中以get方式提交的请求对query-string处理时采用了和post方法不一样的处理方式。

解决这个问题的方法是是打开Tomcat安装目录下的/conf/server.xml文件,找到Connector块,往其中添加URLEncoding="utf-8"/>

4.数据库访问时的乱码问题

数据库中所有表的编码方式和jsp中的使用的编码要保持一致,这样做的目的可以减少不必要的编码转换问题.另外,在使用jdbc连接MySQL数据库时,连接字符串写成如下形式可以避免一些中文问题:

jdbc://mysql://hostname:port/DBname?user=username&password=pwd&useUnicode=true&character Encoding=utf-8

如果是以数据源的方式连接数据库,配置文件中使用:

<parameter>

   <name>url</name>

   <value>jdbc:mysql://hostname:port/DBname?&useUnicode=true&characterEncoding=utf-8

   </value>

</parameter>

但是如果使用一个已经存在的数据库,数据库的编码方式为ISO-8859-1,而Web应用中使用的utf-8,且数据库已经有很多重要的信息,因此不能通过更改数据库的编码方式来解决。这个时候,在往数据库中写数据时,一定要在jdbc连接字符串中加入“useUnicode=true&characterEncoding=ISO-8859-1”,这样可以顺利的王数据库写入正常的数据。但是,在将数据读出数据库时,乱码又会出现,这个时候就应该在数据取出时对其转码,可以将转码功能写为一个函数,具体实现如下:

public String charConvert(String src){

String result=null;

if(src!=null){

  try{

   result=new String(src.getBytes("ISO-8859-1"),"UTF-8");

  }catch(Exception e){

   result=null;

  }

}

return result;

}

于是,在数据库读出数据过后调用charConvert(rs.getString("colName"));这样就可以正常的显示数据库中的中文数据了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics