1. 1. 关于SpringMVC
    1. 1.1. 优点
    2. 1.2. 基本开发步骤
    3. 1.3. 如何实操
    4. 1.4. @RequestMapping
    5. 1.5. 数据提交方式的优化
      1. 1.5.0.1. 散提数据
      2. 1.5.0.2. 对象封装
      3. 1.5.0.3. 动态占位符提交
      4. 1.5.0.4. 映射参数名称不一致
      5. 1.5.0.5. 手工提取数据
  2. 1.6. 如何解决中文乱码的问题
  3. 1.7. servlet方法的返回值
    1. 1.7.0.1. String
    2. 1.7.0.2. Object
    3. 1.7.0.3. void
    4. 1.7.0.4. 基本数据类型
    5. 1.7.0.5. ModelAndView
  • 1.8. 完成ajax请求访问服务器,返回学生集合
  • 1.9. SpringMVC的四种跳转方式
    1. 1.9.0.1. SpringMVC默认的参数类型
  • 1.10. 页面上日期的显示
    1. 1.10.0.1. 日期提交
    2. 1.10.0.2. 日期的显示处理
  • 1.11. SpringMVC执行分析
    1. 1.11.0.1. 关于annotation-drivern
    2. 1.11.0.2. 为什么资源放在WEB-INF目录下
  • 1.12. 拦截器开发与应用
    1. 1.12.0.1. 处理流程:
    2. 1.12.0.2. 实现方式
    3. 1.12.0.3. 实现步骤
  • 关于SpringMVC

    基于MVC开发模式的框架,用来优化控制器,也是spring家族的一员,同样具备IoC和AOP特性

    优点

    • 轻量级,基于MVC架构
    • 易上手,易理解
    • 具备IoC和AOP
    • 完全基于注解开发

    基本开发步骤

    1. 新建项目,选择webapp模板
    2. 修改目录,添加缺失的test,java,resources(*2),并修改目录属性
    3. 修改pom.xml,添加springMVC依赖,添加servlet的依赖
    4. 添加springmvc.xml配置文件,指定扫描包,添加视图解析器
    5. 删除web.xml(原有版本过低),新建web.xml
    6. 在web.xml中注册springMVC框架(请求基于servlet)
    7. 删除index.jsp,新建,发送请求给服务器
    8. 开发控制器(servlet),它是一个普通的类

    如何实操

    • 访问权限public
    • 返回值任意
    • 名称任意
    • 参数任意,可以为空
    • 使用@RequeseMapping来声明访问路径(可以分级)

    @RequestMapping

    • 可以加在方法或类上,指定该方法(或类)的访问路径
      1
      2
      3
      4
      5
      6
      7
      8
      @RequestMapping("/sr")
      public class qwq{
      @RequeseMapping("/firstController")
      public String req(){
      return "success";
      }
      }
      //这样即可通过{path}/sr/firstController访问该类了
    • 可以约定请求提交方式
      1
      2
      3
      4
      5
      6
      7
      8
      9
      @RequestMapping("/sr")
      public class qwq{
      @RequeseMapping(value="/firstController",method=RequestMethod.GET)
      public String req(){
      return "success";
      }
      //method留空默认接受所有类型请求
      }

    数据提交方式的优化

    散提数据

    1
    2
    3
    4
    <form action="${pageContext.request.contextPath}/try">
    姓名:<input name="name">
    <input type="submit">
    </form>
    1
    2
    3
    4
    5
    6
    7
    public class qwq{
    @RequeseMapping(value="/try",method=RequestMethod.GET)
    public String req(String name){
    return "success";
    }
    //若想传输数据,使形参名和form名一致即可,可以自动进行类型转换
    }

    对象封装

    在提交请求中保证请求参数的名称与实体类中成员变量一致则可以自动提交数据,自动类型转换,自动封装数据到对象中

    1
    2
    3
    4
    5
    <form action="${pageContext.request.contextPath}/try">
    姓名:<input name="name">
    年龄:<input name="age">
    <input type="submit">
    </form>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class Person{
    //一定要有set/get/无参构造/全参构造
    private String name;
    private int age;
    Person(){

    }
    Person(String name,int age){
    this.name=name;
    this.age=age;
    }
    /*get和set就省略了*/
    }
    public class qwq{
    @RequeseMapping(value="/try",method=RequestMethod.GET)
    public String req(Person p){
    return "success";
    }
    //若想传输数据,使形参名和form名一致即可,可以自动进行类型转换
    //注意POST会乱码,之后会讲如何解决
    }

    动态占位符提交

    仅限于超链接或地址栏直接提交,一杠一值

    1
    <a href="${pageContext.request.contextPath}/try/张三/25">点我!</a>
    1
    2
    3
    4
    5
    6
    7
    public class qwq{
    @RequeseMapping(value="/try/{uname}/{uage}",method=RequestMethod.GET)
    public String req(@PathVariable("uname") String name,@PathVariable("uage") int age){
    return "success";
    }
    //使用大括号和@PathVariable,从路径中取值
    //若path和形参名称一致可以省略括号

    映射参数名称不一致

    提交的参数名和形参不一致,使用@RequestParam解析

    1
    2
    3
    4
    <form action="${pageContext.request.contextPath}/try">
    姓名:<input name="uname">
    <input type="submit">
    </form>
    1
    2
    3
    4
    5
    6
    7
    public class qwq{
    @RequeseMapping(value="/try",method=RequestMethod.GET)
    public String req(@RequestParam("uname") String name){
    return "success";
    }
    //使用@RequestParam注解来解决名称不一致的问题,从请求参数中取
    }

    手工提取数据

    1
    2
    3
    4
    <form action="${pageContext.request.contextPath}/try">
    姓名:<input name="uname">
    <input type="submit">
    </form>
    1
    2
    3
    4
    5
    6
    7
    8
    public class qwq{
    @RequeseMapping(value="/try",method=RequestMethod.GET)
    public String req(HttpServletRequest request){
    String name=request.getParameter("uname");
    return "success";
    }
    //使用@RequestParam注解来解决名称不一致的问题,从请求参数中取
    }

    如何解决中文乱码的问题

    配置过滤器->web.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!--建议放在所有的配置之前-->
    <filter>
    <filter-name>encode</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>
    <init-param>
    <param-name>forceRequestEncoding</param-name>
    <param-value>true</param-value>
    </init-param>
    <init-param>
    <param-name>forceResponseEncoding</param-name>
    <param-value>true</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>encode</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

    servlet方法的返回值

    String

    客户端资源的地址,自动拼接前缀后缀,可以屏蔽自动拼接字符串,可以指定返回路径

    Object

    返回json格式的对象,自动将对象或集合转为json,依赖jackson工具,一般用于ajax请求

    void

    一般用于ajax请求

    基本数据类型

    用于ajax请求

    ModelAndView

    返回数据和试图对象,现在用的很少

    完成ajax请求访问服务器,返回学生集合

    1. 添加jackson依赖
      1
      2
      3
      4
      5
      <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.8</version>
      </dependency>
    2. 在webapp下新建js目录,添加jQuery函数库
    3. 在index.jsp上导入函数库
    4. 在action上添加注解@ResponseBody,用来处理ajax请求
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      <script src="js/jquery-3.3.1.js"></script>
      <!--↑head↓body-->
      <a href="javascript:showStu()">请求学生集合</a>
      <div id="mydiv">等待返回数据</div>
      <script type="text/javascript">
      function showStu(){
      $.ajax({
      url:"${pageContext.request.contextPath}/list",
      type:"get",
      dataType:"json",
      success:function(stuList){
      var s="";
      $.each(stuList,function(i,stu)){
      s+=stu.name+"----"+stu.age+"<br>";
      }}
      //回显在div上
      $("#mydiv").html(s);
      })
      }
      </script>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      //省略类的定义
      @RequestMapping("/list")
      @ResponseBody
      public List<Student> list(){
      List<Student> list=new ArrayList<>();
      //添加数据...
      return list;
      //SpringMVC会协助将集合转为json数组
      }
    5. 在springMVC.xml文件中添加注解驱动<mvc:annotationdriven/>,用于解析@ResponseBody注解

    SpringMVC的四种跳转方式

    实质:[请求转发,重定向]到[页面,action]
    请求转发和重定向最大的不同:请求转发地址栏不变,重定向地址栏改变

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public class qwq{
    @RequeseMapping(value="/forwardToJsp",method=RequestMethod.GET)
    public String req1(){
    return "success";
    //请求转发到.../success.jsp
    }
    @RequeseMapping(value="/forwardToAction",method=RequestMethod.GET)
    public String req2(){
    return "forward:success.action";
    //请求转发到另一个方法中
    //字符串具有forward关键字时不会自动拼接前缀和后缀
    }
    @RequeseMapping(value="/redirectToJsp",method=RequestMethod.GET)
    public String req1(){
    return "success";
    //请求重定向到.../success.jsp
    }
    @RequeseMapping(value="/redirectToAction",method=RequestMethod.GET)
    public String req2(){
    return "redirect:success.action";
    //请求重定向到另一个方法中
    //字符串具有redirect关键字时不会自动拼接前缀和后缀
    }
    }

    SpringMVC默认的参数类型

    1. HttpServletRequest
    2. HttpServletResponse
    3. HttpSession
    4. Model
    5. Map
    6. ModelMap
      直接拿来即可用,作用域:Request,所以只有forward时数据仍然存在,如果使用redirect,则需要使用session保存数据

    页面上日期的显示

    日期提交

    • 单个日期处理
      使用注解@DateTimeFormat(),必须搭配springMVC配置文件中<mvc:annontationdriven\>共同使用
      1
      2
      3
      4
      <form action="${pageContext.request.contextPath}/try">
      姓名:<input type="date" name="ddate">
      <input type="submit">
      </form>
      1
      2
      3
      4
      5
      6
      @RequeseMapping(value="/try")
      public String req2(@DateTimeFormat(pattern="yyyy-MM-Ddd HH:ss")Date ddate){
      //注意,如果不使用@DateTimeFormat,无法成功注入
      return "success";
      }
      }
    • 类中全局日期处理
      上文方式的处理方法,如果需要注入多个日期,需要分别填写@DateTimeFormat,因此我们可以尝试复用日期格式
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd");
      @InitBinder
      public void init(WebDataBinder dataBinder){
      dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sf,true));
      }
      @RequeseMapping(value="/try")
      public String req2(Date ddate){
      return "success";
      }
      }

    日期的显示处理

    可以直接格式化日期并返回String
    如果想在页面上自定义样式,需要使用JSTL,步骤如下

    1. 添加依赖
      1
      2
      3
      4
      5
      6
      7
      <!-- https://mvnrepository.com/artifact/jakarta.servlet.jsp.jstl/jakarta.servlet.jsp.jstl-api -->
      <dependency>
      <groupId>jakarta.servlet.jsp.jstl</groupId>
      <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
      <version>3.0.0</version>
      </dependency>
      <!--spring6.0以上用jakarta-->
    2. 在页面上导入标签库
      1
      2
      <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
      <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
    3. 使用标签显示数据
      1
      <fmt:formatDate value="${date} pattern="yyyy-MM-dd"></fmt:formatDate>

    SpringMVC执行分析

    关于annotation-drivern

    会自动注册以下两个bean

    • DefaultAnnotationHandlerMapping
      解析服务器端资源地址,即地址映射器
    • AnnotationMethodHandlerAdapter
      构建对象,即处理器适配器

    为什么资源放在WEB-INF目录下

    该目录下资源对外不可直接访问

    拦截器开发与应用

    针对请求和响应进行的额外的处理,可以添加预处理、后处理和最终处理

    处理流程:

    ruquest->preHandle()->处理器->postHandle()->afterCompletion()->response

    • preHandle():在请求被处理时进行操作
    • postHandle():在请求被处理,但结果没渲染之前进行操作
    • afterCompletion():在请求响应结束后进行善后

    实现方式

    • 继承父类HandlerInterceptorAdapter
    • 实现接口HandlerInterceptor,推荐使用该方式

    实现步骤

    1. 在springMVC.xml中注册
      1
      2
      3
      4
      5
      6
      7
      <mvc:interceptors>
      <mvc:interceptor>
      <mvc:mapping path="要拦截的请求地址"></mvc:mapping>
      <mvc:exclude-mapping path="要放行的请求"></mvc:exclude-mapping>
      </mvc:interceptor>
      <!--如果配置多个拦截器,可以构成拦截器链-->
      </mvc:interceptors>
    2. 开发拦截器
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      public class MyIntercrptor implements HandlerInterceptor{
      @override
      boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler)throws Exception{
      return false;
      }
      /**
      * 关于返回值类型
      * boolean->true则继续执行,false则止步于此
      */
      @override
      void postHandle(HttpServletRequest request, HttpServletResponse response,Object handler)throws Exception{
      }
      @override
      boolean afterCompletion(HttpServletRequest request, HttpServletResponse response,Object handler)throws Exception{
      }
      /**
      * Object handler
      *
      */
      }

    51