zoukankan      html  css  js  c++  java
  • springboot

    1.概念

    官方文档https://docs.spring.io/spring-boot/docs/1.5.17.RELEASE/reference/htmlsingle/#boot-features-external-config

    2.自动配置

    2.1自动配置启动(源码分析)

    @SpringBootApplication//启动类注解
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    
    @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 {
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration//配置类
    public @interface SpringBootConfiguration {
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage//自动加载的包
    @Import({EnableAutoConfigurationImportSelector.class})//加载EnableAutoConfigurationImportSelector
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import({Registrar.class})//加载Registrar
    public @interface AutoConfigurationPackage {
    
    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
            Registrar() {
            }
    
            public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
                AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
            }//(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()扫描的包,可以打断点使用计算查看
    
    public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector {
    
    public class AutoConfigurationImportSelector implements DeferredImportSelector, ..//这个可以看官网spring的注解,对于这个类有相关介绍
    ....
     public String[] selectImports(AnnotationMetadata annotationMetadata)
      List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
      public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
    
            try {//读取的文件的位置
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
    
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    

     

    其中例如有HttpEncodingAutoConfiguration编码的处理类,该类所有在配置文件中能配置的属性都是在xxxxProperties类中封装

    总结:

    1》@SpringBootApplication的main方法运行时自动扫描的包为:(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()扫描的包,可以打断点使用计算查看,默认为同包下

    2》@SpringBootApplication会加载META-INF/spring.factories文件,将该配置文件中的配置载入到Spring容器。每种具有相应的xxxxProperties与之对应

    2.2 @ConfigurationProperties

    配置该注解后会出现如下

    解决方法

    添加依赖

    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
    </dependency>
    

    添加后如下,添加后的作用增加书写配置的提示功能

     

    功能:自动注入相应的属性。并具备支持jsr3.3功能

     例如:配置数据源

    DataSourceAutoConfiguration自动配置类,对应的自动的properties为DataSourceProperties。

    我们看DataSourceProperties类如下

     

    所以相应的配置为:

    spring.datasource.属性

     总结:@ConfigurationProperties具有自动注解的功能

    备注:其他注解

    @Conditional派生注解//指定的条件成立才生效,否则无效

    我们可以在配置文件中添加debug=true;来让控制台打印自动配置报告,这样可以很方便的知道哪些自动配置类生效;

    2.3依赖的基本讲解

    例如如下

      <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.17.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <!--web依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>//web依赖及启动
            </dependency>
            <!--测试-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    

     在父依赖中我们可以看到这样的一个依赖,里面有相应的的版本和依赖

        <groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-dependencies</artifactId>
    	<version>1.5.17.RELEASE</version>
    

    在配置文件中我们可以看到相应的配置的顶级依赖

    假如我们需要添加向相应的依赖,那么可以参考官网添加相应的组件,如下

     2.4 可自动加载的配置文件类型及位置及顺序及书写规范及使用

    1)可自动加载的配置文件类型

    2)加载的位置及顺序

    a)优先级由高到低

    file:./config/

    file:./

    classpath:/config/

    classpath:/

    b)现在加载的配置优先级高,高优先级的配置会覆盖低优先级的配置,同一文件夹下,文件顺序靠前的优先级高

    c)配置外的加载顺序,优先级由高到低,也可以使用如下方式
    命令行参数
    所有的配置都可以在命令行上进行指定
    java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc,多个配置用空格分开; --配置项=值
    来自java:comp/env的JNDI属性
    Java系统属性(System.getProperties())
    操作系统环境变量
    RandomValuePropertySource配置的random.*属性值
    优先加载带profile
    jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
    jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件

    jar包外部的application.properties或application.yml(不带spring.profile)配置文件
    jar包内部的application.properties或application.yml(不带spring.profile)配置文件

    总结:所有的配置都可以在命令行上进行指定优先级是最高的,然后是系统环境类配置,然后是外部的application-{profile},然后是内部的application-{profile},然后是外部的application,然后是内部的application

    3)书写规范

    a)yml文件概念

    YAML A Markup Language:是一个标记语言,YAML isn't Markup Language:不是一个标记语言;YAML:以数据为中心,比json、xml等更适合做配置文件;

    b)规范

     属性和值也是大小写敏感

    字面量:普通的值(数字,字符串,布尔)

    直接写

    字符串默认不用加上单引号或者双引号;

    "":双引号;不会转义字符串里面的特殊字符;

    '':单引号;会转义特殊字符

    对象、Map(属性和值)(键值对):

    k: v:的方式书写属性和值的关系;例如//注意空格:后有空格

    map:
      name: 张三
      age: 23
    

    行内写法:map: {name: 张三,age: 23}

    数组(List、Set):

    用- 值表示数组中的一个元素//在-后又空格

    例如

    pets:
        ‐ dog
        ‐ cat
    

     行内写法 pets: [dog,cat]

    4) 使用

    map: {name: 张三, age: 23}
    
    @Component
    @ConfigurationProperties(prefix = "map")//会提示红色,需要导入提示jar,当然不导入也可以运行
    public class Person {
    
    <dependency>//提示依赖
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
    </dependency>
    

    备注:

    yml书写是要注意层级关系,yml是依靠空格来控制层级关系的,对齐表示同一层级,靠后表示子层级,类似xml。

    占位符

    例如${random.value}、${random.int}、${random.long},person.last‐name=张三${random.uuid}

     3.@Value获取值和@ConfigurationProperties获取值区别

    4.@PropertySource&@ImportResource的区别

     @PropertySource:加载指定的配置文件,配置中的内容不会生效,需要使用例如spel的方式获取

    @ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;

    备注:在配置文件中可以添加随机占位符,${random.xxx}

    5.@Profile

    server:
    port: 8081
    spring:
    profiles:
    active: prod  #激活prod  端口变为8084 多配置选择
    ‐‐‐  #分块
    server:
    port: 8083
    spring:
    profiles: dev
    ‐‐‐
    server:
    port: 8084
    spring:
    profiles: prod #指定属于哪个环境
    

     激活的方式除了上述还有如下方式

    配置文件中指定 spring.profiles.active=dev需要配合application-{profile}.properties/yml方式使用,默认加载的是application.properties的配置在其中通过spring.profiles.active=dev指定
    命令行
    java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev;
    可以直接在测试的时候,配置传入命令行参数
    虚拟机参数 -Dspring.profiles.active=dev

     5.web中的使用

    5.1静态资源的访问(WebMvcAutoConfiguration)

    webjars:可以以jar包的方式引入静态资源;http://www.webjars.org/

    <!‐‐例如 :引入jquery‐‐>
    <dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.3.1</version>
    </dependency>
    

    所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源;

    "/**" 访问当前项目的任何资源,都去(静态资源的文件夹)找映射(源码中就是采用的/**),所以也可以放入如下位置

    "classpath:/META‐INF/resources/",
    "classpath:/resources/",
    "classpath:/static/",
    "classpath:/public/"
    
     private static final String[] SERVLET_RESOURCE_LOCATIONS = new String[]{"/"};
        private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", 
    "classpath:/public/"};

    也可以自己指定文件位置,spring.resources.static-locations=值的方式指定多个多个位置,用逗号隔开,但是默认位置就不在生效

    默认页面的加载欢迎页; 静态资源文件夹下的所有index.html页面;

    private WelcomePageHandlerMapping(Resource welcomePage, String staticPathPattern) {
                if (welcomePage != null && "/**".equals(staticPathPattern)) {
                    logger.info("Adding welcome page: " + welcomePage);
                    ParameterizableViewController controller = new ParameterizableViewController();
                    controller.setViewName("forward:index.html");
                    this.setRootHandler(controller);
                    this.setOrder(0);
                }
    
            }
    

     图标所有的 **/favicon.ico 都是在静态资源文件下找;

    @Bean
                public SimpleUrlHandlerMapping faviconHandlerMapping() {
                    SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
                    mapping.setOrder(-2147483647);
                    mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", this.faviconRequestHandler()));
                    return mapping;
                }
    

     综上:

    5.2 thymeleaf(官方推荐支持thymeleaf,不支持jsp)(官方文档https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.pdf

    引入依赖(已经有了相应的管理)

    依赖:

     <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
    
    <-- 不需要写版本,假如想更改版本,可以这样写!-->
    <properties> <thymeleaf.version>3.0.9.RELEASE</thymeleaf.version> <!‐‐ 布局功能的支持程序 thymeleaf3主程序 layout2以上版本 ‐‐> <!‐‐ thymeleaf2 layout1‐‐> <thymeleaf‐layout‐dialect.version>3.0.9</thymeleaf‐layout‐dialect.version> </properties>

     配置thymeleaf的默认解析,前缀为classpath:/templates/,后缀为.html

     public static final String DEFAULT_PREFIX = "classpath:/templates/";
        public static final String DEFAULT_SUFFIX = ".html";
    

     基本使用:

    其他(可以去官网看示例)

    Simple expressions:(表达式语法)
    Variable Expressions: ${...}:获取变量值;OGNL;
    1)、获取对象的属性、调用方法
    2)、使用内置的基本对象:
    #ctx : the context object.
    #vars: the context variables.
    #locale : the context locale.
    #request : (only in Web Contexts) the HttpServletRequest object.
    #response : (only in Web Contexts) the HttpServletResponse object.
    #session : (only in Web Contexts) the HttpSession object.
    #servletContext : (only in Web Contexts) the ServletContext object.
    ${session.foo}
    3)、内置的一些工具对象:
    #execInfo : information about the template being processed.
    #messages : methods for obtaining externalized messages inside variables expressions, in the
    same way as they would be obtained using #{…} syntax.
    #uris : methods for escaping parts of URLs/URIs
    #conversions : methods for executing the configured conversion service (if any).
    #dates : methods for java.util.Date objects: formatting, component extraction, etc.
    #calendars : analogous to #dates , but for java.util.Calendar objects.
    #numbers : methods for formatting numeric objects.
    #strings : methods for String objects: contains, startsWith, prepending/appending, etc.
    #objects : methods for objects in general.
    #bools : methods for boolean evaluation.
    #arrays : methods for arrays.
    #lists : methods for lists.
    #sets : methods for sets.
    #maps : methods for maps.
    #aggregates : methods for creating aggregates on arrays or collections.
    #ids : methods for dealing with id attributes that might be repeated (for example, as a
    result of an iteration).
    Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;
    补充:配合 th:object="${session.user}:
    <div th:object="${session.user}">
    <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
    <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
    </div>
    Message Expressions: #{...}:获取国际化内容
    Link URL Expressions: @{...}:定义URL;
    @{/order/process(execId=${execId},execType='FAST')}
    Fragment Expressions: ~{...}:片段引用表达式
    <div th:insert="~{commons :: main}">...</div>
    Literals(字面量)
    Text literals: 'one text' , 'Another one!' ,…
    Number literals: 0 , 34 , 3.0 , 12.3 ,…
    Boolean literals: true , false
    Null literal: null
    Literal tokens: one , sometext , main ,…
    Text operations:(文本操作)
    String concatenation: +
    Literal substitutions: |The name is ${name}|
    Arithmetic operations:(数学运算)
    Binary operators: + , ‐ , * , / , %
    Minus sign (unary operator): ‐
    Boolean operations:(布尔运算)
    Binary operators: and , or
    Boolean negation (unary operator): ! , not
    Comparisons and equality:(比较运算)
    Comparators: > , < , >= , <= ( gt , lt , ge , le )
    Equality operators: == , != ( eq , ne )
    Conditional operators:条件运算(三元运算符)
    If‐then: (if) ? (then)
    If‐then‐else: (if) ? (then) : (else)
    Default: (value) ?: (defaultvalue)
    Special tokens:
    No‐Operation: _
    

     [[]]会转义特殊字符     [()]不会特殊转义

    6.springmvc

    自动配置

    Converter , GenericConverter , Formatter beans 视图解析器ContentNegotiatingViewResolver and BeanNameViewResolver beans  静态资源处理等

     具体可以查看

    拓展的配置

    <mvc:view‐controller path="/hello" view‐name="success"/>
    <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/hello"/>
                <bean></bean>
            </mvc:interceptor>
    </mvc:interceptors>            

    自定义配置

    @Configuration  

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Configuration {

    自己添加功能可以实现WebMvcConfigurerAdapter,也就spring注解的中的一些接口实现

    //使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
    @Configuration
    public class MyMvcConfig extends WebMvcConfigurerAdapter {
    @Override
        public void addViewControllers(ViewControllerRegistry registry) {
        // super.addViewControllers(registry);
        //浏览器发送 /index请求来到 success
        registry.addViewController("/index").setViewName("success");
        }
    }

    当使用@EnableWebMvc自动配置就失效

     原因

    @Import(DelegatingWebMvcConfiguration.class)
    public @interface EnableWebMvc {
    @Configuration
    public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    @Configuration
    @ConditionalOnWebApplication
    @ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
    WebMvcConfigurerAdapter.class })
    //容器中没有这个组件的时候,这个自动配置类才生效
    @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
    @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
    ValidationAutoConfiguration.class })
    public class WebMvcAutoConfiguration { 

    转发重定向前后缀处理:自定拼串

        public static final String DEFAULT_PREFIX = "classpath:/templates/";
        public static final String DEFAULT_SUFFIX = ".html";

    国际化

    @ConfigurationProperties(
        prefix = "spring.messages"
    )
    public class MessageSourceAutoConfiguration {
        private static final Resource[] NO_RESOURCES = new Resource[0];
        private String basename = "messages";
    默认的就是根据请求头带来的区域信息获取Locale进行国际化
      @Bean
        @ConditionalOnMissingBean
        @ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
        public LocaleResolver localeResolver() {
            if (this.mvcProperties
                    .getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
                return new FixedLocaleResolver(this.mvcProperties.getLocale());
            }
            AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
            localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
            return localeResolver;
        }
    

    点击链接切换国际化

    public class MyLocaleResolver implements LocaleResolver {
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            String l = request.getParameter("l");
            Locale locale = Locale.getDefault();
            if(!StringUtils.isEmpty(l)){
                String[] split = l.split("_");
                locale = new Locale(split[0],split[1]);
            }
            return locale;
        }
        @Override
        public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale
                locale) {
        }
    }
        @Bean
        public LocaleResolver localeResolver(){
            return new MyLocaleResolver();
        }
    }            

    例如

    login.remember=记住我
     <input type="checkbox" value="remember-me"> [[#{login.remember}]]
    spring.messages.basename=i18n.index
    

    禁用thymeleaf模板的缓存,ctrl+f9可以重写编译便于开发

    spring.thymeleaf.cache=false
    
    th:if
    <p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
    

    登录检查

    public class LoginHandlerInterceptor implements HandlerInterceptor {
        //目标方法执行之前
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                                 Object handler) throws Exception {
            Object user = request.getSession().getAttribute("loginUser");
            if(user == null){
    //未登陆,返回登陆页面
                request.setAttribute("msg","没有权限请先登陆");
                request.getRequestDispatcher("/index.html").forward(request,response);
                return false;
            }else{
    //已登陆,放行请求
                return true;
            }
        }
    

    注册拦截器

        @Override
        public void addInterceptors(InterceptorRegistry registry) {
    //super.addInterceptors(registry);
    //静态资源; *.css , *.js   SpringBoot已经做好了静态资源映射
            registry.addInterceptor(new
                    LoginHandlerInterceptor()).addPathPatterns("/**")
                    .excludePathPatterns("/index.html","/","/user/login");
        }
    };
    

    restful

     thymeleaf引入片段

    抽取公共片段
    <div th:fragment="copy">
    © 2018 The Good Thymes Virtual Grocery
    </div>
    引入公共片段
    <div th:insert="~{footer :: copy}"></div>
    ~{templatename::selector}:模板名::选择器
    ~{templatename::fragmentname}:模板名::片段名
    默认效果:
    insert的公共片段在div标签中
    如果使用th:insert等属性进行引入,可以不用写~{}:
    行内写法可以加上:[[~{}]];[(~{})];
    

     th:insert:将公共片段整个插入到声明引入的元素中
    th:replace:将声明引入的元素替换为公共片段
    th:include:将被引入的片段的内容包含进这个标签中

    例如

    <footer th:fragment="copy">
    © 2018 The Good Thymes Virtual Grocery
    </footer>
    引入方式
    <div th:insert="footer :: copy"></div>
    <div th:replace="footer :: copy"></div>
    <div th:include="footer :: copy"></div>
    效果
    <div>
    <footer>
    © 2011 The Good Thymes Virtual Grocery
    </footer>
    </div>
    <footer>
    © 2011 The Good Thymes Virtual Grocery
    </footer>
    <div>
    © 2011 The Good Thymes Virtual Grocery
    </div>
    

     日期格式化

    public Formatter<Date> dateFormatter() {
                return new DateFormatter(this.mvcProperties.getDateFormat());
            }
    

     默认格式

    修改

    spring.mvc.date-format=yyyy-MM-dd
    

     定义了的格式类型

    static {
            Map<ISO, String> formats = new EnumMap(ISO.class);
            formats.put(ISO.DATE, "yyyy-MM-dd");
            formats.put(ISO.TIME, "HH:mm:ss.SSSZ");
            formats.put(ISO.DATE_TIME, "yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            ISO_PATTERNS = Collections.unmodifiableMap(formats);
        }
    

     错误处理机制

    根据不同的头信息accept返回相应的值,html/text返回的是页面,*/*返回的是json数据

    原理:
    可以参照ErrorMvcAutoConfiguration;错误处理的自动配置;
    给容器中添加了以下组件
    DefaultErrorAttributes:

     @Override
        public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
                                                      boolean includeStackTrace) {
            Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();
            errorAttributes.put("timestamp", new Date());
            addStatus(errorAttributes, requestAttributes);
            addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
            addPath(errorAttributes, requestAttributes);
            return errorAttributes;
        }
    

     BasicErrorController:处理默认/error请求,根据不同的accept,返回相应的值

    ErrorPageCustomizer

    @Value("${error.path:/error}")
    private String path = "/error"; 系统出现错误以后来到error请求进行处理;(web.xml注册的错误页面规则)
    

     DefaultErrorViewResolver:

    static {
            Map<Series, String> views = new HashMap();
            views.put(Series.CLIENT_ERROR, "4xx");
            views.put(Series.SERVER_ERROR, "5xx");
            SERIES_VIEWS = Collections.unmodifiableMap(views);
        }
    
     @Override
        public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
                                             Map<String, Object> model) {
            ModelAndView modelAndView = resolve(String.valueOf(status), model);
            if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
                modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
            }
            return modelAndView;
        }
        private ModelAndView resolve(String viewName, Map<String, Object> model) {
            //默认SpringBoot可以去找到一个页面? error/404
            String errorViewName = "error/" + viewName;
            //模板引擎可以解析这个页面地址就用模板引擎解析
            TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
                    .getProvider(errorViewName, this.applicationContext);
            if (provider != null) {
            //模板引擎可用的情况下返回到errorViewName指定的视图地址
                return new ModelAndView(errorViewName, model);
            }
            //模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面 error/404.html
            return resolveResource(errorViewName, model);
        }
    

     thymeleaf模板能获取的信息
    timestamp:时间戳
    status:状态码
    error:错误提示
    exception:异常对象
    message:异常消息
    errors:JSR303数据校验的错误都在这里

    备注:假如以上页面都没有那么返回默认的页面

    另外一种处理异常的方式,这里是转发到error页面来处理,进行根据不同的头信息accept返回相应的值,html/text返回的是页面,*/*返回的是json数据

     @ExceptionHandler(UserNotExistException.class)
        public String handleException(Exception e, HttpServletRequest request){
            Map<String,Object> map = new HashMap<>();
            //传入我们自己的错误状态码 4xx 5xx,否则就不会进入定制错误页面的解析流程
            /**
             * Integer statusCode = (Integer) request
             .getAttribute("javax.servlet.error.status_code");
             */
            request.setAttribute("javax.servlet.error.status_code",500);
            map.put("code","user.notexist");
            map.put("message",e.getMessage());
         request.setAttribute("ext",map)//将map的数据放入,其实这个可要可不要 //转发到/error return "forward:/error"; }

     以上定义存在自定义数据不能携带的问题

    出现错误以后,会来到/error请求,会被BasicErrorController处理,响应出去可以获取的数据是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法);
    1、完全来编写一个ErrorController的实现类【或者是编写AbstractErrorController的子类】,放在容器中;
    2、页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getErrorAttributes得到;容器中DefaultErrorAttributes.getErrorAttributes();默认进行数据处理的;
    自定义ErrorAttributes

    @Component
    public class MyErrorAttributes extends DefaultErrorAttributes {
        @Override
        public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
                                                      boolean includeStackTrace) {
            Map<String, Object> map = super.getErrorAttributes(requestAttributes,
                    includeStackTrace);
         Map ext=requestAttributes.getAttribute("ext",0);//上述放入在request中的ext
         map.put("ext",ext) return map; //这样就将上述的数据携带出去,还可以自定义的在map中添加属性 } }

     7 与servlet之间的配合

    设置相关属性

    配置文件方式

    server.port=8082
    server.context‐path=/test
    server.tomcat.uri‐encoding=UTF‐8
    

     另一种方式

     @Bean //一定要将这个定制器加入到容器中
        public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
            return new EmbeddedServletContainerCustomizer() {
                //定制嵌入式的Servlet容器相关的规则
                @Override
                public void customize(ConfigurableEmbeddedServletContainer container) {
                    container.setPort(8083);
                }
            };
        }
    

     备注:

    SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;
    在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
    在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置

    三大组件的使用

    ServletRegistrationBean

       @Bean
        public ServletRegistrationBean myServlet(){
            ServletRegistrationBean registrationBean = new ServletRegistrationBean(new
                    MyServlet(),"/myServlet");
            return registrationBean;
        }
    

     FilterRegistrationBean

      @Bean
        public FilterRegistrationBean myFilter(){
            FilterRegistrationBean registrationBean = new FilterRegistrationBean();
            registrationBean.setFilter(new MyFilter());
            registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
            return registrationBean;
        }
    

     ServletListenerRegistrationBean

    @Bean
        public ServletListenerRegistrationBean myListener(){
            ServletListenerRegistrationBean<MyListener> registrationBean = new
                    ServletListenerRegistrationBean<>(new MyListener());
            return registrationBean;
        }
    

    8. 外置的Servlet容器:外面安装Tomcat---应用war包的方式打包;

    必须创建一个war项目;(利用idea创建好目录结构)
    将嵌入式的Tomcat指定为provided;

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring‐boot‐starter‐tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    

     必须编写一个SpringBootServletInitializer的子类,并调用configure方法

    public class ServletInitializer extends SpringBootServletInitializer {
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
           //传入SpringBoot应用的主程序
            return application.sources(SpringBoot04WebJspApplication.class);
        }
    }
    

     启动服务器就可以使用

    9 jdbc

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring‐boot‐starter‐jdbc</artifactId>
    </dependency>
    <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql‐connector‐java</artifactId>
            <scope>runtime</scope>
    </dependency>    
    
    spring:
        datasource:
          username: root
          password: 123456
          url: jdbc:mysql://192.168.15.22:3306/jdbc
          driver‐class‐name: com.mysql.jdbc.Driver
    

     自动配置原理:
    org.springframework.boot.autoconfigure.jdbc:
    参考DataSourceConfiguration,根据配置创建数据源,默认使用Tomcat连接池;可以使用spring.datasource.type指定自定义的数据源类型;
    SpringBoot默认可以支持:org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource

    自定义数据源类型

    @ConditionalOnMissingBean(DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type")
    static class Generic {
        @Bean
        public DataSource dataSource(DataSourceProperties properties) {
            //使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
            return properties.initializeDataSourceBuilder().build();
        }
    }
    

     DataSourceInitializer:ApplicationListener

    runSchemaScripts();运行建表语句;
    runDataScripts();运行插入数据的sql语句;

    默认只需要将文件命名为: 

    schema‐*.sql、data‐*.sql
    默认规则:schema.sql,schema‐all.sql;
    可以使用
    schema:
        classpath:department.sql  //指定位置
    

     整合Druid数据源

    spring:
        datasource:
        username: root
        password: 123456
        url: jdbc:mysql://192.168.15.22:3306/jdbc
        driver‐class‐name: com.mysql.jdbc.Driver
       type: com.alibaba.druid.pool.DruidDataSource
    
    @Configuration
    public class DruidConfig {
        @ConfigurationProperties(prefix = "spring.datasource")//yml的前缀spring.datasource,导入资源
        @Bean
        public DataSource druid(){
            return new DruidDataSource();
        }
        //配置Druid的监控
      //1、配置一个管理后台的Servlet
        @Bean
        public ServletRegistrationBean statViewServlet(){
            ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(),
                    "/druid/*");
            Map<String,String> initParams = new HashMap<>();
            initParams.put("loginUsername","admin");
            initParams.put("loginPassword","123456");
            initParams.put("allow","");//默认就是允许所有访问
            initParams.put("deny","192.168.15.21");
            bean.setInitParameters(initParams);
            return bean;
        }
        //2、配置一个web监控的filter
        @Bean
        public FilterRegistrationBean webStatFilter(){
            FilterRegistrationBean bean = new FilterRegistrationBean();
            bean.setFilter(new WebStatFilter());
            Map<String,String> initParams = new HashMap<>();
            initParams.put("exclusions","*.js,*.css,/druid/*");
            bean.setInitParameters(initParams);
            bean.setUrlPatterns(Arrays.asList("/*"));
            return bean;
        }
    }
    
  • 相关阅读:
    大道至简阅读笔记01
    构建之法阅读笔记06
    第二阶段个人工作总结(10)
    学习进度条(十四周)
    第二阶段个人工作总结(9)
    SapringMVC的文件上传下载以及拦截器
    Servlet的请求
    Servlet 的生命周期
    IO流
    set接口
  • 原文地址:https://www.cnblogs.com/gg128/p/9826130.html
Copyright © 2011-2022 走看看