SpringMVC 框架及部署方式介绍

Java语言现在应用比较多的MVC框架有SpringMVC,Struts2两种。


首先,什么是MVC?

MVC其实就是一种软件的设计模式。在开发中并没有强制我们必须去遵循这种设计模式,但是遵循MVC模式会使我们系统层次更清晰;职责更明确;扩展性更强;耦合度降低。

一、SpringMVC 概述:

Spring 为展现层提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的 MVC 框架之一。

    •  Spring3.0 后全面超越 Struts2,成为最优秀的 MVC 框架。

    •  Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口。

    •  支持 REST 风格的 URL 请求。

    •  采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。

SpringMVC工作流程:



Spring MVC 特点:

    清晰的角色划分,每一个角色都可以由一个专门的对象来实现:

    控制器(controller)

    验证器(validator)

    命令对象(command object)

    表单对象(form object)

    模型对象(model object)

    Servlet分发器(DispatcherServlet)

    处理器映射(handler mapping)

    视图解析器(view resolver)等。

    可以非常简单的设计出干净的WEB层,和薄薄的WEB层

    使用Spring MVC可以更加简洁地开发WEB层

    天生与Spring框架集成(IOC、AOP等)

SpringMVC核心组件:


1、DispatcherServlet:前端控制器,核心

作用:接收请求,响应结果,相当于转发器,中央处理器,降低了组件之间的耦合性。

用户发送请求交给DispatcherServlet,DispatcherServlet是整个流程控制的中心,由它调用其他组件处理用户请求,分发到具体的对应Controller,从而获取到需要的业务数据Model,Model再通过DispatcherServlet传递给View完成页面呈现;DispatcherServlet的存在降低了组件的之间的耦合性。

配置DispatcherServlet:


2、HandlerMapping:处理器映射器

作用:根据请求的URL,找到对应的Handler,帮助DispatcherServlet找到对应的Controller。

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


 HandlerMapping执行流程:



3、HandlerInterceptor:Handler执行前后拦截器

HandlerInterceptor是个接口,里面包含三个方法:preHandle、postHandle、afterCompletion

分别在Handler执行前、执行中、执行完成后执行的三个方法

4、HandlerExecutionChain:HandlerMapping返回给DispatcherServlet的执行链

HandlerMapping返回给DispatcherServlet的不光有Handler,还有HandlerInterceptor

preHandle——>ControllerMethod——>postHandle——>afterCompletion

这个链如何实现的呢?使用了Java的反射机制reflection

5、HandlerAdapter:处理器适配器

作用:将各种Controller适配成DispatcherServlet可以使用的Handler,通过特定规则(HandlerAdapter要求的规则)去执行Handler

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

6、Handler:处理器(需要工程师开发)

注意:编写Handler时需要HandlerAdapter的要求去做,这样HandlerAdapter才可以正确执行Handler

Handler是继DispatcherServlet前端控制器的后台控制器,在DispatcherServlet控制下对用户请求进行处理,Handler涉及业务需求,所以需要工程师针对用户需求进行开发,最终返回业务数据

7、ModelAndView:SpringMVC中对Model的一种表示形式

SpringMVC中有Model、Map,但是SpringMVC都会将其转化为ModelAndView,Model、Map都是ModelAndView的具体表现

8、ViewResolver:视图解析器

作用:进行视图解析,根据逻辑视图名解析成真正的视图View

ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成具体的页面地址,然后对View进行渲染,将处理结果通过页面展示给用户;SpringMVC提供了很多类型View视图,包括:jstlView、freemarkerView、pdfView、jsp、html等。

9、View:视图(需要工程师开发jsp、html)

View是一个接口,实现类支持不同的类型(jsp、html、freemarker、pdf等)

SpringMVC三种部署方式:

1.SpringMVC的基本配置

使用SpringMVC开发前需要把meave依赖和Spring所依赖的jar包导进来,idea和ecilpse有所不同,自行百度吧(还可以设置成阿里云的在线依赖库,速度相对比较快些),下面我使用的是ieda

使用IDEA创建一个基于spring的Java项目:

步骤1:选择New Project,在弹出窗口中勾选spring和Web Application(此项也可以不选)。

当勾选Spring选项时,窗口下方的liraries出现load version…进度条,表示在网上检查Spring的可用版本。等待一定时间后,会显示最新可用版本,如下所示。

步骤2:选择下一步,此时会自动从互联网下载spring相关的jar包。

创建SpringMVC工程,架构如下:

重要两个配置文件为: web.xml和springmvc-config.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">
    <display-name>SpringMVC Demo</display-name>
    <jsp-config>
        <jsp-property-group>
            <url-pattern>*.jsp</url-pattern>
            <url-pattern>*.jspf</url-pattern>
            <page-encoding>UTF-8</page-encoding>
            <scripting-invalid>true</scripting-invalid>
            <include-prelude>/WEB-INF/jsp/base.jspf</include-prelude>
            <trim-directive-whitespaces>true</trim-directive-whitespaces>
            <default-content-type>text/html</default-content-type>
        </jsp-property-group>
    </jsp-config>
    <!--过滤器配置 -->
    <!--编码过滤器-->
    <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>
 
    <!--Spring MVC配置-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置初始化参数,读取spring mvc的配置文件 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/config/springmvc-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- 将所有的url访问请求配置由springmvc处理 -->
    <servlet-mapping>
 <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

打开springmvc-config.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:mvc="http://www.springframework.org/schema/mvc"
       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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
 
    <!--扫描指定的包-->
    <context:component-scan base-package="jee.course.ch10.*" />
    <!-- 配置springmvc支持注解 -->
    <mvc:annotation-driven>
        <!--解决@ResponseBody返回的字符出现乱码问题-->
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/plain;charset=UTF-8</value>
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
 
    <!-- 配置静态资源不用经过springmv的解析 -->
    <!-- **表示该文件夹及其子文件夹所有文件-->
    <mvc:resources location="/resource/" mapping="/resource/**"/>
    <mvc:resources location="/" mapping="*.html"/>
    <!-- 配置默认jsp页面的地址 -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

步骤1:在controller包中添加HelloWorldController类,该类为Spring MVC控制器类,主要参考代码如下:
package jee.course.ch10.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
import javax.servlet.http.HttpSession;
 
@Controller
public class HelloWorldController {
    //返还字符串,类似servlet的out。println()
    //演示一个简单的spring MVC应用,返回字符串
    @ResponseBody
    @RequestMapping(value="/hello")
    public String hello(){
        return  "hello";
    }
 
    //演示返回一个jsp页面传递数据
    @RequestMapping("/viewJsp")
    public  String viewJsp(Model model){
        model.addAttribute("value","i am from springmvc value");
        return  "hello";
    }
 
    //演示使用session传递参数
    @RequestMapping("/session")
    public String useSession(HttpSession session){
        session.setAttribute("msg","我是使用session使用session传递参数");
        return  "session";
    }
}
 JSP页面结构如下:

(1)测试/hello路径的访问,

return “hello”; 表示在页面中输出一个字符串hello,重点在于理解@ResponseBody,该注解表示返回一个字符串,而不是返回一个HTML页面。看函数注解。测试如下:

(2)测试http://localhost:8080/springmvc1/viewJsp, 重点理解@RequestMapping("/viewJsp")的使用,return "hello";表示跳转到hello.jsp页面。同时

public String viewJsp(Model model) 表示将model传入到控制器。其中Model为spring内置类。

model.addAttribute("value", "I am from SpringMvc Value");

表示往该页面传递一个参数,名称为value。

在hello.jsp页面中输出从控制器传递过来的参数。hello.jsp代码如下:

程序测试结果如下:

(3)测试http://localhost:8080/springmvc1/session。该方法和上一个相似,把值通过session传递到jsp页面。

同时将session作为参数传入到控制。

public String useSession(HttpSession session)

测试结果如下:

2.基于Spring MVC获取请求参数:

book.java

package jee.course.ch10.entity;

public class Book {

    String bookname;

    String author;

    double price;

    int category;

    String description;

    String press;

 

    public Book() {

    }

    @Override

    public String toString() {

        return "Book{" +

                "bookname='" + bookname + '\'' +

                ", author='" + author + '\'' +

                ", price=" + price +

                ", category=" + category +

                ", description='" + description + '\'' +

                ", press='" + press + '\'' +

                '}';

    }

    /**

     * 构造函数:@param bookname

     * 构造函数:@param author

     * 构造函数:@param price

     * 构造函数:@param category

     * 构造函数:@param picUrl

     * 构造函数:@param description

     * 构造函数:@param press

     */

    public Book(String bookname, String author, double price, int category,

                 String description, String press) {

        super();

        this.bookname = bookname;

        this.author = author;

        this.price = price;

        this.category = category;

        this.description = description;

        this.press = press;

    }

 

    public String getBookname() {

        return bookname;

    }

    public void setBookname(String bookname) {

        this.bookname = bookname;

    }

    public String getAuthor() {

        return author;

    }

    public void setAuthor(String author) {

        this.author = author;

    }

    public double getPrice() {

        return price;

    }

    public void setPrice(double price) {

        this.price = price;

    }

    public int getCategory() {

        return category;

    }

    public void setCategory(int category) {

        this.category = category;

    }

    public String getDescription() {

        return description;

    }

    public void setDescription(String description) {

        this.description = description;

    }

    public String getPress() {

        return press;

    }

    public void setPress(String press) {

        this.press = press;

    }

}

步骤1:添加BookController控制器类,该类主要演示如何获取客户端传递的参数。BookController的参考代码如下:


package jee.course.ch10.controller;

 

import jee.course.ch10.entity.Book;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.*;

 

 @Controller

 @RequestMapping("/book")

public class BookController {

     //跳转到addbook.jsp

     //限制HTTP的请求类型为get

     @RequestMapping(value = "/add",method = RequestMethod.GET)

     public String toBookForm(){

         return "addBook";

 

     }

     //演示使用pojo实体类自动填充表单数据

     //使用model传值

     @RequestMapping(value = "/add",method = RequestMethod.POST)

     public  String addBook(Book book,Model model){

         System.out.println(book);

         model.addAttribute("book",book);

         return  "viewBook";

     }

     //演示url传递参数

     //查看ID为10的图书/book/10

     @RequestMapping(value = "/{id}",produces = "text/html;charset=UTF-8")

     @ResponseBody

     public  String getBook(@PathVariable("id") Long id){

         return  "您目前查看的图书ID为:"+id;

     }

 

     //演示使用@RequParam获取参数

     @RequestMapping("/view")

     @ResponseBody

     public String viewBook(@RequestParam("id") Long id){

 

         return "您查看的图书ID为"+id;

     }

 

     //演示重定向到我另外一个控制器

     @RequestMapping(value = "toHello")

     public  String toHelloController(){

         return "redirect:/hello";

     }

}

(1)测试http://localhost:8080/springmvc1/book/add。跳转到添加图书界面。

相应的代码为:

(2)点击添加图书,后台对应的代码为:

同时跳转到viewBook.jsp页面,viewBook.jsp代码为:

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

<html>

<head>

    <title>图书信息</title>

</head>

 

<body>

<h1>图书添加成功!</h1>

<br>

<h2>图书信息</h2>

<hr>

图书名称:  ${book.bookname}

<br> 图书价格: ${book.price}

<br> 出版社: ${book.press}

<br> 类别: ${book.category}

<br>

</body>

</html>

页面结果如下:

(3)测试通过@RequestParam获取客户端提交的参数。

http://localhost:8080/springmvc1/book/view?id=100

(4)测试通过@PathVariable获取路径参数。代码为:

(5)测试重定向到另一个控制器。

说明:默认情况下控制器方法返回一个字符串值,表示返回的视图为一个jsp页面。如果要从一个控制器跳转到另一个控制器,可以使用下面方法:

在控制器的return语句字符串前面添加forward:或者redirect:。 其中forward:表示可以带数据的跳转,和request的forward相同,使用redirect:表示重定向。

return "forward:aaaa/bbbb.do";

return "redirect:aaaa/bbbb.do";

访问地址:http://localhost:8080/springmvc1/book/toHello

代码如下:

测试结果如下:

3.Spring MVC和Ajax的结合使用

步骤1:ajax.html页面代码。

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

 

</head>

<body>

<div>test</div>

<div>

    <h3>1.演示获取JSON格式的数据对象</h3>

    <button type="button" id="jsonData" onclick="getJsonBook()">

        获取JSON格式的数据对象

    </button>

</div>

<hr>

<div>

    <h3>2.演示获取JSON格式的数据对象</h3>

    <button type="button" id="delTicket" onclick="delMultiTickets()">

        使用Ajax方式删除多个票据

    </button>

</div>

 

<h2>3.演示使用Ajax提交图书数据</h2>

<hr>

<div>

    <table>

    <form id="bookForm" method="POST">

            <tr>

                <td>图书名称:</td>

                <td><input type="text" name="bookname" value="三毛流浪记"></td>

            </tr>

            <tr>

                <td>价格:</td>

                <td><input type="text" name="price" value="39.50"></td>

            </tr>

            <tr>

                <td>作者:</td>

                <td><input type="text" name="author" value="张乐平"></td>

            </tr>

            <tr>

                <td>类别:</td>

                <td><select name="category">

                    <option value="1" selected>文学</option>

                    <option value="2">计算机</option>

                    <option value="3">天文</option>

                    <option value="4">户外探险</option>

                </select>

            </tr>

            <tr>

                <td>出版社:</td>

                <td><input type="text" name="press" value="译林出版社"></td>

            </tr>

    </form>

            <tr>

                <td colspan="2">

                    <button id="#addBook" onclick="addBook()">添加 </button>

                </td>

            </tr>

        </table>

 

</div>

 

<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->

<script src="./resource/static/assets/jquery/jquery-2.1.4.min.js"></script>

<!-- Bootstrap 核心 JavaScript 文件 -->

<script src="./resource/static/assets/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<!-- 站点 自定义 函数库,主要用到serializeObject方法-->

<script src="./resource/static/js/site.js"></script>

<!-- 页面 自定义 JS -->

<script>

    //删除多个票据记录

    function delMultiTickets() {

        alert("test");

        //需要删除的票据id号

        var idList = [1, 2, 3];

        $.ajax({

            method: 'POST',  //提交的方法为POST

            url: './delTickets', //介绍数据URL路径

            data: JSON.stringify(idList),   //转换为字符串

            contentType: 'application/json',

            success: function (result) {   //成功后的方法

                alert("ajax请求成功,服务器返回消息为:" + result)

            },

            error: function () {   // ajax请求失败

                alert("ajax请求执行失败!");

            }

        })

    }

    //添加图书

    function addBook() {

        //获取表单数据并序列化为JSON对象

        var formData = $("#bookForm").serializeObject();

        alert("表单数据:" + formData);

        //提交表单

        $.ajax({

            method: 'POST',  //提交的方法为POST

            url: './ajaxAddBook', //介绍数据URL路径

            //以字符串格式提交数据

            data: JSON.stringify(formData),   //转换

            //使用同步方式提交表单,获取结果后再去执行其他代码。

            // POST方法默认使用异步方式提交表单

            async: false,

            contentType: 'application/json',

            success: function (result) {   //成功后的方法

                alert("ajax请求成功,返回消息:" + result)

            },

            error: function () {   // ajax请求失败

                alert("ajax请求执行失败!");

            }

        })

    }

 

 

    //获取图书对象的JSON格式数据

    function getJsonBook() {

        $.ajax({

            method: 'GET',  //提交的方法为POST

            url: './json_book', //介绍数据URL路径

            success: function (result) {   //成功后的方法

                //将对象转换为字符串输出

                alert("图书格式为:" + JSON.stringify(result))

            },

            error: function () {   // ajax请求失败

                alert("ajax请求执行失败!");

            }

        })

    }

 

</script>

</body>

</html>

运行界面如下

后台代码AjaxParamsController如下:

package jee.course.ch10.controller;

import jee.course.ch10.entity.Book;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestBody;

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

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

//用于演示与ajax提交数据的交互

@Controller

public class AjaxParamsController {

    //1.演示使用@RequestBody读取Ajax提交的JSON格式的数据

    //说明:读取Ajax发送过来的数组对象并转换为List<Long>对象

    @ResponseBody

    @RequestMapping(value = "/delTickets", method = RequestMethod.POST)

    public String delMultiTickets(@RequestBody List<Long> idList){

        //打印输出要删除id

        System.out.println("接收到Ajax请求.");

        StringBuffer sb = new StringBuffer();

        for (Long id: idList) {

            sb.append(id+",");

        }

 

        String resMsg = "##成功删除的票据id为:"+sb.toString();

        return resMsg;

    }

    //2.演示使用@RequestBody读取Ajax表单提交的JSON格式数据

    //说明:读取Ajax发送过来的数组对象并转换为Book类型

    @ResponseBody

    @RequestMapping(value = "/ajaxAddBook", method = RequestMethod.POST)

    public String ajaxAddBook(@RequestBody Book book){

        //打印输出要删除id

        System.out.println("接收到Ajax请求.");

        System.out.println("添加的图书:" + book);

        String resMsg = "操作成功:"+book.toString();

        return resMsg;

    }

 

    @RequestMapping(value = "/json_book", method = RequestMethod.GET)

    @ResponseBody

    public Book getJsonBook(){

        Book book = new Book();

        book.setAuthor("金庸");

        book.setBookname("笑傲江湖");

        book.setPress("广东文学出版社");

        book.setPrice(90.5);

        return  book;

    }

}

发送表单数据: