移动API开发-web service-cxf-rest

参考资料


https://blog.csdn.net/u011474078/article/details/81427579
https://www.cnblogs.com/xdp-gacl/category/629559.html

概述


	WebService是一种跨编程语言和跨操作系统平台的远程调用技术。

WebService是什么?

基于Web的服务:服务器端整出一些资源让客户端应用访问(获取数据)
一个跨语言、跨平台的规范(抽象)
多个跨平台、跨语言的应用间通信整合的方案(实际)
为什么要用Web service?

web service能解决:

跨平台调用
跨语言调用
远程调用

什么时候使用web Service?

同一家公司的新旧应用之间
不同公司的应用之间
一些提供数据的内容聚合应用:天气预报、股票行情
适用场合
1、跨防火墙通信
2、应用程序集成
3、B2B集
4、软件和数据重用
不适用场合
1、单机应用程序
2、局域网的同构应用程序

WebService三个要素:SOAP, WSDL,UDDI
WebService采用HTTP协议传输数据,采用XML格式封装数据。
WebService务器端首先要通过一个WSDL文件来说明自己家里有啥服务可以对外调用,服务是什么(服务中有哪些方法,方法接受 的参数是什么,返回值是什么),服务的网络地址用哪个url地址表示,服务通过什么方式来调用。

辨析:HttpClient和WebService的区别和介绍:前者基于http协议,相当于模拟浏览器,后者基于soap协议,通过xml来交互数据。

 

WebService开发


WebService开发可以分为服务器端开发和客户端开发两个方面

服务端开发

 把公司内部系统的业务方法发布成WebService服务,供远程合作单位和个人调用。(借助一些WebService框架可以很轻松地把自己的业务对象发布成WebService服务,Java方面的典型WebService框架包括:axis,xfire,cxf 等,java ee服务器通常也支持发布WebService服务,例如JBoss。)

客户端开发

 调用别人发布的WebService服务,大多数人从事的开发都属于这个方面,例如,调用天气预报WebService服务。(使用厂商的WSDL2Java之类的工具生成静态调用的代理类代码;使用厂商提供的客户端编程API类;使用SUN公司早期标准的jax-rpc开发包;使用 SUN公司最新标准的jax-ws开发包。当然SUN已被ORACLE收购)
WebService 的工作调用原理
 对客户端而言,我们给这各类WebService客户端API传递wsdl文件的url地址,这些API就会创建出底层的代理类,我调用 这些代理,就可以访问到webservice服务。代理类把客户端的方法调用变成soap格式的请求数据再通过HTTP协议发出去,并把接收到的soap 数据变成返回值返回。对服务端而言,各类WebService框架的本质就是一个大大的Servlet,当远程调用客户端给它通过http协议发送过来 soap格式的请求数据时,它分析这个数据,就知道要调用哪个java类的哪个方法,于是去查找或创建这个对象,并调用其方法,再把方法返回的结果包装成 soap格式的数据,通过http响应消息回给客户端。
 

WebService技术框架 -CXF


参考: cxf开发webservice流程 spring与cxf整合

Spring 4 集成Apache CXF开发JAX-RS Web Service(RESTful)(基于http协议)

1.添加cxfjar包依赖

 <dependencies>
        <!-- CXF -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <!-- 如果在tomcat或者其他servlet容器中发布服务,不需要引用cxf-rt-transports-http-jetty -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <!-- End CXF -->
    </dependencies>

      <!--jackson-->
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-jaxrs</artifactId>
            <version>${jackson.version}</version>
        </dependency>

2.web.xml中配置cxf servlet

<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>/ws/*</url-pattern>
  </servlet-mapping>

3.编写Restful接口及接口实现类

@Path("/userwsservice/")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class UserWSService
{

    @Autowired
    private IUserService userService;

    @GET
    @Path("/users/{id}/")
    public User getUser(@PathParam("id") String id)
    {
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("id", id);
        List<User> userList = userService.query(param);

        return userList.size() > 0 ? userList.get(0) : null;
    }

    @POST
    @Path("/users/getall")
    public List<User> getAllUsers()
    {
        List<User> userList = userService.query(new HashMap<String, Object>());
        return userList;
    }

}

4.application.xml中配置cxf命名空间和jaxrs:server
也可以在在WEB-INF文件夹下创建cxf-servlet.xml,然后在里面配置

 <bean id="userWSService" class="cn.edu.hdu.wsdemo.wsservice.UserWSService"></bean>
 <bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />

    <jaxrs:server id="users" address="/apis">
        <jaxrs:serviceBeans>
            <ref bean="userWSService" />
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <ref bean='jsonProvider' />
        </jaxrs:providers>
    </jaxrs:server>

5.验证
执行maven命令:clean tomcat:run
启动成功后,浏览器输入:http://localhost:8080/wsdemo/ws
结果:
在这里插入图片描述
输入:http://localhost:8080/wsdemo/ws/apis?_wadl

6.使用CXF调用restful服务

(1)添加cxf 客户端依赖

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-client</artifactId>
    <version>${cxf.version}</version>
</dependency>

(2)cxf 提供了三种 REST 客户端

第一种:JAX-RS 1.0 时代的客户端

package demo.ws.rest_cxf;
 
import java.util.ArrayList;
import java.util.List;
import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
 
public class JAXRSClient {
 
    public static void main(String[] args) {
        String baseAddress = "http://localhost:8080/ws/rest";
 
        List<Object> providerList = new ArrayList<Object>();
        providerList.add(new JacksonJsonProvider());
 
        ProductService productService =
                            JAXRSClientFactory.create(baseAddress, ProductService.class, providerList);
        List<Product> productList = productService.retrieveAllProducts();
        for (Product product : productList) {
            System.out.println(product);
        }
    }
}

本质是使用 CXF 提供的 org.apache.cxf.jaxrs.client.JAXRSClientFactory 工厂类来创建 ProductService 代理对象,通过代理对象调用目标对象上的方法。客户端同样也需要使用 Provider,此时仍然使用了 Jackson 提供的 org.codehaus.jackson.jaxrs.JacksonJsonProvider。

第二种:JAX-RS 2.0 时代的客户端

package com.test.rest.client;
 
import java.util.List;
 
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
 
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
 
public class Client {
 
	public static void main(String[] args) {
		String baseAddress = "http://localhost:8080/ws/rest";
		JacksonJsonProvider jsonProvider = new JacksonJsonProvider();
		List productList = ClientBuilder.newClient().register(jsonProvider)
				.target(baseAddress).path("/products")
				.request(MediaType.APPLICATION_JSON).get(List.class);
		for (Object product : productList) {
			System.out.println(product);
		}
	}
}

在 JAX-RS 2.0 中提供了一个名为 javax.ws.rs.client.ClientBuilder 的工具类,可用于创建客户端并调用 REST 服务,显然这种方式比前一种要先进,因为在代码中不再依赖 CXF API 了。

如果想返回带有泛型的 List,那么就该使用如下方式。
JAX-RS 2.0 时代带有泛型的客户端

package com.test.rest.client;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
 
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
import org.junit.Test;
 
import com.test.rest.bean.Product;
 
/**
 * 返回带有泛型的数据
 * @author Administrator
 *
 */
public class Client1 {
 
	String baseAddress = "http://localhost:8080/ws/rest";
	JacksonJsonProvider jsonProvider = new JacksonJsonProvider();
	@Test
	public void retrieveAll() {
		List<Product> productList = ClientBuilder.newClient().register(jsonProvider)
				.target(baseAddress).path("/products")
				.request(MediaType.APPLICATION_JSON).get(new GenericType<List<Product>>(){});
		for (Product product : productList) {
			System.out.println(product);
		}
	}
	
	/**
	 * 该方法测试参数查询,
	 * 如果测试表单参数,则需要提交表单
	 */
	@Test
	public void retrieveByName_param(){
		List<Product> productList = ClientBuilder.newClient()
		.register(jsonProvider)
		.target(baseAddress)
		.path("/products/name")
		.queryParam("name", "iphone63")
		.request(MediaType.APPLICATION_JSON)
		.get(new GenericType<List<Product>>(){});
		
		for (Product product : productList) {
			System.out.println(product);
		}
	}
	
	/**
	 * 添加数据
	 */
	@Test
	public void create(){
		Product product = new Product();
		product.setName("iphone7");
		product.setPrice(6000);
		
		Product resultProduct = ClientBuilder.newClient()
		.register(jsonProvider)
		.target(baseAddress)
		.path("/product")
		.request(MediaType.APPLICATION_JSON)
		.post(Entity.entity(product, MediaType.APPLICATION_JSON), new GenericType<Product>(){});
		
		System.out.println(resultProduct);
		
		retrieveAll();
	}
	
	/**
	 * 修改数据1
	 */
	@Test
	public void update(){
		Product product = new Product();
		product.setId(1L);
		product.setName("iphone6s");
		product.setPrice(4000);
		
		Product resultTarget = ClientBuilder.newClient()
		.register(jsonProvider)
		.target(baseAddress)
		.path("/product")
		.request(MediaType.APPLICATION_JSON)
		.put(Entity.entity(product, MediaType.APPLICATION_JSON), new GenericType<Product>(){});
		
		System.out.println(resultTarget);
		
		System.out.println("==================");
		retrieveAll();
	}
	
	/**
	 * 修改数据2
	 */
	@Test
	public void update2(){
		Map<String,Object> fieldParam = new HashMap<>();
		fieldParam.put("name", "ipad mini");
		fieldParam.put("price", 1999);
		
		Product product = ClientBuilder.newClient()
		.register(jsonProvider)
		.target(baseAddress)
		.path("/product/2")
		.request(MediaType.APPLICATION_JSON)
		.put(Entity.entity(fieldParam, MediaType.APPLICATION_JSON), new GenericType<Product>(){});
		System.out.println(product);
		
		System.out.println("===========================");
		
		retrieveAll();
	}
	
	/**
	 * 路径参数
	 * 删除数据:根据id删除
	 */
	@Test
	public void delete(){
		Product product = ClientBuilder.newClient()
		.register(jsonProvider)
		.target(baseAddress)
		.path("/product/1")
		.request(MediaType.APPLICATION_JSON)
		.delete(new GenericType<Product>(){});
		
		System.out.println(product);
		
		System.out.println("===============");
		
		retrieveAll();
	}
	
	/**
	 * 查询参数
	 * 删除数据:根据id删除
	 */
	@Test
	public void delete_param(){
		Product product = ClientBuilder.newClient()
		.register(jsonProvider)
		.target(baseAddress)
		.path("/product")
		.queryParam("id", 2L)
		.request(MediaType.APPLICATION_JSON)
		.delete(new GenericType<Product>(){});
		
		System.out.println(product);
		
		System.out.println("=================");
		
		retrieveAll();
	}
}

第三种:通用的WebClient客户端

package com.test.rest.client;
 
import java.util.ArrayList;
import java.util.List;
 
import javax.ws.rs.core.MediaType;
 
import org.apache.cxf.jaxrs.client.WebClient;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
 
/**
 * 通用客户端WebClient的实现
 * 
 * @author Administrator
 * 
 */
public class Client3 {
 
	public static void main(String[] args) {
		String baseAddress = "http://localhost:8080/ws/rest";
 
		List<Object> providerList = new ArrayList<Object>();
		providerList.add(new JacksonJsonProvider());
 
		List productList = WebClient.create(baseAddress, providerList)
				.path("/products").accept(MediaType.APPLICATION_JSON)
				.get(List.class);
		
		for(Object product : productList){
			System.out.println(product);
		}
	}
}

CXF 还提供了一种更为简洁的方式,使用 org.apache.cxf.jaxrs.client.WebClient 来调用 REST 服务,这种方式在代码层面上还是相当简洁的。
如果想返回带有泛型的 List,那么可以使用以下代码片段:

List<Product> productList = WebClient.create(baseAddress, providerList)
				.path("/products").accept(MediaType.APPLICATION_JSON)
				.get(new GenericType<List<Product>>(){});

 

[spring mvc restful 与cxf restful]

1.Spring MVC 原生支持构建restful web api,就是楼主说的restful web service(严格说来不算web service,不满足web service的三要素)
2.CXF可以实现restful web api,也可以实现传统web service. 但是cxf并不依赖spring mvc/spring
如果已经使用了spring mvc,也已经能够实现restful web api. 如果你需要实现传统ws,可以集成cxf.否则确实没有必要. 如果你不使用spring mvc,也没有一个合适的实现了 restful mvc 实现,可以考虑使用cxf 。

[拓展1-JAX-RS]

采用jAX-RS注解:它是Java提供用于开发RESTful Web服务基于注解(annotation)的API。JAX-RS旨在定义一个统一的规范,使得Java程序员可以使用一套固定的接口来开发REST应用,避免了依赖第三方框架。同时JAX-RS使用POJO编程模型和基于注解的配置并集成JAXB,可以有效缩短REST应用的开发周期。JAX-RS只定义RESTful API,具体实现由第三方提供,如Jersey美[ˈdʒɜ:rzi]、Apache CXF等。
JAX-RS常用注解:
@Path:标注资源类或方法的相对路径。
@GET、@PUT、@POST、@DELETE:标注方法的HTTP请求类型。
@Produces:标注返回的MIME媒体类型。 @Produces({ javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON })
@Consumes:标注可接受请求的MIME媒体类型。
@PathParam、@QueryParam、@HeaderParam、@CookieParam、@MatrixParam、@FormParam:标注方法的参数来自于HTTP请求的位置。@PathParam来自于URL的路径,@QueryParam来自于URL的查询参数,@HeaderParam来自于HTTP请求的头信息,@CookieParam来自于HTTP请求的Cookie。

[扩展2-规范的rest ful接口实例]

转:https://www.cnblogs.com/duanxz/p/3508983.html

/**
 * 图书馆服务
 * 
 */
@Path("/library")
@Produces("text/xml")
public class LibraryService {
    private Map<String, Book> books = new HashMap<String, Book>();

    public LibraryService() {
       // init();
    }

    /**
     * 获取
     * 
     * @param id
     *            索引
     * @return 书
     */
    @GET
    @Path("/books/{id}/")
    public Book getBook(@PathParam("id") String id) {
        return books.get(id);
    }

    /**
     * 更新
     * 
     * @param book
     * @return
     */
    @PUT
    @Path("/books/")
    public Response updateBook(Book book) {
        Response r;
        if (book == null) {
            r = Response.noContent().build();
            return r;
        }

        String id = book.getId();
        Book b = books.get(id);
        if (b != null) {
            books.put(id, book);
            r = Response.ok(true, MediaType.TEXT_PLAIN).build();
        } else {
            r = Response.notModified().build();
        }

        return r;
    }

    /**
     * 添加
     * 
     * @param book
     * @return
     */
    @POST
    @Path("/books/")
    public Response addBook(Book book) {
        Response r;
        if (book == null) {
            r = Response.notModified().build();
        } else {
            books.put(book.getId(), book);
            r = Response.ok(true, MediaType.TEXT_PLAIN).build();
        }

        return r;
    }

    /**
     * 删除
     * 
     * @param book
     * @return
     */
    @DELETE
    @Path("/books/{id}/")
    public Response deleteBook(@PathParam("id") String id) {
        Response r;
        Book book = books.get(id);

        if (book == null) {
            r = Response.notModified("id不存在").build();
        } else {
            books.remove(id);
            r = Response.ok(book, MediaType.APPLICATION_XML).build();
        }

        return r;
    }

    /**
     * 初始化,在图书馆里加几本书
     */
    private void init() {
       

    }

}
[拓展3-spring mvc实现Restful]

参考:前后端分离springmvc和RESTful理解
核心:spring4以前:@ResponseBody spring4.0以后@RestController 编写restful; 处理安全问题,CORS技术

 

Spring 集成Apache CXF开发JAX-WS Web Service(基于soap协议)

参考:https://www.cnblogs.com/xdp-gacl/category/629559.html

开发流程:

1.定义WS终端接口
2.发布WS
3.生成客户端代码调用WS

一、cxf发布服务的类

用两个不同的类发布应用:
  a. ServerFactoryBean – FacotryBean
  b. JaxWsServerFactoryBean(建议使用此类)
服务端与客户端类的使用映射关系如下图所示:

二、使用ServerFactoryBean发布标准的webservice服务

下载cxf安装包apache-cxf-2.4.2,里面lib下jar包以供项目使用。

1.服务端
a.新建web项目,加入cxf的jar包
b.定义webservice的接口

package com.wp.service;
import javax.jws.WebService;
@WebService
public interface HelloWs {
    public String sayHello(String name);
}
c.定义webservice接口的实现类
package com.wp.service;
public class HelloWsImpl implements HelloWs {
    @Override
    public String sayHello(String name) {
        return "hello" + name;
    }
}
d.发布webservice服务
package com.wp.service;
import org.apache.cxf.frontend.ServerFactoryBean;
public class Server {
    public static void main(String[] args) {
        ServerFactoryBean sfb = new ServerFactoryBean();
        //1.服务提供者实现的接口
        sfb.setServiceClass(HelloWs.class);
        //2.指定访问路径
        sfb.setAddress("http://localhost:9090/ws");
        //3.指定服务实现类
        sfb.setServiceBean(new HelloWsImpl());
        //4.发布
        sfb.create();
        System.out.println("发布成功...");
    }
}

2.客户端
a.使用wsdl2java生成客户端代码调用服务

b.使用ClientProxyFactoryBean类调用service服务
  客户端必须加入cxf的jar包
  浏览器访问http://localhost:9090/ws?wsdl ,查看service和operation
  1) 不同项目中调用

  
package com.wp.test;
import com.wp.client.HelloWs;
import com.wp.client.HelloWsPortType;
public class Client {
    public static void main(String[] args) {
        HelloWs hw = new HelloWs();
        HelloWsPortType h = hw.getHelloWsPort();
        String result = h.sayHello("小强");
        System.out.println(result);
    }
}

2) 在同一项目中调用

package com.wp.service;
import org.apache.cxf.frontend.ClientProxyFactoryBean;
public class Client {
    public static void main(String[] args) {
        ClientProxyFactoryBean cfb = new ClientProxyFactoryBean();
        cfb.setAddress("http://localhost:9090/ws");
        cfb.setServiceClass(HelloWs.class);
        HelloWs hw = (HelloWs) cfb.create();
        System.out.println(hw.sayHello("明明"));
    }
}

类似的例子在apache-cxf-2.6.2安装包下的samples中,开发的时候可以查看

三、使用JaxWsServerFactoryBean类发布服务

1.服务端

package com.wp.service;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService
public interface HelloWs {
    public String sayHello(@WebParam(name="text") String text);
}

package com.wp.service;
import javax.jws.WebService;
@WebService(endpointInterface = "com.wp.service.HelloWs")
public class HelloWsImpl implements HelloWs {
    @Override
    public String sayHello(String name) {
        return "hello  " + name;
    }
}
package com.wp.service;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
public class Server {
    public static void main(String[] args) {
        JaxWsServerFactoryBean jsfb = new JaxWsServerFactoryBean();
        //1.服务提供者实现的接口
        jsfb.setServiceClass(HelloWs.class);
        //2.指定访问路径
        jsfb.setAddress("http://localhost:9090/ws");
        //3.指定服务实现类
        jsfb.setServiceBean(new HelloWsImpl());
        //jsfb.getInInterceptors().add(new LoggingInInterceptor());
        //jsfb.getOutInterceptors().add(new LoggingOutInterceptor());
        //4.发布
        jsfb.create();
        System.out.println("发布成功...");
    }
}

2.客户端
生成客户端代码:

a.在不同项目中

package com.wp.test;
import org.apache.cxf.frontend.ClientProxyFactoryBean;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.wp.client.HelloWs;
public class Client {
    public static void main(String[] args) {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
       // factory.getInInterceptors().add(new LoggingInInterceptor());
       // factory.getOutInterceptors().add(new LoggingOutInterceptor());
        factory.setAddress("http://localhost:9090/ws");
        HelloWs client = factory.create(HelloWs.class);
        System.out.println(client.sayHello("World"));
    }
}

b.在同一项目中

package com.wp.service;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class Client {
    public static void main(String[] args) {
        JaxWsProxyFactoryBean bean = new JaxWsProxyFactoryBean();
        bean.setAddress("http://localhost:9090/ws");
        bean.setServiceClass(HelloWs.class);
        HelloWs hw = (HelloWs) bean.create();
        System.out.println(hw.sayHello("www"));
    }
}

 

补充:CORS解决ajax跨域调用API问题


 cors相比jsonp、改document.domain = ‘跨域地址’灵活简单
 比如,前端应用为静态站点且部署在http://web.xxx.com域下,后端应用发布REST API并部署在http://api.xxx.com域下,如何使前端应用通过AJAX跨域访问后端应用呢?这需要使用到CORS技术来实现,这也是目前最好的解决方案了。
 [CORS全称为Cross Origin Resource Sharing(跨域资源共享),服务端只需添加相关响应头信息,即可实现客户端发出AJAX跨域请求。]
 CORS技术非常简单,易于实现,目前绝大多数浏览器均已支持该技术(IE8浏览器也支持了),服务端可通过任何编程语言来实现,只要能将CORS响应头写入response对象中即可。
 通过CORS技术实现AJAX跨域访问基本实现如下:
 

1.编写一个Filter添加CORS响应头

 这个FIlter用于过滤所有的HTTP请求,并将CORS响应头写入response对象中,代码如下:

public class CorsFilter implements Filter {  
  
    private String allowOrigin;  
    private String allowMethods;  
    private String allowCredentials;  
    private String allowHeaders;  
    private String exposeHeaders;  
  
    @Override  
    public void init(FilterConfig filterConfig) throws ServletException {  
        allowOrigin = filterConfig.getInitParameter("allowOrigin");  
        allowMethods = filterConfig.getInitParameter("allowMethods");  
        allowCredentials = filterConfig.getInitParameter("allowCredentials");  
        allowHeaders = filterConfig.getInitParameter("allowHeaders");  
        exposeHeaders = filterConfig.getInitParameter("exposeHeaders");  
    }  
  
    @Override  
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
        HttpServletRequest request = (HttpServletRequest) req;  
        HttpServletResponse response = (HttpServletResponse) res;  
        if (StringUtil.isNotEmpty(allowOrigin)) {  
            List<String> allowOriginList = Arrays.asList(allowOrigin.split(","));  
            if (CollectionUtil.isNotEmpty(allowOriginList)) {  
                String currentOrigin = request.getHeader("Origin");  
                if (allowOriginList.contains(currentOrigin)) {  
                    response.setHeader("Access-Control-Allow-Origin", currentOrigin);  
                }  
            }  
        }  
        if (StringUtil.isNotEmpty(allowMethods)) {  
            response.setHeader("Access-Control-Allow-Methods", allowMethods);  
        }  
        if (StringUtil.isNotEmpty(allowCredentials)) {  
            response.setHeader("Access-Control-Allow-Credentials", allowCredentials);  
        }  
        if (StringUtil.isNotEmpty(allowHeaders)) {  
            response.setHeader("Access-Control-Allow-Headers", allowHeaders);  
        }  
        if (StringUtil.isNotEmpty(exposeHeaders)) {  
            response.setHeader("Access-Control-Expose-Headers", exposeHeaders);  
        }  
        chain.doFilter(req, res);  
    }  
  
    @Override  
    public void destroy() {  
    }  
}  

 以上CorsFilter将从web.xml中读取相关Filter初始化参数,并将在处理HTTP请求时将这些参数写入对应的CORS响应头中,下面大致描述一下这些CORS响应头的意义:

  • Access-Control-Allow-Origin:允许访问的客户端域名,例如:http://web.xxx.com,若为*,则表示从任意域都能访问,即不做任何限制。
  • Access-Control-Allow-Methods:允许访问的方法名,多个方法名用逗号分割,例如:GET,POST,PUT,DELETE,OPTIONS。
  • Access-Control-Allow-Credentials:是否允许请求带有验证信息,若要获取客户端域下的cookie时,需要将其设置为true。
  • Access-Control-Allow-Headers:允许服务端访问的客户端请求头,多个请求头用逗号分割,例如:Content-Type。
  • Access-Control-Expose-Headers:允许客户端访问的服务端响应头,多个响应头用逗号分割。

 这里有一个值得注意的响应头:Access-Control-Allow-Origin。该响应头用来记录可以访问该资源的域。在接收到服务端响应后,浏览器将会查看响应中是否包含Access-Control-Allow-Origin响应头。如果该响应头存在,那么浏览器会分析该响应头中所标示的内容。如果其包含了当前页面所在的域,那么浏览器就将知道这是一个被允许的跨域访问,从而不再根据Same-origin Policy来限制用户对该数据的访问。
 需要注意的是,CORS规范中定义Access-Control-Allow-Origin只允许两种取值,要么为*,要么为具体的域名,也就是说,不支持同时配置多个域名。为了解决跨多个域的问题,需要在代码中做一些处理,这里将Filter初始化参数作为一个域名的集合(用逗号分隔),只需从当前请求中获取Origin请求头,就知道是从哪个域中发出的请求,若该请求在以上允许的域名集合中,则将其放入Access-Control-Allow-Origin响应头,这样跨多个域的问题就轻松解决了。
 

2.在web.xml中配置CorsFilter:

<filter>  
    <filter-name>corsFilter</filter-name>  
    <filter-class>com.xxx.api.cors.CorsFilter</filter-class>  
    <init-param>  
        <param-name>allowOrigin</param-name>  
        <param-value>http://web.xxx.com</param-value>  
    </init-param>  
    <init-param>  
        <param-name>allowMethods</param-name>  
        <param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>  
    </init-param>  
    <init-param>  
        <param-name>allowCredentials</param-name>  
        <param-value>true</param-value>  
    </init-param>  
    <init-param>  
        <param-name>allowHeaders</param-name>  
        <param-value>Content-Type</param-value>  
    </init-param>  
</filter>  
<filter-mapping>  
    <filter-name>corsFilter</filter-name>  
    <url-pattern>/*</url-pattern>  
</filter-mapping>  

 完成以上过程即可实现AJAX跨域功能了。
参考:https://www.cnblogs.com/loveis715/p/4592246.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值