用户信息列表实现增删改查案例的实现【问题及解决过程记录】&【综合案例】

目录

用户信息列表展示案例

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">&laquo;</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">&raquo;</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;
    }

修正及改进:

之前添加成员进去点击确定后没有数据展示,显示为空,只有再次点击查询后才会有数据检查后发现是跳转链接路径的问题,在对应servlet代码修改正确的路径/findUserByPageServlet即可

 至于限制最后一个分页框无法再后退则是在list.jsp限制条件分开:

①页码为最后一页时无法进入下一页,当前页面不+1

②当页码不为为最后一页时可以进入一页,当前页码+1

代码:

    <c:if test="${pb.currentPage >= pb.totalPage}">
                    <%--为了逻辑更严谨,当页码为最后一页时无法进入下一页--%>
                <li class="disabled">  <%--禁用--%>
                        <%--当前页面不+1--%>
                    <a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${pb.currentPage}&rows=5&name=${condition.name[0]}&address=${condition.address[0]}&email=${condition.email[0]}" aria-label="Next">
                        <span aria-hidden="true">&raquo;</span>
                    </a>
                    </c:if>

                <c:if test="${pb.currentPage < pb.totalPage}">
                        <%--当页码不为为最后一页时可以进入一页--%>
                <li>
                     <%--当前页码+1--%>
                    <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">&raquo;</span>
                    </a>
                         </c:if>

                </li>

这样就不会从最后一页跳转到(不存在的)下一页了^v^

复杂功能

复杂条件查询功能

  动态查询小技巧:

在原本查询语句

"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]}

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

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

 累了,喝茶~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值