Servlet传递数据方式
基本概述
Servlet传递数据的方式有很多,这里提供五种方式:
1、静态变量
2、HttpServletResponse的sendRedirect()方法
3、HttpServletRequest的getRequestDispatch()方法
4、HttpServletRequest的getSession()方法
5、HttpServletRequest的setAttribute()方法
静态变量
通过建立一个数据类来进行传递。
案例:
public class MyData{
public static String data; //通过使用该类来实现数据传递
}
接收到客户端请求后,可以通过 HttpServletResponse 对象直接进行响应,响应时需要获取输出流,
有两种形式
getWriter()获取字符流(只能响应回字符);
getOutputStream()获取字节流(能响应一切数据)。
响应回的数据到客户端被浏览器解析。
注意:两者不能同时使用。
HttpServletResponse的sendRedirect()方法
sendRedirect()方法是让浏览器重定向到另一个链接。其内部原理是设置状态码为303,并设置相应的Location响应头。
基本语法:
response.sendRedirect("/Web应用名/资源名?uname="+username+"&pwd="+password);
response.sendRedirect(“servlet的地址?参数名=参数值&参数名=参数值...”);
参照值是String , 参数名应当使用 字母组合
在接受数据的Servlet中:
String 参数=request.getParameter(“参数名”);
基本原理图

PS:使用重定向不能使用PrintWrite,ServletOutputStream这样的流。因为重定向已经将消息返回给浏览器,其数据流也就没必要使用了。
HttpServletRequest的getRequestDispatch()方法
getRequestDispatch()方法是使WEB服务器从当前Servlet转发到当前应用下的另一个Servlet。
基本语法:
request.getRequestDispatcher(资源地址).forward(request,response);
资源地址:不需要项目名。因为它只能在WEB服务器内部转发。
基本原理图
PS:getRequestDispatcher()请求转发可以一直转发下去,只要最终会处理并给服务器相应内容就行了。而且请求转发不会改变浏览器的URL,sendRedirect()会改变URL。
注意事项:
1、使用forward不能转发到该WEB应用外的URL
2、因为forward发生在文本服务器内,所以Servlet1、Servlet2等等,只要一直转发,使用的都是相同的request和response
示例:
@SuppressWarnings("serial")
public class Servlet02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet02...");
// 设置响应类型
resp.setContentType("text/html;charset=UTF-8");
// getWriter()获取字符流(只能响应回字符);
//PrintWriter writer = resp.getWriter();
//writer.write("<h4>Hello Servlet</h4>");
//writer.close();
// getOutputStream()获取字节流(能响应一切数据)。
//OutputStream outputStream = resp.getOutputStream();
//outputStream.write("<h4>Hello MyServlet</h4>".getBytes());
//outputStream.close()
String form = "<form action='ser02' method='get'>"
+ "<div class='form-group'><label for='uname'>名称</label>"
+ " <input type='text' class='form-control' name='uname' placeholder='请输入名称'>"
+ "</div> <div class='form-group'> <label for='upwd'>密码</label> "
+ " <input type='password' class='form-control' name='upwd' placeholder='请输入密码'> </div>"
+ " <button type='submit' >提交</button> </form>";//拼接表格
resp.getWriter().write(form);
resp.getWriter().close();
}
}
HttpServletRequest的getSession()方法
getSession()方法会获取一个会话,这个内容会在另一篇博客会话技术中详细说明。
基本语法:
1、放入session:request.getSession.setAttribute("loginUser",username);
2、取出session:request.getSession.getAttribute("loginUser");
PS:该方法可以传递对象
案例:
放入:
User user= new User();
user.setName(“zs”);
user.setPassWord(“123”);
request.getSession.setAttribute("userObj",userObj);
取出:
User user=(User)request.getSession.getAttribute(“userObj”);
HttpServletRequest的setAttribute()方法
setAttribute()方法可以设置一个键值对,该键值对在该request的有效期内都可以使用。相应的还有removeAttribute()注销键值对的方法。该方法经常和getRequestDispatch()一起使用。
基本语法:
setAttribute(name, value);
PS:request的Attribute在一次请求中有效。一次请求:没有将响应消息返回给浏览器就视为一次请求。
比较sendRedirect()和forward(request,response)
1、sendRedirect()重定向,forward()转发
2、实际发生的位置不一样
sendRedirect 发生在浏览器
forward 发生在web服务器
3、使用用法不一样
request.getRequestDispatcher(“/资源URI”).forward(request,response)
response.sendRedirect(“/web应用/资源URI”);
4、能够去URL范围不一样
sendRedirect可以去任意URL
forward 只能去当前的WEB应用的资源
乱码解决
如果响应的内容中含有中文,则有可能出现乱码。
这是因为服务器响应的数据也会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则出现乱码。
getWriter()的字符乱码
对于 getWriter()获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用 ISO-8859-1 格式的编码,该编码方式并不支持中文。
所以要解决该种乱码只能在服务器端告知服务器使用一种能够支持中文的编码格式,
比如我们通常用的“UTF-8” resp.setCharacterEncoding("UTF-8");,
此时还只完成了一半的工作,要保证数据正确显示,还需要指定客户端的解码方式
resp.setHeader("content-type", "text/html;charset=UTF-8");,
和服务器一致。两端指定编码后,乱码就解决了。
一句话:保证发送端和接收端的编码一致
getOutputStream()字节乱码
对于 getOutputStream()方式获取到的字节流,响应中文时,由于本身就是传输的字节, 所以此时可能出现乱码,也可能正确显示,这就看人品了^_^。
当服务器端给的字节恰好和客户端使用的编码方式一致时则文本正确显示,否则出现乱码。
无论如何我们都应该准确掌握服务器和客户端使用的是那种编码格式,以确保数据正确显示。指定客户端和服务器使用的编码方式一致即可 。
示例:
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet03...");
/* 设置客服端和服务端的编码一致,并支持中文*/
// 设置服务端的编码
//resp.setCharacterEncoding("UTF-8");
// 设置客户端的编码
//resp.setHeader("content-type", "text/html;charset=UTF-8");
// 使用一句代码代替上面两句
resp.setContentType("text/html;charset=UTF-8"); // 设置响应类型及编码格式
// getWriter()获取字符流(只能响应回字符);
/*PrintWriter writer = resp.getWriter();
writer.write("<h4>你好</h4>");
writer.close();*/
// getOutputStream()获取字节流(能响应一切数据)。
OutputStream outputStream = resp.getOutputStream();
outputStream.write("<h4>你好</h4>".getBytes());
outputStream.close();
}
}
总结:
乱码的原因:
1、客户端和服务端编码不一致
2、编码不支持中文
解决方案:
保证客户端和服务端编码一致且支持中文
response.setContentType("text/html;charset=UTF-8");
三、请求转发和重定向
请求转发:
request.getRequestDispatcher(URL地址).forward(request, response)
处理流程:
客户端发送请求,Servlet做出业务逻辑处理。
Servlet调用forword()方法,服务器Servlet把目标资源返回给客户端浏览器。
请求转发
2)重定向:
response.sendRedirect(URL地址)
处理流程:
客户端发送请求,Servlet做出业务逻辑处理。
Servlet调用response.sendReadirect()方法,把要访问的目标资源作为response响应头信息发给客户端浏览器。
客户端浏览器重新访问服务器资源xxx.jsp,服务器再次对客户端浏览器做出响应。
重定向
以上两种情况,你都需要考虑Servlet处理完后,数据如何在jsp页面上呈现。图例是请求、响应的流程,没有标明数据如何处理、展现。
示例:
@SuppressWarnings("serial")
public class Servlet06 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet06...");
// 接收参数
String uname = req.getParameter("uname");
System.out.println("Servlet06 uname: " + uname);
// 获取域对象的值
System.out.println(req.getAttribute("num"));
}
四、转发和重定向的路径问题
1)使用相对路径在重定向和转发中没有区别
2)重定向和请求转发使用绝对路径时,根/路径代表了不同含义
重定向response.sendRedirect("xxx")是服务器向客户端发送一个请求头信息,由客户端再请求一次服务器。/指的Tomcat的根目录,写绝对路径应该写成"/当前Web程序根名称/资源名" 。如"/WebModule/login.jsp","/bbs/servlet/LoginServlet"
转发是在服务器内部进行的,写绝对路径/开头指的是当前的Web应用程序。绝对路径写法就是"/login.jsp"或"/servlet/LoginServlet"。
总结:以上要注意是区分是从服务器外的请求,还在是内部转发,从服务器外的请求,从Tomcat根写起(就是要包括当前Web的根);是服务器内部的转发,很简单了,因为在当前服务器内,/写起指的就是当前Web的根目录。
示例:
@SuppressWarnings("serial")
public class Servlet07 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet07...");
// 请求转发 req.getRequestDispatcher("index.html").forward(req, resp); //OK
req.getRequestDispatcher("/index.html").forward(req, resp); // OK
req.getRequestDispatcher("s03/index.html").forward(req, resp); // No HTTP Status 404 - /s03/s03/index.html req.getRequestDispatcher("/s03/index.html").forward(req, resp); // No HTTP Status 404 - /s03/s03/index.html
req.getRequestDispatcher("http://localhost:8080/s03/index.html").forward(req, resp); // No HTTP Status 404 - /s03/http://localhost:8080/s03/index.html
req.getRequestDispatcher("http://www.shsxt.com").forward(req, resp); // No HTTP Status 404 - /s03/http://www.shsxt.com
// 重定向
// resp.sendRedirect("index.html"); // OK
// resp.sendRedirect("/index.html"); // No http://localhost:8080/index.html
// resp.sendRedirect("s03/index.html"); // No HTTP Status 404 - /s03/s03/index.html
// resp.sendRedirect("/s03/index.html"); OK
// resp.sendRedirect("http://localhost:8080/s03/index.html");
resp.sendRedirect("http://www.shsxt.com");
}
}
五、转发和重定向的区别
request.getRequestDispatcher()是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;服务器内部转发,整个过程处于同一个请求当中。
response.sendRedirect()则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。不在同一个请求。重定向,实际上客户端会向服务器端发送两个请求。
所以转发中数据的存取可以用request作用域:request.setAttribute(), request.getAttribute(),重定向是取不到request中的数据的。只能用session。
forward()更加高效,在可以满足需要时,尽量使用RequestDispatcher.forward()方法。(思考一下为什么?)
RequestDispatcher是通过调用HttpServletRequest对象的getRequestDispatcher()方法得到的,是属于请求对象的方法。
sendRedirect()是HttpServletResponse对象的方法,即响应对象的方法,既然调用了响应对象的方法,那就表明整个请求过程已经结束了,服务器开始向客户端返回执行的结果。
重定向可以跨域访问,而转发是在web服务器内部进行的,不能跨域访问。
六. 请求转发和重定向两种跳转方式的区别
请求转发:request.getRequsetDispatcher().forward(requset,response);
重定向:response.sendRedirect(),
1)转发作用于服务器端,是在服务器内部进行转发。重定向作用于客户端,相当于客户端重新发送一次新的请求。
2)转发后地址栏不会改变。重定向后地址栏改变。
3)转发后资源能获取到请求中的数据。重定向后的资源不能获得原请求中的数据。
4)转发只能在本应用内部资源之间进行。重定向可以跳转到任何网络资源。
5)转发可以访问受保护资源(WEB-INF里的资源)。重定向不能定位到受保护资源。
request.getRequsetDispatcher().forward(requset,response);
请求转发
1、只有一次请求,request作用域中的数据可以共享
2、浏览器地址栏不发生改变
3、服务端行为
4、跳转的绝对地址可以定位到站点名后
只能请求转发到当前项目下的资源
重定向的区别
1、有两次请求,request作用域中的数据不可以共享
2、浏览器地址栏发生改变
3、客户端行为
4、跳转的绝对地址可以定位到http://后面
重定向可以定位到任意资源
请求转发和重定向不能同时使用
路径问题
相对路径
路径的前面不要加任何符号,一般情况下代表的是: "http://localhost:8080/站点名/"
绝对路径
1、以http://开头的,完整的绝对路径,可以跨域,可以访问任何资源
2、以"/"开头,只能访问当前项目下的资源
请求转发和重定向的"/"代表的含义:
1、请求转发(服务端跳转):http://localhost:8080/站点名/
2、重定向(客户端跳转):"http://localhost:8080/"
客户端跳转:
表单提交、超链接跳转、地址栏直接收入、重定向
服务端跳转:
请求转发
七. servlet四大域对象
pageContext
pageContext作用域为page(页面执行期)。
request
request是表示一个请求,只要发出一个请求就会创建一个request,它的作用域仅在当前请求中有效。
用处:常用语服务器间同一请求不同页面之间的参数传递,常用语表单的控件值传递。
方法:request.setAttribute(); reuqest.getAttribute();
request.removeAttribute(); request.getParameter();
session
服务器会为每一个会话创建一个Session对象,所以Session中的数据可供当前会话中所有Servlet共享。
用处:常用于web开发中的登录验证界面(当用户登陆成功后浏览器分配其中一个Session键值对)。
方法:session.setAttribute(); session.getAttribute();
session.removeAttribute();
获取Session对象:
HttpSession session = request.getSession();
Application(ServletContext上下文)
作用范围:所有的用户都可以取得此信息,此信息在整个服务器端被保留。Application属性范围值只要设置一次,则所有的网页窗口都可以取得数据。ServletContext在服务器启动时创建,在服务器关闭时销毁,一个JavaWeb应用只创建一个ServletContext对象。
方法:ServletContext application = this.getServletContext();
application.setAttribute(); application.getAttribute();
application.removeAttribute();
Servlet作用域
例如,我们访问index.jsp的时候,分别对pageContext、request、session、application四个作用域进行累加。 计算完成后就从index.jsp执行forward转发到test.jsp,在test.jsp里再进行一次累加,然后显示出这四个整数来。
从结果来看:
①page里的变量没法从index.jsp传递到test.jsp,只要页面跳转了,它们就不见了。
②request里的变量可以跨越forward前后两页。但是只要刷新页面,它们就重新计算了。
③session和application的变量一直在累加,开始还看不出区别,只要关闭浏览器,再次重启浏览器访问这个页面,session里的变量就重新计算了。application里的变量一直在累加,除非你重启Tomcat,否则它会一直变大。
作用域规定的是变量的有效期限
①如果把变量放到pageContext里,就说明它的作用域是page,它的有效范围只在当前JSP页面里。从把变量放到pageContext开始,知道JSP页面跳转都可以使用。
②如果把变量放到request里,就说明它的作用域是request,它的有效范围是当前请求周期。 所谓请求周期:就是从Http请求发起,到服务器处理结束,返回响应的整个过程。在这个过程中可能使用forward的方式跳转了多个JSP页面,在这些页面里,你都可以使用这个变量。
③如果把这个变量放到session里,就说明它的作用域是session,它的有效范围是当前会话。 所谓当前会话:就是指从用户打开浏览器开始,知道用户关闭浏览器这中间的过程,这个过程可能包含多个请求响应。 也就是说,只要用户不关闭浏览器,服务器就有办法知道这些请求是一个人发起的,整个过程被称为一个会话,而放到会话中的变量,就可以在当前会话的所有请求里使用。
④如果把变量放到application里,就说明它的作用域是application,它的有效范围是整个应用。 所谓整个应用:是指从应用启动到应用结束。application里的变量存活时间最长,如果不进行手动删除,它们就一直可以使用。