Mybatis
1、简介
1.1、什么是MyBatis
- MyBatis是一款优秀的持久层框架
- 它支持定制化SQL、存储过程以及高级映射。
- MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。
- MyBatis可以使用简单的XML或注解来配置和映射原生类型、接口和Java的POJO(Plain Old Java Object,普通老式Java对象)为数据库中的记录。
- MyBatis本是apache的一个开源项目IBatis,2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis。
- 2013年11月迁移到Github。
1.2、如何获得MyBatis?
- Github:Search · mybatis · GitHub
- 中文文档:GitHub - tuguangquan/mybatis: mybatis源码中文注释
- Maven仓库:
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
1.3、持久化
数据持久化
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程。
- 内存:断电即失
- 数据库(JDBC)、IO文件持久化。
1.4、持久层
Dao层、service层、servlet层…
- 完成持久化工作的代码块
- 层界限十分明显
1.5、为什么要学MyBatis?
- 帮助程序员将数据存入到数据库中。
- 传统的JDBC代码太复杂。简化、框架、自动化。
- 更容易上手。
1.6、优点
- 简单易学
- 灵活
- sql和代码的分离,提高了可维护性
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql
2、第一个Mybatis程序
思路:搭建环境–>导入Mybatis–>编写代码–>测试!
2.1、搭建环境
2.1.1、搭建数据库
create database mybatis;
use mybatis;
create table user(
id int primary key,
username varchar(32),
password varchar(32)
)ENGINE=INNODB default charset=utf8;
insert into user values
(1,'zzl','123456'),
(2,'lll','123456'),
(3,'zkw','123456');
2.1.2、新建项目
- 新建一个普通的maven项目
- 删除src目录
- 导入maven依赖
<!-- 创建父工程-->
<groupId>com.zzl</groupId>
<artifactId>Mybatis-Study</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>mybatis-day01</module>
</modules>
<!-- 导入依赖-->
<dependencies>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<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>
2.2、创建一个模块
- 编写mybatis的核心配置文件
<!--configuration核心配置文件-->
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/zzl/dao/userMapper.xml"/>
</mappers>
</configuration>
- 编写mybatis工具类
public class MybatisUtils {
static SqlSessionFactory sqlSessionFactory= null;
static{
try {
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
sqlSessionFactory= new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
2.3、编写代码
- 实体类
package com.zzl.domain;
public class User {
private int id;
private String username;
private String password;
public User() {
}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
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;
}
}
- Dao接口
public interface userDao {
List<User> getUser();
}
- 接口实现类
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.zzl.dao.userDao">
<!-- select查询语句-->
<select id="getUser" resultType="com.zzl.domain.User">
select * from mybatis.user;
</select>
</mapper>
- 注意:Mapper配置文件和mybatis-config.xml中字符集编码为UTF8
3、CRUD
3.1、namespace
- namespace中的包名要和Dao/Mapper接口的包名一致
3.2、select、update、insert、delete
增删改查语句;
- id:就是对应的namespace中的方法名;
- resultType:sql语句执行的返回值
- parameterType:参数类型
- 注意:增删改需要提交事务
<mapper namespace="com.zzl.dao.UserMapper">
<!-- select查询语句-->
<select id="getUserList" resultType="com.zzl.domain.User">
select * from user
</select>
<select id="getUserById" parameterType="int" resultType="com.zzl.domain.User">
select * from user where id = #{id}
</select>
<insert id="insertUser" parameterType="com.zzl.domain.User">
insert into user (id,username,password) values (#{id},#{username},#{password})
</insert>
<update id="updateUser" parameterType="com.zzl.domain.User">
update user set username = #{username},password = #{password} where id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<select id="getUsers" parameterType="String" resultType="com.zzl.domain.User">
select * from user where username like "%"#{value}"%"
</select>
</mapper>
3.3、万能的Map
-
当实体类或者数据库中的表、字段或者参数较多时,可以考虑使用Map
-
Map传递参数,直接在SQL中取出key即可
-
对象传递参数,直接在SQL中取出对象的属性即可
-
只有一个基本类型参数的情况下,可以直接在SQL中取到
-
多个参数用Map或者注解
4、配置解析
4.1、核心配置文件
- mybatis-config.xml
- MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
4.2、环境配置(environments)
MyBatis 可以配置成适应多种环境,但每个 SqlSessionFactory 实例只能选择一种环境。
学会使用配置多套运行环境!
Mybatis默认的事务管理器就是JDBC,连接池:POOLED
4.3、属性(properties)
我们可以通过properties属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。
编写一个配置文件
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8
username=root
password=123456
在核心配置文件中引入
<configuration>
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/zzl/dao/UserMapper.xml"/>
</mappers>
</configuration>
- 可以直接引入外部文件
- 可以在其中增加一些属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件的值!
4.4、类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
<typeAliases>
<!-- 给实体类起别名-->
<typeAlias type="com.zzl.domain.User" alias="User"/>
<!-- 给包起别名-->
<package name="com.zzl.domain"/>
</typeAliases>
如果实体类比较少,使用第一种方式
如果实体类比较多,建议使用第二种
第一种可以DIY别名,第二种不行,但是可以在实体类上增加注解
@Alias("hello")
public class User {}
4.5、映射器(mappers)
MapperRegistry:注册绑定我们的Mapper文件;
方式一:
<!-- 每一个Mapper.xml文件都需要在核心配置文件里注册-->
<mappers>
<mapper resource="com/zzl/dao/UserMapper.xml"/>
</mappers>
方式二:使用class文件绑定注册
<!-- 每一个Mapper.xml文件都需要在核心配置文件里注册-->
<mappers>
<mapper class="com.zzl.dao.UserMapper"/>
</mappers>
注意点:
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须在同一个包下
方式三:使用扫描包进行注入绑定
<!-- 每一个Mapper.xml文件都需要在核心配置文件里注册-->
<mappers>
<package name="com.zzl.dao"/>
</mappers>
注意点:
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须在同一个包下
4.6、作用域(Scope)和生命周期
理解我们目前已经讨论过的不同作用域和生命周期类是至关重要的,因为错误的使用会导致非常严重的并发问题。
我们可以先画一个流程图,分析一下Mybatis的执行过程!
作用域理解
- SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
- **SqlSessionFactory 可以被认为是一个数据库连接池,**它的作用是创建 SqlSession 接口对象。因为 MyBatis 的本质就是 Java 对数据库的操作,所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用,所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。
- 由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。
- 因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是应用作用域。
- 如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try…catch…finally… 语句来保证其正确关闭。
- 所以 SqlSession 的最佳的作用域是请求或方法作用域。
4.7 resultMap结果集映射
要解决的问题:属性名和字段名不一致
环境:新建一个项目,将之前的项目拷贝过来
1、查看之前的数据库的字段名
2、Java中的实体类设计
public class User {
private int id; //id
private String name; //姓名
private String password; //密码和数据库不一样!
//构造
//set/get
//toString()
}
3、接口
//根据id查询用户
User selectUserById(int id);
4、mapper映射文件
<select id="selectUserById" resultType="user">
select * from user where id = #{id}
</select>
5、测试
@Test
public void testSelectUserById() {
SqlSession session = MybatisUtils.getSession(); //获取SqlSession连接
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
session.close();
}
结果:
- User{id=1, name=‘狂神’, password=‘null’}
- 查询出来发现 password 为空 . 说明出现了问题!
分析:
-
select * from user where id = #{id} 可以看做
select id,name,pwd from user where id = #{id}
-
mybatis会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写) , 去对应的实体类中查找相应列名的set方法设值 , 由于找不到setPwd() , 所以password返回null ; 【自动映射】
解决方案
方案一:为列名指定别名 , 别名和java实体类的属性名一致 .
<select id="selectUserById" resultType="User">
select id , name , pwd as password from user where id = #{id}
</select>
方案二:使用结果集映射->ResultMap 【推荐】
<resultMap id="UserMap" type="User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="selectUserById" resultMap="UserMap">
select id , name , pwd from user where id = #{id}
</select>
ResultMap
自动映射
resultMap
元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBCResultSets
数据提取代码中解放出来。- 实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份
resultMap
能够代替实现同等功能的长达数千行的代码。 - ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。
你已经见过简单映射语句的示例了,但并没有显式指定 resultMap
。比如:
<select id="selectUserById" resultType="map">
select id , name , pwd
from user
where id = #{id}
</select>
上述语句只是简单地将所有的列映射到 HashMap
的键上,这由 resultType
属性指定。虽然在大部分情况下都够用,但是 HashMap 不是一个很好的模型。你的程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为模型。
ResultMap
最优秀的地方在于,虽然你已经对它相当了解了,但是根本就不需要显式地用到他们。
手动映射
1、返回值类型为resultMap
<select id="selectUserById" resultMap="UserMap">
select id , name , pwd from user where id = #{id}
</select>
2、编写resultMap,实现手动映射!
<resultMap id="UserMap" type="User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
如果世界总是这么简单就好了。但是肯定不是的,数据库中,存在一对多,多对一的情况,我们之后会使用到一些高级的结果集映射,association,collection这些,我们将在之后讲解,今天你们需要把这些知识都消化掉才是最重要的!理解结果集映射的这个概念!
5、日志
5.1、日志工厂
如果一个数据库操作出现了异常,我们需要排错,日志就是最好的助手!
曾经:sout、debug
现在:日志工厂!
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | |
---|---|---|
- SLF4J
- LOG4J【掌握】
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING【掌握】
- NO_LOGGING
6、分页
- 分页能减少数据的处理量
6.1、SQL分页
- 语法:
select * form user limit startIndex,pageSize;
使用Mybatis实现分页,核心SQL
1、接口
public List<User> getUserByLimit(Map<String,Object> map);
2、Mapper.xml
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from USER limit #{startIndex},#{pageSize}
</select>
3、测试类
@Test
public void getUserByLimit(){
Map<String, Object> map = new HashMap<>();
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
map.put("startIndex",0);
map.put("pageSize",2);
List<User> users = mapper.getUserByLimit(map);
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
6.2、RowBounds分页
1、接口
public List<User> getUserByRowBounds();
2、Mapper.xml
<select id="getUserByRowBounds" resultMap="UserMap">
select * from user
</select>
3、测试类
@Test
public void getUserByRowBounds(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
RowBounds rowBounds = new RowBounds(1,2);
List<User> users = sqlSession.selectList("com.zzl.dao.UserMapper.getUserByRowBounds",null, rowBounds);
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
6.3、分页插件
- pagehelper
7、注解开发
核心配置文件
必须要把接口绑定注册到核心配置文件中
<mappers>
<mapper class="com.zzl.dao.UserMapper"/>
</mappers>
接口
public interface UserMapper {
//查询所有用户
@Select("select * from user")
List<User> getAllUser();
//通过Id查询用户
@Select("select * from user where id = #{id}")
public User getUserById(@Param("id") int id);
//添加用户
@Insert("insert into user (id,username,password) value(#{id},#{username},#{pwd})")
void insert(User user);
//修改用户
@Update("update user set password = #{password} where id = #{id}")
void update(@Param("password") String password,@Param("id") int id);
}
关于@param()注解
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加
- 如果只有一个基本类型,可以省略,但是建议加!
- 在SQL中引用的就是我们这里的@param()中设定的属性名!
8、Lombok
使用步骤
1、在IDEA中安装Lombok插件!
2、在项目中导入Lombok的jar包
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
3、在实体类上加注解
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data 【掌握】
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
Lombok config system
Code inspections
Refactoring actions (lombok and delombok)
9、多对一
- Student类
public class Student {
private int id;
private String name;
private Teacher teacher;
}
- StudentMapper.xml(按照结果嵌套处理)
<mapper namespace="com.zzl.dao.StudentMapper">
<select id="getStudent" resultMap="StudentTeacher">
select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid=t.id;
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
<result property="id" column=""/>
</association>
</resultMap>
</mapper>
- 查询结果
Student(id=1, name=lll, teacher=Teacher(id=0, name=zzl))
Student(id=2, name=zkw, teacher=Teacher(id=0, name=zzl))
Student(id=3, name=ajk, teacher=Teacher(id=0, name=zzl))
Student(id=4, name=gx, teacher=Teacher(id=0, name=zzl))
10、多对一
- Teacher类
@Data
public class Teacher {
private int id;
private String name;
//一个老师对应多个学生
private List<Student> students;
}
- TeacherMapper.xml(按照结果嵌套处理)
<mapper namespace="com.zzl.dao.TeacherMapper">
<select id="getTeacher" resultMap="TeacherStudent">
select s.name sname,s.id sid,t.name tname,t.id tid
from teacher t,student s
where t.id=s.tid;
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
</mapper>
- 查询结果
Teacher(id=1, name=zzl, students=[
Student(id=1, name=lll, tid=1),
Student(id=2, name=zkw, tid=1),
Student(id=3, name=ajk, tid=1),
Student(id=4, name=gx, tid=1)])
11、动态SQL
什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
if
choose (when, otherwise)
trim (where, set)
foreach
if标签
- 随机ID——UUID
public class IDUtil {
public static String getUUID(){
return UUID.randomUUID().toString().replaceAll("-","");
}
}
- Blog类
@Data
@AllArgsConstructor
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private int views;
}
- BlogMapper.xml
<!-- 查询博客-->
<select id="getBlog" resultType="Blog" parameterType="map">
select * from blog
<where>
<if test="author!=null">
author=#{author}
</if>
<if test="views!=null">
and views>=#{views}
</if>
</where>
</select>
- mybatis-config.xml
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 将数据库字段中的 _ 改为JAVA类中的驼峰-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
choose标签
<!-- 查询博客——choose标签-->
<select id="getBlogByChoose" resultType="Blog" parameterType="map">
select * from blog
<where>
<choose>
<when test="author">
author=#{author}
</when>
<when test="views!=null">
and views>=#{views}
</when>
</choose>
</where>
</select>
trim(where、set)
- where : 动态拼接字符串,能自动在SQL语句中加上或删除where、and
- **set:**动态前置set关键字,并且会删除多余的逗号
<!-- 修改博客——set标签-->
<update id="update" parameterType="map">
update blog
<set>
<if test="author!=null">
author=#{author},
</if>
<if test="title!=null">
title=#{title},
</if>
</set>
where id=#{id}
</update>
SQL片段
将一些公共的部分抽取出来,方便复用!
- 抽取SQL
<sql id="if-author-views">
<where>
<if test="author!=null">
author=#{author}
</if>
<if test="views!=null">
and views>=#{views}
</if>
</where>
</sql>
- 引用SQL
<select id="getBlog" resultType="Blog" parameterType="map">
select * from blog
<include refid="if-author-views"/>
</select>
foreach标签
- BlogMapper.xml
<!-- 查询博客——foreach标签-->
<select id="getBlogByForeach" parameterType="map" resultType="Blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="and (" separator="or" close=")">
id=#{id}
</foreach>
</where>
</select>
- 测试
@Test
public void getBlogByForeach(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Map map = new HashMap();
List<String> ids = new ArrayList<String>();
ids.add("2d49fce450b84a429d321e0afccc7321");
ids.add("034f6fa47cbc4131b5afa6343d8dade3");
map.put("ids",ids);
List<Blog> blogs = mapper.getBlogByForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
12、面试高频
- MySQL引擎
- InnoDB底层原理
- 索引
- 索引优化!
Spring
1、优点
- Spring是一个开源的免费的框架!
- Spring是一个轻量级的、非入侵式的框架!
- 控制反转(IOC),面向切面编程(AOP)!
- 支持事务的处理,对框架整合的支持!
总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
2、拓展
- Spring Boot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速的开发单个微服务
- 约定大于配置
- Spring Cloud
- Spring Cloud 是基于SpringBoot实现的
因为现在大多公司都是在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC,承上启下的作用
3、IOC控制反转
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
- 主动权在用户手中
4、HelloSpring
- 导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
- Hello 类
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
- Bean.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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans ">
<bean id="hello" class="com.zzl.domain.Hello">
<property name="str" value="Spring"/>
</bean>
</beans>
- 测试类
public class HelloTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello);
}
}
- 运行结果
Hello{str='Spring'}
5、IOC创建对象的方式
1、使用无参构造创建对象,默认
2、如果使用有参构造创建对象。
1.下标赋值
<bean id="hello" class="com.zzl.domain.Hello">
<constructor-arg index="0" value="Hello Spring"/>
</bean>
2.类型
<bean id="hello" class="com.zzl.domain.Hello">
<constructor-arg type="java.lang.String" value="HelloSpring"/>
</bean>
3.名称赋值
<bean id="hello" class="com.zzl.domain.Hello">
<constructor-arg name="str" value="Spring"/>
</bean>
注意:在配置文件加载的时候,容器中管理的对象就已经初始化了!
6、Spring配置
6.1、别名
<!-- 如果添加了别名,我们也可以用别名获取到这个对象-->
<bean id="hello" class="com.zzl.domain.Hello">
<constructor-arg name="str" value="Spring"/>
</bean>
<alias name="hello" alias="abc"/>
6.2、bean配置
<!--
id:相当于变量名
class:全类名
name:别名
-->
<bean id="hello" class="com.zzl.domain.Hello" name="hello2 abc,aaa;bbb">
<constructor-arg name="str" value="Spring"/>
</bean>
6.3、import
一般用于团队开发使用,他可以将多个配置文件导入合并为一个
7、依赖注入
7.1、构造器注入
前面已经说过
7.2、Set方式注入【重点】
- 依赖注入:Set注入!
- 依赖:bean对象的创建依赖于容器!
- 注入:bean对象中的所有属性,由容器来注入!
【环境搭建】
1、复杂类型
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
2、真实测试对象
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
}
3、beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans ">
<bean id="address" class="com.zzl.domain.Address">
<property name="address" value="河南省"/>
</bean>
<bean id="student" class="com.zzl.domain.Student">
<!-- 普通值注入 value -->
<property name="name" value="赵治理"/>
<!-- bean注入 ref -->
<property name="address" ref="address"/>
<!-- 数组 -->
<property name="books">
<array>
<value>西游记</value>
<value>水浒传</value>
<value>红楼梦</value>
<value>三国演义</value>
</array>
</property>
<!-- List-->
<property name="hobbys">
<list>
<value>打游戏</value>
<value>听音乐</value>
<value>敲代码</value>
</list>
</property>
<!-- Map-->
<property name="card">
<map>
<entry key="身份证" value="11111111111"/>
<entry key="银行卡" value="222222222222"/>
</map>
</property>
<!-- Set-->
<property name="games">
<set>
<value>王者荣耀</value>
<value>荒野乱斗</value>
</set>
</property>
<!-- null-->
<property name="wife">
<null/>
</property>
<!-- properties-->
<property name="info">
<props>
<prop key="学号">1915925999</prop>
<prop key="性别">男</prop>
</props>
</property>
</bean>
</beans>
4、测试类
public class StudentTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
/*
Student{
name='狂神',
address=Address{address='西安'},
books=[西游记, 水浒传, 红楼梦, 三国演义],
hobbys=[打游戏, 听音乐, 敲代码],
card={身份证=11111111111, 银行卡=222222222222},
games=[王者荣耀, 荒野乱斗],
wife='null',
info={学号=1915925999, 性别=男}
}
*/
}
}
7.3、拓展方式注入
p命名空间 c命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
<!--命名空间-->
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans ">
<!-- p命名空间注入,可以直接注入属性的值:property-->
<bean id="user" class="com.zzl.domain.User" p:name="zzl" p:age="21"/>
<!-- c命名空间注入,通过有参构造器注入:construct-args-->
<bean id="user1" class="com.zzl.domain.User" c:name="狂神" c:age="30"/>
</beans>
注意:
命名空间不能直接使用需要引入xml约束
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
7.4、bean的作用域
- 单例模式singleton(Spring默认机制)
<bean id="user" class="com.zzl.domain.User" p:name="zzl" p:age="21" scope="singleton"/>
- 原型模式prototype:每次从容器中get的时候,都会产生一个新对象
<bean id="user" class="com.zzl.domain.User" p:name="zzl" p:age="21" scope="prototype"/>
- 其余的request、session、application这些只能在web开发中使用!
8、Bean的自动装配Autowire
- 自动装配是Spring满足bean依赖的一种方式!
- Spring会在上下文中自动寻找,并自动给bean装配属性!
在Spring中有三种装配的方式
- 在xml中显示配置
- 在java中显示配置
- 隐式的自动装配bean【重点】
8.1、测试
环境搭建:一个人有两个宠物!
8.2、ByName自动装配
<bean id="cat" class="com.zzl.domain.Cat"/>
<bean id="dog" class="com.zzl.domain.Dog"/>
<bean id="people" class="com.zzl.domain.People" autowire="byName"/>
8.3、ByType自动装配
<bean class="com.zzl.domain.Cat"/>
<bean class="com.zzl.domain.Dog"/>
<bean id="people" class="com.zzl.domain.People" autowire="byType"/>
小结:
- ByName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set的方法的值一致!
- ByType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!
8.4、使用注解实现自动装配
使用注解须知:
1、导入约束:context约束
2、配置注解的支持:context:annotation-config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
3、在属性上加注解
public class People{
private String name;
@Autowired
private Dog dog;
@Autowired
private Cat cat;
}
9、使用注解开发
1、bean
@Component //相当于 <bean id="user" class="com.zzl.domain.User"/>
public class User {
public String name;
}
2、属性如何注入
public class User {
@Value("lll") //相当于<property name="name" value="zzl"/>
public String name;
}
3、衍生的注解
@Component有几个衍生的注解,我没在web开发中,会按照MVC三层架构分层!
- dao 【@Repository】
- service 【@Service】
- controller 【@Controller】
这四个注解功能是一样的,都是代表将某个类注册到Spring中,装配bean
4、自动装配
@Autowire:自动装配,通过类型,名称
如果Autowire不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
@Nullable:字段标记了这个注解,说明这个字段可以为null;
@Resource:自动装配通过名字,类型。
5、作用域
@Scope("prototype")//原型
@Scope("singleton")//单例
6、小结
xml与注解:
- xml更加万能,适用于任何场合,维护简单方便
- 注解 不是自己的类使用不了,维护相对复杂!
xml与注解最佳实践:
- xml用来管理bean;
- 注解只负责完成属性的注入;
使用注解时必须要开启注解的支持
<!-- 指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.zzl.domain"/>
<context:annotation-config/>
10、代理模式
代理模式就是springAOP的底层
静态代理
角色分析:
-
抽象角色:一般会使用接口或者抽象类来解决
-
真实角色:被代理的角色
-
代理角色:代理真实角色,代理真是角色后,我们一般会做一些附属操作
-
客户:访问代理对象的人
步骤:
1、接口
public interface Rent {
public void rent();
}
2、真实角色
//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东租赁房子");
}
}
3、代理角色
//中介
public class Proxy implements Rent{
private Host host;
public void rent(){
seeHouse();
fare();
host.rent();
}
public void setHost(Host host) {
this.host = host;
}
public void seeHouse(){
System.out.println("看房子");
}
public void fare(){
System.out.println("中介费");
}
}
4、客户端访问代理角色
public class client {
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy();
proxy.setHost(host);
proxy.rent();
}
}
代理模式的好处:
- 可以使真实角色的操作更加纯粹!不用关注公共业务
- 公共业务交给代理角色,实现了业务的分工
- 方便集中管理公共业务
缺点:
- 一个真实角色就会产生一个代理角色,效率低
动态代理
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的!
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口–JDK动态代理【我们使用】
- 基于类:cglib
- java字节码实现:javasist
需要了解两个类:Proxy:代理,InvocationHandler:调用处理程序
动态代理的好处:
- 可以使真实角色的操作更加纯粹!不用关注公共业务
- 公共业务交给代理角色,实现了业务的分工
- 方便集中管理公共业务
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可!
调用代理处理程序
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setRent(Rent rent){
this.target=rent;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//处理代理实例并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object invoke = method.invoke(target, args);
return invoke;
}
public void log(String msg){
System.out.println("现在是"+msg+"方法");
}
}
11、AOP
什么是AOP?
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
使用Spring实现AOP
【重点】使用AOP织入,需要导入一个依赖包!
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式一
使用Spring的API接口
BeforeLog**
public class BeforeLog implements MethodBeforeAdvice {
/*
method:要执行的目标对象的方法
args:参数
target:目标对象
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行了");
}
}
AfterLog
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println(method.getName()+"方法被执行了,返回的结果为"+o);
}
}
applicationContet.xml配置文件
<!-- 方式一:使用原生的Spring API接口-->
<!-- 配置aop:需要导入aop的约束-->
<aop:config>
<!-- 切入点 expression:表达式 execution(要执行的位置)-->
<aop:pointcut id="pointcut" expression="execution(* com.zzl.service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
方式二
自定义来实现AOP 【主要是切面定义】
applicationContet.xml配置文件
<!-- 方式二:自定义AOP-->
<aop:config>
<aop:aspect ref="log">
<aop:pointcut id="pointcut" expression="execution(* com.zzl.service.UserServiceImpl.*(..))"/>
<aop:before method="beforeLog" pointcut-ref="pointcut"/>
<aop:after method="afterLog" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
方式三
使用注解来实现AOP
<!-- 方式三:使用注解实现-->
<bean id="annoLog" class="com.zzl.annotationPointcut.annoPointcut"/>
<!-- 打开注解-->
<aop:aspectj-autoproxy/>
@Aspect
public class annoPointcut {
@Before("execution(* com.zzl.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("annotationPointcut------before");
}
@After("execution(* com.zzl.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("annotationPointcut------after");
}
}
12、Spring-Mybatis整合
依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- spring操作数据库的话需要导入 spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
</dependencies>
接口
public interface UserMapper {
List<User> select();
}
实现类
public class UserMapperImpl implements UserMapper{
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> select() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.select();
}
}
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.zzl.mapper.UserMapper">
<select id="select" resultType="User">
select * from mybatis.USER
</select>
</mapper>
静态资源配置文件
- mybatis-config.xml【Mybatis的核心配置文件】
<?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>
<typeAliases>
<package name="com.zzl.domain"/>
</typeAliases>
</configuration>
- spring-dao.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用Spring的数据源替换mybatis的配置
我们这里使用spring提供的JDBC:org.springframework.jdbc.datasource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 绑定Mybatis配置文件-->
<property name="configLocation" value="mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/zzl/mapper/*.xml"/>
</bean>
<!-- sqlSessionTemplate:就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
- applicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.zzl.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
13、声明式事务
事务的ACID原则
原子性、一致性、隔离性、持久性
配置声明式事务
<!-- 配置声明式事务-->
<!-- 开启Spring的事务处理功能 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 结合AOP实现事务的织入 -->
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给哪些方法配置事务 -->
<!-- 配置事务的传播特性 -->
<tx:attributes>
<tx:method name="insert" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
配置事务切入
<!-- 配置事务切入-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.zzl.mapper.UserMapper.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
SpringMVC
接下来的学习
SpringMVC + Vue + SpringBoot + SpringCloud + Linux
Servlet回顾
web.xml
<?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">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.zzl.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
原生SpringMVC
导入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
web.xml
<!-- 注册DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
<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>
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="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<bean id="/hello" class="com.zzl.controller.HelloController"/>
</beans>
Controller类
//导入Controller接口
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
// ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModelAndView中
mv.addObject("msg","HelloSpringMVC");
// 封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello"); // /WEB-INF/jsp/hello.jsp
return mv;
}
}
总结:
- 需要导入相关依赖 springmvc servlet-api jsp-api
- 编写DispatcherServlet分发器
- 编写springmvc-servlet配置文件,在其中添加处理器映射器,处理器适配器,视图解析器
注解SpringMVC
web.xml
<?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">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
</servlet>
<!-- 在springmvc中 / 和 /* 的区别
/ : 只匹配所有的请求,不匹配jsp页面
/*: 匹配所有的请求,包括jsp页面
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.zzl.controller"/>
<!-- 让SpringMVC不处理静态资源 .css .js 等-->
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<!-- 视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
Controller类
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(Model model){
model.addAttribute("msg","HelloControllerAnnotation");
return "hello";
}
}
RestFu风格
public class RestFuController {
// RestFu风格
@GetMapping("/hello1/{a}/{b}")
public String test1(@PathVariable int a,@PathVariable int b, Model model){
int c=a+b;
model.addAttribute("msg","结果为:"+c);
return "hello";
}
// @RequestMapping("/h2")
// public String test2(@RequestParam("username") String name, Model model){
// model.addAttribute("msg",name);
// return "hello";
// }
}
直接在地址栏中传参,以/号分隔
SpringMVC拦截器解决乱码问题
<!-- 解决乱码问题-->
<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>
<url-pattern>/*</url-pattern>
</filter-mapping>
Spring依赖、注解
依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
注解
@Autowire:自动装配,通过类型,名称
如果Autowire不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
@Nullable:字段标记了这个注解,说明这个字段可以为null;
@Resource:自动装配通过名字,类型。
@Component:组件,放在类上,说明这个类被spring管理了,就是bean!