开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情
目录
一: 基于Servlet和JSP改造oa项目
使用Servlet处理业务,收集数据; 使用JSP展示数据!
第一步:将原型中的.html文件,全部修改为.jsp文件
(1)将之前原型模板中的".html"文件,全部修改为".jsp",然后在所有的".jsp"文件头部添加page指令(指定contentType防止中文乱码),将所有的JSP直接拷贝到web目录下。
补充: ctrl+shift+del清除浏览器的缓存!
<%@page contentType="text/html;charset=UTF-8"%>
(2)完成所有页面的正常流转。(页面仍然能够正常的跳转,修改超链接的请求路径)
①这里就需要把所有的超连接路径更改,改成.jsp文件的格式;并加上项目名!
②这里就能体现出.jsp的优势,在jsp中是可以写java代码的;对于前端中的项目名,就可以通过java代码获取,不需要写死了!
③例如:对于欢迎页面index.jsp
<%=request.getContextPath()%> 在JSP中动态的获取应用的根路径
<a href="<%=request.getContextPath()%>/list.jsp">查看部门列表</a>
(3)目前所有原型页面如下:都是静态的页面,都是直接跳转到jsp展示数据,中间没有经过servlet获取数据!
①index.jsp 可以跳转到 list.jsp
<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>欢迎使用OA系统</title>
</head>
<body>
<a href="<%=request.getContextPath()%>/list.jsp">查看部门列表</a>
<hr>
</body>
</html>
②以list.jsp为展开对象,可以跳转到:detail.jsp、modify.jsp、add.jsp
<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>部门列表页面</title>
</head>
<body>
<script type="text/javascript">
function del(dno){
// 弹出确认框,用户点击确定,返回true,点击取消返回false
var ok = window.confirm("亲,删了不可恢复哦!");
if(ok){
document.location.href = "<%=request.getContextPath()%>/dept/delete?deptno=" + dno;
}
}
</script>
<h1 align="center">部门列表</h1>
<hr >
<table border="1px" align="center" width="50%">
<tr>
<th>序号</th>
<th>部门编号</th>
<th>部门名称</th>
<th>操作</th>
</tr>
<tr>
<td>1</td>
<td>10</td>
<td>销售部</td>
<td>
<a href="javascript:void(0)" onclick="del(10)">删除</a>
<a href="<%=request.getContextPath()%>/modify.jsp">修改</a>
<a href="<%=request.getContextPath()%>/detail.jsp">详情</a>
</td>
</tr>
</table>
<hr >
<a href="<%=request.getContextPath()%>/add.jsp">新增部门</a>
</body>
</html>
③detail.jsp展示完以后在跳转到list.jsp
<%@page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>部门详情</title>
</head>
<body>
<h1>部门详情</h1>
<hr >
部门编号:20 <br>
部门名称:销售部<br>
部门位置:北京<br>
<input type="button" value="后退" onclick="window.history.back()"/>
</body>
</html>
④modify.jsp展示完以后在跳转到list.jsp
<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>修改部门</title>
</head>
<body>
<h1>修改部门</h1>
<hr >
<form action="<%=request.getContextPath()%>/list.jsp" method="get">
部门编号<input type="text" name="deptno" value="20" readonly /><br>
部门名称<input type="text" name="dname" value="销售部"/><br>
部门位置<input type="text" name="loc" value="北京"/><br>
<input type="submit" value="修改"/><br>
</form>
</body>
</html>
⑤add.jsp展示完以后在跳转到list.jsp
<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>新增部门</title>
</head>
<body>
<h1>新增部门</h1>
<hr >
<form action="<%=request.getContextPath()%>/list.jsp" 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>
第二步:连接数据库,完成对应的操作
前面我们已经完成了jsp做数据展示的操作,但是并没有进行连接数据库;所以要先跳转到servlet完成数据的收集操作,然后通过servlet再跳到jsp做数据展示的操作!
(1)index.jsp 跳转到 list.jsp
(1)先对index.jsp模板原型进行修改;把超链接路径修改为跳转到一个servlet
<a href="<%=request.getContextPath()%>/list.jsp">查看部门列表</a>
<!--修改为-->
<a href="<%=request.getContextPath()%>/dept/list">查看部门列表</a>
(2)通过注解式开发,连接数据库,取出数据!(要有封装对象的意识---面向抽象编程)
此时取出的数据实际上是很零散的,所以不妨封装一个Dept对象,把取出来的数据封装到这个对象里面。同时在创建一个ArrayList集合depts,把所有的对象在放到这个集合里。然后在通过请求域调用setAttribute方法,把这个集合放到请求域当中。最后在调用getRequestDispatcher方法,通过转发的方式调转到另一个jsp进行数据的展示
①封装的Dept对象用来存放取出来的零散数据
package com.bjpowernode.oa.bean;
import java.util.Objects;
/**
* 普通的java类,张个java类可以封装零散的数据
* @Author:朗朗乾坤
* @Package:com.bjpowernode.oa.bean
* @Project:JavaWeb
* @name:Dept
* @Date:2022/11/28 10:59
*/
public class Dept {
private String deptno;
private String dname;
private String loc;
// 构造方法
public Dept() {
}
public Dept(String deptno, String dname, String loc) {
this.deptno = deptno;
this.dname = dname;
this.loc = loc;
}
// setter and getter
public String getDeptno() {
return deptno;
}
public void setDeptno(String deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
// 重写toString方法
@Override
public String toString() {
return "Dept{" +
"deptno='" + deptno + ''' +
", dname='" + dname + ''' +
", loc='" + loc + ''' +
'}';
}
// 重写equals方法 和 hashCode方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dept dept = (Dept) o;
return Objects.equals(deptno, dept.deptno) &&
Objects.equals(dname, dept.dname) &&
Objects.equals(loc, dept.loc);
}
@Override
public int hashCode() {
return Objects.hash(deptno, dname, loc);
}
}
②跳转到的servlet进行数据的收集
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.bean.Dept;
import com.bjpowernode.oa.utils.DBUtil;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
/**
* @Author:朗朗乾坤
* @Package:com.bjpowernode.oa.web.action
* @Project:JavaWeb
* @name:DeptServlet
* @Date:2022/11/28 10:39
*/
@WebServlet({"/dept/list"})
public class DeptServlet extends HttpServlet {
@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);
}
}
/**
*1、 连接数据库,查询所有的部门信息,然后跳转到jsp做页面展示
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void doList(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
// 再创建一个容器,用来存储部门
ArrayList<Dept> depts = new ArrayList<>();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 连接数据库
conn = DBUtil.getCoonetion();
// 获取预编译的数据库操作对象
String sql = "select deptno,dname,loc from dept";
ps = conn.prepareStatement(sql);
// 执行sql
rs = ps.executeQuery();
// 遍历查询结果集
while (rs.next()) {
// 取出数据
String deptno = rs.getString("deptno");
String dname = rs.getString("dname");
String loc = rs.getString("loc");
// 将零散的数据封装一个对象放进去
Dept dept = new Dept();
dept.setDeptno(deptno);
dept.setDname(dname);
dept.setLoc(loc);
// 肯定不止一个对象,所以创建一个集合(容器),用来存储部门对象
depts.add(dept);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(conn,ps,rs);
}
// 将集合放到请求域当中
request.setAttribute("deptList",depts);
// 转发(不要重定向)
request.getRequestDispatcher("/list.jsp").forward(request,response);
}
}
③通过转发的方式跳转到的另一个list.jsp,进行数据的展示
重点:对于for循环打印,这里实际上是拆分开了,但是转化为java代码还是一个完整的for循环;第一次见到这种输出方式,可能会比较不适应!
<%@ page import="com.bjpowernode.oa.bean.Dept" %>
<%@ page import="java.util.List" %>
<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>部门列表页面</title>
</head>
<body>
<script type="text/javascript">
function del(dno){
// 弹出确认框,用户点击确定,返回true,点击取消返回false
var ok = window.confirm("亲,删了不可恢复哦!");
if(ok){
document.location.href = "<%=request.getContextPath()%>/dept/delete?deptno=" + dno;
}
}
</script>
<h1 align="center">部门列表</h1>
<hr >
<table border="1px" align="center" width="50%">
<tr>
<th>序号</th>
<th>部门编号</th>
<th>部门名称</th>
<th>操作</th>
</tr>
<%
// 从request域当中取出集合
// getAttribute取出来的是Object类型,这里进行了强制类型转换
List<Dept> deptList = (List<Dept>)request.getAttribute("deptList");
// 循环遍历
int i =0;
for(Dept dept:deptList){
%>
<tr>
<td><%=++i%></td>
<td><%=dept.getDeptno()%></td>
<td><%=dept.getLoc()%></td>
<td>
<a href="javascript:void(0)" onclick="del(10)">删除</a>
<a href="<%=request.getContextPath()%>/modify.jsp">修改</a>
<a href="<%=request.getContextPath()%>/detail.jsp">详情</a>
</td>
</tr>
<%
}
%>
</table>
<hr >
<a href="<%=request.getContextPath()%>/add.jsp">新增部门</a>
</body>
</html>
④思考: 如果只使用JSP这一个技术,能不能开发web应用?
①当然可以使用JSP来完成所有的功能。因为JSP就是Servlet,在JSP的<%%>里面写的代码就是在service方法当中的,所以在<%%>当中完全可以编写JDBC代码,连接数据库,查询数据,也可以在这个方法当中编写业务逻辑代码,处理业务都是可以的,所以使用单独的JSP开发web应用完全没问题。
②虽然JSP一个技术就可以完成web应用,但是不建议,还是建议采用servlet + jsp的方式进行开发;这样都能将各自的优点发挥出来。JSP就是做数据展示!Servlet就是做数据的收集!(JSP中编写的Java代码越少越好)一定要职责分明!
⑤思考: JSP文件的扩展名必须是xxx.jsp吗?
①jsp文件的扩展名是可以配置的,不是固定的。
②在CATALINA_HOME/conf/web.xml,在这个文件当中配置jsp文件的扩展名。
③xxx.jsp文件对于Tomcat来说,只是一个普通的文本文件,web容器会将xxx.jsp文件最终生成java程序,最终调用的是java对象相关的方法,真正执行的时候,和jsp文件没有关系。
④小窍门:如果JSP代码看不懂,建议把jsp翻译成java代码,就能看懂了!
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
(2)list.jsp 跳转到detail.jsp
①对list.jsp中的详情超链接路径进行更改;并把部门编号也传过去
<a href="<%=request.getContextPath()%>/detail.jsp">详情</a>
<!--修改为-->
<a href="<%=request.getContextPath()%>/dept/detail?deptno=<%=dept.getDeptno()%>">详情</a>
②跳转到servlet,根据deptno进行数据的收集
这里就和上面不同,上面我们是查询所有的数据,有很多组,需要先把数据放到对象里,再把对象放到集合里;而这里每次使根据depto编号进行查询,就一组数据,所以不需要集合!
/**
*2、 根据部门编号,获取部门的详细信息
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void doDetail(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
// 创建一个集合,用来存放数据
Dept dept = new Dept();
// 通过key获取value,获取部门标号
String deptno = request.getParameter("deptno");
// 根据部门编号获取部门信息,将部门信息封装成对象
// 不需要集合,因为只有一个对象的数据
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 获取连接
conn = DBUtil.getCoonetion();
// 获取预编译的数据库操作对象
String sql = "select dname,loc from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1,deptno);
// 执行sql
rs = ps.executeQuery();
// 处理查询结果集,实际上就一条数据
if (rs.next()){
String dname = rs.getString("dname");
String loc = rs.getString("loc");
// 把数据封装成一个对象
// Dept dept = new Dept(); 定义到这里,下面转发使用不了
dept.setDeptno(deptno);
dept.setDname(dname);
dept.setLoc(loc);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(conn,ps,rs);
}
// 将封装的对象放到请求域当中
request.setAttribute("deptList",dept);
// 转发(不要重定向)
request.getRequestDispatcher("/detail.jsp").forward(request,response);
}
③通过转发的方式跳转到的另一个detail.jsp,进行数据的展示
<%@ page import="com.bjpowernode.oa.bean.Dept" %>
<%@page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>部门详情</title>
</head>
<body>
<h1>部门详情</h1>
<hr >
<%
// 从request域当中取出数据,强制类型转换
Dept dept = (Dept)request.getAttribute("deptList");
%>
部门编号:<%=dept.getDeptno()%> <br>
部门名称:<%=dept.getDname()%><br>
部门位置:<%=dept.getLoc()%><br>
<input type="button" value="后退" onclick="window.history.back()"/>
</body>
</html>
(3)list.jsp 跳转到 删除操作
①对list.jsp中的删除超链接路径进行更改;这里是使用一个回调函数进行路径的跳转
<a href="javascript:void(0)" onclick="del(10)">删除</a>
// 修改为
<a href="javascript:void(0)" onclick="del(<%=dept.getDeptno()%>)">删除</a>
// 回调函数如下,没有修改:
<script type="text/javascript">
function del(dno) {
// 弹出确认框,用户点击确定,返回true,点击取消返回false
var ok = window.confirm("亲,删了不可恢复哦!");
if (ok) {
document.location.href = "<%=request.getContextPath()%>/dept/delete?deptno=" + dno;
}
}
</script>
②跳转到servlet,根据deptno进行数据的收集;并且再次跳转到/dept/list页面进行数据的展示,这里使用的是重定向,因为不涉及从域中存取数据,所以尽可能使用重定向!
/**
*3、 根据部门编号,删除部门
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void doDel(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取部门编号
String deptno = request.getParameter("deptno");
// 连接数据库
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
try {
conn = DBUtil.getCoonetion();
String sql = "delete from dept where deptno=?";
ps = conn.prepareStatement(sql);
ps.setString(1,deptno);
count = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(conn,ps,null);
}
if (count==1) {
// 删除成功,重定向到list页面;因为这里没有想域中放入数据,所以使用重定向
// 重定向是要加项目名的,动态获取
String contextPath = request.getContextPath();
response.sendRedirect(contextPath+"/dept/list");
}
}
(4)list.jsp 跳转到 add.jsp
①对list.jsp中的详新增超链接路径不要更改,因为需要一个提交的表单;从add.jsp这个表单中跳转到servlet
注: 这里是提交数据,所以应该使用post请求!
<!--list.jsp这里不需要更改-->
<a href="<%=request.getContextPath()%>/add.jsp">新增部门</a>
<!--需要更改的是add.jsp里面的路径-->
<form action="<%=request.getContextPath()%>/list.jsp" method="get">
<!--修改为-->
<form action="<%=request.getContextPath()%>/dept/add" method="post">
②add.jsp
<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>新增部门</title>
</head>
<body>
<h1>新增部门</h1>
<hr >
<%--<form action="<%=request.getContextPath()%>/list.jsp" method="get">--%>
<form action="<%=request.getContextPath()%>/dept/add" 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>
③跳转到servlet,根据前端提交的数据,调用getParameter方法获取到后,进行数据的插入;然后再通过重定向/dept/list页面,进行数据的展示
/**
* 4、根据前端提交的数据,新增部门
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void doAdd(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.getCoonetion();
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);
}
if (count == 1) {
response.sendRedirect(request.getContextPath() + "/dept/list");
}
}
(5)list.jsp 跳转到 modify.jsp
思考:我们已经知道对于修改实际上有两次连接数据库的操作;第一次点击list页面的修改实际上就相当于查询;所以我们不妨就让 修改和详情 共享一个页面;然后在打一个标记;根据标记决定最终是跳转到detail.jsp还是modify.jsp
①修改list.jsp代码;两个走的是通过一个servlet(/dept/detail),有一个标记f
<a href="<%=request.getContextPath()%>/dept/detail?f=modify&deptno=<%=dept.getDeptno()%>">修改</a>
<a href="<%=request.getContextPath()%>/dept/detail?f=detail&deptno=<%=dept.getDeptno()%>">详情</a>
②修改/dept/detail代码,就需要获取标记f,根据标记f来决定跳转的页面
// 方法1:获取这个标记,然后讨论
String f = request.getParameter("f");
if ("modify".equals(f)){
request.getRequestDispatcher("/modify.jsp").forward(request,response);
}else if ("detail".equals(f)){
request.getRequestDispatcher("/detail.jsp").forward(request,response);
}
// 方法2:进行拼串
String forward = "/"+request.getParameter("f")+".jsp";
request.getRequestDispatcher(forward).forward(request,response);
③对modify.jsp进行修改,也要修改成post请求
<%@ page import="com.bjpowernode.oa.bean.Dept" %>
<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>修改部门</title>
</head>
<body>
<h1>修改部门</h1>
<hr >
<%
Dept dept = (Dept)request.getAttribute("dept");
%>
<!--<form action="<%=request.getContextPath()%>/list.jsp" method="get">
部门编号<input type="text" name="deptno" value="20" readonly /><br>
部门名称<input type="text" name="dname" value="销售部"/><br>
部门位置<input type="text" name="loc" value="北京"/><br>
<input type="submit" value="修改"/><br>
</form>-->
<form action="<%=request.getContextPath()%>/dept/modify" method="post">
部门编号<input type="text" name="deptno" value="<%=dept.getDeptno()%>" readonly /><br>
部门名称<input type="text" name="dname" value="<%=dept.getDname()%>"/><br>
部门位置<input type="text" name="loc" value="<%=dept.getLoc()%>"/><br>
<input type="submit" value="修改"/><br>
</form>
</body>
</html>
④跳转到/dept/modify,进行数据的更改
/**
* 5、根据部门名称,进行修改
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void doModify(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.getCoonetion();
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) {
// 更新成功
response.sendRedirect(request.getContextPath() + "/dept/list");
}
}