SpringMVC学习

SpringMVC入门

基本步骤

  1. 创建WEB工程,引入开发的jar包。Maven坐标如下

     
     
         5.0.2.RELEASE
     
    
     
         
             org.springframework
             spring-context
             ${spring.version}
         
         
             org.springframework
             spring-web
             ${spring.version}
         
         
             org.springframework
             spring-webmvc
             ${spring.version}
         
         
             javax.servlet
             servlet-api
             2.5
             provided
         
         
             javax.servlet.jsp
             jsp-api
             2.0
             provided
         
     
  2. 配置核心控制器(配置DispatcherServlet)

    在web.xml配置文件中核心控制器DispatcherServlet

     
     
         dispatcherServlet
         org.springframework.web.servlet.DispatcherServlet
         
         
             contextConfigLocation
             classpath:springmvc.xml
         
         
         1
     
     
         dispatcherServlet
         /
     
  3. 编写springmvc.xml的配置文件

     
     
    
         
         
    
         
         
             
             
         
    
         
     
  4. 编写index.jsp和HelloController控制器类

    1. index.jsp

       
           

      入门案例

      入门案例
    2. HelloController

       @Controller
       public class HelloController {
           @RequestMapping(path="/hello")
           public String sayHello() {
               System.out.println("Hello SpringMVC!!");
               return "success";
           }
       }
  5. 在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面
  6. 启动Tomcat服务器,进行测试

执行过程分析

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

RequestMapping注解

  1. RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
  2. RequestMapping注解可以作用在方法和类上
    1. 作用在类上:第一级的访问目录
    2. 作用在方法上:第二级的访问目录
    3. 细节:路径可以不编写 / 表示应用的根目录开始
    4. 细节:${ pageContext.request.contextPath }也可以省略不写,但是路径上不能写 /
  3. RequestMapping的属性
    1. path 指定请求路径的url
    2. value value属性和path属性是一样的
    3. mthod 指定该方法的请求方式
    4. params 指定限制请求参数的条件
    5. headers 发送的请求中必须包含的请求头

请求参数的绑定

  1. 请求参数的绑定说明
    1. 绑定机制
      1. 表单提交的数据都是k=v格式的 username=haha&password=123
      2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
      3. 要求:提交表单的name和参数的名称是相同的
    2. 支持的数据类型
      1. 基本数据类型和字符串类型
      2. 实体类型(JavaBean)
      3. 集合数据类型(List、map集合等)
  2. 基本数据类型和字符串类型
    1. 提交表单的name和参数的名称是相同的
    2. 区分大小写
  3. 实体类型(JavaBean)
    1. 提交表单的name和JavaBean中的属性名称需要一致
    2. 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:address.name
  4. 给集合属性数据封装
    1. JSP页面编写方式:list[0].属性
  5. 请求参数中文乱码的解决
    1. 在web.xml中配置Spring提供的过滤器类

       
       
           characterEncodingFilter
           org.springframework.web.filter.CharacterEncodingFilter
           
           
               encoding
               UTF-8
           
       
       
           characterEncodingFilter
           /*
       
  6. 自定义类型转换器
    1. 表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明Spring框架内部会默认进行数据类型转换。
    2. 如果想自定义数据类型转换,可以实现Converter的接口
      1. 自定义类型转换器

         /**
          * 把字符串转换成日期的转换器
          */
         public class StringToDateConverter implements Converter{
             /**
              * 进行类型转换的方法
              */
             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配置文件中编写配置

         
         
             
                 
                     
                 
             
         
        
         
         
  7. 在控制器中使用原生的ServletAPI对象
    1. 只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象

常用的注解

  1. RequestParam注解
    1. 作用:把请求中的指定名称的参数传递给控制器中的形参赋值
    2. 属性
      1. value:请求参数中的名称
      2. required:请求参数中是否必须提供此参数,默认值是true,必须提供
    3. 代码如下

       @RequestMapping(path="/hello")
       public String sayHello(@RequestParam(value="username",required=false)String name) {
           System.out.println("aaaa");
           System.out.println(name);
           return "success";
       }
  2. RequestBody注解
    1. 作用:用于获取请求体的内容(注意:get方法不可以)
    2. 属性
      1. required:是否必须有请求体,默认值是true
    3. 代码如下

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

       @RequestMapping(path="/hello/{id}")
       public String sayHello(@PathVariable(value="id") String id) {
           System.out.println(id);
           return "success";
       }
  4. RequestHeader注解
    1. 作用:获取指定请求头的值
    2. 属性
      1. value:请求头的名称
    3. 代码如下

       @RequestMapping(path="/hello")
       public String sayHello(@RequestHeader(value="Accept") String header) {
           System.out.println(header);
           return "success";
       }
  5. CookieValue注解
    1. 作用:用于获取指定cookie的名称的值
    2. 属性
      1. value:cookie的名称
    3. 代码

       @RequestMapping(path="/hello")
       public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) {
           System.out.println(cookieValue);
           return "success";
       }
  6. ModelAttribute注解
    1. 作用
      1. 出现在方法上:表示当前方法会在控制器方法执行前线执行。
      2. 出现在参数上:获取指定的数据给参数赋值。
    2. 应用场景
      1. 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
    3. 具体的代码
      1. 修饰的方法有返回值

         /**
          * 作用在方法,先执行
          * @param name
          * @return
          */
         @ModelAttribute
         public User showUser(String name) {
             System.out.println("showUser执行了...");
             // 模拟从数据库中查询对象
             User user = new User();
             user.setName("哈哈");
             user.setPassword("123");
             user.setMoney(100d);
             return user;
         } 
         /**
          * 修改用户的方法
          * @param cookieValue
          * @return
          */
         @RequestMapping(path="/updateUser")
         public String updateUser(User user) {
             System.out.println(user);
             return "success";
         }
      2. 修饰的方法没有返回值

         /**
          * 作用在方法,先执行
          * @param name
          * @return
          */
         @ModelAttribute
         public void showUser(String name,Map map) {
             System.out.println("showUser执行了...");
             // 模拟从数据库中查询对象
             User user = new User();
             user.setName("哈哈");
             user.setPassword("123");
             user.setMoney(100d);
             map.put("abc", user);
         } 
         /**
          * 修改用户的方法
          * @param cookieValue
          * @return
          */
         @RequestMapping(path="/updateUser")
         public String updateUser(@ModelAttribute(value="abc") User user) {
             System.out.println(user);
             return "success";
         }
  7. SessionAttributes注解
    1. 作用:用于多次执行控制器方法间的参数共享
    2. 属性
      1. value:指定存入属性的名称
    3. 代码如下

       @Controller
       @RequestMapping(path="/user")
       @SessionAttributes(value= {"username","password","age"},types= {String.class,Integer.class}) // 把数据存入到session域对象中
       public class HelloController {
      
           /**
            * 向session中存入值
            * @return
            */
           @RequestMapping(path="/save")
           public String save(Model model) {
               System.out.println("向session域中保存数据");
               model.addAttribute("username", "root");
               model.addAttribute("password", "123");
               model.addAttribute("age", 20);
               return "success";
           } 
      
           /**
            * 从session中获取值
            * @return
            */
           @RequestMapping(path="/find")
           public String find(ModelMap modelMap) {
               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";
           } 
      
           /**
            * 清除值
            * @return
            */
           @RequestMapping(path="/delete")
           public String delete(SessionStatus status) {
               status.setComplete();
               return "success";
           }
       }

响应数据和结果视图

返回值分类

  1. 返回字符串

    Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。

         @RequestMapping(value="/hello")
         public String sayHello() {
             System.out.println("Hello SpringMVC!!");
             // 跳转到XX页面
             return "success";
         }
  2. 返回值是void
    1. 如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
      1. 默认会跳转到@RequestMapping(value="/initUpdate") initUpdate的页面。
    2. 可以使用请求转发或者重定向跳转到指定的页面

       @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对象
    1. ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
    2. 具体的代码如下

       @RequestMapping(value="/findAll")
       public ModelAndView findAll() throws Exception {
           ModelAndView mv = new ModelAndView();
           // 跳转到list.jsp的页面
           mv.setViewName("list");
           // 模拟从数据库中查询所有的用户信息
           List users = new ArrayList<>();
           User user1 = new User();
           user1.setUsername("张三");
           user1.setPassword("123");
           User user2 = new User();
           user2.setUsername("赵四");
           user2.setPassword("456");
           users.add(user1);
           users.add(user2);
           // 添加对象
           mv.addObject("users", users);
           return mv;
       }

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

  1. forward请求转发
    1. controller方法返回String类型,想进行请求转发也可以编写成

       @RequestMapping("/delete")
       public String delete() throws Exception {
           System.out.println("delete方法执行了...");
           // return "forward:/WEB-INF/pages/success.jsp";
           return "forward:/user/findAll";
       }
  2. redirect重定向
    1. controller方法返回String类型,想进行重定向也可以编写成

       @RequestMapping("/count")
       public String count() throws Exception {
           System.out.println("count方法执行了...");
           return "redirect:/add.jsp";
           // return "redirect:/user/findAll";
       }

ResponseBody响应json数据

  1. DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
    1. mvc:resources标签配置不过滤
      1. location元素表示webapp目录下的包下的所有文件
      2. mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b

         
          
          
          
  2. 使用@RequestBody获取请求体数据

     $(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);
     }
  3. 使用@RequestBody注解把json的字符串转换成JavaBean的对象

     @RequestMapping("/testJson")
     public void testJson(@RequestBody Address address){}
  4. 使用@ResponseBody注解把JavaBean对象转换成json字符串,直接响应
    1. 要求方法需要返回JavaBean的对象

       @RequestMapping("/testJson")
       public @ResponseBody Address testJson(@RequestBody Address address) {
           System.out.println(address);
           address.setAddressName("上海");
           return address;
       }
  5. json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包。Maven依赖坐标如下:

     
         com.fasterxml.jackson.core
         jackson-databind
         2.9.0
     
     
         com.fasterxml.jackson.core
         jackson-core
         2.9.0
     
     
         com.fasterxml.jackson.core
         jackson-annotations
         2.9.0
     

SpringMVC实现文件上传

文件上传的回顾

  1. 导入文件上传的jar包

     
         commons-fileupload
         commons-fileupload
         1.3.1
     
     
         commons-io
         commons-io
         2.4
     
  2. 编写文件上传的JSP页面

     
    选择文件:
  3. 编写文件上传的Controller控制器

     @RequestMapping(value="/fileupload")
     public String fileupload(HttpServletRequest request) throws Exception {
         // 先获取到要上传的文件目录
         String path = request.getSession().getServletContext().getRealPath("/uploads");
         // 创建File对象,一会向该路径下上传文件
         File file = new File(path);
         // 判断路径是否存在,如果不存在,创建该路径
         if(!file.exists()) {
             file.mkdirs();
         } 
         // 创建磁盘文件项工厂
         DiskFileItemFactory factory = new DiskFileItemFactory();
         ServletFileUpload fileUpload = new ServletFileUpload(factory);
         // 解析request对象
         List list = fileUpload.parseRequest(request);
         // 遍历
         for (FileItem fileItem : list) {
             // 判断文件项是普通字段,还是上传的文件
             if(fileItem.isFormField()) {
             }else {
                 // 上传文件项
                 // 获取到上传文件的名称
                 String filename = fileItem.getName();
                 // 上传文件
                 fileItem.write(new File(file, filename));
                 // 删除临时文件
                 fileItem.delete();
             }
         } 
         return "success";
     }

SpringMVC传统方式文件上传

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

     @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";
     }
  3. 配置文件解析器对象

     
     
         
     

SpringMVC跨服务器方式文件上传

  1. 导入开发需要的jar包

     
         com.sun.jersey
         jersey-core
         1.18.1
     
     
         com.sun.jersey
         jersey-client
         1.18.1
     
  2. 编写文件上传的JSP页面
  3. 编写控制器

     @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找异常处理器进行异常的处理

SpringMVC的异常处理

  1. 自定义异常类

     public class SysException extends Exception{
         private static final long serialVersionUID = 4055945147128016300L;
         // 异常提示信息
         private String message;
         public String getMessage() {
             return message;
         } 
         public void setMessage(String message) {
             this.message = message;
         } 
         public SysException(String message) {
             this.message = message;
         }
     }
  2. 自定义异常处理器

     public class SysExceptionResolver implements HandlerExceptionResolver{
         /**
          * 跳转到具体的错误页面的方法
          */
         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. 配置异常处理器

     
     

SpringMVC框架中的拦截器

拦截器的概述

  1. SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
  2. 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链
    中的拦截器会按着定义的顺序执行。
  3. 拦截器和过滤器的功能比较类似,有区别
    1. 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
    2. 拦截器是SpringMVC框架独有的。
    3. 过滤器配置了/*,可以拦截任何资源。
    4. 拦截器只会对控制器中的方法进行拦截。
  4. 拦截器也是AOP思想的一种实现方式
  5. 想要自定义拦截器,需要实现HandlerInterceptor接口。

自定义拦截器步骤

  1. 创建类,实现HandlerInterceptor接口,重写需要的方法

     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中配置拦截器类

     
     
         
             
             
             
             
             
         
     

HandlerInterceptor接口中的方法

  1. preHandle方法是controller方法执行前拦截的方法
    1. 可以使用request或者response跳转到指定的页面
    2. return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
    3. return false不放行,不会执行controller中的方法。
  2. postHandle是controller方法执行后执行的方法,在JSP视图执行前。
    1. 可以使用request或者response跳转到指定的页面
    2. 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
  3. postHandle方法是在JSP执行后执行
    1. request或者response不能再跳转页面了

配置多个拦截器

  1. 再编写一个拦截器的类
  2. 配置2个拦截器

     
     
         
             
             
             
             
             
         
         
             
             
             
             
         
     

你可能感兴趣的:(SpringMVC学习)