Servlet是单例的
为什么Servlet是单例的
浏览器多次对Servlet的请求,一般情况下,服务器只创建一个Servlet对象,也就是说,Servlet对象一旦创建了,就会驻留在内存中,为后续的请求做服务,直到服务器关闭。对应着一个Servlet的生命周期(上节已经讲过)
之所以是单例的,这是一种设计模式的选择,而不是缺陷。
每次访问请求对象和响应对象都是新的
而对于每次访问请求,Servlet都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doPost或doGet方法。
单例导致的线程安全问题
当多个用户访问Servlet的时候,服务器会为每个用户创建一个线程。当多个用户并发访问Servlet共享资源的时候就会出现线程安全问题。
因此:
- 如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制synchronized (JavaSE基础)
- 如果一个变量不需要共享,则直接在 doGet() 或者 doPost()定义.这样不会存在线程安全问题
请求对象Request
如果我们想针对请求响应的内容进行操作,我们可以通过以下API 获取请求的相关资源:
①获取请求行数据
• String getContextPath():获取虚拟路径
• String getRequestURI(): 获取当前资源路径(真实路径是运行在服务器之后的路径,而不是存在于我们本地工作空间的目录)
②获取请求头数据
• String getHeader(String name) :通过请求头的名称获取请求头的值
• Enumeration
③获取请求体数据:
请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
• BufferedReader getReader() : 获取字符输入流,只可以操作字符数据
• ServletInputStrem getInputSterm():获取字节输入流,可以操作所有类型数据
④请求转发,跳转页面
- getRequestDispatcher(“b.jsp”).forward(request,response):(当前页面跳转到b.jsp)
⑤获取项目的ServletContext对象
ServletContext对象代表整个web应用,可以和程序的容器(服务器)来交互通信
获取途径:
- 通过request对象获取 request.getServletContext()
- 通过HttpServlet获取 this.getServletcContext( )
⑥获取请求参数的方法(get、post方法都通用)
在requests对象中,获取请求参数是公用的,post和get的差别就没有了,所以我们可以在doget中调用dopost(反之亦然)。
- string getParameter(String name) :根据参数名称获取参数值
- Map<string, String[]> getParameterMap() :获取所有参数的map集合
- Void SetCharacterEncoding(“utf-8”):设置post请求的编码格式
响应对象Response
①设置cookies
void addCookie( Cookie cookie );服务端向客户端增加cookie对象
②响应重定向
void sendRedirect(String location ) throws lOException;:页面跳转的一种方式(重定向)
③设置相应格式
void setContentType(String type):设置服务端响应的编码(设置服务端的contentType类型)
当响应格式是json时,应该设置为 application/json;charset=utf-8;
重定向与请求转发的区别:
我们从API可以看到,request有请求转发getRequestDispatcher,而response有重定向sendRedirect。
听上去好像没有什么区别,但其实这两者区别还是蛮大的。我们通过小案例看看先:
我编写了三个简单的jsp页面,不需要看懂,我会事无巨细的讲述里面每一句代码的意思。
我们的关注点只需要在于redirect和forward。
① 首先,我们编写一个HTML表单(login.jsp)
1 | <form action="check.jsp" method="post"> |
②然后,编写一个JSP代码(check.jsp)
1 | <% |
- <%%> 里面嵌套着Java代码,仅此而已。
- 我来解释一下其中的代码:
- request.setCharacterEncoding(“utf-8”):设置请求编码为UTF-8
- request.getParameter(“uname”):在介绍request的API讲过,意思是获取request请求中的uname属性。这里的传的参数对应着表单中的name属性
- 接下来,判断是否输入名称为“zs”,以及密码为“abc”,否则打印“用户名或密码有误”
- request.getRequestDispatcher(“success.jsp”).forward(request,response); 调用request的getRequestDispatcher方法,其接收一个资源文件。后面跟着的.forward表示进行转发,携带request和response参数。也就是说,携带着此次请求的所有参数。
③ 最后,编写一个验证成功的页面(success.jsp)
1 | 登录成功! |
我们这时候,先注册表单,然后提交:
接着,check.jsp会接收到数据,然后转发到success.jsp。(注意:我们使用的是请求转发)
- 可以看到,URL并未发生转变,但是内容已经是success.jsp页面,并且已经获取到我们注册的数据 “zs”。
那么,这次获取属性就算成功了。接下来我们看看重定向。
我们只需更改check.jsp的部分代码,而无需改动其他页面。
1 | <% |
- 调用response的sendRedirect方法,传入一个重定向的页面。
同样的,success.jsp会进行数据展示:
- 但是! 这里的uname却是null,为什么呢? 因为我们在check.jsp中获取到的参数在重定向的过程中丢失掉了。
- 而且,URL也发生变化,这里显示的success.jsp。
于是,我们得出以下结论:
请求转发 Forward的特点
1. 转发地址栏路径不变
2. 转发只能访问当前服务器下的资源
3. 转发是一次请求,可以使用request对象来共享数据
4. 转发是服务器跳转只能去往当前web应用的资源
重定向redirect的特点:
1. 地址栏发生变化
2. 重定向可以访问其他站点(服务器)的资源
3. 重定向是两次请求。request中数据会丢失
4. 重定向是服务器跳转,可以去往任何的资源
请求转发和重定向图解
后记
这个实验涉及到了作用域的问题,我们下次会进行讲解
下回见,peace~