第一部分:
1.java中的finally不受return 影响..
2.java中exception的用处.......方法可以抛出....
3.java的工具类...及迭代...
4.Servlet使用标准的API,可被更多的Web服务器支持..
5.Servlet是单例多线程....
6.Servlet可访问Java平台丰富类库..
7.Servlet容器给Servlet提供额外的功能...如错误处理和安全..
8.在server.xml中可以修改Tomcat的默认端口....
<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> ..
9.CATALINA_HOME环境变量...设置为TomCat安装目录....
Servlet API类库:classpath=%classpath%;E:/apache-tomcat-6.0/lib/servlet-api.jar
在Servlet容器中运行时,Web应用程序的类加载器将首先加载classes目录下,其次才是lib目录下的类....如果两个目录下存在同名类,起作用的将是classes目录下的类..
web.xml文件为Web应用程序的部署描述符......包含如下的配置:SevletContext的初始化信息..Session的配置..MIME类型映射...
10.当startup启动失败,而又看不到出错信息时,可用catalina.bat.....//参数start为在一个单独的窗口中启动Tomcat,run表示在当前窗口中启动,故可以看到出错信息..
11.Tomcat体系结构(组件)....Server(整个容器)..Service...Connector...Engine...Host...Context(一个Web应用程序)....
12.Tomcat的管理程序..manager....用于管理部署Tomcat中的应用程序...
tomcat-users.xml中<tomcat-users><role rolename="manager"/><user username="hanyin" password="1234" roles="manager"/></tomcat-users>,进入manager页面中后,可以管理Web应用程序...
13.Servlet接口的几个方法:
init(servletConfig)....初始化Servlet对象,它有一个ServletConfig参数,Servlet容器通过这个参数向Servelt传递配置信息..
service(request,response).....处理请求,通过request得到客户端的相关信息和请求信息,response设置响应信息...
destroy()..getServletConfig()....getServletInfo().....
14.ServletRequest(封闭请求数据)与ServletResponse(封闭响应数据)......它们作为参数传递给service(),此方法来处理....
Request://getAttribute()...removeAttribute()...stAttribute(xx,xxx)...
getCharacterEncoding()(得到在请求正文中所用字符编码)...
getContentType()(得到文MIME类型)...
getLocalAddr()...getLocalPort().....getLocalName()....
getParameter()....getParameterNames()....getParameterValues()...
getReader()...getProtocol()...
getRemote[Addr|Port]()(得到最后一个代理ip)...getServetPort()....
setCharacterEncoding()(覆盖在请求正文中所用字符编码)
Response://flushBuffer()//(强制把任何在缓存中的内容发送到客户端)...
getCharacterEncoding()(返回在响应正文中所用的字符编码)
getContentType()(返回在响应正文中所用的MIME类型)....
setCharacterEncoding()...setContentType()....
ServletCofig://Servlet容器在Servlet初始化期间向ServletConfig传递配置信息....一个Servlet只有一个ServletConfig对象..
getInitParameter("name")....getServletContext()....
15.GenericServlet.......init(){super.init(config);.......} 当调用init(config)时,系统会自动把参数传递进来....
16..HttpServlet....
两个Service()方法....第一个把参数转换后传递给第二个方法...第二个再根据请求类型调用相应的doXxx()方法.....所以,我们只需要重写相应的doXxx()方法.....
HttpServletRquest: getCookies().....
getSession()//得到和此请求相关的Session如果没有,则他一个新的Session....
getSession(true/fals有e)........getQueryString()....
getRequestURI()...getRequestURL()...
HttpServletResponse: addCookie()....encodeRedirectURL()....encodeURL()....
sendError()....sendRedirect()....setStatus().....
17.HttpServlet....
response.setContentType("text/html; charset=gb2312");
//设置MIME,字符编码.....html与;之间不能有空格..
必须在
out=response.get.gtWriter(); //默认为ISO-8859-1.....
之前....
18.GET与POST:
通常当表单使用get方法时,提交的内容被作为URL参数,如登录时:
输入用户名密码后提交后.........
http://218.198.237.36/MySite/welcome?username=hanyin&password=1234
Post方法则不然...提交数据作为正文的内容发送到服务器端...
19.Servlet异常: ServletException与UnavailableException...
20.Servlet生命周期:
加载与实例化:程序员不应提供带参构造方法...Servlet容器启动后要知道类Servlet在什么地方,成功加载后,调用默认构造方法创实例..
初始化: 实例化后,容器调用init()方法.....初始化期间,实例可以用容器为它准备的ServletConfig对象从应用程序配置信息(在web.xml中配置)中获取初始化的参数信息..
处理请求:service()方法处理请求...当执行期间,发生错误,则抛出异常...
服务终止:释放资源..
21.Servlet上下文_________ServletContext:
ServletContext:是Web服务器中一个已知路径的根,如 webapps/MySite,它可以与Servlet容器通信,如得到文件的MIME类型,转发请求,或者向日志写入消息....它与一个应用程序的所有文件关联..
对共享属性操作:getAttribute()....setAttribute()....removeAttribute()...任何一个Servlet都可以设置某个属性...
getInitParameter()//Web上下文参数可以被所有的Servlet使用......web.xml中的
<context-param>中设置...
getMimeType()....getRquestDispatcher()....log().....
22.请求转发:RequestDispatche......
该对象可由 ServletContext接口的 getRequetDispatcher()得到....
方法:
forward(request,response)....//对请求作初步处理后,调用此方法,但是必须在响应客户端之前调用,在forward()之后,原先在响应缓存中的东西被自动清除...
include(request,response)....//在响应中包含其它资源的内容______被调用的Servlet对请求作出响应,并且,该响应会被并入原来的响应之中_______<jsp:include >与此对应...
23.<Context path="/xxx" docBase="D:/xxx/xx/xxx" reloadable="true"/>
//若在 ROOT下,则path="".....reloadable="true"时,Tomcat自动监视Servelt的改动....
(META-INF/context.xml中配置...也可在localhost下的 mysite.xml中配置....也可在server.xml中配置,但是不建议,因为这个文件只读取一次,当有改动时,不起作用....)
24.打包成war文件...在 mysite下......jar -cvf mysite war * //查看: jar -tf mysite.war
注意:在打包之前,要建立正确的Web应用程序的目录层次结构:WEB-INF...classes..lib(jar)....web.xml....META-INF
25.Servlet的配置原则:
(1).尝试对路径与映射进行精确配置..
(2).尝试最长路径前缀...
(3).如有扩展名,试着匹配有这个扩展名的Servlet.
(4).调用默认的Servlet...如没有则404..Over!!!
部署: /* , *.jsp ,*.do ,/
26.数据库:
//加载JDBC驱动是调用Class类的static方法forName()向其传递要加载的JDBC类名,类加载器找到这个类后加载该类.
//在加载之后,需要注册驱动程序类的一个实例....DriverManager类是驱动程序管理器类,负责管理驱动程序,这个类中所有的方法都是
静态的.....在这个类中提供了registerDriver()来注册实例,但是通常这个方法不需要主动调用,因为这个类包含注册的表态代码..
当这个类被加载时(Class.forName("类名")),类加载器会执行该类的静态代码,从而注册一个实例....
如: class Driver extends...implements...{
....static{ DriverManager.registerDriver(new Driver() ); } ....}
}
即: Class是管理类的, DriverManager是管理驱动的..
import java.io.*; //IOException,PrintWriter....
import java.sql.*;
import java.servlet.ServletException;
import javax.servlet.http.*; //HttpServlet,request,response..
Class.forName("com.mysql.jdbc.Driver"); //可设置成抛出ClassNotFoundException异常....加载失败.
Connection conn=DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement();
stmt.executeUpdate(" ");
Resultset rs=stmt.executeQuery(" ");
数据的批处理操作. addBatch()..
executeQuery()....executeUpdate()....executeBatch()....
ResultSet的操作...
next()....getInt()...getString()....getDate()....getTime()....getTimestamp()...getFloat()...
在这些方法中,又提供了两种形式调用:一种以列索引(从1开始),另一种是以列名...作为参数..
getString(int columnIndex)....getString(String columnName)....getDate()....getObject()..
PreparedStatement pstmt=conn.prepareStatement("....?,?,....?,......?...");
pstmt.setInt(1,10);
pstmt.setFloat(2,10.0f);
pstmt.setString(3,"ok,how are you");
pstmt.setDate(4,java.sql.Date.valueOf("2004-5-8"));
pstmt.executpUpdate();
//还可以 通过循环 pstmt.addBatch()...然后一次执行,以减少执行时间...
SQL数据与java数据类对应...
几个特殊的...java.math.BigDecimal....java.sql.Date[Time,Timestamp,Blob,Clob,Array]
CallableStatement://用于SQL存储过程..
事务处理:保证所有的事务都作为一个单元来执行...要么完整提交,要么整个事务回滚......
conn.setAutoCommit(false); conn.rollback(); conn.commit();
事务隔离:并行的多个事务之间进行分离...避免污染(脏读[读到一个没有完成修改的数据],
不可重复读[另一个事务修改了此事务已经读取的数据,这样同一事务两次读取的内容不同],
幻读[一个事务读取完成以后,再次读取时,另一事务已经插入了一行])..
conn.setTransactionIsolation();
可滚动和可更新结果集:
last()...absolute()....isLast()...next()....previous()...
JDBC数据源和连接池.
DataSource接口由数据库供应商来实现....
利用数据源,不需要在客户程序中加载JDBC驱动,也不需要使用DriverManager类....只需要向JNDI服务器查询来得到DataSource对象,
然后利用DataSource对象的getConnection()方法来建立数据库的连接.
....
javax.naming.Context ctx=new javax.naming.InitialContext();
javax.sql.DataSource ds=(javax.sql.DataSource)ctx.lookup("java:comp/env/jdbc/bookstore");
java.sql.Connection conn=ds.getConnection();
...
conn.close();
javax.naming.Context 表示一个命名上下文,在这个接口中,对义了将对象和名字绑定,以及通过名字查询对象的方法.
ctx.lookup()是在ctx上下文中查询数据源..
DataSource的实现:产生连接....连接池实现......分布式事务实现..
<Context ....><Source name="jdbc/bookstore" auth="Container" .............................. /></Context>
27.会话跟踪:会话(区别用户)+状态(记住前面请求信息).
java Servlet API用Session来跟踪会话和管理会话内的状态.
通过在第一个请求和响应中包含Session ID,服务器就可以把一个用户与另一个用户区别开..
传递Session的方法: Cookies 或 URL重写.
Cookies存储在内存或硬盘中.
服务器用响应报头 Set-Cookie 来发送 Cookie信息...如:
Set-Cookie: NAME=Jsessionid; [Comment=value;] Domain=value; Max-Ag=value; [ Path=value;] [Secur;] Version=1*DIGIT
URL重写:把Session ID作为URL字符串中的路径参数..
每有一个会话请求,Servelt容器就创建一个HttpSession对象,有了这个对象之后,就可以利用这个对象来保存客户的状态信息..并且这个Session有一个唯一的Session ID,Servlet容器将其作为Cookie(或URL一部分)发送给浏览器,浏览器将在内存中保存这个Cookie...客户再次请求时,浏览器将Cookie随请求一起发送........servlet 容器又由Session ID来找到对应的Session对象..从而得到客户的状态信息.
整个过程都是透明的,开发人员只需得到Session对象,然后调用setAttribute()或 getAttribute()..
Session: getAttribute()...rmoveAttribute()....getId()...isNew()...getSession()//返回与请求相关的session...invalidate()..
Cookie: getName()....getValue()//value是以: name1-value1&name2-value2形式的..
如: cookie=new Cookie("userinfo","user-hanyin&pwd-1234");
cookie.setMaxAge(-1); //当浏览器关闭时,Cookie会被删除..在内存中..
resp.addCookie(cookie);
得到Cookie: cookies=req.getCookies();
for(.....){
cookie=cookies[i];
cName=cookie.getName();
if(cName.equals("userinfo"){
cValue=cookie.getValue();
String [] userInfo=cValue.split("&");
.......
}
}
共享Cookie只能在一个进程中....
Session只是在超出了一定时间才消失....
会话跟踪的Cookie: request.doGetSession();
//由于设置了cookie.MaxAge(-1);故只能存储于内存中..
{实现片段:
cookie=new Cookie(Globals.SESSION_COOKIE_NAME,session.getIdInternal());
......
response.addCookieInternal(cookie);
}
Session持久化,要求session及session内的对象实现 Serializable接口....
28:异常处理:
可以将所有的异常交给一个页面处理..
...
catch(exception ec){
req.setAttribute("java.exception",ae);
req.setAttribute("java.exception_uri",req.getRequestURI());
RequestDispatcher rd=req.getRequestDispatcher("Exceptionpage");
rd.forward(req,resp);
}
//Exceptionpage:
String uri=(String)req.getAttribute("java.exception_uri");
Object excep=req.getAttribute("java.exception");
28.线程安全: 线程池,管理线程....(连接池)...
可在server.xml 中<Connector>元素设置线程池中线程数目....
变量的线程安全....如 conn.......第一次关闭后没有设置为null导致...两次关闭...
属性的线程安全: 如 application(不同用户对同一数据的操作)....session(同一用户不同页面的操作)...
29.JSP技术: 是建立在Servelt规范功能之上的网页技术..
ServletContext......对应于........application
PageContext.........对应于........pageContext
config,session,out.....都可以由pageContext来得到....
指令元素: <%@ page|include|taglib ....%> //taglib用于自定义标签..
脚本元素:声明: <%! int i=1; %>
对应的XML <jsp:declaration> declarations </jsp:declaration>
脚本段: <% xxxx; %>
表达式: <%= i %>
动作元素: 为请求处理阶段提供信息......标准动作是一些标签,由JSP容器来实现...当在转换成Servlet期间,jsp窗口遇到这个标签时,就用预先定义好的java代码来替代它....//可在work目录下查看对应的 Servlet代码...
jsp 中定义了20个标准的动作:
<jsp:useBean>,<jsp:setProperty>,<jsp:getPropety>
<jsp:param>.......//可用于include ,forward,plugin标签中..
<jsp:include page="..." flush="true|false"/> //在当前页面中包含资源,一旦被包含的页面执行完毕,请求处理将在调用页面中继续进行.....被包含的页面不能设置响应的状态代码和报头...
注意其与<%@ include file="..." %>的区别:
1.调用时间不同,2.被调用相对路径,一个是相对于page,一个是file..
JSP隐含对象及对应的类型:
pageContext: getAttribute("name",scope); //得到scope范围内的对象..
exception: 异常....当有isErrorPage=true的页面(错误页面)中才可以使用....
30.留言板,创建可滚动结果集:
stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
得到总行数: rs.last(); int rowCount=rs.getRow();
得到总页数: pageCount=(rowCount+countPerPage-1)/countPerPage;
游标到第一行: rs.absolute((curPage-1)*countPerPage+1);
显示: i=0; while(i<countPerPage&&!rs.isAfterLast()){.......}
上/下页: <a href="show.jsp?page=<%curPage-1%>">下一页</a>
31.jsp文档:采用xml语法编写 jsp页面....效果与标准jsp语法相同,但是没有必要,可在MIME类型中指定文档类型..
32.JSP与JavaBean:
JavaBean:封闭业务逻辑......本质上是一个java类....
在Jsp页面中
<useBean id="operatedb" scope="application" class="xxx.xxx.xxx.OperateDB"/>
则 operatedb是一个对象名.....
可在此页面中操作此对象的方法.......
33.网上书店,购物车的实现:
//图书类:
BookBean:
BookBean(int id,String title,String author,String publish_date,float price,int amount,String remark)//有get/set方法..
//购物车中条目类: //计算出总价格,设置数目..
CartItemBean: book,quantity: CartItemBean(book), get/setBook, get/setQuantity..
//购物车类:增加,删除,清除,计算车中图书总数,设置某本书数目,所有图书的价格,所有书的条目,判断某本书是否已经在车中...
CartBean:
HashMap<Integer,CartItemBean>items=null, int numOfItems=0;
deleteItem(),addItem(),setItemNum(),getTotalPrice(),getItems(), isExist().
//数据库类:
BookDBBean:
BookDBBean(){
Context ctx=new InitialContext();
ds=(DataSource)ctx.lookup("java:comp/env/jdbc/bookstore");}
getConnection(),
closeCollection(conn);
closeSttement(stmt);
closePreparedStatement(pstmt);closeResultSet(rs);
//得到所有图书信息:Collection<BookBean> getBooks();
//得到选择的图书信息: BookBean getBook(bookId);
//通过关键字搜索图书: Collection <BookBean> searchBook(keyword)
//判断剩余图书是否大于购买数量: isAmountEnough(bookId,quantity);
//购买购物车中图书: buyBooks(cart) ;
//用pstmt且 pstm.addBatch(); 最后 pstm.executeBatch();
34.技巧:如何提交某一页面后,在同一页面中处理并且返回同一页面?
如:一个作为显示作用的表单.....修改某一项后,保存修改...(即时显示)
String action=request.getParameter("action");
if(action!=null&&action.equals("保存修改")){
....
itemNum=Integer.parseInt(strItemNum);
for(int i=0;i<itemNum;i++){
strNum=request.getParameter("num_"+i);
strBookId=request.getParameter("book_"+i);
int quantity=Integer.parseInt(strNum);
int bookId=Integer.parseInt(strBookId);
//然后对这一项进行操作...bookid,设置数量...
}
//.....
// 在 form中显示:
int i=0;
whie(it.hasNext()){
cartItem=(CartItemBean)it.next();
BookBean book=cartItem.getBook();
int bookId=book.getId();
String fieldNum="num_"+i;
String fieldBook="book_"+i;
<input type="text" name="<%=fieldNum%>" value=<%=cartItem.getQuantity()%> size=2 />
<input type="hidden" name="<%=fieldBook%>" value="<%=bookId%"> />
//注意:这个隐藏对象传递显示的图书的ID
35.文件的上传与下载:
可以上传到服务器的硬盘目录或数据库中,也可以在目录或数据库中下载....request.getInputStream().
36.中文乱码问题:
常用字符集: ASCII(128种) ISO-8859-1(包含ascii ,256种) GB2312(字节最高位为1,GBK的子集) Unicode UTF-8(1,2,3byte)..
乱码原因: java内部使用Unicode....java在读取数据时,将本地字符集编码的数据转换为Unicode编码,而在输出时,将Unicode转换为本地字符集编码......
例如:在中文系统下,读取"中",实际读取GBK码0xD6D0,在java中转换成0x4E2D,此时内存中"中"对应0x4E2D,当输出到控制台时,java将Unicode编码再转换到GBK码,中文系统再根据GBK字符集画出相应的字符...
Java中,不同字符集编码的转换,都是通过Unicode编码作为中介来完成的..
如:GBK--->ISO-88591 GBK---->Unicode----->ISO-8859-1
中: GBK: 0xD6D0--->Unicede : 0x4E2D 但是 0x4E2D在ISO-8859-1中无对应编码...于是得到0x3f....即"?"
当从Unicode编码向某个字符集转换时,如果在该字符集中没有对应的编码,则得到 0x3f即 "?",这就是为什么我们有时输入中文,却得到了问号...
从其它字符集向Unicode转换时,如果这个二进制数从在该字符集中没有标识任何的字符(即不在范围内),则得到的结果是0xfffd... 如:GBK编码 0x8140,从GB2312向Unicode转换,然后0x8140不在GB2312字符集范围内,故无对应字符...所以转换
浏览器会根据本地系统默认的字符集来提交数据,而Web容器默认采用ISO-8859-1解析POST数据,在浏览器提交后Web容器采用ISO-8859-1将接收的二进制数转换为Unicode编码,在Web应用中按照Unicode处理(即调用getParameter(),得到)后,再输出到response,输出时默认ISO-8859-1,当有指定时调用指定字符集进行转换...如:
浏览器:"中"(GB2312 0xd6d0)------------->Web容器:使用ISO-8859-1转换成(Unicode /u00d6/u00d0)[ new String(buf,"ISO-8859-1");]------->在应用程序中getParameter():得到/u00d6/u00d0---->输出到浏览器:
A.没有指定字符集: 默认ISO-8859-1, "/u00d6/u00d0".getBytes("ISO-8859-1"),得到ISO-8859-1编码 0xd6d0,在浏览器中以中文查看正好是GB2312的 0xd6d0
B.指定字符集GB2312: "/u00d6/u00d0".getBytes("GB2312") ----> ? ?[因为这两个编码在GB2312中都无对应编码]
//:注意: 其它字符集向Unicode转换时, ISO-8859-1向Unicode则是byte(1)-->char(2byte), 反过来: char(2byte)---byte(1)
GB2312 向 Unicode 时, 2byte<----------->2byte.
37.中文乱码解决方案:
buf=str.getBytes("ISO-8859-1");//把字符串,转换成进制数...(找到对应编码).. new String(buf,"gb2312");//把二进制数转换成gb2312..两个字节..
1.POST方法:
由于Web容器默认编码为ISO-8859-1,所以在应用中request.getParameter()方法得到的字符串是ISO-8859-1转换而来的....这就是乱码原因之一.........
为了避免容器以ISO-8859-1返回字符串,对于POST正文,可在获得请求参数之前,调用request.setCharacterEncodeing("gb2312");向浏览器发送之前,指定输出内容的编码方式 是 GB2312.... response.setContentType("text/html;gb2312");
2.GET方法:
String name=request.getParameter("name");
//对于"中" 得到(通过iso)转换成unicode后的 /u00d6/u00d0
name =new String(name.getBytes("ISO-8859-1"),"gb2312");
工具方法:
public String toGB2312(String str)throws java.io.UnsupportedEncodingException
{
return new String(str.getBytes("ISO-8859-1"),"gb2312");
}
3.数据库中读取中文: 只需要把数据库字符集改为: GBK或gb2312....
java程序和数据库之间传递数据都是以Iso-8859-1为默认格式的...
所以,中文传递:
提交gb2312---->(gb2312----->Unicode)----->iso-8859-1(java数据库驱动)------>数据库(iso-8859-1---->设定字符集) 出现问题..
//通过过滤器处理乱码问题:
38.文件上传.
form中 ENCTYPE="multipart/form-data"
对于读取文件中内容,要用request.getInputStream()得到输入流....//具体实现请参照RFC1867
利用commons-fileupload... lib: (commons-fileupload-xxx.jar , commons-io-xxx.jar )
主要的三个类:FileItem,DiskFileItemFactory,ServletFileUpload.
ServletFileUpload负责处理上传的文件数据,并将每部分的数据封装到一个FileItem对象中..
DiskFileItemFactory是创建FileItem对象的工厂类,在这个工厂中可配置内存缓冲区大小和存放临时文件的目录.
ServletFileUpload在接收上传文件数据时,会将文件内容保存到内存缓冲区中,如果文件内容超过到指定缓冲区大小,那么文件会保存在指定的临时文件,等文件数据都接收完毕后,ServletFileUpload再从临时文件中将数据写入到上传文件目录下的文件中..
FileItem接口中定义的主要方法:
byte[]get()//返回文件数据据项的内容..
getContentType(),getFieldName() //返回文件数据项对应的表单中字段名字,getInputStream(),getName(),
getOutputStream(),getSiz(),getString(),getString(charset),isFormField()//判断是否表示了一个简单表单字段..
write(file)//将文件内容写到硬盘上..
//示例:
DiskFileItemFactory itemFactory=new DiskFileItemFactory();
itemFactory.setSizeThreshold(0x80000); //设置内存缓冲区512K
File tempDir=new File("E://temp"); //临时文件夹.
if(!tempDir.exists()){
tempDir.mkdir();
}
itemFactory.setRepository(tempDir); //设置存储的临时文件目录..
ServletFileUpload sfu=new ServletFileUpload(itemFactory);
sfu.setSizeMax(0xA0000); //设置上传文件的最大数据量为10M
List fileItems=sfu.parseRequest(request); //解析得到的FileItem对象的列表..
Iterator it=fileItems.iterator();
@@
while(it.hasNext()){ //依次处理每个上传的文件... //此时文件已经传递到临时文件夹中了..
FileItem item=(FileItem)it.next();
if(!item.isFormField()){
long size=item.getSize();
if(name==null||name.equals(""))&&size==0)continue;
out.println(item.getName());
out.println(item.getSize());
File uploadFileDir=new File("E://UploadFile"); @1
if(!uploadFileDir.exists())uploadFileDir.mkdir(); @2
int index=name.lastIndexOf(File.separator);
if(index>0)name=name.subString(index+1,name.length());//取出文件名.
File file=new File(uploadFileDir,name); @3
item.write(file); @4
}
else{
out.println(item.getFieldName());
out.printn(item.getString("gb2312"));
}
}
//注:以下是把文件存储到数据库中:
数据库中表为: id ,filename,filesize,data(MEDIUMBLOB类型)
大部分处理都是一样的,不一样的为:
@@处加上:<配置数据源连接>
pstmt=conn.prepareStatement("insert inot uploadfile(filename,filesize,data) values(?,?,?)");
去掉@1,2,3,4.
在@4处改为:
pstmt.setString(1,name);pstmt.setInt(2,(int)size);
InputStream is=item.getInputStream();
pstmt.setBinaryStream(3,is,(int)size); //往数据库中写二进制大对象的方法setBinaryStream(索引,输入流,字节数);
pstmt.executeUpdate();
is.close();
39.文件下载:
注意,不要用Jsp文件实现下载,因为在下载充分反映地,我们利用的是ServletOutputStream sos=response.getOutputStream(),得到二进制输出流,Jsp页面有一个隐含的输出流对象out,其类型是Writer,这样会造成冲突.....
//在对客户端的输出中,要么使用二进输出,要么和字符输出,二者不可混用..
文件的安全,可以利用程序实现下载,把文件放在Web以外的目录中,也可以放在数据库中..
设置报头:
Content-Type:application/x-msdownload
Content-Disposition:attachment;filename=downloadfile
Content-Length:filesize
浏览器在接收到上述的报头后,就会弹出"文件下载"对话框....
//例:
String strId=request.gtParameter("id");
if(null==strId||strId,equals(""))return ;
File file=null;
InputStream is=null;
String fileName=null;
int fileSize=0;
//对于硬盘下载:
if(strId.equals("111")){
file=new File("D://tomcat.exe");
is=new FileInputStream(file);
fileName=file.getName();
fileSize=(int)file.length();
}
else{
int id=Integer.parseInt(strId);
try{
conn=ds.getConnection();
pstmt=conn.prepareStatement("select * from uploadfile where id=?");
pstmt.setInt(1,id);
rs=pstmt.executeQuery();
if(rs.next()){
fileName=rs.getString("filename");
fileSize=rs.getInt("filesize");
is=rs.getBinaryStream("data"); //读二进制数据...
}
}
//设置报头:
response.setContentType("application/x-msdownload");
String str="attatchement;filename="+fileName;
response.setHeader("Content-Disposition",str);
response.setContentLength(fileSize);
//得到响应的输出流:
ServletOutputStream sos=response.getOutputStream();
byte[]data=new byte[2048];
int len=0;
while((len=is.read(data))>0){
sos.write(data,0,len); //向浏览器输出文件数据..
}
is.close();
sos.close();
//......数据库的关闭..
40.下载时,中文文件名的问题.
下载时,如果下载的文件名中有中文字符,则乱码......要解决这个问题,只需要对下载的盲人摸象中按照UTF-8编码..IE就能正确显示了..
public static String toUTF8String(String str){
StringBuffer sb=StringBuffer();
int len=str.length();
for(int i=0;i<len;i++){
char c=str.charAt(i);
if(c>=0&&c<=255)sb.append(c);
else{
byte [] b;
try{
b=Character.toString(c).getByts("UTF-8");
}
catch(UnsupportedEncodingException ex){
System.err.println(ex);
b=null;
}
for(j=0;j<b.length;j++){
int k=b[j];
if(k<0)k&=255; //保持原来b[j]的内容....去掉int高字节的1..
sb.append("%"+Integer.toHexString(k).toUpperCase());
}
}//else
}//for
return sb.toString();
}
//对于0~255之间Unicode不做任何处理,对于其它的先转换成UTF-8,然后再转换成%HH字符串形式....?????
fileName=toUTF8String(filename);
41.HTTP.
请求: 请求行+ 消息报头 + 请求正文
例:(GET/form.html HTTP/1.1 (CRLF))+( ...... )+(CRLF空行)+(user=zhangsan&pwd=1234)
响应: 状态行+ 消息报头+ 响应正文
例:(HTTP/1.1 200 OK (CRLF) )+(.....)+(CRLF空行)+(<html>.....</html>)
HTTP消息:开始行+消息报头+空行+消息正文
42.避免表单的重复提交.
43.给图片添加水印和文字..
图片格式JPEG,水印图片:gif或JPEG
InputStream is=rs.getbinaryStream(data);
//通过jpeg图像数据输入流创建jpeg数据流解码器.
JPEGImageDecoder jpegDecoder=JPEGCodec.createJPEGDecoder(is);
//解码当前jpeg数据,返回BufferedImage对象
BufferedImage buffImg=jpegDecoder.decodeAsBufferedImage();
//得到Graphics对象用于输出绘图和文字.
Graphics g=buffImg.getGraphics();
//创建Icon对象,将logo.gif作为水印
ImageIcon imgIcon=new ImageIcon("F:/logo.gif");
//得到Image对象
Image img=imgIcon.getImage();
//将水印画到图片上.
g.drawImage(img,80,80,null);
g.setColor(Color.RED);
Font font=new Font("Courier New",Font.BOLD,20);
g.setFont(font);
g.drawString("http://风韵");
//释放图形上下文使用资源.
g.dispose();
response.setContentType("image/jpeg");
ServletOutputStream sos=response.getOutputStream();
//创建编码器,将内存中图像数据输出到JPEG数据输出流
JPEGImageEncoder jpgEncoder=JPEGCodec.createJPEGEncoder(sos);
//编码BufferedImage对象到输出流.
jpgEncoder.encode(buffImg);
is.close();
sos.close();
44.过滤器:对用户进行统一验证,请求和响应数据的替换..
45.Servlet的监听器.
46.JSP表达式语言,标签库..
第二部分
<Context>元素:可在server.xml, conf/context.xml, conf/xxxx/localhost/context.xml.default, localhost/xxx.xml, xxx/META-INF/context.xml中.
<servlet>的子元素:icon, init-param,jsp-file,servlet-class,.....
这个文件是直接解压得到的,不是安装的..
首先要配置:java_home,jre_home...............即jdk 与 jre目录.
startup.bat 实际上是 catalina.bat start
当启动出错时,catalina.bat run可以查看出错信息.
jdk中要用的类+Tomcat中的类
在webapp下的每一个目录都是一个web应用..
并且目录组织形式为: mysite{ web-inf{classses (.class) ,lib(.jar) ,web.xml }, index.jsp }
注意:web-inf是无法被客户端访问的..
Servlet容器运行时,Web应用程序首先加载classes目录下的,其次是lib目录下的.
Servlet 的几种形式:
Servlet--------GenericServlet------HttpServlet
//它们存在一种继承机制.................
//在HttpServlet 中,由于请求URL都是GET方法,故,实现doGet()即可...
JSP:
指令(page,include,taglib),脚本(声明,脚本段,表达式),动作.
<%@include %> 与 <jsp:include />
jsp隐含对象及其类型.....
MySql 配置: 安装,驱动..
对于一个项目,不但要有...,而且在 localhost下要有 "项目名.xml" 的配置文件...
重装时,不但要删除my.ini文件,也要删除 MySQL Server 5.1/data
web.xml中 servlet 最好在 servlet-mapping 之前.....
//配置很重要:
当web.xml 中 sevlet-mappting 中有一个不存在的 Servlet时,这个Web程序就不能启动...
让Tomcat自动加载修改过的Servlet类: reloadable="true"
Enumeration headNames=req.getHeaderNames();
ServletContext :Servlet上下文 ......Servlet容器在Web应用程序加载时创建ServletContext对象,作为Web应用程序的运行时表示,ServletContext对象可以被Web应用程序中所有的Servlet所访问.
//context.getAttribute("counter"); 当第一次访问时,还没有这个属性,故会返回null
//context.setAttribute("counter",count);
//RequestDispatcher........//用于封闭一个由路径所标识的服务器资源.
sendRedirect()与forward()的区别.
web配置:
config/server.xml 中:
<Context path="/MySite" docBase="F:/JSP/../MySite" reloadable="true" />
JDBC驱动程序4种类型 : JDBC-ODBC桥, 部分API部分Java驱动程序,JDBC网络JAVA驱动程序,本地协议纯Java驱动程序.
JDBC操作数据库:加载数据库,获取连接,访问数据.
Statement,PrepaedStatement,ResultSet,CallableStatement.
JSP: 注意,有<%@ page contentType="text/heml;charset=gb2312" %>时,网页有时打不开,而是直接下载...... 是因为设置响应JSP页面的mime类型错误.....
//初始时,ResultSet对象的游标在第一行之前...故要调用一次next().
//注意,在sendRedirect()之后,要用return结束当前方法.
PreparedStatement: ps=con.prepareStatement("insert employee values(?,?,?)"); ps.setInt(1,2);ps.setString(2,"han");ps.seDate(3,java.sql.Date.valueOf("2004-5-8")); ps.executeUpdate();
//存储过程与元数据.
executeQuery();
executeUpdate();
execute();
executeBatch();
rs.getXxx():
getInt().getDate().getTime();getTimestamp().getString().
//using mysql in batch model. ????
// select database();
CREATE TABLE shop (
-> article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
-> dealer CHAR(20) DEFAULT '' NOT NULL,
-> price DOUBLE(16,2) DEFAULT '0.00' NOT NULL,
-> PRIMARY KEY(article, dealer));
mysql> INSERT INTO shop VALUES
-> (1,'A',3.45),(1,'B',3.99),(2,'A',10.99),(3,'B',1.45),
-> (3,'C',1.69),(3,'D',1.25),(4,'D',19.95);
SELECT * FROM shop;
mysql:
mysql -u root -p 1234
show database;
use xxx;
show tables;
describe tables;
//事务处理:保证所有事务作为一个工作单元来执行....要么所有都完成,要么返回到原来状态.
//setAutoCommit(false)取消自动提交事务.所有SQL成功执行后,调用commit()方法来提交事务,出错时,调用rollback()回滚.
//事务隔离:并行事务......隔离级别.
脏读(一个访问并修改,但是没有提交,另一个读取了这个数据,或前一个发生回滚),
不可重复读(一个事务内读取两次数据,并不同),
幻读(第一个事务读取了满足条件所有行后,第二个事务加了一行数据,当它再次读取时,多了一行数据).
设置级别:
setTransactionIsolation().
//当结果集中只有一条时,也要调用next()才行...
//可滚动,.
supportsResultSetType();
createStatement(xxx,xxx);
//可更新结果集
updateXxx().
updateRow();
//jdbc数据源和连接池.
//数据源: DataSource......可以看成是连接工厂.
javax.naming.Context ctx=new javax.naming.InitialContext();
//表示一个命名上下文,定义了将对象和名字绑定,以及通过名字查询对象的方法.
//jdbc子上下文保留给JDBC数据源使用. java:com/env是环境命名上下文.
javax.sql.DataSource ds=(javax.sql.DataSource)ctx.lookup("java:comp/env/jdbc/book");
java.sql.Connection conn=ds.getConnection();
....
conn.close();
conn=null;
localhost/ch04.xml .......
<Context docBase="F:/JSPLesson/ch04" reloadable="true">
<Resource name="jdbc/book" auth="container"
type="javax.sql.DataSource"
maxActive="100" maxIdle="30" amxWait="10000"
username="root" password="1234"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/book?autoReconnect=true"/>
</Context>
//因为种种原因我们是用Tomcat提供的数据源实现来访问MySQL,因为种种原因要将MySQL的JDBC驱动复制到Tomcat的lib中,要明确的是,
是Tomcat需要JDBC驱动,而不是应用程序需要JDBC驱动.
//webapps目录下的web应用程序会被Tomcat自动加载......故不需要<context>的docBase属性指出Web应用程序根目录.
//当Web程序直接在Webapps目录下时,如何配置JDBC数据源...
<context>也可以在META-INF\context.xml中设置....
如webapps/JSP/ , webapps/JSP/META-INF/context.xml
会话跟踪:
1.如何会话.....识别单个用户的一系列请求.
2.状态............记住前面请求的信息.
三种机制:SSL,Cookies,URL重写
Session: 保存在服务器端,对于用户和开发人员都是透明的........
//传递Session ID可由URL重写和Cookie实现
//服务器会同时采用这两种机制
//当Cookie可用时,如已经访问某web程序,则再次发送的消息报头会存在Session ID...
//当使用URL重写时,url会带参数session id...
//通过传递到服务器的session id,服务器识别出对应session对象,从而可以设置用户状态..
//若使用invalidate(),用户与服务器会失去这个session id联系....服务端删去此session...
HttpSession session=req.getSession();
session.setAttribute("xxx",value);
param=(String)session.getAttribute("xxx");
///对于用户禁用Cookie时,可以用 URL重写机制跟踪用户会话..
只须 对向用户客户端发送URL链接的代码作如下修改..
action=resp.encodeURL("a url")
resp.sendRedirect(resp.encodeRedirectURL("a url ");
//encodeRedirectURL()和encodeURL()都是在 url 上加上session信息,达到 url重写的目的...
//注意: 服务器会同时采用这两种机制: 在响应中发送Set-Cookie报头,同时会向URL附加Session ID(假设这个URL采用了response.encodeURL()进行编码.
<form method=post action=loginchk;jsessionid=D93E0E3C27B8AC5202C17DA72246EC1D>
session:存在于服务器.....通常,为了跟踪用户会话,需要将Session ID交给客户端,在用户下交请求时,将这个ID请求一起发送回来....
可以采用Cookie或URL重写方式,将Session ID发送给客户端...........
cookie.存在于客户端.
req.getCookies();
resp.addCookie();
servlet异常处理:
4xx客户端错误..
5xx服务端错误..
//声明式异常处理;;;
<error-page>
<error-code>404</error-code>
<location>/filenotfoune.html</location>
</error-page>
//程序式异常,try..catch()...
RequestDispatcher:将请求转发给其它的Servlt处理.........带上参数.............
rd.forward(req,resp);
//数据源,连接池..........是对数据库来说的.
//线程池.............................多线程.
//Servlet容器采用单例多线程方式...减少产生Servlet实例的开销..
//
try{
.....
rs.close();
rs=null;
stmt.close();
stmt=null;
conn.close(); //注意,连接被放回连接池
//conn=null; //此语句被删去将引发问题.................确保关闭连接不会发生两次...........
}
catch(){
...... AA
}
fianlly{
........... BB
if(null!=conn){ try{ conn.close()}catch(){}finally{conn=null} }
conn=null;
}
/注意,若T1执行到AA后,T2开始执行,并利用 conn所指的对象进行连接,在查询进行一半时,
T1开始执行,并两次执行了conn.close()....断开了数据库的连接...........
属性的线程安全:
ServletContext : 在任何时候都可以被所有Servlet访问...当某一Servlet设置(如删除)一个属性时,其它的Servlet某Servlet正在显示这个属性..则出现异常..
HttpSession : 同一session............若几个窗口同时访问,一个删,一个显示.. synchronized(session){...................}
ServletRequest : 只在一个线程中使用..
第三部分
//Context配置注意,一定不能放在 web-inf/web.xml中, 可以放在 meta-inf/context.xml中,不然会发生错误,(另外,web.xml不能为空文件....)
<%@ page language="java"%>
<%@ page import="java.io.*"%>
<%@ page contentType="text/html;charset=gb2312"%>
<%! int count=1000 ;%>
<%= count %>
<% out.println(" hello world!");
out.println("你好!");
%>
<%@ , <%! ,<% .......
<%-- jsp comments --%>
<!-- html comments -->
<textarea></textarea> //后面必不可少, 用/>是不行的..
//一个标准JavaBean组件具有以下几个特征:
1.它是一个公开的(public)类
2.默认构造函数.
3.提供setXXX()和getXXX();
4.实现序列化.
//JavaBean的属性和实例变量不具有一一对应关系.......
如 getInfo(){return new String("okok");} 得到的info没有与之对应的实例变量....
<jsp:useBean>用于实例化或定位一个已经存在的JavaBean实例,并把实例的引用给一个变量...
参数: id 标识JavaBean名字,并被初始化为JavaBean实例的引用..
scope: JavaBean的范围..........
class:完整类名,.........................................(,若换为type则是找到一个已经建立的useBean...,找不到时会抛出异常..)
beanName: Bean的名字,提供给 instantiate()方法...
其动作如下:jsp容器首先在scope范围内找指定id的javabean,如果找到了,,,
A.没找到但是有class则建一个新的..并赋值给id...
B.没找到但是有beanName则用beanName作为参数调用instantiate()新建对象,并给id..
<jsp:getProperty name="name" property="propertyname"> name对应于 usebean的 id...
<jsp:setProperty name="name" property="propertyName"|property="propertyName" param="parameterName"|property="propertyName" value="parameterValue">
//注: getProperty中 须有setXXX()....同理getXxx();
//如果property属性的值是"*",标签就会在请求对象中查找所有请求参数,看看是否有参数名字和Bean属性名字相同,如果找到匹配的,主会按照正确的类型转换,将参数的值设置为属性的值..
如果参数值为空,则属性值就不会被修改...
//在设置property属性时,如果,请求参数的名字和Bean属性名字不同,则可用param来指定参数的名字...
//value: 用于请求时属性表达式...
// jsp useBean示例 :::::::::::::::;
<% @ page contentType="text/html;charset=gb2312" %>
<% request.setCharacterEncoding("gb2312"); %>
<jsp:useBean id="user" scope="session" class"beans.UserBean"/>
<jsp:setProperty name="user" property="*"/>
<jsp:setProperty name="user" property="email" param="mail"/>
<!--注意,property="*",可以把所有request中参数与属性名相同的值赋给匹配参数...-->
你的学历:<jsp:getProperty name="user" property="education"/>
........:<jsp:getProperty name="user" property="..."/>
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.Iterator;
import java.sql.*;
import javax.sql.Datasource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
//购物车实现:
1.书本信息 bookBean......与bookinfo表对应
2.购物车中一个条目.....包括bookbean对象,数量,合计..
3.购物车:
/*在购物车中增加一个条目,若已经存在,则什么也不*/
/*删除一个图书条目*/
/*清除购物车中所有图书*/
/*得到购物车中图书总条目*/
/*设置某本书的购买数量*/
/*得到购物车中所有价格*/
/*得到购物车中所有的图书条目*/
/*判断图书是否已经加入购物车中*/
4.BookDBBean....封装数据库的操作,包括实现查阅,购买图书功能..
/*关闭连接对象*/
protected void closeConnection(Connection conn){
if(conn!=null){
try{
conn.close();
conn=null;
}
catch(SQLException ex){
ex.printStackTrace();
}
}
}
/*得到数据库中所有的图书信息*/
public Collection<BookBean>getBooks()throws SQLExcption{
Connection conn=null;
Statement stmt=null;
Result rs=null;
ArrayList<BookBean> bookList=new ArrayList<BookBean>();
try{
conn=getConnection();
stmt=conn.createStatement();
rs=stmt.executeQuery("select * from bookinfo ");
while(rs.next()){
BookBean book=new BookBean(rs.getInt(1),rs.getString(2),rs.getString(3),rs.getString(4),rs.getString(5),rs.getFloat(6),rs.getInt(7),rs.getString(8));
bookList.add(book);
}
return bookList;
}
finally{
closeResultSet(rs);
closeStatement(stmt);
closeConnection(conn);
}
}
///
conn=getConnection();
pstmt=conn.prepareStatement("select * from bookinfo where id=?");
pstmt.setInt(1,bookId);
rs=pstmt.executeQuery();
//集合类:
三种::::
Set(不重复)______________List(可重复)________________Map(不重复,键值对应)....
Set: size()...contains(element)...remove(element)..add(element).....clear().....___iterator()___
List:
get(int index)...set(index,element)....add(index,element)...
remove(index)...addAll(index,collection)..indexOf(object)..
lastIndexOf(object)...___listIterator()___..subList(int from,int to)..
Map:
put(key,value)...get(key)...remove(key)...containsKey(key)...
containsValue(value)...size()...hashCode()...isEmpty()...clear()..putAll(Map t)..
//集合视图:keySet()...values()....entySet()...
迭代器:
Iterator: hasNext()...next()....remove()...
//jsp文档: : : xml式语法格式....
分页显示技术:
@ 每页显示的 条数 m
@ 当前页数 作为url参数设置 curpage
@ 查询结果集总条数 n
每次都是查询一次结果集,然后滚动到某页的第一行,开始显示至多 xx条....
关于上下页则要求求出总页数 :
pagecount=(n+m-1)/m;
//相当于(n%m+m-1)/m+n/m......当余数大于0时,单独作为一页...
示例:
1.查询结果...得到 rs..............滚动到rs.last() ....由rs.getRow()当前行得到总条数
2.计算出总页数,并 由 rs.absolute((curpage-1)*countPerPage+1)滚动到要显示的游标出...
3.动态显示上下页,根据 curPage与 1,pageCount的关系.....