1. 程式人生 > 實用技巧 >6.SpringMVC

6.SpringMVC

SpringMVC

檢視View

  負責頁面的顯示;與使用者的互動。包含各種表單。實現檢視用到的技術有html/css/jsp/js等前端技術。

  使用者互動:使用者滑鼠點選頁面;填寫頁面中各種表單........等等

模型Model

   模型負責各個功能的實現(如登入、增加、刪除功能)。模型用JavaBean實現

控制器Controller

   控制器負責將檢視與模型一一對應起來。相當於一個模型分發器。所謂分發就是:

      ①接收請求,並將該請求跳轉(轉發,重定向)到模型進行處理。

      ②模型處理完畢後,再通過控制器,返回給檢視中的請求處。建議使用Servlet實現控制器。

在配置檔案中配置SpringMVC

web.xml
  <!-- 配置前端控制器 -->
  <servlet>         
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    
      <!-- 配置SpringMVC核心檔案的位置  預設去WEB-INF下尋找--> 
    <init-param
> <param-name>contextConfigLocation</param-name> <param-value>classpath:/springmvc-servlet.xml</param-value> </init-param> </servlet><servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>
*.action</url-pattern> <!-- 所有請求都會被攔截 --> </servlet-mapping>
springmvc-servlet.xml
<!-- 配置對映關係 -->
<bean name="/hello.action" class="com.wiscom.demo.FirstController"></bean><!--  配置檢視解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>
com.wiscom.demo.FirstController
package com.wiscom.demo;
​
public class FirstController implements Controller{
    
    public ModelAndView handleRequest(HttpServletRequest arg0,
            HttpServletResponse arg1) throws Exception {
        // 處理資料和介面
        ModelAndView mav = new ModelAndView();
        // 新增資料
        mav.addObject("msg1", "hello");
        mav.addObject("msg2", "springmvc");
        // 設定介面
        mav.setViewName("first");//WEB-INF/first.jsp
        return mav;
    }
}
first.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><!DOCTYPE HTML>
<html>
  <head>
  </head>
  
  <body>
    welcome
    <hr>
        <p>${msg1}</p>
        <p>${msg2}</p>
  </body>
</html>

使用註解方式配置SpringMVC

web.xml
 <!-- 配置前端控制器 -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置SpringMVC核心檔案的位置  預設去WEB-INF下尋找-->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/springmvc-servlet.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.action</url-pattern>
  </servlet-mapping>
springmvc-servlet.xml
<!-- 開啟包掃描 -->
<context:component-scan base-package="com.wiscom.demo"></context:component-scan>
<context:annotation-config></context:annotation-config>
<!-- 開啟mvc註解配置  -->
<mvc:annotation-driven></mvc:annotation-driven><!--  配置檢視解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>
com.wiscom.demo.FirstController
package com.wiscom.demo;
​
@Controller  //將FirstController交由Spring進行管理
public class FirstController {
    
    @RequestMapping("/test01.action")
    public ModelAndView test01(){
        ModelAndView mav = new ModelAndView();
        
        mav.addObject("msg1", "pig");
        mav.addObject("msg2", "fdsfd");
        
        mav.setViewName("first");
        return mav;
    }
    
    @RequestMapping("/test02.action")
    public String test02(){
        // 返回的字串代表的是View的名稱
        return "first";
    }
}
first.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><!DOCTYPE HTML>
<html>
  <head>
 </head>
  
  <body>
    welcome
    <hr>
        <p>${msg1}</p>
        <p>${msg2}</p>
  </body>
</html>

SpringMVC細節

可以在類上新增對映(@RequestMapping)

在類上新增@RequestMapping

在方法上新增@RequestMapping

@Controller  //將FirstController交由Spring進行管理
@RequestMapping("/Detail02")
public class FirstController {
    
    @RequestMapping("/test01.action")
    public ModelAndView test01(){
        ModelAndView mav = new ModelAndView();
        
        mav.addObject("msg1", "pig");
        mav.addObject("msg2", "fdsfd");
​
        mav.setViewName("first");
        return mav;
    }
}

@RequestMapping中的屬性

可以配置多個路徑

@RequestMapping({"/test01.action","/test01*.action"})

params:有這些屬性時被請求傳過來時才能夠被呼叫執行

@RequestMapping(value="/test03.action",params={"username","password"})

method:method設定為POST時,只能接受POST的資料

@RequestMapping(value="/test03.action",method=RequestMethod.POST)

常用POST,GET

headers:只有傳過來的請求包含相關頭部時才會被呼叫(很少使用)

@RequestMapping(value="/test03.action",headers={"host"})

註解屬舉例

指定要將當前處理器繫結到哪個訪問路徑上。

可以配置多個路徑。

@Controller  //將FirstController交由Spring進行管理
public class FirstController {
    
    @RequestMapping({"/test01.action","/test01*.action"})
    public ModelAndView test01(){
        ModelAndView mav = new ModelAndView();
        
        mav.addObject("msg1", "pig");
        mav.addObject("msg2", "fdsfd");
        
        mav.setViewName("first");
        return mav;
    }
}

params

params

有這些屬性時被請求傳過來時才能夠被呼叫執行

@Controller  //將FirstController交由Spring進行管理
public class FirstController {
    
    @RequestMapping(value="/test03.action",params={"username","password"})
    public ModelAndView test01(){
        ModelAndView mav = new ModelAndView();
        
        mav.addObject("msg1", "pig");
        mav.addObject("msg2", "fdsfd");
        
        mav.setViewName("first");
        return mav;
    }
}
method

method=RequestMethod.POST

method設定為POST時,只能接受POST的資料

@Controller  //將FirstController交由Spring進行管理
public class FirstController {
    
    @RequestMapping(value="/test03.action",method=RequestMethod.POST)
    public ModelAndView test01(){
        ModelAndView mav = new ModelAndView();
        
        mav.addObject("msg1", "pig");
        mav.addObject("msg2", "fdsfd");
        
        mav.setViewName("first");
        return mav;
    }
}

headers

headers

只有傳過來的請求包含相關頭部時才會被呼叫

@Controller  //將FirstController交由Spring進行管理
public class FirstController {
    
    @RequestMapping(value="/test03.action",headers={"host"})
    public ModelAndView test01(){
        ModelAndView mav = new ModelAndView();
        
        mav.addObject("msg1", "pig");
        mav.addObject("msg2", "fdsfd");
        
        mav.setViewName("first");
        return mav;
    }
}

處理器方法支援的引數型別和返回值型別

支援的方法引數型別

HttpServletRequest

代表當前請求的物件

HttpServletResponse

代表當前響應的物件

HttpSession

代表當前會話的物件

WebRequest

SpringMVC提供的物件,相當於是request和session的合體,可以操作這兩個域中的屬性

InputStream OutputStream Reader Writer

代表request中獲取的輸入流和response中獲取的輸出流

@PathVariable

可以將請求路徑的指定部分獲取賦值給指定方法引數

@RequestParam

public void test05(@RequestParam(value="nn") String nnn){ System.out.println(nnn); }

可以將指定請求引數賦值給指定方法引數,如果不寫此註解,則預設會將同名的請求引數賦值給方法引數

@CookieValue

可以將請求中的指定名稱的cookie賦值給指定方法引數

@RequestHeader

以將請求引數中的指定名稱的頭賦值給指定方法引數

Model和ModelMap和java.util.Map

向這些Model ModelMap Map中存入屬性,相當於向模型中存入資料

MultipartFile

實現檔案上傳功能時,接收上傳的檔案物件

package com.wiscom.demo;

@Controller  //將FirstController交由Spring進行管理
@RequestMapping("/cbt")
public class FirstController {

    @RequestMapping(value="/test01.action")
    // User中的屬性在請求中要按照順序傳送
    public void test05(User user){
        System.out.println(user);    
    }
    
    @RequestMapping(value="/test02.action")
    public void test05(@RequestParam(value="nn") String nnn){
        System.out.println(nnn);    
    }
    
    @RequestMapping("/test03.action")
    public void test06(String[] like){
//        System.out.println(like);
        System.out.println(Arrays.toString(like));
    }
}

支援的返回值型別

ModelAndView

可以返回一個ModelAndView物件,在其中封裝Model和View資訊

View

可以直接返回一個代表檢視的View物件

字串

直接返回檢視的名稱

void

如果返回值型別是void,則會自動返回和當前處理器路徑名相同的檢視名

@ResponseBody

當方法被@ResponseBody修飾時,預設將返回的物件轉為json寫入輸出

除以上之外返回的任何內容都會被當做模型中的資料來處理,而返回的檢視名等同於當前處理器路徑名

獲取Request Response物件

獲取請求引數

通過request物件獲取
    @RequestMapping(value="/test03.action")
    public void test03(HttpServletRequest request,HttpServletResponse response){
        // 返回的字串代表的是View的名稱
        
        System.out.println(request);
        // 獲取請求引數
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));
        String password = request.getParameter("password");
        User user = new User(age,username,password);
        System.out.println(user);
//        System.out.println(response);
        System.out.println(username + "~~" +age);
    }
直接接收請求引數
    @RequestMapping(value="/test04.action")
    public void test04(String username,int age){
        // 返回的字串代表的是View的名稱
        System.out.println(username + "~~" +age);
        
    }

自動封裝請求引數資訊到bean
    @RequestMapping(value="/test05.action")
    public void test05(User user){    // 請求中的引數必須與bean中的屬性一一對應
        System.out.println(user);
    }

處理複雜型別

FirstController.java

    @RequestMapping(value="/test01.action")
    public void test05(User user){
        System.out.println(user);    
    }

test2.jsp

   <form action="${pageContext.request.contextPath}/cbt/test01.action" method="get">
          年齡:<input type="text" name="age">
          姓名:<input type="text" name="username">
          密碼:<input type="text" name="password">
          狗齡:<input type="text" name="Dog.age">
          狗名:<input type="text" name="Dog.name">
          <input type="submit" value="提交">
      </form>

請求引數中的名稱和屬性名不同的處理@RequestParam

value

引數名字,即入參的請求引數名字,如value=“delId”

required

是否必須,預設是true,表示請求中一定要有相應的引數,否則將報400錯誤碼;

defaultValue

預設值,表示如果請求中沒有同名引數時的預設值

    @RequestMapping(value="/test02.action")
    public void test05(@RequestParam(value="nn") String nnn){
        System.out.println(nnn);    
    }

請求引數中存在多個同名引數

FirstController.java

    @RequestMapping("/test03.action")
    public void test06(String[] like){
//        System.out.println(like);
        System.out.println(Arrays.toString(like));
    }

test3.jsp

    <form action="${pageContext.request.contextPath}/cbt/test03.action" method="get">
          <input type="checkbox" name="like" value="wzry"/>王者榮耀
          <input type="checkbox" name="like" value="lol"/>英雄聯盟
          <input type="checkbox" name="like" value="dota"/>刀塔
          <input type="checkbox" name="like" value="chij"/>絕地求生
          <input type="submit" value="提交">
      </form>

請求引數中的中文亂碼

SpringMVC提供了過濾器用來解決全站亂碼

只能解決post請求的亂碼

web.xml
 <!-- 使用SpringMVC的過濾器來解決中文亂碼問題 針對於post提交 get提交無效  -->
  <filter>
      <filter-name>characterEncodingFilter</filter-name>
      <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
      <init-param>
          <param-name>encoding</param-name>
          <param-value>utf-8</param-value>
      </init-param>
  </filter>

  <filter-mapping>
      <filter-name>characterEncodingFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>

get請求的亂碼處理

System.out.println(new String(username.getBytes("iso8859-1"),"utf-8"));

日期資料的處理

test2.jsp
    <form action="${pageContext.request.contextPath}/cbrt/test02.action" method="get">
          年齡:<input type="text" name="age">
          姓名:<input type="text" name="username">
          日期:<input type="date" name="tday">
          <input type="submit" value="提交">
      </form>    

FirstController.java
    @InitBinder
    public void binding(ServletRequestDataBinder bind){
        // 設定日期預設的解析格式
        bind.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
    }
    
    @RequestMapping(value="/test02.action")
    public void test02(String username,int age,Date tday){
        // 2019-08-21    2019/08/21
        System.out.println(username);
        System.out.println(age);
        System.out.println(tday);
    }

SpringMVC檔案上傳

檔案上傳的三個必要條件

表單必須是Post提交

表單必須是enctype="multipart/form-data"

檔案上傳項必須有name屬性

test2.jsp
<form action="${pageContext.request.contextPath}/cbrt/test02.action" method="post" enctype="multipart/form-data">
          年齡:<input type="text" name="age">
          姓名:<input type="text" name="username">
          <input type="file" name="fx">
          
          <input type="submit" value="提交">
</form>

springmvc-servlet.xml

在配置檔案中配置檔案上傳工具

<!-- 配置檔案上傳 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--  上傳最大體積 -->
    <!-- <property name="maxUploadSize"></property> -->
    
    <!-- 上傳佔用最大記憶體大小 -->
    <!-- <property name="maxInMemorySize"></property> -->
    <!-- 上傳後存放臨時資料夾的位置 -->
    <!-- <property name="uploadTempDir"></property> -->
</bean>
FirstController.java

實現檔案上傳

    @RequestMapping(value="/test02.action")
    public void test02(String username,int age,MultipartFile fx) throws IOException{
        // 向本地c盤存放客戶端上傳的檔案    getOriginalFilename:得到檔案的原始名稱
        FileUtils.writeByteArrayToFile(new File("c://"+fx.getOriginalFilename()), fx.getBytes());
    }
 

RESTFul風格的請求

普通的get請求

Url:localhost:XXXX/addUser.action?name=tom&age=18

restfull風格的請求

Url:localhost:XXXX/addUser/tom/18.action

FirstController.java
@Controller  //將FirstController交由Spring進行管理

public class FirstController {

    @RequestMapping("/restful/{username}/{age}.action")
    public void restful(@PathVariable String username,@PathVariable int age){
        System.out.println(username + "~" + age);
    }
}

pringMVC中的重定向和轉發的實現

  // 轉發
    @RequestMapping("/test01.action")
    public String test01(){
        return "forward:/index.jsp";
    }
    // 轉發
    @RequestMapping("/test02.action")
    public String test02(){
        return "forward:/test01.action";
    }
    // 重定向
    @RequestMapping("/test03.action")
    public String test03(){
        return "redirect:/index.jsp";
    }

SpringMVC中session的使用

model中的域預設是request域

可以通過在類上加@SessionAttributes註解將他變為session域

@Controller  //將FirstController交由Spring進行管理
@SessionAttributes("msg")
public class FirstController {
    // 四大作用域
    // request: 預設SpringMVC使用的就是request
    // session:可以在處理器的形參中直接獲取HttpSession物件
            // 也可以先在處理器的形參中獲取HttpServletRequest,然後再間接的獲取session
    // servletContext:可以通過HttpServletRequest獲取session,在獲取servletContext
    // pageContext
    @RequestMapping("/test01.action")
    public String test01(Model model){
        model.addAttribute("msg", "red apple");
        return "first";
    }
}

異常處理

為當前Controller配置錯誤處理

當前Controller出錯時執行的方法

@ExceptionHandler

FirstController.java
@Controller 
public class FirstController {    
    // 作為異常的攔截方法
    @ExceptionHandler
    public void exceptionDemo(Exception e){
        System.out.println(e.getMessage());
    }
}

註解方式配置全域性的錯誤處理

全域性出現異常時使用此方法處理

@ControllerAdvice

FirstController.java
@Controller 
@ControllerAdvice  //為全域性配置異常攔截
public class FirstController {    
    // 作為異常的攔截方法
    @ExceptionHandler
    public void exceptionDemo(Exception e){
        System.out.println(e.getMessage());
    }
}

實現返回一段資料 - AJAX

    @RequestMapping("test07.action")
    @ResponseBody
    public Hero test07() throws IOException{
        Hero  hero = new Hero();
        hero.setAge(16);
        hero.setName("張三丰");
        hero.setJob("道士");
        
        return hero;
    }