目录
用户信息列表展示案例
1. 需求:
1. 简单功能
1. 列表查询 2. 登录 3. 添加 4. 删除 5. 修改
2. 复杂功能
1. 删除选中 2. 分页查询 * 好处: 1. 减轻服务器内存的开销 2. 提升用户体验 3. 复杂条件查询
2. 设计:
1. 技术选型:
3. 开发:
1. 环境搭建
1. 创建数据库环境 2. 创建项目,导入需要的jar包
细节:
1.添加jar包要注意版本是否适配
2.配置文件要根据实际情况进行修改编辑
3.注意查询语句是否正确
4、据要写在forEach内编辑
2. 编码
4. 测试
进阶:
关于登录界面login.jsp
添加联系人功能
删除功能
修改功能
复杂功能
删除选中
分页查询
编辑
复杂功能
复杂条件查询功能
动态查询小技巧:
用户信息列表展示案例
1. 需求:
1. 简单功能
1. 列表查询
2. 登录
3. 添加
4. 删除
5. 修改
2. 复杂功能
1. 删除选中
2. 分页查询
* 好处:
1. 减轻服务器内存的开销
2. 提升用户体验
3. 复杂条件查询
2. 设计:
1. 技术选型:
Servlet+JSP+MySQL+JDBCTempleat+Duird+BeanUtils+tomcat
控制器 + 页面展示+ 操作数据库+ 自动封装 + 连接池提高连接效率+ 封装数据 + 部署到服务器上


2. 数据库设计:
create database test01; -- 创建数据库
use test01; -- 使用数据库
CREATE TABLE user2( -- 创建表
id int PRIMARY KEY auto_increment,
name VARCHAR(20) not null,
gender VARCHAR(5),
age INT,
address VARCHAR(32),
qq VARCHAR(20),
email VARCHAR(50)
);

3. 开发:
1. 环境搭建
1. 创建数据库环境
2. 创建项目,导入需要的jar包
细节:
1.添加jar包要注意版本是否适配


2.配置文件要根据实际情况进行修改
3.注意查询语句是否正确

4、据要写在forEach内
2. 编码
4. 测试
在/test02/userListServlet下可以输出,但是list.jsp下没有打印出来


试着打印UserListServlet,
response.getWriter();
输出无法识别中文,句首加入
//简单的形式,设置编码,是在获取流之前设置
response.setContentType("text/html;charset=utf-8");
即可。


最后终于得出错误原因,不是代码错误也不是配置错愕,是进入的网址错误,得从index.jsp进入首页

成了!
接着添加增删改操作
先在UserService接口添加对应接口
添加数据,报错
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [insert into user2 set name=?,gender=?,age=?,adress=?,qq=?,email=?]; nested exception is java.sql.SQLSyntaxErrorException: Unknown column 'adress' in 'field list'

查了半天是拼写错误

一个好消息,一个坏消息
好消息:写进去了
坏消息:但没完全写进去
出现中文乱码且丢失

//设置request编码
request.setCharacterEncoding("utf-8");

会发现性别和籍贯因为是有默认选择的复选框,不是手动输入的数据,所以未被存储进去,需要在UserAddServlet里添加存储进去,这样选择框里的对象也能获取到


UserAddServlet代码:
package cn.web.servlet;
import cn.domain.User;
import cn.service.UserService;
import cn.service.impl.UserServiceImpl;
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;
/**
* @author 乱码酱
* @date :2022-11-29 15:44
* @program: HTMLStudy
* @create:
*/
@WebServlet("/userAddServlet")
public class UserAddServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置request编码
request.setCharacterEncoding("utf-8");
//调用UserService完成添加
UserService service = new UserServiceImpl();
//获取参数
String name = request.getParameter("name");
String gender = request.getParameter("gender");
int age = Integer.parseInt(request.getParameter("age"));
String adress = request.getParameter("address");
String qq = request.getParameter("qq");
String email = request.getParameter("email");
//添加到User里
User user = new User();
user.setName(name);
user.setGender(gender);
user.setAge(age);
user.setAddress(adress);
user.setQq(qq);
user.setEmail(email);
// 调用UserService层
User user1 = service.addUser(user);
// 将list存入request域
request.setAttribute("user1",user);
//转发到
request.getRequestDispatcher("/index.jsp").forward(request,response);
3.调转到重新查询的servlet
// response.sendRedirect(request.getContextPath()+"/userListServlet");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
进阶:
将已有用户信息列表改进为后面一种格式


使用Bootstrap上的内联表单样式,但是出现了分层

解决方法:在div标签的style样式加一个float浮动即可
<div style="float: left">

至于分页,在Bootstrap的中文档首页“组件”复制分页即可。
关于登录界面login.jsp
验证码执行一个refreshCode();方法

添加登录所需字段username和password


可以在数据库查询是否添加成功
SELECT * FROM user2;

添加好内容
数据库添加字段,对应实体类User也要跟着修改

先进入登录界面login.jsp,登录成功会提示

添加联系人功能

在list.jsp中添加联系人按钮路径跳转到add.jsp

add.jsp也要连接指定servlet

之前的addservlet没用util工具类,需要一个一个添加,
@WebServlet("/addUserServlet")
public class AddUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置request编码
request.setCharacterEncoding("utf-8");
//调用UserService完成添加
UserService service = new UserServiceImpl();
//获取参数
String name = request.getParameter("name");
String gender = request.getParameter("gender");
int age = Integer.parseInt(request.getParameter("age"));
String adress = request.getParameter("address");
String qq = request.getParameter("qq");
String email = request.getParameter("email");
//添加到User里
User user = new User();
user.setName(name);
user.setGender(gender);
user.setAge(age);
user.setAddress(adress);
user.setQq(qq);
user.setEmail(email);
// 调用UserService层
User user1 = service.addUser(user);
// 将list存入request域
request.setAttribute("user1",user);
//转发到
request.getRequestDispatcher("/index.jsp").forward(request,response);
3.调转到重新查询的servlet
// response.sendRedirect(request.getContextPath()+"/userListServlet");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
后来加入了工具类,效率提高
//1.设置编码
request.setCharacterEncoding("utf-8");
//2.获取参数
Map<String, String[]> map = request.getParameterMap();
//3.封装对象
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.addUser(user);
//5.跳转到/userListServlet
// 没有共享数据使用重定向 加上虚拟路径request.getContextPath()
response.sendRedirect(request.getContextPath()+"/userListServlet");
UserDaoImpl中的addUser方法也优化了
@Override
public User addUser(User user) {
try {
//第一版
//String sql = "insert into user2 set name = ?, gender = ?, age = ?, address = ?, qq= ?, email = ?";
//第二版
String sql ="insert into user2 values(null, ?, ?, ?, ?, ?, ?,null, null )";
template.update(sql, user.getName(), user.getGender(), user.getAge(), user.getAddress(), user.getQq(), user.getEmail());
} catch (DataAccessException e) {
e.printStackTrace();
}
return user;
}
添加用户成功!

删除功能

在list.jsp删除按钮添加路径

编辑DelUserService
原版本:
//1.设置request编码
request.setCharacterEncoding("utf-8");
int id = Integer.parseInt(request.getParameter("id"));
//2.调用service
UserService service = new UserServiceImpl();
service.deleteUser(id);
//3.调转到重新查询的servlet
response.sendRedirect(request.getContextPath()+"/userListServlet");
3.转发到
// request.getRequestDispatcher("/index.jsp").forward(request,response);
现版本:
// 因为是根据id删除,不涉及汉字,可以不用设置编码
// 1.获取id对象
String id = request.getParameter("id");
// 2.调用service删除
UserService service = new UserServiceImpl();
service.deleteUser(id);
//3.跳转查询所有servle
response.sendRedirect(request.getContextPath()+"/userListServlet");
测试:


轻易就删除了记录,但是不排除误删的可能性,想加入一个确认删除的提示框
在list.jsp删除按钮添加一个方法,点击会有确认框


放到上面去获取不到id,于是传参


测试一下:


修改功能

修改update.jsp指向路径并在<input>标签添加value,编写对应service、dao层接口和实现类方法

测试时出现404错误

原因是重新建了一个findUserServlet,需要重新启动服务器,启动即可成功访问

之前的修改性别和地址不知道默认值,所以要判断选择框里的性别和籍贯,需要在update.jsp开头加上标签引入
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
加入判断:


在<select>中selected是默认值

有几个就做几次判断(默默删除几个选项减少工作量)


用户修改都是基于id,但是id是数据库生成的,在表单中没有体现,所以建一个隐藏域,将id创建在里面获取
<%--隐藏域提交id--%>
<input type="hidden" name="id" value="${user.id}">

代码编写好 测试一下


报了一个500的错


原来是没重启的锅,重启后恢复正常
但是新的问题出现了,无法修改内容,除去一部分原因是我在数据库写入数据,里面的地址不在<select>选框中无法显示


于是试了其他的也没能成功修改,查找原因发现是sql语句缺了逗号,离谱!

成了!

复杂功能
删除选中

获取选中条目id的方法:
在<table>外加一个<form>表单


【更正】一下,连接的是/delSelectedServlet(删除选中)不是/delUserServlet(删除用户)

【更正】复选框的name和value也写错位置了
写对应方法

全选和全不选的实现

选中后的提示(防止误删)

测试:
全选然后提示框弹出后取消删除会跳转404页面

原因:在删除选中的超链接写了一个script方法,但是冒号是中文,识别不到方法

改为英文就能识别了!
分页查询
要实现的功能及数据

在三层架构的调用

细节:
//4.调用dao查询List集合 //计算开始的记录索引 0-5 5-10 10-15 ... (含前不含后) int start = (currentPage - 1) * rows; List<User> list = dao.findByPage(start, rows); //5.计算总页码 // 分情况,看能不能整除,例如一页5条记录,15条记录就是显示15/5=3页,17条记录就是显示17/5=3...2,所以是(17/5)+1=4页, int totalPage = (totalCount % rows) == 0 ? (totalCount / rows) : (totalCount / rows) + 1; pb.setTotalPage(totalPage);
UserServiceImpl:
@Override //分页查询
public PageBean<User> findUserByPage(String _currentPage, String _rows, Map<String, String[]> condition) {
//将String类型的参数封装成Integer
int currentPage = Integer.parseInt(_currentPage);
int rows = Integer.parseInt(_rows);
//1.创建空的PageBean对象
PageBean<User> pb = new PageBean<User>();
//2.设置参数
pb.setCurrentPage(currentPage);
pb.setRows(rows);
//3.调用dao查询总记录数
int totalCount = dao.findTotalCount();
pb.setTotalCount(totalCount);
//4.调用dao查询List集合
//计算开始的记录索引 0-5 5-10 10-15 ... (含前不含后)
int start = (currentPage - 1) * rows;
List<User> list = dao.findByPage(start, rows);
pb.setList(list);
//5.计算总页码
// 分情况,看能不能整除,例如一页5条记录,15条记录就是显示15/5=3页,17条记录就是显示17/5=3...2,所以是(17/5)+1=4页,
int totalPage = (totalCount % rows) == 0 ? (totalCount / rows) : (totalCount / rows) + 1;
pb.setTotalPage(totalPage);
return pb;
}
测试异常
http://localhost/test02/findUserByPageServlet?currentPage=1&rows=5

重启后正常了

继续编写前台代码



替换成真正的数据

分页栏和实际数据保持一致
<%--分页栏设计--%>
<c:forEach begin="1" end="${pb.totalPage}" var="i">
<li>
<a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${i}&rows=5">${i}</a>
</li>
</c:forEach>

分页栏的激活与禁用&添加判断,确保分页栏和当前界面地址栏页码一致
<%--分页栏设计--%>
<c:forEach begin="1" end="${pb.totalPage}" var="i">
<%--添加判断,确保分页栏和当前界面地址栏页码一致--%>
<c:if test="${pb.currentPage == i}">
<%--li标签里class="active"确保分页栏激活--%>
<li class="active"><a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${i}&rows=5"></a> </li>
</c:if>
<c:if test="${pb.currentPage != i}"> <%--分页栏和当前界面地址栏页码不匹配,不激活--%>
<li><a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${i}&rows=5">${i}</a></li>
</c:if>
</c:forEach>

分页栏的激活与禁用
确保分页栏和当前界面地址栏页码一致
优化上一页和下一页
在当前页码的基础上进行-1和+1操作
<li> <%--当前页码-1--%>
<a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${pb.currentPage - 1}&rows=5" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>


为了逻辑更严谨,当页码为第一页时无法返回上一页,为最后一页时无法进入下一页

如此就是样式设置成功啦!

虽然样式设置不让点,但是实际上还是可以点,这需要到后台编写代码解决
在后台UserServiceImpl 做判断,分页查询方法findUserByPage
//判断页码是否小于等于0,如果是,设为1

这样就能确保第一页的上一页无法点击,诸如此类方法还有很多,css样式里也能设置无法选择。。。
最后一页也是类似

list.jsp部分改动后代码:
<c:if test="${pb.currentPage == pb.totalPage}">
<%--为了逻辑更严谨,当页码为最后一页时无法进入下一页--%>
<li class="disabled">
</c:if>
<c:if test="${pb.currentPage != pb.totalPage}">
<%--当页码不为为最后一页时可以进入下一页--%>
<li>
</c:if> <%--当前页码+1--%>
<a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${pb.currentPage + 1}&rows=5"
aria-label="Next">
<span aria-hidden="true">»</span>
</a>
UserServiceImpl部分改动代码:

测试出错

出错原因及解决方法:
设置参数存入应该在计算之后而不是之前,将存入部分代码移到方法最后即可解决

@Override //分页查询
public PageBean<User> findUserByPage(String _currentPage, String _rows, Map<String, String[]> condition) {
//将String类型的参数封装成Integer
int currentPage = Integer.parseInt(_currentPage);
int rows = Integer.parseInt(_rows);
//判断页码是否小于等于0,如果是,设为1
if (currentPage <= 0) {
currentPage = 1;
}
//1.创建空的PageBean对象
PageBean<User> pb = new PageBean<User>();
//3.调用dao查询总记录数
int totalCount = dao.findTotalCount();
pb.setTotalCount(totalCount);
//4.调用dao查询List集合
//计算开始的记录索引 0-5 5-10 10-15 ... (含前不含后)
int start = (currentPage - 1) * rows;
List<User> list = dao.findByPage(start, rows);
pb.setList(list);
//5.计算总页码
// 分情况,看能不能整除,例如一页5条记录,15条记录就是显示15/5=3页,17条记录就是显示17/5=3...2,所以是(17/5)+1=4页,
int totalPage = (totalCount % rows) == 0 ? (totalCount / rows) : (totalCount / rows) + 1;
pb.setTotalPage(totalPage);
//判断页码是否大于等于最后一页,如果是,设为最后一页
if (currentPage >= pb.getTotalPage()) {
currentPage = pb.getTotalPage();
}
//2.设置参数
pb.setCurrentPage(currentPage);
pb.setRows(rows);
return pb;
}
复杂功能
复杂条件查询功能

动态查询小技巧:
在原本查询语句
"select count(*) from user2"改为
"select count(*) from user2 where 1 = 1"
这样代码结果不变且可以在后面添加查询条件
sb.append("and key like ?")
在form表单添加路径和读取方法,跳转到分页查询servlet

FindUserByPageServlet添加条件查询参数
UserServiceImpl中findUserByPage分页查询方法添加条件查询参数

在数据库上查询到的:
控制台上查询到的
一条记录,对上了!
接下来完善UserDaoImpl分页查询每页记录方法findByPage()

改写sql语句复制之前我们写的findTotalCount()方法语句过去


一些注意的点:

@Override //分页查询每页记录
public List<User> findByPage(int start, int rows, Map<String, String[]> condition) {
String sql = "select * from user2 where 1 = 1 "; //留空格拼接字符串
StringBuilder sb = new StringBuilder(sql); //字符串拼接
//2.遍历map
Set<String> keySet = condition.keySet();
//定义参数的集合
List<Object> params = new ArrayList<Object>();
for (String key : keySet) {
//排除分页条件参数 只要name、address...参数查询
if("currentPage".equals(key) || "rows".equals(key)){
continue;//结束当前循环进入下一循环
}
//获取value 如果最后不加[0]限定,出来的结果是一个values,所以要加上限定
String value = condition.get(key)[0]; //只获取一个值
System.out.println(value);
//判断value是否有值
if(value != null && !"".equals(value)){
//有值
sb.append(" and "+key+" like ? ");//注意加空格(与前面查询语句拼接) 一个问号对应一个值
params.add("%"+value+"%");//?条件的值 加% %类似 like "%李%" 模糊查询
}
}
//添加分页查询 记得空格
sb.append(" limit ? , ? ");
//添加分页查询参数值
params.add(start);
params.add(rows);
sql = sb.toString();
//不能在调用直接写template.query(sql,... ,start,rows) sql此时变成了sb.toString(), start,rows变成了params.toArray()
//但是很多时候会忘记template.query(),干脆将sql = sb.toString();
//测试
System.out.println(sql);
System.out.println(params);
// return template.query(sql,new BeanPropertyRowMapper<User>(User.class),start,rows);
return template.query(sql,new BeanPropertyRowMapper<User>(User.class),params.toArray());
}
打印测试:


打印后查询记录不见了,只要在map里存入即可


结果:
新的问题:跳转页码后查询条件消失
解决方法:
在每个分页地址后面拼接查询条件字符串
&name=${condition.name[0]}&address=${condition.address[0]}&email=${condition.email[0]}

这样即便跨页也能保存查询条件

以上就是全部的流程,有很多细节和操作值得注意!
累了,喝茶~








![[附源码]JAVA毕业设计计算机组成原理教学演示软件(系统+LW)](https://img-blog.csdnimg.cn/6ba456fff5cb4967b843accee6a2d4fc.png)










