Ajax、Struts、Spring的无缝结合

2006-12-28     推荐:18875421    收藏:12212441    评论:14027     来源:中华部落阁

去年初,正好负责一个医药信息系统的设计开发,架构设计时,采用Struts+JDBC(自定义采用适配器模式封装了HashMap动态VO实现的持久层)。后来ajax热潮兴起,正好系统中有很多地方需要和服务器端交互数据,如采购销售系统中的订单头/订单明细等主从表结构的维护。

数据交互过程,我们考虑采用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格式的字符串

* @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;

}

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

1.DispatchAction

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

parameter="method" validate="false">





其中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" validate="false">



其中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 的源码如下:

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

expDisplayDetails = new ThreadLocal();



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 methods = new HashMap();

/**

* 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 ActionForward instance describing where and how

* control should be forwarded, or null 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 execute

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

}

}



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

/**

* 带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的无缝结合。欢迎大家拍砖!

您可以针对本文进行:[评论]  [收藏]  [推荐]  
  • [14027楼] 2008-05-28 08:31:23.0  网友
  • [回复]
  • Boss <a href="http://koloji.rack111.com/156.html ">wdef chattanooga</a> <a href="http://koloji.rack111.com/409.html ">craig forbell</a> <a href="http://koloji.rack111.com/150.html ">metaformin</a> <a href="http://koloji.rack111.com/311.html ">cabnet doors</a> [URL=http://koloji.rack111.com/98.html]manufactored homes[/URL] [URL=http://koloji.rack111.com/127.html]japangirls[/URL] end
  • [14026楼] 2008-04-29 12:00:07.0  网友
  • [回复]
  • Cabinet <a href="http://certad.rack111.com/28.html ">vintage subaru</a> <a href="http://certad.rack111.com/321.html ">subaru gas milage</a> <a href="http://certad.rack111.com/82.html ">2003 subaru legacy ecu reprogram</a> <a href="http://certad.rack111.com/499.html ">subaru seat belt extension</a> [URL=http://certad.rack111.com/454.html]subaru hill holder[/URL] [URL=http://certad.rack111.com/359.html]colonial subaru[/URL] links
  • [14025楼] 2008-04-29 11:37:41.0  网友
  • [回复]
  • In bookmarks <a href="http://partasf.info/jaime_pressly_sex_film_clips.html ">jaime pressly sex film clips</a> <a href="http://partasf.info/indianmasala_sex.html ">indianmasala sex</a> <a href="http://partasf.info/hey_sexy_lady_remix.html ">hey sexy lady remix</a> <a href="http://partasf.info/hoolywood_sex.html ">hoolywood sex</a> [URL=http://partasf.info/inden_sex.html]inden sex[/URL] [URL=http://partasf.info/hollywood_sexcapades.html]hollywood sexcapades[/URL] nice
  • [14024楼] 2008-04-29 11:13:05.0  网友
  • [回复]
  • Gangster <a href="http://deferfa.325mb.com/156.html ">marriage counselor pontiac x</a> <a href="http://deferfa.325mb.com/713.html ">valve covers for pontiac 455</a> <a href="http://deferfa.325mb.com/722.html ">pontiac ohc 6</a> <a href="http://deferfa.325mb.com/19.html ">1957 pontiac star chief convertible</a> [URL=http://deferfa.325mb.com/372.html]1977 pontiac grand prix[/URL] [URL=http://deferfa.325mb.com/3.html]1966 pontiac gto[/URL] urls
  • [14023楼] 2008-04-29 10:50:50.0  网友
  • [回复]
  • Hello, people <a href="http://partase.info/gay_sexing.html ">gay sexing</a> <a href="http://partase.info/hausfrauensex.html ">hausfrauensex</a> <a href="http://partase.info/grandmaster_sexay.html ">grandmaster sexay</a> <a href="http://partase.info/free_jenna_lewis_sex_tape.html ">free jenna lewis sex tape</a> [URL=http://partase.info/free_lebian_sex_videos.html]free lebian sex videos[/URL] [URL=http://partase.info/her_fisrt_lesbian_sex.html]her fisrt lesbian sex[/URL] and other
  • [14022楼] 2008-04-29 10:27:06.0  网友
  • [回复]
  • Grand <a href="http://koldas.freehoxt.com/360.html ">rebuildable nissan murano</a> <a href="http://koldas.freehoxt.com/529.html ">nissan xterra foglights</a> <a href="http://koldas.freehoxt.com/642.html ">nissan tida</a> <a href="http://koldas.freehoxt.com/315.html ">nissan maxima custom grills</a> [URL=http://koldas.freehoxt.com/48.html]modified 1999 nissan maximas[/URL] [URL=http://koldas.freehoxt.com/495.html]1997 nissan sentra stalling[/URL] world
  • [14021楼] 2008-04-29 09:40:27.0  网友
  • [回复]
  • America <a href="http://gupolo.oxyhost.com/748.html ">morgantown honda</a> <a href="http://gupolo.oxyhost.com/813.html ">86 honda xr600r info</a> <a href="http://gupolo.oxyhost.com/558.html ">honda nsx for sale</a> <a href="http://gupolo.oxyhost.com/407.html ">1980 honda cb650</a> [URL=http://gupolo.oxyhost.com/626.html]custom honda elite ch125 scooter exhaust[/URL] [URL=http://gupolo.oxyhost.com/133.html]honda kayak racks[/URL] town
  • [14020楼] 2008-04-29 08:55:13.0  网友
  • [回复]
  • Cabinet <a href="http://ewlaoter.oxyhost.com/560.html ">toyota hiace vans</a> <a href="http://ewlaoter.oxyhost.com/693.html ">toyota service eastside</a> <a href="http://ewlaoter.oxyhost.com/690.html ">toyota sequia</a> <a href="http://ewlaoter.oxyhost.com/463.html ">toyota platz upgrade</a> [URL=http://ewlaoter.oxyhost.com/38.html]peoria toyota[/URL] [URL=http://ewlaoter.oxyhost.com/27.html]toyota camry rims[/URL] links
  • [14019楼] 2008-04-29 08:09:42.0  网友
  • [回复]
  • Cabinet <a href="http://certad.rack111.com/244.html ">lariche subaru</a> <a href="http://certad.rack111.com/85.html ">subaru awd transmission fluid</a> <a href="http://certad.rack111.com/438.html ">subaru headlight aiming</a> <a href="http://certad.rack111.com/439.html ">subaru wicked weasel</a> [URL=http://certad.rack111.com/322.html]2003 subaru forester head gasket[/URL] [URL=http://certad.rack111.com/489.html]100 cell subaru[/URL] links
  • [14018楼] 2008-04-29 11:32:11.0  网友
  • [回复]
  • All about site <a href="http://partasa.info/gilf_sex.html ">gilf sex</a> <a href="http://partasa.info/freeanimesex.html ">freeanimesex</a> <a href="http://partasa.info/free_mila_kunis_sex_pictures.html ">free mila kunis sex pictures</a> <a href="http://partasa.info/draco_sex.html ">draco sex</a> [URL=http://partasa.info/drawn_sex_kim_possible.html]drawn sex kim possible[/URL] [URL=http://partasa.info/escort_prague_sex.html]escort prague sex[/URL] pages
  • 共有14027条评论  点击查看更多评论
  • 网友评论仅供网友表达个人看法,并不表明e800同意其观点或证实其描述
我想发表评论:
用户名密码
  • 匿名发表
    验证码: