如何才算掌握Servlet
- ServletConfig
- ServletContext
- Request
- Response
- Cookie
- Session
上面这些对象(当然不止这些,剩下的对象查阅ServletAPI,不是JavaEEAPI)都是web服务器在条用Servlet时所创建的交给Servlet的对象,将这些对象的API掌握熟练,就基本上掌握Servlet技术了,剩下的就是你的Java编程功力了,基本都是设计方面的事了。
Web服务器
web服务器接受到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表相应的response对象。如果需要获取客户端的相关信息,就使用request对象,需要向客户端发送数据,就使用response对象。
这里的request对象和response对象都不是标准的HTTP协议的请求和响应,而是Web服务器根据标准的HTTP协议的请求和响应,然后再根据Servlet规范(接口)实现的Web对象。
###Servlet技术 其实Servlet技术就是一套接口,这个接口是由当年的SUN公司指定的,Tomcat是一个web服务器,也是Servlet和JSP的容器,为什么它是Servlet与JSP的容器呢,原因就是它实现了SUN规定的那一套关于Servlet和JSP的规范与接口,所以在查阅ServletAPI时你会发现,很多都是接口,这是正常的,具体的显示类是由Tomcat来完成的,我们只管调用。HttpServletResponse与HttpServletRequest都是接口。如果你自己编写了一个服务器,而且实现了Servlet与JSP的接口与规范,那么你自己编写的这个服务器也可以是Servlet和JSP的容器(不完全的JAVAEE容器,因为完全的还需要实现EJB相关接口和规范)。
HttpServletResponse
Response对象代表响应,一个标准的HTTP响应包含三部分:状态行、响应头、响应数据。 常用方法有:
setStatus(int sc)
,设置响应的状态信息setHeader(java.lang.String name, java.lang.String value)
,设置响应的头信息getWriter()
,返回一个PrintWriter对象,给客户端发送信息getOutoutStream()
,返回一个ServletOutputStream对象,给客户端发送流信息
在学习过程中要注意,学习什么技术就查什么文档,例如现在在学习JavaEE中的Servlet技术,那么就查阅ServletAPI,不要查阅JavaEEAPI,这样更加方便,清晰。
###ResponseAPI
###response常见应用
-
向客户端输出中文数据
- OutputStream向客户端发送中文数据(默认编码与设定编码的问题,乱码的原因:客户端使用系统默认编码),处理方法:
设置响应头信息
- 使用HTML语言里面的
<meta>
标签来控制浏览器行为(模拟一个http响应头),也可以解决乱码问题 - 使用OutputStream输出数字1,应该字符化
- 使用PrintWriter来输出,设置response的编码(response默认的编码问题),还需要告诉浏览器(客户端)以什么编码方法打开,使用response的setHeader,简写可以使用setConteType
- OutputStream向客户端发送中文数据(默认编码与设定编码的问题,乱码的原因:客户端使用系统默认编码),处理方法:
-
文件下载和中文文件的下载
- 获取需要下载的文件、通知浏览器以下载的方式打开、向浏览器写出数据
- 如果下载文件的名字是中文,必须使用URL编码来进行处理
-
输出随机图片
- 在内存中创建一张图片
- 得到图片
- 设置背景颜色
- 设置图片边框
- 设置图片干扰线
- 向图片上写数据
- 把图片发送给客户端
- 使用中文做验证
- 设置浏览器不要缓存图片
-
定时刷新网页
- 使用response的消息头就可以让浏览器定时刷新网页
- 使用
meta
标签模拟(<meta http-equiv='refresh' content='3;url=/webapp/index.html'>
)
-
请求的重定向
- 重定向与转发的区别(一个向服务器发了两次请求,一个向服务器发了一次请求)
- 重定向发生,地址栏的地址会变化(重定向会增加服务器压力)
- 使用 302 状态码和 location 头来完成,也可以使用response的重定向跳转方法来完成
###response的细节
getOutputStream
和getWriter
方法分别用于得到输出二进制数据、输出文本数据的ServletOutputStream和PrintWriter对象- 这两个方法是互斥的,调用了其中的一个,另一个就不能再调用
- 在一个请求的整个调用链中,只能有一个流存在,如果需要写多种数据,使用字节流来完成
- Servlet引擎在service结束后,会自动检测response的流是否关闭,如果没有会自动关闭,然后再销毁Servlet,但是自己使用的流需要自己手动关闭
#HttpServletRequest HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象,就可以获取客户端的相关信息。
####常用方法:
getRequestURL方法返回客户端发出请求时的完整URL
,资源在互联网上的位置getRequestURI方法返回请求行中的资源名部分
,资源的位置getQueryString 方法返回请求行中的参数部分
getRemoteAddr方法返回发出请求的客户机的IP地址
,屏蔽IPgetRemoteHost方法返回发出请求的客户机的完整主机名
,注册DNS的主机名称,如果没有注册,返回IPgetRemotePort方法返回客户机所使用的网络端口号
getLocalAddr方法返回WEB服务器的IP地址
getLocalName方法返回WEB服务器的主机名
getMethod得到客户机请求方式
####获取客户端请求头:
getHead(name)方法
getHeaders(String name)方法
getHeaderNames方法
####获取客户端请求参数:
getParameter(name)方法
getParameterValues(String name)方法
getParameterNames方法
getParameterMap方法
getInputStream方法
###Request常见应用
####防盗链
防止自己网站的Web资源被别的网站使用。如果你有一个Servet,可以返回一些Web资源(图片、文章等等),那么在别的网站系统中,直接使用<a>
链接,或者发送一个http请求给你的Servlet应用,那么就能获取你网站的Web资源。
- 使用Request对象的
getHeader(“referer”)
方法来获取 referer 信息,rederer可以告诉我们当前这个请求是从哪个网站点击过来的。 - 如果没有使用网页点击,而是直接发送的http请求,那么 rederer 的值为null
- 检测 referer 的开头是否是本站,而且不能为 null,否则就重定向到本站首页
####获取各种表单输入项的数据 如果需要向服务器发送一系列数据,可以使用表单来完成。表单可以提交表单中的表单元素(表单项)的数据到服务器,浏览器会把表单中的可用元素(有name属性、disabled属性不为false的元素)的值封装起来。如果表单以get方式提交,那么这些值就会以 url 参数的形式发送给服务器,如果使用的是 post 方式提交,那么浏览器会将这些数据添加到 http 请求的消息体中(负载)发送给服务器。
常见表单元素:
- text
- password
- radio,如果两个radio的name相同,就表明它们是一组,每次只会有一个被选中,默认选中使用
checked = "checked"
设置,使用 value 值来提交真正的数据 - checkbox,多个值的获取,将多选按钮的名字都设置能一样的,在服务端使用
getParameterValues(name)
方法来获取多个值,返回值是一个数组,使用value值来提交真正的数据 - file
- select,配合 option 项来提交值,select 元素来设置name,具体的值用 option来设置
- textarea,默认值的设置不是用 value ,在标签体中来设置
- hidden,隐藏域
对于表单提交的数据,在服务端一定要做验证才能使用,不然很容易发生异常
####请求数据的中文乱码问题 在做web开发时,经常会遇到乱码的问题,最好的解决乱码的方式就是从一开始就统一编码。
- 如果出现乱码,首先要分析出现乱码的原因,也就是确定是哪一个环节导致了乱码
- 一般常见的是:request的默认编码是 IOS8859-1,而页面提交的数据(页面的编码可以使用响应头和
<meta>
标签来设置,一般推荐UTF-8)不是这个编码。对于这种编码一般很好解决,使用 request的 setCharacterEncoding(encoding) 方法来设置 request的编码就可以了,但是这种设置仅对 post 方式提交的请求有效 - 对于以 get 方式提交的请求,在Servlet中处理的话,只能使用手动的转码来实现,将 ISO8859-1 转成响应的编码。
- get 方式提交的请求的乱码,还有一种方式可以解决乱码:改变 Tomcat 的配置(给连接器配置一个属性:URIEncoding="UTF-8")。
- 如果超链接中提交的数据包含中文,一定要进行URL编码处理
关于get的乱码解决还有一种方式,就是使用 useBodyEncodingForURI="true",这种配置,这个配置的意思是:URI的编码用request实际设置的编码,这样配置后,request的 setCharacterEncoding(encoding) 对于get请求一样有效了。 对于改变服务器配置来解决乱码的方法,在实际开发中并不推荐,不要依赖服务器。
####request对象实现请求转发 使用request也可以实现请求的转发,在实际开发中,使用request做请求转发的多,一般不使用ServletContext做转发。如果在转发过程中需要传值到转发资源,使用request的setAttribute 方法来传值,在实际开发中,是使用 request 来进行转发和传值的,不使用ServletContext。因为ServletContext都整个Web应用中的Servlet共享,容易出现覆盖的问题,而request是独立的,不存在这个问题。 request也是一个域对象,是一个容器。
请求转发主要用来实现MVC设计模式。在MVC设计模式中,都是使用Servletl来处理用户请求,并且产生用户需要查看的数据,然后转发给jsp来显示,转发给jsp显示时,会把数据存在request域里面带给jsp。
####request域
- setAttribute 方法
- getAttribute 方法
- removeAttribute 方法
- getAttributeNames 方法
####请求转发中的细节 在使用转发的时候,有些小细节要注意:
- 如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正传送到了客户端,forward方法将抛出参数异常。(比如使用PrintWriter发送数据给客户端,然后关闭流,然后再使用request来转发,就会抛异常)
- 多次请求转发也是不可取的,一样会抛参数异常
- 关闭response的流,意味着提交响应结果到客户端,如果不关闭,就没有提交,还是有机会做别的响应处理的,那么别的响应处理将会覆盖掉之前的响应(之前的响应被清空,但是对于响应头的设置信息,会保留下来)
总结:在请求转发的前后,都不要写数据,写了也没有用!!!在Servlet中,只产生数据,但是不做输出,输出交给JSP(MVC)
####请求重定向和请求转发的区别
- 一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理,称之为请求转发
- 一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源,称之为请求重定向
- RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源
- 如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录
- 调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变
- HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求;RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为
- RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程
####RequestDispatcher的include方法
- RequestDispatcher.include方法用于将RequestDispatcher对象封装的资源内容作为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能
- 被包含的Servlet程序不能改变响应消息的状态码和响应头,如果它里面存在这样的语句,这些语句的执行结果将被忽略
####Web工程中地址的写法 在web开发中,经常会使用地址,如:
this.getServletContext().getRealPath("/")
request.getRequestDispatcher("/")
response.sendRedirect("/")
response.getWriter().write("<meta http-equiv='refresh' content='3;url=/'>")
<form aciont="/">
<a href="/">,<img src="">
对于这些地址,里面都可以用"/",这些有什么区别呢?总结:凡是给服务器用的地址,"/"代表当前web应用;凡是给浏览器用的地址,"/"代表网站(webapps) 还有"/"与"",前者使用在虚拟路径或者URL地址;后者使用在硬盘地址。 使用斜杠的地址,都是绝对地址,还有一些情况是需要相对地址的(后续课程)。
来源:oschina
链接:https://my.oschina.net/u/872668/blog/284710