在tomcat的webapps目录下创建一个目录(命名必须不包含中文和空格),这个目录称之为项目目录动态网站:
在项目目录下创建一个html文件
在tomcat的webapps目录下创建一个项目目录
在项目目录下创建如下内容
WEB-INF目录
在WEB-INF目录下创建web.xml文件
创建静态或动态页面
http协议:无状态协议,仅连接一次(ftp协议是有状态的)
请求协议:格式:
响应协议:请求行多个请求头信息:头名称:头值 例: User-Agent:浏览器信息等 Content-Type:表示表单中的数据会自动使用url来编码!(字节+128-->转换成16进制-->添加&这个前缀)空行请求体
格式:
响应行(协议/版本 状态码(2开头请求成功 3开头转接 4开头客户端错误 5开头服务器错误) 状态码解析)响应头信息例:(key/value格式)Server:响应内容的MIME类型 Content-Type:text/html;charser=ISO-8859-1(编码)Content-Length:字节数Date:时间空行响应正文
Post请求(提交表单时):有请求体(get无请求体)
1 Content-Type:表示表单中的数据会自动使用url来编码!(字节+128-->转换成16进制-->添加&这个前缀)
2 正文体,表单是一大堆内容,而发送给服务器的只有一行字符串
个别请求头:
1 Refere:请求来自哪个页面 作用:1 统计工作 2 防盗链响应码:
2 Content-Length:请求体的长度
3 Content-Type:表示表单中的数据会自动使用url来编码!(字节+128-->转换成16进制-->添加&这个前缀)
4 if-Modified-Since:把上次请求页面的最后修改时间还给服务器
200:请求成功
404:请求的资源没有找到,说明客户端错误的请求了不存在的资源
500:请求资源找到,但服务器内部出错。
302:重定向
304:比较if-Modified-Since的时间与文件真实的时间一样时,服务器会响应304,而且不会有响应正文,表示浏览器缓存的就是最新版本。
响应头:
last-Modified:最后的修改时间
告诉浏览器不要缓存的响应头
Expires:-1Catche-Control:no-cachePragma:no-cacheRefresh:3;url=地址 3 秒后自动访问 自动刷新
HTML 指定响应头
<meta http-equiv="Refresh" content="5;url=http://www.baidu.com">
Servlet:
每个Servlet都是唯一的,他们能处理的请求是不同的,serlvet是javaweb三大组件之一,它属于动态资源,作用是处理请求,服务器会把接收到的请求交给它来处理
1 接收请求数据 2 处理请求 3 完成响应
特性:单例,一个类只有一个对象,当然可能存在多个servlet类,线程不安全的。
Servlet类由我们来写,但对象由服务器创建,并由服务器来调用响应的方法
1 实现Servlet的方式
实现javax.servlet.Servlet接口
继承javax.servlet.GenericServlet类
继承 javax.servlet.http.HttpServlet类(常用)
方法:
void init(ServletConfig servetConfig): 生命周期方法,进行初始化。它会在Servlet创建对象之后马上执行,只执行一次!,第一次请求创建Servlet
void destroy() :生命周期方法,被销毁之前调用,并且只会被调用一次,服务器关闭时调用
void service(ServletRequest request,ServletResponse response):生命周期方法,会被调用多次,每次请求都调用
ServletConfig ServletConfig:可以用来获取配置信息
getServletInfo:获取servlet信息
如何让浏览器访问Servlet:
1 给Servlet指定一个Servlet路径(让Servlet与一个路径绑定在一起)需要在web.xml中对Servlet进行配置
<servlet>
<servlet-name>xxx</servlet-name>
<servlet-class>cn.itcast.web.servlet.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xxx</servlet-name>
<url-pattern>/AServlet</url-pattren>
</servlet-mapping>
2 浏览器访问Servlet路径
ServletConfig:一个ServletConfig对象,对应一段web.xml中Servlet的配置信息
方法:String getServletName() 获取的是<servlet-name>
ServletContext getServletContext();获取Servlet上下文对象!
String getInitParameter(String name) 通过名称获取指定初始化参数的值
Enumeration getInitParameterNames() 获取所有初始化参数的名称
ServletRequest;请求对象
ServletResponse:响应对象
GenericServlet:继承时只需要覆盖service方法,其他的选择覆盖。
HttpServlet 继承GenderServlet
方法 doGet()
doPost()
service(HttpServletRequest arg0,HttpServletResponse arg1)-->参数是和htp协议相关的,使用方便
会通过request得到当前的请求方式,例如:GET或POST 根据请求方式调用doGet()或doPost()方法
//我们需要做的就是继承这个类重写doGet() doPost() 方法 如果没有覆盖这两个方法,并且调用了这两个方法,会出现405.
Servlet细节
1 Servlet与线程安全,不要在Servlet创建成员,创建局部变量即可,最好可以创建无状态成员,也可以创建有状态成员,但状态是须可读的。
2 让服务器在启动时就创建Servlet,默认为第一次请求时创建。
在<servlet>中配置<load-on-startup>非负整数</load-on-startup> 数字不一样,代表创建顺序不一样
3 <url-pattern>用来指定Servlet的访问路径,它必须是以“/”开头,可以绑定多个URL 但访问的都是一个URL,还可使用通配符
注意:通配符要么为前缀,要么为后缀,不能出现在中间位置,也不能只有通配符。通配符越少,访问的优先级就越高
4 web.xml的父文件(了解)
存在父文件 在Tomcat的conf/web.xml 里面有<url-pattern>/</url-pattern>(优先级最低,404原理) 还有存在请求jsp的配置文件
Servlet与反射,tomcat通过反射技术创建Servlet对象
ServletContext(重要) 一个项目只有一个ServletContext对象 可以在很多个Servlet中获取这个唯一的对象,使用它可以给多个Servlet传递数据
1 ServletContext概述
服务器会为每个应用创建一个ServletContext对象,创建是在服务器启动时完成的,销毁是在服务器关闭时完成的。
2 获取ServletContext
在Servlet中获取ServletContext对象
在void init(ServletConfig config)中:ServletContext context = config.getServletContext()
ServletConfig类中的getServletContext()方法可以用来获取ServletContext对象
在GenericServlet或HttpServlet中获取ServletContext对象
GenericServlet类有getServletContext()方法,所以直接可以用this.getServletContext()来获取
HttpSession,ServletContextEvent 也可以获取到
3 域对象的功能。
ServletContext是javaweb四大域对象之一 PageContext,ServletRequest,HttpSession,Servlet
所有域对象都有存取数据的功能,因为域对象内部都有一个Map,用来存储数据
4 方法:
void setAttribute(String name,Object value):用来存储一个对象,也可以称之为存储一个域属性.如果多次调用该方法,使用相同的key,那么值会被覆盖,于Map相同
Object getAttribute(String name) 用来获取数据,名为name的域属性
void removeAttribute(String name) 用来移除Servlet中的域属性,如果域属性不存在,那么什么都不做
Enumeration getAttributeNames() 获取所有域属性的名称
5 获取应用初始化参数
Servlet也可以获取初始化参数,但它是局部的参数,也就是说,一个Servlet只能获取自己的初始化参数,不能过去别人的,即初始化参数只为一个
调用getInitParameter(String )得到初始化参数
6 获取相关资源方法
6.1 获取真实路径 getRealPath("/index.jsp");
6.2 获取资源流 getResourceAsStream("/index.jsp");
6.3 获取指定目录所有资源的路径 geResourcePaths("/WEB-INF")
练习:访问量统计
一个项目中所有的资源访问都要对访问量进行累加,创建一个int类型的变量,用来保存访问量,然后把它保存到ServletContext的域中,这样可以保存所有的Servlet都可以访问
步骤
1 获取ServletContext对象,查看是否存在名为count属性,如果存在,说明不是第一次访问,不存在说明是第一次访问
2 第一次访问:调用ServletContext的setAttribute()传递一个属性,名为count,值为1
第2-n次访问:调用ServletContext的getAttribute()方法获取原来的访问量,给访问量加1 ,再调用ServletContext的
setAttribute()方法完成设置
3 向浏览器输出,使用响应对象 PrintWriter pw = response.getWriter(); pw.print("<h1>"+count+"</h1>")
获取路径下资源 类路径对于一个javaweb项目而言,就是/WEB-INF/classes和/WEB-INF/lib 每个jar包
1 得到ClassLoader 先得到class 再得到ClassLoader
2 调用其getResourceAsStream(),得到一个InsputStream
ClassLoader c1 = this.getclass().getClassLoader(); InputStream input = c1.getResourceAsStream("cn/itcast/servlet/a.txt") //相对classes
Class c = this.getClass() //这个是相对于.class文件所在的目录 (路径前加/ 表示相对于classes)
服务器处理请求的流程:
服务器每次收到请求时,都会为这个请求开辟一个新的线程
服务器会把客户端的请求数据封装到request对象中,request就是请求数据的载体
服务器还会创建response对象,这个对象与客户端连接在一起,它可以用来向客户端发送响应
HttpServletResponse:与http协议相关的类
方法:
sendError(int sc) 发送错误码,例如404,500
sendError(int sc,String msg) 发送状态码,可以带一个错误信息
setStatus(int sc) 发送成功的状态码,可以用来发送302
头就是一个键值对!
setHeader(String name,String value):适用于单值的响应头
addHeader(String name,String value) 适用于多值的响应头
setIntHeader(String name,int value) 适用于单值的int类型响应头
addIntHeader(String name,int value) 适用于多值的int类型响应头
setDateHeader(String name,long value) 适用于单值的毫秒类型的响应头
addDataHeader(String name,long value) 适用于多值的毫秒类型的响应头
response的两个流:
ServletOutputStream,用来向客户端发送字节数据。ServletOutputStream out = response.getOutputStream()
PrintWriter 用来向客户端发送字符数据,需要设置编码 PrintWriter writer = response.getWriter();
两个流不能同时使用
案例:
重定向:
* 1 设置location
* 2 发送状态码302
例:
response.setHeader("location", "/responce/BServlet");// /项目名/servlet
response.setStatus(302);
快捷方法:sendRedirect(String location) 例:response.sendRedirection(/responce/BServlet)
定时刷新
设置Refresh
例: response.setHeader("Refresh", "5;URL=/resonce/BServlet");
禁用浏览器缓存
response.setHeader("Cache-Control","no-cache");
response.setHeader("pragma","no-cache");
response.setHeader("expires","-1");
<meta>标签可以代替响应头
HttpServletRequest
方法:
获取常用信息:
String getRemoteAddr() 获取客户端的ip地址 可以用来封ip
String getMethod() 获取请求方式
String getHeader("请求头") 获取请求头
获取请求URL
String getScheme() 获取协议
String getServerName() 获取服务器名
String getServerPort() 获取服务器端口
String getContextPath() 获取项目名
String getQueryString() 获取参数部分
String getRequestURI()获取URI 例:获取到 /responce/AServlet
String getRequestURL() 获取请求URL,等于不包含参数的整个路径
获取请求参数:
请求参数:有一个参数一个值得,还有一个参数多个值
String getParameter(String name) 获取指定名称的请求参数值
String[] getParameterValues(String name) 获取指定名称的请求参数值,适用于多值请求参数
Enumeration<String> getPatameterNames() 获取所有请求参数名称
Map<String,String[]> getParameterMap() 获取请求参数,其中key为参数名,value为参数值
请求转发与请求包含
RequestDispatcher rd = request.getRequestDispatcher("/MyServlet");
请求转发:rd.forward(request,response)
请求包含:rd.include(request,response)
有时一个请求需要多个Servlet协作才能完成,所以需要在一个Servlet跳到另一个Servlet
一个请求跨多个Servlet,需要使用转发和包含
请求转发:由下一个Servlet完成响应体,当前Servlet可以设置响应头
请求包含:由两个Servlet共同完成响应体
注意:无论是请求转发,还是请求包含,都在一个范围内(地址栏不会变化 )
request域:
Servlet中三大域对象:request,session,application 都有如下三个方法
void setAttribute(String name,Object value)
Object getAttribute(String name)
void removeAttribute(String name)
同一个范围内使用request.setAttribute()、request.getAttribute() 来传值,前一个Servlet调用setAttribute()设置值,后一个servlet调用getAttribute(0来获取值
请求转发和重定向的区别
请求转发是一个请求一次回应,而重定向是两次请求两次回应
请求转发地址栏不变化,而重定向会显示后一个请求的地址
请求转发只能转发到本项目其他Servlet,而重定向不只能重定向到本项目的其他Servlet,还能定向到其他项目
请求转发是服务端行为,只需给出转发的Servlet路径,而重定向需要给出requsetURI,即包含项目名
请求转发效率更高
常见字符编码:iso-8859-1(不支持中文) gbk(系统默认编码,中国的国标符) utf-8(万国码)
1 响应编码
当使用response.getWriter()来向客户端发送数据时,如果之前没有设置编码,那么默认使用iso,所以乱码
在使用response.getWriter()之前可以用response.setCharaceterEncoding() 来设置编码,但浏览器解析使用gbk解析的,还是会乱码
在使用response.getWriter() 之前可以用respnse.setHeader("Content-type","text/html;charset=utf-8") 来设置响应头,用来通知浏览器
.setHeader("Content-type","text/html;charset=utf-8")的快捷方法是:setContentType("text/html;charset=utf-8")
2 请求编码
客户端发送给服务器的请求参数是什么编码:
客户端首先要打开一个页面,然后在页面中提交表单或点击超链接,请求页面时,上一次服务端响应的页面编码是什么,那客户端发送请求时编码就是什么
服务端默认使用iso-8859-1 来解码(tomcat8使用utf-8)
请求编码处理分为两种 get post :get请求参数不在请求体中,而post请求参数在请求体中,所以处理方式不同
GET请求编码处理:
String name = getParameter("name");
byte[] bytes = name.getBytes("ISO8859-1")
name = new String(bytes,"utf-8")
在servlet.xml中配置URIEncoding=utf-8(不用)
POST请求编码处理
在获取参数之前调用request.setCharacterEncoding("utf-8");
3 URL编码
表单的类型:Content-Type:application/x-www-form-urlencoded 就是把中文转换成&后面跟随两位的16进制
为什么使用?在客户端和服务器之间传递中文时需要把它转成网络适合的部分
不属于字符编码
URL编码需要先指定一种字符编码,把字符串解码后,得到byte[],然后把小于0的字节+256,再转换成16进制,前面加&
POST请求默认就使用URL编码 tomcat会自动使用URL解码
URL编码:String username = URLEncoder.encode(username,"utf-8")
URL解码:String username = URLDecoder.decode(usernme,"utf-8")
(以后可能需要把链接中的中文参数,使用URL来解码)
路径
web.xml中<url-pattern>路径要么以*开头,要么以/开头
转发和包含路径
以/开头:相对当前项目路径
不以/开头,相对当前Servlett路径
重定向路径(客户端路径)
以/开头:相对当前主机,所以需要手动添加项目名
页面中超链接和表单路径
与重定向相同,都是客户端路径,需要添加项目名
ServletContext获取资源路径
相对当前项目目录
ClassLoader获取资源路径,相对classes目录
jsp:
基础:
1 jsp的作用
Servlet: 缺点:不适合设置html响应体,需要大量的response.getWriter().print("<html>")
优点:动态资源,可以编程
html: 缺点:html是静态页面,不能包含动态信息 优点:不用为输出html标签而发愁
jsp优点:在原有html的基础上添加java脚本,构成jsp页面
2 jsp和Servlet的分工
jsp:作为请求发起页面,例如显示表单,超链接,作为请求结束页面,例如显示数据
Servlet:作为请求中处理数据的环节
3 jsp的组成:
jsp = html + java脚本 + jsp标签(指令)
jsp中无需创建即可使用的对象一共有9个,被称之为9大内置对象,例如:request对象,out对象
3种java脚本
<%.....%> java代码片段(常用),用于定义0-n条java语句
<%=....%> java表达式,用于输出(常用),用于输出一条表达式(或变量)的结果
<%!.....%> 声明,用来创建类的成员变量和成员方法(基本不用)
jsp原理
jsp其实是一种特殊的Servlet
当jsp页面第一次被访问时,服务器会把jsp编译成java文件(这个java其实是一个Servlet类)
然后再把java编译成.class
然后创建该类对象
最后调用它的service()方法
第二次请求同一jsp时,直接调用service()方法
在tomcat的work目录下可以找到jsp对应的.java源代码
jsp注释:
<%-- --%>:当服务器把jsp编译成java文件时已经忽略了注释部分 (<!--<% code..%>--> 里面的代码会执行,但是结果会被注释掉)
Cookie(服务器保存到客户端的东西)
1 http协议与cookie
Cookie是http协议制定的!先由服务器保存cookie到浏览器,在下次浏览器请求服务器时把上一次请求得到的cookie再归还给服务器
由服务器创建保存到客户端浏览器的一个键值对,服务器保存cookie的响应头。
当浏览器请求服务器时,会把该服务器保存的cookie随请求发送给服务器。浏览器归还cookie的请求头
Http协议规定
1个cookie最大4kb
1个服务器最多向1个浏览器保存20个cookie
1个浏览器最多可以保存300个cookie
浏览器大战:因为浏览器竞争很激烈,所以很多浏览器都会在一定范围内违反http规定,但也不会让一个cookie为4GB
2 Cookie的用途
服务器使用cookie来跟踪客户端状态
保存购物车(购物车中的商品不能使用request保存,因为它是一个用户向服务器发送的多个请求信息)
显示上交登陆名(也是一个用户多个请求)
3 javaweb中使用cookie
原始方式
使用response发送Set-Cookie响应头
使用request获取Cookie请求头
便捷方式
使用response.addCookie() 方法向浏览器保存cookie
使用request.getCookies() 方法获取浏览器归还的Cookie
4 Cookie详解
cookie不只有name和value两个属性
cookie的maxAge(掌握) :cookie的最大生命,即cookie可保存的多大时长。以秒为单位,例如:Cookie cookie = new Cookie("aaa","AAA") cookie.setMaxAge(60)
maxAge>0:浏览器会把cookie保存到客户机硬盘上,有效时长为maxAge的值决定
maxAge<0:Cookie只在浏览器内存中存在,当用户关闭浏览器时,浏览器进程结束,同时Cookie也就死亡了
maxAge=0:浏览器会马上删除这个Cookie
Cookie的path:
Cookie的path并不是设置这个Cookie在客户端的保存路径
cookie的path由服务器创建cookie时设置
当浏览器访问服务器某个路径时,需要归还哪些Cookie给服务器呢?这由cookie的path决定
浏览器访问服务器的路径,如果包含 某个cookie的路径,那么就会归还这个cookie
cookie的域(了解)
HttpSession
1 概述
HttpSession是由javaweb提供的,用来会话跟踪的类。session是服务端对象,保存在服务端
HttpSession是Servlet三大域对象之一(request session application)所以它也有setAttribute() getAttribute() removeAttribute()
HttpSession底层依赖Cookie,或是URL重写
2 作用
会话范围:会话范围是某个用户从首次访问服务器开始,到该用户关闭浏览器结束
会话:一个用户对服务器的多次连贯性请求,所谓连贯性请求,就是该用户多次请求中间没有关闭浏览器
服务器会为每个客户端创建一个session对象,session就好比客户在服务器端的账户,它们被服务器保存到一个Map中,这个Map被称之为session缓存
Servlet中得到session对象:HttpSession session = request.getSession();
jsp中得到session对象,session是jsp内置对象之一,不用创建就可以直接使用
3 案例:演示保存用户登录信息(重要)
案例相关页面和Servlet:
login.jsp:登录页面
succ1.jsp:只有登录成功才能访问的页面
succ2.jsp:只有登录成功才能访问的页面
loginServlet:获取请求参数,校验用户是否登录成功
失败:保存错误信息到request域,转发到login.jsp(login.jsp显示request域中的错误信息)
成功:保存用户信息到session域中,重定向到succ1.jsp页面,显示session域中的用户信息
succ1.jsp:从session域获取用户信息,如果不存在,显示“您还没有登录”。存在则显示用户信息
succ2.jsp:从session域获取用户信息,如果不存在,显示“您还没有登录”。存在则显示用户信息
4 HttpSession原理:
request.getSession()方法
获取Cookie中的JSESSIONID;
如果sessionId不存在,创建session,把session保存起来,把新创建的session保存到Cookie中
如果sessionId存在,通过sessionId查找session对象,如果没有查找到,创建session,把session保存起来,把新创建的sessionId保存起来,把新创建的sessionId保存到Cookie 中
如果sessionId存在,通过sessionId查找到了session对象,那么就不会再创建session对象了
如果创建了新的session,浏览器会得到一个包含了sessionid的Cookie,这个Cookie的生命为-1,即只在浏览器内存中存在,如果不关闭浏览器,那么cookie会一直存在
下次请求时,再次执行request.getSession()方法时,因为可以通过Cookie中的sessionId找到session对象,所以与上一次请求使用的是同一session对象。
服务器不会马上创建session,在第一次获取session时,才会创建
request.getSession(false) 如果session缓存中(如果cookie不存在),不存在session,那么会返回null,而不会创建session对象。
5HttpSession的其他方法
String getId() 获取sessionId ID设置方式: UUID.randomUUID().toString().replace("-","").toUpperCase()
int getMaxInactiveInterval() 获取session可以的最大不活动时间,默认为30分钟。
void invalidate(); 让session失效
boolean isNew() 查看session是否为新。(是否有cookie)
6 可以在web.xml中配置session的最大不活动时间
<session-config>
<session-timeout>30</session-timeout>
</session-config>
7 URL重写(理解)
session依赖Cookie,目的是让客户端发出请求时归还sessionId,这样才能找到对应的session
如果客户端禁用了Cookie,那么就无法得到sessionId,那么session也就无用了
也可以使用URL重写来代替Cookie
让网站的所有超链接,表单中都添加一个特殊的请求参数,即sessionId
这样服务器可以通过获取请求参数得到sessionId,从而找到session对象
response.encodeURL(String url)
该方法会对url进行智能的重写:当请求中没有归还session这个cookie,那么该方法会重写url。否则不重写。当然url必须是指本站的url。
JSP指令
指令概述:一个jsp页面中,可以有0-n个指令的定义
格式:<%@指令名 attr1=" " attr2=" "%>,一般都会把jsp指令放到jsp文件的最上方。但这不是必须的
jsp中有三大指令:page、include、taglib(最为常用)
1 page <%@page language="java" info="xxx"...%>
pageEncoding: 指定当前jsp页面的编码,在服务器要把jsp编译成.java时需要使用
contentType:它表示添加一个响应头:Content-Type 等同于response.setContentType("text/html;charset=utf-8")
import:导包,可以出现多次
errorPage:当前页面如果抛出异常,那么要转发到哪一个页面,由errorPage来指定
isErrorPage:它指定当前页面是否为处理错误的页面!当该属性为true时,这个页面会设置状态码500,而且这个页面可以使用9大内置对象中的exception
也可以在web.xml中配置
<error-page>
<error-code>404<error-code>
<location>/error/errorPage.jsp</location>
<error-page>
<exception-type>java.RuntimeException</exception-type>
<location>/index.jsp</location>
</error-page>
</error-page>
autoFlush:指定jsp的输出流缓冲区满时,是否自动刷新!默认为true,如果为false,那么在缓冲区满时抛出异常
buffer:指定缓冲区的大小,默认为8kb,通常不需要修改
isELIgnored:是否忽略el表达式,默认值为false
language:指定当前jsp编译后的语言类型,默认值为java
info:jsp说明信息
isThreadSafe:当前的jsp是否支持并发访问
session:当前页面是否支持session,如果为false.那么当前页面就没有session这个内置对象
extends:让jsp生成的servlet去继承该属性指定的类
2 include--->静态包含
与RequestDispatcher的include() 方法的功能相似
<%@include%> 它是在jsp编译成java文件时完成的,他们共同生成一个java(就是一个servlet)文件,然后再生成一个class
作用:把页面分解,使用包含的方式组合在一起,这样一个页面中不变的的部分,就是一个独立的jsp,我们只需要处理变化的部分
3 taglib-->导入标签库
prefix:指定标签库在本页面的前缀,由我们自己来起名称
uri:指定标签库的位置 例:<%@taglib perfix="s" uri="/struts-tags"%> <s:text>
九大内置对象
out jsp的输出流,用来向客户端响应
page 当前jsp对象,它的引用类型是object ,即真是中有如下代码 Object page = this
config 它对应真身中的ServletConfig对象
pageContext
request HttpServletRequest
response HttpServletResonse
exception Throwable
session HttpSession
application ServletContext
pageContext:范围是一个jsp页面,这个域是在当前jsp页面和当前jsp页面中使用的标签之间共享数据
作用:
域对象
代理其他域:例:pageContext.setAttribute("xxx","XXX",PageContext.SESSION_SCOPE)
全域查找:pageContext.findAttribute("xxx") (从小域到大域)
获取其他八个内置对象
jsp动作标签
这些jsp的动作标签,与html提供的标签有本质的区别
动作标签是由tomcat(服务器)来解释执行,它与java代码一样,都是在服务端执行的
<jsp:forward> 转发 例:<jsp:forward page="b.jsp">
<jsp:include> 包含(动态) 不是只生成一个java文件
<jsp:param> 它用来作为forward和include的子标签!用来给转发或包含的页面传递参数 可以使用request.getParameter()方法来获取参数
javaBean
规范:
1 必须要有一个默认构造器
2 提供get/set方法,如果只有get方法,那么这个属性是只读属性
3 属性:有get/set方法的成员,还可以没有成员,只有get/set方法。属性名称由get/set方法来决定。而不是成员名称。去掉set/get 首字母小写即为属性
4 方法名称满足一定的规范,那么它就是属性,boolean可以是is开头
内省就是通过反射来操作javaBean,比使用反射方便一些,需要提供javaBean类
BeanInfo info = Introspector.getBeanInfo(类型)
getPropertyDiscritpor() 通过BeanInfo可以得到所有属性描述符对象
PropertyDiscriptor[] ---->getReadMethod getWriterMethod
可以通过PropertyDiscriptor得到一个属性的读写方法操作javaBean的属性
内省类-->Bean信息-->属性描述符-->属性的get/set对应的Method-->可以反射了
commons-beanutils 它是依赖内省完成
导包:common-beanutils.jar common-logging.jar
jsp中与javaBean相关的标签
<jsp:useBean>-->创建或查询bean
例:<jsp:useBean id="user1" class="cn.itcast.domain.User" scope="session"/> 在session域中查找名为user1的bean,如果不存在创建之
<jsp:setProperty>
例:<jsp:setProperty property="username" name="user1" value="admin"/> 设置名为user1 的这个javabean的username的属性为admin
<jsp:getProperty property="username" name="user1"/>获取名为user1的javabean的名为username属性值
EL表达式
1 EL是jsp内置的表达式语言
jsp2.0开始,不让再使用java脚本,而是使用el表达式和动态标签来替代java脚本
el替代的是<%=...%> 也就是说,EL只能做输出
2 EL表达式来读取四大域
${xxx } 区域查找名为xxx的属性,如果不存在,输出空字符串,而不是null
${pageScope.xxx} ${requestScope.xxx} ${sessionScope.xxx} ${applicationScope.xxx} 指定域获取属性
3 javabean导航
例:${requestScope.emp.address.street} 相当于 request.getAttribute("emp").getAddress().getStreet()
4 EL内置对象 只有pageContext不是Map
pageScope
requestScope
sessionScope
applicationScope
param:对应参数,它是一个map。其中key参数名,value是参数值,适用于单值的参数
paramValues:对应参数,它是一个map。其中key参数名,value是多个参数值,适用于多值的参数
header:对应请求头,它是一个map。其中key表示头名称,value是单个头值,适用于单值请求头 例:header[User-Agent] 因为中间有个减号,所以不能用点
headerValues:对应请求头,它是一个map。其中key表示头名称,value是多个头值,适用于多值请求头
initParam:获取<context-param>的参数
cookie 是Map<String,Cookie> 其中key是cookie的name,value是cookie对象。${cookie.username.value}
pageContext 是PageContext类型 例:${pageContext.request.contextPath }(获取项目名,表单提交地址,超链接地址都是用这个然后加/....)
5 EL函数库(JSTL提供)
<%@ taglib prefix="fn" url="http://java.sun.com/jsp/jstl/funtions"%> 导入函数库
使用:例:<fn:toUpperCase("hello")>
subStringAfter(String input,String subString) 截取之后的字符串
subStringBefore(String input,String subString) 截取之前的字符串
escapeXML() 转义 < > & ' "
int length(Object o)
join(String array[],String separator) 合并字符串
toUpperCase
toLowerCase
indexOf(String str,String str)
contains(String str,String str)
containsIgnoreCase(String str,String str)
startWith(String str,String str(开始符符))
endswith(String str,String str(结束符))
substring(String str,int start,int end)
trim
replace(String str,String old,String new)
spilt(String str,String str(分隔符))
6 自定义函数库
写一个java类,类中可以定义0-n个方法,但必须是static ,须有返回值
在后缀为tld文件中配置(在WEB-INF中创建)
例:
<funtion>
<name>fun</name>
<funtion-class>cn.itcast.fn.MyFuntion</funtion-class>
<funtion-signature>java.lang.String fun()<funtion-signature>
</funtion>
导入函数库
JSTL标签库
JSTL概述
apache,依赖EL,对EL表达式的扩展,标签语言
jstl标签库:
core:核心标准库
fmt:格式化:日期,数字
sql:过时
xml:过时
导入标签库
jar包
<%@taglib prefix="前缀" uri="路径"%>
core标签常用标签-->c标签
out :<c:out>输出
value:可以是字符串常量,也可以是EL表达
default:当要输出的内容为null时,会输出default指定的值
escapeXml:默认值为true。表示转义
set:<c:set>
var:变量
value:变量值,可以是EL表达式
scope:域,默认为page。可选填:page、request、session、application
remove <c:remove>:删除域变量
var :变量名
scope:如果不给出scope,表示删除所有域中的该名称的编乱给,如果指定了域,那么只删除该域的变量
url
value:指定一个路径,它会在路径前面自动添加项目名 <c:url value="/index.jsp/"> 输出/项目名/index.jsp
子元素:<c:param> 用来给url后面添加参数,例如:
<c:url value="/index.jsp/">
<c:param name="username" value="zhangsan"/> 可以对参数进行url编码
</c:url>
结果为:/项目名/index.jsp?username=%ED%2C%3F%ED%2C%3F%
var:指定变量名,一旦添加了这个属性,那么url标签就不会再输出到页面,而是把生成的url保存到域中
scope:与var一起使用
if:对应java中的if语句
<c:if test="布尔类型">......</c:if> 当test为真时,执行标签体内容 empty 表示为空(“布尔类型”),还有not的使用
choose:
<c:choose>
<c:when test="" >...</c:when>
.......
<c:otherwise>...</c:otherwise>
</c:choose>
等同于
if(...){ }
else if(...){ }...
else{}
forEach 用来循环遍历数组,集合,还可以用计数方式来循环
<c:forEach var="i" begin="1" end="10">
</c:forEach>
相当于:for(int i = 1;i<=10;i++){}
step::设置步长。等同于i++ ,或i+=2 step 默认等于1
var:var 循环变量
begin:设置循环变量从几开始
end:设置循环变量到几结束
用来输出数据集合
<c:forEach items="" var="">
<c:forEach>
相当于增强for
属性:
items:指定要遍历的目标,它可以是一个数组,或一个集合
var:把数组或集合中的每个元素赋值给var指定的变量
循环状态:使用varStatus来创建循环状态变量 例:varStatus=“VS”
VS.index:元素下标
VS.count:循环元素的个数
VS.first:是否为第一个元素
VS.last:是否为最后一个元素
VS.current:当前元素
fmt标签库常用标签
<fmt:format value="" pattern=""> 格式化日期
value:指定一个Date类型的变量
pattern:用来指定输出的模板 例如:yyyy-MM-dd HH:mm:ss
<fmt:formatNumber value="" pattern="">
value:用来指定要格式化的数字
pattern:格式:例如 0.00(保留小数点后两位,位数不够进行补位) #.##(不补位)
自定义标签
1 步骤:
标签处理类(标签也是一个对象,那么就需要先有类)
tld文件,它是一个xml
页面中使用<%@taglib%>来指定文件的位置
2 标签处理类
SimpleTag接口:
void doTag() :执行标签时会调用这个方法
JspTag getParent() 返回父标签(非生命周期方法)
void setParent(JspTag a) 设置父标签
void setJspBody(JspFragment b)设置标签体
void setJspContext(JspContext c) 设置jsp上下文对象,子类为PageContext
其中doTag() 会在其他三个方法之后被tomcat调用
simpleTagSupport 实现了SimpleTag接口 已经把所有的tomcat传递的数据保存起来,提供get方法供子类调用,只需重写doTag()方法就可以
3 tld文件配置,一般放在WEB-INF之下,这样保证客户端访问不到
<tag>
<name>...</name> 指定当前标签的名称
<tag-class>..</tag-class> 指定当前标签的标签处理类
<body-content>...</body-content> 指定标签体的类型
</tag>
4 页面中指定tld文件的位置 <%@taglib prefix="" url=""%>
5 标签体内容: (执行标签体this.getJspBody().invoke(...)如果传递的输出流是null。表示使用的就是当前页面的out)
empty:无标签体
JSP:jsp2.0不支持
scriptless:只能是EL表达式,也可以是其他的标签
tagdependent :标签体内容不会被执行,而是直接赋值标签处理类
不在执行标签下面内容的标签
在标签处理类中的doTag()中使用SkipPageException来结束
Tomcat会调用标签处理类的doTage()方法,然后Tomcat会得到SkipPageException,它会跳过本页面其他内容
标签属性
步骤:
1 给标签处理类添加属性,并且至少提供set方法。这个set方法会在doTag()方法之前被Tomcat调用
2 在tld文件中对属性进行配置
<attribute>
<name>属性的名字</name>
<required>true/false <required> 指定属性是否为必须的
<rtexprvalue>true/false(是否可以为EL表达式)</rtexprvalue>
</attribute>
MVC 设计模式
它不是java独有,所有的B/S结构的项目都在使用它
M--- model 模型 (自己写代码)
V--- view 视图(JSP)
C--- Cotroller 控制器(Servlet)
JavaWeb 三层框架
Web 层-->与Web 相关的内容(Servlet,JSP,Servlet相关API:request response session ServletContext)
业务层-->业务对象(Service)
数据层-->操作数据库(DAO Data Access Object)(所有对数据库的操作,不能跳出DAO之外)
案例:
功能:
注册:
登陆:
JSP:
login.jsp 登陆表单
regist.jsp 注册表单
index.j主页(只有登录成功才能看到)
Servlet
loginServlet
RegistServlet
Service
UserService 与用户相关的业务类
Dao
UserDao 与用户相关的数据类
Domin
User(对应数据库,还要对应所有表单)
username
password
verifyCode
数据库设计
users.xml
<users>
<user username="xxx" passwoed="xxx"/>
</users>
步骤:
1 创建空项目
2 导包:
CommonUtils
commons-beanutils.jar
commons-logging.jar
dom4j
3 建包
cn.com.user.domian
User
cn.com.user.dao
UserDao
cn.com.user.service
UserService
cn.com.user.web.servlet
LoginServlet
RegistServlet
4 创建一个users.xml
添加根元素
保证文件编码utf-8
5 JSP
login.jsp
regist.jsp
index.jsp
注册
regist.jsp
第一步:完成regist.jsp的基本功能
RegistServlet
封装表单数据,封装到User对象中。
调用UserService的regist()方法
如果这个方法没有出问题,给页面显示成功信息
如果这个方法抛出了异常,把错误信息保存到request域,转发到regist.jsp
UserService
没有返回值,但注册失败抛出一个自定义的异常,可以在异常中添加异常信息
校验用户名是否已被注册(通过用户名查询用户),如果已被注册,抛出异常,异常信息为“用户名已被注册”
添加用户
UserDao 通过业务分析,得到结果,需要提供两个方法
按用户名查询用户对象 User findByUsername(String username)
插入一个用户到数据库中 void add(User user)
工作
1 在service层添加一个UserException
2 dao:
User findByUsername(String username)
void add(User user)
3 service
void regist() throws UserException
4 servlet
1 封装表单数据到User对象中
2 使用user调用service的regist()方法
3 如果得到UserException,那么把异常信息保存到request域中,转发回regist.jsp
4 输出“注册成功”
给注册添加验证码:
1 VerifyCode类
BufferedImage getImage() 获取随机的验证码图片
String getText() 获取图片上的文本
static output(BfferedImage,ouputStream) 把图片写入到指定的输出流中
2VerifyCodeServlet
获取随机验证码图片
把验证码图片上的文本保存到session中
把图片响应到response的outputStream中
3 regist.jsp
添加<img src="指向Servlet"/>
添加一个文本框,用来输入验证码
“看不清,换一张”,是一个超链接。把上面的<img>的src重新指向Servlet,为了处理浏览器的缓存,需要使用时间来做参数
4 修改RegistServlet
校验验证码
错误:保存表单数据到request域,保存错误信息到request域,转发回regist.jsp
正确:什么都不做。向下执行原来代码
服务器端表单(输入校验)
我们把这段校验,放到获取表单数据之后
1 使用Map类型类装载错误信息
key:表单项名称,例如:username password
value:
非空:用户名不能为空,或者是密码不能为空
长度:用户名长度必须在3-20之间,密码长度必须在3-20之间
2 校验失败时,向map添加错误信息!那个字段出错,就给哪个字段添加错误信息
3 判断map是否为空(长度是否为0),如果不空,说明有错误存在,保存到map到request域中,保存form到request域,转发回regist.jsp
4 在regist.jsp页面中,显示map中的错误信息。例 ${map.username}
登陆功能:
页面:login.jsp-->登陆表单
LoginServlet-->
1 获取表单数据,封装到User中
2 调用service的login()方法,传递form过去
3 如果service的login()方法,没有抛出异常!返回User对象
4 有异常:获取异常信息,保存到request域,保存form,转发到login,jsp
5 没异常:保存返回的User对象到session中,重定向到index.jsp中(显示当前用户信息)
UserServlice#longin()
public User login(User form){}
1 使用用户名查询数据库,得到返回的User
返回为null,抛出异常,异常信息为(用户名不存在)
返回不为null,获取查询出来的user的password与form的password进行比较,如果不同,抛出异常(密码错误)
如果相同,返回查询结果
UserDao
1 通过用户名查询用户(已经存在了,不用再写了)