前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaWeb| 深入Servlet技术(三)

JavaWeb| 深入Servlet技术(三)

作者头像
Python进击者
发布2019-06-21 20:56:14
4950
发布2019-06-21 20:56:14
举报
文章被收录于专栏:JAVAandPython君

1

写在前面的话

这篇文章应该是Servlet篇的结尾篇了,在这篇文章中,我会讲到重定向并且给大家演示一个小栗子,还会讲到请求转发和重定向的区别、网页的自动刷新以及Servlet线程安全问题。废话不多说了,继续往下看吧!

2

重定向这个东东

首先当然是来自百度百科的解释:

重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向、域名的重定向、路由选择的变化也是对数据报文经由路径的一种重定向)。

也有另外一种解释:

重定向是根据服务器返回状态码来实现的。如果此时服务器返回了一个301或者302的状态码,那么浏览器就会到新的网址重新请求该资源。服务器的响应中会带着这个新资源的地址。

可能你现在还是不懂重定向是啥,我给你举个简单的例子,当我们在某个网站登录时,我们点击登录之后就会跳转到个人中心之类的页面,此时就是因为发生了重定向。

给大家简单的画了张图:

我们通过一个实际的代码案例来让大家体验一下:

代码语言:javascript
复制
  <form action="test2" method="get">
  用户名:<input name="username" type="text">    密码:<input name="password" type="password">    <input type="submit" name="tijiao">  </form>

这是我们的表单,模拟登录界面。

代码语言:javascript
复制
@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

网页的自动刷新和跳转

这里给大家的是一个小案例:

代码语言:javascript
复制
@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线程安全

首先给大家一串代码,大家思考一下此时是否存在线程安全问题?

代码语言:javascript
复制
@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方法模拟一个并发问题。

代码语言:javascript
复制
@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.同步代码块:

代码语言:javascript
复制
@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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python进击者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档