SpringMVC框架從入門到總結二

json數據交互

案例實現

  1. 導入pom依賴
    說明:springmvc框架,默認使用HttpMessageConverter消息轉換器,進行json格式數據轉換。需要加入jackson依賴包支持
 <!--依賴管理-->
    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>
        <!--Apache的文件解析器-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
    </dependencies>
  1. SpringMVC核心配置文件
<?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:mvc="http://www.springframework.org/schema/mvc"
       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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- bean definitions here -->
    
	<!--開啓包掃描註解-->
    <context:component-scan base-package="cn.itcast.controller"></context:component-scan>
    
	<!--springmvc的註解驅動-->
    <mvc:annotation-driven></mvc:annotation-driven>
	
	<!--視圖解析器的前綴和後綴-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="suffix" value=".jsp"></property>
        <property name="prefix" value="/WEB-INF/jsp/"></property>
    </bean>
	
	<!--前端控制器是/,所以要釋放靜態資源-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>
</beans>
  1. web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

    <!--配置前端控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--將springmvc的配置文件交給前端控制器-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:SpringConfig.xml</param-value>
        </init-param>
    </servlet>

    <!--攔截規則-->
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!--亂碼過濾器-->
    <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>
    
</web-app>
  1. log4j日誌文件
### direct log messages to stdout ###
### 輸出源的配置 語法  log4j.appender.輸出源的名字=輸出源的實現類 ###
### log4j.appender.輸出源的名字.屬性=屬性值   ###
log4j.appender.a=org.apache.log4j.ConsoleAppender
log4j.appender.a.Target=System.out
log4j.appender.a.layout=org.apache.log4j.PatternLayout
log4j.appender.a.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=/home/travel.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###
### 日誌記錄器的配置,固定語法  log4j.rootLogger=輸出級別, 輸出源,輸出源...  ###
log4j.rootLogger=debug, a,file
  1. MyController
@Controller
public class MyController {
    @RequestMapping("/demo")
    public String demo() {
        return "demo";
    }

    @ResponseBody  //直接聲明一個方法,返回值類型是java實體對象類型.在方法上添加@ResponseBody註解通過springmvc轉換json
    @RequestMapping("/returnJson")
    public Item returnJson() {
        Item item = new Item();
        item.setName("耳機");
        item.setPrice(1000);
        item.setDetail("詳情");
        return item;
    }

    @RequestMapping("/getJson")
    @ResponseStatus(HttpStatus.OK)//void類型,並且沒有響應體
    public void getJson(@RequestBody Item item) { //@RequestBody 讓springmvc將請求中的json轉換成java中的對象
        System.out.println(item);
    }
}

如果一個controller中所有的方法全部都是json返回值,我們直接使用@RestController來替代之前的@Controller

restful支持

restful介紹

  1. restful是一種軟件設計風格
  2. restful根據HTTP請求方法:
    POST/GET/PUT/DELETE,定義了資源的操作方法:新增/查詢/修改/刪除
  3. restful風格的優點:
    結構清晰、符合標準、易於理解、 擴展方便、請求的url更加簡潔,得到越來越多網站的採用

案例實現

步驟:

  /**
     *  restful風格:
     *  需求:
     *      /item/1   get     查詢id爲1的商品信息
     *      /item/1   delete  刪除id爲1的商品
     *      /item/1   put     更新id爲1的商品
     *      /item     post     新增
     *
     *  步驟:
     *      1.後臺需要4個方法來處理請求.但是這4個方法映射的路徑是一樣,只是限定請求的方式不一樣
     *      2.前端發送請求,請求的地址一樣,但是請求的方式不一樣:
     *          a.通過rest插件發送put和delete請求
     *          b.springmvc提供了一個HiddenHttpMethodFilter,將所有的POST請求轉換成對應的post或者delete或者get或者put請求
     *            根據POST請求中的_method參數的值進行轉換
     */

RestfulController

@Controller
public class RestfulController {

    @RequestMapping(value = "/item/{id}", method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    public void queryItemById(@PathVariable("id") String id) {
        System.out.println("查詢商品:" + id);
    }

    @RequestMapping(value = "/item/{id}", method = RequestMethod.DELETE)
    @ResponseStatus(HttpStatus.OK)
    public void deleteItemById(@PathVariable String id) {
        System.out.println("刪除商品:" + id);
    }

    @RequestMapping(value = "/item/{id}", method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.OK)
    public void updateItemById(@PathVariable String id) {
        System.out.println("修改商品:" + id);
    }

    @RequestMapping(value = "/item/{id}", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.OK)
    public void add() {
        System.out.println("添加商品");
    }

}

前端頁面請求:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <form action="/item/1" method="post">
        <input type="hidden" name="_method" value="GET">
        <input type="submit" value="get請求">
    </form>

    <form action="/item/2" method="post">
        <input type="hidden" name="_method" value="DELETE">
        <input type="submit" value="delete請求">
    </form>

    <form action="/item/3" method="post">
        <input type="hidden" name="_method" value="PUT">
        <input type="submit" value="put請求">
    </form>

    <form action="/item/1" method="post">
        <input type="hidden" name="_method" value="POST">
        <input type="submit" value="post請求">
    </form>
</body>
</html>

web.xml
請求方式過濾器

<!--請求方式過濾器-->
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

@PathVariable註解

請求中,路徑中的變量

路徑中的變量:
 *      變量格式 : {變量名}
 *
 *     獲取路徑中的變量格式   @PathVariable(變量名)
 *                      如果變量名和方法名一樣,  直接寫@PathVariable

文件上傳

servlet中的文件上傳

  •   前端
      a.請求的方式必須是post類型.
      b.inpute type=file 文件標籤
      c.enctype=multipart/form-data
    
  •   後臺servlet
      a.在servlet上添加一個註解,用來解析文件上傳的這種數據格式類型
      b.直接使用request.getPart();獲取文件
    

文件上傳三要素

  • 表單的提交方式 method=“POST”
  • 表單的enctype屬性是多部分表單形式 enctype=“multipart/form-data"
  • 表單項(元素)type=“file”
<form action="" method="post" enctype="multipart/form-data">
    姓名:<input type="text" name="username"> <br>
	頭像:<input type="file" name="picFile"> <br>
</form>

SpringMVC實現文件上傳

案例實現

步驟:

  /**
     *  springmvc的文件上傳:
     *   前端:
     *      a.請求的方式必須是post類型.
            b.inpute type=file 文件標籤
            c.enctype=multipart/form-data
     *
     *   後臺:
     *      springmvc是通過apache的fileUpload依賴來解析文件的.
     *      1.需要引入apache的fileupload依賴
     *      2.配置一個文件解析器
     *      3.直接在handler中聲明MultipartFile 類型的變量,然後直接操作
     */

pom依賴

<!--apache的文件解析器-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>

springMVC.xml

    <!--配置文件解析器-->
    <!--id:必須是multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--限制文件上傳的大小 字節-->
        <property name="maxUploadSize" value="10240000"></property>
        <!--上傳的文件名的編碼-->
        <property name="defaultEncoding" value="utf-8"></property>

    </bean>

UploadFileController

@Controller
public class UploadFileController {

    @ResponseStatus(HttpStatus.OK)
    @RequestMapping("/updateItem.do")
    public void updateItem(Item item, @RequestParam("img") MultipartFile pictureFile) {
        System.out.println("表單參數插入到數據庫:" + item);

        //獲取源文件名
        String originalFilename = pictureFile.getOriginalFilename();
        //保存圖片
        try {
            pictureFile.transferTo(new File("d://" + originalFilename));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

統一異常處理

概述

  1. 請求流程:
    客戶端(瀏覽器)–>前端控制器(DispatcherServlet)–>表現層(controller)–>業務層(service)–>持久層(dao)

  2. 處理思路:
    從持久層dao開始,每一層發生異常都向上一層拋出,一直拋到前端控制器(DispatcherServlet)。到此不能再拋出,我們不能把異常拋給用戶
    在前端控制器需要進行異常處理,前端控制器是中央處理器,不負責具體的業務處理,因此在前端控制器需要調用異常處理器進行異常處理,最終返回一個友好的異常提示頁面,提示用戶
    在這裏插入圖片描述

案例實現

需求:根據商品id查詢商品,如果查詢不到商品,拋出商品不存在異常
步驟:

  • 1.自定義異常
  • 2.拋出運行時異常
  • 3.自定義異常處理器,實現HandlerExceptionResolver接口
  • 4.在springmvc中配置當前異常處理器對象

NoResultException

//自定義一個異常類
public class NoResultException extends Exception {
    public NoResultException(String message) {
        super(message);
    }
}

Controller

@Controller
public class ExceptionController {

    @ResponseStatus(HttpStatus.OK)
    @RequestMapping("/findItemById")
    public void findItemById(Integer id) throws NoResultException {
        if (id > 5) {
            System.out.println("查詢id爲" + id + "的商品不存在");
            //throw new NoResultException("查詢id爲" + id + "的商品不存在");
        } else {
            System.out.println("查詢id爲" + id + "的商品信息");
        }
    }
}

MyExceptionResolver

//自定義異常處理器,捕獲到的所有異常,都在這裏統一處理
public class MyExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView modelAndView = new ModelAndView();

        //需要判斷異常的類型
        if (ex instanceof NoResultException) {
            //獲取業務中的錯誤信息
            String message = ex.getMessage();
            //保存數據
            modelAndView.addObject("errorMsg", message);
        } else if (ex instanceof MaxUploadSizeExceededException) {
            modelAndView.addObject("errorMsg", "上傳的圖片過大");

        }
        //錯誤的頁面視圖
        modelAndView.setViewName("error");
        return modelAndView;
    }
}

SpringMVC.xml

    <!--配置異常處理器-->
    <bean id="exceptionResolver" class="cn.itcast.exceptionHandler.MyExceptionResolver"></bean>

SpringMVC攔截器

概述

  1. springmvc框架中的攔截器,相當於web階段學習的過濾器(filter),可以實現前置增強和後置增強功能
  2. 在springmvc框架中,攔截器可以對處理器方法執行預處理(前置增強),和執行後處理(後置增強)
  •   web開發中過濾器的作用:
      在請求訪問目標資源之前進行攔截,一般都是通用性功能的抽取。(多個請求共有功能的抽取)
      例如亂碼的處理,用於登錄的判斷,權限的判斷。。。。
    
  •   在springmvc中,只有一個servlet。所有的請求,都是經過servlet再派發到controller。
      ItemController進行攔截。
      /item/save
      /item/delete
    

在這裏插入圖片描述

快速入門

需求:

  1. 創建一個demo級別的handler
  2. 創建一個類,實現攔截器接口 HandlerInterceptor
  3. 在springmvc.xml中配置攔截器

Controller

@Controller
@RequestMapping("/interceptor")
public class InterceptorController {
    @RequestMapping("/demo")
    public String demo(Model model) {
        model.addAttribute("msg", "controller");
        System.out.println("經過了controller");
        return "demo";
    }

}

interceptor

//攔截器
public class MyInterceptor1 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("在controller的handler之前執行");
        return true; //返回true,表示放行.
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("在controller的handler之後執行,但是在視圖渲染之前");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("在視圖渲染之後做這個功能");
    }
}

/**輸出結果爲:
 * 在controller的handler之前執行
 * 經過了controller
 * 在controller的handler之後執行,但是在視圖渲染之前
 * 2020-06-23 21:04:01,587 [http-nio-8080-exec-1] [org.springframework.web.servlet.DispatcherServlet]-[DEBUG] Rendering view [org.springframework.web.servlet.view.InternalResourceView: name 'demo'; URL [/WEB-INF/jsp/demo.jsp]] in DispatcherServlet with name 'DispatcherServlet'
 * 2020-06-23 21:04:01,587 [http-nio-8080-exec-1] [org.springframework.web.servlet.view.InternalResourceView]-[DEBUG] Added model object 'msg' of type [java.lang.String] to request in view with name 'demo'
 * 2020-06-23 21:04:01,588 [http-nio-8080-exec-1] [org.springframework.web.servlet.view.InternalResourceView]-[DEBUG] Forwarding to resource [/WEB-INF/jsp/demo.jsp] in InternalResourceView 'demo'
 * 在視圖渲染之後做這個功能
 *
 *
 *
 */

SpringMVC.xml

<!--
    配置攔截器
    聲明攔截器配置
-->
<mvc:interceptors>
    <!-- 配置單個攔截器-->
    <mvc:interceptor>
        <!-- 配置攔截器攔截的路徑-->
        <mvc:mapping path="/interceptor/*"/>
        <!-- 配置攔截器對象-->
        <bean class="cn.itcast.interceptors.MyInterceptor1"></bean>
    </mvc:interceptor>
</mvc:interceptors>

攔截器作用方法說明

在這裏插入圖片描述

攔截器鏈

<!--
    配置攔截器
    聲明攔截器配置

    攔截器鏈:多個攔截器組成的整體. 按照上下的配置順序
-->
<mvc:interceptors>
    <!-- 配置單個攔截器-->
    <mvc:interceptor>
        <!-- 配置攔截器攔截的路徑-->
        <mvc:mapping path="/interceptor/*"/>
        <!-- 配置攔截器對象-->
        <bean class="cn.itcast.interceptors.MyInterceptor1"></bean>
    </mvc:interceptor>
    <!-- 配置單個攔截器-->
    <mvc:interceptor>
        <!-- 配置攔截器攔截的路徑-->
        <mvc:mapping path="/interceptor/*"/>
        <!-- 配置攔截器對象-->
        <bean class="cn.itcast.interceptors.MyInterceptor2"></bean>
    </mvc:interceptor>
    <!-- 配置單個攔截器-->
    <mvc:interceptor>
        <!-- 配置攔截器攔截的路徑-->
        <mvc:mapping path="/interceptor/*"/>
        <!-- 配置攔截器對象-->
        <bean class="cn.itcast.interceptors.MyInterceptor3"></bean>
    </mvc:interceptor>
</mvc:interceptors>

在這裏插入圖片描述

攔截器應用實現

案例需求

  •   用戶訪問商品列表數據,判斷用戶是否登錄:
      1.如果用戶已經登錄,直接訪問商品列表數據
      2.如果用戶未登錄,先到登錄頁面執行登錄。成功登錄以後再訪問商品列表數據
    

代碼實現

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

    <!--配置前端控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--讀取配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:SpringMvc.xml</param-value>
        </init-param>
    </servlet>
    <!--配置攔截規則-->
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

SpringMVC.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:mvc="http://www.springframework.org/schema/mvc"
       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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <!--開啓註解掃描-->
    <context:component-scan base-package="cn.itcast"></context:component-scan>

    <!--springmvc的註解驅動-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!--攔截路徑是/,所以開啓加載靜態資源-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>

    <!--配置視圖解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前綴和後綴-->
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--攔截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/item/*"/>
            <bean class="cn.itcast.interceptor.LoginInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>

UserController

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/goToLogin")
    public String goToLogin() {
        return "login";
    }

    @RequestMapping("/login")
    public String login(HttpSession session) {
        //表示登錄成功
        session.setAttribute("user","user");
        return "list";
    }


}

ItemController

@Controller
@RequestMapping("/item")
public class ItemController {
    @RequestMapping("/goToItemList")
    public String goToItemList() {
        //商品信息頁面
        return "list";
    }
}

LoginInterceptor

//登錄攔截器
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //判斷登錄權限
        Object user = request.getSession().getAttribute("user");
        //判斷
        if (user != null) {
            //登錄成功
            return true;
        } else {
            //登錄失敗
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
            return false;
        }

    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章