URL重写
URL重写
是一种会话跟踪技术,它将一个或多个键值对
添加到URL
的查询字符串中,每个键值对
通常为 key=value
形式,格式如下所示:
1
| url?key_1=value_1&key_2=value_2...&key_n=value_n
|
注意,URL
和键值对
之间用问号?
来分割,键值对
之间用单与符号&
分割。
URL
重写适合于在少数URL
之间传递信息
的情况下,它有如下限制:
URL
在某些浏览器上最大长度为2000字符,所以URL
重写可能无法传递大量数据。
- 如果要传递
信息
到下一个资源,需要将信息
插入到URL
的查询字符串中,这种情况适用于动态页面之间传值,而不适用于静态页面之间传值;
URL
重写需要在服务端上完成,所有的链接都必须带值,因此当一个页面存在很多链接时,其处理过程会是一个不小的挑战;
- 对应信息中的某些字符,例如
空格
、单与符号&
和问号?
等必须用base64
编码,而编码和解码会增加开销;
URL
的内容会显示在浏览器的地址栏上,所以URL
重写不适合用来传递敏感信息。
所以,**URL
重写仅适合于在少量页面间
传递不敏感信息
的情况。**
下面来写个Demo,实用URL重写在同一个页面中传递信息。
Demo
项目目录
穿件一个名为SessionManagement
的动态Java Web项目,然后创建项目结果如下所示:
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
| package session.management; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet( name = "RewriteURL", // 为一个servlet匹配多个URL urlPatterns ={"/test"} ) public class RewriteURL extends HttpServlet { private static final long serialVersionUID = 1L; private ArrayList<String> fruits = null; private ArrayList<String> vegetables = null; @Override public void init() throws ServletException { fruits = new ArrayList<String>(5); fruits.add("苹果"); fruits.add("香蕉"); fruits.add("草莓"); fruits.add("西瓜"); fruits.add("龙眼"); vegetables = new ArrayList<String>(5); vegetables.add("白菜"); vegetables.add("紫菜"); vegetables.add("菠菜"); vegetables.add("南瓜"); vegetables.add("冬瓜"); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String choice = request.getParameter("choice"); if (choice == null) { showIndex(response); } else if ("fruits".equals(choice)) { showFruits(response); } else if ("vegetables".equals(choice)) { showVegetables(response); } } private void showIndex(HttpServletResponse response) { response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter writer; try { writer = response.getWriter(); String htmlResponse = "<html>\r\n" + " <head>\r\n"+ " <meta charset=\"utf-8\">\r\n"+ " <title>测试URL重写</title>\r\n"+ " </head>\r\n"+ " <body>\r\n"+ " <hr>\r\n" + " <br><br>"+ " <hr>\r\n"+ " <a href=\"?choice=fruits\">显示水果</a> \r\n"+ " <a href=\"?choice=vegetables\">显示蔬菜</a>\r\n"+ " </body>\r\n" + "</html>"; writer.write(htmlResponse); } catch (IOException e) { e.printStackTrace(); } } private void showFruits(HttpServletResponse response) { response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter writer; try { writer = response.getWriter(); String ul = ""; for (String string : fruits) { ul += "<li>" + string + "</li>"; } String responseHTML = "<html>\r\n" + " <head>\r\n"+ " <meta charset=\"utf-8\">\r\n"+ " <title>测试URL重写</title>\r\n" + " </head>\r\n"+ " <body>\r\n" + " <a href=\"test\">返回首页</a>"+ " <hr>\r\n" + ul + " <hr>\r\n"+ " <a href=\"?choice=fruits\">显示水果</a> \r\n"+ " <a href=\"?choice=vegetables\">显示蔬菜</a>\r\n"+ " </body>\r\n" + "</html>"; writer.write(responseHTML); } catch (IOException e) { e.printStackTrace(); } } private void showVegetables(HttpServletResponse response) { response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter writer; try { writer = response.getWriter(); String ul = ""; for (String string : vegetables) { ul += "<li>" + string + "</li>"; } String responseHTML = "<html>\r\n" + " <head>\r\n"+ " <meta charset=\"utf-8\">\r\n"+ " <title>测试URL重写</title>\r\n" + " </head>\r\n"+ " <body>\r\n" + " <a href=\"test\">返回首页</a>"+ " <hr>\r\n" + ul + " <hr>\r\n"+ " <a href=\"?choice=fruits\">显示水果</a> \r\n"+ " <a href=\"?choice=vegetables\">显示蔬菜</a>\r\n"+ " </body>\r\n" + "</html>"; writer.write(responseHTML); } catch (IOException e) { e.printStackTrace(); } } }
|
代码详解
URL映射
Servlet中的URL映射的注解如下所示:
1 2 3 4 5 6
| @WebServlet( name = "RewriteURL", // 为一个servlet匹配多个URL urlPatterns ={"/test"} )
|
name
表示当前session.management.RewriteURL
这个Servlet
的部署名。
urlPatterns
表示该Servlet
的URL
地址,这个是个数字形式,同一个Servlet
可以设置不同的URL
地址.
映射好URL后,后面就可以通过http://localhost:8080/项目名称/test
这样的格式来访问这个Servlet,这里是:
http://localhost:8080/SessionManagement/test
初始化数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| private ArrayList<String> fruits = null; private ArrayList<String> vegetables = null;
@Override public void init() throws ServletException { fruits = new ArrayList<String>(5); fruits.add("苹果"); fruits.add("香蕉"); fruits.add("草莓"); fruits.add("西瓜"); fruits.add("龙眼"); vegetables = new ArrayList<String>(5); vegetables.add("白菜"); vegetables.add("紫菜"); vegetables.add("菠菜"); vegetables.add("南瓜"); vegetables.add("冬瓜"); }
|
在这个Servlet中有两个成员变量fruits
和vegetables
用于存放要展示的数据。
当用户第一次通过URL
访问到该Servelet
时,Web
容器(Tomcat)会调用init()
方法来初始化数据。在这里,init()方法用来初始化成员变量的数据。
响应get请求 覆盖doGet方法
当直接通过http://localhost:8080/SessionManagement/test这个URL访问的时候,Tomcat会调用init()方法来初始化,初始化只进行一次.后面不再调用init()方法.然后调用doGet()方法来响应请求。doGet方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String choice = request.getParameter("choice"); if (choice == null) { showIndex(response); } else if ("fruits".equals(choice)) { showFruits(response); } else if ("vegetables".equals(choice)) { showVegetables(response); } }
|
doGet方法会获取请求中名称为choice
的参数值。然后根据参数值的不同来调用不同的方法进行响应。
当我们请求http://localhost:8080/SessionManagement/test对应的Servlet时,URL中没有带查询字符串,所以不存在choice这个参数。request.getParameter("choice");
返回null.这样就会调用showIndex(response);
这个方法来响应。
返回初始界面
showIndex()方法如下,所谓的响应,就是往响应对象里写一些字符串。Web容器会把响应对象中的这些字符串处理一下然后发送给浏览器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| private void showIndex(HttpServletResponse response) { response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter writer; try { writer = response.getWriter(); String htmlResponse = "<html>\r\n" + " <head>\r\n"+ " <meta charset=\"utf-8\">\r\n"+ " <title>测试URL重写</title>\r\n" + " </head>\r\n"+ " <body>\r\n"+ " <hr>\r\n" + " <br><br>"+ " <hr>\r\n"+ " <a href=\"?choice=fruits\">显示水果</a> \r\n"+ " <a href=\"?choice=vegetables\">显示蔬菜</a>\r\n"+ " </body>\r\n" + "</html>"; writer.write(htmlResponse); } catch (IOException e) { e.printStackTrace(); } }
|
此时浏览器显示如下:
这个页面有两个超链接,如下所示:
1 2
| <a href="?choice=fruits">显示水果</a> <a href="?choice=vegetables">显示蔬菜</a>
|
响应重写的URL
在刚才的页面中,显示水果
的URL为?choice=fruits
这是个查询字符串,查询字符串中有一个名为choice
的参数,参数值为fruits
。
如果点击这超链接,浏览器会再次发送一个HTTP请求给服务器。
这里URL中地址缺省,浏览器会默认发给当前的地址。也就是在http://localhost:8080/SessionManagement/test
这个地址后面加上查询字符串,得到的URL为:http://localhost:8080/SessionManagement/test?choice=fruits
,这相当于重写了URL
.
虽然,这个时候请求的Servlet还是http://localhost:8080/SessionManagement/test
这个URL对应的Servlet.但是这回跟第一次请求时的情况是不一样的,第一次没有带请求参数,这次带了请求参数。Tomcat还是会调用doGet来生成响应。
不过这次因为带了参数choice=fruits
,doGet方法会调用showFruits
方法来生成响应。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| private void showFruits(HttpServletResponse response) { response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter writer; try { writer = response.getWriter(); String ul = ""; for (String string : fruits) { ul += "<li>" + string + "</li>"; } String responseHTML = "<html>\r\n" + " <head>\r\n"+ " <meta charset=\"utf-8\">\r\n"+ " <title>测试URL重写</title>\r\n" + " </head>\r\n"+ " <body>\r\n" + " <hr>\r\n" + ul + " <hr>\r\n"+ " <a href=\"?choice=fruits\">显示水果</a> \r\n"+ " <a href=\"?choice=vegetables\">显示蔬菜</a>\r\n"+ " </body>\r\n" + "</html>"; writer.write(responseHTML); } catch (IOException e) { e.printStackTrace(); } }
|
这个方法会把水果列表中的数据输出。如下所示:
同理如果此时点击显示蔬菜
链接我们就可以显示蔬菜。