初学Java Web(4)——Servlet学习总结
经过一段时间的学习,对于Servlet有了新的不一样的见解,在这里做一下总结,将近来学习到的知识总结一下。
Servlet 的请求流程
浏览器发出请求:http://localhost:80/xxx1/xxx2 (80端口可以默认不写,因为这是http协议默认的端口,平时我们访问https://www.baidu.com/ 时其实访问的是https://www.baidu.com:80/)
服务器解析请求信息:
- http:协议名称
- localhost:访问的是互联网中的哪一台计算机
- 80:从主机当中找到对应 80 端口的程序 (这里即为 Tomcat 服务器)
- /xxx1:当前项目的上下文路径 (即在 server.xml 中配置主机时配置的 path属性)
- /xxx2:当前请求的资源名
解析 Tomcat 服务器根目录下的 /config/server.xml 文件:
<Context docBase="D:\javaPros\test\webapp" path="xxx1" />
判断哪一个<Context />
元素的 path属性 属性为xxx1
- 若找不到,则返回 404错误
- 若找到了,则解析该
<Context />
元素,得到docBase
属性,获取当前访问 Web 项目的跟的绝对路径:D:\javaPros\test\webapp
从
D:\javaPros\test\webapp
下的 WEB-INF 下找到 web.xml 文件
判断 web.xml 文件中是否有<url-pattern>
的文本内容为 /xxx2- 若找不到,则返回 404错误
- 若找到了,则继续获取该资源对应 Servlet 类的全限名称: xxx.xxx
判断 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:
}
}
使用反射调用构造器,创建对应的对象
obj = Class.forName("xxx.xxx").newInstance();
把当前创建的 Servlet 对象,存放在缓存之中,供给下一次的使用.
cache.put("xxx.xxx",obj);
创建 ServletConfig 对象,并调用 init() 方法
obj.init(config);
创建 ServletRequest 对象和 ServletResponse 对象,并调用 service()方法
obj.service(req,resp);
在 service() 方法中对浏览器作出响应操作。
Servlet 生命周期
在 Web 容器中,Servlet 主要经历 4 个阶段,如下图:
- 加载 Servlet:当 Tomcat 第一次访问 Servlet 的时候,Tomcat 会负责创建 Servlet 的实例。
- 初始化 Servlet:当 Servlet 被实例化之后,Tomcat 会调用 init() 方法来初始化这个对象。
- 处理服务:当浏览器访问 Servlet 的时候,Servlet 会调用 service() 方法处理请求。
- 销毁:当 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 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(修改端口的那一行)
Servlet 细节
- 1.一个 Servlet 可以有多个
<url-pattern>
,可以使用多个资源名称找到当前的 Servlet - 2.配置 Servlet 可以使用通配符(*)
*
表示任意字符
/*
:可以使用任意的字符访问当前的 Servlet
*.xxx
:如 wmyskxz.wudi - 3.自定义的 Servlet 的
<servlet-name>
不能够为 default ,使用它会造成项目下面的静态资源找不到,在Tomcat/conf/web.xml
文件中配置一个名字为default的Servlet,该Servlet在负责访问项目下的静态资源
- 4.关于 Servlet 的初始化操作,如果初始化操作非常的耗时,那么第一个请求的用户的用户体验就非常差
解决思路:将初始化操作向前移,在服务器启动的时候执行 Servlet 的初始化
通过注解配置 Servlet
这是 Servlet 3.0 提出的新特性,支持注解配置,这大大简化了我们的工作。
在之前的开发工作中,我们总是去 web.xml
文件中进行配置,至少会出现8行:
而当一个项目中存在很多 Servlet ,那么配置文件就会变得非常臃肿,不便于后期的维护,在 Servlet 3.0 推出之后,我们可以使用注解来配置 Servlet,上面 8 行的配置可以简化为下面的简单的注解:
或者也可以使用属性 value
定义访问的 URL,只有 URL 这个属性是必要的,name
是可以缺省的值,而默认的 value
也可以省略不写,所以可以简写成:
@WebServlet("/foreServlet")
Web 组件之间的跳转方式
1.请求转发(forward)
又叫做直接转发方式,客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的。
比如:从 AServlet 请求转发到 BServlet
- 语法:
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
- 语法:
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)上。
这部分可以参考一下这里
欢迎转载,转载请注明出处!
简书ID:@我没有三颗心脏
github:wmyskxz
欢迎关注公众微信号:wmyskxz_javaweb
分享自己的Java Web学习之路以及各种Java学习资料
初学Java Web(4)——Servlet学习总结的更多相关文章
- 初学Java Web(6)——JSP学习总结
为什么要学习 JSP Servlet 的短板: Servlet 的出现,是为了解决动态输出网页的问题. 虽然这样做目的能达到,但是存在一些缺陷: 在 Servlet 输出网页片段非常恶心 (可读性差, ...
- 初学Java Web(5)——cookie-session学习
HTTP 协议 Web 浏览器与 Web 服务器之间的一问一答的交互过程必须遵守一定的规则,这样的规则就是 HTTP 协议. HTTP 是 hypertext transfer protocol(超文 ...
- Java Web编程技术学习要点及方向
学习编程技术要点及方向亮点: 传统学习编程技术落后,应跟著潮流,要对业务聚焦处理.要Jar, 不要War:以小为主,以简为宝,集堆而成.去繁取简 Spring Boot,明日之春(future of ...
- 使用Intellij idea新建Java Web项目(servlet) 原理及初步使用
准备 JDK (配置JDK_HOME\bin 和 CLASSPATH) 注:JDK8下载已经需要注册了,请使用JDK11(现在是官方长期支持的版本) 对于我们新手来说,JD ...
- Java Web之Servlet中response、request乱码问题解决
Java Web之Servlet中response.request乱码问题解决 一.request请求参数出现的乱码问题 get请求: get请求的参数是在url后面提交过来的,也就是在请求行中, ...
- java web中servlet、jsp、html 互相访问的路径问题
java web中servlet.jsp.html 互相访问的路径问题 在java web种经常出现 404找不到网页的错误,究其原因,一般是访问的路径不对. java web中的路径使用按我的分法可 ...
- JAVA WEB 用servlet实现分页,思路比较清晰和简单。
JAVA WEB 用servlet实现分页,思路比较清晰和简单.借鉴了其他大佬的思路.特别感谢. 是我第一次发表博客,如果有什么错误,欢迎大家指出!,谢谢 一.思路分析 前台一定是有类似这种的界面 点 ...
- 初学 Java Web 开发,请远离各种框架,从 Servlet 开发
Web框架是开发者在使用某种语言编写Web应用服务端时关于架构的最佳实践.很多Web框架是从实际的Web项目抽取出来的,仅和Web的请求和响应处 理有关,形成一个基础,在开发别的应用项目的时候则可以从 ...
- 初学 Java Web 开发,从 Servlet 开发
1. 基本要求:Java 编程基础 有良好的 Java 语言编程基础,这是必须的,在讨论 Web 开发技术时提了一个 Java 编程基础的问题会被鄙视的. 2. 环境准备 (Eclipse + Tom ...
随机推荐
- 使用Angular CLI进行Build (构建) 和 Serve
第一篇文章是: "使用angular cli生成angular5项目" : http://www.cnblogs.com/cgzl/p/8594571.html 第二篇文章是: & ...
- Dell服务器系统安装后无法正常进入系统
问题描述: 正常安装完系统后,重启,出现无法进入系统 问题解决: 此问题出现意味着系统引导项出现错误,进入raid配置里设置相应的所装系统盘为boot引导项:
- java--计时器
计时器 一.窗口化 public class Pro extends JFrame{ private JTextField textField = new JTextField(45);//系统时间文 ...
- UVA 10305 Ordering Tasks(拓扑排序的队列解法)
题目链接: https://vjudge.net/problem/UVA-10305#author=goodlife2017 题目描述 John有n个任务,但是有些任务需要在做完另外一些任务后才能做. ...
- IMLite轻量级即时通信工具开发指南
花了一周时间开发了一个简单的即时通信工具,勉强算是程序原型.现在我把开发流程和一些个人的想法记录下来.本文首先介绍程序架构和通信接口,之后会聚焦到服务器的信号槽设计原则,接下来将解释有关TCP通信的粘 ...
- STL --> queue单向队列
queue单向队列 queue 模板类的定义在<queue>头文件中.与stack 模板类很相似,queue 模板类也需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器 ...
- 自己开发的 vue 滑动按钮组件 vue-better-slider
写在前面的 这个人第一次尝试开发并发布一个 vue 的组件,该组件实现了类似 ios 手机淘宝客户端 -> 消息界面中消息的滑动删除功能等,如下为该组件的文档. 一个 Vue 的滑动按钮组件,有 ...
- [css 揭秘]:CSS揭秘 技巧(四):边框内圆角
我的github地址:https://github.com/FannieGirl/ifannie/ 源码都在这上面哦! 喜欢的给我一个星吧 边框内圆角 问题:有时候我们需要一个容器,只在内侧有圆角,而 ...
- [jdoj1090]矩阵_区间dp
矩阵 jdoj-1910 题目大意:给你连续的n个矩阵的长和宽,保证每连续的两个相邻矩阵满足相乘的条件,不能改变题目中矩阵的位置,求将这些矩阵相乘为一个矩阵的最小乘法次数. 注释:1<=n< ...
- 小细节,大用途,35 个 Java 代码性能优化总结!
前言: 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用 ...