成功实现了ajax--struts--spring无缝地结合构建
2007-01-30 11:34
295 查看
去年初,正好负责一个医药信息系统的设计开发,架构设计时,采用Struts+JDBC(自定义采用适配器模式封装了HashMap动态VO实现的持久层)。后来ajax热潮兴起,正好系统中有很多地方需要和服务器端交互数据,如采购销售系统中的订单头/订单明细等主从表结构的维护。
数据交互过程,我们考虑采用xml来组织数据结构,更新/保存:前台封装需要的xml,通过ajax提交---〉action解析xml ---〉改造原有的持久层实现xml持久化;
查询时:持久层根据实际需要返回xml,document对象,---〉action 处理 --〉前台自己封装js库来解析xml,并刷新部分页面。
ajax:已经有很多方法实现跨浏览器的方式,这里只介绍最简单的方式,同步模式下提交xmlStr给action(*.do)。
struts中我们扩展了Action,实现了xmlStr转化成document对象(dom4j),并且完善了转发方式。如:
1.DispatchAction
以一个Controller响应一组动作绝对是Controller界的真理,Struts的DispatchAction同样可以做到这点。
其中parameter="method" 设置了用来指定响应方法名的url参数名为method,即/admin/user.do?method=list 将调用UserAction的public ActionForward list(....) 函数。 public ActionForward unspecified(....) 函数可以指定不带method方法时的默认方法。 但是这样需要在url后多传递参数method=list ;并且action节点配置中的parameter="method"也没有被充分利用,反而觉得是累赘! 因此我们直接在BaseDispatchAction中增加xml字符串解析,并充分利用action节点配置中的parameter="targetMethod" ,使得转发的时候,action能够直接转发到子类的相应方法中,减少了url参数传递,增强了配置信息可读性,方便团队开发。 同样以上述为例,扩展后的配置方式如下:
其中parameter="list" 设置了用来指定响应url=/admin/user.do的方法名,它将调用UserAction的public ActionForward list(....) 函数。
BaseDispatchDocumentAction 的代码如下,它做了三件重要的事情:
1、采用dom4j直接解析xml字符串,并返回document,如果没有提交xml数据,或者采用form形式提交的话,返回null;
2、采用模版方法处理系统异常,减少了子类中无尽的try{...}catch(){...};其中异常处理部分另作描述(你可以暂时去掉异常处理,实现xml提交和解析,如果你有兴趣,我们可以进一步交流);
3、提供了Spring配置Bean的直接调用,虽然她没有注入那么优雅,但是实现了ajax、struts、spring的结合。
BaseDispatchDocumentAction 的源码如下:
开发人员只需要继承它就可以了,我们写个简单的示例action,如下:
至此,我们成功实现了ajax--struts--spring的无缝结合。欢迎大家拍砖!
数据交互过程,我们考虑采用xml来组织数据结构,更新/保存:前台封装需要的xml,通过ajax提交---〉action解析xml ---〉改造原有的持久层实现xml持久化;
查询时:持久层根据实际需要返回xml,document对象,---〉action 处理 --〉前台自己封装js库来解析xml,并刷新部分页面。
ajax:已经有很多方法实现跨浏览器的方式,这里只介绍最简单的方式,同步模式下提交xmlStr给action(*.do)。
/** * 将数据同步传递给后台请求url * @return 返回xmlhttp 响应的信息 * @param-url = '/web/module/xxx.do?p1=YY&p2=RR'; * @param-xmlStr:xml格式的字符串 <data><xpath><![CDATA[数据信息]]></xpath></data> * @author zhipingch * @date 2005-03-17 */ function sendData(urlStr, xmlStr) { var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); xmlhttp.open("POST", urlStr, false); xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); if (xmlStr) { xmlhttp.send(xmlStr); } else { xmlhttp.send(); } return xmlhttp.responseXml; } |
1.DispatchAction
以一个Controller响应一组动作绝对是Controller界的真理,Struts的DispatchAction同样可以做到这点。
<action path="/admin/user" name="userForm" scope="request" parameter="method" validate="false"> <forward name="list" path="/admin/userList.jsp"/> </action> |
<action path="/admin/user" scope="request" parameter="list" validate="false"> <forward name="list" path="/admin/userList.jsp"/> </action> |
BaseDispatchDocumentAction 的代码如下,它做了三件重要的事情:
1、采用dom4j直接解析xml字符串,并返回document,如果没有提交xml数据,或者采用form形式提交的话,返回null;
2、采用模版方法处理系统异常,减少了子类中无尽的try{...}catch(){...};其中异常处理部分另作描述(你可以暂时去掉异常处理,实现xml提交和解析,如果你有兴趣,我们可以进一步交流);
3、提供了Spring配置Bean的直接调用,虽然她没有注入那么优雅,但是实现了ajax、struts、spring的结合。
BaseDispatchDocumentAction 的源码如下:
package com.ufida.haisheng.struts; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigDecimal; import java.sql.Timestamp; import java.util.Date; import java.util.HashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.converters.BigDecimalConverter; import org.apache.commons.beanutils.converters.ClassConverter; import org.apache.commons.beanutils.converters.IntegerConverter; import org.apache.commons.beanutils.converters.LongConverter; import org.apache.log4j.Logger; 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 org.apache.struts.util.MessageResources; import org.dom4j.Document; import org.dom4j.io.SAXReader; import org.hibernate.HibernateException; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.dao.DataAccessException; import org.springframework.web.context.support.WebApplicationContextUtils; import com.ufida.haisheng.constants.Globals; import com.ufida.haisheng.converter.DateConverter; import com.ufida.haisheng.converter.TimestampConverter; import com.ufida.haisheng.exp.ExceptionDTO; import com.ufida.haisheng.exp.ExceptionDisplayDTO; import com.ufida.haisheng.exp.exceptionhandler.ExceptionHandlerFactory; import com.ufida.haisheng.exp.exceptionhandler.ExceptionUtil; import com.ufida.haisheng.exp.exceptionhandler.IExceptionHandler; import com.ufida.haisheng.exp.exceptions.BaseAppException; import com.ufida.haisheng.exp.exceptions.MappingConfigException; import com.ufida.haisheng.exp.exceptions.NoSuchBeanConfigException; /** * 系统的Ajax转发基类。增加模版处理异常信息。 * * @author 陈志平 chenzp * @desc BaseDispatchDocumentAction.java * * @说明: web 应用基础平台 * @date 2005-03-02 11:18:01 AM * @版权所有: All Right Reserved 2006-2008 */ public abstract class BaseDispatchDocumentAction extends Action { protected Class clazz = this.getClass(); protected static Logger log = Logger.getLogger( BaseDispatchDocumentAction.class); /** * 异常信息 */ protected static ThreadLocal<ExceptionDisplayDTO> expDisplayDetails = new ThreadLocal<ExceptionDisplayDTO>(); private static final Long defaultLong = null; private static ApplicationContext ctx = null; /** * 注册转换的工具类 使得From中的string -- * Model中的对应的类型(Date,BigDecimal,Timestamp,Double...) */ static { ConvertUtils.register(new ClassConverter(), Double.class); ConvertUtils.register(new DateConverter(), Date.class); ConvertUtils.register(new DateConverter(), String.class); ConvertUtils.register(new LongConverter(defaultLong), Long.class); ConvertUtils.register(new IntegerConverter(defaultLong), Integer.class); ConvertUtils.register(new TimestampConverter(), Timestamp.class); ConvertUtils.register(new BigDecimalConverter(defaultLong), BigDecimal.class); } /** * The message resources for this package. */ protected static MessageResources messages = MessageResources.getMessageResources("org.apache.struts.actions.LocalStrings"); /** * The set of Method objects we have introspected for this class, keyed by * method name. This collection is populated as different methods are * called, so that introspection needs to occur only once per method name. */ protected HashMap<String, Method> methods = new HashMap<String, Method>(); /** * The set of argument type classes for the reflected method call. These are * the same for all calls, so calculate them only once. */ protected Class[] types = { ActionMapping.class, ActionForm.class, Document.class, HttpServletRequest.class, HttpServletResponse.class }; /** * Process the specified HTTP request, and create the corresponding HTTP * response (or forward to another web component that will create it). * Return an <code>ActionForward</code> instance describing where and how * control should be forwarded, or <code>null</code> if the response has * already been completed. * * @param mapping * The ActionMapping used to select this instance * @param form * The optional ActionForm bean for this request (if any) * @param request * The HTTP request we are processing * @param response * The HTTP response we are creating * * @exception Exception * if an exception occurs */ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { response.setContentType("text/html; charset=UTF-8"); ExceptionDisplayDTO expDTO = null; try { Document doc = createDocumentFromRequest(request); /* * 这里直接调用mapping的parameter配置 */ String actionMethod = mapping.getParameter(); /* * 校验配置的方法是否正确、有效 */ isValidMethod(actionMethod); return dispatchMethod(mapping, form, doc, request, response, actionMethod); } catch (BaseAppException ex) { expDTO = handlerException(request, response, ex); } catch (Exception ex) { ExceptionUtil.logException(this.getClass(), ex); renderText(response,"[Error :对不起,系统出现错误了, 请向管理员报告以下异常信息./n" + ex.getMessage() + "]"); request.setAttribute(Globals.ERRORMSG, "对不起, 系统出现错误了,请向管理员报告以下异常信息./n" + ex.getMessage()); expDTO = handlerException(request,response, ex); } finally { expDisplayDetails.set(null); } return null == expDTO ? null : (expDTO.getActionForwardName() == null ? null : mapping.findForward(expDTO.getActionForwardName())); } /** * 直接输出纯字符串 */ public void renderText(HttpServletResponse response, String text) { PrintWriter out = null; try { out = response.getWriter(); response.setContentType("text/plain;charset=UTF-8"); out.write(text); } catch (IOException e) { log.error(e); } finally { if (out != null) { out.flush(); out.close(); out = null; } } } /** * 直接输出纯HTML */ public void renderHtml(HttpServletResponse response, String text) { PrintWriter out = null; try { out = response.getWriter(); response.setContentType("text/html;charset=UTF-8"); out.write(text); } catch (IOException e) { log.error(e); } finally { if (out != null) { out.flush(); out.close(); out = null; } } } /** * 直接输出纯XML */ public void renderXML(HttpServletResponse response, String text) { PrintWriter out = null; try { out = response.getWriter(); response.setContentType("text/xml;charset=UTF-8"); out.write(text); } catch (IOException e) { log.error(e); } finally { if (out != null) { out.flush(); out.close(); out = null; } } } /** * 异常处理 * @param request * @param out * @param ex * @return ExceptionDisplayDTO异常描述对象 */ private ExceptionDisplayDTO handlerException(HttpServletRequest request,HttpServletResponse response, Exception ex) { ExceptionDisplayDTO expDTO = (ExceptionDisplayDTO) expDisplayDetails.get(); if (null == expDTO) { expDTO = new ExceptionDisplayDTO(null,this.getClass().getName()); } IExceptionHandler expHandler = ExceptionHandlerFactory.getInstance().create(); ExceptionDTO exDto = expHandler.handleException(expDTO.getContext(), ex); request.setAttribute("ExceptionDTO", exDto); renderText(response,"[Error:" + (exDto == null ? "ExceptionDTO is null,请检查expinfo.xml配置文件." : exDto.getMessageCode()) + "]"); return expDTO; } private void isValidMethod(String actionMethod) throws MappingConfigException { if (actionMethod == null || "execute".equals(actionMethod) || "perform".equals(actionMethod)) { log.error("[BaseDispatchAction->error] parameter = " + actionMethod); expDisplayDetails.set(new ExceptionDisplayDTO(null, "MappingConfigException")); throw new MappingConfigException("对不起, 配置的方法名不能为 " + actionMethod); } } /** * 解析xml流 * @param request * @return Document对象 */ protected static Document createDocumentFromRequest(HttpServletRequest request) throws Exception { try { request.setCharacterEncoding("UTF-8"); Document document = null; SAXReader reader = new SAXReader(); document = reader.read(request.getInputStream()); return document; } catch (Exception ex) { log.warn("TIPS:没有提交获取XML格式数据流! "); return null; } } /** * Dispatch to the specified method. * * @since Struts 1.1 */ protected ActionForward dispatchMethod(ActionMapping mapping, ActionForm form, Document doc,HttpServletRequest request, HttpServletResponse response, String name) throws Exception { Method method = null; try { method = getMethod(name); } catch (NoSuchMethodException e) { String message = messages.getMessage("dispatch.method", mapping.getPath(), name); log.error(message, e); expDisplayDetails.set(new ExceptionDisplayDTO(null, "MappingConfigException")); throw new MappingConfigException(message, e); } ActionForward forward = null; try { Object args[] = { mapping, form, doc, request, response }; log.debug("[execute-begin] -> " + mapping.getPath() + "-> [" + clazz.getName() + "->" + name + "]"); forward = (ActionForward) method.invoke(this, args); log.debug(" [execute-end] -> " + (null == forward ? " use ajax send to html/htm" : forward.getPath())); } catch (ClassCastException e) { String message = messages.getMessage("dispatch.return", mapping.getPath(), name); log.error(message, e); throw new BaseAppException(message, e); } catch (IllegalAccessException e) { String message = messages.getMessage("dispatch.error", mapping.getPath(), name); log.error(message, e); throw new BaseAppException(message, e); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); String message = messages.getMessage("dispatch.error", mapping.getPath(), name); throw new BaseAppException(message, t); } return (forward); } /** * Introspect the current class to identify a method of the specified name * that accepts the same parameter types as the <code>execute</code> * method does. * * @param name * Name of the method to be introspected * * @exception NoSuchMethodException * if no such method can be found */ protected Method getMethod(String name) throws NoSuchMethodException { synchronized (methods) { Method method = (Method) methods.get(name); if (method == null) { method = clazz.getMethod(name, types); methods.put(name, method); } return (method); } } /** * 返回spring bean对象 * @param name Spring Bean的名称 * @exception BaseAppException */ protected Object getSpringBean(String name) throws BaseAppException { if (ctx == null) { ctx = WebApplicationContextUtils.getWebApplicationContext (this.getServlet().getServletContext()); } Object bean = null; try { bean = ctx.getBean(name); } catch (BeansException ex) { throw new NoSuchBeanConfigException("对不起,您没有配置名为:" + name + "的bean。请检查配置文件!", ex.getRootCause()); } if (null == bean) { throw new NoSuchBeanConfigException("对不起,您没有配置名为:" + name + "的bean。请检查配置文件!"); } return bean; } } |
/** * 带Ajax提交xml数据的action类模版 * * @author 陈志平 chenzp * * @说明: web 应用基础平台 * @date Aug 1, 2006 10:52:13 AM * @版权所有: All Right Reserved 2006-2008 */ public class UserAction extends BaseDispatchDocumentAction { /** * 这里 actionForm 和 doc 参数必有一个为空,请聪明的你分析一下 * @param mapping --转发的映射对象 * @param actionForm --仍然支持表单提交,此时doc == null * @param doc document对象,解析xml后的文档对象 * @param request --请求 * @param response --响应 */ public ActionForward list(ActionMapping mapping, ActionForm actionForm, Document doc,HttpServletRequest request, HttpServletResponse response) throws BaseAppException { /** * 转发的名称 userAction.search: 系统上下文 用于异常处理 */ expDisplayDetails.set(new ExceptionDisplayDTO(null, "userAction.search")); /** * 处理业务逻辑部分: * * 获取各种类型的参数 RequestUtil.getStrParameter(request,"ParameterName"); * * 调用父类的 getSpringBean("serviceID")方法获取spring的配置bean * */ UserManager userManager = (LogManager) getSpringBean("userManager"); //返回xml对象到前台 renderXML(response, userManager.findUsersByDoc(doc)); return null; } |
相关文章推荐
- ajax、Struts、spring的无缝结合
- J2EE项目系列(四)--SSM框架构建积分系统和基本商品检索系统(Spring+SpringMVC+MyBatis)(3)Ajax使用详解(级联列表)以及企业级报表Excel导入导出实现
- Spring4 Spring MVC实战(四)——Spring MVC实现类struts通配符跳转,HMTL、Ajax和EasyUI的交互,405及406错误
- 来段代码提提神-Java实现EXCEL模板化导出:ajax+springMVC或者Struts为例
- Spring+Struts+Hibernate+Buffalo构建支持Ajax的轻量级J2EE框架
- ajax和struts结合实现无刷新验证用户名是否存在
- ajax和struts配合实现判断文件是否上传成功
- ajax 结合struts实现跨域访问
- 重温之Struts与Ajax结合向前台传送json数据实现ztree(一次性加载ztree)
- 利用ajax结合highchart和Spring实现数据可视化中的柱状图
- Spring 过滤器、分发器结合实现 只对某种类型数据 在 Ajax调用时候 进行过滤
- 运用DWR框架实现AJAX并与Spring与struts以及hibernate中的整合
- Struts2+AJAX+JQuery 实现用户登入与注册功能
- Repeater控件结合UpdatePanel实现Ajax分页和删除功能
- 基于ajax+struts实现的二级联动
- 基于james3.0 的邮件系统(struts2.3.2 +spring3.0.1+jpa(hibernate3.6.5)实现)b/s模式--java邮件系统
- Struts下实现ajax的小例子
- Spring和Hibernate和Struts整合(二)实现登陆验证
- 自己实现的简单MVC框架(类似Struts2+Spring)
- Struts、Hibernate复习 && 了解与Spring结合的SSH