`
maiguang
  • 浏览: 257461 次
  • 性别: Icon_minigender_1
  • 来自: 焦作
社区版块
存档分类
最新评论

ajax、Struts、spring的无缝结合

阅读更多

去年初,正好负责一个医药信息系统的设计开发,架构设计时,采用Struts+JDBC(自定义采用适配器模式封装了HashMap动态VO实现的持久层)。后来ajax热潮兴起,正好系统中有很多地方需要和服务器端交互数据,如采购销售系统中的订单头/订单明细等主从表结构的维护。
[color=blue]数据交互过程[/color],我们考虑采用xml来组织数据结构,更新/保存:前台封装需要的xml,通过ajax提交---〉action解析xml ---〉改造原有的持久层实现xml持久化;

 查询时:持久层根据实际需要返回xml,document对象,---〉action 处理 --〉前台自己封装js库来解析xml,并刷新部分页面。

ajax:已经有很多方法实现跨浏览器的方式,这里只介绍最简单的方式,同步模式下提交xmlStr给action(*.do)。

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;
}

 struts中我们扩展了Action,实现了xmlStr转化成document对象(dom4j),并且完善了转发方式。如 [quote]

 1.DispatchAction
 以一个Controller响应一组动作绝对是Controller界的真理,Struts的DispatchAction同样可以做到这点。

 [list]
 <action path="/admin/user" name="userForm" scope="request" parameter="method" validate="false">
 <forward name="list" path="/admin/userList.jsp">
 </action>
 [/list]


 其中parameter="method" 设置了用来指定响应方法名的url参数名为method,即/admin/user.do?method=list 将调用UserAction的public ActionForward list(....) 函数。

public ActionForward unspecified(....) 函数可以指定不带method方法时的默认方法。[/quote]但是这样需要在url后多传递参数[size=18][color=red]method=list [/color][/size];并且action节点配置中的[color=red]parameter="method" [/color]也没有被充分利用,反而觉得是累赘!

因此我们直接在BaseDispatchAction中增加xml字符串解析,并充分利用action节点配置中的[color=red]parameter="targetMethod" [/color],使得转发的时候,action能够直接转发到子类的相应方法中,减少了url参数传递,增强了配置信息可读性,方便团队开发。
同样以上述为例,扩展后的配置方式如下:

[quote]
<action path="/admin/user" scope="request" [color="red]parameter=&quot;list&quot;[/color]" validate="false">
<forward name="list" path="/admin/userList.jsp">
</action>
[/quote]

其中[color=red]parameter="list"[/color] 设置了用来指定响应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 的源码如下:

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;

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;


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);
}

protected static MessageResources messages = MessageResources.getMessageResources("org.apache.struts.actions.LocalStrings");

protected HashMap<string, method=""> methods = new HashMap<string, method="">();

protected Class[] types = { ActionMapping.class, ActionForm.class, Document.class, HttpServletRequest.class,
HttpServletResponse.class };

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);


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;
}
}
}

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;
}
}
}

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;
}
}
}

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);
}
}


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;
}
}

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);
}


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);
}
}

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;
}
}

 开发人员只需要继承它就可以了,我们写个简单的示例action,如下:

public class UserAction extends BaseDispatchDocumentAction {

public ActionForward list(ActionMapping mapping, ActionForm actionForm, [color=red]Document doc[/color],HttpServletRequest request, HttpServletResponse response) throws BaseAppException {

expDisplayDetails.set(new ExceptionDisplayDTO(null, "userAction.search"));

UserManager userManager = (LogManager) getSpringBean("userManager");

//返回xml对象到前台
renderXML(response, userManager.findUsersByDoc(doc));
return null;
}

 至此,我们成功实现了ajax--struts--spring的无缝结合,下次介绍spring的开发应用。欢迎大家拍砖!
分享到:
评论

相关推荐

    Struts2+Hibernate+Spring框架电子商城

    本系统采用的关键技术是Struts2+Hibernate+Spring整合和AJAX。之所以采用SSH整合是因为在软件工程领域,为了降低模块耦合度,提高模块的可重用性,分层一直是广为采纳的一个方法。其实分层还可以使开发人员专注于某...

    个人信息管理系统Struts2 spring hibernate dwr

    在Ajax更新复习次数时通常都会第一次失败,再点一次就能成功了,第一次失败是因为Request 取到了NULL值,因为对三大框架无缝组合还不太熟悉,如果你知识别忘了告诉我哦(yukiceo@126.com) 由于对页面样式了解不多...

    移动商务短信平台

    由当前流行的jsp+struts2+hibernate+spring+ajax等最新技术实现。 主要功能: 1.能进行短信的群发,接收; 2.支持通过Excel文件、文本文件批量导入导出发送数据; 3.内置4000万条用户数据,用户可通过条件筛选合适的...

    最新myeclipse10中文版下载地址与汉化2013、注册码、破解包(汉化包2013更新)

    MyEclipse目前支持Java Servlet, AJAX, JSP, JSF, Struts,Spring, Hibernate,EJB3,JDBC数据库链接工具等多项功能。可以说MyEclipse几乎囊括了目前所有主流开源产品的专属eclipse开发工具。 MyEclipse 10 使用高级...

    房地产销售管理系统

    由当前流行的jsp+struts2+hibernate+spring+ajax等最新技术实现; 有很高的安全性,对系统中的任何操作均有日志记录;方便快捷,支持通过Excel文件批量导入导出各种数据,实现与第三方软件的无缝连接; 针对各种房...

    房地产销售管理系统V3.0

    由当前流行的jsp+struts2+hibernate+spring+ajax等最新技术实现; 有很高的安全性,对系统中的任何操作均有日志记录;方便快捷,支持通过Excel文件批量导入导出各种数据,实现与第三方软件的无缝连接; 针对各种房...

    java web 开发详解

     优点: 对覆盖绑定(overriding binding)、验证(validation)等提供生命周期管理 与许多表示层技术/框架无缝集成:JSP/JSTL、Tiles、Velocity、FreeMarker、Excel、XSL、PDF 等 便于测试——归功于IoC 缺点: ...

    JAVA上百实例源码以及开源项目

     一个Java+ajax写的登录实例,附有JAVA源文件,JAVA新手朋友可以学习一下。 JAVA+JSP的聊天室 8个目标文件 简单 JavaScript万年历 显示出当前时间及年份,还可以选择年份及月份和日期 Java编写的HTML浏览器 一个...

    《Wicket开发指南一书》PDF版本下载

    象Spring这种大量使用XML方式,我并不欣赏,Spring也意识到了这一点,在2.0版本中努力的简化Xml的配置,但是并不尽如人意)。如果使用简单的规则来配置或者管理一个系统,用户就会很容易的查找到自己需要的内容。而...

    可视化智能仓储管理系统.doc

    " "SSH "SSH为Struts+Spring+Hibernate的一个集成框架,是目前较流 " " "行的一种Web应用程序开源框架。 " 2系统总体介绍 本项目中的可视化智能仓储管理系统需要将所有的子功能进行整合,统一进行管理。 建立集出...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    由于J2EE的开源的框架中提供了MVC模式实现框架Struts、对象关系模型中的Hibernate 的框架及拥有事务管理和依赖注入的Spring。利用现存框架可以更快开发系统。所以选择Java技术作为blog 的开发工具。 为了增加系统的...

    java开源包1

    利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth ...

    java开源包11

    利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth ...

    java开源包2

    利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth ...

    java开源包3

    利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth ...

    java开源包6

    利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth ...

    java开源包5

    利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth ...

    java开源包10

    利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth ...

    java开源包4

    利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth ...

    java开源包8

    利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth ...

Global site tag (gtag.js) - Google Analytics