1. Servlet:小服务器程序
1.1. 继承体系:Servlet(I)-> GenericServlet(AC) -> HttpServlet(AC)
1.2. 生存周期:
1.2.1. 初始化:默认是第一次被访问(可以修改为项目启动即初始化)
1.2.2. 销毁:项目关闭
1.2.2.1. 正常关闭:会调用destroy方法
1.2.2.2. 非正常关闭:不会调用destroy方法
1.2.3. 注意:Servlet在WEB服务器是单例的。
1.3. 核心方法:
1.3.1. service方法,在HttpServlet中被进行方法分发:
1.3.1.1. doXxx方法(根据提交请求的请求方式进行分发doGet/doPost)
1.3.1.2. 方法接收两个参数:
1.3.1.2.1. HttpServletRequest:请求对象
1.3.1.2.2. HttpServletResponse:响应对象
1.4. ServletConfig【不重要】:
1.4.1. 取得servlet-name
1.4.2. 取得Servlet的自定义的初始化参数(web.xml中的)
1.5. ServletContext【重要】:Servlet上下文对象,代表整个WEB项目
1.5.1. 域对象
1.5.2. 取得当前项目名:getContextPath()
1.5.3. 把服务器的WEB路径转换成绝对路径:getRealPath()
2. ServletContext域对象(域对象是一个Map,都有三个方法):
2.1. void setAttribute( String name , Object value )
2.2. Object getAttribute( String name )
2.3. void removeAttribute( String name )
3. 为什么WEB项目中会产生乱码
3.1. HTTP协议使用的是ISO-8859-1字符集。(和ASCII码是一致)
3.2. ASCII码:取值是0~127,其中包含0~9,a~z,A~Z,和一些标点符号、指令。
3.2.1. 0:48
3.2.2. A:65
3.2.3. a:97
3.2.4. 空格:32
3.2.5. 回车:13 0D
3.2.6. 换行:10 0A
3.2.7. 一个字节表示一个字符,以0开头。以1开头的扩展集(各国自定义)
3.3. GB2312-80:6000个汉字,还有一些特殊的符号
3.3.1. 一级字库:以拼音排序,约4000字
3.3.2. 二级字库:以笔画排序,约2000字
3.4. GBK:
3.5. BIG5:繁体字符集
3.6. utf-8:
3.7. 字符串在浏览器中使用时用的是UTF-8,在向服务器发请求时,使用了HTTP协议,所以在传输字符串时,字符串变成了ISO-8859-1。服务器接收到请求后,把字符串当成了utf-8(Java默认的)。因为使用的字符集产生了差异,所以产生了乱码。所以解决乱码的办法就是设置字符集。请求响应对象:setCharacterEncoding(“UTF-8”)
4. 案例一:记录网站登录成功的人数
4.1. 需求分析:用户登录网站,如果登录成功,则显示是第几位访客
4.2. 技术分析:
4.2.1. 有一个计数器(整型变量),每次有用户登录成功,则计数器自增1
4.3. 步骤分析:
4.3.1. 创建登录页面
4.3.2. 创建验证登录的Servlet
4.3.3. 接收请求:得到用户名和密码
4.3.4. 调用业务逻辑,进行登录验证,如果登录成功则计数器自增1
4.3.5. 做出响应,如果登录成功,则显示计数器的值
4.4. 注意:一般在项目中,最低层的方法会把异常抛出,因为如果在最底层就异常给处理掉了,则上层的调用方法不知道发生了什么问题。具体抛到哪一层停止,没有定论。
5. 响应对象:HttpServletResponse:此对象封装了所有服务器发给浏览器的响应信息。
5.1. 响应行:设置响应状态码及文本
5.1.1. resp.setStatus( int code ):设置响应的状态码,设置状态文本的方法已经过时,不推荐使用。
5.2. 响应头:设置响应头
5.2.1. setHeader( String name , Stringvalue ):通用的
5.2.2. setIntHeader( String name , intvalue ):只适用于设置整型值的响应头
5.2.3. setDateHeader( String name ,long value ):只适用于设置日期型的响应头
5.3. 响应体:
5.3.1. resp.getWriter().write(“响应体”):输出文本内容。
5.3.2. resp.getOutputStream().write(响应体):输出任何内容
5.3.3. 注意:两个流不能同时用
6. 案例二:文件下载
6.1. 需求分析:提供一个下载页面,页面中提供一些下载文件用的超链接,当点击超链接时,下载对应的文件。
6.2. 技术分析:
6.2.1. 直接使用超链接进行下载:对于浏览器“认识”的文件类型,会直接在浏览器中打开。不会弹出下载的对话框。(不能用)
6.2.2. 用Servlet的字节输出流,把文件内容以二进制流的方式发回给浏览器。
6.2.3. 使用ServletContext把要下载的文件的WEB路径转换成绝对路径,用于创建文件输入流。getRealPath/getResourceAsStream( String webPath )
6.2.4. 如果文件名中存在中文,也会有乱码问题。解决的办法:
6.2.4.1. 把文件名进行URLEncoding:把字符串进行URL编码。把不能正常在HTTP协议中传输的字符,变成以%开头,根两个16进制数来表示一个字节的形式来传输。中-> %E9%33
6.2.4.2. URL编码内容发送到浏览器后,浏览器会自动进行解码
6.2.4.3. 注意:火狐浏览器使用的是base64编码,所以URL编码不认。
6.2.4.4.
6.3. 步骤分析:
6.3.1. 创建下载页面,提供若干个超链接,不直接指向被下载的文件,而是发送请求到专门负责下载的Servlet,并提交要下载的文件名。
6.3.2. 创建下载的Servlet(DownloadServlet),接收请求,得到要下载的文件名
6.3.3. 读取要下载的文件的内容(使用文件输入流:FileInputStream)
6.3.4. 把文件的二进制内容使用响应对象的字节输出流发送回给浏览器
7. 案例三:动态验证码
7.1. 需求分析:在登录界面中,除了要输入用户名和密码之后,还显示一个验证图片。验证图片中是一个四到五位的字符串,可以包含字母、数字。随机显示。点击图片,换一张。
7.2. 技术分析:
7.2.1. 随机数:Random.nextInt(int num),用随机数生成验证码
7.2.2. 把验证码画到图片上:
7.2.2.1. BufferedImage:此类对象相当于一个画布,要在此画布上画出图形,则需要画笔:Graphics
7.2.2.2.
7.2.3. 把图片发回给浏览器:
7.2.3.1. 浏览器如何显示:<imgsrc=”checkCode.servlet” />
7.2.3.2. Servlet如何发送:ImageIO工具类使用输出字节流输出图片
7.2.4. 当点击图片时,重新发请求到CheckCodeServlet:
7.2.4.1. 使用JS,在图片onclick事件中,改变图片源为CheckCodeServlet
7.3. 步骤分析:
7.3.1. 创建一个登录页面,增加验证码输入框和图片
7.3.2. 图片的源指向生成验证码图片的Servlet
7.3.3. 创建一个生成验证码的CheckCodeServlet
7.3.4. 生成验证码(字符串)
7.3.5. 把验证码画到图片上
7.3.6. 把图片发回给浏览器
8. HttpServletResponse:响应对象
8.1. 设置响应行
8.1.1. setStatus( int code )
8.2. 设置响应头
8.2.1. setHeader(“name’ , “value”)
8.3. 设置响应体
8.3.1. getWriter()
8.3.2. getOutputStream()
8.3.3. 注意:两个流不能同时使用
1. HttpServletRequest:封装了浏览器发给服务器的请求的所有信息
1.1. 取得请求行
1.1.1. getMethod():取得请求方式(GET/POST)
1.1.2. getRequestURL():
1.1.3. getRequestURI():
1.1.4. getProtocol():
1.2. 取得请求头
1.2.1. String getHeader( String name);
1.2.2. int getIntHeader( String name )
1.2.3. Enumeration<String>getHeaderNames():取得所有请求头的名字
1.2.4. getHeaders( String name):一个名多个值
1.3. 取得请求体:(不区分提交方式的)
1.3.1. String getParameter( Stringname ):取得提交的请求参数
1.3.2. String[] getParameterValues(String name ):取得提交的参数中的一个字多个值
1.3.3. Enumeration<String>getParameterNames():取得提交的所有参数的名字
1.3.4. Map<String,String[]>getParameterMap();
1.3.5. 前两个是给程序员用的
1.3.6. 后两个是给框架用的(BeanUtils)
1.4. 其它方法
1.4.1. setCharacterEncoding(“字符集”):解决POST方式提交的中文乱码问题
1.4.1.1. 乱码产生的原因:字符串在HTTP协议进行传输时,被HTTP协议改成了ISO-8859-1字符集,但浏览器和服务器用的都是UTF-8。所以数据传到另一端时会产生乱码。
1.4.1.2. 服务器的解决办法:
1.4.1.2.1. POST:req.setCharacterEncoding(“UTF-8”)
1.4.1.2.2. GET:GET方式默认不支持中文
new String(src.getBytes(“ISO-8859-1”) , “UTF-8” )
1.4.1.3. 浏览器的解决办法:URLEncoder
1.4.2. getRequestDispatcher(“服务器的WEB路径”).forward(req,resp);请求转发(内部转发)
1.5. 域对象:就是个Map(在一次请求范围内的)
1.5.1. setAttribute( String name,Object value )
1.5.2. Object getAttribute( Stringname )
1.5.3. void removeAttribute( Stringname )
2. 在Servlet中用代码进行页面转跳的方式:
2.1. 重定向:向浏览器发送一个指令(302),要求浏览器发送请求到指定的路径。
2.1.1. resp.sendRedirect(“客户端的WEB路径”)
2.2. 内部转发:从服务器内部把请求转到指定的路径
2.2.1. req.getRequestDispatcher(“服务端的WEB路径”).forward(req, resp)
2.3. 注意两种转跳方式内部转发的效率高,所以优先使用。有两种情况需要使用重定向:
2.3.1. 要转跳的目标是别的项目。
2.3.2. 转跳到本项目中的目标页面时,之前是一个表单提交,转跳到的页面有刷新的需求,需要使用重定向。因为内部转发会产生之前的表单的重复提交。
3. 案例一:登录时的提示信息的传递
3.1. 需求分析:登录后提示登录成功或失败。
3.2. 技术分析:
3.2.1. 不再使用Servlet直接向浏览器输出内容的方式输出提示信息,而是把提示信息保存起来带到一个专门显示提示信息的页面上进行显示。
3.2.2. 有一个在两个页面之间保存和传递数据的区域:域对象。
3.2.2.1. ServletContext:因为此域是公共的,所以不能用
3.2.2.2. Request:一次请求范围内(请求到达服务器创建请求对象,域开始。响应发回给浏览器,请求销毁,域中的数据也跟着一起被销毁。)如果使用Request域传递数据,则两个页面之间必须用内部转发进行转跳。
3.2.3. 在显示页面中进行显示:使用JSP页面,在页面中使用${域中的名字}(EL表达式)
3.3. 步骤分析:
3.3.1. 传统的登录过程。
3.3.2. 在进行登录验证的Servlet中,调用业务逻辑之后,不再直接发送响应内容。而是把提示信息保存到Request域。
3.3.3. 用内部转发转跳到专门用于显示提示信息的页面(JSP)
4. 用户注册
4.1. 需求分析:提供一个注册页面,由用户填写注册信息,并把信息写入到数据库中
4.2. 技术分析:
4.2.1. 表单中提交了很多用户信息,这些信息不能散着放,要封装成User对象。使用BeanUtils。
4.3. 步骤分析:
4.3.1. 创建一个注册页面,由用户输入注册信息
4.3.2. 注册页面的表单提交到RegistServlet。接收请求,得到用户信息并封装成User对象。
4.3.3. 调用业务逻辑,注册用户。(调用Dao把用户信息Insert到数据库的用户表中)
4.3.4. 给用户提示注册结果(转跳到信息页面显示提示信息)