springMVC框架學習-2

springMVC框架學習安排

第二天

1. 響應數據和結果視圖

1. 響應返回值分類

1. 響應String字符串
    @RequestMapping("testString")
    public String testString(Model model){
        User user = new User();
        user.setUname("liuzeyu");
        user.setAge(100);

        model.addAttribute("user",user);

        return "success";
    }
<%@page contentType="text/html; charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>入門成功</title>
</head>
<body>

<h2>執行成功</h2>

${requestScope.user.uname}<br>
${requestScope.user.age}

</body>
</html>

在這裏插入圖片描述

2. 響應void
<a href="user/testVoid">測試返回void</a>
    @RequestMapping("testVoid")
    public void testVoid() throws Exception {
        System.out.println("testVoid......");
    }

如果以上面的形式返回,則將報錯404
在這裏插入圖片描述
出現此問題是無返回值時,springMVC默認把請求的路徑當作轉發的路徑使用了,解決的辦法有兩個:

  1. 轉發:
    @RequestMapping("testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("testVoid......");
        request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
    }

回顧請求轉發的特點:

1. 請求只發送一次
2. 瀏覽器地址欄路徑不會改變
3. 只能轉發服務內部的資源,這裏是webapp下的資源,必須由 / 開頭
  1. 重定向:
    @RequestMapping("testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("testVoid......");
        response.sendRedirect(request.getContextPath()+"/index.jsp");
    }

在這裏插入圖片描述
回顧重定向特點:

1.瀏覽器地址欄會發送變化,如上圖
2.可以重定向到服務器外部資源
3.重定向會發送兩個請求,成功的話對應的狀態碼分別是302200
3. 響應ModelAndView
<a href="user/testModelAndView">測試返回ModelAndView</a>
@RequestMapping("testModelAndView")
public ModelAndView testModelAndView(){
    System.out.println("testModelAndView......");
    ModelAndView mv = new ModelAndView();
    User user = new User();
    user.setUname("liuzeyu");
    user.setAge(100);

    mv.addObject("user",user);
    mv.setViewName("success");  //設置轉發視圖
    return mv;
}
4. 使用forward和redirect進行頁面響應跳轉
<a href="user/testForwardAndRedirect">測試返回testForwardAndRedirect</a>
    @RequestMapping("testForwardAndRedirect")
    public String testForwardAndRedirect(){

        //return "forward:/WEB-INF/pages/success.jsp";
        return "redirect:/index.jsp";
        //return "redirect:/WEB-INF/pages/success.jsp";  //不能訪問WEB-INF下的web文件
    }
5. 爲什麼redirect重定向不能訪問WEB-INF目錄下的內容?

答案還得從WEB-INF這個目錄的作用說起

WEB-INF目錄是Java的Web應用安全目錄,客戶端是無法訪問的,只有服務器能訪問。將一些頁面放在這個目錄下可以限制外部訪問,提高安全性,如一些jsp,html頁面。

原因:
既然是安全目錄,客戶端無法訪問,那重定向當然是無法訪問到的,因爲重定向的特點是客戶端沒有直接請求服務器資源,而是二次請求服務器資源,因此是屬於直接訪問內部資源的,這是不被允許的。
然而請求轉發是請求服務器去轉發訪問資源,因此服務器是可以訪問資源的。

6. 響應json數據
  1. 加載jQuery文件(也不明白爲什麼本地會加載失敗)
    <script src="http://libs.baidu.com/jquery/1.9.1/jquery.js"></script>
  1. 添加按鈕和點擊事件
<script>

    $(function () {
       $("#bt").click(function () {
           alert("按鈕被點擊了....")
           $.ajax({
               url:"user/testAjax",
               contentType:"application/json;charset=UTF-8",
               type:"post",
               data:'{"uname":"liuzeyu","age":"66"}',
               success:function (data) {
                   //接收服務器響應的數據
               }
           });
       });
    });
</script>
<button id="bt"> 發送異步請求</button>
  1. controller層接收
    @RequestMapping("testAjax")
    public void testAjax(@RequestBody String body){
        System.out.println(body);
    }

在這裏插入圖片描述

  1. controller層響應
    @RequestMapping("testAjax")
    public @ResponseBody User testAjax(@RequestBody User user){
        user.setAge(9999);   //修改年齡爲9999
        System.out.println(user);
        return user;
    }
  1. 前端渲染
success:function (data) {
                   //接收服務器響應的數據
                   alert(data);
                   alert(data.uname);  //liuzeyu
                   alert(data.age);   //999
               }

2. 文件上傳

1. 傳統的文件上傳方式

1. 文件上傳的必要前提
A form 表單的 enctype 取值必須是:multipart/form-data
(默認值是:application/x-www-form-urlencoded)
enctype:是表單請求正文的類型
B method 屬性取值必須是 Post(get的參數瀏覽器欄裝不下)
C 提供一個文件選擇域<input type=”file” />
2. 文件上傳的原理分析
當 form 表單的 enctype 取值不是默認值後,request.getParameter()將失效。
enctype=”application/x-www-form-urlencoded”時,form 表單的正文內容是:
key=value&key=value&key=value
當 form 表單的 enctype 取值爲 Mutilpart/form-data 時,請求正文內容就變成:
每一部分都是 MIME 類型描述的正文
-----------------------------7de1a433602ac 			分界符
Content-Disposition: form-data; name="userName" 	協議頭
aaa 												協議的正文
-----------------------------7de1a433602ac
Content-Disposition: form-data; name="file";
filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt"
Content-Type: text/plain 							協議的類型(MIME 類型)
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-----------------------------7de1a433602ac--
3. 藉助第三方組件實現文件上傳

使用 Commons-fileupload 組件實現文件上傳,需要導入該組件相應的支撐 jar 包:Commons-fileupload 和
commons-io。commons-io 不屬於文件上傳組件的開發 jar 文件,但Commons-fileupload 組件從 1.1 版本開始,它
工作時需要 commons-io 包的支持。
導入座標

<!--導入傳統形式上傳文件依賴的jar包座標-->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
4. 實現步驟
  1. 編寫JSP頁面
<h2>文件上傳</h2>
<form action="user/testUpload1" method="post" enctype="multipart/form-data">
    選擇文件:<input type="file" value="文件" name="upload">
    <input type="submit" value="上傳">
</form>
  1. controller層
@RequestMapping("/user")
@Controller
public class UserController {

    @RequestMapping("testUpload1")
    public String testUpload(HttpServletRequest request) throws Exception {
        System.out.println("testUpload1...");
        //使用fileupload組件完成文件上傳
        //上傳位置
        String realPath = request.getSession().getServletContext().getRealPath("/uploads/");
        //判斷該路徑是否存在
        File file = new File(realPath);
        if(!file.exists())
        {
            //創建文件夾
            file.mkdirs();
        }
        //解析request對象,獲取上傳文件選中
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        //解析request
        List<FileItem> fileItems = upload.parseRequest(request);
        //遍歷
        for (FileItem item : fileItems) {
            //進行判斷,當前的item是否是上傳文件項
            if(item.isFormField()){
                //表示普通的表單項
            }else{
                //上傳文件項
                //獲取上傳文件名稱
                String name = item.getName();
                //把名字id設置成唯一值
                String uuid = UUID.randomUUID().toString().replace("-", "");
                name = uuid+ "_"+name;
                //完成文件上傳
                item.write(new File(realPath,name));
                //刪除臨時文件
                item.delete();
            }
        }
        return "success";
    }
}

上傳成功!
在這裏插入圖片描述

2. 使用springMVC文件上傳方式

  1. 分析
    在這裏插入圖片描述

  2. 搭建環境

<h2>文件上傳2</h2>
<form action="user/testUpload2" method="post" enctype="multipart/form-data">
    選擇文件:<input type="file" value="文件" name="upload">
    <input type="submit" value="上傳">
</form>
  @RequestMapping("testUpload2")
  public String testUpload2(HttpServletRequest request, MultipartFile upload) {
      return null;
  }
  1. 配置文件解析器
 <!--配置文件上傳解析器-->
 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
     <!--設置上傳文件的最小尺寸爲5m-->
     <property name="maxUploadSize" value="5242880"></property>
 </bean>

在這裏插入圖片描述

  1. controller層代碼
    @RequestMapping("testUpload2")
    public String testUpload2(HttpServletRequest request, MultipartFile upload) throws IOException {
        System.out.println("testUpload1...");
        //使用fileupload組件完成文件上傳
        //上傳位置
        String realPath = request.getSession().getServletContext().getRealPath("/uploads/");
        //判斷該路徑是否存在
        File file = new File(realPath);
        if(!file.exists())
        {
            //創建文件夾
            file.mkdirs();
        }

        //上傳文件項
        //獲取上傳文件名稱
        String name = upload.getOriginalFilename();
        //把名字id設置成唯一值
        String uuid = UUID.randomUUID().toString().replace("-", "");
        name = uuid+ "_"+name;
        //完成文件上傳
        upload.transferTo(new File(realPath,name));
        return "success";
    }

其中很重要的一步:解析request對象獲取文件上傳項,交給了springMVC來做。

3. springMVC跨服務器文件上傳

在這裏插入圖片描述

  1. 搭建omcat圖片服務器,要修改HTTP端口號
    在這裏插入圖片描述

  2. 實現springMVC跨服務器文件上傳

     /**
         * 跨服務器器文件上傳
         * @param
         * @param upload
         * @return
         * @throws IOException
         */
        @RequestMapping("testUpload3")
        public String testUpload3(MultipartFile upload) throws IOException {
    
            System.out.println("testUpload3 跨服務器上傳");
            String path = "http://localhost:9090/uploads/"; //圖片服務器路徑,需要手動創建一個/uplodas目錄
            //上傳文件項
            //獲取上傳文件名稱
            String name = upload.getOriginalFilename();
            //把名字id設置成唯一值
            String uuid = UUID.randomUUID().toString().replace("-", "");
            name = uuid+ "_"+name;
            //創建客戶端對象
            Client client = Client.create();
            //和圖片服務器進行連接
            WebResource resource = client.resource(path + name);
    
            //上傳文件
            resource.put(upload.getBytes());
    
            return "success";
        }
    

3. springMVC處理異常

存在的異常問題:
在這裏插入圖片描述
如果在dao層出現了異常,會拋向service層,再拋向…前端控制器。如果前端控制器再往瀏覽器拋,則用戶一般看不懂,這顯然對用於不友好,於是我們應該在前端控制處對異常進行處理,這個任務交給異常處理器,最後將處理好的異常發送給前端瀏覽器。

  1. jsp頁面
<a href="user/testException">測試異常</a>
  1. controller層代碼
@RequestMapping("/user")
@Controller
public class UserController {

    @RequestMapping("testException")
    public String testException() throws SysException {
        System.out.println("發生了異常....");

        try {
            int i = 1/0;
        } catch (Exception e) {
            e.printStackTrace();
            //拋出自定義的異常
            throw  new SysException("查詢所有用戶失敗...");
        }
        return "success";
    }
}

  1. spring配置文件
<!--配置創建springIOC容器時要掃描的包-->
    <context:component-scan base-package="com.liuzeyu"></context:component-scan>

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

    <!--配置spring開啓註解mvc的支持-->
    <mvc:annotation-driven></mvc:annotation-driven>
 <!--配置spring開啓異常處理器的支持-->
    <bean id="sysException" class="com.liuzeyu.exception.SysExceptionResolver"></bean>
  1. web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!--配置servlet-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!--servlet啓動後需要加載的spring配置文件-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!--處理post請求的中文亂碼問題-->
  <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. 自定義異常類
/**
 * Created by liuzeyu on 2020/4/29.
 * 自定義異常類
 */
public class SysException extends Exception {

    private String message;

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public SysException(String message) {
        this.message = message;
    }
}

  1. 異常處理器
/**
 * Created by liuzeyu on 2020/4/29.
 * 異常類處理器
 */
public class SysExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest,
                                         HttpServletResponse httpServletResponse,
                                         Object o, Exception e) {
        SysException sysException = null;
        if(e instanceof SysException){
            sysException = (SysException)e;
        }else{
            sysException = new SysException("系統正在維護");
        }
        //創建ModleAndView對象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",sysException.getMessage());
        mv.setViewName("error");
        return mv;
    }
}

在這裏插入圖片描述

4. springMVC攔截功能

1. 攔截器的作用

springMVC的攔截器類似於servlet的Filter,用於對處理器進行預處理和後處理,用戶可以自定義攔截器來實現特定的功能。
談到攔截器,還要向大家提一個詞——攔截器鏈(Interceptor Chain)。攔截器鏈就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或字段時,攔截器鏈中的攔截器就會按其之前定義的順序被調用。
攔截器和過濾器的區別:

  1. 過濾器是servlet的規範中的一部分,任何web工程都可以使用,包括springMVC工程
  2. 攔截器是springMVC框架自身的,只有springMVC框架能使用
  3. 過濾器在配置了 /* 後,可以對訪問的資源進行攔截
  4. 攔截器只會攔截controller裏面的方法,如果要訪問某某jsp,html,或者js資源,攔截器是不會進行攔截的,它也是AOP思想的應用。
    如果需要自定義攔截器,需要實現接口HandlerInterceptor接口

2. 攔截器的入門使用

  1. 自定義攔截器
public class MyInterceptor implements HandlerInterceptor{

/**預處理方法:
preHandle:在controller方法執行執行的攔截器方法
返回值:
	true:表示可以放行以下要執行的controller方法
	false:表示不能執行以行的controller方法
*/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor....");
        return true;
    }
}
  1. 配置攔截器
    <mvc:interceptors>
        <mvc:interceptor>
            <!--攔截路徑-->
            <mvc:mapping path="/user/*"/>
            <!--不攔截路徑-->
            <!--<mvc:exclude-mapping path=""/>-->
            <!--配置攔截器對象-->
            <bean class="com.liuzeyu.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
  1. controller方法
    @RequestMapping("testInterceptor")
   public String  testInterceptor(){
        System.out.println("測試攔截器...");
        return "success";
   }

測試結果:
在這裏插入圖片描述

3. 攔截器的其它兩個方法

  1. postHandle
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor....preHandle");
        return true;
    }
    /**
     * 方法執行時機:controller執行之後,success.jsp執行之前
     * @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("MyInterceptor....postHandle");
        request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

結果:
在這裏插入圖片描述
error.jsp在這裏插入圖片描述

:攔截器處理轉發後不會再去跳轉controller裏面的任何頁面跳轉。

  1. afterCompletion
/**
 * Created by liuzeyu on 2020/4/29.
 */
public class MyInterceptor implements HandlerInterceptor{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor....preHandle");
        return true;
    }

    /**
     * controller執行之後,success.jsp執行之前
     * @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("MyInterceptor....postHandle");
        request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }


    /**
     * 最後執行方法:通常用於是否資源,在success.jsp執行後才執行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor....afterCompletion");
    }
}

測試結果:
在這裏插入圖片描述

4. 攔截鏈執行順序

  1. 配置攔截器2
/**
 * Created by liuzeyu on 2020/4/29.
 */
public class MyInterceptor2 implements HandlerInterceptor{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor22222....preHandle");
        return true;
    }

    /**
     * controller執行之後,success.jsp執行之前
     * @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("MyInterceptor2222....postHandle");
        //request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }


    /**
     * 最後執行方法:通常用於是否資源,在success.jsp執行後才執行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor2222....afterCompletion");
    }
}

  1. 配置文件
 <mvc:interceptors>
        <mvc:interceptor>
            <!--攔截路徑-->
            <mvc:mapping path="/user/*"/>
            <!--不攔截路徑-->
            <!--<mvc:exclude-mapping path=""/>-->
            <!--配置攔截器對象-->
            <bean class="com.liuzeyu.interceptor.MyInterceptor"/>
        </mvc:interceptor>
        <!--再配置一個攔截器-->
        <mvc:interceptor>
            <!--攔截路徑-->
            <mvc:mapping path="/**/"/>
            <!--不攔截路徑-->
            <!--<mvc:exclude-mapping path=""/>-->
            <!--配置攔截器對象-->
            <bean class="com.liuzeyu.interceptor.MyInterceptor2"/>
        </mvc:interceptor>
    </mvc:interceptors>

  1. 執行順序分析
    在這裏插入圖片描述
    結果:
    在這裏插入圖片描述

可見執行順序如上,符合攔截鏈的執行流程。

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