• Spring框架学些(三)SpringBoot


    关于SpringBoot

    SpringBoot官方简介:

    Spring Boot makes it easy to create stand-alone, production-grade Spring-based Applications that you can run. We take an opinionated view of the Spring platform and third-party libraries, so that you can get started with minimum fuss. Most Spring Boot applications need very little Spring configuration.

    个人理解的SpringBoot做了这几件事:

    • 针对不同场景提供一些基础包(starter),其中处理了各个场景下不同包的版本依赖,简化了写pom文件
    • 提供一系列功能性的辅助包,比如国际化(Localizer/Internationization)、拦截(Interceptor/Filter)、制动(Actuator)等等
    • 最重要的:自动配置。这是SpringBoot的思想,简化配置,尽量做到零配置。并非所有组件没有配置功能,而是用约定替代认为配置,格个组件已经默认使用最常用的配置作为默认值,很多时候并不需要认为手工配置。

    所以学习SpringBoot稍微会不太明白究竟学的是什么,内容比较散似乎没有核心,可能向我理解的,核心就是自动配置的思想,外加各种配置吧。

    无论怎样,我是参照TutorialPoint上的教程大体了解了一边

    核心的一些内容

    starter

    Spring官方有这样一个Starter页面(地址),在这里选择工程类型、springboot版本和初始依赖后,可以生成一个spring项目下载下来,作为项目开发的起点。

    这个想法刚看到其实觉得有点不可思议,第一次看到一个框架会提供这样的功能帮助开展一个项目。不过Spring涉及的组件实在是太多,由这样的功能帮助解决依赖的确会方便不少。

    基本的一个web项目内容:

    	<!-- Inherit defaults from Spring Boot -->
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.2.0.RELEASE</version>
    	</parent>
    
    	<!-- Add typical dependencies for a web application -->
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    	</dependencies>
    

    parent模块包含了spring项目的一系列默认配置(比如再也不用手动指定java1.8版本了),而spring-boot-starter-web依赖项包含了一系列开发web项目需要的包,这里不需要指定版本,而是spring包帮忙维护了。

    这些spring-boot-starter-***的依赖,就是springboot的起点,除了web,还有一些其他的依赖封装,代表不同的功能。

    自动配置

    主入口

    不再是SpringCore的ApplicationContext,而是封装在了SpringApplication

    package com.example.myapplication;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
            // or new SpringApplicationBuilder(Example.class).run(args);
        }
    
    }
    

    传入的Example.class是类似SpringCore中的@Configuration注解类,代表这个类里可以定义Bean等,不过在SpringBoot中,不再是用Configuration,而是使用@SpringBootApplication

    这个注解包含了很多默认的配置,比如一个关键的从这个类开始进行component scan,扫描application.properties作为程序的property(bean中也会用到),配置默认的MessageSource读取位置等等。

    推荐的项目结构

    Spring推荐的项目结构:

    com
     +- example
         +- myapplication
             +- Application.java
             |
             +- customer
             |   +- Customer.java
             |   +- CustomerController.java
             |   +- CustomerService.java
             |   +- CustomerRepository.java
             |
             +- order
                 +- Order.java
                 +- OrderController.java
                 +- OrderService.java
                 +- OrderRepository.java
    

    简单来说,Spring的主入口(main函数,以及spring程序的主入口)最好也在main函数的类中,而且最好在整个项目的基础包中。

    这是因为spring默认的@ComponetScan等功能,会以次类作为扫描起点扫描子包,如果配置成其他的,就需要一些额外的手动配置了。

    其他功能

    感觉SpringBoot核心就是这些,但是主要相关功能还是一些组件/注解的使用和配置,当然这些可能实际都不属于SpringBoot的范畴了。。

    properties

    bean注解中也会用到,如

    @Value("${prop.field.name}")
    

    默认springboot会读取resources目录下的application.properties文件作为配置属性,当然,属性可以被命令行传入参数替换。

    ApplicationRunner/CommandLineRunner

    可以配置相应的Bean,或者实现这两个接口中的一个,使Spring启动后,运行这个Bean的Run方法,如:

    	@Bean
    	public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
    		return args -> {
    			log.info("Command line runner called");
    			Quote quote = restTemplate.getForObject("https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
    			log.info(quote.toString());
    		};
    	}
    

    interceptor/filter

    两个功能上有点类似,都是拦截HTTP请求做处理的,类似SpringCore中的PostProcesser等,但是Filter使用更复杂一些,属于Servlet级别的。而Interceptor是Spring框架自己维护的机制。

    这里注册了一个Intercepter,分别有三个接口,在请求处理前,处理后,处理完成时调用。

    @Component
    public class ProductInterceptor implements HandlerInterceptor {
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		System.out.println("Pre Handle method is Calling");
    		return true;
    	}
    
    	@Override
    	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    			ModelAndView modelAndView) throws Exception {
    		System.out.println("Post Handle method is Calling");
    	}
    
    	@Override
    	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
    			Exception exception) throws Exception {
    		System.out.println("Request and Response is completed");
    	}
    }
    

    Controller Advice

    这个注解可以用于处理异常:

    @ControllerAdvice
    public class ProductExceptionController {
    	@ExceptionHandler(value = ProductNotfoundException.class)
    	public ResponseEntity<Object> exception(ProductNotfoundException exception) {
    		return new ResponseEntity<>("Product not found", HttpStatus.NOT_FOUND);
    	}
    }
    

    定义这个类,当Controller出现异常时,就会被其中的exception方法捕获,处理响应

    @Service和@RestController

    其实本来没什么联系,但是放到一起。

    @Service用于标记MVC中的服务层。
    @RestController类似MVC中的@Controller,不同的是@Controller的返回值会被进一步交给View处理,而@RestController会将结果直接返回

    i18n

    国际化/多语言配置,需要配置多个bean和注册interceptor:

    
    //定义默认的Local
    	@Bean
    	public LocaleResolver localeResolver() {
    		SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
    		sessionLocaleResolver.setDefaultLocale(Locale.US);
    		return sessionLocaleResolver;
    	}
    
    //处理每个请求对应的不同的locale
    	@Bean
    	public LocaleChangeInterceptor localeChangeInterceptor() {
    		LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
    		localeChangeInterceptor.setParamName("language");
    		return localeChangeInterceptor;
    	}
    
    //定义国际化的资源文件,默认在resources目录下的messages.properties
    //这里改为i18n目录下的messages.properties
    //注意默认语言外的文件,通过下标来区分,如messages_cn.properties
    	@Bean
    	public MessageSource messageSource() {
    		ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    		messageSource.setBasenames("classpath:/i18n/messages");
    		return messageSource;
    	}
    

    注册:

    @Component
    public class ProductInterceptorConfig implements WebMvcConfigurer {
    
    	@Autowired
    	LocaleChangeInterceptor localeChangeInterceptor;
    
    	@Override
    	public void addInterceptors(InterceptorRegistry registry) {
    		registry.addInterceptor(localeChangeInterceptor);
    	}
    }
    

    我看的教程,ProductInterceptorConfig是继承的WebMvcConfigurerAdapter类,不过在我的版本中,这个类已经被废弃了,可以直接实现WebMvcConfigurer接口就能起作用。

    我定义的一个工具类,用于获取资源:

    @Component
    public class I18nUtil {
    	@Autowired
    	MessageSource messageSource;
    
    	public String getMessage(String msg, Object[] args) {
    		String localeMessage = "";
    
    		try {
    			localeMessage = messageSource.getMessage(msg, args, LocaleContextHolder.getLocale());
    		} catch (Exception var4) {
    			System.out.println("Exception[" + messageSource + "]:" + var4.getMessage());
    		}
    
    		return localeMessage;
    	}
    }
    

    在Controller中就能获取对应的文字:

    
    	@Autowired
    	I18nUtil i18n;
      	@RequestMapping(value = "/hello")
    	public ResponseEntity<Object> sayHello() {
    		return new ResponseEntity<>(i18n.getMessage("welcome.text", null), HttpStatus.OK);
    	}
    

    如果请求中增加?language=zh,就能去查找中文

  • 相关阅读:
    LeetCode: Reverse Linked List
    DataBase: MySQL在.NET中的应用
    DataBase: LeetCode
    DirectShow+VS2010+Win7配置说明
    MathType应用:批量改变公式格式
    $LaTeX$笔记:首字下沉
    Latex学习笔记-序
    反思--技术博客的写作应该是怎样的?
    用Latex写学术论文:作者(Author)&摘要(Abstract)
    用Latex写学术论文: IEEE Latex模板和文档设置(documentclass)
  • 原文地址:https://www.cnblogs.com/mosakashaka/p/12609117.html
Copyright © 2020-2023  润新知