<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Marshal&#039;s Blog &#187; spring</title>
	<atom:link href="http://marshal.easymorse.com/archives/tag/spring/feed" rel="self" type="application/rss+xml" />
	<link>http://marshal.easymorse.com</link>
	<description>It&#039;s swap of marshal&#039;s memory.</description>
	<lastBuildDate>Mon, 30 Jan 2012 07:03:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>gwt和spring security的集成方法</title>
		<link>http://marshal.easymorse.com/archives/2240?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gwt%25e5%2592%258cspring-security%25e7%259a%2584%25e9%259b%2586%25e6%2588%2590%25e6%2596%25b9%25e6%25b3%2595</link>
		<comments>http://marshal.easymorse.com/archives/2240#comments</comments>
		<pubDate>Mon, 01 Feb 2010 06:08:24 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[gwt mvp]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring security]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2240</guid>
		<description><![CDATA[gwt如何与spring security集成，这是个问题。如果能够合理的集成，可以实现很多需要认证和授权的场合。 比如在访问需要授权的地方，显示登录界面： 登录后可以看到授权的界面： 如果退出，将返回到登录界面： 登录的用户，如果没有授权，比如没有上传权限，当执行文件上传时，提示权限不足。 当然，不具备权限的用户，应该看不到上传视频界面才对。这里只是演示针对授权不足的服务器端与客户端交互的实例。在正式的系统中，应该根据用户授权生成用户界面，另外，也还要提供服务器端的检查和客户端的提示机制。 下面说说集成gwt和spring security的基本思路。 spring security提供了对web的认证和授权支持。但是，是基于传统的web mvc模式的，视图由服务器端生成。而gwt，视图都在浏览器端由javascript生成，只需从服务器端获取数据，比如json格式的数据。spring security没有提供对ajax的通用支持。 这里就需要考虑，是否还要使用spring security，自己实现认证和授权不也可以么？经过比较，还是使用spring security工作量小，至少大部分认证授权功能都可以使用，只是需要考虑如何与gwt对接。 如何与gwt集成，spring security提供了三种web认证形式，比较主要的是form和basic，都做了集成的实验。还是form方式比较好集成，因为form方式可以通过服务器端的重定向等动作识别和拦截，而basic，是通过请求头信息，以及返回401/403码和浏览器通信，会造成浏览器的响应早于javascritp。 具体方案，是在web app中，增加一个靠前的Filter，用于检查是否有对*.json和j_spring_security_check。 因为，如果spring security受保护的资源被访问，会重定向到登录界面，要求用户登录。而gwt不需要这个重定向，因为gwt有自己的登录界面，只是需要服务器端触发它。因此监控*.json和j_spring_security_check如果被重定向到spring_security_login，也就是登录界面，则不执行重定向操作，改为返回401（未授权错误），gwt根据401，产生事件，触发登录界面。 有关认证部分的配置和代码。 web.xml的配置： &#60;filter&#62; &#160;&#160;&#160; &#60;filter-name&#62;ajaxAuthFilter&#60;/filter-name&#62; &#160;&#160;&#160; &#60;filter-class&#62;com.easymorse.videos.server.FormAuthenticationFilter&#60;/filter-class&#62; &#60;/filter&#62; &#60;filter-mapping&#62; &#160;&#160;&#160; &#60;filter-name&#62;ajaxAuthFilter&#60;/filter-name&#62; &#160;&#160;&#160; &#60;url-pattern&#62;*.json&#60;/url-pattern&#62; &#60;/filter-mapping&#62; &#60;filter-mapping&#62; &#160;&#160;&#160; &#60;filter-name&#62;ajaxAuthFilter&#60;/filter-name&#62; &#160;&#160;&#160; &#60;url-pattern&#62;/j_spring_security_check&#60;/url-pattern&#62; &#60;/filter-mapping&#62; &#160; Filter代码： package com.easymorse.videos.server; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import [...]]]></description>
			<content:encoded><![CDATA[<p>gwt如何与spring security集成，这是个问题。如果能够合理的集成，可以实现很多需要认证和授权的场合。</p>
<p>比如在访问需要授权的地方，显示登录界面：</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/02/image.png" rel="lightbox"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://marshal.easymorse.com/wp-content/uploads/2010/02/image_thumb.png" width="374" height="225" /></a> </p>
<p>登录后可以看到授权的界面：</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/02/image1.png" rel="lightbox"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://marshal.easymorse.com/wp-content/uploads/2010/02/image_thumb1.png" width="521" height="348" /></a> </p>
<p> <span id="more-2240"></span>
</p>
<p>如果退出，将返回到登录界面：</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/02/image2.png" rel="lightbox"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://marshal.easymorse.com/wp-content/uploads/2010/02/image_thumb2.png" width="412" height="269" /></a> </p>
<p>登录的用户，如果没有授权，比如没有上传权限，当执行文件上传时，提示权限不足。</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/02/image3.png" rel="lightbox"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://marshal.easymorse.com/wp-content/uploads/2010/02/image_thumb3.png" width="509" height="260" /></a> </p>
<p>当然，不具备权限的用户，应该看不到<em><strong>上传视频</strong></em>界面才对。这里只是演示针对授权不足的服务器端与客户端交互的实例。在正式的系统中，应该根据用户授权生成用户界面，另外，也还要提供服务器端的检查和客户端的提示机制。</p>
<p>下面说说集成gwt和spring security的基本思路。</p>
<p>spring security提供了对web的认证和授权支持。但是，是基于传统的web mvc模式的，视图由服务器端生成。而gwt，视图都在浏览器端由javascript生成，只需从服务器端获取数据，比如json格式的数据。spring security没有提供对ajax的通用支持。</p>
<p>这里就需要考虑，是否还要使用spring security，自己实现认证和授权不也可以么？经过比较，还是使用spring security工作量小，至少大部分认证授权功能都可以使用，只是需要考虑如何与gwt对接。</p>
<p>如何与gwt集成，spring security提供了三种web认证形式，比较主要的是form和basic，都做了集成的实验。还是form方式比较好集成，因为form方式可以通过服务器端的重定向等动作识别和拦截，而basic，是通过请求头信息，以及返回401/403码和浏览器通信，会造成浏览器的响应早于javascritp。</p>
<p>具体方案，是在web app中，增加一个靠前的Filter，用于检查是否有对*.json和j_spring_security_check。</p>
<p>因为，如果spring security受保护的资源被访问，会重定向到登录界面，要求用户登录。而gwt不需要这个重定向，因为gwt有自己的登录界面，只是需要服务器端触发它。因此监控*.json和j_spring_security_check如果被重定向到spring_security_login，也就是登录界面，则不执行重定向操作，改为返回401（未授权错误），gwt根据401，产生事件，触发登录界面。</p>
<p>有关认证部分的配置和代码。</p>
<p>web.xml的配置：</p>
<blockquote><p>&lt;filter&gt;      <br />&#160;&#160;&#160; &lt;filter-name&gt;ajaxAuthFilter&lt;/filter-name&gt;       <br />&#160;&#160;&#160; &lt;filter-class&gt;com.easymorse.videos.server.FormAuthenticationFilter&lt;/filter-class&gt;       <br />&lt;/filter&gt; </p>
<p>&lt;filter-mapping&gt;      <br />&#160;&#160;&#160; &lt;filter-name&gt;ajaxAuthFilter&lt;/filter-name&gt;       <br />&#160;&#160;&#160; &lt;url-pattern&gt;*.json&lt;/url-pattern&gt;       <br />&lt;/filter-mapping&gt; </p>
<p>&lt;filter-mapping&gt;      <br />&#160;&#160;&#160; &lt;filter-name&gt;ajaxAuthFilter&lt;/filter-name&gt;       <br />&#160;&#160;&#160; &lt;url-pattern&gt;/j_spring_security_check&lt;/url-pattern&gt;       <br />&lt;/filter-mapping&gt;</p>
<p>&#160;</p>
</blockquote>
<p>Filter代码：</p>
<blockquote><p>package com.easymorse.videos.server; </p>
<p>import java.io.IOException; </p>
<p>import javax.servlet.Filter;      <br />import javax.servlet.FilterChain;       <br />import javax.servlet.FilterConfig;       <br />import javax.servlet.ServletException;       <br />import javax.servlet.ServletRequest;       <br />import javax.servlet.ServletResponse;       <br />import javax.servlet.http.HttpServletResponse;       <br />import javax.servlet.http.HttpServletResponseWrapper; </p>
<p>public class FormAuthenticationFilter implements Filter { </p>
<p>&#160;&#160;&#160; @Override      <br />&#160;&#160;&#160; public void destroy() {       <br />&#160;&#160;&#160; } </p>
<p>&#160;&#160;&#160; @Override      <br />&#160;&#160;&#160; public void doFilter(ServletRequest request, ServletResponse response,       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FilterChain chain) throws IOException, ServletException {       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; HttpServletResponse httpServletResponse = new AuthenticationResponseWrapper(       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (HttpServletResponse) response);       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; chain.doFilter(request, httpServletResponse);       <br />&#160;&#160;&#160; } </p>
<p>&#160;&#160;&#160; @Override      <br />&#160;&#160;&#160; public void init(FilterConfig config) throws ServletException {       <br />&#160;&#160;&#160; } </p>
<p>} </p>
<p>class AuthenticationResponseWrapper extends HttpServletResponseWrapper { </p>
<p>&#160;&#160;&#160; public AuthenticationResponseWrapper(HttpServletResponse response) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; super(response);       <br />&#160;&#160;&#160; } </p>
<p>&#160;&#160;&#160; @Override      <br />&#160;&#160;&#160; public void sendRedirect(String location) throws IOException {       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (location.contains(&quot;spring_security_login&quot;)) {       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.sendError(401, &quot;need login&quot;);       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!location.endsWith(&quot;json&quot;)) {       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; super.sendRedirect(location);       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }       <br />&#160;&#160;&#160; } </p>
<p>}</p>
<p>&#160;</p>
</blockquote>
<p>gwt有关代码，使用了gwt的mvp模式，http 401会引发NeedLoginEvent事件，代码就不贴出来了，可以见google code上的源代码。</p>
<p>还有一种情况，是授权不够的问题，即已经登录了，但是这个用户没有足够权限访问某个资源。按理说，应该根据用户的权限动态生成界面，这样用户就不会访问未授权的资源了。但是也可能是这样，比如用户有两个帐号，一个普通用户，一个管理员的。用户的操作可能产生url的变化，在gwt中是token，比如：</p>
<blockquote><p><font style="background-color: #ffffff"><a href="http://easymorse.com/aaa/a.html#admin">http://easymorse.com/aaa/a.html#admin</a></font></p>
</blockquote>
<p>用户用管理员权限登录访问过上述资源，并保留了书签，下次直接访问书签，却用了普通用户登录。这时就需要上面提到的处理方式。</p>
<p>源代码见：</p>
<blockquote><p><a href="http://easymorse.googlecode.com/svn/tags/Videos-0.3.2/">http://easymorse.googlecode.com/svn/tags/Videos-0.3.2/</a></p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2240/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>spring 3.0中的校验</title>
		<link>http://marshal.easymorse.com/archives/2221?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=spring-3-0%25e4%25b8%25ad%25e7%259a%2584%25e6%25a0%25a1%25e9%25aa%258c</link>
		<comments>http://marshal.easymorse.com/archives/2221#comments</comments>
		<pubDate>Fri, 22 Jan 2010 05:59:49 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[hibernate validator]]></category>
		<category><![CDATA[jsr303]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring validation]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2221</guid>
		<description><![CDATA[在weapon项目中，表单在客户端实现了校验，简单而有效。但是还要提防可能出现的客户端校验失效问题，在这种情况下也要做到服务器端不会录入问题数据。这就需要服务器端校验。 spring 3.0引入了jsr 303的java校验工具框架。 需要导入的类库： &#60;dependency&#62; &#160;&#160;&#160; &#60;groupId&#62;org.hibernate&#60;/groupId&#62; &#160;&#160;&#160; &#60;artifactId&#62;hibernate-validator&#60;/artifactId&#62; &#160;&#160;&#160; &#60;version&#62;4.0.0.GA&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#160;&#160;&#160; &#60;groupId&#62;org.slf4j&#60;/groupId&#62; &#160;&#160;&#160; &#60;artifactId&#62;slf4j-log4j12&#60;/artifactId&#62; &#160;&#160;&#160; &#60;version&#62;1.5.6&#60;/version&#62; &#60;/dependency&#62; &#160; spring的配置： &#60;bean &#160;&#160;&#160; class=&#34;org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter&#34;&#62; &#160;&#160;&#160; &#60;property name=&#34;webBindingInitializer&#34;&#62; &#160;&#160;&#160;&#160;&#160;&#160;&#160; &#60;bean &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&#34;org.springframework.web.bind.support.ConfigurableWebBindingInitializer&#34;&#62; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#60;property name=&#34;validator&#34; ref=&#34;validator&#34; /&#62; &#160;&#160;&#160;&#160;&#160;&#160;&#160; &#60;/bean&#62; &#160;&#160;&#160; &#60;/property&#62; &#60;/bean&#62; &#60;bean id=&#34;validator&#34; &#160;&#160;&#160; class=&#34;org.springframework.validation.beanvalidation.LocalValidatorFactoryBean&#34; /&#62; &#160; 然后写点儿代码即可。首先是domain对象，就是javabean，要校验的名词对象，需要这样写： @NotNull @NotEmpty private String name; [...]]]></description>
			<content:encoded><![CDATA[<p>在weapon项目中，表单在客户端实现了校验，简单而有效。但是还要提防可能出现的客户端校验失效问题，在这种情况下也要做到服务器端不会录入问题数据。这就需要服务器端校验。</p>
<p>spring 3.0引入了jsr 303的java校验工具框架。</p>
<p>需要导入的类库：</p>
<blockquote><p>&lt;dependency&gt;      <br />&#160;&#160;&#160; &lt;groupId&gt;org.hibernate&lt;/groupId&gt;       <br />&#160;&#160;&#160; &lt;artifactId&gt;hibernate-validator&lt;/artifactId&gt;       <br />&#160;&#160;&#160; &lt;version&gt;4.0.0.GA&lt;/version&gt;       <br />&lt;/dependency&gt;       <br />&lt;dependency&gt;       <br />&#160;&#160;&#160; &lt;groupId&gt;org.slf4j&lt;/groupId&gt;       <br />&#160;&#160;&#160; &lt;artifactId&gt;slf4j-log4j12&lt;/artifactId&gt;       <br />&#160;&#160;&#160; &lt;version&gt;1.5.6&lt;/version&gt;       <br />&lt;/dependency&gt;</p>
<p>&#160;</p>
</blockquote>
<p> <span id="more-2221"></span>
<p>spring的配置：</p>
<blockquote><p>&lt;bean      <br />&#160;&#160;&#160; class=&quot;org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter&quot;&gt;       <br />&#160;&#160;&#160; &lt;property name=&quot;webBindingInitializer&quot;&gt;       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;org.springframework.web.bind.support.ConfigurableWebBindingInitializer&quot;&gt;       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;validator&quot; ref=&quot;validator&quot; /&gt;       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;       <br />&#160;&#160;&#160; &lt;/property&gt;       <br />&lt;/bean&gt; </p>
<p>&lt;bean id=&quot;validator&quot;      <br />&#160;&#160;&#160; class=&quot;org.springframework.validation.beanvalidation.LocalValidatorFactoryBean&quot; /&gt;</p>
<p>&#160;</p>
</blockquote>
<p>然后写点儿代码即可。首先是domain对象，就是javabean，要校验的名词对象，需要这样写：</p>
<blockquote><p>@NotNull      <br />@NotEmpty       <br />private String name;</p>
<p>&#160;</p>
</blockquote>
<p>表示不能为空，也不能为空字串。这里NotEmpty不是jsr303标准的注解，是hibernate扩展的。</p>
<p>使用校验：</p>
<blockquote><p>@RequestMapping(value = &quot;/save.json&quot;, method = RequestMethod.POST)      <br />public String save(@Valid Weapon weapon, BindingResult results) {       <br />&#160;&#160;&#160; if (results.hasErrors()) {       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new RuntimeException(results.getAllErrors().toString());       <br />&#160;&#160;&#160; } </p>
<p>&#160;&#160;&#160; if (weapon.getId() == null || weapon.getId().isEmpty()) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; create(weapon);       <br />&#160;&#160;&#160; } else {       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; update(weapon);       <br />&#160;&#160;&#160; } </p>
<p>&#160;&#160;&#160; return &quot;saved&quot;;      <br />}</p>
</blockquote>
<p>在这里通过Valid注解，标注需要校验的变量。后面的BindingResult，是存储错误信息的对象。这里做的很简单，如果校验有错误，将直接抛出runtime异常。因为正常情况下都应该通过客户端的校验机制处理了。</p>
<p>这里将客户端校验代码屏蔽，测试到的结果是返回了异常：</p>
<blockquote><p>java.lang.RuntimeException: [Field error in object 'weapon' on field 'name': rejected value []; codes [NotEmpty.weapon.name,NotEmpty.name,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [weapon.name,name]; arguments []; default message [name],{org.hibernate.validator.constraints.NotEmpty.message},[Ljava.lang.Class;@1d6ced0,[Ljava.lang.Class;@1a3ece5]; default message [may not be empty]]      <br />&#160;&#160;&#160; at com.easymorse.weapons.server.WeaponService.save(WeaponService.java:74)</p>
</blockquote>
<p>另外，还可以在注解中使用提示信息，比如：</p>
<blockquote><p><font style="background-color: #ffffff">@NotEmpty(message=”请输入名称”)</font></p>
</blockquote>
<p>还有，校验注释有：</p>
<blockquote><p><a></a>
<p>@Pattern(regex=, flag=)</p>
</p>
<p>   <font style="background-color: #ffffff"></font></p></blockquote>
<p>这是标准的，可以写正则表达式。</p>
<p>源代码：</p>
<blockquote><p><a title="http://easymorse.googlecode.com/svn/tags/Weapons-0.5.5" href="http://easymorse.googlecode.com/svn/tags/Weapons-0.5.5">http://easymorse.googlecode.com/svn/tags/Weapons-0.5.5</a></p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2221/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>weapon项目增加文件上传功能</title>
		<link>http://marshal.easymorse.com/archives/2220?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=weapon%25e9%25a1%25b9%25e7%259b%25ae%25e5%25a2%259e%25e5%258a%25a0%25e6%2596%2587%25e4%25bb%25b6%25e4%25b8%258a%25e4%25bc%25a0%25e5%258a%259f%25e8%2583%25bd</link>
		<comments>http://marshal.easymorse.com/archives/2220#comments</comments>
		<pubDate>Thu, 21 Jan 2010 07:39:50 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[gwt view]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring mvc]]></category>
		<category><![CDATA[weapon project]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2220</guid>
		<description><![CDATA[为weapon项目增加了图片上传功能。 这需要服务器端（Spring MVC）和客户端（GWT）两部分程序。 spring mvc这部分比较简单。需要类库支持： &#60;dependency&#62; &#160;&#160;&#160; &#60;groupId&#62;commons-fileupload&#60;/groupId&#62; &#160;&#160;&#160; &#60;artifactId&#62;commons-fileupload&#60;/artifactId&#62; &#160;&#160;&#160; &#60;version&#62;1.2.1&#60;/version&#62; &#60;/dependency&#62; &#160; 然后，需要配置spring的支持： &#60;bean id=&#34;multipartResolver&#34; &#160;&#160;&#160; class=&#34;org.springframework.web.multipart.commons.CommonsMultipartResolver&#34;&#62; &#160;&#160;&#160; &#60;property name=&#34;maxUploadSize&#34; value=&#34;100000&#34; /&#62; &#60;/bean&#62; 最后，写spring程序部分，需要至少传递一个id参数和一个文件内容部分。 @RequestMapping(&#34;/upload.do&#34;) public void upload(@RequestParam(&#34;id&#34;) String id, &#160;&#160;&#160;&#160;&#160;&#160;&#160; @RequestParam(&#34;file&#34;) MultipartFile file, &#160;&#160;&#160;&#160;&#160;&#160;&#160; HttpServletRequest request, HttpServletResponse response) { &#160;&#160;&#160; try { &#160;&#160;&#160;&#160;&#160;&#160;&#160; if (id != null &#38;&#38; !id.isEmpty()) { &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; File [...]]]></description>
			<content:encoded><![CDATA[<p>为weapon项目增加了图片上传功能。</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/01/image19.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://marshal.easymorse.com/wp-content/uploads/2010/01/image_thumb19.png" width="256" height="310" /></a> </p>
<p>这需要服务器端（Spring MVC）和客户端（GWT）两部分程序。</p>
<p> <span id="more-2220"></span>
<p>spring mvc这部分比较简单。需要类库支持：</p>
<blockquote><p>&lt;dependency&gt;     <br />&#160;&#160;&#160; &lt;groupId&gt;commons-fileupload&lt;/groupId&gt;      <br />&#160;&#160;&#160; &lt;artifactId&gt;commons-fileupload&lt;/artifactId&gt;      <br />&#160;&#160;&#160; &lt;version&gt;1.2.1&lt;/version&gt;      <br />&lt;/dependency&gt;</p>
<p>&#160;</p>
</blockquote>
<p>然后，需要配置spring的支持：</p>
<blockquote><p>&lt;bean id=&quot;multipartResolver&quot;     <br />&#160;&#160;&#160; class=&quot;org.springframework.web.multipart.commons.CommonsMultipartResolver&quot;&gt;      <br />&#160;&#160;&#160; &lt;property name=&quot;maxUploadSize&quot; value=&quot;100000&quot; /&gt;      <br />&lt;/bean&gt;</p>
</blockquote>
<p>最后，写spring程序部分，需要至少传递一个id参数和一个文件内容部分。</p>
<blockquote><p>@RequestMapping(&quot;/upload.do&quot;)     <br />public void upload(@RequestParam(&quot;id&quot;) String id,      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; @RequestParam(&quot;file&quot;) MultipartFile file,      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; HttpServletRequest request, HttpServletResponse response) {      <br />&#160;&#160;&#160; try {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (id != null &amp;&amp; !id.isEmpty()) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; File image = new File(request.getSession().getServletContext()      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; .getRealPath(&quot;/images/&quot; + id));      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (image.exists()) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; image.delete();      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FileOutputStream outputStream = new FileOutputStream(image);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; outputStream.write(file.getBytes());      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; outputStream.close();      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; response.getWriter().append(&quot;ok&quot;);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; response.getWriter().append(&quot;undo while no id&quot;);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />&#160;&#160;&#160; } catch (IOException e) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new RuntimeException(e);      <br />&#160;&#160;&#160; }      <br />}</p>
<p>&#160;</p>
</blockquote>
<p>客户端，代码有点儿乱，主要是事件处理部分，采用比较直接的方式写了这部分的对话框和处理代码。</p>
<p>点击图片，将弹出替换图片的对话框。这里面是一个form，和form提交的监听器，这里只写了提交成功的监听器。</p>
<blockquote><p>@Override     <br />public void setData(final Weapon weapon) {      <br />&#160;&#160;&#160; this.name.setValue(weapon.getName());      <br />&#160;&#160;&#160; this.description.setValue(weapon.getDescription());      <br />&#160;&#160;&#160; this.image = new Image(&quot;/getImage.do?id=&quot; + weapon.getId() + &quot;&amp;time=&quot;      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + System.currentTimeMillis());      <br />&#160;&#160;&#160; this.detailsTable.setWidget(2, 1, this.image); </p>
<p>&#160;&#160;&#160; this.image.addClickHandler(new ClickHandler() { </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; @Override     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void onClick(ClickEvent event) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; final DialogBox dialogBox = new DialogBox();      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogBox.setText(&quot;替换图片&quot;);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogBox.setGlassEnabled(true);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogBox.setAnimationEnabled(true);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; VerticalPanel dialogContents = new VerticalPanel(); </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; final FormPanel form = new FormPanel();     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; form.setAction(&quot;/upload.do&quot;);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; form.setEncoding(FormPanel.ENCODING_MULTIPART);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; form.setMethod(FormPanel.METHOD_POST); </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; form.addSubmitCompleteHandler(new SubmitCompleteHandler() {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; @Override      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void onSubmitComplete(SubmitCompleteEvent event) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogBox.setGlassEnabled(false);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogBox.hide();      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; setData(weapon);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; });      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogContents.add(form); </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; HorizontalPanel uploadPanel = new HorizontalPanel();     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; form.add(uploadPanel); </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; final FileUpload fileUpload = new FileUpload();     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; uploadPanel.add(fileUpload);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; fileUpload.setName(&quot;file&quot;);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Hidden hidden = new Hidden(&quot;id&quot;, weapon.getId());      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; uploadPanel.add(hidden); </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Button sendButton = new Button(&quot;上传&quot;, new ClickHandler() { </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; @Override     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void onClick(ClickEvent event) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (fileUpload.getFilename().isEmpty()) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Window.alert(&quot;请选择文件后上传&quot;);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; form.submit();      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; });      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; uploadPanel.add(sendButton); </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Button closeButton = new Button(&quot;关闭&quot;, new ClickHandler() {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; @Override      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void onClick(ClickEvent event) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogBox.setGlassEnabled(false);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogBox.hide();      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; });      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogContents.add(closeButton); </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogContents.setSpacing(4);     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogBox.setWidget(dialogContents);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dialogBox.show();      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />&#160;&#160;&#160; });</p>
</blockquote>
<p>源代码见：</p>
<blockquote><p><a title="http://easymorse.googlecode.com/svn/tags/Weapons-0.5.0" href="http://easymorse.googlecode.com/svn/tags/Weapons-0.5.0">http://easymorse.googlecode.com/svn/tags/Weapons-0.5.0</a></p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2220/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>weapon项目服务器端动态加载图片</title>
		<link>http://marshal.easymorse.com/archives/2216?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=weapon%25e9%25a1%25b9%25e7%259b%25ae%25e6%259c%258d%25e5%258a%25a1%25e5%2599%25a8%25e7%25ab%25af%25e5%258a%25a8%25e6%2580%2581%25e5%258a%25a0%25e8%25bd%25bd%25e5%259b%25be%25e7%2589%2587</link>
		<comments>http://marshal.easymorse.com/archives/2216#comments</comments>
		<pubDate>Thu, 21 Jan 2010 03:02:00 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring mvc]]></category>
		<category><![CDATA[weapon project]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2216</guid>
		<description><![CDATA[weapon项目已经可以加载图片了，见weapon项目增加图片的显示。但是静态的。 使用spring mvc动态加载图片文件，然后将流写入到Servlet输出流中。 代码如下： @RequestMapping(&#34;/getImage.do&#34;) public void getImage(@RequestParam(&#34;id&#34;) String id, &#160;&#160;&#160;&#160;&#160;&#160;&#160; HttpServletRequest request, HttpServletResponse response) { &#160;&#160;&#160; response.setHeader(&#34;Pragma&#34;, &#34;No-cache&#34;); &#160;&#160;&#160; response.setHeader(&#34;Cache-Control&#34;, &#34;no-cache&#34;); &#160;&#160;&#160; response.setDateHeader(&#34;Expires&#34;, 0); &#160;&#160;&#160; if (id == null &#124;&#124; id.isEmpty()) { &#160;&#160;&#160;&#160;&#160;&#160;&#160; id = &#34;1&#34;; &#160;&#160;&#160; } &#160;&#160;&#160; try { &#160;&#160;&#160;&#160;&#160;&#160;&#160; OutputStream outputStream = response.getOutputStream(); &#160;&#160;&#160;&#160;&#160;&#160;&#160; BufferedInputStream inputStream = new BufferedInputStream( &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; new [...]]]></description>
			<content:encoded><![CDATA[<p>weapon项目已经可以加载图片了，见<a href="http://marshal.easymorse.com/archives/2214" title="weapon项目增加图片的显示">weapon项目增加图片的显示</a>。但是静态的。</p>
<p>使用spring mvc动态加载图片文件，然后将流写入到Servlet输出流中。</p>
<p>代码如下：</p>
<blockquote><p>@RequestMapping(&quot;/getImage.do&quot;)     <br />public void getImage(@RequestParam(&quot;id&quot;) String id,      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; HttpServletRequest request, HttpServletResponse response) {      <br />&#160;&#160;&#160; response.setHeader(&quot;Pragma&quot;, &quot;No-cache&quot;);      <br />&#160;&#160;&#160; response.setHeader(&quot;Cache-Control&quot;, &quot;no-cache&quot;);      <br />&#160;&#160;&#160; response.setDateHeader(&quot;Expires&quot;, 0); </p>
<p>&#160;&#160;&#160; if (id == null || id.isEmpty()) {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; id = &quot;1&quot;;      <br />&#160;&#160;&#160; } </p>
<p>&#160;&#160;&#160; try {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; OutputStream outputStream = response.getOutputStream();      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; BufferedInputStream inputStream = new BufferedInputStream(      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; new FileInputStream(request.getSession()      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; .getServletContext().getRealPath(&quot;/images/&quot;)      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + id));      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; byte[] data = new byte[1024];      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; for (int i = inputStream.read(data); i &gt; 0; i = inputStream      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; .read(data)) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; outputStream.write(data, 0, i);      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; inputStream.close();      <br />&#160;&#160;&#160; } catch (IOException e) {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new RuntimeException(e);      <br />&#160;&#160;&#160; }      <br />}</p>
<p>&#160;</p>
</blockquote>
<p> <span id="more-2216"></span>
<p>其他的，变化不大，需要在web.xml文件中增加映射：</p>
<blockquote><p>&lt;servlet-mapping&gt;     <br />&#160;&#160;&#160; &lt;servlet-name&gt;controller&lt;/servlet-name&gt;      <br />&#160;&#160;&#160; &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;      <br />&lt;/servlet-mapping&gt;</p>
<p>&#160;</p>
</blockquote>
<p>这样就可以动态加载图片了。</p>
<p>但是问题在于，gwt这边只加载一次同url的图片，如果再次创建带图片的对话框，将不再和服务器端通信。这需要GWT端的解决方案。</p>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2216/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>weapon项目修改表单为对话框</title>
		<link>http://marshal.easymorse.com/archives/2210?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=weapon%25e9%25a1%25b9%25e7%259b%25ae%25e4%25bf%25ae%25e6%2594%25b9%25e8%25a1%25a8%25e5%258d%2595%25e4%25b8%25ba%25e5%25af%25b9%25e8%25af%259d%25e6%25a1%2586</link>
		<comments>http://marshal.easymorse.com/archives/2210#comments</comments>
		<pubDate>Wed, 20 Jan 2010 12:21:26 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[gwt mvp]]></category>
		<category><![CDATA[gwt view]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[weapon project]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2210</guid>
		<description><![CDATA[做了个简单的处理，将weapon项目中的表单处理为对话框。 做的不是很彻底，只是简单的。细作的话，需要调整事件处理部分。 截图： 另外，修改了小的bug，通过除firefox浏览器提交中文都是乱码，包括iphone和htc g3，查了一下原因，比如android的chrome，默认的字符集是iso-8859-1。 通过spring的filter强制服务器端做utf-8编码，问题解决。 &#60;filter&#62; &#160;&#160;&#160; &#60;filter-name&#62;Set Character Encoding&#60;/filter-name&#62; &#160;&#160;&#160; &#60;filter-class&#62;org.springframework.web.filter.CharacterEncodingFilter&#60;/filter-class&#62; &#160;&#160;&#160; &#60;init-param&#62; &#160;&#160;&#160;&#160;&#160;&#160;&#160; &#60;param-name&#62;encoding&#60;/param-name&#62; &#160;&#160;&#160;&#160;&#160;&#160;&#160; &#60;param-value&#62;utf8&#60;/param-value&#62; &#160;&#160;&#160; &#60;/init-param&#62; &#60;/filter&#62; &#60;filter-mapping&#62; &#160;&#160;&#160; &#60;filter-name&#62;Set Character Encoding&#60;/filter-name&#62; &#160;&#160;&#160; &#60;url-pattern&#62;/*&#60;/url-pattern&#62; &#60;/filter-mapping&#62; &#160; 见代码： http://easymorse.googlecode.com/svn/tags/Weapons-0.4.2]]></description>
			<content:encoded><![CDATA[<p>做了个简单的处理，将weapon项目中的表单处理为对话框。</p>
<p>做的不是很彻底，只是简单的。细作的话，需要调整事件处理部分。</p>
<p>截图：</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/01/image17.png" rel="lightbox"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://marshal.easymorse.com/wp-content/uploads/2010/01/image_thumb17.png" width="260" height="232" /></a> </p>
<p> <span id="more-2210"></span>
<p>另外，修改了小的bug，通过除firefox浏览器提交中文都是乱码，包括iphone和htc g3，查了一下原因，比如android的chrome，默认的字符集是iso-8859-1。</p>
<p>通过spring的filter强制服务器端做utf-8编码，问题解决。</p>
<blockquote><p>&lt;filter&gt;     <br />&#160;&#160;&#160; &lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt;      <br />&#160;&#160;&#160; &lt;filter-class&gt;org.springframework.web.filter.CharacterEncodingFilter&lt;/filter-class&gt;      <br />&#160;&#160;&#160; &lt;init-param&gt;      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;param-name&gt;encoding&lt;/param-name&gt;      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;param-value&gt;utf8&lt;/param-value&gt;      <br />&#160;&#160;&#160; &lt;/init-param&gt;      <br />&lt;/filter&gt;      <br />&lt;filter-mapping&gt;      <br />&#160;&#160;&#160; &lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt;      <br />&#160;&#160;&#160; &lt;url-pattern&gt;/*&lt;/url-pattern&gt;      <br />&lt;/filter-mapping&gt;</p>
</blockquote>
<p>&#160;</p>
<p>见代码：</p>
<blockquote><p><a title="http://easymorse.googlecode.com/svn/tags/Weapons-0.4.2" href="http://easymorse.googlecode.com/svn/tags/Weapons-0.4.2">http://easymorse.googlecode.com/svn/tags/Weapons-0.4.2</a></p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2210/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>weapon项目实现增加新记录功能</title>
		<link>http://marshal.easymorse.com/archives/2199?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=weapon%25e9%25a1%25b9%25e7%259b%25ae%25e5%25ae%259e%25e7%258e%25b0%25e5%25a2%259e%25e5%258a%25a0%25e6%2596%25b0%25e8%25ae%25b0%25e5%25bd%2595%25e5%258a%259f%25e8%2583%25bd</link>
		<comments>http://marshal.easymorse.com/archives/2199#comments</comments>
		<pubDate>Wed, 20 Jan 2010 05:27:26 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[gwt json]]></category>
		<category><![CDATA[gwt mvp]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring mvc]]></category>
		<category><![CDATA[weapon project]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2199</guid>
		<description><![CDATA[weapon项目，已经实现了列表和删除功能。继续临摹google mvp项目。实现增加新记录的功能。 目前实现功能截图，列表功能： &#160; 增加新记录： 保存后的效果： 在实现过程中发现原来写的WeapenDeleteEvent和相关Handler类没有作用。在event包下面的代码应该是事件和对应处理类。只有需要视图切换的时候才需要创建这些。 所有和视图切换有关的代码，都应该集中到AppController中，在presenter包中的部分，都是具体视图内部的事件变化和控制。 这里牵扯到一些技术点，Weapon是javabean，虽然是JavaScriptObject类型的，不能直接实例化，比如new，这是因为其实它是javacript在java中的代理对象。 之前没有问题，因为并不需要实例化Weapon对象，因为是从response中得到文本，借助GWT自动得到Weapon对象。但是现在需要将表单中的数据发送到服务器端。好像不用封装为对象也可以，但是这样其实并不省事儿。表单的参数很多，传递起来不方便，不利于维护。 需要实例化Weapon，不能new，而是要这样： this.weapon = JavaScriptObject.createObject().cast(); 然后，通过POST，提交到服务器端，用的方式和前面删除功能类似： RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.POST, &#160;&#160;&#160;&#160;&#160;&#160;&#160; &#34;../save.json&#34;); requestBuilder.setHeader(&#34;Content-Type&#34;, &#160;&#160;&#160;&#160;&#160;&#160;&#160; &#34;application/x-www-form-urlencoded&#34;); requestBuilder.setRequestData(new StringBuilder().append(&#34;name=&#34;) &#160;&#160;&#160;&#160;&#160;&#160;&#160; .append(weapon.getName()).append(&#34;&#38;description=&#34;).append( &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; weapon.getDescription()).toString()); &#160; 然后，需要spring mvc这边能够比较舒服的得到Weapon实例。代码如下： @RequestMapping(value = &#34;/save.json&#34;, method = RequestMethod.POST) public String save(Weapon weapon) { &#160;&#160;&#160; if (weapon.getId() == null) { &#160;&#160;&#160;&#160;&#160;&#160;&#160; create(weapon); &#160;&#160;&#160; } [...]]]></description>
			<content:encoded><![CDATA[<p>weapon项目，已经实现了列表和删除功能。继续临摹google mvp项目。实现增加新记录的功能。</p>
<p>目前实现功能截图，列表功能：</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/01/image13.png" rel="lightbox"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://marshal.easymorse.com/wp-content/uploads/2010/01/image_thumb13.png" width="260" height="137" /></a>&#160;</p>
<p>增加新记录：</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/01/image14.png" rel="lightbox"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://marshal.easymorse.com/wp-content/uploads/2010/01/image_thumb14.png" width="269" height="220" /></a> </p>
<p>保存后的效果：</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/01/image15.png" rel="lightbox"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://marshal.easymorse.com/wp-content/uploads/2010/01/image_thumb15.png" width="260" height="153" /></a> </p>
<p> <span id="more-2199"></span>
<p>在实现过程中发现原来写的WeapenDeleteEvent和相关Handler类没有作用。在event包下面的代码应该是事件和对应处理类。只有需要视图切换的时候才需要创建这些。</p>
<p>所有和视图切换有关的代码，都应该集中到AppController中，在presenter包中的部分，都是具体视图内部的事件变化和控制。</p>
<p>这里牵扯到一些技术点，Weapon是javabean，虽然是JavaScriptObject类型的，不能直接实例化，比如new，这是因为其实它是javacript在java中的代理对象。</p>
<p>之前没有问题，因为并不需要实例化Weapon对象，因为是从response中得到文本，借助GWT自动得到Weapon对象。但是现在需要将表单中的数据发送到服务器端。好像不用封装为对象也可以，但是这样其实并不省事儿。表单的参数很多，传递起来不方便，不利于维护。</p>
<p>需要实例化Weapon，不能new，而是要这样：</p>
<blockquote><p>this.weapon = JavaScriptObject.createObject().cast();</p>
</blockquote>
<p>然后，通过POST，提交到服务器端，用的方式和前面删除功能类似：</p>
<blockquote><p>RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.POST,     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &quot;../save.json&quot;);      <br />requestBuilder.setHeader(&quot;Content-Type&quot;,      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &quot;application/x-www-form-urlencoded&quot;); </p>
<p>requestBuilder.setRequestData(new StringBuilder().append(&quot;name=&quot;)     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; .append(weapon.getName()).append(&quot;&amp;description=&quot;).append(      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; weapon.getDescription()).toString());</p>
<p>&#160;</p>
</blockquote>
<p>然后，需要spring mvc这边能够比较舒服的得到Weapon实例。代码如下：</p>
<blockquote><p>@RequestMapping(value = &quot;/save.json&quot;, method = RequestMethod.POST)     <br />public String save(Weapon weapon) { </p>
<p>&#160;&#160;&#160; if (weapon.getId() == null) {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; create(weapon);      <br />&#160;&#160;&#160; } </p>
<p>&#160;&#160;&#160; return &quot;saved&quot;;     <br />}</p>
</blockquote>
<p>可以看到spring可以自动将同名参数注入到方法的参数中。</p>
<p>源代码如下：</p>
<blockquote><p><a href="http://easymorse.googlecode.com/svn/tags/Weapons-0.3/">http://easymorse.googlecode.com/svn/tags/Weapons-0.3/</a></p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2199/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>gwt weapon项目增加删除功能</title>
		<link>http://marshal.easymorse.com/archives/2192?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gwt-weapon%25e9%25a1%25b9%25e7%259b%25ae%25e5%25a2%259e%25e5%258a%25a0%25e5%2588%25a0%25e9%2599%25a4%25e5%258a%259f%25e8%2583%25bd</link>
		<comments>http://marshal.easymorse.com/archives/2192#comments</comments>
		<pubDate>Tue, 19 Jan 2010 11:06:43 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[gwt mvp]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring json]]></category>
		<category><![CDATA[spring mvc]]></category>
		<category><![CDATA[weapon project]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2192</guid>
		<description><![CDATA[为weapon项目（gwt实现基于spring的json应用实例）增加了删除功能。增加了基本的事件处理机制。主要是event包下面的类。 在原有列表功能基础上增加了删除功能。不过还不完善，没有加上地址栏历史处理部分。 主要需要解决的是，删除功能，因为改变了资源，通过的是POST方法（当然最好是用DELETE方法）。 在GWT客户端的POST写法是： RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.POST, “../delete.json”); requestBuilder.setHeader(“Content-Type”, “application/x-www-form-urlencoded”); StringBuilder builder = new StringBuilder(); for (Integer id : selectedRows) { builder.append(“id=”).append(id).append(“&#38;”); } requestBuilder.setRequestData(builder.toString()); requestBuilder.setCallback(new RequestCallback() { @Override public void onResponseReceived(Request request, Response response) { list(); } @Override public void onError(Request request, Throwable e) { Window.alert(“error”); } }); try { requestBuilder.send(); } catch [...]]]></description>
			<content:encoded><![CDATA[<p>为weapon项目（<a href="http://marshal.easymorse.com/archives/2190" title="gwt实现基于spring的json应用实例">gwt实现基于spring的json应用实例</a>）增加了删除功能。增加了基本的事件处理机制。主要是event包下面的类。</p>
<p>在原有列表功能基础上增加了删除功能。不过还不完善，没有加上地址栏历史处理部分。</p>
<p>主要需要解决的是，删除功能，因为改变了资源，通过的是POST方法（当然最好是用DELETE方法）。</p>
<p><span id="more-2192"></span></p>
<p>在GWT客户端的POST写法是：</p>
<blockquote><p>RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.POST,<br />
“../delete.json”);<br />
requestBuilder.setHeader(“Content-Type”,<br />
“application/x-www-form-urlencoded”);</p>
<p>StringBuilder builder = new StringBuilder();</p>
<p>for (Integer id : selectedRows) {<br />
builder.append(“id=”).append(id).append(“&amp;”);<br />
}</p>
<p>requestBuilder.setRequestData(builder.toString());</p>
<p>requestBuilder.setCallback(new RequestCallback() {</p>
<p>@Override<br />
public void onResponseReceived(Request request, Response response) {<br />
list();<br />
}</p>
<p>@Override<br />
public void onError(Request request, Throwable e) {<br />
Window.alert(“error”);<br />
}<br />
});<br />
try {<br />
requestBuilder.send();<br />
} catch (RequestException e) {<br />
e.printStackTrace();<br />
}</p></blockquote>
<p>在服务器端使用的是spring，写法是：</p>
<blockquote><p>@RequestMapping(value = “/delete.json”, method = RequestMethod.POST)<br />
public String delete(@RequestParam(“id”) List&lt;Integer&gt; ids) {<br />
for (Integer id : ids) {<br />
data.remove(id.intValue());<br />
}<br />
return “delete”;<br />
}</p></blockquote>
<p>这里限制是POST方法提交才可以。</p>
<p>这个代码还有很多问题，比如对异常的处理，对GWT model部分的处理（需要使用观察者模式解耦）等。在后续演化版本中逐渐加入。</p>
<p>源代码见：</p>
<blockquote><p><a title="http://easymorse.googlecode.com/svn/tags/Weapons-0.2" href="http://easymorse.googlecode.com/svn/tags/Weapons-0.2">http://easymorse.googlecode.com/svn/tags/Weapons-0.2</a></p></blockquote>
<p>下一个版本，将实现“增加”武器功能。</p>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2192/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>gwt实现基于spring的json应用实例</title>
		<link>http://marshal.easymorse.com/archives/2190?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gwt%25e5%25ae%259e%25e7%258e%25b0%25e5%259f%25ba%25e4%25ba%258espring%25e7%259a%2584json%25e5%25ba%2594%25e7%2594%25a8%25e5%25ae%259e%25e4%25be%258b</link>
		<comments>http://marshal.easymorse.com/archives/2190#comments</comments>
		<pubDate>Tue, 19 Jan 2010 09:03:50 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[gwt json]]></category>
		<category><![CDATA[gwt mvp]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring json]]></category>
		<category><![CDATA[weapon project]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2190</guid>
		<description><![CDATA[在这里写了一个实例，我管它叫“武器列表”。仿google GWT的mvp示例写的，它的示例是为了演示MVP开发模式写的，见： http://code.google.com/p/gwt-mvp-sample/ 但是这个示例使用的是rpc方式和服务器通信。我们使用spring 3.0和json通信。 因此参照它写了个简单的实例，主要是解释json数据如何发送和如何获取。另外，临摹了一下，体会mvp模式。 spring的json返回视图，默认情况下将ModelMap中的所有对象都转化了，而实际上客户端只需要其中的某个对象。 这需要这样，比如： @RequestMapping(“/list.json”) @ModelAttribute(“data”) public List list() { return data; } 这里使用了ModelAttribute注解，这样只返回名为data的对象，在这里是个List，样子大概是这样： {“data”:[{"name":"w1","id":"1","description":"w1.desc","imageUrl":"w1.png"},{"name":"w2","id":"2","description":"w2.desc","imageUrl":"w2.png"}]} 一个名为data的数组。 那么，在gwt的客户端，我只想要这个数组，而不是带data属性的对象，怎么办呢？见Weapon代码，用于表示客户端的模型： package com.easymorse.weapons.client.model; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; public class Weapon extends JavaScriptObject { protected Weapon() { } public final native String getId() /*-{ return this.id; }-*/; public final native void setId(String id) /*-{ this.id = [...]]]></description>
			<content:encoded><![CDATA[<p>在这里写了一个实例，我管它叫“武器列表”。仿google GWT的mvp示例写的，它的示例是为了演示MVP开发模式写的，见：</p>
<blockquote><p><a href="http://code.google.com/p/gwt-mvp-sample/">http://code.google.com/p/gwt-mvp-sample/</a></p></blockquote>
<p>但是这个示例使用的是rpc方式和服务器通信。我们使用spring 3.0和json通信。</p>
<p>因此参照它写了个简单的实例，主要是解释json数据如何发送和如何获取。另外，临摹了一下，体会mvp模式。</p>
<p><span id="more-2190"></span></p>
<p>spring的json返回视图，默认情况下将ModelMap中的所有对象都转化了，而实际上客户端只需要其中的某个对象。</p>
<p>这需要这样，比如：</p>
<blockquote><p>@RequestMapping(“/list.json”)<br />
@ModelAttribute(“data”)<br />
public List list() {<br />
return data;<br />
}</p></blockquote>
<p>这里使用了ModelAttribute注解，这样只返回名为data的对象，在这里是个List，样子大概是这样：</p>
<blockquote><p>{“data”:[{"name":"w1","id":"1","description":"w1.desc","imageUrl":"w1.png"},{"name":"w2","id":"2","description":"w2.desc","imageUrl":"w2.png"}]}</p></blockquote>
<p>一个名为data的数组。</p>
<p>那么，在gwt的客户端，我只想要这个数组，而不是带data属性的对象，怎么办呢？见Weapon代码，用于表示客户端的模型：</p>
<blockquote><p>package com.easymorse.weapons.client.model;</p>
<p>import com.google.gwt.core.client.JavaScriptObject;<br />
import com.google.gwt.core.client.JsArray;</p>
<p>public class Weapon extends JavaScriptObject {</p>
<p>protected Weapon() {<br />
}</p>
<p>public final native String getId() /*-{<br />
return this.id;<br />
}-*/;</p>
<p>public final native void setId(String id) /*-{<br />
this.id = id;<br />
}-*/;</p>
<p>public final native String getName() /*-{<br />
return this.name;<br />
}-*/;</p>
<p>public final native void setName(String name) /*-{<br />
this.name = name;<br />
}-*/;</p>
<p>public final native String getDescription() /*-{<br />
return this.description;<br />
}-*/;</p>
<p>public final native void setDescription(String description) /*-{<br />
this.description = description;<br />
}-*/;</p>
<p>public final native String getImageUrl() /*-{<br />
return this.imageUrl;<br />
}-*/;</p>
<p>public final native void setImageUrl(String imageUrl) /*-{<br />
this.imageUrl = imageUrl;<br />
}-*/;</p>
<p>public static native JsArray&lt;Weapon&gt; arrayFromJson(String jsonString) /*-{<br />
return eval(&#8216;(&#8216; + jsonString + &#8216;)&#8217;).data;<br />
}-*/;<br />
}</p></blockquote>
<p>这里在eval方法执行后，加.data，表示只取data属性的内容，也即数组。当然数组的格式是JsArray而不是java的List啥的了。</p>
<p>其他部分，使用了MVP模式，但是还不完全，因为没有事件处理部分。在后续实例中逐渐加上。</p>
<p>源代码见：</p>
<blockquote><p><a title="http://easymorse.googlecode.com/svn/tags/Weapons-0.1" href="http://easymorse.googlecode.com/svn/tags/Weapons-0.1">http://easymorse.googlecode.com/svn/tags/Weapons-0.1</a></p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2190/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>gwt异常NoSuchMethodError的解决</title>
		<link>http://marshal.easymorse.com/archives/2189?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gwt%25e5%25bc%2582%25e5%25b8%25b8nosuchmethoderror%25e7%259a%2584%25e8%25a7%25a3%25e5%2586%25b3</link>
		<comments>http://marshal.easymorse.com/archives/2189#comments</comments>
		<pubDate>Tue, 19 Jan 2010 01:47:30 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[servlet]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2189</guid>
		<description><![CDATA[在集成spring3.0后，在eclipse下debug GWT webapp时报错： &#160;&#160; [WARN] Error starting handlers java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String; &#160;&#160;&#160; at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:254) &#160;&#160;&#160; at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:192) &#160;&#160;&#160; at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47) &#160;&#160;&#160; at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:543) &#160;&#160;&#160; at org.mortbay.jetty.servlet.Context.startContext(Context.java:136) 但是如果在命令行中： mvn gwt:run 或者: mvn jetty:run 都没有错误。 pom文件中的serlvet和jsp版本是： &#60;dependency&#62; &#160;&#160;&#160; &#60;groupId&#62;javax.servlet&#60;/groupId&#62; &#160;&#160;&#160; &#60;artifactId&#62;servlet-api&#60;/artifactId&#62; &#160;&#160;&#160; &#60;version&#62;2.4&#60;/version&#62; &#160;&#160;&#160; &#60;scope&#62;provided&#60;/scope&#62; &#60;/dependency&#62; &#60;dependency&#62; &#160;&#160;&#160; &#60;groupId&#62;javax.servlet&#60;/groupId&#62; &#160;&#160;&#160; &#60;artifactId&#62;jsp-api&#60;/artifactId&#62; &#160;&#160;&#160; &#60;version&#62;2.0&#60;/version&#62; &#160;&#160;&#160; &#60;scope&#62;provided&#60;/scope&#62; &#60;/dependency&#62; &#160; 更换为高版本后，问题解决： [...]]]></description>
			<content:encoded><![CDATA[<p>在集成spring3.0后，在eclipse下debug GWT webapp时报错：</p>
<blockquote><p>&#160;&#160; [WARN] Error starting handlers     <br />java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String;      <br />&#160;&#160;&#160; at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:254)      <br />&#160;&#160;&#160; at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:192)      <br />&#160;&#160;&#160; at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)      <br />&#160;&#160;&#160; at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:543)      <br />&#160;&#160;&#160; at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)</p>
</blockquote>
<p> <span id="more-2189"></span>
<p>但是如果在命令行中：</p>
<blockquote><p><font style="background-color: #ffffff">mvn gwt:run</font></p>
</blockquote>
<p>或者:</p>
<blockquote><p><font style="background-color: #ffffff">mvn jetty:run</font></p>
</blockquote>
<p>都没有错误。</p>
<p>pom文件中的serlvet和jsp版本是：</p>
<blockquote><p>&lt;dependency&gt;     <br />&#160;&#160;&#160; &lt;groupId&gt;javax.servlet&lt;/groupId&gt;      <br />&#160;&#160;&#160; &lt;artifactId&gt;servlet-api&lt;/artifactId&gt;      <br />&#160;&#160;&#160; &lt;version&gt;2.4&lt;/version&gt;      <br />&#160;&#160;&#160; &lt;scope&gt;provided&lt;/scope&gt;      <br />&lt;/dependency&gt;      <br />&lt;dependency&gt;      <br />&#160;&#160;&#160; &lt;groupId&gt;javax.servlet&lt;/groupId&gt;      <br />&#160;&#160;&#160; &lt;artifactId&gt;jsp-api&lt;/artifactId&gt;      <br />&#160;&#160;&#160; &lt;version&gt;2.0&lt;/version&gt;      <br />&#160;&#160;&#160; &lt;scope&gt;provided&lt;/scope&gt;      <br />&lt;/dependency&gt;</p>
<p>&#160;</p>
</blockquote>
<p>更换为高版本后，问题解决：</p>
<blockquote><p>&lt;dependency&gt;     <br />&#160;&#160;&#160; &lt;groupId&gt;javax.servlet&lt;/groupId&gt;      <br />&#160;&#160;&#160; &lt;artifactId&gt;servlet-api&lt;/artifactId&gt;      <br />&#160;&#160;&#160; &lt;version&gt;2.5&lt;/version&gt;      <br />&#160;&#160;&#160; &lt;scope&gt;provided&lt;/scope&gt;      <br />&lt;/dependency&gt;      <br />&lt;dependency&gt;      <br />&#160;&#160;&#160; &lt;groupId&gt;javax.servlet.jsp&lt;/groupId&gt;      <br />&#160;&#160;&#160; &lt;artifactId&gt;jsp-api&lt;/artifactId&gt;      <br />&#160;&#160;&#160; &lt;version&gt;2.1&lt;/version&gt;      <br />&#160;&#160;&#160; &lt;scope&gt;provided&lt;/scope&gt;      <br />&lt;/dependency&gt;</p>
<p>&#160;</p>
</blockquote>
<p>主要原因是，spring 3.0使用了2.5版本的servlet。javax.servlet.ServletContext.getContextPath()方法是2.5版本中加入的。</p>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2189/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>复杂一些的spring json示例</title>
		<link>http://marshal.easymorse.com/archives/2187?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e5%25a4%258d%25e6%259d%2582%25e4%25b8%2580%25e4%25ba%259b%25e7%259a%2584spring-json%25e7%25a4%25ba%25e4%25be%258b</link>
		<comments>http://marshal.easymorse.com/archives/2187#comments</comments>
		<pubDate>Mon, 18 Jan 2010 08:56:59 +0000</pubDate>
		<dc:creator>Marshal</dc:creator>
				<category><![CDATA[计算机技术]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring json]]></category>

		<guid isPermaLink="false">http://marshal.easymorse.com/archives/2187</guid>
		<description><![CDATA[在在spring web项目中使用json视图中，写了个最简单的json示例。现在输出的内容复杂一些，比如类图关系如下： 代码见： http://easymorse.googlecode.com/svn/tags/spring.json.demo-0.2 返回值如下： {&#34;page&#34;:{&#34;results&#34;:[{&#34;authors&#34;:[{&#34;name&#34;:&#34;张三&#34;,&#34;id&#34;:&#34;1&#34;},{&#34;name&#34;:&#34;李四&#34;,&#34;id&#34;:&#34;2&#34;}],&#34;name&#34;:&#34;五百年来谁著史&#34;,&#34;id&#34;:&#34;1&#34;}],&#34;pageNo&#34;:2}} 主要复杂了的部分是： @Controller public class DemoService { @RequestMapping(&#34;/a.json&#34;) public String doService(ModelMap modelMap) { Pagination pagination = new Pagination(); pagination.setPageNo(2); pagination.setResults(new ArrayList&#60;Object&#62;()); Book book = new Book(); book.setId(&#34;1&#34;); book.setName(&#34;五百年来谁著史&#34;); book.setAuthors(new ArrayList&#60;Author&#62;()); pagination.getResults().add(book); Author author = new Author(); author.setId(&#34;1&#34;); author.setName(&#34;张三&#34;); book.getAuthors().add(author); author = new Author(); author.setId(&#34;2&#34;); author.setName(&#34;李四&#34;); book.getAuthors().add(author); modelMap.put(&#34;page&#34;, pagination); return &#34;list&#34;; [...]]]></description>
			<content:encoded><![CDATA[<p>在<a href="http://marshal.easymorse.com/archives/2184" title="在spring web项目中使用json视图">在spring web项目中使用json视图</a>中，写了个最简单的json示例。现在输出的内容复杂一些，比如类图关系如下：</p>
<p><a href="http://marshal.easymorse.com/wp-content/uploads/2010/01/classes4json.jpg" rel="lightbox"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="classes4json" border="0" alt="classes4json" src="http://marshal.easymorse.com/wp-content/uploads/2010/01/classes4json_thumb.jpg" width="355" height="271" /></a></p>
<p>代码见：</p>
<blockquote><p><a title="http://easymorse.googlecode.com/svn/tags/spring.json.demo-0.2" href="http://easymorse.googlecode.com/svn/tags/spring.json.demo-0.2">http://easymorse.googlecode.com/svn/tags/spring.json.demo-0.2</a></p>
</blockquote>
<p>返回值如下：</p>
<blockquote><p>{&quot;page&quot;:{&quot;results&quot;:[{&quot;authors&quot;:[{&quot;name&quot;:&quot;张三&quot;,&quot;id&quot;:&quot;1&quot;},{&quot;name&quot;:&quot;李四&quot;,&quot;id&quot;:&quot;2&quot;}],&quot;name&quot;:&quot;五百年来谁著史&quot;,&quot;id&quot;:&quot;1&quot;}],&quot;pageNo&quot;:2}}</p>
</blockquote>
<p> <span id="more-2187"></span>
<p>主要复杂了的部分是：</p>
<blockquote><pre>@Controller
public class DemoService {
	@RequestMapping(&quot;/a.json&quot;)
	public String doService(ModelMap modelMap) {
		Pagination pagination = new Pagination();
		pagination.setPageNo(2);
		pagination.setResults(new ArrayList&lt;Object&gt;());
		Book book = new Book();
		book.setId(&quot;1&quot;);
		book.setName(&quot;五百年来谁著史&quot;);
		book.setAuthors(new ArrayList&lt;Author&gt;());
		pagination.getResults().add(book);
		Author author = new Author();
		author.setId(&quot;1&quot;);
		author.setName(&quot;张三&quot;);
		book.getAuthors().add(author);
		author = new Author();
		author.setId(&quot;2&quot;);
		author.setName(&quot;李四&quot;);
		book.getAuthors().add(author);

		modelMap.put(&quot;page&quot;, pagination);
		return &quot;list&quot;;
	}</pre>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://marshal.easymorse.com/archives/2187/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

