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;
    }
}

 

posted @ 2018-10-21 18:26  fatale  阅读(233)  评论(0编辑  收藏  举报