SpringMVC-GetMapping注解總結
@GetMapping是一個組合注解,是@RequestMapping(method= RequestMethod.GET)的縮寫。該注解將HTTP Get 映射到特定的處理方法上。
所以此處個人的理解,@GetMapping可以算是@RequestMapping的子集,可能該說法不是很嚴謹,但是我個人暫時是這么理解的。
Spirng與Web集成
1.1 ApplicationContext應用上下文獲取方式#
應用上下文對象是通過new ClasspathXmlApplicationContext(spring配置文件) 方式獲取的,但是每次從容器中獲得Bean時都要編寫new ClasspathXmlApplicationContext(spring配置文件) ,這樣的弊端是配置文件加載多次,應用上下文對象創建多次。
在Web項目中,可以使用ServletContextListener監聽Web應用的啟動,我們可以在Web應用啟動時,就加載Spring的配置文件,創建應用上下文對象ApplicationContext,在將其存儲到最大的域servletContext域中,這樣就可以在任意位置從域中獲得應用上下文ApplicationContext對象了。
1.2 Spring提供獲取應用上下文的工具#
上面的分析不用手動實現,Spring提供了一個監聽器ContextLoaderListener就是對上述功能的封裝,該監聽器內部加載Spring配置文件,創建應用上下文對象,並存儲到ServletContext域中,提供了一個客戶端工具WebApplicationContextUtils供使用者獲得應用上下文對象。
所以我們需要做的只有兩件事:
在web.xml中配置ContextLoaderListener監聽器(導入spring-web坐標)
使用WebApplicationContextUtils獲得應用上下文對象ApplicationContext
- 哪一些情況下,瀏覽器會發送get請求
a. 直接在瀏覽器地址欄輸入某個地址
b. 點擊鏈接
c. 表單默認的提交方式
2.特點:
a. 請求參數會添加到請求資源路勁的后面,只能添加少量參數
b. 請求參數會顯示在瀏覽器地址欄,路由器會記錄請求地址
5:@PostMapping
- 哪一些情況下,瀏覽器會發送post請求
a. 設置表單method = "post"
2.特點:
a. 請求參數添加到實體內容里面,可以添加大量的參數(也解釋了為什么瀏覽器地址欄不能發送post請求,在地址欄里我們只能填寫URL,並不能進入到Http包的實體當中)
b. 相對安全,但是,post請求不會對請求參數進行加密處理(可以使用https協議來保證數據安全)。
6:RequestBody
如果傳輸的是單層json對象,我們后台可以直接用 @RequestParam接收
$.ajax({
type : "post",
dataType : "json",
url : "/testRequestBody",
data:{
name:"韋德",
age:35
},
success : function(result) {
}
});
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestParamMap<String, Object> map) {
System.out.println(map);// {name=韋德, age=35}
return"index";
}
如果傳輸的是多層嵌套json對象,這個時候會就會出現數據丟失問題
@RequestBody很好的解決了這個問題,它會把前台傳輸過來的json轉化為后台對應的對象
$.ajax({
type : "post",
dataType : "json",
url : "/testRequestBody",
contentType:"application/json",
data:JSON.stringify({
name:"韋德",
win:[2006,2012,2013],
age:35
}),
success : function(result) {
}
});
@RequestMapping("/testRequestBody")
public StringtestRequestBody(@RequestBodyMap<String, Object> map) {
System.out.println(map);//{name=韋德, win=[2006, 2012, 2013], age=35}
return"index";
}
需要注意的是前台需要指定contentType為"application/json"
同時要把json對象轉化為String,否則后台不能識別
7:@ResponseBody
@ResponseBody注解到方法上,直接傳回結果(字符串)
ajax請求返回json格式,往常我們這樣做
privatevoid writeJson(HttpServletResponseresponse,Object object) {
String json =JSON.toJSONString(object);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = null;
try {
out = response.getWriter();
out.write(json);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
}
這個時候 @ResponseBody就派上用場了,只需要一個注解,全部搞定
$.ajax({
type : "post",
dataType : "json",
url : "/testResponseBody",
success : function(result) {
console.info(result);
}
});
@RequestMapping("/testResponseBody")
@ResponseBody
public Map<String, Object>testRequestBody(){
Map<String,Object> result = new HashMap<String,Object>();
result.put("name", "韋德");
result.put("age", 35);
return result;
}
前台console輸出
{
"age": 35,
"name": "韋德"
}
說一些個人的看法,非技術層面上的,一個 API 何時用 GET、POST 甚至 PUT 請求。
首先引入一個副作用的概念,副作用指當你發送完一個請求以后,網站上的資源狀態沒有發生修改,即認為這個請求是無副作用的。比如注冊用戶這個請求是有副作用的,獲取用戶詳情可以認為是無副作用的。
再引入一個冪等性的概念,冪等是說,一個請求原封不動的發送N次和M次(N不等於M,N和M都大於1)服務器上資源的狀態最終是一致的。比如發貼是非冪等的,重放10次發貼請求會創建10個帖子。但修改帖子內容是冪等的,一個修改請求重放無論多少次,帖子最終狀態都是一致的。(前提是同一個修改操作重復10次)
嘮叨了這么多,回過頭來,何時用 PUT POST GET DELETE:
GET:無副作用,冪等
PUT:副作用,冪等
POST:副作用,非冪等
DELETE:副作用,冪等
這么看的話,DELETE 和 PUT 請求好像毫無區別。為了進一步區分這些請求方式的應用場景,我們再引入一個技術特性,request body,就是大家廣為流傳的 "POST 請求傳輸數據量比較大“ 這一說法的來源。
POST/PUT 請求可以通過傳遞 request body 來發送大量的數據,而 GET/DELETE 不能。
所以上面的表格需要再加一項:
GET:無副作用,冪等,不可帶 Request Body
PUT:副作用,冪等,可以帶 Request Body
POST:副作用,非冪等,可以帶 Request Body
DELETE:副作用,冪等,不可帶 Request Body
-
params,headers
params:指定request中必須包含某些參數值,才讓該方法處理。
headers:
指定request中必須包含某些指定的header值,才能讓該方法處理請求。
- consumes,produces
consumes:
指定處理請求的提交內容類型(Content-Type),例如application/json,text/html;
produces:
指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回;
2:@PathVariable
用於將請求URL中的模板變量映射到功能處理方法的參數上,即取出uri模板中的變量作為參數。如:
3: @RequestParam
@RequestParam主要用於在SpringMVC后台控制層獲取參數,類似一種是request.getParameter("name"),
它有三個常用參數:defaultValue = "0", required = false,value="isApp";
defaultValue 表示設置默認值,required通過boolean設置是否是必須要傳入的參數,value 值表示接受的傳入的參數類型。
形式如項目中的:
public ObjectuserMemberShop(@RequestParam(required= false,value="corpId")IntegercorpId,
@RequestParam("uid")Longuid){
}
參考一篇文章,其中講了@controller、@service、@repository注解,自己復制下再總結下自己的一些想法。
如果一個類帶了@controller、@service、@repository注解,將自動注冊到Spring容器,不需要再在applicationContext.xml文件定義bean了。
首先:
Controller層使用@Controller注解
Service層使用@Service注解
Dao層使用@Repository注解
@Controller可注解於類上,聲明該類為SpringMVC的Controller對象。
簡單說:被@Controller注解的類是一個控制器,該類的方法是相應的動作。
@Service可注解於類上,
簡單說:
1.聲明該類是一個bean。如
@Service
@Scope("prototype")
public class Zoo
2.Zoo.java在bean中的id是"zoo",即類名且首字母小寫
例:@Service("userService")注解是告訴Spring,當Spring要創建UserServiceImpl的的實例時,bean的名字必須叫做"userService",這樣當Action需要使用UserServiceImpl的的實例時,就可以由Spring創建好的"userService",然后注入給Action。
dao層使用@repository注解
@Repository可注解於類上,
@Repository(value="userDao")注解是告訴Spring,讓Spring創建一個名字叫“userDao”的UserDaoImpl實例。
當Service需要使用Spring創建的名字叫“userDao”的UserDaoImpl實例時,
就可以使用@Resource(name = "userDao")注解告訴Spring,Spring把創建好的userDao注入給Service即可。
java 解析URL里的協議及參數工具類,解析URL中的主域名,並統一把協議修改成http或去掉協議
public class UrlDomainUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(UrlDomainUtils.class);
/**
* 獲取主域名,即URL頭
* @param url
* @return
*/
public static String getDomainHost(String url){
String pattern = "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/)";
Pattern p = Pattern.compile(pattern);
String line = url;
Matcher m = p.matcher(line);
if(m.find()){
//匹配結果
String domain = m.group();
LOGGER.info("解析的URL主域名是------------>{} 原始url is {}" ,domain,url);
domain = domain.replace("https","http");
LOGGER.info("修改解析出的URL主域名的協議成http------------>{} 原始url is {}" ,domain,url);
// domain = domain.replace("http://","");
// LOGGER.info("修改解析出的URL主域名后去掉協議------------>{} 原始url is {}" ,domain,url);
return domain;
}
LOGGER.info("未找到的URL主域名 原始url is {}" ,url);
return null;
}
/**
* 獲取主域名,即URL頭
* @param url
* @param key url中的參數key
* @return
*/
public static Map<String, String> parseURLParam(String URL, String key) {
Map<String, String> mapRequest = new HashMap<String, String>();
String[] arrSplit = null;
String strUrlParam = TruncateUrlPage(URL);
if (strUrlParam == null) {
return mapRequest;
}
//每個鍵值為一組
arrSplit = strUrlParam.split("[&]");
for (String strSplit : arrSplit) {
String[] arrSplitEqual = null;
arrSplitEqual = strSplit.split("[=]");
//解析出鍵值
if (arrSplitEqual.length > 1) {
//正確解析
if(key.equals(arrSplitEqual[0])){
mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
break;
}
} else {
if (arrSplitEqual[0] != "") {
//只有參數沒有值,不加入
mapRequest.put(arrSplitEqual[0], "");
}
}
}
return mapRequest;
}
/**
* 截取URL中的?之后的部分
* @param strUrl
* @return
*/
private static String TruncateUrlPage(String strURL) {
String strAllParam = null;
String[] arrSplit = null;
strURL = strURL.trim();
arrSplit = strURL.split("[?]");
if (strURL.length() > 1) {
if (arrSplit.length > 1) {
if (arrSplit[1] != null) {
strAllParam = arrSplit[1];
}
}
}
return strAllParam;
}
public static void main(String[] args) {
String url = "https://developer.baidu.com/forum/search?keyword=%E5%90%AC%E8%AF%9D%E8%8D%AF%7C%2B14%E2%91%A392%E2%91%A438V%7C";
String url = "https://developer.baidu.com/forum/search?keyword=%E5%90%AC%E8%AF%9D%E8%8D%AF%E6%B0%B4%7C%2B14%E2%91%A392%E2%91%A438V%7C";
String url = "https://developer.baidu.com/forum/search?keyword=%E5%90%AC%E8%AF%9D%E7%9A%84%E8%8D%AF%7C%2B14%E2%91%A392%E2%91%A438V%7C";
String url = "https://developer.baidu.com/forum/search?keyword=%E5%90%AC%E8%AF%9D%E7%9A%84%E8%8D%AF%E6%B0%B4%7C%2B14%E2%91%A392%E2%91%A438V%7C";
String url = "https://developer.baidu.com/forum/search?keyword=%E5%90%AC%E8%AF%9D%E5%9E%8B%E8%8D%AF%7C%2B14%E2%91%A392%E2%91%A438V%7C";
String url = "https://developer.baidu.com/forum/search?keyword=%E5%90%AC%E8%AF%9D%E5%9E%8B%E8%8D%AF%E6%B0%B4%7C%2B14%E2%91%A392%E2%91%A438V%7C";
getDomainHost(url);
}
}
一,Spirng與Web集成
1.1 ApplicationContext應用上下文獲取方式#
應用上下文對象是通過new ClasspathXmlApplicationContext(spring配置文件) 方式獲取的,但是每次從容器中獲得Bean時都要編寫new ClasspathXmlApplicationContext(spring配置文件) ,這樣的弊端是配置文件加載多次,應用上下文對象創建多次。
在Web項目中,可以使用ServletContextListener監聽Web應用的啟動,我們可以在Web應用啟動時,就加載Spring的配置文件,創建應用上下文對象ApplicationContext,在將其存儲到最大的域servletContext域中,這樣就可以在任意位置從域中獲得應用上下文ApplicationContext對象了。
1.2 Spring提供獲取應用上下文的工具#
上面的分析不用手動實現,Spring提供了一個監聽器ContextLoaderListener就是對上述功能的封裝,該監聽器內部加載Spring配置文件,創建應用上下文對象,並存儲到ServletContext域中,提供了一個客戶端工具WebApplicationContextUtils供使用者獲得應用上下文對象。
所以我們需要做的只有兩件事:
在web.xml中配置ContextLoaderListener監聽器(導入spring-web坐標)
使用WebApplicationContextUtils獲得應用上下文對象ApplicationContext
1.3 Spring與Web集成實現#
1.導入spring-web坐標,其他的spring坐標也需要導入
復制代碼
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
復制代碼
2.配置ContextLoaderListener監聽器在web項目的web.xml文件配置中配置。
復制代碼
<!--這里配置spring監聽器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
復制代碼
3.測試
復制代碼
package com.itcast.web;
import com.itcast.service.UserService;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.jws.WebService;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/user")
public class UserServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 獲取servletContext域
ServletContext servletContext = this.getServletContext();
// 從servletContext域中獲取上下文對象
WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
// 從容器中獲取對象
UserService userService = (UserService) applicationContext.getBean("userService");
System.out.println(userService);
userService.save();
resp.getWriter().write("aaaa");
}
}
復制代碼
二,SpringMVC簡介
2.1 SpringMVC概述#
SpringMVC 是一種基於 Java 的實現 MVC 設計模型的請求驅動類型的輕量級 Web 框架,屬於SpringFrameWork 的后續產品,已經融合在 Spring Web Flow 中。
SpringMVC 已經成為目前最主流的MVC框架之一,並且隨着Spring3.0 的發布,全面超越 Struts2,成為最優秀的 MVC 框架。它通過一套注解,讓一個簡單的 Java 類成為處理請求的控制器,而無須實現任何接口。同時它還支持 RESTful 編程風格的請求。
SpringMVC優點:
無需事先任何接口,實現操作方便
支持RESTFUL編程風格
2.2 SpirngMVC實現#
1.坐標導入
復制代碼
<!--集成的web坐標-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--spring-webmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
復制代碼
2.在web.xml文件中配置SpirngMVC的核心控制器
復制代碼
復制代碼
3.啟動組件掃描在spring-mvc.xml文件中配置,該配置文件放在resources下
復制代碼
<context:component-scan base-package="com.itcast"></context:component-scan>
復制代碼
4.測試:
編寫controller和業務方法
復制代碼
@Controller
public class QuickController {
// 頁碼跳轉返回
// 返回字符串形式
@RequestMapping("/quick")
public String quickMethod(){
System.out.println("quickMethod running .....");
return "index";
}
}
復制代碼
可以通過瀏覽器進行該路徑訪問:例:localhost:8080/mvc/quick
mvc為虛擬路徑
quick為RequestMapping的參數
2.3 SpringMVC流程圖#
三,SpringMVC組件解析
3.1 SpringMVC的執行流程#
復制代碼
1.用戶發送請求至前端控制器DispatcherServlet。
2.DispatcherServlet收到請求調用HandlerMapping處理器映射器。
3.處理器映射器找到具體的處理器(可以根據xml配置、注解進行查找),生成處理器對象及處理器攔截器(如果有則生成)一並返回給DispatcherServlet。
4.DispatcherServlet調用HandlerAdapter處理器適配器。
5.HandlerAdapter經過適配調用具體的處理器(Controller,也叫后端控制器)。
6.Controller執行完成返回ModelAndView。
7.HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet。
8.DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。
9.ViewReslover解析后返回具體View。
10DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中)。DispatcherServlet響應用戶。
復制代碼
3.2 組件解析#
復制代碼
-
前端控制器:DispatcherServlet
用戶請求到達前端控制器,它就相當於 MVC 模式中的 C,DispatcherServlet 是整個流程控制的中心,由
它調用其它組件處理用戶的請求,DispatcherServlet 的存在降低了組件之間的耦合性。 -
處理器映射器:HandlerMapping
HandlerMapping 負責根據用戶請求找到 Handler 即處理器,SpringMVC 提供了不同的映射器實現不同的
映射方式,例如:配置文件方式,實現接口方式,注解方式等。 -
處理器適配器:HandlerAdapter
通過 HandlerAdapter 對處理器進行執行,這是適配器模式的應用,通過擴展適配器可以對更多類型的處理
器進行執行。 -
處理器:Handler
它就是我們開發中要編寫的具體業務控制器。由 DispatcherServlet 把用戶請求轉發到 Handler。由
Handler 對具體的用戶請求進行處理。 -
視圖解析器:View Resolver
View Resolver 負責將處理結果生成 View 視圖,View Resolver 首先根據邏輯視圖名解析成物理視圖名,即具體的頁面地址,
再生成 View 視圖對象,最后對 View 進行渲染將處理結果通過頁面展示給用戶。 -
視圖:View
SpringMVC 框架提供了很多的 View 視圖類型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的視圖就是 jsp。
一般情況下需要通過頁面標簽或頁面模版技術將模型數據通過頁面展示給用戶,需要由程序員根據業務需求開發具體的頁面
復制代碼
3.3 注解解析#
復制代碼
@RequestMapping
作用:用於建立請求 URL 和處理請求方法之間的對應關系
位置:
類上,請求URL 的第一級訪問目錄。此處不寫的話,就相當於應用的根目錄
方法上,請求 URL 的第二級訪問目錄,與類上的使用@ReqquestMapping標注的一級目錄一起組成訪問虛擬路徑
屬性:
value:用於指定請求的URL。它和path屬性的作用是一樣的
method:用於指定請求的方式
params:用於指定限制請求參數的條件。它支持簡單的表達式。要求請求參數的key和value必須和配置的一模一樣
例如:
params = {"accountName"},表示請求參數必須有accountName
params = {"moeny!100"},表示請求參數中money不能是100
復制代碼
復制代碼 -
mvc命名空間引入
命名空間:xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
約束地址:http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd -
組件掃描
SpringMVC基於Spring容器,所以在進行SpringMVC操作時,需要將Controller存儲到Spring容器中,如果使用@Controller注解標注的話,
就需要使用<context:component-scan base-package=“com.itheima.controller"/>進行組件掃描。
復制代碼
3.4 XML配置解析# -
視圖解析器
SpringMVC有默認組件配置,默認組件都是DispatcherServlet.properties配置文件中配置的,
該配置文件地址org/springframework/web/servlet/DispatcherServlet.properties,該文件中配置了默認的視圖解析器,如下
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
翻看該解析器源碼,可以看到該解析器的默認設置,如下:
REDIRECT_URL_PREFIX = "redirect:" --重定向前綴
FORWARD_URL_PREFIX = "forward:" --轉發前綴(默認值)
prefix = ""; --視圖名稱前綴
suffix = ""; --視圖名稱后綴
視圖解析器
我們可以通過屬性注入的方式修改視圖的的前后綴