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:\Users\Administrator\Desktop\xx\demo.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异常处理体系

转载于:https://www.cnblogs.com/weiyinfu/p/6818783.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值