springBoot整合CXF並實現使用者名稱密碼校驗
阿新 • • 發佈:2019-01-05
話不多說直接上程式碼:
準備工作:
建立springBoot專案webservice_server
建立springBoot專案webservice_client
分別新增CXF的依賴:
<!-- CXF webservice --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version>3.1.11</version> </dependency> <!-- CXF webservice -->
一.定義要釋出的介面和實現類
介面:
@WebService public interface AppService { @WebMethod String getUserName(@WebParam(name = "id") String id) throws UnsupportedEncodingException; @WebMethod public User getUser(String id) throws UnsupportedEncodingException; }
實現類:
//name暴露的服務名稱, targetNamespace:名稱空間,設定為介面的包名倒寫(預設是本類包名倒寫). endpointInterface介面地址 @WebService(name = "test" ,targetNamespace ="http://cxf.wolfcode.cn/" ,endpointInterface = "cn.wolfcode.cxf.AppService") public class AppServiceImpl implements AppService { JSONResult jsonResult = JSONResult.getJsonResult(); @Overridepublic String getUserName(String id) throws UnsupportedEncodingException { System.out.println("==========================="+id); JSONResult result= JSONResult.getJsonResult(); result.setSuccess(true); result.setMessage("明哥"); return result.toJsonObject(); } @Override public User getUser(String id)throws UnsupportedEncodingException { System.out.println("==========================="+id); return new User(1L,"明哥"); } }
二.釋出服務
1.定義配置類
@Configuration public class CxfConfig { //預設servlet路徑/*,如果覆寫則按照自己定義的來 @Bean public ServletRegistrationBean dispatcherServlet() { return new ServletRegistrationBean(new CXFServlet(), "/services/*"); } @Bean(name = Bus.DEFAULT_BUS_ID) public SpringBus springBus() { return new SpringBus(); } //把實現類交給spring管理 @Bean public AppService appService() { return new AppServiceImpl(); } //終端路徑 @Bean public Endpoint endpoint() { EndpointImpl endpoint = new EndpointImpl(springBus(), appService()); endpoint.getInInterceptors().add(new AuthInterceptor());//新增校驗攔截器 endpoint.publish("/user"); return endpoint; } }
2.釋出服務
@SpringBootApplication public class WebserviceApplication { public static void main(String[] args) { SpringApplication.run(WebserviceApplication.class, args); } }
因為我添加了使用者名稱和密碼校驗所以在釋出之前還需要定義自己校驗使用者名稱和密碼的Interceptor
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> { Logger logger = LoggerFactory.getLogger(this.getClass()); private static final String USERNAME="root"; private static final String PASSWORD="admin"; public AuthInterceptor() { //定義在哪個階段進行攔截 super(Phase.PRE_PROTOCOL); } @Override public void handleMessage(SoapMessage soapMessage) throws Fault { List<Header> headers = null; String username=null; String password=null; try { headers = soapMessage.getHeaders(); } catch (Exception e) { logger.error("getSOAPHeader error: {}",e.getMessage(),e); } if (headers == null) { throw new Fault(new IllegalArgumentException("找不到Header,無法驗證使用者資訊")); } //獲取使用者名稱,密碼 for (Header header : headers) { SoapHeader soapHeader = (SoapHeader) header; Element e = (Element) soapHeader.getObject(); NodeList usernameNode = e.getElementsByTagName("username"); NodeList pwdNode = e.getElementsByTagName("password"); username=usernameNode.item(0).getTextContent(); password=pwdNode.item(0).getTextContent(); if( StringUtils.isEmpty(username)||StringUtils.isEmpty(password)){ throw new Fault(new IllegalArgumentException("使用者資訊為空")); } } //校驗使用者名稱密碼 if(!(username.equals(USERNAME) && password.equals(PASSWORD))){ SOAPException soapExc = new SOAPException("認證失敗"); logger.debug("使用者認證資訊錯誤"); throw new Fault(soapExc); } } }
現在可以釋出服務了.....
釋出完成後訪問http://localhost:8888/services/user?wsdl
能夠出現以下介面就是釋出OK
三.呼叫服務
1.新建呼叫端專案,新增依賴
2.因為示例演示了兩種呼叫方式,其中一種需要用到介面,所以先把服務介面拷貝一份到呼叫端專案中(程式碼就是上面介面的程式碼)
3.因為服務端添加了使用者名稱密碼校驗,所以呼叫的時候需要新增使用者名稱密碼資訊, 所以需要使用下面的Interceptor完成新增使用者名稱密碼資訊
/** * Created by sky on 2018/2/27. */ public class LoginInterceptor extends AbstractPhaseInterceptor<SoapMessage> { private String username="root"; private String password="admin"; public LoginInterceptor(String username, String password) { //設定在傳送請求前階段進行攔截 super(Phase.PREPARE_SEND); this.username=username; this.password=password; } @Override public void handleMessage(SoapMessage soapMessage) throws Fault { List<Header> headers = soapMessage.getHeaders(); Document doc = DOMUtils.createDocument(); Element auth = doc.createElementNS("http://cxf.wolfcode.cn/","SecurityHeader"); Element UserName = doc.createElement("username"); Element UserPass = doc.createElement("password"); UserName.setTextContent(username); UserPass.setTextContent(password); auth.appendChild(UserName); auth.appendChild(UserPass); headers.add(0, new Header(new QName("SecurityHeader"),auth)); } }
4.呼叫介面
/** * Created by sky on 2018/2/27. */ public class Cxfclient { //webservice介面地址 private static String address = "http://localhost:8888/services/user?wsdl"; //測試 public static void main(String[] args) { test1(); test2(); } /** * 方式1:使用代理類工廠,需要拿到對方的介面 */ public static void test1() { try { // 代理工廠 JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean(); // 設定代理地址 jaxWsProxyFactoryBean.setAddress(address); //新增使用者名稱密碼攔截器 jaxWsProxyFactoryBean.getOutInterceptors().add(new LoginInterceptor("root","admin"));; // 設定介面型別 jaxWsProxyFactoryBean.setServiceClass(AppService.class); // 建立一個代理介面實現 AppService cs = (AppService) jaxWsProxyFactoryBean.create(); // 資料準備 String LineId = "1"; // 呼叫代理介面的方法呼叫並返回結果 User result = (User)cs.getUser(LineId); System.out.println("==============返回結果:" + result); } catch (Exception e) { e.printStackTrace(); } } /** * 動態呼叫方式 */ public static void test2() { // 建立動態客戶端 JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient(address); // 需要密碼的情況需要加上使用者名稱和密碼 client.getOutInterceptors().add(new LoginInterceptor("root","admin")); Object[] objects = new Object[0]; try { // invoke("方法名",引數1,引數2,引數3....); System.out.println("======client"+client); objects = client.invoke("getUserName", "1"); System.out.println("返回資料:" + objects[0]); } catch (Exception e) { e.printStackTrace(); } } }
嗯...總體上就是這麼簡單, 演示程式碼可以去這裡下載:http://download.csdn.net/download/weixin_41138656/10262143