一、构建Web应用
(一)“徒手”建立一个空的Web应用
1.任意选取一个目录,新建项目文件夹
2.在上述文件夹中新建WEB-INF文件夹
3.从tomcat的应用中随便复制一个web.xml到刚才新建的WEB-INF文件夹中
4.打开复制过来的web.xml并将其修改成只有一个根元素的xml文件。
5.在上述所建的WEB-INF文件夹下新建两个文件夹,classes和lib。
这两个文件夹的作用完全相同,都是用于保存Web应用所需要的Java类文件,区别是classes保存单个*.class文件;lib保存打包后的JAR文件。
6.新建一个简单的jsp文件。
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>Helloworld</title>
</head>
<body>
This is a test.
</body>
</html>
经过上述步骤,就建立了一个Web应用。将该应用复制到Tomcat的webapps路径下,就会自动部署到Tomcat中。
双击startup.bat,启动Tomcat
http://localhost:8080/20170710_webDemo/a.jsp
浏览器访问上述地址
访问成功。
(二)配置描述符web.xml
1.web.xml的根元素是
<web-app></web-app>
2.metadata-complete
该属性有true跟false两个值。
为true时,该Web应用不会自动加载Annotation配置的Web组件(如Servlet、Filter、Listener等)。
3.welcome-file-list
用来配置首页。
<welcome-file-list>
<welcome-file>a.html</welcome-file>
<welcome-file>a.htm</welcome-file>
<welcome-file>a.jsp</welcome-file>
</welcome-file-list>
就是先找a.html充当首页,如果没有a.html就找a.htm,以此类推。
二、JSP基本原理
1.JSP的本质是Servlet。
每个JSP页面就是一个Servlet实例,JSP页面由系统编译成Servlet,Servlet再负责响应用户请求。
JSP实际上是一种简化的Servlet,使用JSP其实还是使用的Servlet,因为Web应用中的每个JSP页面都会由Servlet容器生成对应的Servlet。
Servlet跟JSP是完全统一的,二者在底层的运行原理是完全一样的。
JSP必须被WEB服务器编译成Servlet提供HTTP服务的是Servlet。JSP可以视为一个“草稿”文件,WEB服务器根据其生成servlet,真正提供HTTP服务的是Servlet。
所以广义的servlet包括JSP和Servlet。
那既然是一样的,为什么要有这两种东西呢?
当用户向指定的Servlet发送请求的时候,Servlet利用输出流动态的生成HTML页面,包括每一个静态的HTML标签和所有在HTML页面中出现的内容。复杂的内容降低了Servlet的开发效率。
而JSP是一种动态页面技术,主要目的就是将表示逻辑从Servlet中分离出来。
它实现了HTML页面的Java扩展(<%…%>),封装了产生动态网页的处理逻辑。
2.JSP的结构
静态部分:标准的HTML标签、静态的页面内容,与静态的HTML页面相同。
动态部分:受Java程序控制的内容,由Java程序动态产生。
3.举个栗子
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>Helloworld</title>
</head>
<body>
This is a test.
现在时间是:
<%out.println(new java.util.Date());%>
</body>
</html>
打开了这个页面后
tomcat的这个路径\work\Catalina\localhost\20170710_webDemo\org\apache\jsp下
就会发现tomcat根据JSP页面生成了对应Servlet的Java文件和class文件。
三、JSP注释
JSP注释不会输出到客户端。
(1)JSP注释
<%–注释内容–%>
(2)HTML注释
<!--注释内容-->
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>Helloworld</title>
</head>
<body>
<!--HTML注释-->
<%--JSP注释--%>
This is a test.
现在时间是:
<%out.println(new java.util.Date());%>
</body>
</html>
页面上只能看到HTML注释,不能显示JSP注释。
四、JSP声明
<%!–声明部分–%>
用于声明变量跟方法
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>Helloworld</title>
</head>
<!--JSP声明定义变量和方法-->
<%!
public int count = 0;
public String info(){
return "hello";
}
%>
<body>
<%out.println(count++);%>
<%out.println(++count);%>
<%=count++%>
<%=++count%>
</body>
</html>
注意这里的声明是写在标签外面的,写在里面就不对,可执行的Java代码是写在标签里面的。
这里输出结果是0 2 2 4.
然后我们可以再到D:\java\save\apache-tomcat-8.0.24\work\Catalina\localhost\20170710_webDemo\org\apache\jsp这个目录下看看刚才生成的Servlet对应的Java文件
五、JSP执行数据库查询
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<%@ page import="java.sql.*"%>
<html>
<head>
<title>Helloworld</title>
</head>
<body>
<%
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"", "", "");
Statement statm = conn.createStatement();
ResultSet rs = statm.executeQuery("select * from test_student");
%>
<table>
<%
while(rs.next()){
%>
<tr>
<td><%=rs.getString(1)%></td>
<td><%=rs.getString(2)%></td>
<td><%=rs.getString(3)%></td>
</tr>
<%}%>
</table>
</body>
</html>
在这里出现了一个小错误,报错Connection cannot be resolved to a type
这个是因为开始忘记在JSP中导入数据库包了,就是在tomcat的lib目录下加一个oracle的jar包,再在jsp文件的开头加上这一句话
<%@ page import=”java.sql.*”%>就好啦。
六、JSP的3个编译指令
编译指令是通知JSP引擎的消息,是有默认值的,无需为每个设定值。
(1)page指令
上面已经用过啦。
page指令通常位于页面顶端,一个JSP页面可以有多个page指令。
这里就说一下errorPage这个属性,它的实质是JSP的异常处理机制,在运行中出现异常的话,系统将自动跳转到errorPage指定的页面,如果不指定,就会在客户端浏览器上直接显示错误信息,以前我就做过这样的蠢事情,这样是不好的。
那用法就是这样啦。
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="error.jsp" %>
(2)include:用于指定包含另一个页面
(3)taglib:用于定义和访问自定义标签
七、JSP的7个动作指令
动作指令跟编译指令的区别
编译指令是通知Servlet引擎的处理消息;
动作指令只是运行时的动作。
编译指令在JSP编译成Servlet时起作用,处理指令通常可替换成JSP脚本,只是JSP脚本的标准化写法。
1.forward指令
用于将页面响应转发到另外的页面
举个栗子
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>jsp_forward原始页</title>
</head>
<body>
<jsp:forward page="20170726_jsp_forward_res.jsp">
<jsp:param name="age" value="18"></jsp:param>
</jsp:forward>
</body>
</html>
结果页
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>jsp_forward结果页</title>
</head>
<body>
<%=request.getParameter("age")%>
</body>
</html>
结果页面直接显示18
但是地址栏还是http://localhost:8080/20170710_webDemo/20170726_jsp_forward.jsp没有改变。
从这里可以看出执行forward指令转发请求时,客户端的请求参数不会丢失。
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>jsp_forward表单提交</title>
</head>
<body>
<form id="login" method="post" action="20170726_jsp_forward.jsp">
<input type="text" name="username">
<input type="submit" value="login">
</form>
</body>
</html>
刚才那个结果页文件里加一句话啦。
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>jsp_forward结果页</title>
</head>
<body>
<%=request.getParameter("age")%>
<%=request.getParameter("username")%>
</body>
</html>
2.include指令
include指令只会将被导入页面的body内容插入到本页面。
它跟forward指令十分相似,下面用一个简单的栗子来对比一下
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>jsp_include原始页</title>
</head>
<body>
<jsp:include page="20170726_jsp_forward_res.jsp">
<jsp:param name="age" value="18"></jsp:param>
</jsp:include>
</body>
</html>
注:20170726_jsp_forward_res.jsp中注释掉
<%=request.getParameter("username")%>
这句话
结果跟刚才的forward一样,都是18
现在我们来对比一下两个指令的Servlet代码,到tomcat的这个目录下
\work\Catalina\localhost\20170710_webDemo\org\apache\jsp
可以发现一个是用forward()方法来引入目标页面,另一个则是通过include()方法来引入,区别在于,执行forward时,目标页面将完全代替原有页面,执行include时,目标页面只是插入了原有的页面。
3.useBean、setProperty、getProperty指令
这三个指令都跟JavaBean有关
其中,useBean用于在jsp页面中初始化一个Java实例;
setProperty用于为JavaBean实例设置属性值;
getProperty用于输出JavaBean实例的属性值。
如果我们有很多的jsp页面都需要使用重复的某段代码,就可以将其写成Java代码来调用该方法。
又要来举一个小栗子啦。
Person类
package com.yolanda.fun.temp;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
上面的是一个Person.java文件,但是Web应用对它是不起作用的,所以我在外面用sts编译了一下这个文件,将得到的二进制文件Person.class放入WEB-INF\classes路径下。
好哒,接下来就来写jsp啦。
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<html>
<head>
<title>jsp三个JavaBean相关指令</title>
</head>
<body>
<jsp:useBean id="p1" class="com.yolanda.fun.temp.Person" scope="page"></jsp:useBean>
<jsp:setProperty name="p1" property="name" value="Anna"></jsp:setProperty>
<jsp:setProperty name="p1" property="age" value="12"></jsp:setProperty>
<jsp:getProperty name="p1" property="name"></jsp:getProperty>
<jsp:getProperty name="p1" property="age"></jsp:getProperty>
</body>
</html>
这里的scope属性用于指定JavaBean实例的作用范围,里面的参数有四个
page:该JavaBean实例仅在该页面有效;
request:该JavaBean实例在本次请求有效;
session:该JavaBean实例在本次session有效;
application:该JavaBean实例在本应用内一直有效。
在这里要注意几点,
第一,我在源文件里用了包名,所以在jsp中也要写,不然就会报500的错误;
第二,包名写对了还是出现了
The value for the useBean class attribute com.yolanda.fun.temp.Person is invalid.这个错误
这是为什么呢?
因为没有找到这个类,如果本来有包名的话,在WEB-INF\classes路径下也要建个一样的目录出来,也就是说这个文件要放在\WEB-INF\classes\com\yolanda\fun\temp目录下,就好啦
有的坑真的是不踩都想象不出来~
4.plugin指令和param指令
param前面都用过啦,单独的param指令没有实际意义,跟jsp:include、jsp:forward还有jsp:plugin结合使用。
plugin指令见都没见过,不说啦~