金牌译作 Spring Json View(Spring+Json)

713个读者 翻译: jdonee  07/04/2008 原文 引用 双语对照及眉批

简介

Spring  json-view    为Spring-MVC提供了对JavaScript  Object  Notation  (json)  的支持,它深入地集成在Spring  MVC模块里,能够适用于所有标准的控制器类。

什么是Spring Json View?
 
Spring json-view  为Spring-MVC提供了对JavaScript Object Notation (json) 的支持,它深入地集成在Spring MVC模块里,能够适用于所有标准的控制器类。
在Web 2.0 Ajax 时代里常见的方式是客户(浏览器)和服务器的交互。在Java服务器端通常把Spring MVC看成是一个标准的web框架。他们尝试通过Spring MVC和Json方式的视图结合成为一个方案,比如Json-Lib-Ext-Spring。
在我们第一个Web2.0工程里我们寻找一种方式使用服务器端Spring-MVC的知识接收和响应Ajax请求。但是没有一个令苛刻的Spring MVC开发者们感到满意。所以我们开始探索Spring Json-View用于支持所有Spring MVC特性。
 
 

近况

新闻

Spring-json 1.0 最终版发布

更新 ( 更新报告 )

  增加支持Json-Lib写法

  增加 JsonWriterConfiguratorTemplateRegistry

  更新文档和测试

   Bug修正

 

spring-json 1.0 增加到Maven2的下载库,地址如下:

http://repo1.maven.org/maven2

http://spring-json.sourceforge.net/repository

下  载

 
哪些不同点?
 
Spring Json View 深入地集成在Spring MVC模块里。它能够适用于所有的SpringMVC支持(如SimpleFormController)的标准控制器类。
 
 
配置
它通过SpringXml方式配置
 
 
绑定
它支持用Spring方式把Bean属性转换到View里。(请参见SimpleFormController的initBinder()方法)
 
集成了普遍的Json组件
它现在默认支持Sojo,当然还有JsonLib
 
校验
它支持用ValidatorBeans Spring 方式的校验
 
错误处理
它支持Spring方式错误处理,包括全局、字段和绑定错误。
 
异常处理
它使用 JsonExceptionResolver支持 Spring 方式的异常处理。
 

通过它你只要改变视图而不必改变后台编码就能把典型Spring应用转换为典型Web2.0应用。
 

文档中心
 
Spring json-view  为Spring-MVC提供了对JavaScript Object Notation (json) 的支持,它能让你像平时使用spring-mvc一样使用。现在它能够让你的基于Ajax的前端工具更容易提取(服务器端)数据。
基本上,它是通过AbstractView实现的。现在它增加了Spring BindingResult(结果绑定),Field 和GlobalErrors(字段和公共错误信息),完成校验和一个将属性值转换成显示字符串的属性编辑器。但是它也可以提供一些有用的特性为Ajax-Frameworks服务。比如,类似prototype的错误处理。当然还有转换成Json 字符串的Model。
 
查看演示程序可以获得实用的例子。
 
绑定
   1.用法说明
   2.JsonStringWriter
       1.SojoJsonStringWriter
       2.JsonlibJsonStringWriter
   3.比较
       
校验
   1. Spring MVC 校验样例
 
错误处理
    1.配置概述
    2.Http状态错误
    3.模型标记错误
    4.自主实现的Json错误处理器
 
异常处理
    1.配置概述
    2.Json错误处理器
    3.Json异常处理器
       1.ExceptionMessageExceptionHandler(异常消息异常处理器)
       2.StackTraceExceptionHandler (堆栈异常处理器)
       3.自定义实现JsonExceptionHandler

 
其它配置
    1.容器类型支持(ContentType)
    2.编码支持(Encoding )

 
 
绑定-数据类型转换
 
1.用法说明
   2.JsonStringWriter
       2.1.SojoJsonStringWriter
       2.2.JsonlibJsonStringWriter
   3.比较
 
1. 用法说明
你可以从Spring Command 和FormController中实现你知道的绑定方式。通常你在ServletRequestDataBander中用控制器的初始绑定方法定义一个自定义对象.
 
你能绑定的CustomEditor包括
默认的Spring-MVC提供了如下对象绑定到CustomEditor:
  • 像java.util.Date普通数据类型的类
  • 能按CommensBeanUtils-Syntax匹配ComandBean字段的类  

     @Override
     protected void initBinder(HttpServletRequest request, 
                        ServletRequestDataBinder binder) throws Exception{
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
        CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
        binder.registerCustomEditor(Date.class, editor);
        binder.registerCustomEditor(Date.class, "birthday", editor);
     }

    

2. JsonStringWriter

JsonStringWriter 控制 模型/Command对象间值的转换,当然,还有生成Json字符串。JsonStringWriter 最大限度地保持着这种在Spring MVC所知道的自定义编辑器的注册方式。在已经存在Json库的那些数据格式转换的特性没有找到完全符合我们需要的特性。在另外协助的库支持的特殊特性你又不得不使用。

所以你将发现依照JsonStringWriter的实现绑定支持的不同。在下面的章节你会发现它们如何帮助你去选择一个JsonStringWriter。

 

2.1 SojoJsonStringWriter - Sojo Json 支持

SojoJsonWriter 是Spring Json-View 的默认实现。它是一个通过Sojo Json 方式传输和接近默认Spring-MVC绑定方式的整合方案。

你可以按如下方式绑定自定义编辑器:

   1.  像java.util.Date普通数据类型的类

   2. 能按CommensBeanUtils-Syntax匹配ComandBean字段的类  
   3. 可选:像那些附加referenceData-method的Model中任意其它类

 

2.2 JsonlibJsonStringWriter -  Json-Lib支持

JsonlibJsonStringWriter 提供了Json-Lib框架到Spring Json-View的集成。我没有发现它有按CommensBeanUtils-Syntax匹配ComandBean实现本地化属性的方法。但是你可以通过注册一个JsonlibJsonWriterConfiguratorTemplat从而操纵Json-Lib框架。它被封装在一个net.sf.json.JsonConfig对象里。更多信息请参见Json-lib 主页。

你可以按如下方式绑定自定义编辑器:

   1. 像java.util.Date普通数据类型的对象  (it converts the howl model map.)
   2. 可选:通过JsonlibJsonWriterConfiguratorTemplate注册一个自定义的"net.sf.json.JsonConfig" 对象。

  
3 比较

                                                                              SojoJsonStringWriter     JsonlibJsonStringWriter
Supported library                                                       sojo-0.5.0                        json-lib-2.2.1
Default Writer                                                            yes                                  no
ComandBean convertion   
convert class types                                                    yes                                  yes
Properties located by CommensBeanUtils-Syntax              yes
                                                                              explicit Collection                no
                                                                              conversion  
Other model map properties convertion   
convert class types                                                    optional                             always
Properties located by                                                 optional
CommensBeanUtils-Syntax                                    explicit Collection                        no
                                                                              conversion 
JsonWriterConfiguratorTemplate                                     no                                     optional
 
 
SojoJsonWriter - Sojo Json 支持
   1. 绪论
   2. 简单绑定
   3. 使用CommandBean-Property绑定
   4. 转换所有Model Values.
         1. Model-Map通过CustomEditor转换所有值
         2. Model-Map通过CustomEditor转换特殊值

1. 绪论
SojoJsonWriter 是Spring Json-View 的默认实现。它是一个通过Sojo Json 方式传输和接近默认Spring-MVC绑定方式的整合方案。
 

你可以按如下方式绑定自定义编辑器:

   1.  像java.util.Date普通数据类型的类 
   2. 能按CommensBeanUtils-Syntax匹配ComandBean字段的类

   3. 可选:像那些附加referenceData-method的Model中任意其它类

 

注意: 
        Spring Json View 不能绑定如下例Bean中Collection类型中的属性
        * Spring提供的写法:
          bean.list.property
          这个语法是找出conllection中从0-n的所有属性
        * Spring Json View 能找出像下面这样使用解释型索引的Collection-Beans的属性:
          bean.list[0].property
          bean.set[1].list[2].property

2. 简单绑定
 
initBinder 源文件:
=================
@Override
protected void initBinder(HttpServletRequest request, 
                        ServletRequestDataBinder binder) throws Exception{
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
        CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
        binder.registerCustomEditor(Date.class, editor);
}
 
结果:
=======
{"command":{
            "birthday":"30-01-2008",
            "marriage":"30-01-2008",
            "placeofbirth":"Sydney"
}}
 
3. 使用CommandBean-Property绑定

CommonsBeanUtils-Syntax 找出CommandBean中的属性
initBinder 源文件:
==================
@Override
protected void initBinder(HttpServletRequest request, 
                ServletRequestDataBinder binder) throws Exception{
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
        CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
        binder.registerCustomEditor(Date.class, "birthday", editor);
}
 
结果:
======
{"command":{
          "birthday":"30-01-2008",
          "marriage":"Wed Jan 30 00:00:00 GMT 2008",
          "placeofbirth":"Sydney"
}}
 
4. 转换所有Model的值
SojoJsonStringWriter 已经提供对非CommandBean-Values在Model Map 随意的转换。你可以利用这个特性在view.xml用JsonWriter- Bean设置convertAllMapValues 属性。
你能在一个CustomEditor定义的字段利用non_commandbean_key找到它们。
    * (name_in_model_map_key).property
    * (key).list[1].property
 
配置文件
<beans>
    <bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
        <property name="jsonWriter"><ref bean="jsonWriter"/></property>
    </bean>
   
    <bean name="jsonWriter"
          class="org.springframework.web.servlet.view.json.writer.sojo.SojoJsonStringWriter">
        <property name="convertAllMapValues"><value>true</value></property>
    </bean>
</beans>
 
4.1 Model-Map通过CustomEditor转换所有值
 
initBinder 源文件:
==================
@Override
protected void initBinder(HttpServletRequest request, 
                ServletRequestDataBinder binder) throws Exception{
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
        CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
        binder.registerCustomEditor(Date.class, editor);
}
       
结果:
=======
{"signdate":"30-01-2008",
 "command":{
            "birthday":"30-01-2008",
            "marriage":"30-01-2008",
            "placeofbirth":"Sydney"
}}
 
4.2 Model-Map通过CustomEditor转换特殊值
initBinder 源文件:
==================
@Override
protected void initBinder(HttpServletRequest request, 
                ServletRequestDataBinder binder) throws Exception{
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
        CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
        binder.registerCustomEditor(Date.class, "birthday", editor);
        binder.registerCustomEditor(Date.class, "(signdate)", editor);
}
       
结果:
=======
{"signdate":"30-01-2008",
 "command":{
            "birthday":"30-01-2008",
            "marriage":"Wed Jan 30 00:00:00 GMT 2008",
            "placeofbirth":"Sydney"
}}
 
 
JsonlibJsonWriter - Json-Lib支持
   1. 绪论
   2. 使用
   3. 绑定
   4. 注册 JsonlibJsonWriterConfiguratorTemplates
 
1. 绪论
   JsonlibJsonWriter的绑定能力是相当弱的.
   1.你仅仅能在所有Model Map绑定像java.util.Date普通数据类型的类 (你不能具体制定到单个Bean的属性或者Collection 的索引!!!)
   2. 在“model-map to json”转换的过程中你能通过注册JsonlibJsonWriterConfiguratorTemplate订制一个JsonConfig对象。JsonlibJsonWriterConfiguratorTemplate 使你能够使用一些Json-Lib的高级特性,比如你能使用过滤或者触发一些事件。
 
注意:
    JsonlibJsonWriter会 注册一个自己的JsonValueProcessor 并用JsonValueProcessorMatcher匹配。
      * JsonValueProcessor 使JsonlibJsonWriter 能够把自定义编辑器注册到它的一个初始化方法里。
      * JsonValueProcessorMatcher 会匹配JsonValueProcessor所有的值。JsonValueProcessor来决定值是否需要转换。如果你想注册一个自定义的JsonValueProcessor或者 BeanProcessor,请记住,在某种程度上您并不能按你期望的可能来改变JsonlibJsonWriter 的行为,最好多测试你的程序。
      * 你注册的自定义行为不会影响"request-attribute to CommandBean"的绑定和转换方式。
 
2. 使用
   注册一个JsonlibJsonStringWriter-Bean到JsonView。
 
<beans>
    <bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
            <property name="jsonWriter"><ref bean="jsonlibJsonWriter"/></property>
    </bean>
       
        <bean name="jsonlibJsonWriter" class="org.springframework.web.servlet.view.json.writer.jsonlib.JsonlibJsonStringWriter"/>
</beans>
 
3. 绑定
initBinder 源文件:
=================
@Override
protected void initBinder(HttpServletRequest request, 
                        ServletRequestDataBinder binder) throws Exception{
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
        CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
        binder.registerCustomEditor(Date.class, editor);
}
 
结果:
=======
{"signdate":"30-01-2008",
 "command":{
            "birthday":"30-01-2008",
            "marriage":"30-01-2008",
            "placeofbirth":"Sydney"
}}
 
4. 注册JsonlibJsonWriterConfiguratorTemplates
如果你想使用JsonlibJsonWriterConfiguratorTemplate,你不得不
   1.   在JsonlibJsonStringWriter设置"enableJsonConfigSupport"属性。
   2.   实现JsonlibJsonWriterConfiguratorTemplate抽象类。
   3.    注册JsonlibJsonWriterConfiguratorTemplate到JsonWriterConfiguratorTemplateRegistry,它会优先把一个JsonlibJsonWriterConfiguratorTemplate 注册一个初始化绑定方法里,但是也你能在任何你能发送请求的控制器方法里注册它。这和在基于控制器接口的实现时处理请求的方法是一样的。

4.1 在Spring 配置文件里设置 "enableJsonConfigSupport"属性
<beans>
    <bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
            <property name="jsonWriter"><ref bean="jsonlibJsonWriter"/></property>
    </bean>
       
        <bean name="jsonlibJsonWriter" class="org.springframework.web.servlet.view.json.writer.jsonlib.JsonlibJsonStringWriter">
        <property name="enableJsonConfigSupport"><value>true</value></property>
    </bean>
</beans>
 
4.2 注册 JsonlibJsonWriterConfiguratorTemplate
initBinder 源文件:
==================
@Override
protected void initBinder(HttpServletRequest request,  ServletRequestDataBinder binder) throws Exception{
               
    JsonWriterConfiguratorTemplateRegistry registry = JsonWriterConfiguratorTemplateRegistry.load(request);            
    registry.registerConfiguratorTemplate(
         new JsonlibJsonWriterConfiguratorTemplate(){
                @Override
                public JsonConfig getJsonConfig() {
                    JsonConfig config =  new JsonConfig();
                                               
                    // Exclude all date properties
                    config.setJsonPropertyFilter( new PropertyFilter(){ 
                    public boolean apply( Object source, String name, Object value ) { 
                          if( value != null && Date.class.isAssignableFrom( value.getClass() ) ){ 
                              return true; 
                          } 
                          return false; 
                       } 
                    }); 
                    return config;
                }
         }
   );
}
       
结果:
=======
{
 "command":{
            "placeofbirth":"Sydney"
}}
 
校验
 
来自Post的请求校验的非常容易。仅仅需要按Spring方式注册一个校验器。Spring Json View 在返回Json字符串数据时增加字段错误处理
 
 校验器
 
用Validaor-Interface实现一个自己校验器类
 
public class SpringJsonValidator implements Validator {
public void validate(Object obj, Errors errors) {
SpringJsonForm form = (SpringJsonForm) obj;
if (form.getPlaceofbirth() == null || "".equals(form.getPlaceofbirth())) {
errors.rejectValue("placeofbirth", "error.no.placeofbirth", null, "Placeofbirth required.");
}
}
@Override
public boolean supports(Class clazz) {
return SpringJsonForm.class.equals(clazz);
}
}
 
Spring ApplicationContext
 
在SimpleFormController中添加校验器
 
<beans>
<bean name="simpleJsonPostFormController"
class="org.thing.spring.json.controller.SimpleJsonPostFormController">
<property name="commandClass">
<value>org.thing.spring.json.controller.SpringJsonForm</value>
</property>
<property name="formView"><value>jsonView</value></property>
<property name="successView"><value>jsonView</value></property>
<property name="validator"><ref bean="validator"/></property>
</bean>
<bean name="validator" class="org.thing.spring.json.controller.SpringJsonValidator"/>
</beans>
 
结果
Spring Json View  增加Json response 字段错误提示。
 
{"command":{
"birthday":"08-02-2008",
"placeofbirth":""
},
"failure":"true",
"hasGlobalErrors":"false",
"hasFieldErrors":"true",
"fielderrors":{
"placeofbirth":"Please enter a a place of birth!"
}}
 
错误处理
错误处理在控制器向Model中增加一些公共或字段级错误(绑定的结果集)后触发。
 
配置
HttpStatusError
ModelFlagError 
自主实现的JsonErrorHandler
 
1. Spring配置文件:view.xml
 
把错误(公共级别的和字段级别的)配置好后转换成一个json字符串,所有注册的Json错误处理器在他们被添加按规则触发。
 
下列是JsonErrorHadnders的实现:
 
HttpStatusError
用response.setStatus(errorCode)设置一个新返回状态;一些Ajax框架比如prototype.js中触发成功状态使用返回状态编码是200-299,失败状态使用>=300,
默认编码为311.
 
ModelFlagError
在Model里增加一个简单键值对。一些Web2.0 表现层框架需要一个标记来判断服务器端的操作是否成功或失败。比如Ext框架需要一个failure=true 或者 success=true
默认标记是failure=true
 
<beans>
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="jsonErrors">
<list>
<ref bean="statusError" />
<ref bean="modelflagError" />
</list>
</property>
</bean>
<bean name="statusError"
class="org.springframework.web.servlet.view.json.error.HttpStatusError"/>
<bean name="modelflagError"
class="org.springframework.web.servlet.view.json.error.ModelFlagError"/>
</beans>
 
结果:
=======
Response-Status : 311
{"command":{
"birthday":"30-01-2008",
"placeofbirth":"Sydney"
},
"failure":"true",
"hasGlobalErrors":"true",
"globalerrors": ["errormessage1","errormessage2"],
"hasFieldErrors":"true",
"fielderrors":{
"birthday":"Please enter a valide date!"
}}
 
2. HttpStatusError
你能在HttpStatusError Bean的错误编码属性里自定义状态错误编码到响应信息里。
 
<beans>
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="jsonErrors">
<list>
<ref bean="statusError" />
</list>
</property>
</bean>
<bean name="statusError"
class="org.springframework.web.servlet.view.json.error.HttpStatusError">
<property name="errorCode"><value>999</value></property>
</bean>
</beans>
 
结果:
=======
Response-Status : 999
{"command":{
"birthday":"30-01-2008",
"placeofbirth":"Sydney"
},
"hasGlobalErrors":"true",
"globalerrors": ["errormessage1","errormessage2"],
"hasFieldErrors":"true",
"fielderrors":{
"birthday":"Please enter a valide date!"
}}
 
3. ModelFlagError
你能在ModelFlagError Bean以键值对方式设置到Model里。
 
<beans>
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="jsonErrors">
<list>
<ref bean="statusError" />
<ref bean="modelflagError" />
</list>
</property>
</bean>
<bean name="modelflagError"
class="org.springframework.web.servlet.view.json.error.ModelFlagError">
<property name="name"><value>failure</value></property>
<property name="value"><value>true</value></property>
</bean>
</beans>
 
结果:
=======
Response-Status : 200
{"command":{
"birthday":"30-01-2008",
"placeofbirth":"Sydney"
},
"failure":"true",
"hasGlobalErrors":"true",
"globalerrors": ["errormessage1","errormessage2"],
"hasFieldErrors":"true",
"fielderrors":{
"birthday":"Please enter a valide date!"
}}
 
4. 自定义实现JsonErrorHandler
你也可以实现JsonErrorHandler,来用一些完全不同的方式重构。
 
public class MyErrorHandler implements JsonErrorHandler {
public void triggerError(Map model, RequestContext rc, BindingResult br,
HttpServletRequest request, HttpServletResponse response)
throws Exception{
// Do something ...
}
}
 
 
异常处理
Spring Json-View 提供HandlerExceptionResolver (JsonExceptionResolver)在Controller操作的期间捕获并抛出异常。
 

配置
JsonErrorHandler
JsonExceptionHandler
ExceptionMessageExceptionHandler(异常消息异常处理器)
StackTraceExceptionHandler (堆栈异常处理器)
自定义实现JsonExceptionHandler
   
   
1. 配置:Spring ApplicationContext
你几乎只需要注册一个JsonErrorHandlers 或者 JsonExceptionHandler 就可以来操作函数中的响应以便抛出异常。
 
注意:
把JsonExceptionResolver 注册在ApplicationContext.xml,
而不是view.xml !!!,不然会找不到它。
 
JsonErrorHandlers
JsonErrorHandlers 发响应到客户端因为有些产生了错误。详细信息参见Errorhandling
 
HttpStatusError
用response.setStatus(错误编码)设置一个Response-Status。
   
ModelFlagError
在Model中添加一个简单键值对。
   
JsonExceptionHandler
JsonExceptionHandler负责把Java异常对象转换成一个Json字符串。
 
ExceptionMessageExceptionHandler
添加一个Java异常到Model里。默认的ModelKey是"exception.message ". ExceptionMessageExceptionHandler 用"Exception Classname : Exception Message "格式设置错误信息。
比如 : "java.lang.IllegalArgumentException : Please set Parameter "
 
StackTraceExceptionHandler  
把完整的堆栈异常添加到Model.默认的ModelKey是"exception.stacktrace".当replaceLineBreakes=true时表示可用Html</br>标记代替"\n",默认replaceLineBreakes=false。
   
<beans>
<bean id="exceptionResolver"
class="org.springframework.web.servlet.view.json.exception.JsonExceptionResolver">
<property name="exceptionView"><value>jsonView</value></property>
<property name="errorHandler">
<list>
<ref bean="statusError" />
<ref bean="modelFlagError" />
</list>
</property>
<property name="exceptionHandler">
<list>
<ref bean="exceptionMessageExceptionHandler" />
<ref bean="stackTraceExceptionHandler" />
</list>
</property>
</bean>
<bean name="exceptionMessageExceptionHandler"
class="org.springframework.web.servlet.view.json.exception.ExceptionMessageExceptionHandler" />
<bean name="stackTraceExceptionHandler"
class="org.springframework.web.servlet.view.json.exception.StackTraceExceptionHandler" />
<bean name="statusError"
class="org.springframework.web.servlet.view.json.error.HttpStatusError"/>
<bean name="modelFlagError"
class="org.springframework.web.servlet.view.json.error.ModelFlagError"/>
</beans>
 
结果:
=======
Response-Status : 311
{
"failure":"true",
"exception.message":"java.lang.Exception: You throw an exeption !",
"exception.stacktrace": "java.lang.Exception: You throw an exeption !
\n\tat org.thing.spring.json.controller.[...]
\n\tat org.springframework.web.servlet.mvc.[...]
[...]"
}
 
2. ExceptionMessageExceptionHandler
你也可以自己订制Model-key方式的异常信息。默认是exception.message
 
<beans>
<bean id="exceptionResolver"
class="org.springframework.web.servlet.view.json.exception.JsonExceptionResolver">
<property name="exceptionView"><value>jsonView</value></property>
<property name="exceptionHandler">
<list>
<ref bean="exceptionMessageExceptionHandler" />
</list>
</property>
</bean>
<bean name="exceptionMessageExceptionHandler"
class="org.springframework.web.servlet.view.json.exception.ExceptionMessageExceptionHandler">
<property name="modelKey"><value>myKey</value></property>
</bean>
</beans>
 
结果:
=======
Response-Status : 200
{
"myKey":"java.lang.Exception: You throw an exeption !"
}
 
3. StackTraceExceptionHandler
你能订制Model-Key的堆栈跟踪异常(默认是exception.stacktrace);你也能用Html视图模式展现它,replaceLineBreakes=true可用Html</br>标记代替"\n",默认replaceLineBreakes=false
 
<beans>
<bean id="exceptionResolver"
class="org.springframework.web.servlet.view.json.exception.JsonExceptionResolver">
<property name="exceptionView"><value>jsonView</value></property>
<property name="exceptionHandler">
<list>
<ref bean="stackTraceExceptionHandler" />
</list>
</property>
</bean>
<bean name="stackTraceExceptionHandler"
class="org.springframework.web.servlet.view.json.exception.StackTraceExceptionHandler">
<property name="replaceLineBreakes"><value>true</value></property>
<property name="modelKey"><value>myKey</value></property>
</bean>
</beans>
 
结果:
=======
Response-Status : 200
{
"myKey": "java.lang.Exception: You throw an exeption !
<\br>\tat org.thing.spring.json.controller.[...]
<\br>\tat org.springframework.web.servlet.mvc.[...]
[...]"
}
4. Custom implementation of JsonExceptionHandler
你也可以自己实现JsonExceptionHandler,并用一些完全不同的方式重构。
 
public class MyExceptionHandler implements JsonExceptionHandler {
public void triggerException(Exception exception, Map model,
HttpServletRequest request, HttpServletResponse response)
throws Exception{
// Do something ...
}
}
 
其它配置
 
ContentType 内容类型
Encoding 字符编码
 
 
1. Content type
你可以像下面展现的那样,在JsonView设置contentType的值来改变输出内容的文本类型。
 
<beans>
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="contentType"><value>application/json</value></property>
</bean>
</beans>
 
2. Encoding
你可以像下面展现的那样,在JsonView设置encoding的值来改变输出内容的字符编码。
 
<beans>
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="encoding"><value>ISO-8859-1</value></property>
</bean>
</beans>
 
 
演示程序
 
关于
 
这个演示程序显示了下列用例生成的Json-Result方式的结果集
用Controller-Interface方式提交Get请求 [快速开始]
用Command-Controller方式提交Post请求 [快速开始]
用SimpleForm-Controller方式提交GET/Post请求[快速开始]
使用JsonExceptionResolver抛出异常捕获信息的请求 [快速开始]
 
 
安装
仅仅需要在这里下载war并部署到你的应用服务器.这里的测试环境建立在apache-tomcat-5.5.25.
 
 
快速开始
 
首先要了解Spring-MVC的基础.
详细信息参考如下资料:
          Springframework Doku
          Spring-MVC Step-by-Step
 
配置Spring Json-View非常容易,只需要注册一个XML视图解析器
Spring ApplicationContext
<beans>
[...]
<bean name="viewResolver"
class="org.springframework.web.servlet.view.XmlViewResolver" />
[...]
</beans>
Spring view.xml
<beans>
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView"/>
</beans>
 
快速开始-用Controller-Interface提交Get请求

Spring中不支持Controller-Interface的验证或绑定。它却能容易地处理来自Get方式的请求。
这个示例在Controller中仅仅返回一个用Model-Map产生的Json字符串,没有错误包含或者格式转换。
 
Spring ApplicationContext
 
<beans>
<bean name="simpleJsonGetController"
class="org.thing.spring.json.controller.SimpleJsonGetController"/>
<bean name="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.json">simpleJsonGetController</prop>
</props>
</property>
</bean>
<bean name="viewResolver"
class="org.springframework.web.servlet.view.XmlViewResolver" />
</beans>
Spring view.xml
<beans>
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView"/>
</beans>
 
form.html
 
<head>
<title>
First Test Spring Json Demo
</title>
<script type="text/javascript" src="script/prototype.js"></script>
<script type="text/javascript" src="script/behaviour.js"></script>
<script type="text/javascript" src="script/behaviour-roles.js"></script>
<meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"/>
</head>
</head>
<body>
<h1>Spring JSON DEMO</h1>
<h2>Spring Ajax Get (ControlerInterface)</h2>
<b>firstname : </b><span id="firstname"></span><br/>
<b>secondname : </b><span id="secondname"></span><br/>
</br>
<button id="getName">get name</button>
<button id="clearName">clear name</button><br/>
</body>
 
JavaScript behaviour-roles.js
 
var printResult = function(transport){
var result =
"Status : " + transport.status
+ "\n"
+ "\n"
+ "Json-Result:"
+ "\n" + transport.responseText;
alert(result);
};
var myrules = {
'button#getName' : function(element){
element.onclick = function(){
new Ajax.Request('hello.json', { method:'get',
onSuccess: function(transport, json){
var json = transport.responseText.evalJSON();
printResult(transport);
$('firstname').innerHTML = json.firstname;
$('secondname').innerHTML = json.secondname;
}
});
}
},
'button#clearName' : function(element){
element.onclick = function(){
$('firstname').innerHTML = '';
$('secondname').innerHTML = '';
}
}
};
Behaviour.register(myrules);
 
Controller 源码
 
public class SimpleJsonGetController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Map model = new HashMap();
model.put("firstname", "Peter");
model.put("secondname", "Schmitt");
return new ModelAndView("jsonView", model);
}
}
 
结果
 
 Status : 200
 Result:
           {"firstname":"Peter","secondname":"Schmitt"}
 
 
快速开始- 用Command-Controller提交Post请求
 
Command-Controller提供一个完整的CommandBean,Spring对它提供校验和绑定支持。但是你不得不在你的控制器类里添加校验和绑定处理。它处理简单的Post请求非常容易。这个示例在Command-Controller中仅仅返回一个用Model-Map产生的Json字符串,没有错误包含或者格式转换。
 
 Spring ApplicationContext
 
<beans>
    <bean name="simpleJsonPostFormController"
          class="org.thing.spring.json.controller.SimpleJsonPostFormController">
            <property name="commandClass">
                <value>org.thing.spring.json.controller.SpringJsonForm</value>
            </property>
    </bean>
    <bean name="urlMapping"
          class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hello.json">simpleJsonPostCommandController</prop>
           </props>
        </property>
    </bean>
    <bean name="viewResolver"
        class="org.springframework.web.servlet.view.XmlViewResolver" />
</beans> Spring view.xml<beans>
    <bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView"/>
</beans>
 
 form.html
<head>
        <title>
                First Test Spring Json Demo
        </title>
        <script type="text/javascript" src="script/prototype.js"></script>
        <script type="text/javascript" src="script/behaviour.js"></script>
        <script type="text/javascript" src="script/behaviour-roles.js"></script>
        <meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"/>
</head>
</head>
<body>
        <h1>Spring JSON DEMO</h1>
        <h2>Spring Ajax Post (SimpleFormControler and CommandController)</h2>
        <form method="post" id="form">
                <input id="placeofbirth" type="text" name="placeofbirth" ><br>
                <input id="birthday" type="text" name="birthday" ><br/>
                <br/>
                <b>place of birth : </b><span id="t_placeofbirth"></span><br/>
                <b>birthday : </b><span id="t_birthday"></span><br/>
       
        </form>
        <br/>
        <button id="clearData">clear name</button>
        <button id="cc_postData">send data to CommandController</button>
</body>
 
JavaScript behaviour-roles.js
 
var printResult = function(transport){
                var result =
                        "Status : " + transport.status
                        + "\n"
                        + "\n"
                        + "Json-Result:"
                        + "\n" + transport.responseText;
                alert(result);
};
var myrules = {
        'button#clearData' : function(element){
                element.onclick = function(){
                        $('t_placeofbirth').innerHTML = '';
                        $('t_birthday').innerHTML = '';
                        $('error').innerHTML = '';
        },
        'button#cc_postData' : function(element){
                element.onclick = function(){
                        new Ajax.Request('hello.json', {
                                method:'post',
                                parameters: $('form').serialize(false),
                                onSuccess: function(transport){
                                        var json = transport.responseText.evalJSON();
                                        printResult(transport);
                                        $('t_placeofbirth').innerHTML = json.placeofbirth;
                                        $('t_birthday').innerHTML = json.birthday;
                                        $('error').innerHTML = '';
                        },
                        onFailure: function(transport){
                                printResult(transport);
                                addErrors(transport);
                        }
                       
                        });
                }
        }
};
Behaviour.register(myrules);
 
CommandBean
 
public class SpringJsonForm {
        private String placeofbirth;
        private Date birthday;
       
       
        public String getPlaceofbirth() {
                return placeofbirth;
        }
        public void setPlaceofbirth(String placeofbirth) {
                this.placeofbirth = placeofbirth;
        }
        public Date getBirthday() {
                return birthday;
        }
        public void setBirthday(Date birthday) {
                this.birthday = birthday;
        }
}
 
控制器源码
 
 public class SimpleJsonPostCommandController extends AbstractCommandController {
        @Override
        protected void initBinder(HttpServletRequest request, 
                        ServletRequestDataBinder binder) throws Exception{
                SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
                CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
                binder.registerCustomEditor(Date.class, editor);
        }
       
        @Override
        protected ModelAndView handle(HttpServletRequest request,
                        HttpServletResponse response, Object command,
                        BindException exception) throws Exception {
               
                SpringJsonForm bean = (SpringJsonForm) command;
               
                ModelAndView modelAndView = new ModelAndView("jsonView");
               
                modelAndView.addObject("birthday",  bean.getBirthday());
                modelAndView.addObject("placeofbirth",  bean.getPlaceofbirth());
                return modelAndView;
        }
}
 
结果 
 
Status : 200
 
 Result:
 {"placeofbirth":"Sydney","birthday":"Wed Jan 30 00:00:00 GMT 2008"}
 
 
快速开始-用SimpleForm-Controller提交GET/POST请求
 
 Command-Controller提供一个完整的CommandBean,Spring对它提供校验和绑定支持。这个示例在Command-Controller中返回一个用Model-Map产生的Json字符串,返回信息中包含字段错误、全局错误和绑定。支持CommandBean属性类型转换。Get请求需要依赖formBackingObject方法Post请求需要依赖onSubmitAction方法详细信息参见文档
 
Spring ApplicationContext
 
 <beans>
    <bean name="simpleJsonPostFormController"
         class="org.thing.spring.json.controller.SimpleJsonPostFormController">
            <property name="commandClass">
                <value>org.thing.spring.json.controller.SpringJsonForm</value>
            </property>
        <property name="formView"><value>jsonView</value></property>
        <property name="successView"><value>jsonView</value></property>
    </bean>
    <bean name="urlMapping"
          class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hello.json">simpleJsonPostFormController</prop>
           </props>
        </property>
    </bean>
    <bean name="viewResolver"
        class="org.springframework.web.servlet.view.XmlViewResolver" />
</beans>Spring view.xml<beans>
    <bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
            <property name="jsonErrors">
                <list>
                        <ref bean="statusError" />
                        <ref bean="modelflagError" />
                </list>
        </property>
    </bean>
   
    <bean name="statusError"
          class="org.springframework.web.servlet.view.json.error.HttpStatusError">
          <property name="errorCode"><value>311</value></property>
    </bean>
    <bean name="modelflagError"
          class="org.springframework.web.servlet.view.json.error.ModelFlagError">
          <property name="name"><value>failure</value></property>
          <property name="value"><value>true</value></property>
    </bean>
       
</beans>
 
form.html
 
<head>
        <title>
                First Test Spring Json Demo
        </title>
        <script type="text/javascript" src="script/prototype.js"></script>
        <script type="text/javascript" src="script/behaviour.js"></script>
        <script type="text/javascript" src="script/behaviour-roles.js"></script>
        <meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"/>
</head>
</head>
<body>
        <h1>Spring JSON DEMO</h1>
        <h2>Spring Ajax Post (SimpleFormControler and CommandController)</h2>
        <form method="post" id="form">
                <input id="placeofbirth" type="text" name="placeofbirth" ><br>
                <input id="birthday" type="text" name="birthday" ><br/>
                <br/>
                <b>place of birth : </b><span id="t_placeofbirth"></span><br/>
                <b>birthday : </b><span id="t_birthday"></span><br/>
       
        </form>
        <br/>
        <span id ="error" ></span>
        <br/>
        <button id="clearData">clear name</button>
        <<button id="sfc_postData">send data to SimpleFormController</button>
</body>
 
JavaScript behaviour-roles.js
 
var printResult = function(transport){
                var result =
                        "Status : " + transport.status
                        + "\n"
                        + "\n"
                        + "Json-Result:"
                        + "\n" + transport.responseText;
                alert(result);
};
var addErrors = function(transport){
        var json = transport.responseText.evalJSON();
       
        var error = "Errorhandler Info: </br>"
        + "failture: " + json.failure +"</br>"
        + "status : + " + transport.status +"</br>"
        +"</br>"
        +"Spring Errorhandling: </br>"
        + "hasGlobalErrors : " + json.hasGlobalErrors +"</br>"
        + "</br>"
        + "hasFieldErrors : " + json.hasFieldErrors +"</br>";
        if(json.fielderrors.birthday)
                error = error + "birthday : " + json.fielderrors.birthday +"</br>";
        if(json.fielderrors.placeofbirth)
                error = error + "placeofbirth : " + json.fielderrors.placeofbirth +"</br>";
       
        $('error').innerHTML = error;
};
var myrules = {
        'button#clearData' : function(element){
                element.onclick = function(){
                        $('t_placeofbirth').innerHTML = '';
                        $('t_birthday').innerHTML = '';
                        $('error').innerHTML = '';
        },
        'button#sfc_postData' : function(element){
       
            new Ajax.Request('hello1.json', {
                                method:'get',
                                onSuccess: function(transport){
                                        var json = transport.responseText.evalJSON();
                                        printResult(transport);
                                $('placeofbirth').value = json.command.placeofbirth;
                                $('birthday').value = json.command.birthday;
                        },
                        onFailure: function(transport){
                                var json = transport.responseText.evalJSON();
                                        printResult(transport);
                                        addErrors(transport);
                        }
                       
                        });
           
                element.onclick = function(){
                        new Ajax.Request('hello1.json', {
                                method:'post',
                                parameters: $('form').serialize(false),
                                onSuccess: function(transport){
                                        var json = transport.responseText.evalJSON();
                                        printResult(transport);
                                        $('t_placeofbirth').innerHTML = json.command.placeofbirth;
                                $('t_birthday').innerHTML =  json.command.birthday;
                                $('error').innerHTML = '';
                        },
                        onFailure: function(transport){
                                var json = transport.responseText.evalJSON();
                                        printResult(transport);
                                        addErrors(transport);
                        }
                       
                        });
                }
        }
};
Behaviour.register(myrules);
 
CommandBean
 
public class SpringJsonForm {
        private String placeofbirth;
        private Date birthday;
       
       
        public String getPlaceofbirth() {
                return placeofbirth;
        }
        public void setPlaceofbirth(String placeofbirth) {
                this.placeofbirth = placeofbirth;
        }
        public Date getBirthday() {
                return birthday;
        }
        public void setBirthday(Date birthday) {
                this.birthday = birthday;
        }
}
 
控制器源码
 
public class SimpleJsonPostFormController extends SimpleFormController {
        protected void initBinder(HttpServletRequest request,  ServletRequestDataBinder binder) throws Exception{
                SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
                CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
                binder.registerCustomEditor(Date.class, editor);
        }
        @Override
        protected Object formBackingObject(HttpServletRequest request)
                        throws Exception {
                SpringJsonForm bean = new SpringJsonForm();
                bean.setBirthday(new Date());
                bean.setPlaceofbirth("Sydney");
                return bean;
        }
        public void onSubmitAction(Object command, BindException errors) {
                SpringJsonForm bean = (SpringJsonForm) command;
        }
}
 
结果 
 
GET-Response  Status : 200
 
 Result:
 {"firstname":"Peter","secondname":"Schmitt"}POST Response Response-Status : 311
{"command":{
            "birthday":"30-01-2008",
            "placeofbirth":"Sydney"
           },
 "failure":"true",
 "hasGlobalErrors":"true",
 "globalerrors": ["errormessage1","errormessage2"], 
 "hasFieldErrors":"true",
 "fielderrors":{
             "birthday":"Please enter a valide date!"
}}
 
 
快速开始-使用JsonExceptionResolver抛出异常捕获信息的请求
 
实现异常处理是通过异常分析处理分析器来完成:JsonExceptionResolver。你仅仅需要注册一个JsonErrorHandlers或者JsonExceptionHandler操作一个返回信息以便抛出异常。 JsonErrorHandlers 发响应到客户端因为有些产生了错误。详细信息参见ErrorhandlingJsonExceptionHandler 转换java.lang.Exception对象并添加到Json字符串。详细信息参见Exceptionhandling
 
Spring ApplicationContext
 
 <beans>
    <bean name="viewResolver"
        class="org.springframework.web.servlet.view.XmlViewResolver" />
   
    <bean name="throwExceptionGetController"
        class="org.thing.spring.json.controller.ThrowExceptionGetController"/>
       
    <bean id="exceptionResolver"
        class="org.springframework.web.servlet.view.json.exception.JsonExceptionResolver">
        <property name="exceptionView"><value>jsonView</value></property>
                <property name="errorHandler">
                <list>
                        <ref bean="statusError" />
                        <ref bean="modelflagError" />
                </list>
        </property>
        <property name="exceptionHandler">
                <list>
                        <ref bean="stackTraceExceptionHandler" />
                        <ref bean="exceptionMessageExceptionHandler" />
                </list>
        </property>
        </bean>
   
        <bean name="statusError"
              class="org.springframework.web.servlet.view.json.error.HttpStatusError"/>
       
        <bean name="modelflagError"
              class="org.springframework.web.servlet.view.json.error.ModelFlagError"/
       
        <bean name="stackTraceExceptionHandler"
              class="org.springframework.web.servlet.view.json.exception.StackTraceExceptionHandler"/>
       
        <bean name="exceptionMessageExceptionHandler"
              class="org.springframework.web.servlet.view.json.exception.ExceptionMessageExceptionHandler"/>
</beans>
Spring view.xml
<beans>
    <bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
            <property name="jsonErrors">
                <list>
                        <ref bean="statusError" />
                        <ref bean="modelflagError" />
                </list>
        </property>
    </bean>
   
    <bean name="statusError"
          class="org.springframework.web.servlet.view.json.error.HttpStatusError">
          <property name="errorCode"><value>311</value></property>
    </bean>
    <bean name="modelflagError"
          class="org.springframework.web.servlet.view.json.error.ModelFlagError">
          <property name="name"><value>failure</value></property>
          <property name="value"><value>true</value></property>
    </bean>
       
</beans>
 
form.html
 
<head>
        <title>
                First Test Spring Json Demo
        </title>
        <script type="text/javascript" src="script/prototype.js"></script>
        <script type="text/javascript" src="script/behaviour.js"></script>
        <script type="text/javascript" src="script/behaviour-roles.js"></script>
        <meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"/>
</head>
</head>
<body>
        <h1>Spring JSON DEMO</h1>
        <h2>Exception-Handling by JsonExceptionResolver</h2>
        <button id="throwException">throw exception</button>
</body>
 
JavaScript behaviour-roles.js
 
var printResult = function(transport){
                var result =
                        "Status : " + transport.status
                        + "\n"
                        + "\n"
                        + "Json-Result:"
                        + "\n" + transport.responseText;
                alert(result);
};
var myrules = {
        'button#throwException' : function(element){
                element.onclick = function(){
                        new Ajax.Request('exception.json', {
                                method:'get',
                                parameters: {throwException: 'true'},
                                onFailure: function(transport){
                                var json = transport.responseText.evalJSON();
                                        printResult(transport);
                        }
                        });
                }
        }
       
};
Behaviour.register(myrules);
 
控制器源码
 
public class ThrowExceptionGetController implements Controller {
        /** Logger for this class and subclasses */
        protected final Log logger = LogFactory.getLog(getClass());
        public ModelAndView handleRequest(HttpServletRequest request,
                        HttpServletResponse response) throws Exception {
                if(request.getParameter("throwException")!= null)
                        throw new Exception("You throw an exeption !");
               
                Map model = new HashMap();
                model.put("exception", "false");
                return new ModelAndView("json1", model);
        }
}
 
结果
 
 GET-Response
 
 Response-Status : 311
{
        "failure":"true",
        "exception.message":"java.lang.Exception: You throw an exeption !",
        "exception.stacktrace":
                        "java.lang.Exception: You throw an exeption !
                        \n\tat org.thing.spring.json.controller.[...]
                        \n\tat org.springframework.web.servlet.mvc.[...]
                        [...]"
}
 
 
下载

你能下载Spring Json View的:
工程源码
Jar包
演示程序
在这里下载
 
SVN地址
 
问答
 
Spring Json-view提供所有的我们知道的Spring-MVC特征吗?
是的,几乎支持所有。Spring Json View能唯一绑定ConllectionBean的详细属性(参见文档Binding部分) 
 
Spring Json-view 直接输出到Json结果集吗? 
不,还没有。暂时它是先产生一个字符串再写到输出流里。  
 
Spring Json View使用哪一个Json引擎 
sojo,详情参见http://sojo.sourceforge.net/ 
继续阅读
  • Facebook 详解

    译者:本文译自英文维基百科条目“Facebook”。只翻译了个人觉得对中国互联网从业者有价值的部分。比如有关Facebook相关的法律纠纷,就略去了。中文维基百科只完成了原文2%的翻译。如中文维基百...

  • Top 100 web2.0网站 最热门的100个网站

    视频 *YouTube :YouTube(你的视频)是一个可以让用户免费上传、观赏、分享视频短片的热门视频共享网站 *Meta Cafe: Metacafe (麦塔咖啡厅)-得到最好的网上视频-搞笑...

  • 《长尾(The Long Tail)》的完整中译版

    自从2004年10月发表以来,Chris Anderson的经典文章《长尾》一直在深刻地影响着全球各地互联网业的发展。他所提出的推动型模式与拉动型模式的结合,广泛性与个性化的统一,已经成为网络产品设计...

  • Facebook上最伟大的十个应用程序(Apps)——工作篇

    作为读写网Facebook周活动的一部分,我为大家带来Facebook平台下的最优秀的Apps。有将近1800个Apps可以在Facebook平台下运行,这给Facebook带来了巨大的成功。在这些应...

  • 长尾全译 PDF 下载

    欢迎您来下载《长尾(译言版中译)》的PDF文件。这是Chris Anderson最初在《连线》杂志发表的《长尾》原文的中译版。我们有下列几个版本供您选择下载或阅读。 *译言长尾中译PDF版(拙尘制作...

  • Facebook如何击败Myspace,Yahoo!和Google?

    Facebook如何击溃Myspace,Yahoo!和Google? 原文作者:Christopher Beam (Slate.com在线杂志专栏作家) 每个年轻人——通常刚脱稚气——必须作出一个重...

  • 什么是商业模式

    商业模式这个话题在现在的市场竞争中已经变得越来越重要。依靠引入新的商业模式来保持持续的变革和创新能力对于企业在快速变化的商业环境中存活并发展是极其重要的。对于目前的商业环境来说,商业模式是一种非常好...

  • Web 2.0 的核心思想

    (译者:到底什么是Web 2.0的精髓?新技术?还是新观念?对此的争论可谓仁者见仁,智者见智。本文作者认为是“大众的智慧”这一新观念,带动了技术和社会的变革,因而是Web 2.0的精髓所在。稍后,我们...

相关小组

标签:

内容有问题?请与我们联络。

译作评分

  • Currently 4.00/5
  • 1
  • 2
  • 3
  • 4
  • 5
 4.0  |  1 个评分

5条评论    0眉批

  • 1.

    tsaizb 榜眼 | Blog

    我的神,我见过的最长译文。

    唉,我不写代码已很多年~

    07/04/2008

  • 2.

    jdonee 贡生

    呵呵  我花了三天翻译完的

    第一次翻译  ~

    07/04/2008

  • 3.

    琴清 童生

    真的很难看懂啊~我也是学软件开发的.不过目前也没学到什么真本事.
    只不过是简单的c语言,数据库,计组而已.最要命的是没有编程的感觉.

    07/04/2008

  • 4.

    jdonee 贡生

    那你最好转行  ,做程序开发是需要激情的,而且竞争激烈,呵呵

    07/07/2008

  • 5.

    琴清 童生

    不过呢,我才是大一的学生.开学就大二了.我相信自己有实力培养编程的感觉!我也知道感觉很重要啊.

    07/07/2008

添加评论

欢迎访问译言网。在这里,您可以。。。

阅读
发现
翻译