SpringMvc

第一天
三层架构
SpringMvc概述
Spring的入门程序
入门案例中使用的组件介绍(特别重要)
RequestMapping注解的作用
请求参数的绑定(特别重要)
过滤器解决中文乱码
自定义类型转换器
获取Servlet原生的API
常用注解
第二天
响应数据和结果视图
Response响应json数据
SpringMvc文件上传
SpringMvc的异常处理
SpringMvc中的拦截器

三层架构

在这里插入图片描述
在这里插入图片描述
MVC模式:
在这里插入图片描述

SpringMvc概述

在这里插入图片描述
SpringMvc在三层架构中的位置
在这里插入图片描述
SpringMVC的优势
在这里插入图片描述

SpringMvc和Struct2的优略分析

在这里插入图片描述

Spring入门程序

入门程序的需求:

在这里插入图片描述

1、搭建环境
用骨架来构建:
在这里插入图片描述
进去之后我们发现结构是这样的,没有java和resources文件

在这里插入图片描述
所以我们要自己创建java和resources文件。
在这里插入图片描述
在这里插入图片描述
2、导入依赖
这里将版本改成1.8

在这里插入图片描述

然后再将spring的版本控制成5.0.2
然后再导入依赖:

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

配置前端控制器

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

创建spring配置文件,导入协议
在这里插入图片描述

<?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

部署tomcat
在这里插入图片描述
在这里插入图片描述
入门程序代码编写
默认的index.jsp文件中没有文件头,所以需要将默认的index.jsp文件删除后重新创建一个index.jsp,创建一个超链接
在这里插入图片描述
创建一个Controller类
在这里插入图片描述
在这里插入图片描述
用@Controller注解将controller类创建到容器中,在方法上使用@RequestMapping注解,作用其实和servlet是差不多的,这样在jsp文件中就能用@RequestMapping的path属性使用被映射的方法。(注意:这里的斜杠不能省略)
所以这时我们就要配置注解扫描
在springmvc中加入标签

    <context:component-scan base-package="cn.itcast"></context:component-scan>

但是需要注意的是,虽然我们配置了这个文件,但是这个文件从来没有被加载过,那里面的配置也就一点作用都不起。
所以这又回到了前端控制器中,让前端控制器帮我们加载。

  <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>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

在里面加入<init-param>这个标签,表示给DispatcherServlet类的contextConfigLocation这个属性配置了classpath:springmvc.xml这个值。意思就是在创建DispatcherServlet类的时候,DispatcherServlet就会帮我们加载classpath:springmvc.xml这个路径下的文件。而DispatcherServlet是一个servlet,servlet是什么时候创建的,是在第一次客户端发送请求的时候创建的,而配置的<load-on-startup>1</load-on-startup>表示在创建服务器的时候就创建DispatcherServlet这个对象,也就会加载springmvc这个文件。
跳转成功页面
在这里插入图片描述
在WEB-INF/pages/success.jsp创建成功页面。现在我们想从sayHello()这个方法跳回到这个页面,就需要用到一个叫做视图解析器的组件。
配置视图解析器
在springmvc.xml中配置

    <!-- 视图解析器  -->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property><!-- 配置前缀 -->
        <property name="suffix" value=".jsp"></property>
    </bean><!-- 配置后缀 -->

也就是当我们的RequsetMapping注解的方法返回一个"success"的字符串,前端控制器就会去找/WEB-INF/pages里的success.jsp文件

最后,开启spring框架注解的支持

    <!-- 开启SpringMvc框架注解的支持 -->
    <mvc:annotation-driven conversion-service="ConversionService"/>

最后将所有的配置全都统一看一遍:
web.xml:
在这里插入图片描述
springmvc:
在这里插入图片描述
controller类
在这里插入图片描述

index.jsp(注意:这里的hello不能加/)

在这里插入图片描述
success.jsp
在这里插入图片描述
入门程序的流程总结:
在这里插入图片描述

入门案例中使用的组件介绍

***这张图片是SpringMvc的流程图,非常重要。***

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到spring主要有3个组件,但是前面我们只配置了前端控制器和视图解析器,那处理器适配器难道我们就没打开吗?不对!
在这里插入图片描述

RequestMapping注解的作用

作用:用于建立请求url和处理请求方法之间的关系
我们进去RequestMapping注解的源码:
在这里插入图片描述
发现它既可以用在方法上,也可以用在类上。
举个例子:
我们在类上加一个@RequestMapping("/user")
在这里插入图片描述
这样的话在index.jsp就要改变成<a href="user/hello">入门程序</a>
也就是说在类上加@RequestMapping注解其实是起到分模块的作用,以后我们有accountController,userController,就可以用account/*user/*来区分,让开发更清晰,但是需要注意的是,第一级目录的前面一定不能加斜杠


@RequestMapping注解的属性:
1、path和value
      可以发现path和value属性的别名互相是对方,也就是所path和value的作用是一样的,并且在只写path或者value的情况下,可以不用写属性名:@RequestMapping("/user")
2、method
我们看到method属性是一个RequestMethod数组,点进去一看发现RequestMethod是一个枚举类型,也就是说可以直接用。
在这里插入图片描述

method的作用是指定请求方式。@RequestMapping(path = "/hello", method = {RequestMethod.POST})这里的意思就是只有post方法能访问到这个方法。
3、params
我们看到params是一个字符串数组,它的意思是,要想访问这个方法就必须给方法传params里所有的属性。@RequestMapping(path = "/hello", params = {"username"})这个的意思是必须要传一个名为username的属性。那就要这样<a href="user/hello?username=hehe">入门程序</a>才能访问到。而当我这样设置@RequestMapping(path = "/hello", params = {"username=heiheihei"})就意味着你不仅要给我传一个username的属性,这个属性的值还必须得是heihei,不然就无法访问。
4、headers
意思是发送的请求中必须包含的请求头@RequestMapping(path = "/hello", params = {"username=heiheihei"},headers = {"accept"})

请求参数的绑定

之前在使用servlet的时候,我们要想拿到请求的参数,都要使用request.getParameter()这个方法来获取参数值,这样会比较麻烦。所以在springmvc中已经帮我们简便里这个,就叫做参数绑定。
它的实现方式很简单。比如现在有一个请求传了这样一些参数:username=hehe&password=123,然后有这样一个方法:sayHello(String username, String password)那么当这个请求到这个方法上时,springmvc就会帮我们把参数直接传到方法的username和password中,但是要注意,他们的参数名字必须一样,springmvc支持基本数据类型和字符串类型,JavaBean和集合

在这里插入图片描述
1、基本类型和字符串类型:
建立超链接:<a href="param/testParam?username=hehe&password=123">请求参数绑定</a>
建立Controller类:
在这里插入图片描述
2、JavaBean
先建立实体类:
在这里插入图片描述

这里需要注意,实体类属性的注入依靠的是set方法,如果没有set方法将无法注入
编写jsp文件:
在这里插入图片描述
在这里插入图片描述

当实体类中还有其他的JavaBean,就写成这个JavaBean的名字+. +属性名,如上图所示。
3、集合类型
创建集合属性:
在这里插入图片描述
编写jsp文件

    <form action="param/saveAccount" method="post">
        姓名:<input type="text" name="username" /><br/>
        密码:<input type="text" name="password" /><br/>
        金额:<input type="text" name="money" /><br/>

        用户姓名:<input type="text" name="list[0].uname" /><br/>
        用户年龄:<input type="text" name="list[0].age" /><br/>

        用户姓名:<input type="text" name="map['one'].uname" /><br/>
        用户年龄:<input type="text" name="map['one'].age" /><br/>
        <input type="submit" value="提交" />
    </form>

过滤器解决中文乱码

在上面的参数绑定中,我们都没有输入过中文,如果我们输入中文试试,控制台就会出现下图这样乱码的情况。

在这里插入图片描述
之前我们的解决办法是:request.setCharacterEncoding("UTF-8");,但是在每一个方法前面都加这个太麻烦了。这里SpringMvc给我们提供了一个过滤器。
在web.xml文件中,配置以下代码:

  <!--配置解决中文乱码的过滤器-->
  <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>

这里<url-pattern>里的/*表示拦截所有请求

自定义类型转换器

因为页面提交的任何数据都是字符串,但是在上面的参数绑定中,依然可以绑定到Integer类型,这是因为springmvc框架已经为我们自动进行了数据转换。但是对于日期类型,有2000/11/11的,也有2000-11-11的,由于有太多的格式,这个springmvc没办法为我们转换了,这样就用到了自定义类型转换器。
我们进入Converter的类看看他的实现类
在这里插入图片描述
可以看到有很多的类型转换,比如我箭头指示的string变成number的方法。
在这里插入图片描述
先创建一个类,让这个类实现Converter接口,并且以<String,Data>形式编写好,再引入需要实现的方法。
在这里插入图片描述
编写这个类,实现String到Data的方法。

public class StringToDateConverter implements Converter<String,Date>{

    /**
     * String source    传入进来字符串
     * @param source
     * @return
     */
    public Date convert(String source) {
        // 判断
        if(source == null){
            throw new RuntimeException("请您传入数据");
        }
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        try {
            // 把字符串转换日期
            return df.parse(source);
        } catch (Exception e) {
            throw new RuntimeException("数据类型转换出现错误");
        }
    }

}

配置自定义类型转换器
在springmvc中配置,这里的set里面的<bean>标签里就放我们刚刚写的实现类。这里的作用是加入我们实现的这个类,它原本的那些实现类依然存在

    <!--配置自定义类型转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="cn.itcast.utils.StringToDateConverter"/>
            </set>
        </property>
    </bean>

获取Servlet原生的API

直接在方法的参数上加入request或者response就行了。

    @RequestMapping("/testServlet")
    public String testServlet(HttpServletRequest request, HttpServletResponse response){
        System.out.println("执行了...");
        System.out.println(request);

        HttpSession session = request.getSession();
        System.out.println(session);

        ServletContext servletContext = session.getServletContext();
        System.out.println(servletContext);

        System.out.println(response);
        return "success";
    }

常用注解

@RequestParam
在前面的参数绑定中,我们要方法的参数和请求的参数名必须保持一致,并且区分大小写。这个注解就是解决参数名不一样的情况。
我们进入这个注解的源码:
在这里插入图片描述
这里的required表示了必须,并且默认是true。意思就是,看下图,我这样配置了,你就必须给我传一个name的属性,哪怕是uname都不行,不传也不行。

    public String testRequestParam(@RequestParam(name="name") String username){
        System.out.println("执行了...");
        System.out.println(username);
        return "success";
    }

只需要在参数名前加入@RequestParam就行,里面的参数值指定了请求中的属性名。
@RequestBody
这个注解蛮重要的,在后面的异步请求中用处很大。只需要在方法的参数前面加上就行了
在这里插入图片描述

    @RequestMapping("/testRequestBody")
    public String testRequestBody(@RequestBody String body){
        System.out.println("执行了...");
        System.out.println(body);
        return "success";
    }

PathVaribale
在这里插入图片描述
@PathVaribale 这个注解主要是用于REST风格URL,也就是Restful风格。在原来的方式中,我们用不同的@RequestMapping的path来找到不同的方法。而在restful风格中,path都是一样的,首先它会以提交的不同方式来分类,比如get就会去找get,如果找到有多个get方法的,就会用后面的url占位符来确定。比如下面的,用user能找到findAll和findById两种,但是在url中加入10,就会指定到findById这个方法。
在这里插入图片描述
这个注释用起来很简单,在参数前直接加就行了,然后再@RequestMapping中加入占位符,这样@PathVariable就能读到占位符里的数据然后传给参数。注意:@PathVariable的name必须和@RequestMapping里的占位符名字一样。
在这里插入图片描述

<a href="anno/testPathVariable/10">testPathVariable</a>

@HiddenHttpMethodFilter
就是一个模拟提交方式的一个组件
在这里插入图片描述
@RequestHeader
用处不大,不具体说明,直接在参数前面加就行了
在这里插入图片描述
在这里插入图片描述
这样可以获得accept的消息头。

@CookieValue
这个也用的比较少
在这里插入图片描述
在这里插入图片描述
@ModelAttribute
在这里插入图片描述
作用在方法上时,会在控制器的方法执行前先执行它。
有两种情况。一种有返回值,一种没有返回值。
有返回值的情况
jsp文件:

    <form action="anno/testModelAttribute" method="post">
        用户姓名:<input type="text" name="uname" /><br/>
        用户年龄:<input type="text" name="age" /><br/>
        <input type="submit" value="提交" />
    </form>

Controller类

    @RequestMapping(value="/testModelAttribute")
    public String testModelAttribute(@ModelAttribute("abc") User user){
        System.out.println("testModelAttribute执行了...");
        System.out.println(user);
        return "success";
    }

    @ModelAttribute
    public User showUser(String uname){
        System.out.println("showUser执行了...");
        // 通过用户查询数据库(模拟)
        User user = new User();
        user.setUname(uname);
        user.setAge(20);
        user.setDate(new Date());
        return user;
    }

也就是在执行testModelAttribute方法执行,先执行了showUser,然后返回了一个user对象,这个user对象会传给testModelAttribute的参数。
没有返回值的情况:

    @RequestMapping(value="/testModelAttribute")
    public String testModelAttribute(@ModelAttribute("abc") User user){
        System.out.println("testModelAttribute执行了...");
        System.out.println(user);
        return "success";
    }

    @ModelAttribute
    public void showUser(String uname, Map<String,User> map){
        System.out.println("showUser执行了...");
        // 通过用户查询数据库(模拟)
        User user = new User();
        user.setUname(uname);
        user.setAge(20);
        user.setDate(new Date());
        map.put("abc",user);
    }

需要在showUser的参数中加入一个map集合,然后把返回值传入map中。testModelAttribute再直接从@ModelAttribute注解的中,取出key为value的对象赋值给参数。

SessionAttribute巨重要
在这里插入图片描述
当我们想从方法中向request的域对象存一些值,然后再在jsp文件中拿出来。以前的方法是创建一个HttpServletRequest request对象,然后用request.setAttribute();这个方法存值。现在我们用一个叫Model的接口,它的实现类是map,键值对的形式。当我们向Model中存键值对时,底层会把数据存入request的域对象中。
用法:
直接把model当成参数使用

    @RequestMapping(value="/testSessionAttributes")
    public String testSessionAttributes(Model model){
        System.out.println("testSessionAttributes...");
        // 底层会存储到request域对象中
        model.addAttribute("msg","美美");
        return "success";
    }

jsp文件用EL表达式直接看值,sessionScope是session的全部内容
在这里插入图片描述
在这里插入图片描述
可以看到的确是存到了request的域对象中。
接下类我们看SessionAttributes注解:下图我们可以看到这个注解只能在类上使用。
在这里插入图片描述
在这里插入图片描述
在类上使用里这个注解后,会将model中以value为key的键值对都传到session里面去。注意:是从model中取值的,不是从request中,因为取值的时候,model中增加的数据还没加入到request中。
当我们想要从session中取出来值的时候,就需要用到ModelMap对象。

    @RequestMapping(value="/getSessionAttributes")
    public String getSessionAttributes(ModelMap modelMap){
        System.out.println("getSessionAttributes...");
        String msg = (String) modelMap.get("msg");
        System.out.println(msg);
        return "success";
    }

当我们想要从session中删除对象时,就需要用到SessionStatus对象。

    @RequestMapping(value="/delSessionAttributes")
    public String delSessionAttributes(SessionStatus status){
        System.out.println("getSessionAttributes...");
        status.setComplete();
        return "success";
    }

响应数据和结果视图

返回值分类:

  1. 字符串(String)
  2. 无返回值(void)
  3. ModelAndView
  4. 关键字进行请求转发和重定向

字符串(String)

在这里插入图片描述
字符串就是之前一直用来跳转"success"这个界面的方法,不做过多解释。

无返回值(void)

没有返回值的方法,其实主要就是用请求转发和重定向,注意:重定向不能直接访问到WEB-INF文件夹里的内容,并且路径是不会被视图解析器扫描的,所以必须写全。

    /**
     * 是void
     * 请求转发一次请求,不用编写项目的名称
     */
    @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);

        // 重定向
        // response.sendRedirect(request.getContextPath()+"/index.jsp");

        // 设置中文乱码
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        // 直接会进行响应
        response.getWriter().print("你好");

        return;
    }

然后还有一个直接响应的方法,直接在页面上显示“你好”两个字,不过这种方法用处不大。

ModelAndView

ModelAndView是SpringMvc提供的一个对象,可以用来调整具体的JSP视图。
其实这个对象就是字面意思一样,model和view,模型和视图,就是既可以存javaBean对象,也可以存储向往哪个页面转,和上面Model效果其实是一样的,只是写法不一样。
我们进入这个对象看一下:发现里面也是个model对象,用的就是model对象的方法,也就是说当我们存数据进ModelAndView的时候,也会被存到request中。并且设置view的时候,这个view会经过视图解析器,所以可以直接写字符串形式。
在这里插入图片描述

    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        // 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        System.out.println("testModelAndView方法执行了...");
        // 模拟从数据库中查询出User对象
        User user = new User();
        user.setUsername("小凤");
        user.setPassword("456");
        user.setAge(30);

        // 把user对象存储到mv对象中,也会把user对象存入到request对象
        mv.addObject("user",user);
        mv.addObject("password","123");

        // 跳转到哪个页面
        mv.setViewName("success");

        return mv;
    }

上面的以字符串为返回值的方式,其实底层也是用ModelAndView的对象来实现的。

关键字

    /**
     * 使用关键字的方式进行转发或者重定向
     * @return
     */
    @RequestMapping("/testForwardOrRedirect")
    public String testForwardOrRedirect(){
        System.out.println("testForwardOrRedirect方法执行了...");

        // 请求的转发
        // return "forward:/WEB-INF/pages/success.jsp";

        // 重定向
        return "redirect:/index.jsp";
    }

Response响应json数据

当我们想实现,前端传来一个ajax请求,然后我们要把数据打包成json传回去的情况。
先写一个button按钮,然后给它绑定一个ajax请求。
首先,我们要导入JavaScript文件,然后打入以下代码:

<head>
    <title>Title</title>

    <script src="js/jquery.min.js"></script>

    <script>
        // 页面加载,绑定单击事件
        $(function(){
            $("#btn").click(function(){
                 alert("hello btn");
            });
        });

    </script>

</head>
<body>
    <button id="btn">发送ajax的请求</button>

</body>

但是运行的时候发现并没有因为alert弹窗,这是什么问题呢。
这里我们看到引入了一个src="js/jquery.min.js"的代码,但是由于前端控制器在设置的时候,用了/来拦截,这个静态文件也被拦截了,所以用不了src目录下的文件,以至于alert也起不了作用。
解决办法,就是需要配置,让前端控制器不要拦截静态资源。
springmvc.xml中,加入以下代码:

    <!--前端控制器,哪些静态资源不拦截-->
    <mvc:resources location="/css/" mapping="/css/**"/>
    <mvc:resources location="/images/" mapping="/images/**"/>
    <mvc:resources location="/js/" mapping="/js/**"/>

css是样式文件,images是图片,js是JavaScript文件。以后都这个规范来写的话,这样配置就够了。注意:location里面不能带*号。
接下来,继续编写ajax请求:

    <script>
        // 页面加载,绑定单击事件
        $(function(){
            $("#btn").click(function(){
                // alert("hello btn");
                // 发送ajax请求
                $.ajax({
                    // 编写json格式,设置属性和值
                    url:"user/testAjax",
                    contentType:"application/json;charset=UTF-8",//指明编码方式为json
                    data:'{"username":"hehe","password":"123","age":30}',
                    dataType:"json",//指明传回的数据的类型是json类型
                    type:"post",
                    success:function(data){
                        // data服务器端响应的json的数据,进行解析
                        alert(data);
                        alert(data.username);
                        alert(data.password);
                        alert(data.age);
                    }
                });

            });
        });

    </script>

然后编写Controller

    @RequestMapping("/testAjax")
    public void testAjax(@RequestBody String body){
        System.out.println("testAjax方法执行了...");

        System.out.println(body);
    }

可以在控制台得到{"username":"hehe","password":"123","age":30},也就是传进来的data。
这里如果发过来的data的key值和JavaBean里的属性值是一样的,就能把value对应封装到JavaBean中,但是需要导入额外的3个jar包。
在这里插入图片描述
导入依赖。

    <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-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>

首先,我们把方法参数变成@RequestBody User user,这里的user的属性值取跟data的key值相同,所以会自动帮我们把数据封装到user类中,这就完成了从json到实体类的转换,但是当我们返回的时候,返回的是user对象,可是在前面ajax的配置中,dataType已经指明了要返回一个json的数据,这里就可以在返回值前面加一个@ResponseBody的注解,它就会帮我们把user对象转换成json的数据:

    /**
     * 模拟异步请求响应
     */
    @RequestMapping("/testAjax")
    public @ResponseBody User testAjax(@RequestBody User user){
        System.out.println("testAjax方法执行了...");
        // 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
        System.out.println(user);
        // 做响应,模拟查询数据库
        user.setUsername("haha");
        user.setAge(40);
        // 做响应
        return user;
    }

SpringMvc文件上传

注意,这里在配置tomcat的时候,选项目的时候要选exploded
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里可以看到,当我们把form表单的enctype改成multipart/form-data后,请求内容就被分成了几个区域,那这样我们怎么解析呢,这里就需要导入这两个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>

1、传统文件上传:
我尝试的时候是传统上传方式一直不行,不过SpringMvc可以。找到原因了,回来记录,由于之前我在尝试传统文件上传的时候,已经配置了springmvc的文件解析器,这样当我在用传统文件上传的时候,参数里的request其实已经被springmvc解析过了,并且解析其实就是用的传统文件上传的方法,所以当我们再解析一次,肯定是为空,解决办法就是把文件解析器的配置给删掉,就能正常使用了。从这里得到答案:别人的详细分析

 @RequestMapping("/fileupload1")
    public String fileuoload1(HttpServletRequest request) throws Exception {
        System.out.println("文件上传...");

        // 使用fileupload组件完成文件上传
        // 上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        System.out.println(path);
        // 判断,该路径是否存在
        File file = new File(path);
        if(!file.exists()){
            // 创建该文件夹
            System.out.println("文件不存在,要创建");
            file.mkdirs();
        }

        // 解析request对象,获取上传文件项
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 解析request
        List<FileItem> items = upload.parseRequest(request);
        // 遍历
        for(FileItem item:items){
            System.out.println("66666");
            // 进行判断,当前item对象是否是上传文件项
            if(item.isFormField()){
                // 说明普通表单向
            }else{
                // 说明上传文件项
                // 获取上传文件的名称
                String filename = item.getName();
                // 把文件的名称设置唯一值,uuid
//                String uuid = UUID.randomUUID().toString().replace("-", "");
//                filename = uuid+"_"+filename;
                // 完成文件上传
                System.out.println(path);
                item.write(new File(path,filename));
                // 删除临时文件
                item.delete();
            }
        }

        return "success";
    }

2、SpringMvc上传方式
执行方法:利用文件解析器来做中转站,直接拿到upload,然后通过参数绑定的方式赋值给方法的参数,所以名称必须一致。
在这里插入图片描述
配置文件解析器:

    <!--配置文件解析器对象,要求id名称必须是multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760" />
    </bean>

这里的properties里面的maxUploadSize属性是上传的最大字节(Byte), 1KB = 1024Byte,1M=1024KB

    /**
     * SpringMVC文件上传
     * @return
     */
    @RequestMapping("/fileupload2")
    public String fileuoload2(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("springmvc文件上传...");

        // 使用fileupload组件完成文件上传
        // 上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        // 判断,该路径是否存在
        File file = new File(path);
        if(!file.exists()){
            // 创建该文件夹
            file.mkdirs();
        }

        // 说明上传文件项
        // 获取上传文件的名称
        String filename = upload.getOriginalFilename();
        // 把文件的名称设置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;
        // 完成文件上传
        upload.transferTo(new File(path,filename));

        return "success";
    }

3、SpringMvc跨服务器的文件上传
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里需要导入额外的jar包

    <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>
    /**
     * 跨服务器文件上传
     * @return
     */
    @RequestMapping("/fileupload3")
    public String fileuoload3(MultipartFile upload) throws Exception {
        System.out.println("跨服务器文件上传...");

        // 定义上传文件服务器路径
        String path = "http://localhost:9090/uploads/";

        // 说明上传文件项
        // 获取上传文件的名称
        String filename = upload.getOriginalFilename();
        // 把文件的名称设置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;

        // 创建客户端的对象
        Client client = Client.create();

        // 和图片服务器进行连接
        WebResource webResource = client.resource(path + filename);

        // 上传文件
        webResource.put(upload.getBytes());

        return "success";
    }

这个讲的很少,我也没成功,等以后作为一个专栏再学习一下吧,就贴个代码。

SpringMvc的异常处理

用异常处理器,来跳到指定的页面。

在这里插入图片描述

1、编写自定义异常类:
注意要继承Exception

public class SysException extends Exception{

    // 存储提示信息的
    private String message;

    public String getMessage() {
        return message;
    }

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

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

}

2、编写异常处理器
注意要实现HandlerExceptionResolver的接口

public class SysExceptionResolver implements HandlerExceptionResolver{

    /**
     * 处理异常业务逻辑
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @return
     */
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 获取到异常对象
        SysException e = null;
        if(ex instanceof SysException){
            e = (SysException)ex;
        }else{
            e = new SysException("系统正在维护....");
        }
        // 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",e.getMessage());
        mv.setViewName("error");
        return mv;
    }

}

3、配置异常处理器

    <!--配置异常处理器-->
    <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>

SpringMvc中的拦截器

拦截器是AOP思想的具体实现

在这里插入图片描述

在这里插入图片描述1、编写拦截器类
我们点进需要实现的HandlerInterceptor看到,其实它已经把所有方法都默认实现过了,所以这里不是继承方法,而是重写方法,要从这里获取。

在这里插入图片描述

在这里插入图片描述
编写拦截器类的java代码

public class MyInterceptor1 implements HandlerInterceptor{

    /**
     * 预处理,controller方法执行前
     * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
     * return false不放行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1执行了...前1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }

    /**
     * 后处理方法,controller方法执行后,success.jsp执行之前
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor1执行了...后1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    /**
     * success.jsp页面执行后,该方法会执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor1执行了...最后1111");
    }

}

2、配置拦截器
/**代表拦截所有方法,/user/*代表拦截/user/下的方法。

    <!--配置拦截器-->
    <mvc:interceptors>
        <!--配置拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体的方法-->
            <mvc:mapping path="/user/*"/>
            <!--不要拦截的方法
            <mvc:exclude-mapping path=""/>
            -->
            <!--配置拦截器对象-->
            <bean class="cn.itcast.interceptor.MyInterceptor1" />
        </mvc:interceptor>

        <!--配置第二个拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体的方法-->
            <mvc:mapping path="/**"/>
            <!--不要拦截的方法
            <mvc:exclude-mapping path=""/>
            -->
            <!--配置拦截器对象-->
            <bean class="cn.itcast.interceptor.MyInterceptor2" />
        </mvc:interceptor>
    </mvc:interceptors>

结果,配置的两个拦截器完全按照上面的流程图来进行的,并且是按照从上到下的顺序来拦截的。
这个
接下来就是ssm的整合了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值