1. 转向(Forward)
转向(forward)是通过RequestDispatcher对象的forward(HttpServletRequest request, HttpServletResponse response)来实现的。示例如下:
RequestDispatcher dispatcher = request.getRequestDispatcher( "/servlet/LifeCycleServlet" ); dispatcher.forward(request, response); |
getRequestDispatcher()方法的参数必须以“/”开始,“/”表示本Web应用程序的根目录。如上例中,
表示要跳转的地址为http://localhost:8080/servlet/servlet/LifeCycleServlet。
forward是最常用的方式,在Structs等MVC框架中,都是用Servlet来处理用户请求,把结果通过request.setAttribute()放到request中,
然后forward到JSP中显示。
当执行forward方法时,不能有任何输出到达客户端,否则会抛出异常,也就是说,在forward之前,不要使用out.println()语句向客户端输出。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String destination = request.getParameter( "destination" ); if ( "file" .equals(destination)){ RequestDispatcher d = request.getRequestDispatcher( "/WEB-INF/web.xml" ); d.forward(request, response); } else if ( "jsp" .equals(destination)){ request.setAttribute( "date" , new Date()); //attributes are reset between requests. RequestDispatcher dispatcher = request.getRequestDispatcher( "/forward.jsp" ); dispatcher.forward(request, response); } else if ( "servlet" .equals(destination)){ RequestDispatcher disp = request.getRequestDispatcher( "/servlet/LifeCycleServlet" ); disp.forward(request, response); } else { response.setCharacterEncoding( "UTF-8" ); response.getWriter().println( "缺少参数。用法:" +request.getRequestURI()+ "?destination=jsp或者file或者servlet" ); } } |
2. 重定向(Redirect)
重定向是通过服务器端返回状态码来实现的。301,302都表示重定向,区别是301表示永久性重定向,302表示临时性重定向。通过sendRedirect(String location)就可以实现重定向,下面是例子。本例子主要实现了Servlet来实现文件下载并统计下载次数。要下载的文件以及下载次数都保存在一个Map中。主要思路是:首先加载页面表单,当用户点击下载链接时,客户端发起请求,运行doGet里的if判断,实现重定向。
重定向和跳转的区别:跳转是在服务器端实现的,客户端浏览器并不知道该浏览动作,而使用Redict跳转时,跳转是在客户端实现的,也就是说客户端浏览器实际上请求了2次服务器。
public class RedictServlet extends HttpServlet { Map<String,Integer> map = new HashMap<String,Integer>(); //new一个Map public void init() throws ServletException { //放在init中,加载servlet时运行此方法,把文件内容放到map中去 map.put( "/download/setup.exe" , 0 ); map.put( "/download/application.zip" , 0 ); map.put( "/download/01.mp3" , 0 ); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filename = request.getParameter( "filename" ); if (filename!= null ){ int hit = map.get(filename); //取下载次数 map.put(filename, ++hit); //下载次数加1后保存 response.sendRedirect(request.getContextPath()+filename); //重定向到文件 } else { response.setCharacterEncoding( "UTF-8" ); PrintWriter out = response.getWriter(); response.setContentType( "text/html" ); out.println( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">" ); out.println( "<HTML>" ); out.println( " <HEAD><TITLE>文件下载</TITLE></HEAD>" ); out.println( " <link rel='stylesheet' type='text/css' href='../css/style.css'>" ); out.println( " <BODY><br/>" ); out.println( "<fieldset align=center style=width:90%><legend>文件下载</legend>" ); //绘制页面表单 out.println( "<table width=100%>" ); out.println( " <tr>" ); out.println( " <td><b>文件名" + "</b></td>" ); out.println( " <td><b>下载次数</b></td>" ); out.println( " <td><b>下载</b></td>" ); out.println( " </tr>" ); for (Entry<String,Integer> entry: map.entrySet()){ //遍历map的方法 out.println( "<tr>" ); out.println( " <td>" +entry.getKey()+ "</td>" ); out.println( " <td>" +entry.getValue()+ "</td>" ); out.println( " <td><a href = '" +request.getRequestURI()+ "?filename=" +entry.getKey()+ "'target = '_blank' onclick ='location = location;'>下载</a></td>" ); //target='_blank'目标地址在无标题的新页面中打开。onclick ='location = location;'页面刷新 out.println( "</tr>" ); } out.println( "</table>" ); out.println( " </legend>" ); out.println( " </BODY>" ); out.println( "</HTML>" ); out.flush(); out.close(); } } public void destroy() { super .destroy(); // Just puts "destroy" string in log // Put your code here map = null ; } } |
结果图:
点击下载chrome浏览器就会自动下载