JavaWeb笔记Day8------会话技术与JSP

会话技术

会话

一次会话包含多次请求和响应

  • 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止

功能

在一次会话的范围内的多次请求间,共享数据

方式

  1. 客户端会话技术:Cookie

  2. 服务器端会话技术:Session

概念:

客户端会话技术,将数据保存到客户端

使用步骤:

  1. 创建Cookie对象,绑定数据
new Cookie(String name, String value) 
  1. 发送Cookie对象
response.addCookie(Cookie cookie) 
  1. 获取Cookie,拿到数据
Cookie[]  request.getCookies()  

实现原理

基于响应头set-cookie和请求头cookie实现

image-20220309153815493

Cookie细节

  1. 一次可不可以发送多个cookie?
  • 可以
  • 可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。
  1. cookie在浏览器中保存多长时间?

    • 默认情况下,当浏览器关闭后,Cookie数据被销毁
  2. 持久化存储:

    • setMaxAge(int seconds)

      • 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效

      • 负数:默认值

      • 零:删除cookie信息

      1. cookie能不能存中文?
    • 在tomcat 8 之前 cookie中不能直接存储中文数据。

    • 需要将中文数据转码---一般采用URL编码(%E3)

    • 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析

  3. cookie共享问题

    1. 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享

      • 默认情况下cookie不能共享
      • setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录
        • 如果要共享,则可以将path设置为"/"
    2. 不同的tomcat服务器间cookie共享问题

      • setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享

      • setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享

Cookie特点

  1. cookie存储数据在客户端浏览器
  2. 浏览器对于单个cookie 的大小有限制(4kb) 以及 对同一个域名下的总cookie数量也有限制(20个)

Cookie作用

  1. cookie一般用于存出少量的不太敏感的数据

  2. 在不登录的情况下,完成服务器对客户端的身份识别

案例

需求
  1. 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问。

  2. 如果不是第一次访问,则提示:欢迎回来,您上次访问的时间为:显示时间字符串

分析
  1. 可以采用Cookie来完成
  2. 在服务器中的Servlet判断是否有一个名为lastTime的cookie
  3. 有:不是第一次访问
    1. 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
    2. 写回Cookie:lastTime=2018年6月10日11:50:01
  4. 没有:是第一次访问
    1. 响应数据:您好,欢迎您首次访问
    2. 写回Cookie:lastTime=2018年6月10日11:50:01
代码
package Cookie;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;


import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;

@WebServlet(name = "CookieTest", value = "/CookieTest")
public class CookieTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置响应的消息体的数据格式以及编码
        response.setContentType("text/html;charset=utf-8");

        //1.获取所有的Cookie
        Cookie[] cookies=request.getCookies();
        boolean flag=false;//没有Cookie为lastTime
        //2.遍历Cookie
        if (cookies!=null && cookies.length>0){
            for (Cookie cookie:cookies){
                //3.获取Cookie的名称
                String name=cookie.getName();
                //4.判断名称是否是lastTime
                if ("lastTime".equals(name)){
                    //有该Cookie,不是第一次访问

                    flag=true;//有lastTime的Cookie
                    //提取上次访问的时间
                    String value=cookie.getValue();

                    //设置Cookie的value值
                    //获取当前时间的字符串,重新设置Cookie的value值,重新发送Cookie
                    Date date=new Date();
                    SimpleDateFormat formatter=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                    String dateString=formatter.format(date);



                    //URL编码
                    dateString= URLEncoder.encode(dateString,"utf-8");
                    cookie.setValue(dateString);

                    //设置Cookie的有效期为一个月
                    cookie.setMaxAge(60*60*24*30);

                    response.addCookie(cookie);

                    //响应数据
                    //获取Cookie的value,时间

                    //URL解码
                    value= URLDecoder.decode(value,"utf-8");
                    System.out.println("上次访问的时间:"+value);
                    response.getWriter().write("<h1>欢迎回来,您上次访问的时间为:"+value+"</h1>");

                    break;
                }
            }
        }


        if(cookies==null || cookies.length==0 || !flag){
            //没有,第一次访问

            //设置Cookie的value值
            //获取当前时间的字符串,重新设置Cookie的value值,重新发送Cookie
            Date date=new Date();
            SimpleDateFormat formatter=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String dateString=formatter.format(date);
            //URL编码
            dateString= URLEncoder.encode(dateString,"utf-8");
            Cookie cookie=new Cookie("lastTime",dateString);

            //设置Cookie的有效期为一个月
            cookie.setMaxAge(60*60*24*30);
            response.addCookie(cookie);

            response.getWriter().write("<h1>欢迎您第一次访问</h1>");
        }

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

Session

概念

服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HTTPSession

方法

//获取HttpSession对象
HTTPSession session=request.getSession();

//使用HttpSession对象
Object getAttribute(String name);
void setAttribute(String name,Object value);
void removeAttribute(String name);

原理

Session的实现是依赖于Cookie的。

image-20220310223931013

细节

  1. 当客户端关闭后,服务器不关闭,两次获取session是否为同一个

    • 默认情况下,不是

    • 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存

      Cookie c=new Cookie("JSESSIONID",session.getId());
      c.setMaxAge(60*60);
      response.addCookie(c);
      
      
  2. 客户端不关闭,服务器关闭后,两次获取的session是否是同一个

    • 不是同一个,但要确保数据不丢失
      • session的钝化:
        • 在服务器正常关闭之前,将session对象系列化到硬盘上
      • session的活化:
        • 在服务器启动后,将session文件转化为内存中的session对象即可
  3. session的失效时间

    1. 服务器关闭

    2. session对象调用invalidate()。

    3. session默认失效时间是30分钟

      <!--选择性配置修改-->
      <session-config>
          <session-timeout>30</session-timeout>
      </session-config>
      

特点

  1. session用于存储一次会话的多次请求的数据,存在服务器端
  2. session可以存储任意类型,任意大小的数据

session与cookie的区别

  1. session存储数据在服务器端,Cookie在客户端
  2. session没有数据大小限制,Cookie有
  3. session数据安全,Cookie相对于不安全

案例

  1. 需求:

    1. 访问带有验证码的登录页面login.jsp
    2. 用户输入用户名,密码以及验证码。
      • 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
      • 如果验证码输入有误,跳转登录页面,提示:验证码错误
      • 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
  2. 分析:

    image-20220310235137499

  3. 代码:

    User类

    package web.test.domain;
    
    /**
     * 用户的实体类
     */
    public class User {
        private int id;
        private String username;
        private String password;
        private String checkCode;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    
        public String getCheckCode() {
            return checkCode;
        }
    
        public void setCheckCode(String checkCode) {
            this.checkCode = checkCode;
        }
    }
    

    loginServlet.java

    package web.servlet;
    
    import jakarta.servlet.*;
    import jakarta.servlet.http.*;
    import jakarta.servlet.annotation.*;
    import org.apache.commons.beanutils.BeanUtils;
    import web.test.dao.UserDao;
    import web.test.domain.User;
    
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.util.Map;
    
    @WebServlet(name = "loginServlet", value = "/loginServlet")
    public class loginServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.设置request编码
            request.setCharacterEncoding("utf-8");
            //2.获取参数Map
            Map<String, String[]> parameterMap = request.getParameterMap();
    
            //获取生成的验证码
            HttpSession session = request.getSession();
            String checkCodeInSession = (String) session.getAttribute("checkCode");
    
            //删除session中的验证码
            session.removeAttribute("checkCode");
    
            //判断验证码是否正确
            //忽略大小写比较
            if (checkCodeInSession!=null && checkCodeInSession.equalsIgnoreCase(parameterMap.get("checkCode")[0])) {
                //判断用户名和密码是否正确
                User loginUser = new User();
    
                //3.1使用BeanUtils封装
                try {
                     BeanUtils.populate(loginUser, parameterMap);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
    
                ////4.调用UserDao的login方法
                UserDao userDao = new UserDao();
                User user = userDao.login(loginUser);
    
                //5.判断user
                if (user != null) {
                    //登录成功
                    //存储信息,用户信息
                    session.setAttribute("user", parameterMap.get("username")[0]);
                    //重定向到success.jsp
                    response.sendRedirect(request.getContextPath()+"/success.jsp");
                }else {
                    //登录失败
                    //存储信息到request域
                    request.setAttribute("login_error", "用户名或密码错误");
                    //转发到登录页面
                    request.getRequestDispatcher("/login.jsp").forward(request, response);
                }
            }else {
                //验证码错误
                //存储提示信息到request域中
                request.setAttribute("cc_error", "验证码错误");
                //转发到登录页面
                request.getRequestDispatcher("/login.jsp").forward(request, response);
            }
    
        }
    }
    
    

    login.jsp

    <%--
      Created by IntelliJ IDEA.
      User: admin
      Date: 2022-03-11
      Time: 17:17
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>login</title>
    
        <script>
            window.onload = function () {
                document.getElementById("img").onclick = function () {
                    document.getElementById("img").src = "/StudyJavaWeb00/CheckCodeServlet?time=" + new Date().getTime();
                }
            }
        </script>
    
        <style>
            div{
                color: red;
            }
        </style>
    </head>
    <body>
    <form action="/StudyJavaWeb00/loginServlet" method="post">
        <table>
            <tr>
                <td>用户名</td>
                <td><input type="text" name="username"/></td>
            </tr>
            <tr>
                <td>密码</td>
                <td><input type="password" name="password"/></td>
            </tr>
            <tr>
                <td>验证码</td>
                <td><input type="text" name="checkCode"/></td>
            </tr>
            <tr>
                <td colspan="2"><img id="img" src="/StudyJavaWeb00/CheckCodeServlet"/></td>
            <tr>
                <td colspan="2"><input type="submit" value="登录"/></td>
            </tr>
        </table>
    </form>
    
    <div><%=request.getAttribute("cc_error") == null ? "" : request.getAttribute("cc_error")%></div>
    <div><%=request.getAttribute("login_error") == null ? "" : request.getAttribute("login_error")%>></div>
    </body>
    </html>
    
    

    success.jsp

    <%--
      Created by IntelliJ IDEA.
      User: admin
      Date: 2022-03-11
      Time: 19:56
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h1><%=request.getSession().getAttribute("user")%>,欢迎您</h1>
    </body>
    </html>
    

JSP

概念

Java Server Pages:Java服务器端页面

  • 可以理解为:一个特殊的页面,其中既可以指定定义HTML标签,又可以定义Java代码
  • 用于简化书写

原理

  • JSP本质上就是一个Servlet
    image-20220309220244375

脚本

  • 概念:JSP定义Java代码的方式

  • 种类:

    <% 代码%>:定义的Java代码,在service方法中。service方法中可以定义什么,该脚本中就可以定义什么     
    <%! 代码%>:定义的Java代码,在jsp转换后的Java类的成员位置
    <%=代码%>:定义的Java代码,会输出到页面上。输出语句中可以定义什么
    

内置对象

在jsp页面中不需要获取和创建,可以直接使用的对象

jsp一共有9个内置对象

变量名 真实类型 作用
pageContext PageContext 当前页面共享数据,还可以获取其他八个内置对象
request HttpServletRequest 一次请求访问的多个资源(转发)
session HttpSession 一次会话的多个请求间
application ServletContext 所有用户间共享数据
response HttpServletResponse 响应对象
page Object 当前页面(Servlet)的对象 this
out JspWriter 输出对象,数据输出到页面上(字符输出流对象。可以将数据输出到页面上。和response.getWriter()类似。(注:①在Tomcat服务器真正给客户端做出响应之前,会先找response缓冲区数据,在找out缓冲区数据。②response.getWriter()数据输出永远在out.write()之前))
config ServletConfig Servlet的配置对象
exception Throwable 异常对象

image-20220309225310898

指令

作用

用于配置JSP页面,导入资源文件

格式

<%@ 指令名称 属性名1=属性值1 属性名2=属性值2 ...%>

分类

  1. page:配置JSP页面的

    • contentType:等同于response.setContentType()
      1. 设置响应体的mime类型以及字符集
      2. 设置当前jsp页面的编码(只能是高级的IDE才能生效,如果使用低级工具,则需设置pageEncoding属性设置当前页面的字符集)
    • import:导包
    • errorPage:当前页面发生一次后,会自动跳转到指定的错误页面
    • iserrorPag:标识当前页面是否是错误页面。
      • true:是,可以使用内置对象exception
      • false:否,默认值。不可以使用内置对象exception
  2. include:页面包含的。导入页面的资源文件

    <%@include file="top.jsp">
    
  3. taglib:导入资源

    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    
    • prefix:前缀,自定义的

    注:关于idea中http://java.sun.com/jsp/jstl/core“报红,解决方案参考

    1. 解决idea中http://java.sun.com/jsp/jstl/core“红色异常_居贝比的博客-CSDN博客
    2. IntelliJ IDEA 怎么导入JSTL标签_百度知道 (baidu.com)

注释

  1. html注释:

    <!--只能注释HTML代码片段-->
    
  2. jsp注释:推荐使用

    <%--
        可以注释所有
        --%>
    

MVC开发模式

Jsp演变历史

image-20220311222557157

MVC

  1. M:Model,模型
    • 完成具体的业务操作,如:查询数据库,封装对象
  2. V:View,视图
    • 展示数据
  3. C:Controller,控制器。Servlet
    • 获取用户的输入
    • 调用模型
    • 将数据交给视图进行展示

优点

  1. 耦合性低,方便维护,可以利于分工协作
  2. 重用性高

缺点

  1. 使得项目架构变得复杂,对开发人员要求高

EL表达式

概念

Expression Language

作用

替换和简化jsp页面中Java代码的编写

语法

${表达式}

注意

  • jsp默认支持el表达式的。如果要忽略el表达式

    1. 设置jsp中page指令中:isELIgnored="true" 忽略当前jsp页面中所有的el表达式
    2. \${表达式}:忽略当前这个el表达式

使用

  1. 运算符

    1. 算术运算符:+ - * /(div)%(mod)
    2. 比较运算符:> < >= <= == !=
    3. 逻辑运算符:&&(and)||(or) !(not)
    4. 空运算符:empty
      • 功能:用于判断字符串,集合,数组对象是否为null并且长度是否为0
      • $
      • {not empty str}:表示判断字符串,集合,数组对象是否不为null,并且长度>0
  2. 获取值

    1. el表达式只能从域对象获取值

    2. 语法:

      1. {域名称,键名}:从指定域中获取指定的值

        1. 域名称:

          域名 对象
          pageScope pageContext
          requestScope request
          sessionScope session

        | applicationScope | application(ServletContext) |

        1. 举例:在request域中存储了name=张三

        2. 获取:$

      2. ${键名}:表示依次从最小的域中查找是否有该键对应的值,直到找到为止

      3. 获取对象,List集合,Map集合的值

        1. 对象:$
          • 本质上会去调用对象的getter方法
        2. List集合:$
        3. Map集合:
          • $
          • $
    3. 隐式对象:

      • el表达式中有11个隐式对象

      • pageContext:

        • 获取jsp其他八个内置对象

          ${pageContext.request.contextPath}:动态获取虚拟目录
          

JSTL

概念

JavaServer Pages Tags Library JSP标准标准库

  • 是由Apache组织提供的开源的免费的jsp标签 <标签>

作用

用于简化和替换jsp页面上的Java代码

使用步骤

  1. 导入jstl相关jar包

    参考:jsp - How to install JSTL? The absolute uri: http://java.sun.com/jstl/core cannot be resolved - Stack Overflow

  2. 引入标签库:taglib指令:<%@ taglib%>

  3. 使用标签

常用的JSTL标签

  1. if:相当于Java代码的if语句

    1. 属性:
      • test 必须属性,接受boolean表达式
        • 如果表达式为true,则显示if标签体内容,如果为false,则不显示标签体内容
        • 一般情况下,test属性值会结合el表达式一起使用
    2. 注意:c:if标签没有else情况,想要else情况,则可以再定义一个c:if标签
  2. choose:相当于Java代码的switch语句

  3. foreach:相当于Java代码的for语句

    • 完成重复操作

      • 属性:
        • begin:开始值
        • end:结束值
        • var:临时变量
        • step:步长
        • varStatus:循环状态对象
          • index:容器中元素的索引,从0开始
          • count:循环次数,从1开始
    • 遍历容器

      • items:容器对象
      • var:容器中元素的临时变量
      • varStatus:循环状态对象
        • index:容器中元素的索引,从0开始
        • count:循环次数,从1开始

练习

需求

在request域中有一个存有User对象的List集合。需要使用jstl+el将list集合数据展示到jsp页面的表格table中

代码

<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="web.test.jstl.User" %>
<%@ page import="java.util.Date" %><%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2022-03-14
  Time: 2:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Test</title>
</head>
<body>
<%
    List list = new ArrayList();
    list.add(new User("张三",23,new Date()));
    list.add(new User("李四",24,new Date()));
    list.add(new User("王五",25,new Date()));
    request.setAttribute("list",list);
%>

<table border="1" width="500" align="center">
    <tr>
        <th>编号</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>生日</th>
    </tr>
<%--    数据行--%>
    <c:forEach items="${list}" var="user" varStatus="s">
        <c:if test="${s.count%2==0}">
            <tr bgcolor="blue">
                <td>${s.count}</td>
                <td>${user.name}</td>
                <td>${user.age}</td>
                <td>${user.birStr}</td>
            </tr>
        </c:if>

        <c:if test="${s.count%2!=0}">
            <tr bgcolor="red">
                <td>${s.count}</td>
                <td>${user.name}</td>
                <td>${user.age}</td>
                <td>${user.birStr}</td>
            </tr>
        </c:if>

    </c:forEach>

</table>
</body>
</html>

三层架构

  1. 界面层(表示层):用户看的界面。用户可以通过界面上的组件和访问器进行交互
  2. 业务逻辑层:处理业务逻辑的。
  3. 数据访问层:操作数据存储文件的 image-20220315000223221

案例

需求

用户信息的增删改查操作

设计

  1. 技术选型:Servlet+JSP+MySQL+JDBCTempleat+Duird+BeanUtils+Tomcat

  2. 数据库设计:

    #使用数据库
    USE Test;
    
    CREATE TABLE user(
        #建表
        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包
    2. 编码
  4. 测试

  5. 部署运维

简单功能

列表查询

分析

image-20220315005147048

代码
userListServlet
package web.servlet;

import domain.User;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import service.UserService;
import service.impl.UserServiceImpl;

import java.io.IOException;
import java.util.List;

@WebServlet(name = "userListServlet", value = "/userListServlet")
public class userListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 调用UserService完成查询
        UserService service = new UserServiceImpl();
        List<User> users = service.findAll();
        //2.将list存入request域
        request.setAttribute("users", users);
        //3.转发到list.jsp
        request.getRequestDispatcher("/list.jsp").forward(request, response);
    }
}

UserServiceImpl
package service.impl;

import dao.UserDao;
import dao.impl.UserDaoImpl;
import domain.Login;
import domain.PageBean;
import domain.User;
import service.UserService;

import java.util.List;

public class UserServiceImpl implements UserService {
    private UserDao dao =new UserDaoImpl();
    @Override
    public List<User> findAll() {
        //调用Dao完成查询
        return dao.findAll();
    }
}

JDBCUtils
package util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * JDBC工具类,使用Durid连接池
 */
public class JDBCUtils {
    private static DataSource ds;

    static{
        //1.加载配置文件
        Properties pro = new Properties();
        //使用ClassLoader加载配置文件,获取字节输入流
        InputStream is=JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
        try {
            pro.load(is);

            //2.初始化连接池对象
            ds= DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接池对象
     * @return
     */
    public static DataSource getDataSource(){
        return ds;
    }

    /**
     * 获取连接Connection对象
     * @return
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
}

UserDaoImpl
package dao.impl;

import dao.UserDao;
import domain.Login;
import domain.User;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import util.JDBCUtils;

import java.util.List;

public class UserDaoImpl implements UserDao {
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
    @Override
    public List<User> findAll() {
        //操作数据库
        //1. 定义sql
        String sql="select * from user";
        List<User> users = template.query(sql, new BeanPropertyRowMapper<User>(User.class));
        return users;
    }


}

User
package domain;

public class User {
    private int id;
    private String name;
    private String gender;
    private int age;
    private String address;
    private String qq;
    private String email;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getQq() {
        return qq;
    }

    public void setQq(String qq) {
        this.qq = qq;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", qq='" + qq + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}
Index.jsp
<div align="center">
  <a
          href="${pageContext.request.contextPath}/UserListServlet" style="text-decoration:none;font-size:33px">查询所有用户信息
  </a>
</div>
list.jsp
       <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="${users}" var="user" varStatus="s">
      <tr>
        <td><input type="checkbox" value="${user.id}" id="" name="uid"></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>&nbsp;
          <a class="btn btn-default btn-sm" href="javascript:deleteUser(${user.id});">删除</a>
        </td>
      </tr>
    </c:forEach>
  </table >

登录

分析
  1. 调整页面,加入验证码功能(验证码实现扩展:Java滑动验证码的原理与实现_Lark丶的博客-CSDN博客_滑动验证码的原理

  2. 代码实现

代码
loginServlet
@WebServlet(name = "loginServlet", value = "/loginServlet")
public class loginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置编码
        request.setCharacterEncoding("utf-8");
        //2.获取数据
        //2.1获取用户填写的验证码
        String verifycode = request.getParameter("verifycode");

        Map<String,String[]> map =request.getParameterMap();

        //4.验证码校验(常用套路)
        HttpSession session = request.getSession();
        String CHECKCODE_SERVER = (String) session.getAttribute("CHECKCODE_SERVER");
        //验证码校验成功后,需要清除验证码(确保一次性)
        session.removeAttribute("CHECKCODE_SERVER");

        if(verifycode ==null || !verifycode.equalsIgnoreCase(CHECKCODE_SERVER)){
            //验证码错误
            //提示信息
            request.setAttribute("login_msg","验证码错误");
            //跳转到登录页面
            request.getRequestDispatcher("/login.jsp").forward(request,response);
            return;
        }
        //4.封装User对象
        Login login = new Login();
        try {
            BeanUtils.populate(login,map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //5.调用service方法
        UserService service = new UserServiceImpl();
        Login login_user = service.login(login);
        //6.判断是否登录成功
        if(login_user != null){
            //登录成功
            //将用户信息存入session
            session.setAttribute("login_user",login_user);
            //跳转到首页
            response.sendRedirect(request.getContextPath()+"/index.jsp");

        }else{
            //登录失败
            //提示信息
            request.setAttribute("login_msg","用户名或者密码错误");
            //跳转到登录页面
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }
}

字符验证码(CheckCode)

注:拓展参考:

  1. Java滑动验证码的原理与实现_Lark丶的博客-CSDN博客_滑动验证码的原理
  2. Java实现字符验证码、运算验证码_Lark丶的博客-CSDN博客_java运算验证码
/**
 * 验证码
 */
@WebServlet("/CheckCodeServlet")
public class CheckCodeServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		
		//服务器通知浏览器不要缓存
		response.setHeader("pragma","no-cache");
		response.setHeader("cache-control","no-cache");
		response.setHeader("expires","0");
		
		//在内存中创建一个长80,宽30的图片,默认黑色背景
		//参数一:长
		//参数二:宽
		//参数三:颜色
		int width = 80;
		int height = 30;
		BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		
		//获取画笔
		Graphics g = image.getGraphics();
		//设置画笔颜色为灰色
		g.setColor(Color.GRAY);
		//填充图片
		g.fillRect(0,0, width,height);
		
		//产生4个随机验证码,12Ey
		String checkCode = getCheckCode();
		//将验证码放入HttpSession中
		request.getSession().setAttribute("CHECKCODE_SERVER",checkCode);
		
		//设置画笔颜色为黄色
		g.setColor(Color.YELLOW);
		//设置字体的小大
		g.setFont(new Font("黑体",Font.BOLD,24));
		//向图片上写入验证码
		g.drawString(checkCode,15,25);
		
		//将内存中的图片输出到浏览器
		//参数一:图片对象
		//参数二:图片的格式,如PNG,JPG,GIF
		//参数三:图片输出到哪里去
		ImageIO.write(image,"PNG",response.getOutputStream());
	}
	/**
	 * 产生4位随机字符串 
	 */
	private String getCheckCode() {
		String base = "0123456789ABCDEFGabcdefg";
		int size = base.length();
		Random r = new Random();
		StringBuffer sb = new StringBuffer();
		for(int i=1;i<=4;i++){
			//产生0到size-1的随机值
			int index = r.nextInt(size);
			//在base字符串中获取下标为index的字符
			char c = base.charAt(index);
			//将c放入到StringBuffer中去
			sb.append(c);
		}
		return sb.toString();
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request,response);
	}
}
UserServiceImpl
public class UserServiceImpl implements UserService {
    private UserDao dao =new UserDaoImpl();
    @Override
    public Login login(Login login) {
        return dao.login(login.getUsername(),login.getPassword());
    }
}

UserDaoImpl
public class UserDaoImpl implements UserDao {
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());

    @Override
    public Login login(String username, String password) {
        String sql="select * from login where username=? and password=?";
        try {
            Login login=template.queryForObject(sql,new BeanPropertyRowMapper<Login>(Login.class),username,password);
            return login;
        }catch (EmptyResultDataAccessException e){
            return null;
        }
    }
}

Login
package domain;

public class Login {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Login{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
login.jsp
 <script type="text/javascript">
    //切换验证码
    function refreshCode(){
        //1. 获取验证码图片对象
        let vcode=document.getElementById("vcode");
        //2.设置其src属性,加时间戳
        vcode.src="${pageContext.request.contextPath}/CheckCodeServlet?time="+new Date().getTime();
    }
  </script>
    <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>


  <!-- 出错显示的信息框 -->
<strong>${login_msg==null?"":login_msg}</strong>

添加联系人

分析

image-20220316000837127

代码
addUserServlet
@WebServlet(name = "addUserServlet", value = "/addUserServlet")
public class addUserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置编码
        request.setCharacterEncoding("utf-8");
        //2.获取参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        //3.封装对象
        User user = new User();
        try {
            BeanUtils.populate(user, parameterMap);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //4.调用service保存
        UserService service = new UserServiceImpl();
        service.addUser(user);

        //5.跳转到userListServlet
        response.sendRedirect(request.getContextPath() + "/findUserByPageServlet");
    }
}

UserServiceImpl
public class UserServiceImpl implements UserService {
    private UserDao dao =new UserDaoImpl();
    @Override
    public void addUser(User user) {
        dao.addUser(user);
    }
}

UserDaoImpl
public class UserDaoImpl implements UserDao {
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
    @Override
    public void addUser(User user) {
        //1.定义SQL
        String sql="insert into user values(null,?,?,?,?,?,?)";
        //2.执行SQL
        template.update(sql,user.getName(),user.getGender(),user.getAge(),user.getAddress(),user.getQq(),user.getEmail());
    }
}
add.jsp
   <form action="${pageContext.request.contextPath}/addUserServlet" method="post">
        ........
    </form>

删除联系人

分析

image-20220318193740203

代码
delUserServlet
@WebServlet(name = "delUserServlet", value = "/delUserServlet")
public class delUserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取id
        String id = request.getParameter("id");
        //2.调用service删除
        UserService service = new UserServiceImpl();
        service.deleteUser(id);

        //3.跳转到查询所有Servlet
        response.sendRedirect(request.getContextPath()+"/findUserByPageServlet");
    }
}
UserServiceImpl
public class UserServiceImpl implements UserService {
    private UserDao dao =new UserDaoImpl();

    @Override
    public void deleteUser(String id) {
        dao.deleteUser(Integer.parseInt(id));
    }
}

UserDaoImpl
public class UserDaoImpl implements UserDao {
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
    @Override
    public void deleteUser(int id) {
        //1.定义SQL
        String sql="delete from user where id=?";
        template.update(sql,id);
    }
}
list.jsp
<script>
    function deleteUser(id){
      //用户安全提示
      if (confirm("确定要删除吗?")){
        //访问路径
        location.href = "${pageContext.request.contextPath}/delUserServlet?id=" + id;
      }
    }
  </script>
        <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="${pageBean.list}" var="user" varStatus="s">
      <tr>
        <td><input type="checkbox" value="${user.id}" id="" name="uid"></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>&nbsp;
          <a class="btn btn-default btn-sm" href="javascript:deleteUser(${user.id});">删除</a>
        </td>
      </tr>
    </c:forEach>
  </table >

修改信息

分析

image-20220318200525102

代码
findUserServlet
@WebServlet(name = "findUserServlet", value = "/findUserServlet")
public class findUserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //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
@WebServlet(name = "updateUserServlet", value = "/updateUserServlet")
public class updateUserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //一条龙
        //1.设置编码
        request.setCharacterEncoding("utf-8");
        //2.获取map
        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.updateUser(user);

        //5.跳转到查询所有Servlet
        response.sendRedirect(request.getContextPath()+"/findUserByPageServlet");
    }
}
UserServiceImpl
public class UserServiceImpl implements UserService {
    private UserDao dao =new UserDaoImpl();

    @Override
    public void updateUser(User user) {
        dao.updateUser(user);
    }
    
    @Override
    public User findUserById(String id) {
        return dao.findUserById(Integer.parseInt(id));
    }
}

UserDaoImpl
public class UserDaoImpl implements UserDao {
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
   @Override
    public void updateUser(User user) {
        String sql="update user set name=?,gender=?,age=?,address=?,qq=?,email=? where id=?";
        template.update(sql,user.getName(),user.getGender(),user.getAge(),user.getAddress(),user.getQq(),user.getEmail(),user.getId());
    }
    
    @Override
    public User findUserById(int id) {
        String sql="select * from user where id=?";
        User user=template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),id);
        return user;
    }
    
}

update.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
<head>
    <!-- 指定字符集 -->
    
    
    
    <title>修改用户</title>

    <link href="css/bootstrap.min.css" rel="stylesheet">
    <script src="js/jquery-2.1.0.min.js"></script>
    <script src="js/bootstrap.min.js"></script>

</head>
<body>
<div class="container" style="width: 400px;">
    <h3 style="text-align: center;">修改联系人</h3>
    <form action="${pageContext.request.contextPath}/updateUserServlet" method="post">
<%--        隐藏域,提交id(重点)--%>
        <input type="hidden" name="id" value="${user.id}">
        <div class="form-group">
            <label for="name">姓名:</label>
            <input type="text" class="form-control" id="name" name="name" value="${user.name}"  readonly="readonly" placeholder="请输入姓名" />
        </div>

        <div class="form-group">
            <label>性别:</label>
            <c:if test="${user.gender=='男'}">
                <input type="radio" name="gender" value="男" checked />男
                <input type="radio" name="gender" value="女"  />女
            </c:if>

            <c:if test="${user.gender=='女'}">
                <input type="radio" name="gender" value="男"  />男
                <input type="radio" name="gender" value="女" checked />女
            </c:if>
        </div>

        <div class="form-group">
            <label for="age">年龄:</label>
            <input type="text" class="form-control" id="age"  value="${user.age}" name="age" placeholder="请输入年龄" />
        </div>

        <div class="form-group">
            <label for="address">籍贯:</label>
            <select name="address" id="address" class="form-control" >
                <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>
            </select>
        </div>

        <div class="form-group">
            <label for="qq">QQ:</label>
            <input type="text" id="qq" value="${user.qq}" class="form-control" name="qq" placeholder="请输入QQ号码"/>
        </div>

        <div class="form-group">
            <label for="email">Email:</label>
            <input type="text" id="email" class="form-control" value="${user.email}" name="email" placeholder="请输入邮箱地址"/>
        </div>

        <div class="form-group" style="text-align: center">
            <input class="btn btn-primary" type="submit" value="提交" />
            <input class="btn btn-default" type="reset" value="重置" />
            <input class="btn btn-default" type="button" value="返回"/>
        </div>
    </form>
</div>
</body>
</html>
list.jsp
  <form id="form" action="${pageContext.request.contextPath}/delSelectedServlet"  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="${pageBean.list}" var="user" varStatus="s">
      <tr>
        <td><input type="checkbox" value="${user.id}" id="" name="uid"></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>&nbsp;
          <a class="btn btn-default btn-sm" href="javascript:deleteUser(${user.id});">删除</a>
        </td>
      </tr>
    </c:forEach>
  </table >
  </form>

复杂功能

删除选中

分析

image-20220318210325046

代码
delSelectedServlet
@WebServlet(name = "delSelectedServlet", value = "/delSelectedServlet")
public class delSelectedServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取所有id
        String[] ids = request.getParameterValues("uid");
        //2.调用service删除
        UserService service = new UserServiceImpl();
        service.delSelectedUser(ids);
        //3.跳转到查询所有的Servlet
        response.sendRedirect(request.getContextPath()+"/findUserByPageServlet");
    }
}
UserServiceImpl
public class UserServiceImpl implements UserService {
    private UserDao dao =new UserDaoImpl();
    @Override
    public void delSelectedUser(String[] ids) {
        if (ids != null && ids.length > 0) {
            //1.遍历数组
            for (String id : ids) {
                //2.调用Dao完成删除
                dao.deleteUser(Integer.parseInt(id));
            }
        }
    }
}

UserDaoImpl
public class UserDaoImpl implements UserDao {
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());


    @Override
    public void deleteUser(int id) {
        //1.定义SQL
        String sql="delete from user where id=?";
        template.update(sql,id);
    }
}

list.jsp
<script>
    function deleteUser(id){
      //用户安全提示
      if (confirm("确定要删除吗?")){
        //访问路径
        location.href = "${pageContext.request.contextPath}/delUserServlet?id=" + id;
      }
    }

    window.onload=function(){
      //给删除选中按钮添加点击事件
      document.getElementById("delSelected").onclick=function(){


        //用户安全提示
        if (confirm("确定要删除选中条目吗?")){

          let flag = false;
          //判断是否有选中条目
          const cbs = document.getElementsByName("uid");
          for(let i=0; i<cbs.length; i++){
            //有一个条目被选中,就设置flag为true
            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.遍历所有的cb
        for(var i=0;i<cbs.length;i++){
          //4.设置cbs[i]的选中状态=firstCb.checked
          cbs[i].checked=this.checked;
        }
      }
    }
  </script>
  <div style="float: right;margin: 5px">
    <a class="btn btn-primary" href="add.jsp">添加联系人</a></td>
    <a class="btn btn-primary" href="javascript:void (0);"id="delSelected">删除选中</a></td>
  </div>

  <form id="form" action="${pageContext.request.contextPath}/delSelectedServlet"  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="${pageBean.list}" var="user" varStatus="s">
      <tr>
        <td><input type="checkbox" value="${user.id}" id="" name="uid"></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>&nbsp;
          <a class="btn btn-default btn-sm" href="javascript:deleteUser(${user.id});">删除</a>
        </td>
      </tr>
    </c:forEach>
  </table >
  </form>

分页查询

好处
  1. 减少服务器开销

  2. 提升用户体验

分析

image-20220319233300887

image-20220319235948681

代码
findUserByPageServlet
@WebServlet(name = "findUserByPageServlet", value = "/findUserByPageServlet")
public class findUserByPageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取参数
        String currentPage=request.getParameter("currentPage");//当前页码
        String rows=request.getParameter("rows");//每页显示的条数

        if (currentPage==null||"".equals(currentPage) || Integer.parseInt(currentPage)<=0){
            currentPage="1";
        }

        if (rows==null||"".equals(rows)) {
            rows="5";
        }

        //2.调用service查询
        UserService service=new UserServiceImpl();
        PageBean<User> pageBean=service.findUserByPage(currentPage,rows);



        //3.将pageBean放入request域中
        request.setAttribute("pageBean",pageBean);


        //4.转发到list.jsp
        request.getRequestDispatcher("/list.jsp").forward(request,response);
    }
}
UserServiceImpl
public class UserServiceImpl implements UserService {
    private UserDao dao =new UserDaoImpl();

    @Override
    public PageBean<User> findUserByPage(String currentPage, String rows) {

        //创建空的PageBean对象
        PageBean<User> pb = new PageBean<User>();
        //设置参数
        pb.setCurrentPage(Integer.parseInt(currentPage));
        pb.setRows(Integer.parseInt(rows));
        //调用Dao查询总记录数
        int totalCount = dao.findTotalCount();
        pb.setTotalCount(totalCount);

        //计算总页码
        int totalPage = totalCount % pb.getRows() == 0 ? totalCount / pb.getRows() : totalCount / pb.getRows() + 1;
        pb.setTotalPage(totalPage);

        if (pb.getCurrentPage() >= totalPage) {
            pb.setCurrentPage(totalPage);
        }

        //调用Dao查询List集合
        //计算开始的记录索引
        int start = (pb.getCurrentPage() - 1) * pb.getRows();
        List<User> list = dao.findByPage(start, pb.getRows());
        pb.setList(list);


        return pb;
    }
}

UserDaoImpl
public class UserDaoImpl implements UserDao {
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());

    @Override
    public int findTotalCount() {
        String sql="select count(*) from user";
        return template.queryForObject(sql,Integer.class);
    }

    @Override
    public List<User> findByPage(int start, int rows) {
        String sql="select * from user limit ?,?";
        List<User> users=template.query(sql,new BeanPropertyRowMapper<User>(User.class),start,rows);
        return users;
    }
}
PageBean
package domain;

import java.util.List;

/**
 * 分页对象
 */
public class PageBean<T> {
    private int totalCount; // 总记录数
    private int totalPage ; // 总页码
    private List<T> list ; // 每页的数据
    private int currentPage ; //当前页码
    private int rows;//每页显示的记录数

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }

    public int getRows() {
        return rows;
    }

    public void setRows(int rows) {
        this.rows = rows;
    }

    @Override
    public String toString() {
        return "PageBean{" +
                "totalCount=" + totalCount +
                ", totalPage=" + totalPage +
                ", list=" + list +
                ", currentPage=" + currentPage +
                ", rows=" + rows +
                '}';
    }
}
list.jsp
 <form id="form" action="${pageContext.request.contextPath}/delSelectedServlet"  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="${pageBean.list}" var="user" varStatus="s">
      <tr>
        <td><input type="checkbox" value="${user.id}" id="" name="uid"></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>&nbsp;
          <a class="btn btn-default btn-sm" href="javascript:deleteUser(${user.id});">删除</a>
        </td>
      </tr>
    </c:forEach>
  </table >
  </form>
  <div>
    <nav aria-label="Page navigation">
      <ul class="pagination">
        <c:if test="${pageBean.currentPage==1}">
          <li class="disabled">
        </c:if>

        <c:if test="${pageBean.currentPage!=1}">
          <li>
        </c:if>
          <a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${pageBean.currentPage-1}&rows=5" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
        </li>


        <c:forEach begin="1" end="${pageBean.totalPage}" var="i">
          <c:if test="${pageBean.currentPage==i}">
            <li class="active"><a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${i}&rows=5">${i}</a></li>
          </c:if>

          <c:if test="${pageBean.currentPage!=i}">
            <li><a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${i}&rows=5">${i}</a></li>
          </c:if>
        </c:forEach>

        <c:if test="${pageBean.currentPage!=pageBean.totalPage}">
          <li>
        </c:if>

        <c:if test="${pageBean.currentPage==pageBean.totalPage}">
          <li class="disabled">
        </c:if>
          <a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${pageBean.currentPage+1}&rows=5" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
        <span style="font-size:25px;margin-left:5px">
          共${pageBean.totalCount}条记录,共${pageBean.totalPage}页
        </span>
      </ul>
    </nav>
  </div>


复杂条件查询

分析

image-20220321011712519

代码
findUserByPageServlet
@WebServlet(name = "findUserByPageServlet", value = "/findUserByPageServlet")
public class findUserByPageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");

        //1.获取参数
        String currentPage=request.getParameter("currentPage");//当前页码
        String rows=request.getParameter("rows");//每页显示的条数

        if (currentPage==null||"".equals(currentPage) || Integer.parseInt(currentPage)<=0){
            currentPage="1";
        }

        if (rows==null||"".equals(rows)) {
            rows="5";
        }

        //获取条件查询参数
        Map<String,String[]> condition=request.getParameterMap();

        //2.调用service查询
        UserService service=new UserServiceImpl();
        PageBean<User> pageBean=service.findUserByPage(currentPage,rows,condition);

//        try{
//            PageBean<User> pageBean=service.findUserByPage(currentPage,rows,condition);
//            //3.将pageBean放入request域中
//            request.setAttribute("pageBean",pageBean);
//            //将查询条件存入request域中
//            request.setAttribute("condition",condition);
//
//
//            //4.转发到list.jsp
//            request.getRequestDispatcher("/list.jsp").forward(request,response);
//        }catch (Exception e){
//            request.getRequestDispatcher("/error.jsp").forward(request,response);
//        }

        //3.将pageBean放入request域中
        request.setAttribute("pageBean",pageBean);
        //将查询条件存入request域中
        request.setAttribute("condition",condition);


        //4.转发到list.jsp
        request.getRequestDispatcher("/list.jsp").forward(request,response);
    }
}
UserServiceImpl
public class UserServiceImpl implements UserService {
    private UserDao dao =new UserDaoImpl();
    @Override
    public PageBean<User> findUserByPage(String currentPage, String rows, Map<String, String[]> condition) {

        //创建空的PageBean对象
        PageBean<User> pb = new PageBean<User>();
        //设置参数
        pb.setCurrentPage(Integer.parseInt(currentPage));
        pb.setRows(Integer.parseInt(rows));
        //调用Dao查询总记录数
        int totalCount = dao.findTotalCount(condition);
        pb.setTotalCount(totalCount);

        //计算总页码
        int totalPage = totalCount % pb.getRows() == 0 ? totalCount / pb.getRows() : totalCount / pb.getRows() + 1;
        pb.setTotalPage(totalPage);

        if (pb.getCurrentPage() >= totalPage) {
            pb.setCurrentPage(totalPage);
        }

        //调用Dao查询List集合
        //计算开始的记录索引
        int start = (pb.getCurrentPage() - 1) * pb.getRows();
        List<User> list = dao.findByPage(start, pb.getRows(),condition);
        pb.setList(list);
        
        return pb;
    }
}

UserDaoImpl
public class UserDaoImpl implements UserDao {
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
    @Override
    public int findTotalCount(Map<String, String[]> condition) {
        //1.定义模板初始化sql
        String sql="select count(*) from user 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){
            //排除分页条件参数
            if("currentPage".equals(key) || "rows".equals(key)){
                continue;
            }

            //获取value
            String value=condition.get(key)[0];
            //判断value是否有值
            if(value!=null&&!"".equals(value)){
                //有值
                sb.append(" and "+key+" like ? ");
                params.add("%"+value+"%");//?条件的值
            }
        }

        sql=sb.toString();

        return template.queryForObject(sql,Integer.class,params.toArray());
    }

    @Override
    public List<User> findByPage(int start, int rows, Map<String, String[]> condition) {
        String sql="select * from user 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){
            //排除分页条件参数
            if("currentPage".equals(key) || "rows".equals(key)){
                continue;
            }

            //获取value
            String value=condition.get(key)[0];
            //判断value是否有值
            if(value!=null&&!"".equals(value)){
                //有值
                sb.append(" and "+key+" like ? ");
                params.add("%"+value+"%");//?条件的值
            }
        }

        //3.添加分页查询
        sb.append(" limit ?,?");

        //防止查询结果为空,报错
        if (start<0){
            start=0;
        }

        //添加分页查询参数值
        params.add(start);
        params.add(rows);

        sql=sb.toString();

        List<User> users=template.query(sql,new BeanPropertyRowMapper<User>(User.class),params.toArray());
        return users;
    }
}
list.jsp
<body>
<div class="container">
  <h3 style="text-align: center">用户信息列表</h3>

  <div style="float: left">
    <form class="form-inline" action="${pageContext.request.contextPath}/findUserByPageServlet" method="post">
      <div class="form-group">
        <label for="exampleInputName2">姓名</label>
<%--        查询条件回显--%>
        <input type="text" name="name" value="${condition.name[0]}" class="form-control" id="exampleInputName2" placeholder="李四">
      </div>
      <div class="form-group">
        <label for="exampleInputEmail2">籍贯</label>
        <input type="text" name="address" value="${condition.address[0]}" class="form-control" id="exampleInputEmail2" placeholder="北京">
      </div>
      <div class="form-group">
        <label for="exampleInputEmail3">邮箱</label>
        <input type="text" name="email" value="${condition.email[0]}" class="form-control" id="exampleInputEmail3" placeholder="">
      </div>
      <button type="submit" class="btn btn-default">查询</button>
    </form>
  </div>

  <div>
    <nav aria-label="Page navigation">
      <ul class="pagination">
        <c:if test="${pageBean.currentPage==1}">
          <li class="disabled">
        </c:if>

        <c:if test="${pageBean.currentPage!=1}">
          <li>
        </c:if>
          <a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${pageBean.currentPage-1}&rows=5&name=${condition.name[0]}&address=${condition.address[0]}&email=${condition.email[0]}" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
        </li>


        <c:forEach begin="1" end="${pageBean.totalPage}" var="i">
          <c:if test="${pageBean.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="${pageBean.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="${pageBean.currentPage!=pageBean.totalPage}">
          <li>
        </c:if>

        <c:if test="${pageBean.currentPage==pageBean.totalPage}">
          <li class="disabled">
        </c:if>
          <a href="${pageContext.request.contextPath}/findUserByPageServlet?currentPage=${pageBean.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>
        </li>
        <span style="font-size:25px;margin-left:5px">
          共${pageBean.totalCount}条记录,共${pageBean.totalPage}页
        </span>
      </ul>
    </nav>
  </div>
</div>
</body>
posted @ 2022-03-21 02:50  灰之魔女伊蕾娜  阅读(51)  评论(0)    收藏  举报