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;
        }
    }
    
  • 相关阅读:
    使用JDBC连接MySql时出现:The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration
    Mysql Lost connection to MySQL server at ‘reading initial communication packet', system error: 0
    mysql-基本命令
    C# 监听值的变化
    DataGrid样式
    C# 获取当前日期时间
    C# 中生成随机数
    递归和迭代
    PHP 时间转几分几秒
    PHP 根据整数ID,生成唯一字符串
  • 原文地址:https://www.cnblogs.com/gg128/p/9826130.html
Copyright © 2011-2022 走看看