[Spring MVC] 入门基础

(ps: 这篇文章简要的讲述 JavaWeb开发的 Spring MVC 框架基础,由于是初学Spring MVC,然后便上手做系统分析与设计的大作业,做的总结可能有些瑕疵,对一些概念的理解可能比较片面,欢迎大神纠错)

目录:

MVC框架


模型-视图-控制器(MVC)是一个众所周知的以设计界面应用程序为基础的设计模式。它主要通过分离模型、视图及控制器在应用程序中的角色将业务逻辑从界面中解耦。

  • 模型负责封装应用程序数据在视图层展示。
  • 视图仅仅只是展示这些数据,不包含任何业务逻辑。
  • 控制器负责接收来自用户的请求,并调用后台服务(manager或者dao,即三层架构中的业务逻辑层和数据访问层)来处理业务逻辑。处理后,后台业务层可能会返回了一些数据在视图层展示。控制器收集这些数据及准备模型在视图层展示。

MVC模式的核心思想是将业务逻辑从界面中分离出来,允许它们单独改变而不会相互影响。

图片来源于网络
(图片来源于网络)

图片来源于网络
(图片来源于网络)

优点

(1)多个视图能共享一个模型。同一个模型可以被不同的视图重用,提高了代码的可重用性。

(2)由于MVC的三个模块相互独立,改变其中一个不会影响其他两个,所以依据这种设计思想能构造良好的松耦合的构件。

(3)此外,控制器提高了应用程序的灵活性和可配置性。控制器可以用来联接不同的模型和视图去完成用户的需求,这样控制器可以为构造应用程序提供强有力的手段。

缺点

(1)增加了系统结构和实现的复杂性。
对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。

(2)视图与控制器间的过于紧密的连接。
视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。

(3)视图对模型数据的低效访问。
依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。


Spring的MVC框架


简单原理

这里写图片描述
(图片来源于网络)

在Spring MVC中前端的控制器就是DispatcherServlet这个Servlet来掌管着用户的请求及最后的系统回应。这个DispatcherServlet同具体的业务逻辑一点都不着边,而是把所有的事情委派给控制器去做(Controller);然后当控制器把事情都做完了后,这个时候轮到视图(View)上场了,它可以把数据以不同的展现形式交给客户,可以是jsp、xml、json等等。

第一步:pom.xml

pom.xml文件中包含spring mvc依赖及为编写jsp文件提供支持的各种相关依赖。因为这是一个maven项目,所有依赖(jar)都在pom.xml中进行配置,maven将自动帮我们下载所有的对应依赖(jar包)。

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>hello</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>hello Maven Webapp</name>
  <url>http://maven.apache.org</url>

  <properties>  
        <springframework.version>4.0.6.RELEASE
        </springframework.version>  
    </properties>  

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-webmvc</artifactId>  
            <version>${springframework.version}</version>  
        </dependency>  
        <!-- Below declared dependencies are included for the servers who may complain about servlet/jstl missing dependency -->  
        <dependency>  
            <groupId>javax.servlet</groupId>  
            <artifactId>javax.servlet-api</artifactId>  
            <version>3.1.0</version>  
        </dependency>  
        <dependency>  
            <groupId>javax.servlet.jsp</groupId>  
            <artifactId>javax.servlet.jsp-api</artifactId>  
            <version>2.3.1</version>  
        </dependency>  
        <dependency>  
            <groupId>javax.servlet</groupId>  
            <artifactId>jstl</artifactId>  
            <version>1.2</version>  
        </dependency>  
  </dependencies>

  <build>
    <finalName>hello</finalName>
  </build>
</project>

第二步:web.xml

即Servlet部分,上面说到前端控制器是DispatcherServlet这个Servlet,那很显然需要在web.xml中加入一个servlet,然后把用户的请求都让DispatcherServlet去处理。

<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

 <display-name>hello Web Application </display-name>

 <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
 </servlet-mapping>

</web-app>

这里有个地方就是contextConfigLocation,这个是个初始化参数(init-param),在servlet进行初始化的时候可以设置它的值,而这个值定义了spring应用上下文(context—上下文,指的是一种环境,主要是各种bean,可以理解为各种component)的配置文件(XML格式)的位置,这个上下文会被DispatcherServlet加载进来,这样Dispatcher工作起来时会依照这个上下文的内容进行分配任务。

关于上下文的配置,这里使用的是xml的配置方式,上面代码指定了配置文件是/WEB-INF/spring-servlet.xml,这个也可以使用java的配置方式

第三步:Controller类

package com.hello.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/")
public class HelloWorldController {

    @RequestMapping(method = RequestMethod.GET)
    public String sayHello(ModelMap model) {
        model.addAttribute("greeting", "Hello World from Spring 4 MVC");
        return "welcome";
    }


    @RequestMapping(value="/helloagain", method = RequestMethod.GET)
    public String sayHelloAgain(ModelMap model) {
        model.addAttribute("greeting", "Hello World Again, from Spring 4 MVC");
        return "welcome";
    }

}

1、使用了@Controller这个annotation(这个可以翻译成“注释”,表示下面的类的作用),来表示HomeController这个类是作为Spring MVC中的Controller(控制器),根据上面的那个图也就是表示这个类具有处理用户请求的能力。所以这里HomeController也是作为一个组件(Component),在Spring初始化扫描的时候它会被自动检测到并且加入到Spring container中(Spring容器或者叫Spring上下文,都是类似的概念),然后生成对应的类实例,最后像其他任何Spring组件一样允许注入到系统中。

2、home这个方法使用了@RequestMapping这个注释,表示home这个方法可以用来处理对应于路径“/”(根路径)的用户请求

3、这里home的处理就是在log中打印一个字符串,然后返回welcome,这个是交给View去处理的,这里就是个jsp文件. 默认情况下,如果我们没有设置特定的View的话,Spring会使用默认的View来处理WEB-INF/views/home.jsp这个Response(回应);对应View在后面将详细讲,这里只要知道View会把系统的home.jsp这个文件呈现给客户就好

第四步:spring-servlet.xml

在 WEB-INF 文件夹下创建一个名为spring-servlet.xml 的配置文件。
注意:此名字你可以随便起,但是要和web.xml里面声明的一致。

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="com.hello.controller" />

    <mvc:annotation-driven />

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

</beans>

spring 配置

<mvc:annotation-driven /> 意思是我们可以不在xml中声明该bean,或者实现一个借口或者继承一个bean类或者其他类的情况下定义bean的依赖。例如仅仅在类上加上一个 @Controller注解(我们上面的控制器类就是这么用的),这样就不需要再在xml中配置bean,spring就会知道我们带了此注解的类包含响应http请求的处理器。

<context:component-scan base-package="com.websystique.springmvc" />

spring 自动扫描此包下面的组件
base-package [com.websystique.springmvc],
看看它们有没有带 [@Controller, @Service,@Repository, @Component, 等等]这些注解。如果有这些注解spring将自动的将它们在bean 工厂里面注册,和在xml中配置bean效果是一样的。

通过上面我们声明了一个view resolver,帮助控制器(controller)代理响应到正确的视图(view).

第五步:XXX.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>HelloWorld page</title>
</head>
<body>
    Greeting : ${greeting}
</body>
</html>

实战:大作业

1.目录结构

src/main/java:
  com.filmgogo.Controller    // 存放Controller
  com.filmgogo.DAO          // 存放业务层Repository
  com.filmgogo.VO           // 存放实体类Model

src/main/resources:
  filmgogo-servlet.xml     // 配置Spring上下文
  jdbc.properties         // 存放jdbc相关自定义的键值对

src/main/webapp:          // 存放前端相关的资源文件
  WEB-INF
      index.jsp          // 首页布局
target:
    pom.xml              //项目依赖包配置文件

2. Servlet 配置

放置于filmgogo-servlet.xml文件中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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-3.0.xsd
                       http://www.springframework.org/schema/mvc
                       http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    <mvc:annotation-driven />
    <context:component-scan base-package="com.filmgogo" />
    <context:property-placeholder location="classpath:jdbc.properties" />
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" lazy-init="false">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="initialSize" value="${jdbc.initialSize}" />
        <property name="maxActive" value="${jdbc.maxActive}" />
        <property name="maxIdle" value="${jdbc.maxIdle}" />
        <property name="minIdle" value="${jdbc.minIdle}" />
        <property name="maxWait" value="${jdbc.maxWait}" />
    </bean>

    <bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

以及相应的键值映射:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/filmgogo?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true
jdbc.username=root
jdbc.password=XXXXXXXXX
jdbc.initialSize=10
jdbc.maxActive=20
jdbc.maxIdle=20
jdbc.minIdle=1
jdbc.maxWait=10000

3.VO层

这里写图片描述

例如:定义Reservation实体类:
这里写图片描述

4.DAO层

这里写图片描述

例如:MovieDAO, 用以完成对 Movie 实体的CRUD 操作:

    @Repository
public class MovieDAO {
    @Autowired
    private JdbcTemplate jdb;

    public String getMoviesViaCid(int cid)
    {
        String sql = "select distinct movie.id, movie.name, movie.type, movie.description, movie.image, movie.score, movie.star from movie, cinema " + "where cinema.id = ?;";
        Object[] para = new Object[]{cid};
        List<MovieVO> lm = jdb.query(sql, para, new RowMapper<MovieVO>(){

            public MovieVO mapRow(ResultSet res, int arg1) throws SQLException
            {
                MovieVO m = new MovieVO();
                m.setId(res.getInt("id"));
                m.setName(res.getString("name"));
                m.setType(res.getString("type"));
                m.setDescription(res.getString("description"));
                m.setImg(res.getString("image"));
                m.setScore(res.getFloat("score"));
                m.setStar(res.getString("star"));
                return m;
            }

        });
        return JSONArray.fromObject(lm).toString();
    }

5.Controller层

例如:Customer的登录请求映射:

@Controller
@RequestMapping(value="/login", method=RequestMethod.POST)
public class CustomerLogin {
    @Autowired
    private CustomerDAO customerInfo;

    @RequestMapping
    void login(HttpServletRequest request, HttpServletResponse response) throws IOException
    {
        request.setCharacterEncoding("UTF-8");
        StringBuffer requestData = new StringBuffer(); //requestData存放输入的用户名和密码等数据
        String line = null;
        try
        { //读取json数据
            BufferedReader reader = request.getReader();
            while ((line = reader.readLine()) != null)
            {
                requestData.append(line);
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        JSONObject requestInfo = JSONObject.fromObject(requestData.toString());
        JSONObject res = new JSONObject();
        if (customerInfo.isNameExisted(requestInfo.getString("name"))) 
        { //用户名存在
            if (customerInfo.isExisted(requestInfo.getString("name"), requestInfo.getString("password")))
            { //密码正确
                res.put("exist", true);
                res.put("loginAble", true);
            }
            else //密码不正确
            {
                res.put("exist", true);
                res.put("loginAble", false);
            }
        }
        else 
        { //用户名不存在
            res.put("exist", false);
            res.put("loginAble", false);
        }
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        out.print(res.toString());
    }
}

客户端的 POST 请求中将附带 name 和 password 这两个参数,并返回 loginAble参数。

(完)


大作业项目源码:
https://github.com/cajet/FilmGoGo

(题外话:通过大作业还学到了很多关于设计模式方面的东西,具体的有时间再写博客进行记录。欢迎纠错~)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值