第一次亲密接触--系统集成

  项目业务背景:该项目是XX公司为YY能源公司创建的企业内容管理(ECM,Enterprise Content Manager)解决方案。该项目分为两大部分,CM和BPM,其中CM创建并保存YY公司在生产及运营过程中产生的文档,而BPM则负责处理YY公司中的业务流程。同时,该项目还与YY公司现有的企业系统EAM进行集成,将EAM系统中的一些文档ECM进行存储。
第一次亲密接触--系统集成_第1张图片


    项目开发背景:ECM系统包含了三个子系统,分别是CM系统,BPM系统与COMMON系统。CM负责文档的创建与保管;BPM调用DM中的文档,进行业务处理,BPM在业务流程中也可能会产生一些文档到BPM中;COMMON为DM和BPM提供业务参数配置,也完成外部系统(EAM)与内部系统的交互工作。我是CM中的一名开发工程师,前期负责几个CM中几个模块的开发工作,后期主要负责与其它系统(如BPM、EAM等)的集成。

    CM中独立模块的开发工作就不多说了,根据需求分析说明书与需求跟踪矩阵,还有业务状态切换图来确认系统中每个业务的用例,从而完成该功能的开发。难度不大,最重要的是理解业务。我们主要讲解在系统集成过程中发生的一些问题。

    对每一个未接触过集成的人来说,都觉得系统集成是一个高深莫测的东西。因为他们只是在系统内部的框架内完成接口的调用,不懂得换了框架之后,接口的实现会发生什么样的变化。对框架的依赖性太强,这是现代开发人员的一个弊病,其实与外部系统的集成从底层看来,就是使用其它框架的实现。

    在BPM与CM进行集成时,既可能有BPM调用CM,也可能有CM调用BPM,但是无论怎么调用,归根到底都是为对方提供可行性的接口。我们以BPM调用CM为例,在代码中讲述集成。在系统集成中,有一个很重要的安全问题,那就是单点登录,由于此部分内容较多,这里不做详细介绍。

    我们知道Servlet通过HTTP协议,在Request获取数据时,有GET、POST、PUT几种方式,我们(CM)在为BPM提供接口时,就需要考虑这几种常用的情况,考虑到BPM对CM的调用比较频繁,以及系统的可扩展性,我们提供一个抽象类,来实现支持这几种方式。为保证数据的正确性,我们在里面使用事务进行封装。

    
public abstract class AbstractRestController {
	private static final int POST = 0;
	private static final int GET = 1;
	private static final int PUT = 2;
	
	//使用Log4j记录日志
	protected static final Logger logger = Logger
			.getLogger(AbstractRestController.class);

	protected ThreadLocal<HttpServletRequest> request = new ThreadLocal<HttpServletRequest>();

	protected String body;

	private BackLoginModule module = null;
	
	/**
	* 使用注解处理POST请求
	*/
	@RequestMapping(method = RequestMethod.POST)
	public void handlePOSTRequest(@RequestBody String body,
			HttpServletRequest request, HttpServletResponse response)
			throws ServletException {
		this.body = body;
		process(request, response, POST);
	}

	/**
	* 使用注解处理GET请求
	*/
	@RequestMapping(method = RequestMethod.GET)
	public void handleGetRequest(HttpServletRequest request,
			HttpServletResponse response) throws ServletException {
		process(request, response, GET);
	}

	/**
	* 使用注解处理PUT请求
	*/
	@RequestMapping(method = RequestMethod.PUT)
	public void handlePUTRequest(@RequestBody String body,
			HttpServletRequest request, HttpServletResponse response)
			throws ServletException {
		this.body = body;
		process(request, response, PUT);
	}

	private void process(HttpServletRequest request,
			HttpServletResponse response, int type) {
		this.request.set(request);

		//使用事务,发生错误时可以回滚
		UserTransaction tx = null;
		try {
			tx = TransactionUtil.getUserTransaction();
			tx.begin();


			Object result = null;
			if(type == POST)
				result = processPost();
			else if(type == PUT)
				result = processPut();
			else if(type == GET)
				result = processGet();
			

			writeResponse(result, response);
			tx.commit();
		} catch (EcmException ex) {
			try {				
				tx.rollback();
			} catch (Exception e) {
				e.printStackTrace();
			}
			logger.error("Error occurred when invoking remoting services.", ex);

			BizResponse br = new BizResponse();
			br.setErrorCode(ex.getCode());
			br.setErrorDescription(ex.getErrorDescrption());
			Map<String, String> map = new HashMap<String, String>();
			map.put(RestConstants.RESPONSE_BODY_CONTENT, body);

			br.setItem(map);
			writeResponse(br, response);
		} catch (Exception ex) {
			try {				
				tx.rollback();
			} catch (Exception e) {
				e.printStackTrace();
			}

			logger.error("Error occurred when invoking remoting services.", ex);
			BizResponse br = new BizResponse();
			br.setErrorCode(ErrorCode.UNKNOW_ERROR);
			br.setErrorDescription(ErrorMessageHelper
					.getErrMessage(ErrorCode.UNKNOW_ERROR));
			Map<String, String> map = new HashMap<String, String>();
			map.put(RestConstants.RESPONSE_BODY_CONTENT, body);
			br.setItem(map);
			writeResponse(br, response);
		} finally {
			this.request.set(null);
			if(module != null){
				try {
					module.logout();
				} catch (Exception e) {
					// TODO: handle exception
				}
			}
//			if (EcmConfig.useTomcat())
			 if (EcmConfig.useSSO == false) {
				UserContextUtils.popSubject();
			 }
			// SubjectUtil.clear();
			ObjectStoreHelper.clear();
		}
	}

	protected Object processPost() throws EcmException {
		return null;
	}

	protected Object processGet() throws EcmException {
		return null;
	}

	protected Object processPut() throws EcmException {
		return null;
	}

	protected void writeResponse(Object bmpResp, HttpServletResponse response) {
		String body = null;
		if (bmpResp instanceof String) {
			body = (String) bmpResp;
		} else {
			body = JsonUtil.toJson(bmpResp);
		}

		response.setContentType("application/json");
		try {
			PrintWriter out = response.getWriter();
			out.print(body);
		} catch (IOException ioe) {
			logger.error("Error occurred when setting HTTP response via JSON.",
					ioe);
		}
	}
	
	protected HttpServletRequest getRequest(){
		return request.get();
	}
}


    CM与BPM继承,并为提供接口时,新的接口(类)继承AbstractRestController抽象类,就可以通过几种不同的HTTP请求来进行数据传递,同时也保证了事务性。下面是为BPM提供的一个借阅接口,在这里我们使用了PUT方式。
 
@Controller
@RequestMapping("/borrowProcessUpdate.do")
public class UpdateBorrowStatusController extends AbstractRestController {

	//此处使用PUT方式
	@Override
	public Object processPut() throws EcmException {
		UpdateBorrowReq req = JsonUtil.fromJson(body, UpdateBorrowReq.class);
		BorrowDocument[] borrowDocumentList = new BorrowDocument[req.getBorrowDocumentList().length];
		//...此处省去部分代码
		boolean flag = IntegrateBorrowProcess.executeProcess(obj,borrowDocumentList);
		ResetUniversalResponse results = new ResetUniversalResponse();
		results.setBsuccessed(flag);
		return results;
	}


    其实,集成并不是像我们想象中的那么可怕,重要的是要找到它的突破口。我们这里所讲的集成,最重要的是AbstractRestController,它为外部提供了几种方式HTTP请求方式,给了BPM一个入口。

你可能感兴趣的:(exception,框架,String,object,null,文档)