springmvc_day02_@ModelAttribute(所有方法前執行)_SessionAttribute(使用session)_方法各種返回值_json_文件上傳_統一異常處理

一、今日內容

1、ModelAttribute和SessionAttribute註解的使用
2、RestFul風格
3、控制器方法的返回值
4、交互JSON數據
5、springMVC實現文件上傳
6、springMVC異常處理

二、ModelAttribute和SessionAttribute註解的使用

ModelAttribute

a. @ModelAttribute註解標記在方法上
	特點:當執行控制器中任何一個方法時,都會先執行@ModelAttribute標記的方法
	缺點:慎重使用,因爲執行控制器中任何一個方法時,都會先執行@ModelAttribute標記的方法, 效率太低
	適用於專門更新或查詢的控制器(方法比較少 且單一):
		UserUpdateController
		UserQueryController
b. 應用舉例:提供空缺參數值的默認值  (寫法2:map寫法 略)
	/**
     * 模擬根據id查詢用戶
     */
    @ModelAttribute
    public User findById(Integer id){
        User user = new User();
        user.setUsername("王五");
        user.setSex("女");
        return user;//會彌補下面user對象中殘缺的值 使得其不至於被清空
    }

    /**
     * 更新時的sql語句一般這麼寫   update user set username=?,sex=? where id=? 萬一性別無需修改而沒有傳遞值 就麻煩了 此時用到@ModelAttribute
     * @param user
     * @return
     */
    @RequestMapping(value = "/testUpdate",method = RequestMethod.POST)
    public String testUpdate(User user){
        System.out.println(user);//先執行的@ModelAttribute:findById 返回一個user彌補此user的空缺屬性
        System.out.println("更新");
        return "show";
    }

SessionAttribute

c. 註解@SessionAttributes:在session範圍內存儲對象
	1) @SessionAttributes({"username","password"}) 在類上標記該註解
	   表示在session範圍內可以存儲這兩個變量名(username和password)
	2) /**
	* 把用戶名和密碼存入到Session範圍內
	*/
	@RequestMapping("/testPut")
	public void testPut(Model model){
		model.addAttribute("username","zhangsan");
		model.addAttribute("password","123456");
	}
	3) /**
	* 獲取session範圍內的對象
	*/
	@RequestMapping("/testGet")
	public void testGet(ModelMap modelMap){
		Object username = modelMap.get("username");
		System.out.println(username);
		Object password = modelMap.get("password");
		System.out.println(password);
	} 
	4) 
	/**
	* 清空session
	* @param sessionStatus
	*/
	@RequestMapping("/testClear")
		public void testClear(SessionStatus sessionStatus){
		sessionStatus.setComplete();
	}

Demo

pom.xml

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>
    <!--lombok-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.4</version>
    </dependency>
  </dependencies>

spring-mvc.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.ahpu"></context:component-scan>
    <!--視圖解析器  內部資源視圖解析 簡化return-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    <!--引入註解驅動-->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

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>
  <!--編碼過濾器 處理post請求亂碼   get請求亂碼tomcat內配-->
  <filter>
    <filter-name>CharacterEncoding</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>CharacterEncoding</filter-name>
    <url-pattern>/*</url-pattern> <!--只攔截所有請求 不攔截靜態資源-->
  </filter-mapping>


  <!--前端控制器-->
  <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:spring-mvc.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern><!--攔截所有資源 請求+靜態資源-->
  </servlet-mapping>
</web-app>

User.java

@Data
public class User {
    private Integer id;
    private String username;
    private String sex;
}

UserController.java

package cn.ahpu.controller;

import cn.ahpu.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

/**
 * @author 寒面銀槍
 * @create 2020-04-26 17:41
 */
@Controller
@RequestMapping("/user")
@SessionAttributes({"username","password"})
public class UserController {

    //將用戶名密碼存到session內
    @RequestMapping("/testPut")
    public void testPut(Model model){//往session內存 框架指定的參數 model
        model.addAttribute("username","張三");
        model.addAttribute("password","123");
    }
    //獲取session範圍內的對象
    @RequestMapping("/testGet")
    public void testGet(ModelMap modelMap){//從session中取 框架指定參數 modelMap (存的時候也可以用modelmap)
        Object username = modelMap.get("username");
        System.out.println(username);
        Object password = modelMap.get("password");
        System.out.println(password);
    }

    //清空session
    @RequestMapping("/testClear")
    public void testClear(SessionStatus sessionStatus){//設置一下會話狀態即可清除session值
        sessionStatus.setComplete();
    }


    @ModelAttribute
    public void print(){
        System.out.println("執行了");
    }

    @RequestMapping("/testModelAttribute")
    public String testModelAttribute(){
        System.out.println("test方法執行了...");
        return "show";
    }

    @RequestMapping("/testModelAttribute2")
    public String testModelAttribute2(){
        System.out.println("test2方法執行了...");
        return "show";
    }

    /**
     * 模擬根據id查詢用戶
     */
    @ModelAttribute
    public User findById(Integer id){
        User user = new User();
        user.setUsername("王五");
        user.setSex("女");
        return user;//會彌補下面user對象中殘缺的值 使得其不至於被清空
    }

    /**
     * 更新時的sql語句一般這麼寫   update user set username=?,sex=? where id=? 萬一性別無需修改而沒有傳遞值 就麻煩了 此時用到@ModelAttribute
     * @param user
     * @return
     */
    @RequestMapping(value = "/testUpdate",method = RequestMethod.POST)
    public String testUpdate(User user){
        System.out.println(user);//先執行的@ModelAttribute:findById 返回一個user彌補此user的空缺屬性
        System.out.println("更新");
        return "show";
    }
}

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2020/4/26
  Time: 17:45
  To change this template use File | Settings | File Templates.
--%>
<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>4</title>
</head>
<body>
    <a href="${pageContext.request.contextPath}/user/testModelAttribute">testModelAttribute</a><br>
    <a href="${pageContext.request.contextPath}/user/testModelAttribute2">testModelAttribute2</a><br>
    <hr>
    <form action="${pageContext.request.contextPath}/user/testUpdate" method="post">
        <input type="hidden" name="id" value="1">
        姓名:<input type="text" name="username"> <br>
        <%--性別:<input type="text" name="sex"><br>--%>
        <input type="submit" value="提交">
    </form>
    <hr>
    <a href="${pageContext.request.contextPath}/user/testPut">testPut Session</a><br>
    <a href="${pageContext.request.contextPath}/user/testGet">testGet Session</a><br>
    <a href="${pageContext.request.contextPath}/user/testClear">testClear Session</a><br>
</body>
</html>

三、RestFul風格(目前並不常用)

根據請求方式不同,最終執行的方法不同

a. rest 是一種編程風格
b. 滿足了rest風格的網站就是restful風格
c. 只是一種規範,不是規則   
d. eg:根據id獲取一個用戶: /user/findById?id=1 restful風格:/user/operate/1 使用get方式提交
	  根據id刪除一個用戶:/user/delById?id=1 restful風格:/user/operate/1 使用delete方式提交
	  更新一個用戶:/user/update?id=1&username=zzz restful風格:/user/operate/1 使用put方式提
	  添加一個用戶:/user/save?id=1&username=zzz restful風格:/user/operate 使用post方式提交
	根據請求方式不同,最終執行的方法不同
e. 根據id獲取
頁面
	http://localhost:8080/user/operate/1
方法
	/**
	* 根據id查詢
	* @param id
	* @return
	*/
	@RequestMapping(value = "/operate/{id}",method = RequestMethod.GET)
		public String findById(@PathVariable("id") Integer id){
		System.out.println("findById:"+id);
		return "show";
	}
f. 添加一個用戶
頁面
	<%--請求保存用戶--%>
	<form action="${pageContext.request.contextPath}/user/operate/1" method="post">
	<input type="submit" value="提交">
	</form>
方法
	/**
	* 保存用戶
	* @param id
	* @return
	*/
	@RequestMapping(value = "/operate/{id}" , method = RequestMethod.POST)
		public String save(@PathVariable("id") Integer id){
		System.out.println("save:" + id);
		return "show";
	}
h. 更新用戶
頁面:
	<%--請求更新用戶--%>
	<form action="${pageContext.request.contextPath}/user/operate/1" method="post">
	<%--要使用put,delete提交方式
	1) 在web.xml開啓put和delete提交方式
	2) 表單的提交方式必須post
	3) 表單中必須設置一個隱藏域 name=_method value=PUT
	4) 請求的方法返回值必須以流的形式返回,在方法上標記註解:@ResponseBody
	流的形式返回: response.getWriter().print()
	--%>
	<input type="hidden" name="_method" value="PUT">
	<input type="submit" value="更新">
	</form>
方法
	/**
	* 更新用戶
	* @param id
	* @return
	*/
	@RequestMapping(value = "/operate/{id}" , method = RequestMethod.PUT)
	@ResponseBody
	public String update(@PathVariable("id") Integer id){
		System.out.println("update:" + id);
		return "show";
	}
i. 刪除用戶
頁面
	<%--請求刪除用戶--%>
	<form action="${pageContext.request.contextPath}/user/operate/1" method="post">
		<input type="hidden" name="_method" value="DELETE">
		<input type="submit" value="刪除">
	</form>
方法
	/**
	* 刪除用戶
	* @param id
	* @return
	*/
	@RequestMapping(value = "/operate/{id}" , method = RequestMethod.DELETE)
	@ResponseBody
	public String delById(@PathVariable("id") Integer id){
		System.out.println("delById:" + id);
		return "show";
	}
j, web.xml
	<!--開啓另外兩種提交方式:put, delete-->
	<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>

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2020/4/26
  Time: 17:45
  To change this template use File | Settings | File Templates.
--%>
<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>4</title>
</head>
<body>
    請求保存用戶(post):
    <form action="${pageContext.request.contextPath}/user/save" method="post">
        <input type="text" name="id" value="1">
        <input type="submit" value="提交">
    </form>
    findById(get):
    <a href="${pageContext.request.contextPath}/user/findById?id=1">findById(get):</a>
    <hr>
    resful風格提交(4個請求路徑完全一樣,就是提交方式不同導致執行不同方法):<br>
    請求保存用戶(post):
    <form action="${pageContext.request.contextPath}/user/operate/1" method="post">
        <input type="submit" value="保存">
    </form>
    findById(get):
    <a href="${pageContext.request.contextPath}/user/operate/1">findById(get):</a>
    <%--1)先在web.xml中開啓put和delete提交方式
        2)表單提交方法必須是post
        3)表單中必須設置一個隱藏域: name=_method value=PUT
        4)請求的方法返回值必須以流的形式返回,即在方法上標記註解:@ResponseBody
    --%>
    請求更新用戶(put) 先在web.xml中開啓put和delete提交方式:
    <form action="${pageContext.request.contextPath}/user/operate/1" method="post">
        <input type="hidden" name="_method" value="PUT">
        <input type="submit" value="更新">
    </form>
    請求刪除用戶(delete) 先在web.xml中開啓put和delete提交方式:
    <form action="${pageContext.request.contextPath}/user/operate/1" method="post">
        <input type="hidden" name="_method" value="DELETE">
        <input type="submit" value="刪除">
    </form>

</body>
</html>

web.xml

在這裏插入圖片描述

UserController.java

@Controller
@RequestMapping("/user")
@SessionAttributes({"username","password"})
public class UserController {

    //普通寫法
    /*@RequestMapping(value = "/findById",method = RequestMethod.GET)
    public String findById(Integer id){
        System.out.println("findById:"+id);
        return "show";
    }
    @RequestMapping(value = "/save",method = RequestMethod.POST)
    public String save(Integer id){
        System.out.println("save:"+id);
        return "show";
    }*/


    @RequestMapping(value = "/operate/{idx}",method = RequestMethod.GET)
    public String findById(@PathVariable("idx") Integer id){
        System.out.println("findById:"+id);
        return "show";
    }

    @RequestMapping(value = "/operate/{id}",method = RequestMethod.POST)
    public String save(@PathVariable("id") Integer id){
        System.out.println("save:"+id);
        return "show";
    }

    //web.xml中配置新的filter
    //更新用戶 put
    @RequestMapping(value = "/operate/{id}",method = RequestMethod.PUT)
    @ResponseBody
    public String update(@PathVariable("id") Integer id){
        System.out.println("update:"+id);
        return "show";
    }


    //刪除用戶 delete
    @RequestMapping(value = "/operate/{id}",method = RequestMethod.DELETE)
    @ResponseBody
    public String del(@PathVariable("id") Integer id){
        System.out.println("del:"+id);
        return "show";
    }

}

四、控制器方法的返回值

1、返回值爲void類型

a. 方法一:
    @RequestMapping("/testVoid")
    public void testVoid(){
        System.out.println("測試沒有返回值");
        //沒有指定返回值頁面,會自動截取請求路徑,進入視圖解析器(xml內配置的),拼接完整路徑
        //1.對應路徑下創建對應jsp   /WEB-INF/user/testVoid.jsp
    }
 
b. 方法二:response重定向
	@RequestMapping("/testVoid2")
    public void testVoid2(HttpServletResponse response){
        System.out.println("測試沒有返回值");
        //手動重定向
        try {
            //重定向不能進入WEB-INF   轉發可以進入
            response.sendRedirect("/show2.jsp");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

c. 方法三:servlet轉發
	@RequestMapping("/testVoid3")
    public void testVoid3(HttpServletResponse response, HttpServletRequest request){
        System.out.println("測試沒有返回值3");
        //手動轉發
        try {
            request.getRequestDispatcher("/WEB-INF/show.jsp").forward(request,response);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2、返回值爲String類型(常用)

a. 默認的情況:(return 一個路徑)轉發請求,返回值直接進入視圖解析器,拼接前綴和後綴,完整的路徑
	//方法返回值爲string
    @RequestMapping("/testString")
    public String testString(){
        System.out.println("返回值string");
        return "show";
    }
b. 請求重定向
	/**
     * 可以重定向到一個controller
     *  eg;save----redirect:findAll
     *
     * 方法返回值爲string
     *     返回值直接進入視圖解析器 拼接前後綴 形成完整路徑
     *     redirect:添加了redirect後,則是重定向,則不會進入視圖解析器,需要配置完整路徑
     */
    @RequestMapping("/testString2")
    public String testString2(){
        System.out.println("返回值string 重定向");
        return "redirect:/show2.jsp";
    }
c. 請求轉發 (不進入視圖解析器拼接)
	 /**
     * 不使用視圖解析器轉發(不拼接  直接轉發到寫的路徑)
     *  forward:轉發 不會進入視圖解析器,需要配置完整的路徑
     * @return
     */
    @RequestMapping("/testString3")
    public String testString3(){
        System.out.println("返回值string 不使用視圖解析器轉發");
        return "forward:/show2.jsp";
    }

3、返回值爲ModelAndView類型(常用 ★ 超級好用)

a. ModelAndView: Model 模型:封裝數據 view 視圖: 指定頁面 ---> 模型和視圖
b. eg:
	//返回值類型爲ModelAndView:包含數據和視圖頁面  ★太牛
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        //準備數據  數據庫查詢
        List<User> userList=new ArrayList<User>();
        User user1 = new User(); user1.setSex("男");user1.setUsername("張三");user1.setId(1);
        User user2 = new User(); user2.setSex("女");user2.setUsername("李四");user2.setId(2);
        userList.add(user1);userList.add(user2);

        ModelAndView modelAndView = new ModelAndView();
        //添加數據
        modelAndView.addObject("userList",userList);
        //指定頁面
        modelAndView.setViewName("show");//視圖解析器仍然起作用
        return modelAndView;
    }

在這裏插入圖片描述

五、交互JSON數據

注意: idea映入壓縮版的min.js時寫$()會報錯(不影響運行) 引入開發版的js就行了
springmvc的前端控制器將所有靜態資源也都攔截了,一定在spring-mvc.xml中放行
<mvc:resources mapping="/js/*" location="/js/"></mvc:resources>
pom.xml裏引入3個json的jar包

1. 引入依賴 pom.xml


	 <!--引入json依賴 3個jar-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
        <version>2.9.0</version>
    </dependency>

2. 前端jsp

<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>TestJson</title>
    <%--web.xml裏前端控制器攔截所有資源 js靜態資源也攔截了 一定要在覈心xml內放行--%>
    <script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script>
</head>
<script type="text/javascript">
    //window.οnlοad=function (ev) { alert("hello") }
    /*$(function () {
        alert("jquery");
        $("#btn").click(
            function () {
                alert("btn click")
            }
        );
    });*/

    function excute() {
        alert("提交");
        $.ajax({
            url:"${pageContext.request.contextPath}/user/testRequestJson2",
            data:{"username":"張三","age":20},
            success:function (data) {
                alert(data);
            },
            dataType:"json",
            type:"post"
        });
    }

</script>
<body>
    <input id="btn" type="button" value="提交" onclick="excute()">
</body>
</html>

測試responseBody時改成

    function excute() {
        alert("提交");
        $.ajax({
            <%--url:"${pageContext.request.contextPath}/user/testRequestJson2",--%>
            url:"${pageContext.request.contextPath}/user/testResponseBody",
            /*data:{"username":"zangsan","age":20},*/
            success:function (data) {
                /*alert(data[0].username);
                alert(data[1].username);*/
                //直接遍歷 這個方法好記 而且不論data類型如何都可遍歷
                $.each(data,function () {
                    alert(this.username+"|"+this.sex+"|"+this.id);
                })
            },
            dataType:"json",
            type:"post"
        });
    }

3、 @ReqeustBody註解(爛註解 直接參數解析最好)

   /**
     * 自動解析前端json格式數據 ★★ ★★ 與@ReqeustBody註解無關   
     */
    @RequestMapping("/testRequestJson")
    public void testRequestJson(String username,Integer age){//前端json格式也可以直接幫你封裝到參數裏
        System.out.println(username);
        System.out.println(age);
    }

    //所有參數轉換爲一個字符串
    @RequestMapping("/testRequestJson2")
    public void testRequestJson2(@RequestBody String body){//
        System.out.println(body);
        //輸出:username=zangsan&age=20
    }

4、ResponseBody註解 (★ 一個註解解決json格式轉換問題)

   /**
     * @ResponseBody註解標記的方法,數據會以流的形式返回(字符串流也就是json格式數據)
     *      ★ 多好 一個註解就解決了返回json格式轉換的問題 牛★★
     * @return
     */
    @RequestMapping("/testResponseBody")
    @ResponseBody
    public List<User> testResponseBody(){
        //準備數據  數據庫查詢
        List<User> userList=new ArrayList<User>();
        User user1 = new User(); user1.setSex("男");user1.setUsername("張三");user1.setId(1);
        User user2 = new User(); user2.setSex("女");user2.setUsername("李四");user2.setId(2);
        userList.add(user1);userList.add(user2);
        return userList;//會自動轉json
    }

六、SpringMVC實現文件上傳

1、文件上傳

a、引入依賴

引入fileUpload會自動依賴commons-io
<!--文件上傳依賴-->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>

b、spring-mvc.xml 配置文件

建議複製 無需記憶

<!-- 配置文件上傳解析器 -->
    <!-- id的值是固定的 直接複製 不要記憶-->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 設置上傳文件的最大尺寸爲5MB -->
        <property name="maxUploadSize">
            <value>5242880</value>
        </property>
    </bean>

c、頁面配置

 	<%--上傳文件的表單前提
        1) 提交方式必須post (get只能提交少量數據 post提交大量數據)
        2) 表單類型必須:enctype="multipart/form-data"   多功能表單數據
        3) 必須有一個type=file的表單元素
    --%>
    <form action="" method="post" enctype="multipart/form-data">
        <input type="text" name="username"><br>
        <input type="file" name="upload"><br>
        <input type="submit" value="上傳">
    </form>

d、controller代碼

	@RequestMapping("/upload")
    public String upload(String username, MultipartFile upload,HttpServletRequest request){
        /*System.out.println(username);
        System.out.println(upload);*/

        //1.目標路徑
        //1.1 獲取項目運行的真實路徑(創建子目錄upload)
        String realPath = request.getSession().getServletContext().getRealPath("/upload");
        System.out.println("真實路徑:"+realPath);
        //1.2 判斷路徑是否存在  不存在創建
        File realFile=new File(realPath);
        if(!realFile.exists()){
            realFile.mkdirs();
        }

        //2.獲取唯一的文件名稱(包含拓展名)
        String uuidName= UUID.randomUUID().toString().replace("-","");
        //2.1獲取真實文件名
        String originalFilename = upload.getOriginalFilename();
        System.out.println(originalFilename);
        //2.2獲取拓展名
        int n = originalFilename.lastIndexOf(".");//找到最後一個點
        String extendName = originalFilename.substring(n);//從最後一個.開始往後截取即可 包括.
        System.out.println(extendName);//.txt  .jpg
        //2.3生成唯一文件名
        String fileName=uuidName+extendName;
        System.out.println("唯一文件名:"+fileName);

        //3.文件上傳 非常簡單
        //transferTo:執行文件上傳
        //參數file:目標文件 路徑+文件名
        try {
            upload.transferTo(new File(realFile,fileName));//路徑和文件名
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "show";
    }

在這裏插入圖片描述

2、跨服上傳

a、引入依賴

<!--引入jersey服務器的包 跨服上傳-->
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-core</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
      <version>1.18.1</version>
    </dependency>

b、修改tomcat配置

1. tomcat默認不能跨服上傳的
2. tomcat/conf/web.xml
	<init-param>
		<param-name>debug</param-name>
		<param-value>0</param-value>
	</init-param>
	<!--需要添加的-->
	<init-param>
		<param-name>readonly</param-name>
		<param-value>false</param-value>
	</init-param>

在這裏插入圖片描述

c、配置圖片服務器

1. 創建一個web項目
2. 配置一個tomcat,與原來tomcat端口號不一致
3. 在新項目的webapp目錄下創建一個upload目錄,空的文件夾不會編譯(否則以上傳就報錯),需要在upload目錄添加(任意)一個文件

在這裏插入圖片描述
在這裏插入圖片描述

d、修改controller代碼

//跨服務器上傳
    @RequestMapping("/uploadServer")
    public String uploadServer(String username, MultipartFile upload,HttpServletRequest request){

        //1.配置圖片服務器路徑
        String serverPath="http://localhost:9090/img_server/upload/";

        //2.獲取唯一的文件名稱(包含拓展名)
        String uuidName= UUID.randomUUID().toString().replace("-","");
        //2.1獲取真實文件名
        String originalFilename = upload.getOriginalFilename();
        //2.2獲取拓展名
        int n = originalFilename.lastIndexOf(".");//找到最後一個點
        String extendName = originalFilename.substring(n);//從最後一個.開始往後截取即可 包括.
        //2.3生成唯一文件名
        String fileName=uuidName+extendName;

        //3.獲取jersey服務器客戶端
        Client client=Client.create();
        //配置上傳路徑的資源對象
        WebResource resource = client.resource(serverPath + fileName);

        //4.上傳
        //參數: 資源的類型   文件的字節內容
        try {//String.class:字符串路徑
            resource.put(String.class, upload.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("上傳完畢!");

        return "show";
    }

七、SpringMVC的統一異常處理

1. 自定義異常類 (也可以沒有)

CustomerException.java

@Data
public class CustomerException extends Exception {
    private String message;

    public CustomerException(String message) {
        super(message);
        this.message = message;
    }
}

2. 定義異常的統一處理對象-實現接口HandlerExceptionResolver

(該類只要創建了(存在於容器中) 就會生效 不需要其他多餘的配置)
MyExceptionResolver.java

//創建該類對象就生效了  一旦發生異常就自動轉到這來了
@Component
public class MyExceptionResolver implements HandlerExceptionResolver {
    /**
     * 解析異常
     * @param request
     * @param response
     * @param handler
     * @param e 別處傳過來的異常對象
     * @return
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        //添加數據
        if(e instanceof CustomerException){//instanceof 實例類型判斷運算符
            //若是自定義異常類型
            CustomerException customerException= (CustomerException) e;
            modelAndView.addObject("message",customerException.getMessage());
        }else{
            modelAndView.addObject("message","系統錯誤,請聯繫管理員!");
        }

        //指定跳轉頁面
        modelAndView.setViewName("error");//視圖解析器起作用
        return modelAndView;
    }
}

3. 錯誤頁面

<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    ${message}
</body>
</html>

4、異常測試controller

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

    @RequestMapping("/print")
    public String print(){
        System.out.println(1/0);
        return "show";
    }
}

在這裏插入圖片描述
在這裏插入圖片描述

八、小結

1. @ModelAttribute ,@SessionAttribute
2. restful
3. 控制器方法的返回值
   void : 
   String :
   ModelAndView: 視圖和模型
4. json數據的交互
   @RequestBody: 
   @ResponseBody:
5. 文件上傳: upload.trsansferTo(new File("path"))
6. 跨服上傳文件:
7. 統一處理異常:


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