需求:在用戶註冊頁面實現上傳圖片做爲用戶頭像javascript
1. springmvc中對多部件類型請求數據解析:在頁面form中提交enctype="multipart/form-data"的數據時,須要springmvc對multipart類型的數據進行解析。在springmvc.xml中配置multipart類型解析器。html
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!--指定上傳文件的最大空間爲10mb--> <property name="maxUploadSize"> <value>1048576</value> </property> <!--上傳文件的編碼格式爲utf-8--> <property name="defaultEncoding"> <value>utf-8</value> </property> </bean>
2. 加入上傳圖片的jar,上邊的解析內部使用下邊的jar進行圖片上傳。前端
3. 在tomcat服務器中建立圖片虛擬目錄用於存儲圖片:經過圖形化界面建立,java
Document base就表示本地路徑,而path就表示瀏覽器訪問路徑;也能夠直接修改tomcat的配置:在conf/server.xml文件,添加虛擬目錄 :jquery
注意:在圖片虛擬目錄 中,必定將圖片目錄分級建立(提升i/o性能),通常咱們採用按日期(年、月、日)進行分級建立。web
3. jsp頁面中對上傳圖片代碼編寫:主要有三個要編寫的地方,form表單的enctype="multipart/form-data"和method="post"兩個屬性,以及<input type="file" name="">標籤上傳文件ajax
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>註冊頁面</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <!--enctype="multipart/form-data"和method="post"這兩個配置必須有,multipart/form-data表示上傳多部件類型的數據,必須爲post請求方式是由於post請求方式能發送包含文件的數據請求--> <form action="/user_manage/user/regist.do" enctype="multipart/form-data" method="post"> <div>請輸入名稱:<input type="text" name="userName"></div> <div>請輸入密碼:<input type="password" name="userPassword"></div> <div>請輸入年齡:<input type="text" name="userAge"></div> <div>請輸入地址:<input type="text" name="userAddress"></div> <div>請輸入手機:<input type="text" name="userTelephone"></div> <!--主要經過<input type="file" name="">標籤上傳文件,不必定是圖片--> <div>請選擇一張圖片做爲頭像:<input type="file" name="img"></div> <div><input type="submit" value="註冊"></div> </form> </body> </html>
4. 服務端controller方法接收圖片文件:接收的文件會綁定爲org.springframework.web.multipart.MultipartFile類型的對象形參,也就是說,發送的文件會保存在MultipartFile對象中,綁定規則和簡單類型參數的綁定同樣,形參名和請求中的key值相同spring
@RequestMapping("/regist") public String userRegist(MultipartFile img,@Validated(value={validatorGroup1.class}) User user,BindingResult result,Model model){ String picPath=uploadPicture(img);//調用下面的方法,保存圖片並返回該圖片的訪問地址 user.setUserImage(picPath);//將圖片的訪問地址保存到User對象中 userservice.insertUser(user); model.addAttribute("userAccount", user.getUserAccount()); return "login"; } public class User { private Integer userAccount; private String userName; private String userPassword; private Integer userAge; private String userAddress; private String userTelephone; //添加圖片路徑屬性 private String userImage; //省略get/set方法 }
5. 將接收的文件發送到圖片服務器的虛擬目錄中:json
//保存圖片到服務器中,並生成該圖片的訪問路徑 private static String uploadPicture(MultipartFile uploadFile){ String oldFileName=uploadFile.getOriginalFilename();//獲取初始文件名 String fileSuffix=oldFileName.substring(oldFileName.lastIndexOf("."));//獲取文件類型後綴 String newFileName=UUID.randomUUID().toString();//新圖片名稱的生成有多種方式,只需保證不重複便可 //本地服務器中存放圖片所在文件夾的物理路徑 String path="D:\\develop\\upload\\"; //拼接本地存放的完整路徑 File newPicture=new File(path+newFileName+fileSuffix); try { //將圖片保存在該路徑下 uploadFile.transferTo(newPicture); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //返回完整的虛擬路徑 return "http://localhost:8081/pic/"+newFileName+fileSuffix; }
6. 在上面的上傳圖片實現中,圖片上傳後會保存在運行應用系統的服務器中,但若是是應用系統分佈式部署環境下圖片引用會出現問題,並且圖片的上傳下載會給服務器增長額外的壓力跨域
因此在實際開發中會採起分佈式部署,保存用戶上傳下載文件的服務器不會和系統應用部署的服務器處於同一臺服務器,而是分開部署的,這時就須要一些網絡傳輸代碼來進行兩個服務器之間的數據上傳與下載,通常採用FTP協議。這裏不作具體實現
1. 客戶端與服務端的json數據交互過程:
2. 若是是請求的數據格式爲json、響應的數據格式也爲json,在前端頁面中須要將請求的內容轉成json,不太方便,因此經常使用請求的數據格式爲key/value、響應的數據格式爲json。
3. 使用json的緣由就在於:json數據格式在接口調用中、html頁面中較經常使用,json格式簡單,解析方便。好比Ajax異步數據交互時經常使用json、還有最重要JSONP跨域請求數據資源
4. 簡單使用示例:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>test page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript" src="../js/jquery-1.4.4.min.js"></script> <script type="text/javascript"> //設置提交的數據格式爲json,即請求頭contentType=application/json,接收json數據 function requestJson(){ $.ajax({ type:'post', url:'http://localhost:8081/user_manage/requestJson', contentType:'application/json;charset=utf-8', data:'{userAccount:"123456",userName="123",userPassword="123456"}', success:function(data){ alert(data); }, error:function(){ alert("請求失敗"); } }); } //默認提交的數據格式爲key/value,即請求頭contentType=application/x-www-form-urlen,接收json數據 function requestKeyValue(){ $.ajax({ type:'post', url:'http://localhost:8081/user_manage/requestKeyValue', data:"userAccount=123456&userName=123&userPassword=123456", success:function(data){ alert(data); }, error:function(){ alert("請求失敗"); } }); } </script> </head> <body> <button onclick="requestJson()">提交json數據</button> <button onclick="requestKeyValue()">提交key/value數據</button> </body> </html>
@RequestMapping("/requestJson") @ResponseBody//該註解就會把返回的對象user轉爲json字符串,而@RequestBody會把json字符串綁定到user形參中 public User JsonTest1(@RequestBody User user){ user.setUserPassword("12345678"); return user; } @RequestMapping("/requestKeyValue") @ResponseBody public User JsonTest2(User user){ user.setUserPassword("12345678"); return user; }
1. 何爲RESTful格式路徑:
2. 實現一個需求做爲示例:在用戶管理界面,實現刪除用戶
2. 首先要在web.xml中配置好用於接收RESTful格式請求路徑的前端控制器:
<!-- RESTful風格的路徑配置 --> <servlet> <servlet-name>RESTful</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--SpringMVC加載的配置文件,這裏是springweb應用上下文 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:conf/springMVC.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>RESTful</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
2. 請求路徑爲:http://localhost:8081/user_manage/delete/1/20/1000000001
3. 服務端Controller方法:page表示該用戶信息所在的頁數,rows表示每頁最大顯示的用戶信息數量,userAccount表示用戶帳號
@RequestMapping("/delete/{page}/{rows}/{userAccount}") @ResponseBody public String deleteUser(@PathVariable(value="page") int page, @PathVariable(value="userAccount") int userAccount, @PathVariable(value="rows") int rows){ userService.deleteUser(userAccount); DataGridResult users=userService.findUserList(page, rows); return users; }
4. RESTful格式請求路徑所帶來的問題:配置前端控制器的url-parttern中指定/,對靜態資源的解析出現問題,由於此時前端控制器對於靜態資源的請求路徑也會攔截並在控制器映射器中尋找對應的Controller,而此時是沒法尋找到對應的Controller的,因此會報404
5. 解決RESTful格式請求路徑對靜態資源的解析出現的問題:
<mvc:resources location="/WEB-INF/js/" mapping="/js/**"/>
<mvc:default-servlet-handler/>
可是該配置必須保證靜態資源文件在webapp目錄下,而經過resources配置的能夠將靜態資源放在WEB-INF目錄下
1. 自定義攔截器:實現org.springframework.web.servlet.HandlerInterceptor接口便可
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; //定義攔截器,實現HandlerInterceptor接口。接口中提供三個方法。 public class HandlerInterceptor1 implements HandlerInterceptor { //進入 Handler(即Controller)方法以前執行 //用於身份認證、身份受權 //好比身份認證,若是認證經過表示當前用戶沒有登錄,須要此方法攔截再也不向下執行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //return false表示攔截,不向下執行 //return true表示放行 return false; } //進入Handler方法以後,返回modelAndView以前執行 //應用場景從modelAndView出發:將公用的模型數據(好比菜單導航)在這裏傳到視圖,也能夠在這裏統一指定視圖 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } //完成執行Handler後執行此方法 //應用場景:統一異常處理,統一日誌處理 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
2. 配置全局攔截器:springmvc配置全局的攔截器,springmvc框架將配置的攔截器注入到每一個處理器映射器中,springmvc攔截器針對HandlerMapping(處理器映射器)進行攔截設置,或者說會將攔截器配置處處理器映射器中,若是某個請求路徑該HandlerMapping映射成功(找到對應的Handler),那麼會先被攔截器進行攔截處理,在處理器返回響應以前在進行一次處理。在SpringMVC的配置文件(springmvc.xml)中添加以下配置
<!-- 若是配置多個攔截器,在mvc:interceptors中添加多個mvc:interceptor便可 --> <mvc:interceptors> <mvc:interceptor> <!-- 攔截器類 --> <bean class="user_manage.interceptor.HandlerInterceptor1"></bean> <!-- 攔截器攔截的請求路徑,/**表示攔截全部的url --> <mvc:mapping path="/**"/> </mvc:interceptor> <mvc:interceptor> <!-- 攔截器類 --> <bean class="user_manage.interceptor.HandlerInterceptor2"></bean> <!-- 攔截器攔截的請求路徑,/**表示攔截全部的url --> <mvc:mapping path="/**"/> </mvc:interceptor> </mvc:interceptors>
3. 攔截器執行順序:若是配置了多個攔截器,那麼就按照配置中所寫攔截器的順序來依次進行攔截,只有前一個攔截器對請求放行以後,後一個攔截器才能繼續攔截。
4. 攔截器使用實例:登陸認證攔截,除了登陸請求和註冊請求以外,其餘請求必須經過登陸認證攔截器攔截
public class LoginInterceptor implements HandlerInterceptor { //進入 Handler方法以前執行 //用於身份認證、身份受權 //好比身份認證,若是認證經過表示當前用戶沒有登錄,須要此方法攔截再也不向下執行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //獲取請求的url String url = request.getRequestURI(); //判斷url是不是公開 地址(實際使用時將公開 地址配置配置文件中) //這裏公開地址是登錄提交的地址 if(url.indexOf("login")>=0){ //若是是登錄請求的路徑地址,放行 return true; } //判斷session HttpSession session = request.getSession(); //從session中取出用戶身份信息 String username = (String) session.getAttribute("username"); if(username != null){ //身份存在,放行 return true; } //執行這裏表示用戶身份須要認證,跳轉登錄頁面 request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response); //return false表示攔截,不向下執行 //return true表示放行 return false; }