1.Servlet简介
Servlet(Server Applet)服务器的小程序。是用java编写的一个服务器程序,目的是和浏览器交互并且生成动态的web内容。Servlet广义上来讲指的是servlet接口,狭义上来讲指的是所有实现接口的实现类。
Servlet是指实现了Servlet接口类,Servlet运行于支持java的应用服务器(tomcat,Servlet是tomcat的一个组件)中。从原理上来讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务。
2.Servlet体系结构与Tomcat的关系
Servlet是Tomcat的一个组件。Servlet的功能需要依赖一个servlet-api.jar,这个包是由tomcat提供的。
Tomcat在初始化Servlet时,首先读取web.xml文件,根据web.xml文件中的参数信息初始化ServletConfig、ServletContext对象,同时帮助我们创建HttpServletRequest和HttpServletResponse对象一并交给Servlet实例,此时,Servlet就具有了相关的功能。
Servlet API 包含以下4个Java包:
1.javax.servlet:定义了servlet接口、GenericServlet抽象类等相关的通用接口和类。
2.javax.servlet.http: 主要定义了与HTTP协议相关的HttpServlet类,HttpServletRequest接口和HttpServletResponse接口。
3.javax.servlet.annotation:包含标注servlet,Filter,Listener的标注。它还为被标注元件定义元数据。
4.javax.servlet.descriptor:提供程序化登录Web应用程序的配置信息的类型。
3.Servlet实现方式
- 实现Servlet接口
- 继承GenericServelt抽象类(这个类是Servlet接口的一级实现类)
- 继承HttpServlet抽象类就可以间接的实现Servlet接口(位于javax.servlet.http包中的HttpServlet抽象类继承自GenericServlet类,是Servlet接口的二级实现类)
4. Get与Post请求
1.doGet、doPost方法与service方法的关系
在HttpServlet的API中,新增了两个特殊的方法doGet和doPost,这两个方法是对servlet方法的拆分,目的是希望不同的请求方式使用不同的方法处理。
这让大家联想到表单的两种常用提交方式get和post,如果是get提交方式则使用doGet方法处理,如果时post提交方式则使用doPost方法处理。
而service方法可以处理任何类型的请求,当我们去查看HttpServlet中service方法的源码,不难发现内部也通过对method请求方式做了验证决定调用doGet或doPost方法,所以三个方法之间的关系如下:
结论:
- 要么重写service方法
- 要么重写doget和dopost方法
二者选择其一
2.Get与Post请求的区别
1. 参数传递方式
Get:通过Url传递参数,Url与参数之间用?隔开,多个参数之间用&隔开,也是表单的默认提交参数。
Post:所有操作对用户来说都是不可见的,相对于get方式更安全。
2. 传递数据量大小不同
Get传送的数据量较小,这主要是因为受URL长度限制2kb-6kb;
Post传送的数据量较大,一般被默认为不受限制。
3. 信息缓存
Get提交的信息能被缓存,请求保留在浏览器历史记录中
Post提交的数据一般不能被缓存,请求不会保留在浏览器历史中
4. 编码方式与乱码处理问题
Get:默认编码类型是:application/x-www-form-urlencoded;Tomcat8之前的版本,默认编码格式是iso-8859-1,从Tomcat8版本之后默认编码改为UTF-8,所以如果是Tomcat8及以上版本就不需要进行转码处理,如果是Tomcat7及之前版本可以使用以下进行转码:
String name = request.getParameter(“name”);
String encodingName = new String(name.getBytes(“iso-8859-1”),””utf-8”) ;
Post: 支持多种编码类型,application/x-www-form-urlencoded或multipart/form-data.可以使用以下方法进行转码:
Request.setCharacterEncoding(“utf-8”);
在这里顺便说一下响应的乱码处理方法:
Response.setContentType(“text/html;charset=utf-8”);
5. 总结:
- get会把参数暴露在地址栏上,post不会;
- Get传递参数大小2-6kb,post没有限制
- Get会留下缓存,post不会
- 处理乱码:1. Get请求:tomcat8之后 默认字符集是utf-8 不需要处理2. Post请求: req.setCharacterEncoding(“utf-8”);
5. MVC设计模式
(一)分层开发
项目在实际开发过程中,会将整个项目从上到下分为表示层、业务逻辑层、数据访问层。三层开发是项目开发实践中典型的开发模式。
分层开发的目的:实现高内聚、低耦合。
各层的功能:
- 表示层:负责数据展示,搜集用户输入。即和用户进行交互的层。表示层一般是指jsp页面、html页面等。
- 业务逻辑层(service):负责处理功能模块的业务逻辑,以及界面层和数据层的数据传输。
- 数据访问层(dao):和数据库进行交互。一般在数据访问层会编写SQL语句完成增删改查的功能方法;(JDBC,Hibernate,mybatis)。
(二)MVC模式
MVC模式(Model-view-controller)是软件工程中的一种软件架构模式,他把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。这种模式用于应用程序的分层开发。
Model(模型):模型代表一个存取数据的对象或JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
View(视图):试图代表模型包含的数据的可视化,即对Model数据的呈现。
Controller(控制器):控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化更新视图。他是视图与模型分离开。
(三)MVC模式与分层的关系
Model不属于任何层,他可能在每个层中都会用到,是数据存储和传输的载体。V和C都属于表示层,所以在某些情况下,可以认为MVC模式是对表示层的进一步分层,通过C将数据显示与数据模型分类离,同样起到降低耦合性的作用,简化后续对程序的修改和扩展,并且是程序某一部分的重复利用成为可能。
(四)注意事项
- Servlet调用service,service调用dao
- Servlet不能直接调用dao
- Servlet不能去调用servlet
- Dao不能调用service和servlet
6. 多方法请求
1、目前一个servlet只能接受一个请求,项目是分模块开发的
2、用户模块,增删改查,需要5个servlet
3、使用多方法请求,可以让一个servlet来接收一个模块的请求
UserServlet 接收用户模块的所有请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="demo05?mark=insert">添加</a>
<a href="demo05?mark=query">查询</a>
<a href="demo05?mark=update">修改</a>
<a href="demo05?mark=delete">删除</a>
</body>
</html>
package com.ujiuye.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 多方法请求
* 一个servlet只有一个service方法,比如写项目,一个模块最低有增删改查4个功能
* 最低要创建5个servlet,项目有6个模块,30个servlet
*
* 用一个servlet去接收一个模块的所有请求
* UserServlet 去接收用户模块的所有请求
*
*/
public class Demo05Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//先去获取mark参数
String mark = req.getParameter("mark");
//常量放到前面判断 防止空指针异常
if("insert".equals(mark)) {
//说明是添加的功能
insert(req,resp);
}else if("query".equals(mark)) {
//查询
query(req,resp);
}else if("update".equals(mark)) {
//修改
update(req,resp);
}else if("delete".equals(mark)) {
//删除
delete(req,resp);
}
}
private void delete(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("删除的功能");
}
private void update(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("修改的功能");
}
private void query(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("查询的功能");
}
private void insert(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("执行添加的代码 调用service");
}
}
7. Servlet生命周期
(一)Servlet生命周期:从创建到销毁的全过程,共分为三个阶段
- 初始化init方法: 只会执行一次(启动tomcat的时候默认是不执行的,在访问的时候才会执行)
- 服务方法service: 可以执行多次
- 销毁方法destory: 只执行一次(停止服务器)
(二)测试Servlet的声明周期
1、创建一个servlet继承httpservlet,重写init,service,destroy方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="demo06">测试servlet生命周期</a>
</body>
</html>
ackage com.ujiuye.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Demo06Servlet extends HttpServlet {
public Demo06Servlet() {
System.out.println("无参构造方法执行了");
}
@Override
public void init() throws ServletException {
//初始化方法 只会执行一次
System.out.println("init方法执行了");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//服务方法 可以执行多次
System.out.println("service方法执行了");
}
public void destroy() {
//销毁的方法 只会执行一次
System.out.println("destroy方法执行了");
}
}
2、第一次访问servlet,实例化servlet,执行init方法,执行service
3、第二次访问servlet
4、停止服务器
通过以上案例发现Servlet默认情况下是在第一次访问时被创建并初始化的,为了减少内存的压力,我们 可否改变它的创建时机呢?
答案是肯定的。我们可以在web.xml文件中进行配置,使得Servlet在服务器启动时直接创建并初始化。
load-on-startup节点必须写在servlet节点的内部,且作为最后一个节点。取值必须是整数,如果是大于等于0的整数表示在服务器启动时就被创建并初始化,如果有多个Servlet设置了load-on-startup节点的 值,那么值越小越优先执行;如果是负数则表示第一次被访问时创建并初始化,也就是默认情况,可以省略不写。
![](https://img-blog.csdnimg.cn/dc2f0ea5c00e48f2b0b683847042626b.png)
** 总结:**
1、分为三个阶段
(1)初始化阶段 会执行init方法 只会执行一次
默认是在第一次访问servlet时进行执行,可以在web.xml进行配置,配置<load-on-startup> 让servlet随着tomcat的启动而进行 初始化,配置的值大于0即可,配置为负数就是默认情况,当多个 servlet配置了<load-on-startup>值越小的优先执行
(2)服务阶段 执行service方法 会执行多次
(3)销毁阶段 会执行destroy方法 只会执行一次 点击停止服务器
2、注意点
访问servlet会实例化servlet对象,发现构造方法只会执行一次,说明对象只创建了一
次,即单例模式。
8. Servlet映射方式(url-pattern)
1.第一种配置方式:/*
* 是通配符 例如:/hello、/admin/login、/*
/hello :<url-pattern>/hello<url-pattern>这个配置只拦截hello,其他的不拦截
/admin/login :层级目录的格式,请求的方式<url-pattern>/admin/login<url-pattern>
/* :拦截所有,无论是脚本、css、或者是单纯的一个页面,全部拦截
2. 第二种配置方式:*.?
*.do 表示特定的拦截方式,只拦截action中带.do的url(do可以换成任意字符)
<url-pattern>*.do</url-pattern>
3. URL的总结
servlet本身很特殊,因为前台的URL都会进入service方法或doGet、doPost方法,那么这些URL基本很少使用统配的形式,最常用的两种方式就是:/hello、/admin/login,而*.do的方式很少用。
正常情况下同一个业务实体的功能会对应一个servlet,例如:
用户管理UserServlet(用户所有的CRUD都在这个Servlet中执行,和页面无关)
权限控制RoleServlet(权限所有CRUD都在这个Servlet中执行)
9. Request对象
(1)Request理解
Request是由tomcat创建的。
Request对象是来获取请求信息的。
(2)Request对象的体系
ServletRequest 接口 javax.servlet
|^继承
HttpServletRequest 子接口 javax.servlet.http
(3)Request的作用
接收客户端的请求,获取请求中的信息。除了可以获取请求中携带的数据之外,还可以 获取比如主机地址、端口、请求方式、项目名称等一系列信息。
请求分类: 请求行、请求头、请求体。
![](https://img-blog.csdnimg.cn/a5aa7d4ebf0045c094dcfe354dcb8844.png)
![](https://img-blog.csdnimg.cn/5b970b8bd79847c8aa9c3155ef558786.png)
1、获取请求行数据
请求行中,我们可以通过request对象的相应方法获取到比如协议名、服务名、端口号、项目名称、请求方式、参数列表等信息。
"协议名:" request.getScheme();
"服务器:" request.getServerName();
"端口号:" request.getServerPort();
"项目名:" request.getContextPath();
"请求方式:" request.getMethod();
"参数字符串:" request.getQueryString();
"项目名+具体地址:" request.getRequestURI();
"获取请求的URL:" request.getRequestURL();
"获取请求的URL:" request.getServletPath();
package com.ujiuye.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;
/**
* 请求头
* "协议名:" request.getScheme();
* "服务器:" request.getServerName();
* "端口号:" request.getServerPort();
* "项目名:" request.getContextPath();
* "请求方式:" request.getMethod();
* "参数字符串:" request.getQueryString();
* "项目名+具体地址:" request.getRequestURI();
* "获取请求的URL:" request.getRequestURL();
* "获取请求的URL:" request.getServletPath();
*/
@WebServlet("/demo09")
public class Demo09Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
String scheme = req.getScheme();
System.out.println("scheme = " + scheme);
String serverName = req.getServerName();
System.out.println("serverName = " + serverName);
int serverPort = req.getServerPort();
System.out.println("serverPort = " + serverPort);
String contextPath = req.getContextPath();
System.out.println("contextPath = " + contextPath);
String method = req.getMethod();
System.out.println("method = " + method);
String queryString = req.getQueryString();
System.out.println("queryString = " + queryString);
String uri = req.getRequestURI();
System.out.println("uri = " + uri);
StringBuffer url = req.getRequestURL();
System.out.println("url = " + url);
String servletPath = req.getServletPath();
System.out.println("servletPath = " + servletPath);
}
}
2、获取请求头数据
请求头是当前对用户发送的数据的描述信息。
请求头信息在请求的时候不需要程序员手动添加,是浏览器发送的时候已经处理好的。
如果想查看请求头信息,也可以在Servlet中通过getHeader方法获取。
获取请求头数据的方法:
方法名描述
String getHeader(String name)
根据请求头的名称获取请求头信息
Enumeration getHeaderNames()
返回此请求包含的所有头名称的枚举
package com.ujiuye.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.util.Enumeration;
/**
* 请求头
*/
@WebServlet("/demo10")
public class Demo10Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//通过请求头的key获取对应的value
String host = req.getHeader("Host");
System.out.println("host = " + host);
//获取所有头的key
Enumeration<String> en = req.getHeaderNames();
//遍历
while (en.hasMoreElements()) {
String name = en.nextElement();
//通过name获取value
String value = req.getHeader(name);
System.out.println(name + "..." + value);
}
}
}
3、获取请求正文数据
请求体就是请求中携带的数据,也就是我们需要获取的参数
获取请求参数的方法:
方法名
描述
String getParameter(String name)
根据参数名获取参数值
String[] getParameterValues(String name)
根据参数名获取参数值(可以是多个值)
Enumeration getPatameterNames()
获取所有的参数名
Map<String,String[]> getParameterMap()
获取所有参数的map集合
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请求体</title>
</head>
<body>
<!--
-->
<form action="demo11" method="get">
账号: <input type="text" name="username"> <br>
密码: <input type="password" name="password"> <br>
性别: <input type="radio" name="sex" value="男"> 男
<input type="radio" name="sex" value="女">女 <br>
爱好: <input type="checkbox" name="hobby" value="唱">唱
<input type="checkbox" name="hobby" value="跳">跳
<input type="checkbox" name="hobby" value="rap">rap
<input type="checkbox" name="hobby" value="打篮球">打篮球 <br>
学校: <select name="school">
<option value="小学">小学</option>
<option value="中学">中学</option>
<option value="大学">大学</option>
</select>
<br>
简介: <textarea name="mark" cols="30" rows="10"></textarea> <br>
<input type="submit" value="点我">
</form>
</body>
</html>
package com.ujiuye.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.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
/**
* 请求体
*/
@WebServlet("/demo11")
public class Demo11Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//获取文本框、密码框、隐藏框、日期框
//通过name值获取value 没有传递参数获取的是""
String username = req.getParameter("username");
System.out.println("username = " + username);
//单选框 通过name值获取被选中单选框的value值 没有选中获取的是bull
String sex = req.getParameter("sex");
System.out.println("sex = " + sex);
//复选框 getParameterValues获取 没有选中获取的是null
String[] hobbies = req.getParameterValues("hobby");
System.out.println(Arrays.toString(hobbies));
//下拉列表 通过name值获取被选中option的value值
String school = req.getParameter("school");
System.out.println("school = " + school);
//简介 通过name值获取
String mark = req.getParameter("mark");
System.out.println("mark = " + mark);
System.out.println("-----------------------------------------------------------------------");
//一次获取所有的参数
Map<String, String[]> map = req.getParameterMap();
Set<String> set = map.keySet();
for (String key : set) {
System.out.println(key + "...." + Arrays.toString(map.get(key)));
}
System.out.println("-----------------------------------------------------------------------");
//获取所有的参数名
Enumeration<String> en = req.getParameterNames();
while (en.hasMoreElements()) {
System.out.println(en.nextElement());
}
}
}
10. Response对象
(1)Response理解
Response是由tomcat创建的
Response对象是来设置响应信息
(2)Response对象的体系
ServletResponse 接口
|^继承
HttpServletResponse 子接口
|^实现
org.apache.catalina.connector.ResponseFacade 实现类
(3)Response的作用
针对页面发送的请求做出数据响应,向页面输出信息,包括文本、图片、视频等。
响应分类: 响应行、响应头、响应体。
![](https://img-blog.csdnimg.cn/fbc729fd9ad34ce199f72c5387d2c82e.png)
1、设置响应行
响应行中包含的信息:可以通过开发者模式F12-Network查看
![](https://img-blog.csdnimg.cn/834cbf1125a947959be7fd411aabedf4.png)
由上图可知,响应行中包含协议和状态码
(1)HTTP协议
HTTP协议的特点:
1、 简单快捷。客户端向服务器请求时,只需要传送请求方法和路径。
2、灵活。HTTP协议允许传送任意格式的数据。正在传输的类型由content-type标明。
3、 无连接(长连接)。每个请求都建立一个连接,请求处理完毕并发送至客户端之后就断开连接。这样明显有其缺点,就是在需要连续发送请求时,需要为每一个请求单独的在此建立连接,很浪费时间和资源。
于是HTTP协议1.1版本之后引入了可持续连接,也就是在每个请求处理完毕后,他不会立刻就断开连接,而是在等待一段时间,如果在此期间又有新的请求过来,那么等待时间刷新,如果没有,则等待时间完毕后,连接关闭。
4、 无状态。是指协议对于每次请求的处理没有记忆能力,他不知道之前是否已经访问过,不保留访问痕迹。主要目的是保证数据传输的安全性。
HTTP的版本:
0.9 -适用于各种数据信息的简洁快速协议,仅限于传输文本
1.0 -该协议对每一次请求/响应建立并拆除一次连接,不支持长连接
1.1 -在1.0版本的基础上支持长连接keep-alive
HTTPS:以安全为目标的HTTP通道,简单的讲是HTTP的安全版本,即HTTP下加入SSL层,简称HTTPS。
其中HTTPS的安全基础为SSL,因此通过它的传输内容都是经过SSl加密的,他的主要作用可以分为两种:
- 建立一个信息安全通道来保证数据传输的安全
- 确保网站的真实性,凡是使用了HTTPS的网站,都可以通过点击浏览器地址栏的锁头标志来查看网站认证之后的真实信息。
HTTP底层协议:TCP协议
TCP的特点:面向连接,保证可靠性
TCP三次握手,因为HTTP是基于TCP协议的,所以也可以认为是HTTP的三次握手:
第一次握手:客户端向服务器发送一个请求消息,服务端收到信息后知道自己与客户端是可以连接成功的;
第二次握手:此时客户端并不知道服务端是否已经接收到了他的请求,所以服务端接收到消息后要向客户端做出响应,客户端的到服务端的反馈后,才确定自己与服务器是可以连接上的。
第三次握手:客户端确认与服务器建立连接后,才开始向服务器发送数据。
(2)状态码
响应状态码200表示响应成功,不同的状态码代表不同的含义。
1xx -信息,服务器收到请求,需要请求者继续执行操作
2xx -成功,操作被成功接收并处理
3xx -重定向,需要进一步的操作已完成请求
4xx -客户端错误,请求包含语法错误或无法请求
5xx -服务器错误,服务器在处理请求的过程中发生了错误
几种常见的状态码:
200 请求和响应成功
404 客户端的错误、浏览器url地址写错误、tomcat没有启动、servlet没有拦截路径
500 服务器错误、后台代码有问题、查看控制台寻找错误信息、java代码或者jsp代码出错、空指针异常
案例实现:
package com.ujiuye.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;
@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//设置错误的状态码和提示消息 测试一下 一般不用
resp.sendError(500,"你自己写的烂代码心里没有b数吗?");
}
}
2、设置响应头
当我们在浏览器中打开network工具时,每一次的请求响应数据,都可以被捕捉到,而在内容中Response Headers中的的内容就是当前这一次请求响应的响应头信息。
![](https://img-blog.csdnimg.cn/e0992786e64648539237846ab1c167fe.png)
设置响应头信息可以通过以下两种方法:
response.setHeader("Content-Type", "text/html;charset=utf-8");
response.addHeader("Content-Type", "text/html;charset=utf-8");
二者的区别:
response.setHeader(String name, String value);一个关键字对应一个值,如果设置
了多个值,则会覆盖。 name zhangsan name lisi
response.addHeader(String name, String value);一个关键字可以对应多个值
在实际开发中,同一个响应头信息只会对应一个值,所以在使用时一般没什么区别。
案例实现:
package com.ujiuye.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;
@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setHeader("name","zhangsan");
resp.setHeader("name","lisi");
resp.addHeader("age","17");
resp.addHeader("age","18");
}
}
3、设置响应体
响应的数据就是响应体。响应对象response在返回数据、响应数据的时候,会将一些HTML、text、流数据等信息通过响应主体返回给页面,而响应体返回给页面,而响应体绝大多数都是文本类型。
响应数据需要通过流来进行数据传输,而response自带的流有两个:
Response.getWriter() ==>PrintWriter 输出文本信息
Response.getOutputStream ==> ServletOutputStream 输出字节信息
注意:这两个流不能同时共存
需求:演示两个流不能同时共存
案例实现:
package com.ujiuye.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/demo03")
public class Demo03Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//设置请求和响应的字符集
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
/*//1、第一种响应流
PrintWriter w = resp.getWriter();
w.print("zhangsan");
//可以识别标签和样式
w.print("<h2 style='color:red;'>李四</h2>");*/
/*
2、第二种响应体 处理字节信息 处理字符没有优势
1、通过字符串的构造器将张三转成iso8859-1
2、配置tomcat的vm -Dfile.encoding=utf-8
才能在页面上看到汉字张三
*/
ServletOutputStream sos = resp.getOutputStream();
sos.print(new String("张三".getBytes(),"iso8859-1"));
}
}
案例:响应表格
package com.ujiuye.servlet;
import com.ujiuye.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.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
/**
* 响应表格
*/
@WebServlet("/demo04")
public class Demo04Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//设置请求和响应的字符集
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
List<Student> lists = new ArrayList<>();
lists.add(new Student(1,"张三1","男","吃饭","大学"));
lists.add(new Student(2,"张三2","男","吃饭","大学"));
lists.add(new Student(3,"张三3","男","吃饭","大学"));
lists.add(new Student(4,"张三4","男","吃饭","大学"));
lists.add(new Student(5,"张三5","男","吃饭","大学"));
lists.add(new Student(6,"张三6","男","吃饭","大学"));
PrintWriter w = resp.getWriter();
w.print("<table border=1 width=400px>");
w.print("<tr><td>学号</td><td>姓名</td><td>性别</td><td>爱好</td><td>学校</td></tr>");
//遍历lists集合 每遍历一次 拼接一行tr
for (Student stu : lists) {
w.print("<tr>");
w.print("<td>" + stu.getSid() + "</td>");
w.print("<td>" + stu.getSname() + "</td>");
w.print("<td>" + stu.getSex() + "</td>");
w.print("<td>" + stu.getHobby() + "</td>");
w.print("<td>" + stu.getSchool() + "</td>");
w.print("</tr>");
}
w.print("</table>");
}
}
11. ServletContext对象
(1)ServletContext理解
当 Tomcat 启动时,Tomcat 会为每个 Web 应用创建一个唯一的 ServletContext 对象代 表当前的 Web 应用,该对象封装了当前 Web 应用的所有信息。可以利用该对象获取整个Web 应用程序的初始化信息、读取资源文件等。它与Servlet是一对多的关系,其内部封装的信息可以被同一web 应用内的所有Servlet共享。
servletcontext是全局的配置对象 代表的web应用 被所有的servlet共享
(2)ServletContext的获取
获取方式有两种:
1. request.getServletContext();
2. this.getServletContext();
(3)ServletContext的作用
1.域对象:共享数据
ServletContext是一个全局作用域对象,在整个Web应用内所有用户所有请求的数据(周期长)。 request域对象,作用范围是一次请求
package com.ujiuye.servlet;
import com.ujiuye.bean.Student;
import javax.servlet.ServletContext;
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.util.HashMap;
import java.util.Map;
/**
* 获取ServletContext 和域对象
*/
@WebServlet("/demo05")
public class Demo05Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//获取 servletContext在web应用是唯一的
/*ServletContext sc1 = getServletContext();
ServletContext sc2 = this.getServletContext();
System.out.println(sc1 == sc2);//true*/
/**
* ServletContext和request都是域对象
* 什么是域对象 可以向对象中存值取值的对象,并且拥有作用域范围
* 1、域对象如何存值、取值、移除值
* 存 setAttribute(string,object)
* 取 getAttribute(key)
* 移除 removeAttribute(key)
* 2、ServletContext和request存取移除值的方式都是一样的
* 3、作用域范围
* ServletContext是整个web应用
* request作用域范围是一次请求
* 4、获取文件的真实路径 获取的是工件在本地的真实路径
* getRealPath
*/
ServletContext sc = getServletContext();
//存值
Student s = new Student();
s.setSname("张三");
sc.setAttribute("student",s);
//取值 通过key获取value
Student student = (Student) sc.getAttribute("student");
System.out.println("student = " + student);
//移除值
sc.removeAttribute("student");
System.out.println(sc.getAttribute("student"));
String realPath = sc.getRealPath("/");
System.out.println("realPath = " + realPath);
}
}
ServletContext作用域:
1、在Demo06Servlet中存值
package com.ujiuye.servlet;
import javax.servlet.ServletContext;
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;
/**
* 测试ServletContext和request的作用范围
*/
@WebServlet("/demo06")
public class Demo06Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//设置请求和响应的字符集
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
ServletContext sc = getServletContext();
sc.setAttribute("name","张三");
req.setAttribute("age",17);
}
}
2、 在Demo07Servlet中取值
package com.ujiuye.servlet;
import javax.servlet.ServletContext;
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;
/**
* 测试ServletContext和request的作用范围
*/
@WebServlet("/demo07")
public class Demo07Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//设置请求和响应的字符集
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//获取servletContext中的值
ServletContext sc = getServletContext();
Object name = sc.getAttribute("name");
System.out.println("name = " + name);
Object age = req.getAttribute("age");
System.out.println("age = " + age);
}
}
总结:
request作用域仅限于一次请求范围内可以实现信息的共享,一次请求结束,request对象消失, 内部的值也随之消失,周期短,但效率高,不会占用过多的内存资源;而ServletContext是一个全局 作用域对象,整个web项目的所有组件(Servlet、jsp)共享信息,周期长,可用来保存所有web组件之 间需要共享的信息。它在tomcat服务器启动时创建,关闭时销毁。
2.获取文件的真实路径
获取文件的真实路径方法:
getRealPath("web下的资源路径");
12. 转发和重定向
无论是转发还是重定向都起到了跳转页面、跳转到其他地址的作用
转发 req.getRequestDispatcher("success.html").forward(req, resp);
重定向 resp.sendRedirect("error.html");
1、转发
(1)理解
一种在服务器内部资源跳转的方式。浏览器请求ServletA资源时,ServletA资源不足或者没有资源,ServletA请求其他的资源然后响应给浏览器,这个过程叫转发;
(2)实现
案例:在AServlet中向request作用域中保存信息并以转发的方式跳转到BServlet
结论: bServlet可以获取到request作用域的值
案例实现:
Aservlet:
package com.ujiuye.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;
@WebServlet("/aServlet")
public class AServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//向request作用域中存值
req.setAttribute("sex","nan");
//转发到bServlet
req.getRequestDispatcher("bServlet").forward(req,resp);
//重定向到bServlet
//resp.sendRedirect("bServlet");
}
}
Bservlet:
package com.ujiuye.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;
@WebServlet("/bServlet")
public class BServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取request作用域的值
Object sex = req.getAttribute("sex");
System.out.println("sex = " + sex);
}
}
(3)特点
请求转发的特点:
1. 转发发生在服务器内部
2. 转发的过程中url地址不变 浏览器不知道
3. 转发可以访问到 WEB-INF 中的资源
4. 转发的路径是当前项目下 因此转发不可以访问项目以外的资源
5. 转发的路径一般是相对路径
6. 转发发生一次请求中 request作用域共享
2、重定向
(1)理解
重定向是客户端行为,当客户端浏览器向AServlet发送一个请求,经过处理后向客户端做出响 应,这个响应就是向服务器再次发送新的请求,去请求BServlet,而这个新请求的地址将为浏览器做出 第二次响应,此时浏览器地址栏会发生改变,由于一次请求/响应结束后,request对象会自动销毁,所 以两次请求的request对象并非同一个,所以两次请求域中的数据信息不会共享。由此可见,重定向是 做了两次请求和响应。
(2)实现
案例:在OneServlet中向request作用域中保存信息并以重定向的方式跳转到TwoServlet,此时,在TwoServlet中就无法获取到先前存到域对象中的值了,并且地址栏发生了改变。
案例实现:
结论:bServlet不可以获取到request作用域的值
AServlet:
package com.ujiuye.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;
@WebServlet("/aServlet")
public class AServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//向request作用域中存值
req.setAttribute("sex","nan");
//转发到bServlet
//req.getRequestDispatcher("bServlet").forward(req,resp);
//重定向到bServlet
resp.sendRedirect("bServlet");
}
}
BServlet:
package com.ujiuye.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;
@WebServlet("/bServlet")
public class BServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取request作用域的值
Object sex = req.getAttribute("sex");
System.out.println("sex = " + sex);
}
}
(3)特点
重定向的特点:
1. 重定向发生在浏览器和服务器之间
2. 重定向的过程url地址发生变化
3. 重定向发生至少两次请求中
4. 重定向访问不到WEB-INF的资源
5. 重定向可以访问当前应用外的资源
6. 重定向一般使用绝对路径
版权归原作者 互联网底层民工 所有, 如有侵权,请联系我们删除。