**SpringMVC 筆記二 [共三篇,史上最全重點]*
阿新 • • 發佈:2018-12-17
今日內容:
1. 響應
2. 檔案上傳
3. 異常處理
4. 攔截器[作用不大了,瞭解]
響應
1. 概述:就是把後臺的資料返回給瀏覽器/使用者; 2. 搭建環境: 1. 建立專案:Maven->選擇骨架或者手動新增.. 在main中建立java,resources,webapp三個包,webapp包下建立WEB-INF,pages:建立succes.jsp;[成功的返回頁面] 2. 匯入相關座標.. [可以應用版本鎖定] 3. 引入前端控制器[固定寫法] 4. springmvc.xml:開啟註解掃描,檢視解析器,註解支援 5. 刪除webapp中的index.jsp重新建立一個; 3. 響應資料和結果檢視: 1. Controller方法返回字串 【使用Model存入資料再返回】 1. 解析: Controller方法執行後,返回的字串根據檢視解析器所前後拼接的檔名和地址,就能成功的跳轉到所需的頁面; 2. jsp頁面接收物件: * 在Controller方法中,使用model.addAttribute("user",user) [該方法需傳入一個Model] * Model不需要我們建立,這是框架為我們生成的; * isELIgnored="false" [識別el表示式] * 使用${user.username}進行取值... * 示例: * @Controller * @RequestMapping("/user") * public class UserController { * /** * *請求引數的繫結 * */ * @RequestMapping(value="/initUpdate") * public String initUpdate(Model model) { * // 模擬從資料庫中查詢的資料 * User user = new User(); * user.setUsername("張三"); * user.setPassword("123"); * user.setMoney(100d); * user.setBirthday(new Date()); * model.addAttribute("user", user); * return "update"; * } * } 2. Controller方法返回void 【return;】 1. 請求轉發:請求轉發是一次請求,不能簡寫 [手動跳動轉發,不會觸動檢視解析器,需要自己寫全路徑和檔案格式] * 示例:request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response); 2. 重定向:請求轉發是可以直接訪問web-inf下的檔案,所以不用寫虛擬地址; * reponse.sendRedirect(request.getContextPath()+"WEB-INF/pages/xxx.jsp") 3. 解決中文亂碼: * reponse.setCharacterEncoding("UTF-8"); * response.setContentType("text/html;charset=UTF-8"); 4. 直接響應: * response.getWriter().print("你好"); 5. 注意:程式執行到響應,那麼響應後面的程式碼應寫上return; * 一次請求對應一次響應,所以response.getWriter.print("xxx"),裡面列印的需要在整個方法執行完才會整體的去響應,在此之前它是將列印的語句儲備起來,還未傳送響應;所以使用return;進行結尾,那麼就可以不讓框架繼續執行其他,直接返回; 6. 使用框架後,request,response這些以後都不經常用了; 7. 為什麼domain實體類要實現Serializable介面? * 它是實體類,專門用來儲存類,它存在於記憶體中,實現序列化介面,可以將封裝好的類儲存到硬碟中,如果突然斷電關機什麼意外情況,可以反序列化還原; * 實現該介面,才可以將該物件遠端呼叫,遠端傳輸到其他的伺服器,傳輸時以流的形式 8. 實體類中的常見問題: 1. 如果實體類中寫了有參構造,那麼需要再為它建立一個無參構造; 2. 成員變數最好使用private修飾,加強安全性,只能通過get,set對其操作; 3. 成員變數儘量使用包裝型別,不要使用基本型別,即儘量使用Integer類,而不使用int基本型別; 4. Integer修飾的變數可以為空,但基本型別不能為null; 比如:private Integer ge=null; 3. ModelAndView: 1. 把user物件儲存到mv物件中,也會把user物件存入到request物件; 2. 它既可以儲存鍵值對[發揮model],它也可以轉發檢視[view]的作用; * 示例: * @RequestMapping("/testModelAndView") * public ModelAndView testModelAndView(){ * ModelAndView mv =new ModelAndView(); * System.out.println("testModelAndView方法執行了...") * User user=new User(); * user.setUsername("小楓") * user.setPassword(123); * user.setAge(30); * mv.addObject("user",user); * mv.setViewName("success"); * reutrn mv; * } 4. 使用關鍵字的方式進行轉發或者重定向 [使用關鍵字是不會被檢視解析器所管理,需要自己手動補全路徑] * @RequestMapping("/testForwardOrRedirect") * public String testForwardOrRedirect(){ * //請求的轉發: * return "forward:/WEB-INF/pages/success.jsp"; * //重定向 * return "redirect:/index.jsp"; * } 4. ResponseBody響應json資料 1. DispatcherServlet會攔截到所有的資源,導致一個問題就是靜態資源(img、css、js)也會被攔截到,從而不能被使用。解決問題就是需要配置靜態資源不進行攔截,在springmvc.xml配置檔案新增如下配置: * //前端控制前,哪些資源不攔截: * <mvc:resources location="/css/" mapping="/css/**"/> * <mvc:resources location="/images/" mapping="/images/**"/> * <mvc:resources location="/js/" mapping="/js/**"/> 2. 特點: 1. mvc:resources標籤配置不過濾 2. location元素表示webapp目錄下的包下的所有檔案 3. mapping元素表示以/static開頭的所有請求路徑,如/static/a 或者/static/a/b 5. 模擬示例: 1. 模擬非同步請求響應: 1. 伺服器: * @RequestMapping("/testAjax") * public void testAjax(@RequestBody String body){ * // * System.out.println(body); * } 2. 瀏覽器: * $(function(){ * $("#btn").click(funcation(){ * $.ajax({ * url:""user/testAjax", * contextType:"application/json;charset=UTF-8", //設定了這種格式,提交是以json格式提交,如果不以此設定,$.get |$.post 則都是表單提交格式 * data:'{"username":"heihei","password":"123","age":30}', * dataType:"json", * type:"post", * success:function(date){ * //data伺服器端響應的json資料,進行解析。 * } * }) * }) 3. 如果傳入已經定義好了的domain裡User實體類,那麼也可以直接傳入這個實體類,只要屬性值對應的上,那麼springmvc就會自動繫結,與ajax傳送的屬性值一一對應;
檔案上傳
1. 檔案上傳三要素: [只要是檔案上傳,就必須滿足這三個要素] 1. form表單的enctype取值必須是:multipart/form-data * [預設值是:application/x-222-form-urlencoded] * enctype:是表單請求正文的型別 2. method屬性必須是post * get請求會把檔案攜帶在位址列上,而get請求是有大小限制的; 3. 提供一個檔案選擇域而且必須有name屬性: * <input type="file"> 2. 藉助第三方元件實現檔案上傳: * 匯入commons-fileupload-1.3.1.jar和commons-io-2.4.jar 3. 案例實現:
1. 搭建開發環境: 1. 建立一個新的maven專案: * 座標,springmvc.xml,web.xml * <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> 2. 補全包路徑 3. 編寫檔案上傳的JSP頁面: <h3>檔案上傳</h3> <form action="user/fileupload" method="post" enctype="multipart/form-data"> 選擇檔案:<input type="file" name="upload"/><br/> <input type="submit" value="上傳檔案"/> </form> 4. 編寫檔案上傳的Controller控制器: * @RequestMapping(value="/fileupload") public String fileupload(HttpServletRequest request) throws Exception { // 先獲取到要上傳的檔案目錄 String path = request.getSession().getServletContext().getRealPath("/uploads"); // 建立File物件,一會向該路徑下上傳檔案 File file = new File(path); // 判斷路徑是否存在,如果不存在,建立該路徑 if(!file.exists()) { file.mkdirs(); } // 建立磁碟檔案項工廠 DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload fileUpload = new ServletFileUpload(factory); // 解析request物件 List<FileItem> list = fileUpload.parseRequest(request); // 遍歷 for (FileItem fileItem : list) { // 判斷檔案項是普通欄位,還是上傳的檔案 if(fileItem.isFormField()) { }else { // 上傳檔案項 // 獲取到上傳檔案的名稱 String filename = fileItem.getName(); // 上傳檔案 fileItem.write(new File(file, filename)); // 刪除臨時檔案 fileItem.delete(); } } return "success"; }
5. SpringMVC實現原理分析:
1. 選擇檔案後點擊上傳;
2. 當檔案上傳後,通過request進入到前端控制器
3. 前端控制器通過新增的配置檔案解析器,解析request並返回upload
4. 前端控制器呼叫Controller,將upload傳入Controller類下的fileuoload2(MultipartFile upload),然後對其進行操作;
5. 注意:前端的name屬性值必須和後端Controller類下finduoload2內傳入的引數名保持一致;
6. 實現程式碼:
1. SpringMVC傳統方式檔案上傳:
1. SpringMVC框架提供了MultipartFile物件,該物件表示上傳的檔案,要求變數名必須和表單file標籤的name屬性相同;
2. 程式碼如下:
@RequestMapping(value="/fileupload2")
public String fileupload2(HttpServletRequest request,MultipartFile upload) throws
Exception {
System.out.println("SpringMVC方式的檔案上傳...");
// 先獲取到要上傳的檔案目錄
String path = request.getSession().getServletContext().getRealPath("/uploads");
// 建立File物件,一會向該路徑下上傳檔案
File file = new File(path);
// 判斷路徑是否存在,如果不存在,建立該路徑
if(!file.exists()) {
file.mkdirs();
}
// 獲取到上傳檔案的名稱
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 把檔案的名稱唯一化
filename = uuid+"_"+filename;
// 上傳檔案
upload.transferTo(new File(file,filename));
return "success";
}
3. 配置檔案解析器物件: 【如果是傳統的檔案上傳那麼會報錯,只有SpringMVC的檔案上傳才能起作用】
<!-- 配置檔案解析器物件,要求id名稱必須是multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/> // 10485760=1024*1024*10=10MB
</bean>
2. SpringMVC跨伺服器檔案上傳:
1. 搭建圖片伺服器:
1. 根據文件配置tomcat9的伺服器,現在是兩個伺服器
2. 匯入資料中day02_SpringMVC5_02image專案,作為圖片伺服器使用 [兩個tomcat模擬兩臺伺服器,一臺伺服器作為控制器接收請求,一臺伺服器作為圖片儲存]
2. 實現SpringMVC跨伺服器檔案上傳
1. 匯入開發需要的jar包:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
2. 編寫檔案上傳JSP頁面:
<h3>跨伺服器的檔案上傳</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
選擇檔案:<input type="file" name="upload"/><br/>
<input type="submit" value="上傳檔案"/>
</form>
3. 編寫控制器:
@RequestMapping(value="/fileupload3")
public String fileupload3(MultipartFile upload) throws Exception {
System.out.println("SpringMVC跨伺服器方式的檔案上傳...");
// 定義圖片伺服器的請求路徑
String path = "http://localhost:9090/day02_springmvc5_02image/uploads/";
// 獲取到上傳檔案的名稱
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 把檔案的名稱唯一化
filename = uuid+"_"+filename;
// 向圖片伺服器上傳檔案
// 建立客戶端物件
Client client = Client.create();
// 連線圖片伺服器
WebResource webResource = client.resource(path+filename);
// 上傳檔案
webResource.put(upload.getBytes());
return "success";
}
異常處理
1. SpringMVC異常處理流程:
1. 瀏覽器-> 前端控制器-> web-> service-> dao
2. 如果出現錯誤,預設處理方案是將錯誤依次往上丟擲:
* 假如dao層出現錯誤,會拋給service->web->前端控制器->瀏覽器
3. 出現錯誤如果將錯誤出現在瀏覽器上,會降低使用者體驗,產生不好的影響;
* 此時可在前端控制器新增一個異常處理器元件,它將從內部拋給前端控制器的異常攔截,並將異常進行處理,返回給瀏覽器一個友好的錯誤提示頁面;
4. Controller呼叫service,service呼叫dao,異常都是向上丟擲的,最終有DispathcherServlet找異常處理器進行異常的處理。
5. 示例:
1. 自定義異常類:
package cn.itcast.exception;
public class SysException extends Exception{
private static final long serialVersionUID = 4055945147128016300L;
// 異常提示資訊
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public SysException(String message) {
this.message = message;
}}
2. 自定義異常處理器
package cn.itcast.exception;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
/**
* 異常處理器
* @author rt
*/
public class SysExceptionResolver implements HandlerExceptionResolver{
/**
* 跳轉到具體的錯誤頁面的方法
*/
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse
response, Object handler,
Exception ex) {
ex.printStackTrace();
SysException e = null;
// 獲取到異常物件
if(ex instanceof SysException) {
e = (SysException) ex;
}else {
e = new SysException("請聯絡管理員");
}
ModelAndView mv = new ModelAndView();
// 存入錯誤的提示資訊
mv.addObject("message", e.getMessage());
// 跳轉的Jsp頁面
mv.setViewName("error");
return mv;
}
}
3. 配置異常處理器:
< bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolvaer"/>
攔截器
1. SpringMVC的處理器攔截器類似於Servlet開發中的過濾器Filter,用於對處理器進行預處理和後處理;
2. 攔截器鏈:(Interceptor Chain)。攔截器鏈就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或欄位時,攔截器鏈中的攔截器就會按其之前定義的順序被呼叫。
3. 解釋:
* 過濾器:是servlet規範中的一部分,任何java web工程都可以使用。
* 攔截器:是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
* 過濾器:是在url-pattern中配置了/*之後,可以對所有要訪問的資源攔截;
* 攔截器:它是隻會攔截訪問的控制器方法,如果訪問的是jsp,html,css,image或者js是不會進行攔截的。
* 它也是AOP思想的具體應用。
* 我們要想自定義攔截器,要求必須實現:HandlerInterceptor介面。
4. 不同點:過濾器什麼都攔截,而攔截器只能攔截特定的;即過濾器的範圍大於攔截器;