技术是须要积累的。html
spring boot内部使用Commons Logging来记录日志,但也保留外部接口可让一些日志框架来进行实现,例如Java Util Logging,Log4J2还有Logback。若是你想用某一种日志框架来进行实现的话,就必须先配置,默认状况下,spring boot使用Logback做为日志实现的框架。java
debug是打印信息最冗余的级别,其次是info,warn,error。在开发阶段,可能须要debug级别的日志,这能够经过以下两种方式实现:git
logback.xmlgithub
<!-- 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中,进行以下配置web
#log logging.config=classpath:logback.xml logging.path=${user.home}/poem-log
spring boot 在springmvc的视图解析器方面就默认集成了ContentNegotiatingViewResolver和BeanNameViewResolver,在视图引擎上就已经集成自动配置的模版引擎,以下:spring
JSP技术spring boot 官方是不推荐的,缘由有三:spring-mvc
而其余的模版引擎spring boot 都支持,并默认会到classpath的templates里面查找模版引擎,这里假如咱们使用freemarker模版引擎tomcat
Spring Boot 默认配置的/**
映射到/static
(或/public
,/resources
,/META-INF/resources
),/webjars/**
会映射到classpath:/META-INF/resources/webjars/
。springboot
注意:上面的/static
等目录都是在classpath:
下面。mvc
静态资源映射还有一个配置选项,为了简单这里用.properties方式书写:
spring.mvc.static-path-pattern=/** # Path pattern used for static resources.
这个配置会影响默认的/**
,例如修改成/static/**
后,只能映射如/static/js/sample.js
这样的请求(修改前是/js/sample.js
)。这个配置只能写一个值,不像大多数能够配置多个用逗号隔开的。
SpringBoot提供了健全的异常机制。异常处理分为三种:
@ResponseStatus
定义异常的类型众所周知,Java中能够经过继承Exception自定义异常类型。在JavaWeb中还能够更进一步,异常能够分为不少种:
使用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"; }
@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; } }
千万不要让用户看见异常的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> -->
@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; } }
使用devtools
运行springBoot的两种方式:mvn run,springboot:run
过去,我觉得每一个类都写一个main函数测试一下这个类就能够了。这种方式在使用Spring的状况下很差使,由于不少注解都没有发挥做用。
使用Spring的代码,必须写测试,不然
@Autowired
的成员变量都不会自动注入。写测试很简单,只须要用到三个注解:
@SpringBootTest @RunWith(SpringJUnit4ClassRunner.class)
@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的单例、多例、注入等机制。
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异常处理体系