SpringMVC入门教程

一、基本概念

1.三层架构

  我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,几乎全都是基于 B/S 架构的开发。那么在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。

  • 表现层:

  也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web 层,web 需要接收 http 请求,完成 http 响应。

  表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
  表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
  表现层的设计一般都使用 MVC 模型。(MVC 是表现层的设计模型,和其他层没有关系)

  • 业务层:

  也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web 层依赖业务层,但是业务层不依赖 web 层。

  业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。(也就是我们说的,事务应该放到业务层来控制)

  • 持久层:

  也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进行曾删改查的。

2.MVC模式

  MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职:

  • Model(模型):

  通常指的就是我们的数据模型,也就是实体类。作用一般情况下用于封装数据。

  • View(视图):

  通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。通常视图是依据模型数据创建的。

  • Controller(控制器):

  是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。

  这里举个例子:我们要保存一个用户的信息,该用户信息中包含了姓名,性别,年龄等等。这时候表单输入要求年龄必须是 1~100 之间的整数。姓名和性别不能为空。并且把数据填充到模型之中。此时除了 js 的校验之外,服务器端也应该有数据准确性的校验,那么校验就是控制器的该做的。当校验失败后,由控制器负责把错误页面展示给使用者。如果校验成功,也是控制器负责把数据填充到模型,并且调用业务层实现完整的业务需求。

3.SpringMVC

  SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。

  SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。

在这里插入图片描述

二、入门案例

1.需求分析

  • 两个jsp页面: 首先需要一个页面index.jsp,它是一个欢迎界面,界面中应该有一个超链接1。点击超链接,可以跳转到success.jsp页面,表示跳转成功。

  • 一个类: 用来获取jsp页面的请求,并执行页面的跳转。

2.搭建开发环境(IDEA)

(1)创建项目和相应的模块

  新建项目,选择maven模块,勾选create from archetype,并且选择下面的webapp。

  填写好group id等信息后,点击下一步。

  这一步需要选择maven仓库了,然后需要在下面添加一个属性(避免从网上下载一些插件,项目创建会比较慢)。点击加号后,添加键值对,再点击next:

在这里插入图片描述

  进入下一个页面后,再点击完成,就创建好了。

(2)完善目录结构

  在main下面创建目录java。把java目录标记为source root。
  在java下面新建包com.wang,这是用来放java代码的。
  在main下面创建目录resources,用来放配置文件的。把resources目录标记为resource root。
  在WEB-INF下面创建pages目录,用来放前端jsp页面。

(3)引入依赖

  打开pom.xml,配置如下(只需要配置<properties>和<dependencies>):

<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>
    <!--版本锁定-->
    <spring.version>5.2.6.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.2</version>
      <scope>provided</scope>
    </dependency>

  </dependencies>

(4)配置前端控制器servlet

  打开web.xml,配置如下:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--加载springMVC.xml用的-->
    <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>
</web-app>

(5)配置spring

  在resources下面新建一个xml configuration file > spring config,然后命名为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: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.xsd
        http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
    <!--开启注解扫描-->
    <context:component-scan base-package="com.wang"/>

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

    <!--开启注解springMVC框架的支持-->
    <mvc:annotation-driven/>

</beans>

(6)部署服务

  点击右上角的add configuration,然后在左边选择Tomcat > Local,左边有几个tab页,Server的配置如下(根据自己的情况自行调整):

在这里插入图片描述

  然后部署deployment,点击+号,点击artifact,然后选择springMVC:war,冒号前面是你的模块名,点击确定。再点击应用和确定,就算是部署好了。

(7)代码部分

  • index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <h3>入门项目</h3>
    <!--这里的hello表示会调用标注为/hello的方法-->
    <a href="hello">Hello SpringMVC</a>
</body>
</html>
  • 编写java类:

  在com.wang下面创建包controller,然后在Controller下面新建类HelloMVC,它是一个控制器类:

package com.wang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

//控制器类
@Controller
public class HelloMVC {
    
    

    @RequestMapping(path = "/hello")
    public String sayHello(){
    
    
        System.out.println("Hello SpringMVC!");
        return "success";
    }
}
  • success.jsp:

  在pages下面新建success.jsp,作为从index.jsp跳转过去的页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <h3>入门成功了</h3>
</body>
</html>

(8)启动服务器

  点击右上角的绿色的三角,表示启动Tomcat服务器,启动成功后会自动在浏览器打开链接,这页面其实就是index.jsp:

在这里插入图片描述

  点击超链接后,会跳转到success.jsp:

在这里插入图片描述

  入门案例结束。

三、入门教程的流程说明

1.启动服务器,加载一些配置文件

  • 先是加载web.xml文件:由于我们配置了 启动服务器第一个创建servlet对象,因此先创建了servlet对象。

  • 然后会加载springmvc.xml文件也就是spring的配置文件:

先是开启注解扫描,那么之后就能创建controller对象。
由于也开启了注解springMVC框架的支持,接着就会使controller中的@RequestMapping生效,通过url能访问到相应的方法。

2.发送请求,后台进行处理

  • 现在我们通过url访问到了index.jsp页面,我们看这个代码:

在这里插入图片描述

  一旦我们点击index.jsp页面上的链接,就发起了请求,Servlet作为前端控制器,能接收到来自前端的请求。

  • servlet作为指挥中心,就会根据href=hello调用controller中标注URL为/hello的方法,执行完后,返回了“success”字符串。
  • 由于我们在springMVC.xml中配置了视图解析器,servlet又会指挥视图解析器帮助跳转到success.jsp页面,将视图响应给客户端。

  可以看出来,servlet非常重要,它是整个系统运作的指挥中心。

四、组件介绍

  SpringMVC框架底层是基于组件方式执行流程:

在这里插入图片描述

  • DispatcherServlet:前端控制器

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

  • HandlerMapping:处理器映射器

  HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

  • Handler:处理器

  它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。

  • HandlAdapter:处理器适配器

  通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

  • View Resolver:视图解析器

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

  • View:视图

  SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

  • <mvc:annotation-driven>说明:

  在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。使 用 <mvc:annotation-driven> 自动加载 RequestMappingHandlerMapping (处理映射器) 和RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用<mvc:annotation-driven>替代注解处理器和适配器的配置。

五、请求参数的绑定

1.机制说明

  表单提交的数据都是k=v格式的:比如username=haha&password=123。

  SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的。提交表单的name和参数的名称是相同的。

  支持的数据类型:

  • 基本数据类型和字符串类型
  • 实体类型
  • 集合数据类型(List、map集合等)。

2.基本数据类型和字符串类型

  • params.jsp:

  在webapp下面创建params.jsp页面,注意,jsp页面如果放在WEB-INF下面,将不能在浏览器中直接通过jsp文件名访问该页面,所以我们将params.jsp放在WEB-INF外面,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <!--请求参数绑定-->
    <a href="params/testParam?username=tracy">请求参数绑定</a>
</body>
</html>

  • controller类:

  在controller包下创建ParamController类:

package com.wang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/params")
public class ParamController {
    
    
    @RequestMapping("/testParam")
    public String testParam(String username){
    
    // 提交表单的name和参数的名称是相同的,都是username
        System.out.println("执行了testParam");
        System.out.println("username="+username);
        return "success";
    }

}

  • 运行服务:

  运行Tomcat,然后按如下方式输入链接:

在这里插入图片描述

  然后点击链接,页面会跳转至success.jsp,并且IDEA的控制台也打印了来自前端的参数username,参数绑定成功:

在这里插入图片描述

3.实体类型

  很多时候单个参数的传递并不能满足需要,所以这里介绍实体类型的参数绑定。

  提交表单的name和JavaBean中的属性名称需要一致。

  • params.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <!--请求参数绑定:基本类型和String类型-->
    <!--<a href="params/testParam?username=tracy">请求参数绑定</a>-->

    <!--请求参数绑定:实体类型-->
    <form action="params/saveUser" method="post">
        姓名:<input type="text" name="username"/> <br/>
        密码:<input type="text" name="password"/> <br/>
        金额:<input type="text" name="money"/> <br/>
        <input type="submit" name="提交"/>
    </form>
</body>
</html>

  • User实体类:

  在com.wang下面新建entity包,再在entity下创建User类:

package com.wang.entity;

public class User {
    
    
    private String username;
    private String password;
    private Double money;

    @Override
    public String toString(){
    
    
        return "User:["+username+","+password+","+money+"]";
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }

    public Double getMoney() {
    
    
        return money;
    }

    public void setMoney(Double money) {
    
    
        this.money = money;
    }
}

  • controller类中方法:

  还是ParamController类:

@RequestMapping("/saveUser")
    public String saveUser(User user){
    
    
        System.out.println("执行了saveUser()");
        System.out.println(user);
        return "success";
    }
  • 运行服务:

  运行服务后,输入地址并填入相应数据:

在这里插入图片描述

  点击提交后跳转至success.jsp页面:

在这里插入图片描述

  IDEA中也打印出了相应数据,说明前端数据传到了后端:

在这里插入图片描述

  • 如果User类中的某个属性是个引用类型:

  User类如下,多了一个Address类型的属性:

package com.wang.entity;

public class User {
    
    
    private String username;
    private String password;
    private Double money;
    private Address address;

    @Override
    public String toString(){
    
    
        return "User:["+username+","+password+","+money+","+address+"]";
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }

    public Double getMoney() {
    
    
        return money;
    }

    public void setMoney(Double money) {
    
    
        this.money = money;
    }

    public Address getAddress() {
    
    
        return address;
    }

    public void setAddress(Address address) {
    
    
        this.address = address;
    }
}

package com.wang.entity;

public class Address {
    
    
    private String country;
    private String city;
    private String street;

    @Override
    public String toString(){
    
    
        return "address:"+country+"-"+city+"-"+street;
    }

    public String getCountry() {
    
    
        return country;
    }

    public void setCountry(String country) {
    
    
        this.country = country;
    }

    public String getCity() {
    
    
        return city;
    }

    public void setCity(String city) {
    
    
        this.city = city;
    }

    public String getStreet() {
    
    
        return street;
    }

    public void setStreet(String street) {
    
    
        this.street = street;
    }
}

  params.jsp修改如下,其中引用address中的属性必须要加address前缀:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <!--请求参数绑定:基本类型和String类型-->
    <!--<a href="params/testParam?username=tracy">请求参数绑定</a>-->

    <!--请求参数绑定:实体类型-->
    <form action="params/saveUser" method="post">
        姓名:<input type="text" name="username"/> <br/>
        密码:<input type="text" name="password"/> <br/>
        金额:<input type="text" name="money"/> <br/>
        国籍:<input type="text" name="address.country"/> <br/>
        城市:<input type="text" name="address.city"/> <br/>
        街道:<input type="text" name="address.street"/> <br/>
        <input type="submit" name="提交"/>
    </form>
</body>
</html>

  运行服务:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  执行成功,但乱码了,这个问题后面说。

4.集合类型

  • params.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <!--请求参数绑定:基本类型和String类型-->
    <!--<a href="params/testParam?username=tracy">请求参数绑定</a>-->

    <!--请求参数绑定:集合类型-->
    <form action="params/saveAccount" method="post">
        账户id:<input type="text" name="id"/><br/>
        <!--表明数据将存放到list的坐标0处的user对象中-->
        用户姓名:<input type="text" name="list[0].username">
        金额:<input type="text" name="list[0].money">

        <!--表明数据将存放到map的以1为key的user对象中-->
        用户姓名:<input type="text" name="map[1].username">
        金额:<input type="text" name="map[1].money">

        <input type="submit" name="提交"/>
    </form>
</body>
</html>

  • Account实体类:
package com.wang.entity;

import java.util.List;
import java.util.Map;

public class Account {
    
    
    private List<User> list;
    private Map<Integer,User> map;

    public List<User> getList() {
    
    
        return list;
    }

    public void setList(List<User> list) {
    
    
        this.list = list;
    }

    public Map<Integer, User> getMap() {
    
    
        return map;
    }

    public void setMap(Map<Integer, User> map) {
    
    
        this.map = map;
    }

    @Override
    public String toString() {
    
    
        return "Account{" +
                "list=" + list +
                ", map=" + map +
                '}';
    }
}

  • controller类中方法:

    @RequestMapping("/saveAccount")
    public String saveAcount(Account account){
    
    
        System.out.println("执行了saveAccount()方法");
        System.out.println(account);
        return "success";
    }
  • 运行服务:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

六、解决乱码问题

1.方法一:给springMVC配置过滤器

  这段配置加在web-app标签中,display-name标签后面。

<!--配置防止乱码的过滤器-->
  <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>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

2.方法二:修改tomcat配置

在这里插入图片描述

3.方法三:修改IDEA设置

  点击文件 - 设置 - 编辑器 - 文本编码:

在这里插入图片描述

  设置完后重启IDEA。

七、常用注解

1.@RequestMapping

  RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系,可以作用在方法和类上。

  RequestMapping的属性:

  • path 指定请求路径的url
  • value value属性和path属性是一样的
  • mthod 指定该方法的请求方式
  • params 指定限制请求参数的条件
  • headers 发送的请求中必须包含的请求头

2.@RequestParam

  作用:把请求中的指定名称的参数传递给控制器中的形参赋值。

  属性:

  • value:请求参数中的名称
  • required:请求参数中是否必须提供此参数,默认值是true,必须提供
@RequestMapping(path="/hello") 
public String sayHello(@RequestParam(value="username",required=false)String name) {
    
     
	System.out.println("aaaa"); 
	System.out.println(name); 
	return "success"; 
}

3.@RequestBody

  作用:用于获取请求体的内容(注意:get方法不可以)。

  属性:

  • required:是否必须有请求体,默认值是true。
@RequestMapping(path="/hello") 
public String sayHello(@RequestBody String body) {
    
     
	System.out.println("aaaa"); System.out.println(body); 
	return "success"; 
}

4.@PathVariable

  作用:用于绑定url中的占位符。例如:url中有/delete/{id},{id}就是占位符。

  属性:

  • value:指定url中的占位符名称

  Restful风格的URL:请求路径一样,可以根据不同的请求方式去执行后台的不同方法。优点是结构清晰、符合标准、易于理解、扩展方便。

<a href="user/hello/1">入门案例</a> 

@RequestMapping(path="/hello/{id}") 
public String sayHello(@PathVariable(value="id") String id) {
    
     
	System.out.println(id); 
	return "success"; 
}

5.@RequestHeader

  获取指定请求头的值,属性:

  • value:请求头的名称
@RequestMapping(path="/hello") 
public String sayHello(@RequestHeader(value="Accept") String header) {
    
     
	System.out.println(header); 
	return "success";
 }

6.@CookieValue

  用于获取指定cookie的名称的值,属性:

  • value:cookie的名称
@RequestMapping(path="/hello") 
public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) {
    
     
	System.out.println(cookieValue); 
	return "success"; 
}

7.@ModelAttribute

8. @SessionAttributes

猜你喜欢

转载自blog.csdn.net/Tracycoder/article/details/113730833