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);
}
}