实现逻辑层
既然数据层已经准备就绪,我们开始在适当的位置放置 Java 类。逻辑层由三个类组成: SubjectName.java、SubjectCounselor.java 和 AccessDB.java。这几个类提供两种功能;它们通过响应数据请求(SubjectName.java 和 SubjectCounselor.java)连接 JSP 页面,并通过执行基于用户指定信息(AccessDB.java)的查询与数据库进行连接。我们介绍一下这两种功能:
2. 连接数据库
连接 JSP 页面
SubjectName.java
SubjectName.java 使 index.jsp 页面能够访问 subjects 表中列出的主题名称。它通过允许 AccessDB.java 使用 setter 方法设置实例变量 id 和 name执行此操作,然后让 index.jsp 使用公共 getter 方法访问它们。要设置 SubjectName.java,执行以下操作:
- 在 Projects 窗口中,右键单击该项目节点,并选择 New > Java Class...。打开 New Java Class 向导。
- 在 Class Name 文本字段中输入 SubjectName。还应该创建一个新包,包含项目的所有 Java 类。对于 Package,键入 org。单击 Finish。新类的模板在 Source Editor 中打开。在 Projects 窗口中,新包和类的节点在 Source Packages 中显示出来。
- 现在,在 Source Editor 中新建的模板里,将以下内容添加到新的 SubjectName 类的主体部分,然后保存(Ctrl+S)文件:
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;
}
SubjectCounselor.java
根据从 index.jsp 窗体接收到的 subject_id 值,SubjectCounselor.java 能够使 response.jsp 页面访问数据库中的主题和顾问详细信息。像 SubjectName.java 一样,该类通过允许 AccessDB.java 使用公共 setter 方法设置所有实例变量来实现此操作,然后让 response.jsp 使用 getter 方法访问它们。要设置 SubjectCounselor.java,执行以下操作:
- 在 Projects 窗口中,再次右键单击该项目节点,并选择 New > Java Class...。打开 New Java Class 向导。
- 在 Class Name 文本字段中输入 SubjectCounselor。单击 Finish。新类的模板在 Source Editor 中打开。在 Projects 窗口中,新类节点显示在我们之前创建的 org 包下。
- 现在,在 Source Editor 中新建的模板里,将以下内容添加到新的 SubjectCounselor 类中的主体部分,然后保存(Ctrl+S)文件:
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 编码,所以您可以在此下载工作版本的 AccessDB.java。这样,如果在某个点感到迷惑,可以将您的代码与保存的版本进行对比。
首先创建文件,然后准备代码。该代码能使类建立与上面定义的连接池的连接:
- 在 Projects 窗口中,右键单击该项目节点,并选择 New > Java Class...。打开 New Java Class 向导。
- 在 Class Name 文本字段中输入 SubjectName。单击 Finish。新类模板在 Source Editor 中打开。在 Projects 窗口中,新类节点显示在我们之前创建的 org 包下。
- 现在,在 Source Editor 中新建的模板里,右键单击画布并选择 Enterprise Resources > Use Database。在 Choose Database 对话框中,选择我们之前从 Data Source 下拉列表中定义的数据源的 JNDI 名称。确保选择了 Generate Inline Lookup Code 单选按纽并单击 Finish。在 Source Editor 中生成以下代码:
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 的以下类:
现在可以开始编码该类对两个 JSP 页面执行的数据库查询了。我们首先查询 index.jsp,它涉及检索列在 subjects 表中的所有主题的姓名和 ID:
- 在 AccessDB.java 的 Source Editor 中,将以下字符串变量输入到类声明下面的区域中:
private String sqlSubjectName="SELECT subjects_id, name FROM subjects";
SQL 查询允许我们指定想要从数据库中引出的数据。
- 现在,将以下 getSubjectName() 方法添加到类中。这基本上创建了与连接池的连接,然后与数据库连接并执行查询。它然后在数据库返回的结果集中循环,并创建 SubjectName 的实例,保留每个返回行的 ID 和姓名。每个实例都被添加到列表中,最后通过调用方法被返回至对象:
// 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 可以为错误提供可能的解决方案。
- 通过单击灯泡图标或按下 Alt-Enter 打开相应工具提示修正所有错误:
我们将探讨5种错误,并且它们都涉及将类(和接口)导入项目中:
m 用作方法返回对象的 List 接口需要从 java.util 中定义。
m ArrayList 类被用于实现 List,并且我们需要该类保存 SubjectName 的所有实例。
m 与数据库通信需要来自 java.sql API 的 Connection、PreparedStatement 和 ResultSet。
为这些错误中的每一个从工具提示中选择 Add Import,并且注意在 Source Editor 中自动生成新的导入语句:
现在,可以为来自 response.jsp 的查询添加代码。这与之前演示的 index.jsp 方法相同,例如创建合适的 SQL 查询,然后创建一个查询数据库和保存数据的方法。然而,在这种情况下,需要创建两个查询:第一个访问 subjects 表并检索用户从 index.jsp 的下拉菜单中所选 ID 的相应行。然后通过使用返回的主体行中的 counselors_idfk,第二个查询可以匹配 counselors 表中的 counselor ID:
- 在 AccessDB.java 的 Source Editor 中,将以下两个字符串变量输入到类声明以下的区域中:
private String sqlSubject="SELECT * FROM subjects WHERE subjects_id = ?";
private String sqlCounselor="SELECT * FROM counselors WHERE counselors_id = ?";
- 现在,将以下 getSubCounselor() 方法添加到类中。这会创建与连接池的连接,然后如上所述,连接到数据库并执行两个查询。然后它创建一个 SubjectCounselor 实例来保留从这两个结果集中获得的所有数据:
// 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个步骤:
向项目的编译类路径中添加 JSTL Library
为了能让 JSP 资源更好地为我们所用,我们将使用JavaServer Pages Standard Tag Library (JSTL) 中的标记访问并显示从逻辑层所得的数据。该库与 IDE 捆绑在一起。因此,我们需要确保将 JSTL 库添加到了 Web 项目的编译类路径中,然后向每个 JSP 页面添加相关的 taglib 指令。这样,我们使用的服务器就能够在从 JSP 页面中读取标记时识别它们。根据您使用的是 Tomcat 还是 SJSAS,执行以下操作:
捆绑的 Tomcat Web Server
- 在 Projects 窗口中,右键单击该项目 Libraries 节点,并选择 Add Library。选择 JSTL 1.1 库并单击 Add Library。
- 现在展开 Libraries 节点,而且您应该看到两个新节点:一个是 JSTL 库的 standard.jar 文件,另一个是库的 jstl.jar 文件:
Sun Java System Application Server
不执行任何操作!我们不需要采取任何措施将 JSTL 库添加到项目的编译类路径中。这是因为 JSTL 库已经包含在应用程序服务器库中。您可以通过展开 Libraries > Sun Java System Application Server 节点验证这一点:appserv-jstl.jar 节点在 JSTL 库中定义所有的标准标记。