Spring理论学习

news2024/10/6 14:24:36

1、什么是IOC

IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过, IoC 并非 Spring 特有,在其他语言中也有应用。

为什么叫控制反转?

  • 控制 :指的是对象创建(实例化、管理)的权力
  • 反转 :控制权交给外部环境(Spring 框架、IoC 容器)

没有引入IOC容器之前,对象A依赖于对象B,那么对象A在初始化或运行到某一点时,自己必须主动创建对象B或者使用已经创建的对象B,无论是创建还是使用对象B,控制权都在自己手里。

引入IOC容器之后,对象A和对象B失去了直接联系,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。

对象A获得依赖对象B的过程,由主动变成被动,控制权颠倒,这就是控制反转

IOC容器:在项目启动的时候读取项目中的bean节点,根据全限定类名(全限定类名是指一个类的完整名称,包括它所在的包名和类名,用点号分隔。例如,java.lang.String就是一个全限定类名,表示String类位于java.lang包中。)使用反射创建对象放到map里,扫描到有(@service\@Compent等注解)的类也是通过反射创建对象放到map里。

将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。

在实际项目中一个 Service 类可能依赖了很多其他的类,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。

在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。

接下来我没在代码中需要用到里面的对象时候,通过注入(@Autowired/@Resourse)等,项目启动时会根据类型或id注入;id为对象名,为类的首字母小写形式

Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。

2、什么是Spring Bean

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

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

<!-- Constructor-arg with 'value' attribute -->
<bean id="..." class="...">
   <constructor-arg value="..."/>
</bean>

下图简单地展示了 IoC 容器如何使用配置元数据来管理对象。

org.springframework.beans和 org.springframework.context 这两个包是 IoC 实现的基础,如果想要研究 IoC 相关的源码的话,可以去看看

3、将一个类声明为bean的注解有哪些?

  • @Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
  • @Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。

4、@Compent和@bean的相同与区别

  • 区别:
    • @Compent注解作用于类上,表示该类是一个Spring的组件,可以被自动扫描和装配到容器中。
    • @Bean注解作用于方法上,表示该方法返回一个对象可以被注册到容器中。该方法所在的类必须被@Configuration或@Compent注解标注。
    • @Compent注解通常用于自定义的类,而@Bean注解通常用于第三方库中的类或者需要自定义创建逻辑的类。
    • @Compent注解只能创建单例的Bean(在多线程的条件下容易出并发问题),而@Bean注解可以通过scope属性指定创建单例或多例的Bean。
  • 相同点:
    • @Compent和@Bean注解都可以将一个类声明为Spring的Bean,让容器管理其生命周期和依赖关系。
    • @Compent和@Bean注解都可以通过name属性指定Bean的名称,如果不指定,默认使用类名或方法名作为名称。

@Bean注解使用示例:

@Bean注解只能作用于方法上,表示该方法返回一个对象,可以被注册到容器中。如果要给类注解,可以使用@Compent或其他派生的注解,如@Repository,@Service,@Controller等。

@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }

}

上面的代码相当于下面的 xml 配置

<beans>
    <bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>

下面这个例子是通过 @Component 无法实现的。

@Bean
public OneService getService(status) {
    case (status)  {
        when 1:
                return new serviceImpl1();
        when 2:
                return new serviceImpl2();
        when 3:
                return new serviceImpl3();
    }
}

 5、注入Bean的注解有哪些?

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

AnnotaionPackageSource
@Autowiredorg.springframework.bean.factorySpring 2.5+
@Resourcejavax.annotationJava JSR-250
@Injectjavax.injectJava JSR-330

@Autowired 和@Resource使用的比较多一些。

6、@Autowired和@Resource的区别是什么

Autowired 属于 Spring 内置的注解,默认的注入方式为byType(根据类型进行匹配),也就是说会优先根据接口类型去匹配并注入 Bean (接口的实现类)。

这会有什么问题呢? 当一个接口存在多个实现类的话,byType这种方式就无法正确注入对象了,因为这个时候 Spring 会同时找到多个满足条件的选择,默认情况下它自己不知道选择哪一个。

这种情况下,注入方式会变为 byName(根据名称进行匹配),这个名称通常就是类名(首字母小写)。就比如说下面代码中的 smsService 就是我这里所说的名称,这样应该比较好理解了吧。

// smsService 就是我们上面所说的名称
@Autowired
private SmsService smsService;

举个例子,SmsService 接口有两个实现类: SmsServiceImpl1和 SmsServiceImpl2,且它们都已经被 Spring 容器所管理。

// 报错,byName 和 byType 都无法匹配到 bean
@Autowired
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Autowired
private SmsService smsServiceImpl1;
// 正确注入  SmsServiceImpl1 对象对应的 bean
// smsServiceImpl1 就是我们上面所说的名称
@Autowired
@Qualifier(value = "smsServiceImpl1")
private SmsService smsService;

我们还是建议通过 @Qualifier 注解来显式指定名称而不是依赖变量的名称。

@Resource属于 JDK 提供的注解,默认注入方式为 byName。如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为byType

@Resource 有两个比较重要且日常开发常用的属性:name(名称)、type(类型)。

public @interface Resource {
    String name() default "";
    Class<?> type() default Object.class;
}

如果仅指定 name 属性则注入方式为byName,如果仅指定type属性则注入方式为byType,如果同时指定name 和type属性(不建议这么做)则注入方式为byType+byName

// 报错,byName 和 byType 都无法匹配到 bean
@Resource
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Resource
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean(比较推荐这种方式)
@Resource(name = "smsServiceImpl1")
private SmsService smsService;

简单总结一下:

  • @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
  • Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。
  • 当一个接口存在多个实现类的情况下,@Autowired 和@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。

 7、Bean的作用域通常有哪些?

Spring 中 Bean 的作用域通常有下面几种:

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

HTTP请求和HTTP会话的区别是:

HTTP请求是一种用于获取网络资源的通信协议,它由客户端(或浏览器)发起,由服务端(如Web服务器)响应,每个请求都包含一个方法(如Get或post),一个URL,一些标头和一个可选消息体。

HTTP会话是一种用于在多个请求之间保持状态信息的机制,它由客户端和服务端共同维护,通常使用HTTP Cookie来实现,每个会话都有唯一的标识符。

·  

如何配置 bean 的作用域呢?

xml 方式:

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

注解方式:

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {
    return new Person();
}

8、springAOP

AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:

 什么是动态代理?

动态代理是一种编程技术,它可以在运行时动态地创建和修改代理类,而不需要事先为每个被代理的类编写固定的代理类。动态代理可以实现对目标对象的功能增强,如添加日志、事务、权限等。

动态代理的实现原理是利用Java的反射机制,通过字节码操作或者接口实现,来生成代理类的字节码文件,并加载到内存中,从而创建代理对象。动态代理可以在编译期、类加载期或运行期进行。

AOP 切面编程设计到的一些专业术语:

术语含义
目标(Target)被通知的对象
代理(Proxy)向目标对象应用通知之后创建的代理对象
连接点(JoinPoint)目标对象的所属类中,定义的所有方法均为连接点
切入点(Pointcut)被切面拦截 / 增强的连接点(切入点一定是连接点,连接点不一定是切入点)
通知(Advice)增强的逻辑 / 代码,也即拦截到目标对象的连接点之后要做的事情
切面(Aspect)切入点(Pointcut)+通知(Advice)
Weaving(织入)将通知应用到目标对象,进而生成代理对象的过程动作

 切入点和连接点的区别:

  • 连接点是在程序执行过程中能够插入切面的一个点,如方法执行、构造器调用、字段赋值等。在Spring AOP中,连接点只表示方法执行。
  • 切入点是一些特定的连接点,是切面要织入的地方。切入点可以通过表达式或注解来匹配连接点。在Spring AOP中,切入点使用AspectJ的语法来定义。
  • 连接点是切面可以应用的所有可能性,而切入点是切面实际应用的具体位置。因此,切入点一定是连接点,但连接点不一定是切入点。

举个例子,假设有一个类A,它有三个方法:m1(), m2(), m3()。那么这三个方法都是连接点,因为它们都可以被切面拦截。但是如果我们定义一个切入点,只匹配m1()方法,那么只有m1()方法是切入点,而m2()和m3()方法不是切入点。

通知类型有哪些?

  • Before(前置通知):目标对象的方法调用之前触发
  • After (后置通知):目标对象的方法调用之后触发
  • AfterReturning(返回通知):目标对象的方法调用完成,在返回结果值之后触发
  • AfterThrowing(异常通知) :目标对象的方法运行中抛出 / 触发异常后触发。AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值。
  • Around (环绕通知):编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法

9、springboot注解

9.1 @SpringBootApplication

我们可以把 @SpringBootApplication看作是 @Configuration@EnableAutoConfiguration@ComponentScan 注解的集合。

@SpringBootApplication注解源码

package org.springframework.boot.autoconfigure;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
   ......
}

package org.springframework.boot;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

@Target注解(修饰注解的注解)是一个元注解,也就是说,它只能用于修饰其他的注解。它的作用是指定一个注解可以应用于哪些程序元素,如类、方法、字段、参数等。它的唯一参数是一个ElementType枚举类型的数组,表示该注解可以修饰的元素类型。​​​​​​

@Retention注解是一个元注解,用于指定一个注解的保留策略,即该注解在什么时候被丢弃。它的唯一参数是一个RetentionPolicy枚举类型的值,表示该注解的生命周期。有三种保留策略:

RetentionPolicy.SOURCE: 该注解只保留在源代码中,编译器会忽略它。 RetentionPolicy.CLASS: 该注解保留在.class文件中,但是虚拟机会忽略它。这是默认的保留策略。 RetentionPolicy.RUNTIME: 该注解保留在.class文件中,并且可以在运行时被反射机制读取。

@EnableAutoConfiguration:是一个Spring Boot提供的注解,用于启用Spring应用上下文的自动配置功能。它会根据类路径中的组件和用户定义的Bean,自动创建和注册Bean。这样可以简化开发者的工作,无需手动配置各种Bean。这个注解通常包含在@SpringBootApplication注解中

  • 如果类路径中有HSQLDB这个jar文件,而用户没有手动配置任何数据库连接的Bean,那么Spring Boot会自动配置一个内存数据库的Bean
  • 如果类路径中有tomcat-embedded.jar这个jar文件,而用户没有手动配置任何ServletWebServerFactory的Bean,那么Spring Boot会自动配置一个TomcatServletWebServerFactory的Bean
  • 如果类路径中有spring-webmvc.jar这个jar文件,而用户没有手动配置任何DispatcherServlet的Bean,那么Spring Boot会自动配置一个DispatcherServlet的Bean

@ComponentScan: 扫描被@Component (@Repository,@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。

@Configuration:允许在 Spring 上下文中注册额外的 bean 或导入其他配置类

9.2 @Autowired

注入bean

9.3 @Component、@Repository、@Service、@Controller

我们一般使用 @Autowired 注解让 Spring 容器帮我们自动装配 bean。要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类,可以采用以下注解实现:

  • @Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
  • @Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。

9.4 @RestController

@RestController注解是@Controller@ResponseBody的合集,表示这是个控制器 bean,并且是将函数的返回值直接填入 HTTP 响应体中,是 REST 风格的控制器。

代码示例:

单独使用@controller

@Controller
public class HelloController {
    @GetMapping("/hello")
    public String greeting(@RequestParam(name = "name", required = false, defaultValue = "World") String name, Model model) {
        model.addAttribute("name", name);
        return "hello";
    }
}

使用@Controller与@ResponseBody注解返回json格式数据

@Controller
public class HelloController {
    @PostMapping("/hello")
    @ResponseBody
    public Person greeting(@RequestBody Person person) {
        return person;
    }

}

直接使用@RestController注解 

@RestController
public class HelloController {
    @PostMapping("/hello")
    public Person greeting(@RequestBody Person person) {
        return person;
    }

}

单独使用 @Controller 不加 @ResponseBody的话一般是用在要返回一个视图的情况,这种情况属于比较传统的 Spring MVC 的应用,对应于前后端不分离的情况。@Controller +@ResponseBody 返回 JSON 或 XML 形式数据

Controller 返回一个页面

单独使用 @Controller 不加 @ResponseBody的话一般使用在要返回一个视图的情况,这种情况属于比较传统的Spring MVC 的应用,对应于前后端不分离的情况。

SpringMVC 传统工作流程

@RestController 返回JSON 或 XML 形式数据

@RestController只返回对象,对象数据直接以 JSON 或 XML 形式写入 HTTP 响应(Response)中,这种情况属于 RESTful Web服务,这也是目前日常开发所接触的最常用的情况(前后端分离)。

SpringMVC+RestController

@Controller +@ResponseBody 返回JSON 或 XML 形式数据

如果你需要在Spring4之前开发 RESTful Web服务的话,你需要使用@Controller 并结合@ResponseBody注解,也就是说@Controller +@ResponseBody@RestController(Spring 4 之后新加的注解)。

@ResponseBody 注解的作用是将 Controller 的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到HTTP 响应(Response)对象的 body 中,通常用来返回 JSON 或者 XML 数据,返回 JSON 数据的情况比较多。

Spring3.xMVC RESTfulWeb服务工作流程

@RestController vs @Controller

9.5 @Scope

声明 Spring Bean 的作用域,使用方法:

@Bean
@Scope("singleton")
public Person personSingleton() {
    return new Person();
}

四种常见的 Spring Bean 的作用域:

  • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
  • prototype : 每次请求都会创建一个新的 bean 实例。
  • request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
  • session : 每一个 HTTP Session 会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。

9.6 @Configuration

一般用来声明配置类(第三方类),可以使用 @Component注解替代,不过使用@Configuration注解声明配置类更加语义化。

@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }

}

9.7 处理常见的http请求类型

5 种常见的请求类型:

  • GET :请求从服务器获取特定资源。举个例子:GET /users(获取所有学生)
  • POST :在服务器上创建一个新的资源。举个例子:POST /users(创建学生)
  • PUT :更新服务器上的资源(客户端提供更新后的整个资源)。举个例子:PUT /users/12(更新编号为 12 的学生)
  • DELETE :从服务器删除特定的资源。举个例子:DELETE /users/12(删除编号为 12 的学生)
  • PATCH :更新服务器上的资源(客户端提供更改的属性,可以看做作是部分更新),使用的比较少,这里就不举例子了。

9.7.1 Get请求

@GetMapping("users") 等价于@RequestMapping(value="/users",method=RequestMethod.GET)

@GetMapping("/users")
public ResponseEntity<List<User>> getAllUsers() {
 return userRepository.findAll();
}

 9.7.2 POST请求

@PostMapping("users") 等价于@RequestMapping(value="/users",method=RequestMethod.POST)

@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody UserCreateRequest userCreateRequest) {
 return userRespository.save(userCreateRequest);
}

9.7.3 PUT请求

@PutMapping("/users/{userId}") 等价于@RequestMapping(value="/users/{userId}",method=RequestMethod.PUT)

@PutMapping("/users/{userId}")
public ResponseEntity<User> updateUser(@PathVariable(value = "userId") Long userId,
  @Valid @RequestBody UserUpdateRequest userUpdateRequest) {
  ......
}

9.7.4 Delete请求

@DeleteMapping("/users/{userId}")等价于@RequestMapping(value="/users/{userId}",method=RequestMethod.DELETE)

@DeleteMapping("/users/{userId}")
public ResponseEntity deleteUser(@PathVariable(value = "userId") Long userId){
  ......
}

9.7.5 PATCH请求

一般实际项目中,我们都是 PUT 不够用了之后才用 PATCH 请求去更新数据。

  @PatchMapping("/profile")
  public ResponseEntity updateStudent(@RequestBody StudentUpdateRequest studentUpdateRequest) {
        studentRepository.updateDetail(studentUpdateRequest);
        return ResponseEntity.ok().build();
    }

9.8 前后端传值

9.8.1 @PathVariable和@RequestParam

@PathVariable和@RequestParam都是Spring MVC中用于从请求中获取参数值的注解,但是它们有一些相同和区别:

  • 相同点:它们都可以用在控制器方法的参数上,它们都可以指定参数的名称,它们都可以设置参数是否必须。
  • 区别点:@PathVariable用于获取路径中的占位符值,例如/user/ {id}而@RequestParam用于获取查询字符串中的参数值,例如/user?id=123。@PathVariable获取的值不会被URL解码,而@RequestParam获取的值会被URL解码。@PathVariable可以使用正则表达式来限制匹配的范围,而@RequestParam不能。@PathVariable可以从Spring 4.3.3开始设置为可选,而@RequestParam一直可以设置为可选。

@RequestParam 的使用示例

@RequestParam注解有一些属性可以设置,例如:

  • value: 指定参数的名称,如果不指定,默认使用方法参数的名称。
  • required: 指定参数是否必须,默认为true,如果为false,那么当参数缺失时不会报错,而是赋值为null。
  • defaultValue: 指定参数的默认值,如果参数缺失或者无法转换为目标类型,那么使用该值。

@RequestParam用于获取查询字符串的中的参数值,

前端代码示例,当用户在表单中输入姓名和年龄,并点击提交按钮时,前端会向后端发送一个GET请求,例如:http://localhost:8080/user?name=Tom&age=20

<form action="/user" method="get">
  <label for="name">Name:</label>
  <input type="text" id="name" name="name">
  <label for="age">Age:</label>
  <input type="number" id="age" name="age">
  <button type="submit">Submit</button>
</form>

后端控制器有一个方法,用于接收前端传来的姓名和年龄,并返回一个欢迎信息。后端控制器的代码如下:

// 在控制器类中使用@RequestMapping注解
@Controller
@RequestMapping("/user")
public class UserController {

  // 在控制器方法中使用@RequestParam注解
  @RequestMapping (method = RequestMethod.GET)
  public String welcomeUser(@RequestParam (value = "name") String userName,
                            @RequestParam (value = "age") int userAge,
                            Model model) {
    // 将用户信息添加到模型中
    model.addAttribute("name", userName);
    model.addAttribute("age", userAge);
    // 返回一个视图名称
    return "welcome";
  }
}

后端会根据@RequestParam注解获取name和age的值,并将它们添加到模型中,然后返回一个视图名称welcome。视图层会根据模型中的数据渲染一个欢迎页面。

@PathVariable的使用示例

@PathVariable注解有一些属性可以设置,例如:

  • value: 指定占位符的名称,如果不指定,默认使用方法参数的名称。
  • required: 指定占位符是否必须,默认为true,如果为false,那么当占位符缺失时不会报错,而是赋值为null。这个属性从Spring 4.3.3开始支持。
  • name: 指定占位符的名称,和value属性相同。这个属性从Spring 4.3.3开始支持

传参案例:

前端:前端页面有一个列表,显示用户的姓名和年龄,并且每个用户都有一个详情按钮,点击后可以查看用户的详细信息。前端页面的代码如下:

<ul>
  <li>Name: Tom, Age: 20 <a href="/user/1">Details</a></li>
  <li>Name: Alice, Age: 18 <a href="/user/2">Details</a></li>
  <li>Name: Bob, Age: 22 <a href="/user/3">Details</a></li>
</ul>

后端控制器有一个方法,用于接收前端传来的用户id,并返回一个用户详情页面。后端控制器的代码如下:

// 在控制器类中使用@RequestMapping注解
@Controller
@RequestMapping("/user")
public class UserController {

  // 在控制器方法中使用@PathVariable注解
  @RequestMapping (value = "/ {id}", method = RequestMethod.GET)
  public String getUserDetails(@PathVariable (value = "id") int userId,
                               Model model) {
    // 根据userId获取用户详情
    User user = userService.getUserById(userId);
    // 将用户详情添加到模型中
    model.addAttribute("user", user);
    // 返回一个视图名称
    return "details";
  }
}

当用户点击某个用户的详情按钮时,前端会向后端发送一个GET请求,例如:

http://localhost:8080/user/1

后端会根据@PathVariable注解获取1这个值,并根据它获取用户详情,并将它添加到模型中,然后返回一个视图名称details。视图层会根据模型中的数据渲染一个用户详情页面

9.8.2 @RequestBody

用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且Content-Type 为 application/json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。系统会使用HttpMessageConverter或者自定义的HttpMessageConverter将请求的 body 中的 json 字符串转换为 java 对象

 需要注意的是:**一个请求方法只可以有一个@RequestBody,但是可以有多个@RequestParam@PathVariable**。 如果你的方法必须要用两个 @RequestBody来接受数据的话,大概率是你的数据库设计或者系统设计出问题了!

9.9 读取配置信息的注解

很多时候我们需要将一些常用的配置信息比如阿里云 oss、发送短信、微信认证的相关配置信息等等放到配置文件中。

下面我们来看一下 Spring 为我们提供了哪些方式帮助我们从配置文件中读取这些配置信息。

我们的数据源application.yml内容如下:

wuhan2020: 2020年初武汉爆发了新型冠状病毒,疫情严重,但是,我相信一切都会过去!武汉加油!中国加油!

my-profile:
  name: Guide哥
  email: koushuangbwcx@163.com

library:
  location: 湖北武汉加油中国加油
  books:
    - name: 天才基本法
      description: 二十二岁的林朝夕在父亲确诊阿尔茨海默病这天,得知自己暗恋多年的校园男神裴之即将出国深造的消息——对方考取的学校,恰是父亲当年为她放弃的那所。
    - name: 时间的秩序
      description: 为什么我们记得过去,而非未来?时间“流逝”意味着什么?是我们存在于时间之内,还是时间存在于我们之中?卡洛·罗韦利用诗意的文字,邀请我们思考这一亘古难题——时间的本质。
    - name: 了不起的我
      description: 如何养成一个新习惯?如何让心智变得更成熟?如何拥有高质量的关系? 如何走出人生的艰难时刻?

9.9.1 @Value(常用)

使用 @Value("${property}") 读取比较简单的配置信息:

@Value("${wuhan2020}")
String wuhan2020;

9.9.2 @ConfigurationProperties(常用)

@ConfigurationProperties 的功能是将配置文件中的属性绑定到一个 Java 类的字段上,从而方便地获取和使用这些属性


使用 @ConfigurationProperties 的步骤如下:

  1. 在配置文件中定义一些属性,例如 application.properties 或 application.yml,可以使用前缀来区分不同的属性组。
  2. 在 Java 类中添加 @ConfigurationProperties 注解,并指定前缀,然后为每个要绑定的属性提供一个带有公共 setter 方法的字段。
  3. 在 Spring Boot 应用中激活 @ConfigurationProperties 类,可以通过以下几种方式之一:
    • 在类上添加 @Component 注解,让其被 Component Scan 扫描到。
    • 在类上添加 @Configuration 注解,并在方法上添加 @Bean 注解,返回一个 @ConfigurationProperties 类型的对象。
    • 在其他类上添加 @EnableConfigurationProperties 注解,并指定要激活的 @ConfigurationProperties 类型。

使用示例:

myapp.mail.enabled=true
myapp.mail.default-subject=Test Mail

 我们可以创建一个 MailModuleProperties 类来绑定这些参数:

@Component
@ConfigurationProperties(prefix = "myapp.mail")
public class MailModuleProperties {
    private boolean enabled;
    private String defaultSubject;

    // getter and setter methods
}

然后我们可以在其他类中注入 MailModuleProperties 类型的 bean,并使用它的字段来访问配置文件中的属性值: 

@Service
public class MailService {
    @Autowired
    private MailModuleProperties mailModuleProperties;

    public void sendMail(String to, String content) {
        if (mailModuleProperties.isEnabled()) {
            // send mail with default subject and content
String enabled=mailModuleProperties.getEnabled();
        }
    }
}

10、参数校验注解

10.1 一些常用字段的注解

通常用于校验服务端传过来的参数是否合法

@NotEmpty 被注释的字符串的不能为 null 也不能为空
@NotBlank 被注释的字符串非 null,并且必须包含一个非空白字符
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Pattern(regex=,flag=)被注释的元素必须符合指定的正则表达式
@Email 被注释的元素必须是 Email 格式。
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=)被注释的元素的大小必须在指定的范围内
@Digits(integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期

10.2 验证请求体

即校验一个类是否合法

即在一个类中,用注解表明其属性的一些规范,接收客户端那边传过来的json对象,可以校验其参数是否合法

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    @NotNull(message = "classId 不能为空")
    private String classId;

    @Size(max = 33)
    @NotNull(message = "name 不能为空")
    private String name;

    @Pattern(regexp = "((^Man$|^Woman$|^UGM$))", message = "sex 值不在可选范围")
    @NotNull(message = "sex 不能为空")
    private String sex;

    @Email(message = "email 格式不正确")
    @NotNull(message = "email 不能为空")
    private String email;

}

我们在需要验证的参数上加上了@Valid注解,如果验证失败,它将抛出MethodArgumentNotValidException

@RestController
@RequestMapping("/api")
public class PersonController {

    @PostMapping("/person")
    public ResponseEntity<Person> getPerson(@RequestBody @Valid Person person) {
        return ResponseEntity.ok().body(person);
    }
}

10.3 验证请求参数

一定一定不要忘记在类上加上 @Validated 注解了,这个参数可以告诉 Spring 去校验方法参数。

示例如下

@RestController
@RequestMapping("/api")
@Validated
public class PersonController {

    @GetMapping("/person/{id}")
    public ResponseEntity<Integer> getPersonByID(@Valid @PathVariable("id") @Max(value = 5,message = "超过 id 的范围了") Integer id) {
        return ResponseEntity.ok().body(id);
    }
}

11、全局异常处理

可见牛客项目,有具体的使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/413017.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里通义千问、ChatGPT和文心一言有何区别,在哪里能使用?

目前&#xff0c;聊天机器人技术在人工智能领域的发展越来越成熟了。现在已经有几款备受关注的聊天机器人产品问世&#xff0c;例如ChatGPT、阿里的通义千问和百度的文心一言。它们有什么区别&#xff0c;怎么使用呢&#xff1f; 其实&#xff0c;我也挺好奇的&#xff0c;毕竟…

人人拥有ChatGPT的时代来临了,这次微软很大方!

技术迭代的在一段时间内是均匀发展甚至止步不前的&#xff0c;但在某段时间内会指数级别的爆发。 ChatGPT背后的GPT 3.5训练据说花了几百万美金外加几个月的时间&#xff0c;参数大概有1700多亿。 这对于绝大多数的个人或企业来说绝对是太过昂贵的。 然而&#xff0c;微软&am…

月薪过 3w 的 软件测试工程师 都是怎么做到的?

对任何职业而言&#xff0c;薪资始终都会是众多追求的重要部分。前几年的软件测试行业还是一个风口&#xff0c;随着不断地转行人员以及毕业的大学生疯狂地涌入软件测试行业&#xff0c;目前软件测试行业“缺口”已经基本饱和。 当然&#xff0c;我说的是最基础的功能测试的岗…

如何使用双轴XY平台绘制正弦曲线

1. 功能说明 本文示例将实现双轴XY平台绘制正弦曲线的功能。 2. 电子硬件 在这个示例中&#xff0c;采用了以下硬件&#xff0c;请大家参考&#xff1a; 主控板 Basra主控板&#xff08;兼容Arduino Uno&#xff09; 扩展板 Bigfish2.1扩展板 SH-ST步进电机扩展板 电池11.1V动…

跟着原子学I2C

I2C通讯 1、IIC总线介绍 集成电路总线&#xff0c;是一种同步串行半双工通信总线。 总线or协议&#xff1f;&#xff01; 总线是数据传输通道&#xff0c;协议是数据传输规则。 1、1介绍 a、由时钟线SCL和数据线SDA组成&#xff0c;并且都接上拉电阻&#xff0c;确保总线空…

UDP套接字

大家好,又见面了,&#x1f389;&#x1f389;&#x1f389;&#x1f338;&#x1f338;&#x1f338; 今天为大家带来UDP套接字的相关知识 文章目录认识socketUDP和TCP认识UDPAPI有关方法基于UDP实现回显服务器UDP的方法基于UDP实现回显程序认识socket UDP和TCP 认识UDPAPI有…

【数据结构】二叉树的概念及结构

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; 初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是…

Linux内核设备驱动设备树概念与使用

一、设备树概念以及作用 1.1设备树概念 设备树(Device Tree)&#xff0c;将这个词分开就是“设备”和“树”&#xff0c;描述设备树的文件叫做 DTS(DeviceTree Source)&#xff0c;这个 DTS 文件采用树形结构描述板级设备&#xff0c;也就是开发板上的设备信息&#xff0c;比…

prometheus基本介绍

001 基本介绍 1.主要功能 多维数据模型&#xff08;时序由metric名字和k/v的labels构成&#xff09;灵活的查询语句无依赖存储&#xff0c;支持local和remote不同的模型采用http协议&#xff0c;使用pull模式&#xff0c;拉取数据&#xff0c;简单易懂监控目标&#xff0c;可…

session,zookeeper,mq-rabbitmq,kafka,websocket

spring-boot-demo-session pom.xml <?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://…

INSERT INTO IF NOT EXISTS问题

情景说明&#xff1a;工作上遇到一个树形结构的数据&#xff0c;如有文件夹和子文件夹这样的数据。由于后端逻辑问题&#xff0c;导致在前端页面操作了删除功能后&#xff0c;数据库中仅部分数据被删除&#xff0c;比如只把根节点或是父节点删除了&#xff0c;没有级联删除所有…

九龙证券|什么是庄家洗盘和出货?各有什么特征?

在股市独占的是庄家&#xff0c;在市场上独占的是商人。庄家的存在便是为了把资金投入市场变成本钱&#xff0c;使用本钱获取最大赢利。庄家的各类方法也是为了不惜一切代价获取最大赢利。今天我们来了解什么是庄家洗盘和出货&#xff1f;各有什么特征&#xff1f;下面就为大家…

所有知识付费都可以用 ChatGPT 再割一次?

伴随春天一起到来的&#xff0c;还有如雨后春笋般冒出的 ChatGPT / AI 相关的付费社群、课程训练营、知识星球等。 ChatGPT 吹来的这股 AI 热潮&#xff0c;这几个月想必大家多多少少都能感受到。 ▲ 图片来源&#xff1a;网络 这两张图是最近在圈子里看到的。 一张是国内各…

SpringBoot —— 日志基本操作

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ SpringBoot —— 日志基本操作一、日志的作用二…

Adobe全家桶功能介绍

Adobe全家桶是一套由Adobe公司开发的创意设计软件集合&#xff0c;包含了许多功能强大的软件&#xff0c;可以帮助用户完成各种创意设计任务。 以下是Adobe全家桶中一些主要软件的功能介绍&#xff1a; Photoshop&#xff1a;用于图像处理和编辑&#xff0c;可以进行图像裁剪…

Gradio介绍

Gradio App 就是给 AI 算法工程师训练的模型赋予分享给大众的能力。 从技术侧拆分&#xff0c;由三个部分组成&#xff1a; 前端页面 后端接口 AI算法模型推理 Gradio 做了一件事情&#xff0c;就是将这三个部分封装到一个 python 接口里&#xff0c;用户通过实现其封装的…

进来拿!最近疯传的154页微软 GPT-4早期实验报告:探究 AGI进化之路(全中文版)

这应该是&#xff0c;最近一段时间以来&#xff0c;关于 ChatGPT4.0剖析最全面的一份报告。 看懂10%&#xff0c;能帮我们对 ChatGPT 的认识&#xff0c;有一个质的跃升&#xff1b; 看懂50%&#xff0c;你将是分享 ChatGPT 知识领域最顶尖的那一拨人。 这份报告证明了 GPT-4…

Prometheus+Mysqld_exporter+Grafana从0到1搭建MySQL的可视化监控

目 录1. 准备工作1.1 安装MySQL1.2 安装Prometheus1.3 安装Mysqld_exporter1.4 安装Grafana2. 更改配置2.1 配置Mysqld_exporter2.2 配置Prometheus2.3 配置Grafana3. 小 结1. 准备工作 安装 MySQL 数据库安装 Prometheus安装 Mysqld_exporter安装 Grafana 在正式开始搭建之前…

面试官:如何在命令行跑Postman?

在接口自动化过程中&#xff0c;每次都打开postman工具来手动运行脚本显得不智能&#xff0c;所以可以通过命令在无UI或者其他持续集成的平台上执行脚本和数据。 01、环境准备与检查 环境准备 导出collection 安装node.js和cnpm 安装newman 环境检查 检测node.js&#x…

加密组件Jasypt学习、实战及踩坑记录

概述 最近入职新公司&#xff0c;因几乎全部项目都使用到jasypt&#xff0c;故而初步学习记录下本文&#xff08;持续更新&#xff09;。 官网及GitHub给出的简介&#xff1a;使用简单&#xff0c;性能好&#xff0c;特性features非常丰富&#xff1b;支持 另&#xff0c;有个…