Spring MVC入门级项目示例

实践出真知!

前言

跳过废话,直接看正文

在参与了两三个基于spring MVC框架的网站开发项目后,我对spring的配置和开发也有了一些了解。在这里给出一个入门级的spring MVC示例项目并加以详细解释,希望能够帮助刚接触springMVC的同学快速入门。

这里只是一个简单的spring项目解析,想要进一步了解spring MVC框架的处理过程,请前往spring官方文档查看。


正文

预备知识

MVC

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

Spring MVC 的请求处理流程

The request processing workflow in Spring Web MVC

如上图所示, 当用户用浏览器访问一个网址时,浏览器会向web服务器发送http请求(Incoming request), 这个请求首先会被服务器端的DispatcherServlet获取(图中把这个Servlet叫做Front controller),Servlet会根据请求的URL将这个请求交给对应的Controller去处理(具体怎么映射后面会讲),然后Controller会调用数据访问层的相关接口来获取用户想要访问的数据(Create Mode),随后Controller会找到对应的View模板,并将这些数据发送到该View模板进行渲染,从而生成最终的view(也就是网页文件),并返回给用户。

ok,预备知识到此为止,有了这些知识就足够看懂此示例项目了,spring的一些其他功能以及其底层的实现,以后再慢慢研究。

项目配置

想要方便快速地运行此项目,需要配置以下几个环境
java开发环境:jdk 1.7及以上
项目开发环境:IntelliJ IDEA(我用版本的是2016.2,不清楚其兼容性怎么样)

项目下载

https://github.com/clayandgithub/SpringDemo

项目文件结构

项目文件结构

文件详解

pom.xml

这个是maven的配置文件,主要用来管理项目依赖,与spring的配置没啥关系,想要详细了解的同学可以参考Maven pom.xml 配置详解

webapp/WEB-INF/web.xml

  • 这个是java web项目的基本配置文件,在这里配置servlet、filter、context、listener等等。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

<!-- basic configure -->
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>com.clayandgithub</param-value>
    </context-param>

<!-- listeners -->
<!-- global listener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

<!-- spring log4j listener -->
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>

<!-- application context setting 使用applicationContext.xml来配置spring的bean-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/spring/applicationContext.xml </param-value>
    </context-param>

<!-- servlets 这里之所以是复数,是因为可以添加多个servlet,由servlet-mapping来确定请求发到哪个servlet来处理 -->
    <!--spring 的DispatcherServlet,这里只配置了一个url-pattern为/的servlet,因此所有的请求都将由此servlet来处理-->
    <servlet>
        <servlet-name>mvc-servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 使用mvc-servlet.xml来初始化此servlet-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:/spring/mvc-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-servlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

<!-- filters -->
<!-- charset utf-8 filter -->
    <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>

<!-- spring security filter 这是spring 安全相关的配置,可以暂时不用管-->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <mime-mapping>
        <extension>ico</extension>
        <mime-type>image/vnd.microsoft.icon</mime-type>
</mime-mapping>

<!-- general error page setting 这里可以定义错误码对应的页面文件,使用静态页面可以跳过spring框架的处理,因此访问速度会快些-->
    <error-page>
        <error-code>500</error-code>
        <location>/static/html/500.html</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/static/html/404.html</location>
    </error-page>
    <error-page>
        <error-code>403</error-code>
        <location>/static/html/403.html</location>
    </error-page>
<!--使用通用的未知错误页面来处理未被捕获的Exception,防止发生错误时网站代码信息泄露。也可以使用Spring中的ExceptionHandler来实现更加丰富的功能-->
    <error-page>
       <exception-type>java.lang.Exception</exception-type>
     <location>/static/html/uncatched_exception.html</location>
    </error-page>
</web-app>

resources/spring/mvc-servlet.xml

  • servlet 配置文件
<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd  
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
    http://www.springframework.org/schema/jdbc
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
    <!--spring3.*的新标签,隐式注入一些bean-->
    <context:annotation-config />
    <!-- 管理response的编码-->
    <mvc:annotation-driven>
    <mvc:message-converters>
        <ref bean="stringHttpMessageConverter" />
        <ref bean="marshallingHttpMessageConverter" />
    </mvc:message-converters>
    </mvc:annotation-driven>

<!--配置自动扫描的包路径,这样就可以在配置的包中使用spring的注解来自动注册bean了(如@Controller、@Interceptor)-->
    <context:component-scan base-package="com.clayandgithub.controller" />
    <context:component-scan base-package="com.clayandgithub.interceptor" />

<!-- mvc:resources 配置资源文件映射路径,将相应的url映射到对应的资源文件,这里的资源文件(夹)可以直接通过url请求访问,不会经过controller这一层,通常是js、html、图片这些可公开的静态文件-->
    <mvc:resources mapping="/static/**" location="/static/" />
    <mvc:resources mapping="/favicon.ico" location="/static/images/favicon.ico"/>

<!-- viewResolvers 配置 view层的解析器,此项目使用的是freemarker,也可以使用jsp的viewResolver-->
     <!-- FreeMarker configuration -->
     <bean id="freemarkerConfiguration"
        class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="location" value="classpath:freemarker.properties" />
    </bean>

    <bean id="freemarkerConfigurer"
        class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/views/" />
        <property name="defaultEncoding" value="UTF-8" />
        <property name="freemarkerSettings" ref="freemarkerConfiguration" />
        <property name="freemarkerVariables">
            <map>
                <entry key="testFreemarkerVar" value="TestFreemarkerVarValue" />
            </map>
        </property>
    </bean>
    <bean id="freeMarkerViewResolver"
        class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
         <!--这里的suffix会被自动拼接到controller传来的view的名字之后,用来寻找对应的view模板文件-->
        <property name="suffix" value=".ftl" />
        <property name="contentType" value="text/html;charset=UTF-8" />
        <property name="allowSessionOverride" value="true" />
        <property name="exposeRequestAttributes" value="true" />
        <property name="exposeSessionAttributes" value="true" />
        <property name="exposeSpringMacroHelpers" value="true" />
        <property name="requestContextAttribute" value="rca"></property>
    </bean>
    <!-- messageConverters -->
    <bean id="stringHttpMessageConverter"
        class="org.springframework.http.converter.StringHttpMessageConverter">
        <constructor-arg value="UTF-8" index="0"></constructor-arg>
        <property name="supportedMediaTypes">
            <list>
                <value>text/plain;charset=UTF-8</value>
                <value>text/json;charset=UTF-8</value>
                <value>text/html;charset=UTF-8</value>
                <value>text/javascript;charset=UTF-8</value>
                <value>application/json;charset=UTF-8</value>
                <value>application/javascript;charset=UTF-8</value>
            </list>
        </property>
    </bean>
    <bean id="mappingJacksonHttpMessageConverter"
        class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>application/json;charset=UTF-8</value>
                <value>application/javascript;charset=UTF-8</value>
                <value>text/html;charset=UTF-8</value>
                <value>text/json;charset=UTF-8</value>
                <value>text/javascript;charset=UTF-8</value>
            </list>
        </property>
    </bean>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
    <bean id="marshallingHttpMessageConverter"
        class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
        <property name="marshaller" ref="castorMarshaller" />
        <property name="unmarshaller" ref="castorMarshaller" />
        <property name="supportedMediaTypes">
            <list>
                <value>text/xml;charset=UTF-8</value>
                <value>application/xml;charset=UTF-8</value>
            </list>
        </property>
    </bean>

<!--文件上传相关配置-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
        <!-- 设置上传文件的最大尺寸为1MB -->  
        <property name="maxUploadSize">  
            <value>1048576</value>  
        </property>  
    </bean>
</beans>

resources/spring/applicatioonContext.xml

  • spring bean 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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/tx
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:property-placeholder ignore-unresolvable="true"
        location="classpath:settings.properties"/>

    <!--将bean的定义按照逻辑分到多个文件中,模块化加载,这样逻辑会清楚一些,也避免此文件太长-->
    <import resource="jpa-context.xml"/>
    <import resource="mvc-servlet.xml"/>
    <import resource="general-beans.xml"/>
    <import resource="spring-security.xml"/>

</beans>

resources/spring/jpa-context.xml

  • 数据库相关的 bean 配置文件
<?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:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/data/jpa
        http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
        http://www.springframework.org/schema/data/repository
        http://www.springframework.org/schema/data/repository/spring-repository-1.6.xsd"
    default-lazy-init="true">

    <description>spring-data-jpa (java persistence api) </description>
    <context:component-scan base-package="com.clayandgithub.service" />

<!-- Jpa Entity Manager -->
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
        <property name="packagesToScan" value="com.clayandgithub.entity" />
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.ejb.naming_strategy">${hibernate.ejb.naming_strategy}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
            </props>
        </property>
    </bean>

<!-- Jpa transaction manager -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

<!-- trasactions with annotation -->
    <tx:annotation-driven transaction-manager="transactionManager"
        proxy-target-class="true" />

<!-- Jpa repositories -->
    <jpa:repositories base-package="com.clayandgithub.repository"
        entity-manager-factory-ref="entityManagerFactory"
        transaction-manager-ref="transactionManager" />

<!-- Jpa vendor adapter of hibernate -->
    <bean id="hibernateJpaVendorAdapter"
        class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="database" value="${hibernate.database}" />
        <property name="showSql" value="${hibernate.show_sql}" />
    </bean>

<!-- JSR303 Validator -->
    <bean id="validator"
        class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

<!-- connection pool -->
    <bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource">
        <property name="alias" value="proxoolDataSource" />
        <property name="driver" value="${connection.driver_class}" />
        <property name="driverUrl" value="${connection.url}" />
        <property name="user" value="${connection.username}" />
        <property name="password" value="${connection.password}" />
        <!-- <value type="int"> ${connection.housekeepingsleeptime}</value> -->
        <property name="prototypeCount" value="${connection.prototypecount}" />
        <property name="maximumActiveTime" value="${connection.maximumactivetime}" />
        <property name="statistics" value="${proxool.statistics}" />
        <property name="simultaneousBuildThrottle" value="${proxool.simultaneous.build.throttle}" />
        <property name="maximumConnectionCount" value="${proxool.maximum.connection.count}" />
        <property name="minimumConnectionCount" value="${proxool.minimum.connection.count}" />
    </bean>
</beans>

resources/spring/spring-security.xml

  • spring 安全相关 bean 配置文件

    此示例项目并未涉及到安全配置,暂不阐述。

properties文件

这些properties文件内容可以直接看项目中的文件内容,就是简单的键值对。

PageController

  • 示例Controller
/**
 * PageController.java
 * Copyright 2016 escenter@zju.edu.cn, all rights reserved.
 * any form of usage is subject to approval.
 */
package com.clayandgithub.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

/**
 *
 * @author clayanddev
 *
 */
@Controller
public class PageController {

    //这里使用RequestMapping就是前面所说的映射定义了,这里映射的是"/",也就是根路径
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView getIndexPage(final HttpServletRequest request, final HttpServletResponse response) {
        // 这里index就是view的名字,结合viewResolver(此项目的freemarker)的配置信息(<property name="templateLoaderPath" value="/WEB-INF/views/" /><property name="suffix" value=".ftl" />,controller就能够找到对应的模板文件(/WEB-INF/views/index.ftl),进而完成视图渲染)
        ModelAndView modelAndView = new ModelAndView("index");
        modelAndView.addObject("message", "This message is from PageController!");
        return modelAndView;
    }
}

后记

项目的主要文件都已一一说明,其他文件内容都无关紧要或者很容易理解。
这是个简单的spring入门项目,spring提供的功能很丰富,因此配置也非常的多,此后有时间再慢慢向此项目中添加一些常用的功能,如数据库操作(Service与Repository)、登录验证机制、安全机制等等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值