Servlet&Jsp的异同

相同点

jsp可以被看做一个特殊的Servlet类,它只不过是对Servlet的扩充,它们都可以生成动态页面

不同点

执行过程和结构

我们可以将Servlet看作是嵌套了一定量的html的一个类,在执行的过程中,Servlet就是一个类,会首先被编译成class文件,然后由服务器调用,而jsp首先被转化为Servlet(java文件),然后再被编译为class文件,最后由服务器调用。jsp看作是嵌套了java代码的一个html页面。

jsp本质上就是个servlet,服务器(也就是tomcat,文件位于tomcat下的work文件夹)主要是先把jsp解析成servlet,也就是java文件,然后通过jsdk解析为class文件,执行后生成静态文本,返回给客户端客户端只是单纯的提交请求,所有的处理和响应都由服务器去完成,返回一个纯静态的页面给客户端显示

jsp是servlet基础之上的语言,我理解就是html代码量大,而java代码量小,所以不如把java代码嵌入html页面中

服务方式(MVC)

正因为上一点的原因,jsp处理页面显示,servelet处理业务逻辑


模型(javabean):表示企业数据和业务逻辑的处理,模型接收视图请求数据,并返回最终的处理结果。根据请求处理业务逻辑并返回结果,不关心其它

视图(jsp)视图是用户看到并与之交互的界面。显示信息,不关心获得方式

控制器(servlet):接收用户输入并调用模型和视图去完成用户的需求

Servlet

servlet的生命周期

初始化阶段的工作

初始化阶段:Servlet启动,会读取配置文件中的信息构造指定的Servlet对象(HttpServletResponse和HttpServletRequest)创建ServletConfig对象,将ServletConfig作为参数来调用init()方法(通过ServletConfig接口的getInitParameter(java.lang.String name)方法可以在初始化时获得ServletContext设置的参数值)。
###ServletContext对象和servletConfig对象
ServletContext对象:servlet容器在启动时会加载web应用,并为每个web应用创建唯一的servlet context对象,可以把ServletContext看成是一个Web应用的服务器端组件的共享内存,在ServletContext中可以存放共享数据。ServletContext对象是真正的一个全局对象,凡是web容器中的Servlet都可以访问。 整个web应用只有唯一的一个ServletContext对象

ServletConfig对象:用于封装servlet的配置信息。从一个servlet被实例化后,对任何客户端在任何时候访问有效,但仅对servlet自身有效,一个servlet的ServletConfig对象不能被另一个servlet访问。
###详细的生命周期
Servlet的生命周期分为5个阶段:加载、创建、初始化、处理客户请求、卸载。

用户通过单击一个连接来向Servlet发起请求

未创建阶段

(1)加载:web容器通过类加载器使用servlet类对应的文件加载servlet
(2)创建:通过调用servlet构造函数创建一个servlet对象

在初始化执行之前就创建好servlet的实例了

(3)初始化:调用init方法初始化,仅执行一次,负责装载Servlet时初始化Servlet对象,也就是HttpServletResponse和HttpServletRequest

(4)处理客户请求:调用 service() 核心方法,每当有一个客户请求,容器会创建一个线程来处理客户请求,一般HttpServlet中会有doGet和doPost两种处理方式。

(5)卸载:调用destroy方法让servlet自己释放其占用的资源,在停止并且卸载Servlet时执行,负责释放资源。仅执行一次


###代码结构


<form action="/test/Login" method="post">                 //提交方式
        username:<input type="text" name="username"><br>
        password:<input type="password" name="password"><br>
        <input type="submit" value="提交">&nbsp;&nbsp;&nbsp;&nbsp;
        <input type="reset" value="重置"><br>
    </form>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public class loginservlet extends HttpServlet{
     @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)//对应的service的方法,已经初始化后HttpServletRequest和HttpServletResponse后的对象
    		throws ServletException, IOException {
    	 System.out.println("doget in process");
    	process(req, resp);
    }
	
     @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    		throws ServletException, IOException {
     	 System.out.println("dopsot in process");
    	 process(req, resp);
    }
     private void process(HttpServletRequest req, HttpServletResponse resp)
 			throws IOException {
 		String username=req.getParameter("username");    //得到请求名的参数
     	String password=req.getParameter("password");
     	resp.setContentType("text/html");
     	PrintWriter out=resp.getWriter();    //将写入到响应里的字符流传给out,打印到客户端
     	out.println("<html><head><title>Login Result</title></head>");  
     	out.println("<body>username:"+username+"<br>password:"+password+"</body></html>");
     	out.flush();
 	}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

###servlet的体系结构
下图是servlet的体系结构:

更详细的继承体系:

  • ServletConfig接口定义了在Servlet初始化的过程中由Servlet容器传递给Servlet得配置信息对象

  • GenericServlet是个抽象类,必须给出子类才能实例化。它给 出了设计servlet的一些骨架,定义了servlet生命周期,还有一些得到名字、配置、初始化参数的方法,其设计的是和应用层协议无关的,也就是说 你有可能用非http协议实现它。大多数Servlet通过从GenericServlet或HttpServlet类进行扩展来实现

  • HttpServlet是子类,当然就具有GenericServlet的一切特性,还添加了doGet, doPost, doDelete, doPut, doTrace等方法对应处理http协议里的命令的请求响应过程。

  • HttpServletRequest接口扩展ServletRequest接口,为HTTP Servlet提供HTTP请求信息

##HttpServletResponse和HttpServletRequest
###HttpServletRequest接口中常用的方法

参数相关

通过用户提交的参数name获取参数value(最常用的方法)
String value = request.getParameter(String name);
向HttpServletRequest对象中存储数据(绑定)
request.setAttribute(String name,Object obj);
从HttpServletRequest对象中获取数据(读取数据)
Object obj = request.getAttribute(String name);

请求转发

使用request对象完成转发(转发是一次请求,一次请求跨越多个Servlet)
request.getRequestDispatcher(“资源路径”).forward(request,response);

路径相关

获取客户端的IP地址
String clientIP = request.getRemoteAddr();
获取URI
String uri = request.getRequestURI();
StringBuffer url = request.getRequestURL();
获取Servlet Path
String servletPath = request.getServletPath();
获取应用程序的根路径,获取应用上下文路径
String contextPath = request.getContextPath();

解决乱码

解决请求体中的乱码问题(在从request对象中获取任何数据之前设置有效)
request.setCharacterEncoding(“UTF-8”);

获取Cookie

在服务器端获取用户发送的请求中的所有Cookie
Cookie[] cookies = request.getCookies();

获取头HTTP

request.getHeader(String s);

获取session

获取会话对象session
HttpSession sessoin = request.getSessoin(); 获取session对象,如果获取不到则开启新session
HttpSession sessoin = request.getSession(true); 获取session对象,如果获取不到则开启新session
HttpSession sessoin = request.getSession(false); 获取session对象,如果获取不到则返回null

###HttpServletResponse接口中常用的方法

输出返回数据

从Servlet中可以通过getWriter方法取得PrintWriter对象,来输出字符数据。

设置cookie

addCookie方可以在Web服务器响应中加入Cookie对象,这个对象将被浏览器所保存。Cookie机制也被用来维护会话状态。

设置HTTP头标

setHeader可以指定特定名称的头信息值

设置重定向

sendRedirect方法向客户发出临时重新导向的响应。它生成的响应状态码为302。

设置响应的编码格式

response.setContentType(“text/html;charset=utf-8”);

##请求转发和重定向

###通常意义讲

从网上找了下,觉得解答的很好
1.从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
2.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.
redirect:不能共享数据.
3.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.
4.从效率来说
forward:高.
redirect:低.
本质区别

###好的解释方式

解释一  
一句话,转发是服务器行为,重定向是客户端行为。为什么这样说呢,这就要看两个动作的工作流程:

转发过程:客户浏览器发送http请求----》web服务器接受此请求–》调用内部的一个方法在容器内部完成请求处理和转发动作----》将目标资源 发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客 户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。

重定向过程:客户浏览器发送http请求----》web服务器接受后发送302状态码响应及对应新的location给客户浏览器–》客户浏览器发现 是302响应,则自动再发送一个新的http请求,请求url是新的location地址----》服务器根据此请求寻找资源并发送给客户。在这里 location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的 路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。

解释二
重定向,其实是两次request, 第一次,客户端request A,服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。
解释三
假设你去办理某个执照,
重定向:你先去了A局,A局的人说:“这个事情不归我们管,去B局”,然后,你就从A退了出来,自己乘车去了B局。
转发:你先去了A局,A局看了以后,知道这个事情其实应该B局来管,但是他没有把你退回来,而是让你坐一会儿,自己到后面办公室联系了B的人,让他们办好后,送了过来。
##Servlet的安全性问题
Servlet在多线程下其本身并不是线程安全的。

如果在类中定义成员变量,而在service中根据不同的线程对该成员变量进行更改,那么在并发的时候就会引起错误。

**最好是在方法中,定义局部变量,而不是类变量或者对象的成员变量。**由于方法中的局部变量是在栈中,彼此各自都拥有独立的运行空间而不会互相干扰,因此才做到线程安全。
#Jsp
##执行流程

如果该jsp之前被访问过,则可以省略掉将java解析为class文件的过程,因为此时已经是class文件了,这么做是为了提高效率。

jsp本质上就是个servlet,服务器(也就是tomcat,文件位于tomcat下的work文件夹)

  • 主要是先把jsp解析成servlet,也就是java文件

  • 然后通过jsdk解析为class文件

  • 执行后生成静态文本,返回给客户端客户端只是单纯的提交请求

所有的处理和响应都由服务器去完成,返回一个纯静态的页面给客户端显示


##Jsp语法
在 JSP 2.0 规范中,JSP页面主要包括4部分:JSP 指令元素,JSP 脚本元素,JSP 动作元素和注释:

###JSP指令元素

page(<%@ page ...%>) 
include(<%@ include file="..." %>) 
taglib(<%@ taglib uri="tagLibraryURI" | prefix="tagPrefix" %>) 

使用示例
1,page

<%@ page language="java" import="java.util.*,java.io.*" pageEncoding="UTF-8"%>  

//编译器指令中的page指令可以一行写,也可多行写,import表示要引入的java包文件,引入后才有代码自动补全,还可以设置页面编码格式。

2,include

 <%@ include file="testinclude.jsp"  %>       //  编译器指令中的include指令,可以包含其它静态文件的内容  

3,taglib

 <%@ taglib prefix="s" uri="/struts-tags" %> //用于引入定制标签库

###JSP脚本语法

======================jsp脚本元素=================

声明(<%! deslaration %>) 
脚本程序(<% scriptlet %>) 
表达式(<%= expression %>) 

=====================jsp注释======================

html注释   <!-- 这是html注释<%=new Date().toLocaleString() %> -->
jsp注释  <%--这是jsp注释 --%>  

使用示例
1,声明

<%! int a=3;  %>   //页面每次刷新减1,相当于一个全局变量
<%  int b=3;  %>  //局部变量,b不会变
<%=a-- %>
<%=b-- %>     
//单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例。特点:1,一个类只能有一个实例2,自己创建这个实例。3,整个系统都要使用这个实例,单实例的成员变量使用效果相当于静态成员变量最好不要用声明

2,脚本段

 <% File file=new File("text.txt") ; %>    
 
//脚本语法中的脚本段,要求符合java语法规范,且目前为止,只能写入java语句

3,表达式

<%=a-- %>
<%=b-- %>    

4,html注释

<!-- 这是html注释<%=new Date().toLocaleString() %> -->  //脚本语法中的html注释,在查看源码时可见,其中的脚本语句也是可执行的

5,jsp注释

 <%--这是jsp注释 --%>                 //脚本语法中的jsp注释,也叫隐藏注释语句,在查看源码时不可见,安全性强
 
<% /*Java脚本注释*/ %> 
<% /**Java脚本文档注释**/ %>

###JSP动作元素

==========================基本的六个动作元素=============
<jsp:include> 动作 
<jsp:forward> 动作 
<jsp:usebean> 动作 
<jsp:setproperty>和<jsp:getproperty> 动作 
<jsp:plugin>
=======================================================
<jsp:param> 动作 
<jsp:params>和<jsp:fallback> 动作 

使用示例

1,jsp跳转动作语法中的forward可以用于参数传递

<%@ page contentType="text/html;charset=gb2312" %>
<html>
<head>
<title>test</title>
</head>
<body>
=============================================  携带参数传递
<jsp:forward page="forwardTo.jsp">
   <jsp:param name="userName" value="riso"/>
</jsp:forward>
===============================================
</body>
</html>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<%@ page
contentType="text/html;charset=gb2312" %>
<!--forwardTo.jsp-->
<%
String
useName=request.getParameter("userName");  //传递参数到这里值为riso
String outStr= "谢谢光临!";
outStr+=useName;
out.println(outStr); //谢谢光临:riso
%>


2,jsp的包含动作语法,携带参数

jsp的包含动作语法include
<html>
<head>
<title>peixun.2.10.jsp</title>
</head>
<body>
====================================================
<jsp:include page="peixun2.10.1.jsp" >
    <jsp:param name="User" value="HiFi King" />      //jsp参数动作语法
</jsp:include>
==================================================
</body>
</html>
+++++++++++++++++++++++++++++++++++++++++++++
<%
String username;
username=request.getParameter("User");
out.println("Username is "+username+"<br>");
%>

3,Javabean对象

<jsp:useBean id="car"  scope="session"  class="com.Car" > //实例化一个类
<jsp:setProperty name="car"  property="color"  value="red" > //设置已经实例化的对象的某个属性
Color = <jsp:getProperty  name="car"  property="color"  > //获取某个属性的值
  • 当scope为page时;javabean作用范围在当前页面,请求转发也会失效
  • 当scope为request(page在页面不跳转的时候与request大致相同)时;javabean作用范围在一个请求内
  • 当scope为session时;javabean作用范围在整个浏览器
  • 当scope为application时;javabean作用范围在整个服务器

##Jsp内置对象

可以分为四类
第一类:与Servlet有关的:page(表示当前JSP页面)和config(提供一些配置信息)
第二类:与输入输出有关的:out,request,response
第三类:与Context有关的:aplicationsession,pageContext
第四类:与Error有关的,exception.

###request,session与application




##会话跟踪技术
###定义
会话跟踪是一种灵活、轻便的机制,它使Web上的状态编程变为可能。HTTP是一种无状态协议,每当用户发出请求时,服务器就会做出响应,客户端与服务器之间的联系是离散的、非连续的。当用户在同一网站的多个页面之间转换时,根本无法确定是否是同一个客户,会话跟踪技术就可以解决这个问题。当一个客户在多个页面间切换时,服务器会保存该用户的信息。
###方式
1)隐藏表单域<input type="hidden">,非常适合步需要大量数据存储的会话应用。

2)URL 重写:URL 可以在后面附加参数,和服务器的请求一起发送,这些参数为名字/值对。

3).Cookie:一个 Cookie 是一个小的,已命名数据元素。服务器使用 SET-Cookie 头标将它作为 HTTP响应的一部分传送到客户端,客户端被请求保存 Cookie 值,在对同一服务器的后续请求使用一个Cookie 头标将之返回到服务器。与其它技术比较,Cookie 的一个优点是在浏览器会话结束后,甚至在客户端计算机重启后它仍可以保留其值。

4).Session:使用 setAttribute(String str,Object obj)方法将对象捆绑到一个会话
###session和cookie

1.session用来表示用户会话,session对象在服务端维护,一般tomcat设定session生命周期为30分钟,超时将失效,也可以主动设置无效;

2.cookie存放在客户端,可以分为内存cookie和磁盘cookie。内存cookie在浏览器关闭后消失,磁盘cookie超时后消失。当浏览器发送请求时,将自动发送对应cookie信息,前提是请求url满足cookie路径;

3.可以将sessionId存放在cookie中也可以通过重写url将sessionId拼接在url。因此可以查看浏览器cookie或地址栏url看到sessionId;

4,请求到服务端时,将根据请求中的sessionId查找session,如果可以获取到则返回,否则返回null或者返回新构建的session,老的session依旧存在

5,隐藏域在页面中对于用户(浏览器)是不可见的,在表单中插入隐藏域的目的在于收集或发送信息,以利于被处理表单的程序所使用。浏览者单击发送按钮发送表单的时候,隐藏域的信息也被一起发送到服务器。