一、JSP基础
1.1什么是JSP
JSP(Java ServerPage)是Java服务器端动态页面技术。是sun公司制订的一种服务器端的动态页面生成技术规范。
1.2为什么要使用JSP
因为直接使用Servlet,虽然也可以生成动态页面。但是,编写繁琐(需要使用out.println来输出),并且维护困难(如果页面发生了改变,需要修改Java代码),所以sun指定了JSP规范。
1.3JSP与Servlet的关系
JSP其实是一个以.jsp为后缀的文件,容器会自动将.jsp文件转换成一个.java文件(其实就是一个Servlet),然后调用该Servlet。所以,从本质上讲,JSP其实就是一个Servlet。
1.4如何写一个JSP文件
step1:创建一个以“.jsp”为后缀的文件。
step2:在该文件里面,可以添加如下的内容:
1)HTML(CSS、JS):直接写即可
2)Java代码:
形式一:Java代码片段:<%Java代码%>
形式二:JSP表达式:<%=Java表达式%>
形式三:JSP声明:<%!%>
3)指令
1.5JSP是如何运行的
step1:容器依据.jsp文件生成.java文件(也就是先转换成一个Servlet):
1)HTML(CSS、JS)放到service方法里,使用out.write输出
2)<%%>也放到service方法里,照搬,不改动。
3)<%=%>也会放到service方法里,使用out.print输出。
4)<%!%>给Servlet添加新的属性或者新的方法(转成.java文件后,声明内的部分添加在service方法之外)。
这样就把一个JSP变成了一个Servlet容器。
注意事项:out.writer方法只能输出简单的字符串,对象是没法输出的。优点是把null自动转换成空字符串输出。如:<%out.println(newDate());%>不能用writer
step2:容器接下来就会调用Servlet来处理请求了(会将之前生成的.java文件进行编译、然后实例化、初始化、调用相应的方法处理请求)
step3:隐含对象
1)所谓隐含对象(共9个),指的是在.jsp文件里面直接可以使用的对象,比如out、request、response、session、application(ServletContext上下文)、exception、pageContext、config、page。
2)之所以能直接使用这些对象,是因为容器会自动添加创建这些对象的代码。(JSP仅仅是个草稿,最终会变为一个Servlet。)
1.6隐含对象
1)exception对象:当jsp页面运行时发生了异常,容器会将异常信息封装到该对象,可以使用该对象提供的方法来输出异常的信息。另外,必须在页面设置isErrorPage="true"指令才能使用该隐含对象。
2)pageContext对象:容器会为每一个JSP实例(JSP所对应的那个Servlet对象)创建唯一的一个符合pageContext接口的对象,称之为page上下文。该对象会一直存在,除非JSP实例被销毁。它作用:①绑定数据(绑定的数据只有对应的JSP实例才可以访问):setAttribute、removeAttribute、getAttribute。②找到其他八个隐含对象(详情看JSP标签)。
3)config对象:即ServletConfig,可以使用该对象获得初始化参数。
4)page对象:JSP实例本身(一般不用)。
1.7指令
1)指令是什么
通知容器,在将.jsp文件转换成.java文件时,作一些额外的处理,比如导包。
2)指令的语法
<%@指令名称属性名=属性值%>
3)page指令
①import属性:导包。
例如:<%@page import="java.util.*"%>
<%@page import="java.util.*,java.text.*"%>
eg:页面显示系统时间
currenttime:<%out.println(newDate());%>
currenttime:<%=newDate()%>
注意事项:两个是等价,newDate()会被放入out.print();里
②contenType属性:设置response.setContentType的内容。
例如:<%@pageimport="java.util.*"contentType="text/html;charset=utf-8"%>
③pageEncoding属性:告诉容器.jsp的文件的编码格式,这样,容器在获取jsp文件的内容(即解码)时,不会出现乱码。最好加入,有些容器默认以ISO-8859-1编码。
例如:<%@pagecontentType="text/html;charset=utf-8" pageEncoding="utf-8"%>
④session属性:true/false,缺省值true,如果值为false,则容器不会添加获得session的语句。
例如:<%@pagesession="false"%>
sessionID:<%=session.getId()%>
⑤isELIgnored属性:true/false,缺省值true,如果值为false,则告诉容器不要忽略el表达式。J2EE5.0需要使用isELIgnored="false",否则EL表达式无效。
⑥isErrorPage属性:true/false,缺省值false,如果值为true,表示这是一个错误处理页面(即专门用来处理其他JSP产生的异常,只有值为true时,才能使用exception隐含对象去获取错误信息)。
例如:<%=exception.getMessage()%>
⑦errorPage属性:设置一个错误处理页面。
例如:step1:a3.jsp页面,测试输入a3.jsp?num=100a
<%@pageerrorPage="a4.jsp"%>
<%String num=request.getParameter("num");
intsum=Integer.parseInt(num)+100;out.println(sum);%> step2:a4.jsp页面
<%@pageisErrorPage="true"pageEncoding="UTF-8"
contentType="text/html;charset=utf-8"%>
<%=exception.getMessage()%>
4)include指令
file属性:①对于页面的公共部分,我们可以使用相同的jsp文件,并使用include指令导入,如此实现代码的优化。②告诉容器,在将.jsp文件转换成.java文件时,在指令所在的位置插入相应的文件的“内容“(由file属性来指定)。插入的页面并未运行,而是机械的将内容插入。
例如:<%@includefile="head.jsp"%>
5)taglib指令
导入JSP标签<%@taglib uri="命名空间"prefix="前缀"%>
①uri:在standard.jar/META-INF/c.tld中查找,详情看2.2
②prefix:前缀,用于代表命名空间。
例如:<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
1.8JSP注释
1):允许注释的内容是Java代码,如果是Java代码,会被容器执行,但是执行的结果会被浏览器忽略(不会显示出来)
2)<%--注释内容--%>:注释的内容不能是Java代码,如果是Java代码,会被容器忽略。
二、JSP标签和EL表达式
2.1什么是JSP标签
sun公司制定的一种技术规范,利用JSP标签(类似于HTML标签)来代替JSP中的Java代码。这样作的好处是,JSP页面会更加简洁,并且更好维护(比如,将这样的页面交给美工,可以很方便地去修改)。
2.2JSTL及其使用
1)什么是JSTL:JavaStandardTaglib(Java标准标签库,apache开发了一套标签,捐献给了sun,sun将其命名为JSTL)。
2)如何使用:
step1:将JSTL标签对应的jar(标签类)文件拷贝到WEB-INF\lib下,standard.jarjstl.jar
step2:使用taglib指令引入JSP标签
2.3什么是EL表达式
是一套简单的计算规则,用于给JSP标签的属性赋值,也可以直接输出。注意事项:新建工程,J2EE选1.4可直接使用EL表达式,JavaEE5.0需要使用isELIgnored属性,否则无法使用!!详见1.7。
2.4EL表达式的使用
1)访问bean的属性(就是普通的Java类,有属性和get/set方法)第一种方式:例如:${user.name},容器会依次从4个隐含对象中pageContext、request、session、application中查找(getAttribute)绑定名为"user"的对象。接下来,会调用该对象的"getName"方法(自动将n变大写然后加get),最后输出执行结果。
优点:①会自动将null转换成""输出。
②如果绑定名称对应的值不存在,会不报null指针异常,会输出""。
注意事项:依次是指先从pageContext中查找,如果找不到,再查找request,如果找到了,则不再向下查找。如果要指定查找范围,可以使用pageScope、requestScope、sessionScope、applicationScope来指定查找的范围。
eg:jsp页面测试
<%Useruser=newUser();user.setName("chang");user.setAge(22);request.setAttribute("user",user);Useruser2=newUser();user2.setName("bo"); user2.setAge(22);session.setAttribute("user",user2);%>
name:<%Useruser=(User)request.getAttribute("user");out.println(user.getName());%>
name:${user.name}
name:${sessionScope.user.name}
第二种方式:比如${user["name"]},与第一种方式是等价的!容器会依次从4个隐含对象中pageContext、request、session、application中查找(getAttribute)绑定名为"user"的对象。接下来,会调用该对象的"getName"方法(自动将n变大写然后加get),最后输出执行结果。
优点:①中括号[]里面可以出现变量。②中括号[]里面可以出现下标从0开始的数组。
注意事项:
中括号[]里的字符串用双引号、单引号都可以!
EL表达式中没引号的为变量,有引号的为字符串。
eg:jsp页面测试
step1:User类
privateString name;privateintage;privateString[]interest;privateIdCardcard;……get/set方法
step2:IdCard类
privateStringcardNo;……get/set方法
step3:jsp页面
<%Useruser=newUser();user.setName("chang");user.setAge(22); user.setInterest(newString[]{"台球","乒乓球"});
user.setCard(newIdCard("1008611"));request.setAttribute("user",user);%>name:${user["name"]}
<%request.setAttribute("propname","age");%> name:${user[propname]}
interest:${user.interest}
interest:${user.interest[1]}
IdCard:${user.card.cardNo}
2)进行一些简单的计算,计算的结果可以用来给JSP标签的属性赋值,也可以直接输出。
①算术运算:“+”、“-”、“*”、“/”、“%”
注意事项:"+"号操作不能连接字符串。如"abc"+"bcd"会报错!
"100"+"200"=${"100"+"200"}可以!
②关系运算:“>”、“>=”、“<”、“<=”、“!=”、"=="
注意事项:“eq”也可判断是否相等
eg:相关测试
1>0?${1>0}
<%request.setAttribute("str1","abc");request.setAttribute("str2","bcd");%>
${str1==str2}
${str1=="abc"}
eq:${str1eq"abc"}
${sessionScope.str1=="abc"}
③逻辑运算:"&&"、"||"、"!",与Java中的一样
④empty运算:判断是否是一个空字符串,或者是一个空的集合,如果是,返回true。以下四种情况都是true:A.空字符串。B.空集合。C.null。D.根据绑定名找不到值。
eg:相关测试
<%request.setAttribute("str3","");%>
空字符串:${emptystr3}
<%Listlist1=newArrayList();//list1.add("abc");//falserequest.setAttribute("list1",list1);%>
空集合:${emptylist1}
<%request.setAttribute("obj",null);%> null:${emptyobj}
找不到值:${emptyabc}
3)获取请求参数值
①${param.username}等价于request.getParameter("username");
②${paramValues.city}等价于request.getParameterValues("city");eg:相关测试a6.jsp页面
username:${param.username}
interest:${paramValues.interest[0]}
三、JSTL中的几个核心标签
3.1if
1)语法:当test属性值为true,执行标签体的内容,test属性可以使用EL表达式。
2)var属性:用来指定绑定名称。
3)scope属性:指定绑定范围,可以是page(pageContext)、request、session、
application
注意事项:可以在if标签里写Java代码。
3.2choose
1)语法:
注意事项:
when和otherwise必须要放到choose标签里面才能使用。
when可以出现1次或者多次,otherwise可以出现0次或者1次,表例外。
eg:相关测试
<%
Person p = new Person();
p.setAttribute("p",p);
%>
性别:
3.3forEach
1)语法:
用法一(遍历集合):
①items属性:用来指定要遍历的集合,可以使用EL表达式。
②var属性:指定绑定名,绑定范围是pageContext,绑定值是从集合中取出的某个元素。
③carStatus属性:指定绑定名,绑定范围是pageContext,绑定值是一个由容器创建的一个对象,该对象封装了当前迭代的状态。比如,该对象提供了getIndex、getCount方法,其中,getIndex会返回当前迭代的元素的下标(从0开始),getCount会返回当前迭代的次数(从1开始)。
用法二(指定位置迭代):
①begin:如果指定了items,那么迭代就从items[begin]开始进行迭代;如果没有指定items,那么就从begin开始迭代。它的类型为整数。
②end:如果指定了items,那么就在items[end]结束迭代;如果没有指定items,那么就在end结束迭代。它的类型也为整数。
注意事项:forEach还一个属性为step="":迭代的步长。
3.4url
1)语法:
①当用户禁止cookie以后,会自动在地址后面添加sessionId。
②当使用绝对路径时,会自动在地址前添加应用名。
2)value属性:指定地址,在表单提交、链接当中,可以使用该标签。
3.5set
1)语法:
2)value属性:绑定值。
3.6remove
1)语法:
3.7catch
1)语法:
3.8import
1)语法:
2)url属性:指定一个jsp文件的地址,jsp会在运行时调用这个jsp。
3.9redirect
1)语法:< c:redirect url=" ">,重定向到另外一个地址。
2)url属性:指定重定向的地址。
3.10 out
1)语法:
2)value属性:指定输出的值。
3)default属性:指定缺省值。
4)escapeXml属性:设置成true,会将value中的特殊字符替换成相应的实体。缺省值就是true。
3.11JSP标签是如何运行的
容器依据命名空间找到标签的描述文件(.tld文件),接下来,依据标签的名称找到标签类的类名,然后将该标签实例化,最后,调用标签实例的相应的方法。
注意事项:容器会从WEB-INF下查找,如果找不到,还会查找WEB-INF\lib下的
jar文件。
3.12案例:将员工列表中的Java代码改为JSP标签,并添加分页
step1:删除该页上所有Java代码,并修改如下
step2:JSP页面添加分页
step3:修改ActionServlet中service方法中的if语句
四、自定义标签
4.1如何写一个自定义标签
step1:写一个Java类(标签类),且必须继承SimpleTagSupport类。
step2:在doTag方法里面(覆盖doTag方法),编写相应的处理逻辑。标签有哪些属性,则标签类也有哪些属性,并且类型要匹配。此外,这些属性必须提供相应的set方法
step3:在.tld文件当中,描述该标签。.tld文件可以放在WEB-INF下(或它的子文件夹下),也可以放到META-INF下,可以参考c.tld文件来写。
注意事项:
简单标签技术是新技术,新的规范。
1)empty:没有标签体。2)scriptless:可以有标签体,但是标签体里面不能够出现Java代码(三种形式都不行!)。3)JSP:有标签体,并且标签体的内容可以是Java代码。只有复杂标签技术支持JSP。简单标签技术只支持empty和scriptless。
4.2JavaEE5.0中,如何使用EL表达式和JSTL
在JavaEE5.0以上版本中,已经将JSTL标签库对应的jar文件包含进来了,不用再去将
那两个jar文件拷贝到WEB-INF\lib下了。
4.3案例:自定义标签
4.4案例:修改之前员工列表中的日期显示
step1:JSP页面
五、MVC
5.1什么是MVC
ModelViewController,是一种软件架构的思想,将一个软件的模块划分成三种不同类型的模块,分别是模型(封装业务逻辑)、视图(实现表示逻辑)、控制器(协调模型和视图,即模型返回的结果要先交给控制器,由控制器来选择合适的视图来展示处理结果;另外,视图发送请求给控制器,由控制器来选择对应的模型来处理。)
5.2使用MVC的目的
使用MVC思想来设计软件,最根本的目的是为了实现模型的复用:即模型只返回处理结果,并不关心这些结果如何展现,展现由不同的视图来处理;另外可以使用不同的视图来调用同一个模型。
5.3如何使用MVC来开发一个Web应用程序(JavaEE)
使用Java类来实现模型(将业务逻辑写在Java类里面,写完之后可以立即测试),使用
Servlet或者Filter来实现控制器,使用JSP来实现视图。
注意事项:
一般模型产生应用异常(即不是系统的原因产生的异常,而是用户使用不当造成的,需要提示用户采取正确的操作)时,抛自定义异常给控制器(自定义异常可自己写个最简单的类,但是,当有许多应用异常时可采用异常编号方式),控制器再返回结果给视图。
对于客户端,WEB-INF下的文件都是受保护的,不能直接访问!只有服务器之间的组件可以访问。某个结果页面不想被用户访问,可以设置主页,然后使用ActionServlet采取转发方式。
5.4MVC的优缺点
1)优点:①可以实现模型的复用。②模型或者视图发生改变,不会相互影响。③方便测试(比如,将业务逻辑写在Java类里面,可以直接测试,如果写在Servlet里面,必须要先部署才能测试)。
2)缺点:使用MVC后,①会增加设计的难度。②代码量也会增加。③相应地也会增加软件的开发成本。
5.5案例:简易贷款(贷款数小于余额数*10)
JSP九大内置对象:request、response、session、application、out、pagecontext、config、page、exception
1.request对象
request对象是javax.servlet.httpServletRequest类型的对象。该对象代表了客户端的请求信息,主要用于接受通过http协议传送到服务器的数据(包括信息、系统信息、请求方式以及请求参数等)
2.response对象
response代表的是对客户端的响应,主要是讲JSP容器处理过得对象传回到客户端。reswponse对象也具有作用域,它只在JSP页面内有效
3.session对象
session对象是由服务器自动创建的与用户请求相关的对象,服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用MAP类来保存数据,因此保存数据的格式是“key/value”.session对象的value可以是复杂的对象类型,而不仅仅局限于字符串类型
4.application对象
application对象可以将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,spplication对象生命周期更长,类似于系统的“全局变量”
5.out对象
out对象用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓冲区。在使用out对象输出数据时,可以对数据缓冲区进行操作,及时清除缓冲区中的残余数据,为其他的输出让出缓冲空间。待数据输出完毕之后,要及时关闭输出流。
6.pageContext对象
pageContext对象的作用是去的任何范围的参数,通过它可以获取JSP页面的out、request、response、session、application等对象。pageContext对象的创建和初始化都是由容器来完成的,在JSP页面中可以直接使用pageContext对象
7.config对象
config对象的主要作用是取得服务器的配置信息,通过pagecontext对象的getServletConfig()方法可以获取一个config对象。当一个Servlet初始化时,容器把某些信息通过config对象传递给这个Servlet。开发者可以在web.xml文件之中为应用程序环境中的Servlet程序和JSP页面提供初始化参数
8.page对象
page对象代表jsp本身,只有在JSP页面内才是合法的。page隐含对象本质上包含当前servlet接口引用的变量,类似于java编程肿的this指针
9.exception对象
exception对象的作用是显示异常信息,只有包含isErrorPage="true"的页面才可以被使用,在一般的jsp页面中使用该对象将无法编译jsp文件。exception对象和java的所有对象一样,都具有系统提供的继承结构。exception对象几乎定义了所有异常情况。在java程序中,可以使用try/catch关键字来处理异常情况;如果在jsp页面中出现没有捕获到的异常,就会生成exception对象,并且把exception对象传送到在page指令中设定的错误页面中,然后在错误页面中处理相应的exception对象
总结:
request 请求对象 类型 javax.servlet.ServletRequest 作用域 Request
response 响应对象 类型 javax.servlet.SrvletResponse 作用域 Page
pageContext 页面上下文对象 类型 javax.servlet.jsp.PageContext 作用域 Page
session 会话对象 类型 javax.servlet.http.HttpSession 作用域 Session
application 应用程序对象 类型 javax.servlet.ServletContext 作用域 Application
out 输出对象 类型 javax.servlet.jsp.JspWriter 作用域 Page
config 配置对象 类型 javax.servlet.ServletConfig 作用域 Page
page 页面对象 类型 javax.lang.Object 作用域 Page
exception 例外对象 类型 javax.lang.Throwable 作用域 page
“exception” 对象则代表了JSP文件运行时所产生的例外对象,此对象不能在一般JSP文件中直接使用,而只能在使用了“<%@ page isErrorPage="true "%>”的JSP文件中使用。
何为作用域
先让我们看看效果:
大概流程是这样的,我们访问index.jsp的时候,分别对pageContext, request, session,application四个作用域中的变量进行累加。(当然先判断这个变量是不是存在,如果变量不存在,则要把变量初始化成1)。计算完成后就从index.jsp执行forward跳转到test.jsp。在test.jsp里再进行一次累加,然后显示出这四个整数来。
从显示的结果来看,我们可以直观的得出结论:
page里的变量没法从index.jsp传递到test.jsp。只要页面跳转了,它们就不见了。
request里的变量可以跨越forward前后的两页。但是只要刷新页面,它们就重新计算了。
session和application里的变量一直在累加,开始还看不出区别,只要关闭浏览器,再次重启浏览器访问这页,session里的变量就重新计算了。
application里的变量一直在累加,除非你重启tomcat,否则它会一直变大。
作用域规定的是变量的有效期限
如果把变量放到pageContext里,就说明它的作用域是page,它的有效范围只在当前jsp页面里。
从把变量放到pageContext开始,到jsp页面结束,你都可以使用这个变量。
如果把变量放到request里,就说明它的作用域是request,它的有效范围是当前请求周期。
所谓请求周期,就是指从http请求发起,到服务器处理结束,返回响应的整个过程。在这个过程中可能使用forward的方式跳转了多个jsp页面,在这些页面里你都可以使用这个变量。
如果把变量放到session里,就说明它的作用域是session,它的有效范围是当前会话。
所谓当前会话,就是指从用户打开浏览器开始,到用户关闭浏览器这中间的过程。这个过程可能包含多个请求响应。也就是说,只要用户不关浏览器,服务器就有办法知道这些请求是一个人发起的,整个过程被称为一个会话(session),而放到会话中的变量,就可以在当前会话的所有请求里使用。
如果把变量放到application里,就说明它的作用域是application,它的有效范围是整个应用。
整个应用是指从应用启动,到应用结束。我们没有说“从服务器启动,到服务器关闭”,是因为一个服务器可能部署多个应用,当然你关闭了服务器,就会把上面所有的应用都关闭了。
application作用域里的变量,它们的存活时间是最长的,如果不进行手工删除,它们就一直可以使用。
与上述三个不同的是,application里的变量可以被所有用户共用。如果用户甲的操作修改了application中的变量,用户乙访问时得到的是修改后的值。这在其他scope中都是不会发生的,page, request,session都是完全隔离的,无论如何修改都不会影响其他人的数据。