目录
什么是servlet
一个完整的servlet程序
(1)创建一个maven项目
(2)引入依赖
?(3)创建目录
(4)编写servlet代码
(5)打包程序
?(6)部署
(7)运行
补充
部署方式
(1)安装smart插件
?(2)配置Smart Tomcat插件
?访问出错的情况
404
?405
?500
Servlet运行原理
Servlet相关API
【1】HttpServlet
【2】HttpServletRequest
【3】HttpServletResponse
上传文件
HttpServletRequest类方法
Part类的常用api
请求和响应(总结)
服务器获取数据的格式
服务端返回数据的格式
序列化和反序列化
实现页面跳转
Cookie和Session
Cookie
会话管理(Cookie+Session)
Servlet中使用Session会话管理
HttpServletRequest类中的方法
HttpSession类中的方法
什么是servlet
Java官方规定的web开发的api(规范)。
网络编程对于客户端和服务端:
两端使用支持网络编程的语言,就能实现网络编程(网络通信)
但是应用层协议,还是需要应用程序自己来进行封装和分用。
对于hhtp协议:
- 客户端:基于浏览器可以省略程序自己封装分用http数据的步骤(浏览器会帮助我们进行封装和分用);
- 服务端:基于web服务器(部署网站,对应省略http协议处理的逻辑)也可以类似的省略封装和分用的步骤。
对于web服务器,有多种产品(支持多种编程语言),支持Java语言的,对应也有多种产品。对以一个Java开发的网站,可以运行在这些支持Java语言的不同web服务器上,就需要满足一定的规范,这个规范就是servlet。
总结:
- web服务器:针对所有编程语言,能运行网站系统的服务器程序;
- servlet容器:运行Java开发的网站(Java开发的网站就一定使用了servlet技术);
- servlet:Java官方规定的web开发的api规范。
一个完整的servlet程序
(1)创建一个maven项目
(2)引入依赖
项目创建完成后,会自动生成一个pom.xml文件。我们需要在该文件中引入servlet依赖包。需要注意以下事项:
?(3)创建目录
项目创建好之后,idea会帮我们自动创建一些目录(我们还需要自己配置一个webapp目录):
- src:表示源代码所在的目录;
- main/java:源代码的根目录;
- main/resources:项目的一些资源文件所在的目录;
- test/java:测试代码的根目录。
此外,我们还需要创建一些新的目录:
在main目录下,和Java目录并列,创建一个webapp目录,webapp目录内部再创建一个WEB-INF目录,在该目录下创建一个web.xml文件。
编写web.xml:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
- webapp目录是未来部署到Tomcat中的一个重要的目录,可以在其中放一些静态的文件(html,css等);
- web.xml文件:Tomcat找到这个文件才能正确处理webapp中的动态资源。
(4)编写servlet代码
开发servlet的步骤(java目录下):
- 类注解@WebServlet:字符串必须以/开头,一个项目可以开发多个servlet,但是其路径必须唯一;
- 继承HttpServlet;
- 重写doXXX方法,XXX表示提供的方法。(常见doGet、doPost)
【1】获取请求信息:通过servlet规定的api,HttpServletRequest方法参数对象; 【2】进行一些逻辑操作:比如数据库的操作等; 【3】获取响应信息:通过servlet规定的api,HttpServletResponse方法参数对象。
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello world");
}
}
(5)打包程序
使用maven进行打包,找到项目目录下的Lifecycle的package双击即可,一定要出现success才算打包成功。打包成功后会在target目录下生成一个war包。
?(6)部署
将war文件复制到tomcat/webapps目录下。
(7)运行
通过tomcat来运行网站。
补充
可以看到我们打包的war包名称很长,而且其中包含版本号,牵涉到版本更新的时候比较麻烦,所以我们可以使用以下代码配置文件名。
<build>
<!-- 最终打包的文件名,建议配置 -->
<finalName>servlet-demo</finalName>
</build>
部署方式
对于上面的部署方式,手动将war包拷贝到webapps目录下比较麻烦,我们可以使用idea中的Smart Tomcat插件更方便的完成部署。
(1)安装smart插件
按照以下步骤安装Smart Tomcat插件:
?(2)配置Smart Tomcat插件
找到右上角Add:
?进行如下配置:
?访问出错的情况
404
表示用户访问的资源不存在。大部分情况是URL的路径有问题。
注意请求路径的写法:
如下,缺少上下文路径:
?405
表示对应的HTTP请求方法没有实现。
如下,将上面的servlet程序的重写的doGet方法改为doPost方法(通过地址栏访问使用的是get方法):
?500
往往是servlet代码中抛出异常导致。
如下,修改servlet代码,使其抛出异常,访问时HTTP状态码为500:
Servlet运行原理
Servlet容器(tomcat等运行Java网站的web服务器)和Servlet:容器管理整个Servlet的生命周期。
- Tomcat的代码中内置了main方法。我们启动Tomcat时,就是从Tomcat的main方法开始执行的;
- 类@WebServlet注解修饰的类会在Tomcat启动的时候被获取到,并集中管理;
- Tomcat通过反射来创建被注解修饰的类的实例;
- 这些实例被创建完之后,会调用init()方法进行初始化;
- 这些势力被销毁之前,会调用destory()方法进行收尾工作;
- Tomcat为了能同时相应多个HTTP请求,采取了多线程的方式实现。
处理请求的时候,根据请求路径(url)找到对应的servlet对象。
servlet三大生命周期方法:
- init():初始化方法,实例化对象之后,执行一次;
- service():每次请求,执行一次;
- destory():销毁方法,只执行一次。
Servlet相关API
【1】HttpServlet
方法 | 调用时机 | init | 对象实例化之后调用一次,初始化 | service | 收到HTTP请求调用一次 | destroy | 实例不在使用的是时候调用一次 | doGet/doPost | 收到GET/POST请求之后调用(由service方法调用) | doPut/doDelete/… | 收到其他请求的时候调用 |
注:HttpServlet实例只在程序启动时创建一次。
【2】HttpServletRequest
方法 | 描述 | String getProtocol() | 返回请求协议的名称和版本号 | String getMethod() | 返回请求的HTTP的方法 | String getContextPath() | 获取URL的应用上下文路径 | String Parameter(String name) | 以字符串的形式返回请求参数的值,如果参数不存在返回null。 | InputStream getInputStream() | 用于获取请求的body内容。返回一个InputStream对象。(body的任何格式都可以获取,但一般用于json) | void setCharacterEncoding() | 设置被发送到客户端的响应的字符编码格式 |
【3】HttpServletResponse
void setStatus(int sc) | 为该响应设置状态码 | void setContentType(String type) | 设置被发送到客户端的相应的内容的类型 | PrintWriter getWriter() | 往body中写入文本格式(写网页、json) | OutPutStream? getOutPutStream() | 往body中写入二进制格式的数据(写文件) |
- 对于Servlet代码,需要注意的是,代码执行执行到重写的doXXX方法时,表示网站可以正常响应,此时响应状态码为200,所以即使重写的方法中抛出异常,状态码也为200。(即使状态码为200,也可能是后端出现异常);
- 对于状态码/响应头的设置要放到getWriter/getOutPutStream之前,否则可能设置失效。
上传文件
HttpServletRequest类方法
方法 | 描述 | Part getPart(String name) | 获取请求中给定name的文件 | Collection<Part> getPart() | 获取所有的文件 |
Part类的常用api
方法 | 描述 | String getSubmittidFileName() | 获取提交的文件名 | String getContentType() | 获取提交的文件类型 | long getSize() | 获取文件的大小 | void write(String path) | 把提交的文件数据写入磁盘文件 |
POST提交from-date(包含上传文件)
在提交from-data格式的数据时,会保存客户端上传的文件到服务端本地路径,那么保存的文件,一般如何进行设计呢?
- ?文件可以存放在数据库中:
【1】文件非常小,可以考虑放进去=>将二进制的数据转换为Base64(字符串)保存 【2】文件比较大,就不建议放进去了=>数据库网络带宽非常重要,一般是用单独的服务器来存储文件。 - 也可以存放在某个服务器主机硬盘上(此时需要考虑,如何才能访问):
可以自己写代码提供一个服务资源(servlet),请求数据包含一些信息,就可以返回不同的文件响应了。(但是不要将其放在web项目的webapp包下,虽然此时tomcat可以直接访问到,但是打包的时候消耗的资源太多)
请求和响应(总结)
服务器获取数据的格式
- queryString:
String s=request.getParacmeter("请求数据的键"); - 表单格式:getParacmeter;
- json格式:
(1)先获取请求中的输入流(getInputStream),输入流包含body请求数据; (2)再使用第三方json框架来处理:把json字符串转换为Java对象(反序列化); - from-data:
(1)简单格式:getParacmeter (2)复杂格式:getPart;
服务端返回数据的格式
前后端分离技术:
- ajax请求:返回json字符串(将Java字符串转换为josn对象:序列化);
- 图片,音频等,浏览器会自动的发送请求,servlet返回二进制数据。
序列化和反序列化
- 序列化:站在自己程序角度,将程序中的对象转换为其他格式用于返回响应数据;
- 反序列化:站在自己程序的角度,将其他格式转换为自己程序中的对象,用于接收请求数据。
实现页面跳转
- 使用a标签:
(1)如果直接给html路径,就无法进行校验: (2)写servlet路径,可以进行校验。 - 前端js代码:location.herf=“跳转的路径”(相当于修改地址栏的url)
需要进行验证:前端某个事件中调用ajax函数,发请求,根据返回的响应数据,来决定是否跳转。 - 后端进行跳转:重定向。
重定向和转发:
- 重定向:两次请求,路径会发生改变:
(1)发送的请求,返回重定向状态码,响应头Location字段(表示要跳转的路径) (2)浏览器自动发起第二次请求(地址栏会改变为location路径) - 转发:一次请求,路径不会发生改变(服务端会自动帮助找资源)。
Cookie和Session
Cookie
客户端保存数据的技术。属于客户端的机制,而session是服务端的机制。
如何操作数据?
- 保存数据:js、服务端的响应头(Set-Cookie)=>保存在客户端本地硬盘和浏览器/域名相关的路径上;
- 使用数据:浏览器自动的携带请求头(Cookie)
会话管理(Cookie+Session)
背景:Http协议是一种无状态协议(应用层没有保存连接状态)。多次请求,基于Http本身不知道具体是哪个用户发送。
会话的本质就是一个哈希表,存储一些键值对结构,value就是用户信息。
会话:web开发中,会话是用户登录一个网站后,推出或超时之前,都属于一个会话。
流程:
- ?登录时,验证账号密码:
【1】创建Session会话,并保存在服务端; 【2】返回响应头Set-Cookie:sessionid=XXX。 - 客户端保存Cookie信息到本地;
- 客户端的每次请求都会携带Cookie请求头(sessionid).
Servlet中使用Session会话管理
HttpServletRequest类中的方法
方法 | 描述 | HtttpSession? getSession() | 在服务器中获取会话(不带参数时默认是true),参数如果为true,会话不存在时新建会话;参数为false,会话不存在时返回null。 |
HttpSession类中的方法
方法 | 描述 | Object getAttribute(String name) | 该方法返回该session会话中具有指定名称的对象,如果没有指定名称的对象,则返回null | void setAttribute(String name,Object value) | 该方法使用指定的名称绑定一个对象到该session会话 | void invalidate() | 使会话失效,注销时使用 |
|