Java基础框架

文章目录

一.JavaWeb servler

1.session

context session cookie的区别

  1. Session和cookie的区别:

    • Cookie是把用户的数据写给用户的浏览器,浏览器保存(可保存多个)
    • Session把用户的数据写到用户独占Session中,服务器端保存(保存重要的信息,减少服务器资源的浪费)
    • Session对象由服务器创建
  2. 使用场景:

    • 保存一个登录用户的信息
    • 购物车信息
    • 在整个网站中经常会使用的数据,我们将它保存在Session中

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. jsp内置对象

  1. 一些内置对象
    在这里插入图片描述

  2. 输出页面前增加的代码
    在这里插入图片描述

  3. jsp语法

 <!-- jsp表达式 在_jspService方法内-->
  <%= 变量表达式 输出%>
  <!-- jsp脚本片段 在_jspService方法内-->
  <% %>
  <!--jsp声明表达式 在类里面-->
  <%! %>
<%--jsp注释不会再客户端显示--%>
page指令
<%@ page errorPage="error/500.jsp" %>//错误页面

<%@ page include %>//提取公共页面

在这里插入图片描述

[11]
在这里插入图片描述

3.拦截器

<form action="/web/login" method="post">
    用户名:<input name="username" type="text">
    提交<input type="submit">
</form>
req.getParameter("username");//获取jsp变量
//servlet之间传值使用session
req.getSession().setAttribute("SEC_ION",req.getSession().getId());
req.getSession().getAttribute("SEC_ION")

4.事务 ACID原则

二.MyBatis

MmyBatis需要掌握的东西

  • JDBC
  • Mysql
  • Java基础
  • Maven
  • Junit

SSM框架:学习配置文件。 最好的方式是查看官方文档

1、简介

1.1、什么是MyBatis

  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了[google code](https://baike.baidu.com/item/google code/2346604),并且改名为MyBatis
  • 2013年11月迁移到Github

如何获得MyBatis?

  • maven仓库

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    
  • 进入 GitHub搜索MyBatis

  • 中文官方文档

1.2、持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程

  • 内存:断电即失

  • 持久化方式: 数据库(jdbc),io文件持久化

1.3、持久层

Dao层,Service层,Controller层

  • 完成持久化工作的代码块
  • 层界限十分明显

1.4、为什么需要MyBatis?

  • 帮助程序员将数据存入到数据库中。
  • 传统的JDBC代码太复杂了,需要简化框架。自动化实现
  • 优点:
    • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
    • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
    • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供xml标签,支持编写动态sql。

2、第一个MyBatis程序

思路: 搭建环境–>导入MyBatis–>编写代码–>测试

2.1、搭建环境

  • 搭建数据库
    在这里插入图片描述
  • 新建项目
  1. 新建一个普通maven项目
  2. 删除src目录,作为父工程
  3. 导入maven依赖
<!--导入依赖-->
    <dependencies>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
    </dependencies>

2.2、创建一个模块

  • 编写mybatis的核心配置文件mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <!--核心配置文件-->
    <configuration>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                        <!--如果使用的是MySQL8.0+,需要增加时区配置serverTimezone-->
                        <!--useUnicode=characterEncoding解决中文乱码问题-->
                        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useLSS=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=GMT%2B8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
    </configuration>
    
  • 编写MyBatis工具类MyBatisUtil.java

    // SqlSessionFactory --> sqlSession
    public class MyBatisUtil {
        private static SqlSessionFactory sqlSessionFactory;
        static {
            try {
                // 使用MyBatis第一步:获取SqlSessionFactory对象
                String resource = "mybatis-config.xml";
                InputStream resourceAsStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        // 既然有了SqlSessionFactory,就可以从中获得SqlSession的实例了
        // SqlSession完全包含了面向数据库执行SQL命令所需的所有方法,相当于connection
        public static SqlSession getSqlSession(){
            return sqlSessionFactory.openSession();
        }
    }
    

2.3、编写代码

  • pojo类

    public class User {
        private int id;
        private String name;
        private String pwd;
    
        public User() {
        }
    
        public User(int id, String name, String pwd) {
            this.id = id;
            this.name = name;
            this.pwd = pwd;
        }
    
        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 getPwd() {
            return pwd;
        }
    
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", pwd='" + pwd + '\'' +
                    '}';
        }
    }
    
  • Dao接口

    public interface UserDao {
        public List<User> getUsers();
    }
    
  • 接口实现类(由原来的Impl转换为Mapper.xml配置文件)

    <!-- 本来Dao层需要组装sql,执行sql,获取结果集 -->
    <!-- 但现在只需要通过Mapper.xml配置几个sql映射文件 -->
    <?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">
    <!-- namespace=绑定一个对应的Dao/Mapper接口,与Impl作用一样 -->
    <mapper namespace="com.jing.dao.UserDao">
        <!-- resultType返回类型,如果是集合,需要写泛型里面的类型,需要全限定名 -->
        <select id="getUsers" resultType="com.jing.dao.UserDao">
            select * from User where id = #{id}
        </select>
    </mapper>
    
  • 测试

    • 问题一、org.apache.ibatis.binding.BindingException: Type interface com.jing.dao.UserDao is not known to the MapperRegistry.

    ​ MapperRegistry注册需要在核心配置文件mybatis-config.xml中注册mappers:

    	<mappers>
            <mapper resource="com/jing/dao/UserMapper.xml"></mapper>
        </mappers>
    
    • 问题二、 Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/jing/dao/UserMapper.xml

      找不到.xml资源 maven到处资源失败,需要在pom中添加如下:

          <build>
              <resources>
                  <resource>
                      <directory>src/main/resources</directory>
                      <includes>
                          <include>**/*.properties</include>
                          <include>**/*.xml</include>
                      </includes>
                      <filtering>true</filtering>
                  </resource>
                  <resource>
                      <directory>src/main/java</directory>
                      <includes>
                          <include>**/*.properties</include>
                          <include>**/*.xml</include>
                      </includes>
                      <filtering>true</filtering>
                  </resource>
              </resources>
          </build>
      
    • 问题三、 Cause: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: 1 字节的 UTF-8 序列的字节 1 无效。

          <!-- 在pom.xml文件中配置 --> 
      	<properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
          </properties>
      
    • 问题四、com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘Use where id = 1’ at line 1 at sun.reflect.NativeConstructor

      SQL不正确,应该是 select * from User where id = 1

    • 问题五、 Mapped Statements collection does not contain value for com.jing.dao.UserDao.getUsers

      // 方式二忘记改UserMapper名字,可见依赖于字符串字面值方式的弊端
      List<User> objects = sqlSession.selectList("com.jing.dao.UserDao.getUsers");
      
  • junit测试

    public class UserDaoTest {
        @Test
        public void test(){
            // 1.获取SqlSession对象
            SqlSession sqlSession = MyBatisUtil.getSqlSession();
    
            //方式一,通过getMapper,UserMapper是 UserDao的实现类,可以直接通过抽象类来获取mapper对象
            // 优势,首先它不依赖于字符串字面值,会更安全一点;其次,如果你的 IDE 有代码补全功能,那么代码补全可以帮你快速选择到映射好的 SQL 语句。
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            // 获取之后就可以执行里面的方法
            List<User> users = mapper.getUsers();
            
            // 方式二
            List<User> objects = sqlSession.selectList("com.jing.dao.UserDao.getUsers");
            
            for (User user : users) {
                System.out.println(user);
            }
    
            // 2.关闭SqlSession
            sqlSession.close();
        }
    }
    

    可能遇到的问题:

    1. 配置文件没有注册;
    2. 绑定接口错误;
    3. 方法名不对;
    4. 返回类型不对;
    5. Maven导出资源问题。

2.4、作用域(Scope)和生命周期

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:

try (SqlSession session = sqlSessionFactory.openSession()) {
  // 你的应用逻辑代码
}

在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。

3、CRUD

1、namespace

namespace=绑定一个对应的Dao/Mapper接口,与Impl作用一样

2、select

选择,查询语句

  • id:就是对应namespace中的方法名
  • resultType:sql执行的返回类型,如果是集合,需要写泛型里面的类型,必须全路径名
  • parameterType=“int”:对应入参类型
  1. 编写接口
User getUsersById(int id);
  1. 编写对应mapper中的sql语句
    <select id="getUsersById" resultType="com.jing.pojo.User" parameterType="int">
        select * from User where id = #{id};
    </select>
  1. 测试
  		// 1.获取SqlSession对象
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        // 2.通过getMapper,UserMapper是 UserDao的实现类,可以直接通过抽象类来获取mapper对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUsersById(1);
        System.out.println(user);
        // 3.关闭SqlSession
        sqlSession.close();
3、insert
    <insert id="insertUser" parameterType="com.jing.pojo.User">
        insert into User (id,name,pwd) values (#{id},#{name},#{pwd});
    </insert>
4、update
<update id="updateUser" parameterType="user">
    update User set name = #{name} where id = #{id};
</update>
5、delete
<delete id="deleteUser" parameterType="int">
    delete from User where id = #{id};
</delete>

注意:增删改需要提交事务,结束需要关闭sqlSession

// 需要提交事务
sqlSession.commit();
// 关闭sqlSession
sqlSession.close();
6、万能的map

假设我们的实体类或者数据库中的表字段太多,可以考虑使用map

int insertUser2(Map<String, Object> map);
<!--对象中的属性可以直接取出来 传递map的key-->
<insert id="insertUser2" parameterType="map">
    insert into User (id,name,pwd) values (#{userId},#{name},#{pwd});
</insert>

Map传递参数,直接在sql中取出key即可

对象传递参数,直接在sql中取出对象属性即可

只有一个基本参数类型的情况下,可以直接在sql中取到

多个参数用Map或者注解

7、思考

模糊查询怎么写?

  1. Java代码执行的时候,传递通配符 %,会造成sql注入

    List<User> users = mapper.getUsersLike("%狗%");
    
  2. 在sql中拼接%

    <select id="getUsersLike" resultType="user">
        select * from mybatis.user where name like "%"#{name}"%"
    </select>
    

4、配置解析

1、核心配置文件
  • mybatis-config.xml

  • MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

    官方文档

configuration(配置)
    properties(属性)
    settings(设置)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境配置)
    environment(环境变量)
    transactionManager(事务管理器)
    dataSource(数据源)
    databaseIdProvider(数据库厂商标识)
    mappers(映射器)
2、环境配置(environments)

MyBatis 可以配置成适应多种环境

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

MyBatis 默认的事务管理器是JDBC, 连接池POOLED

3、属性(properties)

我们可以通过properties属性来实现引用配置文件

这些属性可以在外部进行配置,并可以进行动态替换。既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties】

在xml中所有的标签都有规定的位置
在这里插入图片描述

编写一个配置文件db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useLSS=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
username=root
password=123456

在配置文件中映入

<properties resource="db.properties">
    <property name="password" value="111111"/>
</properties>
  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一个字段,优先使用外部配置文件的
4、类型别名(typeAliases)
  • 类型别名可为 Java 类型设置一个缩写名字。意在降低冗余的全限定类名书写。
<typeAliases>
    <typeAlias alias="user" type="com.jing.pojo.User">		</typeAlias>
</typeAliases>
  • 也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean
<!--扫描实体类的包,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。-->
<typeAliases>
  <package name="com.jing.pojo"/>
</typeAliases>
//若有注解,则别名为其注解值
@Alias("user")
public class User {
    ...
}
5、设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

在这里插入图片描述

一个配置完整的 settings 元素的示例如下:

<settings>
  <setting name="cacheEnabled" value="true"/>缓存
  <setting name="lazyLoadingEnabled" value="true"/>延迟加载
  <setting name="multipleResultSetsEnabled" value="true"/>是否允许单个语句返回多结果集,需要数据库驱动支持
  <setting name="useColumnLabel" value="true"/>使用列标签代替列名
  <setting name="useGeneratedKeys" value="false"/>允许 JDBC 支持自动生成主键,需要数据库驱动支持
  <setting name="autoMappingBehavior" value="PARTIAL"/>指定MyBatis应如何自动映射列到字段或属性
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>指定发现自动映射目标未知列(或未知属性类型)的行为
  <setting name="defaultExecutorType" value="SIMPLE"/>配置默认的执行器
  <setting name="defaultStatementTimeout" value="25"/>设置超时时间
  <setting name="defaultFetchSize" value="100"/>为驱动的结果集获取数量(fetchSize)设置一个建议值
  <setting name="safeRowBoundsEnabled" value="false"/>指定语句默认的滚动策略
  <setting name="mapUnderscoreToCamelCase" value="false"/>是否允许在嵌套语句中使用分页(RowBounds)
  <setting name="localCacheScope" value="SESSION"/>MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询
  <setting name="jdbcTypeForNull" value="OTHER"/>当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>指定对象的哪些方法触发一次延迟加载
6、其他配置
7、映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件

方式一:【推荐使用】

    <mappers>
		<mapper resource="com/jing/dao/UserDao.xml"/>
    </mappers>

方式二:使用class文件绑定注册

<mappers>
    <mapper class="com.jing.dao.UserDao"/>
</mappers>

注意点:

  • 接口和它的Mapper配置文件必须同名
  • 接口和它的Mapper配置文件必须在同一个包下

方式三:使用扫描包进行注入绑定

    <mappers>
	    <package name="com.jing.dao"/>
    </mappers>

注意点:

  • 接口和它的Mapper配置文件必须同名

  • 接口和它的Mapper配置文件必须在同一个包下

8、作用域(Scope)和生命周期

在这里插入图片描述

作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题

SqlSessionFactoryBuilder:

  • 一旦创建了 SqlSessionFactory,就不再需要它了
  • 最佳作用域是方法作用域(也就是局部方法变量)

SqlSessionFactory:

  • 可以想象为数据库连接池
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
  • SqlSessionFactory 的最佳作用域是应用作用域。最简单的就是使用单例模式或者静态单例模式。

SqlSession:

  • 可以看作是连接到连接池的一个请求
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域
  • 用完之后需要赶紧关闭,否则资源被占用
    在这里插入图片描述

这里面的每一个Mapper就代表一个具体的业务

5、解决属性名和字段名不一致的问题

  1. 问题

数据库中的字段

在这里插入图片描述

新建一个项目,拷贝之前的,测试实体类字段不一致的情况

public class User {
    private String 密码;
    private String 暗杀事件;
    private int id;
}

测试结果:对应不上的按照字段的先后顺序对应

在这里插入图片描述

 select * from User where id=#{id}
-- 类处理器
 select id,name as 暗杀事件,pwd from User where id=#{id}

解决方法:

  • 取别名

    -- 类处理器
     select id,name,pwd as 密码 from User where id=#{id}
    
  1. resultMap

    结果集映射

    id name    pwd
    id 暗杀事件 密码
    
    <resultMap id="userMap" type="usera">
        <result column="name" property="暗杀事件"/>
        <result column="pwd" property="密码"/>
    </resultMap>
    <select id="getUserById" resultMap="userMap">
        select * from User where id=#{id}
    </select>
    
  • resultMap 元素是 MyBatis 中最重要最强大的元素
  • resultMap 的设计思想是,对于简单的语句根本不需要配置现实的结果映射,而对于复杂一点的语句只需要描述他们的关系就行了
  • resultMap 最优秀的地方在于,虽然你已经对他相当了解了,但是根本就不需要显示的用到他们

6、日志

1、日志工厂

如果一个数据库操作出现了异常,我们需要排错,日志就是最好的助手

以前的方法:sout、debug

现在使用:日志工厂

在这里插入图片描述

  • SLF4J
  • LOG4J 【√】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING【标准日志输出】
  • NO_LOGGING
    <settings>
		<!--开启标准日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

在这里插入图片描述

2、Log4j

什么是Log4j

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
  • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
  1. 先导入log4j的包

            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
    
  2. log4j.properties

    # 将等级为DEBUG的日志信息输出到console,file这两个目的地
    log4j.rootLogger=DEBUG,console,file
    
    ### 配置输出到控制台 ###
    log4j.appender.console = org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target = System.out
    log4j.appender.console.Threshold = DEBUG
    log4j.appender.console.layout = org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern = %p %d{yyyy-MM-dd HH:mm:ss} %c %m %n 
    
    ### 配置输出到文件 ###
    log4j.appender.file = org.apache.log4j.RollingFileAppender
    log4j.appender.file.File = ./log/jing.log
    log4j.appender.file.MaxFileSize = 10mb
    log4j.appender.file.Threshold = DEBUG
    log4j.appender.file.layout = org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern = %p %d{yyyy-MM-dd HH:mm:ss} %m %n 
    
    ### 日志输出级别 ###
    log4j.logger.org.mybatis = DEBUG
    log4j.logger.java.sql = DEBUG
    log4j.logger.java.sql.Statement = DEBUG
    log4j.logger.java.sql.ResultSet = DEBUG
    log4j.logger.java.sql.PreparedStatement = DEBUG
    
  3. 配置log4j为日志的实现

        <settings>
            <setting name="logImpl" value="LOG4J"/>
        </settings>
    
  4. 测试运行

在这里插入图片描述

简单使用

  1. 在要使用的类中导入包import org.apache.log4j.Logger;

  2. 日志对象,参数为当前类的class

    static Logger logger = Logger.getLogger(String.valueOf(UserUserTest.class));
    
  3. 日志级别

    logger.info( "info:UserUserTest.test" );
    logger.debug( "debug:UserUserTest.test" );
    logger.error( "error:UserUserTest.test" );
    
  4. 打印

在这里插入图片描述

7、分页

为什么要分页?

  • 减少数据处理量
1、使用Limit分页
select * from user limit 0,2(0开始查询2)
select * from user limit 3,-1(3开始查询到最后一个,这是个bug,已被修复)
select * from user limit 3(0开始到3)

使用MyBatis实现分页

  1. 接口

    List<Usera> getUserByLimit(Map<String, Integer> map);
    
  2. Mapper.xml

    <select id="getUserByLimit" parameterType="map"(可以不用写) resultMap="userMap">
        select * from User limit #{startIndex},#{pageSize}
    </select>
    
  3. 测试

    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String,Integer> map = new HashMap();
    map.put("startIndex",2);
    map.put("pageSize",4);
    
    List<Usera> users = mapper.getUserByLimit(map);
    for (Usera user : users) {
        logger.debug( "debug:UserUserTest.test1" + user);
    }
    sqlSession.close();
    
2、使用RowBounds实现
RowBounds rowBounds = new RowBounds(2, 4);
List<Usera> users = sqlSession.selectList("com.jing.dao.UserMapper.getUserByRowBounds", null, rowBounds);
3、分页插件

pagehelper,mybatis中经典的分页插件的使用方法

  1. 引入分页插件
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.0</version>
</dependency>
  1. 添加配置拦截器插件

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <property name="helperDialect" value="sqlite"/>
        </plugin>
    </plugins>
    
  2. 在代码中使用

    PageHelper.startPage(2, 3);
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Page<Usera> users = mapper.getUserByPageHelper();
    logger.info("第几页:" + users.getPageNum());
    logger.info("每页数量:" + users.getPageSize());
    logger.info("总页数:" + users.getPages());
    logger.info("总记录数:" + users.getTotal());
    for (Usera user : users) {
        logger.info("查询结果:" + user);
    }
    sqlSession.close();
    
  3. 测试结果

在这里插入图片描述

8、使用注解查询

java代码

@Select("select * from teacher where id=#{tid}")
List<Teacher> getTeachers(@Param("tid") int id);

Mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--核心配置文件只需要声明命名空间-->
<mapper namespace="com.jing.dao.TeacherMapper">
</mapper>

9、多对一处理

测试环境搭建

  1. 导入lombak
  2. 新建实体类 Teacher,Student
  3. 建立Mapper接口
  4. 建立Mapper.xml
  5. 在核心配置文件中绑定注册我们的Mapper接口或者文件
  6. 测试查询结果

按照查询嵌套处理

<!--核心配置文件-->
<mapper namespace="com.jing.dao.StudentMapper">
<!--    思路
        1. 查询出所有学生
        2. 根据学生的tid查询对应老师
-->
    <select id="getStudents" resultMap="studentMap">
        select * from student
    </select>
    <resultMap id="studentMap" type="student">
        <!-- 复杂属性处理:  对象:association 集合:collection-->
        <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
    </resultMap>
    <select id="getTeacher" resultType="teacher">
        select * from teacher where id=#{tid}
    </select>
</mapper>

按照结果嵌套处理

<!-- 需要每一项都对应上,否则是默认值,0或null -->
<resultMap id="studentTeacherMap" type="student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="teacher">
        <result property="name" column="tname"></result>
        <result property="id" column="tid"></result>
    </association>
</resultMap>

<select id="getStudents2" resultMap="studentTeacherMap">
    select a.id as sid,a.name as sname,b.name as tname from student a,teacher b where a.tid=b.id
</select>

10、一对多处理

按照结果嵌套处理

<resultMap id="teacherStudentMap" type="teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <collection property="studentList" column="sid" ofType="student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
    </collection>
</resultMap>
<select id="getTeacherById" resultMap="teacherStudentMap">
    select t.id as tid,t.name as tname,s.id as sid,s.name as sname from teacher t,student s where t.id=#{tid} and t.id=s.tid
</select>

按照查询嵌套处理

<resultMap id="teacherStudent2" type="teacher">
    <collection property="studentList" column="id" javaType="ArrayList" ofType="student" select="getStudentByTid"/>
</resultMap>
<select id="getTeacherById2" resultMap="teacherStudent2">
    select * from teacher where id=#{tid}
</select>
<select id="getStudentByTid" resultType="student">
    select * from student where tid = #{id}
</select>

小结

  1. 关联 - association【多对一】
  2. 集合 - collection 【一对多】
  3. javaType & ofType
    • javaType 用来指定实体类中属性的类型
    • ofType 用来指定映射到list或者集合中的pojo类型

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段的问题
  • 如果问题不好排查错误,可以使用日志,建议使用Log4j
结果映射(resultMap)
  • constructor- 用于在实例化类时,注入结果到构造方法中
    • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
    • arg - 将被注入到构造方法的一个普通结果
  • id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
  • result – 注入到字段或 JavaBean 属性的普通结果
  • association– 一个复杂类型的关联;许多结果将包装成这种类型
    • 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
  • collection– 一个复杂类型的集合
    • 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
  • discriminator– 使用结果值来决定使用哪个 resultMap
    • case– 基于某些值的结果映射
      • 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射

11.mybatis的缓存机制:

1. 一级缓存和二级缓存的区别

(镶嵌点:)Sqlsession(接口)的底层是hashmap存储,线程不安全,sqlsessionTemplate是其实现类线程安全的

区别:一级缓存的作用域是一个sqlsession内;二级缓存作用域是针对mapper进行缓存.

一级缓存:

1、第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。

2、如果中间sqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

3、第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

小结:一级缓存时执行commit,close,增删改等操作,就会清空当前的一级缓存;当对SqlSession执行更新操作(update、delete、insert)后并执行commit时,不仅清空其自身的一级缓存(执行更新操作的效果),也清空二级缓存(执行commit()的效果)。

二级缓存:

不管是不是相同的session,只要mapper的namespace相同,可能共享缓存,要求:如果开启了二级缓存,那么在关闭sqlsession后(close),才会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。

开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中

那么在 同一个session下,执行同一个select语句时,Cache Hit Ratio [Mapper]: 0.0,二级缓存的命中率为0那?

答:这里要讲解一下二级缓存的缓存什么时候存入了:只有当当前的session.close()时,该session的数据才会存入二级缓存.在同一session下时,肯定没有执行.close()关闭session,自然也就没有存入二级缓存.第二次执行却没有重新发送sql语句,是因为第二次调用的是一次缓存中的数据.

如果想让二级缓存命中率不为0,需要先开启一个session,执行一个sql语句,然后关闭该session,然后在创建一个新的session,执行相同的sql语句,这时,二级缓存才会命中

2. 开启二级缓存:

1.开启全局缓存,默认开启

<settings>
    <!--默认开启状态,这里显示开启-->
    <setting name="cacheEnabled" value="true"/>
    <!-- 记得开启日志,开启标准日志-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

2.在Mapper中开启缓存

<cache/>

3.注意

需要将实体类序列化

开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中

Caused by: java.io.NotSerializableException: com.jing.pojo.Teacher

序列化

@Data
public class Teacher implements Serializable {
    private int id;
    private String name;
}

3.缓存原理

在这里插入图片描述

三.spring

1.IOC(控制反转),DI(依赖注入)

1.IOC和DI是什么?

IoC,控制反转,即放弃已有的控制权,交由上层来控制。
站在Java的角度就是方法不再决定使用哪个组件来完成功能,而是交由调用者决定。
DI,依赖注入,对于IoC更为直观的描述。

简单的说,IoC,我位低权轻,只干事,不决策,还是让老大来拍板吧。

2.使用IoC

所以我们不让MessageService来决定使用那个实现类了,你只要专心提供服务就行了,将决定权交给调用者,这就是IoC。我们把代码改进一下:

public class MessageService{
  private Operator operator;

  public void setOperator(Operator operator){
    this.operator = operator;
  }

  public Message dealMessage(){
    //operator由外部传入
    return this.operator.operate();  
  } 
}

采用面向接口编程,提供一个set方法,将实现类传进来,从数据库读就传DBOperator,从文件读就传FileOperator,要测试就传TestOperator。实现解耦,灵活替换,又方便测试。

3.以滴滴平台例子解释

以滴滴平台为例子:我作为打车端的会员,司机作为司机端的会员司机。

我有坐车的需求,告诉滴滴平台我什么时间点需要什么样子的车,滴滴平台召集司机端的司机,根据我需要的要求分配一辆车给我。 这样子就很好解释Ioc,滴滴平台做为Ioc,我和司机就是Ioc的对象或bean。

4.升级IoC

IoC的思想是有了,但总是由调用者来执行setXXX(),代码分散在"世界各地",咱能不能把set的工作都统一到一个地方来搞呢?
整一个xml,在里面来配置所有要用的bean;解析xml,反射创建bean,在需要用的地方通过反射set bean;controller用到了service,service用到了dao,那就倒着创建bean,直接把依赖关系统统搞定;想对bean搞点事情,把bean包装一下(AOP),设置bean在特殊状态下的行为(init/后置处理器/destory)等等。

所有这一切统统交由容器来实现,它帮我们统一创建bean,管理bean,暴露各种接口让我们随时干预bean。至此,IoC成熟落地了。

有了容器,我们可以更专注于业务逻辑的开发,容器会将我们需要的组件注射到应用程序中,我们对这一套重新起了一个更形象的名字:DI(依赖注入)。

2.注解

使用注解需要添加

<beans xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"/>
<context:annotation-config/>
@Autowired//也可以在set上使用,使用Autowired可以省略set,前提是ioc容器中存在,且符合名字byName
@Resource//java的注解
@Autowired和@Resource的区别
  1. 都是用来自动装配的,都可以放在属性上
  2. Autowired先通过byType装配, @Qulifier(value="")
  3. Resource先name后byType (naem="")

3.AOP切面

1.代理模式
  1. 接口

  2. 实现类

  3. 编写动态生成代理类的处理器

    public class ProxyInvocationHandler implements InvocationHandler {
        //被代理的接口
        private Object target;
        public void setTarget(Object target) {
            this.target = target;
        }
    
        //生成代理类
        public Object getProxy(){
             return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
        }
    
        //生成代理实例
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //动态代理的本质,就是使用反射机制实现
            log(method.getName());
            Object result = method.invoke(target, args);
            return result;
        }
    
        public void log(String methodName){
            System.out.println("执行"+methodName+"方法");
        }
    }
    
  4. 测试

    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();
    
        //代理角色,现在没有
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
    
        //通过调用程序处理角色来处理我们要调用的接口对象
        pih.setTarget(userService);
    
        UserService proxy = (UserService) pih.getProxy();//这里的proxy就是动态生成的
        proxy.delete();
    }
    
2.AOP的实现
方式一
<!--方式一-->
<aop:config>
    <!--切入点-->
    <aop:pointcut id="pointcut" expression="execution(* com.jing.demo1.UserServiceImpl.*(..))"/>
    <!--执行环绕增加-->
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
</aop:config>

通过实现AOP接口方式

public class BeforeLog implements MethodBeforeAdvice {

    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行了");

    }
}


public class AfterLog implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,执行结果为"+returnValue);
    }
}
方式二
<!--方式二-->
<aop:config>
    <aop:aspect ref="diy">
       <!--切入点-->
        <aop:pointcut id="pointcut" expression="execution(* com.jing.demo1.UserServiceImpl.*(..))"/>
        <!--通知-->
        <aop:after method="after" pointcut-ref="pointcut"/>
        <aop:before method="before" pointcut-ref="pointcut"/>
    </aop:aspect>
</aop:config>
方式三
<bean id="annotationPiontCut" class="com.jing.diy.AnnotationPiontCut"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>

添加注解

@Aspect//标注这个类是一个切面
public class AnnotationPiontCut {
    @Before("execution(* com.jing.demo1.UserService.*(..))")
    public void before(){
        System.out.println("=====方法执行前=====");
    }
    @After("execution(* com.jing.demo1.UserService.*(..))")
    public void after(){
        System.out.println("=====方法执行后=====");
    }
    //在环绕增强中,我们给定一个参数,代表我们要获取处理切入的点
    @Around("execution(* com.jing.demo1.UserService.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        jp.proceed();//执行方法
        System.out.println("环绕后");

        //获取签名,执行方法的一些信息
        Signature signature = jp.getSignature();
        System.out.println("signature:"+signature);
    }
}

4.spring整合mybatis

方式一

1.使用spring的数据源替换mybatis的配置

<!--DataSource使用spring的数据源替换mybatis的配置
使用spring提供的jdbc: org.springframework.jdbc.datasource-->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=GMT%2B8"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean>

2.注入sqlSessionFactory

<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="datasource"/>
    <!--绑定mybatis配置文件-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <!--也可以放到mybatis配置文件中-->
    <property name="mapperLocations" value="classpath:com/jing/mapper/*.xml"/>
</bean>

3.注入SqlSessionTemplate

<!--SqlSessionTemplate:就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <!--只能使用构造器注入,因为它没有set方法-->
    <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>

4.编写实现类

//在之前我们所有的操作都是使用sqlSession来执行
//现在都是用SqlSessionTemplate;
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
    this.sqlSession = sqlSession;
}
public List<User> getUsers() {
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    return mapper.getUsers();
}

5.注入实现类到bean

<!--注入sqlSession-->
<bean id="userMapperImpl" class="com.jing.mapper.UserMapperImpl">
    <property name="sqlSession" ref="sqlSession"/>
</bean>

6.测试

ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
UserMapper userMapper = context.getBean("userMapperImpl", UserMapper.class);
for (User user : userMapper.getUsers()) {
    System.out.println(user);
}
方式二

继承SqlSessionDaoSupport,里面会生成getSqlSession,可以直接获取

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{

    public List<User> getUsers() {
        return getSqlSession().getMapper(UserMapper.class).getUsers();
    }
}

将接口注入bean,注入参数sqlSessionFactory

<bean id="userMapperImpl2" class="com.jing.mapper.UserMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

四、springMVC

1. springMVC流程图

在这里插入图片描述

2. springMVC执行流程一(配置版)

在这里插入图片描述

3. springMVC具体实现步骤

  1. web.xml
  • 注册DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 1.注册DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--关联一个springmvc的配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!--启动级别为1-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!--/匹配所有的请求(不包括.jsp)-->
    <!--/*匹配所有的请求(包括.jsp)-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  1. 配置springmvc-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
        <!--视图解析器:DispatcherServlet给她的ModelAndView-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
            <!--前缀-->
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <!--后缀-->
            <property name="suffix" value=".jsp"/>
         </bean>
    
        <bean id="/hello" class="com.jing.controller.HelloController"/>
    </beans>
    
  2. Controller

    //注意:这里我们先导入Controller接口
    public class HelloController implements Controller {
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
            //模型和视图
            ModelAndView mv = new ModelAndView();
            //封装对象,放到ModelAndView中
            mv.addObject("msg","HelloSpringMVC!");
            //封装要跳转的视图,方在ModelAndView中
            mv.setViewName("hello");//: /WEB-INF/jsp/hello.jsp
            return mv;
        }
    }
    

4. 404解决方案

在这里插入图片描述

在这里插入图片描述

5. springMVC执行流程一(注解版)

在这里插入图片描述

6. 过滤器解决乱码

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>encoding</filter-name>
    <!--过滤所有资源包括.jsp-->
    <url-pattern>/*</url-pattern>
</filter-mapping>

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

前端:bootstrap可视化工具

在这里插入图片描述

前端化工程:SSM+Vue+BootStrap

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值