面试题-Spring

Spring、SpringMVC和SpringBoot的关系

(1)Spring:是一个开源的java框架,核心是控制反转和面向切面,

(2)SpringMVC:是Spring框架基础上的一个MVC框架,一种基于 MVC(模型-视图-控制器)架构的 Web 应用程序开发方式。主要处理Web开发的路径映射和视图的渲染

(3)Springboot:是为了简化Spring配置的快速开发整合包,简化了Spring的搭建和开发,Spring Boot 可以帮助开发人员快速搭建 Web 应用程序、批处理应用程序、集成测试应用程序等等。它集成了常用的第三方库和框架,并提供了自己的自动化配置和启动器,使得应用程序的搭建和开发更加快速、简单和方便。

简单来说,Spring 提供了一个全面的编程和配置模型,Spring MVC 提供了 Web 应用程序开发的框架,而 Spring Boot 则是在 Spring MVC 的基础上进一步简化了应用程序的开发。因此,它们都是 Spring Framework 的不同模块,可以灵活地根据需要进行选择和使用。

Spring

什么是Spring Bean

简单来说,Bean 代指的就是那些被 IoC 容器所管理的对象。

我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类。

Spring常用注解

声明bean的注解

@Component:泛指各种组件

@Controller、@Service、@Repository都可以称为@Component

@Controller:控制层

@Service:业务层

@Repository:数据访问层

注入bean的注解

@Autowired:由Spring提供

@Inject:由JSR-330提供

@Resource:由JSR-250提供

Java配置类相关注解

@Configuration:声明当前类为配置类

@Bean:注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式

@ComponentScan:用于对Component进行扫描

切面(AOP)相关注解

Spring支持AspectJ的注解式切面编程

@Aspect:声明一个切面

@After:在方法执行之后执行(方法上)

@Before:在方法执行之前执行(方法上)

@Around:在方法执行之前与之后执行(方法上)

@PointCut:声明切点

@EnableAspectJAutoProxy:开启Spring对AspectJ代理的支持

将一个类声明为Bean的注解有哪些

@Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。

@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。

@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。

@Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

@Autowired和@Resource区别

https://blog.csdn.net/xyh820/article/details/7303330/

  • Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。

  • Autowired默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。

  • 一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。

1
2
@Autowired
@Qualifier(value = "smsServiceImpl1")
1
2
@Resource(name = "smsServiceImpl1")
private SmsService smsService;

在注入对象不存在的情况下

@Autowired默认情况下,是一定要找到bean的,如果找不到会抛出BeanCreationException异常,为了允许找不到的情况发生,需要设置:@Autowired(required = false),就不会抛出异常了,但调用的时候会产生空指针。、

@Resource:抛出异常。

bean的作用域

  • singleton : IoC 容器中只有唯一的 bean 实例,单例模式
  • prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续 getBean() 两次,得到的是不同的 Bean 实例。
  • request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
  • session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
  • application/global-session (仅 Web 应用可用): 每个 Web 应用在启动时创建一个 Bean(应用 Bean),,该 bean 仅在当前应用启动时间内有效。
  • websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。

注解方式:

1
2
3
4
5
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {
return new Person();
}

xml文件方式

1
<bean id="..." class="..." scope="singleton"></bean>

@Component 和 @Bean 的区别是什么?

  • @Component 注解作用于类,而@Bean注解作用于方法。
  • @Component通常是通过类路径扫描来自动装配到 Spring 容器中,@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了 Spring 这是某个类的实例,当我需要用它的时候还给我。

注入bean的注解有哪些

Spring 内置的 @Autowired 以及 JDK 内置的 @Resource@Inject 都可以用于注入 Bean。

Bean的生命周期

(1)实例化:在容器启动时,Spring 会根据配置文件或注解等方式实例化 Bean 对象。

(2)属性赋值:在 Bean 对象实例化后,Spring 会将配置文件或注解中配置的属性值注入到 Bean 对象中

(3)自定义初始化方法:如果 Bean 类实现了 InitializingBean 接口,或在配置文件或注解中通过 init-method 属性配置了初始化方法,Spring 会在属性赋值完成后调用该方法进行自定义初始化

(4)Bean 可用:Bean 对象初始化完成后,可以被容器使用

(5)自定义销毁方法:如果 Bean 类实现了 DisposableBean 接口,或在配置文件或注解中通过 destroy-method 属性配置了销毁方法,当容器关闭时,Spring 会调用该方法进行自定义销毁

(6)销毁:容器关闭时,会销毁 Bean 对象

Spring 事务中哪几种事务传播行为?

事务传播行为是为了解决业务层方法之间互相调用的事务问题

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

1.TransactionDefinition.PROPAGATION_REQUIRED

默认的事务传播行为,如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

2.TransactionDefinition.PROPAGATION_REQUIRES_NEW

不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。

3.TransactionDefinition.PROPAGATION_NESTED

如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED

4.TransactionDefinition.PROPAGATION_MANDATORY

如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性),这个使用的很少。

Spring框架中用到了哪些设计模式

工厂设计模式 : Spring 使用工厂模式通过 BeanFactoryApplicationContext 创建 bean 对象。

代理设计模式 : Spring AOP 功能的实现。

单例设计模式 : Spring 中的 Bean 默认都是单例的。

模板方法模式 : Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。

包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。

观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。

适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller

注释配置和XML配置的应用场景

是否有了这些 IOC 注释,我们就可以完全摒除原来 XML 配置的方式呢?答案是否定的。有以下几点原因:

  • 注释配置不一定在先天上优于 XML 配置。如果 Bean 的依赖关系是固定的,(如 Service 使用了哪几个 DAO 类),这种配置信息不会在部署时发生调整,那么注释配置优于 XML 配置;反之如果这种依赖关系会在部署时发生调整,XML 配置显然又优于注释配置,因为注释是对 Java 源代码的调整,您需要重新改写源代码并重新编译才可以实施调整。
  • 如果 Bean 不是自己编写的类(如 JdbcTemplateSessionFactoryBean 等),注释配置将无法实施,此时 XML 配置是唯一可用的方式。
  • 注释配置往往是类级别的,而 XML 配置则可以表现得更加灵活。比如相比于 @Transaction 事务注释,使用 aop/tx 命名空间的事务配置更加灵活和简单。

所以在实现应用中,我们往往需要同时使用注释配置和 XML 配置,对于类级别且不会发生变动的配置可以优先考虑注释配置;而对于那些第三方类以及容易发生调整的配置则应优先考虑使用 XML 配置。Spring 会在具体实施 Bean 创建和 Bean 注入之前将这两种配置方式的元信息融合在一起。

Spring MVC

SpringMVC常用注解

2、@Controller

3、@RequestMapping:用于映射web请求,包括访问路径和参数

4、@ResponseBody:支持将返回值放到response内,而不是一个页面,通常用户返回json数据

5、@RequestBody:允许request的参数在request体中,而不是在直接连接的地址后面

6、@PathVariable:用于接收路径参数,比如@RequestMapping(“/hello/{name}”)声明的路径,将注解放在参数前,即可获取该值,通常作为Restful的接口实现方法。

7、@RestController:该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody。

8、@ControllerAdvice:全局异常处理、全局数据绑定、全局数据预处理

9、@ExceptionHandler:用于全局处理控制器里的异常

10、@InitBinder:用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到Model中

SpringMVC的核心组件

记住下面这些核心组件,也就记住了工作原理

  • DispatcherServlet核心中央处理器,负责接收请求、分发,并给予客户端响应。
  • HandlerMapping处理器映射器,根据 uri 去匹配查找能处理的 Handler ,并会将请求涉及到的拦截器和 Handler 一起封装。
  • HandlerAdapter处理器适配器,根据 HandlerMapping 找到的 Handler ,适配执行对应的 Handler
  • Handler请求处理器,处理实际请求的处理器。
  • ViewResolver视图解析器,根据 Handler 返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给 DispatcherServlet 响应客户端

SpringMVC工作原理

(1)客户端(浏览器)发送请求, DispatcherServlet拦截请求。

(2)DispatcherServlet 根据请求信息调用 HandlerMappingHandlerMapping 根据 uri 去匹配查找能处理的 Handler(也就是我们平常说的 Controller 控制器) ,并会将请求涉及到的拦截器和 Handler 一起封装。

(3)DispatcherServlet 调用 HandlerAdapter适配执行 Handler

(4)Handler 完成对用户请求的处理后,会返回一个 ModelAndView 对象给DispatcherServletModelAndView 顾名思义,包含了数据模型以及相应的视图的信息。Model 是返回的数据对象,View 是个逻辑上的 View

(5)ViewResolver 会根据逻辑 View 查找实际的 View

(6)DispaterServlet 把返回的 Model 传给 View(视图渲染)。

(7)把 View 返回给请求者(浏览器)

SpringBoot

SpringBoot常用注解

@SpringBootApplication:启动类上的注解,是@Configuration@EnableAutoConfiguration@ComponentScan注解的集合

前后端传值的:

@RequestParam:用于获取http请求中的查询参数

@RequestBody

Http请求相关的:

@RestController:接收用户请求,并调用service层返回给前端页面,是@RequestBody@Controller的合体。

@RequestMapping:URL到Controller中具体函数的映射

@GetMapping:用在方法上,标注接口的请求路径,只支持get请求。

@PostMapping:只支持post请求

@PutMapping:只支持put请求

@DeleteMapping:只支持Delete请求

事务:

@Transactional:标注在类或方法上,

配置相关:

@Value:在任意Spring管理的Bean中,通过这个注解可获取任何配置文件的属性值。

SpringBoot的启动类

image-20221207213045946

元注解:可以注解到注解上的注解,对其它注解进行说明的注解

  • Target:元注解,说明注解作用的目标,(允许被修饰的注解作用在类、接口和枚举上)
  • Retention:表示注解的生命周期,(保存到class文件,jvm加载class文件后,仍然存在,运行时也存在)
  • Documented:java在生成文档后,是否显示注解
  • Inherited:表示子类可以继承父类的注解

启动类上面的注解为**@springBootApplication**,是 Spring Boot 的核心注解,包含了以下三个注解:

(1)@SpringBootConfiguration:里面 是 @Configuration注解,它的作用就是将当前类声明为配置类,同时还可以使用@bean注解修饰的方法交给Spring容器,实例化对象,而方法名就是实例名。

1
@SpringBootApplication(scanBasePackages = "com.xxx")//扫描com.xxx包下的相关Configuration文件、自动映射文件、组件文件

(2)@ComponentScan他的作用就是扫描当前包以及子包,将有@Component@Controller@Service@Repository等注解的类注册到容器中,以便调用。

(3)@EnableAutoConfiguration会对我们配置的一些类自动注入的spring容器中。(对spring.factories包下的文件进行扫描)

它主要就是通过内部的方法,扫描classpathMETA-INF/spring.factories配置文件(key-value),将其中的
org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项实例化并且注册到spring容器。

打开@EnableAutoConfiguration源码

1
2
3
4
5
6
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)

我们springboot项目为什么可以自动载入应用程序所需的bean就是因为这个神奇的注解@Import

进入AutoConfigurationImportSelector类,可以看到他有一个方法selectImports()

在这里插入图片描述

进入getAutoConfigurationEntry()方法

可以看到这里有个List集合,那这个List集合又是干嘛的?没事,我们继续跟踪getCandidateConfigurations()方法!

在这里插入图片描述

红框中的方法:就是读取classpath下的META-INF/spring.factories文件的配置,将keyorg.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项读取出来,通过反射机制实例化为配置文件,然后注入spring容器。

这个方法可以返回集合里找到我们自定义的配置文件路径!

SpringBoot的starter

starter是启动依赖,日常企业应用研发中的各种场景都抽取出来,做成一个个的 starter(启动器),starter 中整合了该场景下各种可能用到的依赖,用户只需要在 Maven 中引入 starter 依赖,SpringBoot 就能自动扫描到要加载的信息并启动相应的默认配置。让用户摆脱了处理各种依赖和配置的困扰。

主要的作用有:

(1)以功能为维度,维护对应的jar包的版本依赖

(2)开发者不需要关注版本冲突问题

(3)starter会把所有jar包依赖的全部导入进来,避免开发者自己去引入依赖带来麻烦

(4)只需要在application.properties文件里面进行维护就行了,比如Redis这个starter,只需要在application.properties文件里面添加redis的连接信息就可以直接使用了.

(5)starter中集成了自动装配的机制,也就是说程序中依赖对应的starter组件以后,这个组件会自动集成到Spring中,

SpringBoot自动装配原理

SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。

使用@EnableAutoConfiguration注解来实现的,将所有符合条件的配置都加载到当前的SpringBoot创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所有组件注册到容器中
@Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

Class<?>[] exclude() default {};

String[] excludeName() default {};
}

在EnableAutoConfiguration 这个注解中发现有下面这个注解:

1
@Import({AutoConfigurationImportSelector.class})

spring.factories包下的文件进行扫描,添加到容器中去。

SpringBoot的核心配置文件是什么

单纯做 Spring Boot 开发,可能不太容易遇到 bootstrap.properties 配置文件,但是在结合 Spring Cloud 时,这个配置就会经常遇到了,特别是在需要加载一些远程配置文件的时侯。

  • bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext 加载的,比 applicaton 优先加载,配置在应用程序上下文的引导阶段生效。一般来说我们在 Spring Cloud Config 或者 Nacos 中会用到它。且 boostrap 里面的属性不能被覆盖;
  • application (. yml 或者 . properties): 由ApplicatonContext 加载,用于 spring boot 项目的自动化配置。

spring-boot-starter-parent 有什么用 ?

  1. 定义了 Java 编译版本为 1.8 。
  2. 使用 UTF-8 格式编码。
  3. 继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号。
  4. 执行打包操作的配置。
  5. 自动化的资源过滤。
  6. 自动化的插件配置。

Mybatis

mybatis中#和$的区别

#传入的参数在SQL中显示为字符串,$传入的参数在SqL中直接显示为传入的值.

#方式能够很大程度防止sql注入,$方式无法防止Sql注入;

Mybatis怎么防止sql注入

(1)适用预编译语句:使用预编译语句可以防止 SQL 注入。在 Mybatis 中,可以使用 #{} 占位符来代替用户输入的参数。例如:

1
2
3
<select id="getUserByName" resultType="User">
SELECT * FROM user WHERE name = #{name}
</select>

(2)适用参数类型

使用参数类型可以限制用户输入的参数类型,从而防止 SQL 注入。在 Mybatis 中,可以使用 parameterType 属性来指定参数类型。例如:

1
2
3
<select id="getUserById" resultType="User" parameterType="java.lang.Long">
SELECT * FROM user WHERE id = #{id}
</select>

(3)使用Mybatis内置的动态SQL

Mybatis 提供了内置的动态 SQL 功能,可以根据条件动态生成 SQL 语句,从而防止 SQL 注入。例如:

1
2
3
4
5
6
7
8
9
10
11
<select id="getUserByCondition" resultType="User" parameterType="Map">
SELECT * FROM user
<where>
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>

Mybatis与mysql是怎么连接的

(1)首先创建maven工程,引入依赖,mybatis和mysql-connector-java。

(2)创建mybatis的核心配置文件,习惯上命名为:mybatis-config.xml,主要用于连接数据库的环境以及mybatis的全局配置(driver、url、username、password等等)

(3)创建实体类,User

(4)创建mapper接口,相当于以前的dao层,UserMapper.java

1
2
3
4
5
6
public interface UserMapper {
/**
* 添加用户信息
*/
int insertUser();
}

(5)创建mybatis的映射文件,ORM(object,relation,mapping)对象关系映射,映射文件的命名为:实体名+Mapper.xml,因此一个映射文件对应一个实体类,对应一张表。UserMapper.xml

1
2
3
4
5
6
7
8
9
10
<?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="com.atguigu.mybatis.mapper.UserMapper">
<!--int insertUser();-->
<insert id="insertUser">
insert into t_user values(null,'张三','123',23,'女')
</insert>
</mapper>
  • mapper接口的全类名和映射文件中的namespace保持一致
  • mapper接口中方法的方法名与映射文件中编写SQL标签的id属性保持一致

Mybatis和原生JDBC的区别

传统的JDBC操作:

  • 连接数据库,注册驱动和数据库信息
  • 操作Connection,打开Sataement对象
  • 通过Statement执行SQL,返回结果到ResultSet对象
  • 适用ResultSet读取数据,然后通过代码转化为具体的POJO对象
  • 关闭数据库相关资源

jdbc存在弊端:

工作量相对较大,每次都要去创建,关闭,获取
JDBC编程可能产生的异常进行捕捉处理并正确关闭资源

MyBatis是一个支持普通SQL查询,存储过程和高级映射的持久层的框架

MyBatis是对JDBC的封装,它可以基于xml或者注解的方式进行配置和原始映射,消除了几乎所有的jdbc代码和参数的手动设置和对结果集的封装。
MyBatis可以使用简单的XML配置,将接口和Java的POJO(普通的Java对象)映射成数据库中的记录。

相对于JDBC,MyBatis具有以下优点:

1.MyBatis通过dataSource实现数据库连接池的配置,实现了隔离解耦,统一从dataSource中获取数据库连接,具体实现通过让用户配置应对变化。
2.MyBatis将所有的SQL统一放在配置文件(XXXMapper.xml)中统一管理,不需要再次编译,而传统的jdbc的SQL语句分布在代码中,修改之后需要再次编译。可读性差,不便于维护。
3.MyBatis还可以通过标签动态的生成SQL语句。
4.MyBatis可以直接将结果映射为自己需要的类型,如:Javabean,map,list等。而在使用jdbc时,我们要从返回的结果集ResultSet中获取结果封装为我们需要的类型中。

MybatisPlus怎么与数据库连接的


  1. 配置 Maven 依赖

在 Maven 项目的 pom.xml 文件中,添加 Mybatis-Plus 和 MySQL 连接驱动的依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- Mybatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>

<!-- MySQL 连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
  1. 配置数据源

在 Spring Boot 项目中,可以在 application.propertiesapplication.yml 文件中配置 MySQL 数据库的连接信息,例如:

1
2
3
4
5
6
# MySQL 数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123456

  1. 配置 Mybatis-Plus

在 Spring Boot 项目中,可以使用 MybatisPlusAutoConfiguration 类自动配置 Mybatis-Plus。在 application.propertiesapplication.yml 文件中添加以下配置即可:

1
2
3
# Mybatis-Plus 配置
mybatis-plus.configuration.map-underscore-to-camel-case=true

其中,map-underscore-to-camel-case 配置项可以使 Mybatis-Plus 自动将下划线命名的数据库字段转换为驼峰命名的 Java 对象属性。

  1. 创建实体类和 Mapper

使用 Mybatis-Plus 的关键是创建实体类和 Mapper 接口。实体类需要使用 @TableName 注解指定对应的数据库表名,Mapper 接口需要继承 BaseMapper 接口。例如

1
2
3
4
5
6
7
8
9
10
11
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
// 省略 getter 和 setter 方法
}

public interface UserMapper extends BaseMapper<User> {
}
  1. 使用 Mybatis-Plus 进行 CRUD 操作

创建好实体类和 Mapper 接口后,就可以使用 Mybatis-Plus 进行 CRUD 操作了。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Service
public class UserService {
@Autowired
private UserMapper userMapper;

public User getUserById(Long id) {
return userMapper.selectById(id);
}

public boolean saveUser(User user) {
return userMapper.insert(user) > 0;
}

public boolean updateUser(User user) {
return userMapper.updateById(user) > 0;
}

public boolean deleteUser(Long id) {
return userMapper.deleteById(id) > 0;
}
}


面试题-Spring
http://example.com/2022/11/28/面试题-Spring/
作者
zlw
发布于
2022年11月28日
许可协议