一、Mybatis学习笔记
1、创建springboot项目
-
勾选mybatisFrame和Mysql
-
导入相关依赖,删除无关项目
-
导入数据库文件,配置application.properties信息,链接数据库的重要信息
-
编写pojo实体类
-
创建mapper接口,查询数据库信息,利用注解@Select调用sql语句,再将查询结果放入list集合中
-
@Mapper注解,在运行过程中,会自动生成代理对象
-
在Springboot的测试类中,使用自动装配,使用对象进行调用方法,达到访问数据库信息的目的,输出在控制台
<dependencies> <!-- mybatis的起步依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.4</version> </dependency> <!-- Mysql的驱动包--> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- SpringBoot的单元测试--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter-test</artifactId> <version>3.0.4</version> <scope>test</scope> </dependency> </dependencies>
spring.application.name=Mybatis_SpringBoot #配置数据库信息 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_db spring.datasource.username=root spring.datasource.password=123456
package com.mao.pojo; public class User { private Integer id; private String name; private Short age; private Short gender; private String phone; public User() { } public User(Integer id, String name, Short age, Short gender, String phone) { this.id = id; this.name = name; this.age = age; this.gender = gender; this.phone = phone; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Short getAge() { return age; } public void setAge(Short age) { this.age = age; } public Short getGender() { return gender; } public void setGender(Short gender) { this.gender = gender; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", gender=" + gender + ", phone='" + phone + '\'' + '}'; } }
package com.mao.mapper; import com.mao.pojo.User; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper//运行时,自动生成该接口的实现类对象(代理对象),并且将该对象交给IOC容器管理 public interface UserMapper { //查询全部用户信息(用list集合装起来)返回对象为User类型 @Select("select * from user")//填写sql语句 public List<User> list(); }
//整合单元测试的注解 @SpringBootTest class MybatisSpringBootApplicationTests { @Autowired private UserMapper userMapper; @Test public void testListUser(){ List<User> userList = userMapper.list(); userList.stream().forEach(user ->{ System.out.println(user); }); } }
实体类的三个注解(简化操作)
@Data @NoArgsConstructor @AllArgsConstructor
预编译的sql语句更加的安全,更加的高效,就比如已经固定给好参数的sql语句,每次都需要执行,而预编译的使用占位符,单独把sql语句先缓存,后再执行参数,省去了每次都需要缓存sql语句的步骤,性能更高、更安全(防止sql注入)
-
COUNT(1)
: 计算查询结果集中的行数,性能与COUNT(*)
基本相同。 -
COUNT(\*)
: 计算查询结果集中的总行数,包括所有列,不忽略任何行,通常是最常用和推荐的方式。 -
COUNT(列名)
: 计算查询结果集中某一列非NULL
值的行数,适用于统计特定列中的有效数据。
#{id} 与 ${id}的区别
#是预编译(执行时替换成?号),$是拼接sql语句【可以用于模糊查询】,直接将参数拼接在SQL语句中,存在SQL注入问题(密码改为' or '1' = 1,如何情况下皆可登录)
2、Mybatis的运用
1. 导入依赖
Mybatis起步依赖
Mysql的驱动包
SpringBoot的单元测试
druid连接池
lombok依赖 ==> @Data包含get、set、toString、equals...方法,直接使用
<dependencies> <!-- mybatis的起步依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.4</version> </dependency> <!-- Mysql的驱动包--> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- SpringBoot的单元测试--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter-test</artifactId> <version>3.0.4</version> <scope>test</scope> </dependency> <!-- druid连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.24</version> </dependency> <!-- lombok依赖 方法,直接使用--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.38</version> <scope>provided</scope> </dependency> </dependencies>
2. 创建实体类
三个注解
@Data:包含getter、setter、toString、equals等方法
@NoArgsConstructor:空参构造
@AllArgsConstructor:全参构造
两种定义类型
LocalDate:包含年、月、日
LocalDateTime:包含年、月、日、时、分、秒
@Data @NoArgsConstructor @AllArgsConstructor public class Emp { private Integer id; //ID private String username; //用户名 private String password; //密码 private String name; //姓名 private Short gender; //性别, 1 男, 2 女 private String image; //图像url private Short job; //职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师' private LocalDate entrydate; //入职日期 private Integer deptId; //部门ID private LocalDateTime createTime; //创建时间 private LocalDateTime updateTime; //修改时间 }
2. 创建mapper包
在mapper包下的EmpMapper文件下,包含各种预先定义好的抽象方法,以及实现的sql语句
动态更新等操作,可以在mapper.xml配置文件中实现
@Mapper//运行时,自动创建代理对象,并放入IOC容器中 public interface EmpMapper { //定义抽象方法(并注入删除注解,写入对应的sql语句) 删除员工 @Delete("delete from emp where id = ${id}") public int delete(Integer id); //定义insert操作(如果有多个属性的时候,可以使用对象来获取其属性) 新增员工 //values属性中,不需要再用单引号将每个元素进行包含,里面只需要是占位符的形式即可 @Options(keyProperty = "id", useGeneratedKeys = true)//会自动将生成的主键值,赋值给emp对象的id属性 //useGeneratedKeys = true表示要获取到返回回来的主键值,keyProperty表示给哪个属性进行封装 @Insert("insert into emp(username,name,gender,image,job,entrydate,dept_id,create_time,update_time) " + "values(#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})") public void insert(Emp emp); //更新员工(写完每个更新的属性占位符后,应该写上根据什么条件进行更新,如这里是根据where id = #{id}) @Update("update emp set username= #{username},name = #{name},gender=#{gender},image=#{image},job=#{job},entrydate=#{entrydate},dept_id=#{deptId},update_time=#{updateTime} where id=#{id}") public void update(Emp emp); //查询员工(返回类型为一个emp对象,若为多条数据,则可以使用lise集合进行封装) @Select("select * from emp where id = #{id}") public Emp getById(Integer id); /* //多条件查询(可以存在多个查询结果,所以需要封装在List集合内) @Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc") public List<Emp> getByLimit(String name, short gender, LocalDate begin, LocalDate end);*/ //多条件查询(可以存在多个查询结果,所以需要封装在List集合内)【使用xml形式进行sql操作】 public List<Emp> getByLimit(String name, Short gender, LocalDate begin, LocalDate end); //动态更新 public void update2(Emp emp); // 动态删除foreach【批量删除员工】 public void deleteByids(List<Integer> ids); }
3. Mapper.xml配置文件
此处的配置信息,多用于sql语句的动态使用,也有为了解耦、减少复用性、复杂度
mapper内的namespace标签,命名空间为mapper文件的绝对路径
sql标签内的id对应的是mapper文件中的抽象方法
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace对应的是mapper包的绝对路径--> <mapper namespace="com.mao.mapper.EmpMapper"> <!-- 动态更新员工--> <!-- 动态sql、include--> <sql id="commonSelect"> select id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_time from emp </sql> <update id="update2"> <!-- set可以去除多余的逗号 --> update emp <set> <if test="username != null"> username= #{username}, </if> <if test="name != null"> name = #{name}, </if> <if test="gender != null"> gender=#{gender}, </if> <if test="updateTime != null"> update_time = #{updateTime} </if> </set> where id = #{id} </update> <!-- 批量删除员工 先编写sql语句,delete from emp where id in(11,12);删除11 12的元素 collection:遍历的集合 item:遍历出来的元素 separator:分隔符 open:遍历开始前拼接的SQL片段 close:遍历结束后拼接的SQL片段 --> <delete id="deleteByids"> delete from emp where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </delete> <!-- 动态查询员工--> <!--动态sql--> <select id="getByLimit" resultType="com.mao.pojo.Emp"> <include refid="commonSelect"/> <!-- where可以去除多余的and或者or【有条件成立则进入语句】 --> <where> <!-- if语句用于条件判断,若成立则拼接sql语句 --> <if test="name != null"> name like concat('%', #{name}, '%') </if> <if test="gender != null"> and gender = #{gender} </if> <if test="begin != null and end != null"> and entrydate between #{begin} and #{end} </if> </where> order by update_time desc </select> </mapper>
4. 测试类
定义私有化对象,private EmpMapper empMapper;后续可用于调用
@Autowired,自动导入,让 spring 完成 bean 自动装配的工作
插入操作需要设置对象值时,使用 ==> 对象名.set完成设置
当返回的对象、数据较多时,可以使用List集合进行封装,返回的对象<对象>,一般多为实体类的对象,单简单数值时,也可以是Integer
//整合单元测试的注解 @SpringBootTest class MybatisSpringBootApplicationTests { @Autowired//注入注解,自动导入,让 spring 完成 bean 自动装配的工作 private EmpMapper empMapper; @Test public void testDelete() { int line = empMapper.delete(16); System.out.println(line); } @Test public void testInsert() { Emp emp = new Emp(); emp.setUsername("Jerry"); emp.setName("杰瑞"); //short对象需要强转才可以 emp.setGender((short) 1); emp.setImage("2.jpg"); emp.setJob((short) 2); //LocalDate是年月日,LocalDateTime是年月日时分秒 emp.setEntrydate(LocalDate.of(2025, 4, 12)); emp.setDeptId(1); emp.setCreateTime(LocalDateTime.now()); emp.setUpdateTime(LocalDateTime.now()); empMapper.insert(emp); //输出获取到的返回id属性值 System.out.println(emp.getId()); } @Test public void testUpdate() { //创建对象 Emp emp = new Emp(); emp.setId(16); emp.setUsername("Tom"); emp.setName("汤姆"); //short对象需要强转才可以 emp.setGender((short) 1); emp.setUpdateTime(LocalDateTime.now()); empMapper.update2(emp); } @Test public void testSelect() { //empMapper.getById(20)需要返回一个对象,所以应该直接引入Emp emp = ? Emp emp = empMapper.getById(20); System.out.println(emp); } @Test public void testSelectbyLimit() { /* //全选查询 List<Emp> list = empMapper.getByLimit("张",(short)1,LocalDate.of(2000,12,21),LocalDate.of(2019,12,21)); System.out.println(list);*/ /* //全不选查询【即查询所有】 List<Emp> list = empMapper.getByLimit(null,null,null,null); System.out.println(list);*/ //单选性别为女的查询【动态条件查询】 List<Emp> list = empMapper.getByLimit(null, (short) 2, null, null); System.out.println(list); } @Test public void deleteByids(){ List<Integer> list = Arrays.asList(11, 12); empMapper.deleteByids(list);//把创建的集合传入到方法中 } }
3、Spring整合Mybatis
1. 简化xml配置(Spring、JDBC、Mybatis)
public class JdbcConfig { /*@Value("com.mysql.cj.jdbc.Driver")//给下面变量直接赋值,动态调用则使用占位符 private String driver; @Value("jdbc:mysql://localhost:3306/smbms") private String url; @Value("root") private String userName; @Value("123456") private String password;*/ @Value("${jdbc.driver}")//给下面变量直接赋值,动态调用则使用占位符 private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String userName; @Value("${jdbc.password}") private String password; //导入bean,DataSource负责管理数据库连接的创建、使用和释放 @Bean//让下面的方法产生一个bean,然后交给Spring容器管理 public DataSource dataSource() { DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; } }
@Configuration @ComponentScan("com.mao")//扫描位置 @PropertySource("classpath:jdbc.properties")//获取数据库资源 @Import({JdbcConfig.class,MybatisConfig.class})//若未在JdbcConfig内编写@Configuration,则需要在此导入 public class SpringConfig { }
public class MybatisConfig { //sqlSessionFactory @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){ //创建一个对象 SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); //设置typeAliases的位置 sqlSessionFactoryBean.setTypeAliasesPackage("com.mao.domain"); //获取数据源 sqlSessionFactoryBean.setDataSource(dataSource); return sqlSessionFactoryBean; } @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ //创建一个对象 MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); //获取mapper包的位置 mapperScannerConfigurer.setBasePackage("com.mao.dao"); return mapperScannerConfigurer; } }
public interface AccountDao { //注解形式、配置映射关系 @Insert("insert into tbl_account(name,money) values (#{name},#{money})") void save(Account account); @Delete("delete from tbl_account where id = #{id}") void delete(Integer id); @Update("update tbl_account set name = #{name},money = #{money} where id =#{id}") void update(Account account); @Select("select * from tbl_account where id = #{id}") Account findById(Integer id); @Select("select * from tbl_account") List<Account> findAll(); }
2. 接口的实现,有注解则不需要实现类
//使用注解的形式后,动态代理和反射机制在运行时自动生成代理对象来处理接口方法调用,所以此处无需再写接口的实现类 public interface AccountDao { //注解形式、配置映射关系 @Insert("insert into tbl_account(name,money) values (#{name},#{money})") void save(Account account); @Delete("delete from tbl_account where id = #{id}") void delete(Integer id); @Update("update tbl_account set name = #{name},money = #{money} where id =#{id}") void update(Account account); @Select("select * from tbl_account where id = #{id}") Account findById(Integer id); @Select("select * from tbl_account") List<Account> findAll(); }
3. 实体类domain
// Serializable接口是Java编程语言中的一个标记接口,它用于启用其序列化功能。 // 简单来说,只有实现了Serializable接口的类的对象才能被序列化和反序列化 public class Account implements Serializable { private Integer id; private String name; private Double money; public Integer getId() { return id; } public String getName() { return name; } public Double getMoney() { return money; } public void setId(Integer id) { this.id = id; } public void setName(String name) { this.name = name; } public void setMoney(Double money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } }
xxxxxxxxxx6 1@Configuration2@ComponentScan("com.mao")3@PropertySource("jdbc.properties")4public class SpringConfig {5}6name=com.mysql.cj.jdbc.Driverjava
@Service public class AccountServiceImpl implements AccountService { @Autowired //导入注解、自动生成bean private AccountDao accountDao; public void save(Account account) { accountDao.save(account); } public void update(Account account) { accountDao.update(account); } public void delete(Integer id) { accountDao.delete(id); } public Account findById(Integer id) { return accountDao.findById(id); } public List<Account> findAll() { return accountDao.findAll(); } }
@Service public interface AccountService { public void save(Account account); public void update(Account account); public void delete(Integer id); public Account findById(Integer id); public List<Account> findAll(); }
5. SqlSessionFactoryBean测试类
public class App { public static void main(String[] args) throws IOException { // 1. 创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 2. 加载SqlMapConfig.xml配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml.bak"); // 3. 创建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); // 4. 获取SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 5. 执行SqlSession对象执行查询,获取结果User,获取数据层接口 AccountDao accountDao = sqlSession.getMapper(AccountDao.class); Account ac = accountDao.findById(2); System.out.println(ac); // 6. 释放资源 sqlSession.close(); } }
通过拿数据层接口Service,再向下调用,进行测试
public class App2 { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); AccountService accountService = ctx.getBean(AccountService.class); Account ac = accountService.findById(2); System.out.println(ac); } }
6. 整合Junit
导入pom配置
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency>
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class AccountServiceTest { @Autowired private AccountService accountService; @Test public void testFindById(){ System.out.println(accountService.findById(1)); } @Test public void testFindAll(){ //泛型一定要对应 List<Account> accountList = accountService.findAll(); System.out.println(accountList); } }
4、AOP简介
@Component代表把以下内容,封装为bean,交给Spring容器执行
@Aspect,代表以下内容生效,说明下面内容为AOP内容,切面类、
@EnableAspectJAutoProxy,开启AOP的注解功能
切入点,执行
ProceedingJoinPoint校验访问的对象
获取签名信息
signature.getDeclaringTypeName( ) 获取类包名
signature.getName( ) 获取方法名
二、SpringMVC学习
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mao</groupId> <artifactId>SpringMvc_quickstart</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>SpringMvc_quickstart Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- 1.导入坐标springmvc与servlet--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>7.0.0-M3</version> </dependency> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <!-- Tomcat 10 对应 Servlet 6.0 --> <scope>provided</scope> <!-- 由 Tomcat 提供,不打包进 WAR --> </dependency> </dependencies> <build> <finalName>SpringMvc_quickstart</finalName> </build> </project>
//2.定义controller //2.1使用@Controller定义bean @Controller//声明识别为bean public class UserController { //2.2设置当前操作的访问路径 @RequestMapping("/save") //2.3设置当前操作的返回值类型 @ResponseBody public String save(){ System.out.println("user save ..."); return "{'module':'springMvc'}"; } }
//Spring的配置类 //3.创建SpringMvc的配置文件,加载controller对应的bean @Configuration//创建或初始化bean @ComponentScan("com.mao.controller")//指定扫描哪里的bean public class SpringMvcConfig { }
//4.定义一个servlet容器的启动类,在里面加载spring的配置,按照spring继承的方式开发 public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer { //记载springMVC容器配置 @Override protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } //设置哪些请求归属springMVC处理 @Override protected String[] getServletMappings() { return new String[]{"/"};//所有请求归其处理 } //加载Spring容器配置 @Override protected @Nullable WebApplicationContext createRootApplicationContext() { return null; } }
1、一些必要的注解(前提、导入JSON坐标)
1. SpringMvc解决乱码问题的过滤器
2. @RequestParam
GET / POST请求存在的几个问题
若形式参数的名称对应不上,那么加入此注解,@RequestParam("name") String username;
若对象为List集合,那么就需要加@RequestParam
其他统一的则不需要额外加@RequestParam
@RequestParam,形参注解,用于绑定请求参数与处理器方法形参间的关系
3. JSON格式
JSON格式首先为:["game","music","travel"]
在mvc中,需要加入注解@EnableWebMvc才可以使用JSON格式的传递和接收
其次需要在形式参数前面加@RequestBody注解
4. @RequestParam 和 @RequestBody的区别
5. 日期型参数传递
需要加入注解@DateTimeFormat,并需要其属性 => pattern=" ",引号中为日期格式的样式,如图所示
因为内部有类型转换器接口,Converter接口,所以会自动根据类型帮我们完成转换
6. @ResponseBody
可以用于响应JSON数据,在方法体之前加入此注解即可,把需要返回的东西写上,返回值类型 + return 数据;
因为内部有类型转换器接口,HttpMessageConverter接口,将HTTP的消息进行转换
2、Rest风格
全称为Representational State Transfer,表现形式状态转换
优点:
1. @RequestMapping
使用Rest风格开发后,因为不知道到底是调用了什么方法,所以需要在@RequestMapping加入method属性
@RequestMapping(value = "/users",method = RequestMethod.POST)
value是请求访问路径
删除请求:
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE) 因为删除需要传id,所以需要花括号引入属性
然后要在方法体中,加入注解@PathVariable,用于映射 URL 绑定的占位符,即上文提到的花括号,只有在需要id传递时需要
2. @RestController
包含@RequestBody和@Controller两个注解,然后放于@RequestMapping上面,而@RequestMapping直接放于类前,达到通用的效果,如@RequestMapping("/books"),下面就不需要写value了,只有需要特定传递参数时才需要,比如delete操作,需要根据id去删除
3. @PostMapping
4. @DeleteMapping
这些都可以直接代替@RequestMapping(value = "/{id}" , method = RequestMethod.DELETE)
5. @PutMapping
6. @GetMapping
7. Lombok依赖
可以使用@Data等注解,去简化pojo类的开发
3、SSM整合开发
1. 导入pom配置坐标
注意此处的版本问题,老是困扰我,导致extends AbstractAnnotation...出现问题
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.23</version> <!-- 或使用你需要的版本 --> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>6.2.5</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>6.2.5</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.17</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.24</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.16</version> <!-- 推荐 1.2.8+ --> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.18.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> </dependencies>
2. 编写jdbc.properties
Mysql8.0以上的版本,在加载驱动时,需要加上cj
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm_db?useSSL=false jdbc.username=root jdbc.password=123456
3. 编写实体类domain的book
package com.mao.domain; public class Book { private Integer id; private String type; private String name; private String description; public Book() { } public Book(Integer id, String type, String name, String description) { this.id = id; this.type = type; this.name = name; this.description = description; } @Override public String toString() { return "Book{" + "id=" + id + ", type='" + type + '\'' + ", name='" + name + '\'' + ", description='" + description + '\'' + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
4. 数据层接口(不依托实现类)
使用注解的形式,不依托实现类来实现sql语句的调用,之前都是sql的相应和请求进行sql处理
public interface BookDao { @Insert("insert into tbl_book (type,name,description) values (#{type},#{name},#{description})") public void save(Book book); @Update("update tbl_book set type = #{type} , name = #{name}, description = #{description} where id = #{id}") public void update(Book book); @Delete("delete from tbl_book where id = #{id}") public void delete(Integer id); @Select("select * from tbl_book where id = #{id}") public Book getById(Integer id); @Select("select * from tbl_book") public List<Book> getAll(); }
5. 业务层接口的实现类
service层调用dao层进行数据持久化,处理业务逻辑
最重要的是 必须先引入数据层的对象
@Autowired注解
将某个类的实例注入到当前类中,实现依赖注入,
自动注入依赖对象(可以是服务类、DAO层的对象等),所以在后续才可以调用bookdao对象完成业务操作
@Service注解
通常用于标记业务逻辑层的类,以便 Spring 容器能够将其识别为一个 Bean。
将类标识为服务层 Bean,让 Spring 容器能扫描并管理它。
save操作
update操作
delete操作
get操作
and so on
@Service public class BookServiceImpl implements BookService { @Autowired private BookDao bookDao; @Override public boolean save(Book book) { bookDao.save(book); return true; } @Override public boolean update(Book book) { bookDao.update(book); return true; } @Override public boolean delete(Integer id) { bookDao.delete(id); return false; } @Override public Book getById(Integer id) { return bookDao.getById(id); } @Override public List<Book> getAll() { return bookDao.getAll(); } }
6. 业务层的接口
此部分主要是对方法进行一个抽象化的业务逻辑,但是需要进行实现
在不同的实现中解耦业务逻辑和数据访问层
@Transactional
是 Spring 框架中的一个注解,用于声明事务管理。
在业务层中,通常我们会在业务逻辑方法上使用
@Transactional
注解确保该方法中的操作在同一个事务上下文中执行。
它保证了事务的一致性、隔离性、持久性等特性,确保业务操作的原子性。
@Transactional public interface BookService { /** * 保存 * @param book * @return */ public boolean save(Book book); /** * 修改 * @param book * @return */ public boolean update(Book book); /** * 根据id删除 * @param id * @return */ public boolean delete(Integer id); /** * 根据id查询 * @param id * @return */ public Book getById(Integer id); /** * 查询全部 * @return */ public List<Book> getAll(); }
7. 控制层(处理前端发送的请求)
1. BookController
@Autowired private BookService bookService;
这里就是自动注入依赖对象,所以在此类中,可调用bookService完成相应的操作
主要通过以下几个注解
@RestController
@Controller
@RequestMapping("/books")
再使用其他请求的注释
加上@PostMapping等注释
加上@RequestBody
加上@PathVariable
比如POST、GET、PUT、DELETE等请求
比如前端传递的表单数据、URL参数等
比如用户需要进行一个订单创建请求
接收前端请求,委托给service层处理
等service层调用dao层处理完毕后
service层把处理结果返回给controller层
controller层接收到service层返回的数据,再以JSON数据的形式返回给前端页面,进行展示
@RestController @RequestMapping("/books") public class BookController { @Autowired private BookService bookService; @PostMapping public Result save(@RequestBody Book book) { boolean flag = bookService.save(book); //Result对象,三个构造方法、空参、 code,data、 code,data,msg; //这里返回的是两参 return new Result(flag ? Code.SAVE_SUCCESS : Code.SAVE_FAIL, flag); } @PutMapping public Result update(@RequestBody Book book) { boolean flag = bookService.update(book); //Result对象,三个构造方法、空参、 code,data、 code,data,msg; //这里返回的是两参 return new Result(flag ? Code.UPDATE_SUCCESS : Code.UPDATE_FAIL, flag); } @DeleteMapping("/{id}") public Result delete(@PathVariable Integer id) { boolean flag = bookService.delete(id); //Result对象,三个构造方法、空参、 code,data、 code,data,msg; //这里返回的是两参 return new Result(flag ? Code.DELETE_SUCCESS : Code.DELETE_FAIL, flag); } @GetMapping("/{id}") public Result getById(@PathVariable Integer id) { Book book = bookService.getById(id); Integer code = book != null ? Code.GET_SUCCESS : Code.GET_FAIL; String msg = book !=null ? "" :"数据查询失败,请重试"; //Result对象,三个构造方法、空参、 code,data、 code,data,msg; //这里返回的是全参 return new Result(code,book,msg); } @GetMapping public Result getAll() { List<Book> bookList = bookService.getAll(); Integer code = bookList != null ? Code.GET_SUCCESS : Code.GET_FAIL; String msg = bookList !=null ? "" :"数据查询失败,请重试"; //Result对象,三个构造方法、空参、 code,data、 code,data,msg; //这里返回的是全参 return new Result(code,bookList,msg); } }
2. Code
用于处理给前端页面展示的 代码 ,告诉用户处理完成的情况
这个类
Code
的作用是 定义一组常量,用于表示不同的操作状态码,通常用于在应用中统一管理 操作成功 和 操作失败 的状态码。
这些常量通常会用于 API 响应中,与
Result
类的code
字段配合使用。final断子绝孙
当一个变量被声明为
final
时,这个变量一旦被初始化后就不能再改变其值。final int a = 10; // a = 20; // 编译错误,a 不能被重新赋值
class Parent { public final void show() { System.out.println("Parent show"); } }
class Child extends Parent { // public void show() { // 编译错误,无法重写父类的 final 方法 // System.out.println("Child show"); // } }
final class FinalClass { // some methods }
class SubClass extends FinalClass { // 编译错误,不能继承 final 类 // some methods }
"断子绝孙”这个说法来源于
final
关键字限制了后续的操作、继承和修改。具体来说:
对
final
变量 的修改被禁止;对
final
方法 的重写被禁止;对
final
类 的继承被禁止。
public class Code { public static final Integer SAVE_SUCCESS = 1011; public static final Integer DELETE_SUCCESS = 1012; public static final Integer UPDATE_SUCCESS = 1013; public static final Integer GET_SUCCESS = 1014; public static final Integer SAVE_FAIL = 1021; public static final Integer DELETE_FAIL = 1022; public static final Integer UPDATE_FAIL = 1023; public static final Integer GET_FAIL = 1024; }
3. Result
用于统一封装和返回 API 响应的数据结构
常常需要将响应结果统一封装为某种标准格式
这个类就是用来作为统一的 API 响应格式。
package com.mao.controller; public class Result { private Object data; private Integer code; private String msg; public Result() { } public Result(Integer code, Object data) { this.code = code; this.data = data; } public Result(Integer code, Object data, String msg) { this.code = code; this.data = data; this.msg = msg; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
8. config配置类
1. JdbcConfig类
@Bean注解的作用
@Bean
注解用于 声明一个方法是一个 Bean 定义,并将该方法的返回值作为一个 Spring 容器中的 Bean 实例通常用于 手动创建并注册第三方的或其他不方便直接通过自动装配的方式管理的 Bean。
Spring容器的工作原理
Spring 容器是 Spring Framework 的核心
负责对象的创建、生命周期管理、依赖注入(DI)、AOP(面向切面编程)等功能。
容器初始化:
当 Spring 应用启动时,Spring 容器(
ApplicationContext
)会首先初始化。Spring 容器会加载应用上下文的配置类(Java 配置类、XML 配置文件等),并扫描配置中定义的所有 Bean。Bean 定义与注册:
@Component
,@Service
,@Repository
,@Controller
,@Bean
等注解标记的类和方法会被 Spring 自动扫描并注册为 Bean。Spring 容器会通过读取配置类中的
@Bean
方法,或者通过类上的注解(如@Component
)来发现需要创建的 Bean。Bean 实例化:
一旦 Bean 被定义并注册,Spring 容器会根据配置和上下文来实例化这些 Bean(调用带有
@Bean
注解的方法或自动扫描的类的构造函数)。依赖注入(DI):
一旦 Bean 被实例化,Spring 会自动注入依赖的 Bean。比如使用
@Autowired
注解自动注入依赖,或者手动在配置类中注入。生命周期管理:
Spring 会管理 Bean 的生命周期,包括初始化、销毁等操作。你可以通过实现
InitializingBean
和DisposableBean
接口,或者使用@PostConstruct
和@PreDestroy
注解来定义初始化和销毁方法。使用和访问 Bean:
一旦 Bean 创建并完成依赖注入,Spring 容器就会管理这个 Bean。其他组件可以通过依赖注入(例如
@Autowired
)访问这些 Bean。容器关闭:
当应用停止时,Spring 容器会关闭并销毁管理的所有 Bean,释放相关资源。
public class JdbcConfig { //动态获取外部配置文件中的值 @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean//变成bean注解,第三方bean依赖导入 public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } }
2. MybatisConfig类
SqlSessionFactoryBean
:
创建并配置一个
SqlSessionFactory
实例。
SqlSessionFactory
是 MyBatis 中与数据库交互的核心,负责提供SqlSession
来执行 SQL 操作。设置数据源(
DataSource
)和类型别名包(setTypeAliasesPackage
),使得 MyBatis 能够连接到数据库并简化 XML 配置文件中的类名引用。
MapperScannerConfigurer
:
自动扫描指定包中的 Mapper 接口并注册为 Spring 的 Bean。
这些 Mapper 接口会被自动代理,Spring 可以通过依赖注入来使用这些接口,执行 SQL 操作。
public class MybatisConfig { @Bean//自动代理 public SqlSessionFactoryBean SqlSessionFactory(DataSource dataSource) { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setTypeAliasesPackage("com.mao.domain"); return factoryBean; } @Bean//自动代理 public MapperScannerConfigurer getMapperScannerConfigurer() { MapperScannerConfigurer configurer = new MapperScannerConfigurer(); configurer.setBasePackage("com.mao.dao"); return configurer; } }
3. SpringConfig类
多注解组合在一起,构成了一个 Spring 配置类
用于配置和管理 Spring 应用的组件、事务和外部资源。
通过
SpringConfig
类,Spring 容器能够:
扫描和管理服务层的 Bean。
加载外部配置文件中的数据库连接属性。
集成数据库和 MyBatis 配置。
启用事务管理,确保数据库操作的原子性和一致性。
@Configuration @ComponentScan({"com.mao.service"}) // 自动扫描并注册指定包下的组件 @PropertySource("classpath:jdbc.properties") // 加载外部配置文件(如 jdbc 配置) @Import({JdbcConfig.class, MybatisConfig.class}) // 导入其他配置类,实现模块化配置 @EnableTransactionManagement // 启用 Spring 声明式事务管理 public class SpringConfig { }
4. SpringMvcConfig类
这段代码定义了一个 Spring 配置类
SpringMvcConfig
,用于配置 Spring MVC 相关的内容特别是加载和管理 Controller 相关的 Bean,并启用 Spring MVC 功能。
SpringMvcConfig
类的作用是为 Spring MVC 配置环境,它包含以下几个核心功能:
扫描 Controller:自动扫描
com.mao.controller
包中的所有类并注册为 Spring Bean,特别是@Controller
注解的类。启用 Spring MVC:通过
@EnableWebMvc
启用 Spring MVC 功能,使 Spring MVC 能够处理 HTTP 请求,配置DispatcherServlet
等。定义配置类:通过
@Configuration
注解,告诉 Spring 这是一个配置类,负责配置和初始化相关的 Spring MVC 组件。
//Spring的配置类 //3.创建SpringMvc的配置文件,加载controller对应的bean @Configuration//创建或初始化bean @ComponentScan({"com.mao.controller"})//指定扫描哪里的bean @EnableWebMvc public class SpringMvcConfig { }
5. ServletContainerInitConfig类
ServletContainerInitConfig
是一个 Spring 配置类,主要用于配置和初始化DispatcherServlet
,并替代传统的web.xml
文件。主要完成以下任务:
配置 Spring 根容器:
通过
getRootConfigClasses()
指定 Spring 配置类(SpringConfig.class
)这些配置类用于管理与 Web 层无关的 Bean(如数据库连接、事务管理等)。
配置 Spring MVC 环境:
通过
getServletConfigClasses()
指定 Spring MVC 配置类(SpringMvcConfig.class
)它用于配置与 Web 层相关的 Bean(如 Controller、视图解析器等)。
配置 Servlet 映射:
通过
getServletMappings()
指定DispatcherServlet
的请求映射路径。在这里,
"/"
映射表示所有的请求都会由DispatcherServlet
处理。配置过滤器:
通过
getServletFilters()
配置了CharacterEncodingFilter
确保所有请求和响应都使用 UTF-8 编码,从而避免出现乱码问题。
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"};//访问所有斜杠下的请求 } //乱码处理 @Override protected Filter[] getServletFilters(){ CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("UTF-8"); filter.setForceEncoding(true); return new Filter[]{filter}; } }
9. 测试类
这段代码是一个 Spring 集成测试,它使用了 Spring 的依赖注入和 JUnit 框架来测试 BookService 的方法。
通过 @RunWith(SpringJUnit4ClassRunner.class) 启动 Spring 容器并加载配置类
@Autowired 注解将 BookService 注入到测试类中
最后通过 @Test 注解的方法验证 getById() 和 getAll() 方法的功能是否正常。
@RunWith(SpringJUnit4ClassRunner.class):让 JUnit 使用 Spring 测试支持运行测试。
@ContextConfiguration(classes = SpringConfig.class):加载 Spring 配置类。
@Autowired:自动注入 Spring 管理的 BookService Bean。
@Test:定义一个 JUnit 测试方法,验证 BookService 的功能
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class BookServiceTest { @Autowired private BookService bookService; @Test public void testGetById(){ Book book = bookService.getById(1); System.out.println(book); } @Test public void testGetAll() { List<Book> books = bookService.getAll(); System.out.println(books); } }
10. 拦截器
4、Maven高级
1. 可选依赖(不透明,不公开被使用)
<optional> true </optional>为可选依赖,如果开启true则是隐藏这个依赖,不让别人去依赖,对应资源不具备依赖性了。
2. 排除依赖(不需要此个依赖,无需添加版本,直接全局排除)
3. 聚合工程
<packaging>pom</packaging> <modules> <module>../SsmStudy/Maven_02_Pojo</module> <module>../SsmStudy/Maven_03_Dao</module> <module>../SsmStudy/Maven_01_Plus</module> </modules>