Apache CXF 在项目中的真实运用--WS服务编写
我的项目是一个医疗用品公司的网站,其中的诊所数据、工单数据、工单图片数据来自客户的另个自己CS系统。客户需要每天定时上传这些数据到我的服务器。考虑使用WebService作为解决方案.
1、处于了团队分工合作考虑,我的整个解决方案由多个项目构成:
2、SY WS就是CXF WebService项目,这个WS比较简单:
项目结构:
各个包说明如下:
com.defshare.sy.ws:WS接口包
com.defshare.sy.ws.config:WS配置包
com.defshare.sy.ws.impl:WS实现类包
com.defshare.sy.ws.po:WS的VO类包
com.defshare.sy.ws.test:WS测试包
ws.properties:存放WS所有接口访问的安全账户和密码以及文件上传后的存放路径
只有一个接口,代码如下:
package com.defshare.sy.ws; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; import com.defshare.sy.ws.po.Clinique; import com.defshare.sy.ws.po.ToothSpec; import com.defshare.sy.ws.po.WorkList; import com.defshare.sy.ws.po.WorkListPicFile; @WebService(targetNamespace="http://www.springframework.org/schema/beans") public interface ISYWebService { /** * <pre> * 上传工单[工单中包含牙齿规格],同时记录工单上传历史 * </pre> * @param workLists 要上传工单所组成的数组 * @return 上传结果 */ @WebMethod public int upLoadWorkList(@WebParam String userName,@WebParam String password,@WebParam WorkList[] workLists); /** * 上传诊所信息,同时记录上传历史 * @param cliniques 要上传诊所所组成的数组 * @return 上传结果 */ public int upLoadClinique(@WebParam String userName,@WebParam String password,@WebParam Clinique[] cliniques); /** * 上传工单图片文件,如果该图片文件对应的工单编号在系统中不存在则当前文件上传失败 * @param file 要上传的工单图片文件 * @return 上传结果 */ @WebMethod public int upLoadWorkListPic(@WebParam String userName,@WebParam String password,@WebParam WorkListPicFile file); /** * 更新工单,工单编号不能存在则更新失败 * @param workList 包含更新后工单信息的工单对象 * @return 更新结果 */ @WebMethod public int updateWorkList(@WebParam String userName,@WebParam String password,@WebParam WorkList workList); /** * 更新牙齿规格的工序 * @param toothSpecId 牙齿规格编号 * @param gx 新的工序 * @return */ @WebMethod public int updateToothSpecGX(@WebParam String toothSpecId,@WebParam String gx); /** * 更新诊所信息,诊所编号不存在则更新失败 * @param cliniques 包含更新后诊所信息的工单对象 * @return 更新结果 */ @WebMethod public int updateClinique(@WebParam String userName,@WebParam String password,@WebParam Clinique cliniques); /** * 删除工单,删除工单要一并删除工单对应的图片 * @param workListId 要删除工单的编号 * @return 删除结果 */ @WebMethod public int removeWorkList(@WebParam String userName,@WebParam String password,@WebParam String workListId); /** * <h3>成功</h3> * <p>SUCCESS = 0</p> */ public static final int SUCCESS = 0; /** * <h3>工单编号为空</h3> * <p>WORKLIST_ID_IS_EMPTY = 1</p> */ public static final int WORKLIST_ID_IS_EMPTY = 1; /** * <h3>诊所编号为空</h3> * <p>CLINIQUE_ID_IS_EMPTY = 2</p> */ public static final int CLINIQUE_ID_IS_EMPTY = 2; /** * <h3>没有文件信息上传</h3> * <p>NO_FILEINFO_UPLOAD = 3</p> */ public static final int NO_FILEINFO_UPLOAD = 3; /** * <h3>没有工单信息可以上传</h3> * <p> NO_WORKLIST_UPLOAD = 4</p> */ public static final int NO_WORKLIST_UPLOAD = 4; /** * <h3>没有工单图片文件可以上传</h3> * <p> NO_WORKLIST_PIC_UPLOAD = 5</p> */ public static final int NO_WORKLIST_PIC_UPLOAD = 5; /** * <h3>没有诊所信息可以上传</h3> * <p>NO_CLINIQUE_UPLOAD = 6</p> */ public static final int NO_CLINIQUE_UPLOAD = 6; /** * <h3>没有工单可以更新</h3> * <p>NO_WORKLIST_UPDATE = 7</p> */ public static final int NO_WORKLIST_UPDATE = 7; /** * <h3>没有诊所信息可以更新</h3> * <p>NO_CLINIQUE_UPDATE = 8</p> */ public static final int NO_CLINIQUE_UPDATE = 8; /** * <h3>不安全的调用</h3> * <p>INSECURE_CALL = 9</p> */ public static final int INSECURE_CALL = 9; /** * <h3>不存在的工单[上传工单图片时检查]</h3> * <p>NO_EXSITS_WORKLIST = 10</p> */ public static final int NO_EXSITS_WORKLIST = 10; /** * <h3>输入输出异常</h3> * <p>IO_EXCEPTION = 11</p> */ public static final int IO_EXCEPTION = 11; /** * <h3>录入数据失败[存在重复数据]</h3> * <p>IO_EXCEPTION = 12</p> */ public static final int IO_REPEAT = 12; /** * 应用程序异常 */ public static final int APPLICATION_EXCEPTION = 13; /** * 数据库异常 */ public static final int SQLEXCEPTION = 14; /** * <h3>规格编号为空</h3> * <p>TOOTHSPEC_ID_IS_EMPTY = 15</p> */ public static final int TOOTHSPEC_ID_IS_EMPTY = 15; }
3、实现类如下:
package com.defshare.sy.ws.impl; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.sql.Timestamp; import java.util.List; import java.util.UUID; import javax.jws.WebParam; import javax.jws.WebService; import javax.servlet.ServletContext; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.aspectj.lang.annotation.AfterThrowing; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.ProjectionList; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.springframework.web.context.ServletContextAware; import com.defshare.foundation.dao.IHibernateCallback; import com.defshare.foundation.global.DateUtil; import com.defshare.foundation.global.ExceptionUtil; import com.defshare.foundation.pubs.Md5Encrypt; import com.defshare.sy.biz.impl.ServiceTemplate; import com.defshare.sy.po.SystemLog; import com.defshare.sy.po.ToothSpec; import com.defshare.sy.po.WorkListHistory; import com.defshare.sy.ws.ISYWebService; import com.defshare.sy.ws.po.Clinique; import com.defshare.sy.ws.po.WorkList; import com.defshare.sy.ws.po.WorkListPicFile; //@Service("syWebService") @WebService(targetNamespace = "http://www.springframework.org/schema/beans") public class SYWebService implements ISYWebService, ServletContextAware { Logger LOG = Logger.getLogger(SYWebService.class); /** * 删除工单 * * <pre> * 1.查询出工单关联的图片名称:xxx.jpg,xxx2.jpg,xxx3.jpg * 2.删除工单关联的牙齿规格数据 session.delete(arg0) * 3.删除工单数据 session.delete(arg0) * 4.循环删除管理的图片 * 5.以上步骤2、3、4必须运行在一个事务里面 * </pre> */ @Override public int removeWorkList(@WebParam String userName, @WebParam String password, final String workListId) { // 判断登陆信息是否有效 if (!isSecure(userName, password)) return INSECURE_CALL; // 判断工单id是否有效 if (StringUtils.isBlank(workListId)) return WORKLIST_ID_IS_EMPTY; return (Integer)serviceTemplate.getCommonDao().execute(new IHibernateCallback() { @SuppressWarnings("unchecked") @Override public Object doInHibernate(Session session) { // 删除工单 LOG.info(session.isOpen() ? "Hibernate Session 是有效的" : "Hibernate session是无效的"); try { ProjectionList plist = Projections.projectionList(); plist.add(Projections.property("pics")); plist.add(Projections.property("gdbh")); // 查询工单图片 Object[] wl = (Object[]) session.createCriteria( com.defshare.sy.po.WorkList.class).setProjection( plist).add(Restrictions.eq("gdbh", workListId)) .uniqueResult(); if (wl == null && wl.length <= 0) return NO_EXSITS_WORKLIST; LOG .info("-------------------------------------------------------------------------------"); String pics = null; String[] picses = null; if (wl[0] != null) { pics = wl[0].toString(); picses = pics.split(","); } LOG.info("-----------图片名称-------------" + pics); // 查询牙齿规格 List<ToothSpec> toothlist = (List<ToothSpec>) session .createCriteria(ToothSpec.class).add( Restrictions.eq("gdbh", workListId)).list(); // 循环删除牙齿规格 if (toothlist != null && toothlist.size() > 0) { for (ToothSpec toothSpec : toothlist) { session.delete(toothSpec); LOG.info("删除牙齿规格成功"); } } // 删除工单 com.defshare.sy.po.WorkList worklist = new com.defshare.sy.po.WorkList(); worklist.setGdbh(workListId); session.delete(worklist); LOG.info("删除工单成功"); // LOG.info("===========================" + getSavepath()); // File file = new File(getSavepath()); // String path = file.getAbsolutePath(); // System.out.println("---------" + path); // // 循环删除本地图片 --------------------(本地测试)worklist // if (picses != null && picses.length > 0) { // for (String ps : picses) { // File f = new File(path + "/" + ps); // f.delete(); // LOG.info("每次本地删除文件成功"); // } // } // 循环删除本地图片 --------------------(服务器) if (picses != null && picses.length > 0) { for (String ps : picses) { File f = new File(servletContext.getRealPath("/") + "/" + getSavepath() + "/" + ps); f.delete(); } } } catch (HibernateException e) { return NO_EXSITS_WORKLIST; } return SUCCESS; } }); } /** * 上传诊所信息 */ @Override public int upLoadClinique(@WebParam String userName, @WebParam String password, final Clinique[] cliniques) { if (!isSecure(userName, password)) return INSECURE_CALL; if (null == cliniques || 0 == cliniques.length) return NO_CLINIQUE_UPLOAD; return (Integer)serviceTemplate.getCommonDao().execute(new IHibernateCallback() { private static final long serialVersionUID = -1708351120071544240L; @Override public Object doInHibernate(Session session) { for (Clinique clinique : cliniques) { if (StringUtils.isBlank(clinique.getZsid())) return CLINIQUE_ID_IS_EMPTY; com.defshare.sy.po.Clinique cli = new com.defshare.sy.po.Clinique(); cli.setDq(clinique.getDq()); cli.setZsid(clinique.getZsid()); cli.setDqbh(clinique.getDqbh()); cli.setDxts(clinique.getDxts()); cli.setLxdh(clinique.getLxdh()); cli.setYsxm(clinique.getYsxm()); cli.setYwjl(clinique.getYwjl()); cli.setYwy(clinique.getYwy()); cli.setZsdz(clinique.getZsdz()); cli.setZsjx(clinique.getZsjx()); cli.setZsmc(clinique.getZsmc()); if(clinique.getZsmm()==null || "".equals(clinique.getZsmm())){ clinique.setZsmm("0000"); } cli.setZsmm(new Md5Encrypt().getMD5ofStr(clinique.getZsmm()));//MD5后再存入数据库 try { session.save(cli); } catch (Exception e) { return IO_REPEAT; } WorkListHistory workList = new WorkListHistory(); workList.setKind("2"); workList.setReceiveTime(new Timestamp(System .currentTimeMillis())); workList.setBh(cli.getZsid()); workList.setWorkListHistoryId(UUID.randomUUID().toString()); session.save(workList); } return SUCCESS; } }); } /** * 上传工单 */ @Override public int upLoadWorkList(@WebParam String userName, @WebParam String password, final WorkList[] workLists) { if (null == workLists || 0 == workLists.length) return NO_WORKLIST_UPLOAD; if (!isSecure(userName, password)) return INSECURE_CALL; return (Integer) serviceTemplate.getCommonDao().execute(new IHibernateCallback() { private static final long serialVersionUID = -3808681177275551002L; @Override public Object doInHibernate(Session session) { for (WorkList workList : workLists) { LOG.info(workList.getGdbh()); if (StringUtils.isBlank(workList.getGdbh())) return WORKLIST_ID_IS_EMPTY; com.defshare.sy.po.WorkList wo = new com.defshare.sy.po.WorkList(); wo.setBrxm(workList.getBrxm()); wo.setCjr(workList.getCjr()); wo.setCjrq(Timestamp.valueOf(workList.getCjrq())); wo.setFggdbh(workList.getFggdbh()); wo.setFgyy(workList.getFgyy()); wo.setGdbh(workList.getGdbh()); wo.setJjrq(Timestamp.valueOf(workList.getJjrq())); wo.setJzrq(Timestamp.valueOf(workList.getJzrq())); wo.setLuz(workList.getLuz()); wo.setPics(workList.getPics()); wo.setSsdq(workList.getSsdq()); wo.setYsxm(workList.getYsxm()); wo.setYwy(workList.getYwy()); wo.setZsid(workList.getZsid()); session.save(wo); if (workList.getToothSpecs()!= null) { LOG.info("------------jin---------"); for (com.defshare.sy.ws.po.ToothSpec tt : workList .getToothSpecs()) { if(tt!=null){ ToothSpec ts = new ToothSpec(); ts.setToothSpecId(tt.getToothSpecId()); ts.setAddsl(tt.getAddsl()); ts.setDx(tt.getDx()); ts.setGdbh(wo.getGdbh()); ts.setGx(tt.getGx()); ts.setHbhid(tt.getHbhid()); ts.setJg(tt.getJg()); ts.setSl(tt.getSl()); ts.setYclx(tt.getYclx()); ts.setYs(tt.getYs()); ts.setYw(tt.getYw()); ts.setZl(tt.getZl()); session.save(ts); }} } LOG.info("------------没进---------"); WorkListHistory work = new WorkListHistory(); work.setKind("0"); work.setReceiveTime(new Timestamp(System .currentTimeMillis())); work.setBh(workList.getGdbh()); work.setWorkListHistoryId(UUID.randomUUID().toString()); session.save(work); } return SUCCESS; } }); } /** * 上传工单图片文件 */ @Override public int upLoadWorkListPic(@WebParam String userName, @WebParam String password, final WorkListPicFile file) { LOG.info("-----------------------------------------------------"); LOG.info("开始执行上传工单图片"); if (!isSecure(userName, password)) return INSECURE_CALL; if (StringUtils.isBlank(file.getWorkListId())) return WORKLIST_ID_IS_EMPTY; if (file.getPosition() == 0) { LOG.info("首次上传文件块,检查是否存在该图片关联的工单[" + file.getWorkListId() + "]"); // 如果是首次上传则检查工单编号对应的工单在系统中是否存在 Object result = serviceTemplate.getCommonDao().execute( new IHibernateCallback() { @Override public Object doInHibernate(Session session) { LOG .info(session.isOpen() ? "Hibernate Session 是有效的" : "Hibernate session是无效的"); return session.createCriteria( com.defshare.sy.po.WorkList.class) .setProjection(Projections.rowCount()).add( Restrictions.eq("gdbh", file .getWorkListId())) .uniqueResult(); } }); LOG.info("检查结果,存在[" + result + "]条"); if (result == null || Integer.valueOf(result.toString()) != 1) { return NO_EXSITS_WORKLIST; } } // 执行上传 LOG.info("执行上传文件块[" + file.getBytes().length + "\t" + file.getPosition() + "/" + file.getFileSize() + "]"); OutputStream os = null; try { File f = new File(servletContext.getRealPath("/") + "/" + getSavepath() + "/" + file.getServerFile()); LOG.info("服务器保存文件路径:" + f.getAbsolutePath()); if (file.getPosition() != 0) { os = FileUtils.openOutputStream(f, true); } else { os = FileUtils.openOutputStream(f, false); } os.write(file.getBytes()); } catch (IOException e) { return IO_EXCEPTION; } finally { if (os != null) try { os.close(); } catch (IOException e) { e.printStackTrace(); } IOUtils.closeQuietly(os); } LOG.info("上传文件块完成"); // 如果是最后一次上传则修改工单 if (file.getPosition() + file.getBytes().length == file.getFileSize()) { LOG.info("最后一次上传文件数据块,上传后修改工单的图片字段"); com.defshare.sy.po.WorkList workList = serviceTemplate.findById( com.defshare.sy.po.WorkList.class, file.getWorkListId()); String pics = workList.getPics(); pics = pics == null ? "" : pics; pics = pics.equals("") ? file.getServerFile() : pics + "," + file.getServerFile(); workList.setPics(pics); } LOG.info("执行本次上传工单图片完成\n"); return SUCCESS; } /** * 更新诊所信息 */ @Override public int updateClinique(@WebParam String userName, @WebParam String password, final Clinique clinique) { LOG.info("-----------------------------------------------------"); LOG.info("----------------开始执行更新---------------------"); if (null == clinique) return NO_CLINIQUE_UPDATE; if (StringUtils.isBlank(clinique.getZsid())) return CLINIQUE_ID_IS_EMPTY; if (!isSecure(userName, password)) return INSECURE_CALL; LOG .info(serviceTemplate.getCommonDao() == null ? "serviceTemplate.getCommonDao()无效" : "serviceTemplate.getCommonDao()有效"); LOG.info("-----------------------------------------------------"); LOG.info("----------------正在执行更新---------------------"); return (Integer)serviceTemplate.getCommonDao().execute(new IHibernateCallback() { @Override public Object doInHibernate(Session session) { LOG.info(session.isOpen() ? "Hibernate Session 是有效的" : "Hibernate session是无效的"); com.defshare.sy.po.Clinique cqe = (com.defshare.sy.po.Clinique) session .get(com.defshare.sy.po.Clinique.class, clinique .getZsid()); if(null==cqe) return NO_CLINIQUE_UPDATE; LOG.info("***********" + cqe.getDq()); if (!StringUtils.isBlank(clinique.getDq())) cqe.setDq(clinique.getDq()); if (!StringUtils.isBlank(clinique.getDqbh())) cqe.setDqbh(clinique.getDqbh()); if (!StringUtils.isBlank(clinique.getLxdh())) cqe.setLxdh(clinique.getLxdh()); if (!StringUtils.isBlank(clinique.getLxdh())) cqe.setLxdh(clinique.getLxdh()); if (!StringUtils.isBlank(clinique.getYwjl())) cqe.setYwjl(clinique.getYwjl()); if (!StringUtils.isBlank(clinique.getYwy())) cqe.setYwy(clinique.getYwy()); if (!StringUtils.isBlank(clinique.getZsdz())) cqe.setZsdz(clinique.getZsdz()); if (!StringUtils.isBlank(clinique.getZsjx())) cqe.setZsjx(clinique.getZsjx()); if (!StringUtils.isBlank(clinique.getZsmc())) cqe.setZsmc(clinique.getZsmc()); if (!StringUtils.isBlank(clinique.getZsmm())) cqe.setZsmm(new Md5Encrypt().getMD5ofStr(clinique.getZsmm())); if (clinique.getDxts() != null && !clinique.getDxts().equals("")) cqe.setDxts(clinique.getDxts()); LOG .info("-----------------------------------------------------"); LOG.info("----------------更新成功---------------------"); return SUCCESS; } }); } /** * 更新工单 */ @Override public int updateWorkList(@WebParam final String userName, @WebParam final String password, final WorkList workList) { if (!isSecure(userName, password)) return INSECURE_CALL; if (null == workList) return NO_WORKLIST_UPDATE; if (StringUtils.isBlank(workList.getGdbh())) return WORKLIST_ID_IS_EMPTY; return (Integer) serviceTemplate.getCommonDao().execute(new IHibernateCallback() { private static final long serialVersionUID = -5913043706463089942L; @Override public Object doInHibernate(Session session) { LOG.info(session.isOpen() ? "Hibernate Session 是有效的" : "Hibernate session是无效的"); com.defshare.sy.po.WorkList _workList = (com.defshare.sy.po.WorkList) session .get(com.defshare.sy.po.WorkList.class, workList .getGdbh()); if (_workList == null) return NO_WORKLIST_UPDATE; if (!StringUtils.isBlank(workList.getFggdbh())) _workList.setFggdbh(workList.getFggdbh()); if (!StringUtils.isBlank(workList.getZsid())) _workList.setZsid(workList.getZsid()); if (!StringUtils.isBlank(workList.getYsxm())) _workList.setYsxm(workList.getYsxm()); if (!StringUtils.isBlank(workList.getBrxm())) _workList.setBrxm(workList.getBrxm()); if (!StringUtils.isBlank(workList.getYwy())) _workList.setYwy(workList.getYwy()); if (!StringUtils.isBlank(workList.getSsdq())) _workList.setSsdq(workList.getSsdq()); if (!StringUtils.isBlank(workList.getFgyy())) _workList.setFgyy(workList.getFgyy()); if (!StringUtils.isBlank(workList.getJjrq())) _workList.setJjrq(Timestamp.valueOf(workList.getJjrq())); if (!StringUtils.isBlank(workList.getCjrq())) _workList.setCjrq(Timestamp.valueOf(workList.getCjrq())); if (!StringUtils.isBlank(workList.getJzrq())) _workList.setJzrq(Timestamp.valueOf(workList.getJzrq())); if (!StringUtils.isBlank(workList.getXgrq())) _workList.setXgrq(Timestamp.valueOf(workList.getXgrq())); if (!StringUtils.isBlank(workList.getXgcs())) _workList.setXgcs(Short.valueOf(workList.getXgcs())); if (!StringUtils.isBlank(workList.getLuz())) _workList.setLuz(workList.getLuz()); if (!StringUtils.isBlank(workList.getCjr())) _workList.setCjr(workList.getCjr()); if (workList.getToothSpecs() != null) { for (com.defshare.sy.ws.po.ToothSpec tt : workList .getToothSpecs()) { if(tt!=null){ List<ToothSpec> spec = session.createCriteria( ToothSpec.class).add( Restrictions.eq("gdbh", tt.getGdbh())).list(); ToothSpec ts = null; LOG.info("ToothSpec查询出的规格:" + spec.size()); if (spec != null) { for (ToothSpec toothSpec : spec) { LOG.info("ToothSpec查询出的工单编号:" + toothSpec.getGdbh()); session.delete(toothSpec); } } ts = new ToothSpec(); ts.setToothSpecId(tt.getToothSpecId()); ts.setAddsl(tt.getAddsl()); ts.setDx(tt.getDx()); ts.setGdbh(tt.getGdbh()); ts.setGx(tt.getGx()); ts.setHbhid(tt.getHbhid()); ts.setJg(tt.getJg()); ts.setSl(tt.getSl()); ts.setYclx(tt.getYclx()); ts.setYs(tt.getYs()); ts.setYw(tt.getYw()); ts.setZl(tt.getZl()); session.save(ts); } } } return SUCCESS; } }); } /** * 更新牙齿规格的工序 * @param toothSpecId 牙齿规格编号 * @param gx 新的工序 * @return */ @Override public int updateToothSpecGX(final String toothSpecId, final String gx) { // TODO Auto-generated method stub LOG.info("ToothSpec规格编号:" + toothSpecId); LOG.info("ToothSpec工序:" + gx); if(StringUtils.isBlank(toothSpecId)) return TOOTHSPEC_ID_IS_EMPTY; return (Integer)serviceTemplate.getCommonDao().execute(new IHibernateCallback() { @Override public Object doInHibernate(Session session) { LOG.info("ToothSpec规格编号:" + toothSpecId); LOG.info("ToothSpec工序:" + gx); ToothSpec spec=(ToothSpec) session.createCriteria(ToothSpec.class).add(Restrictions.eq("toothSpecId", toothSpecId)).uniqueResult(); LOG.info("ToothSpec查询出的规格:" +spec.getGx()); if(!StringUtils.isBlank(gx)) spec.setGx(gx); return SUCCESS; } }); } // @Resource(name = "serviceTemplate") private ServiceTemplate serviceTemplate; public ServiceTemplate getServiceTemplate() { return serviceTemplate; } public void setServiceTemplate(ServiceTemplate serviceTemplate) { this.serviceTemplate = serviceTemplate; } /** * 调用是否安全,每个WebService方法应该调用此方法 * * @param userName * @param password * @return */ private Boolean isSecure(String userName, String password) { if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)) { return false; } return userName.equals(wsUserName) && password.equals(wsPassword); } private String wsUserName; private String wsPassword; public String getWsUserName() { return wsUserName; } public void setWsUserName(String wsUserName) { this.wsUserName = wsUserName; } public String getWsPassword() { return wsPassword; } public void setWsPassword(String wsPassword) { this.wsPassword = wsPassword; } private String savepath = "worklistupfiles"; public String getSavepath() { return savepath; } public void setSavepath(String savepath) { this.savepath = savepath; } private ServletContext servletContext; public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } }
4、CXF配置文件如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd" default-lazy-init="true" default-dependency-check="none"> <!--会向cxf jar包去找 --> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <!-- 以下Bean的状态可以修改为通过注解实现装配--> <bean id="syWebService" class="com.defshare.sy.ws.impl.SYWebService"> <property name="savepath" value="${ws.upfiles}"></property> <property name="serviceTemplate" ref="serviceTemplate"/> <property name="wsUserName" value="${ws.username}"></property> <property name="wsPassword" value="${ws.password}"></property> </bean> <jaxws:endpoint id="syWS" implementor="#syWebService" address="/SYWebService" endpointName="SYWebService" serviceName="SYWebService"> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:outInterceptors> </jaxws:endpoint> </beans>
5、关于WS的VO类的说明:
VO类的属性成员完全根据WS的客户端需要决定,不一定和项目的PO类属性相同。
此项目中CXF和Spring、Hibernate集成,开发中曾经反了一个荒唐错误就是“在WS项目中使用VO作Hibernate查询类,导致查询不来系统有没有错误警告,折腾许久”。想在想来可笑。(总结一下:当你遇到一个极近明显而又找不到原因的错误,小心可能只是你的粗心大意造成)
6、这个项目由于和Spring集成,因此方法中凡是涉及数据库部分自然也用到了容器事务。这个事务的配置我是在另一个项目中(SY Core)完成的,这个SY Core项目是我这个项目的Spring配置文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd" default-lazy-init="true" default-dependency-check="none"> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:jdbc.properties</value> <value>classpath:ws.properties</value> </list> </property> </bean> <!-- 扫描类路径下被注解的组件,这些组件将被自动注册为Spring Bean--> <context:component-scan base-package="com.defshare.foundation.dao,com.defshare.sy.biz.impl,com.defshare.sy.ws.impl,com.defshare.sy.web.action" /> <!-- 配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass"> <value>${jdbc.driverClassName}</value> </property> <property name="jdbcUrl"> <value>${jdbc.url}</value> </property> <property name="user"> <value>${jdbc.username}</value> </property> <property name="password"> <value>${jdbc.password}</value> </property> <!--初始化时获取0个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 --> <property name="initialPoolSize"> <value>0</value> </property> <property name="minPoolSize"> <value>1</value> </property> <!--连接池中保留的最大连接数。Default: 15 --> <property name="maxPoolSize"> <value>15</value> </property> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --> <property name="acquireIncrement"> <value>1</value> </property> <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 --> <property name="acquireRetryAttempts"> <value>3</value> </property> <!--两次连接中间隔时间,单位毫秒。Default: 1000 --> <property name="acquireRetryDelay"> <value>1000</value> </property> <!--连接关闭时默认将所有未提交的操作回滚。Default: false --> <property name="autoCommitOnClose"> <value>false</value> </property> <!--最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --> <property name="maxIdleTime"> <value>1800</value> </property> <!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出 SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --> <property name="checkoutTimeout"> <value>30000</value> </property> <!--每600秒检查所有连接池中的空闲连接。Default: 0 --> <property name="idleConnectionTestPeriod"> <value>600</value> </property> <!--c3p0将建一张名为C3P0TEST的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么 属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试 使用。Default: null --> <property name="automaticTestTable"> <value>C3P0TEST</value> </property> <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试 获取连接失败后该数据源将申明已断开并永久关闭。Default: false --> <property name="breakAfterAcquireFailure"> <value>false</value> </property> </bean> <!-- <bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" lazy-init="true"> </bean> --> <!-- Spring针对Hibernate提供的标准本地会话工厂Bean子类,支持JDK1.5以上元数据映射,这个类需要Hibernate3.2以上版本 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <!-- <property name="lobHandler"> <ref bean="lobHandler" /> </property> --> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> </props> </property> <property name="configLocation"> <value>classpath:com/defshare/sy/config/hibernate.cfg.xml</value> </property> <property name="packagesToScan" value="com.defshare.sy.po"></property> <!-- 存放特殊的查询语句 <property name="mappingResources"> <list> <value>com/defshare/sy/config/hibernate/ReportQuery.hbm.xml</value> </list> </property> --> </bean> <!-- Spring整合Hibernate提供的Hibernate模板,可以简化Hibernate操作,同时整合Hibenate操作到事务 --> <bean name="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 事务通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 配置事务传递属性 --> <tx:attributes> <tx:method name="get*" propagation="REQUIRED" read-only="true" /> <tx:method name="find*" propagation="REQUIRED" read-only="true" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="log*" propagation="REQUIRES_NEW" rollback-for="Exception"/> <tx:method name="*" propagation="REQUIRED" /> </tx:attributes> </tx:advice> <!-- 事务切面 --> <aop:config> <!--切入点 --> <aop:pointcut id="myPointCutA" expression="execution(* com.defshare.sy.biz.impl.*.*(..))" /> <aop:pointcut expression="execution(* com.defshare.sy.ws.impl.*.*(..))" id="myPointCutB"/> <!-- 将切入点和通知组合在一起 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointCutA" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointCutB"/> </aop:config> <!-- 日志工具 <bean id="logUtil" class="com.defshare.sy.log.LogUtil"></bean>--> <!-- 日志切面 <aop:config> <aop:aspect ref="logUtil"> <aop:pointcut expression="execution(* com.defshare.sy.biz.impl.*.*(..))" id="doLog1" /> <aop:around pointcut-ref="doLog1" method="doLog" /> </aop:aspect> </aop:config>--> </beans>
注意其中的:
<context:component-scan
base-package="com.defshare.foundation.dao,com.defshare.sy.biz.impl,com.defshare.sy.ws.impl,com.defshare.sy.web.action" />
和
<!--切入点 -->
<aop:pointcut id="myPointCutA"
expression="execution(* com.defshare.sy.biz.impl.*.*(..))" />
<aop:pointcut expression="execution(* com.defshare.sy.ws.impl.*.*(..))" id="myPointCutB"/>
就是对WS中的方法的事务配置。
当初这个地方忘记配置出现的问题是WS的方法不能完成数据库的写操作(又是折腾许久:))。