jsp,servlet的学习

1. Web 相关概念
1.1 软件架构
C/S :客户端 / 服务器端
B/S :浏览器 / 服务器端
1.2 资源分类
静态资源:所有用户访问后,得到的结果都是一样
的,称为静态资源 . 静态资源可以直接被浏览器解析
如: html,css,JavaScript
动态资源 : 每个用户访问相同资源后,得到的结果可能
不一样。称为动态资源。动态资源被访问后,需要先
转换为静态资源,在返回给浏览器
如: servlet/jsp,php
图解: 1.3 网络通信三要素
IP :电子设备在网络中的唯一标识。
端口 :应用程序在计算机中的唯一标识。 0~65536
传输协议 :规定了数据传输的规则
1. 基础协议:
1. tcp: 安全协议,三次握手。 速度稍慢
2. udp :不安全协议。 速度快
2. 服务器
服务器:安装了服务器软件的计算机
服务器软件:接收用户的请求,处理请求,做出响应 web 服务器软件:接收用户的请求,处理请求,做出
响应。
web 服务器软件中,可以部署 web 项目,让用户
通过浏览器来访问这些项目
动态资源必须依赖于 web 服务器才能运行,所以也
被称为 web 容器
常见的 Java 相关的 web 服务器软件:
webLogic oracle 公司,大型的 JavaEE 服务器,
支持所有的 JavaEE 规范,收费的。
webSphere IBM 公司,大型的 JavaEE 服务器,
支持所有的 JavaEE 规范,收费的。
JBOSS JBOSS 公司的,大型的 JavaEE 服务器,支
持所有的 JavaEE 规范,收费的。
Tomcat Apache 基金组织,中小型的 JavaEE 服务
器,仅仅支持少量的 JavaEE 规范 servlet/jsp 开源
的,免费的 Tomcat 性能优异,并且支持集群,
所以深受广大企业喜爱。
3.Tomcat
3.1 下载:
进入官网 http://tomcat.apache.org/ 下载 8.5.61 3.2 安装:
解压即可使用
建议:安装目录不建议有中文 和 空格
3.3 目录结构:
3.4 卸载:
删除文件夹即可 3.5 启动:
bin/start.bat
错误 1 :启动报错
解决方案: logs --- catalina. 当天日期 .log 日志文
件中查找错误信息 ---- 》百度
错误 2 :启动窗口闪退
解决方案: JAVA_HOME 配置有问题,正确配置
后,便修复此问题
错误 3 :错误日志中出现:端口号占用错误
解决方案 1 cmd ---> 命令: netstat -ano --->
到对应端口的 PID ----> 任务管理器中 详细信息
项卡 ---> 找到对应 PID ---> 右键 ----> 结束任务
解决方案 2 :修改 Tomcat 默认端口号 conf --->
server.xml ---> 找到对应的 8080 进行修改。
特殊端口( 80 :80 端口号是 http 协议的默认端
口号 , 设置为 80 ,在访问服务器时,就不用输入
端口号
3.6 访问:
浏览器输入 : Http://localhost:8080 访问本机服务
Http:// 他人的 ip 8080 访问他人的
服务器 3.7 关闭:
正常关闭
bin/shutdown.bat
启动窗口: Ctrl + C
强制关闭
点击启动窗口右上角的关闭按钮 X
3.8 项目部署
方式 1 :直接将项目复制到 webapps 目录中
1. 我们建一个目录,里面放一个 html 文件:演示案例目
录结构 Myweb\index.html
2. 将文件夹复制到目录中
3. 启动服务
4. 通过浏览器访问项目:
localhost:8080/Myweb/index.html
/Myweb : 项目访问路径,其实它是一个虚拟路径,没
有配置前,默认是实际路径。
这种方式还有一种简化部署方式:将项目打包成 war
包,因为 war 包 和 zip 压缩包的压缩方式比较相似,所以
我们直接把演示案例项目压缩成 zip 格式,然后将后缀改
.war 。将压缩好的 war 包,复制到 webapps 目录中, 这种方式不用重新启动服务器,它会自动给我们部署,
删除只需要删除 war 包,对应的项目也会自动被删除
缺点:需要拷贝项目到 webapps, 耗时耗力
方式 2 :通过配置 server.xml
1. 在配置文件中找到 Host 标签
2. Host 标签中加入配置:
<Context docBase = "D:\Myweb" path = "/baidu" />
Context 是一个自闭和标签
docBase: 项目存放的实际路径
path: 访问的虚拟路径
缺点: server.xml 是针对服务器的配置文件,一般我们
不会修改这个文件,容易导致服务器崩溃。
方式 3 :在 conf\Catalina\localhost 文件夹下创建 虚
拟路径 .xml
1. conf\Catalina\localhost 目录下创建一个 .xml 配置
文件
2. 该配置文件名就是访问的虚拟路径
3. 文件中加入 Context 标签,并配置属性即可。 该方式的好处: 1. 不用修改服务器配置文件, 2. 热部
署:部署和删除不需要重启服务器。
4. IDEA Tomcat 集成
IDEA Tomcat 集成的好处,启动,关闭,部署项目都
非常方便,不用再去安装目录的 bin 中找程序之类的操作
1.Run ---- Edit Confifigurations...
<Context docBase="D:\Myweb" path="/baidu"/> 2. 点击左上角的 + 3. 选择: Tomcat Server ----- Local
image-20210115101654152
4. Confifigureation ----  Tomcat Home --- 选择 Tomcat
装目录即可
5. 配置成功后, IDEA Run 会变成 Tomcat 样式
5. 创建 JavaWeb 项目 1. 新建一个普通 java 工程( Module Project 都可以)
2. 项目名称上右键 --- > add 
3. 选择 Web Application
成功之后,该 java 项目会多出几个目录结构
6. 部署 JavaWeb 项目 1. Run ---- Edit Confifigurations...
2. Artifact...
3. 在弹出的窗口中,选择你要部署的 JavaWeb 项目
4. 配置虚拟访问路径(也可以不配置) 5. 配置热部署,这样我们新建页面就不必重新启动服务
器了。 6. 以上配置完成后,就可以点击启动 Tomcat ,访问你的
第一个页面啦!
7. Servlet
7.1 概述
运行在服务器端的 java 小程序
图解: Servlet 是一个接口,定义了 Java 类被 Tomcat 识别的
规则。
Servlet 的开发就是实现 Servlet 接口,重写里面的方
法。
7.2 快速入门
步骤
1. 创建 JavaEE 项目
2. 定义一个类,实现 Servlet 接口
3. 实现接口中的抽象方法
4. 配置 Servlet
1. 在刚才创建的 web 工程的 src 目录中创建包
org.wdzl.web.servlet ,并创建一个类 ServletDemo 2. 实现 Servlet 接口
注意:实现接口时会发现,找不到依赖
解决办法
1. File ---> Project Structure
2. 选择 Library
3. 选择 Tomcat 8.5.61---> Add Selected 3. 重写的方法我们先不管是干什么的,我们先找到
service 方法
// 提供服务的方法
@Override
public void service ( ServletRequest
servletRequest , ServletResponse
servletResponse ) throws ServletException ,
IOException {
System . out . println ( "Hello
Servlet" ); // 写一条输出语句即可
} 4. 配置 Servlet
为什么要配置 Servlet?
因为浏览器要访问动态资源是要通过 URL ,而 URL
何要和 Servlet 对应上,就是我们接下来要做的事
情。
web.xml 中配置
配置好后通过 localhost/demo1 进行访问即可
7.3 servlet 执行原理
图解:
<!-- 配置 Servlet -->
<servlet>
<servlet-name>demo1</servlet-name>
<servlet-
class>org.wdzl.web.servlet.ServletDemo</ser
vlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<!-- 访问 Servlet 的虚拟路径 -->
<url-pattern>/demo1</url-pattern>
</servlet-mapping> 执行原理
1. 服务器接收到浏览器的请求后,会解析请求 URL
径,获取访问的 Servlet 的资源路径
2. 查找 web.xml 文件,是否有对应的 <url - pattern>
3. 如果有,则会找到对应的 servlet - class 全类名
4. tomcat 将对应的字节码文件加载到内存中,并创建该
类的对象
5. 调用方法
7.4 Servlet 的方法 和 生命周期
1. 生命周期
被创建:执行 init 方法,只执行一次
提供服务 : 执行 service 方法,执行多次
被销毁:执行 destroy, 只执行一次
2. 方法 /**
* 初始化的方法
* Servlet 被创建时执行,只会执行一次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init ( ServletConfig
servletConfig ) throws ServletException {
System . out . println ( "init..." );
}
/**
* 获取 ServletConfig 对象
* ServletConfig Servlet 的配置对象
* @return
*/
@Override
public ServletConfig
getServletConfig () {
return null ;
}
/**
* 提供服务方法
* 每次 Servlet 被访问时执行,执行多次。
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException */
@Override
public void service ( ServletRequest
servletRequest , ServletResponse
servletResponse ) throws ServletException ,
IOException {
System . out . println ( "Hello
Servlet" );
}
/**
* 获取 Servlet 的一些信息,版本,作者等
* @return
*/
@Override
public String getServletInfo () {
return null ;
}
/**
* 销毁的方法
* Servlet 销毁或在服务器正常关闭时,被执
行一次
*/
@Override
public void destroy () {
System . out . println ( "destroy..." );
} 7.5 Servlet 方法详解
1. init():
初始化的时机可以改变
Servlet 是单例模式,多个用户访问可能存在线程
安全问题
解决:使用 Servlet 时,尽量不要在 Servlet 中使
用成员变量 ,即使定义了成员变量,也不要有
修改值的操作。
7.6 注解配置
配置文件方式配置比较麻烦, 3.0 之后的版本支持注解方
式,比较方便
步骤:
1. 创建 JavaEE 项目,选择 3.0 以上版本,可以不创建
web.xml
2. 定义一个类,实现 Servlet 接口
3. 重写方法 4. 在类上使用注解进行配置
准备工作 : 重新创建一个,这次不勾选 Create
web.xml
1.  定义一个类,实现 Servlet 接口,重写方法
2. 在类上使用注解进行配置 3. 注解 WebServlet 属性名
类型
描述
name
String
指定 Servlet name
属性,等价于
<servlet - name> 。如
果没有显式指定,则该
Servlet 的取值即为类
的全限定名。
value
String[]
该属性等价于
urlPatterns 属性。两
个属性不能同时使用。
使用时可以省略属性
名。
urlPatterns
String[]
指定一组 Servlet
URL 匹配模式。等价
<url - pattern>
签。
loadOnStartup
int
指定 Servlet 的加载顺
序,等价于 <load - on -
startup> 标签。
initParams
WebInitParam[]
指定一组 Servlet 初始
化参数,等价于 <init -
param> 标签。
asyncSupported
boolean
声明 Servlet 是否支持
异步操作模式,等价于
<async - supported>
标签。 属性名
类型
描述
description
String
Servlet 的描述信
息,等价于
<description>
签。
displayName
String
Servlet 的显示名,
通常配合工具使用,等
价于 <display - name>
标签。
7.7 小常识:
1. 工作空间项目 和 tomcat 部署的 web 项目 并不是一个
项目
tomcat 部署位置: CATALINA_BASE\work
工作空间项目位置:项目右键
1. WEB-INFO 目录下的资源不能被浏览器直接访问
7.8 Servlet 继承体系结构
查询 API 我们了解一下 Servlet 的继承体系结构:
Servlet 接口
|
GenericServlet 抽象类 |
HttpServlet 抽象类
GenericServlet 抽象类
它将 Servlet 接口中的其他方法都做了空实现,只留下了
service() 方法作为抽象方法
HttpServlet 抽象类
该抽象类是对 Http 协议的一种封装,可以简化操作。
图解:
7.9 HttpServlet
使用步骤
1. 定义类,继承 HttpServlet
2. 重写 doGet()/doPost()
查看源码,理解原理 HttpServlet 中的 service() 方法
service ()继续往下翻
因为 Http 7 种请求方式,我们只需要关注常用的两个
Get Post
get() 方式效果演示
1. 新建一个 ServletDemo2 @WebServlet ( "/demo2" )
public class ServletDemo2 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "doGet..." );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "doPost..." );
}
}
2. 启动服务,直接用浏览器请求该 Servlet
注意:浏览器默认访问方式是 GET() 方式
post() :方式
1. post 方式需要借助 Html <form> 标签 7.10 urlPatterns()
1. 一个 Servlet 可以匹配多个访问路径
注解源码:
urlPatterns 的数据类型是 String 类型的数组,就表示 该
servlet 可以设置多个访问路径
演示案例:
<body>
<form action = "demo2" method = "post" >
<input type = "text" name = "username" >
<input type = "submit" value = " 登录 " >
</form>
</body> @WebServlet ( urlPatterns =
{ "/a" , "/a2" , "/a3" })
public class ServletDemo3 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "ServletDemo3
doGet()...." );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "ServletDemo3
doPost()...." );
}
}
2. 路径定义规则
路径匹配: /xxx
目录结果匹配: /xxx/xxx
扩展名匹配: *.xxx
案例: 8. HTTP - 请求消息
8.1 概念
//@WebServlet("/aa/bb") 通过 /aa/bb 访问
//@WebServlet("/aa/*") 通过 /aa/ 任意字符 访问
//@WebServlet("/*") 通过 / 任意字符访问
@WebServlet ( "*.do" )
public class ServletDemo4 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "demo4
doGet()" );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "demo4
doPost()" );
}
} 超文本传输协议: Hyper Text Transfer Protocol 超文本
传输协议
8.2 特点
1. 基于 TCP/IP 的高级协议:安全的
2. 默认端口号 :80
3. 基于请求 / 相应模型:一次请求对应一次相应
图示:
1. 无状态的:每次请求之间相互独立,不能交互数据
8.3 历史版本
演示:使用火狐浏览器
我们访问 baidu 首页一共发送了几次请求?实际访问百
度主页会发送很多次请求,因为主页的每一个图片,文
本内容都是一次请求 1. 1.0 :每一次请求响应都会建立新的连接
2. 1.1 :复用连接,请求连接不会立马释放,会保留一
段时间,如果在时间内该链接还有数据进行传输,就
会复用该连接。
9. 请求消息 - 数据格式
数据格式
1. 请求行
2. 请求头
3. 请求空行
4. 请求体 JSP + Servlet
演示案例:使用 post() 演示案例结合火狐浏览器查看数
据格式
9.1 请求行 格式 :请求方式 请求 URL 请求协议 / 版本号
结合演示案例得出案例种请求行的信息:
请求方式: Http 共有 7 种请求方式,常用的有 2
GET
1. 请求参数在请求行中,在 URL
2. 请求的 URL 长度是有限制的
3. 不安全
POST
1. 请求参数在请求体中
2. 请求的 URL 长度没有限制
3. 相对安全
请求 URL
GET
1. URL 可能携带参数
POST
1. URL 不携带参数
9.2 请求头
请求头内容就是浏览器告诉服务器自身的一些信息。
GET /demo/login.html HTTP/1.1 格式 :请求头名称 : 请求头值 ,请求头值, ……
结合演示案例得出案例种请求行的信息:
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0;
Win64; x64; rv:84.0) Gecko/20100101
Firefox/84.0
Accept:
text/html,application/xhtml+xml,application
/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-
TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-
urlencoded
Content-Length: 15
Origin: http://localhost:8080
Connection: keep-alive
Referer:
http://localhost:8080/demo/login.html
Cookie:
JSESSIONID=EA1651C97732902D299C5CD859AE1647
; Idea-e44921c1=1d14f60c-0164-4cc4-9ed0-
2d9d05535a13
Upgrade-Insecure-Requests: 1
常见的请求头
Host :发送请求的主机 User-Agent: 浏览器告诉服务器,当前浏览器的版
本信息
可以在服务器端获取浏览器版本信息,来解决
浏览器兼容问题(原因:静态页面的解析都是
浏览器自己完成的。这就造成了相同的内容,
在不同浏览器中可能出现不同的样式。)
Accept: 浏览器告诉服务器自己支持的数据格式
Referer: 告诉服务器当前请求从哪里来
作用:
1. 防盗链
2. 统计工作 Connection:keep-alive (现在都使用的 HTTP 1.1
所以该头信息被省略)
9.3 请求空行
空行:用于分割请求头 和请求体
9.4 请求体(正文)
封装 POST 请求信息的请求参数
GET 方式种没有请求体,我们可以看表单提交后的效果
参数 = 对应的值
1. 请求消息 - 格式: 10. Request 对象
POST /demo/demo2 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0;
Win64; x64; rv:84.0) Gecko/20100101
Firefox/84.0
Accept:
text/html,application/xhtml+xml,application
/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-
TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-
urlencoded
Content-Length: 15
Origin: http://localhost:8080
Connection: keep-alive
Referer:
http://localhost:8080/demo/login.html
Cookie:
JSESSIONID=EA1651C97732902D299C5CD859AE1647
; Idea-e44921c1=1d14f60c-0164-4cc4-9ed0-
2d9d05535a13
Upgrade-Insecure-Requests: 1
username=hahaha 10.1 Request Response 对象的
原理
Response 对象后面细讲:
图解:
通过原理图,我们得出
1. request response 对象是由服务器创建,我们使
用即可
2. request 对象是用来获取请求信息, response 对象用
设置相应信息
10.2 Request 继承体系
查询 API
ServletRequest -- 接口 | 继承
HttpServletRequest -- 接口
| 实现( service 中打印 request 对象)
org.apache.catalina.connector.RequestFacade --
tomcat 中实现
10.3 获取请求消息数据
10.3.1 获取请求行数据
我们根据请求行数据格式分析需要的方法
GET /demo/demo2 HTTP/1.1
获取请求方式: GET
String getMethod()
获取虚拟目录(常用) /demo
String getContextPath()
获取 Servlet 路径 : /demo2
String getServletPath()
获取 get 方式请求参数: name=zhangsan String getQueryString()
获取请求 URI (常用) /demo/demo2
String getRequestURI(): /demo/demo2
StringBuffffer getRequestURL()
: http://localhost:8080/demo/demo2
获取协议及版本: HTTP/1.1
String getProtocol()
获取客户机的 IP 地址:
String getRemoteAddr()
演示案例:
@WebServlet ( "/req" )
public class RequestDemo extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
// 获取请求方式
String method = req . getMethod ();
System . out . println ( method );
// 获取虚拟目录
String contextPath =
req . getContextPath ();
System . out . println ( contextPath );
// 获取 Servlet 路径 String servletPath =
req . getServletPath ();
System . out . println ( servletPath );
// 获取 get 方式的请求参数
String queryString =
req . getQueryString ();
System . out . println ( queryString );
// 获取 URI
String requestURI =
req . getRequestURI ();
StringBuffer requestURL =
req . getRequestURL ();
System . out . println ( requestURI );
System . out . println ( requestURL );
// 获取协议版本
String protocol =
req . getProtocol ();
System . out . println ( protocol );
// 返回用户 ip
String remoteAddr =
req . getRemoteAddr ();
System . out . println ( remoteAddr );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException { 通过网址 localhost:8080//localhost/demo/req?
name=aaa&age=18 查看控制台
10.3.2 获取请求头数据
String getHeader(String name) : 通过请求头的名
称获取请求头的值(常用)
Enumeration getHeaderNames(): 获取所有的请
求头名称
Enumeration 相当于迭代器, API 中有说
演示案例 1 :获取所有请求头数据
super . doPost ( req , resp );
}
}
@WebServlet ( "/req2" ) public class RequestDemo2 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
// 获取所有请求头名称
Enumeration < String > headerNames =
req . getHeaderNames ();
while
( headerNames . hasMoreElements ()) {
// 获取请求头的键
String name =
headerNames . nextElement ();
// 获取请求头的值
String value =
req . getHeader ( name );
System . out . println ( name + "--"
+ value );
}
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException { }
}
通过网址: localhost:8080//localhost/demo/req2
演示案例 2 :获取用户浏览器信息
@WebServlet ( "/req3" )
public class RequestDemo3 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
// 获取 UserAgent
String agent = req . getHeader ( "user-
agent" ); // 请求头的 key 不区分大小写
if ( agent . contains ( "QQBrowser" )) {
// 因为我们无法处理浏览器兼容问题,所
以我们用一个输出语句代替处理
System . out . println ( " 您用的是 QQ
览器 " );
} else if
( agent . contains ( "Firefox" )) { System . out . println ( " 您用的是火狐
浏览器 " );
}
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
}
}
通过不同浏览器访问 servlet 可以有不同的效果。
演示案例 3 :获取 referer
@WebServlet ( "/req4" )
public class RequestDemo4 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
// 获取 Referer
String referer =
req . getHeader ( "referer" );
System . out . println ( referer );
if ( referer . contains ( "/demo" )) {
System . out . println ( " 播放音乐 " ); // 等学了 response 之后就可以把输出语
句中的内容显示到网页中
} else {
System . out . println ( " " );
}
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
}
}
注意:如果直接通过 /demo/req4 访问这个 Servlet, 就相
当于直接自己访问自己, referer 的值是 null ,所以我们
需要在 index.jsp 中加一个超链接,控制跳转 10.3.4 获取请求体数据
请求体 :只有 POST 方式有请求体。在请求体中封装
POST 请求的请求参数
步骤:
1. 获取流对象
BufffferedReader getReader() : 获取字符输
入流,只能操作字符数据
ServletInputStream getInputStream() :
取字节输入流,它可以操作所有类型数据(文
件上传时讲解)
2. 从流中获取数据
演示案例:
1. 创建 regist.html
<!DOCTYPE html>
<html lang = "en" >
<head>
<meta charset = "UTF-8" >
<title> 注册页面 </title>
</head>
<body>
<form action = "/demo/req5"
method = "post" >
用户名: <input type = "text"
placeholder = " 请输入用户名 "
name = "username" ><br> 密码: <input type = "password"
placeholder = " 请输入密码 "
name = "username" ><br>
<input type = "submit" value = " 注册 " >
</form>
</body>
</html>
2. 创建 servlet
@WebServlet ( "/req5" )
public class RequestDemo5 extends
HttpServlet {
@Override
protected void
doGet ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
// 获取请求消息体
//1. 获取字符流
BufferedReader br =
req . getReader ();
//2. 读取数据 10.3.4 其他方法
这些方法是由前面基础方法衍生出来的一些通用方法,
更方便使用
1. 获取请求参数对象( GET/POST 都能用)
String getParameter(String name) : 根据参数名
称获取参数值
String[] getParameterValues(String name) :
据参数名称获取参数值的数组(多用于复选框)例
如: hobby=java &hobby=c
Enumeration getParameterNames() : 获取所有请
求的参数名称
Map<String,String[]> getParameterMap() : 获取
所有参数的 map 集合
演示案例 1
String line = null ;
while (( line = br . readLine ()) !=
null ) {
System . out . println ( line ); //username=aaa&
username=aaa
}
}
} regist2.html
<!DOCTYPE html>
<html lang = "en" >
<head>
<meta charset = "UTF-8" >
<title> 注册页面 </title>
</head>
<body>
<form action = "/demo/req6" method = "post" >
用户名: <input type = "text"
placeholder = " 请输入用户名 " name = "username" >
<br>
密码: <input type = "password"
placeholder = " 请输入密码 " name = "username" ><br>
爱好:
打游戏 <input type = "checkbox"
name = "hobby" value = "playGame" >
看书 <input type = "checkbox" name = "hobby"
value = "read" >
<input type = "submit" value = " 注册 " >
</form>
</body>
</html>
ServletDemo6
@WebServlet ( "/req6" )
public class RequestDemo6 extends
HttpServlet { @Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
// 根据参数名获取参数值
/* String username =
req.getParameter("username");
System.out.println("get:"+username);*/
// 因为方法通用,所以我们可以采取统一的处理
方式
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
//1 根据参数名获取参数值
String username =
req . getParameter ( "username" );
System . out . println ( "post:" + username );
System . out . println ( "**********************
*****" );
//2 根据参数名获取参数值数组
String [] hobbies =
req . getParameterValues ( "hobby" ); for ( String hobby : hobbies ) {
System . out . println ( hobby );
}
//3 获取请求中所有的参数名称
Enumeration < String > parameterNames
= req . getParameterNames ();
while
( parameterNames . hasMoreElements ()) {
String name =
parameterNames . nextElement ();
String value =
req . getParameter ( name );
System . out . println ( name + "---"
+ value ); //hobby 复选框,所以结果中只拿了一个值
}
//4 获取所有参数的 map 集合
Map < String , String [] > parameterMap
= req . getParameterMap ();
Set < String > keys =
parameterMap . keySet ();
for ( String key : keys ) {
// 获取值
String [] values =
parameterMap . get ( key );
for ( String value : values ) {
System . out . println ( key + "---
" + value );
} POST 中文乱码解决:
2. 请求转发
概述: 一种在服务器内部的资源跳转方式。
简单理解服务器内部的资源跳转:一个服务器中有多
Servelt, 多个 Servlet 分工协作完成用户的一个请
求,这多个 Servlet 间数据的交换,就是资源跳转
步骤
1. 通过 request 对象 获取请求转发器对象:
RequestDispatcher
getRequestDispatcher(String path)
2. 使用转发器对象进行转发:
forward(ServletRequest request,
ServletResponse response)
演示案例:
ServletDemo7
}
}
}
// 在获取参数前,设置 req 编码集
req . setCharacterEncoding ( "utf-8" );
@WebServlet ( "/req7" ) public class RequestDemo7 extends
HttpServlet {
@Override
protected void
doGet ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "ServletDemo7
被访问。。。 " );
// 请求转发 : 链式编程
req . getRequestDispatcher ( "/demo/req8" ). f
orward ( req , resp );
}
}
ServletDemo8
@WebServlet ( "/req8" )
public class RequestDemo8 extends
HttpServlet {
@Override 通过访问 req7 跳转到 req8
特点
1. 浏览器地址栏路径不发生变化
2. 只能转发到当前服务器内部资源中。
3. 转发是一次请求,即无论内部转发几次,调用几个
Servlet 使用的都是同一次请求。
3. 共享数据
概述: 多个 Servlet 间协作数据的共享,在学习共享数
据前,我们还需要学习域对象
protected void
doGet ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "ServletDemo8
被访问。。。 " );
}
} 域对象: 一个有作用范围的对象,可以在范围内共享
数据
request 域: 代表一次请求的范围。它的作用范围刚
好就是请求转发的范围,所以,一般用于请求转发中
多个资源中共享数据。也就是我们常说的 一次请求,
多个资源
方法:
void setAttribute(String name,Object obj)
: 存储数据
Object getAttitude(String name) : 通过键
获取值
void removeAttribute(String name) :
过键移除键值对
演示案例:使用 ServletDemo7  ServletDemo8
ServletDemo7
@WebServlet ( "/req7" )
public class RequestDemo7 extends
HttpServlet {
@Override
protected void
doGet ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
} @Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "ServletDemo7
被访问。。。 " );
req . setAttribute ( "info" , "Hello" );
// 请求转发 : 链式编程
req . getRequestDispatcher ( "/req8" ). forwar
d ( req , resp );
}
}
ServletDemo8
@WebServlet ( "/req8" )
public class RequestDemo8 extends
HttpServlet {
@Override
protected void
doGet ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override 通过访问 req7 跳转到 req8 并转发 info 属性
4. 获取 ServletContext 对象
方法: ServletContext getServletContext()
后面细讲,它很重要
10.4 用户登录
需求:
1. 编写 login.html 登录页面
2. 使用 Druid 数据库连接池技术,操作 mysql
bookManager 库中的 user
3. 使用 JdbcTemplate 技术封装 JDBC
4. 登录成功后,转发到 SuccessServlet 并在页面输出:
欢迎 XXX 回来!
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "ServletDemo8
被访问。。。 " );
String info = ( String )
req . getAttribute ( "info" );
System . out . println ( info );
}
} 5. 登录失败后,转发到 ErrorServlet 并在页面输出:用
户名或密码错误
步骤:
1. 创建项目,导入 Druid 配置文件, JdbcTemplate
Druid Mysql 连接驱动的 jar 包。创建 login.html
<!DOCTYPE html>
<html lang = "en" >
<head>
<meta charset = "UTF-8" >
<title> Title </title>
</head>
<body>
<!--action 属性: / 虚拟路径 /servlet 资源路径 --
>
<form action = "/book/loginServlet"
method = "post" >
用户名 : <input type = "text"
name = "username" > <br>
密码 : <input type = "password"
name = "password" ><br>
<input type = "submit" value = " 登录 " >
</form>
</body>
</html> 1. 创建数据库
CREATE DATABASE bookManager CHARSET utf8;
USE bookManager;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR ( 32 ) UNIQUE NOT NULL ,
PASSWORD VARCHAR ( 64 ) NOT NULL
)
INSERT INTO USER
VALUES ( NULL , 'admin' , 'admin' );
2. 创建包 org.wdzl.pojo 在包中创建对应实体类 User
public class User {
private Integer id ;
private String username ;
private String password ;
public User () {
}
public User ( Integer id , String
username , String password ) {
this . id = id ;
this . username = username ; this . password = password ;
}
public Integer getId () {
return id ;
}
public void setId ( Integer id ) {
this . id = id ;
}
public String getUsername () {
return username ;
}
public void setUsername ( String
username ) {
this . username = username ;
}
public String getPassword () {
return password ;
}
public void setPassword ( String
password ) {
this . password = password ;
}
@Override public String toString () {
return "User{" +
"id=" + id +
", username='" + username
+ '\'' +
", password='" + password
+ '\'' +
'}' ;
}
}
3. 创建包 org.wdzl.dao 在包中创建操作数据库的接口
public interface UserDao {
User login ( User loginUser );
}
5. 创建包 org.wdzl.dao.impl 在包中创建接口实现类
UserDaoImpl
先不做实现,第 6 步写完后,再回来做具体实现。实现
完后,写一个测试类测试一下。确保代码正确,再继续
往下写。
package org . wdzl . dao . impl ; import
org . springframework . dao . DataAccessException
;
import
org . springframework . jdbc . core . BeanPropertyR
owMapper ;
import
org . springframework . jdbc . core . JdbcTemplate ;
import org . wdzl . dao . UserDao ;
import org . wdzl . pojo . User ;
import org . wdzl . utils . JDBCUtils ;
public class UserDaoImpl implements UserDao
{
// 声明一个 JDBCTemplate 对象供该类中的所有方法
使用
private JdbcTemplate template = new
JdbcTemplate ( JDBCUtils . getDataSource ());
/**
* 用户登录
* @param loginUser 包含用户和密码
* @return user 包含的全部数据
*/
@Override
public User login ( User loginUser ) {
try {
//1. 编写 SQL
String sql = "select * from
user where username=? and password=?" ; // 调用 query 方法:用户存在则代码顺序
执行,用户不存在则会报错
User user =
template . queryForObject (
sql ,
new
BeanPropertyRowMapper <> ( User . class ),
loginUser . getUsername (),
loginUser . getPassword ()
);
// 返回 User
return user ;
} catch ( DataAccessException e ) {
e . printStackTrace ();
// 报错就代表用户不存在,我们返回 null
即可
return null ;
}
}
}
6. 准备 JDBCUtils 工具类
import
com . alibaba . druid . pool . DruidDataSourceFacto
ry ;
import com . mysql . jdbc . Statement ;
import javax . sql . DataSource ;
import java . sql . Connection ; import java . sql . ResultSet ;
import java . sql . SQLException ;
import java . util . Properties ;
/**
* Druid 连接池工具类
*/
public class JDBCUtils {
// 成员变量
private static DataSource dataSource ;
static {
try {
//1. 加载配置文件
Properties properties = new
Properties ();
properties . load ( JDBCUtils . class . getClassLo
ader (). getResourceAsStream ( "druid.propertie
s" ));
//2. 获取连接池对象
dataSource =
DruidDataSourceFactory . createDataSource ( pro
perties );
} catch ( Exception e ) {
e . printStackTrace ();
}
}
/** * 获取连接对象
* @return 连接对象
*/
public static Connection
getConnection () throws SQLException {
return dataSource . getConnection ();
}
/**
* 释放资源
* @param stmt 执行 sql 的对象
* @param conn 连接数据库的对象
*/
public static void close ( Statement
stmt , Connection conn ) {
close ( stmt , conn , null );
}
/**
* 释放资源
* @param stmt 执行 sql 的对象
* @param conn 连接数据库的对象
* @param rs 查询结果集对象
*/
public static void close ( Statement
stmt , Connection conn , ResultSet rs ) {
if ( stmt != null ) {
try {
stmt . close (); } catch ( SQLException
throwables ) {
throwables . printStackTrace ();
}
}
if ( conn != null ) {
try {
conn . close ();
} catch ( SQLException
throwables ) {
throwables . printStackTrace ();
}
}
if ( rs != null ) {
try {
rs . close ();
} catch ( SQLException
throwables ) {
throwables . printStackTrace ();
}
}
}
/**
* 获取连接池对象 * @return 连接池对象
*/
public static DataSource
getDataSource () {
return dataSource ;
}
}
7. 测试 login() 方法
public class UserDaoImplTest {
UserDaoImpl userDao = new
UserDaoImpl ();
@Test
public void test () {
// 正确:则打印出用户信息,不正确则会报错
User user = new User ( null , "admin" ,
"admin" );
User login = userDao . login ( user );
System . out . println ( login );
}
}
8. 创建包 org.wdzl.servlet 在包中创建 LoginServlet
import org . wdzl . dao . UserDao ;
import org . wdzl . dao . impl . UserDaoImpl ;
import org . wdzl . pojo . User ; import javax . servlet . ServletException ;
import javax . servlet . annotation . WebServlet ;
import javax . servlet . http . HttpServlet ;
import
javax . servlet . http . HttpServletRequest ;
import
javax . servlet . http . HttpServletResponse ;
import java . io . IOException ;
@WebServlet ( "/loginServlet" )
public class LoginServlet extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
//1. 设置编码集
req . setCharacterEncoding ( "UTF-8" );
//2. 获取请求参数
String username =
req . getParameter ( "username" ); String password =
req . getParameter ( "password" );
//3. 封装 User 对象
User loginUser = new User ( null ,
username , password );
//4. 调用 UserDao 的方法
UserDao userDao = new
UserDaoImpl ();
User user =
userDao . login ( loginUser );
if ( user != null ) {
req . setAttribute ( "user" , user );
req . getRequestDispatcher ( "/successServlet"
). forward ( req , resp );
} else {
req . getRequestDispatcher ( "/errorServlet" ).
forward ( req , resp );
}
}
}
9. 创建 SuccessServlet
import org . wdzl . pojo . User ;
import javax . servlet . ServletException ; import
javax . servlet . annotation . WebServlet ;
import javax . servlet . http . HttpServlet ;
import
javax . servlet . http . HttpServletRequest ;
import
javax . servlet . http . HttpServletResponse ;
import java . io . IOException ;
@WebServlet ( "/successServlet" )
public class SuccessServlet extends
HttpServlet {
@Override
protected void
doGet ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
// 获取 user 对象
User user = ( User )
req . getAttribute ( "user" );
// 给页面写一句话,后面讲 先照着抄 resp . setContentType ( "text/html;charset=u
tf-8" );
resp . getWriter (). write ( "
" + user . getUsername () + " 回来!!! " );
}
}
10. 创建 ErrorServlet
import javax . servlet . ServletException ;
import
javax . servlet . annotation . WebServlet ;
import javax . servlet . http . HttpServlet ;
import
javax . servlet . http . HttpServletRequest ;
import
javax . servlet . http . HttpServletResponse ;
import java . io . IOException ;
@WebServlet ( "/errorServlet" )
public class ErrorServlet extends
HttpServlet {
@Override
protected void
doGet ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
} 封装 user 对象的过程是比较繁琐的,因为我们这个
案例只有两个字段,如果是注册业务呢?可能有几十个
字段,我们也要一步一步去写吗?
接下来我们讲解一个可以简化对象封装的工具类:
BeanUtils
10.5 BeanUtils 简化数据封装
使用 BeanUtils 简化数据封装
以上一个案例的 LoginServlet 为例
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
resp . setContentType ( "text/html;charset=u
tf-8" );
resp . getWriter (). write ( " 用户名或密
码错误 " );
}
} 使用要求:
类必须被 public 修饰
必须提供无参构造
成员变量必须被 private 修饰
提供公共的 get/set 方法
11. HTTP- 相应消息
1. 请求消息:客户端发送给服务器端的数据
数据格式:
2. 相应消息:服务器端相应客户端的数据
数据格式:
1. 相应行
2. 相应头
3. 相应空行
4. 相应体体
11.1 响应消息的字符串格式: 通过获取浏览器 F12 查看 格式
图示:
HTTP / 1.1 200 OK // 响应行
// ****************************** 响应头
*****************************
Bdpagetype : 1
Bdqid : 0x86f2f3e6001eefab
Cache - Control : private
Connection : keep - alive
Content - Encoding : gzip
Content - Type : text / html ; charset = utf - 8
Date : Wed , 20 Jan 2021 18 : 07 : 52 GMT
Expires : Wed , 20 Jan 2021 18 : 07 : 52 GMT
Server : BWS / 1.1
Set - Cookie : BDSVRTM = 12 ; path =/
Set - Cookie : BD_HOME = 1 ; path =/
Set - Cookie :
H_PS_PSSID = 33425_33430_33344_33286_33395_33
398_33334_26350 ; path =/ ; domain = . baidu . com
Strict - Transport - Security : max - age = 172800 11.2 响应行
1. 组成:
协议 / 版本 响应状态码 响应码描述
2. 状态码:
状态码都是 3 位数字 服务器告诉客户端本次 请求 和 响
应的状态
分类
1. 1xx - 服务器接收客户端消息,但是没有接收完
成。等待一段时间后,发送 1xx 状态码,询问客户
端是否继续发送消息
2. 2xx :成功。代表码: 200
3. 3xx: 重定向。资源跳转的方式。代表码: 302-
定向 304- 访问缓存
Traceid :
161116607205735506029724102714616377259
X - Ua - Compatible : IE = Edge , chrome = 1
Transfer - Encoding : chunked
// ****************************** 响应头结束
*****************************
// 响应空行
// 响应体:就是整个页面的内容(包括: html css,js,
及数据) 重定向:比如你要访问 ServletA, A 说它做不
了,让你访问 B ,然后浏览器接收到 A 的相应之
后,会自动的访问 ServletB ,就相当于你一次
回车进行了两次请求。
4. 4xx: 客户端错误。比如访问路径有问题,没有对
应资源 ,就会报 404
5. 5xx: 服务器端错误。 如果服务器代码出现异常就
会报 500
11.3 响应头
1. 组成:
头名称 :值
2. 常见响应头:
Content-Type :服务器告诉客户端本次响应体数
据格式以及编码格式
Content-disposition :服务器告诉客户端以什么
格式打开响应体数据。如果没有设置就使用默认
值。
1. 值:
in-line: 默认值 , 在当前页面内打开
attachment ; fifilename=xxx :以附件形式打
开响应体。即文件下载 fifilename 执行下载文
件名称 12. Response 对象
12.1 概述
Response 对象是用来设置响应消息的
设置响应行
设置状态码: setStatus( int sc) - sc 为状态码
设置响应头
setHeader(String name , String value)
设置响应体 :
步骤:
1. 获取输出流
字节输出流: ServletOutputStream
getOutputStream()
字符输出流 : PrintWriter() getWriter()
2. 使用输出流将数据输出到客户端浏览器
我们通过下面 4 个小案例来讲解上述内容
1. 完成重定向
2. 服务器输出字符数据到浏览器
3. 服务器输出字节数据到浏览器
4. 验证码
12.2 重定向 图解:
步骤:
1. 设置状态码为 302
2. 设置响应头 Location
简化操作:
由于 302 location 为固定参数,所以将重定向简化
为方法: sendRedirect("/ 虚拟路径 / 资源路径 ")
演示案例: responseDemo 通过重定向 访问
responseDemo2
responseDemo
/**
* 重定向演示案例 */
@WebServlet ( "/responseDemo" )
public class ResponseDemo extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "responseDemo
访问 " );
// 设置状态码
resp . setStatus ( 302 );
// 设置响应头
resp . setHeader ( "location" , "/book/responseD
emo2" );
// 重定向简单的方法实现 : 因为 302
location 是固定的。
resp . sendRedirect ( "/book/responseDemo2" );
} }
responseDemo2
@WebServlet ( "/responseDemo2" )
public class ResponseDemo2 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
System . out . println ( "responseDemo2
被访问 " );
}
}
重定向的特点:
转发的特点: forward
1. 地址栏 路径不变
2. 转发只能访问当前服务器下的资源 3. 转发是一次请求 可以使用 request 对象共享数据
重定向的特点: redirect
1. 地址栏发生变化
2. 可以访问其他服务器的资源
3. 重定向是两次请求,不可以使用 request 对象共享
数据
面试题: forward redirect 的 区别
路径写法:
路径分类
相对路径:找到当前资源和目标资源之间的相对位
置关系
./ 开头
../ 表示上一级目录
绝对路径:通过绝对路径可以确定唯一资源
/ 开头。因为当前项目中
localhost:8080/ 虚拟路径都是统一的,所以
可以省略为 /
判断路径给谁用
1. 浏览器用,要加虚拟目录 。例子:重定向
2. 服务器用,不用加虚拟目录。例子:转发
使用 request.getContextPath() 动态获取项目虚
拟路径,这样即便是修改项目虚拟目录,我们
之前写的重定向方法也不会失效。 12.3 服务器输出字符数据到浏览器
演示案例:
/**
* 响应字符数据到浏览器
*/
@WebServlet ( "/responseDemo3" )
public class ResponseDemo3 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
// 获取流 PrintWriter writer =
resp . getWriter ();
// 输出字符
// writer.write("Hello Response");
// 输出 html 标签
writer . write ( "<h1>Hello
Response</h1>" );
writer . write ( " 你好 response" ); // 乱码
}
}
演示案例 2 :处理中文乱码
/**
* 处理中文乱码
*/
@WebServlet ( "/res4" )
public class ResponseDemo4 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
/*
分析:中文乱码问题
qq 浏览器查看网页源码:默认编码集 GBK
输出流通过 tomcat 获取。编码集应该是 ISO-
8859-1
*/
// 解决中文乱码
//1. 获取流之前设置编码集
//resp.setCharacterEncoding("GBK");
/*
但是仅仅设置输出流的编码集,万一用户的编码
集被修改不是默认的 GBK 呢?
我们可以使用相应头 content-type, 告诉浏览
器本次相应的编码格式,浏览器读取到后,就会使用相应的
编码
*/
// 设置响应头的同时也设置了本身的编码集,所
resp.setCharacterEncoding() 可以省略不写
//resp.setHeader("content-
type","text/html;charset=utf-8");
// 简单的方法设置编码
resp . setContentType ( "text/html;charset=utf
-8" ); // 获取流
resp . getWriter (). write ( " 哈哈哈哈 " );
}
}
12.4 服务器输出字节数据到浏览器
演示案例:
/**
* 服务器相应字节数据:
* 一般这种方法我们不用在输出字符上,而是用在
输出图片上,比如说验证码。
*/
@WebServlet ( "/res5" )
public class ResponseDemo5 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override 12.5 验证码
本质: 它是一张图片
目的: 提高安全性,防止恶意注册等操作。
方式: 随机生成
本次案例做的是比较初级的验证码:在内存中随机生成
验证码
演示案例:
1. 后台生成图片
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
resp . setContentType ( "text/html;charset=utf
-8" );
ServletOutputStream outputStream =
resp . getOutputStream ();
outputStream . write ( "
" . getBytes ( "utf-8" ));
}
} import javax . imageio . ImageIO ;
import javax . servlet . ServletException ;
import javax . servlet . annotation . WebServlet ;
import javax . servlet . http . HttpServlet ;
import
javax . servlet . http . HttpServletRequest ;
import
javax . servlet . http . HttpServletResponse ;
import java . awt . * ;
import java . awt . image . BufferedImage ;
import java . io . IOException ;
import java . util . Random ;
@WebServlet ( "/code" )
public class CheckCodeServlet extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException { //1. 创建一个对象,代表内存中的一张图片(空
白画布)
int width = 100 ;
int height = 50 ;
/*
new BufferedImage( 参数 1 ,参数 2 ,参数 3)
参数 1 :宽
参数 2 :高
参数 3 :图片类型 - 常用
BufferedImage.TYPE_INT_RGB
*/
BufferedImage image = new
BufferedImage ( width , height ,
BufferedImage . TYPE_INT_RGB );
//2. 美化图片,让它变成我们想要的样子
//2.1 填充背景色
Graphics g = image . getGraphics (); //
获取画笔工具
g . setColor ( Color . ORANGE ); // 设置画笔颜
g . fillRect ( 0 , 0 , width , height ); // 填充
一个矩形
//2.2 画边框
g . setColor ( Color . green ); // 设置画笔颜
// g.drawRect(0, 0, 100, 50);// 因为边
框本身占一个像素,所以右边和下边的边框会超出
g . drawRect ( 0 , 0 , width - 1 , height - 1 ); //2.3 验证码所有可能出现的字符
String str =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop
qrstuvwxyz0123456789" ;
//2.4 获取随机数根据随机数取字符
for ( int i = 1 ; i <= 4 ; i ++ ) {
int index = new
Random (). nextInt ( str . length ());
char ch = str . charAt ( index );
//2.5 写验证码
g . drawString ( ch + "" , width / 5 * i , height / 2 );
}
//2.6 画干扰线
g . setColor ( Color . BLUE );
// 两点确定一条线,一条线由 x,y 左边的组成。
一共画十条
for ( int i = 0 ; i < 10 ; i ++ ) {
int x1 = new
Random (). nextInt ( width );
int x2 = new
Random (). nextInt ( width );
int y1 = new
Random (). nextInt ( height );
int y2 = new
Random (). nextInt ( height );
g . drawLine ( x1 , x2 , y1 , y2 );
} //3. 将图片输出到页面展示
ImageIO . write ( image , "jpg" ,
resp . getOutputStream ());
}
}
2. 前端页面展示验证码,并通过单击改变验证码
<!DOCTYPE html>
<html lang = "en" >
<head>
<meta charset = "UTF-8" >
<title> 注册页面 </title>
<script>
window . onload = function (){
// 获取图片标签对象
var img =
document . getElementById ( "checkCode" );
// 绑定单击时间
img . onclick = function () {
// 获取时间戳,为了让浏览器不读取
缓存图片
var date = new
Date (). getTime ();
// 重新请求
img . src = "/book/code?" + date ;
};
}
</script>
</head> 13. ServletContext 对象
13.1 概述
ServletContext 对象代表整个 web 应用,可以和程序的
容器(服务器进行通信)。
13.2 获取该对象
1. 通过 Request 对象获取
request.getServletContext()
2. 通过 HttpServlet 获取 ( 实际是他的父类实现了该方法 )
this.getServletContext()
演示案例:
<body>
<input type = "text" name = "username" >
<img id = "checkCode" src = "/book/code" />
看不清,换一张
</body>
</html>
@WebServlet("/scd") public class ServletContextDemo extends
HttpServlet {
@Override
protected void doGet(HttpServletRequest
req, HttpServletResponse resp) throws
ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void
doPost(HttpServletRequest req,
HttpServletResponse resp) throws
ServletException, IOException {
ServletContext servletContext =
req.getServletContext();
ServletContext servletContext1 =
this.getServletContext();
System.out.println(servletContext);
System.out.println(servletContext1);
System.out.println(servletContext
== servletContext1);
// 两种方式获取的是一个 ServletContext
}
} 13.3 功能
1. 获取 MIME 类型:
MIME 类型:在互联网通信过程中定义的一种文件数
据类型
格式:大数据类型 / 小数据类型 比如: text / html ,
image/jpeg
获取: String getMimeType(String fifile): 通过文件名
(包含扩展名)获取 MIME 的值
扩展名对应的 MIME 可以去 tomcat --- conf -
web.xml 中查看
演示案例:
@WebServlet ( "/scd2" )
public class ServletContextDemo2 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override 2. 域对象:可以共享数据
功能:所有域对象都有该功能
void setAttribute(String name,Object obj) :
存储数据
Object getAttitude(String name) : 通过键获
取值
void removeAttribute(String name) : 通过
键移除键值对
作用域:
最大范围,所有用户的所有数据
演示案例:定义两个 Servlet ,不经过转发获取数据
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
ServletContext servletContext =
req . getServletContext ();
// 定义一个文件名
String fileName = "index.html" ;
// 获取 MIME
String mimeType =
servletContext . getMimeType ( fileName );
System . out . println ( mimeType );
}
} @WebServlet ( "/scd3" )
public class ServletContextDemo3 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
ServletContext servletContext =
req . getServletContext ();
servletContext . setAttribute ( "info" ,
" 牛逼 " );
}
}
@WebServlet ( "/scd4" )
public class ServletContextDemo4 extends
HttpServlet {
@Override 3. 获取文件的服务器真实存储路
演示案例:
1. 分别在 src,web,WEB-INF 下创建 a.txt, b.txt , c.txt
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
ServletContext servletContext =
req . getServletContext ();
Object info =
servletContext . getAttribute ( "info" );
System . out . println ( info );
}
} 2. 测试案例
@WebServlet ( "/scd6" )
public class ServletContextDemo6 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException { 13.4 文件下载
ServletContext servletContext =
req . getServletContext ();
// 获取 web 目录下的资源
String realPath =
servletContext . getRealPath ( "/b.txt" ); // ‘/’
System . out . println ( realPath );
// 获取 WEB-INF 下的资源 : 到文件夹中找对应文
件对比着写 .
realPath =
servletContext . getRealPath ( "/WEB-
INF/c.txt" );
System . out . println ( realPath );
//src 下的文件都会被放到 WEB-INF 下的
classes 路径中
realPath =
servletContext . getRealPath ( "/WEB-
INF/classes/a.txt" );
System . out . println ( realPath );
}
} 需求:
1. 在一个 html 文件中写一个超链接
2. 点击超链接,弹出下载提示框
如果超链接的 href 属性直接指向图片路径,因为
浏览器解析器可以解析图片,所以会直接显示图片
而不是下载,但是如果 src 指向视频,因为浏览器
无法解析视频,就会默认的弹出下载框。
3. 下载图片
分析:
需要使用响应头设置资源的打开方式,否则图片无法
通过超链接下载
Content-disposition attachment ; fifilename=xxx
步骤:
1. 定义页面,编辑超链接 href 属性,指向 Servlet, 传递
资源的名称: fifilename
2. 定义 servlet
获取文件名
指定 response 的响应头:
Content-disposition attachment ;
fifilename=xxx MIME
使用字节输入流加载文件进内存
使用 ServletContext 对象获取实际路径
将数据写出到 response 输出流
演示案例:
1. 先在 web 路径下新建 image 文件夹,将图片放入该文
件夹,再创建一个下载页面: download.html
<! DOCTYPE html >
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< title > Title </ title >
</ head >
< body >
< a href = "/book/image/Lucky.jpg" > 小柯基 </ a >
< a href = "/book/downloadServlet?
filename=Lucky.jpg" > 小柯基 </ a >
</ body >
</ html >
2. downloadServlet
import javax . servlet . ServletContext ;
import javax . servlet . ServletException ;
import javax . servlet . ServletOutputStream ;
import javax . servlet . annotation . WebServlet ; import javax . servlet . http . HttpServlet ;
import
javax . servlet . http . HttpServletRequest ;
import
javax . servlet . http . HttpServletResponse ;
import java . io . FileInputStream ;
import java . io . IOException ;
@WebServlet ( "/downloadServlet" )
public class DownloadServlet extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
// 获取文件名称
String filename =
req . getParameter ( "filename" );
// 找到文件真实路径
ServletContext servletContext =
this . getServletContext (); String path =
servletContext . getRealPath ( "/image/" + filena
me );
// 设置响应头
//MIME 类型
String mimeType =
servletContext . getMimeType ( filename );
resp . setHeader ( "content-type" ,
mimeType );
// 打开方式
resp . setHeader ( "content-
disposition" , "attachment;filename=" + filenam
e );
// 获取输入输出流
FileInputStream fis = new
FileInputStream ( path );
ServletOutputStream outputStream =
resp . getOutputStream ();
byte [] bytes = new byte [ 1024 ];
int len = 0 ;
while (( len = fis . read ( bytes )) !=
0 ) {
outputStream . write ( bytes , 0 ,
len );
}
// 释放资源
fis . close (); 14. 会话技术
概述 :
一次会话中包含多次请求和相应。并且在会话范围内
可以共享数据
会话就和谈话的过程一样,你来我往很多次问答。
功能:
共享技术
分类:
2. 服务器端会话技术: Session
14.1 Cookie
概述:客户端会话技术,将数据保存到客户端
步骤:
1. 创建 Cookie 对象,绑定参数
new Cookie(String name ,String value)
}
}
1. 客户端会话技术 Cookie 2. 发送 Cookie 对象
reponse . addCookie(String name)
3. 获取 Cookie 对象,拿到对象
Cookie[] request.getCookies()
14.2 入门案例:
测试案例:
1. CookieServlet
@WebServlet("/cookieServlet")
public class CookieServlet extends
HttpServlet {
@Override
protected void doGet(HttpServletRequest
req, HttpServletResponse resp) throws
ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void
doPost(HttpServletRequest req,
HttpServletResponse resp) throws
ServletException, IOException {
// 获取 cookie 对象
Cookie cookie = new Cookie("msg",
"hello");
// 发送 cookie resp.addCookie(cookie);
}
}
2. CookieServlet2
import javax . servlet . ServletException ;
import javax . servlet . annotation . WebServlet ;
import javax . servlet . http . Cookie ;
import javax . servlet . http . HttpServlet ;
import
javax . servlet . http . HttpServletRequest ;
import
javax . servlet . http . HttpServletResponse ;
import java . io . IOException ;
@WebServlet ( "/cookieServlet2" )
public class CookieServlet2 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override 通过浏览器分别访问这两个 servlet, 并且读取 cookie 中的
数据
14.3 原理图
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
// 获取 cookie
Cookie [] cookies =
req . getCookies ();
// 获取数据,遍历 cookie
if ( cookies != null ) {
for ( Cookie cookie : cookies ) {
String name =
cookie . getName ();
String value =
cookie . getValue ();
System . out . println ( name + ":" + value );
}
}
}
} 14.4 注意事项
1. 一次发送多个 cookie
创建多个 cookie 对象,多次调用 addCookie ()方
2. Cookie 在浏览器中保存多长时间
默认清空下,当浏览器关闭, Cookie 数据被销毁
持久化存储:
setMaxAge intt seconds ):
seconds:
1. 正数:将 Cookie 数据写到硬盘文件中,持
久化存储 : second 具体的数值表示文件
存活的时长,以秒为单位。
2. 负数:默认值 3. 0 :删除 cookie 信息,因为服务器无法直
接操作用户电脑。
3. Tomcat 8 版本之前,不能直接存储中文数据。 8
本之后,可以直接存储中文
4. Cookie 的获取范围
一个服务器多个 web 项目
默认情况下一个 tomcat 服务器中,多个 web 项目
中的 cookie 是不能共享的
我们可以方法设置: setPath("/") ,这样 cookie
可以共享了
不同 tomcat 服务器
通过 setDomain ()方法,设置相同的一级域
名,那么这些一级域名相同的服务器间 cookie 可以
共享
tieba.baidu.com baidu.com 就是一级域名 .
14.5 Cookie 的特点
1. cookie 存储数据在客户端浏览器不安全
2. 大小有限制:单个 Cookie 的大小为 4KB , 同一个域
名下的总 cookie 数 不超过 20
14.6 Cookie 的作用
1. 存储少量,内容不敏感的作用 2. 在不登陆的情况下,完成服务器对客户端的身份识别
(主要用途)
比如:用户在不登陆百度的情况下对百度页面进行
的个性化设置信息,会被存储在 cookie 中,下次访
问百度。浏览器带着 cookie 的信息,百度服务器就
可以识别其身份,展示用户个性设置的页面
14.7 练习
需求: 访问网站时给出上一次登录信息:如果是第一次
则显示首次登录。
分析:
2. 在服务器中的 Servlet 判断是否有一个 lastTime
cookie
有:则不是第一次访问
响应数据
更新 Cookie
没有:则是第一次访问
响应:欢迎您,您是首次访问
添加 cookie:lastTime = 当前时间戳
代码实现:
1. 可以采用 Cookie 完成 @WebServlet ( "/cookie3" )
public class CookieServlet3 extends
HttpServlet {
@Override
protected void doGet ( HttpServletRequest
req , HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
// 设置响应编码集
resp . setContentType ( "text/html;charset=utf
-8" );
//1. 获取所有 Cookie
Cookie [] cookies =
req . getCookies ();
boolean flag = false ; // 标记是否有
lastTime
//2. 遍历数组
if ( cookies != null &&
cookies . length > 0 ) {
for ( Cookie cookie : cookies ) {
//3. 获取 cookie 名称 String name =
cookie . getName ();
//4. 判断
if
( "lastTime" . equals ( name )) {
// 存在,不是第一次访问
// 响应数据
String value =
cookie . getValue ();
resp . getWriter (). write ( "<h1> 您上一次访问的时
间是: " + value + "</h1>" );
// 设置新的 cookie 时间
Date date = new Date ();
SimpleDateFormat sdf =
new SimpleDateFormat ( "yyyy MM dd
HH:mm:ss" );
String newDate =
sdf . format ( date );
cookie . setValue ( newDate );
// 设置 cookie 存活时间
cookie . setMaxAge ( 60 *
60 * 24 * 30 ); // 存活一个月
// 发送 cookie
resp . addCookie ( cookie );
flag = true ;
}
}
} // 第一次访问
if ( cookies == null ||
cookies . length == 0 || flag == false ) {
// 设置新的 cookie 时间
Date date = new Date ();
SimpleDateFormat sdf = new
SimpleDateFormat ( "yyyy MM dd HH:mm:ss" );
String newDate =
sdf . format ( date );
Cookie cookie = new
Cookie ( "lastTime" , newDate );
// 设置 cookie 存活时间
cookie . setMaxAge ( 60 * 60 * 24 *
30 ); // 存活一个月
resp . addCookie ( cookie );
flag = true ;
resp . getWriter (). write ( "<h1> 您是
第一次访问 </h1>" );
}
}
}
写好之后会报错,因为 时间格式中有一个空格,虽
Tomcat8 之后对于中文字符可以支持,但是对于特殊
字符它还是不支持,所以我们需要将 Cookie 数据转化为
URL 编码存储,使用 URL 解码来解析。 所以:我们需要在存储数据前进行 URL 编码,在获取
数据后进行 URL 解码
15. JSP
15.1 概述: JSP - Java Server Page : Java 服务器端页面,该页面
中可以写 html 标签,也可以写 Java 代码。可以简化动态
内容书写量
演示案例:
当你浏览该页面时,页面既能输出 html 标签,服务器中
又能输出
15.2 原理:
JSP 页面本质是一个 Servlet
<% @ page
contentType = "text/html;charset=UTF-8"
language = "java" %>
<html>
<head>
<title> $Title$ </title>
</head>
<body>
<%
System . out . println ( "Hello JSP" );
%>
<h1> Hello JSP </h1>
</body>
</html> 因为,能在 web 服务器运行的 java 程序肯定是
Servlet 。我们通过前面的案例也能体会到如果我们
通过 Servlet response 对象响应静态资源工作量非
常大的。所以将动态资源和静态资源统一定义在 JSP
中,服务器启动后,会将 JSP 转换成对应的 Servlet
class 字节码文件。里面的方法就是处理动态资源 和
对静态内容的输出
15.3 脚本:
就是定义了 JSP Java 代码的书写方式
1. <% 代码 %> : 定义的 java 代码,相当于定义在 Servlet
中的 service() 方法中
2. <%! 代码 %> :定义的 Java 代码,相当于定义在
Servlet 中的成员位置,即成员变量和成员方法
3. <%= 代码 %> :输出语句,使用 JSP 的内置对象
Out (后面讲)
演示案例:
<% @ page
contentType = "text/html;charset=UTF-8"
language = "java" %>
<html>
<head>
<title> $Title$ </title>
</head>
<body>
<% 效果:
15.4 内置对象:
1. 概述: 直接在 JSP 页面中,不需要获取和创建,可以
直接使用的对象
2. 分类 :九大内置对象
request
response
session
out
page
application
System . out . println ( "Hello JSP" );
%>
<% ! int i = 10 ;%>
<% i = 3 ; %>
<% = i %>
<h1> Hello JSP </h1>
</body>
</html> pageContext
confifig
exception 内置对象名
真实数据类型
作用
request
HttpServletRequest
一次请
求中共
享数据
response
HttpServletResponse
响应对
session
HttpSession
一次会
话中共
享数据
out
JspWriter
输出对
象,输
出数据
到当前
页面
page
Objcet(this- 当前 jsp
)
当前页
面的对
application
ServletContext
所有用
户间共
享数据 内置对象名
真实数据类型
作用
pageContext
PageContext
当前页
面共享
数据,
还可以
获取其
8
内置对
confifig
ServletConfifig
Servlet
配置对
exception
Throwable
只有异
常页面
有该对
3.
4. response.getWriter() out 对象输出 :由于 web
服务器的工作机制,对于页面的输出,服务器都会先
访问 response 缓冲区,再访问 out 缓冲区,所以无论
response.getWriter() 的编写位置在哪里,它都会先
out 对象的输出。
15.5 Session 1. 概念 : 服务器端会话技术 - HttpSession
2. 功能
获取 HttpSession 对象
request.getSession()
使用 HttpSession 对象:
Object getAttribute(String name)
void setAttribute(String name Object value)
void removeAttribute(String name)
3. 原理:
session 的实现时依赖于 cookie 的。
第一次发送请求,服务器会创建 Session 对象,
并设置一个唯一的 ID 属性,并在相应时将该 Session
对象的的 ID 存入响应头: set-cookie : JSESSIONID=
id 属性。
当客户端发送第二次请求时, cookie 中就会有对
应的 Session id , web 服务器读取到头信息后,就会
将两次会话中使用的 Session 对象指向同一个 session
对象。
4. 注意
1. 客户端关闭后,再次开启客户端获取的 Sesion
同一个吗?
默认情况下不是,因为客户端关闭, cookie
被清空
如果需要相同,可以通过设置 cookie @WebServlet ( "/session1" )
public class SessionDemo extends
HttpServlet {
@Override
protected void
doGet ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
this . doPost ( req , resp );
}
@Override
protected void
doPost ( HttpServletRequest req ,
HttpServletResponse resp ) throws
ServletException , IOException {
// 获取 session 对象
HttpSession session =
req . getSession ();
//System.out.println(session);// 没有设
cookie 存活时间前, session 不是同一个
// 设置 cookie 存活时长
Cookie cookie = new
Cookie ( "JSESSIONID" , session . getId ());
cookie . setMaxAge ( 60 * 60 );
resp . addCookie ( cookie );
System . out . println ( session );
}
} 2. 服务器重新启动后,两个会话的 Sesion 是同一个
吗?
因为 Session 对象会被清空,所以很难相同。但是
我们不能因为重启服务器而丢失 Session 数据
解决: Session 的钝化 和 活化
1. 钝化:就是将 Seession 对象序列化到磁盘上
2. 活化:在服务器启动后,将 session 文件反序
列化成 Session 对象即可。
3. 注意: Tomcat 可以自动完成 Session 的活化
和钝化,但是 Idea 无法演示出效果,因为
idea 重启服务器会先将 work 目录删除,再重
新创建。而钝化的 session 文件就是在 work
目录中
3. Session 的什么时候销毁
服务器关闭
session 对象调用 invalidate(): 将自己杀死
session 默认失效时间: 30 分钟
可以通过 tomcat --- > conf ---->web.xml 配置失
效时间
image-20210124024029769
5. 特点:
session 用于存储一次会话中多次请求的数据,存
储在服务器端
session 可以存储任意类型,任意大小的数据
6. Session cookie 的区别 session 存储在服务器端, cookie 存储在客户端
session 没有数据大小的限制, Cookie
session 数据安全, cookie 相对不安全
15.6 登录案例优化
1. 将验证码实际内容存储到 session 对象中进行共享
2. 将错误提示信息显示在对应标签后部
3. 将验证码设置为一次性验证码
15.7 JSP 指令
1. 作用: 用于配置 JSP 页面,导入资源文件
2. 格式: <%@ 指令名称 属性名 1= 属性值 1 属性名 1=
性值 1 %>
3. 分类:
page :配置 JSP 页面
include :页面包含。(基本不用) taglib :导入资源,后面使用的 JSTL 标签就需要使
用该指令导入
15.6 page 指令
1. 常见属性:
contentType : 等同于
response.setContentType() :设置响应体的
Mime 类型及编码集。并且可以设置当前 JSP 的编
码集(高级开发工具才有的功能)
pageEncoding : 当前页面的编码集
language :jsp 语言,当年想统一所有表现层语
言,结果没实现,所以现在的 language 只有 java
这个属性值。
buffffer : 缓冲区大小,因为 jsp 中使用输出流,需要
缓冲区
import :导包,高级开发工具会自动导包
errorPage: 当前页面如果报错,会自动跳转至该
属性配置的页面。
演示:在演示案例页面中写入 <% int i = 3
/0%> , 指定 errorPage 属性跳转路径,即可看到
效果
isErrorPage : 标注当前页面是否是错误页面,如果
true , 则可以使用 Exception 这个内置对象 15.7 taglib
我们常用于引入标签库,后面学习 JSTL 会用到
prefifix : 前缀,自定义
15.8 mvc 开发模式
早期还没有 jsp 时,都是使用 servlet 开发,只能使用
response 输出标签数据,工作量非常大。后来 jsp 出现
后,简化了 servlet 的开发,开发人员开始过度的使用
jsp ,导致前后端无法分离,并且代码结构混乱,阅读性
非常差。为了解决这写问题 后来的 java 开发就借鉴了
MVC 开发模式,具体的规定了什么代码写什么位置,使
得程序设计更加合理。
1. MVC
M - Model 模型 JavaBean
完成具体的业务操作:比如:查询数据库,封装对
象等。
V - View 视图层 JSP
展示数据
C - Controller 控制器 Servlet
<% @ taglib prefix = "c"
uri = "http://java.sun.com/jsp/jstl/core" %> 获取用户的输入(请求)
调用模型
将数据交给视图层展示
2. 优点
耦合性低:将代码分为三部分,各司其职,便于维
护,
重用性高:
3. 缺点
使得架构变复杂,对程序员要求比较高。
因为三部分各司其职,所以 JSP 页面仅仅做展示,所以我
们需要学习替换他的两外两个技术 EL 表达式 和 JSTL
签。 16 EL 表达式
16.1 概述
EL - EXpression Language 表达式语言, jsp 本使支持 EL
表达式
16.2 作用
替换 和 简化 jsp 页面中 java 代码的编写
16.3 语法
${ 表达式 }
演示案例:
16.4 使用
1. 运算
算数运算: + - * / %
${ 3>4}
结果:页面会直接输出运算结果
\${ 表达式 }
结果:他会原样输出 比较运算: > ,< , >= , < = , >= , == ,!=
逻辑运算: && (and) , ||(or) , ! ( )
空运算符: empty 用于判断 字符串,集合 数组对
象是否为 null 并且长度是否为 0
<h3> 算数运算符 </h3>
${1+2 } <br>
${1-2 } <br>
${1*2 } <br>
${1/2 } <br>
${1%2 } <br>
<h3> 逻辑运算符 </h3>
${ 3>4 && 5 <6}
${ 3 > 4 and 5 <6}
2. 获取值
EL 表达式只能从域对象中获取值
语法: ${ 域名称 . 键名 } 从指定域中获取指定键的
域名称:
1. pageScope --->pageContext
2. requestScope ---> requestScope
3. sessionScope --->session
4. applicationScope --->application 举例:取出 request 域中的 name 属性值:
${request.name}
演示案例 1
演示案例 2
语法 2 ${ 键名 } : 默认会从最小的域以此向上寻找
16.5 获取对象 和 集合
1. user
<%
request . setAttribute ( "name" , " 刘德华 " );
%>
${requestScope.name}
${requestScope.age} 读不出数据也不会显示 null
而是显示空格
<%
request . setAttribute ( "name" , " 刘德华 " );
session . setAttribute ( "name" , " 周杰伦 " )
%>
${name}
import java . text . SimpleDateFormat ;
import java . util . Date ; public class User {
private String name ;
private int age ;
private Date birthday ;
public User ( String name , int age , Date
birthday ) {
this . name = name ;
this . age = age ;
this . birthday = birthday ;
}
public User () {
}
/**
* 逻辑视图
* @return
*/
public String getBirStr (){
if ( birthday != null ){
//1. 格式化日期对象
SimpleDateFormat sdf = new
SimpleDateFormat ( "yyyy-MM-dd HH:mm:ss" );
//2. 返回字符串即可
return sdf . format ( birthday ); } else {
return "" ;
}
}
public String getName () {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
public int getAge () {
return age ;
}
public void setAge ( int age ) {
this . age = age ;
}
public Date getBirthday () {
return birthday ;
}
public void setBirthday ( Date birthday )
{
this . birthday = birthday ; }
}
演示案例:
<html>
<head>
<title> el 获取数据 </title>
</head>
<body>
<%
User user = new User ();
user . setName ( " 张三 " );
user . setAge ( 23 );
user . setBirthday ( new Date ());
request . setAttribute ( "u" , user );
List list = new ArrayList ();
list . add ( "aaa" );
list . add ( "bbb" );
list . add ( user );
request . setAttribute ( "list" , list ); Map map = new HashMap ();
map . put ( "sname" , " 李四 " );
map . put ( "gender" , " " );
map . put ( "user" , user );
request . setAttribute ( "map" , map );
%>
<h3> el 获取对象中的值 </h3>
${requestScope.u} <br> 这里打印的是对象的字符串
表示形式
<% --
* 通过的是对象的属性来获取
* setter getter 方法,去掉 set get ,在
将剩余部分,首字母变为小写。
* setName --> Name --> name
-- %>
${requestScope.u.name} <br>
${u.age} <br>
${u.birthday} <br>
${u.birthday.month} <br> // 调用的 Date 类中的
getMonth 方法
// 如果我们想获取到格式化后的日期,我们可以去
user 类中提供一个方法 getBirStr()( 下面定义 )
${u.birStr} <br> 16.6 隐式对象
概述: el 表达式中直接可以使用的对象,
只需要知道通过 pageContext 对象可以获取其他 8 jsp
内置对象
常用的是获取 request 对象 , 再获取项目的虚拟目录
<h3> el 获取 List </h3>
${list} <br>
${list[0]} <br>
${list[1]} <br>
${list[10]} <br> // 越界 不会报错,显示空
${list[2].name}
<h3> el 获取 Map </h3>
${map.gender} <br>
${map["gender"]} <br>
${map.user.name}
</body>
</html>
${pageContext.request} <br>
<h4> jsp 页面动态获取虚拟目录 </h4>
${pageContext.request.contextPath} 17. JSTL 标签
17.1 概述:
JavaServer Pages Tag Library JSP 标准标签库 ,用于简
化和替换 jsp 页面上的 java 代码
17.2 使用
1. 导入 jstl 相关 jar
2. 引入标签库: taglib 指令: <%@ taglib %>
3. 使用标签
17.3 if
<% @ page import = "java.util.List" %>
<% @ page import = "java.util.ArrayList" %>
<% @ page
contentType = "text/html;charset=UTF-8"
language = "java" %>
<% @ taglib prefix = "c"
uri = "http://java.sun.com/jsp/jstl/core" %>
< html > < head >
< title > if 标签 </ title >
</ head >
< body >
<%--
c : if 标签
1. 属性:
* test 必须属性,接受 boolean 表达式
* 如果表达式为 true ,则显示 if
签体内容,如果为 false ,则不显示标签体内容
* 一般情况下, test 属性值会结合
el 表达式一起使用
2. 注意: c : if 标签没有 else 情况,想要 else
情况,则可以在定义一个 c : if 标签
--%>
< c : if test = "true" >
< h1 > 我是真 ... </ h1 >
</ c : if >
< br >
<%
// 判断 request 域中的一个 list 集合是否为
空,如果不为 null 则显示遍历集合 List list = new ArrayList ();
list . add ( "aaaa" );
request . setAttribute ( "list" , list );
// 判断 number 的奇偶性
request . setAttribute ( "number" , 4 );
%>
< c : if test = "${not empty list}" >
遍历集合 ...
</ c : if >
< br >
< c : if test = "${number % 2 != 0}" >
$ { number } 为奇数
</ c : if >
< c : if test = "${number % 2 == 0}" >
$ { number } 为偶数
</ c : if >
</ body >
</ html > 17.4 choose
<html>
<head>
<title> choose 标签 </title>
</head>
<body>
<% --
完成数字编号对应星期几案例
1. 域中存储一数字
2. 使用 choose 标签取出数字
相当于 switch 声明
3. 使用 when 标签做数字判断
相当于 case
4. otherwise 标签做其他情况的声明 相
当于 default
-- %>
<%
request . setAttribute ( "number" , 51 );
%>
<c:choose>
<c:when test = "${number == 1}" > 星期一
</c:when>
<c:when test = "${number == 2}" > 星期二
</c:when> 17.5 foreach
<c:when test = "${number == 3}" > 星期三
</c:when>
<c:when test = "${number == 4}" > 星期四
</c:when>
<c:when test = "${number == 5}" > 星期五
</c:when>
<c:when test = "${number == 6}" > 星期六
</c:when>
<c:when test = "${number == 7}" > 星期天
</c:when>
<c:otherwise> 数字输入有误
</c:otherwise>
</c:choose>
</body>
</html>
<% @ page import = "java.util.ArrayList" %>
<% @ page import = "java.util.List" %>
<% @ page
contentType = "text/html;charset=UTF-8"
language = "java" %> <% @taglib prefix = "c"
uri = "http://java.sun.com/jsp/jstl/core" %>
< html >
< head >
< title > foreach 标签 </ title >
</ head >
< body >
<%--
foreach : 相当于 java 代码的 for 语句
1. 完成重复的操作
for ( int i = 0 ; i < 10 ; i ++ ){
}
* 属性:
begin :开始值(包含)
end :结束值(包含)
var :临时变量 - 相当于 i
step :步长,每次改变量
varStatus : 循环状态对象,在普通
for 循环中 与 var 相同
index : 容器中元素的索引,从
0 开始
count : 循环次数,从 1 开始
2. 遍历容器
List < User > list ;
for ( User user : list ){ }
* 属性:
items : 容器对象 - list 集合
var : 容器中元素的临时变量 - 遍历
操作中存储集合元素的临时变量
varStatus : 循环状态对象 - 循环第
几次
index : 容器中元素的索引,从
0 开始
count : 循环次数,从 1 开始
--%>
// 打印 1-10 的基数
< c : forEach begin = "1" end = "10" var = "i"
step = "2" varStatus = "s" >
$ { i } < h3 > $ { s . index } < h3 > < h4 > $ { s . count }
</ h4 >< br >
</ c : forEach >
< hr >
<%
List list = new ArrayList ();
list . add ( "aaa" );
list . add ( "bbb" );
list . add ( "ccc" ); request . setAttribute ( "list" , list );
%>
// 遍历集合
< c : forEach items = "${list}" var = "str"
varStatus = "s" >
$ { s . index } $ { s . count } $ { str }
< br >
</ c : forEach >
</ body >
</ html >
练习 :
< html >
< head >
< title > test </ title >
</ head >
< body >
<%
List list = new ArrayList (); list . add ( new User ( " 张三 " , 23 , new
Date ()));
list . add ( new User ( " 李四 " , 24 , new
Date ()));
list . add ( new User ( " 王五 " , 25 , new
Date ()));
request . setAttribute ( "list" , list );
%>
< table border = "1" width = "500"
align = "center" >
< tr >
< th > 编号 </ th >
< th > 姓名 </ th >
< th > 年龄 </ th >
< th > 生日 </ th >
</ tr >
<%-- 数据行 --%>
< c : forEach items = "${list}" var = "user"
varStatus = "s" >
< c : if test = "${s.count % 2 != 0}" >
< tr bgcolor = "red" >
< td > $ { s . count } </ td >
< td > $ { user . name } </ td >
< td > $ { user . age } </ td > 18. 过滤器
< td > $ { user . birStr } </ td >
</ tr >
</ c : if >
< c : if test = "${s.count % 2 == 0}" >
< tr bgcolor = "green" >
< td > $ { s . count } </ td >
< td > $ { user . name } </ td >
< td > $ { user . age } </ td >
< td > $ { user . birStr } </ td >
</ tr >
</ c : if >
</ c : forEach >
</ table >
</ body >
</ html > 18.1 概述
1. 概述:当访问服务器资源时,过滤器可以将请求拦截
下来,进行一些特殊的功能
2. 作用:一般用于完成通用的操作,比如登录操作,统
一编码处理,过滤敏感字符
18.2 快速入门
步骤:
1. 定义一个类,实现接口 Fileter
2. 复写方法
3. 配置拦截路径。
演示案例
创建一个类,实现 Filter 接口,启动服务器,如果没有放
行代码,则 jsp 中内容将不会给展示。
/**
* @author lp
* @version 1.0
*/
@WebFilter("/*")// 访问所有资源都会被执行
public class FilterDemo1 implements Filter
{
@Override 18.3 执行流程
通过代码来演示 Filter 的执行流程:
public void init(FilterConfig
filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest
servletRequest, ServletResponse
servletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println(" 过滤器被执
行。。。。 ");
// 放行
filterChain.doFilter(servletRequest,servlet
Response);
}
@Override
public void destroy() {
}
} 新建一个过滤器
@WebFilter ( "/*" ) // 访问所有资源都会被执行
public class FilterDemo2 implements Filter
{
@Override
public void init ( FilterConfig
filterConfig ) throws ServletException {
}
@Override
public void doFilter ( ServletRequest
servletRequest , ServletResponse
servletResponse , FilterChain filterChain )
throws IOException , ServletException {
System . out . println ( " 过滤器被执
行。。。。 " );
// 放行
filterChain . doFilter ( servletRequest , servle
tResponse );
System . out . println ( " 过滤器又被执行
了。。。 " );
}
@Override
public void destroy () { }
}
index.jsp 中添加一条输出语句
<% @ page
contentType = "text/html;charset=UTF-8"
language = "java" %>
<html>
<head>
<title> $Title$ </title>
</head>
<body>
<%
System . out . println ( "JSP 被执行 " );
%>
</body>
</html>
执行结果: 为什么会这样呢? 因为过滤器是对访问数据和响应
数据进行处理的,所以访问前,过滤会执行一次,处理
request 中的对象, jsp 页面执行完毕后,过滤器又会对
response 中的数据进行处理。
有一点需要注意的是, 过滤器再次被执行就从 放行
语句后开始执行
18.4 过滤器配置:(只讲注解方式)
拦截路径配置:
1. 具体资源路径: /index.jsp 只有访问 index.jsp
源时,过滤器才会被执行
2. 拦截目录: /user/*
访问 /user 下的所有资源时,
过滤器都会被执行
3. 后缀名拦截: *.jsp
访问所有后缀名为 jsp 资源
时,过滤器都会被执行
4. 拦截所有资源: /* 访问所有资源时,过滤器都
会被执行
拦截方式配置:资源被访问的方式:直接访问,转发
1. 注解配置:
设置 dispatcherTypes 属性
REQUEST :默认值。浏览器直接请求资源
FORWARD :转发访问资源 INCLUDE :包含访问资源
ERROR :错误跳转资源 : jsp 中配置
ASYNC :异步访问资源
18.5 过滤器链
这里我们只需要了解执行顺序即可
执行顺序:如果有两个过滤器:过滤器 1 和过滤器 2
1. 过滤器 1
2. 过滤器 2
3. 资源执行
4. 过滤器 2
5. 过滤器 1
过滤器先后顺序:按照类名字符串比较顺序。 xml
置按照配置先后。
@WebFilter ( value =
"/index.jsp" , dispatcherTypes =
DispatcherType . REQUEST ) // 配置一种方式
@WebFilter ( value =
"/index.jsp" , dispatcherTypes =
{ DispatcherType . REQUEST , DispatcherType . FORW
ARD }) // 配置多种访问方式被拦截 # 解决控制台中文乱码
1.Tomcat 设置面板
2.Settings 
3. Help --- Edit Custom VM Options 最后一行 :
- Dfile . encoding = UTF - 8

</

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ServletJSP学习指南PDF是一本关于JavaWeb开发的指南,旨在帮助学习者深入理解和掌握ServletJSP技术。 ServletJava Web开发中常用的一种技术,用于处理Web请求和响应。它基于Java语言,提供了一组用于处理HTTP通信的类和接口。通过Servlet,我们可以实现动态的Web应用程序,与数据库进行交互,处理用户的请求,并生成响应结果。Servlet学习指南将介绍Servlet的工作原理、使用方法和常见的应用场景,帮助学习者快速上手并掌握这项技术。 JSP(Java Server Pages)是一种基于Java的动态网页技术,用于在Web服务器上生成动态网页。与Servlet相比,JSP更加注重于网页的内容展示和页面的设计。它允许开发者在HTML文档中嵌入Java代码,通过特殊的标签和表达式,动态生成所需的HTML内容。JSP学习指南将介绍JSP的语法、标签和表达式的使用,以及JSPServlet之间的关联和数据传递方式,帮助学习者全面了解和掌握这项技术。 ServletJSP学习指南PDF提供了详细的实例代码和案例,让学习者可以通过实践来理解和掌握这两项技术。此外,学习指南还介绍了常见的开发工具和调试技巧,以及一些常见问题的解决方法。通过学习这本指南,学习者可以建立起对ServletJSP技术的整体认识和理解,为进一步的Web开发打下坚实的基础。 综上所述,ServletJSP学习指南PDF是一本宝贵的学习资料,它能够帮助人们系统地学习和掌握ServletJSP技术,在JavaWeb开发中大放异彩。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值