Java Web从入门到实战

个人主页:Hello Code.
本文专栏:《Java Web从入门到实战》
篇幅较长,并未完结,后续内容会持续更新
本文后续也会分篇发布,方便大家阅读
如没有Java基础,请先前往《Java零基础指南》专栏学习相应知识
如有问题,欢迎指正,一起学习~~


文章目录

    • Linux
      • 初识Linux
      • Linux的安装和使用
        • Vmware
        • SecureCRT
        • 目录和文件
        • 时间同步
        • 克隆与快照
      • 系统与设置命令
        • 账号管理
        • 用户组
        • 系统管理相关命令
        • 进程相关命令
        • 目录管理
        • 文件基本属性
        • 综合案例
      • 文件管理
        • touch
        • vi/vim编辑器
        • 文件查看
        • echo命令
        • awk命令
        • 软连接
      • 压缩命令
        • 查找命令
        • gzip命令
        • gunzip命令
        • tar命令
        • zip命令
        • unzip命令
        • bzip2命令
      • 网络与磁盘管理
        • 网络管理
        • 磁盘管理
        • yum
        • rpm
      • shell
        • 初识shell
        • 注释和变量
        • 数组
        • 运算符
        • 选择语句
        • 循环语句
        • 函数
    • Nginx
        • 概述
        • 安装
        • 发布项目
    • JavaWeb核心
      • 企业开发简介
        • JavaEE规范
        • WEB概述
        • 系统结构
      • tomcat
        • 服务器
        • Tomcat
        • 基本使用
        • Java WEB项目
        • 配置文件
      • HTTP协议
        • 概述
        • 协议的请求
        • 协议的响应
      • 发布资源案例
        • Servlet介绍
      • Servlet
        • 概述
        • 执行过程
        • 实现方式
        • 生命周期
        • 线程安全问题
        • 映射方式
        • 创建时机
        • 默认Servlet
      • ServletConfig
        • 配置方式
        • 常用方法
      • ServletContext
        • 域对象
        • 配置方式
        • 常用方法
      • 注解开发
        • 自动注解开发
        • 手动创建容器(了解)
      • 学生管理系统1
      • 请求对象
        • 获取各种路径
        • 获取请求头
        • 获取请求参数信息
        • 流对象获取请求信息
        • 中文乱码问题
        • 请求域
        • 请求转发
        • 请求包含
      • 响应对象
        • 常见状态码
        • 字节流响应消息
        • 字符流响应消息
        • 响应图片
        • 设置缓存
        • 定时刷新
        • 请求重定向
        • 文件下载
      • 学生管理系统2
      • Cookie
        • 会话
        • 概述
        • Cookie属性
        • 方法
        • 练习
        • 注意事项
      • Session
        • 常用方法
        • 对象获取
        • 练习
        • 注意事项
      • JSP
        • 快速入门
        • 执行过程
        • 语法
        • 指令
        • 注意事项
        • MVC模型
      • 学生管理系统3
      • EL表达式
        • 快速入门
        • 获取数据
        • 注意事项
        • 运算符
        • 隐式对象
      • JSTL
        • 核心标签
      • Filter
        • 概述
        • FilterChain
        • 过滤器使用
        • 使用细节
        • 生命周期
        • FilterConfig
        • 五种拦截行为
      • Listener
        • 监听器
        • 监听器的使用
      • 学生管理系统优化
        • 解决乱码
        • 检查登录
        • 优化JSP页面
    • Mysql
    • JDBC
    • Mybatis
    • JavaScript
    • jQuery
    • AJAX
    • Vue + Element
    • Redis
    • Maven基础
    • Web项目实战-黑马页面

Linux

初识Linux

操作系统:管理计算机硬件软件资源的计算机程序,同时也是计算机系统的内核与基石。

主流操作系统

  • 桌面操作系统:Window系列、macOS、Linux
  • 服务器操作系统:Linux、Windows Server
  • 嵌入式操作系统:Linux
  • 移动设备操作系统:Unix(Linux、ios)

Linux发展历程

  • 1984年Minix(只用于教学)
  • 1991年编写驱动程序,年底公开Linux内核源码
  • 1994年Linux1.0(Linus Torvalds)
  • 至此开始流行起来

Linux特点

  • Linux是一套免费使用和自由传播的类Unix操作系统
  • 是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统
  • 它能运行主要的Unix工具软件、应用程序和网络协议。它支持32位和64位硬件
  • 继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统
  • 两个基本思想
    • 一切都是文件
    • 每个软件都有确定的用途
  • 完全兼容POSIX1.0标准
  • 多用户、多任务
  • 良好的界面
  • 支持多种平台

Linux与其它操作系统的区别

  • 开源情况
  • 硬件适用
  • 本质不同
  • 系统界面
  • 驱动程序
  • 系统使用
  • 软件与支持

Windows更适用于家庭个人使用

Linux更适用于企业服务器使用

Linux发行商和常见发行版

  • Redhat公司--------Red Hat Linux(最著名的Linux版本、收费)-----免费的CentOS
  • CentOS特点:主流、免费、更新方便

Linux的安装和使用

先安装虚拟机,再安装Centos

Vmware

Vmware简介

  • 不需要分区或者重开机就能在同一台PC上使用两种以上的操作系统
  • 完全隔离并且保护不同操作系统的环境以及所有的软件、资料
  • 不同的操作系统之间还可以进行互动操作
  • 有复原功能
  • 能够设置并且随时修改操作系统的操作环境
  • 常见虚拟机软件:VMware workstation、VirtualBox

Vmware下载:https://www.vmware.com/cn.html

CentOS镜像下载:https://www.centos.org/download/
高速下载地址

  • http://mirrors.aliyun.com
  • http://mirrors.sohu.com
  • http://mirrors.163.com
  • http://mirrors.cqu.edu.cn/CentOS

SecureCRT

简介:SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windows下登录Unix或Linux服务器主机的软件。

目录和文件

  • Linux没有盘符这个概念,只有一个根目录/,所有文件都在他下面
  • etc表示系统中的配置文件
  • usr、usr/bin、usr/sbin都表示系统预设执行文件的放置目录
  • var/log表示程序运行日志的存放目录
  • 切换根目录:cd /
  • 查看目录内容:ls -l

时间同步

Java Web从入门到实战_第1张图片

克隆与快照

克隆:将原系统完完全全的拷贝一份,原系统丢失后克隆的系统还能正常使用

  • 占用空间大
  • 原系统不存在,克隆体还能用

快照:记录系统当前状态,并不会把系统完整拷贝

  • 占用空间小
  • 原系统不存在,快照也就无法使用

克隆和拍摄快照时都需要关闭虚拟机

系统与设置命令

账号管理

与用户相关的命令,必须在管理员权限下才能执行

命令:su root

  • 创建用户:useradd (选项) 用户名
  • 用户口令:passwd (选项) 用户名
    • 密码不能是一个回文
    • 长度必须大于8位
    • 必须是字母和数字的结合

在root权限下切换其它用户可直接切换,无需输入密码

  • 修改用户:usermod 选项 用户名

Java Web从入门到实战_第2张图片

  • 删除用户:userdel (选项) 用户名

Java Web从入门到实战_第3张图片

用户组

将用户分成小组,方便对用户的管理

  • 创建用户组:groupadd (选项) 用户组名
  • 修改用户组:groupmod (选项) 用户组名
    Java Web从入门到实战_第4张图片
  • 查询用户所属组:groups 用户名
  • 删除用户组:groupdel 用户组名
  • 管理用户组内成员:gpasswd (可选项) 组名

    gpasswd是Linux下的管理工具,用于将一个用户添加到组或者从组中删除

    • -a:添加用户到组
    • -d:从组中删除用户
    • -A:指定管理员
    • -M:指定组员和-A的用途差不多
    • -r:删除密码
    • -R:限制用户登入组,只有组中的成员才可以用newgrp加入该组
      Java Web从入门到实战_第5张图片

系统管理相关命令

  • 日期管理:date [参数选项]
    参数选项:
    • -d "字符串":显示字符串所指的日期与时间。字符串前后必须加上双引号
    • -s "字符串":根据字符串来设置日期与时间。字符串前后必须加上双引号
    • -u:显示GMT(北京时间为CST)
    • --help:在线帮助
    • --version:显示版本信息
  • 显示登陆账号的信息:logname
  • 切换用户:su 用户名
  • 查看当前用户详细信息(用户id、群组id、所属组):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命令相当于在Windows系统中打开文件夹,看到的目录以及文件的明细。
    • 语法: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 目录名 目录名:目标目录已存在,将源目录移动到目标目录;目标目录不存在则改名

文件基本属性

  • 文件权限(共10位)
    • 第一位为d表示是一个文件夹;是 - 表示是一个文件;| 表示是一个链接文档(快捷方式)
    • r表示可读;w表示可写;x表示可执行; - 表示没有当前权限
    • 2-4位表示属主权限(文件所属的用户可以做的事情)
    • 5-7位表示属组权限(文件所在用户组可以对它做的事)
    • 8-10位表示其它用户权限
  • chgrp命令(change group)
    • chgrp [选项参数] [所属群组] [文件或目录...]:更改所属组
    • chgrp root aaa:将aaa文件夹所属组更改为root
    • chgrp -v root aaa:将aaa的属组改为root(-v会多一句提示语)
  • chown命令
    • chown 属主名 文件名:更改属主
    • chown [参数选项] 属主名:属组名 文件名:更改属主和属组
    • -R:处理指定目录以及其子目录下的所有文件
  • chmod命令
    • 作用:修改属主、属组、其他用户的权限
    • 数字方式语法:chmod [参数选项] 数字权限 文件或目录
    • 符号方式语法:chmod u=rwx,g=rx,o=r a.txt
    • -R:对目前目录下的所有档案与子目录进行相同的权限变更(即以递回的方式逐个变更)

修改方式

  • 数字方式
    • r-----4
    • w----2
    • x----1
    • -----0

    设置时会把三个数字加在一起设置
    例如:rwx则为7

  • 符号方式
    • user属主权限----u
    • group属组权限----g
    • others其它权限----o
    • all全部身份----a
    • +(加入)、-(除去)、=(设定)
    • r(可读)、w(可写)、x(可执行)

综合案例

需求:一个公司的开发团队有三个用户:Java、erlang、golang
有一个文件目录tmp/work供他们开发,如何实现让这三个用户都对其具有写权限

思路

  • 创建三个用户,并把他们加入到对应的用户组(dev-group)
  • 将tmp/work文件夹所属组更改为dev-group
  • 修改文件夹所属组的权限

在这里插入图片描述

文件管理

touch

  • 语法:touch [参数选项] 文件名

    如果文件不存在就创建文件,如果存在就修改时间属性

  • touch a{1..10}.txt:创建a1.txt一直到a10.txt共10个文件(批量创建空文件)
  • stat a.txt:查看文件的详细信息

vi/vim编辑器

  • vi编辑器:只能是编辑文本内容,不能对字体、段落进行排版
    • 不支持鼠标操作
    • 没有菜单
    • 只有命令
  • vim编辑器:vim是从vi发展出来的一个文本编辑器。
    • 代码补全、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用

简单来说:
vi是老式的文字处理器,不过功能已经很齐全了,但是还是有可以改进的地方
vim则可以说是程序员开发者的一项很好用的工具

  • 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 文件名 +行数:查看文件并定位到具体行数
    • vim a.txt +5:查看a.txt文件并定位到第5行
  • 异常处理
    • 如果vim异常退出,在磁盘上可能会保存有交换文件

    在修改一个文件时(a.txt),为保证文件安全,vim不会对源文件进行修改,会产生一个新的文件(a.txt.swp),并对该文件进行编辑
    只有在保存的时候,才会将新文件写回到源文件中

    • 如果有交换文件,在下次使用vim编辑文件时,系统会提示是否对交换文件继续操作(将交换文件删除即可)

文件查看

命令 功能
cat 文件名 查看小文件内容
less -N 文件名 分屏显示大文件内容
head -n 文件名 查看文件的前一部分
tail -n 文件名 查看文件的最后部分
grep 关键字 文件名 根据关键字搜索文本文件内容
  • cat -n a.txt:可以加入参数选项-n显示行号
    • 只能阅读小文件
    • 阅读大文件可能显示不完整
  • less 文件名:查看大文件
    • 加入-N可显示行号
    • ctrl + F :向前移动一屏
    • ctrl + B :向后移动一屏
    • ctrl + D :向前移动半屏
    • ctrl + U :向后移动半屏
    • j :向前移动一行
    • k :向后移动一行
    • G:移动到最后一行
    • g:移动到第一行
    • q/ZZ:退出less命令
  • 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行内容
    • 其它内容和tail类似
  • grep命令
    • 类似于Windows下打开文件后ctrl+F的查找功能
    • 查找对应的进程
    • 语法:grep [参数选项] 关键字 文件:根据关键字,搜索文本文件内容
    • -n:把包含关键字的行号展示出来
    • -i:把包含关键字的行展示出来,搜索时忽略大小写
    • -v:把不包含关键字的行展示出来
    • ps -ef | grep sshd:将进程中含有sshd的进程展示出来
    • ps -ef | grep -c sshd:将进程中含有sshd的进程的个数展示出来

echo命令

  • echo 字符串:展示文本
  • echo 字符串 > 文件名:将字符串写到文件中(覆盖文件内容)
  • echo 字符串 >> 文件名:将字符串写到文件中(不覆盖原内容)
  • cat 不存在的目录 &>> 存在的文件:将命令的失败结果追加到指定的文件的后面

awk命令

  • AWK是一种处理文本文件的语言,是一个强大的文本分析工具(名字取自三位创始人名字中的字母)
  • 语法: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以及总人数(行数)

软连接

  • 类似于Windows里面的快捷方式
  • 语法:ln -s 目标文件路径 快捷方式路径
  • ln -s aaa/bbb/ccc/ddd/eee/a.txt a.txt

压缩命令

查找命令

  • 语法:find [参数选项] <指定目录> <指定条件> <指定内容>:在指定目录下查找文件
  • 参数选项
    • -name filename:查找名为filename的文件
    • -ctime -n或+n:按时间来查找文件,-n指n天以内,+n指n天以前
  • find . -name "*.txt":查找当前目录下所有以txt为后缀的文件
  • find . -ctime -1:当前文件夹下1天内操作过的文件

    . 替换为 / 则表示在全盘范围进行查找

gzip命令

  • 语法:gzip [参数选项] [文件]:压缩文件
  • gzip a.txt:将a.txt文件压缩
  • gzip *:将当前目录下所有文件都进行压缩(已经压缩过的不能再次被压缩)
  • gzip -dv 文件名:解压文件并显示详细信息

gunzip命令

  • 语法:gunzip [参数] [文件]:解压文件
  • gunzip 压缩文件:解压压缩文件
  • gunzip *:解压当前目录下的所有压缩文件

tar命令

  • 语法:tar [必要参数] [选择参数] [文件]:打包、压缩和解压(文件/文件夹)
  • 注意:tar本身不具有压缩功能,它是调用压缩功能实现的
  • 参数选项
    • -c:建立新的压缩文件
    • -v:显示指令执行过程
    • -f <备份文件>:指定压缩文件
    • -z:通过gzip指令处理压缩文件
    • -t:列出压缩文件中的内容
    • -x:表示解压
  • tar -cvf 打包文件名 文件名:打包文件并指定打包之后的文件名(仅打包不压缩)
  • tar -zcvf b.gz b.txt:通过gzip指令将b.txt压缩为b.gz并显示过程(打包压缩)
  • tar -zcvf aaa.gz aaa:将aaa文件夹压缩为aaa.gz
  • tar -ztvf aaa.gz:查看压缩文件中的内容
  • tar -zxvf aaa.gz:解压aaa.gz文件

zip命令

  • 语法:zip [必要参数] [选择参数] [文件]:压缩
  • 注意:zip是个使用广泛的压缩程序,文件经他压缩后会另外产生具有".zip"扩展名的压缩文件
  • 参数选项
    • -q:不显示指令执行过程
    • -r:递归处理,将指定目录下的所有文件和子目录一并处理
  • zip -q -r 压缩文件名 文件/文件夹:压缩对应的文件/文件夹

unzip命令

  • 语法:unzip [必要参数] [选择参数] [文件]:解压
  • 注意:只能解压".zip"扩展名的压缩文件
  • 参数选项
    • -l:显示压缩文件内所包含的文件
    • -d <目录>:指定文件解压缩后要存储的目录
  • unzip -l aaa.zip:查看aaa.zip压缩文件所包含的文件
  • unzip -d aaa aaa.zip:将aaa.zip压缩文件解压到aaa文件夹中(aaa文件夹可以不存在,会自动创建)

bzip2命令

  • 语法:bzip2 [参数选项] 文件:压缩文件
  • 注意:使用新的压缩算法,和zip相比压缩后的文件比原来的要小,但花费时间变长
  • 若没有加上任何参数,bizp2压缩完文件后会产生bz2的压缩文件,并删除原始文件
  • bzip2 a.txt:压缩并删除a.txt
  • bunzip2命令bunzip2 [参数选项] 文件:解压
    • -v:解压文件时,显示详细的信息
    • bunzip2 -v a.bz2:解压并显示详细信息

网络与磁盘管理

网络管理

  • ifconfig命令
    • 语法:ifconfig [参数选项]:显示或配置网络设备的命令
    • ifconfig ens37 down:关闭ens37这张网卡
    • ifconfig ens37 up:开启网卡ens37
    • ifconfig ens37 192.168.23.199:将ens37网卡的ip更改为192.168.23.199
    • ifconfig ens37 192.168.23.199 netmask 255.255.255.0:配置ip地址和子网掩码
  • ping命令
    • 语法:ping [参数选项]:检测是否与主机联通
    • -c <完成次数>:设置完成要求回应的次数
    • ping -c 2 www.baidu.com:指定接收包的次数
  • netstat命令
    • 语法:netstat [参数选项]:显示网络状态
    • -a:显示所有连线中的Socket
    • -i:显示网卡列表

磁盘管理

  • lsblk命令
    • 语法:lsblk [参数选项]:列出硬盘的使用情况
    • 理解为:list block的英文缩写
    • lsblk -f:显示系统信息
  • df命令
    • 语法:df [参数选项]:显示目前在Linux系统上,磁盘的使用情况
    • –total:显示所有的信息
    • -h:换算成KB,MB,GB等形式进行展示(方便阅读)
    • df:显示整个硬盘的使用情况
    • df 文件夹:显示文件夹使用情况
    • df --total:显示所有的信息
    • df -h:将结果变成kb、mb、gb等形式展示,利于阅读
  • mount命令
    • 语法:mount [参数选项] 目录:用于挂载Linux系统外的设备
    • 类似与Windows中的U盘,但在Linux中需要手动新建一个文件夹,并把该文件夹和U盘关联起来(挂载点和挂载)

    注意:“挂载点”的目录需要以下几个要求:
    目录事先存在,可以用mkdir命令新建目录
    挂载点目录不可被其它进程使用到
    挂载点下原有文件将被隐藏

    • mount -t auto /dev/cdrom PPP:将光驱和PPP文件夹挂载
    • umount PPP:卸载PPP文件夹所挂载的光驱

yum

  • 在Linux中,如果我们需要查找、安装、下载或者卸载另外的软件,就需要通过yum来进行操作。英文全称为:Yellow dog Updater,Modified
  • yum常用命令
    • 列出所有可更新的软件清单命令:yum check -update
    • 更新所有软件命令:yum update
    • 仅安装指定的软件命令:yum install
    • 仅更新指定的软件命令:yum update
    • 列出所有可安装的软件清单命令:yum list
    • 删除软件包命令:yum remove
    • 查找软件包命令:yum search
    • 清除缓存命令:
      • yum clean packages:清除缓存目录下的软件包
      • yum clean headers:清除缓存目录下的headers
      • yum clean oldheaders:清除缓存目录下旧的headers
      • yum clean,yum clean all(= yum clean packages;yum clean oldheades):清除缓存目录下的软件包及旧的headers
  • -y:在安装过程中,如果有选择提示,全部选择y
  • 注意:使用yum必须联网且在root权限下
  • yum -y install tree:安装tree
  • tree:执行tree,展示当前目录结构
  • yum remove tree:移除tree
  • yum list tom*:查找以tom为开头的软件名称
  • yum源
    • 在下载软件的时候,都是从yum源中获取的,默认是centos中默认的yum源(在国外,下载速度慢)
    • 更换国内yum源
      • 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:清理缓存,并重新加载yum
      • yum makecache:为新yum源建立缓存文件
      • yum search tomcat:查找软件,验证阿里云的yum源是否可以正常使用

rpm

  • 在最初,RedHat Linux发行版专门用来管理Linux各种套件的程序
  • 和yum的区别
    • rpm只能安装已经下载到本地机器上的rpm包
    • yum能在线下载并安装rpm包,能更新系统,且还能自动处理包与包之间的依赖问题,这个是rpm工具所不具备的

shell

初识shell

在计算机科学中,shell就是一个命令解释器
shell是位于操作系统和应用程序之间,是他们二者最主要的接口。
shell负责把应用程序的输入命令信息解释给操作系统,将操作系统指令处理后的结果解释给应用程序

一句话,shell就是在操作系统和应用程序之间的一个命令翻译工具。

Windows和Linux中的shell

  • Windows系统:cmd.exe 命令提示字符
  • Linux系统:sh / csh / ksh / bash(默认) / …

shell的使用方式

  • 手工方式

手工敲击键盘,直接输入命令,按Enter后。
执行命令,显示命令执行的结果
重点:逐行输入命令,逐行进行确认执行

  • 脚本方式

我们把手工执行的命令,写到一个文件中,然后运行这个文件,达到执行命令的效果。
这个文件就叫做脚本文件

编写第一个shell脚本

  • 新建一个文件后缀名为sh
  • 编写内容
    #! /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++))

注意点

  1. 原生的bash不支持简单的数学运算。可以通过其它命令实现:expr
  2. 表达式和运算符之间要有空格
  3. 完整的表达式要被反引号包含
  4. 乘法中不能直接使用*,需要在乘号前加\转义

举例:`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语法

casein
模式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 "两数之和为:$?"

Nginx

这部分应该是HTML + CSS + Nginx,因为HTML和CSS是之前学过的,当时并没有记笔记,这部分也相当简单些,如果有没学过的可以自行搜索资料学习一下~

概述

  • Nginx是一款服务器软件
  • 其核心功能是可以和服务器硬件相结合,从而可以将程序发布到Nginx服务器上,让更多用户浏览

安装

  1. 上传压缩包:put nginx压缩包位置(CRT中按alt+p键进入sftp)

  2. 解压压缩包:tar -zxvf 压缩包名

  3. 进入解压目录:cd nginx解压目录

  4. 安装依赖环境

    yum -y install pcre pcre-devel

    yum -y install zlib zlib-devel

    yum -y install openssl openssl-devel
    yum -y install gcc

  5. 安装nginx
    ./configure
    make
    make install(安装完会在/usr/local/下有一个nginx目录)

  6. 进入对应目录:cd /usr/local/nginx/sbin

  7. 启动nginx服务:./nginx
    停止:./nginx -s stop
    重启:./nginx -s reload

  8. 查看nginx服务状态:ps -ef | grep nginx

  9. 测试nginx服务:浏览器打开对应Linux服务器ip地址

最后这里在浏览器打开对应ip地址无法访问,解决方法:
第一步,对80端口进行防火墙配置:firewall-cmd --zone=public --add-port=80/tcp --permanent
第二步,重启防火墙服务:systemctl restart firewalld.service
然后重新在浏览器中访问你的ip,应该就可以访问了。

发布项目

  1. /home 下创建一个web目录:mkdir web

  2. 将项目上传到该目录下:put web项目压缩包

  3. 解压项目压缩包:unzip web程序压缩包

  4. 编辑nginx配置文件:vim /home/nginx-1.18.0/conf/nginx.conf
    找到server的大括号范围,修改location的路径
    Java Web从入门到实战_第6张图片

  5. 进入对应目录:cd /usr/local/nginx/sbin

  6. 关闭nginx服务:./nginx -s stop

  7. 启动nginx服务并加载配置文件:/usr/local/nginx/sbin/nginx -c/home/nginx-1.18.0/conf/nginx.conf

  8. 通过浏览器测试网站


JavaWeb核心

企业开发简介

JavaEE规范

  • JavaEE(Java Enterprise Edition):Java企业版
  • 它是由SUN公司领导、各个厂家共同制定并得到广泛认可的工业标准。
  • JavaEE早期叫做J2EE,但是没有继续采用其命名规则。J2EE的版本从1.0开始到1.4结束。而JavaEE版本是从JavaEE 5 版本开始,目前最新的版本是JavaEE 8。
  • JavaEE规范是很多Java开发技术的总称。这些技术规范都是沿用自J2EE的。一共包括了13个技术规范。
  • 包括:JDBC, JNDI, EJB, RMI, IDL/CORBA, JSP, Servlet, XML, JMS, JTA, JTS, JavaMail, JAF。

WEB概述

概述

  • WEB在计算机领域中代表的是网络
  • 像我们之前所用的WWW,它是World Wide Web 三个单词的缩写,称为:万维网
  • 网络相关技术的出现是为了让我们在网络的世界中获取资源,这些资源的存放之处,我们把它叫做网站
  • 我们通过输入网站的地址(网址),就可以访问网站中提供的资源(不区分局域网或广域网)

资源分类

  • 静态资源
    网站中提供给人们展示的资源是一成不变的,也就是说不同人或者在不同时间,看到的内容都是一样的。
    作为开发者来说,我们编写的HTML, CSS, JavaScript 都属于静态资源。
  • 动态资源
    网站中提供给人们展示的资源是由程序产生的,在不同的时间或者不同的人由于身份的不同,所看到的内容是不一样的。
    作为网站开发者来说,我们编写的JSP、Servlet等都属于动态资源。

系统结构

在之前的学习中,开发的都是Java工程。这些工程在企业中称之为项目或者产品。都是有系统架构的!

  • 基础结构划分
    • CS结构:(Client Server)客户端+服务器的方式(把不同的应用直接安装在客户端上)
    • BS结构:(Browser Server)浏览器+服务器的方式
  • 技术选型划分
    • Model1模型
    • Model2模型
    • MVC模型
    • 三层架构 + MVC模型
  • 部署方式划分
    • 一体化结构
    • 垂直拆分结构
    • 分布式结构
    • 微服务结构

tomcat

服务器

  • 服务器是计算机的一种,它比普通计算机运行更快、负载更高、价格更贵。==服务器在网络中为其它客户机(如PC机、智能设备等)提供计算或者应用服务。==服务器具有高速的CPU运算能力、长时间的可靠运行、强大的I/O外部数据吞吐能力以及更好的扩展性。
  • 而我们这里所说的服务器,其实是web服务器,或者应用服务器。它本质就是一个软件,通过和硬件相结合,从而达到帮助我们来发布应用的功能,让用户通过客户机访问我们的应用。
  • 常用的应用服务器
    服务器名称 说明
    weblogic 实现了JavaEE规范,重量级服务器,又称为JavaEE容器
    websphereAS 实现了JavaEE规范,重量级服务器
    JBOSSAS 实现了JavaEE规范,重量级服务器,免费的
    Tomcat 实现了jsp/servlet规范,是一个轻量级服务器,开源免费

Tomcat

  • Tomcat是Apache软件基金会的Jakarta项目组中的一个核心项目,由Apache、Sun和其它一些公司及个人共同开发而成。由于有了Sun公司的参与和支持,最新的Servlet、JSP规范总能在Tomcat中得到体现。因为Tomcat技术先进、性能稳定,而且免费,所以深受Java爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。
  • Tomcat官网:https://tomcat.apache.org/
  • Tomcat各个版本所需要的支持
    Java Web从入门到实战_第7张图片

下载和安装

  • 下载:官网下载
  • 安装:直接解压即可
  • 目录组成
    • bin:一些二进制可执行文件
    • conf:保存配置文件的路径
    • lib:Tomcat在运行过程中所需要的jar包
    • logs:日志文件
    • temp:临时文件
    • webapps:项目发布目录(一个文件夹代表一个web应用)(ROOT代表根项目)
    • work:工作目录

基本使用

  1. 启动
    startup.bat:Windows下启动执行文件
    startup.sh:Linux下启动执行文件

    启动后浏览器访问:http://localhost:8080可以进入欢迎界面(Tomcat默认端口为8080)

  2. 停止
    shutdown.bat:Windows下关闭执行文件
    shutdown.sh:Linux下关闭执行文件

  3. 部署项目
    在webapps目录下创建一个文件夹
    将资源放到该文件夹中
    启动tomcat,输入正确路径

常见问题

  1. 启动问题
    启动窗口一闪而过:没有配置jdk环境变量
    Java Web从入门到实战_第8张图片

    java.net.BindException:端口8080被占用

  2. 控制台乱码问题解决
    conf-logging.properties
    修改java.util.logging.ConsoleHandler.encoding = UTF-8

    Tomcat默认UTF-8,CMD命令窗口默认GBK,将UTF-8改为GBK即可解决乱码问题

IDEA集成Tomcat

  1. 点击Run -》 Edit Configurations
  2. 点击Defaults -》 Tomcat Servlet -》 Local
  3. 点击Configure -》Tomcat Home -》 选择tomcat所在路径

Linux下的安装

  1. 上传压缩包到/home路径:put d:/apache-tomcat-9.0.58.tar.gz
  2. 解压压缩包:tar -zxvf 压缩包名
  3. 进入bin目录下:cd apache-tomcat-9.0.58/bin
  4. 启动tomcat服务:./startup.sh
  5. 使用浏览器测试:浏览器打开对应Linux服务器ip地址:8080

Java WEB项目

  1. 新建项目模型,选择Java Enterprise
    确定JDK版本、Appalication Server版本
  2. 右键Add Framework Support…
  3. 勾选Web Appalication选项

项目组成详解

  • src:存放Java源代码
  • web:存放项目相关资源(html、css、js、jsp、图片等)
  • WEB-INFO:存放相关配置的(web.xml等)

IDEA发布项目

  1. 点击Run -》 Edit Configurations
  2. 点击Tomcat Server -》 Deployment
    Application Context是项目访问路径,/代表默认路径,多个项目中只能有一个默认路径
  3. 点击Tomcat Server -》 Server
    设置关联浏览器
    两个Update resources设置
    设置JDK、端口号
  4. 启动Tomcat服务
  5. 验证结果(浏览器)

通过war包发布项目

  1. 在项目的web路径下打war包:jar -cvf myweb.war .
  2. 将打好的war包剪切到tomcat的webapps路径下
  3. 启动tomcat服务,自动解压war包
  4. 验证结果

配置文件

配置默认端口号

主配置文件server.xml

标签中,port属性代表Tomcat默认端口号(8080)

在这里插入图片描述

http协议默认端口号为80,Tomcat默认端口号与其不一致,所以每次访问网站需要加上端口号
如果是80端口,就不需要加端口号
真正发布网站的时候,都需要将tomcat默认端口号改为80,这样在访问网站的时候就不需要加端口号了

配置虚拟目录

  • 作用:可以发布任意目录下的项目
  1. 编辑server.xml 配置文件,找到标签

  2. 加入以下内容

    Java Web从入门到实战_第9张图片

    path:访问资源的虚拟目录名称(表示在浏览器地址栏中的访问路径)
    docBase表示需要发布的项目的真实路径

配置虚拟主机

  • 作用:可以指定访问路径的名称
  1. 编辑server.xml 配置文件,找到标签
  2. 加入以下内容
    Java Web从入门到实战_第10张图片

name:虚拟主机名称
appBase:项目所保存的根路径
unpackWARs:是否自动解压war包
autoDeploy:是否自动发布
Context:同虚拟目录

  1. 修改hosts文件
    绑定IP地址和对应的域名
    文件路径:c:\Windows\System32\drivers\etc
    Java Web从入门到实战_第11张图片

HTTP协议

概述

  • HTTP(Hyper Text Transfer Protocol):超文本传输协议
  • HTTP协议是基于 TCP/IP 协议的(安全)
  • 超文本:比普通文本更加强大(还有图片、音频等等)
  • 传输协议:客户端和服务端的通信规则(握手规则)

组成部分

  • 请求:客户端发起请求到服务器
  • 响应:服务器收到客户端的请求后发起响应给客户端

除了手动发起的请求外,JavaScript、CSS、图片等资源会自动发起请求

协议的请求

请求的组成部分

  1. 请求行:请求方式 提交路径(提交参数) HTTP/版本号

  2. 请求头

    名称 说明
    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 会话管理相关,非常的重要
  3. 请求空行:普通换行,用于区分请求头和请求体

  4. 请求体:只有POST提交方式才有请求体,用于显示提交参数

请求的方式

GET
Java Web从入门到实战_第12张图片

POST
Java Web从入门到实战_第13张图片

只有POST请求方式存在请求体,GET请求方式没有请求体
get提交的参数在请求行中,post提交的参数在请求体中

协议的响应

响应的组成部分

  1. 响应行:请求方式 HTTP/版本号 状态码 状态描述
    常见状态码

    状态码 说明
    200 一切OK
    302/307 请求重定向,两次请求,地址栏发生变化
    304 请求资源未发生变化,使用缓存
    404 请求资源未找到
    500 服务器错误
  2. 响应头

    名称 说明
    Location 请求重定向的地址,常与302,307配合使用
    Server 服务器相关信息
    Content-Type 响应正文的MIME类型
    Content-Length 响应正文的长度
    Content-Disposition 告知客户端浏览器,以下载的方式打开响应正文
    Refresh 定时刷新
    Last-Modified 服务器资源的最后修改时间
    Set-Cookie 会话管理相关,非常的重要
    Expires:-1 服务器资源到客户端浏览器后的缓存时间
    Catch-Control:no-catch 不要缓存
  3. 响应空行:普通换行,用于区分响应头和响应体

  4. 响应体:将资源文件发送给客户端浏览器进行解析

发布资源案例

发布静态资源

  1. 创建一个Java WEB项目

  2. 将静态页面所需资源导入到项目的web目录下

  3. 修改web.xml配置文件,修改默认主页

    
    <welcome-file-list>
        <welcome-file>/路径/文件名.htmlwelcome-file>
    welcome-file-list>
    
  4. 将项目部署到tomcat中

  5. 启动tomcat服务

  6. 打开浏览器查看页面

Servlet介绍

  • Servlet是运行在Java服务器端的程序,用于接收和响应来自客户端基于HTTP协议的请求。
  • 如果想实现Servlet的功能,可以通过实现javax.servlet.Servlet接口或者继承它的实现类。
  • 核心方法:service(),任何客户端的请求都会经过该方法。

发布动态资源

  1. 创建一个JavaWEB项目

  2. 将静态页面所需资源导入到项目的web目录下

  3. 修改web.xml配置文件,修改默认主页

  4. 在项目的src路径下编写一个类,实现Servlet接口

  5. 重写service方法,输出一句话即可

  6. 修改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>
    
  7. 将项目部署到tomcat中

  8. 启动tomcat服务

  9. 打开浏览器测试功能

执行流程

  1. 通过浏览器访问到指定的资源路径
  2. 通过url-pattern找到对应的name标签
  3. 通过name找到对应的Servlet声明
  4. 在声明中找到对应的Java实现类
  5. 执行service方法

Servlet

概述

  • Servlet是运行在Java服务器端的程序,用于接收和响应来自客户端基于HTTP协议的请求
  • 是一个接口(javax.servlet.Servlet),常用实现类:GenericServlet、HttpServlet(继承自GenericServlet)
  • 所有的客户端请求都会经过service方法进行处理
  • 初始化会调用init方法,销毁时会调用destroy方法

执行过程

  1. 客户端浏览器向Tomcat服务器发起请求
  2. Tomcat服务器解析请求地址(URL)
  3. Tomcat根据地址找到对应的项目
  4. 找到项目中的web.xml文件
  5. 解析请求资源地址(URI)
  6. 找到项目的资源(对应的Java类)
  7. 执行service方法,响应给客户端浏览器

关系视图

Java Web从入门到实战_第14张图片

实现方式

  1. 实现Servlet接口,实现所有的抽象方法,该方式支持最大程度的自定义
  2. 继承GenericServlet抽象类,必须重写service方法,其他方法可选择重写。该方式让我们开发servlet变得简单。但是这种方式与HTTP协议无关
  3. 继承HttpServlet抽象类,需要重写doGetdoPost方法。该方式表示请求和响应都需要和HTTP协议相关

生命周期

  • 对象的生命周期,就是对象从出生到死亡的过程。即:出生 =》活着 =》死亡。官方说法是对象创建到销毁的过程
  • 出生:请求第一次到达Servlet时,对象就创建出来,并且初始化成功。只出生一次,将对象放到内存中
  • 活着:服务器提供服务的整个过程中,该对象一直存在,每次都是执行service方法
  • 死亡:当服务器停止时,或者服务器宕机时,对象死亡

出生对应的是init方法
活着对应的是service方法(doGetdoPost方法)
死亡对应的是destroy方法

结论: Servlet对象只会创建一次,销毁一次。所以Servlet对象只有一个实例。如果一个对象实例在应用中是唯一的存在,那么就称他为单例模式

线程安全问题

  • 由于Servlet采用的是单例设计模式,也就是整个应用中只有一个实例对象。所以我们需要分析这个唯一的实例对象中的类成员是否线程安全
  • 模拟用户登录功能来查看Servlet线程是否安全

结论: 一个浏览器代表一个线程,多个浏览器代表多个线程。按理说应该是每个浏览器查看的都是自己的信息。但结果浏览器中数据混乱。因此,我们可以认为Servlet是线程不安全的!

解决: 定义类成员要谨慎。如果是共用的,并且只会在初始化时赋值,其它时间都是获取的话,那么是没问题的。如果不是共用的,或者每次使用都有可能对其赋值,那就要考虑线程安全的问题了,可以将其定义到doGet或doPost方法内或者使用同步功能即可

映射方式

  1. 具体名称的方式。访问的资源路径必须和映射配置完全相同 【常用】

    <servlet>
    	<servlet-name>Demoservlet-name>
    	<servlet-class>study.servlet.Demoservlet-class>
    servlet>
    <servlet-mapping>
    	<servlet-name>Demoservlet-name>
    	<url-pattern>/Demourl-pattern>
    servlet-mapping>
    
  2. / 开头 + 通配符的方式。只要符合目录结构即可,不用考虑结尾是什么

    <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>
    
  3. 通配符 + 固定格式结尾的方式。只要符合固定结尾格式即可,不用考虑前面的路径

    <servlet>
            <servlet-name>Demo2servlet-name>
            <servlet-class>study.servlet.Demo2servlet-class>
        servlet>
        <servlet-mapping>
            <servlet-name>Demo2servlet-name>
            <url-pattern>*.testurl-pattern>
        servlet-mapping>
    

注意: 优先级问题。越是具体的优先级越高,越是模糊的 优先级越低。第一种 > 第二种 > 第三种

多路径映射

  • 我们可以给一个Servlet配置多个访问映射,从而根据不同的请求路径来实现不同的功能
  • 场景分析
    如果访问的资源路径是/vip,商品价格打9折
    如果访问的资源路径是/vvip,商品价格打5折
    如果访问的资源路径是其它,商品价格不打折
  • 采用第二种映射方式实现多路径映射(/ + 通配符)
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. 第一次访问时创建
    • 优势:减少对服务器内存的浪费。提高了服务器启动的效率
    • 弊端:如果有一些要在应用加载时就做的初始化操作无法完成
  2. 服务器加载时创建
    • 优势:提前创建好对象,提高了首次执行的效率。可以完成一些应用加载时要完成的初始化操作
    • 弊端:对服务器内存占用较多,影响了服务器启动的效率
  3. 修改Servlet创建时机。在标签中,添加标签
    1
    正整数代表服务器加载时创建,值越小,优先级越高。负整数或不写代表第一次访问时创建

默认Servlet

  • 默认Servlet是由服务器提供的一个Servlet。它配置在 Tomcat 的 conf 目录中的 web.xml 中

Java Web从入门到实战_第15张图片

  • 它的映射路径是/。我们在发送请求时,首先会在我们项目中的web.xml 中查找映射配置,找到则执行。但是当找不到对应的Servlet 路径时,就去找默认的 Servlet ,由默认Servlet 处理。所以,一切都是Servlet

ServletConfig

  • ServletConfig 是Servlet 的配置参数对象,在Servlet 的规范中,允许为每一个Servlet 都提供一些 初始化的配置。所以,每个Servlet 都有一个自己的ServletConfig
  • 作用:在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);
    }
}

ServletContext

  • ServletContext 是应用上下文对象(应用域对象)。每一个应用中只有一个 ServletContext 对象
  • 作用:可以配置和获得应用的全局初始化参数,可以实现Servlet 之间的数据共享
  • 生命周期:应用一加载则创建,应用被停止则销毁

域对象

  • 域对象指的是对象有作用域,也就是作用范围。域对象可以实现数据的共享。不同作用范围的域对象,共享数据的能力也不一样
  • 在Servlet 规范中,一共有4个域对象。ServletContext 就是其中的一个。他也是web 应用中最大的作用域,也叫 application 域。它可以实现整个应用之间的数据共享

配置方式

  • 标签中,通过标签来配置。有两个子标签
    • :代表全局初始化参数的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 规范

  • 我们使用的是Tomcat 9版本。JavaEE规范要求是8.对应的Servlet 版本应该是4.x 版本。但是,在企业开发中,稳定要远比追求新版本重要。所以我们会降低版本使用,用的是Servlet 3.1版本。
  • 其实我们之前的操作全部是基于 Servlet 2.5版本规范的,也就是借助于配置文件的方式。后来随着软件开发逐步的演变,基于注解的配置开始流行。而Servlet 3.0版本也就开始支持注解开发了
  • Servlet 3.0版本既保留了2.5版本的配置方式,同时有支持了全新的注解配置方式。它可以完全不需要 web.xml 配置文件,就能实现 Servlet 的配置,同时还有一些其他的新特性。

自动注解开发

实现步骤

  1. 创建一个 web 项目
  2. 定义一个类,继承HttpServlet
  3. 重写 doGet 和 doPost方法
  4. 在类上使用@WebServlet 注解并配置Servlet
  5. 部署并启动项目
  6. 通过浏览器测试
@WebServlet("/servletDemo")
public class ServletDemo extends HttpServlet{
    
}

Java Web从入门到实战_第16张图片

手动创建容器(了解)

  • Servlet 3.0 规范除了使用自动注解的配置方式外,还支持手动创建 Servlet 容器的方式。如果使用必须遵循其编写规范。在3.0 版本加入了一个新的接口:ServletContainerInitializer,需要重写onStartup方法

步骤

  1. 定义一个类,继承HttpServlet

  2. 重写 doGet 和 doPost方法

  3. 定义一个类,实现ServletContainerInitializer接口

  4. 在src 目录下创建一个META-INF的包

  5. 在 META-INF 包下创建一个services 的包

  6. 在 services 包下创建一个 javax.servlet.ServletContainerInitializer 的文件

  7. 文件中的内容为容器实现类的全类名

  8. 在容器实现类中的 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加载时机
    }
    
  9. 部署并启动项目

  10. 通过浏览器测试

学生管理系统1

  • 需求:添加学生信息到Java服务器中的本地文件

步骤

  1. 创建一个 web 项目
  2. 创建一个用于保存学生信息的html文件
  3. 创建一个类,继承HttpServlet
  4. 重写doGet 和 doPost 方法
  5. 在web.xml 文件中修改默认主页和配置 Servlet
  6. 在doGet 方法中接收表单数据保存到文件中,并响应给浏览器结果
  7. 部署并启动项目
  8. 通过浏览器测试

获取表单数据
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架构中,就是客户端浏览器向服务端发出询问。

请求对象: 就是在项目中用于发送请求的对象(ServletRequestHttpServletRequest)

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

获取请求参数并封装对象

  1. 手动封装方式
    成员变量名称和参数name属性值保持一致
  2. 反射封装方式
    属性描述器:PropertyDescriptor(根据名称获取到对象中对应的get和set方法)
  3. 工具类封装方式
    beanutils工具类,populate方法
    在发布之前,还需要进入File-Project Structure
    Java Web从入门到实战_第17张图片
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);
    }
}

中文乱码问题

  • GET方式
    没有乱码问题,在Tomcat 8 版本后已经解决
  • POST方式
    有乱码问题,可以通过 setCharacterEncoding() 方法来解决(编码格式要和页面编码格式一致)
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);
    }
}

请求域

  • 请求域(request域):可以在一次请求范围内进行共享数据。
  • 一般用于请求转发的多个资源中共享数据
  • 请求对象操作共享数据方法
    返回值 方法名 说明
    void setAttribute(String name, Object value) 向请求域对象中存储数据
    Object getAttribute(String name) 通过名称获取请求域对象中的数据
    void removeAttribute(String name) 通过名称移除请求域对象中的数据

请求转发

  • 请求转发:客户端的一次请求到达以后,发现需要借助其他 Servlet 来实现功能(浏览器请求,A发现做不了,转发给B去做)
  • 特点
    • 浏览器地址栏不变
    • 域对象中的数据不丢失
    • 负责转发的Servlet 转发前后的响应正文会丢失
    • 由转发的目的地来响应客户端
返回值 方法名 说明
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);
    }
}

请求包含

  • 请求包含:可以合并其他Servlet 中的功能一起响应给客户端(浏览器请求,A只能做一半,另一半让B做)
  • 特点
    • 浏览器地址栏不变
    • 域对象中的数据不丢失
    • 被包含的 Servlet 响应头会丢失
返回值 方法名 说明
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);
    }
}

响应对象

  • 响应:回馈结果。在 BS 架构中,就是服务器给客户浏览器反馈结果
  • 响应对象:就是在项目中用于发送响应的对象
    ServletResponse(接口)
    HttpServletResponse(继承自ServletResponse,基于http协议的接口)

    和请求对象一样,不需要我们去写实现类,在Tomcat 服务器创建好,在执行 doGet 或者 doPost 方法时,服务器会把相应的实现类对象传递

常见状态码

状态码 说明
200 成功
302 重定向
304 请求资源未改变,使用缓存
400 请求错误,常见于请求参数错误
404 请求资源未找到
405 请求方式不支持
500 服务器错误

字节流响应消息

返回值 方法名 说明
ServletOutputStream getOutputStream() 获取响应字节输出流对象
void setContentType(“text/html;charset=UTF-8”) 设置响应内容类型,解决中文乱码问题

步骤:

  1. 获取字节输出流对象
  2. 定义一个消息(一个字符串)
  3. 通过字节流对象输出

获取到的字节输出流对象不需要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("字符输出流响应消息");
}

响应图片

  1. 通过文件的相对路径获取绝对路径(getRealPath)
  2. 创建字节输入流对象,关联读取的图片路径
  3. 通过响应对象获取字节输出流对象
  4. 循环读取和写出图片
@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=要跳转的路径")
单位为秒

请求重定向

  • 请求重定向:客户端的一次请求到达后,发现需要借助其他Servlet 来实现功能
  • 特点:浏览器地址栏会发生改变,两次请求,请求域对象中不能共享数据,可以重定向到其他服务器
  • 重定向实现原理
    1. 设置响应状态码为302:resp.setStatus(302);
    2. 设置响应的资源路径(响应到哪里去,通过响应消息头 location 来指定):resp.setHeader("location","/response/responseDemo")
  • 响应对象重定向方法
    返回值 方法名 说明
    void sendRedirect(String name) 设置重定向

文件下载

  1. 创建字节输入流,关联读取的文件
  2. 设置响应消息头支持的类型:resp.setHeader("Content-Type","application/octet-stream")
    Content-Type:消息头名称,代表所支持的类型
    application/octet-stream:消息头参数,代表应用的类型为字节流
  3. 设置响应消息头以下载方式打开资源:resp.setHeader("Content-Disposition","attachment;filename=下载的文件名称")
    Content-Disposition:消息头名称,代表处理形式
    attachment;filename=xxx:消息头参数,代表附件的形式进行处理,filename代表指定下载文件的名称
  4. 通过响应对象获取字节输出流对象
  5. 循环读写
  6. 释放资源
@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();
}

学生管理系统2

  • 资源准备
    1. 创建一个 web 项目
    2. 在web 目录下创建一个 index.html,包含两个超链接标签(添加学生、查看学生)
    3. 在 web目录下创建一个 addStudent.html,用于实现添加功能的表单页面
    4. 在 src 下创建一个 Student 类,用于封装学生信息
// 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>

Cookie

会话

  • 会话:浏览器和服务器之间的多次请求和响应
  • 为了实现一些功能,浏览器和服务器之间可能会产生多次的请求和响应,从浏览器访问服务器开始,到访问服务器结束(关闭浏览器、到了过期时间)。这期间产生的多次请求和响应加在一起就称之为浏览器和服务器之间的一次会话
  • 会话过程所产生的一些数据,可以通过会话技术(Cookie 和 Session)保存。

概述

  • Cookie: 客户端会话管理技术
    把要共享的数据保存到客户端
    每次请求时,把会话信息带到服务器端,从而实现多次请求的数据共享
  • 作用:可以保存客户端访问网站的相关内容,从而保证每次访问时先从本地缓存中获取,以此提高效率
  • 特点:
    • 是一个普通的Java类
    • 两个必须属性:name 和value
    • 发送:HttpServletResponse.addCookie(Cookie对象)
    • 每个网站最多20个Cookie,浏览器存储的Cookie总数不大于300个,每个Cookie大小限制在4kb
    • 获取所有Cookie对象:HttpServletRequest.getCookie()

Cookie属性

属性名 作用 是否重要
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方法)
  • 向客户端添加Cookie:void HttpServletResponse.addCookie(Cookie cookie)
  • 获取所有的Cookie:Cookie[] HttpServletRequest.getCookies()

练习

  • 需求说明:通过Cookie记录最后访问时间,并在浏览器上显示出来
  • 最终目的:掌握Cookie的基本使用,从创建到添加客户端,再到从服务器端获取
  • 实现步骤
    1. 通过响应对象写出一个提示信息
    2. 创建Cookie对象,指定name和value
    3. 设置Cookie最大存活时间
    4. 通过响应对象将Cookie对象添加到客户端
    5. 通过请求对象获取Cookie对象
    6. 将Cookie对象中的访问时间写出
@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); } } }

注意事项

  • 数量限制
    每个网站最多只能用20个Cookie,且大小不能超过4kb,所有网站的Cookie总数不超过300个
  • 名称限制
    Cookie的名称只能包含ASCII码表中的字母、数字字符。不能包含逗号、分号、空格,不能以$开头。
    Cookie的值不支持中文
  • 存活时间限制setMaxAge()方法接收数字
    负整数:当前会话有效,浏览器关闭则清除(默认)
    0:立即清除
    正整数:以秒为单位设置存活时间
  • 访问路径限制
    取自第一次访问的资源路径前缀
    只要以这个前缀开头(包括子级路径)就能获取到,反之获取不到
    设置路径:setPath()方法设置指定路径

Session

  • HttpSession:服务器端会话管理技术
    本质也是采用客户端会话管理技术

    只不过在客户端保存的是一个特殊标识,而共享的数据保存到了服务器端的内存对象中。
    每次请求时,会将特殊标识带到服务器端,根据这个标识来找到对应的内存空间,从而实现数据共享
    是Servlet规范中四大域对象之一的会话域对象

  • 作用:可以实现数据共享
    域对象 功能 作用
    ServletContext 应用域 在整个应用之间实现数据共享
    ServletRequest 请求域 在当前的请求或请求转发之间实现数据共享
    HttpSession 会话域 在当前会话范围之间实现数据共享

常用方法

返回值 方法名 说明
void setAttribute(String name, Object value) 设置共享数据
Object getAttribute(String name) 获取共享数据
void removeAttribute(String name) 移除共享数据
String getId() 获取唯一标识名称
void Invalidate() 让session立即失效

对象获取

  • HttpSession 是一个接口,对应的实现类对象是通过HttpServletRequest 对象来获取
    返回值 方法名 说明
    HttpSession getSession() 获取HttpSession对象
    HttpSession getSession(boolean create) 获取HttpSession对象,未获取到是否自动创建(默认true)

练习

  • 需求说明:通过第一个Servlet 设置共享数据用户名,并在第二个Servlet 获取到
  • 最终目的:掌握HttpSession 的基本使用,如何获取和使用
  • 实现步骤
    1. 在第一个 Servlet 中获取请求的用户名
    2. 获取 HttpSession 对象
    3. 将用户名设置到共享数据中
    4. 在第二个 Servlet 中获取 HttpSession 对象
    5. 获取共享数据用户名
    6. 将获取到的用户名响应给客户端浏览器
// 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+"");
}

注意事项

  • 唯一标识的查看:借助浏览器开发者工具
  • 浏览器禁用Cookie
    方式一:通过提示信息告知用户,大部分网站采用的解决方式【推荐】
    方式二:通过resp.enconeURL方法实现url重写(地址栏拼接jsessionid)【了解】
  • 钝化和活化
    • 钝化:序列化。把长时间不用,但还不到过期时间的HttpSession进行序列化,写到磁盘上
    • 活化:相反的状态
  • 钝化时间
    第一种情况: 当访问量很大时,服务器会根据getLastAccessTime 来进行排序,对长时间不用,但还没到过期时间的HttpSession进行序列化
    第二种情况: 当服务器进行重启的时候,为了保持客户HttpSession 中的数据,也要对其进行序列化

HttpSession 的序列化由服务器自动完成,我们无需关心

JSP

  • JSP(Java Server Pages):是一种动态网页技术标准
  • JSP 部署在服务器上,可以处理客户端发送的请求,并根据请求内容动态的生成 HTML、XML 或其他格式文档的 Web网页,然后再响应给客户端。
  • Jsp 是基于Java 语言的,它的本质就是 Servlet
类别 使用场景
HTML 开发静态资源,无法添加动态资源
CSS 美化页面
JavaScript 给网页添加一些动态效果
Servlet 编写Java 代码,实现后台功能处理
JSP 包含了显示页面技术,也具备Java代码功能

快速入门

  1. 创建一个web项目
  2. 在web 目录下创建一个 index.jsp 文件
  3. 在文件中写一句内容为:这是我的第一个jsp
  4. 部署并启动项目
  5. 通过浏览器测试
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


    第一个jsp



执行过程

  1. 客户端浏览器发送请求到Tomcat 服务器
  2. Tomcat 服务器解析请求地址
  3. 找到具体的应用
  4. 找到对应的jsp文件
  5. 将jsp文件翻译为.java的文件
  6. 编译Java文件
  7. 响应给客户端

文件内容介绍

  • 生成的Java 文件目录
    继承自 HttpJspBase类,而HttpJspBase继承自 HttpServlet(JSP本质上就是一个 Servlet)
    jsp显示页面本质上就是通过获取输出流对象并通过write写出

语法

  • JSP注释:<%-- 注释的内容 --%>
  • Java代码块:<% Java代码 %>
  • JSP表达式:<%=表达式%>
  • JSP声明:<%! 声明变量或方法 %>

System.out.println():普通输出语句,输出在控制台上
out.println():JspWriter 对象,将内容输出在浏览器页面上,不会自动换行
<%="要输出的内容"%>就相当于out.println("要输出的内容")
在声明中,如果加!,代表声明的是成员变量;如果不加!,代表声明的是局部变量;如果是声明方法,就必须加!

指令

  • page 指令:<%@ 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 指令:可以包含其他页面
    <%@ include file=包含的页面 %>
  • taglib 指令:可以引入外部标签库
    <%@ 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 对象
    • 是 JSP 独有的, Servlet 中没有
    • 是四大域对象之一的页面域对象,还可以操作其他三个域对象中的属性
    • 可以获取其他八个隐式对象
    • 生命周期是随着 JSP 的创建而存在,随着 JSP 的结束而消失。每个JSP 页面都有一个 PageContext 对象

四大域对象

域对象名称 范围 级别 备注
PageContext 页面范围 最小,只能在当前页面使用 因范围太小,开发中用的很少
ServletRequest 请求范围 一次请求或当前请求转发用 请求转发之后,再次转发时请求域丢失
HttpSession 会话范围 多次请求数据共享时使用 多次请求共享数据,但不同的客户端不能共享
ServletContext 应用范围 最大,整个应用都可以使用 尽量少用,如果对数据有修改需要做同步处理

MVC模型

  • M(Model):模型。 用于封装数据,封装的是数据模型
  • V(View):视图。 用于显示数据,动态资源用 JSP页面,静态资源用 HTML 页面
  • C(Controller):控制器。 用于处理请求和响应,例如 Servlet

Java Web从入门到实战_第18张图片

学生管理系统3

登录功能

  1. 创建一个web目录
  2. 在web目录下创建一个index.jsp
  3. 在页面中获取会话域中的用户名,获取到了就显示添加和查看功能的超链接,没获取到就显示登录功能的超链接
  4. 在web目录下创建一个login.jsp。实现登录页面
  5. 创建 LoginServlet,获取用户名和密码
  6. 如果用户名为空,则重定向到登录页面
  7. 如果不为空,将用户名添加到会话域中,再重定向到首页
<%-- 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);
    }
}

EL表达式

  • EL(Expression Language):表达式语言
  • 在 JSP 2.0 规范中加入的内容,也是 Servlet 规范的一部分
  • 作用:在 JSP 页面中获取数据,让我们的 JSP 脱离 Java代码块和 JSP 表达式
  • 语法:${表达式内容}

快速入门

  1. 创建一个web 项目
  2. 在web 目录下创建 jsp文件
  3. 在文件中向域对象添加数据
  4. 使用三种方式获取域对象中的数据(Java代码块、JSP表达式、EL表达式)
  5. 部署并启动项目
  6. 通过浏览器测试
<%--
  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>

获取数据

  1. 获取基本数据类型的数据
    ${数据名}
  2. 获取自定义对象类型的数据
    ${对象名.属性名}
    这里获取到对象的成员变量的原理是通过调用get方法获取,所以不必担心private私有问题
  3. 获取数组类型的数据
    ${数组名[索引]}
  4. 获取List 集合类型的数据
    ${集合[索引]}
  5. 获取 Map 集合类型的数据
    ${集合.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>

注意事项

  • EL 表达式没有空指针异常
  • EL 表达式没有索引越界异常
  • EL 表达式没有字符串的拼接

使用细节

  • EL 表达式能够获取到四大域对象的数据,根据名称从小到大在域对象中查找
  • 还可以获取 JSP 其他八个隐式对象,并调用对象中的方法

运算符

  • 关系运算符
    运算符 作用 示例 结果
    == 或 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}

JSTL

  • JSTL(Java Server Pages Standarded Tag Library):JSP 标准标签库
  • 主要提供给开发人员一个标准通用的标签库
  • 开发人员可以利用这些标签来取代 JSP 页面上的Java代码,从而提高程序的可读性,降低程序的维护难度
组成 作用 说明
core 核心标签库 通用的逻辑处理
fmt 国际化 不同地域显示不同语言
functions EL 函数 EL 表达式可以使用的方法
sql 操作数据库 了解
xml 操作XML 了解

核心标签

标签名称 功能分类 属性 作用
<标签名:if> 流程控制 核心标签库 用于条件判断
<标签名:choose>
<标签名:when>
<标签名:otherwise>
流程控制 核心标签库 用于多条件判断
<标签名:forEach> 迭代遍历 核心标签库 用于循环遍历

使用步骤

  1. 创建一个 web 项目
  2. 在 web目录下创建一个 WEB-INF 目录
  3. 在 WEB-INF 目录下创建一个 libs 目录,将 JSTL 的 jar 包导入
  4. 创建 JSP 文件,通过 taglib 导入 JSTL 标签库
  5. 对流程控制和迭代遍历的标签进行使用
  6. 部署并启动项目
  7. 通过浏览器查看
<%@ 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}

Filter

  • 在程序中访问服务器资源时,当一个请求到来,服务器首先判断是否有过滤器与请求资源相关联,如果有,过滤器可以将请求拦截下来,完成一些特定的功能,再由过滤器决定是否交给请求资源。如果没有相关联的过滤器则像之前那样直接请求资源了。响应也是类似的
  • 过滤器一般完成用于通用的操作,例如:登录验证、统一编码处理、敏感字符过滤等等…

概述

  • 是一个接口。如果想实现过滤器的功能,必须实现该接口
  • 核心方法
    返回值 方法名 作用
    void init(FilterConfig config) 初始化方法
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 对请求资源和响应资源过滤
    void destroy() 销毁方法
  • 配置方式
    方式一:配置文件(web.xml)
    方式二:注解方式

FilterChain

  • FilterChain 是一个接口,代表过滤器链对象。由Servlet 容器提供实现类对象。直接使用即可
  • 过滤器可以定义多个,就会组成过滤器链
  • 核心方法
    返回值 方法名 说明
    void doFilter(ServletRequest request, ServletResponse response) 放行方法

如果有多个过滤器,在第一个过滤器中调用下一个过滤器,依此类推。直到到达最终访问资源。
如果只有一个过滤器,放行时,就会直接到达最终访问资源

过滤器使用

  • 需求说明:通过 Filter 过滤器解决多个资源写出中文乱码的问题
  • 实现步骤
    1. 创建一个 web 项目
    2. 创建两个 Servlet 功能类,都向客户端写出中文数据
    3. 创建一个 Filter 过滤器实现类,重写 doFilter 核心方法
    4. 在方法内解决中文乱码,并放行
    5. 部署并启动项目
    6. 通过浏览器测试
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>
    
  • 多个过滤器使用顺序
    如果有多个过滤器,取决于过滤器映射的顺序

生命周期

  • 创建
    当应用加载时实例化对象并执行init初始化方法
  • 服务
    对象提供服务的过程,执行 doFilter 方法
  • 销毁
    当应用卸载时或服务器停止时对象销毁。执行 destroy 方法

FilterConfig

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>

Listener

  • 观察者设计模式,所有的监听器都是基于观察者设计模式的
  • 三个组成部分
    1. 事件源:触发事件的对象
    2. 事件:触发的动作,封装了事件源
    3. 监听器:当事件源触发事件后,可以完成功能
  • 在程序当中,我们可以对:对象的创建销毁、域对象中属性的变化、会话相关内容进行监听
  • Servlet 规范中共计 8 个监听器,监听器都是以接口形式提供,具体功能需要我们自己来完成

监听器

监听对象的创建和销毁的监听器

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
真正的事件指的是会话域中数据钝化、活化的操作

监听器的使用

  • 监听对象的
    ServletContextListener
    HttpSessionListener
    ServletRequestListener
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("监听到了对象的销毁");
    }
}
  • 监听属性变化的
    ServletContextAttributeListener
    HttpSessionAttributeListener
    ServletRequestAttributeListener
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);
    }
}
  • 会话相关的感知型
    HttpSessionBindingListener
    HttpSessionActivationListener

配置监听器

  • 注解方式:@WebListener
  • xml文档方式
    <listener>
    	<listener-class>监听器对象实现类的全路径listener-class>
    listener>
    

学生管理系统优化

解决乱码

使用过滤器实现所有资源的编码统一

  1. 将请求和响应对象转换为和HTTP相关的HttpServletRequest和HttpServletResponse
  2. 设置编码格式
  3. 放行
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);
    }
}

检查登录

使用过滤器解决登录检查

  1. 将请求和响应对象转换为和HTTP相关的HttpServletRequest和HttpServletResponse
  2. 获取会话域对象中的数据
  3. 判断用户名
  4. 重定向(或定时刷新)到登录页面或放行

注解配置过滤器时指定多个拦截路径
@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");
        }
    }
}

优化JSP页面

通过EL表达式和JSTL替换之前的Java代码块和JSP表达式

完整代码:https://github.com/HelloCode66/StudentSystem


Mysql


JDBC


Mybatis


JavaScript


jQuery


AJAX


Vue + Element


Redis


Maven基础


Web项目实战-黑马页面

你可能感兴趣的:(Java,WEB从入门到实战,java,linux,mysql,后端,java-ee)