IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring、Mybatis、Mybatis-plus -> 正文阅读

[Java知识库]Spring、Mybatis、Mybatis-plus

作者:language-java

Spring

一、简介

1、概述:是分层地JavaSE/EE应用full-stack轻量级开源框架,以IOC和AOP为内核
2、优点
????????(1)、方便解耦,简化开发
????????(2)、Aop编程支持
????????(3)、声明式事务的支持
????????(4)、方便程序的测试
????????(5)、方便集成各种优秀框架
????????(6)、降低JavaEEAPI的使用难度
????????(7)、java源码是经典学习范例
3、开发步骤
????????(1)、导入Spring开发的基本包坐标
????????(2)、编写Dao接口和实现类
????????(3)、创建Spring核心配置文件
????????(4)、在Spring配置文件中配置Dao接口的实现类
????????(5)、使用Spring的API获取Bean实例
4、依赖

?<dependency>
? ? ?<groupId>org.springframework</groupId>
? ? ?<artifactId>spring-context</artifactId>
? ? ?<version>5.3.18</version>
?</dependency>

二、IOC

(一)、Bean

1、概述:是一个被实例化,组装,并通过Spring IOC容器所管理的对象
2、属性
????????(1)、id:在spring容器中的唯一标识
????????(2)、class:Bean的全类路径
????????(3)、scope:对象的作用范围

取值范围说明
singleton默认值,单例的;核心配值文件加载,就实例化Bean实例
prototype多例的;调用getBean是,就创建新的实例化Bean
requestweb项目中。spring创建一个Bean对象,将对象存入到request域中
sessionweb项目中。spring创建一个Bean对象,将对象存入到session域中
global sessionweb项目中。应用在Portlet环境中,若没有Portlet环境,那么global session就相当于session

????????(4)、init-method:指定类型初始化方法名称,方法名称随意 ?
????????(5)、destroy-method:指定类型销毁方法的名称,方法名称随意
3、子属性 ?
????????(1)、property:依赖注入,set方法 ?
????????????????①、name:属性名称 ?
????????????????②、value:注入的普通属性值 ?
????????????????③、ref:注入对象的引用值 ?
????????(2)、constructor-arg::依赖注入,有参构造

(二)、实例化

1、无参构造方法实例化

?<bean id="userDao" class="com.spring.entity.UserDao"></bean>

2、工厂静态方法实例化

?<bean id="userDao" class="com.spring.factory.EntityFactory" factory-method="getUserDao"></bean>

3、工厂实例方法实例化

?<bean id="entityFactory" class="com.spring.factory.EntityFactory"></bean>
?<bean id="userDao" factory-bean="entityFactory" factory-method="getUserDao"></bean>

(三)、依赖注入

1、概述:是Spring框架核心的IOC的具体实现
2、方式
????????(1)、set
????????????????①、普通类型

?<bean id="user" class="com.spring.Entity.User">
? ? ?<property name="name" value="三国演义"></property>
?</bean>

????????????????②、引用类型

?<bean id="userDao" class="com.spring.entity.UserDao"></bean>
?<bean id="userServiceImpl" class="com.spring.service.impl.UserServiceImpl">
? ? ?<property name="userDao" ref="userDao"></property>
?</bean>

????????????????③、集合

?<bean id="user" class="com.spring.entity.User">
? ? ?<!-- 数组属性注入 -->
? ? ?<property name="stu">
? ? ? ? ?<array>
? ? ? ? ? ? ?<value>Java</value>
? ? ? ? ? ? ?<value>Mysql</value>
? ? ? ? ?</array>
? ? ?</property>
? ? ?<!-- list属性注入 -->
? ? ?<property name="list">
? ? ? ? ?<list>
? ? ? ? ? ? ?<value>Python</value>
? ? ? ? ? ? ?<value>Php</value>
? ? ? ? ?</list>
? ? ?</property>
? ? ?<!-- set属性注入 -->
? ? ?<property name="set">
? ? ? ? ?<set>
? ? ? ? ? ? ?<value>html</value>
? ? ? ? ? ? ?<value>js</value>
? ? ? ? ?</set>
? ? ?</property>
? ? ?<!-- Map属性注入 -->
? ? ?<property name="map">
? ? ? ? ?<map>
? ? ? ? ? ? ?<entry key="JAVA" value="java"></entry>
? ? ? ? ? ? ?<entry key="HTML" value="html"></entry>
? ? ? ? ?</map>
? ? ?</property>
? ? ?<!-- List属性注入,但是值为对象类型 -->
? ? ?<property name="corseList">
? ? ? ? ?<list>
? ? ? ? ? ? ?<ref bean="corse1" ></ref>
? ? ? ? ? ? ?<ref bean="corse2"></ref>
? ? ? ? ?</list>
? ? ?</property>
? ? ?<!-- Properties属性注入 -->
? ? ?<property name="properties">
? ? ? ? ?<props>
? ? ? ?      <prop key="p1">spring</prop>
? ? ? ? ? ? ?<prop key="p2">springmvc</prop>
? ? ? ? ?</props>
? ? ?</property>
?</bean>
?<!-- 将对象放入list集合中 -->
?<bean id="corse1" class="com.spring.entity.Corse">
? ? ?<property name="name" value="Spring"></property>
?</bean>
?<bean id="corse2" class="com.spring.entity.Corse">
? ? ?<property name="name" value="SpringBoot"></property>
?</bean>

????????(2)、有参构造 ?
????????????????①、普通类型

?<bean id="user" class="com.spring.Entity.User">
? ? ?<constructor-arg name="name" value="西游记"></constructor-arg>
?</bean>

????????????????②、引用类型

?<bean id="userDao" class="com.spring.entity.UserDao"></bean>
?<bean id="userServiceImpl" class="com.spring.service.impl.UserServiceImpl">
? ? ?<constructor-arg name="userDao" ref="userDao"></constructor-arg>
?</bean>

????????????????③、集合

(四)、引入外部模块

1、概述:将主配置文件进行分模块的拆解,通过标签引入即可 2、标签

?<import resourse="applicationContext-xxx.xml"></import>

(五)、相关API

1、ApplicationContext
????????(1)、概述:接口,文件的上下文
????????(2)、实现类
????????????????①、CalssPathXmlApplicationContext:是从类的跟路径下加载配置文件
????????????????②、FileSystemXmlApplicationContext:从磁盘路径下加载配置文件
????????????????③、AnnotaionConfigApplicationContext:注解配置容器对象是,用来读取注解的
2、getBean
????????(1)、getBean(String name):通过Id获取,可以不是唯一的类型,需要强制转换
????????(2)、getBean(Class<T> requireType):通过类型,但是只能是一个唯一的类型,不需要强制转换

(六)、数据源

1、概述:提供了应用程序所需要数据的位置
2、作用:简化开发,提升性能
3、常见数据源:DBCP、C3P0、BoneCP、Druid...
4、开发步骤
????????(1)、导入数据源的坐标和数据驱动坐标
????????(2)、创建数据源对象
????????(3)、设置数据源的基本连接数据
????????(4)、使用数据源获取连接资源和归还资源
5、C3P0
????????(1)、导入依赖

?<dependency>
? ? ?<groupId>c3p0</groupId>
? ? ?<artifactId>c3p0</artifactId>
? ? ?<version>0.9.1.2</version>
?</dependency>

????????(2)、传统案例

?public void c3p0() throws Exception {
? ? ?ComboPooledDataSource dataSource = new ComboPooledDataSource();
? ? ?dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
? ? ?dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mysql");
? ? ?dataSource.setUser("root");
? ? ?dataSource.setPassword("root");
? ? ?Connection connection = dataSource.getConnection();
? ? ?System.out.println(connection);
? ? ?connection.close();
?}

????????(3)、抽取配置消息

?driver=com.mysql.cj.jdbc.Driver
?url=jdbc:mysql://localhost:3306/mysql
?username=root
?password=root
?public void c3p0() throws Exception {
? ? ?ResourceBundle rb = ResourceBundle.getBundle(" jdbc");
? ? ?String driver = rb.getString("driver");
? ? ?String url = rb.getString("ur1");
? ? ?String username = rb.getString("username");
? ? ?String password = rb.getString("password");
? ? ?ComboPooledDataSource dataSource = new ComboPooledDataSource();
? ? ?dataSource.setDriverClass(driver);
? ? ?dataSource.setJdbcUrl(url);
? ? ?dataSource.setUser(username);
? ? ?dataSource.setPassword(password);
? ? ?Connection connection = dataSource.getConnection();
? ? ?System.out.println(connection);
? ? ?connection.close();
?}

????????(4)、spring配置数据源

?driver=com.mysql.cj.jdbc.Driver
?url=jdbc:mysql://localhost:3306/mysql
?username=root
?password=root
?<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
?<bean id="dateSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
?    <property name="driverClass" value="${drive}"></property>
? ? ?<property name="jdbcUrl" value="${url}"></property>
? ? ?<property name="user" value="${username}"></property>
? ? ?<property name="password" value="${password}"></property>
?</bean>

6、Druid
????????(1)、导入依赖

?<dependency>
? ? ?<groupId>com.alibaba</groupId>
? ? ?<artifactId>druid</artifactId>
? ? ?<version>1.2.8</version>
?</dependency>x

????????(2)、传统案例

?public void druid() throws Exception {
? ? ?DruidDataSource dataSource = new DruidDataSource();
? ? ?dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
? ? ?dataSource.setUrl("jdbc:mysql://localhost:3306/mysql");
? ? ?dataSource.setUsername("root");
? ? ?dataSource.setPassword("root");
? ? ?DruidPooledConnection connection = dataSource.getConnection();
? ? ?System.out.println(connection);
? ? ?connection.close();
?}

????????(3)、抽取配置消息

?driver=com.mysql.cj.jdbc.Driver
?url=jdbc:mysql://localhost:3306/mysql
?username=root
?password=root
?public void c3p0() throws Exception {j
? ? ?ResourceBundle rb = ResourceBundle.getBundle(" jdbc");
? ? ?String driver = rb.getString("driver");
? ? ?String url = rb.getString("ur1");
? ? ?String username = rb.getString("username");
? ? ?String password = rb.getString("password");
? ? ?DruidDataSource dataSource = new DruidDataSource();
? ? ?dataSource.setDriverClassName(driver);
? ? ?dataSource.setUrl(url);
? ? ?dataSource.setUsername(username);
? ? ?dataSource.setPassword(password);
? ? ?DruidPooledConnection connection = dataSource.getConnection();
? ? ?System.out.println(connection);
? ? ?connection.close();
?}

????????(4)、spring配置数据源

?driver=com.mysql.cj.jdbc.Driver
?url=jdbc:mysql://localhost:3306/mysql
?username=root
?password=root
?<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
?<bean id="dateSource" class="com.alibaba.druid.pool.DruidDateSource">
?    <property name="driverClassName" value="${drive}"></property>
? ? ?<property name="url" value="${url}"></property>
? ? ?<property name="username" value="${username}"></property>
? ? ?<property name="password" value="${password}"></property>
?</bean>

(七)、注解开发

1、作用:简化配置,提高开发效率
2、原始注解

注解说明
@Component使用在类上用于实例化Bean
@Controller使用在web层类上用于实例化Bean
@Service使用在service层类上用于实例化Bean
@Repository使用在Dao层类上用于实例化Bean
@Autowired使用在字段上用于根据类型依赖注入
@Qualifier结合@Autowired一起使用用于根据名称进行依赖注入
@Resource相当于@Autowired+@Qualifier,安装名称进行注入
@Value注入普通属性
@Scope标注Bean的作用范围
@PostConstruct使用在方法上标注该方法是Bean的初始化方法
@PreDestroy使用在方法上标注该方法是Bean的销毁方法

3、注意事项:使用注解式开发时,要在spring的核心配置文件中,加入注解扫描器

?<!-- 开启扫描组件 -->
?<context:component-scan base-package="com.spring5.UserService"></context:component-scan>

4、新注解

注解说明
@Configuration用于指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解
@ComponentScan用于指定Spring在初始化容器时要扫描的包
@Bean使用在方法上,标注将该方法的返回值存储到Spring容器中
@PropertySource用于加载properties文件中的位置
@Import用于导入其它配置类

三、JDBCTemplate

1、概述:Spring框架对JDBC进行封装,方便实现对数据库操作
2、开发步骤
????????(1)、导入spring-jdbc和spring-tx的依赖

?<dependency>
? ? ?<groupId>org.springframework</groupId>
? ? ?<artifactId>spring-jdbc</artifactId>
? ? ?<version>5.3.18</version>
?</dependency>
?<dependency>
? ? ?<groupId>org.springframework</groupId>
? ? ?<artifactId>spring-tx</artifactId>
? ? ?<version>5.3.18</version>
?</dependency>

????????(2)、创建数据库的表和实体 ?
????????(3)、创建JDBCTemplate对象 ?
????????(4)、执行数据库操作 ?
????????(5)、示例

?jdbc.DriverClass=com.mysql.jdbc.Driver
?jdbc.url=jdbc.mysql://localhost:3306//user_db
?jdbc.username=root
?jdbc.password=root
?@Data
?@NoArgsConstructor
?@AllArgsConstructor
?public class Book {
? ? ?private String userId;
? ? ?private String userName;
? ? ?private String ustatus;
?}
?public interface BookDao{
? ? ?public void add(Book book);//添加
? ? ?public void updateBook(Book book);//修改
? ? ?public void deleteBook(String id);//删除
? ? ?public int selectCount();//返回某个值
?    public Book findBookInfo();//返回一个对象
?    public List<Book> findBookAll();//返回一个集合
?    public void batchAddBook(List<Object[]> batchArgs);//批量添加
?    public void batchUpdateBook(List<Object[]> batchArgs);//批量修改
?    public void batchDeleteBook(List<Object[]> batchArgs);//批量删除
?}
?@Repository
?public class BookDaoImpl implements BookDao{
? ? ?@Autowired
? ? ?private JdbcTemplate jdbcTemplate;
?    public void add(Book book){//添加
?        String sql = "insert into book values(?,?,?)";
?        Objec[] ages = {book.getUserId(),bool.getUserName(),book.getUstatus()};
?        int update = jdbcTemplate.update(sql,ages);//前面是SQl,后面是变值
? ? ? ? ?System.out.println(update);
? ?  }
? ? ?public void updateBook(Book book){//修改
? ? ? ? ?String sql = "update book set userName=?,ustatus=? where userId=?";
? ? ? ? ?Objec[] ages = {bool.getUserName(),book.getUstatus(),book.getUserId()};
? ? ? ? ?int update = jdbcTemplate.update(sql,ages);//前面是SQl,后面是变值
? ? ? ? ?System.out.println(update);
? ?  }
? ? ?public void deleteBook(String id){//删除
? ? ? ? ?String sql = "delete from book where userId=?";
?        Objec[] ages = {id};
?        int update = jdbcTemplate.update(sql,ages);//前面是SQl,后面是变值
? ? ? ? ?System.out.println(update);
? ?  }
? ? ?public int selectCount(){//返回某个值
?        String sql = "select count(*) from book";
?        Integer count = jdbcTemplate.queryForObject(sql,Integer.class);
? ? ? ? ?return count;
? ?  }
? ? ?public Book findBookInfo(String id){//返回一个对象
?        String sql = "select * from book where userId=?";
? ? ? ? ?Objec[] ages = {id};
?        Book book = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),ages);
? ? ? ? ?return book;
? ?  }
?    public List<Book> findBookAll(){//返回一个集合
? ? ? ? ?String sql = "select * from book";
? ? ? ? ?List<Book> listBook = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));
? ? ? ? ?return listBook;
? ?  }
?    public void batchAddBook(List<Object[]> batchArgs){//批量添加
? ? ? ? ?String sql = "insert into book values(?,?,?)";
?        int[] update = jdbcTemplate.batchUpdate(sql,batchArgs);
? ? ? ? ?System.out.println(Arrays.toString(update));
? ?  }
?    public void batchUpdateBook(List<Object[]> batchArgs){//批量修改
? ? ? ? ?String sql = "update book set userName=?,ustatus=? where userId=?";
? ? ? ? ?int[] update = jdbcTemplate.batchUpdate(sql,batchArgs);
? ? ? ? ?System.out.println(Arrays.toString(update));
? ?  }
? ? ?public void batchDeleteBook(List<Object[]> batchArgs){//批量删除
?        String sql = "delete from book where userId=?";
?        int[] update = jdbcTemplate.batchUpdate(sql,batchArgs);
? ? ? ? ?System.out.println(Arrays.toString(update));
? ?  }
?}
?@Service
?public class BookService{
? ? ?@Autowired
? ? ?private BookDao bookDao;
? ? ?public void addBook(Book book){//添加
? ? ? ? ?bookDao.add(book);
? ?  }
? ? ?public void updateBook(Book book){//修改
? ? ? ? ?bookDao.update(book);
? ?  }
? ? ?public void deleteBook(String id){//删除
? ? ? ? ?bookDao.delete(id);
? ?  }
? ? ?public int findCount(){//返回某个值
? ? ? ? return bookDao.selectCount();
? ?  }
? ? ?public Book findOne(String id){//返回一个对象
? ? ? ? ?return bookDao.findBookInfo(id);
? ?  }
?    public List<Book> find(){//返回一个集合
? ? ? ? ?return bookDao.findBookAll();
? ?  }
?    public void batchAdd(List<Object[]> batchArgs){//批量添加
? ? ? ? ?bookDao.batchAddBook(batchArgs);
? ?  }
?    public void batchUpdate(List<Object[]> batchArgs){//批量修改
? ? ? ? ?bookDao.batchUpdateBook(batchArgs);
? ?  }
? ? ?public void batchDelete(List<Object[]> batchArgs){//批量删除
?        bookDao.batchDeleteBook(batchArgs);
? ?  }
?}
?<!-- 组件扫描 -->x
?<context:component-scan base-package="com.spring5"></context:component-scan>
?<!-- 将properties加载到配置文件中去,要使用context空间名称 -->
?<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
?<!-- 配置 -->
?<bean id="dateSource" class="com.alibaba.druid.pool.DruidDateSource">
?    <property name="driverClassName" value="${jdbc.DriverClass}"></property>
? ? ?<property name="url" value="${jdbc.url}"></property>
? ? ?<property name="username" value="${jdbc.username}"></property>
? ? ?<property name="userword" value="${jdbc.password}"></property>
?</bean>
?<!-- JdbcTemplate对象 -->
?<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
?    <!-- 注入dataSource -->
?    <prpperty name="dateSourse" ref="dateSource"></prppe```rty>
?</bean>
?public class Test{
? ? ?public static void main(String[] agrs){
? ? ? ? ?ApplicationContext context = new ClassPathXmlApplicationContext("beam.xml");
? ? ? ? ?BookService bookService = context.getBean("bookService",BookService.class);
? ? ? ? ?bookService.addBook(new Book("1","java","在学");//添加
?        bookService.updateBook(new Book("1","java","完成");//修改
?        bookService.deleteBook(1);//删除
?        System.out.println(bookService.selectCount());//返回某个值
?        System.out.println(bookService.findOne(1));//返回一个对象
?        System.out.println(bookService.find());//返回一个集合
?        List<Object[]> batchArgs = new ArrayList<>();
?        Object[] o1 = {"1","Java","a"};
?        Object[] o2 = {"2","mysql","b"};
?        Object[] o3 = {"3","html","c"};
?        batchArgs.add(o1);
?        batchArgs.add(o2);
?        batchArgs.add(o3);
?        bookService.batchAdd(batchArgs);//批量添加
?        List<Object[]> batchArgs = new ArrayList<>();
?        Object[] o1 = {"js","d","1"};
?        Object[] o2 = {"css","e","2"};
?        Object[] o3 = {"mysql","f","3"};
?        batchArgs.add(o1);
?        batchArgs.add(o2);
?        batchArgs.add(o3);
?        bookService.batchUpdate(batchArgs);//批量修改
?        List<Object[]> batchArgs = new ArrayList<>();
?        Object[] o1 = {"1"};
?        Object[] o2 = {"2"};
?        batchArgs.add(o1);
?        batchArgs.add(o2);
?        batchArgs.add(o3);
?        bookService.batchUpdate(batchArgs);//批量删除
? ?  }
?}

四、AOP

(一)、简介

1、概述:是通过预编译方式和运行期动态代理,实现程序功能的统一维护的一种技术
2、目的:降低业务和逻辑的耦合度,提高程序的可重用行,同时提高了开发效率
3、作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
4、优势:减少重复代码,提高开发效率,并且便于维护
5、底层原理:动态代理
6、常用的动态代理技术
????????(1)、JDK代理:基于接口的动态代理技术
????????(2)、cglib代理:基于父类的动态代理技术
7、术语
????????(1)、目标对象:Target,代理的目标对象
????????(2)、代理:Proxy,一个类被AOP织入增强时,就产生一个结果代理类
????????(3)、连接点:Joinpoint,那些方法可以被增强
????????(4)、切入点:Pointcut,实际真正增强的方法;execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))
????????(5)、通知:Advice,实际增强的逻辑部分
????????(6)、切面:Aspect,把通知应用到切入点的过程
????????(7)、织入:Weaving,把增强应用到目标对象来创建新的代理对象的过程
8、注意事项
????????(1)、需要编写的内容;切点、通知、织入配置
????????(2)、AOP技术实现的内容 (3)、AOP底层使用那种代理方式

(二)、AspectJ

1、概述:是一个易用的功能强大的AOP框架
2、依赖

?<dependency>
? ? ?<groupId>org.aspectj</groupId>
? ? ?<artifactId>aspectjweaver</artifactId>
? ? ?<version>1.8.4</version>
?</dependency>

3、xml实现

public interface TargetInterface{
? ? ?public void save();
?}
?public class Target implements TargetInterface{
? ? ?public void save(){
? ? ? ? System.out.println("需要增强");
? ?  }
?}
?public class MyAspect(){
? ? ?public void before(){//前置
? ? ? ? ?System.out.println("before...");
? ?  }
? ? ?public void afterReturning(){//后置
? ? ? ? ?System.out.println("afterReturning...");
? ?  }
? ? ?public void after(){//最终
? ? ? ? ?System.out.println("after...");
? ?  }
? ? ?public void afterThrowing()//异常
? ? ? ? ?System.out.println("afterThrowing...");
? ?  }
? ? ?public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{//环绕
? ? ? ? ?System.out.println("around...前");
? ? ? ? ?proceedingJoinPoint.proceed();
? ? ? ? ?System.out.println("around...后");
? ?  }
?}
?<!-- 目标对象 -->
?<bean id="target" class="com.spring.aop.Target"></bean>
??
?<!-- 切面对象 -->
?<bean id="myAspect" class="com.spring.aop.MyAspect"></bean>
??
?<aop:config>
? ? ?<!-- 切入点 -->
? ? ?<aop:pointcut id="save" expression="execution(public void com.spring.aop.Target.save())"/>
? ? ?<!-- 配置切面 -->
? ? ?<aop:aspect ref="myAspect">
? ? ? ? ?<!-- 前置通知 -->
? ? ? ? ?<aop:before method="before" pointcut-ref="save"></aop:before>
? ? ? ? ?<!-- 后置通知 -->
? ? ? ? ?<aop:after-returning method="afterReturning" pointcut-ref="save"></aop:after-returning>
? ? ? ? ?<!-- 环绕置通知 -->
? ? ? ? ?<aop:around method="around" pointcut-ref="save"></aop:around>
? ? ? ? ?<!-- 异常通知 -->
? ? ? ? ?<aop:after-throwing method="afterThrowing" pointcut-ref="save"></aop:after-throwing>
? ? ? ? ?<!-- 最终通知 -->
? ? ? ? ?<aop:after method="after" pointcut-ref="save"></aop:after>
? ? ?</aop:aspect>
?</aop:config>

4、注解实现

public interface TargetInterface{
? ? ?public void save();
?}
?@Component("target")
?public class Target implements TargetInterface{
? ? ?public void save(){
? ? ? ? System.out.println("需要增强");
? ?  }
?}
?@Component("myAspect")
?@Aspect
?public class MyAspect(){
? ? ?@Pointcut(value="execution(*[路径].User.add(...))")//相同切入点抽取
? ? ?public void pointdemo(){}
? ? ?@Before("execution(* com.spring.aop.Target.save())")
? ? ?public void before(){//前置
? ? ? ? ?System.out.println("before...");
? ?  }
? ? ?@AfterReturning("execution(* com.spring.aop.Target.save())")
? ? ?public void afterReturning(){//后置
? ? ? ? ?System.out.println("afterReturning...");
? ?  }
? ? ?@After("execution(* com.spring.aop.Target.save())")
? ? ?public void after(){//最终
? ? ? ? ?System.out.println("after...");
? ?  }
? ? ?@AfterThrowing("execution(* com.spring.aop.Target.save())")
? ? ?public void afterThrowing(){//异常
? ? ? ? ?System.out.println("afterThrowing...");
? ?  }
? ? ?@Around("execution(* com.spring.aop.Target.save())")
? ? ?public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{//环绕
? ? ? ? ?System.out.println("around...前");
? ? ? ? ?proceedingJoinPoint.proceed();
? ? ? ? ?System.out.println("around...后");
? ?  }
?}
?@Configuration
?@ComponentScan(basePackages={"com.spring5"})
?@EnableAspectJAutoProxy(proxyTargetClass=true)
?public class ConfigAop{}

五、事务控制

(一)、编程式事务控制

1、PlatformTransactionManager:事务管理器,操作事务的方法
????????(1)、获取事务:TransactionStatus getTransaction(TransactionDefinition definition)
????????(2)、提交事务:void commit(TransactionStatus status)
????????(3)、回滚事务:void rollback(TransactionStatus status)
2、TransactionDefinition:定义了事务的基本信息
????????(1)、获取事务定义名称:String getName()
????????(2)、获取事务的读写属性:boolean isReadOnly()
????????(3)、获取事务隔离级别:int getIsolationLevel()
????????(4)、获事务超时时间:int getTimeout()
????????(5)、获取事务传播行为特征:int getPropagationBehavior()
3、TransactionStatus:事务在执行过程中某个时间点上的状态信息及对应的状态操作
????????(1)、获取事务是否处于新开启事务状态:boolean isNewTransaction()
????????(2)、获取事务是否处于已完成状态:boolean isCompleted()
????????(3)、获取事务是否处于回滚状态:boolean isRollbackOnly()
????????(4)、刷新事务状态:void flush()
????????(5)、获取事务是否具有回滚存储点:boolean hasSavepoint()
????????(6)、设置事务处于回滚状态:void setRollbackOnly()

(二)、声明式事务控制

1、概述:采用声明的方式来处理事务,指在配置文件中声明
2、作用
????????(1)、事务管理不侵入开发的组件
????????(2)、维护方便
3、xml

?<!-- 组件扫描 -->
?<context:component-scan base-package="com.spring5"></context:component-scan>
?<!-- 数据库连接池 -->
?<bean id="dateSource" class="com.alibaba.druid.pool.DruidDateSource" destroy-method="colse">
?    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
? ? ?<property name="url" value="jdbc:mysql://user_db"></property>
? ? ?<property name="username" value="root"></property>
? ? ?<property name="userword" value="root"></property>
?</bean>
?<!-- JdbcTemplate对象 -->
?<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
?    <!-- 注入dataSource -->
?    <prpperty name="dateSourse" ref="dateSource"></prppe```rty>
?</bean>
?<!-- 创建事务管理器 -->
?<bean id="transactionManager" class="org.springframework.jdbc.datasourse.DataSourceTransactuinManager">
?    <!-- 注入数据源 -->
? ? ?<property name="dataSourse" ref="dataSource"></property>
?</bean>
?<!-- 配置通知 -->
?<tx:advice id="txadvice">
?    <!-- 配置事务参数 -->
?    <tx:attributes>
? ?      <!-- 只定那种规则的方法上面添加事务 -->
?        <tx:method name="acccountMoney" propagation="REQUIRED"/>
? ? ?</tx:attributes>
?</tx;advice>
?<!-- 配置切入点和切面 -->
?<aop:config>
?    <!-- 切入点 -->
?    <aop:pointcut id="pt" expression="execution(* com.spring5.account.*(...))"/>
?    <!-- 配置切面 -->
?    <aop:advisor advice-ref="txadcice" pointcut-ref="pt"/>
?</aop:config>

4、注解

?@Configuration//配置类
?@ComponentScan(basePackages="com.spring5")//组件扫描
?@EnableTransactionManagement//开启事务
?public class TxConfig{
?    @Bean
?    public DruidDataSource getDruidDataSource(){ //创建链接池
? ? ? ? ?DruidDataSource dataSource = new DruidDataSource();
? ? ? ? ?dataSource.setDriverClassName("com.mysql.jdbc.Driver");
?        dataSource.setUrl("jdbc:mysql://user_db");
? ? ? ? ?dataSource.setUsername("root");
? ? ? ? ?dataSource.setPassword("root");
? ? ? ? ?return dataSource;
? ?  }
?    @Bean
?    public JdbcTemolate getJdbcTemolate(DataSource dataSource){//创建JDBCTemolate对象
? ? ? ? ?JdbcTemolate jdbcTemolate = new JdbcTemolate();
? ? ? ? ?//注入DataSource
?        JdbcTemolate.setDataSource(dataSource);
? ? ? ? ?return jdbcTemolate;
? ?  }
?    @Bean //创建事务管理对象
?    public DataSourceTransacrionManager getDataSourceTransacrionManager(DataSource dataSource){
? ? ? ? ?DataSourceTransacrionManager transacrionManager = new DataSourceTransacrionManager();
? ? ? ? ?transacrionManager.setDataSource(dataSource);
? ? ? ? ?return transacrionManager;
? ?  }
?}

六、集成

(一)、web环境

1、三层架构
2、ContextLoaderListener

?WebApplicationContext app = WebApplicationContextUtils.getWebApplicationContext (servletContext);
?<context-param>
?    <param-name>contextConfigLocation</param-name>
? ? ?<param-value>classpath:applicationContext.xml</param-value>
?</context-param>
??
?<listener>
?    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
?</listener>

3、步骤
????????(1)、导依赖
????????(2)、配置ContextLoaderListener监听器
????????(3)、使用 WebApplicationContextUtils获取应用上下文

(二)、Junit

1、导入依赖的坐标

?<dependency>
? ? ?<groupId>junit</groupId>
? ? ?<artifactId>junit</artifactId>
? ? ?<version>4.13.1</version>
? ? ?<scope>test</scope>
?</dependency>
?<dependency>
? ? ?<groupId>org.springframework</groupId>
? ? ?<artifactId>spring-test</artifactId>
? ? ?<version>5.3.18</version>
?</dependency>

2、使用@Runwith注解替换原来的运行期
3、使用@ContextConfiguration指定配置文件或配置类
4、使用@Autowired注入需要测试的对象
5、测试
6、示例
????????(1)、整合Junit4

?@RunWith(SpringJUnit4ClassRunner.class)
?@ContestConfiguration("classpath:bean.xml")
?public class JTest4{
? ? ?@Autowired
?    private UserService userService;
? ? ?@Test
? ? ?public void test(){
? ? ? ? ?userService.addMoney();
? ?  }
?}

????????(2)、整合Junit5

@ExtendWith(SprintExtension.class)
?@ContextConfiguration("classpath:bean.xml")
?或
?@SpringJunitConfig(locations="classpath:bean.xml")
?public class Jtest5{
? ? ?@Autowired
?    private UserService userService;
? ? ?@Test
? ? ?public void test(){
? ? ? ? ?userService.addMoney();
? ?  }
?}

SpringMVC

一、简介

1、概述:是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架
2、特点
????????(1)、Spring家族原生产品,与IOC容器等基础设施无缝对接
????????(2)、基于原生地Servlet,通过了功能强大地前端控制器DispatcherServlet,对请求和响应进行统一处理
????????(3)、表述层各细分邻域需要解决的问题全方位覆盖,提供全面解决方案
????????(4)、代码清新简洁,大幅度提升开发效率
????????(5)、内部组件化程序高,可插拔式组件即插即用,想要什么功能配置相应组件即可
????????(6)、性能卓越,尤其适合现代大型、超大型互联网项目要求
3、优点
????????(1)、清晰地角色划分,Spring MVC 在 Model、View 和 Controller 方面提供了一个非常清晰的角色划分,这 3 个方面真正是各司其职,各负其责。
????????(2)、灵活的配置功能,可以把类当作 Bean 通过 XML 进行配置。
????????(3)、提供了大量的控制器接口和实现类,开发者可以使用 Spring 提供的控制器实现类,也可以自己实现控制器接口。
????????(4)、真正做到与 View 层的实现无关。它不会强制开发者使用 JSP,可以根据项目需求使用 Velocity、FreeMarker 等技术。
????????(5)、国际化支持
????????(6)、面向接口编程
????????(7)、与 Spring 框架无缝集成

二、搭建框架

1、开发环境
????????(1)、IDE:IntelliJ IDEA 2021.1.2
????????(2)、构建工具:apache-maven-3.8.2
????????(3)、服务器:apache-tomcat-8.5.70
????????(4)、Spring版本:
2、创建工程(手动)

?<?xml version="1.0" encoding="UTF-8"?>
?<project xmlns="http://maven.apache.org/POM/4.0.0"
? ? ? ? ? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
? ? ? ? ? xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
? ? ?<modelVersion>4.0.0</modelVersion>
? ? ?<groupId>com.springmvc</groupId>
? ? ?<artifactId>springmvc</artifactId>
? ? ?<version>1.0-SNAPSHOT</version>
? ? ?<packaging>war</packaging>
? ? ?<dependencies>
? ? ? ? ?<!-- SpringMVC -->
? ? ? ? ?<dependency>
? ? ? ? ? ? ?<groupId>org.springframework</groupId>
? ? ? ? ? ? ?<artifactId>spring-webmvc</artifactId>
? ? ? ? ? ? ?<version>5.3.1</version>
? ? ? ? ?</dependency>
? ? ? ? ?<!-- 日志 -->
? ? ? ? ?<dependency>
? ? ? ? ? ? ?<groupId>ch.qos.logback</groupId>
? ? ? ? ? ? ?<artifactId>logback-classic</artifactId>
? ? ? ? ? ? ?<version>1.2.3</version>
? ? ? ? ?</dependency>
? ? ? ? ?<!-- ServiceAPI -->
? ? ? ? ?<dependency>
? ? ? ? ? ? ?<groupId>javax.servlet</groupId>
? ? ? ? ? ? ?<artifactId>javax.servlet-api</artifactId>
? ? ? ? ? ? ?<version>3.1.0</version>
? ? ? ? ? ? ?<scope>provided</scope>
? ? ? ? ?</dependency>
? ? ? ? ?<!-- Spring5和Thymeleaf整合包 -->
? ? ? ? ?<dependency>
? ? ? ? ? ? ?<groupId>org.thymeleaf</groupId>
? ? ? ? ? ? ?<artifactId>thymeleaf-spring5</artifactId>
? ? ? ? ? ? ?<version>3.0.12.RELEASE</version>
? ? ? ? ?</dependency>
? ? ?</dependencies>
?</project>

3、添加Web模板
????????(1)、创建webapp文件夹,创建web.xml文件
????????(2)、配置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">
? ? ?<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求进行统一处理 -->
? ? ?<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.xml</param-value>
? ? ? ? ?</init-param>
? ? ? ? ?<!-- 将前端控制器的初始化提前到服务器启动时 -->
? ? ? ? ?<load-on-startup>1</load-on-startup>
? ? ?</servlet>
? ? ?<servlet-mapping>
? ? ? ? ?<servlet-name>springMVC</servlet-name>
? ? ? ? ?<url-pattern>/</url-pattern>
? ? ?</servlet-mapping>
?</web-app>

4、创建控制器

?@Controller
?public class HelloController {
? ? ?@RequestMapping("/")
? ? ?public String index(){
? ? ? ? ?return "index";
? ?  }
? ? ?@RequestMapping("/target")
? ? ?public String target(){
? ? ? ? ?return "target";
? ?  }
?}

5、创建并配置springMVC.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:context="http://www.springframework.org/schema/context"
? ? ? ? xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
? ? ?<!-- 扫描组件 -->
? ? ?<context:component-scan base-package="com.springmvc.controller"></context:component-scan>
? ? ?<!-- 配置视图解析器 -->
? ? ?<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
? ? ? ? ?<!-- 视图解析器的优先级 -->
? ? ? ? ?<property name="order" value="1"></property>
? ? ? ? ?<!-- 视图解析器的编码 -->
? ? ? ? ?<property name="characterEncoding" value="UTF-8"></property>
? ? ? ? ?<!-- 视图解析器的模板 -->
? ? ? ? ?<property name="templateEngine">
? ? ? ? ? ? ?<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
? ? ? ? ? ? ? ? ?<property name="templateResolver">
? ? ? ? ? ? ? ? ? ? ?<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
? ? ? ? ? ? ? ? ? ? ? ? ?<!-- 前缀 -->
? ? ? ? ? ? ? ? ? ? ? ? ?<property name="prefix" value="/WEB-INF/templates/"></property>
? ? ? ? ? ? ? ? ? ? ? ? ?<!-- 后缀 -->
? ? ? ? ? ? ? ? ? ? ? ? ?<property name="suffix" value=".html"></property>
? ? ? ? ? ? ? ? ? ? ? ? ?<property name="templateMode" value="HTML5"></property>
? ? ? ? ? ? ? ? ? ? ? ? ?<property name="characterEncoding" value="UTF-8"></property>
? ? ? ? ? ? ? ? ? ? ?</bean>
? ? ? ? ? ? ? ? ?</property>
? ? ? ? ? ? ?</bean>
? ? ? ? ?</property>
? ? ?</bean>
?</beans>

6、访问首页和指定页面
????????(1)、访问首页

?<!DOCTYPE html>
?<html lang="en" xmlns:th="http://www.thymeleaf.org">
?<head>
? ? ?<meta charset="UTF-8">
? ? ?<title>首页</title>
?</head>
?<body>
?<a th:href="@{/target}">target</a>
?</body>
?</html>

(2)、访问指定页面

<!DOCTYPE html>
?<html lang="en" xmlns:th="http://www.thymeleaf.org">
?<head>
? ? ?<meta charset="UTF-8">
? ? ?<title>target</title>
?</head>
?<body>
?HelloWorld
?</body>
?</html>

7、执行流程
????????(1)、用户点击某个请求路径,发起一个 HTTP request 请求,该请求会被提交到 DispatcherServlet(前端控制器)
????????(2)、由 DispatcherServlet 请求一个或多个 HandlerMapping(处理器映射器),并返回一个执行链(HandlerExecutionChain)
????????(3)、DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器)
????????(4)、HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(常称为 Controller)
????????(5)、Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC的底层对象,包括 Model 数据模型和 View 视图信息)
????????(6)、HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet
????????(7)、DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析
????????(8)、ViewResolver 根据 View 信息匹配到相应的视图结果,并返回给 DispatcherServlet
????????(9)、DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图)
????????(10)、视图负责将结果显示到浏览器(客户端)

三、注解、类型

(一)、@RequestMapping

1、作用:将请求和处理请求的控制器方法进行关联
2、位置
????????(1)、类:设置映射请求的路径的初始信息
????????(2)、方法:设置映射请求路径的具体信息
3、属性
????????(1)、value:通过请求的地址匹配进行映射,可以匹配多个地址进行映射,且必须设置该属性

?@RequestMapping(value="/userAdd")
?public String userAdd(){
? ? ?return "add";
?}

????????(2)、method:通过请求方式匹配请求映射,可以匹配多种请求方式,不满足就报:405 - Request method "POST" not supported

?@RequestMapping(value="/userAdd",method=RequestMethod.POST)
?public String userAdd(){
? ? ?return "add";
?}

????????(3)、params:通过请求的请求参数匹配请求,可以匹配多种请求参数,且要同时满足

?@RequestMapping(value="/userAdd",params={"username"})
?public String userAdd(){
? ? ?return "add";
?}

????????(4)、headers:通过请求的请求头信息匹配映射

?@RequestMapping(value="/userAdd",headers="Host:localhost:8080")
?public String userAdd(){
? ? ?return "add";
?}

4、派生注解
????????(1)、@GetMapping:处理get请求映射
????????(2)、@PostMapping:处理post请求映射
????????(3)、@DeleteMapping:处理delete请求映射
????????(4)、@PutMapping:处理put请求映射

(二)、@RequestParam

1、作用:将请求参数和控制器方法的形参进行映射关系
2、示例

?@RequestMapping(value="/userAdd")
?public String userAdd(@RequestParam("name")String username,@RequestParam("pwd")String password){
? ? ?return "add";
?}

(三)、@RequestHesder

1、作用:将请求头信息和控制器方法的形参进行映射关系
2、示例

?@RequestMapping(value="/userAdd")
?public String userAdd(@RequestHesder("host")String username){
? ? ?return "add";
?}

(四)、@CookieValue

1、作用:将cookie数据信息和控制器方法的形参进行映射关系
2、示例

?@RequestMapping(value="/userAdd")
?public String userAdd(@RequestHesder("cookie")String cookie){
? ? ?return "add";
?}

(五)、@RequestBody

1、作用:将请求的请求体和当前注解所标识的形参赋值
2、示例

@RequestMapping("/param")
?public String testRequestBody(@RequestBody String requestBody){
? ? ?System.out.println("requestBody"+requestBody);
? ? ?return "param";
?}

(六)、RequestEnitty

1、作用:在控制器方法的形参设置该类型时,请求报文信息会自动赋值
2、示例

?@RequestMapping("/param")
?public String testRequestEntity(RequestEntity<String> requestEntity){
? ? ?System.out.println("请求头"+requestEntity.getHeaders());
? ? ?System.out.println("请求体"+requestEntity.getBodty());
? ? ?return "param";
?}

(七)、@ResponseBody

1、作用:在控制器方法上标识,可以将方法的返回值直接作为响应体响应打浏览器中
2、示例

?@RequestMapping("/param")
?@ResponseBody
?public String testResponseBody(){
? ? ?return "param";
?}

(八)、@RestController

1、作用:给当前类所有的方法加上@ResponseBody
2、示例

?@RestController
?public class EmployeeController {
? ? ?@RequestMapping("/param")
? ? ?public String testResponseBody(){
? ? ? ? ?return "param";
? ?  }
? ? ?@RequestMapping("/param")
? ? ?public String testRequestEntity(RequestEntity<String> requestEntity){
? ? ? ? ?System.out.println("请求头"+requestEntity.getHeaders());
? ? ? ? ?System.out.println("请求体"+requestEntity.getBodty());
? ? ? ? ?return "param";
? ?  }
?}

(九)、ResponseEntity

1、作用:用于控制器方法的返回值类型,该类型是返回值就是响应到浏览器的响应报文
2、示例

@RequestMapping("/hello") 
?public ResponseEntity<String> hello() {
? ? ?return new ResponseEntity<>("Hello World!", HttpStatus.OK);
?}

四、域对象

(一)、Repuest

1、servletAPI

?@RequestMapping("/param")
?public String testServletAPI(HttpServletRequest request){
? ? ?request.setAttribute("Scoke","servletAPI");
? ? ?return "param";
?}

2、ModelAndView

?@RequestMapping("/param")
?public ModelAndView testModelAndViewI(){
? ? ?//创建ModelAndView对象
? ? ?ModelAndView mav = new ModelAndView();
? ? ?//向请求域共享数据
? ? ?mav.addObject("Scoke","ModelAndView");
? ? ?//设置视图,实现页面跳转
? ? ?mav.setViewName("param");
? ? ?return mav;
?}

3、Model

?@RequestMapping("/param")
?public String testModel(Model model){
? ? ?model.addAttriubute("Scoke","Model");
? ? ?return "param";
?}

4、Map

?@RequestMapping("/param")
?public String testMap(Map<String,Object> map){
? ? ?map.put("Scoke","Map");
? ? ?return "param";
?}

5、ModelMap

?@RequestMapping("/param")
?public String testModelMap(ModelMap modelMap){
? ? ?modelMap.addAttriubute("Scoke","ModelMap");
? ? ?return "param";
?}

(二)、Session

?@RequestMapping("/param")
?public String testSession(HttpSession Session){
? ? ?session.setAttriubute("Scoke","Session");
? ? ?return "param";
?}

(三)、Application

?@RequestMapping("/param")
?public String testApplication(HttpSession Session){
? ? ?ServletContext application = session.getServletContext();
? ? ?application.setAttriubute("Scoke","Application");
? ? ?return "param";
?}

五、视图

(一)、Thymeleaf

?@RequestMapping("/param")
?public String testThymeleaf(){
? ? ?return "param";
?}

(二)、InternalResourceView

?@RequestMapping("/param")
?public String testForward(){
? ? ?return "forward:/param";
?}

(三)、RedirectView

?@RequestMapping("/param")
?public String testRedirectf(){
?    return "redirect:/param";
?}

(四)、view-controller

?<!-- 视图控制器 -->
?<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
??
?<!-- 开启注解驱动 -->
?<mvc:annotation-driven>

(六)、InternalResourceViewResolver

?<!-- 配置视图解析器 jsp页面 -->
?<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
? ? ?<property name="prefix" value="/WEB—INF/templares/"></property>
? ? ?<property name="suffix" value=".jsp"></property>
?</bean>

六、RESTFurl

(一)、简介

1、概述:是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义
2、特点
????????(1)、每一个URI代表1种资源;
????????(2)、客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作
????????(3)、通过操作资源的表现形式来操作资源;
????????(4)、资源的表现形式是XML或者HTML
????????(5)、客户端与服务端之间的交互在请求之间是无状态的
????????3、资源:看待服务器的方式,即将服务器看作很多高校的资源组成
????????4、资源表述:是一段对于资源在某个特定时刻的状态的描述
????????5、状态转移:指客户端和服务器端之间转移,实现操作资源的目的

(二)、实现

1、基本操作:GET(获取)、POST(新建)、PUT(更新)、DELETE(删除)
2、示例

@Controller
?public class EmployeeController {
? ? ?@Autowired
? ? ?private EmployeeDao employeeDao;
? ? ?//查询所有的信息
? ? ?@RequestMapping(value = "/employee",method = RequestMethod.GET)
? ? ?public String getAllEmployee(Model model){
? ? ? ? ?Collection<Employee> employeesList = employeeDao.getAll();
? ? ? ? ?model.addAttribute("employeesList",employeesList);
? ? ? ? ?return "employee_List";
? ?  }
? ? ?//根据Id进行删除
? ? ?@RequestMapping(value = "/employee/{id}",method = RequestMethod.DELETE)
? ? ?public String deleteEmployee(@PathVariable("id")Integer id){
? ? ? ? ?employeeDao.delete(id);
? ? ? ? ?return "redirect:/employee";
? ?  }
? ? ?//添加信息
? ? ?@RequestMapping(value = "/employee",method = RequestMethod.POST)
? ? ?public String addEmployee(Employee employee){
? ? ? ? ?employeeDao.save(employee);
? ? ? ? ?return "redirect:/employee";
? ?  }
? ? ?//根据Id查询信息
? ? ?@RequestMapping(value = "/employee/{id}",method = RequestMethod.GET)
? ? ?public String getEmployeeById(@PathVariable("id")Integer id,Model model){
? ? ? ? ?Employee employee = employeeDao.get(id);
? ? ? ? ?model.addAttribute("employee",employee);
? ? ? ? ?return "employee_update";
? ?  }
? ? ?//修改信息
? ? ?@RequestMapping(value = "/employee",method = RequestMethod.PUT)
? ? ?public String updateEmployee(Employee employee){
? ? ? ? ?employeeDao.save(employee);
? ? ? ? ?return "redirect:/employee";
? ?  }
?}

3、注意事项:使用PUT和DELETE时要加入配置HiddenHttpMethodFilter过滤器,还要开始的请求方式必须为POST,还要设置_method属性,值为put或delete,大小写无所谓

?<!-- 配置HiddenHttpMethodFilter -->
?<filter>
? ? ?<filter-name>HiddenHttpMethodFilter</filter-name>
? ? ?<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
?</filter>
?<filter-mapping>
? ? ?<filter-name>HiddenHttpMethodFilter</filter-name>
? ? ?<url-pattern>/*</url-pattern>
?</filter-mapping>

七、静态资源

?<!-- 开放对静态资源的访问 -->
?<mvc:default-servlet-handler></mvc:default-servlet-handler>
??
?<!-- 开启注解驱动 -->
?<mvc:annotation-driven></mvc:annotation-driven>

八、HttpMessageConverter

1、概述:请求报文转换器
2、作用:将请求报文转换为java对象,或将java对象转换为响应报文
3、使用:提供了两个注解和两个类型@RequestBody、@ResponseBody、RequestEnitty、ResponseEntity
4、处理JSON数据
????????(1)、导入依赖

?<!-- 处理JSON数据 -->
?<dependency>
? ? ?<groupId>com.fasterxml.jackson.core</groupId>
? ? ?<artifactId>jackson-databind</artifactId>
? ? ?<version>2.13.1</version>
?</dependency>

????????(2)、加入注解驱动

<!-- 开启注解驱动 -->
?<mvc:annotation-driven></mvc:annotation-driven>

????????(3)、在方法上加入@ResponseBody注解 ?
????????(4)、测试
5、处理ajax ?
???????? (1)、下载vue、axios的js文件

?vue ---> https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js
?axios --> https://unpkg.com/axios/dist/axios.min.js

????????(2)、创建Vue实例

?new Vue({
? ? ?el:"#app",
? ? ?methods:{
? ? ? ? ?textAxios:function (ecent){
? ? ? ? ? ? ?axios({
? ? ? ? ? ? ? ? ?method:"post",
? ? ? ? ? ? ? ? ?url:event.target.href,
? ? ? ? ? ? ? ? ?params:{
? ? ? ? ? ? ? ? ? ? ?username:"admin",
? ? ? ? ? ? ? ? ? ? ?password:"123456"
? ? ? ? ? ? ? ?  }
? ? ? ? ? ?  }).then(function (response){
? ? ? ? ? ? ? ? ?alert(response.data);
? ? ? ? ? ?  });
? ? ? ? ? ? ?ecent.preventDefault();
? ? ? ?  }
? ?  }
?});

????????(3)、测试

九、文件下载上传

1、文件下载

@RequestMapping("/textDown")
?public ResponseEntity<byte[]> testResponseEntity(HttpSession session){
? ? ?ResponseEntity<byte[]> responseEntity = null;
? ? ?try {
? ? ? ? ?//获取ServletContext对象
? ? ? ? ?ServletContext servletContext = session.getServletContext();
? ? ? ? ?//获取服务器中的文件的真实路径
? ? ? ? ?String realPath = servletContext.getRealPath("/static/img/1.jpg");
? ? ? ? ?System.out.println(realPath);
? ? ? ? ?//创建输入流
? ? ? ? ?InputStream is = new FileInputStream(realPath);
? ? ? ? ?//创建字节数组
? ? ? ? ?byte[] bytes = new byte[is.available()];
? ? ? ? ?//将流读取到数组
? ? ? ? ?is.read(bytes);
? ? ? ? ?//创建响应头信息
? ? ? ? ?MultiValueMap<String,String> multiValueMap = new HttpHeaders();
? ? ? ? ?//设置下载方式和下载文件的名字
? ? ? ? ?multiValueMap.add("Content-Disposition","attachment;filename=1.jpg");
? ? ? ? ?//设置相应状态码
? ? ? ? ?HttpStatus status = HttpStatus.OK;
? ? ? ? ?//创建 ResponseEntity对象
? ? ? ? ?responseEntity = new ResponseEntity<byte[]>(bytes,multiValueMap,status);
? ? ? ? ?//关闭流
? ? ? ? ?is.close();
? ?  } catch (Exception e) {
? ? ? ? ?e.printStackTrace();
? ?  }
? ? ?return responseEntity;
?}

2、文件上传
????????(1)、导入依赖

?<!-- 上传文件 -->
?<dependency>
? ? ?<groupId>commons-fileupload</groupId>
? ? ?<artifactId>commons-fileupload</artifactId>
? ? ?<version>1.3.1</version>
?</dependency>

????????(2)、配置文件上传解析器

?<!-- 配置文件上传解析器 -->
?<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

????????(3)、上传方法

?@RequestMapping("/textUp")
?public void textUp(MultipartFile multipartFile, HttpSession session) {
? ? ?try {
? ? ? ? ?//获取文件名字
? ? ? ? ?String fileName = multipartFile.getOriginalFilename();
? ? ? ? ?//获取文件的后缀名
? ? ? ? ?String suffixName = fileName.substring(fileName.lastIndexOf("."));
? ? ? ? ?//将UUID作为文件名
? ? ? ? ?String uuid = UUID.randomUUID().toString().replace("-","");
? ? ? ? ?//新的文件名
? ? ? ? ?String newName = uuid + suffixName;
? ? ? ? ?//获取ServletContext对象
? ? ? ? ?ServletContext servletContext = session.getServletContext();
? ? ? ? ?//获取服务器中的文件的真实路径
? ? ? ? ?String realPath = servletContext.getRealPath("photo");
? ? ? ? ?File file = new File(realPath);
? ? ? ? ?//判断目录是否存在
? ? ? ? ?if (!file.exists()) {
? ? ? ? ? ? ?//不存在就创建
? ? ? ? ? ? ?file.mkdir();
? ? ? ?  }
? ? ? ? ?//拼接名字
? ? ? ? ?String finalPath = realPath + File.separator + newName;
? ? ? ? ?//资源转移
? ? ? ? ?multipartFile.transferTo(new File(fileName));
? ?  } catch (Exception e) {
? ? ? ? ?e.printStackTrace();
? ?  }
?}

十、拦截器

1、作用:用于拦截控制器方法的执行
2、示例
????????(1)、实现拦截器

?@Component
?public class FirstInterceptor implements HandlerInterceptor {
? ? ?@Override
? ? ?public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
? ? ? ? ?System.out.println("方法执行之前");
? ? ? ? ?return false;
? ?  }
? ? ?@Override
? ? ?public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
? ? ? ? ?System.out.println("方法执行之后");
? ?  }
? ? ?@Override
? ? ?public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
? ? ? ? ?System.out.println("视图渲染之后");
? ?  }
?}

????????(2)、配置拦截器

?<!-- 配置拦截器 -->
?<mvc:interceptors>
? ? ?<!-- <bean class="com.mvc.Interceptor.FirstInterceptor"></bean> 对所有的控制器方法请求都进行拦截 -->
? ? ?<!-- <ref bean="firstInterceptor"></ref>  对所有的控制器方法请求都进行拦截 -->
? ? ?<mvc:interceptor>
? ? ? ? ?<mvc:mapping path="/**"/><!-- 对那些方法进行拦截 -->
? ? ? ? ?<mvc:exclude-mapping path="/"/><!-- 对那些方法不拦截 -->
? ? ? ? ?<bean class="com.mvc.Interceptor.FirstInterceptor"></bean>
? ? ?</mvc:interceptor>
?</mvc:interceptors>

3、多个拦截器的执行的步骤
????????(1)、若每个拦截器的preHandle()都返回true,此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关。preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行
????????(2)、若某个拦截器的preHandle()返回false,preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的afterCompletion()会执行

十一、异常处理器

1、基于配置文件

?<!-- 异常处理器 -->
?<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
? ? ?<property name="exceptionMappings"><!-- 出现异常后跳转到指定页面 -->
? ? ? ? ?<props>
? ? ? ? ? ? ?<prop key="java.lang.ArithmeticException">error</prop>
? ? ? ? ?</props>
? ? ?</property>
? ? ?<property name="exceptionAttribute" value="ex"></property><!-- 将出现的异常的在请求域中进行共享 -->
?</bean>

2、基于注解

@ControllerAdvice
?public class ExceptionController {
? ? ?@ExceptionHandler(ArithmeticException.class)
? ? ?public String ?handleArithmeticException(Exception ex, Model model){
? ? ? ? ?model.addAttribute("ex",ex);
? ? ? ? ?return "error";
? ?  }
?}

十四、注解配置

1、配置web.xml

?import org.springframework.web.filter.CharacterEncodingFilter;
?import org.springframework.web.filter.HiddenHttpMethodFilter;
?import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
?import javax.servlet.Filter;
?/**
? * @author: 海
? * @version: 1.0
? */
?public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
? ? ?/**
? ? ? * 指定spring配置类
? ? ? * @return: java.lang.Class<?>[]
? ? ? */
? ? ?@Override
? ? ?protected Class<?>[] getRootConfigClasses() {
? ? ? ? ?return new Class[]{SpringConfig.class};
? ?  }
? ? ?/**
? ? ? * 指定springmvc的配置类
? ? ? * @return: java.lang.Class<?>[]
? ? ? */
? ? ?@Override
? ? ?protected Class<?>[] getServletConfigClasses() {
? ? ? ? ?return new Class[]{WebConfig.class};
? ?  }
? ? ?/**
? ? ? * 指定DispatcherServlet的映射规则
? ? ? * @return: java.lang.String[]
? ? ? */
? ? ?@Override
? ? ?protected String[] getServletMappings() {
? ? ? ? ?return new String[]{"/"};
? ?  }
? ? ?/**
? ? ? * 指定Filter的配置类
? ? ? * @return: javax.servlet.Filter[]
? ? ? */
? ? ?@Override
? ? ?protected Filter[] getServletFilters() {
? ? ? ? ?// 处理中文乱码问题
? ? ? ? ?CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
? ? ? ? ?characterEncodingFilter.setEncoding("UTF-8");
? ? ? ? ?characterEncodingFilter.setForceResponseEncoding(true);
? ? ? ? ?// 将请求方式转换
? ? ? ? ?HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
? ? ? ? ?return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
? ?  }
?}

2、创建spring.xml的配置类

?import org.springframework.context.annotation.Configuration;
?/**
? * @author: 海
? * @version: 1.0
? */
?@Configuration
?public class SpringConfig {
?}

3、配置springmvc.xml的配置类

?import com.springmvc.hander.FirstInterceptor;
?import org.springframework.context.annotation.Bean;
?import org.springframework.context.annotation.ComponentScan;
?import org.springframework.context.annotation.Configuration;
?import org.springframework.web.context.ContextLoader;
?import org.springframework.web.context.WebApplicationContext;
?import org.springframework.web.multipart.MultipartResolver;
?import org.springframework.web.multipart.commons.CommonsMultipartResolver;
?import org.springframework.web.servlet.HandlerExceptionResolver;
?import org.springframework.web.servlet.ViewResolver;
?import org.springframework.web.servlet.config.annotation.*;
?import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
?import org.thymeleaf.spring5.SpringTemplateEngine;
?import org.thymeleaf.spring5.view.ThymeleafViewResolver;
?import org.thymeleaf.templatemode.TemplateMode;
?import org.thymeleaf.templateresolver.ITemplateResolver;
?import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
?import javax.servlet.ServletContext;
?import java.util.List;
?import java.util.Properties;
?/**
? * @author: 海
? * @version: 1.0
? */
?@Configuration
?@ComponentScan("com.springmvc")
?@EnableWebMvc
?public class WebConfig implements WebMvcConfigurer {
? ? ?/**
? ? ? * default - servlet - handler
? ? ? */
? ? ?@Override
? ? ?public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
? ? ? ? ?configurer.enable();
? ?  }
? ? ?/**
? ? ? * 拦截器
? ? ? */
? ? ?@Override
? ? ?public void addInterceptors(InterceptorRegistry registry) {
? ? ? ? ?FirstInterceptor firstInterceptor = new FirstInterceptor();
? ? ? ? ?registry.addInterceptor(firstInterceptor).addPathPatterns("/**");
? ?  }
? ? ?/**
? ? ? * 视图控制器
? ? ? */
? ? ?@Override
? ? ?public void addViewControllers(ViewControllerRegistry registry) {
? ? ? ? ?registry.addViewController("").setViewName("");
? ?  }
? ? ?/**
? ? ? * 文件上传解析器
? ? ? */
? ? ?@Bean
? ? ?public MultipartResolver multipartResolver() {
? ? ? ? ?return new CommonsMultipartResolver();
? ?  }
? ? ?/**
? ? ? * 异常处理器
? ? ? */
? ? ?@Override
? ? ?public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
? ? ? ? ?SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
? ? ? ? ?Properties properties = new Properties();
? ? ? ? ?properties.setProperty("java.lang.ArithmeticException", "error");
? ? ? ? ?simpleMappingExceptionResolver.setExceptionMappings(properties);
? ? ? ? ?simpleMappingExceptionResolver.setExceptionAttribute("exception");
? ? ? ? ?resolvers.add(simpleMappingExceptionResolver);
? ?  }
? ? ?/**
? ? ? * 配置生成模板解析器
? ? ? */
? ? ?@Bean
? ? ?public ITemplateResolver templateResolver() {
? ? ? ? ?WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
? ? ? ? ?if(webApplicationContext==null){
? ? ? ? ? ? ?return null;
? ? ? ?  }
? ? ? ? ?ServletContext servletContext = webApplicationContext.getServletContext();
? ? ? ? ?if(servletContext==null){
? ? ? ? ? ? ?return null;
? ? ? ?  }
? ? ? ? ?ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
? ? ? ? ?templateResolver.setPrefix("/WEB-INF/templates/");
? ? ? ? ?templateResolver.setSuffix(".html");
? ? ? ? ?templateResolver.setCharacterEncoding("UTF-8");
? ? ? ? ?templateResolver.setTemplateMode(TemplateMode.HTML);
? ? ? ? ?return templateResolver;
? ?  }
? ? ?/**
? ? ? * 生成模板引擎为模板注入模板解析器
? ? ? */
? ? ?@Bean
? ? ?public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
? ? ? ? ?SpringTemplateEngine templateEngine = new SpringTemplateEngine();
? ? ? ? ?templateEngine.setTemplateResolver(templateResolver);
? ? ? ? ?return templateEngine;
? ?  }
? ? ?/**
? ? ? * 生成视图解析器并为解析器注入模版引擎
? ? ? */
? ? ?@Bean
? ? ?public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
? ? ? ? ?ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
? ? ? ? ?viewResolver.setCharacterEncoding("UTF-8");
? ? ? ? ?viewResolver.setTemplateEngine(templateEngine);
? ? ? ? ?return viewResolver;
? ?  }
?}

十五、SpringMVC的常用组件

1、DispatcherServlet:前端控制器
????????(1)、是否需要工程师开发:不需要
????????(2)、作用:统一处理请求和响应,整个流程控制的中心,由它调用其他组件处理用户的请求
2、HandlerMapping:处理器映射器
????????(1)、是否需要工程师开发:不需要
????????(2)、作用:根据请求的url、method等信息查找Handler,即控制器方法
3、Handler:处理器
????????(1)、是否需要工程师开发:需要
????????(2)、作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
4、HandlerAdapter:处理器适配器
????????(1)、是否需要工程师开发:不需要
????????(2)、作用:通过HandlerAapter对处理器进行执行
5、ViewResolver:视图解析器
???????? (1)、是否需要工程师开发:不需要
????????(2)、作用:进行视图解析、的到响应的视图
6、View:视图
????????(1)、是否需要工程师开发:不需要
????????(2)、作用:将模型数据通过页面展示给用户

Mybatis

一、概述

1、概述:是一个基于Java的持久层框架
2、特性
????????(1)、是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
????????(2)、避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
????????(3)、可以使用简单的XML或注解用于配置和原始映射,将接口和java的POJO映射成数据库的记录
????????(4)、是一个半启动的ORM框架
3、官网:Mybatis
4、与其它持久化层技术对比?
? ? ? ? (1)、JDBC
????????????????①、SQL夹杂在Java代码中,耦合度高,导致硬编码内伤
????????????????②、维护不易且实际开发需求中SQL有变化,频繁修改的情况多见
????????????????③、代码冗长,开发效率低
????????(2)、Hibemate和JPA
????????????????①、操作简便,开发效率高
????????????????②、程序中的长难度复杂的SQL需要绕过框架
????????????????③、内部自动生产的SQL,不容易做特殊优化
????????????????④、基于全映射的全自动框架,大量字段的POJO进行部分映射比较困难
????????????????⑤、反射操作太多,导致数据性能下降
????????(3)、Mybatis
????????????????①、轻量级,性能出色
????????????????②、SQL和java代码分开,功能边界清晰,java代码专注业务、SQL语句专注数据
????????????????③、开发效率稍逊Hibemate,但是能完全接受
5、相应的API
????????(1)、SqlSessionFactoryBuilder:工厂构建器
????????(2)、SqlSessionFactory:获取工厂对象
????????????????①、openSession():默认开启开启一个事务,但要手动提交
????????????????②、openSession(boolean auto):为true时,自动提交
????????(3)、SqlSession:会话对象
????????????????①、查询单个:<T> T selectone (string statement, Object parameter)
????????????????②、查询全部:<E> List<E>kselectList (String statement, object parameter)
????????????????③、插入数据:int insert (String statement, Object parame ter)
????????????????④、修改数据:int update (String statement, Object parameter)
????????????????⑤、删除数据:int delete (String statement, Object parameter)
????????????????⑥、提交事务:void commit()
????????????????⑦、回滚事务:void rollback()
????????????????⑧、获取接口的字节码文件:<T> T getMapper(Class<T> var1)
6、mapper接口开发规范
????????(1)、Mapper.xml文件中的namespace与mapper接口的全限定名相同
????????(2)、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
????????(3)、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
????????(4)、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

二、搭建框架

1、环境
????????(1)、IDE:IDEA 2021.1.2
????????(2)、构建工具:maven3.8.2
????????(3)、MySQl版本:8.0
????????(4)、Mybatis版本:3.5.9
2、创建maven工程

<dependencies>
? ? ?<!-- mybatis -->
? ? ?<dependency>
? ? ? ? ?<groupId>org.mybatis</groupId>
? ? ? ? ?<artifactId>mybatis</artifactId>
? ? ? ? ?<version>3.5.9</version>
? ? ?</dependency>
? ? ?<!-- 测试 -->
? ? ?<dependency>
? ? ? ? ?<groupId>junit</groupId>
? ? ? ? ?<artifactId>junit</artifactId>
? ? ? ? ?<version>4.13.1</version>
? ? ? ? ?<scope>test</scope>
? ? ?</dependency>
? ? ?<!-- 日志 -->
? ? ?<dependency>
? ? ? ? ?<groupId>log4j</groupId>
? ? ? ? ?<artifactId>log4j</artifactId>
? ? ? ? ?<version>1.2.12</version>
? ? ?</dependency>
? ? ?<!-- lombok -->
? ? ?<dependency>
? ? ? ? ?<groupId>org.projectlombok</groupId>
? ? ? ? ?<artifactId>lombok</artifactId>
? ? ? ? ?<version>1.18.22</version>
? ? ?</dependency>
?</dependencies>

3、创建数据库的表和实体

create table `user`(
?    `id` int(0) not null primary key auto_increment comment '主键',
?    `username` varchar(255) not null,
?    `password` varchar(255) not null
?)
?import lombok.AllArgsConstructor;
?import lombok.Data;
?import lombok.NoArgsConstructor;
?@Data
?@AllArgsConstructor
?@NoArgsConstructor
?public class User {
? ? ?private Integer id;
? ? ?private String username;
? ? ?private String password;
?}

4、创建映射文件

?<?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="mybatis.mapper.UserMapper">
? ? ?<!-- 查询全部 -->
? ? ?<select id="findUser" resultType="mybatis.entity.User">
? ? ? ?  select * from user
? ? ?</select>
? ? ?<!-- 添加 -->
? ? ?<insert id="addUser" parameterType="mybatis.entity.User">
? ? ? ?  insert into user values(#{id},#{username},#{password})
? ? ?</insert>
? ? ?<!-- 修改 -->
? ? ?<update id="updateUser" parameterType="mybatis.entity.User">
? ? ? ?  update user set username=#{username},password=#{password} where id=#{id}
? ? ?</update>
? ? ?<!-- 删除 -->
? ? ?<delete id="deleteUser" parameterType="java.lang.Integer">
? ? ? ?  delete from user where id=#{id}
? ? ?</delete>
?</mapper>

5、创建核心文件

?<?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.cj.jdbc.Driver"/>
? ? ? ? ? ? ? ? ?<property name="url" value="jdbc:mysql://localhost:3306/practice"/>
? ? ? ? ? ? ? ? ?<property name="username" value="root"/>
? ? ? ? ? ? ? ? ?<property name="password" value="root"/>
? ? ? ? ? ? ?</dataSource>
? ? ? ? ?</environment>
? ? ?</environments>
? ? ?<!-- 加载映射文件 -->
? ? ?<mappers>
? ? ? ? ?<mapper resource="mapper/UserMapper.xml"></mapper>
? ? ?</mappers>
?</configuration>

6、测试增删改查

import mybatis.entity.User;
?import org.apache.ibatis.io.Resources;
?import org.apache.ibatis.session.SqlSession;
?import org.apache.ibatis.session.SqlSessionFactory;
?import org.apache.ibatis.session.SqlSessionFactoryBuilder;
?import org.junit.Test;
?import java.io.IOException;
?import java.io.InputStream;
?import java.util.List;
?public class UserMapperTest {
? ? ?public static SqlSession sqlSession() {
? ? ? ? ?SqlSession sqlSession = null;
? ? ? ? ?try {
? ? ? ? ? ? ?InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
? ? ? ? ? ? ?SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
? ? ? ? ? ? ?sqlSession = sqlSessionFactory.openSession(true);
? ? ? ?  } catch (IOException e) {
? ? ? ? ? ? ?e.printStackTrace();
? ? ? ?  }
? ? ? ? ?return sqlSession;
? ?  }
? ? ?@Test
? ? ?public void findUser() {
? ? ? ? ?SqlSession sqlSession = sqlSession();
? ? ? ? ?List<Object> list = sqlSession.selectList("mybatis.mapper.UserMapper.findUser");
? ? ? ? ?System.out.println(list);
? ? ? ? ?sqlSession.close();
? ?  }
? ? ?@Test
? ? ?public void addUser() {
? ? ? ? ?User user = new User(null,"tom","123");
? ? ? ? ?SqlSession sqlSession = sqlSession();
? ? ? ? ?sqlSession.insert("mybatis.mapper.UserMapper.addUser",user);
? ? ? ? ?sqlSession.commit();
? ? ? ? ?sqlSession.close();
? ?  }
? ? ?@Test
? ? ?public void updateUser() {
? ? ? ? ?User user = new User(4,"tom","123");
? ? ? ? ?SqlSession sqlSession = sqlSession();
? ? ? ? ?sqlSession.update("mybatis.mapper.UserMapper.updateUser",user);
? ? ? ? ?sqlSession.commit();
? ? ? ? ?sqlSession.close();
? ?  }
? ? ?@Test
? ? ?public void deleteUser() {
? ? ? ? ?SqlSession sqlSession = sqlSession();
? ? ? ? ?sqlSession.delete("mybatis.mapper.UserMapper.deleteUser",5);
? ? ? ? ?sqlSession.commit();
? ? ? ? ?sqlSession.close();
? ?  }
?}

三、映射配置文件
(一)、模板

1、IDEA:点击File,然后在点击Settings,然后再点击Editor,再点击File and Code Templates,然后在Files下的+号进行点击,再然后Name,输入名字mybatis-mapper,再在Extension,输入后缀名xml,然后再在下面的输入框中输入信息,最后点击Apply,再点击OK,就完成映射配置文件的模板的创建

(二)、mapper

1、属性
????????(1)、namespace:命名空间
2、子标签:select、insert、update、delete
????????(1)、概述:增删改查
????????(2)、属性
????????????????①、id:语句的唯一标识
????????????????②、resultType:查询结果返回的数据类型
????????????????③、parameterType:传入的参数的类型或别名
????????????????④、resultMap:引入外部resultMap的引用,不能和resultType一起使用
????????(3)、子标签:if、where、foreach、sql
3、获取参数值的两种方式
????????(1)、${}:字符串拼接,要注意引号问题
????????(2)、#{}:占位符赋值

(三)、动态SQL

1、概述:根据特定条件动态地去拼接SQL语句的功能
2、if

?List<Emp> getEmpCondition(Emp emp)
<select id="getEmpCondition" resultType="Emp">
? ?  select * from emp where 1=1
? ? ?<if test="empName != null and empName != ''">
? ? ? ?  and empName = #{empName}
? ? ?</if>
? ? ?<if test="age != null and age != ''">
? ? ? ?  and age = #{age}
? ? ?</if>
? ? ?<if test="sex != null and sex != ''">
? ? ? ?  and sex = #{sex}
? ? ?</if>
? ? ?<if test="email != null and email= != ''">
? ? ? ?  and email= #{email=}
? ? ?</if>
?</select>

2、where

?List<Emp> getEmpCondition(Emp emp)
?<select id="getEmpCondition" resultType="Emp">
?    select * from emp 
?    <where>
? ? ? ? ?<if test="empName != null and empName != ''">
? ? ? ? ? ? and empName = #{empName}
? ? ? ? ?</if>
? ? ? ? ?<if test="age != null and age != ''">
? ? ? ? ? ?  and age = #{age}
? ? ? ? ?</if>
? ? ? ? ?<if test="sex != null and sex != ''">
? ? ? ? ? ?  and sex = #{sex}
? ? ? ? ?</if>
? ? ? ? ?<if test="email != null and email= != ''">
? ? ? ? ? ?  and email= #{email=}
? ? ? ? ?</if> ? ?
? ? ?</where>
?</select>

3、trim

?List<Emp> getEmpCondition(Emp emp)
<select id="getEmpCondition" resultType="Emp">
?    select * from emp 
?    <trim prefix="where" suffix="and|or">
? ? ? ? ?<!--
? ? ? ? ? ? ?prefix | suffix:在前面或者后面加上指定内容
? ? ? ? ? ? ?prefixOverrides | suffixOverrides:在前面或者后面去掉指定内容
? ? ? ? ?-->
? ? ? ? ?<if test="empName != null and empName != ''">
? ? ? ? ? ?  empName = #{empName}
? ? ? ? ?</if>
? ? ? ? ?<if test="age != null and age != ''">
? ? ? ? ? ?  age = #{age}
? ? ? ? ?</if>
? ? ? ? ?<if test="sex != null and sex != ''">
? ? ? ? ? ?  sex = #{sex}
? ? ? ? ?</if>
? ? ? ? ?<if test="email != null and email= != ''">
? ? ? ? ? ?  email= #{email=}
? ? ? ? ?</if> 
? ? ?</trim>
?</select>

4、choose、when、otherwise

?List<Emp> getEmpChoose(Emp emp)
?<select id="getEmpChoose" resultType="Emp">
? ?  select * from emp 
?    <where>
? ?      <choose>
? ? ? ?      <when test="empName != null and empName != ''">
?                empName = #{empName}
?            </when>
? ? ? ?      <when test="age != null and age != ''">
?                age = #{age}
?            </when>
? ? ? ?      <when test="sex != null and sex != ''">
?                 sex = #{sex}
?            </when>
?            <otherwise>
? ? ? ? ? ?      did = 1
? ? ? ? ? ? ?</otherwise>
? ? ? ? ?</choose>
? ? ?</where>
?</select>

5、foreach
????????(1)、批量添加

?int addEmps(@Param("emps")List<Emp> emps)
?<insert id="addEmps">
?    <foreach collection="emps" item="emp" separator=",">
? ?      (null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email})
? ? ?</foreach>
?</insert>

????????(2)、批量删除

?int deleteEmp(@Param("eids")Integer[] eids)//数组批量删除
???<delete id="deleteEmp">
?    delete from emp where
?    <foreach collection="eids" item="eid" separator=",">
? ?      eid = #{eid}
? ? ?</foreach>
?</delete>

6、sql

<!-- 定义 -->
?<sql id="empColums">eid,emp_Name,age,sex,email</sql>
??
?<!-- 引用 -->
?<select id="getDeptAndEmpt" resultType="Emp">
? ?  select <include refid="empColums"></include> from emp where did = #{did}
?</select>

四、核心配置文件

(一)、模板

1、IDEA:点击File,然后在点击Settings,然后再点击Editor,再点击File and Code Templates,然后在Files下的+号进行点击,再然后Name,输入名字mybatis-config,再在Extension,输入后缀名xml,然后再在下面的输入框中输入信息,最后点击Apply,再点击OK,就完成核心配置文件的模板的创建

(二)、configuration

1、properties:属性
2、settings:设置
3、typeAliases:类型别名
4、typeHandlers:类型处理器
5、objectFactory:对象工厂
6、plugins:插件
7、environments:环境
????????(1)、environment:环境变量
????????????????①、transactionManager:事务管理器
????????????????②、dataSource:数据源
8、databaseldProvider:数据库厂商标识
9、mappers:映射器

(三)、environment

1、概述:配置数据库的环境
2、属性
????????(1)、id:指定当前环境的名称
3、子标签
????????(1)、transactionManager:事务管理器,它的类型有以下两种
????????????????①、JDBC:直接使用JDBC的提交和回滚设置,依赖于数据源得到的连接来管理事务作用域
????????????????②、MANAGED:从来不提交或回滚连接,而是让容器管理整个生命周期,默认情况下关闭连接,需要将closeConnection属性设置为false来阻止关闭行为
????????(2)、dataSource:数据源,它的类型有三种,它的标签是设置数据库的连接池的基本参数的配置
???????????????①、UNPOOLED:每次请求时打开和关闭连接
???????????????②、POOLED:实现利用"池"的概念将JDBC连接对象组织起来
???????????????③、JNDI:是为了能在如EJB或应用服务器这类容器中使用,容器可以集中或外部配置数据源,然后放置在一个JDNI上下文的引用

(四)、mappers

1、概述:引入映射文件的
2、加载方式
????????(1)、使用相对于类路径的资源引用,例如: <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
????????(2)、使用完全限定资源定位符(URL) ,例如: <mapper url="file:///var/mappers/AuthorMapper.xml"/>
????????(3)、使用映射器接口实现类的完全限定类名,例如: <mapper class="org.mybatis.builder.AuthorMapper"/>
????????(4)、将包内的映射器接口实现全部注册为映射器,例如: <package name="org.mybatis.builder"/>

(五)、properties

1、概述:引入外部properties文件的
2、使用:通过resource标签引入即可

(六)、typeAliases

1、概述:定义类型别名
2、已经定义好的类型别名

数据类型StringIntegrtListArrayListMapHashMapDateObject
别名stringintlistarraylistmaphashmapdateobject

3、注意实现:别名要定义在environments标签的上方

(七)、typeHandlers

1、概述:类型处理器
2、常用类型处理器

类型处理器Java类型数据库类型
BooleanTypeHandlerjava.lang.Boolean,booleanBOOLEAN
ByteTypeHandlerjava.lang.Byte,byteNUMERIC,BYTE
ShortTypeHandlerjava.lang.Short,shortNUMERTC,SHORT INTEGER
IntegerTypeHandlerjava.lang.Integer,intNUMERTC,INTEGER
LongTypeHandlerjava.lang.Long,longNUMERTC,LONGnINTEGER

3、开发步骤
???????? ①、定义转换类,继承类BaseTypeHandler<T>
????????②、覆盖4个未实现的方法,其中setNonNullParameter为java程序设置数据到数据库的回调方法,getNullableResult为查询时mysql的字符串类型转换成java的Type类型的方法
????????③、在MyBatis核心配置文件中进行注册
????????④、测试转换是否正确
4、示例

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
public class DateTypeHandler extends BaseTypeHandler<Date> {
    /**
     * 将java类型转换成数据库需要的类型
     */
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
        long time = date.getTime();
        preparedStatement.setLong(i,time);
    }
    /**
     * 将数据库需要的类型转换成Java类型
     */
    @Override
    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
        long aLong = resultSet.getLong(s);
        Date date = new Date(aLong);
        return date;
    }
    /**
     * 将数据库需要的类型转换成Java类型
     */
    @Override
    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
        long aLong = resultSet.getLong(i);
        Date date = new Date(aLong);
        return date;
    }
    /**
     * 将数据库需要的类型转换成Java类型
     */
    @Override
    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        long aLong = callableStatement.getLong(i);
        Date date = new Date(aLong);
        return date;
    }
}
<!-- 注册自定义类型处理器 -->
<typeHandlers>
    <typeHandler handler="mybatis.handler.DateTypeHandler"></typeHandler>
</typeHandlers>

(八)、plugins

1、概述:可以使用第三方插件进行扩展
2、分页插件
????????(1)、概述:使用插件获取分页数据 (
????????2)、步骤
????????????????①、导入分页插件的坐标
????????????????②、配置插件
????????????????③、测试
????????(3)、示例

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>3.7.5</version>
</dependency>
<dependency>
    <groupId>com.github.jsqlparser</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>0.9.1</version>
</dependency>
<!-- 分页插件 -->
<plugins>
    <plugin interceptor="com.github.pagehelper.PageHelper">
        <property name="dialect" value="mysql"/>
    </plugin>
</plugins>
//设置分页参数
PageHelper.startPage(1,2);

//获取分页相关参数
PageInfo<User> pageInfo = new PageInfo<User>(list);
System.out.println("当前页: " + pageInfo.getPageNum());
System.out.println("页显示条数: " + pageInfo.getPageSize());
System.out.println("总条数: " + pageInfo.getTotal());
System.out.println("总页数: " + pageInfo.getPages());
System.out.println("上一页: " + pageInfo.getPrePage());
System.out.println("下一页: " + pageInfo.getNextPage());
System.out.println("是否为第一页: " + pageInfo.isIsFirstPage());
System.out.println("是否为最后一页: " + pageInfo.isIsLastPage());

五、多表操作

(一)、一对一

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private Boolean age;
    private String sex;
    private StudentStatus studentStatus;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentStatus {
    private Integer id;
    private String num;
    private String major;
}
<mapper namespace="com.mybatis.mapper.StudentMapper">
    <resultMap id="resMap" type="student">
        <result property="studentStatus.id" column="st_id"/>
        <result property="studentStatus.major" column="major"/>
        <result property="studentStatus.num" column="num"/>
    </resultMap>
    <select id="findAll" resultMap="resMap">
        select * from student s, student_status st where s.st_id = st.st_id
    </select>
</mapper>

<mapper namespace="com.mybatis.mapper.StudentMapper">
    <resultMap id="resMap" type="com.mybatis.entity.Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
        <result property="age" column="age"/>
        <association property="studentStatus" javaType="com.mybatis.entity.StudentStatus">
            <result property="id" column="st_id"/>
            <result property="major" column="major"/>
            <result property="num" column="num"/>
        </association>
    </resultMap>
    <select id="findAll" resultMap="resMap">
        select * from student s, student_status st where s.st_id = st.st_id
    </select>
</mapper>

<mapper namespace="com.mybatis.mapper.StudentMapper">
    <resultMap id="resMap" type="student" autoMapping="true">
        <association property="studentStatus" resultMap="stMap" />
    </resultMap>
    <resultMap id="stMap" type="StudentStatus" autoMapping="true"/>
    <select id="findAll" resultMap="resMap">
        select * from student s, student_status st where s.st_id = st.st_id
    </select>
</mapper>
<typeAliases>
    <!-- 类型别名 -->
    <package name="com.mybatis.entity"/>
</typeAliases>
public class MybatisDemo {
    @Test
    public void TestA() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Student> list = sqlSession.selectList("com.mybatis.mapper.StudentMapper.findAll");
        System.out.println(list);
    }
}

(二)、一对多

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer sId;
    private String sName;
    private Long sAge;
    private String sSex;
    private Integer cId;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Class {
    private Integer cId;
    private String cName;
    private String cAddr;
    private List<Student> students;
}
<mapper namespace="com.mybatis.mapper.ClassMapper">
    <resultMap id="resMap" type="Class">
        <result property="cId" column="c_id"/>
        <result property="cName" column="c_name"/>
        <result property="cAddr" column="c_addr"/>
        <collection property="students" ofType="Student">
            <result property="sId" column="s_id" />
            <result property="sName" column="s_name"/>
            <result property="sAge" column="s_age"/>
            <result property="sSex" column="s_sex"/>
            <result property="cId" column="c_id"/>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="resMap">
        select * from student s, class c where s.c_id = c.c_id
    </select>
</mapper>
<typeAliases>
    <!-- 类型别名 -->
    <package name="com.mybatis.entity"/>
</typeAliases>
public class MybatisDemo {
    @Test
    public void TestA() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Class> list = sqlSession.selectList("com.mybatis.mapper.ClassMapper.findAll");
        for (Class aClass : list) {
            System.out.println(aClass);
        }
    }
}

(三)、多对多

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Course {
    private Integer cId;
    private String cName;
    private List<Student> students;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer sId;
    private String sName;
    private Long sAge;
    private String sSex;
    private List<Course> courses;
}
<mapper namespace="com.mybatis.mapper.StudentMapper">
    <resultMap id="resMap" type="Student">
        <result property="sId" column="s_id" />
        <result property="sName" column="s_name"/>
        <result property="sAge" column="s_age"/>
        <result property="sSex" column="s_sex"/>
        <collection property="courses" ofType="Course">
           <result property="cId" column="c_id"/>
            <result property="cName" column="c_name"/>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="resMap">
        select * from course c, student s, s_c sc where c.c_id = sc.c_id and s.s_id = sc.s_id
    </select>
</mapper>
<typeAliases>
    <!-- 类型别名 -->
    <package name="com.mybatis.entity"/>
</typeAliases>
public class MybatisDemo {
    @Test
    public void TestA() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Course> courseList = sqlSession.selectList("com.mybatis.mapper.CourseMapper.findAll");
        List<Student> studentList = sqlSession.selectList("com.mybatis.mapper.StudentMapper.findAll");
        System.out.println("### 课程 ###");
        for (Course course : courseList) {
            System.out.println(course);
        }
        System.out.println("### 学生 ###");
        for (Student student : studentList) {
            System.out.println(student);
        }
    }
}

六、注解开发

(一)、常用注解

1、@Insert:实现新增
2、@Update:实现更新
3、@Delete:实现删除
4、@Select:实现查询
5、@Result:实现结果集封装
6、@Results:可以与
7、@Result:一起使用,封装多个结果集
8、@One:实现一对一结果集封装
9、@Many:实现一对多结果集封装

(二)、单表操作

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
}
import mybatis.entity.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface UserMapper {
    @Insert("insert into user values(#{id},#{username},#{password})")
    void save(User user);
    @Update("update user set username=#{username},password=#{password} where id=#{id}")
    void update(User user);
    @Delete("delete from user where id=#{id}")
    void delete(int id);
    @Select("select * from user where id=#{id}")
    User findById(int id);
    @Select("select * from user")
    List<User> find();
}
<!-- 配置数据源 -->
<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/practice"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        </dataSource>
    </environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
    <package name="mybatis.mapper"/>
</mappers>
import mybatis.entity.User;
import mybatis.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserMapperTest {
    private UserMapper userMapper;
    @Before
    public void sqlSession() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        userMapper = sqlSession.getMapper(UserMapper.class);
    }
    @Test
    public void find() {
        List<User> userList = userMapper.find();
        for (User user : userList) {
            System.out.println(user);
        }
    }
    @Test
    public void findById() {
        User user = userMapper.findById(1);
        System.out.println(user);
    }
    @Test
    public void save() {
        User user = new User(null, "tom", "123");
        userMapper.save(user);
    }
    @Test
    public void update() {
        User user = new User(null, "tom", "123");
        userMapper.update(user);
    }
    @Test
    public void delete() {
        userMapper.delete(1);
    }
}

(三)、多表操作

1、一对一

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Card {
	private Integer id;
	private String number;
	private Person p;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
	private Integer id;
	private String name;
	private Integer age;
}
import com.cmy.bean.Card;
import com.cmy.bean.Person;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface CardMapper {
	@Select("SELECT * FROM card")
	@Results({@Result(column = "id", property = "id"),@Result(column = "number", property = "number"),@Result(property = "p",javaType = Person.class,column = "pid",one = @One(select = "com.mybatis.mapper.PersonMapper.selectById"))})
	public abstract List<Card> selectAll();
}
import com.cmy.bean.Person;
import org.apache.ibatis.annotations.Select;
public interface PersonMapper {
	@Select("SELECT * FROM person WHERE id=#{id}")
	public abstract Person selectById(Integer id);
}
<?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.mybatis.entity" />
    </typeAliases>
    <environments default="mysql1">
        <environment id="mysql1">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/practice"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="com.mybatis.mapper"/>
    </mappers>
</configuration>
public class UserMapperTest {
    private CardMapper cardMapper;
    @Before
    public void sqlSession() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
       cardMapper = sqlSession.getMapper(CardMapper.class);
    }
    @Test
    public void find() {
        List<User> userList = cardMapper.selectAll();
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

2、一对多

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Classes {
	private Integer id;
	private String name;
	private List<Student> students;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
	private Integer id;
	private String name;
	private Integer age;
}
public interface ClassesMapper {
    @Select("SELECT * FROM classes")
    @Results({@Result(column = "id", property = "id"),@Result(column = "name", property = "name"),
              @Result(property = "students",javaType = List.class,column = "id",many = @Many(select = "com.mybatis.mapper.StudentMapper.selectByCid"))})
    public abstract List<Classes> selectAll();
}
public interface StudentMapper {
	@Select("SELECT * FROM student WHERE cid=#{cid}")
	public abstract List<Student> selectByCid(Integer cid);
}
<?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.mybatis.entity" />
    </typeAliases>
    <environments default="mysql1">
        <environment id="mysql1">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/practice"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="com.mybatis.mapper"/>
    </mappers>
</configuration>
public class UserMapperTest {
    private ClassesMapper classesMapper;
    @Before
    public void sqlSession() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        classesMapper = sqlSession.getMapper(ClassesMapper.class);
    }
    @Test
    public void find() {
        List<User> userList = classesMapper.selectAll();
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

3、多对多

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Course {
	private Integer id;
	private String name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
	private Integer id;
	private String name;
	private Integer age;
}
public interface StudentMapper {
	@Select("SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id")
	@Results({@Result(column = "id", property = "id"),@Result(column = "name", property = "name"),@Result(column = "age", property = "age"),@Result(property = "courses",javaType = List.class, column = "id",many = @Many(select = "com.mybatis.mapper.CourseMapper.selectBySid"))})
	public abstract List<Student> selectAll();
}
public interface CourseMapper {
	@Select("SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}")
	public abstract List<Course> selectBySid(Integer sid);
}
<?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.mybatis.entity" />
    </typeAliases>
    <environments default="mysql1">
        <environment id="mysql1">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/practice"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="com.mybatis.mapper"/>
    </mappers>
</configuration>
public class UserMapperTest {
    private StudentMapper studentMapper;
    @Before
    public void sqlSession() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        studentMapper = sqlSession.getMapper(StudentMapper.class);
    }
    @Test
    public void find() {
        List<User> userList = studentMapper.selectAll();
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

Mybatis-plus

一、简介

1、概述:是mybatis的增强工具,在mybatis的基础上只做增强,不做改变,为简化开发、提高效率而生
2、特点
????????(1)、无侵入
????????(2)、损耗小
????????(3)、强大的CRUD操作
????????(4)、支持Lanbda形式调用
????????(5)、支持主键自动生成
????????(6)、支持ActiveRecord
????????(7)、支持自定义全局通用操作
????????(8)、内置代码生成器
????????(9)、内置分页插件
????????(10)、内置性能分析插件
???????? (11)、内置全局拦截插件
3、支持数据库
????????(1)、mysql、Oracle、DB2、H2....
????????(2)、达梦数据库、虚谷数据库...
4、官方网址:MyBatis-Plus

二、搭建框架

1、环境
????????(1)、IDE:IDEA 2021.1.2
????????(2)、构建工具:maven3.8.2
????????(3)、MySQl版本:8.0
????????(4)、Mybatis版本:3.5.7
????????(5)、JDK:JDK1.8
????????(6)、SpringBoot:2.6.4
2、创建数据库中的表

create table `user`(
    `id` bigint(0) not null auto_increment comment '主键ID',
    `name` varchar(30) default null comment '姓名',
    `age` int(11) default null comment '年龄',
    `email` varchar(50) default null comment '邮箱',
    primary key (`id`)
)

INSERT INTO `user` (id,name,age,email) values
	(null,'jone',18,'rest1@baomidou.com'),
	(null,'jack',34,'rest2@baomidou.com'),
	(null,'Tom',42,'rest3@baomidou.com'),
	(null,'Sandy',34,'rest4@baomidou.com'),
	(null,'Billie',44,'rest5@baomidou.com')

3、创建SpringBoot工程

<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- mybatis-plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3</version>
</dependency>

<!-- lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
</dependency>

4、创建yml文件,进行配置

spring:
  # 配置数据源信息
  datasource:
    # 配置数据源类型
    type: com.zaxxer.hikari.HikariDataSource
    # 配置连接数据库的各个信息
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/user?characterEncoding=utf-8&userSSL=false
    username: root
    password: root
    
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 将日志信息打印到控制台上
  global-config:
    db-config:
      # 设置数据库自增长
      id-type: auto
      # 数据表的前缀
      table-prefix: 

5、创建实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

6、创建Mapper接口

@Repository
public interface UserMapper extends BaseMapper<User> {
    Map<String,Object> getById(@Param("id")Integer id);
}

7、创建service

public interface UserService extends IService<User> {
}

8、创建service的实现类

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}

9、Maper测试

@SpringBootTest
public class MybatisPlusTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void select() {//查询
        List<User> list = userMapper.selectList(null);//查询全部
        list.forEach(System.out::println);
        User user = userMapper.selectById(7);//根据id查询的单个信息
        System.out.println(user);
        List<Integer> list = Arrays.asList(9, 8, 7);//根据多个id查询信息
        userMapper.selectBatchIds(list);
        Map<String,Object> map = new HashMap<>();
        map.put("name","jack");
        map.put("age",34);
        List<User> userList = userMapper.selectByMap(map);//根据哟用户信息查询
        userList.forEach(System.out::println);
        Map<String, Object> map = userMapper.getById(7);
        System.out.println(map);
    }
    @Test
    public void insert() {//添加
        User user = new User();
        user.setName("张三");
        user.setAge(13);
        user.setEmail("zhangsan@qq.com");
        int result = userMapper.insert(user);
        System.out.println(result);
    }
    @Test
    public void delete() {//删除
        int result = userMapper.deleteById(5);//根据id进行单个删除
        System.out.println(result);
        Map<String,Object> map = new HashMap<>();
        map.put("name","张三");
        map.put("age",13);
        int result = userMapper.deleteByMap(map);//根据用户信息进行和删除
        System.out.println(result);
        List<Integer> list = Arrays.asList(1, 2, 3);
        int resulr = userMapper.deleteBatchIds(list);//根据id进行批量删除
        System.out.println(resulr);
    }
    @Test
    public void update() {//修改
        User user = new User();
        user.setId(4);
        user.setName("张三");
        user.setAge(13);
        user.setEmail("zhangsan@qq.com");
        int result = userMapper.updateById(user);
        System.out.println(result);
    }
}

10、service测试

@SpringBootTest
public class MybatisPlusServiceTest {
    @Autowired
    private UserService userService;
    @Test
    public void count(){//查询记录数
        int count = userService.count();
        System.out.println(count);
    }
    @Test
    public void insert(){//批量添加
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("nhy"+i);
            user.setAge(13+i);
            user.setEmail("nhy"+i+"@qq.com");
            list.add(user);
        }
        boolean b = userService.saveBatch(list);
        System.out.println(b);
    }
}

三、注解

(一)、@TableName

1、概述:将实体类与表名进行映射
2、示例

@Data
@TableName(”t_user“)
public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String email;
}

(二)、@TableId

1、概述:将属性与数据表中的字段指定为主键 2、示例

@Data
public class User {
    @TableId
    private Integer id;
    private String name;
    private Integer age;
    private String email;
}

3、属性
????????(1)、value:用于指定主键的字段
????????(2)、type:主键生成策略,AUTO 为数据库表的主键递增

(三)、@TableField

1、概述:指定属性所对应的字段名
2、示例

@Data
public class User {
    private Integer id;
    @TableField("user_name")
    private String name;
    private Integer age;
    private String email;
}

(四)、@TableLogic

1、概述:逻辑删除
2、示例

@Data
public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    @TableLogic
    private Integer isDelete;
}

(五)、@Version

1、概述:版本号
2、示例

@Data
public class User {
    @TableId(value = "id")
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @Version
    private Integer version;
}

(六)、@EnumVale

1、概述:将标注的属性的值存储到数据库中
2、示例

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    @EnumVale
    private SexEnum sex;
    private String email;
    @Version
    private Integer version;
}

四、全局配置

mybatis-plus:
  # 配置类型别名
  type-aliases-package: com.mybatisPlus.pojo
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # 设置mybatis-plus的全局配置
  global-config:
    db-config:
      # 设置实体类所对应的统一前缀
     # table-prefix: t_
      # 设置统一的主键生成策略
      id-type: auto # auto 数据库自动递增
  # 枚举扫描包
  type-enums-package: com.mybatisPlus.enums    

五、条件构造器

(一)、 AbstractWrapper

1、概述:用于查询条件封装,生成sql的where条件
2、实现子类
????????(1)、QueryWrapper:查询条件封装
????????(2)、UpdateWrapper:Update条件封装

(二)、AbstractLambdaWrapper

1、概述: Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column
2、实现子类
????????(1)、LambdaQueryWrapper:用于Lambda语法使用的查询Warpper
????????(2)、LambdaUpdateWrapper: Lambda 更新封装Wrapper

(三)、QueryWrapper

1、组装查询条件

@Autowired
private UserMapper userMapper;

@Test
void selectList(){
    //查询用户名包含a 年龄在10-30之间,邮箱不为null的用户信息
    //SELECT id,name,age,email FROM user WHERE (name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("name","a").between("age",20,30).isNotNull("email");
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

2、组装排序条件

@Autowired
private UserMapper userMapper;

@Test
void selectList2(){
    //查询信息,按照年龄的降序排序,若年龄相同,则按照id的升序排序
    //SELECT id,name,age,email FROM user ORDER BY age DESC,id ASC
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.orderByDesc("age").orderByAsc("id");
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

3、组装删除条件

@Autowired
private UserMapper userMapper;

@Test
void delete(){
    //删除邮箱地址为null的用户信息
    //DELETE FROM user WHERE (email IS NULL)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.isNull("email");
    int delete = userMapper.delete(queryWrapper);
    System.out.println(delete);
}

4、组装修改条件

@Autowired
private UserMapper userMapper;

@Test
void update(){
    //将年龄大于20并且用户名包含有a或邮箱为null的用户信息修改
    // UPDATE user SET name=?, age=?, email=? WHERE (age > ? AND name LIKE ? OR email IS NULL)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.gt("age",20).like("name","a").or().isNull("email");
    int update = userMapper.update(new User(null,"小明",12,"test@123.com"), queryWrapper);
    System.out.println(update);
}

5、条件的优先级

@Autowired
private UserMapper userMapper;

@Test
void update2(){
    //将用户名中包含a并且(年龄大于20或邮箱为null)的用户信息修改  lambda中条件优先执行
    // UPDATE user SET name=?, age=?, email=? WHERE (name LIKE ? AND (age > ? OR email IS NULL))
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("name","3").and(i->i.gt("age",10).or().isNull("email"));
    int update = userMapper.update(new User(null,"好",22,"test@123.com"), queryWrapper);
    System.out.println(update);
}

6、组装select字句

@Autowired
private UserMapper userMapper;

@Test
void selectList3() {
    //查询用户名、年龄、邮箱信息
    //SELECT name,age,email FROM user
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.select("name","age","email");
    List<Map<String, Object>> mapList = userMapper.selectMaps(queryWrapper);
    mapList.forEach(System.out::println);
}

7、组装子查询

@Autowired
private UserMapper userMapper;

@Test
void selectList4() {
    //查询id大于100的
    //SELECT id,name,age,email FROM user WHERE (id IN (select id from user where id > 100))
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.inSql("id","select id from user where id > 100");
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

(四)、UpdateWrapper

1、修改

@Autowired
private UserMapper userMapper;

@Test
void update3() {
    //将用户名中包含a并且(年龄大于20或邮箱为null)的用户信息修改  lambda中条件优先执行
    //UPDATE user SET name=?,email=? WHERE (name LIKE ? AND (age > ? OR email IS NULL))
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.like("name", "2").and(i -> i.gt("age", 10).or().isNull("email"));
    updateWrapper.set("name","1").set("email","ad@c123.com");
    int update = userMapper.update(null, updateWrapper);
    System.out.println(update);
}

2、实际开发中

@Autowired
private UserMapper userMapper;

@Test
void selectList5() {
    //SELECT id,name,age,email FROM user WHERE (name LIKE ? AND age >= ? AND age <= ?)
    String username = "好";
    Integer ageBegin = 10;
    Integer ageEnd = 23;
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like(StringUtils.isNotBlank(username), "name", username).ge(ageBegin != null, "age", ageBegin).le(ageEnd != null, "age", ageEnd);
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

(五)、LambdaQueryWrapper

@Autowired
private UserMapper userMapper;

@Test
void selectList6() {
    // SELECT id,name,age,email FROM user WHERE (name LIKE ? AND age >= ? AND age <= ?)
    String username = "好";
    Integer ageBegin = 10, ageEnd = 23;
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.like(StringUtils.isNotBlank(username),User::getName,username)
        .ge(ageBegin!=null,User::getAge,ageBegin)
        .le(ageEnd!=null,User::getAge,ageEnd);
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

(六)、LambdaUpdateWrapper

@Autowired
private UserMapper userMapper;

@Test
void update4() {
    //将用户名中包含a并且(年龄大于20或邮箱为null)的用户信息修改  lambda中条件优先执行
    // UPDATE user SET name=?,email=? WHERE (name LIKE ? AND (age > ? OR email IS NULL))
    LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.like(User::getName, "2").and(i -> i.gt(User::getAge, 10).or().isNull(User::getEmail));
    updateWrapper.set(User::getName, "1").set(User::getEmail, "ad@c123.com");
    int update = userMapper.update(null, updateWrapper);
    System.out.println(update);
}

六、插件

(一)、分页插件

@Configuration
@MapperScan("com.mybatisPlus.mapper")
public class MybatisConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

1、使用默认的分页语句

@Autowired
private UserMapper userMapper;

@Test
void page(){
    Page<User> page = new Page<>(1,2);
    Page<User> userPage = userMapper.selectPage(page, null);
    System.out.println(userPage.getRecords());
    System.out.println(userPage.getPages());
    System.out.println(userPage.getTotal());
    System.out.println(userPage.hasNext());
    System.out.println(userPage.hasPrevious());
}

2、使用自定义的分页语句

@Repository
public interface UserMapper extends BaseMapper<User> {
    @Select("select * from user where age > #{age}")
    Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
}
@Autowired
private UserMapper userMapper;

@Test
void page2(){
    Page<User> page = new Page<>(1,2);
    Page<User> userPage = userMapper.selectPageVo(page, 12);
    System.out.println(userPage.getRecords());
    System.out.println(userPage.getPages());
    System.out.println(userPage.getTotal());
    System.out.println(userPage.hasNext());
    System.out.println(userPage.hasPrevious());
}

(二)、乐观锁

@Configuration
@MapperScan("com.mybatisPlus.mapper")
public class MybatisConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @Version
    private Integer version;
}

七、通用枚举

@AllArgsConstructor
@Getter
public enum SexEnum {
    MALE(1,"男"),FEMALE(2,"女");

    @EnumValue
    private Integer sex;
    private String name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private SexEnum sex;
    private String email;
    @Version
    private Integer version;
}

八、代码生成器

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>
public class Code {
    public static void code(String url,String username,String password,String author,String outputDir,String parent,String moduleName,String... table) {
        FastAutoGenerator.create(url, username, password)
                .globalConfig(builder -> {
                    builder.author(author) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir(outputDir); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent(parent) // 设置父包名
                            .moduleName(moduleName) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, outputDir)); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude(table) // 设置需要生成的表名
                            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
                })
                // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .templateEngine(new FreemarkerTemplateEngine())
                .execute();
    }
}

九、多数据源

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.5.0</version>
</dependency>
spring:
  # 配置数据源信息
  datasource:dynamic:
    #设置默认的数据源或者数据源组,默认值即为master
    primary: master
      #严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源
      strict: false
      datasource:
       master:
        ur1: jdbc:mysql://localhost:3306/mybatis_plus_1?char acter Encoding=utf8&useSSL=false
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: root
       slave_1:
        ur1: jdbc:mysq1://localhost:3306/mybatis_plus_2?character Encoding=utf8&useSSL=false
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: root

mybatis-plus:
  # 配置类型别名
  type-aliases-package: com.mybatisPlus.pojo
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # 设置mybatis-plus的全局配置
  global-config:
    db-config:
      # 设置实体类所对应的统一前缀
      # table-prefix: t_
      # 设置统一的主键生成策略
      id-type: auto # auto 数据库自动递增
  # 枚举扫描包
  type-enums-package: com.mybatisPlus.enums
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(value = "id")
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @Version
    private Integer version;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
    @TableId("id")
    private Integer id;
    private String name;
    private Integer price;
    @Version
    private Integer version;
}
@Repository
public interface UserMapper extends BaseMapper<User> {
}
@Repository
public interface ProductMapper extends BaseMapper<Product> {
}
public interface UserService extends IService<User> {
}
public interface ProductService extends IService<Product> {
}
@Service
@DS("mybatis_plus")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
@Service
@DS("mybatis_plus_1")
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
}

SpringBoot

一、简介

1、概述:简化Spring应用的初始搭建以及开发流程
2、特点
????????(1)、独立运行的 Spring 项目
????????(2)、内嵌 Servlet 容器
????????(3)、提供 starter 简化 Maven 配置
????????(4)、提供了大量的自动配置
????????(5)、自带应用监控
????????(6)、无代码生成和 xml 配置
3、优点
????????(1)、起步依赖
????????(2)、自动配置
????????(3)、辅助功能

二、搭建框架

1、IDEA:点击File,然后在点击New,再点击Project,在出现的界面上点击Spring Initializr,然后按照上面文字进行输入,输入完之后点击Next,然后在下一个界面点击你想要开发哪一个项目就添加哪一个,添加完之后,就点击Fiish,最后运行看是否成功;网址为:https://start.spring.io
2、官网:进入到Spring官网,然后进入SpringBoot的详情页面,滑倒最下面,找到Spring Initializr进行点击,然后按照上面的文字进行输入,然后再在右边添加依赖,点击ADD DEPENDENCIES,进入到依赖添加详情页面,找打需要的依赖进行添加即可,这个添加依赖的过程可能需要重复进入...到了最后一个依赖,就点击GENERATE,把下载的文件进行解压,把项目引入工程中即可运行;网址为:Spring Boot
3、阿里云:点击File,然后在点击New,再点击Project,在出现的界面上点击Spring Initializr,然后按照上面文字进行输入,输入完之后点击Next,然后在下一个界面点击你想要开发哪一个项目就添加哪一个,添加完之后,就点击Fiish,最后运行看是否成功;网址为:http://start.aliyun.com
4、Maven创建:在idea中使用Maven作为创建工具,但是有一个前提是要有SpringBoot的依赖即可创建,把SpringBoot的依赖放入到pom.xml文件中进行加载即可,最为创建一个Application类,类上@SpringBootApplication注解标识,在下面创建main方法,方法体中输入SpringApplication.run(Application.class),最后运行即可
5、解析
????????(1)、parent:仅定义未使用,减少依赖冲突问题
????????(2)、starter:依赖传递,减少依赖配置问题
????????(3)、引导类:启动Spring容器
????????(4)、内嵌tomcat

三、配置

(一)、配置文件

1、默认类型:properties
2、作用:修改springboot的默认设置
3、类型
????????(1)、properties:默认值,优先级最高
????????(2)、yml:建议使用这个,其次
????????(3)、yaml:优先级最低
4、yaml
????????(1)、定义:一种数据序列化格式
????????(2)、优点
????????????????①、容易阅读
????????????????②、容易与脚本语言交互
????????????????③、以数据为核心,重数据清格式
????????(3)、文件的扩展名
????????????????①、.yml:主流的
????????????????②、.yaml
????????(4)、语法规则
????????????????①、大小写敏感
????????????????②、属性层级关机使用多行描述,每行结尾使用冒号结束
????????????????③、使用缩进表示层级关系,同层级左侧对齐,只允许空格,不能使用Tab键
????????????????④、属性值前面添加空格,属性名与属性值之间使用冒号+空格作为分隔符
????????????????⑤、# 表示注释
????????(5)、表示方式
????????????????①、字面值:string: HelloWorld
????????????????②、数组:like: [王者荣耀,吃鸡战场]
????????????????③、对象数组:userr: [{name:Tom,age:4},{name:Juerry,age:6}]
????????(6)、读取数据
????????????????①、获取上面的单个属性数据:@Value("${一级属性名.二级属性名...}")
????????????????②、获取全部数据:@Autowied
????????????????③、获取引用类型数据:@Autowied

四、整合

(一)、Junit

public interface BookDao{
   void sove();
}
@Repository
public class implBooKDap implements BookDao{
    @Override
    void sove(){
        System.out.println("sove");
    }
}
@SpringBootTest
class ApplicationTests {
    @Autowired
    private BookDao bookDao;
    @Test
    void contextLoads() {
        bookDao.save();
    }
}

(二)、Mybatis

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
</dependency>
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/book?serverTimezone=UTC
    username: root
    password: root
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}
@Mapper
public interface BookMapper {
    @Select("select * from boook where id = #{id}")
    public Book getById(Integer id);
}
@SpringBootTest
class ApplicationTests {
    @Autowired
    private BookMapper bookMapper;
    @Test
    void contextLoads() {
        bookMapper.getById(1);
    }
}

(三)、Mybayis-plus

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/book?serverTimezone=UTC
    username: root
    password: root

mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_ # 数据表的前缀
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}
@Mapper
public interface BookDao extends BaseMapper<Book>{
}
@SpringBootTest
class ApplicationTests {
    @Autowired
    private BookDao bookDao;
    @Test
    void contextLoads() {
    	bookDao.selectById(1);
    }
}

(四)、Druid

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.6</version>
</dependency>
spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/user_db
      username: root
      password: root
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}
@Mapper
public interface BookDao {
    @Select("select * from boook where id = #{id}")
    public Book getById(Integer id);
}
@SpringBootTest
class ApplicationTests {
    @Autowired
    private BookDao bookDao;
    @Test
    void contextLoads() {
        bookDao.getById(1);
    }
}

SpringSecurity

一、简介

1、概述:是一个高度自定义的安全框架。利用 Spring loC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作
2、常用的安全框架
????????(1)、SpringSerurity:Spring家族中的一员
????????(2)、ApacheShiro:一个功能强大且易于使用的Java安全框架,提供了认证授权,加密和会话管理

二、搭建框架

1、环境
????????(1)、IDE:IDEA 2021.1.2
????????(2)、构建工具:maven3.8.2
????????(3)、JDK:JDK1.8
????????(4)、SpringBoot:2.6.4
????????(5)、SpringSecurity:2.6.4
2、创建maven工程

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

3、创建控制器

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
    @RequestMapping("login")
    public String login(){
        System.out.println("执行登录方法");
        return "redirect:login.html";
    }
}

4、创建页面
????????(1)、登录

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>登录</title>
    </head>
    <body>
        <form action="/login" method="post">
            用户名: <input type="text" name="username" /><br/>
            密码: <input type="password" name="password" /><br/>
            <input type="submit" value="登录" />
        </form>
    </body>
</html>

????????(2)、登录成功页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>mian</title>
</head>
<body>
	登录成功
</body>
</html>

5、测试

三、类

(一)、UserDetailsService

1、概述:用来实现自定义登录逻辑的接口
2、loadUserByUsername:通过用户名来加载用户,并将用户传入到UserDetails接口中去

(二)、UserDetails

1、概述:是提供用户信息的核心接口
2、方法
????????(1)、Collection<? extends GrantedAuthority> getAuthorities():返回所有的权限
????????(2)、String getPassword():获取密码
????????(3)、String getUsername():货期用户名
????????(4)、boolean isAccountNonExpired():判断用户是否过期
????????(5)、boolean isAccountNonLocked():判断用户是否锁定
????????(6)、boolean isCredentialsNonExpired():判断凭证是否过期
????????(7)、boolean isEnabled():判断账号是否可用
3、实现类:User

(三)、PasswordEncoder

1、概述:提供的密码加密方式的接口
2、方法 (1)、String encode(CharSequence rawPassword):对密码进行加密,推荐使用BCryptPasswordEncoder加密方法 (2)、boolean matches(CharSequence rawPassword, String encodedPassword):将原始密码和加密后的密码进行匹配 (3)、default boolean upgradeEncoding(String encodedPassword):解析密码

四、自定义登录

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 表单提交
        http.formLogin()
                // 自定义密码和用户名的参数别名
                .usernameParameter("username")
                .passwordParameter("password")
                // 当发现是login是,就要走登录逻辑
                .loginProcessingUrl("/login")
                // 自定义登录页面
                .loginPage("/login.html")
                // 登录成功后的页面,必须是POST请求
                .successForwardUrl("/toMain")
                //登录成功处理器,不能和successForwardUrl共存
                //.successHandler(new MyAuthenticationFailureHandler("https://youdao.com/"))
                // 登录失败后的页面,必须是POST请求
                .failureForwardUrl("/toError");
                //登录失败处理器,不能和failureForwardUrl共存
                //.failureHandler(new MyAuthenticationFailureHandler("https://youdao.com/"));
        // 授权认证
        http.authorizeRequests()
                //登录页面不需要被认证
                .antMatchers("/login.html").permitAll()
                // 错误页面不需要被认证
                .antMatchers("/error.html").permitAll()
                //所有请求都必须被认证,才能访问
                .anyRequest().authenticated();
        //关闭csrf防护
        http.csrf().disable();
    }
}
@Controller
public class LoginController {
    @RequestMapping("toMain")
    public String toMain(){
        return "redirect:main.html";
    }
    @RequestMapping("toError")
    public String toError(){
        return "redirect:error.html";
    }
}
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    private String url;
    public MyAuthenticationFailureHandler(String url) {
        this.url = url;
    }
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.sendRedirect(url);
    }
}
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private String url;
    public MyAuthenticationSuccessHandler(String url) {
        this.url = url;
    }
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.sendRedirect(url);
    }
}
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        String oldUserName = "admin";
        String oldPassWord = "123";
        if(!oldUserName.equals(username)){
            throw new UsernameNotFoundException("用户名不存在!");
        }
        String newPassWord = passwordEncoder.encode(oldPassWord);
        return new User(username,newPassWord, AuthorityUtils.commaSeparatedStringToAuthorityList(oldUserName));
    }
}

五、方法

(一)、授权

1、概述:本质就是请求 2、方法 (1)、anyRequest:所有请求 (2)、antMatchers:单个请求,也可以使用匹配符进行匹配 (3)、regexMathcers:使用正则表达式或者使用请求方式进行匹配 (4)、mvcMatchers:给请求加入一个前缀

(二)、访问控制

1、概述:请求的匹配符 2、方法 (1)、parmitAll:允许任何人访问 (2)、dentAll:所有人不允许访问 (3)、anonymous:匿名访问 (4)、authenticated:需要认证才可访问 (5)、fullAuthenticated:完全认证才可访问 (6)、remenberMe:规定时间内才可访问

(三)、权限判断

1、概述:用户登录后判断权限,严格区分大小写 2、方法 (1)、hasAuthority:用户是否具有特定权限就允许访问 (2)、hasAuythority:用户具有某一个权限就允许访问

(四)、角色判断

1、概述:用户登录后判断权限,严格区分大小写,在传入数据是必须要ROLE_开头才可以,后面验证不需要 2、方法 (1)、hasRole:用户是否具有特定用户就允许访问 (2)、hasAnyRole:用户具有某一个用户就允许访问

(五)、IP地址

1、概述:通过Id地址才能访问 2、方法 (1)、hasIpAddress:给定Ip地址才可访问

(六)、表达式控制

1、本质:access方法 2、作用:控制方法的访问 3、常用的表达式

表达式说明
hasRole([role])如果当前主体具有指定的角色,则返回true。默认情况下,如果提供的角色不是以'ROLE_'开头,它将被添加。这可以通过修改DefaulthebSecurityExpressionHandler上的defaultRolePrefix来定制
hasAnyRole([rolel,role2])如果当前主体具有任何提供的角色(以逗号分隔的字符串列表给出),则返回true。默认情况下,如果提供的角色不以'ROLE_'开头,则将添加该角色。这可以通过在DefaultwebSecurityExpressionHandler上修改defaultRolePrefix来定制
hasAuthority([authority1)如果当前主体具有指定的权限,则返回true。
hasAnyAuthority([authority1, authority2])如果当前主体具有任何提供的权限(以逗号分隔的字符串列表形式给出),则返回true
principal允许直接访问代表当前用户的主体对象
authentication允许直接访问从SecurityContext获得的当前Authentication对象
permitAll总是计算为true
denyAll计算结果总是为false
isAnonymous ()如果当前主体是匿名用户,则返回true
isRememberMe()如果当前主体是remember-me用户,则返回true
isAuthenticated()如果用户不是匿名的,则返回true
isFullyAuthenticated()如果用户不是匿名用户或remember-me用户,则返回true
hasPernission(Object target, Object permission)如果用户能够访问给定权限下提供的目标,则返回true。
hasPermission(Object targetId, String targetType, Object permission))如果用户有权限访问提供的目标,则返回true。为例。hasPermission (com . example。”域。消息”、“读”)

4、自定义权限控制 (1)、配置类

public interface MyService {
    boolean hasPermission(HttpServletRequest request, Authentication authentication);
}
@Service
public class MyServiceImpl implements MyService {
    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        Object o = authentication.getPrincipal();
        if (o instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) o;
            Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
            return authorities.contains(new SimpleGrantedAuthority(request.getRequestURI()));
        }
        return false;
    }
}
http.authorizeRequests().anyRequest().access("@myServiceImpl.hasPermission(request,authentication)");

(2)、注解

@Secured("ROLE_abc")
@RequestMapping("toError")
public String toError(){
    return "redirect:error.html";
}
ngBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SpringSecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityApplication.class, args);
    }
}

六、SpringSecurityOauth2

(一)、简介

1、授权服务器 (1)、Authorize Endpoint :授权端点,进行授权 (2)、Token Endpoint :令牌端点,进过授权拿到对应的 (3)、TokenIntrospection Endpoint :校验端点,校验Token的合法性 (4)、Revocation Endpoint :撤销端点,撤销授权 2、流程 (1)、用户访问,此时没有Token。 Oauth2RestTemplate会报错,这个报错信息会被Oauth2ClientContextFilter捕获并重定向到认证服务器 (2)、认证服务器通过Authorization Endpoint进行授权,并通过AuthorizationServerTokenServices生成授权码并返回给客户端 (3)、客户端拿到授权码去认证服务器通过Token Endpoint调用AuthorizationServerTokenServices生成Token并返回给客户端 (4)、客户端拿到Token去资源服务器访问资源,一般会通过Oauth2AuthenticationManager调用ResourceServerTokenServices进行校验。校验通过可以获取资源

(二)、授权模式

1、授权码模式

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-security</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

2、密码模式

Oauth2

一、简介

1、概述:是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息 2、主要角色 (1)、Resource Owner(资源所有者):用户,即资源的拥有人,想要分享某些资 源给第三方应用 (2)、Resource Server(资源服务器):放受保护资源,要访问这些资源,需要获得访问令牌 (3)、Authorization server(授权(认证)服务器):授权服务器用于发放访问令牌给客户端 (4)、Client(客户端(第三方应用)):客户端代表请求资源服务器资源的第三方程序 3、常用术语 (1)、客户凭证(client Credentials):客户端的clientld和密码用于认证客户 (2)、令牌(tokens):授权服务器在接收到客户请求后,颁发的访问令牌 (3)、作用域(scopes):客户请求访问令牌时,由资源拥有者额外指定的细分权限(permission (4)、用户代理(User Agent):用户代理。一般就是指浏览器 4、令牌类型 (1)、授权码:仅用于授权码授权类型,用于交换获取访问令牌和刷新令牌 (2)、访问令牌:用于代表一个用户或服务直接去访问受保护的资源 (3)、刷新令牌:用于去授权服务器获取一个刷新访问令牌 (4)、Bear erToken:不管谁拿到Token都可以访问资源,类似现金 (5)、Prooof of Possession(PoP) Token:可以校验client是否对Token有明确的拥有权 5、优点 (1)、更安全,客户端不接触用户密码,服务器端更易集中保护 (2)、广泛传播并被持续采用 (3)、短寿命和封装的token (4)、资源服务器和授权服务器解耦 (5)、集中式授权,简化客户端 (6)、HTTP/JSON友好,易于请求和传递token考虑 (7)、多种客户端架构场景 (8)、客户可以具有不同的信任级别 6、缺点 (1)、协议框架太宽泛,造成各种实现的兼容性和互操作性差 (2)、不是一个认证协议,本身并不能告诉你任何用户信息。

二、授权模式

(一)、授权码模式

1、概述:是功能最完整、使用最广泛、流程最严密的授权模式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌 2、步骤 (1)、用户访问客户端,客户端将用户导向授权服务器,通过用户代理(User-Agent)发送包括它的客户端标识符、请求的范围、本地状态和一个重定向URI,授权服务器在授予(或拒绝)访问权后将其发送给用户代理 (2)、授权服务器对资源所有者进行身份验证(通过用户代理,让用户输入用户名和密码),并确定资源所有者是否授予或拒绝客户端的访问请求。 (3)、用户跳转后,假如资源所有者同意授权请求,那么授权服务器将会使用前面提供的或者事先指定的重定向URI(redirection URI),重定向到客户端,并附上一个授权码(code)和一个前面提供的本地状态(state)(如果有的话,则会原值返回) (4)、客户端收到授权码,附上早先的重定向URI,向授权服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。在发出请求时,授权服务器对客户端进行身份验证。请求参数包含授权代码、用于获得验证的授权代码的重定向URI、标识客户端身份的client id和client secret (5)、授权服务器对客户端进行身份验证,验证授权代码,并确保所收到的重定向URI与用于在步骤?中对客户端重定向的URI相匹配,如果有效,授权服务器将发送访问令牌access token和刷新令牌refresh token,然后授权服务器给我们返回授权码

(二)、简化模式

1、概述:不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了"授权码"这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证 2、步骤 (1)、用户访问客户端,客户端将用户导向授权服务器,通过用户代理(User-Agent)发送包括它的客户端标识符、请求的范围、本地状态和一个重定向URI,授权服务器在授予(或拒绝)访问权后将其发送给用户代理 (2)、授权服务器对资源所有者进行身份验证(通过用户代理,让用户输入用户名和密码),并确定资源所有者是否授予或拒绝客户端的访问请求 (3)、用户跳转后,假如资源所有者同意授权请求,那么授权服务器将会使用前面提供的或者事先指定的重定向URI(redirection URI),重定向到客户端,并附上访问令牌等信息

(三)、密码模式

1、概述:用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权 2、步骤 (1)、用户访问客户端,客户端将用户导向授权服务器,然后提供URI连接包含用户名和密码信息给授权服务器 (2)、授权服务器认证用户名和密码信息正确后,然后返回客户端access_token等信息

(四)、客户端模式

1、概述:客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证 2、步骤 (1)、客户端直接向授权服务器发起认证请求 (2)、授权服务器通过认证后,直接返回客户端access_token等信息

JWT

一、简介

1、常见的认证机制 (1)、HTTP Basic Auth (2)、Cookie Auth (3)、OAuth (4)、Token Auth 2、概述:JSON网络令牌,JWT是一个轻便的安全跨平台传输格式,定义了一个紧凑的自包含的方式在不同实体之间安全传输信息(JSON格式)。它是在Web环境下两个实体之间传输数据的一项标准 3、官网:JWT 4、优点 (1)、jwt基于json,非常方便解析 (2)、可以在令牌中自定义丰富的内容,易扩展 (3)、通过非对称加密算法及数字签名技术,JWT防止篡改 (4)、资源服务使用JWT可不依赖认证服务即可完成授权 5、缺点:JWT令牌较长,占存储空间比较大 6、组成: (1)、头部:描述关于该JWT最基本的信息 (2)、载荷:存放有效信息的地方 (3)、签名:签证信息

二、实现

(一)、永久有效

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
@Test
void getToken() {
    JwtBuilder jwtBuilder = Jwts.builder()
        // 标识
        .setId("8888")
        // 用户
        .setSubject("海")
        // 时间
        .setIssuedAt(new Date())
        .signWith(SignatureAlgorithm.HS256, "0903");
    String token = jwtBuilder.compact();
    System.out.println(token);
    String[] split = token.split("\\.");
    for (String s : split) {
        System.out.println(Base64Codec.BASE64.decodeToString(s));
    }
}

@Test
void parseToken() {
    String token = "";
    Claims body = Jwts.parser()
        .setSigningKey("0903")
        .parseClaimsJws(token)
        .getBody();
    System.out.println(body.getId());
    System.out.println(body.getSubject());
    System.out.println(body.getIssuedAt());

}

(二)、超时失效

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
@Test
void getToken1() {
    long now = System.currentTimeMillis();
    long exp = now + 60 * 10000;
    JwtBuilder jwtBuilder = Jwts.builder()
        // 标识
        .setId("8888")
        // 用户
        .setSubject("海")
        // 时间
        .setIssuedAt(new Date())
        .setExpiration(new Date(exp))
        .signWith(SignatureAlgorithm.HS256, "0903");
    String token = jwtBuilder.compact();
    System.out.println(token);
    String[] split = token.split("\\.");
    for (String s : split) {
        System.out.println(Base64Codec.BASE64.decodeToString(s));
    }
}

@Test
void parseToken1() {
    String token = "";
    Claims body = Jwts.parser()
        .setSigningKey("0903")
        .parseClaimsJws(token)
        .getBody();
    System.out.println(body.getId());
    System.out.println(body.getSubject());
    System.out.println(body.getIssuedAt());
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    System.out.println("签发时间" + simpleDateFormat.format(body.getIssuedAt()));
    System.out.println("过期时间" + simpleDateFormat.format(body.getExpiration()));
    System.out.println("当前时间" + simpleDateFormat.format(new Date()));
}

(三)、自定义声明

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
@Test
void getToken2() {
    JwtBuilder jwtBuilder = Jwts.builder()
        // 标识
        .setId("8888")
        // 用户
        .setSubject("海")
        // 时间
        .setIssuedAt(new Date())
        .signWith(SignatureAlgorithm.HS256, "0903")
        //自定义声明
        .claim("roles","admin")
        .claim("logo","ss.jpg");
    String token = jwtBuilder.compact();
    System.out.println(token);
    String[] split = token.split("\\.");
    for (String s : split) {
        System.out.println(Base64Codec.BASE64.decodeToString(s));
    }
}


@Test
void parseToken2() {
    String token = "";
    Claims body = Jwts.parser()
        .setSigningKey("0903")
        .parseClaimsJws(token)
        .getBody();
    System.out.println(body.getId());
    System.out.println(body.getSubject());
    System.out.println(body.getIssuedAt());
    System.out.println(body.get("logo"));
    System.out.println(body.get("roles"));

}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-06 10:55:43  更:2022-05-06 10:57:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:22:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码