Servlet
(1)Servlet与Tomcat的关系
图略
(2)概念
不能独立运行,要依赖于Web容器的一种Java服务器程序。
(3)Servlet开发的三种方式
需求:
1.进行Servlet开发,tomcat服务器向客户端发送信息。
步骤:
1.创建web应用。
2.将Servlet部署到web.xml
1. 实现Servlet接口
public class FirstServlet implements Servlet
{ //该函数用于Servlet初始化,并将其装载内存中
//该函数只运行一次,需要在server.xml文件中进行配置<load-on-start>.
public void init(ServletConfig config)throws ServletException
{ }
//得到ServletConfig对象
public ServletConfig getServletConfig()
{ }
//该函数是服务函数,业务逻辑代码就是在这里编写
//每次启动服务都会调用该函数
//当调用doGet或者doPost才构造ServletRequest和ServletResponse对象
public void service(ServletRequest req,ServletResponse res)
throws ServletException,java.io.IOException
{ }
//获取Servlet的配置信息
public java.lang.String getServletInfo()
{ }
//该函数用于销毁Servlet
//只运行一次
public void destroy(){ }
}
2. 继承GenericServlet
相对于Servlet来说,是需要继承server函数即可。
GenericServlet抽象类,给出了一些设计servlet的一些骨架,定义了servlet的生命周期,还有一些得到的名字,配置初始化参数的方法,其设计是和应用层协议无关的。
3. 继承HttpServlet(常用)
public class FirstHttpServlet extends HttpServlet
{
//两个底层都代用了server函数
//Http协议中的get请求和post请求
//与<form action="提交给?" method="get ro post?"/>中有关
protected void doGet(HttpServletRequest req,HttpServletResonse resp)
throws ServletException,java.io.IOException
{
resp.getWriter().println("HttpServlet");
}
protected void doPost(HttpServletRequest req,HttpServletResonse resp)
throws ServletException,java.io.IOException
{
resp.getWriter().println("HttpServlet");
}
}
(4)Servlet细节
1. Servlet的部署
<!—进行servlet的注册-->
<!-在android开发中的每个Activity都必须要注册—>
<servlet>
<!--servlet-name 可以自定义,但是默认为类名-->
<servlet-name>MyServlet</servlet-name>
<!--servlet-class 用于指定servlet存放在哪一个包中(包名+类名),一定要明确-->
<servlet-class>name.liushiyao.myservlet.MyServlet</servlet-class>
</servlet>
<!-- servlet 的映射(对一个已经注册的Servlet的映射)-->
<!--一个注册号的Servlet可以被多次映射-->
<servlet-mapping>
<!-- 该servlet-name 一定要去上面的servlet-name 相同-->
<servlet-name>MyServlet</servlet-name>
<!--url 的资源文件名(斜杠必须有)-->
<url-pattern>/ab</url-pattern>
</servlet-mapping>
注:
1. 如果url中没有加“/”运行时会出现错误。
2.在IDEA中(应该是JavaEE6的新特性,使用了annotation),可以使用@WebServlet(name = “LastTime”, urlPatterns ={“/LastTime”,”/LastTime2”})进行WebServlet的映射,且可以实现多对一映射,而不需要在web.xml中进行注册。
2. 通配符
1) /*
2) *.拓展名
注:1)比2)优先级高。
3. 单例多线程
当Servlet被第一访问后,就被加载到内存中,以后该实例对各个请求都是用的是同一个内容。JSP也是单例模式。
servlet是多线程的,没有采用同步机制,是不安全的。同一个Servlet可以同时处理多个客户端的请求,比如同时有两个用户A和用户B登录时,会启动两个负责登录的Servlet线程,并通过触发Service方法来处理请求。在两个线程中,接收到的用户名是不同的,也就是说,多线程里的Servlet,可能其中的变量不相同。
4. servlet中的配置
需求:当我们的网站启动的时候,可能会要求初始化一些数据(创建临时表),或者要求定时备份数据,发送邮件。
解决办法:可以通过<load-on-startup>配合,线程知识搞定。
通过配置<load-on-startup>,启动一个servlet中的init函数,且只运行一次。
在web.xml文件中进行配置
<!-- 配置init启动的优先级(必须配置,否者init()不会执行) -->
<load-on-startup>1</load-on-startup>
<!—数值代表启动的顺序-->
【模拟定时发送电子邮件】
//用于发送电子邮件的线程
public class Send extends Thread
{
@Override
public void run() {
int count = 0;
while(true)
{
try {
//====每隔10s发送电子邮件
Thread.sleep(10*1000);
System.out.println("第"+(++count)+"份邮件被发送");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//使用init函数进行线程的启动
public void init() throws ServletException {
// Put your code here
System.out.println("ServletInit 的init函数运行。。。");
Send send = new Send();
send.start();
}
ServletConfig对象
1. 用途
用于读取Servlet的一些配置信息。
在web.xml文件中。
<!-- 使用UTF-8编码 -->
<!-- 局部servlet有效 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
注:String contextString = this.getServletConfig.getInitParameter(“encoding”);
要使被所有的servlet读取,应该在之外定义:
<!—所有servlet有效 -->
<context-param>
<param-name></param-name>
<param-value></param-value>
</context-param>
注:通过String contextString = this.getServletContext().getInitParameter(“encode”);获取
因为该属性属于全局变量,而ServletContext也是属性全局的,所以要通过getServletContext获取,而不是通过getServletConfig获取。
【获取ServletConfig中的数据】
1. 获取单一的数据在Servlet中
response.setContentType("text/html;charset=utf-8");//默认编码
PrintWriter printWriter = response.getWriter();
//获取param参数内容
String encodingString = this.getServletConfig().getInitParameter("encoding");
request.setCharacterEncoding(encodingString);
printWriter.println(encodingString);
printWriter.close();
- 获取所有的数据
//获取所有的param的enum对象
Enumeration<String> enum1 = this.getServletConfig().getInitParameterNames();
while (enum1.hasMoreElements()) {
String string = (String) enum1.nextElement();
System.out.println(string);
System.out.println(this.getServletConfig().getInitParameter(string));
}
HttpResponse对象
所有的信息多会封装到response中,返回给web服务。web服务器会将response信息进行拆解,形成http相应信息,返回给浏览器。
1. getWrite();与getOutputStream()
注:一个是字符流,一个是字节流。虽然说两者可以相互转换,但是针对不同的数据针对性的使用。
两个流不能同时使用。否则会出现如下异常:
java.lang.IllegalStateException: getWriter() has already been called for this response
org.apache.catalina.connector.Response.getOutputStream(Response.java:605)
org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:197)
name.liushiyao.userlogin.Download.doGet(Download.java:37)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
注:会自动关闭IO,所以不能同时出现getWrite();getOutputStream();
2. sendRedirect();
sendRedirect( 重定向)发生在浏览器的跳转,服务器根据逻辑,发送一个状态码,告诉浏览器去重新请求那个地址。
实现界面的跳转,并可以随带字符串信息。
1. 实现跳转:
//执行调转到登录成功界面(java中其中一种跳转方式)
//"/web应用名/servlet"
response.sendRedirect("/UserLogin/MainFrame");
- 携带字符串信息:
response.sendRedirect("/UserLogin/MainFrame?uname="+
name+"&upassword="+password
注:url与字符串信息之间通过“?”进行连接。
不同的字符串之间通过“&”连接。
sendRedirect不能实现对象的传递。但是可以通过session传递(也不能说是“传递”,只是在服务器内存中存储的session)。
User u = new User(name,password);
request.getSession().setAttribute("u",u);
- 获取对象:
User us = (User)request.getSession().getAttribute("u");
out.println(us.getName()+"||"+us.getPassword());
HttpRequest对象
该对象表示浏览器的请求,即http请求信息。但web服务器等到该请求后,会把浏览器请求的信息封装成HttpRequest对象。因此可以通过该对象获取用户的各种请求信息。
1. getRequestURL();
String uri = request.getRequestURI();
String url = request.getRequestURL().toString();
System.out.println("uri"+uri);
System.out.println("url"+url);
输出:
uri /RequestDemo/RequestInfo
url http://localhost:8080/RequestDemo/RequestInfo
2. getQueryString();
以GET方法获取参数信息(参数+值)。
String quary = request.getQueryString();
System.out.println("query:"+quary);
输出:
query:name=123
注:这个的参数时url后面带的所有信息,而request.getParameter(“age”);则是当个属性所带的值
3. getRemoteAddr();
可以获取用户的ip地址。(利用该函数可进行ip封杀)
4. getRemotePort();
获取用户的端口。
int localport = request.getLocalPort();
int port = request.getRemotePort();
System.out.println("localport:"+localport);
System.out.println("port:"+port);
5. getParameterValues();
获得传过来的参数名相同的一个数组;
String[] string = request.getParameterValues(“checkbox”);
6. getRequestDispatcher();
request转向函数。
request.getRequestDispatcher("/MainFrame").forward(request,
response);
实现原理:
- sendReDirect与forward的区别?
forward(转向):发生在服务器的跳转,服务器请求资源,直接访问目标地址的URL,把URL的响应再发送给浏览器,浏览器根本不知道服务器发送的内容是从哪里来的,所以地址栏中的URL还是原来的。
答:(1)叫法不同:sendReDirect()叫重定向(转发);forward叫转向。
(2)实际发送的位置不同:sendReDirect发生在浏览器;forward发生在服务器
(3)用法不同:response.sendReDirect(“/web应用/资源URI”);需要加‘/web应用名’(根据其原理可以知道)
request.getRequestDispather(“/资源URI”).forward(request,response);
不需要加web应用名
(4)范围不同:sendReDirect 与浏览器之间
forward 与web服务器之间。
注:1.所谓的一次http请求:就是没有重回到浏览器或者重新启动则叫为“一次http请求”。
2.request.setAttribute(“key”,”123”);//存储此请求中的属性。在请求之间重置属性。此方法常常与 RequestDispatcher 一起使用。
3. //效果同request.getRequestDispather request.getServletContext().getRequestDispatcher(“/OtherServlet”).forward(request,response);
4. 使用sendReDirect可以防止刷新带来的再次访问servlet(因为sendReDirect需要web应用名)
Cookie
1. 概念
cookie是客户端技术,服务器把每个用户的数据以cookie的形式写给用户各自的浏览器。 Cookie包含属性(String)和值(String)。注:1. Cookie只能保存字符串(键值对)
2. 客户端在发送Http请求时,会携带该Web应用的Cookie。
3. Cookie必须设置setMaxAge,否则Cookie在浏览器关闭时被销毁(setMaxAge(0)则销毁Cookie)。
4. 可以被多个浏览器共享。
5. 如果Cookie重名,会覆盖之前的数据。
6. 当web创建多个Cookie时,会保存在同一个文件中,并且存在时间可以不一样。
7. 创建Cookie时禁止使用“ 空格、逗号”等。
2. Cookie的用途
账号和密码的保存(需要加密)、用户的喜好、设置等等。3. Cookie的限制
一个浏览器只能存放300个Cookie,一个web站点最多存储20个Cookie,且 每个大小限制在4K。4.禁用Cookie
如果用户禁用Cookie,可以使用URL重写技术跟踪回话。5. Cookie的生命周期
Cookie的生命周期指的是累积时间,即从开始创建时间到设置的结束时间的长度。Session
1. 概念
Session(域对象)是服务器端技术,当用户打开浏览器,访问服务器。服务器为每一个浏览器提供一个Session对象。 Session包含属性(String)和值(Object)。注:1. 只要不关闭浏览器,不同的页面就会处于同一个Session中,而这个Session默认的生存时间是1800s(30分钟,可以在web.xml中修改)。
2. session是存放在服务器的内存中的
3. session被特定的一个浏览器所独享
4. 当同一个session中的属性名相同时则会覆盖前一个属性值
2. Session的生命周期
- 在web.xml中可以进行生存时间的设定
<session-config>
<session-timeout>20</session-timeout>
</session-config>
- 使用httpSession.setMaxInactiveInterval(60);
//该时间设置的是“发呆时间”—用户没有操作Session的时间 - 当关闭或重启Tomcat时都会删除Session(Session是保存在内存中的)或者使用 invalidate(); 删除Session中所有的属性和对象(强制性的,用于安全退出)
- 单独删除一个对象
httpSession.removeAttribute(“name”);
3. Session的原理
服务器如何为特定的浏览器分配特定的Session?
答:通过ID
实现流程:
1. 当浏览器第一次访问Servlet时,Cookie中是没有携带JSESSIONID
(Cookie JSESSIONID=D7561FE5F83BACF4E0091BCDADE04078),
2. 访问Servlet之后,会生成Session并分配Session ID,通过Cookie写入浏览器中;
3. 当用户再次访问Servlet,http请求会携带带有JSESSIONID的cookie,此时服务器就能准确的知道该浏览器是与那个Session相关联的。
6. Cookie与Session的区别?
①存在的位置不同:
Cookie:存在客户端(临时文件夹)
Session:存在服务器的内存中(一个Session域对象为一个用户浏览器服务)
②安全性
Cookie:是以明文方式存放在客户端,安全性较弱(可以通过加密的方式进行加密)
Session:是存在服务器中的内存中,安全性较强。、
③网络通信量
Cookie:会传递信息给服务器(每次在Http请求中都会携带Cookie,所以会增加网络压力)(所以获取Cookie时是从Request中获取 的)
Session:session是存在服务器的内存中的,所以不存在网络通信压力问题。
④生命周期
Cookie:是累积时间,即为绝对时间
Session:是“发呆时间”,即相对时间(当浏览器没有对session进行操作时的间隔时间)。session失效是指无法访问session的属性(API解释:使此会话无效,然后取消对任何绑定到它的对象的绑定。)。相关应用(安全退出)
⑤访问范围
Cookie:浏览器共享
Session:浏览器独享
注:Session会占用服务器的内存,所以要根据实际情况进行取舍。
ServletContext
1. 概念
Web容器在启动时,它会为每一个Web应用程序都创建一个对应的ServletContext对象,它代表web应用。
注:可以被多个用户共享(同一个Web应用中的所有Servlet)
2. 获取ServletContext
//方法一(通过this)
ServletContext servletContext = this.getServletContext();
//方法二(通过getServletConfig)
ServletContext servletContext1 = this.getServletConfig().getServletContext();
3. 添加ServletContext属性
servletContext.setAttribute(“name”,”刘石尧”);
4. 读取ServletContext属性
String string = (String) servletContext.getAttribute(“name”);
5. 删除ServletContxt 属性
if (servletContext.getAttribute(“name”) != null){
servletContext.removeAttribute(“name”);
out.println(“已删除 name”);
}
6. 使用ServletContext的使用原则
需要数据共享,而且存储的大小不大又不想出入数据库,可以使用ServletContext。
7. ServletContext的生命周期
ServletContext是长期存放在服务器中的内存中的,所有不将过大的数据存放在ServletContext中。
8.获取web.xml中的设置参数
context.getInitParameter("param");
会话跟踪
会话跟踪是一种灵活,轻便的机制,使Web上的状态变成成为可能。
可是使用session,Cookie,地址重写和隐藏域实现。
JSP
JSP九大内置对象
内置对象 | 对象名称 | 类型 | 作用域 |
---|---|---|---|
request | 请求对象 | javax.servlet.ServletReques | Request |
response | 响应对象 | javax.servlet.SrvletResponse | Page |
pageContext | 页面上下文对象 | javax.servlet.jsp.PageContext | Page |
session | 会话对象 | javax.servlet.http.HttpSession | Session |
application | 应用程序对象 | javax.servlet.ServletContext | Application |
out | 输出对象 | javax.servlet.jsp.JspWriter | Page |
config | 配置对象 | javax.servlet.ServletConfig | Page |
page | 页面对象 | javax.lang.Object | Page |
exception | 例外对象 | javax.lang.Throwable | page |
注:“exception” 对象则代表了JSP文件运行时所产生的例外对象,此对象不能在一般JSP文件中直接使用,而只能在使用了“<%@ page isErrorPage=”true “%>”的JSP文件中使用。
作用域
作用域 | 范围 | 说明 |
---|---|---|
page | 有效范围只在当前jsp页面里 | 从把变量放到pageContext开始,到jsp页面结束,你都可以使用这个变量。 |
request | 有效范围是当前请求周期 | 所谓请求周期,就是指从http请求发起,到服务器处理结束,返回响应的整个过程。在这个过程中可能使用forward的方式跳转了多个jsp页面,在这些页面里你都可以使用这个变量。 |
session | 有效范围是当前会话 | 所谓当前会话,就是指从用户打开浏览器开始,到用户关闭浏览器这中间的过程。这个过程可能包含多个请求响应。也就是说,只要用户不关浏览器,服务器就有办法知道这些请求是一个人发起的,整个过程被称为一个会话(session),而放到会话中的变量,就可以在当前会话的所有请求里使用。 |
application | 有效范围是整个应用 | 整个应用是指从应用启动,到应用结束。我们没有说“从服务器启动,到服务器关闭”,是因为一个服务器可能部署多个应用,当然你关闭了服务器,就会把上面所有的应用都关闭了。 |
application作用域里的变量,它们的存活时间是最长的,如果不进行手工删除,它们就一直可以使用。
注:application里的变量可以被所有用户共用。如果用户甲的操作修改了application中的变量,用户乙访问时得到的是修改后的值。这在其他scope中都是不会发生的,page, request,session都是完全隔离的,无论如何修改都不会影响其他人的数据。
jsp注释
1. <%-- JSP中的注释,看不见 --%>
2. // 注释,看不见
3. /*
注释,看不见
*/
4. <!--显式注释-->
JSP语法
脚本
<% java代码 %>:在<%%>中定义局部变量或者调用方法,但不能定义方法。
<%!%>:可以在<%!%>中声明方法、属性、全局变量。
<%=%>:称作jsp表达式,用于将已经声明的变量或者表达式输出到网页上面。
include指令
静态include:
从外部引入一个jsp文件(只含指令和内容本身,不需要body等其他内容),编译成同一个servlet。属于静态引入。
<%@ include file="B.jsp" %>
动态include:
<jsp:include />
注:动态引入,会翻译成两个servlet。所以被引入的文件可以包含等内容。