JSP组成
JSP技术是以Java语言作为脚本语言的,JSP网页为整个服务器端的Java库单元提供了一个接口来服务于HTTP的应用程序。
指令
page
页面指令用来定义jsp文件中的全局变量,一个pagepage可以包含多个页面指令。
如:
<%@ page
定义要使用的脚本语言:[language="java"]
需要引入的包:[import="java.util.Date, java.util.ArrayList"]
JSP字符编码,页面响应类型:[contentType="text/html";charset=CHARSET]
指定一个Http回话,该页面是否参与:[session="true|false"]
指定到客户输出缓冲流模式:[buffer="none|8kb|otherBuffSize"]
缓冲区满时,是否刷新:[autoFlush="true|false"]
是否能够多线程:[isThreadSafe="true|false"]
关于jsp页面信息:[info='text']
当前页是否可为其他页面错误讯息页:[isErrorPage="true|false"]
该页面错误时使用的错误信息页:[errorPage="relativeURL"]
指定servlet从哪一个类继承: [extends="package.class"]
制定EL是否被忽略:[isELIgnored="true|false"]
页面字符编码:[pageEncoding="peinfo"]
%>
- import=“导包列表”,可以多次导入,也可以用逗号分隔开。
- language=“scriptingLangeuage”,指定在脚本元素使用的脚本语言,默认是Java。
- contentType=“cinfo”,指定HTTP响应的头部的Content-Type值。客户端的浏览器会根据我们在contentType中指定的MIME类型和字符集代码来显示Servlet输出的内容。
include
<%@ include file="jspfilename" %>
该包含为静态包含,该页面包含file2,则将file2的代码插入至指定位置作为一个jspfile,然后再编译。两个文件中变量会复用。
taglib
taglib 指令是定义一个标签库以及其自定义标签的前缀。
prefix 是一个标签库别名
导入标签库
自定义方式
- 首先需要导入standard.jar jsp-api.jar 两个包 。
- 在web.xml中注册标签库
<jsp-config> <taglib> <taglib-uri>myjstl</taglib-uri> <taglib-location>/WEB-INF/tld/c.tld</taglib-location> </taglib> </jsp-config>
- 在jsp页面中中导入
<%@ taglib uri="" prefix="c"%>
标准定义方式
- 打开tid文件,找到文件头部的uri节点。
- 直接在jsp中的taglib指令中使用tid文件中的uri。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> ...... <c:forEach var="l" items="${list}">
脚本
<% %> ,jsp页面处理请求时执行的代码。
声明
<%! %> ,声明是一段java代码,可以用来定义类或方法。
表达式
SCRIPLETS <%= SOME JAVA EXPRESSION %> ,可以产生输出。
注释
- html注释
<!-- 注释 -->
- JSP注释
<%-- 注释 --%>
- 脚本注释
//注释 /* 注释 */
JSP动作元素
<jsp:action> </jsp:action>
param
<jsp:param name="paramName" value="paramValue"/>
jsp:param操作被用来以“名-值”对的形式为其他标签提供附加信息,通常与jsp:include jsp:forward jsp:plugin组合使用。
include
<jsp:include page="fiilename" flush="true"/>
jsp:include操作允许在请求时间内,让现成的jsp页面中包含静态或动态资源。被包含的对象只有对jsp writer对象的访问权,并且不能设置头或cookie。如果页面输出是缓冲的,那么缓冲区的刷新要优于包含的刷新。
forward
<jsp:forward page="filename"/>
将请求转发到另一个页面。
setProperty
setProperty动作用于设置useBean中指定的Bean的属性的值。setProperty动作指定名称、属性、值和参数,用于赋给Bean的属性。
getProperty
etProperty动作用于获取Bean中指定的属性中的值,系统先将收到的值转换成字符串,然后再将其作为输出结果发送。
userBean
JavaBean与其它Java类相比而言有独一无二的特征:
- 提供一个默认的无参构造函数。
- 需要被序列化并且实现了Serializable接口。
- 可能有一系列可读写属性。
- 可能有一系列的"getter"或"setter"方法。
<jsp:useBean id="id" scope="page|request|session|application" typeSpec> <jsp:useBean id="user" scope="page" class="com.servlet.test.TestBean" /> 此句实例化出一个名为user的TestBean对象
属性
- id: 一个大小写相关的名字,在所定义的范围中确认Bean的变量
- page:能够在包含jsp:useBean标签的JSP文件以及此文件中的所有静态包含文件使用Bean
- request:在请求范围内使用有效 request.getAttribute(name) name是bean实例化的名字
- scope: 此对象可使用的范围
- session.getValues(name) name是bean实例化的名字
- session:从创建Bean开始,就可以在session有效范围内使用这个Bean,这个Bean对JSP来说是共享的。
- application:从创建Bean开始,就可以在aplication有效范围内使用这个Bean,这个Bean对JSP来说是共享的。
- application对象在应用服务器启动时创建,直至服务器关闭。
- application.getAttribute(name) name是bean实例化的名字
- typeSpec
- class=“className” bean的类路径和类名,这个class不能是抽象的。必须有一个公用的无参构造器。
- type="typeName"type 表示这个对象声的类型
<jsp:useBean id="test" class="p.Apple" type="p.Fruit"/> 按这么写 就相当于 Fruit test = new Apple(); <jsp:useBean id="test" class="p.Apple" /> 相当于 Apple test = new Apple();
示例
创建JavaBean对象及属性
<jsp:useBean id="id" class="bean 编译的类" scope="bean 作用域">
<jsp:setProperty name="bean 的 id" property="属性名" value="value"/>
...........
</jsp:useBean>
name属性指的是Bean的id属性。property属性指的是想要调用的getter或setter方法。
访问JavaBean对象的属性
<p>
学生名字: <jsp:getProperty name="students" property="firstName"/>
</p>
plugin
plugin用于连接客户端的Applet和Bean插件。plugin动作为Web开发人员提供了一种在JSP文件中嵌入客户端运行的Java程序(如Applet、JavaBean)的方法。在处理这个动作的时候,根据客户端浏览器的不同,JSP在执行以后将分别输出为OBJECT或MEBED这两个不同的HTML元素。
ER表达式
EL主要的语法结构:**
s
e
s
s
i
o
n
S
c
o
p
e
.
u
s
e
r
.
s
e
x
∗
∗
所
有
E
L
都
是
以
{sessionScope.user.sex}** 所有EL都是以
sessionScope.user.sex∗∗所有EL都是以{为起始、以}为结尾的。上述EL范例的意思是:从Session的范围中,取得
用户的性别。假若依照之前JSP Scriptlet的写法如下:
User user =(User)session.getAttribute("user");
String sex =user.getSex( );
jstl常用标签
------------------------ c:set ------------------------
<c:set var="i" value="10" scope="page"></c:set>
------------------------ c:out ------------------------
<c:out value="${user}"></c:out>
<c:out value="${sessionScope.user}"></c:out>
---------------------- c:forEach ----------------------
<c:forEach items="${list}" var="s">
<p><c:out value="${s}"></c:out></p>
</c:forEach>
<c:forEach var="j" begin="0" end="2" step="1">
<p><c:out value="${list[j]}"></c:out></p>
</c:forEach>
------------------------ c:if ------------------------
<c:if test="${1>0}">
<p>yes</p>
</c:if>
其他相关
include指令与jsp:include动作的区别:
include指令通过file属性来指定被包含的页面。jsp:include动作通过page属性来指定被包含的页面。
使用include指令,被包含的文件被原封不动的插入到包含页面中使用该指令的位置,然后JSP编译器再对这个合成的文件进行编译,所以在一个JSP页面中使用include指令来包含另一个JSP页面,最终编译后的文件只有一个。(静态包含)
使用jsp:include动作包含文件时,当该动作标识执行后,JSP程序会将请求转发到(注意不是重定向)被包含页面,并将执行结果输出到浏览器中,然后返回页面继续执 行后面的代码,以为web容器执行的两个文件,所以JSP编译器会分别对这两个文件进行编译。(动态包含)。
Servlet三大组件
关于Servlet
重定向和转发
1. 转发
客户首先发送一个请求到服务器端,服务器端发现匹配的servlet,并指定它去执行,当这个servlet执行完之后,它要调用getRequestDispacther()方法,把请求转发给指定的jsp,整个流程都是在服务器端完成的,而且是在同一个请求里面完成的,因此servlet和jsp共享的是同一个request,在servlet里面放的所有东西,在jsp中都能取出来,jsp执行完把结果返回给客户端。整个过程是一个请求,一个响应。
2. 重定向
客户发送一个请求到服务器,服务器匹配servlet,这都和请求转发一样,servlet处理完之后调用了sendRedirect()这个方法,这个方法是response的方法,所以,当这个servlet处理完之后,看到response.senRedirect()方法,立即向客户端返回这个响应,响应行告诉客户端你必须要再发送一个请求,去访问jsp,紧接着客户端受到这个请求后,立刻发出一个新的请求,去请求jsp,这里两个请求互不干扰,相互独立,在前面request里面setAttribute()的任何东西,在后面的request里面都获得不了。可见,在sendRedirect()里面是两个请求,两个响应。
3. 重点
重定向是客户端行为,也就注定可以向任何地址发送请求,客户端行为的改变是服务器所给的指示,亦即是response的行为返回,就像一个人不能两次同时踏进一个河流一样,每次请求都是新的行为,request不保留上次的内容。
两者最大区别是:运用forward方法只能重定向到同一个Web应用程序中的一个资源。而sendRedirect方法可以让你重定向到任何 。
form表单填写注意事项
- 填写路径时,若填写全路径,必须加上http协议。
- 填写相对路径时,/XXX 中的/表示服务器地址。
@WebServlet的使用方法
@WebServlet("/hello.view")
public class HelloServlet extends HttpServlet {...}
只要在Servlet上设置@WebServlet标注,容器就会自动读取当中的信息。上面的@WebServlet告诉容器,如果请求的URL是"/hello.view",则由HelloServlet的实例提供服务。例如:
@WebServlet(
name="helloUser2",
urlPatterns={"/getUser","/userInfo"},
loadOnStartup=1)
@WebServlet属性表
在servlet3.0以后,我们可以不用再web.xml里面配置servlet,只需要加上@WebServlet注解就可以修改该servlet的属性了。
属性 | 值类型 | 作用 |
---|---|---|
name | String | 指定Servlet 的 name 属性,等价于 。如果没有显式指定,则该 Servlet 的取值即为类的全限定名。 |
value | String[] | 该属性等价于 urlPatterns 属性。两个属性不能同时使用。 |
urlPatterns | String[] | 指定一组 Servlet 的 URL 匹配模式。等价于标签。 |
loadOnstartup | int | 指定 Servlet 的加载顺序,等价于 标签。 |
asyncSupported | boolean | 声明 Servlet 是否支持异步操作模式,等价于 标签。 |
description | String | 该 Servlet 的描述信息,等价于 标签。 |
displayName | String | 该 Servlet 的显示名,通常配合工具使用,等价于 标签。 |
web.xml可以配置的servlet属性,在@WebServlet中都可以配置。
eclipse中webContent目录理解
- webContent/webRoot:用来存放JSP、JS、CSS、图片等资源文件。
- webRoot/WEB-INF:用来存放SRC编译好的和需要被保护的JSP文件,web-inf是java web的安全目录,只有服务端可以访问,如果要在客户端访问,必须在web.xml文件中对要访问的文件进行映射配置。
- class文件,存放编译过的java程序。
- web.xml是网站部署描述文件。
java servlet执行流程
-
浏览器请求:浏览器向服务器请求时,服务器不会直接执行我们的类,而是到web.xml里寻找路径名
- 第一步,浏览器输入访问路径后,携带了请求行,头,体
- 第二步,根据访问路径找到已注册的servlet名称,既图中的demo
- 第三步,根据映射找到对应的servlet名
- 第四步,根据根据servlet名找到我们全限定类名,既我们自己写的类
-
服务器创建对象
- 服务器找到全限定类名后,通过反射创建对象,同时也创建了servletConfig,里面存放了一些初始化信息(注意服务器只会创建一次servlet对象,所以servletConfig也只有一个)
-
调用init方法
- 对象创建好之后,首先要执行init方法,但是我们发现我们自定义类下没有init方法,所以程序会到其父类HttpServlet里找
- 我们发现HttpServlet里也没有init方法,所以继续向上找,既向其父类GenericServlet中继续寻找,在GenericServlet中我们发现了init方法,则执行init方法(对接口Servlet中的init方法进行了重写)
注意: 在GenericServlet中执行public void init(ServletConfig config)方法的时候,又调用了自己无参无方法体的init()方法,其目的是为了方便开发者,如果开发者在初始化的过程中需要实现一些功能,可以重写此方法
-
调用service方法:
接着,服务器会先创建两个对象:ServletRequest请求对象和ServletResponse响应对象,用来封装浏览器的请求数据和封装向浏览器的响应数据- 接着服务器会默认在我们写的类里寻找service(ServletRequest req, ServletResponse res)方法,但是DemoServlet中不存在,那么会到其父类中寻找
- 到父类HttpServlet中发现有此方法,则直接调用此方法,并将之前创建好的两个对象传入
- 然后将传入的两个参数强转,并调用HttpServlet下的另外个service方法
- 接着执行service(HttpServletRequest req, HttpServletResponse resp)方法,在此方法内部进行了判断请求方式,并执行doGet和doPost,但是doGet和doPost方法已经被我们自己重写了,所以会执行我们重写的方法
看到这里,你或许有疑问:为什么我们不直接重写service方法?
因为如果重写service方法的话,我们需要将强转,以及一系列的安全保护判断重新写一遍,会存在安全隐患。
4、向浏览器响应
其他问题
遍历request
Map<String, String[]> map = request.getParameterMap();
for(Map.Entry<String, String[]> e: map.entrySet()){
System.out.format("key: %s, value: ", e.getKey());
for(String s: e.getValue()){
System.out.format("%s, ", s);
}
System.out.println("");
}
Servlet与浏览器之间的乱码解决
//设置从request中读入的编码
request.setCharacterEncoding("utf-8");
//设置返回到浏览器的编码
response.setCharacterEncoding("utf-8");
//告诉浏览器用utf-8格式解码
response.setHeader("Content-type", "text/html; charset=utf-8");
servlet中的路径区别
区域 | 路径区别 |
---|---|
重定向 | ‘/’ 代表 服务器路径,若定向至外部网址,则需加上协议号 |
转发 | ‘/’ 代表 项目根目录 |
cookie.setPath( ) | ‘/’ 代表 服务器路径(其中/*无法匹配) |
web.xml | ‘/’ 代表 项目根目录 |
关于Filter
Filter,过滤器,顾名思义,即是对数据等的过滤,预处理过程。
定义
过滤作用,对从客户端向服务器端发送的请求进行过滤,也可以对服务器端返回的响应进行处理。它使用户可以改变一个request和修改一个response。Filter不是一个servlet,它不能产生一个response,但是它能够在一个request到达servlet之前预处理request,也可以在 response离开servlet时处理response。换句话说,filter其实是客户端与servlet中间的一个传递者,并且它可以对要传递 的东西进行修改,而servlet是用来处理请求并产生响应的。
filter四种拦截方式
- REQUEST:直接访问目标资源时执行过滤器。包括:在地址栏中直接访问、表单提交、超链接、重定向,只要在地址栏中可以看到目标资源的路径,就是REQUEST;
- FORWARD:转发访问执行过滤器。包括RequestDispatcher#forward()方法、< jsp:forward>标签都是转发访问;
- INCLUDE:包含访问执行过滤器。包括RequestDispatcher#include()方法、< jsp:include>标签都是包含访问;
- ERROR:当目标资源在web.xml中配置为< error-page>中时,并且真的出现了异常,转发到目标资源时,会执行过滤器。
如:
<filter-mapping>
<filter-name>myfilter</filter-name>
<url-pattern>/test.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>......</dispatcher>
</filter-mapping>
过滤器如何实现拦截
- 当客户端发生请求后,在HttpServletRequest 到达Servlet 之前,过滤器拦截客户的HttpServletRequest。
- 根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。
- 在过滤器中调用doFilter方法,对请求放行。请求到达Servlet后,对请求进行处理并产生HttpServletResponse发送给客户端。
- 在HttpServletResponse 到达客户端之前,过滤器拦截HttpServletResponse。
- 根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。
- 最后,HttpServletResponse到达客户端。
适用场合
实现URL级别的权限访问控制,过滤敏感词汇,压缩响应信息等。
Filter接口
Servlet API提供了一个Filter接口,编写的过滤器必须实现该接口。
Filter的生命周期
- Filter接口中有三个重要的方法:
*init()*方法:初始化参数,在创建Filter时自动调用。当我们需要设置初始化参数的时候,可以写到该方法中。
*doFilter()*方法:拦截到要执行的请求时,doFilter就会执行。这里面写我们对请求和响应的预处理。
*destroy()*方法:在销毁Filter时自动调用。 - Filter的生命周期:
Filter的创建和销毁由web服务器控制:
服务器启动的时候,web服务器创建Filter的实例对象,并调用其init方法,完成对象的初始化功能。filter对象只会创建一次,init方法也只会执行一次。
拦截到请求时,执行doFilter方法。可以执行多次。
服务器关闭时,web服务器销毁Filter的实例对象。
Filter对象**——FilterConfig
用户在配置filter时,可以使用为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过 filterConfig对象的方法,就可获得:
String getFilterName() //得到filter的名称。
String getInitParameter(String name) //返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
Enumeration getInitParameterNames() //返回过滤器的所有初始化参数的名字的枚举集合。
public ServletContext getServletContext() //返回Servlet上下文对象的引用。
过滤器链——FilterChain
一组过滤器对某些web资源进行拦截,那么这组过滤器就称为过滤器链。过滤器的执行顺序和有关(谁在前先执行谁)。
关于Listener
Listener就是监听器,我们在JavaSE开发或者Android开发时,经常会给按钮加监听器,当点击这个按钮就会触发监听事件,调用onClick方法,本质是方法回调。在JavaWeb的Listener也是这么个原理,但是它监听的内容不同,它可以监听Application、Session、Request对象,当这些对象发生变化就会调用对应的监听方法。
八大监听器
JavaWeb中的八大监听器,三大域对象各有一个生命周期监听器和属性操作监听器,共计6个,还有2个与HttpSession相关的感知型监听器。
ServletContextListener
Servlet的上下文监听,它主要实现监听ServletContext的创建和删除。该接口提供了两种方法
contextInitialized(ServletContextEvent event); 通知正在收听的对象,应用程序已经被加载和初始化。
contextDestroyed(ServletCotextEvent event); 通知正在收听的对象,应用程序已经被载出,即关闭。
ServletAttributeListener
主要实现监听ServletContext属性的增加,删除和修改。该接口提供了以下3个方法
1.attributeAdded(ServletContextAttributeEvent event); 当有对象加入Application的范围时,通知正在收听的对象
2.attributeReplaced(ServletContextAttributeEvent event); 当在application的范围有对象取代另一个对象的时,通知正在收听的对象
3.attributeRemoved(ServletContextAttributeEvent event); 当有对象从application的范围移除时,通知正在收听的对象
HttpSessionListener
HTTP会话监听,该接口实现监听HTTP会话创建、销毁。该接口提供了以下两种方法
1.sessionCreated(HttpSessionEvent event); 通知正在收听的对象,session已经被加载及初始化
2. sessionDestoryed(HttpSessionEvent event) 通知正在收听的对象,session已经被载出(HttpSessionEvent类的主要方法是getSession(),可以使用该方法回传一个session对象)
HttpSessionActivationListener
该接口实现监听HTTP会话active和passivate。 该接口提供了以下3个方法
1.attributeAdded(HttpSessionBindingEvent event);当有对象加入session的范围时,通知正在收听的对象
2.attributeReplaced(HttpSessionBindingEvent event)当在session的范围有对象取代另一个对象时,通知正在收听的对象。
3.attributeRemoved(HttpSessionBindingEvent event); 当有对象从session的范围有对象取代另一个对象时,通知正在收听的对象
其中HttpSessionBindingEvent类主要有三个方法:getName()、getSession()和getValue()
HttpSessionBindingListener
接口实现监听HTTP会话中对象的绑定信息。它是唯一不需要在web.xml中设定Listener的。该接口提供了以下2个方法
1.valueBound(HttpSessionBindingEvent event); 当有对象加入session的范围时会被自动调用
2.valueUnBound(HttpSessionBindingEvent event); 当有对象从session的范围内移除时会被自动调用
HttpSessionAttributeListener
该接口实现监听HTTP会话中属性的设置请求。该接口提供了以下两个方法。
1.sessionDidActivate(HttpSessionEvent event); 通知正在收听的对象,它的session已经变为有效状态。
2.sessionWillPassivate(HttpSessionEvent event); 通知正在收听的对象,它的session已经变为无效状态
ServletRequestListener
该接口提供了以下两个方法。
1.requestInitalized(ServletRequestEvent event); 通知正在收听的对象,ServletRequest已经被加载及初始化
2.requestDestroyed(ServletRequestEvent event); 通知正在收听的对象,ServletRequest已经被载出,即关闭
ServletRequestAttributeListener
该接口提供了以下三种方法。
1.attributeAdded(ServletRequestAttributeEvent event); 当有对象加入request的范围时,通知正在收听的对象
2.attributeReplaced(ServletRequestAttributeEvent event); 当在request的范围内有对象取代两一个对象时,通知正在收听的对象
3.attributeRemoved(ServletRequestAttributeEvent event); 当有对象从request的范围移除时,通知正在收听的对象
MVC编程模式:Model View Controller 模型-视图-控制器
模型(Model)
用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“ Model ”有对数据直接访问的权力,例如对数据库的访问。“Model”不依赖“View”和“Controller”,也就是说, Model 不关心它会被如何显示或是如何被操作。但是 Model 中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此 Model 的 View 必须事先在此 Model 上注册,从而,View 可以了解在数据 Model 上发生的改变。
视图(View)
能够实现数据有目的的显示(理论上,这不是必需的)。在 View 中一般没有程序上的逻辑。为了实现 View 上的刷新功能,View 需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。
控制器(Controller)
起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据 Model 上的改变。