CIS6930: CGI and Servlets

Download Report

Transcript CIS6930: CGI and Servlets

CIS 5930-04 – Spring 2001
Part 7: JDBC Tutorial
http://aspen.csit.fsu.edu/it1spring01
Instructors: Geoffrey Fox , Bryan Carpenter
Computational Science and Information Technology
Florida State University
Acknowledgements: Nancy McCracken
Syracuse University
[email protected]
1
Introduction





JDBC—usually interpreted as an acronym for Java
Database Connectivity—was introduced in 1996, and
revamped in 1998 for Java 2.
It is an API definition intended for implementation as a Java
interface to an SQL database.
SQL (“sequel”) is the Structured Query Language, originally
defined by IBM in the 70’s, standardized by ANSI/ISO in
1992.
SQL is in turn based on the relational database model. It is
implemented (with much variation) by many vendors of
RDBMS (Relational Database Management System)
software.
First commercial implementation of SQL: Oracle, 1979.
[email protected]
2
SQL
[email protected]
3
Relations


Mathematically, a relation is a subset of a product space.
Equivalently, it is a set of “tuples” with entries from some
fixed domains.
In mathematics, the most important relations tend to be
binary relations between entities of the same type:
LessThan, on {0, 1, 2, 3}  {0, 1, 2, 3}:
{ (0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3) }
Contains, on {sunder, sun, sundry, dry}  {sunder, sun, sundry,
dry}:
{ (sunder, sunder), (sunder, sun), (sun, sun),
(sundry, sundry), (sundry, sun), (sundry, dry), (dry, dry) }
SameColor, on {tomato, cherry, banana}  {tomato, cherry,
banana}:
{ (tomato, tomato), (tomato, cherry), (cherry, tomato),
(cherry, cherry), (banana, banana) }
Examples respectively [email protected]
of total order, partial order and
4
General Relations

For databases, we are nearly always interested in n-ary
relations between distinct domains, e.g. assume:
Login
= {wcao, Flora, Fulay, zyr98210, jin0328}
LastName = {Cao, Flora, Fulay, Zhang}
Dept
= {CSIT, EE, CS}
then we may define the relation:
Students, on Login  LastName  Dept :
{ (wcao,
Cao,
CSIT),
(Flora,
Flora, EE ),
(Fulay,
Fulay, CS ),
(zyr98210, Zhang, CS ),
(jin0328, Zhang, CS ) }
[email protected]
5
SQL Tables






SQL is inspired by this mathematical model.
Names are changed, and for pragmatic reasons the
SQL model does not try to be mathematically pure.
A relation is replaced by a table.
The individual tuples in the relation are called rows.
The domain sets of the relation are replaced by columns
or attributes.
Typing is not as strict as the mathematical model
suggests. We define the allowed values of a column in
terms of a limited set of predefined types, rather than
actual sets.
[email protected]
6
Creating a Table

A possible SQL command to create a table for our
Students relation is:
CREATE TABLE students (
login VARCHAR(10),
lastname VARCHAR(20),
dept VARCHAR(5)
)

Things to note:
– Case is not significant here. By convention we use upper case
for SQL keywords.
– White-space, including line-breaks, is not significant.
– The CREATE TABLE statement is syntactically like a class
definition, defining columns (c.f. fields) and their types.
– In this analogy, rows of the table would be like class instances.
[email protected]
7
Column Types

There are a limited set of types for column data.

Unfortunately (although there is supposed to be a
standard) in practice the available types are completely
dependent on the vendor.

In JDBC the types are standardized and include:
INTEGER
FLOAT(N)
CHARACTER(N)
VARCHAR(N)
BLOB
Typically 32-bit integer.
Floating point with N bits of precision.
Fixed length string, N characters.
Variable length string, maximum N.
A large binary object.
[email protected]
8
SQL*Plus

To create a table using the Oracle SQL*Plus interpreter,
type the sqlplus command and enter your Oracle
account name and password, then:
SQL> create table students (
2 login varchar(10),
3 lastname varchar(20),
4 dept varchar(5)
5 );
Table created

In this interpreter commands are terminated by a
semicolon.
[email protected]
9
Inserting a Row

The SQL command for adding a row to a table is, e.g.:
INSERT INTO students VALUES (‘wcao’, ‘Cao’, ‘CSIT’)

In sqlplus I enter:
SQL> insert into students values (
2 ‘wcao’,
3 ‘Cao’,
4 ‘CSIT’) ;
1 row created.

The following examples assume the other tuples from
the Student relation are entered in the same way.
[email protected]
10
The SELECT command

To view the Students table I can use the SELECT
command:
SELECT * FROM students

The asterisk is a wildcard that causes all columns to be
display.
In sqlplus:
SQL> select * from students ;
LOGIN
LASTNAME
DEPT
----------------- ----------------------------- -----------wcao
Cao
CSIT
Flora
Flora
EE
Fulay
Fulay
CS
zyr98210
Zhang
CS
jin0328
Zhang
CS
5 rows selected
[email protected]
11
Displaying Chosen Columns

To limit the set of columns printed, specify them in the
SELECT command, e.g.:
SELECT login, lastname FROM students

In sqlplus:
SQL> select login, lastname from students ;
LOGIN
LASTNAME
----------------- ----------------------------wcao
Cao
Flora
Flora
Fulay
Fulay
zyr98210
Zhang
jin0328
Zhang
5 rows selected
[email protected]
12
Displaying Chosen Rows

To limit the set of rows printed, I add a WHERE clause:
SELECT * FROM students WHERE dept=‘CS’

Other kinds of tests that can appear in the WHERE
clause will be described later.
In sqlplus:
SQL> select * from students where dept=‘CS’ ;
LOGIN
LASTNAME
DEPT
----------------- ----------------------------- -----------Fulay
Fulay
CS
zyr98210
Zhang
CS
jin0328
Zhang
CS
3 rows selected
[email protected]
13
A Second Table

The following examples assume I define a second table by:
CREATE TABLE departments (
abbrev VARCHAR(5),
name VARCHAR(50)
)
and add the rows:
{ (‘CSIT’, ‘Computational Science and Information Technology’),
(‘EE’,
‘Electrical Engineering’),
(‘CS’,
‘Computer Science’) }
[email protected]
14
Selecting from Multiple Tables

A SELECT command can display data from more than
one tables:
SELECT * FROM students, departments

By itself this just produces a mess. In sqlplus:
SQL> select * from students, departments ;
LOGIN
LASTNAME
DEPT
ABBRE
----------------- ----------------------------- ------------ ---------NAME
-------------------------------------------------------------------wcao
Cao
CSIT
CSIT
Computational Science and Information Technology
Flora
Flora
EE
CSIT
Computational Science and Information Technology
Fulay
Fulay
CS
CSIT
Computational Science and Information Technology
...
15 rows selected
[email protected]
15
Joins




The previous query returned 15 rows.
It simply yielded a “Cartesian product” of the two
relations, with every row of students being combined
with every row of departments.
In itself this is not a useful result. But is a basis from
which to add a WHERE clause to select out some
meaningful combinations of values from the two tables.
If two tables appearing in the same statement share
some identical column names, can disambiguate by
using qualified names, e.g.:
students.login, students.lastname, students.dept, etc.
[email protected]
16
References Between Tables

Here is a meaningful query involving the two tables:
SELECT login, name FROM students, departments
WHERE dept=abbrev

In sqlplus:
SQL> select login, name from students, departments
2 where dept=abbrev ;
LOGIN
NAME
----------------- -------------------------------------------------------------------------Fulay
Computer Science
zyr98210
Computer Science
jin0328
Computer Science
wcao
Computational Science and Information
Technology
Flora
Electrical Engineering
5 rows selected
[email protected]
17
Primary Keys and Foreign Keys

This kind of cross-reference is so important that SQL
provides syntax to allow automatic “integrity checks”
and allow optimizations.

We can change the abbrev column to be a primary key
of the departments table by the following SQL
command:
ALTER TABLE departments ADD PRIMARY KEY (abbrev)

We add a constraint that any allowed value in the dept
column of students must be a valid primary key in the
departments table by the SQL command:
ALTER TABLE students ADD FOREIGN KEY (dept)
REFERENCES departments (abbrev)
[email protected]
18
Integrity Checks

The system will now forbid addition of values to the dept
column of students that do not correspond to values in
the abbrev column of departments.

For example, I can try to change the dept column of the
row describing wcao by the SQL UPDATE command:
UPDATE students SET dept=‘IE’ WHERE login=‘wcao’

Because of the constraints, Oracle will refuse to make
this update. In sqlplus:
SQL> update students set dept=‘IE’ where login=‘wcao’ ;
ERROR at line 1 :
ORA-02291: integrity constraint violated - parent key not
found.

Incidentally this example illustrates the use of UPDATE
command, which changes attributes of existing rows.
[email protected]
19
Other Useful Commands

. . . in addition to CREATE, SELECT and UPDATE,
which were illustrated earlier:
DELETE FROM table_name WHERE condition
Deletes selected rows.
DROP TABLE table_name
Removes a table.
DESCRIBE table_name
Describes columns of a table.
COMMIT
Save changes made in this transaction.
ROLLBACK
Undo changes made in this transaction.
[email protected]
20
Conditions

Conditions in WHERE clauses are Boolean expressions
built from:
– Comparision operators =, <>, <, <=, >, >=
– Boolean operators AND, OR, NOT
– The LIKE operator.

The LIKE operator compares a column value to a
pattern.
– In the pattern the wildcard % represents zero or more
characters.
– The wildcard _ represents a single character.
[email protected]
21
JDBC
[email protected]
22
A Simple Example
import java.sql.* ;
public class ShowStudents {
public static void main(String args[]) throws Exception {
System.setProperty(“jdbc.drivers”,
“oracle.jdbc.driver.OracleDriver”) ;
String url = “jdbc:oracle:thin:@sirah.csit.fsu.edu:1521:oralin” ;
Connection conn =
DriverManager.getConnection(url, “dbc”, “ . . . ”) ;
Statement stat = conn.createStatement() ;
ResultSet rs = stat.executeQuery(“SELECT * FROM students”) ;
while(rs.next())
System.out.println(rs.getString(1) + “ ” +
rs.getString(2) + “ ” + rs.getString(3))
;
conn.close() ;
}
}
[email protected]
23
Remarks


To compile and run this example you must have the
JDBC driver code on your class path.
On the course hosts, add
/usr/oracle/jdbc/lib/classes111.zip
to your CLASSPATH. For example you might add the
line
export CLASSPATH=$CLASSPATH:\
$ORACLE_HOME/jdbc/lib/classes111.zip
to the end of you .bashrc file.
[email protected]
24
Running ShowStudents

If we run ShowStudents we may see something like:
sirah$ java ShowStudents
wcao Cao CSIT
Flora Flora EE
Fulay Fulay CS
zyr98210 Zhang CS
jin0328 Zhang CS

Effect is essentially like typing the command
select * from students ;
directly into the SQL*Plus interpreter.
[email protected]
25
Classes in the Example

The example introduces the following classes and
interfaces from java.sql:
DriverManager
Manages a set of JDBC drivers.
Connection
A connection or session with a specific database. Context in
which SQL statements are executed and results returned.
Statement
Object used for executing an SQL statement.
ResultSet
Provides access to a table of data generated by executing a
statement.
[email protected]
26
The Driver Manager




The driver manager sits between the JDBC application
and one or more JDBC drivers.
A JDBC driver contains vendor-specific code to interface
to a particular back-end database.
On initialization, the class DriverManager will try to load
driver classes referenced in the jdbc.drivers property.
One can also load JDBC drivers explicitly, e.g.:
Class.forName(“oracle.jdbc.driver.OracleDriver”) ;
[email protected]
27
Making a Connection

There are several getConnection() methods on
DriverManager with different argument lists. The one
we will use is:
static Connection getConnection(String url,
String username,
String password)

Before you can use this method, you will, of course,
need an account on the database concerned.
– The username and password are associated with the database
(not your UNIX account!)
[email protected]
28
Database URLs

Ideally the syntax of the URL would follow the normal
conventions for Internet URLs:
protocol // host : port / name
– protocol will be a sub-protocol of jdbc:, e.g.
jdbc:oracle:thin:
– host and port are self-explanatory.
– name is the name of the database on the host.

Oracle JDBC URLs follow this general pattern, but they
use different separators.
– @ and : in place of // and /.
[email protected]
29
The Connection Interface


The Connection interface includes many methods.
Our first example only uses two simple ones:
Statement createStatement()
Creates a Statement object for sending SQL statements to the
database.
void close()
Releases database connection and associated JDBC
resources.
[email protected]
30
The Statement Interface


Object used for executing an SQL statement.
The most important methods for us will be:
ResultSet executeQuery(String sql) throws SQLException
Executes an SQL statement that returns a single result set.
Typically sql will be a SELECT statement.
int executeUpdate(String sql) throws SQLException
Executes an SQL statement that returns nothing. Typically sql
will be an INSERT, UPDATE or DELETE statement. Result is
number rows modified.


Note only one ResultSet can exist per Statement. If
you need to interleave queries, use multiple Statement
objects.
Other useful methods:
– addBatch(), executeBatch() to batch several SQL commands.
[email protected]
31
The ResultSet Interface



A result set behaves something like an Enumeration or
Iterator. This allows to iterate over the set of rows
returned by a query.
The next() method is used to move to the first row, then
all subsequent rows.
There is a large number of methods of the form:
XXX getXXX(int columnIndex)



that extract the contents of a column in the current row.
The one we will use most is getString(), which
interprets the column as a String.
Note columnIndex starts at 1, not zero.
ResultSet has many other methods. Many were added
in JDBC 2.0.
[email protected]
32
Example: Web Front End to SQL



Will now go through a fairly substantial example that
combines JDBC with servlets.
This Web application will allow a user to connect to an
Oracle account on the server host, and submit arbitrary
SQL commands and queries.
Besides introducing a couple of new JDBC features, it
will illustrate (in more depth than the vending machine
examples) the structure of a Web application involving
multiple servlets.
[email protected]
33
A First Screen

The introductory screen to our application is a static HTML
form, sqlconnect.html:
<html>
<head> . . . </head>
<body>
<h1>Connect to Oracle database</h1>
<form method=post action=“/dbc/servlet/SQLConnect”>
Oracle user name: <input type=text name=username size=20>
<p>
Oracle password: <input type=password name=password
size=20>
<p>
<input type=submit value=“Connect to database”>
</form>
</body>
</html>
[email protected]
34
Remarks



The form prompts for Oracle user name and password.
These are sent using the POST method (for privacy) to
the servlet SQLConnect.
Note the form of the action URL. This is a URL to a the
servlet context /dbc in the same Web server.
[email protected]
35
The SQLConnect servlet
public class SQLConnect extends HttpServlet {
...
public void doPost(HttpServletRequest req,
HttpServletResponse resp) throws . . . {
try {
String username = req.getParameter(“username”) ;
String password = req.getParameter(“password”) ;
HttpSession session = req.getSession(true) ;
Connection conn =
DriverManager.getConnection(url, username,
password) ;
session.setAttribute(“connection”, conn) ;
resp.sendRedirect(
resp.encodeRedirectURL(“/dbc/servlet/SQLCommand”))
;
} catch (SQLException e) {
. . . make suitable sendError() call . . .
}
[email protected]
36
}
Remarks




The essential code creates a servlet session, connects
to the database, and stores the Connection object in the
servlet session.
This done, the browser is redirected to the
SQLCommand servlet.
encodeRedirectURL() is similar to encodeURL(), but
specifically intended for use with a sendRedirect() .
We assume that the driver is loaded by a suitable init()
method, e.g.:
public void init() {
Class.forName(“oracle.jdbc.driver.OracleDriver”) ;
}
and the URL for the database is predefined in a static
variable url.
[email protected]
37
The SQLCommand servlet
public class SQLCommand extends HttpServlet {
public void doGet(HttpServletRequest req,
HttpServletResponse resp) throws . . . {
HttpSession session = req.getSession(true) ;
Connection conn = (Connection)
session.getAttribute(“connection”) ;
if(conn == null)
. . . session probably timed out: call sendError() . . .
else {
resp.setContentType(“text/html”) ;
PrintWriter out = resp.getWriter() ;
out.println(“<html><head></head><body>”) ;
. . . print forms . . .
out.println(“</body></html>”) ;
}
}
}
[email protected]
38
Remarks


The connection is retrieved from the current session, if it
exists.
Otherwise the servlet just prints three forms, for SQL
queries, SQL action commands, and disconnecting,
respectively. . .
[email protected]
39
Printing the Forms
out.println("<form action=" +
resp.encodeURL("/dbc/servlet/SQLQuery") + ">") ;
out.println("<h1>SQL <em>query</em></h1>") ;
out.println("<textarea name=query cols=60 rows=3></textarea><p>") ;
out.println("<input type=submit value=\"Submit Query\">") ;
out.println("</form>");
out.println("<form action=" +
resp.encodeURL("/dbc/servlet/SQLUpdate") + ">") ;
out.println("<h1>SQL <em>update</em></h1>") ;
out.println("<textarea name=update cols=60 rows=3></textarea><p>")
;
out.println("<input type=submit value=\"Submit Update\">") ;
out.println("</form>");
out.println("<form action=" +
resp.encodeURL("/dbc/servlet/SQLClose") + ">") ;
out.println("Close Oracle Connection:") ;
out.println("<input type=submit value=\"Close\">") ;
out.println("</form>");
[email protected]
40
Handling Queries




The most complicated servlet in our application is
SQLQuery.
This will execute an arbitrary SELECT command, and
print out the results as an HTML table.
This presents some special problems because we don’t
know in advance how many columns the result table will
need, or what is the meaning of the entries.
We can cope with this kind of situation using result set
metadata.
[email protected]
41
Result Set Metadata

The ResultSet class has a method:
ResultSetMetaData getMetaData()
that returns a metadata object describing the results.

The only methods on ResultSetMetaData we will use
here are:
int getColumnCount()
returns the number of columns in the result set.
String getColumnLabel(int columnIndex)
returns a suggested label for use in printouts.
[email protected]
42
The SQLQuery servlet
public class SQLQuery extends HttpServlet {
public void doGet(HttpServletRequest req,
HttpServletResponse resp) throws . . . {
HttpSession session = req.getSession(true) ;
Connection conn = (Connection)
session.getAttribute(“connection”) ;
if(conn == null)
. . . session probably timed out: call sendError() . . .
else {
String query = req.getParameter(“query”) ;
try {
Statement stat = conn.createStatement() ;
ResultSet rs = stat.executeQuery(query) ;
. . . generate response . . .
} catch (SQLException e) {
. . . make suitable sendError() call . . .
}
}
[email protected]
}
43
Remarks


This servlet gets the SQL query command from the form
data, creates a Statement, and executes the query.
The non-trivial work is in generating the HTML
response. . .
[email protected]
44
Generating the Response
ResultSetMetaData rsmd = rs.getMetaData() ;
int cols = rsmd.getColumnCount() ;
. . . set response content type, print HTML headers . . .
out.println("<table border cellspacing=0 cellpadding=5>") ;
out.println("<tr bgcolor=lightblue>") ; // print column headers
for(int i = 1 ; i <= cols ; i++)
out.println("<td>" + rsmd.getColumnLabel(i) + "</td>") ;
out.println("</tr>") ;
while(rs.next()) {
// print the rows
out.println("<tr>") ;
for(int i = 1 ; i <= cols ; i++)
out.println("<td>" + rs.getString(i) + "</td>") ;
out.println("</tr>") ;
}
out.println("</table>") ;
. . . print HTML footers . . .
[email protected]
45
Remarks

The complete code generates a couple of form buttons
at the end of the HTML page, giving the option to submit
another command (go back to the SQLCommand
servlet) or close the connection (go to the SQLClose
servlet).
[email protected]
46
Action Statements

The last two servlets are relatively simple.

SQLUpdate has a similar structure to SQLQuery but it
reads the update parameter, and executes the
command by:
String update = req.getParameter(“update”) ;
try {
Statement stat = conn.createStatement() ;
int rows = stat.executeUpdate(update) ;
. . . generate response . . .
} catch (. . .) { . . .}

SQLClose calls conn.close() then redirects the
browser back to the sqlconnect.html page.
[email protected]
47
Submitting a Command
[email protected]
48
The Response
[email protected]
49
An Elementary “3-tier” Application
[email protected]
50
A Student Database





The application is highly simplified, but it illustrates a
form-based interface to an Oracle database on a server,
with a servlet “middle-tier”.
It is more developed than the preceding SQL frontend—it doesn’t require the client to actually type SQL
commands and interpret the results!
It uses session tracking to implement an “undo” feature
for updates.
It also illustrates a new feature of the servlet sessiontracking API—session binding listeners.
Otherwise it is quite limited:
– It doesn’t include features to add or delete records, only to
modify existing records.
– The user interface is not very pretty.
[email protected]
51
Creating the Table



As a preliminary, we need to create the initial state for
database table.
This is a management task for our Web application—not
part of the online functionality.
Nevertheless it is quite convenient to write a Java
program to create the table.
[email protected]
52
Java “Script” to Create Table
class MakeTable implements DBConstants {
public static void main(String args[]) throws Exception {
. . . Load driver . . .
Connection conn =
DriverManager.getConnection(url, username, password);
Statement stat = conn.createStatement();
stat.executeUpdate(
"CREATE TABLE " + table + " (" +
"login VARCHAR(10)," +
"lastname VARCHAR(20)," +
"firstnames VARCHAR(20)," +
"email VARCHAR(50)," +
"dept VARCHAR(5)" +
")"
);
. . . Add entries to table . . .
conn.close();
}
}
[email protected]
53
Adding the Entries
BufferedReader in = new BufferedReader(new FileReader(table)) ;
String login, lastname, firstnames, email, dept ;
login = in.readLine() ;
while(login != null) {
lastname = in.readLine() ;
firstnames = in.readLine() ;
email
= in.readLine() ;
dept
= in.readLine() ;
stat.executeUpdate(
"INSERT INTO " + table +
" VALUES ('" + login + "', '" + lastname + "', '" + firstnames + "', "
+
"'" + email + "', '" + dept + "')"
);
in.readLine() ; // skip blank line ;
login = in.readLine() ;
}
[email protected]
54
Remarks


This assumes the initial data is stored in a file having
the same name as the table to be created.
Various constants associated with the database account
and table are stored in the DBConstants interface, e.g.:
public interface DBConstants {
static final String url =
“jdbc:oracle:thin:@sirah.csit.fsu.edu:1521:oralin” ;
static final String username = “dbc” ;
static final String password = “ . . . ” ;
static final String table
= “it1fall00” ;
}
[email protected]
55
The Servlets



This particular application consists of several servlets
and associated classes.
We will collect them together into a new context in our
Web server, under the path /students.
In conf/server.xml we add the lines:
<Context path=“/students” docBase=“webapps/students”
debug=“0” reloadable=“true”>
</Context>
and create the associated document directories (see
the lecture on configuring the Tomcat server).
[email protected]
56
Selection Page





The “main” page of our application offers a list of “keys”
to select from—in our case student login IDs.
This page is generated by a servlet called Select.
This servlet checks session data is in order and
retrieves or creates an object of auxiliary class
DBSession, which we use to manage the database
connection.
It extracts to column of login IDs from the table.
Finally it generates the HTML for the displayed page.
[email protected]
57
Overview of Select servlet
public class Select extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws . . .
{
try {
DBSession dbs ;
. . . Initialize session, and extract dbs.
ResultSet rs = dbs.stat.executeQuery(
"SELECT login FROM " + DBConstants.table
);
. . . Generate response . . .
} catch (SQLException e) {
response.sendError(HttpServletResponse.SC_OK,
"SQL error: " + e.getMessage()) ;
}
}
[email protected]
58
}
Initializing the Session
HttpSession session = request.getSession(true) ;
dbs = (DBSession) session.getAttribute("dbs") ;
if(dbs == null) {
// Session new or timed out
dbs = new DBSession() ;
session.setAttribute("dbs", dbs) ;
session.setMaxInactiveInterval(300) ; // 5 minutes.
}


We don’t want to accumulate many idle database
connections, so we explicitly set a relatively short timeout interval for the session.
The DBSession constructor creates a database
connection. The object then stores the Connection
object and a reusable Statement object.
[email protected]
59
The DBSession class
public class DBSession implements
HttpSessionBindingListener, DBConstants {
static {
Class.forName("oracle.jdbc.driver.OracleDriver") ;
}
DBSession() throws SQLException {
conn = DriverManager.getConnection(url, username,
password);
stat = conn.createStatement();
}
public void valueBound(HttpSessionBindingEvent evt) {}
public void valueUnbound(HttpSessionBindingEvent evt) {
try {
conn.close() ;
} catch (SQLException e) {} // Not much to be done about it.
}
public Connection conn ;
public Statement stat ;
}
[email protected]
60
Remarks





The most interesting feature of this class is that it
implements HttpSessionBindingListener.
The event-handling method valueBound() is invoked
whenever this object is bound to a session using
setAttribute().
The method valueUnbound() is invoked whenever this
object is unbound from a session, either by
removeAttribute() or (more importantly) when the
session is invalidated (e.g. when it times out).
This ensures that the database connection is closed
promptly (and not left to the garbage collector).
The class also illustrates use of a static initialization
clause.
[email protected]
61
Generating the Response
response.setContentType("text/html");
PrintWriter out = response.getWriter();
. . . print HTML headers . . .
out.println("<form action=" +
response.encodeURL("/students/servlet/View") +
">") ;
out.println("Select by ID:<br>") ;
out.println("<select name=login size=15>") ;
while(rs.next())
out.println("<option> " + rs.getString(1)) ;
out.println("</select>") ;
out.println("View selected record: " +
"<input type=submit value=\"View\">") ;
out.println("</form>");
. . . print HTML footers . . .
[email protected]
62
Remarks

This mainly just prints a form containing big select
element holding all the key values from the result set.
[email protected]
63
Viewing and Modifying Record






The viewing page displays all the fields in the selected
record in a form that allows them to be modified, if
desired.
This page is generated by a servlet called View.
The session handling is similar to Select (at this point if
the session has timed out we simply create a new one).
The servlet extracts the row associated with the
selected login ID.
For future reference, it saves the current value of the
fields in the session object.
It generates the HTML for the displayed page.
[email protected]
64
Overview of the View servlet
public class View extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws . . .
{
try {
DBSession dbs ;
. . . Initialize session, and extract dbs.
String login, lastname, firstnames, email, dept ;
login = request.getParameter("login") ; // Get the key string
if(login == null) { . . . Call sendError() . . . }
. . . Query the database, and extract values lastname, etc. . . .
session.setAttribute("curr",
new Student(login, lastname, firstnames, email,
dept)) ;
. . . Generate updateable display of current record . . .
} catch (SQLException e) {
. . . Call sendError() . [email protected]
..
65
}
Remarks

The Student class defines a simple object that just
holds 5 public fields.
[email protected]
66
Querying the Database
ResultSet rs = dbs.stat.executeQuery(
"SELECT * FROM " + DBConstants.table + " " +
"WHERE login=’ " + login + “ ’ ”
);
if(rs.next()) {
lastname = rs.getString(2) ;
firstnames = rs.getString(3) ;
email
= rs.getString(4) ;
dept
= rs.getString(5) ;
} else {
response.sendError(HttpServletResponse.SC_OK,
"Record not found") ;
return ;
}
[email protected]
67
Generating the Response
response.setContentType("text/html");
PrintWriter out = response.getWriter();
. . . Print HTML headers . . .
out.println("<form method=post action=" +
response.encodeURL("/students/servlet/Update") + ">")
;
out.println("Login ID: " +
"<input type=text size=10 name=login value=\"" +
login + "\"><br>") ;
out.println("Last Name: " +
"<input type=text size=20 name=lastname value=\"" +
lastname +"\"><br>") ;
. . . etc... Input elements for the other three fields . . .
out.println("<br>Update this record: " +
"<input type=submit value=Update>") ;
out.println("</form>");
. . . Print small alternate form to return to selection page . . .
[email protected]
68
. . . Print HTML footers . . .
Updating the Database



This is handled by a servlet that normally generates no
output. When it is finished it just redirects the browser
back to the selection page.
The session handling is slightly different to Select. In
this case if the servlet cannot find a current session it
will report an error.
The servlet updates the row associated with the
selected login ID.
[email protected]
69
Overview of the Update Servlet
public class Update extends HttpServlet {
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws . . .
{
try {
DBSession dbs ;
Student curr ;
. . . Extract dbs, curr from the session object . . .
. . . Update row in database . . .
. . . Build a command to undo the update, and save it . . .
response.sendRedirect(
response.encodeRedirectURL("/students/servlet/Select"));
} catch (SQLException e) {
. . . Call sendError() . . .
}
}
}
[email protected]
70
Extracting Session Data
HttpSession session = request.getSession(true) ;
DBSession dbs = (DBSession)
session.getAttribute("dbs") ;
Student curr
= (Student) session.getAttribute("curr") ;
if(dbs == null || curr == null) {
response.sendError(HttpServletResponse.SC_OK,
"Session timed out. Please resubmit form.") ;
return ;
}

In this case it is difficult to proceed without the session
data.
[email protected]
71
Updating the Row
String login
= request.getParameter("login") ;
String lastname = request.getParameter("lastname") ;
String firstnames = request.getParameter("firstnames") ;
String email
= request.getParameter("email") ;
String dept
= request.getParameter("dept") ;
dbs.stat.executeUpdate(
"UPDATE " + DBConstants.table + " SET " +
"login=’ "
+ login
+ “', " +
"lastname=’ " + lastname + “', " +
"firstnames=’ " + firstnames + “', " +
"email=’ "
+ email
+ “', " +
"dept=’ "
+ dept
+ “' " +
"WHERE login=’ " + curr.login + “'”
);
[email protected]
72
Building an “Undo” Command
String sql = "UPDATE " + DBConstants.table + " SET " +
"login='"
+ curr.login
+ "', " +
"lastname='" + curr.lastname + "', " +
"firstnames='" + curr.firstnames + "', " +
”email='"
+ curr.email
+ "', " +
"dept='"
+ curr.dept
+ "' " +
"WHERE login='" + login + "'" ;
Vector undoList = (Vector)
session.getAttribute("undoList") ;
if(undoList == null) {
undoList = new Vector() ;
session.setAttribute("undoList", undoList) ;
}
undoList.addElement(sql) ;
[email protected]
73
Remarks


The “undo” command will reverse the effect of the
update.
It is not executed here: it is added to a stack held in the
session.
[email protected]
74
An Undo Button

To complete the application we generate the following
extra form in the Select servlet:
Vector undoList = (Vector)
session.getAttribute("undoList") ;
if (undoList != null && undoList.size() > 0) {
out.println("<form action=" +
response.encodeURL("/students/servlet/Undo") +
">") ;
out.println("Undo most recent change: " +
"<input type=submit value=\"Undo\">") ;
out.println("</form>");
}

The Undo servlet just retrieves the undoList from the
session and does:
int last = undoList.size() - 1 ;
[email protected] undoList.remove(last)) ; 75
dbs.stat.executeUpdate((String)