Java Web
概念
javaWeb 是指所有通过 java 语言编写可以通过浏览器访问的程序的总称。
javaWeb 是基于请求和响应来开发的
请求是什么?
请求是指客户端给服务器发送数据,叫请求 Request
响应是什么
响应是指服务端给客户端回传数据,叫响应 Response
请求和响应是成对出现的
Web 资源分类
web 资源按实现的技术和呈现的效果不同,又称为静态资源和动态资源两种。
静态资源: html、css、js、txt、mp4视频、mp3音频、jpg图片
动态资源:jsp 页面、Servlet 程序
常用的 Web 服务器
-
Tomcat
tomca
是由Apache
组织提供的一种服务器,提供对jsp
和Servlet
的支持,它是一种轻量级的 web 容器(即服务器),也是当前应用最广的javaWeb
服务器(免费) -
Jboos
是一个遵循 JavaEE 规范的、开放代码的、纯 Java 的 EJB 服务器,它支持所有的 JavaEE 规范(免费)
-
GlassFish
由
Oracle
公司开发的一款 javaWeb 服务器,是一款强健的商业服务器,达到产品级质量(应用很少) -
Resin
是
CAUCHO
公司的产品,是一个非常流行的服务器,对 servlet 和 JSP 提供了良好的支持,性能也比较优良,resin 自身采用 Java 语言开发(收费,应用比较多) -
WebLogic
是
Oracle
公司的产品,是目前应用最广泛的 web 服务器,支持 javaEE 规范,而且不断的完善以适应新的开发要求,适合大型项目(收费,用的不多,适合大公司)
Tomcat 服务器和 Servlet 版本关系
Servlet规格 | JSP规范 | EL规格 | WebSocket规范 | JASPIC规格 | Apache Tomcat版本 | 最新发行版本 | 支持的Java版本 |
---|---|---|---|---|---|---|---|
4.0 | 2.3 | 3.0 | 1.1 | 1.1 | 9.0.x | 9.0.27 | 8及更高版本 |
3.1 | 2.3 | 3.0 | 1.1 | 1.1 | 8.5.x | 8.5.47 | 7及更高版本 |
3.1 | 2.3 | 3.0 | 1.1 | 不适用 | 8.0.x(已取代) | 8.0.53(已取代) | 7及更高版本 |
3.0 | 2.2 | 2.2 | 1.1 | 不适用 | 7.0.x | 7.0.96 | 6及更高版本 (WebSocket为7及更高版本) |
2.5 | 2.1 | 2.1 | 不适用 | 不适用 | 6.0.x(已归档) | 6.0.53(已归档) | 5及更高版本 |
2.4 | 2.0 | 不适用 | 不适用 | 不适用 | 5.5.x(已存档) | 5.5.36(存档) | 1.4及更高版本 |
2.3 | 1.2 | 不适用 | 不适用 | 不适用 | 4.1.x(已归档) | 4.1.40(已归档) | 1.3及更高版本 |
2.2 | 1.1 | 不适用 | 不适用 | 不适用 | 3.3.x(已存档) | 3.3.2(已存档) | 1.1及更高版本 |
Servlet 程序从 2.5 是现在使用最多的版本 (xml 配置)
到了 Servlet 3.0 之后,就是注解版本 Servlet 使用
Tomcat 的使用
Tomcat 安装
下载 tomcat zip 文件解压即可,并配置和 java 环境。
Tomcat 目录
-
bin
专门用来存放 Tomcat 服务器的可执行程序
-
config
专门用来存放 Tomcat 服务器的配置文件
-
lib
专门用来存放 Tomcat 服务器的 jar 包
-
logs
专门用来存放 Tomcat 服务器运行时输出的日志信息
-
temp
专门用来存放 Tomcat 服务器运行时的临时数据
-
webapps
专门用来存放部署的 web 工程
-
work
是 Tomcat 的工作是的目录,用来存放 Tomcat 运行时 jsp 翻译为 Servlet 的源码,和 Session 钝化(序列化)的目录。
如何启动 Tomcat
点击 startup.bat 启动
找到 Tomcat 安装目录下的 bin 目录下的 startup.bat
,双击点击即可启动 Tomcat。
打开浏览器在地址栏中输入 http://localhost:8080
来测试 Tomcat 是否成功启动。它是一个 Tomcat 的欢迎页面。
使用命令行启动
打开 cmd 窗口,cd 到 tomcat bin
目录(也可以把 tomcat bin 目录配置到 path 环境变量中),使用命令 catalina run
启动 tomcat
关闭 Tomcat
- 直接点击 Tomcat 窗口的 X 按钮。
- 在 Tomcat 窗口中使用
Ctrl + C
- 找到 Tomcat bin 目录的
showdown.bat
点击即可关闭
修改 Tomcat 端口号
找到 Tomcat conf
目录,找到 server.xml
中的 Connect 标签的 port 属性进行修改
,修改完端口号一定要重启 Tomcat 才能生效。
如果修改 Tomcat 端口号为 80
,在使用时可以不写 80
端口号
http 协议的默认端口号是 80,浏览器解析时会自动抹掉端口号 80
如何部署 web工程到 Tomcat
-
只需要把 web 工程的目录拷贝到
Tomcat
的webapps
目录下即可。 -
找到 Tomcat 下的
conf\Catalina\localhost
目录,创建一个工程配置xml
文件。<Context path="/abc" docBase="E:\\xxx\\xxx\\projectName"> </Context>
-
<Context>
元素将本地文件系统中的一个目录映射成一个可供 Web 浏览器访问的虚拟目录。 -
path
指定在浏览器中的访问路径 -
docBase
指定项目实际路径
-
ROOT 的工程访问,以及默认 index.html 访问
当我们在浏览器中输入如下地址访问时:
http://ip:port ------ 没有工程名的时候,默认访问的是 ROOT 工程
当我们在浏览器中输入如下地址访问时:
http://ip:port/工程名 ------ 没有资源名,默认访问 index.html 页面
java Web 工程
idea 中创建 javaWeb工程
使用 idea 2022 为例创建 java web 工程为例
- 点击项目创建节目的
New Project
,项目名称和包名取好后,点击CREATE
按钮 - 右键点击创建的项目的文件夹,点击
Add Frameworks Support
,勾选Web Application
后,再点击ok
在 module 中添加 web 支持也是一样,只是点击 module 文件夹,也是点击Add Frameworks Support
,勾选 Web Application
后,再点击 ok
目录
-
src
java 源代码
-
web
专门用来存放
web
工程的资源文件,比如html、css、js
文件等等注意:web 文件夹上面有一个蓝色小点,说明 web 目录正确配置了
-
WEB-INF
是一个受服务器保护的目录,浏览器无法直接访问此目录的内容。
位于 WEB-INF 目录下的
web.xml
文件,它是整个动态 web 工程的配置部署描述文件。可以在这里配置很多 web 工程的组件,比如Servlet 程序、Filter、Listener、Session 超时等
idea 中 tomcat 实例和其他细节
-
修改模块的工程路径,在
Deployment
中修改Application context
值即可完成访问路径修改可以修改为
/projectName
-
修改端口号,在
Server
中修改HTTP port
的值即可 -
修改启动浏览器,在
Server
中修改After launch
后面下拉框中的浏览器即可 -
配置点击运行按钮时的动作。在
Server
中的On 'Update' action
后面的下拉选项默认是Restart server
,表示重启 server。可以选择Update classes and resources
,来进行热更新
Artifacts
项目的打包部署设置,这个是项目配置里面比较关键的地方
官方定义:
即编译后的 Java 类,Web 资源等的整合,用以测试、部署等工作。再白话一点,就是说某个 module 要如何打包,例如 war exploded、war、jar、ear
等等这种打包形式。某个 module 有了 Artifacts 就可以部署到应用服务器中了。
jar:Java ARchive,通常用于聚合大量的 Java 类文件、相关的元数据和资源(文本、图片等)文件到一个文件,以便分发Java平台应用软件或库;
war:Web application ARchive,一种 JAR 文件,其中包含用来分发的 JSP、Java Servlet、Java 类、XML 文件、标签库、静态网页(HTML 和相关文件),以及构成 Web 应用程序的其他资源;
exploded:在这里你可以理解为展开,不压缩的意思。也就是 war、jar 等产出物没压缩前的目录结构。建议在开发的时候使用这种模式,便于修改了文件的效果立刻显现出来。
默认情况下,IDEA 的 Modules 和 Artifacts 的 output 目录已经设置好了,不需要更改,打成 war 包的时候会自动在 WEB-INF 目录下生成 classes,然后把编译后的文件放进去。
其实,实际上,当你点击运行 tomcat 时,默认就开始做以下事情:
- 编译,IDEA 在保存/自动保存后不会做编译,不像 Eclipse 的保存即编译,因此在运行 server 前会做一次编译。编译后 class 文件存放在指定的项目编译输出目录下;
- 根据
artifact
中的设定对目录结构进行创建; - 拷贝
web
资源的根目录下的所有文件到artifact
的目录下; - 拷贝编译输出目录下的
classes
目录到artifact
下的WEB-INF
目录下; - 拷贝
lib
目录下所需的jar
包到artifact
下的WEB_INF
目录下; - 运行
server
,运行成功后,如有需要,会自动打开浏览器访问指定url
。
Facets
Facets: 英文翻译“(事物的)方面特征”,表述了在 module
(项目/模块/组件)中使用的各种各样的框架、技术和语言。这些 Facets
让 IDEA 知道怎么对待 module
内容,并保证与相应的框架和语言保持一致。
使用 Facet
s 能让我们下载并配置 framework
所必须的组件,会自动生成各种各样的描述符,并存储在适当的位置,等等。
大多数 Facets 可以无冲突得添加到 Module 中。
也有一些 Facets 是继承其他 Facets 的,这些 Facets 的添加就必须先添加他们的父 Facets,这些 Facets 也要依赖Intellij IDEA 的相关插件是否开启.
例如 web 项目,他有一个很重要的作用是配置 web.xml
文件的访问路径和部署 root
的位置
Facets 可以增加某种组件支持,如 web 支持
Servlet
什么是 Servlet?
- servlet 是 JavaEE 规范之一,规范就是接口
- Servlet 是 JavaWeb 三大组件之一,三大组件分别是:
Servlet程序、Filter过滤器、Listener监听器
- Servlet 是运行在服务器上的一个 java 小程序,它可以接收客户端发送过来的请求,并响应数据给客户端。
如何创建 Servlet 程序?
-
编写一个类去实现 Servlet 接口
-
实现 service 方法,处理请求,并响应数据
-
到 web.xml 中注册 Servlet 组件
<?xml version="1.0" encoding="UTF-8"?> <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"> <!--servlet 标签给 Tomcat 配置 Servlet 程序--> <servlet> <!--Servlet 程序的名称,一般是类名--> <servlet-name>HelloServlet</servlet-name> <!--Servlet 程序的全类名--> <servlet-class>cn.xx.HelloServlet</servlet-class> </servlet> <!--给 Servlet 程序配置访问地址--> <servlet-mapping> <!--该标签的作用是告诉服务器,我当前配置的地址给哪个 Servlet 程序使用--> <servlet-name>HelloServlet</servlet-name> <!--配置访问地址 1. 如果配置 / 服务器解析的时候,表示地址为:http://ip:port/工程名 2. 如果配置 /hello 服务器解析的时候,表示地址为:http://ip:port/工程名/hello --> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
Servlet 查找定位
浏览器资源位置去匹配 web.xml
中的 <servlet-mapping>
标签中的 <url-pattern>
中的值,找到后通过
<servlet-name>
的值去找到对应 servlet
处理类。
Servlet 生命周期
-
Servlet 构造器 (仅在第一次访问时调用)
-
init 方法(仅在第一次访问时调用)
-
service 方法(每次访问都会调用)
-
destroy 方法(在 web 工程停止时调用)
GET POST 请求分发
在 service 中进行 GET、POST 分发
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
String method = request.getMethod();
if ("GET".equals(method)) {
System.out.println("GET METHOD");
}else if ("POST".equals(method)){
System.out.println("POST METHOD");
}
}
继承 HttpServlet
实际使用中,一般继承 HttpServlet
来进行开发
public class BuyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("request get: "+ req.getQueryString());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("request post: "+req.getParameter("username")+" "+req.getParameter("stu_class"));
}
}
idea 创建 Servlet 程序
- 在项目包目录上点击右键,再点击
new
,再选择Servlet
- 填写类名,可选是否使用基于
servlet3
的注解的配置。(我这里使用 xml 配置) - 在 web.xml 中配置
<servlet-mapping>
请求映射路径。
Servlert 继承关系
Interface Servlet <------------ Class GenericServlet <----------------- Class HttpServlet
各自的作用
-
Servlet
只是负责定义 Servlet 程序的访问规范
-
GenericServlet
实现了 Servlet 接口,做了很多空实现。并持有一个
ServletConfig
类的引用,并对 ServletConfig 的使用做了一些方法。public ServletConfig getServletConfig() public ServletContext getServletContext()
-
HttpServlet
继承了抽象类 GenericServlet 的
service
方法,并实现了请求的分发。在分发的doGet、doPost
等方法中只是做了抛异常的处理。
ServletConfig
在继承的 Servlet 类中可以在 init 方法中直接使用 servletConfig 对象
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init");
}
在继承 HttpServlet 类中可以使用下面的代码获取
ServletConfig servletConfig = getServletConfig();
ServletConfig 的作用
-
可以获取 Servlet 程序的别名,也就是 web.xml 中
<servlet-name>
标签中的值String servletName = servletConfig.getServletName();
-
可以获取初始化参数的值,在 web.xml 的
<servlet> 的 <init-param> 中的键值对
String username = servletConfig.getInitParameter("username");
-
可以获取 ServletContext 对象
ServletContext servletContext = servletConfig.getServletContext();
<servlet>
<!--Servlet 程序的名称,一般是类名-->
<servlet-name>HelloServlet</servlet-name>
<!--Servlet 程序的全类名-->
<servlet-class>cn.xx.HelloServlet</servlet-class>
<!--初始化的数据-->
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
</servlet>
ServletContext
- Servlet 是一个接口,它表示 Servlet 上下文对象
- 一个 web 工程,只有一个
ServletContext
对象实例 ServletContext
对象是一个域对象- ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁。
域对象
可以在不同的 Servlet 中进行数据传递的对象称为域对象。
域对象必须有的方法
void setAttribute(name,value);//存储数据的方法
Object getAttribute(name);//根据 name 获取对应数据值
void removeAttribute(name);//删除数据
ServletContext 的作用
-
获取 web.xml 中配置的上下文参数
context-param
context-param 是上下文参数(属于整个 web 工程,可以配置多个 context-param
ServletContext servletContext = getServletConfig().getServletContext(); String password = servletContext.getInitParameter("password");
<!--context-param是上下文参数(属于整个web工程,可以配置多个context-param)--> <context-param> <param-name>password</param-name> <param-value>123456</param-value> </context-param>
-
获取当前的工程路径,格式为:/工程路径
ServletContext servletContext = getServletConfig().getServletContext(); String contextPath = servletContext.getContextPath(); System.out.println("contextPath: "+ contextPath);
-
获取部署到服务器上的工程绝对路径,映射到 idea 代码中的 web 目录
ServletContext servletContext = getServletConfig().getServletContext(); String realPath = servletContext.getRealPath("/");
path 必须以
/
开始,/
表示当前 Web 应用的根目录。 -
像 Map 一样存储数据。
ServletContext 存放数据
context.setAttribute("key1","value1");
String val = context.getAttribute("key1");
context.removeAttribute("key1");
HTTP 协议
GET 请求
-
请求行
- 请求方式 GET
- 请求的资源路径 [+?+请求参数]
- 请求的协议版本 HTTP/1.1
-
请求头
由 key : value 组成,不同的键值对,表示不同的含义
Accept
:告诉服务器,客户端可以接收的数据类型Accept-Language
:告诉服务器,客户端可以接收的语言类型User-Agent
:浏览器的信息Accept-Encoding
:告诉服务器,客户端可以接收的数据编码(压缩)格式Host
:表示请求的服务器的 ip 和端口号Connection
:告诉服务器请求连接如何处理。Keep-Alive
告诉服务器回传数据不要马上关闭,保持一小段时间的连接。Closed
马上关闭。
POST 请求
-
请求行
- 请求方式 POST
- 请求的资源路径 [+?+请求参数]
- 请求的协议版本 HTTP/1.1
-
请求头
由 key : value 组成,不同的键值对,表示不同的含义
Referer
: 表示请求时,浏览器地址中的地址(从哪来)Content-Type
: 表示发送的数据的类型。application/x-www-form-urlencoded
表示提交的数据格式是:name=value&name=value,然后对其进行 url 编码。url 编码是把非英文的内容转换为 %xx%xx
multipart/form-data
表示以多段的形式提交数据给服务器(以流的形式提交,用于上传)Content-Length
: 表示发送数据的长度Cache-Control
表示如何控制缓存,no-cache 表示无缓存。 -
空行
-
请求体
发送给服务器的数据
常用的请求头
Accept
:告诉服务器,客户端可以接收的数据类型
Accept-Language
:告诉服务器,客户端可以接收的语言类型
User-Agent
:浏览器的信息
Host
:表示请求的服务器的 ip 和端口号
GET 和 POST 请求分类
GET 请求
- form 标签 method 为 get
- a 标签
- link 标签引入 css
- script 标签引入 js
- img 标签引入图片
- iframe 引入 html 页面
- 在浏览器地址栏中输入地址按回车
POST 请求
- form 标签 method 为 post
响应 HTTP 协议格式
-
响应行
- 响应的协议
- 响应状态码
- 响应状态描述
-
响应头
由 key : value 组成,不同的键值对,表示不同的含义
Server
: 表示服务器的信息Content-Type
: 表示响应的数据的类型。Content-Length
: 表示响应数据的长度Date
: 请求响应的时间。(格林时间) -
空行
-
响应体
回传给客户端的数据
常用的响应码
-
200
请求成功
-
302
请求重定向
-
404
请求服务器已收到,但请求的数据不存在
-
500
请求服务器已收到,服务器内部错误
MIME
MIME 是 HTTP 协议中的数据类型
MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式。
MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。
浏览器通常使用 MIME 类型(而不是文件扩展名)来确定如何处理 URL,因此 Web 服务器在响应头中添加正确的 MIME 类型非常重要。如果配置不正确,浏览器可能会无法解析文件内容,网站将无法正常工作,并且下载的文件也会被错误处理。
语法
MIME 类型通用结构:type/subtype
MIME类型对大小写不敏感,但是传统写法都是小写。
两种主要的 MIME 类型在默认类型中扮演了重要的角色:
-
text/plain 表示文本文件的默认值。
-
application/octet-stream 表示所有其他情况的默认值。
常见的 MIME 类型
- 超文本标记语言文本 .html、.html:text/html
- 普通文本 .txt: text/plain
- RTF 文本 .rtf: application/rtf
- GIF 图形 .gif: image/gif
- JPEG 图形 .jpeg、.jpg: image/jpeg
- au 声音文件 .au: audio/basic
- MIDI 音乐文件 mid、.midi: audio/midi、audio/x-midi
- RealAudio 音乐文件 .ra、.ram: audio/x-pn-realaudio
- MPEG 文件 .mpg、.mpeg: video/mpeg
- AVI 文件 .avi: video/x-msvideo
- GZIP 文件 .gz: application/x-gzip
- TAR 文件 .tar: application/x-tar
详细请参考 MIME 类型 | 菜鸟教程 (runoob.com)
HttpServletRequest
每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到 Request 对象中,然后传递到 service 方法 (doGet、doPost) 中给我们使用。我们可以通过 HttpServletRequst
对象,获取到所有的请求信息。
HttpServletRequest 常用方法
-
String getRequestURI();
获取请求的资源路径
-
StringBuffer getRequestURL();
获取请求资源的绝对路径
-
String getRemoteHost();
获取客户端的 ip 地址
-
String getHeader(String var1);
获取指定请求头
-
String getMethod();
获取请求方法
-
String getParameter(String var1);
获取请求的参数(一个 key 对应一个值)
-
String[] getParameterValues(String var1);
获取多个值的请求参数(一个 key 对应多个值)
POST 请求的乱码问题
设置请求的编码解决请求乱码问题,一般设置为 UTF-8
void setCharacterEncoding(String var1) throws UnsupportedEncodingException;
注意:必须在获取请求参数前设置请求编码才能生效
请求转发
请求收到后,从一个资源跳到另一个资源。
//向请求域中传递数据
req.setAttribute("param1","value6666");
//获取请求调度器,设置好请求路径
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/save");
//请求转发
requestDispatcher.forward(req,resp);
请求转发的特点
- 浏览器的地址没有变化
- 它们是一次请求
- 它们共享 Request 域中的数据
- 可以转发到
WEB-INF
目录下 - 无法访问工程以外的资源
请求包含
请求包含是指使用 RequestDispatcher 的 include 方法将 当前的 Servlet 请求和其他的 Web 资源进行处理。改响应头既包含当前 Servlet 的响应内容也包含其他 Servlet 的响应内容。
//获取请求调度器,设置好请求路径
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/save2");
//请求包含
requestDispatcher.include(req,resp);
html 的 base 标签
base 标签设置页面相对路径工作是的参照的地址,href 属性就是参照的值
<base href="http://xxx/xxx/"/>
所有相对路径在工作的时候都会参照当前浏览器地址中的地址来进行跳转
javaweb 中的相对路径和绝对路径
相对路径
- . 表示当前目录
- …(两个点) 表示上一级目录
- 资源名 表示当前目录/资源名
绝对路径
http://ip:port/工程路径/资源路径
web 中斜杠的不同意义
在 web 中 / 是一种绝对路径
/ 被浏览器解析,得到的地址是 http://ip:port
/ 被服务器解析,得到的地址是 http://ip:port/工程路径
绝对路径的使用:
<url-pattern>/test</url-pattern>
- servletContext.getRealPath(“/”);
- request.getRequestDispacher(“/”);
特殊情况
把 / 发送给服务器解析,得到 http://ip:port
response.sendRediect("/");
referer 请求头
Referer 请求头包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。 服务端一般使用 Referer 请求头识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等。
HttpServletResponse
每次只要有请求进入 Tomcat 服务器,Tomcat 服务器都会创建一个 Response 对象,然后传递到 service 方法 (doGet、doPost) 中给我们使用。我们可以通过 HttpServletResponse 对象,返回数据给客户端。
添加响应头
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setContentLength(int length)
addHeader 方法可以添加同名的响应头。而 setHeader 方法会覆盖同名的响应头。
setContentLength 方法设置 Content-Length
响应头字段的值
响应流
字节流,用于下载(传递二进制数据)
ServletOutputStream getOutputStream() throws IOException;
字符流,常用语传递字符串。响应的默认字符集是 ISO-8859-1
,不支持中文
PrintWriter getWriter() throws IOException;
往客户端回传数据
使用流写入数据给客户端
response.getOutputStream().write("hello world 好伐好伐".getBytes(StandardCharsets.UTF_8));
response.getWriter().write("111111");
响应的乱码问题
设置响应的字符集可以防止响应内容乱码
//设置服务器使用 UTF-8 字符集
response.setCharacterEncoding("UTF-8");
//设置浏览器也使用 UTF-8 字符集
response.setHeader("Content-Type", "text/html; charset=UTF-8");
或
它会同时设置服务器和浏览器都使用 UTF-8 字符集,还设置了响应头
注意:此方法需要在获取流对象之前调用才会生效
response.setContentType("text/html; charset=UTF-8");
两种流只能使用一种,否则会报错
禁止浏览器缓存页面
通过设置响应的响应头来禁止浏览器缓存页面
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
请求重定向
请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端去请求新的地址(因为之前的地址可能失效了)
请求重定向的第一种方法
请求重定向,第一次请求响应码 为 302
,响应头中 Location
会携带新的地址。第二次请求会请求新的地址。
//第一次重定向的请求的响应
response.setStatus(302);
response.setHeader("Location", "http://localhost:8080/webmodule01/redirect2");
请求重定向的第二种方法 (推荐使用)
response.sendRedirect("http://localhost:8080/module01/redirect2");
请求重定向特点
- 浏览器地址栏会发生变化
- 两次请求
- 不共享 Request 域中的数据
- 不能访问 WEB-INF 下的资源
- 可以访问工程以外的资源
JavaEE 三层架构
1. Web 层
Web 层的作用有:
-
获取请求参数,封装成 Bean
-
调用 Service 层,处理业务
-
响应数据给客户端、请求转发、重定向
Servlet 程序,对应技术有 SpringMvc
Web 层对应 java 的 controller
2. Service 层
Service 层的作用有:
- 处理业务逻辑
- 调用持久层保存数据到数据库
Spring 框架
Service 层对应 java 的 service 接口和 service.impl 接口实现类
3. Dao 层
只负责跟数据库进行交互,执行 CRUD 操作。
JDBC,对应有 Mybatis、JPA 等等
Dao 层对应 java 的 Dao 接口和 dao.impl Dao 接口实现类
javaEE 对应的其他类有 javaBean 和 测试类
文件上传和下载
文件上传
文件上传步骤:
- 要有一个 form标签,
method = post
- form 标签的
encType
属性值必须为multipart/form-data
值 - 在 form 标签中使用
<input type='file' name='file'>
添加上传的文件 - 编写服务器代码接收,处理上传的数据
encType = multipart/form-data 表示提交的数据,以多段的形式进行拼接,然后以二进制的形式发送给服务器
请求头中的关键数据
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryVMxBfKK3iE7W6FSO
Content-Type : 表示提交的数据类型。
boundary : 表示每段数据的分割符,它的值由浏览器每次随机生成。
----WebKitFormBoundaryVMxBfKK3iE7W6FSO 表示每段数据的开始
----WebKitFormBoundaryVMxBfKK3iE7W6FSO-- 后面多了两个减号,表示数据的结束标记
commons-fileupload.jar 的使用
commons-fileupload.jar 依赖 commons-io.jar,所以需要导入这两个 jar 包
ServletFileUpload
用于解析上传数据
FileItem
表示每个表单项
ServletFileUpload
常用方法
-
public static final boolean isMultipartContent(HttpServletRequest request)
判断当前上传的数据格式是否是多段上传
-
public List<FileItem> parseRequest(HttpServletRequest request)
解析上传数据
FileItem
常用方法
-
boolean isFormField()
判断当前这个表单项是普通表单项还是上传的文件类型
true 表示普通表单项
false 表示上传的文件类型
-
String getFieldName()
获取表单项的 name 属性值
-
String getString()
获取当前表单项的值
-
String getName()
获取上传的文件名
-
void write(File var1) throws Exception
将上传的文件写入到参数 var1 指向的位置
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//先判断上传的数据是否是多段数据
if(ServletFileUpload.isMultipartContent(request)){
FileItemFactory fileItemFactory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
List<FileItem> list = servletFileUpload.parseRequest(req);
for(FileItem item:list){
if(item.isFormField()){
//普通表单项
}else{
//上传的文件
item.write(new File("d"\\"+item.getName()));
}
}
}
}
文件下载
文件下载步骤:
- 获取需要下载的文件名
- 读取要下载的文件内容
- 通过响应头高速客户端返回的数据类型
- 还要告诉客户端收到的数据是用于下载使用
- 把下载的内容回传给客户端
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取需要下载的文件名
String name = request.getParameter("name");
System.out.println("name: " + name);
ServletContext context = getServletContext();
//2.读取要下载的文件内容
InputStream inputStream = context.getResourceAsStream(path);
String path = "/file/" + name;
System.out.println("path: " + path);
//获取文件的类型
String mimeType = context.getMimeType(path);
//3.通过响应头高速客户端返回的数据类型
response.setContentType(mimeType);
//4.告诉客户端收到的数据是用于下载使用
response.setHeader("Content-Disposition", "attachment; filename="+name);
System.out.println("mimeType: " + mimeType);
//5.把下载的内容回传给客户端
IOUtils.copy(inputStream, response.getOutputStream());
}
Content-Disposition
响应头,表示收到的数据怎样处理
attachment
表示附件,表示 用于下载。
filename=
表示指定下载的文件名
注意:
Google 浏览器
中如果文件名有中文,需要使用URL 编码
,再替换到 filename=右边的值
String encode = URLEncoder.encode("你好.jpg", "utf-8");
注意:
火狐浏览器
中如果文件名有中文,需要使用BASE64 编码
,header 格式为attachment; filename==?charset?B?xxx?=
response.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?"+
new BASE64Encoder().encode("你好.jpg".getBytes("UTF-8"))+"?=");
- =? 表示编码内容开始
- charset 表示字符集
- B 表示 BASE64 编码
- xxx 表示编码后的内容
- ?= 表示编码内容结束
使用 User-Agent 请求头判断浏览器类型
req.getHeader("User-Agent").contains("FireFox");//返回 true 表示是火狐浏览器
Cookie
Cookie 是在客户端
- Cookie 是服务器通知客户端保存键值对的一种技术。
- 客户端有了 Cookie 后,每次请求都会发送给服务器
- 每个 Cookie 的大小不超过 4K。
注意: Cookie 不支持中文以及特殊符号。可以对内容使用 BASE64 编码后,在进行使用
服务器向浏览器发送 Cookie 使用步骤
-
创建
Cookie
对象 -
通知客户端保存
Cookie
,通过响应头Set-Cookie
通知客户端保存 cookie。Set-Cookie: key1=value1
private void createCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie cookie = new Cookie("key1","value1");
response.addCookie(cookie);
response.setContentType("text/html; charset=UTF-8");
response.getWriter().write("cookie 创建成功");
}
浏览器向服务器发送 Cookie 步骤
-
通过请求头
Cookie
把 Cookie 信息发送给服务器Cookie: key1=value1; Idea-8296eef3=99ae362b-2ac2-4692-a6e7-469bd0e47a3a
-
服务器通过
request.getCookies()
方法获取到浏览器发送过来的所有 Cookie,它返回一个 Cookie 数组。
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
System.out.println("received cookie: " + cookie.getName() + "=" + cookie.getValue());
}
}
Cookie 的修改
第一种方式:
- 在构造器中创建一个相同 name 的 Cookie 对象,同时 value 设置为一个新值
- 调用
response.addCookie(cookie)
通知浏览器保存修改
第二种方式
- 先查询到需要修改的
cookie
对象 - 通过
cookie.setValue(newVal)
赋予新的值 - 调用
response.addCookie(cookie)
通知浏览器保存修改
Cookie 的生命控制
Cookie 的生命控制是指如何管理 Cookie 什么时候被删除
void setMaxAge(int expiry)
参数情况:
- 参数为正数,表示经过
expiry
秒就删除 - 参数为负数,表示浏览器一关,Cookie 就会被删除。默认就是 -1。浏览器上
Expires/Max-Age
显示为Seesion
级别 - 参数为 0,表示马上删除该 Cookie
Cookie 的 Path 属性
可以通过 cookie.setPath(path)
来设置 cookie 的 path 属性。
path 属性可以有效的过滤哪些 Cookie 可以发送给服务器,哪些不发。
path 属性是通过请求的地址来进行有效的过滤
例如:
-
Cookie1 path=/工程名称
-
Cookie2 path=/工程名称/aaa
请求地址如下:
-
http://ip:port/工程名称/a.html
Cookie1 发送,Cookie2 不发送
-
http://ip:port/工程名称/aaa/a.html
Cookie1 发送,Cookie2 发送
Seesion
Seesion 是一种将会话数据保存在服务器端的技术。数据是存放在服务端
- seesion 是一个接口(HttpSeesion)
- seesion 是一个会话,它是用来维护一个客户端和服务端之间关联的一种技术
- 每个客户端都有自己的一个 Seesion 会话
- Seesion 会话中,我经常用来保存用户登录之后的信息
使用 HttpServletRequest getSession()
方法创建 Seesion
HttpSession getSession()
第一次调用该方法表示创建 Seesion
会话
之后调用该方法表示获取前面创建好的 Seesion
会话
使用HttpSession isNew() 方法判断 seesion 是否是新创建的
boolean isNew()
true 表示新创建的
false 表示之前创建的
每个会话都有唯一的 id 值
Seesion 的 getId() 方法
String getId()
Seesion 域存取数据
取数据
HttpSession session = request.getSession();
Object val1 = session.getAttribute("key1");
存数据
HttpSession session = request.getSession();
session.setAttribute("key1","value1");
Seesion 设置超时时间
void setMaxInactiveInterval(int var1)
设置 seesion 的存活时间,单位为秒。默认存活时间为 30 分钟。(在 Tomcat 的 web.xml
配置文件中配置了 seesion-timeout
时间是 30 分钟)
当参数为正数时,表示 seesion 存活时长为 var1 秒
当参数为负数时,表示 seesion 永不过期(极少使用)
可以在自己项目的 web.xml 中配置该属性
<seesion-config>
<seesion-timeout>20</seesion-timeout>
</seesion-config>
获取 Seesion 超时时间
int getMaxInactiveInterval()
设置 Seesion 会话马上超时
void invalidate()
浏览器与 Seesion 的关系
服务器每次创建 Seesion 会话的时候,都会创建一个 Cookie 对象,这个 Cookie 对象的 key 永远是 JSEESIONID
,值是新创建出来的 Seesion 的 id 值。
通过响应把创建出来的 Seesion 的 id 返回给 客户端。在 Set-Cookie
响应头中的中会有该 Seesion 的 id 数据。
Set-Cookie: JSESSIONID=E75CB401E7763AC94007887ACFA1E77B; Path=/fmjw; HttpOnly
客户端将此 Cookie 存起来,客户端在下次请求服务器时,会将此 Cookie 发送给服务器,服务器根据此 Cookie 的JSEESIONID
去内存中找出该 Seesion 对象。
Seesion 技术底层技术是基于 Cookie 技术来实现的,存放 Seesion 的 id 的 Cookie 的存活时间是 Seesion 级别的,所以当浏览器关闭时,该 Cookie 就被删除了。同时 Seesion 由于没有了 Cookie 中的 JSEESIONID ,所以会创建新的 Seesion
这就是浏览器打开时,Seesion 就存在,关闭浏览器 Seesion 就销毁了
使用 kaptcha Google 验证码
- 导入 kaptcha jar 包
- 注册 KaptchaServlet 程序(可以使用 kaptcha jar 包中自带的 KaptchaServlet)
- 在 KaptchaServlet 中创建随机验证码
- 将验证码存放在 Seesion 中,方便服务器验证客户端发送过来的验证码。
- 生成验证码图片,并返回给客户端。
//验证码配置属性
private Producer kaptchaProducer(){
Properties properties=new Properties();
//图片的宽度
properties.setProperty("kaptcha.image.width","100");
//图片的高度
properties.setProperty("kaptcha.image.height","40");
//字体大小
properties.setProperty("kaptcha.textproducer.font.size","32");
//字体颜色(RGB)
properties.setProperty("kaptcha.textproducer.font.color","0,0,0");
//验证码字符的集合
properties.setProperty("kaptcha.textproducer.char.string","123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
//验证码长度(即在上面集合中随机选取几位作为验证码)
properties.setProperty("kaptcha.textproducer.char.length","4");
//图片的干扰样式
properties.setProperty("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");
DefaultKaptcha Kaptcha = new DefaultKaptcha();
Config config=new Config(properties);
Kaptcha.setConfig(config);
return Kaptcha;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Producer producer = kaptchaProducer();
//创建随机验证码
String text = producer.createText();
System.out.println("text=" + text);
HttpSession session = request.getSession();
//存放验证码到 Seesion 中
session.setAttribute("kaptcha",text);
//生成验证码并返回给客户端
BufferedImage image = producer.createImage(text);
ImageIO.write(image,"jpg",response.getOutputStream());
}
服务器验证验证码
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//从 seesion 中获取验证码
String token = (String)session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
//获取完成后,从 seesion 中移除验证码
session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);
//从 request中获取 验证码 参数的值
String code = request.getParameter("code");
// 比较验证码
if (token != null && token.equalsIgnoreCase(code)){
System.out.println("验证成功");
}
}
前端更新图片验证码
$(function () {
// 刷新验证码
$("#verification").bind("click", function () {
$(this).hide().attr('src', '/verification?random=' + Math.random()).fadeIn();
});
});
Filter
- Filter 过滤器是 JavaWeb 的三大组件之一。
- Filter 过滤器它是 JavaEE 的规范,也就是接口。
- Filter 过滤器它的作用是
拦截请求、过滤响应
拦截请求的场景
- 权限检查
- 日志操作
- 事务操作
Filter
Filter 过滤器的使用步骤
- 编写一个类去实现
Filter
接口 - 实现过滤方法
doFilter()
- 到
web.xml
中配置Filter
以及它的拦截路径
Fillter 生命周期
- 构造器初始化 (在 web 工程启动的时候就已经执行。)
init
方法(在 web 工程启动的时候就已经执行。)doFilter
方法(每次拦截到请求,就会执行。)destroy
方法(在 web 工程停止的时候执行。)
web.xml 中配置 Filter 过滤器
<!--filter 标签用于配置一个 Filter 过滤器-->
<filter>
<!--给 Filter 过滤器取别名-->
<filter-name>MyFilter</filter-name>
<!--Filter 过滤器全类名-->
<filter-class>cn.xx.web.MyFilter</filter-class>
<!--配置 filter 的初始化数据,可以配置多组,和 servlet 一样-->
<init-param>
<param-name>test</param-name>
<param-value>123456</param-value>
</init-param>
<init-param>
<param-name>test2</param-name>
<param-value>66666</param-value>
</init-param>
</filter>
<!--filter-mapping 配置 Filter 过滤器的拦截路径-->
<filter-mapping>
<!--filter-name 指定当前拦截路径给哪个 filter 使用-->
<filter-name>MyFilter</filter-name>
<!--url-pattern 配置拦截路径-->
<!-- / 表示http:ip:port/工程路径-->
<url-pattern>/*</url-pattern>
</filter-mapping>
FilterConifg 类
Filter 过滤器的配置文件类。Tomcat 每次创建 Filter 的时候,也同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。
FilterConfig
类的作用是获取 filter
过滤器的配置内容
- 获取 filter 的名称,
<filter-name>
标签中的值 - 获取在 filter 中配置的
<init-param>
初始化的值 - 获取 ServletContext 的值
public void init(FilterConfig config) throws ServletException {
//获取 filter-name 标签的值
String filterName = config.getFilterName();
//获取 filter 中配置的初始化数据
String test = config.getInitParameter("test");
//获取 ServletContext 的值
ServletContext servletContext = config.getServletContext();
System.out.println("filterName: "+filterName);
System.out.println("test: "+test);
System.out.println("servletContext: "+servletContext);
}
FilterChain
FilterChain.doFilter() 方法的作用
- 执行下一个 Filter 过滤器 (如果有下一个 Filter)
- 执行目标资源 (如果没有 Filter)
在多个 Filter 过滤器执行的时候,它们执行的优先顺序是由它们在 web.xml 中配置的顺序
决定的!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AkEFYgid-1687073342237)(D:\self\notebook\java\javaweb\filter_order.png)]
多个 Filter 过滤器的执行的特点
- 所有 Filter 和目标资源默认都执行在同一个线程中
- 多个 Filter 共同执行的时候,它们都使用同一个 Request 对象
Filter 拦截路径
拦截路径可以配置多个
-
精确匹配
<url-pattern> /target.html </url-pattern>
匹配的地址为 http://ip:port/工程名称/target.html
-
目录匹配
<url-pattern> /res/* </url-pattern>
匹配的地址为 http://ip:port/工程名称/res/*
-
后缀名匹配
<url-pattern> *.jpg </url-pattern>
表示请求的地址必须以 .jpg 结尾才会拦截到
注意:后缀名匹配的不能带有 / ,如 / *.jgp (两种通配方式不能同时使用)
Filter 过滤器只关心请求的地址是否匹配,不关心请求的资源是否存在 !!!
可以通过 Filter 中的后置代码来给 Servlet 中的 Service 逻辑增加事务的提交和回滚
@Override
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
// 获得Connection对象
Connection connection = JDBCUtils.getConnection();
try {
// 开启事务,将默认的自动提交改为false
connection.setAutoCommit(false);
// 放行,执行相应代码
chain.doFilter(req, res);
// 如果无异常的话,执行到这一步就都成功了,所以提交事务
connection.commit();
} catch (Exception e) {
// 处理异常
try {
// 若有异常则回滚数据
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
// 关闭事务
JDBCUtils.releaseConnection();
}
}
Listener
概念
Listener 表示监听器,是 JavaWeb 三大组件之一。
监听器可以监听就是在 application、session、request 三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件
分类
监听器分类 | 监听器名称 | 作用 |
---|---|---|
ServletContext监听 | ServletContextListener | 用于对ServletContext对象进行监听(创建、销毁) |
ServletContextAttributeListener | 用于对ServletContext对象中属性的监听(增删改属性) | |
Seesion监听 | HttpSeesionListener | 对Seesion对象的整体状态的监听(创建、销毁) |
HttpSeesionAttributeListener | 用于对Seesion对象中属性的监听(增删改属性) | |
HttpSeesionBindingListener | 监听对象与Seesion的绑定和解除 | |
HttpSeesionActivationListener | 对Seesion数据的钝化和活化的监听 | |
Request监听 | ServletRequestListener | 对Request对象进行监听(创建、销毁) |
ServletRequestAttributeListener | 对Request对象中的属性的监听(增删改属性) |
使用
public class MyListener implements ServletContextListener{
public MyListener() {
}
@Override
public void contextInitialized(ServletContextEvent sce) {
/* This method is called when the servlet context is initialized(when the Web application is deployed). */
//加载资源
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
/* This method is called when the servlet Context is undeployed or Application Server shuts down. */
}
}