Servlet
1)Servlet的概述
1、什么是Servlet?
Servlet,全称Java Servlet,是用Java编写的服务器端程序。其主要功能在于处理请求和发送响应。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
Servlet是Java Web的核心类,是Java Web三大组件之一(Servlet、Filter、Listener)。
2、Servlet的作用
用来处理客户端发送过来的请求,并对该请求做出响应:在HTTP请求过程中会把请求的参数存放在请求行的URL中,或者是请求体中,这个参数需要服务器来接受解析并处理,Servlet就是用来处理这个过程的
1)处理HTTP请求
2)获取接收客户端发送来的请求数据
3)将处理的结果通过响应发送到客户端
3、Servlet的版本
Servlet 3.0作为Java EE 6规范体系中的一员,随着Java EE 6规范一起发布。该版本在前一版本(Servlet 2.5)的基础上提供了若干新特性用于简化Web应用的开发和部署
异步处理支持,在接收到请求之后,Servlet线程可以将耗时的操作委派给另一个线程来完成,自己在不生成响应的情况下返回至容器。针对业务处理较耗时的情况,这将大大减少服务器资源的占用,并且提高并发处理速度。有了该特性,Servlet线程不再需要一直阻塞,直到业务处理完毕才能再输出响应,最后才结束该Servlet线程。
新增的注解支持,该版本新增了若干注解,用于简化Servlet、过滤器(Filter)和监听器(Listener)的声明,这使得web.xml部署描述文件从该版本开始不再是必选的了。
可插性支持,熟悉Struts2的开发者一定会对其通过插件的方式与包括Spring在内的各种常用框架的整合特性记忆犹新。将相应的插件封装成JAR包并放在类路径下,Struts2运行时便能自动加载这些插件。现在Servlet 3.0提供了类似的特性,开发者可以通过插件的方式很方便的扩充已有Web应用的功能,而不需要修改原有应用。
2)编写第一个Servlet
1、创建一个类继承HttpServlet
Servlet程序必须编写实现类,并继承javax.servlet.http.HttpServlet接口
1)在src下创建一个包
2)创建一个类,继承HttpServlet
2、重写HttpServlet中的doGet()、doPost()
1)鼠标右键,弹出菜单选Generate,也可使用快捷键ALT+Insert
2)选Override Methods
3)选择doGet、doPost方法,选确定
4)自动补全代码
3、配置web.xml
HelloServlet
com.ceit.servlet.HelloServlet
HelloServlet
/hello
其中是用来注册Servlet的
内部的是servlet的名称,在当前配置文件中必须唯一
内部的是servlet实现类的类名,类名要包含package名称
4、部署项目并通过浏览器访问
启动Tomcat服务器,在浏览器中访问http://localhost:8080/hello
查看IDEA控制台,输出“接收到get请求了!”
5、Servlet的执行流程
第一步根据浏览器地址栏中访问的接口名也就是hello找到web.xml中对应的
第二步会根据对应的
第三步会根据name找到对应的
第四步根据找到真正的servlet的位置
3)在Servlet3.0版本下创建Servlet
1)创建项目file—>New Project—>Java Enterprise,java EE版本选择6.0以上
2)在IDEA的src包目录下直接右键new,选择Servlet
3)配置
@WebServlet(urlPatterns = "/test"),注解内的访问路径等同于web.xml下的url-patterner
@WebServlet(name = "TestServlet",urlPatterns = "/test")
4)Servlet的生命周期
什么是Servlet的生命周期
生命周期:就是一个对象从创建到销毁的过程
Servlet的生命周期:Servlet从创建到销毁的过程
Servlet接口以及相关方法
Servlet接口:javax.servlet.Servlet接口
init(ServletConfig config)
service(ServletRequest request,ServletResponse response)
destroy()
HttpServlet接口:javax.servlet.http
继承自Servlet接口,并重新实现了service方法,根据不同请求方式调用不同的处理方法。
service(HttpServletRequest,HttpServletResponse)方法,获取请求方式,分别调用doGet(),或者doPost()方法。
Servlet生命周期整个过程描述
1)客户端发送请求给服务器。
2)服务器开始接受,先判断该请求的servlet实例是否存在,如果不存在先装载一个servlet类并创建实例。
3)如果存在则直接调用该servlet的service方法,之后进行判断是调用 doGet方法还是doPost方法。
4)servlet创建实例后,调用init方法进行初始化。之后调用servce方法,判断是调用doGet方法还是doPost方法。
5)最后判断服务器是否关闭,如果关闭则调用destroy方法。
示例:在代码中验证HttpServlet生命周期
1.新建LifeServlet类继承HttpServlet
2.重写inti、doGet、doPost、destroy方法
3.客户端发送请求,在控制台查看Servlet中方法执行
5)HttpServletRequest请求对象
1.HttpServletRequest简介
在Servlet的API中,定义了一个HttpServletRequest接口,它继承自ServletRequest接口,专门用于封装HTTP的请求,由于HTTP请求包含着请求行、请求头和请求体三部分,因此,在HttpServletRequest中分别定义了获取请求行、请求头和请求体的相关方法
2.获取请求行
获取请求行相关信息的相关方法:
getMethod()方法:返回请求方法,请求方法通常是GET或者POST,但也可能是HEAD、PUT或者DELETE
getRequestURI()方法:返回URL(URI是URL的从主机和端口之后到表单数据之前的那一部分)例:hello?name=xiaohong&password=123456
getRemoteAddr ()方法:该方法用于获取请求客户端的IP地址
getRemoteport ()方法:该方法用于获取请求客户端的端口号
getLocalAddr ()方法:该方法用于获取服务器当前接受请求的IP地址
getContextPath ()方法:该方法用于获取URL中属于web应用程序的路径
getProtocol ()方法:该方法用于获取请求行中的协议名和版本
3.获取请求头
getHeader(String name):该方法用于获取一个指定头字段的值,如果请求头中不包含该字段则返回null,如果包含多个该字段的值则获取第一个值。
getIntHeader(String name):该方法用于获取指定头字段的值,并且将其值转为int类型,如果不存在该字段则返回-1,如果获取到的值不能转换为int则会发生NumberFormatException异常。
getDateHeaders(String name):该方法用于获取指定头字段的值,并将其按照GMT时间格式转换成一个代表日期/时间的长整型
getHeaderNames():该方法用于获取所有包含请求头字段的Enumeration
示例:
Enumeration headers = request.getHeaderNames();
while(headers.hasMoreElements()){
String header = headers.nextElement();
System.out.println(header);
}
4.获取请求参数
GET请求,参数在请求头,POST请求,参数在请求体,无论哪种方式,request都能获取参数
getParameter(String name):用于获取某个指定名称的参数值,如果请求中灭有包含指定名称的参数,则返回null,如果有指定名称参数但是没有给设定值,则返回空字符串,如果包含多个该参数的值则返回第一个出现的参数值。
getParameterNames ():该方法用于返回一个包含请求消息中所有参数名的Enumeration
getParameterMap():该方法用于将请求中的所有参数和值装入一个map对象然后返回
6)HttpServletResponse响应请求
1.HttpServletResponse简介
在Servlet的API中,定义了一个HttpServletResponse接口,它继承自ServletResponse接口,专门用于封装HTTP的响应,由于HTTP响应包含着响应行、响应头和响应体三部分,因此,在HttpServletResponse中分别定义了发送响应行、响应头和响应体的相关方法。
2.发送响应行
setStatus(int status):当Servlet向客户端回送响应消息时,需要设置一个状态码,该方法用于设置HTTP响应消息的状态码,并生成响应状态行。由于响应状态行中状态的描述直接和状态码相关,而HTTP协议版本由服务器决定,因此只需要设置该方法,就可以发送一个响应行,正常情况下,web服务器会默认发送一个200状态码。
sendError(int code):该方法用于发送表示错误信息的状态码,例如404找不到访问的资源,他还有一种重载的形式
sendError(int code,String errorMessage):errorMessage可以以文本形式显示在客户端浏览器。
3.发送响应头
addHeader(String name,String value):该方法用来设置HTTP协议的响应头字段,其中name是响应头字段名,value是响应头字段的值
setHeader(String name,String value):该方法和addHeader相同,唯一的区别是addHeader可以重复添加一个同名的响应头字段,setHeader会覆盖之前添加的同名响应头
addIntHeader(String name,int value)、setIntHeader(String name int value):这两个方法用于将value值为int的字段加入到响应头中
setContentLength():该方法用于设置HTTP响应消息的内容大小,单位是字节
setContenType(String type):该方法用于设置Servlet输出内容的类型,也就是HTTP协议中的Content-Type响应头。例如发送到客户端的内容是jpeg格式的图像数据,就需要将响应头字段的类型设置为“image/jpeg”,另外,如果响应的内容是文本,那这个时候setContentType还可以设置字符编码,例如“text/html;charset=UTF-8”,通常在浏览器和服务器出现乱码时考虑使用
setCharacterEncoding(String charset):该方法用的较少
4.发送响应消息体
在HTTP响应消息中,大量的数据都是通过响应体传递的,因此ServletResponse遵循以IO流传递大数据的设计理念,定义了两个与输出流相关的方法,具体如下:
getoutputStream():该方法获取的字节流输出对象为ServletOutputStream类型,它是OutputString的子类,因此可以直接输出字节数组中的二进制数据
getWriter():该方法获得的字符输出流对象是PrintWriter类型,由于它可以直接输出文本类型,因此要输出网页文档,需要使用这个方法,默认编码ISO8859-1,需要使用setContentType修改编码
案例:文件下载
创建DownloadServlet,URLPatterns= "/download"
在WEB-INF下创建download文件夹,将需要下载文件放到文件夹下
从请求中获取文件名,通过文件输入流将读取文件(文件使用绝对路径)
通过HttpServletResponse输出流将文件返回给客户端浏览器
通过对应的http响应头通知浏览器下载该文件
告知浏览器文件的类型——可直接由浏览器打开
response.setContentType(文件的MIME类型);
告知浏览器文件的打开方式是下载:
response.setHeader("Content-Disposition","attachment;filename=文件名称");
7)ServletConfig对象
1.什么是ServletConfig对象?
ServletConfig对象是它所对应的Servlet对象的相关配置信息
在web.xml中我们可以配置每个servlet的基本信息,除此以外,还可以使用init-param配置参数,servlet都能够通过ServletConfig对象获取到。
encode
utf-8
特点:
每一个Servlet对象都有一个ServletConfig对象和它相对应
ServletConfig对象在多个Servlet对象之间是不能共享的
2.常见的ServletConfig对象的方法:
getInitParameter(String name):返回一个初始化变量的值
getInitParameterNames():返回servlet初始化参数的所有名称
getServletContext():获取ServletContext对象
getServletName():获取Servlet的name配置值
3.获取ServletConfig对象方法:
HttpServlet中直接通过this.getServletConfig()获取。
在实际开发中,需要在配置文件中配置某个Servlet初始化参数,可以使用ServletConfig对象获取。
8)ServletContext对象
1.什么是ServletContext对象?
1)获取ServletContext对象
通过ServletConfig的getServletContext()方法可以得到ServletContext对象。
HttpServlet中直接通过this.getServletContext()获取。
2)域对象
域对象就是在不同资源之间共享数据,保存数据,获取数据
ServletContext对象通常称为Context域对象,ServletContext是我们学习的第一个域对象。
2.ServletContext对象的应用
1)使用ServletContext获取整个web项目初始化参数
在web.xml中配置初始化参数:
参数名 参数值 String getInitParameter(String name):根据名称获取初始化参数 Enumeration getInitParameteraNames():获取所有初始化参数名称 2)使用ServletContext在多个Servlet中共享数据 void setAttribute(String name,Object object):存放数据 Object getAttribute(String name):获取数据 void removeAttribute(String name):删除数据 3)使用ServletContext获取web项目的属性文件(重要) (1)新建属性文件db.properties,注意扩展名为.properties不要写错 (2) 在文件中添加属性名、属性值,如下db.driver=com.mysql.jdbc.Driver db.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8 db.username=root db.password=root (3)在servlet中获取ServletContext this.getServletContext() (4) 调用ServletContext方法getResourceAsStream(String path),该方法读取文件,返回文件流 InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
参数是文件部署后路径
“/”是项目根路径,“web”文件夹下文件路径直接补全即可
如果文件放在“src”文件夹下,部署后,文件在“/WEB-INF/classess”下
(5)使用Properties对象从文件流中获取属性
Properties properties = new Properties();
properties.load(resourceAsStream);
String param = properties.getProperty(“参数名”);
完整代码:
InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
String dbDriver = properties.getProperty(“db.driver”);
String dbUrl = properties.getProperty(“db.url”);
String dbUserName = properties.getProperty(“db.username”);
String dbPassword = properties.getProperty(“db.password”);
System.out.println(dbDriver+"\n"+dbUrl+"\n"+dbUserName+"\n"+dbPassword);
注意:获取属性文件方法是固定的,记住就可!
9)Servlet之间的跳转
转发Forward
重定向Redirect
重定向和请求转发的区别
10)Servlet线程安全
1.什么是线程安全?
当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内部如果访问了同一个资源的话,就可能引发线程安全问题。
2.如何解决Servlet线程安全?
1)使用同步代码块
synchronize(this){
}
2)让Servlet实现SingleThreadModle接口
不再是单例模式
每个请求都会创建一个Servlet实例
浪费服务器资源
已经过时,不建议使用
3)尽量不要在Servlet实例内使用共享变量