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.613.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,并创建一个类ServletDemo2. 实现Servlet接口
注意:实现接口时会发现,找不到依赖
解决办法
1. File ---> Project Structure
2. 选择 Library
3. 选择 Tomcat 8.5.61---> Add Selected3. 重写的方法我们先不管是干什么的,我们先找到
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=hahaha10.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=zhangsanString 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;
}
@Overridepublic 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=17280011.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);
}
@Overrideprotected 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);
}
@Override12.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);
}
@Override2. 域对象:可以共享数据
功能:所有域对象都有该功能
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 {
@Override3. 获取文件的服务器真实存储路
演示案例:
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=xxxMIME
使用字节输入流加载文件进内存
使用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. 客户端会话技术Cookie2. 发送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");
//发送cookieresp.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 Session1. 概念:服务器端会话技术 - 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
{
@Override18.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
</
本文深入浅出地介绍了Web相关概念,涵盖C/S与B/S架构、资源分类、网络通信、服务器管理、Tomcat实战、Servlet与JSP、HTTP协议、会话技术及JSP与JSTL标签的应用。
725

被折叠的 条评论
为什么被折叠?



