推荐淘宝秋冬男装热卖网店

追求无止境

我的程序人生
随笔 - 31, 文章 - 2, 评论 - 20, 引用 - 0
数据加载中……

2009年11月20日

有一天你会长大

什么话该说,什么话不该说,该说的话该怎么说。谁能告诉我。

posted @ 2010-01-19 13:21 追求无止境 阅读(196) | 评论 (0)编辑 收藏

2009年度盛事 - 总结2009

       2009年12月31日,站在2009年的尾巴上,不禁感到时间飞逝。2009年,匆匆而过。在过去的2009年,收获何多,失去何多。2009年,对我来说,是一个重要的转折点。渐渐的发现自己应该长大了,也发现自己确实长大了,更发现自己实际上还是需要继续长大。

      每年的这个时候,各个新闻媒体都会评出什么十大之类的,我也落一会俗(当然自己本身就很俗),来看看今年发生在我身上的几大事件:

先大体罗列一下吧:

  1. 订婚
  2. 进京
  3. 工作
  4. 毕业
  5. 读研
  6. 买笔记本

     从时间跨度上来说, 1月到2月在家过年,2月和3月在青岛某公司实习,4月和5月在北京某公司实习,6月在中国石油大学享受毕业之前的时光,7月到8月继续在北京某公司实习,9月到12月在上学+实习。2009年最幸福的事情发生在1到2月,尽快也有不快;最平常的日子在2月和3月,到了4月和5月或许是我最纠结的日子吧;6月或许是最快乐的日子的吧;7月和8月让我体会到了工作的滋味;而9月到12月,整天在公司与学校之间奔跑,知道了工作+上课两者要做到兼顾的滋味,虽然并没有做到兼顾。

     2009年大体经历如此。2009年对我最大的关键字或许就是“改变”,这一年我订婚了,在这一点上,改变了我的准非单身状态;在这一年,我实习了,而且大量的时间都在于此,改变了我仅仅是学生的状态;在这一年,我毕业了,我离开了生活学习四年的中国石油大学,离开了让我毕生难忘的日子;在这一年,我来北京了,从对北京的一无所知,到开始的彷徨,然后渐渐熟悉和适应;在这一年,我的经济渐渐独立,尽管每个月只有不到1000的收入,但能满足的我的基本需求;在这一年,我买了笔记本,虽然对其他人来说,这不是一件特别的事,对我来说,因采用了分期付款,而用接下来一年中近半个月的工资来还,但我不觉得后悔,在这个过程中,我的经济观念和理财观念开始渐渐改变;在这一年,工作成了我的核心,工作教会我很多东西,在与人交流、在工作态度、在技术上,都有一定的提高。

     回忆2009年,收获颇多,也失去不少。但日子总是向前的,有得必有失。希望在以后的2009年,自己能够渐渐提高自己的能力。无论是在生活上,在工作上,还是在心理上。

 

    2009年10大大事:

       与老婆订婚:

       2009年,

posted @ 2009-12-31 12:55 追求无止境 阅读(200) | 评论 (0)编辑 收藏

Spring web MVC 框架学习笔记 之 ViewResolver技术

上次的文章中介绍了ModelAndView对象中的view对象,可以使用字符串来让Spring框架进行解析获得适合的视图。而解析View的就是ViewResolver技术。

ViewResolver的定义如下:

public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}
 
在[spring-dispatcher-name]-servlet.xml中,可以定义viewResolver:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

来让DispacherServlet进行加载默认的viewResolver,如果没有设置viewResolver,spring使用InternalResourceViewResolver进行解析。

Spring实现ViewResolver的非抽象类且我们经常使用的viewResolver有以下四种:

InternalResourceViewResolver 将逻辑视图名字解析为一个路径
BeanNameViewResolver 将逻辑视图名字解析为bean的Name属性,从而根据name属性,找定义View的bean
ResourceBundleResolver 和BeanNameViewResolver一样,只不过定义的view-bean都在一个properties文件中,用这个类进行加载这个properties文件
XmlViewResolver 和ResourceBundleResolver一样,只不过定义的view-bean在一个xml文件中,用这个类来加载xml文件

 

使用多视图解析器:

我们不想只使用一种视图解析器的话,可以在[spring-dispatcher-name]-servlet.xml定义多个viewResolver:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

<bean id=”beanNameViewResolver” class=”...BeanNameViewResolver”>
<property name="order" value="1"></property>
</bean>

<bean id=”beanNameViewResolver” class=”...XmlViewResolver”>
<property name="order" value="0"></property>
</bean>

DispatcherServlet会加载所有的viewResolver到一个list中,并按照优先级进行解析。注意order中的值越小,优先级越高。而id为viewResolver

的viewResolver的优先级是最低的。

posted @ 2009-11-27 12:11 追求无止境 阅读(6869) | 评论 (1)编辑 收藏

Spring MVC框架学习笔记 之 View技术

以前,我们详细介绍了Spring的Controller技术。Spring的面向接口编程,使Controller的实现多种多样。View技术也一样。今天的分析先从在Controller中的ModelAndView开始。

public class ModelAndView {     
  private Object view; //View实例或者view的字符串    
/** Model Map */  
  private ModelMap model; //model
 /* * Convenient constructor when there is no model data to expose.     * Can also be used in conjunction with <code>addObject</code>.    
 * @param view View object to render   
  * @see #addObject     */  
 public ModelAndView(View view) {        
    this.view = view;    
}
public ModelAndView(String viewName){ 
   this.view = viewName;
}

 
可以看到view实例可以指向一个View对象或者字符串。现在先看看View接口:
public interface View { 

    /**
     * Return the content type of the view, if predetermined.
     * <p>Can be used to check the content type upfront,
     * before the actual rendering process.
     * @return the content type String (optionally including a character set),
     * or <code>null</code> if not predetermined.
     */
    String getContentType(); 

    /**
     * 绘制视图
     * 绘制视图的第一步是准备请求: 如果是JSP的视图技术
     * 首先会把model设为request的属性。
     * 第二步则是真正的绘制视图
     * @param model Map with name Strings as keys and corresponding model
     * objects as values (Map can also be <code>null</code> in case of empty model)
     * @param request current HTTP request
     * @param response HTTP response we are building
     * @throws Exception if rendering failed
     */
    void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception; 

}
在这之后,我们再来看看View的实现继承类图,可以看到Spring支持多种类型视图:

org.springframework.web.servlet.view.AbstractView (implements org.springframework.beans.factory.BeanNameAware, org.springframework.web.servlet.View)

  • org.springframework.web.servlet.view.document.AbstractExcelView
  • org.springframework.web.servlet.view.document.AbstractJExcelView
  • org.springframework.web.servlet.view.document.AbstractPdfView
  • org.springframework.web.servlet.view.AbstractUrlBasedView (implements org.springframework.beans.factory.InitializingBean)
    • org.springframework.web.servlet.view.jasperreports.AbstractJasperReportsView
      • org.springframework.web.servlet.view.jasperreports.AbstractJasperReportsSingleFormatView
        • org.springframework.web.servlet.view.jasperreports.ConfigurableJasperReportsView
        • org.springframework.web.servlet.view.jasperreports.JasperReportsCsvView
        • org.springframework.web.servlet.view.jasperreports.JasperReportsHtmlView
        • org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
        • org.springframework.web.servlet.view.jasperreports.JasperReportsXlsView
      • org.springframework.web.servlet.view.jasperreports.JasperReportsMultiFormatView
    • org.springframework.web.servlet.view.document.AbstractPdfStamperView
    • org.springframework.web.servlet.view.AbstractTemplateView
      • org.springframework.web.servlet.view.freemarker.FreeMarkerView
      • org.springframework.web.servlet.view.velocity.VelocityView
        • org.springframework.web.servlet.view.velocity.VelocityToolboxView
          • org.springframework.web.servlet.view.velocity.VelocityLayoutView
    • org.springframework.web.servlet.view.InternalResourceView
      • org.springframework.web.servlet.view.JstlView
      • org.springframework.web.servlet.view.tiles.TilesView
        • org.springframework.web.servlet.view.tiles.TilesJstlView
    • org.springframework.web.servlet.view.RedirectView
    • org.springframework.web.servlet.view.tiles2.TilesView
    • org.springframework.web.servlet.view.xslt.XsltView
  • org.springframework.web.servlet.view.xslt.AbstractXsltView
 
和Controller一样,View的第一个实现也是AbstractView。所以先让我们看看AbstractView对render函数的实现:

 

public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
" and static attributes " + this.staticAttributes);
}

// Consolidate static and dynamic model attributes.
Map mergedModel = new HashMap(this.staticAttributes.size() + (model != null ? model.size() : 0));
mergedModel.putAll(this.staticAttributes);
if (model != null) {
mergedModel.putAll(model);
}

// Expose RequestContext?
if (this.requestContextAttribute != null) {
mergedModel.put(this.requestContextAttribute, createRequestContext(request, mergedModel));
}

prepareResponse(request, response);
renderMergedOutputModel(mergedModel, request, response);
}

第一步,将静态属性和model的属性都添加到mergedModel里面。如果需要请求上下文,则将请求上下文添加到model中。

静态属性是继承AbstractView进行设置的属性。而请求上下文如果设置的名字就会创建一个request上下文。在requestContext中定义了一些包括本地化和主题的处理工具。

第二步,对响应进行预处理。最后调用子类需要实现的函数renderMergedOutputModel。

对PDF和EXCEL格式我们暂且不管,且Spring支持多种视图技术,这里我们主要关注JSTL技术,

接着我们来看AbstractUrlBasedView 类。在AbstractUrlBasedView 只定义了一个url属性。别的没有什么特殊处理。

接着继承AbstractUrlBasedView 的是InternalResourceView。他对renderMergedOutputModel进行实现,实现如下:

/**
* Render the internal resource given the specified model.
* This includes setting the model as request attributes.
*/
protected void renderMergedOutputModel(
Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {

// 获取要暴露的request,一般都是传入的参数request
HttpServletRequest requestToExpose = getRequestToExpose(request);

// 将model的数据添加到request属性中
        exposeModelAsRequestAttributes(model, requestToExpose);

// 设置helper,如果存在的话
exposeHelpers(requestToExpose);

// 对绘制进行预处理,从而获得到要分发的url
String dispatcherPath = prepareForRendering(requestToExpose, response);

// 获取请求分发对象
RequestDispatcher rd = requestToExpose.getRequestDispatcher(dispatcherPath);
if (rd == null) {
throw new ServletException(
"Could not get RequestDispatcher for [" + getUrl() + "]: check that this file exists within your WAR");
}

// 决定使用RequestDispatcher的include方法还是forward方法
if (useInclude(requestToExpose, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.include(requestToExpose, response);
}

else {
// Note: The forwarded resource is supposed to determine the content type itself.
exposeForwardRequestAttributes(requestToExpose);
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.forward(requestToExpose, response);
}
}
可以看到InternalResourceView对请求进行了转发。转发到url上。最后我们看看JSTLView的实现:

 
public class JstlView extends InternalResourceView {

    private MessageSource messageSource;

    public JstlView() {
    }

    
    public JstlView(String url) {
        super(url);
    }

    public JstlView(String url, MessageSource messageSource) {
        this(url);
        this.messageSource = messageSource;
    }

    protected void initServletContext(ServletContext servletContext) {
        if (this.messageSource != null) {
            this.messageSource = JstlUtils.getJstlAwareMessageSource(servletContext, this.messageSource);
        }
        super.initServletContext(servletContext);
    }

    protected void exposeHelpers(HttpServletRequest request) throws Exception {
        if (this.messageSource != null) {
            JstlUtils.exposeLocalizationContext(request, this.messageSource);
        }
        else {
            JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext()));
        }
    }

}

 

在InternalResourceView  中,基本上所有的处理都差不多了。在JSTLView对两个方法进行了覆盖。第一个initServletContext,主要初始化了MessageResource

第二个exposeHelpers将messageSource放在了request里面。

这样view的解析就结束了。接下来容器对jsp进行解析,并进行tag等的处理。然后将生成的页面返回给客户端。

posted @ 2009-11-26 13:25 追求无止境 阅读(8199) | 评论 (2)编辑 收藏

SpringMVC web框架学习 Controller 分析

org.springframework.web.servlet.mvc.AbstractController (implements org.springframework.web.servlet.mvc.Controller)

Spring MVC框架中的Controller对请求进行处理:所有的Controller都实现接口Controller:

public interface Controller { 

    /**
     * Process the request and return a ModelAndView object which the DispatcherServlet
     * will render. A <code>null</code> return value is not an error: It indicates that
     * this object completed request processing itself, thus there is no ModelAndView
     * to render.
     * @param request current HTTP request
     * @param response current HTTP response
     * @return a ModelAndView to render, or <code>null</code> if handled directly
     * @throws Exception in case of errors
     */
    ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; 

}
上面的doc表明Controller返回的modelandview可以使空,表明请求都是该函数中处理完成了,不需要modeland来进行渲染。
 
在继续之前先介绍一个有用的工具类:WebUtils。用这个可以简化session,request的处理。具体的内容可以参考文档。
 
Controller的第一个实现是:AbstractController。他是一个Abstract类,除了实现了Controller接口,它还继承了WebContentGenerator。
 
WebContentGenerator的作用是什么?参考文档可以发现,该类主要对Cache和Session进行管理。
 
cacheSeconds 指定内容缓存的时间,默认为1
requireSession 是否需要会话,默认支持
supportedMethods 支持的方法,默认是GET\post\Head
useCacheControlHeader 指定是否使用http1.1的cache控制头信息,默认使用
useCacheControlNoStore 指定是否设置http1.1的cache控制头信息为no-store。默认使用
useExpiresHeader 指定是否使用http1.0的expire头信息。默认使用
用户可以对这些参数进行测试,cache和expire信息涉及到了http协议信息,更多信息可以参考http协议文档。这里不再说明。
 
再看AbstractController的代码:
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {

// Delegate to WebContentGenerator for checking and preparing.
checkAndPrepare(request, response, this instanceof LastModified);

// Execute handleRequestInternal in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return handleRequestInternal(request, response);
}
}
}
return handleRequestInternal(request, response);
}
checkandPrepare的目的就是使用用于进行的配置来对request进行预处理和准备。
他会检查支持的方法,和会话,然后应用cache设置。
如果需要session同步,就进行同步处理。session同步应用于有session的情况下。如果没有session,session同步是没有用的。
AbstractController会调用handleRequestInternal方法进行处理,继承AbstractController的类需要实现该方法。
下面我们再看看AbstractUrlViewController 的代码实现和文档,先看handleRequestInternal的实现:

 
/**
* Retrieves the URL path to use for lookup and delegates to
* {@link #getViewNameForRequest}.
*/
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
String viewName = getViewNameForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Returning view name '" + viewName + "' for lookup path [" + lookupPath + "]");
}
return new ModelAndView(viewName);
}

可以看到,它使用了getViewNameForRequest获取需要的viewName。而getViewNameForRequest是一个抽象函数,需要子类实现。lookupPath就是我们请求的URL中的一部分。如我们使用UrlFilenameViewController来进行如下的配置:
<bean name="/index.do" class="org.springframework.web.servlet.mvc.UrlFilenameViewController"></bean>、
09-11-25 11:56:06 - DEBUG [http-8200-1] - Returning view name 'index' for lookup path [/index.do]
该Controller对/index.do解析成index,然后再通过viewResolver对index进行扩展为/jsp/index.jsp。从而找到该页面。
可以看到这个类的主要是用于对url进行解析,然后转到合适的页面上,而在转到这个页面之前不需要进行特别的处理。
明白了该类的作用自然也就知道了UrlFilenameViewController的作用。这里不再进行详细分析。
 
 

posted @ 2009-11-26 09:35 追求无止境 阅读(4154) | 评论 (0)编辑 收藏

Spring MVC 框架学习之AbstractFormController以及AbstractFormControll

在看完BaseCommandController和AbstractCommandController之后,我们再看BaseCommandController的另一个实现AbstractFormController,以及AbstractFormController的具体实现SimpleFormController。

先看看AbstractFormController对handleRequestInternal的实现:

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// Form submission or new form to show?
if (isFormSubmission(request)) {
// Fetch form object from HTTP session, bind, validate, process submission.
try {
Object command = getCommand(request);
ServletRequestDataBinder binder = bindAndValidate(request, command);
BindException errors = new BindException(binder.getBindingResult());
return processFormSubmission(request, response, command, errors);
}
catch (HttpSessionRequiredException ex) {
// Cannot submit a session form if no form object is in the session.
if (logger.isDebugEnabled()) {
logger.debug("Invalid submit detected: " + ex.getMessage());
}
return handleInvalidSubmit(request, response);
}
}
else {
// New form to show: render form view.
return showNewForm(request, response);
}
}
这个方法,首先判断是不是Form提交,判断方法是:
protected boolean isFormSubmission(HttpServletRequest request) {
return "POST".equals(request.getMethod());
}
如果是form提交的话,系统首先创建一个Command,然后对数据进行绑定和验证,之后调用processFormSubmission方法。showNewForm则调用showForm。
在AbstractFormController中里面有两个抽象方法:

protected abstract ModelAndView processFormSubmission(
HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)
throws Exception;
protected abstract ModelAndView showForm(
HttpServletRequest request, HttpServletResponse response, BindException errors)
throws Exception;



 

 

好了,看完AbstractFormController之后,再看看SimpleFormController是如何实现:

protected ModelAndView processFormSubmission(
HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)
throws Exception {

if (errors.hasErrors()) {
if (logger.isDebugEnabled()) {
logger.debug("Data binding errors: " + errors.getErrorCount());
}
return showForm(request, response, errors);
}
else if (isFormChangeRequest(request, command)) {
logger.debug("Detected form change request -> routing request to onFormChange");
onFormChange(request, response, command, errors);
return showForm(request, response, errors);
}
else {
logger.debug("No errors -> processing submit");
return onSubmit(request, response, command, errors);
}
}
在上面的方法中,如果有错误,调用showForm,来显示form。没有错误的话,则调用onSubmit方法。
protected final ModelAndView showForm(
HttpServletRequest request, BindException errors, String viewName, Map controlModel)
throws Exception {

// In session form mode, re-expose form object as HTTP session attribute.
// Re-binding is necessary for proper state handling in a cluster,
// to notify other nodes of changes in the form object.
if (isSessionForm()) {
String formAttrName = getFormSessionAttributeName(request);
if (logger.isDebugEnabled()) {
logger.debug("Setting form session attribute [" + formAttrName + "] to: " + errors.getTarget());
}
request.getSession().setAttribute(formAttrName, errors.getTarget());
}

// Fetch errors model as starting point, containing form object under
// "commandName", and corresponding Errors instance under internal key.
Map model = errors.getModel();

// Merge reference data into model, if any.
Map referenceData = referenceData(request, errors.getTarget(), errors);
if (referenceData != null) {
model.putAll(referenceData);
}

// Merge control attributes into model, if any.
if (controlModel != null) {
model.putAll(controlModel);
}

// Trigger rendering of the specified view, using the final model.
return new ModelAndView(viewName, model);
}
在showForm中,设置属性,放在model中,然后在viewName进行设置。
FormController就是上面的过程。具体的执行过程和详细信息会在以后的博客中具体介绍。

posted @ 2009-11-25 17:31 追求无止境 阅读(2439) | 评论 (0)编辑 收藏

Spring MVC 框架学习笔记之BaseCommandController和AbstractCommandController

 

Spring的BaseCommandController继承自AbstractController。在看BaseCommandController之前先看他的继承类AbstractCommandController是如何实现

AbstractController的handleInternalRequest方法的:

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
Object command = getCommand(request);
ServletRequestDataBinder binder = bindAndValidate(request, command);
BindException errors = new BindException(binder.getBindingResult());
return handle(request, response, command, errors);
}

getCommand就是BaseCommandController中的方法。

protected Object getCommand(HttpServletRequest request) throws Exception {
return createCommand();
}
protected final Object createCommand() throws Exception {
if (this.commandClass == null) {
throw new IllegalStateException("Cannot create command without commandClass being set - " +
"either set commandClass or (in a form controller) override formBackingObject");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating new command of class [" + this.commandClass.getName() + "]");
}
return BeanUtils.instantiateClass(this.commandClass);
}

createCommand创建了一个CommandClass的对象。

然后再看bindAndValidate方法:

protected final ServletRequestDataBinder bindAndValidate(HttpServletRequest request, Object command)
throws Exception {
ServletRequestDataBinder binder = createBinder(request, command);
BindException errors = new BindException(binder.getBindingResult());
if (!suppressBinding(request)) {
binder.bind(request);
onBind(request, command, errors);
if (this.validators != null && isValidateOnBinding() && !suppressValidation(request, command, errors)) {
for (int i = 0; i < this.validators.length; i++) {
ValidationUtils.invokeValidator(this.validators[i], command, errors);
}
}
onBindAndValidate(request, command, errors);
}
return binder;
}

这个方法首先创建了 DataBinder对象,然后,获取创建绑定对象时发生的错误。报错在errors。接下来绑定对象,调用onBind处理绑定事件;接下来应用Validator。然后调用onBindAndValidate来处理绑定和验证事件。最后返回binder。

处理完之后调用handle方法进行处理。

综上所述,AbstractCommandController具有两个功能:

1、将请求参数转换为Command对象。在该Controller中,我们设置一个object对象。然后BaseCommandController将请求的参数进行转换。如果请求参数有value值,就会调用object的的setValue对象来设置对象里的值。如果请求参数中有address.city.就会调用object中getAddress().setCity()方法来赋值。这个object可以是任意的object,唯一的要求就是这个object类没有参数。

2、对数据进行验证。在转换和验证时发生错误时,需要在handle(request, response, command, errors)中进行处理。

posted @ 2009-11-25 16:25 追求无止境 阅读(5368) | 评论 (0)编辑 收藏

Spring的MVC web框架学习笔记

1、Spring web 框架的核心:DispatcherServlet

DispatcherServlet 用于接收请求。是使用Spring框架的入口。在web.xml中,需要配置该servlet。在配置该Servlet的时候url-pattern你可以使用你自己想使用的形式,如*.aspx,*.do,*.htm,*.action,用以混淆客户端对服务器架构的认识。

另外,该Servlet在容器中还会加载一个APPlicationContext的xml文件。默认加载的是[servlet-name]-servlet.xml。例如,你在web.xml中配置的servlet如下:

<web-app>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>*.form</url-pattern>
</servlet-mapping>
</web-app>
该Servlet就会在服务器启动时,加载example-servlet.xml。当然,你也可以自己来指定加载文件。
要看看DispatcherServlet真面目,打开源文件,发现定义了很多BeanName的常量,如本地化解析器beanname,主题解析器beanname,视图解析器beanname,上传文件解析的multipart解析器beanname。
等:
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
这个类怎么使用这些bean呢?以上面的exexample-servlet.xml为例,我们定义的名字为example的DispatcherServlet使用example-servlet.xml的配置。在example-servlet.xml里,我们可以配置名字上面的beanName的bean,来让servlet加载这些bean。
这下明白了,servlet.xml该怎么配置,该配置什么了。
好了,看完了最重要的servlet的配置问题,我们再看下一个重要的接口:Controller。至于上面servlet要使用的什么什么解析器啦,我们稍后在分析。
 
2、Controller
我们的请求提交到DispacherServlet后,会转给Controller。怎么找Controller?通过使用handlerMapping。如果没有设置handlerMapping,spring使用默认的BeanNameUrlHandlerMapping来找Controller。
BeanNameUrlHandlerMapping?顾名思义,就是通过bean的name属性来映射controller。bean的name请求是一个url,如果请求的是logout.do,在example-servlet.xml中定义一个名字(name)为login.do的Controller.

<bean name="/logout.do" class="com.jy.bookshop.web.spring.LogoutController">
    </bean>

再插一句话,在handlerMapping中,我们可以使用请求拦截器来对请求进行拦截处理。该拦截器怎么使用这里暂且不表,有机会再讨论。

ok,现在我们创建一个LogoutController来让他处理请求,让他实现Controller吧:

public class LogOutController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest req,
            HttpServletResponse res) throws Exception {
          …
        return new ModelAndView(new RedirectView("login.do"));
    }
}
看看这个Controller接口的定义,发现这个接口只定义了一个handleRequest方法。在这个方法中,返回一个ModelAndView。
先说ModelAndView。我们知道MVC,那么ModelAndView就是 MV了。Controller就是C。这样MVC全了。呵呵。
继续说ModelAndView,要了解他的结构,那自然要看看他的源代码了:
/** View instance or view name String */
private Object view; 

/** Model Map */
private ModelMap model;

   

    只关注我们关注的,里面包含了一个View对象和model对象。model对象是一个Map,这里不再说了。关键看看view,奇怪,怎么是一个Object,太抽象了。再继续看源代码的话,会更加明白:

 

public ModelAndView(String viewName, String modelName, Object modelObject) {
        this.view = viewName;
        addObject(modelName, modelObject);
    }
public void setViewName(String viewName) {
        this.view = viewName;
    }

原来这个view可以指向一个View对象,也可以指向String对象啊。View一个接口,如果看doc的话,他的实现类有AbstractExcelView, AbstractJasperReportsSingleFormatView, AbstractJasperReportsView, AbstractJExcelView, AbstractPdfStamperView, AbstractPdfView,AbstractTemplateView, AbstractUrlBasedView, AbstractView, AbstractXsltView, ConfigurableJasperReportsView, FreeMarkerView, InternalResourceView,JasperReportsCsvView, JasperReportsHtmlView, JasperReportsMultiFormatView, JasperReportsPdfView, JasperReportsXlsView, JstlView, RedirectView,TilesJstlView, TilesView, TilesView, VelocityLayoutView, VelocityToolboxView, VelocityView, XsltView(诚实的说,这些View是拷doc的)。

现在可以知道,我们的Controller返回一个View和Model,来让Spring框架来创建一个回应。

现在奇怪的还有一点,我吧view设置为字符串,Spring框架怎么处理?在ModelAndView中,如果view是一个字符串,则会将这个值交给DispatcherServlet的viewResovler来处理。记得上面提到的viewResovler了吗?呵呵,派上用场了。

view的问题解决了,然后再说model吧。在ModelAndView添加了一些对象,Spring是怎么处理的呢?总应该把这些对象给弄到request对象里,让jsp页面来使用吧。让View使用?那么看看View接口吧:

public interface View {

    String getContentType();

    void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception;

}
render函数需要带一个model变量。再找找view的实现类,看看是怎么工作的。不过view有那么多,对于一些像什么pdf啦,excel了他们都不需要在request中添加这个model。
最终呢,我们在jstlView的父类InternalResourceView中的renderMergedOutputModel函数发现他把model放在了request里面了。
 
OK,现在我们明白了,controller返回的modelandview交给Servlet进行处理,来生成一个页面。
最简单的Controller介绍完毕。现在看看Spring提供的一些controller的实现,Spring提供了很多controller的实现,继承的结构如下:

 

org.springframework.web.servlet.mvc.AbstractController (implements org.springframework.web.servlet.mvc.Controller)

  • org.springframework.web.servlet.mvc.AbstractUrlViewController
    • org.springframework.web.servlet.mvc.UrlFilenameViewController
  • org.springframework.web.servlet.mvc.BaseCommandController
    • org.springframework.web.servlet.mvc.AbstractCommandController
    • org.springframework.web.servlet.mvc.AbstractFormController
      • org.springframework.web.servlet.mvc.AbstractWizardFormController
      • org.springframework.web.servlet.mvc.SimpleFormController
        • org.springframework.web.servlet.mvc.CancellableFormController
  • org.springframework.web.servlet.mvc.ParameterizableViewController
  • org.springframework.web.servlet.mvc.ServletForwardingController (implements org.springframework.beans.factory.BeanNameAware)
  • org.springframework.web.servlet.mvc.ServletWrappingController (implements org.springframework.beans.factory.BeanNameAware, org.springframework.beans.factory.DisposableBean, org.springframework.beans.factory.InitializingBean)
    AbstractController是Controller的第一个实现。其他的Controller都是继承这个Controller的。我们先看比较重要的Controller。
    先说UrlFilenameViewController。不如我们自己来部署一个吧。
    在example-servlet.xml中增加如下的配置:

    <bean name="/error.do"  class="org.springframework.web.servlet.mvc.UrlFilenameViewController">
        </bean>

    OK,当/error.do的请求上来后,urlFileNameViewController将他变成/error。然后返回个View,这个view的name就是/error,然后使用viewresolver来进行解析,可以解析成/jsp/error.jsp。
    另外还有比较重要的controller是baseCommandController,将请求参数转换为一个对象,并对对象参数合法性进行验证。另外,SimpleFormController可以对表单进行处理。
    关于各个controller的分析。未完待续。。

     

     

     

    posted @ 2009-11-25 11:09 追求无止境 阅读(3706) | 评论 (2)编辑 收藏

    [转] java.beans.PropertyEditor(属性编辑器)简单应用

    原文:http://www.blogjava.net/orangewhy/archive/2007/06/26/126371.html

    java.beans.PropertyEditor的从字义来看是一个属性编辑器,但总觉得它的作用更像一个转换器--从字符串转换为类对象的属性。

    java.beans.PropertyEditor接口定义的方法有好几个,但是最重要为下面两个:

     void setValue(Object value)

     void setAsText(String text) throws java.lang.IllegalArgumentException;

    一般地,我们要使用PropertyEditor时,并不直接实现此接口,而是通过继承实现此接口的java.beans.PropertyEditorSupport来简化我们的工作,在子类覆盖setAsText方法就可以了,setValue方法一般不直接使用,在setAsText方法中将字符串进行转换并产生目标对象以后,由调setAsText调用setValue来把目标对象注入到编辑器中。当然,你可用覆盖更多的方法来满足你的特殊要求。JavaBean的类和接口,被大部分spring包使用,可以从spring中学习更成熟的JavaBean使用方法。

    简单的例子:

    实体类Person:

    public class Person
    {
        
    private String name;
        
    private String sex;
        
    private int age;
        
        
    public Person(String name, String sex, int age)
        
    {
            
    this.name = name;
            
    this.sex = sex;
            
    this.age = age;
        }

        
        
    public int getAge()
        
    {
            
    return age;
        }

        
    public void setAge(int age)
        
    {
            
    this.age = age;
        }

        
    public String getName()
        
    {
            
    return name;
        }

        
    public void setName(String name)
        
    {
            
    this.name = name;
        }

        
    public String getSex()
        
    {
            
    return sex;
        }

        
    public void setSex(String sex)
        
    {
            
    this.sex = sex;
        }

        
        @Override
        
    public String toString()
        
    {
            
    return "Person["+name+""+sex+""+age+"]";
        }

    }

     

    Person的属性编辑器:

    public class PersonPropertyEditor extends PropertyEditorSupport
    {
        
    public void setAsText(String text)
        
    {
            setValue(parseString(text));
        }


        
    private Object parseString(String text)
        
    {
            String[] parts 
    = tokenizeToStringArray(text, ""falsefalse);
            String name 
    = (parts.length > 0 ? parts[0] : "undefine");
            String sex 
    = (parts.length > 1 ? parts[1] : "undefine");
            
    int age = (parts.length > 2 ? Integer.valueOf(parts[2]) : 0);
            
    return (text.length() > 0 ? new Person(name, sex, age) : null);
        }


        
    private  String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens,
                                                        
    boolean ignoreEmptyTokens)
        
    {
            StringTokenizer st 
    = new StringTokenizer(str, delimiters);
            List tokens 
    = new ArrayList();
            
    while(st.hasMoreTokens())
            
    {
                String token 
    = st.nextToken();
                
    if(trimTokens)
                
    {
                    token 
    = token.trim();
                }

                
    if(!ignoreEmptyTokens || token.length() > 0)
                
    {
                    tokens.add(token);
                }

            }

            
    return toStringArray(tokens);
        }


        
    private  String[] toStringArray(Collection collection)
        
    {
            
    if(collection == null)
            
    {
                
    return null;
            }

            
    return (String[])collection.toArray(new String[collection.size()]);
        }

    }

     

    测试代码:

        public static void main(String[] args)
        
    {
            PersonPropertyEditor editor 
    = new PersonPropertyEditor();
            editor.setAsText(
    "aSam,man,22");
            System.out.println(editor.getValue());
        }

     

    结果输出:

    Person[aSam, man, 22]

    posted @ 2009-11-20 22:07 追求无止境 阅读(286) | 评论 (0)编辑 收藏