springmvc常用註解配置說明@[
關於SpringMVC中@Requestmapping的相關配置可以參考下面文章:
URL中的變數——PathVariable
在Web應用中URL通常不是一成不變的,例如微博兩個不同使用者的個人主頁對應兩個不同的URL: http://weibo.com/user1 和 http://weibo.com/user2。 我們不可能對於每一個使用者都編寫一個被@RequestMapping
註解的方法來處理其請求,Spring MVC提供了一套機制來處理這種情況:
@RequestMapping("/users/{username}") public String userProfile(@PathVariable("username") String username) { return String.format("user %s", username); } @RequestMapping("/posts/{id}") public String post(@PathVariable("id") int id) { return String.format("post %d", id); }
在上述例子中,URL中的變數可以用{variableName}
來表示,同時在方法的引數中加上@PathVariable("variableName")
,那麼當請求被轉發給該方法處理時,對應的URL中的變數會被自動賦值給被@PathVariable
註解的引數(能夠自動根據引數型別賦值,例如上例中的int
)。
支援HTTP方法
對於HTTP請求除了其URL,還需要注意它的方法(Method)。例如我們在瀏覽器中訪問一個頁面通常是GET方法,而表單的提交一般是POST方法。@Controller
中的方法同樣需要對其進行區分:
@RequestMapping(value = "/login", method = RequestMethod.GET) public String loginGet() { return "Login Page"; } @RequestMapping(value = "/login", method = RequestMethod.POST) public String loginPost() { return "Login Post Request"; }
Spring MVCSpring 4.3的版本中提供了一種更加簡潔的配置HTTP方法的方式,增加了四個標註:
@PutMapping
@GetMapping
@PostMapping
@DeleteMapping
在Web應用中常用的HTTP方法有四種:
- PUT方法用來新增的資源
- GET方法用來獲取已有的資源
- POST方法用來對資源進行狀態轉換
- DELETE方法用來刪除已有的資源
這四個方法可以對應到CRUD操作(Create、Read、Update和Delete),比如部落格的建立操作,按照REST風格設計URL就應該使用PUT方法,讀取部落格使用GET方法,更新部落格使用POST方法,刪除部落格使用DELETE方法。
每一個Web請求都是屬於其中一種,在Spring MVC中如果不特殊指定的話,預設是GET請求。
比如@RequestMapping("/")
和@RequestMapping("/hello")
和對應的Web請求是:
- GET
/
- GET
/hello
實際上@RequestMapping("/")
是@RequestMapping("/", method = RequestMethod.GET)
的簡寫,即可以通過method
屬性,設定請求的HTTP方法。
比如PUT /hello
請求,對應於@RequestMapping("/hello", method = RequestMethod.PUT)
基於新的標註@RequestMapping("/hello", method = RequestMethod.PUT)
可以簡寫為@PutMapping("/hello")
。@RequestMapping("/hello")
與GetMapping("/hello")
等價。
模板渲染
在之前所有的@RequestMapping
註解的方法中,返回值字串都被直接傳送到瀏覽器端並顯示給使用者。但是為了能夠呈現更加豐富、美觀的頁面,我們需要將HTML程式碼返回給瀏覽器,瀏覽器再進行頁面的渲染、顯示。
一種很直觀的方法是在處理請求的方法中,直接返回HTML程式碼,但是這樣做的問題在於——一個複雜的頁面HTML程式碼往往也非常複雜,並且嵌入在Java程式碼中十分不利於維護。更好的做法是將頁面的HTML程式碼寫在模板檔案中,渲染後再返回給使用者。為了能夠進行模板渲染,需要將@RestController
改成@Controller
:
import org.springframework.ui.Model;
@Controller
public class HelloController {
@RequestMapping("/hello/{name}")
public String hello(@PathVariable("name") String name, Model model) {
model.addAttribute("name", name);
return "hello"
}
}
在上述例子中,返回值"hello"
並非直接將字串返回給瀏覽器,而是尋找名字為hello
的模板進行渲染,我們使用Thymeleaf模板引擎進行模板渲染,需要引入依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
接下來需要在預設的模板資料夾src/main/resources/templates/
目錄下新增一個模板檔案hello.html
:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>
th:text="'Hello, ' + ${name} + '!'"
也就是將我們之前在@Controller
方法裡新增至Model
的屬性name
進行渲染,並放入<p>
標籤中(因為th:text
是<p>
標籤的屬性)。模板渲染還有更多的用法,請參考Thymeleaf官方文件。
處理靜態檔案
瀏覽器頁面使用HTML作為描述語言,那麼必然也脫離不了CSS以及JavaScript。為了能夠瀏覽器能夠正確載入類似/css/style.css
, /js/main.js
等資源,預設情況下我們只需要在src/main/resources/static
目錄下新增css/style.css
和js/main.js
檔案後,Spring MVC能夠自動將他們釋出,通過訪問/css/style.css
, /js/main.js
也就可以正確載入這些資源。
檔案上傳
Spring MVC還能夠支援更為複雜的HTTP請求——檔案資源。我們在網站中經常遇到上傳圖片、附件一類的需求,就是通過檔案上傳技術來實現的。
處理檔案的表單和普通表單的唯一區別在於設定enctype
——multipart編碼方式則需要設定enctype
為multipart/form-data
。
<form method="post" enctype="multipart/form-data">
<input type="text" name="title" value="tianmaying">
<input type="file" name="avatar">
<input type="submit">
</form>
這裡我們還設定了
<input type='text'>
的預設值為tianmaying
。
該表單將會顯示為一個文字框、一個檔案按鈕、一個提交按鈕。然後我們選擇一個檔案:chrome.png
,點選表單提交後產生的請求可能是這樣的:
請求頭:
POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
請求體:
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="title"
tianmaying
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="avatar"; filename="chrome.png"
Content-Type: image/png
... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
這便是一個multipart編碼的表單。Content-Type
中還包含了boundary
的定義,它用來分隔請求體中的每個欄位。正是這一機制,使得請求體中可以包含二進位制檔案(當然檔案中不能包含boundary
)。檔案上傳正是利用這種機制來完成的。
如果不設定<form>
的enctype
編碼,同樣可以在表單中設定type=file
型別的輸入框,但是請求體和傳統的表單一樣,這樣伺服器程式無法獲取真正的檔案內容。
在服務端,為了支援檔案上傳我們還需要進行一些配置。
控制器邏輯
對於表單中的文字資訊輸入,我們可以通過@RequestParam
註解獲取。對於上傳的二進位制檔案(文字檔案同樣會轉化為byte[]
進行傳輸),就需要藉助Spring提供的MultipartFile
類來獲取了:
@Controller
public class FileUploadController {
@PostMapping("/upload")
@ResponseBody
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
byte[] bytes = file.getBytes();
return "file uploaded successfully."
}
}
通過MultipartFile
的getBytes()
方法即可以得到上傳的檔案內容(<form>
中定義了一個type="file"
的,在這裡我們可以將它儲存到本地磁碟。另外,在預設的情況下Spring僅僅支援大小為128KB的檔案,為了調整它,我們可以修改Spring的配置檔案src/main/resources/application.properties
:
multipart.maxFileSize: 128KB
multipart.maxRequestSize: 128KB
修改上述數值即可完成配置。
HTML表單
HTML中支援檔案上傳的表單元素仍然是<input>
,只不過它的型別是file
:
<html>
<body>
<form method="POST" enctype="multipart/form-data" action="/upload">
File to upload: <input type="file" name="file"><br />
Name: <input type="text" name="name"><br /> <br />
<input type="submit" value="Upload"> Press here to upload the file!
</form>
</body>
</html>
multipart/form-data
表單既可以上傳檔案型別,也可以和普通表單一樣提交其他型別的資料,在Spring MVC的@RequestMapping
方法引數中用@RequestParam
標註即可(也可以利用資料繫結機制,繫結一個物件)
攔截器Interceptor
Spring MVC框架中的Interceptor,與Servlet API中的Filter十分類似,用於對Web請求進行預處理/後處理。通常情況下這些預處理/後處理邏輯是通用的,可以被應用於所有或多個Web請求,例如:
- 記錄Web請求相關日誌,可以用於做一些資訊監控、統計、分析
- 檢查Web請求訪問許可權,例如發現使用者沒有登入後,重定向到登入頁面
- 開啟/關閉資料庫連線——預處理時開啟,後處理關閉,可以避免在所有業務方法中都編寫類似程式碼,也不會忘記關閉資料庫連線
Spring MVC請求處理流程
上圖是Spring MVC框架處理Web請求的基本流程,請求會經過DispatcherServlet
的分發後,會按順序經過一系列的Interceptor
並執行其中的預處理方法,在請求返回時同樣會執行其中的後處理方法。
在DispatcherServlet
和Controller
之間哪些豎著的彩色細條,是攔截請求進行額外處理的地方,所以命名為攔截器(Interceptor)。
HandlerInterceptor介面
Spring MVC中攔截器是實現了HandlerInterceptor
介面的Bean:
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception;
void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception;
void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) throws Exception;
}
preHandle()
:預處理回撥方法,若方法返回值為true
,請求繼續(呼叫下一個攔截器或處理器方法);若方法返回值為false
,請求處理流程中斷,不會繼續呼叫其他的攔截器或處理器方法,此時需要通過response
產生響應;postHandle()
:後處理回撥方法,實現處理器的後處理(但在渲染檢視之前),此時可以通過ModelAndView
對模型資料進行處理或對檢視進行處理afterCompletion()
:整個請求處理完畢回撥方法,即在檢視渲染完畢時呼叫
HandlerInterceptor
有三個方法需要實現,但大部分時候可能只需要實現其中的一個方法,HandlerInterceptorAdapter
是一個實現了HandlerInterceptor
的抽象類,它的三個實現方法都為空實現(或者返回true
),繼承該抽象類後可以僅僅實現其中的一個方法:
public class Interceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 在controller方法呼叫前列印資訊
System.out.println("This is interceptor.");
// 返回true,將強求繼續傳遞(傳遞到下一個攔截器,沒有其它攔截器了,則傳遞給Controller)
return true;
}
}
配置Interceptor
定義HandlerInterceptor
後,需要建立WebMvcConfigurerAdapter
在MVC配置中將它們應用於特定的URL中。一般一個攔截器都是攔截特定的某一部分請求,這些請求通過URL模型來指定。
下面是一個配置的例子:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
@ModelAttribute
方法使用@ModelAttribute標註
@ModelAttribute
標註可被應用在方法或方法引數上。
標註在方法上的@ModelAttribute
說明方法是用於新增一個或多個屬性到model上。這樣的方法能接受與@RequestMapping
標註相同的引數型別,只不過不能直接被對映到具體的請求上。
在同一個控制器中,標註了@ModelAttribute
的方法實際上會在@RequestMapping
方法之前被呼叫。
以下是示例:
// Add one attribute
// The return value of the method is added to the model under the name "account"
// You can customize the name via @ModelAttribute("myAccount")
@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountManager.findAccount(number);
}
// Add multiple attributes
@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
model.addAttribute(accountManager.findAccount(number));
// add more ...
}
@ModelAttribute
方法通常被用來填充一些公共需要的屬性或資料,比如一個下拉列表所預設的幾種狀態,或者寵物的幾種型別,或者去取得一個HTML表單渲染所需要的命令物件,比如Account
等。
@ModelAttribute
標註方法有兩種風格:
- 在第一種寫法中,方法通過返回值的方式預設地將新增一個屬性;
- 在第二種寫法中,方法接收一個
Model
物件,然後可以向其中新增任意數量的屬性。
可以在根據需要,在兩種風格中選擇合適的一種。
一個控制器可以擁有多個@ModelAttribute
方法。同個控制器內的所有這些方法,都會在@RequestMapping
方法之前被呼叫。
@ModelAttribute
方法也可以定義在@ControllerAdvice
標註的類中,並且這些@ModelAttribute
可以同時對許多控制器生效。
屬性名沒有被顯式指定的時候又當如何呢?在這種情況下,框架將根據屬性的型別給予一個預設名稱。舉個例子,若方法返回一個
Account
型別的物件,則預設的屬性名為"account"。可以通過設定@ModelAttribute
標註的值來改變預設值。當向Model
中直接新增屬性時,請使用合適的過載方法addAttribute(..)
-即帶或不帶屬性名的方法。
@ModelAttribute
標註也可以被用在@RequestMapping
方法上。這種情況下,@RequestMapping
方法的返回值將會被解釋為model的一個屬性,而非一個檢視名,此時檢視名將以檢視命名約定來方式來確定。
方法引數使用@ModelAttribute標註
@ModelAttribute
標註既可以被用在方法上,也可以被用在方法引數上。
標註在方法引數上的@ModelAttribute
說明了該方法引數的值將由model中取得。如果model中找不到,那麼該引數會先被例項化,然後被新增到model中。在model中存在以後,請求中所有名稱匹配的引數都會填充到該引數中。
這在Spring MVC中被稱為資料繫結,一個非常有用的特性,我們不用每次都手動從表格資料中轉換這些欄位資料。
@RequestMapping(path = "/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Pet pet) { }
以上面的程式碼為例,這個Pet型別的例項可能來自哪裡呢?有幾種可能:
- 它可能因為
@SessionAttributes
標註的使用已經存在於model中 - 它可能因為在同個控制器中使用了
@ModelAttribute
方法已經存在於model中——正如上一小節所敘述的 - 它可能是由URI模板變數和型別轉換中取得的(下面會詳細講解)
- 它可能是呼叫了自身的預設構造器被例項化出來的
@ModelAttribute
方法常用於從資料庫中取一個屬性值,該值可能通過@SessionAttributes
標註在請求中間傳遞。在一些情況下,使用URI模板變數和型別轉換的方式來取得一個屬性是更方便的方式。這裡有個例子:
@RequestMapping(path = "/accounts/{account}", method = RequestMethod.PUT)
public String save(@ModelAttribute("account") Account account) {
}
這個例子中,model屬性的名稱("account")與URI模板變數的名稱相匹配。如果配置了一個可以將String
型別的賬戶值轉換成Account
型別例項的轉換器Converter<String, Account>
,那麼上面這段程式碼就可以工作的很好,而不需要再額外寫一個@ModelAttribute
方法。
下一步就是資料的繫結。WebDataBinder
類能將請求引數——包括字串的查詢引數和表單欄位等——通過名稱匹配到model的屬性上。成功匹配的欄位在需要的時候會進行一次型別轉換(從String型別到目標欄位的型別),然後被填充到model對應的屬性中。
進行了資料繫結後,則可能會出現一些錯誤,比如沒有提供必須的欄位、型別轉換過程的錯誤等。若想檢查這些錯誤,可以在標註了@ModelAttribute
的引數緊跟著宣告一個BindingResult
引數:
@RequestMapping(path = "/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
拿到BindingResult
引數後,可以檢查是否有錯誤,可以通過Spring的<errors>
表單標籤來在同一個表單上顯示錯誤資訊。
BindingResult
被用於記錄資料繫結過程的錯誤,因此除了資料繫結外,還可以把該物件傳給自己定製的驗證器來呼叫驗證。這使得資料繫結過程和驗證過程出現的錯誤可以被蒐集到一起,然後一併返回給使用者:
@RequestMapping(path = "/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "petForm";
}
// ...
}
又或者可以通過新增一個JSR-303規範的@Valid
標註,這樣驗證器會自動被呼叫。
@RequestMapping(path = "/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
異常處理
Spring MVC框架提供了多種機制用來處理異常,初次接觸可能會對他們用法以及適用的場景感到困惑。現在以一個簡單例子來解釋這些異常處理的機制。
假設現在我們開發了一個部落格應用,其中最重要的資源就是文章(Post),應用中的URL設計如下:
- 獲取文章列表:
GET /posts/
- 新增一篇文章:
POST /posts/
- 獲取一篇文章:
GET /posts/{id}
- 更新一篇文章:
PUT /posts/{id}
- 刪除一篇文章:
DELETE /posts/{id}
這是非常標準的複合RESTful風格的URL設計,在Spring MVC實現的應用過程中,相應也會有5個對應的用@RequestMapping
註解的方法來處理相應的URL請求。在處理某一篇文章的請求中(獲取、更新、刪除),無疑需要做這樣一個判斷——請求URL中的文章id是否在於系統中,如果不存在需要返回404 Not Found
。
使用HTTP狀態碼
在預設情況下,Spring MVC處理Web請求時如果發現存在沒有應用程式碼捕獲的異常,那麼會返回HTTP 500(Internal Server Error)錯誤。但是如果該異常是我們自己定義的並且使用@ResponseStatus
註解進行修飾,那麼Spring MVC則會返回指定的HTTP狀態碼:
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No Such Post")//404 Not Found
public class PostNotFoundException extends RuntimeException {
}
在Controller
中可以這樣使用它:
@RequestMapping(value = "/posts/{id}", method = RequestMethod.GET)
public String showPost(@PathVariable("id") long id, Model model) {
Post post = postService.get(id);
if (post == null) throw new PostNotFoundException("post not found");
model.addAttribute("post", post);
return "postDetail";
}
這樣如果我們訪問了一個不存在的文章,那麼Spring MVC會根據丟擲的PostNotFoundException
上的註解值返回一個HTTP 404 Not Found給瀏覽器。
最佳實踐
上述場景中,除了獲取一篇文章的請求,還有更新和刪除一篇文章的方法中都需要判斷文章id是否存在。在每一個方法中都加上if (post == null) throw new PostNotFoundException("post not found");
是一種解決方案,但如果有10個、20個包含/posts/{id}
的方法,雖然只有一行程式碼但讓他們重複10次、20次也是非常不優雅的。
為了解決這個問題,可以將這個邏輯放在Service中實現:
@Service
public class PostService {
@Autowired
private PostRepository postRepository;
public Post get(long id) {
return postRepository.findById(id)
.orElseThrow(() -> new PostNotFoundException("post not found"));
}
}
這裡`PostRepository`繼承了`JpaRepository`,可以定義`findById`方法返回一個`Optional<Post>`——如果不存在則Optional為空,丟擲異常。
這樣在所有的Controller
方法中,只需要正常獲取文章即可,所有的異常處理都交給了Spring MVC。
在Controller
中處理異常
Controller
中的方法除了可以用於處理Web請求,還能夠用於處理異常處理——為它們加上@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 the 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 exception) {
logger.error("Request: " + req.getRequestURL() + " raised " + exception);
ModelAndView mav = new ModelAndView();
mav.addObject("exception", exception);
mav.addObject("url", req.getRequestURL());
mav.setViewName("error");
return mav;
}
}
首先需要明確的一點是,在Controller
方法中的@ExceptionHandler
方法只能夠處理同一個Controller
中丟擲的異常。這些方法上同時也可以繼續使用@ResponseStatus
註解用於返回指定的HTTP狀態碼,但同時還能夠支援更加豐富的異常處理:
- 渲染特定的檢視頁面
- 使用
ModelAndView
返回更多的業務資訊
大多數網站都會使用一個特定的頁面來響應這些異常,而不是直接返回一個HTTP狀態碼或者顯示Java異常呼叫棧。當然異常資訊對於開發人員是非常有用的,如果想要在檢視中直接看到它們可以這樣渲染模板(以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提供了和上一節一樣的異常處理能力,但是可以被應用於Spring應用上下文中的所有@Controller
:
@ControllerAdvice
class GlobalControllerExceptionHandler {
@ResponseStatus(HttpStatus.CONFLICT) // 409
@ExceptionHandler(DataIntegrityViolationException.class)
public void handleConflict() {
// Nothing to do
}
}
Spring MVC預設對於沒有捕獲也沒有被@ResponseStatus
以及@ExceptionHandler
宣告的異常,會直接返回500,這顯然並不友好,可以在@ControllerAdvice
中對其進行處理(例如返回一個友好的錯誤頁面,引導使用者返回正確的位置或者提交錯誤資訊):
@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;
}
}
總結
Spring在異常處理方面提供了一如既往的強大特性和支援,那麼在應用開發中我們應該如何使用這些方法呢?以下提供一些經驗性的準則:
- 不要在
@Controller
中自己進行異常處理邏輯。即使它只是一個Controller相關的特定異常,在@Controller
中新增一個@ExceptionHandler
方法處理。 - 對於自定義的異常,可以考慮對其加上
@ResponseStatus
註解 - 使用
@ControllerAdvice
處理通用異常(例如資源不存在、資源存在衝突等)
相關推薦
springmvc常用註解配置說明@<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6537001410001611080415150c0b02253504110d3304170c04070900">[
關於SpringMVC中@Requestmapping的相關配置可以參考下面文章: URL中的變數——PathVariable 在Web應用中URL通常不是一成不變的,例如微博兩個不同使用者的個人主頁對應兩個不同的URL: http://weibo.com/user1
Arch Linux 下Intel + NVIDIA 雙顯示卡3D 遊戲配置(<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="72161d06134032010617131f">[email
下午打了幾場dota2 感覺流暢度還算很不錯的,寫點東西記錄一下。用Arch Linux 的一般來說都會用搜索引擎,所以只說下需要注意的地方即可。 1. steam 自帶的OpenGL 庫是過時的,
SpringMVC基礎<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ad80ede0c2c9c8c1ecd9d9dfc4cfd8d9c8">[email protected]a>註解&P
在總結@ModelAttribute註解功能配合PUT請求方式使用之前,先來總結一下POJO類作為入參接收form表單POST提交方式提交資料。 POJO類接收引數 總的來說POJO類還是與普通的Java Bean類還是特別的相似的,私有的屬性,需要
Spring高級話題<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b29ff2f7dcd3d0ded7">[email protected]a>***註解的工作原理
sso metadata bool logs tcl task ota -c ann 出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy註解 激活Aspe
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="297a595b40474e69685c5d465e405b4c4d">[email protected]a>註解與自動裝配(轉發)
配置 調用方法 support autowired 信息 ann over 反射機制 test 1 配置文件的方法我們編寫spring 框架的代碼時候。一直遵循是這樣一個規則:所有在spring中註入的bean 都建議定義成私有的域變量。並且要配套寫上 get 和 se
Springboot註解<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="260b0b666549485254494a4a4354">[email protected]a>和@RestCon
1.使用@Controller 註解,在對應的方法上,檢視解析器可以解析return 的jsp,html頁面,並且跳轉到相應頁面;若返回json等內容到頁面,則需要加@ResponseBody註解 [email protected]註解,相當於@[email protected
eclipse支援@<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="95d2f0e1e1f0e7d5c6f0e1e1f0e7">[email protected]a>註解使用 -轉載
1. 下載lombok.jar 2.將下載的lombok.jar放在你的eclipse安裝目錄下,如圖: 3.修改eclipse.ini檔案,新增如下兩行配置: -Xbootclasspath/a:lombok.jar -javaage
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="40333032292e27001432212e33212334292f2e212c">[email protected]a>註解事務不回滾
這幾天在專案裡面發現我使用@Transactional註解事務之後,拋了異常居然不回滾。後來終於找到了原因。 如果你也出現了這種情況,可以從下面開始排查。 一、特性先來了解一下@Transactional註解事務的特性吧,可以更好排查問題 1、service類標籤(一般不建議在介面上)上新增@Transa
spring宣告式事務管理方式( 基於tx和aop名字空間的xml配置<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0922495d7b68677a686a7d6066676865">[email
轉自:https://www.cnblogs.com/niceyoo/p/8732891.html 1. 宣告式事務管理分類 宣告式事務管理也有兩種常用的方式, 一種是基於tx和aop名字空間的xml配置檔案,另一種就是基於@Transactional註解。 顯然基於註解的方式更簡單
spring <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e5878a8a91a5a08b84878980bdbdbdbd">[email protected]a>註解程式設計模型分析
@EnableXXXX程式設計模型 在spring boot中,@EnableXXX註解的功能通常是開啟某一種功能。根據某些外部配置自動裝配一些bean,來達到開啟某些功能的目的。光說很抽象,要具體分析。 @Enable模型的實現方式基本有3種。一個基本的@
kafka 消費者優化及配置詳解 <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4c3f3c3e25222b2e232338670c072d2a272d00253f382922293e">[email
自定義屬性和執行工廠 public KafkaListenerContainerFactory<?> batchFactory(){ ConcurrentKafkaListenerContainerFactory<Integer, Stri
springMVC @<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9eddf1f3eef1f0fbf0eab3deccfbedf1ebecfdfbb3">[email protected]
作用: @Component------------------------泛指元件,當元件不好歸類的時候,我們可以使用這個註解進行標註。(Component-------成分; 組分; 零件) @Resource------------------------(資源) @Autowired------
Spring註解<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7e53533e2e0c111817121b">[email protected]a>的使用
@Profile的作用:當容器根據標識啟用對應的@Profile註解時,其所關聯的bean類才會註冊到容器。但容器不能或找不到對應的@Profile,就不生成bean例項。 建立配置類MainConf
Spring註解開發<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="96a5bbbbd6dffbe6f9e4e2">[email protected]a> , FacotryBean 註冊
目錄 @ComponentScan註解用於掃描自己寫的類(@Controller,@Service,@Component,@Repository),用於加入IOC容器中 @Bean 可以把其他包或者自己寫的類加到IOC容器中 @Import 也可以辦
手寫<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="92e0f7f6fbe1d2d1f3f1faf7f3f0fef7">[email protected]a>註解 引數java物件作為ke
1.實現方式說明 本文在---- 手寫redis @ Cacheable註解支援過期時間設定 的基礎之上進行擴充套件。 1.1問題說明: @ Cacheable(key = “'leader'+#p0 +#p1 +#p2” )一般用法,#p0表示方法的第一個引數,#p1表示
手寫<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bdcfd8d9d4cefdfedcded5d8dcdfd1d8">[email protected]a>註解 支援過期時間設定
原理解釋 友情連結 手寫redis @ Cacheable註解引數java物件作為鍵值 @Cacheable註解作用,將帶有該註解方法的返回值存放到redis的的中; 使用方法在方法上使用@Cacheable(鍵=“測試+#P0 + P1
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4f2326213a370f3a2d3a213b3a">[email protected]a>工具Eclipse配置python的pydev
沒辦法,被逼的,幹嘛成功後都要做下記錄,免得以後犯同樣的問題。 首先,電腦裡已經安裝了java環境,同時已經安裝好了eclipse 現在要做的就是配置Eclipse的python的環境,python一般是linux自帶的,不過要注意下puthon的版本。 第一步
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6c3f1c1e05020b213a2f2c22031829011c1815">[email protected]a>等註解不生效
現象 表單資料對應的Java Bean屬性上新增的諸多校驗註解不生效,如下示例: @NotEmpty(message = "規則不能為空", groups = {AppConfigGroup.Add.class,AppConfigGroup.Update.class}) @S
Spring 註解中 @<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="622c0d162c170e0e222c0d16270f12161b">[email protected]a>,@N
首先要清楚的是下邊1,2,3; 且空格是有長度的: 1 @NotNull:不能為null,但可以為empty,沒有Size的約束 2 @NotEmpty :不能為null,且Size>0 3 @NotBlank:只用於String,不能為null且trim()之
spring給容器中註冊元件的幾種方式,1.包掃描+元件標註註解<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0634284664636768">[email protected]a>(
給容器中註冊元件; 1)、包掃描+元件標註註解(@Controller/@Service/@Repository/@Component)[