玩命加载中 . . .

SpringMVC


SpringMVC

三层架构和 MVC

  • 三层架构
    • 表现层: 也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求 web 层,web 需要接收 http 请求,完成 http 响应。
    • 业务层: 也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。
    • 持久层: 也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层。
  • MVC
    • 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 是一种用于设计创建 Web 应用程序表现层的模式。
    • Model(模型): 通常指的就是我们的数据模型。作用一般情况下用于封装数据。
    • View(视图): 通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。
    • Controller(控制器): 是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。

SpringMVC 概述

  • SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 表现层框架

SpringMVC的入门

需求:点击超链接发送一个请求,跳转页面

步骤:

  1. 创建maven web工程,导入依赖(ioc,web,webmvc,servletapi,jspapi)

        <!-- 版本锁定 -->    
    <properties>        
        <spring.version>5.0.2.RELEASE</spring.version>    
    </properties>
     
        <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>
    
  2. 配置核心的控制器(配置DispatcherServlet)

    在web.xml配置文件
    <!-- SpringMVC的核心控制器 -->    
    <servlet>        
        <servlet-name>dispatcherServlet</servlet-name>      
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>   
        <!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建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-name>dispatcherServlet</servlet-name>       
        <url-pattern>/</url-pattern>  
    </servlet-mapping>
    
  3. 编写springmvc.xml的配置文件

    <?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans"    xmlns:mvc="http://www.springframework.org/schema/mvc"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="        http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/mvc        http://www.springframework.org/schema/mvc/spring-mvc.xsd        http://www.springframework.org/schema/context        http://www.springframework.org/schema/context/spring-context.xsd">            
        <!-- 配置spring创建容器时要扫描的包 -->   
        <context:component-scan base-package="com.itheima"></context:component-scan>      
        <!-- 配置视图解析器 -->   
        <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">      
            <property name="prefix" value="/WEB-INF/pages/"></property>        
            <property name="suffix" value=".jsp"></property>   
        </bean>      
        <!-- 配置spring开启注解mvc的支持     -->
        <mvc:annotation-driven></mvc:annotation-driven>
    </beans>
    
  4. 编写index.jsp和HelloController控制器类

        
    

入门案例

入门案例
/** 控制器 */
@Controller 
public class HelloController {     
    /**     
    * 接收请求         
    */    
    //请求映射
    @RequestMapping(path="/hello")    
    public String sayHello() {        
        System.out.println("Hello SpringMVC!!");        
        return "success";    }
}
  1. 在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面

    
        

    入门成功!!

  2. 启动Tomcat服务器,进行测试

执行过程分析

1. 入门案例的执行流程

  1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会**加载springmvc.xml配置文件 **
  2. 开启了注解扫描,那么HelloController对象就会被创建
  3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 **找到执行的具体方法 **
  4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下**查找指定名称的JSP文件 **
  5. Tomcat服务器渲染页面,做出响应

image-20200608001412839

原理(运行机制)

  1. 客户端发送请求到DispacherServlet(分发器)

  2. 由DispacherServlet控制器查询HanderMapping,找到处理请求的Controller

  3. Controller调用业务逻辑处理后,返回ModelAndView

  4. DispacherServlet查询视图解析器,找到ModelAndView指定的视图

  5. 视图负责将结果显示到客户端

2. 入门案例中涉及的组件

  1. DispatcherServlet:前端控制器

    • 用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
  2. HandlerMapping:处理器映射器

    • 负责根据用户请求找到 sayhello 即处理器
  3. Handler:处理器 (方法)

    • 它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。
  4. HandlAdapter:处理器适配器

    • 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,不同的处理器都可以通过适配器执行
  5. View Resolver:视图解析器 (根据方法执行的结果找到对应的页面)

  • View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名 即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
  1. View:视图

  2. < mvc:annotation-driven>说明

  • 在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
    • 开启mvc注解支持代表自动加载 RequestMappingHandlerMapping (处理映射器)和 RequestMappingHandlerAdapter ( 处 理 适 配 器 ),同时集成了json转换工具
  1. 明确: 我们只需要编写处理具体业务的控制器(方法)以及视图(页面)。

请求参数的绑定

  1. 请求参数的绑定说明

    1. 表单提交的数据都是k=v格式的 username=haha&password=123
    2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
    3. 要求:提交表单的name和参数的名称是相同的
  2. 支持的数据类型

    1. 基本数据类型和字符串类型
    2. 实体类型(JavaBean)
    3. 集合数据类型(List、map集合等)
  3. 基本数据类型和字符串类型

    1. 提交表单的name和参数的名称是相同的
    2. 区分大小写
  4. 实体类型(JavaBean)

    1. 提交表单的name和JavaBean中的属性名称需要一致,方法参数写实体对象,可自动封装
    2. 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name
  5. 给数组属性数据封装

    1. 提交表单的name和方法参数的数组对象名称需要一致
  6. 给集合属性数据封装

    创建Vo对象,属性包含实体类集合,方法参数是vo,表单如下

    1. JSP页面编写方式:list[0].实体类属性
    2. Map:map[‘one’].属性
  7. 请求参数中文乱码的解决

    • 在web.xml中配置Spring提供的过滤器类

        <!-- 配置过滤器,解决中文乱码的问题 -->    
      <filter>        
          <filter-name>characterEncodingFilter</filter-name>
          <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filterclass>        <!-- 指定字符集 -->    
          <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>
      
  8. 自定义类型转换器

    • 接收到的数据都是字符串类型,springMVC里面有配置好的类型转换器进行转换为其他类型,有特殊需求可以自己加类型转换器

    • 步骤:

      1. 写一个自定义类型转换器的类,实现Converter的接口

        /**  把字符串转换成日期的转换器 */ 
        public class StringToDateConverter implements Converter<String, Date>{
            /**     * 进行类型转换的方法     */    
            public Date convert(String source) {        
                // 判断        
                if(source == null) {            
                    throw new RuntimeException("参数不能为空");
                }
                try {            
                    DateFormat df = new SimpleDateFormat("yyyy-MM-dd");            
                    // 字符串转换日期           
                    Date date = df.parse(source);            
                    return date;        
                } catch (Exception e) {        
                    throw new RuntimeException("类型转换错误");        }    
            }
        }
        
      2. 注册自定义类型转换器,在springmvc.xml配置文件中编写配置

         <!-- 注册自定义类型转换器 -->    
        <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
            <!--注入自定义的转换器-->
            <property name="converters">            
                <set>               
                    <bean class="cn.itcast.utils.StringToDateConverter"/> 
                </set>      
            </property> 
        </bean>       
        <!-- 开启Spring对MVC注解的支持 -->  
        <mvc:annotation-driven conversion-service="conversionService"/>
        
  9. 在控制器中使用原生的ServletAPI对象

    • 只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象

常用的注解

RequestMapping 注解

  • 作用: 用于建立请求 URL 和处理请求方法之间的对应关系
  • 出现位置:
    • 类上: 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。 它出现的目的是为了使我们的 URL 可以按照模块化管理
    • 方法上: 请求 URL 的第二级访问目录。
  • 属性:
    • value:用于指定请求的 URL。它和 path 属性的作用是一样的。
    • method:用于指定请求的方式。 post/get
    • params:用于指定限制请求参数的条件。要求请求参数的 key 和 value 必须和 配置的一模一样。
      • 例如:params = {“accountName”} params = {“accountName=hehe”}
    • headers:用于指定限制请求消息头的条件。

@WebServlet、@WebFilter、@Weblistener

  1. 作用:加在类上,表示该类是一个三大组件
  2. 属性
    1. value:url路径 如: /hello

RequestParam注解 (解决参数名称和传递参数名称不一致)

  1. 作用:把请求中的指定名称的参数传递给控制器中的形参赋值
  2. 属性
    1. value:请求参数中的名称
    2. required:请求参数中是否必须提供此参数,默认值是true,必须提供
<input type="text" name="username">
public String sayHello(@RequestParam(value="username",required=false)String name) {               

RequestBody注解

  1. 作用:用于获取请求体的内容(注意:get方法不可以)
  2. 属性
    1. required:是否必须有请求体,默认值是true
 public String sayHello(@RequestBody String body) { 

ResponseBody注解

  1. 作用:用在方法上,不进行页面跳转,直接回写数据

RequestHeader注解

  1. 作用:获取指定请求头的值
  2. 属性
    1. value:请求头的名称
@RequestMapping(path="/hello")   
public String sayHello(@RequestHeader(value="Accept") String header) {

CookieValue注解

  1. 作用:用于获取指定cookie的名称的值
  2. 属性
    1. value:cookie的名称
@RequestMapping(path="/hello")    
public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) {

PathVariable注解

  1. 作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符
  2. 属性
    1. value:指定url中的占位符名称
  3. Restful风格的URL
    1. 请求路径一样,可以根据不同的请求方式去执行后台的不同方法
    2. restful风格的URL优点 1. 结构清晰 2. 符合标准 3. 易于理解 4. 扩展方便
 @RequestMapping(path="/hello/{id}")    
 public String sayHello(@PathVariable(value="id") String id) { 

ModelAttribute注解

  1. 作用

  2. 出现在方法上:表示当前方法会在控制器方法执行前先执行。

  3. 出现在参数上:获取指定的数据给参数赋值。

  4. 应用场景:当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。

  5. 运行流程:

    1. 执行@ModelAttribute注解修饰的方法:从数据库中取出对象,把对象放到model/map当中
    2. SpringMVC从model/map取出对象,把表单的请求参数给该对象的对应属性
    3. springMVC把上述对象传入目标方法的参数

    注意:在@ModelAttribute修饰的方法中,放入到Map时的键和目标方法的参数类型的第一个字符小写的字符串一致

修饰方法有返回值
/**     
* 作用在方法,先执行
* 有返回值,方法控制器获取的值就有修饰方法返回的值
*/    
@ModelAttribute    
public User showUser(String name) {        
    System.out.println("showUser执行了...");        
    // 模拟从数据库中查询对象        
    User user = new User();        
    user.setName("哈哈");        
    user.setPassword("123");        
    user.setMoney(100d);        
    return user;    }
/**     
* 修改用户的方法     
*/    
@RequestMapping(path="/updateUser")    
public String updateUser(User user) {        
    System.out.println(user);        
    return "success";    }
修饰方法无返回值
 /**     
 * 作用在方法,先执行
 * 无返回值会将值存到map中,方法控制器使用注解会从map中取
 */    
@ModelAttribute    
public void showUser(String name,Map<String, User> map) {      
    System.out.println("showUser执行了...");   
    // 模拟从数据库中查询对象      
    User user = new User();      
    user.setName("哈哈");     
    user.setPassword("123");      
    user.setMoney(100d);       
    map.put("abc", user);    }        
/**     
* 修改用户的方法 
*/
@RequestMapping(path="/updateUser")    
public String updateUser(@ModelAttribute(value="abc") User user) {        System.out.println(user);        
 return "success";    }

SessionAttributes注解 (存到session域中)

  1. 作用:用于多次执行控制器方法间的参数共享
  2. 属性
    1. value:指定存入属性的名称
    2. types:指定类型,存入属性
@Controller 
@RequestMapping(path="/user") 
@SessionAttributes(value= {"username","password","age"},types={String.class})        
// 把数据存入到session域对象中 
public class HelloController {        
    /**     
    * 向session中存入值      
    */    
    @RequestMapping(path="/save")    
    public String save(Model model) {   
        //将数据存储到model中,底层实际上是存储到了request域中
        System.out.println("向session域中保存数据");       
        model.addAttribute("username", "root");     
        model.addAttribute("password", "123");     
        model.addAttribute("age", 20);   
        User user = new User("tom",11);
        model.addAttribute("user",user);
        return "success";    }
/**     
* 从session中获取值  
*/    
    @RequestMapping(path="/find")    
    public String find(ModelMap modelMap) {      
        //ModelMap是model的实现类,能够获取存储在model中的值
        String username = (String) modelMap.get("username");   
        String password = (String) modelMap.get("password");    
        Integer age = (Integer) modelMap.get("age");   
        System.out.println(username + " : "+password +" : "+age);     
        return "success";    } 
/**     
* 清除值    
*/ 
    @RequestMapping(path="/delete")
    public String delete(SessionStatus status) {
        //SessionStatus会话状态,将会话完成,即删除session域中的值,
        status.setComplete();       
        return "success";    }
}

响应数据和结果视图

Model,ModelAndView

底层实际上是存储到了request域中

Map

map.put()方法也会存入到request域中

返回值分类

  1. 返回字符串:根据视图解析器为物理视图的地址。

  2. 返回值是void :

    1. 可使用 request 转向页面
    2. 也可以通过 response 页面重定向
    3. 也可以通过 response 指定响应结果
    @RequestMapping(value="/initAdd")    
    public void initAdd(HttpServletRequest request,HttpServletResponse response) throws Exception {        
        System.out.println("请求转发或者重定向");        
        // 请求转发        
         request.getRequestDispatcher("/WEB-INF/pages/add.jsp").forward(request, response);     
        // 重定向        
        response.sendRedirect(request.getContextPath()+"/add2.jsp");
        response.setCharacterEncoding("UTF-8");    
        response.setContentType("text/html;charset=UTF-8");                
        // 直接响应数据        
        response.getWriter().print("你好");       
        return;   
    }
    
  3. 返回值是ModelAndView对象 :类似返回字符串,调用视图解析器跳转到具体的JSP视图

    /**     
    * 返回ModelAndView对象     
    * 可以传入视图的名称(即跳转的页面),还可以传入对象。
    */
    @RequestMapping(value="/findAll")    
    public ModelAndView findAll() throws Exception {       
        ModelAndView mv = new ModelAndView(); 
        // 跳转到list.jsp的页面   
        mv.setViewName("list");
        // 模拟从数据库中查询所有的用户信息        
        List<User> users = new ArrayList<>();       
        User user1 = new User();     
        user1.setUsername("张三");    
        user1.setPassword("123"); 
        // 添加对象       
        mv.addObject("users", users);
        return mv;    } 
    
    也可以ModelAndView作为参数,SpringMVC会自动创建
        public ModelAndView findAll(ModelAndView modelAndView){
        modelAndView.setViewName("list");
    }
    
  4. 返回值是字符串,参数是model:用于携带数据

@RequestMapping("/quick4")
    public String sayHello4(Model model){
        System.out.println("Hello SpringMVC!!");
        model.addAttribute("username","zhaowu");
        return "success";
    }
  1. 使用@ResponseBody回写字符串
@RequestMapping("/quick5")
@ResponseBody
public String sayHello4(){    
        return "hello success";
    }

SpringMVC框架提供的转发和重定向

  1. forward请求转发

     @RequestMapping("/delete")    
    public String delete() throws Exception {     
        System.out.println("delete方法执行了...");      
         return "forward:/WEB-INF/pages/success.jsp";      
    }
    
  2. redirect重定向

    @RequestMapping("/count")    
    public String count() throws Exception {       
        System.out.println("count方法执行了..."); 
        //不需要写项目名request.getContextPath(),底层已经写好了
        return "redirect:/add.jsp";     
    }
    

ResponseBody响应json数据

  1. 第一种方式:开启mvc注解驱动,导入jar包,使用@ResponseBody,直接返回对象,回写json数据

    @RequestMapping("/quick")
    @ResponseBody
    public User count() throws Exception {       
        User user = new User();
        user.setName("zhangsan");
        return user;     
    }
    
  • DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而 不能被使用。解决问题就是需要配置静态资源不进行拦截,

    <!-- 设置静态资源不过滤
        1. location元素表示webapp目录下的包下的所有文件
        2. mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b 
    -->  
    <mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->   
    <mvc:resources location="/images/" mapping="/images/**"/>  <!-- 图片 -->  
    <mvc:resources location="/js/" mapping="/js/**"/>  <!-- javascript -->
    
    也可以使用,效果一样
    <mvc:default-servlet-handler></mvc:default-servlet-handler>
    
  • 使用@RequestBody获取请求体数据

    //使用Ajax需要提前导入jquery的js文件
    // 页面加载       
    $(function(){      
        // 绑定点击事件      
        $("#btn").click(function(){         
            $.ajax({             
                url:"user/testJson",        
                contentType:"application/json;charset=UTF-8",
                data:'{"addressName":"aa","addressNum":100}',         
                dataType:"json",              
                type:"post",       
                success:function(data){          
                    alert(data);             
                    alert(data.addressName);       
                }        
            });     
        }); 
    });
    /*
    获取请求体数据
    */
    @RequestMapping("/testJson")    
    public void testJson(@RequestBody String body) {    
        System.out.println(body);    }
    
  • json字符串和JavaBean对象互相转换的过程中,需要使用jackson的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注解把json的字符串自动转换成JavaBean的对象

    @RequestMapping("/testJson")    
    public void testJson(@RequestBody Address address) {       
    System.out.println(address);    }
    
  • 使用@ResponseBody注解把JavaBean对象自动转换成json字符串,直接响应 ,前提开启了mvc注解驱动

    //ajax的回调函数
    success:function(data){           
    alert(data);                  
    alert(data.addressName);       
    }
    
     @RequestMapping("/testJson")   
    public @ResponseBody Address testJson(@RequestBody Address address) {
        System.out.println(address);   
        address.setAddressName("上海");       
        return address;    }
    

SpringMVC实现文件上传

SpringMVC传统方式文件上传(省去了解析request域获取上传文件项的过程,直接获得文件项)

  1. 导入文件上传的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>
    
  2. 编写文件上传的JSP页面

    • SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的 name属性名称相同

    文件上传

    选择文件:
  3. 配置文件解析器对象

    <!-- 在springMVC.xml中配置文件解析器对象,要求id名称必须是multipartResolver -->   
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    
        <!--配置文件上传大小为10M-->
        <property name="maxUploadSize" value="10485760"/>  
    </bean>
    
  4. 编写文件上传的方法

    /**     
    * SpringMVC方式的文件上传     
    */    
    @RequestMapping(value="/fileupload2")   
    public String fileupload2(HttpServletRequest request,MultipartFile upload) throws Exception {
        System.out.println("SpringMVC方式的文件上传...");        
        // 先获取到要上传的文件目录        
        String path = request.getSession().getServletContext().getRealPath("/uploads");      
        // 创建File对象,一会向该路径下上传文件     
        File file = new File(path);      
        // 判断路径是否存在,如果不存在,创建该路径     
        if(!file.exists()) {       
            file.mkdirs();        
        }       
        // 获取到上传文件的名称   
        String filename = upload.getOriginalFilename();  
        //创建随机序列号
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();    
        // 把文件的名称唯一化    
        filename = uuid+"_"+filename;    
        // 上传文件     
        upload.transferTo(new File(file,filename));     
        return "success";   
    }
    

SpringMVC跨服务器方式文件上传

bug1:403错误
    原因:tomcat权限不够
    改为:修改tomcat的web.xml
    <init-param>
    <param-name>readonly</param-name>
    <param-value>false</param-value>
    </init-param>
    位置:<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    
bug2:409错误
    原因:没有该文件夹
    改为:在部署的目录中创建该文件夹
        E:\Java\springMVC_day02_image\target\springMVC_day02_image\uploads
  1. 搭建图片服务器

  2. 导入开发需要的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>
    
  3. 编写文件上传的JSP页面

  4. 编写控制器

    @RequestMapping(value="/fileupload3")
    public String fileupload3(MultipartFile upload) throws Exception {
        System.out.println("SpringMVC跨服务器方式的文件上传...");                
        // 定义图片服务器的请求路径        
        String path = "http://localhost:9090/day02_springmvc5_02image/uploads/";                
        // 获取到上传文件的名称      
        String filename = upload.getOriginalFilename();     
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();    
        // 把文件的名称唯一化   
        filename = uuid+"_"+filename;     
        // 向图片服务器上传文件           
        // 创建客户端对象  
        Client client = Client.create();      
        // 连接图片服务器  
        WebResource webResource = client.resource(path+filename);   
        // 上传文件   
        webResource.put(upload.getBytes());     
        return "success";    }
    

SpringMVC的异常处理

  • 异常处理思路 :Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理

  • 前提:程序的异常必须抓并抛自己定义的异常

  • 步骤(简单异常处理器):

    遇到异常,只能跳转到指定的页面。不能增加其他逻辑

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
            <property name="defaultErrorView" value="error"></property><!--没有匹配到的异常跳转到这个,error,因为配置了视图解析器,所以直接输入error即可跳转error.jsp-->
            <property name="exceptionMappings">
                <map>
                    <entry key="java.lang.ClassCastException" value="error2"></entry>
                    <entry key="com.jm.MyException" value="error3"></entry>
                </map>
            </property>
    </bean>
    
  • 步骤(自定义异常):

    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{
          /**     * 跳转到具体的错误页面的方法     
          ex:程序执行时抛出的异常(前提:程序的异常必须抓并抛自己定义的异常)
          */   
          public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) {    
              ex.printStackTrace();     
              SysException e = null;      
              // 获取到异常对象      
              if(ex instanceof SysException) {
                  //是自己定义的异常类对象
                  e = (SysException) ex;    
              }else {         
                  //不是自己定义的异常
                  e = new SysException("请联系管理员");   
              }     
              ModelAndView mv = new ModelAndView();    
              // 存入错误的提示信息
              mv.addObject("message", e.getMessage());     
              // 跳转的Jsp页面
              mv.setViewName("error");      
              return mv;    }
      }
      
    3. 配置异常处理器

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

SpringMVC框架中的拦截器

概述:用于对处理器进行预处理和后处理的技术

拦截器和过滤器的功能比较类似,有区别

  1. 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
  2. 拦截器是SpringMVC框架独有的。
  3. 过滤器配置了/*,可以拦截任何资源。
  4. 拦截器只会对控制器中的方法进行拦截。

想要自定义拦截器,需要实现HandlerInterceptor接口

步骤:

  1. 创建拦截器类,实现接口(接口内部已经实现了方法,需要自己重载)

    public class MyInterceptor1 implements HandlerInterceptor{
        /**     
        * controller方法执行前,进行拦截的方法     
        * return true放行     
        * return false拦截     
        * 可以使用转发或者重定向直接跳转到指定的页面。     
        */    
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {       
            System.out.println("拦截器执行了...");      
            return true;    }
    }
    
  2. 在springmvc.xml中配置拦截器类

    <!-- 配置拦截器 -->   
    <mvc:interceptors>      
        <mvc:interceptor>       
            <!-- 哪些方法进行拦截 -->       
            <mvc:mapping path="/user/*"/>     
            <!-- 哪些方法不进行拦截             <mvc:exclude-mapping path=""/>            -->            <!-- 注册拦截器对象 -->       
            <bean class="cn.itcast.demo1.MyInterceptor1"/>    
        </mvc:interceptor> 
        <!--第二个拦截器也是要全部配置mvc:interceptor,且拦截顺序按配置的顺序执行,12方法21-->
    </mvc:interceptors>
    

HandlerInterceptor接口中的方法

preHandle方法:控制器方法执行前拦截

  1. 可以使用request或者response跳转到指定的页面
  2. return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
  3. return false不放行,不会执行controller中的方法。

postHandle方法是controller方法执行后拦截

  1. 可以使用request或者response跳转到指定的页面
  2. 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示,但输出控制台的仍然会执行。
  3. 参数ModelAndView可以将参数修改

afterCompletion方法是在页面加载后执行

  1. request或者response不能再跳转页面了

文章作者: 小苏
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小苏 !
评论
  目录