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
</