一、請求處理
1、常用注解
@RequestMapping
作用 :用來匹配客戶端發送的請求(用來處理URL映射,將請求映射到處理方法中),可以在類或者方法上使用。 用在類上,可以將請求模塊化,避免請求方法中的映射重復。表示為當前控制器類中的所有方法添加一個前置路徑。 用在方法上,表示用來匹配要處理的請求(注意:在整個項目的不同方法上不能出現URL重復的情況)。 相關屬性 : value :要匹配的請求路徑method :顯示發送請求的方式(GET、POST、PUT、DELETE)params :表示請求要接收的參數,如果定義了該屬性,那么發送請求時必須要攜帶該參數;headers :填寫請求頭信息;consumers :設置接收的請求的內容類型,相當于指定Content-type;produces :設置返回的內容類型; @RequestMapping ( value = "/test" , method = RequestMethod . GET , params = "entname" , headers = { "User‐Agent=Mozilla/5.0 (Windows NT 10.0;" } ) public String test ( ) { return "/index.jsp" ; }
@RequestParam
@RequestHeader
@CookieValue
@PathVariable
作用 :獲取請求路徑中的參數如果是單個參數接收,必須使用@PathVariable來聲明獲取對應的參數占位符的值; 如果是JavaBean,則可以省略@PathVariable,但要保證各個占位符的參數名與JavaBean中的屬性名一致;@RequestMapping ( "/user/{id}/{username}" )
public String path01 ( @PathVariable ( "id" ) Integerid , @PathVariable ( "username" ) String name) { System . out. println ( id) ; System . out. println ( name) ; return "/index.jsp" ;
} @RequestMapping ( "/user02/{id}/{name}" )
public String path02 ( User user) { System . out. println ( user) ; return "/index.jsp" ;
}
2、REST風格
3、靜態資源的訪問
當頁面中直接使用靜態資源時,是沒辦法直接獲取到的,是因為找不到對應的mapping映射,DispatcherServlet會攔截所有的請求,而此時我們沒有對應圖片的請求處理方法。此時只需要在springmvc.xml中添加如下配置即可:
< mvc: annotation-driven/> < mvc: resources mapping = " /images/**" location = " /images/" /> < mvc: default-servlet-handler/>
二、響應處理
1、視圖解析器
< bean id = " viewResolver" class = " org.springframework.web.servlet.view.InternalResourceViewResolver" > < property name = " prefix" value = " /WEB-INF/views/" /> < property name = " suffix" value = " .jsp" /> </ bean>
2、視圖控制器
< mvc: view-controller path = " /" view-name = " index" > </ mvc: view-controller>
3、使用Model,Map,ModelMap傳輸數據到頁面
當使用以下三種方式設置之后,所有的參數值都設置到了request的作用域中; ${requestScope.type}
@RequestMapping ( "/servlet" ) public String servletApi ( HttpServletRequest request) { request. setAttribute ( "type" , "servletAPI" ) ; return "main" ; } @RequestMapping ( "/model" ) public String modelAttribute ( Model model) { model. addAttribute ( "type" , "modelAttribute" ) ; return "main" ; } @RequestMapping ( "/modelMap" ) public String modelMapAttribute ( ModelMap modelMap) { modelMap. addAttribute ( "type" , "modelMapAttribute" ) ; return "main" ; } @RequestMapping ( "/map" ) public String map ( Map map) { map. put ( "type" , "map" ) ; return "main" ; }
4、使用ModelAndView對象傳輸數據到頁面
使用ModelAndView對象時,返回值類型也是該對象,可以將要跳轉的頁面設置為view的名稱,來完成跳轉功能,同時,數據也是存放到了request作用域中; springmvc還會隱式的將請求綁定的參數自動設置到request域中;
@RequestMapping ( "/modelAndView" ) public ModelAndView modelAndView ( ) { ModelAndView modelAndView = new ModelAndView ( "main" ) ; modelAndView. addObject ( "type" , "modelAndView" ) ; return modelAndView; }
5、使用session傳輸數據到頁面
方式一:通過Servlet API的方式讀寫session 通過參數綁定的方式去獲取Servlet API 通過自動注入的方式去獲取Servlet API(推薦使用這種方式) ${sessionScope.type}
@RequestMapping ( "/session" ) public String session ( HttpSession session) { session. setAttribute ( "type" , "servletApi-session" ) ; return "main" ; } @Autowired private HttpSession session; @RequestMapping ( "/autoSession" ) public String autoSession ( ) { session. setAttribute ( "type" , "auto-session" ) ; return "main" ; }
方式二:通過注解的方式讀取session @SessionAttributes 用在類上,表示當前控制器類下的所有方法,都會將model指定的屬性寫入session。 它會從model中獲取指定的屬性寫入session中。即:底層會從model中找一個叫type的屬性寫到session中,這種方式是依賴model的。 @SessionAttribute 用在參數上,讀取session。 model和session是互通的:session可以通過model中去獲取寫入指定的屬性, model也會從session中自動寫入指定的屬性。
@Controller @SessionAttributes ( "type" ) public class DTVController { @RequestMapping ( "/getSession" ) public String getSession ( @SessionAttribute ( value= "type" , required = false ) String type) { System . out. println ( type) ; return "main" ; } }
6、轉發和重定向
轉發的特點 : a、地址欄的url從始至終都不會變 b、請求次數,僅只有一次 c、請求域中的數據不會丟失 d、根目錄包含了項目的訪問地址,所以,不用寫完成的訪問地址,只需要寫明轉發的視圖即可:/index2.jsp 重定向的特點 : a、地址欄的url會發生變化,第一次:初識地址(localhost:8080/springmvc/);第二次:重定向地址(localhost:8080/springmvc/index2.jsp) b、請求次數,兩次 c、請求域中的數據會丟失,因為是不同的請求 d、根目錄不包含項目的訪問地址
@RequestMapping ( "/Hello" ) public String helloWorld ( @RequestParam ( value = "name" , defaultValue = "開發者" , required = false ) String name) { System . out. println ( "hello springmvc:" + name) ; return "redirect:/index2.jsp" ; }
三、JSON處理
< dependency> < groupId> com.fasterxml.jackson.core</ groupId> < artifactId> jackson-core</ artifactId> < version> 2.9.8</ version> </ dependency> < dependency> < groupId> com.fasterxml.jackson.core</ groupId> < artifactId> jackson-databind</ artifactId> < version> 2.9.8</ version> </ dependency> < dependency> < groupId> com.fasterxml.jackson.core</ groupId> < artifactId> jackson-annotations</ artifactId> < version> 2.9.0</ version> </ dependency>
1、返回JSON數據
1、加入jackjson依賴 2、將jackjson的jar包加入WEB-INF的lib文件夾中 3、在對應處理方法上加上@ResponseBody注解,用于標記該處理方法返回json 4、或者將類上的@Controller改為@RestController注解,表示標記該類中所有的方法都返回json 5、@RestController相當于 @Controller + @ResponseBody
@Controller
public class JsonController { @RequestMapping ( "/testJson01" ) @ResponseBody public String responseJson01 ( ) { System . out. println ( "testJson" ) ; return "json" ; } @RequestMapping ( "/testJson02" ) @ResponseBody public User responseJson02 ( ) { User user = new User ( ) ; user. setId ( 1001 ) ; user. setName ( "張三" ) ; user. setAlias ( new String [ ] { "張三豐" , "張無忌" } ) ; user. setBirthday ( new Date ( ) ) ; return user; }
2、獲取JSON數據
使用@RequestBody來接收前端發送的json數據
@RequestMapping ( "/testJson03" ) @ResponseBody public User responseJson03 ( @RequestBody User user) { User user2 = new User ( ) ; user. setId ( 1002 ) ; user. setName ( "張三" ) ; user. setAlias ( new String [ ] { "張三豐" , "張無忌" } ) ; user. setBirthday ( new Date ( ) ) ; System . out. println ( user) ; return user2; }
四、文件上傳和下載
1、文件下載
@RequestMapping ( "/download" ) public void downLoad ( HttpServletRequest request, HttpServletResponse response) throws IOException { String realPath = request. getServletContext ( ) . getRealPath ( "/images/123.png" ) ; File tmpFile= new File ( realPath) ; String fileName = tmpFile. getName ( ) ; response. setHeader ( "content-disposition" , "attachment;filename=" + URLEncoder . encode ( fileName, "UTF-8" ) ) ; InputStream in = Files . newInputStream ( Paths . get ( realPath) ) ; int len = 0 ; byte [ ] buffer = new byte [ 1024 ] ; OutputStream out = response. getOutputStream ( ) ; while ( ( len = in. read ( buffer) ) > 0 ) { out. write ( buffer, 0 , len) ; } in. close ( ) ; }
2、文件上傳
Spring MVC 為文件上傳提供了直接的支持,這種支持是通過 MultipartResolver 實現的。Spring 用 Jakarta Commons FileUpload 技術實現了一個 MultipartResolver 實現類:CommonsMultipartResovler。 Spring MVC 上下文中默認沒有裝配 MultipartResovler,因此默認情況下不能處理文件的上傳工作,如果想使用 Spring 的文件上傳功能,需現在上下文中配置 MultipartResolver。 添加Jakarta Commons FileUpload的依賴支持
< dependency> < groupId> commons-fileupload</ groupId> < artifactId> commons-fileupload</ artifactId> < version> 1.4</ version> </ dependency>
配置MultipartResolver文件上傳解析器
< bean class = " org.springframework.web.multipart.commons.CommonsMultipartResolver" id = " multipartResolver" > < property name = " defaultEncoding" value = " UTF-8" /> < property name = " maxUploadSize" value = " #{1024*1024*10}" /> </ bean>
@RequestMapping ( "/upload" ) public String upload ( @RequestParam ( "desc" ) String desc, @RequestParam ( "uploadFile" ) MultipartFile multipartFile) throws IOException { System . out. println ( "des:" + desc) ; System . out. println ( "uploadFile:" + multipartFile. getOriginalFilename ( ) ) ; if ( ! multipartFile. isEmpty ( ) ) { String realPath = "C:\\Users\\TRS\\Desktop\\Out" ; String fileName = multipartFile. getOriginalFilename ( ) ; File tmpFile; if ( fileName != null ) { tmpFile = new File ( realPath, fileName) ; multipartFile. transferTo ( tmpFile) ; } } return "Success" ; }
五、攔截器
1、實現過程
SpringMVC攔截器采用AOP的設計思想,它跟過濾器類似,用來攔截處理方法在之前或者之后執行一些跟主業務沒有關系的公共功能。 比如:權限控制、日志記錄、異常記錄等 實現攔截器的步驟: 1、實現接口:HandlerInterceptor 2、重寫三個方法:preHandle、postHandle、afterCompletion 3、在springmvc.xml的配置文件中裝配攔截器
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
預處理回調方法,實現處理器方法的預處理(如:登錄檢查); 第三個參數為響應的處理器返回值; true 表示放行,繼續向下執行(如調用下一個攔截器或處理器);false 表示攔截(如登錄檢查失敗),終止執行。此時我們需要通過response來產生響應; postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
后處理回調方法,實現處理器的后處理(但在渲染視圖之前); 此時我們可以通過modelAndView(模型和視圖對象)對模型數據進行處理或對 視圖進行處理,modelAndView也可能為null; afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
請求處理完畢后回調方法,在視圖渲染完后執行; 如性能監控中我們可以在此記錄結束時間并輸出消耗時間,還可以進行一些資源清 理,類似于try-catch-finally中的finally,但僅當上面的preHandle方法返回true時才會執行。 自定義攔截器
@Component
public class MyInterceptor implements HandlerInterceptor { public boolean preHandle ( HttpServletRequest request, HttpServletResponse response, Object handler) { System . out. println ( "============>>>>preHandle()方法執行" ) ; HandlerMethod handlerMethod = ( HandlerMethod ) handler; System . out. println ( "處理方法所在類:" + handlerMethod. getBean ( ) . getClass ( ) . getName ( ) ) ; System . out. println ( "處理方法的方法名:" + handlerMethod. getMethod ( ) . getName ( ) ) ; System . out. println ( "處理方法的參數:" + Arrays . toString ( handlerMethod. getMethod ( ) . getParameters ( ) ) ) ; return true ; } public void postHandle ( HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { System . out. println ( "=========>>>postHandle()方法執行" ) ; } public void afterCompletion ( HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { System . out. println ( "==========>>>afterCompletion()方法執行" ) ; }
}
< mvc: interceptors> < bean class = " org.example.interceptor.MyInterceptor" > </ bean> </ mvc: interceptors>
2、攔截器與過濾器的區別
過濾器是基于函數回調的,而攔截器是基于java反射的; 過濾器依賴于servlet容器,而攔截器不依賴與Servlet容器,依賴于SpringMVC; 過濾器幾乎對所有的請求都可以起作用,而攔截器只能對SpringMVC請求起作用; 攔截器可以訪問處理方法的上下文,而過濾器不可以;
3、使用攔截器實現登錄權限攔截
public class UserInterceptor implements HandlerInterceptor { @Override public boolean preHandle ( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request. getSession ( ) ; System . out. println ( "當前用戶名:" + session. getAttribute ( "username" ) ) ; if ( ! "張三" . equals ( session. getAttribute ( "username" ) ) ) { response. sendRedirect ( request. getContextPath ( ) + "/login" ) ; return false ; } else { return true ; } } }
< mvc: interceptors> < bean class = " org.example.interceptor.MyInterceptor" > </ bean> < mvc: interceptor> < mvc: mapping path = " /**" /> < mvc: exclude-mapping path = " /login" /> < bean class = " org.example.interceptor.UserInterceptor" > </ bean> </ mvc: interceptor> </ mvc: interceptors>
六、異常處理
1、內置異常處理解析器
在SpringMVC中擁有一套非常強大的異常處理機制,SpringMVC通過HandlerExceptionResolver處理程序的異常,包括請求映射、數據綁定以及目標方法執行時發生的異常。 通過@ExceptionHandler
可以在方法中記錄日志,并轉發到一個友好的界面進行提示;
@Controller
public class ExceptionController { @RequestMapping ( "/hello" ) public String testException ( @RequestParam ( value = "name" ) String name) { System . out. println ( "方法執行中..." ) ; return "index" ; } @ExceptionHandler ( value = { Exception . class } ) public ModelAndView handleException ( Exception e) { ModelAndView mv = new ModelAndView ( ) ; mv. setViewName ( "exception" ) ; mv. addObject ( "ex" , e) ; System . out. println ( e. getMessage ( ) ) ; return mv; }
}
2、全局統一異常處理
如果想要對所有的控制器類進行統一異常處理,可以通過@ControllerAdvice
注解來實現。 @ControllerAdvice
是Spring3.2提供的新注解,它是對Controller的增強,可對Controller中被 @RequestMapping注解標識的方法加一些邏輯處理: 全局異常處理、全局數據綁定、全局數據預處理;全局異常處理的實現步驟: 添加@ControllerAdvice注解 添加@ExceptionHandler注解 處理器中自己的異常處理器優先級高于全局異常處理 如果處理器類中存在異常處理方法,則優先使用處理器異常處理方法,否則,使用全局異常處理中的異常(精準異常 > 全局異常) 統一異常處理:同時處理普通請求和ajax請求 普通請求:返回ModelAndView對象,跳轉到指定頁面 ajax請求:返回json數據
@ControllerAdvice public class GolablExceptionController { @ExceptionHandler ( value = { Exception . class } ) public ModelAndView handleException ( HttpServletRequest request, HttpServletResponse response, HandlerMethod handler, Exception e) { System . out. println ( "全局異常處理" ) ; ModelAndView mv = new ModelAndView ( ) ; RestController restAnnotation = handler. getClass ( ) . getAnnotation ( RestController . class ) ; ResponseBody resAnnotation = handler. getMethod ( ) . getAnnotation ( ResponseBody . class ) ; if ( restAnnotation != null || resAnnotation != null ) { mv = new ModelAndView ( new MappingJackson2JsonView ( ) ) ; mv. addObject ( "方法名" , handler. getMethod ( ) . getName ( ) ) ; mv. addObject ( "ex" , e. getMessage ( ) ) ; mv. addObject ( "code" , HttpStatus . INTERNAL_SERVER_ERROR . value ( ) ) ; } else { mv. setViewName ( "exception" ) ; mv. addObject ( "ex" , e) ; StringWriter stringWriter = new StringWriter ( ) ; PrintWriter printWriter = new PrintWriter ( stringWriter) ; e. printStackTrace ( printWriter) ; System . out. println ( stringWriter) ; } return mv; }