技術是須要積累的。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異常處理體系