javaWEB

javaWEB

2020/9/3 17:21:44


服务器搭建

tomcat独立环境 安装 

	前置条件: 
		1.	环境变量中, 配置JAVA_HOME变量, 变量值为: JDK安装的路径, 切记不包含in
		2.	关闭防火墙, 卸载杀毒软件 卸载**安全管家 , 卸载 *60安全卫士 

	步骤:
		1.	下载tomcat  (官网- http://tomcat.apache.org/ )(下载tomcat85)
		2.	解压到任意英文目录下 . 
		3.	使用管理员身份, 进入dos命令行
		4.	在dos命令行中, 进入tomcat解压目录/bin
		5.	输入安装指令并回车
			service install
		6.	观察安装成功的提示信息:
			the service 'tomcat8' has been installed;

运行tomcat , 通过网址访问

	前置条件:
		tomcat默认端口号为 8080 , 将其修改为 8090
		1.	找到tomcatconfserver.xml
		2.	在service.xml 大概70行的位置, 将8080更改为8090

	1.	打开tomcatin	omcat8w.exe
	2.	点击start启动服务器
	3.	在浏览器中, 通过ip:8090 来访问网站

卸载tomcat:

方式1.	通过tomcat自身service命令 完成卸载
		1.	管理员身份, dos命令行进入tomcatin
		2.	执行卸载指令: service remove

方式2.	通过windows指令, 删除服务
		1.	管理员身份, dos命令行输入: sc delete 服务名

HTTP协议

超文本传输协议 , 是一个应用层的网络传输协议 . 属于TCP/IP协议集中的一个子协议.

特点:
	1.	简单 , 快速
	2.	无连接协议 ,  每次连接服务器只处理一次客户端的请求, 处理完毕, 立即断开.
	3.	无状态协议 ,  处理请求时 , 以及给客户端回复时. 没有记忆能力 .
	4.	支持多种不同的数据提交方式, GET/POST等等
	5.	数据传输灵活, 支持任意数据类型.

HTTP协议的组成部分

由两部分组成 
	1.	请求
		请求由四部分组成:
			1.	请求头	 request header
					请求的头部信息 , 由一个个的键值对组成, 这些键值对描述的是客户端的信息.
			2.	请求体
					GET请求不存在请求体 ,将请求的参数存储在网址中
					POST请求请求体的作用:	用于存储客户端请求的数据
			3.	请求空行
					请求头部与请求体之间的一行空白行	
			4.	请求行
					由一个个的键值对组成, 这些键值对描述的是 请求的方式 ,访问的网址, 以及http协议的版本.


	2.	响应
		响应由三部分组成:
			1.	响应头
					响应头部的信息, 由一个个的键值对组成,  这些键值对描述的是服务器的信息.
			2.	响应体
					一个单独的数据报, 是服务器给客户端回复的主要内容.
			3.	响应行
					由一个个的键值对组成, 这些键值对描述的是 : 响应的状态码, 以及响应成功与失败的提示


常见的响应状态码:

	200	:	成功
	404	:	资源不存在
	500	:	服务器内部错误, (当程序出现异常时)

动态网页技术

网页会根据数据的不同, 展示不同的效果.

HttpServlet类

简介:
	是JavaWeb体系中 三大组件之一.
	本质上, 就是一个运行在tomcat中的java类, 
	作用是:可以用来处理客户端的请求, 以及对客户端进行响应.

实现步骤:
	1.	编写一个类 , 继承自HttpServlet类
	2.	重写父类的service(HttpServletRequest request,HttpServletResponse response)
	3.	在service方法中, 准备响应体.


将HttpServlet 映射到网址上 *****

	web3.0版本之前:
		步骤:
			1.	通过eclipse的javaEE 工具, 创建web.xml  (在3.0之前的项目创建时, web.xml默认是存在的)
			2.	向web.xml的根节点, 加入子节点:
					将Java类配置到tomcat中.
					<servlet>
						<servlet-name>给servlet起别名</servlet-name>
						<servlet-class>servlet的包名.类名</servlet-class>
					</servlet>
					给tomcat中的某个类, 添加网址 
					<servlet-mapping>
						<serlvet-name>要添加网址的别名</servlet-name>
						<url-pattern>/映射网址</url-pattern>
					</servlet-mapping>

			注意:
				如果映射网址为:  /demo1
				则浏览器访问时:	http://ip地址:端口号/项目名称/demo1

案例:
Java:
	public class Servlet1 extends HttpServlet{
		@Override
		protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
			//1.	设置响应内容的编码格式, 以及内容类型
			response.setContentType("text/html;charset=utf-8");
			//2.	通过响应对象, 得到用于准备响应体的打印流
			PrintWriter out = response.getWriter();
			//3.	打印内容
			out.println("<h1>Hello JavaWeb</h1>");
			
		}
	}

web.xml
	<servlet>
		<servlet-name>haha</servlet-name>
		<servlet-class>cn.xdl.demo1.Servlet1</servlet-class>
	</servlet>
	<!-- 给tomcat中的某个类, 添加网址 -->
	<servlet-mapping>
		<servlet-name>haha</servlet-name>
		<url-pattern>/s1</url-pattern>
	</servlet-mapping>

web3.0版本 和 3.0版本之后:

通过注解来完成映射网址的配置 : 

	
案例:

	@WebServlet("/s2")
	public class Servlet2 extends HttpServlet {
	
		/**
		 * service方法, 表示服务方法
		 * 当用户每次请求对应的网址时 , 此方法自动执行.
		 * 方法中的参数: 
		 * 		参数1.	HttpServletRequest  http协议中请求部分由tomcat进行了封装, 封装为了此对象, 对象中包含的是请求的相关信息.
		 * 		参数2.	HttpServletResponse 
		 * 				http协议存在响应部分, 而响应的内容, 是由我们的代码所生成的 , 
		 * 				而HttpServletResponse , 它就是tomcat为了方便我们进行响应, 将响应的操作 ,封装为了这个对象.
		 */
		@Override
		protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
			//1.	设置内容的类型 以及 编码
			response.setContentType("text/html;charset=utf-8");
			//2.	通过响应对象 得到向响应体输出的流
			PrintWriter out = response.getWriter();
			//3.	通过打印流, 向响应体中打印内容
			out
			.append("<html>")
			.append("<head><title>Servlet准备的网页内容</title></head>")
			.append("<body>")
			.append("<h1>示例标题</h1>");
			
			for (int i = 0; i < 100; i++) {
				out.append("<div>嘿嘿嘿"+i+"</div>");
			}
			out
			.append("</body>")
			.append("</html>")
			;
			//4.	当此方法执行完毕后, 则tomcat认为 响应体准备完毕, 会将内容响应给客户端.
		}

servlet的生命周期

指的是 Servlet从创建到消亡的周期

Servlet的创建时机:
	默认情况下, 当用户第一次访问Servlet的映射地址时, Servlet的对象被创建。
Serlvet的销毁时机:
	当tomcat关闭, 或 应用被卸载时, Servlet被销毁 
	(当tomcat关闭后 或 应用被卸载后, 用户无法再访问Servlet , 我们Servlet也就不需要在内存中存在了, 所以此时被销毁)


tocmat为了方便我们 进行资源的缓存 ,
为了让我们能在Servlet创建时, 初始化一些重复利用的资源, 
为了让我们能在Servlet销毁时, 释放这些重复利用的资源, 
提供了生命周期对应的方法 : 

	1.	init	方法:	当Servlet被创建时, 此方法执行,用于告知程序员, 第一次访问产生了. 我们可以在此方法中初始化后续重复利用的资源.
	2.	service	方法:	服务方法, 当用户每一次访问时, 都会执行, 用于处理用户的请求, 以及对用户进行响应.
	3.	destroy	方法:	当servlet即将被销毁时 , tomcat会调用此方法,  告知程序员. 我们可以在此方法中释放初始化的那些重复利用的资源.

调整Servlet对象的创建时机 (可以理解为: 懒汉变饿汉)

使用web.xml的配置方式: 
	在servlet节点中, 加入子节点: load-on-startup 来调整启动时机
	
	格式:

		<serlvet>
			<servlet-name></..
			<servlet-class>></...
			<load-on-startup>整型数字</load-on-startup>
		</servlet>

	load-on-startup: 
		取值为数字 , 默认值为-1:
			当值为负数时:			第一次请求时加载.
			当值≥0时 , 含义是: 服务器启动时 , 就加载servlet. 
								多个servlet之间值越小 越早加载. 值相同按照web.xml中自上而下的配置顺序加载 

ServletConfig

是Servlet的配置对象, 每一个Servlet都拥有一个配置对象.
我们在web.xml中, 进行servlet的配置时 , 可以向Servlet中添加初始化的参数
这些参数, 会被存储到一个ServletConfig 对象中.

 web.xml中配置的格式:
	<servlet>
		...
		...
		<!-- servlet节点中, 可以编写n个init-param节点, 每一个init-param节点都表示一个键值对. -->
		<init-param>
			<param-name>键</param-name>
			<param-value>值</param-value>
		</init-param>
	</servlet>

从servlet中得到SerlvetConfig对象的格式:
	在Servlet类中, 可以通过两种方式, 来获取配置对象 , 这两种方式在使用中, 是互斥的.
	
	方式1.	
		生命周期init方法中, 存储ServletConfig 参数. 在方法中使用参数即可.

	方式2.
		在Servlet的任意代码位置, 通过getServletConfig()方法得到对象

从servletConfig对象中, 根据键得到值的格式:

	String value = config对象.getInitParameter(String name);

GET请求 与 POST请求的区别

GET请求:
	-	请求的参数 以多个键值对的形式存储在网址中, 在网址的?后 , 键与值键值使用等号连接, 多个键值对之间&分割
	-	只能阐述字符串类型的参数
	-	网址的最大长度为4kb , 通常支持的文字数量是: 最大2048 
	-	数据传输的时 不安全

POST请求:
	-	请求的参数 以多个键值对的形式存储在单独的数据包中 , 这个数据包叫做请求体.
	-	请求体中可以包含任意类型的数据, 例如: 图片 . 音频 等..
	-	数据大小, 理论上是无上限的.
	-	因为请求体是单独的数据包, 所以较GET请求而言 安全;

什么样的请求 是 GET

以我们目前掌握的技术来说, 只有表单提交时method=POST , 请求方式是POST.  其他方式都是GET:

	-	浏览器输入网址 , 回车
	-	点击超链接访问
	-	表单提交时, method=GET
	-	通过js:  wondow.location对象, 进行替换与跳转 
	-	ajax的get请求

什么样的请求 是 POST

-	表单提交时method=POST 
-	ajax的post请求 

如何接受请求的参数:

1.	根据一个name , 接收单个参数
		String value = request.getParameter(String name);

2.	根据一个name , 接收一组参数
		String[] values = request.getParameterValues(String name);

上述的两个方法在获取数据时,  name不存在, 则获取的结果为null

请求乱码的问题解决:

解决乱码问题的两种方式:

	方式1. 
		适用于tomcat8版本之前的GET请求乱码解决, 以及所有版本的POST乱码解决:

		解决乱码的原理: 
				将文字乱码的流程, 倒序执行一遍,得到正确的文字.
				倒序:	
					1.	将乱码的文字,按照ISO-8859-1转换为字节数组
					2.	将字节数组按照UTF-8的编码转换为文字

		格式:
			//1.	将乱码的文字,按照ISO-8859-1转换为字节数组
			byte[] bytes = 乱码文字.getBytes("ISO-8859-1");
			//2.	将字节数组按照UTF-8的编码转换为文字
			String text = new String(bytes,"UTF-8");

方式2.
	适用于tomcat所有版本的post乱码的解决.

	解决乱码的原理:
		在使用请求体之前, 将请求体的默认编码更改为utf-8.

	格式:
		//设置请求体的编码,  一定要写在获取参数之前.
		request.setCharacterEncoding("UTF-8");

Servlet线程安全问题

Servlet的service方法,  在用户每次请求时调用.
service方法的调用比较特殊:
	service方法的执行, 每一次都是在新的线程中.

因为service方法,  执行在新线程中,  有可能同时存在多个线程.  多线程操作时, 有可能发生线程安全问题.1


1.	静态的同步方法的 同步锁  --> 类.class 这个对象

2.	非静态的同步方法的 同步锁 --> this对象

3.	同步代码块的 同步锁 --> 程序员使用时 提供.


案例:

	@WebServlet("/s1.do")
	public class Servlet1 extends HttpServlet {
		//余票
		private int count = 10;
		protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
			synchronized(this) {
				if(count>0) {
					//有票
					System.out.println("有票, 正在出票");
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					count--;
					System.out.println("出票完成, 余票:"+count);
				}else {
					System.out.println("很遗憾 ,没有余票了");
				}
			}
			response.getWriter().append("ok");
		}
	}

请求的转发

概念:	将一个web组件 为处理完毕的请求, 通过tomcat转交给另一个web组件处理.

步骤:
		1.	获取请求转发器
				RequestDispatcher rd = request.getRequestDispatcher("转发的地址");

		2.	通过转发器 发起转发
				rd.forward(请求对象 , 响应对象);

简写步骤:
		 request.getRequestDispatcher("转发的地址").forward(请求对象 , 响应对象);

原理(tomcat内部执行流程):
		1.	当浏览器访问服务器中的tomcat时.
		2.	tomcat将协议中的请求进行封装, 封装为HttpServletRequest对象 , 将响应封装到HttpServletResponse对象中
		3.	找到对应映射地址的Servlet , (第一次寻找会创建对象) , 调用对象的service方法, 传入请求与响应对象.
		4.	在serlvet中, 我们可以控制将请求转发到另一个地址 , 
		5.	tomcat接收到请求转发指令后, 将原请求对象 和 新的响应对象传给转发的新地址.
		6.	此时旧的响应对象就失效了, 无法在进行响应了. 由新的地址的响应对象 负责给用户进行响应.
		7.	新地址准备完毕响应体, 发送给浏览器
特点:
	1.	转发的过程中, 只发生了一次请求, 多个Servlet之间共享一份请求信息.
	2.	转发无法跨域实现 ( 无法跨网站进行转发, 例如: 京东无法转发给淘宝.)
	3.	无论转发过程中, 触发了多少个web组件 , 对于浏览器而言, 它能感知到的 只是发起了一次请求, 接收到了一次响应.
	4.	转发过程中, 浏览器地址不会发生改变
	5.	相较于重定向而言, 效率高.

请求的重定向

概念:	在进行响应时, 告知浏览器新的请求地址, 浏览器接到后,自动发起新的请求找指定的地址.

步骤:
		response.sendRedirect("重定向的新地址");

原理(执行流程):
		1.	当浏览器请求某个Servlet时.  
		2.	Servlet对浏览器响应一个302的状态码 ,  以及一个 键为location的值, 这个值表示新的地址;
		3.	当浏览器接收到302的状态码以后, 会自动寻找lcoation的值, 并网页自动跳转到location的值表示地址上 !
特点:
	1.	重定向会产生新的请求 和 新的响应.
	2.	使用重定向,  可以跨域实现 (可以跨网站操作 ,例如: 京东可以将请求重定向到淘宝)
	3.	浏览器地址会发生改变 , 显示的是重定向的地址;
	4.	相较于请求转发而言, 效率较低.

注意:

1.	在用户的一次访问过程中, 我们可以进行无限次的转发/重定向 ! 但是记住一点: 在多次转发/重定向的操作中, 一定要有出口 !
2.	不只是可以将请求转发/重定向到servlet上, 任何的web资源都可以接受转发 和 重定向. 
3.	当我们的代码进行了转发/重定向时 , 相当于将响应的操作交给了其他资源. 那么在进行转发和重定向的代码后面, 就不要再编写响应的操作了. 因为无效. 

HttpServletRequest 类的常用操作

1.	获取客户端的ip地址:
		String ip = request.getRemoteAddr();

2.	获取客户端访问的地址:
		String url = reuqest.getRequestURI();

3.	获取tomcat运行的ip地址
		String ip = request.getServerName();

4.	获取tomcat运行的端口号
		String port = request.getServerPort();

5.	获取请求方式
		String method = request.getMethod();	

6.	获取get请求的?后的参数列表
		String params = request.getQueryString();	

HttpServletResponse 类的常用操作

1.	设置响应的内容类型(网页) 以及 编码格式(UTF-8)
		response.setContentType("text/html;charset=utf-8");

2.	设置响应的内容编码格式 (常用于响应JSON数据)
		response.setCharacterEncoding("UTF-8"); 

3.	响应错误码给客户端
		response.sendError(int status,String msg);

ServletContext 对象 (Servlet上下文)

每一个Servlet都是一个独立的网页地址 , 它们之间无法进行通信以及交流 ,
例如:	我们想统计网站的访问次数 , 每一个servlet只能统计自己被访问的次数, 无法汇总.

Servlet上下文对象, 就是用于Servlet之间信息共享的, 是多个servlet之间通信的桥梁 
Servelt上下文对象, 在项目的运行过程中, 只有一个.每一个Servlet获取的上下文对象, 都是同一份.
Servlet上下文对象, 就像一个Map集合, 可以存储n个键值对信息!
如何得到项目的Servlet上下文对象
格式:
	ServletContext context = getServletContext();
上下文对象常用方法 熟悉
1.	存储数据
		context.setAttribute(String name,Object value);
2.	获取数据
		Object value = context.getAttribute(String name);
3.	删除数据
		context.removeAttribute(String name);

4.	获取项目运行时的文件夹 绝对路径.
		String path = context.getRealPath("/");

会话跟踪技术 (状态管理)

Http协议是无状态的 , 没有记忆能力.
在浏览器与服务器交互时, 因为无状态的特性, 会导致无法连贯的交互.

HTTP协议实现状态管理, 有两种方式:

	1.	Cookie技术		:	将交互时产生的状态 存储在客户端中.
	2.	Session技术		:	将交互时产生的状态 存储在服务器中.

Cookie技术

技术步骤, 以及原理:

	1.	当服务器向客户端响应时,  可以向响应头中加入Cookie , 每一个Cookie表示一个键值对
	2.	当浏览器接收到响应头中的Cookie后, 会将其存储在本地的一个文本文件中, 
	3.	当浏览器再次访问相同的服务器时,  会去文本文件中寻找这个服务器之前存储的Cookie 
	4.	将寻找到的Cookie 携带到请求头中, 发送给服务器.


如何创建一个Cookie 
	Cookie 在Java程序中的体现 是一个表示键值对的 Java类. 类名为Cookie

	格式:
		Cookie  cookie  = new Cookie(String name,String value);

如何将创建的Cookie 添加到响应的头部 

	通过响应对象, 将Cookie 添加到响应的头部

	格式:
		response.addCookie(Cookie cookie);

	一次响应, 可以添加0-n个Cookie  , 
	浏览器接收后, 会存储到文本文件中 , 如果相同域的相同路径 存储相同键的Cookie , 会导致旧值被覆盖.



如何从请求头部 得到 我们之前存储的多个Cookie 

	可以从请求对象中, 得到之前存储的Cookie信息, 得到的是一个Cookie数组 , 如果从未存储过Cookie ,则得到的数据是null
	
	格式:
		Cookie[] cookies = request.getCookies();

如何调整Cookie的存活时长 

	cookie.setMaxAge(int 秒);

	传入的值:
		-	负数		:	默认值为-1, 负数表示浏览会话结束时 删除. (指的是浏览器关闭)
		-	正数		:	存活的秒数
		-	0		:	存活的秒数, 通常用户覆盖一个Cookie ,来完成删除操作.


Cookie存储时的路径问题 

	因为Cookie发送时, 需要匹配域 和路径 . 
	我们在编写项目时, 经常因为路径不同, 导致cookie无法读取. 

	Java为我们提供了设置Cookie路径的方法, 我们可以在任意的servlet中, 将Cookie路径设置为一致, 来存储和读取.

	格式:
		在cookie添加到响应头部之前 设置:
		cookie.setPath("/");


Cookie技术的优缺点: 

	缺点:
		1.	Cookie存储的数据类型有限制, 只能存储字符串 		( 早期无法存储中文 )
		2.	数据存储的大小有限制, 不能超过4kb (4096个字节)	
		3.	数据存储在用户的计算机的 文本文件中 , 不安全, 有可能被恶意程序读取.
		4.	受限于用户的浏览器设置,  当浏览器禁用Cookie时, cookie就无法使用了.
		
	优点:
		数据存储在客户端中, 分散了服务器的压力. 

Session技术

技术步骤, 以及原理

	1.	浏览器访问服务器时,  服务器可以主动创建Session对象 , 一个session表示一个键值对的容器 ,类似Map集合
	2.	每一个Session创建时, 会产生一个id , 这个id会存储到一个Cookie中, 并发送给浏览器
	3.	等浏览器下一次访问时, 会携带Cookie, cookie中包含session的id , 
	4.	我们就可以根据得到的sessionid , 从服务器中寻找到属于这个浏览器的session对象.

如何获取session对象

格式1. ****
		调用请求的获取session的方法 (无参) , 方法的内部调用了一参方法, 传入了true
		HttpSession session = request.getSession();

格式2.
		调用请求的获取session的方法 (一参)
		HttpSession session =  request.getSession(boolean isNew);

		参数的含义:
			true:	根据浏览器发来的sessionid 寻找session对象并返回, 如果不存在 ,则创建新的并返回
			false:	根据浏览器发来的sessionid 寻找session对象并返回, 如果不存在 ,则返回null

session的常用方法

1.	存储数据
		session.setAttribute(String name,Object value);
2.	取出数据
		Object value = session.getAttribute(String name);
3.	删除数据
		session.removeAttribute(String name);
4.	销毁这个Session
		session.invalidate();

session的存活时长

session的默认存活时长为30分钟, 
当用户的上一次访问 距离现在已经超过30分钟时,  session会自动销毁.

设置session的存储时长:

	方式1.	修改单个session的时长:
				session.setMaxInactiveInterval(int 秒);

	方式2.	修改tomcat下, 所有session的默认时长
				独立环境:	找到conf/web.xml文件
				开发环境:	找到servers/web.xml

				修改其中的session-config节点
				
				案例:
					<session-config>
						<session-timeout>数值分钟</session-timeout>
					</session-config>

session的优缺点

优点:
		1.	数据存储在服务器中, 安全
		2.	session中可以存储任意类型数据
		3.	存储的数据大小, 理论上是无限制的.
缺点:
		数据存储在服务器中, 大量的用户存储session时, 会对服务器造成极大的压力, 极易导致服务器资源耗尽.

Cookie技术 和 Session技术 不是互斥的.

Cookie和session 我们是结合使用的.

	对于安全无要求的字符串数据, 存储在cookie中
	对于安全敏感的数据, 存储在session中
	对于安全敏感 , 且较大数据, 存储在数据库中...

JSP简介

Java Server Pages Java的动态网页技术

JSP引擎

引擎原理:

	JSP引擎用于将JSP文件, 转换为Servlet

原理步骤:
	1.	在服务器启动时, JSP引擎读取JSP文件
	2.	将文件转换为Servlet , 并给Servlet添加映射地址为 原JSP 文件名称.
	3.	当用户访问  xxxx.jsp时, 请求的不是jsp文件, 而是JSP引擎根据文件转换的Servlet

JSP语法结构 *

JSP文件保存在 .jsp文件中 .  保存的路径:  webContent目录下.

JSP语法存在三大语法结构:

	1.	HTML代码
	2.	Java代码
	3.	JSP特有的一些语法结构.


Java代码声明区 

	指的是 Java类的成员位置 , 在JSP文件中的Java代码声明区中编写的Java代码, 会原封不动的生成到Servlet的成员位置!


	语法格式:
		<%!
			编写声明区的Java代码
		%>

Java代码执行区 

	指的是Servlet的service方法. 用于每次请求都会执行

	语法格式:
		<%
			编写Java逻辑代码,  生成到service方法中
		%>

输出表达式 

	用于快速的将Java代码中的变量, 输出到网页中

	语法格式:
		<%=变量名 %>

	上述语法格式中的值, 其实是被生成到了out的print方法中,

	例如:			<%=count  %>
	生成的Servlet:	out.print(count);

JSP中的注释:

因为JSP包含了三种语法结构.

所以三种结构的注释, 都可以使用.

HTML注释:
	语法:	<!-- 注释 -->
	注意:	在JSP中, 只能编写在HTML代码的位置 ,只能用于注释HTML部分. 
			编写的HTML注释会被JSP引擎认为是HTML代码 , 转换为:	out.write("<!-- 注释 -->");
	
Java注释:
	语法:	//单行  /*多行*/ /**文档*/
	注意:	在JSP中, 只能编写在Java代码的位置, 只能用于注释Java部分.
			编写Java注释会被JSP引擎认为是Java代码, 原封不动的转换到Servlet中

JSP注释:
	语法:	<%-- JSP的注释 --%>
	注意:	指的是JSP文件的注释, 被JSP注释的内容, 在JSP引擎转换时期被忽略.

JSP三大指令

指令的格式:
	<%@ 指令名称 属性名1=值 属性名2=值 ... 属性名n=值 %>

page指令

完整格式:
	<%@ page
		language="java"
		contentType="text/html;charset=utf-8"
		pageEncoding="UTF-8"
		extends="继承的类"
		buffer="数字|none" -- 是否允许缓存, 以及允许缓存的大小. 默认缓存, 大小为8kb
		autoFlush="true|false" -- 缓冲器是否自动清除, 默认为true
		session="true|false" -- 是否在service方法中,  提前创建好session , 默认true
		isThreadSafe="true|false" -- service方法是否是线程安全的. 默认false
		errorPage="网址" -- 当JSP中的代码出异常时,  页面自动跳转到网址 ,通常用语提示BUG.  **
		isErrorPage="true|false" -- 用于处理错误的页面 , 通常isErrorPage=true的页面, 会被其他页面通过errorPage引入.  **
								 --	为true时, 会在service中提前准备好, 异常对象 exception
		import="导包列表" -- 属性值是导包的内容,  多个包之间使用逗号隔开 ** 
	%>

指定项目全局错误码的 处理页面 *

步骤:
	1.	先打开项目的 web.xml文件
	2.	在根节点中, 加入子节点:
			<error-page>
				<error-code>错误码</error-code>
				<location>处理的页面地址</location>
			</error-page>

	注意:	error-page可以编写多个

	例如:
			<error-page>
				<error-code>404</error-code>
				<location>/error.jsp</location>
			</error-page>
			<error-page>
				<error-code>500</error-code>
				<location>/error.jsp</location>
			</error-page>

include指令

用于将一个JSP 或 HTML文件, 引入到另一个JSP文件中

格式:	<%@ include file="地址" %>

include动作

用于将一个JSP或HTML文件 引入到另一个JSP文件中.

格式:	<jsp:include page="地址" flush="true" />

include 指令与动作的区别

include指令:	在JSP的转换时期 , 将引入的JSP文件嵌入到了include指令的位置 (合并为了一个文件), 然后转换为Servlet ! 最终生成的是一个.java文件
include动作:	在JSP程序的转换时期, 引入的JSP文件会独立转换为Servlet , 到访问时, 在将响应体合并, (将被引入文件的响应体 , 动态加载在文件中) !

JSP内置对象(隐含对象)

内置对象指的是:	JSP引擎在转换时期 , 在service方法的前面, 帮我们提前准备好的一些对象. 我们在<%%>代码块中, 可以直接使用它们.

作用:
	这些对象包含了我们进行动态网页开发 常用的一些对象. 提供了大量的便于我们开发的功能, 可以简化我们的开发过程.

九大内置对象

1. * 
	对象名	:	request
	类型		:	HttpServletRequest
	作用		:	请求对象, 包含了请求相关的信息 !

2. *
	对象名	:	response
	类型		:	HttpServletResponse
	作用		:	响应对象, 包含了一些用于响应的功能

3. *
	对象名	:	pageContext
	类型		:	PageContext
	作用		:	页面的上下文 ,  用于获取其它8大内置对象. 

4. *
	对象名	:	session
	类型		:	HttpSession
	作用		:	会话对象 , 用于会话跟踪 与 状态管理

5. *
	对象名	:	application
	类型		:	ServletContext
	作用		:	Servlet的上下文 , 一个应用程序启动中, 只会存在一个Servlet上下文, 用于多个Servlet之间的数据共享与通信.

6. 
	对象名	:	out
	类型		:	JSPWriter
	作用		:	打印流, 用于向响应体中输出数据.

7.
	对象名	:	config
	类型		:	ServletConfig
	作用		:	Servlet的配置对象, 用于初始化一些键值对信息

8.
	对象名	:	page
	类型		:	Object , 但是在赋值时, 使用的是this . 所以本质上是当前JSP转换的Servlet类的类型.
	作用		:	指当前页面自身 .

9.
	对象名	:	exception
	类型		:	Throwable
	作用		:	当页面的page指令: isErrorPage="true"时, 才会存在的一个对象.
				当别的页面发生异常后, 跳转到此页面时 , exception是发生的异常对象.

JSP的四大域对象

九大内置对象中, 包含四个较为特殊的对象. 这四个对象我们称其为:		域对象! 
域对象存在一个特点: 
	都包含存储数据 / 删除数据 / 获取数据的方法 , 所谓的域, 指的是存储的数据使用的作用域.
	
	存储数据:
		setAttribute(String key,Object value);
	获取数据:
		Object value = getAttribute(String key);
	删除数据:
		removeAttribute(String key);

四大域对象:
	-	pageContext (一个JSP页面的域对象) 
			页面的上下文 , 存储在pageContext中的数据 , 域是最小的, 只有当前请求的当前页面才可以使用. 页面响应完毕对象就被垃圾回收了. 
	-	request (一次请求域对象)
			请求对象 , 存储在request对象中的数据, 只有当前请求 , 才可以使用 ! 一次请求可能发生多次转发 ,所以有可能跨越多个Servlet/JSP页面.
	-	session (一次会话域对象)
			会话对象, 存储在session对象中的数据, 在当前会话中可以使用. 一次会话可能包含多次请求.
	-	application (一次服务域对象)
			Servlet上下文对象, 存储在application中的数据, 在服务器关闭之前都可以使用.  
			应用的一次启动, 服务器中只会存在一个application对象, 一次服务器启动中可能包含多次会话.

EL表达式

作用, 用于快速的从域对象中 取出数据, 并将结果输出到网页中 .

格式:
	${ 表达式 }

EL表达式的使用

1.	用于运算

	${1+2+3+4+5}	输出的结果是:	15

2.	用于取出域对象中的数据  

	访问存储的数据格式: ***
		${存储的key}

	访问存储的对象的属性:
		格式1.	${存储的key.属性名} ***
		格式2.	${存储的key["属性名"]}
		格式3.	
			动态取值:	
				指的是按照域对象中存储的一个属性名, 以及对象名, 从对象中取出属性值
			
				${存储的对象key[属性名的key]}

3.	用于取出域对象中的集合/数组中的对象属性	
		格式1.	${存储的key[下标].属性名}
		格式2.	${存储的key[下标]["属性名"]}
		格式3.	
			动态取值:	
				指的是按照域对象中存储的一个属性名, 以及对象名, 从对象中取出属性值
			
				${存储的对象key[下标][属性名的key]}

EL表达式, 取出数据的流程

寻找的顺序:	从域范围小的 到 域范围大的	

步骤:

	1.	先从pageContext中, 寻找数据是否存在.
	2.	如果pageContext中不存在数据, 则去request中寻找数据是否存在.
	3.	如果request中不存在数据, 则去session中寻找数据是否存在.
	4.	如果session中不存在数据, 则去application中寻找数据是否存在
	5.	如果application中不存在数据, 则向网页输出 :  ""

在上述的步骤中, 一旦寻找到数据, 则流程结束, 将寻找到的数据输出到网页中.

taglib 指令 熟悉

用于在JSP中, 引入标签库.

语法格式:
	<%@ taglib prefix="短名称" uri="地址"%>


属性:
	prefix	:	是引入的标签库的名称, 用于区分引入的多个标签库 , 
				在使用标签库中的标签时 , 需要在前面加入库名:

	uri		:	引入标签库的操作 与 网页中引入其他静态资源不一样. 
				引入静态资源(图片,音乐等等) , 使用相对路径.
				每一个标签库都拥有uri属性, 引入标签库, 不需要路径, 只需要匹配uri就可以

JSTL标签库的使用

JSTL 是一套JSP的标准标签库
IF标签
格式
	<短名称:if test=""></短名称:if>
	test值:	boolean值 , 可以是具体的boolean值, 也可以是el表达式运算的结果

	如果test值为true , 则内容显示
	如果test值为false , 则内容不显示 (内容不会通过流, 输出到响应体中)

案例:
		<heihei:if test="${ flag }">
			从前有一座山 , 山上有座尼姑庵 , 庵里有个老尼姑 和 一个小姐姐 . 
		</heihei:if>

choose + when + otherwise

类似Java中的:	switch + case + default

作用:
	用于多分支, 显示.

案例:
	<%
		pageContext.setAttribute("flag",6);
	%>
	<heihei:choose>
		<heihei:when test="${ flag==1 }">孔子东游 , 见两小儿辩日</heihei:when>
		<heihei:when test="${ flag==2 }">千呼万唤始出来</heihei:when>
		<heihei:when test="${ flag==3 }">白日依山尽</heihei:when>
		<heihei:when test="${ flag==4 }">日照香炉生紫烟</heihei:when>
		<heihei:when test="${ flag==5 }">万里江陵十日还</heihei:when>
		<heihei:otherwise>
			停车坐爱枫林晚
		</heihei:otherwise>
	</heihei:choose>


forEach 标签

	用于遍历集合或数组元素

	格式:
		<标签库名称:forEach items="" var="">
		
		</标签库名称:forEach>

	属性:
		items	:	使用el表达式, 从域对象中取出的要遍历的数组或集合对象.
		var		:	在进行遍历时, 数组或集合中的每一个元素被取出后, 会单独存储在pageContext中, var的值就是存储时的键

	案例:
		
		<%
			ArrayList<String> data = new ArrayList<>();
			data.add("孔子东游 , 见两小儿辩日");
			data.add("千呼万唤始出来");
			data.add("白日依山尽");
			data.add("日照香炉生紫烟");
			data.add("万里江陵十日还");
			data.add("停车坐爱枫林晚");
			data.add("老骥伏枥志在千里");
			pageContext.setAttribute("data", data);
		%>
		<heihei:forEach items="${data }" var="str">
			<h1>${ str }</h1>
		</heihei:forEach>

自定义标签库

步骤:
	1.	编写一个类, 继承SimpleTagSupport 类
	2.	重写类的doTag方法 ,
	3.	在doTag方法中, 通过getJspContext() 方法 得到JSP的上下文.
	4.	通过上下文对象, 可以得到其他8大内置对象 , 通常我们是getOut()得到输出流, 向网页输出内容.

	5.	编写tld文件, 描述标签库和标签.


案例:
	Class:
		public class MyTag extends SimpleTagSupport {

		private static ArrayList<String> data = new ArrayList<>();
		static {
			data.add("理想是人生的太阳。 —— 德莱赛");
			data.add("真实是人生的命脉,是一切价值的根基。 —— 德莱塞");
			data.add("真的猛士,敢于直面惨淡的人生,敢于正视淋漓的鲜血。 —— 鲁迅");
			data.add("人生须自重。 —— 黄宗羲");
			data.add("在人生的道路上,当你的希望一个个落空的时候,你也要坚定,要沉着。 —— 朗费罗");
			data.add("真理惟一可靠的标准就是永远自相符合。 —— 欧文");
			data.add("竹子用了4年扎根,第五年一出头就被做成竹笋炒肉。");
			data.add("公主病的成因没别的,不是丑就是穷。“那有钱又漂亮脾气却不好的呢?”那本来就是公主,不叫病。");
			data.add("所谓的女汉子,只不过是因为长得丑而已,但凡有些爷们气质的漂亮姑娘,都被称为女王大人。");
			data.add("腾不出时间来睡觉的人,迟早会腾出时间来生病;腾不出时间来恋爱的人,迟早会腾出时间来相亲。");
			data.add("快乐分享错了人就成了显摆,难过分享错了人就成了矫情。");
			data.add("请记住,你并不是一无所有,你还有病!哈哈");
			data.add("鱼和熊掌不可兼得,但单身和穷可以!");
			data.add("用钱当然买不到快乐,但只要你有钱,别人会想办法让你快乐。");
			data.add("你才二十多岁,没有遇到对的人很正常,以后你就知道,大概遇不到了!");
			data.add("这年头,当个宅男宅女,也得先买房子!");
			data.add("能背后给你一刀的,往往是你信任的!");
			data.add("失败并不可怕,可怕的是你还相信这句话。");
			data.add("比一个人吃火锅更寂寞可怜的是,一个人没有钱吃火锅。");
			data.add("你只知道人家化妆比你好看,却不知道,她们卸了妆,不仅比你好看,皮肤还吹弹可破。");
			data.add("从前车马很慢,书信很远,一生只够爱一个人,但是能纳很多妾。");
			data.add("岁月告诉我,除了快递,我啥也等不到!");
			data.add("假如今天的你被生活辜负了,别伤心,因为明天生活还会继续辜负你!");
		}
		
		@Override
		public void doTag() throws JspException, IOException {
			JspContext context = getJspContext();
			JspWriter out = context.getOut();
			String text = getText();
			out.print(text);
			
		}
		public String getText() {
			Random r = new Random();
			int i = r.nextInt(data.size());
			return data.get(i);
		}
	}




	TLD文件:

	<?xml version="1.0" encoding="UTF-8" ?>
	<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
	    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
	    version="2.0">
	  	<!-- 注释 ,描述  -->
	  	<description>这是兄弟连Java30期自定义的一个标签库</description>
	  	<!-- 名称 -->
	  	<display-name>XDL</display-name>
	  	<!-- 版本 -->
	  	<tlib-version>5.21</tlib-version>
	  	<!-- 短名称 -->
	  	<short-name>x</short-name>
	  	<!-- 用于匹配的uri -->
	  	<uri>http://hahaha.heiheihei.com</uri>
	  	<!-- 在标签库中 一个tag节点 , 表示库中的一个自定义标签 -->
		<tag>
			<!-- 标签的描述 ,在使用时, 会提示 -->
			<description>这个标签会向网页中输出一条鸡汤句子</description>
			<!-- 标签的名称 -->
			<name>djt</name>
			<!-- 标签的类的全名 -->
			<tag-class>cn.xdl.tag.MyTag</tag-class>
			<body-content>empty</body-content>
		</tag>
	</taglib>

web三大组件

1.	Servlet
2.	Filter	过滤器
3.	Listener 监听器

Filter 过滤器

所谓的过滤. 指的是过滤请求.
有时我们进行后段项目开发时, 有些请求 ,需要特定的条件才能操作 我们可以通过Filter , 来过滤不满足的用户操作.
例如:	
	用于的个人中心, 应该是登录	后才可以查看的.
	当用户请求个人中心页面时, 我们就可以编写过滤器, 将未登录的所有用户过滤掉, 并重定向至登录页面.

采用了面向切面编程思想(AOP) .

使用步骤:

	1.	编写一个类 , 实现Filter接口
	2.	通过web.xml 或 注解的方式, 配置过滤器的过滤地址. 

案例:

	public class ParamFilter implements Filter {
		/**
		 * 当发生匹配过滤地址的请求时, doFilter执行
		 * 过滤器执行在web的所有资源之前 , 默认此方法是拦截请求的, 
		 * 如果需要放行 , 需编写: chain.doFilter(request,response);
		 */
		@Override
		public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
				throws IOException, ServletException {
			
			HttpServletRequest req = (HttpServletRequest) request;
			HttpServletResponse resp = (HttpServletResponse) response;
			if(req.getParameter("a")==null) {
				resp.setContentType("text/html;charset=utf-8");
				//拦截
				resp.getWriter().append("<h1>很遗憾, 参数错误, 无法访问</h1>");
			}else {
				//放行
				chain.doFilter(request, response);
			}
		}
	}


web.xml

  <filter>
  	<filter-name>pf</filter-name>
  	<filter-class>cn.xdl.demo1.ParamFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>pf</filter-name>
  	<url-pattern>/home.jsp</url-pattern>
  </filter-mapping>

过滤器链 

	当多个过滤器, 过滤地址重复时 , 就形成了过滤器链 . 用户的请求, 需要过滤器链中的所有过滤器放行, 才可以正常访问.

	过滤器链执行的顺序: 
		web.xml中的顺序: 按照web.xml中配置的先后顺序, 来执行. 

		注解配置的顺序:	 按照类名的自然排序, 顺序执行. 

		web.xml中配置的过滤器, 一定执行在注解配置过滤器的前面.

Listener

监听器 , 监听是服务器的一些事件 . 

两类事件:
	1.	服务器中组件的生命周期相关事件. 
	2.	域对象中数据的变化事件 . 


ServletContextListener 

	用于监听Servlet上下文的创建与销毁.  

	案例:
		@WebListener
		public class MyServletContextListener implements ServletContextListener {
		
			/**
			 * 当上下文对象 即将销毁时, 方法执行
			 * 上下文对象销毁的时机, 是 服务器关闭或项目被卸载. 所以我们常在这里进行全局资源释放的操作. 
		     */
		    public void contextDestroyed(ServletContextEvent arg0)  { 
		    	System.out.println("项目关闭了");
		    }
		
			/**
			 * 当上下文对象 被创建初始化时  , 这个方法执行
			 * 因为上下文对象创建的时机是 服务器中项目启动时  , 所以我们常在这里进行全局资源的初始化操作.
		     */
		    public void contextInitialized(ServletContextEvent arg0)  { 
		    	System.out.println("项目启动了");
		    }
		}


ServletContextAttributeListener 

	用于监听ServletContext中属性的变化 

	案例:
		@WebListener
		public class MyServletContextAttributeListener implements ServletContextAttributeListener {
		
			/**
			 * 当向上下文中 添加属性时, 代码执行
		     */
		    public void attributeAdded(ServletContextAttributeEvent e)  { 
		    	//从事件对象中, 得到存储的键和值
		    	String key = e.getName();
		    	Object value = e.getValue();
		    	System.out.println("监听到ServletContext中数据的增加:"+key+" --> "+value);
		    }
		
			/**
			 * 当从上下文中 移除属性时, 代码执行
		     */
		    public void attributeRemoved(ServletContextAttributeEvent e)  { 
		    	//从事件对象中, 得到被移除的键和值
		    	String key = e.getName();
		    	Object value = e.getValue();
		    	System.out.println("监听到ServletContext中数据的移除:"+key+" --> "+value);
		    }
		
			/**
			 * 当操作上下文对象 存储数据 ,发生替换时, 代码执行.
		     */
		    public void attributeReplaced(ServletContextAttributeEvent e)  { 
		    	//从事件对象中, 得到被替换掉的旧的键和值
		    	String key = e.getName();
		    	Object oldValue = e.getValue();
		    	System.out.println("监听到ServletContext中数据的替换, 旧数据:"+key+" --> "+oldValue);
		    	//从事件对象中, 得到上下文对象
		    	Object newValue = e.getServletContext().getAttribute(key);
		    	System.out.println("监听到ServletContext中数据的替换, 新数据:"+key+" --> "+newValue);
		    }
			
		}


HttpSessionListener 

	用于监听session的创建与销毁. 

	@WebListener
	public class MySessionListener implements HttpSessionListener {
		
		private static int count = 0;
		private static Random r = new Random();
		ArrayList<Integer> nums = new ArrayList<>();
	    public void sessionCreated(HttpSessionEvent arg0)  { 
	    	//30-60的随机数字
	    	int num = r.nextInt(31)+30;
	    	count+=num;
	    	nums.add(num);
	    }
	
	    public void sessionDestroyed(HttpSessionEvent arg0)  { 
	    	int num = nums.remove(nums.size()-1);
	    	count-=num;
	    }
	    
	    public static int getCount() {
	    	return count;
	    }
		
	}

HttpSessionAttributeListener

用于监听session中的数据的增加 ,删除, 修改.

	public class LoginServlet2 extends HttpServlet {

		/**
		 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
		 */
		protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
			String uname = request.getParameter("uname");
			String upass = request.getParameter("upass");
			
			request.getSession().setAttribute("username", request.getRemoteAddr()+":"+uname);
			response.sendRedirect("home2.jsp");
		}
	
		/**
		 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
		 */
		protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
			// TODO Auto-generated method stub
			doGet(request, response);
		}
	
	}
原文地址:https://www.cnblogs.com/lzy1212/p/13608925.html