1. Trang chủ
  2. » Công Nghệ Thông Tin

Web Server Programming phần 6 docx

63 282 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Client State And Sessions
Trường học University Name
Chuyên ngành Web Server Programming
Thể loại Bài tập
Năm xuất bản 2023
Thành phố City Name
Định dạng
Số trang 63
Dung lượng 625,1 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

public class CheckoutServlet extends HttpServlet { public void doGet HttpServletRequest request, HttpServletResponse response throws ServletException, IOException{ HttpSession current =

Trang 1

The CheckoutServlet gets invoked when the client follows one of the links in either aproducts form page or the response page produced by the PurchaseServlet Its doGet methoduses private helper functions to produce a display of the contents of the ‘shopping cart’ vector.

// The usual imports

public class CheckoutServlet extends HttpServlet {

public void doGet (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

HttpSession current = request.getSession(false);

if(current==null) {response.sendRedirect("/demo2/Login.html");

return;

}

listOrderItems(current, response);

}

private void listOrderItems(HttpSession current,

HttpServletResponse response) throws ServletException, IOException{

response.setContentType(”text/html”);

PrintWriter out = response.getWriter();

out.println("<html><head><title>Your order </title>");

out.println("</head><body bgcolor=white>");

Vector v = (Vector) current.getAttribute("shoppingcart");

if(v!=null) {out.println("<h2>Items in your cart</h2>");

out.println("<ul>");

Enumeration e = v.elements();

while(e.hasMoreElements()) {String str = (String) e.nextElement();

out.print("<li>");

out.println(str);

}out.println("</ul>");

}else out.println("The shopping cart was empty");

out.println("</body>");

out.println("</html>");

}

}

Trang 2

The LoginServlet made use of a SubscriberRecord’s ability to load itself from themembers data table:

import java.sql.*;

public class SubscriberRecord {

// As shown for the "members" example

public boolean loadFromDatabase(int idNumber, Connection db) {

// Try to load data for record with key idNumber // Clear private data members

"select * from members " +

"where membernumber=" + idNumber;

// Run the query, if get a result copy data

ResultSet rset = stmt.executeQuery(request);

// Database in mode where require explicit commits

db.commit();

}}catch (Exception e) {return false;

}

Trang 3

// Return success/failure result

Trang 4

7.6 Images

The PHP ‘Big Brother’ voting example illustrated how images are often the best way ofpresenting response data While the PHP image libraries do seem a little easier to use thantheir Java counterparts, it is possible for a servlet to return a GIF image (or other formatimage) Generation of images requires the use of classes that are not in the standard Javalibraries Standard Java awt code can create an image, but the image must be encoded inGIF or JPG format before it can be returned to a client Image encoders are available fromSun (in the package com.sun.image.codec.jpeg) or from http://www.acme.com/ Theacme.comweb site has links to a useful library of Java components that includes a GIFencoder

A servlet can generate an image file as a response by:

G Using the ServletOutputStream associated with the response rather than the usualPrintWriter A ServletOutputStream supports output of binary data

G Setting the content-type of the response to image/gif (or image/jpg as appropriate)

G Using an instance of Java’s BufferedImage class

G Getting the associated Graphics object

G Using this Graphics object to perform java.awt drawing operations

G Encoding the resulting image

(You may have problems running graphics examples on a shared Unix server with Xlibgraphics; these are essentially configuration problems At some points, the Java awt codeseeks information about the graphics devices available If none are defined, the image isnot generated The Xlib graphics library relies on an environment variable, DISPLAY, ref-erencing an X-server You should seek help from your system administrator regarding thesetting of this environment variable Java 1.4 awt has some extra functionionality aimed atavoiding such problems.)

The example generates a fixed image purportedly illustrating a histogram of utilityusage; its output is illustrated in Figure 7.1 The image is GIF-encoded, using the packageAcme.JPM.Encodersfrom http://www.acme.com/ The Acme package should be down-loaded and installed in the classes directory where the servlet is defined (the package isquite large; you can save space by extracting just the GIF encoder and its support classesand changing the import statements in the example code)

Figure 7.1 A simple graphic image response page from a servlet.

Trang 5

The servlet code is:

public class HistogramServlet extends HttpServlet {

public void doGet (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

Graphics g = null;

try{

// Pick up output stream for binary data

ServletOutputStream out = response.getOutputStream();

// Set the header type to say that we are returning an // image (gif encoded)

response.setContentType("image/gif");

// Create work space for building image in memory

BufferedImage bi = new BufferedImage(

GifEncoder encoder = new GifEncoder(bi, out);

Trang 6

// encode and send to client

encoder.encode();

}finally {

// Always remember to tidy up after using a Graphics // object.

if(g!=null) g.dispose();

}}

}

7.7 Security features

Servlet containers incorporate security controls that are a limited extension and ment of HTTP authentication Restrictions can be placed on servlets; only logged in userscan access restricted servlets The restriction system can even differentiate among dif-ferent servlet methods – some users might be able to use both get and post (read andupdate) methods of a servlet, while others might be restricted to get (read) access to thesame servlet Security restrictions are primarily a deployment issue A servlet can bewritten and then deployed in different environments with or without security restrictions.However, if a servlet is designed for use with security restrictions, its code can obtaindetails of the permissions pertaining to the current client; these details are obtained fromthe servlet container This allows a servlet to generate dynamic pages with content specifi-cally selected for different classes of users

refine-Restrictions are not defined for individual users; instead they apply to ‘roles’ that usersmay fill Really, ‘roles’ are simply the same as user groups in HTTP authentication InHTTP authentication, users can have individual names and passwords in the password file,while a group file contains a list of ‘groups’ and the user-identifiers of the members of eachgroup With servlets, ‘roles’ replace ‘groups’ The password files contain entries for eachuser; the entries comprise username, password and a list of the roles permitted to that user.The deployment specification, the web.xml file, contains any restrictions on access toservlets The restrictions are composed of the following elements:

G Security roles:

These elements simply list the role names that are referenced in the security constraintsand in the associated password files

Trang 7

Browser support for digests and client certificates is limited; usually, the login straints for servlets are either ‘basic’ (use the default browser support for HTTP authenti-cation) or ‘form’ (use a customized version of the HTTP authentication) The form style ispreferred because it allows for a site-specific login page that can provide help informationalong with input fields for a user’s name and password.

con-The example for this section illustrates:

G Form authentication

G Using roles to adapt behavior of servlets

G Using shared data held in an attribute of the servlet’s context

The example is a web application that records the times that employees spend on differenttasks and calculates pay The application comprises a number of servlets and associatedstatic HTML pages There are three classes (roles) of user: ‘boss’, ‘manager’ and

‘worker’ The application has a simple database with three tables: one table recordsdetails of work times (employee identifier, hours, task), another records employee/man-ager relations (managers can inspect their employees’ records), and the third table con-tains pay rates for different types of task The servlets are:

role-do vary The role-doPost method is common to all users; it adds a work record to the work datatable

The ShowRecord servlet is similar in that it can be used by all employees, but itsbehavior is again role-dependent Employees in the worker role can use this servlet toobtain a display of their own individual records Managers can see their own records or therecords of any employee that they manage A worker is immediately shown their personaldata; a manager is presented with a form in which the name of an employee can be entered.When this name is returned to the servlet, that employee’s record will be displayed (if themanager is permitted to see the data)

Only an employee in the boss role can use the final servlet: Rates This servlet can beused to add new task types or change the pay rates associated with existing task types

In total, the application comprises:

G Static HTML pages:

– Login page

Customized login page for entry of name and password (see Figure 7.3 onp 310)

Trang 8

Error report page for an attempt to view records without authority.

G Servlets and support classes:

– RateChangeServlet – insert or update records in rates data table; also updates an memory copy

in-– WorkerServlet in-– record hours worked and task

– CheckRecords servlet – inspect records of self or subordinate

G Data tables (illustrated in Figure 7.2):

– Work

Fields: name and activity as varchar, hours as double This holds records of the time

an employee spent on a task of a specified type

Trang 9

deployment file The updated version of the tomcat-users.xml file as used for thisexample is:

<tomcat-users>

<user name="tomcat" password="tomcat" roles="tomcat" />

<user name="Anne" password="7ftGvqm" roles="worker" />

<user name="Claire" password="Erialc" roles="manager,worker" />

<user name="Leila" password="s8hhgv45pn" roles="worker" />

Client entertainment 180

Trang 10

The default browser-supplied dialog used for HTTP authentication is rarely priate Most companies will wish to customize their login page The servlet container sup-ports such customization; the customized login page must simply use specified names forfields and return the inputs for processing by a specified action element The followinglogin form produces the simple login page illustrated in Figure 7.3.

appro-<HTML><TITLE>Acme Record's Login</TITLE>

<BODY>

<FORM METHOD=POST ACTION=j_security_check>

<table align=center border=2>

<caption>Enter your name and password</caption>

j_secu-In this example, each servlet manages a private connection to the database As usual, alock controls a connection so that only one thread can use a connection These servlets allperform their database activities in private auxiliary functions called from their doGet ordoPostmethods; these auxiliary functions are defined as synchronized – so applying alock to the entire function that accessed the database

Figure 7.3 A simple customized form for HTTP authentication.

Trang 11

The DBInfo class is a simple helper class used by the servlets when they need to opendatabase connections Its real role is to serve as a single point where details like drivers,passwords etc have to be defined.

import java.sql.*;

public class DBInfo {

// Substitute appropriate values for your database and drivers

public static final String userName = "HSimpson";

public static final String userPassword = "Duh";

private static final String dbDriverName =

"sun.jdbc.odbc.JdbcOdbcDriver";

private static final String dbURL =

"jdbc:odbc:Acme";

public static final Connection connectToDatabase() {

Connection dbConnection = null;

try {Class.forName (dbDriverName);

dbConnection = DriverManager.getConnection(

dbURL,userName, userPassword);

}catch(Exception e) { }return dbConnection;

}

}

The rates data are relatively heavily used Each request to record work needs to accessthe rates data (the choices of task type appropriate to show to different employee roles arebased on pay rate) The display of work done by an employee also needs to computeoverall pay and must access the rate data This usage makes worthwhile the use of an in-memory copy of the rates data

The class RatesRecord is instantiated to provide an in-memory version of the ratesdata It owns a Hashtable that maps String task names to Double values that hold payrates Its constructor loads the necessary data from the corresponding table in thedatabase

import java.util.*;

import java.sql.*;

public class RatesRecord {

private Hashtable rates = new Hashtable();

public Enumeration keys() { return rates.keys(); }

Trang 12

public double getRate(String task) {

double rate = 0.0;

try {Double data = (Double) rates.get(task);

rate = data.doubleValue();

}catch (Exception e) { }return rate;

Statement stmt =db.createStatement ();

String request =

"select * from rates";

ResultSet rset = stmt.executeQuery(request);

while(rset.next()) {String key = rset.getString("ACTIVITY");

double val = rset.getDouble("RATE");

Double dval = new Double(val);

rates.put(key,dval);

}stmt.close();

db.close();

}catch(Exception e) { }}

}

}

A RatesRecord object is placed in the ServletContext as its RatesTable attribute.Each servlet in this web application accesses the same ServletContext; if it needs the payrates data, a servlet asks for this RatesTable attribute If this attribute is null, therequesting servlet instantiates a RatesRecord and places it in the ServletContext; thenew RatesRecord loads the most recent data from the database Once loaded, the record isavailable for subsequent use by the same servlet, or any other servlet in the application

Trang 13

The RateChangeServlet implements both doGet and doPost methods Its doGetmethod creates a simple form that the boss can use to enter task names and pay rates ThedoPostmethod handles input with a new task and rate, or input with a new rate for anexisting task The servlet owns a database connection, used to update the rates table; this

is obtained, using the helper DBInfo class, in the init function and released in the destroyfunction There is only one boss, so mutex locks did not appear necessary for this databaseconnection!

public class RateChangeServlet extends HttpServlet {

private Connection dbConnection;

public void init() {

dbConnection = DBInfo.connectToDatabase();

}

public void destroy() {

if(dbConnection != null) {try {

dbConnection.close();

}catch(Exception e) { }}

public void doPost (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException

Trang 14

}

public void doGet (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

han-public void doGet (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<html><head><title>Change hourly rate</title></head>" );out.println("<body bgcolor=white>" );

out.println("<form action=\"/combo/Rates\" method=post>");

out.println("<table align=center border=2>");

out.println("<td colspan=2 align=center>");

out.println("<input type=Submit value=\"Submit Change\">");

Trang 15

HttpServletResponse response) throws ServletException, IOException{

// Pick up form data

String activity = request.getParameter("Activity");

String rate = request.getParameter("Rate");

// Perform limited validation of submitted data

if((activity==null) || (rate==null) ||

(activity.equals("")) || (rate.equals(""))) {response.sendRedirect("/combo/BadData.html");

// Need to check against existing records; obtain

// the RatesTable from the shared ServletContext

// Get existing rate; if 0, it's a new record

double dcurrent = rates.getRate(activity);

Trang 16

}

response.setContentType("text/html");

// Report that all is well

PrintWriter out = response.getWriter();

out.println("<html><head><title>Change recorded</title></head>");out.println("<body bgcolor=white>");

"insert into rates values (";

insertcommand = insertcommand + "'" + activity + "', ";

insertcommand = insertcommand + rate + ")";

Trang 17

The WorkerServlet has the same overall structure – init and destroy methods formanaging a database connection, a doGet function that generates a form, and a doPostfunction that, with the help of auxiliary functions, handles input from the form Thebehavior is slightly more interesting as the content of the form now depends on the roletaken by the client.

public class WorkerServlet extends HttpServlet {

private Connection dbConnection;

public void init() { }

public void destroy() { }

synchronized private boolean recordWork(

String name, String activity, double hours){

// Update Work data table

}

public void doPost (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

}

private void showOptions(HttpServletRequest req, PrintWriter out){

// Generate the options for a select box.

// Options are task names from rates table; the choice // of tasks is role dependent.

}

public void doGet (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<html><head><title>Record Work</title></head>" );

Trang 18

out.println("<body bgcolor=white>" );

out.println("<form action=\"/combo/Hours\" method=post>");

out.println("<table align=center border=2>");

out.println("<td colspan=2 align=center>");

out.println("<input type=Submit value=\"Submit Record\">");

out.println("</tr></table>");

out.println("</form></body></html>");

}

}

The data entry form has a field for input of hours worked, and a selection that displays a list

of options for task types These options are created in the auxiliary showOption method Thisobtains information about the user’s role from the HttpServletRequest object and details ofpay rates from the RatesRecord in the ServletContext (creating this RatesRecord if noneexists) The options are selected based on a combination of role and rate data

private void showOptions(HttpServletRequest req, PrintWriter out)

// Create if first user

rates = new RatesRecord();

ctx.setAttribute("RatesTable", rates);

}

double low = 0.0;

double high = Double.MAX_VALUE;

// Will list options for all tasks in pay low to high, setting

// these limits according to role of user.

// (Could make limit values into initialization parameters, this // would ease task of dealing with effects of rate changes)

Trang 19

String activity = (String) activities.nextElement();

double dval =rates.getRate(activity);

if((dval<low) || (dval>high)) continue;

(redi-public void doPost (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

// Read, validate inputs - redirect user if have problems

String activity = request.getParameter("Activity");

String time = request.getParameter("Hours");

if((activity==null) || (time==null) ||

(activity.equals("")) || (time.equals(""))) {response.sendRedirect("/combo/BadData.html");

// Pick up name of user

String name = request.getRemoteUser();

if(!recordWork(name, activity, dtime)) {

response.sendRedirect("/combo/NoDB.html");

Trang 20

The recordWork method, synchronized to prevent use by multiple threads, does asimple update of the work data table:

synchronized private boolean recordWork(

String name, String activity, double hours)

{

try {

Statement stmt = dbConnection.createStatement ();

String insertcommand =

"insert into Work values (";

insertcommand = insertcommand + "'" + name + "', ";

insertcommand = insertcommand + "'" + activity + "', ";

insertcommand = insertcommand + hours + ")";

an employee name This servlet once again has a database connection, created in the initmethod and cleared up in the destroy method; this is used to read data from the work andmanager tables The servlet again needs to identify the remote user both when generating

Trang 21

a report for a worker and when checking manager/employee relationships TheRatesTableheld by the ServletContext is accessed when generating reports.

import java.io.*;

// The usual imports

public class CheckRecords extends HttpServlet {

private Connection dbConnection;

public void init() { }

public void destroy() { }

public void doGet (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

if(request.isUserInRole("manager")) generatePrompt(response);

else

generateReport(request.getRemoteUser(), response);

}

public void doPost (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

}

private void generatePrompt(HttpServletResponse response)

throws ServletException, IOException{

// Send HTML form for entry of employee name

}

synchronized public void generateReport(String name,

HttpServletResponse response) throws ServletException, IOException{

// Select, then print details, of all records in the Work // table relating to specified name

Trang 22

private void generatePrompt(HttpServletResponse response)

throws ServletException, IOException

{

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<html><head><title>Check records</title></head>" );out.println("<body bgcolor=white>" );

out.println("<form action=\"/combo/ShowRecord\" method=post>");

out.println("<table align=center border=2>");

out.println("<tr><th>Employee's name</th>");

out.println("<td><input type=text name=ENAME size=20 maxsize=32>

</td>");

out.println("</tr>");

out.println("<td colspan=2 align=center>");

out.println("<input type=Submit value=\"Submit Request\">");

out.println("</tr></table>");

out.println("</form></body></html>");

}

The doPost function must confirm that it received a name as input, redirecting the user

if there was no data A work report can be generated if the entered employee name is thesame as the username (it is a manager reading his or her own work records) In other cases,the servlet must first confirm that the user really is a manager and then determine whetherhe/she manages the named employee

public void doPost (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException{

String person = request.getParameter("ENAME");

Trang 23

}

// Confirm that user is a manager (if not, send them an access

// denied error page)

The getManager function involves a simple database query:

synchronized private String getManager(String person)

"Select * from Manages where EMPLOYEE='" + person + "'";

ResultSet rset = stmt.executeQuery(selectcommand );

if(rset.next()) {manager = rset.getString("Manager");

}stmt.close();

Trang 24

to limit access to one thread at a time The calculation of total pay requires access to theRatesRecordheld by the ServletContext The body of the function is a big try-catchblock; any errors involving the database result in the client being diverted to the standardapology page.

synchronized public void generateReport(String name,

HttpServletResponse response) throws ServletException, IOException{

try {

response.setContentType("text/html");

// Generate header for work report response page

PrintWriter out = response.getWriter();

out.println("<html><head><title>Check records</title></head>" );out.println("<body bgcolor=white>" );

out.println("<h1 align=center>Records for " + name + "</h1><p>");int count = 0;

ctx.setAttribute("RatesTable", rates);

}Statement stmt = dbConnection.createStatement ();

String selectsql =

"Select * from Work where NAME='" + name + "'";

ResultSet rset = stmt.executeQuery(selectsql);

// Generate a table with work records (there may be none)

while(rset.next()) {if(count==0) {

// Output table header on first time

out.println("<table align=center border=2>");

// Grab data from result set

String key = rset.getString("activity");

double val = rset.getDouble("hours");

Trang 25

// Lookup rate in RatesTable

double rate = rates.getRate(key);

double amount = val*rate;

// Output line of HTML table

out.println("<tr><td align=right>"+ key + "</td>");

// Final outputs, total earnings

if(count==0) out.println("No work records available");

else out.println("</table><p>Total earnings $"+total);

The web.xml file is a little more complex in this case As usual, the file must define theservlets and their URLs; in this example, the class names, registered servlet names andURLs all happen to be distinct The additional security control data consists of a ‘securityconstraint’ section for each controlled servlet (actually, each URL – so you could have dif-ferent security constraints applying to the same servlet that depend on how the nameunder which it is accessed), a single login record, and a set of role names corresponding tothe worker, manager and boss roles The login record specifies the mechanism (BASIC forusing HTTP default authentication, FORM if using the custom version); if the FORM style isspecified, the login record must also identify the form page and the error page ‘Securityrole’ records simply name the roles

Trang 27

A security constraint consists of one (or more) ‘web resource collection’ and an associated

‘authorization constraint’ A web resource collection is basically a set of URLs and a list ofHTTP methods; it must also contain a name (which does not serve any real purpose exceptmaybe to help document things) An authorization constraint is basically a set of role names.The entry for the Rates service, which can only be utilized by clients in the boss role, is:

Trang 28

The other two services have similar security constraint records, except that they specifythe worker role in their authorization constraints.

Exercises

Practical

These exercises require a servlet engine The Apache Tomcat engine, run in standalonemode, is probably the most suitable This is available as a compressed (Windows exe or.zip, or Unix/Linux tar-gzip) file for download from http://jakarta.apache.org/tomcat/ The file can be decompressed and will install a version of Tomcat on yourmachine The system includes extensive documentation and examples Applicationsshould be prepared in some private directory and copied into Tomcat’s webapps directorywhen ready; apart from installing your applications, the only other changes that you mayneed to make are to files in Tomcat’s config directory This directory holds theusernames and passwords file, and other control files

It is preferable to have each student run his or her own Tomcat server If students areusing a single time-shared system, a scheme will be required so that each uses a differentport number for the server (rather than have conflicts over the single 8080 port)

If you are using a database driver other than Sun’s jdbc.odbc driver, you must install ajar file with driver classes It is simplest if you place this in the common/lib directory ofyour Tomcat system (With Oracle for example, you would take a copy of Oracle’sclasses12.zip file that is used to distribute the drivers and place a copy, namedoracle.jar, in the common/lib directory.)

The exercises suggested for PHP can of course be re-implemented using servlets.

(1) Tomcat installation

This exercise simply checks out your Tomcat, using the ‘square root servlet’ examplefrom the chapter Some details of the instructions (like fragments of shell script) pertain toUnix/Linux, but it is quite easy to adapt the exercise to a Windows environment (usingbatch files and a command prompt window)

(a) Decompress the downloaded file (here assumed to be jakarta-tomcat-4.1.18.tar.gz).gunzip jakarta-tomcat-4.1.18.tar.gz

Trang 29

JAVA_HOME=/packages/java/jdk/1.4.1; export JAVA_HOME

./bin/startup.sh

echo "REMEMBER TO PUT OUT YOUR TOMCAT BEFORE YOU GO TO BED"

Save this as waketom; make it executable (chmod +x)

(d) Now wake your tomcat:

<form method=get action="/demo/sqrtservlet">

<input type=text name=number>

Trang 30

(i) Try to view your page from you web browser:

http://localhost:8080/demo/formpage.html

It appears that this file isn’t there This is because Tomcat looks at its web-apps directory

on start up, and only deals out stuff that was there when it started

Put your tomcat to rest (in the window where you started tomcat, do bin/shutdown.sh).Wake a new tomcat (keep this terminal session separate so that you can continue to con-trol your tomcat)

Try viewing your page; it should be there this time

(j) In tom/demo/WEB-INF create a file web.xml with content such as:

public class SqrtServlet extends HttpServlet {

public void doGet (HttpServletRequest request,

Trang 31

try {value = Double.parseDouble(data);

}catch(Exception e) {out.println("<p>Need NUMERIC data.");

out.println("</body></html>");

return;

}if(value<0.0) {out.println("You are living in an imaginary world");

out.println("</body></html>");

return;

}value = Math.sqrt(value);

out.println("Your square root value is " + value);

a scheme that defines the file location relative to the classes directory where your cation code is located The following illustrates a mechanism using relative pathnames:

appli-#.classes is below WebInf, which is below demo, which is below webapps

#which is below Tomcat's main install directory that contains

#the common/lib subdirectory; so go up 4-levels than down into lib

#That added the servlet stuff to the libraries that you use

Now you can try

javac SqrtServlet.java

It should compile without errors

(m) Try entering a number in the form that is still in your browser window from step (i) Itwon’t work: it says there is no demo/servlet2 Remember, Tomcat works with the stuffthat was there when it woke up Your servlet wasn’t there then

Ngày đăng: 14/08/2014, 12:20

TỪ KHÓA LIÊN QUAN

w