开发前的准备
导入sql脚本创建一张部门表
drop table if exists dept;
create table dept(
deptno int primary key,
dname varchar(255),
loc varchar(255)
);
insert into dept(deptno, dname, loc) values(10, 'XiaoShouBu', 'BeiJing');
insert into dept(deptno, dname, loc) values(20, 'YanFaBu', 'SHANGHAI');
insert into dept(deptno, dname, loc) values(30, 'JiShuBu', 'GUANGZHOU');
insert into dept(deptno, dname, loc) values(40, 'MeiTiBu', 'SHENZHEN');
commit;
select * from dept;
通过绑定属性资源配置文件的方式创建JDBC的工具类utils/DBUtil
#在src类路径下新建包resourcse,在包中新建一个属性配置文件jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/javaweb
user=root
password=123456
public class DBUtil {
// 绑定属性资源配置文件,配置文件的后缀名不用写,文件路径路径分隔符可以是"."也可以是"/"
private static ResourceBundle bundle = ResourceBundle.getBundle("resources.jdbc");
// 根据属性配置文件的key获取value,静态变量在类加载时按自上而下的顺序执行
private static String driver = bundle.getString("driver");
private static String url = bundle.getString("url");
private static String user = bundle.getString("user");
private static String password = bundle.getString("password");
static {
// 由于注册驱动只需要注册一次所以可以放在静态代码块当中,当DBUtil类加载的时候执行静态代码块中的代码
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接对象
* @return conn 连接对象
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
// 获取连接
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
/**
* 释放资源
* @param conn 连接对象
* @param ps 数据库操作对象
* @param rs 结果集对象
*/
public static void close(Connection conn, Statement ps, ResultSet rs){
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
分析系统的功能: 只要这个操作连接了数据库,就表示一个独立的功能
实现一个具体功能: 可以从后端往前端一步一步写, 以可以从前端一步一步往后端写 , 千万不要想起来什么写什么
实现查看部门列表功能
设置欢迎页面index.html的超链接,用户通过点击"查看部门列表按钮"跳转到部门列表页面
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>欢迎使用OA系统title>
head>
<body>
<a href="/oa/dept/list">查看部门列表a>
body>
html>
编写DeptListServlet类继承HttpServlet类并重写doGet方法(配置到web.xml文件中)
<servlet>
<servlet-name>listservlet-name>
<servlet-class>com.bjpowernode.oa.web.action.DeptListServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>listservlet-name>
<url-pattern>/dept/listurl-pattern>
servlet-mapping>
public class DeptListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取应用的根路径
String contextPath = request.getContextPath();
// 设置响应的内容类型以及字符集,防止中文乱码问题
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// 使用多行编辑功能 , 按住Alt键 , 鼠标往下托就行
out.print("");
out.print("");
out.print(" ");
out.print(" ");
out.print(" 部门列表页面 ");
//删除按钮执行的事件函数
out.print("");
out.print(" ");
out.print(" ");
out.print(" 部门列表
");
out.print("
");
out.print(" ");
out.print(" ");
out.print(" 序号 ");
out.print(" 部门编号 ");
out.print(" 部门名称 ");
out.print(" 操作 ");
out.print(" ");
/*上面一部分是死的*/
// 动态的连接数据库,查询所有的部门
//...................
/*下面一部分是死的*/
out.print("
");
out.print("
");
out.print(" 新增部门");
out.print(" ");
out.print("");
}
}
动态的连接数据库查询所有的部门
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 获取连接
conn = DBUtil.getConnection();
// 获取预编译的数据库操作对象
String sql = "select deptno as a,dname,loc from dept";
ps = conn.prepareStatement(sql);
// 执行SQL语句
rs = ps.executeQuery();
// 处理结果集
// i 表示序号
int i = 0;
while(rs.next()){
String deptno = rs.getString("a");
String dname = rs.getString("dname");
String loc = rs.getString("loc");
out.print(" ");
out.print(" "+(++i)+" ");
out.print(" "+deptno+" ");
out.print(" "+dname+" ");
out.print(" ");
//点击按钮不会进行页面的跳转,而是执行事件函数
out.print(" +deptno+")'>删除");
out.print(" 修改");
out.print(" 详情");
out.print(" ");
out.print(" ");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 释放资源
DBUtil.close(conn, ps, rs);
}
实现查看部门详情功能
用户点的“详情”的按钮是DeptListServlet 动态的响应的内容,后端连接数据库查询部门信息时,不同的部门对应不同的编号,同理请求参数deptno的值也不同
while(rs.next()){
String deptno = rs.getString("a");
// 部分代码省略
// 向服务器提交数据的格式:uri?name=value&name=value&...
out.print(" 详情");
}
编写DeptDetailServlet继承HttpServlet并重写doGet方法((配置到web.xml文件中)
<servlet>
<servlet-name>detailservlet-name>
<servlet-class>com.bjpowernode.oa.web.action.DeptDetailServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>detailservlet-name>
<url-pattern>/dept/detailurl-pattern>
servlet-mapping>
public class DeptDetailServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("");
out.print("");
out.print(" ");
out.print(" ");
out.print(" 部门详情 ");
out.print(" ");
out.print(" ");
out.print(" 部门详情
");
out.print("
");
/*上面一部分是死的*/
// 根据部门编号连接数据库查询对应部门的信息并动态展示
//...................
/*下面一部分是死的*/
out.print(" ");
out.print(" ");
out.print("");
}
}
从请求地址[/oa/dept/detail?deptno=30][]中uri中的请求参数获取部门编号然后连接数据库查询该部门的信息,最后动态展示部门详情页的代码
// 虽然浏览器提交的是30这个数字,但是服务器获取的是"30"字符串
String deptno = request.getParameter("deptno");
// 连接数据库根据部门编号查询部门信息
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
// mysql底层自动会把"30"转换成30
String sql = "select dname,loc from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, deptno);
rs = ps.executeQuery();
// 这个结果集一定只有一条记录
if(rs.next()){
String dname = rs.getString("dname");
String loc = rs.getString("loc");
out.print("部门编号:"+deptno+"
");
out.print("部门名称:"+dname+"
");
out.print("部门位置:"+loc+"
");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, rs);
}
实现删除部门功能
用户点的“删除”按钮是DeptListServlet 动态响应的内容 ,点击删除按钮要执行的事件函数也是DeptListServlet动态的响应的内容
while(rs.next()){
// 部分代码省略
String deptno = rs.getString("a");
// href设置为javascript:void(0)或javascript:;都会保留超链接的样子,但是点击后不进行页面的跳转
out.print(" +deptno+")'>删除");
}
// 根据部门编号删除对应的部门
out.print("");
编写DeptDelServlet继承HttpServlet并重写doGet方法(配置到web.xml文件中)
<servlet>
<servlet-name>deleteservlet-name>
<servlet-class>com.bjpowernode.oa.web.action.DeptDelServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>deleteservlet-name>
<url-pattern>/dept/deleteurl-pattern>
servlet-mapping>
public class DeptDelServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 根据请求参数获取的部门编号连接数据库删除对应部门记录
String deptno = request.getParameter("deptno");
Connection conn = null;
PreparedStatement ps = null;
// count判断判断删除成功了还是失败了
int count = 0;
try {
conn = DBUtil.getConnection();
// 开启事务(自动提交机制关闭)
conn.setAutoCommit(false);
String sql = "delete from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, deptno);
// 返回值是影响了数据库表当中多少条记录
count = ps.executeUpdate();
// 事务提交
conn.commit();
} catch (SQLException e) {
// 遇到异常要回滚
if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, null);
}
// 判断删除成功了还是失败了..........
}
}
删除成功或者失败的时候的一个处理 , 因为不需要共享数据所以我们使用重定向机制
if (count == 1) { //删除成功
response.sendRedirect(request.getContextPath() + "/dept/list");
}else{ // 删除失败
response.sendRedirect(request.getContextPath() + "/error.html");
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>errortitle>
head>
<body>
<h1>操作失败,<a href="javascript:void(0)" onclick="window.history.back()">返回a>h1>
body>
html>
实现新增部门功能
“新增部门”的按钮在DeptListServlet动态响应的内容中, 通过点击该链接直接跳转到新增部门的表单页面,利用表单发起post请求提交新增部门的信息
/*下面一部分是死的*/
out.print(" 新增部门");
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>新增部门title>
head>
<body>
<h1>新增部门h1>
<hr >
<form action="/oa/dept/save" method="post">
部门编号<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>
编写DeptSaveServlet继承HttpServlet并重写doPost方法(配置到web.xml文件中)
<servlet>
<servlet-name>saveservlet-name>
<servlet-class>com.bjpowernode.oa.web.action.DeptSaveServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>saveservlet-name>
<url-pattern>/dept/saveurl-pattern>
servlet-mapping>
public class DeptSaveServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取部门的信息时注意乱码问题(Tomcat10不会出现这个问题)
request.setCharacterEncoding("UTF-8");
String deptno = request.getParameter("deptno");
String dname = request.getParameter("dname");
String loc = request.getParameter("loc");
// 连接数据库执行insert语句
Connection conn = null;
PreparedStatement ps = null;
// 判断保存成功还是失败
int count = 0;
try {
conn = DBUtil.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);
count = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, null);
}
// 判断保存成功还是失败 , 保存成功跳转到列表页面.................
}
}
转发到/dept/list会出现405错误, 由于转发是一次请求, 保存新增部门信息表单发起的是post请求, 转发到DeptListServlet时需要调用doPost方法处理请求
public class DeptListServlet extends HttpServlet {
// 处理post请求然后在doPost方法中调用doGet方法
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 连接数据库,动态展示部门列表页面
}
重定向到/oa/dept/list, 浏览器此时会在地址栏上发起一次全新的get请求,调用DeptListServlet的doGet方法处理请求
if (count == 1) {//新增成功
// 显示部门列表页面
response.sendRedirect(request.getContextPath() + "/dept/list");
}else{// 新增失败
// 使用重定向跳转到错误页面
response.sendRedirect(request.getContextPath() + "/error.html");
}
实现查看部门详情可修改功能
用户点击的“修改”按钮是DeptListServlet动态响应的内容,后端连接数据库查询部门信息时,不同的部门对应不同的编号,同理请求参数deptno的值也不同
while(rs.next()){
String deptno = rs.getString("a");
out.print(" 修改");
}
编写DeptEditServlet继承HttpServlet并重写doGet方法(配置到web.xml文件中)
<servlet>
<servlet-name>editservlet-name>
<servlet-class>com.bjpowernode.oa.web.action.DeptEditServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>editservlet-name>
<url-pattern>/dept/editurl-pattern>
servlet-mapping>
public class DeptEditServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取应用的根路径
String contextPath = request.getContextPath();
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("");
out.print("");
out.print(" ");
out.print(" ");
out.print(" 修改部门 ");
out.print(" ");
out.print(" ");
out.print(" 修改部门
");
out.print("
");
// 利用表单发起请求,保存部门修改后的信息
out.print(" );
//上面一部分是死的
// 连接数据库,动态输出部门的信息.....
。
//下面一部分是死的
out.print("
");
out.print(" ");
out.print(" ");
out.print("");
}
}
根据请求参数中携带的部门编号连接数据库,动态的将查询到的部门信息保存到一个表单中并返回给浏览器(这里的部门编号是只读的,readonly属性)
// 获取请求参数中携带的部门编号
String deptno = request.getParameter("deptno");
// 根据部门编号连接数据库查询部门信息
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
String sql = "select dname, loc as location from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, deptno);
rs = ps.executeQuery();
// 这个结果集中只有一条记录
if(rs.next()){
String dname = rs.getString("dname");
// 参数"location"是sql语句查询结果列的列名
String location = rs.getString("location");
// 部门编号是只读的
out.print(" 部门编号
");
out.print(" 部门名称
");
out.print(" 部门位置
");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, rs);
}
实现修改部门功能
用户点击的“修改”按钮是DeptEditServlet动态响应的内容,这个路径是需要加项目名的, 表单的name作为请求参数,表单的值作为value
// 利用表单发起请求,保存部门修改后的信息
out.print(" );
//下面一部分是死的
out.print("
");
out.print(" ");
编写DeptModifyServlet类继承HttpServlet并重写doPost方法(配置到web.xml文件中)
<servlet>
<servlet-name>modifyservlet-name>
<servlet-class>com.bjpowernode.oa.web.action.DeptModifyServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>modifyservlet-name>
<url-pattern>/dept/modifyurl-pattern>
servlet-mapping>
public class DeptModifyServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 解决请求体的中文乱码问题
request.setCharacterEncoding("UTF-8");
// 获取表单中的数据
String deptno = request.getParameter("deptno");
String dname = request.getParameter("dname");
String loc = request.getParameter("loc");
// 连接数据库执行更新语句
Connection conn = null;
PreparedStatement ps = null;
// 判断更新成功或者失败
int count = 0;
try {
conn = DBUtil.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);
count = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, null);
}
//更新部门信息成功或者失败的一个处理.....
}
}
更新部门信息成功或者失败的一个处理, 如果不需要共享数据,页面跳转都是以重定向
if (count == 1) { // 更新成功
// 重定向到部门列表页面(部门列表页面是通过Java程序动态生成的,所以还需要再次执行另一个Servlet)
response.sendRedirect(request.getContextPath() + "/dept/list");
}else{ // 更新失败
response.sendRedirect(request.getContextPath() + "/error.html");
}
模板方法设计模式解决类爆炸
如果每一个请求都对应一个Servlet类就会导致类爆炸 , 一般一个请求对应一个方法 , 一个业务对应一个Servlet类
重写HttpServlet类提供的重载的参数含httpXxx的service模板方法,本类提供以后会调本类的service模板方法(但是就享受不到HTTP协议专属的提醒)
// 模糊匹配 ,只要请求路径是以"/dept"开始的,都走这个Servlet
@WebServlet("/dept/*")
// @WebServlet({"/dept/list", "/dept/save", "/dept/edit", "/dept/detail", "/dept/delete", "/dept/modify"})
public class DeptServlet extends HttpServlet {
// 重写service模板方法(并没有重写doGet或者doPost)
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取servlet path
String servletPath = request.getServletPath();
if("/dept/list".equals(servletPath)){
doList(request, response);
} else if("/dept/save".equals(servletPath)){
doSave(request, response);
} else if("/dept/edit".equals(servletPath)){
doEdit(request, response);
} else if("/dept/detail".equals(servletPath)){
doDetail(request, response);
} else if("/dept/delete".equals(servletPath)){
doDel(request, response);
} else if("/dept/modify".equals(servletPath)){
doModify(request, response);
}
}
private void doList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 查看部门列表的业务逻辑
}
private void doSave(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 保存部门的业务逻辑
}
private void doEdit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 查看部门可修改的业务逻辑
}
private void doDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 查看部门详情的业务逻辑
}
private void doDel(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 删除部门的业务逻辑
}
private void doModify(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 修改部门的业务逻辑
}
}