User interfaces to applications has changed over the last 30 years.
The traditional text/console/VT user interface are mostly gone.
The traditional client GUI application became popular (VB6, Delphi etc.) but is today most common on phones and tablets - not desktop computers.
By far the most common user interface today is web/browser based.
The average age of applications on VMS is way higher than on Windows/Linux and many VMS applications predate web and browsers. But still a web/browser based user interface is relevant if the application need to be modernized.
The article will present a number of technologies for creating web applications.
The technologies will be presented in approximate chronological order. That makes sense because a new technology is often designed to avoid problems found in the previous technology, so understanding the previous technology gives a better understanding of current technology.
Note that as a general rule then the newer more advanced more complex web frameworks are better for big web applications. But for small web applications, then an older but simpler technology may be just fine.
Newer web applications typical use one of:
ASP.NET and node.js are currently not available on VMS.
Java, PHP and Python are available on VMS. Python is not yet available for VMS x86-64 though.
This article will show examples in older technology (CGI in traditional VMS languages), Java and PHP.
There are an overrepresentation of Java based solutions as I simply know those better.
All of these frameworks are huge and this article is not a tutorial on all of them. This article just provide an appetizer to show what is available on VMS and to give the reader an overview that makes it possible to pick the right technology. After chosing a technology then studying a tutorial is recommended (unless the reader already knows the technology from other platforms.
All examples will follow the simple model.
Data as rows of T1 with fields F1 integer and F2 string length 32.
Index-sequential file create:
$ create/fdl=sys$input db.isq
FILE
ORGANIZATION indexed
RECORD
FORMAT fixed
SIZE 36
KEY 0
SEG0_LENGTH 4
SEG0_POSITION 0
TYPE int4
$
Since DCL cannot use integer keys the DCL examples will use:
isq2.com:
$ create/fdl=sys$input db2.isq
FILE
ORGANIZATION indexed
RECORD
FORMAT fixed
SIZE 36
KEY 0
SEG0_LENGTH 4
SEG0_POSITION 0
TYPE string
$
MySQL create:
CREATE TABLE t1 (
f1 INTEGER NOT NULL,
f2 VARCHAR(50),
PRIMARY KEY (f1)
);
The flow will be:
When the web was new then no web-specific languages or frameworks existed.
All that existed was the web server and the CGI protocol for communication between the web server and external scripts.
So web applications was done in the same languages as other types of applications. Perl, C, DCL, Cobol, Fortran etc..
And because the languages was not web specific then web applications outputted HTML markup similar to how previous applications had outputted console output (possible with VT escape sequences for formatting).
We will see examples using an index-sequential file and examples using a MySQL database for data.
Fundamentally CGI is a standard and a CGI script should work identical across web servers - in this case Apache and OSU.
In reality there are a few differences:
We will see examples in Pascal, Basic and Cobol.
Apache:
isq.pas:
type
pstr = varying [255] of char;
char32 = packed array [1..32] of char;
t1 = packed record
f1 : integer;
f2 : char32;
end;
t1file = file of t1;
function trim(s : char32) : pstr;
var
i : integer;
begin
i := length(s);
while (i > 0) and (s[i] = ' ') do i := i - 1;
trim := substr(s, 1, i);
end;
isqshow.pas:
program isqshow(input, output);
%include 'isq.pas'
var
db : t1file;
f1 : integer;
f2 : pstr;
begin
writeln('content-type: text/html');
writeln('');
writeln('<html>');
writeln('<head>');
writeln('<title>CGI - Pascal</title>');
writeln('</head>');
writeln('<body>');
writeln('<h1>CGI - Pascal</body>');
writeln('<h2>Show:</h2>');
writeln('<table border="1">');
writeln('<tr>');
writeln('<th>F1</th>');
writeln('<th>F2</th>');
writeln('</tr>');
open(db, 'disk5:[cgi.apache]db.isq', old, organization := indexed, access_method := keyed);
reset(db);
while not(eof(db)) do begin
f1 := db^.f1;
f2 := trim(db^.f2);
writeln('<tr>');
writeln('<td>', f1:1, '</td>');
writeln('<td>', f2, '</td>');
writeln('<td><a href="/cgi-bin/isqdel?f1=', f1:1, '">Delete</a></td>');
writeln('</tr>');
get(db);
end;
close(db);
writeln('</table>');
writeln('<h2>Add:</h2>');
writeln('<form method="post" action="/cgi-bin/isqadd">');
writeln('F1: <input type="text" name="f1">');
writeln('<br>');
writeln('F2: <input type="text" name="f2">');
writeln('<br>');
writeln('<input type="submit" value="Add">');
writeln('</form>');
writeln('</body>');
writeln('</html>');
end.
isqadd.pas:
program isqadd(input, output);
%include 'isq.pas'
const
EXTRA = chr(13) + chr(10);
var
db : t1file;
f : text;
line : varying [1000] of char;
ix1, ix2 : integer;
form_f1, form_f2 : varying [255] of char;
f1 : integer;
f2 : pstr;
begin
open(f, 'apache$input', old);
reset(f);
readln(f, line);
close(f);
ix1 := index(line, 'f1=') + 3;
ix2 := index(line + '&', '&');
form_f1 := substr(line, ix1, ix2 - ix1);
readv(form_f1, f1);
line := substr(line, ix2 + 1, line.length - ix2);
ix1 := index(line, 'f2=') + 3;
ix2 := index(line + '&', '&');
form_f2 := substr(line, ix1, ix2 - ix1);
f2 := form_f2;
open(db, 'disk5:[cgi.apache]db.isq', old, organization := indexed, access_method := keyed);
reset(db);
db^.f1 := f1;
db^.f2 := f2;
put(db);
close(db);
writeln('Location: http://arne1.vajhoej.dk/cgi-bin/isqshow', EXTRA);
writeln(EXTRA);
end.
isqdel.pas:
[inherit('sys$library:pascal$lib_routines')]
program isqdel(input, output);
%include 'isq.pas'
const
EXTRA = chr(13) + chr(10);
var
db : t1file;
q, q_f1 : varying [255] of char;
f1 : integer;
begin
lib$get_symbol('QUERY_STRING', q.body, q.length);
q_f1 := substr(q, 4, q.length - 3);
readv(q_f1, f1);
open(db, 'disk5:[cgi.apache]db.isq', old, organization := indexed, access_method := keyed);
reset(db);
findk(db, 0, f1);
delete(db);
close(db);
writeln('Location: http://arne1.vajhoej.dk/cgi-bin/isqshow', EXTRA);
writeln(EXTRA);
end.
Start URL: http://nodename:port/cgi-bin/isqshow
isq.bas:
record t1
integer f1
string f2 = 32
end record
isqshow.bas:
program isqshow
option type = explicit
%include "isq.bas"
map (t1buf) t1 buf
declare integer f1
declare string f2
print "content-type: text/html"
print ""
print "<html>"
print "<head>"
print "<title>CGI - Basic</title>"
print "</head>"
print "<body>"
print "<h1>CGI - Basic</body>"
print "<h2>Show:</h2>"
print "<table border='1'>"
print "<tr>"
print "<th>F1</th>"
print "<th>F2</th>"
print "</tr>"
open "disk5:[cgi.apache]db.isq" as file #1, indexed fixed, map t1buf, primary key buf::f1
handler eof_handler
end handler
when error use eof_handler
while 1 = 1
get #1
print "<tr>"
print using "<td>#</td>", buf::f1
print using "<td>'E</td>", buf::f2
print using "<td><a href='E/cgi-bin/isqdel?f1=#'E>Delete</a></td>", "'", buf::f1, "'"
print "</tr>"
next
end when
close #1
print "</table>"
print "<h2>Add:</h2>"
print "<form method='post' action='/cgi-bin/isqadd'>"
print "F1: <input type='text' name='f1'>"
print "<br>"
print "F2: <input type='text' name='f2'>"
print "<br>"
print "<input type='submit' value='Add'>"
print "</form>"
print "</body>"
print "</html>"
end program
isqadd.bas:
program isqadd
option type = explicit
%include "isq.bas"
map (t1buf) t1 buf
declare integer f1, ix1, ix2
declare string f2, form_f1, form_f2
map (buf) string lin = 1000
open "apache$input" for input as file #1, map buf
get #1
close #1
ix1 = instr(1, lin, "f1=") + 3
ix2 = instr(1, lin + "&", "&")
form_f1 = mid(lin, ix1, ix2 - ix1)
f1 = integer(form_f1)
lin = mid(lin, ix2 + 1, len(lin) - ix2)
ix1 = instr(1, lin, "f2=") + 3
ix2 = instr(1, lin + "&", "&")
form_f2 = mid(lin, ix1, ix2 - ix1)
f2 = form_f2
open "disk5:[cgi.apache]db.isq" as file #1, indexed fixed, map t1buf, primary key buf::f1
buf::f1 = f1
buf::f2 = f2
put #1
close #1
print "Location: http://arne1.vajhoej.dk/cgi-bin/isqshow" + chr$(13)
print chr$(10) + ""
end program
isqdel.bas:
program isqdel
option type = explicit
%include "isq.bas"
external sub lib$get_symbol(string, string)
map (t1buf) t1 buf
declare integer f1
declare string q, q_f1
call lib$get_symbol('QUERY_STRING', q)
q_f1 = mid(q, 4, len(q) - 3)
f1 = integer(q_f1)
open "disk5:[cgi.apache]db.isq" as file #1, indexed fixed, map t1buf, primary key buf::f1
find #1, key #0 eq f1
delete #1
close #1
print "Location: http://arne1.vajhoej.dk/cgi-bin/isqshow" + chr$(13)
print chr$(10) + ""
end program
Start URL: http://nodename:port/cgi-bin/isqshow
isq.cob:
fd db-file.
01 t1.
03 f1 pic s9(8) comp.
03 f2 pic x(32).
isqshow.cob:
identification division.
program-id.isqshow.
*
environment division.
input-output section.
file-control.
select db-file assign to "disk5:[cgi.apache]db.isq" organization is indexed access mode is dynamic record key is f1.
*
data division.
file section.
copy "isq.cob".
working-storage section.
01 eof-flag pic x.
01 f1-print pic 9(8) display.
*
procedure division.
main-paragraph.
display "content-type: text/html"
display ""
display "<html>"
display "<head>"
display "<title>CGI - Cobol</title>"
display "</head>"
display "<body>"
display "<h1>CGI - Cobol</body>"
display "<h2>Show:</h2>"
display "<table border='1'>"
display "<tr>"
display "<th>F1</th>"
display "<th>F2</th>"
display "</tr>"
open i-o db-file
move 0 to f1
start db-file key is greater than f1
invalid key display "Error rewinding"
not invalid key continue
end-start
move 'N' to eof-flag
perform until eof-flag = 'Y'
read db-file next
at end move 'Y' to eof-flag
not at end perform display-paragraph
end-read
end-perform
close db-file
display "</table>"
display "<h2>Add:</h2>"
display "<form method='post' action='/cgi-bin/isqadd'>"
display "F1: <input type='text' name='f1'>"
display "<br>"
display "F2: <input type='text' name='f2'>"
display "<br>"
display "<input type='submit' value='Add'>"
display "</form>"
display "</body>"
display "</html>"
stop run.
display-paragraph.
move f1 to f1-print
display "<tr>"
display "<td>" f1-print "</td>"
display "<td>" f2 "</td>"
display "<td><a href='/cgi-bin/isqdel?f1=" f1-print "'>Delete</a></td>"
display "</tr>".
isqadd.cob:
identification division.
program-id.isqadd.
*
environment division.
input-output section.
file-control.
select db-file assign to "disk5:[cgi.apache]db.isq" organization is indexed access mode is dynamic record key is f1.
select in-file assign to "apache$input" organization is line sequential.
*
data division.
file section.
fd in-file.
01 in-record.
03 lin pic x(1000).
copy "isq.cob".
working-storage section.
01 i pic s9(8) comp.
01 f1-tag pic x(3) value is "f1=".
01 f2-tag pic x(3) value is "f2=".
01 delim-tag pic x(1) value is "&".
01 ix1 pic s9(8) comp.
01 ix2 pic s9(8) comp.
01 form-f1 pic s9(8) comp.
01 form-f2 pic x(32).
*
procedure division.
main-paragraph.
open input in-file
read in-file
at end display "No form data"
not at end continue
end-read
close in-file
perform varying i from 1 by 1 until lin(i:1) = " "
continue
end-perform
move "&" to lin(i:1)
call "str$position"
using
by descriptor lin
by descriptor f1-tag
giving
ix1
end-call
compute ix1 = ix1 + 3
call "str$position"
using
by descriptor lin
by descriptor delim-tag
giving
ix2
end-call
move lin(ix1:ix2 - ix1) to form-f1
move lin(ix2 + 1:1000 - ix2 - 1) to lin
call "str$position"
using
by descriptor lin
by descriptor f2-tag
giving
ix1
end-call
compute ix1 = ix1 + 3
call "str$position"
using
by descriptor lin
by descriptor delim-tag
giving
ix2
end-call
move lin(ix1:ix2 - ix1) to form-f2
open i-o db-file
move form-f1 to f1
move form-f2 to f2
write t1
invalid key display "Error writing"
not invalid key continue
end-write.
close db-file
display "Location: http://arne1.vajhoej.dk/cgi-bin/isqshow" function char(14) function char(11)
display ""
stop run.
isqdel.cob:
identification division.
program-id.isqdel.
*
environment division.
input-output section.
file-control.
select db-file assign to "disk5:[cgi.apache]db.isq" organization is indexed access mode is dynamic record key is f1.
*
data division.
file section.
copy "isq.cob".
working-storage section.
01 q-sym pic x(12) value is "QUERY_STRING".
01 q pic x(12).
01 q-len pic s9(8) comp.
01 q-f1 pic x(9).
*
procedure division.
main-paragraph.
call "lib$get_symbol"
using
by descriptor q-sym
by descriptor q
by reference q-len
move q(4:q-len - 3) to q-f1
compute q-len = q-len - 3
move q-f1(1:q-len) to f1
open i-o db-file
delete db-file
invalid key display "Error deleting"
not invalid key continue
end-delete
close db-file
display "Location: http://arne1.vajhoej.dk/cgi-bin/isqshow" function char(14) function char(11)
display ""
stop run.
Start URL: http://nodename:port/cgi-bin/isqshow
isqshow2.com:
$ write sys$output "content-type: text/html"
$ write sys$output ""
$ write sys$output "<html>"
$ write sys$output "<head>"
$ write sys$output "<title>CGI - DCL</title>"
$ write sys$output "</head>"
$ write sys$output "<body>"
$ write sys$output "<h1>CGI - DCL</body>"
$ write sys$output "<h2>Show:</h2>"
$ write sys$output "<table border='1'>"
$ write sys$output "<tr>"
$ write sys$output "<th>F1</th>"
$ write sys$output "<th>F2</th>"
$ write sys$output "</tr>"
$ open db disk5:[cgi.apache]db2.isq
$ loop:
$ read/end=endloop db rec
$ write sys$output "<tr>"
$ f1 = f$edit(f$extract(0, 4, rec), "trim")
$ f2 = f$edit(f$extract(4, f$length(rec) - 4, rec), "trim")
$ write sys$output "<td>" + f1 + "</td>"
$ write sys$output "<td>" + f2 + "</td>"
$ write sys$output "<td><a href='/cgi-bin/isqdel2?f1=" + f1 + "'>Delete</a></td>"
$ write sys$output "</tr>"
$ goto loop
$ endloop:
$ close db
$ write sys$output "</table>"
$ write sys$output "<h2>Add:</h2>"
$ write sys$output "<form method='post' action='/cgi-bin/isqadd2'>"
$ write sys$output "F1: <input type='text' name='f1'>"
$ write sys$output "<br>"
$ write sys$output "F2: <input type='text' name='f2'>"
$ write sys$output "<br>"
$ write sys$output "<input type='submit' value='Add'>"
$ write sys$output "</form>"
$ write sys$output "</body>"
$ write sys$output "</html>"
$ exit
isqadd2.com:
$ open f apache$input
$ read f line
$ close f
$ temp = f$extract(3, f$length(line) - 3, line)
$ ix = f$locate("&", temp)
$ f1 = f$extract(0, ix, temp)
$ temp = f$extract(ix + 1, f$length(temp) - ix, temp)
$ f2 = f$extract(3, f$length(temp) - 3, temp)
$ rec = f$extract(0, 4 - f$length(f1), " ") + f1 + f2 + f$extract(0, 32 - f$length(f2), " ")
$ open/read/write db disk5:[cgi.apache]db2.isq
$ write db rec
$ close db
$ crlf[0,8] = 13
$ crlf[8,8] = 10
$ write sys$output "Location: http://arne1.vajhoej.dk/cgi-bin/isqshow2" + crlf
$ write sys$output "" + crlf
$ exit
isqdel2.com:
$ q = "''QUERY_STRING'"
$ f1 = f$extract(3, f$length(q) - 3, q)
$ realf1 = f$extract(0, 4 - f$length(f1), " ") + f1
$ open/read/write db disk5:[cgi.apache]db2.isq
$ read/index=0/key="''realf1'"/delete db rec
$ close db
$ crlf[0,8] = 13
$ crlf[8,8] = 10
$ write sys$output "Location: http://arne1.vajhoej.dk/cgi-bin/isqshow2" + crlf
$ write sys$output "" + crlf
$ exit
Start URL: http://nodename:port/cgi-bin/isqshow2
OSU:
isq.pas:
type
pstr = varying [255] of char;
char32 = packed array [1..32] of char;
t1 = packed record
f1 : integer;
f2 : char32;
end;
t1file = file of t1;
function trim(s : char32) : pstr;
var
i : integer;
begin
i := length(s);
while (i > 0) and (s[i] = ' ') do i := i - 1;
trim := substr(s, 1, i);
end;
isqshow.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("isqshow.exe;",f$environment("procedure"))'
$ exit
isqshow.pas:
program isqshow(input, output);
%include 'isq.pas'
var
db : t1file;
f1 : integer;
f2 : pstr;
begin
writeln('content-type: text/html');
writeln('');
writeln('<html>');
writeln('<head>');
writeln('<title>CGI - Pascal</title>');
writeln('</head>');
writeln('<body>');
writeln('<h1>CGI - Pascal</body>');
writeln('<h2>Show:</h2>');
writeln('<table border="1">');
writeln('<tr>');
writeln('<th>F1</th>');
writeln('<th>F2</th>');
writeln('</tr>');
open(db, 'disk5:[cgi.osu]db.isq', old, organization := indexed, access_method := keyed);
reset(db);
while not(eof(db)) do begin
f1 := db^.f1;
f2 := trim(db^.f2);
writeln('<tr>');
writeln('<td>', f1:1, '</td>');
writeln('<td>', f2, '</td>');
writeln('<td><a href="/htbin/isqdel?f1=', f1:1, '">Delete</a></td>');
writeln('</tr>');
get(db);
end;
close(db);
writeln('</table>');
writeln('<h2>Add:</h2>');
writeln('<form method="post" action="/htbin/isqadd">');
writeln('F1: <input type="text" name="f1">');
writeln('<br>');
writeln('F2: <input type="text" name="f2">');
writeln('<br>');
writeln('<input type="submit" value="Add">');
writeln('</form>');
writeln('</body>');
writeln('</html>');
end.
isqadd.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))' www_ form_
$ define sys$output net_link
$ mcr 'f$parse("isqadd.exe;",f$environment("procedure"))'
$ exit
isqadd.pas:
[inherit('sys$library:pascal$lib_routines')]
program isqadd(input, output);
%include 'isq.pas'
var
db : t1file;
form_f1, form_f2 : varying [255] of char;
f1 : integer;
f2 : pstr;
begin
lib$get_symbol('FORM_FLD_F1', form_f1.body, form_f1.length);
readv(form_f1, f1);
lib$get_symbol('FORM_FLD_F2', form_f2.body, form_f2.length);
f2 := form_f2;
open(db, 'disk5:[cgi.osu]db.isq', old, organization := indexed, access_method := keyed);
reset(db);
db^.f1 := f1;
db^.f2 := f2;
put(db);
close(db);
writeln('Location: http://arne1.vajhoej.dk:81/htbin/isqshow');
writeln;
end.
isqdel.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("isqdel.exe;",f$environment("procedure"))'
$ exit
isqdel.pas:
[inherit('sys$library:pascal$lib_routines')]
program isqdel(input, output);
%include 'isq.pas'
var
db : t1file;
q, q_f1 : varying [255] of char;
f1 : integer;
begin
lib$get_symbol('WWW_QUERY_STRING', q.body, q.length);
q_f1 := substr(q, 4, q.length - 3);
readv(q_f1, f1);
open(db, 'disk5:[cgi.osu]db.isq', old, organization := indexed, access_method := keyed);
reset(db);
findk(db, 0, f1);
delete(db);
close(db);
writeln('Location: http://arne1.vajhoej.dk:81/htbin/isqshow');
writeln;
end.
Start URL: http://nodename:port/htbin/isqshow
isq.bas:
record t1
integer f1
string f2 = 32
end record
isqshow.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("isqshow.exe;",f$environment("procedure"))'
$ exit
isqshow.bas:
program isqshow
option type = explicit
%include "isq.bas"
map (t1buf) t1 buf
declare integer f1
declare string f2
print "content-type: text/html"
print ""
print "<html>"
print "<head>"
print "<title>CGI - Basic</title>"
print "</head>"
print "<body>"
print "<h1>CGI - Basic</body>"
print "<h2>Show:</h2>"
print "<table border='1'>"
print "<tr>"
print "<th>F1</th>"
print "<th>F2</th>"
print "</tr>"
open "disk5:[cgi.osu]db.isq" as file #1, indexed fixed, map t1buf, primary key buf::f1
handler eof_handler
end handler
when error use eof_handler
while 1 = 1
get #1
print "<tr>"
print using "<td>#</td>", buf::f1
print using "<td>'E</td>", buf::f2
print using "<td><a href='E/htbin/isqdel?f1=#'E>Delete</a></td>", "'", buf::f1, "'"
print "</tr>"
next
end when
close #1
print "</table>"
print "<h2>Add:</h2>"
print "<form method='post' action='/htbin/isqadd'>"
print "F1: <input type='text' name='f1'>"
print "<br>"
print "F2: <input type='text' name='f2'>"
print "<br>"
print "<input type='submit' value='Add'>"
print "</form>"
print "</body>"
print "</html>"
end program
isqadd.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))' www_ form_
$ define sys$output net_link
$ mcr 'f$parse("isqadd.exe;",f$environment("procedure"))'
$ exit
isqadd.bas:
program isqadd
option type = explicit
%include "isq.bas"
external sub lib$get_symbol(string, string)
map (t1buf) t1 buf
declare integer f1
declare string f2, form_f1, form_f2
call lib$get_symbol('FORM_FLD_F1', form_f1)
f1 = integer(form_f1)
call lib$get_symbol('FORM_FLD_F2', form_f2)
f2 = form_f2
open "disk5:[cgi.osu]db.isq" as file #1, indexed fixed, map t1buf, primary key buf::f1
buf::f1 = f1
buf::f2 = f2
put #1
close #1
print "Location: http://arne1.vajhoej.dk:81/htbin/isqshow"
print ""
end program
isqdel.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("isqdel.exe;",f$environment("procedure"))'
$ exit
isqdel.bas:
program isqdel
option type = explicit
%include "isq.bas"
external sub lib$get_symbol(string, string)
map (t1buf) t1 buf
declare integer f1
declare string q, q_f1
call lib$get_symbol('WWW_QUERY_STRING', q)
q_f1 = mid(q, 4, len(q) - 3)
f1 = integer(q_f1)
open "disk5:[cgi.osu]db.isq" as file #1, indexed fixed, map t1buf, primary key buf::f1
find #1, key #0 eq f1
delete #1
close #1
print "Location: http://arne1.vajhoej.dk:81/htbin/isqshow"
print ""
end program
Start URL: http://nodename:port/htbin/isqshow
isq.cob:
fd db-file.
01 t1.
03 f1 pic s9(8) comp.
03 f2 pic x(32).
isqshow.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("isqshow.exe;",f$environment("procedure"))'
$ exit
isqshow.cob:
identification division.
program-id.isqshow.
*
environment division.
input-output section.
file-control.
select db-file assign to "disk5:[cgi.osu]db.isq" organization is indexed access mode is dynamic record key is f1.
*
data division.
file section.
copy "isq.cob".
working-storage section.
01 eof-flag pic x.
01 f1-print pic 9(8) display.
*
procedure division.
main-paragraph.
display "content-type: text/html"
display ""
display "<html>"
display "<head>"
display "<title>CGI - Cobol</title>"
display "</head>"
display "<body>"
display "<h1>CGI - Cobol</body>"
display "<h2>Show:</h2>"
display "<table border='1'>"
display "<tr>"
display "<th>F1</th>"
display "<th>F2</th>"
display "</tr>"
open i-o db-file
move 0 to f1
start db-file key is greater than f1
invalid key display "Error rewinding"
not invalid key continue
end-start
move 'N' to eof-flag
perform until eof-flag = 'Y'
read db-file next
at end move 'Y' to eof-flag
not at end perform display-paragraph
end-read
end-perform
close db-file
display "</table>"
display "<h2>Add:</h2>"
display "<form method='post' action='/htbin/isqadd'>"
display "F1: <input type='text' name='f1'>"
display "<br>"
display "F2: <input type='text' name='f2'>"
display "<br>"
display "<input type='submit' value='Add'>"
display "</form>"
display "</body>"
display "</html>"
stop run.
display-paragraph.
move f1 to f1-print
display "<tr>"
display "<td>" f1-print "</td>"
display "<td>" f2 "</td>"
display "<td><a href='/htbin/isqdel?f1=" f1-print "'>Delete</a></td>"
display "</tr>".
isqadd.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))' www_ form_
$ define sys$output net_link
$ mcr 'f$parse("isqadd.exe;",f$environment("procedure"))'
$ exit
isqadd.cob:
identification division.
program-id.isqadd.
*
environment division.
input-output section.
file-control.
select db-file assign to "disk5:[cgi.osu]db.isq" organization is indexed access mode is dynamic record key is f1.
select in-file assign to "apache$input" organization is line sequential.
*
data division.
file section.
fd in-file.
01 in-record.
03 lin pic x(1000).
copy "isq.cob".
working-storage section.
01 f1-sym pic x(11) value is "FORM_FLD_F1".
01 f2-sym pic x(11) value is "FORM_FLD_F2".
01 form-f1 pic x(9).
01 form-f2 pic x(32).
01 f1-len pic s9(8) comp.
01 f2-len pic s9(8) comp.
*
procedure division.
main-paragraph.
call "lib$get_symbol"
using
by descriptor f1-sym
by descriptor form-f1
by reference f1-len
end-call
call "lib$get_symbol"
using
by descriptor f2-sym
by descriptor form-f2
by reference f2-len
end-call
open i-o db-file
move form-f1(1:f1-len) to f1
move form-f2(1:f2-len) to f2
write t1
invalid key display "Error writing"
not invalid key continue
end-write.
close db-file
display "Location: http://arne1.vajhoej.dk:81/htbin/isqshow"
display ""
stop run.
isqdel.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("isqdel.exe;",f$environment("procedure"))'
$ exit
isqdel.cob:
identification division.
program-id.isqdel.
*
environment division.
input-output section.
file-control.
select db-file assign to "disk5:[cgi.osu]db.isq" organization is indexed access mode is dynamic record key is f1.
*
data division.
file section.
copy "isq.cob".
working-storage section.
01 q-sym pic x(16) value is "WWW_QUERY_STRING".
01 q pic x(12).
01 q-len pic s9(8) comp.
01 q-f1 pic x(9).
*
procedure division.
main-paragraph.
call "lib$get_symbol"
using
by descriptor q-sym
by descriptor q
by reference q-len
move q(4:q-len - 3) to q-f1
compute q-len = q-len - 3
move q-f1(1:q-len) to f1
open i-o db-file
delete db-file
invalid key display "Error deleting"
not invalid key continue
end-delete
close db-file
display "Location: http://arne1.vajhoej.dk:81/htbin/isqshow"
display ""
stop run.
Start URL: http://nodename:port/htbin/isqshow
isqshow2.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ write sys$output "content-type: text/html"
$ write sys$output ""
$ write sys$output "<html>"
$ write sys$output "<head>"
$ write sys$output "<title>CGI - DCL</title>"
$ write sys$output "</head>"
$ write sys$output "<body>"
$ write sys$output "<h1>CGI - DCL</body>"
$ write sys$output "<h2>Show:</h2>"
$ write sys$output "<table border='1'>"
$ write sys$output "<tr>"
$ write sys$output "<th>F1</th>"
$ write sys$output "<th>F2</th>"
$ write sys$output "</tr>"
$ open db disk5:[cgi.osu]db2.isq
$ loop:
$ read/end=endloop db rec
$ write sys$output "<tr>"
$ f1 = f$edit(f$extract(0, 4, rec), "trim")
$ f2 = f$edit(f$extract(4, f$length(rec) - 4, rec), "trim")
$ write sys$output "<td>" + f1 + "</td>"
$ write sys$output "<td>" + f2 + "</td>"
$ write sys$output "<td><a href='/htbin/isqdel2?f1=" + f1 + "'>Delete</a></td>"
$ write sys$output "</tr>"
$ goto loop
$ endloop:
$ close db
$ write sys$output "</table>"
$ write sys$output "<h2>Add:</h2>"
$ write sys$output "<form method='post' action='/htbin/isqadd2'>"
$ write sys$output "F1: <input type='text' name='f1'>"
$ write sys$output "<br>"
$ write sys$output "F2: <input type='text' name='f2'>"
$ write sys$output "<br>"
$ write sys$output "<input type='submit' value='Add'>"
$ write sys$output "</form>"
$ write sys$output "</body>"
$ write sys$output "</html>"
$ exit
isqadd2.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))' www_ form_
$ define sys$output net_link
$ f1 = "''FORM_FLD_F1'"
$ f2 = "''FORM_FLD_F2'"
$ rec = f$extract(0, 4 - f$length(f1), " ") + f1 + f2 + f$extract(0, 32 - f$length(f2), " ")
$ open/read/write db disk5:[cgi.osu]db2.isq
$ write db rec
$ close db
$ write sys$output "Location: http://arne1.vajhoej.dk:81/htbin/isqshow2"
$ write sys$output ""
$ exit
isqdel2.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ q = "''WWW_QUERY_STRING'"
$ f1 = f$extract(3, f$length(q) - 3, q)
$ realf1 = f$extract(0, 4 - f$length(f1), " ") + f1
$ open/read/write db disk5:[cgi.osu]db2.isq
$ read/index=0/key="''realf1'"/delete db rec
$ close db
$ write sys$output "Location: http://arne1.vajhoej.dk:81/htbin/isqshow2"
$ write sys$output ""
$ exit
Start URL: http://nodename:port/htbin/isqshow2
We will see examples in C, Pascal and Basic.
Apache:
show.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET int
#include <mysql.h>
#define F2_MAX_LEN 50
int main()
{
printf("content-type: text/html\n");
printf("\n");
printf("<html>\n");
printf("<head>\n");
printf("<title>CGI - C</title>\n");
printf("</head>\n");
printf("<body>\n");
printf("<h1>CGI - C</body>\n");
printf("<h2>Show:</h2>\n");
printf("<table border='1'>\n");
printf("<tr>\n");
printf("<th>F1</th>\n");
printf("<th>F2</th>\n");
printf("</tr>\n");
int stat;
MYSQL *con = mysql_init(NULL);
con = mysql_real_connect(con, "localhost", "root", "", "test", 3306, NULL, 0);
MYSQL_STMT *stmt = mysql_stmt_init(con);
char *sqlstr = "SELECT f1,f2 FROM t1";
stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
stat = mysql_stmt_execute(stmt);
MYSQL_BIND out[2];
int f1;
char f2[F2_MAX_LEN + 1];
unsigned long int lenf2;
memset(out, 0, sizeof(out));
out[0].buffer_type = MYSQL_TYPE_LONG;
out[0].buffer = &f1;
out[0].buffer_length = sizeof(f1);
out[1].buffer_type = MYSQL_TYPE_STRING;
out[1].buffer = f2;
out[1].buffer_length = sizeof(f2);
out[1].length = &lenf2;
stat = mysql_stmt_bind_result(stmt, out);
stat = mysql_stmt_store_result(stmt);
while(!mysql_stmt_fetch(stmt))
{
f2[lenf2] = 0;
printf("<tr>\n");
printf("<td>%d</td>\n", f1);
printf("<td>%s</td>\n", f2);
printf("<td><a href='/cgi-bin/del?f1=%d'>Delete</a></td>\n", f1);
printf("</tr>\n");
}
mysql_stmt_free_result(stmt);
mysql_close(con);
printf("</table>\n");
printf("<h2>Add:</h2>\n");
printf("<form method='post' action='/cgi-bin/add'>\n");
printf("F1: <input type='text' name='f1'>\n");
printf("<br>\n");
printf("F2: <input type='text' name='f2'>\n");
printf("<br>\n");
printf("<input type='submit' value='Add'>\n");
printf("</form>\n");
printf("</body>\n");
printf("</html>\n");
return 0;
}
add.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET int
#include <mysql.h>
static char *parse(char *line, char *marker)
{
char *p = strstr(line, marker);
if(p == NULL)
{
return NULL;
}
else
{
char *res = malloc(strlen(line) + 1);
p = p + strlen(marker);
char *p2 = p;
while(*p2 && *p2 != '&') p2++;
memcpy(res, p, p2 - p);
res[p2 - p] = 0;
for(int i = 0; i < strlen(res); i++) if(res[i] == '+') res[i] = ' ';
return res;
}
}
int main()
{
FILE *fp = fopen("apache$input", "r");
char line[1000];
fgets(line, sizeof(line), fp);
fclose(fp);
char *form_f1 = parse(line, "f1=");
char *form_f2 = parse(line, "f2=");
int stat;
MYSQL *con = mysql_init(NULL);
con = mysql_real_connect(con, "localhost", "root", "", "test", 3306, NULL, 0);
MYSQL_STMT *stmt = mysql_stmt_init(con);
char *sqlstr = "INSERT INTO t1 VALUES(?, ?)";
stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
MYSQL_BIND in[2];
int f1 = atoi(form_f1);
char *f2 = form_f2;
memset(in, 0, sizeof(in));
in[0].buffer_type = MYSQL_TYPE_LONG;
in[0].buffer = &f1;
in[0].buffer_length = sizeof(f1);
in[0].is_null= 0;
in[1].buffer_type = MYSQL_TYPE_STRING;
in[1].buffer = f2;
in[1].buffer_length = strlen(f2);
stat = mysql_stmt_bind_param(stmt, in);
stat = mysql_stmt_execute(stmt);
mysql_stmt_free_result(stmt);
mysql_close(con);
char *EXTRA = "\r\n";
printf("Location: http://arne1.vajhoej.dk/cgi-bin/show%s\n", EXTRA);
printf("%s\n", EXTRA);
return 0;
}
del.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET int
#include <mysql.h>
static char *parse(char *line, char *marker)
{
char *p = strstr(line, marker);
if(p == NULL)
{
return NULL;
}
else
{
char *res = malloc(strlen(line) + 1);
p = p + strlen(marker);
char *p2 = p;
while(*p2 && *p2 != '&') p2++;
memcpy(res, p, p2 - p);
res[p2 - p] = 0;
for(int i = 0; i < strlen(res); i++) if(res[i] == '+') res[i] = ' ';
return res;
}
}
int main()
{
char *q = getenv("QUERY_STRING");
char *q_f1 = parse(q, "f1=");
int stat;
MYSQL *con = mysql_init(NULL);
con = mysql_real_connect(con, "localhost", "root", "", "test", 3306, NULL, 0);
MYSQL_STMT *stmt = mysql_stmt_init(con);
char *sqlstr = "DELETE FROM t1 WHERE f1 = ?";
stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
MYSQL_BIND in[1];
int f1 = atoi(q_f1);
memset(in, 0, sizeof(in));
in[0].buffer_type = MYSQL_TYPE_LONG;
in[0].buffer = &f1;
in[0].buffer_length = sizeof(f1);
in[0].is_null= 0;
stat = mysql_stmt_bind_param(stmt, in);
stat = mysql_stmt_execute(stmt);
mysql_stmt_free_result(stmt);
mysql_close(con);
char *EXTRA = "\r\n";
printf("Location: http://arne1.vajhoej.dk/cgi-bin/show%s\n", EXTRA);
printf("%s\n", EXTRA);
return 0;
}
Start URL: http://nodename:port/cgi-bin/show
show.pas:
[inherit('pmysqldir:pmysql', 'pmysqldir:common', 'pmysqldir:mysql')]
program show(input, output);
var
con : mysql_ptr;
stmt : mysql_stmt_ptr;
stat : integer;
outparam : array[1..2] of mysql_bind;
f1 : integer;
f2 : longpstr(255);
begin
writeln('content-type: text/html');
writeln('');
writeln('<html>');
writeln('<head>');
writeln('<title>CGI - Pascal</title>');
writeln('</head>');
writeln('<body>');
writeln('<h1>CGI - Pascal</body>');
writeln('<h2>Show:</h2>');
writeln('<table border="1">');
writeln('<tr>');
writeln('<th>F1</th>');
writeln('<th>F2</th>');
writeln('</tr>');
con := pmysql_init;
con := pmysql_real_connect(con, 'localhost', 'root', '', 'test');
stmt := pmysql_stmt_init(con);
stat := pmysql_stmt_prepare(stmt, 'SELECT f1,f2 FROM t1');
stat := pmysql_stmt_execute(stmt);
pmysql_init_bind_long(outparam[1], f1);
pmysql_init_bind_string_out(outparam[2], f2);
stat := pmysql_stmt_bind_result(stmt, outparam);
stat := pmysql_stmt_store_result(stmt);
while pmysql_stmt_fetch(stmt) = 0 do begin
writeln('<tr>');
writeln('<td>', f1:1, '</td>');
writeln('<td>', stdstr(f2), '</td>');
writeln('<td><a href="/cgi-bin/del?f1=', f1:1, '">Delete</a></td>');
writeln('</tr>');
end;
pmysql_stmt_free_result(stmt);
pmysql_close(con);
writeln('</table>');
writeln('<h2>Add:</h2>');
writeln('<form method="post" action="/cgi-bin/add">');
writeln('F1: <input type="text" name="f1">');
writeln('<br>');
writeln('F2: <input type="text" name="f2">');
writeln('<br>');
writeln('<input type="submit" value="Add">');
writeln('</form>');
writeln('</body>');
writeln('</html>');
end.
add.pas:
[inherit('pmysqldir:pmysql', 'pmysqldir:common', 'pmysqldir:mysql')]
program add(input, output);
const
EXTRA = chr(13) + chr(10);
var
con : mysql_ptr;
stmt : mysql_stmt_ptr;
stat : integer;
inparam : array[1..2] of mysql_bind;
f : text;
line : varying [1000] of char;
ix1, ix2 : integer;
form_f1, form_f2 : varying [255] of char;
f1 : integer;
f2 : pstr;
begin
open(f, 'apache$input', old);
reset(f);
readln(f, line);
close(f);
ix1 := index(line, 'f1=') + 3;
ix2 := index(line + '&', '&');
form_f1 := substr(line, ix1, ix2 - ix1);
readv(form_f1, f1);
line := substr(line, ix2 + 1, line.length - ix2);
ix1 := index(line, 'f2=') + 3;
ix2 := index(line + '&', '&');
form_f2 := substr(line, ix1, ix2 - ix1);
f2 := form_f2;
con := pmysql_init;
con := pmysql_real_connect(con, 'localhost', 'root', '', 'test');
stmt := pmysql_stmt_init(con);
stat := pmysql_stmt_prepare(stmt, 'INSERT INTO t1 VALUES(?, ?)');
pmysql_init_bind_long(inparam[1], f1);
pmysql_init_bind_string_in(inparam[2], f2);
stat := pmysql_stmt_bind_param(stmt, inparam);
stat := pmysql_stmt_execute(stmt);
pmysql_stmt_free_result(stmt);
pmysql_close(con);
writeln('Location: http://arne1.vajhoej.dk/cgi-bin/show', EXTRA);
writeln(EXTRA);
end.
del.pas:
[inherit('sys$library:pascal$lib_routines', 'pmysqldir:pmysql', 'pmysqldir:common', 'pmysqldir:mysql')]
program del(input, output);
const
EXTRA = chr(13) + chr(10);
var
con : mysql_ptr;
stmt : mysql_stmt_ptr;
stat : integer;
inparam : array[1..1] of mysql_bind;
q, q_f1 : varying [255] of char;
f1 : integer;
begin
lib$get_symbol('QUERY_STRING', q.body, q.length);
q_f1 := substr(q, 4, q.length - 3);
readv(q_f1, f1);
con := pmysql_init;
con := pmysql_real_connect(con, 'localhost', 'root', '', 'test');
stmt := pmysql_stmt_init(con);
stat := pmysql_stmt_prepare(stmt, 'DELETE FROM t1 WHERE f1 = ?');
pmysql_init_bind_long(inparam[1], f1);
stat := pmysql_stmt_bind_param(stmt, inparam);
stat := pmysql_stmt_execute(stmt);
pmysql_stmt_free_result(stmt);
pmysql_close(con);
writeln('Location: http://arne1.vajhoej.dk/cgi-bin/show', EXTRA);
writeln(EXTRA);
end.
Start URL: http://nodename:port/cgi-bin/show
show.bas:
program show
option type = explicit
%include "bmysqldir:b.bas"
declare integer dbcon, stmt, outparam
declare integer stat
declare integer f1
declare string f2
print "content-type: text/html"
print ""
print "<html>"
print "<head>"
print "<title>CGI - Basic</title>"
print "</head>"
print "<body>"
print "<h1>CGI - Basic</body>"
print "<h2>Show:</h2>"
print "<table border='1'>"
print "<tr>"
print "<th>F1</th>"
print "<th>F2</th>"
print "</tr>"
dbcon = bmysql_open("localhost", 3306, "root", "", "test")
stmt = bmysql_stmt_prepare(dbcon, "SELECT f1,f2 FROM t1")
outparam = bmysql_outparam_init(2)
call bmysql_outparam_long(outparam, 0, f1)
call bmysql_outparam_string(outparam, 1, f2)
stat = bmysql_stmt_execute(stmt, 0, outparam)
while bmysql_stmt_fetch(stmt, outparam) = 0
print "<tr>"
print using "<td>#</td>", f1
print using "<td>'E</td>", f2
print using "<td><a href='E/cgi-bin/del?f1=#'E>Delete</a></td>", "'", f1, "'"
print "</tr>"
next
call bmysql_outparam_free(outparam)
call bmysql_stmt_free(stmt)
call bmysql_close(dbcon)
print "</table>"
print "<h2>Add:</h2>"
print "<form method='post' action='/cgi-bin/add'>"
print "F1: <input type='text' name='f1'>"
print "<br>"
print "F2: <input type='text' name='f2'>"
print "<br>"
print "<input type='submit' value='Add'>"
print "</form>"
print "</body>"
print "</html>"
end program
add.bas:
program add
option type = explicit
%include "bmysqldir:b.bas"
declare integer dbcon, stmt, inparam
declare integer stat
declare integer f1, ix1, ix2
declare string f2, form_f1, form_f2
map (buf) string lin = 1000
open "apache$input" for input as file #1, map buf
get #1
close #1
ix1 = instr(1, lin, "f1=") + 3
ix2 = instr(1, lin + "&", "&")
form_f1 = mid(lin, ix1, ix2 - ix1)
f1 = integer(form_f1)
lin = mid(lin, ix2 + 1, len(lin) - ix2)
ix1 = instr(1, lin, "f2=") + 3
ix2 = instr(1, lin + "&", "&")
form_f2 = mid(lin, ix1, ix2 - ix1)
f2 = form_f2
dbcon = bmysql_open("localhost", 3306, "root", "", "test")
stmt = bmysql_stmt_prepare(dbcon, "INSERT INTO t1 VALUES(?,?)")
inparam = bmysql_inparam_init(2)
call bmysql_inparam_long(inparam, 0, f1)
call bmysql_inparam_string(inparam, 1, f2)
stat = bmysql_stmt_execute(stmt, inparam, 0)
call bmysql_inparam_free(inparam)
call bmysql_stmt_free(stmt)
call bmysql_close(dbcon)
print "Location: http://arne1.vajhoej.dk/cgi-bin/show" + chr$(13)
print chr$(10) + ""
end program
del.bas:
program xdel
option type = explicit
%include "bmysqldir:b.bas"
external sub lib$get_symbol(string, string)
declare integer dbcon, stmt, inparam
declare integer stat
declare integer f1
declare string q, q_f1
call lib$get_symbol('QUERY_STRING', q)
q_f1 = mid(q, 4, len(q) - 3)
f1 = integer(q_f1)
dbcon = bmysql_open("localhost", 3306, "root", "", "test")
stmt = bmysql_stmt_prepare(dbcon, "DELETE FROM t1 WHERE f1 = ?")
inparam = bmysql_inparam_init(1)
call bmysql_inparam_long(inparam, 0, f1)
stat = bmysql_stmt_execute(stmt, inparam, 0)
call bmysql_inparam_free(inparam)
call bmysql_stmt_free(stmt)
call bmysql_close(dbcon)
print "Location: http://arne1.vajhoej.dk/cgi-bin/show" + chr$(13)
print chr$(10) + ""
end program
Start URL: http://nodename:port/cgi-bin/show
showpy.com:
$ set def disk5:[cgi.apache]
$ python show.py
$ exit
show.py:
import pymysql
print('content-type: text/html')
print('')
print('<html>')
print('<head>')
print('<title>CGI - Python</title>')
print('</head>')
print('<body>')
print('<h1>CGI - Python</body>')
print('<h2>Show:</h2>')
print('<table border="1">')
print('<tr>')
print('<th>F1</th>')
print('<th>F2</th>')
print('</tr>')
con = pymysql.connect(host='localhost',user='root',password='',db='test')
c = con.cursor()
c.execute('SELECT f1,f2 FROM t1')
res = c.fetchall()
for o in res:
f1 = o[0]
f2 = o[1]
print('<tr>')
print('<td>%d</td>' % (f1))
print('<td>%s</td>' % (f2))
print('<td><a href="/cgi-bin/delpy?f1=%s">Delete</a></td>' % (f1))
print('</tr>')
c.close()
con.close()
print('</table>')
print('<h2>Add:</h2>')
print('<form method="post" action="/cgi-bin/addpy">')
print('F1: <input type="text" name="f1">')
print('<br>')
print('F2: <input type="text" name="f2">')
print('<br>')
print('<input type="submit" value="Add">')
print('</form>')
print('</body>')
print('</html>')
addpy.com:
$ set def disk5:[cgi.apache]
$ define/nolog sys$input apache$input
$ python add.py
$ exit
add.py:
import cgi
import pymysql
form = cgi.FieldStorage()
f1 = form['f1'].value
f2 = form['f2'].value
con = pymysql.connect(host='localhost',user='root',password='',db='test')
c = con.cursor()
c.execute('INSERT INTO t1(f1,f2) VALUES(%s,%s)', (f1,f2))
c.close()
con.commit()
con.close()
print('Location: http://arne1.vajhoej.dk/cgi-bin/showpy')
print('')
delpy.com:
$ set def disk5:[cgi.apache]
$ python del.py
$ exit
del.py:
import cgi
import pymysql
q = cgi.parse()
f1 = q['f1'][0]
con = pymysql.connect(host='localhost',user='root',password='',db='test')
c = con.cursor()
c.execute('DELETE FROM t1 WHERE f1 = %s', (f1,))
c.close()
con.commit()
con.close()
print('Location: http://arne1.vajhoej.dk/cgi-bin/showpy')
print('')
Start URL: http://nodename:port/cgi-bin/showpy
OSU:
show.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("show.exe;",f$environment("procedure"))'
$ exit
show.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET int
#include <mysql.h>
#define F2_MAX_LEN 50
int main()
{
printf("content-type: text/html\n");
printf("\n");
printf("<html>\n");
printf("<head>\n");
printf("<title>CGI - C</title>\n");
printf("</head>\n");
printf("<body>\n");
printf("<h1>CGI - C</body>\n");
printf("<h2>Show:</h2>\n");
printf("<table border='1'>\n");
printf("<tr>\n");
printf("<th>F1</th>\n");
printf("<th>F2</th>\n");
printf("</tr>\n");
int stat;
MYSQL *con = mysql_init(NULL);
con = mysql_real_connect(con, "localhost", "root", "", "test", 3306, NULL, 0);
MYSQL_STMT *stmt = mysql_stmt_init(con);
char *sqlstr = "SELECT f1,f2 FROM t1";
stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
stat = mysql_stmt_execute(stmt);
MYSQL_BIND out[2];
int f1;
char f2[F2_MAX_LEN + 1];
unsigned long int lenf2;
memset(out, 0, sizeof(out));
out[0].buffer_type = MYSQL_TYPE_LONG;
out[0].buffer = &f1;
out[0].buffer_length = sizeof(f1);
out[1].buffer_type = MYSQL_TYPE_STRING;
out[1].buffer = f2;
out[1].buffer_length = sizeof(f2);
out[1].length = &lenf2;
stat = mysql_stmt_bind_result(stmt, out);
stat = mysql_stmt_store_result(stmt);
while(!mysql_stmt_fetch(stmt))
{
f2[lenf2] = 0;
printf("<tr>\n");
printf("<td>%d</td>\n", f1);
printf("<td>%s</td>\n", f2);
printf("<td><a href='/htbin/del?f1=%d'>Delete</a></td>\n", f1);
printf("</tr>\n");
}
mysql_stmt_free_result(stmt);
mysql_close(con);
printf("</table>\n");
printf("<h2>Add:</h2>\n");
printf("<form method='post' action='/htbin/add'>\n");
printf("F1: <input type='text' name='f1'>\n");
printf("<br>\n");
printf("F2: <input type='text' name='f2'>\n");
printf("<br>\n");
printf("<input type='submit' value='Add'>\n");
printf("</form>\n");
printf("</body>\n");
printf("</html>\n");
return 0;
}
add.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))' www_ form_
$ define sys$output net_link
$ mcr 'f$parse("add.exe;",f$environment("procedure"))'
$ exit
add.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET int
#include <mysql.h>
int main()
{
FILE *fp = fopen("apache$input", "r");
char line[1000];
fgets(line, sizeof(line), fp);
fclose(fp);
char *form_f1 = getenv("FORM_FLD_F1");
char *form_f2 = getenv("FORM_FLD_F2");
int stat;
MYSQL *con = mysql_init(NULL);
con = mysql_real_connect(con, "localhost", "root", "", "test", 3306, NULL, 0);
MYSQL_STMT *stmt = mysql_stmt_init(con);
char *sqlstr = "INSERT INTO t1 VALUES(?, ?)";
stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
MYSQL_BIND in[2];
int f1 = atoi(form_f1);
char *f2 = form_f2;
memset(in, 0, sizeof(in));
in[0].buffer_type = MYSQL_TYPE_LONG;
in[0].buffer = &f1;
in[0].buffer_length = sizeof(f1);
in[0].is_null= 0;
in[1].buffer_type = MYSQL_TYPE_STRING;
in[1].buffer = f2;
in[1].buffer_length = strlen(f2);
stat = mysql_stmt_bind_param(stmt, in);
stat = mysql_stmt_execute(stmt);
mysql_stmt_free_result(stmt);
mysql_close(con);
printf("Location: http://arne1.vajhoej.dk:81/htbin/show\n");
printf("\n");
return 0;
}
del.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("del.exe;",f$environment("procedure"))'
$ exit
del.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET int
#include <mysql.h>
static char *parse(char *line, char *marker)
{
char *p = strstr(line, marker);
if(p == NULL)
{
return NULL;
}
else
{
char *res = malloc(strlen(line) + 1);
p = p + strlen(marker);
char *p2 = p;
while(*p2 && *p2 != '&') p2++;
memcpy(res, p, p2 - p);
res[p2 - p] = 0;
for(int i = 0; i < strlen(res); i++) if(res[i] == '+') res[i] = ' ';
return res;
}
}
int main()
{
char *q = getenv("WWW_QUERY_STRING");
char *q_f1 = parse(q, "f1=");
int stat;
MYSQL *con = mysql_init(NULL);
con = mysql_real_connect(con, "localhost", "root", "", "test", 3306, NULL, 0);
MYSQL_STMT *stmt = mysql_stmt_init(con);
char *sqlstr = "DELETE FROM t1 WHERE f1 = ?";
stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
MYSQL_BIND in[1];
int f1 = atoi(q_f1);
memset(in, 0, sizeof(in));
in[0].buffer_type = MYSQL_TYPE_LONG;
in[0].buffer = &f1;
in[0].buffer_length = sizeof(f1);
in[0].is_null= 0;
stat = mysql_stmt_bind_param(stmt, in);
stat = mysql_stmt_execute(stmt);
mysql_stmt_free_result(stmt);
mysql_close(con);
printf("Location: http://arne1.vajhoej.dk:81/htbin/show\n");
printf("\n");
return 0;
}
Start URL: http://nodename:port/htbin/show
show.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("show.exe;",f$environment("procedure"))'
$ exit
show.pas:
[inherit('pmysqldir:pmysql', 'pmysqldir:common', 'pmysqldir:mysql')]
program show(input, output);
var
con : mysql_ptr;
stmt : mysql_stmt_ptr;
stat : integer;
outparam : array[1..2] of mysql_bind;
f1 : integer;
f2 : longpstr(255);
begin
writeln('content-type: text/html');
writeln('');
writeln('<html>');
writeln('<head>');
writeln('<title>CGI - Pascal</title>');
writeln('</head>');
writeln('<body>');
writeln('<h1>CGI - Pascal</body>');
writeln('<h2>Show:</h2>');
writeln('<table border="1">');
writeln('<tr>');
writeln('<th>F1</th>');
writeln('<th>F2</th>');
writeln('</tr>');
con := pmysql_init;
con := pmysql_real_connect(con, 'localhost', 'root', '', 'test');
stmt := pmysql_stmt_init(con);
stat := pmysql_stmt_prepare(stmt, 'SELECT f1,f2 FROM t1');
stat := pmysql_stmt_execute(stmt);
pmysql_init_bind_long(outparam[1], f1);
pmysql_init_bind_string_out(outparam[2], f2);
stat := pmysql_stmt_bind_result(stmt, outparam);
stat := pmysql_stmt_store_result(stmt);
while pmysql_stmt_fetch(stmt) = 0 do begin
writeln('<tr>');
writeln('<td>', f1:1, '</td>');
writeln('<td>', stdstr(f2), '</td>');
writeln('<td><a href="/htbin/del?f1=', f1:1, '">Delete</a></td>');
writeln('</tr>');
end;
pmysql_stmt_free_result(stmt);
writeln('</table>');
writeln('<h2>Add:</h2>');
writeln('<form method="post" action="/htbin/add">');
writeln('F1: <input type="text" name="f1">');
writeln('<br>');
writeln('F2: <input type="text" name="f2">');
writeln('<br>');
writeln('<input type="submit" value="Add">');
writeln('</form>');
writeln('</body>');
writeln('</html>');
pmysql_close(con);
end.
add.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))' www_ form_
$ define sys$output net_link
$ mcr 'f$parse("add.exe;",f$environment("procedure"))'
$ exit
add.pas:
[inherit('sys$library:pascal$lib_routines', 'pmysqldir:pmysql', 'pmysqldir:common', 'pmysqldir:mysql')]
program add(input, output);
var
con : mysql_ptr;
stmt : mysql_stmt_ptr;
stat : integer;
inparam : array[1..2] of mysql_bind;
form_f1, form_f2 : varying [255] of char;
f1 : integer;
f2 : pstr;
begin
lib$get_symbol('FORM_FLD_F1', form_f1.body, form_f1.length);
readv(form_f1, f1);
lib$get_symbol('FORM_FLD_F2', form_f2.body, form_f2.length);
f2 := form_f2;
con := pmysql_init;
con := pmysql_real_connect(con, 'localhost', 'root', '', 'test');
stmt := pmysql_stmt_init(con);
stat := pmysql_stmt_prepare(stmt, 'INSERT INTO t1 VALUES(?, ?)');
pmysql_init_bind_long(inparam[1], f1);
pmysql_init_bind_string_in(inparam[2], f2);
stat := pmysql_stmt_bind_param(stmt, inparam);
stat := pmysql_stmt_execute(stmt);
pmysql_stmt_free_result(stmt);
pmysql_close(con);
writeln('Location: http://arne1.vajhoej.dk:81/htbin/show');
writeln;
end.
del.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("del.exe;",f$environment("procedure"))'
$ exit
del.pas:
[inherit('sys$library:pascal$lib_routines', 'pmysqldir:pmysql', 'pmysqldir:common', 'pmysqldir:mysql')]
program del(input, output);
var
con : mysql_ptr;
stmt : mysql_stmt_ptr;
stat : integer;
inparam : array[1..1] of mysql_bind;
ix1, ix2 : integer;
q, q_f1 : varying [255] of char;
f1 : integer;
begin
lib$get_symbol('WWW_QUERY_STRING', q.body, q.length);
q_f1 := substr(q, 4, q.length - 3);
readv(q_f1, f1);
con := pmysql_init;
con := pmysql_real_connect(con, 'localhost', 'root', '', 'test');
stmt := pmysql_stmt_init(con);
stat := pmysql_stmt_prepare(stmt, 'DELETE FROM t1 WHERE f1 = ?');
pmysql_init_bind_long(inparam[1], f1);
stat := pmysql_stmt_bind_param(stmt, inparam);
stat := pmysql_stmt_execute(stmt);
pmysql_stmt_free_result(stmt);
pmysql_close(con);
writeln('Location: http://arne1.vajhoej.dk:81/htbin/show');
writeln;
end.
Start URL: http://nodename:port/htbin/show
show.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("show.exe;",f$environment("procedure"))'
$ exit
show.bas:
program show
option type = explicit
%include "bmysqldir:b.bas"
declare integer dbcon, stmt, outparam
declare integer stat
declare integer f1
declare string f2
print "content-type: text/html"
print ""
print "<html>"
print "<head>"
print "<title>CGI - Basic</title>"
print "</head>"
print "<body>"
print "<h1>CGI - Basic</body>"
print "<h2>Show:</h2>"
print "<table border='1'>"
print "<tr>"
print "<th>F1</th>"
print "<th>F2</th>"
print "</tr>"
dbcon = bmysql_open("localhost", 3306, "root", "", "test")
stmt = bmysql_stmt_prepare(dbcon, "SELECT f1,f2 FROM t1")
outparam = bmysql_outparam_init(2)
call bmysql_outparam_long(outparam, 0, f1)
call bmysql_outparam_string(outparam, 1, f2)
stat = bmysql_stmt_execute(stmt, 0, outparam)
while bmysql_stmt_fetch(stmt, outparam) = 0
print "<tr>"
print using "<td>#</td>", f1
print using "<td>'E</td>", f2
print using "<td><a href='E/htbin/del?f1=#'E>Delete</a></td>", "'", f1, "'"
print "</tr>"
next
call bmysql_outparam_free(outparam)
call bmysql_stmt_free(stmt)
call bmysql_close(dbcon)
print "</table>"
print "<h2>Add:</h2>"
print "<form method='post' action='/htbin/add'>"
print "F1: <input type='text' name='f1'>"
print "<br>"
print "F2: <input type='text' name='f2'>"
print "<br>"
print "<input type='submit' value='Add'>"
print "</form>"
print "</body>"
print "</html>"
end program
add.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))' www_ form_
$ define sys$output net_link
$ mcr 'f$parse("add.exe;",f$environment("procedure"))'
$ exit
add.bas:
program add
option type = explicit
%include "bmysqldir:b.bas"
external sub lib$get_symbol(string, string)
declare integer dbcon, stmt, inparam
declare integer stat
declare integer f1
declare string f2, form_f1, form_f2
call lib$get_symbol('FORM_FLD_F1', form_f1)
f1 = integer(form_f1)
call lib$get_symbol('FORM_FLD_F2', form_f2)
f2 = form_f2
dbcon = bmysql_open("localhost", 3306, "root", "", "test")
stmt = bmysql_stmt_prepare(dbcon, "INSERT INTO t1 VALUES(?,?)")
inparam = bmysql_inparam_init(2)
call bmysql_inparam_long(inparam, 0, f1)
call bmysql_inparam_string(inparam, 1, f2)
stat = bmysql_stmt_execute(stmt, inparam, 0)
call bmysql_inparam_free(inparam)
call bmysql_stmt_free(stmt)
call bmysql_close(dbcon)
print "Location: http://arne1.vajhoej.dk:81/htbin/show"
print ""
end program
del.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ mcr 'f$parse("del.exe;",f$environment("procedure"))'
$ exit
del.bas:
program xdel
option type = explicit
%include "bmysqldir:b.bas"
external sub lib$get_symbol(string, string)
declare integer dbcon, stmt, inparam
declare integer stat
declare integer f1
declare string q, q_f1
call lib$get_symbol('WWW_QUERY_STRING', q)
q_f1 = mid(q, 4, len(q) - 3)
f1 = integer(q_f1)
dbcon = bmysql_open("localhost", 3306, "root", "", "test")
stmt = bmysql_stmt_prepare(dbcon, "DELETE FROM t1 WHERE f1 = ?")
inparam = bmysql_inparam_init(1)
call bmysql_inparam_long(inparam, 0, f1)
stat = bmysql_stmt_execute(stmt, inparam, 0)
call bmysql_inparam_free(inparam)
call bmysql_stmt_free(stmt)
call bmysql_close(dbcon)
print "Location: http://arne1.vajhoej.dk:81/htbin/show"
print ""
end program
Start URL: http://nodename:port/htbin/show
showpy.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ set def disk5:[cgi.osu]
$ python show.py
$ exit
show.py:
import pymysql
print('content-type: text/html')
print('')
print('<html>')
print('<head>')
print('<title>CGI - Python</title>')
print('</head>')
print('<body>')
print('<h1>CGI - Python</body>')
print('<h2>Show:</h2>')
print('<table border="1">')
print('<tr>')
print('<th>F1</th>')
print('<th>F2</th>')
print('</tr>')
con = pymysql.connect(host='localhost',user='root',password='',db='test')
c = con.cursor()
c.execute('SELECT f1,f2 FROM t1')
res = c.fetchall()
for o in res:
f1 = o[0]
f2 = o[1]
print('<tr>')
print('<td>%d</td>' % (f1))
print('<td>%s</td>' % (f2))
print('<td><a href="/htbin/delpy?f1=%s">Delete</a></td>' % (f1))
print('</tr>')
c.close()
con.close()
print('</table>')
print('<h2>Add:</h2>')
print('<form method="post" action="/htbin/addpy">')
print('F1: <input type="text" name="f1">')
print('<br>')
print('F2: <input type="text" name="f2">')
print('<br>')
print('<input type="submit" value="Add">')
print('</form>')
print('</body>')
print('</html>')
addpy.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))' www_ form_
$ define sys$output net_link
$ set def disk5:[cgi.osu]
$ python add.py
$ exit
add.py:
import os
import pymysql
f1 = os.getenv('FORM_FLD_F1')
f2 = os.getenv('FORM_FLD_F2')
con = pymysql.connect(host='localhost',user='root',password='',db='test')
c = con.cursor()
c.execute('INSERT INTO t1(f1,f2) VALUES(%s,%s)', (f1,f2))
c.close()
con.commit()
con.close()
print('Location: http://arne1.vajhoej.dk:81/htbin/showpy')
print('')
delpy.com:
$ write net_link "<DNETRECMODE>"
$ mcr 'f$parse("cgi_symbols.exe;",f$environment("procedure"))'
$ define sys$output net_link
$ set def disk5:[cgi.osu]
$ python del.py
$ exit
del.py:
import os
import pymysql
q = os.getenv('WWW_QUERY_STRING')
f1 = q[3:]
con = pymysql.connect(host='localhost',user='root',password='',db='test')
c = con.cursor()
c.execute('DELETE FROM t1 WHERE f1 = %s', (f1,))
c.close()
con.commit()
con.close()
print('Location: http://arne1.vajhoej.dk:81/htbin/showpy')
print('')
Start URL: http://nodename:port/htbin/showpy
oshow.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET int
#include <mysql.h>
#include "cgilib.h"
#define F2_MAX_LEN 50
int main(int argc, char *argv[])
{
cgi_init(argc, argv);
cgi_printf("content-type: text/html\n");
cgi_printf("\n");
cgi_printf("<html>\n");
cgi_printf("<head>\n");
cgi_printf("<title>CGI (OSU) - C</title>\n");
cgi_printf("</head>\n");
cgi_printf("<body>\n");
cgi_printf("<h1>CGI (OSU) - C</body>\n");
cgi_printf("<h2>Show:</h2>\n");
cgi_printf("<table border='1'>\n");
cgi_printf("<tr>\n");
cgi_printf("<th>F1</th>\n");
cgi_printf("<th>F2</th>\n");
cgi_printf("</tr>\n");
int stat;
MYSQL *con = mysql_init(NULL);
con = mysql_real_connect(con, "localhost", "root", "", "test", 3306, NULL, 0);
MYSQL_STMT *stmt = mysql_stmt_init(con);
char *sqlstr = "SELECT f1,f2 FROM t1";
stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
stat = mysql_stmt_execute(stmt);
MYSQL_BIND out[2];
int f1;
char f2[F2_MAX_LEN + 1];
unsigned long int lenf2;
memset(out, 0, sizeof(out));
out[0].buffer_type = MYSQL_TYPE_LONG;
out[0].buffer = &f1;
out[0].buffer_length = sizeof(f1);
out[1].buffer_type = MYSQL_TYPE_STRING;
out[1].buffer = f2;
out[1].buffer_length = sizeof(f2);
out[1].length = &lenf2;
stat = mysql_stmt_bind_result(stmt, out);
stat = mysql_stmt_store_result(stmt);
while(!mysql_stmt_fetch(stmt))
{
f2[lenf2] = 0;
cgi_printf("<tr>\n");
cgi_printf("<td>%d</td>\n", f1);
cgi_printf("<td>%s</td>\n", f2);
cgi_printf("<td><a href='/htbin/odel?f1=%d'>Delete</a></td>\n", f1);
cgi_printf("</tr>\n");
}
mysql_stmt_free_result(stmt);
mysql_close(con);
cgi_printf("</table>\n");
cgi_printf("<h2>Add:</h2>\n");
cgi_printf("<form method='post' action='/htbin/oadd'>\n");
cgi_printf("F1: <input type='text' name='f1'>\n");
cgi_printf("<br>\n");
cgi_printf("F2: <input type='text' name='f2'>\n");
cgi_printf("<br>\n");
cgi_printf("<input type='submit' value='Add'>\n");
cgi_printf("</form>\n");
cgi_printf("</body>\n");
cgi_printf("</html>\n");
return 0;
}
oadd.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET int
#include <mysql.h>
#include "cgilib.h"
static char *parse(char *line, char *marker)
{
char *p = strstr(line, marker);
if(p == NULL)
{
return NULL;
}
else
{
char *res = malloc(strlen(line) + 1);
p = p + strlen(marker);
char *p2 = p;
while(*p2 && *p2 != '&') p2++;
memcpy(res, p, p2 - p);
res[p2 - p] = 0;
for(int i = 0; i < strlen(res); i++) if(res[i] == '+') res[i] = ' ';
return res;
}
}
int main(int argc, char *argv[])
{
cgi_init(argc, argv);
int linelen = atoi(cgi_info("CONTENT_LENGTH"));
char line[1000];
cgi_read(line, linelen);
line[linelen] = 0;
char *form_f1 = parse(line, "f1=");
char *form_f2 = parse(line, "f2=");
int stat;
MYSQL *con = mysql_init(NULL);
con = mysql_real_connect(con, "localhost", "root", "", "test", 3306, NULL, 0);
MYSQL_STMT *stmt = mysql_stmt_init(con);
char *sqlstr = "INSERT INTO t1 VALUES(?, ?)";
stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
MYSQL_BIND in[2];
int f1 = atoi(form_f1);
char *f2 = form_f2;
memset(in, 0, sizeof(in));
in[0].buffer_type = MYSQL_TYPE_LONG;
in[0].buffer = &f1;
in[0].buffer_length = sizeof(f1);
in[0].is_null= 0;
in[1].buffer_type = MYSQL_TYPE_STRING;
in[1].buffer = f2;
in[1].buffer_length = strlen(f2);
stat = mysql_stmt_bind_param(stmt, in);
stat = mysql_stmt_execute(stmt);
mysql_stmt_free_result(stmt);
mysql_close(con);
cgi_printf("Location: http://arne1.vajhoej.dk:81/htbin/oshow\n");
cgi_printf("\n");
return 0;
}
odel.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET int
#include <mysql.h>
#include "cgilib.h"
static char *parse(char *line, char *marker)
{
char *p = strstr(line, marker);
if(p == NULL)
{
return NULL;
}
else
{
char *res = malloc(strlen(line) + 1);
p = p + strlen(marker);
char *p2 = p;
while(*p2 && *p2 != '&') p2++;
memcpy(res, p, p2 - p);
res[p2 - p] = 0;
for(int i = 0; i < strlen(res); i++) if(res[i] == '+') res[i] = ' ';
return res;
}
}
int main(int argc, char *argv[])
{
cgi_init(argc, argv);
char *q = cgi_info("QUERY_STRING");
char *q_f1 = parse(q, "f1=");
int stat;
MYSQL *con = mysql_init(NULL);
con = mysql_real_connect(con, "localhost", "root", "", "test", 3306, NULL, 0);
MYSQL_STMT *stmt = mysql_stmt_init(con);
char *sqlstr = "DELETE FROM t1 WHERE f1 = ?";
stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
MYSQL_BIND in[1];
int f1 = atoi(q_f1);
memset(in, 0, sizeof(in));
in[0].buffer_type = MYSQL_TYPE_LONG;
in[0].buffer = &f1;
in[0].buffer_length = sizeof(f1);
in[0].is_null= 0;
stat = mysql_stmt_bind_param(stmt, in);
stat = mysql_stmt_execute(stmt);
mysql_stmt_free_result(stmt);
mysql_close(con);
cgi_printf("Location: http://arne1.vajhoej.dk:81/htbin/oshow\n");
cgi_printf("\n");
return 0;
}
Start URL: http://nodename:port/htbin/oshow
Around 2000 new web pages languages was invented that allows mixing HTML markup and code in same file.
Languages include ASP, PHP, JSP, CFM etc..
PHP and JSP are available on VMS.
show.php:
<html>
<head>
<title>Spagetti PHP</title>
</head>
<body>
<h1>Spagetti PHP</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<?php
$con = mysqli_connect('localhost', 'root', '', 'test');
$stmt = mysqli_prepare($con, 'SELECT f1,f2 FROM t1');
mysqli_stmt_execute($stmt);
$rs = mysqli_stmt_get_result($stmt);
while($row = mysqli_fetch_array($rs, MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
echo "<tr>\n<td>$f1</td>\n<td>$f2</td>\n<td><a href='del.php?f1=$f1'>Delete</a></td></tr>\n";
}
mysqli_stmt_close($stmt);
mysqli_close($con);
?>
</table>
<h2>Add:</h2>
<form method="post" action="add.php">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
add.php:
<?php
$f1 = $_POST['f1'];
$f2 = $_POST['f2'];
$con = mysqli_connect('localhost', 'root', '', 'test');
$stmt = mysqli_prepare($con, 'INSERT INTO t1 VALUES(?,?)');
mysqli_stmt_bind_param($stmt, 'is', $f1, $f2);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
header('Location: show.php');
?>
del.php:
<?php
$q = $_SERVER['QUERY_STRING'];
$f1 = (int)substr($q, 3);
$con = mysqli_connect('localhost', 'root', '', 'test');
$stmt = mysqli_prepare($con, 'DELETE FROM t1 WHERE f1 = ?');
mysqli_stmt_bind_param($stmt, 'i', $f1);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
header('Location: show.php');
?>
Start URL: http://nodename:port/application/show.php
showx.php:
<html>
<head>
<title>Spagetti PHP (pool)</title>
</head>
<body>
<h1>Spagetti PHP (pool)</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<?php
$con = mysqli_connect('p:localhost', 'root', '', 'test');
$stmt = mysqli_prepare($con, 'SELECT f1,f2 FROM t1');
mysqli_stmt_execute($stmt);
$rs = mysqli_stmt_get_result($stmt);
while($row = mysqli_fetch_array($rs, MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
echo "<tr>\n<td>$f1</td>\n<td>$f2</td>\n<td><a href='delx.php?f1=$f1'>Delete</a></td></tr>\n";
}
mysqli_stmt_close($stmt);
mysqli_close($con);
?>
</table>
<h2>Add:</h2>
<form method="post" action="addx.php">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
addx.php:
<?php
$f1 = $_POST['f1'];
$f2 = $_POST['f2'];
$con = mysqli_connect('p:localhost', 'root', '', 'test');
$stmt = mysqli_prepare($con, 'INSERT INTO t1 VALUES(?,?)');
mysqli_stmt_bind_param($stmt, 'is', $f1, $f2);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
header('Location: showx.php');
?>
delx.php:
<?php
$q = $_SERVER['QUERY_STRING'];
$f1 = (int)substr($q, 3);
$con = mysqli_connect('p:localhost', 'root', '', 'test');
$stmt = mysqli_prepare($con, 'DELETE FROM t1 WHERE f1 = ?');
mysqli_stmt_bind_param($stmt, 'i', $f1);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
header('Location: showx.php');
?>
Start URL: http://nodename:port/application/showx.php
JSP (Java Server Pages) allow for mixing of HTML markup and Java code.
show.jsp:
<%@ page import="java.sql.*" %>
<html>
<head>
<title>Spagetti JSP</title>
</head>
<body>
<h1>Spagetti JSP</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<%
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
%>
<tr>
<td><%=f1%></td>
<td><%=f2%></td>
<td><a href='del.jsp?f1=<%=f1%>'>Delete</a></td>
</tr>
<%
}
rs.close();
pstmt.close();
con.close();
%>
</table>
<h2>Add:</h2>
<form method="post" action="add.jsp">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
add.jsp:
<%@ page import="java.sql.*" %>
<%
int f1 = Integer.parseInt(request.getParameter("f1"));
String f2 = request.getParameter("f2");
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, f1);
pstmt.setString(2, f2);
pstmt.executeUpdate();
pstmt.close();
con.close();
response.sendRedirect("show.jsp");
%>
del.jsp:
<%@ page import="java.sql.*" %>
<%
int f1 = Integer.parseInt(request.getParameter("f1"));
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
response.sendRedirect("show.jsp");
%>
Start URL: http://nodename:port/application/show.jsp
showx.jsp:
<%@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>
<html>
<head>
<title>Spagetti JSP (pool)</title>
</head>
<body>
<h1>Spagetti JSP (pool)</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<%
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
DataSource ds = (DataSource)envctx.lookup("jdbc/TestDB");
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
%>
<tr>
<td><%=f1%></td>
<td><%=f2%></td>
<td><a href='delx.jsp?f1=<%=f1%>'>Delete</a></td>
</tr>
<%
}
rs.close();
pstmt.close();
con.close();
%>
</table>
<h2>Add:</h2>
<form method="post" action="addx.jsp">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
addx.jsp:
<%@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>
<%
int f1 = Integer.parseInt(request.getParameter("f1"));
String f2 = request.getParameter("f2");
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
DataSource ds = (DataSource)envctx.lookup("jdbc/TestDB");
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, f1);
pstmt.setString(2, f2);
pstmt.executeUpdate();
pstmt.close();
con.close();
response.sendRedirect("showx.jsp");
%>
delx.jsp:
<%@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>
<%
int f1 = Integer.parseInt(request.getParameter("f1"));
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
DataSource ds = (DataSource)envctx.lookup("jdbc/TestDB");
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
response.sendRedirect("showx.jsp");
%>
Start URL: http://nodename:port/application/showx.jsp
[.WEB-INF]web.xml:
<web-app 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_3_0.xsd"
version="3.0">
</web-app>
Directory structure:
Directory DISK5:[WWW_arne1.Tomcat.spagetti] add.jsp;1 addx.jsp;1 del.jsp;1 delx.jsp;1 show.jsp;1 showx.jsp;1 WEB-INF.DIR;1 Total of 7 files. Directory DISK5:[WWW_arne1.Tomcat.spagetti.WEB-INF] lib.DIR;1 web.xml;1 Total of 2 files. Directory DISK5:[WWW_arne1.Tomcat.spagetti.WEB-INF.lib] mysql-connector-java-5_1_36-bin.jar;1 Total of 1 file. Grand total of 3 directories, 10 files.
Early ASP/PHP/JSP often turned into spagetti code, so the next step was to try and separate markup and code.
A common design was MVC:
We will see some examples with DIY MVC with multiple controllers and an example of a real MVC framework: Struts.
display.php:
<html>
<head>
<title>PHP MVC</title>
</head>
<body>
<h1>PHP MVC</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<?php
foreach($data as $o) {
$f1 = $o->f1;
$f2 = $o->f2;
echo "<tr>\n<td>$f1</td>\n<td>$f2</td>\n<td><a href='del.php?f1=$f1'>Delete</a></td></tr>\n";
}
?>
</table>
<h2>Add:</h2>
<form method="post" action="add.php">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
show.php:
<?php
include 'data.php';
$data = selectAllT1();
include 'display.php';
?>
add.php:
<?php
include 'data.php';
$f1 = $_POST['f1'];
$f2 = $_POST['f2'];
$o = new T1($f1, $f2);
insertOneT1($o);
header('Location: show.php');
?>
del.php:
<?php
include 'data.php';
$q = $_SERVER['QUERY_STRING'];
$f1 = (int)substr($q, 3);
deleteOneT1($f1);
header('Location: show.php');
?>
data.php:
<?php
class T1 {
public $f1;
public $f2;
public function __construct($f1, $f2) {
$this->f1 = $f1;
$this->f2 = $f2;
}
}
function getConnection() {
$con = mysqli_connect('localhost', 'root', '', 'test');
return $con;
}
function selectAllT1() {
$con = getConnection();
$stmt = mysqli_prepare($con, 'SELECT f1,f2 FROM t1');
mysqli_stmt_execute($stmt);
$rs = mysqli_stmt_get_result($stmt);
$res = array();
while($row = mysqli_fetch_array($rs, MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
$res[] = new T1($f1, $f2);
}
mysqli_stmt_close($stmt);
mysqli_close($con);
return $res;
}
function insertOneT1($o) {
$con = getConnection();
$stmt = mysqli_prepare($con, 'INSERT INTO t1 VALUES(?,?)');
mysqli_stmt_bind_param($stmt, 'is', $o->f1, $o->f2);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
function deleteOneT1($f1) {
$con = getConnection();
$stmt = mysqli_prepare($con, 'DELETE FROM t1 WHERE f1 = ?');
mysqli_stmt_bind_param($stmt, 'i', $f1);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
?>
Start URL: http://nodename:port/application/show.php
displayx.php:
<html>
<head>
<title>PHP MVC (pool)</title>
</head>
<body>
<h1>PHP MVC (pool)</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<?php
foreach($data as $o) {
$f1 = $o->f1;
$f2 = $o->f2;
echo "<tr>\n<td>$f1</td>\n<td>$f2</td>\n<td><a href='delx.php?f1=$f1'>Delete</a></td></tr>\n";
}
?>
</table>
<h2>Add:</h2>
<form method="post" action="addx.php">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
showx.php:
<?php
include 'datax.php';
$data = selectAllT1();
include 'displayx.php';
?>
addx.php:
<?php
include 'datax.php';
$f1 = $_POST['f1'];
$f2 = $_POST['f2'];
$o = new T1($f1, $f2);
insertOneT1($o);
header('Location: showx.php');
?>
delx.php:
<?php
include 'datax.php';
$q = $_SERVER['QUERY_STRING'];
$f1 = (int)substr($q, 3);
deleteOneT1($f1);
header('Location: showx.php');
?>
datax.php:
<?php
class T1 {
public $f1;
public $f2;
public function __construct($f1, $f2) {
$this->f1 = $f1;
$this->f2 = $f2;
}
}
function getConnection() {
$con = mysqli_connect('localhost', 'root', '', 'test');
return $con;
}
function selectAllT1() {
$con = getConnection();
$stmt = mysqli_prepare($con, 'SELECT f1,f2 FROM t1');
mysqli_stmt_execute($stmt);
$rs = mysqli_stmt_get_result($stmt);
$res = array();
while($row = mysqli_fetch_array($rs, MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
$res[] = new T1($f1, $f2);
}
mysqli_stmt_close($stmt);
mysqli_close($con);
return $res;
}
function insertOneT1($o) {
$con = getConnection();
$stmt = mysqli_prepare($con, 'INSERT INTO t1 VALUES(?,?)');
mysqli_stmt_bind_param($stmt, 'is', $o->f1, $o->f2);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
function deleteOneT1($f1) {
$con = getConnection();
$stmt = mysqli_prepare($con, 'DELETE FROM t1 WHERE f1 = ?');
mysqli_stmt_bind_param($stmt, 'i', $f1);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
?>
Start URL: http://nodename:port/application/showx.php
Besides the MVC split then the JSP can be further made code free by replacing Java code fragments with special tags - JSTL (Java Standard Tag Library) - providing common functionality.
display.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>JSP + Java MVC</title>
</head>
<body>
<h1>JSP + Java MVC</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="${data}" var="o">
<tr>
<td><c:out value="${o.f1}"/></td>
<td><c:out value="${o.f2}"/></td>
<td><a href='del?f1=<c:out value="${o.f1}"/>'>Delete</a></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<form method="post" action="add">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
Show.java:
package mvcj;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Show extends HttpServlet {
private Data data = new Data();
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("data", data.selectAllT1());
req.getRequestDispatcher("display.jsp").forward(req, resp);
}
}
Add.java:
package mvcj;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Add extends HttpServlet {
private Data data = new Data();
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int f1 = Integer.parseInt(req.getParameter("f1"));
String f2 = req.getParameter("f2");
T1 o = new T1(f1, f2);
data.insertOneT1(o);
resp.sendRedirect("show");
}
}
Del.java:
package mvcj;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Del extends HttpServlet {
private Data data = new Data();
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int f1 = Integer.parseInt(req.getParameter("f1"));
data.deleteOneT1(f1);
resp.sendRedirect("show");
}
}
T1.java:
package mvcj;
public class T1 {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
Data.java:
package mvcj;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Data {
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/show
displayx.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>JSP + Java MVC (pool)</title>
</head>
<body>
<h1>JSP + Java MVC (pool)</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="${data}" var="o">
<tr>
<td><c:out value="${o.f1}"/></td>
<td><c:out value="${o.f2}"/></td>
<td><a href='delx?f1=<c:out value="${o.f1}"/>'>Delete</a></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<form method="post" action="addx">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
ShowX.java:
package mvcj;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ShowX extends HttpServlet {
private DataX data = new DataX();
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("data", data.selectAllT1());
req.getRequestDispatcher("displayx.jsp").forward(req, resp);
}
}
AddX.java:
package mvcj;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AddX extends HttpServlet {
private DataX data = new DataX();
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int f1 = Integer.parseInt(req.getParameter("f1"));
String f2 = req.getParameter("f2");
T1 o = new T1(f1, f2);
data.insertOneT1(o);
resp.sendRedirect("showx");
}
}
DelX.java:
package mvcj;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DelX extends HttpServlet {
private DataX data = new DataX();
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int f1 = Integer.parseInt(req.getParameter("f1"));
data.deleteOneT1(f1);
resp.sendRedirect("showx");
}
}
T1.java:
package mvcj;
public class T1 {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
DataX.java:
package mvcj;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DataX {
private static DataSource ds;
static {
try {
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
ds = (DataSource)envctx.lookup("jdbc/TestDB");
} catch(NamingException ex) {
ex.printStackTrace();
}
}
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/showx
[.WEB-INF]web.xml:
<web-app 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_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>ShowServlet</servlet-name>
<servlet-class>mvcj.Show</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ShowServlet</servlet-name>
<url-pattern>/show</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>AddServlet</servlet-name>
<servlet-class>mvcj.Add</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddServlet</servlet-name>
<url-pattern>/add</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>DelServlet</servlet-name>
<servlet-class>mvcj.Del</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DelServlet</servlet-name>
<url-pattern>/del</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ShowXServlet</servlet-name>
<servlet-class>mvcj.ShowX</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ShowXServlet</servlet-name>
<url-pattern>/showx</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>AddXServlet</servlet-name>
<servlet-class>mvcj.AddX</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddXServlet</servlet-name>
<url-pattern>/addx</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>DelXServlet</servlet-name>
<servlet-class>mvcj.DelX</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DelXServlet</servlet-name>
<url-pattern>/delx</url-pattern>
</servlet-mapping>
</web-app>
Directory structure:
Directory DISK5:[WWW_arne1.Tomcat.mvcj] display.jsp;1 displayx.jsp;1 WEB-INF.DIR;1 Total of 3 files. Directory DISK5:[WWW_arne1.Tomcat.mvcj.WEB-INF] classes.DIR;1 lib.DIR;1 web.xml;1 Total of 3 files. Directory DISK5:[WWW_arne1.Tomcat.mvcj.WEB-INF.classes] mvcj.DIR;1 Total of 1 file. Directory DISK5:[WWW_arne1.Tomcat.mvcj.WEB-INF.classes.mvcj] ADD.CLASS;1 Add.java;1 AddX.class;1 AddX.java;1 DATA.CLASS;1 Data.java;1 DataX.class;1 DataX.java;1 DEL.CLASS;1 Del.java;1 DelX.class;1 DelX.java;1 gen.com;1 SHOW.CLASS;1 Show.java;1 ShowX.class;1 ShowX.java;1 T1.CLASS;1 T1.java;1 Total of 19 files. Directory DISK5:[WWW_arne1.Tomcat.mvcj.WEB-INF.lib] jstl.jar;1 mysql-connector-java-5_1_36-bin.jar;1 standard.jar;1 Total of 3 files. Grand total of 5 directories, 29 files.
The Java code in controllers and models can be replaced by Groovy code utilizing socalled groovelets. This can reduce code size.
display.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>JSP + Groovy MVC</title>
</head>
<body>
<h1>JSP + Groovy MVC</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="${data}" var="o">
<tr>
<td><c:out value="${o.f1}"/></td>
<td><c:out value="${o.f2}"/></td>
<td><a href='del.groovy?f1=<c:out value="${o.f1}"/>'>Delete</a></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<form method="post" action="add.groovy">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
show.groovy:
import mvcg.*
data = new Data()
request.setAttribute("data", data.selectAllT1())
request.getRequestDispatcher("display.jsp").forward(request, response)
add.groovy:
import mvcg.*
data = new Data()
f1 = Integer.parseInt(request.getParameter("f1"))
f2 = request.getParameter("f2")
o = new T1(f1: f1, f2: f2)
data.insertOneT1(o)
response.sendRedirect("show.groovy")
del.groovy:
import mvcg.*
data = new Data()
f1 = Integer.parseInt(request.getParameter("f1"))
data.deleteOneT1(f1)
response.sendRedirect("show.groovy")
Data.groovy:
package mvcg
import java.sql.*
class T1 {
int f1
String f2
}
class Data {
List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>()
Class.forName("com.mysql.jdbc.Driver")
def con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "")
def pstmt = con.prepareStatement("SELECT f1,f2 FROM t1")
def rs = pstmt.executeQuery()
while(rs.next()) {
def f1 = rs.getInt(1)
def f2 = rs.getString(2)
def o = new T1(f1: f1, f2: f2)
res.add(o)
}
rs.close()
pstmt.close()
con.close()
return res
}
void insertOneT1(T1 o) {
Class.forName("com.mysql.jdbc.Driver")
def con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "")
def pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)")
pstmt.setInt(1, o.f1)
pstmt.setString(2, o.f2)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
void deleteOneT1(int f1) {
Class.forName("com.mysql.jdbc.Driver")
def con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "")
def pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?")
pstmt.setInt(1, f1)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
}
Start URL: http://nodename:port/application/show.groovy
displayx.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>JSP + Groovy MVC (pool)</title>
</head>
<body>
<h1>JSP + Groovy MVC (pool)</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="${data}" var="o">
<tr>
<td><c:out value="${o.f1}"/></td>
<td><c:out value="${o.f2}"/></td>
<td><a href='delx.groovy?f1=<c:out value="${o.f1}"/>'>Delete</a></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<form method="post" action="addx.groovy">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
showx.groovy:
import mvcg.*
data = new DataX()
request.setAttribute("data", data.selectAllT1())
request.getRequestDispatcher("displayx.jsp").forward(request, response)
addx.groovy:
import mvcg.*
data = new DataX()
f1 = Integer.parseInt(request.getParameter("f1"))
f2 = request.getParameter("f2")
o = new T1(f1: f1, f2: f2)
data.insertOneT1(o)
response.sendRedirect("showx.groovy")
delx.groovy:
import mvcg.*
data = new DataX()
f1 = Integer.parseInt(request.getParameter("f1"))
data.deleteOneT1(f1)
response.sendRedirect("showx.groovy")
DataX.groovy:
package mvcg
import java.sql.*
import javax.naming.*
import javax.sql.*
class T1 {
int f1
String f2
}
class DataX {
static DataSource ds
static {
def initctx = new InitialContext()
def envctx = initctx.lookup("java:/comp/env")
ds = envctx.lookup("jdbc/TestDB")
}
List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>()
def con = ds.getConnection()
def pstmt = con.prepareStatement("SELECT f1,f2 FROM t1")
def rs = pstmt.executeQuery()
while(rs.next()) {
def f1 = rs.getInt(1)
def f2 = rs.getString(2)
def o = new T1(f1: f1, f2: f2)
res.add(o)
}
rs.close()
pstmt.close()
con.close()
return res
}
void insertOneT1(T1 o) {
def con = ds.getConnection()
def pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)")
pstmt.setInt(1, o.f1)
pstmt.setString(2, o.f2)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
void deleteOneT1(int f1) {
def con = ds.getConnection()
def pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?")
pstmt.setInt(1, f1)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
}
Start URL: http://nodename:port/application/showx.groovy
[.WEB-INF]web.xml:
<web-app 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_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>GroovyServlet</servlet-name>
<servlet-class>groovy.servlet.GroovyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GroovyServlet</servlet-name>
<url-pattern>*.groovy</url-pattern>
</servlet-mapping>
</web-app>
Directory structure:
Directory DISK5:[WWW_arne1.Tomcat.mvcg] add.groovy;1 addx.groovy;1 del.groovy;1 delx.groovy;1 display.jsp;1 displayx.jsp;1 show.groovy;1 showx.groovy;1 WEB-INF.DIR;1 Total of 9 files. Directory DISK5:[WWW_arne1.Tomcat.mvcg.WEB-INF] classes.DIR;1 lib.DIR;1 web.xml;1 Total of 3 files. Directory DISK5:[WWW_arne1.Tomcat.mvcg.WEB-INF.classes] Data.groovy;1 DataX.groovy;1 gen.com;1 mvcg.DIR;1 Total of 4 files. Directory DISK5:[WWW_arne1.Tomcat.mvcg.WEB-INF.classes.mvcg] Data.class;1 DataX.class;1 T1.class;1 Total of 3 files. Directory DISK5:[WWW_arne1.Tomcat.mvcg.WEB-INF.lib] groovy-all-2_2_2.jar;1 jstl.jar;1 mysql-connector-java-5_1_36-bin.jar;1 standard.jar;1 Total of 4 files. Grand total of 5 directories, 23 files.
Struts 1.x was the first popular web MVC framework.
It uses a fixed controller servlet with specific action classes.
display.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Struts 1.x</title>
</head>
<body>
<h1>Struts 1.x</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="${data}" var="o">
<tr>
<td><c:out value="${o.f1}"/></td>
<td><c:out value="${o.f2}"/></td>
<td><a href='del.do?f1=<c:out value="${o.f1}"/>'>Delete</a></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<form method="post" action="add.do">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
ShowAction.java:
package struts;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class ShowAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
Data data = new Data();
request.setAttribute("data", data.selectAllT1());
return mapping.findForward("show.ok");
}
}
AddAction.java:
package struts;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
public class AddAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
DynaActionForm daf = (DynaActionForm)form;
int f1 = (Integer)daf.get("f1");
String f2 = (String)daf.get("f2");
T1 o = new T1(f1, f2);
Data data = new Data();
data.insertOneT1(o);
return mapping.findForward("add.ok");
}
}
DelAction.java:
package struts;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
public class DelAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
DynaActionForm daf = (DynaActionForm)form;
int f1 = Integer.parseInt(request.getParameter("f1"));
Data data = new Data();
data.deleteOneT1(f1);
return mapping.findForward("del.ok");
}
}
T1.java:
package struts;
public class T1 {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
Data.java:
package struts;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Data {
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/show.do
displayx.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Struts 1.x (pool)</title>
</head>
<body>
<h1>Struts 1.x (pool)</body>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="${data}" var="o">
<tr>
<td><c:out value="${o.f1}"/></td>
<td><c:out value="${o.f2}"/></td>
<td><a href='delx.do?f1=<c:out value="${o.f1}"/>'>Delete</a></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<form method="post" action="addx.do">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
ShowXAction.java:
package struts;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class ShowXAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
DataX data = new DataX();
request.setAttribute("data", data.selectAllT1());
return mapping.findForward("showx.ok");
}
}
AddXAction.java:
package struts;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
public class AddXAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
DynaActionForm daf = (DynaActionForm)form;
int f1 = (Integer)daf.get("f1");
String f2 = (String)daf.get("f2");
T1 o = new T1(f1, f2);
DataX data = new DataX();
data.insertOneT1(o);
return mapping.findForward("addx.ok");
}
}
DelXAction.java:
package struts;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
public class DelXAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
DynaActionForm daf = (DynaActionForm)form;
int f1 = Integer.parseInt(request.getParameter("f1"));
DataX data = new DataX();
data.deleteOneT1(f1);
return mapping.findForward("delx.ok");
}
}
T1.java:
package struts;
public class T1 {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
DataX.java:
package struts;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DataX {
private static DataSource ds;
static {
try {
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
ds = (DataSource)envctx.lookup("jdbc/TestDB");
} catch(NamingException ex) {
ex.printStackTrace();
}
}
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/showx.do
[.WEB-INF]web.xml:
<web-app 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_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
[.WEB-INF]struts-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd" >
<struts-config>
<form-beans>
<form-bean name="addForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="f1" type="java.lang.Integer"/>
<form-property name="f2" type="java.lang.String"/>
</form-bean>
</form-beans>
<action-mappings>
<action path="/show" type="struts.ShowAction">
<forward name="show.ok" path="/display.jsp"/>
</action>
<action path="/add" type="struts.AddAction" name="addForm" input="/display.jsp">
<forward name="add.ok" path="/show.do" redirect="true"/>
</action>
<action path="/del" type="struts.DelAction">
<forward name="del.ok" path="/show.do" redirect="true"/>
</action>
<action path="/showx" type="struts.ShowXAction">
<forward name="showx.ok" path="/displayx.jsp"/>
</action>
<action path="/addx" type="struts.AddXAction" name="addForm" input="/displayx.jsp">
<forward name="addx.ok" path="/showx.do" redirect="true"/>
</action>
<action path="/delx" type="struts.DelXAction">
<forward name="delx.ok" path="/showx.do" redirect="true"/>
</action>
</action-mappings>
</struts-config>
Directory structure:
Directory DISK5:[WWW_arne1.Tomcat.struts] display.jsp;1 displayx.jsp;1 WEB-INF.DIR;1 Total of 3 files. Directory DISK5:[WWW_arne1.Tomcat.struts.WEB-INF] classes.DIR;1 lib.DIR;1 struts-config.xml;1 web.xml;1 Total of 4 files. Directory DISK5:[WWW_arne1.Tomcat.struts.WEB-INF.classes] struts.DIR;1 Total of 1 file. Directory DISK5:[WWW_arne1.Tomcat.struts.WEB-INF.classes.struts] AddAction.class;1 AddAction.java;1 ADDXACTION.CLASS;1 AddXAction.java;1 Data.class;1 Data.java;1 DataX.class;1 DataX.java;1 DelAction.class;1 DelAction.java;1 DELXACTION.CLASS;1 DelXAction.java;1 gen.com;1 ShowAction.class;1 ShowAction.java;1 SHOWXACTION.CLASS;1 ShowXAction.java;1 T1.class;1 T1.java;1 Total of 19 files. Directory DISK5:[WWW_arne1.Tomcat.struts.WEB-INF.lib] antlr-2_7_2.jar;1 commons-beanutils-1_8_0.jar;1 commons-chain-1_2.jar;1 commons-digester-1_8.jar;1 commons-fileupload-1_1_1.jar;1 commons-logging-1_0_4.jar;1 commons-validator-1_3_1.jar;1 jstl.jar;1 mysql-connector-java-5_1_36-bin.jar;1 oro-2_0_8.jar;1 standard.jar;1 struts-core-1_3_10.jar;1 Total of 12 files. Grand total of 5 directories, 39 files.
Zend Framework was one of the first PHP MVC frameworks. And it has inspired many other PHP MVC frameworks.
As I cannot get composer working on VMS, then I created the project on PC, zipped, uploaded to VMS and unzipped.
Project creation:
php composer.phar create-project zendframework/skeleton-application zf
module/Application/view/application/t1/show.phtml:
<html>
<head>
<title>Zend Framework</title>
</head>
<body>
<h1>Zend Framework</h1>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<?php
foreach($data as $o) {
?>
<tr>
<td><?= $o->f1 ?></td>
<td><?= $o->f2 ?></td>
<td><a href="<?php echo $this->url('t1', array('action' => 'del'), array('query' => array('f1' => $o->f1))); ?>">Delete</a></td>
</tr>
<?php
}
?>
</table>
<h2>Add:</h2>
<form method="post" action="<?php echo $this->url('t1', array('action' => 'add')); ?>">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
module/Application/src/Controller/T1Controller.php:
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Model\Data;
use Application\Model\T1;
class T1Controller extends AbstractActionController
{
public function showAction() {
$data = new Data();
return new ViewModel(array('data' => $data->selectAllT1()));
}
public function addAction() {
$formdata = $this->params()->fromPost();
$f1 = $formdata['f1'];
$f2 = $formdata['f2'];
$data = new Data();
$data->insertOneT1(new T1($f1, $f2));
$this->redirect()->toRoute('t1', [ 'action' => 'show' ]);
}
public function delAction() {
$querydata = $this->params()->fromQuery();
$f1 = $querydata['f1'];
$data = new Data();
$data->deleteOneT1($f1);
$this->redirect()->toRoute('t1', [ 'action' => 'show' ]);
}
}
module/Application/src/Model/T1.php:
<?php
namespace Application\Model;
class T1 {
public $f1;
public $f2;
public function __construct($f1, $f2) {
$this->f1 = $f1;
$this->f2 = $f2;
}
}
?>
module/Application/src/Model/Data.php:
<?php
namespace Application\Model;
class Data {
private function getConnection() {
$con = mysqli_connect('arnepc5', 'arne', 'hemmeligt', 'test');
return $con;
}
public function selectAllT1() {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'SELECT f1,f2 FROM t1');
mysqli_stmt_execute($stmt);
$rs = mysqli_stmt_get_result($stmt);
$res = array();
while($row = mysqli_fetch_array($rs, MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
$res[] = new T1($f1, $f2);
}
mysqli_stmt_close($stmt);
mysqli_close($con);
return $res;
}
public function insertOneT1($o) {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'INSERT INTO t1 VALUES(?,?)');
mysqli_stmt_bind_param($stmt, 'is', $o->f1, $o->f2);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
public function deleteOneT1($f1) {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'DELETE FROM t1 WHERE f1 = ?');
mysqli_stmt_bind_param($stmt, 'i', $f1);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
}
?>
Start URL: http://nodename:port/t1/show
module/Application/view/application/t1/showx.phtml:
<html>
<head>
<title>Zend Framework (pool)</title>
</head>
<body>
<h1>Zend Framework (pool)</h1>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<?php
foreach($data as $o) {
?>
<tr>
<td><?= $o->f1 ?></td>
<td><?= $o->f2 ?></td>
<td><a href="<?php echo $this->url('t1x', array('action' => 'delx'), array('query' => array('f1' => $o->f1))); ?>">Delete</a></td>
</tr>
<?php
}
?>
</table>
<h2>Add:</h2>
<form method="post" action="<?php echo $this->url('t1x', array('action' => 'addx')); ?>">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add">
</form>
</body>
</html>
module/Application/src/Controller/T1xController.php:
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Model\DataX;
use Application\Model\T1;
class T1xController extends AbstractActionController // it hs to be T1xController as T1XController cause a hyphen to be inserted
{
public function showxAction() {
$data = new DataX();
return new ViewModel(array('data' => $data->selectAllT1()));
}
public function addxAction() {
$formdata = $this->params()->fromPost();
$f1 = $formdata['f1'];
$f2 = $formdata['f2'];
$data = new DataX();
$data->insertOneT1(new T1($f1, $f2));
$this->redirect()->toRoute('t1x', [ 'action' => 'showx' ]);
}
public function delxAction() {
$querydata = $this->params()->fromQuery();
$f1 = $querydata['f1'];
$data = new DataX();
$data->deleteOneT1($f1);
$this->redirect()->toRoute('t1x', [ 'action' => 'showx' ]);
}
}
module/Application/src/Model/T1.php:
<?php
namespace Application\Model;
class T1 {
public $f1;
public $f2;
public function __construct($f1, $f2) {
$this->f1 = $f1;
$this->f2 = $f2;
}
}
?>
module/Application/src/Model/DataX.php:
<?php
namespace Application\Model;
class DataX {
private function getConnection() {
$con = mysqli_connect('p:arnepc5', 'arne', 'hemmeligt', 'test');
return $con;
}
public function selectAllT1() {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'SELECT f1,f2 FROM t1');
mysqli_stmt_execute($stmt);
$rs = mysqli_stmt_get_result($stmt);
$res = array();
while($row = mysqli_fetch_array($rs, MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
$res[] = new T1($f1, $f2);
}
mysqli_stmt_close($stmt);
mysqli_close($con);
return $res;
}
public function insertOneT1($o) {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'INSERT INTO t1 VALUES(?,?)');
mysqli_stmt_bind_param($stmt, 'is', $o->f1, $o->f2);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
public function deleteOneT1($f1) {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'DELETE FROM t1 WHERE f1 = ?');
mysqli_stmt_bind_param($stmt, 'i', $f1);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
}
?>
Start URL: http://nodename:port/t1x/showx
module/Application/config/module.config.php fragment:
't1' => [
'type' => Segment::class,
'options' => [
'route' => '/t1[/:action]',
'defaults' => [
'controller' => Controller\T1Controller::class,
'action' => 'show',
],
],
],
't1x' => [
'type' => Segment::class,
'options' => [
'route' => '/t1x[/:action]',
'defaults' => [
'controller' => Controller\T1xController::class,
'action' => 'showx',
],
],
],
],
],
...
'controllers' => [
'factories' => [
...
Controller\T1Controller::class => InvokableFactory::class,
Controller\T1xController::class => InvokableFactory::class,
],
],
Note that this way to do database access is not the ZF way. But I have done it this way to keep the code more comparable to to the rest of the code.
Struts 1.x faded away and it was not replaced by Struts 2.x but with Spring MVC.
Spring MVC build on the popular Spring DI framework. But are otherwise a rather traditional MVC framework.
display.jsp:
<%@ page language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Spring with JSP view</title>
</head>
<body>
<h1>Spring with JSP view</h1>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="${data}" var="o">
<tr>
<td><c:out value="${o.f1}"/></td>
<td><c:out value="${o.f2}"/></td>
<td><a href='del?f1=<c:out value="${o.f1}"/>'>Delete</a></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<form method="post" action="add">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add"/>
</form>
</body>
</html>
Manager.java:
package springjsp;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.servlet.View;
@Controller
public class Manager {
@RequestMapping(value="/show", method=RequestMethod.GET)
public String show(Model m) {
Data data = new Data();
m.addAttribute("data", data.selectAllT1());
return "display";
}
@RequestMapping(value="/add", method=RequestMethod.POST)
public View add(@RequestParam("f1") int f1, @RequestParam("f2") String f2, Model m) {
T1 o = new T1(f1, f2);
Data data = new Data();
data.insertOneT1(o);
return new RedirectView("show");
}
@RequestMapping(value="/del", method=RequestMethod.GET)
public View del(@RequestParam("f1") int f1, Model m) {
Data data = new Data();
data.deleteOneT1(f1);
return new RedirectView("show");
}
}
T1.java:
package springjsp;
import java.io.Serializable;
public class T1 implements Serializable {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
Data.java:
package springjsp;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Data {
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/show
displayx.jsp:
<%@ page language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Spring with JSP view (pool)</title>
</head>
<body>
<h1>Spring with JSP view (pool)</h1>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="${data}" var="o">
<tr>
<td><c:out value="${o.f1}"/></td>
<td><c:out value="${o.f2}"/></td>
<td><a href='delx?f1=<c:out value="${o.f1}"/>'>Delete</a></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<form method="post" action="addx">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add"/>
</form>
</body>
</html>
ManagerX.java:
package springjsp;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.servlet.View;
@Controller
public class ManagerX {
@RequestMapping(value="/showx", method=RequestMethod.GET)
public String showx(Model m) {
DataX data = new DataX();
m.addAttribute("data", data.selectAllT1());
return "displayx";
}
@RequestMapping(value="/addx", method=RequestMethod.POST)
public View addx(@RequestParam("f1") int f1, @RequestParam("f2") String f2, Model m) {
T1 o = new T1(f1, f2);
DataX data = new DataX();
data.insertOneT1(o);
return new RedirectView("showx");
}
@RequestMapping(value="/delx", method=RequestMethod.GET)
public View delx(@RequestParam("f1") int f1, Model m) {
DataX data = new DataX();
data.deleteOneT1(f1);
return new RedirectView("showx");
}
}
T1.java:
package springjsp;
import java.io.Serializable;
public class T1 implements Serializable {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
DataX.java:
package springjsp;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DataX {
private static DataSource ds;
static {
try {
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
ds = (DataSource)envctx.lookup("jdbc/TestDB");
} catch(NamingException ex) {
ex.printStackTrace();
}
}
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/showx
[.WEB-INF]web.xml:
<web-app 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_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
[.WEB-INF]spring-servlet.xml:
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:context = "http://www.springframework.org/schema/context"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="springjsp" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
Directory structure:
Directory TOMCAT$ROOT:[webapps.springjsp] WEB-INF.DIR;1 Total of 1 file. Directory TOMCAT$ROOT:[webapps.springjsp.WEB-INF] classes.DIR;1 jsp.DIR;1 lib.DIR;1 spring-servlet.xml;1 web.xml;1 Total of 5 files. Directory TOMCAT$ROOT:[webapps.springjsp.WEB-INF.classes] springjsp.DIR;1 Total of 1 file. Directory TOMCAT$ROOT:[webapps.springjsp.WEB-INF.classes.springjsp] Data.class;1 Data.java;1 DataX.class;1 DataX.java;1 gen.com;1 Manager.class;1 Manager.java;1 ManagerX.class;1 ManagerX.java;1 T1.class;1 T1.java;1 Total of 11 files. Directory TOMCAT$ROOT:[webapps.springjsp.WEB-INF.jsp] display.jsp;1 displayx.jsp;1 Total of 2 files. Directory TOMCAT$ROOT:[webapps.springjsp.WEB-INF.lib] commons-logging-1_1.jar;1 mysql-connector-j-8_0_33.jar;1 spring-aop-5_1_2_RELEASE.jar;1 spring-aspects-5_1_2_RELEASE.jar;1 spring-beans-5_1_2_RELEASE.jar;1 spring-context-5_1_2_RELEASE.jar;1 spring-core-5_1_2_RELEASE.jar;1 spring-expression-5_1_2_RELEASE.jar;1 spring-web-5_1_2_RELEASE.jar;1 spring-webmvc-5_1_2_RELEASE.jar;1 Total of 10 files. Grand total of 6 directories, 30 files.
JSF (Java Server Faces) is not a traditional MVC framework - instead it attempts to make a web application look similar to a desktop GUI application.
JSF is very much inspired by ASP.NET web forms.
For more details about JSF see here.
show.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<html>
<head>
<title>JSF with JSP view</title>
</head>
<body>
<f:view>
<h1>JSF with JSP view</h1>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="#{manager.data}" var="o">
<tr>
<td><h:outputText value="#{o.f1}"/></td>
<td><h:outputText value="#{o.f2}"/></td>
<td><h:form><h:commandButton value="Delete" action="#{manager.del(o.f1)}"/></h:form></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<h:form>
F1: <h:inputText value="#{manager.f1}"/>
<br>
F2: <h:inputText value="#{manager.f2}"/>
<br>
<h:commandButton value="Add" action="#{manager.add}"/>
</h:form>
</f:view>
</body>
</html>
Manager.java:
package jsf1;
import java.io.Serializable;
import java.util.List;
public class Manager implements Serializable {
// show
public List<T1> getData() {
Data data = new Data();
return data.selectAllT1();
}
// add
private Integer f1;
private String f2;
public Integer getF1() {
return f1;
}
public void setF1(Integer f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
public String add() {
T1 o = new T1((int)f1, f2);
Data data = new Data();
data.insertOneT1(o);
f1 = null;
f2 = null;
return "display";
}
// del
public String del(int f1) {
Data data = new Data();
data.deleteOneT1(f1);
return "display";
}
}
T1.java:
package jsf1;
import java.io.Serializable;
public class T1 implements Serializable {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
Data.java:
package jsf1;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Data {
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/show.jsf
showx.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<html>
<head>
<title>JSF with JSP view (pool)</title>
</head>
<body>
<f:view>
<h1>JSF with JSP view (pool)</h1>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<c:forEach items="#{managerx.data}" var="o">
<tr>
<td><h:outputText value="#{o.f1}"/></td>
<td><h:outputText value="#{o.f2}"/></td>
<td><h:form><h:commandButton value="Delete" action="#{managerx.del(o.f1)}"/></h:form></td>
</tr>
</c:forEach>
</table>
<h2>Add:</h2>
<h:form>
F1: <h:inputText value="#{managerx.f1}"/>
<br>
F2: <h:inputText value="#{managerx.f2}"/>
<br>
<h:commandButton value="Add" action="#{managerx.add}"/>
</h:form>
</f:view>
</body>
</html>
ManagerX.java:
package jsf1;
import java.io.Serializable;
import java.util.List;
public class ManagerX implements Serializable {
// show
public List<T1> getData() {
DataX data = new DataX();
return data.selectAllT1();
}
// add
private Integer f1;
private String f2;
public Integer getF1() {
return f1;
}
public void setF1(Integer f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
public String add() {
DataX data = new DataX();
T1 o = new T1((int)f1, f2);
data.insertOneT1(o);
f1 = null;
f2 = null;
return "display";
}
// del
public String del(int f1) {
DataX data = new DataX();
data.deleteOneT1(f1);
return "display";
}
}
T1.java:
package jsf1;
import java.io.Serializable;
public class T1 implements Serializable {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
DataX.java:
package jsf1;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DataX {
private static DataSource ds;
static {
try {
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
ds = (DataSource)envctx.lookup("jdbc/TestDB");
} catch(NamingException ex) {
ex.printStackTrace();
}
}
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/showx.jsf
[.WEB-INF]web.xml:
<web-app 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_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
</web-app>
[.WEB-INF]faces-config.xml:
<?xml version="1.0"?>
<faces-config 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/web-facesconfig_1_2.xsd http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<navigation-rule>
<from-view-id>/show.jsp</from-view-id>
<navigation-case>
<from-outcome>display</from-outcome>
<to-view-id>/show.jsp</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/showx.jsp</from-view-id>
<navigation-case>
<from-outcome>display</from-outcome>
<to-view-id>/showx.jsp</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
<managed-bean>
<managed-bean-name>manager</managed-bean-name>
<managed-bean-class>jsf1.Manager</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>managerx</managed-bean-name>
<managed-bean-class>jsf1.ManagerX</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
Directory structure:
Directory TOMCAT$ROOT:[webapps.jsf1] show.jsp;1 showx.jsp;1 WEB-INF.DIR;1 Total of 3 files. Directory TOMCAT$ROOT:[webapps.jsf1.WEB-INF] classes.DIR;1 faces-config.xml;1 lib.DIR;1 web.xml;1 Total of 4 files. Directory TOMCAT$ROOT:[webapps.jsf1.WEB-INF.classes] jsf1.DIR;1 Total of 1 file. Directory TOMCAT$ROOT:[webapps.jsf1.WEB-INF.classes.jsf1] Data.class;1 Data.java;1 DataX.class;1 DataX.java;1 gen.com;1 Manager.class;1 Manager.java;1 ManagerX.class;1 ManagerX.java;1 T1.class;1 T1.java;1 Total of 11 files. Directory TOMCAT$ROOT:[webapps.jsf1.WEB-INF.lib] commons-beanutils-1_9_2.jar;1 commons-collections-3_2_2.jar;1 commons-digester-1_8.jar;1 commons-logging-1_1_1.jar;1 geronimo-atinject_1_0_spec-1_0.jar;1 myfaces-api-2_2_12.jar;1 myfaces-bundle-2_2_12.jar;1 myfaces-impl-2_2_12.jar;1 mysql-connector-j-8_0_33.jar;1 Total of 9 files. Grand total of 5 directories, 28 files.
I think it should work, but I cannot get it to work with PHP 8.1 on VMS x86-64.
Grails is very much inspired by the popular RoR (Ruby on Rails) framework.
And Grails is not just a runtime environment but also a development environment.
Grails web applications runs fine on VMS, but I have not even tried getting the development environment up and running on VMS. I develop on Windows, build a war file and deploy war file to VMS.
Project creation:
grails create-app grails
cd grails
grails create-controller Manager
Build of war:
cd grails
grails war
(note that paths below are paths in dev enviroment not on VMS!)
grails-app/views/manager/show.gsp:
<html>
<head>
<title>Grails</title>
</head>
<body>
<h1>Grails</h1>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<g:each in="${data}" var="o">
<tr>
<td>${o.f1}</td>
<td>${o.f2}</td>
<td><g:link action="del" params="[f1: o.f1]">Delete</g:link></td>
</tr>
</g:each>
</table>
<h2>Add:</h2>
<g:form method="post" action="add">
F1: <input type="text" name="f1">
<br>
F2: <input type="text" name="f2">
<br>
<input type="submit" value="Add"/>
</g:form>
</body>
</html>
grails-app/controllers/grails/ManagerController.groovy:
package grails
class ManagerController {
def show() {
Data data = new Data()
return [data: data.selectAllT1()]
}
def add() {
Data data = new Data();
data.insertOneT1(new T1(f1: Integer.parseInt(params.f1), f2: params.f2))
redirect(action: "show")
}
def del() {
Data data = new Data();
data.deleteOneT1(Integer.parseInt(params.f1))
redirect(action: "show")
}
}
grails-app/domain/grails/Data.groovy:
package grails
import java.sql.*
class T1 {
int f1
String f2
}
class Data {
List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>()
Class.forName("com.mysql.cj.jdbc.Driver")
def con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt")
def pstmt = con.prepareStatement("SELECT f1,f2 FROM t1")
def rs = pstmt.executeQuery()
while(rs.next()) {
def f1 = rs.getInt(1)
def f2 = rs.getString(2)
def o = new T1(f1: f1, f2: f2)
res.add(o)
}
rs.close()
pstmt.close()
con.close()
return res
}
void insertOneT1(T1 o) {
Class.forName("com.mysql.cj.jdbc.Driver")
def con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt")
def pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)")
pstmt.setInt(1, o.f1)
pstmt.setString(2, o.f2)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
void deleteOneT1(int f1) {
Class.forName("com.mysql.cj.jdbc.Driver")
def con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt")
def pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?")
pstmt.setInt(1, f1)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
}
Start URL: http://nodename:port/application/manager/show
A grails web application does not need to be deployed to Tomcat but can also be run standalone. Simply:
java -jar application.war
Note that this way to do database access is not the Grails way. But I have done it this way to keep the code more comparable to to the rest of the code.
Ktor is one of the newest web frameworks.
It uses Kotlin as programming language and for web applications (as opposed to web services) it can use THymeleaf as view technology.
It can be built both as standalone application and as war for servlet engine deployment.
Ktor web applications can be made to on VMS, but I have not even tried getting the development environment up and running on VMS. I develop on Windows, build a fatjar and deploy fatjar to VMS.
Ktor need to be built for Java 8 to run on VMS.
To do that:
src/main/resources/templates/thymeleaf/show.html:
<html xmlns:th="https://thymeleaf.org">
<head>
<title>Ktor with Thymeleaf</title>
</head>
<body>
<h1>Ktor with Thymeleaf</h1>
<h2>Show data:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
<th></th>
</tr>
<tr th:each="o: ${data}">
<td th:text="${o.f1}"/>
<td th:text="${o.f2}"/>
<td><a th:href="@{del?f1={v}(v=${o.f1})}">Delete</a></td>
</tr>
</table>
<h2>Add data:</h2>
<form method="post" action="add" th:object="${addForm}">
F1: <input type="text" name="f1" th:field="*{f1}"/>
<br>
F2: <input type="text" name="f2" th:field="*{f2}"/>
<br>
<input type="submit" value="Add"/>
</form>
</body>
</html>
src/main/kotlin/demo/plugins/Templating.kt:
package demo.plugins
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.thymeleaf.Thymeleaf
import io.ktor.server.thymeleaf.ThymeleafContent
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver
import demo.model.*
fun Application.configureTemplating() {
install(Thymeleaf) {
setTemplateResolver(ClassLoaderTemplateResolver().apply {
prefix = "templates/thymeleaf/"
suffix = ".html"
characterEncoding = "utf-8"
})
}
routing {
get("/show") {
call.respond(ThymeleafContent("show", mapOf("data" to Data.selectAllT1(), "addForm" to AddForm("", ""))))
}
get("/showx") {
call.respond(ThymeleafContent("showx", mapOf("data" to DataX.selectAllT1(), "addForm" to AddForm("", ""))))
}
}
}
data class AddForm(var f1: String, var f2: String)
src/main/kotlin/demo/plugins/Routing.kt:
package demo.plugins
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import demo.model.*
fun Application.configureRouting() {
routing {
post("/add") {
val param = call.receiveParameters()
val f1 = param["f1"]!!.toInt()
val f2 = param["f2"].toString()
Data.insertOneT1(T1(f1, f2))
call.respondRedirect("/show")
}
get("/del") {
val f1 = call.request.queryParameters["f1"]!!.toInt()
Data.deleteOneT1(f1)
call.respondRedirect("/show")
}
post("/addx") {
val param = call.receiveParameters()
val f1 = param["f1"]!!.toInt()
val f2 = param["f2"].toString()
DataX.insertOneT1(T1(f1, f2))
call.respondRedirect("/showx")
}
get("/delx") {
val f1 = call.request.queryParameters["f1"]!!.toInt()
DataX.deleteOneT1(f1)
call.respondRedirect("/showx")
}
}
}
src/main/kotlin/demo/model/Data.kt:
package demo.model
import java.sql.*
data class T1(var f1: Int, var f2: String)
object Data {
fun selectAllT1(): List<T1> {
val con = DriverManager.getConnection("jdbc:mysql://arnepc5/test", "arne", "hemmeligt")
val stmt = con.createStatement()
val rs = stmt.executeQuery("SELECT f1,f2 FROM t1")
val res = ArrayList<T1>()
while(rs.next()) {
val f1 = rs.getInt(1)
val f2 = rs.getString(2)
res.add(T1(f1, f2))
}
rs.close()
stmt.close()
con.close()
return res
}
fun insertOneT1(o: T1) {
val con = DriverManager.getConnection("jdbc:mysql://arnepc5/test", "arne", "hemmeligt")
val pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)")
pstmt.setInt(1, o.f1)
pstmt.setString(2, o.f2)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
fun deleteOneT1(f1: Int) {
val con = DriverManager.getConnection("jdbc:mysql://arnepc5/test", "arne", "hemmeligt")
val pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?")
pstmt.setInt(1, f1)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
}
Start URL: http://nodename:port/show
src/main/resources/templates/thymeleaf/showx.html:
<html xmlns:th="https://thymeleaf.org">
<head>
<title>Ktor with Thymeleaf (pool)</title>
</head>
<body>
<h1>Ktor with Thymeleaf (pool)</h1>
<h2>Show data:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
<th></th>
</tr>
<tr th:each="o: ${data}">
<td th:text="${o.f1}"/>
<td th:text="${o.f2}"/>
<td><a th:href="@{delx?f1={v}(v=${o.f1})}">Delete</a></td>
</tr>
</table>
<h2>Add data:</h2>
<form method="post" action="addx" th:object="${addForm}">
F1: <input type="text" name="f1" th:field="*{f1}"/>
<br>
F2: <input type="text" name="f2" th:field="*{f2}"/>
<br>
<input type="submit" value="Add"/>
</form>
</body>
</html>
src/main/kotlin/demo/plugins/Templating.kt:
package demo.plugins
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.thymeleaf.Thymeleaf
import io.ktor.server.thymeleaf.ThymeleafContent
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver
import demo.model.*
fun Application.configureTemplating() {
install(Thymeleaf) {
setTemplateResolver(ClassLoaderTemplateResolver().apply {
prefix = "templates/thymeleaf/"
suffix = ".html"
characterEncoding = "utf-8"
})
}
routing {
get("/show") {
call.respond(ThymeleafContent("show", mapOf("data" to Data.selectAllT1(), "addForm" to AddForm("", ""))))
}
get("/showx") {
call.respond(ThymeleafContent("showx", mapOf("data" to DataX.selectAllT1(), "addForm" to AddForm("", ""))))
}
}
}
data class AddForm(var f1: String, var f2: String)
src/main/kotlin/demo/plugins/Routing.kt:
package demo.plugins
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import demo.model.*
fun Application.configureRouting() {
routing {
post("/add") {
val param = call.receiveParameters()
val f1 = param["f1"]!!.toInt()
val f2 = param["f2"].toString()
Data.insertOneT1(T1(f1, f2))
call.respondRedirect("/show")
}
get("/del") {
val f1 = call.request.queryParameters["f1"]!!.toInt()
Data.deleteOneT1(f1)
call.respondRedirect("/show")
}
post("/addx") {
val param = call.receiveParameters()
val f1 = param["f1"]!!.toInt()
val f2 = param["f2"].toString()
DataX.insertOneT1(T1(f1, f2))
call.respondRedirect("/showx")
}
get("/delx") {
val f1 = call.request.queryParameters["f1"]!!.toInt()
DataX.deleteOneT1(f1)
call.respondRedirect("/showx")
}
}
}
src/main/kotlin/demo/model/DataX.kt:
package demo.model
import java.sql.*
import org.apache.commons.dbcp2.*
import org.apache.commons.pool2.impl.*
data class T1X(var f1: Int, var f2: String)
object DataX {
init {
Class.forName("org.apache.commons.dbcp2.PoolingDriver")
val driver = DriverManager.getDriver("jdbc:apache:commons:dbcp:") as PoolingDriver
val pcf = PoolableConnectionFactory(DriverManagerConnectionFactory("jdbc:mysql://arnepc5/test", "arne", "hemmeligt"), null)
val cp = GenericObjectPool<PoolableConnection>(pcf)
cp.setMinIdle(10)
cp.setMaxTotal(100)
pcf.setPool(cp)
driver.registerPool("test", cp)
}
fun selectAllT1(): List<T1> {
val con = DriverManager.getConnection("jdbc:apache:commons:dbcp:test", "arne", "hemmeligt")
val stmt = con.createStatement()
val rs = stmt.executeQuery("SELECT f1,f2 FROM t1")
val res = ArrayList<T1>()
while(rs.next()) {
val f1 = rs.getInt(1)
val f2 = rs.getString(2)
res.add(T1(f1, f2))
}
rs.close()
stmt.close()
con.close()
return res
}
fun insertOneT1(o: T1) {
val con = DriverManager.getConnection("jdbc:apache:commons:dbcp:test", "arne", "hemmeligt")
val pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)")
pstmt.setInt(1, o.f1)
pstmt.setString(2, o.f2)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
fun deleteOneT1(f1: Int) {
val con = DriverManager.getConnection("jdbc:apache:commons:dbcp:test", "arne", "hemmeligt")
val pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?")
pstmt.setInt(1, f1)
pstmt.executeUpdate()
pstmt.close()
con.close()
}
}
Start URL: http://nodename:port/shows
JSP is a relative old technology and comes with a lot of baggage, so new view technologies was invented in the Java world.
Spring MVC introduced Thymeleaf as alternative to JSP.
display.html:
<html xmlns:th="https://thymeleaf.org">
<head>
<title>Spring with Thymeleaf view</title>
</head>
<body>
<h1>Spring with Thymeleaf view</h1>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<tr th:each="o: ${data}">
<td th:text="${o.f1}"/>
<td th:text="${o.f2}"/>
<td><a th:href="@{del?f1={v}(v=${o.f1})}">Delete</a></td>
</tr>
</table>
<h2>Add:</h2>
<form method="post" th:action="@{add}" th:object="${addForm}">
F1: <input type="text" name="f1" th:field="*{f1}"/>
<br>
F2: <input type="text" name="f2" th:field="*{f2}"/>
<br>
<input type="submit" value="Add"/>
</form>
</body>
</html>
AddForm.java:
package springtl;
public class AddForm {
private Integer f1;
private String f2;
public AddForm() {
this(null, null);
}
public AddForm(Integer f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public Integer getF1() {
return f1;
}
public void setF1(Integer f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
Manager.java:
package springtl;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.servlet.View;
@Controller
public class Manager {
@RequestMapping(value="/show", method=RequestMethod.GET)
public String show(Model m) {
Data data = new Data();
m.addAttribute("data", data.selectAllT1());
m.addAttribute("addForm", new AddForm());
return "display";
}
@RequestMapping(value="/add", method=RequestMethod.POST)
public View add(@ModelAttribute("addForm") AddForm addfrm, Model m) {
T1 o = new T1(addfrm.getF1(), addfrm.getF2());
Data data = new Data();
data.insertOneT1(o);
return new RedirectView("show");
}
@RequestMapping(value="/del", method=RequestMethod.GET)
public View del(@RequestParam("f1") int f1, Model m) {
Data data = new Data();
data.deleteOneT1(f1);
return new RedirectView("show");
}
}
T1.java:
package springtl;
import java.io.Serializable;
public class T1 implements Serializable {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
Data.java:
package springtl;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Data {
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/show
displayx.html:
<html xmlns:th="https://thymeleaf.org">
<head>
<title>Spring with Thymeleaf view (pool)</title>
</head>
<body>
<h1>Spring with Thymeleaf view (pool)</h1>
<h2>Show:</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<tr th:each="o: ${data}">
<td th:text="${o.f1}"/>
<td th:text="${o.f2}"/>
<td><a th:href="@{delx?f1={v}(v=${o.f1})}">Delete</a></td>
</tr>
</table>
<h2>Add:</h2>
<form method="post" th:action="@{addx}" th:object="${addForm}">
F1: <input type="text" name="f1" th:field="*{f1}"/>
<br>
F2: <input type="text" name="f2" th:field="*{f2}"/>
<br>
<input type="submit" value="Add"/>
</form>
</body>
</html>
AddForm.java:
package springtl;
public class AddForm {
private Integer f1;
private String f2;
public AddForm() {
this(null, null);
}
public AddForm(Integer f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public Integer getF1() {
return f1;
}
public void setF1(Integer f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
ManagerX.java:
package springtl;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.servlet.View;
@Controller
public class ManagerX {
@RequestMapping(value="/showx", method=RequestMethod.GET)
public String showx(Model m) {
DataX data = new DataX();
m.addAttribute("data", data.selectAllT1());
m.addAttribute("addForm", new AddForm());
return "displayx";
}
@RequestMapping(value="/addx", method=RequestMethod.POST)
public View addx(@ModelAttribute("addForm") AddForm addfrm, Model m) {
T1 o = new T1(addfrm.getF1(), addfrm.getF2());
DataX data = new DataX();
data.insertOneT1(o);
return new RedirectView("showx");
}
@RequestMapping(value="/delx", method=RequestMethod.GET)
public View delx(@RequestParam("f1") int f1, Model m) {
DataX data = new DataX();
data.deleteOneT1(f1);
return new RedirectView("showx");
}
}
T1.java:
package springtl;
import java.io.Serializable;
public class T1 implements Serializable {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
DataX.java:
package springtl;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DataX {
private static DataSource ds;
static {
try {
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
ds = (DataSource)envctx.lookup("jdbc/TestDB");
} catch(NamingException ex) {
ex.printStackTrace();
}
}
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/showx
[.WEB-INF]web.xml:
<web-app 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_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
[.WEB-INF]spring-servlet.xml:
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:context = "http://www.springframework.org/schema/context"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="springtl" />
<bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/html/" />
<property name="suffix" value=".html" />
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
</bean>
</beans>
Directory structure:
Directory TOMCAT$ROOT:[webapps.springtl] WEB-INF.DIR;1 Total of 1 file. Directory TOMCAT$ROOT:[webapps.springtl.WEB-INF] classes.DIR;1 html.DIR;1 lib.DIR;1 spring-servlet.xml;1 web.xml;1 Total of 5 files. Directory TOMCAT$ROOT:[webapps.springtl.WEB-INF.classes] springtl.DIR;1 Total of 1 file. Directory TOMCAT$ROOT:[webapps.springtl.WEB-INF.classes.springtl] AddForm.class;1 AddForm.java;1 Data.class;1 Data.java;1 DataX.class;1 DataX.java;1 gen.com;1 Manager.class;1 Manager.java;1 ManagerX.class;1 ManagerX.java;1 T1.class;1 T1.java;1 Total of 13 files. Directory TOMCAT$ROOT:[webapps.springtl.WEB-INF.html] display.html;1 displayx.html;1 Total of 2 files. Directory TOMCAT$ROOT:[webapps.springtl.WEB-INF.lib] attoparser-2_0_6_RELEASE.jar;1 commons-logging-1_1.jar;1 mysql-connector-j-8_0_33.jar;1 slf4j-api-2_0_3.jar;1 spring-aop-5_1_2_RELEASE.jar;1 spring-aspects-5_1_2_RELEASE.jar;1 spring-beans-5_1_2_RELEASE.jar;1 spring-context-5_1_2_RELEASE.jar;1 spring-core-5_1_2_RELEASE.jar;1 spring-expression-5_1_2_RELEASE.jar;1 spring-web-5_1_2_RELEASE.jar;1 spring-webmvc-5_1_2_RELEASE.jar;1 thymeleaf-3_1_0_RELEASE.jar;1 thymeleaf-extras-springsecurity5-3_1_0_RELEASE.jar;1 thymeleaf-spring5-3_1_0_RELEASE.jar;1 unbescape-1_1_6_RELEASE.jar;1 Total of 16 files. Grand total of 6 directories, 38 files.
JSF from the beginning supported two view technologies: JSP and facelets.
In JSF 2.x then JSP became deprecated and facelets became the recommended view technology.
In JSF 2.x the XML declarations was replaced by annotations.
For more details about JSF see here.
show.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>JSF with facelet view</title>
</h:head>
<h:body>
<f:view>
<h1>JSF with facelet view</h1>
<h2>Show (data table):</h2>
<h:dataTable value="#{manager.data}" var="o" border="1">
<h:column><f:facet name="header">F1</f:facet>#{o.f1}</h:column>
<h:column><f:facet name="header">F2</f:facet>#{o.f2}</h:column>
<h:column><h:form><h:commandButton value="Delete" action="#{manager.del(o.f1)}"/></h:form></h:column>
</h:dataTable>
<h2>Show (loop):</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<ui:repeat value="#{manager.data}" var="o">
<tr>
<td><h:outputText value="#{o.f1}"/></td>
<td><h:outputText value="#{o.f2}"/></td>
<td><h:form><h:commandButton value="Delete" action="#{manager.del(o.f1)}"/></h:form></td>
</tr>
</ui:repeat>
</table>
<h2>Add:</h2>
<h:form>
F1: <h:inputText value="#{manager.f1}"/>
<br/>
F2: <h:inputText value="#{manager.f2}"/>
<br/>
<h:commandButton value="Add" action="#{manager.add}"/>
</h:form>
</f:view>
</h:body>
</html>
Manager.java:
package jsf2;
import java.io.Serializable;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean
@SessionScoped
public class Manager implements Serializable {
// show
public List<T1> getData() {
Data data = new Data();
return data.selectAllT1();
}
// add
private Integer f1;
private String f2;
public Integer getF1() {
return f1;
}
public void setF1(Integer f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
public String add() {
T1 o = new T1((int)f1, f2);
Data data = new Data();
data.insertOneT1(o);
f1 = null;
f2 = null;
return "display";
}
// del
public String del(int f1) {
Data data = new Data();
data.deleteOneT1(f1);
return "display";
}
}
T1.java:
package jsf2;
import java.io.Serializable;
public class T1 implements Serializable {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
Data.java:
package jsf2;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Data {
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/show.jsf
showx.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>JSF with facelet view (pool)</title>
</h:head>
<h:body>
<f:view>
<h1>JSF with facelet view (pool)</h1>
<h2>Show (data table):</h2>
<h:dataTable value="#{managerX.data}" var="o" border="1">
<h:column><f:facet name="header">F1</f:facet>#{o.f1}</h:column>
<h:column><f:facet name="header">F2</f:facet>#{o.f2}</h:column>
<h:column><h:form><h:commandButton value="Delete" action="#{managerX.del(o.f1)}"/></h:form></h:column>
</h:dataTable>
<h2>Show (loop):</h2>
<table border="1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
<ui:repeat value="#{managerX.data}" var="o">
<tr>
<td><h:outputText value="#{o.f1}"/></td>
<td><h:outputText value="#{o.f2}"/></td>
<td><h:form><h:commandButton value="Delete" action="#{managerX.del(o.f1)}"/></h:form></td>
</tr>
</ui:repeat>
</table>
<h2>Add:</h2>
<h:form>
F1: <h:inputText value="#{managerX.f1}"/>
<br/>
F2: <h:inputText value="#{managerX.f2}"/>
<br/>
<h:commandButton value="Add" action="#{managerX.add}"/>
</h:form>
</f:view>
</h:body>
</html>
ManagerX.java:
package jsf2;
import java.io.Serializable;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean
@SessionScoped
public class ManagerX implements Serializable {
// show
public List<T1> getData() {
DataX data = new DataX();
return data.selectAllT1();
}
// add
private Integer f1;
private String f2;
public Integer getF1() {
return f1;
}
public void setF1(Integer f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
public String add() {
T1 o = new T1((int)f1, f2);
DataX data = new DataX();
data.insertOneT1(o);
f1 = null;
f2 = null;
return "display";
}
// del
public String del(int f1) {
DataX data = new DataX();
data.deleteOneT1(f1);
return "display";
}
}
T1.java:
package jsf2;
import java.io.Serializable;
public class T1 implements Serializable {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
DataX.java:
package jsf2;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DataX {
private static DataSource ds;
static {
try {
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
ds = (DataSource)envctx.lookup("jdbc/TestDB");
} catch(NamingException ex) {
ex.printStackTrace();
}
}
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/showx.jsf
[.WEB-INF]web.xml:
<web-app 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_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<resource-env-ref>
<resource-env-ref-name>BeanManager</resource-env-ref-name>
<resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
</resource-env-ref>
</web-app>
[.WEB-INF]faces-config.xml:
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
</faces-config>
[.WEB-INF]beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="annotated">
</beans>
[.META-INF]Context.xml:
<Context>
<Resource name="BeanManager"
auth="Container"
type="javax.enterprise.inject.spi.BeanManager"
factory="org.jboss.weld.resources.ManagerObjectFactory" />
</Context>
The last two config files are required to get dependency injection working in Tomcat.
And fair warning: one need to be very careful with this stuff to get dependency injection working in Tomcat - just one tiny mistake and the managed bean reference end up as null.
Directory structure:
Directory TOMCAT$ROOT:[webapps.jsf2] META-INF.DIR;1 show.xhtml;1 showx.xhtml;1 WEB-INF.DIR;1 Total of 4 files. Directory TOMCAT$ROOT:[webapps.jsf2.META-INF] Context.xml;1 Total of 1 file. Directory TOMCAT$ROOT:[webapps.jsf2.WEB-INF] beans.xml;1 classes.DIR;1 faces-config.xml;1 lib.DIR;1 web.xml;1 Total of 5 files. Directory TOMCAT$ROOT:[webapps.jsf2.WEB-INF.classes] jsf2.DIR;1 Total of 1 file. Directory TOMCAT$ROOT:[webapps.jsf2.WEB-INF.classes.jsf2] Data.class;1 Data.java;1 DataX.class;1 DataX.java;1 gen.com;1 Manager.class;1 Manager.java;1 ManagerX.class;1 ManagerX.java;1 T1.class;1 T1.java;1 Total of 11 files. Directory TOMCAT$ROOT:[webapps.jsf2.WEB-INF.lib] commons-beanutils-1_9_2.jar;1 commons-collections-3_2_2.jar;1 commons-digester-1_8.jar;1 commons-logging-1_1_1.jar;1 geronimo-atinject_1_0_spec-1_0.jar;1 myfaces-api-2_2_12.jar;1 myfaces-bundle-2_2_12.jar;1 myfaces-impl-2_2_12.jar;1 mysql-connector-j-8_0_33.jar;1 weld-servlet-shaded.jar;1 Total of 10 files. Grand total of 6 directories, 32 files.
The current trend in web applications are "HTML 5 web applications".
Which really is not much about HTML 4.x versus HTML 5.x.
Instead it covers an architecture with:
There are several wellknown JavaScript frameworks for doing the client side including Angular, Vue and React.
I don't have the skills to do Angular, Vue or React, so I will just do a demo client using plain jQuery and primitive DOM manipulation.
Slim is a popular PHP framework for RESTful web services.
As I cannot get composer working on VMS, then I created the project on PC, zipped, uploaded to VMS and unzipped.
Project creation:
php composer.phar require slim/slim
php composer.phar require guzzlehttp/psr7 "^2"
display.html:
<html>
<head>
<title>HTML 5 + Slim</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
function fmtrow(f1, f2) {
var res = '';
res += '<tr id="row_' + f1 + '">';
res += '<td>' + f1 + '</td>';
res += '<td>' + f2 + '</td>';
res += '<td><input type="button" value="Delete" onclick="del(' + f1 + ')"></td>';
res += '</tr>';
return res;
}
function show() {
$.ajax({
method: 'GET',
url: 'http://192.168.68.40/api.php/t1',
headers: { accept: 'application/json' },
dataType: 'json'
}).done(function(data) {
var rows = '';
for(var i = 0; i < data.length; i++) {
var o = data[i];
rows += fmtrow(o.f1, o.f2);
}
$('#t1').append(rows);
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function add() {
f1 = $('#f1').val();
f2 = $('#f2').val();
$.ajax({
method: 'POST',
url: 'http://192.168.68.40/api.php/t1',
headers: { accept: 'application/json', "content-type": 'application/json' },
dataType: 'json',
data: '{"f1":' + f1 + ',"f2":"' + f2 + '"}'
}).done(function(data) {
$('#t1').append(fmtrow(f1, f2));
$('#f1').val('');
$('#f2').val('');
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function del(f1) {
$.ajax({
method: 'DELETE',
url: 'http://192.168.68.40/api.php/t1/' + f1
}).done(function(data) {
$('#row_' + f1).remove();
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
$(document).ready(show());
</script>
</head>
<body>
<h1>HTML 5 + Slim</h1>
<h2>Show:</h2>
<table border="1" id="t1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
</table>
<h2>Add:</h2>
<form>
F1: <input type="text" name="f1" id="f1">
<br>
F2: <input type="text" name="f2" id="f2">
<br>
<input type="button" value="Add" onclick="add()">
</form>
</body>
</html>
api.php:
<?php
require '../vendor/autoload.php';
require 'T1.php';
require 'Data.php';
use Slim\Factory\AppFactory;
$app = AppFactory::create();
$app->get('/api.php/t1', function($request, $response, $args) {
$data = new Data();
$response->getBody()->write(json_encode($data->selectAllT1()));
return $response->withHeader('Content-Type', 'application/json');
});
$app->post('/api.php/t1', function($request, $response, $args) {
$o = json_decode($request->getBody());
$data = new Data();
$data->insertOneT1($o);
$response->getBody()->write(json_encode($o));
return $response->withHeader('Content-Type', 'application/json');
});
$app->delete('/api.php/t1/{f1}', function($request, $response, $args) {
$f1 = (int)$args['f1'];
$data = new Data();
$data->deleteOneT1($f1);
return $response->withStatus(204);
});
$app->run();
?>
T1.php:
<?php
class T1 {
public $f1;
public $f2;
public function __construct($f1, $f2) {
$this->f1 = $f1;
$this->f2 = $f2;
}
}
?>
Data.php:
<?php
class Data {
private function getConnection() {
$con = mysqli_connect('arnepc5', 'arne', 'hemmeligt', 'test');
return $con;
}
public function selectAllT1() {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'SELECT f1,f2 FROM t1');
mysqli_stmt_execute($stmt);
$rs = mysqli_stmt_get_result($stmt);
$res = array();
while($row = mysqli_fetch_array($rs, MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
$res[] = new T1($f1, $f2);
}
mysqli_stmt_close($stmt);
mysqli_close($con);
return $res;
}
public function insertOneT1($o) {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'INSERT INTO t1 VALUES(?,?)');
mysqli_stmt_bind_param($stmt, 'is', $o->f1, $o->f2);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
public function deleteOneT1($f1) {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'DELETE FROM t1 WHERE f1 = ?');
mysqli_stmt_bind_param($stmt, 'i', $f1);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
}
?>
Start URL: http://nodename:port/api.php/t1
displayx.html:
<html>
<head>
<title>HTML 5 + Slim (pool)</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
function fmtrow(f1, f2) {
var res = '';
res += '<tr id="row_' + f1 + '">';
res += '<td>' + f1 + '</td>';
res += '<td>' + f2 + '</td>';
res += '<td><input type="button" value="Delete" onclick="del(' + f1 + ')"></td>';
res += '</tr>';
return res;
}
function show() {
$.ajax({
method: 'GET',
url: 'http://192.168.68.40/apix.php/t1x',
headers: { accept: 'application/json' },
dataType: 'json'
}).done(function(data) {
var rows = '';
for(var i = 0; i < data.length; i++) {
var o = data[i];
rows += fmtrow(o.f1, o.f2);
}
$('#t1').append(rows);
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function add() {
f1 = $('#f1').val();
f2 = $('#f2').val();
$.ajax({
method: 'POST',
url: 'http://192.168.68.40/apix.php/t1x',
headers: { accept: 'application/json', "content-type": 'application/json' },
dataType: 'json',
data: '{"f1":' + f1 + ',"f2":"' + f2 + '"}'
}).done(function(data) {
$('#t1').append(fmtrow(f1, f2));
$('#f1').val('');
$('#f2').val('');
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function del(f1) {
$.ajax({
method: 'DELETE',
url: 'http://192.168.68.40/apix.php/t1x/' + f1
}).done(function(data) {
$('#row_' + f1).remove();
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
$(document).ready(show());
</script>
</head>
<body>
<h1>HTML 5 + Slim (pool)</h1>
<h2>Show:</h2>
<table border="1" id="t1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
</table>
<h2>Add:</h2>
<form>
F1: <input type="text" name="f1" id="f1">
<br>
F2: <input type="text" name="f2" id="f2">
<br>
<input type="button" value="Add" onclick="add()">
</form>
</body>
</html>
apix.php:
<?php
require '../vendor/autoload.php';
require 'T1.php';
require 'DataX.php';
use Slim\Factory\AppFactory;
$app = AppFactory::create();
$app->get('/apix.php/t1x', function($request, $response, $args) {
$data = new DataX();
$response->getBody()->write(json_encode($data->selectAllT1()));
return $response->withHeader('Content-Type', 'application/json');
});
$app->post('/apix.php/t1x', function($request, $response, $args) {
$o = json_decode($request->getBody());
$data = new DataX();
$data->insertOneT1($o);
$response->getBody()->write(json_encode($o));
return $response->withHeader('Content-Type', 'application/json');
});
$app->delete('/apix.php/t1x/{f1}', function($request, $response, $args) {
$f1 = (int)$args['f1'];
$data = new DataX();
$data->deleteOneT1($f1);
return $response->withStatus(204);
});
$app->run();
?>
T1.php:
<?php
class T1 {
public $f1;
public $f2;
public function __construct($f1, $f2) {
$this->f1 = $f1;
$this->f2 = $f2;
}
}
?>
DataX.php:
<?php
class DataX {
private function getConnection() {
$con = mysqli_connect('p:arnepc5', 'arne', 'hemmeligt', 'test');
return $con;
}
public function selectAllT1() {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'SELECT f1,f2 FROM t1');
mysqli_stmt_execute($stmt);
$rs = mysqli_stmt_get_result($stmt);
$res = array();
while($row = mysqli_fetch_array($rs, MYSQLI_ASSOC)) {
$f1 = $row['f1'];
$f2 = $row['f2'];
$res[] = new T1($f1, $f2);
}
mysqli_stmt_close($stmt);
mysqli_close($con);
return $res;
}
public function insertOneT1($o) {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'INSERT INTO t1 VALUES(?,?)');
mysqli_stmt_bind_param($stmt, 'is', $o->f1, $o->f2);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
public function deleteOneT1($f1) {
$con = $this->getConnection();
$stmt = mysqli_prepare($con, 'DELETE FROM t1 WHERE f1 = ?');
mysqli_stmt_bind_param($stmt, 'i', $f1);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
}
?>
Start URL: http://nodename:port/display.html
Flask is a very common framework for RESTful web services in Python.
display.html:
<html>
<head>
<title>HTML 5 + Flask</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
function fmtrow(f1, f2) {
var res = '';
res += '<tr id="row_' + f1 + '">';
res += '<td>' + f1 + '</td>';
res += '<td>' + f2 + '</td>';
res += '<td><input type="button" value="Delete" onclick="del(' + f1 + ')"></td>';
res += '</tr>';
return res;
}
function show() {
$.ajax({
method: 'GET',
url: 'http://arne1.vajhoej.dk/flask/flaskapi/t1',
headers: { accept: 'application/json' },
dataType: 'json'
}).done(function(data) {
var rows = '';
for(var i = 0; i < data.length; i++) {
var o = data[i];
rows += fmtrow(o[0], o[1]);
}
$('#t1').append(rows);
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function add() {
f1 = $('#f1').val();
f2 = $('#f2').val();
$.ajax({
method: 'POST',
url: 'http://arne1.vajhoej.dk/flask/flaskapi/t1',
headers: { accept: 'application/json', "content-type": 'application/json' },
dataType: 'json',
data: '{"f1":' + f1 + ',"f2":"' + f2 + '"}'
}).done(function(data) {
$('#t1').append(fmtrow(f1, f2));
$('#f1').val('');
$('#f2').val('');
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function del(f1) {
$.ajax({
method: 'DELETE',
url: 'http://arne1.vajhoej.dk/flask/flaskapi/t1/' + f1
}).done(function(data) {
$('#row_' + f1).remove();
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
$(document).ready(show());
</script>
</head>
<body>
<h1>HTML 5 + Flask</h1>
<h2>Show:</h2>
<table border="1" id="t1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
</table>
<h2>Add:</h2>
<form>
F1: <input type="text" name="f1" id="f1">
<br>
F2: <input type="text" name="f2" id="f2">
<br>
<input type="button" value="Add" onclick="add()">
</form>
</body>
</html>
server.py:
from flask import Flask, request, Response
import json
import pymysql
app = Flask(__name__)
@app.route('/flaskapi/t1', methods=['GET'])
def get_all():
con = pymysql.connect(host='localhost',user='root',password='',db='test')
c = con.cursor()
c.execute('SELECT f1,f2 FROM t1')
res = c.fetchall()
c.close()
con.close()
return Response(json.dumps(res), status=200, content_type='application/json')
@app.route('/flaskapi/t1', methods=['POST'])
def add():
o = json.loads(request.data)
con = pymysql.connect(host='localhost',user='root',password='',db='test')
c = con.cursor()
c.execute('INSERT INTO t1(f1,f2) VALUES(%s,%s)', (o['f1'], o['f2']))
c.close()
con.close()
return Response(json.dumps(o), status=200, content_type='application/json')
@app.route('/flaskapi/t1/<int:f1>', methods=['DELETE'])
def xdel(f1):
con = pymysql.connect(host='localhost',user='root',password='',db='test')
c = con.cursor()
c.execute('DELETE FROM t1 WHERE f1 = %s', (f1,))
c.close()
con.close()
return Response(status=204)
if __name__ == '__main__':
app.run(host='arne1.vajhoej.dk', port=8000)
Start URL: http://nodename:port/display.html
The setup I tested with is:
Apache httpd.conf fragment:
ProxyPass "/flask" "http://arne1.vajhoej.dk:8000"
So:
JAX-RS is the Java standard for RESTful web services. Jersey is an implementation of that standard.
display.html:
<html>
<head>
<title>HTML 5 + Jersey</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
function fmtrow(f1, f2) {
var res = '';
res += '<tr id="row_' + f1 + '">';
res += '<td>' + f1 + '</td>';
res += '<td>' + f2 + '</td>';
res += '<td><input type="button" value="Delete" onclick="del(' + f1 + ')"></td>';
res += '</tr>';
return res;
}
function show() {
$.ajax({
method: 'GET',
url: 'http://192.168.68.40:8080/jersey/api/T1',
headers: { accept: 'application/json' },
dataType: 'json'
}).done(function(data) {
var rows = '';
for(var i = 0; i < data.t1.length; i++) {
var o = data.t1[i];
rows += fmtrow(o.f1, o.f2);
}
$('#t1').append(rows);
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function add() {
f1 = $('#f1').val();
f2 = $('#f2').val();
$.ajax({
method: 'POST',
url: 'http://192.168.68.40:8080/jersey/api/T1',
headers: { accept: 'application/json', "content-type": 'application/json' },
dataType: 'json',
data: '{"f1":' + f1 + ',"f2":"' + f2 + '"}'
}).done(function(data) {
$('#t1').append(fmtrow(f1, f2));
$('#f1').val('');
$('#f2').val('');
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function del(f1) {
$.ajax({
method: 'DELETE',
url: 'http://192.168.68.40:8080/jersey/api/T1/' + f1
}).done(function(data) {
$('#row_' + f1).remove();
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
$(document).ready(show());
</script>
</head>
<body>
<h1>HTML 5 + Jersey</h1>
<h2>Show:</h2>
<table border="1" id="t1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
</table>
<h2>Add:</h2>
<form>
F1: <input type="text" name="f1" id="f1">
<br>
F2: <input type="text" name="f2" id="f2">
<br>
<input type="button" value="Add" onclick="add()">
</form>
</body>
</html>
T1Service.java:
package jersey;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.POST;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
@Path("/T1")
public class T1Service {
@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("")
public List<T1> show() {
Data data = new Data();
return data.selectAllT1();
}
@POST
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
@Path("")
public T1 add(T1 o) {
Data data = new Data();
data.insertOneT1(o);
return o;
}
@DELETE
@Path("/{f1}")
public void del(@PathParam("f1") int f1) {
Data data = new Data();
data.deleteOneT1(f1);
}
}
T1.java:
package jersey;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class T1 {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
Data.java:
package jersey;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Data {
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/display.html
displayx.html:
<html>
<head>
<title>HTML 5 + Jersey (pool)</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
function fmtrow(f1, f2) {
var res = '';
res += '<tr id="row_' + f1 + '">';
res += '<td>' + f1 + '</td>';
res += '<td>' + f2 + '</td>';
res += '<td><input type="button" value="Delete" onclick="del(' + f1 + ')"></td>';
res += '</tr>';
return res;
}
function show() {
$.ajax({
method: 'GET',
url: 'http://192.168.68.40:8080/jersey/api/T1X',
headers: { accept: 'application/json' },
dataType: 'json'
}).done(function(data) {
var rows = '';
for(var i = 0; i < data.t1.length; i++) {
var o = data.t1[i];
rows += fmtrow(o.f1, o.f2);
}
$('#t1').append(rows);
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function add() {
f1 = $('#f1').val();
f2 = $('#f2').val();
$.ajax({
method: 'POST',
url: 'http://192.168.68.40:8080/jersey/api/T1X',
headers: { accept: 'application/json', "content-type": 'application/json' },
dataType: 'json',
data: '{"f1":' + f1 + ',"f2":"' + f2 + '"}'
}).done(function(data) {
$('#t1').append(fmtrow(f1, f2));
$('#f1').val('');
$('#f2').val('');
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function del(f1) {
$.ajax({
method: 'DELETE',
url: 'http://192.168.68.40:8080/jersey/api/T1X/' + f1
}).done(function(data) {
$('#row_' + f1).remove();
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
$(document).ready(show());
</script>
</head>
<body>
<h1>HTML 5 + Jersey (pool)</h1>
<h2>Show:</h2>
<table border="1" id="t1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
</table>
<h2>Add:</h2>
<form>
F1: <input type="text" name="f1" id="f1">
<br>
F2: <input type="text" name="f2" id="f2">
<br>
<input type="button" value="Add" onclick="add()">
</form>
</body>
</html>
T1XService.java:
package jersey;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.POST;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
@Path("/T1X")
public class T1XService {
@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("")
public List<T1> show() {
DataX data = new DataX();
return data.selectAllT1();
}
@POST
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
@Path("")
public T1 add(T1 o) {
DataX data = new DataX();
data.insertOneT1(o);
return o;
}
@DELETE
@Path("/{f1}")
public void del(@PathParam("f1") int f1) {
DataX data = new DataX();
data.deleteOneT1(f1);
}
}
T1.java:
package jersey;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class T1 {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
DataX.java:
package jersey;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DataX {
private static DataSource ds;
static {
try {
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
ds = (DataSource)envctx.lookup("jdbc/TestDB");
} catch(NamingException ex) {
ex.printStackTrace();
}
}
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/displayx.html
LoadServices.java:
package jersey;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/api")
public class LoadServices extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> res = new HashSet<Class<?>>();
res.add(T1Service.class);
res.add(T1XService.class);
return res;
}
}
web.xml:
<web-app 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_3_0.xsd"
version="3.0">
</web-app>
Directory structure:
Directory TOMCAT$ROOT:[webapps.jersey] display.html;1 displayx.html;1 WEB-INF.DIR;1 Total of 3 files. Directory TOMCAT$ROOT:[webapps.jersey.WEB-INF] classes.DIR;1 lib.DIR;1 web.xml;1 Total of 3 files. Directory TOMCAT$ROOT:[webapps.jersey.WEB-INF.classes] jersey.DIR;1 Total of 1 file. Directory TOMCAT$ROOT:[webapps.jersey.WEB-INF.classes.jersey] Data.class;1 Data.java;1 DataX.class;1 DataX.java;1 gen.com;1 LoadServices.class;1 LoadServices.java;1 T1.class;1 T1.java;1 T1Service.class;1 T1Service.java;1 T1XService.class;1 T1XService.java;1 Total of 13 files. Directory TOMCAT$ROOT:[webapps.jersey.WEB-INF.lib] activation-1_1_1.jar;1 asm-3_1.jar;1 config-1_4_3.jar;1 jackson-core-asl-1_1_1.jar;1 jaxb-api-2_1.jar;1 jaxb-impl-2_1_12.jar;1 jersey-bundle-1_2.jar;1 jersey-client-1_2.jar;1 jersey-core-1_2.jar;1 jersey-json-1_2.jar;1 jersey-server-1_2.jar;1 jettison-1_1.jar;1 jsr311-api-1_1_1.jar;1 mysql-connector-j-8_0_33.jar;1 stax-api-1_0-2.jar;1 Total of 15 files. Grand total of 5 directories, 35 files.
Spring MVC is not only for traditional web applicatiosn but also for RESTful web services.
display.html:
<html>
<head>
<title>HTML 5 + Spring</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
function fmtrow(f1, f2) {
var res = '';
res += '<tr id="row_' + f1 + '">';
res += '<td>' + f1 + '</td>';
res += '<td>' + f2 + '</td>';
res += '<td><input type="button" value="Delete" onclick="del(' + f1 + ')"></td>';
res += '</tr>';
return res;
}
function show() {
$.ajax({
method: 'GET',
url: 'http://192.168.68.40:8080/spring/api/T1',
headers: { accept: 'application/json' },
dataType: 'json'
}).done(function(data) {
var rows = '';
for(var i = 0; i < data.length; i++) {
var o = data[i];
rows += fmtrow(o.f1, o.f2);
}
$('#t1').append(rows);
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function add() {
f1 = $('#f1').val();
f2 = $('#f2').val();
$.ajax({
method: 'POST',
url: 'http://192.168.68.40:8080/spring/api/T1',
headers: { accept: 'application/json', "content-type": 'application/json' },
dataType: 'json',
data: '{"f1":' + f1 + ',"f2":"' + f2 + '"}'
}).done(function(data) {
$('#t1').append(fmtrow(f1, f2));
$('#f1').val('');
$('#f2').val('');
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function del(f1) {
$.ajax({
method: 'DELETE',
url: 'http://192.168.68.40:8080/spring/api/T1/' + f1
}).done(function(data) {
$('#row_' + f1).remove();
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
$(document).ready(show());
</script>
</head>
<body>
<h1>HTML 5 + Spring</h1>
<h2>Show:</h2>
<table border="1" id="t1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
</table>
<h2>Add:</h2>
<form>
F1: <input type="text" name="f1" id="f1">
<br>
F2: <input type="text" name="f2" id="f2">
<br>
<input type="button" value="Add" onclick="add()">
</form>
</body>
</html>
T1Service.java:
package spring;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value="/T1")
public class T1Service {
@RequestMapping(value="",method=RequestMethod.GET,produces={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<List<T1>> show() {
Data data = new Data();
return new ResponseEntity<List<T1>>(data.selectAllT1(), HttpStatus.OK);
}
@RequestMapping(value="",method=RequestMethod.POST,produces={MediaType.APPLICATION_JSON_VALUE},consumes={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<T1> add(@RequestBody T1 o) {
Data data = new Data();
data.insertOneT1(o);
return new ResponseEntity<T1>(o, HttpStatus.OK);
}
@RequestMapping(value="/{f1}",method=RequestMethod.DELETE)
public ResponseEntity<Void> delete(@PathVariable("f1") int f1) {
Data data = new Data();
data.deleteOneT1(f1);
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
}
T1.java:
package spring;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class T1 {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
Data.java:
package spring;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Data {
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://arnepc5:3306/test", "arne", "hemmeligt");
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(ClassNotFoundException ex) {
ex.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/display.html
displayx.html:
<html>
<head>
<title>HTML 5 + Spring (pool)</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
function fmtrow(f1, f2) {
var res = '';
res += '<tr id="row_' + f1 + '">';
res += '<td>' + f1 + '</td>';
res += '<td>' + f2 + '</td>';
res += '<td><input type="button" value="Delete" onclick="del(' + f1 + ')"></td>';
res += '</tr>';
return res;
}
function show() {
$.ajax({
method: 'GET',
url: 'http://192.168.68.40:8080/spring/api/T1X',
headers: { accept: 'application/json' },
dataType: 'json'
}).done(function(data) {
var rows = '';
for(var i = 0; i < data.length; i++) {
var o = data[i];
rows += fmtrow(o.f1, o.f2);
}
$('#t1').append(rows);
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function add() {
f1 = $('#f1').val();
f2 = $('#f2').val();
$.ajax({
method: 'POST',
url: 'http://192.168.68.40:8080/spring/api/T1X',
headers: { accept: 'application/json', "content-type": 'application/json' },
dataType: 'json',
data: '{"f1":' + f1 + ',"f2":"' + f2 + '"}'
}).done(function(data) {
$('#t1').append(fmtrow(f1, f2));
$('#f1').val('');
$('#f2').val('');
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
function del(f1) {
$.ajax({
method: 'DELETE',
url: 'http://192.168.68.40:8080/spring/api/T1X/' + f1
}).done(function(data) {
$('#row_' + f1).remove();
}).fail(function(header, status, error) {
alert(status + ' ' + error);
});
}
$(document).ready(show());
</script>
</head>
<body>
<h1>HTML 5 + Spring (pool)</h1>
<h2>Show:</h2>
<table border="1" id="t1">
<tr>
<th>F1</th>
<th>F2</th>
</tr>
</table>
<h2>Add:</h2>
<form>
F1: <input type="text" name="f1" id="f1">
<br>
F2: <input type="text" name="f2" id="f2">
<br>
<input type="button" value="Add" onclick="add()">
</form>
</body>
</html>
T1XService.java:
package spring;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value="/T1X")
public class T1XService {
@RequestMapping(value="",method=RequestMethod.GET,produces={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<List<T1>> show() {
DataX data = new DataX();
return new ResponseEntity<List<T1>>(data.selectAllT1(), HttpStatus.OK);
}
@RequestMapping(value="",method=RequestMethod.POST,produces={MediaType.APPLICATION_JSON_VALUE},consumes={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<T1> add(@RequestBody T1 o) {
DataX data = new DataX();
data.insertOneT1(o);
return new ResponseEntity<T1>(o, HttpStatus.OK);
}
@RequestMapping(value="/{f1}",method=RequestMethod.DELETE)
public ResponseEntity<Void> delete(@PathVariable("f1") int f1) {
DataX data = new DataX();
data.deleteOneT1(f1);
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
}
T1.java:
package spring;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class T1 {
private int f1;
private String f2;
public T1() {
this(0, "");
}
public T1(int f1, String f2) {
this.f1 = f1;
this.f2 = f2;
}
public int getF1() {
return f1;
}
public void setF1(int f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
}
DataX.java:
package spring;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DataX {
private static DataSource ds;
static {
try {
Context initctx = new InitialContext();
Context envctx = (Context)initctx.lookup("java:/comp/env");
ds = (DataSource)envctx.lookup("jdbc/TestDB");
} catch(NamingException ex) {
ex.printStackTrace();
}
}
public List<T1> selectAllT1() {
List<T1> res = new ArrayList<T1>();
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 FROM t1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
int f1 = rs.getInt(1);
String f2 = rs.getString(2);
T1 o = new T1(f1, f2);
res.add(o);
}
rs.close();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
return res;
}
public void insertOneT1(T1 o) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("INSERT INTO t1 VALUES(?,?)");
pstmt.setInt(1, o.getF1());
pstmt.setString(2, o.getF2());
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
public void deleteOneT1(int f1) {
try {
Connection con = ds.getConnection();
PreparedStatement pstmt = con.prepareStatement("DELETE FROM t1 WHERE f1 = ?");
pstmt.setInt(1, f1);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
}
Start URL: http://nodename:port/application/displayx.html
Application.java:
package spring;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class Application extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class[] getRootConfigClasses() {
return new Class[] { Config.class };
}
@Override
protected Class[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/api/*" };
}
}
Config.java:
package spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "spring")
public class Config {
}
web.xml:
<web-app 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_3_0.xsd"
version="3.0">
</web-app>
Directory structure:
Directory TOMCAT$ROOT:[webapps.spring] display.html;1 displayx.html;1 WEB-INF.DIR;1 Total of 3 files. Directory TOMCAT$ROOT:[webapps.spring.WEB-INF] classes.DIR;1 lib.DIR;1 web.xml;1 Total of 3 files. Directory TOMCAT$ROOT:[webapps.spring.WEB-INF.classes] spring.DIR;1 Total of 1 file. Directory TOMCAT$ROOT:[webapps.spring.WEB-INF.classes.spring] Application.class;1 Application.java;1 Config.class;1 Config.java;1 Data.class;1 Data.java;1 DataX.class;1 DataX.java;1 gen.com;1 T1.class;1 T1.java;1 T1Service.class;1 T1Service.java;1 T1XService.class;1 T1XService.java;1 Total of 15 files. Directory TOMCAT$ROOT:[webapps.spring.WEB-INF.lib] commons-logging-1_1.jar;1 jackson-annotations-2_9_0.jar;1 jackson-core-2_9_9.jar;1 jackson-databind-2_9_9.jar;1 jackson-dataformat-cbor-2_9_9.jar;1 jackson-dataformat-smile-2_9_9.jar;1 mysql-connector-j-8_0_33.jar;1 spring-aop-5_1_2_RELEASE.jar;1 spring-aspects-5_1_2_RELEASE.jar;1 spring-beans-5_1_2_RELEASE.jar;1 spring-context-5_1_2_RELEASE.jar;1 spring-core-5_1_2_RELEASE.jar;1 spring-expression-5_1_2_RELEASE.jar;1 spring-web-5_1_2_RELEASE.jar;1 spring-webmvc-5_1_2_RELEASE.jar;1 Total of 15 files. Grand total of 5 directories, 37 files.
The two key aspects of web application performance is:
Note that starting a new process to execute each request obviously does not work with an in memory database connection pool, so for a web application using database (and that is by far the most web applications) then we have 3 models:
Note that the database connection overhead increases significantly when switching to encryption between web application and database, which is increasingly becoming a security requirment.
Let us try measure.
Test configuration:
Config:
Results:
Technology | Model | requests/second |
---|---|---|
CGI (C) (Apache) |
start new process to execute each request | awaiting MySQL client libs on VMS x86-64) |
CGI (DCL wrapper + PHP) (Apache) |
start new process to execute each request | 4 |
CGI (DCL wrapper + Python) (Apache) |
start new process to execute each request | 1 |
Spagetti PHP - no pool (Apache mod_php) |
execute requests in thread within server process connect and disconnect to database for every request |
11 (default config) 133 (modified config) |
Spagetti PHP - pool (Apache mod_php) |
execute requests in thread within server process use an in memory database connection pool |
11 (default config) 151 (modified config) |
PHP DIY MVC - no pool (Apache mod_php) |
execute requests in thread within server process connect and disconnect to database for every request |
11 (default config) 94 (modified config) |
PHP DIY MVC - pool (Apache mod_php) |
execute requests in thread within server process use an in memory database connection pool |
11 (default config) 103 (modified config) |
PHP DIY MVC - no pool (Tomcat + Quercus) |
execute requests in thread within server process connect and disconnect to database for every request |
208 |
PHP DIY MVC - pool (Tomcat + Quercus) |
execute requests in thread within server process use an in memory database connection pool |
214 |
Spagetti JSP - no pool (Tomcat) |
execute requests in thread within server process connect and disconnect to database for every request |
105 |
Spagetti JSP - pool (Tomcat) |
execute requests in thread within server process use an in memory database connection pool |
691 |
JSP + Java DIY MVC - no pool (Tomcat) |
execute requests in thread within server process connect and disconnect to database for every request |
100 |
JSP + Java DIY MVC - pool (Tomcat) |
execute requests in thread within server process use an in memory database connection pool |
684 |
ZF - no pool (Apache mod_php) |
execute requests in thread within server process connect and disconnect to database for every request |
3 (default and modified config) |
ZF - pool (Apache mod_php) |
execute requests in thread within server process use an in memory database connection pool |
3 (default and modified config) |
Grails (Tomcat) |
execute requests in thread within server process connect and disconnect to database for every request |
87 |
Ktor with Thymeleaf view - no pool standalone |
execute requests in thread within server process connect and disconnect to database for every request |
95 |
Ktor with Thymeleaf view - pool standalone (with commons dbcp2) |
execute requests in thread within server process use an in memory database connection pool |
621 |
Spring with Thymeleaf view - no pool (Tomcat) |
execute requests in thread within server process connect and disconnect to database for every request |
87 |
Spring with Thymeleaf view - pool (Tomcat) |
execute requests in thread within server process use an in memory database connection pool |
618 |
JSF with Facelet view - non pool (Tomcat) |
execute requests in thread within server process connect and disconnect to database for every request |
50 |
JSF with Facelet view - pool (Tomcat) |
execute requests in thread within server process use an in memory database connection pool |
380 |
Technology | Model | requests/second |
---|---|---|
Slim - non pool (Apache mod_php) |
execute requests in thread within server process connect and disconnect to database for every request |
5 (default and modified config) |
Slim - pool (Apache mod_php) |
execute requests in thread within server process use an in memory database connection pool |
5 (default and modified config) |
Jersey - non pool (Tomcat) |
execute requests in thread within server process connect and disconnect to database for every request |
95 |
Jersey - pool (Tomcat) |
execute requests in thread within server process use an in memory database connection pool |
556 |
Spring MVC - non pool (Tomcat) |
execute requests in thread within server process connect and disconnect to database for every request |
96 |
Spring MVC - pool (Tomcat) |
execute requests in thread within server process use an in memory database connection pool |
621 |
We see that:
Changes to Apache config (difference between default and modified config):
More on the Java performance and resource requirements:
Regarding resources then this what I tested with:
$ mcr sysgen SYSGEN> SHOW CHANNELCNT Parameter Name Current Default Min. Max. Unit Dynamic -------------- ------- ------- ------- ------- ---- ------- CHANNELCNT 8192 512 64 65535 Channels
$ mcr authorize UAF> show system ... Maxjobs: 0 Fillm: 4000 Bytlm: 8192000 Maxacctjobs: 0 Shrfillm: 0 Pbytlm: 0 Maxdetach: 0 BIOlm: 2000 JTquota: 4096 Prclm: 10 DIOlm: 2000 WSdef: 4096 Prio: 4 ASTlm: 5000 WSquo: 8192 Queprio: 0 TQElm: 100 WSextent: 16384 CPU: (none) Enqlm: 32767 Pgflquo: 4000000
It is definitely possible to create web applications including modern web applications on VMS.
The available options to choose from may be smaller than on Linux/Windows, but there are multiple options.
What to choose will depend on ones skills in PHP, Java and JavaScript.
Apache performance on VMS is below expectations. I suspect that the port of *nix execution model with multiple variable number processes each running multiple threads did not port well to VMS. I suspect that the Windows model with a single massive multi-threaded process would work better (it does for Tomcat).
Version | Date | Description |
---|---|---|
1.0 | March 29th 2024 | Initial version |
1.1 | April 3rd 2024 | Add some DCL and Python examples |
1.2 | September 27th 2024 | New Apache + PHP performance numbers for modified config |
1.3 | October 27th 2024 | Add Ktor examples |
See list of all articles here
Please send comments to Arne Vajhøj
Personally I would choose like:
but that is because I know Java and Groovy.