前言
博主在Web阶段也学习了近一个月,对于前端和后端的一些连接部分也有了一些了解
本篇博客是用来总结自己写过的一个小的综合案例,其实增删改查的操作都很简单了,最重要的是如何 将前端和后端连接起来 的思想
欢迎大家提出意见哦~ 觉得博主写得不错的可以一键三连啦~ 博主写得头都要昏了~
目录
登录界面
在进入系统前,我们要先进操作员的登录,这里本来该建一个新的操作员实体类,并在数据库中创建一个操作员信息表的,但是这里为了方便,直接给用户信息添加了 username 和 password 两个属性
界面展示
后端代码思路分析
LoginServlet 类的代码编写流程:
-
设置编码
request.setCharacterEncoding("utf-8");
-
获取数据:获取用户填写的验证码
String verifycode = request.getParameter("verifycode");
-
验证码校验
如果验证失败: 1、先设置提示信息 request.setAttribute("login_msg","验证码错误"); 2、再跳转界面,跳转回登录界面(使用转发) 为什么要跳转呢?仔细想想,点击登录按钮后,系统自动将数据拿到数据库进行比较 如果登录失败就要跳转到登录界面,而登录成功就需要跳转到另一个系统界面 所以这里要做跳转这一步,后面都会使用到跳转,就不再详细解释了 request.getRequestDispatcher("/login.jsp").forward(request,response);
-
封装User对象
将前端获取的数据进行封装,封装成实体类User(用户信息实体类)对象,这里使用的是 BeanUtils类的 populate 方法,参数为 :(存储数据的对象,要转换的对象)
-
调用Service查询
调用Service实现类中的方法将封装后的对象 user 与数据库中的数据进行比较,这里要说明:
根据三层架构,我们分为: 1.界面层(表示层):用户看的得界面。用户可以通过界面上的组件和服务器进行交互 2.业务逻辑层:处理业务逻辑的。(接口命名为Service,实现类为ServiceImp) 3.数据访问层:操作数据存储文件。(接口命名为Dao,实现类为DaoImp)
-
判断是否登录成功
验证成功 1、把数据存入session session.setAttribute("user",login_user); 2、跳转页面(重定向) response.sendRedirect(request.getContextPath()+"/index.jsp"); 验证失败 1、提示信息 request.setAttribute("login_msg","用户名或密码错误"); 2、跳转登录界面 request.getRequestDispatcher("/login.jsp").forward(request,response);
前端代码分析
-
为表单设置action属性,设置表单提交的地址,其中
${pageContext.request.contextPath}
用来替代虚拟路径,这样就不用再更换虚拟路径后又一个个进行修改<form action="${pageContext.request.contextPath}/loginServlet" method="post">
-
给每一个文本框添加 id 属性,因为要将文本框的数据传入后端,传入的数据是一个map集合,key 就是 id 的内容,例如:
<input type="text" name="username" class="form-control" id="user" placeholder="请输入用户名"/>
-
登录界面肯定需要验证码,添加一张验证码的图,
"href="javascript:refreshCode();"
是为该链接添加一个函数,使之能切换不同的验证码验证码的div如下:
<div class="form-inline"> <label for="vcode">验证码:</label> <input type="text" name="verifycode" class="form-control" id="verifycode" placeholder="请输入验证码" style="width: 120px;"/> <a href="javascript:refreshCode();"> <img src="${pageContext.request.contextPath}/checkCodeServlet" title="看不清点击刷新" id="vcode"/> </a> </div>
验证码的
script
<script type="text/javascript"> //切换验证码 function refreshCode(){ //1.获取验证码图片对象 var vcode = document.getElementById("vcode"); //2.设置其src属性,加时间戳 vcode.src = "${pageContext.request.contextPath}/checkCodeServlet?time="+new Date().getTime(); } </script>
-
修改错误提示框里的提示信息,
<strong>xxx</strong>
中的xxx改为${login_msg}
,在Servlet中会定义这个信息,并用setAttribute()方法传入request中<!-- 出错显示的信息框 --> <div class="alert alert-warning alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" > <span>×</span> </button> <strong>${login_msg}</strong> </div>
增加功能
界面展示
后端代码思路分析
AddUserServlet 的代码编写思路:
-
设置编码
设置编码的作用主要是为了防止乱码,代码如下:
request.setCharacterEncoding("utf-8");
-
获取参数
这里的参数指的是页面里输入的数据(前端输入的数据),获取到后端,再到数据库中进行查询和比较,使用的是 getParameterMap() 方法
-
封装对象
将前端获取的数据进行封装,封装成实体类User(用户信息实体类)对象,这里使用的是 BeanUtils类的 populate 方法,参数为 :(存储数据的对象,要转换的对象)
-
调用Service
调用Service实现类中的方法将封装后的对象 user 与数据库中的数据进行比较
-
跳转到 FindUserByPageServlet(重定向)
前端代码分析
-
为表单设置action属性,设置表单提交的地址,其中
${pageContext.request.contextPath}
用来替代虚拟路径,这样就不用再更换虚拟路径后又一个个进行修改<form action="${pageContext.request.contextPath}/addUserServlet" method="post">
-
给每一个文本框添加 id 属性,因为要将文本框的数据传入后端,传入的数据是一个map集合,key 就是 id 的内容,例如:
<input type="text" class="form-control" id="age" name="age" required="required" placeholder="请输入年龄">
删除功能
界面展示
删除有两种删除方法,一是单独删除一行,二是删除选中的多行数据
后端代码思路分析
DelUserServlet 类(删除单行) 代码编写思路:
-
获取id
String id = request.getParameter("id");
-
调用Service删除
UserService service=new UserServiceImpl(); service.deletUser(id);
-
跳转到查询所有Servlet
response.sendRedirect(request.getContextPath()+"/findUserByPageServlet");
DelSelectServlet 类(删除多行) 代码编写思路:
-
获取所有id
String[] ids=request.getParameterValues("uid");
-
调用Service删除
UserService service=new UserServiceImpl(); service.delSelectedUser(ids);
-
跳转到查询所有Servlet
response.sendRedirect(request.getContextPath()+"/findUserByPageServlet");
前端代码分析
-
为单行删除按钮添加函数,完成删除功能
<a class="btn btn-default btn-sm" href="javascript:deleteUser(${user.id});">删除</a></td>
<script> function deleteUser(id){ //用户安全提示 if(confirm("您确定要删除吗?")){ //访问路径 location.href="${pageContext.request.contextPath}/delUserServlet?id="+id; } } </script>
-
给多行删除按钮添加单击事件
<a class="btn btn-primary" href="javascript:void(0);" id="delSelected">删除选中</a>
<script> window.onload = function(){ //给删除选中按钮添加单击事件 document.getElementById("delSelected").onclick = function(){ if(confirm("您确定要删除选中条目吗?")){ var flag = false; //判断是否有选中条目 var cbs = document.getElementsByName("uid"); for (var i = 0; i < cbs.length; i++) { if(cbs[i].checked){ //有一个条目选中了 flag = true; break; } } if(flag){ //有条目被选中 //表单提交 document.getElementById("form").submit(); } } } //1.获取第一个cb document.getElementById("firstCb").onclick = function(){ //2.获取下边列表中所有的cb var cbs = document.getElementsByName("uid"); //3.遍历 for (var i = 0; i < cbs.length; i++) { //4.设置这些cbs[i]的checked状态 = firstCb.checked cbs[i].checked = this.checked; } } } </script>
实现了两个小细节:(1) 点击删除后有一个确认框,避免删除过快导致无法挽回;(2) 可以实现复选框全选中功能
-
给表单第一列添加复选框,实现多行删除的选中功能
<form id="form" action="${pageContext.request.contextPath}/delSelectServlet" method="post"> <table border="1" class="table table-bordered table-hover"> <tr class="success"> <!-- 复选框 --> <th><input type="checkbox" id="firstCb"></th> <th>编号</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>籍贯</th> <th>QQ</th> <th>邮箱</th> <th>操作</th> </tr> <c:forEach items="${pb.list}" var="user" varStatus="s"> <tr> <!-- 复选框 --> <td><input type="checkbox" name="uid" value="${user.id}"></td> <td>${s.count}</td> <td>${user.name}</td> <td>${user.gender}</td> <td>${user.age}</td> <td>${user.address}</td> <td>${user.qq}</td> <td>${user.email}</td> <td><a class="btn btn-default btn-sm" href="${pageContext.request.contextPath}/findUserServlet?id=${user.id}">修改</a> <a class="btn btn-default btn-sm" href="javascript:deleteUser(${user.id});">删除</a></td> </tr> </c:forEach> </table> </form>
修改功能
界面展示
后端代码思路分析
FindUserServlet 类代码编写思路:
//1.获取id
String id = request.getParameter("id");
//2.调用Service
UserService service=new UserServiceImpl();
User user=service.findUserById(id);
//3.将user存入request
request.setAttribute("user",user);
//4.转发到update.jsp
request.getRequestDispatcher("/update.jsp").forward(request,response);
UpdateUserServlet 类代码编写思路:
//1.设置编码
request.setCharacterEncoding("utf-8");
//2.获取map
Map<String, String[]> map = request.getParameterMap();
//封装对象
User user=new User();
try {
BeanUtils.populate(user,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//4.调用Service修改
UserService service=new UserServiceImpl();
service.updateUser(user);
//5.跳转到查询所有Servlet
response.sendRedirect(request.getContextPath()+"/findUserByPageServlet");
前端代码分析
-
为表单设置action属性,设置表单提交的地址,其中
${pageContext.request.contextPath}
用来替代虚拟路径,这样就不用再更换虚拟路径后又一个个进行修改<form action="${pageContext.request.contextPath}/updateUserServlet" method="post">
-
设置隐藏域 提交id
<input type="hidden" name="id" value="${user.id}">
-
设置信息回显,点击进入修改页面后,依然能看到原来的信息
普通的文本框就添加
value
属性,性别选择添加一个value
属性和checked
地址信息的回显用以下方法:
<c:if test="${user.address == '陕西'}"> <option value="陕西" selected>陕西</option> <option value="北京">北京</option> <option value="上海">上海</option> </c:if> <c:if test="${user.address == '北京'}"> <option value="陕西" >陕西</option> <option value="北京" selected>北京</option> <option value="上海">上海</option> </c:if> <c:if test="${user.address == '上海'}"> <option value="陕西" >陕西</option> <option value="北京">北京</option> <option value="上海" selected>上海</option> </c:if>
-
给姓名设置 readonly 属性规定输入字段为只读,修改时无法修改姓名
<input type="text" class="form-control" id="name" name="name" value="${user.name}" readonly="readonly" placeholder="请输入姓名" />
分页查询功能
因为需要做出分页的效果,所以原来的简单的查询功能就不再使用了,这里就结合着分页来介绍
界面展示
后端代码思路分析
先创建一个PageBean实体类,实体类成员变量如下:
//总记录数
private int totalCount;
//总页码
private int totalPage;
//每页的数据
private List<T> list;
//当前页码
private int currentPage;
//每页显示的记录数
private int rows;
FindUserByPageServlet 代码编写思路:
request.setCharacterEncoding("utf-8");
//1.获取参数
//当前页码
String currentPage = request.getParameter("currentPage");
//每页显示条数
String rows = request.getParameter("rows");
//当页码为0时,使当前页码变为1
if(currentPage==null || "".equals(currentPage)){
currentPage="1";
}
if(rows==null||"".equals(rows)){
rows="5";
}
//获取条件查询参数
Map<String,String[]> condition=request.getParameterMap();
//2.调用service查询
UserService service=new UserServiceImpl();
PageBean<User> pb=service.findUserByPage(currentPage,rows,condition);
//3.将PageBean存入request
request.setAttribute("pb",pb);
request.setAttribute("condition",condition);
//4.转发到 list.jsp
request.getRequestDispatcher("/list.jsp").forward(request,response);
上述代码的第2步是一个重点,返回的pb是根据查询文本框输入的数据进行查询得到的List数据
前端代码分析
<div>
<nav aria-label="Page navigation">
<ul class="pagination">
<!-- 左角标 -->
<c:if test="${pb.currentPage == 1}">
<li class="disabled">
</c:if>
<c:if test="${pb.currentPage != 1}">
<li>
</c:if>
<a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${pb.currentPage - 1}&rows=5&name=${condition.name[0]}&address=${condition.address[0]}&email=${condition.email[0]}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<!-- 页码 -->
<c:forEach begin="1" end="${pb.totalPage}" var="i">
<c:if test="${pb.currentPage == i}">
<li class="active"><a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${i}&rows=5&name=${condition.name[0]}&address=${condition.address[0]}&email=${condition.email[0]}">${i}</a></li>
</c:if>
<c:if test="${pb.currentPage != i}">
<li><a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${i}&rows=5&name=${condition.name[0]}&address=${condition.address[0]}&email=${condition.email[0]}">${i}</a></li>
</c:if>
</c:forEach>
<!-- 右角标 -->
<c:if test="${pb.currentPage==pb.totalPage}">
<li class="disabled">
</c:if>
<c:if test="${pb.currentPage != pb.totalPage}">
<li>
</c:if>
<a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${pb.currentPage + 1}&rows=5&name=${condition.name[0]}&address=${condition.address[0]}&email=${condition.email[0]}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
<!-- 备注 -->
<span style="font-size: 25px;margin: 5px" >
共${pb.totalCount}条数据,共${pb.totalPage}页
</span>
</ul>
</nav>
</div>
上述代码大致分为四个部分:"<" 、页码数字、">"、一共多少数据
(1) 每个部分的链接地址都由 ${pageContext.request.contextPath}
+ 实际地址 + 当前页码 + 每页显示的记录数 + 文本框的值信息 组成,这样就组成了复制分页查询的分页条
(2) 在 “<” 和 “>” 的部分做了 if 选择,当页码为1或者最大时,再点击 “<” 和 “>” 图标,就会显示无法点击的图标,用法是给 li
标签添上class="disabled"
属性,但是实际上还是能点击,并且网页会报错,但是这个问题在后端已经解决了
(3) 在页码数字的部分做了 if 选择,使每个当前页码的样式与其他的页码样式不一样,用法是给 li
标签添上class="active"
属性