zoukankan      html  css  js  c++  java
  • SpringBoot总结

    技术是需要积累的。

    一、日志

    spring boot内部使用Commons Logging来记录日志,但也保留外部接口可以让一些日志框架来进行实现,例如Java Util Logging,Log4J2还有Logback。如果你想用某一种日志框架来进行实现的话,就必须先配置,默认情况下,spring boot使用Logback作为日志实现的框架。

    1.显示debug级别的日志

    debug是打印信息最冗余的级别,其次是info,warn,error。在开发阶段,可能需要debug级别的日志,这可以通过如下两种方式实现:

    • 通过application.properites配置debug=true
    • 既然是更改的application.properties,那么肯定也能通过命令行来配置:
      java -jar C:UsersAdministratorDesktopxxdemo.jar --debug

    2.一份完美的配置

    logback.xml

    <!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
    <configuration scan="true" scanPeriod="10 seconds">
        <include resource="org/springframework/boot/logging/logback/base.xml"/>
    
        <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <File>${LOG_PATH}/info.log</File>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_PATH}/info-%d{yyyyMMdd}.log.%i</fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>10MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <maxHistory>2</maxHistory>
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n
                </Pattern>
            </layout>
        </appender>
    
        <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>ERROR</level>
            </filter>
            <File>${LOG_PATH}/error.log</File>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_PATH}/error-%d{yyyyMMdd}.log.%i
                </fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>10MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <maxHistory>2</maxHistory>
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n
    
                </Pattern>
            </layout>
        </appender>
        <root level="INFO">
            <appender-ref ref="INFO_FILE"/>
            <appender-ref ref="ERROR_FILE"/>
        </root>
    
    </configuration>
    

    在application.properties中,进行如下配置

    #log
    logging.config=classpath:logback.xml
    logging.path=${user.home}/poem-log
    

    3.最佳实践

    • 日志目录最好不要放在webapp中,而要放在其它文件夹中。
    • 日志配置最好单独一个文件进行配置,这样扩展性好、清晰。

    二、视图

    spring boot 在springmvc的视图解析器方面就默认集成了ContentNegotiatingViewResolver和BeanNameViewResolver,在视图引擎上就已经集成自动配置的模版引擎,如下:

    1. FreeMarker
    2. Groovy
    3. Thymeleaf
    4. Velocity (deprecated in 1.4)
    5. Mustache

    JSP技术spring boot 官方是不推荐的,原因有三:

    1. 在tomcat上,jsp不能在嵌套的tomcat容器解析即不能在打包成可执行的jar的情况下解析
    2. Jetty 嵌套的容器不支持jsp
    3. Undertow

    而其他的模版引擎spring boot 都支持,并默认会到classpath的templates里面查找模版引擎,这里假如我们使用freemarker模版引擎

    三、静态资源

    Spring Boot 默认配置的/**映射到/static(或/public/resources/META-INF/resources),/webjars/**会映射到classpath:/META-INF/resources/webjars/

    注意:上面的/static等目录都是在classpath:下面。

    静态资源映射还有一个配置选项,为了简单这里用.properties方式书写:
    spring.mvc.static-path-pattern=/** # Path pattern used for static resources.
    这个配置会影响默认的/**,例如修改为/static/**后,只能映射如/static/js/sample.js这样的请求(修改前是/js/sample.js)。这个配置只能写一个值,不像大多数可以配置多个用逗号隔开的。

    四、异常处理

    SpringBoot提供了健全的异常机制。异常处理分为三种:

    • 按照异常分类处理
    • 按照Controller分类处理
    • 全局异常处理

    1、使用@ResponseStatus定义异常的类型

    众所周知,Java中可以通过继承Exception自定义异常类型。在JavaWeb中还可以更进一步,异常可以分为很多种:

    • 404:页面不见了
    • 500:内部错误(这是一切异常的默认statusCode)
      ......

    使用SpringBoot可以通过注解来定义异常的种类,如下所以定义了一个“订单未找到”异常,这个异常的状态码是404

     @ResponseStatus(value=HttpStatus.NOT_FOUND, reason="No such Order")  // 404
     public class OrderNotFoundException extends RuntimeException {
         // ...
     }
    

    使用这个异常时,如下写法:直接抛出这个异常就行了。

     @RequestMapping(value="/orders/{id}", method=GET)
     public String showOrder(@PathVariable("id") long id, Model model) {
         Order order = orderRepository.findOrderById(id);
    
         if (order == null) throw new OrderNotFoundException(id);
    
         model.addAttribute(order);
         return "orderDetail";
     }
    

    2、使用@ExceptionHandler处理某个Controller内的异常

    在一个Controller中,使用@RequestMapping注解某个函数,表示这个函数用来处理请求。使用@ExceptionHandler注解某个函数,表示这个函数用来处理@RequestMapping函数所抛出的异常。

    如下代码,在Controller中定义了三个ExceptionHandler,体会一下用法。

    @Controller
    public class ExceptionHandlingController {
    
      // @RequestHandler methods
      ...
      
      // Exception handling methods
      
      // Convert a predefined exception to an HTTP Status code
      @ResponseStatus(value=HttpStatus.CONFLICT,
                      reason="Data integrity violation")  // 409
      @ExceptionHandler(DataIntegrityViolationException.class)
      public void conflict() {
        // Nothing to do
      }
      
      // Specify name of a specific view that will be used to display the error:
      @ExceptionHandler({SQLException.class,DataAccessException.class})
      public String databaseError() {
        // Nothing to do.  Returns the logical view name of an error page, passed
        // to the view-resolver(s) in usual way.
        // Note that the exception is NOT available to this view (it is not added
        // to the model) but see "Extending ExceptionHandlerExceptionResolver"
        // below.
        return "databaseError";
      }
    
      // Total control - setup a model and return the view name yourself. Or
      // consider subclassing ExceptionHandlerExceptionResolver (see below).
      @ExceptionHandler(Exception.class)
      public ModelAndView handleError(HttpServletRequest req, Exception ex) {
        logger.error("Request: " + req.getRequestURL() + " raised " + ex);
    
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", ex);
        mav.addObject("url", req.getRequestURL());
        mav.setViewName("error");
        return mav;
      }
    }
    

    3、异常显示页面

    千万不要让用户看见异常的stacktrace,那样显得很不专业。但是调试的时候,可以直接显示异常栈。
    例如使用JSP:

      <h1>Error Page</h1>
      <p>Application has encountered an error. Please contact support on ...</p>
        
      <!--
        Failed URL: ${url}
        Exception:  ${exception.message}
            <c:forEach items="${exception.stackTrace}" var="ste">    ${ste} 
        </c:forEach>
      -->
    

    4、全局异常控制@ControllerAdvice

    使用@ControllerAdvice注解了的类相当于拦截器,把Controller的请求处理前、请求处理后、请求有异常的时候分别进行处理。
    使用@ControllerAdvice注解的类功能可以包含@ModelAttribute,@ExceptionHandler
    ,@InitBinder。但是只需要了解@ExceptionHandler注解即可,别的都用不上。

    @ControllerAdvice
    class GlobalControllerExceptionHandler {
        @ResponseStatus(HttpStatus.CONFLICT)  // 409
        @ExceptionHandler(DataIntegrityViolationException.class)
        public void handleConflict() {
            // Nothing to do
        }
    }
    

    可以定义一个全局的处理一切异常的函数:

    @ControllerAdvice
    class GlobalDefaultExceptionHandler {
      public static final String DEFAULT_ERROR_VIEW = "error";
    
      @ExceptionHandler(value = Exception.class)
      public ModelAndView
      defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        // If the exception is annotated with @ResponseStatus rethrow it and let
        // the framework handle it - like the OrderNotFoundException example
        // at the start of this post.
        // AnnotationUtils is a Spring Framework utility class.
        if (AnnotationUtils.findAnnotation
                    (e.getClass(), ResponseStatus.class) != null)
          throw e;
    
        // Otherwise setup and send the user to a default error-view.
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", e);
        mav.addObject("url", req.getRequestURL());
        mav.setViewName(DEFAULT_ERROR_VIEW);
        return mav;
      }
    }
    

    5、优先级

    • 同一个异常被局部范围异常处理器和全局范围异常处理器同时覆盖,会选择小范围的局部范围处理器
    • 同一个异常被小范围的异常类和大范围的异常处理器同时覆盖,会选择小范围的异常处理器

    五、热部署

    使用devtools
    运行springBoot的两种方式:mvn run,springboot:run

    六、SpringBoot测试

    过去,我以为每个类都写一个main函数测试一下这个类就可以了。这种方式在使用Spring的情况下不好使,因为很多注解都没有发挥作用。

    使用Spring的代码,必须写测试,否则

    • application.properties文件不会正常加载。
    • 使用的@Autowired的成员变量都不会自动注入。

    写测试很简单,只需要用到三个注解:

    1. 用下面两个注解来注解测试类
    @SpringBootTest
    @RunWith(SpringJUnit4ClassRunner.class)
    
    1. @Test注解来注解测试方法

    下面看一个具体的例子,这个例子演示了多例的用法。

    在Spring中,使用Component注解的类相当于一个“Bean”,像Controller本身也是Component。使用Component注解的类默认都是单例,即@Scope("singleton"),如果改成多例,可以通过@Scope("prototype")注解来实现。

    下面定义了一个类Config,这个类有一个成员变量token。如果Config是单例,会发现config2跟config指向同一个对象;如果Config是多例,会发现config和config2互不影响。

    @SpringBootTest
    @RunWith(SpringJUnit4ClassRunner.class)
    public class SingletonTest {
    @Autowired Config config;
    @Autowired Config config2;
    @Test
    public void go(){
       System.out.println(config.getToken());
       System.out.println(config2.getToken());
       config2.setToken("haha");
       System.out.println(config.getToken());
    }
    }
    

    注意一个知识点,在SpringBoot中,Controller默认是单例
    对于只包含静态方法的类,完全可以用单例来替代。
    即便不使用Web,也可以使用Spring的单例、多例、注入等机制。

    参考资料

    打不死的小强
    深入学习微框架SpringBoot

    http://jinnianshilongnian.iteye.com/blog/1866350 开涛的@ControllerAdvice(三个作用)
    http://www.tuicool.com/articles/fA7nuii springboot约定的异常处理体系
    https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc springMVC异常处理体系
    这篇博客提供了一个github代码,用到thymleaf,是挺好的SpringMVC入门资料。

    http://www.baeldung.com/2013/01/31/exception-handling-for-rest-with-spring-3-2/ springMVC异常处理体系

  • 相关阅读:
    Hive 使用问题集锦
    scala def/val/lazy val区别以及call-by-name和call-by-value
    spark学习流程
    Hadoop
    Hive
    Chrome快捷键
    Java API帮助文档
    Java 访问修饰符与非访问修饰符
    java 关键字
    Solr配置Ikanalyzer分词器
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/6818783.html
Copyright © 2011-2022 走看看