SpringBoot学习(一)

SpringBoot简介

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
Spring Boot特点:
1. 遵循“习惯优于配置”的原则,使用Spring Boot只需很少的配置,大部分时候可以使用默认配置。
2. 项目快速搭建,可无配置整合第三方框架。
3. 可完全不使用xml配置,只使用自动配置和Java config。
4. 内嵌Servlet容器(如Tomcat),应用可用jar包运行(java-jar)。
5. 运行中应用状态的监控。

SpringBoot基础

pom文件

    <!-- springboot的父目录,包含大量默认配置,简化开发 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath />
    </parent>

  <properties>
    <!-- 编码 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!-- jdk版本 -->
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <!-- junit测试依赖包 -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
    <!-- springboot的web支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- springboot测试 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- springboot热启动工具 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
        <!-- springboot插件 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
  </build>

代码示例

    /**
     * 用户控制器
     */
    @RestController
    @RequestMapping("/user")
    public class UserController {

        @Value(value="${aric.secret}")
        private String secret;
        @Value(value="${aric.number}")
        private int id;
        @Value(value="${aric.desc}")
        private String desc;

        @RequestMapping
        public String index(){
            return "hello world !";
        }

        //@RequestParam 简单类型的绑定
        @RequestMapping("/get")
        public Map<String,Object> get(@RequestParam String name){
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("title", "spring boot");
            map.put("name", name);
            map.put("secret", secret);
            map.put("id", id);
            map.put("desc", desc);
            return map;
        }

        // @PathVariable 获取请求url中的动态参数
        @RequestMapping("/get/{id}/{name}")
        public User getUser(@PathVariable int id, @PathVariable String name){
            User user = new User();
            user.setId(id);
            user.setName(name);
            user.setDate(new Date());
            return user;
        }
    }

/**
 * SpringBoot 启动
 */
@SpringBootApplication
public class App {

    public static void main( String[] args ){
        SpringApplication.run(App.class, args);
    }
}

/**
 * springboot测试类
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class AppTest {

    private MockMvc mvc;

    @Before
    public void setUp(){
        this.mvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
    }

    @Test
    public void contextLoads() throws Exception{
        RequestBuilder request = get("/user");
        mvc.perform(request).andExpect(status().isOk()).andExpect(content().string("hello world !"));

        request = get("/user/get").param("name","张三");
        mvc.perform(request).andExpect(status().isOk()).andExpect(content().string("{\"author\":\"张三\",\"title\":\"spring boot\"}"));
    }
}

运行项目:
直接运行main方法或者使用maven命令: spring-boot:run

配置文件

一、配置文件的生效顺序,会对值进行覆盖:
1. @TestPropertySource 注解
2. 命令行参数
3. Java系统属性(System.getProperties())
4. 操作系统环境变量
5. 只有在random.*里包含的属性会产生一个RandomValuePropertySource
6. 在打包的jar外的应用程序配置文件(application.properties,包含YAML和profile变量)
7. 在打包的jar内的应用程序配置文件(application.properties,包含YAML和profile变量)
8. 在@Configuration类上的@PropertySource注解
9. 默认属性(使用SpringApplication.setDefaultProperties指定)

二、配置随机值:
#32位随机字符串
aric.secret=${random.value}
#int类型的随机数字
aric.number= random.int使@Value(value= {aric.secret}”)
private String secret;

三、属性占位符
当application.properties里的值被使用时,它们会被存在的Environment过滤,所以你能够引用先前定义的值(比如,系统属性)。

aric.name=www.aric.com
`#`属性占位符属性
aric.desc=the domain is ${aric.name}

四、Application属性文件,按优先级排序,位置高的将覆盖位置低的
1. 当前目录下的一个/config子目录
2. 当前目录
3. 一个classpath下的/config包
4. classpath根路径(root)

五、服务端口和其他配置
#端口配置:
server.port=8090
#时间格式化
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
#时区设置
spring.jackson.time-zone=Asia/BeiJing

六、使用YAML代替Properties

    #配置文件环境配置
    spring:
      profiles:
        active: dev

      #jackson
      jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: Asia/Chongqing

    #端口
    server: 
      port: 8888

    ---
    spring:
      profiles: dev
    server:
      port: 8080

    ---
    spring:
      profiles: prod
    server:
      port: 8082

    ---
    spring:
      profiles: test
    server:
      port: 8081

多环境配置

一. 多环境配置的好处:
1.不同环境配置可以配置不同的参数
2.便于部署,提高效率,减少出错

二. Properties多环境配置
1. 配置激活选项,主配置文件配置这个会优先读取里面的属性覆盖主配置文件的属性
spring.profiles.active=dev
2.添加其他配置文件
application-dev.properties
application-prod.properties
application-test.properties
三.YAML多环境配置
1.配置激活选项
spring:
profiles:
active: dev
2.在配置文件添加三个英文状态下的短横线即可区分
---
spring:
profiles: dev

四.两种配置方式的比较
1.Properties配置多环境,需要添加多个配置文件,YAML只需要一个配件文件
2.书写格式的差异,yaml相对比较简洁,优雅
3.YAML的缺点:不能通过@PropertySource注解加载。如果需要使用@PropertySource注解的方式加载值,那就要使用properties文件。

五.使用对应的环境

java -jar myapp.jar --spring.profiles.active=dev

配置日志

支持日志框架:Java Util Logging, Log4J2 and Logback,默认是使用logback
配置方式:默认配置文件配置和引用外部配置文件配置
一、 默认配置文件配置(不建议使用:不够灵活,对log4j2等不够友好)
# 日志文件名,比如:aric.log,或者是 /var/log/aric.log
logging.file=aric.log
# 日志级别配置,比如: logging.level.org.springframework=DEBUG
logging.level.*=info
logging.level.org.springframework=DEBUG

二、 引用外部配置文件
2.1 logback配置方式:
spring boot默认会加载classpath:logback-spring.xml或者classpath:logback-spring.groovy
使用自定义配置文件,配置方式为:
logging.config=classpath:logback-aric.xml
注意:不要使用logback这个来命名,否则spring boot将不能完全实例化

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!-- 文件输出格式 -->
    <property name="PATTERN" value="%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) |-%-5level [%thread] %c [%L] -| %msg%n" />
    <!-- test文件路径 -->
    <property name="TEST_FILE_PATH" value="e:/develop/logs" />
    <!-- pro文件路径 -->
    <property name="PRO_FILE_PATH" value="/develop/aric/logs" />

    <!-- 开发环境 -->
    <springProfile name="dev">
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>${PATTERN}</pattern>
            </encoder>
        </appender>

        <logger name="com.roncoo.education" level="debug"/>

        <root level="info">
            <appender-ref ref="CONSOLE" />
        </root>
    </springProfile>

    <!-- 测试环境 -->
    <springProfile name="test">
        <!-- 每天产生一个文件 -->
        <appender name="TEST-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 文件路径 -->
            <file>${TEST_FILE_PATH}</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 文件名称 -->
                <fileNamePattern>${TEST_FILE_PATH}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
                <!-- 文件最大保存历史数量 -->
                <MaxHistory>100</MaxHistory>
            </rollingPolicy>

            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${PATTERN}</pattern>
            </layout>
        </appender>

        <root level="info">
            <appender-ref ref="TEST-FILE" />
        </root>
    </springProfile>

    <!-- 生产环境 -->
    <springProfile name="prod">
        <appender name="PROD_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${PRO_FILE_PATH}</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${PRO_FILE_PATH}/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
                <MaxHistory>100</MaxHistory>
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${PATTERN}</pattern>
            </layout>
        </appender>

        <root level="warn">
            <appender-ref ref="PROD_FILE" />
        </root>
    </springProfile>
</configuration>

2.2 log4j配置
1. 去除logback的依赖包,添加log4j2的依赖包
2. 在classpath添加log4j2.xml或者log4j2-spring.xml(spring boot 默认加载)
3. 自定义配置文件

SpringBoot自定义配置Json转换器

引入fastJson的maven依赖

    <!-- fastJson依赖 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.15</version>
    </dependency>

第一种方式,继承WebMvcConfigurerAdapter,重写configureMessageConverters方法。

    public class AricApplication extends WebMvcConfigurerAdapter {

        /**
         * 自定义json转换器
         */
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            super.configureMessageConverters(converters);
            //1.定义一个converter转换消息对象
            FastJsonHttpMessageConverter fjhmc = new FastJsonHttpMessageConverter();
            //2.fastjson配置信息
            FastJsonConfig jsonConfig = new FastJsonConfig();
            //添加配置信息
            jsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
            //3.在conver中添加配置信息
            fjhmc.setFastJsonConfig(jsonConfig);
            //4.将converter添加到converters中
            converters.add(fjhmc);
        }
    }   

第二种方式,使用@Bean注解注入fastjsonHttpMessageConverter。

     /**
     * 自定义json转换器
     * 使用@Bean注入fastjsonHttpMessageConverter
     * @param args
     */
    @Bean
    public HttpMessageConverters fastJsonHttpMessage(){
        //1.定义一个converter转换消息对象
        FastJsonHttpMessageConverter jsonConverter = new FastJsonHttpMessageConverter();
        //2.fastjson配置信息
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        jsonConverter.setFastJsonConfig(fastJsonConfig);
        HttpMessageConverter<?> converter = jsonConverter;
        return new HttpMessageConverters(converter);
    }

SpringBoot核心

SpringBoot注解

@SpringBootApplication注解是Spring Boot的核心注解,该注解主要组合了以下注解:
1. @SpringBootConfiguration:这是Spring Boot项目的配置注解,这也是一个组合注解。在Spring Boot项目中推荐使用@ SpringBootConfiguration替代@Configuration。
2. @EnableAutoConfiguration:启用自动配置,该注解会使Spring Boot根据项目中依赖的jar包自动配置项目的配置项。如添加了spring-boot-starter-web的依赖,项目中也就会引入SpringMVC的依赖,Spring Boot就会自动配置tomcat和SpringMVC。
3. @ComponentScan:默认扫描@SpringBootApplication所在类的同级目录以及它的子目录。

关闭自动配置

Spring Boot会根据项目中的jar包依赖,自动做出配置,如果不需要自动配置可手动关闭。

//启动类
@SpringBootApplication(exclude={MongoAutoConfiguration.class})//关闭Mongo自动配置
public class AricApplication{

}
自定义Banner

将banner.txt拷贝到项目的resources目录中可自定义banner。
设置关闭banner

    public class Main {

        public static void main( String[] args ) throws SchedulerException, InterruptedException{

            SpringApplication app =  new SpringApplication(AricApplication.class);
            //设置关闭Banner
            app.setBannerMode(Banner.Mode.OFF);
            app.run(args);  
        }
    }
全局配置文件
  1. 修改tomcat的端口:server.port=8003
  2. 修改进入DispatcherServlet的规则:server.servlet-path=*.do
  3. 更多配置可参考官方文档
加载xml配置

实际项目中,可能有一些需要必须加载xml配置,可以通过spring提供的@ImportResource来加载xml配置。

    @ImportResource({"classpath:logback-dev.xml","classpath:logback-test.xml"})

日志

Spring Boot对各种日志框架都做了支持,我们可以通过配置来修改默认的日志的配置。上面多配置文件方式可以根据环境选择日志输出方式。
设置日志输出级别:

    logging.level.org.springframework=DEBUG

Spring Boot的自动配置的原理

Spring Boot在进行SpringApplication对象实例化时会加载META-INF/spring.factories文件,将该配置文件中的配置载入到Spring容器。

条件注解


SpringBoot异常处理

一、Spring Boot 将所有的错误默认映射到/error, 实现ErrorController

    @Controller
    @RequestMapping(value = "/error")
    public class BaseErrorController implements ErrorController {

        private static final Logger logger = LoggerFactory.getLogger(BaseErrorController.class);

        @Override
        public String getErrorPath() {
            logger.info("出错,错误异常处理器!");
            return "error/error";
        }

        @RequestMapping
        public String error(){
            return getErrorPath();
        }

    }

方法二:添加自定义的错误页面
2.1 html静态页面:在resources/public/error/ 下定义
如添加404页面: resources/public/error/404.html页面,中文注意页面编码
2.2 模板引擎页面:在templates/error/下定义
如添加500页面: templates/error/500.ftl
注意事项:templates/error/ 这个的优先级比较 resources/public/error/高

方法三:使用注解@ControllerAdvice

    /**
     * 异常消息处理类
     */
    @ControllerAdvice
    public class GlobalDefaultExceptionHandler {

        private static final Logger logger = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class);

        @ExceptionHandler(RuntimeException.class)
        @ResponseBody
        public String defaultExceptionHandler(HttpServletRequest req,Exception e){
            logger.error("自定义异常-RuntimeException");
            return "该功能出现异常!";
        }

        @ExceptionHandler(Exception.class)
        @ResponseStatus(HttpStatus.OK)
        public ModelAndView doExceptionHandler(HttpServletRequest req,Exception e){
            logger.error("自定义异常-Exception");
            ModelAndView mav = new ModelAndView();
            mav.addObject("aricException", e.getMessage());
            mav.setViewName("exception/500");
            return mav;
        }
    }

SpringBoot的Web开发

一.spring boot的web应用开发,是基于spring mvc
二.Spring boot 在spring默认基础上,自动配置添加了以下特性:
1. 包含了ContentNegotiatingViewResolver和BeanNameViewResolver beans。
2. 对静态资源的支持,包括对WebJars的支持。
3. 自动注册Converter,GenericConverter,Formatter beans。
4. 对HttpMessageConverters的支持。
5. 自动注册MessageCodeResolver。
6. 对静态index.html的支持。
7. 对自定义Favicon的支持。
8. 主动使用ConfigurableWebBindingInitializer bean

三.模板引擎的选择
FreeMarker
Thymeleaf
Velocity (1.4版本之后弃用,Spring Framework 4.3版本之后弃用)
Groovy
Mustache
jsp应该尽量避免使用,原因如下:
1. jsp只能打包为:war格式,不支持jar格式,只能在标准的容器里面跑(tomcat,jetty都可以)
2. 内嵌的Jetty目前不支持JSPs
3. Undertow不支持jsps
4. jsp自定义错误页面不能覆盖spring boot 默认的错误页面

模板引擎FreeMarker

一.FreeMarker Maven 依赖

    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>

二. application.properties 中配置

#freemarker 配置
spring.freemarker.allow-request-override=false
spring.freemarker.cache=true
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false

三. 代码示例

    @Controller
    @RequestMapping("/templates")
    public class TemplatesController {

        /**
         * 访问ftl文件
         * @return
         */
        @RequestMapping("/hello")
        public String hello(Map<String,Object> map){
            map.put("name", "curry");
            return "hello";
        }
    }

resource下的templates中hello.ftl文件

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    </head>
    <body>
        <h1>Hello,${name} !</h1>
    </body>
    </html>

模板引擎Thymeleaf

一. maven 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

二. application.properties配置

    #thymeleaf 配置
    #开发过程建议关闭缓存
    #spring.thymeleaf.cache=false

三. 代码示例

    @Controller
    @RequestMapping("/templates")
    public class TemplatesController {

        /**
         * 访问html页面
         * @return
         */
        @RequestMapping("/index")
        public String index(Map<String,Object> map){
            map.put("name", "james");
            return "index";
        }

    }

resource下的templates中index.html文件

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    </head>
    <body>
        <h1>Hello,thymeleaf !</h1>
        <br/>
        welcome <span th:text="${name}"></span>
    </body>
    </html>

模板引擎jsp

一. maven依赖

<!-- servlet -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <scope>provided</scope>
</dependency>
<!-- jstl -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>
<!-- 内嵌的tamcat不支持jsp页面 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>

二. application.properties配置

#jsp 配置
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

三. 代码示例

    @Controller
    @RequestMapping("/testJsp")
    public class JspController {

        @RequestMapping("/demo")
        public String test(Map<String,Object> map){
            map.put("name", "messi");
            return "demo";
        }
    }

webapp下的WEB-INF下的jsp文件中demo.jsp文件

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>jsp demo</title>
</head>
<body>
    <h2>hello ${name } !</h2>
</body>
</html>

资源路径和配置文件

Web开发的自动配置类:org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration自动配置ViewResolver。
自动配置静态资源:
如果进入SpringMVC的规则为/时,Spring Boot的默认静态资源的路径为:

#配置进入sprngmvc规则
server.servlet-path=/
#静态资源路径
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/

进入规则为*.xxx 或者 不指定静态文件路径时,将静态资源放置到webapp下的static目录中即可通过地址访问。

读取外部的配置文件:

    @PropertySource(value = {"classpath:jdbc.properties", "classpath:env.properties",
    "classpath:httpclient.properties", "classpath:redis.properties", "classpath:rabbitmq.properties" }, 
    ignoreResourceNotFound = true) //读取外部配置文件,如果不存在则忽略
    @ComponentScan(basePackages = "cn.aric") //扫描包
    public class AricApplication {

自定义消息转换器

自定义消息转化器,只需要在@Configuration的类中添加消息转化器的@bean加入到Spring容器,就会被Spring Boot自动加入到容器中。

    /**
     * 自定义消息转换器
     * @return
     */
    @Bean
    public StringHttpMessageConverter stringHttpMessageConverter(){
        StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
        return converter;
    }

SpringBoot整合Servlets、Filters、listeners

自定义Servlet、Filter、Listener

    @WebServlet
    public class CustServlet extends HttpServlet {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("servlet get method");
            doPost(req,resp);
        }

        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("servlet post method");
            resp.getWriter().write("hello world");
        }

    }

    /**
     * 自定义过滤器
     */
    @WebFilter
    public class CustFilter implements Filter {

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("init filter");
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            System.out.println("do filter");
            chain.doFilter(request, response);
        }

        @Override
        public void destroy() {
            System.out.println("destory filter");
        }

    }

    /**
     * 自定义监听器
     */
    @WebListener
    public class CustListener implements ServletContextListener {

        @Override
        public void contextInitialized(ServletContextEvent sce) {
            System.out.println("contextInitialized");
        }

        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            System.out.println("contextDestroyed");
        }

    }

方法一:通过注册ServletRegistrationBean、 FilterRegistrationBean 和 ServletListenerRegistrationBean 获得控制

    /**
     * 注入自定义servlet
     * @return
     */
    @Bean
    public ServletRegistrationBean servletRegistrationBean(){
        return new ServletRegistrationBean(new CustServlet(),"/aric");
    }

    /**
     * 注入自定义过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        return new FilterRegistrationBean(new CustFilter(), servletRegistrationBean());
    }

    /**
     * 注入自定义监听器
     * @return
     */
    @Bean
    public ServletListenerRegistrationBean<CustListener> servletListenerRegistrationBean(){
        return new ServletListenerRegistrationBean<CustListener>(new CustListener());
    }       

方法二:通过实现 ServletContextInitializer 接口直接注册

    /**
     * 实现ServletContainerInitializer实现注册 servlet、filter、listener
     */
    public class MyServletcontainerInitializer implements ServletContainerInitializer{

        @Override
        public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
            //注册自定义servlet
            ctx.addServlet("custServlet", new CustServlet()).addMapping("/aric");
            //注册自定义filter
            ctx.addFilter("custFilter", new CustFilter()).
                addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), true, "custFilter");
            //注册自定义listener
            ctx.addListener(new CustListener());
        }

    }

方法三:在 SpringBootApplication 上使用@ServletComponentScan 注解后,直接通过@WebServlet、@WebFilter、@WebListener 注解自动注册

SpringBoot自定义拦截器

    /**
     * 自定义拦截器
     */
    @Component
    public class UserLoginHandlerInterceptor implements HandlerInterceptor {

        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            System.out.println("登陆拦截器...");
            return false;
        }

        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {

        }

        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {

        }

    }

    /**
     * 注册自定义拦截器
     */
    @Configuration
    public class SpringMvcConfig extends WebMvcConfigurerAdapter{

        //注入用户登陆拦截器
        @Autowired
        private UserLoginHandlerInterceptor userLoginHandlerInterceptor;

        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //判断用户是否登陆的拦截器
            registry.addInterceptor(userLoginHandlerInterceptor).addPathPatterns("/user/**");
        }
    }

CORS支持 ###

一、Web开发经常会遇到跨域问题,解决方案有:jsonp,iframe,CORS等等
CORS与JSONP相比:
1、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
2、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
3、 JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS

二、在spring MVC 中可以配置全局的规则,也可以使用@CrossOrigin注解进行细粒度的配置。

    /**
     * Cors全局配置
     */
    @Configuration
    public class CustCorsConfiguration {

        @Bean
        public WebMvcConfigurerAdapter corsConfigurer(){
            return new WebMvcConfigurerAdapter() {

                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/api/**").allowedOrigins("http://127.0.0.1:8002");
                }

            };
        }
    }

或者

    /**
     * Cors自定义全局配置
     */
    @Configuration
    public class CustomCorsConfiguration extends WebMvcConfigurerAdapter{

        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/api/**").allowedOrigins("http://127.0.0.1:8002");
        }

    }

定义方法:

    /**
     * api控制器,定义方法
     */
    @RestController
    @RequestMapping("/api")
    public class ApiController {

        @RequestMapping("/get")
        public Map<String,Object> get(@RequestParam String name){
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("title", "spring boot");
            map.put("name", name);
            return map;
        }
    }

细粒度控制:

    /**
     * @CrossOrigin 进行Cors细粒度控制
     */
    @RestController
    @RequestMapping(value = "/api",method=RequestMethod.POST)
    public class ApiThinController {

        @CrossOrigin(origins="http://localhost:8002")
        @RequestMapping("/get")
        public Map<String,Object> get(@RequestParam String name){
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("title", "spring");
            map.put("name", name);
            return map;
        }
    }

文件上传

一、Spring Boot 默认使用springMVC包装好的解析器进行上传
二、配置

#上传文件配置
#默认支持文件上传
spring.http.multipart.enabled=true
#支持文件写入磁盘
spring.http.multipart.file-size-threshold=0
#上传文件的临时目录
spring.http.multipart.location=
#最大支持文件大小
spring.http.multipart.max-file-size=1Mb
#最大支持请求大小
spring.http.multipart.max-request-size=10Mb

三、代码示例
jsp文件夹下的upload.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>文件上传测试</title>
    </head>
    <body>
        <div>
            <form method="post" enctype="multipart/form-data" action="/file/upload">
                文件:<input type="file" name="aricFile"><br>
                <input type="submit" value="上传">
            </form>
        </div>
    </body>
    </html>

上传文件后台处理代码:

    /**
     * 文件Contrller
     */
    @Controller
    @RequestMapping("/file")
    public class FileController {

        private static Logger logger = LoggerFactory.getLogger(FileController.class);

        @RequestMapping("/toPage")
        public String toPage(){
            return "upload";
        }

        @RequestMapping("/upload")
        @ResponseBody
        public String upload(@RequestParam("aricFile") MultipartFile file){
            if (file.isEmpty()) {
                return "文件为空!";
            }
            //获取文件名
            String filename = file.getOriginalFilename();
            logger.info("上传文件名称: " + filename);

            //获取文件后缀名
            String suffixName = filename.substring(filename.lastIndexOf("."));
            logger.info("文件后缀名: " + suffixName);

            //上传文件地址
            String filePath = "e:/develop/temp/";

            //文件名称加密
            filename = UUID.randomUUID() + suffixName;

            //目标文件
            File dest = new File(filePath,filename);

            //检查是否存在目录
            if(!dest.getParentFile().exists()){
                dest.getParentFile().mkdirs();
            }

            try {
                file.transferTo(dest);
                return "上传成功!";
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "上传失败!";
        }
    }

SpringBoot的数据访问

SpringBoot集成Spring Data Jpa

引入Maven依赖

    <!-- mysql数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- spring-data-jpa -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

实现接口:

    /**
     * 继承CrudRepository,具有增删查功能
     */
    public interface CatDao extends CrudRepository<Cat,Integer>{

    }

    /**
     * 继承PagingAndSortingRepository,具有分页和排序功能
     */
    public interface CatsDao extends PagingAndSortingRepository<Cat,Integer>{

        public Cat findByName(String name);

        @Query(" from Cat where age=:a")
        public List<Cat> findByAge(@Param("a") Integer age);

    }

SpringBoot中使用JdbcTemplate

引入Maven依赖

<!-- jdbc依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

代码:

    @Repository
    public class PersonDao {

        @Autowired
        private JdbcTemplate jdbcTemplate;

        public void save(Person person){
            if (null != person) {
                String sql = "insert into person(name,birth_day,remark) values(";
                if (!StringUtils.isEmpty(person.getName())) {
                    sql += "'" + person.getName() +  "',";
                }
                if (null != person.getBirthDay()) {
                    sql += person.getBirthDay() + ",";
                }
                if (!StringUtils.isEmpty(person.getName())) {
                    sql += "'" + person.getRemark() + "',";
                }
                if (sql.endsWith(",")){
                    sql = sql.substring(0, sql.length()-1);
                }
                sql += ")";
                jdbcTemplate.execute(sql);
            }

        }
    }

SpringBoot集成MyBatis

引入mybatis和分页工具的Maven依赖

<!-- mybatis依赖 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.1.1</version>
</dependency>
<!-- mybatis分页工具依赖 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.1.0</version>
</dependency>

代码配置:

    /**
     * MyBatis配置
     */
    @Configuration
    public class MyBatisConfig {

        /**
         * 注入分页工具
         * @return
         */
        @Bean
        public PageHelper pageHelper(){
            System.out.println("MyBatisConfig.PageHelper");
            PageHelper pageHelper = new PageHelper();
            Properties properties = new Properties();
            properties.setProperty("offsetAsPageNum", "true");
            properties.setProperty("rowBoundsWithCount", "true");
            properties.setProperty("reasonable", "true");
            pageHelper.setProperties(properties);
            return pageHelper;
        }
    }

    /**
     * Mapper文件配置
     */
    @Configuration
    @AutoConfigureAfter(MyBatisConfig.class) //保证在MyBatisConfig实例化之后再实例化该类
    public class MapperConfig {


    }

在启动类上添加注解扫描mapper

    @SpringBootApplication
    @MapperScan("cn.aric.*.mapper") //扫描该包下响应的class,Mybatis的持久化类
    public class AricApplication{

    }

Mapper文件

    /**
     * Cat实体的mapper文件
     */
    public interface CatMapper {

        //#{name}命名占位符
        @Select("select * from Cat where name = #{name} ")
        public List<Cat> getByName(String name);

        /**
         * 保存操作
         * @param cat
         */
        @Insert("insert into Cat(name) values(#{name})")
        @Options(useGeneratedKeys=true,keyProperty="id",keyColumn="id")//设置id自增长
        public void save(Cat cat);
    }

service略

controller代码

    @RestController
    public class MyCatController {

        @Autowired
        private MyCatService myCatService;

        @RequestMapping("/getByName")
        public List<Cat> getByName(String name){
            //设置分页
            PageHelper.startPage(1, 2);
            return myCatService.getByName(name);
        }
    }

事务管理

引入maven依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

当引入jdbc依赖之后,SpringBoot会自动默认分别注入DataSourceTransactionManager或JpaTransactionManager,所以我们不需要任何额外配置就可以用@Transactional注解进行事务的使用。
@Transactional不仅可以注解在方法上,也可以注解在类上。注解在类上时,此类的所有public方法都是开启事务的。如果类级别和方法级别同时使用@Transactional注解,则使用在方法级别的注解会重载类级别的注解。

SpringBoot整合Druid连接池

引入maven依赖

<!-- druid连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.18</version>
</dependency>

配置文件,只写了部分,详细参考druid资料

    #指定mysql数据库连接消息
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
    spring.datasource.username=root
    spring.datasource.password=123
    spring.datasource.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.max-active=20
    spring.datasource.max-idle=8
    spring.datasource.min-idle=8
    spring.datasource.initial-size=10
    # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    spring.datasource.filters=stat,wall,log4j
    # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
    spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
    # 合并多个DruidDataSource的监控数据
    #spring.datasource.useGlobalDataSourceStat=true

配置过滤器

    @SpringBootApplication
    public class AricApplication extends SpringBootServletInitializer{

        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            //设置启动类,用于独立tomcat运行的入口
            return builder.sources(AricApplication.class);
        }

        @Bean
        public FilterRegistrationBean fileterRegistrationBean(){
            FilterRegistrationBean filter = new FilterRegistrationBean();
            filter.setFilter(new WebStatFilter());
            filter.setName("druidWebStatFilter");
            filter.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*");  
            filter.addUrlPatterns("/");
            return filter;
        }

        @Bean
        public ServletRegistrationBean servletRegistrationBean(){
            ServletRegistrationBean servlet = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
            servlet.setName("druidStatViewServlet");
            servlet.addInitParameter("restEnable", "false");
            return servlet;
        }
    }

访问url:http://ip地址:端口号/druid/

SpringBoot开发部署

SpringBoot热部署

第一种方式,springloader插件。

    <!-- springloader plugin -->
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <dependencies>
            <!-- springloaded hot deploy -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
                <version>1.2.4.RELEASE</version>
            </dependency>
        </dependencies>
        <executions>
            <execution>
                <goals>
                    <goal>repackage</goal>
                </goals>
                <configuration>
                    <classifier>exec</classifier>
                </configuration>
            </execution>
        </executions>
    </plugin>

第二种方式,devtools工具。

    <!-- devtools依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
        <scope>true</scope>
    </dependency>

    <!-- spring boot devtools plugin -->
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <!-- fork:没有配置,应用不会restart -->
            <fork>true</fork>           
        </configuration>
    </plugin>

修改tomcat

 /**
 * 修改tomcat配置
 * @return
 * @throws SchedulerException 
 * @throws InterruptedException 
 */
@Bean
public EmbeddedServletContainerFactory servletContainer(){
    TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
    factory.setPort(8001);
    factory.setSessionTimeout(10,TimeUnit.SECONDS);
    factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,"/notfound.html"));
    return factory;
}

将spring-boot-starter-tomcat的范围设置为provided,设置为provided是在打包时会将该包排除,因为要放到独立的tomcat中运行,是不需要的。

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

设置启动配置

集成SpringBootServletInitializer,然后重写configure,将Spring Boot的入口类设置进去。

    @SpringBootApplication
    public class AricApplication extends SpringBootServletInitializer{

        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            //设置启动类,用于独立tomcat运行的入口
            return builder.sources(AricApplication.class);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值