项目中要用到webservice,刚听到的时候还挺开心的,因为我之前接触过,想来应该不是很难,。
谁料,事实不是这样的....,让我费了个好劲啊。
不说了,下面上代码,这是入门级的,所以会比较详细,仔细看:
服务器端:
1、接口+实现类
//接口 package com.ekservice.service; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import com.ek.entry.user.User; /** * @author Administrator * 类说明 */ @WebService(targetNamespace="http://jeeek-dp/", name="ExampleService") public interface ExampleService { @WebResult(name="password") @WebMethod(action="http://jeeek-dp/ExampleService/getStr") public User getStr(@WebParam(name="name")String userName); }
//实现类 package com.ekservice.impl; import javax.jws.WebService; import com.ek.entry.user.User; import com.ekservice.service.ExampleService; /** * @author Administrator * 类说明 */ @WebService(targetNamespace="http://jeeek-dp/", serviceName="ExampleService", name="ExampleService") public class ExampleServiceImpl implements ExampleService { public User getStr(String userName) { User user = new User(); user.setAddress("北京市海淀区222号"); user.setMobilePhone("010-1101111"); return user; } }
2、WS-Security 安全验证 - 过滤器
package com.ekservice.interceptor; import java.io.IOException; import java.util.HashMap; import java.util.Map; 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 org.apache.ws.security.WSSecurityException; /** * @author Administrator * 类说明 */ public class ExampleServiceInterceptor implements CallbackHandler{ private Map<String, String> passwords = new HashMap<String, String>(); public ExampleServiceInterceptor() { passwords.put("admin", "password");//此处的对应的是验证信息-用户名+密码,必须与客户端一致才可验证通过 } 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();//验证方式 if (usage == WSPasswordCallback.USERNAME_TOKEN) {// 密钥方式USERNAME_TOKEN if (!passwords.containsKey(identifier)) { try { throw new WSSecurityException("User not match - "+identifier); } catch (WSSecurityException e) { e.printStackTrace(); } } // username token pwd... // ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同 // 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime // Changes片段 pc.setPassword(passwords.get(identifier));// ▲【这里非常重要】▲ // ▲PS 如果和客户端不同将抛出org.apache.ws.security.WSSecurityException: // The // security token could not be authenticated or // authorized异常,服务端会认为客户端为非法调用 }else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE if (!passwords.containsKey(identifier)) { try { throw new WSSecurityException("User not match - "+identifier); } catch (WSSecurityException e) { e.printStackTrace(); } } // set the password for client's keystore.keyPassword // ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同; // 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime // Changes片段 pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲ // ▲PS:如果和客户端不同将抛出org.apache.ws.security.WSSecurityException:The // security token could not be authenticated or // authorized异常,服务端会认为客户端为非法调用 } } } }
3、Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:/META-INF/cxf/cxf.xml" /> <import resource="classpath:/META-INF/cxf/cxf-servlet.xml" /> <import resource="classpath:/META-INF/cxf/cxf-extension-soap.xml" /> <!-- 安全验证过滤器 --> <bean id="exampleServiceInterceptor" class="com.ekservice.interceptor.ExampleServiceInterceptor"></bean> <!-- 接口实现类 --> <bean id="exampleServiceImpl" class="com.ekservice.impl.ExampleServiceImpl" /> <!-- 发布接口 spring+cxf --> <jaxws:endpoint implementor="#exampleServiceImpl" address="/ExampleService"> <!-- 为接口添加安全验证过滤器 --> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" /> <!-- 这个地方不知道为什么,浪费了我宝贵的时间,官方文档说CXF2.0.x需要加这个过滤器,2.1.x及以后版本可以不加, 但是我用的是CXF2.7.7不加SAAJInInterceptor过滤器报错--> <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" /> <bean id="WSS4JInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken"></entry> <entry key="passwordType" value="PasswordText"></entry> <!-- 设置密码类型为加密 <entry key="passwordType" value="PasswordDigest" /> --> <entry key="passwordCallbackClass" value="com.ekservice.interceptor.ExampleServiceInterceptor"></entry> </map> </constructor-arg> </bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> </jaxws:outInterceptors> </jaxws:endpoint> </beans>
4、User.java
package com.ek.entry.user; import java.io.Serializable; import java.util.Date; /** * @包名 ek.entry.user.po * @文件名 User.java * @版本 V 1.0 */ public class User implements Serializable{ private static final long serialVersionUID = 1L; private int id; private String userName; //用户名 private String passWord; //密码 private String address; private String mobilePhone; private Date entryTime; //录入时间 private Date updateTime; //更新时间 private String entryUserId; //录入人ID private String validFlag; //有效标识 private Integer access; /** * @return the userName */ public String getUserName() { return userName; } /** * @param userName the userName to set */ public void setUserName(String userName) { this.userName = userName; } /** * @return the passWord */ public String getPassWord() { return passWord; } /** * @param passWord the passWord to set */ public void setPassWord(String passWord) { this.passWord = passWord; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getMobilePhone() { return mobilePhone; } public void setMobilePhone(String mobilePhone) { this.mobilePhone = mobilePhone; } public static long getSerialversionuid() { return serialVersionUID; } /** * @return the entryTime */ public Date getEntryTime() { return entryTime; } /** * @param entryTime the entryTime to set */ public void setEntryTime(Date entryTime) { this.entryTime = entryTime; } /** * @return the updateTime */ public Date getUpdateTime() { return updateTime; } /** * @param updateTime the updateTime to set */ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } /** * @return the entryUserId */ public String getEntryUserId() { return entryUserId; } /** * @param entryUserId the entryUserId to set */ public void setEntryUserId(String entryUserId) { this.entryUserId = entryUserId; } /** * @return the validFlag */ public String getValidFlag() { return validFlag; } /** * @param validFlag the validFlag to set */ public void setValidFlag(String validFlag) { this.validFlag = validFlag; } /** * @return the id */ public int getId() { return id; } /** * @param id the id to set */ public void setId(int id) { this.id = id; } public User() { super(); this.entryTime = new Date(); this.updateTime = new Date(); this.validFlag = "1"; } /** * @return the access */ public Integer getAccess() { return access; } /** * @param access the access to set */ public void setAccess(Integer access) { this.access = access; } }
至此,服务器端开发完成,启动tomcat即可访问接口,http://localhost:8080/jeeek-dp/services/ExampleService?wsdl
客户端:
1、使用wsdl2java命令生成客户端代码,只保留生成的javabean跟接口即可,其他的文件可以全部删去,,我留下的文件。
2、编写客户端接口访问验证拦截器,只要确保用户名密码与服务器相同即可(我的理解),代码:
package com.ek.client.interceptor; import java.io.IOException; import java.util.HashMap; import java.util.Map; 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 org.apache.ws.security.WSSecurityException; /** * @author * 类说明 */ public class ExampleServiceClientInterceptor implements CallbackHandler{ private Map<String, String> passwords = new HashMap<String, String>(); public ExampleServiceClientInterceptor() { passwords.put("admin", "password"); } 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(); if (usage == WSPasswordCallback.USERNAME_TOKEN) {// 密钥方式USERNAME_TOKEN System.out.println(passwords.containsKey(identifier)+"="+passwords.get(identifier)+"-"+identifier); if (!passwords.containsKey(identifier)) { try { throw new WSSecurityException("User not match - "+identifier); } catch (WSSecurityException e) { e.printStackTrace(); } } pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲ }else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE if (!passwords.containsKey(identifier)) { try { throw new WSSecurityException("User not match - "+identifier); } catch (WSSecurityException e) { e.printStackTrace(); } } pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲ } } } }
3、客户端配置文件
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <bean id="exampleServiceClientInterceptor" class="com.ek.client.interceptor.ExampleServiceClientInterceptor"></bean> <jaxws:client id="service" address="http://localhost:8080/jeeek-dp/services/ExampleService" serviceClass="com.ek.client.services.example.ExampleService"> <jaxws:outInterceptors> <bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"></bean> <bean id="WSS4JOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken" /> <entry key="passwordType" value="PasswordText" /> <entry key="user" value="admin" /> <!-- <entry key="mustUnderstand" value="false"></entry> --> <entry key="passwordCallbackRef"> <ref bean="exampleServiceClientInterceptor" /> </entry> </map> </constructor-arg> </bean> </jaxws:outInterceptors> </jaxws:client> </beans>
4、客户端调用接口:
package com.ek.client.call; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.ek.client.services.example.ExampleService; import com.ek.client.services.example.User; /** * @author * 类说明 */ public class ExampleServiceClient { public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cxf-client.xml"); ExampleService es = (ExampleService) ctx.getBean("service"); User u = es.getStr("ssss"); System.out.println(u.getAddress); } }
整个项目的包目录结构就不截图了,配置文件新建个src 文件放到里面即可,也可以直接放到src目录下。
因为整这个东西费了很多时间,坐下记录。
共勉!
时间: 2024-10-14 01:31:30