1
写在前面的话
这篇文章应该是Servlet篇的结尾篇了,在这篇文章中,我会讲到重定向并且给大家演示一个小栗子,还会讲到请求转发和重定向的区别、网页的自动刷新以及Servlet线程安全问题。废话不多说了,继续往下看吧!
2
重定向这个东东
首先当然是来自百度百科的解释:
重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向、域名的重定向、路由选择的变化也是对数据报文经由路径的一种重定向)。
也有另外一种解释:
重定向是根据服务器返回状态码来实现的。如果此时服务器返回了一个301或者302的状态码,那么浏览器就会到新的网址重新请求该资源。服务器的响应中会带着这个新资源的地址。
可能你现在还是不懂重定向是啥,我给你举个简单的例子,当我们在某个网站登录时,我们点击登录之后就会跳转到个人中心之类的页面,此时就是因为发生了重定向。
给大家简单的画了张图:
我们通过一个实际的代码案例来让大家体验一下:
<form action="test2" method="get">
用户名:<input name="username" type="text"> 密码:<input name="password" type="password"> <input type="submit" name="tijiao"> </form>
这是我们的表单,模拟登录界面。
@WebServlet(name = "TestServlet2",urlPatterns = "/test2")public class TestServlet2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = "JAP"; String password = "123456";
String username = request.getParameter("username"); String passWord = request.getParameter("password");
if (name.equals(username)&&password.equals(passWord)){ // HttpServletResponse.SC_MOVED_TEMPORARILY是302常量 response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); response.setHeader("Location","https://www.baidu.com"); } }}
上面是我们的Servlet代码,其实非常的简单,我们运行案例之后,如果登录成功,那么页面会跳转至百度。
3
请求转发和重定向的区别
区别:
①重定向可以跳转至任何的网址,转发只能在服务器内部进行,就好比上面我们重定向至百度。
②重定向的地址栏是会发生变化的而转发不会
③重定向是两次请求,两次响应,转发是一次请求一次响应。
④重定向路径需要加工程名而转发路径不需要。
这里也给大家两张图:
(请求重定向)
(请求转发)
4
网页的自动刷新和跳转
这里给大家的是一个小案例:
@WebServlet(name = "TestServlet3",urlPatterns = "/test3")public class TestServlet3 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //防止乱码 response.setContentType("text/html;charset=utf-8"); // 设置自动刷新和跳转 response.setHeader("refresh","3;url='index.jsp'"); response.getWriter().println("3秒后自动跳转!"); }}
这三句简单的代码就可以实现页面的自动刷新和跳转
5
Servlet线程安全
首先给大家一串代码,大家思考一下此时是否存在线程安全问题?
@WebServlet(name = "ThreadServlet",urlPatterns ="/thread")public class ThreadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int i =0; i++; }}
其实这里是没有线程安全问题的,为啥呢?因为doGet方法是由Service方法实现的,Service方法是一个多线程的方法,当多个客户端同时访问doGet方法时,它会为每个doGet方法创建一个int i的变量。
我们再来看看这串代码,我们将i变量变成成员变量,并且我们通过Thread的sleep方法模拟一个并发问题。
@WebServlet(name = "ThreadServlet",urlPatterns ="/thread")public class ThreadServlet extends HttpServlet { int i =0; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { i++; try { Thread.sleep(5*1000); } catch (InterruptedException e) { e.printStackTrace(); } response.setContentType("text/html;charset=utf-8"); response.getWriter().write(i+""); }}
我们来看一下两个浏览器同时访问它会是一个怎样的结果:
可以看到,我们两个浏览器同时去访问它时,两个显示的都是2,这说明了当第一个线程运行i++并且睡眠5秒时,另一个线程此时访问进来了并且执行了i++,所以此时i变成了2,当休眠期过了,就在浏览器上显示了2.
咱们来总结一下:
当多个客户端并发访问同一个Servlet的时候,web服务器会为每一个客户端的访问创建一个线程,并且在这个线程上调用service方法,因此service方法内部如果访问同一个共享资源时,就可能引发线程安全问题
既然问题出来了,怎么去解决它呢?
1.同步代码块:
@WebServlet(name = "ThreadServlet",urlPatterns ="/thread")public class ThreadServlet extends HttpServlet { int i =0; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { synchronized (this){ i++; try { Thread.sleep(5*1000); } catch (InterruptedException e) { e.printStackTrace(); } response.setContentType("text/html;charset=utf-8"); response.getWriter().write(i+""); } }}
通过加synchronized同步代码块,可以解决多线程安全问题,结果我就不展示了。其实这种方法也会给我们带来一些问题,例如,我们加了同步代码块后,我们第二次线程访问时需要等待第一个线程结束才能够进去访问,如果一个网站1000人去访问,那需要等很久很久,所以这给用户带来的体验也是不好的。
总结:为了减少这种线程安全问题的发生,唯一一种有效的方法就是少去使用一些共享的资源,最好都是一些局部资源,这样就可以去保证Servlet的线程安全问题。
End