Spring +Spirng MVC+Mybatis +SpringBoot

news/2025/3/4 18:09:42/

AI ------>>>直接使用阿里的 通义天问

Maven基础

介绍

Maven 介绍

在这里插入图片描述

Maven 作用

在这里插入图片描述
项目构建 比较简单~

在这里插入图片描述

核心功能

依赖管理

<!--    gavp属性--><groupId>com.example</groupId><artifactId>tials-manage</artifactId><version>0.0.1-SNAPSHOT</version><!--    打包方式 jar--><packaging>jar</packaging><!--   自定义属性--><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.6.13</spring-boot.version></properties>

依赖传递

依赖传递 A----->B------>C

导入依赖,会自动导入依赖的依赖 即依赖传递

在这里插入图片描述

依赖冲突

在这里插入图片描述
解决: 谁短谁 优先—>>>引用的路径长度

在这里插入图片描述

继承

不需要写 版本

在这里插入图片描述
如果 子工程声明了依赖版本,以 子工程 依赖版本为主


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!--    gavp属性--><groupId>com.example</groupId><artifactId>tials-manage</artifactId><version>0.0.1-SNAPSHOT</version><!--    打包方式 jar--><packaging>jar</packaging><!--   自定义属性--><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.6.13</spring-boot.version></properties><!--  导入依赖--><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><!--  依赖范围--><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.9</version></dependency></dependencies><!--  导入插件--><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.example.tialsmanage.TialsManageApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build><!--  只做 依赖的版本控制,不导入依赖--><dependencyManagement></dependencyManagement></project>

Spring

介绍

在这里插入图片描述

IOC


<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><!--  依赖范围--><scope>test</scope>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
@ServletComponentScan // 扫描过滤器
public class TialsManageApplication {public static void main(String[] args) {ConfigurableApplicationContext ioc = SpringApplication.run (TialsManageApplication.class, args);Object zs = ioc.getBean ("zhangsan");}}

@ComponentScan(basePackages = "com.example.tialsmanage") // 扫描注解,只扫 Spring注解

介绍

在这里插入图片描述

@Bean + @Configuration


@Configuration  // 配置类
public class PersonConfig {/*** 将返回值放入容器* 默认是单例的** @return*/@Scope@Bean("zhangsan") // 默认方法名就是 bean的idpublic User zhangsan() {return new User ("zhangsan", 18);}}

@Component 与衍生 分层注解


/*** 默认,分层注解 能起作用的前提是: 这些组件 必须在主程序所在的包及其子包结构下。** Spring为我们提供了快速的 MVC分层注解:* 1. @Controller 控制器* 2. @Service 服务层* 3. @Repository 持久层* 4. @Component 组件** @param args*/

在这里插入图片描述

在这里插入图片描述

@Scope + @Lazy

/*** @Scope 调整组件的作用域:* 1. @Scope("prototype"): 非单实例:*    容器启动的时候 不会 创建非单实例组件的对象。*    什么时候获取,什么时候创建~* 2. @Scope("singleton"): 单实例: 默认值*    容器启动的时候 会创建 单实例组件的对象。*    容器启动完成之前就会创建好* @Lazy: 懒加载*    容器启动 完成之前不会创建 懒加载组件的对象*    什么时候获取,什么时候创建* 3. @Scope("request"): 同一个请求单实例* 4. @Scope("session"): 同一次会话单实例** @return*/@Configuration
@Scope("singleton")
@Lazy   // 单例模式下,可以继续调整为 懒加载public class WebConfig implements WebMvcConfigurer {@Autowiredprivate TokenInterceptor tokenInterceptor;}

@Conditional 条件注册 + @ConditionalOnMissingBean 没有则注册

MacCondition

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;/*** @author dc* @version 1.0* @date 2025/02/26 23:16*/
public class MacCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 判断环境变量中的OS,如果是mac,则返回trueif (context.getEnvironment ().getProperty ("os.name").contains ("Mac")) {return true;}return false;}
}

WindowsCondition

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;/*** @author dc* @version 1.0* @date 2025/02/26 23:15*/
public class WindowsCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 判断环境变量中的OS,如果是 windows,则返回trueString property = context.getEnvironment ().getProperty ("os.name");if (property.contains ("Windows")) {return true;}return false;}
}

** @Conditional 使用 **

@Conditional(value = WindowsCondition.class)@Beanpublic User bill() {return new User ("bill", 25);}@Conditional(value = MacCondition.class)@Beanpublic User qbs() {return new User ("qbs", 35);}

在这里插入图片描述

@Autowired + @Resource + @Primary

import com.example.tialsmanage.Interceptor.TokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource;@Configurationpublic class WebConfig implements WebMvcConfigurer {@Autowired // 按照类型注入private TokenInterceptor tokenInterceptor;@Autowiredprivate User user;@Resourceprivate MacCondition macCondition;@Beanpublic User u2() {return new User ("李四", 21);}@Primary //  按照类型注入时 优先级最高@Beanpublic User u1() {return new User ("张三", 18);}@Beanpublic MacCondition macCondition() {return new MacCondition ();}}

@Profile ---- 多环境

@Profile({"dev", "default"})public User u2() {return new User ("李四", 21);}@Profile("test")@Beanpublic User u1() {return new User ("张三", 18);}

spring:profiles:active: dev

生命周期

在这里插入图片描述

在这里插入图片描述


import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@Data
@AllArgsConstructor
public class User implements InitializingBean, DisposableBean {private String name;private Integer age;public void initUser() {System.out.println ("@Bean   初始化User");}public void destoryUser() {System.out.println ("@Bean  销毁User");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println ("afterPropertiesSet");}@Overridepublic void destroy() throws Exception {System.out.println ("destroy");}@PostConstruct // 构造器之后public void postConstruct() {System.out.println ("PostConstruct");}@PreDestroypublic void preDestroy() {System.out.println ("PreDestroy");}
}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configurationpublic class WebConfig {private MacCondition macCondition;@Autowiredpublic void setMacCondition(MacCondition macCondition) {System.out.println ("自动注入属性"+macCondition); // 在 initMethod之前调用this.macCondition = macCondition;}/*** initMethod 在属性设置之后-->>set之后* @return*/@Bean(initMethod = "initUser",destroyMethod = "destoryUser")public User get() {return new User ("zs", 15);}}

import com.example.tialsmanage.config.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;@Component // 拦截所有Bean的后置处理器
public class MyTestBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println ("【postProcessAfterInitialization】: " + beanName);return bean;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println ("【postProcessBeforeInitialization】: " + beanName);if (bean instanceof User) { // bean为 User类User u = (User) bean;u.setName ("张三测试");}return bean;}
}

单元测试 @SpringBootTest

在这里插入图片描述

import com.example.tialsmanage.config.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
@Slf4j // lombok 日志
class TialsManageApplicationTests {@AutowiredUser user;@Testvoid contextLoads() {System.out.println ("Hello World");}}

AOP

导入依赖


<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.3.12.RELEASE</version>
</dependency>

切面

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Order(1) // 调顺序 ,数字越小--->>>优先级越高
@Component // 交给 spring 管理
@Aspect  // 切面类
public class RecordTimeAspect {/*** 线程本地变量* 每个线程一个*/private static final ThreadLocal<Long> threadLocal = ThreadLocal.withInitial (() -> 3000L);@Around("bf()")public void get() {long val = threadLocal.get ().longValue ();System.out.println (val);}/*** 拦截*/@Pointcut(" execution(* com.example.tialsmanage.demos.web.UploadController.*(..))") // 抽取切点表达式public void bf() {}@Before("@annotation(Login)") // 拦截所有带Login注解的方法public void before() {System.out.println ("before");}@After("@annotation(Login)") // 拦截所有带Login注解的方法public void after() {System.out.println ("after");}}
@After ("@annotation(ReTime)")public Object recordTime(ProceedingJoinPoint joinPoint) {long start = System.currentTimeMillis ();Object proceed = null;try {proceed = joinPoint.proceed ();} catch (Throwable e) {throw new RuntimeException (e);}long end = System.currentTimeMillis ();System.out.println ("运行时间:" + (end - start));return proceed;}

AOP 应用场景

在这里插入图片描述

  1. 日志记录(Logging)

场景:
需要 记录方法 执行时间、参数、返回值或异常信息,但又 不希望日志代码侵入业务逻辑。
实现逻辑:

切面(Aspect):定义日志记录逻辑(如@Around或@AfterThrowing通知)。

切点(Pointcut):匹配需要记录的方法(如 execution(* com.example.service..(…)))。

示例代码(Spring AOP):


@Aspect
@Component
public class LoggingAspect {private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);@Around("execution(* com.example.service.*.*(..))")public Object logMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {long startTime = System.currentTimeMillis();Object result = joinPoint.proceed();long duration = System.currentTimeMillis() - startTime;logger.info("Method {} executed in {} ms", joinPoint.getSignature(), duration);return result;}
}

优势:

日志代码集中管理,业务代码保持简洁。

修改日志策略时 无需改动业务方法

  1. 事务管理(Transaction Management)
    场景:
    在数据库操作中自动开启、提交或回滚事务,避免手动重复编写事务代码。
    实现逻辑:

声明式事务:通过 @Transactional 注解标记事务边界。

底层实现:Spring AOP代理类拦截注解方法,结合PlatformTransactionManager管理事务。

示例配置:


@Service
public class UserService {@Transactionalpublic void createUser(User user) {// 数据库操作(如插入用户记录)}
}

优势:

事务控制与业务逻辑解耦。

支持传播行为、隔离级别等高级配置。

  1. 权限校验(Authentication & Authorization)
    场景:
    在方法执行前验证用户权限(如角色校验、接口访问控制)。
    实现逻辑:

自定义注解:定义权限校验注解(如@RequireRole(“ADMIN”))。

切面拦截:在方法执行前(@Before)校验权限。

示例代码:


@Aspect
@Component
public class SecurityAspect {@Before("@annotation(RequireRole)") // 拦截标注了RequireRole 注解的方法public void checkRole(JoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();RequireRole annotation = signature.getMethod().getAnnotation(RequireRole.class);String requiredRole = annotation.value();// 从上下文中获取当前用户角色String currentRole = getCurrentUserRole();if (!requiredRole.equals(currentRole)) {throw new AccessDeniedException("权限不足");}}
}

优势:

权限逻辑 集中化 ---------->>>避免 每个方法 重复校验

通过注解灵活控制权限粒度。

  1. 性能监控(Performance Monitoring)
    场景:
    统计方法执行耗时,定位性能瓶颈。
    实现逻辑:

使用@Around通知计算执行时间。

将耗时数据推送至监控系统(如Prometheus)。

示例代码:


@Aspect
@Component
public class PerformanceAspect {@Around("execution(* com.example.service.*.*(..))")public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis();Object result = joinPoint.proceed();long elapsedTime = System.currentTimeMillis() - start;Metrics.recordTime(joinPoint.getSignature().getName(), elapsedTime);return result;}
}

优势:

无侵入式监控,代码零耦合。

实时发现性能问题。

  1. 缓存管理(Caching)
    场景:
    自动缓存方法返回值,减少重复计算或数据库查询。
    实现逻辑:

通过@Cacheable注解声明缓存规则。

示例代码:


@Service
public class ProductService {@Cacheable(value = "products", key = "#id")public Product getProductById(Long id) {return productRepository.findById(id); // 仅第一次调用会执行此方法}
}

底层原理:
Spring AOP拦截方法调用,优先从缓存中读取数据,未命中时执行方法并缓存结果。

  1. 数据校验(Validation)
    场景:
    在方法执行前校验参数合法性(如非空检查、格式验证)。
    实现逻辑:

结合JSR 303规范(如@Valid、@NotNull)。

自定义切面拦截参数校验。

示例代码:


@Aspect
@Component
public class ValidationAspect {@Before("execution(* com.example.service.*.*(..)) && args(.., @Valid param)")public void validateParameters(JoinPoint joinPoint, Object param) {// 手动触发校验逻辑(如Hibernate Validator)Set<ConstraintViolation<Object>> violations = validator.validate(param);if (!violations.isEmpty()) {throw new ConstraintViolationException(violations);}}
}

何时使用AOP?

横切关注点:多个模块需要相同功能(如日志、权限)。

代码复用:避免重复代码(DRY原则)。

解耦需求:非核心逻辑(如监控)与业务逻辑分离。

避免滥用AOP的情况

  • 性能敏感场景:AOP代理可能引入额外开销。

  • 过度复杂化:简单逻辑直接编码更清晰。

  • 调试困难:链式代理可能增加调试复杂度。

循环依赖、三级缓存

源码------>>> 三级缓存

在这里插入图片描述
在这里插入图片描述

什么是循环依赖?

在这里插入图片描述

Spring可以解决 哪些情况 的循环依赖?

Spring 不支持基于构造器注入的循环依赖,但是假如AB循环依赖,如果一个是构造器注入,一个是 setter注入呢?

看看几种情形:

在这里插入图片描述

我们来看一下 三级缓存解决循环依赖 的过程:

当 A、B 两个类发生 循环依赖时:

在这里插入图片描述

A实例的初始化过程:

创建A实例,实例化的时候把 A对象⼯⼚放⼊三级缓存,表示 A开始实例化了,虽然我这个对象还不完整,但是先曝光出来让大家知道
在这里插入图片描述

A注⼊属性时,发现依赖B,此时B还没有被创建出来,所以去实例化B

同样,B注⼊属性时发现依赖A,它就会从缓存里找A对象。依次从⼀级到三级缓存查询A,从三级缓存通过对象⼯⼚拿到A,发现A虽然不太完善,但是存在,把A放⼊⼆级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入⼀级缓存。

在这里插入图片描述

接着A继续属性赋值,顺利从⼀级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除⼆级缓存中的A,同时把A放⼊⼀级缓存

最后,⼀级缓存中保存着实例化、初始化都完成的A、B对象

在这里插入图片描述

所以,我们就知道为什么Spring能解决setter注入的循环依赖了,因为实例化和属性赋值是分开的,所以里面有操作的空间。如果都是构造器注入的化,那么都得在实例化这一步完成注入,所以自然是无法支持了。

为什么要三级缓存?⼆级不⾏吗?

不行,主要是为了⽣成代理对象。如果是没有代理的情况下,使用二级缓存解决循环依赖也是OK的。但是如果存在代理,三级没有问题,二级就不行了。

因为三级缓存中放的是⽣成具体对象的匿名内部类,获取Object的时候,它可以⽣成代理对象,也可以返回普通对象。使⽤三级缓存主要是为了保证不管什么时候使⽤的都是⼀个对象。

假设只有⼆级缓存的情况,往⼆级缓存中放的显示⼀个普通的Bean对象,Bean初始化过程中,通过 BeanPostProcessor 去⽣成代理对象之后,覆盖掉⼆级缓存中的普通Bean对象,那么 可能就导致取到的Bean对象不一致了。

在这里插入图片描述

事务tx

声明式 事务


<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.3.22</version>
</dependency>

实验

/*** 默认:出现运行时异常会回滚* 可以指定回滚类型* 默认只对同一个数据库的事务管理有效* 分布式事务可以实现跨数据库的事务管理** @param username* @param bookId* @param buyNum*/@Transactional(rollbackFor = Exception.class,timeout = 15,propagation = Propagation.REQUIRED) // 超时会回滚public void checkout(String username, Integer bookId, Integer buyNum) {// 1、查询图书信息Book book = bookDao.getBookById (bookId);BigDecimal price = book.getPrice ();// 2、计算扣减额度BigDecimal total = new BigDecimal (buyNum).multiply (price);// 3、扣减余额accountDao.updateBalanceByUsername (username, total.negate ());int i = 10 / 0; // 这行代码会导致除以零异常// 4、扣减库存bookDao.updateBookStock (bookId, buyNum);}

细节

  • 默认只对同一个数据库的事务管理有效

详见:[Spring](https://blog.csdn.net/qq_30659573/article/details/127581112)

隔离级别、传播行为

在这里插入图片描述

双检查锁、IOC容器启动流程

双检查锁

// 私有的 静态实例变量private static SingletonLazy instance;// 私有的构造函数,防止外部实例化private SingletonLazy() {// 初始化逻辑}// 提供一个公共的静态方法,返回类的唯一实例public static SingletonLazy getInstance() {// 第一次检查实例是否存在,如果不存在,才进入同步块if (instance == null) {synchronized (SingletonLazy.class) {// 双检查// 第二次检查实例是否存在,防止多个线程同时进入同步块if (instance == null) {instance = new SingletonLazy();}}}// 返回实例return instance;}

IOC启动流程简述

在Java的Spring框架中,IOC容器的启动流程主要包括以下几个步骤:

  1. 读取 配置文件

    • Spring容器启动时会读取配置文件(如XML、注解或Java配置类),解析其中的Bean定义信息。
  2. 实例化BeanFactory

    • 创建BeanFactory或其子类(如DefaultListableBeanFactory)作为IOC容器的核心组件。
  3. 注册Bean定义

    • 将解析后的Bean定义信息注册到BeanDefinitionRegistry中,为后续的Bean创建做准备。
  4. 初始化Bean工厂后处理器

    • 如果配置中有BeanFactoryPostProcessor类型的Bean,则在此阶段调用它们。这些处理器可以在Bean实例化之前修改Bean定义属性。
  5. 实例化所有单例Bean

    • 对于所有非懒加载的单例Bean,Spring容器会提前实例化并初始化它们。这包括:
      • 实例化:根据Bean定义创建Bean实例。
      • 属性填充:通过依赖注入(DI)设置Bean的属性值。
      • 初始化前处理:如果存在InstantiationAwareBeanPostProcessor,则在此阶段进行处理。
      • 初始化方法调用:调用Bean的初始化方法(如@PostConstruct注解的方法或InitializingBean接口的afterPropertiesSet方法)。
      • 初始化后处理:如果存在BeanPostProcessor,则在此阶段调用postProcessAfterInitialization方法。
  6. 完成容器刷新

    • 容器完成所有必要的初始化工作后**,发布容器事件通知所有监听器。**
  7. 使用容器

    • 应用程序可以 通过容器获取Bean实例,并使用这些Bean执行业务逻辑。
  8. 销毁Bean

    • 当容器关闭时,会调用所有实现了DisposableBean接口或配置了销毁方法的Bean的销毁方法,以释放资源。

Spirng MVC

介绍及入门

在这里插入图片描述

前后端分离开发: @ResponseBody 与 @RestController

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.7.5</version>
</dependency>

@RestController //   @RestController= @Controller + @ResponseBodypublic class hello {@RequestMapping("/hello")public String hello(){return "hello sd";}
}

在这里插入图片描述

@RequestMapping("/hello/{name}")// @PathVariable("name")绑定路径中的name到参数 String name//  @GetMapping 、@PostMapping 都可以public String hello(@PathVariable("name") String name) {return "hello sd" + name;}

在这里插入图片描述

HTTP 复习

在这里插入图片描述

请求头

在这里插入图片描述

响应格式

在这里插入图片描述

响应状态码

在这里插入图片描述

请求处理

1、@RequestParam 接收参数

@RestController //   @RestController= @Controller + @ResponseBody
public class Hello {@RequestMapping("/hello")// 将请求参数name 传到参数 String namepublic String hello(@RequestParam(value = "name", required = false) String name,@RequestParam(value = "age", required = false) Integer age) {return "hello " + name + " " + age;}
}

在这里插入图片描述
2、接受参数 很多时,使用对象 进行封装

此时属性名和参数名 对应即可~


@Data
public class Person {private String name;private int age;private String sex;private String address;}

@RestController //   @RestController= @Controller + @ResponseBodypublic class Hello {@RequestMapping("/hello")public String hello(Person person) {return "hello " + person;}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、@RequestBody 将前端 json数据转为 对象 (需要该对象提供 无参构造方法 )


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor // 无参构造,不然无法 将json转为对象
public class Person {private String name;private Integer age;private String sex;private String address;
}

@RestController //   @RestController= @Controller + @ResponseBody
public class Hello {@PostMapping("/requestBody")// @RequestBody 要求对象提供无参构造方法,动态注入public String hello(@RequestBody Person person) {return "hello " + person;}
}

{"name": "ds","age": 25,"sex": "男","address": "北京"
}

在这里插入图片描述

4、原生API : HttpServletRequest 、HttpServletResponse、HttpSession


@RestController //   @RestController= @Controller + @ResponseBody
public class Hello {@GetMapping("/set")public String set(HttpServletRequest request) {HttpSession session = request.getSession ();session.setAttribute ("name", "ds");return " set ok ";}@GetMapping("/get")public String get(HttpServletRequest request) {HttpSession session = request.getSession ();Object name = session.getAttribute ("name");return String.valueOf (name);}
}

在这里插入图片描述

5、文件上传

在这里插入图片描述

/*** MultipartFile 专门上传文件的** @param person* @param headerImg* @param lifeImg* @return*/@GetMapping("/load")public String load(Person person,@RequestParam("headerImg") MultipartFile headerImg,@RequestParam("lifeImg") MultipartFile[] lifeImg) { // 多文件HttpSession session = request.getSession ();session.setAttribute ("name", "ds");return "  ok ";}

# 设置传输文件大小
spring:servlet:multipart:max-request-size: 10MBmax-file-size: 100MB

响应处理

1、返回 json

@ResponseBody 返回 json数据时,需要 对象提供无参构造和 set/get 方法

//  二合一注解
//  @ResponseBody 返回json数据@RestController //   @RestController= @Controller + @ResponseBody
public class Hello {@GetMapping("/resp")public String resp(HttpServletRequest req) {return "  Hello World";}}

在这里插入图片描述

2、文件下载


import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;@RestController
public class FileDownloadController {/*** 文件下载** @return* @throws IOException*/@GetMapping("/download")public ResponseEntity<InputStreamResource> download() throws IOException {// 文件路径String filePath = "C:\\Users\\Administrator\\Desktop\\"+"算法刷题.pdf";File file = new File (filePath);// 创建 FileInputStream 对象FileInputStream inputStream = new FileInputStream (file);// 解决文件名中文乱码问题String encode = URLEncoder.encode (file.getName (), "UTF-8");// 以下代码永远不改// 文件太大会oomInputStreamResource resource = new InputStreamResource (inputStream);// 设置响应头信息HttpHeaders headers = new HttpHeaders ();// 内容类型:流headers.setContentType (MediaType.APPLICATION_OCTET_STREAM);// 内容大小headers.setContentLength (inputStream.available ());// 内容处理方式headers.set ("Content-Disposition", "attachment; filename=" + encode);// 返回 ResponseEntity 对象return ResponseEntity.ok ().headers (headers).body (resource);}
}

在这里插入图片描述

Restful风格

1、Restful风格 + @PathVariable 入门练习

在这里插入图片描述

在这里插入图片描述

@PathVariable


@RestController //   @RestController= @Controller + @ResponseBody
public class Hello {@GetMapping("/get/{id}")// @PathVariable("id")------->>> 将路径中的id 绑定到 Integer idpublic String resp(@PathVariable("id") Integer id) {return "  Hello World "+ id;}}

在这里插入图片描述

2、三层架构

在这里插入图片描述

在这里插入图片描述

解耦

在这里插入图片描述

3、统一返回对象


@Data
@AllArgsConstructor
@NoArgsConstructorpublic class Result {/*** 业务的状态码code,200是成功,剩下都是失败;前后端将来会一起商定 不同的业务状态码前端要 显示不同效果。* msg: 服务端返回给前端的提示消息* data: 服务器返回给前端的数据** 示例:* {*     "code": 300,*     "msg": "余额不足",*     "data": null* }** 前端 统一处理:* 1. 前端发送请求,接受服务器数据* 2. 判断状态码,成功就显示数据,失败就显示提示消息(或者执行其他操作)。*/private Integer code;private String msg;private Object data;public static Result ok(Object data) {return new Result (200, "success", data);}
}

{"code": 200,"msg": "success","data": {"name": "ds","age": 15,"sex": "男","address": "北京"}
}

4、跨域处理

浏览器要 遵循同源策略


@RestController //   @RestController= @Controller + @ResponseBody
@RequestMapping("/api/v1")
public class Hello {@GetMapping("/get/{id}")public String resp(@PathVariable("id") Integer id) {return "  Hello World "+ id;}}

在这里插入图片描述

解决跨域

过滤器 Filter 实现:


public class CorsFilter implements Filter {@Overridepublic void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) res;response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");response.setHeader("Access-Control-Max-Age", "3600");response.setHeader("Access-Control-Allow-Headers", "x-requested-with");chain.doFilter(req, res);}@Overridepublic void init(FilterConfig filterConfig) {}@Overridepublic void destroy() {}
}

注解方式: @CrossOrigin // 允许跨域,注意:加在类上与 加在方法上的区别


import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;/*** CORS policy: 同源策略* 解决跨域: 在Controller上加注解 @CrossOrigin*/@CrossOrigin // 允许跨域,注意:加在类上与 加在方法上的区别
@RestController //   @RestController= @Controller + @ResponseBody
public class Hello {@GetMapping("/get/{id}")public String resp(@PathVariable("id") Integer id) {return "  Hello World " + id;}}

拦截器

拦截 Controller

在这里插入图片描述

拦截器:


import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
@Order(1) // 多个拦截器时,拦截器执行顺序,值越小,优先级越高
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 在请求处理之前进行拦截逻辑response.getWriter ().write ("No Permission!");return false; // 返回true表示 继续处理请求,返回false则中断请求处理}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 在请求处理之后 进行拦截逻辑}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 在请求完成之后 进行拦截逻辑}
}

配置类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate MyInterceptor myInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor (myInterceptor).addPathPatterns ("/**") // 拦截所有请求.excludePathPatterns ("/login", "/public/**"); // 排除特定路径}
}

在这里插入图片描述

异常处理

在这里插入图片描述

全局 异常处理

1、统一返回对象


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data 
@AllArgsConstructor
@NoArgsConstructor
public class Result {private Integer code; // 状态码private String msg; // 状态码对应的信息private Object data; // 返回的数据public static Result ok(Object data) {return new Result (200, "success", data);}public static Result error(Integer code, String msg) {return new Result (code, msg, null);}
}

2、 定义 异常枚举类


/*** 枚举类,用于表示订单模块中的异常状态。*/
public enum BizExceptionEnum {ORDER_CLOSED (10001, "订单已关闭"),ORDER_NOT_EXIST (10002, "订单不存在"),ORDER_TIMEOUT (10003, "订单超时"),PRODUCT_STOCK_NOT_ENOUGH (20003, "库存不足"),PRODUCT_HAS_SOLD (20002, "商品已售完"),PRODUCT_HAS_CLOSED (20001, "商品已下架");private final int code;private final String msg;BizExceptionEnum(int code, String msg) {this.code = code;this.msg = msg;}public int getCode() {return code;}public String getMsg() {return msg;}
}

3、定义 异常类 ,继承 RuntimeException


import lombok.Data;@Data
// 继承 RuntimeException
public class BizException extends RuntimeException {private Integer code; // 业务异常码private String msg; // 业务异常信息public BizException(Integer code, String message) {super (message);this.code = code;this.msg = message;}public BizException(BizExceptionEnum exceptionEnum) {super (exceptionEnum.getMsg ());this.code = exceptionEnum.getCode ();this.msg = exceptionEnum.getMsg ();}
}

4、全局异常 处理器


import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice // 告诉 Spring,这个类是一个全局异常处理类
public class GlobalExceptionHandler {/*** 默认 从上往下找* 可以建立 异常处理文档*/@ExceptionHandler(ArithmeticException.class)public Result ArithmeticException(ArithmeticException ex) {return Result.error (201, "数学错误");}/*** 业务异常** @param ex* @return*/@ExceptionHandler(BizException.class)public Result handleBizException(BizException ex) {return Result.error (ex.getCode (), ex.getMsg ());}@ExceptionHandler(Exception.class)public Result handleAllExceptions(Exception ex) {return Result.error (500, "未知异常");}}

5、 测试


import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@CrossOrigin
@RestController //   @RestController= @Controller + @ResponseBody
public class Hello {@GetMapping("/math")public Result resp() {int i = 1 / 0;  // 数学异常return Result.ok ("OK");}@GetMapping("/biz")public Result biz() {int stock = -1;if (stock < 0) {// 业务异常,中断业务逻辑throw new BizException (BizExceptionEnum.ORDER_CLOSED);}return Result.ok ("OK");}}

在这里插入图片描述

在这里插入图片描述

数据校验

在这里插入图片描述

引入依赖


<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>2.7.5</version>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version>
</dependency>

统一返回类


import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructorpublic class Result {private Integer code; // 状态码private String msg; // 状态码对应的信息private Object data; // 返回的数据public static Result ok(Object data) {return new Result (200, "success", data);}public static Result error(Integer code, String msg) {return error (code, msg, null);}public static Result error(Integer code, String msg, Object data) {return new Result (code, msg, data);}
}

自定义校验注解


// 校验注解,需要绑定校验器
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {GenderValidator.class} // 指定校验器去完成校验
)
public @interface Gender {String message() default "性别只能为:男/女";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}

自定义校验器


import org.example.Gender;import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class GenderValidator implements ConstraintValidator<Gender, String> { // 校验类型:String/*** @param value   前端提交来的,准备让我们进行校验的属性值* @param context 校验上下文* @return 返回校验结果*/@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {return "男".equals (value) || "女".equals (value);}
}

用户类User


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import javax.validation.constraints.Email;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {@Size(min = 2, max = 4, message = "用户名长度必须在2-4之间")private String name;@Max(value = 100, message = "最大不超过100岁")@Min(0)private Integer age;private String sex;@Email(message = "邮箱格式不正确")private String email;private String address;@Size(min = 11, max = 11, message = "手机号不正确")private String phone;@Gender // 自定义校验注解private String gender;}

全局异常处理


import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.Map;
import java.util.stream.Collectors;@RestControllerAdvice // 告诉 Spring,这个类是一个全局异常处理类
public class GlobalExceptionHandler {/*** 默认 从上往下找* 可以建立 异常处理文档*/@ExceptionHandler(ArithmeticException.class)public Result ArithmeticException(ArithmeticException ex) {return Result.error (201, "数学错误");}// 处理参数校验@ExceptionHandler(MethodArgumentNotValidException.class)public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {BindingResult bindingResult = ex.getBindingResult ();// 使用 HashMap封装 字段校验错误信息Map<String, Object> map = bindingResult.getFieldErrors ().stream ().collect (Collectors.toMap (e -> e.getField (), e -> e.getDefaultMessage ()));return Result.error (500, "校验失败", map);}@ExceptionHandler(Exception.class)public Result handleAllExceptions(Exception ex) {return Result.error (500, "未知异常");}}

Controller 控制器


import org.example.Result;
import org.example.User;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;import javax.validation.Valid;@CrossOrigin
@RestController //   @RestController= @Controller + @ResponseBody
public class Hello {@PostMapping("/test")public Result resp(@RequestBody @Valid User user) {return Result.ok (user);}}

测试

在这里插入图片描述

最佳实践

1、JavaBean 分层

在这里插入图片描述

2、 VO的最佳实践

在这里插入图片描述


@PostMapping("/employee")
public Result add(@RequestBody @Valid EmployeeAddVo vo) {// 把vo转为do:Employee employee = new Employee();// 属性对拷,Spirng 提供BeanUtils.copyProperties(vo, employee);// 保存员工信息employeeService.saveEmp(employee);return Result.ok();
}

在这里插入图片描述

在这里插入图片描述

3、接口文档

Swagger 接口文档

源码流程图【面试】

在这里插入图片描述

Mybatis

入门

1、安装插件

在这里插入图片描述

2、导入依赖

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><!-- web 依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MySQL JDBC 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version><scope>compile</scope></dependency>

3、yaml


# 配置MySQL
spring:profiles:active: testdatasource:url: jdbc:mysql://localhost:3306/db?useSSL=false&serverTimezone=UTCusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver# 日志
logging:level:# 设置mapper的日志级别为debugorg.example.mapper: debug
# 添加MyBatis配置
mybatis-plus:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl # SQL语句输出到控制台mapper-locations: classpath:mapper/*.xml

4 、 pojo


@Data
public class Emp {private Integer id;private String name;private Integer age;private String sex;private String email;private String address;private String phone;private double salary;}

5、Mapper 接口


@Mapper // Spring 会自动扫描这个接口,并创建一个实现类,并注入到 Spring 容器中
public interface EmpMapper {// 可以直接使用 #{对象属性名} 获取参数值void insertEmp(Emp emp);// 更新员工信息void updateEmp(@Param("e") Emp emp);void deleteEmpByID(@Param("id") Integer id);Emp selectEmpById(Integer id);// 实际业务需要分页,不然容易OOMList<Emp> selectAllEmps();List<Emp> selectComplexEmp();@MapKey ("id")Map<Integer,Emp> getAllMap();
}

6、mapper .xml


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="org.example.mapper.EmpMapper"><!--  #{name} 预编译SQL: 可以防止SQL注入--><!--useGeneratedKeys:自动生成主键keyProperty:指定主键的属性名,将生成的主键值 赋给id属性--><insert id="insertEmp" useGeneratedKeys="true" keyProperty="id">insert into emp (name, age, sex, email, address, phone, salary)values (#{name}, #{age}, #{sex}, #{email}, #{address}, #{phone}, #{salary})</insert><!--  使用e--><update id="updateEmp">update empset name    = #{e.name},age     = #{e.age},sex     = #{e.sex},email   = #{e.email},address = #{e.address},phone   = #{e.phone},salary  = #{e.salary}WHERE id = #{id}e.</update><delete id="deleteEmpByID">delete from emp where id = #{id}</delete><select id="selectEmpById" resultType="org.example.pojo.Emp">select * from emp  where id = #{id}</select><!--  返回集合,要写集合中的元素类型--><select id="selectAllEmps" resultType="org.example.pojo.Emp">select * from emp</select><!--  返回 map集合,resultType 写map中value的类型--><select id="getAllMap" resultType="java.util.Map">select * from emp</select><!-- 定义 ResultMap --><resultMap id="empResultMap" type="org.example.pojo.Emp"><!--property:Emp的属性名column:数据库的列名--><id property="id" column="id"/><result property="name" column="name"/><result property="age" column="age"/><result property="sex" column="sex"/><result property="email" column="email"/><result property="address" column="address"/><result property="phone" column="phone"/><result property="salary" column="salary"/></resultMap><!-- 复杂查询,使用 ResultMap 进行封装 --><select id="selectComplexEmp" resultMap="empResultMap">select id, name, age, sex, email, address, phone, salaryfrom empwhere age > 25 and salary > 5000</select></mapper>

数据库连接池

Mybatis 数据库连接池

在这里插入图片描述

在这里插入图片描述

<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.15</version>
</dependency>
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/userusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSource # 数据库 连接池druid:initial-size: 5 # 初始化大小max-active: 20 # 最大连接数min-idle: 5 # 最小连接数

关联查询

association 一对一


@Data
public class Order {private Long id;private String address;private BigDecimal amount;private Long customerId;private Customer customer;
}

@Data
public class Customer {private Long id;private String customerName;private String phone;
}

@Mapper
public interface OrderMapper {Order getOrderById(@Param("id") Integer id);
}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.example.mapper.OrderMapper"><select id="getOrderById" resultMap="OrderRM">select o.*,c.id c_id,c.customer_name,c.phonefrom t_order oleft join t_customer c on o.customer_id = c.idwhere o.id = #{id}</select><!--   自定义结果集--><resultMap id="OrderRM" type="org.example.pojo.Order"><id column="id" property="id"/><result column="address" property="address"/><result column="amount" property="amount"/><result column="customer_id" property="customerId"/><association property="customer" javaType="org.example.pojo.Customer"><id column="c_id" property="id"/><result column="customer_name" property="customerName"/><result column="phone" property="phone"/></association></resultMap></mapper>

collection 一对多


@Data
public class Customer {private Long id;private String customerName;private String phone;// 订单表List<Order> orders;
}

@Data
public class Order {private Long id;private String address;private BigDecimal amount;private Long customerId;private Customer customer;
}
<!-- CutomerRM --><resultMap id="CutomerRM" type="org.example.pojo.Customer"><id column="c_id" property="id"/><result column="customer_name" property="customerName"/><result column="phone" property="phone"/><!-- collection: 说明一对N的封装规则ofType: 集合中的元素类型--><collection property="orders" ofType="org.example.pojo.Order"><id column="id" property="id"/><result column="address" property="address"/><result column="amount" property="amount"/><result column="c_id" property="customerId"/></collection></resultMap><!-- select Customer  --><select id="getCustomerByIdWithOrders" resultMap="CutomerRM">select c.id c_id,c.customer_name,c.phone,o.*from t_customer cleft join t_order o on c.id = o.customer_idwhere c.id = #{id}</select>

分步 查询

1、association 分步


@Data
public class Order {private Long id;private String address;private BigDecimal amount;private Long customerId;private Customer customer;
}
<!-- OrderCustomerStepRM --><resultMap id="OrderCustomerStepRM"  type="org.example.pojo.Order"><id column="id" property="id"></id><result column="address" property="address"></result><result column="amount" property="amount"></result><result column="customer_id" property="customerId"></result><!-- customer属性关联一个对象,启动下一次查询,查询这个客户 --><association property="customer"select="getCustomerById"column="customer_id"></association></resultMap><select id="getCustomerById">select  * from t_customer where id=#{id}</select>

2、 collection 分步

<!-- CutomerRM --><resultMap id="CutomerRM" type="org.example.pojo.Customer"><id column="c_id" property="id"/><result column="customer_name" property="customerName"/><result column="phone" property="phone"/><!-- collection: 说明一对N的封装规则ofType: 集合中的元素类型--><collection property="orders"ofType="org.example.pojo.Order"select="getOrderById"column="id"></collection></resultMap><!-- select Customer  --><select id="getCustomerByIdWithOrders" resultMap="CutomerRM">select c.id c_id,c.customer_name,c.phone,o.*from t_customer cleft join t_order o on c.id = o.customer_idwhere c.id = #{id}</select>

在这里插入图片描述

3、开启延迟加载


mybatis-plus:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl # SQL语句输出到控制台lazy-loading-enabled: true # 懒加载mapper-locations: classpath:mapper/*.xml

在这里插入图片描述

分页查询

1、分页查询

在这里插入图片描述

Mapper


@Mapper
public interface EmpMapper {// 统计员工数量@Select("select count(*) from emp left join dept on emp.dept_id = dept.id")public Long count();/*** 分页 查询* 查询后 将d.name 取别名为 deptName* 因为 Emp类没有deptName属性,故在Emp类中添加deptName属性--->>进行封装** @return*/@Select("select e.*,d.name deptName from emp e left join dept d on e.dept_id = d.id" +"order by e.update_time desc limit #{start},#{size}")public List<Emp> list(@Param("start") Integer start, @Param("size") Integer size);}

Controller

@Slf4j
@RestController
@RequestMapping("/Dept") // 访问的公共前缀
public class DeptController {@GetMapping("/add")public Result add() {return   Result.ok();}}

2、PageHelper

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.5</version>
</dependency>
@Mapper
public interface EmpMapper {/*** PageHelper 实现分页,只需要指定从哪张表中查询,返回哪些字段** @return*/@Select("select e.*,d.name deptName from emp e left join dept d on e.dept_id = d.id" +"order by e.update_time desc")public List<Emp> list();}
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class DeptService {@Autowiredprivate EmpMapper empMapper;public PageInfo<Emp> selectList(Integer start, Integer size) {// 设置分页参数// 动态代理 实现分页PageHelper.startPage (start, size);// 执行查询// Page extends ArrayList<>Page<Emp> page = (Page<Emp>) empMapper.list ();// 封装分页结果return new PageInfo<Emp> (page.getTotal (), page.getResult ());}
}

Controller


@Slf4j
@RestController
@RequestMapping("/Dept") // 访问的公共前缀
public class DeptController {@Autowiredprivate DeptService deptService;@GetMapping("/add")public Result add(Integer start, Integer size) {PageInfo<Emp> pageInfo = deptService.selectList (start, size);long total = pageInfo.getTotal ();List<Emp> empList = pageInfo.getList ();return Result.ok (empList);}}

在这里插入图片描述

3、条件分页查询----->>> 优化版

请求参数太多的 优化,使用 对象 封装参数

在这里插入图片描述
在这里插入图片描述

动态SQL

1、 if 与 where 标签

在这里插入图片描述


@Mapper
public interface EmpMapper {/*** 查询* @param empQueryParam* @return*/public List<Emp> list(EmpQueryParam empQueryParam );}
@Autowiredprivate DeptService deptService;@GetMapping("/emps")public Result add(EmpQueryParam empQueryParam) {PageInfo<Emp> pageInfo = deptService.selectList (empQueryParam);long total = pageInfo.getTotal ();List<Emp> empList = pageInfo.getList ();return Result.ok (empList);}

Mapper 文件


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.tialsmanage.demos.web.EmpMapper"><select id="list" resultType="com.example.tialsmanage.demos.web.Demp">select emp.*,dept.name deptName from emp left join dept on dept.id=emp.dept_id-- #{name} 不能用在 ''中<where><if test="name !=null and name !='' ">and emp.name like concat('%',#{name},'%')</if><if test="gender !=null ">and emp.gender=#{gender}</if><if test="begin !=null and end !=null ">and emp.entry_date between #{begin} and #{end}</if></where></select>
</mapper>

2、set 标签

在这里插入图片描述

3、foreach 标签

void  insertBatch(List<Emp> empList);

<insert id="insertBatch">insert into emp(name, gender, entry_date, dept_id) values<foreach collection="empList" item="emp" separator=",">(#{emp.name}, #{emp.gender}, #{emp.entry_date}, #{emp.deptId})</foreach>
</insert>

考虑使用 Mybatis-Plus

问题

插入几个数据之后 出现问题,无法回滚

此时考虑 事务

使用事务控制----> @Transactional –>指定回滚类型(可见 事务管理内容)

在这里插入图片描述

缓存机制

在这里插入图片描述

1、事务级别 缓存 ( 一级缓存)

默认:事务期间 会开启缓存

在这里插入图片描述

2、二级缓存

** 注意:pojo 需要实现 序列化接口,不然会报错 ~~~**


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.example.mapper.OrderMapper"><!--   所有的查询都会共享到二级缓存--><cache/>  <!-- 开启 二级缓存--><select id="getCustomerById">select *from t_customerwhere id = #{id}</select></mapper>

@Data
public class Order implements Serializable {private static final long serialVersionUID = 1L;private Long id;private String address;private BigDecimal amount;private Long customerId;private Customer customer;
}

SpringBoot

介绍

在这里插入图片描述

简化 部署

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

使用Maven命令 mvn clean package 来 清理项目并进行打包。执行该命令后,会在项目的 target目录下生成一个可执行的Jar文件。

在这里插入图片描述

在这里插入图片描述

场景启动器

在这里插入图片描述


<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>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

自动配置【面试、核心】

1、初步理解

在这里插入图片描述

2、自动导入 配置类

在这里插入图片描述

根据条件 @Conditional 注解 进行 导入

再 配置组件,将配置文件与属性类 绑定

在这里插入图片描述

在这里插入图片描述

基础

1、依赖


<dependencies><!-- web 依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.7.5</version></dependency><!-- MySQL JDBC 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.9</version></dependency></dependencies>

2、 yaml 配置

# 配置mysql
spring:datasource:url: jdbc:mysql://localhost:3306/dw_test?useSSL=false&serverTimezone=UTCusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver

3、启动类


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Main {public static void main(String[] args) {SpringApplication.run (Main.class, args);}
}

4、Controller 控制类


import org.example.Result;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@CrossOrigin
@RestController //   @RestController= @Controller + @ResponseBody
public class Hello {@PostMapping("/test")public Result resp(@RequestBody String name) {return Result.ok (name);}}

日志

1、lombok 依赖

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency>

2、日志级别


# 日志级别
logging:level:root: debug

3、日志 输出到文件


# 日志级别
logging:file:# 指定输出的文件路径path: D://aaa.logname: boot.loglevel:root: debug

4、测试


@CrossOrigin
@RestController //   @RestController= @Controller + @ResponseBody
@Slf4j
public class Hello {@PostMapping("/test")public Result resp(@RequestBody String name) {log.info("接收到请求,请求参数为:{}", name);return Result.ok (name);}}

总结:

在这里插入图片描述

多环境

在这里插入图片描述


@Configuration
public class WebConfig {@Bean@Profile("dev")public Result r1() {return Result.ok ("User dev");}@Bean@Profile("test")public Result r2() {return Result.ok ("User test");}
}

# 指定环境
spring:profiles:active: test

@CrossOrigin
@RestController //   @RestController= @Controller + @ResponseBody
@Slf4j
public class Hello {@Autowiredprivate Result result;@GetMapping("/test")public Result resp() {log.info("接收到请求,请求参数为:{}", result);return Result.ok ("OK");}}

在这里插入图片描述

在这里插入图片描述

单元测试


<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>2.7.5</version>
</dependency>
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest // Spring提供的测试环境
@Slf4j
public class HTest {@Testpublic void  test() {System.out.println ("OK 666");}
}

http://www.ppmy.cn/news/1576606.html

相关文章

中间件专栏之MySQL篇——MySQL的基本原理和基本操作

一、什么是MySQL MySQL是一个常用的数据库管理系统&#xff0c;它是关系型数据库&#xff0c;它使用结构化查询语言&#xff08;SQL&#xff09;来管理数据库中的数据。MySQL 使用 表&#xff08;Table&#xff09;来存储数据&#xff0c;数据以 行&#xff08;Row&#xff09…

git命令学习记录

1. git reset 参数说明 git reset 是用来回退版本的&#xff0c;它可以添加三个参数&#xff0c;常用的使用格式是这样的&#xff1a;git reset [--hard | --soft | --mixed] 版本号 一般使用git修改文件并提交需要三步&#xff0c;第一步在文本编辑器中编辑文件&#xff0c;也…

爬虫:一文掌握 Celery 分布式爬虫,及对应实战案例

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 1. Celery 简介1.1 什么是 Celery?1.2 Celery 的核心组件2. 环境准备2.1 安装依赖2.2 启动 Redis3. 创建 Celery 分布式爬虫3.1 项目结构3.2 编写 Celery 任务3.3 启动 Worker3.4 分发任务4. 分布式部署4.1 多台机器部…

Java 入门 (超级详细)

一、什么是Java Java是一种高级编程语言&#xff0c;由Sun Microsystems公司于1995年推出。Java具有跨平台性、面向对象、健壮性、安全性、可移植性等特点&#xff0c;被广泛应用于企业级应用开发、移动应用开发、大数据处理、云计算等领域。Java程序可以在不同的操作系统上运…

基于FPGA的一些常识问题

1.FPGA&#xff08;现场可编程门阵列&#xff09;主要由以下几个部分构成‌&#xff1a; ‌1、可编程逻辑单元&#xff08;CLB&#xff09;‌&#xff1a;CLB是FPGA的基本逻辑单元&#xff0c;负责执行大部分的逻辑运算。每个CLB包含一个可配置开关矩阵&#xff0c;该矩阵由多…

【目标检测】目标检测中的数据增强终极指南:从原理到实战,用Python解锁模型性能提升密码(附YOLOv5实战代码)

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

【Linux vi文本编辑器使用指南】

Linux vi文本编辑器使用指南 一、模式切换二、启动与退出三、光标移动&#xff08;命令模式&#xff09;四、编辑文本五、查找与替换六、其他实用命令七、示例流程八、学习建议 Linux系统中的 vi&#xff08;及其增强版 vim&#xff09;是一款功能强大的文本编辑器&#xff0…

嵌入式产品级-超小尺寸游戏机(从0到1 硬件-软件-外壳)

Ultra-small size gaming console。 超小尺寸游戏机-Pico This embedded product is mainly based on miniaturization, followed by his game functions are also very complete, for all kinds of games can be played, and there will be relevant illustrations in the fo…