专栏首页JAVAandPython君JavaWeb| 深入Servlet技术(三)

JavaWeb| 深入Servlet技术(三)

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

本文分享自微信公众号 - JAVAandPython君(JAVAandPythonJun)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ABAP文档生成工具

    版权声明:本文为博主汪子熙原创文章,未经博主允许不得转载。 https://jerry.bl...

    Jerry Wang
  • 重拾Kotlin(11)-集合

    Kotlin 的集合设计和 Java 不同的另一项特性是:Kotlin 把访问数据的接口和修改集合数据的接口分开了,kotlin.collections.Col...

    叶应是叶
  • 一些使用javap反编译出来的结果分析

    版权声明:本文为博主汪子熙原创文章,未经博主允许不得转载。 https://jerry.bl...

    Jerry Wang
  • Java Swagger的注释类是怎么被调用到的

    版权声明:本文为博主汪子熙原创文章,未经博主允许不得转载。 https://jerry.bl...

    Jerry Wang
  • 从另一个角度理解java并发

    掌握了Sequential Consistency一致性模型之后,我们重新审视一下java的并发。

    大神带我来搬砖
  • 关于SAP UI5 CRM Reuse Fiori应用的代码审查

    If we open the target folder: What is exactly the usage of these four parts?

    Jerry Wang
  • 一文快速了解Java集合框架

    JDK1.2 引入了 Java 集合框架,包含一组数据结构。与数组不同,这些数据结构的存储空间会随着元素添加动态增加。其中,一些支持添加重复元素另一些不支持,一...

    乱敲代码
  • 代码重构那些事儿

    大家好,这是我今天演讲的目录,分Java,JavaScript,ABAP三门编程语言来讲述。

    Jerry Wang
  • 【干货】你还分不清Java监听器与过滤器吗?

    它是一种Servlet中特殊的类,能监听某个对象的状态变化的组件,主要是监听域对象的变化。

    老九君
  • 震惊!几道Python 理论面试题,Python面试题No18

    解释型语言编写的程序不需要编译,在执行的时候,专门有一个解释器能够将VB语言翻译成机器语言,每个语句都是执行的时候才翻译。这样解释型语言每执行一次就要翻译一次,...

    梦想橡皮擦

扫码关注云+社区

领取腾讯云代金券