spring-boot-learning-REST風格網站
阿新 • • 發佈:2020-09-07
什麼是REST風格:
Representational State Transfer :表現層狀態轉換,實際上是一種風格。標準,約定
首先需要有資源才能表現, 所以第一個名詞是“ 資源”。有了資源也要根
據需要以合適的形式表現資源,這就是第二個名詞一一表現層。最後是資源可以被新增、修改、刪
除等,也就是第三個名詞“狀態轉換”。
資源: 它可以是系統許可權使用者、角色和選單等,也可以是一些媒體型別, 如文字、圖片、歌曲,總之它就是一個具體存在的
物件。可以用一個URI ( Unifonn Resource Identifier ,統一資源定位符)指向它, 每個資源對應一個特定的U陽。要獲取這個資源, 訪問它的U陽即可,而在REST 中每一個資源都會對應一個獨一無二的U阻。在阻ST 中, URI 也可以稱
為端點(End Point ) 。
表現層: 有了資源還需要確定如何表現這個資源。例如, 一個使用者可以使用JSON 、XML 或者其他的形式表現出來,又如
可能返回的是一幅圖片。在現今的網際網路開發中, JSON 資料集己經是一種最常用的表現形式
REST風格當中,每一個資源都只是對應一個網址,而一個資源網址應該是一個名詞,不存在動詞。
URI (Unifonn Resource Identifier)統一資源定位符
REST風格其實就是一種約定問題,不同的http請求對應的不同的資源操作,
@GetMapping
/** * RestController,作用是使返回的結果能夠以json資料集的方法進行返回 * 轉換為JSTL或者json * 11預設將方法或者類標註為application/json;charset=UTF-8 * 22方法執行結束後,spring會遍歷註冊號的HttpMessageConverter介面 * 的實現類。 * 33註冊好的MappingJackson2HttpMessageConverter就會放回true, * 啟動轉換器將結果轉換為JSON資料集 */ @RestController @RequestMapping("annotation") public class RedisUserController { @Autowired private UserService userService =null; /** * http的get請求,獲取資源 * @param id * @return */ @GetMapping("/{id}") public User getUser(@PathVariable("id") Long id){ System.out.println(System.currentTimeMillis()); User user = userService.getUser(id); System.out.println(System.currentTimeMillis()); return user; }
請求:
@PostMapping
/** * http的post請求,建立資源 * @param userName * @param note * @return */ @PostMapping() public User insertUser( @RequestParam ("userName") String userName, @RequestParam ("note") String note ){ User user = new User(); user.setUserName(userName); user.setNote(note); userService.insertUser(user); return user; }
請求結果;
@DeleteMapping
/** * http的Delete請求,刪除伺服器資源 * @param id * @return */ @DeleteMapping("{id}") public int delUser(@PathVariable("id") Long id){ return userService.deleteUser(id); }
從資料庫中刪除了id為44員工
@PutMapping
@PatchMapping
/** * http Put請求,提交所有的資源屬性以修改資源, * http patch請求,提交資源的部分修改屬性, * 其實他們兩個都差不多,只不過是約定的問題而已 * @param id * @param userName * @return */ @PatchMapping("/user/{id}") public User updUser( @PathVariable("id") Long id, @RequestParam("userName") String userName ){ return userService.updateUser(id,userName); }
修改之前的:
處理HTTP請求狀態碼,異常和響應頭
通過實體類去實現;
/** * 當發生資源找不到或者處理邏輯發生異常時,需要考慮返回給客戶端的http狀態碼和錯誤訊息 * spring提供實體封裝類ResponseEntity:有效的封裝錯誤訊息和狀態碼 * 和註解@ResponseStatus:配置指定的響應碼給客戶端 */ @RestController public class HttpStatusController { @Autowired UserService userService; /** * 11新建一個請求頭物件, * 22向請求頭通過add方法進行加入k-v * 33需要建立一個響應實體類,將需要放回的資訊,請求頭物件,響應http狀態碼 * 備註:這裡使用 HttpStatus.CREATED ,指定狀態碼為201,標識資源建立成功 * @param userName * @param note * @return */ @PostMapping("/http/status") public ResponseEntity<Integer> insertUser( @RequestParam("userName") String userName, @RequestParam ("note") String note ){ User user = new User(); user.setUserName(userName); user.setNote(note); Integer re = userService.insertUser(user); // 設定http響應頭 HttpHeaders httpHeaders = new HttpHeaders();//新建請求頭 String success = (re == 0 ) ? "false" : "true";//如果結果為0,就是false httpHeaders.add("success",success); return new ResponseEntity<Integer>(re,httpHeaders, HttpStatus.CREATED); }
使用註解:
/** * 通過註解@ResponseStatus去指定 * 當方法正常返回的時候,http狀態碼為201 * @param userName * @param note * @return */ @PostMapping("/http/status/an") @ResponseStatus(HttpStatus.CREATED) public Integer insertUseran( @RequestParam("userName") String userName, @RequestParam ("note") String note ){ User user = new User(); user.setUserName(userName); user.setNote(note); Integer re = userService.insertUser(user); return re; } }
異常處理;
定義一個執行時的異常:
//場景:執行的時候,查詢id使用者,找不到資料或出現異常,這時候不能以正常返回去處理。 /** * 11自定義異常類:找不到使用者的時候丟擲異常 * 異常丟擲後,可以在控制器通知@ControllerAdvice裡面進行處理 * @ControllerAdvice:定義控制器通知 * @ExceptionHandler:指定異常發生的處理方法 *繼承的異常RuntimeException是指:執行時的異常,和我們普通的 * Exception:受檢查的異常,這種異常是強制我們catch或throw的異常。 * 你遇到這種異常必須進行catch或throw,如果不處理,編譯器會報錯。 * */ public class NotFoundException extends RuntimeException{ public static final long serialVersionUID = 1L; private Long code;//異常編碼 private String customMsg;//異常自定義訊息 public NotFoundException() { } public NotFoundException(Long code, String customMsg) { super(); this.code = code; this.customMsg = customMsg; } public Long getCode() { return code; } public void setCode(Long code) { this.code = code; } public String getCustomMsg() { return customMsg; } public void setCustomMsg(String customMsg) { this.customMsg = customMsg; } }
定義一個控制器通知:
/** * 2自定義一個控制器通知 * 在@ControllerAdvice中指定攔截包路徑,限定被攔截的註解為@Controller/@RestController * 在@ExceptionHandler註解方法上,通過value屬性,指定異常型別進行攔截 * 在@ResponseBody定義響應的資訊已json的格式表達 * 在@ResponseStatus定義伺服器內部錯誤500程式碼 */ @ControllerAdvice( basePackages = {"com.quan.annotationredis.controller.*"}, annotations = {Controller.class, RestController.class} ) public class UserControllerAdvice { @ExceptionHandler(value = NotFoundException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)//定義伺服器錯誤程式碼 @ResponseBody public Map<String,Object> exception(HttpServletRequest request, NotFoundException ex){ Map<String,Object> msgMap = new HashMap<>(); msgMap.put("code",ex.getCode()); msgMap.put("message",ex.getCustomMsg()); return msgMap; } }
測試controller:
@Controller public class ExceptionController { @Autowired UserService userService; /** * 一旦方法出現異常,就會別控制器通知所攔截,最後經@ExceptionHandler定義 * 的方法進行處理。 * @param id * @return */ @GetMapping("/exception/{id}") @ResponseStatus(HttpStatus.OK) @ResponseBody public User getUser(@PathVariable("id") Long id){ System.out.println(System.currentTimeMillis()); User user = userService.getUser(id); if (user == null){ throw new NotFoundException(1L,"找不到使用者"+id+"的資訊"); } System.out.println(System.currentTimeMillis()); return user; } }
使用RestTemplate請求後端;
底層是通過類HttpURLConnection實現的。
/** * restTemplate.getForObject方法中: * 第一個引數URL:標明請求伺服器什麼資源,{id}代表引數 * 第二個引數:表示將請求返回User類的結果,實際上伺服器只會給回我們json格式資料 * 是因為restTemplate內部將其轉化給java物件。 * 第三個引數:就是URL對應的引數。 * @return */ private static User getUser() { int id = 1; RestTemplate restTemplate = new RestTemplate(); User user = restTemplate.getForObject( "http://localhost:8012/annotation/{id}", User.class, id ); System.out.println(user.getUserName()); return user; } }
輸出的日誌結果:
14:10:42.839 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:8012/annotation/1 14:10:42.904 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json] 14:10:42.921 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK 14:10:42.924 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [com.quan.annotationredis.entity.User] gangganghao
多個引數的時候:
@RestController @RequestMapping("annotation") public class RedisUserController { @Autowired private UserService userService =null; @PostMapping("/{userName}/{note}") public User insertUser( @PathVariable ("userName") String userName, @PathVariable ("note") String note ){ User user = new User(); user.setUserName(userName); user.setNote(note); userService.insertUser(user); return user; }
將引數用一個Map物件封裝起來,Map的鍵名稱和URI中所定義的引數時保持一致的。這樣子就能將引數統一封裝到Map中了
/** *因為我們的Controller層返回的是User型別,所以我們這裡也放回User,並使用ResponseEntity<User>接受 * postForEntity ,通過post請求返回一個實體類,需要url,請求型別,返回型別,引數列表 * responseEntity.getBody();通過類的方法從返回體裡面拿到返回體的內容。(contorller裡面是返回user) * @return */ public static User insertUser(){ RestTemplate restTemplate = new RestTemplate(); String userName = "huolalala"; String note = "huolalanote"; String url = "http://localhost:8012/annotation/{userName}/{note}"; Map<String,Object> params = new HashMap<>(); params.put("userName",userName); params.put("note",note); ResponseEntity<User> responseEntity = restTemplate.postForEntity(url,User.class,User.class,params); User user = responseEntity.getBody(); System.out.println(user); return user; }
執行日誌;
14:55:47.888 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP POST http://localhost:8012/annotation/huolalala/huolalanote 14:55:47.948 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json] 14:55:47.966 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [class com.quan.annotationredis.entity.User] with org.springframework.http.converter.json.MappingJackson2HttpMessageConverter 14:55:47.987 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK 14:55:47.990 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [com.quan.annotationredis.entity.User] User{id=49, userName='huolalala', note='huolalanote'}
請求體獲取引數:
/** * 11先定義請求頭HttpHeaders,設定請求體為JSON格式 * 22將請求體實體user和請求頭繫結到請求實體物件HttpEntiry * 33restTemplate.postForObject將請求物件傳遞過去, * @return */ public static User insertUser1(){ User user = new User(); user.setNote("RRRR"); user.setUserName("QQQQ"); HttpHeaders httpheaders = new HttpHeaders(); httpheaders.setContentType(MediaType.APPLICATION_JSON_UTF8); HttpEntity<User> httpEntity = new HttpEntity<>(user,httpheaders); RestTemplate restTemplate = new RestTemplate(); restTemplate.postForObject("http://localhost:8012/annotation",httpEntity,User.class); return user; }
刪除:
/** * */ public static void delUser(){ Long id = 48L; RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8012/annotation/{id}"; restTemplate.delete(url,id);//這個方法沒有返回值 }
執行日誌:
17:09:06.618 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP DELETE http://localhost:8012/annotation/48 17:09:06.639 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK