spring boot的定位
Spring Boot并不是不對Spring功能上的增強,而是提供了一種快速使用Spring的方式
本節(jié)轉載自spring boot與spring mvc的區(qū)別是什么贵试?
Spring Boot與spring及spring mvc的關系
簡介
- Spring 框架就像一個家族撼唾,有眾多衍生產品例如 boot蝌矛、security、jpa等等。但他們的基礎都是Spring 的 IOC(提供了依賴注入的容器)和 AOP(解決了面向橫切面的編程) 梭域,然后在此兩者的基礎上實現了其他延伸產品的高級功能酥夭。
- Spring MVC是基于 Servlet 的一個 MVC 框架 主要解決 WEB 開發(fā)的問題
- 因為 Spring 的配置非常復雜赐纱,各種XML、 JavaConfig熬北、hin處理起來比較繁瑣疙描。于是為了簡化開發(fā)者的使用,從而創(chuàng)造性地推出了Spring boot讶隐,
約定優(yōu)于配置
起胰,簡化了spring的配置流程
關系
- Spring 最初利用“工廠模式”(DI)和“代理模式”(AOP)解耦應用組件。
- 大家覺得挺好用巫延,于是按照這種模式搞了一個 MVC框架(一些用Spring 解耦的組件)效五,用開發(fā) web 應用( SpringMVC )。
- 然后有發(fā)現每次開發(fā)都寫很多樣板代碼烈评,為了簡化工作流程火俄,于是開發(fā)出了一些“懶人整合包”(starter),這套就是 Spring Boot讲冠。
所以瓜客,用最簡練的語言概括就是:
Spring 是一個“引擎”;
Spring MVC 是基于Spring的一個 MVC 框架 竿开;
Spring Boot 是基于Spring4的條件注冊的一套快速開發(fā)整合包谱仪。
spring mvc < spring <springboot
為什么用spring boot
功能
Spring Boot實現了自動配置,降低了項目搭建的復雜度否彩。
眾所周知Spring框架需要進行大量的配置疯攒,Spring Boot引入自動配置的概念,讓項目設置變得很容易列荔。Spring Boot本身并不提供Spring框架的核心特性以及擴展功能敬尺,只是用于快速枚尼、敏捷地開發(fā)新一代基于Spring框架的應用程序。也就是說砂吞,它并不是用來替代Spring的解決方案署恍,而是和Spring框架緊密結合用于提升Spring開發(fā)者體驗的工具。同時它集成了大量常用的第三方庫配置(例如Jackson, JDBC, Mongo, Redis, Mail等等)蜻直,Spring Boot應用中這些第三方庫幾乎可以零配置的開箱即用(out-of-the-box)盯质,大部分的Spring Boot應用都只需要非常少量的配置代碼,開發(fā)者能夠更加專注于業(yè)務邏輯概而。
Spring Boot只是承載者呼巷,輔助你簡化項目搭建過程的。如果承載的是WEB項目赎瑰,使用Spring MVC作為MVC框架王悍,那么工作流程和你上面描述的是完全一樣的,因為這部分工作是Spring MVC做的而不是Spring Boot乡范。
對使用者來說配名,換用Spring Boot以后,項目初始化方法變了晋辆,配置文件變了渠脉,另外就是不需要單獨安裝Tomcat這類容器服務器了,maven打出jar包直接跑起來就是個網站瓶佳,但你最核心的業(yè)務邏輯實現與業(yè)務流程實現沒有任何變化
芋膘。
優(yōu)點
- Spring Boot可以建立獨立的
Spring
應用程序 -
內嵌了如
Tomcat,Jetty
和Undertow這樣的容器霸饲,也就是說可以直接跑起來为朋,用不著再做部署工作了 - 可以自動配置Spring:無需再像Spring那樣搞一堆繁瑣的
xml文件的配置
- 提供了一些現有的功能,如量度工具厚脉,表單數據驗證以及一些外部配置這樣的一些第三方功能
- 提供的POM可以簡化
Maven
的配置
spring Boot實例demo
程序入口
SpringApplication.run(App.class, args)
首先來創(chuàng)建src/main/java/ToutiaoApplication.java
:
@SpringBootApplication
public class ToutiaoApplication {
public static void main(String[] args) {
SpringApplication.run(ToutiaoApplication.class, args);
}
}
程序的入口:SpringApplication.run(Application.class, args)
习寸,SpringApplication是Spring Boot框架中描述Spring應用的類,它的run()方法會創(chuàng)建一個Spring應用上下文(Application Context)傻工。
另一方面它會掃描當前應用類路徑上的依賴霞溪,如果Spring Boot判斷這是一個Web應用,會啟動一個內嵌的Servlet容器(默認是Tomcat)用于處理HTTP請求中捆。
@SpringBootApplication
Spring Boot提供一個方便的 @SpringBootApplication 選擇鸯匹。該 @SpringBootApplication 注解等價于以默認屬性使用 @Configuration+@EnableAutoConfiguration+@ComponentScan
1. @Configuration
定義一個配置類,用@Configuration注解該類泄伪,等價于XML中配置beans
殴蓬;用@Bean標注方法等價于XML中配置bean
public class SpringConfig {
@Bean
public Piano piano(){
return new Piano();
}
@Bean(name = "counter")
public Counter counter(){
return new Counter(12,"Shake it Off",piano());
}
}
2. @EnableAutoConfiguration
啟動Spring MVC
3. @ComponentScan
啟用組件掃描
實現Hello World顯示
在controller目錄下創(chuàng)建一個IndexController 類(之后的方法除特殊說明,否則都是IndexController類中的方法)
@Controller
public class IndexController {
@RequestMapping(path = {"/","/index"})
@ResponseBody
public String index(HttpSession session){
return "Hello World" ;
}
}
運行Application文件蟋滴,右鍵Run As -> Java Application染厅,之后打開瀏覽器輸入地址:http://127.0.0.1:8080/(或者http://127.0.0.1:8080/ index) 就可以看到Hello world痘绎。
@Controller
基于@Component注解,表明是控制類組件肖粮,輔助實現組件掃描简逮,組件掃描會自動找到@Controller注解對應的類,并將其聲明為Spring應用上下文的一個bean
@RequestMapping(value=”/”,method)
- 作用
@RequestMapping 注解為控制器指定可以處理那些URL 請求
@RequestMapping (value=”/”,method)尿赚,value值屬性指定了這個方法所要處理的請求路徑,method屬性細化了它所處理的HTTP方法(GET或者POST),例如
@RequestMapping(value = "/login", method = RequestMethod.POST)
獲取請求中信息
- @RequestBody
綁定請求對象蕉堰,Spring會幫你進行協(xié)議轉換凌净,將Json、Xml協(xié)議轉換成你需要的對象屋讶。 - @ResponseBody
標注任何對象冰寻,由Srping完成對象——協(xié)議的轉換。
在SpringMVC中皿渗,可以使用@RequestBody和@ResponseBody兩個注解斩芭,分別完成請求報文到對象和對象到響應報文的轉換,底層這種靈活的消息轉換機制乐疆,就是Spring3.x中新引入的HttpMessageConverter即消息轉換器機制划乖。
//value與path都是別名,實質上是一樣的
@RequestMapping(value = {"/profile/{groupId}/{userId}"})
@ResponseBody
//127.0.0.1:8080/profile/12/33?key=xx&type=33
public String profile(
@PathVariable("groupId") String groupId,
@PathVariable("userId") int userId,
@RequestParam(value = "key",defaultValue = "megustas") String key,
@RequestParam(value = "type",defaultValue = "1") int type) {
return String.format("GID{%s},UID{%d},KEY{%s},TYPE{%d}",groupId,userId,key,type);
}
@RequestParam注解和@PathVariable注解的區(qū)別挤土,從字面上可以看出前者是獲取請求里邊攜帶的參數琴庵;后者是獲取請求路徑里邊的變量參數。
例如:
127.0.0.1/user/{userId}?userName=datiangou
- userId是路徑上的變量
- userName才是請求參數信息
@Pathvariable
通過 @PathVariable 可以將 URL 中占位符參數綁定到控制器處理方法的入參中:URL 中的{xxx}
占位符可以通過@PathVariable("xxx") 綁定到操作方法的入參
中仰美。
@RequestMapping("/pathVariable/{name1}")
public String pathVariable(@PathVariable("name1")String name2){
System.out.println("hello "+name2);
return "helloworld";
}
URL 中的{name1}
占位符通過@PathVariable("name1") 綁定到操作方法的String name2入參
中迷殿。
@RequestParam
獲取請求參數
模板
直接返回HTML代碼太復雜
在之前所有的@RequestMapping注解的方法中,返回值字符串都被直接傳送到瀏覽器端并顯示給用戶咖杂。但是為了能夠呈現更加豐富庆寺、美觀的頁面,我們需要將HTML代碼返回給瀏覽器诉字,瀏覽器再進行頁面的渲染懦尝、顯示。
一種很直觀的方法是在處理請求的方法中奏窑,直接返回HTML代碼导披,但是這樣做的問題在于——一個復雜的頁面HTML代碼往往也非常復雜,并且嵌入在Java代碼中十分不利于維護埃唯。更好的做法是將頁面的HTML代碼寫在模板文件中(此處使用Velocity模板語言)撩匕,渲染后再返回給用戶。
模板引擎
模板引擎是為了使用戶界面與業(yè)務數據分離而產生的墨叛,它可以生成特定格式的文檔止毕,用于網站的模板引擎就會生成一個標準的HTML文檔模蜡。
在MVC模式中,模板引擎的工作原理基本一樣扁凛,比如說以freemarker為例忍疾,如下圖:
可概括為一個公式:
模板 + 數據模型 = 輸出
@RequestMapping(value = {"/vm"})
public String news(Model model){
model.addAttribute("value1", "vv1");
List<String> colors = Arrays.asList(new String[]{"RED", "GREEN", "BLUE"});
Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < 4; ++i) {
map.put(String.valueOf(i), String.valueOf(i * i));
}
model.addAttribute("colors", colors);
model.addAttribute("map", map);
model.addAttribute("user",new User("Megustas"));//傳遞自定義對象
return "news";//news.vm
}
Model
后端與渲染之間鉸鏈的一個數據模型Model,通過Model向前臺視圖傳遞參數,Model中存入的數據在Velocity中直接使用
return "news";
返回值不再是ResponseBody,
在上述例子中谨朝,返回值”news”并非直接將字符串返回給瀏覽器卤妒,而是尋找名字為news的模板進行渲染,news.vm文件存放于resources/templates目錄下
Velocity簡單語法
1.標識Velocity的腳本語句 #
用來標識Velocity的腳本語句字币,包括#set则披、#if 、#else洗出、#end士复、#foreach、#end翩活、#iinclude阱洪、#parse、#macro等
2. 用來標識一個變量$
3. 把不存在的變量顯示為空白!
4. 注釋##
5. 常用指令
常用指令 | 說明 | 例子 |
---|---|---|
#include | include指令用于引入其他的文件菠镇,引入的文件將會被當做靜態(tài)文件來處理 | #include("test1.txt") |
#parse | 引入的文件通常是動態(tài)文件冗荸,并且parse指令中允許嵌套 | ? |
#set | 賦值指令:可以用于創(chuàng)建一個新的實例,或者更新一個已經存在的實例利耍。set指令中也支持基本的數據運算 | #set($username="yxd") |
#if #else #end | 條件判斷指令 | ? |
#foreach #end | 循環(huán)指令 | #foreach ($item in [1..5]).. #end |
#macro #end | 提供了一個構建模板代碼復用的機制俏竞,類似于Java中的函數 | #macro ( sayHi $username)Hello $username #end |
request/response
一次網頁請求中,通過request獲取它的所有數據
@RequestMapping(value = {"/request"})
@ResponseBody
public String request(HttpServletRequest request,
HttpServletResponse response,
HttpSession session){
//獲取Http請求的頭文件
StringBuilder sb = new StringBuilder();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()){
String name = headerNames.nextElement();
sb.append(name + ":" + request.getHeader(name) + "<br>");
}
for(Cookie cookie : request.getCookies()){
sb.append("Cookie");
sb.append(cookie.getName());
sb.append(":");
sb.append(cookie.getValue());
sb.append("<br>");
}
sb.append("getMethod:" + request.getMethod()+ "<br>");
sb.append("getPathInfo:" + request.getPathInfo()+ "<br>");
sb.append("getQueryString:" + request.getQueryString()+ "<br>");
sb.append("getRequestURI" + request.getRequestURI());
return sb.toString();
}
Enumeration
Enumeration接口作用和Iterator類似堂竟,提供了遍歷元素的功能魂毁,其中只定義了兩種方法:
方法 | 作用 |
---|---|
boolean hasMoreElements() | 測試Enumeration對象中是否包含元素,如果有返回true出嘹,則表示至少包含一個元素 |
Object nextElement() | 如果Enumeration對象還有元素席楚,返回對象的下一個元素,否則拋出NoSuchElementException |
request.getQueryString():
request.getQueryString()就是獲取查詢字符串
即請求税稼?后面的就是QueryString烦秩,例如
127.0.0.1:8080/request?type=2&&k=xx
- QueryString為type=2&&k=xx
- RequestURI為/request
response
可以通過HttpServletResponse response將更多數據寫回
@RequestMapping(value = {"/response"})
@ResponseBody
public String response(
@CookieValue(value="nowcoderid",defaultValue = "a") String nowcoderId,
@RequestParam(value = "key", defaultValue = "key") String key,
@RequestParam(value = "value", defaultValue = "value") String value,
HttpServletResponse response){
response.addCookie(new Cookie(key,value));
response.addHeader(key,value);
return "NowCoderId From Cookie:" + nowcoderId;
}
訪問:127.0.0.1:8080/response
:
輸出:NowCoderId From Cookie:a(此時為默認值)
訪問127.0.0.1:8080/response?key=nowcoderid&value=22
:
輸出:NowCoderId From Cookie:22
重定向
redirect
前綴,跳到首頁郎仆,默認是302跳轉
從一個頁面跳到另一個頁面只祠,所有的訪問都是同一個HttpSession,可以在redirect中添加session的一些特性扰肌,返回到首頁的時候抛寝,把session的信息讀取出來,顯示在首頁。用戶體驗較好盗舰。
301和302的區(qū)別
301:永久轉移
如果是301晶府,會把信息存入瀏覽器,下次瀏覽器訪問網址钻趋,會直接定位到另一個地方川陆。
302:臨時轉移
統(tǒng)一的異常處理
@ExceptionHandler
- 統(tǒng)一處理某一類異常,從而能夠減少代碼重復率和復雜度
- @ExceptionHandler只會是在當前的Controller里面起作用
@RequestMapping("/admin")
@ResponseBody
public String admin(@RequestParam(value = "key",required = false) String key){
if("admin".equals(key)){
return "hello admin";
}
throw new IllegalArgumentException("Key 錯誤");
}
//好處是可以用統(tǒng)一的頁面處理問題
@ExceptionHandler()
@ResponseBody
public String error(Exception e){
return "error:" + e.getMessage();
}
@ControllerAdvice
如果想所有的Controller統(tǒng)一處理異常的話蛮位,可以用@ControllerAdvice來創(chuàng)建一個專門處理的類较沪,這樣所有控制器的異常可以在一個地方進行處理
@ResponseStatus
- 可以將某種異常映射為HTTP狀態(tài)碼
- 不要輕易把@ResponseStatus修飾目標方法失仁,因為無論它執(zhí)行方法過程中有沒有異常產生购对,用戶都會得到異常的界面,而目標方法正常執(zhí)行