Spring Boot第3部分:依赖注入和@RestController

Spring Boot第3部分:依赖注入和@RestController

介绍

本系列文章将研究Spring Boot的功能。 第三篇文章通过演示Spring Dependency Injection的基础知识来构建该系列文章。 为了创建可演示的代码,该示例还创建了@RestController实现,这是一个简单的共享属性服务器,客户端可以在其中放置和获取属性值。

Github上提供了该系列以及本部分的完整源代码。

@ComponentScan和依赖注入

这不是详尽的描述,仅描述了Spring依赖项注入的最简单(但可以说是最常见)的功能。

Spring Boot进程从Launcher::main方法(与本系列的第1部分和第2部分描述的实现保持不变)开始,并构造 SpringApplication并调用其run方法。 使用@SpringBootApplication注释类等同于使用@Configuration @EnableAutoConfiguration@ComponentScan @EnableAutoConfiguration@ComponentScan注释。

@SpringBootApplication
@NoArgsConstructor @ToString @Log4j2
public class Launcher {
    public static void main ( String [] argv ) throws Exception {
        SpringApplication application = new SpringApplication ( Launcher . class );

        application . run ( argv );
    }
}

SpringApplicationapplication.Launcher类开始分析。 @EnableAutoConfiguration指示Spring Boot应该在必要时尝试“猜测”。 @ComponentScan批注指示Spring Boot应该开始在application包(包含Launcher包)中扫描用@Component批注的@Component 。 注意:用@Component注释的注释类型也是组件。 例如, @Configuration@Controller@RestController都是@Component S,而不是相反。

对于每个用@Component注释的@Component ,Spring:

  1. 实例化一个实例,

  2. 对于每个带@Value注释的实例字段,请评估SpEL表达式1并使用结果初始化该字段,

  3. 对于@Configuration类中每个以@Bean注释的方法,请只调用一次该方法以获得Bean值,然后,

  4. 对于每个用@Autowired注释的字段,分配通过评估@Bean方法获得的相应值。

同样,以上内容是一个过分的简化,并非详尽无遗,它依赖于挥手,但应该足以上手。

本文的示例代码不需要@Value注入,但是上一篇文章在其MysqldConfiguration实现中提供了示例:

    @Value ( "${mysqld.home}" )
    private File home ;

    @Value ( "${mysqld.defaults.file:${mysqld.home}/my.cnf}" )
    private File defaults ;

    @Value ( "${mysqld.datadir:${mysqld.home}/data}" )
    private File datadir ;

    @Value ( "${mysqld.port}" )
    private Integer port ;

    @Value ( "${mysqld.socket:${mysqld.home}/socket}" )
    private File socket ;

    @Value ( "${logging.path}/mysqld.log" )
    private File console ;

上面的代码利用了在SpEL表达式中指定默认值和自动类型转换的优势。

在此实现的简单属性服务器在DictionaryConfiguration中创建一个“字典” bean:

@Configuration
@NoArgsConstructor @ToString @Log4j2
public class DictionaryConfiguration {
    @Bean
    public Map < String , String > dictionary () {
        return new ConcurrentSkipListMap <>();
    }
}

并将该bean连接到DictionaryRestController ,如下所示:

@RestController
...
@NoArgsConstructor @ToString @Log4j2
public class DictionaryRestController {
    @Autowired private Map < String , String > dictionary = null ;
    ...
}

下一节描述@RestController的实现。

@RestController实现

@RestController实现的@RestController提供以下Web API:

方法 URI 查询参数 退货
GET http://localhost:8080/dictionary/get key关联的值(可以为null
GET 2 http://localhost:8080/dictionary/put = key关联的先前值(可以为null
GET http://localhost:8080/dictionary/remove 先前与key关联的值(可以为null
GET http://localhost:8080/dictionary/size 没有 整型
GET http://localhost:8080/dictionary/entrySet 没有 键值对数组
GET http://localhost:8080/dictionary/keySet 没有 键值数组

DictionaryRestController@RestController@RequestMapping注释,其value = { "/dictionary" }指示请求路径将以/dictionary前缀,并produces = "application/json"指示HTTP响应应以JSON编码。

@RestController
@RequestMapping ( value = { "/dictionary" }, produces = MediaType . APPLICATION_JSON_VALUE )
@NoArgsConstructor @ToString @Log4j2
public class DictionaryRestController {
    @Autowired private Map < String , String > dictionary = null ;
    ...
}

如上一节所述,字典映射为@Autowired

/dictionary/put方法的实现是:

    @RequestMapping ( method = { RequestMethod . GET }, value = { "/put" })
    public Optional < String > put ( @RequestParam Map < String , String > parameters ) {
        if ( parameters . size () != 1 ) {
            throw new IllegalArgumentException ();
        }

        Map . Entry < String , String > entry =
            parameters . entrySet (). iterator (). next ();
        String result = dictionary . put ( entry . getKey (), entry . getValue ());

        return Optional . ofNullable ( result );
    }

Spring将在方法调用中将请求的查询参数作为parameters注入。 该方法验证是否恰好指定了一个查询参数,将该键值放入字典中,然后返回结果(映射中该键的先前值)。 Spring将String解释为文字JSON因此该方法将结果包装在Optional以强制Spring编码为JSON

/dictionary/get方法的实现是:

    @RequestMapping ( method = { RequestMethod . GET }, value = { "/get" })
    public Optional < String > get ( @RequestParam Map < String , String > parameters ) {
        if ( parameters . size () != 1 ) {
            throw new IllegalArgumentException ();
        }

        Map . Entry < String , String > entry =
            parameters . entrySet (). iterator (). next ();
        String result = dictionary . get ( entry . getKey ());

        return Optional . ofNullable ( result );
    }

同样,必须完全有一个查询参数,并将结果包装在Optional/dictionary/remove请求的实现几乎相同。

/dictionary/size方法的实现是:

    @RequestMapping ( method = { RequestMethod . GET }, value = { "/size" })
    public int size ( @RequestParam Map < String , String > parameters ) {
        if (! parameters . isEmpty ()) {
            throw new IllegalArgumentException ();
        }

        return dictionary . size ();
    }

不应指定查询参数。 /dictionary/entrySet的实现与Set<Map.Entry<String,String>>的方法返回类型几乎相同:

    @RequestMapping ( method = { RequestMethod . GET }, value = { "/entrySet" })
    public Set < Map . Entry < String , String >> entrySet ( @RequestParam Map < String , String > parameters ) {
        if (! parameters . isEmpty ()) {
            throw new IllegalArgumentException ();
        }

        return dictionary . entrySet ();
    }

/dictionary/keySet的实现遵循相同的模式。

Maven项目POM提供了本系列第一篇文章中描述的spring-boot:run配置文件,并且服务器可以通过mvn -B -Pspring-boot:run 。 使用此配置文件启动后 ,即可使用Spring Boot执行器@RestServer处理程序映射可以通过以下查询进行验证:

$  curl -X GET http://localhost:8081/actuator/mappings \
> | jq '.contexts.application.mappings.dispatcherServlets[][]
        | {handler: .handler, predicate: .predicate}'
{
  "handler" : "application.DictionaryRestController#remove(Map)" ,
  "predicate" : "{GET /dictionary/remove, produces [application/json]}"
}
{
  "handler" : "application.DictionaryRestController#get(Map)" ,
  "predicate" : "{GET /dictionary/get, produces [application/json]}"
}
{
  "handler" : "application.DictionaryRestController#put(Map)" ,
  "predicate" : "{GET /dictionary/put, produces [application/json]}"
}
{
  "handler" : "application.DictionaryRestController#size(Map)" ,
  "predicate" : "{GET /dictionary/size, produces [application/json]}"
}
{
  "handler" : "application.DictionaryRestController#entrySet(Map)" ,
  "predicate" : "{GET /dictionary/entrySet, produces [application/json]}"
}
{
  "handler" : "application.DictionaryRestController#keySet(Map)" ,
  "predicate" : "{GET /dictionary/keySet, produces [application/json]}"
}
{
  "handler" : "org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)" ,
  "predicate" : "{ /error, produces [text/html]}"
}
{
  "handler" : "org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)" ,
  "predicate" : "{ /error}"
}
{
  "handler" : "ResourceHttpRequestHandler [ \" classpath:/META-INF/resources/webjars/ \" ]" ,
  "predicate" : "/webjars/**"
}
{
  "handler" : "ResourceHttpRequestHandler [ \" classpath:/META-INF/resources/ \" ,  \" classpath:/resources/ \" ,  \" classpath:/static/ \" ,  \" classpath:/public/ \" ,  \" / \" ]" ,
  "predicate" : "/**"
}

使用curl验证put操作(请注意第一次和第二次调用返回值的不同):

$  curl -X GET -i http://localhost:8080/dictionary/put?foo = bar
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 11 Dec 2019 19:56:43 GMT

null

$  curl -X GET -i http://localhost:8080/dictionary/put?foo = bar
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 11 Dec 2019 19:56:44 GMT

"bar"

然后使用get操作验证先前的put:

$  curl -X GET -i http://localhost:8080/dictionary/get?foo
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 11 Dec 2019 19:59:22 GMT

"bar"

检索字典条目集演示了复杂的JSON编码:

$  curl -X GET -i http://localhost:8080/dictionary/entrySet
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 11 Dec 2019 20:00:24 GMT

[ {
  "foo" : "bar"
} ]

提供查询参数大小可演示错误处理:

$  curl -X GET -i http://localhost:8080/dictionary/size?foo
HTTP/1.1 500
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 11 Dec 2019 20:03:42 GMT
Connection: close

{
  "timestamp" : "2019-12-11T20:03:42.110+0000" ,
  "status" : 500,
  "error" : "Internal Server Error" ,
  "message" : "No message available" ,
  "trace" : "java.lang.IllegalArgumentException \n\t at application.DictionaryRestController.size(DictionaryRestController.java:65) \n ..." ,
  "path" : "/dictionary/size"
}

摘要

本文通过展示如何“演示基本春天依赖注入@Value的”可以被计算并注入“ @Bean的”可以创建和“ @Autowired在” @RestController实现。

本系列的第4部分将讨论Spring MVC,并以一个简单的国际化时钟应用程序为例。


  1. SpEL还提供对application.properties资源中定义的属性的访问。

  2. 不幸的是, GET HTTP方法与Map put方法结合使用可能会造成混乱,并且更复杂的API定义可能会合理地使用POSTPUT方法获取其语义值。

From: https://dev.to/allenball/spring-boot-part-3-dependency-injection-and-restcontroller-3374

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Spring Boot 中使用 Principal 注入的方法如下: 1. 在 Controller 类的方法参数中加入 Principal 类型的参数,Spring Boot 会自动将当前用户的 Principal 注入进来。 例如: ``` @GetMapping("/user") public String getUser(Principal principal) { return "Hello, " + principal.getName(); } ``` 2. 在 Controller 类中使用 @AuthenticationPrincipal 注解标注一个方法参数,Spring Boot 会将当前用户的 Principal 注入进来。 例如: ``` @GetMapping("/user") public String getUser(@AuthenticationPrincipal User user) { return "Hello, " + user.getUsername(); } ``` 需要注意的是,使用 @AuthenticationPrincipal 注解时,方法参数的类型不能是 Principal,而必须是你在身份认证过程中使用的身份对象的类型(例如:User)。 ### 回答2: 在Spring Boot中,我们可以通过注解的方式将check/token Principal注入到我们的应用程序中。 首先,我们需要在我们的应用程序中使用`@EnableWebSecurity`注解来启用Web安全配置。然后,我们需要创建一个实现了`UserDetailsService`接口的类,来加载用户的信息。 具体步骤如下所示: 1. 首先,我们需要创建一个实体类来表示用户信息,该实体类需要实现`UserDetails`接口,并重写相应的方法,如`getUsername()`、`getPassword()`等。 2. 接下来,我们需要创建一个实现了`UserDetailsService`接口的类,该类用于加载用户的信息。在该类中,我们需要重写`loadUserByUsername()`方法,根据用户名从数据库或其他数据源中加载对应的用户信息,并返回一个`UserDetails`对象。 3. 然后,我们可以在其他需要使用用户信息的地方通过依赖注入的方式来获取该信息。可以使用`@Autowired`注解将`UserDetailsService`实例注入到其他类中,然后调用`loadUserByUsername()`方法获取用户信息,并进行相应的操作。 另外,如果我们需要在控制器中获取当前用户的信息,可以使用`@AuthenticationPrincipal`注解来注入用户信息。在方法参数中使用该注解,Spring Boot会自动将当前用户的信息注入到该参数中。 总结来说,在Spring Boot注入check/token Principal的方式主要有两种: 1. 通过注入`UserDetailsService`实例来获取用户信息,然后在需要使用的地方调用`loadUserByUsername()`方法获取用户信息。 2. 在控制器中使用`@AuthenticationPrincipal`注解来注入当前用户的信息。 ### 回答3: 在Spring Boot中,我们可以使用Spring Security框架来进行身份验证和授权。在进行身份验证时,Spring Security将会为每个认证过的用户生成一个Principal对象,该对象包含了用户的信息和角色。 在Spring Boot注入Principal对象有以下几种方法: 1. 在Controller中注入Principal对象: 在Controller方法的参数列表中添加Principal对象,Spring Boot会自动将认证用户的Principal对象注入进来,代码示例如下: ```java @RestController public class MyController { @GetMapping("/user") public String getUser(Principal principal) { // 使用Principal对象获取用户信息 String username = principal.getName(); // ... } } ``` 2. 在Service或Component中使用SecurityContextHolder获取Principal对象: 通过SecurityContextHolder获取SecurityContext对象,在SecurityContext对象中可以获取Principal对象。代码示例如下: ```java @Service public class MyService { public void doSomething() { SecurityContext context = SecurityContextHolder.getContext(); Principal principal = context.getAuthentication().getPrincipal(); // 使用Principal对象获取用户信息 String username = principal.getName(); // ... } } ``` 需要注意的是,在使用第二种方法时,必须确保在调用doSomething方法之前,用户已经进行了身份验证,否则可能会出现NullPointerException。 总结来说,Spring Boot注入Principal对象可以通过在Controller中将Principal对象作为方法参数来实现,也可以在Service或Component中通过SecurityContextHolder获取SecurityContext对象,并从中获取Principal对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值