目录
引言
之前写了创建了那么多JSP页面,但是JSP页面到底如何编写,怎么组成,和servlet又有什么关系呢?
今天我们就来初略的学习一下JSP的内容(需要很详细的学习请看菜鸟教程)
JSP页面组成
我们先来看一下的JSP页面
我们可以看到,在<%@ %>里面的是JSP标记,JSP指令用于告诉JSP容器如何处理JSP网页;JSP标记分为JSP指令标记和JSP动作标记。
JSP指令标记是用于设置页面相关属性或者执行动作的一种标记,一个指令标记中可以有多个属性,作用范围时整个页面
在jsp中的书写格式有两种
- <%@指令名称 属性1=“属性值” 属性2=“属性值”……%>
- <jsp:directive.指令属性 属性1=“属性值” 属性2=“属性值” …/>
- page:定义与页面相关的一些属性,page指令有13个属性:
- language jsp使用的脚本语言,默认java
- extend jsp->servlet后继承的父类
- import 和java的import类似,默认import了java.lang.*,javax.servlet.*,javax.servlet.jsp.*和javax.servlet.http.*,且这是唯一一个可以重复使用的属性
- session 是否使用session对象,session是保持连接的东西,下面有介绍
- buffer 输出out对象(下面讲到)的缓存区大小,none的话直接输出不缓存,以KB为单位
- autoFlush 缓存满的时候是否自动刷新,false的话溢出时候抛出异常
- isThreadSafe 默认true 指定jsp页面是否线程安全,即可以让多个客户端同时请求访问
- info 指定页面相关信息,可以通过调用servlet接口的getServletInfo()来获得
- errorPage 指定异常发生的时候,转向哪一个错误处理页面
- isErrorPage 是否是错误处理页面 默认false
- contentType 指定用于相应的jsp页面的MIME类型和字符编码,中文页面的话必须要设置<%@ page contentType="text/html; charset=gb2312" %> 或者charset=utf-8
- pageEncoding 指定JSP页面使用的字符编码,没有设置的话使用contentType的字符集,如果两个都没有就是ISO-8859-1 --->这使得第三章我们输入的编码是ISO,传到服务器的时候就乱码了
- isELIgnored 是否执行或者忽略EL表达式 true忽略 false执行
- include用于在JSP页面中静态包含一个文件,该文件可以是JSP页面、HTML网页、文本文件或一段Java代码<%@ include file="relativeURL" %>
例4.2:include指令的使用 <%@ page contentType="text/html;charset=gb2312" %> <html> <head><title>欢迎你</title></head> <body> 欢迎你,现在的时间是 <%@ include file="date.jsp" %> </body> </html> date.jsp: <% out.println(new java.util.Date().toLocaleString()); %> 访问该页面,会显示当前的系统时间。
- taglib指令允许页面使用用户自定义的标记 <%@ taglib (uri="tagLibraryURI" | tagdir="tagDir") prefix="tagPrefix" %>
JSP的动作标记是JSP的另一种标记,它利用XML语法格式来控制JSP服务器实现某种功能
JSP2.0规范中定义了20个标准的动作标记
常用的JSP动作标记有
- <jsp:include>:在页面被请求时动态引入一个文件。
- <jsp:forward>:把请求转到一个新的页面。
<jsp:forward>动作的语法格式为: 不带参数: <jsp:forward page=“url”/> 带参数: <jsp:forward page=“url”>{ <jsp:param …. /> }* </jsp:forward> <jsp:forward>动作只有一个属性page。 page属性指定请求被转向的页面的相对路径,该路径是相对于当前JSP页面的URL,也可以是经过表达式计算得到的相对URL。
- <jsp:plugin>:用于产生与客户端浏览器相关的HTML标记(<OBJECT>或<EMBED>)。
- <jsp:useBean>:实例化一个javaBean。
- <jsp:setProperty>:设置一个javaBean的属性。
- <jsp:getProperty>:获得一个javaBean的属性。
- <jsp:useBean>,<jsp:setProperty>和<jsp:getProperty>:访问JavaBean时所用。
- <jsp:param>以“名-值对”的形式为其他标记提供附加信息,如传递参数等。它和<jsp:include>,<jsp:forward>和<jsp:plugin>一起使用。它的语法为: <jsp:param name="name" value="value" />
在<% %>里面的是JSP代码,实现某些需要java代码实现的功能
在<html> </html>里的是html代码,进行网页的显示。
JSP的运行
直接将jsp放在tomcat的ROOT目录下就可以运行,打开浏览器输入http:://127.0.0.1:8080/我们写的jsp页面的名字.jsp就可以运行了
JSP和servlet的区别:
- servlet是一个完整的java应用程序,有类和方法,而jsp不需要类和方法的定义,比较简单。
- servlet需要先编译,生成的类文件部署在指定路径下,并且在配置文件(web.xml)中注册了才可以运行,而jsp直接放在相应的目录下,不需要注册(虽然第一次访问的时候是需要tomcat去编译成servlet然后提供服务的)
- 速度不同,servlet先编译好了所以可以直接运行,而jsp是存放的源码,只有在首次访问的时候经过编译才可以运行,但是第一次访问比较慢,之后的访问速度就正常了
JSP隐含对象
JSP为了方便程序开发和信息交互,提供了九个隐含对象,这些对象不需要声明就可以在JSP脚本和JSP表达式中使用
可分为4类:
(1)输出输入对象:
- request对象(代表来自客户端的请求,是javax.servlet.http.HttpServletRequest接口类的实例)
- response对象(用于响应客户端请求)
- out对象(javax.servlet.jsp.jspWriter类的实例,用于输出,以及与缓存相关功能)
(2)与属性作用域相关对象:
- pageContext对象(可以访问到本页中的所有其他对象。
- session对象(让服务器和客户端之间一直保持连接,直到客户端主动关闭或超时(一般为30分钟)无反应才会取消这次会话,在session中可以保存关于用户的很多信息,实现同一用户在访问web站点的时候在多个页面共享信息:setAttribute()和getAttribute())
- application对象(用于保存应用程序在服务器上的全局数据,所有用户都访问唯一的一个application对象)
(3)Servlet相关对象:
- page对象(JSP页面本身,它代表JSP被编译成的Servlet,可以使用它来调用Servlet类中所定义的方法,等同于Java中的this)
- config对象 (代表当前JSP 配置信息)
(4)错误处理对象: exception对象
EL表达式和JSTL标签
类似于JavaScript的语言,主要用于在网页上显示动态内容,替代Java脚本完成复杂功能。
习题:
1、表示层、逻辑层、数据层分离
表示层一般是可以显示在页面上的,但是页面上点击后的逻辑,一般是由逻辑层实现的,而逻辑层(至少在现在)绝大部分使用servlet进行实现的,数据层则是与数据库打交道的java类。
我们一般下了MyEclipse之后有自带jdk以及tomcat,jdk是1.6,tomcat是6版本的,我们可以使用原来的tomcat也可以使用自己下载的tomcat(详情请看Java EE 开发技术与案例教程——第一章),我由于之前使用tomcat7在工程里找不到问题,但是就是显示不了,所以新建工程使用了tomcat6(自带的)
下面先介绍一下我的工程结构
WebRoot下面的jsp全部都是用于显示的,JdbcUtils是用来和数据库打交道的,LoginServlet是处理index中login的逻辑的,RegisterServlet是用来处理注册时候的逻辑的。
首先新建一个工程,然后在index.jsp写入以下的代码
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>登录界面</title>
<style type="text/css">
body{
background-image:url(images/timg.jpg);
background-position:center;
background-repeat:no-repeat;
}
</style>
</head>
<body>
<div style="text-align:center;margin-top:120px">
<h2>XQ的主页</h2>
<form action="LoginServlet" method="post">
<table style="margin-left:40%">
<marquee width="200"scrolldelay="250">用户登录</marquee>
<tr>
<td>登录名:</td>
<td><input name="username" type="text" size="21"></td>
</tr>
<tr>
<td>密码:</td>
<td><input name="password" type="password" size="21"></td>
</tr>
</table>
<input type="submit" value="登录">
<input type="reset" value="重置">
</form>
<br>
<a href="register.jsp">注册</a>
</div>
</body>
</html>
这里要注意的就是<form action=" " method="post">这里的action的字符串,也就是需要调用的逻辑层的文件的路径,如果登入的话会调用这个servlet的post方法,所以这里的路径需要写清楚,也就是和xml需要一致。如何一致呢,我们先看看这里的LoginServlet和其xml怎么写
(注意,我们在src下兴建了一个work4的package,同一个package下的java文件可以互相调用(因为很明显我们需要用到数据层的java类的接口)
work4中的LoginServlet.java
package work4;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import work4.User;
import work4.UserDAO;
/**
* Servlet implementation class LoginServlet
*/
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
UserDAO userDAO=new UserDAO();
User user=userDAO.login(username, password);
if(user!=null){
request.getRequestDispatcher("success.jsp").forward(request, response);;
}else{
request.getRequestDispatcher("error.jsp").forward(request, response);
}
}
}
其中本来在tomcat6,貌似找不到import javax.servlet.annotation.WebServlet;的定义,根据此处,import了tomcat7的jar文件,是可以不报错,找得到的。
值得关注的就是UserDAO,这个UserDAO是一个检验用户是否正确以及增加用户的类,而login方法如果用户密码出错的话就会返回一个null对象,进而跳到不同的处理jsp。
xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>work4.LoginServlet</servlet-class>
</servlet>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>work4.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/RegisterServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
因为查看用户是否正确,为了方便我们兴建了User.java类来存储数据,并且需要连接数据库,所以我们下面从源头的数据库操作数据层开始介绍
JdbcUtils.java
package work4;
import java.io.IOException;
import java.io.InputStream;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
import com.mysql.jdbc.Statement;
public class JdbcUtils {
//注册驱动的工具类
private static String url = null;
private static String user = null;
private static String password = null;
private static String dv = null;
static{
Properties prop = new Properties();
InputStream in = JdbcUtils.class.getResourceAsStream("a.properties");
try {
prop.load(in);
url = prop.getProperty("url");
user = prop.getProperty("user");
password = prop.getProperty("password");
dv = prop.getProperty("driver");
/*System.out.println("url:"+url);*/
//注册驱动
try {
Class.forName(dv);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取连接对象
public static Connection getCon() throws SQLException{
Connection conn = null;
conn = (Connection) DriverManager.getConnection(url, user, password);
return conn;
}
//关闭的方法
public static void close(Statement statement,Connection conn){
if(statement !=null){
try {
statement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn !=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//关闭的方法
public static void close(PreparedStatement preparedStatement,Connection conn,ResultSet resultSet){
if(preparedStatement !=null){
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn !=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
这个类getCon可以返回一个数据库连接的句柄 ,close方法可以关闭连接,并且有静态方法(也就是一种类一开始就会执行且只执行一遍的方法), InputStream in = JdbcUtils.class.getResourceAsStream("a.properties"); 意思就是从a.properties这个(相当于配置文件)文件中提出连接数据库的信息,然后加载驱动。然后需要连接的时候就调用getCon。
那么我们来看看a.properties
url:jdbc:mysql://localhost:3306/work1?characterEncoding=utf-8
user:root
password:12341234
driver:com.mysql.jdbc.Driver
看来挺简单的,实现了连接数据库和关闭数据库的工程,对数据库的操作就在UserDAO.java中实现了
package work4;
import java.sql.ResultSet;
import java.sql.SQLException;
import work4.User;
import work4.JdbcUtils;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
public class UserDAO {
//数据库连接对象
public User login(String username,String password) {
User u=null;
Connection connection =null;
PreparedStatement pstmt=null;
ResultSet resultSet=null;
//赋值
try {
connection=JdbcUtils.getCon();
//静态sql语句
String sql = "select * from user where name=? and password=?";
pstmt = (PreparedStatement) connection.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
resultSet = pstmt.executeQuery();
if(resultSet.next()){
u=new User();
u.setName(resultSet.getString("name"));
u.setPassword(resultSet.getString("password"));
System.out.println("登录成功!");
}else{
System.out.println("用户名或者密码错误!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(pstmt, connection);
}
return u;
}
public void addUser(User user) {
Connection connection = null;
PreparedStatement psmt = null;
try {
connection = JdbcUtils.getCon();
String sql ="insert into user(id,name,password,role)values(?,?,?,?);";
psmt = (PreparedStatement) connection.prepareStatement(sql);
//运用实体对象进行参数赋值
psmt.setInt(1, user.getId());
psmt.setString(2, user.getName());
psmt.setString(3,user.getPassword());
psmt.setInt(4, user.getRole());
psmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JdbcUtils.close(psmt, connection);
}
}
}
第一个方法login首先获得连接然后设置preparedstatement的sql语句然后连接,如果说为null那么就是没有找到这样的用户数据,失败,有的话就登入成功。
然后增加用户的操作也是大同小异,最后记得要关闭资源就可以了。
同时,我们在index.jsp中看到了
<br>
<a href="register.jsp">注册</a>
</div>
也就是说这是一个超链接,连接到我们的ch4工程下的register(注意路径)
register.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>注册界面</title>
<style type="text/css">
body{
background-image:url(images/tim.jpg);
background-position:center;
background-repeat:no-repeat;
}
</style>
</head>
<body>
<div style="text-align:center;margin-top:120px">
<h1 >请注册</h1>
<form action="http://192.168.199.196:8080/ch4/RegisterServlet" method="post">
<table style="margin-left:40%">
<caption>用户注册</caption>
<tr>
<td>ID:</td>
<td><input name="id" type="text" size="20"></td>
</tr>
<tr>
<td>登录名:</td>
<td><input name="name" type="text" size="20"></td>
</tr>
<tr>
<td>密码:</td>
<td><input name="password" type="password" size="20"></td>
</tr>
<tr>
<td>角色:</td>
<td><input name="role" type="text" size="20"></td>
</tr>
</table>
<input type="submit" value="注册">
<input type="reset" value="重置">
</form>
<br>
<a href="index.jsp">登录</a>
</div>
</body>
</html>
这里就是跳转到RegisterServlet.java去处理
package work4;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import work4.User;
import work4.UserDAO;
/**
* Servlet implementation class RegisterServlet
*/
@WebServlet("/RegisterServlet")
public class RegisterServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public RegisterServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPut(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
int id=Integer.valueOf(request.getParameter("id"));
String name=request.getParameter("name");
String password=request.getParameter("password");
int role=Integer.valueOf(request.getParameter("role"));
User user=new User();
user.setId(id);
user.setName(name);
user.setPassword(password);
user.setRole(role);
UserDAO userDAO=new UserDAO();
userDAO.addUser(user);
System.out.println("注册成功");
request.getRequestDispatcher("index.jsp").forward(request, response);
}
}
注意这里的最后一句话 request.getRequestDispatcher("index.jsp").forward(request, response);
注册成功之后我们就跳回index.jsp页面了,记住不要写错了自己这个index.jsp,否则会出现错误。