`

基于Spring和Spring MVC实现可跨域访问的REST服务(转帖)

阅读更多

转帖地址:https://www.tianmaying.com/tutorial/cross-origin-rest-service

Web应用中前端JavaScript访问后端的REST服务默认是不能跨域的,这里的域英文中叫Origin,有时也叫Domain,包含了协议(HTTP/HTTPS),域名和端口号。不能跨域指的是,如果来自http://abc.com:80的JavaScript代码只能访问http://abc.com:80中的资源(HTTP默认端口号为80,注意端口号不同也是不同的域)。大家不妨试一试在自己的JavaScript代码中去访问Google搜索的URL,代码是不能正常运行的。

Same Origin Policy(SOP)是浏览器默认的安全模型,为什么需要SOP呢? 因为如果允许JavaScript代码访问非相同域资源的话,那么安全性将变得完全不可控。举个例子,如果另外一个网址中包含的恶意脚本就可以没有任何防备的加载进来,那就就能随意获取或者恶意修改页面元素Cookie信息等。SOP则保证了所有你访问的资源和服务是来自于你自己的服务器,外部的脚本就不能没有任何障碍得攻击你了。当然这只是基本的安全模型,通过XSS等技术,如果你的代码有漏洞的话,还是可能受到来自不同域的恶意代码的攻击,这里就不展开啦。

但是有时候我们就是希望自己的服务是可以被跨域访问的,我们知道要访问的不同域的远程资源是安全的,这时候SOP反而给我们带来了限制。所以又出现了一些跨域访问的技术,比如JSONP。今天我们就来介绍如何基于Spring来实现可跨域访问的REST服务。

准备工作

今天我们来创建一个接收HTTP GET请求的REST服务,访问地址是http://localhost:8080/greetin),返回的格式为:

 

{
    "id": 1,
    "content": "Hello, World!"
}

如果请求中包含name参数,则会将默认的World替换为name的值。比如http://localhost:8080/greeting?name=User请求则返回:

 

{
    "id": 1,
    "content": "Hello, User!"
}

开发环境:

  • IDE+Java环境(JDK 1.7或以上版本)
  • Maven 3.0+(Eclipse和Idea IntelliJ内置,如果使用IDE并且不使用命令行工具可以不安装)

POM文件:

pom.xml

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.tianmaying</groupId>
  <artifactId>cross-origin-demo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>cross-origin-demo</name>
  <description>Demo of enabling Cross Origin Requests for a RESTful Web Service</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
    <relativePath/>
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>  
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

REST服务的实现

Greeting JSON格式的信息对应的模型类为Greeting类,非常简单。

Greeting.java

 

package com.tianmaying.crossorigin;

public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}

Controller的实现我们应该也是轻车熟路了。

GreetingController.java

 

package com.tianmaying.crossorigin;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @RequestMapping("/greeting")
    public @ResponseBody Greeting greeting(
            @RequestParam(value="name", required=false, defaultValue="World") String name) {
        return new Greeting(counter.incrementAndGet(),
                            String.format(template, name));
    }
}

@RequestMapping标注将/greeting请求映射到greeting()方法。

提示

上面的例子中没有指定URL对应的HTTP方法,比如GETPUTPOST或者DELETE,这表示所有HTTP方法都映射到这个URL上。如果希望指定特定的方法,可以这样设置@RequestMapping(method=GET)

@RequestParam将请求参数绑定到greeting()方法中的参数,该参数不是必须的,如果没有提供,则使用默认值World

方法的实现创建并返回了一个Greeting对象,id通过AtomicLong来设置,content则通过一个简单的字符串模板来生成。

REST服务和传统的MVC控制器的一个关键区别在于,REST服务通常并不依赖于一种模板技术(比如JSP、Velocity等)来生成HTML,REST服务只是填充好对象的信息,然后将对象信息转换为JSON字符串直接写入HTTP的响应中。而@ResponseBody正是来做这件事情的!

而对象转为为JSON这件事情,有了Spring的HTTP消息转换(HTTP Message Converter)的支持可以自动化的完成。只要Jackson 2在类路径中,Spring的MappingJackson2HttpMessageConverter会自动启用将Greeting对象转为JSON。

 

关于Spring MVC的更多内容请大家参考Spring MVC实战入门训练

跨域支持

接下来是最关键的时候了,之前我们已经实现了一个普通的REST服务,如何支持跨域就在此一举了:)我们只需要增加一个Filter,在HTTP响应中增加一些头信息,我们通过SimpleCORSFilter来实现。

SimpleCORSFilter.java

 

package com.tianmaying.crossorigin;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;

@Component
public class SimpleCORSFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}

}

SimpleCORSFilter在响应中增加了一些Access-Control-*头。在上面的例子中,设置的头信息表示允许来自任何域的客户端访问POSTGETOPTIONS和 DELETE请求,请求的结果将缓存至多3600秒。当然,这只是一个很简单的跨域支持filter,大家可以根据需要进行更多的设置,比如只支持来自特定域的请求访问特定的资源。

测试

最后我们通过main()函数将这个SpringBootApplication Run起来:

App.java

 

package com.tianmaying.crossorigin;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
分享到:
评论

相关推荐

    基于Spring和Spring MVC实现可跨域访问的REST服务

    这篇博客“基于Spring和Spring MVC实现可跨域访问的REST服务”深入探讨了如何使用这两个流行的Java框架来创建这样的服务。Spring作为核心框架提供依赖注入和整体架构支持,而Spring MVC作为其Web模块,专门用于构建...

    Spring MVC 基于注解实例

    Spring MVC 基于注解实例Spring MVC 基于注解实例Spring MVC 基于注解实例Spring MVC 基于注解实例Spring MVC 基于注解实例Spring MVC 基于注解实例Spring MVC 基于注解实例Spring MVC 基于注解实例Spring MVC 基于...

    基于Spring + Spring MVC + MyBatis的图书馆管理系统

    总的来说,这个基于Spring + Spring MVC + MyBatis的图书馆管理系统,充分展示了Java企业级开发的强大之处,通过合理的技术选型和设计模式,实现了功能完善的图书管理服务,同时也为开发者提供了良好的开发体验和...

    基于spring+spring mvc+hibernate的智能农业信息管理系统

    本文将深入探讨一款基于Spring、Spring MVC和Hibernate架构的智能农业信息管理系统,以及如何利用Spring Security进行安全防护。 首先,Spring作为Java领域中的轻量级框架,其核心特性是依赖注入(Dependency ...

    毕设项目基于Spring + Spring MVC + Mybatis的销售管理系统源码.zip

    毕设项目基于Spring + Spring MVC + Mybatis的销售管理系统源码.zip毕设项目基于Spring + Spring MVC + Mybatis的销售管理系统源码.zip毕设项目基于Spring + Spring MVC + Mybatis的销售管理系统源码.zip毕设项目...

    Spring MVC REST Demo

    "Spring MVC REST Demo"是一个示例项目,旨在展示如何在Spring MVC框架中实现RESTful Web服务。下面将详细讨论Spring MVC与RESTful API的结合,以及如何创建和测试此类服务。 首先,Spring MVC是Spring框架的一部分...

    基于Spring+Spring MVC+MyBatis的图书馆管理系统(带完整文档报告,E-R图)课设

    包含课设要求所有资源 基于Spring + Spring MVC + MyBatis的图书馆管理系统,使用Maven进行包管理。主要功能包括:图书查询、图书管理、图书编辑、读者管理、图书的借阅与归还以及借还日志记录等。

    基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)

    基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)...

    使用Spring MVC创建REST服务简单例子

    REST(Representational State Transfer)是一种网络应用程序的设计风格和开发方式,它基于HTTP协议,实现了资源的分布式管理和访问。本教程将通过一个简单的例子,讲解如何利用Spring MVC创建REST服务。 首先,...

    spring 3.0 mvc实现rest代码

    Spring 3.0 MVC 实现 REST 代码是一个关于构建基于 RESTful 风格的 Web 服务的示例。REST(Representational State Transfer)是一种架构风格,常用于设计网络应用程序,强调通过统一资源标识符(URI)来访问资源,...

    Spring+Spring MVC+Spring JDBC+MySql实现简单登录注册

    在本项目中,我们主要利用Spring框架,包括其核心模块Spring、MVC模块Spring MVC以及数据访问/集成模块Spring JDBC,结合MySQL数据库来构建一个基础的登录注册系统。以下是这个项目涉及的关键技术点: 1. **Spring...

    spring mvc rest基础学习demo

    Spring MVC 是一个强大的Java Web应用程序框架,用于构建高效、可维护的Web应用。它扩展了Spring框架的功能,提供了模型-视图-控制器(MVC)架构模式,使得开发者可以更轻松地处理HTTP请求和响应。在"spring mvc ...

    基于ssm(spring+spring mvc+mybatis+maven)高仿bilibili视频网站项目源码.zip

    基于ssm(spring+spring mvc+mybatis+maven)高仿bilibili视频网站项目源码.zip 基于ssm(spring+spring mvc+mybatis+maven)高仿bilibili视频网站项目源码.zip 基于ssm(spring+spring mvc+mybatis+maven)高仿bilibili...

    spring-rest.rar_DEMO_employeeDS.java_rest spring mvc_spring mvc_

    在本示例中,我们将深入探讨如何利用Spring MVC框架构建RESTful API,主要涉及`employeeDS.java`这个可能的数据服务类以及与`rest_spring_mvc`、`spring_mvc`和`spring_rest`相关的概念。`spring-rest.rar`是一个...

    基于maven+spring+spring mvc+mybatis 框架web项目

    在IT行业中,构建Web应用程序是一项常见的任务,而“基于maven+spring+spring mvc+mybatis框架web项目”提供了一个适用于初学者的学习路径。这个项目利用了四个关键的技术组件,它们分别是Maven、Spring、Spring MVC...

    OSGI整合Spring、Mybatis、Spring MVC实现一个登录应用案例

    总的来说,这个案例展示了OSGI的模块化优势,以及如何将Spring、Mybatis和Spring MVC集成到OSGI环境中,构建一个可维护、可扩展的登录应用。通过实践这样的案例,开发者可以更好地掌握这些技术在企业级开发中的应用...

    spring3.0 mvc和rest入门例子

    Spring 3.0 MVC 和 REST 是 Java Web 开发中的重要组成部分,它们为构建现代、高效的应用程序提供了强大的框架支持。本文将深入探讨这两个概念以及如何通过一个入门实例来理解它们。 Spring MVC(Model-View-...

    Spring MVC jar包

    Spring MVC 是一个基于Java的轻量级Web应用框架,它为开发者提供了模型-视图-控制器(MVC)架构,使开发人员能够更好地组织和分离应用程序的业务逻辑、数据处理和用户界面。Spring MVC是Spring框架的一个核心组件,...

    基本的spring mvc + spring security实现的登录(无数据库)

    在本项目中,我们主要探讨的是如何利用Spring MVC和Spring Security框架构建一个基本的无数据库登录系统。Spring MVC是Spring框架的一部分,用于处理Web应用程序的请求-响应模型,而Spring Security则是一个强大的...

Global site tag (gtag.js) - Google Analytics