[Spring MVC] 入门基础

来源:互联网 发布:华藏净宗网络直播台 编辑:程序博客网 时间:2024/06/07 07:45

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

目录:

  • MVC框架
    • 优点
    • 缺点
  • Spring的MVC框架
    • 简单原理
    • 第一步pomxml
    • 第二步webxml
    • 第三步Controller类
    • 第四步spring-servletxml
    • 第五步XXXjsp
  • 实战大作业
    • 目录结构
    • Servlet 配置
    • VO层
    • DAO层
    • Controller层

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           // 存放实体类Modelsrc/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.Driverjdbc.url=jdbc:mysql://localhost:3306/filmgogo?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=truejdbc.username=rootjdbc.password=XXXXXXXXXjdbc.initialSize=10jdbc.maxActive=20jdbc.maxIdle=20jdbc.minIdle=1jdbc.maxWait=10000

3.VO层

这里写图片描述

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

4.DAO层

这里写图片描述

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

    @Repositorypublic 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

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

0 0
原创粉丝点击