虽然现在在公司里大多不会使用servlet,但是这是学习java过程的一个过渡,以后学习到框架的时候,有些地方还是需要理解一下的。
首先我们得认识 HTTP协议
(Hypertext Transfer Protocol, 超⽂本传输协议),是⼀个客户端请求和响应的标准协议,这个协议详细规定了浏览器和万维⽹服务器之间互相通信的规则。⽤户输⼊地址和端⼝号之后就可以从服务器上取得所需要的⽹⻚信息。
请求协议:客户端发给服务器的格式
响应协议:服务器发给客户端的格式
浏览器中满足 HTTP协议格式的URL
http:// localhost: 8080 /resource/e ? name=za
规则 域名 端口 资源路径 参数
https://www.baidu.com/s?ie=UTF-8&wd=baidu
通过百度的地址对比
1.HTTP协议的特点
- 支持客户/服务器模式
- 简单快速:常用方法get、post,HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快
- 灵活:允许传输任意类型的数据,由Content-Type标记
- 无连接:每次只处理一个请求,处理完了再进行下一次请求,但是在HTTP1.1版本之后支持可持续连接,在发送完一个请求时,还没有得到处理时,可以再发送下一个请求,直到连接关闭。
- 无状态:每次处理一个数据都需要重新传数据,数据不被记忆,后续想要前面的数据得不到。
2.HTTP请求
HTTP请求含有三部分:请求行、请求头、请求正文
通过chrome浏览器,F12 -> Network查看
Get请求:没有请求体
Post请求:Form Data为其请求正文
3.Tomcat
使用servlet时需要用到Tomcat容器,它是一个符合javaEE-WEB标准的最小WEB容器,所有的 JSP 程序⼀定要有 WEB 容器的⽀持才能运⾏,⽽且在给定的 WEB 容器⾥⾯都会⽀持事务处理操作。
安装Tomcat自行百度,网上安装教程。
注意:运⾏ Tomcat 需要 JDK 的⽀持【Tomcat 会通过 JAVA_HOME 找到所需要的 JDK】。
启动 Tomcat,能访问localhost:8080,则算安装好了,如果出现端口问题,请参考我的一篇笔记,端口冲突
如果未安装oracle数据库,8080端口被其他应用占用,则可以选择修改Tomact的默认端口。
Idea配置Tomcat,网上教程找一波
创建一个java web 项目,创建一个ServletTest类,继承HttpServlet类,重写service方法,
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Hello Servlet!");
resp.getWriter().write("Hello World");
}
}
开发servlet项⽬,使⽤@WebServlet
将⼀个继承于javax.servlet.http.HttpServlet 的类定义为Servlet组件。在Servlet3.0中 , 可以使⽤@WebServlet注解将⼀个继承于javax.servlet.http.HttpServlet的类标注为可以处理⽤户请求的 Servlet。
**项⽬发布到服务器上并运⾏服务器。**
1.设置项⽬的站点名(项⽬对外访问路径)
2.设置项⽬的Tomcat配置
3.启动服务器
在项⽬正确发布到服务器上之后,⽤户即可通过浏览器访问该项⽬中的资源。注意 url 的 格式正确,tomcat 的端⼝为 8080。
浏览器访问地址:http://localhost:8080/s01/ser01
⻚⾯效果
后台结果
4.servlet的工作流程
- 通过请求头获知浏览器访问的是哪个主机
- 再通过请求⾏获取访问的是哪个⼀个web应⽤
- 再通过请求⾏中的请求路径获知访问的是哪个资源
- 通过获取的资源路径在配置中匹配到真实的路径,
- 服务器会创建servlet对象,(如果是第⼀次访问时,创建servlet实例,并调⽤init⽅法进⾏初始化
操作) - 调⽤service(request, response)⽅法来处理请求和响应的操作
- 调⽤service完毕后返回服务器 由服务器讲response缓冲区的数据取出,以http响应的格式发送给
浏览器
5.servlet的生命周期
servlet类加载 —> 实例化 —> 服务 —> 销毁
Tomcat工作图:
- Web Client 向 Servlet 容器(Tomcat)发出 Http 请求
- Servlet 容器接收 Web Client 的请求
- Servlet 容器创建⼀个 HttpServletRequest 对象,将 Web Client 请求的信息封装到这个对象 中
- Servlet 容器创建⼀个 HttpServletResponse 对象
- Servlet 容器调HttpServlet 对象service ⽅法,把 Request 与 Response 作为参数,传给HttpServlet
- HttpServlet 调⽤ HttpServletRequest 对象的有关⽅法,获取 Http 请求信息
- HttpServlet 调⽤ HttpServletResponse 对象的有关⽅法,⽣成响应数据
- Servlet 容器把 HttpServlet 的响应结果传给 Web Client
6.HttpServletRequest对象
接收客户端发送过来的信息
常用方法:
// 获取客户端请求的完整URL (从http开始,到?前⾯结束)
String url = request.getRequestURL().toString();
System.out.println("获取客户端请求的完整URL:" + url);
// 获取客户端请求的部分URL (从站点名开始,到?前⾯结束)
String uri = request.getRequestURI();
System.out.println("获取客户端请求的部分URL:" + uri);
// 获取请求⾏中的参数部分
String queryString = request.getQueryString();
System.out.println("获取请求⾏中的参数部分:" + queryString);
// 获取客户端的请求⽅式
String method = request.getMethod();
System.out.println("获取客户端的请求⽅式:" + method);
// 获取HTTP版本号
String protocol = request.getProtocol();
System.out.println("获取HTTP版本号:" + protocol);
// 获取webapp名字 (站点名)
String webapp = request.getContextPath();
System.out.println("获取webapp名字:" + webapp);
// 获取指定名称的参数,返回字符串
String uname = request.getParameter("uname");
System.out.println("uname的参数值:" + uname);
// 获取指定名称参数的所有参数值,返回数组
String[] hobbys = request.getParameterValues("hobby");
System.out.println("获取指定名称参数的所有参数值:" + Arrays.toString(hobbys));
在发送请求时可能会出现乱码问题,原因在于解析过程
中默认使⽤的编码⽅式为 ISO-8859-1(此编码不⽀持中⽂),解决方法如下:
//这种⽅式只针对 POST 有效(必须在接收所有的数据之前设定)
request.setCharacterEncoding("UTF-8");
new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
Tomcat8以后版本乱码问题不会再出现。
7.请求转发
语法:
request.getRequestDispatcher(url).forward(request,response);
有时需要设置request的作用域,通过该对象可以在⼀个请求中传递数据,作⽤范围:在⼀次请求中有效,即服务器跳转有效。
// 设置域对象内容
request.setAttribute(String name, String value);
// 获取域对象内容
request.getAttribute(String name);
// 删除域对象内容
request.removeAttribute(String name);
8.HttpServletResponse对象
Web服务器收到客户端的http请求,会针对每⼀次请求,分别创建⼀个⽤于代表请求的 request 对象和代表响应的 response 对象。
request 和 response 对象代表请求和响应:获取客户端数据,需要通过 request 对象;向客户端输
出数据,需要通过 response 对象。
有两种响应数据的方法,注意两种方式不要一起写,有时两个流同时运行会报错。
第一种 ,通过字符输出流
//中文输出会乱码
//设置服务端编码格式
response.setCharacterEncoding("UTF-8");
//设置客户端编码格式
response.setHeader("content-type","text/html;charset=UTF-8");
//一行代码设置服务端、客户端编码格式
// response.setContentType("text/html;charset=UTF-8");
//响应数据
PrintWriter writer = response.getWriter();
writer.write("加油");
writer.write("<p>这是一个p标签</p>");
writer.write("hello world");
//刷出是因为write有一个缓存区,如果内容不够的话是不会输出的
writer.flush();
writer.close();
第二种方法:通过字节流
//中文输出会乱码
//设置服务端编码格式
response.setCharacterEncoding("UTF-8");
//设置客户端编码格式
response.setHeader("content-type","text/html;charset=UTF-8");
//一行代码设置服务端、客户端编码格式
//response.setContentType("text/html;charset=UTF-8");
ServletOutputStream os = response.getOutputStream();
os.write("你好".getBytes());
os.flush();
os.close();
9.重定向
重定向是⼀种服务器指导,客户端的⾏为。客户端发出第⼀个请求,被服务器接收处理后,服务器会进⾏响应,在响应的同时,服务器会给客户端⼀个新的地址(下次请求的地址response.sendRedirect(url);
),
当客户端接收到响应后,会⽴刻、⻢上、⾃动根据服务器给的新地址发起第⼆个请求,服务器接收请求并作出响应,重定向完成。从描述中可以看出重定向当中有两个请求存在,并且属于客户端⾏为。
// 重定向跳转到index.jsp
response.sendRedirect("index.jsp");
重定向和请求转发的区别
request.getRequestDispatcher(url).forward(request,response); | response.sendRedirect(url); |
---|---|
一次请求,数据在request域中共享 | 两次请求,request域中不共享数据 |
服务端行为 | 客户端行为 |
地址栏不会发生改变 | 地址栏发送改变 |
绝对定位到资源路径后面 | 绝对地址可写到http:// |
10.Cookie对象
Cookie是一种将某些数据存放在客户端当中的技术,常用于记住密码或者自动登录过程。
其格式为:键值对用"="连接,多个键值对通过";"隔开
Cookie的使用:
创建Cookie并添加到浏览器中:
//创建cookie对象
Cookie cookie1 = new Cookie("aa", "AAA");
//发送cookie对象,默认项目路径下可以访问
response.addCookie(cookie1);
获取cookie的内容:
//获取cookie
Cookie[] cookies = request.getCookies();
//首先判断cookie是否为空和长度为0
if (cookies != null || cookies.length>0){
//遍历
for (Cookie cookie : cookies) {
//getName(),获取key值,getValue(),获取value值
String s = cookie.getName() + "-" + cookie.getValue();
System.out.println(s);
}
}
设置Cookie的存活时间:
//设置cookie存活时间,负数:浏览器关闭即消失,正数:毫秒数,零:销毁cookie值
cookie1.setMaxAge(-1);
cookie2.setMaxAge(30);
//删除cookie,存活时间为0,即删除
cookie.setMaxAge(0);
设置Cookie的访问路径:
//当前项目路径为 /s01
// 1、设置路径为"/",表示在当前服务器下任何项⽬都可访问到Cookie对象
cookie.setPath("/");
// 2、设置路径为"/s01",表示在当前项⽬下任何项⽬都可访问到Cookie对象
cookie.setPath("/s01"); // 默认情况,可不设置path的值
// 3、设置路径为"/s02",表示在s02项⽬下才可访问到Cookie对象
cookie.setPath("/s02"); // 只能在s02项⽬下获取Cookie,就算cookie是s01产⽣的,s01也不能获取它
// 4、设置路径为"/s01/cook",表示在s02/cook⽬录下才可访问到Cookie对象
cookie.setPath("/s01/cook");
注意:
- cookie中存储的数据key值不可以为中文,不然输出会乱码,可以通过
URLEncoder.encode()
进行编码,接收时使用URLDecoder.decode()
解码。 - Cookie存储在当前浏览器中
- 同名Cookie存储时,会覆盖掉之前的value值
- 不同的浏览器存储cookie的数量有限制
- 当访问的路径包含了cookie的路径时,则该请求将带上该cookie;如果访问路径不包含cookie路径,则该请求不会携带该cookie。
11.HttpSession对象
作用: session保存在当前的浏览器中,标识一次会话,并且在一个会话中(可能存在一个用户的多次请求)共享数据
获取Session对象:
// 如果session对象存在,则获取;如果session对象不存在,则创建
HttpSession session = request.getSession();
获取session中的数据:
// 获取session对象
HttpSession session = request.getSession();
// 设置session域对象
session.setAttribute("uname","admin");
// 获取指定名称的session域对象
String uname = (String) request.getAttribute("uname");
// 移除指定名称的session域对象
session.removeAttribute("uname");
Session的生命周期:
默认时间到期:
Tomcat中的session默认时间是30分钟,可以在Tomcat中的conf目录下的web.xml文件修改,建议一般不改,有时候改了会影响到其他地方。
<!-- session 默认的最⼤不活动时间。单位:分钟。 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
除了默认时间外,我们可以通过方法设置存活时间
// 获取session对象
HttpSession session = request.getSession();
// 设置session的最⼤不活动时间
session.setMaxInactiveInterval(15); // 15秒
// 获取session的最⼤不活动时间
int time = session.getMaxInactiveInterval();
// 销毁session对象
session.invalidate();
注意:
- session会话的底层依赖
cookie
实现 - session有一个唯一标识
JSessionId
- 关闭服务器则session销毁
12.ServletContext对象
获取ServletContext对象:
//获取ServletContext对象
ServletContext servletContext = request.getServletContext();
ServletContext servletContext1 = request.getSession().getServletContext();
ServletContext servletContext2 = getServletConfig().getServletContext();
ServletContext servletContext3 = getServletContext();
System.out.println(servletContext);
//这两个方法是偶尔会用到的,上面的记住一种获取对象的方式就够了
//获取项目存放的真实路径
String realPath = request.getServletContext().getRealPath("/");
System.out.println(realPath);
//获取当前服务器的版本信息
String serverInfo = request.getServletContext().getServerInfo();
System.out.println(serverInfo);
设置域对象:
// 获取ServletContext对象
ServletContext servletContext = request.getServletContext();
// 设置域对象
servletContext.setAttribute("name","zhangsan");
// 获取域对象
String name = (String) servletContext.getAttribute("name");
// 移除域对象
servletContext.removeAttribute("name");
Servlet的三大域对象:
- request域对象
在一次请求中有效,请求转发有效,重定向无效 - session域对象
在一次会话中有效,请求转发和重定向都有效,session销毁后失效 - ServletContext域对象
在整个应用程序中有效,服务器关闭后失效
最后根据所学知识,实现一个简单的demo,文件上传和下载:
文件上传:
前台代码:
<!--
⽂件上传表单
1. 表单提交类型 method="post"
2. 表单类型 enctype="multipart/form-data"
3. 表单元素类型 ⽂件域设置name属性值
-->
<form method="post" action="fileUpLoad" enctype="multipart/form-data">
⽂件:<input type="file" name="myfile" > <br>
<button type="submit">提交</button>
</form>
后台Servlet代码:
@WebServlet("/fileUpLoad")
@MultipartConfig/*该注解是为了上传文件的必须性*/
public class FileUpLoad extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码格式
request.setCharacterEncoding("UTF-8");
//获取输入的参数
Part part = request.getPart("myfile");
//获取文件名
String fileName = part.getSubmittedFileName();
//获取项目绝对路径
String realPath = getServletContext().getRealPath("/");
//上传文件
part.write(realPath+fileName);
//最后文件上传的位置是在out编译文件夹中
}
}
文件下载:
当浏览器遇到可识别的资源时,默认打开,不会下载,不识别的话默认打开
前台直接下载Demo:
<html>
<head>
<title>Title</title>
</head>
<body>
<%--浏览器可识别资源--%>
<a href="1.jpg">图片1</a>
<a href="2.jpg">图片2</a>
<a href="一单元.docx">文档</a>
<%--浏览器可识别资源,通过download属性下载,属性值为下载的文件名称--%>
<a href="一单元.docx" download>文档2</a>
<a href="1.jpg" download="壁纸1">图片1</a>
<a href="2.jpg" download="壁纸2">图片2</a>
<%--通过表单下载--%>
<form action="fileDownload" method="post">
<input type="file" name="myfile">
<button type="submit">下载</button>
</form>
</body>
</html>
根据表单提交实现后台下载代码:
@WebServlet("/fileDownload")
public class FileDownLoad extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码格式
request.setCharacterEncoding("UTF-8");
//获取文件下载路径
String realPath = getServletContext().getRealPath("/");
//获取文件名
String name = request.getParameter("myfile");
System.out.println(name);
//获取文件
File file = new File(realPath + name);
//判断文件是否存在
if (file.exists() && file.isFile()){
//设置响应类型
response.setContentType("application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename=" + name);
//获取输入流
FileInputStream is = new FileInputStream(file);
//获取输出流
ServletOutputStream os = response.getOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len=is.read(bytes))!=-1){
os.write(bytes,0,len);
}
os.flush();
os.close();
is.close();
System.out.println("下载成功");
}else{
System.out.println("文件下载失败");
}
}
}