@liayun
2016-06-28T18:58:40.000000Z
字数 7319
阅读 1833
JavaWeb
以如下格式的exam.xml文件为例。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<exam>
<student examid="222" idcard="111">
<name>张三</name>
<location>沈阳</location>
<grade>89</grade>
</student>
<student examid="444" idcard="333">
<name>李四</name>
<location>大连</location>
<grade>97</grade>
</student>
</exam>
把XML当做数据库,完成系统的增加、删除、查找功能!之所以能把XML当做是数据库,是因为XML可以体现数据之间的关系,可以完成整个数据库单独模块内容的操作!
利用三层架构,将程序的功能拆分,某部分代码负责某部分的功能实现!
将整个程序进行拆分,如图所示:
注意:写程序的时候,先写bean,开发从下层往上层写,因为此处没有数据库,所以先把代表数据库的xml写出来。
Student对象类:对象数据的存储或传递。
// 代表学生的JavaBean
public class Student {
private String idcard; // 身份证号
private String examid; // 准考证号
private String name;
private String location;
private double grade;
public String getIdcard() {
return idcard;
}
public void setIdcard(String idcard) {
this.idcard = idcard;
}
public String getExamid() {
return examid;
}
public void setExamid(String examid) {
this.examid = examid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public double getGrade() {
return grade;
}
public void setGrade(double grade) {
this.grade = grade;
}
}
XmlUtils类:工具类,得到Document对象和更新文档这些工具性质的操作!
// 公共的代码使用工具类进行抽取,工具类中的方法都为静态(约定俗成)
public class XmlUtils {
private static String filename = "src/exam.xml";
// 获得Document对象
public static Document getDocument() throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(filename);
}
/*
* 更新XML文档
* 当想把异常当作返回值使用编译时异常,否则通通转换为运行时异常
*/
public static void write2Xml(Document document) throws Exception {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer tf = factory.newTransformer();
tf.transform(new DOMSource(document), new StreamResult(new FileOutputStream(filename)));
}
}
注意:一定要深刻认识到对异常的处理原则,当要把异常当作一个返回值的时候,使用编译时异常,否则通通转换为运行时异常。
StudentDao对象类:最核心的部分,增删改查的功能实现部分!
通过以下代码深刻理解对异常的处理:
public class StudentDao {
// 根据需求来看,记得将公共代码用工具类进行抽取
public void add(Student s) {
try {
Document document = XmlUtils.getDocument(); // checked exception(编译时异常)
// 创建出封装学生信息的标签
Element student_tag = document.createElement("student");
student_tag.setAttribute("idcard", s.getIdcard());
student_tag.setAttribute("examid", s.getExamid());
// 创建用于封装学生姓名、所在地和成绩的标签
Element name = document.createElement("name");
Element location = document.createElement("location");
Element grade = document.createElement("grade");
name.setTextContent(s.getName());
location.setTextContent(s.getLocation());
grade.setTextContent(s.getGrade()+"");
student_tag.appendChild(name);
student_tag.appendChild(location);
student_tag.appendChild(grade);
// 把封装了信息的学生标签挂到文档上
document.getElementsByTagName("exam").item(0).appendChild(student_tag);
// 更新内存
XmlUtils.write2Xml(document);
} catch (Exception e) {
/*
* 编译时异常,必须自己处理,直接抛到上层甚至上上层,
* 没有意义只会带来麻烦,只能抓,并且对异常进行转型,
* 转成运行时异常再抛出去,但异常链不能断,
* 必须把原来的异常信息封装进去,抛出异常给上一层,
* 上一层就会知道到底出了什么问题,问题已经报告给上层了,
* 它爱处理就处理,不处理就不处理。
*/
throw new RuntimeException(e); // unchecked exception(运行时异常)
/*
* 出现异常,一定要通知上一层程序,抛个异常给上一层,
* 不能打印在控制台上,没有意义,只是给程序员看的。
*/
// e.printStackTrace();
}
}
public Student find(String examid) {
try {
Document document = XmlUtils.getDocument();
NodeList list = document.getElementsByTagName("student");
// NodeList没实现Iterable接口,所以不能使用增强for循环
for(int i = 0; i < list.getLength(); i++) {
Element student_tag = (Element) list.item(i);
if(student_tag.getAttribute("examid").equals(examid)) {
// 找到与examid相匹配的学生,new出一个student对象封装这个学生的信息返回
Student s = new Student();
s.setExamid(examid);
s.setIdcard(student_tag.getAttribute("idcard"));
// 得到student_tag这个标签下的name标签
s.setName(student_tag.getElementsByTagName("name").item(0).getTextContent());
s.setLocation(student_tag.getElementsByTagName("location").item(0).getTextContent());
s.setGrade(Double.parseDouble(student_tag.getElementsByTagName("grade").item(0).getTextContent()));
return s;
}
}
return null;
} catch (Exception e) {
throw new RuntimeException(e); // 异常处理同上
}
}
public void delete(String name) throws StudentNotExistException { // 此处抛出编译时异常,则必须要处理,即让调用者知道删除是否成功
try {
Document document = XmlUtils.getDocument();
NodeList list = document.getElementsByTagName("name");
for(int i = 0; i < list.getLength(); i++) {
if(list.item(i).getTextContent().equals(name)) {
list.item(i).getParentNode().getParentNode().removeChild(list.item(i).getParentNode());
XmlUtils.write2Xml(document);
return;
}
}
/*
* 如果删除没成功,抛一个编译时异常(自定义异常)
* 自定义异常都放在exception包中,如cn.itcast.exception包
*
* 当要把异常当作一个返回值的时候,使用编译时异常
*/
throw new StudentNotExistException(name + "不存在!");
} catch (StudentNotExistException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e); // 异常处理同上
}
}
}
定义一个自定义异常:StudentNotExistException。
public class StudentNotExistException extends Exception {
public StudentNotExistException() {
// TODO Auto-generated constructor stub
}
public StudentNotExistException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public StudentNotExistException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
public StudentNotExistException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public StudentNotExistException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
}
StudentDaoTest:写程序过程中的测试类,此测试类放在junit.test包中。
在实际的代码实现阶段,还会需要一个测试类,方便于在整个程序还没有完成的时候对程序的部分功能进行测试,做一步,测试一步,以免整个程序完成后由于页面太多或者是代码量太大给查找错误造成更大的负担!所以这里会多一个测试类!
public class SyudentDaoTest {
@Test
public void testAdd() {
StudentDao dao = new StudentDao();
Student s = new Student();
s.setExamid("121");
s.setGrade(90);
s.setIdcard("121");
s.setLocation("北京");
s.setName("李阿昀");
dao.add(s);
}
@Test
public void testFind() {
StudentDao dao = new StudentDao();
dao.find("121"); // 在断点模式Watch
}
@Test
public void testDelete() throws StudentNotExistException {
StudentDao dao = new StudentDao();
dao.delete("李阿昀"); // 在断点模式Watch
}
}
Main:主页UI类(虽然这里界面仍然是控制台)
public class Main {
public static void main(String[] args) {
try { // 只要不是用户界面的错误,就上抛,但是一旦到用户这层,就停止抛,并提示用户信息
System.out.println("添加学生:(a) 删除学生:(b) 查找学生:(c)");
System.out.print("请输入操作类型:");
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
String type = bufr.readLine();
if("a".equals(type)) {
System.out.print("请输入学生姓名:");
String name = bufr.readLine();
System.out.print("请输入学生准考证号:");
String examid = bufr.readLine();
System.out.print("请输入学生身份证号:");
String idcard = bufr.readLine();
System.out.print("请输入学生所在地:");
String location = bufr.readLine();
System.out.print("请输入学生成绩:");
String grade = bufr.readLine();
Student s = new Student();
s.setExamid(examid);
s.setGrade(Double.parseDouble(grade));
s.setIdcard(idcard);
s.setLocation(location);
s.setName(name);
StudentDao dao = new StudentDao();
dao.add(s);
System.out.println("添加成功!!");
} else if("b".equals(type)) {
System.out.print("请输入要删除的学生姓名:");
String name = bufr.readLine();
try {
StudentDao dao = new StudentDao();
dao.delete(name);
System.out.println("删除成功!!");
} catch (StudentNotExistException e) {
/*
* 不需要记录这个异常,预料不到才记录,便于后来维护,但此异常是预料到的,
* 所以不需要记录这个异常。
*/
System.out.println("您要删除的用户不存在!!!");
}
} else if("c".equals(type)) {
System.out.print("请输入查询的学生准考证号:");
String examid = bufr.readLine();
StudentDao dao = new StudentDao();
Student s = dao.find(examid);
if(s != null) {
System.out.println("您查询的学生信息为:");
System.out.println("姓名:"+s.getName()+", 身份证号:"+
s.getIdcard()+", 准考证号:"+s.getExamid()
+", 地区:"+s.getLocation()+", 成绩:"+s.getGrade());
} else {
System.out.println("没有查询到任何信息!!!");
}
} else {
System.out.println("不支持您的操作!!!");
}
} catch(Exception e) {
/*
* 给用户友好提示,还要在后台记录这个异常,记录这个异常是为了便于
* 程序员去观察这个异常,去修正这个异常,去维护这个程序。
*/
e.printStackTrace();
System.out.println("对不起,俺出错了!!!");
}
}
}
项目截图:
总结:这个程序最重要的还是XML节点操作的应用,顺带的加上了简单的三层构架!工具类,业务实现(实际操作)类,UI类!