Servlet基础
1.web应用演变:从单机向网络;从CS向BS
(1)两层CS架构:客户端+DB
特点:数据库作为Server,使用数据库特定的编程语言编写业务逻辑,客户端提供操作界面和少量的业务逻辑处理;
缺点:移植性差(更换数据库需要重新编程),不适合大型应用;
(2)三层CS架构:客户端+应用服务器(任何支持TCP编程的语言)+DB
特点:1.数据库只负责数据管理;2.应用服务器提供所有的业务处理;3.客户端只负责提供界面
优点:移植性好,适合大型应用;
缺点:客户端需要单独安装,开发复杂(需要自定义协议,编写客户端和服务端的通信模板)
(3)网络程序+BS架构:Brower+Web Server+DB
特点:1.数据库只负责数据的管理;2.web服务器负责业务逻辑的处理;3.浏览器负责提供操作页面;
优点:不需要单独安装客户端;开发相对于CS简单,客户端和服务端都是使用标准的HTTP协议进行通信;
2.什么是Servlet
概念(官方):Sun(Oracle)公司制定的一种用来扩展Web服务器功能的组件规范;是Sun推出在服务端处理HTTP协议的组件;
组件(官方):在软件开发行业,符合一定规范,实现部分功能,并且需要部署到容器当中才能运行的软件模块;
Servlet运行原理:
3.Servlet特征
- 部署在服务器上
- 能拼网页、图片、视频,即可以动态拼网络资源(包括:HTML/img等等);这件事就叫HTTP协议
- 必须满足sun规范
4.Servlet开发步骤
(1)创建WEB项目;WEB目录: webapp/WEB-INF/web.xml
(2)导入jar包
- 通过maven搜索javaee导入
- 使用tomcat自带的javaee包(右键项目 -> properties -> Targeted Runtimes -> 勾选你所配置的tomcat)
(3)写Servlet(必须满足规范,即实现Servlet接口或者继承HttpServlet类)
(4)注册Servlet
<!-- 1.声明Servlet ,并给它取一个别名,别名是便于在此文件中引用此类方便。-->
<servlet>
<servlet-name>time</servlet-name>
<servlet-class>web.TimeServlet</servlet-class>
</servlet>
<!-- 2.给此Servlet注册一个网名,网名是用来在互联网上访问此类的途径。 -->
<servlet-mapping>
<servlet-name>time</servlet-name>
<url-pattern>/tm</url-pattern>
</servlet-mapping>
(5)部署项目到tomcat;启动tomacat,访问即可
5.Servlet运行步骤
(1)浏览器依据IP建立与容器的连接
(2)浏览器数据打包
(3)容器解析请求数据包,封装对象
(4)容器依据路径找到Servlet创建对象
(5)容器调用Servlet对象的service方法
(6)容器将响应打包发给浏览器
(7)浏览器取出结果,生产页面
通俗讲:Tomcat通过路径读取wptWebapp下的项目,然后通过项目下的servlet配置获取名称,通过别名获取类名,然后Tomcat直接实例化类,调用它的service方法。
Servlet工作原理
1.获取请求参数
- 获取请求参数的方式:
· 获取提交1:1的Name-Value的方法
getParameter(name)
//接收账号
String name = req.getParameter("userName");
<p>
账号:<input type="text" maxlength=12 name="userName"/>
</p>
· 获取提交1:M的Name-Value的方法(多用于复选框)
getParameterValues(name)
- 处理乱码问题(三种解决方式):
· 乱码问题由来:当编码和解码使用的字符集不一致的时候就会出现乱码
a.利用Servlet处理方案.缺点:麻烦;有点:对get和post都有效
1.采用ISO8859-1将乱码的String还原成byte
2.采用UTF-8将byte转成String
b.修改servlet.xml(即tomcat的配置文件,在server项目里面),在65行加上URIEncoding=“UTF-8”.
优点:简单;缺点:只有get有效。对所有项目都有影响。
url和uri都是路径的意思
c(重点).在获取参数前,增加request.setCharacterEncoding("utf-8")
优点:简单,后续所有的都可以用
缺点:只对post有效
建议:1.get请求避免传中文
2.post请求使用request设置编码
响应乱码情况:下面两处写一处即可
res.setContentType("text/html;charset=utf-8"),因为这句话必须写,所有一般写它
res.setCharacterEncoding("utf-8")
Servlet特性
1.Servlet生命周期
- 什么是Servlet生命周期
即容器如何创建Servlet对象、如何为Servlet对象分配资源、如何调用Servlet对象方法来处理请求、以及如何销毁Servlet对象的整个过程;
- 生命周期四个阶段
(1)阶段一:实例化(类似于单例模式创建对象的两种方式)
容器调用Servlet构造器,创建一个Servlet对象。
情形1:开始容器里面没有Servlet对象,只有收到请求后才会创建Servlet对象;
情形2:容器启动之后就立即创建相应的实例;
(2)阶段二:初始化(init方法只会执行一次)
容器在创建好Servlet对象之后,会立即调用该对象的init方法;一般情况下,我们不用写init方法,因为GenericServlet已经提供了init方法的实现(将容器传递过来的ServletConfig对象保存下来,并且,提供了getServletConfig方式来获取ServletConfig对象)。
可以配置初始化参数:
<init-param>
<param-name>参数名字</param-name>
<param-value>参数值</param-value>
</init-param>
String ServletConfig.getInitParameter("参数名字")
(3)阶段三:就绪
容器收到请求之后调用Servlet对象的service()来处理请求
(4)阶段四:销毁
- 容器依据自身的算法删除Servlet对象,删除前会调用destory();
- 只会执行一次
- 可以override(重写) destory方法来实现自己的逻辑
- 应用程序卸载时,一定要调用destory()方法
2.Servlet特征
ServletContext(Servlet上下文)
1.什么是ServletContext
- 容器启动之后,会为每一个Web应用创建唯一的一个符合ServletContext接口要求的对象,该对象就是Servlet上下文
2.如何获取Servlet上下文
- 通过GenericServlet提供的getServletContext();
- 通过ServletConfig提供的getServletContext();
- 通过HttpSession提供的getServletContext();
- 通过FilterConfig提供的getServletContext();
3.Servlet上下文的作用及特点
- 使用setAttribute绑定数据
- 使用removeAttribute移除绑定数据
- 使用getAttribute获取绑定数据
特点:servletContext绑定的数据可以被整个应用上的所有组件共享,并且一直访问;
//使用context获取web.xml中预置的参数,
//该对象中的数据可以被所有的Servlet共用。
ServletContext ctx = getServletContext();
System.out.println(ctx.getInitParameter("size"));
<context-param>
<!--此参数可以被多个Servlet共用在tomcat启动时,它会自动创建ServletContext对象且调用该对象的方法自动读取此参数。-->
<param-name>size</param-name>
<param-value>10</param-value>
</context-param>
ServletContext(公用秘书,一对多,相当于教室)和ServletConfig(私人秘书,一对一,相当于账号),都是辅助Servlet的,能给Servlet预置数据
配置文件写在xml中,读取xml用dom4j,
或者写到properties里面,用properties类创建实例读取
1.有时候需要给Servlet预置一些参数,如每页显示条目数(size)
2.可以自己写配置文件(properties/xml),自己写工具读取
3.也可以使用ServletConfig和ServletContext,他们都能够自动获取web.xml中预置的参数,传给Servlet。
ServletConfig典型使用场景:(标签写在servlet内部,给一个使用)
- 假设做一个网页游戏,需要限制在线人数maxOnline.
- 此参数应该可以配置,写在配置文件里。
- 该参数只有LoginServlet使用,因此使用config预置即可。
ServletContext典型使用场景:(标签写在servlet外部,给多个使用)
- 假设做一个员工管理软件,里面很多查询功能都需要分页
- 每页显示的行数(size)是固定的,且可以配置
- 此参数被很多查询Servlet共享,所有使用context读取比较合适
Servlet线程安全问题
1.为什么会有线程安全问题
- 当容器收到请求之后,会启动一个线程来进行相应的处理;默认情况下,容器只会为了每个Servlet创建一个实例;如果同时多个请求访问同一个Servlet,则肯定会有多个线程访问这个Servlet的实例。如果这些线程要修改Servlet实例的某个属性,就有可能发生线程安全问题。
2.线程安全问题的由来
3.解决办法
- 不用成员变量
- 加锁
Servlet容器对路径的处理
1.重定向(后续补上转发,并说明他们之间的区别)
什么是重定向
服务器想浏览器发送一个302状态码及一个Location消息头(该消息头的值是一个地址,称之为重定向地址),浏览器收到之后会立即向重定向地址发送请求;如图:
如上图:
(1)访问AddEmp;
(2)执行数据插入操作;
(3)执行结束后使用重定向代码发回一个数据包,里面包括302状态码和一个消息头;
(4)浏览器收到消息后会立即向服务器的ListEmp发出请求
注:3,4这个过程就是重定向
重定向代码实现
重定向特点
(1)重定向地址栏可以是任意地址
(2)重定向之后,浏览器地址栏的地址会发生改变
(3)重定向过程中涉及到的Web组件并不会共享同一个request和response对象
一般用途:
1.删除后重定向到查询;
2.增加、修改后重定向到查询
2.URI和URL的区别
狭义(单纯从java方面来说)
URI:资源(比如servlet)的绝对路径
URL:资源的完整路径
广义(任何web项目,包括.net/php)
URI:资源的名称(如:小名、外号、真名等等)
URL:资源的真名
注:URI包含URL
3.Servlet容器如何处理请求资源路径
什么是请求资源路径
Web服务器对请求地址的处理过程
(1)浏览器依据ip、port建立与Servlet容器之间的连接,然后将请求资源路径appName/xxx.html发送给容器;
(2)容器依据应用名"/appName"找到应用所在的文件夹,容器会默认请求的是一个Servlet,查找web.xml文件中所有的Servlet配置“<url-pattern>”,看是否有匹配的Servlet;
Servlet访问路径的3种配置方式
(1)精确匹配(/abc)
- 只有这一个路径可以访问servlet
- 改servlet只能处理这一个请求
(2)通配符(/*)
- 所有的路径都可以访问该servlet
- 该servlet可以处理一切请求
(3)后缀匹配(*.do)
- 以do为后缀的请求可以访问该servlet
- 该servlet可以处理很多请求
4.单个servlet实现多请求
为什么要将多个servlet合并
- 一般情况下,Servlet的主要作用是充当控制器的角色,即接收请求分发给不同资源,这时Servlet只要有一个就可以完成分发的过程,所以需要将Servlet合并;
实现合并步骤
(1)使用后缀匹配模式修改web.xml文件
如下图: