引言
刚接触Java开发的时候,就直接从Spring Boot入手了,所以一直对Spring下层使用的Servlet和Tomcat等技术认识很模糊,所以整理了本文,其中介绍了Java Web技术的发展,与各个技术相关的核心内容,以及一些关于Web的小知识。
CGI
CGI(通用网关接口)CGI即使可以让服务器能够调用外部程序,并将HTTP请求信息传递给外部程序处理,对于每一个请求,会启动一个新的进程。
CGI的不足之处
- 需要为每个请求启动一个操作CGI程序的系统进程。如果请求频繁,这将会带来很大的开销。
- 需要为每个请求加载和运行一个CGI程序,这将带来很大的开销
- 需要重复编写处理网络协议的代码以及编码,这些工作都是非常耗时的。
Servlet
Sun Microsystems公司在1996年发布Servlet技术就是为了和CGI进行竞争,Servlet是一个特殊的Java程序,一个基于Java的Web应用通常包含一个或多个Servlet类。Servlet不能够自行创建并执行,它是在Servlet容器中运行的,容器将用户的请求传递给Servlet程序,并将Servlet的响应回传给用户。通常一个Servlet会关联一个或多个JSP页面。以前CGI经常因为性能开销上的问题被诟病,然而Fast CGI早就已经解决了CGI效率上的问题,事实上有很多你熟悉的网站都使用了CGI技术。
A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol.
To implement this interface, you can write a generic servlet that extends javax.servlet.GenericServlet or an HTTP servlet that extends javax.servlet.http.HttpServlet.
This interface defines methods to initialize a servlet, to service requests, and to remove a servlet from the server. These are known as life-cycle methods and are called in the following sequence:
The servlet is constructed, then initialized with the init method.
Any calls from clients to the service method are handled.
The servlet is taken out of service, then destroyed with the destroy method, then garbage collected and finalized.
In addition to the life-cycle methods, this interface provides the getServletConfig method, which the servlet can use to get any startup information, and the getServletInfo method, which allows the servlet to return basic information about itself, such as author, version, and copyright.
Servlet的优点
- 只需要启动一个操作系统进程以及加载一个JVM,大大降低了系统的开销
- 如果多个请求需要做同样处理的时候,这时候只需要加载一个类,这也大大降低了开销
- 所有动态加载的类可以实现对网络协议以及请求解码的共享,大大降低了工作量。
- Servlet能直接和Web服务器交互,而普通的CGI程序不能。Servlet还能在各个程序之间共享数据,使数据库连接池之类的功能很容易实现。
Tomcat和Servlet
The Apache Tomcat software is an open source implementation of the Java Servlet, JavaServer Pages, Java Expression Language and Java WebSocket technologies.
Tomcat作为Servlet容器,当然也可以当作web服务器直接使用,负责把接收和返回http请求。
下面,我们通过一个更细致的时序图来看一下具体工作过程:
从上图我们看出一个Http的具体处理流程:
- Web客户向Servlet容器(Tomcat)发出Http请求
- Servlet容器分析客户的请求信息
- Servlet容器创建一个HttpRequest对象,将客户请求的信息封装到这个对象中
- Servlet容器创建一个HttpResponse对象
- Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数传给 HttpServlet对象
- HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息
- HttpServlet调用HttpResponse对象的有关方法,生成响应数据
- Servlet容器把HttpServlet的响应结果传给Web客户
Servlet的基本目录
在tomcat/webapps目录下创建上述目录结构,所有HTML,静态文件直接保存在应用程序目录下,所有的Servlet类保存在web-inf/classe目录或子目录下,web.xml(部署描述,filter,url与servlet的对应关系)文件保存在web-inf目录下。
Servlet接口
在最基本的Servlet类中,需要实现Servlet接口定义的init()、servic()、destroy()、getServletConfig()和geServletInfo()方法,其中业务逻辑在service中编写,在service方法中最常用的是通过PrintWriter对象进行内容的输出。
后来,为了简化实现Servlet的成本,GenericServlet抽象类诞生了,它实现了Servlet接口的大部分函数。在GenericServlet抽象类的帮助下,只需要重写service方法即可实现Servlet接口。
之后出现了HttpServlet,它覆写了GenericServlet类,将ServletRequest和ServletResponse对象分别封装为HttpServletRequest和HttpServletResponse对象。HttpServlet同时实现了service方法,在请求进来时,Web容器首先调用HttpServlet的service方法,并根据请求的类型调用doGet或doPost方法,所以我们只需要覆盖doGet()和goPost()方法即可。
JSP
Servlet的最大缺点就是在Servlet类中编写大量繁杂的HTML代码,使得Java代码与HTML代码糅杂在一起,所以JSP应运而生。
JSP本质也是Servelt,然而其不需要编译,JSP页面是一个以.jsp扩展名的文本文件。简单的JSP页面在第一次请求后被翻译为(JSP名)_jsp的servlet,翻译之后的Servelt可以看到:_jspInit(),_jspDestory(),_jspService()这样的方法其实都是和Servlet相对应的。
Spring MVC
当要使用Servlet完成的复杂的功能时,需要编写多个Servlet类,并且在web.xml进行注册,这对于完成复杂的Web应用,代码编写会变得很复杂,开发成本也会很高。所以Spring提供了强大的Web开发框架Spring MVC。Spring MVC是Spring产品的一部分,享有Spring松耦合等所有优点。
Spring MVC是一个模型-视图-控制器的Web框架,建立在前端控制器servlet(DispatcherServlet),它负责发送每个请求到合适的处理程序,使用视图来返回响应结果。
Spring MVC的架构:
Spring web MVC框架提供了MVC(模型 - 视图 - 控制器)架构和用于开发灵活和松散耦合的Web应用程序的组件。MVC模式导致应用程序的不同方面(输入逻辑,业务逻辑和UI逻辑)分离,同时提供这些元素之间的松散耦合
- 模型(Model):封装了应用程序的数据,通常由POJO类组成
- 视图(View):负责渲染模型数据,一般来说它生成客户端浏览器可以解释HTML输出
- 控制器(Controller):负责处理用户请求并构建适当的模型,并将其传递给视图进行渲染
DispatcherServlet组件类 Spring MVC框架是围绕DispatcherServlet设计的,它处理所有的请求和响应。Spring MVC DispatcherServlet的工作流程:
会话跟踪技术
Cookie
向客户端发送Cookie
Cookie c =new Cookie("name","value"); //创建Cookie
c.setMaxAge(60*60*24); //设置最大时效,此处设置的最大时效为一天
response.addCookie(c); //把Cookie放入到HTTP响应中
从客户端读取Cookie
String name ="name";
Cookie[]cookies =request.getCookies();
if(cookies !=null){
for(int i= 0;i<cookies.length;i++){
Cookie cookie =cookies[i];
if(name.equals(cookis.getName()))
//something is here.
//you can get the value
cookie.getValue();
}
}
优点:数据可以持久保存,不需要服务器资源,简单,基于文本的Key-Value
缺点:大小受到限制,用户可以禁用Cookie功能,由于保存在本地,有一定的安全风险。
URL 重写
在URL中添加用户会话的信息作为请求的参数,或者将唯一的会话ID添加到URL结尾以标识一个会话。
优点: 在Cookie被禁用的时候依然可以使用
缺点: 必须对网站的URL进行编码,所有页面必须动态生成,不能用预先记录下来的URL进行访问。
隐藏的表单域
<input type="hidden" name ="session" value="..."/>
优点: Cookie被禁时可以使用
缺点: 所有页面必须是表单提交之后的结果。
HttpSession
在所有会话跟踪技术中,HttpSession对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动创建 HttpSession,每个用户可以访问他自己的HttpSession。可以通过HttpServletRequest对象的getSession方 法获得HttpSession,通过HttpSession的setAttribute方法可以将一个值放在HttpSession中,通过调用 HttpSession对象的getAttribute方法,同时传入属性名就可以获取保存在HttpSession中的对象。与上面三种方式不同的 是,HttpSession放在服务器的内存中,因此不要将过大的对象放在里面,即使目前的Servlet容器可以在内存将满时将HttpSession 中的对象移到其他存储设备中,但是这样势必影响性能。添加到HttpSession中的值可以是任意Java对象,这个对象最好实现了 Serializable接口,这样Servlet容器在必要的时候可以将其序列化到文件中,否则在序列化时就会出现异常。
Cookie 和 Session都是用来跟踪浏览器用户身份的会话方式,但是两者的应用场景不太一样。
Cookie 一般用来保存用户信息 比如①我们在 Cookie 中保存已经登录过的用户信息,下次访问网站的时候页面可以自动帮你登录的一些基本信息给填了;②一般的网站都会有保持登录也就是说下次你再访问网站的时候就不需要重新登录了,这是因为用户登录的时候我们可以存放了一个 Token 在 Cookie 中,下次登录的时候只需要根据 Token 值来查找用户即可(为了安全考虑,重新登录一般要将 Token 重写);③登录一次网站后访问网站其他页面不需要重新登录。
Session 的主要作用就是通过服务端记录用户的状态。 典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了。
Cookie 数据保存在客户端(浏览器端),Session 数据保存在服务器端。
Cookie 存储在客户端中,而Session存储在服务器上,相对来说 Session 安全性更高。如果使用 Cookie 的一些敏感信息不要写入 Cookie 中,最好能将 Cookie 信息加密然后使用到的时候再去服务器端解密。
文章说明
更多有价值的文章均收录于贝贝猫的文章目录
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
创作声明: 本文基于下列所有参考内容进行创作,其中可能涉及复制、修改或者转换,图片均来自网络,如有侵权请联系我,我会第一时间进行删除。
参考内容
[1] Servlet 到 Spring MVC 的简化之路
[2] J2EE基础知识
[3] Servlet/tomcat/spring mvc之间关系
[4] SpringMVC、Tomcat怎样完成一次Http请求的?