Javaee——Servlet学习总结

参考原文地址

Servlet 的请求流程

  1. 浏览器发出请求:http://localhost:80/xxx1/xxx2 (80端口可以默认不写,因为这是http协议默认的端口,平时我们访问https://www.baidu.com/ 时其实访问的是https://www.baidu.com:80/

  2. 服务器解析请求信息:

    • http:协议名称
    • localhost:访问的是互联网中的哪一台计算机
    • 80:从主机当中找到对应 80 端口的程序 这里即为 Tomcat 服务器
    • /xxx1:当前项目的上下文路径 (即在 server.xml 中配置主机时配置的 path属性
    • /xxx2:当前请求的资源名
  3. 解析 Tomcat 服务器根目录下的 /config/server.xml 文件:
    <Context docBase="D:\javaPros\test\webapp" path="xxx1" />
    判断哪一个<Context />元素的 path属性 属性为 xxx1

    • 若找不到,则返回 404错误
    • 若找到了,则解析该<Context />元素,得到docBase属性,获取当前访问 Web 项目的跟的绝对路径:D:\javaPros\test\webapp
  4. D:\javaPros\test\webapp下的 WEB-INF 下找到 web.xml 文件
    判断 web.xml 文件中是否有 <url-pattern> 的文本内容为 /xxx2

    • 若找不到,则返回 404错误
    • 若找到了,则继续获取该资源对应 Servlet 类的全限名称: xxx.xxx
  5. 判断 Servlet 实例缓存池 中是否有 xxx.xxx 的对象

Map<String,Servlet> cache = ......(Tomcat提供的);
    key:存Servlet类的全限定名称
    value:该Servlet类的对象.
Servlet obj = cache.get("xxx.xxx");
    if(obj==null){
        //Servlet实例缓存中没有该类的对象,第一次.
        GOTO 6:
    }else{
        //有对象,非第一次.
        GOTO 8:
    }
}

  1. 使用反射调用构造器,创建对应的对象
    obj = Class.forName("xxx.xxx").newInstance();
    把当前创建的 Servlet 对象,存放在缓存之中,供给下一次的使用.
    cache.put("xxx.xxx",obj);

  2. 创建 ServletConfig 对象,并调用 init() 方法
    obj.init(config);

  3. 创建 ServletRequest 对象和 ServletResponse 对象,并调用 service()方法
    obj.service(req,resp);

  4. service() 方法中对浏览器作出响应操作。


Servlet 生命周期

在 Web 容器中,Servlet 主要经历 4 个阶段,如下图:

image.png
  1. 加载 Servlet:当 Tomcat 第一次访问 Servlet 的时候,Tomcat 会负责创建 Servlet 的实例。
  2. 初始化 Servlet:当 Servlet 被实例化之后,Tomcat 会调用 init() 方法来初始化这个对象。
  3. 处理服务:当浏览器访问 Servlet 的时候,Servlet 会调用 service() 方法处理请求。
  4. 销毁:Tomcat 关闭或者检测到 Servlet 要从 Tomcat 删除的时候,会自动调用 destroy() 方法,让该实例所占用的资源释放掉。一个 Servlet 如果长时间不被使用的话,也会被 Tomcat 自动销毁。
  • 简单总结:只要访问 Servlet ,就会调用其对应的 service() 方法,init() 方法只会在第一次访问 Serlvet 的时候才会被调用。

这一部分参考文章:这里是链接


Servlet 提供处理请求的方法

前面的文章里面提到过,广义上,Servlet 即实现了 Servlet 接口 的类,当我们创建一个自定义类,实现 Servlet 接口 的时候,会发现有 5 个方法需要重写,有init【初始化】,destroy【销毁】,service【服务】,ServletConfig【Servlet配置】,getServletInfo【Serlvet信息】。

这样做的话,我们每次都需要实现 5 个方法,太麻烦了!

我们可以直接继承 HttpServlet 类,该类已经默认实现了 Servlet 接口中的所有方法,在编写 Servlet 的时候,你只需要重写你需要的方法就好了,并且该类还在原有 Servlet 接口上添加了一些与 HTTP 协议处理相关的方法,比 Servlet 接口的功能更强大。

  • Servlet 处理请求的方法一共有三种:
    ① 实现 service() 方法。
    ② 重写 doGet()doPost() 方法,并在 doGet() 中添加一句this.doPost(req, resp);(因为无论是get或post请求提交的数据,处理方式都基本相同,下同)
    ③ 重写 doGet()doPost() 方法,并在 doPost() 中添加一句this.doGet()(req, resp);
  • 推荐方式①。

Servlet 是单例的

为什么Servlet是单例的

浏览器多次对Servlet的请求,一般情况下,服务器只创建一个Servlet对象,也就是说,Servlet对象一旦创建了,就会驻留在内存中,为后续的请求做服务,直到服务器关闭。

每次访问请求对象和响应对象都是新的

对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。

线程安全问题

当多个用户访问Servlet的时候,服务器会为每个用户创建一个线程。当多个用户并发访问Servlet共享资源的时候就会出现线程安全问题。

原则:
1. 如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制synchronized (对象){}
2. 如果一个变量不需要共享,直接在 doGet() 或者 doPost()定义.这样不会存在线程安全问题

这一部分参考文章:这里是链接


HttpServletRequest 和 HttpServletResponse 对象

对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,即 request 和 response 对象。

既然 request 对象代表 http 请求,那么我们获取浏览器提交过来的数据,就找 request 对象 即可。response 对象代表 http 响应,那么我们向浏览器输出数据,找 response 对象即可。

HttpServletRequest 常用方法

  • String getContextPath():
    获取上下文路径,<Context path="上下文" ../>
  • String getHeader(String headName):
    根据指定的请求头获取对应的请求头的值.
  • String getRequestURI():
    返回当期请求的资源名称. 上下文路径/资源名
  • StringBuffer getRequestURL():
    返回浏览器地址栏的内容
  • String getRemoteAddr():
    返回请求服务器的客户端的IP

获取请求参数的方法:

  • String getParameter(String name):
    根据参数名称,获取对应参数的值.
  • String[] getParameterValues(String name):
    根据参数名称,获取该参数的多个值.
  • Enumeration<String> getParameterNames():
    获取所有请求参数的名字
  • Map<String,String[]> getParameterMap():
    返回请求参数组成的Map集合.
    key:参数名称
    value:参数值,封装在String数组中.

HttpServletResponse 常用方法

  • OutputStream getOutputStream():
    获取字节输出流:文件下载
  • Writer getWriter():
    获取字符输出流:输出内容
    设置文件输出的编码格式和内容类型:resp.setContentType("text/html;charset=utf-8");

GET 和 POST 的区别

要知道,GET 和 POST 都是请求方式

  • GET:
    浏览器器地址栏:http://localhost/test.html?name=wmyskxz&sex=male
    这里提交了两个参数,一个是name属性值为wmyskxz,另一个是sex属性值为male,这是一种直接的请求方式,在请求资源后面跟上 ? 符号与参数连接,其他的参数使用 & 符号连接。

  • 缺点:
    1.暴露请求信息,不安全
    2.请求信息不能超过1kb,可传输的信息有限,不能上传图片

  • POST:
    浏览器地址栏:http://localhost/test.html#

  • 优点:
    1.隐藏了请求信息,较安全(但仍可以通过相关工具访问到数据)
    2.POST 方式没有限制请求的数据大小,可以做图片的上传

但并不是所有的数据都需要使用 POST 请求来完成,事实上,GET 请求方式会比 POST 请求更快,当数据小并且安全性要求不是那么高的时候,GET 仍然是很好的选择.(并且 GET 相较 POST 简单)


请求中文乱码的处理

Tomcat 服务器中,接受请求的时候,默认的编码方式为 ISO-8859-1,而该编码方式只占一个字节,不支持中文(两个字节),所以当我们做请求的时候,会出现乱码的问题

  • 解决方案:
    1.对乱码使用 ISO-8859-1 解码,转换成byte数组,恢复为二进制
    byte[] data = name.getBytes("ISO-8859-1");
    2.对byte数组重新进行 UTF-8 编码:
    name = new String(data,"UTF-8");
    但是这样会出现一个问题,那就是当表单数据太多的时候,这样反复解码-编码,会很繁琐。
  • 终极解决方案:
    1.对于 POST 请求:
    设置请求的编码方式:request.setCharacterEncoding("UTF-8");
    注意:必须在获取第一个参数之前设置,并且该方式只对 POST 方式有效。
    2.对于 GET 请求:
    重新设置 Tomcat 的编码方式,修改 Tomcat 的配置文件:
    Tomcat根目录/conf/server.xml(修改端口的那一行)
image.png

Servlet 细节

  • 1.一个 Servlet 可以有多个 <url-pattern> ,可以使用多个资源名称找到当前的 Servlet
  • 2.配置 Servlet 可以使用通配符
    *表示任意字符
    /*:可以使用
    任意的字符*访问当前的 Servlet
    *.xxx:如 wmyskxz.wudi
  • 3.自定义的 Servlet 的 <servlet-name> 不能够为 default ,使用它会造成项目下面的静态资源找不到,在 Tomcat/conf/web.xml 文件中配置一个名字为default的Servlet,该Servlet在负责访问项目下的静态资源
image.png
  • 4.关于 Servlet 的初始化操作,如果初始化操作非常的耗时,那么第一个请求的用户的用户体验就非常差
    解决思路:将初始化操作向前移,在服务器启动的时候执行 Servlet 的初始化

    [图片上传失败...(image-8224bf-1533369380227)]


通过注解配置 Servlet

这是 Servlet 3.0 提出的新特性,支持注解配置,这大大简化了我们的工作。

在之前的开发工作中,我们总是去 web.xml 文件中进行配置,至少会出现8行:

[图片上传失败...(image-8c6662-1533369380228)]

而当一个项目中存在很多 Servlet ,那么配置文件就会变得非常臃肿,不便于后期的维护,在 Servlet 3.0 推出之后,我们可以使用注解来配置 Servlet,上面 8 行的配置可以简化为下面的简单的注解:

[图片上传失败...(image-5545f-1533369380228)]

或者也可以使用属性 value 定义访问的 URL,只有 URL 这个属性是必要的,name 是可以缺省的值,而默认的 value 也可以省略不写,所以可以简写成:

@WebServlet("/foreServlet")


Web 组件之间的跳转方式

1.请求转发(forward)

又叫做直接转发方式,客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的。

比如:从 AServlet 请求转发到 BServlet


image.png
  • 语法:
request.getRequestDispatcher(path).forward(request, response);

参数:path,要跳转到的资源路径:上下文路径 / 资源路径

  • 特点:
    1.地址栏中的地址【不会】改变
    通常看作是服务端的跳转
    2.只有一个请求
    3.资源是共享的,也就是说在两个 Servlet 中可以共享请求的资源
    可以通过request.setAttribute(String var1,Object var2)设置要共享的数据资源,并通过request.getAttribute(String var1);获取传递的资源
    4.【可以】访问 WEB-INF 中的资源
    WEB-INF 文件夹是 Java Web 应用的默认安全目录,即客户端无法直接访问,只有服务端可以访问的目录。
    如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问。
    注意:在实际的开发中,可以把不希望用户直接访问到(通过浏览器输入地址栏)的网页放在文件夹中通过此方式访问。
    5.请求转发【不能】跨域访问
    所谓的同域,是指域名,协议,端口均相同

2.URl 重定向(redirect)

又叫做间接转发方式(Redirect)实际是两次HTTP请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。

比如:从AServlet重定向到BServlet


image.png
  • 语法:
response.sendRedirect(String location);

参数:location,转发到的资源路径

  • 特点:
    1.地址栏中的地址【会】发生改变
    通常看作是客户端跳转
    2.有两个请求
    3.在两个 Servlet 中不可以共享请求中的数据
    4.最终的响应由 BServlet 来决定,和 AServlet 没有关系
    5.【不可以】访问 WEB-INF 中的资源
    6.请求转发【能】跨域访问
    就像是在网页中点开了新的链接一样
  • 总结:URL 重定向相当于是将重定向的资源路径,重新复制到浏览器地址栏中按下回车一样,重新发送一次新的请求。

3.请求包含(include)


MVC 模式

MVC 是一种分层的设计模式 。

  • M 代表 模型(Model)
    模型是什么呢? 模型就是数据,就是dao,bean
  • V 代表 视图(View)
    视图是什么呢? 就是网页, JSP,用来展示模型中的数据
  • C 代表 控制器(controller)
    控制器是什么? 控制器的作用就是把不同的数据(Model),显示在不同的视图(View)上。

这部分可以参考一下这里

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,300评论 1 92
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,169评论 11 349
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 我在知乎上经常被人问到财务人的职业发展,这里就把我的经验和想法总结一下,算是抛砖引玉了。 我的职业路径 本人大学毕...
    微水滴石每一天阅读 7,330评论 6 8
  • 一树响亮的雪白 在春风里抖落着神采 于是云光黯淡 宛若尘埃 水在暗涌处澎湃 淹没时间的慷慨 薄雾滚入涟漪后 没了姿...
    宋予屿阅读 337评论 2 8