教你搭建SpringMVC框架( 附源碼)


一、項目目錄結構

二、SpringMVC需要使用的jar包

  1. commons-logging-1.2.jar
  2. junit-4.10.jar
  3. log4j-api-2.0.2.jar
  4. log4j-core-2.0.2.jar
  5. log4j-web-2.0.2.jar
  6. spring-beans-3.2.4.RELEASE.jar
  7. spring-context-3.2.4.RELEASE.jar
  8. spring-core-4.0.5.RELEASE.jar
  9. spring-expression-3.2.4.RELEASE.jar
  10. spring-web-4.0.5.RELEASE.jar
  11. spring-webmvc-3.2.9.RELEASE.jar

三、在Web.xml配置SpringMVC控制器

在不設置contextConfigLocation參數的情況下,SpringMVC框架默認在WEB-INF路徑下查找文件名為XXX-servlet.xml(XXX是web.xml中配置的SpringMVC框架控制器的名稱)。可以通過設置contextConfigLocation參數,自定義SpringMVC-servlet.xml的路徑。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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">
    <display-name>SpringMVC</display-name>

    <!-- 添加Spring控制器及映射規則 -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 不設置contextConfigLocation,SpringMVC 會在WEB-INF文件夾下查找<servlet-name/>-servlet.xml,設置 
            contextConfigLocation,可自定義SpringMVC-servlet.xml的位置 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:config/SpringMVC-servlet.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 首頁文件列表 -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

四、配置SpringMVC-servlet.xml

在路徑/SpringMVCDemo/src/comm/config/配置SpringMVC-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" 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-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/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
    ">

    <!-- 自動掃描的包名 -->
    <context:component-scan base-package="com.candy.dao"></context:component-scan>
    <context:component-scan base-package="com.candy.service"></context:component-scan>
    <context:component-scan base-package="com.candy.web"></context:component-scan>

    <!-- 添加注解驅動 -->
    <mvc:annotation-driven/>

    <!-- 模型視圖名稱解析 -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/jsp/</value>
        </property>
        <property name="suffix">
            <value></value>
        </property>
    </bean>

    <!-- 對靜態資源文件的訪問 方案 -->
    <mvc:default-servlet-handler />
</beans> 

五、編寫Controller

BaseController:

package com.candy.web;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.propertyeditors.CustomCollectionEditor;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;

@Controller
public class BaseController {


    protected final Logger log = LogManager.getLogger();

    /**
     * 處理頁面參數序列化后數據類型的問題
     * 
     * @author Candy
     * @date 2014-11-3
     * @version V1.0
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        log.debug("initBinder");
        SimpleDateFormat dataSdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat dataTimesdf = new SimpleDateFormat(
                "yyyy-MM-dd HH:mm:ss");
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dataSdf,
                true));
        binder.registerCustomEditor(Timestamp.class, new CustomDateEditor(
                dataTimesdf, true));
        binder.registerCustomEditor(List.class, new CustomCollectionEditor(
                List.class, true));
    }

    /**
     * 獲取客戶端真實IP地址
     * 
     * @author Candy
     * @date 2014-11-3
     * @version V1.0
     * @param request
     * @return
     */
    public String getIpAddr(HttpServletRequest request) {
        log.debug("getIpAddr");
        if (request == null) {
            return null;
        }
        String ip = request.getRemoteAddr();

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("x-forwarded-for");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        return ip;
    }
}

TestController:

/**
 * @projectName SpringMVC
 * @package com.candy.web.IndexController.java
 * @Copyright Copyright(c) 2014 Candy工會
 * @author Candy
 * @date 2014-11-3
 * @version V1.0
 */
package com.candy.web.test;

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

import com.candy.service.TestService;
import com.candy.web.BaseController;

/**
 * 測試Controller
 * 
 * @author Candy
 * @date 2014-11-3
 * @version V1.0
 */
@Controller
public class TestController extends BaseController {

    @Autowired
    private TestService testService;
    /**
     * 測試跳轉
     * 
     * @author Candy
     * @date 2014-11-3
     * @return
     */
    @RequestMapping("/transfer")
    public ModelAndView testTransfer() {
        log.debug("控制器查找到請求的路徑!");
        String viewName =testService.testTransfer();
        return new ModelAndView(viewName);
    }

}

六、編寫測試頁面

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://"
            + request.getServerName() + ":" + request.getServerPort()
            + path + "/";
%>
<!DOCTYPE html>
<html lang="zh">

<head>
<base href="<%=basePath%>">

<title>SpringMVCDemo-首頁</title>

<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css"
    href="${pageContext.request.contextPath}/css/styles.css">

</head>

<body>
    <div class="container">
        <div class="header"></div>
        <div class="content">
            <a href="${pageContext.request.contextPath}/transfer">發起請求</a>,后台響應,跳轉到指定頁面!
        </div>
        <div class="footer"></div>
    </div>
</body>
</html>

在路徑/SpringMVCDemo/WebContent/WEB-INF/jsp/下編寫success.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://"
            + request.getServerName() + ":" + request.getServerPort()
            + path + "/";
%>
<!DOCTYPE html>
<html lang="zh">

<head>
<base href="<%=basePath%>">

<title>SpringMVCDemo-成功頁面</title>

<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css"
    href="${pageContext.request.contextPath}/css/styles.css">

</head>

<body>
    <div class="container">
        <div class="header"></div>
        <div class="content">
            <h3>跳轉成功!</h3>
            <p>當你看到這些文字時,說明SpringMVC配置成功了!</p>
        </div>
        <div class="footer"></div>
    </div>
</body>
</html>

七、訪問測試

在瀏覽器中訪問http://localhost:8080/SpringMVCDemo/,根據Web.xml中的配置默認顯示index.jsp

    <!-- 首頁文件列表 -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

點擊index.jsp中的“發起請求”鏈接,根據index.jsp代碼,此時,瀏覽器會向服務器發出請求訪問路徑為“/SpringMVCDemo/transfer"的資源。

<a href="${pageContext.request.contextPath}/transfer">發起請求</a>,后台響應,跳轉到指定頁面!

SpringMVC框架通過Web.xml中定義的控制器及映射規則,讀取SpringMVC-servlet中的配置。

    <!-- 添加Spring3控制器及映射規則 -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 不設置contextConfigLocation,SpringMVC 會在WEB-INF文件夾下查找<servlet-name/>-servlet.xml,設置 
            contextConfigLocation,可自定義SpringMVC-servlet.xml的位置 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:config/SpringMVC-servlet.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

SpringMVC框架掃描各個包,查找注解為“@Controller”的類,並掃描注解為"@RequestMapping("/transfer")"對應的方法。

    <!-- 自動掃描的包名 -->
    <context:component-scan base-package="com.candy.dao"></context:component-scan>
    <context:component-scan base-package="com.candy.service"></context:component-scan>
    <context:component-scan base-package="com.candy.web"></context:component-scan>

    <!-- 添加注解驅動 -->
    <mvc:annotation-driven/>

此時SpringMVC框架已經定位到了com.candy.web.test.TestController.testTransfer()方法。

在TestController的testTransfer()方法中,SpringMVC框架根據注解和自動掃描配置,查找類名為“TestService”,類注解為“@Component”的類,完成自動注入(Autowired)。

此時,TestController的testTransfer()方法返回一個ModelAndView的對象。SpringMVC框架根據SpringMVC-servlet.xml中的配置,在路徑/WEB-INF-jsp中查找success.jsp文件,並返回給客戶端。

    <!-- 模型視圖名稱解析 -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/jsp/</value>
        </property>
        <property name="suffix">
            <value></value>
        </property>
    </bean>

此時,你就可以看到成功訪問的信息了。


 

注:以上博文中,簡單的貼了下配置,並在第七步“訪問測試”中,按照自己的理解,通過簡單易懂的文字,描述了框架的執行順序。

其實在項目啟動時,SpringMVC框架就完成了以下工作:

  1. 讀取web.xml,獲取到contextConfigLocation中配置的SpringMVC-servlet.xml路徑。
  2. 讀取SpringMVC-servlet.xml,掃描配置的各個包。
  3. 根據注解,加載所有的Controller、Service等組件,並完成自動注入。
  4. 根據注解,計算可能多的訪問路徑。

 源碼下載地址:http://pan.baidu.com/s/1c0gZUXa


 以下是搭建環境時,遇到的各種問題筆記。 

  1. 搭建JUnit環境時,測試Controller時,提示“Caused by: javax.validation.ValidationException: Unable to instantiate Configuration.
    2014-11-3 18:06:46 org.springframework.context.support.FileSystemXmlApplicationContext prepareRefresh
    信息: Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@f81843: startup date [Mon Nov 03 18:06:46 CST 2014]; root of context hierarchy
    2014-11-3 18:06:46 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    信息: Loading XML bean definitions from file [D:\Workspaces\SpringMVCDemo\WebContent\WEB-INF\SpringMVC-servlet.xml]
    2014-11-3 18:06:46 org.springframework.context.annotation.ClassPathBeanDefinitionScanner registerDefaultFilters
    信息: JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
    2014-11-3 18:06:46 org.springframework.context.annotation.ClassPathBeanDefinitionScanner registerDefaultFilters
    信息: JSR-330 'javax.inject.Named' annotation found and supported for component scanning
    2014-11-3 18:06:46 org.springframework.context.annotation.ClassPathBeanDefinitionScanner registerDefaultFilters
    信息: JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
    2014-11-3 18:06:46 org.springframework.context.annotation.ClassPathBeanDefinitionScanner registerDefaultFilters
    信息: JSR-330 'javax.inject.Named' annotation found and supported for component scanning
    2014-11-3 18:06:46 org.springframework.context.annotation.ClassPathBeanDefinitionScanner registerDefaultFilters
    信息: JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
    2014-11-3 18:06:46 org.springframework.context.annotation.ClassPathBeanDefinitionScanner registerDefaultFilters
    信息: JSR-330 'javax.inject.Named' annotation found and supported for component scanning
    2014-11-3 18:06:46 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
    信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
    2014-11-3 18:06:46 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
    信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@dda25b: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,baseController,testController,mvcContentNegotiationManager,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0,org.springframework.format.support.FormattingConversionServiceFactoryBean#0,org.springframework.validation.beanvalidation.LocalValidatorFactoryBean#0,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0,org.springframework.web.servlet.handler.MappedInterceptor#0,org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0,org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0,org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0,org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,viewResolver,org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#0,org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#0,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
    ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...
    2014-11-3 18:06:46 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping registerHandlerMethod
    信息: Mapped "{[/transfer],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView com.candy.web.test.TestController.referLogin()
    2014-11-3 18:06:46 org.hibernate.validator.util.Version <clinit>
    信息: Hibernate Validator bean-validator-3.0-JBoss-4.0.2
    2014-11-3 18:06:46 org.springframework.beans.factory.support.DefaultListableBeanFactory destroySingletons
    信息: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@dda25b: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,baseController,testController,mvcContentNegotiationManager,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0,org.springframework.format.support.FormattingConversionServiceFactoryBean#0,org.springframework.validation.beanvalidation.LocalValidatorFactoryBean#0,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0,org.springframework.web.servlet.handler.MappedInterceptor#0,org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0,org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0,org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0,org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,viewResolver,org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#0,org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#0,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
    java.lang.ExceptionInInitializerError
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.validation.beanvalidation.LocalValidatorFactoryBean#0': Invocation of init method failed; nested exception is javax.validation.ValidationException: Unable to instantiate Configuration.     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1482)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
        at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:140)
        at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:84)
        at com.candy.web.BaseController.<clinit>(BaseController.java:25)
    Caused by: javax.validation.ValidationException: Unable to instantiate Configuration.
        at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:272)
        at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.afterPropertiesSet(LocalValidatorFactoryBean.java:188)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1541)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1479)
        ... 12 more
    Caused by: java.lang.NullPointerException
        at java.util.ResourceBundle.getBundle(ResourceBundle.java:950)
        at org.hibernate.validator.engine.ResourceBundleMessageInterpolator.loadBundle(ResourceBundleMessageInterpolator.java:202)
        at org.hibernate.validator.engine.ResourceBundleMessageInterpolator.getFileBasedResourceBundle(ResourceBundleMessageInterpolator.java:182)
        at org.hibernate.validator.engine.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:81)
        at org.hibernate.validator.engine.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:73)
        at org.hibernate.validator.engine.ConfigurationImpl.<init>(ConfigurationImpl.java:57)
        at org.hibernate.validator.HibernateValidator.createGenericConfiguration(HibernateValidator.java:43)
        at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:269)
        ... 15 more
    Exception in thread "main" 

    解決方案:刪除JavaEE6中自帶的jar包:bean-validator.jar

  2. 如何刪除JavaEE6中自帶的jar包?
          在MyEclipse的菜單:Window-->Properties-->MyEclipse-->Java Enterprise Project-->Library Sets中,選擇到Java EE6.0選項卡(默認選中),然后選擇bean-validator.jar,點擊右側的“Remove”按鈕,然后點“OK”按鈕即可。
  3. Log4j2輸出到控制台的log是亂碼。
    解決方案:在使用的PatternLayout中加入屬性:charset="GBK"即可。
  4. ……

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM