Servlet: server applet
运行在服务器端的小程序
- Servlet就是一个接口,定义了Java类被浏览器访问到(
tomcat识别
)的规则。 - 自定义一个类,实现
Servlet
接口,复写方法。
快速入门
- 创建
JavaEE
项目
- 定义一个类,实现
Servlet
接口package cn.web; import javax.servlet.*; import java.io.IOException; public class ServletDemo1 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
- 实现接口中的抽象方法
- 配置Servlet
在web.xml
中配置, 写在标签里面
demo1 cn.web.ServletDemo1 demo1 /demo1
执行原理
- 当服务器接受到客户端浏览器的请求后,会解析请求
URL
路径,获取访问的Servlet
的资源路径 - 查找
web.xml
文件,是否有对应的
标签体内容。 - 如果有,则在找到对应的
全类名 -
tomcat
会将字节码文件加载进内存,并且创建其对象 - 调用
service
方法
生命周期
- 被创建:执行·方法,只执行一次
-
Servlet什么时候被创建?
- 默认情况下,第一次被访问时,Servlet被创建
- 可以配置执行Servlet的创建时机。
- 在
标签下配置 - 第一次被访问时,创建
的值为负数
- 在服务器启动时,创建
的值为0或正整数
- 第一次被访问时,创建
- 在
-
Servlet的
init
方法,只执行一次,说明一个Servlet
在内存中只存在一个对象,Servlet
是单例的- 多个用户同时访问时,可能存在线程安全问题。
- 解决:尽量不要在
Servlet
中定义成员变量。即使定义了成员变量,也不要对修改值
-
- 提供服务:执行
service
方法,执行多次- 每次访问
Servlet
时,Service方法都会被调用一次。
- 每次访问
- 被销毁:执行
destroy
方法,只执行一次-
Servlet
被销毁时执行。服务器关闭时,Servlet
被销毁 - 只有服务器正常关闭时,才会执行
destroy
方法。 -
destroy
方法在Servlet
被销毁之前执行,一般用于释放资源
-
Servlet3.0
-
好处:
- 支持注解配置。可以不需要
web.xml
了。
- 支持注解配置。可以不需要
-
步骤:
- 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建
web.xml
- 定义一个类,实现
Servlet
接口 - 复写方法
- 在类上使用
@WebServlet
注解,进行配置
@WebServlet("资源路径")
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WebServlet { String name() default "";//相当于
String[] value() default {};//代表urlPatterns()属性配置 String[] urlPatterns() default {};//相当于 int loadOnStartup() default -1;//相当于 WebInitParam[] initParams() default {}; boolean asyncSupported() default false; String smallIcon() default ""; String largeIcon() default ""; String description() default ""; String displayName() default ""; }
- 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建
urlpartten:Servlet
访问路径
- 一个
Servlet
可以定义多个访问路径 :@WebServlet({"/d4","/dd4","/ddd4"})
- 路径定义规则:
-
/xxx
:路径匹配 -
/xxx/xxx
:多层路径,目录结构 -
*.do
:扩展名匹配
-
HttpServlet
Servlet的体系结构
-
GenericServlet
:将Servlet
接口中其他的方法做了默认空实现,只将service()
方法作为抽象, 将来定义Servlet类时, 可以继承GenericServlet
,实现service()
方法即可 -
HttpServlet
:对http
协议的一种封装,简化操作- 定义类继承
HttpServlet
- 复写
doGet/doPost
方法
- 定义类继承
Request
request
对象和response
对象的原理
1. `request`和`response`对象是由服务器创建的。我们来使用它们
2. `request`对象是来获取请求消息,`response`对象是来设置响应消息
request对象继承体系结构
ServletRequest -- 接口
| 继承
HttpServletRequest -- 接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat)
request
功能
获取请求消息数据
@WebServlet("/demo2")
public class ServletDemo2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String contextPath = request.getContextPath();
System.out.println("contextPath = " + contextPath);
String servletPath = request.getServletPath();
System.out.println("servletPath = " + servletPath);
String method = request.getMethod();
System.out.println("method = " + method);
String queryString = request.getQueryString();
System.out.println("queryString = " + queryString);
String requestURI = request.getRequestURI();
System.out.println("requestURI = " + requestURI);
StringBuffer requestURL = request.getRequestURL();
System.out.println("requestURL = " + requestURL);
String remoteAddr = request.getRemoteAddr();
System.out.println("remoteAddr = " + remoteAddr);
}
}
contextPath = /UserDemo_war_exploded
servletPath = /demo2
method = GET
queryString = name=IIce
requestURI = /UserDemo_war_exploded/demo2
requestURL = http://localhost:8080/UserDemo_war_exploded/demo2
remoteAddr = 0:0:0:0:0:0:0:1
其他功能
-
获取请求参数通用方式:不论get还是post请求方式都可以使用下列方法来获取请求参数
-
String getParameter(String name)
:根据参数名称获取参数值username=zs&password=123
-
String[] getParameterValues(String name)
:根据参数名称获取参数值的数组hobby=xx&hobby=game
-
Enumeration
:获取所有请求的参数名称getParameterNames() -
Map
:获取所有参数的map集合getParameterMap() - 中文乱码问题
- 解决:在获取参数前,设置
request
的编码request.setCharacterEncoding("utf-8");
- 解决:在获取参数前,设置
-
-
请求转发:一种在服务器内部的资源跳转方式
-
步骤:
- 通过
request
对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
- 使用
RequestDispatcher
对象来进行转发:forward(ServletRequest request, ServletResponse response)
- 通过
-
特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中。
- 转发是一次请求
-
-
共享数据:
- 域对象:一个有作用范围的对象,可以在范围内共享数据
-
request域
:代表一次请求的范围,一般用于请求转发的多个资源中共享数据 - 方法:
-
void setAttribute(String name,Object obj)
:存储数据 -
Object getAttitude(String name)
:通过键获取值 -
void removeAttribute(String name)
:通过键移除键值对
-
-
获取
ServletContext
:ServletContext getServletContext()
JavaBean
用于封装JavaBean的
-
JavaBean:标准的Java类
- 要求:
- 类必须被
public
修饰 - 必须提供
空参
的构造器 - 成员变量必须使用
private
修饰 - 提供公共
setter
和getter
方法
- 类必须被
- 功能:封装数据
- 要求:
概念:
成员变量:
属性:setter
和getter
方法截取后的产物, 例如:getUsername() --> Username--> username
-
方法:
setProperty()
getProperty()
-
populate(Object obj , Map map)
:将map集合的键值对信息,封装到对应的JavaBean
对象中
HTTP
响应头
常见的响应头:
-
Content-Type
:服务器告诉客户端本次响应体数据格式以及编码格式 -
Content-disposition
:服务器告诉客户端以什么格式打开响应体数据- 值:
-
in-line
:默认值,在当前页面内打开 -
attachment;filename=xxx
:以附件形式打开响应体。文件下载
-
- 值:
Response对象
设置响应消息
设置响应行
- 格式:
HTTP/1.1 200 ok
- 设置状态码:
setStatus(int sc)
设置响应头
setHeader(String name, String value)
设置响应体
- 获取输出流
- 字符输出流:
PrintWriter getWriter()
- 字节输出流:
ServletOutputStream getOutputStream()
- 字符输出流:
- 使用输出流,将数据输出到客户端浏览器
重定向
//简单的重定向方法
response.sendRedirect("/responseDemo2");
- 重定向的特点:
redirect
- 地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求。不能使用request对象来共享数据
- 转发的特点:
forward
- 转发地址栏路径不变
- 转发只能访问当前服务器下的资源
- 转发是一次请求,可以使用request对象来共享数据
路径问题
- 相对路径:通过相对路径不可以确定唯一资源
如:
./index.html
不以
/
开头,以.
开头路径-
规则:找到当前资源和目标资源之间的相对位置关系
-
./
:当前目录 -
../
:后退一级目录
-
- 绝对路径:通过绝对路径可以确定唯一资源
服务器输出字符数据到浏览器
-
步骤:
- 获取字符输出流
- 输出数据
-
乱码问题:
-
PrintWriter pw = response.getWriter();
获取的流的默认编码是ISO-8859-1
- 设置该流的默认编码
- 告诉浏览器响应体使用的编码
//简单的形式,设置编码,是在获取流之前设置 response.setContentType("text/html;charset=utf-8");
-
ServletContext对象
概念
代表整个web应用,可以和程序的容器(服务器)来通信
获取
- 通过
request
对象获取
request.getServletContext();
- 通过
HttpServlet
获取
this.getServletContext();
功能
获取MIME类型
- MIME类型:在互联网通信过程中定义的一种文件数据类型
格式: 大类型/小类型 text/html image/jpeg
- 获取:
String getMimeType(String file)
域对象: 共享数据
setAttribute(String name,Object value)
getAttribute(String name)
removeAttribute(String name)
ServletContext
对象范围:所有用户所有请求的数据
获取文件的真实(服务器)路径
String getRealPath(String path)
String b = context.getRealPath("/b.txt");//web目录下资源访问
System.out.println(b);
String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问
System.out.println(c);
String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问
System.out.println(a);
文件下载
文件下载需求
- 页面显示超链接
- 点击超链接后弹出下载提示框
- 完成图片文件下载
分析
- 超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框。不满足需求
- 任何资源都必须弹出下载提示框
- 使用响应头设置资源的打开方式
content-disposition:attachment;filename=xxx
步骤
- 定义页面,编辑超链接
href
属性,指向Servlet
,传递资源名称filename
- 定义
Servlet
- 获取文件名称
- 使用字节输入流加载文件进内存
- 指定
response
的响应头:content-disposition:attachment;filename=xxx
- 将数据写出到
response
输出流
Cookie
保存在客户端
- 创建Cookie对象,绑定数据
new Cookie(String name, String value)
- 发送Cookie对象
response.addCookie(Cookie cookie)
- 获取Cookie,拿到数据
Cookie[] request.getCookies()
cookie的细节
-
一次可不可以发送多个
cookie
?- 可以
- 可以创建多个
Cookie
对象,使用response
调用多次addCookie
方法发送cookie
即可。
-
cookie
在浏览器中保存多长时间?- 默认情况下,当浏览器关闭后,
Cookie
数据被销毁 - 持久化存储:
-
setMaxAge(int seconds)
- 正数:将
Cookie
数据写到硬盘的文件中。持久化存储。并指定cookie
存活时间,时间到后,cookie
文件自动失效 - 负数:默认值
- 零:删除
cookie
信息
- 正数:将
-
- 默认情况下,当浏览器关闭后,
-
cookie
能不能存中文?- 在tomcat 8 之前 cookie中不能直接存储中文数据。
- 需要将中文数据转码---一般采用URL编码(
%E3
)
- 需要将中文数据转码---一般采用URL编码(
- 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
- 在tomcat 8 之前 cookie中不能直接存储中文数据。
-
cookie共享问题?
-
假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
- 默认情况下cookie不能共享
-
setPath(String path)
:设置cookie
的获取范围。默认情况下,设置当前的虚拟目录- 如果要共享,则可以将path设置为
"/"
- 如果要共享,则可以将path设置为
-
不同的tomcat服务器间cookie共享问题?
-
setDomain(String path)
:如果设置一级域名相同,那么多个服务器之间cookie可以共享-
setDomain(".baidu.com")
,那么tieba.baidu.com
和news.baidu.com
中cookie可以共享
-
-
-
Cookie的特点和作用
- cookie存储数据在客户端浏览器
- 浏览器对于单个cookie 的大小有限制(
4kb
) 以及 对同一个域名下的总cookie
数量也有限制(20个
)
- 作用:
-
cookie
一般用于存出少量的不太敏感的数据 - 在不登录的情况下,完成服务器对客户端的身份识别
-
Session
依赖于Cookie
, 保存在服务器端
- 获取HttpSession对象:
HttpSession session = request.getSession();
- 使用HttpSession对象:
Object getAttribute(String name) void setAttribute(String name, Object value) void removeAttribute(String name)
细节
-
当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
- 默认情况下。不是。
- 如果需要相同,则可以创建
Cookie
,键为JSESSIONID
,设置最大存活时间,让cookie
持久化保存。
Cookie c = new Cookie("JSESSIONID",session.getId()); c.setMaxAge(60*60); response.addCookie(c);
-
客户端不关闭,服务器关闭后,两次获取的
session
是同一个吗?- 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作
-
session
的钝化: 在服务器正常关闭之前, 将session
对象系列化到硬盘上 -
session
的活化: 在服务器启动后, 将session
文件转化为内存中的session
对象即可。
-
- 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作
-
session什么时候被销毁?
- 服务器关闭
-
session
对象调用invalidate()
。 -
session
默认失效时间 30分钟
选择性配置修改30
-
session的特点
- session用于存储一次会话的多次请求的数据,存在服务器端
- session可以存储任意类型,任意大小的数据
session与Cookie的区别
- session存储数据在服务器端,Cookie在客户端
- session没有数据大小限制,Cookie有
- session数据安全,Cookie相对于不安全
JSP(Java Server Pages)
JSP本质上就是一个Servlet
JSP的脚本: JSP定义Java代码的方式
-
<% 代码 %>
: 定义的java代码,在service
方法中。service
方法中可以定义什么,该脚本中就可以定义什么。 -
<%! 代码 %>
: 定义的java代码,在jsp转换后的java类的成员位置。 -
<%= 代码 %>
: 定义的java代码,会输出到页面上。输出语句中可以定义什么,该脚本中就可以定义什么。
JSP的内置对象
- 在jsp页面中不需要获取和创建,可以直接使用的对象
- jsp一共有9个内置对象。
变量名 | 真实类型 | 作用 |
---|---|---|
pageContext |
PageContext |
当前页面共享数据,还可以获取其他八个内置对象 |
request |
HttpServletRequest |
一次请求访问的多个资源(转发) |
session |
HttpSession |
一次会话的多个请求间 |
application |
ServletContext |
所有用户间共享数据 |
response |
HttpServletResponse |
响应对象 |
page |
Object |
当前页面(Servlet)的对象,this |
out |
JspWriter |
输出对象,数据输出到页面上 |
config |
ServletConfig |
Servlet的配置对象 |
exception |
Throwable |
异常对象 |
response.getWriter()
和out.write()
的区别:
- 在tomcat服务器真正给客户端做出响应之前,会先找
response
缓冲区数据,再找out
缓冲区数据。response.getWriter()
数据输出永远在out.write()
之前
El表达式
- 概念:
Expression Language
表达式语言 - 作用:替换和简化
jsp
页面中java
代码的编写 - 语法:
${表达式}
- 注意:
- jsp默认支持el表达式的。如果要忽略el表达式
- 设置jsp中page指令中:
isELIgnored="true"
忽略当前jsp页面中所有的el表达式 -
\${表达式}
:忽略当前这个el表达式
- 设置jsp中page指令中:
- jsp默认支持el表达式的。如果要忽略el表达式
使用
运算符
- 算数运算符:
+
-
*
/(div)
%(mod)
- 比较运算符:
>
<
>=
<=
==
!=
- 逻辑运算符:
&&(and)
||(or)
!(not)
- 空运算符:
empty
- 功能:用于判断字符串、集合、数组对象是否为null或者长度是否为0
-
${empty list}
:判断字符串、集合、数组对象是否为null或者长度为0 -
${not empty str}
:表示判断字符串、集合、数组对象是否不为null 并且长度>0
获取值
- el表达式只能从域对象中获取值
- 语法:
-
${域名称.键名}
:从指定域中获取指定键的值- 域名称:
-
pageScope
-->pageContext
-
requestScope
-->request
-
sessionScope
-->session
-
applicationScope
-->application(ServletContext)
-
- 举例:在request域中存储了
name=张三
- 获取:
${requestScope.name}
- 域名称:
${键名}
:表示依次从最小的域中查找是否有该键对应的值,直到找到为止。-
获取对象、List集合、Map集合的值
-
对象:
${域名称.键名.属性名}
- 本质上会去调用对象的getter方法
List集合:
${域名称.键名[索引]}
-
Map集合:
${域名称.键名.key名称}
${域名称.键名["key名称"]}
-
-
隐式对象
- el表达式中有11个隐式对象
-
pageContext
- 获取jsp其他八个内置对象
-
${pageContext.request.contextPath}
:动态获取虚拟目录
-
- 获取jsp其他八个内置对象
JSTL
概念:JavaServer Pages Tag Library
JSP标准标签库
是由Apache组织提供的开源的免费的jsp标签 <标签>
作用:用于简化和替换jsp页面上的java代码
使用步骤:
- 导入jstl相关jar包
- 引入标签库:taglib指令:
<%@ taglib %>
放在jsp头部 - 使用标签
常用的JSTL标签
-
if
:相当于java代码的if语句- 属性:
-
test
必须属性,接受boolean
表达式- 如果表达式为true,则显示if标签体内容,如果为false,则不显示标签体内容
- 一般情况下,test属性值会结合el表达式一起使用
- 注意:
-
c:if
标签没有else
情况,想要else
情况,则可以在定义一个c:if
标签
-
-
- 属性:
-
choose
:相当于java代码的switch语句- 使用
choose
标签声明 相当于switch
声明 - 使用
when
标签做判断 相当于case
- 使用
otherwise
标签做其他情况的声明 相当于default
- 使用
foreach
:相当于java代码的for语句
三层架构:软件设计架构
- 界面层(表示层):用户看的得界面。用户可以通过界面上的组件和服务器进行交互
- 业务逻辑层:处理业务逻辑的。
- 数据访问层:操作数据存储文件。
MVC
model
: dao(data access object)
操作数据库 包名xx.xx.dao
view
: jsp
包名xx.xx.web
, 接受用户参数, 封装数据完成显示
controller
: service
包名xx.xx.service
业务逻辑操作
Filter: 过滤器
概念
- 生活中的过滤器:净水器,空气净化器,土匪、
- web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
- 过滤器的作用:
- 一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤...
快速入门
步骤
- 定义一个类,实现接口
Filter
- 复写方法
- 配置拦截路径
web.xml
- 注解
代码
@WebFilter("/*")//访问所有资源之前,都会执行该过滤器
public class FilterDemo1 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("filterDemo1被执行了....");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
过滤器细节
web.xml配置
demo1
cn.itcast.web.filter.FilterDemo1
demo1
/*
过滤器执行流程
- 执行过滤器
- 执行放行后的资源
- 回来执行过滤器放行代码下边的代码
过滤器生命周期方法
-
init
:在服务器启动后,会创建Filter
对象,然后调用init
方法。只执行一次。用于加载资源 -
doFilter
:每一次请求被拦截资源时,会执行。执行多次 -
destroy
:在服务器关闭后,Filter
对象被销毁。如果服务器是正常关闭,则会执行destroy
方法。只执行一次。用于释放资源
过滤器配置详解
-
拦截路径配置:
- 具体资源路径:
/index.jsp
只有访问index.jsp
资源时,过滤器才会被执行 - 拦截目录:
/user/*
访问/user
下的所有资源时,过滤器都会被执行 - 后缀名拦截:
*.jsp
访问所有后缀名为jsp
资源时,过滤器都会被执行 - 拦截所有资源:
/*
访问所有资源时,过滤器都会被执行
- 具体资源路径:
-
拦截方式配置:资源被访问的方式
- 注解配置:
- 设置
dispatcherTypes
属性-
REQUEST
:默认值。浏览器直接请求资源 -
FORWARD
:转发访问资源 -
INCLUDE
:包含访问资源 -
ERROR
:错误跳转资源 -
ASYNC
:异步访问资源
-
- 设置
- web.xml配置
- 设置
标签即可
- 设置
- 注解配置:
过滤器链(配置多个过滤器)
执行顺序:如果有两个过滤器:过滤器1和过滤器2(入栈出栈)
- 过滤器1
- 过滤器2
- 资源执行
- 过滤器2
- 过滤器1
- 过滤器先后顺序问题:
- 注解配置:按照类名的字符串比较规则比较,值小的先执行
- 如:
AFilter
和BFilter
,AFilter
就先执行了。
- 如:
- web.xml配置:
谁定义在上边,谁先执行
- 注解配置:按照类名的字符串比较规则比较,值小的先执行
Listener:监听器
概念:web的三大组件之一。
- 事件监听机制
- 事件 :一件事情
- 事件源 :事件发生的地方
- 监听器 :一个对象
- 注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后,执行监听器代码
ServletContextListener:监听ServletContext对象的创建和销毁
- 方法:
-
void contextDestroyed(ServletContextEvent sce)
:ServletContext
对象被销毁之前会调用该方法 -
void contextInitialized(ServletContextEvent sce)
:ServletContext
对象创建后会调用该方法
-
- 步骤:
- 定义一个类,实现
ServletContextListener
接口 - 复写方法
- 配置
- web.xml
cn.web.listener.ContextLoaderListener - 注解:
@WebListener
- 定义一个类,实现