若是進入SpringMVC的規則爲/時,Spring Boot的默認靜態資源的路徑爲:css
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
也就是說,在默認的Spring MVC進入規則下,classpath下的META-INF/resources目錄、resources目錄、static目錄和public目錄中的靜態資料是能夠直接經過 "http: // xxx.com/靜態資源" 的方式訪問到的。如:html
若是進入SpringMVC的規則爲*.xxx時(如:*.html),則上述目錄下的靜態資源將沒法直接訪問,須要將靜態資源放置到webapp下的static目錄中便可經過 "http://xxx.com/static/靜態資源" 訪問。此外,默認不配置SpringMVC的規則下也能夠如此訪問,也就是說這種訪問靜態資源的方式是通用的。如圖所示:前端
增長一個攔截器,須要經過繼承WebMvcConfigurerAdapter而後重寫父類中的方法進行擴展。java
@Configuration public class MySpringMvcConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { HandlerInterceptor handlerInterceptor = new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { System.out.println("自定義攔截器。。。"); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }; // 添加攔截器並設置攔截規則 registry.addInterceptor(handlerInterceptor).addPathPatterns("/**"); } }
自定義消息轉化器有兩種實現方式,一種是@Bean方式,另外一種是自定義攔截器。mysql
只須要在@Configuration的類中添加消息轉化器的@bean加入到Spring容器,就會被Spring Boot自動加入到容器中。git
// spring boot默認就有消息轉化器,其編碼格式爲utf-8 @Bean public StringHttpMessageConverter stringHttpMessageConverter() { StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8")); return stringHttpMessageConverter; }
WebMvcConfigurerAdapter的功能很強大,除了能夠配置攔截器外,還能夠配置消息轉換器。github
@Configuration public class MySpringMvcConfig extends WebMvcConfigurerAdapter { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8")); converters.add(stringHttpMessageConverter); } }
@Configuration @PropertySource(value = { "classpath:jdbc.properties", "classpath:base.properties" }, ignoreResourceNotFound = true) public class 任意類 { }
Druid提供了一個高效、功能強大、可擴展性好的數據庫鏈接池,經常使用於替換DBCP和C3P0。但在Spring Boot上配置比較「噁心」,這裏就簡單的貼出我的參照網上的配置代碼,沒必要深究。web
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.11</version> </dependency>
項目中通常會建立一個jdbc.properties文件來記錄數據庫的鏈接信息。正則表達式
#MySQL jdbc.url=jdbc:mysql://127.0.0.1:3306/dbxxx?useUnicode=true&characterEncoding=utf-8 jdbc.username=root jdbc.password=123456 #Druid jdbc.initialSize=0 jdbc.minIdle=0 jdbc.maxActive=150
建議將配置Druid數據源的操做放在@SpringBootApplication註解的類中。spring
@SpringBootApplication @Configuration @PropertySource(value = {"classpath:jdbc.properties"}) public class MyWebApplication{ @Value("${jdbc.url}") public String jdbcUrl; @Value("${jdbc.username}") public String jdbcUsername; @Value("${jdbc.password}") public String jdbcPassword; @Value("${jdbc.initialSize}") public int jdbcInitialSize; @Value("${jdbc.minIdle}") public int jdbcMinIdle; @Value("${jdbc.maxActive}") public int jdbcMaxActive; @Bean public ServletRegistrationBean druidServletRegistrationBean() { ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(); servletRegistrationBean.setServlet(new StatViewServlet()); servletRegistrationBean.addUrlMappings("/druid/*"); return servletRegistrationBean; } @Bean public FilterRegistrationBean duridFilterRegistrationBean() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new WebStatFilter()); HashMap<String, String> initParams = new HashMap<>(); // 設置忽略請求 initParams.put("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"); filterRegistrationBean.setInitParameters(initParams); filterRegistrationBean.addUrlPatterns("/*"); return filterRegistrationBean; } @Bean(initMethod = "init", destroyMethod = "close") public DruidDataSource druidDataSource() { DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setUrl(jdbcUrl); druidDataSource.setUsername(jdbcUsername); druidDataSource.setPassword(jdbcPassword); druidDataSource.setInitialSize(jdbcInitialSize); druidDataSource.setMinIdle(jdbcMinIdle); druidDataSource.setMaxActive(jdbcMaxActive); return druidDataSource; } }
以後就能夠經過@AutoWried註解獲得數據源(druidDataSource)了。
Jpa在使用上跟Hibernate很像,由於它們以前的關係非同通常,有興趣能夠看看《Hibernate與Jpa的關係,終於弄懂》這篇文章。Spring Boot對jpa的支持也是很好的,配置起來很是簡單。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1/dbgirl username: root password: 123456 jpa: hibernate: ddl-auto: update #第一次加載hibernate時根據model類會自動創建起表的結構(前提是先創建好數據庫),之後加載hibernate時根據 model類自動更新表結構,即便表結構改變了但表中的行仍然存在不會刪除之前的行。要注意的是當部署到服務器後,表結構是不會被立刻創建起來的,是要等 應用第一次運行起來後纔會。 show-sql: true
Mybatis和Spring Boot的整合有兩種方式:
第一種:使用mybatis官方提供的Spring Boot整合包實現,地址:spring-boot-starter
第二種:使用mybatis-spring整合的方式,也就是咱們傳統的方式
這裏推薦並使用第二種方式,由於能夠很方便的控制Mybatis的各類配置。這裏假設你已經配置過數據源了(數據源能夠是druid、dbcp、c3p0...)。
首先,須要在pom.xml文件中引用mybatis依賴
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.2.2</version> </dependency>
而後,建立一個Mybatis的配置類:
@Configuration public class MybatisConfig { @Autowired DruidDataSource druidDataSource; @Bean @ConditionalOnMissingBean// 當Spring容器中沒有SqlSessionFactoryBean時才建立 public SqlSessionFactoryBean sqlSessionFactoryBean() { SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean(); // 設置數據源 sqlSessionFactory.setDataSource(druidDataSource); // 設置別名掃描包 sqlSessionFactory.setTypeAliasesPackage("com.lqr.demo3.bean"); // 設置Mybatis的配置文件位置 PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource mybatisConfigXml = resolver.getResource("classpath:mybatis-config.xml"); sqlSessionFactory.setConfigLocation(mybatisConfigXml); return sqlSessionFactory; } }
最後,建立Mapper接口的掃描類MapperScannerConfig:
@Configuration @AutoConfigureAfter(MybatisConfig.class)// Mybatis的掃描配置必須在SqlSessionFactory被建立以後 public class MapperScanConfig { @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.lqr.demo3.mapper"); return mapperScannerConfigurer; } }
Spring Boot中推薦使用@Transactional註解來申明事務。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
當引入jdbc依賴以後,Spring Boot會自動默認分別注入DataSourceTransactionManager或JpaTransactionManager,因此咱們不須要任何額外配置就能夠用@Transactional註解進行事務的使用。
@Service @Transactional public class GirlService { @Transactional public void insertGirl() { Girl girlA = new Girl(); girlA.setCupSize("A"); girlA.setAge(18); girlRespository.save(girlA); } }
@Transactional不只能夠註解在方法,也能夠註解在類上。當註解在類上時,意味着此類全部public方法都會開啓事務。若是類級別和方法級別同時使用了@Transactional註解,則使用在類級別的註解會重載方法級別的註解。
Spring boot默認內嵌的tomcat是不支持jsp頁面的,若是項目中使用到了jsp,須要導入以下依賴才能正常訪問。
<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency>
這部分可能跟Spring Boot的關係並非很大(或者說,並不是Spring Boot特有),但很值得咱們在編碼方面做爲參考。
如今的Web項目已經愈來愈趨向於將後端與前端分別開發了,若是貴公司的項目就是使用json來進行先後端交互,且使用Spring MVC來開發的話,就必定會用到下面這2個註解:
@Controller @ResponseBody public class GirlController { ... }
而在Spring MVC4以後,咱們可使用@RestController 註解來開發基於Spring MVC4的REST風格的JSON服務。
通俗的說就是@RestController = @Controller + @ResponseBody。
@Controller和@RestController的區別:
若是隻是使用@RestController註解Controller,則Controller中的方法沒法返回jsp頁面,配置的視圖解析器InternalResourceViewResolver不起做用,返回的內容就是Return 裏的內容。 例如:原本應該到success.jsp頁面的,則其顯示success.
Spring4.3中引進了{@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping},來幫助簡化經常使用的HTTP方法的映射,並更好地表達被註解方法的語義。
@GetMapping => @RequestMapping(value = "/xxx",method = RequestMethod.GET) @PostMapping => @RequestMapping(value = "/xxx",method = RequestMethod.POST) @PutMapping => @RequestMapping(value = "/xxx",method = RequestMethod.PUT) @DeleteMapping => @RequestMapping(value = "/xxx",method = RequestMethod.DELETE) ...
Web開發中,對從前端傳過來的數據作數據校驗已是屢見不鮮的事了,但若是校驗的數據不少,那麼,一方面在開發上就須要作不少if判斷,另外一方面則是代碼上顯得再也不簡潔。其實,使用@Valid + BindingResult就能夠優雅地解決這樣的問題。使用示例以下:
首先,使用一個Java Bean來接收前端提交的數據。在這個Java Bean以前加上@Valid,在這個Java Bean以後加上BindingResult(BindingResult參數必須緊跟在@Valid參數以後。)
/** * 添加一個女生 */ @PostMapping(value = "/girls") public Result<Girl> girlAdd(@Valid Girl girl, BindingResult bindingResult) { if (bindingResult.hasErrors()) { return ResultUtils.error(-1, bindingResult.getFieldError().getDefaultMessage()); } return ResultUtils.success(girlRespository.save(girl)); }
而後,須要在@Valid註解的Java Bean中,使用各類"規則註解"對其中的屬性進行校驗規則的設定。示例以下:
public class Girl { private Integer id; @NotBlank(message = "這個字段必傳") private String cupSize; @Min(value = 18, message = "未成年少女禁止入內") private Integer age; @NotNull(message = "金額必傳") private Double money; ... }
示例中,"規則註解"的message值能夠在Controller中經過bindingResult.getFieldError().getDefaultMessage()獲取。
這類用於數據校驗的註解還有不少,有興趣的能夠好好研究一下:
註解 | 類型 | 說明 |
---|---|---|
@AssertFalse | Boolean,boolean | 驗證註解的元素值是false |
@AssertTrue | Boolean,boolean | 驗證註解的元素值是true |
@NotNull | 任意類型 | 驗證註解的元素值不是null |
@Null | 任意類型 | 驗證註解的元素值是null |
@Min(value=值) | BigDecimal,BigInteger, byte,short, int, long,等任何Number或CharSequence(存儲的是數字)子類型 | 驗證註解的元素值大於等於@Min指定的value值 |
@Max(value=值) | 和@Min要求同樣 | 驗證註解的元素值小於等於@Max指定的value值 |
@DecimalMin(value=值) | 和@Min要求同樣 | 驗證註解的元素值大於等於@ DecimalMin指定的value值 |
@DecimalMax(value=值) | 和@Min要求同樣 | 驗證註解的元素值小於等於@ DecimalMax指定的value值 |
@Digits(integer=整數位數, fraction=小數位數) | 和@Min要求同樣 | 驗證註解的元素值的整數位數和小數位數上限 |
@Size(min=下限, max=上限) | 字符串、Collection、Map、數組等 | 驗證註解的元素值的在min和max(包含)指定區間以內,如字符長度、集合大小 |
@Past | java.util.Date,java.util.Calendar;Joda Time類庫的日期類型 | 驗證註解的元素值(日期類型)比當前時間早 |
@Future | 與@Past要求同樣 | 驗證註解的元素值(日期類型)比當前時間晚 |
@NotBlank | CharSequence子類型 | 驗證註解的元素值不爲空(不爲null、去除首位空格後長度爲0),不一樣於@NotEmpty,@NotBlank只應用於字符串且在比較時會去除字符串的首位空格 |
@Length(min=下限, max=上限) | CharSequence子類型 | 驗證註解的元素值長度在min和max區間內 |
@NotEmpty | CharSequence子類型、Collection、Map、數組 | 驗證註解的元素值不爲null且不爲空(字符串長度不爲0、集合大小不爲0) |
@Range(min=最小值, max=最大值) | BigDecimal,BigInteger,CharSequence, byte, short, int, long等原子類型和包裝類型 | 驗證註解的元素值在最小值和最大值之間 |
@Email(regexp=正則表達式,flag=標誌的模式) | CharSequence子類型(如String) | 驗證註解的元素值是Email,也能夠經過regexp和flag指定自定義的email格式 |
@Pattern(regexp=正則表達式,flag=標誌的模式) | String,任何CharSequence的子類型 | 驗證註解的元素值與指定的正則表達式匹配 |
@Valid | 任何非原子類型 | 指定遞歸驗證關聯的對象;如用戶對象中有個地址對象屬性,若是想在驗證用戶對象時一塊兒驗證地址對象的話,在地址對象上加@Valid註解便可級聯驗證 |
AOP是Spring中一大核心,若在SpringBoot中要使用AOP只需兩步:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
@Aspect @Component public class HttpAspect { private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class); @Pointcut("execution(public * com.lqr.controller.GirlController.*(..))") public void log() { } @Before("log()") public void deBefore(JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // url logger.info("url={}", request.getRequestURL()); // method logger.info("method={}", request.getMethod()); // ip logger.info("ip={}", request.getRemoteAddr()); // 類方法 logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); // 參數 logger.info("args={}", joinPoint.getArgs()); } @After("log()") public void doAfter() { logger.info("doAfter..."); } @AfterReturning(returning = "object", pointcut = "log()") public void doAfterReturning(Object object) { if (object != null) logger.info("response={}", object.toString()); } }
這裏之因此繼承RuntimeException,是爲了方便事務回滾。而自定義異常的好處在於:一方面可使代碼語義化,另外一方面使得咱們編碼更加方便。
public class GirlException extends RuntimeException { private Integer code; public GirlException(ResultEnum resultEnum) { super(resultEnum.getMsg()); this.code = resultEnum.getCode(); } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } }
使用全局異常捕獲器,一方面能夠捕獲到整個項目中的Exception及其子類(包含RuntimeException等),另外一方面能夠對異常進行統一處理並返回統一的數據格式,爲前端提供友好的數據交互。
@ControllerAdvice public class ExceptionHandle { private final Logger logger = LoggerFactory.getLogger(ExceptionHandle.class); @ExceptionHandler(value = Exception.class) @ResponseBody public Result handle(Exception e) { if (e instanceof GirlException) { GirlException girlException = (GirlException) e; return ResultUtils.error(girlException.getCode(), girlException.getMessage()); } else { logger.error("【系統異常】{}", e); return ResultUtils.error(-1, "未知錯誤"); } } }
Web開發中,沒有熱部署怎麼能行呢?因此,下面就介紹下Spring Boot的熱部署配置。
<dependencies> ... <!--spring boot 熱部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <!--spring boot 熱部署--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> </configuration> </plugin> </plugins> ... </build>
打開Idea的Settings界面,找到"Build,Execution,Depolyment",在Compiler中將"Build project automatically"打鉤。
使用快捷鍵 "ctrl+shift+alt+/" 打開pom.xml的維護(Maintenance)菜單,找到登記(registry)項,單擊打開。
在登記(registry)中找到"compiler.automake.allow.when.app.running"這一項打鉤,關閉。最後重啓項目便可!!!
儘管Spring Boot項目會內置一個tomcat,僅只需經過一個簡單的指令即可啓動項目,但在生產環境下,咱們仍是習慣將項目發佈到第三外的servlet容器中,下面將介紹若是將一個Spring Boot項目團部署到第三方tomcat中運行。
spring-boot-starter-tomcat是Spring Boot默認就會配置的,即上面說到的內嵌tomcat,將其設置爲provided是在打包時會將該包(依賴)排除,由於要放到獨立的tomcat中運行,Spring Boot內嵌的Tomcat是不須要用到的。
<!--spring boot tomcat(默承認以不用配置,但當須要把當前web應用佈置到外部servlet容器時就須要配置,並將scope配置爲provided)--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency>
須要繼承SpringBootServletInitializer,並重寫configure()方法,將Spring Boot的入口類設置進去。
// 若要部署到外部servlet容器,須要繼承SpringBootServletInitializer並重寫configure() @SpringBootApplication @Configuration public class MyWebApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { // 設置啓動類,用於獨立tomcat運行的入口 return builder.sources(MyWebApplication.class); } }