SpringMVC

一、Spring与Web环境集成

1.1 AppliacationContext应用上下文获取方式

应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件) 方式获取的,但每次从容器中获取Bean时都要编写此配置文件,这样的弊端是配置文件加载多次,应用上下文对象创建多次。

处理方式:

① 静态块:

监听器

在Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在web应用启动时,就加载spring的配置文件,创建应用上下文对象ApplicationContext,再将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象。

创建监听器实现类: 把容器存储到最大的域ServletContext中

public class ContextLoaderListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        
        ServletContext servletContext = servletContextEvent.getServletContext();

        // 读取web.xml中的全局参数
        String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");

        //初始化是创建ApplicationContext的容器
        ApplicationContext app = new ClassPathXmlApplicationContext(contextConfigLocation);
        //将Spring的应用上下文对象存储到ServletContext域中
        servletContext.setAttribute("app",app);
        System.out.println("spring容器创建完毕");

    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}

web.xml中配置监听器:

<!--配置监听器-->
  <listener>
    <listener-class>com.chu.listener.ContextLoaderListener</listener-class>
  </listener>

	<!--全局初始化参数-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>applicationContext.xml</param-value>
  </context-param>

Uservlet代码如下:

public class UserServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        ServletContext servletContext = this.getServletContext();
        ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
        //ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        //ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        UserService userService = app.getBean(UserService.class);
        userService.save();
    }
}

1.2 spring提供获取应用上下文的工具

1.1中不用手动去实现,Spring提供了一个监听器ContextLoaderListener就是对上述功能的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象。

在这里插入图片描述
① pom.xml中导入依赖坐标

	<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

② web.xml中配置监听器和全局初始化参数

 <!--配置spring中的监听器-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!--配置spring中的全局初始化参数-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>

获取容器:

public class UserServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        ServletContext servletContext = this.getServletContext();
        //ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
        ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);

        UserService userService = app.getBean(UserService.class);
        userService.save();
    }
}

二、SpringMVC的简介

2.1 SpringMVC概述

SpringMVC是一种基于Java的实现MVC设计模式的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品,已经融合在SPringle Web Flow中。

SpringMVC已经目前最主流的MVC框架之一,它通过一套注解,让一个简单的Java类成为处理请求的控制器(servlet),而无需实现任何接口。 同时还支持RESTful编程风格的请求。

使用SpringMVC控制Servlet的共有行为
在这里插入图片描述

从上图知SpringMVC的开发步骤

导入SpringMVC相关坐标

pop.xml中:

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

配置SpringMVC核心控制器DispatcherServlet(共有行为

web.xml中:

  <!--配置SpringMVC的前端控制器-->
  <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

编写Controller和视图页面(在springMVC中习惯把此简单的Bean称为Controller

将Controller使用注解配置到Spring容器中(@Controller)、配置Controller类中业务方法的映射地址(特有行为

Controller类:

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

    @RequestMapping("/quick") //配置业务方法映射地址
    public String save(){
        System.out.println("Controller save running...");
        return "success.jsp";  //表示当前资源所在地址
        	//如果类上加入/user,在访问此资源时要使用/success.jsp
    }
}

success.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <h1>创建成功</h1>

</body>
</html>

配置spring-mvc.xml文件(配置组件扫描)

	<!--Controller的组件扫描-->
    <context:component-scan base-package="com.chu.controller"/>

同时要在web.xml定义全局初始化参数,来加载此配置文件:

  <!--配置SpringMVC的前端控制器-->
  <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>

客户端发起请求测试

http://localhost:8080/spring_mvc/quick		页面输出创建成功,控制台输出Controller save running...

2.2 SpringMVC流程图示

在这里插入图片描述

三、SpringMVC的组件解析

3.1 SpringMVC的执行流程

处理器Handler是上述例子中创建的Controller
在这里插入图片描述
在这里插入图片描述


3.2 SpringMVC注解解析

在这里插入图片描述

在这里插入图片描述

3.3 SpringMVC的XML配置解析 (资源解析器)

success.jsp前省略了forword:(请求转发-默认)或redirect:(重定向)

@Controller
public class UserController {

    @RequestMapping("/quick") //配置业务方法映射地址
    public String save(){
        System.out.println("Controller save running...");
        return "success.jsp";
    }
}

例如访问jsp包下的success.jsp文件: 减轻开发复杂度

spring_mvc.xml配置如下:

    <!--配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--拿到前缀,视图的名称,再拿到后缀 /jsp/success.jsp-->
        <property name="prefix" value="/jsp"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

3.4 知识要点

在这里插入图片描述

四、SpringMVC的数据响应

4.1 SpringMVC的数据响应方式

1)页面跳转

① 直接返回字符串
② 通过ModleAndView对象返回

2)回写数据

① 直接返回字符串
② 返回对象或集合

4.2 页面跳转

1)返回字符串形式

直接返回字符串:此方式会将返回的字符串域视图解析器的前后缀拼接后跳转。
在这里插入图片描述
2)返回ModleAndView对象的几种方式

@Controller
public class UserController {

	// 不常用,尽量使用框架提供的对象
	@RequestMapping("/quick5") //配置业务方法映射地址
    public String save5(HttpServletRequest request){ // request原生的javaWeb对象

        request.setAttribute("username","good");

        return "success";
    }

	@RequestMapping("/quick4") //配置业务方法映射地址
    public String save4(Model model){ //model是springMVC封装好的对象

        model.addAttribute("username","jie");

        return "success";
    }

    @RequestMapping("/quick3") //配置业务方法映射地址
    public ModelAndView save3(ModelAndView modelAndView){
        // 对方法参数进行设置模型数据
        modelAndView.addObject("username","xiao");
        //设置视图名称
        modelAndView.setViewName("success");
        return modelAndView;
    }

    @RequestMapping("/quick2") //配置业务方法映射地址
    public ModelAndView save2(){
        /*
        * Model:模型  封装数据
        * View:视图   展示数据
        * */
        ModelAndView modelAndView = new ModelAndView();
        //设置模型数据
        modelAndView.addObject("username","chu");
        //设置视图名称
        modelAndView.setViewName("success");
        return modelAndView;
    }
	
}

spring_mvc.xml中配置如下:

 	<!--Controller的组件扫描-->
    <context:component-scan base-package="com.chu.controller"/>

    <!--配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--拿到前缀,视图的名称,再拿到后缀 /jsp/success.jsp-->
        <property name="prefix" value=""></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

success.jsp:

<html>
<head>
    <title>Title</title>
</head>
<body>

    <h1>创建成功 ${username}</h1>

</body>
</html>

4.3 回写数据

1直接返回字符串

Web基础阶段,客户端访问服务器端,如果想直接回写字符串作为响应体返回的话,只需要使用response.getWriter().print() 即可。
response.getWriter().print(),不仅可以打印输出文本格式的(包括html标签),还可以将一个对象以默认的编码方式转换为二进制字节输出

response.getWriter().writer(),只能打印输出文本格式的(包括html标签),不可以打印对象。

那么在Controller中该如何直接回写字符串:

通过SpringMVC框架注入的response对象,使用response.getWriter().print()回写数据,此时不需要试图跳转,业务方法返回值为void。
在这里插入图片描述

@RequestMapping("/quick6") //配置业务方法映射地址
    public void save6(HttpServletResponse response) throws Exception{ // response原生的javaWeb对象

        response.getWriter().print("hello chu");
    }

将需要回写的字符串直接返回,但此时需要通过 @ResponseBody注解告知SpringMVC框架,方法返回的字符串不是跳转是直接在http响应体中返回。(不加注解默认与跳转与第一种相同了。)如果返回类型是void,则说明响应体为空,什么都不回写

	@RequestMapping("/quick7") //配置业务方法映射地址
    @ResponseBody   // 不加注解与第一种相同了,要加注解告知框架,方法返回的字符串不是跳转而是在http响应体中返回
    public String save7() throws Exception{ // response原生的javaWeb对象

        return "hello chu";
    }

返回json格式的字符串:

	@RequestMapping("/quick8") //配置业务方法映射地址
    @ResponseBody   // 不加注解与第一种相同了,要加注解告知框架,方法返回的字符串不是跳转而是在http响应体中返回
    public String save8() throws Exception{ // response原生的javaWeb对象

        return "{\"username\":\"zhangsan\",\"age\":18}";  //返回json格式数据
    }

手打格式过于繁琐,导入包,直接转换成json格式:

导入pop.xml坐标:

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

代码:

	@RequestMapping("/quick9") //配置业务方法映射地址
    @ResponseBody   // 不加注解与第一种相同了,要加注解告知框架,方法返回的字符串不是跳转而是在http响应体中返回
    public String save9() throws Exception{ // response原生的javaWeb对象
        User user = new User();
        user.setUsername("lisi");
        user.setAge(99);
        //使用json的转换工具将对象转换成json格式字符串再返回
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(user);

        return json;
    }

2返回对象或集合

期望SpringMVC自动将User转换成json格式的字符串。

要再spring_mvc.xml中配置处理器映射器(即,注入json转换的转换器):

    <!--配置处理器映射器-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
            </list>
        </property>
    </bean>

测试如下:

    @RequestMapping("/quick10") //配置业务方法映射地址
    @ResponseBody   // 不加注解与第一种相同了,要加注解告知框架,方法返回的字符串不是跳转而是在http响应体中返回
    //期望SpringMVC自动将User转换成json格式的字符串
    public User save10() throws Exception{ // response原生的javaWeb对象
        User user = new User();
        user.setUsername("lisi");
        user.setAge(99);

        return user;
    }

在方法上添加@ResponseBody就可以返回json格式的字符串,但是这样的配置比较麻烦,配置的代码比较多,因此,可以使用mvc的注解驱动代替上述配置。
在这里插入图片描述
在spring_mvc.xml文件中替换掉上面的处理器映射器配置;

要先在上方导入mvc的命名空间:

<beans xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<!--mvc的注解驱动,默认底层就会继承jackson进行对象或集合的json格式字符串的转换-->
    <mvc:annotation-driven/>

五、SpringMVC的请求

5.1 获得请求参数

客户端请求参数的格式是:name=value&name=value… …

服务器端要获得请求的参数,有时还需要进行数据的封装, SpringMVC可以接受如下类型的参数:

基本数据参数
POJO类型参数(简单JavaBean)
数组类型参数
集合类型参数

5.2 获得基本类型参数

Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。
在这里插入图片描述
返回类型void,说明响应体为空,什么都不回写

	@RequestMapping("/quick11") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save11(String username,int age) throws Exception{ // void表示什么都不回写,即:响应体什么都没有

        System.out.println(username);
        System.out.println(age);
    }

发送请求:

http://localhost:8080/spring_mvc/quick11?username=chu&age=25

控制台输出:
chu
25

5.3 获得POJO类型参数

Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。
在这里插入图片描述
业务方法的参数要是POJO(简单bean对象):

@RequestMapping("/quick12") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save12(User user) throws Exception{ // void表示什么都不回写,即:响应体什么都没有

        System.out.println(user); //重写了user的toString,输出...
    }

发送请求:

http://localhost:8080/spring_mvc/quick12?username=chu&age=99

控制台输出:
User{username='chu', age=99}

5.4 获得数组类型参数

Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。
在这里插入图片描述

	@RequestMapping("/quick13") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save13(String[] strs) throws Exception{ // void表示什么都不回写,即:响应体什么都没有

        System.out.println(Arrays.asList(strs)); //重写了user的toString,输出...
    }

发送请求:

http://localhost:8080/spring_mvc/quick13?strs=aaa&strs=bbb&strs=ccc

控制台输出:
[aaa, bbb, ccc]

5.5 获得集合类型参数

1)常用方式:

获得集合参数时,要将集合参数包装到一个POJO中才可以

VO包装的POJO泛型是User:

public class VO {

    private List<User> userList;

    public VO() {
    }

    public VO(List<User> userList) {
        this.userList = userList;
    }

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }

    @Override
    public String toString() {
        return "VO{" +
                "userList=" + userList +
                '}';
    }
}

UserController如下: VO是POJO类型,故业务方法的POJO参数的属性名与请求参数的name一致

	@RequestMapping("/quick14") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save14(VO vo) throws Exception{
        // VO是泛型为user的list集合,请求的数据要是集合形式
        //   请求参数不好在网页输入,故写入form.jsp中放入表单进行提交
        System.out.println(vo);
    }

由于VO是泛型为user的list集合,请求的数据要是集合形式,请求参数不好在网页输入,故写入form.jsp中放入表单进行提交。

form.jsp:

<body>
        <%--请求参数不好在网页输入,故放入表单进行提交--%>
        <form action="${pageContext.request.contextPath}/quick14" method="post">
            <%--表明是第几个User对象(userList[])的username age--%>
            用户名1:<input type="text" name="userList[0].username"><br/>
            年龄1:<input type="text" name="userList[0].age"><br/>

            用户名2<input type="text" name="userList[1].username"><br/>
            年龄2<input type="text" name="userList[1].age"><br/>
            提交:<input type="submit">
        </form>
</body>

发送请求:

http://localhost:8080/spring_mvc/form.jsp
	
输入表单信息...,之后提交跳转请求,其中参数的表单输入信息后的集合。

控制台输出:
VO{userList=[User{username='zhangsan', age=12}, User{username='lisi', age=11}]}

2)特殊情况:

当使用ajax提交时,可以指定contextType为json形式,那么在方法参数位置使用 @RequestBody 可以直接接收集合数据而无需使用POJO进行包装

ajax.jsp代码如下:

<head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/jquery-3.3.1.js"></script>
    <script>
        var userList=new Array();
        userList.push({username:"zhangsan",age:12});
        userList.push({username:"lisi",age:15});
		
		//ajax请求,其中将集合转为json字符串
        $.ajax({
           type:"POST",
           url:"${pageContext.request.contextPath}/quick15",
           data:JSON.stringify(userList), //把集合转为json字符串
           contentType:"application/json;charset=utf-8"
        });
    </script>
</head>

请求代码: 使用ajax请求,无需把集合参数封装成POJO类型,使用@RequestBody注解修饰。

@RequestBody是请求体,上述是把请求体的内容封装到userList集合中。

	@RequestMapping("/quick15") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save15(@RequestBody List<User> userList) throws Exception{
    	// @RequestBody是请求体,上述是把请求体的内容封装到userList集合中
        System.out.println(userList);

    }

发出请求后,可能出现找不到jquery-3.3.1.js的情况,要在spring_mvc.xml中配置访问静态资源:

	<!--开放静态资源的访问
        方式一:mapping代表映射地址 location代表是哪个路径下的资源开放
    -->
    <!--<mvc:resources mapping="/**" location="//"/>-->

    <!--方式二:先找匹配地址,如果找不到就交给原始容器(Tomcat)找对应的静态资源-->
    <mvc:default-servlet-handler/>

发送请求:

http://localhost:8080/spring_mvc/ajax.jsp

控制台输出:
[User{username='zhangsan', age=12}, User{username='lisi', age=15}]

5.6 请求数据乱码问题

当post请求时,数据会出现乱码(例如上述集合表单中文数据提交后,控制台就会出现乱码)。可以设置一个过滤器来进行编码的过滤。
在这里插入图片描述
web.xml:

  <!--配置全局过滤的filter-->
  <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>

发送请求:

http://localhost:8080/spring_mvc/form.jsp		表单提交之后

控制台输出:
VO{userList=[User{username='张三', age=12}, User{username='李四', age=11}]}

5.7 参数绑定注解@requestParam

请求的参数名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定。
在这里插入图片描述
@RequestParam把请求参数name映射到username上:

	@RequestMapping("/quick16") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save16(@RequestParam(value = "name") String username) throws Exception{
        // @RequestParam把请求参数name映射到username上
        System.out.println(username);
    }

发送请求:

http://localhost:8080/spring_mvc/quick16?name=iii

控制台输出:
iii

在这里插入图片描述

5.8 获得Restful风格的参数

在这里插入图片描述
在这里插入图片描述
@PathVariable把占位符的值映射给username:

    //localhost:8080/user/quick17/zhangsan
    @RequestMapping("/quick17/{name}") //配置业务方法映射地址,{}占位符
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save17(@PathVariable(value = "name") String username) throws Exception{
        // @PathVariable把占位符的值映射给username
        System.out.println(username);
    }

发送请求:

http://localhost:8080/spring_mvc/quick17/zhangsan

控制台输出:
zhangsan

5.9 自定义类型转换器(不常用)

SpringMVC默认已经提供了一些常用的类型转换器。例如客户端提交的字符串转换成int型进行参数设置。

但是不是所有的数据类型都提供了转换器,每提供的就需要自定义转换器,例如:日期类型的数据就需要自定义转换器。

自定义类型转换器的开发步骤:

① 定义转换器类实现Converter接口

com.chu.converter包下:

public class DateConverter implements Converter<String, Date> {
    public Date convert(String dateStr){
        //将日期字符串转换成日期对象返回
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

}

② 在spring_mvc.xml文件中声明转换器

    <!--声明转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.chu.converter.DateConverter"></bean>
            </list>
        </property>
    </bean>

③ 在<annotation-driven>中引用转换器

	<!--mvc的注解驱动,默认底层就会继承jackson进行对象或集合的json格式字符串的转换-->
    <mvc:annotation-driven conversion-service="conversionService"/>

发送请求:

http://localhost:8080/spring_mvc/quick18?date=2021-07-13

控制台输出:
Tue Jul 13 00:00:00 CST 2021

5.10 获得Servlet相关API

SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:

HttpServletRequest
HttpServletResponse
HttpSession

在这里插入图片描述

    @RequestMapping("/quick19") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save19(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception{
        System.out.println(request);
        System.out.println(response);
        System.out.println(session);
    }

发送请求:

http://localhost:8080/spring_mvc/quick19

控制台输出:
org.apache.catalina.connector.RequestFacade@6fc2ebae
org.apache.catalina.connector.ResponseFacade@162b9ab4
org.apache.catalina.session.StandardSessionFacade@76d21d1b

5.11 获得请求头

1)@ReqyestHeader
在这里插入图片描述
@RequestHeader把请求头的值映射给user_agent:

	@RequestMapping("/quick20") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save20(@RequestHeader(value = "User-Agent",required = false) String user_agent) throws Exception{
        //@RequestHeader把请求头的值映射给user_agent
        System.out.println(user_agent);
    }

发送请求:

http://localhost:8080/spring_mvc/quick20

控制台输出:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36

2)@CookieValue
在这里插入图片描述

	@RequestMapping("/quick21") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save21(@CookieValue(value = "JSESSIONID",required = false) String jsessionid) throws Exception{
        //@CookieValue把cookie的键映射给jsessionid,得到cookie的值
        System.out.println(jsessionid);
    }

发送请求:

http://localhost:8080/spring_mvc/quick21

控制台输出:
419A304875A3E039A5CFDDAA5D2781A4

5.12 文件上传(也属于客户端把数据请求发送到服务器端)

1文件上传客户端三要素:

① 表单项type="file"
② 表单的提交方式时post
③ 表单的enctype属性是多部份表单形式,即enctype="multipart/form-data"

在这里插入图片描述
upload.jsp写入三要素(在表单项中):

<body>
        <form action="${pageContext.request.contextPath}/quick22" method="post" enctype="multipart/form-data">
            名称<input type="text" name="username"><br/>
            文件<input type="file" name="upload"><br/>
            <input type="submit" value="提交"><br/>
        </form>
</body>

2文件上传原理(解释改为多部分表单时…):
在这里插入图片描述


5.13 单文件上传步骤

导入fileupload和io坐标

    <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.3</version>
    </dependency>

spring_mvc.xml中配置文件上传解析器

    <!--配置文件上传解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--上传文件的编码类型-->
        <property name="defaultEncoding" value="UTF-8"/>
        <!--上传文件总大小-->
        <property name="maxUploadSize" value="5242800"/>
        <!--上传单个文件的大小-->
        <property name="maxUploadSizePerFile" value="5242800"/>
    </bean>

编写文件上传代码

注意文件上传业务的参数名字要与表单file类型的name相同。

先获取原始文件名称,然后利用transferTo方法将文件保存到本地:

	@RequestMapping("/quick22") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save22(String username, MultipartFile uploadFile) throws Exception{
        System.out.println(username);
        //获得上传文件的名称
        String originalFilename = uploadFile.getOriginalFilename();
        //把文件保存到D盘根目录,且带上文件名称
        uploadFile.transferTo(new File("D:\\"+originalFilename));
    }

发送请求:

http://localhost:8080/spring_mvc/upload.jsp		表单提交数据: 张三、(上传的文件)

控制台输出:
张三
(本地D盘有上传的文件)

5.14 多文件上传实现

1)文件名不一样时(uploadFile1、uploadFile2):

		<form action="${pageContext.request.contextPath}/quick22" method="post" enctype="multipart/form-data">
            名称<input type="text" name="username"><br/>
            文件1<input type="file" name="uploadFile1"><br/>
            文件2<input type="file" name="uploadFile2"><br/>
            <input type="submit" value="提交"><br/>
        </form>

则分两个参数传入:

	@RequestMapping("/quick22") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save22(String username, MultipartFile uploadFile1,MultipartFile uploadFile2) throws Exception{
        System.out.println(username);
        //获得上传文件的名称
        String originalFilename1 = uploadFile1.getOriginalFilename();
        //把文件保存到D盘根目录,且带上文件名称
        uploadFile1.transferTo(new File("D:\\"+originalFilename1));
        String originalFilename2 = uploadFile2.getOriginalFilename();
        uploadFile2.transferTo(new File("D:\\"+originalFilename2));
    }

2)文件名一样时(uploadFile1、uploadFile1、uploadFile2):

        <form action="${pageContext.request.contextPath}/quick23" method="post" enctype="multipart/form-data">
            名称<input type="text" name="username"><br/>
            文件1<input type="file" name="uploadFile1"><br/>
            文件2<input type="file" name="uploadFile1"><br/>
            文件3<input type="file" name="uploadFile2"><br/>
            <input type="submit" value="提交"><br/>
        </form>

文件名相同的并到一个数组参数中传入、文件名不同的分为两个参数:

@RequestMapping("/quick23") //配置业务方法映射地址
    @ResponseBody   // 加注解告知框架,方法返回的字符串不是跳转而是在http响应体中回写数据
    public void save23(String username, MultipartFile[] uploadFile1,MultipartFile uploadFile2) throws Exception{
        System.out.println(username);
        // 遍历获得上传文件的名称,并保存到D盘根目录
        for (MultipartFile multipartFile:uploadFile1){
            String originalFilename = multipartFile.getOriginalFilename();
            multipartFile.transferTo(new File("D:\\"+originalFilename));
        }
        String originalFilename2 = uploadFile2.getOriginalFilename();
        uploadFile2.transferTo(new File("D:\\"+originalFilename2));
    }

六、SpringMVC拦截器

6.1 拦截器(interceptor)的作用

SpringMVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理后处理

将拦截器按一定的孙旭联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或字段,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。

6.2 拦截器和过滤器的区别

在这里插入图片描述

6.3 拦截器的快速入门

自定义拦截器步骤:

创建拦截器类实现HandlerInterceptor接口

public class MyInterceptor1 implements HandlerInterceptor {
    //在目标方法执行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("priHandle...");
        return false; //false表示拦截后,后面方法都不执行
    }

    //在目标方法执行之后,视图返回之前执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }

    //在整个流程都执行完毕后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}

spring_mvc.xml配置拦截器

    <!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--对哪些资源执行拦截操作-->
            <mvc:mapping path="/**"/>
            <bean class="com.chu.interceptor.MyInterceptor1"/>
        </mvc:interceptor>
    </mvc:interceptors>

测试拦截器的拦截效果

情况1: 拦截器preHandle()方法最后return false(false表示拦截,后面方法都不执行)时:

发送请求:

http://localhost:8080/spring_interceptor/target	页面无显示

控制台输出:

priHandle...

情况2: 拦截器preHandle()方法最后return true(true表示放行,后面方法可以执行)时:

发送请求:

http://localhost:8080/spring_interceptor/target	页面显示Hello World! chu

控制台输出:

priHandle...
目标资源执行...
postHandle...
afterCompletion...

6.4 拦截器实现类的方法以及配置说明

方法说明:
在这里插入图片描述

例如:

preHandle方法可以利用request对请求参数进行判定;

postHandle方法中的参数modelAndView可以对目标方法中的结果进行修改。

public class MyInterceptor1 implements HandlerInterceptor {
    //在目标方法执行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("priHandle...");
        //利用request对请求参数进行判定
        String param = request.getParameter("param");
        if ("yes".equals(param)){
            return true;
        }else {
            request.getRequestDispatcher("/error.jsp").forward(request,response);
            return false;
        }
    }

    //在目标方法执行之后,视图返回之前执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //方法中的参数modelAndView可以对目标方法中的结果进行修改
        modelAndView.addObject("name","xiao");
        System.out.println("postHandle...");
    }

    //在整个流程都执行完毕后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}

配置说明:

两个拦截器时:

    <!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--对哪些资源执行拦截操作-->
            <mvc:mapping path="/**"/>
            <bean class="com.chu.interceptor.MyInterceptor1"/>
        </mvc:interceptor>
        <mvc:interceptor>
            <!--对哪些资源执行拦截操作-->
            <mvc:mapping path="/**"/>
            <bean class="com.chu.interceptor.MyInterceptor2"/>
        </mvc:interceptor>
    </mvc:interceptors>

发送请求: 控制台输出与配置的上下顺序有关,与Filter一样

http://localhost:8080/spring_interceptor/target	页面显示Hello World! xiao

控制台输出:  

priHandle...
priHandle222...
目标资源执行...
postHandle222...
postHandle...
afterCompletion222...
afterCompletion...

七、SpringMVC异常处理机制

7.1 异常处理的思路

在这里插入图片描述

7.2 异常处理两种方式

1)使用SprigMVC提供的简单异常处理器SimpleMappingExceprionResolver

SpringMVC已经定义好了该类型转换器,在使用时可以根据项目情况进行相应异常与视图的映射配置

在这里插入图片描述
spring_mvc.xml文件中配置如下:

	<!--配置异常处理器-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="defaultErrorView" value="error"/>
        <property name="exceptionMappings">
            <map>
                <entry key="java.lang.ClassCastException" value="error1"/>
                <entry key="com.chu.exception.MyException" value="error2"/>
            </map>
        </property>
    </bean>

2)实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器

创建异常处理器类实现HandlerExceptionResolver

public class MyExceptionResolver implements HandlerExceptionResolver {

    /*
        参数Exception:异常对象
        返回值ModelAndView:跳转到错误视图信息
     */
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();

        if(e instanceof MyException){
            modelAndView.addObject("info","自定义异常");
        }else if(e instanceof ClassCastException){
            modelAndView.addObject("info","类转换异常");
        }

        modelAndView.setViewName("error");

        return modelAndView;
    }
}

spring_mvc.xml中配置异常处理器(让spring容器知道有个自定义…)

    <!--自定义异常处理器-->
    <bean class="com.chu.resolver.MyExceptionResolver"/>

编写异常页面error.jsp

<body>
    <h1>通用的错误提示页面</h1>
    <h1>${info}</h1>
</body>

测试异常跳转

发送请求:

http://localhost:8080/spring_exception/show	页面显示 error页面信息

控制台输出:

show running......
自定义异常....

7.3 知识要点

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值