个人主页:Hello Code.
本文专栏:《Java Web从入门到实战》
篇幅较长,并未完结,后续内容会持续更新
本文后续也会分篇发布,方便大家阅读
如没有Java基础,请先前往《Java零基础指南》专栏学习相应知识
如有问题,欢迎指正,一起学习~~
操作系统:管理计算机硬件与软件资源的计算机程序,同时也是计算机系统的内核与基石。
主流操作系统
Linux发展历程
Linux特点
Linux与其它操作系统的区别
Windows更适用于家庭个人使用
Linux更适用于企业服务器使用
Linux发行商和常见发行版
先安装虚拟机,再安装Centos
Vmware简介
Vmware下载:https://www.vmware.com/cn.html
CentOS镜像下载:https://www.centos.org/download/
高速下载地址
简介:SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windows下登录Unix或Linux服务器主机的软件。
cd /
ls -l
克隆:将原系统完完全全的拷贝一份,原系统丢失后克隆的系统还能正常使用
快照:记录系统当前状态,并不会把系统完整拷贝
克隆和拍摄快照时都需要关闭虚拟机
与用户相关的命令,必须在管理员权限下才能执行
命令:
su root
useradd (选项) 用户名
passwd (选项) 用户名
在root权限下切换其它用户可直接切换,无需输入密码
usermod 选项 用户名
userdel (选项) 用户名
将用户分成小组,方便对用户的管理
groupadd (选项) 用户组名
groupmod (选项) 用户组名
groups 用户名
groupdel 用户组名
gpasswd (可选项) 组名
gpasswd是Linux下的管理工具,用于将一个用户添加到组或者从组中删除
date [参数选项]
-d "字符串"
:显示字符串所指的日期与时间。字符串前后必须加上双引号-s "字符串"
:根据字符串来设置日期与时间。字符串前后必须加上双引号-u
:显示GMT(北京时间为CST)--help
:在线帮助--version
:显示版本信息logname
su 用户名
id 用户名
sudo [参数选项]
实时显示process的动态 :top
pid:每个进程的id
user:进程是属于哪个用户
PR:进程的优先级
NI:进程优先级(负数为高优先级,正数为低优先级)
VIRT:当前进程占用虚拟内存的总量
S:当前进程的状态
top -c
top -p PID
q
查看当前正在运行的进程信息:ps
ps -A
ps -ef
ps -u 用户名
中断执行中的程序:kill PID
kill 1111
表示杀死PID为1111的进程kill -9 PID
:强制杀死指定PID的进程killall -u 用户名
:杀死这个用户中的所有进程kill -9 $(ps -ef|grep 用户名)
:杀死指定用户的所有进程kill -l
:查看对应编号关机命令:shutdown
(延迟关机)
shutdown -h now
:立即关机shutdown +1 "1分钟以后关机"
:延迟一分钟以后关机,并给出警告信息shutdown -r +1 "准备重启了"
:延迟一分钟以后重启,并给出警告信息shutdown -c
:取消关机命令reboot
(立即重启)显示当前登录系统的用户:who
who -H
:显示明细(标题)信息校正服务器时间、时区:timedatectl
几个小概念
项目 | 说明 |
---|---|
时区 | 因时区不同显示的时间不同,牵扯到夏令时和调整等问题,date命令可查看 |
系统时钟:System Clock | Linux OS的时间,date命令可查看 |
硬件时钟:RTC:Real Time Clock | 主板上由电池供电的BIOS时间,hwclock -r可查看 |
NTP:Network Time Protocol | 本机时间和实际的时间之间的经常会有差别,一般使用NTP服务器进行时间校准 |
timedatectl status
:显示系统的当前时间和日期timedatectl list-timezones
:查看所有可用的时区timedatectl set-timezone "Asia/Shanghai"
:设置本地时区timedatectl set-ntp false
:禁用时间同步timedatectl set-time "2022-02-22 20:20:00"
:设置时间timedatectl set-ntp true
:启用时间同步清除屏幕:clear
常见命令 | 作用 |
---|---|
ls | 列出目录 |
cd | 切换目录 |
pwd | 显示目前的目录 |
mkdir | 创建新目录 |
rmdir | 删除空目录 |
cp | 复制文件或目录 |
rm | 删除文件或目录 |
mv | 移动文件或目录 修改文件或者目录的名字 |
ls [参数选项] 目录名称
-a
:显示所有文件或目录(包含隐藏)-d
:仅列出目录本身,而不是列出目录内的文件数据(常用)-l
:长数据串列出,包含文件的属性与权限等等数据(常用)
ls
:显示不隐藏的文件与文件夹
ls -l
:显示不隐藏的文件与文件夹的详细信息
ls -al
:显示所有文件与文件夹的详细信息
pwd -P
:查看当前所在目录cd [相对路径或绝对路径]
:切换目录
cd ..
:返回上一级目录mkdir
mkdir 文件夹的名字
:创建单级目录mkdir -p aaa/bbb
rmdir
rmdir 文件夹名字
:删除空目录rmdir -p aaa/bbb
:删除多级目录(先删bbb,如果删完aaa也为空,则aaa也一起删除)rm
rm 文件路径
:删除文件rm -r 目录路径
:删除目录和目录里面所有的内容(单级目录或多级目录都行)touch 文件名.后缀名
:创建一个文件cp
cp 数据源 目的地
:文件复制(仅文件)cp -r aaa/* ccc
:将aaa目录中的所有文件及目录拷贝到ccc中(*
代指所有)mv
mv 数据源 目的地
:改名(数据源和目的地相同)、移动文件或文件夹mv 文件名 文件名
:将源文件名改为目标文件名mv 目录名 目录名
:目标目录已存在,将源目录移动到目标目录;目标目录不存在则改名chgrp
命令(change group)
chgrp [选项参数] [所属群组] [文件或目录...]
:更改所属组chgrp root aaa
:将aaa文件夹所属组更改为rootchgrp -v root aaa
:将aaa的属组改为root(-v会多一句提示语)chown
命令
chown 属主名 文件名
:更改属主chown [参数选项] 属主名:属组名 文件名
:更改属主和属组chmod
命令
chmod [参数选项] 数字权限 文件或目录
chmod u=rwx,g=rx,o=r a.txt
修改方式
设置时会把三个数字加在一起设置
例如:rwx则为7
需求:一个公司的开发团队有三个用户:Java、erlang、golang
有一个文件目录tmp/work供他们开发,如何实现让这三个用户都对其具有写权限
思路
touch [参数选项] 文件名
如果文件不存在就创建文件,如果存在就修改时间属性
touch a{1..10}.txt
:创建a1.txt一直到a10.txt共10个文件(批量创建空文件)stat a.txt
:查看文件的详细信息简单来说:
vi是老式的文字处理器,不过功能已经很齐全了,但是还是有可以改进的地方
vim则可以说是程序员开发者的一项很好用的工具
命令模式下只能读不能写
在命令模式下输入i
可以进入编辑模式,在编辑完成之后按下Esc
又可以退出到命令模式
在命令模式下输入:
可以进入末行模式,在保存完之后还可以按下两次Esc
继续回退到命令模式
vim 文件名
命令 | 英文 | 功能 | 常用 |
---|---|---|---|
i | insert | 在当前字符前插入文本 | 常用 |
I | insert | 在行首插入文本 | 较常用 |
a | append | 在当前字符后添加文本 | |
A | append | 在行末添加文本 | 较常用 |
o | 在当前行后面插入一空行 | 常用 | |
O | 在当前行前面插入一空行 | 常用 |
:q
:当vim进入文件没有对文件内容做任何操作可以按“q”退出:q!
:当vim进入文件对文件内容有操作但不想保存退出:wq
:正常保存退出:wq!
:强行保存退出,只针对于root用户或文件所有人vim 文件名 +行数
:查看文件并定位到具体行数vim a.txt +5
:查看a.txt文件并定位到第5行在修改一个文件时(a.txt),为保证文件安全,vim不会对源文件进行修改,会产生一个新的文件(a.txt.swp),并对该文件进行编辑
只有在保存的时候,才会将新文件写回到源文件中
命令 | 功能 |
---|---|
cat 文件名 | 查看小文件内容 |
less -N 文件名 | 分屏显示大文件内容 |
head -n 文件名 | 查看文件的前一部分 |
tail -n 文件名 | 查看文件的最后部分 |
grep 关键字 文件名 | 根据关键字搜索文本文件内容 |
cat -n a.txt
:可以加入参数选项-n
显示行号
less 文件名
:查看大文件
-N
可显示行号tail 文件名
:默认查看文件最后10行内容
tail -3 b.txt
:查看文件最后3行内容tail -f b.txt
:动态显示文件最后10行内容(ctrl + C停止)tail -n +2 b.txt
:显示文件b.txt的内容,从第2行至文件末尾tail -c 45 b.txt
:显示文件最后45个字符head 文件名
:查看文件前10行内容
grep命令
grep [参数选项] 关键字 文件
:根据关键字,搜索文本文件内容ps -ef | grep sshd
:将进程中含有sshd的进程展示出来ps -ef | grep -c sshd
:将进程中含有sshd的进程的个数展示出来echo 字符串
:展示文本echo 字符串 > 文件名
:将字符串写到文件中(覆盖文件内容)echo 字符串 >> 文件名
:将字符串写到文件中(不覆盖原内容)cat 不存在的目录 &>> 存在的文件
:将命令的失败结果追加到指定的文件的后面awk [参数选项] '语法' 文件
cat a.txt | awk '/zhang|li/'
:查看a.txt文件中包含zhang或者li的行选项 | 含义 |
---|---|
-F ',' |
使用指定字符分割 |
$ + 数字 |
获取第几段内容 |
$0 |
获取当前行内容 |
OFS="字符" |
向外输出时的段分割字符串 |
toupper() |
字符转成大写 |
tolower() |
字符转成小写 |
length() |
返回字符长度 |
cat a.txt | awk -F ' ' '{print $1,$2,$3}'
:将a.txt中的内容按空格分割并打印第1-3列
cat a.txt | awk -F ' ' '{print toupper($1),$2,$3}'
:将a.txt中的内容分隔后并将$1中的内容转为大写字符后输出
cat a.txt | awk -F '' '{OFS="---"}{print $1,$2,$3}'
:将a.txt中的内容分隔后并用—重新分隔后输出
命令 | 含义 |
---|---|
awk BEGIN{初始化操作} {每行都执行} END{结束时操作} 文件名 |
固定语法 BEGIN{这里面放的是执行前的语句} {这里面放的是处理每一行要执行的语句} END{这里面放的是处理完所有的行后要执行的语句} 文件名 |
cat a.txt | awk -F' ' 'BEGIN{}{totle=totle+$2}END{print totle}'
:将a.txt分割后把$2的值相加并输出
cat a.txt | awk -F' ' 'BEGIN{}{totle=totle+$2}END{print totle}'
:输出totle以及总人数(行数)
ln -s 目标文件路径 快捷方式路径
ln -s aaa/bbb/ccc/ddd/eee/a.txt a.txt
find [参数选项] <指定目录> <指定条件> <指定内容>
:在指定目录下查找文件find . -name "*.txt"
:查找当前目录下所有以txt为后缀的文件find . -ctime -1
:当前文件夹下1天内操作过的文件
将 . 替换为 / 则表示在全盘范围进行查找
gzip [参数选项] [文件]
:压缩文件gzip a.txt
:将a.txt文件压缩gzip *
:将当前目录下所有文件都进行压缩(已经压缩过的不能再次被压缩)gzip -dv 文件名
:解压文件并显示详细信息gunzip [参数] [文件]
:解压文件gunzip 压缩文件
:解压压缩文件gunzip *
:解压当前目录下的所有压缩文件tar [必要参数] [选择参数] [文件]
:打包、压缩和解压(文件/文件夹)tar -cvf 打包文件名 文件名
:打包文件并指定打包之后的文件名(仅打包不压缩)tar -zcvf b.gz b.txt
:通过gzip指令将b.txt压缩为b.gz并显示过程(打包压缩)tar -zcvf aaa.gz aaa
:将aaa文件夹压缩为aaa.gztar -ztvf aaa.gz
:查看压缩文件中的内容tar -zxvf aaa.gz
:解压aaa.gz文件zip [必要参数] [选择参数] [文件]
:压缩zip -q -r 压缩文件名 文件/文件夹
:压缩对应的文件/文件夹unzip [必要参数] [选择参数] [文件]
:解压unzip -l aaa.zip
:查看aaa.zip压缩文件所包含的文件unzip -d aaa aaa.zip
:将aaa.zip压缩文件解压到aaa文件夹中(aaa文件夹可以不存在,会自动创建)bzip2 [参数选项] 文件
:压缩文件bzip2 a.txt
:压缩并删除a.txtbunzip2 [参数选项] 文件
:解压
bunzip2 -v a.bz2
:解压并显示详细信息ifconfig [参数选项]
:显示或配置网络设备的命令ifconfig ens37 down
:关闭ens37这张网卡ifconfig ens37 up
:开启网卡ens37ifconfig ens37 192.168.23.199
:将ens37网卡的ip更改为192.168.23.199ifconfig ens37 192.168.23.199 netmask 255.255.255.0
:配置ip地址和子网掩码ping [参数选项]
:检测是否与主机联通ping -c 2 www.baidu.com
:指定接收包的次数netstat [参数选项]
:显示网络状态lsblk [参数选项]
:列出硬盘的使用情况lsblk -f
:显示系统信息df [参数选项]
:显示目前在Linux系统上,磁盘的使用情况df
:显示整个硬盘的使用情况df 文件夹
:显示文件夹使用情况df --total
:显示所有的信息df -h
:将结果变成kb、mb、gb等形式展示,利于阅读mount [参数选项] 目录
:用于挂载Linux系统外的设备注意:“挂载点”的目录需要以下几个要求:
目录事先存在,可以用mkdir命令新建目录
挂载点目录不可被其它进程使用到
挂载点下原有文件将被隐藏
mount -t auto /dev/cdrom PPP
:将光驱和PPP文件夹挂载umount PPP
:卸载PPP文件夹所挂载的光驱yum check -update
yum update
yum install
yum update
yum list
yum remove
yum search
yum clean packages
:清除缓存目录下的软件包yum clean headers
:清除缓存目录下的headersyum clean oldheaders
:清除缓存目录下旧的headersyum clean,yum clean all(= yum clean packages;yum clean oldheades)
:清除缓存目录下的软件包及旧的headersyum -y install tree
:安装treetree
:执行tree,展示当前目录结构yum remove tree
:移除treeyum list tom*
:查找以tom为开头的软件名称yum -y install wget
:安装一个下载工具cd /etc/yum.repos.d/
:进入yum的相关文件夹中mv CentOS-Base.repo CentOS-Base.repo.back
:对原yum文件改名(备份)wget -O CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
:下载阿里yum源文件yum clean all
:清理缓存,并重新加载yumyum makecache
:为新yum源建立缓存文件yum search tomcat
:查找软件,验证阿里云的yum源是否可以正常使用在计算机科学中,shell就是一个命令解释器
shell是位于操作系统和应用程序之间,是他们二者最主要的接口。
shell负责把应用程序的输入命令信息解释给操作系统,将操作系统指令处理后的结果解释给应用程序
一句话,shell就是在操作系统和应用程序之间的一个命令翻译工具。
Windows和Linux中的shell
shell的使用方式
手工敲击键盘,直接输入命令,按Enter后。
执行命令,显示命令执行的结果
重点:逐行输入命令,逐行进行确认执行
我们把手工执行的命令,写到一个文件中,然后运行这个文件,达到执行命令的效果。
这个文件就叫做脚本文件
编写第一个shell脚本
#! /bin/bash
#这是临时shell脚本
echo 'nihao'
echo 'hello'
注释
#!/bin/bash
# 这是单行注释
echo 'hello world'
#!/bin/bash
:<<! 这是多行注释
多行注释
多行注释
!
echo 'hello world'
:<<字符
注释内容
字符
变量
变量名=变量值
(变量值必须是一个整体,中间没有特殊字符)变量名='变量值'
(单引号中的内容,原样赋值)变量名="变量值"
(如果双引号中有其它变量,会把变量的结果进行拼接,然后赋值)习惯:数字不加引号,其它默认加双引号
变量名=$(命令)
(常用)$变量名
(非标准写法,图省事)"$变量名"
(非标准写法,图省事)${变量名}
(在双引号里面要使用变量的值)"${变量名}"
(标准使用方式)readonly 变量名
unset 变量名
定义数组 | 数组名=(值1 值2 … 值n) | arr=(1 2 3 4 5) |
---|---|---|
给数组的元素赋值 | 数组名[索引]=值 | arr[0]=1 |
获取元素 | ${数组名[下标]} | ${arr[0]} |
获取长度 | ${#数组名[*]} ${#数组名[@]} |
${#arr[*]} ${#arr[@]} |
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | expr $a + $b |
- | 减法 | expr $a - $b |
* | 乘法 | expr $a \* $b |
/ | 除法 | expr $b / $a |
% | 取余 | expr $b % $a |
= | 赋值 | a=$b (把b变量的值赋给a变量) |
++ / – | 自增 / 自减 | ((a++)) |
注意点
举例:`expr 2 + 2`
字符串运算符
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回true | [ $a = $b ] |
!= | 检测两个字符串是否不相等,不相等返回true | [ $a != $b ] |
-z | 检测字符串长度是否为0,为0返回true | [ -z $a ] |
-n | 检测字符串长度是否不为0,不为0返回true | [ -n $a ] |
$ | 检测字符串是否为空,不为空返回true | [ $a ] |
[]
与里面的代码命令有个空格隔开,不能贴在一起
$?
可以获取上一条语句的执行结果在shell中,0为真,1为假
${#字符串}
获取字符串长度
关系运算符
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回true(equals) | [ $a -eq $b ] |
-ne | 检测两个数是否不相等,不相等返回true(not equals) | [ $a -ne $b ] |
-gt | 检测左边的数是否大于右边的,如果是,则返回(truegreater than) | [ $a -gt $b ] |
-lt | 检测左边的数是否小于右边的,如果是,返回true(less than) | [ $a -lt $b ] |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回true(greater equals) | [ $a -ge $b ] |
-le | 检测左边的数是否小于等于右边的,如果是,则返回true(less equals) | [ $a -le $b] |
关系运算符只支持数字,不支持字符串,除非字符串的值是数字
布尔运算符
运算符 | 说明 | 举例 |
---|---|---|
! | 取反运算 | [ ! false ] 返回true |
-o | 或运算,有一个表达式为true 则返回true (or) | [ $a -lt 20 -o $b -gt 100 ] |
-a | 与运算,两个表达式都为true 才返回true(and) | [ $a -lt 20 -a $b -gt 100 ] |
逻辑运算符
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ true && true ]] 返回true |
|| | 逻辑的 OR | [[ false || false ]] 返回false |
if语法
if[ 条件 ]
then
语句体
fi
if [ 条件 ]
then
语句体
else
语句体
fi
if [ 条件1 ]
then
语句体
elif [ 条件2 ]
语句体
else
语句体
fi
小练习
#!/bin/bash
# if语句
#if的第一种格式:
#查找一个进程,如果进程存在,就打印true
if [ $(ps -ef | grep -c "ssh") -gt 1 ]
then
echo "true"
fi
case语法
case 值 in
模式1 )
语句体1
;;
模式2 )
语句体2
;;
esac
v="hhxx"
case "${v}" in
"hhxx")
echo "好好学习"
;;
"ttxs")
echo "天天向上"
;;
esac
for循环
for 变量 in 范围
do
循环体
done
for loop in A B C
do
echo $loop
done
while循环
while 条件
do
循环体
done
a=1
while [ "${a}" -le 10 ]
do
echo "${a}"
((a++))
done
无参无返回值
函数名(){
函数体
}
test(){
echo "函数测试!"
}
echo "==========="
test
echo "============"
有参无返回值
method(){
echo "第一个参数$1"
echo "第二个参数$2"
}
method a b
有参有返回值
method(){
echo "接收到参数$1和$2"
return $(($1 + $2))
}
method 10 20
echo $?
小练习
read 变量名
:表示把键盘录入的数据赋值给这个变量
#!/bin/bash
#在方法中键盘录入两个整数,并返回这两个整数和
method(){
echo "请录入第一个数:"
read num1
echo "请录入第二个数:"
read num2
echo "两个数分别为:${num1},${num2}"
return $(($num1 + $num2))
}
method
echo "两数之和为:$?"
这部分应该是HTML + CSS + Nginx,因为HTML和CSS是之前学过的,当时并没有记笔记,这部分也相当简单些,如果有没学过的可以自行搜索资料学习一下~
上传压缩包:put nginx压缩包位置
(CRT中按alt+p键进入sftp)
解压压缩包:tar -zxvf 压缩包名
进入解压目录:cd nginx解压目录
安装依赖环境
yum -y install pcre pcre-devel
yum -y install zlib zlib-devel
yum -y install openssl openssl-devel
yum -y install gcc
安装nginx
./configure
make
make install
(安装完会在/usr/local/下有一个nginx目录)
进入对应目录:cd /usr/local/nginx/sbin
启动nginx服务:./nginx
停止:./nginx -s stop
重启:./nginx -s reload
查看nginx服务状态:ps -ef | grep nginx
测试nginx服务:浏览器打开对应Linux服务器ip地址
最后这里在浏览器打开对应ip地址无法访问,解决方法:
第一步,对80端口进行防火墙配置:firewall-cmd --zone=public --add-port=80/tcp --permanent
第二步,重启防火墙服务:systemctl restart firewalld.service
然后重新在浏览器中访问你的ip,应该就可以访问了。
在 /home 下创建一个web目录:mkdir web
将项目上传到该目录下:put web项目压缩包
解压项目压缩包:unzip web程序压缩包
编辑nginx配置文件:vim /home/nginx-1.18.0/conf/nginx.conf
找到server的大括号范围,修改location的路径
进入对应目录:cd /usr/local/nginx/sbin
关闭nginx服务:./nginx -s stop
启动nginx服务并加载配置文件:/usr/local/nginx/sbin/nginx -c/home/nginx-1.18.0/conf/nginx.conf
通过浏览器测试网站
概述
资源分类
在之前的学习中,开发的都是Java工程。这些工程在企业中称之为项目或者产品。都是有系统架构的!
服务器名称 | 说明 |
---|---|
weblogic | 实现了JavaEE规范,重量级服务器,又称为JavaEE容器 |
websphereAS | 实现了JavaEE规范,重量级服务器 |
JBOSSAS | 实现了JavaEE规范,重量级服务器,免费的 |
Tomcat | 实现了jsp/servlet规范,是一个轻量级服务器,开源免费 |
下载和安装
启动
startup.bat
:Windows下启动执行文件
startup.sh
:Linux下启动执行文件
启动后浏览器访问:http://localhost:8080可以进入欢迎界面(Tomcat默认端口为8080)
停止
shutdown.bat
:Windows下关闭执行文件
shutdown.sh
:Linux下关闭执行文件
部署项目
在webapps目录下创建一个文件夹
将资源放到该文件夹中
启动tomcat,输入正确路径
常见问题
java.net.BindException:端口8080被占用
控制台乱码问题解决
conf-logging.properties
修改java.util.logging.ConsoleHandler.encoding = UTF-8
Tomcat默认UTF-8,CMD命令窗口默认GBK,将UTF-8改为GBK即可解决乱码问题
IDEA集成Tomcat
Linux下的安装
put d:/apache-tomcat-9.0.58.tar.gz
tar -zxvf 压缩包名
cd apache-tomcat-9.0.58/bin
./startup.sh
项目组成详解
IDEA发布项目
通过war包发布项目
jar -cvf myweb.war .
配置默认端口号
主配置文件server.xml
标签中,port属性代表Tomcat默认端口号(8080)
http协议默认端口号为80,Tomcat默认端口号与其不一致,所以每次访问网站需要加上端口号
如果是80端口,就不需要加端口号
真正发布网站的时候,都需要将tomcat默认端口号改为80,这样在访问网站的时候就不需要加端口号了
配置虚拟目录
配置虚拟主机
name
:虚拟主机名称
appBase
:项目所保存的根路径
unpackWARs
:是否自动解压war包
autoDeploy
:是否自动发布
Context
:同虚拟目录
组成部分
除了手动发起的请求外,JavaScript、CSS、图片等资源会自动发起请求
请求的组成部分
请求行:请求方式 提交路径(提交参数) HTTP/版本号
请求头
名称 | 说明 |
---|---|
Accept | 客户端浏览器所支持的MIME类型 |
Accept-Encoding | 客户端浏览器所支持的压缩编码格式。最常用的就是gzip压缩 |
Accept-Language | 客户端浏览器所支持的语言。一般都是zh_CN或en_US等 |
Referer | 告知服务器,当前请求的来源 |
Content-Type | 请求正文所支持的MIME类型 |
Content-Length | 请求正文的长度 |
User-Agent | 浏览器相关信息 |
Connection | 连接的状态。Keep-Alive保持连接 |
If-Modified-Since | 客户端浏览器缓存文件的最后修改时间 |
Cookie | 会话管理相关,非常的重要 |
请求空行:普通换行,用于区分请求头和请求体
请求体:只有POST提交方式才有请求体,用于显示提交参数
请求的方式
只有POST请求方式存在请求体,GET请求方式没有请求体
get提交的参数在请求行中,post提交的参数在请求体中
响应的组成部分
响应行:请求方式 HTTP/版本号 状态码 状态描述
常见状态码
状态码 | 说明 |
---|---|
200 | 一切OK |
302/307 | 请求重定向,两次请求,地址栏发生变化 |
304 | 请求资源未发生变化,使用缓存 |
404 | 请求资源未找到 |
500 | 服务器错误 |
响应头
名称 | 说明 |
---|---|
Location | 请求重定向的地址,常与302,307配合使用 |
Server | 服务器相关信息 |
Content-Type | 响应正文的MIME类型 |
Content-Length | 响应正文的长度 |
Content-Disposition | 告知客户端浏览器,以下载的方式打开响应正文 |
Refresh | 定时刷新 |
Last-Modified | 服务器资源的最后修改时间 |
Set-Cookie | 会话管理相关,非常的重要 |
Expires:-1 | 服务器资源到客户端浏览器后的缓存时间 |
Catch-Control:no-catch | 不要缓存 |
响应空行:普通换行,用于区分响应头和响应体
响应体:将资源文件发送给客户端浏览器进行解析
发布静态资源
创建一个Java WEB项目
将静态页面所需资源导入到项目的web目录下
修改web.xml配置文件,修改默认主页
<welcome-file-list>
<welcome-file>/路径/文件名.htmlwelcome-file>
welcome-file-list>
将项目部署到tomcat中
启动tomcat服务
打开浏览器查看页面
发布动态资源
创建一个JavaWEB项目
将静态页面所需资源导入到项目的web目录下
修改web.xml配置文件,修改默认主页
在项目的src路径下编写一个类,实现Servlet接口
重写service方法,输出一句话即可
修改web.xml配置文件,配置servlet相关资源
<servlet>
<servlet-name>自定义名称servlet-name>
<servlet-class>java全类名(包名.类名)servlet-class>
servlet>
<servlet-mapping>
<servlet-name>和声明中的名称保持一致servlet-name>
<url-pattern>/访问路径(浏览器地址栏要输入的访问路径)url-pattern>
servlet-mapping>
将项目部署到tomcat中
启动tomcat服务
打开浏览器测试功能
执行流程
关系视图
出生对应的是
init
方法
活着对应的是service
方法(doGet
和doPost
方法)
死亡对应的是destroy
方法
结论: Servlet对象只会创建一次,销毁一次。所以Servlet对象只有一个实例。如果一个对象实例在应用中是唯一的存在,那么就称他为单例模式
结论: 一个浏览器代表一个线程,多个浏览器代表多个线程。按理说应该是每个浏览器查看的都是自己的信息。但结果浏览器中数据混乱。因此,我们可以认为Servlet是线程不安全的!
解决: 定义类成员要谨慎。如果是共用的,并且只会在初始化时赋值,其它时间都是获取的话,那么是没问题的。如果不是共用的,或者每次使用都有可能对其赋值,那就要考虑线程安全的问题了,可以将其定义到doGet或doPost方法内或者使用同步功能即可
具体名称的方式。访问的资源路径必须和映射配置完全相同 【常用】
<servlet>
<servlet-name>Demoservlet-name>
<servlet-class>study.servlet.Demoservlet-class>
servlet>
<servlet-mapping>
<servlet-name>Demoservlet-name>
<url-pattern>/Demourl-pattern>
servlet-mapping>
/
开头 + 通配符的方式。只要符合目录结构即可,不用考虑结尾是什么
<servlet>
<servlet-name>Demo2servlet-name>
<servlet-class>study.servlet.Demo2servlet-class>
servlet>
<servlet-mapping>
<servlet-name>Demo2servlet-name>
<url-pattern>/Demo2/*url-pattern>
servlet-mapping>
通配符 + 固定格式结尾的方式。只要符合固定结尾格式即可,不用考虑前面的路径
<servlet>
<servlet-name>Demo2servlet-name>
<servlet-class>study.servlet.Demo2servlet-class>
servlet>
<servlet-mapping>
<servlet-name>Demo2servlet-name>
<url-pattern>*.testurl-pattern>
servlet-mapping>
注意: 优先级问题。越是具体的优先级越高,越是模糊的 优先级越低。第一种 > 第二种 > 第三种
多路径映射
/
+ 通配符)package study.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class Demo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取浏览器路径
String requestURI = req.getRequestURI();
// 分隔路径
String path = requestURI.substring(requestURI.lastIndexOf("/"));
// 路径判断,区分价格
if(path.equals("/vip")){
System.out.println("100元");
}else if(path.equals("/vvip")){
System.out.println("200元");
}else System.out.println("300元");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
标签中,添加
标签1
/
。我们在发送请求时,首先会在我们项目中的web.xml 中查找映射配置,找到则执行。但是当找不到对应的Servlet 路径时,就去找默认的 Servlet ,由默认Servlet 处理。所以,一切都是Servlet
标签中,通过
标签来配置。有两个子标签
:代表初始化参数的key
:代表初始化参数的value<servlet>
<servlet-name>servletConfigDemoservlet-name>
<servlet-class>study.servlet.servletConfigDemoservlet-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
<init-param>
<param-name>descparam-name>
<param-value>This is ServletConfigparam-value>
init-param>
servlet>
返回值 | 方法名 | 说明 |
---|---|---|
String | getInitParameter(String name) | 根据参数名称获取参数的值 |
Enumeration | getInitParameterNames() | 获取所有参数名称的枚举 |
String | getServletName() | 获取Servlet的名称 |
ServletContext | getServletContext() | 获取ServletContext对象 |
通过init方法,来对ServletConfig对象进行赋值
private ServletConfig config;
public void init(ServletConfig config) throws ServletException{
this.config = config;
}
枚举项遍历
Enumeration<String> keys = config.getInitParameterNames();
while(keys.hasMoreElements()){
String key = keys.nextElement();
String value = config.getInitParameter(key);
System.out.println(key + "--" + value);
}
// ServletConfigDemo测试代码
package study.servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
public class ServletConfigDemo extends HttpServlet {
private ServletConfig config;
// 通过init方法对config赋值,获取ServletConfig对象
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 根据name获取value
String encoding = config.getInitParameter("encoding");
System.out.println("encoding:" + encoding);
// 获取所有name并遍历
Enumeration<String> names = config.getInitParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = config.getInitParameter(name);
System.out.println(name + "---" + value);
}
// 获取Servlet-name
String sname = config.getServletName();
System.out.println("Servlet-name:" + sname);
// 获取ServletContext对象
ServletContext servletContext = config.getServletContext();
System.out.println(servletContext);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
标签中,通过
标签来配置。有两个子标签
:代表全局初始化参数的key
:代表全局初始化参数的value<context-param>
<param-name>globalencodingparam-name>
<param-value>UTF-8param-value>
context-param>
<context-param>
<param-name>globaldescparam-name>
<param-value>This is ServletContextparam-value>
context-param>
返回值 | 方法名 | 说明 |
---|---|---|
String | getInitParameter(String name) | 根据名称获取全局配置的参数 |
String | getContextPath() | 获取当前应用的访问虚拟目录 |
String | getRealPath(String path) | 根据虚拟目录获取应用部署的磁盘绝对路径 |
HttpServlet
类继承自GenericServlet
类
GenericServlet
类中有getServletContext
方法,可以直接获取ServletContext
对象
返回值 | 方法名 | 说明 |
---|---|---|
void | setAttribute(String name, Object value) | 向应用域对象中存储数据 |
Object | getAttribute(String name) | 通过名称获取应用域对象中的数据 |
void | removeAttribute(String name) | 通过名称移除应用域对象中的数据 |
package study.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
public class ServletContextDemo extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = req.getServletContext();
Enumeration<String> names = servletContext.getInitParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = servletContext.getInitParameter(name);
System.out.println(name + "====" + value);
}
resp.setContentType("text/html;charset=UTF-8");
String contextPath = servletContext.getContextPath();
String realPath = servletContext.getRealPath(contextPath);
PrintWriter pw = resp.getWriter();
pw.write("虚拟目录为:" + contextPath + "
");
pw.write("真实目录为:" + realPath);
servletContext.setAttribute("use","lisi");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
Servlet3.0 规范
实现步骤
@WebServlet("/servletDemo")
public class ServletDemo extends HttpServlet{
}
步骤
定义一个类,继承HttpServlet
重写 doGet 和 doPost方法
定义一个类,实现ServletContainerInitializer接口
在src 目录下创建一个META-INF的包
在 META-INF 包下创建一个services 的包
在 services 包下创建一个 javax.servlet.ServletContainerInitializer 的文件
文件中的内容为容器实现类的全类名
在容器实现类中的 onStartup 方法中完成注册 Servlet
public void onStartup(Set<Class<?>> set, ServletContext servletContext){
// 1.创建ServletDemo类的对象
ServletDemo servletDemo = new ServletDemo();
// 2. 在ServletContext 对象中添加Servlet,并得到Servlet的动态配置对象
ServletRegistration.Dynamic registration = servletContext.addServlet("ServletDemo", servletDemo);
// 3. 配置Servlet
registration.addMapping("/servletDemo"); // 映射访问资源的路径
registration.setLoadOnStartup(1); // 设置Servlet加载时机
}
部署并启动项目
通过浏览器测试
步骤
获取表单数据
req.getParameter(name值)
:就可以通过HttpServletRequest 对象中的方法 通过表单的name属性获取到对应的表单数据响应数据
PrintWriter pw = resp.getWriter()
:通过 HttpServletResponse 对象中的方法获取输出流对象
pw.println("Save Success")
:将指定内容响应到浏览器中
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加学生title>
head>
<body>
<form action="/add" method="get">
姓名:<input type="text" name="username"> <br>
年龄:<input type="number" name="age"> <br>
成绩:<input type="number" name="score"> <br>
<button type="submit">添加button>
form>
body>
html>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<welcome-file-list>
<welcome-file>/studentAdd.htmlwelcome-file>
welcome-file-list>
<servlet>
<servlet-name>StudentServletservlet-name>
<servlet-class>studentServlet.addservlet-class>
servlet>
<servlet-mapping>
<servlet-name>StudentServletservlet-name>
<url-pattern>/addurl-pattern>
servlet-mapping>
web-app>
// add.java
package studentServlet;
import studentServlet.bean.Student;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class add extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取对应表单内容
String username = req.getParameter("username");
String age = req.getParameter("age");
String score = req.getParameter("score");
// 封装学生对象
Student stu = new Student(username, Integer.parseInt(age), Integer.parseInt(score));
// 保存到本地文件
BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\Java\\code\\StudentServlet\\stu.txt",true));
bw.write(stu.getUsername() + "," + stu.getAge() + "," + stu.getScore());
bw.newLine();
bw.close();
// 响应给浏览器
resp.setContentType("text/html;charset=UTF-8");
PrintWriter pw = resp.getWriter();
pw.println("添加成功,将在3秒后跳转到首页!!!");
resp.setHeader("Refresh","3;url=/index.html");
pw.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
请求: 获取资源。在BS架构中,就是客户端浏览器向服务端发出询问。
请求对象: 就是在项目中用于发送请求的对象(ServletRequest
和HttpServletRequest
)
ServletRequest 和 HttpServletRequest 都是接口,但是Tomcat 服务器会帮我们处理好实现类的赋值等工作,我们不需要关心这些
返回值 | 方法名 | 说明 |
---|---|---|
String | getContextPath() | 获取虚拟目录名称 |
String | getServletPath() | 获取Servlet映射路径 |
String | getRemoteAddr() | 获取访问者ip地址 |
String | getQueryString() | 获取请求的消息数据 |
String | getRequestURI() | 获取统一资源标识符 |
StringBuffer | getRequestURL() | 获取统一资源定位符 |
package study.servlet;
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;
import java.io.PrintWriter;
@WebServlet("/request")
public class RequestDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String contextPath = req.getContextPath();
String servletPath = req.getServletPath();
String remoteAddr = req.getRemoteAddr();
String queryString = req.getQueryString();
String requestURI = req.getRequestURI();
StringBuffer requestURL = req.getRequestURL();
PrintWriter pw = resp.getWriter();
pw.println("contextPath= " + contextPath);
pw.println("servletPath= " + servletPath);
pw.println("remoteAddr= " + remoteAddr);
pw.println("queryString= " + queryString);
pw.println("requestURI= " + requestURI);
pw.println("requestURL= " + requestURL);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
返回值 | 方法名 | 说明 |
---|---|---|
String | getHeader(String name) | 根据请求头名称获取一个值 |
Enumeration | getHeaders(String name) | 根据请求头名称获取多个值 |
Enumeration | getHeaderNames() | 获取所有请求头名称 |
package study.servlet;
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;
import java.io.PrintWriter;
import java.util.Enumeration;
@WebServlet("/request2")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req.getHeader("host"));
System.out.println(req.getHeader("user-agent"));
Enumeration<String> headers = req.getHeaders("user-agent");
while(headers.hasMoreElements()){
String s = headers.nextElement();
System.out.println(s);
}
System.out.println("===============");
Enumeration<String> names = req.getHeaderNames();
while(names.hasMoreElements()){
System.out.println(names.nextElement());
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
返回值 | 方法名 | 说明 |
---|---|---|
String | getParameter(String name) | 根据名称获取数据 |
String[] | getParameterValues(String name) | 根据名称获取所有数据 |
Enumeration | getParameterNames() | 获取所有名称 |
Map |
getParameterMap() | 获取所有参数的键值对 |
package study.servlet;
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 javax.swing.*;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
@WebServlet("/request3")
public class RequestDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req.getParameter("username"));
System.out.println("================");
for (String hobby : req.getParameterValues("hobby")) {
System.out.println(hobby);
}
System.out.println("===================");
Enumeration<String> parameterNames = req.getParameterNames();
while(parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
for (String value : req.getParameterValues(name)) {
System.out.println(value);
}
}
System.out.println("===================");
Map<String, String[]> parameterMap = req.getParameterMap();
for (String key : parameterMap.keySet()) {
String[] value = parameterMap.get(key);
System.out.println(key + " === " + value);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
获取请求参数并封装对象
PropertyDescriptor
(根据名称获取到对象中对应的get和set方法)beanutils
工具类,populate
方法package study.servlet;
import study.servlet.bean.Student;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/*
* 封装对象------反射方式
* */
public class RequestDemo5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取所有数据
Map<String, String[]> map = req.getParameterMap();
// 封装学生对象
Student stu = new Student();
// 遍历集合
for(String name : map.keySet()){
String[] value = map.get(name);
try {
// 获取Student对象的属性描述器
PropertyDescriptor pd = new PropertyDescriptor(name, stu.getClass());
// 获取对应的set方法
Method writeMethod = pd.getWriteMethod();
// 执行方法
writeMethod.invoke(stu,value);
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
package study.servlet;
import org.apache.commons.beanutils.BeanUtils;
import study.servlet.bean.Student;
/*
* 封装对象------工具类方式
需要导包:BeanUtils
* */
public class RequestDemo6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取所有数据
Map<String, String[]> map = req.getParameterMap();
// 封装学生对象
Student stu = new Student();
try {
BeanUtils.populate(stu, map);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
返回值 | 方法名 | 说明 |
---|---|---|
BufferedReader | getReader() | 获取字符输入流 |
ServletInputStream | getInputStream() | 获取字节输入流 |
用IO流获取请求信息时,不支持get方式,只支持post提交方式
获得到的流对象都不是自己new出来的,不需要close释放资源,会由请求对象处理并释放
package study.servlet;
import org.apache.commons.beanutils.BeanUtils;
import study.servlet.bean.Student;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Map;
/*
* 流对象获取数据
* */
@WebServlet("/request7")
public class RequestDemo7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 字符流(必须是post请求方式)
BufferedReader br = req.getReader();
String line;
while((line = br.readLine()) != null) System.out.println(line);
// 字节流
ServletInputStream is = req.getInputStream();
byte[] arr = new byte[1024];
int len;
while((len = is.read(arr)) != -1){
System.out.println(new String(arr, 0, len));
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
package study.servlet;
/*
* 中文乱码问题
* */
@WebServlet("/request8")
public class RequestDemo8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String name = req.getParameter("name");
System.out.println(name);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
返回值 | 方法名 | 说明 |
---|---|---|
void | setAttribute(String name, Object value) | 向请求域对象中存储数据 |
Object | getAttribute(String name) | 通过名称获取请求域对象中的数据 |
void | removeAttribute(String name) | 通过名称移除请求域对象中的数据 |
返回值 | 方法名 | 说明 |
---|---|---|
RequestDispatcher | getRequestDispatcher(String name) | 获取请求调度对象 |
void | forward(ServletRequest req, ServletResponse resp) | 实现转发(用请求调度对象调用) |
package study.servlet.request;
/*
* 请求转发
* */
@WebServlet("/request9")
public class RequestDemo9 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置共享数据
req.setAttribute("name","张三");
// 获取请求调度对象
RequestDispatcher rd = req.getRequestDispatcher("/request10");
// 请求转发
rd.forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
package study.servlet.request;
/*
* 转发目的
* */
@WebServlet("/request10")
public class RequestDemo10 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取共享数据
System.out.println(req.getAttribute("name"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
返回值 | 方法名 | 说明 |
---|---|---|
RequestDispatcher | getRequestDispatcher(String name) | 获取请求调度对象 |
void | include(ServletRequest req, ServletResponse resp) | 实现包含 |
package study.servlet.request;
/*
* 请求包含
* */
@WebServlet("/request11")
public class RequestDemo11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置共享数据
req.setAttribute("name","张三");
// 获取请求调度对象
RequestDispatcher rd = req.getRequestDispatcher("/request10");
// 请求转发
rd.include(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
ServletResponse
(接口)HttpServletResponse
(继承自ServletResponse,基于http协议的接口)
和请求对象一样,不需要我们去写实现类,在Tomcat 服务器创建好,在执行
doGet
或者doPost
方法时,服务器会把相应的实现类对象传递
状态码 | 说明 |
---|---|
200 | 成功 |
302 | 重定向 |
304 | 请求资源未改变,使用缓存 |
400 | 请求错误,常见于请求参数错误 |
404 | 请求资源未找到 |
405 | 请求方式不支持 |
500 | 服务器错误 |
返回值 | 方法名 | 说明 |
---|---|---|
ServletOutputStream | getOutputStream() | 获取响应字节输出流对象 |
void | setContentType(“text/html;charset=UTF-8”) | 设置响应内容类型,解决中文乱码问题 |
步骤:
获取到的字节输出流对象不需要close释放,会由响应对象处理并释放
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取字节输出流
ServletOutputStream os = resp.getOutputStream();
String s = "字节输出流响应消息";
os.write(s.getBytes());
}
未出现乱码问题:浏览器默认gbk编码,idea默认UTF-8编码;但是
getBytes
方法在将字符串转为字节数组时,如果不传递参数指定编码,就会根据当前系统平台默认编码进行转换,Windows系统默认编码为gbk,和浏览器一致,故未出现乱码
// 统一编码格式为UTF-8并解决乱码问题
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置相应内容类型,并设置编码格式(告知浏览器应该采用的编码格式)
resp.setContentType("text/html;charset=UTF-8");
// 获取字节输出流
ServletOutputStream os = resp.getOutputStream();
String s = "字节输出流响应消息";
os.write(s.getBytes("UTF-8"));
}
返回值 | 方法名 | 说明 |
---|---|---|
PrintWriter | getWriter() | 获取响应字符输出流对象 |
void | setContentType(“text/html;charset=UTF-8”) | 设置响应内容类型,解决中文乱码问题 |
步骤和上面字节流一样,同样不需要自己close释放资源
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置相应内容类型,并设置编码格式(告知浏览器应该采用的编码格式)
resp.setContentType("text/html;charset=UTF-8");
// 获取字符输出流对象
PrintWriter pw = resp.getWriter();
pw.write("字符输出流响应消息");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String realPath = getServletContext().getRealPath("/img/tx.png");
// 创建字节输入流对象,关联图片
BufferedInputStream is = new BufferedInputStream(new FileInputStream(realPath));
// 获取字节输出流对象,响应图片
ServletOutputStream os = resp.getOutputStream();
// 循环读写
byte[] arr = new byte[1024];
int len;
while((len = is.read(arr)) != -1){
os.write(arr, 0, len);
}
// 释放资源
is.close();
}
返回值 | 方法名 | 说明 |
---|---|---|
void | setDateHeader(String name,long time) | 设置消息头添加缓存 |
例:
resp.setDateHeader("Expires",System.currentTimeMillis() + 1*60*60*1000);
设置一个小时缓存时间
Expires 就是过期的意思
时间单位为毫秒,1秒等于1000毫秒
返回值 | 方法名 | 说明 |
---|---|---|
void | setHeader(String name,String value) | 设置消息头定时刷新 |
例:
resp.setHeader("Refresh","3;URL=要跳转的路径")
单位为秒
resp.setStatus(302);
resp.setHeader("location","/response/responseDemo")
返回值 | 方法名 | 说明 |
---|---|---|
void | sendRedirect(String name) | 设置重定向 |
resp.setHeader("Content-Type","application/octet-stream")
resp.setHeader("Content-Disposition","attachment;filename=下载的文件名称")
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 创建字节输入流,关联读取的文件
String realPath = req.getServletContext().getRealPath("/img/tx.png");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
// 设置响应消息头支持的类型
resp.setHeader("Content-Type", "application/octet-stream");
// 设置响应消息头以下载方式打开资源
resp.setHeader("Content-Disposition","attachment;filename=file.png");
// 通过响应对象获取字节输出流对象
ServletOutputStream os = resp.getOutputStream();
int len;
byte[] arr = new byte[1024];
while((len = bis.read(arr)) != -1){
os.write(arr, 0, len);
}
// 释放资源
bis.close();
}
// list.java
package studentServlet;
import studentServlet.bean.Student;
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.*;
import java.util.ArrayList;
@WebServlet("/list")
public class list extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BufferedReader br = new BufferedReader(new FileReader("E:\\Java\\code\\StudentServlet\\stu.txt"));
ArrayList<Student> list = new ArrayList<>();
String str;
while((str = br.readLine()) != null){
String[] split = str.split(",");
Student stu = new Student(split[0], Integer.parseInt(split[1]), Integer.parseInt(split[2]));
list.add(stu);
}
resp.setContentType("text/html;charset=UTF-8");
PrintWriter pw = resp.getWriter();
for(Student student : list){
pw.write(student.getUsername() + "," + student.getAge() + "," + student.getScore());
pw.write("
");
}
br.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>学生信息管理系统title>
head>
<body>
<h1>学生信息管理系统h1>
<hr>
<a href="/studentAdd.html">添加学生信息a>
<a href="/list">查看学生信息a>
body>
html>
HttpServletResponse.addCookie(Cookie对象)
HttpServletRequest.getCookie()
属性名 | 作用 | 是否重要 |
---|---|---|
name | Cookie的名称 | 必须属性 |
value | Cookie的值(不支持中文) | 必须属性 |
path | Cookie的路径 | 重要 |
domain | Cookie的域名 | 重要 |
maxAge | Cookie的存活时间(s) | 重要 |
version | Cookie的版本号 | 不重要 |
comment | Cookie的描述 | 不重要 |
方法名 | 作用 |
---|---|
Cookie(String name, String value) | 构造方法创建对象 |
属性对应的set和get方法 | 赋值和获取值(name有final修饰,无set方法) |
void HttpServletResponse.addCookie(Cookie cookie)
Cookie[] HttpServletRequest.getCookies()
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 通过响应对象写出一个提示信息
resp.setContentType("text/html;charset=UTF-8");
PrintWriter pw = resp.getWriter();
pw.write("您的最后访问时间为:");
pw.write("
");
// 创建Cookie对象,指定name和value
Cookie cookie = new Cookie("time", System.currentTimeMillis()+"");
// 设置Cookie最大存活时间
cookie.setMaxAge(3600);
// 通过响应对象将Cookie对象添加到客户端
resp.addCookie(cookie);
// 通过请求对象获取Cookie对象
Cookie[] cookies = req.getCookies();
// 将Cookie对象中的访问时间写出
for(Cookie ck : cookies){
if("time".equals(ck.getName())){
String value = ck.getValue();
// 格式化时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String lastTime = sdf.format(new Date(Long.parseLong(value)));
pw.write(lastTime);
}
}
}
setMaxAge()
方法接收数字setPath()
方法设置指定路径只不过在客户端保存的是一个特殊标识,而共享的数据保存到了服务器端的内存对象中。
每次请求时,会将特殊标识带到服务器端,根据这个标识来找到对应的内存空间,从而实现数据共享
是Servlet规范中四大域对象之一的会话域对象
域对象 | 功能 | 作用 |
---|---|---|
ServletContext | 应用域 | 在整个应用之间实现数据共享 |
ServletRequest | 请求域 | 在当前的请求或请求转发之间实现数据共享 |
HttpSession | 会话域 | 在当前会话范围之间实现数据共享 |
返回值 | 方法名 | 说明 |
---|---|---|
void | setAttribute(String name, Object value) | 设置共享数据 |
Object | getAttribute(String name) | 获取共享数据 |
void | removeAttribute(String name) | 移除共享数据 |
String | getId() | 获取唯一标识名称 |
void | Invalidate() | 让session立即失效 |
返回值 | 方法名 | 说明 |
---|---|---|
HttpSession | getSession() | 获取HttpSession对象 |
HttpSession | getSession(boolean create) | 获取HttpSession对象,未获取到是否自动创建(默认true) |
// Session01
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 在第一个 Servlet 中获取请求的用户名
String username = req.getParameter("username");
// 获取 HttpSession 对象
HttpSession session = req.getSession();
// 将用户名设置到共享数据中
session.setAttribute("username",username);
}
// session02
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 在第二个 Servlet 中获取 HttpSession 对象
HttpSession session = req.getSession();
// 获取共享数据用户名
Object username = session.getAttribute("username");
// 将获取到的用户名响应给客户端浏览器
PrintWriter pw = resp.getWriter();
pw.write(username+"");
}
resp.enconeURL
方法实现url重写(地址栏拼接jsessionid)【了解】HttpSession 的序列化由服务器自动完成,我们无需关心
类别 | 使用场景 |
---|---|
HTML | 开发静态资源,无法添加动态资源 |
CSS | 美化页面 |
JavaScript | 给网页添加一些动态效果 |
Servlet | 编写Java 代码,实现后台功能处理 |
JSP | 包含了显示页面技术,也具备Java代码功能 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
第一个jsp
文件内容介绍
<%-- 注释的内容 --%>
<% Java代码 %>
<%=表达式%>
<%! 声明变量或方法 %>
System.out.println()
:普通输出语句,输出在控制台上
out.println()
:JspWriter 对象,将内容输出在浏览器页面上,不会自动换行
<%="要输出的内容"%>
就相当于out.println("要输出的内容")
在声明中,如果加!
,代表声明的是成员变量;如果不加!
,代表声明的是局部变量;如果是声明方法,就必须加!
<%@ page 属性名=属性值 属性名=属性值... %>
属性名 | 作用 |
---|---|
contentType | 响应正文支持的类型和设置编码格式 |
language | 使用的语言,默认是Java |
errorPage | 当前页面出现异常后跳转的页面 |
isErrorPage | 是否抓住异常,如果为true则页面中就可以使用异常对象,默认是false |
import | 导包 import= “java.util.ArrayList” |
session | 是否创建 HttpSession 对象,默认是true |
buffer | 设定 JspWriter 输出jsp内容缓存的大小,默认8kb |
pageEncoding | 翻译jsp时所用的编码格式 |
isEIgnored | 是否忽略EL表达式,默认是false |
<%@ include file=包含的页面 %>
<%@ taglib uri=标签库的地址 prefix=前缀名称 %>
隐式对象名称 | 代表实际对象 |
---|---|
request | javax.servlet.http.HttpServletRequest |
response | javax.servlet.http.HttpServletResponse |
session | javax.servlet.http.HttpSession |
application | javax.servlet.ServletContext |
page | java.lang.Object |
config | javax.servlet.ServletConfig |
exception | java.lang.Throwable |
out | javax.servlet.jsp.JspWriter |
pageContext | javax.servlet.jsp.PageContext |
四大域对象
域对象名称 | 范围 | 级别 | 备注 |
---|---|---|---|
PageContext | 页面范围 | 最小,只能在当前页面使用 | 因范围太小,开发中用的很少 |
ServletRequest | 请求范围 | 一次请求或当前请求转发用 | 请求转发之后,再次转发时请求域丢失 |
HttpSession | 会话范围 | 多次请求数据共享时使用 | 多次请求共享数据,但不同的客户端不能共享 |
ServletContext | 应用范围 | 最大,整个应用都可以使用 | 尽量少用,如果对数据有修改需要做同步处理 |
登录功能
<%-- login.jsp --%>
<%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/24
Time: 20:25
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
登录
学生信息管理系统--登录
// login.java
package studentServlet;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String username = req.getParameter("username");
String password = req.getParameter("password");
resp.setContentType("text/html;charset=UTF-8");
if(null == username || "".equals(username)){
resp.getWriter().write("账号不能为空,请重新输入(2s后返回...)");
resp.setHeader("Refresh","2;URL=/login.jsp");
}else{
if("admin".equals(username) && "abc123".equals(password)){
session.setAttribute("username",username);
resp.sendRedirect("/index.jsp");
}else{
resp.getWriter().write("账号密码不正确,请重新输入(2s后返回...)");
resp.setHeader("Refresh","2;URL=/login.jsp");
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
<%-- index.jsp --%>
<%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/24
Time: 19:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
学生信息管理系统
学生信息管理系统
<% if(session.getAttribute("username") == null){ %>
请登录
<% } else { %>
添加学生信息
查看学生信息
<% } %>
<%-- list.jsp --%>
<%@ page import="java.util.ArrayList" %>
<%@ page import="studentServlet.bean.Student" %>
<%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/24
Time: 20:30
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
查看学生
姓名
年龄
成绩
<%
ArrayList students = (ArrayList) session.getAttribute("students");
for(Student stu : students){
%>
<%=stu.getUsername()%>
<%=stu.getAge()%>
<%=stu.getScore()%>
<% } %>
// list.java
package studentServlet;
import studentServlet.bean.Student;
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.*;
import java.util.ArrayList;
@WebServlet("/list")
public class list extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BufferedReader br = new BufferedReader(new FileReader("E:\\Java\\code\\StudentServlet\\stu.txt"));
ArrayList<Student> list = new ArrayList<>();
String str;
while((str = br.readLine()) != null){
String[] split = str.split(",");
Student stu = new Student(split[0], Integer.parseInt(split[1]), Integer.parseInt(split[2]));
list.add(stu);
}
req.getSession().setAttribute("students",list);
resp.sendRedirect("/list.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
${表达式内容}
<%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/25
Time: 10:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL表达式快速入门</title>
</head>
<body>
<% request.setAttribute("username","zhangsan"); %>
<%--java代码块--%>
<% out.println(request.getAttribute("username")); %><br>
<%-- jsp表达式 --%>
<%=request.getAttribute("username")%><br>
<%--EL表达式--%>
${username}
</body>
</html>
${数据名}
${对象名.属性名}
${数组名[索引]}
${集合[索引]}
${集合.key值}
:获取key对应的value<%@ page import="study.servlet.bean.Student" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.HashMap" %><%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/25
Time: 10:10
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL表达式获取数据</title>
</head>
<body>
<%
Student stu = new Student("张三",23);
int[] arr = {1,2,3,4,5};
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
HashMap<String,String> map = new HashMap<>();
map.put("user","zhangsan");
map.put("age","28");
pageContext.setAttribute("stu",stu);
pageContext.setAttribute("arr",arr);
pageContext.setAttribute("list",list);
pageContext.setAttribute("map",map);
%>
<%--EL表达式获取数据--%>
${stu.name}<br> <%--获取自定义对象类型的数据--%>
${arr[2]}<br> <%--获取数组类型的数据--%>
${list[1]}<br> <%--获取List 集合类型的数据--%>
${map.user} <%--获取 Map 集合类型的数据--%>
</body>
</html>
使用细节
运算符 | 作用 | 示例 | 结果 |
---|---|---|---|
== 或 eq | 等于 | ${5 == 5} 或 ${5 eq 5} | true |
!= 或 ne | 不等于 | ${5 != 5} 或 ${5 ne 5} | false |
< 或 lt | 小于 | ${3 < 5} 或 ${3 lt 5} | true |
> 或 gt | 大于 | ${3 > 5} 或 ${3 gt 5} | false |
<= 或 le | 小于等于 | ${3 <= 5} 或 ${3 le 5} | true |
>= 或 ge | 大于等于 | ${3 >= 5} 或 ${3 ge 5} | false |
运算符 | 作用 | 示例 | 结果 |
---|---|---|---|
&& 或 and | 并且 | ${A && B} 或 ${A and B} | true / false |
|| 或 or | 或者 | ${A || B} 或 ${A or B} | true / false |
! 或 not | 取反 | ${!A} 或 ${not A} | true / false |
运算符 | 作用 |
---|---|
empty | 1. 判断对象是否为null 2. 判断字符串是否为空字符串 3. 判断容器元素是否为0 |
条件 ? 表达式1 : 表达式2 | 三元运算符 |
隐式对象名称 | 对应JSP隐式对象 | 说明 |
---|---|---|
pageContext | pageContext | 功能完全相同 |
applicationScope | 无 | 操作应用域对象数据 |
sessionScope | 无 | 操作会话域对象数据 |
requestScope | 无 | 操作请求域对象数据 |
pageScope | 无 | 操作页面域对象数据 |
header | 无 | 获取请求头数据 |
headerValues | 无 | 获取请求头数据(多个值) |
param | 无 | 获取请求参数数据 |
paramValues | 无 | 获取请求参数数据(多个值) |
initParam | 无 | 获取全局配置参数数据 |
cookie | 无 | 获取Cookie对象 |
<%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/25
Time: 10:21
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
隐式对象
<%--pageContext对象,可以获取其他三个域对象和JSP中八个隐式对象--%>
${pageContext.request.requestURL}
<%--applicationScope sessionScope requestScope pageScope 操作四大域对象中的数据--%>
${pageContext.setAttribute("username","zhangsan")}
${pageScope.username}
<%--header headerValues 获取请求头数据--%>
${header["connection"]}
${headerValues["connection"][0]}
${header.connection}
<%--param paramValues 获取请求参数数据--%>
${param.username}
${paramValues.hobby[0]}
<%--initParam 获取全局配置参数--%>
${initParam.globaldesc}
<%--cookie 获取cookie信息--%>
${cookie} <%--直接写cookie获取到的是一个map集合--%>
${cookie.JSESSIONID.value}
组成 | 作用 | 说明 |
---|---|---|
core | 核心标签库 | 通用的逻辑处理 |
fmt | 国际化 | 不同地域显示不同语言 |
functions | EL 函数 | EL 表达式可以使用的方法 |
sql | 操作数据库 | 了解 |
xml | 操作XML | 了解 |
标签名称 | 功能分类 | 属性 | 作用 |
---|---|---|---|
<标签名:if> | 流程控制 | 核心标签库 | 用于条件判断 |
<标签名:choose> <标签名:when> <标签名:otherwise> |
流程控制 | 核心标签库 | 用于多条件判断 |
<标签名:forEach> | 迭代遍历 | 核心标签库 | 用于循环遍历 |
使用步骤
<%@ page import="java.util.ArrayList" %><%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/25
Time: 10:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--导入核心库并起标签名--%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
JSTL【JSP标准标签库】
${pageContext.setAttribute("score","A")}
<%--对成绩进行判断--%>
优秀
<%--多条件判断--%>
优秀
良好
及格
较差
成绩非法
<%--循环遍历--%>
<%
ArrayList list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
pageContext.setAttribute("list",list);
%>
${str}
返回值 | 方法名 | 作用 |
---|---|---|
void | init(FilterConfig config) | 初始化方法 |
void | doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | 对请求资源和响应资源过滤 |
void | destroy() | 销毁方法 |
返回值 | 方法名 | 说明 |
---|---|---|
void | doFilter(ServletRequest request, ServletResponse response) | 放行方法 |
如果有多个过滤器,在第一个过滤器中调用下一个过滤器,依此类推。直到到达最终访问资源。
如果只有一个过滤器,放行时,就会直接到达最终访问资源
package study.servlet.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/filter01")
public class filter 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("filter执行了");
// 处理乱码
servletResponse.setContentType("text/html;charset=UTF-8");
// 放行
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {}
}
@WebFilter(拦截路径)
<filter>
<filter-name>demofilter-name>
<filter-class>全类名filter-class>
filter>
<filter-mapping>
<filter-name>demofilter-name>
<url-pattern>/拦截路径url-pattern>
filter-mapping>
FilterConfig 是一个接口。代表过滤器的配置对象,可以加载一些初始化参数
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
String | getFilterName() | 获取过滤器对象名称 |
String | getInitParameter(String name) | 根据name获取 value |
Enumeration |
getInitParameterNames() | 获取所有参数的key |
ServletContext | getServletContext() | 获取应用上下文对象 |
<filter>
<filter-name>demofilter-name>
<filter-class>全类名filter-class>
<init-param>
<param-name>usernameparam-name>
<param-value>zhangsanparam-value>
init-param>
filter>
Filter 过滤器默认拦截的是请求,但是在实际开发中,我们还有请求转发和请求包含,以及由服务器触发调用的全局错误页面。默认情况下过滤器是不参与过滤的,要想使用,就需要我们配置
拦截方式
<filter>
<filter-name>demofilter-name>
<filter-class>全类名filter-class>
filter>
<filter-mapping>
<filter-name>demofilter-name>
<url-pattern>/拦截路径url-pattern>
<dispatcher>REQUESTdispatcher>
<dispatcher>FORWARDdispatcher>
<dispatcher>INCLUDEdispatcher>
<dispatcher>ERRORdispatcher>
<dispatcher>ASYNCdispatcher>
filter-mapping>
REQUEST:默认值,浏览器直接请求的资源会被过滤器拦截
FORWARD:转发访问资源会被过滤器拦截
INCLUDE:包含访问资源
ERROR:全局错误跳转资源
ASYNC:异步访问资源
全局错误页面配置
<error-page>
<exception-type>java.lang.exceptionexception-type>
<location>/error.jsplocation>
error-page>
<error-page>
<error-code>404error-code>
<location>/error.jsplocation>
error-page>
监听对象的创建和销毁的监听器
ServletContextListener:用于监听 ServletContext 对象的创建和销毁
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | contextInitialized(ServletContextEvent sce) | 对象创建时执行该方法 |
void | contextDestroyed(ServletContextEvent sce) | 对象销毁时执行该方法 |
参数:ServletContextEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletContext
真正的事件指的是创建或销毁 ServletContext 对象的操作
HttpSessionListener:用于监听 HttpSession 对象的创建和销毁
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | sessionCreated(HttpSessionEvent se) | 对象创建时执行该方法 |
void | sessionDestroyed(HttpSessionEvent se) | 对象销毁时执行该方法 |
参数:HttpSessionEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是创建或销毁 HttpSession 对象的操作
ServletRequestListener:用于监听 ServletRequest 对象的创建和销毁
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | requestInitialized(ServletRequestEvent sre) | 对象创建时执行该方法 |
void | requestDestroyed(ServletRequestEvent sre) | 对象销毁时执行该方法 |
参数:ServletRequestEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletRequest
真正的事件指的是创建或销毁 ServletRequest 对象的操作
监听域对象属性变化的监听器
ServletContextAttributeListener:用于监听 ServletContext 应用域中属性的变化
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | attributeAdded(ServletContextAttributeEvent scae) | 域中添加属性时执行该方法 |
void | attributeRemoved(ServletContextAttributeEvent scae) | 域中移除属性时执行该方法 |
void | attributeReplaced(ServletContextAttributeEvent scae) | 域中替换属性时执行该方法 |
参数:ServletContextAttributeEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletContext
真正的事件指的是添加、移除、替换应用域中属性的操作
HttpSessionAttributeListener:用于监听 HttpSession 会话域中属性的变化
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | attributeAdded(HttpSessionBindingEvent se) | 域中添加属性时执行该方法 |
void | attributeRemoved(HttpSessionBindingEvent se) | 域中移除属性时执行该方法 |
void | attributeReplaced(HttpSessionBindingEvent se) | 域中替换属性时执行该方法 |
参数:HttpSessionBindingEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是添加、移除、替换会话域中属性的操作
ServletRequestAttributeListener:用于监听 ServletRequest 请求域中属性的变化
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | attributeAdded(ServletRequestAttributeEvent srae) | 域中添加属性时执行该方法 |
void | attributeRemoved(ServletRequestAttributeEvent srae) | 域中移除属性时执行该方法 |
void | attributeReplaced(ServletRequestAttributeEvent srae) | 域中替换属性时执行该方法 |
参数:ServletRequestAttributeEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletRequest
真正的事件指的是添加、移除、替换请求域中属性的操作
监听会话相关的感知型监听器
感知型监听器:在定义好之后就可以直接使用,不需要再通过注解或xml文件进行配置
HttpSessionBindingListener:用于感知对象和会话域绑定的监听器
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | valueBound(HttpSessionBindingEvent event) | 数据添加到会话域中(绑定)时执行该方法 |
void | valueUnbound(HttpSessionBindingEvent event) | 数据从会话域中移除(解绑)时执行该方法 |
参数:HttpSessionBindingEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是添加、移除会话域中数据的操作
HttpSessionActivationListener:用于感知会话域对象钝化和活化的监听器
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | sessionWillPassivate(HttpSessionEvent se) | 会话域中数据钝化时执行该方法 |
void | sessionDidActivate(HttpSessionEvent se) | 会话域中数据活化时执行该方法 |
参数:HttpSessionEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是会话域中数据钝化、活化的操作
package study.servlet.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.annotation.WebServlet;
@WebServlet("/listener01")
@WebListener
public class listener01 implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("监听到了对象的创建");
ServletContext servletContext = servletContextEvent.getServletContext();
// 添加属性
servletContext.setAttribute("username","张三");
// 替换属性
servletContext.setAttribute("username","李四");
// 移除属性
servletContext.removeAttribute("username");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("监听到了对象的销毁");
}
}
package study.servlet.listener;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
@WebServlet("/listener02")
public class listener02 implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("监听到了属性的添加");
ServletContext servletContext = servletContextAttributeEvent.getServletContext();
Object username = servletContext.getAttribute("username");
System.out.println(username);
}
@Override
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("监听到了属性的移除");
ServletContext servletContext = servletContextAttributeEvent.getServletContext();
Object username = servletContext.getAttribute("username");
System.out.println(username);
}
@Override
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("监听到了属性的替换");
ServletContext servletContext = servletContextAttributeEvent.getServletContext();
Object username = servletContext.getAttribute("username");
System.out.println(username);
}
}
配置监听器
@WebListener
<listener>
<listener-class>监听器对象实现类的全路径listener-class>
listener>
使用过滤器实现所有资源的编码统一
package studentSystem.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 将请求和响应对象转换为和HTTP相关的HttpServletRequest和HttpServletResponse
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 设置编码格式
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 放行
filterChain.doFilter(request, response);
}
}
使用过滤器解决登录检查
注解配置过滤器时指定多个拦截路径
@WebFilter(value = {"/拦截路径一", "/拦截路径二", ...})
package studentSystem.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter(value = {"/add.jsp", "/list.jsp"})
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 将请求和响应对象转换为和HTTP相关的HttpServletRequest和HttpServletResponse
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 获取会话域对象中的数据
HttpSession session = request.getSession();
Object username = session.getAttribute("username");
Object password = session.getAttribute("password");
// 判断用户名
if("admin".equals(username) && "abc123".equals(password)){
filterChain.doFilter(request, response);
}else{
// 输出提示信息并设置定时刷新到登录页面
response.getWriter().write("您还未登录,请登录后再试。(2s后为您跳转到登录页面)");
response.setHeader("Refresh","2:URL=/login.jsp");
}
}
}
通过EL表达式和JSTL替换之前的Java代码块和JSP表达式
完整代码:https://github.com/HelloCode66/StudentSystem