5/12day52_mybatis嵌套查询&缓存

MyBatis嵌套查询&缓存.png

回顾

1. 单表高级查询
    resultMap标签:手动映射封装
    多条件查询
        @param("xx")  #{xx}
        User          #{属性名}
    like模糊匹配:concat() 函数拼接
        
2. mapper映射文件深入
    返回主键:<selectKey> select late_insert_id </selectKey>
    动态sql
        if 判断
        where 条件拼接(去掉 前置 and | or)
        set 更新拼接(去掉 后置 ,)
        foreach 循环
            普通list  collection="list"
            普通array collection="array"
            实体list属性 collection="属性名"
    sql片段:抽取公共sql,提高复用性
3. 多表回顾
    数据库表关系:主外键
    实体(模型)关系:属性

4. 多表查询
    一对一
    一对多
    多对多
        看老师发的画图

MyBatis嵌套查询&缓存

今日目标

1. 嵌套查询

2. 加载策略
    立即加载
    延迟加载【讲】
    
3. 缓存:提高查询效率
    一级缓存
    二级缓存
    
4. 回顾核心配置文件常用标签

一 MyBatis嵌套查询

1.1 什么是嵌套查询

嵌套查询就是将原来多表查询中的联合查询语句拆成==多个单表的查询==,再使用mybatis的语法嵌套在一起。

举个栗子

* 需求:查询一个订单,与此同时查询出该订单所属的用户

* 关联查询:
        select * from orders o inner join user u on o.uid = u.id where o.id = 1;
* 缺点:
        sql语句编写难度大
        数据量过大,笛卡尔积数量倍增,可能造成内存溢出
* 嵌套查询:
    1.根据订单id查询订单表
        select * from orders where id = 1;
    2.再根据订单表中uid(外键)查询用户表
        select * from user where id = 订单表uid;
    3.最后由mybatis框架进行嵌套组合
    
* 优点:
        sql语句编写简单
        没有多表关联,不会产生笛卡尔积

环境搭建

1589246911073.png

1.2 一对一==嵌套==查询

需求:查询一个订单,与此同时查询出该订单所属的用户

sql语句

-- 1.根据订单id查询订单表
    select * from orders where id = 1;
-- 2.再根据订单表中uid(外键)查询用户表
    select * from user where id = 41;

① OrderMapper接口

public interface OrderMapper {

    // 一对一嵌套查询
    public Order findByIdWithUser(Integer id);
}

② OrderMapper映射

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.dao.OrderMapper">

    <resultMap id="orderMap" type="cn.itcast.domain.Order">
        <id column="id" property="id"></id>
        <result column="ordertime" property="ordertime"></result>
        <result column="money" property="money"></result>
        <!--通过mybatis嵌套查询user表-->
    </resultMap>

    <!--
        一对一嵌套查询
            resultType:单表映射封装
            resultMap:多表查询必须手动映射封装
    -->
    <select id="findByIdWithUser" parameterType="int" resultMap="orderMap">
        select * from orders where id = #{id};
    </select>
</mapper>

③ UserMapper接口

public interface UserMapper {
    
    // 根据用户id查询user对象
    public User findById(Integer id);
}

④ UserMapper映射

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.dao.UserMapper">

    <!--
        根据用户id查询user对象
    -->
    <select id="findById" parameterType="int" resultType="cn.itcast.domain.User">
        select * from user where id = #{id};
    </select>

</mapper>

⑤ 通过mybatis进行嵌套组合

1589247990774.png

⑥ 测试

public class OrderMapperTest extends BaseMapperTest { // 继承父类,就可以直接使用 父类的方法和成员变量了

    // 一对一嵌套测试
    @Test
    public void test01() throws Exception {
        // 获取代理对象
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);

        // 根据id查询
        Order order = orderMapper.findByIdWithUser(1);
        System.out.println(order);
    }
}
1589247953911.png

⑦ 嵌套关系

1589248264800.png

1.3 一对多嵌套查询

需求:查询一个用户,与此同时查询出该用户具有的订单

sql语句

-- 1. 先根据用户id,查询用户表(一个)
SELECT * FROM USER WHERE id = 41;
-- 2. 再根据用户id,查询订单表(多个)
SELECT * FROM orders WHERE uid = 41;

① UserMapper接口

public interface UserMapper {


    // 一对多嵌套查询
    public User findByIdWithOrders(Integer id);

}

② UserMapper映射

<resultMap id="userWithOrdersMap" type="cn.itcast.domain.User">
    <id column="id" property="id"></id>
    <result column="birthday" property="birthday"></result>
    <result column="username" property="username"></result>
    <result column="sex" property="sex"></result>
    <result column="address" property="address"></result>
    <!--一对多嵌套组合-->
</resultMap>

<!--一对多嵌套查询-->
<select id="findByIdWithOrders" parameterType="int" resultMap="userWithOrdersMap">
    SELECT * FROM USER WHERE id = #{id};
</select>

③ OrderMapper接口

public interface OrderMapper {

    // 根据用户id,查询订单列表
    public List<Order> findByUid(Integer uid);
}

④ OrderMapper映射

<select id="findByUid" parameterType="int" resultType="cn.itcast.domain.Order">
    SELECT * FROM orders WHERE uid = #{uid};
</select>

⑤ 通过mybatis进行嵌套组合

1589249903827.png

⑥ 测试

public class UserMapperTest extends BaseMapperTest {

    // 一对多嵌套查询测试
    @Test
    public void test01() throws Exception {
        // 获取代理
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user = userMapper.findByIdWithOrders(41);

        System.out.println(user);
    }

}
1589249880000.png

⑦ 嵌套关系

1589250191685.png

1.4 多对多嵌套查询(由二个一对多组成)

需求:查询用户同时查询出该用户的所有角色

mybatis的实现方案就是(一对多),区别在于sql语句不同

sql语句

-- 1. 先根据用户id,查询用户表(一个)
SELECT * FROM USER WHERE id = 41;
-- 2. 再根据用户id,查询角色表(多个)
SELECT * FROM role r INNER JOIN user_role ur ON ur.`rid` = r.`id` WHERE ur.`uid` = 41;

① UserMapper接口

public interface UserMapper {

    // 多对多嵌套查询
    public User findByIdWithRoles(Integer id);
}

② UserMapper映射

<resultMap id="userWithRolesMap" type="cn.itcast.domain.User">
    <id column="id" property="id"></id>
    <result column="birthday" property="birthday"></result>
    <result column="username" property="username"></result>
    <result column="sex" property="sex"></result>
    <result column="address" property="address"></result>
    <!-- 多对多嵌套-->
</resultMap>

<!--多对多嵌套查询-->
<select id="findByIdWithRoles" parameterType="int" resultMap="userWithRolesMap">
    SELECT * FROM USER WHERE id = #{id};
</select>

③ RoleMapper接口

public interface RoleMapper {

    // 根据用户id,查询角色列表
    public List<Role> findByUid(Integer id);
}

④ RoleMapper映射

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.dao.RoleMapper">


    <resultMap id="roleResultMap" type="cn.itcast.domain.Role">
        <id column="id" property="id"></id>
        <result column="role_name" property="roleName"></result>
        <result column="role_desc" property="roleDesc"></result>

    </resultMap>

    <!--
        根据用户id,查询角色列表
    -->
    <select id="findByUid" parameterType="int" resultMap="roleResultMap">
        SELECT * FROM role r INNER JOIN user_role ur ON ur.`rid` = r.`id` WHERE ur.`uid` =#{uid}
    </select>
</mapper>

⑤ 通过mybatis进行嵌套组合

1589251531415.png

⑥ 测试

// 多对多测试(根据用户查询角色)
@Test
public void test02()throws Exception{
    // 获取代理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    User user = userMapper.findByIdWithRoles(41);

    System.out.println(user);
}
1589251469136.png

⑦ 嵌套关系

1589251724851.png

1.5 知识小结

* 步骤:一对多举例
    1)先查询(一方)单表
    2)在查询(多方)单表
    3)最后由mybatis嵌套组合


一对一配置:使用<resultMap>+<association>做配置,通过column条件,执行select查询

一对多配置:使用<resultMap>+<collection>做配置,通过column条件,执行select查询

多对多配置:使用<resultMap>+<collection>做配置,通过column条件,执行select查询

优点:1.简化sql语句编写、2.不会产生笛卡尔积

缺点:麻烦...


开发中到底使用哪一种?
    传统开发,数据量小:使用关联查询
    互联网开发,数据量大:使用嵌套查询
        当前也有人这么玩
            在java中先查用户,在查角色,不在使用嵌套....

二 MyBatis加载策略

2.1 什么是加载策略

​ 当多个模型(表)之间存在关联关系时, 加载一个模型(表)的同时, 是否要立即加载其关联的模型, 我们把这种决策成为==加载策略==

​ 如果加载一个模型(表)的时候, 需要立即加载出其关联的所有模型(表), 这种策略称为==立即加载==

​ 如果加载一个模型的时候, 不需要立即加载出其关联的所有模型, 等到真正需要的时候再加载, 这种策略称为==延迟加载(懒加载)==

Mybatis中的加载策略有两种:立即加载和延迟加载, 默认是立即加载

注意:延迟加载是在嵌套查询基础上实现的

* 什么样的场景使用立即加载
    一对一
    
* 什么样的场景使用延迟加载(什么时候用,什么时候查询,提高数据库性能)
    一对多、多对多

2.2 配置延迟加载

2.2.1 全局

SqlMapConfig.xml,设置开启全局延迟加载

<!--全局配置-->
<settings>
    <!--开启延迟(懒)加载  true 开始  false(默认值) 关闭-->
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

2.2.3 局部

mapper映射文件,指定某一个select标签配置

<association></association> 标签
<collection></collection> 标签
    fetchType=""属性
        eager 立即加载
        lazy  延迟加载

注意:局部优先级高于全局的...

2.3 触发(立即)加载

有这样一个全局配置lazyLoadTriggerMethods,它定义的方法会触发立即加载

也就说当你调用它定义的方法时, 会执行数据加载, 它的默认值是equals,clone,hashCode,toString

<!--全局配置-->
<settings>
    <!--开启延迟(懒)加载  true 开始  false(默认值) 关闭-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--触发立即加载的配置
            默认值:equals,clone,hashCode,toString
            value="" 覆盖了默认值,表示在执行上述四个方法时,不会触发立即加载...
            只有在执行get方法获取时,触发数据加载...
        -->
    <setting name="lazyLoadTriggerMethods" value=""/>
</settings>

三 MyBatis缓存

什么是缓存?

服务器内存(硬盘)中的一块区域

为什么使用缓存?

提高查询效率的

什么样的数据适合做缓存?

经常访问但又不经常修改的数据...

缓存是用来提高查询效率的,所有的持久层框架基本上都有缓存机制
Mybatis也提供了缓存策略,分为一级缓存,二级缓存

1589254870618.png

3.1 一级缓存

3.1.1 介绍

MyBatis一级缓存是:SqlSession级别的缓存,默认开启,不需要手动配置


1589201319071.png

3.1.2 验证

需求:根据id查询用户

// 一级缓存测试
@Test
public void test03() throws Exception {
    // 获取sqlSession会话对象
    SqlSession sqlSession = MyBatisUtils.openSession();

    // 获取第一个代理对象
    UserMapper userMapper1 = sqlSession.getMapper(UserMapper.class);
    User user1 = userMapper1.findById(41);// 走数据库
    System.out.println(user1);

    // 清除缓存(自己测试增、删、改)
    sqlSession.clearCache();

    // 获取第二个代理对象
    UserMapper userMapper2 = sqlSession.getMapper(UserMapper.class);
    User user2 = userMapper2.findById(41);// 走缓存(如果上面清除缓存,还是走数据库)
    System.out.println(user2);

    // sqlSession关闭(清除缓存...)
    MyBatisUtils.close(sqlSession);
}

3.1.3 分析

​ 一级缓存是SqlSession范围的缓存,不同的SqlSession之间的缓存区域是互相不影响的,执行SqlSession的C(增加)U(更新)D(删除)操作,或者调用clearCache()、commit()、close()方法,都会清空缓存

1589255593980.png

一级缓存源码

1589256171662.png

3.2 二级缓存【了解】

3.2.1 介绍

​ MyBatis的二级缓存虽然是默认开启的,但需要在映射文件中配置<cache/>标签才能使用,而且要求实体类的必须实现序列化接口

1589202614175.png

3.2.2 验证

mybatis全局配置,默认值就是开启了二级缓存

1589263893048.png

指定需要开启二级缓存的映射配置文件

1589263857841.png

指定User实现序列化接口

1589263995869.png
// 二级缓存
@Test
public void test04() throws Exception {
    // 模拟第一个用户
    SqlSession sqlSession1 = MyBatisUtils.openSession();
    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
    User user1 = userMapper1.findById(41);
    System.out.println(user1);
    sqlSession1.close();

    // 模拟第二个用户
    SqlSession sqlSession2 = MyBatisUtils.openSession();
    UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
    User user2 = userMapper2.findById(41);
    System.out.println(user2);
    sqlSession2.close();

}

3.1.3 分析

​ 二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

二级缓存相比一级缓存的范围更大(按namespace来划分)

1589264629385.png

3.3 知识小结

1564842702588.png
1. mybatis的缓存,都不需要我们手动存储和获取数据。mybatis自动维护的。

2. 使用mybatis,如果是中小型项目,使用自带缓存的机制是可以满足需求的。如果是大型(分布式)项目,mybatis的缓存灵活性不足,需要使用第三方的缓存技术解决问题。

四 核心配置文件回顾

4.1 properties标签

加载外部的properties文件

<properties resource="jdbc.properties"></properties>

4.2 settings标签

全局参数配置

<settings>
    <!--开启懒加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 指定触发延迟加载的方法,只有get方法执行时才会触发立即加载 -->
    <setting name="lazyLoadTriggerMethods" value=""/>
    <!--开启二级缓存 true开启(默认) false关闭-->
    <setting name="cacheEnabled" value="true"/>
</settings>

4.3 typeAliases标签

为 Java 类型设置一个别名

1. 单个定义别名

    <typeAliases>
        <typeAlias type="cn.itcast.domain.User" alias="user"></typeAlias>
    </typeAliases>

1. 使用包的形式批量定义别名

    <typeAliases>
        <package name="cn.itcast.domain"></package>
    </typeAliases>

4.4 mappers标签

加载映射配置

1. 加载指定的src目录下的映射文件,例如:

    <mapper resource="cn/itcast/mapper/UserMapper.xml"/>

1. 加载并扫描指定包下所有的映射文件(接口),例如:

    <package name="cn.itcast.mapper"/>

4.5 environments标签

数据源环境配置

<environments default="mysql">
    <environment id="mysql">
        <!--事务管理器使用JDBC类型-->
        <transactionManager type="JDBC"/>
        <!--数据源使用连接池-->
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
</environments>

老师下午总结

回顾(登陆展示用户列表)

1.环境搭建

1.创建数据库

CREATE TABLE user (
  id INT(11) NOT NULL,
  username VARCHAR(32) DEFAULT NULL,
  password VARCHAR(32) DEFAULT NULL,
  sex VARCHAR(6) DEFAULT NULL,
  email VARCHAR(50) DEFAULT NULL,
  PRIMARY KEY (id),
  KEY email (email)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO user VALUES(1,'admin','123','男','admin@itcast.cn'),(2,'guest','123','男','admin@itcast.cn'),(3,'gouwa','123','男','admin@itcast.cn'),(4,'gousheng','123','男','admin@itcast.cn');
       ```

2.创建模块然后导入对应的jar

导入jar我们需要分析我们要使用到的技术,这个过程应该是你们的项目组长负责

  • mysql的驱动

  • 数据库的连接池

  • jstl

  • Beanutils

    1589269607126.png

3.分包分层

1589269804767.png

4. 导入静态资源文件

1589269869357.png

==注意: 2019&2020版拷贝静态资源的时候经常没有拷贝到out目录中,程序运行的时候是执行out目录的内容==

1589270024992.png

5. 导入工具类(在今天素材里面)

1589270143510.png

6.导入字符过滤器

1589270590593.png
package com.itheima.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//该字符串过滤器要解决全局乱码问题
/*
乱码的分类:
     1. 请求乱码( html页面提交表单数据---servlet --- servlet通过getparameter()方法获取参数的时候是否乱码)
           get请求: 没有
           post请求: 有乱码
     2. 响应乱码     response.getWrite().write("呵呵")  向浏览器输出数据乱码
          不管任何请求方式都会乱码的。
 */
//配置过滤路径
@WebFilter("/*")
public class CharacterEncondingFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
       //1. 强制类型转换 (目的: 是为了使用HttpServletRequest的getmethod方法)
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        //2. 解决response响应乱码问题
        response.setContentType("text/html;charset=utf-8");

        //3. 获取客户请求方式,如果是post请求方式我们需要解决获取请求参数乱码问题
        String method = request.getMethod();
        if("post".equalsIgnoreCase(method)){
            request.setCharacterEncoding("utf-8");
        }

        //解决完毕乱码之后记得要放行
        chain.doFilter(request, response);
    }


    public void destroy() {
    }



    public void init(FilterConfig config) throws ServletException {

    }

}

2.登陆

1.流程分析

1589271149898.png

2.修改login.jsp页面,修改其提交的地址的信息

1589271432614.png

2.编写Userservlet的login方法

package com.itheima.web.servlet;

import com.itheima.domain.User;
import com.itheima.service.UserService;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

@WebServlet("/userServlet")
public class UserServlet extends HttpServlet {

    private UserService userService = new UserService();

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取action,从而得知用户需要调用方法
        String methodName = request.getParameter("action");
        if("login".equalsIgnoreCase(methodName)){
            //登录方法
            login(request,response);
        }else if("list".equalsIgnoreCase(methodName)){
            //展示用户列表
            list(request,response);
        }
    }

    //用户登陆
    protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        try {
            //1. 获取请求参数
            Map<String, String[]> parameterMap = request.getParameterMap();
            //2. 把请求参数封装到user对象中
            User user = new User();
            BeanUtils.populate(user,parameterMap); //把参数封装到user对象中了
            //3.调用userService的login方法,判断是否登陆成功
            boolean isLogin = userService.login(user);
            if(isLogin){
                //4. 登陆成功,设置登陆成功的标记,并且返回首页
                request.getSession().setAttribute("loginUser",user);
                //请求重定向到首页
                response.sendRedirect(request.getContextPath()+"/index.jsp");  // request.getContextPath() 获取模块的根路径
            }else {
                //5. 登陆失败,设置登陆错误的信息,回到login.jsp页面
                request.setAttribute("error","用户名或者密码错误");
                //请求转发到登录页面(这里使用请求转发的原因是因为request域中存储有数据)
                request.getRequestDispatcher("/login.jsp").forward(request,response);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    //展示用户列表
    protected void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


    }

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

3.编写UserService的login方法

package com.itheima.service;

import com.itheima.dao.UserDao;
import com.itheima.domain.User;

public class UserService {

    private UserDao userDao = new UserDao();


    //用户登陆
    public boolean login(User user){
        return userDao.login(user);
    }
}

4.编写UserDao的login方法

package com.itheima.dao;

import com.itheima.domain.User;
import com.itheima.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class UserDao {



    public boolean login(User user) {
        Connection connection = null;
        PreparedStatement pst =null;
        ResultSet rs = null;
        try {
            //1. 通过工具类得到连接
            connection = JdbcUtils.getConnection();
            //2. 准备sql语句得到PreparedStatement
            String sql = "SELECT * FROM USER WHERE username=? AND PASSWORD=?";
             pst = connection.prepareStatement(sql);
            //3. 设置参数
            pst.setObject(1,user.getUsername());
            pst.setObject(2,user.getPassword());

            //4. 执行sql语句,得到结果
             rs = pst.executeQuery();
            //5. 返回结果
            return rs.next();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //6. 关闭资源
            JdbcUtils.close(rs,pst,connection);
        }

        //该语句只是为了让代码不报错,让方法最终有返回值而已
        return false;
    }
}

3.用户展示列表

1.流程分析

1589273051193.png

2.修改index.jsp页面修改连接地址

1589273149885.png

3.编写Userservlet的login方法

@WebServlet("/userServlet")
public class UserServlet extends HttpServlet {

    private UserService userService = new UserService();

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取action,从而得知用户需要调用方法
        String methodName = request.getParameter("action");
        if("login".equalsIgnoreCase(methodName)){
            //登录方法
            login(request,response);
        }else if("list".equalsIgnoreCase(methodName)){
            //展示用户列表
            list(request,response);
        }
    }

  

    //展示用户列表
    protected void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 调用userService的findAll方法得到所有的用户信息
        List<User> list =  userService.findAll();
       //2. 把用户信息存储到request域中
        request.setAttribute("list",list);
        //3. 请求转发到list页面
        request.getRequestDispatcher("/list.jsp").forward(request,response);
    }
}

3.编写UserService的login方法

package com.itheima.service;

import com.itheima.dao.UserDao;
import com.itheima.domain.User;

import java.util.List;

public class UserService {

    private UserDao userDao = new UserDao();



    public List<User> findAll() {
        return userDao.findAll();
    }
}

4.编写UserDao的login方法

package com.itheima.dao;

import com.itheima.domain.User;
import com.itheima.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class UserDao {



    //查询用户列表
    public List<User> findAll() {
        Connection connection = null;
        PreparedStatement pst =null;
        ResultSet rs = null;
        List<User> list = new ArrayList<>();
        try {
            //1. 通过工具类得到连接
            connection = JdbcUtils.getConnection();
            //2. 准备sql语句得到PreparedStatement
            String sql="select * from user";
            pst = connection.prepareStatement(sql);
            //3. 执行sql语句,得到查询的结果
             rs = pst.executeQuery();
            //4. 然后遍历resutset,把遍历结果存储到集合中
            while(rs.next()){
                //每一行数据就是一个用户对象的数据
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                user.setSex(rs.getString("sex"));
                user.setEmail(rs.getString("email"));
                list.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //6. 关闭资源
            JdbcUtils.close(rs,pst,connection);
        }
        return list;
    }
}

5.修改list.jsp的el表达式

1589273912576.png
<%@ 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>
    <!-- 指定字符集 -->
    <meta charset="utf-8">
    <!-- 使用Edge最新的浏览器的渲染方式 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。
    width: 默认宽度与设备的宽度相同
    initial-scale: 初始的缩放比,为1:1 -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>用户信息管理系统</title>

    <!-- 1. 导入CSS的全局样式 -->
    <link href="css/bootstrap.min.css" rel="stylesheet">
    <!-- 2. jQuery导入,建议使用1.9以上的版本 -->
    <script src="js/jquery-2.1.0.min.js"></script>
    <!-- 3. 导入bootstrap的js文件 -->
    <script src="js/bootstrap.min.js"></script>
    <style type="text/css">
        td, th {
            text-align: center;
        }
    </style>
</head>
<body>
<div class="container">
    <h3 style="text-align: center">用户信息列表</h3>
    <table border="1" class="table table-bordered table-hover">
        <tr class="success">
            <th>编号</th>
            <th>姓名</th>
            <th>性别</th>
            <th>邮箱</th>
            <th>操作</th>
        </tr>
     <c:forEach items="${list}" var="user">
        <tr>
            <td>${user.id}</td>
            <td>${user.username}</td>
            <td>${user.sex}</td>
            <td>${user.email}</td>
            <td><a class="btn btn-default btn-sm" href="update.jsp">修改</a>&nbsp;<a class="btn btn-default btn-sm" href="">删除</a></td>
        </tr>
     </c:forEach>
    </table>
</div>
</body>
</html>

4.ajax发送数据

4.1 html&jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <%--1.导入jquery的js--%>
    <script src="${pageContext.request.contextPath}/js/jquery-3.2.1.min.js"></script>
</head>
<body>


<%--//2. 给按钮注册点击事件--%>
<input type="button" value="发送ajax请求" onclick="send()"/><br/>

    用户名:<span id="userName"></span><br/>
    密码:<span id="password"></span><br/>
</body>
<script>

    //需求:点击按钮发送ajax请求,获取到一个User的json对象,然后把用户用户名与密码设置对应的span中
    //3. 发送ajax请求
    function send(){
        $.ajax(
            {
              url:"${pageContext.request.contextPath}/testServlet",  //发送地址
              data:{},  //发送的参数,目前没有参数交给testServlet,所以我留空了。
              type:"get",//请求的方式
              dataType:"json", //服务器返回的数据格式
              success:function(user){  //成功的回调函数
                  $("#userName").html(user.username);
                  $("#password").html(user.password);
              }
            }
        );

    }

</script>

</html>

4.2 servlet接收参数

package com.itheima.web.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.domain.User;

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;

@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        User user = new User();
        user.setUsername("狗娃");
        user.setPassword("123");
        //把对象转发为json
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(user);
        //把json字符串写出
        response.getWriter().write(json);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249