原始js,访问WebService会存在跨域无法访问的问题,可以使用ajax请求一个Servlet,在Servlet使用HttpURLConnection放问WebService,解决ajax直接访问WebService带来的跨域问题。
一 js下的ajax访问WebService
服务器端
先导入cxf的包。
自定义拦截器(不需要不用加)
package ws.server.interceptor; import javax.xml.namespace.QName; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.headers.Header; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.w3c.dom.Element; /** * 检查用户名称和密码 * @author * */ public class MyServerInterceptor extends AbstractPhaseInterceptor<SoapMessage> { public MyServerInterceptor() { super(Phase.PRE_PROTOCOL); // TODO Auto-generated constructor stub } @Override public void handleMessage(SoapMessage msg) throws Fault { // 读header里的数据 Header header=msg.getHeader(new QName("atguigu"));//参数和客户端传的一样 if(header!=null){ Element atguigu=(Element) header.getObject(); String name=atguigu.getElementsByTagName("name").item(0).getTextContent(); String pwd=atguigu.getElementsByTagName("pwd").item(0).getTextContent(); System.out.println("name|pwd:::::::::::::::::::::::::::::::::::"+name+"|"+pwd); if(name.equals("zhangsan")&&pwd.equals("123")){ System.out.println("server:check ok"); return; } } //没通过校验,抛出异常 System.out.println("没有通过校验-------------------------------------------"); throw new Fault(new RuntimeException("用户名或密码不对")); } }
UserBean.java
package ws.spring.server; public class UserBean { private int id; private String name; public UserBean(int id, String name) { super(); this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "UserBean [id=" + id + ", name=" + name + "]"; } }
SEI接口
package ws.spring.server; import javax.jws.WebMethod; import javax.jws.WebService; @WebService public interface UserWS { @WebMethod public UserBean getUserById(int id); }
接口实现
package ws.spring.server; import javax.jws.WebService; @WebService public class UserWSImpl implements UserWS { public UserWSImpl(){ System.out.println("初始化 UserWSImpl"); } @Override public UserBean getUserById(int id) { System.out.println("server getUserById:"+id); return new UserBean(1, "张三"); } }
cxf框架的配置(beans.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/jaxws"> <!-- 引cxf的一些核心配置 --> <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" /> <jaxws:endpoint id="userWS" implementor="ws.spring.server.UserWSImpl" address="/userws"> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> <bean class="ws.server.interceptor.MyServerInterceptor"></bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:outInterceptors> </jaxws:endpoint> </beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>ws_ajax_server</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
客户端:
导入jar包;
生成客户端代码:
GetUserById.java
GetUserByIdResponse.java
ObjectFactory.java
package-info.java
UserBean.java
UserWS.java
UserWSImplService.java
自定义的客户端拦截器:
package ws.client.interceptor; import java.util.List; import javax.xml.namespace.QName; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.headers.Header; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.apache.xml.utils.DOMHelper; import org.w3c.dom.Document; import org.w3c.dom.Element; public class MyClientInterceptor extends AbstractPhaseInterceptor<SoapMessage> { //自定义的校验字段,姓名和密码 private String name; private String pwd; public MyClientInterceptor(String name,String pwd) { super(Phase.PRE_PROTOCOL);//配置拦截时机,一定要有,准备协议化得时候拦截 this.name=name; this.pwd=pwd; } //封装数据到消息里,格式如下 /* <Envelop> * <head> //里面的标签可以有多个 * <atguigu> //自定义标签,随意 * <name>zhangsan</name> * <pwd>123123</pwd> * </atguigu> * <atguigu1> //自定义标签,随意 * <name>zhangsan</name> * <pwd>123123</pwd> * </atguigu1> * </head> * <body> * <sayHello> * <arg0>BOB</arg0> * </sayHello> * </body> * </Envelop> * * * * * * * * */ @Override public void handleMessage(SoapMessage msg) throws Fault { List<Header> headers=msg.getHeaders(); //创建Head //创建head里的元素,添加到head Document document=DOMHelper.createDocument(); Element atguigu=document.createElement("atguigu"); Element name=document.createElement("name"); name.setTextContent(this.name); atguigu.appendChild(name); Element pwd=document.createElement("pwd"); pwd.setTextContent(this.pwd); atguigu.appendChild(pwd); headers.add(new Header(new QName("atguigu"), atguigu));//QName里的参数要和标签名一样 System.out.println("client:handleMessage"); } }
客户端的配置(client-beans.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/jaxws"> <jaxws:client id="userClient" serviceClass= "ws.spring.server.UserWS" address= "http://localhost:8080/ws_ajax_server/userws"> <!-- 添加客户端出拦截器 --> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"/> <bean class="ws.client.interceptor.MyClientInterceptor"> <constructor-arg name="name" value="zhangsan"/> <constructor-arg name="pwd" value="123"/> </bean> </jaxws:outInterceptors> </jaxws:client> </beans>
jNewFile.sp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Insert title here</title> <script type="text/javascript"> function ajaxFunc(){ var name=document.getElementById("uid").value; var data='<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><atguigu><name>zhangsan</name><pwd>123</pwd></atguigu></soap:Header><soap:Body><ns2:getUserById xmlns:ns2="http://server.spring.ws/"><arg0>'+name+'</arg0></ns2:getUserById></soap:Body></soap:Envelope>'; var req=getxmlHttp(); req.onreadystatechange=function(){ if(req.readyState==4 && req.status==200) { var result=req.responseXML;// 返回xml数据 ,alert(req.responseText);可以以文本形式查看返回xml内容,再解析 // alert(req.responseText); var ret=result.getElementsByTagName("name")[0]; var res=ret.firstChild.data; alert(res); } } req.open("POST","http://localhost:8080/ws_ajax_server/userws"); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); req.send(data); } function HttpURLConnectionFunc(){ var name=document.getElementById("uid").value; var data='<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><atguigu><name>zhangsan</name><pwd>123</pwd></atguigu></soap:Header><soap:Body><ns2:getUserById xmlns:ns2="http://server.spring.ws/"><arg0>'+name+'</arg0></ns2:getUserById></soap:Body></soap:Envelope>'; var req=getxmlHttp(); req.onreadystatechange=function(){ if(req.readyState==4 && req.status==200) { var result=req.responseXML;// 返回xml数据 ,alert(req.responseText);可以以文本形式查看返回xml内容,再解析 var ret=result.getElementsByTagName("name")[0]; var res=ret.firstChild.data; alert(res); } } req.open("POST","HttpURLConnectionServlet"); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); req.send("data="+data); } //XMLHttpRequest function getxmlHttp(){ var xmlHttp = null; try { // Firefox, Opera 8.0+, Safari chrome xmlHttp = new XMLHttpRequest(); } catch (e) { // Internet Explorer try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } } return xmlHttp; } </script> </head> <body> <input type="text" name="uid" id="uid"/> <button onclick="ajaxFunc()" >ajaxBut</button> <button onclick="HttpURLConnectionFunc()" >HttpURLConnectionBut</button> </body> </html>
点击ajaxBut按钮,可以使用ajax请求webService,由于WebService的发布路径是
http://localhost:8080/ws_ajax_server/userws
<span style="white-space:pre"> </span>当我们用http://IP/ws_ajax_client/NewFile.jsp登录页面
请求WebService时候,无法请求,IP 到Localhost存在跨域,虽然都是本机地址,仍是跨域。
但是把Ip换成localhost就可以访问了。
二 解决Ajax不能跨域访问WebService问题:
我们想使用 http://192.168.1.103:8080/ws_ajax_client/NewFile.jsp 和 http://localhost:8080/ws_ajax_client/NewFile.jsp 都能访问WebService,可以先访问本地的Servlet,在Servlet使用HttpURLConnection请求webService.
NewFile.jsp页面中的第二个按钮HttpURLConnectionBUtton就是使用的这种方式,对应的HttpURLConnectionServlet代码如下:
package servlet; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //页面使用ajax把数据提交到这个Servlet,这个Servlet使用HttpServletRequest向WebService发送请求。请求结果返回,再返给页面 public class HttpURLConnectionServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String data=request.getParameter("data"); System.out.println("------------------------------------------------"); System.out.println(data); //获取页面提交的数据 System.out.println("------------------------------------------------"); URL url=new URL("http://localhost:8080/ws_ajax_server/userws"); HttpURLConnection httpUrlConnection=(HttpURLConnection) url.openConnection() ; httpUrlConnection.setDoInput(true); httpUrlConnection.setDoOutput(true); httpUrlConnection.setRequestProperty("Content-type", "text/xml;charset=utf-8"); OutputStream outputStream = httpUrlConnection.getOutputStream(); outputStream.write(data.getBytes("UTF-8")); outputStream.flush(); int responseCode = httpUrlConnection.getResponseCode(); if(responseCode==200){ //服务器已成功处理了请求 InputStream inputStream = httpUrlConnection.getInputStream(); response.setContentType("text/xml;charset=utf-8"); ServletOutputStream outputStream2 = response.getOutputStream(); byte[] bs=new byte[1024]; int len=0; while((len=inputStream.read(bs))>0){ outputStream2.write(bs, 0, len); } outputStream2.flush(); outputStream2.close(); inputStream.close(); } outputStream.close(); } }
此时使用Ip跨域访问,点击第二个按钮时候可以正确请求WebService了。