搭建

<?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">

	<!--1.spring的中央控制器DispatcherServlet-->
	<servlet>
		<servlet-name>DispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!--加载spring的配置文件-->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>
		<!--设置servlet在服务器启动时创建-->
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<!--
		servlet的路径:/  拦截所有请求,但是不包含jsp页面,依然拦截静态资源【推荐】
		servlet的路径:/* 拦截所有请求,并且包含jsp
		-->
		<servlet-name>DispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<!--2.处理乱码的过滤器-->
	<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>
servlet的路径:/  拦截所有请求,但是不包含jsp页面,依然拦截静态资源【推荐】
 servlet的路径:/* 拦截所有请求,并且包含jsp

原因

自己配置的中心控制器覆盖了默认的DefultServlet
Default是Tomcat默认提供的servlet,用来专门处理静态资源

处理方案

方案一:
配置servlet映射

<!--将静态资源的请求还是交给DefaultServlet去处理-->
	<servlet-mapping>
		<servlet-name>default</servlet-name>
		<url-pattern>*.html</url-pattern>
		<url-pattern>*.htm</url-pattern>
		<url-pattern>*.js</url-pattern>
		<url-pattern>*.css</url-pattern>
		<url-pattern>*.jpg</url-pattern>
		<url-pattern>*.png</url-pattern>
	</servlet-mapping>
方案二:
 方式1:mapping 映射路径,就是访问路径。location 访问路径对应的真实路径。-->
<mvc:resources mapping="/pages/**" location="/pages/"/>                                                                                             <mvc:resources mapping="/index.html" location="/index.html"/>

方式二:推荐写法
<mvc:default-servlet-handler></mvc:default-servlet-handler>

Model与ModelMap

作用:可以往请求域中
springmvc优化请求域的三种方式
方式一:Model 方法addAttribute,是一个接口

方式二:modelMap addAttribute与model一模一样,是一个类

方式三:modelAndView 必须在控制器内自己手动实例化对象,既可以先请求域中写入数据,又可以设置返回的视图名字,
方法setViewName设置视图名字

package com.itheima.controller.a_model;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * @author 黑马程序员
 */
@Controller
@RequestMapping("/model")
public class ModelController {

    @RequestMapping("/request")
    public String request(HttpServletRequest request, HttpSession session){

        //使用servlet的api进行操作请求域数据
        request.setAttribute("request_data","播仔");
        //注意:如果操作会话域session、全局域servletContext都是一样的操作
        //session.getServletContext()
        return "success";
    }

    /*
    * springMVC优化请求域的操作方式
    *   1.Model  【用的较多】
    *   2.ModelMap
    *   3.ModelAndView
    *
    * 注意:Model与ModelMap操作请求域功能一样
    *       model是一个接口,ModelMap是一个类
    *
    *      ModelAndView 必须在控制器方法内自己手动实例对象,不像上面2个可以直接方法参数定义
    * */
    @RequestMapping("/model")
    public String model2(Model model){
        //使用model往请求域中写入数据
        model.addAttribute("model_data","播妞");
        return "success";
    }
    @RequestMapping("/modelmap")
    public String modelMap(ModelMap modelMap){
        //使用ModelMap往请求域中写入数据
        modelMap.addAttribute("modelmap_data","狗娃");
        return "success";
    }

    @RequestMapping("/modelAndView")
    public ModelAndView modelAndView(ModelMap modelMap){
        //实例ModelAndView: 既可以向请求域中写入数据,又可以设置返回的视图名字
        ModelAndView modelAndView = new ModelAndView();
        //设置视图名字
        modelAndView.setViewName("success");
        //写入请求域数据
        modelAndView.addObject("model_and_view","黑马");
        return modelAndView;
    }
}

交互json数据

先添加json相关的依赖包
<!--添加jackson支持包: springMVC框架操作json数据时调用的技术-->
<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>

jsp异步请求例子
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>发送异步请求</title>
</head>
<body>
<input type="button" value="发送异步请求" id="b1">
<script src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
<script>

    //目标:前端发送异步请求,传递json字符串请求数据给后端
    //1.给按钮注册点击事件
    $("#b1").click(function () {

        //2.发送异步请求
        //2.1 准备发送的json数据
        //json字符串格式:'{"key1":value1,"key2":value2,...}'  注意里面的key必须有双引号括起来
        //第一种使用json字符串:自定义字符串格式数据
        //let jsonStr = '{"id":100,"name":"播仔"}';
        //第二种使用json字符串:将json对象转换为json字符串,推荐方式
        //  语法:JSON.stringify(json对象) 返回值是json字符串
        let jsonObj = {name:"播仔",id:100};
        let jsonStr = JSON.stringify(jsonObj);

        //2.2 发送异步请求,传递json字符串
        $.ajax({
            url:"${pageContext.request.contextPath}/json/jsonData",
            //data: {name:"播仔",id:100},  //看着传递的json数据,起始本质是通过请求体传递原生格式:"key1=value1&key2=value2..."
            data: jsonStr,  //看着传递的json数据,起始本质是通过请求体传递原生格式:"key1=value1&key2=value2..."
            contentType:"application/json;charset=utf-8", //设置请求传递json字符串格式数据与码表,如果不设置,传递的数据依然是原生key=value的格式
            method:"post",
            dataType:"json",  //设置返回的数据类型为json字符串
            success:function (user) {
                //user是返回的json对象数据
                alert("name:"+user.name+",id="+user.id);
            }
        })
    });
</script>
</body>
</html>

控制器
package com.itheima.controller.c_json;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author 
 */
@Controller
@RequestMapping("/json")
public class JsonController {

    @RequestMapping(value = "/jsonData",produces ="application/json;charset=utf-8" )
    @ResponseBody  //作用:将控制器方法返回值转换为json字符串给前端
    public User jsonData(@RequestBody User user){
       //@RequestBody 会将请求体中的json字符串转换为java对象,
        // 注意:1.如果json中含有中文,需要设置@RequestMapping中的produces接收数据类型与码表
        //       2.前端传递过来的json字符串中的属性名 与 封装JAVA对象中的属性名一样才可以封装
        System.out.println("进入ajaxData方法接收到的用户数据:"+user);

        //修改user对象的数据
        user.setId(200);
        user.setName("播妞");

        return user;
    }
}

总结:在发送请求中需要设置传递json字符串格式和码表,如果不设置,数据将会是原生格式,
produces ="application/json;charset=utf-8" 可以处理乱码问题
RequestBody:将请求体中的json数据转换为java对象,在对象前面定义
responseBody:将控制器的返回值转化为json数据给前端页面展示S

控制器方法返回值

1. 返回String
2. 字符串 
   1. 返回页面名称字符串
    eg:return "success" 经过视图解析器拼接
    返回转发字符串
    return "forward:完整路径
    转发只能跳转到服务器当前内部资源
    
   返回重定向字符串
  语法:"redirect:完整重定向路径"
  其中springmvc回自动补全项目路径
  可以跳转到外部资源,比如http:/www.baidu.com
  里面中的第一个"/",代表跳转但前项目类的资源地址

3. 返回void
//返回void
    @RequestMapping("/void")
    public void returnString(HttpServletRequest request, HttpServletResponse response){

        try {
            //使用原生servlet的api的应用场景
            //1.转发
            //request.getRequestDispatcher("/index.jsp").forward(request,response);
            //2.重定向
            //response.sendRedirect(request.getContextPath()+"/index.jsp");
            //3.附件下载
            //设置响应头:通知浏览器进行附件下载
            response.setHeader("content-disposition","attachment;filename=6.jpg");
            //获取当前项目“/down/6.jpg”的输入流
            InputStream inputStream = request.getServletContext().getResourceAsStream("/down/6.jpg");
            //使用commons-io工具类将收入流通过response的输出流输出给浏览器
            IOUtils.copy(inputStream,response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }



4. 返回ModelAndView对象
5. 返回任意对象。(配置@ResponseBody注解)

RestFul风格的URL

RestFul就是一个URl地址,是一种地址编风格
特点:更简洁,更有层次感,借助了不同的http请求(get/post/put/delete)
的方法来区分不同业务操作,更易于浏览器实现缓存
浏览器的同步请求:可以提交Post和Get,默认为Get,无法提交PUT与de'lete请求
js异步请求: 可以提交get/post/put/delete
1. 如果要用restful风格的url地址,可以直接用,不用做任何操作或配置等。
2. 配置HiddenHttpMethodFilter与restful没有关系, 主要是为了让页面支持put、delete请求而已。
3. 总结两点问题:
   1. 使用HiddenHttpMethodFilter过滤请求,主要是为了让页面支持put、delete请求
   2. put、delete请求, 只支持返回json类型的数据

一个地址可以表示多次请求(直接在方法上定义 “请求类型”,另外可以在括号里设置value的值) 而方法的形参需要用@PathVariable来表明接收


实现文件上传

用到了Apache的文件上传组件实现
实现
-------------------------------------------------------------------------------
1.导入上传依赖
<!--添加Apache文件上传支持包-->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>
---------------------------------------------------------------------------------
2. jsp页面
 <%--
  文件上传客户端要求三要素
    1.必须使用form表单的post提交请求
    2.form表单属性enctype的值必须为multipart/form-data"
    3.form表单里面必须有文件域表单项元素,就是submit
  --%>
  表单实例
   <form action="${pageContext.request.contextPath}/upload/uploadFile" method="post" enctype="multipart/form-data">
      <input type="file" name="imgFile">
      <input type="submit" value="文件上传">
  </form>
--------------------------------------------------------------------------------------
3.编写控制类
@Controller
@RequestMapping("/upload")
public class UploadController {

    /*
    * 目标:将客户端上传的文件上传到服务器端项目内“upload/2020-10-26/xxxxx.jpg”
    *
    * 服务器端SpringMVC使用apache的File-upload组件实现文件上传
    *    1.控制器的方法参数 MultipartFile类型,参数名必须为表单文件域元素的name属性值
    *        eg:<input type="file" name="imgFile">, 所以参数:MultipartFile imgFile
    *
    *    MultipartFile的作用:可以获取上传文件的名称,文件的输入流
    * */
    @RequestMapping("/uploadFile")
    public String uploadFile(MultipartFile imgFile, HttpServletRequest request){

        try {
            //1.定义上传文件的唯一名字
            //1.1 获取客户端文件的扩展名(后缀名)
            String clientFileName = imgFile.getOriginalFilename();  //获取客户端上传文件名
            String fileExtName = clientFileName.substring(clientFileName.lastIndexOf("."));

            //1.2 生成一个唯一值(UUID)
            UUID uuid = UUID.randomUUID();

            //1.3 拼接文件名
            String fileName = uuid + fileExtName;

            //2.判断上传目录“upload/2020-10-26”是否存在,不存在则创建
            //2.1 获取当前日期
            String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            //2.2 获取当前项目内“upload/2020-10-26”目录的绝对路径(磁盘路径)
            String path = request.getServletContext().getRealPath("/upload/" + date);
            //2.3 判断目录是否存在,不存在创建
            File file = new File(path);
            if(!file.exists()){
                file.mkdir();
            }

            //3.上传
            imgFile.transferTo(new File(path,fileName));

            return "success";
        } catch (IOException e) {
            e.printStackTrace();
            throw  new RuntimeException(e);
        }
    }
}

注意事项:控制器的方法参数 MultipartFile类型的参数名,必须与表单上文件域的name一样
              MultipartFile的作用:可以获取上传文件的名称,文件的输入流
              要用请求域获取上下文域,直接上下文域没用

-------------------------------------------------------------------------------------------------------------------------------
4.配置spring
<!--
    创建文件上传解析器创建文件上传对象
       " 文件上传解析器对象的id属性值=“multipartResolver”,必须为这个值",否则无法解析
       maxUploadSize:设置上传文件的大小,单位字节,如果限制文件上传大小为10M=1024*1024*10
    --
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="#{1024*1024*10}"></property>
    </bean>
----------------------------------------------------------------------------------------
**部署文件上需要查看是否有这个文件**