JSP(Java Servlet Pages)是一个简化的Servlet设计,实现了在服务器端Java中使用HTML标签显示动态网页技术,也是一个JavaEE标准。与PHP相比,JSP具有更好的跨平台性、安全性,适用于开发大型的企业级Web应用程序。
1、JSP页面组成元素
JSP页面由六个元素构成:静态内容、指令、表达式、小脚本、声明和注释
指令
jsp指令包裹在<%@ %>之间。其中page指令常位于jsp页面的顶端,用于对页面的编码等进行指定,如下所示定义页面编码方式为UTF-8,脚本语言为Java,并且导入java.util类下的包
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" %>
include指令用于将一个外部文件嵌入到当前jsp页面中并完成页面jsp语句的解析
taglib指令可以自定义标签并在页面中使用
注释
在jsp中可以使用三种注释:HTML注释、JSP注释和Java注释,只有html注释在客户端的源码中可以看到
<!-- html注释,在客户端源码中能看到 -->
<%-- JSP注释,在客户端不可见--%>
<%
//java单行注释
/*Java多行注释*/
%>
声明
包裹在<%! %>之间,用于定义页面中使用的变量或方法,
<%!
String s = "你好,欢迎使用JSP!"; //定义字符串
int add(int x, int y) { //定义一个相加函数
return x + y;
}
%>
脚本
包裹在<% %>之间,用于在jsp页面执行Java代码
<%
out.println(s); //浏览器页面输出字符串s
%>
表达式
包裹在<%= %>之间,用于定义在页面执行的表达式,注意结尾没有分号;
<%-- 表达式调用之前定义的相加函数--%>
x+y结果为<%=add(1,2) %>
JSP的生命周期
当有用户第一次请求index.jsp页面时,JSP引擎会把文件转换成为一个servlet,调用jspInt()方法生成一个字节码文件.class保存在Tomcat/work对应的项目目录下。生成的servlet常驻内存,只有jsp页面发生改变后,JSP才会重新编译字节码文件。当有另一个请求index.jsp文件时,这时不必重新生成字节码文件,而是调用jspService()方法创建一个新的线程来处理该请求,返回已经生成的字节码文件。通过多线程的方式执行可以降低对于系统资源的消耗,提高系统并发量与响应时间,但是也带来了多线程的同步问题。
2、JSP内置对象
内置对象是WEB容器创建的一组对象,不使用new创建就可以使用的对象,常用的有九类:out、request、response、session、application、Page、pageContent、exception、config
out对象
out对象通过缓冲区向jsp页面输出内容,常用println向缓冲区输入内容,缓冲区会在满了之后或者页面生成前自动输出到页面,也可以通过flush()手动输出。通过clear()清空缓冲区内容,但是在flush之后调用clear()会保存,而应该用clearBuffer()代替。还可以getXxx()获取缓冲区相关信息。如下使用out进行输出:
<h1>绝句</h1>
<%
out.println("两个黄鹂鸣翠柳,<br/>");
out.println("一行白鹭上青天。<br/>");
out.flush(); //手动刷新缓冲区
out.println("窗含西岭千秋雪,<br/>");
// out.clear(); //清空缓冲区,放这里出错
out.clearBuffer();
out.println("门泊东吴万里船。<br/>");
%>
缓冲区大小:<%=out.getBufferSize()%>字节<br>
缓冲区剩余:<%=out.getRemaining()%>字节<br>
自动刷新缓冲区:<%=out.isAutoFlush()%>
输出结果如下,在前两句之后通过flush()将缓冲区内容手动输出。之后由于使用clearBuffer()清空了缓冲区,导致第三句没有被输出。

Request对象
request对象封装了用于处理浏览器请求的方法。通过setCharacterEncoding()设置页面编码方式,防止页面中文出现乱码,setAttribute()可以将对象以键值对的方式保存在request对象中,之后通过getAttribute()方法可以取出保存的对象。通过getSession()可以获取服务器中保存的session信息,通过getParameter()可以获取客户端发来的请求中的参数,如果传来的是数组则需要使用getParameterValues()来接收。还可以通过其他getXxx()之类的方法来获取请求相关的信息,比如请求的地址、协议类型,服务器端口号、文件地址等。
如下为前端发送一个表单信息,后端接收处理显示的例子:
<h3>用户注册</h3>
<form action="regServer.jsp" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>爱好:</td>
<td>
<input type="checkbox" name="favorite" value="read">看书
<input type="checkbox" name="favorite" value="music">听音乐
<input type="checkbox" name="favorite" value="movie">看电影
</td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>
<a href="regServer.jsp?username=小李">通过get方式传递参数</a>
<body>
<h3>request接收请求</h3>
<%
request.setCharacterEncoding("utf-8"); //设置编码方式
request.setAttribute("info","一个字符串"); //通过request保存参数对象
%>
用户名:<%=request.getParameter("username")%> <%--获取单个参数--%>
<br>
爱好:
<%
String[] hobbies=request.getParameterValues("favorite"); //接收数组参数
if (hobbies!=null){
for (int i = 0; i < hobbies.length; i++) {
out.print(hobbies[i]+" ");
}
}
%>
<br>
保存的参数对象:<%=request.getAttribute("info")%><br>
请求的MIME类型:<%=request.getContentType()%><br>
协议类型:<%=request.getProtocol()%><br>
服务器主机号:<%=request.getServerName()%><br>
服务器端口号:<%=request.getServerPort()%><br>
客户端地址:<%=request.getRemoteAddr()%><br>
文件的相对路径:<%=request.getContextPath()%><br>
</body>
运行结果如下

Response对象
response包含了服务器响应请求的相关信息,通过response来设置服务器给客户端返回的响应的信息。例如通过setContentType()设置响应类型,除了可以通过out对象进行输出,response也提供了PrintWriter对象用于输出内容,而且其输出内容总是先于out对象的输出,除非使用out.flush()强制先输出。
通过response.sendRedirect()重定向请求,其本质相当于客户端重新发送了一次请求,客户端的地址会改变,而且会重新生成请求对象。而请求转发是服务器端的自身行为,客户端不可知,其浏览器的url地址不会发生改变,而且可以在转发中传递request、response对象。
response.setContentType("text/html;charset=UTF-8");
out.print("这是out对象输出的信息<br>");
PrintWriter printWriter=response.getWriter();
printWriter.println("这是Response对象Print Writer输出的信息<br>");
response.sendRedirect("regServer.jsp"); //重定向请求
request.getRequestDispatcher("regServer.jsp").forward(request,response); //请求转发
Session对象
Session是客户端在第一次访问服务器时创建,并一直保持到浏览器所有与服务器有关页面关闭之前的状态对象,用于在不同浏览器页面之间切换时标识用户。
Session的生命周期有创建、活动、销毁。当客户端第一次访问jsp,服务器会为当前会话创建一个sessionId,之后每次客户端访问服务器都会携带这个sessionId供服务器进行校验。注意除非浏览器与服务器所有的会话都关闭,否则在页面内跳转或者新打开一个页面,都属于本次Session。而当所有页面关闭后,重新打开后服务器会创建一个新的sessionId给客户端,但是之前的session仍然存在,直到超时或者手动结束其生命周期。
<%
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date date=new Date(session.getCreationTime()); //获取session创建时间
out.print("session创建时间:"+sdf.format(date));
session.setAttribute("username","小李"); //设置session参数
session.setMaxInactiveInterval(100); //设置session最大生存时间为100秒
%>
Session的ID:<%=session.getId()%><br>
获取Session的attribute属性:<%=session.getAttribute("username")%>
<%
session.invalidate(); //销毁当前会话
%>
也可以在web.xml文件中配置session超时的时间:
<session-config>
<session-timeout>30</session-timeout> <!--三十分钟后销毁-->
</session-config>
Session钝化:正常情况下session对象会保存到服务器的内存,但是当session数量过大或者服务器关闭时,服务器会把session暂时序列化存储到Tomcat/work/Catalina/服务器名/应用名/session.ser文件中,当服务器再次启动再从文件中反序列化到内存中
Application对象
application用于存放不同用户之间可以共享的全局变量,开始于服务器启动,终止于服务器关闭。
通过setAttribute()和getAttribute()可以对变量进行设置和获取。
Page对象
page对象是指jsp页面本身,类似于Java对象的this。
通过toString()方法可以打印页面jsp对象名@哈希code,equals()比较两个对象,getClass()返回class对象
pageContent对象
相当于页面各种功能对象的集合体,可以通过getXxx()获取其他对象。例如getOut()获得out对象,getSession(),getPage(),getRequest(),getResponse()。
也可以通过setAttribute()/getAttribute()设置和获取属性
可以通过forward()导航到指定页面,include()包含页面内容
config对象
包含Servlet初始化所要用到参数(键值对)以及服务器有关信息
getServletContext()返回服务器相关信息,getInitParameter()返回初始化信息
exception对象
页面运行中发生异常所产生的对象。如果要在当前页面使用该对象需要设置page指令isErrorPage="true",通过errorPage指定页面发生异常时交给哪个页面处理。
例如在一个页面中使用1/0抛出一个除以0的异常,交给exception.jsp页面处理
<%@page errorPage="exception.jsp" %>
<%=1/0%>
<--异常处理页面exception.jsp-->
<%@ page isErrorPage="true" %>
异常描述信息:<%=exception.getMessage()%><br>
异常的toString:<%=exception.toString()%><br>
异常栈轨迹:
<%
exception.printStackTrace();
%>
3、使用JavaBean
JavaBean是指符合特定规范的Java类,使用它可以减少代码重复编写、冗余,明确功能分区,提高代码可维护性。其设计原则包括四个,首先该类为public,其次包含无参构造方法,其属性为private,通过get/set方法进行获取和设置。如下所示为一个符合规则的Student类:
public class Student { //1、公有类
private String name; //2、属性私有
private int age;
public Student() { //3、无参构造方法
}
public String getName() { //4、get与set方法
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
可以使用Java引入包的方式使用JavaBean,在jsp页面使用page指令import所需的JavaBean即可和普通Java类一样使用
<%@page import="modules.Student" %> <!--引入所需JavaBean类-->
<%
Student s=new Student();
s.setName("小明");
s.setAge(24);
%>
学生姓名:<%=s.getName()%><br>
年龄:<%=s.getAge()%>
还可以通过JSP的动作元素在JSP页面使用JavaBean,动作元素为符合XML语法规则的标签,用于为请求处理阶段提供信息。例如<jsp:useBean><jsp:setProperty><jsp:getBean>三个是与使用JavaBean有关的。此外还有与Document有关的<jsp:root>、<jsp:text>等,与XML标签有关的<jsp:attribute>、<jsp:body>等,<jsp:include><jsp:forward>
<jsp:useBean>引入JavaBean对象,id属性为JavaBean的对象名,class属性指出引用哪个类,scope定义作用域范围,默认为当前页面page。如果作用域内存在该id的对象,则引入该对象,否则创建一个该id的对象。
<jsp:setProperty>为JavaBean的对象赋值,共有三种使用方式。第一种是和表单关联,表单在提交后会把name值和JavaBean类的变量进行比对,如果一样则调用set方法设置对象的值。比如客户端表单name=age,Student变量也有age,则调用setAge()为age赋值。通过property指定所需要赋值的变量,如果填"*",默认比对所有变量。第二种方式是手动赋值,通过value字段为property字段赋值。第三种方式是request参数赋值,通过param="request参数名"为 property字段赋值。
<jsp:getProperty>获取指定对象的指定property属性值。也可以直接调用该对象的getXxx()方法获取。
<!--客户端提交的表单-->
<form action="JavaBean.jsp" method="post">
<table>
<tr>
<td>姓名:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>年龄:</td>
<td><input type="text" name="age"></td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>
<!--服务器端接收的jsp-->
<%--引入Student类并创建myStudent对象--%>
<jsp:useBean id="myStudent" class="modules.Student" scope="page"></jsp:useBean>
<%--使用表单设置值--%>
<jsp:setProperty name="myStudent" property="*"></jsp:setProperty>
<%--手动设置property--%>
<jsp:setProperty name="myStudent" property="name" value="小明"></jsp:setProperty>
<%--通过request参数设置property--%>
<jsp:setProperty name="myStudent" property="age" param="age"></jsp:setProperty>
学生姓名:<%=myStudent.getName()%><br> <!--直接调用get方法获取属性-->
年龄:<jsp:getProperty name="myStudent" property="age"/> <!--通过jsp动作获取属性-->
JavaBean的作用域范围共有四种,由小到大:Page、Request、Session、Application。Page仅为当前页面可见对象。Request为一个请求内可见,比如页面请求转发时,仍然属于一个请求,此时前一个页面内的JavaBean对象仍然可用。Session为一次会话可见,只要页面没有关闭,在规定时间内打开的页面都属于一个会话。Application为整个应用可见,服务器开始到关闭都属于一个应用。在作用域内可以通过getAttribute()方法获取到可见的对象。例如在一个页面内将对象myStudent保存到session中,在另一个页面通过session获取myStudent对象:
<% //通过getAttribute获取作用域内的对象
Student student=(Student)session.getAttribute("myStudent");
%>
学生姓名:<%=student.getName()%>
年龄:<jsp:getProperty name="myStudent" property="age"/> <!--通过jsp动作获取属性-->
在JavaBean出现之前,jsp页面不仅负责页面的展示,而且还包括数据读取、处理和业务逻辑等操作,非常不利于业务扩展和大型程序的开发。JavaBean出现之后,可以使用它来封装业务逻辑和数据模型,使jsp页面功能得到分离,提高了代码可维护性,这个开发模式也被称为模型1(Module1)。

4、Cookie
由于http协议具有无状态性,即浏览器每一次给服务器发送请求时,服务器都会把请求当作一个新的浏览器发来的,不会记住之前是否访问过。为了“记住”浏览器客户端,需要存储一些信息来辨识,除了之前使用session在服务器端存储之外,还可以使用cookie在客户端存储信息。由于cookie保存在本地,容易造成数据泄露,因此常保存一些不重要的用户信息,比如浏览记录、用户设置等,两者区别如下:

Cookie本质是一个字符串,因此有时在设置cookie时会因字符串编码而报错,此时可以存储前先将字符串进行编码,取出cookie时再解码
String encodeName=URLEncoder.encode("小明","utf-8"); //对字符串进行编码
Cookie nameCookie=new Cookie("username",encodeName); //创建cookie
Cookie hobbyCookie=new Cookie("hobby","听音乐");
nameCookie.setMaxAge(1000); //设置cookie生存周期一千秒
hobbyCookie.setMaxAge(1000);
response.addCookie(nameCookie); //保存cookie
response.addCookie(hobbyCookie);
Cookie[] cookies=request.getCookies(); //获取cookie
for (Cookie c:cookies){
if (c.getName().equals("username")) { //获取cookie名
String decodeName=URLDecoder.decode(c.getValue(),"utf-8"); //获取cookie值并进行解码
out.print("用户名:"+decodeName);
}
if (c.getName().equals("hobby"))
out.print("爱好:"+c.getValue());
}
nameCookie.setMaxAge(0); //设置cookie失效
hobbyCookie.setMaxAge(0);
5、jsp动作
除了JavaBean使用的动作之外,JSP还有许多其他动作。例如include动作可以引入另一个jsp页面,其效果与include指令相同,但include动作包含的是页面的执行结果,即另一个页面先编译成servlet再包含,而include指令包含的是页面的源代码,因此如果子页面经常改变需要重新编译,则使用include动作单独编译更好,而如果子页面固定不变,使用include指令更快。

使用forward动作完成页面请求转发操作,其效果等同request.getRequestDispatcher("login.jsp").forward(request,response);
并且在转发时可以使用param传递新的参数
<jsp:forward page="login.jsp">
<%--转发时传递参数--%>
<jsp:param name="email" value="test@163.com"/>
</jsp:forward>
本文详细介绍了JSP技术,包括其组成元素、生命周期、内置对象、JavaBean使用、Cookie及JSP动作,帮助读者掌握JSP在Web开发中的应用。


被折叠的 条评论
为什么被折叠?



