Spring MVC入门(一)

2019-07-05  本文已影响0人  月哥说了算

一、关于三层架构和 MVC

三层架构

我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,几乎全都是基于 B/S 架构的开发。那么在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。
三层架构中,每一层各司其职,接下来我们就说说每层都负责哪些方面:

表现层:

也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web 层,web 需要接收 http 请求,完成 http 响应。
表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
表现层的设计一般都使用 MVC 模型。(MVC 是表现层的设计模型,和其他层没有关系)

业务层:

也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web 层依赖业务层,但是业务层不依赖 web 层。业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。(也就是我们说的,事务应该放到业务层来控制)

持久层:

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

MVC 模型

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

Model(模型):

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

View(视图):

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

Controller(控制器):

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

二、SpringMVC 概述

SpringMVC 是什么

SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。
SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。

SpringMVC 在三层架构的位置

Snipaste_2019-07-05_20-14-45.png

SpringMVC 的优势

1、清晰的角色划分:
前端控制器(DispatcherServlet)
请求到处理器映射(HandlerMapping)
处理器适配器(HandlerAdapter)
视图解析器(ViewResolver)
处理器或页面控制器(Controller)
验证器( Validator)
命令对象(Command 请求参数绑定到的对象就叫命令对象)
表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。 3、由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。 4、和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。 5、可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。 6、可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。 7、功能强大的数据验证、格式化、绑定机制。 8、利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。 9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
10、强大的 JSP 标签库,使 JSP 编写更容易。
………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配
置支持等等。

三、SpringMVC入门

第一步:导入所需Maven标注

<!--spring家族核心包-->
<dependency>
 <groupId>org.springframework</groupId> 
<artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version>
</dependency> 
<!--Spring webmvc:包含SpringMVC框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、 Tiles、Velocity、XSLT相关类。-->
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-webmvc</artifactId> 
<version>5.0.2.RELEASE</version>
</dependency> 
<!--servlet支持包-->
<dependency>
 <groupId>javax.servlet</groupId>
 <artifactId>servlet-api</artifactId>
 <version>2.5</version>
</dependency>

第二步:配置xml文件

<?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"
       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">
<!--开启包扫描-->
    <context:component-scan base-package="com.gzy.web"></context:component-scan>
    <!--
        定制化了一下 视图解析器 不然话 每次写很长的路径 配置前缀后后缀
    -->
    <bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

第三步:配置web.xml文件

注意: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_3_1.xsd"
         version="3.1">
<!-- 配置 spring mvc 的核心控制器 -->
    <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 的对象的创建时间点:应用加载时创建。
取值只能是非 0 正整数,表示启动顺序 --> 
           <load-on-startup>1</load-on-startup>
    </servlet>
<!--应用范围-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
<!--利用拦截器设置编码-->
    <filter>
        <filter-name>encodingFilter</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>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

第四步:编写控制器并使用注解配置

package com.gzy.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.text.SimpleDateFormat;
import java.util.Date;
//测试:发送日期时间到页面
@Controller
public class UserController {
    @RequestMapping("/test1")
    public ModelAndView test1(ModelAndView modelAndView){
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd  hh:mm:ss");
        String format = simpleDateFormat.format(date);
        modelAndView.addObject("cc",format);
        //springmvc.xml不配置前缀后后缀
        //modelAndView.setViewName("/WEB-INF/pages/user/hello.jsp");
        //springmvc.xml配置前缀后后缀后改为
        modelAndView.setViewName("user/hello");
        return modelAndView;
    }
}

hello.jsp页面代码

<%--
  Created by IntelliJ IDEA.
  User: gzy
  Date: 2019/7/5
  Time: 21:05
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>测试</title>
</head>
<body>
<div style="text-align: center;color: red;margin: 200px auto;">
    当前时间是:<br/>
    ${cc}
</div>
</body>
</html>

效果:

Snipaste_2019-07-05_21-52-28.png

涉及的组件

DispatcherServlet:

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

HandlerMapping:

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

Handler:

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

HandlAdapter:处理器适配器

Snipaste_2019-07-06_12-56-07.png

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>替代注解处理器和适配器的配置。
它就相当于在 xml 中配置了:

<!-- 上面的标签相当于 如下配置-->
<!-- Begin -->
<!-- HandlerMapping -->
 <bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerM
apping">
</bean> 
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
</bean>
<!-- HandlerAdapter -->
 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
</bean> 
<bean
class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
</bean>
 <bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter">
</bean>
<!-- HadnlerExceptionResolvers -->
 <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExcept
ionResolver">
</bean><beanclass="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver">
</bean> 
<bean
class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean>
<!-- End -->

注意:
一般开发中,我们都需要写上此标签.
明确:
我们只需要编写处理具体业务的控制器以及视图。


演示参数绑定

演示使用的实体类

user

package com.gzy.domain;

import java.util.Date;

public class User {
    private int id;
    private String username;
    private String desc;
    private boolean vip;
    private Date birthday;
      ......................
    }

QueryVo

package com.gzy.domain;

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

public class QueryVo {
    private User user;
    private int age;
    private String[] hobbies;
    private List<User> users;
    private Map faxinren;
       ................
}

jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<fieldset>
    <legend>演示1 演示参数绑定 简单类型</legend>
    <form action="/mvc/user/test2" method="post">
        id:<input type="text" name="xid"><br>
        用户名:<input type="text" name="username"><br>
        描述:<input type="text" name="desc"><br>
        是否是vip:<input type="text" name="vip"><br>
        <input type="submit" value="点我提交">

    </form>
</fieldset>
<fieldset>
    <legend>演示2 演示参数绑定 复合对象类型</legend>
    <form action="/mvc/user/test3" method="post">
        id:<input type="text" name="user.id"><br>
        用户名:<input type="text" name="user.username"><br>
        描述:<input type="text" name="user.desc"><br>
        是否是vip:<input type="text" name="user.vip"><br>
        生日:<input type="date" name="user.birthday"><br>
        年龄:<input type="text" name="age"><br>
        爱好:
        <input type="checkbox" name="hobbies" value="抽烟">抽烟
        <input type="checkbox" name="hobbies" value="喝酒">喝酒
        <input type="checkbox" name="hobbies" value="烫头">烫头
        <br>
        收信人列表:<br>
        收信人1:<input type="text" name="users[0].id">
        <input type="text" name="users[0].username">
        <br>
        收信人2:<input type="text" name="users[1].id">
        <input type="text" name="users[1].username">
        <br>
        收信人3:<input type="text" name="users[2].id">
        <input type="text" name="users[2].username">
        <br>
        发信人:
        <input type="text" name="faxinren['name']">
        <input type="text" name="faxinren['tel']">
        <input type="text" name="faxinren['address']">
        <input type="submit" value="点我提交">

    </form>
</fieldset>
</body>
</html>

Handler代码(只做简单演示,代码简陋,勿喷)

package com.gzy.web.controller;

import com.gzy.domain.QueryVo;
import com.gzy.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/test1")
    public ModelAndView test1(ModelAndView modelAndView){
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd  hh:mm:ss");
        String format = simpleDateFormat.format(date);
        modelAndView.addObject("cc",format);
        //springmvc.xml不配置前缀后后缀
        //modelAndView.setViewName("/WEB-INF/pages/user/hello.jsp");
        //springmvc.xml配置前缀后后缀后改为
        modelAndView.setViewName("user/hello");
        return modelAndView;
    }

    /**
     * RequestParam  强制告诉springmvc 该位置参数名字 是啥
     * 可以给默认值
     * 主要的作用 协商的作用
     * 跟前端开发协商  参数名字叫啥
     * @RequestMapping(value = "/test2",method = RequestMethod.POST)
     * method代表请求方式,value请求路径
     */
    @RequestMapping(value = "/test2",method = RequestMethod.POST)
    public ModelAndView test2(ModelAndView modelAndView, @RequestParam(name ="xid",defaultValue = "123") int id, String username, String desc, boolean vip){
        System.out.println(id);
        System.out.println(username);
        System.out.println(desc);
        System.out.println(vip);
        return modelAndView;
    }
//演示参数绑定 复合对象类型,简单对象包含特殊类型(这里是Date)
    @RequestMapping(value = "/test3",method = RequestMethod.POST)
    public ModelAndView test3(ModelAndView modelAndView, QueryVo queryVo){
        System.out.println(queryVo);
        return modelAndView;
    }
    //获取请求头的值
    @RequestMapping(value="/test4",method = RequestMethod.GET)
    public ModelAndView test10(ModelAndView modelAndView,@RequestHeader(value = "user-agent") String useragent){
        System.out.println(useragent);
        return  modelAndView;

    }
    //获取HttpServletRequest,cookie参数
    @RequestMapping(value="/test5",method = RequestMethod.GET)
    public ModelAndView test11(ModelAndView modelAndView, HttpServletRequest request, @CookieValue(value = "JSESSIONID") String useragent){
        String host = request.getHeader("Host");
        System.out.println(host);
        System.out.println(useragent);
        return  modelAndView;

    }
}

springmvc.xml配置

<?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.gzy.web"></context:component-scan>
    <!--
       主动强制性告诉springmvc  处理映射器采用 RequestMappingHandlerMapping来实现

       历史原因导致的:
           1.很久以前  3版本 4 版本的时候 已经人们写了RequestMappingHandlerMapping  但是考虑向下兼容性
           2.不仅仅是用来指明默认 处理映射器 还有其他的作用
   -->
    <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

    <!--
       写了一个注册转换服务器类  这个类 负责将很多的转换器 注册给我springmvc框架
   -->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.gzy.web.conterver.MyDateConverter"></bean>
            </set>
        </property>
    </bean>
    <!--
        定制化了一下 视图解析器 不然话 每次写很长的路径 配置前缀后后缀
    -->

    <bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

转换服务器类(这里将Date特殊类型转换为String)

package com.gzy.web.conterver;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
//这是一个类型转换类
public class MyDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        Date date=null;
        //现在一个 2019-07-02
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            date = simpleDateFormat.parse(s);
        } catch (ParseException e) {
            date=new Date();
        }
        return date;
    }
}

上一篇下一篇

猜你喜欢

热点阅读