SpringMVC(2)- 注解式开发

134 阅读8分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

目录

一.使用SpringMVC框架的开发步骤

1.环境搭建 

 2.请求流程

二.SpringMVC框架的基本应用

1.controller类如何接收dispatcher转发的请求

(0)带有注解的方法的规范

(1)注解在controller类中的具体的方法上

(2)注解在controller类上

(3)GET和POST请求方式的注解

2.提交数据的五种方式

(1)方式1:散提交数据

(2)方式2:对象封装提交

(3)方式3:动态占位符提交

 (4)方式4:映射名称不一致

(5)方式5:手工提交数据

3.处理中文乱码

4.controller类的方法的返回值

(1)无返回值void

(2)String返回值

(3)返回基本数据类型

(4)返回对象类型

(5)ModelAndView

5.SpringMVC的四种跳转方式

(1)请求转发至页面(默认)

(2)请求转发至控制器

(3)重定向至页面

(4) 重定向至控制器

6.数据的传递

(1)SpringMVC默认支持的参数类型

(2)参数传递演示

三.注解驱动


一.使用SpringMVC框架的开发步骤

1.环境搭建

Step1:创建maven工程

Step2:创建web项目

Step3:集成tomcat服务器

Step4:修改pom.xml配置文件

框架就是上依赖 上配置

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>Pro1</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>Pro1 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
<!--    springMVC依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.19</version>
    </dependency>
<!--    servlet依赖-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>

  </dependencies>

  <build>
    <resources>
        <resource>
          <directory>src/main/java</directory>
          <includes>
            <include>**/*.xml</include>
            <include>**/*.properties</include>
          </includes>
        </resource>
       <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
       </resource>
    </resources>
  </build>
</project>

 Step5:创建SpringMVC核心配置文件

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-4.2.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--    添加包扫描-->
    <context:component-scan base-package="controller"/>
<!--    添加视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--        配置前缀-->
        <property name="prefix" value="/admin/"></property>
<!--        配置后缀-->
        <property name="suffix" value=".jsp"></property>
    </bean>
<!--    将访问的请求去掉后缀-->
    <mvc:annotation-driven>
        <mvc:path-matching suffix-pattern="true" />
    </mvc:annotation-driven>
</beans>

Step6:修改web.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
<!--    注册SpringMVC的框架,就是配置DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--        读取SpringMVC核心配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
<!--        DispatcherServlet拦截的请求,只接收*.action的请求-->
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
</web-app>

​编辑

 2.请求流程

1.页面请求先经过web.xml文件查看是否有SpringMVC框架,所以要在web.xml中配置dispatcherServlet的信息,就相当于声明了这个servlet。指明这个servlet接收的请求的类型

2.dispatcherServlet这个类也有很多初始化信息需要配置,所以SpringMVC核心配置文件中配置dispatcherServlet后,要在web.xml中加载信息。

3.初始化的信息包括要告诉dispatcher转发请求的目标对象,也就是具体转发给哪个controller类,所以要先用包扫描去创建这些类。

4.当controller类处理完请求后,还要经过dispatcher处理,则需要指明需要转发的资源,所以要标明前后缀。

二.SpringMVC框架的基本应用

1.controller类如何接收dispatcher转发的请求

由简到繁的方式来介绍controller类的注解方式。

注意controller下的类要有@Controller注解。

(0)带有注解的方法的规范

  • 访问权限是public
  • 方法返回值任意,以前的doGet和doPost只能是void
  • 方法名称任意 不用叫doGet或者doPost
  • 方法可以没有参数,如果有可以是任意类型
  • 要使用@RequestMapping注解来声明一个访问的路径(名称)

(1)注解在controller类中的具体的方法上

<a href="${pageContext.request.contextPath}/demo.action">注解在方法上</a>

@Controller //spring的注解,交给spring去创建对象
public class Action {
    @RequestMapping(value = "/demo")
    public String demo(){
        System.out.println("访问服务器get");
        return "main";//可以跳到/admin/main.jsp页面上去
    }
}

通过@RequestMapping代替了之前的@WebServlet注解。

如果没有在SpringMVC下配置下面代码,则value的值需要加上后缀名。

    <mvc:annotation-driven>
        <mvc:path-matching suffix-pattern="true" />
    </mvc:annotation-driven>

(2)注解在controller类上

<a href="${pageContext.request.contextPath}/user/demo.action">注解在方法上</a>

@Controller //spring的注解,交给spring去创建对象
@RequestMapping("/user")
public class Action {
    @RequestMapping(value = "/demo")
    public String demo(){
        System.out.println("访问服务器get");
        return "main";//可以跳到/admin/main.jsp页面上去
    }
}

注解到类上相当于在资源上增加了一级目录或包名。如果两个类中的方法上的@RequestMapping的值相同,转发器便不知道将请求转发给哪个controller类,此时可以在类上加注解加以区别。

(3)GET和POST请求方式的注解

 请求路径相同,而请求方法不同,也可以区分具体要请求的方法

<form action="${pageContext.request.contextPath}/user/demo.action" method="get">
    <input type="submit" value="get提交">
</form>

<form action="${pageContext.request.contextPath}/user/demo.action" method="post">
    <input type="submit" value="post提交">
</form>

@Controller //spring的注解,交给spring去创建对象
@RequestMapping("/user")
public class Action {
@RequestMapping(value = "/demo",method = RequestMethod.GET)
    public String demo(){
        System.out.println("访问服务器get");
        return "main";//可以跳到/admin/main.jsp页面上去
    }
    @RequestMapping(value = "/demo",method = RequestMethod.POST)
    public String demo2(){
        System.out.println("访问服务器post");
        return "main";//可以跳到/admin/main.jsp页面上去
    }
}

请求的路径名相同,但是请求方式不同,也看作是请求不同的资源。

2.提交数据的五种方式

(1)方式1: 散提交数据

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h2>方式1</h2>
<form action="${pageContext.request.contextPath}/Para1.action">
    <input type="text" name="myname">
    <input type="text" name="age">
    <input type="submit" value="参数提交">
</form>
</body>
</html>

@Controller
public class Para {
    @RequestMapping("/Para1")
    public String para1(String myname,int age){
        System.out.println("myname:"+myname+",age:"+age);
        return "main";
    }
}

1.要求请求参数的name值要和controller类的方法中的参数名相同

2.不需要关心方法中参数的转换问题,SpringMVC会进行类型自动转换

(2)方式2: 对象封装提交

<h2>方式2</h2>
<form action="${pageContext.request.contextPath}/Para2.action">
    <input type="text" name="myname">
    <input type="text" name="age">
    <input type="submit" value="参数提交">
</form>

    @RequestMapping("/Para2")
    public String para2(User user){
        System.out.println("myname:"+user.getMyname()+",age:"+user.getAge());
        return "main";
    }

1.需要创建User实体类,并且实体类的属性名要和请求参数的name值相同,就可以自动创建对象。

2.实体类要有set和get方法

public class User {
    private String myname;
    private int age;

    public String getMyname() {
        return myname;
    }

    public void setMyname(String myname) {
        this.myname = myname;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

(3)方式3: 动态占位符提交

<h2>方式3</h2>
<a href="${pageContext.request.contextPath}/Para3/张三/22.action">方式三提交</a>

    @RequestMapping("/Para3/{myname}/{age}")
    public String para3(@PathVariable("myname") String name,@PathVariable("age") int age){
        System.out.println("myname:"+name+",age:"+age);
        return "main";
    }

方式3常用于链接方式的请求。

@PathVariable先从myname这个请求参数取值,再注入到name上。

也可以只写@PathVaribale,默认这个注解里的值和上方大括号里的相同,引用时形参名字要写myname。

@RequestMapping中的大括号中的参数名可以随意取,但这个名字要么和@PathVariable的值相同,要么和形参名字相同(当不写@PathVariable的值时)。

(4)方式4: 映射名称不一致

<h2>方式4</h2>
<form action="${pageContext.request.contextPath}/Para4.action">
    <input type="text" name="myname">
    <input type="text" name="age">
    <input type="submit" value="参数提交">
</form>

    @RequestMapping("/Para4")
    public String para4(@RequestParam("myname") String uname,@RequestParam("age") int uage){
        System.out.println("myname:"+uname+",age:"+uage);
        return "main";
    }

处理请求参数的name值和方法中的参数名不相同的情况。

注解@RequestParam先从myname这个请求参数中取值,再将值注入到uname上。

(5)方式5: 手工提交数据

<h2>方式5</h2>
<form action="${pageContext.request.contextPath}/Para5.action">
    <input type="text" name="myname">
    <input type="text" name="age">
    <input type="submit" value="参数提交">
</form>

    @RequestMapping("/Para5")
    public String para5(HttpServletRequest request){
        String myname = request.getParameter("myname");
        int age = Integer.parseInt(request.getParameter("age"));
        System.out.println("myname:"+myname+",age:"+age);
        return "main";
    }

这种方法就是跟之前获取参数的方式相同了。

3.处理中文乱码

当post请求时,传过来的请求参数如果是中文的话会乱码。

可以在web.xml中配置过滤器设置编码格式来处理乱码问题

<!--    中文编码过滤器-->
    <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>

4.controller类的方法的返回值

(1)无返回值void

一般用于Ajax请求

(2)String返回值

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

(3)返回基本数据类型

用户Ajax请求

返回学生集合案例

Step1:添加Jackson依赖

<!--    添加Jackson依赖-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.8</version>
    </dependency>
    <dependency>

Step2:在webapp目录下创建js目录,添加jQuery函数库

Step3:前端发送Ajax请求

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="js/jquery-3.4.1.min.js"></script>
</head>
<body>
<a href="javascript:showStu()">访问服务器返回学生集合</a>
<div id="mydiv">
    等待服务器返回数据
</div>
<script type="text/javascript">
    function showStu() {
        //使用Jquery封装的Ajax方法发送请求
        $.ajax({
            url:"${pageContext.request.contextPath}/list.action",
            type:"get",
            dataType:"json",
            success: function (stuList){
                 var s = "";
                 $.each(stuList,function (i,stu){
                    //stu.name其实在调用getName方法,所以这个stu.name要和实体类属性相同
                    s+=stu.name + "---" + stu.age + "<br>";
                 });
                 //回显数据
                 $("#mydiv").html(s);
            }
        });
    }
</script>
</body>
</html>

Step4:后端处理Ajax请求

@Controller
public class Ajax {
    @RequestMapping("/list")
    @ResponseBody //解析Ajax请求,还要在springmvc.xml中添加注解驱动
    public List<Student> getList(){
        List<Student> list = new ArrayList<>();
        list.add(new Student("张三",18));
        list.add(new Student("李四",19));
        return list;//SpringMVC框架负责将集合转为json数组
    }
}

Step5:添加注解驱动

    <mvc:annotation-driven></mvc:annotation-driven>

注意:

1.Ajax请求要加@ResponseBody注解

2.注解驱动内部还有其他属性可以更改,可以用下面代码代替上面注解驱动代码

    <mvc:annotation-driven>
        <mvc:path-matching suffix-pattern="true" />
    </mvc:annotation-driven>

  1. 在处理Ajax请求时,不需要视图解析器,Ajax请求哪来的回哪去

(4)返回对象类型

返回json格式的对象,自动将对象或集合转为json,使用的是Jackson工具进行转换,必须要添加Jackson依赖,一般用于Ajax请求

(5)ModelAndView

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

5.SpringMVC的四种跳转方式

(1)请求转发至页面(默认)

直接返回资源名的字符串,视图解析器会自动添加前缀和后缀

(2)请求转发至控制器

返回forward:/资源名的字符串,如"forward:/user.action"。视图解析器便不会添加前缀和后缀了。

(3)重定向至页面

返回redirect:/资源名的字符串,如"redirect:/index.jsp",视图解析器便不会添加前缀和后缀了。

(4) 重定向至控制器

 返回redirect:/资源名的字符串,如"redirect:/user.action",视图解析器便不会添加前缀和后缀了。

  

<a href="${pageContext.request.contextPath}/jump1">请求转发页面</a>
<a href="${pageContext.request.contextPath}/jump2">请求转发控制器</a>
<a href="${pageContext.request.contextPath}/jump3">重定向页面</a>
<a href="${pageContext.request.contextPath}/jump4">重定向控制器</a>

@Controller
public class Jump {
    @RequestMapping("/jump1")
    public String  jump1(){
        System.out.println("请求转发页面");
        return "main";
    }
    @RequestMapping("/jump2")
    public String jump2(){
        System.out.println("请求转发控制器");
        return "forward:/other";
    }
    @RequestMapping("/jump3")
    public String jump3(){
        System.out.println("重定向页面");
        return "redirect:/admin/main.jsp";
    }
    @RequestMapping("/jump4")
    public String jump4(){
        System.out.println("重定向控制器");
        return "redirect:/other";
    }
}

@Controller
public class JumoToMe {
    @RequestMapping("/other")
    public String  other(){
        System.out.println("跳到了other");
        return "main";
    }
}

6.数据的传递

(1)SpringMVC默认支持的参数类型

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • Model
  • Map
  • ModelMap

1.Map,Model,ModelMap和request都一样,都使用请求作用域进行数据传递,所以服务器的跳转必须是请求转发。

2.这些参数可以直接写到方法的形参中,dispatcher就会将其对象转发进来。

3.只有请求转发才能携带数据。

(2)参数传递演示

    @RequestMapping("/data")
    public String data(HttpServletRequest request,
                       HttpServletResponse response,
                       HttpSession session,
                       Model model,
                       Map map,
                       ModelMap modelMap){
        int a = 10;
        request.setAttribute("requesta",a);
        session.setAttribute("sessiona",a);
        model.addAttribute("modela",a);
        map.put("mapa",a);
        modelMap.addAttribute("modelMapa",a);
        return "main";
    }
}

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
main...
${requesta}<br>
${sessiona}<br>
${mapa}<br>
${modela}<br>
${modelMapa}<br>
${param.name}<br>
</body>
</html>

 param代表整个请求中的参数集合,name是controller的上一个页面传递过来的参数

<a href="${pageContext.request.contextPath}/data?name=w">data</a>

三.注解驱动

​编辑

mvc:annotation-driven/标签

在springmvc.xml中写了这行代码后,SpringMVC框架会自动注册两个bean,分别是DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter,是springmvc为@controller分发请求所必须的。

注解驱动还提供其他功能

​编辑

走一遍流程图

第一个小帮手HandlerMapping去解析请求路径,可以找到访问资源的名称(去掉后缀和前缀)

第二个小帮手 HandlerAdapter根据资源的名称去创建控制器的对象,生成的方式可以是bean标签,可以是注解方式。拿到对象的时候,里面的数据都注入成功了,比如方法的参数,对象的属性等

最后的Handler就是生成的对象,也就是controller对象

接下来这个对象还会去调用业务逻辑层,数据访问层

再将数据返回到controller对象,再返回给dispatcher要转发的路径,又调用下一个小帮手,ViewResolver(当返回的是字符串的时候并且没有加forward和redirect),添加前缀和后缀

再返回到dispatcher,带着放在作用域中的数据,判断是转发到哪个页面,将数据渲染到页面上,一并交给客户端