| |
|
开发:
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为内核
二、IOC(一)、Bean1、概述:是一个被实例化,组装,并通过Spring IOC容器所管理的对象
????????(4)、init-method:指定类型初始化方法名称,方法名称随意 ? (二)、实例化1、无参构造方法实例化
2、工厂静态方法实例化
3、工厂实例方法实例化
(三)、依赖注入1、概述:是Spring框架核心的IOC的具体实现
????????????????②、引用类型
????????????????③、集合
????????(2)、有参构造 ?
????????????????②、引用类型
????????????????③、集合 (四)、引入外部模块1、概述:将主配置文件进行分模块的拆解,通过标签引入即可 2、标签
(五)、相关API1、ApplicationContext (六)、数据源1、概述:提供了应用程序所需要数据的位置
????????(2)、传统案例
????????(3)、抽取配置消息
????????(4)、spring配置数据源
6、Druid
????????(2)、传统案例
????????(3)、抽取配置消息
????????(4)、spring配置数据源
(七)、注解开发1、作用:简化配置,提高开发效率
3、注意事项:使用注解式开发时,要在spring的核心配置文件中,加入注解扫描器
4、新注解
三、JDBCTemplate1、概述:Spring框架对JDBC进行封装,方便实现对数据库操作
????????(2)、创建数据库的表和实体 ?
四、AOP(一)、简介1、概述:是通过预编译方式和运行期动态代理,实现程序功能的统一维护的一种技术 (二)、AspectJ1、概述:是一个易用的功能强大的AOP框架
3、xml实现
4、注解实现
五、事务控制(一)、编程式事务控制1、PlatformTransactionManager:事务管理器,操作事务的方法 (二)、声明式事务控制1、概述:采用声明的方式来处理事务,指在配置文件中声明
4、注解
六、集成(一)、web环境1、三层架构
3、步骤 (二)、Junit1、导入依赖的坐标
2、使用@Runwith注解替换原来的运行期
????????(2)、整合Junit5
SpringMVC一、简介1、概述:是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架 二、搭建框架1、开发环境
3、添加Web模板
4、创建控制器
5、创建并配置springMVC.xml
6、访问首页和指定页面
(2)、访问指定页面
7、执行流程 三、注解、类型(一)、@RequestMapping1、作用:将请求和处理请求的控制器方法进行关联
????????(2)、method:通过请求方式匹配请求映射,可以匹配多种请求方式,不满足就报:405 - Request method "POST" not supported
????????(3)、params:通过请求的请求参数匹配请求,可以匹配多种请求参数,且要同时满足
????????(4)、headers:通过请求的请求头信息匹配映射
4、派生注解 (二)、@RequestParam1、作用:将请求参数和控制器方法的形参进行映射关系
(三)、@RequestHesder1、作用:将请求头信息和控制器方法的形参进行映射关系
(四)、@CookieValue1、作用:将cookie数据信息和控制器方法的形参进行映射关系
(五)、@RequestBody1、作用:将请求的请求体和当前注解所标识的形参赋值
(六)、RequestEnitty1、作用:在控制器方法的形参设置该类型时,请求报文信息会自动赋值
(七)、@ResponseBody1、作用:在控制器方法上标识,可以将方法的返回值直接作为响应体响应打浏览器中
(八)、@RestController1、作用:给当前类所有的方法加上@ResponseBody
(九)、ResponseEntity1、作用:用于控制器方法的返回值类型,该类型是返回值就是响应到浏览器的响应报文
四、域对象(一)、Repuest1、servletAPI
2、ModelAndView
3、Model
4、Map
5、ModelMap
(二)、Session
(三)、Application
五、视图(一)、Thymeleaf
(二)、InternalResourceView
(三)、RedirectView
(四)、view-controller
(六)、InternalResourceViewResolver
六、RESTFurl(一)、简介1、概述:是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义 (二)、实现1、基本操作:GET(获取)、POST(新建)、PUT(更新)、DELETE(删除)
3、注意事项:使用PUT和DELETE时要加入配置HiddenHttpMethodFilter过滤器,还要开始的请求方式必须为POST,还要设置_method属性,值为put或delete,大小写无所谓
七、静态资源
八、HttpMessageConverter1、概述:请求报文转换器
????????(2)、加入注解驱动
????????(3)、在方法上加入@ResponseBody注解 ?
????????(2)、创建Vue实例
????????(3)、测试 九、文件下载上传1、文件下载
2、文件上传
????????(2)、配置文件上传解析器
????????(3)、上传方法
十、拦截器1、作用:用于拦截控制器方法的执行
????????(2)、配置拦截器
3、多个拦截器的执行的步骤 十一、异常处理器1、基于配置文件
2、基于注解
十四、注解配置1、配置web.xml
2、创建spring.xml的配置类
3、配置springmvc.xml的配置类
十五、SpringMVC的常用组件1、DispatcherServlet:前端控制器 Mybatis一、概述1、概述:是一个基于Java的持久层框架 二、搭建框架1、环境
3、创建数据库的表和实体
4、创建映射文件
5、创建核心文件
6、测试增删改查
三、映射配置文件
|
数据类型 | String | Integrt | List | ArrayList | Map | HashMap | Date | Object |
---|---|---|---|---|---|---|---|---|
别名 | string | int | list | arraylist | map | hashmap | date | object |
3、注意实现:别名要定义在environments标签的上方
1、概述:类型处理器
2、常用类型处理器
类型处理器 | Java类型 | 数据库类型 |
---|---|---|
BooleanTypeHandler | java.lang.Boolean,boolean | BOOLEAN |
ByteTypeHandler | java.lang.Byte,byte | NUMERIC,BYTE |
ShortTypeHandler | java.lang.Short,short | NUMERTC,SHORT INTEGER |
IntegerTypeHandler | java.lang.Integer,int | NUMERTC,INTEGER |
LongTypeHandler | java.lang.Long,long | NUMERTC,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>
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);
}
}
}
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);
}
}
1、概述:将实体类与表名进行映射
2、示例
@Data
@TableName(”t_user“)
public class User {
private Integer id;
private String name;
private Integer age;
private String email;
}
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 为数据库表的主键递增
1、概述:指定属性所对应的字段名
2、示例
@Data
public class User {
private Integer id;
@TableField("user_name")
private String name;
private Integer age;
private String email;
}
1、概述:逻辑删除
2、示例
@Data
public class User {
private Integer id;
private String name;
private Integer age;
private String email;
@TableLogic
private Integer isDelete;
}
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;
}
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
1、概述:用于查询条件封装,生成sql的where条件
2、实现子类
????????(1)、QueryWrapper:查询条件封装
????????(2)、UpdateWrapper:Update条件封装
1、概述: Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column
2、实现子类
????????(1)、LambdaQueryWrapper:用于Lambda语法使用的查询Warpper
????????(2)、LambdaUpdateWrapper: Lambda 更新封装Wrapper
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);
}
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);
}
@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);
}
@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 {
}
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
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();
}
}
<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);
}
}
<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);
}
}
<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);
}
}
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、测试
1、概述:用来实现自定义登录逻辑的接口
2、loadUserByUsername:通过用户名来加载用户,并将用户传入到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
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:用户具有某一个用户就允许访问
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); } }
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、密码模式
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等信息
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")); }
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |