该项目纯粹用 Servlet 编写,理解跳转过程。理解原理.....
一、准备数据库脚本
USE `test`;DROP TABLE IF EXISTS `dept`;CREATE TABLE `dept` (`deptno` int(2) NOT NULL,`dname` varchar(14) DEFAULT NULL,`loc` varchar(13) DEFAULT NULL,PRIMARY KEY (`DEPTNO`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;/*Data for the table `dept` */insert into `dept`(`DEPTNO`,`DNAME`,`LOC`) values (10,'ACCOUNTING','NEW YORK'),(20,'RESEARCH','DALLAS'),(30,'SALES','CHICAGO'),(40,'OPERATIONS','BOSTON'),(50,'XIAOSHOUBU','TangShan'),(51,'RenShiBu','TangShan'),(60,'YBUMEN','HENAN'),(70,'QBUMEn','TX');
二、准备页面
- 欢迎页面:先进入到这个页面,有个连接跳转到查询页面
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>欢迎界面</title></head><style type="text/css">div {font-size: 150px;text-align: center;}</style><body><!--带项目名+DeptListServlet的路径名--><a href="/oa/list"><div>欢迎使用本系统</div></a></body>
</html>
- 查询页面:返回dept表中的所有信息
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title><style type="text/css">table,td,tr,th {border: blue solid 2px;align: center;}</style></head><body><!-- 处理查询页面 --><h1 align="center">部门管理</h1><hr><table align="center" style="width: 40%; height: 40%;"><tr><th>部门编号</th><th>部门名称</th><th>部门地址</th><th>操作</th></tr><!--下面是动态的从数据库中获取数据。编号,部门名字,地点都是动态显示的--><tr><td>1</td><td>销售部</td><td>北京</td><td><a href="add.html">增加</a><a href="update.html">修改</a><a href="#" onclick="window.confirm('确定删除吗?')">删除</a></td></tr></table></body>
</html>
- 增加页面:向 dept 表中增加数据
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title></head><body><h1>部门增加</h1><hr /><form action="list.html" method="get"><!-- -->部门编号:<input type="text" name="deptno" /><br />部门名称:<input type="text" name="dname" /><br />部门地点:<input type="text" name="loc" /><br /><input type="submit" value="提交" /><br /></form></body>
</html>
- 修改页面:修改dept表中的数据
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title></head><body><h1>部门修改</h1><hr /><form action="list.html" method="get"><!-- value 是动态获取的,部门编号不能修改 -->部门编号:<input type="text" name="deptno" value="1" readonly="readonly" /><br />部门名称:<input type="text" name="dname" value="销售部" /><br />部门地点:<input type="text" name="loc" value="北京" /><br /><input type="submit" value="修改" /><br /></form></body>
</html>
- 详情页面
<!DOCTYPE html>
<html lang='en'>
<head><meta charset='UTF-8'><title>Title</title>
</head>
<body><!--这是动态获取的-->部门编号:1部门名称:部门地点:<input type='button' value='后退' onclick='history.back()'>
</body>
</html>
三、准备实现的功能
- 查询数据:dept表中的数据,有增加,修改,删除,详情操作链接
- 增加数据:增加完跳转到查询页面
- 修改数据:要求动态获取信息,比如:对销售部进行修改,要把销售部的原始信息显示到修改页面中,部门编号不能修改
- 删除数据:删除有确认框,删除后呆在查询页面。
- 部门的详细情况:点击哪个部门就将哪个部门的信息显示出来
四、搭建项目环境
- 构建Servlet环境
- 引进 mysql-connector.jar 包到 WEB-INF的lib目录下
- 创建工具类 DButils 。主要负责连接数据库。将 Driver,url,user,password 写进配置文件中,符合 OCP 原则:对扩展是开放的,而对修改是封闭的。
/** JDBC 工具类* */
public class DBUtils {//静态变量:“在类加载的时候执行,并且自上而下按顺序执行。//获取配置文件的信息,不需要加 后缀名。 包名.文件名private static ResourceBundle resource = ResourceBundle.getBundle("yangzhaoguang.resource.jdbc");private static String driver = resource.getString("driver");private static String url = resource.getString("url");private static String user = resource.getString("user");private static String password = resource.getString("password");/** 静态代码快:注册驱动。注册一次就可以,所以写进静态代码块中* */static {//这样就会链接数据库的驱动写死了。以后还可能链接别的数据库。// 不符合:OCP原则:对扩展开放,对修改关闭//什么是符合OCP原则呢? 在进行功能扩展的时候,不用修改源代码// Class.forName("com.jdbc.mysql.Driver");try {Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}/*连接数据库*/public Connection getConnection() {Connection conn = null;try {conn = DriverManager.getConnection(url, user, password);} catch (SQLException e) {e.printStackTrace();}return conn;}/*释放资源*/public void close(Connection conn , ResultSet rs, PreparedStatement ps){if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (ps != null) {try {ps.close();} catch (SQLException e) {e.printStackTrace();}}}
}
- 配置文件 jdbc.properties:
#驱动
driver=com.mysql.jdbc.Driver
#url
url=jdbc:mysql://localhost:3306/test
#账户
user=root
#密码
password=root
五、实现查询功能
- 创建 DeptListServlet 类,并配置web.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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/web-app_4_0.xsd"version="4.0"><!--设置欢迎界面--><welcome-file-list><welcome-file>welcome.html</welcome-file></welcome-file-list><!--DeptListServlet映射信息--><servlet><servlet-name>DeptListServlet</servlet-name><servlet-class>yangzhaoguang.oa.DeptListServlet</servlet-class></servlet><servlet-mapping><servlet-name>DeptListServlet</servlet-name><!--DeptListServlet类的路径名。不需要加项目名--><url-pattern>/list</url-pattern></servlet-mapping>
</web-app>
- 实现从数据库中查询数据的功能,并显示到 list 页面。单纯的使用Servlet是比较繁琐的。需要将动态获取的数据放在 处理查询结果集 的while 循环中。【提前将 list.html 页面的 "" 替换成 '' 要不会和 DeptListServlet 类中的 "" 冲突】。原来的list页面其实可以删除了!
/** 实现查询功能* */
public class DeptListServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html");PrintWriter writer = resp.getWriter();writer.print(" <!DOCTYPE html>");writer.print("<html>");writer.print(" <head>");writer.print(" <meta charset='utf-8'>");writer.print(" <title></title>");writer.print(" <style type='text/css'>");writer.print(" table,");writer.print(" td,");writer.print(" tr,");writer.print(" th {");writer.print(" border: blue solid 2px;");writer.print(" align: center;");writer.print(" }");writer.print(" </style>");writer.print(" </head>");writer.print(" <body>");writer.print(" <!-- 处理查询页面 -->");writer.print(" <h1 align='center'>部门管理</h1>");writer.print(" <hr>");writer.print(" <table align='center' style='width: 40%; height: 40%;'>");writer.print(" <tr>");writer.print(" <th>部门编号</th>");writer.print(" <th>部门名称</th>");writer.print(" <th>部门地址</th>");writer.print(" <th>操作</th>");writer.print(" </tr>");/*以上是固定不变的,不需要改动*//*连接数据库*/PreparedStatement ps = null;ResultSet rs = null;Connection conn = null;try {/*获取连接*/conn = DBUtils.getConnection();/*获取预编译的数据库操作对象*/String sql = "select * from dept";ps = conn.prepareStatement(sql);/*处理查询结果集*/rs = ps.executeQuery();while (rs.next()) {String deptno = rs.getString(1);String dname = rs.getString(2);String loc = rs.getString(3);/*这部分是要动态显示的,需要从数据库中获取数据,需要放到循环中去*/writer.print(" <tr>");writer.print(" <td>" + deptno + "</td>");writer.print(" <td>" + dname + "</td>");writer.print(" <td>" + loc + "</td>");writer.print(" <td><a href='add.html'>增加</a>");writer.print(" <a href='update.html'>修改</a>");writer.print(" <a href='#' onclick='window.confirm('确定删除吗?')'>删除</a>");writer.print(" <a href='update.html'>详情</a>");writer.print(" </td>");writer.print(" </tr>");}} catch (SQLException e) {e.printStackTrace();} finally {/*释放资源*/DBUtils.close(conn, rs, ps);}/*以下也是固定的,不需要改变*/writer.print(" </table>");writer.print(" </body>");writer.print("</html>");}
}
- 到这里就完成了查询功能。
- 这个功能的具体流程是什么样的呢?
- 首先Tomcat根据在欢迎界面设置的超链接, 通过配置信息中的映射信息,找到我们写好的 DeptListServlet 类,由于超链接是 GET 请求,会执行 DeptListServlet 中的doGet 方法。
六、实现查看部门详情功能
- 实现参数传递是有固定写法的:url?name=value&name=value......
/*获取根路径*/String contextPath = req.getContextPath();/*首先路径需要更改:跳转到一个 Servlet ,这里也需要加项目名:但是在java程序里,项目名可以动态获取。*/writer.print(" <a href='"+contextPath+"/detail?deptno="+deptno+"'>详情</a>");
- 编辑配置文件,编写 deptDetailServlet 类
<!--DeptDetailServlet映射信息--><servlet><servlet-name>DeptDetailServlet</servlet-name><servlet-class>yangzhaoguang.oa.DeptDetailServlet</servlet-class></servlet><servlet-mapping><servlet-name>DeptDetailServlet</servlet-name><!--设置DeptDetailServlet类的路径名,不需要加项目名--><url-pattern>/detail</url-pattern></servlet-mapping>
- 提前将 detail 页面的 "" 替换成 ''
public class DeptDetailServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {/*获取 地址栏上请求参数 deptno 的 value*/String deptno = req.getParameter("deptno");resp.setContentType("text/html");PrintWriter writer = resp.getWriter();writer.print("<!DOCTYPE html>");writer.print("<html lang='en'>");writer.print("<head>");writer.print(" <meta charset='UTF-8'>");writer.print(" <title>Title</title>");writer.print("</head>");writer.print("<body>");/*连接数据库操作*/Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {/*获取连接*/conn = DBUtils.getConnection();/*获取预编译数据库操作对象*/String sql = "select * from dept where deptno=?";ps = conn.prepareStatement(sql);/*传值*/ps.setString(1, deptno);/*结果集中只有一条对象,不需要while循环*/rs = ps.executeQuery();if (rs.next()) {String dname = rs.getString(2);String loc = rs.getString(3);/*动态获取*/writer.print(" 部门编号:" + deptno + "<br>");writer.print(" 部门名称:" + dname + "<br>");writer.print(" 部门地点:" + loc + "<br>");}} catch (SQLException e) {e.printStackTrace();}finally {/*释放资源*/DBUtils.close(conn,rs,ps);}writer.print(" <input type='button' value='后退' onclick='history.back()'>");writer.print("</body>");writer.print("</html>");}
}
七、实现删除功能
- 纯粹的用Servlet写,需要将删除的前端代码写到后端当中。【学完JSP会简单很多】。
- 凡是前端向后端发送请求,那么请求路径必须要加上项目名,项目名能动态获取就动态获取使用:getContextPath();
/*点击缺点删除后,浏览器发送删除请求。请求路径需要带项目名:只要是前端向后端发送请求都需要加项目名*//*deptno 是动态获取的。删除数据的where条件*/writer.print("; <script type='text/javascript'>");writer.print("; function del(deptno) {");writer.print("; var res = window.confirm('确认删除吗?');");writer.print("; if(res){");writer.print("; window.location = '"+contextPath+"/del?deptno='+deptno ;");writer.print("; }");writer.print(";}");writer.print("</script>");
/* javascript:void(0):保持超链接的样式,但是不实现跳转执行del()函数:参数是 deptno,是动态的*/writer.print(" <a href='javascript:void(0)' onclick='del("+deptno+")'>删除</a>");
- 编写 DeptDelServlet 类,并编辑配置文件
<!--DeptDelServlet 映射信息--><servlet><servlet-name>DeptDelServlet</servlet-name><servlet-class>yangzhaoguang.oa.DeptDelServlet</servlet-class></servlet><servlet-mapping><servlet-name>DeptDelServlet</servlet-name><!--设置DeptDelServlet 类的路径名,不需要加项目名--><url-pattern>/del</url-pattern></servlet-mapping>
public class DeptDelServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Connection conn = null;PreparedStatement ps = null;/*获取请求信息的参数:deptno*/String deptno = req.getParameter("deptno");try {conn = DBUtils.getConnection();String sql = "delete from dept where deptno=?";ps = conn.prepareStatement(sql);ps.setString(1, deptno);int count = ps.executeUpdate();/*判断是否删除成功*/if (count != 0){/*删除成功后,需要重新访问 查询列表。这个查询列表是需要重新访问数据库的。* 所以我们可以用转发【重定向最好】* */req.getRequestDispatcher("list").forward(req,resp);}else{req.getRequestDispatcher("err.html").forward(req,resp);}} catch (SQLException e) {e.printStackTrace();}finally {DBUtils.close(conn,null,ps);}}
}
八、增加功能
- 首先将增加页面的表单提交路径设置为: 项目名+DeptInsertServlet 类的路径名
<form action="/oa/insert" method="post">
- 配置web.xml信息,编写 DeptInsertServlet 类
<!--DeptInsertServlet 映射信息--><servlet><servlet-name>DeptInsertServlet</servlet-name><servlet-class>yangzhaoguang.oa.DeptInsertServlet </servlet-class></servlet><servlet-mapping><servlet-name>DeptInsertServlet </servlet-name><!--DeptInsertServlet 类的路径名,不需要加项目名--><url-pattern>/insert</url-pattern></servlet-mapping>
public class DeptInsertServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Connection conn = null;PreparedStatement ps= null ;/*获取请求中的 deptno ,dname, loc 信息。* 这里的 name 是在前端页面form表单中的name属性* */String deptno = req.getParameter("deptno");String dname = req.getParameter("dname");String loc = req.getParameter("loc");try {/*第一步:获取连接*/conn = DBUtils.getConnection();/*第二步:获取预编译数据库操作对象*/String sql = "insert into dept(deptno,dname,loc) values(?,?,?)";ps = conn.prepareStatement(sql);/*第三步:给占位符传值*/ps.setString(1,deptno);ps.setString(2,dname);ps.setString(3,loc);/*第四步:返回结果*/int count = ps.executeUpdate();if (count != 0){/*增加成功跳转到 list 页面*/req.getRequestDispatcher("/list").forward(req,resp);}else{req.getRequestDispatcher("err.html").forward(req,resp);}} catch (SQLException e) {e.printStackTrace();}finally {DBUtils.close(conn,null,ps);}}
}
- 当我们测试的时候,他会报 405 错误。
- 这是因为前端发送的是 POST 请求,虽然在 DeptInsertServlet 类中重写的也是 doPost 方法,但是当执行到 转发 到 list 界面的时候,DeptListServlet类中重写的是 doGet 方法。所以会报 405
- 解决办法:
- 1、在 DeptListServlet 类中重写 doPost方法,doPost方法中调用 doGet
- 2、重定向可以解决。
/*防止增加的时候报 405 错误*/@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doGet(req,resp);}
访问流程:
九、修改
- 对部门进行修改的时候,需要将部门的信息回显到单元格中。并且 部门编号不能修改
- 需要动态获取 deptno,根据 deptno 在数据库进行查询,和 详情 操作一样。
- 获取部门信息:配置文件,编写 DeptUpdateServlet 类
<!--DeptUpdateServlet 映射信息--><servlet><servlet-name>DeptUpdateServlet</servlet-name><servlet-class>yangzhaoguang.oa.DeptUpdateServlet </servlet-class></servlet><servlet-mapping><servlet-name>DeptUpdateServlet </servlet-name><!--DeptUpdateServlet 类的路径名,不需要加项目名--><url-pattern>/update</url-pattern></servlet-mapping>
public class DeptUpdateServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html");PrintWriter writer = resp.getWriter();writer.print("<!DOCTYPE html>");writer.print("<html>");writer.print(" <head>");writer.print(" <meta charset='utf-8'>");writer.print(" <title></title>");writer.print(" </head>");writer.print(" <body>");writer.print(" <h1>部门修改</h1>");writer.print(" <hr />");/*向 DeptModifyServlet 提交数据,在DeptModifyServlet中做真正的修改* 提交方式:post* */writer.print(" <form action='/oa/modify' method='post'>");/*从前端获取deptno,根据 deptno 从数据库中获取数据*/String deptno = req.getParameter("deptno");Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = DBUtils.getConnection();/*获取预编译数据库操作对象*/String sql = "select * from dept where deptno=?";ps = conn.prepareStatement(sql);ps.setString(1, deptno);rs = ps.executeQuery();if (rs.next()) {/*取数据*/String dname = rs.getString(2);String loc = rs.getString(3);/*动态获取页面*/writer.print(" <!-- value 是动态获取的,部门编号不能修改 -->");writer.print(" 部门编号:<input type='text' name='deptno' value='" + deptno + "' readonly='readonly' /><br />");writer.print(" 部门名称:<input type='text' name='dname' value='" + dname + "' /><br />");writer.print(" 部门地点:<input type='text' name='loc' value='" + loc + "' /><br />");}} catch (SQLException e) {e.printStackTrace();} finally {DBUtils.close(conn, rs, ps);}writer.print(" <input type='submit' value='修改' /><br />");writer.print(" </form>");writer.print(" </body>");writer.print("</html>");}
}
- 对数据进行修改,注意:前端发送的请求时 doPost请求,要重写doPost 方法
<!--DeptModifyServlet 映射信息--><servlet><servlet-name>DeptModifyServlet</servlet-name><servlet-class>yangzhaoguang.oa.DeptModifyServlet </servlet-class></servlet><servlet-mapping><servlet-name>DeptModifyServlet </servlet-name><!--DeptModifyServlet类的路径名,不需要加项目名--><url-pattern>/modify</url-pattern></servlet-mapping>
public class DeptModifyServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html");/*从前端获取数据*/String deptno = req.getParameter("deptno");String dname = req.getParameter("dname");String loc = req.getParameter("loc");Connection conn = null ;PreparedStatement ps = null;ResultSet rs = null ;try {conn = DBUtils.getConnection();String sql = "update dept set dname=?,loc=? where deptno=?";ps = conn.prepareStatement(sql);/*修改数据*/ps.setString(1,dname);ps.setString(2,loc);ps.setString(3,deptno);int count = ps.executeUpdate();if (count != 0){/*修改成功后跳转到 list 页面*/req.getRequestDispatcher("/list").forward(req,resp);}else{req.getRequestDispatcher("/err.html").forward(req,resp);}} catch (SQLException e) {e.printStackTrace();}finally {DBUtils.close(conn,rs,ps);}}
}
访问流程:
到这里,用Servlet 制作单表增删改查已经完毕。部分代码使用 JSP+重定向 效果更好,代码更简单!~