1. @Controllerhtml
@Controller 用於標記在一個類上,使用它標記的類就是一個SpringMVC Controller 對象。分發處理器將會掃描使用了該註解的類的方法,並檢測該方法是否使用了@RequestMapping 註解。
使用@Controller 註解,在對應的方法上,視圖解析器能夠解析return 的jsp,html頁面,而且跳轉到相應頁面;
若返回json等內容到頁面,則須要加@ResponseBody註解。前端
2. @RestControllerjava
@RestController註解至關於@ResponseBody + @Controller合在一塊兒的做用。web
返回json數據不須要在方法前面加@ResponseBody註解了,但使用@RestController這個註解,就不能返回jsp,html頁面,視圖解析器沒法解析jsp,html頁面,返回的內容就是return 裏的內容。spring
若使用@RestController,又想返回頁面,則須要使用ModelAndView:數據庫
public ModelAndView login(){ ModelAndView mv = new ModelAndView("index"); return mv; }
3. @ControllerAdvicejson
@ControllerAdvice,是Spring3.2後提供的新註解,從名字上能夠看出大致意思是控制器加強。數組
ControllerAdvice拆分開來就是Controller Advice,關於Advice,其是用於封裝一個切面全部屬性的,包括切入點和須要織入的切面邏輯。這裏ContrllerAdvice也能夠這麼理解,其抽象級別應該是用於對Controller進行「切面」環繞的,而具體的業務織入方式則是經過結合其餘的註解來實現的(@ControllerAdvice並非使用AOP的方式來織入業務邏輯的,而是Spring內置對其各個邏輯的織入方式進行了內置支持)。@ControllerAdvice是在類上聲明的註解,其用法主要有三點:瀏覽器
(1) 全局異常處理,結合方法型註解@ExceptionHandler,用於捕獲Controller中拋出的指定類型的異常,從而達到不一樣類型的異常區別處理的目的session
@ControllerAdvice(basePackages = "mvc") public class SpringControllerAdvice { @ExceptionHandler(RuntimeException.class) public ModelAndView runtimeException(RuntimeException e) { e.printStackTrace(); return new ModelAndView("error"); } }
在該接口中拋出了RuntimeException,那麼理論上,這裏的異常捕獲器就會捕獲該異常,而後返回默認的error視圖。如下是UserController的代碼:
@RequestMapping(value = "/detail", method = RequestMethod.GET) public ModelAndView detail(@RequestParam("id") long id) { ModelAndView view = new ModelAndView("user"); User user = userService.detail(id); view.addObject("user", user); throw new RuntimeException("mock user detail exception."); }
在UserController中拋出的異常可以被SpringControllerAdvice捕獲。
這裏須要注意的是,統一處理異常的controller須要放在和普通controller同級的包下,或者在ComponentScan的包下。在處理異常的時候可使用System.out的方式,也可使用logger.info,或者能夠入到數據庫中。
(2) 全局數據綁定,結合方法型註解@InitBinder,用於request中自定義參數解析方式進行註冊,從而達到自定義指定格式參數的目的;
對於@InitBinder,該註解的主要做用是綁定一些自定義的參數。通常狀況下咱們使用的參數經過@RequestParam,@RequestBody或者@ModelAttribute等註解就能夠進行綁定了,但對於一些特殊類型參數,好比Date,它們的綁定Spring是沒有提供直接的支持的,咱們只能爲其聲明一個轉換器,將request中字符串類型的參數經過轉換器轉換爲Date類型的參數,從而供給@RequestMapping標註的方法使用。
@ControllerAdvice(basePackages = "mvc") public class SpringControllerAdvice { @InitBinder public void globalInitBinder(WebDataBinder binder) { binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); } }
@InitBinder標註的方法註冊的Formatter在每次request請求進行參數轉換時都會調用,用於判斷指定的參數是否爲其能夠轉換的參數。如下是UserController的代碼:
@RequestMapping(value = "/detail", method = RequestMethod.GET) public ModelAndView detail(@RequestParam("id") long id, Date date) { System.out.println(date); ModelAndView view = new ModelAndView("user"); User user = userService.detail(id); view.addObject("user", user); return view; }
(3) 全局數據預處理,結合方法型註解@ModelAttribute,表示其標註的方法將會在目標Controller方法執行以前執行。
使用@ModelAttribute,若是聲明在方法上,而且結合@ControllerAdvice,該方法將會在@ControllerAdvice所指定的範圍內的全部接口方法執行以前執行,而且@ModelAttribute標註的方法的返回值還能夠供給後續會調用的接口方法使用。
@ControllerAdvice(basePackages = "mvc") public class SpringControllerAdvice { @ModelAttribute(value = "message") public String globalModelAttribute() { System.out.println("global model attribute."); return "this is from model attribute"; } }
這裏須要注意的是,該方法提供了一個String類型的返回值,而@ModelAttribute中指定了該屬性名稱爲message,這樣在Controller層就能夠接收該參數了,以下是UserController(普通的@Controller):
@RequestMapping(value = "/detail", method = RequestMethod.GET) public ModelAndView detail(@RequestParam("id") long id, @ModelAttribute("message") String message) { System.out.println(message); ModelAndView view = new ModelAndView("user"); User user = userService.detail(id); view.addObject("user", user); return view; }
@ModelAttribute標註的方法的執行是在全部攔截器的preHandle()方法執行以後纔會執行。
4. @ControllerAdvice和@RestControllerAdvice的區別
//@ControllerAdvice和@RestControllerAdvice均可以指向控制器的一個子集 // 指向全部帶有註解@RestController的控制器 @ControllerAdvice(annotations = RestController.class) public class AnnotationAdvice {}
// 指向全部指定包中的控制器 @ControllerAdvice("org.example.controllers") public class BasePackageAdvice {}
// 指向全部帶有指定簽名的控制器 @ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class}) public class AssignableTypesAdvice {}
@ControllerAdvice和@RestControllerAdvice的區別 相似於 @RestController 與 @Controller的區別。
1. @RequestBody
@RequestBody是做用在形參列表上,用於將前臺發送過來固定格式的數據【xml 格式或者 json等】封裝爲對應的 JavaBean 對象,封裝時使用到的一個對象是系統默認配置的 HttpMessageConverter進行解析,而後封裝到形參上。
public Object login(@RequestBody User loginUuser, HttpSession session)
2. @ResponseBody
@ResponseBody是做用在方法上的,@ResponseBody 表示該方法的返回結果直接寫入 HTTP response body 中,通常在異步獲取數據時使用【也就是AJAX】,在使用 @RequestMapping後,返回值一般解析爲跳轉路徑,可是加上 @ResponseBody 後返回結果不會被解析爲跳轉路徑,而是直接寫入 HTTP response body 中。 好比異步獲取 json 數據,加上 @ResponseBody 後,會直接返回 json 數據。@RequestBody 將 HTTP 請求正文插入方法中,使用適合的 HttpMessageConverter 將請求體寫入某個對象。
@ResponseBody public Object login(String name, String password, HttpSession session)
1. @ModelAttribute
@ModelAttribute註釋方法,被@ModelAttribute註釋的方法會在此controller每一個方法執行前被執行,所以對於一個controller映射多個URL的用法來講,要謹慎使用。
(1) @ModelAttribute註釋void返回值的方法
@Controller public class HelloWorldController { @ModelAttribute public void populateModel(@RequestParam String abc, Model model) { model.addAttribute("attributeName", abc); } @RequestMapping(value = "/helloWorld") public String helloWorld() { return "helloWorld"; } }
(2) @ModelAttribute註釋返回具體類的方法
@ModelAttribute public Account addAccount(@RequestParam String number) { return accountManager.findAccount(number); }
這種狀況,model屬性的名稱沒有指定,它由返回類型隱含表示,如這個方法返回Account類型,那麼這個model屬性的名稱是account。
這個例子中model屬性名稱由返回對象類型隱含表示,model屬性對象就是方法的返回值。它無需要特定的參數。
(3) @ModelAttribute(value="")註釋返回具體類的方法
@Controller public class HelloWorldController { @ModelAttribute("attributeName") public String addAccount(@RequestParam String abc) { return abc; } @RequestMapping(value = "/helloWorld") public String helloWorld() { return "helloWorld"; } }
這個例子中使用@ModelAttribute註釋的value屬性,來指定model屬性的名稱。model屬性對象就是方法的返回值。它無需要特定的參數。
(4) @ModelAttribute和@RequestMapping同時註釋一個方法
@Controller public class HelloWorldController { @RequestMapping(value = "/helloWorld.do") @ModelAttribute("attributeName") public String helloWorld() { return "hi"; } }
這時這個方法的返回值並非表示一個視圖名稱,而是model屬性的值,視圖名稱由RequestToViewNameTranslator根據請求"/helloWorld.do"轉換爲邏輯視圖helloWorld。
Model屬性名稱由@ModelAttribute(value=」」)指定,至關於在request中封裝了key=attributeName,value=hi。
@ModelAttribute註釋一個方法的參數
(1) 從model中獲取
@Controller public class HelloWorldController { @ModelAttribute("user") public User addAccount() { return new User("jz","123"); } @RequestMapping(value = "/helloWorld") public String helloWorld(@ModelAttribute("user") User user) { user.setUserName("jizhou"); return "helloWorld"; } }
在這個例子裏,@ModelAttribute("user") User user註釋方法參數,參數user的值來源於addAccount()方法中的model屬性。
此時若是方法體沒有標註@SessionAttributes("user"),那麼scope爲request,若是標註了,那麼scope爲session。
(2) 從Form表單或URL參數中獲取(實際上,不作此註釋也能拿到user對象)
@Controller public class HelloWorldController { @RequestMapping(value = "/helloWorld") public String helloWorld(@ModelAttribute User user) { return "helloWorld"; } }
注意這時候這個User類必定要有沒有參數的構造函數。
@ModelAttribute註解做用在方法上或者方法的參數上,表示將被註解的方法的返回值或者是被註解的參數做爲Model的屬性加入到Model中,而後Spring框架自會將這個Model傳遞給ViewResolver。Model的生命週期只有一個http請求的處理過程,請求處理完後,Model就銷燬了。
若是想讓參數在多個請求間共享,那麼能夠用到要說到的@SessionAttribute註解。
2. @SessionAttributes
@SessionAttributes做用於處理器類上,用於在多個請求之間傳遞參數,相似於Session的Attribute,但不徹底同樣,通常來講@SessionAttribute設置的參數只用於暫時的傳遞,而不是長期的保存,長期保存的數據仍是要放到Session中。
經過@SessionAttributes註解設置的參數有3類用法:
將一個參數設置到SessionAttribute中須要知足兩個條件:
@Controller @RequestMapping("sc") @SessionAttributes("name") public class SessionController { @RequestMapping("session") public String sessions(Model model,HttpSession session){ model.addAttribute("name", "winclpt"); session.setAttribute("myName", "chke"); return "session"; }
上面的代碼將Model中的name參數保存到了session中(若是Model中沒有name參數,而session中存在一個name參數,那麼SessionAttribute會這個參數塞進Model中)
SessionAttributes有兩個參數:
String[] value:要保存到session中的參數名稱
Class[] typtes:要保存的參數的類型,和value中順序要對應上
因此能夠這樣寫:@SessionAttributes(types = {User.class,Dept.class},value={「attr1」,」attr2」})
原理理解:它的作法大概能夠理解爲將Model中的被註解的attrName屬性保存在一個SessionAttributesHandler中,在每一個RequestMapping的方法執行後,這個SessionAttributesHandler都會將它本身管理的「屬性」從Model中寫入到真正的HttpSession;一樣,在每一個RequestMapping的方法執行前,SessionAttributesHandler會將HttpSession中的被@SessionAttributes註解的屬性寫入到新的Model中。
若是想刪除session中共享的參數,能夠經過SessionStatus.setComplete(),這句只會刪除經過@SessionAttributes保存到session中的參數
首先要知道另外一個東西,default-autowire,它是在xml文件中進行配置的,能夠設置爲byName、byType、constructor和autodetect;好比byName,不用顯式的在bean中寫出依賴的對象,它會自動的匹配其它bean中id名與本bean的set**相同的,並自動裝載。
@Autowired是用在JavaBean中的註解,經過byType形式,用來給指定的字段或方法注入所需的外部資源。
在屬性中使用該註解,不用再寫setXXX方法。
1. @Validated
@Valid是javax.validation裏的。
@Validated是@Valid 的一次封裝,是Spring提供的校驗機制使用。@Valid不提供分組功能。
(1) 分組
當一個實體類須要多種驗證方式時,例:對於一個實體類的id來講,新增的時候是不須要的,對於更新時是必須的。
能夠經過groups對驗證進行分組。
//分組接口類(經過向groups分配不一樣類的class對象,達到分組目的): public interface First { }
//在bean定義的時候: //在First分組時,判斷不能爲空 @NotEmpty(groups={First.class}) private String id;
//控制類: //不需驗證ID public String addPeople(@Validated People p,BindingResult result) //驗證ID public String updatePeople(@Validated({First.class}) People p,BindingResult result)
注意:
對一個參數須要多種驗證方式時,也可經過分配不一樣的組達到目的
(2) 組序列
默認狀況下,不一樣組別的約束驗證是無序的,然而在某些狀況下,約束驗證的順序卻很重要。
//分組接口類 public interface First { } public interface Second { }
//經過@GroupSequence註解對組進行排序 @GroupSequence({First.class,Second.class}) public interface Group { }
//驗證ID public String addPeople(@Validated({Group.class}) People p,BindingResult result)
2. @Value
爲了簡化讀取properties文件中的配置值,spring支持@value註解的方式來獲取,這種方式大大簡化了項目配置,提升業務中的靈活性。
兩種使用方式:
(1) @Value("#{configProperties['key']}")
配置方法一:
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="locations"> <list> <value>classpath:value.properties</value> </list> </property> </bean>
配置方法二:
<util:properties id="configProperties" location="classpath:value.properties"></util:properties>
注:方法一和方法二是等價的,這種方法須要util標籤,要引入util的xsd:
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd"
value.properties
key=1
ValueDemo.java
@Component
public class ValueDemo {
@Value("#{configProperties['key']}")
private String value;
public String getValue() {
return value;
}
}
(2) @Value("${key}")
<!--在上面的配置基礎上加上:--> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="properties" ref="configProperties"/> </bean> <!--或直接完整指定:--> <bean id="appProperty" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <array> <value>classpath:value.properties</value> </array> </property> </bean>
@Component public class ValueDemo { @Value("${key}") private String value; public String getValue() { return value; } }
3. @Required
@Required 註釋應用於 bean 屬性的 setter 方法,它代表受影響的 bean 屬性在配置時必須放在 XML 配置文件中,不然容器就會拋出一個 BeanInitializationException 異常。
<bean id="resultMessage" class="com.jake.ResultMessage"> <property name="code" value="001" /><!--設置屬性--> </bean>
使用<context:annotation-config/>會隱式地註冊RequiredAnnotationBeanPostProcessor,使@Required註解生效,若是沒有就必須在xml文件中配置RequiredAnnotationBeanPostProcessor bean。
注意:@Required只能設置在setter方法上
@ExceptionHandler只有一個參數,能夠是一個數組,表示要捕獲的異常。
@ResponseStatus
註解中有兩個參數,value屬性設置異常的狀態碼,reaseon是異常的描述。
狀態碼定義在HttpStatus上。
RequestMapping是一個用來處理請求地址映射的註解,可用於類或方法上。用於類上,表示類中的全部響應請求的方法都是以該地址做爲父路徑。
@RequestMapping 除了修飾方法, 還可來修飾類 :
RequestMapping註解有六個屬性,下面咱們把它分紅三類進行說明:
從字面意思能夠看出這個的做用是給Binder作初始化的,被此註解的方法能夠對WebDataBinder初始化。WebDataBinder是用於表單到方法的數據綁定的!
@InitBinder只在@Controller中註解方法來爲這個控制器註冊一個綁定器初始化方法,方法只對本控制器有效。
1. 對數據綁定進行設置
WebDataBinder中有不少方法能夠對數據綁定進行具體的設置:好比咱們設置name屬性爲非綁定屬性(也能夠設置綁定值setAllowedFields):
@InitBinder public void initBinder(WebDataBinder binder) { //setDisallowedFields表示禁止接收的參數 binder.setDisallowedFields("name"); }
2. 註冊已有的編輯器
WebDataBinder是用來綁定請求參數到指定的屬性編輯器.因爲前臺傳到controller裏的值是String類型的,當往Model裏Set這個值的時候,若是set的這個屬性是個對象,Spring就會去找到對應的editor進行轉換,而後再set進去!Spring本身提供了大量的實現類(在org.springframwork.beans.propertyEditors下的全部editor),諸如CustomDateEditor ,CustomBooleanEditor,CustomNumberEditor等許多,基本上夠用。 在平時使用SpringMVC時,會碰到javabean中有Date類型參數,表單中傳來表明日期的字符串轉化爲日期類型,SpringMVC默認不支持這種類型的轉換。咱們就須要手動設置時間格式並在webDateBinder上註冊這個編輯器!
//這裏咱們在@RequestMapping參數上就能夠直接使用Date類型的參數。 CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true); binder.registerCustomEditor(Date.class, editor);
3. 註冊自定義編輯器
用自定義編輯器就是在第二個的基礎上添加個自定義編輯器就好了,自定義的編輯器類須要繼承org.springframework.beans.propertyeditors.PropertiesEditor;,並重寫setAsText和getAsText兩個方法就好了!
好比下面這個DoubleEditor:
public class DoubleEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { if (text == null || text.equals("")) { text = "0"; } setValue(Double.parseDouble(text)); } @Override public String getAsText() { return getValue().toString(); } }
4. 設置屬性的前綴能夠實現參數綁定
form表單:
<form action="/testBean" method="post"> name: <input type="text" name="u.name"> <br> age: <input type="text" name="u.age"> <br> name: <input type="text" name="s.name"> <br> age: <input type="text" name="s.age"> <br> <input type="submit"> </form>
Controller:
@InitBinder("user") public void init1(WebDataBinder binder) { binder.setFieldDefaultPrefix("u."); } @InitBinder("stu") public void init2(WebDataBinder binder) { binder.setFieldDefaultPrefix("s."); } @RequestMapping("/testBean") public ModelAndView testBean(User user, @ModelAttribute("stu") Student stu) { System.out.println(stu); System.out.println(user); String viewName = "success"; ModelAndView modelAndView = new ModelAndView(viewName); modelAndView.addObject("user", user); modelAndView.addObject("student", stu); return modelAndView; }
@PathVariable 映射 URL 綁定的佔位符:
如:
<a href="springmvc/testPathVariable/1">testPathVariable</a>
//@PathVariable能夠用來映射URL中的佔位符到目標方法的參數中 @RequestMapping("/testPathVariable/{id}") public String testPathVariable(@PathVariable("id") Integer id){ System.out.println("testPathVariable:"+id); return SUCCESS; }
REST的支持
- /order/1 HTTP GET :獲得 id = 1 的 order
- /order/1 HTTP DELETE:刪除 id = 1的 order
- /order/1 HTTP PUT:更新id = 1的 order
- /order HTTP POST:新增 order
HiddenHttpMethodFilter:瀏覽器 form 表單只支持 GET與 POST 請求,而DELETE、PUT 等 method 並不支持,Spring3.0 添加了一個過濾器,能夠將這些請求轉換爲標準的 http 方法,使得支持 GET、POST、PUT 與DELETE 請求。
<!-- 配置org.springframework.web.filter.HiddenHttpMethodFilter:能夠把POST請求轉換成DELETE或者POST請求 --> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
1. @RequestHeader
@RequestHeader 註解,能夠把Request請求header部分的值綁定到方法的參數上。
這是一個Request 的header部分:
2. @RequestParam
在SpringMvc後臺進行獲取數據,通常是兩種。
@RequestParam 有三個屬性:
(1) value:請求參數名(必須配置)
(2) required:是否必需,默認爲 true,即 請求中必須包含該參數,若是沒有包含,將會拋出異常(可選配置)
(3) defaultValue:默認值,若是設置了該值,required 將自動設爲 false,不管你是否配置了required,配置了什麼值,都是 false(可選配置)
值得注意的是:若是方法上的@RequestMapping 配置了 params 屬性,則請求中也必須包含該參數。
//能夠對傳入參數指定參數名: // 下面的對傳入參數指定爲aa,若是前端不傳aa參數名,會報錯 @RequestParam(value="aa") String inputStr //能夠經過required=false或者true來要求@RequestParam配置的前端參數是否必定要傳 // required=false表示不傳的話,會給參數賦值爲null,required=true就是必需要有 @RequestMapping("testRequestParam") public String filesUpload(@RequestParam(value="aa", required=true) String inputStr, HttpServletRequest request) /**若是@requestParam註解的參數是int類型,而且required=false,此時若是不傳參數的話,會報錯。緣由是,required=false時,不傳參數的話,會給參數賦值null,這樣就會把null賦值給了int,所以會報錯。*/ // required=false表示不傳的話,會給參數賦值爲null,required=true就是必需要有 @RequestMapping("testRequestParam") public String filesUpload(@RequestParam(value="aa", required=false) int inputStr, HttpServletRequest request) //如果前端頁面不傳參的話,此處就會報錯。固然能夠用Integer代替int