大二第一学期的时候有学JSP的课,但是因为在开学之前做过JSP的小项目,所以一个学期的课也没听,直到期末考试成绩出来了,才回想JSP的内容还有多少记得,没想到模模糊糊也记不起多少,赶紧回头学回来。接下来是关于Servlet和JSP的梳理。 ---2018.01.15
------------------------------------------------------------------
在寒假里回顾JSP的内容的过程中,发现学校教的东西太少了(参考了《Servlet、JSP和Spring MVC初学指南》这本书,发现学校发的书里面并没有EL表达式、JSTL这些基础内容,更别说是过滤器这些了),遂返回去学习了一段时间,现在结合书和视频再把之前看不太下去的内容,后期会继续总结一下。 ---2018.2.21
------------------------------------------------------------------
接下来内容的分块参考《Servlet、JSP和Spring MVC》这本书。
Servlets
Servlet是一个Java程序,一个Servlet应用有一个或多个Servlet程序,而且JSP页面也会被转换和编译成Servlet程序。
Servlet应用无法独立运行,必须运行在Servlet容器中。Servlet容器将用户的请求传递给Servlet应用,并将结果返回给用户。由于大部分Servlet应用都包含多个JSP页面,因此更准确地说是“Servlet/JSP应用”。
其中,Servlet API是开发Servlet的主要技术。而Servlet API有以下4个Java包:
Java包 | 包含的内容 |
javax.servlet | 定义Servlet和Servlet容器之间契约的类和接口 |
javax.servlet.http | 定义HTTP Servlet和Servlet容器之间契约的类和接口 |
javax.servlet.annotation | 标注Servlet、Filter、Listener的标注。它还被标注原件定义元数据 |
javax.servlet.descriptor | 包含提供程序化登陆web应用程序的配置信息的类型。 |
Servlet技术的核心是Servlet,它是所有Servlet类必须直接或间接实现的一个接口,而Servlet接口定义了Servlet与Servlet容器之间的契约。这个契约归结起来就是,Servlet容器将Servlet类载入内存,并在Servlet实例上调用具体的方法。当用户的请求使得Servlet容器调用Servlet的Service方法,会传入一个ServletRequest实例和一个ServletResponse实例,其中,ServletRequest中封装了当前的HTTP请求,而ServletResponse表示当前用户的HTTP响应。对于每一个应用程序,Servlet容器还会创建一个ServletContext实例,这个对象中封装了上下文(应用程序)的环境详情。每个上下文只有一个ServletContext,而且每个Servlet实例都有一个配置的ServletConfig。
Servlet的生命周期方法:
Servlet容器的生命周期方法 | 作用 |
init | 该方法在Servlet第一次被请求的时候,Servlet就会调用这个方法,而后不再被调用,所以可以用这个方法进行初始化工作。调用这个方法时,Servlet容器会传入一个ServletConfig。 |
Service | 每当请求Servlet时,Servlet容器就会调用这个方法。第一次请求Servlet时,Servlet容器调用init方法和Service方法。后续的请求将只调用Service方法。 |
destroy | 当要销毁Servlet时,Servlet容器就会调用这个方法。一般会在这个方法中编写清除代码。 |
在介绍一个Servlet中另外两个非生命周期的方法:
Servlet容器的非生命周期方法 | 作用 |
getServletInfo | 这个方法会返回Servlet的描述 |
getServletConfig | 这个方法会返回由Servlet容器传给init方法的ServletConfig。 但是为了让getServletConfig返回一个非null值,必须将传给init方法的ServletConfig赋给一个类级变量。 |
接下来是Servlet的各类接口:
ServletRequest
接口 | 说明 |
ServletRequest | 对于每一个HTTP请求,Servlet容器都会创建一个ServletRequest实例,并将它传给Servlet的Service方法。ServletRequest封装了关于这个请求的信息。 |
常用的方法有:
方法 | 说明 |
public int getContentLength() | 返回请求主体的字节数。 |
public java.lang.String getContentType() | 返回请求主体的MIME类型。 |
public java.lang.String getParameter(java.lang.String name) | 返回指定请求参数的值 |
public java.lang.String getProtocol() | 返回这个HTTP请求的协议名称和版本 |
ServletResponse
接口 | 说明 |
ServletResponse | 该接口表示一个Servlet响应。在调用Servlet的Service方法前,Servlet容器首先创建一个ServletResponse,并将它作为第二个参数传给Service方法。ServletResponse隐藏了向浏览器发送响应的复杂过程。 |
常用的方法:
方法 | 说明 |
getWriter() | 返回了一个可以向客户端发送文本的java.io.PrintWriter。默认情况下,PrintWriter对象使用ISO-8859-1编码。 |
setContentType(“type”) | 设置响应的内容类型,并将”text/html”作为一个参数传入。如果没有设置相应内容类型,有些浏览器就会将HTML标签显示为普通文本。 |
ServletConfig
接口 | 说明 |
ServletConfig | 用于存储关于Servlet的配置信息。 当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init()方法传入一个ServletConfig。ServletConfig封装可以通过@WebServlet或描述符传给Servlet的配置信息。 |
常用的方法:
方法 | 说明 |
java.lang.String getInitParameter(java,lang.String name) | 为了从Servlet内部获取到初始参数的值,要在Servlet容器传给Servlet的init方法的ServletConfig中调用getInitParameter方法。 |
java.util.Enumration<java.lang.String> getInitParameterNames() | 返回所有初始参数名称的一个Enumeration。 |
String contactName = servletConfig.getInitParameter(“contactName”) | 获取contactName参数值 |
ServletContext
接口 | 说明 |
ServletContext | 每个Web应用程序只有一个上下文,所以ServletContext可以存储这个上下文,并且ServletContext还可以共享从应用程序中的所有资料处访问到的信息,并且可以动态注册Web对象,而且是用ServletContext内部的Map保存。 |
常用的方法:
方法 | 说明 |
getServletContext().getInitParameter(String name) | 获取在项目下的web.xml中设置context的初始化参数 |
this.getServletContext().log(“测试”) | 在web.xml文件中,使用logger元素来设置日志文件 |
getAttribute(String name)/get AttributeNames() | 获取ServletContext中的属性 |
setAttribute(String name, Object object) | 设置ServletContext中的属性 |
removeAttribute(String name) | 移除ServletContext中的属性 |
GenericServlet
接口 | 说明 |
GenericServlet | GenericServlet实现了Servlet和ServletConfig接口。将init方法中的ServletConfig赋给一个类级变量,以便可以通过getServletConfig获取,为Servlet接口中的所有方法提供默认的实现,而且提供包括ServletConfig中的方法。 |
Http Servlets
接口 | 说明 |
HttpServlet | HttpServlet类覆盖了javax.servlet.GenericServlet类。使用HttpServlet时,还要借助分别代表Servlet请求和Servlet响应的HttpServletRequest和HttpServletResponse对象。而HttpServlet与GenericServlet的差别在于,HttpServlet覆盖的是doGet或者doPost方法,而不是Service方法,而且使用的是HttpServletRequest和HttpServletResponse,而不是ServletRequest和ServletResponse。 |
HttpServletRequest | 表示HTTP环境中的Servlet请求 |
HttpServletResponse | 表示HTTP环境中的Servlet响应 |
各个接口常用的方法如下:
接口 | 方法 | 说明 |
HttpServletRequest | java.lang.String getContextPath() | 返回表示请求上下文的请求URI部分。 |
HttpServletRequest | Cookie[] getCookies() | 返回一个Cookie对象的数组。 |
HttpServletRequest | java.lang.String getHeader(java.lang.String name) | 返回指定HTTP标题的值。 |
HttpServletRequest | java.lang.String getMethod() | 返回生成这个请求的HTTP方法名称 |
HttpServletRequest | java.lang.String getQueryString() | 返回请求URL中的查询字符串。 |
HttpServletRequest | HttpSession getSession() | 返回与这个请求相关的会话对象。如果没有,将创建一个新的会话对象。 |
HttpServletRequest | HttpSession getSession(Boolean create) | 返回与这个请求相关的绘画对象,如果有,并且create参数为True,将创建一个新的会话对象。 |
HttpServletResponse | void addCookie(Cookie cookie) | 给这个响应对象添加一个cookie。 |
HttpServletResponse | void addHeader(java.lang.String name, java.lang.String value) | 给这个响应对象添加一个header。 |
HttpServletResponse | void sendRedirect(java.lang.String location) | 发送一条响应码,将浏览器跳转到指定的位置。 |
当用户提交HTML表单时,在表单元素中输入的值就会被当作请求参数发送到服务器。HTML输入域(文本域、隐藏域或者密码域)或者文本区的值,会被当作字符串发送到服务器。空的输入域或者文本区会发送空的字符串。
包含多个值的select元素发出一个字符串数组,可以通过ServletRequest.getParameterValues进行处理。
核查过的复选框会发送字符串"on"到服务器,未经核查的复选框则不向服务器发送任何内容,ServletRequest.getParameter(fieldName)返回null。
单选框将被选中按钮的值发送到服务器。如果没有选择任何按钮,将没有任何内容被发送到服务器,并且ServletRequest.getParameter(fieldName)返会null。
如果一个表单中包含多个输入同名的元素,那么所有值都会被提交,并且必须利用ServletRequest.getParameterValues来获取它们。ServletRequest.getParameter将只返回最后一个值。
会话管理
由于HTTP的无状态性(不会保存会话),使得会话管理或会话跟踪称为Web应用开发的一个重点主题。这儿会介绍四种不同的状态保持技术:URL重写、隐藏域、cookies、HTTPSession对象。
URL重写
URL重写是一种将一个后多个token添加到URL的查询字符串中,每个token通常为key=value形式。如下:
url?key-1=value-1&key-2=value-2 ... &key-n=value-n //注意,URL和token之间用问号(?)分割,token间用与号(&)
但是URL重写有以下限制:
① URL在某些浏览器上最大长度为2000字符。
② 若要传递值到下一个资源,需要将值插入到链接中,也就是说静态页面很难传值。
③ URL重写需要在服务端上完成,所有的链接都必须带值,因此当一个页面存在很多链接时,处理过程会是一个不小的挑战。
④ 某些字符,例如空格、与和问号等必须用base64编码。
⑤ 所有的信息都是可见的,不利于信息保护。
因为上面的限制,所以URL重写仅适合于信息仅在少量页面间传递,且信息本身不敏感。
隐藏域
使用隐藏域来保持状态类似于URL重写技术,但不是将值附加到URL上,而是放在HTML表单的隐藏域中。当表单提交时,隐藏域的值也同时提交到服务器端。隐藏域技术仅当网页哟表单时有效。该技术相对于URL重写的优势在于,没有字符数限制,同时无需额外的编码,但是它也不适合跨越多个页面。
<input type="hidden" value="1" name="hide>.....
Cookie
Cookie是一个很少的信息片段,可自动地在浏览器和Web服务器间交互,因此cookie可存储在多个页面间传递的信息。Cookie作为HTTP header的一部分,其传输由HTTP协议控制。此外,你可以控制cookies的有效时间(浏览器通常支持每个网站高达20个cookies)。但是yoghurt可以通过改变其浏览器设置来拒绝接受cookies。
使用Cookie:
① 可以通过传递name和value两个参数给Cookie类的构造函数来创建一个cookies:
Cookie cookie = new Cookie(name,value);
② 创建完一个Cookie对象后,可以设置domain(访问此cookie的域名)、path(访问此Cookie的页面路径)、maxAge(决定cookie何时过期)属性。
③ 要将cookie发送到浏览器,需要调用HttpServletResponse的add方法。
HttpServletResponse.addCookie(cookie);
④ 服务器若要读取浏览器提交的cookie,可以通过HttpServletRequest接口的getCookies方法,该方法返回一个Cookie数组,若没有cookies则返回null。
Cookie[] cookies = request.getCookies(); Cookie maxRecordCookie = null; if(cookies!=null){ for(Cookie cookie:cookies){ if(cookie.getName().equals("maxRecords"){ maxRecordsCookie = cookie; break; } } }
⑤ 如果要删除一个cookie,也只能这么做:
Cookie cookie = new Cookie("userName",""); cookie.setMaxAge(0); response.addCookie(cookie);
HttpSession
在所有的会话跟踪技术中,HttpSession对象是最强大和最通用的。一个用户可以有且最多有一个HttpSession,并且不会被其他用户访问到。
① HttpSession对象在用户第一次访问网站的时候自动被创建,可通过调用HttpServletRequest的getSession方法获取该对象。getSession有两个重载方法:
HttpSession getSession() HttpSession getSession(boolean create)
没有参数的getSession方法会返回当前的httpSession,若当前没有,则创建一个返回getSession(false)返回当前HttpSession,如果当前存在,则返回null。getSession(true)返回当前HttpSession,若当前没有,则创建一个getSession(true)同getSession()一致。
② 可以通过HttpSession的setAttribute方法将值放入HttpSession,而且放入到HttpSession的值,是存储在内存中的。
void setAttribute(java.String name, java.lang.Object value) //如果传入的name值之前被用过,则会用性质覆盖旧值。
③ 通过调用HttpSession的getAttribute方法可以取回之前放入的对象。
java.lang.Object getAttribute(java.lang.String name)
④ getAttributeNames()会放回一个Enumeration对象来迭代访问保存在HttpSession中的所有值。
java.util.Enumeration<java.lang.String> getAttributeNames()
⑤ 可以调用HttpSession的getId方法来读取该标识。
java.lang.String getId()
⑥ HttpSession定义了一个名为invalidate方法来强制会话过期,并清空其保存的对象。
void HttpSession.invalidate()
⑦ 可以通过调用HttpSession的getMaxInactiveInterval方法来查看会话多久会过期。
void setMaxInactiveInterval(int seconds)
不过HttpSession的缺点就是,相比起URL重写、隐藏域和cookie会更消耗服务器内存。