springboot
SpringBoot笔记
前言
教程文档:
黑马:Docs
苍穹外卖:苍穹外卖_吾浴西风的博客-CSDN博客
起步
初始程序
在idea选择 springboot generators,在选择依赖中加入spring web 依赖 创建即可
spring web中包含了tomcat启动时即会启动tomcat
结构:
pom
在创建好项目后,项目会依赖着springboot父工程,其下再引入springboot的其他依赖时不用指明版本,父工程内已声明了
启动类:
自动生成,被@SpringBootApplication 注解修饰
资源文件:
static: 存放着静态页面, html css js
application.properties:springboot的配置, 可以改为yml文件
接收前端请求
@RestController //标识当前类是一个请求处理类
public class HelloController {
@RequestMapping("/hello") //标识请求路径
public String hello(String name){
System.out.println("HelloController ... hello: " + name);
return "Hello " + name; //返回的值在响应体内 ,若要返回文件,获取response对象调用.getOutputStream() 将文件写入流即可
}
}
获取和响应数据
tomcat服务器对HTTP协议的请求数据进行解析,并进行了封装
springboot的获取数据会封装到tomcat提供的类中, 如请求HttpServletRequest,响应 HttpServletResponse
@RestController
public class RequestController {
/**
* 请求路径 http://localhost:8080/request?name=Tom&age=18
* @param request
* @return
*/
@RequestMapping("/request")
public String request(HttpServletRequest request){
//1.获取请求参数 name, age
String name = request.getParameter("name");
String age = request.getParameter("age");
System.out.println("name = " + name + ", age = " + age);
//2.获取请求路径
String uri = request.getRequestURI(); // /request
String url = request.getRequestURL().toString();// /http://localhost:8080/request
System.out.println("uri = " + uri);
System.out.println("url = " + url);
//3.获取请求方式
String method = request.getMethod();
System.out.println("method = " + method);
//4.获取请求头
String header = request.getHeader("User-Agent");
System.out.println("header = " + header);
return "request success";
//5.获取请求体
BufferedReader reader = null;
reader = request.getReader();
}
}
设置响应数据
@RestController
public class ResponseController {
@RequestMapping("/response")
public void response(HttpServletResponse response) throws IOException {
//1.设置响应状态码
response.setStatus(401);
//2.设置响应头
response.setHeader("name","itcast");
//3.设置响应体
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
response.getWriter().write("<h1>hello response</h1>");
//以流的形式写入 getOutputStream() 获取流
}
@RequestMapping("/response2")
public ResponseEntity<String> response2(){
return ResponseEntity #以spring提供的ResponseEntity进行返回
.status(401)
.header("name","itcast")
.body("<h1>hello response</h1>"); //泛型类型就是这里响应体的类型
}
}
RestController注解
@RestController 由@Controller 和@ResponseBody 组合而成
Controller 注解标明该类是一个接收请求的类,
ResponseBody 标明该类方法内将方法返回值直接响应给浏览器,如果返回值类型是实体对象/集合,将会转换为JSON格式后在响应给浏览器
@RestController
public class UserController {
@RequestMapping("/list")
public List<User> list(){
//1.加载并读取文件
InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");
ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8, new ArrayList<>());
//2.解析数据,封装成对象 --> 集合
List<User> userList = lines.stream().map(line -> {
String[] parts = line.split(",");
Integer id = Integer.parseInt(parts[0]);
String username = parts[1];
String password = parts[2];
String name = parts[3];
Integer age = Integer.parseInt(parts[4]);
LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
return new User(id, username, password, name, age, updateTime);
}).collect(Collectors.toList());
//3.响应数据
//也可以自己解析成字符串返回,不用通过Spring解析
//return JSONUtil.toJsonStr(userList, JSONConfig.create().setDateFormat("yyyy-MM-dd HH:mm:ss"));
return userList;
}
}
static静态资源
由于spring web依赖内嵌了tomcat,在resource内的static就是tomcat提供的,在其里面放置的静态资源在外部可像发起前端请求一样,之前获取界面
相当于托管了前端页面,如
static
-index.html
-css
-js
在外部访问时, host:post/index.html 即可访问
分层解耦
三层架构
把后端的功能分层3层结构
controller:
控制层,负责接收前端的数据,调用服务层,再将数据返回
service:
服务层,负责逻辑处理
dao:
数据层,各个实体类就在这里,可以使用实体类操作数据
解耦
spring 2个核心概念
-
控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
- 对象的创建权由程序员主动创建转移到容器(由容器创建、管理对象)。这个容器称为:IOC容器或Spring容器。
-
依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
- 程序运行时需要某个资源,此时容器就为其提供这个资源。
- 例:EmpController程序运行时需要EmpService对象,Spring容器就为其提供并注入EmpService对象。
具体实现:
每个实现类都有一个接口,在外部调用实现类时,直接调用接口
使用@Component 修饰实现类,将实现类交给spring容器管理
在外部调用时,声明其接口类,使用@Autowired修饰该变量,spring会自动创建对应的类
//服务层接口
public interface UserService {
public List<User> findAll();
}
//管理层进行逻辑处理,调用数据层数据
@Component
public class UserServiceImpl implements UserService {
//依赖注入
@Autowired
private UserDao userDao;
@Override
public List<User> findAll() {
}
}
//由控制层调用服务处
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/list")
public List<User> list(){
//1.调用Service
List<User> userList = userService.findAll();
//2.响应数据
return userList;
}
}
IOC(控制反转)
衍生注解
使用衍生注解可标明是哪一层的, 可以不用,直接使用 Component注解
| 注解 | 说明 | 位置 |
|---|---|---|
| @Component | 声明bean的基础注解 | 不属于以下三类时,用此注解 |
| @Controller | @Component的衍生注解 | 标注在控制层类上 |
| @Service | @Component的衍生注解 | 标注在业务层类上 |
| @Repository | @Component的衍生注解 | 标注在数据访问层类上(由于与mybatis整合,用的少) |
组件扫描
- 前面声明bean的四大注解,要想生效,还需要被组件扫描注解
@ComponentScan扫描。 - 该注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解
@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包。
若要扫描其他包,需要手动添加@ComponentScan注解
@ComponentScan({"com.littled","com.abc"}) //传给value的数组就是添加的包
- 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
- 使用以上四个注解都可以声明bean,但是声明控制器bean只能用@Controller。@RestController 包含着Controller注解
DI(依赖注入)
Autowired注入
@Autowired注解,默认是按照类型进行自动装配的(去IOC容器中找某个类型的对象,然后完成注入操作)
若将多个实现同一个父类接口的类托管给IOC容器,则在注入时会发生报错,此时需要使用其他注解
属性注入:
@RestController
public class UserController {
//方式一: 属性注入
@Autowired
private UserService userService;
}
构造函数注入:
如果只有一个构造函数,@Autowired注解可以省略。(通常来说,也只有一个构造函数)
@RestController
public class UserController {
//方式二: 构造器注入
private final UserService userService;
@Autowired //如果当前类中只存在一个构造函数, @Autowired可以省略
public UserController(UserService userService) {
this.userService = userService;
}
}
set注入:
@RestController
public class UserController {
//方式二: 构造器注入
private final UserService userService;
@Autowired //如果当前类中只存在一个构造函数, @Autowired可以省略
public UserController(UserService userService) {
this.userService = userService;
}
}
其他注入方式
使用@Primary注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现。
使用@Qualifier注解:指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。
使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。
- @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
- @Autowired 默认是按照类型注入,而@Resource是按照名称注入
@Primary
@Service
public class ServiceA implements Service{}
@Autowired
@Qualifier("serviceA") //IOC容器内bean对象容器名称,默认为类的首字母小写,也可在声明时自己指定
@Primary
@Service
public class ServiceA implements Service{}
请求控制
请求类别
前端的请求有 get,post,delete等, 在用@RequestMapping获取时,需要判断请求类别
可以使用对应方法的注解进行接收
get: @GetMapping("URI")
post: @PostMapping("URI")
delete: @DeleteMapping("URI")
请求参数
路径参数:
/depts/{id}
使用@PathVariable 注解 获取
@DeleteMapping("/depts/{id}")
public Result delete(@PathVariable Integer id) {
}
/depts?name=littled&age=18
使用@RequestParam 注解获取,按键名和变量名配对
可设置默认值@RequestParam(defaultValue = "1")
@DeleteMapping("/depts")
public Result delete(@RequestParam String name,@RequestParam Integer age) {
}
请求体参数:
若请求体是json类型,可用@RequestBody 将JSON直接封装到实体类中
若不封存到对象中,则使用与键名相同的变量名自动接收,若名字不同可使用@RequestParam("键名") 指定名字
@PostMapping("/depts")
public Result add(@RequestBody Dept dept){
}
请求路径
可在一个控制类中声明该控制类接管的路径
在RestController注解的value中声明
@Slf4j
@RestController("/user")
public class DeptController {
@PostMapping("/depts") //实际是接管 /user/depts
public Result add(@RequestBody Dept dept){
}
}
配置文件
springboot的配置文件可改为yml格式
在配置文件内的配置可使用@Value 注解读取
@Component
public class AliOSSUtils {
@Value("${qwq.awa.aaaa}")
private String name;
}
qwq.awa.aaaa=littled
@ConfigurationProperties注解:
需要引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
@ConfigurationProperties可以批量的将外部的属性配置注入到bean对象的属性中
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/*阿里云OSS相关配置*/
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
//区域
private String endpoint;
//身份ID
private String accessKeyId ;
//身份密钥
private String accessKeySecret ;
//存储空间
private String bucketName;
}
使用这些配置文件的注解,都需要先注入类 也就是@AutoWired
过滤器Filter
步骤:
定义过滤器 :定义一个类,实现 Filter 接口,并重写其所有方法。
配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件支持
定义过滤器
//定义一个类,实现一个标准的Filter过滤器的接口
@WebFilter(urlPatterns = "/*") //配置过滤器要拦截的请求路径( /* 表示拦截浏览器的所有请求 )
public class DemoFilter implements Filter {
@Override //初始化方法, 只调用一次
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init 初始化方法执行了");
}
@Override //拦截到请求之后调用, 调用多次
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("Demo 拦截到了请求...放行前逻辑");
//放行
chain.doFilter(request,response);
}
@Override //销毁方法, 只调用一次
public void destroy() {
System.out.println("destroy 销毁方法执行了");
}
}
Filter是servlet提供的,在springboot中要使用,还需要在启动类中开启,加上@ServletComponentScan注解 即可
@ServletComponentScan
@SpringBootApplication
public class TliasWebManagementApplication {
public static void main(String[] args) {
SpringApplication.run(TliasWebManagementApplication.class, args);
}
}
过滤器链
过滤器链指的是在一个web应用程序当中,可以配置多个过滤器,多个过滤器就形成了一个过滤器链
以注解方式配置的Filter过滤器,它的执行优先级是按时过滤器类名的自动排序确定的,类名排名越靠前,优先级越高
拦截器Interceptor
- 是一种动态拦截方法调用的机制,类似于过滤器。
- 拦截器是Spring框架中提供的,用来动态拦截控制器方法的执行。
步骤:
定义拦截器
注册配置拦截器
自定义拦截器:实现HandlerInterceptor接口,并重写其所有方法
//自定义拦截器
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
//目标资源方法执行前执行。 返回true:放行 返回false:不放行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle .... ");
return true; //true表示放行
}
//目标资源方法执行后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle ... ");
}
//视图渲染完毕后执行,最后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion .... ");
}
}
注册配置拦截器:实现WebMvcConfigurer接口,并重写addInterceptors方法,加上@Configuration注解
@Configuration
public class WebConfig implements WebMvcConfigurer {
//自定义的拦截器对象
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册自定义拦截器对象
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");//设置拦截器拦截的请求路径( /** 表示拦截所有请求)
registry.addInterceptor(loginCheckInterceptor)
.addPathPatterns("/**")//设置拦截器拦截的请求路径( /** 表示拦截所有请求)
.excludePathPatterns("/login");//设置不拦截的请求路径
}
}
| 拦截路径 | 含义 | 举例 |
|---|---|---|
| /* | 一级路径 | 能匹配/depts,/emps,/login,不能匹配 /depts/1 |
| /** | 任意级路径 | 能匹配/depts,/depts/1,/depts/1/2 |
| /depts/* | /depts下的一级路径 | 能匹配/depts/1,不能匹配/depts/1/2,/depts |
| /depts/** | /depts下的任意级路径 | 能匹配/depts,/depts/1,/depts/1/2,不能匹配/emps/1 |
注:
当拦截器和过滤器都存在时,先走过滤器再走拦截器
- 当我们打开浏览器来访问部署在web服务器当中的web应用时,此时我们所定义的过滤器会拦截到这次请求。拦截到这次请求之后,它会先执行放行前的逻辑,然后再执行放行操作。而由于我们当前是基于springboot开发的,所以放行之后是进入到了spring的环境当中,也就是要来访问我们所定义的controller当中的接口方法。
- Tomcat并不识别所编写的Controller程序,但是它识别Servlet程序,所以在Spring的Web环境中提供了一个非常核心的Servlet:DispatcherServlet(前端控制器),所有请求都会先进行到DispatcherServlet,再将请求转给Controller。
- 当我们定义了拦截器后,会在执行Controller的方法之前,请求被拦截器拦截住。执行`preHandle()`方法,这个方法执行完成后需要返回一个布尔类型的值,如果返回true,就表示放行本次操作,才会继续访问controller中的方法;如果返回false,则不会放行(controller中的方法也不会执行)。
- 在controller当中的方法执行完毕之后,再回过来执行`postHandle()`这个方法以及`afterCompletion()` 方法,然后再返回给DispatcherServlet,最终再来执行过滤器当中放行后的这一部分逻辑的逻辑。执行完毕之后,最终给浏览器响应数据。
事务
Transactional注解
@Transactional注解书写位置:
- 方法
- 当前方法交给spring进行事务管理
- 类
- 当前类中所有的方法都交由spring进行事务管理
- 接口
- 接口下所有的实现类当中所有的方法都交给spring 进行事务管理
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Autowired
private EmpMapper empMapper;
@Override
@Transactional //当前方法添加了事务管理
public void delete(Integer id){
//根据部门id删除部门信息
deptMapper.deleteById(id);
//模拟:异常发生
int i = 1/0; //运行时异常
//删除部门下的所有员工信息
empMapper.deleteByDeptId(id);
}
}
以上业务功能delete()方法在运行时,会引发除0的算数运算异常(运行时异常),出现异常之后,
由于我们在方法上加了@Transactional注解进行事务管理,所以发生异常会执行rollback回滚操作,从而保证事务操作前后数据是一致的。
默认情况下,只有出现RuntimeException(运行时异常)才会回滚事务
配置@Transactional注解当中的rollbackFor属性,通过rollbackFor这个属性可以指定出现何种异常类型回滚事务
@Transactional(rollbackFor=Exception.class)
propagatrion
@Transactional注解当中的第二个属性propagation,这个属性是用来配置事务的传播行为的
| 属性值 | 含义 |
|---|---|
| REQUIRED | 【默认值】需要事务,有则加入,无则创建新事务 |
| REQUIRES_NEW | 需要新事务,无论有无,总是创建新事务 |
| SUPPORTS | 支持事务,有则加入,无则在无事务状态中运行 |
| NOT_SUPPORTED | 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
| MANDATORY | 必须有事务,否则抛异常 |
| NEVER | 必须没事务,否则抛异常 |
| … |
AOP
起步
Aspect Oriented Programming(面相切面编程)
AOP就是可以将代码插入到指定方法的 前面和后面
引入依赖pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
切面类:
@Component
@Aspect //当前类为切面类
public class TimeAspect {
@Around("execution(* com.itheima.service.*.*(..))") //切入点表达式,用于匹配被切入的类的方法
public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
//记录方法执行开始时间
long begin = System.currentTimeMillis();
//执行原始方法
Object result = pjp.proceed();
//记录方法执行结束时间
long end = System.currentTimeMillis();
//计算方法执行耗时
log.info(pjp.getSignature()+"执行耗时: {}毫秒",end-begin);
return result;
}
}
通知类型
Spring中AOP的通知类型:
- @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
- @Before:前置通知,此注解标注的通知方法在目标方法前被执行
- @After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
- @AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
- @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行
通知顺序
默认按照切面类的类名字母排序:
- 目标方法前的通知方法:字母排名靠前的先执行
- 目标方法后的通知方法:字母排名靠前的后执行
如果我们想控制通知的执行顺序有两种方式:
- 修改切面类的类名(这种方式非常繁琐、而且不便管理)
- 使用Spring提供的@Order注解
@Order(2) //切面类的执行顺序(前置通知:数字越小先执行; 后置通知:数字越小越后执行)
切入点表达式
execution
execution主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:
execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
其中带?的表示可以省略的部分
-
访问修饰符:可省略(比如: public、protected)
-
包名.类名: 可省略
-
throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
@Before("execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")
可以使用通配符描述切入点
-
*:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分 -
..:多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
annotation
我们可以借助于另一种切入点表达式annotation来描述这一类的切入点,从而来简化切入点表达式的书写
实现步骤:
-
编写自定义注解
-
在业务类要做为连接点的方法上添加自定义注解
自定义注解:MyLog
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
}
切面类
@Component
@Aspect
public class MyAspect6 {
//前置通知
@Before("@annotation(com.itheima.anno.MyLog)")
public void before(){
log.info("MyAspect6 -> before ...");
}
}
使用:
@MyLog //自定义注解(表示:当前方法属于目标方法)
public List<Dept> list() {
return deptList;
}
Bean
获取Bean
Spring容器中提供了一些方法,可以主动从IOC容器中获取到bean对象,下面介绍3种常用方式:
-
根据name获取bean
Object getBean(String name) -
根据类型获取bean
<T> T getBean(Class<T> requiredType) -
根据name获取bean(带类型转换)
<T> T getBean(String name, Class<T> requiredType)
获取IOC对象:
直接注入
@SpringBootTest
class SpringbootWebConfig2ApplicationTests {
@Autowired
private ApplicationContext applicationContext; //IOC容器对象
//获取bean对象
@Test
public void testGetBean(){
//根据bean的名称获取
DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
System.out.println(bean1);
//根据bean的类型获取
DeptController bean2 = applicationContext.getBean(DeptController.class);
System.out.println(bean2);
//根据bean的名称 及 类型获取
DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
System.out.println(bean3);
}
}
Bean的作用域
| 作用域 | 说明 |
|---|---|
| singleton | 容器内同名称的bean只有一个实例(单例)(默认) |
| prototype | 每次使用该bean时会创建新的实例(非单例) |
| request | 每个请求范围内会创建新的实例(web环境中,了解) |
| session | 每个会话范围内会创建新的实例(web环境中,了解) |
| application | 每个应用范围内会创建新的实例(web环境中,了解) |
可以借助Spring中的@Scope注解来进行配置作用域
@Scope("prototype") //bean作用域为非单例
@Lazy //延迟加载(第一次使用bean对象时,才会创建bean对象并交给ioc容器管理)
@RestController
@RequestMapping("/depts")
public class DeptController {
@Autowired
private DeptService deptService;
public DeptController(){
System.out.println("DeptController constructor ....");
}
}
-
IOC容器中的bean默认使用的作用域:singleton (单例)
-
默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)
第三方Bean
引入的其他依赖中的Bean即为第三方Bean
若要使用IOC容器管理依赖中的类,需要 @Bean 注解
在配置类中定义@Bean标识的方法:
@Configuration //配置类 (在配置类当中对第三方bean进行集中的配置管理)
public class CommonConfig {
//声明第三方bean
@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
//通过@Bean注解的name/value属性指定bean名称, 如果未指定, 默认是方法名
public SAXReader reader(DeptService deptService){
System.out.println(deptService);
return new SAXReader();
}
}
-
通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
-
如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
Mybatis
Mybatis可用于减少JDBC操作
起步
引入Mybatis
在springboot创建时,在sql中选中 Mybatis Framework 和mysql driver即可,其会自动为我们引入对应依赖的配置
<dependencies>
<!-- mybatis起步依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!-- mysql驱动包依赖 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
数据准备
实体类:实体类的属性名与表中的字段名一一对应
例:
用户表 user
create table user(
id int unsigned primary key auto_increment comment 'ID,主键',
username varchar(20) comment '用户名',
password varchar(32) comment '密码',
name varchar(10) comment '姓名',
age tinyint unsigned comment '年龄'
) comment '用户表';
insert into user(id, username, password, name, age) values (1, 'daqiao', '123456', '大乔', 22),
(2, 'xiaoqiao', '123456', '小乔', 18),
实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id; //ID
private String username; //用户名
private String password; //密码
private String name; //姓名
private Integer age; //年龄
}
配置
在 application.properties 中配置数据库的连接信息
#数据库访问的url地址
spring.datasource.url=jdbc:mysql://localhost:3306/web
#数据库驱动类类名
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#访问数据库-用户名
spring.datasource.username=root
#访问数据库-密码
spring.datasource.password=root@1234
Mapper接口
在该接口使用@Mapper注解修饰,方法用对应操作数据库注解修饰,value值为sql语句
方法的返回值为查询到结果后封装数据的对象
如下列
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface UserMapper {
/**
* 查询全部
*/
@Select("select * from user")
public List<User> findAll(); //查到的数据按属性和字段一一对应封装进User对象然后进入list列表
}
- @Mapper注解:表示是mybatis中的Mapper接口
程序运行时,框架会自动生成接口的实现类对象(代理对象),并给交Spring的IOC容器管理
- @Select注解:代表的就是select查询,用于书写select查询语句
查询:
最终在需要操作数据库的地方,注入Mapper接口,直接调用方法
@SpringBootTest
class SpringbootMybatisQuickstartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testFindAll(){
List<User> userList = userMapper.findAll();
for (User user : userList) {
System.out.println(user);
}
}
}
数据库操作
删除
Mapper接口方法:
/**
* 根据id删除
*/
@Delete("delete from user where id = #{id}")
public void deleteById(Integer id);
在Mybatis中,我们可以通过参数占位符号 #{...} 来占位,在调用deleteById方法时,传递的参数值,最终会替换占位符。
DML语句执行完毕,是有返回值的,我们可以为Mapper接口方法定义返回值来接收,如下:
/**
* 根据id删除
*/
@Delete("delete from user where id = #{id}")
public Integer deleteById(Integer id);
Integer类型的返回值,表示DML语句执行完毕影响的记录数
| 符号 | 说明 | 场景 |
|---|---|---|
| # | 占位符。执行时,会将#{…}替换为?,生成预编译SQL | 参数值传递 |
| $ | 拼接符。直接将参数拼接在SQL语句中,存在SQL注入问题 | 表名、字段名动态设置时使用 |
增加
/**
* 添加用户
*/
@Insert("insert into user(username,password,name,age) values(#{username},#{password},#{name},#{age})")
public void insert(User user);
如果在SQL语句中,我们需要传递多个参数,我们可以把多个参数封装到一个对象中。
然后在SQL语句中,我们可以通过#{对象属性名}的方式,获取到对象中封装的属性值。
修改
/**
* 根据id更新用户信息
*/
@Update("update user set username = #{username},password = #{password},name = #{name},age = #{age} where id = #{id}")
public void update(User user);
查询
/**
* 根据用户名和密码查询用户信息
*/
@Select("select * from user where username = #{username} and password = #{password}")
public User findByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
@param注解的作用是为接口的方法形参起名字的。
(由于用户名唯一的,所以查询返回的结果最多只有一个,可以直接封装到一个对象中)
XML映射配置
实现复杂的SQL功能,使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中
规范:
- XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
- XML映射文件的namespace属性为Mapper接口全限定名一致
- XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致


浙公网安备 33010602011771号