Spring高级程序设计 17 基于Spring MVC的Web应用开发




1MVC架构

MVC是模型(model)、视图(view)、控制器(controller)。
有些应用需要处理用户请求并操纵和显示数据,MVC模式可以简化其实现。


该模式由3个组件构成:
1、模型表示用户希望看到的数据。通常情况下,模型由JavaBean构成。
2、视图负责显示模型。文件编辑器中的视图组件会以恰当的格式显示一段文本,视图在Web应用中会生成客户端浏览器可以解释显示的HTML。
3、控制器表示逻辑代码,负责处理请求和执行用户的意图。他会构建恰当的模型并将其传入视图进行显示。对Java Web应用来说,控制器多是一个Servlet。当然,控制器可以使用任意语言实现,只要Web容器支持就行。


2Spring MVC介绍

Spring MVC支持可以让我们使用MVC模式二构建灵活方便应用,他的实现相当通用。
模型就是一个包含数据的简单的Map,视图就是一个接口,由他实现显示数据,控制器是Controller接口的实现。


(Spring MVC不仅实现了Servlet,而且完全支持JSR 168 portlet开发)


Spring对Web应用下的MVC模式的实现基于DispatcherServlet。该Servlet会处理请求并调用恰当的控制元素对请求进行处理。
DispatcherServlet会拦截请求并决定由哪个控制器处理请求。Spring控制器的handling方法会返回一个ModelAndView实例。该实例持有对视图和模型的引用。模型就是一个简单的Map实例,他里面是JavaBean,View接口会显示这些JavaBean。View接口定义 render方法。他遵循这样的原则:View的实现可以是任何东西,只要客户端能对其进行解析就行。


MVC实现
MVC入口方式

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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_2_5.xsd">
	<display-name></display-name>

	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>*.html</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>*.tile</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

3使用处理器映射

org.springframework.web.servlet.HandlerMapping:
Interface to be implemented by objects that define a mapping between requests and handler objects. 


This class can be implemented by application developers, although this is not necessary, as org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping and org.springframework.web.servlet.handler.SimpleUrlHandlerMapping are included in the framework. The former is the default if no HandlerMapping bean is registered in the application context. 


HandlerMapping implementations can support mapped interceptors but do not have to. A handler will always be wrapped in a HandlerExecutionChain instance, optionally accompanied by some HandlerInterceptor instances. The DispatcherServlet will first call each HandlerInterceptor's preHandle method in the given order, finally invoking the handler itself if all preHandle methods have returned true. 


The ability to parameterize this mapping is a powerful and unusual capability of this MVC framework. For example, it is possible to write a custom mapping based on session state, cookie state or many other variables. No other MVC framework seems to be equally flexible. 


Note: Implementations can implement the org.springframework.core.Ordered interface to be able to specify a sorting order and thus a priority for getting applied by DispatcherServlet. Non-Ordered instances get treated as lowest priority.


HandlerMapping实现:
BeanNameUrlHandlerMapping:bean的名称由URL标识。如果URL为/product/index.html,那么我们就必须将处理该映射的控制器bean的ID设为/product/index.html。该映射很适合小型应用,因为他不支持请求的通配符。
SimpleUrlHandlerMapping:凭借该处理器映射,我们可以在请求中(使用全名和通配符)处理该请求的控制器。
ControllerClassNameHandlerMapping:该处理器 映射属于2.5引入的约定优于配置的方案。他会根据控制器的类名自动生成URL路径。


org.springframework.web.servlet.handler.AbstractHandlerMapping:
Abstract base class for org.springframework.web.servlet.HandlerMapping implementations. Supports ordering, a default handler, and handler interceptors. 


Note: This base class does not support exposure of the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE. Support for this attribute is up to concrete subclasses, typically based on request URL mappings.




上面三个最终实现类都继承了AbstractHandlerMapping,此类具有如下属性:
List interceptors:该属性表示使用的拦截器列表。
Object defaultHandler:在映射和处理器都不匹配的情况下,改属性指定了默认的处理器。
int order:Spring可以根绝order属性值对context中的所有处理器映射进行排序,并使用第一个匹配的处理器。


AbstractUrlHandlerMapping extends AbstractHandlerMapping:
UrlPathHelper urlPathHelper:借助于该属性,你可以通过UrlPathHelper来检查URL。
boolean lazyInitHandlers = false:改属性可以对单例(singleton)处理器进行延迟初始化(prototype处理器总是延迟初始化)。其默认值为false。


AbstractUrlHandlerMapping的实例变量UrlPathHelper urlPathHelper = new UrlPathHelper():
boolean alwaysUseFullPath = false:是否匹配全路径。
boolean urlDecode = true:默认false。HttpServletRequest会返回未经解码的URL和URI。如果希望在处理器出气之前进行解码,就改为true。默认是ISO-8859-1。




BeanNameUrlHandlerMapping配置:
(如果没有指定HandlerMapping,默认情况下DispatcherServlet会实例化BeanNameUrlHandlerMapping)

<beans>
	<bean name="index.html.form" class="MyIndexController"/>
</beans>



SimpleUrlHandlerMapping配置:

    <bean id="internalPathMethodNameResolver"
          class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver">
        <property name="suffix" value="Handler"/>
    </bean>
    <bean id="publicUrlMapping"
          class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <value>
                /index.html=indexController
                /exception/*.html=exceptionController
            </value>

        </property>
    </bean>
    <bean id="exceptionController"
          class="com.apress.prospring2.ch17.web.exception.ExceptionController">
        <property name="methodNameResolver" ref="internalPathMethodNameResolver"/>
    </bean>
    <bean id="indexController"
          class="com.apress.prospring2.ch17.web.IndexController">
    </bean>



4Spring控制器

控制器负责请求处理的一切:根据请求构建模型并将其传到视图以进行显示。
Spring的DispatcherServlet会拦截客户端发来的请求并使用HandlerAdapter的一个实现(该实现负责代理请求)做进一步的处理。 你可以自己实现HandlerAdapter,这样就可以对请求所经过的命令链进行修改了。
DispatcherServlet有一个List handlerAdapters属性,他可用来指定你想用的handlerAdapter实现。可以在自己的handlerAdapter中实现Ordered接口以指定顺序。
如果handlerAdapters为空,使用默认的SimpleControllerHandlerAdapter。
SimpleControllerHandlerAdapter会将请求代理给Controller接口的实现(action需要实现Controller接口)。
Controller接口依赖于HttpServletRequest和HttpServletResponse,这意味着你只能将其用在Web应用中。


helloworld:

package cn.partner4java.controller;

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

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class IndexController implements Controller {

	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.getWriter().println("hello,world");
		return null;
	}

}

1、AbstractController类
控制器只需要继承AbstractController而不用实现Controller接口就可以直接访问到ServletContext、WebApplicationContext、ApplicationContext、Log和MessageSourceAccessor。
WebContextGenerator和AbstractController属性:
supportedMethods -- 支持和容许HTTP方法  -- GET、POST
requiresSession -- 是否需要HttpSession实现来处理请求 -- false
useExpiresHeader -- 是否使用HTTP1.0 expires头   -- true
useCacheControlHeader -- 是否使用HTTP1.1 cache-control头 -- true
cacheSeconds -- 让客户端对生成的内容缓存指定的秒数 -- -1
synchronizeOnSession -- 调用handleRequestInternal前,控制器是否应该同步HttpSession实例。这对客户端可重用的请求处理的序列化非常有用   -- false


helloworld:

package cn.partner4java.controller;

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

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class IndexController2 extends AbstractController {

	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		setCacheSeconds(10);
		response.getWriter().println("hello world " + System.currentTimeMillis());
		return null;
	}

}

但是缓存不知道为什么不起作用




2、ParameterizableViewController
ParameterizableViewController extends AbstractController
它实现了handleRequestInternal方法以通过viewName属性中的名字返回新的模型。返回的模型中并没有数据,你使用控制器的唯一理由就是用其名字来显示视图。


helloworld:

package cn.partner4java.controller;

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

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.ParameterizableViewController;

/**
 * getViewName()可以配置进来
 * @author partner4java
 *
 */
public class IndexController3 extends ParameterizableViewController {

	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.getWriter().println("hello world");
		return null;
//		return new ModelAndView(getViewName());
	}
	
}





3、MultiActionController类
通过该Controller实现,你可以将多个URL映射到同一个控制器上并使用不同的方法来处理各种URL。
AbstractController的另两个属性--delegate和methodNameResolver用于告诉MultiActionController调用哪个对象的哪个方法来处理每个请求。
如果delegate为默认值或者null,控制器就会调用MultiActionController子类自己的方法;如果delegate属性不为null就会调用代理的方法。
methodNameResolver属性的值必须是MethodNameResolver的实现。
MethodNameResolver实现:
InternalPathMethodNameResolver -- 从路径的最后一部分(文件部分)获取方法名并去掉扩展名。在使用该解析器解析路径时会将/servlet/foo.html映射到方法public ModelAndView foo(..)上。这也是MultiActionController所用的默认实现。
ParameterMethodNameResolver -- 从特定的请求参数获取方法名。其默认的参数名是action,可以在context文件中修改。
PropertiesMethodNameResolver -- 从外部的属性文件中获取方法名。可以指定精确的映射规则,如/test.html=handleTest,还可以使用通配符,如/*=handleAll


以方法名作为请求匹配:

//http://localhost:8080/springmvc/index/view.html?productId=10
public class IndexController4 extends MultiActionController {

	public ModelAndView view(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		response.getOutputStream().println(
				"Viewing product" + request.getParameter("productId"));
		return null;
	}
}

	<bean id="publicUrlMapping"
		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<value>
				/index/view.html=indexController4
            </value>
		</property>
	</bean>
	<bean id="indexController4" class="cn.partner4java.controller.IndexController4"/>

以viewHandler方法名的方式调用(去掉扩展名,增加“Handler”字符串):
public class IndexController5 extends MultiActionController {

	public ModelAndView viewHandler(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		response.getOutputStream().println(
				"Viewing product" + request.getParameter("productId"));
		return null;
	}
}

	<bean id="publicUrlMapping"
		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<value>
				/product/view.html=indexController5
            </value>
		</property>
	</bean>

	<bean id="internalPathMethodNameResolver"
		class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver">
		<!-- Specify a common suffix for handler method names. Will be appended 
			to the internal path found in the URL: e.g. internal path "baz", suffix "Handler" 
			-> method name "bazHandler". -->
		<property name="suffix" value="Handler" />
	</bean>
	<bean id="indexController5" class="cn.partner4java.controller.IndexController5">
		<property name="methodNameResolver" ref="internalPathMethodNameResolver" />
	</bean>



可以通过设置paramName属性来改变这一点,可以将defaultMethodName属性设为调用的方法名:
//http://localhost:8080/springmvc/product/a.html?productId=131&method=view
//http://localhost:8080/springmvc/product/a.html?productId=131
public class IndexController6 extends MultiActionController {

	public ModelAndView view(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		response.getOutputStream().println(
				"Viewing product" + request.getParameter("productId"));
		return null;
	}
}

	<bean id="publicUrlMapping"
		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<value>
				/product/a.html=indexController6
            </value>
		</property>
	</bean>
	<bean id="parameterMethodNameResolver"
		class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
		<property name="paramName" value="method" />
		<property name="defaultMethodName" value="view" />
	</bean>
	<bean id="indexController6" class="cn.partner4java.controller.IndexController6">
		<property name="methodNameResolver" ref="parameterMethodNameResolver" />
	</bean>

	
	
从外部的属性文件中获取方法名:
//http://localhost:8080/springmvc/pro/viewpro.html?productId=22
public class IndexController7 extends MultiActionController {

	public ModelAndView view(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		response.getOutputStream().println(
				"Viewing product" + request.getParameter("productId"));
		return null;
	}
}

	<bean id="publicUrlMapping"
		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<value>
				/pro/viewpro.html=indexController7
			</value>
		</property>
	</bean>
	<bean id="propertiesMethodNameResolver"
		class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
		<property name="mappings">
			<value>
				/pro/view.html=view
				/pro/v*.html=view
			</value>
		</property>
	</bean>
	<bean id="indexController7" class="cn.partner4java.controller.IndexController7">
		<property name="methodNameResolver" ref="propertiesMethodNameResolver" />
	</bean>



5拦截器

HandlerInterceptor
提供默认实现HandlerInterceptorAdapter:
demo:
public class BigBrotherHandlerInterceptor extends HandlerInterceptorAdapter {

	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("BigBrotherHandlerInterceptor postHandle:"
				+ request.getContextPath());
	}

}

	<bean id="bigBrotherHandlerInterceptor" class="cn.partner4java.interceptor.BigBrotherHandlerInterceptor"/>

	<bean id="publicUrlMapping"
		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="interceptors">
			<list>
				<ref local="bigBrotherHandlerInterceptor"/>
			</list>
		</property>
		<property name="mappings">
			<value>
				/index.html=indexController
			</value>
		</property>
	</bean>



6视图、本地化和主题

以编程的方式使用试图:
客户端必须实现View接口的唯一方法--render(Map model, HttpServletRequest request, HttpServletResponse response)

demo:
public class PlainTextView implements View {

	public String getContentType() {
		return "text/plain";
	}

	public void render(Map model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
        response.setContentType("text/plain");
        response.addHeader("Content-disposition", "attachment; filename=output.txt");
        PrintWriter writer = response.getWriter();
        for(Iterator k = model.keySet().iterator();k.hasNext();){
        	Object key = k.next();
        	writer.print(key);
        	writer.println(" contains:");
        	writer.println(model.get(key));
        }
	}

}

public class IndexController8 extends MultiActionController {
	private View view;

	public ModelAndView view(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		setCacheSeconds(10);
		Map model = new HashMap();
		model.put("Greeting", "hello world");
		model.put("Server time", new Date());
		
		return new ModelAndView(view, model);
	}

	public void setView(View view) {
		this.view = view;
	}
}


	<bean id="publicUrlMapping"
		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="interceptors">
			<list>
				<ref local="bigBrotherHandlerInterceptor"/>
			</list>
		</property>
		<property name="mappings">
			<value>
				/index8/view.html=indeController8
			</value>
		</property>
	</bean>
	<bean id="plainTextView" class="cn.partner4java.view.PlainTextView"/>
	<bean id="indeController8" class="cn.partner4java.controller.IndexController8">
		<property name="view" ref="plainTextView"/>
	</bean>
	
	
	
使用试图解析器:
ViewResolver是一种策略接口,SpringMVC会根绝视图名和locale使用它来寻找并实例化恰当的视图。
ViewResolver的实现:
BeanNameViewResolver:这个简单的实现会以bean的形式得到配置在applicationContext中的View。
ResourceBundleViewResolver:将视图定义在单独的配置文件中,这样就无需在applicationContext文件中配置View bean了。支持国际化。
UrlBasedViewResolver:根绝URL实例化恰当的视图,我们可以使用前缀和后缀来配置URL。不支持国际化。
XmlViewResolver:解析类似于ResourceBundleViewResolver,也需要将视图定义放在单独的文件中。不支持国际化。

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
        <property name="basename" value="views"/>
    </bean>

那么就会有views.properties默认或者其他语言的  messages.properties
properties格式:
products-edit.class=org.springframework.web.servlet.view.JstlView
products-edit.url=/WEB-INF/views/en_GB/product/edit.jsp
#products-edit.class=org.springframework.web.servlet.view.freemarker.FreeMarkerView
#products-edit.url=product/edit.ftl
#products-edit.class=org.springframework.web.servlet.view.velocity.VelocityView
#products-edit.url=product/edit.vm

controller调用方式:
    public ModelAndView index(HttpServletRequest request,
                              HttpServletResponse response) {

        return new ModelAndView("products-index", "products", products);
    }


使用本地化消息:
通过spring:message标签呈现。


使用Locale:
ResourceBundleViewResolver国际化底层实现方式,Spring使用LocalResolver接口拦截请求并调用其方法来读取和设置Locale。
LocaleResolver实现:
AcceptHeaderLocaleResolver:根据用户发送的accept-language头返回。
CookieLocaleResolver:根绝客户端的cookie来识别,用户可以指定语言无需改变浏览器。
FixedLocaleResolver:返回配置好的。
SessionLocaleResolver:类似于cookie。

使用主题:
    <bean id="themeResolver"
          class="org.springframework.web.servlet.theme.FixedThemeResolver">
        <property name="defaultThemeName">
            <value>cool</value>
        </property>
    </bean> 
cool.properties
default.properties

<link rel="stylesheet" href="<spring:theme code="css"/>">



7命令控制器

命令控制器可以通过表单提交来组装命令对象的属性。由于命令控制器会与Spring标签库紧密协作来简化数据验证,因此在其中执行业务验证再适合不过了。
AbstractCommandController:用来提供对验证和数据绑定的基本支持,你可以用它来实现自己的命令控制器。
AbstractFormController:继承自AbstractCommandController,可以处理html表单提交。处理request中的值并将其组装成控制器的命令对象。还能检测表单的重复提交,同时还可以在代码而不是Spring context文件中指定显示的视图。有一个有用的方法Map referenceData(),他为表单视图返回模型对象(java.util.Map类型)。在该方法中,你可以轻松传递用于表单页面的参数。
SimpleFormController:你可以指定初始和随后的视图,同时还可以用提交的数据来设定需要组装的命令对象。
AbstractWizardFormController:有助于实现向导式的页面集,因为他必须放在当前的HttpSession中,这样你需要实现validatePage()方法来检查当前页面上的数据是否有效以及向导是否可以进入到下一个界面。最后会会调用processFinish()方法,以表明其完成了向导的最后一个界面,同时也表明数据是有效的,可以传到业务层。但是Spring建议使用Spring Web Flow替代本使用。


1、使用表单控制器
2、探索AbstractWizardFormController类
3、文件上传


(具体本节内容查看P567-P580)




8处理异常

Spring提供了HandlerExceptionResolver来处理控制器中的异常。
提供的开箱方式:
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="defaultErrorView" value="defaultErrorView"/>
	<property name="exceptionMappings">
		<props>
			<prop key="java.lang.NullPointerException">nullPointerErrorView</prop>
			<prop key="javax.servlet.ServletException">servletErrorView</prop>
		</props>
	</property>
</bean>


自己实现:
public class ApressExceptionResolver implements HandlerExceptionResolver {

	public ModelAndView resolveException(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex) {
		Map<String, Object> model = new HashMap<String, Object>();
		model.put("message", ex.getMessage());
		return new ModelAndView("/exception.jsp", model);
	}

}
配置很简单,你只需要定义一个实现了HandlerExceptionResolver的bean就可以,id都可以省略,spring就会那他来处理异常。(约定优于配置,后面还很多这种用法)
<bean id="exceptionResolver" class="cn.partner4java.ApressExceptionResolver"/>



9Spring与其他Web技术

1、使用JSP
2、使用Velocity
3、FreMarker
4、使用XSLT视图
5、使用PDF视图
6、实现PDF视图
7、使用Excel视图
8、使用Tiles
9、JasperReports报表引擎


(具体查看P583-P626)




10Spring的约定优于配置

控制器约定:
Spring2.0提供了ControllerClassHandlerMapping类,实现了HandlerMapping接口。
该类根绝Spring配置文件中控制器类的名字将请求URL映射到控制器类上。

demo:
会匹配去掉Controller的类名的路径
//http://localhost:8080/springmvc/defaulttest.html
//http://localhost:8080/springmvc/defaulttestwwwwwwwww.html
public class DefaultTestController implements Controller {


	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		return new ModelAndView("/test/mytest.vm");
	}

}
配置文件就两行:
	<bean
		class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
	<bean class="cn.partner4java.controller.DefaultTestController" />

	
	
MultiActionController约定:
Demo:
//http://localhost:8080/springmvc/defaulttest2/view.html
public class DefaultTest2Controller extends MultiActionController {

	public ModelAndView view(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		return new ModelAndView("/test/mytest.vm");
	}

}

	<bean
		class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
	<bean class="cn.partner4java.controller.DefaultTest2Controller"/>	

还可以像Controller一样给予一个统一方法后缀:
public ModelAndView viewHandler

	<bean id="internalPathMethodNameResolver"
		class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver">
		<!-- Specify a common suffix for handler method names. Will be appended 
			to the internal path found in the URL: e.g. internal path "baz", suffix "Handler" 
			-> method name "bazHandler". -->
		<property name="suffix" value="Handler" />
	</bean>
	<bean id="indexController5" class="cn.partner4java.controller.IndexController5">
		<property name="methodNameResolver" ref="internalPathMethodNameResolver" />
	</bean>	
	



模型约定:
ModelAndView引入的private ModelMap model;(ModelMap extends LinkedHashMap),就是只需要写入数据,具体数据对应的存储名称是什么,根据变量名字生成,首字母小写。



视图约定:
就是会自动识别视图,如果返回的ModelAndView并没有指定
public class DefaultTest3Controller extends MultiActionController {

	public ModelAndView view(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		return new ModelAndView();
	}
}

	<bean id="viewNameTranslator" 
		class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator" />
	<bean
		class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
	<bean class="cn.partner4java.controller.DefaultTestController" />
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"/>
		<property name="suffix" value=".jsp"/>
	</bean>

创建文件/WebRoot/WEB-INF/views/defaulttest3/view.jsp
最后会访问到上面的view.jsp	
	


11使用注解配置控制器

@Controller注解:
@Controller注解简化了控制类的声明。无需再去实现Controller接口或继承任何Spring的控制器类,甚至都无需引用Servlet API了。
@Controller
public class IndexController {
...
}
<context:component-scan base-package="cn.partner4java.controller"/>

======================

@RequestMapping注解:
用于将URL映射到控制器类或特定的方法上。
@Controller
@RequestMapping("/index/ann.html")
public class IndexController {
	
	@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
	public ModelAndView displayIndex(HttpServletRequest request,
            HttpServletResponse response){
		return new ModelAndView("/index.jsp");
	}
}
或
@Controller
public class IndexController2 {
	
	@RequestMapping("/index2/ann.html")
	public ModelAndView displayIndex(HttpServletRequest request,
            HttpServletResponse response){
		return new ModelAndView("/index.jsp");
	}
}


===============

@RequestParam注解:
用于将控制器的请求参数绑定到控制器中的方法参数上。
(注意返回类型可以变为了String)
//http://localhost:8080/springmvc/index3/ann.html?productId=12
@Controller
public class IndexController3 {
	
	@RequestMapping("/index3/ann.html")
	public String displayIndex(@RequestParam("productId") int productId,
			ModelMap model){
		model.put("productId", productId);
		return "/index.jsp";
	}
}

前台获取:${productId }


===============

@ModelAttribute注解:
一:如果方法返回的类型需要用到模型中,可以使用本注解。该注解会用方法的返回值来组装模型属性,这是通过其参数和模型名实现的。
	@ModelAttribute("types")
	public Collection<String> populateProductTypes() {
        List<String> types = new ArrayList<String>();
        types.add("Books");
        types.add("CDs");
        types.add("MP3 Players");

        return types;
    }
二:用于方法参数上,特定名称的模型属性就会映射到方法参数上。
	@RequestMapping(method = RequestMethod.POST)
	public String processSubmit(@ModelAttribute("product")Product product, BindingResult result,
			SessionStatus status) {

	    System.out.println(product);

        return "products-index";
	}


参数也可以随意加入:
	@RequestMapping("/index3/ann3.html")
	public String displayIndex3(@ModelAttribute("product") Product product,
			BindingResult result,SessionStatus status,ModelMap model2){
		System.out.println(result.hasErrors());
		model2.put("product", product);
		return "/index.jsp";
	}	




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值