今天是张老师讲留言板项目,首先说一下JDBC封装的问题,其实这一点Spring已经做到了,有现成的封装例子可以使用。
为了避免每一次写JDBC连接代码的麻烦,可以考虑把这些和JDBC相关的连接或是更新查询语句全部封装到一个类里面,
资源的关闭(结果集、语句、连接等)最好也封装到这个类里面。其实finally里面是需要逐一关闭资源的,try、catch、
finally等于是成了一个JDBC语句的模板,相同的地方可以考虑封装到一个类里面,这样以后的编程人员就可以不用考虑
这种公共的JDBC语句(诸如url、driver还有创建连接、关闭资源等)了。其实这种简化开发也可以算是一种设计模式
JDBC的封装:
一般流程
DataSource ds = new BasicDataSource();
ds.setUrl(url);
ds.setDriver(driver);
ds.setUser(user);
ds.setPassword(password);
Connection cn = null ;
PreparedStatement pstmt = null ;
ResultSet rs = null ;
try
{
cn = ds.getConnection();
pstmt = cn.prepareStatement(sql);
rs = pstmt.executeQuery();
while(rs.next())
{
System.out.println(rs.getString(1));
}
}
catch(Exception e)
{
log(); //记录日志
}
finally //无论是否出现异常,这段代码都会执行,资源关闭要放在这里
{
rs.close();
pstmt.close();
cn.close();
//注意如果像上面这么写的话绝对不行,因为如果发生异常导致rs、或是pstmt或是cn为null的话,
//由于null引用无法使用方法,所以一旦try里面发生异常,finally里面的关闭资源方法肯定也会
//对应的发生异常,所以在关闭资源之前,一定要确认是否资源为null!
//应该像下面这么写
if(rs!=null)
{
try
{
rs.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
if(pstmt!=null)
{
try
{
pstmt.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
if(rs!=null)
{
try
{
rs.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
所以真正和业务相关的代码无非是下面三句而已:
pstmt = cn.prepareStatement();
rs = pstmt.executeQuery(sql);
while(rs.next())
{
System.out.println(rs.getString(1));
}
剩下的全是千篇一律的……
public class BaseDAO
{
public void executeQuery(String sql) //传入一个字符串表明按照sql语句执行一个方法
{
//这里面可以放上面写的那些代码
}
}
//上面的那个方法里面其实真正应用起来需要更改的只是
while(rs.next())
{
System.out.println(rs.getString(1));
}
=======================================
所以可以这么来定义:
public abstract class BaseDAO
{
public abstract void doResultSet(ResultSet rs);
//把对结果集的操作做成一个抽象的方法,由此这个类也不得不是抽象的了,
//以后如果有人要用这个类的话,必须继承这个抽象类,而且必须实现这个doResultSet方法
public void executeQuery(String sql) //传入一个字符串表明按照sql语句执行一个方法
{
DataSource ds = new BasicDataSource();
ds.setUrl(url);
ds.setDriver(driver);
ds.setUser(user);
ds.setPassword(password);
Connection cn = null ;
PreparedStatement pstmt = null ;
ResultSet rs = null ;
try
{
cn = ds.getConnection();
pstmt = cn.prepareStatement(sql);
rs = pstmt.executeQuery();
/*while(rs.next())
{
System.out.println(rs.getString(1));
}*/
doResultSet(rs);
}
catch(Exception e)
{
log(); //记录日志
}
finally //无论是否出现异常,这段代码都会执行,资源关闭要放在这里
{
rs.close();
pstmt.close();
cn.close();
//注意如果像上面这么写的话绝对不行,因为如果发生异常导致rs、或是pstmt或是cn为null的话,
//由于null引用无法使用方法,所以一旦try里面发生异常,finally里面的关闭资源方法肯定也会
//对应的发生异常,所以在关闭资源之前,一定要确认是否资源为null!
//应该像下面这么写
if(rs!=null)
{
try
{
rs.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
if(pstmt!=null)
{
try
{
pstmt.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
if(rs!=null)
{
try
{
rs.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
}
}
----------------------------
public class HisBaseDao extends BaseDAO
{
void doResultSet(ResultSet rs) //重写父类中的抽象方法来处理具体的业务逻辑!
{
while(rs.next())
{
out.println(rs.getString(1));
}
}
}
//这样继承后就可以使用HisBaseDao对象的executeQuery(sql)方法来实现具体的业务了,
//因为子类中已经实现了具体的doResultSet方法
于是第一个就是抽象的基类,第二个就是具体的继承实现子类,基类里面都是公共功能的封装,
具体的业务做成了抽象方法,其实所谓的公司培训就是告诉你如何继承和使用公司里面开发的基类,如此
而已,这其实就是模板设计模式,前面也说过多次的
但是上面这种模板设计是不好的,因为要多用组合,少用继承
可以改造上面的例子,使之用组合而不是继承,其实就是上面的doResultSet方法不定义成抽象的,
而是要引出一个接口,让接口去做,这也就是面向接口编程。
这其实就是让这个基类和接口去组合做事,也就是策略模式!!
public Interface ResultSetDealer
{
public abstract void doResultSet(ResultSet rs);//由于是接口,所以前面的public abstract可以省略!
}
public class MyClass implements ResultSetDealer
{
//实现doResultSet方法!
}
public class BaseDAO
{
//这样在基类中如果要实现doResultSet方法的话,我只需要传入ResultSetDealer接口的实现类的引用就OK了
//传入的实现类可以是MyClass,这样下面方法里面的doResultSet就可以让这个实现类去作了
//这就是策略模式,接口ResultSetDealer可以说是BaseDAO的合作伙伴,BaseDAO中的doResultSet方法
//是因人而异的,每个人有不同的逻辑处理,这样就需要我单独实现这个doResultSet方法,之所以使用接口
//是为了定义一个公共的模式,让大家都去遵守,因为可能有很多这种方法需要具体实现,而可以把这些方法
//按照类别来放到不同的接口中,每个接口都可以放置一类的这种需要具体实现的方法,传入的基于这个接口的引用
//可以在基类方法中调用具体的实现方法(比如doResultSet)
public void executeQuery(String sql,ResultSetDealer rsd)
{
//方法里面相同的代码我省略了
rsd.doResultSet(rs);
}
}
具体调用的时候可以这么写:
MyClass myclass = new MyClass();//在MyClass里面已经实现了具体的接口中定义的抽象方法!
BaseDAO base = new BaseDAO();
base.executeQuery("select * from table",myclass);
这样只要继承了BaseDAO,就可以了,我只需要BaseDAO的class就可以了
-----------------------------------
老师的源代码:
1 模板模式:
/*尽量使用组合,少使用继承*/
abstract class BaseDAO
{
abstract void doResultSet(ResultSet rs);
executeQuery(String sql)
{
DataSource ds = new BasicDataSource();
ds.setUrl(url);
ds.setDriver(driver);
ds.setUser(user);
ds.setPassword(password);
Connection cn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
cn = databaseSource.getConnection();
pstmt = cn.prepareStatement(sql);
rs = pstmt.executeQuery();
/*while(rs.next())
{
system.out.println(rs.getString(1));
}*/
doResultSet(rs);
}
catch(Exception e)
{
log();
}
finally
{
if(rs != null)
{
try{rs.close();}catch(Exception e){}
}
if(pstmt != null)
{
try{pstmt.close();}catch(Exception e){}
}
if(cn != null)
{
try{cn.close();}catch(Excetpion e){}
}
}
}
}
class MyBaseDAO extends BaseDAO
{
void doResultSet(ResultSet rs)
{
while(rs.next())
{
system.out.println(rs.getString(1));
}
}
}
class HisBaseDAO extends BaseDAO
{
void doResultSet(ResultSet rs)
{
while(rs.next())
{
out.println(rs.getString(1));
}
}
}
--------------------------------------------
2 策略模式
/*尽量使用组合,少使用继承*/
策略模式
class BaseDAO
{
executeQuery(String sql,ResultSetDealer rsd)
{
DataSource ds = new BasicDataSource();
ds.setUrl(url);
ds.setDriver(driver);
ds.setUser(user);
ds.setPassword(password);
Connection cn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
cn = databaseSource.getConnection();
pstmt = cn.prepareStatement(sql);
rs = pstmt.executeQuery();
/*while(rs.next())
{
system.out.println(rs.getString(1));
}*/
rsd.doResultSet(rs);
}
catch(Exception e)
{
log();
}
finally
{
if(rs != null)
{
try{rs.close();}catch(Exception e){}
}
if(pstmt != null)
{
try{pstmt.close();}catch(Exception e){}
}
if(cn != null)
{
try{cn.close();}catch(Excetpion e){}
}
}
}
}
interface ResultSetDealer
{
void doResultSet(ResultSet rs);
}
class MyResultSetDealer implements ResultSetDealer
{
void doResultSet(ResultSet rs)
{
while(rs.next())
{
system.out.println(rs.getString(1));
}
}
}
class Test
{
main()
{
new BaseDAO().executeQuery(
"select * from user",new MyResultSetDealer());
}
}
==================================================
Spring其实也是一样的道理
在Spring中是JdbcTemplate类,在org.springframework.jdbc包里面
构造方法JdbcTemplate(DataSource dataSource)
里面有个execute方法,
Object execute(PreparedStatementCreator psc,PreparedStatementCallback pscb)
第一个参数是个接口,里面有个方法是createPreparedStatement(Connection con),返回的是
PreparedStatement,这样就根据这个接口(PreparedStatement的生产者)就得到了PreparedStatement对象,
这就是典型的策略模式。
public class MyPsc implements PreparedStatementCreator
{
private String sql ;
public void setSql(String sql)
{
this.sql = sql ;
}
public PreparedStatement createPreparedStatement(Connection con) throws SQLException
{
return con.prepareStatement("select * from user");
}
}
这样就得到了execute方法中的第一个实现类引用,可以将new MyPsc的接口引用传给execute方法的第一个参数了
第二个参数PreparedStatementCallback用于处理PreparedStatement语句
该接口里面有个方法
Object doInPreparedStatement(PreparedStatement ps)
这就是要具体实现的处理PreparedStatement语句的方法
execute还有个重载方法叫做void execute(String sql)
注意里面的sql只能是DDL或是DML语句,也就是不可以产生结果集,这就不用处理结果集了,用这个方法就行了。
如果需要处理结果集的话,使用JdbcTemplate类里面的
query()方法里面同样有两个参数,可以具体去查看api文档!
==========================================
留言板建表
create database bbs CHARACTER SET GBK COLLATE gbk_chinese_ci; 建立数据库中文
查询create database可以找到上面的字符集定义和建库的格式
mysql>use bbs;
查一下create table
注意下面name的类型char是固定宽度为16,虽然可能会浪费存储空间,但是查询速度要快于varchar,
密码最好使用MD5算法加密(不可解密)后存储
mysql>create table bbs_user(id int AUTO_INCREMENT primary key,name char(16) not null,password char(32),
birthday datetime,phone char(20),mobile char(20),city char(20)[,primary key(id)]);
注意主键约束有两种写法,一种是在id后面写,还有一种是在所有字段都定义完成后再定义主键约束。
如果要把脚本拷贝出来的话只需要在可视化环境下单击数据库或者数据表右键中的相关选项即可将脚本拷贝到文本编辑器中去
输入help;之后可以看到/.命令的说明
如果要从脚本导入数据库脚本的话,执行如下语句即可。
mysql> /. “sql脚本的路径”
mysqldump -u root -proot bbs >c:/a.sql
也可以用上述语句将bbs数据库的脚本导出到c盘下面的a.sql脚本中去。
============================================================================================
下面使用数据源DataSource来编写注册程序
在Tomcat里面的第9项是JDBCDataSources,有详细的配置方法的说明
可以对server.xml进行配置
<Context path="bbs" docBase="bbs">
//这里面的信息可以从doc文档中拷贝来
</Context>
上面这些关于Context元素的配置还可以放到具体工程文件夹下的META-INF中去
可以在里面新建一个文件叫做context.xml,把上面的配置信息拷贝到里面去即可。
在spring-framework-1.2.7的dist目录下的spring.jar包需要导入,
然后写一个jsp页面test.jsp来测试一下数据源是否配置成功
<%
//这里把doc文档中的示例数据源代码拷贝进来,然后导入包
Context initContext = new InitialContext();
Context evnContext = (Context)initContext.lookup("java:/comp/env");//每一个JNDI前缀都不一样,根据这个前缀名选出不同的JNDI的Provider
//也就是JNDI的驱动
//context.lookup("java:/comp/env"),就像DriverManager.getConnection(url)方法中的url一样,用于选择相应的
//JNDI Provider(driver)
DataSource ds = (DataSource)envContext.lookup("jdbc/datasource"); //注意这里要和数据源的配置name相一致
JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);
JdbcTemplate.update("insert into bbs_user values(8,'zxx',md5('1234'),'1980-12-01','01051551121',null,'beijing')");
//注意上面的md5('1234')是把1234加密后存入数据库中,注意加密后的md5是16字节,32个字符
%>
============================================================================================
下午张老师去开会,不上课,自己练习,上午的那个数据源实在是没办法搞,在server.xml中配置的url后面如果加上
useUnicode=true&characterEncoding=gbk,那么我连Tomcat都无法启动,不加倒是可以正常执行插入操作,还有
一点很重要,使用数据源的时候,那个mysql的驱动必须得放到common下的lib中去,不然无法加载驱动类!!数据源
这里太糊涂……哪天让田老师好好讲讲
刚才睡了一下,起来之后脑子清醒了不少,随便翻看了一下文档,上面两个问题原来人家都在文档中解释的很清楚了…………
首先是mysql的驱动,关于这一点在Tomcat文档中有详细说明
User Guide中的 9) JDBC DataSources里面:
MySQL DBCP Example项目中有下面一段话:
0. Introduction
Versions of MySQL and JDBC drivers that have been reported to work:
MySQL 3.23.47, MySQL 3.23.47 using InnoDB,, MySQL 3.23.58, MySQL 4.0.1alpha
Connector/J 3.0.11-stable (the official JDBC Driver)
mm.mysql 2.0.14 (an old 3rd party JDBC Driver)
Before you proceed, don't forget to copy the JDBC Driver's jar into $CATALINA_HOME/common/lib.
//注意上面那句话,多余的废话不用我多说了吧……
1. MySQL configuration
---------------------------------
还有,那个url的问题,记住,凡是涉及到了url必然是jdbc驱动的事情,要找也要到具体的驱动文档中去找,
在Tomcat中去找是没有用的!
/mysql-connector-java-5.0.4/docs中的connector-j.html就是驱动帮助文档,在里面搜索datasource可以很快定位到
“1.4.1. Driver/Datasource Class Names, URL Syntax and Configuration Properties for Connector/J”
从这里开始往下找,可以在下面的属性列表上面看到这样一句话:
Note. If the mechanism you use to configure a JDBC URL is XML-based, you will need to use
the XML character literal & to separate configuration parameters, as the ampersand is a reserved
character for XML.
很清楚,如果你的url是写在XML中的,那么原来的
url="jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=GBK"
必须转为
url="jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=GBK"
才可以
也就是说原来的分隔符&必须转换为&才可以!!
也就是在server.xml的localhost的Host标签里面加上(别忘了在common/lib中放入mysql驱动以及工程中导入spring.jar)
<Context path="/BBS" docBase="BBS"
debug="5" reloadable="true" crossContext="true">
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=GBK"/>
</Context>
然后在jsp页面中就可以通过如下代码来调用Spring数据源插入数据库了。
<%
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/TestDB");
//Connection conn = ds.getConnection();
JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);
jdbcTemplate.update("insert into listitem values(13,'袁彬')");
System.out.println("插入成功了!!");
%>
=======================================================
下面是童小军从数学之美系列文章(由Google研究员吴军所写)中整理出来的一些和数学有关的“伟人”,他们研究的理论
在计算机中很实用。
数学家兼信息论的
|---祖师爷--香农 (Claude Shannon) *****
| |
| |_“信息熵”(shāng)
|
斯坦福大学--托马斯.科弗 (Thomas Cover) 教授 ****
|
|"信息论基础"(Elements of Information Theory)
|
|剑桥大学--斯巴克-琼斯
语音和语言处理大师
|
|---贾里尼克 (Fred Jelinek)
|
宾西法尼亚大学---马库斯 (Mitch Marcus) 教授 ***
|
|
贾格布森 Roman Jakobson
|
最伟大的语言学家----乔姆斯基(Noam Chomsky)
|
麦克尔 · 柯林斯 (Michael Collins) 追求完美--马库斯 (Mitch Marcus)
|
布莱尔 (Eric Brill)简单才美 ****** 和 Ratnaparkhi 以及师弟 Eisnar
统计语言模型分词
|--哈工大的---王晓龙博士
|
|
---清华大学的郭进博士--Computational Linguistics
|
---Google 的--葛显平博士---朱安博士
|
--- 孙茂松--Chinese word segmentation without using lexicon and hand
隐含马尔可夫模型来识别语音
|
|
IBM--Fred Jelinek (贾里尼克)
|
|
卡内基·梅隆大学--Jim and Janet Baker (贝克夫妇,李开复的师兄师姐)
|
|
清华--随王作英教授
离散数学
|
|--布尔代数 --布尔(George Boole) *****
|
“思维规律”(An Investigation of the Laws of Thought, on which are founded the Mathematical Theories of Logic and Probabilities)
|
|大数学家欧拉(Leonhard Euler)*****
|
|最大熵迭代算法/模型
|
达拉皮垂(Della Pietra)
|
|
BCJR 算法 --维特比算法
|库克(Cocke)和拉维夫(Raviv)
|
|--GIS 迭代算法 GIS(generalized iterative scaling)
| --孪生兄弟的达拉皮垂(Della Pietra) --迭代算法 IIS(improved iterative scaling)
|
Darroch 和 Ratcliff --数学家希萨(Csiszar)
|
微软的研究员拉纳帕提(Adwait Ratnaparkhi) *****
|
文艺复兴技术公司 (Renaissance Technologies) --贾里尼克
有限状态机程序库
|---AT&T 实验室 -- 莫瑞(Mohri), 皮瑞尔(Pereira) 和瑞利(Riley)
Google 的排序算法
|-- 康乃尔大学 --辛格、Matt Cutts ********
信息处理的很多数学手段,包括隐含马尔可夫模型、子波变换、贝叶斯网络等等,在华尔街多有直接的应用。由此可见,数学模型的作用。
1.****祖师爷--香农 (Claude Shannon) “信息熵”(shāng)
2.****斯坦福大学--托马斯.科弗 (Thomas Cover) 教授 "信息论基础"(Elements of Information Theory)
3.*****语音和语言处理大师
宾西法尼亚大学---马库斯 (Mitch Marcus) 教授
|---布莱尔 (Eric Brill)简单才美
4.离散数学
布尔代数 --布尔(George Boole) --思维规律
大数学家欧拉(Leonhard Euler)
微软的研究员拉纳帕提(Adwait Ratnaparkhi) ******
5.Google 的排序算法
康乃尔大学 --辛格、Matt Cutts ********
==============================================================================
晚上对着张老师的纠错记录好好改了一下那本书,错误还是挺多的:
张老师书的纠错记录如下:
-----------------------------------------------------------
deliberately 故意的
某人为了宣传自己的东东非常易用,就好像电视机、电冰箱等一样只要完成“从box里拿出来”这个“复杂”的动作,就可以轻而易举地使用它了。也就是说“从box里拿出它来”是你可以掌握和使用该技术的所需付出滴一切,这样就可以说这是一个或一项out-of-the-box的软件或技术了。
序言中的修改:
1.前言中的第二行“都是经过我长时间的思索”,改为“都经过我长时间的思索”,删除一个“是”
2.“扣出来了”应改为“抠了出来”
p13的">"应改为"<",即将g改为l。
p145的“给动态动态网页程序调用”改为“给动态网页程序调用”,其中多了一个“动态”。
P155页发现的问题,出版社的排版人员把所有的WEB-INF都弄成了Web-INF,把所有的web.xml文件都弄成了Web.xml文件,他们盲目地把所有单词的首字母变成大写,而不知道有些内容是大小写敏感的。
p162的“AppClassLoader负责加载应用程序的启动执行类,即当使用java命令”改为:“AppClassLoader负责加载CLASSPATH环境变量指定的路径中的类,例如,当使用java命令...”
p203的“servet.xml文件”改成“server.xml文件”
p228的“与网页文档中的中文字符的字符集编码不一致所造成的”改为“与网页文档中的中文字符的实际字符集编码不一致所造成的”,即加了“实际”两个字符。
p246的“8092”改成“8192”
p247的“它们与正文部分采用MIME格式组合在一个文件中进行存储和传输,从这个文件中可以解析出邮件正文和各个附件的内容。”改成
“它们与邮件正文部分采用MIME格式组合在一个“大”的文件中进行存储和传输,从这个“大”文件中可以解析出邮件正文和各个附件的内容。”,即增加了“邮件”、““大”的”、““大””。
p248的“而是一个要保存到本地的下载文件,这就需要通过HttpServletResponse.setContentType方法设置Content-Type头字段的值为.......,例如”改为
“而是一个要保存到用户本地的下载文件,这就需要调用HttpServletResponse.setContentType方法,将Content-Type头字段的值设置为浏览器无法直接打开的MIME类型、或者无法激活某个程序来进行处理的MIME类型,例如”,即增加了“用户”、“通过”改“调用”
p249中的“显示出图5.16所示的下载提示对话框,”。用括号在后面加一点内容,改为:“显示出图5.16所示的下载提示对话框(注意:如果浏览器中安装了一些特殊的插件,可能会出现不显示此对话框、而是直接打开下载内容的情况),”
p253中的else部分增加如下一段注释:/*改为StringBuffer类的append方法来完成下面的逻辑,程序的
运行效率将更高,建议读者自己修改一下*/
p262的图5.20和图5.21中的a改成p1,另外,“这是因为被包含的Servlet程序不能改变响应消息的状态码和响应头,如果它里面存在这样的语句,这些语句的执行结果将被忽略。”这段话要用黑体加粗。
p267页的RequestDispatcher.include改为RequestDispatcher.forward,即将"include"改为"forward"。
p303将如下两行代码移动到if里面
response.setContentType("text/html ;charset=gb2312");
PrintWriter out = response.getWriter();
p311“在其service方法中检查请求消息中是否包含Authorization头字段,如果没有的话,服务器发送401响应状态码和BASIC认证的WWW-Authenticate响应头给客户端,如果包含Authorization头字段,”改为
“在其service方法中检查请求消息中是否包含Authorization头字段。如果没有的话,则发送401响应状态码和BASIC认证的WWW-Authenticate响应头给客户端;如果包含Authorization头字段,”。
p312中有两处代码换行的问题!
p312的下行代码的前后加如下一段提示:
byte [] decodedBytes = decoder.decodeBuffer(encodedAuth.substring(6));
加注释后内容为:
/*
提示:对于BASIC验证方式,客户端把用冒号(:)分隔的用户名和密码进行Base64 编码之后传送给WEB服务器。例如,要发送用户名为“zxx”和密码为“123456”的认证信息,使用的请求头字段内容应该如下:
Authorization: Basic enh4OjEyMzQ1Ng==
*/
byte [] decodedBytes = decoder.decodeBuffer(encodedAuth.substring(6));
/*读者可以试试对于中文的用户名,下行代码该选择什么字符集进行解码?*/
p327的程序代码中的“请求头”改为“参数”。
p337中的HttpServletResponse改为HttpServletRequest
p345中的“是一个”改为“就是那个”。
p406的CookieServlet1改为LogonServlet。
p441在指点迷津部分的最后加上如下说明:
笔者后来实验发现,上面的test.jsp程序在tomcat 4.x中运行时,out.write方法抛出NullPointerException异常,但是,在tomcat 5.x中运行时,out.write方法不抛出NullPointerException异常,也不输出任何内容。
p459中的“custormBean”改为“customerBean”
p471的“如果设置了某个JSP页面的errorPage属性,那么在web.xml文件中设置的异常错误处理将不对该页面起作用。”这段话要用黑体加粗。
p484中的两处“include”被写成了“inlcude”。
p485中的RequestDipatcher. forward是可能是出版排版时加了一个空格。
-------------------------------
p311中倒数第9行的程序代码中的headerName不应该换行,建议从某个加号前开始断行。
p313中的两个图6.6应分别改为图6.8和图6.9。我的原书稿没这问题,出版社那边怎会搞成这样??!!
p516页倒数第三行多了一个<jsp:getPropperty>改为<jsp:getProperty>,其中多了一个p
p517页第6行的Javaean应写成“JavaBean”,少了一个B。
---------------------------------------------------
P485中的第7行尾和第8行头中的“获致宝”不要,原书稿是对的,出版社那边怎么加入了这几个字呢?应该检查一下您们那边的工作方式了,是什么原因导致工作中会出现这样的问题呢?
---------------------------------------------------------------------
10月5日后发现的错误(新书中还未修改过)
p344的6.8.2节中的getParameter应改为getAttribute。
p337中的“对其中的参数值都被进行了”,多了个“被”。

被折叠的 条评论
为什么被折叠?



