WebService学习——回顾之前应用
2014-12-30 14:02
393 查看
回顾之前项目的应用——Cxf在spring框架中的简单运用
之前项目需要用到WebService,但是由于项目开发的快节奏,所以虽然把他搭起来,但是没有了解他的原理。1 准备工作
cxf核心包(cxf-2.4.1.jar)、wss4j(安全模块)、spring包。其他包如
commons-logging-1.1.1.jar geronimo-activation_1.1_spec-1.0.2.jar (or Sun's Activation jar) geronimo-annotation_1.0_spec-1.1.1.jar (JSR 250) geronimo-javamail_1.4_spec-1.6.jar (or Sun's JavaMail jar) geronimo-servlet_2.5_spec-1.2.jar (or Sun's Servlet jar) geronimo-ws-metadata_2.0_spec-1.1.2.jar (JSR 181) geronimo-jaxws_2.1_spec-1.0.jar (or Sun's jaxws-api-2.1.jar) geronimo-stax-api_1.0_spec-1.0.1.jar (or other stax-api jar) jaxb-api-2.1.jar jaxb-impl-2.1.12.jar jetty-6.1.21.jar jetty-util-6.1.21.jar neethi-2.0.4.jar saaj-api-1.3.jar saaj-impl-1.3.2.jar wsdl4j-1.6.2.jar wstx-asl-3.2.8.jar XmlSchema-1.4.5.jar xml-resolver-1.2.jar
如果使用的Maven,需要注意了,Maven仓库中下不到cxf的包。
2 配置web.xml
<!-- 配置CXFServlet --> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping>
3 spring整合cxf
在spring配置文件之一applicationContext.xml中,加入:<!-- 引入CXF Bean定义如下 --> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
如果你需要自定义返回的信息,为了目录清除编写一个wssec.xml,然后import进你的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:cxf="http://cxf.apache.org/core" xmlns:wsa="http://cxf.apache.org/ws/addressing" xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:wsrm-policy="http://schemas.xmlsoap.org/ws/2005/02/rm/policy" xmlns:wsrm-mgr="http://cxf.apache.org/ws/rm/manager" xsi:schemaLocation=" http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd http://schemas.xmlsoap.org/ws/2005/02/rm/policy http://schemas.xmlsoap.org/ws/2005/02/rm/wsrm-policy.xsd http://cxf.apache.org/ws/rm/manager http://cxf.apache.org/schemas/configuration/wsrm-manager.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <cxf:bus> <cxf:features> <cxf:logging /> <wsa:addressing /> </cxf:features> </cxf:bus> </beans>
spring配置文件 beans.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- Spring配置文件 --> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans default-lazy-init="false" default-dependency-check="none" default-autowire="no"> <import resource="applicationContext.xml" /> <import resource="applicationContext-aop.xml" /> <import resource="applicationContext-webService.xml" /> <import resource="applicationContext-Quartz.xml" /> <import resource="wssec.xml"></import> </beans>
4 编写客户端
WsClinetAuthHandler.javapackage com.interfaces.utils; import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback; /** * 用一句话描述功能 * @author lzy * @date(开发日期) 2014-9-9下午10:00:51 */ public class WsClinetAuthHandler implements CallbackHandler { public static String userAcc; public static String password; public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback) callbacks[i]; System.out.println("identifier: " + pc.getIdentifier()); // 这里必须设置密码,否则会抛出:java.lang.IllegalArgumentException: pwd == null // but a password is needed pc.setPassword(password);// ▲【这里必须设置密码】▲ } } public static String getUserAcc() { return userAcc; } public static void setUserAcc(String userAcc) { WsClinetAuthHandler.userAcc = userAcc; } public static String getPassword() { return password; } public static void setPassword(String password) { WsClinetAuthHandler.password = password; } }
JaxBeansFactory.java
package com.interfaces.utils; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.apache.cxf.binding.soap.interceptor.SoapInterceptor; import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor; import org.apache.ws.security.WSConstants; import org.apache.ws.security.handler.WSHandlerConstants; import com.saleSystem.util.Constants; /** * 通过传入相应的接口类,以及地址,进行数据通信 * @author lzy * @version Ver1.0 2014-8-12 * @date(开发日期) 2014-8-12上午11:39:40 */ public class JaxBeansFactory { public static String userName; public static void setUserAccAndPaswword(String userAcc,String password){ WsClinetAuthHandler.setPassword(password); setUserName(userAcc); } public static Object createService(Class T,String Address){ Object obj = null; Map<String, Object> outProps = new HashMap<String, Object>(); outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN); outProps.put(WSHandlerConstants.USER,userName); outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT); // 指定在调用远程ws之前触发的回调函数WsClinetAuthHandler,其实类似于一个拦截器 outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, WsClinetAuthHandler.class.getName()); ArrayList<SoapInterceptor> list = new ArrayList<SoapInterceptor>(); // 添加cxf安全验证拦截器,必须 list.add(new SAAJOutInterceptor()); list.add(new WSS4JOutInterceptor(outProps)); JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(T); factory.setAddress(Address); factory.getOutInterceptors().addAll(list); obj = factory.create(); return obj; } public static String getUserName() { return userName; } public static void setUserName(String userName) { JaxBeansFactory.userName = userName; } }
ISaleTerReceive.java
package com.interfaces.saleSystem.services; import java.util.List; import javax.jws.WebService; import com.interfaces.saleSystem.models.DownloadDatas; /** * 用一句话描述功能 * @author lzy * @version Ver1.0 2014-8-8 * @date(开发日期) 2014-8-8上午10:05:13 */ @WebService public interface ISaleTerReceive { public DownloadDatas receivePorkResults(String[] porkIds); public DownloadDatas receivePorkPdtResults(String[] porkPdtIds); }
5 编写服务器端
WsAuthHandler.javapackage com.interfaces.utils; import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback; import com.centrySystem.util.JDBCCon; /** * 用一句话描述功能 * * @author lzy * @date(开发日期) 2014-9-9下午10:16:38 */ public class WsAuthHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback) callbacks[i]; String identifier = pc.getIdentifier(); int usage = pc.getUsage(); String password = this.getPasswordByUserAcc(identifier); if (usage == WSPasswordCallback.USERNAME_TOKEN) { // username token pwd... // ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同 // 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime // Changes片段 pc.setPassword(password);// ▲【这里非常重要】▲ // ▲PS 如果和客户端不同将抛出org.apache.ws.security.WSSecurityException: // The // security token could not be authenticated or // authorized异常,服务端会认为客户端为非法调用 } else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE // set the password for client's keystore.keyPassword // ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同; // 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime // Changes片段 // System.out.println(password); pc.setPassword(password);// ▲【这里非常重要】▲ // ▲PS:如果和客户端不同将抛出org.apache.ws.security.WSSecurityException:The // security token could not be authenticated or // authorized异常,服务端会认为客户端为非法调用 } // 不用做其他操作 } } private String getPasswordByUserAcc(String userAcc) { JDBCCon con = new JDBCCon(); String password = con.getPasswordByUserName(userAcc); return password; } }
private String getPasswordByUserAcc(String userAcc) { JDBCCon con = new JDBCCon(); String password = con.getPasswordByUserName(userAcc); return password; }
这里,我写了一个JDBC的连接,来验证客服端传过来的用户名密码是否正确,即验证他是否是我服务端的合法用户,如果是合法用户,我再提供给他服务。
SaleTerReceiveImpl.java
/** * ISaleTerSendImpl.java * 类名: ISaleTerSendImpl * * ver 变更日 变更人 变更内容 * ────────────────────────────────── * V1.0 2014-8-8 lzy 初始生成 * * Copyright 2014 */ package com.interfaces.saleSystem.services.impl; import java.util.ArrayList; import java.util.List; import javax.annotation.Resource; import javax.jws.WebService; import com.centrySystem.services.government.warning.IPorkPdtWarningService; import com.centrySystem.services.government.warning.IPorkWarningService; import com.centrySystem.util.TypeInCenterUtil; import com.interfaces.saleSystem.models.DownloadDatas; import com.interfaces.saleSystem.models.PorkPdtWarningResult; import com.interfaces.saleSystem.models.PorkWarningResult; import com.interfaces.saleSystem.services.ISaleTerReceive; /** * 用一句话描述功能 * * @author lzy * @version Ver1.0 2014-8-8 * @date(开发日期) 2014-8-8上午10:05:38 */ @WebService public class SaleTerReceiveImpl implements ISaleTerReceive { @Resource private IPorkWarningService porkWarningSer; @Resource private IPorkPdtWarningService porkPdtWarningSer; @Override public DownloadDatas receivePorkResults(String[] porkIds) { List<PorkWarningResult> list = new ArrayList<PorkWarningResult>(); for (String porkId : porkIds) { PorkWarningResult pork = new PorkWarningResult(); pork.setPorkId(porkId); pork = this.porkStartInStorWarning(porkId, pork); list.add(pork); } DownloadDatas datas = new DownloadDatas(); datas.setPorkWarningResults(list); return datas; } private PorkWarningResult porkStartInStorWarning(String porkId, PorkWarningResult pork) { String result = porkWarningSer.getPorkWarningResult(porkId); if(result==null||result.equals("")){ pork.setIsRejection(TypeInCenterUtil.TYPE_OF_WARNING_ACCESS); } else{ pork.setIsRejection(TypeInCenterUtil.TYPE_OF_WARNING_REJECT); pork.setResultReason(result); } return pork; } private PorkPdtWarningResult porkPdtStartInStorWarning(String porkPdtId, PorkPdtWarningResult porkPdt) { String result = porkPdtWarningSer.getPorkPdtWarningResult(porkPdtId); if(result==null||result.equals("")){ porkPdt.setIsRejection(TypeInCenterUtil.TYPE_OF_WARNING_ACCESS); } else{ porkPdt.setIsRejection(TypeInCenterUtil.TYPE_OF_WARNING_REJECT); porkPdt.setResultReason(result); } return porkPdt; } @Override public DownloadDatas receivePorkPdtResults(String[] porkPdtIds) { List<PorkPdtWarningResult> list = new ArrayList<PorkPdtWarningResult>(); for (String porkPdtId : porkPdtIds) { PorkPdtWarningResult porkPdt = new PorkPdtWarningResult(); porkPdt.setPorkPdtId(porkPdtId); porkPdt = this.porkPdtStartInStorWarning(porkPdtId, porkPdt); list.add(porkPdt); } DownloadDatas datas = new DownloadDatas(); datas.setPorkPdtWarningResults(list); return datas; } }
服务器端,除了有客户端相同ISaleTerReceive接口外,还实现了这个接口。
服务端发布服务 applicationContext-webService.xml
<?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:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.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://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- 引入CXF Bean定义如下 --> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <!-- 发布webservice --> <bean id="saleTerReceiveImpl" class="com.interfaces.saleSystem.services.impl.SaleTerReceiveImpl" ></bean> <jaxws:endpoint id="saleTerReceive" implementor="#saleTerReceiveImpl" address="/saleTerReceive"> <jaxws:inInterceptors> <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" /> <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"> <constructor-arg> <map> <!-- 设置加密类型 --> <entry key="action" value="UsernameToken" /> <!-- 设置密码类型为明文 --> <entry key="passwordType" value="PasswordText" /> <!--<entry key="action" value="UsernameToken Timestamp" /> 设置密码类型为加密<entry key="passwordType" value="PasswordDigest" /> --> <entry key="passwordCallbackClass" value="com.interfaces.utils.WsAuthHandler" /> </map> </constructor-arg> </bean> </jaxws:inInterceptors> </jaxws:endpoint> </beans>
6.客户端调用
InStorWarningAction.javapackage com.interfaces.action; import javax.annotation.Resource; import org.springframework.stereotype.Component; import com.interfaces.saleSystem.models.DownloadDatas; import com.interfaces.saleSystem.services.ISaleTerReceive; import com.interfaces.utils.JaxBeansFactory; import com.saleSystem.dao.systemManag.ISysConfigDao; import com.saleSystem.models.TSysConfig; import com.saleSystem.services.upload.IUploadService; import com.saleSystem.util.md5.CipherUtil; @Component("instorWarningAction") public class InStorWarningAction { @Resource private ISysConfigDao sysConfigDao; @Resource private IUploadService uploadSer; public DownloadDatas getDownloadDatasByPorkIdList(String[] porkIdStr) throws Exception { DownloadDatas datas = null; TSysConfig sys = sysConfigDao.get("from TSysConfig"); String userAcc = sys.getUserAcc(); String password = sys.getUserPassword(); String ip = sys.getServerIp(); String serviceAdd = "http://" + ip + ":8080/centrySystem/service/saleTerReceive?wsdl"; String newPassword = CipherUtil.generatePassword(password); JaxBeansFactory.setUserAccAndPaswword(userAcc, newPassword); ISaleTerReceive service = (ISaleTerReceive) JaxBeansFactory.createService(ISaleTerReceive.class, serviceAdd); datas = service.receivePorkResults(porkIdStr); return datas; } public DownloadDatas getDownloadDatasByPorkPdtIdList(String[] porkPdtIdStr) throws Exception { DownloadDatas datas = null; TSysConfig sys = sysConfigDao.get("from TSysConfig"); String userAcc = sys.getUserAcc(); String password = sys.getUserPassword(); String ip = sys.getServerIp(); String serviceAdd = "http://" + ip + ":8080/centrySystem/service/saleTerReceive?wsdl"; String newPassword = CipherUtil.generatePassword(password); JaxBeansFactory.setUserAccAndPaswword(userAcc, newPassword); ISaleTerReceive service = (ISaleTerReceive) JaxBeansFactory.createService(ISaleTerReceive.class, serviceAdd); datas = service.receivePorkPdtResults(porkPdtIdStr); return datas; } }
这是项目中一个调用的地方。
其中CipherUtil.generatePassword(password)是MD5加密,这第一是为了防止密码被窃取,第二是由于在服务端数据库中密码也是加密的。
JaxBeansFactory.setUserAccAndPassword(userAcc,newPassword)这是将账号密码填入账号密码。
datas是返回的数据,是自己定义的类型。
很重要的一点,客户端和服务器端在通信的时候,使用的model,需要一样。即你返回的DownloadDatas在你客户端与服务器端的定义是相同的!
请忽视我将hql写在action里面.....
上面使用的例子中,还有很多是我之前囫囵吞枣就使用进去的,我希望通过几天学习能把webSevice真正的用起来!
相关文章推荐
- 【WCF学习随笔二】第一个WebService应用。
- 数据库的学习和之前不熟悉的知识点回顾
- 101与金根回顾敏捷个人:(97)通过实践TOGAF来思考如何学习并应用新的方法?
- CCF ADL 78 深度学习讲习班回顾:这几个大热领域的算法到应用,8位学术大牛带你掌握人工智能前沿技术
- java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)
- JSP学习笔记(一百二十三):使用axis1.4开发webservice应用(二)
- Web Services 应用开发学习笔记(五):创建WebService的简单例子
- JSP学习笔记(一百二十二):使用axis1.4开发webservice应用(一)
- 执行数据库命令(Command对象)——ADO.NET学习&应用笔记之三
- javascript中正则表达式应用学习_Split()
- javascript中正则表达式应用学习_match()
- 浅析WebService客户端应用方法
- 在WEBSERVICE学习中遇到的问题
- unix并发技术的学习及在扫描器上的应用二
- webservice.htc 应用
- javascript中正则表达式应用学习_search ()
- 学习Internet Explorer之前需要掌握的一些知识
- 学习Struts(3)-配置Struts应用
- oracle分区表学习及应用
- unix并发技术的学习及在扫描器上的应用一