重头开始学 Spring JPetStore 5

重头开始学 Spring JPetStore 4 里面的Controller似乎太简单了一些。

让我们看一个更复杂一些的请求

看看注册页面

[quote]http://localhost:8080/jpetstore/shop/newAccount.do[/quote]

这里有一个表单需要提交。沿着这个请求 /shop/newAccount.do 找到对应的bean

[quote]<bean name="/shop/newAccount.do" class="org.springframework.samples.jpetstore.web.spring.AccountFormController">
<property name="petStore" ref="petStore"/>
<property name="validator" ref="accountValidator"/>
<property name="successView" value="index"/>
</bean>[/quote]

我们可以看到这个控制器变成了AccountFormController。继续SimpleFormController 看看文档我们发现这个控制器就是一个为表单而生的。另外注入了一个petStore ,看看代码,我们就知道这是一个真实的业务层处理的类。还有一个验证器 :accountValidator

但是这个验证在哪?在另一个文件 applicationContext.xml 里。

[quote] <!-- Generic validator for Account objects, to be used for example by the Spring web tier -->
<bean id="accountValidator" class="org.springframework.samples.jpetstore.domain.logic.AccountValidator"/>[/quote]

以及 successView 一个view页面指向。

看看这个控制器最主要的方法吧。

[quote]
protected ModelAndView onSubmit(
HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)
throws Exception {

AccountForm accountForm = (AccountForm) command;
try {
if (accountForm.isNewAccount()) {
this.petStore.insertAccount(accountForm.getAccount());
}
else {
this.petStore.updateAccount(accountForm.getAccount());
}
}
catch (DataIntegrityViolationException ex) {
errors.rejectValue("account.username", "USER_ID_ALREADY_EXISTS",
"User ID already exists: choose a different ID.");
return showForm(request, response, errors);
}

UserSession userSession = new UserSession(this.petStore.getAccount(accountForm.getAccount().getUsername()));
PagedListHolder myList = new PagedListHolder(
this.petStore.getProductListByCategory(accountForm.getAccount().getFavouriteCategoryId()));
myList.setPageSize(4);
userSession.setMyList(myList);
request.getSession().setAttribute("userSession", userSession);
return super.onSubmit(request, response, command, errors);
}
[/quote]

有一点让人愉快的是这里的AccountForm似乎不需要像在struts中一样特别麻烦的配置一次。只要一句话就可以了,省力了。
[quote]
AccountForm accountForm = (AccountForm) command;
[/quote]


[quote] if (accountForm.isNewAccount()) {
this.petStore.insertAccount(accountForm.getAccount());
}
else {
this.petStore.updateAccount(accountForm.getAccount());
}[/quote]

保存的业务逻辑被petStore包起来了,所以直接调用就结束了。关键是异常处理

[quote] catch (DataIntegrityViolationException ex) {
errors.rejectValue("account.username", "USER_ID_ALREADY_EXISTS",
"User ID already exists: choose a different ID.");
return showForm(request, response, errors);
}[/quote]

这里处理了一个重复用户名的异常。errors. rejectValue方法带了好几个参数。应该是国际化资源文件里的key,以及默认提示信息等内容,然后呢,然后调用了
[quote]showForm(request, response, errors);[/quote]
这个方法应该是一个父类的方法。自动回填了表单的提交的数据?自己试试提交一个重复的用户名,页面是不是回填了?我试验了一下是这样的,完成的还算不错。

看看它是怎么实现这个工作的呢?这个页面到底在哪?让我们看看。

[quote] public AccountFormController() {
setSessionForm(true);
setValidateOnBinding(false);
setCommandName("accountForm");
setFormView("EditAccountForm");
}[/quote]

其中有一个 setFormView("EditAccountForm"); 知道了吧。就是EditAccountForm.jsp了。

找到它,看看。

页面开始就是这么一段。似乎是所有的accountForm的属性都被绑定到status这个变量了现在我还不确定。先留下这个问号?接下去再看看。起码我们通过el标签可以看出来status有个属性 errorMessages 。这个集合保存了所有的错误。JSTL c:forEach标签遍历了显示了所有的错误。
[quote]

<!-- Support for Spring errors object -->
<spring:bind path="accountForm.*">
<c:forEach var="error" items="${status.errorMessages}">
<B><FONT color=RED> <BR> <c:out value="${error}" /> </FONT>
</B>
</c:forEach>
</spring:bind>

[/quote]

随便看一个input
[quote]

<tr bgcolor="#FFFF88">
<td>
New password:
</td>
<td>
<spring:bind path="accountForm.account.password">
<input type="password"
name="<c:out value="${status.expression}"/>"
value="<c:out value="${status.value}"/>" />
</spring:bind>
</td>
</tr>

[/quote]

总是被一个<spring:bind 标签包裹着。name属性也被${status.expression}动态生成了。这样做似乎于前面提到的一个方便有关。 [b]不需要像在struts中一样特别麻烦的配置一次AccountForm。只要一句话就可以了[/b] 猜得不错的话,应该是与这个很大的关系。

看到这个页面不怎么好。满页面的<spring:bind ,每个input都要。还真是烦。


这个控制器里面有一个方法 referenceData
Create a reference data map for the given request.

在AbstractFormController里面可以找到这个方法如何被调用的。合并到一个MAP里面了。

接下来干嘛了?
[quote]

UserSession userSession = new UserSession(this.petStore.getAccount(accountForm.getAccount().getUsername()));
PagedListHolder myList = new PagedListHolder(
this.petStore.getProductListByCategory(accountForm.getAccount().getFavouriteCategoryId()));
myList.setPageSize(4);
userSession.setMyList(myList);
request.getSession().setAttribute("userSession", userSession);
return super.onSubmit(request, response, command, errors);

[/quote]

[quote]PagedListHolder[/quote]似乎是一个分页的类。没看到这个list在index.jsp页面有调用。他在哪里?不知道。


经过这个请求的跟踪,我发现spring mvc真的太灵活。以至于我都不知道什么地方该写哪些?没人告诉我必须实现
[quote]

public AccountFormController() {
setSessionForm(true);
setValidateOnBinding(false);
setCommandName("accountForm");
setFormView("EditAccountForm");
}

[/quote]

里面的4个方法。如果我没写setFormView("EditAccountForm");应该不行。但是没有一个机制让我知道哪些是必须的。在这样的系统上写代码是不是有点走钢丝的感觉?
从代码的角度来看,它这样的实现无可厚非,但似乎对使用者不够友好 。
阅读更多
个人分类: spring
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭