Spring Boot如何让某个Controller支持跨源请求,以及如何让Controller类某个成员方法支持跨源请求

Posted zhangchao19890805

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot如何让某个Controller支持跨源请求,以及如何让Controller类某个成员方法支持跨源请求相关的知识,希望对你有一定的参考价值。

在前面我们已经讨论了Spring Boot 如何全局支持跨源请求。如果你想了解可以查看这篇文章

下面我们讨论另一种场景。有些时候,你需要让你的应用在大部分的时候,仅仅支持当前域名下的请求。而仅仅在极其特殊的几个场合下,才支持跨源请求。这个时候,你需要把跨源请求仅仅缩小在几个Controller上,或者Controller类的几个成员方法上。这个时候你需要用到如下的注解:@CrossOrigin(origins = "*", maxAge = 3600) 。把这个注解放到 Controller 类上或者Controller类的成员方法上,就可以支持跨源请求了。

下面给出了一个例子。
这个项目名字是 blog3。由Maven管理。这个项目源代码组织结构如下:

blog3
  src
    main
      java
        zhangchao
          blog3
            Blog3Application.java
            MethodController.java
            User.java
            UserController.java    
      resources
        application.properties
  pom.xml

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>zhangchao</groupId>
    <artifactId>blog3</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.2.RELEASE</version>
        <relativePath/>
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</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>

application.properties

#S Beautiful jsckson string 
spring.jackson.serialization.indent_output=true
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true

Blog3Application.java

package zhangchao.blog3;

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

@SpringBootApplication
public class Blog3Application {
    public static void main(String[] args){
        SpringApplication.run(Blog3Application.class, args);
    }
}

实体类 User.java

package zhangchao.blog3;

import java.math.BigDecimal;

public class User {
    public String id;
    public String name;
    public BigDecimal balance;
}

UserController.java 演示Controller范围,支持跨源请求

package zhangchao.blog3;

import java.math.BigDecimal;
import java.util.UUID;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

//@CrossOrigin(origins = "http://localhost:3000", maxAge = 3600)
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value="",method=RequestMethod.POST)
    public User save(@RequestBody User user){
        user.id = UUID.randomUUID().toString();
        return user;
    }

    @RequestMapping(value="/{id}",method=RequestMethod.GET)
    public User get(@PathVariable String id){
        User user = new User();
        user.balance = new BigDecimal("3.2");
        user.id = id;
        user.name = "小明";
        return user;
    }

    @RequestMapping(value="",method=RequestMethod.PUT)
    public User update(@RequestBody User user){
        return user;
    }

    @RequestMapping(value="/{id}",method=RequestMethod.DELETE)
    public String delete(@PathVariable String id){
        return "success";
    }
}

MethodController.java 演示仅仅指定 Controller 类的成员方法支持跨源请求

package zhangchao.blog3;

import java.math.BigDecimal;
import java.util.UUID;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/methodTest")
public class MethodController {

    @RequestMapping(value="",method=RequestMethod.POST)
    public User save(@RequestBody User user){
        user.id = UUID.randomUUID().toString();
        return user;
    }

    @RequestMapping(value="/{id}",method=RequestMethod.GET)
    public User get(@PathVariable String id){
        User user = new User();
        user.balance = new BigDecimal("3.2");
        user.id = id;
        user.name = "小明";
        return user;
    }

    @CrossOrigin(origins = "*", maxAge = 3600)
    @RequestMapping(value="",method=RequestMethod.PUT)
    public User update(@RequestBody User user){
        return user;
    }

    @CrossOrigin(origins = "*", maxAge = 3600)
    @RequestMapping(value="/{id}",method=RequestMethod.DELETE)
    public String delete(@PathVariable String id){
        return "success";
    }
}

为了做测试,你需要前端程序来模拟跨源请求。对于浏览器来说,只要协议、域名、ip和端口有任意一个不同,就视作跨源请求。我在自己的电脑上使用了nodejs的serve工具作为前端的服务器。你可以查看这个项目的地址:https://github.com/zeit/serve

我新建了一个文件夹,名字是blog3client。blog3client一共包含三个文件:index.html、vue.js 和 vue-resource.js。其中 vue 的版本是2。

index.html 文件内容如下:

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta content="text/html;charset=UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>测试</title>
</head>
<body>
<div id="app">
    整个Controller设置成跨域
    <table border="1" width="600">
        <tbody>
            <tr>
                <td width="50%">
                    姓名:<input v-model="e1.name" type="text"/> <br/>
                    余额:<input v-model="e1.balance" type="text"/> <br/>
                    <button v-on:click="saveE1()" >保存</button>
                </td>
                <td>
                    <div v-if="e1success">
                        保存成功 <br/>
                        id: {{e1.id}} <br />
                        name: {{e1.name}} <br />
                        balance: {{e1.balance}} <br />
                    </div>
                </td>
            </tr>
            <tr>
                <td>
                    <button v-on:click="deleteE2()" >删除</button>
                </td>
                <td>
                    <div v-if="e2success">
                        删除成功
                    </div>
                </td>
            </tr>
        </tbody>
    </table>
    <hr/>
    Controller里面的部分方法跨域<br/>
    <table border="1" width="600">
        <tbody>
            <tr>
                <td width="50%">
                    姓名:<input v-model="e5.name" type="text"/> <br/>
                    余额:<input v-model="e5.balance" type="text"/> <br/>
                    <button v-on:click="updateE5()" >更新</button>
                </td>
                <td>
                    <div v-if="e5success">
                        更新成功 <br/>
                        id: {{e5.id}} <br />
                        name: {{e5.name}} <br />
                        balance: {{e5.balance}} <br />
                    </div>
                </td>
            </tr>
            <tr>
                <td>
                    <button v-on:click="getE6()" >详情</button>
                </td>
                <td>
                    <div v-if="e6success">
                        详情<br/>
                        id: {{e6.id}} <br />
                        name: {{e6.name}} <br />
                        balance: {{e6.balance}} <br />
                    </div>
                </td>
            </tr>
        </tbody>
    </table>
</div>
<script src="./vue.js" type="text/javascript"></script>
<script src="./vue-resource.js" type="text/javascript"></script>
<script type="text/javascript">
Vue.use(VueResource);
var app = new Vue({
    el: '#app',
    data: {
        "e1":{
            "name": "",
            "balance": ""
        },
        "e1success": false,
        "e2success": false,
        "e5":{
            "name": "",
            "balance": ""
        },
        "e5success": false,
        "e6success": false,
        "e6":{
            "id":"",
            "name": "",
            "balance": ""
        }
    },
    methods: {
        saveE1: function() {
            var entity = this.e1;
            var self = this;
            const successCallback = function(res) {
                console.log(res.data)
                self.e1 = res.data;
                self.e1success = true;
            }; 
            this.$http.post("http://localhost:8080/user/", entity, {
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(successCallback, function(e){                   
                window.console.log("error");
            });
        },
        deleteE2: function(){
            var self = this;
            this.$http.delete("http://localhost:8080/user/234", {}, {
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(function(res){
                self.e2success = true;
            }, 
            function(e){                   
                window.console.log("error");
            });
        },
        updateE5:function(){
            var self = this;
            self.e5.id="123";
            this.$http.put("http://localhost:8080/methodTest/", self.e5, {
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(function(res){
                self.e5 = res.data;
                self.e5success = true;
            }, function(e){                   
                window.console.log("error");
            });
        },
        getE6: function(){
            this.$http.get("http://localhost:8080/methodTest/123", {}, {
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(function(res){
                self.e6 = res.data;
                self.e5success = true;
            }, function(e){                   
                window.console.log("error");
            });
        }
    } // end methods
});
</script>
</body>
 </html>

安装好 serve 后,用cd命令进入blog3client文件夹。使用serve 启动前端服务器,默认端口是3000。浏览器访问 http://localhost:3000/ 。运行Spring Boot 的后端代码。打开浏览器的控制面板,点击按钮,查看相应的返回信息即可。

以上是关于Spring Boot如何让某个Controller支持跨源请求,以及如何让Controller类某个成员方法支持跨源请求的主要内容,如果未能解决你的问题,请参考以下文章

如何检查spring boot应用程序在自动配置类中是不是有某个注释

Spring Boot 启动时,让方法自动执行的 4 种方法!

如何让 Spring Boot 使用 MultiTenantSpringLiquibase?

如何让 Spring Boot 启动的更快?

如何让 Spring Boot 自动重新连接到 PostgreSQL?

如何让 Spring Boot 应用程序在 tomcat 失败时退出