既然数据层已经准备就绪,我们开始在适当的位置放置 Java 类。逻辑层由三个类组成: SubjectName.java、SubjectCounselor.java 和 AccessDB.java。这几个类提供两种功能;它们通过响应数据请求(SubjectName.java 和 SubjectCounselor.java)连接 JSP 页面,并通过执行基于用户指定信息(AccessDB.java)的查询与数据库进行连接。我们介绍一下这两种功能:
2. 连接数据库
SubjectName.java 使 index.jsp 页面能够访问 subjects 表中列出的主题名称。它通过允许 AccessDB.java 使用 setter 方法设置实例变量 id 和 name执行此操作,然后让 index.jsp 使用公共 getter 方法访问它们。要设置 SubjectName.java,执行以下操作:
private String id;
private String name;
// create setter methods
public void setId(String id){
this.id=id;
}
public void setName(String name){
this.name=name;
}
// create getter methods
public String getId(){
return id;
}
public String getName(){
return name;
}
根据从 index.jsp 窗体接收到的 subject_id 值,SubjectCounselor.java 能够使 response.jsp 页面访问数据库中的主题和顾问详细信息。像 SubjectName.java 一样,该类通过允许 AccessDB.java 使用公共 setter 方法设置所有实例变量来实现此操作,然后让 response.jsp 使用 getter 方法访问它们。要设置 SubjectCounselor.java,执行以下操作:
private String subjectName;
private String description;
private String counselorID;
private String firstName;
private String nickName;
private String lastName;
private String telephone;
private String email;
private String memberSince;
// create setter methods
public void setSubjectName(String subject) {
this.subjectName=subject;
}
public void setDescription(String desc) {
this.description=desc;
}
public void setCounselorID(String conId) {
this.counselorID=conId;
}
public void setFirstName(String first) {
this.firstName=first;
}
public void setNickName(String nick) {
this.nickName=nick;
}
public void setLastName(String last) {
this.lastName=last;
}
public void setTelephone(String phone) {
this.telephone=phone;
}
public void setEmail(String email) {
this.email=email;
}
public void setMemberSince(String mem){
this.memberSince=mem;
}
// create getter methods
public String getSubjectName() {
return subjectName;
}
public String getDescription() {
return description;
}
public String getCounselorName() {
String counselorName=firstName + " "
+ nickName + " " + lastName;
return counselorName;
}
public String getMemberSinceDate() {
return memberSince;
}
public String getTelephone() {
return telephone;
}
public String getEmail() {
return email;
4. }
我们可以通过将任务各个击破的方式来编码 AccessDB.java:它必须与数据库连接,发送用户指定的查询,然后存储从查询中接收的数据。因为我们以片段的方式处理 AccessDB.java 编码,所以您可以在此下载工作版本的 AccessDB.java。这样,如果在某个点感到迷惑,可以将您的代码与保存的版本进行对比。
首先创建文件,然后准备代码。该代码能使类建立与上面定义的连接池的连接:
private DataSource getJdbcConnectionPool() throws NamingException {
Context c=new InitialContext();
return (DataSource) c.lookup("java:comp/env/jdbc/connectionPool");
}
这允许该类与使用之前在 Web 服务器上定义的连接池的数据库连接。另外,注意在创建 getJdbcConnectionPool() 方法时,IDE 在 Source Editor 中自动生成导入语句,用于 javax.sql 和 javax.naming API 的以下类:
<shape id="_x0000_i1027" style="WIDTH: 225pt; HEIGHT: 57pt" alt="import statements displayed in Source Editor" type="#_x0000_t75"><imagedata o:href="http://www.netbeans.org/images/articles/mySQL-webapp/con-pool-import-statements.png" src="file:///C:/DOCUME~1/fujiang/LOCALS~1/Temp/msohtml1/01/clip_image003.png"></imagedata></shape>
现在可以开始编码该类对两个 JSP 页面执行的数据库查询了。我们首先查询 index.jsp,它涉及检索列在 subjects 表中的所有主题的姓名和 ID:
private String sqlSubjectName="SELECT subjects_id, name FROM subjects";
SQL 查询允许我们指定想要从数据库中引出的数据。
// get subject names from database
public List getSubjectName() throws Exception{
// connection instance
Connection connection=null;
// instance of SubjectName used to retain retrieved data
SubjectName subName=null;
// list to hold all instances of SubjectName
List list=new ArrayList();
try {
// connect to database
DataSource dataSource=getJdbcConnectionPool();
connection=dataSource.getConnection();
// prepare the SQL query to get subject name and id
PreparedStatement stat=connection.prepareStatement(sqlSubjectName);
// set up the result set to retain all queried data
ResultSet rs=stat.executeQuery();
// now loop through the rows from the generated result set
while(rs.next()){
// declare an instance of SubjectName to match
// returned data with class' instance variables
subName=new SubjectName();
String subject_id=rs.getString("subjects_id");
String name=rs.getString("name");
// set the data to the variables
subName.setId(subject_id);
subName.setName(name);
// finally, add the subName instance to the list
list.add(subName);
}
} catch(Exception e){
System.out.println(e.getMessage());
// close the connection so it can be returned to
// the connection pool then return the list
} finally{
connection.close();
return list;
}
}
在为 getSubjectName() 方法添加以上代码时,注意出现在 Source Editor 中的各种错误,加下划线的红色文本。将光标放在有下划线的文本中时,在该行最左边会显示一个灯泡图标。这表示 IDE 可以为错误提供可能的解决方案。
m 用作方法返回对象的 List 接口需要从 java.util 中定义。
m ArrayList 类被用于实现 List,并且我们需要该类保存 SubjectName 的所有实例。
m 与数据库通信需要来自 java.sql API 的 Connection、PreparedStatement 和 ResultSet。
为这些错误中的每一个从工具提示中选择 Add Import,并且注意在 Source Editor 中自动生成新的导入语句:
<shape id="_x0000_i1029" style="WIDTH: 223.5pt; HEIGHT: 118.5pt" alt="import statements displayed in Source Editor" type="#_x0000_t75"><imagedata o:href="http://www.netbeans.org/images/articles/mySQL-webapp/import-statements.png" src="file:///C:/DOCUME~1/fujiang/LOCALS~1/Temp/msohtml1/01/clip_image007.png"></imagedata></shape>
现在,可以为来自 response.jsp 的查询添加代码。这与之前演示的 index.jsp 方法相同,例如创建合适的 SQL 查询,然后创建一个查询数据库和保存数据的方法。然而,在这种情况下,需要创建两个查询:第一个访问 subjects 表并检索用户从 index.jsp 的下拉菜单中所选 ID 的相应行。然后通过使用返回的主体行中的 counselors_idfk,第二个查询可以匹配 counselors 表中的 counselor ID:
private String sqlSubject="SELECT * FROM subjects WHERE subjects_id = ?";
private String sqlCounselor="SELECT * FROM counselors WHERE counselors_id = ?";
// get subject data and counselor data for corresponding subject
public SubjectCounselor getSubCounselor(String subjectID) throws Exception{
// instance of SubjectCounselor used to retain data
SubjectCounselor subCon=new SubjectCounselor();
// connection instance
Connection connection=null;
try {
// connect to database
DataSource dataSource=getJdbcConnectionPool();
connection=dataSource.getConnection();
// prepare the SQL query to get subject data
PreparedStatement stat=connection.prepareStatement(sqlSubject);
stat.setString(1, subjectID);
ResultSet rs=stat.executeQuery();
// this assumes there is only one row in the result set
rs.next();
// match all returned fields with the below variables
String subjectName=rs.getString("name");
String description=rs.getString("description");
String counselorID=rs.getString("counselors_idfk");
// prepare the SQL query to get counselor data
stat = connection.prepareStatement(sqlCounselor);
stat.setString(1, counselorID);
rs=stat.executeQuery();
// this assumes there is only one row in the result set
rs.next();
// match all returned fields with the below variables
String firstName=rs.getString("first_name");
String nickName=rs.getString("nick_name");
String lastName=rs.getString("last_name");
String telephone=rs.getString("telephone");
String email=rs.getString("email");
String memberSince=rs.getString("member_since");
// finally set all variables to their
// equivalents in the SubjectCounselor instance
subCon.setSubjectName(subjectName);
subCon.setDescription(description);
subCon.setCounselorID(counselorID);
subCon.setFirstName(firstName);
subCon.setNickName(nickName);
subCon.setLastName(lastName);
subCon.setTelephone(telephone);
subCon.setEmail(email);
subCon.setMemberSince(memberSince);
} catch(Exception e){
System.out.println(e.getMessage());
} finally{
// close the connection so it can be returned to the
// connection pool then return the SubjectCounselor instance
connection.close();
return subCon;
}
}
现在 AccessDB.java 需要的代码已经添加完成,并且使用它,完成了实现逻辑层所需的所有步骤。可能在继续下一步之前,想要将您的 AccessDB.java 版本与可下载的版本相比较。剩下的唯一任务就是将 JSP 代码添加到 Web 页面中,使我们能够显示在 SubjectName 和 SubjectCounselor 实例中保留的数据。
现在我们返回到之前在本教程中创建的 index.jsp 和 response.jsp 占位符。添加 JSP 代码使我们的页面能动态地生成内容,如基于用户输入生成内容。要实现这个操作,需要采取以下3个步骤:
为了能让 JSP 资源更好地为我们所用,我们将使用JavaServer Pages Standard Tag Library (JSTL) 中的标记访问并显示从逻辑层所得的数据。该库与 IDE 捆绑在一起。因此,我们需要确保将 JSTL 库添加到了 Web 项目的编译类路径中,然后向每个 JSP 页面添加相关的 taglib 指令。这样,我们使用的服务器就能够在从 JSP 页面中读取标记时识别它们。根据您使用的是 Tomcat 还是 SJSAS,执行以下操作:
不执行任何操作!我们不需要采取任何措施将 JSTL 库添加到项目的编译类路径中。这是因为 JSTL 库已经包含在应用程序服务器库中。您可以通过展开 Libraries > Sun Java System Application Server 节点验证这一点:appserv-jstl.jar 节点在 JSTL 库中定义所有的标准标记。