- 浏览: 1700808 次
- 性别:
- 来自: 杭州699号
文章分类
最新评论
-
莫莫摸:
为什么不用dubbo
RCP数据传输模型回顾 -
大胡子爸爸:
String, Class 都实现了Serializable接 ...
RPC框架几行代码就够了 -
lss598018587:
谢谢大神分享,比起新手看复杂的dubbo框架还不如看大神的这一 ...
RPC框架几行代码就够了 -
15606915740:
你好,请问一下。<dubbo:consumer filt ...
Dubbo文档 -
joqk12345:
...
一些设计上的基本常识
进入新的项目组,
checkout项目下来,
看了一下其整体结构与代码,哎,比较乱。
经过我的建议,部门经理让我对该项目进行全面重构。
首先,此项目是以AppFuse作为基础的,还记得robin说它就一toy
选择的模板是iBatis + Spring + Struts
我的第一步工作是要隔离Struts。
Struts是老牌的MVC实现,那个年代IoC和轻量级还没现在流行,框架侵入性也没有得到重视。
所以Struts的实现让应用程序严重依赖它:
1.所有控制器都必需继承Action类
2.所有数据封装类必需继承ActionForm
3.控制器方法execute必需返回ActionForward,与Struts藕合
4.控制器方法execute的参数ActionMapping,与Struts藕合
5.控制器方法execute的参数HttpServletRequest,HttpServletResponse,与Servlet容器藕合
6.由于Action类是Struts管理的,不支持Service类的IoC注入,除非将控制权委托给IoC容器,再配一遍(如:org.springframework.web.struts.DelegatingActionProxy)。
目标:
1.控制器不继承任何类,也不实现任何接口
2.数据封装Form类应为简单的POJO,不要继承ActionForm
3.execute返回值可以是任意对象(包括基本类型和void),
标准返回String,即forward的索引值,
如果返回其它类型对象就调用其toString。
如果返回类型为void或返回值为null,forward到默认的"success"
4和5.execute只传入POJO的Form,
如果该动作不需要Form数据,也可以保持空的参数列表。
如果有多个参数,第一个参数为Form(作为传入,也作为传出,这个是struts已经实现的规则),后面的都为传出对象,必需保证为POJO,传出对象会根据struts的action配置的scope,放入相应域。
6.支持IoC注入Service,即然IoC,当然不能依赖某个具体IoC容器,没有Spring一样运行。要不然会被ajoo一顿臭骂,什么什么? IoC还:容器类.getXXX()?
7.当然,还要实现一个线程安全的容器类,持有与Servlet相关的信息,
这样,若有特殊要求需要访问HttpServletRequest,HttpServletResponse
则可以通过:容器类.get当前线程容器().getRequest()方式获取。
最后类应该像这样:
不用说,这样的类是易于测试的。
例如:
当然还有测试传入一个null的ItemsForm等的其它测试,这里就不例举了。
好,明确目标后,开始重构,重构后要先保证以前的代码也能运行。
由于要使Action彻底独立,我暂时想到的办法是反射回调。
我先写一个通用的Action,然后回调具体的控制器类。
实现如下:
通用Action
IoC的Service供给接口
Spring的Service供给实现,依赖Spring,作为一种策略应该不成问题。
线程安全的Servlet相关信息持有类,
还有几个Map的封装,不贴也应该猜得到,
就是map.put时调用request,session,cookie,application相应的setAttribute等,get也类似
Struts配置中,parameter属性是作为扩展用的,所以我们可以利用它。
改动:
parameter指定控制器类的类名和方法名,格式为:包名.类名:函数名
type固定为com.ynmp.webapp.frame.BaseAction
如:
配置管理类:
Class辅助工具类
其它JUnit的测试类就不贴了。
现在Action解放了,Form对象还没解放
还是必需继承ActionForm,
因为<form-bean配置会检查该对象是否继承于ActionForm,否则报错。
验证框架和ActionForm也有点藕合。
我现在还没有想到好的办法,先搞个权宜之计,
写了一个BaseForm,继承于ActionForm,然后将从ActionForm中继承来的方法全给final掉
其它Form都继承于BaseForm,这样先保证Form不会重写ActionForm中的方法,
看起来像个POJO,若以后能去掉ActionForm,就只要改BaseForm。
谢谢你的提议,但此项目使用weblogic8.1,其solaris版本不支持jdk5.0,
annotation是个不错的主意,可以更好的aop,也省些xml配置。
怎么会冲突呢?
ThreadLocal的实现是比较简单的,
其内部持有一个Map,以当前Thread作为key,
去取其中的所存的对象,
这样就可以保证每个Thread拿到的对象实例都不同。
以实现线程安全。
且在一个Thread内的程序都能拿到。
你没理解的是一个ThreadLocal,只存一种类实例。
两个ThreadLocal根本不会相干。
如我们有两个Holder类,都用了ThreadLocal技术:
aContext和bContext分别实例化了,
这样aContext和bContext内部分别持有一个Map
你用当前线程作为key,
去AHolder里拿到的是aContext持有的对象
去BHolder里拿到的是bContext持有的对象
怎么会冲突?
checkout项目下来,
看了一下其整体结构与代码,哎,比较乱。
经过我的建议,部门经理让我对该项目进行全面重构。
首先,此项目是以AppFuse作为基础的,还记得robin说它就一toy
选择的模板是iBatis + Spring + Struts
我的第一步工作是要隔离Struts。
Struts是老牌的MVC实现,那个年代IoC和轻量级还没现在流行,框架侵入性也没有得到重视。
所以Struts的实现让应用程序严重依赖它:
1.所有控制器都必需继承Action类
2.所有数据封装类必需继承ActionForm
3.控制器方法execute必需返回ActionForward,与Struts藕合
4.控制器方法execute的参数ActionMapping,与Struts藕合
5.控制器方法execute的参数HttpServletRequest,HttpServletResponse,与Servlet容器藕合
6.由于Action类是Struts管理的,不支持Service类的IoC注入,除非将控制权委托给IoC容器,再配一遍(如:org.springframework.web.struts.DelegatingActionProxy)。
目标:
1.控制器不继承任何类,也不实现任何接口
2.数据封装Form类应为简单的POJO,不要继承ActionForm
3.execute返回值可以是任意对象(包括基本类型和void),
标准返回String,即forward的索引值,
如果返回其它类型对象就调用其toString。
如果返回类型为void或返回值为null,forward到默认的"success"
4和5.execute只传入POJO的Form,
如果该动作不需要Form数据,也可以保持空的参数列表。
如果有多个参数,第一个参数为Form(作为传入,也作为传出,这个是struts已经实现的规则),后面的都为传出对象,必需保证为POJO,传出对象会根据struts的action配置的scope,放入相应域。
6.支持IoC注入Service,即然IoC,当然不能依赖某个具体IoC容器,没有Spring一样运行。要不然会被ajoo一顿臭骂,什么什么? IoC还:容器类.getXXX()?
7.当然,还要实现一个线程安全的容器类,持有与Servlet相关的信息,
这样,若有特殊要求需要访问HttpServletRequest,HttpServletResponse
则可以通过:容器类.get当前线程容器().getRequest()方式获取。
最后类应该像这样:
// Action无任何要求(哦,不对,要求有一个没有参数的构造函数,不算太高吧^_^) public class ItemAction { private ItemService itemService; // IoC注入 public void setItemService(ItemService itemService) { this.itemService = itemService; } // 只有一个forward "success" 时,也可以用void // ItemForm写实际类型,不要用Object,然后在函数内强制转型,多麻烦 // 建议参数加final public String viewAllItems(final ItemForm itemForm) { itemForm.setItems(itemService.getItems()); return "success"; } //多个跳转,返回String识别 public String saveItem(final ItemForm itemForm) { return itemService.saveItem(itemForm.getItem()) ? "success" : "failure"; } }
不用说,这样的类是易于测试的。
例如:
public void testRightAllViewItems() { ItemAction itemAction = new ItemAction(); ItemService itemService = new ItemServiceMock(); itemAction.setItemService(itemService); ItemsForm itemsForm = new ItemsForm(); String forward = itemAction.viewAllItems(itemsForm); assertEquals("没有正确跳转!", "success", forward); assertNotNull("没有向itemsForm写入数据!", itemsForm.getItems()); // 下面这些断言是判断和ItemServiceMock中写硬编码的值是否一样 assertEquals("取得的items大小与ItemServiceMock中的不一致!", 1, itemsForm.getItems().size()); Item item = (Item) itemsForm.getItems().iterator().next(); assertEquals("获取的item的Id不对!", new Long(5), item.getId()); assertEquals("获取的item的CategoryId不对!", new Long(2), item.getCategoryId()); assertEquals("获取的item的Name不对!", "aaa", item.getName()); assertEquals("获取的item的Price不对!", new Float(1.2), item.getPrice()); }
当然还有测试传入一个null的ItemsForm等的其它测试,这里就不例举了。
好,明确目标后,开始重构,重构后要先保证以前的代码也能运行。
由于要使Action彻底独立,我暂时想到的办法是反射回调。
我先写一个通用的Action,然后回调具体的控制器类。
实现如下:
通用Action
package com.ynmp.webapp.frame; import java.lang.reflect.Method; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import com.ynmp.webapp.frame.provider.ServiceProvider; import com.ynmp.webapp.frame.provider.SpringServiceProvider; import com.ynmp.webapp.frame.util.ClassUtils; public class BaseAction extends Action { private static final Log log = LogFactory.getLog(BaseAction.class); private static final String UNCALL_METHOD = "*"; private static final String SUCCESS_FORWARD = "success"; private static final String ERROR_FORWARD = "error"; public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String forward; try { ActionContext.initCurrentContext(request, response); forward = getActionForward(mapping.getScope(), mapping.getParameter(), form); } catch (Exception e) { e.printStackTrace(); log.warn(e); forward = ERROR_FORWARD; request.setAttribute("BeanActionException", e); } return mapping.findForward(forward); } // 处理forward private String getActionForward(String scope, String config, Object model) throws Exception { // TODO Exception处理待重构 String forward = SUCCESS_FORWARD; ActionConfig actionConfig = new ActionConfig(config); Object actionObject = populateActionClass(actionConfig.getClassName()); Object returnObject = callActionMethod(actionObject, actionConfig.getMethodName(), model, scope); if (returnObject!= null && String.valueOf(returnObject) != null) { forward = String.valueOf(returnObject); } return forward; } // 处理action类 private Object populateActionClass(String className) throws Exception { Class actionClass = Class.forName(className); Object action = actionClass.newInstance(); injectService(action); return action; } // 简单实现IoC private void injectService(Object action) throws Exception { ServiceProvider serviceProvider = new SpringServiceProvider(getServlet()); // TODO 待重构为策略 Method[] methods = action.getClass().getMethods(); for (int i = 0; i < methods.length; i ++) { if (methods[i].getName().startsWith("set")) { Class[] parameters = methods[i].getParameterTypes(); if (parameters != null && parameters.length == 1) { String methodName = methods[i].getName(); String serviceName = methodName.substring(3,4).toLowerCase() + methodName.substring(4); methods[i].invoke(action, new Object[]{serviceProvider.getService(serviceName, parameters[0])}); } } } } // 处理action方法 private Object callActionMethod(Object action, String methodName, Object model, String scope) throws Exception { if (UNCALL_METHOD.equals(methodName)) return null; Method actionMethod = ClassUtils.findMethodByName(action.getClass(), methodName); Object[] parameters = initParameters(actionMethod, model); Object returnObject = actionMethod.invoke(action, parameters); outParameters(getScopeMap(scope), parameters); return returnObject; } // 组装action方法的参数列表 private Object[] initParameters(Method actionMethod, Object model) throws Exception { Class[] parameterTypes = actionMethod.getParameterTypes(); int parameterSize = parameterTypes.length; if (parameterSize == 0) { return new Object[0]; } else if (parameterSize == 1) { return new Object[] {model}; } else { Object[] parameters = new Object[parameterSize]; parameters[0] = model; for (int i = 1; i < parameterSize; i ++) { parameters[i] = parameterTypes[i].newInstance(); } return parameters; } } // 向指定范围域输出参数 private void outParameters(Map scopeMap, Object[] parameters) throws Exception { if (parameters.length < 2) return ; for (int i = 1; i < parameters.length; i ++) { String name = ClassUtils.getLowerClassName(parameters[i].getClass()); scopeMap.put(name, parameters[i]); } } // 通过scope配置找到相应域Map private Map getScopeMap(String scope) { if ("request".equals(scope)) { return ActionContext.getActionContext().getRequestMap(); } else if ("session".equals(scope)) { return ActionContext.getActionContext().getSessionMap(); } else if ("application".equals(scope)) { return ActionContext.getActionContext().getApplicationMap(); } throw new RuntimeException("不合法的scope:" + scope + ",scope必需为request,session,application中的一个!"); } }
IoC的Service供给接口
package com.ynmp.webapp.frame.provider; public interface ServiceProvider { public Object getService(String serviceName, Class serviceClass) throws Exception; }
Spring的Service供给实现,依赖Spring,作为一种策略应该不成问题。
package com.ynmp.webapp.frame.provider; import javax.servlet.http.HttpServlet; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; public class SpringServiceProvider implements ServiceProvider { private HttpServlet servlet; public SpringServiceProvider(HttpServlet servlet) { this.servlet = servlet; } public Object getService(String serviceName, Class serviceClass) throws Exception { ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servlet.getServletContext()); Object serviceObject = ctx.getBean(serviceName); if (serviceObject == null) { throw new RuntimeException("在IoC容器中未找到引用:" + serviceName); } return serviceObject; } }
线程安全的Servlet相关信息持有类,
还有几个Map的封装,不贴也应该猜得到,
就是map.put时调用request,session,cookie,application相应的setAttribute等,get也类似
package com.ynmp.webapp.frame; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.ynmp.webapp.frame.map.ApplicationMap; import com.ynmp.webapp.frame.map.CookieMap; import com.ynmp.webapp.frame.map.ParameterMap; import com.ynmp.webapp.frame.map.RequestMap; import com.ynmp.webapp.frame.map.SessionMap; public class ActionContext { private static final ThreadLocal localContext = new ThreadLocal(); private HttpServletRequest request; private HttpServletResponse response; private Map cookieMap; private Map parameterMap; private Map requestMap; private Map sessionMap; private Map applicationMap; private ActionContext() { cookieMap = new HashMap(); parameterMap = new HashMap(); requestMap = new HashMap(); sessionMap = new HashMap(); applicationMap = new HashMap(); } static void initCurrentContext(HttpServletRequest request, HttpServletResponse response) { ActionContext ctx = getActionContext(); ctx.request = request; ctx.response = response; ctx.cookieMap = null; ctx.parameterMap = null; ctx.requestMap = null; ctx.sessionMap = null; ctx.applicationMap = null; } public static ActionContext getActionContext() { ActionContext ctx = (ActionContext) localContext.get(); if (ctx == null) { ctx = new ActionContext(); localContext.set(ctx); } return ctx; } public Map getCookieMap() { if (cookieMap == null) { cookieMap = new CookieMap(request, response); } return cookieMap; } public Map getParameterMap() { if (parameterMap == null) { parameterMap = new ParameterMap(request); } return parameterMap; } public Map getRequestMap() { if (requestMap == null) { requestMap = new RequestMap(request); } return requestMap; } public Map getSessionMap() { if (sessionMap == null) { sessionMap = new SessionMap(request); } return sessionMap; } public Map getApplicationMap() { if (applicationMap == null) { applicationMap = new ApplicationMap(request); } return applicationMap; } public HttpServletRequest getRequest() { return request; } public HttpServletResponse getResponse() { return response; } public String getAppURL() { StringBuffer url = new StringBuffer(); int port = request.getServerPort(); if (port < 0) { port = 80; } String scheme = request.getScheme(); url.append(scheme); url.append("://"); url.append(request.getServerName()); if ((scheme.equals("http") && (port != 80)) || (scheme.equals("https") && (port != 443))) { url.append(':'); url.append(port); } url.append(request.getContextPath()); return url.toString(); } }
Struts配置中,parameter属性是作为扩展用的,所以我们可以利用它。
改动:
parameter指定控制器类的类名和方法名,格式为:包名.类名:函数名
type固定为com.ynmp.webapp.frame.BaseAction
如:
<action path="/item_list" parameter="com.ynmp.webapp.action.ItemAction:viewAllItems" name="itemsForm" type="com.ynmp.webapp.frame.BaseAction"> <forward name="success" path="/item_list.jsp" /> </action>
配置管理类:
package com.ynmp.webapp.frame; public class ActionConfig { private static final String ACTION_CONFIG_REGEX = "^([A-Z|a-z|_]+\\.)+[A-Z|a-z|_]+\\:(([A-Z|a-z|_]+)|\\*)$"; private String className; private String methodName; public ActionConfig(String config) { if (config == null || config.length() == 0 || ! config.replaceAll(" ", "").matches(ACTION_CONFIG_REGEX)) { throw new RuntimeException("Parameter=\"" + config + "\" 格式不合法!应为:包名.类名:方法名,如:com.company.UserAction:login"); } int index = config.indexOf(":"); className = config.substring(0, index).trim(); methodName = config.substring(index + 1).trim(); } public ActionConfig(String className, String methodName) { this.className = className; this.methodName = methodName; } public String getClassName() { return className; } public String getMethodName() { return methodName; } public void setClassName(String className) { this.className = className; } public void setMethodName(String methodName) { this.methodName = methodName; } }
Class辅助工具类
package com.ynmp.webapp.frame.util; import java.lang.reflect.Method; public class ClassUtils { public static Method findMethodByName(Class clazz, String methodName) { int count = 0; Method actionMethod = null; Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; i ++) { if (methods[i].getName().equals(methodName)) { // 其实也可以不检查函数是否重载,直接返回第一个定义的, // 但这样有可能会使程序员迷惑,还是检查一下重载。 count ++; if (count > 1) { throw new RuntimeException(clazz + " 类中有重载的同名方法: " + methodName + ",无法判定使用哪一个!"); } actionMethod = methods[i]; } } if (count == 0 || actionMethod == null) { throw new RuntimeException(clazz + " 类中找到不方法: " + methodName); } return actionMethod; } public static String getLowerClassName(Class clazz) { String className = clazz.getName(); int index = className.lastIndexOf("."); if (index != -1) { className = className.substring(index + 1); } return className.substring(0,1).toLowerCase() + className.substring(1); } }
其它JUnit的测试类就不贴了。
现在Action解放了,Form对象还没解放
还是必需继承ActionForm,
因为<form-bean配置会检查该对象是否继承于ActionForm,否则报错。
验证框架和ActionForm也有点藕合。
我现在还没有想到好的办法,先搞个权宜之计,
写了一个BaseForm,继承于ActionForm,然后将从ActionForm中继承来的方法全给final掉
其它Form都继承于BaseForm,这样先保证Form不会重写ActionForm中的方法,
看起来像个POJO,若以后能去掉ActionForm,就只要改BaseForm。
评论
8 楼
shaucle
2007-03-09
injection也可用annotation
其solaris版本不支持jdk5.0, 晕
其solaris版本不支持jdk5.0, 晕
7 楼
lgx522
2007-03-09
我用的是JSF版本,从头到尾一个人干,30多张表的管理系统,差不多也就一个多月,效率还是很高的。
此系统稳定运行了一年,说明Appfuse是可靠的。
目前第二个系统正要上线。规模差不多,稍复杂,但有了上一个系统的经验,20天左右也就搞定了。
建议同道们不要再搞自行一套的集成方案了。有了Appfuse这种久经考验的东西,开发得快,学习交流起来也方便。
此系统稳定运行了一年,说明Appfuse是可靠的。
目前第二个系统正要上线。规模差不多,稍复杂,但有了上一个系统的经验,20天左右也就搞定了。
建议同道们不要再搞自行一套的集成方案了。有了Appfuse这种久经考验的东西,开发得快,学习交流起来也方便。
6 楼
javatar
2007-01-26
heyosi 写道
你可以去看看stecks!annotation风格的struts,不需要直接继承struts的Action和Form了。
谢谢你的提议,但此项目使用weblogic8.1,其solaris版本不支持jdk5.0,
annotation是个不错的主意,可以更好的aop,也省些xml配置。
5 楼
javatar
2007-01-26
graymood 写道
为什么要要把ActionContext放在ThreadLocal中?
假如我在项目的其它地方也用ThreadLocal那样不是会产生冲突的?
假如我在项目的其它地方也用ThreadLocal那样不是会产生冲突的?
怎么会冲突呢?
ThreadLocal的实现是比较简单的,
其内部持有一个Map,以当前Thread作为key,
去取其中的所存的对象,
这样就可以保证每个Thread拿到的对象实例都不同。
以实现线程安全。
且在一个Thread内的程序都能拿到。
你没理解的是一个ThreadLocal,只存一种类实例。
两个ThreadLocal根本不会相干。
如我们有两个Holder类,都用了ThreadLocal技术:
public class AHolder { ThreadLocal aContext = new ThreadLocal(); //注意这里new public static AHolder getAHolder() { // 写法主帖有.... } }
public class BHolder { ThreadLocal bContext = new ThreadLocal(); //注意这里也new public static BHolder getBHolder() { // 写法主帖有.... } }
aContext和bContext分别实例化了,
这样aContext和bContext内部分别持有一个Map
你用当前线程作为key,
去AHolder里拿到的是aContext持有的对象
去BHolder里拿到的是bContext持有的对象
怎么会冲突?
4 楼
heyosi
2007-01-23
你可以去看看stecks!annotation风格的struts,不需要直接继承struts的Action和Form了。
3 楼
graymood
2007-01-22
为什么要要把ActionContext放在ThreadLocal中?
假如我在项目的其它地方也用ThreadLocal那样不是会产生冲突的?
假如我在项目的其它地方也用ThreadLocal那样不是会产生冲突的?
2 楼
javatar
2007-01-16
嗯,多谢,正在参考它的原理,
但DynaActionForm在Action还是要依赖它,
而且有点像用Map,没有强类型。
但DynaActionForm在Action还是要依赖它,
而且有点像用Map,没有强类型。
1 楼
seairy
2007-01-16
ActionForm可以用DynaActionForm和LazyValidatorForm代替呀,数据验证用Validator
发表评论
-
能力成长模型
2012-05-09 00:28 22944最近看了温伯格1986年出版的《技术领导之路》, 很老的书,讲 ... -
以HTTL为例讲讲模块分包&领域模型&扩展框架
2011-10-09 20:08 16751注:该博客内容已加入 ... -
使用Map参数的Webx3扩展
2011-08-28 02:10 5917因Webx3是开源的,所以把这个简单的Webx3扩展发在博客上 ... -
Netty内存泄露
2011-08-02 20:09 24967转于自己在公司的Blog: ... -
Grizzly和Netty以及Mina简单性能对比
2011-07-17 02:48 29747转于自己在公司的Blog: http://pt.alibaba ... -
RPC框架几行代码就够了
2011-07-14 00:34 90198转于自己在公司的Blog: http://pt.alibaba ... -
魔鬼在细节中
2011-05-24 14:50 32255转于自己在公司的Blog: ... -
Dubbo扩展点重构
2011-05-12 22:09 38899转于自己在公司的Blog: http://pt.alibaba ... -
配置设计
2011-03-09 23:41 23586转于自己在公司的Blog: ... -
[转]HTML5设计原理
2011-03-09 22:57 7805Jeremy Keith在 Fronteers 2010 ... -
Hessian序列化不设SerializerFactory性能问题
2010-12-27 11:38 6474转于自己在公司的Blog: http://pt.alibaba ... -
动态代理方案性能对比
2010-11-17 21:38 46205转于自己在公司的Blog: http://pt.alibaba ... -
防痴呆设计
2010-11-05 18:58 17688转于自己在公司的Blog: ... -
负载均衡扩展接口重构
2010-11-05 18:53 8757转于自己在公司的Blog: ... -
分布式服务框架常被质疑的价值
2010-11-05 18:52 5734转于自己在公司的Blog: http://pt.alibaba ... -
Hessian3.2.1在序列化32.5k字符串时的问题
2010-11-05 18:49 7256转于自己在公司的Blog: http://pt.alibaba ... -
一些设计上的基本常识
2010-07-05 19:28 27738转于自己在公司的Blog: ... -
谈谈扩充式扩展与增量式扩展
2010-06-12 19:46 19387转于自己在公司的Blog: http://pt.alibaba ... -
Scaling Architecture
2010-02-25 10:31 4119Scaling Second Life: http://p ... -
EBay SOA
2010-02-23 18:23 4801EBay SOA PPT
相关推荐
为了更好地利用这些资源,开发者应先了解AppFuse的基础,包括其依赖的Spring和Struts框架。然后,学习DisplayTag的使用,理解其标签语法和配置选项。接着,深入研究StrutsMenu的配置,以及如何根据用户的权限生成...
这个"appfuse-tutorial-struts-1.6.zip"文件是一个基于Struts 1.6的AppFuse教程,用于指导开发者如何构建一个企业级的人员管理系统。Struts是Apache软件基金会下的一个开源框架,专门用于构建基于MVC(Model-View-...
AppFuse作为构建Web应用的基础框架,它整合了多种开源技术,如Spring、Hibernate、Apache Struts或Spring MVC等。Spring作为核心框架,负责管理应用的业务逻辑和依赖注入;Hibernate用于对象关系映射(ORM),简化...
appfuse2.0.2 Struts2 hibernate Spring 构建的基于SQLServer2005 的ssh2项目的过程全记录 网上很多帖子介绍appfuse2构建过程的,但是基于SQLServer2005的没有,顶多一笔带过,另外对于期间出现的各种问题也没有个说明,...
在AppFuse 2.0时代,它主要支持Struts或 Tapestry 框架,而非现代的Spring Boot。由于描述中提到“没有jar包”,这可能意味着下载的实例源码不包含运行所需的所有依赖库,因此需要开发者自行解决这个问题。 首先,...
现在就将笔者使用Myeclipse工具应用struts2 + spring2 + hibernate3 实现CRUD操作的步骤一一纪录下来,为初学者少走弯路略尽绵薄之力!在本文中,笔者将Struts2.0.6、Spring2.0.6和Hibernate3.1进行整合,希望通过...
appfuse 有struts2+hibernate+spring的整合 springmvc+hibernate+spring的整合 多模块,但模块都有 学习开发参考使用非常方便 可以到官方下载最新版的,我只是把自己下载的打包整理一下 注意哈,都是基于maven的...
Appfuse框架解析,包括登陆验证,执行顺序,加载策略等。
AppFuse 是一个开源项目,它为创建Java Web应用程序提供了一个快速开发框架。它结合了多种技术和库,使得开发者能够更高效地构建应用,而无需从零开始编写基础代码。在AppFuse中,CSS(Cascading Style Sheets)框架...
AppFuse是一个集成了众多当前最流行开源框架与工具(包括Hibernate、ibatis、Struts、Spring、DBUnit、Maven、Log4J、Struts Menu、Xdoclet、SiteMesh、OSCache、JUnit、JSTL等(现在还有lucene的,无敌了))于一身的...
它通过集成各种流行框架,如Struts、Spring、Hibernate等,提供了一个项目骨架,使得开发者能够快速搭建新项目的结构。AppFuse分为1.x和2.0两个主要版本,其中2.0版是重构建的,采用了Maven 2作为构建工具,而1.x...
### 使用Struts 2与AppFuse 2:深入解析与实战指南 #### 一、Struts 2简介 Struts 2(前身为WebWork)是一款以简洁为设计理念的Web框架,它基于XWork构建,XWork是一个通用的命令模式框架。尽管XWork拥有自己的...
AppFuse 是一个由 Matt Raible 创建的开源项目,它为初学者提供了一个基础的 J2EE 框架,用于演示如何集成多个流行的技术,如 Spring、Hibernate、iBatis、Struts、xDcolet、JUnit、Taperstry 和 JSF 等。这个框架的...
文档和教程最早于2003年11月发布,自那以后,AppFuse不断更新和完善,成为了java.net网站上最受欢迎的项目之一。 #### 三、功能特点 AppFuse提供了许多有用的功能,帮助开发者快速搭建和测试应用程序: 1. **容器...
Appfuse 是一个开源框架,旨在帮助开发者高效地构建企业级应用。通过提供一套完善的架构模板、最佳实践和技术栈组合,使得开发者能够专注于业务逻辑的实现,而不是基础架构的搭建。这不仅大大提升了开发效率,还保证...
AppFuse是一个开源项目,旨在简化Web应用程序的开发,它提供了一个基础框架,可以帮助开发者快速启动新项目,整合了Spring、Hibernate、Struts等流行技术。在本教程中,我们将深入了解如何利用Maven这个强大的构建...
- **Struts 2**:另一个常用的 Java Web 框架,AppFuse 同样支持 Struts 2 的集成,并提供了配置和使用指南。 - **JSF**:除了 Spring MVC 和 Struts 2 外,AppFuse 还支持 JSF 框架,提供了相关的文档和教程。 4...
总之,Appfuse开发教程涵盖了从创建数据库表到构建基于Struts的用户界面的全过程,利用了DAO、POJO、Spring和JUnit等技术,帮助开发者高效地构建Java Web应用程序。通过本教程,你可以了解到如何在Appfuse环境中进行...