SpringMVC源码分析

本文深入剖析了SpringMVC的工作原理,包括启动流程、执行流程和设计思路。核心类如DispatcherServlet、HandlerMapping和HandlerAdapter等在请求处理中的角色被详细阐述。在执行流程中,从HTTP请求到DispatcherServlet,再到HandlerMapping路由,HandlerAdapter处理参数和返回值,最终由ModelAndView渲染视图。异常处理和初始化过程也进行了说明,展示了SpringMVC如何利用策略模式和过滤器链模式实现高效处理。

前几天看了分析了@RequestBody的原理,并且DIY了一个参数解析器,今天趁热打铁,分析下SpringMVC的原理,主要包括启动流程和执行流程以及其设计思路。

SpringMVC中的MVC指的是model view 和 controller,view指的是渲染的视图,model指的是应用中包含的各种数据,controller则是负责业务处理的控制器。对于整个流程来说,当一个HTTP请求进入服务器之后,controller会对后台的数据,即model进行加工处理,然后由SpringMVC将这些model渲染为对应的view,形成response响应给client

主要模块

SpringMVC中有几个非常重要的类,分别是 DispatherServletHandlerMappingHandlerMethodHandlerAdapterHandlerExceptionResolverHandlerInterceptorHandlerExecutionChainHandlerMethodArgumentResolverHandlerMethodReturnValueHanlder

  1. DispatherServlet负责两件事情,一个是兼容Servlet规范(实现servlet的init方法,使得MVC相关的处理器在此时初始化);一个是使得该MVC程序可以简单实用Spring的IOC(可以获得Environment,设置Environment和ApplicationContext)。除此之外,DispatherServlet还负责路由之后的核心逻辑的处理
  2. 对于HandlerMapping来说,它负责将request和handlerExecutionChain关联起来,用于请求的路由处理。它的一个实现类RequestMappingHandlerMapping需要在初始化的时候检测@Controller注解或者@RequestMapping注解的类,将对应RequestMappingInfo(里面装着url的映射)和HandlerMethod关联起来
  3. HandlerMethod封装了对应的Method和持有它的bean
  4. HandlerAdapter依赖并代理了HandlerMethod,聚合了ModelAndViewResolver, HandlerMethodArgumentResolverHandlerMethodReturnValueHanlder,用于处理参数,返回值和渲染视图
  5. HandlerExecutionChain封装了HandlerAdapter和拦截器集合,通过它可以拿到HandlerAdapter,并且可以进行拦截器前置方法,后置方法和完成方法的监听和处理
  6. HandlerMethodArgumentResolverHandlerMethodReturnValueHanlder用户参数和返回值的个性化处理。用到的设计思想和HandlerAdapter是一样的
  7. 最后一步,就是要去将数据渲染为对应的视图,而这一步就是由ModelAndViewView来完成的,它负责将model以不同的方式,如Jsp,Html等渲染成view,装入response中
  8. 而几乎所有的框架都会有异常处理模块,SpringMVC也不例外,HandlerExceptionResolver则是负责这么一个处理流程的。它主要的功能就是将异常转换为合适的ModelAndView之后渲染到response中,而不至于出现5**的响应。其中,我们可以自定义发生异常后的响应方式。

对于这几个模块,我们可以这么理解:

对于一个普通的MVC设计思路来说,路由request和method是必不可少的,然后通过代理method的adapter来实现对参数和返回值的处理,又因为需要进行拦截器的拦截,所以需要一个interceptorChain和interceptor。最后,因为业务需要对某些异常进行特定的处理,所以我们还需要一个异常处理模块。

这,便是SpringMVC的核心类和模块。

执行流程

我们知道,对于Http请求来说,tomcat执行了HttpServlet#service方法,继承了HttPServletFrameServlet则是执行doService方法,而SpringMVC的DispatcherServlet则是继承了HttpServlet,进入到SpringMVC的流程中,在DispatcherServlet中的流程如下:

先通过HandlerMapping拿到request对应的HandlerExecutionChain,然后再拿到HandlerExecutionChain中handler对应的HandlerAdapter,执行HandlerExecutionChaininterceptor#prehandle方法。

再通过handlerAdapter去执行handler,handler其实对应的是之前注册的HandlerMethod(handlerMethod里面封装的映射的真正方法 handler还有可能是原生的Servlet),所以要执行handler.invoke,不过在这之前要去判断参数,这一步需要参数解析器HandlerMethodArgumentResolver。反射调用完之后,需要调用返回值解析器HandlerMethodReturnValueHanlder

真正方法执行完了之后,再执行HandlerExecutionChain中interceptor#posthandle方法进行拦截器的后置处理。

SpringMVC执行完之后返回的是ModelAndView,我们还需要对ModelAndView进行render,即把modelAndView中的view渲染到response中

当发生异常时,会将异常拉到用户业务自己的异常处理方法中,这时也需要对参数和返回值进行custom,此时就需要用到HandlerExceptionResolver系列了。因为用户标记的@ExceptionHandler方法已经被ExceptionHandlerMethodResolver找到并且注册(key为对应异常,value为对应方法),只需要调用该方法就可以对异常进行处理,此时的方法调用和之前的handler几乎没有区别

// DispatherServlet#doDispath关于异常处理的部分源码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ...
    try {
        ...
        try {  
            ...  
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        // 处理异常和渲染modelAndView的方法
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    ...
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

    boolean errorView = false;

    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            // 真正处理异常的方法
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }
    ...
}

启动流程

默认使用SpringBoot的自动装备

当我们点击SpringBoot的run之后,马老师,发绳肾么事了?

在回答问题之前,我们需要明白一件事情:SpringMVC在启动的时候需要利用SpringIOC的特性,同时也需要符合Servlet规范,即对servlet进行初始化。

SpringBoot会首先获得AnnotationConfigServletWebServerApplicationContext,然后进入到它的父类AbstractApplicationContext#finishBeanFactoryInitialization中,它会去遍历所有bean,对bean进行后置方法的处理。因为RequestMappingHandlerMapping需要对bean进行后置化处理,在这个过程中,它会去查找到有@Controller注解或者@RequestMapping注解的类,将对应RequestMappingInfo(里面装着url的映射)和HandlerMethod关联起来,在这个过程中,它不仅会注册用户自己标记的Controller,SpringMVC还内置了error的默认处理类BasicErrorController

// 附:AbstractHandlerMethodMapping.java 部分源码

/**
 * Detects handler methods at initialization.
 */
@Override
public void afterPropertiesSet() {
   initHandlerMethods();
}

/**
 * Scan beans in the ApplicationContext, detect and register handler methods.
 */
protected void initHandlerMethods() {
   
   ... 
       
   for (String beanName : beanNames) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
         Class<?> beanType = null;
         try {
            beanType = obtainApplicationContext().getType(beanName);
         }
         catch (Throwable ex) {
            // An unresolvable bean type, probably from a lazy bean - let's ignore it.
            if (logger.isDebugEnabled()) {
               logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
            }
         }
         // 如果该bean有@Controller或者@RequestMapping注解,则获取它的方法
         if (beanType != null && isHandler(beanType)) {
            detectHandlerMethods(beanName);
         }
      }
   }
   // 后置处理,由子类实现,目前为空
   handlerMethodsInitialized(getHandlerMethods());
}
/**
  * Look for handler methods in a handler.
  * @param handler the bean name of a handler or a handler instance
  */
protected void detectHandlerMethods(final Object handler) {
    Class<?> handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
        // 将该类中的method和对应的RequestMappingInfo装入map中
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> {
                    try {
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
								userType.getName() + "]: " + method, ex);
                    }
				});
		if (logger.isDebugEnabled()) {
			logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
		}
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            // 形成HandlerMethod类,并将该类与mapping进行映射
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}

我们知道,Servlet需要通过init方法进行初始化,Servlet也需要在init方法中初始化。

AbstractApplicationContext#finishBeanFactoryInitialization执行之后,便会执行AbstractApplicationContext#finishRefresh,在这个过程中,它会去启动Tomcat服务器,在Tomcat启动的过程中,调用StandardWrapper#loadServlet,而此时,则会对DefaultServlet进行初始化,对默认Servlet进行一些属性的设置

初始化流程

在服务启动之后,当一个request进入我们的服务器的时候,经过一系列的Valve和Filter后,会进入StandardWrapper#allocate中申请Servlet,同时对DispatherServlet进行初始化,它主要执行了DispatherServlet#initStrategies,然后在初始化策略的过程中会初始化HandlerMappingHandlerAdapterHandlerExceptionResolverViewResolver等等。在这个过程中,如果有对应的bean则获取,如果没有则拿到dispatcherServlet.properties中的默认策略

设计思路

  1. SpringMVC中大量使用工厂模式,组合模式,策略模式和过滤器链模式等等,包括且不限于异常处理模块,参数解析和返回值渲染模块,方法代理模块(这个模块还用了代理模式)等等,它常见的表现形式如下:

    interface Handler{
        public boolean supports(Object obj);
        public Object resolve(Object obj);
    }
    class Composite implements Handler{
        List<Handler> handlerList;
        
        @Override
       	public boolean supports(Object obj){
            for(Handler handler: handlerList) {
                if(handler.supports(obj)) {
                    return true;
                }
            }
            return false;
        }
        @Override
        public Object resolve(Object obj){
             for(Handler handler: handlerList) {
                if(handler.supports(obj)) {
                    return handler.resolve(obj);
                }
            }
        }
    }
    class DiyHandler implements Handler{
        ...
    }
    
  2. 在责任链模式的使用过程中,我发现SpringMVC的过滤器链和Tomcat的还有一些不同,Tomcat的过滤器模式比较正统,而对于SpringMVC的责任链中,它其实只是起了一个拦截器的作用,只用到了两个类就实现了,即HandlerInterceptorHandlerExecutionChain,前者有多个实现类,对应着多个不同种类的拦截器。而Tomcat当中,有两种方式实现了责任链模式,一个是pipeline/valve(valve的多个实现类对应着不同的水阀),另一个是filterChain/filter/filterConfig(chain负责调度多个filter并执行,filterConfig聚合了filter及其配置)

  3. 同时,大量的Map形式或者类形式(如Match类)的缓存也是必须的

采坑点

  1. 看SpringMVC最好不要直接用SpringBoot来看,它有自动装配,会让人看源码看的更加复杂
  2. <---- 参数和返回值 依赖关系 和 <—<> 属性 聚合关系
  3. Spring的BeanFactory和ApplicationContext,ApplicationListener,Environment和这四个对应的Aware接口
  4. spring-web和spring-webmvc的依赖的区别,前者是将spring应用的web环境中,后者是实现web中的spring模式
  5. 目前狭义上的SpringMVC是由服务端来负责渲染。从狭义上说,目前被大家广泛接受的前后端分离的形式,即后台只给前端传递json数据,这样是不属于MVC模式的,因为我们是直接把model转化为json传递给前端,由前端渲染。从源码中我们也可以看到,SpringMVC如果返回json数据的时候,返回的ModelAndView类是空的。所以我就产生了这样一个念头,简化SpringMVC
弃用了struts,用spring mvc框架了几个项目,感觉都不错,而且使用了注解方式,可以省掉一大堆配置文件。本文主要介绍使用注解方式配置的spring mvc,之前写的spring3.0 mvc和rest小例子没有介绍到数据层的内容,现在这一篇补上。下面开始贴代码。 文中用的框架版本:spring 3,hibernate 3,没有的,自己上网下。 先说web.xml配置: [java] view plaincopy 01.<?xml version="1.0" encoding="UTF-8"?> 02.<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> 03. <display-name>s3h3</display-name> 04. <context-param> 05. <param-name>contextConfigLocation</param-name> 06. <param-value>classpath:applicationContext*.xml</param-value> 07. </context-param> 08. <listener> 09. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 10. </listener> 11. 12. <servlet> 13. <servlet-name>spring</servlet-name> 14. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 15. <load-on-startup>1</load-on-startup> 16. </servlet> 17. <servlet-mapping> 18. <servlet-name>spring</servlet-name> <!-- 这里在配成spring,下边也要写一个名为spring-servlet.xml的文件,主要用来配置它的controller --> 19. <url-pattern>*.do</url-pattern> 20. </servlet-mapping> 21. <welcome-file-list> 22. <welcome-file>index.jsp</welcome-file> 23. </welcome-file-list> 24.</web-app> spring-servlet,主要配置controller的信息 [java] view plaincopy 01.<?xml version="1.0" encoding="UTF-8"?> 02. <beans 03. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 04. xmlns:context="http://www.springframework.org/schema/context" 05. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 06. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 07. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 08. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 09. 10. <context:annotation-config /> 11. <!-- 把标记了@Controller注解的类转换为bean --> 12. <context:component-scan base-package="com.mvc.controller" /> 13. <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 --> 14. <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> 15. 16. <!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 --> 17. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 18. p:prefix="/WEB-INF/view/" p:suffix=".jsp" /> 19. 20. <bean id="multipartResolver" 21. class="org.springframework.web.multipart.commons.CommonsMultipartResolver" 22. p:defaultEncoding="utf-8" /> 23. </beans> applicationContext.xml代码 [java] view plaincopy 01.<?xml version="1.0" encoding="UTF-8"?> 02.<beans 03. xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 04. xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" 05. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 06. xsi:schemaLocation=" 07. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 08. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd 09. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 10. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> 11. 12. <context:annotation-config /> 13. <context:component-scan base-package="com.mvc" /> <!-- 自动扫描所有注解该路径 --> 14. 15. <context:property-placeholder location="classpath:/hibernate.properties" /> 16. 17. <bean id="sessionFactory" 18. class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 19. <property name="dataSource" ref="dataSource" /> 20. <property name="hibernateProperties"> 21. <props> 22. <prop key="hibernate.dialect">${dataSource.dialect}</prop> 23. <prop key="hibernate.hbm2ddl.auto">${dataSource.hbm2ddl.auto}</prop> 24. <prop key="hibernate.hbm2ddl.auto">update</prop> 25. </props> 26. </property> 27. <property name="packagesToScan"> 28. <list> 29. <value>com.mvc.entity</value><!-- 扫描实体类,也就是平时所说的model --> 30. </list> 31. </property> 32. </bean> 33. 34. <bean id="transactionManager" 35. class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 36. <property name="sessionFactory" ref="sessionFactory" /> 37. <property name="dataSource" ref="dataSource" /> 38. </bean> 39. 40. <bean id="dataSource" 41. class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 42. <property name="driverClassName" value="${dataSource.driverClassName}" /> 43. <property name="url" value="${dataSource.url}" /> 44. <property name="username" value="${dataSource.username}" /> 45. <property name="password" value="${dataSource.password}" /> 46. </bean> 47. <!-- Dao的实现 --> 48. <bean id="entityDao" class="com.mvc.dao.EntityDaoImpl"> 49. <property name="sessionFactory" ref="sessionFactory" /> 50. </bean> 51. <tx:annotation-driven transaction-manager="transactionManager" /> 52. <tx:annotation-driven mode="aspectj"/> 53. 54. <aop:aspectj-autoproxy/> 55.</beans> hibernate.properties数据库连接配置 [java] view plaincopy 01.dataSource.password=123 02.dataSource.username=root 03.dataSource.databaseName=test 04.dataSource.driverClassName=com.mysql.jdbc.Driver 05.dataSource.dialect=org.hibernate.dialect.MySQL5Dialect 06.dataSource.serverName=localhost:3306 07.dataSource.url=jdbc:mysql://localhost:3306/test 08.dataSource.properties=user=${dataSource.username};databaseName=${dataSource.databaseName};serverName=${dataSource.serverName};password=${dataSource.password} 09.dataSource.hbm2ddl.auto=update 配置已经完成,下面开始例子 先在数据库建表,例子用的是mysql数据库 [java] view plaincopy 01.CREATE TABLE `test`.`student` ( 02. `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 03. `name` varchar(45) NOT NULL, 04. `psw` varchar(45) NOT NULL, 05. PRIMARY KEY (`id`) 06.) 建好表后,生成实体类 [java] view plaincopy 01.package com.mvc.entity; 02. 03.import java.io.Serializable; 04. 05.import javax.persistence.Basic; 06.import javax.persistence.Column; 07.import javax.persistence.Entity; 08.import javax.persistence.GeneratedValue; 09.import javax.persistence.GenerationType; 10.import javax.persistence.Id; 11.import javax.persistence.Table; 12. 13.@Entity 14.@Table(name = "student") 15.public class Student implements Serializable { 16. private static final long serialVersionUID = 1L; 17. @Id 18. @Basic(optional = false) 19. @GeneratedValue(strategy = GenerationType.IDENTITY) 20. @Column(name = "id", nullable = false) 21. private Integer id; 22. @Column(name = "name") 23. private String user; 24. @Column(name = "psw") 25. private String psw; 26. public Integer getId() { 27. return id; 28. } 29. public void setId(Integer id) { 30. this.id = id; 31. } 32. 33. public String getUser() { 34. return user; 35. } 36. public void setUser(String user) { 37. this.user = user; 38. } 39. public String getPsw() { 40. return psw; 41. } 42. public void setPsw(String psw) { 43. this.psw = psw; 44. } 45.} Dao层实现 [java] view plaincopy 01.package com.mvc.dao; 02. 03.import java.util.List; 04. 05.public interface EntityDao { 06. public List<Object> createQuery(final String queryString); 07. public Object save(final Object model); 08. public void update(final Object model); 09. public void delete(final Object model); 10.} [java] view plaincopy 01.package com.mvc.dao; 02. 03.import java.util.List; 04. 05.import org.hibernate.Query; 06.import org.springframework.orm.hibernate3.HibernateCallback; 07.import org.springframework.orm.hibernate3.support.HibernateDaoSupport; 08. 09.public class EntityDaoImpl extends HibernateDaoSupport implements EntityDao{ 10. public List<Object> createQuery(final String queryString) { 11. return (List<Object>) getHibernateTemplate().execute( 12. new HibernateCallback<Object>() { 13. public Object doInHibernate(org.hibernate.Session session) 14. throws org.hibernate.HibernateException { 15. Query query = session.createQuery(queryString); 16. List<Object> rows = query.list(); 17. return rows; 18. } 19. }); 20. } 21. public Object save(final Object model) { 22. return getHibernateTemplate().execute( 23. new HibernateCallback<Object>() { 24. public Object doInHibernate(org.hibernate.Session session) 25. throws org.hibernate.HibernateException { 26. session.save(model); 27. return null; 28. } 29. }); 30. } 31. public void update(final Object model) { 32. getHibernateTemplate().execute(new HibernateCallback<Object>() { 33. public Object doInHibernate(org.hibernate.Session session) 34. throws org.hibernate.HibernateException { 35. session.update(model); 36. return null; 37. } 38. }); 39. } 40. public void delete(final Object model) { 41. getHibernateTemplate().execute(new HibernateCallback<Object>() { 42. public Object doInHibernate(org.hibernate.Session session) 43. throws org.hibernate.HibernateException { 44. session.delete(model); 45. return null; 46. } 47. }); 48. } 49.} Dao在applicationContext.xml注入 <bean id="entityDao" class="com.mvc.dao.EntityDaoImpl"> <property name="sessionFactory" ref="sessionFactory" /> </bean> Dao只有一个类的实现,直接供其它service层调用,如果你想更换为其它的Dao实现,也只需修改这里的配置就行了。 开始写view页面,WEB-INF/view下新建页面student.jsp,WEB-INF/view这路径是在spring-servlet.xml文件配置的,你可以配置成其它,也可以多个路径。student.jsp代码 [xhtml] view plaincopy 01.<%@ page language="java" contentType="text/html; charset=UTF-8" 02. pageEncoding="UTF-8"%> 03.<%@ include file="/include/head.jsp"%> 04.<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 05.<html> 06.<head> 07.<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 08.<title>添加</title> 09.<mce:script language="javascript" src="<%=request.getContextPath()%><!-- 10./script/jquery.min.js"> 11.// --></mce:script> 12.<mce:style><!-- 13.table{ border-collapse:collapse; } 14.td{ border:1px solid #f00; } 15.--></mce:style><style mce_bogus="1">table{ border-collapse:collapse; } 16.td{ border:1px solid #f00; }</style> 17.<mce:script type="text/javascript"><!-- 18.function add(){ 19. [removed].href="<%=request.getContextPath() %>/student.do?method=add"; 20.} 21. 22.function del(id){ 23.$.ajax( { 24. type : "POST", 25. url : "<%=request.getContextPath()%>/student.do?method=del&id;=" + id, 26. dataType: "json", 27. success : function(data) { 28. if(data.del == "true"){ 29. alert("删除成功!"); 30. $("#" + id).remove(); 31. } 32. else{ 33. alert("删除失败!"); 34. } 35. }, 36. error :function(){ 37. alert("网络连接出错!"); 38. } 39.}); 40.} 41.// --></mce:script> 42.</head> 43.<body> 44. 45.<input id="add" type="button" value="添加"/> 46.<table > 47. <tr> 48. <td>序号</td> 49. <td>姓名</td> 50. <td>密码</td> 51. <td>操作</td> 52. </tr> 53. <c:forEach items="${list}" var="student"> 54. <tr id="<c:out value="${student.id}"/>"> 55. <td><c:out value="${student.id}"/></td> 56. <td><c:out value="${student.user}"/></td> 57. <td><c:out value="${student.psw}"/></td> 58. <td> 59. <input type="button" value="编辑"/> 60. <input type="button" value="${student.id}"/>')" value="删除"/> 61. </td> 62. </tr> 63. </c:forEach> 64. 65.</table> 66.</body> 67.</html> student_add.jsp [xhtml] view plaincopy 01.<%@ page language="java" contentType="text/html; charset=UTF-8" 02. pageEncoding="UTF-8"%> 03.<%@ include file="/include/head.jsp"%> 04.<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 05.<html> 06.<head> 07.<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 08.<title>学生添加</title> 09.<mce:script type="text/javascript"><!-- 10.function turnback(){ 11. [removed].href="<%=request.getContextPath() %>/student.do"; 12.} 13.// --></mce:script> 14.</head> 15.<body> 16.<form method="post" action="<%=request.getContextPath() %>/student.do?method=save"> 17.<div><c:out value="${addstate}"></c:out></div> 18.<table> 19. <tr><td>姓名</td><td><input id="user" name="user" type="text" /></td></tr> 20. <tr><td>密码</td><td><input id="psw" name="psw" type="text" /></td></tr> 21. <tr><td colSpan="2" align="center"><input type="submit" value="提交"/><input type="button" value="返回" /> </td></tr> 22.</table> 23. 24.</form> 25.</body> 26.</html> controller类实现,只需把注解写上,spring就会自动帮你找到相应的bean,相应的注解标记意义,不明白的,可以自己查下@Service,@Controller,@Entity等等的内容。 [java] view plaincopy 01.package com.mvc.controller; 02. 03.import java.util.List; 04. 05.import javax.servlet.http.HttpServletRequest; 06.import javax.servlet.http.HttpServletResponse; 07. 08.import org.apache.commons.logging.Log; 09.import org.apache.commons.logging.LogFactory; 10.import org.springframework.beans.factory.annotation.Autowired; 11.import org.springframework.stereotype.Controller; 12.import org.springframework.ui.ModelMap; 13.import org.springframework.web.bind.annotation.RequestMapping; 14.import org.springframework.web.bind.annotation.RequestMethod; 15.import org.springframework.web.bind.annotation.RequestParam; 16.import org.springframework.web.servlet.ModelAndView; 17. 18.import com.mvc.entity.Student; 19.import com.mvc.service.StudentService; 20. 21.@Controller 22.@RequestMapping("/student.do") 23.public class StudentController { 24. protected final transient Log log = LogFactory 25. .getLog(StudentController.class); 26. @Autowired 27. private StudentService studentService; 28. public StudentController(){ 29. 30. } 31. 32. @RequestMapping 33. public String load(ModelMap modelMap){ 34. List<Object> list = studentService.getStudentList(); 35. modelMap.put("list", list); 36. return "student"; 37. } 38. 39. @RequestMapping(params = "method=add") 40. public String add(HttpServletRequest request, ModelMap modelMap) throws Exception{ 41. return "student_add"; 42. } 43. 44. @RequestMapping(params = "method=save") 45. public String save(HttpServletRequest request, ModelMap modelMap){ 46. String user = request.getParameter("user"); 47. String psw = request.getParameter("psw"); 48. Student st = new Student(); 49. st.setUser(user); 50. st.setPsw(psw); 51. try{ 52. studentService.save(st); 53. modelMap.put("addstate", "添加成功"); 54. } 55. catch(Exception e){ 56. log.error(e.getMessage()); 57. modelMap.put("addstate", "添加失败"); 58. } 59. 60. return "student_add"; 61. } 62. 63. @RequestMapping(params = "method=del") 64. public void del(@RequestParam("id") String id, HttpServletResponse response){ 65. try{ 66. Student st = new Student(); 67. st.setId(Integer.valueOf(id)); 68. studentService.delete(st); 69. response.getWriter().print("{/"del/":/"true/"}"); 70. } 71. catch(Exception e){ 72. log.error(e.getMessage()); 73. e.printStackTrace(); 74. } 75. } 76.} service类实现 [java] view plaincopy 01.package com.mvc.service; 02. 03.import java.util.List; 04. 05.import org.springframework.beans.factory.annotation.Autowired; 06.import org.springframework.stereotype.Service; 07.import org.springframework.transaction.annotation.Transactional; 08. 09.import com.mvc.dao.EntityDao; 10.import com.mvc.entity.Student; 11. 12.@Service 13.public class StudentService { 14. @Autowired 15. private EntityDao entityDao; 16. 17. @Transactional 18. public List<Object> getStudentList(){ 19. StringBuffer sff = new StringBuffer(); 20. sff.append("select a from ").append(Student.class.getSimpleName()).append(" a "); 21. List<Object> list = entityDao.createQuery(sff.toString()); 22. return list; 23. } 24. 25. public void save(Student st){ 26. entityDao.save(st); 27. } 28. public void delete(Object obj){ 29. entityDao.delete(obj); 30. } 31.} OK,例子写完。有其它业务内容,只需直接新建view,并实现相应comtroller和service就行了,配置和dao层的内容基本不变,也就是每次只需写jsp(view),controller和service调用dao就行了。 怎样,看了这个,spring mvc是不是比ssh实现更方便灵活。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值