jsp & servlet 精华一页纸

servlet/jsp 本质上是一种java编程协议/规范, 存在于web容器中,由web容器解析,管理其生命周期。

1、容器

一个典型简单容器的实现:

实现一个Java程序Application

使用Socket监听一个端口

解析url/解析协议

发送数据给客户端

容器处理请求的典型过程:

I、客户请求

II、Web容器接受到请求,把相关信息封装成两个对象 HttpServletRequest/HttpServletResponse

III、根据请求的URL找到具体的servlet,并为这个请求创建一个线程,把请求和响应对象传递给这个servlet线程

IV、容器调用 servlet提供的service方法(doGet、doPost)

V、servlet把处理结果设置到 响应对象中去

VI、线程结束,容器把响应翻译并返回给客户端

2、典型应用

I、部署结构

web-app

WEB-INF

web.xml

classes

html/jsp

II、web.xml

两个部分:处理的servlet  | 拦截的URL路径

servletA

xxx.xxx.ServletA 

servletA

/

首先定义 servlet 名称,并且映射到具体的代码路径

其次定义 servlet 名称,到url响应的服务名

III、Servelt实现

public class ServletA extends HttpServlet {

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String c = request.getParameter("xxx"); -- 获取参数

MyObject o = new MyObject-- Model 部分

request.setAttribute("styles", o); -- View 部分

RequestDispatcher view = request.getRequestDispatcher("result.jsp");

view.forward(request, response);-- 转发请求

}

}

注意标红的这段代码, 这是很多 第三方MVC 框架(比如 Spring MVC)的核心基础, 从这里开始是第一步,基于此不断构建了一个庞大的框架体系。

3、Servlet详解

继承体系

servlet接口 -> genericservlet抽象类 -> HttpServlet

ServletRequest(接口) - HttpServletReqeust(接口)

ServletResponse(接口) - HttpServletResponse

生命周期- httpServlet 接口方法

启动 - init: servlet创建后,服务前执行

服务 - service doGet/doPost:应用覆盖执行

销毁 - destory:释放资源

数据交互

客户端请求数据 - HttpRequest : 参数 getParameter | 头部 getHeader | 缓存 getCookies ...

返回客户端数据 - HttpResponse: 头部 setHeader | 输出流 getOutputStream ...

系统全局参数 - servletConfig | servletContext

监听与全局参数

全局参数 与 的区别

是整个webApp 级别的参数,给所有Servlet使用

是Servlet级别的参数,给当前Servlet的 多个实例使用

另外,纠正网上 以讹传讹的一个错误,init-param并不是只能在 init方法中使用,而是从 init 方法的生命周期之后才能使用,具体说来就是 构造函数里不能使用,直到容器调用init方法开始才能使用

监听

web.xml

com.example.MyServletContextListener

因为监听类扩展的接口 ServletContextListener ,可以获取全局对象 ServletContext,因而可以做一些全局的准备工作,把对应的结果缓存到全局对象中;典型的就是数据库链接

几个注意点:

a、请求幂等性的问题, 非查询性的请求处理时要注意检查,防止重复执行

b、请求重定向与请求分派的区别:

请求分派在服务端发生,分派是由服务器的一个组件传递给另一个组件

重定向在客户端发生。服务器发送一个 301 状态的响应给浏览器,并在头部有一个location的参数,包含新的URL,浏览器根据新的URL重新请求,在客户端浏览器能够看到变化

4、会话管理

http协议是无状态协议 ,如何缓存状态,如何跟踪用户的访问

思考一下, 要跟踪一个客户, 首先需要标识一个客户; 其次这个标识在交互中要一直携带,如何携带

I、生成这个标识

方法一: 本地 自己生成 - 比如非浏览器的http请求

方法二:服务端 在初次访问时生成一个唯一标识 request.getSession(); session.getId();

II、携带这个标识

方法一:客户端在发送请求的 cookie中携带这个标识; 服务端在发送相应时 set-Cookie (除了设置标识外,cookie 可以存储更多的数据)-- 这部分工作是容器在处理

方法二:通过 URL 重写,response.encodeURL("SessionTest.do") -- 原理就是http请求携带一个 参数jsessionid

方法三:通过表单 hidden 域,这个已不推荐使用

会话的生命周期

创建 : 创建会话 getSession

变化 :增加属性 setAttribute | 删除属性 removeAttribute

销毁 :销毁会话 Invalidate

迁移 :如果是分布式商用容器(比如weblogic/websphere),会把一台设备上的会话钝化,然后迁移到另一台设备上

更多关于 session 的讨论,参见本人写的另一片文章 《Session 一页纸精华》

5、JSP详解 - java裸编码

jsp本质是由容器转化成Servlet来处理,目的是减少写 html 脚本的工作量。如果使用的是tomcat,可以到work目录下查找对应jsp的class文件

引子- 既然是java代码, 那按照java代码的过程和元素,描述一下 jsp的使用

a、引入 包 -- page 指令

<%@ page import="java.util.*,java.io.*" %> 多个包用逗号分隔

b、定义Servlet类

-- 因为 类是自动生成的,所以这一步是容器生成的,跳过

c、定义域、属性、全局变量 -- 声明

在 _jspService之前执行

<%!

int count = 0;

%>

d、使用表达式片段 - scriptlet

因为所有的jsp最终都翻译成 _jspService 方法调用, 所以一般在 scriptlet中不能定义方法,如果非要定义的话,可以在声明里面定义,因为这部分内容不在方法内

<%

out.println(new Counter().getCount());

%>

表达式 -- 容器会调用表达式返回值(必须有返回值),通过out输出

<%=new Counter().getCount()%>

e、注释

<%-- --%>

最常用的例子,表格取数据迭代

<% for(int i = 0 ; i < 5; i++){ %>

<%=i%>

<% } %>

最终在 html页面中,就可以灵活插入各个java代码执行的片段,把其中的html变成 outputStream的输出

生命周期

创建 : 容器接受请求,翻译成 servlet的源代码,然后加载,实例化,最终变成一个Servlet

处理 : 执行service方法

销毁 : 容器执行 _jspDestroy方法

部署与全局(隐式)参数

部署和Servlet一样,只是Servlet-class 换成了 /testjsp.jsp

同Servlet一样, jsp 也拥有Servlet所有的全局参数, request | session | config | application(对应ServletContext) | out 等等对应Servlet各个部分

6、JSP进阶 - JavaBean + EL表达式

从上面table的例子可以看到,直接Java编程是非常low的事情,逻辑混乱,而且不利于解耦,前端和业务人员无法界定。所以JSP又演进了一步,不写Java的Scriptlet代码

I、使用JavaBean绑定

name:

ID#:

-- 因为JavaBean属性和表单名称

--一致,使用了通配符

II、再加上 EL 表达式

${xxx.xxx} -- 左边是隐式(param,scope,cookie..)对象、map或者bean,右边是属性

${xxx["xxx"} --可以适用于map,数组,或者bean等对象

[] 方式可以嵌套表达式,括号中的内容如果没有使用引号,容器会进行计算,否则会可能成键值等

比如request里面有 map和array两个对象

request.setAttribute("map", map);

request.setAttribute("array", array);

EL:${map[array[0]]}

tag标签 - 可以通过表达式使用 java代码中的静态方法

a、提供java静态方法

b、在WEB-INF中提供 *.tld 文件,标注方法和参数

c、在jsp中引用静态方法

<%@ taglib prefix="mine" uri="DiceFunctions" %> --mine只是一个别名而已

${mine:rollIt()}

可以设置模版值,替换另一个文件的表达式,以达到模板化的目的。

EL表达式和JavaBean绑定只解决了取值问题,虽然动态标记可以解决一些逻辑控制问题,但都是固化的模式,并没有能灵活使用。怎么解决Scriptlet代码在页面中的控制问题?

答案是 JSTL - 具体参加本人博客 《标签模版技术 JSTL 一页纸精华》

7、过滤器

过滤器是和Servlet平级的另一种处理过程,在请求到达处理Servlet之前经过一些列过滤,这里体现了 面向切面的思想,虽然没有采用AOP的技术。

I、典型例子

a、声明过滤器

在web.xml(DD)中定义,定义方法和Servlet类似

FilterA

com.example.web.FilterA

BeerRequest

/ -- 也可以指定servlet SessionTest

REQUEST -- 可以指定拦截的资源类型,REQUEST 客户端请求,INCLUDE通过include调用分派的请求,

FORWARD 通过forward调用分派来的请求,ERROR 错误处理器调用的请求

b、编写过滤器

public class FilterA implements Filter {

public void doFilter(ServletRequest req, ServletResponse resp,

FilterChain chain) throws IOException, ServletException {

处理代码

chain.doFilter(req, resp);

处理代码

}

}

II、生命周期

启动 : init 提供FilterConfig对象

服务 : doFilter()中处理,提供三个对象 ServletRequest/ServletRequest/FilterChain

销毁 : destroy 方法

III、过滤器的概念栈

a、调用第一个过滤器a的doFilter方法,直到 chain.doFilter方法

b、调用第n个过滤器n的doFilter方法,直到 chain.doFilter方法

c、调用真实Servlet的 service 方法,执行完返回

d、容器把控制器返回第n个过滤器的doFilter方法,chain.doFilter之后的内容

e、容器把控制器返回第1个过滤器的doFilter方法,chain.doFilter之后的内容

f、容器完成整个流程响应

这里,有一个最有名的应用,struts2 - 基于过滤器拦截, 进行的流程处理,而没有使用servlet这种经典流程

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

推荐阅读更多精彩内容

  • 这部分主要是与Java Web和Web Service相关的面试题。 96、阐述Servlet和CGI的区别? 答...
    杂货铺老板阅读 1,404评论 0 10
  • 本文包括:1、Filter简介2、Filter是如何实现拦截的?3、Filter开发入门4、Filter的生命周期...
    廖少少阅读 7,272评论 3 56
  • 监听器(listener) 监听器简介 :监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个...
    奋斗的老王阅读 2,507评论 0 53
  • Servlet过滤器是 Servlet 程序的一种特殊用法,主要用来完成一些通用的操作,如编码的过滤、判断用户的登...
    重山杨阅读 1,223评论 0 12
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139