寫在前面
🛫更多知識總結見SpringBoot 2專欄
🚕本篇知識點總結自尚硅谷雷神的視頻
🚒博主對于該知識尚在學習階段
🚄如果發現存在問題請毫不吝嗇的指出
🚀🚀扎哇太棗糕的博客首頁🚀🚀
文章目錄
- 1 數據響應
- 1.1 數據響應(JSON為例)
- 1.2 數據響應之內容協商
- 2 頁面響應
- 2.1 模板引擎之Thymeleaf
- 2.2 攔截器
- 2.3 文件上傳
1 數據響應
??數據響應一般分為兩種:頁面響應和數據響應,一般來說頁面響應是用來開發一些單體項目(也就是前后端都在一個開發工具中),而數據響應則是用來進行前后端分離開發的項目,前端發送過來請求后端響應相應的數據。
1.1 數據響應(JSON為例)
??如果想讓SpringMVC響應返回一個JSON類型的數據,首先需要在項目的pom.xml文件中導入web場景的啟動器
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!--web場景的啟動器的底層導入了JSON的開發場景-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-json</artifactId><version>2.6.4</version><scope>compile</scope>
</dependency>
??其次就是在controller中加入@ResponseBody注解,這樣的話就是響應數據而不是頁面跳轉,或者將controller上的@Controller注解換成@RestController,相當于這個controller下的所有方法都自動加上了@ResponseBody注解。
1.2 數據響應之內容協商
??內容協商: 服務器會根據客戶端接收能力的不同,返回不同媒體類型的數據。
??原理: 前端發送請求的時候請求頭攜帶Accept字段,用于服務器聲明自己(客戶端)能夠接收的數據類型。
??處理流程: 首先判斷當前響應頭中是否已經有之前處理時緩存的媒體類型,如果沒有的話就是第一次處理需要確定處理的媒體類型,通過Accept字段獲取客戶(PostMan、瀏覽器)支持接收的內容類型。經過遍歷循環所有當前系統的MessageConverter看誰支持操作這個對象(Person),找到支持操作Person的converter之后把它支持的媒體類型統計出來。如此操作我們就得到了客戶端支持接受的類型和服務端能夠返回的類型,再通過內容協商的最佳匹配媒體類型,用支持將對象轉為最佳匹配媒體類型converter。
2 頁面響應
??SpringBoot默認的打包方式是jar包方式,但是JSP不支持在jar包(一種壓縮包)中編譯,所以SpringBoot默認不支持JSP,于是我們需要引入第三方的模板引擎技術——Thymeleaf實現頁面的渲染。
2.1 模板引擎之Thymeleaf
??要想使用Thymeleaf實現頁面的渲染的話,首先需要在pom.xml文件里引入它的場景啟動器依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
??在導入場景啟動器之后,SpringBoot就會給我們在ThymeleafAutoConfiguration自動配置類中配置好所有的相關組件,并將相關配置項與ThymeleafProperties.class(代碼如下)通過注解@EnableConfigurationProperties相關聯,配置類中設置了默認頁面跳轉的前綴和后綴,也就是規范了頁面存放的位置必須是templates文件夾和頁面的文件后綴必須是.html,我們只需要直接開發頁面即可。
private String prefix = "classpath:/templates/";
private String suffix = ".html";
入門案例
第一步: templates文件夾下建個html文件
第二步: <html>標簽引入templates命名空間,這樣的優點就是在進行頁碼編寫的時候會有相關的提示信息xmlns:th="http://www.thymeleaf.org"
第三步: 創建一個controller用于進頁面跳轉
@Controller public class ViewTestController {@GetMapping("/jump")public String jumpTo(Model model) {// 之前講過model的所有屬性值都會存儲在request域中,需要使用的時候直接使用model.addAttribute("msg", "你好,張三");model.addAttribute("link", "http://www.baidu.com");return "seccess";} }
第四步: 編寫頁面代碼獲取域中的值
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><h1 th:text="${msg}">哈哈</h1><h2><a th:href="${link}">點擊進入百度</a><a th:href="@{link}">點擊進入百度</a></h2> </body> </html>
? ?頁面中兩種符號區別:${}是直接獲取到link屬性的值作為鏈接地址,而@{}是拼裝項目的訪問路徑+符號里的值,對本案例而言:第一個鏈接是打開百度,第二個是發送http://localhost:8080/link的請求
2.2 攔截器
??用戶登陸成功之后,再發送任意請求的時候都應該是有個登錄判斷的過程(判斷session中是否有正確的用戶名和密碼),這個功能可以在每個controller使用代碼進行判斷,但是這個過程是重復的會大大增加代碼的冗余,于是我們可以將判斷功能放在攔截器中,將登陸成功后的所有從頁面發送的請求攔截住進行用戶判斷,成功則放行失敗則返回登錄。
??以上述例子為例講解攔截器的使用:
第一步: 自定義攔截器(實現HandlerInterceptor接口,重寫內置方法在相應的方法內編寫判斷邏輯)
public class LoginInterceptor implements HandlerInterceptor {// 在目標方法執行之前執行的方法@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 實現登錄檢查的邏輯HttpSession session = request.getSession();Object user = session.getAttribute("loginUser");if (user != null) {// 已經登錄,放行return true;}// 未登錄,重定向到登錄頁面request.setAttribute("msg", "請先登錄之后再進行相關操作");request.getRequestDispatcher("/").forward(request, response);return false;}// 在目標方法執行之后執行的方法@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}// 頁面渲染之后執行的方法@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
第二步: 自定義配置類實現WebMvcConfigurer接口,重寫addInterceptors方法將攔截器注冊進容器中,并指定攔截規則
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 有個問題就是,攔截器攔截的不只是動態請求,還有靜態的頁面資源和樣式,所以也要將靜態資源放行registry.addInterceptor(new LoginInterceptor())// 攔截所有的請求.addPathPatterns("/**")// 直接放行的請求.excludePathPatterns("/", "/login", "/css/**", "/fonts/**", "/js/**", "/images/**");}
}
2.3 文件上傳
??文件上傳需要前后端的協調配合,前端使用一個form表單提交所有的信息,包括單文件上傳和多文件上傳,后端使用注解獲取到表單中的所有值,對他們進行操作
前端表單:
<form role="form" th:action="@{/upload}" method="post" enctype="multipart/form-data"><!--email郵箱--><div class="form-group"><label for="exampleInputEmail1">Email address</label><input type="email" name="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email"></div><!--userName用戶名--><div class="form-group"><label for="exampleInputPassword1">userName</label><input type="text" name="userName" class="form-control" id="exampleInputPassword1" placeholder="Password"></div><!--單文件上傳 頭像--><div class="form-group"><label for="exampleInputFile">headerImg</label><input type="file" name="headerImg" id="exampleInputFile"></div><!--多文件上傳 生活照--><div class="form-group"><label for="exampleInputFile">image of yourself</label><input type="file" name="photos" multiple ></div><div class="checkbox"><label><input type="checkbox"> Check me out</label></div><button type="submit" class="btn btn-primary">Submit</button>
</form>
后端controller:
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,@RequestParam("userName") String userName,@RequestPart("headerImg")MultipartFile headerImg,@RequestPart("photos")MultipartFile[] photos) throws IOException {// 將頭像保存到本地磁盤中if (!headerImg.isEmpty()) {// 創建相應的文件夾File file1 = new File("E:\\bootTest\\" + userName + "\\headerImg");file1.mkdirs();// 獲取圖片名 生成存儲路徑headerImg.transferTo(new File("E:\\bootTest\\" + userName + "\\headerImg\\" + headerImg.getOriginalFilename()));}// 將生活照保存到本地磁盤中if (photos.length > 0) {// 創建相應的文件夾File file1 = new File("E:\\bootTest\\" + userName + "\\photos");file1.mkdirs();// 存儲圖片for (MultipartFile photo:photos) {if (!photo.isEmpty()) {// 獲取圖片名 生成存儲路徑photo.transferTo(new File("E:\\bootTest\\" + userName + "\\photos\\" + photo.getOriginalFilename()));}}}return "index";
}
文件上傳的配置:
# 文件上傳大小的設置
spring:servlet:multipart:# 單個文件的最大大小max-file-size: 50MB# 總文件的最大大小max-request-size: 100MB