SpringMVC詳解(補加)

Trycol發表於2020-11-27

SpringMVC詳解(補加)

1. 學習⽬標

在這裡插入圖片描述

2. 攔截器

2.1. 基本概念

SpringMVC 中的 Interceptor 攔截器也是相當重要和相當有⽤的,它的主要作⽤是攔截⽤戶的請求並進⾏相應的處理。⽐如通過它來進⾏許可權驗證,或者是來判斷⽤戶是否登陸等操作。對於 SpringMVC攔截器的定義⽅式有兩種:

  • 實現接⼝:org.springframework.web.servlet.HandlerInterceptor
  • 繼承介面卡:org.springframework.web.servlet.handler.HandlerInterceptorAdapter

2.2. 攔截器實現

2.2.1. 實現 HandlerInterceptor 接⼝

  • 接⼝實現類
package com.suntao.springmvc.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 攔截器實現
 * 實現 HandlerInterceptor 接⼝
 */
public class MyInterceptor01 implements HandlerInterceptor {
    /**
     * 在 ⽬標Handler(⽅法)執⾏前 執⾏
     * 返回 true:執⾏handler⽅法
     * 返回 false:阻⽌⽬標handler⽅法執⾏
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("⽬標Handler執⾏前執⾏MyInterceptor01 --> preHandle⽅ 法...");
        /**
         * 返回 true:執⾏handler⽅法
         * 返回 false:阻⽌⽬標handler⽅法執⾏
         */
        return true;
    }
    /**
     * 在 ⽬標Handler(⽅法)執⾏後,檢視⽣成前 執⾏
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("⽬標Handler執⾏後,檢視⽣成後執⾏MyInterceptor01 --> afterCompletion⽅法...");
    }
}

攔截器spring.xml配置

 <!-- 攔截器配置:⽅式⼀ -->
    <!--<mvc:interceptors>
        &lt;!&ndash;
        使⽤bean定義⼀個Interceptor
        直接定義在mvc:interceptors根下⾯的Interceptor將攔截所有的請求
        &ndash;&gt;
        <bean class="com.suntao.springmvc.interceptor.MyInterceptor01"/>
    </mvc:interceptors>-->
    <!-- 攔截器配置:⽅式⼆ (推薦使⽤) -->
    <mvc:interceptors>
        <!--
        定義在 mvc:interceptor 下⾯,可以⾃定義需要攔截的請求
        如果有多個攔截器滿⾜攔截處理的要求,則依據配置的先後順序來執⾏
        -->
        <mvc:interceptor>
            <!-- 通過 mvc:mapping 配置需要攔截的資源。⽀持萬用字元。可配置多個。 -->
            <mvc:mapping path="/**"/> <!-- "/**"表示攔截所有的請求。 -->
            <!-- 通過 mvc:mapping 配置不需要被攔截的資源。⽀持萬用字元。可配置多個。 -->
            <mvc:exclude-mapping path="/url/*"/> <!-- "/url/*"表示放⾏url路徑下的請
求。 -->
            <bean class="com.suntao.springmvc.interceptor.MyInterceptor01"/>
        </mvc:interceptor>
    </mvc:interceptors>

2.2.2. 繼承 HandlerInterceptorAdapter

實際上最終還是 HandlerInterceptor 接⼝實現。

  • ⼦類實現類
package com.suntao.springmvc.interceptor;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 攔截器實現
 * 繼承 HandlerInterceptorAdapter 介面卡
 */
public class MyInterceptor02 extends HandlerInterceptorAdapter {
    /**
     * 在 ⽬標Handler(⽅法)執⾏前 執⾏
     * 返回 true:執⾏handler⽅法
     * 返回 false:阻⽌⽬標handler⽅法執⾏
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("⽬標Handler執⾏前執⾏MyInterceptor02 --> preHandle⽅ 法...");
        /**
         * 返回 true:執⾏handler⽅法
         * 返回 false:阻⽌⽬標handler⽅法執⾏
         */
        return true;
    }
}

攔截器xml配置

<mvc:interceptors>
		<mvc:interceptor>
            <!-- 攔截的資源 -->
            <mvc:mapping path="/**"/>
            <!-- 放⾏的資源 -->
            <mvc:exclude-mapping path="/url/test01"/>
            <mvc:exclude-mapping path="/url/test02"/>
            <bean class="com.suntao.springmvc.interceptor.MyInterceptor02"/>
        </mvc:interceptor>
    </mvc:interceptors>

2.2.3. 多個攔截器實現

SpringMVC 框架⽀持多個攔截器配置,從⽽構成攔截器鏈,對客戶端請求進⾏多次攔截操作。

  • 攔截器程式碼實現
    這⾥參考MyInterceptor01、MyInterceptor02程式碼
  • 攔截器xml配置
<mvc:interceptors>
	 <!--
 	攔截器鏈(多個攔截器)
		如果有多個攔截器滿⾜攔截處理的要求,則依據配置的先後順序來執⾏
 		先配置的攔截器的 preHandle ⽅法先執⾏
 		先配置的攔截器的 postHandle、afterCompletion ⽅法後執⾏
 	-->
 	<mvc:interceptor>
 		<!-- 攔截所有請求 -->
 		<mvc:mapping path="/**" />
 		<bean class="com.suntao.springmvc.interceptor.MyInterceptor01" />
 </mvc:interceptor>
 	<mvc:interceptor>
 		<!-- 攔截所有請求 -->
 		<mvc:mapping path="/**" />
 		<bean class="com.suntao.springmvc.interceptor.MyInterceptor02" />
 	</mvc:interceptor>
</mvc:interceptors>

2.3. 攔截器應⽤ - ⾮法請求攔截

使⽤攔截器完成⽤戶是否登入請求驗證功能

2.3.1. ⽤戶控制器

UserInfoController 定義

package com.suntao.springmvc.controller;


import com.suntao.springmvc.po.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;

/**
 * ⽤戶操作模擬實現
 * ⽤戶登入(⽆需登入)
 * ⽤戶新增(需要登入)
 * ⽤戶修改(需要登入)
 * ⽤戶刪除(需要登入)
 */
@Controller
@RequestMapping("/userInfo")
public class UserInfoController {
    /**
     * ⽤戶登入
     * @return
     */
    @RequestMapping("/login")
    public ModelAndView userLogin(HttpSession session){
        System.out.println("使用者登入");
        ModelAndView mv = new ModelAndView();
        //設定檢視
        mv.setViewName("success");
        // ⽤戶登入後,設定對應的session域物件
        User user = new User();
        user.setId(1);
        user.setUserName("admin");
        user.setUserPwd("123456");
        session.setAttribute("user",user);

        return mv;
    }
    /**
     * ⽤戶新增
     * @return
     */
    @RequestMapping("/add")
    public ModelAndView userAdd(){
        System.out.println("⽤戶新增...");
        ModelAndView mv = new ModelAndView();
        // 設定檢視
        mv.setViewName("success");
        return mv;
    }
    /**
     * ⽤戶修改
     * @return
     */
    @RequestMapping("/update")
    public ModelAndView userUpdate(){
        System.out.println("⽤戶更新...");
        ModelAndView mv = new ModelAndView();
        // 設定檢視
        mv.setViewName("success");
        return mv;
    }
    /**
     * ⽤戶刪除
     * @return
     */
    @RequestMapping("/delete")
    public ModelAndView userDelete(){
        System.out.println("⽤戶刪除...");
        ModelAndView mv = new ModelAndView();
        // 設定檢視
        mv.setViewName("success");
        return mv;
    }
}

2.3.2.頁面定義

success.jsp 定義

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>Title</title>
</head>
<body>
 <h3>歡迎登入!</h3>
</body>
</html>

2.3.3. ⾮法請求攔截器定義

LoginInterceptor 定義

package com.suntao.springmvc.interceptor;

import com.suntao.springmvc.po.User;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * ⾮法訪問攔截
 */
public class LoginInterceptor extends HandlerInterceptorAdapter {
    /**
     * 在 ⽬標⽅法執⾏前 執⾏
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //獲取session域物件中的user物件
        User user = (User) request.getSession().getAttribute("user");
        //判斷session域物件是否為空
        if(null == user){
            //為空表示使用者未登入
            //攔截使用者跳轉到登入頁面
            response.sendRedirect(request.getContextPath()+"/login.jsp");
            return false;
        }
        return true;
    }
}

2.3.4. 攔截器xml配置

<!-- 攔截所有請求 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- 攔截所有請求 -->
            <mvc:mapping path="/**" />
            <!-- 放⾏⽤戶登入請求 -->
            <mvc:exclude-mapping path="/userInfo/login"/>
            <bean class="com.suntao.springmvc.interceptor.LoginInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>

3. ⽂件上傳

3.1. 環境配置

3.1.1. pom.xml⽂件修改

<!-- 新增 commons-fileupload 依賴 -->
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.2</version>
</dependency>

3.2. 程式碼實現

3.2.1. 單⽂件上傳

3.2.1.1. ⻚⾯表單
  • input 的type設定為file
  • form 表單的method設為post,
  • form 表單的enctype設定為multipart/form-data,以⼆進位制的形式傳輸資料
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>檔案上傳</title>
</head>
<body>
    <form action="uploadFile" method="post" enctype="multipart/form-data">
        <input type="file" name="file" />
        <button type="submit">提交</button>
    </form>
</body>
</html>
3.2.1.2. 程式碼實現
package com.suntao.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;

/**
 * ⽂件上傳
 */
@Controller
public class FileController {
    /**
     * 單⽂件上傳
     * 使⽤MultipartFile物件作為引數,接收前端傳送過來的⽂件
     *
     * @param file
     * @param request
     * @return
     */
    @RequestMapping("/uploadFile")
    public String uploadFile(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        // 判斷⽂件是否為空,如果不為空進⾏對應的⽂件上傳操作
        if (!file.isEmpty()) {
            try {
                // 獲取項⽬的所在的路徑 (絕對路徑)
                String path = request.getServletContext().getRealPath("/");
                // 設定上傳的⽂件存放的⽬錄
                File uploadFile = new File(path + "/upload");
                // 判斷⽂件⽬錄是否存在,不存在則新建⽬錄
                if (!uploadFile.exists()) {
                    // 新建⽬錄
                    uploadFile.mkdir();
                }
                // 獲取上傳⽂件的原⽂件名
                String originalName = file.getOriginalFilename();
                // 獲取上傳的⽂件的字尾
                String suffix =
                        originalName.substring(originalName.lastIndexOf("."));
                // 通過系統當前時間的毫秒數,⽣成隨機⽂件名 (避免上傳的⽂件名重複)
                String fileName = System.currentTimeMillis() + suffix;
                // 上傳⽂件 (轉存⽂件到指定⽬錄)
                file.transferTo(new File(uploadFile, fileName));
                // 設定成功的域物件
                request.setAttribute("msg", "⽂件上傳成功!");
            } catch (IOException e) {
                e.printStackTrace();
                // 如果報錯,設定的域物件
                request.setAttribute("msg", "⽂件上傳失敗!");
            }
        } else {
            // 上傳⽂件不存在,設定的域物件
            request.setAttribute("msg", "⽂件不存在,上傳失敗!");
        }
        return "result";
    }
}

3.2.2. 多⽂件上傳

3.2.2.1. ⻚⾯表單
<form action="uploadFiles" method="post" enctype="multipart/form-data">
	<input type="file" name="files" />
	<input type="file" name="files" />
	<input type="file" name="files" />
	<button type="submit"> 提交</button>
</form>
3.2.2.2.程式碼實現
 /**
     * 上傳⽂件
     *
     * @param file
     * @param request
     */
    public void saveFile(MultipartFile file, HttpServletRequest request) {
        // 判斷⽂件是否為空,如果不為空進⾏對應的⽂件上傳操作
        if (!file.isEmpty()) {
            try {
                // 獲取項⽬的所在的路徑 (絕對路徑)
                String path = request.getServletContext().getRealPath("/");
                // 設定上傳的⽂件存放的⽬錄
                File uploadFile = new File(path + "/upload");
                // 判斷⽂件⽬錄是否存在,不存在則新建⽬錄
                if (!uploadFile.exists()) {
                    // 新建⽬錄
                    uploadFile.mkdir();
                }
                // 獲取上傳⽂件的原⽂件名
                String originalName = file.getOriginalFilename();
                // 獲取上傳的⽂件的字尾
                String suffix = originalName.substring(originalName.lastIndexOf("."));
                // 通過系統當前時間的毫秒數,⽣成隨機⽂件名 (避免上傳的⽂件名重複)
                String fileName = System.currentTimeMillis() + suffix;
                // 上傳⽂件 (轉存⽂件到指定⽬錄)
                file.transferTo(new File(uploadFile, fileName));
                // 設定成功的域物件
                request.setAttribute("msg", "⽂件上傳成功!");
            } catch (IOException e) {
                e.printStackTrace();
                // 如果報錯,設定的域物件
                request.setAttribute("msg", "⽂件上傳失敗!");
            }
        } else {
            // 上傳⽂件不存在,設定的域物件
            request.setAttribute("msg", "⽂件不存在,上傳失敗!");
        }
    }

    /**
     * 多⽂件上傳
     *
     * @param files
     * @param request
     * @return
     */
    @RequestMapping("/uploadFiles")
    public String uploadFiles(@RequestParam("files") List<MultipartFile> files,
                              HttpServletRequest request) {
        // 判斷⽂件集合是否為空
        if (files != null && files.size() > 0) {
            // 迴圈上傳
            for (MultipartFile file : files) {
                // 上傳⽂件
                saveFile(file, request);
            }
        }
        return "result";
    }

4. SSM 框架整合與測試

4.1. 環境配置

4.1.1. IDEA 下建立項⽬

建立Maven對應的Web項⽬

4.1.2. 配置 pom.xml

4.1.2.1. 修改 JDK 版本與新增座標依賴、設定資源⽬錄和外掛
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.suntao</groupId>
  <artifactId>ssm</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>ssm Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <!-- spring 核⼼jar -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>
    <!-- spring 測試jar -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>

    <!-- spring jdbc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>
    <!-- spring事物 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>
    <!-- aspectj切⾯程式設計的jar -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.5</version>
    </dependency>

    <!-- c3p0 連線池 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
    </dependency>
    <!-- mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.3</version>
    </dependency>
    <!-- 新增mybatis與Spring整合的核⼼包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.3</version>
    </dependency>

      <!-- mysql 驅動包 -->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.19</version>
      </dependency>
      <!-- ⽇志列印相關的jar -->
      <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.7.2</version>
      </dependency>
      <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>1.7.2</version>
      </dependency>

    <!-- 分⻚外掛 -->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.10</version>
    </dependency>
    <!-- spring web -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>
    <!-- spring mvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>
    <!-- web servlet -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
    </dependency>
    <!-- 新增json 依賴jar包(注意版本問題) -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.10.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.10.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.10.0</version>
    </dependency>
    <!-- commons-fileupload -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.2</version>
    </dependency>



  </dependencies>

  <build>
    <finalName>ssm</finalName>
    <!--
    Maven 項⽬:如果原始碼(src/main/java)存在xml、properties、tld 等⽂件
    Maven 預設不會⾃動編譯該⽂件到輸出⽬錄,如果要編譯原始碼中xml properties tld 等⽂件
    需要顯式配置 resources 標籤
    -->
    <resources>
      <resource>
        <directory>src/main/resources</directory>
      </resource>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
          <include>**/*.tld</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
    <plugins>
      <!-- 編譯環境外掛 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
      <!-- jetty外掛 -->
      <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>9.4.27.v20200227</version>
        <configuration>
          <scanIntervalSeconds>10</scanIntervalSeconds>
          <!-- 設定端⼝ -->
          <httpConnector>
            <port>8989</port>
          </httpConnector>
          <!-- 設定項⽬路徑 -->
          <webAppConfig>
            <contextPath>/ssm</contextPath>
          </webAppConfig>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

4.1.3. 配置 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <!-- 啟動spring容器-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring.xml</param-value>
  </context-param>
  <!-- 設定監聽器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- 編碼過濾 utf-8 -->
  <filter>
    <description>char encoding filter</description>
    <filter-name>encodingFilter</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>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!-- servlet請求分發器 -->
  <servlet>
    <servlet-name>springMvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:servlet-context.xml</param-value>
    </init-param>
    <!-- 表示啟動容器時初始化該Servlet -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springMvc</servlet-name>
    <!-- 這是攔截請求, "/"代表攔截所有請求,"*.do"攔截所有.do請求 -->
    <url-pattern>/</url-pattern>
    <!--<url-pattern>*.do</url-pattern>-->
  </servlet-mapping>
</web-app>

4.1.4. 配置 servlet-context.xml

在項⽬的 src/main/resources 下建立 servlet-context.xml ⽂件, 內容如下

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
 http://www.springframework.org/schema/mvc
 http://www.springframework.org/schema/mvc/spring-mvc.xsd
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 開啟掃描器 -->
    <context:component-scan base-package="com.xxxx.ssm.controller" />
    <!-- mvc 註解驅動 並新增json ⽀持 -->
    <mvc:annotation-driven>
        <mvc:message-converters>
            <!-- 返回資訊為字串時 處理 -->
            <bean
                    class="org.springframework.http.converter.StringHttpMessageConverter"/>
            <!-- 將物件轉換為json 物件 -->
            <bean
                    class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <!-- 使⽤預設的 Servlet 來響應靜態⽂件 -->
    <mvc:default-servlet-handler/>

    <!-- 配置檢視解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!-- 字首:在WEB-INF⽬錄下的jsp⽬錄下 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 字尾:以.jsp結尾的資源 -->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- ⽂件上傳 -->
    <bean id="multipartResolver"

          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 允許⽂件上傳的最⼤尺⼨ -->
        <property name="maxUploadSize">
            <value>104857600</value>
        </property>
        <!--
        設定⽂件放⼊臨時⽂件夾的最⼤⼤⼩限制。
        此值是閾值,低於此值,則儲存在記憶體中,如⾼於此值,則⽣成硬碟上的臨時⽂件。
        -->
        <property name="maxInMemorySize">
            <value>4096</value>
        </property>
    </bean>
</beans>

4.1.5. 配置 spring.xml

在項⽬的 src/main/resources 下建立 spring.xml ⽂件, 內容如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!-- 掃描基本包 -->
    <context:component-scan base-package="com.xxxx.ssm" >
        <!-- context:exclude-filter標籤:排除對某個註解的掃描 (過濾controller層)
       -->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    <!-- 載入properties 配置⽂件 -->
    <context:property-placeholder location="classpath:db.properties" />
    <!-- aop -->
    <aop:aspectj-autoproxy />
    <!-- 配置c3p0 資料來源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!-- 配置事務管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 設定事物增強 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    <!-- aop 切⾯配置 -->
    <aop:config>
        <aop:pointcut id="servicePointcut"
                      expression="execution(* com.xxxx.ssm.service..*.*(..))"
        />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut" />
    </aop:config>
    <!-- 配置 sqlSessionFactory -->
    <bean id="sqlSessionFactory"
          class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis.xml" />
        <property name="mapperLocations" value="classpath:com/xxxx/ssm/mapper/*.xml" />
    </bean>
    <!-- 配置掃描器 -->
    <bean id="mapperScanner"
          class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 掃描com.xxxx.ssm.dao這個包以及它的⼦包下的所有對映接⼝類 -->
        <property name="basePackage" value="com.xxxx.ssm.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>
</beans>

4.1.6. 配置 mybatis.xml

在項⽬的 src/main/resources 下建立 mybatis.xml ⽂件, 內容如下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="com.xxxx.ssm.po"/>
    </typeAliases>
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
</configuration>

4.1.7. 配置 db.properties

在項⽬的 src/main/resources 下建立 db.properties ⽂件,內容如下(mysql 建立資料庫ssm)

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?
useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
jdbc.username=root
jdbc.password=123456

4.1.8. 新增 log4j.properties

在項⽬的 src/main/resources 下建立 log4j.properties ⽂件,內容如下

log4j.rootLogger=DEBUG, Console
# Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

4.2. 新增原始碼

4.2.1. 新增包

在項⽬的 src/main/java 下建立對應的包結構
com.xxxx.ssm.controller
com.xxxx.ssm.service
com.xxxx.ssm.mapper
com.xxxx.ssm.dao
com.xxxx.ssm.po

4.2.2. 新增 User.java

在 com.xxxx.ssm.po 包下建立 JavaBean ⽂件 User.java (資料庫欄位對應如下)

package com.xxxx.ssm.po;

import java.util.Date;

public class User {

    private Integer userId;
    private String userName;
    private String userPwd;
    private String userEmail;
    private Date createDate;
    private Date updateDate;

    public User() {
    }

    public User(Integer userId, String userName, String userPwd, String userEmail, Date createDate, Date updateDate) {
        this.userId = userId;
        this.userName = userName;
        this.userPwd = userPwd;
        this.userEmail = userEmail;
        this.createDate = createDate;
        this.updateDate = updateDate;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPwd() {
        return userPwd;
    }

    public void setUserPwd(String userPwd) {
        this.userPwd = userPwd;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public Date getUpdateDate() {
        return updateDate;
    }

    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userPwd='" + userPwd + '\'' +
                ", userEmail='" + userEmail + '\'' +
                ", createDate=" + createDate +
                ", updateDate=" + updateDate +
                '}';
    }
}

4.2.3. 新增UserDao.java 接⼝

com.xxxx.ssm.dao 包下建立 UserDao.java ⽂件,提供對應的⽤戶詳情查詢功能

public interface UserDao {
	User queryUserByUserId(Integer userId);
}

4.2.4. 新增UserMapper.xml 對映⽂件

com.xxxx.ssm.mapper 包下建立 UserMapper.xml ⽂件,提供select 查詢標籤配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxxx.ssm.dao.UserDao">
    <select id="queryUserByUserId" parameterType="int" resultType="com.xxxx.ssm.po.User">
        select
            user_id userId,user_name userName, user_pwd userPwd , user_email userEmail,
            create_date createDate, update_date updateDate
        from
            user
        where
            user_id = #{id}
 </select>
</mapper>

4.2.5. 新增 UserService.java

com.xxxx.ssm.service 包下建立UserService.java ⽂件,提供⽤戶詳情查詢⽅法

package com.xxxx.ssm.service;

import com.xxxx.ssm.dao.UserDao;
import com.xxxx.ssm.po.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    public User queryUserByUserId(Integer userId){
        return userDao.queryUserByUserId(userId);
    }
}

4.2.6. 新增 HelloController.java

在 com.xxxx.ssm.controller 包下建立 HelloController.java ⽂件

package com.xxxx.ssm.controller;

import com.xxxx.ssm.po.User;
import com.xxxx.ssm.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {
    // 注⼊userService
    @Autowired
    private UserService userService;
    @RequestMapping("/hello")
    public ModelAndView hello(){
        ModelAndView mv = new ModelAndView();
        // 調⽤service 層查詢⽅法
        User user = userService.queryUserByUserId(1);
        mv.addObject("user", user);
        mv.setViewName("hello");
        return mv;
    }
}

4.2.7. 新增 hello.jsp 檢視⽂件

在src/main/webapp/WEB-INF 建立jsp ⽬錄,並在該⽬下建立hello.jsp ,展示查詢的⽤戶資訊

<body>
	歡迎你,${user.userName}
</body>

4.3. 執⾏測試

4.3.1. Idea 下配置 jetty 啟動命令

在這裡插入圖片描述

4.3.2. 啟動 jetty 瀏覽器訪問http://localhost:8080/ssm/hello檢視結果

5. RestFul URL

5.1. 基本概念

模型 - 檢視 - 控制器(MVC)是⼀個眾所周知的以設計界⾯應⽤程式為基礎的設計思想。


Restful ⻛格的 API 是⼀種軟體架構⻛格,設計⻛格⽽不是標準,只是提供了⼀組設計原則和約束條件。它主要⽤於客戶端和伺服器互動類的軟體。基於這個⻛格設計的軟體可以更簡潔,更有層次,更易於實現快取等機制。


在Restful ⻛格中,⽤戶請求的 url 使⽤同⼀個 url,⽤請求⽅式:get,post,delete,put…等⽅式對請求的處理⽅法進⾏區分,這樣可以在前後臺分離式的開發中使得前端開發⼈員不會對請求的資源地址產⽣混淆和⼤量的檢查⽅法名的麻煩,形成⼀個統⼀的接⼝。


在 Restful ⻛格中,現有規定如下:

  • GET(SELECT):從伺服器查詢,可以在伺服器通過請求的引數區分查詢的⽅式。
  • POST(CREATE):在伺服器端新建⼀個資源,調⽤ insert 操作。
  • PUT(UPDATE):在伺服器端更新資源,調⽤ update 操作。
  • PATCH(UPDATE):在伺服器端更新資源(客戶端提供改變的屬性)。(⽬前 jdk7 未實現,tomcat7 不⽀持)。
  • DELETE(DELETE):從伺服器端刪除資源,調⽤ delete 語句。

5.2. SpringMVC ⽀持 RestFul URL ⻛格設計

案例:如何使⽤ Java 構造沒有副檔名的RESTful url,如 /forms/1?
SpringMVC 是通過 @RequestMapping 及 @PathVariable 註解提供的。
通過如@RequestMapping(value="/blog /{id}", method = RequestMethod.DELETE),即可處理/blog/1 的 delete 請求。

5.3. RestFul URL 對映地址配置

5.3.1. 準備環境

5.3.1.1. 新增 Account

在 src/resources/java 對應的 com.xxxx.ssm.po ⽬錄下新建 Account.java 實體類

package com.xxxx.ssm.po;

import java.util.Date;

public class Account {

    private Integer accountId;
    private String accountName;
    private String accountType;
    private Double money;
    private Date createDate;
    private Date updateDate;
    private String remark;

    public Integer getAccountId() {
        return accountId;
    }

    public void setAccountId(Integer accountId) {
        this.accountId = accountId;
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public String getAccountType() {
        return accountType;
    }

    public void setAccountType(String accountType) {
        this.accountType = accountType;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public Date getUpdateDate() {
        return updateDate;
    }

    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }
}

5.3.1.2. 新增 AccountDao

在 src/resources/java 對應的 com.xxxx.ssm.dao ⽬錄下新建 AccountDao.java 接⼝類

package com.xxxx.ssm.dao;

import com.xxxx.ssm.po.Account;
import com.xxxx.ssm.po.User;

public interface AccountDao {

    //查詢
    public Account queryAccountById(Integer id);

    //刪除
    public Integer deleteAccountById(Integer id);

    //修改
    public Integer updateAccount(Account account);

    //新增
    public Integer insertAccount(Account account);

}

}
5.3.1.3. 新增 AccountMapper

在 src/resources/java 對應的 com.xxxx.ssm.mapper ⽬錄下新建 AccountMapper.xml 對映⽂件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxxx.ssm.dao.AccountDao">
    <select id="queryAccountById" parameterType="Integer" resultType="com.xxxx.ssm.po.Account">
        select
            account_id accountId,account_name accountName , money money , account_type accountType,
            create_date createDate, update_date updateDate , remark remark
        from
            tb_account
        where
            account_id = #{id}
    </select>

    <delete id="deleteAccountById" parameterType="Integer">
        delete from tb_account where account_id = #{id}
    </delete>

    <update id="updateAccount" parameterType="com.xxxx.ssm.po.Account">
        update
            tb_account
        set
            account_name = #{accountName},
            money = #{money},
            account_type = #{accountType},
            create_date = now(),
            update_date = now(),
            remark = #{remark}
        where
            account_id = #{accountId}
    </update>

    <insert id="insertAccount" parameterType="com.xxxx.ssm.po.Account">
        insert into
            tb_account(account_name , money  , account_type ,create_date , update_date  , remark )
        values
            (#{accountName},#{money},#{accountType},now(),now(),#{remark})
    </insert>
</mapper>
5.3.1.4. 新增 AccountService

在 src/resources/java 對應的 com.xxxx.ssm.service ⽬錄下新建 AccountService.java

@Service
public class AccountService {
 	@Autowired
 	private AccountDao accountDao;
 	public Account selectById(Integer id){
 		return accountDao.selectById(id);
 	}
 	public int saveAccount(Account account){
 		return accountDao.save(account);
 	}
 	public int updateAccount(Account account){
 		return accountDao.update(account);
 	}
 	public int delAccount(Integer id){
 		return accountDao.delete(id);
 	}
}

5.3.2. URL 對映地址配置

5.3.2.1. 請求配置
package com.xxxx.ssm.controller;

import com.xxxx.ssm.po.Account;
import com.xxxx.ssm.service.AccountService;
import com.xxxx.ssm.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * RestFul
 *      GET
 *      POST
 *      PUT
 *      DELETE
 *
 *      @RequestMapping(value = "url地址",method = RequestMethod.GET)
 *
 *      @PathVariable:表示引數為地址引數(值在url地址中)
 */
@Controller
public class AccountController {

    @Resource
    private AccountService accountService;

    @GetMapping("account/{id}")
    @ResponseBody
    public Account queryUser(@PathVariable Integer id){
        return accountService.queryAccountById(id);
    }

    @DeleteMapping("account/{id}")
    public ModelAndView deleteUser(@PathVariable Integer id){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("New_result");
        Integer index = accountService.deleteAccountById(id);
        if(index > 0){
            mv.addObject("msg","刪除成功");
            mv.addObject("code",1);
        }else{
            mv.addObject("msg","刪除失敗");
            mv.addObject("code",0);
        }
        return mv;
    }


    @PostMapping("account")
    public ModelAndView insertUser(@RequestBody Account account){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("New_result");
        Integer index = accountService.insertAccount(account);
        if(index > 0){
            mv.addObject("msg","新增成功");
            mv.addObject("code",1);
        }else{
            mv.addObject("msg","新增失敗");
            mv.addObject("code",0);
        }
        return mv;
    }


    @PutMapping("account")
    public ModelAndView updatetUser(@RequestBody Account account){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("New_result");
        Integer index = accountService.updateAccount(account);
        if(index > 0){
            mv.addObject("msg","修改成功");
            mv.addObject("code",1);
        }else{
            mv.addObject("msg","修改失敗");
            mv.addObject("code",0);
        }
        return mv;
    }
}

6. 全域性異常統⼀處理

6.1. 全域性異常概念

在 JavaEE 項⽬的開發中,不管是對底層的資料庫操作過程,還是業務層的處理過程,還是控制層的處理過程,都不可避免會遇到各種可預知的、不可預知的異常需要處理。每個過程都單獨處理異常,系統的程式碼耦合度⾼,⼯作量⼤且不好統⼀,維護的⼯作量也很⼤。SpringMVC 對於異常處理這塊提供了⽀持,通過 SpringMVC 提供的全域性異常處理機制,能夠將所有型別的異常處理從各處理過程解耦出來,既保證了相關處理過程的功能較單⼀,也實現了異常資訊的統⼀處理和維護。
全域性異常實現⽅式 Spring MVC 處理異常有 3 種⽅式:

  1. 使⽤ Spring MVC 提供的簡單異常處理器 SimpleMappingExceptionResolver
  2. 實現 Spring 的異常處理接⼝ HandlerExceptionResolver ⾃定義⾃⼰的異常處理器
  3. 使⽤ @ExceptionHandler 註解實現異常處理

6.2. 異常處理實現

6.2.1. 全域性異常處理⽅式⼀

6.2.1.1. 配置簡單異常處理器

配置 SimpleMappingExceptionResolver 物件

<!-- 配置全域性異常統⼀處理的 Bean (簡單異常處理器) -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
 <!-- ⻚⾯在轉發時出現異常,設定預設的錯誤⻚⾯ (error代表的是⼀個檢視) -->
 <property name="defaultErrorView" value="error"></property>
 <!-- 異常發⽣時,設定異常的變數名 -->
 <property name="exceptionAttribute" value="ex"></property>
</bean>

可以在處理異常的⻚⾯獲取異常資訊

${ex}
6.2.1.2. 使⽤⾃定義異常

引數異常

/**
* ⾃定義異常:引數異常
*/
public class ParamsException extends RuntimeException {

 	private Integer code = 300;
	private String msg = "引數異常!";
 	public ParamsException() {
 		super("引數異常!");
 	}
 	public ParamsException(String msg) {
 		super(msg);
 		this.msg = msg;
 	}
 	public ParamsException(Integer code) {
 		super("引數異常!");
 		this.code = code;
 	}
 	public ParamsException(Integer code, String msg) {
 		super(msg);
 		this.code = code;
 		this.msg = msg;
 	}
 	public Integer getCode() {
 		return code;
 	}
 	public void setCode(Integer code) {
 		this.code = code;
 	}
 	public String getMsg() {
 		return msg;
 	}
 	public void setMsg(String msg) {
 		this.msg = msg;
 	}
}

業務異常

/**
* ⾃定義異常:業務異常
*/
public class BusinessException extends RuntimeException {
 	private Integer code=400;
 	private String msg="業務異常!";

 	public BusinessException() {
 		super("業務異常!");
 	}
 	public BusinessException(String msg) {
 		super(msg);
 		this.msg = msg;
 	}
 	public BusinessException(Integer code) {
 		super("業務異常!");
 		this.code = code;
 	}
 	public BusinessException(Integer code, String msg) {
 		super(msg);
 		this.code = code;
 		this.msg = msg;
 	}
 	public Integer getCode() {
 		return code;
 	}
 	public void setCode(Integer code) {
 		this.code = code;
 	}
 	public String getMsg() {
 		return msg;
 	}
 	public void setMsg(String msg) {
 		this.msg = msg;
 	}
}
6.2.1.3. 設定⾃定義異常與⻚⾯的對映
<!-- 設定⾃定義異常與⻚⾯的對映 -->
<property name="exceptionMappings">
 	<props>
 	<!-- key:⾃定義異常物件的路徑; 標籤中設定具體的處理⻚⾯的檢視名-->
 	<prop key="com.xxxx.ssm.exception.BusinessException">error</prop>
 	<prop key="com.xxxx.ssm.exception.ParamsException">error</prop>
 	</props>
</property>

使⽤ SimpleMappingExceptionResolver 進⾏異常處理,具有整合簡單、有良好的擴充套件性、對已有程式碼沒有⼊侵性等優點,但該⽅法僅能獲取到異常資訊,若在出現異常時,對需要獲取除異常以外的資料的情況不適⽤。

6.2.2. 全域性異常處理⽅式⼆(推薦)

6.2.2.1. 實現 HandlerExceptionResolver 接⼝
/**
* 全域性異常統⼀處理
*/
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
 	@Override
 	public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler,Exception ex) {
 	ModelAndView mv = new ModelAndView("error");
 	mv.addObject("ex","預設錯誤資訊");
 	return mv;
 	}
}
6.2.2.2. ⾃定義異常處理
/**
* 全域性異常統⼀處理
*/
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
 	@Override
 	public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler,Exception ex) {
 	ModelAndView mv = new ModelAndView("error");
 	mv.addObject("ex","預設錯誤資訊");
 	// 判斷是否是⾃定義異常
 	if (ex instanceof ParamsException) {
 	mv.setViewName("params_error");
 	ParamsException e = (ParamsException) ex;
 	mv.addObject("ex", e.getMsg());
 	}
 	if (ex instanceof BusinessException) {
 	mv.setViewName("business_error");
 	BusinessException e = (BusinessException) ex;
 	mv.addObject("ex", e.getMsg());
 	}
 	return mv;
 	}
}

6.2.3. 全域性異常處理⽅式三

⻚⾯處理器繼承 BaseController

public class BaseController {
 @ExceptionHandler
 public String exc(HttpServletRequest request,HttpServletResponse response,Exception ex){
	request.setAttribute("ex", ex);
 	if(ex instanceof ParamsException){
 		return "error_param";
 	}
 	if(ex instanceof BusinessException){
 		return "error_business";
 	}
 		return "error";
 	}
}

使⽤ @ExceptionHandler 註解實現異常處理,具有整合簡單、有擴充套件性好(只需要將要異常處理的Controller 類繼承於 BaseController 即可)、不需要附加Spring 配置等優點,但該⽅法對已有程式碼存在⼊侵性(需要修改已有程式碼,使相關類繼承於 BaseController),在異常處理時不能獲取除異常以外的資料。

6.3. 未捕獲異常的處理

對於 Unchecked Exception ⽽⾔,由於程式碼不強制捕獲,往往被忽略,如果運⾏期產⽣了
Unchecked Exception,⽽程式碼中⼜沒有進⾏相應的捕獲和處理,則我們可能不得不⾯對尷尬的 404、500……等伺服器內部錯誤提示⻚⾯。


此時需要⼀個全⾯⽽有效的異常處理機制。⽬前⼤多數伺服器也都⽀持在 web.xml 中通過
(Websphere/Weblogic)或者(Tomcat)節點配置特定異常情況的顯示⻚⾯。修改 web.xml ⽂件,增加以下內容:

<!-- 出錯⻚⾯定義 -->
<error-page>
 	<exception-type>java.lang.Throwable</exception-type>
 	<location>/500.jsp</location>
</error-page>
<error-page>
 	<error-code>500</error-code>
 	<location>/500.jsp</location>
</error-page>
<error-page>
 	<error-code>404</error-code>
 	<location>/404.jsp</location>
</error-page>

7. 總結

SpringMVC 攔截器概念、實現配置與應⽤場景,藉助SpringMvc來實現應⽤資源的攔截操作,藉助 SpringMVC 框架⽂件上傳環境實現了單⽂件與多⽂件上傳功能。同時為了以後使⽤ SSM 框架開發企業應⽤,還完成了 SSM 框架環境整合操作,以後對與 SpringMVC 應⽤的開發基本都是在整合環境下進⾏,這⾥希望⼤家能夠在整合環境下實現功能程式碼開發操作。


最後兩塊主要介紹 Restful 概念,在 SpringMVC 環境下 Restful URL 地址設計規範與賬戶模組程式碼實現,同時對於應⽤程式的異常通過使⽤ SpringMVC 全域性異常來進⾏統⼀處理,從⽽降低異常處理程式碼的耦合度。

相關文章